# khhao 新数据来源接入设计 ## 1. 背景 当前系统的订单来源只有 `agiso`,核心模式是: - 上游通过 webhook 推送订单事件; - 后端按 `provider + platform + shopId + platformOrderId` 幂等落库; - 命中履约绑定后生成任务、领取链接、自动发货等后续流程。 现在需要新增一个来源:`admin.khhao.com` 这一套已开发好的平台后台。 和 `agiso` 的差异是: - **不是 webhook 推送**,而是**账号密码登录 + 验证码识别 + Cookie 会话查询**; - 订单数据来自平台接口查询; - 初期目标是先完成**登录能力**与**订单查询能力**,再决定是否做定时拉取/增量同步。 ## 2. 已确认事实(来自 `2026-05-02` 的 HAR) HAR 文件:`/Users/yml/Desktop/抓包/登陆.har` 已确认接口链路: 1. 打开登录页 `GET https://admin.khhao.com/c/login/index.php` 2. 获取验证码图片 `GET https://admin.khhao.com/verify_img.php` 3. 提交登录表单 `POST https://admin.khhao.com/c/login/index.php` 表单字段: - `username` - `password` - `img_code` 4. 登录成功响应 ```json {"errcode":0,"msg":"登陆成功","url":"/c/payOrder/index.php"} ``` 5. 查询订单列表 `GET https://admin.khhao.com/c/payOrder/get.php?page=1&limit=50` 6. 当前 HAR 中,登录依赖 `PHPSESSID` Cookie 维持会话。 订单列表响应里已看到这些关键字段: - `ordersn`:外部订单号 - `pingtai` / `pingtaiName`:平台标识/平台名 - `shopid` / `shopName`:店铺 - `goodid` / `goodName`:商品 - `sku`:SKU - `fee`:成交金额 - `chengben` / `lirun`:成本/利润 - `num`:数量 - `status` / `statusName`:订单状态 - `addtime`:下单/录入时间 ## 3. 设计目标 ### 3.1 MVP 目标 先做最小可用能力: 1. 后端可通过账号密码自动登录 khhao; 2. 自动拉取验证码图片,并用现有 `ddddocr` 识别; 3. 登录成功后带 Cookie 调用订单查询接口; 4. 能按统一结构把 khhao 订单转换为内部订单模型; 5. 提供一个**手动查询 / 手动同步**入口,先不直接接入自动履约主流程。 ### 3.2 第二阶段目标 1. 支持按时间窗口或页码批量拉取订单; 2. 增加定时轮询同步; 3. 将 khhao 订单正式纳入现有订单履约流程; 4. 视需要增加远端订单详情接口接入。 ## 4. 关键设计决策 ## 4.1 新来源标识 建议: - `provider = 'khhao'` - `platform = 由返回字段映射` 原因: - 现有系统已经以 `provider/platform` 作为来源分层; - khhao 本身更像“聚合后台/运营后台”,其下可能有多个平台; - 后续如果 `pingtai=3` 代表快手、还有其它平台,也可以继续扩展。 建议先做一个映射表,例如: - `3 -> kuaishou` - 未识别值 -> `unknown` 同时把原始 `pingtai`、`pingtaiName` 放进 `raw_payload_json` 保留证据。 ## 4.2 接入模式 `agiso` 是 **push**;`khhao` 应设计成 **pull**。 因此不要强行塞进 `webhook-service`,而是单独建立: - 登录会话服务 - 验证码识别服务 - 订单查询服务 - 订单转换/同步服务 ## 4.3 会话管理 建议优先采用 **纯 HTTP + Cookie Jar**,不引入浏览器自动化。 原因: - HAR 显示登录流程很简单,没有前端加密、签名或复杂跳转; - 验证码是普通图片; - 登录后查询接口是标准 XHR; - 用 HTTP 实现更稳定,也更适合服务端定时任务。 只有在后续发现以下情况时,再退回浏览器方案: - 服务端校验动态前端字段; - 有 JS 生成签名; - Cookie/会话依赖浏览器行为; - 验证码识别成功但仍反复登录失败。 ## 4.4 OCR 复用 现有 OCR 子服务已经使用: - `apps/backend/subservices/ocr-worker` - `ddddocr>=1.6.1` 因此不需要新增 OCR 技术栈,只需要把 khhao 验证码图片作为图片字节传给现有 OCR 能力即可。 建议新增一个更通用的方法,而不是继续绑定在 “Tencent” 语义上: - 现状:`recognizeTencentCaptcha` - 建议新增:`recognizeImageCaptcha` 然后: - 腾讯验证码继续走原接口或复用通用接口; - khhao 登录验证码直接走通用接口。 ## 5. 推荐模块拆分 建议新增目录: `apps/backend/src/services/platforms/khhao/` 建议模块: ### 5.1 `captcha-service.js` 职责: - 请求 `/verify_img.php` - 读取图片字节 - 调 OCR - 返回识别结果与调试信息 建议返回: - `captchaText` - `imageBase64`(仅调试阶段可选) - `cookieHeaders` ### 5.2 `session-service.js` 职责: - 初始化 Cookie 容器; - 访问登录页,拿到初始 `PHPSESSID`; - 获取验证码并识别; - 提交登录表单; - 校验登录响应; - 返回已登录会话对象。 建议会话对象: - `baseUrl` - `cookieHeader` - `cookieMap` - `loggedInAt` ### 5.3 `order-query-service.js` 职责: - 调用 `/c/payOrder/get.php` - 支持分页参数:`page`、`limit` - 后续支持筛选参数(如果继续抓到更多接口) - 返回原始平台订单列表 ### 5.4 `order-mapper-service.js` 职责: - 将 khhao 原始订单映射成内部统一订单结构; - 归一化金额、数量、状态、平台、店铺、SKU; - 产出可供 `order-service` 或新同步服务消费的对象。 建议映射: - `platformOrderId <- ordersn` - `shopId <- shopid` - `shopName <- shopName` - `totalAmount <- fee`(转分) - `items[0].skuCode <- sku` - `items[0].skuName <- goodName` - `items[0].quantity <- num` - `rawPayload <- 原始整条记录` 注意: - 当前列表接口一条记录看起来像“一单一商品”,但不能假设永远如此; - 第一版可以先按单商品映射; - 如果后续发现有多商品订单,再调整内部映射。 ### 5.5 `order-sync-service.js` 职责: - 批量查询 khhao 订单; - 调 `order-mapper-service` 转换; - 调内部订单 upsert; - 记录同步结果、失败原因、游标信息。 这里建议不要直接复用 `upsertOrderFromWebhook(event)`,因为它的命名和语义绑定 webhook。 更合理的演进方向: - 抽一个来源无关的方法,例如 `upsertOrderFromSource(event)`; - `webhook-service` 继续只负责 webhook 解析; - `khhao` 同步服务直接调用来源无关的 upsert。 ## 6. 配置设计 ## 6.1 运行时配置 建议在: - `apps/backend/config/default.cjs` - `apps/backend/src/types/runtime-config.js` - `apps/backend/src/config/runtime.js` 增加: ```js platforms: { khhao: { baseUrl: 'https://admin.khhao.com', timeoutMs: 5000, loginPath: '/c/login/index.php', captchaPath: '/verify_img.php', orderListPath: '/c/payOrder/get.php', }, } ``` ## 6.2 凭据配置 不建议把账号密码直接写进仓库文档或默认配置。 建议通过以下方式之一管理: 1. 环境变量; 2. `apps/backend/data/khhao-sources.json`; 3. 后台平台配置页维护。 建议结构: ```json { "sources": [ { "sourceKey": "khhao-main", "enabled": true, "baseUrl": "https://admin.khhao.com", "username": "******", "password": "******", "defaultPlatform": "kuaishou" } ] } ``` 第一阶段最省成本的方案:**本地文件 + 环境变量覆盖**。 ## 7. 与现有系统的衔接方式 ## 7.1 第一阶段:只做手动查询/同步 建议新增后台接口,例如: - `POST /api/v1/admin/platform-config/khhao/test-login` - `POST /api/v1/admin/platform-config/khhao/query-orders` - `POST /api/v1/admin/platform-config/khhao/sync-orders` 这样好处是: - 不会影响现有 `agiso` 主链路; - 可以先验证 OCR、登录、Cookie、字段映射; - 便于比对真实订单数据。 ## 7.2 第二阶段:纳入统一订单流程 当字段映射稳定后,再把 khhao 同步数据接到统一订单主链路: - 来源查询 -> 订单映射 -> 通用 upsert -> 履约绑定 -> 任务生成 这一步需要补充: - khhao 订单状态到内部 `orderStatus/payStatus` 的映射; - 去重与增量同步策略; - 同一来源重复登录的频率控制; - 同步审计日志。 ## 8. 状态映射建议 当前 HAR 仅看到: - `status = 2` => `已发货` - `status = 0` => `未打款` 第一阶段不要写死太多业务含义,建议: ### 内部订单状态 - `status=0` -> `created` - `status=2` -> `delivered` - 未知值 -> `unknown` ### 内部支付状态 - `status=0` -> `unpaid` - `status=2` -> `paid` - 未知值 -> `unknown` 但这只是 **初版推断**,最终要以更多样本验证。 ## 9. 风险点 1. **验证码识别率** - `ddddocr` 大概率可用,但识别失败需要自动重试; - 建议单次登录允许 `2~3` 次验证码重试。 2. **登录态过期** - 需要判断何时复用 Cookie,何时重新登录; - 第一阶段可以每次查询都重新登录,先求稳定。 3. **订单列表不是详情接口** - 当前拿到的是列表接口,不排除存在订单详情页/详情接口; - 第一版先以列表字段落库; - 如果后续履约需要更多字段,再补抓详情接口。 4. **平台字段含义未完全确认** - `pingtai=3` 目前只从样本推断是快手; - 需要再抓几个平台样本确认映射表。 5. **同步边界** - khhao 是拉取式来源,必须明确增量条件; - 第一版建议按 `page/limit` 手动同步,先不做自动游标。 ## 10. 推荐实施顺序 ### 阶段 A:打通基础能力 1. 增加 khhao 配置结构; 2. 增加通用图片 OCR 能力; 3. 实现登录 + Cookie 会话; 4. 实现订单列表查询; 5. 增加后台“测试登录 / 查询订单”接口。 ### 阶段 B:打通内部模型 1. 实现 khhao -> 内部订单映射; 2. 提炼 webhook 无关的通用 order upsert; 3. 增加手动同步接口; 4. 在后台展示同步结果。 ### 阶段 C:进入自动履约 1. 增量同步; 2. 定时任务; 3. 状态回补; 4. 接入履约绑定、任务生成、消息通知。 ## 11. 本次设计结论 结论很明确: - khhao 不应该按 `agiso webhook` 思路接; - 应该作为一个新的 **pull 型来源** 单独建接入层; - OCR 直接复用现有 `ddddocr` 子服务; - 第一阶段先做**手动查询/同步**最稳; - 等字段、状态、平台映射稳定后,再接入统一履约主流程。