company-classify-dms-sync.md 5.0 KB

企业信息分类同步(company_info → classify → DMS 1888/1886)

目标

对话返回的 result 事件里带 company_info(非空)时,自动把该企业的分类结果同步到 DMS 的企业基础信息(1888)与企业荣誉信息(1886)两个栏目:没有该企业就新增, 已有就按字段差异更新。全程 fire-and-forget,失败不影响聊天。

依据接口文档:../../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_infoapi-chat-coordinator.tscase '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' 作所有权标记。
  4. 1888 对比范围 = 身份三字段(企业名/信用代码/法人)+ 6 个标签字段。

Step-0 实测(2026-09-18)

探测 结果
classify 空体 {} 200,返回六角度全空 + input_warnings:["company_info_empty"],不调用 LLM
classify 任何带键的体(文档示例 / ASCII / 中文 / company:{} / profile:{} / honors:null / company_info:{} / Company:{} 全部 422 invalid_request(响应头有 x-request-id,可据此找后端日志)
POST /dms/model/getModelById(form modelId=2036/2032 200,拿到完整 fieldList:1888 47 字段 / 1886 12 字段,c_tag_* 已存在
1888 must c_credit_code
1886 must c_id + c_credit_code

⚠️ classify 的 422 是后端问题(前端已排除编码/引号/键名因素),需后端排查; 在它修好之前,「真实分类响应」这条链路只能靠注入假响应验证。

步骤

  1. 纯函数层 src/network/api/dms/classification-sync-utils.ts(身份抽取、编解码、diff、集合同步)
  2. 网络层 src/network/api/company-classification.tsclassifyCompany
  3. 编排层 src/network/api/dms/company-info-sync.ts(查→分类→写/改,串行链)
  4. 协调器捕获 company_info(3 处)+ composable 挂钩(1 处)
  5. client.ts 加 1888/2036、1886/2032 常量;把 findRowBy/enqueueWritechat-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 buildvue-tsc --noEmitvalidate-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 行);若业务要保留历史荣誉, 改成「只增不删」即可(一行)