1. 10 Sep, 2026 5 commits
  2. 09 Sep, 2026 1 commit
  3. 07 Sep, 2026 4 commits
  4. 24 Aug, 2026 21 commits
    • Data Governance Dev's avatar
      feat(web3): 数据质量页加「点击 ! 图标 AI 分析」入口提示 · 6eac98c4
      Data Governance Dev authored
      任务信息条右侧大片空白,用户不知道数据明细里红色 ! 图标可以点,
      P2 上线的「一键问 LLM」功能完全没被触达。
      
      加 .ai-hint chip:橙底橙字 + pill 圆角 + hover 加深,v-if="rows.length > 0"
      只在有不合规行时显示。文案:💡 点击单元格的红色 ! 图标进行 AI 分析,
      红色 ! 复用表格 ! icon 同色(#f56c6c)做视觉关联。
      6eac98c4
    • Data Governance Dev's avatar
      fix(web3): 编辑任务弹窗补回表注释显示 · b56174a1
      Data Governance Dev authored
      编辑弹窗打开时 tableOptions = [](用户没点过测试连接),
      el-select 渲染 label 时查不到匹配 entry,退化成只显示纯表名(GR_GRXX)。
      
      form.tableComment 本身已经从 props.task.table_comment 回填了,
      只是没注入到 tableOptions 里。修法:从 props.task 构造一条合成 entry
      注入 tableOptions,点「测试连接」后 loadTables 会用真实列表覆盖,
      不影响后续流程。
      b56174a1
    • Data Governance Dev's avatar
      fix(web3): vite dev server 监听 0.0.0.0,支持 LAN 访问 · 8bf84b17
      Data Governance Dev authored
      默认配置下 server.host 不配 → vite 绑 localhost,LAN IP(如 192.168.x.x)
      访问直接 ERR_CONNECTION_REFUSED。
      
      加 host: '0.0.0.0' 监听所有网卡;第一次启动 Windows 防火墙会弹询问,
      需要允许。
      
      ⚠️ dev server 现在暴露在局域网里,敏感环境慎用。
      8bf84b17
    • Data Governance Dev's avatar
      fix(web3): RuleModal 规则名/规则说明行的右边缘对齐「复制」按钮 · 577fca07
      Data Governance Dev authored
      原来两行 input/textarea 独占整行右侧,视觉上跟下面 Python 函数/正则行
      (右侧带 复制 按钮)对不齐,弹窗右边空旷不对称。
      
      按 .btn(padding 0 16px + 1px border + 14px 中文 2 字 ≈ 28px = 62px)
      设 .rule-line-spacer 占位宽度,规则名 / 规则说明行也用 .rule-flex-line
      包成 [input/textarea][62px 占位] 跟 .code-line / .test-line 同一套结构。
      
      flex 子项显式 min-width: 0,覆盖全局 .text-input { min-width: 160px }
      避免窄容器溢出。顺手给原裸 textarea 补 padding/border/radius/font
      跟其他输入框视觉一致。
      577fca07
    • Data Governance Dev's avatar
      fix(find-field): 修两个 MySQL 兼容 bug · ddbe0048
      Data Governance Dev authored
      1. MySQL 8.0 INFORMATION_SCHEMA.COLUMNS 没有 TABLE_COMMENT 列
         - 原查询 SELECT TABLE_COMMENT FROM INFORMATION_SCHEMA.COLUMNS 直接报 1054
         - 改成 LEFT JOIN INFORMATION_SCHEMA.TABLES 拿表注释
      
      2. schema/table 名含 '-' 时 quote_ident 校验失败
         - web3/backend/core/db_adapter.py::quote_ident 用 ^[A-Za-z_][A-Za-z0-9_]*$ 校验
         - 但 MySQL 的 schema/table 名合法可含 '-', 只要用反引号包即可
         - 仅在 skill 脚本 table_row_count() 里给 MySQL 分支走自定义 _safe_mysql_ident,
           其他方言照旧用 quote_ident, 不动通用 db_adapter 逻辑
      
      触发场景: 查 smart-build 库时直接报错; 修完后能正常输出 6 张含 credit_code/uscc 的表
      附加: 踩坑已记录到 memory (mysql-information-schema-columns-no-table-comment)
      ddbe0048
    • Data Governance Dev's avatar
      fix(web3): TaskModal 任务分组下拉去掉「+ 新建分组」选项 · 0a4f6eaa
      Data Governance Dev authored
      任务分组应由后端 taskGroups 码表统一管理,弹窗里加 + 新建分组
      会让用户随手造出码表外的分组,导致任务列表/侧边栏展示与码表对不上。
      全文件 grep 无其他配套代码,直接删干净。
      0a4f6eaa
    • Data Governance Dev's avatar
      fix(web3): ExplainIssueDialog match(一致)时不展示一致性结论条 · 323090fd
      Data Governance Dev authored
      LLM 审查结论为 match(代码正确实现规则)时,右栏的「✅ 一致:代码正确
      实现了规则」绿条不再展示 —— 既然一致,这条结论本身就成了冗余信息。
      违规原因卡片继续展示,左栏的规则说明 + 代码也始终保留,方便用户对照。
      323090fd
    • Data Governance Dev's avatar
      feat(web3): 字段配置 + 任务字段表加 ⤒ 置顶 + 重试提示跟随滚动 · a3b54910
      Data Governance Dev authored
      字段配置(FieldConfigDrawer)与任务编辑(TaskModal 默认展示列):
      - ↑↓ 按钮组前再加一个「⤒ 置顶」按钮,splice(idx, 1) + unshift
        把对象字段直接搬到列表最前(非交换),首行禁用
      - FieldConfigDrawer 三个按钮右对齐:把 .field-comment-icon 的
        margin-left: auto 移除,让 .ord-group 独占推右责任,ⓘ icon 紧跟其后
      
      ExplainIssueDialog LLM 弹框:
      - LLM 未按 JSON 输出时的重试说明(原独立 .note-block 灰底框)
        嵌进违规原因卡片底部,跟 reason-text 一起被父容器滚动
        - 虚线分隔 + 小字号 + 灰字,跟违规原因区分但不抢眼
      a3b54910
    • Data Governance Dev's avatar
      feat(web3): 字段配置加 ↑↓ 调整展示顺序 · cfc4c803
      Data Governance Dev authored
      字段配置(FieldConfigDrawer + TaskModal 字段表)新增 ↑↓ 排序按钮,
      调整字段在结果表里的展示列顺序:
      
      - FieldConfigDrawer:每项右侧加 ↑↓ 按钮组,icon 左边
        - 把原来的 localChecked dict 改成 localItems 数组(同时管顺序 + 勾选)
        - 保存时 emit 完整字段顺序 + 仅勾选字段
      - TaskModal:字段表去掉最左「排序」列,只在「默认展示」checkbox
        左边留 ↑↓(统一入口,列宽 130 → 170px 给按钮腾空间)
        - 空数据行 colspan 同步 6 → 5
      - ResultTable:allColumns computed 在 visibleFields 非空时按其顺序排
        (FieldConfigDrawer ↑↓ 调整的结果),无 visibleFields 时回退原序
      - 样式:.ord-btn / .ord-cell / .ord-group 抽到 global.css
        初始上下排版,用户反馈丑 → 改为左右排版(flex-direction: row)
      cfc4c803
    • Data Governance Dev's avatar
      fix(web3): ExplainIssueDialog 规则说明过长导致左栏溢出截断 · 8450d6f3
      Data Governance Dev authored
      现象
      点「!」弹框左栏「规则说明」desc 很长的规则(如邮箱校验规则 8 / 200+ 字),
      整段 desc 没有最大高度限制,把左栏撑爆,下面的「规则代码」标题 + code-block
      被视觉截断;右侧的 pane-title-tag(规则类型胶囊)跟 desc-block 视觉重叠,UI 崩。
      
      修复
      src/components/ExplainIssueDialog.vue
      - .explain-dialog 加 min-height: 0
        (flex 子容器需要 min-height: 0 才能让 overflow 真正生效;
         否则 flex item 默认 min-height: auto,会按内容撑开无视 max-height)
      - .desc-block 加 max-height: 200px; overflow-y: auto
        跟 .code-block 视觉统一;超长 desc 内部独立滚动,不再撑爆左栏
      
      效果
      - 规则说明超 200px → 内部独立滚动条
      - 整个 dialog 高度超 84vh → .modal-body 兜底滚动
      - 两层滚动不冲突(外层兜底,内层是单段 desc 限高)
      
      验证
      npx vite build → ✓ built in 6.80s
      
      注
      4 个 web3/tests/*.png modified 未提交(与本修复无关)
      8450d6f3
    • Data Governance Dev's avatar
      feat(web3): 规则设置弹窗 · 从其他任务导入规则 + 字段中文标签 · 5f6fe045
      Data Governance Dev authored
      动机
      1) 每建一个新任务都要从零手写规则,重复劳动严重。
         任务间的规则往往通用(手机号格式、身份证校验、年龄范围),希望能从已有任务复制。
      2) 导入弹框只显示 ZJHM 这种英文列名,业务人员看不懂字段是啥意思。
         需要在字段标题后补字段中文标签(数据库列注释)。
      
      改动
      src/components/ImportRulesDialog.vue (新)
      - 左右两栏布局(960px 宽):
        · 左列:所有非自身的任务列表(listTasks(),过滤掉 currentTaskId)
        · 右列:选中任务的所有字段+规则(getTask(id) 拿详情,按字段分组),每条规则 checkbox
      - 字段标题:field_key + field_comment 横排显示(comment 为空时「(无字段注释)」灰斜体兜底)
      - 顶部「全选 / 反选」;底部「已选 N 条 + 取消 + 导入 N 条」
      
      src/components/RuleModal.vue
      - 在 + 添加规则 下方加「📥 从其他任务导入规则」按钮(绿色边区分)
      - 新增 taskId prop + importOpen ref + onImportRules()
      - 去掉后端 id(避免保存时按 id 当 update 走错路径),用 Date.now()+count 生成临时占位 id
      - 清空 testVal/testResult(让用户在新字段下重新测试)
      
      src/components/TaskModal.vue
      - <RuleModal> 加 :task-id="props.task?.id || 0"
      
      backend/routers/tasks.py
      - FieldOut 加 comment: Optional[str] = None
      - 新增 _fetch_field_comments(t, conn):用任务自身的 conn_json 连一次数据源,
        调 db_adapter.list_columns() 拿 {field_key: column_comment}
        · 连接信息不全 / 连不上 / 表不存在 → 降级返回空 dict,不报错(comment 是辅助信息)
        · 复用既有 db_adapter,无新依赖;schema/table_name 走绑定参数无 SQL 注入
      - _row_to_out(include_field_list=True) 时拉一次 comment_map 注入每个 FieldOut
      
      关键决策
      - 后端主动拉 comment 而非前端:前端拿不到密码
      - 失败不报错:comment 缺失不影响主流程
      - 不持久化到 Field 表:跟 plan §4 决策一致——数据字典不存,每次按 task 重新拉
      
      Bug 修复
      第一次实现时 computed 返 {fieldKey, fieldComment, rules},但模板里写了 v-if="group.comment",
      comment 没定义 → 永远 falsy → 显示「(无字段注释」兜底。不报错只静默渲染空。
      改成 v-if="group.fieldComment"。已记到 memory(vue-computed-template-prop-name-mismatch)。
      
      验证
      - 后端 TestClient: GET /api/tasks/24 → field_list[ZJHM].comment = '证件号码 | 数据标准: 01010007' ✓
      - npx vite build → ✓ built in 7.09s(1640 modules,无报错)
      
      注
      - 4 个 web3/tests/*.png modified 未提交(与本功能无关)
      - 后端有改动需用户重启进程
      5f6fe045
    • Data Governance Dev's avatar
      feat(web3): 数据明细「!」一键问 LLM · 违规原因 + 规则 vs 代码一致性审查 + 多 tab 并行 · 5cb07f5a
      Data Governance Dev authored
      动机
      用户在结果表看到红 ! 标记的不合规行时,只能从 tooltip 看违反哪条规则,
      但不知道为什么错、这条规则的代码是否真的实现了规则描述。需要点 !
      直接问 LLM,让模型同时审计数据违规原因和 规则 vs 代码 一致性。
      同一字段常违反多条规则(如「11 位数字」+「号段分配」),需要开多个 tab 并行诊断。
      
      改动
      backend
      - core/ai_explain.py (新): explain_issue() 拼 prompt 调 LLM,解析 JSON,
        失败时附带上次原文 + 修复提示自动重试,最多 3 次;JSON 解析失败不抛异常,
        降级返回原文 + consistency='unknown'
      - routers/ai.py: 新增 POST /api/ai/explain_issue 端点
        (ExplainIssueRequest/ExplainIssueResponse Pydantic)
      - routers/queries.py: _evaluate_row() 的 issues 字典追加 rule_id
      - core/session_manager.py: CompiledFieldRules.rules 快照元组 6 元→7 元
        (追加 rule_id),让 _evaluate_row 能拿到规则 id
      
      frontend
      - components/ExplainIssueDialog.vue (新): Teleport + 自定义 .modal 模式
        · ctx-strip 顶部展示字段名 + 原始值(所有 tab 共享)
        · 多 tab 行:每条违规规则一个 tab,打开即 Promise.allSettled 并行调 LLM
        · 每个 tab 独立 loading/result/error 状态(互不干扰)
        · tab 标题旁小圆点:加载中蓝色脉冲 / 失败红 ⚠ /
          完成按 consistency 染色(绿✓ / 红! / 黄? / 灰·)
        · 单 issue 时隐藏 tab 行
        · 「重新分析」只重跑当前 active tab
      - components/ResultTable.vue: .err-flag 加 cursor:pointer + @click.stop,
        emitExplainIssue() 把该字段所有命中的 issue 都 enrich 后塞进 issues[]
        一起 emit(之前只取第一条,第二条违规原因被忽略)
      - views/DataQualityView.vue: 监听 explain-issue → 打开 ExplainIssueDialog
      - api/ai.js: explainIssue(payload) 导出
      
      LLM Prompt 关键设计
      - 系统提示强调「先想清楚再用严格 JSON 输出」
      - 用户提示拆任务 1(违规原因)+ 任务 2(一致性审查),
        加 ASCII 双引号避坑(历史踩坑:value 里用裸 " 会让 json.loads 中断)
      - 一致性三档:match / code_bug / rule_ambiguous
      
      关键决策
      - Promise.allSettled 而非 Promise.all:单条 LLM 失败不应拖垮其他 tab
      - LLMUnavailable 不重试(无 key / 网络挂 / 限流):立即降级返回
      - 重试时附上次原文:让 LLM 看到自己刚才错在哪,比纯说「修一下 JSON」有效
      - 「重新分析当前规则」而非「全部重试」:定位精准,省 token
      
      E2E 验证
      - regex 类型:consistency='code_bug'(LLM 正确识别硬性限制年份的 bug)
      - number 类型:consistency='rule_ambiguous'(LLM 指出「0-150 是否合理」需业务再斟酌)
      - npx vite build → ✓ built in 10.92s(1638 modules transformed,无报错)
      
      注
      - work-logs/2026-08-24.md 已记录三轮迭代详情 + 踩坑
      - 另有 4 个 web3/tests/*.png modified 未提交(与本功能无关)
      5cb07f5a
    • Data Governance Dev's avatar
      fix(web3): in-flight 时禁止切换分组 · f3a3ab93
      Data Governance Dev authored
      用户反馈:邮箱分组跑完后切别的分组能看到老结果 → 上一节已修;
      再继续叠加"in-flight 期间切分组→ 切回来自动续跑"方案后又出新 bug
      (resultFields 与 rows/lastResult 串数据),放弃了复杂的续跑逻辑。
      
      简化方案:watch(type) 头部拦截 runningQuery=true,
      弹 ElMessage.warning + router.replace 回原 type,不做切。
      
      - typeReverting 旗子防 router.replace 触发的二次 watch 循环
      - 跑完后的 cacheByType / applySnapshot 保留(切走再切回仍能看历史结果)
      - continueQuery + takeSnapshot.inFlight 元数据暂留(未来如恢复续跑逻辑可复用)
      - build: ✓ built in 6.81s
      f3a3ab93
    • Data Governance Dev's avatar
      fix(web3): TaskModal 编辑任务时 schema/table 被 watch(form.dbType) microtask 阶段清空 · 25cb466d
      Data Governance Dev authored
      现象:编辑 Oracle 任务,「数据连接」Tab 的 Schema/数据表 下拉空白显示
      「请先测试连接」。连接字段正确回填,但 schema/table 区域像新建任务一样
      要重新选。
      
      根因:watch(open) 编辑分支同步执行 form.dbType = task.db_type(即把
      默认值 'MySQL' 改成 'Oracle')后,Vue 把 watch(form.dbType) 排进 microtask;
      同步代码继续把 form.schema / form.table 从 task 回填完毕。等当前 microtask
      跑完,watch(form.dbType) 才执行函数体,里面 '切方言就清 schema/table' 的
      清理逻辑把刚回填的值一并清空。MySQL 任务也有这个 bug,只是 schema 通常
      等于 db,看起来症状没那么明显。
      
      修法(方案 A):
      - 加 isInitializing ref 作为初始化旗子
      - watch(open) 入口 isInitializing=true,结束后 await nextTick() × 2 + false
      - watch(form.dbType) 头部 if (isInitializing.value) return
      
      用户主动切 dbType / applyPreset() 行为不变(旗子默认 false,watcher 正常清理)。
      
      验证:
      - npx vite build → ✓ built in 7.00s
      - 编辑 Oracle 任务 → Schema/数据表 自动回填,不再显示「请先测试连接」
      - 新建任务切 dbType / applyPreset() 行为不变
      25cb466d
    • Data Governance Dev's avatar
      feat(skill): 新增 find-field —— 跨库盘点字段 + 行数 + 视图溯源 · 0634fb08
      Data Governance Dev authored
      新建 .claude/skills/find-field/:
      - SKILL.md:调用方式 / 参数 / 输出格式 / 6 条踩坑 / 安全约束
      - scripts/find_field.py:从 web3 connection_preset 读连接,三方言
        (MySQL/达梦/Oracle) 扫列名 + COUNT(*) + USER_DEPENDENCIES 溯源 V_* 视图
      
      安全:
      - 数据库连接只能选 web3 已存的(13 个预设),不允许临时输入密码
      - 只读 SELECT,不发 DML(CLAUDE.md 原则)
      
      附带 web3/tests/_probe_gjj80_bankcard.py:
      GJJ80 一次性探测脚本,作为本次 skill 命名的原型被保留作历史对照。
      SKILL.md 里点名「已被本 skill 取代」,但保留 git 历史。
      
      验证:find-field huanggang-gjj 银行卡号 → 与一次性脚本结果完全一致
      (V_JCFX_DWXX 11768 + V_JCFX_GRXX 567523 + 基表 GJ_DWXX/GJ_GRXX)
      0634fb08
    • Data Governance Dev's avatar
      feat(web3): RuleModal 新建规则时「跳过空值」默认勾选 · b0b09f46
      Data Governance Dev authored
      - src/components/RuleModal.vue:248 addRule() 把 skip_null 默认值 false→true
      - 编辑/复制老规则不走 addRule(),skip_null 仍按 r.skip_null 实际值显示
      - 保存链路 onSave 仍透传 !!rule.skip_null,不强制覆盖存量数据
      
      业务上「空值不计入不合规」更符合直觉,省得用户每加一条新规则手动勾。
      b0b09f46
    • Data Governance Dev's avatar
      feat(web3): 导出 Excel 加违规单元格浅红 + Review Note 写规则详细 · 8d71b57f
      Data Governance Dev authored
      页面上数据明细的红格 + hover tooltip 在 Excel 里丢了,
      业务人员拿到的导出文件看不到「哪几格不合规 / 为什么不合规」,
      还得回系统查。
      
      src/utils/excel.js 加 applyErrorHighlight():
      - 数据行起始偏移 = 2(前两行是注释行 + 字段名行)
      - row.errorCells.includes(cols[C].key) → 给那个 cell 加浅红底 + 写 Excel Note
      - 浅红 #FEF0F0 + 红字 #F56C6C,跟页面上 .cell-error 同色
      - Note 内容每行一条 issue:规则名:desc(name 空时回退 desc)
        —— 跟 ResultTable.errTip 同款格式;Note 空间够,把 desc 详细全展开
      - 作者标「数据治理工具」方便业务识别
      - 调用方零改动:errorCells/issues 已在 DataQualityView 透传,excel.js 直接读
      - 不传 errorCells/issues 的复用场景安全:length===0 直接 continue 跳过
      8d71b57f
    • Data Governance Dev's avatar
      fix(web3): ResultTable cell tooltip 精简只列规则名 · a9e0336b
      Data Governance Dev authored
      errTip() 改成 .filter() + join(';') 后,格式是 name(desc),
      但 desc 太长(动辄一二百字),在小 tooltip 里展开反而看不清是哪几条规则。
      
      cell tooltip 只列违规的规则名(name),desc 不再展开;
      表头 ruleHint 保持 name(desc)不变,那里用户需要看规则定义。
      
      效果对比:
      - 改前:11位数字(11位数字);首位两位数字规则(第 1 位:固定为 1 ...)
      - 改后:11位数字;首位两位数字规则
      
      老规则(name 为空串)回退到 desc。
      a9e0336b
    • Data Governance Dev's avatar
      fix(web3): RuleModal 允许保存空规则列表 · 9890df70
      Data Governance Dev authored
      字段原本有规则,点「规则设置」进 RuleModal 把所有规则删完,
      「保存」按钮被 length>0 限制变灰卡死。
      
      语义上用户明确点删除就是想清空,字段应该回到「无规则」状态;
      后端 _replace_fields 收到空 f.rules 也只是不写任何 Rule,本来就支持。
      
      去掉 length>0 && 这一截。Array.every() 对空数组天然返回 true
      (vacuous truth),删空所有规则后保存按钮就亮起来。
      9890df70
    • Data Governance Dev's avatar
      feat(web3): rule 表加「规则名称」列 → 前端展示「违反哪条规则」 · 69eea339
      Data Governance Dev authored
      数据明细(不合规行)当前只展示「哪个字段不合规」,没有「哪条规则被违反」。
      desc 是给 LLM 看的自然语言(含「必须 18 位」指令式描述),
      不适合直接给用户看。加独立字段 name 给前端展示,desc 继续喂 LLM。
      
      【schema 变更】
      - rule.name TEXT NOT NULL DEFAULT ''(老规则保持空串,迁移不破坏存量)
      - _migrate_rule_name():ALTER TABLE ADD COLUMN name(幂等,123 条老规则验证保留)
      
      【API 校验】
      - RulePayload.name: str = PydField(..., min_length=1) —— 必填
      - RuleOut.name: str = "" —— 老规则空串兜底
      
      【检测引擎链路】
      - CompiledFieldRules.rules 5 元 → 6 元(追加 name)
      - _load_task_compiled snapshot / rule_list 都带 name
      - _evaluate_row 返回 issues: {field, name, desc}
        → bad_rows 透传到前端「数据明细」备注列
      
      【前端 UI】
      - RuleModal:在「规则说明」上方加「规则名称」输入框(红星必填)
        - hasValidRules 加 name.trim() 校验
        - onSave 序列化带 name
        - namePlaceholder 按 rule_type 给不同示例
        - scoped .required 红星样式(不污染全局)
      - ResultTable:ruleHint / errTip / 备注列 issues 优先展示 name
      - FieldConfigDrawer:ruleHint 同步升级「name(desc)」格式
      
      【兼容策略】
      - 老规则 name=空串,UI 三处自动回退 desc 显示
      - 编辑老规则保存时强制补 name(避免历史脏数据持续累积)
      
      【测试】
      - test_rule_types_e2e 6 处 rule payload 补 name(Pydantic 必填后端会拒 422)
      - pytest tests/ → 123 passed
      - vite build → ✓ built in 9.64s
      - 冒烟:init_db() 对线上 DB 跑迁移,老规则全保留默认 ''
      69eea339
    • Data Governance Dev's avatar
      fix(web3): TaskModal「测试连接」按钮被长提示挤成竖排 · cc4144fd
      Data Governance Dev authored
      数据连接 Tab 点测试后,提示文本把按钮挤到 ~30px,
      「测试连接」四字竖排(测/试/连/接 各一行)。
      
      根因:
      - .conn-form-grid 给所有 input 行加了 max-width:150px,
        但 selector 没排除 .form-row.full,「测试连接」行
        是 .full(横跨 3 列 = 720px),里面的 .form-control
        却被锁死 150px
      - 通用 .btn 没有 flex-shrink:0,被 flex 父挤压
      
      修两处:
      - .conn-form-grid > .form-row:not(.full) .form-control
        限宽 selector 收窄到非 full 行,6 个 input 行照旧,
        full 行放开用满 720px
      - 通用 .btn 加 flex-shrink:0 + white-space:nowrap,
        顺手防御其他按钮同类问题
      cc4144fd
  5. 21 Aug, 2026 9 commits
    • Data Governance Dev's avatar
      feat(web3): FieldConfigDrawer 字段后也显示「⚠ N规则」徽章 · e4af262d
      Data Governance Dev authored
      结果表表头已经显示规则数徽章 + tooltip 列规则 desc,但字段配置面板(drawer)
      只显示字段名 + 注释图标 —— 用户看不到「这个字段有几条规则」。
      
      复用 f.rules / f.ruleList(DataQualityView 在 resultFields 已经塞了,
      不用改父组件),加 el-tooltip + ⚠ N规则 徽章。
      
      布局:rule-mark 插在 .en 后、comment icon 前;
      .comment-icon { margin-left: auto } 推最右,所以
      - 有规则 + 有 comment:cn/en/rule-mark 靠左,icon 推右
      - 有规则 + 无 comment:cn/en/rule-mark 自然铺开
      - 无规则 + 有 comment:cn/en + icon 推右(不变)
      - 无规则 + 无 comment:cn/en(不变)
      
      scoped CSS .rule-mark:黄橙色 #e6a23c + help 光标,
      跟 ResultTable 表头 rule-mark 视觉一致。
      e4af262d
    • Data Governance Dev's avatar
      feat(web3): 沙箱 import 白名单扩到常用纯计算类库(json/unicodedata/collections/dataclass 等) · c0bdbc92
      Data Governance Dev authored
      用户反馈:AI 生成 JSON 校验函数,运行时报 ImportError: 'json' is not allowed。
      原白名单只有 6 个模块(datetime/time/math/decimal/re/_strptime),太窄。
      
      设计准则:「只能改内存里的 Python 对象,不能碰进程外的东西」——
      纯计算 / 数据结构类库一律放;I/O、网络、进程、动态执行类一律不放。
      
      白名单(31 个):
        数据 / 时间  : datetime, time
        数学 / 数值  : math, decimal, fractions, statistics, numbers, operator
        字符串 / 编码: re, string, unicodedata, html
        数据结构     : collections, collections.abc, itertools, functools
        序列化 / 二进制: json, csv, struct, array
        编码 / 哈希  : hashlib, base64, binascii
        实用工具     : uuid, enum, dataclasses, typing, difflib
        其他         : copy, pprint, reprlib, ipaddress
      
      故意不放:os/sys/pathlib/subprocess/pickle/ctypes/importlib/socket/...
      连 urllib.parse 也不放(import urllib 后 urllib.request 属性访问能拿到,副作用太大)。
      
      沙箱三件套(踩坑):
      1. builtin 白名单加 __build_class__ —— class X: / enum.Enum / @dataclasses.dataclass 都靠它;
         动态 type('X', (), {}) 走 type.__call__ 不经过它,所以风险 ≈ 0
      2. namespace 预填 __name__ / __qualname__ —— enum/dataclass metaclass 会查
      3. __name__ 必须用 '__main__' 不能用假名 —— dataclasses._is_type 内部
         sys.modules.get(cls.__module__).__dict__,假名返 None 然后 .__dict__ 报错
      
      另:
      - ai_rule.py 的 number / date / string prompt 都加上「沙箱已预注入的常用模块」清单
      - RuleModal.vue 的 string rule 提示区也列已预注入模块清单
      - test_rule_runner.py 新增 TestSandboxImports 类,46 个用例
        (26 个模块 smoke + 3 个 import 形式 + 16 个危险模块被拦 + 1 个 urllib 被拦)
      
      验证:
        python -m pytest web3/tests/  →  123 passed, 3 warnings
        npx vite build                →  ✓ built in 6.84s
      c0bdbc92
    • Data Governance Dev's avatar
      fix(web3): TaskModal UI 整理(基础信息两列对齐 + 连接字段3列紧凑布局 + 删冗余提示) · 75f471e3
      Data Governance Dev authored
      基础信息 tab:
      - 删除「用户在查询下拉框看到的名称,建议格式:校验类型_表名」提示文字
      - form-grid 加 .basic-info-grid class + CSS 让前两个 form-row(任务名称 / 任务分组)
        各占 grid 一列水平对齐;任务说明仍 .full 占整行
      
      数据连接 tab 「连接方式」section:
      - form-grid 加 .conn-form-grid class + CSS 改 3 列布局 + 固定列宽 240px
      - .form-control { max-width: 150px } 缩 input 容器 —— 只在 conn-form-grid 作用域下生效,
        不污染全局 .text-input width:100%(避免影响其他弹框 FieldConfigDrawer / RuleModal 等)
      - 6 个 input 紧凑靠左排列,不再撑满 modal
      
      数据连接 tab 「数据表」section:
      - 删除「选择数据表后自动加载该表全部字段」提示文字
      - loading 提示「正在加载表列表...」保留
      75f471e3
    • Data Governance Dev's avatar
      feat(web3): 规则类型加 'string' + 「跳过空值」开关 · 33b60dc0
      Data Governance Dev authored
      字符串规则 (rule_type='string'):
      - RULE_TYPES 扩展;rule/code 列与 number/date 共用,存 Python def check(value) -> bool
      - ai_rule.py 加 _STRING prompt 模板(字符串语义:len/startswith/re)
      - RuleModal tab 加「字符串」+ desc/codePlaceholder/aiBtnLabel 分支 + Python 函数 hint 提示 value 是字符串
      
      跳过空值开关 (skip_null):
      - rule 表加 skip_null 列(INTEGER NOT NULL DEFAULT 0)+ 迁移函数
      - run_rule() 入口短路 None/空 str/空 bytes(regex 在 _evaluate_row 内联短路)
      - RulePayload/RuleOut + _replace/_copy/_row_to_out + _load_task_compiled 全链路透传
      - RuleModal 「规则类型」行右侧加 checkbox;测试/保存透传 skip_null
      - /api/rule/test 同步支持(用户在 RuleModal 测试空值时也走短路)
      
      UI 修复:
      - 「规则类型」行用嵌套 modifier .rule-type-row flex 化,不污染其他 grid cell 行
        (之前全局改 .rule-item-ctrl flex 把 .code-line/.test-line/.regex-line 全压塌)
      
      测试:
      - test_rule_types_e2e.py 加 4 个新用例(string 持久化 + dispatch + skip_null=False/True + regex skip_null)
      - FAKE_TABLE_ROWS 加 2 行空值('' + None),覆盖 skip_null 场景
      - test_rule_runner.py RULE_TYPES 常量断言更新
      
      后端 77 passed;vite build clean
      33b60dc0
    • Data Governance Dev's avatar
      feat(web3): 任务列表加「表注释」列 + TaskModal 选表时拉存 · 29987689
      Data Governance Dev authored
      1. TaskModal.vue
      
         form 加 tableComment 字段
      
         watch(form.table) 从 tableOptions 找对应项的 table_comment 写入
      
         编辑场景从 props.task.table_comment 回填
      
         payload 加 table_comment: form.tableComment || null
      
         选表时存一次到 task,列表直接读,零 N+1 查询
      
      2. TaskConfigView.vue
      
         模板加 <th>表注释</th>(位置在数据表后)
      
         colspan 8 → 9
      
         td 渲染 {{ row.table_comment || '—' }}
      
      3. 后端 commit 已加 task.table_comment 列 + 字段流通(commit 3)
      
         老任务没存过 → 列表显示「—」,重新编辑任务选一次表就有
      29987689
    • Data Governance Dev's avatar
      feat(web3): task 表加 checked_at + table_comment 元数据列 · 21ee05b2
      Data Governance Dev authored
      两个独立功能(同一个表的两列)一起做,因为迁移逻辑都走 init_db 兜底:
      
      1. task.checked_at: TIMESTAMP NULL
      
         schema.sql / Task ORM 加列
      
         _migrate_task_checked_at() 在 init_db 里兜底
      
         routers/queries.py::start_query 末尾:sm_put 后写 task.checked_at = utc_now
      
         try/except + rollback + warning:元数据写失败不能阻塞查询主流程
      
         时刻选 /start(不是最后一页 /page):中断也算「最近关注过」
      
      2. task.table_comment: TEXT NULL
      
         schema.sql / Task ORM 加列
      
         _migrate_task_table_comment() 兜底
      
         routers/tasks.py: TaskBase/Update/Out 加字段 + _row_to_out + create_task 写入
      
         update_task 的 setattr 循环自动覆盖
      
         list_tasks 接口直接读这列返前端,零查询开销
      
      3. CLAUDE.md「只做查询」边界
      
         这里写 task 元数据,不是业务数据修改
      
         业务表(field/rule/connection_preset)一律不 UPDATE
      
      4. 前端 TaskConfigView 现在用 row.table_comment 还没显示(commit 4 才加列)
      
         formatCheckedAt 已经备好(commit 2),checked_at 写完即可生效
      21ee05b2
    • Data Governance Dev's avatar
      fix(web3): 任务配置页分组选择没生效过滤 + checked_at 格式化 · 0c10c10a
      Data Governance Dev authored
      1. 分组过滤没生效
      
         <select v-model=groupFilter> 只绑了 model,没 watch 触发 load
      
         选了「手机号」不点「查询」list 不刷新
      
         加 watch(groupFilter, () => load()) 自动 reload
      
         keyword 保留「回车 + 查询按钮」(避免每个 keystroke 都请求)
      
      2. formatCheckedAt:把 ISO 字符串转成 'YYYY-MM-DD HH:mm'
      
         后端已返 checked_at(先 hardcoded None,下个 commit 接上)
      
         —— format 函数先备好,避免后续加 checked_at 字段后还要再改前端
      
      3. import 加 watch
      0c10c10a
    • Data Governance Dev's avatar
      feat(web3): ResultTable 列宽可拖拽(参照 web2 el-table resizable) · f33c4901
      Data Governance Dev authored
      web3 ResultTable 是自定义 table,el-table resizable 不能直接复用,自实现:
      
      1. ResultTable.vue
      
         columnWidths reactive + startResize/onResizeMove/endResize
      
         拖拽状态不放 reactive(频繁写不触发响应式刷新整张表格)
      
         window mousemove/mouseup(用户拖快会脱出 th 丢失 mouseup)
      
         拖拽过程 document.body user-select=none + cursor col-resize
      
         onBeforeUnmount 清理监听 + 还原 body 样式
      
      2. global.css
      
         .resize-handle 样式(透明 + hover 变蓝 409eff)
      
         table.dq-table 加 table-layout: fixed(auto 时 width 被无视)
      
         thead th 加 position: relative 让 handle absolute 定位
      
      3. 踩坑:改 Vue setup 的 import 段要核对所有 export 符号
      
         我改 import 时删了 watch 符号,但 setup 里 line 248 的 watch() 还在用
      
         → 运行时 ReferenceError: watch is not defined 把页面打白
      
      4. localStorage 列宽持久化没做(用户没要求;后续可加 key→width 存)
      f33c4901
    • Data Governance Dev's avatar
      feat(web3): 删导入/批量删除按钮 + 通用 Excel 导出(抽自 web2) · ef99984a
      Data Governance Dev authored
      1. DataQualityView 按钮区只留「字段配置 + 导出 Excel」
      
         删导入(btn-success)/批量删除(btn-danger)+ 对应的 mock 函数
      
         导出按钮加 :disabled(rows 为空或导出中禁用)
      
      2. 新增 src/utils/excel.js
      
         从 web2 IdCardTable.vue 抽 exportExcel + applyAllBorders + applyHeaderStyle
      
         封装成纯函数 exportToExcel({ rows, columns, filename, sheetName, confirm })
      
         三行表头:comment / cn / 数据;冻结前 2 行 + 黑色细边框 + 加粗灰背景
      
         columns 兼容 {key,cn,comment}[] 和 string[](fallback)
      
         大于 5000 行走 confirm(n) 二次确认(弹窗 UI 在调用方做)
      
      3. onExport 列范围
      
         visibleFields 非空 → 用户勾选;为空(未保存过)→ 退化为 resultFields 全量
      
         过滤掉 __reason(ResultTable 内部追加的备注列)
      
         文件名 <任务名>_<时间戳>.xlsx 防多次导出覆盖
      
      4. +xlsx-js-style 依赖(跟 web2 同库,导出样式一致)
      
         ⚠ bundle 多约 700KB(xlsx-js-style 是胖依赖,build 已超 500KB 阈值)
      
         后续可改 dynamic import(点导出按钮时再加载),本次没做
      ef99984a