4.7 KiB
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
这些字段可用于将消息关联到询盘/贸易实体,但 encryFeedbackId、encryTradeId 和 sign 属于不应跨 MAIN-world 边界的敏感原始值。
extInfo.icbuData 具有 actions、cardUrls、title、iconUrl、defaultContent、chatEvent 等候选键名;本样本实际只有 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 结果,绝不能传递整个 message、content、params、chatToken 或序列化的原始对象。
5. 已验证与未覆盖
- 已验证:上述判别组合、
originalData.params键集合、icbuData字段可用性、单页 SDK 返回形态。 - 未覆盖:询盘
content的稳定文本格式、商品详情 API、详情链接生成规则、不同站点/订单状态下的变体。