fix(strategy-map): 战略地图三处 P1 缺陷(D1 完备度路由 422 / D2 连线删除不落库 / D3 窄屏拖拽失效)

D1 GET /api/cma/maps/completeness/objectives 恒 422:真抢占者是先注册的
   objectives.router GET /{map_id}/objectives(map_id 被当 int 解析)。把
   map_completeness / map_summary 两个字面路径路由器前移到 objectives 之前,
   不动 prefix、不删参数化路由。新增同前缀族全量巡检用例。

D2 DELETE /{id}/connections 返回 200 不落库:canvas_data 为裸 Column(JSON),
   就地/换列表赋值不被 ORM 判脏。模型改 MutableDict.as_mutable(JSON)(不改 DDL),
   add_connection / delete_connection_by_key 均显式 flag_modified 双保险。

D3 窄视口 .kp-panel(fixed/z-1000) 遮画布,onTreeDragOver 用 elementFromPoint
   取节点恒 null ⇒ 拖拽建连线失效。改为遍历画布内 [data-node-key] 做 rect 包含
   判定、多点取中心最近者,不再回退 elementFromPoint。

测试:新增 backend/tests/test_map_route_shadowing_20261020.py(路由解析断言到
endpoint.__module__)与 test_map_connection_persistence_20261020.py(新 session
原生 SQL 复读 + 负测)。零生产写、零上线。
This commit is contained in:
Hermes CI Fix
2026-10-21 02:04:28 +08:00
parent 86e24c6310
commit b736e0727a
6 changed files with 275 additions and 5 deletions
+5 -2
View File
@@ -41,6 +41,11 @@ app.include_router(kpis.router)
app.include_router(kpi_governance.router)
app.include_router(templates.router)
app.include_router(maps.router)
# 顺序铁律(2026-10-20 D1 修复):同前缀族的路由必须把**字面路径段**路由器 include 在
# 任何 `/{map_id}/<literal>` 参数化路由(objectives.router 的 GET /{map_id}/objectives)之前,
# 否则 /api/cma/maps/completeness/objectives 会被判 map_id="completeness" → 恒 422。
app.include_router(map_completeness.router) # 战略地图数据完备度(口径 CMA-CALIBER-MAP-COMPLETENESS-20261018 v1.0)
app.include_router(map_summary.router) # 战略地图摘要条(收入分线/新式毛利率/管理指标 · 口径 CMA-A1 终稿)
app.include_router(dashboard.router)
app.include_router(data.router)
app.include_router(alerts.router)
@@ -56,8 +61,6 @@ app.include_router(action_plans.router)
app.include_router(alignment.router)
app.include_router(org.router)
app.include_router(objectives.router)
app.include_router(map_completeness.router) # 战略地图数据完备度(口径 CMA-CALIBER-MAP-COMPLETENESS-20261018 v1.0)
app.include_router(map_summary.router) # 战略地图摘要条(收入分线/新式毛利率/管理指标 · 口径 CMA-A1 终稿)
app.include_router(versions.router)
app.include_router(budget.router)
app.include_router(value_sources.router)