from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from typing import List, Optional import uuid from database import get_db from models.product import Product from models.user import User from schemas.product import ( ProductResponse, ProductCreate, ProductUpdate, ProductDetailResponse ) from routers.auth import get_current_user, is_admin_user # 导入日志模块 from utils.logger import logger router = APIRouter() def generate_product_number(): """生成 11 位 UUID 货号""" return uuid.uuid4().hex[:11].upper() @router.get("/", response_model=List[ProductResponse]) async def read_products( skip: int = 0, limit: int = 100, category_id: Optional[int] = None, status: Optional[int] = None, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """获取产品列表""" logger.info(f"获取产品列表 - skip: {skip}, limit: {limit}, category_id: {category_id}, status: {status}, user: {current_user.username}") query = db.query(Product) if not is_admin_user(current_user): query = query.filter(Product.company_code == current_user.company_code) if category_id is not None: query = query.filter(Product.category_id == category_id) if status is not None: query = query.filter(Product.status == status) products = query.order_by(Product.sort_order, Product.id).offset(skip).limit(limit).all() logger.info(f"获取产品列表成功 - 共 {len(products)} 个产品") return products @router.get("/{product_number}", response_model=ProductDetailResponse) async def read_product_detail( product_number: str, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """获取单个产品详情(包含所有关联数据)""" logger.info(f"获取产品详情 - product_number: {product_number}, user: {current_user.username}") from models.product_certification import ProductCertification from models.product_media import ProductMedia from models.product_packaging import ProductPackaging query = db.query(Product).filter(Product.product_number == product_number) if not is_admin_user(current_user): query = query.filter(Product.company_code == current_user.company_code) product = query.first() if product is None: logger.error(f"产品不存在 - product_number: {product_number}") raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) certifications = db.query(ProductCertification).filter( ProductCertification.product_number == product_number ).all() media = db.query(ProductMedia).filter( ProductMedia.product_number == product_number ).order_by(ProductMedia.sort_order).all() packaging = db.query(ProductPackaging).filter( ProductPackaging.product_number == product_number ).all() logger.info(f"获取产品详情成功 - product_number: {product_number}, 认证: {len(certifications)}, 媒体: {len(media)}, 包装: {len(packaging)}") return ProductDetailResponse( **product.__dict__, certifications=certifications, media=media, packaging=packaging ) @router.post("/", response_model=ProductResponse, status_code=status.HTTP_201_CREATED) async def create_product( product: ProductCreate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """创建新产品""" logger.info(f"创建新产品 - user: {current_user.username}") product_data = product.model_dump() if not is_admin_user(current_user): product_data['company_code'] = current_user.company_code product_data['product_number'] = generate_product_number() db_product = Product(**product_data) db.add(db_product) db.commit() db.refresh(db_product) logger.info(f"创建新产品成功 - product_number: {db_product.product_number}") return db_product @router.put("/{product_number}", response_model=ProductResponse) async def update_product( product_number: str, product_update: ProductUpdate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """更新产品信息""" logger.info(f"更新产品信息 - product_number: {product_number}, user: {current_user.username}") query = db.query(Product).filter(Product.product_number == product_number) if not is_admin_user(current_user): query = query.filter(Product.company_code == current_user.company_code) product = query.first() if product is None: logger.error(f"产品不存在 - product_number: {product_number}") raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) update_data = product_update.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(product, field, value) db.commit() db.refresh(product) logger.info(f"更新产品信息成功 - product_number: {product_number}") return product @router.delete("/{product_number}", status_code=status.HTTP_204_NO_CONTENT) async def delete_product( product_number: str, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """删除产品(级联删除所有关联数据)""" logger.info(f"删除产品 - product_number: {product_number}, user: {current_user.username}") from models.product_certification import ProductCertification from models.product_media import ProductMedia from models.product_packaging import ProductPackaging query = db.query(Product).filter(Product.product_number == product_number) if not is_admin_user(current_user): query = query.filter(Product.company_code == current_user.company_code) product = query.first() if product is None: logger.error(f"产品不存在 - product_number: {product_number}") raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) if product.status == 1: logger.error(f"产品未下架,无法删除 - product_number: {product_number}") raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="请先下架商品才能删除" ) # 统计关联数据 certifications_count = db.query(ProductCertification).filter(ProductCertification.product_number == product_number).count() media_count = db.query(ProductMedia).filter(ProductMedia.product_number == product_number).count() packaging_count = db.query(ProductPackaging).filter(ProductPackaging.product_number == product_number).count() # 级联删除 db.query(ProductCertification).filter(ProductCertification.product_number == product_number).delete() db.query(ProductMedia).filter(ProductMedia.product_number == product_number).delete() db.query(ProductPackaging).filter(ProductPackaging.product_number == product_number).delete() db.delete(product) db.commit() logger.info(f"删除产品成功 - product_number: {product_number}, 认证: {certifications_count}, 媒体: {media_count}, 包装: {packaging_count}") return None