6.0 KiB
OneTalk 名片消息:运行态格式观察
观察日期:2026-09-11
证据边界:现有已登录 OneTalk PWA 的 Chromium CDP,只读调用页面 SDK;不保存或输出原始消息、联系人资料、令牌、加密标识或正文。
性质:单个真实样本的运行态观察,不是当前跨层数据合同。
1. 怎么判断是名片
SDK 历史条目的名片判别条件为:
const isBusinessCardMessage = (message: Record<string, unknown>): boolean =>
message.messageType === "rec" &&
message.type === 1 &&
message.viewType === 0 &&
message.msgType === 10010 &&
message.subType === 57 &&
message.originalData?.cardType === 1;
这里的联合条件不可缩减成 msgType=10010:附件、询盘和订单也使用该 msgType。
2. JSON 中已有的数据
2.1 名片卡片参数
originalData.cardType = 1
originalData.params keys =
ctime, from, showCertifications, showCompanyName,
showEmailAddress, sign, to
showCompanyName、showEmailAddress 和 showCertifications 是展示开关;它们不是公司名、邮箱或认证详情本身。
2.2 历史条目的 contact(登录人/发送者资料,不能作为客户来源)
同一条 SDK 条目的 contact 中可观察到以下候选字段。运行态复核确认,这组资料对应登录人或发送者侧的用户资料,不等于当前会话关联客户资料;它不能被当作名片内容来源。
accountId, accountIdEncrypt, aliId, aliIdEncrypt,
loginId, loginIdEncrypt, name, fullPortrait,
companyName, complianceCountryCode, currentTimeZone, serviceType
可谨慎使用的资料含义如下:
| 字段 | 观察到的信息 | 使用限制 |
|---|---|---|
contact.name |
显示名 | 可能是登录人/发送者资料,不能证明是会话客户或名片字段 |
contact.companyName |
公司名 | 可为空或滞后;不能写入名片消息事实 |
contact.complianceCountryCode |
国家/地区代码 | 国旗由 UI 按代码渲染,不是消息图片 |
contact.fullPortrait |
头像候选 URL | 本样本未填;不能假设必有或作为名片快照保存 |
截图中的邮箱没有观察到独立的 email JSON 字段。本样本 content 是非 JSON 的普通字符串;邮箱可能出现在其中的展示文本,但没有验证出可复用的字段格式。
extInfo.icbuData 同样只有 chatEvent 有实际值,title、iconUrl、cardUrls、actions、defaultContent 都不可直接使用。
3. 怎么获取
名片和其它业务卡共享同一只读历史入口;区别只在过滤条件。
const getBusinessCardMessages = 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 === 57 &&
message.originalData?.cardType === 1,
);
};
如果后续业务需要联系人名称、公司、国家代码或头像,应从独立的联系人资料观察链路获取,而不是复用历史条目的 contact。window.__conversationListData__ / profile 观察与消息采集可能异步到达,因此消息观察只输出 { version: 1, kind: "business_card" } marker;Bright 读取 /messages 时再按 [channelAccountId, conversationId] 读取当前客户资料,并以内存方式补出 contactName、companyName、countryCode、avatarUrl 四项。没有客户资料时返回 marker,单字段缺失时返回 null,不回退到登录人资料,也不把 view 写回消息事实。
跨层同步只应传递经业务批准的 profile 白名单字段;不能透传 contact 整体对象、加密标识、chatToken、content 或 sign。
4. 跨层使用边界(实施后)
- MAIN 历史 decoder 仍使用完整
(messageType, type, viewType, msgType, subType, cardType)联合条件识别名片,但只生成business_cardmarker。 item.contact不参与名片消息归一化;它可能描述登录人/发送者,不能代表当前会话关联客户。- 客户资料沿独立
contact.profile.observed→onetalk_contact_profile路径持久化。消息事实表的content只保留kind和version,数据库 exact CHECK 会拒绝附带客户字段的名片 JSON。 - 服务端读取先按账号和会话读取当前 profile,再以内存组合出可选 view。profile 不存在时对外仍是 marker;部分 profile 只返回对应
null。 - 以上实施边界不改变本页“单个真实样本的运行态观察”性质;它记录的是如何避免把观察到的登录人资料误当成客户资料。
5. 已验证与未覆盖
- 已验证:
10010/57/cardType=1判别组合,originalData.params键集合,contact候选资料和icbuData可用性;contact不应作为会话客户名片来源。 - 已实施的跨层规则:消息事实只保存 marker,读取时按同账号同会话 profile 组合 view,资料缺失/部分缺失分别返回 marker/
null。 - 未覆盖:
content的名片展示文本格式,独立邮箱字段来源,头像字段在不同名片中的填充率,以及名片详情/跳转链接。