"""商品查询 API。""" from __future__ import annotations from uuid import UUID from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from db import get_db from models import Product, ProductAsset from schemas import AssetOut, ProductListOut, ProductOut from services import storage router = APIRouter(prefix="/api", tags=["products"]) def _asset_out(a: ProductAsset) -> AssetOut: return AssetOut( id=str(a.id), group_key=a.group_key, variant_name=a.variant_name, type=a.type, source_url=a.source_url, url=a.stored_url, status=a.status, ) @router.get("/products", response_model=ProductListOut) async def list_products( q: str = "", page: int = 1, page_size: int = 20, db: AsyncSession = Depends(get_db), ): cond = [] if q: cond.append(Product.name.contains(q)) total = (await db.scalar(select(func.count()).select_from(Product).where(*cond))) or 0 rows = (await db.scalars( select(Product).where(*cond).order_by(Product.created_at.desc()) .offset((page - 1) * page_size).limit(page_size) )).all() return ProductListOut(total=total, items=[ ProductOut( id=str(p.id), stage=p.stage, source_platform=p.source_platform, source_item_id=p.source_item_id, source_url=p.source_url, name=p.name, description=p.description, price=p.price, asset_counts=p.asset_counts, created_at=p.created_at.isoformat() if p.created_at else None, ) for p in rows ]) @router.get("/products/{product_id}", response_model=ProductOut) async def get_product(product_id: str, db: AsyncSession = Depends(get_db)): p = await db.get(Product, UUID(product_id)) if p is None: raise HTTPException(status_code=404, detail="商品不存在") assets = (await db.scalars( select(ProductAsset).where(ProductAsset.product_id == p.id) .order_by(ProductAsset.sort_order) )).all() return ProductOut( id=str(p.id), stage=p.stage, source_platform=p.source_platform, source_item_id=p.source_item_id, source_url=p.source_url, name=p.name, description=p.description, price=p.price, asset_counts=p.asset_counts, assets=[_asset_out(a) for a in assets], created_at=p.created_at.isoformat() if p.created_at else None, )