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

256 lines
9.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 查价系统 · 宿主 postMessage 对接说明
**版本**:1.1
**更新日期**:2026-07-24
**适用对象**:在 iframe 中嵌入查价页的宿主系统(如 ShipRo / 元子侧适配方)
**嵌入页**:`/embed-demo`(须先按 `嵌入对接文档.md` 完成 API Key 直登)
> 原则:**由查价系统定义「要填什么 / 查完回什么」**;宿主按本协议发 `postMessage` 预填、收结果。字段与程序内部询价结构对齐,宿主无需再猜哪些字段可用。
---
## 0. ShipRo 联调要点(v1.1)
### 0.1 URL 直进 MotherShip 登录后表单(方案 A)
```text
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. 总览
```text
宿主页面
└─ 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` | 用户或宿主切换了模块 |
信封统一格式:
```json
{
"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 通用写法
```js
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`
```json
{
"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)
```json
{
"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 仅切模块
```json
{ "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 发:
```json
{ "source": "chajia", "version": 1, "type": "chajia:scroll-quotes" }
```
iframe 收到后再次滚承运商区。需查价页与 cc-client **一起部署** 才完整。
### 4.3 「继续」进入二级后置顶
用户在一级点「继续」进入提货/送货详情时:
1. **查价页**:iframe 内 `scrollTo(0)` + 根节点 `scrollIntoView`
2. **同时**向宿主发:
```json
{
"source": "chajia",
"version": 1,
"type": "chajia:scroll-top",
"module": "MS_LOGGED_IN",
"payload": { "reason": "logged-in-details" }
}
```
3. **宿主**:收到后将私卡询价弹窗/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`。