Commit 9ac8c11b authored by Data Governance Dev's avatar Data Governance Dev

feat(web+step7): 国标违规 — 取数口径 + 字段点击联动 + 0违规过滤 + 表/字段注释

经历多轮迭代,本次提交整合以下改动:

后端 step7_standards.py:
- SAMPLE_SPECS 列表:每条标准可对应多条抽样规格(当前 1 条 default)
- 抽样时捕获实际渲染的 SQL 与 spec_id 落到每条 detail
  (sample_sql / sample_spec_id)— 后端保留供报告用
- violations_flat 增 table_comment / column_comment 字段
- 每条标准新增 violating_fields_count + details_with_violations
  (过滤掉 violations==0 的字段,前端直接消费)
- 过滤零违规标准,不进入 violations_by_standard

前端 index.html:
- 字段点击联动:selectedField + selectFieldFilter / clearFieldFilter
  + filteredViolations computed;选中后明细表只显示该字段违规
- 按标准统计表中字段清单改用 details_with_violations,
  自动隐藏 0 违规字段;字段数列加「N / M」红字显示有违规字段数
- 标准列去除「取数口径」折叠面板(用户认为没意义)
- 明细表去除选中字段时的 SQL 蓝边面板(用户认为没意义)
- 明细表改为 4 列:表/表注释、字段/字段注释、标准/标准名、值/违规原因
- alert 文案改为「X 个标准有违规(共 Y 条违规记录)」
- .field-link / .field-link--active CSS:选中字段高亮

数据 / UI 一致性验证:本后端 AST 通过;本地 == HTTP 服务返回(59051 字节)。
"
parent d2917cf8
......@@ -26,6 +26,25 @@ SAMPLE_LIMIT = 500 # 每字段最多抽样
MAX_TABLES_PER_FIELD = 5 # 每字段最多检查前 N 张表
# 取数口径列表 —— 一个标准可对应多条抽样 SQL(按 spec_id 区分)
# 当前所有标准都共享同一默认口径;后续若不同标准需不同抽样策略,
# 在此处按 standard_id 配置多条即可。
SAMPLE_SPECS: list[dict] = [
{
"id": "default",
"name": "抽样非空非空白字段值",
"description": f"从每张表抽 ≤{SAMPLE_LIMIT} 行非空、非空白字段值",
"sql_template": (
"SELECT `${field}` AS val\n"
"FROM `${table}`\n"
"WHERE `${field}` IS NOT NULL\n"
" AND TRIM(`${field}`) <> ''\n"
"LIMIT ${limit}"
),
},
]
def run_step7(cfg: DBConfig, dict_data: dict, log: Callable | None = None) -> dict:
"""执行 Step 7:国标校验"""
columns = dict_data.get("data_dictionary", [])
......@@ -104,6 +123,9 @@ def run_step7(cfg: DBConfig, dict_data: dict, log: Callable | None = None) -> di
limit=SAMPLE_LIMIT,
)
rows = db.fetchall(sql)
# 真正执行过的 SQL,落库展示给审计
sample_sql_rendered = sql
sample_spec_id = "default"
except Exception as e:
std_record["fields"].append({
"table": table,
......@@ -111,6 +133,8 @@ def run_step7(cfg: DBConfig, dict_data: dict, log: Callable | None = None) -> di
"error": str(e),
"violations": 0,
"sampled": 0,
"sample_spec_id": "default",
"sample_sql": f"SELECT `${field_name}` ... -- 渲染失败: {e}",
})
if log:
log("WARN",
......@@ -136,7 +160,9 @@ def run_step7(cfg: DBConfig, dict_data: dict, log: Callable | None = None) -> di
})
violations_flat.append({
"table_name": table,
"table_comment": col_record.get("table_comment", ""),
"column_name": field_name,
"column_comment": col_record.get("column_comment", ""),
"rule_type": std_id,
"standard_name": std_instance.standard_name,
"column_type": col_record.get("column_type", ""),
......@@ -154,6 +180,8 @@ def run_step7(cfg: DBConfig, dict_data: dict, log: Callable | None = None) -> di
"violations": invalid_count,
"violation_rate": round(invalid_count / sampled, 4) if sampled else 0,
"samples": invalid_samples,
"sample_spec_id": sample_spec_id,
"sample_sql": sample_sql_rendered,
})
logger.debug(
f"{table}.{field_name}: 抽样 {sampled}, 违规 {invalid_count}"
......@@ -165,18 +193,33 @@ def run_step7(cfg: DBConfig, dict_data: dict, log: Callable | None = None) -> di
by_standard_list = []
for std_id, rec in by_standard.items():
# 过滤掉零违规的标准
if rec["total_invalid"] == 0:
if log:
log("INFO",
f" · 标准 {rec['standard']} 抽样 {rec['total_sampled']} 条全部合规,跳过",
step="7")
continue
violating_fields = [d for d in rec["fields"] if d.get("violations", 0) > 0]
by_standard_list.append({
"standard": rec["standard"],
"standard_name": rec["standard_name"],
"fields_count": len(rec["fields"]),
"violating_fields_count": len(violating_fields),
"total_invalid": rec["total_invalid"],
"total_sampled": rec["total_sampled"],
"violation_rate": round(rec["total_invalid"] / rec["total_sampled"], 4) if rec["total_sampled"] else 0,
"details": rec["fields"],
# 字段清单只展示有违规的,过滤掉 0 违规的占位项
"details_with_violations": violating_fields,
# 取数口径:每条标准附带一份规格清单(一个标准可对应多条)
"sample_specs": [dict(s) for s in SAMPLE_SPECS],
"sample_limit": SAMPLE_LIMIT,
"max_tables_per_field": MAX_TABLES_PER_FIELD,
})
if log:
log("INFO", f"校验完成: {len(by_standard_list)} 个标准, {total_fields_checked} 个字段, {total_violations} 条违规", step="7")
log("INFO", f"校验完成: {len(by_standard_list)} 个标准有违规, {total_fields_checked} 个字段, {total_violations} 条违规", step="7")
return {
"summary": {
......
This diff is collapsed.
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