- 29 Sep, 2026 3 commits
- 28 Sep, 2026 1 commit
-
-
wangteng authored
-
- 24 Sep, 2026 6 commits
-
-
wangteng authored
旧方案每页独立连接跑 LIMIT/OFFSET,页越深扫得越多(50万行=1000次建连+ 1000次全表扫描排序)。改为 /start 起 daemon 线程单连接 iter_rows 流式扫 全表一遍(保留 ORDER BY 首列,全表只排序一次),命中行进 session 缓冲区, 前端由 3-worker 分页队列改为轮询 /pull 增量拉取(满额立即续拉)。 后端: - queries.py:_scan_worker 扫描线程(cancelled 无锁读+关连接双保险、每 1000 行发布进度、命中超 10 万条截断只计数);/pull 游标切片;/cancel 摘 session+request_cancel;删 /page;_load_task_compiled 批量化(N+1→ 固定 4 条查询)+ 接入 compile_rule 预编译(regex 每行 re.compile、code 类每行 compile+exec 的量级浪费消除);/start 的 COUNT 与字段注释合并 单连接;并发扫描软上限 MAX_ACTIVE_SCANS=4 - session_manager.py:QuerySession 扩展流式扫描状态(scanned/bad_rows/ scan_done/scan_error/truncated,统一持锁读写),request_cancel() 幂等 取消(置标志+关连接),TTL 清理锁外停掉过期扫描线程 - db_adapter.py:DBConnection.close() 抽为 public 幂等(跨线程取消用); iter_rows finally 的 cur.close 包保护(取消关连接后 generator 提前退出) 前端: - queries.js:fetchPage → pullQuery(after 游标) - DataQualityView.vue:pollLoop 轮询器(404 分流本端取消/会话过期、网络 异常 2s 退避×3、done 定稿 toast);进度条改「已扫描 X/Y 条(百分比)」; 快照/续跑按 __row_index 去重适配;无规则任务提示修正(原误报"无数据") - client.js:错误对象挂 HTTP status 实测(37151 行任务):扫描 12.5s→0.9s;扫描期间 /api/health 均值 114ms→2.2ms;code 类规则求值 175x;命中结果与旧版逐字节一致。 Co-Authored-By:Claude Fable 5 <noreply@anthropic.com>
-
wangteng authored
- db.py 四端点、ai.py explain/gen_regex 从 async def 改 def:内部是同步阻塞的 DB 建连(最长 10s)与 LLM 调用(最长 30s×2),挂事件循环上会冻结整个后端; def 走 FastAPI 线程池。explain 按 /ai/rule 同款补 run_in_executor - rule_runner 新增 compile_rule() 编译期 API(regex→编译好的 Pattern; number/date/string→沙箱 exec 一次取出 check 闭包,skip_null/date 归一化烘焙 进闭包);run_rule 收敛为薄封装(单值测试端点继续用);_exec_user_function 拆为 _compile_user_function + _sandbox_namespace - tasks.py list_tasks 批量计数(逐任务 3~4 条 SQL → 3 条 group_by 聚合) - app.py 加 GZipMiddleware(minimum_size=1024) 检测引擎接入预编译(queries.py)与流式扫描在下一笔。 Co-Authored-By:Claude Fable 5 <noreply@anthropic.com>
-
wangteng authored
-
wangteng authored
-
wangteng authored
-
wangteng authored
-
- 10 Sep, 2026 5 commits
- 09 Sep, 2026 1 commit
-
-
wangteng authored
-
- 07 Sep, 2026 4 commits
- 24 Aug, 2026 20 commits
-
-
Data Governance Dev authored
任务信息条右侧大片空白,用户不知道数据明细里红色 ! 图标可以点, P2 上线的「一键问 LLM」功能完全没被触达。 加 .ai-hint chip:橙底橙字 + pill 圆角 + hover 加深,v-if="rows.length > 0" 只在有不合规行时显示。文案:
💡 点击单元格的红色 ! 图标进行 AI 分析, 红色 ! 复用表格 ! icon 同色(#f56c6c)做视觉关联。 -
Data Governance Dev authored
编辑弹窗打开时 tableOptions = [](用户没点过测试连接), el-select 渲染 label 时查不到匹配 entry,退化成只显示纯表名(GR_GRXX)。 form.tableComment 本身已经从 props.task.table_comment 回填了, 只是没注入到 tableOptions 里。修法:从 props.task 构造一条合成 entry 注入 tableOptions,点「测试连接」后 loadTables 会用真实列表覆盖, 不影响后续流程。
-
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 现在暴露在局域网里,敏感环境慎用。 -
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 跟其他输入框视觉一致。 -
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) -
Data Governance Dev authored
任务分组应由后端 taskGroups 码表统一管理,弹窗里加 + 新建分组 会让用户随手造出码表外的分组,导致任务列表/侧边栏展示与码表对不上。 全文件 grep 无其他配套代码,直接删干净。
-
Data Governance Dev authored
LLM 审查结论为 match(代码正确实现规则)时,右栏的「
✅ 一致:代码正确 实现了规则」绿条不再展示 —— 既然一致,这条结论本身就成了冗余信息。 违规原因卡片继续展示,左栏的规则说明 + 代码也始终保留,方便用户对照。 -
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 一起被父容器滚动 - 虚线分隔 + 小字号 + 灰字,跟违规原因区分但不抢眼
-
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)
-
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 未提交(与本修复无关)
-
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 未提交(与本功能无关) - 后端有改动需用户重启进程 -
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 未提交(与本功能无关) -
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
-
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() 行为不变
-
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)
-
Data Governance Dev authored
- src/components/RuleModal.vue:248 addRule() 把 skip_null 默认值 false→true - 编辑/复制老规则不走 addRule(),skip_null 仍按 r.skip_null 实际值显示 - 保存链路 onSave 仍透传 !!rule.skip_null,不强制覆盖存量数据 业务上「空值不计入不合规」更符合直觉,省得用户每加一条新规则手动勾。
-
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 跳过
-
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。 -
Data Governance Dev authored
字段原本有规则,点「规则设置」进 RuleModal 把所有规则删完, 「保存」按钮被 length>0 限制变灰卡死。 语义上用户明确点删除就是想清空,字段应该回到「无规则」状态; 后端 _replace_fields 收到空 f.rules 也只是不写任何 Rule,本来就支持。 去掉 length>0 && 这一截。Array.every() 对空数组天然返回 true (vacuous truth),删空所有规则后保存按钮就亮起来。
-
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 跑迁移,老规则全保留默认 ''
-