feat: OKR模板库改造 — 弹窗模板库联动+时间分解落库+制造业包6个

This commit is contained in:
Hermes CI Fix
2026-08-11 00:11:25 +08:00
parent 32fe3e4d50
commit 0b191d278e
7 changed files with 413 additions and 8 deletions
+30
View File
@@ -155,9 +155,39 @@ def create_plan(
db.add(plan)
db.commit()
db.refresh(plan)
# OKR时间分解:KR创建时自动生成3个月度里程碑(按截止日期向前均分)
if due_date and not plan.monthly_milestones:
try:
plan.monthly_milestones = _auto_build_milestones(due_date)
db.commit()
except Exception:
db.rollback() # 里程碑生成失败不影响KR创建
db.refresh(plan)
return plan_to_dict(plan)
def _auto_build_milestones(due_date: datetime) -> list:
"""按截止日期向前均分3个月度里程碑"""
base = due_date.replace(day=1)
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.put("/{plan_id}")
def update_plan(
plan_id: int,
+80
View File
@@ -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自动计算)"""