dsh-data-cleaning-agent 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.en.md +3 -1
- package/README.md +3 -2
- package/docs/RELEASE-0.7.0.md +44 -0
- package/docs/UI-WORKFLOW-V2-ACCEPTANCE.md +40 -0
- package/docs/UI-WORKFLOW-V2.md +16 -7
- package/lib/client.js +157 -37
- package/lib/qcc-field-catalog.js +185 -0
- package/lib/qcc-safety.js +11 -1
- package/lib/qcc.js +276 -79
- package/lib/workflow-contract.js +17 -70
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.7.0] - 2026-09-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- 数据清洗补全字段目录从 30 项扩展到 128 项:第一批开放联系方式、上市信息、税务开票、进出口信用 40 字段;第二批开放企业自身与关联风险扫描 58 字段。
|
|
11
|
+
- 新增 6 个一企一行 Host 适配器、风险因子稳定透视与目录漂移审计;电话/邮箱/网址全集、海关资质、风险明细和关联方列表继续排除。
|
|
12
|
+
- UI 按 8 个来源工具展示字段;同工具多字段每企只调用一次,Host 按实际来源工具在调用前校验 300 次预算上限。
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- 所有新增字段贯通任务草稿、Agent-owned 命令、候选续跑、结果预览和中文 CSV/XLSX;缺失值保留空列,股票代码、税号、电话和银行账号保持文本。
|
|
16
|
+
|
|
7
17
|
## [0.6.3] - 2026-09-05
|
|
8
18
|
|
|
9
19
|
### Fixed
|
package/README.en.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> A data cleaning & completion agent plugin for DeepSeek Harness: local CSV/XLSX/JSON engine plus optional Qichacha (QCC) MCP enterprise-data enrichment. Initiated and maintained by the Qichacha (QCC) team.
|
|
4
4
|
>
|
|
5
|
-
> Current source version / 当前源码版本: **0.
|
|
5
|
+
> Current source version / 当前源码版本: **0.7.0** (stable release)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/dsh-data-cleaning-agent)
|
|
@@ -117,6 +117,8 @@ See [the Phase-3 acceptance record](docs/PHASE3-ACCEPTANCE.md) and
|
|
|
117
117
|
See [the 0.5.1 release record](docs/RELEASE-0.5.1.md) for the README fix and release-text gate.
|
|
118
118
|
See [the 0.5.2 release record](docs/RELEASE-0.5.2.md) for native DSH UI alignment, verification, and rollback.
|
|
119
119
|
See [the 0.5.3 release record](docs/RELEASE-0.5.3.md) for the business landing view and prompt builder.
|
|
120
|
+
See [the 0.7.0 release record](docs/RELEASE-0.7.0.md) for the first 40 and second 58
|
|
121
|
+
one-company-one-row fields, deduplicated QCC tool dispatch, and real two-company acceptance.
|
|
120
122
|
See [the 0.6.3 release record](docs/RELEASE-0.6.3.md) for multiline entity-list parsing,
|
|
121
123
|
editable execution summaries, and workbench/composer layout fixes.
|
|
122
124
|
See [the 0.6.2 release record](docs/RELEASE-0.6.2.md) for Chinese export headers,
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 在 DeepSeek Harness 中清洗、补全、画像企业名单数据的智能体插件:本地 CSV/XLSX/JSON 引擎 + 可选企查查(Qichacha/QCC)MCP 企业数据补全,由企查查(Qichacha/QCC)团队发起并维护。
|
|
4
4
|
>
|
|
5
|
-
> 当前源码版本 / Current source version: **0.
|
|
5
|
+
> 当前源码版本 / Current source version: **0.7.0**(正式版本)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/dsh-data-cleaning-agent)
|
|
@@ -113,7 +113,8 @@ bash <(curl -fsSL https://raw.githubusercontent.com/duhu2000/dsh-data-cleaning-a
|
|
|
113
113
|
0.5.1 文档补丁与防回归发布门见 [docs/RELEASE-0.5.1.md](docs/RELEASE-0.5.1.md)。
|
|
114
114
|
0.5.2 DSH 原生 UI 对齐范围、验收与回滚见 [docs/RELEASE-0.5.2.md](docs/RELEASE-0.5.2.md)。
|
|
115
115
|
0.5.3 业务首页、提示词生成和输入框下方流程栏见 [docs/RELEASE-0.5.3.md](docs/RELEASE-0.5.3.md)。
|
|
116
|
-
0.
|
|
116
|
+
0.7.0 第一批 40 字段、第二批 58 字段、调用编排和真实两企业验收见
|
|
117
|
+
[docs/RELEASE-0.7.0.md](docs/RELEASE-0.7.0.md)。0.6.3 多行名单解析、可编辑执行说明与工作台遮挡修复见
|
|
117
118
|
[docs/RELEASE-0.6.3.md](docs/RELEASE-0.6.3.md)。0.6.2 中文导出表头、完整字段选择传递与画像字段补全见
|
|
118
119
|
[docs/RELEASE-0.6.2.md](docs/RELEASE-0.6.2.md)。0.6.1 Agent-owned QCC 工作台、会话隔离、恢复统计及真实闭环验收见
|
|
119
120
|
[docs/RELEASE-0.6.1.md](docs/RELEASE-0.6.1.md)。0.6.0 五步 taskId 工作流、耐久制品、
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 0.7.0 · 一企一行 128 字段补全
|
|
2
|
+
|
|
3
|
+
> 版本:**0.7.0**
|
|
4
|
+
> 发布日期:2026-09-05
|
|
5
|
+
> 发布方式:推送 `v0.7.0` Tag 后,由 GitHub Actions 使用 npm OIDC Trusted Publishing 发布并创建 GitHub Release。
|
|
6
|
+
|
|
7
|
+
## 目标
|
|
8
|
+
|
|
9
|
+
0.7.0 把已经核对 QCC MCP 一手契约、能够稳定投影到单个 Excel 单元格的字段统一为 128 项目录:
|
|
10
|
+
|
|
11
|
+
- 基础 30 字段:企业工商信息 27、企业简介 3;
|
|
12
|
+
- 第一批 40 字段:联系方式 6、上市信息 15、税务开票信息 8、进出口信用 11;
|
|
13
|
+
- 第二批 58 字段:企业自身风险扫描 38、企业关联风险扫描 20。
|
|
14
|
+
|
|
15
|
+
字段 ID、中文表头、来源工具和发布批次由 `lib/qcc-field-catalog.js` 单一来源管理。一级行业、二级行业、
|
|
16
|
+
电话/邮箱/网址全集、风险明细、关联方名单等未被上游声明为稳定一对一值的数据不会进入主表。
|
|
17
|
+
|
|
18
|
+
## 业务与调用规则
|
|
19
|
+
|
|
20
|
+
- 提示词向导和规则确认页按 8 个来源工具展示字段,支持整组全选与清空。
|
|
21
|
+
- 同一工具选择多个字段时,每家企业只调用一次;调用上界按
|
|
22
|
+
`唯一企业数 ×(主体定位 + 去重后的来源工具)` 计算,并在任何 QCC 调用前执行 300 次硬上限。
|
|
23
|
+
- 风险扫描明细由 Host 透视为稳定计数、命中摘要和关联方数量;数组不进入单元格。
|
|
24
|
+
- 新字段贯通任务草稿、Agent-owned 命令、候选续跑、结果预览及中文 CSV/XLSX;缺失值保留空列,
|
|
25
|
+
股票代码、税号、电话和银行账号按文本保存。
|
|
26
|
+
- 生产风险目录变化记录为脱敏的 `QCC_RISK_CATALOG_DRIFT` 审计事件,不静默扩张稳定字段契约。
|
|
27
|
+
|
|
28
|
+
## 验收
|
|
29
|
+
|
|
30
|
+
- 字段目录:基础 30、第一批 40、第二批 58,共 128 个唯一字段 ID 和 128 个唯一中文表头。
|
|
31
|
+
- 自动化:`npm run check` 通过,186/186 测试通过;npm tarball 内容全部命中白名单。
|
|
32
|
+
- 真实环境:本机 DSH `0.1.1-rc.2`,两家企业选择第一、二批全部 98 字段及基础默认 5 字段。
|
|
33
|
+
- QCC 调用:8 个工具,估算 16 次、实际 16 次且全部成功;任务结果为补全 2、待核验 0、未匹配 0、失败 0。
|
|
34
|
+
- 结果 XLSX:`清洗补全结果!A1:DB3`,106 列、2 行;第一、二批中文表头完整,无重复、无内部英文表头、
|
|
35
|
+
无公式错误,统一社会信用代码保持文本。
|
|
36
|
+
|
|
37
|
+
详细证据见 `docs/UI-WORKFLOW-V2-ACCEPTANCE.md` 第 9 节。
|
|
38
|
+
|
|
39
|
+
## 升级与回滚
|
|
40
|
+
|
|
41
|
+
- 升级:安装 `dsh-data-cleaning-agent@0.7.0`,完全停止并重新运行 `dsh web`。
|
|
42
|
+
- 回滚:重新安装 `dsh-data-cleaning-agent@0.6.3`,完全重启 DSH。
|
|
43
|
+
- 本版本不修改 `dc_workflows_v2` 持久化 schema,也不删除旧任务或耐久制品。
|
|
44
|
+
- 旧任务维持创建时的字段选择和既有制品;如需新增字段,升级后创建新任务并重新生成结果。
|
|
@@ -82,3 +82,43 @@ npm pack --dry-run --json --cache .npm-cache
|
|
|
82
82
|
版本确定为 **0.6.0**,原因是新增 Host 工作流 API、持久化 domain、耐久制品和完整五步业务流程。
|
|
83
83
|
发布按顺序执行:最终代码审查 → 版本/README/Changelog 快照 → commit/push → Tag → OIDC npm 发布 →
|
|
84
84
|
GitHub Release → 公共 Registry 全新安装。验收记录本身不等于外部平台已经完成发布。
|
|
85
|
+
|
|
86
|
+
## 9. 2026-09-05 · 第一批 40 字段与第二批 58 字段验收
|
|
87
|
+
|
|
88
|
+
### 9.1 契约与界面
|
|
89
|
+
|
|
90
|
+
- 字段目录共 128 个一对一字段:基础 30、第一批 40、第二批 58;字段 ID、中文表头、来源工具和批次由
|
|
91
|
+
`lib/qcc-field-catalog.js` 单一来源管理。
|
|
92
|
+
- 第一批覆盖联系方式 6、上市信息 15、税务开票 8、进出口信用 11;第二批覆盖企业自身风险 38、
|
|
93
|
+
企业关联风险 20。
|
|
94
|
+
- 提示词向导和规则页均按维度分组展示字段,支持组内全选/清空;调用量按“唯一企业数 ×(主体定位 +
|
|
95
|
+
去重后的来源工具)”精确估算,并在 300 次硬上限前阻断。
|
|
96
|
+
- 风险类明细数组只在 Host 内透视为稳定计数和摘要,不进入单元格;所有输出保持一企业一行、单字段一单元格。
|
|
97
|
+
|
|
98
|
+
### 9.2 真实 DSH + QCC 回归
|
|
99
|
+
|
|
100
|
+
环境为本机 DSH `0.1.1-rc.2`,由市场安装包覆盖当前本地候选代码;使用当前用户自己连接的企查查 MCP
|
|
101
|
+
账号。输入两家企业,选择基础 5 字段以及第一、二批全部 98 字段,共 103 个补全字段。
|
|
102
|
+
|
|
103
|
+
| 验收项 | 实测结果 |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| 输入解析 | 2 行、2 个唯一企业,未再复现“两条只识别一条” |
|
|
106
|
+
| 来源工具 | 主体定位、工商、联系方式、上市、税务开票、进出口信用、自身风险、关联风险,共 8 个 |
|
|
107
|
+
| 调用估算 / 实际 | 16 / 16,全部成功 |
|
|
108
|
+
| 任务 | `g5-e7dfb2a9-e72a-4866-9813-d8ad5a119b17`,`completed` |
|
|
109
|
+
| 业务结果 | 已补全 2、待核验 0、未匹配 0、失败 0 |
|
|
110
|
+
| 耐久制品 | 结果与异常清单的 CSV/XLSX 四件套均生成,可从任务历史恢复下载 |
|
|
111
|
+
|
|
112
|
+
真实结果工作簿 `清洗补全结果!A1:DB3` 共 106 列、2 条数据:原始主体列 1 + 所选字段 103 +
|
|
113
|
+
匹配状态 1 + 数据来源 1。第一批 40 和第二批 58 的预期中文表头全部存在,无重复表头、无内部英文表头、
|
|
114
|
+
无公式错误;两家企业统一社会信用代码均以文本保留。未上市企业的上市字段为空,未构造不存在的数据;
|
|
115
|
+
风险为零的计数保留数值 0。
|
|
116
|
+
|
|
117
|
+
### 9.3 非阻断观察项
|
|
118
|
+
|
|
119
|
+
生产返回的企业关联风险目录包含当前固定目录以外的扩展标签,因此审计记录
|
|
120
|
+
`QCC_RISK_CATALOG_DRIFT`。本次所选 20 个关联风险字段均完整输出,故不阻断双批验收。审计事件现额外保留
|
|
121
|
+
受限、脱敏后的 `catalogVersion`、`missing` 与 `unknown` 标签,便于后续根据生产目录升级固定字段契约,
|
|
122
|
+
而不是静默吞掉或擅自把动态数组写入单元格。
|
|
123
|
+
|
|
124
|
+
**结论:第一批 40 字段与第二批 58 字段功能、调用编排、中文导出及真实两企业闭环验收通过。**
|
package/docs/UI-WORKFLOW-V2.md
CHANGED
|
@@ -18,12 +18,19 @@
|
|
|
18
18
|
|
|
19
19
|
## 2. 当前范围
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
当前字段目录共 128 项,UI/Host/XLSX 按 8 个来源工具分组:
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
23
|
+
- 基础 30 项:`get_company_registration_info`(企业工商信息,27 项)和 `get_company_profile`(企业简介,3 项)。
|
|
24
|
+
- 第一批 40 项:`get_contact_info`(联系方式,6 项)、`get_listing_info`(上市信息,15 项)、`get_tax_invoice_info`(税务开票,8 项)、`get_import_export_credit`(进出口信用,11 项)。
|
|
25
|
+
- 第二批 58 项:`get_company_risk_scan`(企业自身风险扫描,38 项)和 `get_company_related_risk_scan`(企业关联风险扫描,20 项)。
|
|
26
|
+
- 基础工商:企业名称、统一社会信用代码、注册号、组织机构代码、纳税人识别号、登记状态、法定代表人、注册/实缴资本、成立日期、企业类型、核准日期、登记机关、纳税人资质、支付系统行号、进出口企业代码、企业简称、英文名。
|
|
27
|
+
- 地址与地区:注册地址、通信地址、所属地区原值。
|
|
28
|
+
- 经营信息:经营范围、国标行业、企查查行业、营业期限、人员规模、参保人数、分支机构参保人数、企业简介、产业链概览。
|
|
29
|
+
- 上传列“联系电话”仍可作为本地质量检查字段;QCC 联系方式另以“首选联系电话/邮箱/官网”等字段输出。电话、邮箱和网址全集不拼接进单元格。
|
|
30
|
+
- 风险字段只输出扫描工具已返回的聚合计数、命中摘要与重点维度命中关联方数;风险明细、关联方名单和下钻结果不进入一企一行主表。
|
|
31
|
+
- 一级行业、二级行业、省、市、区县、曾用名和知识产权摘要不在当前目录;不得推断、拼接或用其他字段冒充。
|
|
32
|
+
|
|
33
|
+
字段来源、185 工具审计及后续可适配字段详见 `docs/QCC-185-ONE-TO-ONE-FIELD-CATALOG.md`。
|
|
27
34
|
|
|
28
35
|
历史域、人员域、招投标域已明确延期,不进入当前实现或字段目录。
|
|
29
36
|
|
|
@@ -47,12 +54,14 @@ draft → uploaded → rules_confirmed → diagnosed(可选)
|
|
|
47
54
|
- 至少映射一个主体锚点:`company_name`、`credit_no`、`reg_no`。
|
|
48
55
|
- 同一目标字段不能被多个输入列重复映射。
|
|
49
56
|
- 同一输入列不能重复映射到多个目标;未知目标字段按契约错误处理,不静默忽略。
|
|
50
|
-
-
|
|
57
|
+
- 企业名称可以结合输入中的地址、所属地区、电话辅助人工核验,但辅助字段不能取代主体锚点,也不因此成为 QCC 输出字段。
|
|
51
58
|
- 匹配结果只保存状态、数量汇总、运行引用和可审计依据;不得生成或展示无来源的置信度百分比。
|
|
52
59
|
- 多候选必须进入 `review_required`;人工确认完成后才能进入补全。
|
|
53
60
|
- `exact`、`candidate`、`confirmed`、`unresolved`、`failed` 是互斥数量,合计不得超过 `total`。
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
目录单一来源位于 `lib/qcc-field-catalog.js`,`lib/workflow-contract.js` 对外发布只读契约;Client 仅保留 Host 契约暂不可用时的同版本降级快照。
|
|
63
|
+
|
|
64
|
+
所选字段先按 `sourceTool` 去重,再执行 `主体查询 + 所选来源工具`。同一工具选择多个字段时每家企业只调用一次;Host 在任何 QCC 调用前以 `唯一企业数 × (1 + 来源工具数)` 校验 300 次调用上限。
|
|
56
65
|
|
|
57
66
|
## 5. Host 持久化与隐私边界
|
|
58
67
|
|
package/lib/client.js
CHANGED
|
@@ -723,7 +723,21 @@ window.__ModuleLoader__.load({
|
|
|
723
723
|
.dcAgentMappingRow > b { text-align: center; color: light-dark(#8792a3, #8290a5); }
|
|
724
724
|
.dcAgentRulesGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
725
725
|
.dcAgentFieldGroup { display: grid; gap: 7px; margin-top: 12px; }
|
|
726
|
-
.
|
|
726
|
+
.dcAgentFieldGroupHead { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
|
|
727
|
+
.dcAgentFieldGroupHead > div:first-child { display: grid; gap: 2px; min-width: 0; }
|
|
728
|
+
.dcAgentFieldGroupHead b { font-size: 12px; }
|
|
729
|
+
.dcAgentFieldGroupActions { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; }
|
|
730
|
+
.dcAgentFieldAction {
|
|
731
|
+
padding: 2px 7px;
|
|
732
|
+
border: 0;
|
|
733
|
+
border-radius: 6px;
|
|
734
|
+
background: transparent;
|
|
735
|
+
color: light-dark(#2869e6, #8cb3ff);
|
|
736
|
+
font: inherit;
|
|
737
|
+
font-size: 11px;
|
|
738
|
+
cursor: pointer;
|
|
739
|
+
}
|
|
740
|
+
.dcAgentFieldAction:hover, .dcAgentFieldAction:focus-visible { background: light-dark(#edf4ff, #172841); }
|
|
727
741
|
.dcAgentPreviewTable { margin-top: 12px; overflow: auto; border: 1px solid light-dark(#e4e8f0, #303947); border-radius: 10px; }
|
|
728
742
|
.dcAgentHistoryTask { display: block; width: 100%; padding: 10px; text-align: left; }
|
|
729
743
|
.dcAgentHistoryTask h3 { margin: 0; font-size: 12px; }
|
|
@@ -831,32 +845,92 @@ window.__ModuleLoader__.load({
|
|
|
831
845
|
['validate_identity', '主体标识校验'],
|
|
832
846
|
['complete_fields', '补全所选企业字段'],
|
|
833
847
|
];
|
|
848
|
+
const SELF_RISK_FIELD_OPTIONS = [
|
|
849
|
+
['dishonest', '失信信息'], ['judgment_debtor', '被执行人'], ['consumption_restriction', '限制高消费'],
|
|
850
|
+
['terminated_case', '终本案件'], ['judicial_document', '裁判文书'], ['case_filing', '立案信息'],
|
|
851
|
+
['hearing_announcement', '开庭公告'], ['court_announcement', '法院公告'], ['service_notice', '送达公告'],
|
|
852
|
+
['bankruptcy_reorganization', '破产重整'], ['equity_freeze', '股权冻结'], ['judicial_auction', '司法拍卖'],
|
|
853
|
+
['valuation_inquiry', '询价评估'], ['pre_litigation_mediation', '诉前调解'], ['exit_restriction', '限制出境'],
|
|
854
|
+
['administrative_penalty', '行政处罚'], ['operating_exception', '经营异常'], ['serious_violation', '严重违法'],
|
|
855
|
+
['environmental_penalty', '环保处罚'], ['abnormal_taxpayer', '税务非正常户'], ['tax_arrears', '欠税公告'],
|
|
856
|
+
['tax_violation', '税收违法'], ['disciplinary_list', '惩戒名单'], ['default_matter', '违约事项'],
|
|
857
|
+
['guarantee', '担保信息'], ['equity_pledge_registration', '股权出质'], ['stock_pledge', '股权质押'],
|
|
858
|
+
['chattel_mortgage', '动产抵押'], ['land_mortgage', '土地抵押'], ['simple_cancellation', '简易注销'],
|
|
859
|
+
['cancellation_filing', '注销备案'], ['liquidation', '清算信息'], ['labor_arbitration', '劳动仲裁'],
|
|
860
|
+
['public_notice', '公示催告'], ['property_reward_notice', '财产悬赏公告'],
|
|
861
|
+
];
|
|
862
|
+
const RELATED_RISK_FIELD_OPTIONS = [
|
|
863
|
+
['dishonest', '失信被执行人'], ['judgment_debtor', '被执行人'], ['consumption_restriction', '限制高消费'],
|
|
864
|
+
['serious_violation', '严重违法'], ['tax_violation', '税收违法'], ['administrative_penalty', '行政处罚'],
|
|
865
|
+
['bankruptcy_reorganization', '破产重整'], ['terminated_case', '终本案件'], ['equity_freeze', '股权冻结'],
|
|
866
|
+
['tax_arrears', '欠税公告'], ['operating_exception', '经营异常'],
|
|
867
|
+
];
|
|
868
|
+
const RELATED_RISK_KEY_FIELD_OPTIONS = [
|
|
869
|
+
['dishonest', '失信被执行人'], ['serious_violation', '严重违法'], ['bankruptcy_reorganization', '破产重整'],
|
|
870
|
+
['tax_violation', '税收违法'], ['judgment_debtor', '被执行人'], ['terminated_case', '终本案件'],
|
|
871
|
+
['equity_freeze', '股权冻结'],
|
|
872
|
+
];
|
|
834
873
|
const FIELD_GROUPS = [
|
|
835
|
-
['
|
|
874
|
+
['company_registration', '企业工商信息', [
|
|
836
875
|
['company_name', '企业名称'], ['credit_no', '统一社会信用代码'], ['reg_no', '注册号'],
|
|
837
|
-
['
|
|
876
|
+
['org_no', '组织机构代码'], ['tax_no', '纳税人识别号'], ['reg_status', '登记状态'],
|
|
877
|
+
['legal_rep', '法定代表人'], ['reg_capital', '注册资本'],
|
|
838
878
|
['paid_capital', '实缴资本'], ['establish_date', '成立日期'], ['company_type', '企业类型'],
|
|
839
|
-
['
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
['registered_address', '注册地址'], ['
|
|
843
|
-
['
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
['company_profile', '企业简介'],
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
['
|
|
855
|
-
]],
|
|
879
|
+
['approval_date', '核准日期'], ['registration_authority', '登记机关'],
|
|
880
|
+
['taxpayer_qualification', '纳税人资质'], ['payment_line_no', '支付系统行号'],
|
|
881
|
+
['import_export_company_code', '进出口企业代码'], ['short_name', '企业简称'], ['english_name', '英文名'],
|
|
882
|
+
['registered_address', '注册地址'], ['mailing_address', '通信地址'], ['region', '所属地区'],
|
|
883
|
+
['business_scope', '经营范围'], ['industry_category', '国标行业'],
|
|
884
|
+
['operating_period', '营业期限'], ['company_size', '人员规模'], ['insured_count', '参保人数'],
|
|
885
|
+
['branch_insured_count', '分支机构参保人数'],
|
|
886
|
+
], 'get_company_registration_info'],
|
|
887
|
+
['company_profile', '企业简介', [
|
|
888
|
+
['qcc_industry', '企查查行业'], ['company_profile', '企业简介'],
|
|
889
|
+
['industry_chain_overview', '产业链概览'],
|
|
890
|
+
], 'get_company_profile'],
|
|
891
|
+
['contact_info', '联系方式', [
|
|
892
|
+
['contact_preferred_phone', '首选联系电话'], ['contact_phone_invalid_flag', '首选电话无效标记'],
|
|
893
|
+
['contact_phone_tags', '首选电话标签'], ['contact_preferred_email', '首选邮箱'],
|
|
894
|
+
['contact_official_website', '官方网站'], ['contact_official_website_icp', '官网 ICP 备案'],
|
|
895
|
+
], 'get_contact_info'],
|
|
896
|
+
['listing_info', '上市信息', [
|
|
897
|
+
['listing_date', '上市日期'], ['listing_short_name', '股票简称'], ['listing_stock_code', '股票代码'],
|
|
898
|
+
['listing_exchange', '上市交易所'], ['listing_board', '上市板块'], ['listing_former_short_name', '上市曾用名'],
|
|
899
|
+
['listing_total_market_value', '总市值'], ['listing_total_shares', '总股本'], ['listing_predicted_pe', '预测市盈率'],
|
|
900
|
+
['listing_float_market_value', '流通值'], ['listing_float_shares', '流通股'], ['listing_pb_ratio', '市净率'],
|
|
901
|
+
['listing_eps', 'EPS'], ['listing_voting_rights_difference', '表决权差异'],
|
|
902
|
+
['listing_registration_based', '是否注册制'],
|
|
903
|
+
], 'get_listing_info'],
|
|
904
|
+
['tax_invoice_info', '税务开票信息', [
|
|
905
|
+
['tax_company_name', '税务主体名称'], ['tax_identification_no', '税务纳税人识别号'],
|
|
906
|
+
['tax_company_type', '税务企业类型'], ['tax_business_status', '税务经营状态'],
|
|
907
|
+
['invoice_address', '开票地址'], ['invoice_phone', '开票联系电话'],
|
|
908
|
+
['invoice_bank', '开户行'], ['invoice_bank_account', '开户行账号'],
|
|
909
|
+
], 'get_tax_invoice_info'],
|
|
910
|
+
['import_export_credit', '进出口信用', [
|
|
911
|
+
['import_export_credit_no', '进出口统一社会信用代码'], ['import_export_customs', '所在地海关'],
|
|
912
|
+
['import_export_admin_division', '进出口行政区划'], ['import_export_address', '进出口备案地址'],
|
|
913
|
+
['import_export_economic_area', '经济区划'], ['import_export_trade_type', '经营类别'],
|
|
914
|
+
['import_export_statistical_economic_area', '统计经济区划'], ['import_export_industry', '进出口行业种类'],
|
|
915
|
+
['import_export_ecommerce_type', '跨境贸易电子商务类型'], ['import_export_credit_grade', '海关信用等级'],
|
|
916
|
+
['import_export_filing_date', '进出口备案日期'],
|
|
917
|
+
], 'get_import_export_credit'],
|
|
918
|
+
['company_risk_scan', '企业自身风险扫描', [
|
|
919
|
+
['risk_recorded_factor_count', '风险有记录因子数'], ['risk_no_record_factor_count', '风险无记录因子数'],
|
|
920
|
+
['risk_hit_summary', '企业自身风险命中摘要'],
|
|
921
|
+
...SELF_RISK_FIELD_OPTIONS.map(([id, label]) => [`risk_${id}_count`, `${label}条目数`]),
|
|
922
|
+
], 'get_company_risk_scan'],
|
|
923
|
+
['company_related_risk_scan', '企业关联风险扫描', [
|
|
924
|
+
['related_risk_party_count', '有风险关联方数'], ['related_risk_summary', '企业关联风险摘要'],
|
|
925
|
+
...RELATED_RISK_FIELD_OPTIONS.map(([id, label]) => [`related_risk_${id}_count`, `关联风险-${label}条目数`]),
|
|
926
|
+
...RELATED_RISK_KEY_FIELD_OPTIONS.map(([id, label]) => [`related_risk_${id}_party_count`, `关联风险-${label}命中关联方数`]),
|
|
927
|
+
], 'get_company_related_risk_scan'],
|
|
856
928
|
];
|
|
857
929
|
const ENRICHMENT_OPTIONS = FIELD_GROUPS.flatMap(([, , fields]) => fields);
|
|
930
|
+
const INPUT_ONLY_MAPPING_OPTIONS = [['phone', '联系电话']];
|
|
858
931
|
const RESULT_FIELD_LABELS = new Map([
|
|
859
932
|
...ENRICHMENT_OPTIONS,
|
|
933
|
+
...INPUT_ONLY_MAPPING_OPTIONS,
|
|
860
934
|
['biz_status', '经营状态'],
|
|
861
935
|
['risk_tags', '风险标签'],
|
|
862
936
|
['qcc_match_status', '匹配状态'],
|
|
@@ -1104,7 +1178,6 @@ window.__ModuleLoader__.load({
|
|
|
1104
1178
|
['credit_no', /^(credit_no|creditCode|unified_credit_code|统一社会信用代码|信用代码)$/i],
|
|
1105
1179
|
['reg_no', /^(reg_no|registration_no|注册号)$/i],
|
|
1106
1180
|
['phone', /^(phone|mobile|tel|telephone|联系电话|手机号码|手机号)$/i],
|
|
1107
|
-
['province', /^(province|省份|省份地区)$/i],
|
|
1108
1181
|
['registered_address', /^(address|registered_address|注册地址|企业地址|公司地址)$/i],
|
|
1109
1182
|
];
|
|
1110
1183
|
|
|
@@ -1931,6 +2004,15 @@ window.__ModuleLoader__.load({
|
|
|
1931
2004
|
}),
|
|
1932
2005
|
label,
|
|
1933
2006
|
));
|
|
2007
|
+
const setPromptFieldGroup = (fields, enabledGroup) => {
|
|
2008
|
+
const groupIds = new Set(fields.map(([id]) => id));
|
|
2009
|
+
const selected = new Set(enrichmentKeys);
|
|
2010
|
+
for (const id of groupIds) {
|
|
2011
|
+
if (enabledGroup) selected.add(id); else selected.delete(id);
|
|
2012
|
+
}
|
|
2013
|
+
const catalogOrder = FIELD_GROUPS.flatMap(([, , groupFields]) => groupFields.map(([id]) => id));
|
|
2014
|
+
setEnrichmentKeys(catalogOrder.filter((id) => selected.has(id)));
|
|
2015
|
+
};
|
|
1934
2016
|
|
|
1935
2017
|
return h('div', { className: 'dcAgentPromptLayer' },
|
|
1936
2018
|
h('button', {
|
|
@@ -2008,13 +2090,22 @@ window.__ModuleLoader__.load({
|
|
|
2008
2090
|
) : null,
|
|
2009
2091
|
wizardStep === 3 ? h('div', { className: 'dcAgentWizardPane' },
|
|
2010
2092
|
h('h4', null, '选择清洗目标和补全字段'),
|
|
2011
|
-
h('p', null, '
|
|
2093
|
+
h('p', null, '共 128 个一企一行字段:基础 30、第一批 40、第二批 58。最终可用字段以当前用户连接的 QCC MCP 能力为准。'),
|
|
2012
2094
|
h('div', { className: 'dcAgentPromptGroup' },
|
|
2013
2095
|
h('b', null, '清洗目标'),
|
|
2014
2096
|
h('div', { className: 'dcAgentPromptChoices' }, choice(CLEANING_OPTIONS, cleaningKeys, setCleaningKeys)),
|
|
2015
2097
|
),
|
|
2016
|
-
FIELD_GROUPS.map(([groupId, label, fields]) => h('div', { className: 'dcAgentPromptGroup', key: groupId },
|
|
2017
|
-
h('
|
|
2098
|
+
FIELD_GROUPS.map(([groupId, label, fields, sourceTool]) => h('div', { className: 'dcAgentPromptGroup', key: groupId },
|
|
2099
|
+
h('div', { className: 'dcAgentFieldGroupHead' },
|
|
2100
|
+
h('div', null,
|
|
2101
|
+
h('b', null, `${label} · ${fields.filter(([id]) => enrichmentKeys.includes(id)).length}/${fields.length}`),
|
|
2102
|
+
sourceTool ? h('small', { className: 'dcAgentHint' }, `来源:${sourceTool}`) : null,
|
|
2103
|
+
),
|
|
2104
|
+
h('div', { className: 'dcAgentFieldGroupActions' },
|
|
2105
|
+
h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setPromptFieldGroup(fields, true) }, '全选'),
|
|
2106
|
+
h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setPromptFieldGroup(fields, false) }, '清空'),
|
|
2107
|
+
),
|
|
2108
|
+
),
|
|
2018
2109
|
h('div', { className: 'dcAgentPromptChoices' }, choice(fields, enrichmentKeys, setEnrichmentKeys)),
|
|
2019
2110
|
)),
|
|
2020
2111
|
) : null,
|
|
@@ -2540,14 +2631,18 @@ window.__ModuleLoader__.load({
|
|
|
2540
2631
|
|
|
2541
2632
|
const estimateQcc = async () => {
|
|
2542
2633
|
const uniqueCompanies = new Set(runtime.rows.map((row) => String(row?.[nameField] ?? '').trim()).filter(Boolean)).size;
|
|
2543
|
-
const
|
|
2544
|
-
const
|
|
2634
|
+
const selected = fieldSelection.length ? fieldSelection : DEFAULT_ENRICHMENT_KEYS;
|
|
2635
|
+
const selectedGroups = uiFieldGroups.filter(([, , fields]) => fields.some(([id]) => selected.includes(id)));
|
|
2636
|
+
const sourceTools = [...new Set(selectedGroups.map(([, , , sourceTool]) => sourceTool).filter(Boolean))];
|
|
2637
|
+
const callsPerCompany = 1 + sourceTools.length;
|
|
2638
|
+
const estimatedCalls = uniqueCompanies * callsPerCompany;
|
|
2545
2639
|
actions.setQccEstimate({
|
|
2546
2640
|
uniqueCompanies,
|
|
2547
|
-
tools:
|
|
2548
|
-
|
|
2641
|
+
tools: ['主体查询', ...selectedGroups.map(([, label]) => label)],
|
|
2642
|
+
sourceTools,
|
|
2643
|
+
estimatedCalls,
|
|
2549
2644
|
maxCalls: 300,
|
|
2550
|
-
withinLimit: runtime.rows.length <= 100,
|
|
2645
|
+
withinLimit: runtime.rows.length <= 100 && estimatedCalls <= 300,
|
|
2551
2646
|
estimateType: 'upper-bound',
|
|
2552
2647
|
});
|
|
2553
2648
|
};
|
|
@@ -2889,9 +2984,20 @@ window.__ModuleLoader__.load({
|
|
|
2889
2984
|
h('b', { className: tone ? `is-${tone}` : null }, displayStatValue(value))
|
|
2890
2985
|
);
|
|
2891
2986
|
const uiFieldGroups = Array.isArray(workflowContract?.fieldCatalog)
|
|
2892
|
-
? workflowContract.fieldCatalog.map((group) => [group.id, group.label, (group.fields || []).map((field) => [field.id, field.label])])
|
|
2987
|
+
? workflowContract.fieldCatalog.map((group) => [group.id, group.label, (group.fields || []).map((field) => [field.id, field.label]), group.sourceTool])
|
|
2893
2988
|
: FIELD_GROUPS;
|
|
2894
|
-
const
|
|
2989
|
+
const inputOnlyMappingFields = Array.isArray(workflowContract?.inputOnlyMappingFields)
|
|
2990
|
+
? workflowContract.inputOnlyMappingFields.map((field) => [field.id, field.label])
|
|
2991
|
+
: INPUT_ONLY_MAPPING_OPTIONS;
|
|
2992
|
+
const targetFields = [...uiFieldGroups.flatMap(([, , fields]) => fields), ...inputOnlyMappingFields];
|
|
2993
|
+
const setWorkbenchFieldGroup = (fields, enabledGroup) => {
|
|
2994
|
+
const selected = new Set(fieldSelection);
|
|
2995
|
+
for (const [id] of fields) {
|
|
2996
|
+
if (enabledGroup) selected.add(id); else selected.delete(id);
|
|
2997
|
+
}
|
|
2998
|
+
const catalogOrder = uiFieldGroups.flatMap(([, , groupFields]) => groupFields.map(([id]) => id));
|
|
2999
|
+
actions.setFieldSelection(catalogOrder.filter((id) => selected.has(id)));
|
|
3000
|
+
};
|
|
2895
3001
|
|
|
2896
3002
|
let pane;
|
|
2897
3003
|
if (step === 'history') {
|
|
@@ -2964,8 +3070,22 @@ window.__ModuleLoader__.load({
|
|
|
2964
3070
|
),
|
|
2965
3071
|
h('section', { className: 'dcAgentSection' },
|
|
2966
3072
|
h('h3', null, `输出字段 · 已选 ${fieldSelection.length}`),
|
|
2967
|
-
|
|
2968
|
-
h('
|
|
3073
|
+
h('div', { className: 'dcAgentRow', 'aria-label': '补全字段批次概览' },
|
|
3074
|
+
h('span', { className: 'dcAgentChip' }, '基础字段 30'),
|
|
3075
|
+
h('span', { className: 'dcAgentChip' }, '第一批 40'),
|
|
3076
|
+
h('span', { className: 'dcAgentChip' }, '第二批 58'),
|
|
3077
|
+
),
|
|
3078
|
+
uiFieldGroups.map(([groupId, label, fields, sourceTool]) => h('div', { key: groupId, className: 'dcAgentFieldGroup' },
|
|
3079
|
+
h('div', { className: 'dcAgentFieldGroupHead' },
|
|
3080
|
+
h('div', null,
|
|
3081
|
+
h('b', null, `${label} · ${fields.filter(([id]) => fieldSelection.includes(id)).length}/${fields.length}`),
|
|
3082
|
+
sourceTool ? h('small', { className: 'dcAgentHint' }, `来源:${sourceTool}`) : null,
|
|
3083
|
+
),
|
|
3084
|
+
h('div', { className: 'dcAgentFieldGroupActions' },
|
|
3085
|
+
h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setWorkbenchFieldGroup(fields, true) }, '全选'),
|
|
3086
|
+
h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setWorkbenchFieldGroup(fields, false) }, '清空'),
|
|
3087
|
+
),
|
|
3088
|
+
),
|
|
2969
3089
|
h('div', { className: 'dcAgentChips' }, fields.map(([key, fieldLabel]) => h('label', { key, className: `dcAgentChip${fieldSelection.includes(key) ? ' is-selected' : ''}` },
|
|
2970
3090
|
h('input', { type: 'checkbox', checked: fieldSelection.includes(key), onChange: () => actions.toggleField(key) }), ` ${fieldLabel}`,
|
|
2971
3091
|
))),
|
|
@@ -3016,14 +3136,14 @@ window.__ModuleLoader__.load({
|
|
|
3016
3136
|
);
|
|
3017
3137
|
} else if (step === 'match') {
|
|
3018
3138
|
pane = h('div', { className: 'dcAgentPane' },
|
|
3019
|
-
h('p', { className: 'dcAgentHint' }, '通过当前用户连接的企查查 MCP
|
|
3139
|
+
h('p', { className: 'dcAgentHint' }, '通过当前用户连接的企查查 MCP 定位企业主体,并按已选维度补全一企一行字段。多候选始终由人工选择;界面不生成虚构置信度。'),
|
|
3020
3140
|
h('section', { className: 'dcAgentSection' },
|
|
3021
3141
|
h('h3', null, '匹配依据'),
|
|
3022
|
-
h('div', { className: 'dcAgentChips' }, mappings.filter((mapping) => ['company_name', 'credit_no', 'reg_no'].includes(mapping.targetField)).map((mapping) => h('span', { key: mapping.sourceField, className: 'dcAgentChip' }, `${mapping.sourceField} → ${
|
|
3142
|
+
h('div', { className: 'dcAgentChips' }, mappings.filter((mapping) => ['company_name', 'credit_no', 'reg_no'].includes(mapping.targetField)).map((mapping) => h('span', { key: mapping.sourceField, className: 'dcAgentChip' }, `${mapping.sourceField} → ${resultFieldLabel(mapping.targetField)}`))),
|
|
3023
3143
|
h('p', { className: 'dcAgentHint' }, '统一社会信用代码等强标识优先;名称匹配不明确时进入人工核验队列。'),
|
|
3024
3144
|
),
|
|
3025
3145
|
h('section', { className: 'dcAgentSection' },
|
|
3026
|
-
h('h3', null, '
|
|
3146
|
+
h('h3', null, '企查查一企一行补全能力'),
|
|
3027
3147
|
h('div', { className: 'dcAgentRow' },
|
|
3028
3148
|
h('button', { type: 'button', className: 'dcAgentButton', disabled: busy, onClick: loadQccCapabilities }, busy ? '检测中…' : '检测企查查连接'),
|
|
3029
3149
|
qccCapabilities ? h('span', { className: 'dcAgentHint' }, qccCapabilities.capabilities?.ready ? '主体查询与工商信息工具已就绪' : '连接未就绪或基础工具不完整') : null,
|
|
@@ -3083,7 +3203,7 @@ window.__ModuleLoader__.load({
|
|
|
3083
3203
|
h('p', { className: 'dcAgentHint' }, '执行本地确定性清洗并核对本任务所选补全字段。外部字段以当前用户企查查 MCP 的真实返回为准,缺失值不会被编造。'),
|
|
3084
3204
|
h('section', { className: 'dcAgentSection' },
|
|
3085
3205
|
h('h3', null, `已选补全字段 · ${fieldSelection.length}`),
|
|
3086
|
-
h('div', { className: 'dcAgentChips' }, fieldSelection.map((id) => h('span', { className: 'dcAgentChip', key: id },
|
|
3206
|
+
h('div', { className: 'dcAgentChips' }, fieldSelection.map((id) => h('span', { className: 'dcAgentChip', key: id }, resultFieldLabel(id)))),
|
|
3087
3207
|
),
|
|
3088
3208
|
h('section', { className: 'dcAgentSection' },
|
|
3089
3209
|
h('h3', null, '本地清洗预处理'),
|