Files
trade-message-center/docs/onetalk-inquiry-message-format-observation-2026-09-11.md

4.7 KiB
Raw Permalink Blame History

OneTalk 询盘消息:运行态格式观察

观察日期:2026-09-11
证据边界:现有已登录 OneTalk PWA 的 Chromium CDP,只读调用页面 SDK;不切换会话、不更新已读状态、不保存或输出原始消息、令牌、加密标识、媒体 URL 或正文。
性质:单个真实样本的运行态观察,不是 OneTalk 全局类型枚举,也不是当前跨层数据合同。

1. 怎么判断是询盘

SDK 历史返回的单条扁平消息必须同时满足以下条件:

const isInquiryMessage = (message: Record<string, unknown>): boolean =>
    message.messageType === "rec" &&
    message.type === 1 &&
    message.viewType === 0 &&
    message.msgType === 10010 &&
    message.subType === 50 &&
    message.originalData?.cardType === 6;

其中 msgType=10010 不是充分条件:当前已观察到的附件、名片和订单同样使用它。

类型 msgType subType originalData.cardType
询盘 10010 50 6
名片 10010 57 1
订单 10010 59 9
附件 10010 61 12

2. JSON 中已有的数据

SDK 返回是 { hasMore, list },本样本的询盘条目具有以下顶层字段:

autoReply, contact, contactRead, content, conversationCode, extInfo,
localExt, messageId, messageType, msgType, opId, originExt,
originalData, owner, receiver, sendTime, sender, spamStatus, status,
subType, type, unread, uuid, viewType

询盘专有的稳定结构位于 originalData

originalData.cardType = 6
originalData.params keys =
  ctime, encryFeedbackId, encryTradeId, fbType, from, marketType,
  sign, source, to, version

这些字段可用于将消息关联到询盘/贸易实体,但 encryFeedbackIdencryTradeIdsign 属于不应跨 MAIN-world 边界的敏感原始值。

extInfo.icbuData 具有 actionscardUrlstitleiconUrldefaultContentchatEvent 等候选键名;本样本实际只有 chatEvent 有值。不能把键存在误认为标题、商品图片或详情链接可直接取得。

本样本的 content 是普通字符串,不是 JSON、URI-JSON 或 Base64-JSON。它不是稳定的业务字段合同。

3. 展示卡与 SDK 字段的差异

页面渲染的询盘卡可显示商品标题、采购量、需求、商品图片和按钮,但这些并非本次 SDK 对象中直接可用的结构化字段:

  • 商品标题、采购量、详细需求和图片可以在已渲染且当前可见的卡片 DOM 中读取;这只是 UI 观察,不可代替消息事实源。
  • 本样本的 SDK cardUrls 为空,卡片内也没有静态 <a href>;“查看详情 / 立即报价”由前端点击逻辑生成,不能从原始消息直接宣称存在详情链接。
  • 不应通过 DOM 抓取的展示文本反推稳定的后端协议字段。

4. 怎么获取

在 OneTalk PWA 的 MAIN world 中,从精确会话对象调用只读历史方法。不要从昵称、列表顺序或页面文本推断 conversationId

const getInquiryMessages = async (conversation) => {
    const service = window.IcbuIM.IMBaaSSDK.default.getMessageService();
    const response = await service.fetchMessagesWithoutUpdateToRead(
        {
            conversationCode: conversation.cid,
            contactAccountId: conversation.accountId,
            contactAccountIdEncrypt: conversation.accountIdEncrypt,
            aliId: conversation.aliId,
            aliIdEncrypt: conversation.aliIdEncrypt,
            searchMessageId: "",
            timeSlide: { forward: false, timeStamp: Date.now(), pageSize: 20 },
        },
        conversation,
    );

    return (response.list ?? []).filter(
        (message) =>
            message.messageType === "rec" &&
            message.type === 1 &&
            message.viewType === 0 &&
            message.msgType === 10010 &&
            message.subType === 50 &&
            message.originalData?.cardType === 6,
    );
};

这个函数的返回值只应在 MAIN world 中用于归类或进一步受控解析。跨页面桥、Service Worker、IndexedDB、Bright 或 Mind 时,应传递白名单化的业务字段或明确的 unsupported 结果,绝不能传递整个 messagecontentparamschatToken 或序列化的原始对象。

5. 已验证与未覆盖

  • 已验证:上述判别组合、originalData.params 键集合、icbuData 字段可用性、单页 SDK 返回形态。
  • 未覆盖:询盘 content 的稳定文本格式、商品详情 API、详情链接生成规则、不同站点/订单状态下的变体。