一些检查失败了
changelog-filename-gate / validate (push) Failing after 2s
修改原因:hl-ui changelog loop 需要把前端消费进度回写到契约源,避免领取、实现状态与实际交付脱节。 修改内容:将 frontend_status 与已有 legacy frontend 同步为 implemented,记录负责人 hl-ui-codex,并关联 mmg/hl-ui@98c6f66843395b3b2d4bd1cd23cdc286e20b0bf9;发布和验收字段保持不变。 实际验证:回写器已校验目标文件、状态单调性、提交范围和 Front Matter 内容,提交只包含当前 changelog。 Frontend-Status: tools/mcp-api-sync/.changelog-repo/changelogs-v2/2026-07/24_5203_出行人手机号订单级门禁-修改接口-管理后台.md
35 KiB
35 KiB
schema, ticket, title, consumer, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 5203 | 出行人手机号改为订单级门禁 | admin | 修改接口 | deployed | verified | implemented | hl-ui-codex | mmg/hl-ui@98c6f66843 | 后端新语义已发布;前端需按逐人五项资料和订单级手机号门禁消费 | 2026-07-24T09:57:22.169Z | dev-v3 |
🔧【修改接口·管理后台】出行人手机号改为订单级门禁(#5203)
PR: #5210 服务:
hl-order-service-v3更新时间: 2026-07-24 影响范围: 订单详情、出行人维护/校验、确认订单前置检查与确认提交
1. 接口背景
出行人逐人资料状态与订单签约门禁原来使用了冲突口径:成人没有手机号时,逐人的
profileStatus 会是 PENDING;但确认订单只需要整单至少一名出行人提供手机号。
本次统一为两层规则:
- 逐人资料完整度只检查
name、gender、birthday、idType、idNo五项。 - 手机号是订单级门禁:整单至少一名出行人填写手机号,才允许校验通过、自动推进和确认行程。
手机号字段本身没有删除,所有请求和响应结构保持不变;变化的是
profileStatus、完成数统计、missingFields 和确认门禁的字段语义。
变更接口
| # | 接口 | 方法 | 路径 | 变更类型 | 本次变化 |
|---|---|---|---|---|---|
| 1 | 订单详情 | GET | /v3/admin/order/{id} |
出参语义修改 | overview.customerInfo.travelers[].profileStatus 改用逐人五项资料判断 |
| 2 | 出行人列表 | GET | /v3/admin/order/{id}/traveler/list |
出参语义修改 | profileStatus 改用逐人五项资料判断 |
| 3 | 批量编辑出行人 | POST | /v3/admin/order/{id}/traveler/batch-edit |
出参语义修改 | 完成数与 allCompleted 不再逐人要求手机号;自动推进仍要求整单至少一部手机号 |
| 4 | 单个新增出行人 | POST | /v3/admin/order/{id}/traveler/add |
出参语义修改 | 无手机号但五项资料齐全时返回 COMPLETED |
| 5 | 补全出行信息 | PUT | /v3/admin/order/{id}/traveler-info |
出参语义修改 | 完成数与 allCompleted 改用逐人五项资料判断;自动推进仍保留订单级手机号门禁 |
| 6 | 智能批量解析 | POST | /v3/admin/order/{id}/traveler/smart-parse |
出参语义修改 | 预览和入库结果的 profileStatus 改用逐人五项资料判断 |
| 7 | 出行人信息校验 | GET | /v3/admin/order/{id}/traveler/validate |
出参枚举语义修改 | missingFields 删除 phone,增加 gender、birthday;无任何手机号改由 blockReasons 表达 |
| 8 | 确认订单前置检查 | GET | /v3/admin/order/{id}/confirm-checklist |
出参语义修改 | TRAVELER_COMPLETE 先检查逐人五项,再检查整单至少一部手机号 |
| 9 | 确认行程 | POST | /v3/admin/order/{id}/confirm-itinerary |
行为修改 | 每人无须都有手机号;整单完全无手机号仍返回 581036 |
3. 接口详情
所有接口均使用管理后台 JWT。除批量编辑、单个新增、补全出行信息外,接口没有额外幂等窗口。 公共响应包装为:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
Integer | 200 表示成功;业务失败返回业务错误码 |
message |
String | 响应说明 |
data |
见各接口 | 业务数据;失败时通常为 null |
success |
Boolean | 是否成功 |
3.1 订单详情
- 方法/路径: GET
/v3/admin/order/{id} - 使用场景: 打开订单详情,读取主单、标签和概览中的出行人。
- 幂等性: 是,只读。
- 路径参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 订单 ID |
- 响应:
Result<OrderDetailRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
data.main |
OrderMainVO | 订单主单、进度和各 Tab 状态;本次字段结构未变 |
data.tags[] |
TagVO[] | 标签列表;每项含 name、color、creator |
data.overview.customerInfo |
CustomerInfoVO | 客户信息 |
data.overview.customerInfo.contactName |
String/null | 联系人 |
data.overview.customerInfo.contactPhone |
String/null | 联系电话 |
data.overview.customerInfo.agencyName |
String/null | 商户名 |
data.overview.customerInfo.consultantName |
String/null | 定制师姓名 |
data.overview.customerInfo.peopleSummary |
String/null | 人数摘要 |
data.overview.customerInfo.adultCount |
Integer | 成人数 |
data.overview.customerInfo.childCount |
Integer | 儿童数 |
data.overview.customerInfo.youngChildCount |
Integer | 小童数 |
data.overview.customerInfo.babyCount |
Integer | 幼童数 |
data.overview.customerInfo.createTime |
String/null | 创建时间,格式 yyyy-MM-ddTHH:mm:ss |
data.overview.customerInfo.emergencyContactName |
String/null | 订单紧急联系人姓名 |
data.overview.customerInfo.emergencyContactPhone |
String/null | 订单紧急联系人电话 |
data.overview.customerInfo.travelers[] |
TravelerPlainVO[] | 出行人列表;字段见下表 |
data.overview.remarkInfo.customerRemark |
String/null | 客户备注 |
data.overview.remarkInfo.consultantRemark |
String/null | 定制师备注 |
data.overview.remarkInfo.hotelRemark |
String/null | 用房备注 |
data.overview.remarkInfo.vehicleRemark |
String/null | 用车备注 |
data.unreadMessageCount |
Integer | 联系房务未读数;无会话或降级时为 0 |
TravelerPlainVO 完整字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
Long | 出行人 ID |
orderId |
Long | 订单 ID |
travelerType |
String | 出行人类型 |
travelerTypeName |
String/null | 出行人类型中文名 |
name |
String/null | 姓名 |
gender |
String/null | 性别 |
birthday |
String/null | 出生日期,yyyy-MM-dd |
idType |
String/null | 证件类型 |
idTypeName |
String/null | 证件类型中文名 |
idCard |
String/null | 证件号 |
nationality |
String/null | 国籍 |
race |
String/null | 民族 |
phone |
String/null | 出行人手机号 |
emergencyContact |
String/null | 紧急联系人姓名 |
emergencyPhone |
String/null | 紧急联系人电话 |
roomGroupNo |
Integer/null | 同住分组号 |
profileStatus |
String | PENDING / COMPLETED;本次语义见第 6 节 |
transportPlanIds[] |
Long[] | 关联大交通批次 ID |
- 错误码:
581007订单不存在;581045房务角色无权查看订单详情。 - 业务边界: 出行人没有手机号但五项资料齐全时,
profileStatus=COMPLETED。 - 典型示例:
请求
GET /v3/admin/order/2079576729147338754
Authorization: Bearer <admin-token>
响应
{
"code": 200,
"message": "success",
"data": {
"main": {
"id": "2079576729147338754",
"orderNo": "HL202607240001",
"orderStatus": "CUSTOMIZING",
"flowStatus": "AWAITING_CONFIRM"
},
"tags": [],
"overview": {
"customerInfo": {
"contactName": "张三",
"adultCount": 2,
"childCount": 0,
"youngChildCount": 0,
"babyCount": 0,
"travelers": [
{
"id": "2079576729147338801",
"name": "张三",
"gender": "1",
"birthday": "1990-01-01",
"idType": "ID_CARD",
"idCard": "110101199001011234",
"phone": "13800138000",
"profileStatus": "COMPLETED",
"transportPlanIds": []
},
{
"id": "2079576729147338802",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"idCard": "110101199202021235",
"phone": null,
"profileStatus": "COMPLETED",
"transportPlanIds": []
}
]
},
"remarkInfo": {
"customerRemark": null,
"consultantRemark": null,
"hotelRemark": null,
"vehicleRemark": null
}
},
"unreadMessageCount": 0
},
"success": true
}
3.2 出行人列表
- 方法/路径: GET
/v3/admin/order/{id}/traveler/list - 使用场景: 加载出行人 Tab。
- 幂等性: 是,只读。
- 路径参数:
id,Long,必填,订单 ID。 - 响应:
Result<List<TravelerVO>>
TravelerVO 完整字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id、orderId |
Long | 出行人 ID、订单 ID |
travelerType、travelerTypeName |
String/null | 出行人类型及中文名 |
name |
String/null | 姓名 |
gender |
String/null | 性别 |
birthday |
String/null | 出生日期 |
idType、idTypeName |
String/null | 证件类型及中文名 |
idCardMasked |
String/null | 脱敏证件号 |
idProvinceCode、idProvinceName |
String/null | 大陆身份证省级代码及名称 |
nationality、race |
String/null | 国籍、民族 |
phoneMasked |
String/null | 脱敏手机号 |
emergencyContact |
String/null | 紧急联系人姓名 |
emergencyPhoneMasked |
String/null | 脱敏紧急联系电话 |
roomGroupNo |
Integer/null | 同住分组号 |
profileStatus |
String | PENDING / COMPLETED |
transportPlanIds[] |
Long[] | 关联大交通批次 ID |
- 错误码:
581102订单不存在。 - 业务边界: 空列表返回
data=[];手机号为空不再单独令profileStatus变成PENDING。 - 典型示例:
请求
GET /v3/admin/order/2079576729147338754/traveler/list
Authorization: Bearer <admin-token>
响应
{
"code": 200,
"message": "success",
"data": [
{
"id": "2079576729147338802",
"orderId": "2079576729147338754",
"travelerType": "ADULT",
"travelerTypeName": "成人",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"idTypeName": "身份证",
"idCardMasked": "110***********1235",
"idProvinceCode": "11",
"idProvinceName": "北京市",
"nationality": "中国",
"race": "汉族",
"phoneMasked": null,
"emergencyContact": null,
"emergencyPhoneMasked": null,
"roomGroupNo": 1,
"profileStatus": "COMPLETED",
"transportPlanIds": []
}
],
"success": true
}
3.3 批量编辑出行人
- 方法/路径: POST
/v3/admin/order/{id}/traveler/batch-edit - 使用场景: 一次新增或更新最多 30 名出行人。
- 幂等性: 同一订单 3 秒内重复提交会被拒绝。
- 路径参数:
id,Long,必填,订单 ID。 - 请求体:
TravelerBatchEditReqVO
| 字段 | 类型 | 必填 | 约束 |
|---|---|---|---|
travelers |
TravelerEditItem[] | 是 | 1~30 项 |
travelers[].id |
Long/null | 否 | null 新增;非空更新且必须属于本订单 |
travelers[].name |
String/null | 条件必填 | 新增项 name/idType/idNo 至少一项非空 |
travelers[].gender |
String/null | 否 | 0 / 1 / 2 |
travelers[].birthday |
String | 是 | 不得晚于今天;用于派生人群类型 |
travelers[].idType |
String/null | 条件必填 | 取值见第 6 节 |
travelers[].idNo |
String/null | 条件必填 | 与证件类型匹配 |
travelers[].nationality |
String/null | 否 | 不可传空字符串 |
travelers[].race |
String/null | 否 | 不可传空字符串 |
travelers[].phone |
String/null | 否 | 有值时必须为 11 位数字 |
travelers[].emergencyContact |
String/null | 否 | 出行人级紧急联系人 |
travelers[].emergencyPhone |
String/null | 否 | 有值时必须为 11 位数字 |
travelers[].roomGroupNo |
Integer/null | 否 | 不得超过订单家庭数上限 |
- 响应:
Result<TravelerBatchEditRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
data.createdCount |
Integer | 本次新增数 |
data.updatedCount |
Integer | 本次更新数 |
data.completedCount |
Integer | 操作后五项资料完整的出行人数 |
data.pendingCount |
Integer | 操作后五项资料不完整的出行人数 |
data.allCompleted |
Boolean | 所有出行人的五项资料是否完整;不表示整单手机号门禁已通过 |
- 错误码:
581101、581102、581103、581104、581105、581110、581111、581112、581113、581114、581118、581119、581146、581147、581148、581149。 - 业务边界: 两人五项资料齐全且仅一人有手机号时,
completedCount=2、pendingCount=0、allCompleted=true,同时满足订单级手机号门禁。 - 典型示例:
请求
POST /v3/admin/order/2079576729147338754/traveler/batch-edit
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"travelers": [
{
"id": "2079576729147338801",
"name": "张三",
"gender": "1",
"birthday": "1990-01-01",
"idType": "ID_CARD",
"idNo": "110101199001011234",
"nationality": "中国",
"race": "汉族",
"phone": "13800138000",
"roomGroupNo": 1
},
{
"id": "2079576729147338802",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"idNo": "110101199202021235",
"nationality": "中国",
"race": "汉族",
"phone": null,
"roomGroupNo": 1
}
]
}
响应
{
"code": 200,
"message": "success",
"data": {
"createdCount": 0,
"updatedCount": 2,
"completedCount": 2,
"pendingCount": 0,
"allCompleted": true
},
"success": true
}
3.4 单个新增出行人
- 方法/路径: POST
/v3/admin/order/{id}/traveler/add - 使用场景: 在订单声明人数尚未补齐时新增一名出行人。
- 幂等性: 同一订单 3 秒内重复提交会被拒绝。
- 路径参数:
id,Long,必填,订单 ID。 - 请求体:
| 字段 | 类型 | 必填 | 约束 |
|---|---|---|---|
name |
String/null | 否 | 姓名 |
gender |
String/null | 否 | 0 / 1 / 2 |
birthday |
String | 是 | 不得晚于今天 |
idType |
String/null | 否 | 证件类型 |
idNo |
String/null | 否 | 证件号 |
nationality、race |
String/null | 否 | 默认中国、汉族 |
phone |
String/null | 否 | 有值时 11 位数字 |
emergencyContact、emergencyPhone |
String/null | 否 | 出行人级紧急联系人 |
roomGroupNo |
Integer/null | 否 | 同住分组号 |
- 响应:
Result<TravelerVO>,完整字段同 3.2。 - 错误码:
581102、581103、581104、581112、581113、581114、581115、581116、581119、581146、581147、581148、581149。 - 业务边界: 五项资料齐全、
phone=null时,新行可返回profileStatus=COMPLETED; 若订单其他出行人也都没有手机号,整单仍不能通过订单级门禁。 - 典型示例:
请求
POST /v3/admin/order/2079576729147338754/traveler/add
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"idNo": "110101199202021235",
"nationality": "中国",
"race": "汉族",
"phone": null,
"roomGroupNo": 1
}
响应
{
"code": 200,
"message": "success",
"data": {
"id": "2079576729147338802",
"orderId": "2079576729147338754",
"travelerType": "ADULT",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"idCardMasked": "110***********1235",
"phoneMasked": null,
"profileStatus": "COMPLETED",
"transportPlanIds": []
},
"success": true
}
3.5 补全出行信息
- 方法/路径: PUT
/v3/admin/order/{id}/traveler-info - 使用场景: 全量同步出行人,并保存订单级紧急联系人和客户备注。
- 幂等性: 同一订单 3 秒内重复提交会被拒绝。
- 路径参数:
id,Long,必填,订单 ID。 - 请求体:
| 字段 | 类型 | 必填 | 约束 |
|---|---|---|---|
travelers |
TravelerEditItem[] | 是 | 全量列表,1~30 项;单项字段同 3.3 |
emergencyContactName |
String | 是 | 订单级紧急联系人姓名 |
emergencyContactPhone |
String | 是 | 11 位数字 |
customerRemark |
String/null | 否 | 客户备注 |
- 响应:
| 字段 | 类型 | 说明 |
|---|---|---|
data.createdCount |
Integer | 新增数 |
data.updatedCount |
Integer | 更新数 |
data.deletedCount |
Integer | 原有但未出现在本次全量列表中的删除数 |
data.completedCount |
Integer | 五项资料完整人数 |
data.pendingCount |
Integer | 五项资料不完整人数 |
data.allCompleted |
Boolean | 所有人五项资料是否完整;不等同于手机号门禁通过 |
- 错误码:
581102、581103、581104、581109、581110、581111、581112、581113、581114、581118、581119、581146、581147、581148、581149。 - 业务边界:
travelers为全量数据;五项资料全部完整但整单没有任何出行人手机号时,allCompleted=true,但流程不会自动越过订单级手机号门禁。 - 典型示例:
请求
PUT /v3/admin/order/2079576729147338754/traveler-info
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"travelers": [
{
"id": "2079576729147338801",
"name": "张三",
"gender": "1",
"birthday": "1990-01-01",
"idType": "ID_CARD",
"idNo": "110101199001011234",
"phone": "13800138000"
},
{
"id": "2079576729147338802",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"idNo": "110101199202021235",
"phone": null
}
],
"emergencyContactName": "王五",
"emergencyContactPhone": "13900139000",
"customerRemark": null
}
响应
{
"code": 200,
"message": "success",
"data": {
"createdCount": 0,
"updatedCount": 2,
"deletedCount": 0,
"completedCount": 2,
"pendingCount": 0,
"allCompleted": true
},
"success": true
}
3.6 智能批量解析
- 方法/路径: POST
/v3/admin/order/{id}/traveler/smart-parse - 使用场景: 将多行“姓名、身份证、手机号”文本解析为出行人,可预览或直接保存。
- 幂等性/限流: 每名管理员每分钟最多 10 次;
dryRun=true只读。 - 请求体:
| 字段 | 类型 | 必填 | 约束 |
|---|---|---|---|
rawText |
String | 是 | 非空,最多 20000 字符 |
dryRun |
Boolean | 否 | 默认 false;true 仅预览 |
- 响应:
| 字段 | 类型 | 说明 |
|---|---|---|
data.successCount |
Integer | 成功解析行数 |
data.failCount |
Integer | 失败行数 |
data.successList[] |
TravelerVO[] | 成功结果,字段同 3.2;预览时 id 可为 null |
data.failures[].lineIndex |
Integer | 原文有效行序号,从 1 起 |
data.failures[].maskedSnippet |
String | 脱敏原文片段 |
data.failures[].reason |
String | 中文失败原因 |
- 错误码:
100501调用过于频繁;581102订单不存在;581131原文超长;581132原文为空或全行无法解析;581134当前订单状态不允许批量导入。 - 业务边界: 成功行五项资料齐全时,即使没有解析到手机号也返回
profileStatus=COMPLETED;整单手机号门禁仍在校验和确认阶段单独判断。 - 典型示例:
请求
POST /v3/admin/order/2079576729147338754/traveler/smart-parse
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"rawText": "李四 110101199202021235",
"dryRun": true
}
响应
{
"code": 200,
"message": "success",
"data": {
"successCount": 1,
"failCount": 0,
"successList": [
{
"id": null,
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "ID_CARD",
"phoneMasked": null,
"profileStatus": "COMPLETED"
}
],
"failures": []
},
"success": true
}
3.7 出行人信息校验
- 方法/路径: GET
/v3/admin/order/{id}/traveler/validate - 使用场景: 保存后检查人数、逐人五项资料和订单级手机号门禁。
- 幂等性: 是,只读。
- 路径参数:
id,Long,必填,订单 ID。 - 响应:
| 字段 | 类型 | 说明 |
|---|---|---|
data.passed |
Boolean | 人数一致、逐人五项完整且 blockReasons 为空时为 true |
data.declaredCount |
Integer | 订单声明总人数 |
data.actualCount |
Integer | 当前实际出行人数 |
data.countMismatch |
Boolean | 声明人数与实际人数是否不一致 |
data.incompleteList[] |
IncompleteTravelerVO[] | 五项资料不完整的出行人 |
data.incompleteList[].travelerId |
Long | 出行人 ID |
data.incompleteList[].name |
String/null | 脱敏姓名 |
data.incompleteList[].missingFields[] |
String[] | 只可能是 name/gender/birthday/idType/idNo |
data.blockReasons[] |
String[] | 订单级阻断原因;整单无手机号时包含固定文案 |
- 错误码:
581102订单不存在。 - 业务边界:
- 两人五项资料齐全,仅一人有手机号:
passed=true。 - 每人五项资料齐全,但所有人都无手机号:
incompleteList=[],blockReasons包含“至少需要一名出行人填写手机号用于合同签署”,passed=false。
- 两人五项资料齐全,仅一人有手机号:
- 典型示例:
请求
GET /v3/admin/order/2079576729147338754/traveler/validate
Authorization: Bearer <admin-token>
响应
{
"code": 200,
"message": "success",
"data": {
"passed": true,
"declaredCount": 2,
"actualCount": 2,
"countMismatch": false,
"incompleteList": [],
"blockReasons": []
},
"success": true
}
3.8 确认订单前置检查
- 方法/路径: GET
/v3/admin/order/{id}/confirm-checklist - 使用场景: 打开确认订单弹框前检查五项门禁。
- 幂等性: 是,只读。
- 路径参数:
id,Long,必填,订单 ID。 - 响应:
| 字段 | 类型 | 说明 |
|---|---|---|
data.allPassed |
Boolean | 五项是否全部通过 |
data.items[] |
ChecklistItemVO[]/null | 未全部通过时返回;全部通过时为 null |
data.items[].code |
String | 检查项代码 |
data.items[].checkName |
String | 中文名称 |
data.items[].passed |
Boolean | 是否通过 |
data.items[].failReason |
String/null | 失败原因 |
data.preview |
PreviewVO/null | 全部通过时返回;未通过时为 null |
data.preview.departureDate |
String/null | 出发日期 |
data.preview.totalPeopleCount |
Integer | 总人数 |
data.preview.driverName |
String/null | 司机姓名 |
data.preview.driverPhoneMasked |
String/null | 脱敏司机手机号 |
data.preview.hotels[] |
HotelSummaryVO[] | 酒店摘要,含 cityName、hotelName |
data.preview.staffs[] |
StaffItemVO[] | 人员摘要 |
data.preview.staffs[].assignmentId |
String | 分配记录 ID |
data.preview.staffs[].staffId |
String | 员工 ID |
data.preview.staffs[].staffName |
String/null | 员工姓名 |
data.preview.staffs[].staffPhone |
String/null | 脱敏手机号 |
data.preview.staffs[].staffRole |
String | 人员角色 |
data.preview.staffs[].staffRoleName |
String/null | 角色中文名 |
data.preview.staffs[].isPrimaryReporter |
Boolean | 是否主报账人 |
data.preview.contractAutoAction |
Object/null | 合同动作,含 planName、autoSign |
data.preview.insuranceAutoAction |
Object/null | 保险动作,含 planName、peopleCount、effectiveDescription |
- 错误码:
581007订单不存在;581045房务角色无权查看。 - 业务边界:
TRAVELER_COMPLETE通过必须同时满足: 所有出行人的五项资料均完整,且整单至少一人有手机号。 - 典型示例:
请求
GET /v3/admin/order/2079576729147338754/confirm-checklist
Authorization: Bearer <admin-token>
响应
{
"code": 200,
"message": "success",
"data": {
"allPassed": false,
"items": [
{
"code": "PAYMENT_OK",
"checkName": "订单款项",
"passed": true,
"failReason": null
},
{
"code": "TRAVELER_COMPLETE",
"checkName": "出行人信息",
"passed": false,
"failReason": "至少需要一名出行人填写手机号用于合同签署"
}
],
"preview": null
},
"success": true
}
3.9 确认行程
- 方法/路径: POST
/v3/admin/order/{id}/confirm-itinerary - 使用场景: 五项 checklist 全部通过后确认行程。
- 幂等性: 状态机约束;成功后重复确认会因状态不匹配失败。
- 路径参数:
id,Long,必填,订单 ID。 - 请求体: 可不传。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
reporterAssignmentId |
Long/null | 否 | 新主报账人 assignmentId;不传沿用当前主报账人 |
- 响应:
| 字段 | 类型 | 说明 |
|---|---|---|
data.success |
Boolean | 是否成功 |
data.oldStatus |
String | 变更前粗状态 |
data.newStatus |
String | 变更后粗状态 |
data.oldFlowStatus |
String | 变更前细状态 |
data.newFlowStatus |
String | 变更后细状态 |
data.triggeredEvents[] |
String[] | 触发的后续事件代码 |
- 错误码:
581007订单不存在;581009状态不允许;581036前置 checklist 未通过;581045房务角色无权查看;581046主报账人 ID 格式非法。 - 业务边界: 多名出行人不要求每人都有手机号;整单完全没有手机号时,
TRAVELER_COMPLETE不通过,本接口返回581036。 - 典型示例:
请求
POST /v3/admin/order/2079576729147338754/confirm-itinerary
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"reporterAssignmentId": "2072930844657283074"
}
响应
{
"code": 200,
"message": "success",
"data": {
"success": true,
"oldStatus": "CUSTOMIZING",
"newStatus": "PENDING_DEPARTURE",
"oldFlowStatus": "AWAITING_CONFIRM",
"newFlowStatus": "PENDING_DEPARTURE",
"triggeredEvents": [
"ASYNC_CONTRACT_GENERATE",
"ASYNC_INSURANCE_ISSUE"
]
},
"success": true
}
4. 接口入参汇总
本次没有新增、删除或改名请求字段。需要注意:
phone仍可在批量编辑、单个新增、补全出行信息和智能解析中提交。phone允许单人为空,但整单至少一人必须填写。gender、birthday原本已存在;本次只将二者纳入逐人资料完整度。- 批量编辑和补全出行信息的
allCompleted只代表逐人五项资料,不代表订单级手机号门禁。
5. 出参汇总
| 字段 | 改前 | 改后 |
|---|---|---|
profileStatus |
成人通常还需手机号才为 COMPLETED |
五项资料齐全即为 COMPLETED,与手机号无关 |
completedCount / pendingCount |
受逐人手机号影响 | 只按逐人五项资料统计 |
allCompleted |
可能因某个成人没手机号为 false |
只表示所有人五项资料完整 |
incompleteList[].missingFields[] |
name/idType/idNo/phone |
name/gender/birthday/idType/idNo |
blockReasons[] |
手机号与逐人缺失字段存在语义重叠 | 整单无手机号时统一返回固定订单级阻断原因 |
checklist TRAVELER_COMPLETE |
逐人状态可能要求成人各自有手机号 | 所有人五项完整,并且整单至少一人有手机号 |
6. 枚举 / 数据字典
6.1 profileStatus
| 值 | 中文 | 判定 |
|---|---|---|
PENDING |
待完善 | name/gender/birthday/idType/idNo 任一为空 |
COMPLETED |
已完善 | 上述五项全部非空;不检查该出行人的手机号 |
6.2 missingFields
| 值 | 中文 | 说明 |
|---|---|---|
name |
姓名 | 姓名为空 |
gender |
性别 | 性别为空;本次新增为缺失项 |
birthday |
出生日期 | 出生日期为空;本次新增为缺失项 |
idType |
证件类型 | 证件类型为空 |
idNo |
证件号 | 证件号为空 |
phone 已从此列表删除,改由订单级 blockReasons 表达。
6.3 gender
| 值 | 中文 | 说明 |
|---|---|---|
0 |
未知 | 有值,满足逐人完整度 |
1 |
男 | 有值,满足逐人完整度 |
2 |
女 | 有值,满足逐人完整度 |
6.4 travelerType
| 值 | 中文 |
|---|---|
ADULT |
成人 |
CHILD |
儿童 |
YOUNG_CHILD |
小童 |
BABY |
幼童 |
6.5 idType
| 值 | 中文 |
|---|---|
ID_CARD |
身份证 |
PASSPORT |
护照 |
HK_MACAU_PASS |
港澳通行证 |
TAIWAN_PASS |
台湾通行证 |
HONGKONG_RESIDENT_PASS |
回乡证 |
MILITARY_ID |
军官证 |
OTHER |
其他 |
6.6 checklist code
| 值 | 中文 |
|---|---|
PAYMENT_OK |
订单款项 |
TRAVELER_COMPLETE |
出行人信息 |
HOTEL_DONE |
用房准备 |
VEHICLE_DONE |
用车准备 |
CONTRACT_TEMPLATE_OK |
合同方案 |
7. 错误码
本次没有新增错误码。与本次语义直接相关的错误:
| code | 含义 | 触发场景 |
|---|---|---|
581036 |
确认订单前置校验未通过,请先补全所有必填项 | 确认行程时整单无手机号,或其他 checklist 项未通过 |
581102 |
订单不存在,无法编辑出行人 | 出行人查询、编辑或校验的订单不存在 |
581103 |
性别编码不合法 | gender 不是 0/1/2 |
581112 |
证件号格式不合法 | idType 与 idNo 不匹配 |
581113 |
手机号格式非法 | 非空手机号不是 11 位数字 |
581114 |
出生日期不能晚于今天 | birthday 为未来日期 |
581119 |
出行人证件号重复 | 同订单出现重复证件号 |
581149 |
出行人类型人数超出订单配置 | 按生日派生的人群类型超过订单声明配额 |
固定订单级阻断文案为:
至少需要一名出行人填写手机号用于合同签署
8. 示例
8.1 典型成功:两名成人仅一人有手机号
前置数据:两人五项资料均完整,第一人有手机号,第二人没有手机号。
{
"profileStatuses": [
"COMPLETED",
"COMPLETED"
],
"validate": {
"passed": true,
"incompleteList": [],
"blockReasons": []
},
"checklistTravelerComplete": {
"passed": true,
"failReason": null
}
}
8.2 边界:五项完整但整单无手机号
{
"profileStatuses": [
"COMPLETED",
"COMPLETED"
],
"validate": {
"passed": false,
"incompleteList": [],
"blockReasons": [
"至少需要一名出行人填写手机号用于合同签署"
]
},
"checklistTravelerComplete": {
"passed": false,
"failReason": "至少需要一名出行人填写手机号用于合同签署"
}
}
8.3 异常:缺性别并确认行程
先调用校验接口:
{
"code": 200,
"message": "success",
"data": {
"passed": false,
"declaredCount": 1,
"actualCount": 1,
"countMismatch": false,
"incompleteList": [
{
"travelerId": "2079576729147338801",
"name": "张*",
"missingFields": [
"gender"
]
}
],
"blockReasons": []
},
"success": true
}
继续提交确认行程会失败:
{
"code": 581036,
"message": "确认订单前置校验未通过,请先补全所有必填项",
"data": null,
"success": false
}
9. 业务边界
- 逐人五项资料是:姓名、性别、出生日期、证件类型、证件号。
- 手机号不属于逐人
missingFields,不影响单人的profileStatus。 gender=0是有效枚举值,不等于字段缺失;gender=null或空值才缺失。- 订单至少需要一名出行人有手机号;可以不是每名成人都有手机号。
allCompleted=true只说明五项资料完整。需要判断订单能否确认时,应读取traveler/validate的passed/blockReasons或confirm-checklist的allPassed/items。- 确认行程仍会服务端复检,不能仅凭前端本地判断绕过。
10. 修改前后对比
10.1 字段级
| 字段 | 修改前 | 修改后 |
|---|---|---|
missingFields 可选值 |
name/idType/idNo/phone |
name/gender/birthday/idType/idNo |
blockReasons 手机号语义 |
与逐人 phone 缺失可能重叠 |
统一表达整单手机号门禁 |
10.2 行为级
| 场景 | 修改前 | 修改后 |
|---|---|---|
| 成人五项完整、本人无手机号、同行人有手机号 | 本人可能为 PENDING |
本人为 COMPLETED,整单可通过 |
| 五项完整、整单无手机号 | 逐人状态与订单门禁混在一起 | 每人可 COMPLETED,但校验与确认被订单级门禁阻断 |
| 只缺性别或出生日期 | 可能不进入 missingFields |
精确返回 gender 或 birthday |
11. 影响评估 / 回滚
- 是否破坏向后兼容: 字段名、类型和层级不变,但枚举集合与字段语义变化;依赖旧
missingFields=phone或自行按“每人必须有手机号”判断的前端逻辑需要调整。 - 前端是否必须同步上线: 是。应删除逐人手机号必填对
profileStatus的本地推断, 并使用blockReasons/ checklist 表达订单级阻断。 - 回滚影响: 若接口语义回滚,旧逻辑会再次把部分无手机号成人标为
PENDING; 前端不应在本地固化任一后端历史口径。
12. 注意事项
- 不要用“手机号输入框是否为空”自行重算
profileStatus。 - 不要再判断
missingFields是否包含phone;该值已从允许集合删除。 allCompleted=true不等于可确认订单;确认按钮的权威结果是confirm-checklist.allPassed。- 手机号格式校验仍存在:非空时必须是 11 位数字。
GET order detail的出行人字段与GET traveler/list的敏感字段展示口径不同, 但两者的profileStatus语义完全一致。
验证证据
- 两名成人五项资料齐全、仅一人有手机号:两行均为
COMPLETED,校验通过。 - 成人五项资料齐全且本人无手机号:订单详情、列表、智能解析均返回
COMPLETED。 - 所有人均无手机号:逐人状态仍为
COMPLETED,校验返回订单级阻断原因,确认行程返回581036。 - 只缺
gender或只缺birthday:逐人状态为PENDING,missingFields精确返回对应字段。 - PR 验证结果:Order + MP 聚焦测试 165 个通过;全量 Reactor 8420 个测试通过;本次增量行与分支覆盖率均为 100%。