from fastapi import APIRouter, Depends, HTTPException, File, UploadFile from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, and_ from fastcrud import FastCRUD from pathlib import Path import os import shutil from datetime import datetime from database import get_db from models import SystemSetting, User from schemas import ( SystemSettingCreate, SystemSettingUpdate, SystemSettingResponse, ) from middleware import get_current_user from utils.like_filter import ilike_contains router = APIRouter(prefix="/settings", tags=["settings"]) # 创建FastCRUD实例 setting_crud = FastCRUD(SystemSetting, SystemSettingResponse) # 图片存储目录 UPLOAD_DIR = Path(__file__).parent.parent.parent / "uploads" UPLOAD_DIR.mkdir(exist_ok=True) @router.post("/", response_model=SystemSettingResponse) async def create_setting( setting_data: SystemSettingCreate, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """创建设置项""" # 检查设置键名是否已存在 result = await db.execute(select(SystemSetting).filter(SystemSetting.key == setting_data.key)) existing_setting = result.scalar_one_or_none() if existing_setting: raise HTTPException(status_code=400, detail="设置键名已存在") # 创建设置实例 db_setting = SystemSetting( key=setting_data.key, value=setting_data.value, type=setting_data.type or "string", options=setting_data.options, description=setting_data.description, ) db.add(db_setting) await db.commit() await db.refresh(db_setting) return db_setting @router.get("/", response_model=list[SystemSettingResponse]) async def get_settings( db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """获取所有设置项""" result = await db.execute(select(SystemSetting)) settings = result.scalars().all() return [SystemSettingResponse.model_validate(s) for s in settings] @router.get("/{setting_id}", response_model=SystemSettingResponse) async def get_setting( setting_id: int, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """获取单个设置项""" setting = await setting_crud.get(db, id=setting_id) if not setting: raise HTTPException(status_code=404, detail="设置项不存在") return setting @router.get("/key/{key}", response_model=SystemSettingResponse) async def get_setting_by_key( key: str, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """根据键名获取设置项""" result = await db.execute(select(SystemSetting).filter(SystemSetting.key == key)) setting = result.scalar_one_or_none() if not setting: raise HTTPException(status_code=404, detail="设置项不存在") return setting @router.put("/{setting_id}", response_model=SystemSettingResponse) async def update_setting( setting_id: int, setting_data: SystemSettingUpdate, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """更新设置项""" # 检查设置键名是否被其他设置使用 if setting_data.key: result = await db.execute( select(SystemSetting).filter(SystemSetting.key == setting_data.key, SystemSetting.id != setting_id) ) existing_setting = result.scalar_one_or_none() if existing_setting: raise HTTPException(status_code=400, detail="设置键名已存在") # 准备更新数据 update_data = setting_data.model_dump(exclude_unset=True) # 使用FastCRUD更新设置 updated_setting = await setting_crud.update( db, update_data, id=setting_id, schema_to_select=SystemSettingResponse, return_as_model=True ) if not updated_setting: raise HTTPException(status_code=404, detail="设置项不存在") return updated_setting @router.delete("/{setting_id}") async def delete_setting( setting_id: int, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): """删除设置项""" # 检查设置是否存在 result = await db.execute(select(SystemSetting).filter(SystemSetting.id == setting_id)) existing_setting = result.scalar_one_or_none() if not existing_setting: raise HTTPException(status_code=404, detail="设置项不存在") # 使用FastCRUD删除设置 deleted = await setting_crud.delete(db, id=setting_id) return {"message": "设置项删除成功"} @router.post("/upload") async def upload_image( file: UploadFile = File(...), current_user: User = Depends(get_current_user), ): """上传图片""" # 检查文件类型 if not file.filename or not file.filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp')): raise HTTPException(status_code=400, detail="只支持图片格式(png, jpg, jpeg, gif, webp)") # 检查文件大小(2MB) file_size = 0 chunk = await file.read(1024) while chunk: file_size += len(chunk) if file_size > 2 * 1024 * 1024: raise HTTPException(status_code=400, detail="文件大小不能超过2MB") chunk = await file.read(1024) # 重置文件指针 await file.seek(0) # 生成文件名 timestamp = datetime.now().strftime("%Y%m%d%H%M%S") ext = file.filename.split('.')[-1] filename = f"setting_{timestamp}.{ext}" file_path = UPLOAD_DIR / filename # 保存文件 with open(file_path, "wb") as buffer: shutil.copyfileobj(file.file, buffer) # 返回文件路径 return {"url": f"/uploads/{filename}"}