""" OKR目标管理 API — 季度目标 + 关键结果 + KPI联动 """ from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from sqlalchemy import func from datetime import datetime from typing import Optional from app.database import get_db from app.auth_middleware import require_role from app.models import Objective, ActionPlan router = APIRouter(prefix="/api/cma/okr", tags=["OKR目标管理"], dependencies=[Depends(require_role("ceo", "finance", "it"))], ) @router.get("") def list_objectives( quarter: Optional[str] = Query(None, description="筛选季度: 2026Q3"), dimension: Optional[str] = Query(None), status: Optional[str] = Query(None), db: Session = Depends(get_db), ): """列出OKR目标""" q = db.query(Objective) if quarter: q = q.filter(Objective.quarter == quarter) if dimension: q = q.filter(Objective.dimension == dimension) if status: q = q.filter(Objective.status == status) objs = q.order_by(Objective.quarter.desc(), Objective.id).all() results = [] for o in objs: krs = db.query(ActionPlan).filter(ActionPlan.objective_id == o.id).all() kr_summary = [ {"id": kr.id, "title": kr.title, "status": kr.status, "progress": kr.progress} for kr in krs ] results.append({ "id": o.id, "title": o.title, "description": o.description, "dimension": o.dimension, "quarter": o.quarter, "owner": o.owner, "status": o.status, "progress": o.progress, "confidence": o.confidence, "key_results": kr_summary, "kr_count": len(krs), "kr_completed": sum(1 for kr in krs if kr.status == "completed"), "created_at": o.created_at.isoformat() if o.created_at else None, }) return {"total": len(results), "items": results} @router.post("") def create_objective( title: str = Query(...), quarter: str = Query(...), description: Optional[str] = Query(None), dimension: Optional[str] = Query(None), owner: Optional[str] = Query(None), db: Session = Depends(get_db), ): """创建OKR目标""" obj = Objective(title=title, quarter=quarter, description=description, dimension=dimension, owner=owner) db.add(obj) db.commit() db.refresh(obj) return {"ok": True, "id": obj.id, "title": obj.title} @router.get("/{obj_id}") def get_objective(obj_id: int, db: Session = Depends(get_db)): """获取单个OKR详情""" obj = db.query(Objective).filter(Objective.id == obj_id).first() if not obj: raise HTTPException(404, "目标不存在") krs = db.query(ActionPlan).filter(ActionPlan.objective_id == obj_id).all() return { "objective": { "id": obj.id, "title": obj.title, "description": obj.description, "dimension": obj.dimension, "quarter": obj.quarter, "owner": obj.owner, "status": obj.status, "progress": obj.progress, "confidence": obj.confidence, }, "key_results": [ {"id": kr.id, "title": kr.title, "kpi_id": kr.kpi_id, "status": kr.status, "progress": kr.progress, "due_date": kr.due_date.isoformat() if kr.due_date else None, "assignee": kr.assignee} for kr in krs ] } @router.patch("/{obj_id}") def update_objective(obj_id: int, db: Session = Depends(get_db)): """更新OKR进度(通过查询ActionPlan自动计算)""" obj = db.query(Objective).filter(Objective.id == obj_id).first() if not obj: raise HTTPException(404, "目标不存在") krs = db.query(ActionPlan).filter(ActionPlan.objective_id == obj_id).all() if krs: obj.progress = sum(kr.progress for kr in krs) // len(krs) db.commit() return {"ok": True, "id": obj_id, "progress": obj.progress}