""" System Functions API 系統功能明細 CRUD API """ from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session from sqlalchemy import and_, or_ from app.db.session import get_db from app.models.system_function import SystemFunction from app.schemas.system_function import ( SystemFunctionCreate, SystemFunctionUpdate, SystemFunctionResponse, SystemFunctionListResponse ) from app.api.deps import get_pagination_params from app.schemas.base import PaginationParams router = APIRouter() @router.get("", response_model=SystemFunctionListResponse) def get_system_functions( function_type: Optional[int] = Query(None, description="功能類型 (1:node, 2:function)"), upper_function_id: Optional[int] = Query(None, description="上層功能代碼"), is_mana: Optional[bool] = Query(None, description="系統管理"), is_active: Optional[bool] = Query(None, description="啟用(預設顯示全部)"), search: Optional[str] = Query(None, description="搜尋 (code or name)"), pagination: PaginationParams = Depends(get_pagination_params), db: Session = Depends(get_db), ): """ 取得系統功能列表 - 支援分頁 - 支援篩選 (function_type, upper_function_id, is_mana, is_active) - 支援搜尋 (code or name) """ query = db.query(SystemFunction) # 篩選條件 filters = [] if function_type is not None: filters.append(SystemFunction.function_type == function_type) if upper_function_id is not None: filters.append(SystemFunction.upper_function_id == upper_function_id) if is_mana is not None: filters.append(SystemFunction.is_mana == is_mana) if is_active is not None: filters.append(SystemFunction.is_active == is_active) # 搜尋 if search: filters.append( or_( SystemFunction.code.ilike(f"%{search}%"), SystemFunction.name.ilike(f"%{search}%") ) ) if filters: query = query.filter(and_(*filters)) # 排序 (依照 order 排序) query = query.order_by(SystemFunction.order.asc()) # 計算總數 total = query.count() # 分頁 offset = (pagination.page - 1) * pagination.page_size items = query.offset(offset).limit(pagination.page_size).all() return SystemFunctionListResponse( total=total, items=items, page=pagination.page, page_size=pagination.page_size ) @router.get("/{function_id}", response_model=SystemFunctionResponse) def get_system_function( function_id: int, db: Session = Depends(get_db), ): """ 取得單一系統功能 """ function = db.query(SystemFunction).filter(SystemFunction.id == function_id).first() if not function: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"System function not found: {function_id}" ) return function @router.post("", response_model=SystemFunctionResponse, status_code=status.HTTP_201_CREATED) def create_system_function( function_in: SystemFunctionCreate, db: Session = Depends(get_db), ): """ 建立系統功能 驗證規則: - function_type=1 (node) 時, module_code 不能輸入 - function_type=2 (function) 時, module_code 和 module_functions 為必填 - upper_function_id 必須是 function_type=1 且 is_active=1 的功能, 或 0 (初始層) """ # 驗證 upper_function_id if function_in.upper_function_id > 0: parent = db.query(SystemFunction).filter( SystemFunction.id == function_in.upper_function_id, SystemFunction.function_type == 1, SystemFunction.is_active == True ).first() if not parent: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Invalid upper_function_id: {function_in.upper_function_id} " "(must be function_type=1 and is_active=1)" ) # 檢查 code 是否重複 existing = db.query(SystemFunction).filter(SystemFunction.code == function_in.code).first() if existing: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"System function code already exists: {function_in.code}" ) # 建立資料 db_function = SystemFunction(**function_in.model_dump()) db.add(db_function) db.commit() db.refresh(db_function) return db_function @router.put("/{function_id}", response_model=SystemFunctionResponse) def update_system_function( function_id: int, function_in: SystemFunctionUpdate, db: Session = Depends(get_db), ): """ 更新系統功能 (完整更新) """ # 查詢現有資料 db_function = db.query(SystemFunction).filter(SystemFunction.id == function_id).first() if not db_function: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"System function not found: {function_id}" ) # 更新資料 update_data = function_in.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(db_function, field, value) db.commit() db.refresh(db_function) return db_function @router.patch("/{function_id}", response_model=SystemFunctionResponse) def patch_system_function( function_id: int, function_in: SystemFunctionUpdate, db: Session = Depends(get_db), ): """ 更新系統功能 (部分更新) """ return update_system_function(function_id, function_in, db) @router.delete("/{function_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_system_function( function_id: int, db: Session = Depends(get_db), ): """ 刪除系統功能 (實際上是軟刪除, 設定 is_active=False) """ db_function = db.query(SystemFunction).filter(SystemFunction.id == function_id).first() if not db_function: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"System function not found: {function_id}" ) # 軟刪除 db_function.is_active = False db.commit() return None @router.delete("/{function_id}/hard", status_code=status.HTTP_204_NO_CONTENT) def hard_delete_system_function( function_id: int, db: Session = Depends(get_db), ): """ 永久刪除系統功能 (硬刪除) ⚠️ 警告: 此操作無法復原 """ db_function = db.query(SystemFunction).filter(SystemFunction.id == function_id).first() if not db_function: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"System function not found: {function_id}" ) # 硬刪除 db.delete(db_function) db.commit() return None @router.get("/menu/tree", response_model=List[dict]) def get_menu_tree( is_sysmana: bool = Query(False, description="是否為系統管理公司"), db: Session = Depends(get_db), ): """ 取得功能列表樹狀結構 (用於前端選單顯示) 根據 is_sysmana 過濾功能: - is_sysmana=true: 返回所有功能 (包含 is_mana=true 的系統管理功能) - is_sysmana=false: 只返回 is_mana=false 的一般功能 返回格式: [ { "id": 10, "code": "system_managements", "name": "系統管理後台", "function_type": 1, "order": 100, "function_icon": "", "module_code": null, "module_functions": [], "children": [ { "id": 11, "code": "system_settings", "name": "系統資料設定", "function_type": 2, ... } ] } ] """ # 查詢條件 query = db.query(SystemFunction).filter(SystemFunction.is_active == True) # 如果不是系統管理公司,過濾掉 is_mana=true 的功能 if not is_sysmana: query = query.filter(SystemFunction.is_mana == False) # 排序 functions = query.order_by(SystemFunction.order.asc()).all() # 建立樹狀結構 def build_tree(parent_id: int = 0) -> List[dict]: tree = [] for func in functions: if func.upper_function_id == parent_id: node = { "id": func.id, "code": func.code, "name": func.name, "function_type": func.function_type, "order": func.order, "function_icon": func.function_icon or "", "module_code": func.module_code, "module_functions": func.module_functions or [], "description": func.description or "", "children": build_tree(func.id) if func.function_type == 1 else [] } tree.append(node) return tree return build_tree(0)