8.0 KiB
8.0 KiB
小程序订单 - 保险弹窗接口 + hotels/serviceItems 字段修复
- 日期: 2026-04-19
- PR:
- 类型: FEATURE + BUGFIX
- 状态: 已合并到 dev + 测试环境部署中
- 服务: hl-mp-service + hl-order-service-v2
一、接口变更清单
| # | 方法 | 路径 | 变更类型 | 影响位置 | 变更内容 |
|---|---|---|---|---|---|
| 1 | GET | /mp/order/{orderId}/insurance |
🟢 新增接口 | — | 保险详情弹窗 |
| 2 | GET | /mp/order/{orderId}/hotels |
🔴 出参修复 | data.items[].coverUrl |
已分配路径此前硬编码 null, 现从产品快照反查返回图片 URL |
| 3 | POST /mp/order/createGET /mp/order/{id}PUT /mp/order/{id}/edit |
🔴 出参字段值变化 | data.serviceItems[type=INSURANCE].clickable |
此前 INCLUDED 时返回 false, 现统一返回 true |
所有接口入参无变化。
二、接口详情
1. 🟢 新增: GET /mp/order/{orderId}/insurance
保险详情弹窗数据。
鉴权
- Header:
Authorization: Bearer {mp-token} - 订单必须属于当前用户, 否则返回
code=403
路径参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
orderId |
path | Long | 是 | 订单 ID |
Query 参数
无。
Request Body
无。
响应 Schema
{
code: number; // 200 成功 / 403 无权 / 404 订单不存在
message: string;
data: MpInsuranceDetailVO | null; // 订单无保险时为 null
success: boolean;
}
interface MpInsuranceDetailVO {
// ===== 方案基础信息 =====
schemeId: string; // 方案 ID (String 防 JS 大数丢精度)
schemeName: string; // 方案名
description: string | null; // 方案描述
isOverseas: boolean; // 境内/境外
totalDays: number; // 适用行程天数
notice: 'INCLUDED' | 'OPTIONAL'; // INCLUDED=必含, OPTIONAL=可选
// ===== 保障分段(方案配置, 与订单无关) =====
segments: CoverageSegment[];
// ===== 投保记录(订单付款后才有) =====
policies: PolicyItem[];
}
interface CoverageSegment {
segmentName: string; // 分段名 "低风险"/"高风险"
dayOffsetStart: number; // 起始天(1 起)
dayOffsetEnd: number; // 结束天(-1 表示最后一天)
productName: string; // 保险产品名
planName: string; // 保障计划名
}
interface PolicyItem {
insuranceOrderId: string; // 保险订单 ID (String, 用于下载单张保单)
policyNo: string; // 保单号
productName: string;
planName: string;
premium: number; // 保费(元)
insuredCount: number; // 被保人数
coverageStartDate: string; // 起保日 yyyy-MM-dd
coverageEndDate: string; // 截止日
status: 'PENDING' | 'INSURING' | 'INSURED' | 'FAILED'; // CANCELLED 不返回
statusLabel: string; // 状态中文
insuredPersons: InsuredPerson[];
}
interface InsuredPerson {
name: string; // 姓名
idCardType: 'ID_CARD' | 'PASSPORT';
idCardNo: string; // 证件号(后端已脱敏: 110***********1234)
birthday: string; // 生日 yyyy-MM-dd
gender: 'MALE' | 'FEMALE';
phone: string; // 手机号(后端已脱敏: 138****5678)
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"schemeId": "2028762847782060034",
"schemeName": "测试3日方案",
"description": null,
"isOverseas": false,
"totalDays": 3,
"notice": "INCLUDED",
"segments": [
{ "segmentName": "低风险", "dayOffsetStart": 1, "dayOffsetEnd": 2,
"productName": "山河令(太保山东新)", "planName": "10万计划" },
{ "segmentName": "高风险", "dayOffsetStart": 3, "dayOffsetEnd": 3,
"productName": "平安保游万里行马术专属保险(互联网)", "planName": "计划一" }
],
"policies": [
{
"insuranceOrderId": "9100000000001001",
"policyNo": "BY202604190001",
"productName": "山河令(太保山东新)",
"planName": "10万计划",
"premium": 50.00,
"insuredCount": 2,
"coverageStartDate": "2026-05-28",
"coverageEndDate": "2026-05-29",
"status": "INSURED",
"statusLabel": "已承保",
"insuredPersons": [
{ "name": "张三", "idCardType": "ID_CARD",
"idCardNo": "110***********2222", "birthday": "1990-01-01",
"gender": "MALE", "phone": "138****8001" },
{ "name": "李四", "idCardType": "ID_CARD",
"idCardNo": "110***********3333", "birthday": "1995-02-02",
"gender": "FEMALE", "phone": "138****8002" }
]
}
]
},
"success": true
}
几种特殊返回
| 场景 | 返回 |
|---|---|
| 订单不存在 | code=404, data=null, message="订单不存在" |
| 订单不属于当前用户 | code=403, data=null, message="无权查看此订单" |
订单未配保险 (insuranceNotice=EXCLUDED) 或无 INSURANCE 服务项 |
code=200, data=null |
| 订单配了保险但未付款 | code=200, data.policies=[] (只有方案+分段, 无保单) |
| 订单已付款, 正在投保中 | code=200, data.policies 含 status=PENDING 或 INSURING 的条目 |
| 一订单多保单 (分段投保 / 退保重保) | code=200, data.policies 返回多条, CANCELLED 已过滤不返回 |
| 方案在数据库被删 | code=200, data=null (兜底) |
2. 🔴 修复: GET /mp/order/{orderId}/hotels
变更位置
出参 data.items[].coverUrl
变更前
已分配路径 (订单已确认实际入住酒店时) 返回:
{
"items": [
{ "hotelId": "xxx", "hotelName": "某酒店", "coverUrl": null,
"assignmentDate": "2026-05-28", "roomType": "大床房", "hotelType": "HOTEL" }
]
}
变更后
{
"items": [
{ "hotelId": "xxx", "hotelName": "某酒店",
"coverUrl": "https://cdn.../hotel-cover.jpg",
"assignmentDate": "2026-05-28", "roomType": "大床房", "hotelType": "HOTEL" }
]
}
变更原因
订单分配表 order_hotel_assignment 不存 coverUrl, 此前硬编码 null. 现按 hotelId 从产品快照 hotels[] 里反查图片 URL. 未分配路径行为不变.
其他字段
无变化 (hotelId/hotelName/assignmentDate/roomType/hotelType 及同级 nightCount/roomTypeStats 均无改动)。
3. 🔴 字段值变化: serviceItems[type=INSURANCE].clickable
影响接口
POST /mp/order/create返回data.serviceItemsGET /mp/order/{orderId}返回data.serviceItemsPUT /mp/order/{orderId}/edit返回data.serviceItems
变更位置
data.serviceItems 数组中 type === 'INSURANCE' 的元素的 clickable 字段。
变更前
insuranceNotice |
clickable |
|---|---|
EXCLUDED |
条目不返回 |
INCLUDED (必含保险) |
false |
OPTIONAL (可选加保) |
true |
变更后
insuranceNotice |
clickable |
|---|---|
EXCLUDED |
条目不返回 (不变) |
INCLUDED |
true (与 OPTIONAL 统一) |
OPTIONAL |
true (不变) |
变更原因
新增了保险弹窗接口 /mp/order/{id}/insurance 后, INCLUDED 也有点击交互需求 (查看方案 + 保单列表), 不再需要前端禁用这个条目。
历史订单
在本次改动之前已下单的订单, order_service_item 表里固化的 clickable 仍是原值 (可能 false), 新下单的订单起是 true。如果需要批量修正历史数据, 可提 Issue 加补偿脚本。
三、不兼容变更
无。
- 新增接口: 老前端不调用不影响
- hotels
coverUrl: 从 null 变为有值, 前端原本 null 态处理代码仍然正确 clickable: 从 false 变为 true 只是让条目变可点, 旧代码不点它也不会出错