"""改善行动计划 API — 管理会计OS""" from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from datetime import datetime from typing import Optional from app.database import get_db from app.auth_middleware import require_role, require_auth from app.models import ActionPlan, KPIAlert, KPIDefinition, User import logging logger = logging.getLogger("cma.action_plans") router = APIRouter(prefix="/api/cma/action-plans", tags=["改善行动"], dependencies=[Depends(require_role("ceo", "finance", "business", "it"))], ) def plan_to_dict(p: ActionPlan) -> dict: return { "id": p.id, "alert_id": p.alert_id, "kpi_id": p.kpi_id, "title": p.title, "description": p.description, "assignee": p.assignee, "priority": p.priority, "due_date": p.due_date.isoformat() if p.due_date else None, "status": p.status, "progress": p.progress or 0, "result": p.result, "created_by": p.created_by, "created_at": p.created_at.isoformat() if p.created_at else None, "updated_at": p.updated_at.isoformat() if p.updated_at else None, } @router.get("") def list_plans( status: Optional[str] = None, kpi_id: Optional[int] = None, alert_id: Optional[int] = None, db: Session = Depends(get_db), current_user: User = Depends(require_auth), ): """获取行动计划列表""" query = db.query(ActionPlan).order_by(ActionPlan.created_at.desc()) if status: query = query.filter(ActionPlan.status == status) if kpi_id: query = query.filter(ActionPlan.kpi_id == kpi_id) if alert_id: query = query.filter(ActionPlan.alert_id == alert_id) # business角色只看自己的 if current_user.role == "business": query = query.filter( (ActionPlan.assignee == current_user.username) | (ActionPlan.assignee == current_user.name) ) plans = query.all() result = [] for p in plans: item = plan_to_dict(p) # 附带KPI名称 kpi = db.query(KPIDefinition).filter(KPIDefinition.id == p.kpi_id).first() item["kpi_name"] = kpi.kpi_name if kpi else "未知KPI" result.append(item) return {"data": result} @router.post("") def create_plan( data: dict, db: Session = Depends(get_db), current_user: User = Depends(require_auth), ): """创建改善行动计划""" required = ["title", "kpi_id"] for field in required: if field not in data: raise HTTPException(400, f"缺少必填字段: {field}") plan = ActionPlan( alert_id=data.get("alert_id"), kpi_id=data["kpi_id"], title=data["title"], description=data.get("description"), assignee=data.get("assignee"), priority=data.get("priority", "medium"), due_date=datetime.fromisoformat(data["due_date"]) if data.get("due_date") else None, status="pending", progress=0, created_by=current_user.name or current_user.username, ) db.add(plan) db.commit() db.refresh(plan) return plan_to_dict(plan) @router.put("/{plan_id}") def update_plan( plan_id: int, data: dict, db: Session = Depends(get_db), ): """更新行动计划""" plan = db.query(ActionPlan).filter(ActionPlan.id == plan_id).first() if not plan: raise HTTPException(404, "计划不存在") if "title" in data: plan.title = data["title"] if "description" in data: plan.description = data["description"] if "assignee" in data: plan.assignee = data["assignee"] if "priority" in data: plan.priority = data["priority"] if "due_date" in data: plan.due_date = datetime.fromisoformat(data["due_date"]) if data["due_date"] else None if "status" in data: plan.status = data["status"] if "progress" in data: plan.progress = max(0, min(100, data["progress"])) if "result" in data: plan.result = data["result"] db.commit() db.refresh(plan) return plan_to_dict(plan) @router.delete("/{plan_id}") def delete_plan(plan_id: int, db: Session = Depends(get_db)): """删除行动计划""" plan = db.query(ActionPlan).filter(ActionPlan.id == plan_id).first() if not plan: raise HTTPException(404, "计划不存在") db.delete(plan) db.commit() return {"message": "已删除"}