1. 29 Sep, 2026 3 commits
  2. 28 Sep, 2026 1 commit
  3. 24 Sep, 2026 6 commits
    • wangteng's avatar
      性能优化(二)流式扫描:OFFSET 深分页 → 后端单连接流式扫描 + /pull 轮询 · aeb29b90
      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: default avatarClaude Fable 5 <noreply@anthropic.com>
      aeb29b90
    • wangteng's avatar
      性能优化(一)基础层:事件循环解冻 + 规则编译期 API + 接口小优化 · f7446793
      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: default avatarClaude Fable 5 <noreply@anthropic.com>
      f7446793
    • wangteng's avatar
      整理优化完善 · 09a35038
      wangteng authored
      09a35038
    • wangteng's avatar
      整理优化完善 · 8cb592c8
      wangteng authored
      8cb592c8
    • wangteng's avatar
      整理优化完善 · 54429b71
      wangteng authored
      54429b71
    • wangteng's avatar
      模型更换 · bd79c9e5
      wangteng authored
      bd79c9e5
  4. 10 Sep, 2026 5 commits
  5. 09 Sep, 2026 1 commit
  6. 07 Sep, 2026 4 commits
  7. 24 Aug, 2026 20 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