# 企业信息分类同步(company_info → classify → DMS 1888/1886) ## 目标 对话返回的 `result` 事件里带 `company_info`(非空)时,自动把该企业的分类结果同步到 DMS 的企业基础信息(1888)与企业荣誉信息(1886)两个栏目:没有该企业就新增, 已有就按字段差异更新。全程 fire-and-forget,失败不影响聊天。 依据接口文档:[`../../reference/company-classification.md`](../../reference/company-classification.md)(F062)。 ## 现状(2026-09-18 探测所得) - **classify 接口已部署**(`POST /api/company/classify`,与 `/api/chat` 同一后端)。 但 ⚠️ **实测任何带内容的请求体都返回 `422 invalid_request`**——连文档自己的 合成示例也被拒;只有空对象 `{}` 返回 200(`company_info_empty`)。 详见本文件「Step-0 实测」。 - **DMS 侧的字段已经加好了**(2026-09-18 17:35–17:36 由 DMS 侧更新模型): - 1888(modelId 2036,**47 字段**)新增 6 个 `c_tag_*`,别名 = 六个角度名;must 只有 `c_credit_code` - 1886(modelId 2032,**12 字段**)新增 `c_tag_name`(别名「荣誉」);must = `c_id` + `c_credit_code` - 所以**不需要再请 DMS 侧加字段**(原计划里那份清单已作废) - 前端目前**拿不到 company_info**:`api-chat-coordinator.ts` 的 `case 'result'` 是空分支。 - `api-chat.md` 里**还没有 company_info 的契约章节**(classify 文档的引用超前); 分类文档给出的结构是 `{company, profile:{data, source}, honors}`。 ## 已确认的决策(用户 2026-09-18) 1. **DMS 读写复用现有路径**:`/dms-api` 代理 + `src/network/api/dms/client.ts` (「原来怎么用现在就怎么用」),不用 `121.43.55.7:2101/proxy_dms`。 2. 六个角度各存 1888 一个字段(JSON 数组字符串)。 3. ~~1886 一个标签一行,`c_source='company_info_sync'` 作所有权标记~~ → **【2026-09-18 当天修正,见下】1886 改为以 `company_info.honors.records` 为准全量对齐** 4. 1888 对比范围 = 身份三字段(企业名/信用代码/法人)+ 6 个标签字段。 ### 📌 修正:1886 的数据源换成 `honors.records`(用户 2026-09-18 拍板) **起因**:用户用宇树科技股份有限公司实测,1886 只有 2 条,觉得「应该不止两条」。 查证后确认**同步没写错、是数据源选错了**: | | 数量 | |---|---| | 分类接口的「资质荣誉」标签(原实现的数据源) | **2** 个(`中国独角兽企业`、`国家级高新技术企业`)——它是 165 个标签里挑的粗标签 | | `company_info.honors.records`(真实荣誉) | **31** 条,每条含 荣誉名/级别/来源/发布机构/发布日期/证书编号 | | 库里已灌入的行 | 28 条(**同一份企查查荣誉数据的旧快照**,字段与 `honors.records` 一一对应) | **新规则**: - 1886 一行 = 一条真实荣誉;荣誉名同时写 `c_tag_name` 与系统字段 `title` - 与库里该企业的行按「**荣誉名+级别+来源**」**全量对齐**:补新增、更新差异、删多余 - **仅当 `honors.complete === true` 才删**(记录集不完整时删 = 丢数据) - 灌入的行同样参与对齐(它们就是同一份数据的旧快照),首次对齐会补上 `c_tag_name` - 「资质荣誉」标签仍写进 1888 的 `c_tag_honor`(标签与明细各归其位,互不冲突) ## Step-0 实测(2026-09-18) | 探测 | 结果 | |---|---| | classify 空体 `{}` | **200**,返回六角度全空 + `input_warnings:["company_info_empty"]`,不调用 LLM | | classify **精简/合成**载荷(文档里的示例片段 / 纯 ASCII / `company:{}` / `profile:{}` / `honors:null` / `company_info:{}`) | **全部 422 `invalid_request`** | | classify **真实完整**载荷(用户给的真实 company_info) | ✅ **200**,7 秒返回六角度真实分类结果 | | `POST /dms/model/getModelById`(form `modelId=2036`/`2032`) | **200**:1888 47 字段 / 1886 12 字段,`c_tag_*` 已存在 | | 1888 must / 1886 must | 仅 `c_credit_code` / `c_id` + `c_credit_code` | | **1888 / 1886 的实际数据** | **两栏目都已有数据**(2026-09-17 18:12 由 DMS 侧灌入):1888 是完整工商信息行,1886 是真实荣誉行(`c_source` = 来源通知名)。**原文档「仍是空的」已过期** | | 空标签的存储 | 写 `[]` 读回来是**字段不存在**(语义等同);`c_created_at` 在 1888 里写了读不回 | > 📌 **更正**:本轮最初把 classify 的 422 记成「后端坏了」,**不准确**——它是对**载荷完整性**的 > 校验:精简/合成载荷被拒,真实完整载荷正常。已在 `api-chat.md` 的 company_info 章节写明。 ## 步骤 1. 纯函数层 `src/network/api/dms/classification-sync-utils.ts`(身份抽取、编解码、diff、集合同步) 2. 网络层 `src/network/api/company-classification.ts`(`classifyCompany`) 3. 编排层 `src/network/api/dms/company-info-sync.ts`(查→分类→写/改,串行链) 4. 协调器捕获 company_info(3 处)+ composable 挂钩(1 处) 5. `client.ts` 加 1888/2036、1886/2032 常量;把 `findRowBy`/`enqueueWrite` 从 `chat-sessions-dms.ts` 提到 `client.ts` 共用(避免两处 `orderBy` 坑各踩一遍) ## 数据流 ``` result 事件 data.company_info → 协调器暂存 → done → totalResponse 带出 → useBusinessAssistantChat 监听器(saveTurnToDms 之后、finishTask 之前) → void syncCompanyInfoFromChat() → classify → 1888 upsert + 1886 集合同步 ``` ## 验证 - 纯函数:`harness/tools/verify-company-classify-sync.mjs`(打包 `_entry-company-classify.ts`) - 真实 DMS:`harness/tools/verify-company-classify-dms.mjs`(注入假分类响应走编排层, 首写 → 二次改 → 三次清空 → 清理测试数据) - 回归:`npm run build`、`vue-tsc --noEmit`、`validate-harness`、既有 tools 脚本 - 真实 classify:**等后端修好 422 后**补测,届时把真实载荷回填 `api-chat.md` ## 风险 / 未决 - **classify 422 阻塞真实验证**(后端侧);前端实现不受阻 - `c_tag_honor`(1888)的 `frontType=content`(富文本),其余是 `text`/`varchar` —— 写 JSON 数组字符串时**富文本字段可能被转义或清洗**,真实链路验证时要专门核对这一列; 若确实被改写,请 DMS 侧把它改成 `text` - `company_info` 的真实载荷未知 → 全可选 + `profile.data` 优先回退 `company` 的容错读取 - 1886 的 `c_id` 必填(整型,源库主键);前端新写行拿不到源库 id,先按 1889 的经验 传 `0`(实测自动填),若被 214 拒绝再与 DMS 侧确认取值 - completed + 空数组 = 覆盖清空(会删光我方 1886 行);若业务要保留历史荣誉, 改成「只增不删」即可(一行)