#!/usr/bin/env python # -*- coding: utf-8 -*- """ 大屏素材 API 素材分类和素材管理 """ import logging from typing import List from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from online_dev.screen_design.material_schema import ( MaterialCategoryCreateIn, MaterialCategoryUpdateIn, MaterialCategoryOut, MaterialCreateIn, MaterialUpdateIn, MaterialOut, ) from online_dev.screen_design.material_service import MaterialCategoryService, MaterialService logger = logging.getLogger(__name__) router = APIRouter(prefix='/screen/material', tags=['大屏素材']) # ============ 素材分类 API ============ @router.get('/categories', response_model=List[MaterialCategoryOut], summary='素材分类列表') async def list_material_categories(db: AsyncSession = Depends(get_db)): """获取所有素材分类""" categories = await MaterialCategoryService.get_all(db) result = [] for cat in categories: count = await MaterialCategoryService.get_material_count(db, cat.id) result.append(MaterialCategoryOut.from_orm_model(cat, material_count=count)) return result @router.post('/categories', response_model=MaterialCategoryOut, summary='创建素材分类') async def create_material_category( data: MaterialCategoryCreateIn, db: AsyncSession = Depends(get_db), ): """创建素材分类""" # 检查编码是否已存在 if await MaterialCategoryService.check_code_exists(db, data.code): raise HTTPException(status_code=400, detail=f"分类编码 {data.code} 已存在") category = await MaterialCategoryService.create(db, data) await db.commit() return MaterialCategoryOut.from_orm_model(category, material_count=0) @router.put('/categories/{category_id}', response_model=MaterialCategoryOut, summary='更新素材分类') async def update_material_category( category_id: str, data: MaterialCategoryUpdateIn, db: AsyncSession = Depends(get_db), ): """更新素材分类""" category = await MaterialCategoryService.get_by_id(db, category_id) if not category: raise HTTPException(status_code=404, detail="分类不存在") category = await MaterialCategoryService.update(db, category_id, data) await db.commit() count = await MaterialCategoryService.get_material_count(db, category.id) return MaterialCategoryOut.from_orm_model(category, material_count=count) @router.delete('/categories/{category_id}', summary='删除素材分类') async def delete_material_category( category_id: str, db: AsyncSession = Depends(get_db), ): """删除素材分类(同时删除分类下的所有素材)""" category = await MaterialCategoryService.get_by_id(db, category_id) if not category: raise HTTPException(status_code=404, detail="分类不存在") await MaterialCategoryService.delete_with_materials(db, category_id) await db.commit() return {'success': True} # ============ 素材 API ============ async def _get_file_info(db: AsyncSession, file_id: str): """获取文件信息""" file_url = '' file_type = 'image' file_size = 0 if file_id: try: from core.file_manager.model import FileManager stmt = select(FileManager).where(FileManager.id == file_id) file_result = await db.execute(stmt) file_obj = file_result.scalar_one_or_none() if file_obj: file_url = file_obj.url or '' file_size = file_obj.size or 0 file_ext = (file_obj.file_ext or '').lower() file_type = 'svg' if file_ext == 'svg' or file_ext == '.svg' else 'image' except Exception as e: logger.warning(f"获取文件信息失败: {e}") return file_url, file_type, file_size @router.get('/list', response_model=List[MaterialOut], summary='素材列表') async def list_materials( category_id: str = Query(default=None, alias="categoryId", description="分类ID"), db: AsyncSession = Depends(get_db), ): """获取素材列表""" materials = await MaterialService.get_list_by_category(db, category_id) result = [] for material in materials: # 获取分类名称 category_name = '' if material.category_id: category = await MaterialCategoryService.get_by_id(db, material.category_id) if category: category_name = category.name # 获取文件信息 file_url, file_type, file_size = await _get_file_info(db, material.file_id) result.append(MaterialOut.from_orm_model( material, category_name=category_name, file_url=file_url, file_type=file_type, file_size=file_size, )) return result @router.post('/create', response_model=MaterialOut, summary='创建素材') async def create_material( data: MaterialCreateIn, db: AsyncSession = Depends(get_db), ): """创建素材(关联已上传的文件)""" # 验证分类(category_id 为空时表示无分类素材) category = None if data.category_id: category = await MaterialCategoryService.get_by_id(db, data.category_id) if not category: raise HTTPException(status_code=400, detail="分类不存在") # 验证文件 try: from core.file_manager.model import FileManager stmt = select(FileManager).where(FileManager.id == data.file_id) file_result = await db.execute(stmt) file_obj = file_result.scalar_one_or_none() if not file_obj: raise HTTPException(status_code=400, detail="文件不存在") except HTTPException: raise except Exception as e: raise HTTPException(status_code=400, detail=f"验证文件失败: {e}") # 创建素材 material = await MaterialService.create(db, data) await db.commit() # 获取文件信息 file_url = file_obj.url or '' file_size = file_obj.size or 0 file_ext = (file_obj.file_ext or '').lower() file_type = 'svg' if file_ext == 'svg' or file_ext == '.svg' else 'image' return MaterialOut.from_orm_model( material, category_name=category.name if category else '', file_url=file_url, file_type=file_type, file_size=file_size, ) @router.put('/{material_id}', response_model=MaterialOut, summary='更新素材') async def update_material( material_id: str, data: MaterialUpdateIn, db: AsyncSession = Depends(get_db), ): """更新素材信息""" material = await MaterialService.get_by_id(db, material_id) if not material: raise HTTPException(status_code=404, detail="素材不存在") # 如果更新分类,验证分类存在 if data.category_id: category = await MaterialCategoryService.get_by_id(db, data.category_id) if not category: raise HTTPException(status_code=400, detail="分类不存在") material = await MaterialService.update(db, material_id, data) await db.commit() # 获取分类名称 category_name = '' if material.category_id: category = await MaterialCategoryService.get_by_id(db, material.category_id) if category: category_name = category.name # 获取文件信息 file_url, file_type, file_size = await _get_file_info(db, material.file_id) return MaterialOut.from_orm_model( material, category_name=category_name, file_url=file_url, file_type=file_type, file_size=file_size, ) @router.delete('/{material_id}', summary='删除素材') async def delete_material( material_id: str, db: AsyncSession = Depends(get_db), ): """删除素材""" material = await MaterialService.get_by_id(db, material_id) if not material: raise HTTPException(status_code=404, detail="素材不存在") await MaterialService.delete(db, material_id) await db.commit() return {'success': True} @router.delete('/batch', summary='批量删除素材') async def batch_delete_materials( ids: List[str] = Query(..., description="素材ID列表"), db: AsyncSession = Depends(get_db), ): """批量删除素材""" count = await MaterialService.batch_delete(db, ids) await db.commit() return {'count': count}