You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chajia/api调用文档/嵌入-postMessage对接文档.md

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):

  1. 用户点选任意承运商卡片、默认选中出价、或切换保障导致生效费率变化时
  2. iframe 再次发出 chajia:quote-result(不依赖绿色「保存本次询价记录」)
  3. payload.quotes[] 中当前生效那条 selected: true,其余 false
  4. 宿主取 selected === true 的档(无则兜底首条)即可锁定承运商与 final_total / customer_final_total
  5. 绿色「保存」仍可选发 chajia:quote-save(action: "save" + 同样 selected),仅用于写快照;私卡询价跳转不必等保存

触发时机代码入口:onSelectQuote → notifyHostQuoteSelection → reportQuoteResult。

4.2 出报价后视野定位(需求3)

  1. 查价页:报价列表出现后自动 scrollIntoView 到侧栏「选择承运商」(#ms-choose-carrier);「已选」角标与承运商名同一行,不遮挡标题
  2. 宿主:收到 quote-result 后左侧滚到「当前选中报价」,并可向 iframe 发:
{ "source": "chajia", "version": 1, "type": "chajia:scroll-quotes" }

iframe 收到后再次滚承运商区。需查价页与 cc-client 一起部署 才完整。

4.3 「继续」进入二级后置顶

用户在一级点「继续」进入提货/送货详情时:

  1. 查价页:iframe 内 scrollTo(0) + 根节点 scrollIntoView
  2. 同时向宿主发:
{
  "source": "chajia",
  "version": 1,
  "type": "chajia:scroll-top",
  "module": "MS_LOGGED_IN",
  "payload": { "reason": "logged-in-details" }
}
  1. 宿主:收到后将私卡询价弹窗/iframe 容器滚到视口顶部

需查价页与 cc-client 一并更新。


5. 联调顺序(ShipRo)

  1. iframe:...&embed=1&module=MS_LOGGED_IN
  2. 进「创建新货件」后点「填入数据」→ chajia:fill
  3. 收 fill-ack(缓存)→ 再收 ui_applied ack
  4. 用户点选地址联想 → 继续 → chajia:quote-result(出票)
  5. 用户在侧栏点选承运商 → 再收 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。