Spaces:
Sleeping
Sleeping
| from fastapi import APIRouter, Depends, HTTPException, status | |
| from sqlalchemy.orm import Session | |
| from typing import List, Optional | |
| import uuid | |
| import re | |
| from database import get_db | |
| from models.category import Category | |
| from models.product import Product | |
| from models.user import User | |
| from schemas.category import CategoryResponse, CategoryCreate, CategoryUpdate, CategoryTreeResponse | |
| from routers.auth import get_current_user, is_admin_user | |
| router = APIRouter() | |
| def generate_level_code() -> str: | |
| """生成6位字母数字组合编码""" | |
| # 使用UUID生成并截取前6位,确保包含字母和数字 | |
| while True: | |
| code = uuid.uuid4().hex[:6].lower() | |
| # 检查是否同时包含字母和数字 | |
| if re.search(r'[a-z]', code) and re.search(r'[0-9]', code): | |
| return code | |
| def get_category_level_by_code(db: Session, category_code: str, company_code: str) -> int: | |
| """通过编码获取分类的层级,0为顶级""" | |
| if not category_code: | |
| return 0 | |
| # 通过下划线数量判断层级 | |
| return category_code.count('_') | |
| def build_category_code(db: Session, parent_code: str, company_code: str) -> str: | |
| """构建级联编码""" | |
| if not parent_code: | |
| # 顶级分类,直接生成编码 | |
| return generate_level_code() | |
| parent = db.query(Category).filter( | |
| Category.code == parent_code, | |
| Category.company_code == company_code | |
| ).first() | |
| if not parent: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail="Parent category not found" | |
| ) | |
| # 生成当前层级编码,拼接父级编码 | |
| level_code = generate_level_code() | |
| return f"{parent_code}_{level_code}" | |
| def build_category_tree(categories: List[Category], parent_code: str = "") -> List[CategoryTreeResponse]: | |
| """构建分类树形结构""" | |
| tree = [] | |
| for cat in categories: | |
| if cat.parent_code == parent_code: | |
| children = build_category_tree(categories, cat.code) | |
| tree.append(CategoryTreeResponse( | |
| **cat.__dict__, | |
| children=children | |
| )) | |
| return tree | |
| async def get_categories( | |
| parent_code: Optional[str] = None, | |
| current_user: User = Depends(get_current_user), | |
| db: Session = Depends(get_db) | |
| ): | |
| """获取分类列表""" | |
| query = db.query(Category) | |
| if not is_admin_user(current_user): | |
| query = query.filter(Category.company_code == current_user.company_code) | |
| if parent_code is not None: | |
| query = query.filter(Category.parent_code == parent_code) | |
| categories = query.order_by(Category.sort_order, Category.id).all() | |
| # 计算每个分类的产品数量 | |
| result = [] | |
| for category in categories: | |
| product_count = db.query(Product).filter( | |
| Product.category_id == category.id | |
| ) | |
| if not is_admin_user(current_user): | |
| product_count = product_count.filter(Product.company_code == current_user.company_code) | |
| result.append(CategoryResponse( | |
| **category.__dict__, | |
| product_count=product_count.count() | |
| )) | |
| return result | |
| async def get_category_tree( | |
| current_user: User = Depends(get_current_user), | |
| db: Session = Depends(get_db) | |
| ): | |
| """获取分类树形结构""" | |
| query = db.query(Category) | |
| if not is_admin_user(current_user): | |
| query = query.filter(Category.company_code == current_user.company_code) | |
| categories = query.order_by(Category.sort_order, Category.id).all() | |
| return build_category_tree(categories, "") | |
| async def get_category( | |
| category_id: int, | |
| current_user: User = Depends(get_current_user), | |
| db: Session = Depends(get_db) | |
| ): | |
| """获取单个分类详情""" | |
| query = db.query(Category).filter(Category.id == category_id) | |
| if not is_admin_user(current_user): | |
| query = query.filter(Category.company_code == current_user.company_code) | |
| category = query.first() | |
| if not category: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail="Category not found" | |
| ) | |
| # 计算产品数量 | |
| product_count = db.query(Product).filter(Product.category_id == category.id) | |
| if not is_admin_user(current_user): | |
| product_count = product_count.filter(Product.company_code == current_user.company_code) | |
| return CategoryResponse( | |
| **category.__dict__, | |
| product_count=product_count.count() | |
| ) | |
| async def create_category( | |
| category: CategoryCreate, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """创建新分类""" | |
| # 检查层级限制(最多三级) | |
| level = get_category_level_by_code(db, category.parent_code, current_user.company_code) | |
| if level >= 3: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="Maximum category level is 3" | |
| ) | |
| # 检查同级分类名称是否已存在 | |
| existing = db.query(Category).filter( | |
| Category.name == category.name, | |
| Category.parent_code == category.parent_code, | |
| Category.company_code == current_user.company_code | |
| ).first() | |
| if existing: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="Category name already exists in the same level" | |
| ) | |
| # 构建编码 | |
| code = build_category_code(db, category.parent_code, current_user.company_code) | |
| # 创建分类 | |
| category_data = category.model_dump() | |
| if not is_admin_user(current_user): | |
| category_data['company_code'] = current_user.company_code | |
| category_data['code'] = code | |
| db_category = Category(**category_data) | |
| db.add(db_category) | |
| db.commit() | |
| db.refresh(db_category) | |
| return CategoryResponse( | |
| **db_category.__dict__, | |
| product_count=0 | |
| ) | |
| async def update_category( | |
| category_id: int, | |
| category_update: CategoryUpdate, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """更新分类""" | |
| query = db.query(Category).filter(Category.id == category_id) | |
| if not is_admin_user(current_user): | |
| query = query.filter(Category.company_code == current_user.company_code) | |
| db_category = query.first() | |
| if not db_category: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail="Category not found" | |
| ) | |
| update_data = category_update.model_dump(exclude_unset=True) | |
| # 检查是否需要更新父分类 | |
| new_parent_code = update_data.get('parent_code', db_category.parent_code) | |
| if new_parent_code != db_category.parent_code: | |
| # 检查层级限制(最多三级) | |
| level = get_category_level_by_code(db, new_parent_code, current_user.company_code) | |
| if level >= 3: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="Maximum category level is 3" | |
| ) | |
| # 检查是否有子分类,如果有则不能改变父分类 | |
| child_count = db.query(Category).filter( | |
| Category.parent_code == db_category.code, | |
| Category.company_code == current_user.company_code | |
| ).count() | |
| if child_count > 0: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="Cannot change parent category of category with children" | |
| ) | |
| # 重新构建编码 | |
| new_code = build_category_code(db, new_parent_code, current_user.company_code) | |
| update_data['code'] = new_code | |
| # 检查新名称是否与同级分类冲突 | |
| new_name = update_data.get('name', db_category.name) | |
| if new_name != db_category.name or new_parent_code != db_category.parent_code: | |
| existing = db.query(Category).filter( | |
| Category.name == new_name, | |
| Category.parent_code == new_parent_code, | |
| Category.company_code == current_user.company_code, | |
| Category.id != category_id | |
| ).first() | |
| if existing: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail="Category name already exists in the same level" | |
| ) | |
| # 更新分类 | |
| for field, value in update_data.items(): | |
| setattr(db_category, field, value) | |
| db.commit() | |
| db.refresh(db_category) | |
| # 计算产品数量 | |
| product_count = db.query(Product).filter(Product.category_id == db_category.id) | |
| if not is_admin_user(current_user): | |
| product_count = product_count.filter(Product.company_code == current_user.company_code) | |
| return CategoryResponse( | |
| **db_category.__dict__, | |
| product_count=product_count.count() | |
| ) | |
| async def delete_category( | |
| category_id: int, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """删除分类""" | |
| query = db.query(Category).filter(Category.id == category_id) | |
| if not is_admin_user(current_user): | |
| query = query.filter(Category.company_code == current_user.company_code) | |
| db_category = query.first() | |
| if not db_category: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail="Category not found" | |
| ) | |
| # 检查是否有子分类 | |
| child_count = db.query(Category).filter( | |
| Category.parent_code == db_category.code, | |
| Category.company_code == current_user.company_code | |
| ).count() | |
| if child_count > 0: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail=f"Cannot delete category with {child_count} child categories" | |
| ) | |
| # 检查是否有产品属于该分类 | |
| product_count = db.query(Product).filter( | |
| Product.category_id == category_id, | |
| Product.company_code == current_user.company_code | |
| ).count() | |
| if product_count > 0: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail=f"Cannot delete category with {product_count} products" | |
| ) | |
| db.delete(db_category) | |
| db.commit() | |
| return None | |