feat: OKR模板库改造 — 弹窗模板库联动+时间分解落库+制造业包6个
This commit is contained in:
@@ -97,6 +97,86 @@ def get_objective(obj_id: int, db: Session = Depends(get_db)):
|
||||
}
|
||||
|
||||
|
||||
@router.put("/{okr_id}/decomposition/milestones/{kr_id}")
|
||||
def update_kr_milestones(okr_id: int, kr_id: int, data: dict, db: Session = Depends(get_db)):
|
||||
"""保存KR的月度里程碑(时间分解视图编辑) — 同步更新KR进度"""
|
||||
obj = db.query(Objective).filter(Objective.id == okr_id).first()
|
||||
if not obj:
|
||||
raise HTTPException(404, "OKR不存在")
|
||||
kr = db.query(ActionPlan).filter(
|
||||
ActionPlan.id == kr_id, ActionPlan.objective_id == okr_id
|
||||
).first()
|
||||
if not kr:
|
||||
raise HTTPException(404, "KR不存在或不属于该OKR")
|
||||
milestones = data.get("milestones")
|
||||
if not isinstance(milestones, list):
|
||||
raise HTTPException(400, "milestones 必须是数组")
|
||||
# 规范化:只保留 month/label/status/target 字段
|
||||
normalized = []
|
||||
for ms in milestones:
|
||||
normalized.append({
|
||||
"month": ms.get("month", ""),
|
||||
"label": ms.get("label", ""),
|
||||
"status": ms.get("status", "pending"),
|
||||
"target": ms.get("target"),
|
||||
})
|
||||
kr.monthly_milestones = normalized
|
||||
# 里程碑完成 → KR进度同步更新(完成数/总数)
|
||||
if normalized:
|
||||
done = sum(1 for ms in normalized if ms.get("status") == "completed")
|
||||
kr.progress = round(done / len(normalized) * 100)
|
||||
if kr.progress >= 100:
|
||||
kr.status = "completed"
|
||||
elif kr.status == "completed" and kr.progress < 100:
|
||||
kr.status = "in_progress"
|
||||
db.commit()
|
||||
return {"ok": True, "kr_id": kr.id, "progress": kr.progress, "milestones": kr.monthly_milestones}
|
||||
|
||||
|
||||
@router.post("/{okr_id}/decomposition/milestones/generate")
|
||||
def auto_generate_milestones(okr_id: int, data: dict, db: Session = Depends(get_db)):
|
||||
"""为KR自动生成月度里程碑(按季度剩余月份均分)"""
|
||||
obj = db.query(Objective).filter(Objective.id == okr_id).first()
|
||||
if not obj:
|
||||
raise HTTPException(404, "OKR不存在")
|
||||
kr_id = data.get("kr_id")
|
||||
if not kr_id:
|
||||
raise HTTPException(400, "缺少 kr_id")
|
||||
kr = db.query(ActionPlan).filter(
|
||||
ActionPlan.id == kr_id, ActionPlan.objective_id == okr_id
|
||||
).first()
|
||||
if not kr:
|
||||
raise HTTPException(404, "KR不存在或不属于该OKR")
|
||||
# 重新生成:覆盖已有里程碑(幂等)
|
||||
milestones = _build_auto_milestones(kr)
|
||||
kr.monthly_milestones = milestones
|
||||
db.commit()
|
||||
return {"ok": True, "kr_id": kr.id, "milestones": kr.monthly_milestones}
|
||||
|
||||
|
||||
def _build_auto_milestones(kr: ActionPlan) -> list:
|
||||
"""按截止日期向前均分3个月度里程碑"""
|
||||
base = kr.due_date or datetime.now() + timedelta(days=90)
|
||||
base = base.replace(day=1)
|
||||
# 计算前3个月份(从最早的月份开始)
|
||||
month_keys = []
|
||||
for i in range(3, 0, -1):
|
||||
y, m = base.year, base.month - i
|
||||
while m <= 0:
|
||||
m += 12
|
||||
y -= 1
|
||||
month_keys.append(f"{y:04d}-{m:02d}")
|
||||
return [
|
||||
{
|
||||
"month": mk,
|
||||
"label": f"里程碑{i + 1}",
|
||||
"status": "pending",
|
||||
"target": None,
|
||||
}
|
||||
for i, mk in enumerate(month_keys)
|
||||
]
|
||||
|
||||
|
||||
@router.patch("/{obj_id}")
|
||||
def update_objective(obj_id: int, db: Session = Depends(get_db)):
|
||||
"""更新OKR进度(通过查询ActionPlan自动计算)"""
|
||||
|
||||
Reference in New Issue
Block a user