1. 13 Aug, 2026 4 commits
    • Data Governance Dev's avatar
      feat(backend): Oracle 端到端打通(thick + health + 11g 兼容 + schema 名修正) · fd098416
      Data Governance Dev authored
      Oracle 11g (11.2.0.4) 数据库连接抽数据字典端到端跑通,解决 4 个独立问题:
      
      1. connect_timeout → tcp_connect_timeout
         oracledb 1.4.2+ 移除了 connect_timeout kwarg(之前误以为兼容),
         改成 tcp_connect_timeout;报错日志加 inspect 自动定位兼容 kwarg。
      
      2. thick 模式加载 + DPI-1047 深度诊断
         - _ensure_oracle_client() 解析 oci.dll 的 PE 导入表,自动列出
           实际依赖的运行时 DLL(如 MSVCR120.dll → VC++ 2013 Redist)
         - DPY-3010(thin 不支持老 Oracle)日志加针对性安装指引
         - 11.2.0.4 必须 thick 模式(thin 不支持 11.2)
      
      3. 健康检查 SQL 分方言
         新建 check_connection.oracle.sql 写 SELECT 1 FROM dual;
         Oracle 严格执行 SQL 标准,不像 MySQL/达梦 兼容裸 SELECT 1。
         sql_loader 按 <name>.<dialect>.sql 优先 + .sql 回退 自动分流。
      
      4. ALL_TABLES 11g 列兼容性
         修 list_tables.oracle.sql:
         - data_length 用 t.BLOCKS * 8192 估算(11g 没 BYTES 列,12c+ 才有)
         - create_time / update_time 取 NULL(11g 没 CREATED/LAST_DDL_TIME,12c+ 才有)
         - 注释贴了 11.2.0.4 ALL_TABLES 完整可用列清单(用户 DESC 确认)
      
      5. schema 名传递修正
         data_dict.py 之前对所有数据库都传 cfg.database 给 list_tables/list_columns,
         但 Oracle 体系里 ALL_TABLES.OWNER 是用户名(=cfg.user),不是 service_name。
         加 cfg.db_type == 'oracle' 分支:schema_name = cfg.user
      
      6. /api/db-defaults 加 oracle_client_dir
         路径从 web/configs/db_defaults.yaml 预填,前端可隐藏输入框。
      
      验证日志:
        [DB] Oracle Instant Client 已加载(thick 模式)lib_dir=...
        [DB] 连接已建立(耗时 ~100ms)
        [DB] 测试连接成功
        [Cache] 写入数据字典: (表 N 张, 字段 M 个)
      
      踩坑详见 docs/WORKLOG.md(2026-08-13 Oracle 端到端打通条目)。
      fd098416
    • Data Governance Dev's avatar
      refactor(web): 收敛分析项 UI 至 3 组(hide/merge/rename 6 轮) · e7fb2a8c
      Data Governance Dev authored
      UI 从 7 组 / 30+ step 收敛到 3 组 / 15 step;隐藏 27 个 indicator。
      
      合并 / 改名为独立 IND 号(移入 standards 组):
      - IND-401 / IND-402 → std_ind_401(姓名校验,2 子检查合一)
      - IND-006-b → std_ind_006(邮政编码)
      - IND-013-a / -b / -c → std_ind_017 / -018 / -019
        (单位类别 GB/T 12402 / 经济类型 国统字〔2011〕86 号 / 行业代码 GB/T 4754)
      
      隐藏 27 个 indicator(_HIDDEN_SUBS,暂离 UI,按需恢复):
      - IND-016-a / -101 / -201..-204 / -301 / -302 / -501 / -502
      - IND-601..-603 / -901 / -902
      - IND-006-a / -008-a..-011-a(其他业务字段整组下架)
      - IND-013-a..-c(已改名)
      - IND-012-a / -014-a / -014-b / -015-a(单位法人经办人整组下架)
      
      整组下架(5 个 group):
      - 单位对公账户 字段规范
      - 民政信息
      - 证件信息
      - 其他业务字段
      - 单位 / 法人 / 经办人 字段规范
      
      新增 / 重命名 group:
      - 业务字段规范(含 std_ind_401 姓名 + std_ind_007_a 公积金账号)
      
      后端改动:
      - 抽 _run_standards_ind_renamed(source_id, target_step_id, target_title) 工厂
        合并 IND-005/006/013 的改名逻辑
      - _run_standards_combined factory 处理 std_ind_401 合并子检查
      - _IND_COMBINED['ind_401'] 配置(IND-401/IND-402 字符集 + 长度合一)
      - _MERGED_SUBS / _HIDDEN_SUBS / mapped_step 同步更新
      
      前端 / 配置:
      - analysis_tree.json: 7 组 → 3 组;description / default_expand 同步精简
      - routes.py /api/match-config: _COMBINED_GROUPS 聚合 + IND-005/006/013 改名映射
      
      docs(WORKLOG): 6 轮完整记录 + 踩坑(log 闭包 bug 修复、sub_prefix 对无后缀 ID 的适配等)
      
      UI 顺序:基础检查 → 国标字段规范(10 step)→ 业务字段规范(2 step)
      e7fb2a8c
    • Data Governance Dev's avatar
      feat(standards): IND-002/003/004 合并 + IND-005 改名(去 -a) · a72a2ec1
      Data Governance Dev authored
      需求:把 IND-002(USCC 3 子)/ IND-003(手机号 2 子)/ IND-004(行政区划 2 子)
      也和 IND-001 一样合并成单 step;IND-005(固定电话,1 子)UI 不再显示 -a 后缀。
      
      改动:
      - step7_standards.py: 把 IND-001 专属的合并逻辑通用化为配置驱动
        - _IND_COMBINED: {parent_id: {sub_ids, title, format}} 配置表(覆盖 ind_001/-002/-003/-004)
        - _wrap_combined_ind_001 → _wrap_combined_indicator(parent_id, ...)
        - run_step7_for_ind_001 → run_step7_combined(parent_id, ...)
        - 旧名保留为薄包装(backward compat)
      - orchestrator.py:
        - _MERGED_SUBS 扩展到 12 个子指标(4+3+2+2+1)
        - _run_standards_combined(parent_id) 工厂 + _COMBINED_STEP_META 注册表
        - 循环注册 std_ind_001/-002/-003/-004 四个 step
        - _run_standards_ind_005 端到端改 4 处:section_key / step_id / tab.key / tab.title
      - analysis_tree.json: 标准组 7 行 → 5 行(去掉 -a/-b/-c 后缀)
      - routes.py: _COMBINED_GROUPS 4 组聚合 + IND-005 单独处理(YAML key 仍叫 IND-005-a)
      - WORKLOG 追加整段记录 + 踩坑说明(IND-005 改名必须 4 处一致)
      a72a2ec1
    • Data Governance Dev's avatar
      feat(standards): IND-001 a/b/c/d 合并为单分析项目 + 4 子检查合一 · ba75ed1b
      Data Governance Dev authored
      需求:勾一个 IND-001 checkbox 跑全部 4 子检查;
      结果合并展示,单条违规里显示「哪些子检查失败」。
      
      改动:
      - step7_standards.py: 新增 _IND_001_SUB_IDS / _merge_violations_by_tuple
        / _wrap_combined_ind_001 / run_step7_for_ind_001,单 (table,col,value)
        多子检查失败行合并,rule_type 列改为 'IND-001-a, IND-001-b',
        error 列改为 '[a] 长度 19 ≠ 18\n[b] 校验位错误' 拼接原文
      - orchestrator.py: 注册 std_ind_001 step(order=100,llm=none),
        跳过 IND-001-a/b/c/d 自动注册,避免 4 个独立 section 还在
      - analysis_tree.json: 国标字段规范组删 4 行 IND-001-a/b/c/d,加 1 行 std_ind_001
      - routes.py: /api/match-config 过滤未注册为 step 的子 indicator;
        把 IND-001 a/b/c/d 的 applies_to_fields / comment_keywords 聚合到 std_ind_001
        的输入框,避免合并后前端输入框丢失
      - 修复 double-wrap bug:_run_standards_ind_001 不再二次包裹
        run_step7_for_ind_001 原返回值(已含 {section_key, data})
      - WORKLOG 追加 4 段:合并设计 / 关键词输入框回归 / 标题 '合并 a/b/c/d' 去除 /
        结果不显示修复(double-wrap 根因 + 烟测)
      ba75ed1b
  2. 12 Aug, 2026 13 commits
    • Data Governance Dev's avatar
      docs(worklog): 自定义规则 icon + 卡片 header 点击折叠 + 后端 2 bug 修复记录 · b968bb24
      Data Governance Dev authored
      - 改 1:自定义规则卡 icon 换 Operation(之前 MagicStick 渲染不出来)
      - 改 2:4 个卡片 header 点击折叠 + 按钮 .stop(卡 1 / 2 / 2.5 / 3)
      - 改 3:sql_builder 数值比较符强制 float 避免达梦字符串解析为 0.0 坑
      - 改 4:step9 SummarySpec template 改双花括号与前端 renderSummary 匹配
      b968bb24
    • Data Governance Dev's avatar
      fix(backend): step9 SummarySpec template 改双花括号与前端 renderSummary 匹配 · 57c088a1
      Data Governance Dev authored
      - 现象:「自定义规则命中明细」tab 顶部 alert 显示「执行 **{total}** 条规则...」花括号没替换
      - 根因:step9 template 用单花括号 {total},前端 renderSummary 正则只匹配 {{ var }} 双花括号
      - 修复:template 改 {{total}} 双花括号(与其他 step 风格一致:step4 / step5 / step6 / step7)
      - 修后:执行 **1** 条规则,有效 **1** 条,命中 **0** 行(...)
      57c088a1
    • Data Governance Dev's avatar
      fix(backend): sql_builder 数值比较符强制 float 避免达梦隐式转换坑 · 3c2ac416
      Data Governance Dev authored
      - 现象:自定义规则 GRJCJS > 5000 命中 38 行全是 0.0
      - 根因:value 是字符串 '5000',达梦 SQL WHERE GRJCJS > ? 收到字符串 '5000' 后做字符串 vs
        DECIMAL 比较,部分达梦版本把 '5000' 解析为 0.0(字符串解析失败回退),变成 WHERE GRJCJS > 0.0
      - 修复:编译 gt/lt/eq 时 bind.params.append(float(val)) 强制数值化;非法值返回空字符串
        让上层跳过
      - 日期:date_before / date_after 保持 str(val)(达梦 / Oracle DATE 比较认字符串 YYYY-MM-DD)
      3c2ac416
    • Data Governance Dev's avatar
      refactor(web): 自定义规则 icon 换 Operation + 卡片 header 点击折叠 · e68c46a8
      Data Governance Dev authored
      - 自定义规则卡 icon:MagicStick SVG 渲染不出来 → 改用 Operation(扳手+齿轮,贴合自定义规则语义)
      - 4 个卡片 header 点击折叠:连接数据库 / 分析配置 / 自定义规则 / 数据字典浏览器
        - CSS 加 .collapsible-header { cursor: pointer; user-select: none; } + hover 灰底
        - 整个 .card-header 是点击区,@click 切换折叠
        - 内部按钮加 @click.stop 防止冒泡(全选/清空/反选/折叠 按钮)
      - 分析进度 / 分析结果 卡片无折叠按钮,本轮不动
      e68c46a8
    • Data Governance Dev's avatar
      docs(worklog): 自定义规则 v2 条件树改造 + 端到端联调 3 bug 修复记录 · d83cf947
      Data Governance Dev authored
      - 记录需求、设计决策(多层递归 / 日期只支持具体日期 / 3 类字段 7 算子)
      - 记录 3 个新后端文件职责 + step9 重构 + NUMERIC_TYPES / DATE_TYPES + orchestrator 兼容
      - 记录前端 UI 重构(递归组件 <condition-tree> + field-block 排版 + addCustomRule 透传)
      - 记录端到端联调 3 个 bug 修复:
        1. fieldClassTagType 未 setup return 导致渲染崩溃
        2. 字段注释 / 表注释没显示(row 不带 → 兜底查 tableSummary)
        3. orchestrator 只认旧 payload user_input,v2 group 树不追加 custom_value_check 步骤
      d83cf947
    • Data Governance Dev's avatar
      feat(web): 自定义规则卡条件树 UI + 字段类型分类 + 字段注释排版 · cd2c1475
      Data Governance Dev authored
      把单条 el-table 行(含 1 个 el-input 关键字)重写为 div + CSS Grid 4 列布局。
      
      - 字段类型 → 比较符映射(前端镜像 web/core/rule_types.py)
        - NUMERIC_TYPES_FRONT / DATE_TYPES_FRONT / TEXT_TYPES_FRONT 三集合
        - classifyField(dataType) → text/numeric/date/unknown
        - COMPARATORS_FRONT / INPUT_HINT_FRONT 按字段类分发
        - fieldClassTagType(dataType) → 数值 warning / 日期 info / 字符 success
      
      - 全新递归组件 <condition-tree>
        - app.component('condition-tree', { name: 'ConditionTree', ... })
        - props: node(默认空 group) / column / dataType / depth
        - 渲染:group 节点显示 AND/OR radio + 项数 + 「+ 子条件 / + 嵌套组」按钮
        - 渲染:leaf 节点显示 comparator select + value input + × 删除
        - emits: change / remove
      
      - 列表 div 替代 el-table
        - 4 列 grid:规则名称 / 对象·字段·类型 / 条件树 / 操作
        - .field-block 容器:表名 + 表注释 / 字段名 + 类型 + 字段注释 inline 排
        - .field-block--field dashed border-top 视觉分隔两行
      
      - addCustomRule 改造
        - 透传 row.data_type / row.column_type(决定可用比较符)
        - 初始化 group = { kind: 'group', op: 'AND', children: [] }
        - table_comment 兜底查 tableSummary(字段行 row 不带)
        - 自动展开卡片(customConfigCollapsed = false)
      
      - buildCustomRulesForSubmit 改读新结构
        - hasValidLeaf(node) 递归判断:跳过空树
        - 输出包含 {rule_name, table_name, column_name, data_type, group_op, group}
      
      - 修复 2 个调试 bug
        - fieldClassTagType 是模块作用域函数,模板调用须 setup() return 出来
        - <condition-tree> props.node 加 default 兜底,避免 rule.group undefined 渲染崩溃
      cd2c1475
    • Data Governance Dev's avatar
      feat(backend): NUMERIC_TYPES / DATE_TYPES + orchestrator 识别 v2 条件树 payload · 0967e522
      Data Governance Dev authored
      - web/core/db_adapter.py
        - 新增 NUMERIC_TYPES / DATE_TYPES frozenset(紧挨 TEXT_TYPES)
        - 覆盖 MySQL / 达梦 / Oracle 三方言的常见数值 + 日期类型
      
      - web/core/orchestrator.py
        - 修 bug:"自动追加 custom_value_check 步骤" 判断只认旧 payload {user_input}
        - v2 payload 用 group 树结构 → 永远 False → main_steps=[] → 0 步跑
        - 新增 _has_effective_leaf(node) 递归判断:新旧 payload 都认
        - 修后:steps=[] + 1 条有效规则 → 自动追加 custom_value_check → 跑 200 行命中
      0967e522
    • Data Governance Dev's avatar
      feat(backend): 新增 rule_types / like_util / sql_builder + step9 重构支持条件树 · 7563ac51
      Data Governance Dev authored
      自定义规则 v2 后端核心:把单条 LIKE 升级为递归条件树。
      
      - web/core/rule_types.py(新)
        - classify_field(data_type) → text/numeric/date/unknown
        - COMPARATORS_BY_CLASS / DEFAULT_COMPARATOR / INPUT_HINT_BY_CLASS
        - 文本 2 算子(contains / not_contains);数值 3 算子(gt / lt / eq);日期 2 算子(date_before / date_after)
      
      - web/core/like_util.py(新)
        - escape_like(s) + ESCAPE_CHAR = '!'(跨 DB 一致,避开达梦 [CODE:-6106])
        - 从 step9 内嵌函数上提,从此模块 import
      
      - web/core/sql_builder.py(新)
        - build_where(node, bind, column_quoted, db_type) 递归编译 group 树
        - _placeholder(db_type) MySQL %s / 达梦+Oracle ?
        - 顶层 compile_rule(group, column_quoted, db_type) → (clause, params)
      
      - web/core/step_impl/step9_custom_rules.py
        - 主循环重写:每条规则编译 group 树 → 跑 SQL → LIMIT 200 命中
        - _normalize_rule 自动包旧 payload {rule_type, user_input} → 新 group 树,兼容旧调用
        - 摘要字段补齐:total_rules / executed_rules / skipped_empty_keyword / skipped_no_valid_leaf / failed_rules / total_matched_rows / violations / fields_checked
      7563ac51
    • Data Governance Dev's avatar
      refactor(web): 自定义规则卡 startJob 后自动折叠 + Filter 换 MagicStick ✨ · 02a8c7ab
      Data Governance Dev authored
      【折叠】
      [web/static/index.html:1619-1624](web/static/index.html#L1619-L1624) startJob()
      成功回调里追加 customConfigCollapsed.value = true,跟另外 3 张配置卡
      (连接 / 分析配置 / 数据字典浏览器)行为一致 —— 让视觉焦点落到
      「分析进度」和「分析结果」上。
      
      注释里的「3 张」改为「配置卡」(表述更准确)。
      
      【icon】
      [web/static/index.html:366](web/static/index.html#L366) 自定义规则 header
      icon 从 Filter(漏斗)换成 MagicStick ✨(魔法棒):
      - 视觉权重更高,16px 下也比 Filter 显眼
      - 语义贴合「自定义 = 用户施展的小魔法」
      - 不与其他三张卡冲突:Connection / Setting / Document / MagicStick ✨
      - 已 grep 确认 Element Plus icons-vue v2.3.2 IIFE bundle 导出 MagicStick
      
      【WORKLOG】
      docs/WORKLOG.md 顶部追加两条记录说明上述两个改动。
      02a8c7ab
    • Data Governance Dev's avatar
      feat(web): 自定义规则端到端 + 空 steps 区分 None/[] · 4b694b62
      Data Governance Dev authored
      将「数据字典浏览器 → 字段表 + 号 → 累积自定义规则 → 后端跑 LIKE 检索」打通完整链路。
      
      【新增】
      - web/core/step_impl/step9_custom_rules.py:每条规则 SELECT col FROM tbl
        WHERE col LIKE '%kw%' ESCAPE '!' LIMIT 200;跨 DB 占位符
        (mysql=%s / dmPython=oracledb=?)、统一 '!' 避免达梦 [CODE:-6106];
        每条 SQL 命中行 = 1 个 entry(不做 distinct,重复值并列展示)
      - orchestrator 注册 custom_value_check 步骤(hidden=True,前端不展示;
        提交 non-empty custom_rules 时自动追加)
      - models.ConnectRequest.custom_rules 字段
      
      【修改】
      - job_manager:区分 None(跑全部)vs [](显式空选择),同步 orchestrator 语义
      - orchestrator.run_governance_workflow:同上 + 接受 custom_rules 参数
      - step8_report:自定义规则报告渲染改读 matches[](7 列:规则名称/表名/
        字段名/匹配值/规则/关键字/错误;删除「命中行」列)
      - index.html:分析配置卡 + 自定义规则卡 UI 联动
      - docs/WORKLOG.md:上述变更的工作记录
      
      【为什么需要整体提交】
      orchestrator 的 steps 语义修正 + custom_rules 注入 + job_manager 同步 +
      step9 执行 + step8 渲染 + models 字段,每一块独立提交都会留下 broken
      intermediate commit。
      4b694b62
    • Data Governance Dev's avatar
      feat(web): 字段匹配规则外置到 YAML + 检查项自定义输入框 + 卡片折叠 · b95def37
      Data Governance Dev authored
      匹配规则外置:
      - 新增 web/configs/standards_match.yaml(44 个 indicator + 14 条 length 规则)
      - 新增 web/core/match_config.py:线程安全加载 + get_indicator_match / get_length_rules / merge_user_override
      - step6 / step7 走 YAML + 用户运行时 override 三级 fallback(用户输入追加而非替换)
      - ConnectRequest 新增 match_overrides: dict[str, dict[str, list[str]]]
      - 新增 GET /api/match-config:返回前端输入框默认值(逗号分隔格式)
      
      前端检查项 2 个输入框:
      - 每行 leaf 后挂「字段名 / 字段注释」2 个 el-input
      - loadMatchConfig() 启动时拉 YAML 默认值灌进 form.match_overrides
      - buildMatchOverridesForSubmit() 提交时把字符串转 list(Pydantic 期望 list[str])
      - 跨字段 indicator(IND-301/302/901/902)UI 隐藏输入框(_skip: true)
      
      卡片折叠 + 动画:
      - 连接数据库 / 分析配置 / 数据字典浏览器 三张卡都加折叠按钮 + Vue transition
      - startJob() 成功后三张卡自动折叠,焦点落到「分析进度」
      - el-card__body 折叠时 padding 上下 1px(默认 20px),padding 加 0.28s 过渡
      - el-card__header 折叠时 padding 6px,margin-bottom 折叠时 8px
      - i 图标移到输入框右侧
      - progress-block margin 改为 0
      
      Bug fix:
      - testConnection 也走 buildMatchOverridesForSubmit()(否则 names/comments 是 string → 422)
      - inline <style> 全局 CSS 不能用 :deep(),全部改为直接选择器
      
      WORKLOG 详细记录所有决策点。
      b95def37
    • Data Governance Dev's avatar
      refactor(web): 布局调整 + 还原字段名/注释关键字匹配 + 删除字段 checkbox · a0c39eb1
      Data Governance Dev authored
      按 2026-08-12 用户反馈:
      - 「分析配置」卡片上移到「连接数据库」下方、「数据字典浏览器」上方
      - 还原回旧版「字段名 + 字段注释关键字模糊匹配」自动选字段行为
      - 删除右表格字段 checkbox 及全链路 column_filter
      
      前端 (web/static/index.html):
      - 卡片顺序:连接数据库 → 分析配置 → 数据字典浏览器 → 进度 → 结果
      - 删右表格 selection 列、工具栏(全选/清空/反选)、fieldsTableRef、form.columns
      - startJob() 不再带 columns,只看 tables.length
      
      后端:
      - web/core/models.py: 删 ConnectRequest.columns
      - web/core/job_manager.py: 不再透传 columns
      - web/core/orchestrator.py: 移除 columns / column_filter 构造与参数
      - 6 个 step 文件(step2/4/5/6/7)移除 column_filter 参数
      - step7_standards.py: 恢复 _collect_hit_columns + has_name/has_cmt 守卫
      
      文档:
      - docs/WORKLOG.md: 追加本次记录
      a0c39eb1
    • Data Governance Dev's avatar
      refactor(web): 分析配置默认全部不勾选 + 默认全部折叠(含实时日志) · 8728514f
      Data Governance Dev authored
      - loadSteps():去掉 form.steps 默认全选,只保留 hidden step 兜底过滤
        required 步骤仍在 startJob() 里自动补勾
      - expandedGroups:初始化为空 Set,原 watcher 不再消费
        analysisTree.json 的 default_expand 自动展开
      - logExpanded:ref(true) → ref(false),实时日志面板默认折叠
      
      工具栏的「全选 / 清空 / 全部展开 / 全部折叠」按钮照常可用,
      用户想一键操作仍然可以。
      
      .gitignore:追加 Session.vim(Vim 会话临时文件)
      8728514f
  3. 11 Aug, 2026 3 commits
    • Data Governance Dev's avatar
      feat(web): 数据字典右表格字段 checkbox + column_filter 端到端 · 02de2a61
      Data Governance Dev authored
      后端
      - models.py: ConnectRequest 加 columns: list[{table_name, column_name}]
        (空 = 走选中表全量字段;非空 = 仅跑用户勾选字段)
      - orchestrator.py: run_governance_workflow 接 columns,构造
        column_filter: set[(table, column)] 传给每个 step
      - job_manager.py: _run_job 透传 columns
      - step2/4/5/6: 加 column_filter 参数 + 按 (table, column) 过滤
      - step7 (核心): 删除 _collect_hit_columns 关键字推断
        (applies_to_fields / comment_keywords 不再用于挑选目标字段),
        改为 _select_target_columns 直接返回上游 column_filter 后的字段;
        run_step7_for_indicator 单值类分支去掉 has_name/has_cmt 守门
      
      前端
      - index.html: 右表格加 checkbox 列 + 全选/清空/反选 工具栏
      - form.columns: Set<table||column>,勾上表时联动勾上表所有字段、
        取消表时移除该表所有字段,用户手动调整不联动回表
      - startJob(): Set → [{table_name, column_name}] 后提交
      - 启动按钮增加 columns.size === 0 守门 + 新 alert
      - disconnectDataDict / testConnection 成功 后清空 form.columns
      
      修复
      - testConnection() 不再传 Set 类型的 columns(JSON.stringify 会变 {}
        导致 Pydantic 422),改为显式传空 list
      - data_dict.py: 达梦环境下 ALL_TAB_COLUMNS / ALL_COL_COMMENTS 视图
        可能返回 N 倍重复行(B_ZJZX 12 字段实测 78 行),Python 端按
        (table_name, column_name) 兜底去重,命中时打 WARN 日志
      02de2a61
    • Data Governance Dev's avatar
      refactor(web): Step 5 去 LLM 推测 + Step 2 UI 隐藏 + hidden step 提交过滤 · 50b48135
      Data Governance Dev authored
      本批 3 个独立任务合并提交(互相有依赖:hidden 机制引入 → 暴露了一个 bug → 修复)。
      
      【Step 5 缺失注释字段检查:去 LLM 推测,改纯规则】
      - web/core/step_impl/step5_missing_comments.py(全文重写)
        · 删 LLMClient 导入 / llm 参数 / 整段批量推测逻辑
        · TabProtocol 简化为 4 列:表名+注释 / 字段名 / 类型 / 可空
        · 新增 _is_missing() 工具函数
        · 输出 missing_comments[:200](限制条数,避免渲染过大)
      - web/core/orchestrator.py
        · _run_missing_comments 不再向 step5 传 llm(签名保留 # noqa: ARG001)
        · register_step("missing_comments", ...) llm_mode="none" + title/desc/detail 全重写
        · CRITICAL_STEPS: {"merge_redundancy", "missing_comments"} → {"merge_redundancy"}
        · 顶部 docstring L9 同步
      - CLAUDE.md
        · 目标 L10 加变更说明
        · LLM 依赖表 Step 5: required → none,预检提示改 "Step 2"
      
      【Step 2「表合并与冗余字段分析」UI 隐藏:通用 hidden 机制】
      - web/core/orchestrator.py
        · StepDef 加 hidden: bool = False 字段
        · register_step() 同步加 hidden 入参
        · merge_redundancy 注册设 hidden=True
        · 顶部 docstring L7 加 "UI 隐藏" 标注
      - web/api/routes.py(/api/analysis-tree)
        · by_id 过滤 sd.hidden
        · 遍历 children 时 hidden/unregistered 不记入 missing(避免误导)
        · 「未分组」兜底组自然不会泄露 hidden step
      - web/configs/analysis_tree.json
        · 「基础检查」组直接删掉 merge_redundancy 那行(之前用 // 注释导致 JSON 解析失败,已纠正)
      - CLAUDE.md · LLM 依赖表 Step 2 加 "2026-08-11 起 UI 隐藏,但代码保留"
      
      【hidden step 提交过滤(隐藏 step 仍被执行 的 bug 修复)】
      - web/api/routes.py(/api/steps)
        · 与 /api/analysis-tree 一致:for sd in get_step_defs() if not sd.hidden
      - web/static/index.html(loadSteps)
        · 新增兜底分支:form.steps 非空时也清掉残留 hidden step
          (应对浏览器未刷新 / Vue 状态缓存)
      
      【关键:hidden 只影响 UI 入口】
      - 后端 run_job() 不加 hidden 校验 —— 保留「代码保留可手动触发」的灵活性
      - 手动 POST /api/jobs 指定 hidden step 仍能跑(内测可用)
      - CRITICAL_STEPS 不动 —— hidden step 不在提交路径上,自然不会失败终止
      
      【未提交】
      - scripts/_tmp_build_violations_md.py(一次性调试脚本)
      - data_dictionary/standard_fields_violations_report.md(生成报告)
      
      docs/WORKLOG.md 顶部已追加本次 3 个任务的完整记录(含根因 + 验证 + 后续如何加回 LLM)。
      50b48135
    • Data Governance Dev's avatar
      feat(web): 三数据库适配(MySQL/达梦/Oracle)+ 连接默认值独立配置 · 9646cd1a
      Data Governance Dev authored
      【Oracle 适配 — 端到端接入】
      - web/core/db_adapter.py
        · 新增 to_oracle_kwargs(),oracledb 1.4.x 关键字映射
        · _select_driver() 新增 oracle 分支,未安装 oracledb 时给中文友好报错
        · _ensure_oracle_client() 自动检测 Instant Client,老 Oracle 切 thick 模式
        · DBConfig.oracle_client_dir 字段(显式 lib_dir)
        · TEXT_TYPES 补 Oracle 类型(nclob / long)
      - web/sql/info_schema/list_columns.oracle.sql + list_tables.oracle.sql
        · 新增 Oracle 方言的字典查询模板(ALL_TAB_COLUMNS / ALL_TABLES)
        · 表注释 LEFT JOIN ALL_TAB_COMMENTS(同达梦结构)
      - web/sql/standards/{sample_field_groups,sample_field_groups_single,
        sample_field_pairs,sample_field_pairs_two_text}.sql
        · \`\${col}\` → \${col | quote} 跨方言重构,加新数据库零 SQL 改动
      - web/sql/loader.py:dialect 白名单加 "oracle"
      - web/requirements.txt:锁定 oracledb>=1.4.2,<2.0(兼容 Oracle 11.2)
      - web/start.py:start 脚本新增 oracledb / dmPython 可选组件检测
      - web/app.py / web/core/__init__.py / web/core/step_impl/__init__.py /
        web/core/models.py / web/configs/defaults.yaml / web/README.md
        · 描述/注释/枚举更新为「MySQL / 达梦 / Oracle」
        · models.ConnectRequest 加 oracle_client_dir 字段
        · README 加 Oracle 行 + 三端口映射说明
      
      【达梦适配 — 跑通实测】
      - web/core/db_adapter.py
        · to_dm_kwargs() 改用 server= 关键字(不是 host=),删 dmPython 不支持的
          schema / charset / connect_timeout 参数(C 扩展传错会 SystemError 吞真实异常)
        · _rows_as_dicts() 统一 PyMySQL Dict / tuple 两种行格式
        · fetchall / fetchone 从 cur.description 取列名兜底
        · dmPython SystemError 增强日志(提示真实原因 + 给排查脚本路径)
      - web/sql/info_schema/list_columns.dameng.sql
        · 列注释 LEFT JOIN ALL_COL_COMMENTS(修 [CODE:-2207] C.COMMENTS)
      - web/sql/info_schema/list_tables.dameng.sql
        · BYTES → NULL(达梦 ALL_TABLES 无此列)
        · COMMENTS → LEFT JOIN ALL_TAB_COMMENTS(达梦 ALL_TABLES 无此列)
        · CREATED / LAST_DDL_TIME → NULL(达梦 ALL_TABLES 无时间戳)
          真要看时间戳得 LEFT JOIN ALL_OBJECTS,按 OBJECT_TYPE='TABLE' 过滤
      
      【UI 改进】
      - web/static/index.html
        · 数据库类型三选项(MySQL / 达梦 / Oracle)
        · onDbTypeChange 端口切换改用 DB_DEFAULT_PORTS 映射表
          (mysql:3306 / dameng:5236 / oracle:1521),加守卫保留用户自定义端口
        · loadDbDefaults() 启动时从 /api/db-defaults 读连接默认值填表单
        · charset 下拉新增 al32utf8 / zhs16gbk(Oracle NLS 字符集)
        · Oracle radio 暂未实装完成,先注释隐藏(后端代码保留,放开零成本)
      
      【连接默认值独立配置】
      - web/configs/db_defaults.yaml(新增,.gitignore 排除,存真实凭据)
      - web/api/routes.py:新增 GET /api/db-defaults 端点
      - .gitignore:补 web/configs/db_defaults.yaml 防止真实凭据误提交
      
      【诊断与日志】
      - scripts/_probe_dm.py:达梦连接独立诊断工具(C 扩展吞异常时排查用)
      - docs/WORKLOG.md:本次任务完整工作记录(含三库字典表差异表)
      
      【未提交】
      - web/configs/db_defaults.yaml(真实密码,gitignore 排除)
      - scripts/_tmp_build_violations_md.py(一次性调试脚本,硬编码绝对路径)
      - data_dictionary/standard_fields_violations_report.md(生成报告,非源码)
      9646cd1a
  4. 10 Aug, 2026 6 commits
    • Data Governance Dev's avatar
      feat(web): 分析结果折叠树与检测指标共用同一份 analysisTree.json + 渲染骨架 · 0f08eab6
      Data Governance Dev authored
      - 把 groupedResultTabs (嵌套结构) 重构为 flatResultRows (与 flatCheckRows 同构的扁平行)
      - 删除 resultGroupsExpanded / toggleResultGroupExpand / setAllResultGroupsExpanded 三个 result 专用函数
      - 共用 expandedGroups / toggleGroupExpand / setAllGroupsExpanded
      - 分析结果折叠树模板完全对齐检测指标的 .tree-row / .tree-caret / group-* / treeRowStyle(row)
      - 分组行: caret + 标题 + 进度 + 描述 (无 checkbox —— 检测项用, 分析结果不需要)
      - 子行: caret-spacer + 标题 + status tag + 违规计数 + 查看按钮
      - CSS 只保留 result 特有部分 (wrapper / hover / active / 计数)
      - WORKLOG 记录
      
      bugfix: 上一轮 flatResultRows 读 g.children 但 API 已转成 g.checks —— 44 条结果都掉进「其他」
             改用 g.checks || g.children || [] 兼容
      0f08eab6
    • Data Governance Dev's avatar
      feat(standards): 单位/法人/经办人/对公账户 校验 12 项 indicator (3 批合并提交) · 42a0a18c
      Data Governance Dev authored
      === 第一批:单位基本信息 7 项 ===
      * IND-012-a 单位名称 格式(length [4,100])
      * IND-013-a 单位类型 值域(GB/T 12402-2017)
      * IND-013-b 经济类型 值域(国统字〔2011〕86 号)
      * IND-013-c 行业代码 格式(GB/T 4754-2017)
      * IND-014-a 单位设立日期(GB/T 7408)
      * IND-014-b 启缴年月(GB/T 7408)
      * IND-015-a 发薪日 值域
      
      === 第二批:对公账户 + 老代码兼容 3 项 ===
      * IND-002-c USCC 老代码兼容(GB 32100-2015 附录 A.1 + GB/T 12403-1990 MOD 11)
      * IND-016-a CNAPS 联行号 格式(12 位 + 行别字典)
      * IND-016-b 银行账号 格式(12~22 位 + 16~19 位 Luhn)
      
      === 第三批:跨表/跨字段 2 项 ===
      * IND-901 单位名 全局唯一性(单字段 GROUP BY HAVING)
      * IND-902 账户名 一致性(同行双字段配对 + 容错归一化)
      
      === 配套 ===
      * 11 个已有 indicator 补 comment_keywords 让法人/经办人/单位字段自动匹配
        - ind_003a_mobile / 005a_fixed_phone / 006a_address / 006b_postal_code
        - ind_101_id_type / 201_id_card / 202_passport / 203_hkmacao / 204_foreign
        - ind_401_name_charset / 402_name_length
      * orchestrator _derive_target + special_checks 加 12 段描述
      * analysis_tree.json 新增 2 个分组:
        - business_unit(IND-012~15)
        - business_unit_bank(IND-016 + 901/902)
        - standards 组加 IND-002-c(老代码兼容归入 USCC 体系)
      * step7 dispatch 扩展为 4 类执行路径:
        - 单值 / 跨字段 / 跨表聚合 / 跨表单字段 GROUP BY
        - 新增 _run_round3_global_uniqueness_one / _run_round3_cross_field_one
        - run_step7_for_indicator if/elif 链加 IND-901/902 分支
      * 2 个新 SQL 模板:
        - sample_field_groups_single.sql(IND-901)
        - sample_field_pairs_two_text.sql(IND-902)
      * WORKLOG.md 加 2 段工作记录(含 GB/T 12403 字符集修正、GB/T 4754 位数修正等关键技术细节)
      
      验证:orchestrator._STEPS 从 36 → 48 个 step(+12)
      42a0a18c
    • Data Governance Dev's avatar
      feat(standards): 公积金领域 8 项新 indicator + 字段注释匹配 · b783f6ff
      Data Governance Dev authored
      字段匹配双路化(comment_keywords 优先于 applies_to_fields):
        - standards/base.py: BaseStandard 加 comment_keywords: list[str]
        - web/core/step_impl/step7_standards.py: 新增 _collect_hit_columns()
          第 1 路按字段名命中,第 2 路按字段注释 substring 命中(不区分大小写)
          两路并集去重(按 (table, column))
        - standards/registry.py: list_all_standards() 输出 comment_keywords
      
      8 个 indicator 新增/修改:
        - IND-003-a (改): 加「不可全 0」前置校验
        - IND-005-a (新): GB/T 15835 固定电话(区号 3~4 位 + 号码 7~8 位)
        - IND-006-a (新): 通讯地址(长度 [4,200],非全空白/符号/数字)
        - IND-006-b (新): GB/T 23705 邮编(6 位数字)
        - IND-007-a (新): 个人公积金账号(仅位数 check,10/12/18 位,applies_to_fields 故意留空)
        - IND-008-a (新): 首次参加工作年月(YYYYMM/MMDD)
        - IND-009-a (新): 用工类型(6 值枚举 + 文字形式)
        - IND-010-a (新): 本地户籍标记(1/0、是/否、Y/N、T/F、TRUE/FALSE)
        - IND-011-a (新): 职工状态(5 值枚举 + 流转规则说明)
      
      orchestrator / 前端:
        - web/core/orchestrator.py: _derive_target / _derive_check 加 8 个新 indicator 分支;
          _register_indicator_steps() description 同时显示字段名 + 注释关键字
        - web/configs/analysis_tree.json: 注册 8 个新 step_id;新增「业务字段规范」组(默认展开)
        - 国标字段规范组加 std_ind_005_a
      
      KPI 去 card 化:
        - web/static/style.css: 去掉 .kpi-card 的 background / shadow / border / radius / padding;
          改为数字带色 + label 灰字的纯文字布局,密排紧凑
      
      已知限制:
        - IND-011-a 流转限制(销户 → 不可缴存、封存 → 可偿贷)需跨表 SQL JOIN,
          本轮仅在 description 写明业务规则,留待后续跨表 indicator
      
      WORKLOG: docs/WORKLOG.md 2026-08-10 第二条
      b783f6ff
    • Data Governance Dev's avatar
      feat(web): 检查项加 info icon + hover 4 段式说明(作用/查什么/规则/格式) · 1c07dd8c
      Data Governance Dev authored
      要点:
      
      - 后端:StepDetail 从 3 段扩到 4 段(加 check 段,校验规则细节)
      - BaseStandard 加可选 check_detail 字段(子类可覆写,默认空)
      - 4 个基础 step 手填 4 段详细说明(含步骤编号 / 阈值 / 处理策略)
      - 24 个 indicator 通过 _derive_check() 派生:每个 indicator 一段
        「业务背景 + 校验要点」摘要(含正则 / MOD 算法 / 号段表 /
        国标号 / 业务标准引用)
      - 前端:每个 leaf 行 checkbox 后加灰色圆 i 图标,hover 弹出 4 段
        tooltip,规则段用 <pre> 暗色等宽字体渲染多行
      
      修两个 root cause:
      
      1. <span class="tree-caret-spacer" /> 自闭合写法在 Vue 模板里被吞——
         所有后续兄弟节点(el-checkbox / el-tooltip / info-icon)全被塞进
         20px 宽的 spacer 里 overflow:hidden 截掉
         → 改为显式 <span class="tree-caret-spacer"></span>
      
      2. flatCheckRows push leaf 时没透出 c.detail,<el-tooltip v-if="row.detail">
         永远不渲染 → 加 detail: c.detail || null
      
      验证:jsdom + 真 Element Plus 跑 leaf 段渲染,info-icon + tooltip
      内容完整;后端 4 段全填(merge_redundancy / IND-001-a / IND-301 /
      IND-502 等抽样验证)。
      
      兼容性:StepDetail.check / BaseStandard.check_detail 都是 Optional,
      旧调用 register_step 不传 detail 也不会报错。
      1c07dd8c
    • Data Governance Dev's avatar
      feat(web): 检查项改成 JSON 驱动的多级折叠树 + caret 用 span+unicode · 01a2d9b0
      Data Governance Dev authored
      要点:
      
      - 后端:从 web/configs/analysis_tree.json 读分组,与 orchestrator 的
        step_defs 合并返给前端;JSON 没引到的 step 自动归 __ungrouped__,
        避免静默丢失
      - 前端:丢掉 el-table tree-props,自己渲染 caret + el-checkbox,
        每行固定 28px;caret 从 <button><el-icon><CaretRight/></el-icon></button>
        改为 <span>{{ _expanded ? '▼' : '▶' }}</span>(不再依赖 svg icon 组件)
      - 描述:inline ellipsis + :title 悬停(不再用 el-tooltip 包 el-checkbox)
      - README:新增「调整检查项分组(不改前端)」章节说明 JSON 结构
      - 验证:scripts/verify_tree.cjs (23 cases) / verify_caret_span.cjs
        / verify_prod_tree.cjs(jsdom + Vue 3.5.40 prod build 实际渲染 DOM)
      
      兼容性:/api/steps 保留;form.steps 仍为 flat step_id 列表;
      step 注册只动 orchestrator,分组只动 JSON。
      01a2d9b0
    • Data Governance Dev's avatar
      feat(standards): 国标分析拆分为 24 个细粒度 indicator,并注册为独立 step · 5c37925e
      Data Governance Dev authored
      国标分析改造两阶段,合并提交:
      
      【阶段 1】拆分 + 新增 5 类分析对象
      - STD-001 身份证 → IND-001-a/b/c/d (格式/校验位/出生日期/15位兼容)
      - STD-002 USCC  → IND-002-a/b   (格式/校验位)
      - STD-003 手机   → IND-003-a/b   (格式/号段)
      - STD-004 区划   → IND-004-a/b   (格式/编码存在)
      - 新增 IND-101 证件类型枚举(5 值)
      - 新增 IND-201~204 4 种证件号码(身份证/护照/港澳台居住证/外国人永居)
      - 新增 IND-301 跨字段 (证件类型+号码一致性)
      - 新增 IND-302 跨表 (证件唯一性,GROUP BY HAVING)
      - 新增 IND-401/402 姓名 (字符集/长度)
      - 新增 IND-501/502 出生日期 (格式/年龄范围, 性别推断退休年龄)
      - 新增 IND-601/602/603 区划/民族/婚姻
      
      基础设施:
      - BaseStandard 加 group/severity/depends_on 类属性 + validate_rows() 默认实现
      - registry.list_all_standards / list_standards_by_group
      - data_loader.py 惰性加载 data/*.json + extracted_standards.json
      - 新增 data/{id_type,marriage,gender,retirement_age}.json
      - 旧 STD-001~004 标 [已拆分], applies_to_fields=[] (保留兼容)
      
      【阶段 2】每个 indicator 注册为独立 step
      - registry.py 新增 load_standard_class / indicator_step_id /
        step_id_to_indicator_id / list_step_ids 工具函数
      - orchestrator.py 动态按 group 顺序注册 24 个 indicator step
        (国标字段规范=100, 证件信息=200, 身份信息=300, 民政信息=400)
      - step7_standards.py 新增 run_step7_for_indicator,每个 indicator
        独立 section_key (standards_ind_XXX),独立 tab
      - 旧 run_step7() 保留 (向后兼容: 跑全部按 4 group 输出)
      
      校验层:
      - IND-301 用 sample_field_pairs.sql
      - IND-302 用 sample_field_groups.sql
      - 84 单测覆盖所有 indicator (tests/test_indicators.py)
      
      协议层:
      - 沿用上轮的 tab_protocol;每个 indicator 一个独立 tab
        (1 KPI 违规字段 + 1 KPI 检查字段 + 2 表: 指标汇总 + 违规明细)
      
      详细工作记录见 docs/WORKLOG.md。
      5c37925e
  5. 07 Aug, 2026 4 commits
    • Data Governance Dev's avatar
      refactor(web): 分析结果 Tab 通用协议 + 文档 · 714f714a
      Data Governance Dev authored
      把 6 个 tab (merge / redundancy / empty / missing / length / standards)
      的展示抽出成通用协议,让每个 step 在 data 里嵌入 _protocol 自描述渲染,
      前端一个通用 renderer 按协议渲染;新增 step 只需写 data + 嵌 _protocol,
      零前端改动。
      
      后端
      - 新建 web/core/tab_protocol.py:dataclass (TabProtocol / KpiSpec /
        SummarySpec / TableSpec / ColumnSpec / RenderSpec / LinkageSpec) +
        _eval_path() 路径表达式求值 + make_protocol() 一站式 helper
      - 5 个 step 文件在 return 里嵌入 _protocol
        - step2_merge_redundancy.py:2 tab(merge_candidates + redundancy_fields)
        - step4_empty_fields.py:1 tab + 2 子表 + linkage;summary 加 flat 副本
        - step5_missing_comments.py:1 tab
        - step6_length_check.py:1 tab
        - step7_standards.py:1 tab + 2 子表 + linkage
      - orchestrator.py 删 _build_overview 里 KPI 聚合逻辑
      - models.py OverviewStats 缩为 5 字段(database / host / db_type /
        total_tables / total_fields / executed_at)
      
      前端 web/static/index.html 大改
      - 8 个硬编码 KPI 卡 → v-for='k in displayedKpis'
      - 6 个硬编码 <el-tab-pane>(~450 行)→ v-for='t in displayedTabs'
      - 删 TAB_STEP_MAP / perTableStats / flatEmptyFields / perTableRows /
        filteredViolations
      - 新增 displayedTabs / displayedKpis / tabStatus computed
      - 新增 evalPathExpr / resolvePath / resolveRows / renderSummary /
        resolveRenderPath 工具函数
      - 10 种 render.kind 在 template 里以 v-else-if 分发(text / code / tag /
        tag_list / two_line / three_line / progress / percent / ratio / number)
      - 3 个嵌套展开行(merge / standards / empty_fields)保留硬编码 —
        展开行内容太特定,WORKLOG 记为后续协议扩展方向
      
      文档与验证
      - 新建 docs/TAB_PROTOCOL.md:完整协议规范 + 新增 step 模板 + 真实走读
      - 新建 scripts/verify_protocol.cjs(12 case)+ verify_e2e.cjs(9 case)
        + verify_render.cjs(12 case)+ verify_template.cjs(2 case)——
        共 35 个 case 全过
      - verify_template.cjs 用 jsdom + 真实 vue.global.prod.js + Function 劫持
        截获编译产物,专门兜底「页面变白 / 编译出坏 JS」回归
      - WORKLOG 追加 v-else fallback 编译 bug 修复(Vue 3.5.x 在长 v-else-if
        链末尾输出 : () 无条件空 call expression)—— 把 v-else 改为
        v-else-if="!cond" 显式条件
      
      构建
      - package.json + package-lock.json:jsdom + @vue/compiler-dom(verify
        脚本的 dev 依赖)
      - .gitignore 加 scripts/compiled_*.js(verify_template 失败时的 debug
        产物)
      714f714a
    • Data Governance Dev's avatar
      style(web): 数据字典浏览器 — 表名 / 表注释 拆两列 + 优化外观 · edd3d2e5
      Data Governance Dev authored
      # 需求
      用户连续两轮反馈:
      1. 「表名 / 注释」外观扁平、长字段名被截断(`bui_history_field_label_table`
         → `bui_history_field_labe...`)
      2. 第一轮我把表名 + 表注释塞在同一 cell 两行后:「错了,两个表还是在同一行,
         只是显示表信息的那个表,表名和注释不要挤在一行,显得一行很高,
         我希望表名和表注释分两列显示」—— 用户要求真正拆成两列
      
      # 修改
      
      ## 1. style.css — 新增「数据字典浏览器」专属样式块 (+62)
      ```css
      .dict-pane       { display: flex; gap: 16px; }   /* 左右结构保持 */
      .dict-pane-left  { flex: 0 0 560px; }             /* 360 → 480 → 560,容纳 4 列 */
      .dict-pane-right { flex: 1; min-width: 0; }
      
      .dict-name       { display: block; white-space: nowrap; overflow: hidden;
                          text-overflow: ellipsis; font-family: Consolas; }
      .dict-name--field{ display: inline-block; max-width: 100%;
                          background: #f5f7fa; padding: 1px 6px; border-radius: 3px;
                          color: #e6a23c; white-space: nowrap;
                          overflow: hidden; text-overflow: ellipsis; }
      .dict-comment    { font-size: 12px; color: #909399; margin-top: 6px;
                          white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
      .dict-comment--empty { font-style: italic; opacity: 0.6; }
      ```
      
      ## 2. index.html — 拆列 + 类替换 (+12 / -17)
      - 「表名 / 注释」1 列 → 「表名」+「表注释」两列(min-width=220/180)
      - `<style>` 块里 dict-pane 7 行样式删除(已迁去 style.css 集中管理)
      - 字段数列 64 → 72,selection 列 40 → 44(按钮点击更稳)
      - 右侧字段表:表名列 180 → 200,字段名列 160 → min-width=200,
        改用 dict-name / dict-name--field 类
      
      # 验证(jsdom 全页 mock + click 测试连接)
      
      header: 4 列
        [0] 表名       min-width=220
        [1] 表注释     min-width=180
        [2] 字段数     width=72
        [3] (selection) width=44,含全选 checkbox
      
      body row[0]: 4 td
        td[0] "bui_history_field_label_table"   ← 表名
        td[1] "数据源标识表"                     ← 表注释
        td[2] "1"
        td[3] ""  has-checkbox=true             ← selection 列行复选框
      
      body row[2](无注释):
        td[1] "(无注释)" + dict-comment--empty ← 斜体灰字 0.6 透明
      
      # 兼容性
      - dict-pane 仍为 flex-row 左右结构(用户明确要求保持)
      - .dict-name-cell 类暂保留(无引用,后续可清理)
      - selection 列放最后约束保持不变(见上一提交 a07db7bb)
      
      # 文件清单
      - docs/WORKLOG.md       | +129 工作记录(拆分两轮反馈)
      - web/static/index.html | +12 / -17 列结构 + 类替换
      - web/static/style.css  | +62 数据字典浏览器专属样式块
      edd3d2e5
    • Data Governance Dev's avatar
      fix(web): selection 列移到最后 — Element Plus 兼容 bug · a07db7bb
      Data Governance Dev authored
      # 问题
      左侧「数据字典浏览器」表格渲染了表名 / 字段数,但每行没有勾选框,无法单选 / 多选。
      
      # 根因
      Element Plus 的列渲染 bug:当 <el-table-column type="selection"> 写在「最前」,
      且后面紧跟带 <template #default> slot 的列时:
      - header 的 selection <th> 被算成 colspan="2" scope="colgroup"
        (正常应该是 colspan="1" scope="col")
      - body 行的 selection <td> 完全不渲染 → 整个表只剩 header 的 1 个全选框
      
      # 验证(jsdom 跑了 4 个最小 case)
      | selection 位置 | 后续列类型                | 结果                       |
      | 1              | 第 1 | 全部 prop                | ✅ 3 cell + 3 checkbox |
      | 2              | 第 1 | 全部 default slot       | ❌ 2 cell + 1 checkbox(bug)|
      | 3              | 末尾 | 全部 default slot       | ✅ 3 cell + 3 checkbox |
      | 4              | 末尾 | 全部 prop                | ✅ 3 cell + 3 checkbox |
      
      只有 case 2 复现 bug —— 确认是 selection 列在前 + 后列带 slot 的组合触发。
      
      # 修复
      web/static/index.html:142-165 — 把 <el-table-column type="selection">
      从第 1 列移到末尾(第 3 列),并加注释说明这个约束。
      
      # 验证
      jsdom 模拟完整页面渲染后:
      - header 第 3 列:<th class="... el-table-column--selection"
        colspan="1" scope="col">含全选 checkbox
      - body 第 3 列:<td class="... el-table-column--selection">
        含 <label class="el-checkbox"> 行复选框
      - 3 行 × 1 checkbox = 3 个勾选框(全部渲染)
      
      # 兼容性
      - 行复选框从视觉上从最左 → 最右;功能(toggleRowSelection / clearSelection /
        selection-change)不变,依赖的是 row 对象不是列顺序
      - 全选 / 清空 / 反选 三个按钮逻辑不依赖列顺序
      
      # 文件清单
      - docs/WORKLOG.md       | +50 工作记录(排查过程 + 4 个 case 验证表)
      - web/static/index.html | +4 / -1 selection 列移位 + 约束注释
      a07db7bb
    • Data Governance Dev's avatar
      refactor(web): 数据字典抽到 connect-test + 步骤用 step_id 注册 + 修白屏 · 272c10ed
      Data Governance Dev authored
      ## 1. 操作模式重构(核心需求)
      
      按用户要求把 web 端的操作模式从"启动任务时抽数据字典 + 编号步骤"改成
      "测试连接时抽数据字典 + 步骤注册式可扩展 + 勾选表后再分析"。
      
      ### 后端
      - 新增 `web/core/data_dict.py`:`extract_data_dictionary(cfg)` 函数,
        connect-test 与 orchestrator 共用(避免重复查询)
      - 新增 `web/core/data_dict_cache.py`:按连接身份 (db_type/host/port/db/user)
        缓存字典,缓存命中走内存,未命中现场再抽
      - 删除 `web/core/step_impl/step1_data_dict.py`(从流程中彻底移除)
      - `web/core/orchestrator.py`:
        - 流程表从 `[(num, fn, ...), ...]` 改为 `dict[str, StepDef]`
        - 用 `register_step(...)` 装饰器一行注册一个 Step
        - `CRITICAL_STEPS` 改为 `{"merge_redundancy", "missing_comments"}`
        - `run_governance_workflow(..., tables: list[str])` 接受前端勾选的表
      - `web/core/models.py`:
        - `ConnectRequest.tables: list[str]`(必填,空时后端返 400)
        - `StepInfo.num: int` → `StepInfo.id: str` + `order: int`
        - `JobStatusResponse.current_step: Optional[int]` → `Optional[str]`
        - 所有步骤列表 `list[int]` → `list[str]`
        - `TestConnectionResponse` 新增 `table_summary` / `data_dictionary` 字段
      - `web/core/step_impl/step{2,4,5,6,7}.py`:
        - 全部新增 `table_filter: set[str] | None = None` 参数,开头过滤 `columns`
        - 全部 `step="N"` 字符串改为 `step="step_id"`(merge_redundancy / empty_fields / ...)
      - `web/core/job_manager.py`:`Job.current_step` / `steps_planned` / `steps_completed` /
        `steps_failed` 全部从 `int` 改为 `str`,`_sync_step_start/done` 同步
      - `web/api/routes.py`:
        - `/api/connect/test` 成功后 `extract_data_dictionary` + `cache.put`,
          返回 `table_summary` + `data_dictionary`
        - `/api/jobs` 校验 `tables` 非空,否则 `HTTP 400`
        - `/api/steps` 从 `get_step_defs()` 动态生成(不再写死编号)
      
      ### 前端 (`web/static/index.html` 全量重写)
      - 卡片 1:连接数据库(保留)
      - 卡片 2(新增):数据字典浏览器
        - 左侧 el-table(reserve-selection):表名 / 注释 / 字段数;
          全选 / 清空 / 反选 按钮 + 搜索框
        - 右侧 el-table:选中表的所有字段,按 (table_name, ordinal_position) 排序
      - 卡片 3:分析配置
        - 步骤勾选 + 「开始分析」按钮(label 实时显示 X 张表 / Y 项检查)
        - 表为空时按钮 disabled 并提示
      - 卡片 4:分析进度 + 日志(SSE 流式)
      - 卡片 5:分析结果(KPI + 多级表格)
        - `TAB_STEP_MAP` 改用 step_id,不再用编号
        - 移除所有 "Step N:" 前缀
      
      ## 2. 修复页面打开白屏
      
      `web/static/index.html` 打开后页面全白,根因两层叠加:
      
      ### 2.1 多余 `</el-option>`
      DB 表单"字符集"里写了 `<el-option ... />` 自闭合 + `</el-option>` 显式闭合,
      Vue 模板编译器报 `Invalid end tag` (compiler code 23)。
      修复:删除第 102 行的 `</el-option>`。
      
      ### 2.2 `v-else-if` 链断裂(Vue 3 compiler code 30)
      Vue 3 要求 `v-else` / `v-else-if` 必须是上一个 v-if 元素的紧邻兄弟。模板里:
      - 「重新分析」按钮的 `v-else-if` 与「取消」按钮的 `v-if` 中间夹了一个
        无 v-if 的「开始分析」按钮,链断
      - 「勾选提示」el-alert 的 `v-else-if` 上方是 `</el-form-item>`,也不是 v-if
      修复:去掉 v-else-if,改用独立 v-if 显式写互斥条件。
      
      ## 3. 验证
      
      - `python -c "from web.core import ..."` 全部通过
      - `python -m web.app` 启动 OK,注册 5 个 step
      - `/api/steps` 返回 `{id, order, title, ...}`(无 num)
      - `/api/connect/test` 无 DB 时 ok=false,含 `table_summary: []`, `data_dictionary: []`
      - `/api/jobs` 空 tables → `HTTP 400 {"detail": "tables 不能为空:..."}`
      - 用 jsdom 抓真服务器返回的 `#app.innerHTML`(59914 字符),
        喂给浏览器版 Vue 3.5.40 编译:errors=0, warnings=0
      - jsdom 完整挂载:`#app` 渲染 2 子元素 / 8484 字符真实 DOM
      
      ## 4. 兼容性
      
      - 旧的 `outputs/<db>/<ts>/findings/step_*_data_dict.json` 文件保留(前端不读)
      - `step8_report.py` 消费的 6 个 section key
        (`merge_candidates` / `redundancy_fields` / `empty_fields` /
        `missing_comments` / `length_issues` / `standard_violations`)全部保留
      
      ## 5. 文件清单
      
      新增:
      - `web/core/data_dict.py`
      - `web/core/data_dict_cache.py`
      - `docs/WORKLOG.md`
      
      删除:
      - `web/core/step_impl/step1_data_dict.py`
      
      修改:
      - `web/api/routes.py`
      - `web/core/job_manager.py`
      - `web/core/models.py`
      - `web/core/orchestrator.py`
      - `web/core/step_impl/step{2,4,5,6,7}_*.py`
      - `web/static/index.html`(全量重写)
      - `web/README.md`
      - `CLAUDE.md`(项目说明改为"数据治理工具,主要开发 web 端")
      - `.gitignore`(加 tags.lock / tags.temp)
      272c10ed
  6. 06 Aug, 2026 10 commits
    • Data Governance Dev's avatar
      fix(web): 冗余字段 tab 永远停在「分析中」— TAB_STEP_MAP.sectionKey 用错了 · 6c7bc274
      Data Governance Dev authored
      症状:分析完成后所有 tab 都显示「分析完成」徽章,但「冗余字段」
      tab 一直停在「分析中」,即使 sections.merge_candidates.redundancy_fields
      实际有 21 条数据。
      
      根因:移除 Step 3「数据验证」前,Step 3 返回 section_key='redundancy_fields',
      所以 sections.redundancy_fields 直接有数据。移除后没人再写这个顶层 key,
      数据落在 sections.merge_candidates.redundancy_fields(Step 2 输出
      嵌套在 merge_candidates 里)。
      
      修复:TAB_STEP_MAP 支持 field 字段处理嵌套场景:
        redundancy: { step: 2, sectionKey: 'merge_candidates', field: 'redundancy_fields' }
      
      tabStatus computed 检查改为先取顶层 section、再按 field 取子字段:
        const section = sections[sectionKey];
        const hasData = field ? (section && section[field]) : !!section;
      
      行为:
      - merge tab 还是查 sections.merge_candidates 整体
      - redundancy tab 现在查 sections.merge_candidates.redundancy_fields
      - 其他 tab 逻辑不变
      6c7bc274
    • Data Governance Dev's avatar
      fix(web): 恢复误删的 web/sql/verify/count_table_rows.sql · cc494bca
      Data Governance Dev authored
      上一次删除 Step 3「数据验证」时把这个 SQL 模板也删了,但实际
      Step 4_empty_fields.py(新 Step 3 大范围空字段扫描)也需要它来
      预先统计每张表的实际行数(拿真实 COUNT(*) 而不是 information_schema
      的 TABLE_ROWS 估算值)。
      
      症状:最近一次 run (20260806_144238) 把全部 149 张表都标记为
      "统计行数失败: SQL 模板不存在" → high_empty_fields_count=0,
      "大范围空字段" tab 完全没数据(虽然日志显示 Step 已"完成")。
      
      修复:恢复 web/sql/verify/count_table_rows.sql,并更新注释说明
      本 SQL 是 Step 3 大范围空字段扫描用的(不是 Step 3「数据验证」)。
      
      注意:需要重新跑一次分析才能拿到新的 empty_fields 数据。
      cc494bca
    • Data Governance Dev's avatar
      refactor(web): 重新编号 Step — 4-7 → 3-6,让步骤连续 1-6 · 472a0c4a
      Data Governance Dev authored
      移除 Step 3「数据验证」后,Step 号出现断层:1,2,4,5,6,7。重新编号让 Step 号
      连续 1-6,对用户更直观。
      
      改动:
      
      orchestrator.py:
      - STEP_REGISTRY:4→3 (空字段扫描), 5→4 (缺注释), 6→5 (字段长度), 7→6 (国标校验)
      - STEP_DEPENDENCIES 同步重新编号
      - step_name() 同步重新编号('3_empty_fields' / '4_missing_comments' / 等)
      - _run_step4/5/6/7 重命名为 _run_step3/4/5/6(调用方 STEP_REGISTRY 已对,自动匹配)
      - 顶部 docstring 重写:6 步流程 + 重新编号说明
      
      step_impl/*.py:每个文件里的 step="X" 日志标签同步重新编号
      (4→3, 5→4, 6→5, 7→6),同时把 docstring 和 message 文本里的 Step X 字样也改了。
      文件本身保留旧文件名(如 step4_empty_fields.py)—— 内部实现细节,
      不影响外部行为;如果未来想重命名可单独一次提交。
      
      routes.py:list_steps() 的 StepInfo 也重新编号(4→3, 5→4, 6→5, 7→6)
      
      frontend index.html:
      - form.steps 默认 [1,2,4,5,6,7] → [1,2,3,4,5,6]
      - 兜底过滤改成 n >= 1 && n <= 6(兼容旧缓存残留的 8/7/3)
      - TAB_STEP_MAP:
        - redundancy tab:step 3 → 2(与 merge 同一来源)
        - empty: 4 → 3
        - missing: 5 → 4
        - length: 6 → 5
        - standards: 7 → 6
      
      注:未触及 workflow/ 旧 CLI 目录、docs/DESIGN.md / README.md 文档,
      那些是历史描述,单独一次文档 PR 一起改。
      
      行为:UI 显示 Step 1-6 连续 6 个分析 Step,进度计算 / 报告生成
      / section 关联都不变。文件 / 函数命名差异仅是内部实现细节。
      472a0c4a
    • Data Governance Dev's avatar
      refactor(web): 移除 Step 3「数据验证」 · d2cd3ad6
      Data Governance Dev authored
      Step 3 实际产出价值低且有副作用:
      1. 「行政区划孤儿编码检查」只判断字典表 c_bri_xzqh 是否存在,
         没有真正跑 LEFT JOIN 找孤儿(代码注释里写了「可扩展」)
      2. 「数据质量问题检查」只是占位,返回空列表
      3. 「验证合并候选实际行数」有点用,但 result 已经直接覆盖 Step 2 的输出
      
      最致命的是 _run_step3 返回 section_key='redundancy_fields' —— 这会
      反向覆盖 Step 2 的 LLM 分类结果(classification / reasoning /
      recommendation 全没了,只剩 Step 3 的简单 field + table_count 列表)。
      也就是说 Step 2 的 LLM 工作被 Step 3 默默销毁了。移除 Step 3 同时也修了
      这个覆盖 bug,Step 2 的分类结果能正确进入报告。
      
      改动:
      
      - 删除 web/core/step_impl/step3_verify.py
      - 删除 web/sql/verify/ + web/sql/xzqh/ 整个目录(仅 Step 3 使用)
      - orchestrator.py:
        - STEP_REGISTRY 移除 (3, 数据验证, _run_step3, ...)
        - STEP_DEPENDENCIES 移除 3: {1, 2}
        - step_name() 移除 3: '3_verify'
        - 删除 _run_step3 函数
        - 顶部 docstring 重写:6 步流程 + 移除 Step 3 的原因
      - routes.py:list_steps() 不再返回 Step 3
      - job_manager.py:all_steps 默认值改成从 STEP_REGISTRY 取
        (保持单一来源,避免硬编码漏改)
      - frontend index.html:
        - form.steps 默认 [1,2,3,4,5,6,7] → [1,2,4,5,6,7]
        - 兜底过滤也加上 n !== 3(兼容旧本地缓存残留)
      
      注:未触及 workflow/ 旧 CLI 目录,它走的是另一套独立实现。
      
      行为:
      - UI 上「执行步骤」区只有 6 个分析 Step
      - /api/steps 返回 6 项
      - 主流程跑完后无条件生成报告(Step 8 拆出来之前的约定不变)
      - Step 2 LLM 分类结果不再被覆盖,能正确进冗余字段报告
      d2cd3ad6
    • Data Governance Dev's avatar
      fix(llm): Step 2 大量 llm_failed 解析失败 — max_tokens 1024 截断大批量响应 · fbedfe12
      Data Governance Dev authored
      症状:最近 run 里 Step 2「表合并与冗余字段分析」21/21 高频字段全部
      classification=unknown, source=llm_failed。但 LLM 调用本身成功
      (HTTP 200),只是解析阶段拿不到 valid JSON。
      
      根因:web/configs/llm.yaml 默认 max_tokens=1024。Step 2 让 LLM 返回
      每条 reasoning+recommendation 各 50-100 字中文 ≈ 200-300 tokens,
      15 字段 × ~250 tokens ≈ 3750 tokens 远超 1024 上限 → LLM 响应被截断
      在某个汉字中间 → JSON 不完整 → _safe_parse_json 返回 None → 21 个
      字段全标 unknown。
      
      复现:用真实 15 字段 prompt 调 complete(),返回 2824 字符但末尾
      "\u5e76\u4e14\u5bb9\u6613\u88ab'" 明显是截断。
      
      修复(A+B 一起):
      
      A. web/configs/llm.yaml:max_tokens 1024 → 4096,附注释说明为什么
      B. web/core/step_impl/step2_merge_redundancy.py:BATCH 30 → 8,
         附注释说明为什么
      
      实测验证(重启后):8 字段 batch 全部解析成功,分类到 4 种
      (suspicious/common_business/common_base/true_redundancy),没有
      任何 None 失败。
      
      下次跑 21 字段 → 3 个 batch(8+8+5),每个都能塞进 4096 tokens。
      
      注意:需重启后端服务才能让两处都生效(llm.py 是 Python 代码,
      llm.yaml 是启动时 LLMConfig.load() 一次缓存到 _client 单例)。
      fbedfe12
    • Data Governance Dev's avatar
      refactor(web): 报告生成不再作为 Step,主流程跑完后无条件触发 · e6fbfb51
      Data Governance Dev authored
      之前 Step 8 出现在 UI 的「执行步骤」复选框里,用户可取消勾选;后端也按 8 in steps 决定是否生成报告,导致:
      1. 用户可能漏勾导致拿不到报告
      2. 进度条分母里挂着「报告生成」让人误以为它也算分析步骤
      
      按用户要求,报告生成应该是分析完成的固定产出,不应该作为可选步骤。
      
      改动:
      
      - orchestrator.py
        - STEP_REGISTRY 移除 (8, 报告生成, ...) 一项
        - STEP_DEPENDENCIES 移除 8: set() 注释也清掉
        - step_name() 不再支持 8
        - 去掉 has_step8 / main_steps 不再过滤 8
        - 「开始 生成报告(Markdown + Word)」从 if 8 in steps 改为无条件执行
        - 顶部 docstring 改写说明新约定
      
      - job_manager.py:默认 all_steps 从 range(1,9) 改为 range(1,8)
      
      - routes.py:list_steps() 不再返回 Step 8;steps_planned 默认 range(1,9) → (1,8)
      
      - models.py:ConnectRequest.steps 注释从「默认全 8 步」改为「默认全 7 步;报告生成不在 steps 内」
      
      - step8_report.py:移除 4 处 step='8' 日志标签(不再是 Step)
      
      - frontend index.html
        - form.steps 默认 [1..8] 改为 [1..7]
        - startJob 兜底过滤:form.steps = form.steps.filter(n => n !== 8)
          (防止旧浏览器缓存里残留的 8 让后端报错)
        - form-hint 补充「报告生成不在步骤列表里,每次分析完成后会自动生成 Markdown + Word 供下载」
      
      行为:
      - UI 上「执行步骤」区只有 7 个分析 Step
      - /api/steps 返回 7 项
      - 主流程跑完后无条件生成报告,sections.reports.markdown/docx 照常返回
      - 关键 Step 失败时仍会 RuntimeError 终止整个任务(与之前一致,sections 数据不全就没东西可报告)
      e6fbfb51
    • Data Governance Dev's avatar
      feat(web): 报告内容完整化(Markdown + docx 全量明细) · 5d3c7883
      Data Governance Dev authored
      原 step8_report.py 两个问题:
      
      1. Markdown 每个章节都截前 10-20 条样本,详细信息缺失
      2. docx 后半部分只是 stub:标题 + f"{summary}" 把整个 dict 塞进段落,
         浏览器/Word 里看到的就是一坨 JSON 风格的字符串,没有表格
      
      重写方案:两个版本共用 SECTION_ORDER + 同名渲染函数(_md_xxx / _docx_xxx),
      保证两边结构对齐。
      
      新增/补齐的章节内容:
      
      - 表合并候选:完整候选明细(ID/优先级/相似度/公共列数/差异列/建议/风险)
        + 各候选组的公共列清单 + 强/弱废弃候选分开列表
      - 冗余字段:全部高频字段(不再截 20)+ LLM 失败标「⚠️ 待人工核对」
      - 大范围空字段:阈值说明 + 按表汇总(高空数倒序) + 字段明细按表分组
        (每张表高空/中空字段单独子表,含空值率) + 跳过表清单
      - 缺失注释字段:summary(涉及表/LLM 调用次数)+ 按表分布 + 推测注释明细
        (全列) + 未推测样本
      - 字段长度异常:6 个汇总指标 + 全部异常字段(按 wasted_bytes desc 排,
        10 列含国标/规则/依据)
      - 国标违规:按标准统计 + 每标准下的违规字段明细 + 违规样本(最多 500 条)
      
      辅助细节:
      - Markdown 表格换行用 <br>、管道符转义 \|、空值显示 -、浮点格式 xx.xx%
      - docx 用原生 add_table + style 'Light Grid Accent 1',Heading 1/2/3 分层
      - 顶层 docstring 说明新结构;SECTION_ORDER 单一来源驱动两版渲染
      
      smoke test:拿真实 outputs/smart-build/20260804_085733/findings/_all_findings.json
      跑过,Markdown 11425 字符 / 255 行,docx 24 段 + 7 张表格,数据正确。
      5d3c7883
    • Data Governance Dev's avatar
      fix(web): 报告下载链路修复(Markdown 按钮 + 字节流下载 + 路由路径) · 3687f62d
      Data Governance Dev authored
      三处问题一起修:
      
      1. Markdown 按钮点了没反应
         - 按钮 @click 传 'md',但 jobResult.reports 里的 key 是 'markdown'
         - downloadReport 拿不到 url,静默 return
         - index.html:188 downloadReport('md') → downloadReport('markdown')
      
      2. 改为字节流下载
         - 原方案 window.open('/api/reports/...'):浏览器把 .md 直接显示在页面上
         - 改 fetch + blob + <a download>:触发浏览器「另存为」对话框,体验正确
         - 路径正则兼容正反斜杠(Windows/Linux)
         - 三段(db/run_id/filename)都 encodeURIComponent
         - 错误用 ElementPlus.ElMessage.error 提示,不再静默退出
      
      3. API 路由路径少一段导致 404
         - routes.py 在 web/api/,少算一层 base 就跨过了 web/ 目录
         - 原 base = <项目根>/outputs/...,实际文件在 <项目根>/web/outputs/...
         - .parent.parent.parent → .parent.parent,与 job_manager.py 保持一致
      3687f62d
    • Data Governance Dev's avatar
      fix(web): 大范围空字段「按表统计」展开行改用原生表格渲染 · 3f71fa27
      Data Governance Dev authored
      嵌套 el-table 在 expand 行里列宽不稳定(之前两版:先加 width:100%,再换 overflow-x:auto + minWidth,都仍只渲染出 3 列,注释/空值率被挤掉)。
      
      改为原生 <table class="inner-empty-table">,浏览器原生 table 渲染稳定可靠:
      - 列定义:字段名 160 / 类型 100 / 注释 auto / 空值数 110 / 空值率 220
      - 保留 el-progress 进度条展示空值率
      - style.css 新增 .inner-empty-table 样式:表头浅灰、边框、斑马纹、悬停高亮
      
      确认硬刷新(Ctrl+Shift+R)后展开任一行,5 列正常横向排开。
      3f71fa27
    • Data Governance Dev's avatar
      feat(web): LLM 步骤加图标/提示 + 隐藏达梦选项 · 23c896f5
      Data Governance Dev authored
      两处前端 UI 调整:
      
      1. LLM-required 步骤(Step 2 / 5)加 🪄 MagicStick 图标 + tooltip 提示
         - 图标橙色 #e6a23c,仅在 s.llm_mode === 'required' 时显示
         - hover 提示'此步骤需要调用大模型,可能会比较耗时'
         - 标题后追加'需 LLM' warning tag,与'必选'红色 tag 并列
         - form-hint 升级:'带 ✨ 图标的步骤需调用大模型,耗时会较长
           (每步数秒到数十秒)'
      
      2. 数据库类型只露 MySQL:
         - 删 el-radio-button label='dameng'
         - 后端 API 仍接受 db_type='dameng',只是 UI 不再露选项
         - form.db_type 默认 'mysql' 不变
      
      验证:MagicStick 在 element-plus/icons-vue 包内;
      本地 == HTTP 服务返回(66056 字节)。
      23c896f5