"""迁移脚本:更新现有战略地图KPI codes + 关联所有活跃KPI到地图""" from app.database import get_engine from sqlalchemy import text import json def migrate(): e = get_engine() with e.begin() as c: # 1. 更新现有地图的dimensions → 使用真实KPI codes maps = c.execute(text('SELECT id, dimensions FROM strategic_maps')).fetchall() for mid, dims_json in maps: if not dims_json: continue dims = json.loads(dims_json) if isinstance(dims_json, str) else dims_json # 定义层→节点名→真实KPI code的映射 name_to_kpi = { # 财务层 "营收目标": ["F_REVENUE"], "净利润率": ["F_NET_PROFIT"], "现金流": ["F_OP_CFLOW"], # 客户层 "客户满意度": ["C_SATISFACTION"], "市场份额": ["C_MARKET_SHARE"], "客户保留率": ["C_RETENTION_RATE"], # 流程层 "运营效率": ["P_DELIVERY"], "质量合格率": ["P_PASS_RATE"], # 学习层 "关键岗位胜任度": ["L_COMPETENCY"], "培训完成率": ["L_TRAINING"], } updated = False for dim in dims: for obj in dim.get("objectives", []): name = obj.get("name", "") if name in name_to_kpi: real_kpis = name_to_kpi[name] if obj.get("kpis") != real_kpis: obj["kpis"] = real_kpis updated = True if updated: c.execute( text("UPDATE strategic_maps SET dimensions = :dims WHERE id = :mid"), {"dims": json.dumps(dims, ensure_ascii=False), "mid": mid}, ) print(f"✅ 地图 {mid}: dimensions KPI codes 已更新") # 2. 将所有活跃KPI的map_id更新为1 result = c.execute( text("UPDATE kpi_definitions SET map_id = 1 WHERE status = 'active' AND (map_id IS NULL OR map_id != 1)") ) affected = result.rowcount print(f"✅ 已更新 {affected} 个活跃KPI的 map_id → 1") # 3. 验证 total = c.execute(text("SELECT COUNT(*) FROM kpi_definitions WHERE status='active' AND map_id = 1")).scalar() print(f"📊 活跃KPI关联到地图1的数量: {total}") kpis_with_data = c.execute(text(""" SELECT k.kpi_code, k.kpi_name FROM kpi_definitions k WHERE EXISTS ( SELECT 1 FROM kpi_values v WHERE v.kpi_id = k.id ) AND k.map_id = 1 ORDER BY k.kpi_code """)).fetchall() print(f"📊 有历史数据的KPI ({len(kpis_with_data)}个):") for r in kpis_with_data: print(f" {r.kpi_code} - {r.kpi_name}") if __name__ == "__main__": migrate()