Phase 1: OKR模板 — 两步弹窗(O+KR结构) + 14个CMA模板 + okr_templates表 + API
MapCanvasDialogs.vue: - 节点编辑弹窗改为两步交互(模板选择→O+KR编辑) - 第一步:按维度展示对应模板(财务4/客户3/流程4/学习3) - 第二步:编辑O名称+描述+3个KR(名称/目标值/权重) - 14个CMA标准模板硬编码在前端 - 支持添加/删除KR、自定义目标跳过模板 MapCanvas.vue: - 传递 editingLayerKey 到弹窗 - onSaveDialog 适配新 O+KR 数据结构 - onNodeSave 存储 krs 和 template_name 字段 Backend: - OKRTemplate 模型 (okr_templates 表) - okr_templates API: GET(按维度筛选) + POST(用户自定义) + increment use_count - seed_okr_templates.py 迁移脚本(建表+14条种子数据) - 在 main.py 注册新路由
This commit is contained in:
@@ -13,7 +13,7 @@ from app.models import (
|
||||
User, StrategicMap, KPIDefinition, KPITemplate, KPIValue,
|
||||
DataSourceConfig, KPIAlert, OperationLog, NotificationChannel,
|
||||
NotificationLog, RolePermission, ActionPlan, OrgNode,
|
||||
StrategicMapVersion, MapObjective,
|
||||
StrategicMapVersion, MapObjective, Objective,
|
||||
)
|
||||
from app.models.budget_plan import BudgetPlan
|
||||
from app.models.cost_model import StandardCost, ActualCost, AbcActivity, AbcAllocation
|
||||
@@ -451,6 +451,21 @@ def bot_query(
|
||||
for c in sc
|
||||
]
|
||||
|
||||
if q in ("okr", "all"):
|
||||
objs = db.query(Objective).filter(Objective.status == "active").all()
|
||||
result["okr"] = []
|
||||
for o in objs:
|
||||
krs = db.query(ActionPlan).filter(ActionPlan.objective_id == o.id).all()
|
||||
result["okr"].append({
|
||||
"id": o.id, "title": o.title, "quarter": o.quarter,
|
||||
"dimension": o.dimension, "progress": o.progress,
|
||||
"confidence": o.confidence,
|
||||
"key_results": [
|
||||
{"title": kr.title, "status": kr.status, "progress": kr.progress}
|
||||
for kr in krs
|
||||
]
|
||||
})
|
||||
|
||||
if q in ("actions", "all"):
|
||||
acts = db.query(ActionPlan).limit(30).all()
|
||||
result["actions"] = [
|
||||
@@ -526,6 +541,44 @@ def bot_import_excel(
|
||||
|
||||
# ── 自然语言查询 ──
|
||||
|
||||
@router.post("/okr/create")
|
||||
def bot_okr_create(
|
||||
title: str = Query(...),
|
||||
quarter: str = Query(...),
|
||||
dimension: Optional[str] = Query(None),
|
||||
bot: dict = Depends(verify_bot_key),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Bot创建OKR目标"""
|
||||
from app.models import Objective
|
||||
obj = Objective(title=title, quarter=quarter, dimension=dimension, owner=bot["name"])
|
||||
db.add(obj)
|
||||
db.commit()
|
||||
db.refresh(obj)
|
||||
return {"ok": True, "id": obj.id, "title": obj.title, "confidence": obj.confidence}
|
||||
|
||||
|
||||
@router.get("/okr/list")
|
||||
def bot_okr_list(
|
||||
quarter: Optional[str] = Query(None),
|
||||
bot: dict = Depends(verify_bot_key),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""Bot列出OKR(含KR进度)"""
|
||||
from app.models import Objective
|
||||
q = db.query(Objective)
|
||||
if quarter:
|
||||
q = q.filter(Objective.quarter == quarter)
|
||||
objs = q.order_by(Objective.quarter.desc()).all()
|
||||
return {"total": len(objs), "items": [
|
||||
{"id": o.id, "title": o.title, "quarter": o.quarter,
|
||||
"dimension": o.dimension, "progress": o.progress,
|
||||
"confidence": o.confidence, "status": o.status,
|
||||
"kr_count": db.query(func.count(ActionPlan.id)).filter(ActionPlan.objective_id == o.id).scalar() or 0}
|
||||
for o in objs
|
||||
]}
|
||||
|
||||
|
||||
@router.get("/nlp")
|
||||
def bot_nlp(
|
||||
intent: str = Query("overview"),
|
||||
@@ -544,6 +597,7 @@ def bot_nlp(
|
||||
"成本": "cost", "成本分析": "cost",
|
||||
"战略": "maps", "战略地图": "maps",
|
||||
"行动": "actions", "改善": "actions",
|
||||
"okr": "okr", "目标": "okr", "季度目标": "okr",
|
||||
}
|
||||
resolved = m.get(intent, intent)
|
||||
return bot_query(q=resolved, bot=bot, db=db)
|
||||
|
||||
Reference in New Issue
Block a user