• 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
data_dict_cache.py 2.17 KB