Commit 90e89ed5 authored by Data Governance Dev's avatar Data Governance Dev

feat(backend+web): 自定义规则每条独立 tab + 默认名「自定义规则N」

两个用户反馈:

1) 自定义规则命中明细:原来 N 条规则塞进 1 个 tab,规则一多翻不到。
   改为每条规则单独占 1 个 tab:
     - key = custom_value_check_<idx>(idx 从 1 开始,与前端卡片顺序一致)
     - title = <rule_name>(<table>.<column>)
     - summary alert:成功显示"本规则命中 N 行";失败显示"执行失败:**错误**"(红 alert)
     - table source = this.matches_rule_<idx>(扁平命名)
   失败规则也出 tab(alert 显示错误),用户能直接看到为什么失败。

2) 新建自定义规则时输入框默认「自定义规则N」,N 从已用编号集合里找最小可用,
   用户手动改名后 N 仍递增不会撞名。

数据 / 前端配套:
- 后端 data 顶层加 matches_rule_<idx> / error_rule_<idx> / matched_rule_<idx> 三组扁平字段
- 为什么不走 dict 索引(this.by_rule['rule_X']):前端 evalPathExpr 是简单属性路径
  (this.x.y.z),不识别 [key] 语法,扁平命名最干净
- 前端 flatResultRows 识别 custom_value_check_<idx> 前缀的 tab:命中数从
  matched_rule_<idx> 取,检查数固定 1(每条规则 = 1 个字段)

静态验证(mock 两条规则,1 ok + 1 ORA-00933 失败)已通过:
  tabs: [
    {key:custom_value_check_1, type:info,  vars:{matched:this.matched_rule_1}},
    {key:custom_value_check_2, type:error, vars:{error:this.error_rule_2}}
  ]

WORKLOG 待用户在 Oracle 端实跑自定义规则验证后追加(不阻塞提交)
parent f4903d81
This diff is collapsed.
......@@ -1383,16 +1383,29 @@
if (!matched) continue;
matchedStepIds.add(c.step_id);
for (const t of matched) {
// 2026-08-13:自定义规则的每个 tab 是 1 条规则
// 「违规」= 本规则命中行数(matched_rule_<idx>);「检查」= 1
// 其它 step 沿用顶层 summary.violations / summary.fields_checked
let violation_count = 0;
let checked_count = 0;
if (t.tabKey && t.tabKey.startsWith('custom_value_check_')) {
const idx = t.tabKey.replace('custom_value_check_', '');
violation_count = (t.data && t.data[`matched_rule_${idx}`]) || 0;
checked_count = 1;
} else {
violation_count = (
(t.data && t.data.summary && t.data.summary.violations) || 0
);
checked_count = (
(t.data && t.data.summary && t.data.summary.fields_checked) || 0
);
}
matchedItems.push({
tabKey: t.tabKey,
stepId: t.stepId,
title: t.title,
violation_count: (
(t.data && t.data.summary && t.data.summary.violations) || 0
),
checked_count: (
(t.data && t.data.summary && t.data.summary.fields_checked) || 0
),
violation_count,
checked_count,
});
}
}
......@@ -1442,18 +1455,30 @@
const fallbackKey = '__unmatched__';
const isExpanded = expandedGroups.value.has(fallbackKey)
|| !expandedGroups.value.size; // 首次无结果前默认展开兜底组
// 2026-08-13:未匹配分组里也要识别 custom_value_check_<idx> tab
const fallbackItems = items.map(t => {
if (t.tabKey && t.tabKey.startsWith('custom_value_check_')) {
const idx = t.tabKey.replace('custom_value_check_', '');
return {
...t,
violation_count: (t.data && t.data[`matched_rule_${idx}`]) || 0,
checked_count: 1,
};
}
return t;
});
out.push({
key: fallbackKey,
_level: 0,
is_group: true,
title: '其他',
description: 'analysisTree 未匹配',
_checked_count: items.length,
_total_count: items.length,
_checked_count: fallbackItems.length,
_total_count: fallbackItems.length,
_expanded: isExpanded,
});
if (isExpanded) {
for (const it of items) {
for (const it of fallbackItems) {
out.push({
key: it.tabKey,
_level: 1,
......@@ -1598,6 +1623,18 @@
// 点击字段表右侧 + 号:拷贝字段信息 + 字段 data_type(决定可用比较符)
// 已存在的同一字段会被去重(防止用户重复点)
// table_comment 兜底:字段行 row 可能不带,从 tableSummary 反查
// 默认名「自定义规则N」:扫描已用编号,找最小可用 N(用户手动改名后 N 仍递增)
function nextDefaultRuleName() {
const used = new Set(
(customRules.value || [])
.map(r => (r.rule_name || '').trim())
.filter(Boolean)
);
let n = 1;
while (used.has(`自定义规则${n}`)) n++;
return `自定义规则${n}`;
}
function addCustomRule(row) {
if (!row || !row.table_name || !row.column_name) {
return;
......@@ -1621,8 +1658,9 @@
}
const newRule = {
id: `rule_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
// 用户输入的展示名(2026-08-12 起新增列):留空时后端回落到 "<table>.<column>"
rule_name: '',
// 默认名「自定义规则N」:跳过当前已用的所有 N,找最小可用编号
// 用户在卡片里改名后,新规则的 N 不冲突
rule_name: nextDefaultRuleName(),
table_name: row.table_name,
table_comment: tableComment,
column_name: row.column_name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment