任总 2026-09-28 13:38 放行「4 和 5」→ 落笔最小实现: - 新表 quality_rule_config(39 项:37 规则级 + 2 全局)= 唯一配置源 - 三层解析:账套行 → 全账套模板(entity_id=0) → 代码内置默认(=清单 §7 建议值,零行为差异) - 端点 /api/cma/data-quality/rule-config(GET/PUT)+ /history + /meta:写入仅 ceo/it, platform 级仅 it,演示账套(functional)写禁,变更落 operation_logs 同事务 - 数据质量页新增「规则配置」只读 Tab(懒加载) - 唯一行为变更:污染判定去掉 sync —— 酣客 zxt-sync 系统迁入数据不再被误判(口径可配置) - 出厂默认落库脚本 scripts/seed_dq_rule_config.py(--check/--apply/--rollback,幂等 39/0) - 回归:新套件 35 例 + 存量 1508 passed(唯一 FAILED 为他人未完成 migrate_subjects_entity_id_20260923.py 改动所致,HEAD 干净树同例通过) 生产写(DDL/seed)与 push 均走审批门:DDL=54434656 push=3bd00774
This commit is contained in:
@@ -335,6 +335,104 @@
|
||||
</el-card>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ── Tab3: 规则配置(只读)— ASK-20260928-05 最小实现 ── -->
|
||||
<el-tab-pane label="规则配置" name="rulecfg">
|
||||
<div v-if="cfgLoaded">
|
||||
<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 口径清单 · 任务 ASK-20260928-05)</span>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<el-tag size="small" type="info" effect="plain">只读</el-tag>
|
||||
<el-tag size="small" type="primary" effect="plain">{{ entityLabel }}</el-tag>
|
||||
<el-button @click="loadRuleConfig" :loading="cfgLoading">刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="本轮为只读视图;写权限 ceo/it 经 PUT /api/cma/data-quality/rule-config(同一配置源)"
|
||||
:description="cfgSummary"
|
||||
/>
|
||||
|
||||
<el-table :data="cfgRows" size="small" border class="section-gap">
|
||||
<el-table-column label="规则" width="150">
|
||||
<template #default="{ row }">
|
||||
<span style="font-weight:600;">{{ row.ruleName }}</span>
|
||||
<div style="font-size:11px;color:#999;">{{ row.ruleKey }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="参数" width="180">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.paramKey }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前生效值" min-width="190">
|
||||
<template #default="{ row }">
|
||||
<span class="dq-kv">{{ row.valueText }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small" :type="row.sourceTag">{{ row.sourceText }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开放级别" width="100">
|
||||
<template #default="{ row }">{{ row.openLevelText }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最近修改" width="200">
|
||||
<template #default="{ row }">{{ row.updatedText }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="说明" min-width="260">
|
||||
<template #default="{ row }">{{ row.desc }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="section-gap">
|
||||
<template #header>
|
||||
<span>锁死项(不可配置 — 防「治理规则被配置绕过」的 10 类)</span>
|
||||
</template>
|
||||
<el-table :data="cfgLocked" size="small" border>
|
||||
<el-table-column label="锁死项" min-width="320">
|
||||
<template #default="{ row }">{{ row.item }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="理由" min-width="320">
|
||||
<template #default="{ row }">{{ row.reason }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="section-gap">
|
||||
<template #header>
|
||||
<span>最近变更(operation_logs · 仅 ceo/it 可见)</span>
|
||||
</template>
|
||||
<el-table :data="cfgHistory" size="small" border>
|
||||
<el-table-column label="时刻" width="180">
|
||||
<template #default="{ row }">{{ (row.at || '').replace('T', ' ') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="参数" width="220">
|
||||
<template #default="{ row }">{{ row.rule_key }}.{{ row.param_key }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="改前 → 改后" min-width="220">
|
||||
<template #default="{ row }">
|
||||
{{ cfgFmt(row.before) }} → {{ cfgFmt(row.after) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="理由" min-width="260">
|
||||
<template #default="{ row }">{{ row.reason }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="!cfgHistory.length" style="font-size:12px;color:#909399;margin-top:8px;">
|
||||
暂无变更记录
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 异常明细下钻(2026-09-23 P1):项目铁律 —— 一律用 MyDialog(Element 原生弹窗有已知 bug,禁用) -->
|
||||
@@ -536,6 +634,88 @@ const govDetailPageSize = 50 // 与后端契约一致(默认 50、上限 200
|
||||
const govDetailLoading = ref(false)
|
||||
const govExporting = ref(false)
|
||||
|
||||
// ── 规则配置(只读)— ASK-20260928-05 ──
|
||||
const cfgLoaded = ref(false)
|
||||
const cfgLoading = ref(false)
|
||||
const cfgData = ref<any>({})
|
||||
const cfgHistory = ref<any[]>([])
|
||||
|
||||
function cfgFmt(v: any): string {
|
||||
if (v === null || v === undefined) return '-'
|
||||
if (Array.isArray(v)) return v.length ? v.join(', ') : '(空)'
|
||||
if (typeof v === 'boolean') return v ? '是' : '否'
|
||||
return String(v)
|
||||
}
|
||||
|
||||
const SOURCE_TEXT: Record<string, string> = {
|
||||
entity: '账套覆盖', template: '全账套模板', builtin: '内置默认', 'builtin(global)': '内置默认',
|
||||
}
|
||||
|
||||
const cfgSummary = computed(() => {
|
||||
const d: any = cfgData.value
|
||||
if (!d || !d.entity_id) return ''
|
||||
const parts = [
|
||||
`配置表:${d.table_ready ? '已就绪' : '未建(按内置默认运行)'}`,
|
||||
`配置指纹:${d.config_version || '-'}`,
|
||||
`开放参数:${d.rule_param_count ?? 0} 项规则级 + ${Object.keys(d.global_params || {}).length} 项全局`,
|
||||
`本账套可写:${d.entity_config_enabled ? '是' : '否(演示/测试账套只读)'}`,
|
||||
]
|
||||
return parts.join(' · ')
|
||||
})
|
||||
|
||||
const cfgRows = computed(() => {
|
||||
const d: any = cfgData.value
|
||||
const out: any[] = []
|
||||
if (!d || !d.rules) return out
|
||||
for (const ruleKey of Object.keys(d.rules)) {
|
||||
const rule = d.rules[ruleKey]
|
||||
for (const paramKey of Object.keys(rule.params || {})) {
|
||||
const p = rule.params[paramKey]
|
||||
out.push({
|
||||
ruleKey, ruleName: rule.name, paramKey,
|
||||
valueText: cfgFmt(p.value),
|
||||
sourceText: SOURCE_TEXT[p.source] || p.source,
|
||||
sourceTag: p.source === 'entity' ? 'warning' : (p.source === 'template' ? 'success' : 'info'),
|
||||
openLevelText: p.open_level === 'platform' ? '平台级(仅it)' : '账套级(ceo/it)',
|
||||
updatedText: p.updated_at ? `${(p.updated_at || '').replace('T', ' ')}${p.updated_by ? ' · ' + p.updated_by : ''}` : '-',
|
||||
desc: p.desc || '',
|
||||
})
|
||||
}
|
||||
}
|
||||
for (const paramKey of Object.keys(d.global_params || {})) {
|
||||
const p = d.global_params[paramKey]
|
||||
out.push({
|
||||
ruleKey: 'global', ruleName: '全局项', paramKey,
|
||||
valueText: cfgFmt(p.value),
|
||||
sourceText: SOURCE_TEXT[p.source] || p.source,
|
||||
sourceTag: p.source === 'entity' ? 'warning' : (p.source === 'template' ? 'success' : 'info'),
|
||||
openLevelText: p.open_level === 'platform' ? '平台级(仅it)' : '账套级(ceo/it)',
|
||||
updatedText: p.updated_at ? `${(p.updated_at || '').replace('T', ' ')}${p.updated_by ? ' · ' + p.updated_by : ''}` : '-',
|
||||
desc: p.desc || '',
|
||||
})
|
||||
}
|
||||
return out
|
||||
})
|
||||
|
||||
const cfgLocked = computed(() => cfgData.value?.locked || [])
|
||||
|
||||
async function loadRuleConfig() {
|
||||
cfgLoading.value = true
|
||||
try {
|
||||
cfgData.value = await api.get('/data-quality/rule-config')
|
||||
// 变更历史仅 ceo/it 可见:无权限时静默留空,不影响只读视图
|
||||
try {
|
||||
const h: any = await api.get('/data-quality/rule-config/history', { params: { limit: 10 } })
|
||||
cfgHistory.value = h.items || []
|
||||
} catch (e) {
|
||||
cfgHistory.value = []
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.detail || '加载规则配置失败')
|
||||
}
|
||||
cfgLoading.value = false
|
||||
}
|
||||
|
||||
// 环图颜色一律用**合法 HEX 实值**(ECharts 走 canvas,不解析 CSS 变量,传 CSS 变量会
|
||||
// 回退成黑色 —— 2026-09-24 修复)。取值与主题色一致:财务 #F56C6C / 学习成长 #E6A23C。
|
||||
const CHART_COLORS = {
|
||||
@@ -895,6 +1075,11 @@ function handleTabChange(name: string | number) {
|
||||
govLoaded.value = true
|
||||
runGovernanceCheck()
|
||||
}
|
||||
// Tab3 懒加载:首次切换到"规则配置"(只读)时才请求
|
||||
if (name === 'rulecfg' && !cfgLoaded.value) {
|
||||
cfgLoaded.value = true
|
||||
loadRuleConfig()
|
||||
}
|
||||
}
|
||||
|
||||
async function loadStats() {
|
||||
|
||||
Reference in New Issue
Block a user