feat: DAMA数据治理规则检查(财务七规则)— 后端/check-governance + 前端数据质量中心升级

后端 backend/app/api/data_quality.py:
- 新增 GET /api/cma/data-quality/check-governance?entity_id= 端点
- 7条规则: unit_check单位校验/dup_alert重复预警/orphan_check孤儿预警/virtual_pollution虚拟污染/entity_check实体归属/kpi_completeness KPI完整性/reconciliation勾稽验证
- 质量评分: error扣10/warning扣5, 每条规则最多扣一次, 最低0分
- 兼容实体筛选(0全部/1酣客/2博海), 向后兼容既有/check端点

前端 frontend/src/api/index.ts + views/DataQuality.vue:
- dataQualityApi.checkGovernance() 新增
- 页面新增治理规则区: 质量评分仪表盘 + 7规则红黄绿状态表 + 异常明细展开 + 重新检查按钮 + 实体筛选
This commit is contained in:
Hermes CI Fix
2026-08-30 07:26:59 +08:00
parent 240a9fa899
commit c36ed35348
3 changed files with 325 additions and 1 deletions
+2
View File
@@ -344,6 +344,8 @@ export const dataQualityApi = {
logs: (params?: any) => api.get('/data-quality/logs', { params }),
updateLog: (id: number, data: any) => api.put(`/data-quality/logs/${id}`, data),
deleteLog: (id: number) => api.delete(`/data-quality/logs/${id}`),
// DAMA数据治理规则检查(财务七规则)
checkGovernance: (params?: any) => api.get('/data-quality/check-governance', { params }),
}
export const biReportApi = {
+128
View File
@@ -121,6 +121,80 @@
</el-col>
</el-row>
<!-- DAMA 数据治理规则检查财务七规则 -->
<el-card shadow="never" class="section-gap">
<template #header>
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px;">
<span>🛡 DAMA数据治理规则检查财务七规则</span>
<div>
<el-select v-model="govEntity" style="width:130px;margin-right:8px;" @change="runGovernanceCheck">
<el-option label="全部实体" :value="0" />
<el-option label="酣客" :value="1" />
<el-option label="博海" :value="2" />
</el-select>
<el-button type="primary" @click="runGovernanceCheck" :loading="govChecking">重新检查</el-button>
</div>
</div>
</template>
<el-row :gutter="16">
<el-col :span="6">
<div style="text-align:center;padding:20px 0;">
<el-progress type="dashboard" :percentage="govScore" :color="govScoreColor" :width="150">
<template #default>
<div style="font-size:32px;font-weight:700;line-height:1.2;">{{ govScore }}</div>
<div style="font-size:12px;color:#999;">质量评分</div>
</template>
</el-progress>
<div style="font-size:12px;color:#999;margin-top:10px;line-height:1.8;">
检查时间: {{ govCheckedAt || '-' }}<br />
通过 {{ govPassedCount }} / {{ govIssues.length }} 条规则
</div>
</div>
</el-col>
<el-col :span="18">
<el-table :data="govIssues" size="small" border>
<el-table-column type="expand">
<template #default="{ row }">
<div style="padding:10px 18px;background:#fafafa;">
<div v-if="row.detail && row.detail.length" style="font-size:12px;line-height:24px;color:#606266;">
<div v-for="(d, i) in row.detail" :key="i"> {{ d }}</div>
</div>
<div v-else style="font-size:12px;color:#67c23a;"> 未发现异常</div>
</div>
</template>
</el-table-column>
<el-table-column label="状态" width="80">
<template #default="{ row }">
<el-tag :type="govRuleStatus(row)" size="small">{{ govRuleStatusText(row) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="规则" width="160">
<template #default="{ row }">
<span style="font-weight:600;">{{ govRuleName(row.rule) }}</span>
<div style="font-size:11px;color:#999;">{{ row.rule }}</div>
</template>
</el-table-column>
<el-table-column label="检查内容" min-width="240">
<template #default="{ row }">{{ govRuleDesc(row.rule) }}</template>
</el-table-column>
<el-table-column label="级别" width="80">
<template #default="{ row }">
<el-tag :type="row.level === 'error' ? 'danger' : 'warning'" size="small">
{{ row.level === 'error' ? '异常' : '警告' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="异常数" width="90">
<template #default="{ row }">
<span :style="{ color: row.count > 0 ? '#f56c6c' : '#67c23a', fontWeight: 600 }">{{ row.count }}</span>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</el-card>
<!-- 质量日志列表 -->
<el-card shadow="never">
<template #header>
@@ -199,6 +273,14 @@ const checking = ref(false)
const filterSeverity = ref('')
const filterStatus = ref('')
// DAMA 数据治理规则检查状态
const govScore = ref(0)
const govIssues = ref<any[]>([])
const govCheckedAt = ref('')
const govEntity = ref(0)
const govChecking = ref(false)
const govRuleMeta = ref<any>({})
const typeChartOption = computed(() => ({
tooltip: { trigger: 'item' },
series: [{
@@ -228,6 +310,33 @@ const staleDataColor = computed(() => {
return '#f56c6c'
})
// ── DAMA治理规则 computed ──
const govPassedCount = computed(() => govIssues.value.filter((i: any) => i.count === 0).length)
const govScoreColor = computed(() => {
if (govScore.value >= 90) return '#67c23a'
if (govScore.value >= 60) return '#e6a23c'
return '#f56c6c'
})
function govRuleStatus(row: any) {
if (row.count > 0) return row.level === 'error' ? 'danger' : 'warning'
return 'success'
}
function govRuleStatusText(row: any) {
if (row.count > 0) return row.level === 'error' ? '异常' : '警告'
return '通过'
}
function govRuleName(rule: string) {
return govRuleMeta.value?.[rule]?.name || rule
}
function govRuleDesc(rule: string) {
return govRuleMeta.value?.[rule]?.desc || ''
}
async function loadStats() {
try { const r: any = await dataQualityApi.stats(); stats.value = r } catch (e) {}
}
@@ -257,6 +366,24 @@ async function runCheck() {
checking.value = false
}
async function runGovernanceCheck() {
govChecking.value = true
try {
const params: any = {}
if (govEntity.value) params.entity_id = govEntity.value
const r: any = await dataQualityApi.checkGovernance(params)
govScore.value = r.score ?? 0
govIssues.value = r.issues || []
govCheckedAt.value = (r.checked_at || '').replace('T', ' ').slice(0, 19)
govRuleMeta.value = r.rules_meta || {}
const bad = (r.issues || []).filter((i: any) => i.count > 0).length
ElMessage.success(`治理检查完成: 评分${r.score}分, 异常规则${bad}`)
} catch (e: any) {
ElMessage.error(e?.response?.data?.detail || '治理检查失败')
}
govChecking.value = false
}
async function updateStatus(id: number, status: string) {
try {
await dataQualityApi.updateLog(id, { status })
@@ -269,6 +396,7 @@ async function updateStatus(id: number, status: string) {
onMounted(() => {
loadStats()
loadLogs()
runGovernanceCheck()
})
</script>