feat: 数据治理 — 入库约束+元数据卡片+编码清洗+审计看板
This commit is contained in:
@@ -44,6 +44,73 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 数据审计看板 -->
|
||||
<el-row :gutter="16" class="section-gap">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never">
|
||||
<template #header>📊 KPI完整度评分</template>
|
||||
<div style="text-align:center;padding:12px 0;">
|
||||
<div :style="{ fontSize: '36px', fontWeight: 700, color: completenessColor }">
|
||||
{{ stats.completeness?.score ?? '-' }}%
|
||||
</div>
|
||||
<div style="font-size:13px;color:#999;margin-top:4px;">
|
||||
完整 {{ stats.completeness?.complete ?? 0 }} / 总计 {{ stats.completeness?.total ?? 0 }}
|
||||
</div>
|
||||
<div style="font-size:12px;color:#f56c6c;margin-top:8px;">
|
||||
缺失元数据: {{ stats.completeness?.missing_metadata ?? 0 }} 个KPI
|
||||
</div>
|
||||
<el-progress
|
||||
:percentage="stats.completeness?.score ?? 0"
|
||||
:stroke-width="12"
|
||||
:color="completenessColor"
|
||||
style="margin-top:12px;"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never">
|
||||
<template #header>📉 缺失率统计</template>
|
||||
<div style="text-align:center;padding:12px 0;">
|
||||
<div style="font-size:36px;font-weight:700;color:#e6a23c;">
|
||||
{{ stats.data_missing?.rate ?? '-' }}%
|
||||
</div>
|
||||
<div style="font-size:13px;color:#999;margin-top:4px;">
|
||||
无数据值的KPI: {{ stats.data_missing?.count ?? 0 }}
|
||||
</div>
|
||||
<div style="font-size:12px;color:#999;margin-top:4px;">
|
||||
总计 {{ stats.data_missing?.total ?? 0 }} 个KPI
|
||||
</div>
|
||||
<el-progress
|
||||
:percentage="stats.data_missing?.rate ?? 0"
|
||||
:stroke-width="12"
|
||||
color="#e6a23c"
|
||||
style="margin-top:12px;"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never">
|
||||
<template #header>⚠️ 超30天未更新预警</template>
|
||||
<div style="text-align:center;padding:12px 0;">
|
||||
<div :style="{ fontSize: '36px', fontWeight: 700, color: staleDataColor }">
|
||||
{{ stats.stale_data?.count ?? 0 }}
|
||||
</div>
|
||||
<div style="font-size:13px;color:#999;margin-top:4px;">
|
||||
个KPI超过 {{ stats.stale_data?.threshold_days ?? 180 }} 天未更新
|
||||
</div>
|
||||
<el-tag v-if="(stats.stale_data?.count ?? 0) > 0" type="danger" size="small" style="margin-top:8px;">
|
||||
建议立即检查数据源
|
||||
</el-tag>
|
||||
<el-tag v-else type="success" size="small" style="margin-top:8px;">
|
||||
数据更新正常
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 异常类型分布 -->
|
||||
<el-row :gutter="16" class="section-gap">
|
||||
<el-col :span="24">
|
||||
@@ -147,6 +214,20 @@ const typeChartOption = computed(() => ({
|
||||
}],
|
||||
}))
|
||||
|
||||
const completenessColor = computed(() => {
|
||||
const s = stats.value.completeness?.score ?? 0
|
||||
if (s >= 80) return '#67c23a'
|
||||
if (s >= 50) return '#e6a23c'
|
||||
return '#f56c6c'
|
||||
})
|
||||
|
||||
const staleDataColor = computed(() => {
|
||||
const c = stats.value.stale_data?.count ?? 0
|
||||
if (c === 0) return '#67c23a'
|
||||
if (c <= 5) return '#e6a23c'
|
||||
return '#f56c6c'
|
||||
})
|
||||
|
||||
async function loadStats() {
|
||||
try { const r: any = await dataQualityApi.stats(); stats.value = r } catch (e) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user