9.4 KiB
查价系统 · 宿主 postMessage 对接说明
版本:1.1
更新日期:2026-07-24
适用对象:在 iframe 中嵌入查价页的宿主系统(如 ShipRo / 元子侧适配方)
嵌入页:/embed-demo(须先按 嵌入对接文档.md 完成 API Key 直登)
原则:由查价系统定义「要填什么 / 查完回什么」;宿主按本协议发
postMessage预填、收结果。字段与程序内部询价结构对齐,宿主无需再猜哪些字段可用。
0. ShipRo 联调要点(v1.1)
0.1 URL 直进 MotherShip 登录后表单(方案 A)
https://if.dev.51track.vip/embed-demo?login_type=api_key&api_key=<Key>&embed=1&module=MS_LOGGED_IN
等价:entry=ms_logged_in
登录成功后跳过 MotherShip/Flock 卡片与「免账号/登录后」点选,直接进入「创建新货件」。须该客户已绑定 MotherShip 官网账密,否则停在账密面板。
0.2 fill 可晚到 / 可重复 / 先缓存再灌表(方案 B)
- 收到
chajia:fill立刻缓存payload.form(不要求当前已在表单页)。 - 切入
module后,表单挂载时写入 UI;用户在表单页再点「填入数据」会再次灌表(seq递增)。 - 先回
chajia:fill-ack(ok: true,缓存确认);表单真正写入后再回一次 ack(ui_applied: true)。 - 不依赖宿主必须先等
chajia:ready(ready 仍会发,便于时序;晚到 fill 同样有效)。
0.3 MS_LOGGED_IN 地址可只传整段文本
宿主可不传 place_id / mothership_option_id。查价页把 formatted_address 或 street 写入提货/送货搜索框;用户须点选联想确认后才能「继续」。cargo_lines 写入货物行(inch/lb);空数组不改货物。
1. 总览
宿主页面
└─ iframe → .../embed-demo?...&embed=1[&module=MS_LOGGED_IN]
├─ iframe → 宿主:chajia:ready / chajia:fill-ack / chajia:quote-result / chajia:error
└─ 宿主 → iframe:chajia:select-module / chajia:fill / chajia:ping
| 方向 | 类型 | 作用 |
|---|---|---|
| iframe→宿主 | chajia:ready |
会话就绪(可开始发 fill;非强制前置) |
| 宿主→iframe | chajia:select-module |
切入四模块之一 |
| 宿主→iframe | chajia:fill |
按模块写入/缓存表单字段(必带 module,可重复) |
| 宿主→iframe | chajia:scroll-quotes |
请求 iframe 滚到「选择承运商」区(私卡出报价后) |
| iframe→宿主 | chajia:fill-ack |
已缓存;表单写入后再带 ui_applied |
| iframe→宿主 | chajia:quote-result |
查价结束(成功/失败/过期);及 MS 侧栏点选承运商时再次推送(带 selected) |
| iframe→宿主 | chajia:quote-save |
用户点「保存本次询价记录」(可选;写快照) |
| iframe→宿主 | chajia:scroll-top |
进入二级详情等:请求宿主把查价 iframe 区域滚到视口顶部 |
| iframe→宿主 | chajia:error |
协议层错误(缺 module 等) |
| iframe→宿主 | chajia:module-changed |
用户或宿主切换了模块 |
信封统一格式:
{
"source": "chajia",
"version": 1,
"type": "chajia:fill",
"request_id": "宿主生成的 UUID,可选,用于配对",
"module": "MS_LOGGED_IN",
"payload": {}
}
- 必须校验
source === "chajia"且version === 1,忽略其它来源。 targetOrigin:生产建议写成查价域名;联调可用*。- 仅当页面在 iframe 中时,查价页才会向
parent回传。
2. 模块 ID(必须区分)
与 OpenAPI 路线一致,四选一、互斥:
| module | 含义 | 门户表现 |
|---|---|---|
MS_GUEST |
MotherShip 免账号 | MotherShip → 免账号 |
MS_LOGGED_IN |
MotherShip 登录后 | MotherShip → 登录后(须已绑官网账密) |
FLOCK_GUEST |
Flock 免账号 | Flock → 免账号 |
FLOCK_LOGGED_IN |
Flock 登录后 | Flock → 登录后(须已绑官网账密) |
chajia:fill 必须带 module。不同模块的 payload.form 字段不同,不可混用。
3. 宿主 → iframe:预填(按模块)
3.1 通用写法
iframe.contentWindow.postMessage(
{
source: "chajia",
version: 1,
type: "chajia:fill",
request_id: crypto.randomUUID(),
module: "MS_LOGGED_IN",
payload: {
select_module: true,
form: { /* 见 3.3 */ }
},
},
"https://if.dev.51track.vip",
);
也可把 form 直接作为 payload(无 select_module 包装)。
3.2 MS_GUEST
{
"pickup": { "street": "1234 Warehouse Blvd", "city": "Los Angeles", "state": "CA" },
"delivery": { "street": "5678 Distribution Dr", "city": "Dallas", "state": "TX" },
"weight": { "value": 500, "unit": "lb" },
"dimensions": { "length": 48, "width": 40, "height": 48, "unit": "in" },
"pallet_count": 2,
"cargo_type": "general_freight"
}
3.3 MS_LOGGED_IN(ShipRo 现网:整段文本 + cargo_lines)
{
"pickup_address": {
"street": "整段发货地址原文",
"formatted_address": "整段发货地址原文"
},
"delivery_address": {
"street": "整段目的地址原文",
"formatted_address": "整段目的地址原文"
},
"cargo_lines": [
{
"cargo_type": "pallet",
"quantity": 1,
"weight_lb": 100,
"length_in": 48,
"width_in": 40,
"height_in": 48
}
]
}
| 字段 | 说明 |
|---|---|
| 地址 | formatted_address 或 street → 搜索框;可不传 place_id(用户点选联想) |
| cargo_lines | inch/lb;空数组不改货物 |
| ready_* / accessorials | 可选;不传用页默认 |
3.4 仅切模块
{ "source": "chajia", "version": 1, "type": "chajia:select-module", "module": "MS_LOGGED_IN" }
4. 查价结果
chajia:quote-result → payload.quotes[].carrier / final_total;失败读 error_message。
宿主若需明确区分“官网原价”和“客户加价后展示价”,可直接读:
base_total_before_markup:未加价原价customer_markup_amount:该客户加价金额customer_final_total:该客户最终展示价(等同当前final_total)is_customer_markup_applied:是否已叠加客户加价pricing_mode = "customer_final":宿主可直接按客户最终价展示
4.1 侧栏点选承运商即时同步(宿主锁价)
MotherShip 登录后侧栏(MS_LOGGED_IN):
- 用户点选任意承运商卡片、默认选中出价、或切换保障导致生效费率变化时
- iframe 再次发出
chajia:quote-result(不依赖绿色「保存本次询价记录」) payload.quotes[]中当前生效那条selected: true,其余false- 宿主取
selected === true的档(无则兜底首条)即可锁定承运商与final_total/customer_final_total - 绿色「保存」仍可选发
chajia:quote-save(action: "save"+ 同样selected),仅用于写快照;私卡询价跳转不必等保存
触发时机代码入口:onSelectQuote → notifyHostQuoteSelection → reportQuoteResult。
4.2 出报价后视野定位(需求3)
- 查价页:报价列表出现后自动
scrollIntoView到侧栏「选择承运商」(#ms-choose-carrier);「已选」角标与承运商名同一行,不遮挡标题 - 宿主:收到
quote-result后左侧滚到「当前选中报价」,并可向 iframe 发:
{ "source": "chajia", "version": 1, "type": "chajia:scroll-quotes" }
iframe 收到后再次滚承运商区。需查价页与 cc-client 一起部署 才完整。
4.3 「继续」进入二级后置顶
用户在一级点「继续」进入提货/送货详情时:
- 查价页:iframe 内
scrollTo(0)+ 根节点scrollIntoView - 同时向宿主发:
{
"source": "chajia",
"version": 1,
"type": "chajia:scroll-top",
"module": "MS_LOGGED_IN",
"payload": { "reason": "logged-in-details" }
}
- 宿主:收到后将私卡询价弹窗/iframe 容器滚到视口顶部
需查价页与 cc-client 一并更新。
5. 联调顺序(ShipRo)
- iframe:
...&embed=1&module=MS_LOGGED_IN - 进「创建新货件」后点「填入数据」→
chajia:fill - 收
fill-ack(缓存)→ 再收ui_appliedack - 用户点选地址联想 → 继续 →
chajia:quote-result(出票) - 用户在侧栏点选承运商 → 再收
chajia:quote-result(带selected)→ 宿主锁价后可「确认询价并新建集装箱」
亦可打开后立即 fill(先缓存,表单挂载后灌入)。
| 能力 | 状态 |
|---|---|
URL module / entry 直进 |
已实现 |
| fill 缓存 + 可重复 + 晚到灌表 | 已实现 |
| MS_LOGGED_IN 搜索框 + cargo_lines | 已实现 |
| MS_GUEST 预填 / quote-result | 已实现 |
| 侧栏点选承运商 → quote-result + selected | 已实现 |
| 出报价后自动滚到「选择承运商」/ scroll-quotes | 已实现 |
| 「继续」进二级 → scroll-top 置顶 | 已实现 |
6. 文档关系
| 文档 | 用途 |
|---|---|
嵌入对接文档.md |
iframe URL、API Key、module |
| 本文 | postMessage |
api对接文档.md |
OpenAPI |
代码:lib/embed/host-bridge.ts、parseEmbedEntryModule(lib/embed/sso-params.ts)、map-quotes-selection.ts、mothership-logged-in-quote-sidebar / embedded-quote-widget。