| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- """API - 商品轮播图管理"""
- from fastapi import APIRouter, Depends, HTTPException, Request
- from pydantic import ValidationError
- from sqlalchemy.orm import Session
- from app.core.database import get_db
- from app.core.auth import get_current_user
- from app.core.admin_request_json import parse_admin_request_json
- from app.core.response import success_response, error_response
- from app.crud.product_banner import product_banner
- from app.schemas.product_banner import (
- ProductBannerCreate,
- ProductBannerUpdate,
- ProductBannerSortUpdate,
- )
- router = APIRouter(prefix="/web/admin/product-banners", tags=["商品轮播图管理"])
- def require_admin(current_user: dict = Depends(get_current_user)):
- """验证运营人员权限"""
- if current_user.get("role") not in {"admin", "super_admin"}:
- raise HTTPException(status_code=403, detail="需要运营人员权限")
- return current_user
- @router.get("/product/{product_id}", response_model=dict)
- def list_banners(
- product_id: str,
- db: Session = Depends(get_db),
- current_user: dict = Depends(require_admin)
- ):
- """获取商品的所有轮播图"""
- banners = product_banner.get_by_product(db, product_id)
- return success_response({
- "list": [{
- "id": b.id,
- "productId": b.product_id,
- "mediaType": b.media_type,
- "fileUrl": b.file_url,
- "thumbnailUrl": b.thumbnail_url,
- "sortOrder": b.sort_order,
- "createAt": str(b.create_at) if b.create_at else None
- } for b in banners],
- "total": len(banners)
- })
- @router.post("/product/{product_id}", response_model=dict)
- async def create_banners(
- product_id: str,
- request: Request,
- db: Session = Depends(get_db),
- current_user: dict = Depends(require_admin)
- ):
- """批量添加轮播图(请求体为 JSON 数组;兼容密文信封与 ApiCryptoMiddleware 未改写 body 的场景)"""
- items_raw, err = await parse_admin_request_json(
- request, current_user, source="admin_product_banner"
- )
- if err:
- return error_response(400, err)
- if not isinstance(items_raw, list):
- return error_response(400, "请求体应为轮播图条目数组")
- try:
- items = [ProductBannerCreate.model_validate(x) for x in items_raw]
- except ValidationError as exc:
- return error_response(400, str(exc))
- creator = {"user_id": current_user.get("user_id"), "real_name": current_user.get("real_name")}
- items_data = [item.model_dump() for item in items]
- banners = product_banner.create_batch(db, product_id, items_data, creator)
-
- return success_response({
- "list": [{
- "id": b.id,
- "productId": b.product_id,
- "mediaType": b.media_type,
- "fileUrl": b.file_url,
- "thumbnailUrl": b.thumbnail_url,
- "sortOrder": b.sort_order
- } for b in banners],
- "total": len(banners)
- })
- @router.put("/product/{product_id}/sort", response_model=dict)
- async def update_sort(
- product_id: str,
- request: Request,
- db: Session = Depends(get_db),
- current_user: dict = Depends(require_admin)
- ):
- """更新轮播图排序(兼容密文信封)"""
- data, err = await parse_admin_request_json(
- request, current_user, source="admin_product_banner_sort"
- )
- if err:
- return error_response(400, err)
- if not isinstance(data, dict):
- return error_response(400, "请求体应为 JSON 对象且包含 items")
- try:
- sort_data = ProductBannerSortUpdate.model_validate(data)
- except ValidationError as exc:
- return error_response(400, str(exc))
- items_data = [item.model_dump() for item in sort_data.items]
- product_banner.update_sort(db, items_data)
- return success_response({"message": "排序更新成功"})
- @router.put("/{banner_id}", response_model=dict)
- def update_banner(
- banner_id: str,
- update_data: ProductBannerUpdate,
- db: Session = Depends(get_db),
- current_user: dict = Depends(require_admin)
- ):
- """更新轮播图"""
- banner = product_banner.update(db, banner_id, update_data.model_dump(exclude_unset=True))
- if not banner:
- return error_response(404, "轮播图不存在")
- return success_response({
- "id": banner.id,
- "productId": banner.product_id,
- "mediaType": banner.media_type,
- "fileUrl": banner.file_url,
- "thumbnailUrl": banner.thumbnail_url,
- "sortOrder": banner.sort_order
- })
- @router.delete("/{banner_id}", response_model=dict)
- def delete_banner(
- banner_id: str,
- db: Session = Depends(get_db),
- current_user: dict = Depends(require_admin)
- ):
- """删除轮播图"""
- result = product_banner.delete(db, banner_id)
- if not result:
- return error_response(404, "轮播图不存在")
- return success_response({"message": "删除成功"})
|