feat: 战略地图收尾 — 自动保存+导出+表迁移+因果链推荐

This commit is contained in:
Hermes CI Fix
2026-07-14 17:32:22 +08:00
parent 5594a572e9
commit 9afcea8f8d
18 changed files with 207 additions and 59 deletions
+55 -7
View File
@@ -4,7 +4,7 @@ from sqlalchemy.orm import Session
from typing import Optional
from app.database import get_db
from app.auth_middleware import require_auth, require_role
from app.models import StrategicMap, OperationLog
from app.models import StrategicMap, OperationLog, MapObjective
import json
router = APIRouter(prefix="/api/cma/maps", tags=["战略地图"],
@@ -62,7 +62,7 @@ STRATEGIC_MAP_TEMPLATE = [
@router.get("")
def list_maps(db: Session = Depends(get_db)):
maps = db.query(StrategicMap).order_by(StrategicMap.updated_at.desc()).all()
return {"data": [m_to_dict(m) for m in maps]}
return {"data": [m_to_dict(m, db) for m in maps]}
@router.post("")
def create_map(data: dict, db: Session = Depends(get_db)):
@@ -70,7 +70,8 @@ def create_map(data: dict, db: Session = Depends(get_db)):
db.add(m)
db.commit()
db.refresh(m)
return m_to_dict(m)
_sync_map_objectives(m, db)
return m_to_dict(m, db)
@router.post("/create-with-template")
@@ -86,7 +87,8 @@ def create_map_with_template(data: dict, db: Session = Depends(get_db)):
db.add(m)
db.commit()
db.refresh(m)
return m_to_dict(m)
_sync_map_objectives(m, db)
return m_to_dict(m, db)
@router.put("/{map_id}")
@@ -101,12 +103,14 @@ def update_map(map_id: int, data: dict, db: Session = Depends(get_db)):
setattr(m, k, v)
db.commit()
# 同步目标到map_objectives表
_sync_map_objectives(m, db)
# ├─ 版本管理: draft → published 时自动创建快照
if old_status == "draft" and m.status == "published":
_auto_snapshot(m, db)
return m_to_dict(m)
return m_to_dict(m, db)
# ── 删除地图 ─────────────────────────────────
@@ -259,8 +263,52 @@ def _auto_snapshot(m: StrategicMap, db: Session):
# ── 工具函数 ─────────────────────────────────
def m_to_dict(m):
return {c.name: getattr(m, c.name) for c in m.__table__.columns}
def m_to_dict(m, db: Session = None):
d = {c.name: getattr(m, c.name) for c in m.__table__.columns}
if db:
_merge_map_objectives(m, db)
d["dimensions"] = m.dimensions
return d
def _sync_map_objectives(m, db):
"""保存时:将dimensions JSON中的目标同步到map_objectives表"""
db.query(MapObjective).filter(MapObjective.map_id == m.id).delete()
dims = m.dimensions
if isinstance(dims, str):
dims = json.loads(dims)
for dim in dims:
for i, obj in enumerate(dim.get("objectives", [])):
mo = MapObjective(
map_id=m.id,
dimension_key=dim.get("key", ""),
name=obj.get("name", ""),
description=obj.get("description", ""),
icon=obj.get("icon", "target"),
sort_order=i,
)
db.add(mo)
db.commit()
def _merge_map_objectives(m, db):
"""读取时:将map_objectives表的数据合并进dimensions JSON"""
objs = db.query(MapObjective).filter(MapObjective.map_id == m.id).order_by(MapObjective.sort_order).all()
if not objs:
return
dims = m.dimensions
if isinstance(dims, str):
dims = json.loads(dims)
# 按dimension_key分组
from collections import defaultdict
grouped = defaultdict(list)
for o in objs:
grouped[o.dimension_key].append(o)
for dim in dims:
key = dim.get("key", "")
if key in grouped:
dim["objectives"] = [{"name": o.name, "description": o.description or "", "icon": o.icon or "target"} for o in grouped[key]]
m.dimensions = dims
# ── 战略回顾会 聚合接口 ──────────────────────