"""Product memory CRUD endpoints.""" from typing import Optional, List, Dict from pathlib import Path from fastapi import APIRouter, HTTPException, Depends, Query from pydantic import BaseModel from ..auth.dependencies import get_current_user router = APIRouter(prefix="/api/memory", tags=["memory"]) _project_root = Path(__file__).resolve().parent.parent.parent.parent _db_path = str(_project_root / "data" / "product_cache.db") _excel_source = str(_project_root / "templates" / "商品资料.xlsx") class MemoryItem(BaseModel): barcode: str name: str spec: Optional[str] = None unit: Optional[str] = None price: Optional[float] = None confidence: int = 0 source: str = "ocr" last_used: Optional[str] = None use_count: int = 0 class MemoryUpdate(BaseModel): name: Optional[str] = None spec: Optional[str] = None unit: Optional[str] = None price: Optional[float] = None confidence: Optional[int] = None class MemoryListResponse(BaseModel): items: List[MemoryItem] total: int page: int page_size: int def _get_db(): from app.core.db.product_db import ProductDatabase return ProductDatabase(_db_path, _excel_source) def _row_to_item(row: Dict) -> MemoryItem: return MemoryItem( barcode=row.get("barcode", ""), name=row.get("name", ""), spec=row.get("spec"), unit=row.get("unit"), price=row.get("price"), confidence=row.get("confidence", 0), source=row.get("source", "ocr"), last_used=row.get("last_used"), use_count=row.get("use_count", 0), ) @router.get("", response_model=MemoryListResponse) async def list_memory( search: str = "", page: int = Query(1, ge=1), page_size: int = Query(50, ge=1, le=200), current_user: dict = Depends(get_current_user), ): db = _get_db() results = db.get_all_memories() if search: s = search.lower() results = [r for r in results if s in r.get("barcode", "").lower() or s in r.get("name", "").lower()] total = len(results) start = (page - 1) * page_size page_items = results[start:start + page_size] return MemoryListResponse( items=[_row_to_item(r) for r in page_items], total=total, page=page, page_size=page_size, ) @router.get("/{barcode}") async def get_memory( barcode: str, current_user: dict = Depends(get_current_user), ): db = _get_db() product = db.get_memory(barcode) if not product: raise HTTPException(404, f"未找到条码 {barcode} 的记忆记录") return product @router.put("/{barcode}") async def update_memory( barcode: str, body: MemoryUpdate, current_user: dict = Depends(get_current_user), ): db = _get_db() existing = db.get_memory(barcode) if not existing: raise HTTPException(404, f"未找到条码 {barcode}") update_data = body.model_dump(exclude_none=True) if not update_data: raise HTTPException(400, "没有提供更新数据") db.update_memory(barcode, update_data) return {"message": f"已更新 {barcode}", "updated_fields": list(update_data.keys())} @router.delete("/{barcode}") async def delete_memory( barcode: str, current_user: dict = Depends(get_current_user), ): db = _get_db() existing = db.get_memory(barcode) if not existing: raise HTTPException(404, f"未找到条码 {barcode}") db.delete_memory(barcode) return {"message": f"已删除 {barcode}"} @router.post("/reimport") async def reimport_memory( current_user: dict = Depends(get_current_user), ): db = _get_db() try: count = db.reimport() return {"message": f"重新导入完成,共导入 {count} 条记录", "count": count} except Exception as e: raise HTTPException(500, f"导入失败: {e}") @router.get("/export/sync") async def export_memory( current_user: dict = Depends(get_current_user), ): db = _get_db() data = db.export_for_sync() return {"data": data, "count": len(data)} @router.post("/import/sync") async def import_memory( data: dict, current_user: dict = Depends(get_current_user), ): db = _get_db() try: count = db.import_from_sync(data.get("data", [])) return {"message": f"导入完成,共 {count} 条", "count": count} except Exception as e: raise HTTPException(500, f"导入失败: {e}")