feat: 预算按战略地图隔离(map_id) — 切换地图数据区分

问题: 预算数据无map_id, 两地图共用KPI时预算无法区分(切地图数据均显示)
修复:
- budget_plans 加 map_id 字段+索引
- list 支持 map_id 过滤(含NULL历史预算兼容迁移)
- create 收 map_id + 去重键含map_id(同KPI不同地图可各自预算)
- 前端: loadBudget/loadStrategyBudget 传 map_id, 保存带 map_id
- 端到端验证: 地图51 F_REVENUE 300(map_id=51) 地图51显示/地图32不显示 ✓
pytest 35+11 passed, 部署
This commit is contained in:
Hermes CI Fix
2026-08-27 17:33:57 +08:00
parent 3c64dc767e
commit fd814462a2
3 changed files with 15 additions and 6 deletions
+4 -4
View File
@@ -545,7 +545,7 @@ async function loadBudget() {
if (mapCodes.size === 0) { budgetList.value = []; total.value = 0; return }
noMap.value = false; loading.value = true
try {
const params: any = { page: page.value, page_size: pageSize.value, entity_id: getEntityId() }; if (filterYear.value) params.year = filterYear.value; if (filterMonth.value > 0) params.budget_month = filterMonth.value; if (searchKpi.value) params.keyword = searchKpi.value
const params: any = { page: page.value, page_size: pageSize.value, entity_id: getEntityId(), map_id: selectedMapId.value }; if (filterYear.value) params.year = filterYear.value; if (filterMonth.value > 0) params.budget_month = filterMonth.value; if (searchKpi.value) params.keyword = searchKpi.value
const r: any = await budgetApi.list(params); const d = r.data || r || []; const allPlans = (Array.isArray(d) ? d : (d.items || [])) as any[]
// 只保留选中地图关联KPI的预算记录
const plans = allPlans.filter((p: any) => mapCodes.has(p.kpi_code))
@@ -625,7 +625,7 @@ const strategyTree = ref<any[]>([]); const strategyFilterYear = ref(currentYear)
async function loadStrategyBudget() {
if (!selectedMap.value) return
try { const p: any = { budget_year: strategyFilterYear.value, entity_id: getEntityId() }; if (strategyFilterMonth.value > 0) p.budget_month = strategyFilterMonth.value; const r: any = await budgetApi.list(p); const d = r.data || r || []; const plans = (Array.isArray(d) ? d : (d.items || [])) as any[]; strategyAllBudgetPlans.value = plans
try { const p: any = { budget_year: strategyFilterYear.value, entity_id: getEntityId(), map_id: selectedMapId.value }; if (strategyFilterMonth.value > 0) p.budget_month = strategyFilterMonth.value; const r: any = await budgetApi.list(p); const d = r.data || r || []; const plans = (Array.isArray(d) ? d : (d.items || [])) as any[]; strategyAllBudgetPlans.value = plans
let dims = selectedMap.value.dimensions; if (typeof dims === 'string') { try { dims = JSON.parse(dims) } catch { dims = [] } }; if (!Array.isArray(dims) || dims.length === 0) { strategyTree.value = []; return }
const kr: any = await kpiApi.list({ page_size: 100, entity_id: getEntityId() }); const kd = kr.data || kr || []; const km = new Map<string, any>(); (Array.isArray(kd) ? kd : (kd.items || [])).forEach((k: any) => km.set(k.kpi_code, k))
const tree: any[] = []
@@ -640,12 +640,12 @@ function strategySelectDim(dimKey: string) { const dim = strategyTree.value.find
function strategyBatchSetSame() { strategySelectedKpis.value.forEach((k: any) => { k._editValue = strategyBatchValue.value; k._changed = (k._editValue !== (k.budget_value ?? 0)) }) }
async function strategyBatchSave() {
const ts = strategySelectedKpis.value.filter((k: any) => k._changed); if (ts.length === 0) { ElMessage.warning('没有需要保存的变更'); return }; strategyBatchSaving.value = true; let ok = 0; let no = 0
for (const r of ts) { try { if (r.plan_id) { await budgetApi.update(r.plan_id, { budget_value: r._editValue }) } else { const rr: any = await budgetApi.create({ kpi_id: r.kpi_id, period: r.period, budget_value: r._editValue, budget_year: strategyFilterYear.value, budget_month: strategyFilterMonth.value || 1 }); r.plan_id = rr.id }; r.budget_value = r._editValue; r._changed = false; ok++ } catch { no++ } }
for (const r of ts) { try { if (r.plan_id) { await budgetApi.update(r.plan_id, { budget_value: r._editValue }) } else { const rr: any = await budgetApi.create({ kpi_id: r.kpi_id, period: r.period, budget_value: r._editValue, budget_year: strategyFilterYear.value, budget_month: strategyFilterMonth.value || 1, map_id: selectedMapId.value }); r.plan_id = rr.id }; r.budget_value = r._editValue; r._changed = false; ok++ } catch { no++ } }
ElMessage.success(`批量保存完成:${ok} 成功,${no} 失败`); strategyBatchSaving.value = false; loadStrategyBudget()
}
async function saveStrategyKpi(row: any) {
row._saving = true
try { if (row.plan_id) { await budgetApi.update(row.plan_id, { budget_value: row._editValue }) } else { const rr: any = await budgetApi.create({ kpi_id: row.kpi_id, period: row.period, budget_value: row._editValue, budget_year: strategyFilterYear.value, budget_month: strategyFilterMonth.value || 1 }); row.plan_id = rr.id }; row.budget_value = row._editValue; row._changed = false; ElMessage.success('已保存') } catch (e) { ElMessage.error('保存失败') }
try { if (row.plan_id) { await budgetApi.update(row.plan_id, { budget_value: row._editValue }) } else { const rr: any = await budgetApi.create({ kpi_id: row.kpi_id, period: row.period, budget_value: row._editValue, budget_year: strategyFilterYear.value, budget_month: strategyFilterMonth.value || 1, map_id: selectedMapId.value }); row.plan_id = rr.id }; row.budget_value = row._editValue; row._changed = false; ElMessage.success('已保存') } catch (e) { ElMessage.error('保存失败') }
row._saving = false
}