feat: KPI通用化 — 五档评分/三级分解树/因果链追踪

This commit is contained in:
Hermes CI Fix
2026-07-19 10:21:00 +08:00
parent c57f377e04
commit 2d471aa07b
4 changed files with 355 additions and 1 deletions
+51
View File
@@ -93,6 +93,29 @@
</el-table>
</el-tab-pane>
<el-tab-pane label="层级分解" name="hierarchy">
<div v-loading="hierarchyLoading">
<el-alert title="KPI三级分解树:公司级 → 部门级 → 个人级" type="info" show-icon :closable="false" style="margin-bottom:12px;" />
<div v-if="hierarchyTree.length === 0" class="network-empty">暂无层级分解数据</div>
<el-tree v-else :data="hierarchyTree" :props="hierarchyProps" node-key="id" default-expand-all highlight-current>
<template #default="{ node, data }">
<span class="hierarchy-node">
<el-tag :type="hierarchyLevelTag(data.level)" size="small" style="margin-right:8px;">
{{ data.level === 1 ? '公司级' : data.level === 2 ? '部门级' : '个人级' }}
</el-tag>
<b>{{ data.kpi_name }}</b>
<span style="color:#999;margin-left:8px;font-size:12px;">{{ data.kpi_code }}</span>
<el-tag v-if="data.dimension" :type="hierarchyDimTag(data.dimension)" size="small" style="margin-left:6px;">
{{ hierarchyDimLabel(data.dimension) }}
</el-tag>
<span v-if="data.child_name" style="margin-left:8px;color:#409eff;font-size:12px;">· {{ data.child_name }}</span>
<span v-if="data.weight" style="margin-left:6px;color:#e6a23c;font-size:12px;">权重:{{ data.weight }}%</span>
</span>
</template>
</el-tree>
</div>
</el-tab-pane>
<el-tab-pane label="因果链" name="causality">
<div v-loading="networkLoading">
<el-row :gutter="16">
@@ -237,6 +260,32 @@ const fullNetworkNodes = ref<any[]>([])
const fullNetworkEdges = ref<any[]>([])
const fullNetworkLoading = ref(false)
// 层级分解
const hierarchyTree = ref<any[]>([])
const hierarchyLoading = ref(false)
const hierarchyProps = { children: 'children', label: 'kpi_name' }
function hierarchyLevelTag(level: number) {
return level === 1 ? 'success' : level === 2 ? 'warning' : 'info'
}
function hierarchyDimTag(d: string) {
return ({ finance: '', customer: 'success', process: 'warning', learning: 'info' } as any)[d] || ''
}
function hierarchyDimLabel(d: string) {
return ({ finance: '财务', customer: '客户', process: '流程', learning: '学习' } as any)[d] || d
}
async function loadHierarchy() {
hierarchyLoading.value = true
try {
const r: any = await kpiApi.hierarchy({ entity_id: 1, kpi_id: kpi.value?.id })
hierarchyTree.value = r.tree || []
} catch (e) {
console.error('层级分解加载失败', e)
}
hierarchyLoading.value = false
}
const CAT_MAP: Record<string, string> = {
revenue_growth: '收入增长', profitability: '盈利水平', cost_control: '成本费用',
asset_efficiency: '资产效率', cash_risk: '现金流风控',
@@ -513,6 +562,8 @@ onMounted(async () => {
} catch(e) {}
// 加载因果链
await loadCausality(Number(route.params.id))
// 加载层级分解
await loadHierarchy()
// 加载KPI列表(用于模拟推演选择器)
try {
const kr: any = await kpiApi.list({ page_size: 100 })