比较提交

...
作者 SHA1 备注 提交日期
API Changelog Bot 301a05d5cb docs: 记录草原指南视频文件夹选择修复 2026-07-15 12:08:36 +08:00
wx 255427ca51 Merge pull request 'docs: 草原指南素材分类树选择器接口说明' (#8) from docs/4999-grassland-material-descendants into main 2026-07-15 11:27:20 +08:00
API Changelog Bot 686a38cd2c docs: 记录草原指南素材分类树选择器 2026-07-15 11:26:46 +08:00
yaosutu c7e99515de 新增订单详情推送记录接口前端变更说明 2026-07-15 10:47:12 +08:00
API Changelog Bot 2b37f6124b docs(house): 补充房务全量复测与前端接入总览 2026-07-14 23:58:36 +08:00
API Changelog Bot 5954565ec5 docs(草原指南): 通知正式环境发布完成 2026-07-14 18:27:25 +08:00
API Changelog Bot ce13244c9e docs(草原指南): 补充操作人姓名TEST证据 2026-07-14 16:01:54 +08:00
API Changelog Bot 07dac023cf docs(草原指南): 告知操作人名称展示规则 2026-07-14 15:49:31 +08:00
API Changelog Bot 7dd6fc52c6 docs: 补充草原指南操作记录TEST验收 2026-07-14 15:08:11 +08:00
API Changelog Bot a43f11f767 docs: 告知草原指南字段级操作记录接口 2026-07-14 14:44:47 +08:00
API Changelog Bot 13c0027073 docs: 回填草原指南删除新规则 TEST 验收 2026-07-14 10:19:52 +08:00
API Changelog Bot dbc1737725 docs: 纠正草原指南删除规则 2026-07-14 09:57:24 +08:00
API Changelog Bot 6e96521aa7 docs: 回填草原指南 TEST 验收结果 2026-07-13 22:31:33 +08:00
API Changelog Bot 8f2f40c670 docs: 独立说明草原指南视频上传校验 2026-07-13 20:17:11 +08:00
API Changelog Bot 87c8da5c27 docs: 更新草原指南删除接口 dev 状态 2026-07-13 19:15:00 +08:00
API Changelog Bot 8ff0f5accc docs: 告知前端草原指南删除接口 2026-07-13 19:12:38 +08:00
API Changelog Bot 97e4adfdfe docs(api): 记录草原指南 dev-v3 复验结果 2026-07-13 17:13:00 +08:00
API Changelog Bot b3a59759a6 docs(api): 补充草原指南产品绑定与登录鉴权 2026-07-13 16:31:24 +08:00
API Changelog Bot 5b1659a048 docs: 补充新建订单单房差算价口径 2026-07-13 15:32:59 +08:00
API Changelog Bot 3888c46f94 docs: 告知新建订单按日期调用产品报价 2026-07-13 15:22:10 +08:00
API Changelog Bot 0a082cd3bb docs: 删除草原指南无用出品角标字段 2026-07-13 14:03:48 +08:00
yaosutu 61f23b9190 新增确认订单checklist删除actionPath变更说明 2026-07-13 11:00:04 +08:00
yaosutu 20d782c02b 补充确认订单预览提交接口 changelog 2026-07-13 10:16:49 +08:00
API Changelog Bot b651f41f67 docs: 明确草原指南OSS点播与默认域名方案 2026-07-13 09:20:44 +08:00
API Changelog Bot b89cb95b3b docs(house): 补齐4907三页面前端验收要求 2026-07-13 09:03:00 +08:00
API Changelog Bot 3de756a5f3 docs(house): 补齐4907前端返工待办交接 2026-07-12 22:11:44 +08:00
API Changelog Bot 0dc29ef073 docs: 补充草原指南必填契约收尾 2026-07-12 18:36:19 +08:00
API Changelog Bot bc82060cab docs: 补充草原指南4K验收与正式部署说明 2026-07-12 18:22:27 +08:00
API Changelog Bot ccbe202637 docs(fleet): 补齐4882派单看板契约与验收证据 2026-07-12 17:29:01 +08:00
API Changelog Bot 77ba6986b1 docs(house): 明确返工标签与配房晚次调整交接 2026-07-12 16:59:02 +08:00
API Changelog Bot edcf5a27ca docs: 更新草原指南自动推荐分页契约 2026-07-12 15:50:13 +08:00
API Changelog Bot 6ed33870b9 docs: 更新草原指南 OSS 前端契约 2026-07-12 14:50:57 +08:00
API Changelog Bot 1df4ac1a01 docs(house): 通知前端接入单条配房晚次调整 2026-07-12 14:18:14 +08:00
API Changelog Bot 6d40278133 docs(草原指南): 清理交接文档格式 (#4914) 2026-07-12 12:55:53 +08:00
API Changelog Bot 0ab6e12bbb docs(草原指南): 补充管理端与小程序接口交接 (#4914) 2026-07-12 12:55:26 +08:00
API Changelog Bot 7724cc0d3a docs: 更新订单改期配房平移与库存契约 2026-07-12 02:52:40 +08:00
API Changelog Bot d9d9026194 docs: 通知前端订单调整房务复核闭环 2026-07-11 22:27:02 +08:00
yaosutu 037748dcd2 推送调整订单出行人tab紧急联系人接口通知 2026-07-11 17:42:28 +08:00
API Changelog Bot 1f77becb70 docs: 通知前端接入酒店支付方式与询房话术 2026-07-10 18:27:10 +08:00
yaosutu 318917e6cf 新增线下收款代收人接口变更说明 2026-07-10 16:37:52 +08:00
yaosutu 5aad9d2ed3 补充核单Step3合并辅助结算变更通知 2026-07-10 16:18:35 +08:00
API Changelog Bot 54d03ac956 docs(fleet): 补充卡片定制师条件渲染问题 2026-07-10 12:03:40 +08:00
API Changelog Bot 63b70a9aec docs(fleet): 发布团号与定制师下拉对接契约 2026-07-10 11:30:13 +08:00
API Changelog Bot ed32d5bfc8 docs: add fleet demand dispatch contract 2026-07-09 17:40:40 +08:00
yaosutu 96797a8e93 新增确认行程专用接口变更说明 2026-07-09 14:26:41 +08:00
API Changelog Bot b91e01f563 docs: add vehicle special demand dict contract 2026-07-09 10:25:57 +08:00
API Changelog Bot aea6b4091d docs: 同步订单用车座位校验收口 2026-07-08 21:36:06 +08:00
API Changelog Bot f2c9864c02 docs: 补充4856测试服验证结果 2026-07-08 18:20:10 +08:00
API Changelog Bot f3b433a034 docs: 订单用车座位数按车型型号下拉 2026-07-08 18:12:52 +08:00
API Changelog Bot 236f2517bd docs(fleet): add vehicle type readonly contract handoff 2026-07-08 17:15:35 +08:00
API Changelog Bot 03d3a05116 docs(house): add order timeline and empty history handoff 2026-07-08 15:58:27 +08:00
API Changelog Bot 0c5c848630 docs(fleet): 补充派单看板日期筛选验证 2026-07-08 15:40:45 +08:00
API Changelog Bot 2a878856b8 docs(fleet): 派单看板筛选参数兼容说明 2026-07-08 15:26:44 +08:00
API Changelog Bot fd0296c10f docs(resource): add unlimited stock test evidence 2026-07-08 14:08:12 +08:00
API Changelog Bot 9bbf8efddb docs(resource): add unlimited stock api changelog 2026-07-08 14:01:49 +08:00
API Changelog Bot fb963d2133 docs: add fleet daily assignment contract 2026-07-08 13:27:53 +08:00
API Changelog Bot 31b047daf9 docs(house): 修正月度对账明细实际花销口径 2026-07-08 11:27:06 +08:00
API Changelog Bot c7aec1217b docs: add fleet chat vehicle requirement contract 2026-07-08 10:33:47 +08:00
API Changelog Bot 09e2753f5b docs: add house reconciliation actual expense changelog 2026-07-08 08:44:36 +08:00
API Changelog Bot eaa784994d docs(frontend): add house ledger order detail contract 2026-07-07 18:18:25 +08:00
yaosutu 1815d4008f 新增:定制师订单待办 7 个管理端接口(PR #4805/#4814/#4819) 2026-07-07 18:16:13 +08:00
yaosutu 83cbc282aa 推送 4 条核单侧改造接口变更 changelog(PR1 线下收款 / PR2 子表扩列 / PR3 recon+payout / PR5 submit收口) 2026-07-07 18:00:42 +08:00
API Changelog Bot 532afb1c97 docs(house): update ledger export and lead handoff 2026-07-07 16:58:00 +08:00
API Changelog Bot 88d4cd5a8a docs(house): notify ledger summary table UI 2026-07-07 15:24:42 +08:00
API Changelog Bot d3568c4ec1 docs(house): notify candidate available display fix 2026-07-07 14:55:51 +08:00
API Changelog Bot 92549d7697 docs(house): notify reject button visibility fix 2026-07-07 14:15:13 +08:00
API Changelog Bot cbc05a9650 docs(house): clarify reject disabled when assignments exist 2026-07-07 13:22:12 +08:00
API Changelog Bot ab87358753 docs: 同步房务库存当前可用房口径 2026-07-07 12:32:40 +08:00
API Changelog Bot df0179375f docs: 补充房务按天清空配房契约 2026-07-07 11:13:33 +08:00
API Changelog Bot be4f1ddd78 docs: 告知前端修正房务价格同步误弹 2026-07-07 10:32:54 +08:00
API Changelog Bot 6f1945966e docs: 修正房务旧需求同屏展示口径 2026-07-07 09:54:52 +08:00
API Changelog Bot 162c0ca6d8 docs: add hl-ui fleet api mismatch notice 2026-07-07 09:52:13 +08:00
API Changelog Bot 0bd37e49aa docs: 告知前端展示房务驳回历史需求 2026-07-07 09:44:24 +08:00
API Changelog Bot e559045701 docs: add fleet protocol price changelog 2026-07-06 22:29:58 +08:00
API Changelog Bot 946290b259 docs: notify frontend for house inventory switch 2026-07-06 19:40:25 +08:00
API Changelog Bot 93b4742dd7 docs(fleet): notify view detail processing contract 2026-07-06 18:10:43 +08:00
API Changelog Bot bc0ae2c3f8 docs: notify house assignment price snapshot contract 2026-07-06 17:59:43 +08:00
API Changelog Bot 32374f6be7 docs(api): link resource migration fix pr 2026-07-06 17:31:26 +08:00
API Changelog Bot 2a01ff4c79 docs: 告知前端房务清空配房动作契约 2026-07-06 16:46:58 +08:00
API Changelog Bot 146576f3b3 docs(fleet): notify frontend for vehicle requirement reject 2026-07-06 16:32:59 +08:00
API Changelog Bot 7515b06fd9 docs: 房务驳回住宿需求前端通知 2026-07-06 16:02:40 +08:00
API Changelog Bot d1b8a3ef15 docs(api): link resource settle default fix pr 2026-07-06 15:08:40 +08:00
API Changelog Bot 849c4987dd docs(api): note resource settle type default 2026-07-06 15:06:10 +08:00
API Changelog Bot 67e50e3d1e docs(house): 补充修改需求后房务操作按钮缺失 2026-07-06 14:15:30 +08:00
API Changelog Bot 6257f89d90 docs: notify fleet frontend v2.1 integration gaps 2026-07-06 14:00:04 +08:00
API Changelog Bot 42a6367528 docs: update fleet API handoff examples 2026-07-06 12:16:45 +08:00
API Changelog Bot 15f43e9cf9 docs(order): 补充已配房修改需求入口前端根因 2026-07-06 11:50:58 +08:00
API Changelog Bot c46f388641 docs: clarify fleet frontend contracts 2026-07-06 10:40:45 +08:00
API Changelog Bot 31e2bc4fec docs: add fleet insurance API handoff 2026-07-06 09:32:59 +08:00
API Changelog Bot 68627376f1 docs(fleet): expand api handoff examples 2026-07-05 20:52:22 +08:00
API Changelog Bot ed8448c625 docs(fleet): add menu api validation handoff 2026-07-05 20:35:20 +08:00
API Changelog Bot bddb222604 docs(fleet): matrix dispatch contract stats 2026-07-05 17:46:42 +08:00
API Changelog Bot e11300080b docs: add fleet detail context changelog 2026-07-05 16:34:31 +08:00
API Changelog Bot d9ecc04a93 docs(fleet): clarify vehicle model dropdown contracts 2026-07-05 15:59:14 +08:00
API Changelog Bot 6d6ee1ced1 docs(house): align assignment pricing with resource settlement 2026-07-05 15:26:25 +08:00
API Changelog Bot 98094ec861 docs(api): notify resource settlement fields 2026-07-05 15:04:31 +08:00
API Changelog Bot 9e5b45e7a5 docs(vehicle): notify frontend add requirement button 2026-07-05 14:56:46 +08:00
API Changelog Bot 53b8c8b115 docs(house): keep requirement edit entry in all house stages 2026-07-05 14:44:52 +08:00
API Changelog Bot 7d96056258 docs(house): clarify requirement edit after hotel finalized 2026-07-05 14:43:23 +08:00
API Changelog Bot ed801356d9 docs(house): notify frontend todo timeout tags 2026-07-05 14:36:37 +08:00
API Changelog Bot 81914a2244 docs: 通知前端房务已确认后仍可直接修改 2026-07-03 14:43:18 +08:00
API Changelog Bot dd53a9131c docs: 通知前端取消已完成配房需求ID拦截 2026-07-03 14:25:17 +08:00
API Changelog Bot 0458bbaa31 docs: 通知前端已配房后补回修改需求入口 2026-07-03 14:22:52 +08:00
API Changelog Bot 4cf844e182 docs: 通知前端订单详情定制师聊天红点刷新问题 2026-07-03 14:17:19 +08:00
API Changelog Bot 57d49a7210 docs(frontend): clarify house todo reason tags are additive 2026-07-03 11:02:24 +08:00
API Changelog Bot fab5a63922 docs(frontend): notify house todo unread tag issue 2026-07-03 10:58:32 +08:00
API Changelog Bot 7e9f743fe5 docs: notify frontend about house inquiry clipboard issue 2026-07-03 10:54:35 +08:00
API Changelog Bot 573ff6e2e3 docs(changelog-v2): 通知配房需求字段非必填 2026-07-03 10:03:41 +08:00
API Changelog Bot d13fe33798 docs: notify frontend house inquiry copy failure 2026-07-03 09:51:05 +08:00
API Changelog Bot e0cefb1c07 changelog: 房务回配状态价格推荐标识待办超时 2026-07-02 16:53:04 +08:00
yaosutu f1d36b8522 docs(changelog-v2): 签单 sign-voucher 金额改取协议成本价修改接口通知
GET /v3/admin/order/{id}/sign-voucher 出参 unitPrice/amount/totalAmount 取值来源
从客户成交价(sell_price)改为协议成本价(景点 node.unit_price / 酒店 house.proto_price),
字段名与结构不变。关联 HL #4722 / PR #4724。
2026-07-02 14:51:07 +08:00
API Changelog Bot c765f2b285 changelog: 房务待处理排除最终确认单 2026-07-02 14:27:50 +08:00
yaosutu 55944610fb docs(changelog-v2): 签单 sign-voucher 移除服务/接送预订单修改接口通知
GET /v3/admin/order/{id}/sign-voucher 出参 entries 不再返回 type=SERVICE 的
服务/接送预订通知单,只保留 HOTEL 酒店 + SCENIC 景点两类。关联 HL #4715 / PR #4716。
2026-07-02 11:50:18 +08:00
API Changelog Bot f4999c9848 docs: notify frontend house calendar excludes grab pool 2026-07-02 11:28:18 +08:00
API Changelog Bot 39988e5380 changelog: 订单详情住宿已回配展示条件修正说明 2026-07-02 11:08:04 +08:00
API Changelog Bot fe28a296e9 changelog: 订单详情联系房务按钮补未读红点说明 2026-07-02 11:00:47 +08:00
API Changelog Bot 129c8eafd9 changelog: 房务抢单池详情弹窗新增抢单按钮接入说明 2026-07-02 10:24:57 +08:00
API Changelog Bot da656908cc changelog: #4677 房务首页待办卡片化+即将入住过滤 (PR #4710) 2026-07-01 18:12:08 +08:00
API Changelog Bot 5d65d2c241 docs(changelog-v2): 房务订单详情新增 canReopen 标志,前端停用回配启发式 (#4706)
后端 PR #4707 修 bug.docx「未最终确认却显示回配」:GET /admin/house/orders/{orderId}
的 data.actions 新增 canReopen(enabled 仅当 house_status=CONFIRMED 且本人持有),
前端「回配」按钮改读 actions.canReopen.enabled,停用基于共享 PROCESSING/CLAIMING 列的
启发式。附带告知同批红点/待办后端修复(前端无需改)。已测试服 API 实测。
2026-07-01 17:03:56 +08:00
yaosutu f9634974c8 docs(changelog-v2): 电子行程单 documentType 三取值改名(消除撞名)修改接口通知
GET /v3/admin/order/{id}/itinerary-document 的 documentType 三取值改名:
ITINERARY_C→CUSTOMER / ITINERARY_PRINT→CUSTOMER_PRINT / SIGNING→CUSTOMER_QUOTE。
业务零变动,出参结构不变,仅入参枚举值改名。关联 HL #4675 / PR #4705。
2026-07-01 17:00:02 +08:00
yaosutu 50c1cb9b20 docs(changelog): 打印行程单注意事项改用订单服务标准 + 交接清单对齐原型(Issue #4700/#4702,PR #4701/#4703)
notices 由三档 NoticeGroupVO[] 改服务标准服务承诺条目平铺 NoticeItem[] + 新增 noticesIntro;handoverChecklist 文案对齐原型。破坏性,管理后台前端须同步。
2026-07-01 16:43:44 +08:00
API Changelog Bot cde332a840 docs(changelog): 车务看板列表红点已落地去待定(PR #4698/#4695)——BoardOrderRecordVO +orderId +unreadMessageCount
原 02_4689 §订单列表红点 标注「待定(端点待确认)」,现确认=派单看板 /admin/fleet/board/orders,
照房务 grab-pool 服务端注入 unreadMessageCount + 数字 orderId(前端开会话/红点用),已合并部署实测。
2026-07-01 15:17:14 +08:00
yaosutu 0e32011617 docs(changelog): 打印行程单费用块收敛(Issue #4696,PR #4697)
顶层删 orderAmount/payableTotal/outstandingBalance 移入 feeDetail;feeDetail 补优惠/附加费/已付;报价分价改可空(feeDetail 恒返回)。破坏性,管理后台前端须同步。
2026-07-01 15:10:00 +08:00
yaosutu 985240047c docs(changelog): 打印行程单出参二次调整(Issue #4691,PR #4692)
去 printTime / dateRange 拆 departDate+returnDate / 顶层补订单号+订单总额+应收总额+应收尾款 / 餐食三布尔改 meals 数组 / 节点加 serviceStandard。多处破坏性,管理后台前端须同步。
2026-07-01 14:38:23 +08:00
API Changelog Bot 53e36e9fdf docs(changelog): 车务订单聊天(定制师↔车务团队,FLEET:{orderId})新接口 open-fleet + 车管控制台接入(#4689/PR#4690) 2026-07-01 12:11:40 +08:00
yaosutu 7d68720e9b docs(changelog): 打印行程单出参增强 changelog(Issue #4682,PR #4683)
notices 改自描述数组(破坏性)/ breakfast·lunch·dinner 改 Boolean(破坏性)/ 新增 days[].week / nodes[].description / nodes[].contactPerson·contactPhone(仅SCENIC)
2026-07-01 09:34:52 +08:00
API Changelog Bot 36178799e6 docs(changelog-v2): 新增65_后端已上线房务禁看订单详情(581045),前端需隐藏/重定向房务订单详情入口+兜底581045(承接62越权待核已落地) 2026-06-30 19:18:43 +08:00
yaosutu c005372652 feat(order-v3): 新增打印行程单接口 changelog(Issue #4644,PR #4650)
GET /v3/admin/order/{id}/print-itinerary
11 区块全量聚合,含字段表/枚举/3组示例/注意事项/关联链接
2026-06-30 18:37:05 +08:00
API Changelog Bot faca68852a docs(changelog-v2): 新增62(订单消息会话归并+跳转去配房详情+详情页红点)/63(去复制内外链接按钮)/64(待处理显示所有未完成订单含异常)前端处理 2026-06-30 18:03:33 +08:00
API Changelog Bot 3de5eecbe7 docs(changelog-v2): 新增61_选择酒店弹窗点移除已选配房要前端还原可用房/余X显示(询房中不扣后端库存,纯前端展示估算) 2026-06-30 17:43:24 +08:00
API Changelog Bot eae2998409 docs(changelog-v2): 新增60_房务订单详情itinerary收口为单父数组assignments(每项带confirmStatus+confirmStatusLabel),删currentAssignment/currentAssignments/inquiringAssignments/currentSelections 2026-06-30 16:56:53 +08:00
yaosutu 10037c3266 docs(changelog): A2 订单实配层合并进行程节点 — 行程节点结算入参+签单出参+删景点餐接口 (#4628)
管理后台 changelog:行程节点接口加 7 结算入参 / 签单出参加 type=SERVICE+景点出单+房型真名 / 删 6 个景点餐配置接口改走行程节点。epic #4628 五期 PR #4630/#4633/#4640/#4651/#4656。
2026-06-30 16:30:33 +08:00
API Changelog Bot ba20cd65b7 docs(changelog-v2): 新增59_站内信打开会话合并为1接口(元信息+订单卡+首屏+合并未读+标记已读)+订单消息用conversationKey跳转,取代58单独调conversations 2026-06-30 15:44:29 +08:00
API Changelog Bot 1a7103fed3 docs(changelog-v2): 新增58_聊天面板订单信息条空白——订单信息在conversations会话卡(已#4066 enrich),前端打开聊天时取来渲染 2026-06-30 14:42:58 +08:00
API Changelog Bot 3506d7980c docs(changelog-v2): 新增57_站内信三tab统一用list单接口+messageType参数区分(全部/ORDER/NORMAL),前端勿用conversations拼订单tab 2026-06-30 14:18:11 +08:00
API Changelog Bot 4b062a298a docs(changelog-v2): 修正56_站内信红点——根因改为前端「全部」tab收到却不渲染(非没刷新),附Network实证records[0]含该消息 2026-06-30 11:36:23 +08:00
API Changelog Bot d9a38d433d docs(changelog-v2): 房务抢单后预留言红点有列表无——前端收CHAT-SSE要刷消息列表(后端已正确) 2026-06-30 11:20:16 +08:00
API Changelog Bot 4861573da1 docs(changelog-v2): 补充——调整订单编辑界面预算/晚client-side估算要求和(与后端2020口径一致) 2026-06-30 10:12:21 +08:00
API Changelog Bot e21f97ab92 docs(changelog-v2): 预算/晚改方案房费合计(1600) + 房务列表补houseStatusLabel + roomTypeSummary翻中文(PR #4659/#4658)前端对接 2026-06-30 09:57:03 +08:00
API Changelog Bot 34a657af60 docs(changelog/52_4624): 补充 PR#4657 日历 status swagger 枚举对齐 confirmed 2026-06-29 23:45:58 +08:00
API Changelog Bot e942c1f872 docs(changelog-v2): 用房需求候选升级为方案(多房型行)+选酒店选房型(PR #4654)前端对接
#4645 候选→方案:一个方案=1酒店+多条房型行各自房数;PUT 用房需求新增 candidates[].rooms[];
订单详情行程/房务详情 candidate/hotel 回显 rooms[](含中文label);选酒店 roomTypes[] 已就绪,前端选房型显协议价/库存。向后兼容无DB迁移。
2026-06-29 18:16:11 +08:00
API Changelog Bot 0c90b14bc5 docs(changelog-v2): 房务订单列表超管/组长应看团队全部带房务归属(前端对接)
后端all-claims已对SUPER_ADMIN+house_keeper_lead放行(200,含claimerName),前端给超管补团队监督tab。
附后端待办:房务写口未校房务/超管角色门(另跟踪)。
2026-06-29 14:51:07 +08:00
API Changelog Bot 0e1780b8b9 docs(changelog-v2): 房务日历补已完成状态点(PR #4624)前端对接说明
日历 statusDots 新增第5类 confirmed(已完成,blue)+summary.confirmed字段+status筛选支持confirmed;
finalize完成的团不再误显进行中,与订单详情对齐。前端按label+color通用渲染或补confirmed白名单。
2026-06-29 14:36:50 +08:00
yaosutu dc65788d5d 文档(order-v3/调整记录): 新增 TRAVELER_EDIT 出行人资料修改变更项说明 (#4612 #4614) 2026-06-29 14:09:59 +08:00
API Changelog Bot 6ccdd10866 docs(changelog-v2): 房务工作台首页接活的房务待办+即将入住(#4618 前端对接) 2026-06-29 12:54:49 +08:00
API Changelog Bot c5d914d073 docs(changelog-v2): 定时任务管理页补暂停/恢复/立即执行按钮 (#4615) 2026-06-29 12:25:21 +08:00
API Changelog Bot 072645cc30 docs(changelog-v2/house): 49 房务日历点击详情应只读不可操作配房+房务负责人展示(前端处理) 2026-06-29 10:48:44 +08:00
yaosutu aff12f1333 docs(order-v3): 打印签单出参重制为自包含通知单+字段中文化 (#4549/#4566/#4584)
GET /v3/admin/order/{id}/sign-voucher 出参三轮变更合并一份:删 header 概要/FROM 下沉到 entry、新增司机/导游/经办人/付款方式、房型/结算/付款 code 转中文。前端必改:原读 header 改读 entries[]。
2026-06-29 10:09:16 +08:00
API Changelog Bot 28c627b8e1 docs(changelog-v2): #4601 调整记录金额返字符串+终止onsiteBalance拒负(知悉) 2026-06-28 23:58:08 +08:00
API Changelog Bot 234527639f docs(changelog-v2/house): 房务测试报告(1.docx)整改批次前端对接
43 #4573 配房询房即扣库存+单日确认requirementId+弹窗全态回显currentSelections(前端必改)
44 #4574 日历团数按团期折叠修复+某天下钻详情新端点
45 #4575 待办按订单聚合一行多类型标签+类型字典化(前端必改)
46 #4578 定制师联系房务未读角标unreadMessageCount+站内信标题团号·联系人
47 #4576 转单操作日志显示接收人真名+转单理由(知悉)
2026-06-28 20:07:43 +08:00
yaosutu 8de86f6680 补充 changelog:终止退款弹窗加应收尾款 outstandingBalance + 现场实收尾款 onsiteBalance(管理后台 #4579 #4581)
预览出参增 outstandingBalance(应收尾款);提交入参增必填 onsiteBalance(现场实收尾款,纯记录不参与退款)。并入同弹窗已有 changelog(42_4548)。
2026-06-28 17:30:50 +08:00
yaosutu 0b8d673b20 新增管理后台 changelog:订单调整记录新接口 (#4540/#4556) + 退役行程编辑历史接口 (#4565/#4569) 2026-06-28 15:40:31 +08:00
yaosutu 884d6a42b9 新增 changelog:终止行程退款弹窗预览补字段 + 提交下界校验(管理后台 #4548 #4563)
预览接口出参新增 days 数组(结束日选项)+订单基本信息(orderNo/customerName/productName/batchNo/consultantName);提交接口新增错误码 581044(结束日前资源必须已用)+对应入参约束。
2026-06-28 15:11:43 +08:00
API Changelog Bot和Claude Opus 4.8 268ca6e116 docs(changelog): 房务待办列表加 orderTodoCount 本单待办总数(#4542 前端对接)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 13:14:22 +08:00
API Changelog Bot e4c66f3fe0 docs(order-v3/adjustment): 车需求快照回显 fleet/specialTags(#4545) + 候选换房型清旧预算(前端处理) 2026-06-28 12:09:01 +08:00
API Changelog Bot d7a9137f08 docs(order-v3/站内信): 消息分类口径修正 订单消息=聊天会话/普通消息=系统通知(按kind派生)+会话列表过滤空占位 (#4535) 2026-06-28 10:18:14 +08:00
API Changelog Bot和Claude Opus 4.8 7ee03a8399 docs(changelog): 房务E2E揪出3 bug修复对接(#4491改天数级联/#4492反序聊天/#4529切角色token)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 10:09:59 +08:00
API Changelog Bot 34a65ef657 docs(order/traveler): 补全出行信息 身份证号自动回填性别/出生日期(前端对接, 后端无改动) 2026-06-28 10:08:46 +08:00
API Changelog Bot 319751c781 docs(house/calendar): 房务日历 我的/全部 scope 切换契约(前端对接, 后端无改动) 2026-06-28 09:00:36 +08:00
API Changelog Bot ff9310192c docs(changelog-v2): 房务房型 bedType 翻中文 + 配房详情补 roomTypeName (#4527 #4528) 2026-06-27 21:00:17 +08:00
yaosutu ea9d7ed769 docs(changelogs-v2): 订单调整 snapshot/submit 契约重制(#4488/#4498/#4502/#4509/#4516)
snapshot 出参:basic 每次必返+承载订单号/产品名/团号+5金额,删顶层 discounts/surcharges/金额,行程改 days[].nodes[] 带价;
submit 入参:删 editReason/tabLocks/confirmDiffHash/basic/feeChanges,行程改 days[].nodes[];出参精简为仅 success。
2026-06-27 18:14:19 +08:00
API Changelog Bot 8941096a45 docs(changelog-v2): 房务配房 补第3个拒绝码808123(单日确认候选已更新) (#4523 第4份韧性审计补) 2026-06-27 18:07:59 +08:00
API Changelog Bot a4f4889e09 docs(changelog-v2): 房需求提交+回显统一收口进 adjustment snapshot/submit + 旧 PUT deprecated (#4515 PR#4520) 2026-06-27 17:57:44 +08:00
API Changelog Bot 1cd17d2dfc docs(changelog-v2): 房务配房并发/事务加固 新增拒绝码808119(取消态)/808113(作废态) (#4506 PR#4507+#4514) 2026-06-27 17:19:25 +08:00
API Changelog Bot b7b0e45f64 docs(changelog-v2): 补充房务组长all-claims拒普通房务错误码808092(#4496) 2026-06-27 15:05:25 +08:00
API Changelog Bot 24fd4d7e3b docs(changelog-v2): 房务组长只读监督角色+组长房务订单聊天(#4493 PR#4494) 2026-06-27 14:21:13 +08:00
API Changelog Bot 83fcfd8eb3 docs(changelog-v2): 去房务抢单上限(30单) + 改期改天数补需求变更重配待办(#4489 PR#4490) 2026-06-27 12:50:45 +08:00
yaosutu和Claude Opus 4.8 eaf6c7f3cd docs(changelog-v2): 订单调整弹窗出行人tab+改期tab(管理后台 #4458)
GET .../adjustment/snapshot 出参加 schedule 块+travelers脱敏→明文(破坏性)+editableTabLocksHint门控;
POST .../adjustment/submit 启用 updates.travelers(原空转)+新增 updates.schedule;
出参加 newDepartDate/newReturnDate/newFlowStatus+changedDims.DEPART_DATE;
错误码 587034-587038;两tab窗口(出行人≤待出行/改期≤待确认)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 09:59:10 +08:00
API Changelog Bot 8ad3ce4111 docs(changelog-v2): 配房大改补待办①刚抢单+④定制师未读并入待办列表(派生项) (#4480) 2026-06-27 09:58:36 +08:00
API Changelog Bot f7fbc5dacf docs(changelog-v2): 配房流程大改天级确认(询房中→单日确认→整体确认→可改)+删记录式询房+待办2新槽 (#4470 #4475) 2026-06-27 09:08:34 +08:00
yaosutu 4836fc9229 docs(order-v3): 预支借款对象改下拉同步——候选接口+payeeStaffId+585007(#4465)
更新预支管理终态文档:新增 GET /advance/payee-candidates 候选下拉+AdvancePayeeCandidateVO 出参+创建入参 payeeStaffId 必填+585007 错误码+585002 废弃;借款对象语义从强制主报账人改为本单人员下拉选定(默认主报账人)。
2026-06-26 18:42:40 +08:00
yaosutu 558425c4f8 新增 changelog:合同·保险 Tab 无合同/无保险时子对象返 null(订单详情接口 #4460/PR #4461) 2026-06-26 17:35:24 +08:00
yaosutu c88cc66ffd feat: 订单时间线 11 事件类型扩展 + 转单入参正式生效(管理后台 changelog)
覆盖 6 PR:#4422 #4426 #4434 #4449 #4454 #4464
关联 Issue:#4419 #4423 #4428 #4446 #4451 #4459
2026-06-26 17:35:13 +08:00
yaosutu 98e35c6096 docs(order-v3): 预支门槛收紧同步——已完成订单不可创建预支(#4462)
gate 允许集去掉 COMPLETED,改为 待出发/出行中;同步 ③门槛 + ⑨业务边界。
2026-06-26 17:18:41 +08:00
yaosutu 93aac89a3e feat(changelog): 取消单财务口径修正 — payableAmount/balanceAmount 对 CANCELLED 订单固定归零(PR#4432+#4457)
- 涉及接口:GET /v3/admin/order/list、GET /v3/admin/order/{id}、GET /v3/admin/order/{id}/finance
- 仅 orderStatus=CANCELLED 订单受影响;非取消单口径不变
- payableAmount(应收总额):取消=合同作废=应收消灭,固定0
- balanceAmount(待收尾款):取消终态无待收,固定0
- totalAmount/paidAmount/refundAmount 历史台账保留不变
- 关联 Issue #4431/#4456,PR #4432/#4457
2026-06-26 16:41:09 +08:00
yaosutu 037b82eaaa docs(order-v3): 订单预支管理最终态接口契约(创建即待审批+去草稿,#4452)
合并 #4429/#4440/#4452 为单一自包含文档:5 端点(创建即SUBMITTED/审批/驳回/撤回/列表)+借款类型字典+错误码585000-585006;声明 submit 端点已删 404。
2026-06-26 16:40:18 +08:00
API Changelog Bot 19ee4919ee docs(changelog/order-v3): 配房详情逐日一天多家(#4435/#4436) — currentAssignment 单数改 currentAssignments 列表, 前端迁移读列表 2026-06-26 12:00:32 +08:00
API Changelog Bot f041ab68c9 docs(changelog/order-v3): 配房询房候选流程接线说明(#4427/#4433) — 详情逐日询房中态+候选清单, 第一次选房走发询房, 单日确认改结算价/同步协议价 2026-06-26 11:25:22 +08:00
API Changelog Bot 1a12466b30 docs(changelog-v2): 房务月度对账口径修复(已复核标签/订单数全局去重/生命周期过滤)前端对接(#4420 PR#4425) 2026-06-26 10:29:56 +08:00
yaosutu和Claude Opus 4.8 de1292823a docs(changelog-v2): 终止行程接口终态汇总(管理后台 #3556)
合并 #3556 系列 3 篇 + #3965 金额String化 为一份终态,供前端一处对接:
- POST /v3/admin/order/{id}/terminate/refund-preview 终止退款预览
- POST /v3/admin/order/{id}/terminate 终止行程(执行)
点明: 旧路径 cancel/on-trip 已删返404; 金额+LongID 全String化;
终态 COMPLETED+PENDING_REVIEW(非CANCELLED); 581007/581018 错误码。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:04:32 +08:00
API Changelog Bot ede5dd5c30 docs(changelog-v2): #4392 价格日历库存改回不限 写侧 unlimitedStock 最终契约(已部署测试服+live验证)
- 新增 26_ 最终契约: PUT batchSetPrices 加 unlimitedStock=true 显式清 stock=NULL
- 25_ 挂起项收尾, 指向 26_
2026-06-26 10:00:09 +08:00
yaosutu 23d659a74b feat(changelog): 退款明细Tab懒加载出参重构——新增退款原因+申请时间,删除预计到账和逐项明细,修正退款渠道语义 (#4418) 2026-06-26 09:59:26 +08:00
API Changelog Bot b9f588737e docs(changelog-v2): 配房改房交互 — 移除走§2.4 DELETE、更换走配房保存(接 #4407) 2026-06-26 09:51:07 +08:00
yaosutu和Claude Opus 4.8 bc140004b6 docs(changelog-v2): 合同保险Tab创建合同与投保接口对接说明(管理后台)
订单详情合同保险Tab两组操作按钮(选择合同方案+创建合同 / 选择保险方案+投保)
的后端接口对接说明,4个接口自包含契约:
- GET /v3/admin/contract/scheme/list 合同方案下拉
- POST /v3/admin/contract/create-by-scheme 创建合同(按方案)
- GET /v3/admin/insurance/scheme/list 保险方案下拉
- POST /v3/admin/insurance/purchase-by-scheme 投保(按方案)
后端接口早已存在,本文为前端首次对接说明。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 09:27:28 +08:00
yaosutu e0be4ce0d0 新增接口:标签库分页列表 GET /v3/admin/tag-library/page(PR #4416,Issue #4415) 2026-06-26 09:06:25 +08:00
API Changelog Bot 8819ddbf24 docs(changelog-v2): 房务待办+日历+不限库存前端重新对接(#4411 #4413)
待办排序倒置修正/stats枚举常量key+随筛选/urgency三层/UNDELIVERED下线;日历每晚落点+下钻stayDate/询房中桶/异常桶;不限库存unlimited字段。测试服实测通过。
2026-06-25 23:43:41 +08:00
API Changelog Bot 69070e1d39 docs(changelog-v2): 询房弹窗改造前端对接(候选list/真实房型/联系人只读/正文预览/回填改价)
工单 #4404(PR #4408) + #4405(PR #4409),hl-order-service-v3 + hl-resource-service,测试服已部署 + API/DB 实测通过。
2026-06-25 18:58:23 +08:00
yaosutu 500f824518 docs(changelog): 订单详情合同保险Tab出参终态 双端管理后台 (#4390 #4403)
合同顶层补方案名/签署人/签署方式+富时间线(actor/状态/描述);保险结构重构为
聚合层+policies数组(多保单各张独立含时间线,删旧顶层policyNo/premium/events,破坏性)。
覆盖 PR #4391 #4399 #4406。
2026-06-25 18:01:00 +08:00
API Changelog Bot 6cbed28e94 docs(changelog-v2): 配房统一换酒店写口 + 去换酒店按钮 + 回显已配酒店 (#4407) 2026-06-25 17:55:55 +08:00
yaosutu 799981cbe8 推 changelog:发票推送明细日志 #4395/#4397(管理后台,新增 GET push-logs 接口+发票详情出参加 pushLogs 数组,每渠道每次一条含操作人/时间/状态) 2026-06-25 15:18:09 +08:00
API Changelog Bot e27954e833 docs(changelog-v2): 站内信会话化前端待办总览(汇总6项: 会话聚合/团号/简介条/跳转/铃铛/tab, 后端均已就绪) 2026-06-25 15:13:21 +08:00
API Changelog Bot c8e3769e3f docs(changelog-v2): 站内信顶部铃铛未读角标前端接入spec(后端已就绪:未读落库+SSE带unreadCount信令+unread-count接口) 2026-06-25 15:06:01 +08:00
API Changelog Bot c1155e138d docs(changelog-v2): 站内信会话简介字段已上线测试服(PR #4394, 实测库凡巧订单返回) 2026-06-25 14:47:52 +08:00
API Changelog Bot 92f129c52c docs(changelog-v2): 价格日历前端补充 协议价回显复测仍未生效+库存占用显示(看的是总量非余量)+不限缺口#4392修复中
wx 复测:协议价仍没回显(后端确认返了);配房库存"没变"是看了总stock,真减的是stockUsed/available(实测0→1/10→9),前端弹窗补显占用/余。
2026-06-25 14:38:58 +08:00
API Changelog Bot 0277561bc3 docs(changelog-v2): 站内信会话 spec 跳转改按peerRole反推 + §6后端增强(订单简介条产品名/人数+requirementId) 2026-06-25 14:34:07 +08:00
API Changelog Bot c9be57e4b2 docs(changelog-v2): 站内信订单消息跳转 spec 锁定按登录者角色(wx确认) 2026-06-25 13:45:47 +08:00
API Changelog Bot 402e9a0444 docs(changelog-v2): 房务去询房中顶层态 进度条4步+异常红标+我的接单去询房中 (#4389)
PR #4389 工单 #4380。进度条 6→4 步, Progress 加 exception/exceptionLabel 红标字段,
我的接单去询房中 tab + 异常筛选改 todo 驱动并集, houseStatus 不再返 IN_INQUIRY。
已部署测试服双实例 health UP + API 实测通过。
2026-06-25 12:14:52 +08:00
API Changelog Bot 9fedff29d7 docs(changelog-v2): 站内信订单消息改按会话聚合+团号+跳转 前端对接spec(后端零改动复用/chat/conversations) 2026-06-25 12:00:53 +08:00
API Changelog Bot f01e19f62c docs(changelog-v2): 价格日历设置价格弹窗 协议价回显(前端)+库存可空=不限(前后端就位)
协议价回显=前端bug(getPriceCalendar已返protocolPrice);库存null=不限后端已就位+硬扣开关已开,前端放开必填+null显示不限。
2026-06-25 11:56:16 +08:00
API Changelog Bot 1d4ffe4ad3 docs(changelog-v2): 站内信聊天行标题派生【聊天】发件人(角色)补充 (PR #4386) 2026-06-25 11:38:09 +08:00
yaosutu 2d52ce1513 推 changelog:发票管理列表搜索补齐 #4383/#4384(管理后台,GET invoice/page 入参新增 contactName+orderNo 接线生效+跨 tab 完整搜索) 2026-06-25 11:25:44 +08:00
API Changelog Bot 49a9fb9fc9 docs(changelog-v2): 配房前端UX补充③订单详情行程卡显示已配酒店结果(后端已返currentAssignment)
实测 HL20260624092836856 DAY1 currentAssignment 非空返回(海拉尔海棠/1间/sellPrice330),前端未渲染仍显示"待指定酒店",纯前端渲染遗漏。
2026-06-25 11:11:29 +08:00
API Changelog Bot 5561ff5b26 docs(changelog-v2): 配房选酒店弹窗前端UX补充(结算价改自由输入框+已选行显示配房日期)
承接 #4373/#4377,两处纯前端 UX,后端零改动(sellPrice/protoPrice/stayDate 均已返回并部署)。
2026-06-25 11:03:48 +08:00
API Changelog Bot 50b65f0d41 docs(changelog-v2): 站内信收件箱混排聊天-订单类消息恢复可见 (PR #4382) 2026-06-25 10:53:18 +08:00
API Changelog Bot 996996c6f7 docs(changelog-v2): #4378 配房同步协议价开关端到端实测通过(220→288.88→恢复) 2026-06-25 10:50:25 +08:00
yaosutu 10340d0104 推 changelog:发票推送渠道改走数据字典 invoice_push_channel #4379(管理后台,PUT push 渠道合法值由硬编码改字典驱动+降级兜底,渠道值不变) 2026-06-25 10:35:21 +08:00
API Changelog Bot a3bc9a3e17 docs(changelog-v2): 配房填结算价加同步到协议价开关(#4378 后端就绪,前端加开关) 2026-06-25 10:34:20 +08:00
yaosutu 76dcf10531 推 changelog:发票模块 #4337/#4349/#4360(ALL 改订单视角+封面图+申请删 amount+门槛放宽+开票核单门槛,管理后台+小程序端) 2026-06-25 10:17:51 +08:00
API Changelog Bot 3d9ec7021d docs(changelog-v2): 配房选酒店弹窗三连修(定制师标记后端已修#4374 + 分页/售价列前端) 2026-06-25 10:04:51 +08:00
API Changelog Bot b05004cebb docs(changelog-v2): 配房候选数量修复(CORE不再截到10家) (#4369) 2026-06-24 23:22:17 +08:00
API Changelog Bot 71b96ad0d8 配房选酒店一步定房型+房间数:后端回显补 roomCount + 提交契约说明(#4367/#4368) 2026-06-24 19:20:26 +08:00
API Changelog Bot 5b026fd920 补 changelog:配房选酒店前端默认别传 city(抓包实证前端把行程城市当筛选致只剩1条) 2026-06-24 18:46:09 +08:00
API Changelog Bot e7cc66b833 配房选酒店弹窗待补选房型+房间数(后端 roomTypes 已就绪,前端加 UI) 2026-06-24 18:20:57 +08:00
API Changelog Bot a22e9c1ae3 配房选酒店默认不按城市(后端 order+resource 改,跨城列全部)+更正前篇「返全集」定性(#4363/#4364) 2026-06-24 18:16:00 +08:00
yaosutu 597096129b docs(refund): 退款详情 orderInfo 补订单字段(#4356 修改接口-管理后台)
GET /v3/admin/refund/application/{id} 出参 orderInfo 块原恒为 null,
本次修复接通 OrderService 后正常填充,并新增 teamNo / tierName / peopleSummary
三字段,与退款列表接口(PR #4344)保持口径一致。非破坏性变更。

Issue: https://git.1814.love:8443/wx/HL/issues/4356
PR:    https://git.1814.love:8443/wx/HL/pulls/4359
2026-06-24 17:47:11 +08:00
API Changelog Bot d06d8ed6b4 docs(changelog-v2): 抢单池 SSE 实时广播(新单入池/被抢/释放/加急) (#4358) 2026-06-24 17:38:57 +08:00
API Changelog Bot 9ec621d8ec 配房选择酒店候选列表:后端返全集已排序,前端需全量渲染(前端渲染 bug 澄清) 2026-06-24 17:22:16 +08:00
API Changelog Bot e10e9a0b69 订单详情 brief 补 manualUrgent 加急状态回显(补 #4342,#4354/#4355) 2026-06-24 17:06:40 +08:00
API Changelog Bot 529ea1cbef 配房需求段×候选候选酒店补真实房型 roomTypeId/roomTypeName(itinerary #4351/#4352)+ 诉求标签/整单备注前端回显提醒 2026-06-24 16:42:57 +08:00
API Changelog Bot 805bd176f9 @
docs(changelog-v2): 抢单池紧急度+配房选酒店不限城市+站内信类型筛选 (#4342 #4346 #4348)
@
2026-06-24 16:19:05 +08:00
yaosutu a9e26fa47b 退款待办列表出参新增团号/档位/人员数三字段(#4344,Closes #4343) 2026-06-24 16:11:58 +08:00
yaosutu 43d55d0a4d 发票管理列表 ALL tab 改订单视角 (#4338) - changelogs-v2/2026-06 2026-06-24 15:17:37 +08:00
yaosutu 9965b110fb docs(changelog): 待收尾款 balanceAmount 退款口径修正 + 详情头部/列表补 refundAmount 管理后台 (#4333)
balanceAmount 修正(有退款订单数值变大,无退款不变)+ main/list 新增 refundAmount。
2026-06-24 14:37:43 +08:00
API Changelog Bot e6febaa22b @
docs(changelog-v2): 释放后整段对话进留言池+抢单前展示完整留言 (#4336)
@
2026-06-24 14:33:28 +08:00
API Changelog Bot ccb71ead90 @
docs(changelog-v2): 释放回池冻结旧房务会话+消息转留言池真生效 (#4330 #4332)
@
2026-06-24 14:20:16 +08:00
API Changelog Bot cc06bb796a @
docs(changelog-v2): 房务聊天角色徽章中文label(#4328)+前端去留言按钮只留聊天
@
2026-06-24 11:13:59 +08:00
API Changelog Bot a6a18e9943 @
docs(changelog-v2): 房务聊天/站内信4修复+未读实时SSE (#4326)
@
2026-06-24 10:49:29 +08:00
yaosutu 45e2af81f8 docs(changelog): 财务详情新增应收总额 payableAmount 字段 双端管理后台 (#4321)
财务Tab/订单详情头部/订单列表 3 个 admin 接口出参各新增 payableAmount(应收总额)派生字段。
2026-06-24 10:32:39 +08:00
API Changelog Bot 4b866a0371 docs(changelog-v2): 房务异常标记完成+已确认改已完成+释放/转单修复 (#4312 #4318 #4319) 2026-06-23 17:56:09 +08:00
API Changelog Bot 3c32adb73e docs(changelog-v2): 定制师侧订单详情/调整快照候选暴露真实房型 roomTypeId(#4204 P2,PR#4313) 2026-06-23 17:42:23 +08:00
yaosutu f85aa74eb5 docs(发票): PR #4311 收口——4份发票 changelog 勘误(amount 改 JSON number 元)
修正范围:
- 23_4290_发票申请入参票种修正-修改接口-管理后台.md
- 23_4290_发票申请票种修正-修改接口-小程序端.md
- 23_4258_发票详情接口-新增接口-管理后台.md
- 23_4265_发票列表page结构调整-修改接口-管理后台.md

主要变更(4份文件均已对齐最终线上契约):
1. amount 入参/出参全部改为 JSON number(单位元,如 986.00),
   原「integer 分/字符串分/×100」描述已作废
2. 各文件顶部勘误节追加「截至 PR #4311 收口」条目,
   关联 Issue #4290/#4296/#4310、PR #4292/#4302/#4311
3. 详情接口边界示例:专票 email 由 null 改为始终有值(全电子交付)
4. 列表接口:records.amount 和 stats.amount 均改为 number 类型
2026-06-23 17:09:06 +08:00
yaosutu 3e00271082 docs(changelog-v2): 退款待办统计接口出参改数组+分页新增statusGroup参数(#4303/#4308) 2026-06-23 17:06:40 +08:00
API Changelog Bot b658d8671d docs(changelog-v2): 房务详情逐日城市改区县+候选真实房型roomTypeId(#4300/#4305)+聊天发送人企微名(#4309) 2026-06-23 16:39:55 +08:00
yaosutu a47eeeedcb docs(invoice): 发票申请最终契约 - 新增2文件 + 勘误2文件(#4290 #4292 #4302)
新增:
- changelogs-v2/2026-06/23_4290_发票申请入参票种修正-修改接口-管理后台.md
- changelogs-v2-mp/2026-06/23_4290_发票申请票种修正-修改接口-小程序端.md

勘误:
- 23_4258_发票详情接口:删除 mailAddress 出参字段、去掉 ELECTRONIC 枚举、email 改为始终有值
- 23_4265_发票列表:invoiceType 枚举去掉 ELECTRONIC(普票/专票两值)

契约定稿要点:invoiceType 只有 VAT_NORMAL/VAT_SPECIAL;email 始终必填+格式;
专票限 COMPANY 抬头(581523);专票五项全必填(581515);删 mailAddress(全电子交付)
2026-06-23 16:05:51 +08:00
API Changelog Bot bfa877f3db docs(chat): 在线/离线实时SSE已上线(22_4223 §12, presence事件, #4273 PR#4299) 2026-06-23 15:43:42 +08:00
API Changelog Bot 79468ab61f docs(changelog): 车务§13.5未派看板数据打通(#4284/4286/4295)+车辆VIN错误码600107→600113(#4279) — 管理后台 2026-06-23 15:21:17 +08:00
API Changelog Bot 1e9f9ad881 docs(chat): 真已读readByPeer+im-chat-read SSE + 房务侧detail.messages已上线实测(22_4223§11/22_4237§8, #4288/#4289 PR#4294) 2026-06-23 15:15:33 +08:00
API Changelog Bot b30dee3d22 docs(changelog-v2): 订单取消房务生命周期收口(#4287) + control_status词汇单源化(#4293) 2026-06-23 15:04:17 +08:00
API Changelog Bot b5cb91defd docs(chat): 聊天「已读」是前端写死+抢单前应显「留言」澄清(22_4223 §10 / 22_4237 H2)
- 后端 ChatMessageRespVO 无任何已读/送达字段(9字段已列全),14:05已读=前端硬拼,后端给不了
- 抢单前我方消息=留言(待房务接单),抢单后=已送达,别写死「已读」
- 留言→抢单后送达后端全包(bindHouseClaimer.rebindUnreadReceiver),测试时没抢单故正确未送达
- 房务管家抢单池门控保持不变,与定制师单向留言不冲突
- 标2项可选后端增强待wx定:真已读回执/抢单池留言计数预览
2026-06-23 14:16:47 +08:00
yaosutu 2a24c42ba5 feat(发票模块): 新增发票详情接口 + 发票列表 page 结构升级(管理后台·#4258/#4265)
- 新增 GET /v3/admin/order/invoice/{id} 发票详情接口(全量字段含专票四项/开票痕迹/推送痕迹)
- GET /v3/admin/order/invoice/page 列表行新增 9 个订单冗余字段
- tab 入参新增 NONE(未申请,代客申请候选)
- tabCounts 和 stats 从扁平对象改为数组(破坏性)
2026-06-23 12:37:57 +08:00
yaosutu 7907e2aaa6 docs(changelog): 退款申诉新增接口 + 统一售后工单下线 双端 (#4250)
售后拆分重构(PR #4251 #4254)对外接口变更:
- 小程序端(changelogs-v2-mp): 申诉新增 4 接口(发起/我的/详情/撤回)+ /v3/mp/aftersale/ticket* 下线 404
- 管理后台(changelogs-v2): 申诉新增 2 接口(分页/详情,关联展示来源+触发退款)+ /v3/admin/aftersale/ticket* 下线 404
- 申诉复用退款审批(无独立申诉审批);投诉仅移包路径不变
- 13 节自包含:全字段+枚举(appealType/appealStatus)+错误码 530601-609+示例(含工单 404 异常)
2026-06-23 12:26:01 +08:00
API Changelog Bot 3f0c4037fd docs(changelog): #4256/#4266/#4274 房务守卫一致性审计修复(询房守卫+终态闸口808121+按钮enable对齐) 2026-06-23 11:49:36 +08:00
API Changelog Bot 65d5980a7d docs(changelog): 22_4223 §9 切真细节契约 — 答前端Q1(open-house选传/后端不解析对端)/Q2(list+sentAt字符串yyyy-MM-dd/isMine)/Q3(SSE已LIVE别轮询)+在线态SSE工单#4273 2026-06-23 11:44:16 +08:00
API Changelog Bot a5c7d90b8d docs(changelog): 联系房务契约裁决 — 作废误写的23_(基于stale代码), 22_4223补裁决答前端3问(open-house live/抢单前可发/在线态轮询/FLEET deferred) 2026-06-23 11:32:18 +08:00
API Changelog Bot a63cadb822 docs(changelog): 定制师侧联系房务聊天门控+去mock+对接真实房务(管理后台前端) — 后端契约已就绪实测 2026-06-23 11:09:34 +08:00
API Changelog Bot c3060cc10a docs(changelog): 配房行程逐日城市改区县(后端 #4264 已上线) 字段契约 cityName=区县/cityCode=市级 2026-06-23 10:50:51 +08:00
API Changelog Bot 2f8156e0ff 文档(order/admin): 房务6态全返回-订单详情进度条6步(#4255)+我的订单筛选6tab(#4261) 已上线可对接 2026-06-23 10:30:16 +08:00
API Changelog Bot f0443f4368 docs(changelog): 房务管家定制师需求漏候选酒店(#4237 第3项) — 补本单实测复证+验收对齐目标 2026-06-23 10:00:58 +08:00
API Changelog Bot 01bb12416e docs(changelog): 房务管家操作日志 operator 渲染前端项(#4237) — 渲染 operator.name 而非整串 JSON 2026-06-23 09:49:03 +08:00
yaosutu 75dea54f2f docs(changelog): 退款待办工作台后端接口(stats统计+resubmit重新发起+page列表增强) 管理后台 (#4226) 2026-06-22 17:48:20 +08:00
API Changelog Bot b661ff7e89 文档(order+user/admin): 房务「联系房务」面板真实化已上线可对接(#4223 PR#4247)
取代同日「需求澄清·实现中」版。已部署测试服+API验证:
- 订单详情 hotelRequirementBrief 加 claimerId(未抢单 null->前端「未知」)
- 聊天 open/open-house/conversations 加 peerOnline(真实在线态,SSE+Redis TTL near-live)
- 新端点 POST /admin/message/chat/open-house(HOUSE 订单维度单会话 HOUSE:{orderId})
- 抢单前发消息·抢单/转单后送达(后端自动);同人不自聊
2026-06-22 17:44:44 +08:00
yaosutu 41acbe58bb 文档:发票待办补齐三 PR - 财务列表 NONE Tab + 订单字段 + 推送接口(#4233/#4235/#4238,Issue #4228~4230) 2026-06-22 17:10:36 +08:00
API Changelog Bot 9618b1f163 Merge branch 'main' of https://git.1814.love:8443/wx/hl-api-changelog 2026-06-22 17:06:10 +08:00
API Changelog Bot和Claude Opus 4.8 56be7eedae docs(changelog-v2): 房务管家 #4237 补 H — 留言空态对齐定制师需求=1留言
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:05:50 +08:00
yaosutu df6bee83b8 docs(v2/aftersale): v2 申诉退款 execute-appeal 接口废弃 → 迁移至 v3 售后工单 resolve
v2 PUT /order/refund/{id}/execute-appeal 在 v3 不存在(404)
新流程:POST /v3/admin/aftersale/ticket/{id}/resolve 处置时核定金额,OA 通过后自动退款
关联 Issue #4161
2026-06-22 17:05:26 +08:00
API Changelog Bot 56c5498167 docs(changelog): #4246 房务操作日志记录定制师提需求(读侧合成,op_type REQUIREMENT_SUBMIT) 2026-06-22 17:04:22 +08:00
API Changelog Bot和Claude Opus 4.8 3d4e3967e7 docs(changelog-v2): 房务管家 #4237 进度条6态+留言计数 已部署验证版字段契约
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:00:48 +08:00
yaosutu ee75e0ca36 文档:退款原因管理补 reason/list 列表端点(PR #4243,Issue #4242) 2026-06-22 16:35:50 +08:00
yaosutu 8144e7d197 docs(v2): 早鸟优惠 v3 管理后台对接 changelog 补建菜单说明
前端迁移指引加第1步:v3 后台需新建早鸟优惠菜单入口(二期独立工程不会从 v2 自动带菜单),页面照搬 v2 即可。注意事项同步补一条。
2026-06-22 16:23:41 +08:00
yaosutu 3c50202413 文档:退款政策与原因管理接口 v2->v3 路径对照与算法差异说明(管理后台) 2026-06-22 16:23:41 +08:00
API Changelog Bot 8f9153e630 Merge branch 'main' of https://git.1814.love:8443/wx/hl-api-changelog 2026-06-22 16:22:24 +08:00
API Changelog Bot和Claude Opus 4.8 6e457dad42 docs(changelog-v2): 房务管家订单详情/抢单池 渲染缺口+抢单门控 (#4237)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:21:51 +08:00
yaosutu d564ea71e7 docs(order/admin): 早鸟优惠管理页面 v3 接口对接说明 — 路径迁移指引(#4053/#4064/#4076/#4082) 2026-06-22 16:20:59 +08:00
API Changelog Bot 1750cb69ab docs(changelog): #4231 配房工作台抢了才能配 — 未抢单拒绝配房(808116)+前端按钮置灰 2026-06-22 16:02:17 +08:00
yaosutu 0df61a7b61 docs(order/admin): 订单列表售后 Tab 接口变更通知 (#4222/#4225)
GET /v3/admin/order/status-group-counts 返回数组由 5 项增至 6 项,新增末项售后(AFTERSALE)。
GET /v3/admin/order statusGroup 参数新增枚举值 AFTERSALE。
售后为横切叠加语义,计数不纳入全部总数,与出行阶段 Tab 正交。
2026-06-22 15:47:41 +08:00
API Changelog Bot和Claude Opus 4.8 38960ac9d3 docs(changelog-v2): 配房需求面板前端接入 — 房型 roomTypeId 模型 + 酒店/备注渲染 (#4209/#4216/#4221)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:26:38 +08:00
API Changelog Bot efa63eca69 文档(order/admin): 订单详情联系房务在线态结论修正(#4223)——作废前版「去掉在线态」,改后端补真实presence+claimerId
- 上一版误判产品意图(让前端删在线态)作废
- 规格(wx):抢单后真实在线/离线,抢单前房务专员显示「未知」
- 后端补:SSE presence(Redis+TTL)+chat peerOnline+订单详情claimerId
- 正式联调字段等上线测试服验证后更新版
2026-06-22 15:13:32 +08:00
API Changelog Bot fd965deb4f docs(changelog): #4220 补内部留言结构化语句只读卡片(wx 确认格式) — 前端展示不动聊天 2026-06-22 15:12:20 +08:00
yaosutu 60350ddecf 推 changelog:订单财务明细查询(优惠/增项清单)接口说明 — #4205 变更预览历史数据源用法 2026-06-22 14:58:50 +08:00
API Changelog Bot 70f9e64dcb docs(changelog): #4220 配房需求回显修复 — 段×候选结构+晚数dayNumber+候选≠分住(后端已修+前端待改) 2026-06-22 14:56:03 +08:00
API Changelog Bot b52da8dd2f 文档(order/admin): 订单详情「联系房务」面板在线态+房务专员为前端假数据核实(前端BUG)
- 在线绿点=前端写死(后端无在线态来源,HouseStaffQueryReqVO.online注释明写不生效;聊天VO无online字段;SSE连接表不对外)
- 房务专员=抢单人,抢单前claimer为空属占位
- 反向定制师→联系房务真对接缺claimerId(订单详情仅暴露claimerName),需要时后端补
2026-06-22 14:53:23 +08:00
yaosutu cbad66ecc7 文档(aftersale+order/admin): 管理后台——售后工单机审auditStatus(#4196 PR#4203)+订单售后中展示aftersaleStatus(#4197 PR#4208) 2026-06-22 14:25:34 +08:00
yaosutu a9185984e7 文档(aftersale/mp): 售后工单接入wx机审——小程序端入参新增mediaTraceIds,出参新增auditStatus (#4196 PR#4203) 2026-06-22 14:25:21 +08:00
yaosutu 0e9a44568f feat: 订单增减项改造 changelog(Issue #4205,PR #4207)
新增统一端点 POST /v3/admin/order/{orderId}/adjustment + 字典化项目名 + 出参增 itemCode/itemName
2026-06-22 12:40:39 +08:00
API Changelog Bot 2c00668800 docs(admin): 房务月度对账 月度环比+PDF导出 + 缺口答复 (PR #4202) 2026-06-22 11:39:01 +08:00
API Changelog Bot 26ff684c82 docs(admin): 配房移除多家庭团familyIndex字段 (PR #4193) 2026-06-22 10:53:40 +08:00
API Changelog Bot b1d70a9020 docs(changelog): order-v3 每日审查修正 发票金额String序列化(admin)+售后mp归属校验(mp) 2026-06-22 01:25:05 +08:00
yaosutu 77a1c4a780 docs: 新增 order-v3 退款域管理后台接口说明(政策/原因/申请管理,共 21 个接口) 2026-06-22 00:26:20 +08:00
yaosutu a6cc4feb93 新增接口通知:v3 售后申诉(小程序端)4 个新接口 — 发起工单/我的列表/工单详情/撤回(Issue #4161) 2026-06-22 00:17:45 +08:00
yaosutu 63e3b0c964 新增接口通知:v3 售后申诉中心(管理后台)4 个新接口 — 工单分页/详情/受理/处置,退款类处置走企微 OA 审批(Issue #4161) 2026-06-22 00:17:34 +08:00
yaosutu 7c93c5b89d 发票补齐系列:管理后台财务开票闭环+定制师代申请 + 小程序端申请可见性签名下载 2026-06-21 22:47:57 +08:00
API Changelog Bot d5a7d8ac61 docs(changelog): 车管证件到期看板 GET /admin/fleet/board/expiry 上线 (PR #4160) 2026-06-21 13:39:31 +08:00
API Changelog Bot 41822427f7 docs(changelog): 车管微信通知模板 5 接口上线(模板 CRUD + 渲染预览, #4156/#4157/#4158) 2026-06-21 12:42:11 +08:00
API Changelog Bot 4436a5061e docs(mp): 出行人补全订单确认后禁止mp编辑+错误码581145 (PR #4154) 2026-06-21 10:41:10 +08:00
API Changelog Bot 9e8f405d62 docs(v2): 配房/选酒店流程评审11点收口(候选房型富化+段×候选+池内快照+特殊诉求字典)前端对接 2026-06-20 18:36:49 +08:00
API Changelog Bot 9f5731aabb docs(v2): 房务模块4类逻辑问题审计修复9PR前端/下游影响(dispatchRemark/异常待办计数/车控去Mock/候选去假文案等) 2026-06-20 18:12:37 +08:00
API Changelog Bot 0182ffff67 docs(v2): 对接总览补转单字段契约+我的接单totalAmount+stats空态/productType徽标说明 2026-06-20 15:06:56 +08:00
API Changelog Bot 80088ae7d1 docs(v2): 房务前端对接4问答复(转单字段+productType计数+待确认异常空态+我的接单补金额 PR#4123) 2026-06-20 15:05:48 +08:00
API Changelog Bot fc1cf246c3 docs(v2): 早鸟管理优惠金额补String序列化 changelog (PR#4118) 2026-06-20 13:09:11 +08:00
API Changelog Bot e747c7f334 docs(v2): 房务酒店详情金额字段补String序列化 changelog (PR#4117) 2026-06-20 12:57:04 +08:00
API Changelog Bot 28deca3a56 docs(v2): 提房需求每家酒店备注+分住明细转发房务详情 changelog (PR#4116) 2026-06-20 12:43:23 +08:00
API Changelog Bot 40c4c956cb docs(v2): 日期参数 changelog 补「格式错误消息转干净中文」(PR#4115) 2026-06-20 12:23:26 +08:00
API Changelog Bot f95ebe79f9 docs(v2): 修正总览-订单维度操作日志路径(/admin/house->/v3/admin/house,实测纠错) 2026-06-20 12:06:30 +08:00
API Changelog Bot 7e80f1371d docs(v2): 日期参数修复 changelog 补同类隐患连带修复(投诉/配车 PR#4112) 2026-06-20 11:55:48 +08:00
API Changelog Bot a3153e9684 fix(v2): 房务 GET 查询日期参数绑定修复 changelog + 总览补日期格式约定 2026-06-20 11:33:25 +08:00
API Changelog Bot a2866a89cf docs(v2): 房务+定制师提房需求+站内信聊天 前端对接总览(管理后台) 2026-06-20 10:29:05 +08:00
yaosutu 43d69d38d1 docs: 新增早鸟优惠计划管理 CRUD 接口 changelog(管理后台,PR #4076) 2026-06-20 10:17:15 +08:00
API Changelog Bot c674675b44 docs(changelog-v2): 房务列表补 consultantId 站内信接入房务(#4101) 2026-06-20 10:12:32 +08:00
API Changelog Bot 1a7ce36aea docs(changelog-v2): 房务原型对齐(二) 配房改协议价#4072 + 酒店富表单/OCR#4073 + 月度对账#4074 2026-06-20 09:55:41 +08:00
API Changelog Bot d720016808 changelog(order-v3/early-bird): 早鸟一产品至多生效一个早鸟-防同订单冲突保留阶梯(PR #4097) 2026-06-20 09:42:11 +08:00
API Changelog Bot c948be3f1c docs(changelog): 车型管理下线 + 产品编排去车型接口契约变更 (#4062) 2026-06-20 09:33:28 +08:00
API Changelog Bot bd14ac0d07 docs(changelog-v2): 房务原型对齐 配房候选酒店标签(#4070) + 价格日历底价占位(#4071) 2026-06-19 19:58:22 +08:00
yaosutu d553718b36 docs(changelog): 到达计划自驾时段 selfDrivePeriodLabel 文案含时间范围(小程序端)
mp 到达计划出参 selfDrivePeriodLabel 口径变化(上午→上午(06:00-12:00)),前端直显无需改代码。
2026-06-19 17:51:32 +08:00
yaosutu 8c8edd364b Merge branch 'main' of https://git.1814.love:8443/wx/hl-api-changelog 2026-06-19 17:50:21 +08:00
yaosutu a770215188 docs(changelog): 大交通接口对齐v2——list分组结构变更+补全label/接送/类型/来源字段
管理后台大交通(#4061/#4075/#4080):list返回改{arrivals,departures}分组(破坏性),
补 directionLabel/modeLabel/transportTypeLabel/selfDrivePeriodLabel+createTime+creatorType,
add/edit入参补pickup,嵌套出行人补travelerType。
2026-06-19 17:50:07 +08:00
API Changelog Bot 9b43fcc0d9 docs(changelog-v2): 站内信聊天会话列表 enrich——头像/订单摘要/业务状态/待回复tab + 收件箱消息类型 (#4066) 2026-06-19 17:49:09 +08:00
yaosutu 82080d7c4a 新增订单标签筛选项接口 tag-options(PR #4068,Issue #4065)
新增 GET /v3/admin/order/tag-options,返回所有订单已挂标签的去重升序列表,
供订单列表标签筛选下拉使用(替代 /tag-library 避免选到无订单的标签)。
同步说明 tagNames 多选为 OR 语义及传参方式。
2026-06-19 16:41:10 +08:00
API Changelog Bot a66f2acd86 docs(changelog): 配房流程简化 #4052+#4055(取消房务驳回改单向走聊天 + 最终确认回执改不必填) 2026-06-19 15:43:28 +08:00
API Changelog Bot 52da3f6e7f docs(changelog): 配房需求酒店选择增强 #4047(候选API keyword/limit + 预算强制协议价 + 多选) 2026-06-19 14:39:48 +08:00
API Changelog Bot f7313ec8e7 docs(changelog-v2): 站内信聊天 P3 房务列表/详情 unreadMessageCount 接真聊天未读 (#4039) 2026-06-19 12:09:19 +08:00
API Changelog Bot和Claude Opus 4.8 b86916bc8c docs(changelog/order-v3): 修正补全弹窗②为紧急联系人必填(后端PR#4041补强581109),原误写非必填
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:51:17 +08:00
API Changelog Bot d894fc3072 docs(changelog): 配房确认接入房间库存扣减 #4029(全产品硬扣+808901不足拒绝, 当前dormant) 2026-06-19 11:22:04 +08:00
API Changelog Bot 3c93927031 docs(changelog-v2): 站内信聊天 P2 SSE 实时契约(im-chat 事件)就绪 (#4032) 2026-06-19 11:16:39 +08:00
API Changelog Bot和Claude Opus 4.8 8ff78d13a7 docs(changelog/order-v3): 补全出行信息弹窗三处前端缺陷(回显不全/紧急联系人误必填/保存后不关闭)+数据丢失避坑
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:12:05 +08:00
API Changelog Bot 8160c0c7e1 docs(changelog-v2): 站内信聊天 P1 加前端暂不接入横幅(仅后端就绪,前端暂缓动工) (#4020) 2026-06-19 10:47:12 +08:00
API Changelog Bot b23de77d92 docs(changelog-v2): 站内信升级聊天 P1 — 6 个管理端 1:1 会话接口 (#4020) 2026-06-19 10:37:30 +08:00
API Changelog Bot 76b2e4cc0b docs(changelog): 房务配房流程顺畅度修复 #4019(待最终确认可达+finalize/回执状态闸口+808185/808186) 2026-06-19 10:30:44 +08:00
yaosutu 59932b6048 feat(changelog): 订单详情补产品封面字段 productCoverImg (#4026)
GET /v3/admin/order/{id} 的 main 块新增出参字段 productCoverImg,
与订单列表同名同义,历史订单无快照时返回 null,前端做占位图降级即可。
2026-06-19 09:57:14 +08:00
yaosutu 321154e5b1 docs(changelog): 子流程加 displayText 完整文案 + statusName 改纯状态 (#4023)
更新 currentSubFlows changelog:statusName 改纯状态(待配/处理中,房车一致),
新增 displayText=name+状态完整文案(配房已打回/配车处理中);明确前端展示直接用 displayText。
2026-06-19 09:50:10 +08:00
yaosutu 9f1b885bfa fix(changelog): 修正 productTypeName 数据字典 label(ROUTE/CUSTOM/GROUP)
原 changelog 初稿使用了错误 label(线路产品/定制产品/团队产品),
实际 label 以数据字典 product_type 为准:
- ROUTE:自驾路书
- CUSTOM:私人定制
- GROUP:小蒙马
同时补充说明 productTypeName 来源是 sys_dict product_type,
以及修正 PR #4022(Issue #4021)关联链接。
2026-06-19 09:45:03 +08:00
yaosutu 20032ec600 feat(changelogs-v2): 订单列表/详情新增 productType+productTypeName 出参字段
影响接口:
- GET /v3/admin/order/list
- GET /v3/admin/order/{id} (data.main 节点)

枚举: CORE/ROUTE/CUSTOM/GROUP 四值
关联: Issue #4009 / PR #4010
2026-06-19 09:19:30 +08:00
API Changelog Bot 208a8ace7d docs(changelog-v2): 每日审查修复 2 条 — 出行人未来生日拦截(#4018) + 景区车辆可售判定(#4017)
via daily auto-review workflow
2026-06-18 23:45:27 +08:00
API Changelog Bot e41093b371 docs(changelog): 房务配房状态升级6态+最终确认强制回执(#4013/PR#4016) 2026-06-18 21:46:03 +08:00
yaosutu d4dbe654d3 docs(changelog): 订单详情概览 overview 字段对接说明(含 nullable + 备注字段)
GET /v3/admin/order/{id} 概览 overview 字段说明(非契约变更):
customerInfo(联系人/电话/商户/定制师/创建时间/人数)+remarkInfo(4备注)+travelers字段路径类型含义;
特别标注可能为 null 的字段(商户软删/无定制师/未填备注/儿童婴儿未填手机等)。
2026-06-18 18:24:07 +08:00
yaosutu 3eac7ce2a7 Merge branch 'main' of https://git.1814.love:8443/wx/hl-api-changelog 2026-06-18 18:06:10 +08:00
yaosutu ba2a6d16cd docs(changelog): 更正证件类型 changelog 为字典 id_card_type 4 值标准 (#3962)
原稿误列旧词表(BIRTH_CERT/HK_MACAU/TAIWAN/MILITARY)会误导前端造脏数据。
更正为字典唯一标准 4 值(身份证/护照/回乡证/台胞证),强调前端拉字典不硬编码,
婴幼儿用身份证,字典未命中返回原值码(非null)。
2026-06-18 18:05:42 +08:00
API Changelog Bot ea706e839a docs(changelog): 出发日期不可售错误码已优化 581014→581041(清晰文案),同步更新前端待修说明 (PR #4008) 2026-06-18 17:22:14 +08:00
API Changelog Bot 1f87918282 docs(changelog): requirement_status 字典移除团期专用2态(团期配房先不做),仅留散客4态 2026-06-18 17:17:36 +08:00
yaosutu 2c04507372 feat(collab): 新增订单打标签弹窗 tag-picker 聚合接口 + 批量替换标签接口(#3988) 2026-06-18 17:17:24 +08:00
API Changelog Bot 8ab53749fa docs(changelog): 补 requirement_status 数据字典已配置(测试服生效,前端可经 /admin/dict 取6态) 2026-06-18 17:12:07 +08:00
yaosutu ab83944191 feat(changelog): 订单列表接口新增出参字段 tripNights(Issue #4002,PR #4003)
GET /v3/admin/order/list 的 OrderListItemRespVO 补齐 tripNights(行程晚数),
与订单详情口径一致,前端可展示「X天Y晚」格式。
2026-06-18 17:10:24 +08:00
yaosutu a0c5c92ba4 docs(changelog): currentSubFlows 子流程状态删 label 加全态 statusName (#3983 #3997)
管理后台订单列表+详情 currentSubFlows[] 出参:删除 label、新增 statusName(全态中文)。
配房/配车 6 态(待提交需求/待审核/待配房/配房中/已打回/已完成),领队/摄影(待指派/已完成)。
前端统一读 statusName。
2026-06-18 17:10:07 +08:00
API Changelog Bot 6939e6d6b8 docs(changelog): 新建订单出发日期选择器需限制为可售日期(前端待修)——已有 pricing-calendar 接口可置灰+后端已服务端兜底 2026-06-18 16:58:10 +08:00
API Changelog Bot 979ecdf8f1 docs(changelog): 更正房务状态说明——配房全6态已由订单 currentSubFlows.statusName 实现(同事确认状态都有),非待补/待拍板 2026-06-18 16:57:45 +08:00
API Changelog Bot 2c0f1c3ee3 docs(changelog): 房务订单列表接口(抢单池+我的接单)契约确认,核验订单改动未影响+团期配房先不做 2026-06-18 16:34:50 +08:00
API Changelog Bot e9ae6a5ae8 docs(changelog-v2): 司机续签车辆区仅个人车+自带显示 行为变更 (PR #3995 工单 #3991) 2026-06-18 16:29:35 +08:00
API Changelog Bot fc47873ffa docs(changelog): 18_3978 金额String化补充说明——前端无需改动(类型仍BigDecimal,仅序列化口径)
wx 拍板:对齐平台 money=String 约定,字段未改类型,常规渲染/比较/运算无需前端改动。
2026-06-18 16:10:55 +08:00
API Changelog Bot d621d37b5c docs(changelog): order-v3+resource 金额字段补全 String 序列化 W1 后续 (PR #3978/#3979, 管理后台)
W1(#3965) 已修钱/状态热区一批,本批全量补齐剩余漏标金额字段(order-v3 39 VO + resource RoomTypeVO),JSON number→String。已测试服实测订单详情金额返字符串。
2026-06-18 15:52:45 +08:00
yaosutu 362e104708 docs(changelog): 出行人类型改为由出生日期派生,birthday 必填、travelerType 入参移除(小程序端客户出行人补全接口,PR #3981,Issue #3976) 2026-06-18 15:49:59 +08:00
yaosutu 663b93a641 docs(changelog): birthday required, travelerType removed in admin 3 APIs (PR #3981) 2026-06-18 15:49:46 +08:00
yaosutu 8a0d38493f docs(changelog): 出行人证件类型新增 idTypeName 中文字段 (#3962 #3970)
管理后台 3 接口出参新增 idTypeName(字典 id_card_type 优先、IdCardType 枚举兜底):
- GET /v3/admin/order/{id}/traveler/list
- POST /v3/admin/order/{id}/traveler/add
- GET /v3/admin/order/{id} 的 overview.customerInfo.travelers[]
2026-06-18 14:14:19 +08:00
yaosutu 49cd72a481 feat(order-v3): 出参字段 flowDisplayText 重命名为 flowStepName(#3967/PR#3969)
三个接口(创单/列表/详情)破坏性改名,前端需全局替换引用。
2026-06-18 12:52:14 +08:00
API Changelog Bot bc50894a09 docs(changelog): order-v3 接口契约审计修复 W1(金额String+被保人脱敏+退款筛选+投保幂等) PR #3965 2026-06-18 12:34:43 +08:00
yaosutu 05fa996c27 新增 changelog:待支付订单流程状态归入补全信息步(管理后台,PR #3961,Issue #3960) 2026-06-18 10:58:37 +08:00
API Changelog Bot b538ff365c docs(changelog): 保险保单下载只读OSS不再现拉第三方+540310自愈(PR #3959, 管理后台) 2026-06-18 10:41:40 +08:00
API Changelog Bot 9bbb232afe docs(changelog): 资源服务接口契约审计下一梯队 P1中/P2 (PR #3957, 管理后台) 2026-06-18 10:16:18 +08:00
yaosutu 5a6f8675b6 docs(changelog): order-v3 合同/保险镜像状态 NONE→null 前端变更说明 (#3956)
- 受影响接口:GET /v3/admin/order/{id}、GET /v3/admin/order/{id}/contract-insurance、GET /v3/admin/order/group-batch/{groupBatchId}/orders
- 无合同/无保险时 contractStatus/insuranceStatus 由 "NONE" 改为 null
- Issue #3953 / PR #3956
2026-06-18 10:15:07 +08:00
yaosutu cee040f814 新增 changelog:到达计划出行人类型中文名新增字段(小程序端,PR #3954,Issue #3951) 2026-06-18 10:05:48 +08:00
yaosutu 3df368d9c1 新增 changelog:出行人类型枚举化+类型中文走数据字典(管理后台,PR #3954,Issue #3951) 2026-06-18 10:05:31 +08:00
API Changelog Bot 4b90d75330 docs(changelog): 资源服务接口契约审计修复 64 项 (PR #3948, 管理后台) 2026-06-17 21:51:56 +08:00
yaosutu a47582056d 【changelog】PR#3943 标签库作用域分类(SYSTEM/PERSONAL)入出参变更 + PR#3944 订单标签移除tagType字段及分组结构——管理后台 2026-06-17 20:03:34 +08:00
API Changelog Bot 36ba58c0bb docs(changelog): 续签PII口径拍板上线 phone/licenseNo明文 idCard脱敏 (PR #3945)
第4节 待定→已拍板:phone/licenseNo 续签返明文供司机核对,idCard/emergencyPhone 仍脱敏;
已部署测试服 init 实测确认。前端原样渲染 prefill 即可。
2026-06-17 19:27:29 +08:00
API Changelog Bot 29ba67669a docs(changelog): 续签H5全字段全附件回显待前端渲染 (PR #3920/#3921, 司机H5)
后端 init 已返续签全套回显数据(driver 16字段+8类司机附件URL+currentVehicle车辆块
含8类车辆附件URL),测试服实测确认。H5续签页当前只渲染3项,前端需:拉最新后端+
渲染车辆块+附件回显上传+输入框预填。补此前 #3920/#3921 漏发的契约周知。
2026-06-17 18:55:37 +08:00
API Changelog Bot 4b02859399 docs(changelog): 新建订单第3步聊天解析接口+来源/标签/人数档走v3字典(PR3933) 2026-06-17 18:52:45 +08:00
yaosutu 4620642b9f feat(order-v3): 推送订单列表3个接口变更changelog(#3923/#3930/#3938)
- 修改接口: 待支付订单flowStatusName/flowDisplayText返null(#3923)
- 新增接口: GET /v3/admin/order/status-options 订单状态下拉(#3930)
- 新增接口: GET /v3/admin/order/status-group-counts Tab分组计数(#3939)
- 修改接口: GET /v3/admin/order 新增入参statusGroup Tab过滤(#3939)
2026-06-17 18:10:44 +08:00
API Changelog Bot 81f054d3a3 docs(changelog): 个人车常驻双向同步司机车牌 (PR #3929, 管理后台)
后端数据一致性修复:个人车绑/解/换常驻→司机侧 primary_vehicle_plate 双向同步
(公司车豁免)。无接口契约变更,前端无需改动;周知点=司机列表「按常驻车牌筛选」
对个人车现在准确。已部署测试服双实例 + API 实测通过。
2026-06-17 16:50:03 +08:00
API Changelog Bot e4d3cda828 docs(changelog): 用户服务接口契约审计修复 (PR #3924, 管理后台) 2026-06-17 16:44:07 +08:00
API Changelog Bot 46401617c2 docs(changelog): 选主题选产品热门改标签+GROUP起价修复(PR3925/3927) 2026-06-17 16:24:03 +08:00
API Changelog Bot 5af7b5b09c docs(changelog): 选主题向导地区标签拍板A-不显示后端零改动 2026-06-17 15:41:06 +08:00
API Changelog Bot e71ce5cef6 docs(changelog): 新建订单选主题向导接口对照-后端已实现仅需前端接线 2026-06-17 15:36:54 +08:00
API Changelog Bot a8f1e490db chore(changelog): 撤回误推到 changelogs-v2 的 2 个小程序 changelog(3911/3915);小程序 changelog 改归 changelogs-v2-mp 且暂不推送(wx 2026-06-17) 2026-06-17 14:20:56 +08:00
API Changelog Bot 228a744dec docs(changelog): 小程序BFF接口契约审计修复 67处 (PR #3915) 2026-06-17 12:29:41 +08:00
API Changelog Bot ab1318cef0 docs(changelog): H5入职采集对齐档案-车辆司机字段与附件类目补全 (PR #3913/#3914) 2026-06-17 12:16:35 +08:00
API Changelog Bot c9f428dee6 docs(changelog): 相册接口横向越权(IDOR)安全热修 (PR #3911) 2026-06-17 11:46:21 +08:00
API Changelog Bot 987ae18e2f docs(changelog): 自带车审核抽屉全回显-VIN采集与车型库车型建议 (PR #3907) 2026-06-17 11:17:30 +08:00
API Changelog Bot d7992de4c1 docs(changelog): 产品服务接口契约审计修复 50项 (PR #3887) — 金额String/错误码/删除守卫/禁用端点/定制可见性 2026-06-16 18:05:09 +08:00
API Changelog Bot和Claude Opus 4.8 a2b1b821a5 docs(changelog): FLEET 接口契约审计修复(错误码补全+校验收紧+拉黑收口) PR#3874
经 api-contract-audit workflow 全量审计 fleet 11 控制器,修复实现与契约不符 14 处。
前端相关:多端点错误码补全 + typeKey 编辑放宽 + vehicleStatus 仅 maint 人工设 +
拉黑收口专用端点 + CSV 审核状态中文 + generateToken 请前端防抖。
已部署测试服实测通过(health + CSV + V004 真库应用)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:47:43 +08:00
API Changelog Bot 409b3087cc docs(changelog/v2): 站内信通知中心代码审查批量修复 PR#3873 2026-06-16 15:53:20 +08:00
API Changelog Bot c8e19dc870 docs(changelog): 个人车失去常驻立即停用 + 常驻车展示口径 2026-06-16 14:49:05 +08:00
API Changelog Bot 3e02d420c4 docs(changelog): 自带车车队司机可填车管补 + 价格/删车型护栏 2026-06-16 14:35:45 +08:00
API Changelog Bot f77b9740c3 docs(changelog-v2): 续签候选司机列表不渲染=前端bug(字段名id非driverId),后端/page已实测正常 2026-06-16 14:25:44 +08:00
API Changelog Bot 0ab287215b docs(changelog-v2): 司机软删联动作废续签token + 前端需补档案缺失分支 (#3867/PR#3868) 2026-06-16 14:15:46 +08:00
API Changelog Bot f84deb7464 docs(changelog): 自带车审核通过自动建车+审核抽屉加自带车区(前端待加) 2026-06-16 14:13:21 +08:00
API Changelog Bot 75be110438 docs(changelog): 车务全量API审计批量修复6项 2026-06-16 12:02:45 +08:00
API Changelog Bot 09ac87b11c docs(changelog): 司机审核通过附件搬运修复 + 司机删除按钮后端就绪告知 2026-06-16 11:32:28 +08:00
API Changelog Bot 6bebad8b50 docs(changelog-v2): 团期配车/配房重配前置能力 (#3857 #3856 / PR #3862 #3863) 2026-06-16 11:29:46 +08:00
API Changelog Bot 61ed527bf2 docs(changelog): 司机待审核通过也必填原因+去标签 (PR #3858) 2026-06-16 10:59:56 +08:00
API Changelog Bot 150e10f8b9 docs(changelog): 司机待审核详情驾驶证图补进photos块 (PR #3855) 2026-06-16 10:41:19 +08:00
yaosutu 4fdf27bb6e feat(changelog): 推送保险订单列表接口路径改名 changelog(#3682/#3681)
GET /v3/admin/insurance/orders 改名为 GET /v3/admin/insurance/list
旧路径已删除,调用返回 404,前端需立即切换。
入参出参字段不变,仅路径变更。
2026-06-16 10:34:39 +08:00
API Changelog Bot fb9de38a5f docs(changelog): 司机入职H5 OCR换真阿里云识别 (PR #3854) 2026-06-16 10:21:30 +08:00
API Changelog Bot f8d3db6f80 docs(changelog): 保险产品VO金额字段补转字符串 + 房车打回懒清理文档化 #3848 2026-06-16 09:05:27 +08:00
API Changelog Bot 934f62f6da docs(changelog): 保险详情/试算金额改String序列化与列表对齐 (PR #3842) 2026-06-16 00:19:47 +08:00
API Changelog Bot a6a11e2325 docs(changelog): 今日代码审查批量修复 #3841(含保险保费字段转字符串前端需知) 2026-06-15 23:12:29 +08:00
API Changelog Bot c11dac542b feat(order-v3/product-v2): 团期已报名计数改写入持久化-超卖P0-B阶段 (#3836) 2026-06-15 21:22:33 +08:00
API Changelog Bot 1954b38ccc docs(changelog): 司机待审核列表 reviewStatus 删除幽灵态 reviewing (PR #3840) 2026-06-15 21:19:30 +08:00
API Changelog Bot和Claude Opus 4.8 ea1b16a68d docs(前端通知): 保险下载保单改同步按需生成,去掉保单生成中轮询(PR #3834)
点下载后端同步拉保游PDF直接返URL,前端加loading+把自动轮询简化为按需重试,契约不变。
已合并dev-v3+部署+线上验证同步路径生效。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 17:26:36 +08:00
API Changelog Bot和Claude Opus 4.8 ebcaf76a31 docs(前端通知): 保险订单列表补投保人/保费/保障期字段——修列表三列空(PR #3831)
列表VO与详情VO字段名分叉,前端列表表格复用详情字段名(totalPremium/startDate/policyHolderName)
读列表落空。后端把列表接口补齐成与详情同款双名,前端多数无需改动刷新即显示。
已合并dev-v3+部署测试服双实例+6/6实测新字段齐全。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 16:27:34 +08:00
API Changelog Bot和Claude Opus 4.8 cf3c1bc722 docs(前端通知): 司机自助录入H5契约逐字核对——字段名权威清单(submit/new+renew+OCR+init)
前端反馈选填字段名是推断的,请后端拿真实VO逐字核对。本文以dev-v3代码实物为准:
- 纠正VO类名: OcrRespVO实为OcrResultVO, InitRespVO实为H5InitRespVO
- 驾龄字段是drivingYears(非years)
- 标出准驾车型写读不一致: submit/OCR用licenseClass, init预填用licenseType
- 逐字列出 submit/new(含vehicle/emergency嵌套块)/submit/renew/ocr-{step}/init(含renew预填)全字段
后端零改动,纯契约核对回执。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:59:04 +08:00
API Changelog Bot和Claude Opus 4.8 489ef6f535 docs(前端通知): 保险余额显示修复(不再¥0)+保险订单刷新出单状态端点 (PR #3827)
余额: 保游Data直接是余额串非Data.Balance,后端已修,前端无需改刷新即对(实测198304.4)。
新增 POST /v3/admin/insurance/orders/{id}/sync-status 主动对账,可给出单中订单加刷新按钮;
另有定时job每5分钟自动对账兜底。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:45:51 +08:00
API Changelog Bot和Claude Opus 4.8 5ec7ea3277 docs(changelog): 司机H5真实拍照上传OSS免登录通道已补齐(PR#3823)+缺口收口
新增 POST /app/h5/driver-onboard/upload 免登录中转上传端点,补齐上一条标记的
唯一前瞻缺口;后端中转方案,前端不碰OSS SDK,POST文件拿url回填即可。测试服9443实测两例通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 15:17:43 +08:00
API Changelog Bot 68afb81766 docs(changelog-v2): 车务审计修复批次 PR#3818/#3819 (新错误码+H5入职校验加固+编辑误拦修复) 2026-06-15 15:03:43 +08:00
API Changelog Bot和Claude Opus 4.8 618a6fa5bc docs(前端通知): 司机投保承保期改短期默认+限90天(保游无年期产品),计划一取消司机标记
wx 拍先用短期险打通。保游测试目录无≥365天产品(最长豪华版180天),
10万计划≤90天可用、计划一坏的已取消DRIVER标记。前端把投保下单默认承保期
从1年改短期(如30天)+约束≤90天。司机年保1年期待对接保游配年险。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:06:14 +08:00
API Changelog Bot和Claude Opus 4.8 1c5746a977 docs(前端通知): 司机自助录入发短信按钮应调resend端点真发短信(非复制链接)
wx 反馈应在页面直接发短信。后端 POST /admin/fleet/h5/tokens/{pendingId}/resend
早已存在且端到端验证过(真发到手机,收件人确认收到),走通知中心+阿里云SMS_508070093。
现状前端「发短信」只复制链接到剪贴板;前端把按钮接到 resend 端点即可,后端零改动。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:51:42 +08:00
API Changelog Bot和Claude Opus 4.8 e7467fc9bb docs(前端通知): 投保下单选择司机下拉改调轻量 /options 端点 (PR #3817)
/page 作类型搜索下拉太慢(全表seasonCounts聚合+N+1标签+常驻车反查);
新增 GET /admin/fleet/drivers/options 只返 driverId/name/脱敏phone,默认10上限20,
keyword 姓名模糊/11位手机精确同 /page 语义;前端只换数据源。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:15:41 +08:00
API Changelog Bot和Claude Opus 4.8 f23f62a5c4 docs(changelog): 司机录入生成链接需加手机号(必填)+姓名(选填)输入框,新招手机号已变必填(破坏性),后端PR#3815已合并部署测试服四路实测通过 [前端必改P0]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:02:21 +08:00
API Changelog Bot和Claude Opus 4.8 2efa038750 docs(前端通知): 保险计划使用分类打标弹窗单选改多选——后端零改动同一端点
wx 看到 mmg 刚做的打标弹窗(单选 客人/司机/通用)要求改多选。
后端 usage_category 单值列三值恰好是{客人,司机}全部非空子集,BOTH=两个都选,
故纯前端改: 下拉换两个多选项(客人/司机),按映射表换算回同一 usageCategory 值,
PUT /v3/admin/insurance/plans/{planId}/usage-category 端点入参白名单一字不变。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:42:31 +08:00
API Changelog Bot和Claude Opus 4.8 56ee91cb60 docs(changelog): 催办P0-保险计划使用分类(司机可用)打标UI仍缺,司机投保整条卡点,后端端点齐全实测可用只差前端开关 [前端催办]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:34:45 +08:00
API Changelog Bot和Claude Opus 4.8 0be57f0e61 docs(changelog): 司机续签生成链接报targetDriverId格式错误-前端雪花id传成科学计数法丢精度,后端实测整数字符串/数字均正确无需改 [前端BUG·P0]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:16:12 +08:00
API Changelog Bot和Claude Opus 4.8 f47e9fb458 docs(changelog): 司机H5录入全链路免登录已就绪(PR#3803已修,路由守卫误报更正)+标真实拍照上传缺免登录OSS/STS通道前瞻缺口 [前端通知]
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 09:54:38 +08:00
API Changelog Bot 05ed56a8aa docs(changelog): 司机录入表单已解决(误报更正)——后端URL缺/h5前缀+改路径参数,前端无需动 2026-06-15 09:23:27 +08:00
API Changelog Bot和Claude Fable 5 ac303c9d49 docs(changelog): 司机投保下拉空-后端端点全已存在(fleet 4端点+order打标),A方案运营标注,缺前端接线+打标UI [前端通知]
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 09:22:54 +08:00
API Changelog Bot和Claude Fable 5 09cfc2f644 docs(changelog): 司机自助录入已发放链接前端写死→接现成6端点(H5TokenAdminController已存在,实测真实数据,无需补) [前端通知]
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 09:11:34 +08:00
API Changelog Bot 9fb1d5a9fc docs(changelog): 司机录入表单守卫BUG精确定位更正(守卫读meta但部署build的requiresAuth未生效) 2026-06-15 08:59:49 +08:00
API Changelog Bot和Claude Fable 5 ef1f72e195 docs(changelog): 订单列表补/list别名修复关联订单下拉id=list报错(PR#3798后端已修前端无需改)+修正上条房风格说法 [前端通知]
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 17:37:46 +08:00
API Changelog Bot f9199f75b9 docs(changelog): 司机录入H5表单打不开-导航守卫误拦公开路由(前端BUG·P0,通知mmg) 2026-06-13 17:27:37 +08:00
API Changelog Bot和Claude Fable 5 e0dcf2e1af docs(changelog): 保险订单列表前端调错路径/orders/list应改/list——id=list类型错误根因+正确契约 [前端通知]
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 17:03:08 +08:00
API Changelog Bot 44cacffd9b docs(changelog): 司机待审核列表过滤+拉黑解封端点+全年保险下拉关联+保险下单页核实 (#3791/#3792/#3793) 2026-06-13 12:17:35 +08:00
API Changelog Bot和Claude Fable 5 38e1eaa76c changelog(v2): 导入模板示例行内嵌占位示例图(端点契约不变·前端无需改动) (PR #3790)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 11:22:43 +08:00
API Changelog Bot和Claude Fable 5 1da3b00fba changelog(v2): 车务排查批量修复11项 待审详情端点+H5车型下拉源+Label补齐+续签赛季bug (PR #3785)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 09:14:57 +08:00
API Changelog Bot和Claude Fable 5 8fc78a8e7a changelog(v2): 司机驾驶证号必填四入口收口+等级渲染缺口通知 (PR #3783)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 00:02:31 +08:00
API Changelog Bot和Claude Fable 5 5eb9fc1c6f changelog(v2): H5录入链接短链化 shortUrl出参+公开短链跳转端点 (PR #3780)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 21:46:31 +08:00
API Changelog Bot和Claude Fable 5 809e2a1b40 changelog(v2): 司机H5已发放链接管理5端点+H5 init状态机4字段+链接URL收口 (PR #3777/#3778)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:55:12 +08:00
API Changelog Bot c2dcf9efa4 docs(changelog-v2): 保险订单页司机投保+年险自动绑定(#3760/PR#3770)——人员类型单选+bindAnnual+annualSource+两个搜索下拉 2026-06-12 18:22:58 +08:00
API Changelog Bot和Claude Fable 5 213c2b40e0 docs(changelog): 后端核实回执 保单按钮两处收敛+车辆导入弹窗映射确认 blob议题关闭 通知 mmg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 17:56:48 +08:00
API Changelog Bot 17a6397a10 docs(changelog): 前端缺口 车辆档案列表缺关键词搜索框 后端keyword已支持 通知 mmg 2026-06-12 17:18:31 +08:00
API Changelog Bot c5fbc558fe docs(changelog): 前端Bug 车辆批量导入 responseType=blob 致成功误报失败 通知 mmg 2026-06-12 17:10:43 +08:00
API Changelog Bot bc24709a5a changelog(v2): 司机保单列表补source出参+MANUAL年保单PDF按钮收敛(540226) (PR #3765) 2026-06-12 17:07:16 +08:00
API Changelog Bot 384ecdf6f6 changelog(v2): 司机年险绑定保险订单台账(自动落单+双向关联+540224) (PR #3748/#3762) 2026-06-12 16:09:54 +08:00
API Changelog Bot和Claude Fable 5 1179623e25 docs(changelog): 测试服 API 文档站登录改 Gitea 账号 SSO(登录一次30天免登录)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 14:56:10 +08:00
API Changelog Bot 9dc0577cf8 docs(changelog): 司机常驻车改绑下拉+常开车型车型库下拉+回显修正 (PR #3742, 工单 #3739) 2026-06-12 14:51:23 +08:00
API Changelog Bot 790be50fa9 changelog: 司机性别字典化与校验行为变化 (PR #3741) 2026-06-12 14:28:32 +08:00
API Changelog Bot 64c41a1aae changelog(v2): 价格日历聚合总览+多车型批量设价对齐原型 4→6 接口 (PR #3727) 2026-06-12 12:21:42 +08:00
API Changelog Bot e67da05974 changelog: 司机审核驳回短信真发上线与H5驳回重提放行 (PR #3715/#3720/#3722) 2026-06-12 12:02:52 +08:00
API Changelog Bot ce61dbddea changelog(v2): 保险产品全量列表接口(不分页)修复方案弹窗 pageSize=200 报错 (PR #3717) 2026-06-12 11:23:54 +08:00
API Changelog Bot 0cd5ee479e changelog(v2): 车型价格日历三模式调价+节假日筛选+互斥校验 §9 全块说明 (PR #3714) 2026-06-12 10:59:04 +08:00
API Changelog Bot d29253481c docs(changelog-v2): 司机批量续签(#3699)+司机险走保游网投保与保单(#3700) 管理后台 2026-06-11 17:28:12 +08:00
API Changelog Bot 808680ddde changelog: 保游网余额查询URI报错修复(配置补齐+540411清晰报错) (PR #3696) 2026-06-11 15:56:23 +08:00
API Changelog Bot d4f83f6d6e changelog: 车务司机/车辆列表日期筛选报错修复+车型图标长度放宽64 (PR #3694/#3695) 2026-06-11 15:33:49 +08:00
API Changelog Bot 51ddac08de changelog: 车辆生命周期 serviceStatus+停用启用接口+个人车赛季联动 (PR #3690) 2026-06-11 14:35:18 +08:00
API Changelog Bot 1a326b0b12 changelog: 车辆/司机导入模板下载×2 + 车辆导入常驻司机列 (PR #3687) 2026-06-11 12:03:36 +08:00
yaosutu 1453fae332 docs(changelog): #3681 保险订单列表 /orders 改名 /list(破坏性·旧路径下线404)
PR #3682 已合并 dev-v3。声明旧 GET /v3/admin/insurance/orders 下线返 404,
新路径 GET /v3/admin/insurance/list;入参出参不变;详情 /orders/{id} 与
按订单 /orders/by-order/{orderId} 路径保持不变。
2026-06-11 11:48:30 +08:00
yaosutu 71c06434ab docs(changelog): v3保险投保接口入参契约说明(管理后台切v3联调补充)
补 v3 /v3/admin/insurance/purchase 入参契约:idCardType/idCardNo 标准名 +
@JsonAlias 兼容老名 idType/idNo(仍接收不下线);v3 被保人入参无 gender 字段;
insuredPersons/coverage 日期可空自动填充。澄清 404 属网关路由非契约范畴。
2026-06-11 10:57:24 +08:00
API Changelog Bot 04818b47d2 changelog: 行驶证正反面图迁附件表 regCertFrontUrl/BackUrl 字段移除 (PR #3679) 2026-06-11 10:39:09 +08:00
API Changelog Bot 1061cef20d changelog: 司机档案对齐修复 PII脱敏/字段补齐/导入大修 (PR #3678) 2026-06-11 10:12:57 +08:00
yaosutu 0456209b4e docs(changelog): 补出行中取消路径下线说明(cancel/on-trip 改 terminate)
前期 #3556 changelog 只写了新路径入参出参,未点明旧路径已删除,
导致前端联调仍调旧 URL 收到 404。本篇专补路径下线这一环,自包含。
2026-06-11 10:09:10 +08:00
API Changelog Bot f061e1b7e0 changelog: 车辆档案对齐修复(PR #3653/#3656) + 车型大类不分页新接口(PR #3654) 2026-06-10 18:45:42 +08:00
API Changelog Bot 2d7ffb0cb1 changelog: 车型库计数字段上线+sortOrder选填+文档契约勘误 (PR #3650/#3651) 2026-06-10 16:21:33 +08:00
API Changelog Bot d934d7887f docs(changelog): #3642 保险出单改异步-状态新增INSURING-管理后台+小程序 2026-06-10 14:56:39 +08:00
API Changelog Bot da0a49796a changelog(fleet): 常驻司机1:1车侧权威落地+详情回显 (PR #3602) 2026-06-08 17:34:10 +08:00
API Changelog Bot d5dc7e7854 changelog(fleet): 车辆新增所有权性质字段 个人/公司所有 (PR #3601) 2026-06-08 16:54:06 +08:00
API Changelog Bot 221f48266b changelog(fleet): 车辆保险登记瘦身 — 删保险公司/保单号字段 (PR #3600) 2026-06-08 16:33:08 +08:00
API Changelog Bot 1baf0ae2b7 docs(changelog): 准驾车型/民族/保险公司/性别改字典下拉(PR#3599) 2026-06-08 16:01:55 +08:00
API Changelog Bot 979b07dc8e docs(changelog): 附件类目改数据字典驱动+后端撤类目/张数校验(PR#3598,前端按字典remark限制) 2026-06-08 15:31:35 +08:00
API Changelog Bot d37df2feab docs(changelog): 车务金额字段number→String(PR#3592,破坏性) + 车队归属/使用性质改字典下拉(PR#3596) 2026-06-08 14:56:39 +08:00
API Changelog Bot 7c33a382bc docs(changelog): 在线文档恢复显示任务看板等接口分组(文档修复·非契约变更, PR#3597)
hl-user-service Swagger 扫描包过窄(com.hulalv.user.controller)漏扫 task/monitor/file
/callback/notification/wx 等子包,任务看板等整组接口在线文档不显示(接口本身一直可调)。
hl-mp-service 同类问题漏扫 complaint(投诉)。修复后两服务文档分组恢复显示,前端无需改码。
2026-06-08 14:50:44 +08:00
API Changelog Bot a7a92a4828 docs(changelog): 发送日志补 serviceName(服务)列, 两页合并字段全(PR#3554) 2026-06-08 08:58:50 +08:00
yaosutu 694c1c2ee6 破坏性变更:订单详情记录Tab时间线接口LogTimelineVO 6字段重构为13字段(改名/新增/拆分),管理后台前端必须同步迁移(PR #3574) 2026-06-08 08:47:22 +08:00
yaosutu d39345076e docs(changelog/order-v3): 团期级 staff 两级配置(团期共享+订单专属)#3560
新增 GET/PUT /v3/admin/group-batch/{groupBatchId}/staff(团期配置+扇出);
order/{id}/staff 出参加 source,团期共享行订单侧只读(582109)。管理后台 v3。
2026-06-07 14:47:31 +08:00
yaosutu 2106e5be43 新增终止行程退款 changelog(预览新接口 + 终止接口改造,#3556 / PR #3557)
- 终止退款预览:新增 POST /v3/admin/order/{id}/terminate/refund-preview,返回资源清单+行程信息
- 终止行程接口改造:入参改资源已用判定+调整额,出参补退款明细字段(破坏性,前端必改)
2026-06-06 23:29:56 +08:00
yaosutu d5f234455c docs(changelog): 订单取消3退款模式(管理后台)+C端自主取消(小程序) 接口契约 (#3550 #3549) 2026-06-06 18:56:58 +08:00
yaosutu 459f5075a3 Merge branch 'main' of https://git.1814.love:8443/wx/hl-api-changelog 2026-06-06 15:20:46 +08:00
yaosutu b54b294ed5 chore(changelog): 撤回 git add -A 误带入的他人文档
02_3283-3285 订单列表字段说明 / 01_3317 餐厅收费字段 系同事未提交文档,
上一 commit 因 git add -A 误带入并推送,现从仓库移除(本地保留为 untracked,
待同事自行提交)。仅保留 06_3539 补全出行信息接口错误码修正。
2026-06-06 15:20:12 +08:00
共修改 389 个文件,包含 53007 行新增和 310 行删除
@@ -0,0 +1,73 @@
# C 端用户自主取消订单(小程序端)
> 端类型:**小程序端**(v3)|变更类型:**新增接口**|服务:hl-mp-service(Feign → hl-order-service-v3)
> Epic #3540 | PR #3549 |日期:2026-06-06
## 接口地址
`POST /mp/order/{orderId}/cancel`
## 接口介绍
小程序 C 端用户自主取消**自己**的订单。仅出行前可取消,按退款政策(距出发天数阶梯)退款,取消后订单进入 `CANCELLED` 终态、不可恢复。
## 本次修改点
新增接口。此前小程序无自主取消能力(取消只能走后台定制师)。本接口固定 `POLICY` 退款模式(C 端不暴露退款模式选择),并校验订单归属当前登录用户。
## 入参
- 路径参数:`orderId`(Long,订单 ID,必填)
- 请求头:`Authorization`(登录 token,必填)
- 请求体(可选,可不传):
| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| reason | String | 否 | 取消原因 |
**入参示例**
```
POST /mp/order/2063151085698134017/cancel
Authorization: Bearer <token>
Content-Type: application/json
{ "reason": "行程有变,需要取消" }
```
(body 也可整体不传。)
## 出参
`Result<Void>`
**出参示例**
```json
{ "code": 200, "message": "成功", "success": true, "data": null }
```
## 可取消状态(调用约束)
| 订单状态 | 是否可取消 |
|---|---|
| PENDING_PAY 待支付 | ✅ |
| CUSTOMIZING 定制中 | ✅ |
| PENDING_DEPARTURE 待出行 | ✅ |
| TRAVELLING 出行中 | ❌(行程中只能联系客服终止行程) |
| COMPLETED 已完成 | ❌ |
| CANCELLED 已取消 | ❌ |
- 退款模式固定 `POLICY`,按退款政策阶梯计算退款金额(已付订金时退款,未支付时无退款)。
- 仅可取消归属当前登录用户的订单(非本人订单返回 581037)。
## 错误码
| code | message | 触发 |
|---|---|---|
| 581017 | 当前订单状态不允许取消 | 出行中 / 已完成 / 已取消订单调用 |
| 581037 | 无权取消该订单 | 取消非本人(userId 不匹配)订单 |
| 401 | 缺少有效的 Authorization 头 | 未携带 token |
## 关联
- Epic:https://git.1814.love:8443/wx/HL/issues/3540
- PR:https://git.1814.love:8443/wx/HL/pulls/3549
- 后端负责人:腰苏图(订单 v3)
@@ -0,0 +1,33 @@
# 🔴 安全热修:小程序相册接口横向越权(IDOR)修复 — 小程序
> 变更类型:安全修复(后端归属校验加固,**正常使用无影响**,无契约变更)
> 端类型:小程序(相册)
> 日期:2026-06-17
> 服务:hl-order-service-v2(相册域)
> PR:https://git.1814.love:8443/wx/HL/pulls/3911
---
## 说明
`api-contract-audit` 审计小程序 BFF 时发现:相册的 4 个接口存在**横向越权(IDOR)**——后端收到当前用户 userId 后未做归属校验,任意登录用户改 URL 里的 orderId/folderId/albumFileId 即可读取/操作他人订单的相册。本次已修复:后端强制校验"相册所属订单归属当前登录用户",越权一律返回"不存在"。
涉及接口(小程序相册):
- 订单文件夹列表、文件夹文件列表、文件下载地址获取、文件夹公开授权(写)。
## 前端影响:无需改动
- **正常使用完全不受影响**:用户访问自己订单的相册照常工作。
- 仅"访问他人订单相册"这种越权请求会被拒(返回资源不存在)——前端正常逻辑不会触发。
- 接口路径、入参、返回结构均未变。
> 如果前端有任何调试/测试代码用了非当前用户的 orderId/folderId 访问相册,请改为只访问当前用户自己的资源(之前能拿到是 bug,现已封堵)。
## 校验
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3911(squash 合并 dev-v3,via api-contract-audit workflow) |
| 部署 | 已部署测试服,order-v2 双实例健康(滚动重启 uptime 刷新) |
| 测试 | 相册模块单测全绿(新增越权拒绝反例:非本人订单/null-userId/订单缺失 + happy path + 防穿透 verify) |
| 后端负责人 | wx |
@@ -0,0 +1,85 @@
# 小程序 BFF 接口契约审计修复(金额 String + 字段映射 + 可见性 + 缓存)— 修改接口 — 小程序
> 变更类型:⚠️ 多项修复(金额类型 / 字段补全 / 可见性收紧 / 缓存行为,多数前端正向受益)
> 端类型:小程序(hl-mp-service BFF)
> 日期:2026-06-17
> 服务:hl-mp-service
> PR:https://git.1814.love:8443/wx/HL/pulls/3915
---
## ⚠️ 关键说明
`api-contract-audit` 全量审计小程序 BFF 40 个核心 Controller,对抗复核实锤 100 项契约偏差。mp 是聚合层,本次修复 **mp BFF 自身的 67 处**;另有约 40 项根因在下游服务(订单/用户/资源服务),列在文末「待修清单」,会在后续审计中处理。已合并 dev-v3、部署测试服、双实例健康。
最影响前端的是第 1 节(金额→字符串)和第 2 节(原本恒 null 的字段现已修复)。
---
## 1. 金额字段统一为 JSON 字符串
多个 mp 响应 VO 的金额(BigDecimal)此前输出成 JSON 数字,本次统一改为**字符串**(与平台口径一致)。涉及:退款(退款预览/进度/详情)、发票、订单详情/列表、票务、价格明细(含按人群/优惠/附加费的逐项明细)、保费、推荐产品起价等。
> 前端处理:相关金额字段一律按**字符串**接收;若做过数字运算需先转数值。非金额(里程/经纬度/评分)不变。
---
## 2. 原本恒为 null 的字段已修复(前端可正常取值)
以下字段此前因 BFF 与下游字段名不一致(反序列化失败)或 BFF 未填充而恒为 null,现已修复:
| 模块 | 字段 |
|---|---|
| 相册文件 | thumbnailUrl、fileName、fileSize、createdAt |
| 相册订单 | coverUrl、fileCount |
| 发票详情 | invoiceTitle、taxNumber、createdAt |
| 合同 | 状态日志 *Label、出行人证件类型标签 |
| 出行人 | race、roomGroupNo(订单出行人)、travelerTypeLabel |
| 到达计划 | updateTime |
> 前端处理:这些字段现在会返回真实值,可直接使用(之前拿到的是 null)。
---
## 3. 行为收紧(前端需配合)
### 3.1 下架资源详情不再返回(可见性收紧)
景点 / 酒店 / 餐厅 / 活动 详情接口在 BFF 层补了「是否上架」校验,**下架(status=0)的资源详情不再返回**给小程序(之前会原样返回)。前端访问已下架资源详情会得到「不存在/不可见」,请正常处理空态。
### 3.2 浏览量统计 / 错误不再被缓存
- 探索/百科详情的「浏览量+1」此前在缓存命中时不执行(统计失真),现已修复(浏览量正确累加)。
- BFF 缓存不再缓存下游降级错误(避免 TTL 内持续返回陈旧错误)。
- 前端无感,仅数据更准确。
### 3.3 定制需求状态字典修正
定制(/mp/custom)相关接口的状态字典此前文档值有误,实际枚举为 `PENDING/PROCESSING/REPLIED/CONVERTED/CANCELLED`,请前端按此映射。
---
## 4. 待修清单(根因在下游服务,本次未修,后续处理)
以下问题审计已发现,但根因在下游服务,不在本 PR;记录在此供前端知晓(暂仍按现状):
- **订单服务(order-v2)相关 ~21 项**:部分字段缺失/状态机/错误码等(其中相册 4 个越权 P0 已由 PR #3911 安全热修修复)。
- **用户服务相关 ~11 项**:出行人默认删除守卫、token 轮转、资料完善校验、足迹 HOTEL 等 — 将在用户服务审计时在源头修复。
- **资源服务相关 ~3 项**:百科推荐排序、足迹等 — 将在资源服务审计时修复。
---
## 5. 前端 Action 清单
1. 第 1 节金额字段按字符串解析。
2. 第 2 节字段现在有值,可接入使用。
3. 下架资源详情做空态处理(第 3.1)。
4. 定制状态映射用真实枚举(第 3.3)。
---
## 6. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3915(squash 合并 dev-v3,via api-contract-audit + mp-internal-fix workflow) |
| 部署 | 已部署测试服,mp 双实例健康(滚动重启 uptime 刷新);公开端点 /mp/banner/active 等返 code:200 |
| 测试 | 963 单测,本次改动 add 0 新失败(另有 3 个 dev-v3 预存红与本次无关,已单独反馈后端) |
| 后端负责人 | wx |
@@ -0,0 +1,37 @@
# 用户服务接口契约审计修复(mp 侧字段/契约对齐)— 修改接口 — 小程序
> 变更类型:字段/契约对齐(无破坏性删除),小程序侧影响较小
> 端类型:小程序(用户中心/首页配置/收藏足迹/出行人 OCR)
> 日期:2026-06-17
> 服务:hl-user-service
> PR:https://git.1814.love:8443/wx/HL/pulls/3924
> 说明:本文件随 user-service 契约审计一并产出,**暂缓推送**(与小程序侧统一节奏)。admin 侧见 changelogs-v2/2026-06/17_3924_*.md。
---
## 关键说明
用接口契约语义审计工作流扫描 hl-user-service 全部 Controller,mp(小程序 BFF)侧修复一批字段名/null 语义/响应结构与 Swagger 契约不符项。已合并 dev-v3、部署测试服、本地全量 2793 单测零新增回归。下面列 mp 侧对接相关变更。
---
## 1. 收藏 / 足迹(FavoriteRespVO / FootprintRespVO)
- 响应 VO 字段名/缺字段与契约对齐;金额类字段(如有)补 `@JsonSerialize(ToStringSerializer)` 输出字符串。
- 字段语义不变,前端按现有字段名接收即可;如此前对金额字段做数字运算,改为先转数值。
## 2. 首页配置(MpHomeConfig / MpHomeScreen2VO)
- 响应结构与 Swagger 契约对齐(字段名/层级稳定化),无破坏性删除。
## 3. 出行人 OCR / 内容安全(MpTravelerOcr / MpContentSecurity)
- 入参校验(`@Valid` / 校验分组)与错误码规范化;正常路径返回结构不变。
## 4. 站内信(InternalMpMessage / 未读数 UnreadCountRespVO)
- 未读数等响应改强类型 VO,字段名不变。
---
> 待小程序侧统一接线时一并对照本文件;如需提前对接某一节请单独知会。
@@ -0,0 +1,227 @@
# 【修改接口·小程序端】✨ 到达计划出行人类型中文名 travelerTypeName 新增字段 (#3951)
> **PR**: #3954 | **服务**: hl-order-service-v3 / hl-mp-service | **更新时间**: 2026-06-18
## 1. 接口背景
小程序到达计划接口返回的出行人对象(ArrivalPlanTravelerSimpleVO)原先只包含 `travelerType` 英文枚举值,前端展示出行人类型标签时需自行维护一套映射表。本次新增 `travelerTypeName` 字段,由后端查数据字典 `traveler_type` 派生中文名直接下发,小程序侧可零配置展示类型标签。原 `travelerType` 字段保留不变,属纯新增、非破坏性变更。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 获取到达计划(一期路径) | GET | /mp/order/{orderId}/arrival | 新增出参字段 | 出行人对象新增 `travelerTypeName` |
| 2 | 获取到达计划(v3 路径) | GET | /mp/v3/order/arrival/{orderId} | 新增出参字段 | 出行人对象新增 `travelerTypeName` |
> 以上两个路径均经网关路由至 hl-mp-service,数据源为 order-v3 侧透传。
## 3. 接口详情
### 3.1 获取到达计划(一期路径)
- **使用场景**:小程序出行人填写或出行信息确认页,加载出行人到达计划详情。
- **认证**:需要微信登录态 JWT(C 端 token)。
- **幂等性**:是(只读)。
- **限流**:无。
入参无变化。出参中 `travelers[]` 数组每个 `ArrivalPlanTravelerSimpleVO` 元素新增 `travelerTypeName` 字段(String)。
### 3.2 获取到达计划(v3 路径)
- **使用场景**:同上,v3 版本接口路径,功能与 3.1 等价。
- **认证**:需要微信登录态 JWT(C 端 token)。
- **幂等性**:是(只读)。
- **限流**:无。
入参无变化。出参中 `travelers[]` 数组每个 `ArrivalPlanTravelerSimpleVO` 元素新增 `travelerTypeName` 字段(String)。
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 接口 | 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| GET /mp/order/{orderId}/arrival | orderId | String(Long) | 是 | 路径参数,订单 ID |
| GET /mp/v3/order/arrival/{orderId} | orderId | String(Long) | 是 | 路径参数,订单 ID |
### 4.2 请求体字段
均为 GET 接口,无请求体。入参无变化。
## 5. 出参(响应)
### 5.1 ArrivalPlanTravelerSimpleVO 字段
| 字段 | 类型 | 变更 | 说明 |
|------|------|------|------|
| id | String | 不变 | 出行人记录 ID |
| name | String | 不变 | 出行人姓名(脱敏后) |
| travelerType | String | 不变 | 出行人类型枚举值,见 §6 |
| travelerTypeName | String | **新增** | 出行人类型中文名,由数据字典 `traveler_type` 派生 |
> 其余字段视接口版本可能含到达信息、证件信息等,本次仅新增 `travelerTypeName`,其余字段不变。
## 6. 枚举 / 数据字典
### 6.1 travelerType(数据字典:traveler_type)
**所属字段**:`travelerType`(出参,保留不变)与 `travelerTypeName`(出参,新增中文名) | **类型**:`String`
| 枚举值 | 中文名(travelerTypeName) | 说明 |
|--------|--------------------------|------|
| `ADULT` | 成人 | 成年旅客 |
| `CHILD` | 儿童 | 儿童旅客(含独立占位) |
| `YOUNG_CHILD` | 小童 | 小童旅客(不占位或半占位) |
| `BABY` | 幼童 | 婴幼儿(不占位) |
> 字典降级说明:若数据字典 `traveler_type` 中对应 key 缺失,后端使用枚举内置 label 兜底,小程序侧无需处理。
## 7. 错误码
本次为纯新增字段,无新增错误码。原有错误码不变。
| code | 含义 | 触发场景 |
|------|------|----------|
| 581201 | 订单不存在 | orderId 无效 |
| 401 | 未认证 | 未携带或微信 JWT 过期 |
| 403 | 无权限 | 当前用户无权查看该订单的到达计划 |
## 8. 示例(3 组:典型 / 边界 / 异常)
### 8.1 典型成功 — 获取到达计划(含新字段)
请求:
```
GET /mp/v3/order/arrival/2067178767255560193
Authorization: Bearer <mp-token>
```
响应:
```json
{
"code": 200,
"data": {
"orderId": "2067178767255560193",
"travelers": [
{
"id": "2067178767255560201",
"name": "张*明",
"travelerType": "ADULT",
"travelerTypeName": "成人"
},
{
"id": "2067178767255560202",
"name": "张*",
"travelerType": "YOUNG_CHILD",
"travelerTypeName": "小童"
}
]
},
"message": "ok",
"success": true
}
```
### 8.2 边界情况 — 仅含 BABY 类型出行人
请求:
```
GET /mp/order/2067178767255560194/arrival
Authorization: Bearer <mp-token>
```
响应(含 BABY 类型,travelerTypeName 正常返回):
```json
{
"code": 200,
"data": {
"orderId": "2067178767255560194",
"travelers": [
{
"id": "2067178767255560211",
"name": "李*强",
"travelerType": "ADULT",
"travelerTypeName": "成人"
},
{
"id": "2067178767255560212",
"name": "李小宝",
"travelerType": "BABY",
"travelerTypeName": "幼童"
}
]
},
"message": "ok",
"success": true
}
```
### 8.3 业务失败 — 订单不存在
请求:
```
GET /mp/v3/order/arrival/9999999999999999999
Authorization: Bearer <mp-token>
```
响应:
```json
{
"code": 581201,
"data": null,
"message": "订单不存在",
"success": false
}
```
## 9. 业务边界
- 适用:用户已登录且有权限访问该订单,处于任何订单状态均可查询到达计划(只读接口)。
- 适用:四种出行人类型(ADULT / CHILD / YOUNG_CHILD / BABY)均有对应 `travelerTypeName` 中文名。
- 特殊边界:若数据字典维护缺失某枚举值,`travelerTypeName` 降级返回枚举内置中文名,不会返回 null,小程序无需做 null 保护。
- 特殊边界:`travelerType` 原字段值不变,若小程序已有本地映射逻辑,可继续保留或切换为直接展示 `travelerTypeName`,两者等价。
## 10. 修改前后对比
### 10.1 字段级对比
| VO | 字段 | 改前 | 改后 |
|----|------|------|------|
| ArrivalPlanTravelerSimpleVO | travelerTypeName | 不存在 | **新增** String,出行人类型中文名 |
| ArrivalPlanTravelerSimpleVO | travelerType | 原样返回英文枚举值 | 保留不变 |
### 10.2 行为级对比
| 行为 | 改前 | 改后 |
|------|------|------|
| 出行人类型展示 | 小程序自行维护 ADULT→成人 等映射表 | 后端直接下发 travelerTypeName,小程序可直接渲染 |
| 字典缺失兜底 | 无 | 降级用枚举内置 label,小程序无感知 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:**否**,纯新增字段,原字段不变、原结构不变。
- **前端是否必须同步上线**:**否**,旧小程序代码不读新字段也不会出错,可按需对接。
### 11.2 回滚方案
- **回滚方式**:revert PR #3954 并重新部署 hl-order-service-v3 及 hl-mp-service,返回字段恢复为无 travelerTypeName 的旧结构。
## 12. 注意事项
- 前端 workaround 清理点:若小程序已有本地 `travelerType → 中文` 映射对象/函数,上线后可切换为直接读取 `travelerTypeName`,原映射逻辑可清理。
- `travelerTypeName` 由后端数据字典派生,字典修改后立即生效(无需小程序发版),字典当前值为:ADULT=成人 / CHILD=儿童 / YOUNG_CHILD=小童 / BABY=幼童。
- `/mp/order/{orderId}/arrival`(一期路径)与 `/mp/v3/order/arrival/{orderId}`(v3 路径)行为一致,都已包含新字段,小程序按当前接入的路径对接即可。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#3951](https://git.1814.love:8443/wx/HL/issues/3951)
- **PR**: [#3954](https://git.1814.love:8443/wx/HL/pulls/3954)
- **Merge commit**: [16d77c9a5](https://git.1814.love:8443/wx/HL/commit/16d77c9a5)
### 13.2 联系人
- **后端负责人**: @yaosutu
@@ -0,0 +1,316 @@
# 【修改接口·小程序端】出行人类型改为由出生日期自动派生,birthday 必填、travelerType 入参移除 (#3976)
> **PR**: #3981 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-18
## 1. 接口背景
小程序客户出行人补全接口(batch-edit)原先要求客户端传入 `travelerType`(出行人类型枚举值)。本次调整将出行人类型的计算权收归后端:**客户端只需传 `birthday`(出生日期),后端按年龄段自动派生 `travelerType`**,入参不再接受 `travelerType` 字段(传了也会被忽略)。
`birthday` 同步从选填升级为**必填**,不传报 400。响应 VO 不变,`travelerType` / `travelerTypeName` 仍正常返回,展示层无需改动。
> 本次为破坏性入参变更:移除 `travelerType` 入参 + `birthday` 改必填。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 客户出行人补全 | POST | /v3/internal/mp/order/{id}/traveler/batch-edit | 入参破坏性变更 | 出行人对象移除 `travelerType`,`birthday` 改必填 |
## 3. 接口详情
### 3.1 客户出行人补全(POST /v3/internal/mp/order/{id}/traveler/batch-edit)
- **使用场景**:小程序用户自助补全出行信息时,批量 upsert 出行人列表(id=null 新增,id 有值则更新)。
- **认证**:需要微信登录态 JWT(C 端 token)。
- **幂等性**:否(写入操作)。
- **限流**:无。
入参中每个出行人对象移除 `travelerType` 字段,`birthday` 改为必填。响应 VO 不变。
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | String(Long) | 是 | 路径参数,订单 ID |
### 4.2 请求体字段
请求体外层结构示例:
```json
{
"travelers": [{}]
}
```
**出行人对象字段表**:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | String(Long) | 否 | null 或不传=新增;有值=更新已有出行人 |
| name | String | 否 | 出行人姓名 |
| gender | String | 否 | 性别字典码(1=男 / 2=女 / 0=未知) |
| birthday | String | **是** | 出生日期,格式 yyyy-MM-dd,不能晚于今天。**本次改为必填** |
| idType | String | 否 | 证件类型枚举值,见第 6 节 |
| idNo | String | 否 | 证件号码(明文) |
| nationality | String | 否 | 国籍 |
| race | String | 否 | 民族 |
| phone | String | 否 | 手机号 |
| emergencyContact | String | 否 | 紧急联系人 |
| emergencyPhone | String | 否 | 紧急联系人电话 |
| roomGroupNo | Integer | 否 | 房间分组编号(团期订单使用) |
| travelerType(已移除) | — | — | 入参已移除,传入将被忽略;后端按 birthday 自动派生 |
## 5. 出参(响应)
响应 VO 结构**不变**,`travelerType` 和 `travelerTypeName` 仍正常返回。
### 5.1 响应列表元素(TravelerVO 关键字段)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | String | 出行人记录 ID |
| orderId | String | 所属订单 ID |
| travelerType | String | 出行人类型枚举值(后端由 birthday 派生后返回) |
| travelerTypeName | String | 出行人类型中文名(成人 / 儿童 / 小童 / 幼童) |
| name | String | 出行人姓名 |
| birthday | String | 出生日期(yyyy-MM-dd) |
| idType | String | 证件类型枚举值 |
| idTypeName | String | 证件类型中文名 |
| idCardMasked | String | 证件号(脱敏后) |
| gender | String | 性别字典码 |
| nationality | String | 国籍 |
## 6. 枚举 / 数据字典
### 6.1 travelerType 派生规则(后端自动计算,前端仅需理解出参含义)
| 年龄段(按 birthday 计算) | travelerType 枚举值 | travelerTypeName |
|--------------------------|-------------------|-----------------|
| 0-1 岁(未满 2 周岁) | BABY | 幼童 |
| 2-6 岁(未满 7 周岁) | YOUNG_CHILD | 小童 |
| 7-17 岁(未满 18 周岁) | CHILD | 儿童 |
| 18 岁及以上 | ADULT | 成人 |
### 6.2 idType(证件类型字典:id_card_type)
| 枚举值 | 中文名 | 说明 |
|--------|--------|------|
| ID_CARD | 身份证 | 中国居民身份证 |
| PASSPORT | 护照 | 中外护照 |
| BIRTH_CERT | 出生证明 | 婴幼儿出生医学证明 |
| HK_MACAU | 港澳通行证 | 港澳居民来往内地通行证 |
| TAIWAN | 台胞证 | 台湾居民来往大陆通行证 |
| MILITARY | 军官证 | 军人证件 |
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| 400 | 出生日期不能为空 | 出行人对象未传 birthday 或传 null |
| 400 | 出生日期不能晚于今天 | birthday 传入了未来日期 |
| 581201 | 订单不存在 | orderId 无效 |
| 581200 | 出行人不存在 | 传了无效的出行人 id(更新场景) |
| 401 | 未认证 | 未携带或微信 JWT 过期 |
| 403 | 无权限 | 当前用户无权操作该订单的出行人 |
## 8. 示例(3 组:典型 / 边界 / 异常)
### 8.1 典型成功 — 补全两位出行人(成人 + 儿童,含 birthday,不传 travelerType)
请求:POST /v3/internal/mp/order/2067178767255560193/traveler/batch-edit,Authorization: Bearer <mp-token>
请求体示例:
```json
{
"travelers": [
{
"id": null,
"name": "张三",
"gender": "1",
"birthday": "1990-05-20",
"idType": "ID_CARD",
"idNo": "110101199005201234"
},
{
"id": null,
"name": "张小宝",
"gender": "1",
"birthday": "2019-08-10",
"idType": "BIRTH_CERT",
"idNo": "P110101201908101234"
}
]
}
```
响应示例:
```json
{
"code": 200,
"data": [
{
"id": "2067178767255560201",
"orderId": "2067178767255560193",
"travelerType": "ADULT",
"travelerTypeName": "成人",
"name": "张三",
"birthday": "1990-05-20",
"idType": "ID_CARD",
"idTypeName": "身份证",
"idCardMasked": "110***********1234",
"gender": "1"
},
{
"id": "2067178767255560202",
"orderId": "2067178767255560193",
"travelerType": "CHILD",
"travelerTypeName": "儿童",
"name": "张小宝",
"birthday": "2019-08-10",
"idType": "BIRTH_CERT",
"idTypeName": "出生证明",
"idCardMasked": "P1101012019****1234",
"gender": "1"
}
],
"message": "ok",
"success": true
}
```
### 8.2 边界情况 — 幼童(birthday 未满 2 周岁,派生 BABY)
请求体示例:
```json
{
"travelers": [
{
"id": null,
"name": "李小婴",
"gender": "2",
"birthday": "2025-06-01",
"idType": "BIRTH_CERT",
"idNo": "P110101202506011234"
}
]
}
```
响应示例:
```json
{
"code": 200,
"data": [
{
"id": "2067178767255560210",
"orderId": "2067178767255560193",
"travelerType": "BABY",
"travelerTypeName": "幼童",
"name": "李小婴",
"birthday": "2025-06-01",
"idType": "BIRTH_CERT",
"idTypeName": "出生证明",
"idCardMasked": "P1101012025****1234",
"gender": "2"
}
],
"message": "ok",
"success": true
}
```
### 8.3 业务失败 — birthday 缺失,报出生日期不能为空
请求体示例(缺少 birthday):
```json
{
"travelers": [
{
"name": "王五",
"gender": "1"
}
]
}
```
响应示例:
```json
{
"code": 400,
"data": null,
"message": "出生日期不能为空",
"success": false
}
```
## 9. 业务边界
- 适用:用户已登录且有权限操作该订单,且订单处于可编辑出行人的状态时可调用。
- 不适用:订单已完成(COMPLETED)或已取消(CANCELLED)后,出行人信息不可再写入。
- 特殊边界:birthday 为整周岁当天(如刚满 2 岁、7 岁、18 岁生日当天)时,当天即按新档位计算(满龄升档)。
- 特殊边界:如果小程序端表单中仍有 travelerType 字段的存储或传入,不影响功能(后端忽略),建议同步清理。
- 特殊边界:birthday 只允许不晚于今天的日期,传入未来日期(包括明天)报 400。
- 特殊边界:birthday 格式须为 yyyy-MM-dd,格式错误报 400。
## 10. 修改前后对比
### 10.1 字段级对比(入参)
| 字段 | 改前 | 改后 |
|------|------|------|
| travelerType(入参) | 选填,由客户端传入,控制出行人类型 | 已移除,传入被忽略 |
| birthday(入参) | 选填 | 必填,不传报 400 |
### 10.2 字段级对比(出参,不变)
| 字段 | 改前 | 改后 |
|------|------|------|
| travelerType(出参) | 返回客户端传入值 | 返回后端按 birthday 派生值(语义不变) |
| travelerTypeName(出参) | 返回中文名 | 不变 |
| birthday(出参) | 原样返回 | 不变 |
### 10.3 行为级对比
| 行为 | 改前 | 改后 |
|------|------|------|
| 出行人类型来源 | 客户端传入 travelerType,后端直接存储 | 后端按 birthday 自动派生,客户端无需传 |
| birthday 必填性 | 选填,不传不报错 | 必填,不传报 400 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:是,birthday 改必填属破坏性变更。旧版小程序表单若未传 birthday,保存时报 400。
- **小程序是否必须同步上线**:是。调用 batch-edit 接口时,必须确保每个出行人对象带 birthday;原有 travelerType 入参代码可同步清理。
### 11.2 回滚方案
- **回滚方式**:revert PR #3981 并重新部署 hl-order-service-v3,恢复 travelerType 入参有效 + birthday 选填的旧行为。
## 12. 注意事项
- 出行人类型选择器如果仅用于控制 travelerType 入参,本次可直接移除,出行人类型由 birthday 派生后在响应中正常回显,展示无需调整。
- birthday 格式严格为 yyyy-MM-dd(如 1990-05-20),不接受时间戳或其他格式。
- 响应中的 travelerType / travelerTypeName 仍正常返回,出行人卡片上的类型标签展示逻辑无需改动。
- 年龄以服务器当天日期(北京时间)计算,生日当天视为满周岁。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#3976](https://git.1814.love:8443/wx/HL/issues/3976)
- **PR**: [#3981](https://git.1814.love:8443/wx/HL/pulls/3981)
- **Merge commit**: [8209c5702](https://git.1814.love:8443/wx/HL/commit/8209c5702)
### 13.2 联系人
- **后端负责人**: @yaosutu
@@ -0,0 +1,44 @@
# 【修改接口·小程序端】到达计划自驾时段 selfDrivePeriodLabel 文案口径含时间范围
> **PR**: #4061 | **服务**: hl-order-service-v3(经 mp-service 透传)| **更新时间**: 2026-06-19
## 1. 接口背景
大交通枚举改造(#4061)统一了自驾时段 `SelfDrivePeriod` 枚举的中文 label 口径,含时间范围。到达计划(mp)出参 `ArrivalPlanRespVO.selfDrivePeriodLabel` 随之变化。前端直接显示该 label,**无需改代码**,只是显示文案更详细了。
## 2. 变更清单
| 接口 | 方法 | 路径 | 变更 |
|---|---|---|---|
| 到达计划查询 | GET | /v3/internal/mp/order/arrival/{orderId} | 出参 selfDrivePeriodLabel 文案口径变化 |
(同枚举也用于 mp 创建/更新/批量接口的回显出参)
## 3. 出参变化
| 字段 | 类型 | 变更 | 说明 |
|---|---|---|---|
| selfDrivePeriodLabel | String | 文案口径调整 | 自驾时段中文,由「上午/下午/晚上」改为含时间范围 |
## 4. 枚举 / 数据字典
| selfDrivePeriod 码值 | 改前 label | 改后 label |
|---|---|---|
| MORNING | 上午 | **上午(06:00-12:00)** |
| AFTERNOON | 下午 | **下午(12:00-18:00)** |
| EVENING | 晚上 | **晚上(18:00-24:00)** |
## 5. 影响评估
- **破坏向后兼容**:否。`selfDrivePeriod` 码值不变,仅 `selfDrivePeriodLabel` 展示文案更详细。
- **前端是否需改**:否,前端直接展示 label 即可(显示内容自动变详细)。**例外**:若前端有按 label 文案做精确匹配/判断的逻辑(不推荐),需改为按 `selfDrivePeriod` 码值判断。
## 6. 注意事项
- 自驾时段判断逻辑请用 `selfDrivePeriod` 码值(MORNING/AFTERNOON/EVENING),不要依赖 `selfDrivePeriodLabel` 文案。
## 7. 关联 / 联系人
- **Issue**: [#4058](https://git.1814.love:8443/wx/HL/issues/4058)
- **PR**: [#4061](https://git.1814.love:8443/wx/HL/pulls/4061)
- **后端负责人**: @yaosutu
@@ -0,0 +1,65 @@
# 【修改接口·小程序端】客户出行人补全:订单确认后禁止 mp 端编辑(新增门禁 + 错误码 581145)(CR)
> **PR**: #4154 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-21
## 1. 接口背景
小程序客户出行人补全接口(batch-edit)此前**未在后端强制限制可编辑的订单阶段**:客户端只要订单属于本人,任意阶段都能提交编辑。本次安全/一致性收紧:**仅订单确认前(待支付 / 定制中)允许经小程序编辑出行人;订单确认后(待出行起)及已完成 / 已取消一律拒绝**,返回新错误码 `581145`。
收紧原因:订单确认后修改出行人 PII(姓名 / 手机 / 生日等)会误触发后端「合同作废重签 + 退保重投保」链路,造成非预期的合同与保单churn。证件号此前已在签约后冻结,本次把整个编辑动作按订单阶段收口。
> 本次为行为收紧(破坏性变更面向「确认后仍调用」的旧逻辑)。按产品生命周期,出行人补全本就发生在「待补全信息」窗口(定制中阶段),正常流程不受影响。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 客户出行人补全 | POST | /v3/internal/mp/order/{id}/traveler/batch-edit | 行为收紧 | 订单非「待支付/定制中」阶段调用直接拒绝(581145);入参 / 出参结构不变 |
## 3. 关键说明
- **放行阶段(白名单)**:`order_status ∈ {PENDING_PAY 待支付, CUSTOMIZING 定制中}`。
- **拒绝阶段**:`PENDING_DEPARTURE 待出行(确认后)/ TRAVELLING 出行中 / COMPLETED 已完成 / CANCELLED 已取消`,以及任何其他状态(白名单 fail-closed)。
- 拒绝时**整单不写入**(事务回滚),返回 `code=581145`。
- 入参字段、出参 VO 结构**完全不变**,仅新增前置阶段校验。
- 本门禁**只约束小程序(mp)路径**;定制师 / admin 后台路径不受限(如需确认后变更出行人,请走定制师后台)。
## 4. 入参 / 出参
入参(请求体 travelers[] + 路径 id)与响应 VO **均不变**,详见既有文档(如 #3976 出行人补全契约)。本次仅在订单阶段不满足时提前抛 581145。
## 5. 错误码
| code | 含义 | 触发场景 | 本次 |
|------|------|----------|------|
| **581145** | 订单已确认,出行人信息不可再经小程序修改,如需变更请联系定制师 | 订单 status 不在 {待支付, 定制中} 白名单(即确认后 / 已完成 / 已取消)时调用 batch-edit | **新增** |
| 581102 | 订单不存在,无法编辑出行人 | orderId 无效 | 不变 |
| 581122 | 订单不属于当前用户 | 当前登录 userId 与订单归属不一致(横向越权拦截) | 不变 |
## 6. 前端处理建议
- 出行人编辑入口建议按订单状态控制:仅在「待支付 / 定制中(待补全信息)」展示可编辑表单;订单确认后置为只读。
- 若仍调用 batch-edit 命中 581145,按 message 文案提示用户「订单已确认,如需修改出行人请联系定制师」,不要静默失败。
- 正常按生命周期编辑(确认前补全)的前端流程**无需改动**。
## 7. 业务边界
- 适用:订单 `order_status = PENDING_PAY` 或 `CUSTOMIZING`,且出行人属本人订单(581122 越权拦截照旧)。
- 不适用:订单确认后(PENDING_DEPARTURE 起)/ 已完成 / 已取消 —— 一律 581145 拒绝。
- 证件号(idNo)在合同已签(contract_status=SIGNED)时本就冻结(581111),本次门禁覆盖范围更靠前(按订单阶段整体拦截)。
## 8. 影响评估 / 回滚
- **向后兼容**:对「确认前编辑」的正常流程兼容;对「确认后仍调用 batch-edit」的旧行为为破坏性收紧(此前会误触发重签,属应修缺陷)。
- **小程序是否必须同步上线**:建议同步——确认后隐藏 / 禁用编辑入口 + 处理 581145 文案;不同步也不会造成数据错误(后端已兜底拒绝)。
- **回滚**:revert PR #4154 重新部署 hl-order-service-v3,恢复不限阶段编辑的旧行为。
## 9. 关联 / 联系人
### 9.1 链接
- **PR**: [#4154](https://git.1814.love:8443/wx/HL/pulls/4154)(CR 发现,无关联 Issue)
### 9.2 联系人
- **后端负责人**: @wx
@@ -0,0 +1,241 @@
# 发票补齐 - 小程序端申请 + 可见性过滤 + 签名下载(小程序端)
> Issue: [#4174](https://git.1814.love:8443/wx/HL/issues/4174) / [#4182](https://git.1814.love:8443/wx/HL/issues/4182)
> PR: [#4181](https://git.1814.love:8443/wx/HL/pulls/4181)(mp 端申请+可见性)/ [#4184](https://git.1814.love:8443/wx/HL/pulls/4184)(签名下载)
> 日期: 2026-06-21
> 服务: hl-order-service-v3(invoice 域)
> 端类型: 小程序端
---
## 1. 接口背景
小程序发票模块本次补齐三项改动:
- **申请门槛收紧**(PR4 / Issue #4174):原 collab 域 POST /v3/internal/mp/order/{orderId}/invoice/apply 路径不变,但实现从 collab 迁入 invoice 域,门槛由宽松(可叠加多张)改为严格(一单一票 + 订单必须 COMPLETED + 金额不超订单总价)。
- **出参可见性过滤**(PR4):GET /v3/internal/mp/order/{orderId}/invoice/list 和 GET /v3/internal/mp/order/invoice/{invoiceId}/detail 出参中,fileUrl 字段现在仅在 ISSUED / PUSHED 状态时返回;REQUESTED 状态返回 null(处理中,前端勿展示 PDF 链接)。
- **新增签名下载端点**(#4184 / Issue #4182):GET /v3/internal/mp/order/invoice/{invoiceId}/download,返回 1 小时有效期 OSS 签名 URL,供前端调 wx.openDocument 预览或下载发票 PDF。
---
## 2. 变更清单
| # | 接口 | 变更类型 | 说明 |
|---|------|----------|------|
| 1 | POST /v3/internal/mp/order/{orderId}/invoice/apply | 修改接口(行为收紧) | 申请门槛由宽松改严格:一单一票 + 订单 COMPLETED + 金额不超总价;resp status 字段值从 APPLIED 改为 REQUESTED |
| 2 | GET /v3/internal/mp/order/{orderId}/invoice/list | 修改接口(字段行为变化) | fileUrl 字段:REQUESTED 状态由有值改为 null;ISSUED / PUSHED 保持有值 |
| 3 | GET /v3/internal/mp/order/invoice/{invoiceId}/detail | 修改接口(字段行为变化) | fileUrl 字段同上:REQUESTED 返 null,ISSUED / PUSHED 有值 |
| 4 | GET /v3/internal/mp/order/invoice/{invoiceId}/download | 新增接口 | 返回发票 PDF 的 OSS 签名下载 URL(1 小时有效期),含 IDOR 鉴权 |
---
## 3. 接口详情
认证:所有接口走小程序 JWT 认证,Header 携带 Authorization: Bearer token(小程序 openId → userId)。
幂等性:apply 非幂等(一单一票,重复提交报 581511);download 幂等(每次生成新签名 URL)。
限流:网关全局限流。
---
## 4. 接口入参
### 4.1 路径参数 / Query 参数
| 接口 | 参数名 | 类型 | 必填 | 说明 |
|------|--------|------|------|------|
| POST /{orderId}/apply | orderId | Long | 是 | 路径参数,订单 ID |
| GET /{orderId}/invoice/list | orderId | Long | 是 | 路径参数,订单 ID |
| GET /invoice/{invoiceId}/detail | invoiceId | Long | 是 | 路径参数,发票 ID |
| GET /invoice/{invoiceId}/download | invoiceId | Long | 是 | 路径参数,发票 ID |
### 4.2 请求体字段
**POST /v3/internal/mp/order/{orderId}/invoice/apply**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| amount | String | 是 | 开票金额(字符串,单位元),不超过订单总价 |
| invoiceType | String | 是 | 发票类型,枚举见 6 节 |
| titleType | String | 是 | 抬头类型:PERSONAL / COMPANY |
| title | String | 是 | 发票抬头(姓名或公司名) |
| taxNo | String | 条件必填 | 税号(titleType=COMPANY 时必填) |
| bankName | String | 条件必填 | 开户行(invoiceType=VAT_SPECIAL 时必填) |
| bankAccount | String | 条件必填 | 银行账号(invoiceType=VAT_SPECIAL 时必填) |
| registAddress | String | 条件必填 | 注册地址(invoiceType=VAT_SPECIAL 时必填) |
| registPhone | String | 条件必填 | 注册电话(invoiceType=VAT_SPECIAL 时必填) |
| email | String | 条件必填 | 收票邮箱(invoiceType=ELECTRONIC 时必填) |
| remark | String | 否 | 备注 |
GET 接口无请求体。
---
## 5. 出参字段
**POST /v3/internal/mp/order/{orderId}/invoice/apply**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | String | 新建发票 ID(Long 序列化) |
| status | String | 固定为 REQUESTED |
注意:status 值此前旧实现返回 APPLIED(collab 域),新实现返回 REQUESTED(invoice 域)。请前端对齐新值。
**GET /v3/internal/mp/order/{orderId}/invoice/list(单条字段,变化部分)**
| 字段 | 原来行为 | 现在行为 |
|------|---------|---------|
| fileUrl | REQUESTED / ISSUED / PUSHED 均有值 | REQUESTED 返 null;ISSUED / PUSHED 有值 |
其余字段不变(id / orderId / status / statusName / amount / invoiceType / title / taxNo / createTime 等)。
**GET /v3/internal/mp/order/invoice/{invoiceId}/detail(变化部分)**
| 字段 | 原来行为 | 现在行为 |
|------|---------|---------|
| fileUrl | 同上,恒有值 | REQUESTED 返 null;ISSUED / PUSHED 有值 |
**GET /v3/internal/mp/order/invoice/{invoiceId}/download(新增接口)**
| 字段 | 类型 | 说明 |
|------|------|------|
| fileUrl | String | OSS 签名下载 URL(1 小时有效期,格式为 HTTPS 带签名参数的 URL) |
| pdfName | String | PDF 文件名(可选,用于 wx.openDocument 的 name 参数) |
---
## 6. 枚举 / 数据字典
**InvoiceStatus - 发票状态(影响 fileUrl 可见性)**
| 枚举值 | 中文名 | fileUrl 是否可见 |
|--------|--------|----------------|
| REQUESTED | 待开票 | null(处理中,前端勿展示 PDF 链接) |
| ISSUED | 已开票 | 有值 |
| PUSHED | 已推送 | 有值 |
| VOIDED | 已作废 | null |
**InvoiceType - 发票类型**
| 枚举值 | 中文名 |
|--------|--------|
| VAT_NORMAL | 增值税普通发票 |
| VAT_SPECIAL | 增值税专用发票 |
| ELECTRONIC | 电子发票 |
**TitleType - 抬头类型**
| 枚举值 | 中文名 |
|--------|--------|
| PERSONAL | 个人 |
| COMPANY | 公司 |
---
## 7. 错误码
| 错误码 | 常量 | 触发场景 |
|--------|------|----------|
| 581510 | INVOICE_ORDER_NOT_COMPLETED | 订单状态非 COMPLETED,不可申请开票 |
| 581511 | INVOICE_ALREADY_EXISTS | 该订单已有有效发票,不可重复申请(一单一票) |
| 581512 | INVOICE_AMOUNT_EXCEED | 开票金额超过订单总价 |
| 581513 | INVOICE_TYPE_INVALID | 发票类型枚举值非法 |
| 581514 | INVOICE_TAX_NO_REQUIRED | 公司抬头 / 专票时税号为必填 |
| 581515 | INVOICE_VAT_SPECIAL_FIELDS_REQUIRED | 专票时开户行 / 银行账号 / 注册地址 / 注册电话为必填 |
| 581516 | INVOICE_EMAIL_REQUIRED | 电子发票时邮箱为必填 |
| 581517 | INVOICE_NOT_DOWNLOADABLE | 发票尚未开具(REQUESTED / VOIDED 状态),暂时无法下载 |
| 581518 | INVOICE_FORBIDDEN | 无权访问该发票(IDOR 防护,含发票不存在场景) |
| 581519 | INVOICE_SIGNED_URL_FAILED | 获取签名下载 URL 失败,请稍后重试(hl-user-service 暂时不可用) |
---
## 8. 示例
### 8.1 典型成功:申请开票
POST /v3/internal/mp/order/1234567890123456789/invoice/apply
请求体:
响应:
### 8.2 边界情况:列表中 REQUESTED 状态 fileUrl 为 null
GET /v3/internal/mp/order/1234567890123456789/invoice/list 响应示例(某张待开票发票):
### 8.3 业务失败:REQUESTED 状态发票不可下载
GET /v3/internal/mp/order/invoice/111/download
响应:
---
## 9. 业务边界
**适用:**
- 申请:订单状态必须为 COMPLETED;无有效发票(一单一票);金额不超订单总价
- 下载:发票状态为 ISSUED 或 PUSHED;且该发票属于当前登录用户的订单
**不适用:**
- 订单 COMPLETED 之前不可申请
- 已有有效发票,不可重复申请
- REQUESTED / VOIDED 状态发票不可下载(报 581517)
- 访问他人订单的发票报 581518(IDOR 防护,不返回 404 以避免泄露存在性)
**特殊边界:**
- 签名 URL 有效期 1 小时。前端如果缓存了 fileUrl,每次打开下载前须重新调 download 接口获取最新签名 URL,不可长期复用。
- wx.openDocument 下载后端直接返回签名 URL,前端无需中转。
---
## 10. 修改前后对比
### POST apply 申请门槛变化
| 项目 | 变更前(旧 collab 实现) | 变更后(invoice 域) |
|------|----------------------|-------------------|
| 一单一票限制 | 无(可叠加多张) | 有(existsActiveByOrderId 拦截) |
| 金额校验 | 已开+本次 <= 总价 | 本次金额 <= 总价(一单一票前提下等价) |
| 响应 status 值 | APPLIED | REQUESTED |
### GET list / detail fileUrl 可见性变化
| 发票状态 | 变更前 fileUrl | 变更后 fileUrl |
|---------|--------------|--------------|
| REQUESTED | 有值(OSS 公链) | null(前端显示处理中) |
| ISSUED | 有值 | 有值(不变) |
| PUSHED | 有值 | 有值(不变) |
| VOIDED | 有值 | null |
---
## 11. 影响评估 / 回滚
- 破坏兼容性(重要):fileUrl 字段在 REQUESTED 状态下由有值变为 null。前端如果之前有展示 REQUESTED 状态下 PDF 链接的逻辑(点击打开 OSS 文件),现在会读到 null,需要做 null 判断,展示「处理中」状态文案。
- apply status 值变化:从 APPLIED 改为 REQUESTED。前端如果有对 status 值做 hardcode 判断(if status == APPLIED),需要更新。
- 前端同步上线建议:fileUrl null 判断 + apply 响应 status 对齐必须在本次版本同步更新。
- 回滚方案:回滚旧版本,fileUrl 可见性恢复,download 端点返回 404。apply 的 status 回退为 APPLIED(如旧版本有此值)。
---
## 12. 注意事项
1. fileUrl null 判断:list / detail 接口读到 fileUrl 为 null 时,前端应显示「处理中」或「待开票」而不是空链接。
2. 签名 URL 勿缓存超过 1 小时:download 返回的签名 URL 有效期 1 小时,前端每次用前须重新调接口,不可全局缓存复用。
3. apply 响应 status 值变更:旧值 APPLIED 已废弃,现在返回 REQUESTED。如前端有 switch/if 判断该值,须对齐。
4. download IDOR 防护:发票不存在或不属于当前用户均返回 581518(INVOICE_FORBIDDEN),不返回 404,避免存在性枚举攻击。
---
## 13. 关联 / 联系人
- Issue(小程序端 mp): https://git.1814.love:8443/wx/HL/issues/4174
- Issue(签名下载): https://git.1814.love:8443/wx/HL/issues/4182
- PR(mp 端 #4181): https://git.1814.love:8443/wx/HL/pulls/4181
- PR(签名下载 #4184): https://git.1814.love:8443/wx/HL/pulls/4184
- 后端负责人: yaosutu
@@ -0,0 +1,340 @@
# 售后申诉 — 小程序端新增接口
- **端类型**:小程序端
- **变更类型**:新增接口
- **日期**:2026-06-22
- **关联 Issue**:https://git.1814.love:8443/wx/HL/issues/4161
- **关联 PR**:#4185(小程序端接口)/ #4162 #4165 #4168 #4187(基础能力)
- **后端负责人**:腰苏图(yaosutu)
---
## 一、接口背景
v3 全新售后服务中心(com.hulalv.aftersale)上线。小程序端用户可发起投诉或申诉、查看自己的工单列表与详情、以及在工单未处置前随时撤回。
新增 4 个接口(含 1 个原有但归入本域):发起工单、我的工单列表、工单详情、撤回工单。
本次为全新域,不影响任何已有接口。
---
## 二、变更清单
| 编号 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 1 | POST | /v3/mp/aftersale/ticket | 发起投诉/申诉工单 |
| 2 | GET | /v3/mp/aftersale/ticket/my | 我的工单列表(按订单分页) |
| 3 | GET | /v3/mp/aftersale/ticket/{id} | 工单详情 |
| 4 | POST | /v3/mp/aftersale/ticket/{id}/withdraw | 撤回工单 |
---
## 三、接口详情
| 属性 | 说明 |
|------|------|
| 认证方式 | JWT Bearer Token(C 端 Token,Gateway 解析后注入 userId) |
| userId 传递 | Gateway 解析 JWT 后注入到请求属性,后端从 HttpServletRequest 取;前端无需传 userId 字段 |
| 限流 | Gateway 默认限流策略 |
| 路径前缀 | /v3/mp/aftersale/ticket |
---
## 四、接口入参
### 4.1 POST /v3/mp/aftersale/ticket — 发起工单
请求体(JSON):
| 字段 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|
| orderId | Long | 是 | — | 订单 ID |
| category | String | 是 | COMPLAINT / APPEAL | 大类:投诉/申诉 |
| type | String | 是 | 见 §六枚举 | 细分类型,必须与 category 匹配 |
| title | String | 是 | 最多 100 字 | 工单标题 |
| description | String | 是 | 最多 2000 字 | 诉求描述 |
| targetRefId | Long | 条件必填 | — | 申诉时必填:关联退款申请 ID;投诉时可不传(不传则用 orderId) |
| claimType | String | 否 | REFUND / RECTIFY / EXPLANATION | 用户诉求类型,仅供参考 |
| claimAmount | Number | 否 | — | 用户期望金额,仅供参考,无约束力 |
| attachments | Array<String> | 否 | 最多 10 个 | 附件 URL 列表(图片/视频) |
### 4.2 GET /v3/mp/aftersale/ticket/my — 我的工单列表
Query 参数:
| 字段 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|
| orderId | Long | 是 | — | 订单 ID,只查该订单下的工单 |
| pageNo | Integer | 否 | >= 1 | 页码,默认 1 |
| pageSize | Integer | 否 | 1-50 | 每页条数,默认 20 |
### 4.3 GET /v3/mp/aftersale/ticket/{id} — 工单详情
路径参数:id(String/Long)必填,工单 ID。
注:后端校验工单归属,非本人工单返回 586014。
### 4.4 POST /v3/mp/aftersale/ticket/{id}/withdraw — 撤回工单
路径参数:id(String/Long)必填,工单 ID。
无请求体。后端校验:1. 工单归属(非本人返回 586014);2. 状态(只有 SUBMITTED / PROCESSING 可撤回,否则返回 586013)。
---
## 五、出参字段
### 5.1 发起工单 — 返回工单 ID
```json
{"code": 200, "data": "1895000000000001"}
```
data 为 String(Long),即新建工单的 ID。
### 5.2 我的工单列表 — PageResult 结构
```json
{
"code": 200,
"data": {
"list": [],
"total": 5,
"pageNo": 1,
"pageSize": 20
}
}
```
### 5.3 工单详情及列表行 — TicketMpRespVO 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| id | String(Long) | 工单 ID |
| orderId | String(Long) | 关联订单 ID |
| category | String | 大类枚举值:COMPLAINT / APPEAL |
| categoryLabel | String | 大类中文名:投诉 / 申诉 |
| type | String | 细分类型枚举值,见 §六 |
| typeLabel | String | 细分类型中文名 |
| title | String | 工单标题 |
| description | String | 诉求描述 |
| claimType | String | 用户诉求类型(可选) |
| claimAmount | Number | 用户期望金额(可选) |
| attachments | Array<String> | 附件 URL 列表 |
| status | String | 工单状态枚举值,见 §六 |
| statusLabel | String | 工单状态中文名 |
| resolutionRemark | String | 处置说明(RESOLVED / CLOSED 后可见,用于展示给用户) |
| canWithdraw | Boolean | 是否可撤回(SUBMITTED / PROCESSING 且非终态时为 true) |
| createdAt | String(ISO 8601) | 创建时间 |
| updatedAt | String(ISO 8601) | 更新时间 |
注:C 端视图隐藏处置细节(decision / resolutionType / resolutionAmount / approvalNo / linkedRefundId),仅展示 status 和 resolutionRemark。
### 5.4 撤回工单
```json
{"code": 200, "data": null}
```
---
## 六、枚举 / 数据字典
### AftersaleCategory — 工单大类
| 枚举值 | 中文名 | 场景 |
|--------|--------|------|
| COMPLAINT | 投诉 | 对已发生的服务质量不满 |
| APPEAL | 申诉 | 对某个处理结果不服,求复核 |
### AftersaleTicketType — 细分类型(type 字段)
| 枚举值 | 中文名 | 归属大类 |
|--------|--------|----------|
| ITINERARY | 行程 | COMPLAINT |
| HOTEL | 酒店 | COMPLAINT |
| VEHICLE | 车 | COMPLAINT |
| GUIDE | 导游 | COMPLAINT |
| OTHER | 其他 | COMPLAINT |
| REFUND_REJECTED | 退款被拒 | APPEAL |
| REFUND_AMOUNT_DISPUTE | 退款金额异议 | APPEAL |
注:type 必须与 category 匹配,否则返回 586012。
### AftersaleTicketStatus — 工单状态
| 枚举值 | 中文名 | 终态 | 说明 |
|--------|--------|------|------|
| SUBMITTED | 已提交 | 否 | 等待受理 |
| PROCESSING | 处理中 | 否 | 客服受理中 |
| RESOLVED | 已处置 | 否 | 处置方案落定(退款类等待到账) |
| CLOSED | 已关闭 | 是 | 流程终结 |
| WITHDRAWN | 已撤回 | 是 | 用户主动撤回 |
canWithdraw = true 的条件:status 为 SUBMITTED 或 PROCESSING。
### claimType — 用户诉求类型(参考值,无强制约束)
| 常见值 | 中文名 |
|--------|--------|
| REFUND | 退款 |
| RECTIFY | 整改 |
| EXPLANATION | 要个说法 |
---
## 七、错误码
| 错误码 | 说明 | 触发场景 |
|--------|------|----------|
| 586009 | 工单不存在 | 传入 id 找不到工单 |
| 586011 | 同一对象已存在活跃工单 | 防重复提交(同订单下同 target 已有进行中工单) |
| 586012 | category 与 type 不匹配 | 如 COMPLAINT 传了 REFUND_REJECTED |
| 586013 | 撤回时状态非法 | 终态或 RESOLVED 工单不可撤回 |
| 586014 | 非本人工单 | 查看/撤回他人工单 |
| 586015 | 申诉必须关联退款申请 | APPEAL 类工单未传 targetRefId |
| 586016 | 申诉关联退款状态不合法 | 关联的退款申请状态不允许申诉 |
---
## 八、示例
### 8.1 典型成功 — 发起投诉工单
请求:
```
POST /v3/mp/aftersale/ticket
Authorization: Bearer {mp_token}
Content-Type: application/json
{
"orderId": 1800000000000099,
"category": "COMPLAINT",
"type": "HOTEL",
"title": "酒店降级投诉",
"description": "订单挂四星酒店实际入住三星,要求退差价",
"claimType": "REFUND",
"claimAmount": 600.00,
"attachments": ["https://oss.example.com/img1.jpg"]
}
```
响应:
```json
{"code": 200, "data": "1895000000000001"}
```
### 8.2 典型成功 — 发起申诉工单(退款被拒)
```
POST /v3/mp/aftersale/ticket
Authorization: Bearer {mp_token}
Content-Type: application/json
{
"orderId": 1800000000000099,
"category": "APPEAL",
"type": "REFUND_REJECTED",
"targetRefId": 9876543210,
"title": "退款申请被拒申诉",
"description": "退款申请被拒,但供应商确实未提供服务,要求重新审核"
}
```
响应:
```json
{"code": 200, "data": "1895000000000002"}
```
### 8.3 边界情况 — 查询工单详情(已处置,展示处置说明)
```json
{
"code": 200,
"data": {
"id": "1895000000000001",
"orderId": "1800000000000099",
"category": "COMPLAINT",
"categoryLabel": "投诉",
"type": "HOTEL",
"typeLabel": "酒店",
"title": "酒店降级投诉",
"description": "订单挂四星酒店实际入住三星,要求退差价",
"claimType": "REFUND",
"claimAmount": 600.00,
"attachments": ["https://oss.example.com/img1.jpg"],
"status": "CLOSED",
"statusLabel": "已关闭",
"resolutionRemark": "经核实酒店确实降级,已退差价 500 元",
"canWithdraw": false,
"createdAt": "2026-06-22T09:00:00",
"updatedAt": "2026-06-22T15:30:00"
}
}
```
### 8.4 业务失败 — 申诉未传 targetRefId
```json
{"code": 586015, "msg": "申诉必须关联一笔有效的退款申请"}
```
### 8.5 业务失败 — 撤回已 CLOSED 工单
```json
{"code": 586013, "msg": "撤回时工单状态非法(只有 SUBMITTED / PROCESSING 可撤回)"}
```
---
## 九、业务边界
适用:
- 同一订单下同一 targetRef 只能有一个活跃工单(SUBMITTED / PROCESSING / RESOLVED),否则返回 586011
- 申诉(APPEAL)类工单必须关联一笔有效的退款申请(targetRefId 必填)
- SUBMITTED / PROCESSING 状态的工单可撤回,canWithdraw=true
不适用:
- 终态工单(CLOSED / WITHDRAWN)不可撤回
- 非本人工单不可查看/撤回
特殊边界:
- 工单从 PROCESSING 撤回后,若该工单已提交企微 OA,后端会自动撤回 OA 审批(异步,不影响前端响应)
- attachments 最多 10 个,超出返回参数校验错误
---
## 十、修改前后对比
本次为全新域新增接口,无旧接口对比。
---
## 十一、影响评估 / 回滚
本次为全新域,不影响任何已有小程序接口,可独立上线。
回滚方案:回滚后端服务版本即可。
---
## 十二、注意事项
1. 发起工单返回值是 String(Long):data 字段为新建工单的 ID,是字符串而非数字。
2. C 端视图隐藏处置细节:resolutionAmount / decision / approvalNo 等字段在 C 端不返回,不要在小程序页面展示。resolutionRemark 是给用户看的处置说明,可展示。
3. canWithdraw 字段已由后端计算:前端直接用该字段判断是否显示撤回按钮,无需自行判断状态。
4. 所有 ID 为字符串:id / orderId 均序列化为字符串,前端不要转 Number。
5. category=APPEAL 时:targetRefId 必填(关联退款申请 ID),targetRefType 后端自动设为 REFUND_APPLICATION。
---
## 十三、关联 / 联系人
- Issue:https://git.1814.love:8443/wx/HL/issues/4161
- PR #4185(小程序端接口):https://git.1814.love:8443/wx/HL/pulls/4185
- PR #4162(售后基建):https://git.1814.love:8443/wx/HL/pulls/4162
- PR #4165(受理/处置 + OA 接入):https://git.1814.love:8443/wx/HL/pulls/4165
- PR #4168(OA 回调内部接口):https://git.1814.love:8443/wx/HL/pulls/4168
- PR #4187(退款驱动联动):https://git.1814.love:8443/wx/HL/pulls/4187
- 后端负责人:腰苏图(yaosutu)
@@ -0,0 +1,341 @@
# 售后工单接入 wx 内容安全机审 — 修改接口(小程序端)
- **端类型**:小程序端
- **日期**:2026-06-22
- **Issue**:[#4196](https://git.1814.love:8443/wx/HL/issues/4196)
- **PR**:[#4203](https://git.1814.love:8443/wx/HL/pulls/4203)
- **Commit**:[8882eb156](https://git.1814.love:8443/wx/HL/commit/8882eb1568a7e5ab8f48a6db4b7e3d4d4b6f2c15)
- **后端负责人**:yaosutu
---
## 1. 接口背景
用户在小程序发起售后工单(投诉/申诉)时,若附带图片或视频,前端需先通过微信内容安全 `msgSecCheck` 接口对媒体文件做内容审核,得到微信返回的 `traceId` 后,连同创建工单请求一并透传给后端。后端不直接调用微信安全接口,只存储 traceId,等待微信异步回调后更新审核状态。无图/无视频的工单跳过机审,直接置为 `APPROVED`。
---
## 2. 变更清单
| 变更类型 | 接口 | 字段 | 说明 |
|---------|------|------|------|
| ⚠️ 入参新增 | `POST /v3/mp/aftersale/ticket` | `mediaTraceIds` | 新增可选字段,机审 traceId 数组,最多 12 个 |
| ✨ 出参新增 | `GET /v3/mp/aftersale/ticket/{id}` | `auditStatus` | 工单 wx 内容安全机审状态 |
| ✨ 出参新增 | `GET /v3/mp/aftersale/ticket/list` | `auditStatus` | 工单列表每条记录新增机审状态 |
---
## 3. 接口详情
### 3.1 发起售后工单
| 属性 | 值 |
|-----|-----|
| 方法 + 路径 | `POST /v3/mp/aftersale/ticket` |
| 接口描述 | 用户发起售后工单(投诉/申诉),支持附件 + 机审 traceId 透传 |
| 认证 | 需要用户 JWT(小程序登录 token) |
| 幂等性 | 非幂等,每次调用创建一条新工单 |
| 限流 | 无独立限流(受网关全局限流) |
### 3.2 工单详情
| 属性 | 值 |
|-----|-----|
| 方法 + 路径 | `GET /v3/mp/aftersale/ticket/{id}` |
| 接口描述 | 获取单条售后工单详情 |
| 认证 | 需要用户 JWT,仅可查自己的工单 |
| 限流 | 无独立限流 |
### 3.3 工单列表
| 属性 | 值 |
|-----|-----|
| 方法 + 路径 | `GET /v3/mp/aftersale/ticket/list` |
| 接口描述 | 查询当前用户的售后工单列表(分页) |
| 认证 | 需要用户 JWT |
| 限流 | 无独立限流 |
---
## 4. 接口入参
### 4.1 路径参数 / Query 参数
`GET /v3/mp/aftersale/ticket/{id}`
| 参数名 | 类型 | 必填 | 说明 |
|-------|------|------|------|
| id | Long | 是 | 工单 ID |
### 4.2 请求体字段(POST /v3/mp/aftersale/ticket)
| 字段名 | 类型 | 必填 | 校验 | 说明 |
|-------|------|------|------|------|
| orderId | Long | 是 | 不能为空 | 关联订单 ID |
| category | String | 是 | 枚举:COMPLAINT / APPEAL | 工单分类:投诉 / 申诉 |
| type | String | 是 | 枚举,见 §6 | 具体类型(如 HOTEL / GUIDE / PRICE) |
| title | String | 是 | max=100 | 工单标题 |
| description | String | 是 | max=2000 | 问题描述 |
| attachments | List\<String\> | 否 | max=10 | 附件 URL 列表(图片/视频) |
| **mediaTraceIds** | **List\<String\>** | **否** | **max=12** | **微信内容安全 traceId 数组(前端透传,后端只存)** |
> `mediaTraceIds` 与 `attachments` 一一对应关系由前端维护。后端不校验对应关系,仅存储用于异步机审回流。无附件时可不传或传空数组。
---
## 5. 出参字段
### TicketMpRespVO(工单详情/列表单条)
| 字段名 | 类型 | 说明 |
|-------|------|------|
| id | Long | 工单 ID |
| orderId | Long | 关联订单 ID |
| orderNo | String | 订单编号 |
| category | String | 工单分类枚举:COMPLAINT / APPEAL |
| type | String | 工单类型 |
| title | String | 标题 |
| description | String | 描述 |
| status | String | 工单状态:SUBMITTED / PROCESSING / RESOLVED / CLOSED / WITHDRAWN |
| statusName | String | 工单状态中文名 |
| canWithdraw | Boolean | 是否可撤回 |
| **auditStatus** | **String** | **wx 内容安全机审状态,取值见 §6** |
| attachments | List\<String\> | 附件 URL |
| createdAt | String | 创建时间(ISO 8601) |
| updatedAt | String | 更新时间(ISO 8601) |
---
## 6. 枚举 / 数据字典
### auditStatus — wx 内容安全机审状态
| 值 | 含义 | 触发条件 |
|----|------|---------|
| `PENDING` | 机审中 | 创建工单时有 mediaTraceIds(异步等待微信回调) |
| `APPROVED` | 已通过 | 无 mediaTraceIds 的工单直接置此(免审);微信回调结果合规也置此 |
| `MANUAL_REVIEW` | 人工复审 | 微信机审认为需人工介入 |
| `REJECTED` | 已驳回 | 微信机审判定内容违规 |
> **重要**:`PENDING` 状态为异步,工单创建成功后微信回调可能在数秒到数分钟内到达。前端建议在工单详情页轮询或基于页面刷新展示最新状态,不要把 `PENDING` 当作错误。
### category — 工单分类
| 值 | 含义 |
|----|------|
| `COMPLAINT` | 投诉 |
| `APPEAL` | 申诉 |
---
## 7. 错误码
| 错误码 | HTTP 状态 | 含义 | 触发场景 |
|-------|---------|------|---------|
| 581001 | 400 | 工单关联订单不存在 | orderId 无效 |
| 581002 | 400 | 工单已存在,不可重复提交 | 同一订单同分类已有活跃工单 |
| 581003 | 400 | 订单状态不允许发起售后 | 订单未处于可售后状态 |
| 200-001 | 401 | 未授权 | JWT 缺失或过期 |
| 200-002 | 403 | 无权操作 | 工单不属于当前用户 |
---
## 8. 示例
### 8.1 典型成功——带图片机审
**请求**
```http
POST /v3/mp/aftersale/ticket
Authorization: Bearer <user-jwt>
Content-Type: application/json
{
"orderId": 1234567890,
"category": "COMPLAINT",
"type": "HOTEL",
"title": "酒店降级安排",
"description": "预订了四星酒店,实际安排了三星,差价未退。",
"attachments": [
"https://oss.example.com/media/hotel_photo_1.jpg",
"https://oss.example.com/media/hotel_photo_2.jpg"
],
"mediaTraceIds": [
"trace_abc123def456",
"trace_xyz789uvw012"
]
}
```
**响应**
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 987654321,
"orderId": 1234567890,
"orderNo": "HL20260622001",
"category": "COMPLAINT",
"type": "HOTEL",
"title": "酒店降级安排",
"description": "预订了四星酒店,实际安排了三星,差价未退。",
"status": "SUBMITTED",
"statusName": "已提交",
"canWithdraw": true,
"auditStatus": "PENDING",
"attachments": [
"https://oss.example.com/media/hotel_photo_1.jpg",
"https://oss.example.com/media/hotel_photo_2.jpg"
],
"createdAt": "2026-06-22T10:30:00",
"updatedAt": "2026-06-22T10:30:00"
}
}
```
> `auditStatus` 初始为 `PENDING`,等待微信异步回调后更新为 `APPROVED` / `MANUAL_REVIEW` / `REJECTED`。
### 8.2 边界情况——无附件工单(直接 APPROVED)
**请求**
```http
POST /v3/mp/aftersale/ticket
Authorization: Bearer <user-jwt>
Content-Type: application/json
{
"orderId": 1234567890,
"category": "APPEAL",
"type": "PRICE",
"title": "价格异议",
"description": "行程中临时要求加收费用,合同未约定。",
"attachments": [],
"mediaTraceIds": []
}
```
**响应**
```json
{
"code": 200,
"msg": "success",
"data": {
"id": 987654322,
"orderId": 1234567890,
"orderNo": "HL20260622001",
"category": "APPEAL",
"type": "PRICE",
"title": "价格异议",
"description": "行程中临时要求加收费用,合同未约定。",
"status": "SUBMITTED",
"statusName": "已提交",
"canWithdraw": true,
"auditStatus": "APPROVED",
"attachments": [],
"createdAt": "2026-06-22T10:35:00",
"updatedAt": "2026-06-22T10:35:00"
}
}
```
> 无 mediaTraceIds 或传空数组时,`auditStatus` 直接为 `APPROVED`,无需等待回调。
### 8.3 业务失败——订单已有活跃工单
**请求**(同一订单同分类已存在未关闭工单)
```http
POST /v3/mp/aftersale/ticket
Authorization: Bearer <user-jwt>
Content-Type: application/json
{
"orderId": 1234567890,
"category": "COMPLAINT",
"type": "GUIDE",
"title": "导游服务差",
"description": "导游态度恶劣。",
"mediaTraceIds": []
}
```
**响应**
```json
{
"code": 581002,
"msg": "工单已存在,不可重复提交",
"data": null
}
```
---
## 9. 业务边界
**适用场景**:
- 订单处于可售后状态(已出行、出行中、已完成等,具体由后端校验)
- 有图片/视频附件时前端必须先完成 `wx.msgSecCheck` 得到 traceId 再调此接口
- 无附件或不需要机审时,`mediaTraceIds` 可省略或传空数组
**不适用场景**:
- 已取消订单不可发起售后
- 同一订单同分类已有活跃(非 CLOSED/WITHDRAWN)工单时,不可重复发起
**特殊边界**:
- `mediaTraceIds` 最多 12 个,超出返回参数校验错误
- `auditStatus` 为 `PENDING` 时工单照常流转(客服可正常处理),机审结果不阻塞工单流程
- `auditStatus` 为 `REJECTED` 时,仅作展示标记,工单处理流程由客服决定是否关闭
---
## 10. 修改前后对比
### 字段级对比
**CreateTicketReqVO(入参)**
| 字段 | 变更前 | 变更后 |
|------|-------|-------|
| mediaTraceIds | 不存在 | 新增,List\<String\>,可选,max=12 |
**TicketMpRespVO(出参)**
| 字段 | 变更前 | 变更后 |
|------|-------|-------|
| auditStatus | 不存在 | 新增,String,wx 机审状态 |
### 行为级对比
| 场景 | 变更前 | 变更后 |
|------|-------|-------|
| 带图片发起工单 | 无机审,无审核状态 | 存 traceId,初始 auditStatus=PENDING,微信异步回调更新 |
| 无图片发起工单 | 无机审状态字段 | auditStatus 直接置 APPROVED |
---
## 11. 影响评估 / 回滚
| 维度 | 结论 |
|------|------|
| 破坏兼容性 | 否(入参新增可选字段,旧版不传兼容;出参新增字段,旧版忽略) |
| 前端同步上线 | 建议同步:入参传 mediaTraceIds 发挥机审能力;出参展示 auditStatus |
| 回滚方案 | 后端回滚 PR #4203 即可,无 DDL 数据损失风险(DDL 只加列不删) |
---
## 12. 注意事项
1. `mediaTraceIds` 由前端在调用微信 `wx.msgSecCheck` 后获得,后端不直接调微信安全接口,只做存储和转发。
2. `auditStatus=PENDING` 是异步状态,不代表工单异常,客服后台可正常处理。
3. 历史工单(此 PR 上线前创建的)`auditStatus` 字段为 `null`,前端展示时建议视 `null` 等同于 `APPROVED` 处理。
4. 微信机审结果 `REJECTED` 不自动关闭工单,仅打标记,由客服决定后续处理。
---
## 13. 关联 / 联系人
- **Issue**:[https://git.1814.love:8443/wx/HL/issues/4196](https://git.1814.love:8443/wx/HL/issues/4196)
- **PR**:[https://git.1814.love:8443/wx/HL/pulls/4203](https://git.1814.love:8443/wx/HL/pulls/4203)
- **Commit**:[https://git.1814.love:8443/wx/HL/commit/8882eb1568a7e5ab8f48a6db4b7e3d4d4b6f2c15](https://git.1814.love:8443/wx/HL/commit/8882eb1568a7e5ab8f48a6db4b7e3d4d4b6f2c15)
- **关联 Issue**:[#4161 售后申诉中心](https://git.1814.love:8443/wx/HL/issues/4161)
- **后端负责人**:yaosutu
@@ -0,0 +1,31 @@
# 【修正·小程序】售后工单 mp 端接口加归属校验(防横向越权)
> 模块:order-v3 售后工单(aftersale)小程序端
> 类型:安全加固(每日审查驱动,新模块上线前修正)
> 影响端点:`/v3/mp/aftersale/ticket/**`(我的工单列表 / 详情 / 撤回)
> 关联:售后工单中心 PR1-5(#4162/#4165/#4168/#4173/#4185)的每日审查修正
> 测试服已部署验证(9443 实测端点 200)
## ⚠️ 关键说明
售后工单 mp 端三个用户入口此前缺少归属校验,任意登录用户传他人 `ticketId`/`orderId` 即可读取或撤回他人工单(横向越权 IDOR)。本次加固:**经订单归属校验当前用户是否为下单人**,非本人操作返回错误码 **586014(TICKET_NOT_OWN)**。
正常业务流程下,小程序用户只操作自己订单的售后工单,**不会触发**该错误;前端无需改动,仅需对 586014 做兜底提示(如「无权访问该工单」)。
## 1. 受影响端点与行为
| 端点 | 修正 |
|------|------|
| `GET /v3/mp/aftersale/ticket/my`(我的工单列表) | 新增按当前用户校验 `orderId` 归属;端点入参不变,仅服务端加校验 |
| `GET /v3/mp/aftersale/ticket/{id}`(工单详情) | 校验工单所属订单归属当前用户,非本人抛 586014 |
| `POST /v3/mp/aftersale/ticket/{id}/withdraw`(撤回) | 同上归属校验,非本人不可撤回(且不再触发他人 OA 审批撤销) |
## 2. 附带修正:撤回工单不再消失
撤回(WITHDRAWN)此前被误当软删处理,导致撤回后的工单在「我的工单」列表/详情中**永久不可见**。本次修正后,**撤回是可见终态**,撤回的工单仍可在列表与详情中查看(状态显示「已撤回」)。
## 3. 错误码
| code | 含义 |
|------|------|
| 586014 | 无权操作该售后工单(非本人订单)|
@@ -0,0 +1,222 @@
# 退款申诉(新增)+ 统一售后工单接口下线(小程序端)
- 端类型:小程序端
- 变更类型:新增接口(4)+ 删除接口(统一售后工单 mp 端)
- 关联 Issue:#4250 PR:#4251 #4254
- 日期:2026-06-23
---
## ① 接口背景
售后体系重构:原"投诉 + 申诉统一售后工单"方向作废,拆为**投诉**与**申诉**两套独立能力。
- **申诉**:用户对"退款被拒"或"退款金额"不服时发起,**小程序入口仍是「退款申诉」**。申诉记录单独存(不再混入退款申请表)。
- **关键变化**:申诉**复用既有退款审批**——发起申诉后系统自动建一笔 PENDING 退款申请,由管理员在退款审批里复核(通过则退款 / 驳回则结束);申诉本身不再有独立审批。
- 原统一售后工单接口(`/v3/mp/aftersale/ticket*`)**全部下线**。
---
## ② 变更清单
| # | 方法 | 路径 | 类型 |
|---|---|---|---|
| 1 | POST | `/v3/mp/refund/appeal` | 🆕 新增(发起申诉)|
| 2 | GET | `/v3/mp/refund/appeal/my` | 🆕 新增(我的申诉,分页)|
| 3 | GET | `/v3/mp/refund/appeal/{id}` | 🆕 新增(申诉详情)|
| 4 | POST | `/v3/mp/refund/appeal/{id}/withdraw` | 🆕 新增(撤回申诉)|
| 5 | ALL | `/v3/mp/aftersale/ticket*` | ❌ 删除(统一售后工单下线,调用返回 404)|
统一响应包装 `Result<T>`:`{ code, message, data, success }`,`code=200` 为成功。
---
## ③ 接口详情
### 1. 发起申诉 `POST /v3/mp/refund/appeal`
用户对一笔退款申请发起申诉。两种类型:`REFUND_REJECTED`(退款被拒,原退款 status=REJECTED 才可申诉)/ `REFUND_AMOUNT_DISPUTE`(退款金额异议,原退款 status=REFUNDED 求补差)。
> 发起成功后:① 落一条申诉记录(PENDING)② **自动建一笔 PENDING 退款申请**走退款审批 ③ 订单进入「售后中」。
### 2. 我的申诉 `GET /v3/mp/refund/appeal/my`
当前登录用户的申诉分页列表。
### 3. 申诉详情 `GET /v3/mp/refund/appeal/{id}`
单条申诉详情,含关联的两笔退款(来源退款 + 申诉触发的退款)。
### 4. 撤回申诉 `POST /v3/mp/refund/appeal/{id}/withdraw`
仅 `PENDING`(审批中)状态可撤回;撤回会一并取消申诉触发的那笔 PENDING 退款申请。
---
## ④ 入参
### 接口1 create(`@RequestBody`,登录态 userId 由网关注入)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| refundApplicationId | long | 是 | 来源退款申请 ID(被申诉的那笔退款)|
| appealType | string | 是 | 申诉类型:`REFUND_REJECTED` / `REFUND_AMOUNT_DISPUTE` |
| appealReason | string | 是 | 申诉理由(≤2000 字)|
| appealAmount | string(decimal) | 否 | 期望退款金额(金额异议时填)|
| mediaTraceIds | string[] | 否 | 凭证图片机审 traceId 列表(前端上传后透传,≤12)|
### 接口2 my
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| pageNo | int | 否 | 页码,默认 1 |
| pageSize | int | 否 | 每页条数,默认 20 |
### 接口3 detail / 接口4 withdraw
| 参数 | 位置 | 类型 | 说明 |
|---|---|---|---|
| id | path | long | 申诉 ID |
---
## ⑤ 出参
### 接口1 create `Result<Long>`
`data` = 新建申诉 ID(字符串化 Long)。
### 接口2 my `Result<PageResult<AppealMpRespVO>>`;接口3 detail `Result<AppealMpRespVO>`
`PageResult`:`{ records[], total, page, pageSize }`。`AppealMpRespVO`:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string(Long) | 申诉 ID |
| orderId | string(Long) | 订单 ID |
| refundApplicationId | string(Long) | 来源退款申请 ID |
| appealType | string | 申诉类型(枚举值,见⑥)|
| appealTypeLabel | string | 申诉类型中文名 |
| appealReason | string | 申诉理由 |
| appealAmount | string(decimal) | 申诉退款金额 |
| appealStatus | string | 申诉状态(枚举值,见⑥)|
| appealStatusLabel | string | 申诉状态中文名 |
| applicantName | string | 申请人姓名 |
| reviewedAt | datetime | 审批完成时间(可空)|
| createTime | datetime | 创建时间 |
| sourceRefund | object | 来源退款信息(被申诉的原退款),见下 |
| triggeredRefund | object | 申诉触发的退款信息(申诉建单后自动生成的退款),见下 |
`sourceRefund` / `triggeredRefund` 结构(关联退款信息):
| 字段 | 类型 | 说明 |
|---|---|---|
| refundApplicationId | string(Long) | 退款申请 ID |
| status | string | 退款状态(PENDING/APPROVED/REJECTED/REFUNDING/REFUNDED/CANCELLED/ABNORMAL)|
| actualAmount | string(decimal) | 实际退款金额(可空)|
### 接口4 withdraw `Result<Void>`
`data` = null。
---
## ⑥ 枚举 / 数据字典
**申诉类型 appealType**:
| 值 | 含义 |
|---|---|
| REFUND_REJECTED | 退款被拒(原退款被驳回后申诉)|
| REFUND_AMOUNT_DISPUTE | 退款金额异议(已退款但金额有异议,求补差)|
**申诉状态 appealStatus**:
| 值 | 含义 |
|---|---|
| PENDING | 审批中(申诉触发的退款申请待退款审批)|
| REJECTED | 已驳回(退款审批驳回)|
| REFUNDED | 退款到账(申诉成功,退款已退)|
| WITHDRAWN | 已撤回 |
---
## ⑦ 错误码(段位 530600-530699)
| code | message |
|---|---|
| 530601 | 申诉必须关联一笔退款申请 |
| 530602 | 关联的退款申请不存在 |
| 530603 | 退款申请当前状态不满足申诉条件 |
| 530604 | 该退款申请已有处理中的申诉,请勿重复提交 |
| 530605 | 申诉退款金额超出可退余额 |
| 530606 | 申诉记录不存在 |
| 530607 | 无权操作此申诉 |
| 530608 | 当前申诉状态不允许撤回,仅待审核状态可撤回 |
| 530609 | 申诉类型无效 |
---
## ⑧ 示例
### 典型:发起申诉(退款被拒)
请求 `POST /v3/mp/refund/appeal`:
```json
{ "refundApplicationId": 20001, "appealType": "REFUND_REJECTED",
"appealReason": "退款审核不合理,申请复核", "appealAmount": "300.00",
"mediaTraceIds": [] }
```
响应:`{ "code":200, "message":"成功", "data":"40001", "success":true }`
### 典型:我的申诉
请求 `GET /v3/mp/refund/appeal/my?pageNo=1&pageSize=10`,响应(节选一项):
```json
{ "code":200, "success":true, "data": { "total":1, "records":[
{ "id":"40001", "orderId":"10001", "appealType":"REFUND_REJECTED", "appealTypeLabel":"退款被拒",
"appealStatus":"PENDING", "appealStatusLabel":"审批中", "appealAmount":"300.00",
"sourceRefund": { "refundApplicationId":"20001", "status":"REJECTED", "actualAmount":null },
"triggeredRefund": { "refundApplicationId":"20009", "status":"PENDING", "actualAmount":null } }
] } }
```
### 异常:重复申诉
对同一退款申请已有处理中申诉时再发起:
```json
{ "code":530604, "message":"该退款申请已有处理中的申诉,请勿重复提交", "success":false }
```
### 异常:调用已下线的工单接口
请求 `POST /v3/mp/aftersale/ticket`(旧统一售后工单接口):
```json
{ "code":404, "message":"Not Found" }
```
---
## ⑨ 业务边界
- 申诉**复用退款审批**:发起后自动建 PENDING 退款申请,管理员在退款审批里复核——**前端不要再调用任何"申诉审批"接口**(已无独立申诉审批)。
- 申诉状态跟随其触发的退款申请:退款到账→REFUNDED,退款审批驳回→REJECTED。
- 撤回仅 PENDING 可撤,且会取消触发的 PENDING 退款。
- 申诉发起即把订单标记「售后中」,终结(REFUNDED/REJECTED/WITHDRAWN 且无其他活跃售后)后回切。
---
## ⑩ 修改前后对比
| | 修改前 | 修改后 |
|---|---|---|
| 申诉入口 | 统一售后工单 `POST /v3/mp/aftersale/ticket`(category=APPEAL)| `POST /v3/mp/refund/appeal` |
| 我的申诉 | `/v3/mp/aftersale/ticket/my` | `/v3/mp/refund/appeal/my` |
| 详情/撤回 | `/v3/mp/aftersale/ticket/{id}` `/{id}/withdraw` | `/v3/mp/refund/appeal/{id}` `/{id}/withdraw` |
| 审批 | 申诉独立 OA 审批 | 无(复用退款审批)|
---
## ⑪ 影响评估 / 回滚
- **破坏性**:`/v3/mp/aftersale/ticket*` 已删,调用返回 404,前端涉及"退款申诉"的页面**必须切到新申诉接口**。
- 投诉接口不在此列(投诉走 C 端经 BFF 的现有通道,无变化)。
- 回滚:后端回滚 PR #4251 #4254。
---
## ⑫ 注意事项
- 金额字段(appealAmount / actualAmount)均为**字符串**,前端按字符串处理防精度丢失。
- Long 型 ID 均字符串化返回(防 JS 精度)。
- 上传凭证图片仍走既有 wx 内容安全机审通道(mediaTraceIds 透传)。
---
## ⑬ 关联 / 联系人
- Issue:https://git.1814.love:8443/wx/HL/issues/4250
- PR:https://git.1814.love:8443/wx/HL/pulls/4251 ・ https://git.1814.love:8443/wx/HL/pulls/4254
- 后端负责人:腰苏图
- 已部署测试服并网关实调验证通过(申诉接口 200 / 工单接口 404)。
@@ -0,0 +1,336 @@
# 发票申请票种修正(最终契约)— 小程序端
> 变更类型:修改接口(破坏性)
> 端类型:小程序端
> 日期:2026-06-23 | Issue:#4296 | PR:#4292 / #4302 | 服务:hl-order-service-v3
> ⚠️ **破坏性变更**:`invoiceType` 删除 `ELECTRONIC`、`email` 改为始终必填 + 格式校验、专票限公司抬头 + 必填五项、删除 `mailAddress` 字段。小程序开票页与详情页均需同步改动,上线时前后端须同步发布。
> **勘误(截至 PR #4311 收口)**:抬头字段统一 `titleName`、金额 `amount` 改 JSON number(单位元,非分/x100)、票种仅 2 值(`VAT_NORMAL`/`VAT_SPECIAL`)、专票限公司抬头、入参和出参均无 `mailAddress`。关联 Issue [#4290](https://git.1814.love:8443/wx/HL/issues/4290) [#4296](https://git.1814.love:8443/wx/HL/issues/4296) [#4310](https://git.1814.love:8443/wx/HL/issues/4310) / PR [#4292](https://git.1814.love:8443/wx/HL/pulls/4292) [#4302](https://git.1814.love:8443/wx/HL/pulls/4302) [#4311](https://git.1814.love:8443/wx/HL/pulls/4311)。
---
## 接口背景
发票模型经 PR #4292 + #4302 多轮修正后定稿:删除「电子发票」票种(业务决策统一走普票),专票收严字段校验(限公司抬头 + 必填银行注册信息),email 改为始终必填(全系统电子交付),删除纸质邮寄字段 `mailAddress`。
本次涉及小程序两个接口:初次申请 `POST /v3/internal/mp/order/{orderId}/invoice/apply` 和重新开票 `POST /v3/internal/mp/invoice/{id}/reissue`,入参字段矩阵相同,出参亦做同步修正(删 `mailAddress`,invoiceType 去 ELECTRONIC)。
---
## 变更清单
| # | 变更类型 | 说明 |
|---|---------|------|
| 1 | ⚠️ 申请入参删枚举值 | `invoiceType` 删除 `ELECTRONIC`,只保留 `VAT_NORMAL` / `VAT_SPECIAL` |
| 2 | ⚠️ 申请入参删字段 | 删除 `mailAddress`(纸质邮寄地址) |
| 3 | ⚠️ 申请入参校验收严 | `email` 改为始终必填 + 邮箱格式校验 |
| 4 | ⚠️ 申请入参校验新增 | `taxNo`:单位抬头或专票时必填 |
| 5 | ⚠️ 申请入参校验新增 | 专票:`bankName` / `bankAccount` / `registAddress` / `registPhone` 四项必填 |
| 6 | ⚠️ 申请入参新增错误码 | `581523` 专票只能开给单位 |
| 7 | ⚠️ 详情出参删字段 | `GET /v3/internal/mp/order/{orderId}/invoice/detail` 出参删除 `mailAddress` |
| 8 | ⚠️ 列表出参枚举收窄 | `GET /v3/internal/mp/order/{orderId}/invoice/list` 出参 invoiceType 不再出现 ELECTRONIC |
| 9 | 重开接口同步 | `POST /v3/internal/mp/invoice/{id}/reissue` 入参字段矩阵与申请接口保持一致 |
---
## 接口详情
### 小程序申请接口
| 项 | 说明 |
|---|------|
| **方法 + 路径** | `POST /v3/internal/mp/order/{orderId}/invoice/apply` |
| **接口名** | 小程序客户自主申请发票 |
| **描述** | 客户在订单完成后自主提交开票申请,支持普票/专票,全电子交付 |
| **认证** | 小程序 JWT(Bearer Token,C 端用户) |
| **幂等性** | 非幂等,重复提交触发 581511(一单一票) |
| **限流** | 无特殊限流 |
### 小程序重开接口
| 项 | 说明 |
|---|------|
| **方法 + 路径** | `POST /v3/internal/mp/invoice/{id}/reissue` |
| **接口名** | 小程序重新开票 |
| **描述** | 旧发票作废后,客户重新提交开票申请;入参字段矩阵与 apply 接口相同 |
| **认证** | 小程序 JWT(Bearer Token,C 端用户) |
| **幂等性** | 非幂等 |
| **限流** | 无特殊限流 |
---
## 接口入参
### 路径参数
**apply 接口:**
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `orderId` | string(Long 雪花 ID) | 是 | 订单 ID |
**reissue 接口:**
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `id` | string(Long 雪花 ID) | 是 | 被重开的旧发票 ID |
### 请求体字段(两接口共用)
| 字段名 | 类型 | 必填条件 | 说明 |
|--------|------|---------|------|
| `invoiceType` | string | 始终必填 | 发票类型:`VAT_NORMAL`(普票)/ `VAT_SPECIAL`(专票);**不含 ELECTRONIC** |
| `titleType` | string | 始终必填 | 抬头类型:`COMPANY`(单位)/ `PERSONAL`(个人);**VAT_SPECIAL 只能 COMPANY** |
| `titleName` | string | 始终必填 | 发票抬头 |
| `taxNo` | string | `titleType=COMPANY` 或 `invoiceType=VAT_SPECIAL` 时必填 | 纳税人识别号 |
| `bankName` | string | `invoiceType=VAT_SPECIAL` 时必填 | 开户银行 |
| `bankAccount` | string | `invoiceType=VAT_SPECIAL` 时必填 | 银行账号 |
| `registAddress` | string | `invoiceType=VAT_SPECIAL` 时必填 | 注册地址 |
| `registPhone` | string | `invoiceType=VAT_SPECIAL` 时必填 | 注册电话 |
| `amount` | number | 始终必填 | 开票金额,JSON number,单位**元**(如 `986.00`),须 > 0 且不超过订单总金额 |
| `email` | string | 始终必填 | 收件邮箱,须通过邮箱格式校验 |
| `remark` | string | 选填 | 备注 |
> ⚠️ `mailAddress` 字段**已删除**,不再接收。
---
## 出参字段
### apply / reissue 接口出参
返回结构:`Result<Long>`
| 字段名 | 类型 | 说明 |
|--------|------|------|
| `data` | string | 新建/重开发票 ID,字符串雪花 ID |
### 发票详情出参变化(GET /v3/internal/mp/order/{orderId}/invoice/detail)
| 字段名 | 变化 | 说明 |
|--------|------|------|
| `mailAddress` | **已删除** | 原出参中此字段已移除,前端不应再渲染邮寄地址 |
| `invoiceType` | 值范围收窄 | 只会出现 `VAT_NORMAL` / `VAT_SPECIAL`,不再出现 `ELECTRONIC` |
| `email` | 始终有值 | 原可能为 null,现始终有值 |
---
## 枚举 / 数据字典
### 发票类型(invoiceType)
| 枚举值 | 中文名 | 适用抬头 | 专票字段要求 |
|--------|--------|---------|------------|
| `VAT_NORMAL` | 增值税普通发票 | COMPANY / PERSONAL | 专票四项均不需要 |
| `VAT_SPECIAL` | 增值税专用发票 | **仅 COMPANY** | taxNo + bankName + bankAccount + registAddress + registPhone 全必填 |
> ~~`ELECTRONIC`~~ 已删除,不得传入。
### 抬头类型(titleType)
| 枚举值 | 中文名 | 可选票种 |
|--------|--------|---------|
| `COMPANY` | 单位 | VAT_NORMAL / VAT_SPECIAL |
| `PERSONAL` | 个人 | 只能 VAT_NORMAL,选 VAT_SPECIAL 返回 581523 |
---
## 错误码
| 错误码 | 含义 | 触发场景 |
|--------|------|---------|
| `581510` | 订单未完成,不可开票 | 订单状态不是 COMPLETED |
| `581511` | 一单一票,已有有效发票 | 已有 REQUESTED / ISSUED / PUSHED 状态发票 |
| `581512` | 开票金额超订单总额 | `amount` > 订单 `orderAmount` |
| `581513` | 发票类型非法 | `invoiceType` 不是 VAT_NORMAL 或 VAT_SPECIAL |
| `581514` | 公司抬头或专票须填税号 | 单位抬头或专票时 `taxNo` 为空 |
| `581515` | 专票须填银行及注册信息 | 专票时任一四项为空 |
| `581516` | 收件邮箱不能为空 | HTTP 400,入参层 @NotBlank 校验;格式错误返回 400「邮箱格式不正确」 |
| `581523` | 专票只能开给单位 | `invoiceType=VAT_SPECIAL` 且 `titleType=PERSONAL` |
| `401` | 未授权 | 未携带有效 JWT |
| `403` | 无权限 / 越权 | 非订单归属用户操作 |
---
## 示例
### 典型成功(增值税普通发票,个人抬头)
请求:
```
POST /v3/internal/mp/order/1920000000000000001/invoice/apply
Authorization: Bearer <mp-token>
Content-Type: application/json
```
```json
{
"invoiceType": "VAT_NORMAL",
"titleType": "PERSONAL",
"titleName": "张三",
"taxNo": null,
"amount": 986.00,
"email": "zhangsan@qq.com",
"remark": "旅游报销"
}
```
响应:
```json
{
"code": 200,
"msg": "success",
"data": "1934567890123456789"
}
```
### 典型成功(增值税专用发票,公司抬头,全字段)
请求:
```
POST /v3/internal/mp/order/1920000000000000002/invoice/apply
Authorization: Bearer <mp-token>
Content-Type: application/json
```
```json
{
"invoiceType": "VAT_SPECIAL",
"titleType": "COMPANY",
"titleName": "某某科技有限公司",
"taxNo": "91310000XXXXXXXXXX",
"bankName": "招商银行上海支行",
"bankAccount": "1234567890123456",
"registAddress": "上海市浦东新区XX路XX号",
"registPhone": "021-88888888",
"amount": 2980.00,
"email": "finance@company.com"
}
```
响应:
```json
{
"code": 200,
"msg": "success",
"data": "1934567890123456790"
}
```
### 业务失败(专票个人抬头,错误码 581523)
请求:
```
POST /v3/internal/mp/order/1920000000000000003/invoice/apply
Authorization: Bearer <mp-token>
Content-Type: application/json
```
```json
{
"invoiceType": "VAT_SPECIAL",
"titleType": "PERSONAL",
"titleName": "李四",
"taxNo": null,
"amount": 500.00,
"email": "lisi@example.com"
}
```
响应:
```json
{
"code": 581523,
"msg": "增值税专用发票只能开给单位,个人抬头不可选专票",
"data": null
}
```
---
## 业务边界
**适用场景**
- 客户在小程序「我的订单 - 订单详情」中点「申请发票」,订单状态为 COMPLETED 时可用
- 旧发票被作废后,客户在小程序发起重新申请(reissue 接口)
**不适用场景**
- 订单未完成(非 COMPLETED 状态),返回 581510
- 已有有效发票,须先由财务作废后才能 reissue,不能再次 apply
- 管理后台代客申请走 admin 专属接口
**特殊边界**
- 金额单位:`amount` 为 JSON number,单位**元**(如 `986.00`),前端输入框以元为单位直接提交,无需 x100
- 一单一票:同一订单至多一张有效发票
- 专票抬头联动:选专票后,抬头类型需强制为单位,个人选项需禁用或隐藏
- 详情回显:`mailAddress` 字段已不存在,前端不应渲染邮寄地址块
---
## 修改前后对比
### 发票类型枚举
| 旧值 | 新值 |
|------|------|
| VAT_NORMAL(保留) | VAT_NORMAL(保留) |
| VAT_SPECIAL(保留) | VAT_SPECIAL(保留) |
| ELECTRONIC(电子发票) | **已删除** |
### email 字段校验
| 旧行为 | 新行为 |
|--------|--------|
| 条件必填(ELECTRONIC 时才必填) | **始终必填 + 邮箱格式校验** |
### mailAddress 字段
| 旧行为 | 新行为 |
|--------|--------|
| 申请入参可选填;详情/列表出参包含此字段 | **申请入参已删除;详情出参已删除** |
### 专票限制
| 旧行为 | 新行为 |
|--------|--------|
| titleType 无限制 | 专票只能 COMPANY(个人返回 581523) |
| bankName 等无强制要求 | 专票 taxNo + 银行四项全部必填(返回 581515) |
---
## 影响评估 / 回滚
### 小程序开票页必须改动
| 模块 | 必须改动 |
|------|---------|
| 发票类型选择 | 去掉「电子发票」,只保留「增值税普通发票」/「增值税专用发票」 |
| 专票表单区块 | 新增开户行、银行账号、注册地址、注册电话 4 个必填项,仅选专票时显示 |
| 抬头类型联动 | 选专票时隐藏/禁用「个人」选项 |
| email 输入框 | 改为必填(加红星),增加邮箱格式校验 |
| mailAddress 输入框 | 移除,不再渲染邮寄地址块 |
| 详情页 | 移除邮寄地址展示区,invoiceType 显示只有普票/专票两种文案 |
### 回滚方案
后端回滚至 PR #4292 前,ELECTRONIC 重新有效,email 恢复条件必填,mailAddress 重新可用。小程序需同步回滚开票页逻辑。
---
## 注意事项
1. `ELECTRONIC` 已从枚举删除,小程序开票选项只有两项,禁止出现「电子发票」
2. 重开接口(reissue)入参字段矩阵与 apply 完全相同,改动同步适用
3. 专票五项(taxNo + 开户行 + 账号 + 注册地址 + 注册电话)在专票场景下全必填,缺一返回 581515
4. 详情页 `mailAddress` 字段已消失,老版本小程序读到 undefined 需做好空值守卫(不报错)
5. `amount` 为 JSON number,单位**元**(如 `986.00`),小程序输入框直接传元值,无需 x100
---
## 关联 / 联系人
| 项 | 内容 |
|----|------|
| **Issue(功能)** | [#4290 发票申请票种修正](https://git.1814.love:8443/wx/HL/issues/4290) |
| **Issue(小程序)** | [#4296 小程序发票申请同步修正](https://git.1814.love:8443/wx/HL/issues/4296) |
| **PR(票种删 ELECTRONIC)** | [#4292](https://git.1814.love:8443/wx/HL/pulls/4292) |
| **PR(专票限公司/email 必填/删 mailAddress)** | [#4302](https://git.1814.love:8443/wx/HL/pulls/4302) |
| **后端负责人** | yst |
@@ -0,0 +1,217 @@
# 发票申请删 amount · 门槛放宽(小程序端)
- **接口**:POST /v3/internal/mp/order/{orderId}/invoice/apply
- **变更类型**:修改接口,破坏性变更(申请入参删 amount;申请门槛扩展;新增错误码 581524)
- **端类型**:小程序端
- **日期**:2026-06-25
- **Issue**:[#4353](https://git.1814.love:8443/wx/HL/issues/4353)
- **PR**:[#4360](https://git.1814.love:8443/wx/HL/pulls/4360)
---
## 1 接口背景
小程序端发票申请接口(POST /v3/internal/mp/order/{orderId}/invoice/apply)本次同步两项改动:
1. **申请入参删 amount**:开票金额不再前端传入,开票时后端按规则自动计算(正常单=应收总额;取消单=净实收)。
2. **申请门槛放宽**:原门槛仅允许 COMPLETED(已完成)订单申请;放宽为定制中及以后均可申请,同时支持已取消但净实收 > 0 的订单申请。
---
## 2 变更清单
| # | 变更项 | 变更前 | 变更后 |
|---|--------|--------|--------|
| 1 | 申请入参 amount | 必填字段,客户填写开票金额 | ⚠️ 已删除,后端开票时自动算 |
| 2 | 申请门槛(正常订单) | 订单状态必须 COMPLETED | 状态 ∈ {CUSTOMIZING / PENDING_DEPARTURE / TRAVELLING / COMPLETED} 均可申请 |
| 3 | 申请门槛(取消订单) | 不允许 | CANCELLED 且净实收(已付 - 已退)> 0 时可申请 |
| 4 | 不满足门槛的错误码 | 581510 INVOICE_ORDER_NOT_COMPLETED | ✨ 新增 581524 INVOICE_ORDER_NOT_APPLICABLE(更精确语义) |
---
## 3 接口详情
| 属性 | 值 |
|------|----|
| 方法 | POST |
| 路径 | /v3/internal/mp/order/{orderId}/invoice/apply |
| 描述 | 客户自主申请开票(申请阶段不填金额,开票时后端自动算) |
| 认证 | Bearer JWT(小程序用户) |
| 幂等性 | 非幂等,重复提交触发 581511(一单一票) |
| 限流 | 无特殊限制 |
---
## 4 接口入参
### 4.1 路径参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| orderId | string(Long 雪花) | 是 | 订单 ID |
### 4.2 请求体字段(MpInvoiceApplyReqVO,⚠️ amount 已删)
当前完整字段列表(无 amount):
| 字段 | 类型 | 必填条件 | 说明 |
|------|------|---------|------|
| invoiceType | string | 始终必填 | 发票类型,只有 VAT_NORMAL / VAT_SPECIAL 两值 |
| titleType | string | 始终必填 | 抬头类型:COMPANY(单位)/ PERSONAL(个人);VAT_SPECIAL 只能 COMPANY |
| titleName | string | 始终必填 | 发票抬头(企业全称或个人姓名) |
| taxNo | string | titleType=COMPANY 或 invoiceType=VAT_SPECIAL 时必填 | 纳税人识别号 |
| bankName | string | invoiceType=VAT_SPECIAL 时必填 | 开户银行名称 |
| bankAccount | string | invoiceType=VAT_SPECIAL 时必填 | 银行账号 |
| registAddress | string | invoiceType=VAT_SPECIAL 时必填 | 注册地址 |
| registPhone | string | invoiceType=VAT_SPECIAL 时必填 | 注册电话 |
| email | string | 始终必填 | 收件邮箱,需通过邮箱格式校验 |
| remark | string | 选填 | 申请备注 |
---
## 5 出参字段
响应:成功返回新建发票 ID(字符串,雪花 ID)。
---
## 6 枚举 / 数据字典
### 6.1 发票类型(invoiceType)
| code | 说明 |
|------|------|
| VAT_NORMAL | 增值税普通发票 |
| VAT_SPECIAL | 增值税专用发票 |
### 6.2 抬头类型(titleType)
| code | 说明 | 限制 |
|------|------|------|
| COMPANY | 单位 | 普票/专票均可 |
| PERSONAL | 个人 | 只能选 VAT_NORMAL;选 VAT_SPECIAL 返回 581523 |
### 6.3 订单状态与可申请关系
| 订单状态(code) | 中文 | 可申请? | 说明 |
|----------------|------|---------|------|
| CUSTOMIZING | 定制中 | 是 | 放宽新增 |
| PENDING_DEPARTURE | 待出行 | 是 | 放宽新增 |
| TRAVELLING | 出行中 | 是 | 放宽新增 |
| COMPLETED | 已完成 | 是 | 原有 |
| CANCELLED | 已取消 | 条件是 | 净实收(已付 - 已退)> 0 时可申请 |
| 其他状态 | - | 否 | 报 581524 |
### 6.4 开票时金额自动计算规则
| 订单类型 | 金额计算公式 |
|----------|-------------|
| 正常单(非 CANCELLED) | 应收总额 = 订单总价 + 增项 - 优惠 |
| 取消单(CANCELLED) | 净实收 = 已付金额 - 已退金额 |
---
## 7 错误码
| 错误码 | 常量 | 触发场景 |
|--------|------|----------|
| 581511 | INVOICE_ALREADY_EXISTS | 该订单已有有效发票,不可重复申请(一单一票) |
| 581513 | INVOICE_TYPE_INVALID | 发票类型枚举值非法 |
| 581514 | INVOICE_TAX_NO_REQUIRED | 公司抬头/专票时税号为必填 |
| 581515 | INVOICE_VAT_SPECIAL_FIELDS_REQUIRED | 专票时开户行/银行账号/注册地址/注册电话为必填 |
| 581516 | INVOICE_EMAIL_REQUIRED | 收件邮箱为必填或格式错误(HTTP 400) |
| 581518 | INVOICE_FORBIDDEN | 无权访问该订单(IDOR 防护) |
| 581523 | INVOICE_VAT_SPECIAL_PERSONAL_FORBIDDEN | 专票只能开给单位 |
| 581524 | INVOICE_ORDER_NOT_APPLICABLE | ✨ 新增:订单状态不在可申请集合内,或取消单净实收为 0 |
---
## 8 示例
### 8.1 典型成功——普票申请(无 amount 字段)
请求
响应
### 8.2 边界情况——订单处于定制中提前申请
说明:订单状态 CUSTOMIZING(定制中),本次放宽后允许申请。开票金额将在财务执行开票操作时按当时应收总额计算。
请求(结构同 8.1,orderId 为定制中订单 ID)
响应
### 8.3 业务失败——取消订单净实收为 0 被拒
说明:订单已取消,实付 1000 元且已全额退款,净实收 = 0,无法申请开票。
请求(结构同 8.1,orderId 为该取消订单 ID)
响应
---
## 9 业务边界
适用:
- 订单状态 ∈ {CUSTOMIZING / PENDING_DEPARTURE / TRAVELLING / COMPLETED} 均可申请
- CANCELLED 且净实收(已付 - 已退)> 0 时可申请
不适用:
- PAID(已支付但未进入定制阶段)等其他状态报 581524
- CANCELLED 且净实收 = 0 报 581524
- 订单不属于当前登录用户,报 581518(IDOR 防护)
特殊边界:
- 一单一票:同一订单只允许一张有效发票(REQUESTED/ISSUED/PUSHED 状态),重复申请报 581511
- 开票金额由后端在财务执行 issue 操作时自动计算,小程序端申请时不确定最终金额
---
## 10 修改前后对比
| 字段 / 规则 | 变更前 | 变更后 |
|-------------|--------|--------|
| 申请入参 amount | 必填,客户填写开票金额 | ⚠️ 已删除,后端开票时自动算 |
| 正常订单申请门槛 | 仅 COMPLETED | CUSTOMIZING / PENDING_DEPARTURE / TRAVELLING / COMPLETED |
| 取消订单申请 | 不允许 | 净实收 > 0 时可申请 |
| 不满足门槛错误码 | 581510 INVOICE_ORDER_NOT_COMPLETED(已废弃) | 581524 INVOICE_ORDER_NOT_APPLICABLE(新增) |
---
## 11 影响评估 / 回滚
破坏兼容性:是
- 小程序申请发票表单必须删除金额输入框,不再传 amount 字段
- 若现有流程中有基于 amount 的前端金额展示或校验逻辑,须同步移除
- 不满足门槛的错误提示由旧 581510 改为 581524,前端若 hardcode 了 581510 的处理逻辑需同步更新
前端同步上线:申请表单删 amount 必须与后端同期上线。
回滚方案:回滚后端至 #4360 前版本,amount 字段恢复必填,申请门槛收回到仅 COMPLETED,581524 不再存在。
---
## 12 注意事项
1. **amount 字段已删**:小程序申请发票表单必须移除金额输入框,不传 amount,传入后端会忽略。
2. **申请门槛放宽的注意点**:定制中等状态提前申请,开票时金额由财务执行 issue 操作时后端按当时应收总额计算,小程序无法在申请时预知最终开票金额。
3. **581524 vs 旧 581510**:新错误码 581524 取代了旧的 581510,含义更精确(包含取消单净实收为 0 的场景)。若前端有 581510 的 hardcode 判断需更新为 581524。
4. **开票金额由财务操作确定**:小程序端只负责申请,金额由后端在财务开票(PUT issue)时写入,前端无法在申请时展示最终金额。
---
## 13 关联 / 联系人
- **Issue**:[#4353 发票模块门槛放宽与开票规则优化](https://git.1814.love:8443/wx/HL/issues/4353)
- **PR**:[#4360](https://git.1814.love:8443/wx/HL/pulls/4360)
- **后端负责人**:腰苏图(yaosutu)
@@ -1,155 +0,0 @@
# 二期 v3:订单列表 状态 / 进度字段 —— 前端选用说明
> **服务**: hl-order-service-v3
> **端**: 管理后台
> **接口**: `GET /v3/admin/order`(订单列表)
> **类型**: 📘 字段使用说明(**非接口改动**,字段早已在出参里,本文只讲"前端该用哪个")
> **日期**: 2026-06-02
> **关联**: Issue #3283(状态中文名)+ Issue #3285(8 步步骤条)
---
## 一句话结论
订单列表里和"状态 / 进度"有关的字段,前端**只用下面 5 个**即可:
```
orderStatus / orderStatusName —— 订单大状态(6 态)
flowStatus / flowStatusName —— 流程细状态(16 态)
flowStep / flowStepTotal / flowDisplayText —— 8 步进度步骤条
```
> `progress`("3/10")和 `flowItems` 这两个字段**列表不用,前端忽略**(出参里可能还在,是历史字段,不要再消费)。
---
## 字段选用对照表(看这张就够)
| 你要展示什么 | 用哪个字段 | 说明 |
|---|---|---|
| 订单**大状态**(列表标签 / Tab 筛选) | 展示用 `orderStatusName`,逻辑判断用 `orderStatus` | 6 个粗状态 |
| 订单**流程细状态**(当前所处环节文字) | 展示用 `flowStatusName`,逻辑判断用 `flowStatus` | 16 个细状态 |
| **进度步骤条**(第几步 / 共几步) | `flowStep` + `flowStepTotal` | 如 `5` / `8` → "5/8" |
| **步骤条当前步文案**(即"流程进度名称") | `flowDisplayText` | 如 "待出行";前端自拼 "5/8 · 待出行" |
| ~~节点完成度 "3/10"~~ | ~~`progress`~~ | ❌ 列表不用,忽略 |
| ~~并行未完成项列表~~ | ~~`flowItems`~~ | ❌ 列表不用,忽略 |
---
## 字段详解
### 1. 订单大状态 `orderStatus` / `orderStatusName`(6 态)
| `orderStatus` | `orderStatusName` |
|---|---|
| `PENDING_PAY` | 待支付 |
| `CUSTOMIZING` | 定制中 |
| `PENDING_DEPARTURE` | 待出行 |
| `TRAVELLING` | 出行中 |
| `COMPLETED` | 已完成 |
| `CANCELLED` | 已取消 |
### 2. 流程细状态 `flowStatus` / `flowStatusName`(16 态)
| `flowStatus` | `flowStatusName` |
|---|---|
| `AWAITING_PAY` | 待支付 |
| `AWAITING_PROFILE` | 待补全信息 |
| `AWAITING_HOTEL_SUBMIT` | 待提交配房需求 |
| `AWAITING_HOTEL_CLAIM` | 待抢房 |
| `HOTEL_IN_PROGRESS` | 房控处理中 |
| `HOTEL_NEED_ADJUST` | 房控需调整 |
| `AWAITING_VEHICLE_SUBMIT` | 待配车需求 |
| `VEHICLE_IN_PROGRESS` | 车控处理中 |
| `VEHICLE_NEED_ADJUST` | 车控需调整 |
| `PENDING_CONFIRM` | 待确认 |
| `PENDING_DEPARTURE` | 待出行 |
| `TRAVELLING` | 出行中 |
| `PENDING_REVIEW` | 待核单 |
| `REVIEWING` | 核单中 |
| `SETTLED` | 已结算 |
| `COMPLETED` | 已完成 |
| `CANCELLED` | 已取消 |
### 3. 8 步进度步骤条 `flowStep` / `flowStepTotal` / `flowDisplayText`
- `flowStepTotal`:固定 **8**。
- `flowStep`:当前第几步,由 `(orderStatus, flowStatus)` 后端算好:
| `flowStep` 值 | 含义 | 对应 `flowStatus` |
|---|---|---|
| `0` | 待支付(步骤条尚未开始) | `AWAITING_PAY` |
| `1` | 补全信息 | `AWAITING_PROFILE` |
| `2` | 配房 | `AWAITING_HOTEL_SUBMIT` / `AWAITING_HOTEL_CLAIM` / `HOTEL_IN_PROGRESS` / `HOTEL_NEED_ADJUST` |
| `3` | 配车 | `AWAITING_VEHICLE_SUBMIT` / `VEHICLE_IN_PROGRESS` / `VEHICLE_NEED_ADJUST` |
| `4` | 确认 | `PENDING_CONFIRM` |
| `5` | 待出行 | `PENDING_DEPARTURE` |
| `6` | 出行 | `TRAVELLING` |
| `7` | 核单 | `PENDING_REVIEW` |
| `8` | 结算 | `REVIEWING` / `SETTLED` |
| `null` | **终态或未知**(已完成 / 已取消 / 脏数据) | `COMPLETED` / `CANCELLED` 等 |
> ⚠️ `flowStep` 可能为 **null**(终态/脏数据),前端步骤条渲染需对 null 兜底(如直接显示 `flowDisplayText`,不画进度条)。
- `flowDisplayText`:步骤条当前步的中文文案(即你说的"流程进度名称")。规则:
- 终态优先:`orderStatus`=已取消 → "已取消";已完成 → "已完成"
- 非终态:等于当前 `flowStatus` 的中文名
- 只给中文,**不带** "X/8 · " 前缀,需要的话前端自拼。
---
## `flowDisplayText` 与 `flowStatusName` 的区别(容易混)
- **非终态**:两者**完全相同**(都是 `flowStatus` 的中文名)。
- **终态**:
- `flowDisplayText` 走**粗状态**:固定 "已取消" / "已完成"。
- `flowStatusName` 走**细状态**:是 `flowStatus` 字段本身的 label。
- **建议**:步骤条文案用 `flowDisplayText`(终态展示更干净);纯流程状态文字用 `flowStatusName`。
---
## 响应示例(列表单条,只列状态/进度相关字段)
```jsonc
{
"orderStatus": "PENDING_DEPARTURE",
"orderStatusName": "待出行",
"flowStatus": "PENDING_DEPARTURE",
"flowStatusName": "待出行",
"flowStep": 5,
"flowStepTotal": 8,
"flowDisplayText": "待出行"
// progress / flowItems 即使返回也请忽略
}
```
终态示例(已取消):
```jsonc
{
"orderStatus": "CANCELLED",
"orderStatusName": "已取消",
"flowStatus": "CANCELLED",
"flowStatusName": "已取消",
"flowStep": null, // 终态无步骤,前端兜底
"flowStepTotal": 8,
"flowDisplayText": "已取消"
}
```
---
## 业务边界 / 注意事项
1. 文案**权威源是后端枚举**(`OrderStatus` / `OrderFlowStatus`),运营改文案后端改枚举即可,前端不要硬编码英文→中文映射。
2. `flowStep` 可能为 `null`(终态/脏数据),步骤条渲染必须兜底。
3. `progress`("3/10")/ `flowItems` 是历史字段,**列表场景不要消费**;后续可能下线,提前别依赖。
4. 本文不改任何接口契约,纯字段选用约定,**后端无需重启**。
---
## 关联
- **状态中文名**: Issue [#3283](https://git.1814.love:8443/wx/HL/issues/3283) / PR [#3284](https://git.1814.love:8443/wx/HL/pulls/3284)
- **8 步步骤条**: Issue [#3285](https://git.1814.love:8443/wx/HL/issues/3285) / PR [#3286](https://git.1814.love:8443/wx/HL/pulls/3286)
- **接口**: `GET /v3/admin/order`
@@ -0,0 +1,107 @@
# 订单取消(出行前)新增 3 种退款模式(管理后台)
> 端类型:**管理后台**(v3)|变更类型:**修改接口**|服务:hl-order-service-v3
> Epic #3540 | PR #3550 |日期:2026-06-06
## 接口地址
`POST /v3/admin/order/{id}/cancel/pre-trip`
## 接口介绍
定制师在后台对**出行前**订单(PENDING_PAY / CUSTOMIZING / PENDING_DEPARTURE)执行取消。取消后订单进入 `CANCELLED` 终态,已付金额按所选退款模式发起退款。
## 本次修改点
入参 `OrderCancelPreTripReqVO` **新增 2 个字段** `refundMode` + `refundAmount`,支持 3 种退款模式:
- `POLICY`(默认):按退款政策阶梯(距出发天数)计算退款金额。
- `FULL_DEPOSIT`:订金全额退,**无视政策**。
- `PARTIAL`:部分退,金额由 `refundAmount` 指定。
定制师操作即放行退款(无二级审批),退款单据自动进入执行。出参结构 `OrderCancelPreTripRespVO` 不变。新增错误码 581038 / 581039。
## 入参
路径参数:`id`(Long,订单 ID,必填)
请求体 `OrderCancelPreTripReqVO`:
| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| cancelReason | String | 是 | 取消原因(前端可下拉 + 自由填写) |
| cancelDetail | String | 否 | 详细说明 |
| refundMode | String 枚举 | 否(默认 POLICY) | 退款模式:`POLICY` / `FULL_DEPOSIT` / `PARTIAL` |
| refundAmount | BigDecimal | **PARTIAL 时必填** | 部分退金额,须 `0 < refundAmount ≤ 已付金额` |
**入参示例**
按政策退(默认):
```json
{ "cancelReason": "客户临时有事无法出行", "refundMode": "POLICY" }
```
订金全额退:
```json
{ "cancelReason": "我方资源无法满足", "refundMode": "FULL_DEPOSIT" }
```
部分退:
```json
{ "cancelReason": "协商部分退款", "refundMode": "PARTIAL", "refundAmount": 500.00 }
```
## 出参
`Result<OrderCancelPreTripRespVO>`
| 字段 | 类型 | 含义 |
|---|---|---|
| refundApplicationId | Long | 退款申请 ID |
| refundAmount | BigDecimal | 本次退款金额(按所选模式算定) |
| pendingApprovalMsg | String | 提示文案 |
| newStatus | String | 取消后订单状态,固定 `CANCELLED` |
**出参示例**
```json
{
"code": 200, "message": "成功", "success": true,
"data": {
"refundApplicationId": 2063151109765050369,
"refundAmount": 500.00,
"pendingApprovalMsg": "退款已发起",
"newStatus": "CANCELLED"
}
}
```
## 枚举
| 枚举 | 取值 | 含义 |
|---|---|---|
| refundMode | POLICY | 按退款政策阶梯计算 |
| refundMode | FULL_DEPOSIT | 订金全额退(无视政策) |
| refundMode | PARTIAL | 部分退(用 refundAmount) |
| newStatus | CANCELLED | 已取消(终态) |
## 错误码
| code | message | 触发 |
|---|---|---|
| 581017 | 当前订单状态不允许取消 | 非出行前状态(出行中 / 已完成 / 已取消)调用 |
| 581038 | 退款模式非法,仅支持 POLICY/FULL_DEPOSIT/PARTIAL | refundMode 传了非法值 |
| 581039 | 部分退金额非法:须 > 0 且 ≤ 已付金额 | PARTIAL 缺金额 / ≤0 / 超过已付金额 |
## 修改前后对比
| | 修改前 | 修改后 |
|---|---|---|
| refundMode | 无此入参,固定按政策退 | 新增,可选 POLICY / FULL_DEPOSIT / PARTIAL |
| refundAmount | 无此入参 | 新增,PARTIAL 模式必填 |
| 出参 | 同 | 不变 |
> 兼容性:`refundMode` 不传等价于 `POLICY`,旧调用方零改动可继续工作。
## 关联
- Epic:https://git.1814.love:8443/wx/HL/issues/3540
- PR:https://git.1814.love:8443/wx/HL/pulls/3550
- 后端负责人:腰苏图(订单 v3)
@@ -0,0 +1,243 @@
# 【⚠️修改接口·管理后台】终止行程接口改造(资源级退款计算) (#3556)
> **PR**: #3557 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-06
> ⚠️ **破坏性变更**:入参 / 出参结构均调整,前端必须同步改造。
## 1. 接口背景
终止行程原先只让定制师手填一个返还金额,既不准确也没真正进入核单结算。现改为**资源级退款计算**:定制师在弹框里选择「停在第几天」并逐项标记资源是否已用,提交时后端按实际成交价重新核算退款额并写入核单返还。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 终止行程 | POST | `/v3/admin/order/{id}/terminate` | 修改接口 | 入参从「手填返还额」改为「资源已用判定 + 调整额」;出参补退款明细字段 |
## 3. 接口详情
### 3.1 终止行程
- **使用场景**:出行中订单提前终止时调用,配合「终止退款预览」接口(见同日新增接口 changelog)使用
- **认证**:需要管理端 JWT(`Authorization` 头)
- **幂等性**:是(同一订单二次调用因状态已变为「已完成」返回 581018)
- **限流**:无
## 4. 接口入参
### 4.1 路径参数
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | String | ✅ | 订单 ID |
### 4.2 请求体字段
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|------|------|----------|
| cancelReason | String | ✅ | 终止原因(调整金额的说明也写在此处,不再单列字段) | 非空 |
| endDayNumber | Integer | ✅ | 停在第几天 | 1 ≤ 值 ≤ 行程总天数 |
| rooms | Array<{refId, used}> | ✅ | 住宿各行已用判定 | — |
| tickets | Array<{refId, used}> | ✅ | 门票各行已用判定 | — |
| vehicles | Array<{refId, dayNumber, used}> | ✅ | 用车各行已用判定(同车跨天靠 dayNumber 区分) | — |
| adjustAmount | BigDecimal | ❌ | 人工调整额(正=多退,负=少退),默认 0 | — |
> `rooms[].refId` / `tickets[].refId` / `vehicles[].refId` 取自「终止退款预览」接口返回的 `refId`。
> 请求**只需传**资源是否已用(`used`)+ 调整额,**不传任何金额单价**——退款额由后端按预览同源的成交价重新核算(防篡改)。保险不在入参,由后端自动按锁定不退处理。
### 4.2.1 rooms / tickets 行(ResourceUsedItem)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| refId | String | ✅ | 资源记录 ID |
| used | Boolean | ✅ | 该项是否已使用(true=已用不退 / false=未用可退) |
### 4.2.2 vehicles 行(VehicleUsedItem)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| refId | String | ✅ | 用车记录 ID |
| dayNumber | Integer | ✅ | 第几天 |
| used | Boolean | ✅ | 当天该车是否已使用 |
## 5. 出参(响应)
### 5.1 响应字段(`data`)
| 字段 | 类型 | 说明 |
|------|------|------|
| terminateRefundId | String | 终止退款记录 ID |
| baselineRefund | BigDecimal | 系统按已用资源算出的建议退款额 |
| adjustAmount | BigDecimal | 人工调整额(回显入参) |
| finalRefund | BigDecimal | 最终退款额(= baselineRefund + adjustAmount,最低 0) |
| settlementRefundId | String | 核单返还记录 ID(已写入核单 Step5 返还,供财务复核展示) |
| newStatus | String | 终止后订单状态(`COMPLETED`=已完成) |
| newFlowStatus | String | 终止后流程状态(`PENDING_REVIEW`=待核单) |
## 6. 枚举 / 数据字典
### 6.1 newStatus(订单状态)
**所属字段**:`newStatus` | **类型**:`String`
| 值 | 中文 | 说明 |
|----|------|------|
| `COMPLETED` | 已完成 | 终止后订单进入完成态,转入核单流程 |
### 6.2 newFlowStatus(流程状态)
**所属字段**:`newFlowStatus` | **类型**:`String`
| 值 | 中文 | 说明 |
|----|------|------|
| `PENDING_REVIEW` | 待核单 | 终止后等待核单录入与结算复核 |
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非「出行中」时调用(含二次终止) |
## 8. 示例
### 8.1 典型成功
**请求**:
```
POST /v3/admin/order/60001234567890/terminate
Authorization: Bearer {token}
```
```json
{
"cancelReason": "客户中途高反送医终止;林芝段酒店已付全款不可退,调整 -300",
"endDayNumber": 3,
"rooms": [
{"refId": "96011", "used": true},
{"refId": "96014", "used": false}
],
"tickets": [
{"refId": "97001", "used": true}
],
"vehicles": [
{"refId": "98001", "dayNumber": 1, "used": true},
{"refId": "98001", "dayNumber": 2, "used": true},
{"refId": "98001", "dayNumber": 3, "used": true}
],
"adjustAmount": -300.00
}
```
**响应**:
```json
{
"code": 200,
"message": "ok",
"success": true,
"data": {
"terminateRefundId": "9610000001",
"baselineRefund": 2264.00,
"adjustAmount": -300.00,
"finalRefund": 1964.00,
"settlementRefundId": "9620000001",
"newStatus": "COMPLETED",
"newFlowStatus": "PENDING_REVIEW"
}
}
```
### 8.2 边界情况
**场景说明**:不填调整额(默认 0),退款额 = 基线额。
**请求(片段)**:
```json
{ "cancelReason": "客户主动终止", "endDayNumber": 5, "rooms": [], "tickets": [], "vehicles": [] }
```
**响应(片段)**:
```json
{ "code": 200, "data": { "baselineRefund": 0.00, "adjustAmount": 0.00, "finalRefund": 0.00, "newStatus": "COMPLETED", "newFlowStatus": "PENDING_REVIEW" } }
```
### 8.3 业务失败(异常)
**场景说明**:订单非出行中(如已确认待出发或已终止过)。
**响应**:
```json
{ "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false }
```
## 9. 业务边界
- ✅ **适用场景**:订单当前状态 = 出行中(TRAVELLING)
- ❌ **不适用场景**:未出发订单请走「取消订单」流程;已终止/已完成订单二次调用返回 581018
- ⚠️ **特殊边界**:
- `finalRefund` 最低为 0,不会出现负数
- 退款额最终进入核单返还,由财务复核环节确认放款
- 保险恒不退,无需在入参体现
## 10. 修改前后对比
### 10.1 字段级对比
**入参**:
| 字段 | 改前 | 改后 |
|------|------|------|
| cancelReason | ✅ 终止原因 | ✅ 终止原因(+ 调整说明并入此处) |
| returnAmount | ✅ 手填返还金额(必填) | ❌ **删除**(改由后端按资源核算) |
| returnRemark | ✅ 返还备注(必填) | ❌ **删除**(说明并入 cancelReason) |
| endDayNumber | — | ✅ **新增**,停在第几天 |
| rooms / tickets / vehicles | — | ✅ **新增**,各资源行已用判定 |
| adjustAmount | — | ✅ **新增**(可选),人工调整额 |
**出参**:
| 字段 | 改前 | 改后 |
|------|------|------|
| settlementRefundId | ✅(此前恒为 null) | ✅ 真实核单返还记录 ID |
| returnAmount | ✅ 返还额(回显入参) | ❌ **删除** |
| newStatus | ✅ | ✅(不变) |
| terminateRefundId | — | ✅ **新增** |
| baselineRefund / adjustAmount / finalRefund | — | ✅ **新增**,退款明细金额 |
| newFlowStatus | — | ✅ **新增** |
### 10.2 行为级对比
| 行为 | 改前 | 改后 |
|------|------|------|
| 退款额来源 | 定制师手填一个数 | 按已用资源 + 实际成交价由后端核算 |
| 退款是否进核单 | 否(仅记录,未落账) | 是(写入核单返还,财务复核放款) |
| 配合接口 | 无 | 需先调「终止退款预览」拿资源清单 |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **是否破坏向后兼容**:是。入参删除 `returnAmount` / `returnRemark`,新增多个必填字段;出参删除 `returnAmount`。前端按旧契约调用会校验失败。
- **前端是否必须同步上线**:是。终止行程页面需改造为「预览拉清单 → 选结束天 + 勾选已用 → 提交」流程。
- **前端 workaround 清理点**:若此前有「手填返还额」输入框,应替换为资源勾选界面;旧的 returnAmount/returnRemark 入参与回显逻辑可删除。
### 11.2 回滚方案
- **回滚方式**:revert PR #3557
- **回滚后清理**:无需数据迁移(新功能,无历史数据依赖)
## 12. 注意事项
- ⚠️ 本接口为**破坏性改动**,前端务必在后端上线同期改造,否则终止行程功能不可用。
- 必须配合同日「终止退款预览」新增接口使用:预览拿全部资源清单 → 前端本地按结束天标已用/可退 → 提交时只回传 `used` 判定与 `adjustAmount`。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556)
- **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557)
- **Merge commit**: [773dcdacf](https://git.1814.love:8443/wx/HL/commit/773dcdacf)
- **配套新增接口**: 终止退款预览(同日 changelog)
### 13.2 联系人
- **后端负责人**: @yst
- **前端对接(管理后台)**: 终止行程弹框页面
@@ -0,0 +1,159 @@
# 【✨新增接口·管理后台】终止行程·退款预览 (#3556)
> **PR**: #3557 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-06
## 1. 接口背景
出行中订单因特殊原因需要提前终止行程时,需要给定制师一个「按已用资源算应退多少」的界面。本接口提供终止退款弹框所需的**全部资源清单 + 行程时间轴信息**,定制师选择「停在第几天」后,由前端本地标记每项资源已用/未用并实时算出退款额,最终在终止提交接口落账。
## 2. 变更清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 终止退款预览 | POST | `/v3/admin/order/{id}/terminate/refund-preview` | 新增接口 | 返回终止退款弹框所需资源清单 + 行程信息 |
## 3. 接口详情
### 3.1 终止退款预览
- **使用场景**:出行中订单点击「终止行程」打开退款弹框时调用一次,拿到整趟全部资源清单
- **认证**:需要管理端 JWT(`Authorization` 头)
- **幂等性**:是(只读查询,不落库)
- **限流**:无
## 4. 接口入参
### 4.1 路径参数
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | String | ✅ | 订单 ID |
### 4.2 请求体字段
无请求体。前端**一次性**拿到整趟全部资源,「停在第几天」的选择与已用/未用标记、退款金额计算全部在前端本地完成,**不需要每选一天再调本接口**。
## 5. 出参(响应)
### 5.1 响应字段(`data`)
| 字段 | 类型 | 说明 |
|------|------|------|
| paidAmount | BigDecimal | 已付金额(公司账上已收,前端算退款基线用) |
| tripDays | Integer | 行程总天数(画时间轴用,如 7 天 6 晚 = 7) |
| departDate | String(date) | 出发日期(`yyyy-MM-dd`,第 N 天日期 = 出发日 + N−1) |
| tripCurrentDay | Integer | 当前已出行到第几天(时间轴默认选中点) |
| rooms | Array<ResourceItem> | 住宿资源清单(每晚每组房一行) |
| tickets | Array<ResourceItem> | 门票资源清单(每景点每天一行) |
| vehicles | Array<ResourceItem> | 用车资源清单(**整车已按天展开,每天一行**) |
| insurance | Array<ResourceItem> | 保险清单(整单一行,锁定不退) |
### 5.2 ResourceItem 字段(rooms / tickets / vehicles / insurance 各行通用)
| 字段 | 类型 | 说明 |
|------|------|------|
| refId | String | 资源记录 ID(提交终止时按此回传已用判定;用车多天共用同一 refId,靠 dayNumber 区分;保险可能为 null) |
| name | String | 资源名称(酒店名 / 景点名 / 车型 / 保险产品名) |
| dayNumber | Integer | 对应行程第几天(保险为 null) |
| dealPrice | BigDecimal | 成交单价(住宿=每间每晚价 / 门票=每张价 / 用车=每天每辆日租 / 保险=保费) |
| quantity | Integer | 数量(住宿=房间数 / 门票=张数 / 用车=车辆数 / 保险=1) |
| totalAmount | BigDecimal | 本行小计(= dealPrice × quantity) |
| locked | Boolean | 是否锁定不退(保险恒 true,其余 false) |
| lockedReason | String | 锁定原因(如「保险已生效不退」;未锁定为 null) |
> 响应**不含**「是否已用」标记与「退款合计」——这些由前端按所选结束天(`dayNumber ≤ 结束天` 默认已用,之后默认可退)实时计算。
## 6. 枚举 / 数据字典
本接口无枚举字段。资源分类通过 `rooms` / `tickets` / `vehicles` / `insurance` 四个数组区分,无独立 `resourceType` 字段。
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非「出行中」时调用本接口 |
## 8. 示例
### 8.1 典型成功
**请求**:
```
POST /v3/admin/order/60001234567890/terminate/refund-preview
Authorization: Bearer {token}
(无请求体)
```
**响应**:
```json
{
"code": 200,
"message": "ok",
"success": true,
"data": {
"paidAmount": 6000.00,
"tripDays": 7,
"departDate": "2026-05-12",
"tripCurrentDay": 3,
"rooms": [
{"refId": "96011", "name": "拉萨瑞吉度假酒店·大床房", "dayNumber": 1, "dealPrice": 1280.00, "quantity": 1, "totalAmount": 1280.00, "locked": false, "lockedReason": null},
{"refId": "96014", "name": "拉萨瑞吉度假酒店·大床房", "dayNumber": 4, "dealPrice": 1280.00, "quantity": 1, "totalAmount": 1280.00, "locked": false, "lockedReason": null}
],
"tickets": [
{"refId": "97001", "name": "布达拉宫门票", "dayNumber": 2, "dealPrice": 200.00, "quantity": 2, "totalAmount": 400.00, "locked": false, "lockedReason": null}
],
"vehicles": [
{"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 1, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null},
{"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 2, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null},
{"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 3, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null}
],
"insurance": [
{"refId": null, "name": "安联境内旅行险·尊享版", "dayNumber": null, "dealPrice": 256.00, "quantity": 1, "totalAmount": 256.00, "locked": true, "lockedReason": "保险已生效不退"}
]
}
}
```
### 8.2 边界情况
**场景说明**:某天住两个酒店(同一 dayNumber 出现多行)。
**响应(rooms 片段)**:
```json
"rooms": [
{"refId": "96021", "name": "林芝希尔顿·双床房", "dayNumber": 2, "dealPrice": 980.00, "quantity": 1, "totalAmount": 980.00, "locked": false, "lockedReason": null},
{"refId": "96022", "name": "林芝工布庄园·大床房", "dayNumber": 2, "dealPrice": 880.00, "quantity": 1, "totalAmount": 880.00, "locked": false, "lockedReason": null}
]
```
### 8.3 业务失败(异常)
**场景说明**:订单非出行中(如已确认待出发)时调用。
**响应**:
```json
{ "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false }
```
## 9. 业务边界
- ✅ **适用场景**:订单当前状态 = 出行中(TRAVELLING)
- ❌ **不适用场景**:未出发(待支付 / 待完善 / 已确认待出发)→ 返回 581018;这些状态请走「取消订单」流程,不走终止退款
- ⚠️ **特殊边界**:
- 保险行恒 `locked=true`,不参与退款
- 同一天可有多行(多酒店 / 多门票 / 多车),按 refId 区分
- 用车一段车按行程天数展开为多行,多行共用同一 refId
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556)
- **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557)
- **Merge commit**: [773dcdacf](https://git.1814.love:8443/wx/HL/commit/773dcdacf)
- **关联 PR(预览状态校验加固)**: [#3559](https://git.1814.love:8443/wx/HL/pulls/3559)
### 13.2 联系人
- **后端负责人**: @yst
- **前端对接(管理后台)**: 终止行程弹框页面
@@ -31,8 +31,9 @@
| 用户名 `userName`(按名搜) | `userId`(按 ID 搜)+ 列表已回填 `recipientName`(发送对象名)展示 | | 用户名 `userName`(按名搜) | `userId`(按 ID 搜)+ 列表已回填 `recipientName`(发送对象名)展示 |
| 开始/结束时间 | `startTime` / `endTime` | | 开始/结束时间 | `startTime` / `endTime` |
| 通道筛选(旧页没有) | `channel`(INAPP/ADMIN_INAPP/SMS/WEWORK/MINIAPP/OA) | | 通道筛选(旧页没有) | `channel`(INAPP/ADMIN_INAPP/SMS/WEWORK/MINIAPP/OA) |
| **服务 `serviceName`** | ✅ **已补**(PR #3554,已部署):`serviceName`(来源服务,如 hl-user-service / hl-order-service-v3),旧迁移前的历史行为 null |
列展示用发送日志这套:**通道(channelLabel) / 发送对象(recipientName+recipientType) / 信息内容(content) / 状态 / 失败原因 / 事件(eventCode) / 时间**。详情无需单独接口——列表行已含全部字段(content/recipient/paramsJson 等)。 列展示用发送日志这套:**通道(channelLabel) / 发送对象(recipientName+recipientType) / 信息内容(content) / 状态 / 失败原因 / 事件(eventCode) / 服务(serviceName) / 时间**。详情无需单独接口——列表行已含全部字段(content/recipient/paramsJson 等)。
## 3. 后端说明(不用动,给你交底) ## 3. 后端说明(不用动,给你交底)
@@ -0,0 +1,167 @@
# 团期级 staff 两级配置(团期共享 + 订单专属)
> 端类型:**管理后台**(v3)|变更类型:**新增接口 + 修改接口**|服务:hl-order-service-v3
> Issue #3560 | PR #3567 |日期:2026-06-07
## ① 接口背景
团期产品(小蒙马等)同一团期(groupBatchId)下多个订单**共享同一批出团团队**(领队/摄影/司导)。原先 staff 只能逐订单配置(`order_staff_assignment`),同团期 N 个订单要重复配 N 次。
本次新增**团期级**配置:按团期配一次,后端自动扇出到团内所有订单;同时保留**订单级专属**配置,两级叠加。前端形成两个配置入口:
- 独立的「团期 staff 配置页」(按 groupBatchId 配,本次新增接口)
- 订单详情「staff 配置」(订单专属,沿用原接口,出参新增 source 字段区分来源)
## ② 变更清单
| 接口 | 类型 | 说明 |
|---|---|---|
| `GET /v3/admin/group-batch/{groupBatchId}/staff` | 新增 | 查团期 staff 配置列表 |
| `PUT /v3/admin/group-batch/{groupBatchId}/staff` | 新增 | 全量保存团期配置 + 扇出团内订单 |
| `GET /v3/admin/order/{id}/staff` | 修改 | 出参新增 `source` 字段(GROUP_BATCH/ORDER) |
| `DELETE /v3/admin/order/{id}/staff/{staffAssignmentId}` | 行为变更 | 团期来源行(source=GROUP_BATCH)禁止在订单侧删除(582109) |
| `PUT /v3/admin/order/{id}/staff/{staffAssignmentId}` | 行为变更 | 团期来源行禁止在订单侧编辑(582109) |
## ③ 接口详情
### 接口 A:查询团期 staff 配置
`GET /v3/admin/group-batch/{groupBatchId}/staff`
打开「团期 staff 配置页」时调用,回填当前团期已配的共享 staff。
### 接口 B:保存团期 staff 配置(全量 + 扇出)
`PUT /v3/admin/group-batch/{groupBatchId}/staff`
**全量覆盖语义**:传入列表即为最终状态,后端软删旧配置后插入新配置。保存成功后**异步**扇出到团内所有活跃订单的 `order_staff_assignment`(source=GROUP_BATCH),订单专属行(source=ORDER)不受影响。
### 接口 C:订单 staff 列表(出参加字段)
`GET /v3/admin/order/{id}/staff` 出参每项新增 `source`,前端据此区分「团期共享」(置灰、不可在订单侧增删改)与「订单专属」(可增删改)。
## ④ 入参
### 接口 A(GET)
| 参数 | 位置 | 类型 | 必填 | 含义 |
|---|---|---|---|---|
| groupBatchId | path | Long | 是 | 团期批次 ID |
### 接口 B(PUT)
路径参数:`groupBatchId`(Long,必填)
请求体 `BatchStaffConfigReqVO`:
| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| staffList | List\<Item\> | 是 | staff 配置**全集**(全量覆盖,传空数组=清空团期配置) |
`Item`:
| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| staffId | Long | 是 | 用户域员工 ID |
| staffRole | String | 是 | 员工角色(见枚举) |
| sortOrder | Integer | 否 | 展示排序(默认 0) |
| remark | String | 否 | 备注(≤500) |
> 注:`staffName` / `staffPhone` / `avatarUrl` 由后端 Feign 反查冻结快照,**前端不传**。
**入参示例**
```json
{
"staffList": [
{"staffId": 40001, "staffRole": "LEADER", "sortOrder": 0, "remark": "首席领队"},
{"staffId": 40002, "staffRole": "PHOTOGRAPHER", "sortOrder": 1, "remark": "跟拍摄影"}
]
}
```
## ⑤ 出参
### 接口 A:`Result<List<BatchStaffItemVO>>`
### 接口 B:`Result<BatchStaffConfigRespVO>`
`BatchStaffConfigRespVO`:
| 字段 | 类型 | 含义 |
|---|---|---|
| staffList | List\<BatchStaffItemVO\> | 保存后当前团期配置快照 |
| affectedOrderCount | int | 扇出影响的活跃订单数(已触发异步写入) |
`BatchStaffItemVO`:
| 字段 | 类型 | 含义 |
|---|---|---|
| id | Long | 记录 ID(batch_staff_id) |
| staffId | Long | 用户域员工 ID |
| staffRole | String | 员工角色 |
| staffName | String | 员工姓名(快照) |
| staffPhone | String | 员工手机(脱敏前 3 后 4) |
| avatarUrl | String | 头像 URL(快照) |
| sortOrder | Integer | 展示排序 |
| remark | String | 备注 |
### 接口 C:`GET /order/{id}/staff` 出参 `StaffAssignmentVO` 新增字段
| 字段 | 类型 | 含义 |
|---|---|---|
| source | String | **新增**。GROUP_BATCH=团期共享(不可在订单侧改) / ORDER=订单专属 |
**接口 B 出参示例**
```json
{
"code": 200, "message": "成功", "success": true,
"data": {
"staffList": [
{"id": 770001, "staffId": 40001, "staffRole": "LEADER", "staffName": "刘领队",
"staffPhone": "138****6677", "avatarUrl": "https://oss/40001.jpg", "sortOrder": 0, "remark": "首席领队"}
],
"affectedOrderCount": 3
}
}
```
## ⑥ 枚举 / 数据字典
| 枚举 | 取值 | 含义 |
|---|---|---|
| staffRole | LEADER / DRIVER / PHOTOGRAPHER / OTHER | 领队 / 司机 / 摄影师 / 其他 |
| source | GROUP_BATCH / ORDER | 团期共享 / 订单专属 |
## ⑦ 错误码
| code | message | 触发 |
|---|---|---|
| 582109 | 团期共享 staff 不可在订单侧增删改,请到团期配置页操作 | 对 source=GROUP_BATCH 的行调订单侧 DELETE/PUT staff |
| 400 | 参数校验失败 | staffId/staffRole 缺失等 |
| 401 | 缺少有效的 Authorization 头 | 未携带 token |
## ⑧ 示例(典型 / 边界 / 异常)
- **典型**:团期配「领队+摄影」→ 保存返回 affectedOrderCount=3(团内 3 个活跃订单已扇出)。
- **边界**:staffList 传 `[]` → 清空该团期配置,并扇出删除团内订单的所有 GROUP_BATCH 行(订单专属行保留)。
- **异常**:在订单详情对一个「团期共享」的领队点删除 → 返回 582109,前端应禁用团期行的删除/编辑按钮。
## ⑨ 业务边界
- **全量覆盖**:保存即最终状态,未在列表中的旧团期 staff 会被软删并从团内订单移除。
- **扇出范围**:仅团内**活跃**订单(已完成 / 已取消订单不被扇出刷新,保留历史团队记录)。
- **两级叠加**:订单详情 staff = 团期共享(GROUP_BATCH) + 订单专属(ORDER),同一员工去重。
- **下单自动写入**:团期已配 staff 后新下单的订单,创建时自动带上团期 staff。
- **异步最终一致**:扇出为异步,保存接口返回后团内订单的更新可能有秒级延迟(affectedOrderCount 表示已触发的订单数)。
## ⑩ 修改前后对比
| | 修改前 | 修改后 |
|---|---|---|
| 团期共享配置 | 无,同团期逐单重复配 | 团期配一次自动扇出团内 |
| order/{id}/staff 出参 | 无 source | 每项带 source(GROUP_BATCH/ORDER) |
| 订单侧删/改团期行 | 可删(会造成与团期不一致) | 禁止(582109),引导去团期页 |
## ⑪ 影响评估 / 回滚
- **存量兼容**:`order_staff_assignment` 加 source 列默认 ORDER,存量行全部视为订单专属,原订单 staff 展示不变。
- **前端必改**:订单 staff 列表需按 source 渲染(团期行置灰禁操作);新增团期配置页对接 A/B 接口。
- **回滚**:接口为新增 + 加字段,回滚后前端忽略 source 字段即可,无破坏性。
## ⑫ 注意事项
- 团期配置页的「团期信息」(团期号/出发日期/产品)由**产品服务 admin 接口**提供,本接口只管 staff。
- 保存后 affectedOrderCount 是「已触发异步写入」数,非「已写完」数;前端如需精确状态可重查订单。
- staffPhone 出参已脱敏(前 3 后 4),列表展示直接用即可。
## ⑬ 关联 / 联系人
- Issue:https://git.1814.love:8443/wx/HL/issues/3560
- PR:https://git.1814.love:8443/wx/HL/pulls/3567
- 后端负责人:腰苏图(订单 v3)
@@ -0,0 +1,330 @@
# 订单详情「记录 Tab」时间线接口 13 字段重构 — 修改接口 — 管理后台
> 变更类型:⚠️ 破坏性变更(字段删除 / 改名 / 新增)
> 端类型:管理后台
> 日期:2026-06-08
> 服务:hl-order-service-v3
---
## 1. 接口背景
订单详情页「记录」Tab 懒加载接口,返回订单状态流转与操作时间线节点列表。
本次对返回值 `LogTimelineVO` 进行全面重构:旧版 6 字段语义模糊、状态值为英文裸枚举、操作人字段名拼写不一;新版扩展为 13 字段,状态标签全部中文化,引入 `changeType` 区分两类节点样式,新增 `id` 字段满足 list key 需要。
**前端必须同步迁移**。旧字段(`action`、`operator`、`fromStatus`、`toStatus`)已从响应体移除或改名,直接使用旧字段的代码将取不到值。
---
## 2. 变更清单
| # | 变更类型 | 旧字段 | 新字段 | 说明 |
|---|---|---|---|---|
| 1 | ⚠️ 删除 | `action` | — | 已拆分为 `title`(事件名)+ `content`(内容描述),原字段不再返回 |
| 2 | ⚠️ 改名 | `operator` | `operatorName` | 操作人姓名,仅字段名变更,值语义不变 |
| 3 | ⚠️ 改名+中文化 | `fromStatus` | `fromStatusLabel` | 状态来源,英文枚举("PENDING_PAY")→ 中文标签("待支付") |
| 4 | ⚠️ 改名+中文化 | `toStatus` | `toStatusLabel` | 状态目标,英文枚举("PROCESSING")→ 中文标签("定制中") |
| 5 | 保留 | `occurredAt` | `occurredAt` | 事件发生时间,无变化 |
| 6 | 保留 | `amount` | `amount` | 金额,无变化 |
| 7 | ✨ 新增 | — | `id` | 节点唯一 ID(String 雪花),list key 用此字段 |
| 8 | ✨ 新增 | — | `title` | 中文事件名(原 action 前半段,如支付订金) |
| 9 | ✨ 新增 | — | `content` | 事件内容文本("¥500" / "拉萨 瑞吉酒店" / "2 位出行人"),可空 |
| 10 | ✨ 新增 | — | `amountKind` | 金额类型枚举(DEPOSIT/FULL/REFUND/RETURN/SETTLEMENT),可空 |
| 11 | ✨ 新增 | — | `relatedType` | 关联单类型(PAYMENT/REFUND/SETTLEMENT/CONTRACT),可空 |
| 12 | ✨ 新增 | — | `relatedId` | 关联单 ID(String),与 relatedType 配对,可空 |
| 13 | ✨ 新增 | — | `eventType` | 英文事件码(机器字段,前端做图标判断,**不直接展示给用户**) |
| 14 | ✨ 新增 | — | `changeType` | 节点类型(STATUS / DATA),前端据此区分节点渲染样式 |
---
## 3. 接口详情
| 项目 | 值 |
|---|---|
| 请求方法 | GET |
| 路径 | /v3/admin/order/{id}/status-log |
| 接口名 | 订单详情 Tab 时间线 |
| 认证 | 需要 Bearer Token(管理后台 JWT) |
| 幂等性 | 查询接口,天然幂等 |
| 限流 | 无特殊限流,跟随全局网关默认限流 |
| 加载时机 | 懒加载(切换到记录 Tab 时触发) |
---
## 4. 接口入参
### 4.1 路径参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | Long | 是 | 订单 ID |
### 4.2 请求体
无请求体(GET 请求)。
---
## 5. 出参字段
**返回类型**:Result<List<LogTimelineVO>>
| 字段名 | 类型 | 可空 | 说明 |
|---|---|---|---|
| id | String | 否 | 节点唯一 ID(雪花 String,防 JS 精度丢失),list key 用此字段 |
| occurredAt | String (ISO 8601) | 否 | 事件发生时间,如 2026-06-01T14:30:00 |
| title | String | 否 | 中文事件名,如支付订金、配房完成、出行前取消 |
| content | String | 是 | 事件内容描述,如 Y500、拉萨瑞吉酒店/林芝工布庄园希尔顿、2位出行人;DATA 节点通常有值,STATUS 节点可空 |
| operatorName | String | 否 | 操作人姓名,如李雯;系统自动触发时为系统 |
| fromStatusLabel | String | 是 | 状态流转来源(中文),如待支付;仅 changeType=STATUS 节点有值,DATA 节点为 null |
| toStatusLabel | String | 是 | 状态流转目标(中文),如定制中;仅 changeType=STATUS 节点有值,DATA 节点为 null |
| amount | BigDecimal | 是 | 金额,如 500.00;无金额时为 null |
| amountKind | String | 是 | 金额类型枚举值,见枚举节;无金额时为 null |
| relatedType | String | 是 | 关联单类型(PAYMENT/REFUND/SETTLEMENT/CONTRACT),可空 |
| relatedId | String | 是 | 关联单 ID(String),与 relatedType 配对;可空 |
| eventType | String | 否 | 英文事件码,前端做图标/样式判断用,不直接展示给用户 |
| changeType | String | 否 | 节点类型(STATUS / DATA),前端据此区分节点渲染样式 |
---
## 6. 枚举 / 数据字典
### changeType — 节点类型
| 枚举值 | 含义 | 前端渲染说明 |
|---|---|---|
| STATUS | 状态流转节点 | 展示 fromStatusLabel → toStatusLabel 箭头;amount / amountKind 可能有值 |
| DATA | 状态内数据变更节点 | 无状态箭头;fromStatusLabel / toStatusLabel 为 null;展示 title + content |
### amountKind — 金额类型
| 枚举值 | 含义 |
|---|---|
| DEPOSIT | 订金 |
| FULL | 全款 |
| REFUND | 退款金额 |
| RETURN | 退还金额 |
| SETTLEMENT | 结算金额 |
### relatedType — 关联单类型
| 枚举值 | 含义 |
|---|---|
| PAYMENT | 关联支付单 |
| REFUND | 关联退款单 |
| SETTLEMENT | 关联结算单 |
| CONTRACT | 关联合同单 |
### title 取值示例(中文,后端生成,不限于此列表)
创建订单 / 支付订金 / 支付全款 / 确认订单 / 开始出行 / 返团完成 / 出行前取消 / 出行中终止 / 超时自动取消 / 流程推进 / 补全出行信息 / 新增出行人 / 删除出行人 / 批量导入出行人 / 订单信息调整 / 支付尾款 / 配房完成 / 配导游完成 / 配摄影完成 / 配车完成 / 退款到账 / 核单提交 / 结算确认
---
## 7. 错误码
| 错误码 | HTTP 状态 | 说明 | 前端处理建议 |
|---|---|---|---|
| 200 | 200 | 成功,data 为节点列表(无记录时为空数组 []) | 正常渲染,空数组时展示空状态占位 |
| ORDER_NOT_FOUND(4040xxx) | 200 | 订单不存在 | 提示订单不存在 |
| 401 | 401 | Token 无效或过期 | 跳转登录 |
---
## 8. 示例
### 8.1 典型成功 — 状态流转节点(支付订金)
**请求**
```
GET /v3/admin/order/1798000000000000001/status-log
Authorization: Bearer <token>
```
**响应**
```json
{
"code": 200,
"msg": "success",
"data": [
{
"id": "1798000000000000099",
"occurredAt": "2026-06-01T14:30:00",
"title": "支付订金",
"content": "¥500",
"operatorName": "李雯",
"fromStatusLabel": "待支付",
"toStatusLabel": "定制中",
"amount": 500.00,
"amountKind": "DEPOSIT",
"relatedType": "PAYMENT",
"relatedId": "1798000000000000098",
"eventType": "DEPOSIT_PAID",
"changeType": "STATUS"
}
]
}
```
### 8.2 边界情况 — 数据变更节点(配房完成,fromStatusLabel / toStatusLabel 为 null)
```json
{
"code": 200,
"msg": "success",
"data": [
{
"id": "1798000000000000103",
"occurredAt": "2026-06-02T09:15:00",
"title": "配房完成",
"content": "拉萨 瑞吉度假酒店 / 林芝 工布庄园希尔顿",
"operatorName": "系统",
"fromStatusLabel": null,
"toStatusLabel": null,
"amount": null,
"amountKind": null,
"relatedType": null,
"relatedId": null,
"eventType": "ROOM_ASSIGNED",
"changeType": "DATA"
}
]
}
```
> changeType=DATA 节点:fromStatusLabel / toStatusLabel 恒为 null,前端不渲染状态箭头。
### 8.3 业务失败 — 订单不存在
**请求**
```
GET /v3/admin/order/9999999999999999999/status-log
Authorization: Bearer <token>
```
**响应**
```json
{
"code": 4040001,
"msg": "订单不存在",
"data": null
}
```
---
## 9. 业务边界
**适用场景**
- 订单详情页「记录」Tab 懒加载,展示完整时间线。
- 支持所有订单状态(待支付 / 定制中 / 已确认 / 出行中 / 已完成 / 已取消)查看记录。
**不适用场景**
- 不适用于小程序端(该接口为 /v3/admin/*,仅管理后台消费)。
- 不适用于批量查询(接口只支持单订单)。
**特殊边界**
- 新创建订单若尚无任何操作记录,返回 data: [](空数组),前端 Tab 需有空状态占位。
- eventType 为机器字段,后端随业务迭代可能新增新值;前端图标映射表需留 fallback 分支(未知 eventType 显示默认图标),不能写死枚举列表。
- DATA 类型节点的 content 在极少数情况下可能为 null,前端展示时须做空判断。
- amount 字段仅在有金额关联时有值;DATA 类节点(如配房完成)的 amount 恒为 null。
---
## 10. 修改前后对比
### 字段级对比
| 旧字段名 | 旧类型 | 旧值示例 | 新字段名 | 新类型 | 新值示例 | 变更类型 |
|---|---|---|---|---|---|---|
| action | String | "PAY: 支付成功,¥500" | 已删除(拆分) | — | title=支付订金 content=¥500 | ⚠️ 删除 |
| operator | String | "李雯" | operatorName | String | "李雯" | ⚠️ 改名 |
| fromStatus | String | "PENDING_PAY" | fromStatusLabel | String | "待支付" | ⚠️ 改名+语义变 |
| toStatus | String | "PROCESSING" | toStatusLabel | String | "定制中" | ⚠️ 改名+语义变 |
| occurredAt | LocalDateTime | "2026-06-01T14:30:00" | occurredAt | LocalDateTime | 不变 | 保留 |
| amount | BigDecimal | 500.00 | amount | BigDecimal | 不变 | 保留 |
| — | — | — | id | String | "1798000000000000099" | ✨ 新增 |
| — | — | — | title | String | "支付订金" | ✨ 新增 |
| — | — | — | content | String | "¥500" | ✨ 新增 |
| — | — | — | amountKind | String | "DEPOSIT" | ✨ 新增 |
| — | — | — | relatedType | String | "PAYMENT" | ✨ 新增 |
| — | — | — | relatedId | String | "1798000000000000098" | ✨ 新增 |
| — | — | — | eventType | String | "DEPOSIT_PAID" | ✨ 新增 |
| — | — | — | changeType | String | "STATUS" | ✨ 新增 |
### 行为级对比
| 行为 | 旧版 | 新版 |
|---|---|---|
| 状态标签语言 | 英文枚举如 PENDING_PAY,前端需自行映射为中文 | 中文标签如待支付,前端直接展示,无需映射 |
| 事件描述 | 单个 action 字段拼接如 PAY: 支付成功,¥500,前端需解析 | title(名称)+ content(详情)分离,直接使用 |
| list key | 无唯一标识,只能用数组 index | id 字段(雪花 String),可作稳定 list key |
| 节点类型区分 | 无,前端无法区分状态流转节点与数据变更节点 | changeType(STATUS/DATA),前端可差异化渲染 |
| 金额关联信息 | 仅 amount | amount + amountKind + relatedType + relatedId |
---
## 11. 影响评估 / 迁移
### 破坏兼容
此次变更为**破坏性变更**,以下旧字段已从响应体移除或改名:
| 旧字段 | 状态 | 前端必须修改的地方 |
|---|---|---|
| action | 已删除 | 展示事件名的地方改用 title;展示内容的地方改用 content(可空) |
| operator | 已改名为 operatorName | 所有读取 operator 的地方改为 operatorName |
| fromStatus | 已改名为 fromStatusLabel | 所有读取 fromStatus 的地方改为 fromStatusLabel;值已中文化,无需再做枚举映射 |
| toStatus | 已改名为 toStatusLabel | 所有读取 toStatus 的地方改为 toStatusLabel;值已中文化,无需再做枚举映射 |
### 前端同步迁移清单
1. **list key**:将用 index 作为 list key 的地方改为使用 id 字段。
2. **事件名展示**:action → 改用 title(直接字符串,后端已生成中文)。
3. **事件内容展示**:原从 action 拼串截取的内容 → 改用 content(可空,展示前做空判断)。
4. **操作人**:operator → operatorName(字段名替换,值语义不变)。
5. **状态标签**:fromStatus / toStatus → fromStatusLabel / toStatusLabel;新值已为中文,删除前端原有枚举映射表逻辑。
6. **节点样式分支**:新增 changeType 读取逻辑:
- changeType === STATUS:渲染状态流转箭头(fromStatusLabel → toStatusLabel)
- changeType === DATA:仅渲染 title + content,不渲染状态标签
7. **图标映射**:新增对 eventType 的图标选取逻辑;未知 eventType 值使用默认图标(前端不要写死枚举,需留 fallback)。
8. **金额区块**:可利用 amountKind 细化金额标签(订金/全款/退款等),relatedType + relatedId 可用于跳转关联单详情。
### 前端同步上线
接口破坏兼容,后端与前端**需协调同步上线**,避免新后端 + 旧前端代码同时在线导致字段取不到值。
### 回滚方案
若需回滚,后端恢复旧版 LogTimelineVO(6 字段),前端同步回滚字段引用。接口签名变化不向下兼容,必须同步部署。
---
## 12. 注意事项
1. **fromStatusLabel / toStatusLabel 在 DATA 节点为 null**:前端读取这两个字段前必须判断 changeType === STATUS,避免渲染 null。
2. **id 为 String 类型**:雪花 ID 超出 JS Number 精度范围,后端已序列化为字符串。前端直接用字符串处理,不要转 Number,否则精度丢失导致 key 冲突。
3. **eventType 不展示给用户**:该字段为机器码,仅用于图标/样式判断逻辑,不应直接渲染在 UI 上。
4. **content 可空**:部分节点无内容描述,展示时必须做空判断,避免显示 null 或 undefined。
5. **空列表处理**:新订单无操作记录时返回 data: [],记录 Tab 需有空状态占位(如暂无记录)。
6. **eventType 可能扩展**:随业务迭代后端可能新增 eventType 值,前端图标映射表必须留 fallback 分支,不能写死枚举列表。
7. **删除原有枚举映射**:旧版前端可能维护了 fromStatus / toStatus 英文到中文映射表,新版状态标签已由后端生成中文,该映射表可以删除,避免冗余维护。
---
## 13. 关联 / 联系人
| 项目 | 信息 |
|---|---|
| 父 Issue | https://git.1814.love:8443/wx/HL/issues/3561 |
| PR | https://git.1814.love:8443/wx/HL/pulls/3574 |
| Merge Commit | https://git.1814.love:8443/wx/HL/commit/1f93d534fe2073e56f236d6558ba6165706602b5 |
| 后端负责人 | yst |
@@ -0,0 +1,95 @@
# 车务金额字段返回值 number → String — 修改接口 — 管理后台
> 变更类型:⚠️ 破坏性变更(JSON 类型 number → string)
> 端类型:管理后台
> 日期:2026-06-08
> 服务:hl-fleet-service
---
## 1. 背景
车务(fleet)部分接口的金额字段过去序列化为 JSON **数字**(如 `1000.00`)。平台约定金额一律以 **String** 下发前端(Java 内部仍是 BigDecimal),避免 JS 浮点精度问题、与其它模块口径统一。
本次给车务 3 个已上线接口的金额字段补上 `@JsonSerialize(ToStringSerializer)`,返回值由 **number 改为 string**(如 `1000.00` → `"1000.00"`)。**前端读取这些字段时必须按字符串处理**(如需计算先 `parseFloat`/`Number()`,展示直接用字符串)。
> 注:全局 Jackson 只把超出 JS 安全范围的 Long 雪花转 String,**不会自动转 BigDecimal**,所以金额需逐字段显式标注,此前这 3 处漏标导致泄成数字。
---
## 2. 变更清单
| # | 接口 | 字段 | 旧类型(JSON) | 新类型(JSON) | 示例 |
|---|---|---|---|---|---|
| 1 | 车型型号分页 / 详情 | `basePrice` 起步价 | number | **string** | `1000.00` → `"1000.00"` |
| 2 | 车型价格日历查询 | `dayPrice` 当日租赁价 | number | **string** | `800.00` → `"800.00"` |
| 3 | 司机详情·保险块 | `annualPremium` 年保费 | number | **string** | `3600.00` → `"3600.00"` |
| 4 | 司机详情·保险块 | `perDayRate` 行程日费率 | number | **string** | `50.00` → `"50.00"` |
> 仅这 4 个金额字段受影响;其它非金额数字字段(座位数 seats、排序 sortOrder、各类 count)不变。
---
## 3. 受影响接口
| 接口 | 方法 | 路径 | 受影响字段 |
|---|---|---|---|
| 车型型号分页 | GET | `/admin/fleet/vehicle-types/models/page` | basePrice |
| 车型价格日历查询 | GET | `/admin/fleet/vehicle-types/{vehicleModelId}/pricing-calendar` | dayPrice |
| 司机详情 | GET | `/admin/fleet/drivers/{driverId}` | insurance.annualPremium / insurance.perDayRate |
---
## 4. 示例(车型型号分页)
**请求**
```
GET /admin/fleet/vehicle-types/models/page?pageNo=1&pageSize=5
Authorization: Bearer <token>
```
**响应(注意 basePrice 现为带引号的字符串)**
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"id": "2057378612593823745",
"vehicleTypeId": "2057378611889180674",
"modelName": "丰田普拉多",
"seats": 7,
"basePrice": "1000.00",
"alias": "",
"sortOrder": 1
}
],
"total": 1
},
"success": true
}
```
---
## 5. 前端迁移
| 字段 | 前端处理 |
|---|---|
| basePrice / dayPrice / annualPremium / perDayRate | 读到的是字符串 `"1000.00"`。**展示**:直接用。**参与计算**:先 `Number(x)` / `parseFloat(x)` 再算,结果再格式化回字符串。**编辑回填**:表单控件按字符串赋值即可。 |
- 若前端原先把这些字段当 number 直接做算术(`a.basePrice + b.basePrice`),现在会变成字符串拼接,**必须改为先转数字**。
- 提交(保存)入参不受影响——入参金额前端按原样传,后端独立计算/解析。
---
## 6. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3592 |
| 部署 | 已部署测试服并实测:`"basePrice":"1000.00"`(网关 9443 + admin token 实测带引号) |
| 后端负责人 | wx |
@@ -0,0 +1,130 @@
# 车辆档案「车队归属 / 使用性质」改数据字典下拉 — 修改接口 — 管理后台
> 变更类型:🟡 增强(字段取值改字典驱动,字段名/类型不变)
> 端类型:管理后台
> 日期:2026-06-08
> 服务:hl-fleet-service + hl-user-service(字典种子)
---
## 1. 背景
车辆档案(新增 / 编辑)表单里两个字段过去是写死的:
- `fleet`(车队归属)原是后端 `@Pattern` 写死枚举 own/coopA/coopB;
- `regCertUsage`(使用性质)原是纯自由文本输入框。
本次把这两个字段改为**数据字典驱动**,前端应改为**下拉选择框**,选项从通用字典接口实时拉取。这样合作车队、使用性质都能在字典后台增减,无需改代码发版。
> 字段名、类型、提交入参格式**全不变**,前端只是把输入控件换成下拉、并从字典接口取选项。
---
## 2. 变更清单
| 字段 | 位置 | 旧控件 | 新控件 | 字典 type | 存的值 |
|---|---|---|---|---|---|
| `fleet` 车队归属 | 车辆档案新增/编辑表单 | 写死下拉 own/coopA/coopB | 字典下拉 | `fleet_attribution` | dictValue(own/coopA/coopB code) |
| `regCertUsage` 使用性质 | 车辆档案新增/编辑表单 | 自由文本框 | 字典下拉 | `vehicle_reg_cert_usage` | dictValue(中文:营运租赁等) |
---
## 3. 字典选项怎么取(通用接口,已有)
| 项目 | 值 |
|---|---|
| 方法 | GET |
| 路径 | `/admin/dict/data/{dictType}` |
| 认证 | Bearer Token(管理后台 JWT) |
前端渲染下拉:用 `dictValue` 作为选项的 value(提交给后端的值)、`dictLabel` 作为显示文案。已按 `sortOrder` 升序返回。
### 3.1 车队归属 `fleet_attribution`
**请求**
```
GET /admin/dict/data/fleet_attribution
Authorization: Bearer <token>
```
**响应**
```json
{
"code": 200, "message": "成功", "success": true,
"data": [
{"dictValue": "own", "dictLabel": "自有", "sortOrder": 10, "status": "ACTIVE"},
{"dictValue": "coopA", "dictLabel": "合作车队A", "sortOrder": 20, "status": "ACTIVE"},
{"dictValue": "coopB", "dictLabel": "合作车队B", "sortOrder": 30, "status": "ACTIVE"}
]
}
```
### 3.2 使用性质 `vehicle_reg_cert_usage`
**请求**
```
GET /admin/dict/data/vehicle_reg_cert_usage
Authorization: Bearer <token>
```
**响应**
```json
{
"code": 200, "message": "成功", "success": true,
"data": [
{"dictValue": "营运租赁", "dictLabel": "营运租赁", "sortOrder": 10, "status": "ACTIVE"},
{"dictValue": "非营运", "dictLabel": "非营运", "sortOrder": 20, "status": "ACTIVE"},
{"dictValue": "旅游客运", "dictLabel": "旅游客运", "sortOrder": 30, "status": "ACTIVE"}
]
}
```
> 使用性质的 value=label(都是中文),照抄行驶证「使用性质」栏;车队归属 value 是英文 code、label 是中文,**提交给保存接口的是 dictValue(own/coopA/coopB),展示用 dictLabel**。
---
## 4. 保存接口入参(不变,仅举例)
车辆新增 `POST /admin/fleet/vehicles` / 编辑 `PUT /admin/fleet/vehicles/{vehicleId}`,body 里 `fleet` 传选中的 dictValue、`regCertUsage` 传选中的 dictValue:
```json
{
"plate": "蒙A-66666",
"vehicleModelId": "...",
"fleet": "own",
"regCertUsage": "营运租赁",
"...": "..."
}
```
---
## 5. 前端迁移清单
1. **车队归属**:输入控件改为下拉,选项 `GET /admin/dict/data/fleet_attribution`;提交 `fleet` = 选中项 `dictValue`;列表/详情回显时用 `dictValue` 在字典里查 `dictLabel` 显示(也可直接缓存该字典做映射)。
2. **使用性质**:自由文本框改为下拉,选项 `GET /admin/dict/data/vehicle_reg_cert_usage`;提交 `regCertUsage` = 选中项 `dictValue`(中文)。
3. **存量数据兼容**:历史车辆的 `fleet`/`regCertUsage` 值与字典 value 一致(own/coopA/coopB、营运租赁等),回显正常;若遇到字典里没有的历史脏值,下拉做「未匹配则原样显示」兜底。
4. 后端已去掉写死枚举校验,**字典后台新增的合作车队(如 coopC)/ 新使用性质会自动出现在下拉**,前端无需改代码。
---
## 6. 附带:错误码提示已全中文化(无需前端改动,仅告知)
后端把车务错误提示里的英文术语换成了中文,前端若直接透传后端 `message` 展示会更友好:
| 旧提示 | 新提示 |
|---|---|
| VIN 已存在 | 车架号已存在 |
| token 无效 / 已过期 / 已使用 | 邀请链接无效 / 已过期 / 已使用 |
| OCR 识别失败 | 证件识别失败 |
| 车型大类 key 已存在 | 车型大类标识已存在 |
> 另:车辆档案错误码编号文档此前与代码不一致,已按代码对齐——「车架号已存在」实际码 **600107**(非文档旧标的 600101)、「车型不存在」**600108**。前端按 `message` 文案处理即可,一般无需硬编码错误码。
---
## 7. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3596 |
| 部署 | 已部署测试服并实测:两字典经网关 9443 各返 3 项(fleet_attribution / vehicle_reg_cert_usage) |
| 字典维护 | 系统管理 → 字典管理,type=`fleet_attribution` / `vehicle_reg_cert_usage` |
| 后端负责人 | wx |
@@ -0,0 +1,82 @@
# 在线接口文档恢复显示任务看板等接口分组 — 文档修复 — 管理后台兼小程序
> 变更类型:📄 文档修复(接口契约零变化,仅在线文档可见性恢复)
> 端类型:管理后台(hl-user-service)+ 小程序(hl-mp-service)
> 日期:2026-06-08
> 服务:hl-user-service、hl-mp-service
> PR:https://git.1814.love:8443/wx/HL/pulls/3597
---
## ⚠️ 关键说明(务必先看)
1. **这些接口一直都存在,一直可以正常调用** —— 本次 **没有新增、修改或删除任何接口**,没有任何字段 / 路径 / 鉴权变化。
2. 问题是**在线接口文档(Knife4j / Swagger)的扫描包配置过窄**,导致一批接口分组在文档页面**不显示**。前端如果只看在线文档,会误以为「任务看板等接口没有 / 被删了」。
3. 本次修复后,这些分组在在线文档中**恢复显示**。前端**无需改任何代码**,刷新文档页面(建议 Ctrl+F5 强刷)即可看到。
---
## 1. 背景与根因
在线接口文档「用户服务」分组下原本看不到「任务看板管理」「任务管理」等接口。
根因:`hl-user-service` 的 Swagger 配置 `Knife4jConfig` 中,文档扫描包 `basePackage` 被限定为 `com.hulalv.user.controller` 这一个子包;而该服务的 Controller 实际散落在 `com.hulalv` 下的多个并列子包中(如任务看板在 `com.hulalv.task.controller`),这些子包全部落在扫描范围之外,于是整组接口在文档里不显示(但 Spring 照常注册、接口照常可调用)。
排查时一并核对了全部 6 个后端服务的 Swagger 配置,发现 `hl-mp-service` 存在同类问题:扫描包 `com.hulalv.mp.controller` 漏掉了 `com.hulalv.mp.complaint.controller`(投诉接口)。其余服务配置正确。
---
## 2. 恢复显示的接口分组清单
### 2.1 hl-user-service(在线文档分组「用户服务」)
修复后该分组 tag 由原先的「仅 user 子包」扩展到全部 86 个,下表为此前**被漏掉、现恢复显示**的代表性分组:
| 接口分组(tag) | 端 | 说明 |
|---|---|---|
| [admin] 任务看板管理 | 管理后台 | **本次反馈点**:看板 CRUD / 状态列 / 成员 |
| [admin] 任务管理 | 管理后台 | 任务 CRUD / 评论 / 提醒 |
| [admin] MySQL监控 / Redis监控 / RocketMQ监控 / 服务监控 | 管理后台 | 各中间件与服务监控 |
| [admin] 操作日志 / 登录日志 / 错误日志 / 消息通知日志 / 企微审批日志 | 管理后台 | 各类审计日志查询 |
| [admin] 微信内容安全-违规命中日志 | 管理后台 | 小程序内容安全命中记录 |
| [admin] 文件管理 / 通用OSS上传 | 管理后台 | 文件与对象存储 |
| [C端] 文件上传 | 小程序 | C 端文件上传 |
| [admin] 管理端站内信 / 站内信实时推送 / 通知中心管理 | 管理后台 | 站内信与通知中心 |
| [内部] 文件 / 日志接收 / 通知中心 / 登录日志 | 内部 Feign | 服务间内部接口 |
### 2.2 hl-mp-service(在线文档分组「小程序 BFF」)
| 接口分组(tag) | 端 | 说明 |
|---|---|---|
| [C端] 投诉 | 小程序 | 投诉提交 / 查询 |
---
## 3. 对前端的影响
| 项目 | 说明 |
|---|---|
| 是否需要改代码 | **否**。接口签名、路径、字段、鉴权全部不变 |
| 需要做什么 | 刷新在线文档页面(Ctrl + F5 强刷),即可在「用户服务」分组看到任务看板等接口;「小程序 BFF」分组看到投诉接口 |
| 是否影响线上调用 | 否。这些接口此前一直可正常调用,本次仅恢复文档可见性 |
---
## 4. 验证
部署测试服后,直接拉取两个服务的 Swagger JSON 确认(地面真相):
- `hl-user-service` group「用户服务」:tag 总数 86,已含 `[admin] 任务看板管理`、`[admin] 任务管理` 等。
- `hl-mp-service` group「小程序 BFF」:tag 总数 51,已含 `[C端] 投诉`。
- 两服务均双实例 health UP(user 8081/8181,mp 8085/8185)。
---
## 5. 关联 / 联系人
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3597 |
| Merge Commit | 4976d3c8d |
| 关联工单 | 无(在线文档展示问题,经排查为后端 Swagger 扫描配置) |
| 后端负责人 | wx |
@@ -0,0 +1,106 @@
# 车辆/司机附件「类目」改数据字典驱动 + 后端撤类目/张数校验 — 修改接口 — 管理后台
> 变更类型:🟡 增强(类目改字典驱动)+ ⚠️ 行为变更(后端撤校验,改前端限制)
> 端类型:管理后台
> 日期:2026-06-08
> 服务:hl-fleet-service + hl-user-service(字典种子)
---
## 1. 背景
车辆档案 / 司机档案的「附件类目」(category)过去是后端硬编码枚举(含每类目张数上限),后端做两道校验:类目非法(601002)、张数超上限(601003)。
本次改为**数据字典驱动**:类目列表 + 各类目张数上限都放字典,前端从字典接口拉取后渲染上传区块、并**由前端按字典里的上限限制单类目上传张数**。**后端不再校验类目合法性、不再校验张数上限**(601002 / 601003 已废弃)。
---
## 2. 变更清单
| # | 变更 | 说明 |
|---|---|---|
| 1 | 类目改字典 | 车辆 6 类、司机 8 类改为字典 `vehicle_attachment_category` / `driver_attachment_category`,可后台增减 |
| 2 | 张数上限放字典 `remark` | 每个类目的上限写在字典项的 `remark`(纯数字),**前端读取并限制单类目张数** |
| 3 | ⚠️ 后端撤校验 | 后端不再校验类目合法性 + 张数上限,**601002 / 601003 废弃**(不再抛出) |
| 4 | 上传区块前端渲染 | 前端从字典动态渲染上传区块(类目名 = `dictLabel`,提交值 = `dictValue`) |
---
## 3. 字典怎么取(通用接口,已有)
| 项目 | 值 |
|---|---|
| 方法 / 路径 | GET `/admin/dict/data/{dictType}` |
| 认证 | Bearer Token(管理后台 JWT) |
| 取上限 | 字典项的 `remark` 字段 = 该类目张数上限(字符串数字,`parseInt`)|
### 3.1 车辆附件类目 `vehicle_attachment_category`
```
GET /admin/dict/data/vehicle_attachment_category
```
| dictValue | dictLabel | remark(张数上限) |
|---|---|---|
| exterior | 外观照 | 6 |
| interior | 内饰照 | 3 |
| insurance | 保险单据 | 2 |
| inspection | 年检单据 | 2 |
| operation_license | 营运证 | 2 |
| other | 其他 | 5 |
### 3.2 司机附件类目 `driver_attachment_category`
```
GET /admin/dict/data/driver_attachment_category
```
| dictValue | dictLabel | remark(张数上限) |
|---|---|---|
| id_card | 身份证 | 2 |
| driver_license | 驾驶证 | 2 |
| portrait | 肖像照 | 2 |
| health_cert | 健康证 | 2 |
| training_cert | 培训证书 | 5 |
| award | 荣誉奖励 | 5 |
| qualification | 从业资格证 | 3 |
| other | 其他 | 5 |
**响应示例**(节选):
```json
{
"code": 200, "success": true,
"data": [
{"dictValue": "exterior", "dictLabel": "外观照", "sortOrder": 10, "status": "ACTIVE", "remark": "6"},
{"dictValue": "interior", "dictLabel": "内饰照", "sortOrder": 20, "status": "ACTIVE", "remark": "3"}
]
}
```
---
## 4. 保存接口(不变)
车辆 `POST/PUT /admin/fleet/vehicles`、司机 `POST/PUT /admin/fleet/drivers` 的 `attachments[].category` 字段:传选中类目的 `dictValue`(exterior / id_card …)。字段名、类型、结构全不变;后端只是不再校验该值。
---
## 5. 前端迁移清单
1. **上传区块改字典渲染**:车辆 / 司机档案的附件上传区块改为从 `/admin/dict/data/vehicle_attachment_category`(或 driver)拉类目动态渲染,`dictLabel` 作区块标题、`dictValue` 作提交 category。
2. **张数限制读字典**:每个类目允许上传的最大张数 = 该字典项 `remark`(`parseInt(remark)`)。**前端负责限制**(达上限禁止再选/上传);后端不再拦。
3. **类目可后台增减**:运营在「系统管理 → 字典管理」新增类目,前端会自动多出一个上传区块(无需改前端代码),新类目上限同样读其 `remark`。
4. **错误码**:601002 / 601003 已废弃,后端不再返回;前端如有针对这两个码的提示分支可移除。
5. **详情分组**:司机详情 `attachments` 仍按 8 个固定字段分组返回(idCard/driverLicense/portrait/healthCert/trainingCert/award/qualification/other),不变。
---
## 6. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3598 |
| 部署 | 已部署测试服并实测:两字典经网关 9443 各返 6 / 8 项(含 remark 上限) |
| 字典维护 | 系统管理 → 字典管理,type=`vehicle_attachment_category` / `driver_attachment_category` |
| 后端负责人 | wx |
@@ -0,0 +1,77 @@
# 准驾车型 / 民族 / 保险公司 / 性别 改数据字典下拉 — 修改接口 — 管理后台
> 变更类型:🟡 增强(字段改字典下拉,字段名/类型不变)
> 端类型:管理后台
> 日期:2026-06-08
> 服务:hl-fleet-service + hl-user-service(字典种子)
---
## 1. 背景
车务(车辆 / 司机档案)几个「标准受控词表」字段过去是自由文本手填,本次改为**数据字典驱动**,前端应改为**下拉选择框**,选项从字典接口拉取:
- **准驾车型**、**民族**、**保险公司** 是新建字典;
- **性别** 复用平台已有 `gender` 字典(后端这次放开校验、开始接受「未知」)。
字段名、类型、提交格式**全不变**,前端只是把输入控件换成下拉。
---
## 2. 变更清单
| 字段 | 出现位置 | 旧控件 | 新控件(字典 type) | 提交值 |
|---|---|---|---|---|
| 准驾车型 `licenseClass`/`type` | 司机驾照信息 | 文本框 | 下拉 `driving_license_class` | dictValue(A1/A2/B1…国标代码)|
| 民族 `nation` | 司机基本信息 | 文本框 | 下拉 `nation` | dictValue(中文,如 蒙古族)|
| 保险公司 `insurer`(车)/ `company`(司机)| 车辆 / 司机保险 | 文本框 | 下拉 `insurance_company` | dictValue(中文,如 中国人保财险)|
| 性别 `gender` | 司机基本信息 | 文本框/单选 | 下拉 `gender`(**平台已有**)| dictValue(1=男/2=女/**0=未知**)|
> ⚠️ **性别新增「0=未知」**:后端原来只认 1/2,本次放开为 1/2/0,与平台 gender 字典对齐。前端下拉请用全部 3 项。导入 Excel 的「性别」列现支持 `男/女/未知`(也兼容已是 `1/2/0`)。
---
## 3. 字典怎么取(通用接口,已有)
GET `/admin/dict/data/{dictType}`(Bearer Token),用 `dictValue` 作选项值、`dictLabel` 作显示文案,按 `sortOrder` 升序。
| dictType | 项数 | 示例 |
|---|---|---|
| `driving_license_class` | 16 | A1=A1(大型客车)/ C1=C1(小型汽车)… |
| `nation` | 56 | 汉族 / 蒙古族 / 回族 …(value=label=中文)|
| `insurance_company` | 10 | 中国人保财险 / 中国平安财险 …(value=label=中文,末项「其他」)|
| `gender` | 3 | 1=男 / 2=女 / 0=未知 |
**响应示例**(准驾车型节选):
```json
{
"code": 200, "success": true,
"data": [
{"dictValue": "A1", "dictLabel": "A1(大型客车)", "sortOrder": 10, "status": "ACTIVE"},
{"dictValue": "C1", "dictLabel": "C1(小型汽车)", "sortOrder": 60, "status": "ACTIVE"}
]
}
```
---
## 4. 前端迁移清单
1. **准驾车型**:司机驾照表单的准驾车型改下拉,选项 `GET /admin/dict/data/driving_license_class`;提交 `licenseClass`(或 `license.type`)= 选中 `dictValue`(A1 等代码)。
2. **民族**:改下拉,选项 `GET /admin/dict/data/nation`;提交 `nation` = 选中 `dictValue`(中文)。
3. **保险公司**:车辆 `insurer`、司机保险 `company` 都改下拉,选项 `GET /admin/dict/data/insurance_company`;提交选中 `dictValue`(中文)。
4. **性别**:下拉用 `GET /admin/dict/data/gender`,含 **0=未知**;展示已有性别值时用该字典把 0/1/2 映射为 未知/男/女。
5. **存量兼容**:历史值与字典 value 一致(A1、蒙古族、中国人保财险、1/2…),回显正常;遇字典里没有的历史脏值,下拉做「未匹配则原样显示」兜底。
6. **可后台增减**:准驾车型/民族/保险公司都能在「系统管理 → 字典管理」增减,前端无需改代码。
---
## 5. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3599 |
| 部署 | 已部署测试服并实测:准驾 16 / 民族 56 / 保险 10 / 性别 3(含 0=未知),经网关 9443 |
| 字典维护 | 系统管理 → 字典管理,type=`driving_license_class` / `nation` / `insurance_company` / `gender` |
| 后端负责人 | wx |
@@ -0,0 +1,98 @@
# 【字段移除·车辆档案】车辆保险登记瘦身 — 删除「保险公司 / 保单号」字段
> **变更类型**:🟠 字段移除(出入参 + 列表 + 导入列)
> **端类型**:管理后台
> **服务**:hl-fleet-service
> **PR**:https://git.1814.love:8443/wx/HL/pulls/3600
> **日期**:2026-06-08
> **影响范围**:车辆新增 / 编辑 / 详情 / 列表 / Excel 导入
---
## ⚠️ 关键说明
车辆「保险登记」的两个结构化字段 **`insurer`(保险公司)/ `policyNo`(保单号)已删除**。
原因:保险公司、保单号、险种、保额、起止日等明细,**已全部承载在「保险单」附件图片**(`attachments` 里 `category=insurance` 的那张/那几张)中,结构化字段属重复录入,且不参与任何后端逻辑(不进筛选、不进对账、不进提醒)。
**车辆保险结构化只保留 `insureDue`(保险到期日)**——它驱动「保险到期提醒」,继续保留且可独立编辑。
> 注:这同时撤销了 v1.5.11 定的「保险三件套作一张保单整体更新」口径——`insureDue` 现在是独立可编辑字段,续保直接改到期日即可。
---
## 1. 前端要改什么
| 位置 | 改动 |
|---|---|
| 车辆**新增 / 编辑**表单 | 去掉「保险公司」「保单号」两个输入框;**保留「保险到期日」**;保险单证件继续走「保险单」附件上传 |
| 车辆**详情页** | 出参不再返回 `insurer` / `policyNo`;保险公司、保单号看「保险单」附件图片 |
| 车辆**列表页** | 列表项不再返回 `insurer`(如有展示该列请移除) |
| Excel **批量导入** | 模板去掉「保险公司」「保单号」两列;保险相关只保留「保险到期日」列 |
---
## 2. 字段变更明细
| 字段 | 出现位置 | 变更 |
|---|---|---|
| `insurer` 保险公司 | 新增入参 / 编辑入参 / 详情出参 / 列表出参 / 导入列 | ❌ **移除** |
| `policyNo` 保单号 | 新增入参 / 编辑入参 / 详情出参 / 导入列 | ❌ **移除** |
| `insureDue` 保险到期日 | 新增入参 / 编辑入参 / 详情出参 / 列表出参 / 导入列 | ✅ **保留**(独立可编辑) |
---
## 3. 详情出参示例(变更后)
`GET /admin/fleet/vehicles/{vehicleId}`
```json
{
"code": 0,
"data": {
"id": "<vehicleId>",
"plate": "蒙A-88888",
"vehicleModelId": "<id>",
"modelName": "丰田汉兰达",
"seats": 7,
"fleet": "own",
"vehicleStatus": "idle",
"vin": "LFV2A2********01",
"regDate": "2022-03-15",
"inspectDue": "2027-03-15",
"insureDue": "2026-03-14",
"regCertNo": "150102A******01",
"regCertOwner": "内蒙古驼路旅行社",
"regCertUsage": "营运租赁",
"regCertFrontUrl": "https://oss.../front.jpg",
"regCertBackUrl": "https://oss.../back.jpg",
"primaryDriverId": "<driverId>",
"primaryDriverName": "王师傅",
"attachments": [
{ "category": "insurance", "url": "https://oss.../policy.jpg", "mimeType": "image/jpeg", "sortNo": 0 }
],
"createTime": "2026-01-10T10:00:00+08:00"
},
"msg": "成功"
}
```
> 对比变更前:删去了 `"insurer": "中国人保"` 和 `"policyNo": "PVAA20260001"` 两行。
---
## 4. 验证
- `hl-fleet-service` 209 单测全绿。
- 已部署测试服(双实例 8087 + 8187 均 UP),经运行态 OpenAPI 实测 `VehicleDetailRespVO` 已无 `insurer` / `policyNo`、仍有 `insureDue`。
- DB `fleet_vehicle` 已 DROP COLUMN `insurer` / `policy_no`(Flyway `V20260608_001`,双实例正常启动即迁移成功)。
---
## 5. 关联文档
| 文档 | 版本 |
|---|---|
| API-SPEC-FLEET | v1.5.16 |
| DATABASE-SCHEMA-FLEET | v1.5.13 |
| SRS-FLEET | v1.5(§5.2 保险登记) |
@@ -0,0 +1,103 @@
# 【新增字段·车辆档案】车辆新增「所有权性质 ownerType」— 区分个人所有 / 公司所有
> **变更类型**:🟢 新增字段(出入参 + 列表过滤 + 导入列,字典下拉)
> **端类型**:管理后台
> **服务**:hl-fleet-service + hl-user-service(字典种子)
> **PR**:https://git.1814.love:8443/wx/HL/pulls/3601
> **日期**:2026-06-08
> **影响范围**:车辆新增 / 编辑 / 详情 / 列表 / 列表筛选 / Excel 导入
---
## ⚠️ 关键说明
车辆档案新增字段 **`ownerType`(所有权性质)**,字典下拉,取值:
| dictValue | dictLabel |
|---|---|
| `company` | 公司所有 |
| `personal` | 个人所有 |
它和已有的 **`fleet`(车队归属 own/coopA/coopB)正交**,别混:
- `fleet` 回答「**谁在运营这车**」——自有车队 / 合作车队A / 合作车队B。
- `ownerType` 回答「**车登记在谁名下**」——个人 / 公司。
> 原因:原来 `fleet=own`(自有)把「公司自购车」和「司机自带车(个人产权)」混在一起,靠 `regCertOwner`(行驶证所有人)那个文本名字人眼猜。新字段把产权拆清楚。
**不传默认 `company`(公司所有)**,存量车自动视为公司车。
---
## 1. 前端要改什么
| 位置 | 改动 |
|---|---|
| 车辆**新增 / 编辑**表单 | 加「所有权性质」下拉,选项从 `GET /admin/dict/data/vehicle_owner_type` 取(`dictValue` 作值、`dictLabel` 作显示);不选默认 `company` |
| 车辆**详情 / 列表**出参 | 多了 `ownerType` 字段,用字典把 `company`/`personal` 映射为 公司所有/个人所有 显示 |
| 车辆**列表筛选** | `GET /admin/fleet/vehicles/page` 新增可选 query 参数 `ownerType`(`company`/`personal`) |
| Excel **批量导入** | 模板可加「所有权性质(company/personal)」列(可选,不填默认 company) |
---
## 2. 字典接口
`GET /admin/dict/data/vehicle_owner_type`(Bearer Token)
```json
{
"code": 200,
"data": [
{ "dictValue": "company", "dictLabel": "公司所有", "sortOrder": 10, "status": "ACTIVE" },
{ "dictValue": "personal", "dictLabel": "个人所有", "sortOrder": 20, "status": "ACTIVE" }
]
}
```
---
## 3. 字段位置(新增车辆入参示例节选)
`POST /admin/fleet/vehicles`
```json
{
"plate": "蒙A-66666",
"vehicleModelId": "<id>",
"fleet": "own", // 车队归属(运营归属)
"ownerType": "company", // 🆕 所有权性质(产权;不传默认 company)
"seats": 7,
"...": "..."
}
```
详情 `GET /admin/fleet/vehicles/{id}` 出参同样多 `ownerType` 一项。
---
## 4. 关于「司机自带车自动归个人所有」
设计上:司机**自带车**审核通过的车应自动归 `personal`(个人所有)。
⚠️ 但这个自动置值挂在「**自带车 → 自动建车 / 关联**」的路径上,而**该路径目前后端还没实现**(自带车审核当前只在司机档案上记了个车牌字符串,没有自动创建/关联车辆记录;常驻司机 primaryDriverId 也还在后续里程碑)。所以**现阶段**:
- 字段和默认值已就绪。
- 车管在车辆档案里手动建/编辑自带车记录时,**手动选「个人所有」**即可。
- 待「自带车→自动建车」路径落地后,会自动置 `personal`(届时再发 changelog 告知)。
---
## 5. 验证
- `hl-fleet-service` 209 单测全绿。
- 已部署测试服(user + fleet 双实例均 UP);经网关 9443 实测字典返 2 项(公司所有/个人所有),运行态 OpenAPI 契约 SaveReq/Detail/列表项均含 `ownerType`。
---
## 6. 关联文档
| 文档 | 版本 |
|---|---|
| API-SPEC-FLEET | v1.5.17 |
| DATABASE-SCHEMA-FLEET | v1.5.14 |
| SRS-FLEET | v1.5(§5.2 车辆档案·所有权性质) |
@@ -0,0 +1,77 @@
# 【功能落地·车辆/司机】常驻司机 1:1 车侧权威 — primaryDriverId 真实可用 + 详情回显
> **变更类型**:🟢 功能落地(原文档已描述、后端补实现;出入参字段不变)
> **端类型**:管理后台
> **服务**:hl-fleet-service
> **PR**:https://git.1814.love:8443/wx/HL/pulls/3602
> **日期**:2026-06-08
---
## ⚠️ 关键说明
「常驻司机」`primaryDriverId` 之前文档已写、但后端是占位(详情 `primaryDriverName` 一直返 null)。本次**真实落地**:
- **常驻严格 1:1·车侧权威**:一车一常驻司机、一司机一常驻车,权威落 `fleet_vehicle.primary_driver_id`。
- 与「派单 N:N」正交——常驻只是派单候选加权,实际派谁开哪台车仍可任意。
---
## 1. 前端能用什么了
| 场景 | 说明 |
|---|---|
| 车辆**编辑**(`PUT /admin/fleet/vehicles/{id}`)设常驻 | 入参 `primaryDriverId` 传司机 ID = 设为常驻;传 `null`/不传 = **解绑**常驻 |
| 设常驻**冲突** | 选的司机已是别车常驻 → 返 **`605022`**「该司机已是其它车辆的常驻司机,请先解绑后再指定」(不自动转移,需先去那台车解绑) |
| 车辆**详情**(`GET /admin/fleet/vehicles/{id}`)回显 | `primaryDriverId` / `primaryDriverName` / `primaryDriverPhone`(脱敏)现在**真实返回**(无常驻则三者全 null),不再恒 null |
---
## 2. 出参示例(详情,有常驻司机)
```json
{
"code": 0,
"data": {
"id": "<vehicleId>",
"plate": "蒙A-88888",
"primaryDriverId": "1234567890",
"primaryDriverName": "王师傅",
"primaryDriverPhone": "138****1234"
},
"msg": "成功"
}
```
无常驻时:`primaryDriverId` / `primaryDriverName` / `primaryDriverPhone` 均为 `null`。
---
## 3. 新增错误码
| code | msg | 触发场景 |
|---|---|---|
| 605022 | 该司机已是其它车辆的常驻司机,请先解绑后再指定 | 设常驻时所选司机已是别车常驻 |
---
## 4. 尚未包含(下一步)
「司机**自带车**审核通过 → 自动建车 + 自动设常驻本人 + 自动归个人所有」**未包含**——它依赖「自带车→自动建车」路径,该路径目前后端未实现(自带车审核当前只在司机档案记车牌字符串、未建车辆记录)。该路径落地后会自动完成上述联动,届时另发 changelog。当前车管可手动建车 + 手动设常驻。
---
## 5. 验证
- `hl-fleet-service` 211 单测全绿。
- 已部署测试服(双实例 8087 + 8187 均 UP,Flyway 加列成功);运行态 OpenAPI 契约详情含 `primaryDriverId`/`primaryDriverName`/`primaryDriverPhone`、编辑入参含 `primaryDriverId`。
---
## 6. 关联文档
| 文档 | 版本 |
|---|---|
| API-SPEC-FLEET | v1.5.18(§2.2 / §2.4 / §14.3 错误码 605022) |
| DATABASE-SCHEMA-FLEET | v1.5.15(fleet_vehicle.primary_driver_id + uk_primary_driver) |
| SRS-FLEET | v1.5(§9.15.4 常驻 1:1 车侧权威) |
@@ -0,0 +1,44 @@
# 【修改·管理后台+小程序】保险出单改异步,保险状态新增 INSURING(出单中),保单号可能延迟回填
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-order-service-v2 / hl-order-service-v3 / hl-gateway
> PR: #3646(已合并 dev-v3) | Issue: #3642 | 日期: 2026-06-10
> 影响范围: 管理后台保险列表/订单详情、小程序保险展示的**状态字段**与**保单号字段**
## ⚠️ 关键说明(前端必看 2 点)
保游网保险接口升级到 4.2"见费出单",**出单从"同步即时返回保单号"改为部分产品"异步出单"**(保司确认收费后再回调出单结果)。对前端展示有两处影响,均为**向后兼容的字段取值变化**,无字段增删、无结构变化:
1. **保险状态(insuranceStatus / 保险订单 status)新增取值 `INSURING`(出单中)**。原值域 `NONE / INSURED / CANCELLED / FAILED`,现增加 `INSURING`。请前端在保险状态字典/映射中补这一项,文案建议"出单中",否则该状态会显示为原始码 `INSURING` 或落入 default 分支。
2. **保单号(extPolicyNo / policyNo)在异步出单产品下,投保成功瞬间为空**,需等保游回调到达后回填。前端遇保单号为空且状态为 `INSURING` 时,应显示"出单中,保单号生成后展示",不要显示为投保失败。
> 注:仅"异步出单"产品(保游下单同步响应 MsgCode=80099)会经历 `INSURING` 窗口;"实时出单"产品(MsgCode=10000)仍直接 `INSURED` 并立即带保单号,行为不变。保游本月内逐步切换各保司接口,故 `INSURING` 会在切换后开始出现。
## 1. 保险状态值域(完整字典)
| 状态码 | 含义 | 说明 |
|--------|------|------|
| `NONE` | 无保险 | 订单未生成保险(仅订单主表镜像字段出现) |
| `INSURING` | **出单中(新增)** | 异步出单受理成功,等保司回调确认出单 |
| `INSURED` | 已投保 | 出单成功,有保单号 |
| `CANCELLED` | 已退保 | — |
| `FAILED` | 投保失败 | 出单失败,可重投 |
管理后台订单主表镜像 `insuranceStatus` 聚合优先级:`INSURED > INSURING > CANCELLED > FAILED > NONE`。
## 2. 受影响接口(取值变化,非结构变化)
| 端 | 接口 | 变化点 |
|----|------|--------|
| 管理后台 | 保险订单列表/详情(`/admin/insurance/*`、`/v3/admin/insurance/*`) | status/statusLabel 可能为 INSURING/出单中;policyNo 可能为空 |
| 管理后台 | 订单详情-合同保险 Tab | insuranceStatus 可能为 INSURING;保单号可能空 |
| 小程序 | 保险详情/保单展示(`/mp/insurance/*`、订单保险块) | status/statusLabel 同上;policyNo 空时 PDF 暂不可下载(显示"出单中") |
## 3. 无需前端改动的部分
- 保游回调接收端点(`/insurance/callback/baoyou`、`/v3/insurance/callback/baoyou`)是**后端接收保游通知**的内部端点,前端不调用。
- 出单成功回调到达后,后端自动回填保单号 + 翻 INSURED + 触发 PDF 上传 + 发投保成功通知,前端按现有逻辑刷新即可看到。
## 验证
测试服已部署(hl-gateway / hl-order-service-v2 / hl-order-service-v3),回调端点经网关 9443 可达(HTTP 200)。`INSURING` 态的真实产生需保游切换异步出单产品后触发。
@@ -0,0 +1,85 @@
# 【新增·管理后台】车型库计数字段(modelCount/inUseCount)上线 + 型号 sortOrder 改选填 + 文档契约勘误(page 参名/records/成功码 200)
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3650 + #3651(均已合并 dev-v3,**测试服已部署并 API 实测通过**) | 无关联工单 | 日期: 2026-06-10
> 影响范围: 管理后台**车型管理库**页面(`/admin/fleet/vehicle-types/*` 全部 9 端点);另有 FLEET/HOUSE 文档勘误请前端自查
## ⚠️ 关键说明(前端必看 3 点)
1. **计数字段上线了**:车型树/大类分页/型号分页现在直接返回 `modelCount`(大类下型号数)与 `inUseCount`(在役车辆数,大类级+型号级),左栏「N 款 · 在役 N 台」、头部 MiniStat、型号表「在役车辆」列、删除守卫提示「仍有 N 辆在役」**都不用前端自己聚合了**。口径=未软删全量,与删除守卫(600104/600105)同口径,实时查库。
2. **新增/编辑型号不用传 sortOrder 了**(原必填,不传会 400):新增不传自动追加同大类末尾(现有最大+1,空则 1);编辑不传保持原值。原型表单本来就没有排序输入,前端按表单四字段(modelName/seats/basePrice/alias)直接提交即可。
3. **文档勘误,前端如曾照旧文档实现请自查 3 处**(均为文档错、后端行为一直如此,**后端无变化**):
- 分页参数名是 **`page`** 不是 `pageNo`(传 `pageNo` 会被静默忽略、永远返回第 1 页);
- 分页响应列表字段是 **`records`** 不是 `list`(§0.6 及车辆/司机/H5/待审/看板各节示例已订正);
- 成功码是 **`code: 200`** 不是 `code: 0`(FLEET 130 处、HOUSE 48 处示例已全部订正;判 `code===0` 会把所有成功当失败)。
## 1. 计数字段:涉及接口与新字段
| 接口 | 新字段 | 说明 |
|------|--------|------|
| `GET /admin/fleet/vehicle-types`(车型树) | 大类级 `modelCount`、`inUseCount`;`models[].inUseCount` | 两级计数一次带回 |
| `GET /admin/fleet/vehicle-types/page`(大类分页) | `records[].modelCount`、`records[].inUseCount` | 左栏导航/MiniStat 数据源 |
| `GET /admin/fleet/vehicle-types/models/page`(型号分页) | `records[].inUseCount` | 型号表「在役车辆」列数据源 |
| `POST/PUT` 大类/型号(写接口) | 出参=完整对象(含计数) | 新建时计数=0;编辑返回真实计数 |
**树接口响应示例**(测试服实测):
```json
{
"code": 200,
"data": [
{
"id": "1929151481086734337",
"typeKey": "suv2",
"typeName": "SUV 越野",
"icon": "🚙",
"sortOrder": 1,
"modelCount": 1,
"inUseCount": 0,
"models": [
{ "id": "1929151628176175106", "vehicleTypeId": "1929151481086734337",
"modelName": "丰田普拉多", "seats": 7, "basePrice": "100.00",
"alias": "普拉多", "sortOrder": 1, "inUseCount": 0 }
]
}
],
"msg": "成功"
}
```
> 注意:`models[]` 里也带 `vehicleTypeId` 与 `sortOrder`(旧文档示例漏列,实际一直返回);`basePrice` 是字符串。
## 2. 新增/编辑型号:sortOrder 选填
| 场景 | 行为 |
|------|------|
| 新增不传 sortOrder | 自动追加同大类末尾(现有最大+1,空大类=1) |
| 编辑不传 sortOrder | 保持原值不变 |
| 显式传 | 按传入值(行为不变) |
**新增型号请求示例**(四字段即可,测试服实测返回 sortOrder=2 自动追加):
```bash
curl -X POST "https://api.test.1814.love:9443/admin/fleet/vehicle-types/{typeId}/models" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"modelName":"丰田威尔法","seats":7,"basePrice":"2000.00","alias":"威尔法"}'
```
## 3. 错误码表补全(行为未变,文档原漏列)
| code | msg | 触发 |
|------|-----|------|
| 600101 | 车型大类标识已存在 | 新增大类 typeKey 重复 |
| 600102 | 车型大类不存在 | 大类 id 无效(原文档误写「车型不存在」) |
| 600103 | 车型型号已存在 | 同大类内型号名重复(新增/编辑改名) |
| 600104 | 大类下存在型号,不能删除 | 删大类守卫 |
| 600105 | 型号被车辆引用,不能删除 | 删型号守卫(实测文案逐字一致) |
| 600106 | 车型型号不存在 | 型号 id 无效 |
另:编辑大类时 `typeKey` 仍需传非空值(后端忽略其值,不传会 400 参数校验);编辑型号 `alias` 不传=保持原值、传 `""` 才清空。
## 4. 文档版本
- FLEET API → **v1.5.49 + v1.5.50**(§1 全节契约订正 + 全文成功码勘误),文档站已同步:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
- HOUSE API → **v1.1.5**(48 处成功码勘误,无契约变化)
@@ -0,0 +1,52 @@
# 【修改·管理后台】车辆档案:列表新增常驻司机字段、详情补 typeKey/准驾/驾龄、keyword 支持搜车型、批量导入大修(CSV/警告档/局部更新)
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3653 + #3656(均已合并 dev-v3,**测试服已部署并 API 实测通过**) | 无关联工单 | 日期: 2026-06-10
> 影响范围: 管理后台**车辆档案**页面(`/admin/fleet/vehicles/*` 6 端点)+ 全文档级勘误自查项
## ⚠️ 关键说明(前端必看 4 点)
1. **车辆列表(§2.1)新增常驻司机三字段**:`primaryDriverId`/`primaryDriverName`/`primaryDriverLicenseType`(无常驻=null)。派单弹窗车卡显示常驻司机、车辆卡准驾徽章不用再反查司机侧。
2. **keyword 现在真的能搜车型了**:原来只搜车牌(文档一直写「车牌/车型」但代码只搜车牌,按车型名搜会静默返回空列表),现在车牌 OR 车型名模糊均命中。
3. **批量导入行为变化(重要)**:
- **更新已有车牌的行=11 个导入列的局部更新,空白列保持原值**——原来会把该车的附件全部清掉、解绑常驻司机、清空 VIN(已修复,放心重导);
- **CSV 真的可用了**(原来上传 .csv 直接 500;.xlsx 此前部署缺 POI 依赖实际也不可用,已一并修复);
- **新增警告档**:出参多 `warnedCount`/`warnings[{row,plate,field,msg}]`(保险不足 30 天/年检临期或已过期——**行仍然导入**,只是提醒;`warnedCount` 是 inserted+updated 的子集不是加法项);
- 文件解析失败现在返回业务错误码 **100001**(原来静默返回成功 0 行)。
4. **包络字段勘误(纯文档,后端行为没变)**:响应包络真实字段是 **`message`** 不是文档原来写的 `msg`(完整真形 `{code, data, message, success, traceId}`);如前端有按 `res.msg` 取提示文案的代码请自查(取不到值)。注意:**导入出参 errors/warnings 行内的 `msg` 是真实字段名,不受影响**。
## 1. 列表/详情新增字段
| 接口 | 新字段 | 说明 |
|------|--------|------|
| `GET /admin/fleet/vehicles/page` | `primaryDriverId`(String)/`primaryDriverName`/`primaryDriverLicenseType` | 常驻司机,无=null;司机未填准驾时也是 null(不会给空串) |
| `GET /admin/fleet/vehicles/{vehicleId}` | `typeKey`(大类Key,原来文档有代码没返)/`primaryDriverLicenseType`/`primaryDriverYears`(驾龄·年) | 详情主司机块徽章数据源;驾龄未填=null(不会给 0) |
## 2. 批量导入出参示例(测试服实测)
```json
{
"code": 200,
"data": {
"totalRows": 1, "insertedCount": 1, "updatedCount": 0, "errorCount": 0,
"errors": [],
"warnedCount": 1,
"warnings": [ { "row": 2, "plate": "蒙A·T7777", "field": "insureDue", "msg": "保险不足 30 天" } ]
},
"message": "成功"
}
```
## 3. 契约细节订正(文档侧,代码行为如此)
- §2.2 详情「车辆不存在」错误码是 **600110**(原文档误写 404001,前端按 404001 匹配永不命中);
- `seats` 恒随车型冗余(入参不收、传了忽略;型号座位数变更自动回刷已绑车辆)——原文档「可选,默认取自车型」有歧义;
- 编辑(§2.4)入参必须带 `vehicleModelId`(原示例漏了,照抄会 400);附件保留项(带 id)可以不传 `mimeType` 了(原来会 400);**新增附件 mimeType 必填且白名单 jpeg/png/webp/pdf,不命中报 601005**(新校验);
- 附件混插排序修复:编辑时新图插在保留图前面,落库顺序现在与入参数组顺序一致(原来新增项会被挤到末尾);
- 601002/601003(类目/张数校验)确认废弃,类目走字典 `vehicle_attachment_category`;
- 600109(有未完成派单禁删)为契约先行,守卫随派单模块落地,当前删除不拦。
## 4. 文档版本
FLEET API → **v1.5.51 + v1.5.53**,文档站已同步:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html(HOUSE/主文档的 msg→message 同步勘误见各自变更记录)
@@ -0,0 +1,37 @@
# 【新增·管理后台】车型大类全量列表(不分页) GET /admin/fleet/vehicle-types/list
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3654(已合并 dev-v3,**测试服已部署并 API 实测通过**) | 无关联工单(wx 2026-06-10 提出) | 日期: 2026-06-10
> 影响范围: 管理后台车型下拉/筛选场景(新接口,纯增量)
## ⚠️ 关键说明
下拉/筛选要全量大类时不用再调分页接口拼页了:新接口一次返回**全部大类**(不分页、不含 models 数组),单条结构与 `GET /admin/fleet/vehicle-types/page` 的 records **完全一致**(含 `modelCount`/`inUseCount` 计数),按 sort_order 升序。
- 要型号树 → 用 `GET /admin/fleet/vehicle-types`(§1.1,大类+models 全量);
- 要分页检索大类 → 用 `/page`(§1.5);
- 只要大类轻量全量(下拉) → **用本接口**。
## 1. 接口定义
`GET /admin/fleet/vehicle-types/list` —— 入参:无
**响应示例**(测试服实测):
```json
{
"code": 200,
"data": [
{ "id": "1929151481086734337", "typeKey": "suv2", "typeName": "SUV 越野", "icon": "🚙",
"description": "高底盘 / 沙漠越野", "sortOrder": 1, "modelCount": 1, "inUseCount": 0 },
{ "id": "1930561885327036417", "typeKey": "mpv", "typeName": "MPV 商务", "icon": "🚐",
"description": "", "sortOrder": 2, "modelCount": 0, "inUseCount": 0 }
],
"message": "成功"
}
```
## 2. 文档
FLEET API → **v1.5.52** 新增 §1.7 小节(§1 章 10 端点),文档站已同步:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
@@ -0,0 +1,242 @@
# 【⚠️修改接口·管理后台】出行中取消旧路径下线:`cancel/on-trip` → `terminate` (#3556)
> **服务**: hl-order-service-v3 | **更新时间**: 2026-06-11
> ⚠️ **破坏性变更(路径级)**:旧端点 `POST /v3/admin/order/{id}/cancel/on-trip` **已删除**,调用返回 404。
> 📌 本篇专补「路径下线」这一环(前期 #3556 changelog 只写了新路径的入参/出参,未点明旧路径已废,导致前端联调时仍在调旧 URL 收到 404)。入参/出参完整改造见 #3556 那篇,本篇做自包含汇总。
## 1. 接口背景
「出行中取消」此前走 `POST /v3/admin/order/{id}/cancel/on-trip`。后端在终止行程改造时把该端点**重命名为 `POST /v3/admin/order/{id}/terminate`**,并改变了语义:
- 旧:出行中取消 → 订单直接进入 `CANCELLED`(已取消)。
- 新:终止行程 → 订单进入 `COMPLETED`(已完成),再在核单子状态(`reviewStatus` / `flowStatus`)中流转结算,**不再直接 CANCELLED**。
后端代码里 `cancel/on-trip` 路径已**全量删除**(全仓 `git grep` 无残留),任何对旧路径的调用都会 404。前端「出行中取消」分支若仍指向旧 URL,必须改指新 URL。
## 2. 变更清单
| # | 操作 | 旧 | 新 | 变更类型 |
|---|------|----|----|----------|
| 1 | 取消/终止 出行中订单 | `POST /v3/admin/order/{id}/cancel/on-trip` | `POST /v3/admin/order/{id}/terminate` | 路径下线 + 重命名 |
| 2 | 退款预览(出行中) | (旧流程无独立预览,或复用 cancel-preview) | `POST /v3/admin/order/{id}/terminate/refund-preview` | 新增(详见 #3556 配套篇) |
## 3. 接口详情
### 3.1 终止行程(替代出行中取消)
- **路径**:`POST /v3/admin/order/{id}/terminate`
- **使用场景**:出行中订单提前终止,定制师调用。需先调「终止退款预览」拿资源清单。
- **认证**:管理端 JWT(`Authorization` 头)
- **幂等性**:是。订单一旦终止状态变为 `COMPLETED`,二次调用因状态非 `TRAVELLING` 返回 `581018`。
## 4. 接口入参
### 4.1 路径参数
| 字段 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| id | String | ✅ | 订单 ID |
### 4.2 请求体(`OrderTerminateTripReqVO`)
| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|:----:|------|------|
| cancelReason | String | ✅ | 终止原因(调整额说明也并入此处,不单列字段) | 非空 |
| endDayNumber | Integer | ✅ | 停在第几天(截断点,1-based) | ≥ 1 |
| rooms | Array<{refId, used}> | ✅ | 住宿各行已用判定 | 列表非 null |
| tickets | Array<{refId, used}> | ✅ | 门票各行已用判定 | 列表非 null |
| vehicles | Array<{refId, dayNumber, used}> | ✅ | 用车各行已用判定(同车跨天靠 dayNumber 区分) | 列表非 null |
| adjustAmount | BigDecimal | ❌ | 人工调整额(±,正=多退 负=少退),默认 0 | — |
> `refId` 全部取自「终止退款预览」接口返回值。入参**只传 `used` 判定 + `adjustAmount`,不传任何金额单价**——退款额由后端按预览同源成交价权威重算(防篡改)。保险不在入参,后端自动按锁定不退处理。
**rooms / tickets 行(ResourceUsedItem)**
| 字段 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| refId | String | ✅ | 配单记录 ID(住宿=house_hotel_assignment.id;门票=order_scenic_assignment.assignment_id) |
| used | Boolean | ✅ | 是否已使用(true=已用不退 / false=未用可退) |
**vehicles 行(VehicleUsedItem)**
| 字段 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| refId | String | ✅ | 配车记录 ID(同段车跨天 refId 相同) |
| dayNumber | Integer | ✅ | 第几天(1-based,≥ 1) |
| used | Boolean | ✅ | 当天该车是否已使用 |
## 5. 出参(`Result<OrderTerminateTripRespVO>`)
| 字段 | 类型 | 说明 |
|------|------|------|
| terminateRefundId | String | 终止退款主表 ID |
| baselineRefund | BigDecimal | 系统建议基线 = max(0, paidAmount − usedAmount) |
| adjustAmount | BigDecimal | 人工调整额(回显入参,默认 0) |
| finalRefund | BigDecimal | 最终返还额 = max(0, baselineRefund + adjustAmount) |
| settlementRefundId | String | 核单返还记录 ID(核单模块写入后回填) |
| newStatus | String | 终止后订单粗状态(恒 `COMPLETED`) |
| newFlowStatus | String | 终止后流程细状态(恒 `PENDING_REVIEW`) |
## 6. 枚举 / 数据字典
### 6.1 newStatus
| 值 | 中文 | 说明 |
|----|------|------|
| `COMPLETED` | 已完成 | 终止后订单进入完成态,转入核单流程(**注意:不再是旧的 CANCELLED**) |
### 6.2 newFlowStatus
| 值 | 中文 | 说明 |
|----|------|------|
| `PENDING_REVIEW` | 待核单 | 终止后等待核单录入与结算复核 |
## 7. 错误码
| code | 含义 | 触发场景 |
|------|------|----------|
| 581007 | 订单不存在 | id 无对应订单 |
| 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非 `TRAVELLING`(未出发 / 已终止 / 已完成时调用,含二次终止) |
## 8. 示例
### 8.1 典型成功
**请求**:
```
POST /v3/admin/order/60001234567890/terminate
Authorization: Bearer {token}
Content-Type: application/json
```
```json
{
"cancelReason": "客户中途高反送医终止;林芝段酒店已付全款不可退,调整 -300",
"endDayNumber": 3,
"rooms": [
{"refId": "96011", "used": true},
{"refId": "96014", "used": false}
],
"tickets": [
{"refId": "97001", "used": true}
],
"vehicles": [
{"refId": "98001", "dayNumber": 1, "used": true},
{"refId": "98001", "dayNumber": 2, "used": true},
{"refId": "98001", "dayNumber": 3, "used": true}
],
"adjustAmount": -300.00
}
```
**响应**:
```json
{
"code": 200,
"message": "ok",
"success": true,
"data": {
"terminateRefundId": "9610000001",
"baselineRefund": 2264.00,
"adjustAmount": -300.00,
"finalRefund": 1964.00,
"settlementRefundId": "9620000001",
"newStatus": "COMPLETED",
"newFlowStatus": "PENDING_REVIEW"
}
}
```
### 8.2 边界(不填调整额,默认 0)
**请求(片段)**:
```json
{ "cancelReason": "客户主动终止", "endDayNumber": 5, "rooms": [], "tickets": [], "vehicles": [] }
```
**响应(片段)**:
```json
{ "code": 200, "data": { "baselineRefund": 0.00, "adjustAmount": 0.00, "finalRefund": 0.00, "newStatus": "COMPLETED", "newFlowStatus": "PENDING_REVIEW" } }
```
### 8.3 异常 —— 调旧路径(前端联调踩的就是这个)
**请求**:
```
POST /v3/admin/order/60001234567890/cancel/on-trip
```
**响应**:
```
HTTP 404 Not Found
```
> 旧路径在后端已无任何映射,必须改调 `POST /v3/admin/order/{id}/terminate`。
### 8.4 异常 —— 订单非出行中
**响应**:
```json
{ "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false }
```
## 9. 业务边界
- ✅ **适用**:订单当前粗状态 = `TRAVELLING`(出行中)
- ❌ **不适用**:未出发订单走「取消订单」流程(`cancel/pre-trip`);已终止 / 已完成订单二次调用返回 `581018`
- ⚠️ `finalRefund` 最低为 0,不会出现负数;退款额进入核单返还,由财务复核放款;保险恒不退
## 10. 修改前后对比
### 10.1 路径与语义
| 维度 | 改前 | 改后 |
|------|------|------|
| 路径 | `POST /{id}/cancel/on-trip` | `POST /{id}/terminate` |
| 退款预览 | 复用取消预览(或无独立预览) | `POST /{id}/terminate/refund-preview`(独立,POST) |
| 终止后订单状态 | `CANCELLED`(已取消) | `COMPLETED`(已完成)→ 进核单 `PENDING_REVIEW` |
| 入参 VO | `OrderCancelOnTripReqVO` | `OrderTerminateTripReqVO` |
| 出参 VO | `OrderCancelOnTripRespVO` | `OrderTerminateTripRespVO` |
### 10.2 入参字段级
| 字段 | 改前 | 改后 |
|------|------|------|
| cancelReason | ✅ 终止原因 | ✅ 终止原因(+ 调整说明并入) |
| returnAmount | ✅ 手填返还额(必填) | ❌ **删除**(改由后端按资源核算) |
| returnRemark | ✅ 返还备注(必填) | ❌ **删除**(说明并入 cancelReason) |
| endDayNumber | — | ✅ **新增**,停在第几天 |
| rooms / tickets / vehicles | — | ✅ **新增**,各资源行已用判定 |
| adjustAmount | — | ✅ **新增**(可选),人工调整额 |
### 10.3 出参字段级
| 字段 | 改前 | 改后 |
|------|------|------|
| returnAmount | ✅ 返还额(回显) | ❌ **删除** |
| settlementRefundId | ✅(旧实现恒 null) | ✅ 真实核单返还记录 ID |
| newStatus | ✅(值 `已取消`) | ✅(值变 `COMPLETED`) |
| terminateRefundId | — | ✅ **新增** |
| baselineRefund / adjustAmount / finalRefund | — | ✅ **新增** 退款明细金额 |
| newFlowStatus | — | ✅ **新增**(`PENDING_REVIEW`) |
## 11. 影响评估 / 回滚
- **是否破坏向后兼容**:是。路径、入参、出参、终态全部变化。前端仍调旧路径 → 404;仍按旧 body → 校验失败。
- **前端必须同步**:是。「出行中取消」分支需:① 改 URL 为 `/terminate`;② 改 body 为资源勾选模型;③ 终态判断从「已取消」改为「已完成→待核单」。
- **回滚**:本路径下线在后端已合入主线(rename commit + #3557),如需回滚需后端 revert,前端无单独回滚动作。
## 12. 注意事项
- ⚠️ 旧路径 `cancel/on-trip` 在后端**无任何兼容映射**,不会做 301/308 跳转,直接 404。
- 必须配合「终止退款预览」`POST /{id}/terminate/refund-preview` 使用:预览拿资源清单 → 前端本地按结束天标已用/可退 → 提交时只回传 `used` 判定 + `adjustAmount`。
- 终止后订单是「已完成(待核单)」而非「已取消」,列表/详情的状态展示需按新枚举对齐。
## 13. 关联 / 联系人
### 13.1 链接
- **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556)
- **入参/出参完整改造 changelog(同 Issue)**: `06_3556_终止行程接口改造-修改接口-管理后台.md` + `06_3556_终止退款预览-新增接口-管理后台.md`
- **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557)
### 13.2 联系人
- **后端负责人**: @yst
- **前端对接(管理后台)**: 订单详情「出行中取消 / 终止行程」分支
@@ -0,0 +1,47 @@
# 【修改·管理后台】司机档案:详情脱敏修复、列表新增 7 字段(含赛季计数)、编辑不再必传手机/身份证、批量导入大修(CSV/警告档/局部更新)
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3678(已合并 dev-v3,**测试服已部署并 API 实测 12 项通过**) | 无关联工单 | 日期: 2026-06-11
> 影响范围: 管理后台**司机档案**页面(`/admin/fleet/drivers/*` 6 端点)
## ⚠️ 关键说明(前端必看 5 点)
1. **详情两处脱敏变化(原来泄明文)**:`license.no`(驾照号)与 `emergency.phone`(紧急联系人手机)现在返回**脱敏值**(`150***********1234`/`138****9902`)。**编辑回显直接回传脱敏值即可**——后端识别含 `*` 自动跳过更新保持原值;要真改就传新明文。
2. **编辑接口不用再传 phone/idCard 了**(原来 @NotBlank 必填,但前端只有脱敏值,按文档流程必 400):现在编辑可整体省略这两个字段(创建仍必填);传了也会被忽略(创建后不可改,口径不变)。
3. **`relatedOrders` 不再返回假数据**:原来吐 3 条硬编码 mock 订单,现在恒返 `[]` + 新字段 `relatedOrdersReady: false`——请按 flag 显示「派单模块上线后展示关联订单」占位文案,**别再把旧假数据当真渲染**。
4. **列表新增 7 个字段/参数**:出参 +`residentVehiclePlate`(权威常驻车,反查车侧)/`activeYears`(在册年份数组)/`pendingInvitedAt`/`blacklistReason`/顶层 **`seasonCounts`**(赛季 4 值全局计数,不随筛选变化,5 个 Tab 徽章直接用);入参 +`licenseExpireBefore`/`insuranceAnnualEndBefore` 两个到期被动筛。详情同步 +`residentVehiclePlate`/`genderLabel`/`blacklistReason`,且 `activeYearsJson`(字符串)**改名改型**为 `activeYears`(数字数组)。
5. **keyword 语义修正**:姓名模糊 + **手机仅支持 11 位全号精确**(手机是加密列不支持模糊;原文档写「手机模糊」不准确)。
## 1. 校验行为变化
| 场景 | 行为 |
|------|------|
| `season` 赛季 | **不再自由可写**:按转移白名单校验(在册→待续签/拉黑、待续签→在册/归档、归档→在册),非法跳转返 **100001**;**黑名单→在册(解封)编辑端点直接拦截**(走专用解封流程) |
| `insurance.type=annual` | `policyNo`/`annualPremium`/`annualStart`/`annualEnd` 任一缺失返 **100001**(消息列明缺哪个);`none` 不限;`perTrip` 的保险计划选择待保险侧基础设施(暂仍走 `perDayRate` 手填) |
| `insurance.company` | **字段已移除**(出入参都不再有保险公司字段,明细以保险单附件为准;`perDayRate` 保留) |
| 附件 `mimeType` | 新增附件必填且白名单 jpeg/png/webp/pdf(违例 **601005**);编辑保留项(带 id)可省略 |
| 参数错误码 | 文档原写 400001 的场景实际均为 **100001**(平台 `INVALID_PARAM`),文档已订正 |
## 2. 批量导入(`POST /admin/fleet/drivers/import`)
- **CSV 真支持**(原来上传 .csv 直接 500);解析失败/不支持的后缀统一返 **100001**(原来静默返回「成功 0 行」);
- **更新已有司机(续签)= 15 个导入列的局部更新,空白列保持原值**——原来会把该司机**附件全软删、标签清空、年保起止清空**(已修复,放心重导);
- **新增警告档**:出参 +`warnedCount`/`warnings[{row,name,field,msg}]`(驾照距到期不足 60 天仍导入但提醒);
- 注意:导入新增 `保险类型=annual` 的司机会因缺保单子字段进 errors(模板无保单列),annual 新司机请走表单录入。
**实测响应示例**:
```json
{ "code": 200, "data": { "totalRows": 1, "insertedCount": 1, "renewedCount": 0, "errorCount": 0, "errors": [],
"warnedCount": 1, "warnings": [ { "row": 2, "name": "导入测试乙", "field": "licenseExpire", "msg": "驾照不足 60 天" } ] }, "message": "成功" }
```
## 3. 联动行为(无需前端动作)
- **软删司机自动解绑其常驻车**:该司机若是某车常驻司机,删除后车辆的 `primaryDriverId` 自动清空(测试服实测生效);
- 编辑出参为 `{ "kept", "inserted", "softDeleted", "tagsReplaced" }`(文档原写 attachmentKept 等为误,已按代码订正)。
## 4. 文档
FLEET API → **v1.5.54**(§3 全节契约订正 + §14.4 错误码注册表 600205 错位修正),文档站:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
@@ -0,0 +1,49 @@
# 【修改·管理后台】车辆档案:行驶证正/副页图片迁入附件体系,`regCertFrontUrl`/`regCertBackUrl` 字段移除
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087) + hl-user-service(字典种子)
> PR: #3679(已合并 dev-v3,**测试服双服务已部署并 API 实测通过**) | 无关联工单(wx 2026-06-11 拍定) | 日期: 2026-06-11
> 影响范围: 管理后台**车辆档案**新增/编辑表单与详情页的行驶证图片区块
## ⚠️ 关键说明(前端必改 2 处)
行驶证正反面图片本质是附件(纯展示、无业务逻辑消费),从车辆主表字段迁入统一附件体系:
1. **表单(§2.3 新增/§2.4 编辑)**:`regCertFrontUrl`/`regCertBackUrl` 两个独立字段**已移除**(传了会被忽略)。行驶证图片改放 `attachments` 数组,类目:
- `reg_cert_front` = 行驶证正面(上限 1 张)
- `reg_cert_back` = 行驶证副页(上限 1 张)
- 类目从字典 `GET /admin/dict/data/vehicle_attachment_category` 下发(现 8 类,remark=张数上限),编辑走既有 diff 语义(带 id 保留/无 id 新增/未传软删)。
2. **详情(§2.2)**:不再返回 `regCertFrontUrl`/`regCertBackUrl`,从 `attachments[category=reg_cert_front/reg_cert_back]` 读取。
**不变**:行驶证**文本**字段(`regCertNo` 行驶证号/`regCertOwner` 所有人/`regCertUsage` 使用性质)仍是主表结构化字段,表单/详情/批量导入照旧。
## 1. 实测示例(测试服)
新增车辆请求(行驶证图随 attachments 提交):
```json
{
"plate": "蒙A-66666", "vehicleModelId": "<id>", "fleet": "own",
"attachments": [
{ "category": "reg_cert_front", "url": "https://oss.../regfront.jpg", "mimeType": "image/jpeg", "sortNo": 0 },
{ "category": "reg_cert_back", "url": "https://oss.../regback.jpg", "mimeType": "image/jpeg", "sortNo": 0 }
]
}
```
详情 `attachments` 实测返回(节选):
```json
"attachments": [
{ "id": "...", "category": "reg_cert_front", "url": "https://oss.../regfront.jpg", "mimeType": "image/jpeg", "sortNo": 0 },
{ "id": "...", "category": "reg_cert_back", "url": "https://oss.../regback.jpg", "mimeType": "image/jpeg", "sortNo": 0 }
]
```
## 2. 存量数据
已有车辆的两列历史值由 Flyway 自动迁为对应类目附件行(测试服已执行),前端无需任何兼容处理。
## 3. 文档
FLEET API → **v1.5.55** / DB → **v1.5.22**,文档站:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
@@ -0,0 +1,129 @@
---
date: 2026-06-11
type: api-breaking-rename
module: hl-order-service-v3/insurance
priority: high
status: merged-pending-deploy
restart_service: hl-order-service-v3
端类型: 管理后台
breaking_change: true
gitea_issue: 3681
gitea_pr: 3682
---
# ⚠️ 破坏性:保险订单列表接口路径 `/orders` 改名为 `/list`
## ① 接口背景
管理后台保险前端全量切 v3 后,保险页整体 404。排查实测:网关路由通、order-service-v3 健康、Nacos 注册正常;真因是**前端调 `GET /v3/admin/insurance/list`,而后端原路径是 `GET /v3/admin/insurance/orders`**,路径对不上。本次后端把列表接口路径改名为 `/list` 对齐前端。
## ② 变更清单
| 接口 | 旧路径(已下线) | 新路径 | 方法 |
|------|------------------|--------|------|
| 保险订单列表(分页) | `~~/v3/admin/insurance/orders~~` | `/v3/admin/insurance/list` | GET |
> **不加别名**:旧 `/orders` 路径**已删除**,再调用返回 404。
> **未受影响**(仍用 `/orders` 前缀,不要误改):
> - `GET /v3/admin/insurance/orders/{id}`(保险订单详情)
> - `GET /v3/admin/insurance/orders/by-order/{orderId}`(按业务订单查保险列表)
## ③ 接口详情
- **路径**:`GET /v3/admin/insurance/list`
- **作用**:分页查询保险订单列表
- **入参 / 出参与原 `/orders` 完全一致,仅路径变化**
## ④ 入参(query,InsuranceQueryRequest)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `orderId` | Long | 否 | 关联业务订单 ID |
| `policyNo` | String | 否 | 保单号 |
| `status` | String | 否 | 保险状态,枚举见 ⑥ |
| `insuredName` | String | 否 | 被保人姓名 |
| `insuranceProductId` | Long | 否 | 保险产品 ID |
| `pageNo` / `pageSize` | Integer | 否 | 标准分页参数 |
## ⑤ 出参(PageResult<InsuranceOrderVO>)
| 字段 | 类型 | 说明 |
|------|------|------|
| `insuranceOrderId` | Long | 保险订单 ID |
| `orderId` | Long | 关联业务订单 ID |
| `planId` | Long | 保险计划 ID |
| `extOrderNo` | String | 保游网订单号 |
| `extPolicyNo` | String | 保单号(保游网保单号) |
| `policyNo` | String | 兼容字段,与 extPolicyNo 同值,**后续废弃,前端请改用 extPolicyNo** |
| `productName` / `planName` | String | 保险产品 / 计划名称 |
| `premium` | BigDecimal | 保费金额(元) |
| `insuredCount` | Integer | 被保人数 |
| `coverageStartDate` / `coverageEndDate` | LocalDate | 保障起止日期 |
| `status` / `statusLabel` | String | 保险状态 / 状态标签 |
| `policyPdfUrl` | String | 保单 PDF 地址(INSURED 状态异步回填,未回填为 null) |
| `createTime` | LocalDateTime | 投保时间 |
## ⑥ 枚举 / 数据字典
`status` 保险状态:
| 值 | 含义 |
|----|------|
| `PENDING` | 待生效 |
| `EFFECTIVE` | 生效中 |
| `EXPIRED` | 已过期 |
| `CANCELLED` | 已取消 |
## ⑦ 错误码
| 场景 | 响应 |
|------|------|
| 调用已下线的旧路径 `/orders` | **404 Not Found**(路由不存在) |
## ⑧ 示例
### 典型(新路径)
```
GET /v3/admin/insurance/list?pageNo=1&pageSize=20&status=EFFECTIVE
→ 200 { "code":200, "data": { "list":[...], "total":..., "pageNo":1, "pageSize":20 } }
```
### 异常(调旧路径,已下线)
```
GET /v3/admin/insurance/orders?pageNo=1&pageSize=20
→ 404 (旧路径已删除,必须改用 /list)
```
## ⑨ 业务边界
- 仅列表接口改名;详情、按订单查两个接口路径不变。
- 入参出参字段、分页结构与改名前完全相同。
## ⑩ 修改前后对比
| 维度 | 改名前 | 改名后 |
|------|--------|--------|
| 列表路径 | `GET /v3/admin/insurance/orders` | `GET /v3/admin/insurance/list` |
| 旧路径可用性 | — | **下线,调用 404** |
| 入参 / 出参 | InsuranceQueryRequest / PageResult<InsuranceOrderVO> | **不变** |
## ⑪ 影响评估 / 回滚
- 前端**必须**把列表请求从 `/orders` 改为 `/list`,否则继续 404。
- 无后端内部调用方(已 grep mp-service / 其它服务零引用),仅前端直调。
- 回滚:如需回滚,把 Controller `@GetMapping("/list")` 改回 `/orders` 即可(无数据变更)。
## ⑫ 注意事项
- ⚠️ 别把详情 `/orders/{id}` 和按订单 `/orders/by-order/{orderId}` 也改了——这两个**保持 `/orders` 前缀不变**。
- 部署后需重启 `hl-order-service-v3`。
- 待前端确认:若 `/list` 实际想要的是「保险产品列表」而非「保险订单分页」,需另改 `/products`(本次按订单分页处理)。
## ⑬ 关联 / 联系人
- Issue:https://git.1814.love:8443/wx/HL/issues/3681
- PR:https://git.1814.love:8443/wx/HL/pulls/3682
- 代码:`AdminInsuranceController.java`(`@GetMapping("/list")`)
- 负责人:腰苏图
@@ -0,0 +1,51 @@
# 【新增·管理后台】车辆/司机批量导入:新增「下载导入模板」接口 ×2,车辆导入支持直接绑常驻司机
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3687(已合并 dev-v3,**测试服已部署并 API 实测通过**) | 无关联工单(wx 2026-06-11 拍定) | 日期: 2026-06-11
> 影响范围: 管理后台**车辆档案**与**司机档案**的批量导入功能
## ⚠️ 关键说明(前端必看 3 点)
1. **「下载模板」按钮有后端接口了**(原口径「前端静态资源承载模板」作废):
- `GET /admin/fleet/vehicles/import/template` → 车辆导入模板.xlsx
- `GET /admin/fleet/drivers/import/template` → 司机导入模板.xlsx
- **返回 .xlsx 文件流**(`Content-Disposition: attachment`,**不是 Result JSON 包络**),axios 请用 `responseType: 'blob'` + Authorization 头,下载后另存。
2. **模板是双 sheet**:Sheet1 数据页只有表头行(与后端解析逐字一致,提示用户勿改表头;特意不放示例行,防止示例数据被原样导入);Sheet2「填写说明」逐列列出必填/格式/字典取值,前端无需再自造说明文案。
3. **车辆导入新增第 12 列「常驻司机手机号」**(可选):按手机号反查司机直接绑定常驻(严格 1:1)。司机不存在 → 该行报错「常驻司机手机号未找到对应司机」;司机已是别车常驻 → 该行报错(605022 文案);**更新已有车时该列空白=保持原绑定(不会解绑)**。
## 1. 接口契约
| 接口 | 方法 | 返回 |
|---|---|---|
| `/admin/fleet/vehicles/import/template` | GET | xlsx 文件流(12 列表头 + 填写说明 sheet) |
| `/admin/fleet/drivers/import/template` | GET | xlsx 文件流(15 列表头 + 填写说明 sheet) |
实测响应头(测试服):
```
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment;filename="%E8%BD%A6%E8%BE%86%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
```
## 2. 车辆导入带常驻司机实测(测试服)
CSV 行 `蒙A-TPL99,<modelId>,own,company,,,,,,,营运租赁,13977665544` 导入后,车辆详情:
```json
{ "plate": "蒙A-TPL99", "primaryDriverId": "2064920199034810370", "primaryDriverName": "模板测试司机" }
```
反例(手机号无司机)实测:
```json
{ "errorCount": 1, "errors": [ { "row": 2, "plate": "蒙A-TPL98", "msg": "常驻司机手机号未找到对应司机: 13900009999" } ] }
```
## 3. 顺带勘误
司机导入表头「性别」列此前文档/Swagger 误写成「性别(男/女/未知)」——**实际解析 key 就是「性别」两个字**,照旧写法该列整列取不到值。以模板端点下发的表头为准(模板与解析同源,不会再漂移)。
## 4. 文档
FLEET API → **v1.5.56**(§2.6a/§3.6a 新端点 + §2.6 12 列契约),文档站:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
@@ -0,0 +1,49 @@
# 【新增·管理后台】车辆档案:生命周期状态 serviceStatus(在役/停用)+停用/启用接口,个人车随常驻司机赛季自动联动
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3690(已合并 dev-v3,**测试服已部署并 API 实测 11 步全过**) | 无关联工单(wx 2026-06-11 拍定) | 日期: 2026-06-11
> 影响范围: 管理后台**车辆档案**列表/详情/操作列
## ⚠️ 关键说明(前端必看 4 点)
1. **列表/详情新增字段 `serviceStatus`**:`ACTIVE`(在役) / `DISABLED`(停用)。这是**生命周期状态**,与占用态 `vehicleStatus`(idle/busy/maint)**正交**——停用的车不该出现在派单候选里,列表建议给停用车置灰/标签。
2. **新增两个操作接口**(建议放车辆行操作列,仅对**公司车 ownerType=company** 展示):
- `POST /admin/fleet/vehicles/{vehicleId}/disable` 停用
- `POST /admin/fleet/vehicles/{vehicleId}/enable` 启用
- 幂等(重复点不报错);出参 `data: null`。
3. **个人车(ownerType=personal)不能手动停用/启用**:调了返回业务码 **600111**「个人自带车生命周期随常驻司机自动联动,不支持手动停用/启用」。**前端对 personal 车请隐藏/禁用这两个按钮**。个人车的 serviceStatus 完全自动:车主常驻司机在册(active)→车在役;司机归档/拉黑→车自动停用;司机回归→车自动恢复(实测全过,见下)。
4. **列表新增筛选参数 `serviceStatus`**(可选,`ACTIVE`/`DISABLED`,不传=全部)。
## 1. 实测示例(测试服)
个人车随司机赛季联动(实测序列):
| 司机赛季操作 | 车 serviceStatus |
|---|---|
| 建个人车绑常驻司机(司机在册) | `ACTIVE` |
| 司机 在册→待续签(pending) | `ACTIVE`(不变) |
| 司机 待续签→归档 | `DISABLED`(自动停用) |
| 司机 归档→在册 | `ACTIVE`(自动恢复) |
| 司机 在册→黑名单 | `DISABLED`(自动停用) |
公司车手动:
```
POST /admin/fleet/vehicles/{id}/disable → { "code": 200, "data": null, "message": "成功" }
GET /admin/fleet/vehicles/{id} → { ..., "serviceStatus": "DISABLED" }
```
个人车手动(反例实测):
```json
{ "code": 600111, "message": "个人自带车生命周期随常驻司机自动联动,不支持手动停用/启用" }
```
## 2. 存量数据
Flyway 自动加列,存量车全部默认 `ACTIVE`(在役),前端无需兼容处理。
## 3. 文档
FLEET API → **v1.5.57**(§2.5a 新端点 + §2.1/§2.2 字段),文档站:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
@@ -0,0 +1,64 @@
---
date: 2026-06-11
type: dict-data
module: hl-user-service/sys_dict + insurance
priority: medium
status: merged-deployed
restart_service: hl-user-service(已部署并实测通过)
端类型: 管理后台
breaking_change: false
gitea_pr: 3692
---
# 保险状态字典 `insurance_status` 补 INSURING(出单中) + 标签对齐列表措辞
> 关联:保游 4.2 异步出单整改(changelog `10_3642`)引入 INSURING 状态后,字典一直没补;本次为纯字典数据变更,**后端已部署测试服并实测通过,前端零代码改动**(下拉走字典接口自动生效)。
## ⚠️ 关键说明
1. **前端不用改代码**:保险订单管理页筛选下拉走 `GET /admin/dict/data/insurance_status`,刷新页面即可看到新选项(字典接口有 5 分钟 Redis 缓存,测试服已手动清过,立即生效)。
2. **下拉标签措辞变了**:原字典标签(待投保/已投保/已取消/失败)与列表行 `statusLabel`(待出单/已承保/已退保/投保失败)是两套话术,本次统一为列表行同款措辞。若有截图/文案依赖旧措辞请同步。
3. **筛选 INSURING 直接可用**:列表接口 `GET /v3/admin/insurance/list` 的 `status` 入参无白名单校验,传 `INSURING` 即筛出出单中保单。
## 1. 字典终态(共 5 项,按状态生命周期排序)
| dict_value | dict_label(旧 → 新) | sort_order(旧 → 新) | 说明 |
|------------|----------------------|----------------------|------|
| PENDING | 待投保 → **待出单** | 2 → 1 | 已创建未发起投保 |
| **INSURING** | **出单中(新增)** | — → 2 | 保游 4.2 异步出单窗口期,等回调落定 |
| INSURED | 已投保 → **已承保** | 1 → 3 | 出单成功 |
| CANCELLED | 已取消 → **已退保** | 3 → 4 | 已撤单/退保 |
| FAILED | 失败 → **投保失败** | 4 → 5 | 出单失败(可手动重投) |
## 2. 验证示例(测试服实测)
```bash
curl -k "https://api.test.1814.love:9443/admin/dict/data/insurance_status" \
-H "Authorization: Bearer {admin_token}"
```
响应(节选 data,字段同字典接口通用结构):
```json
[
{ "dictValue": "PENDING", "dictLabel": "待出单", "sortOrder": 1 },
{ "dictValue": "INSURING", "dictLabel": "出单中", "sortOrder": 2 },
{ "dictValue": "INSURED", "dictLabel": "已承保", "sortOrder": 3 },
{ "dictValue": "CANCELLED", "dictLabel": "已退保", "sortOrder": 4 },
{ "dictValue": "FAILED", "dictLabel": "投保失败", "sortOrder": 5 }
]
```
筛选出单中保单:
```bash
curl -k "https://api.test.1814.love:9443/v3/admin/insurance/list?status=INSURING&page=1&pageSize=10" \
-H "Authorization: Bearer {admin_token}"
```
(前端按现有 `searchForm.status` 传参即可,无需任何调整。)
## 3. 后端附带变更(与前端无关,备查)
- 新增 Flyway `V20260611_002`(hl-user-service):整字典幂等补种 + 存量行收敛(原种子只在手工脚本 `sql/dict_business_enums.sql`,未纳入 Flyway,新环境会缺整个字典)。
- `InsuranceQueryRequest.status` 的 Swagger 注释由过时值集(PENDING/EFFECTIVE/EXPIRED/CANCELLED)更正为真实值集(PENDING/INSURING/INSURED/CANCELLED/FAILED),v2/v3 双份,纯文档无行为变化。
@@ -0,0 +1,45 @@
# 【修复·管理后台】车务:司机/车辆列表日期筛选参数报错修复 + 车型大类图标长度放宽 64
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-fleet-service(8087)
> PR: #3694 + #3695(文档版本记录)(均已合并 dev-v3,**测试服已部署并 API 实测通过**) | 无关联工单(用户即时报修) | 日期: 2026-06-11
> 影响范围: 管理后台**司机档案/车辆档案列表筛选** + **车型大类新增/编辑**
## ⚠️ 关键说明(前端必看 2 点)
1. **列表日期筛选现在能用了(之前一传就报错)**:司机列表 `licenseExpireBefore`/`insuranceAnnualEndBefore`、车辆列表 `insureDueBefore`/`inspectDueBefore` 四个 GET 日期参数,此前传 `2026-07-11` 这类标准格式直接报 `Failed to convert ... LocalDate`(后端缺日期绑定注解),现已修复。**格式仍是 `yyyy-MM-dd`,请求/响应形状零变化,前端无需改任何代码**,之前因报错被屏蔽的筛选交互可以放开。
2. **车型大类 `icon` 上限 8→64 字符**:之前传图标组件名(如 `BusOutline`=10 字符)被 400「图标长度不能超过 8」拒(原按单 emoji 设计),现在最长 64,**组件名或 emoji 都可以**;超 64 报 400「图标长度不能超过 64」。
## 1. 日期筛选修复(4 个参数)
| 接口 | 参数 | 说明 |
|------|------|------|
| `GET /admin/fleet/drivers/page` | `licenseExpireBefore` | 驾照到期日 ≤ 该日(含),yyyy-MM-dd |
| `GET /admin/fleet/drivers/page` | `insuranceAnnualEndBefore` | 年保到期日 ≤ 该日(含),仅 annual 行命中 |
| `GET /admin/fleet/vehicles/page` | `insureDueBefore` | 保险到期日 ≤ 该日(含)——同根因一并修,此前同样报错 |
| `GET /admin/fleet/vehicles/page` | `inspectDueBefore` | 年检到期日 ≤ 该日(含)——同上 |
测试服实测(用户原始报错 URL):
```
GET /admin/fleet/drivers/page?page=1&pageSize=24&season=active&insuranceAnnualEndBefore=2026-07-11&licenseExpireBefore=2026-08-10
→ {"code":200,"message":"成功","data":{"records":[],"total":0,...}}
// 不再报 Failed to convert property value of type 'java.lang.String' to 'java.time.LocalDate'
```
## 2. 车型大类 icon 放宽
`POST /admin/fleet/vehicle-types` 与 `PUT /admin/fleet/vehicle-types/{typeId}` 入参 `icon`:≤8 → **≤64**(DB 列同步 `VARCHAR(8)→VARCHAR(64)`,Flyway `V20260611_004` 纯加宽,存量 emoji 图标无损)。
测试服实测(用户原始报错请求体):
```
PUT /admin/fleet/vehicle-types/2064609312168083458
{"typeKey":"mpv","typeName":"商务车","icon":"BusOutline","description":"高级团","sortOrder":99}
→ {"code":200,"message":"成功","data":{"id":"2064609312168083458","typeKey":"mpv","typeName":"商务车","icon":"BusOutline","description":"高级团","sortOrder":99,...}}
// 列表回读 icon="BusOutline" 一致
```
## 3. 文档版本
FLEET API → **v1.5.58** / FLEET DB → **v1.5.25**,文档站已同步:https://web.test.1814.love:9443/hl-docs/order-v3/api/API-SPEC-FLEET-V1.5.html
@@ -0,0 +1,25 @@
# 【修复·管理后台】保险:保游网余额查询「URI is not absolute」报错修复(配置补齐+错误提示改清晰)
> 存放目录: changelogs-v2/2026-06/
> 涉及服务: hl-order-service-v3(8086)
> PR: #3696(已合并 dev-v3,**测试服已部署并 API 实测通过**) | 无关联工单(用户即时报修) | 日期: 2026-06-11
> 影响范围: 管理后台**保险管理**(`/v3/admin/insurance/*`),另预防性补齐了合同/支付同类配置
## ⚠️ 关键说明(前端必看 2 点)
1. **余额查询恢复正常,前端无需改任何代码**:`GET /v3/admin/insurance/balance` 此前报「保游网余额查询失败: URI is not absolute」,根因是保险模块迁二期时测试环境配置漏迁(非代码 bug),已补齐并实测恢复;同因风险面(产品同步/投保/退保/充值/保单下载等所有走保游网的接口)一并解除。
2. **错误文案变化(仅异常场景)**:今后若再出现接入配置缺失,返回新错误码 **540411**「保游网接入未配置(baoyou.api.base-url),请检查 Nacos 配置」,不会再出现晦涩的 "URI is not absolute";前端无需针对性处理,照常展示 message 即可。
## 1. 实测结果(测试服网关)
```
GET /v3/admin/insurance/balance
→ {"code":200,"message":"成功","data":0} // 0 = 保游测试账户(apitest251208)真实余额
GET /v3/admin/insurance/products?page=1&pageSize=5
→ {"code":200,"message":"成功","data":{"total":10,...}}
```
## 2. 一并预防性补齐(无行为变化,仅消除同类隐患)
二期 `hl-order-service-v3` 测试环境同批补齐了以下与一期同源同值的配置段,对应模块此前同样存在「一调就报 URI is not absolute」的隐患:微信支付(wechat.pay)、12301 电子合同(contract.platform)、腾讯电子签(tencent-esign)、保单 PDF 公网域名(oss.domain)、保险出单主体(insurance.entities)。前端如之前在二期页面遇到过合同/支付类「URI is not absolute」报错,可以重试。
@@ -0,0 +1,83 @@
# 【新增接口·管理后台】司机档案——车管一键批量续签(换季)
> 服务:hl-fleet-service(8087) | 分支:dev-v3 | PR:#3699 | 已部署测试服并实测通过(2026-06-11)
> 契约出处:FLEET API §3.7 | 前端触发位:司机档案列表页「批量续签」按钮(换季时用)
## ⚠️ 关键说明
1. **一键换季动作**:把指定司机(或全部在册 `season=active` 司机)批量转入续签流程——`active → pending` + 为每人生成续签 H5 邀请链接/二维码。**链接需车管手动转发给司机**(本期无自动推送)。
2. **非在册司机不报错**:`pending/archived/blacklist` 的司机自动跳过,进 `skipped[]` 给原因,不中断整批。
3. `renewSeasonLabel` 必填但**不落库**,仅入审计日志;`remark` 同理。
4. 防双击:同参数 3 秒内重复提交返「批量续签处理中,请勿重复提交」。
## 1. 新增端点
`POST /admin/fleet/drivers/batch-season-renew`
### 入参(body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| driverIds | string[] | 否 | 目标司机ID列表(雪花字符串);**缺省/空数组 = 对全部 season=active 司机全量换季**;含不存在的 ID 整批报 100001 |
| renewSeasonLabel | string | 是 | 续签目标赛季标识(如 `2027`);缺失返 400 |
| remark | string | 否 | 批量动作备注(入审计日志) |
### 请求示例
```bash
curl -k -X POST "https://api.test.1814.love:9443/admin/fleet/drivers/batch-season-renew" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"driverIds":["2065002428792492033"],"renewSeasonLabel":"2027","remark":"2027 赛季换季"}'
```
### 响应示例(测试服实测)
```json
{
"code": 200,
"message": "成功",
"data": {
"matchedCount": 1,
"transitionedCount": 1,
"inviteGeneratedCount": 1,
"invites": [
{
"driverId": "2065002428792492033",
"driverName": "张师傅",
"token": "e4dc8e393bc54224aeb97a346611cb58",
"url": "https://h5.hl-fleet.com/onboard?token=e4dc8e393bc54224aeb97a346611cb58",
"qrCodeUrl": "data:image/png;base64,iVBORw0KGgo...",
"expireAt": "2026-06-25T17:25:20"
}
],
"skipped": []
}
}
```
| 出参字段 | 说明 |
|---|---|
| matchedCount | 匹配司机数 |
| transitionedCount | 成功转入续签(active→pending)数 |
| inviteGeneratedCount | 生成续签邀请数(同事务恒等于 transitionedCount) |
| invites[] | 「待发列表」:driverId/driverName/token/url(H5 链接,`?token=` 参数)/qrCodeUrl(**二维码 Base64 DataURL,前端可直接 img src 渲染**)/expireAt(14 天有效) |
| skipped[] | 跳过明细:driverId + reason(如 `season=pending≠active(非在册,跳过)`) |
### 非 active 司机被跳过(实测)
```json
{ "matchedCount": 1, "transitionedCount": 0, "inviteGeneratedCount": 0, "invites": [],
"skipped": [ { "driverId": "2065002428792492033", "reason": "season=pending≠active(非在册,跳过)" } ] }
```
## 2. 错误码
| code | 触发场景 |
|---|---|
| 400 | renewSeasonLabel 缺失/空白(平台参数校验统一口径) |
| 100001 | driverIds 含不存在的司机 ID(消息列出缺失 ID,整批不执行) |
## 3. 联动效果(前端无需额外调用)
- 司机列表 §3.1 的 `season` 变 `pending`、`pendingInvitedAt` 有值(卡片可显示「续签链接已发送·{日期}」);
- 每位司机自动生成一条 mode=renew 的待审核记录(司机打开链接走 §4 续签 3 步流程,与单个生成链接 §4.1 完全同机制)。
@@ -0,0 +1,85 @@
# 【新增接口+入参变更·管理后台】司机险走保游网——档案页投保/保单/退保 + 保险块字段变更
> 服务:hl-fleet-service(8087) + hl-order-service-v3(8086) | 分支:dev-v3 | PR:#3700 | 已部署测试服并实测通过(2026-06-11)
> 契约出处:FLEET API §3.3/§3.4 保险块 + §13.7 | 业务拍板:司机险由车管在**司机档案页手动点「投保」**出单(非派车自动、非定时);保险提供方走 **order-v3**
## ⚠️ 关键说明(含 2 处破坏性变更)
1. **🔴 破坏性①——司机保存入参 `insurance.perDayRate` 字段删除**(§3.3 新增/§3.4 编辑):perTrip 日费率改走保游网计划费率,不再手填。前端表单请移除该输入项;继续传该字段会被忽略。
2. **🔴 破坏性②——`insurance.type=perTrip` 时 `insurancePlanId` 必填**(返 100001):从「司机可选保险计划下拉」(下方接口 1)选计划。`annual`/`none` 传 null;类型从 perTrip 切走时后端自动清空该字段。
3. 司机详情 §3.2 `insurance` 块新增回显 `insurancePlanId`(perTrip 有值,字符串雪花)。
4. **投保动作会真实调保游网出单、从保游账户真实扣费**——前端联调请只调下拉/保单列表/校验反例,出单正向请约定后用测试计划操作。
5. 计划下拉数据源 = 运营在「保险计划打标」端点把计划标为 `DRIVER`/`BOTH`(接口 5,order-v3 管理端);**新同步计划默认 CUSTOMER,司机端不可见**,须显式打标。
## 1. 司机可选保险计划下拉
`GET /admin/fleet/drivers/insurance/plan-options`
```json
{ "code": 200, "data": [
{ "planId": "2054773833342451714", "planName": "10万计划", "productName": "山河令(太保山东新)", "usageCategory": "DRIVER" }
], "message": "成功" }
```
## 2. 司机险投保(档案页「投保」按钮)
`POST /admin/fleet/drivers/{driverId}/insurance/purchase`
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| planId | string(雪花) | 是 | 司机专用计划(接口 1 选取) |
| coverageStartDate / coverageEndDate | string(yyyy-MM-dd) | 是 | 保障起止;**「按赛季」「按年」快捷预填由前端实现**(仍可手改);起>止返 100001 |
| remark | string | 否 | 缺省后端填「司机险投保: {司机姓名}」 |
成功返回保单(被保人证件号已脱敏;金额/雪花均字符串):
```json
{ "code": 200, "data": {
"insuranceOrderId": "1934567890123456789", "policyNo": "...", "extPolicyNo": "BY-2026-...",
"extOrderNo": "...", "totalPremium": "88.00", "status": "INSURED", "statusLabel": "已投保",
"coverageStartDate": "2026-07-01", "coverageEndDate": "2027-06-30",
"insuredPersons": [ { "name": "周师傅", "idCardNo": "1502**********0017" } ] } }
```
> 异步出单型产品返回 `status=INSURING`(投保中,`extPolicyNo` 暂空),保游回调落定后翻 `INSURED`/`FAILED`,刷新保单列表即可。
## 3. 司机保单列表
`GET /admin/fleet/drivers/{driverId}/insurance/policies` → `data` 为接口 2 同构对象数组(createTime 倒序;无保单返 `[]`)。
## 4. 司机险退保(仅人工误投时用)
`POST /admin/fleet/drivers/{driverId}/insurance/policies/{insuranceOrderId}/cancel`
- 保单不属于该司机 → 100001(越权守卫);仅 `INSURED/INSURING` 可退,否则 540202。
- 业务拍板:**取消派车不退保、换司机投新单旧单到期自然失效、离职拉黑不自动退**——本端点只服务误投撤销。
## 5. 保险计划打标(order-v3 管理端·运营用)
`PUT /v3/admin/insurance/plans/{planId}/usage-category` body:`{"usageCategory":"DRIVER"}`(白名单 CUSTOMER/DRIVER/BOTH,非法返 540223)。
配套:计划查询出参(`GET /v3/admin/insurance/products/{productId}/plans` 等)已新增 `usageCategory` 字段,可做打标 UI。客人端选计划**不收紧**(维持全量,拍板)。
## 6. 错误码汇总
| code | 触发场景 |
|---|---|
| 100001 | perTrip 缺 insurancePlanId / 保障起>止 / 退保保单不属于该司机 |
| 600205 | 司机不存在 |
| 540031 | 该保险计划未标注为司机可用(选了 CUSTOMER 计划) |
| 540032 | 该司机该保障期已有生效保单(一天只一份生效,含投保中) |
| 540202 | 保单当前状态不可退保 |
| 540223 | 计划使用分类非法(打标端点) |
| 605601 | 保险服务不可用(order-v3 不通,稍后重试) |
### 实测反例示例
```bash
# 选 CUSTOMER 计划投保 → 540031
curl -k -X POST "https://api.test.1814.love:9443/admin/fleet/drivers/{driverId}/insurance/purchase" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"planId":"2054773833342451714","coverageStartDate":"2026-07-01","coverageEndDate":"2027-06-30"}'
# => {"code":540031,"message":"该保险计划未标注为司机可用"}
# perTrip 不带 insurancePlanId 建司机 → 100001
# => {"code":100001,"message":"参数非法: 保险类型为 perTrip 时缺少必填子字段: insurancePlanId(保险方案id,选保游网司机专用计划)"}
```
@@ -0,0 +1,184 @@
---
date: 2026-06-11
type: api-contract-clarify
module: hl-order-service-v3/insurance
priority: high
status: code-already-merged
restart_service: hl-order-service-v3
端类型: 管理后台
breaking_change: false
---
# v3 保险「投保」接口入参契约说明(管理后台保险全量切 v3 联调补充)
## ① 接口背景
管理后台保险模块前端已全量指向 v3,投保入参字段名按设计文档(Knife4j / API 文档)硬切。
但 v3 投保接口(`/v3/admin/insurance/purchase`)此前**从未推送过入参契约 changelog**(仓库已有的 `#3642` 只说了出单状态/列表详情出参,未涉及投保入参)。
本文档把 v3 投保两个接口的**入参契约**完整内联,并明确**老字段名是否仍被接收**这一前端关心的问题。
> ⚠️ 本文档不涉及"保险页 404"——404 属网关路由 / 服务注册问题(需后端确认测试服 `/v3/admin/insurance/**` 是否已路由到 hl-order-service-v3:8086、order-service-v3 是否已启动),不在接口契约范畴。
## ② 变更清单
| # | 接口 | 方法 | 说明 |
|---|------|------|------|
| 1 | `/v3/admin/insurance/purchase` | POST | 手动投保(指定方案或产品+计划 + 可选被保人) |
| 2 | `/v3/admin/insurance/purchase-by-scheme` | POST | 按方案自动投保(仅 orderId + schemeId) |
性质:**契约澄清,非破坏性**。字段名与 v2 一致;路径前缀由 `/admin/insurance` 变为 `/v3/admin/insurance`。
## ③ 接口详情
### 3.1 手动投保
- **路径**:`POST /v3/admin/insurance/purchase`
- **Content-Type**:`application/json`
- **请求体**:`PurchaseInsuranceRequest`
- **返回**:`Result<List<InsuranceOrderDetailVO>>`(创建的保险订单详情列表)
### 3.2 按方案自动投保
- **路径**:`POST /v3/admin/insurance/purchase-by-scheme`
- **请求体**:`AutoPurchaseRequest`
- **返回**:`Result<Void>`
## ④ 入参
### 4.1 PurchaseInsuranceRequest(手动投保)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `orderId` | Long | ✅ | 业务订单 ID |
| `schemeId` | Long | 否 | 保险方案 ID(优先用方案匹配;为空则用 `insuranceProductId`+`planId`) |
| `insuranceProductId` | Long | 方案为空时必填 | 保险产品 ID |
| `planId` | Long | 方案为空时必填 | 保险计划 ID |
| `coverageStartDate` | LocalDate | 否 | 保障开始日期,为空时后端按订单 startDate 自动填充 |
| `coverageEndDate` | LocalDate | 否 | 保障结束日期,为空时后端按订单 endDate 自动填充 |
| `insuredPersons` | List<InsuredPersonItem> | 否 | 被保人列表;**为空时后端按订单出行人自动填充**,传了则以传入为准 |
| `remark` | String | 否 | 备注 |
#### InsuredPersonItem(被保人)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `name` | String | ✅ | 姓名 |
| `idCardType` | String | ✅ | 证件类型,枚举见 ⑥;**兼容老字段名 `idType`**(`@JsonAlias`) |
| `idCardNo` | String | ✅ | 证件号码(落库自动加密、查询自动解密,前端无感);**兼容老字段名 `idNo`** |
| `birthday` | LocalDate | 否 | 出生日期 |
| `phone` | String | 否 | 手机号 |
> ⚠️ **v3 被保人入参无 `gender`(性别)字段**:v2 的 `InsuredPersonItem` 有 `gender`,v3 **没有**。前端从 v2 切 v3 若仍传 `gender`,将被 Jackson 静默忽略(`FAIL_ON_UNKNOWN_PROPERTIES=false`,不报错)。
### 4.2 AutoPurchaseRequest(按方案投保)
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `orderId` | Long | ✅ | 旅行订单 ID |
| `schemeId` | Long | ✅ | 保险方案 ID |
## ⑤ 出参
`/v3/admin/insurance/purchase` 返回 `List<InsuranceOrderDetailVO>`(新建保险订单详情)。
其中 `status` / `statusLabel` / `policyNo` 的**异步出单**语义(可能为 `INSURING`/出单中、`policyNo` 可能为空)见同目录 `#3642 保险出单改异步` changelog。
## ⑥ 枚举 / 数据字典
`idCardType` 证件类型(以代码注解为准,完整证件字典与 traveler 模块对齐):
| 值 | 含义 |
|----|------|
| `ID_CARD` | 身份证 |
| `PASSPORT` | 护照 |
| `HONG_KONG` | 港澳通行证 |
| `TAIWAN` | 台湾通行证 |
| `OTHER` | 其他 |
## ⑦ 错误码
| 场景 | 响应 |
|------|------|
| 缺 `orderId` | 400 「订单ID不能为空」 |
| 被保人缺 `idCardType`(或老名 `idType`) | 400 「证件类型不能为空」 |
| 被保人缺 `idCardNo`(或老名 `idNo`) | 400 「证件号码不能为空」 |
| 方案与产品+计划均为空 | 业务校验失败(无法定位保险产品) |
## ⑧ 示例
### 典型(推荐:标准字段名)
```json
POST /v3/admin/insurance/purchase
{
"orderId": "2026270000000000001",
"schemeId": "2026279738275856500",
"insuredPersons": [
{
"name": "张三",
"idCardType": "ID_CARD",
"idCardNo": "110101199001011234",
"phone": "13800138000",
"birthday": "1990-01-01"
}
],
"remark": "管理后台手动投保"
}
```
### 边界(不传被保人 → 后端按订单出行人自动填充)
```json
POST /v3/admin/insurance/purchase
{ "orderId": "2026270000000000001", "schemeId": "2026279738275856500" }
```
### 兼容(老字段名 idType/idNo 仍被接收,@JsonAlias 兜底)
```json
{
"orderId": "2026270000000000001",
"schemeId": "2026279738275856500",
"insuredPersons": [
{ "name": "张三", "idType": "ID_CARD", "idNo": "110101199001011234" }
]
}
```
### 异常(缺证件号 → 400)
```json
请求: { "orderId": "...", "insuredPersons": [ { "name": "张三", "idCardType": "ID_CARD" } ] }
响应: { "code": 400, "message": "证件号码不能为空" }
```
## ⑨ 业务边界
- `insuredPersons` 为空 → 后端按订单出行人自动填充被保人。
- `coverageStartDate` / `coverageEndDate` 为空 → 后端按订单 startDate / endDate 填充。
- 同时传 `idCardType` 和 `idType`(不推荐)→ Jackson 按后出现的覆盖,建议**只传标准名**。
- 出单为异步:返回时保险订单可能处于 `INSURING`、`policyNo` 暂空,需轮询 / 回调获取最终保单号(详见 `#3642`)。
## ⑩ 修改前后对比
| 维度 | v2(`/admin/insurance`) | v3(`/v3/admin/insurance`) |
|------|--------------------------|-----------------------------|
| 路径前缀 | `/admin/insurance` | `/v3/admin/insurance` |
| `idCardType`/`idCardNo` | ✅(兼容 `idType`/`idNo`) | ✅(兼容 `idType`/`idNo`,**一致**) |
| 被保人 `gender` | ✅ 有 | ❌ **无** |
| 出单 | 同步 | 异步(INSURING 状态,见 #3642) |
## ⑪ 影响评估 / 回滚
- 前端切标准字段名 `idCardType`/`idCardNo` **安全**;继续用老名 `idType`/`idNo` 也**不会 400**(兼容未下线)。
- 唯一需前端动作:**停止传 `gender`**(v3 无此入参,传了被忽略;如业务需要被保人性别,由后端从出行人档案带,前端无需关心)。
- 无代码回滚项(本文档为存量契约说明,未改代码)。
## ⑫ 注意事项
- **「保险页 404」非本文档范畴**:属网关路由 / 服务注册问题,请后端在测试服核:① `/v3/admin/insurance/**` 是否路由到 hl-order-service-v3(8086);② order-service-v3 是否已启动;③ 小程序侧若经 BFF,`MpInsuranceFeignClient` 的 `name="hl-order-service"`(无 v3 后缀)在测试服注册到的是 v2 还是 v3。
- `idCardNo` 已挂加密 TypeHandler,落库加密、查询解密,日志脱敏,前端无感。
## ⑬ 关联 / 联系人
- 来源:管理后台保险全量切 v3 联调反馈(前端 sync-log)
- 相关 changelog:`#3642 保险出单改异步`(出参状态)、`changelogs/2026-05/07_fix_insurance_purchase_idcardtype_field_rename.md`(v2 同源字段改名背景)
- 代码位置:`hl-order-service-v3/.../insurance/dto/PurchaseInsuranceRequest.java`、`AdminInsuranceController.java:124`
- 负责人:腰苏图
@@ -0,0 +1,175 @@
# 【修改接口·管理后台】车型价格日历——三模式调价(ABS/DELTA/PERCENT)+节假日筛选+互斥校验落地(§9 全块说明)
> 服务:hl-fleet-service(8087) | 分支:dev-v3 | PR:#3714 | 已部署测试服并 22 项 API 实测通过(2026-06-12)
> 契约出处:FLEET API §9.1-§9.4(文档已同 PR 更新至 v1.5.61) | 前端触发位:车管控制台「价格日历」页(page_pricing 原型 BulkPriceSheet)
> 本文是价格日历**整块 4 接口的完整说明**(应后端要求全面同步),已上线功能 + 本次新增一并列出,前端可按本文直接对接。
## ⚠️ 关键说明
1. **完全向后兼容,已对接代码零改动**:本次新增字段全部可选。不传 `adjustMode` 默认 `ABS`(固定价),与原行为完全一致。
2. **新增三模式调价**(本次 PR):`adjustMode` = `ABS`(设为固定价) / `DELTA`(在各日现价上加减金额) / `PERCENT`(按百分比调整)。`DELTA`/`PERCENT` 时 `dayPrice` 不需要传,改传 `adjustValue`。
3. **DELTA/PERCENT 的基准价规则**:命中日已设价 → 用当日现价计算;未设价 → 用车型 `basePrice` 兜底;两者都没有 → **该日跳过不写**(不报错)。计算结果 < 0 一律按 `0.00` 落库。`PERCENT` 结果四舍五入保留两位(HALF_UP)。
4. **新增仅节假日筛选**(本次 PR):`holidayOnly=true` 只设置节假日(节假日清单由后端 Nacos 配置维护,**当前为验证占位日期,业务法定节假日清单待车管确认后由后端配置**,前端无需关心数据源)。
5. **三筛选互斥**(本次 PR,行为变更):`weekdayOnly` / `weekendOnly` / `holidayOnly` 同时传两个及以上 `true` → 返 `code=400` 参数错(此前是静默 0 命中返成功,**前端若有依赖旧静默行为的逻辑请注意**)。
6. **金额字段两位小数**(本次 PR):`dayPrice`/`adjustValue` 传超过 2 位小数返 `code=400`。
7. **防双击/并发**(本次 PR):三个写端点(批量设价/批量改状态/区间清除)都加了幂等(同参数 3 秒窗口重复提交返「…处理中,请勿重复提交」)+ 同车型并发互斥锁。前端连点按钮会收到 400 类提示,正常单次操作无感。
8. **错误码口径勘正**:参数校验失败统一返业务码 **400**(HTTP 恒 200,错误信息在 `message`)。文档旧版写的 `400001` 为笔误,以 400 为准。
9. 所有金额出参为**字符串**(如 `"800.00"`),雪花 ID 出参为字符串,前端勿当数字解析。
## 1. 查询价格日历(月视图) — 无变更,完整契约
`GET /admin/fleet/pricing-calendar/{vehicleModelId}?year=2026&month=3`
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| vehicleModelId | path | string | 是 | 车型型号 ID(车型树 models[].id) |
| year | query | number | 是 | 年份(2020-2100,越界返 400) |
| month | query | number | 是 | 月份(1-12,越界返 400) |
### 请求示例
```bash
curl -k "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/2057378612593823745?year=2099&month=1" \
-H "Authorization: Bearer {token}"
```
### 响应示例(测试服实测)
```json
{
"code": 200,
"message": "成功",
"data": {
"year": 2099,
"month": 1,
"vehicleModelId": "2057378612593823745",
"modelName": "丰田普拉多",
"prices": [
{ "date": "2099-01-01", "dayPrice": "800.00", "status": "AVAILABLE", "remark": "旺季价格" },
{ "date": "2099-01-08", "dayPrice": "900.00", "status": "CLOSED", "remark": "临时停租" }
]
}
}
```
| 出参字段 | 说明 |
|---|---|
| prices | **仅返回已设置价格的日期**(未设价日期不出现,空月返回空数组) |
| prices[].dayPrice | 当日租赁价,**字符串**两位小数 |
| prices[].status | 可售状态:`AVAILABLE`=可售 / `CLOSED`=关闭 |
## 2. 批量设置价格 — 本次新增三模式/节假日/互斥,完整契约
`PUT /admin/fleet/pricing-calendar/{vehicleModelId}`
### 入参(body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| startDate | string | 是 | 开始日期 yyyy-MM-dd |
| endDate | string | 是 | 结束日期,须 ≥ startDate 且总天数 ≤ 366 |
| adjustMode | string | 否 | 🆕 调价模式:`ABS`=设为固定价 / `DELTA`=现价加减金额 / `PERCENT`=现价按百分比调;**不传默认 ABS**(向后兼容);非法值返 400 |
| dayPrice | string | ABS 必填 | 当日租赁价(¥,≥0,两位小数)。**仅 ABS 模式必填且生效**,DELTA/PERCENT 不需要传 |
| adjustValue | string | DELTA/PERCENT 必填 | 🆕 调整值:DELTA=加减金额(可负,如 `-100.00`) / PERCENT=百分比数值(`10`=+10%,`-5`=-5%)。两位小数 |
| status | string | 否 | `AVAILABLE` / `CLOSED`,不传默认 AVAILABLE,非法值返 400 |
| remark | string | 否 | 备注 |
| weekdayOnly | boolean | 否 | 仅工作日(命中周末跳过) |
| weekendOnly | boolean | 否 | 仅周末(命中工作日跳过) |
| holidayOnly | boolean | 否 | 🆕 仅节假日(命中非节假日跳过,节假日清单后端 Nacos 维护) |
| selectedWeekdays | number[] | 否 | 指定星期几(1=周一…7=周日),非空则只设命中星期 |
| excludeDates | string[] | 否 | 排除日期列表(区间内这些日期不设置) |
> ⚠️ `weekdayOnly`/`weekendOnly`/`holidayOnly` **互斥**,≥2 个同时 true 返 400「工作日/周末/节假日筛选不可同时启用」。
### 请求示例 1——固定价(原有用法,完全不变)
```bash
curl -k -X PUT "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/2057378612593823745" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"startDate":"2099-01-01","endDate":"2099-01-05","dayPrice":"800.00","remark":"旺季价格"}'
```
### 请求示例 2——🆕 全月工作日涨 100 元(DELTA)
```bash
curl -k -X PUT "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/2057378612593823745" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"startDate":"2099-01-01","endDate":"2099-01-31","adjustMode":"DELTA","adjustValue":"100","weekdayOnly":true}'
```
### 请求示例 3——🆕 节假日统一上浮 15%(PERCENT + holidayOnly)
```bash
curl -k -X PUT "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/2057378612593823745" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"startDate":"2099-01-01","endDate":"2099-01-31","adjustMode":"PERCENT","adjustValue":"15","holidayOnly":true}'
```
### 响应
成功:`{ "code": 200, "message": "成功" }`(无 data)
### 测试服实测数据点(可作前端联调预期)
| 操作 | 结果 |
|---|---|
| ABS 800 后 DELTA +100 | 900.00 |
| 900 后 PERCENT -10 | 810.00 |
| DELTA +100 作用于未设价日(车型 basePrice=1000) | 1100.00 |
| DELTA -99999(负穿) | 0.00(兜底) |
| holidayOnly=true,区间 11 天含 1 个节假日 | 仅节假日 1 天写入 |
| weekdayOnly+weekendOnly 同 true | code=400 |
| adjustMode="FOO" / DELTA 缺 adjustValue / ABS 缺 dayPrice / dayPrice 三位小数 | code=400 |
## 3. 批量修改状态 — 无变更(新增幂等防护),完整契约
`PUT /admin/fleet/pricing-calendar/{vehicleModelId}/status`
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| startDate | string | 是 | 开始日期 yyyy-MM-dd |
| endDate | string | 是 | 结束日期 |
| status | string | 是 | `AVAILABLE` / `CLOSED`,非法值返 400 |
| remark | string | 否 | 备注;**不传则保留各记录原备注** |
只改区间内**已有记录**的状态(不影响价格,未设价日期不会凭空建记录)。
```bash
curl -k -X PUT "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/2057378612593823745/status" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"startDate":"2099-01-01","endDate":"2099-01-31","status":"CLOSED","remark":"临时停租"}'
```
成功:`{ "code": 200, "message": "成功" }`
## 4. 清除价格日历 — 无变更(新增幂等防护),完整契约
`DELETE /admin/fleet/pricing-calendar/{vehicleModelId}?startDate=2099-01-01&endDate=2099-01-31`
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| startDate | query | string | 是 | 开始日期 yyyy-MM-dd |
| endDate | query | string | 是 | 结束日期 |
软删除区间内该车型全部价格记录;删后**可重新设置同日价格**(测试服实测通过)。
```bash
curl -k -X DELETE "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/2057378612593823745?startDate=2099-01-01&endDate=2099-01-31" \
-H "Authorization: Bearer {token}"
```
成功:`{ "code": 200, "message": "成功" }`
## 5. 错误码表(§9 全块)
| code | message | 触发场景 | 涉及端点 |
|---|---|---|---|
| 400 | (具体校验消息) | 参数校验失败:必填缺失/格式错/枚举非法/互斥冲突/超两位小数/year·month 越界 | 全部 |
| 600500 | 日租价不能为负 | dayPrice < 0(防御兜底,正常会先被 400 拦) | §9.2 |
| 600501 | 日期范围非法:开始日期不能晚于结束日期 | startDate > endDate | §9.2 |
| 600502 | 日期范围不能超过 366 天 | 区间总天数(含首尾) > 366 | §9.2 |
| 600503 | 车型型号不存在 | vehicleModelId 无效/已软删 | §9.1 / §9.2 / §9.3 |
| 401 | 未登录 | token 缺失/过期 | 全部 |
> §9.4 清除接口不校验车型存在性(按契约,清不存在车型的区间等于无操作返 200)。
> HTTP 状态码恒 200,业务错误看 `code` 字段。
@@ -0,0 +1,43 @@
# 【行为变更·司机H5+管理后台】司机审核驳回短信接通知中心真发上线,H5 驳回后原链接可重提
> 服务:hl-fleet-service(8087) + hl-user-service(8081/8181) | 分支:dev-v3 | PR:#3715(主) #3720 #3722(hotfix) | 工单:#3713
> 已部署测试服并 E2E 实测通过(2026-06-12):驳回短信经阿里云真实发出(模板 SMS_507190242),驳回后原链接重提回待审
## ⚠️ 关键说明
1. **驳回短信从「日志桩」变成「真发」**:此前 `LogStubNotificationServiceImpl` 只打日志、司机实际收不到任何短信;现在车管驳回司机档案申请时,系统经通知中心给司机手机号真实发送阿里云短信(签名「呼籁旅行」)。**测试环境驳回操作会真发短信,联调时请用可控手机号**。
2. **H5 行为变更(前端可感知)**:司机被驳回后用**原链接**重新打开/修改/提交,不再返回 `600302「邀请链接已使用」`——init/ocr/submit 全放行;重提成功后该申请单回到待审状态。**hl-ui 司机 H5 若对 600302 有特判文案/拦截页,请确认驳回场景不再命中**(600302 现在仅 approved 终态返回)。
3. **短信文案**(阿里云已过审模板,变量 ≤2):`${name}您好,您提交的司机档案审核未通过,原因:${reason},请重新打开原链接修改后提交。`
4. ⚠️ **阿里云模板变量 name 是[个人姓名]类型,有姓名规范校验**:实测非规范姓名(如带后缀的测试名)被拒发 `isv.TEMPLATE_PARAMS_ILLEGAL`。蒙古族长名/带「·」的姓名是否在规范内待实测,有拒发风险——拒发时业务不受影响(驳回正常生效),仅短信缺失,`notification_send_log` 留痕 status=1。
## 1. 管理后台行为变更(无接口契约变化)
| 场景 | 旧行为 | 新行为 |
|---|---|---|
| 驳回 `POST /admin/fleet/drivers/pending/{id}/reject` | 仅日志,司机无感 | 落库后异步发短信(姓名+驳回原因,原因超 30 字短信内截断,完整原因仍在申请单详情) |
| 司机重提后 | 不可能发生(链接被 600302 拦死) | 申请单**回到待审列表**(reviewStatus=pending),驳回原因/审核人/审核时间清空,可再次审核 |
| 同一申请单 60 秒内重复驳回 | — | 第二次短信被幂等抑制(只发一条),驳回本身正常 |
## 2. 司机 H5 行为变更
| 场景 | 旧行为 | 新行为 |
|---|---|---|
| 驳回后打开原链接 | init 可看,但 ocr/提交返回 `600302` | 全流程放行,可修改后重新提交 |
| 重提成功 | — | 返回 200 + pendingId(同一条申请单覆盖更新) |
| 审核通过(approved)后打开原链接 | `600302` | 不变,仍 `600302`(唯一终态) |
### 重提请求示例(与首次提交完全一致,无新参数)
```bash
curl -k -X POST "https://web.test.1814.love:9443/app/h5/driver-onboard/submit/new" \
-H "Content-Type: application/json" \
-d '{"token":"{原链接token}","name":"张三","phone":"13812341234","gender":"1"}'
```
## 3. 后端内部变更(前端无需关注,备查)
1. `NotificationEventMessage` 新增 `phone` 字段(directPhone 收件通道,给非 C 端/非员工的裸手机号收件人发短信,当前仅 SMS 通道消费)。
2. 通知中心 SMS 通道支持裸手机号:`phone` 优先,无则按原 `userId` 反查,双空跳过。
3. 新增事件码 `DRIVER_REVIEW_REJECTED`(Flyway V20260612_001 种子,模板码 SMS_507190242 已回填)。
4. fleet 新增错误码 `605701`(通知中心降级,业务旁路不阻断驳回)。
5. 发录入链接短信(DRIVER_ONBOARD_LINK_SENT)**未上线**——当前代码无「发送链接」动作,待重发端点立项时一并落地。
@@ -0,0 +1,63 @@
# 【新增接口·管理后台】保险管理——保险产品全量列表(不分页),修复方案弹窗 pageSize=200 报错
> 服务:hl-order-service-v3(8086/8186) | 分支:dev-v3 | PR:#3717 | 已部署测试服并实测通过(2026-06-12)
> 背景:保险方案新增弹窗的产品下拉调 `GET /v3/admin/insurance/products?page=1&pageSize=200` 被全局分页上限拦截,页面红 toast「每页条数最大为100」
## ⚠️ 关键说明
1. **`pageSize` 全平台上限是 100**(PageParam 全局校验,所有分页接口一致),传 >100 一律返 `code=400`「每页条数最大为100」。**请勿用大 pageSize 模拟全量拉取**。
2. 需要全部数据的下拉/选择器场景,改用本次新增的**不分页全量接口** `GET /v3/admin/insurance/products/all`。
3. 原分页接口 `/products` 行为完全不变,列表页继续用它。
## 1. 新增端点
`GET /v3/admin/insurance/products/all`
### 入参(query)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| isOverseas | boolean | 否 | true=仅境外 / false=仅境内 / 不传=全部(方案弹窗「产品类型」单选可直接映射此参数) |
### 请求示例
```bash
# 全部产品
curl -k "https://web.test.1814.love:9443/v3/admin/insurance/products/all" \
-H "Authorization: Bearer {token}"
# 仅境内(方案弹窗选「境内」时)
curl -k "https://web.test.1814.love:9443/v3/admin/insurance/products/all?isOverseas=false" \
-H "Authorization: Bearer {token}"
```
### 响应示例(测试服实测,当前全量 10 条/境内 8 条)
```json
{
"code": 200,
"message": "成功",
"data": [
{
"insuranceProductId": "2054773831589232641",
"productId": "2054773831589232641",
"productName": "山河令(太保山东新)",
"productCode": "4810725b34654e1e88a7509e5b241c3a"
// ...其余字段与分页版 /products 的列表项完全一致(同一 InsuranceProductVO)
}
]
}
```
| 出参 | 说明 |
|---|---|
| data | **直接是数组**(无 total/page 包装),元素结构与分页版列表项一致,前端可无缝复用渲染逻辑 |
## 2. 回归确认(测试服实测)
| 调用 | 结果 |
|---|---|
| `/products/all` | 200,返回全量 10 条 |
| `/products/all?isOverseas=false` | 200,返回境内 8 条 |
| `/products?page=1&pageSize=200` | 400「每页条数最大为100」(维持不变,前端请改调 all) |
| `/products?page=1&pageSize=100` | 200,分页正常 |
@@ -0,0 +1,124 @@
# 【新增接口·管理后台】价格日历——§9.5 聚合总览 + §9.6 多车型批量设价(对齐原型,4→6 接口)
> 服务:hl-fleet-service(8087) | 分支:dev-v3 | PR:#3727 | 已部署测试服并 14 项 API 实测通过(2026-06-12)
> 契约出处:FLEET API v1.5.62 §9.5/§9.6(文档站已同步) | 前端触发位:车管控制台「价格日历」整页(page_pricing 原型)
> 背景:前端反馈现有价格日历接口拼不出原型页面(原型需要一次拿到全部车型×日期价格矩阵+节假日+统计,且批量改价是多车型多选)——本次补齐,**原有 4 接口零变更**。
## ⚠️ 关键说明
1. **整页数据一次拉取**:新增 `GET /admin/fleet/pricing-calendar/overview`,一次返回[大类→车型→区间价格矩阵+统计]+节假日列表+全局价格区间。「全部大类」月卡片、单大类月热力、季度/半年视图全部用它,**不再需要按车型逐个调 §9.1**。
2. **节假日数据源收口后端**:格子上的「假」标记请改用 overview 返回的 `holidays` 数组判断(原型里前端硬编码的 HOLIDAYS_2026 删掉),真相源=后端 Nacos 配置,每年由后端维护、前端零改动。
3. **`holidays` 只含请求区间内的节假日**:批量改价弹窗如果选择了超出当前已加载区间的日期(例如页面加载了 1-5 月、批改 10 月国庆),请按所选区间重拉一次 overview 取节假日。
4. **月卡片统计口径**:`stats` 按**请求区间**统计(均/低/高)。一次拉多个月时,单月统计请前端从 `prices[]` 按月自聚(原型本来就是前端算的,矩阵数据完备);`yearAvgPrice`(全年均)后端已算好直接用。
5. **多车型批量改价**:新增 `PUT /batch-set`,vehicleModelIds 1-50 个多选,**任一车型 ID 不存在整批拒绝**(600503,消息列出全部缺失 ID),三模式(ABS/DELTA/PERCENT)/仅周末/仅节假日等与单车型 §9.2 完全同源。整批一个事务,失败全回滚无半批。
6. 600503 消息升级为「车型型号不存在: {ID}」(带具体 ID,错误码不变,按 code 判断的前端无影响)。
7. 金额出参一律字符串(如 `"999.00"`),雪花 ID 字符串。
## 1. §9.5 价格日历聚合总览
`GET /admin/fleet/pricing-calendar/overview?startDate=2026-01-01&endDate=2026-05-31`
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| startDate | query | string | 是 | 开始日期 yyyy-MM-dd |
| endDate | query | string | 是 | 结束日期,须 ≥ startDate 且区间 ≤ 366 天(600501/600502) |
### 响应示例(测试服实测裁剪)
```json
{
"code": 200,
"message": "成功",
"data": {
"startDate": "2026-01-01",
"endDate": "2026-05-31",
"globalMinPrice": "950.00", // 区间内全部车型最低日价(色阶图例下界;无任何设价=null)
"globalMaxPrice": "4500.00", // 区间内全部车型最高日价(色阶图例上界)
"holidays": ["2026-01-01", "2026-02-16", "2026-02-17"], // 区间内节假日(格子「假」标记数据源,升序)
"types": [ // 车辆大类(sortOrder 升序,仅含有型号的大类)
{
"vehicleTypeId": "2057378611889180674",
"typeKey": "suv2",
"typeName": "SUV系列",
"icon": "",
"models": [
{
"vehicleModelId": "2057378612593823745",
"modelName": "丰田普拉多",
"basePrice": "1000.00", // 车型基准价(可 null)
"stats": {
"avgPrice": "1673.00", // 请求区间内已设价日均价(HALF_UP 两位;无设价=null)
"minPrice": "1500.00", // 区间最低
"maxPrice": "2250.00", // 区间最高
"yearAvgPrice": "1293.00" // startDate 所在自然年的全年均价(卡片「全年均」)
},
"prices": [ // 区间内已设价日(升序;未设价日不出现)
{ "date": "2026-01-01", "dayPrice": "2250.00", "status": "AVAILABLE", "remark": "" }
]
}
]
}
]
}
}
```
> 无设价的车型也会返回(prices=[]、stats 字段全 null),前端展示全部车型无需另调车型树。
### curl
```bash
curl -k "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/overview?startDate=2026-01-01&endDate=2026-05-31" \
-H "Authorization: Bearer {token}"
```
## 2. §9.6 多车型批量设价
`PUT /admin/fleet/pricing-calendar/batch-set`
### 入参(body) = §9.2 单车型全部字段 + vehicleModelIds
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| vehicleModelIds | string[] | 是 | 车型型号 ID 列表(1-50 个,雪花字符串);任一不存在整批拒绝 600503;重复自动去重;元素不能为 null |
| startDate / endDate | string | 是 | 同 §9.2(≤366 天) |
| adjustMode | string | 否 | ABS=固定价 / DELTA=现价加减 / PERCENT=百分比,默认 ABS |
| dayPrice | string | ABS 必填 | 同 §9.2 |
| adjustValue | string | DELTA/PERCENT 必填 | 同 §9.2(可负;PERCENT 如 10=+10%) |
| status / remark / weekdayOnly / weekendOnly / holidayOnly / selectedWeekdays / excludeDates | — | 否 | 全部与 §9.2 同源(三筛选互斥返 400) |
### 请求示例——原型「批量改价」弹窗:选 2 个车型春节区间上浮 15%
```bash
curl -k -X PUT "https://web.test.1814.love:9443/admin/fleet/pricing-calendar/batch-set" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"vehicleModelIds":["2057378612593823745","2064998010110029826"],
"startDate":"2026-02-16","endDate":"2026-02-22",
"adjustMode":"PERCENT","adjustValue":"15","holidayOnly":true}'
```
成功:`{ "code": 200, "message": "成功" }`
### 错误码
| code | 触发场景 |
|---|---|
| 400 | 参数校验(ID 列表空/>50/含 null、三筛选互斥、条件必填、白名单、两位小数) |
| 600501 / 600502 | 日期顺序 / 区间超 366 天 |
| 600503 | 任一车型不存在,消息列出全部缺失 ID,**整批不执行** |
### 防护(前端无感知,连点会收到提示)
- 同参数 3 秒幂等窗口(传参顺序/重复 ID 不影响判重)+ 批量请求间互斥锁
- 整批一个事务:任一失败全部回滚,不会出现"改了一半"
## 3. 测试服实测数据点
| 操作 | 结果 |
|---|---|
| overview 2099-02 区间(含 2 车型设价) | 200,types 树/stats/globalMin-Max/prices 全正确 |
| overview holidays(配置节假日区间) | `["2099-01-15"]` 与 Nacos 配置一致 |
| batch-set 2 车型 ABS 999 | 两车型全部写入,overview 立即可见 |
| batch-set 含不存在 ID | 600503 消息带缺失 ID,整批未执行 |
| 区间 >366 / start>end | 600502 / 600501 |
| 原 §9.1 单车型月视图 | 回归正常,零变更 |
@@ -0,0 +1,99 @@
# 【新增接口+前端回显修正·管理后台】司机编辑「关联车辆」改造——常驻车搜索下拉改绑 + 常开车型走车型库 + 回显修正
> 服务:hl-fleet-service(8087) | 分支:dev-v3 | PR:#3742 | 工单:#3739
> 已部署测试服并端到端实测通过(2026-06-12,过网关 9443 真 admin token,13/13 场景 PASS):绑定/改绑(自动解绑旧车)/解绑/605023 占用拒绝/幂等/600110/onlyResidentUnbound 筛选全部验证,测试数据已还原
## ⚠️ 关键说明(hl-ui 需改 4 处)
司机档案「编辑司机 → 关联车辆」这一块现状有三个问题:常驻车车牌是自由文本框、打开编辑不回显(卡片显示"常驻 蒙A-G8888"但编辑框空白)、常开车型大类 key 不回显。根因 + 改法如下:
1. **常驻车车牌「不回显」是前端读错字段**:司机详情接口**早已返回** `residentVehiclePlate`(权威常驻车,如 `蒙A-G8888`),前端「关联车辆」块当前绑的是另一个字段 `primaryVehiclePlate`(H5 司机自报参考车牌,非权威,多为空)。**请前端把常驻车的回显改读 `residentVehiclePlate`**。
2. **常驻车车牌改成「车辆搜索下拉 + 改绑」**(本次新增后端端点):选车下拉的数据源用 `GET /admin/fleet/vehicles/page?keyword=蒙A&onlyResidentUnbound=true`(只列**无常驻司机**的空闲车);选定后调**新端点** `PUT /admin/fleet/drivers/{driverId}/resident-vehicle` 绑定。**约束(产品拍定):只能绑当前无常驻司机的车;若目标车已有别的常驻司机,后端返 `605023`,提示去「车辆档案」换绑。**
3. **常开车型(大类 key + 车型名)改成「车型库下拉」**:车型字典接口**全部现成**,选型号自动带出 `preferredTypeKey`(大类 key)+ `preferredModel`(车型名),两字段随司机保存接口一起提交即可(后端早已接收)。巴特尔这类"只填了车型名没填大类 key"就是因为现在是手填文本框、历史没填,改下拉后从源头补齐。
4. **`primaryVehiclePlate` 字段保持不变**:它是 H5 司机自报参考车牌,H5/续签仍在用,admin 编辑表单这块**不要再用它绑常驻车**(改用第 2 点的新端点),但也不要删,后端契约不变。
## 1. 新增接口:改绑司机常驻车
`PUT /admin/fleet/drivers/{driverId}/resident-vehicle`
| 入参 | 类型 | 必填 | 说明 |
|---|---|---|---|
| driverId | path Long | 是 | 司机 ID |
| vehicleId | body Long | 否 | 目标车辆 ID(绑定/改绑);**不传或 null = 解绑本司机当前常驻车** |
**语义**
| 场景 | 行为 | 返回 |
|---|---|---|
| 绑定空闲车 | 该车常驻司机 = 本司机 | code 200 |
| 改绑到另一台空闲车 | **本司机原常驻车自动解绑** + 新车绑上 | code 200 |
| 目标车已是本司机常驻 | 幂等,不重复写 | code 200 |
| 目标车被**别的**司机占为常驻 | 拒绝,提示去车辆档案换绑 | **605023** |
| 解绑(vehicleId 不传/null) | 清掉本司机当前常驻车 | code 200 |
| 目标车不存在 | — | **600110** |
| 司机不存在 | — | **600205** |
> 个人自带车(ownerType=personal)绑定后,生命周期 service_status 会按该司机当前赛季自动联动(active→在役 / archived·blacklist→停用),前端无需处理。
**请求/响应示例**
```bash
# 绑定/改绑
curl -X PUT "https://api.test.1814.love:9443/admin/fleet/drivers/2065272148557021186/resident-vehicle" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"vehicleId":2064998140821319682}'
# → {"code":200,"message":"成功","data":null,"success":true}
# 目标车已被别人占(605023)
# → {"code":605023,"message":"目标车辆已有常驻司机(那顺),请到车辆档案换绑","success":false}
# 解绑
curl -X PUT ".../drivers/{driverId}/resident-vehicle" -H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" -d '{"vehicleId":null}'
# → {"code":200,...}
```
## 2. 修改接口:车辆分页新增筛选参数(下拉数据源用)
`GET /admin/fleet/vehicles/page` 新增可选 query 参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| onlyResidentUnbound | Boolean | `true` = 仅返回**无常驻司机**的车(常驻车下拉数据源,只显示可绑的空闲车);**不传 / false = 全部(行为不变)** |
```bash
# 常驻车下拉:按车牌搜 + 只列空闲车
curl "https://api.test.1814.love:9443/admin/fleet/vehicles/page?keyword=蒙A&onlyResidentUnbound=true&pageSize=20" \
-H "Authorization: Bearer {token}"
```
> 当前已绑的那台常驻车(回显值)由司机详情 `residentVehiclePlate` 单独给出,下拉里只需列空闲车供"换车"。
## 3. 常开车型下拉:用现成车型库接口(无新增)
| 用途 | 接口 | 返回 |
|---|---|---|
| 大类下拉 | `GET /admin/fleet/vehicle-types/list` | 全部大类(typeKey + typeName,不分页) |
| 大类+型号树 | `GET /admin/fleet/vehicle-types` | 大类含 models[](型号名/座位等) |
| 某大类下型号 | `GET /admin/fleet/vehicle-types/models/page?vehicleTypeId={id}` | 型号列表 |
- 「常开车型大类」下拉选项取 `vehicle-types/list` 的 `typeKey`(值)/`typeName`(显示),选定写入司机保存入参 `preferredTypeKey`。
- 「常开车型名」下拉取所选大类下的型号 `modelName`,写入 `preferredModel`。
- 两字段随司机新增/编辑接口(`POST /admin/fleet/drivers`、`PUT /admin/fleet/drivers/{driverId}`)正常提交,后端契约不变。
## 4. 端到端实测记录(测试服,2026-06-12)
```text
腾空 2 台车 → onlyResidentUnbound=true 返 2 台 PASS
绑定 A→蒙A-G8888 PASS
改绑 A→蒙A-H7777(蒙A-G8888 自动解绑) PASS
巴特尔绑已占的蒙A-H7777 → 605023(那顺占用) PASS
幂等:A 再绑蒙A-H7777 → 200 PASS
车不存在 → 600110 PASS
解绑 A → 200,resident 变 null PASS
还原:巴特尔→G8888 / D2→H7777 / 全 6 车绑回(空闲=0) PASS
合计 13/13 PASS,测试数据已还原
```
@@ -0,0 +1,36 @@
# 【行为变更·管理后台+司机H5】司机性别字典化——硬编码删除,渲染/导入/校验全部跟随数据字典 gender
> 服务:hl-fleet-service(8087) | 分支:dev-v3 | PR:#3741 | 工单:#3734
> 已部署测试服并端到端实测通过(2026-06-12):字典加「3=其他」后 ≤60 秒,H5/保存接口即接受 gender=3;删值即恢复拒绝
## ⚠️ 关键说明
1. **性别的取值从代码写死改为数据字典驱动**:后台「数据字典」里 `gender` 字典(当前 1=男/2=女/0=未知)增删改值后,车管模块的列表渲染、Excel 导入、保存校验在 **60 秒内自动跟随**,不再需要改代码发版。
2. **非法性别的报错形态变化(前端需留意)**:原来是参数校验 `code=400`「性别只能 0=未知/1=男/2=女」,现在是业务码 **`code=100001`**「参数非法: 性别编码非法,取值来自字典 gender「男」「女」「未知」,值=X」。**hl-ui 若按 code=400 分支处理表单校验提示,请改为同时兼容 100001**。
3. H5 提交 gender 传空串:原被 400 拒,现**视为未填放行**(与不传同效,后台落「未知」缺省)。
4. 字典里删掉一个已被司机使用的值后:详情/列表渲染兜底显示「未知」不报错;但**编辑该司机时性别必须改为字典内现有值才能保存**(否则 100001)。
## 1. 各场景行为对照
| 场景 | 旧 | 新 |
|---|---|---|
| 详情 genderLabel 渲染 | 代码写死 1男/2女/0未知 | 查字典实时渲染(测试服实测「男」),字典改标签 ≤60s 跟随 |
| Excel 导入「性别」列 | 仅认 男/女/未知 | 认字典内**任意 ACTIVE 标签**(运营加值即放开),非法值仍行级报错 |
| admin 保存 / H5 提交校验 | @Pattern 写死 ^[012]$ | 查字典校验,字典加值后新值自动合法 |
| 字典服务(user-service)不可用 | 不依赖 | 自动退回内置 1男/2女/0未知 兜底,**不报错不阻断**(与旧行为完全一致) |
## 2. 端到端实测记录(测试服)
```text
字典加 3=其他(POST /admin/dict/data) → code 200
等 65s(fleet 侧 60s 字典快照过期)
H5 提交 gender=3 → code 200(新值生效)
删字典值 → 恢复后 gender=3 再次被拒 100001
gender=9(字典外) → 100001「取值来自字典 gender「男」「女」「未知」,值=9」
```
## 3. 后端内部变更(备查)
1. 删除 `GenderDict` 硬编码类;新增 `GenderDictResolver`(60s TTL 快照,Feign 失败退旧快照/内置兜底永不抛)。
2. fleet 第三个出向 Feign:`GenderDictFeignClient` → user `GET /internal/dict/data?dictType=gender`(2s/3s 短超时)。
3. `DriverSaveReqVO`/`SubmitNewReqVO` 的 gender `@Pattern` 删除,校验下沉 Service 层。
@@ -0,0 +1,59 @@
# 【修改接口·管理后台】司机档案——全年保险绑定保险订单台账(自动落单+双向关联)
> 服务:hl-fleet-service(8087) + hl-order-service-v3(8086/8186) | 分支:dev-v3 | PR:#3748/#3754/#3758(空diff作废)/#3762 | 已部署测试服并 8 项端到端实测全过(2026-06-12)
> 契约出处:FLEET API v1.5.63 §3.2/§3.3/§3.4 + §13.7.7/§13.7.8 | wx 拍板:「司机的全年保险得和保险订单绑定」
> **前端编辑弹窗交互零改动**——年险五件套照旧手填,绑定由后端自动完成。
## ⚠️ 关键说明
1. **编辑/新增司机选「全年保险」保存后,后端自动在保险订单台账生成一张 MANUAL 来源的年保单**(保险管理→保险订单可见),保单号/保费/起止照搬档案录入值,状态=已投保(INSURED)。
2. **司机详情 insurance 块新增出参 `insuranceOrderId`**(字符串,关联的台账单 ID;非 annual 或联动未完成时为 null)——前端可用它跳转保险订单详情。联动是**提交后异步**完成(秒级),保存接口响应里不会立即有值,刷新详情即可。
3. **再次编辑年险信息(保费/起止/保单号)→ 同一张台账单原地更新**,不会重复开单。
4. **保险类型从「全年保险」切走(或删除司机)→ 台账单自动作废(CANCELLED)+ 解除关联**。
5. **MANUAL 年保单不能在保险订单页退保**:点退保返 `code=540224`「手工录入的司机年保单请在司机档案中维护」——它没有保游网外部单,生命周期跟司机档案走。
6. **保险订单列表/详情新增出参**:`source`(BAOYOU=保游网出单 / MANUAL=手工录入年保)、`bizType`(ORDER=订单险 / DRIVER=司机险)、`bizId`(字符串;DRIVER 行=司机ID)——列表页可按来源/归属区分展示(建议 MANUAL 行隐藏「退保」按钮)。
7. **口径**:年险司机在保障期内再走「司机险投保」(保游网按天)会被 `540032` 保障期重叠拦截——年险已覆盖全年,按天投保=重复投保;确需投保请先把档案保险类型切走(台账单自动作废)再投。
## 1. 司机编辑/新增(§3.3/§3.4) — 入参零变化
入参与原来完全一致(type=annual + policyNo/annualPremium/annualStart/annualEnd 条件必填),无新增字段。
## 2. 司机详情(§3.2) — insurance 块新增 1 出参
```json
{
"insurance": {
"type": "annual",
"policyNo": "PICC2026X04",
"annualPremium": "3400.00",
"annualStart": "2026-01-01",
"annualEnd": "2026-12-31",
"insurancePlanId": null,
"insuranceOrderId": "2068331660551747586" // 🆕 关联台账单ID(字符串;非annual/未联动=null)
}
}
```
## 3. 保险订单列表与详情 — 新增 3 出参(测试服实测)
```json
{
"insuranceOrderId": "2068331660551747586",
"extPolicyNo": "PICC2026X04",
"totalPremium": 3400.0,
"status": "INSURED",
"source": "MANUAL", // 🆕 BAOYOU=保游网出单 MANUAL=手工录入(司机年保档案联动)
"bizType": "DRIVER", // 🆕 ORDER=订单险 DRIVER=司机险
"bizId": "2065272153565020161" // 🆕 归属业务ID(DRIVER=司机ID,字符串)
}
```
## 4. 端到端实测数据点(可作联调预期)
| 操作 | 结果 |
|---|---|
| 编辑司机设 annual 保存 | 200;~2 秒后详情 insuranceOrderId 有值;台账出现 MANUAL/DRIVER/INSURED 单 |
| 再编辑改保费 3400→3800 | 同一张台账单 totalPremium 更新,单号不变 |
| 保险订单页对 MANUAL 单点退保 | code=540224 |
| 类型切回「无保险」 | 详情 insuranceOrderId=null;台账单变 CANCELLED |
| 删除 annual 司机 | 同上自动作废+解绑 |
@@ -0,0 +1,63 @@
# 【新增·管理后台】保险订单页投保下单支持「人员类型=司机」+ 出单自动绑定司机全年保险
> **变更类型**:新增入参 + 新增出参 + 前端交互改造(含 2 个搜索下拉)
> **影响端**:管理后台(保险订单页 + 司机档案页)
> **关联**:工单 #3760 / PR #3770(已合并 dev-v3,测试服已部署实测通过)
> **服务**:hl-fleet-service + hl-order-service-v3
> **文档**:API-SPEC-FLEET v1.5.68(§3.8 / §13.7.9)/ SRS §9.17.5
## ⚠️ 关键说明
1. **保险订单页「投保下单」弹窗需加「人员类型」单选:客人(默认)/ 司机**。客人路径现行为零变化(关联订单 orderId 仍必填);司机路径是新交互(见下)。
2. **司机路径不调 v3 投保接口**,改调 fleet 的司机投保端点(`POST /admin/fleet/drivers/{driverId}/insurance/purchase`)并传 **`bindAnnual: true`**——出单成功后该保单自动绑定为司机档案的「全年保险」(一个保单只对应一个司机)。
3. **被保人不可编辑**:司机路径下被保人=该司机本人一条,后端按司机档案自动组装,前端隐藏被保人编辑区(不要传 insuredPersons)。
4. **两个搜索下拉(顺便解决项,wx 指示)**:
- 弹窗「选择司机」:搜索下拉,数据源 `GET /admin/fleet/drivers/page?keyword=`(姓名模糊 + 11 位手机全号精确)
- 客人路径「关联订单」:输入框改搜索下拉,数据源 `GET /v3/admin/order/list`(keyword 模糊)
5. **保险计划下拉(司机路径)**:用 `GET /admin/fleet/drivers/insurance/plan-options`(只列运营已打标 DRIVER/BOTH 的计划)。**当前测试服该列表为空**——需运营先在保险产品侧打标(`PUT /v3/admin/insurance/plans/{planId}/usage-category`,出参 PlanItem 已有 usageCategory 字段可做打标 UI,见 11_3700 changelog 第 5 点,打标 UI 目前尚未建,前端可一并补)。
## 1. fleet 司机投保接口加 `bindAnnual` 入参
`POST /admin/fleet/drivers/{driverId}/insurance/purchase`
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| planId | string(雪花) | 是 | 保险计划id(从 plan-options 下拉取) |
| coverageStartDate / coverageEndDate | string(date) | 是 | 保障起止(司机路径建议按年预填) |
| **bindAnnual** | boolean | 否 | **🆕 true=出单成功后自动绑定为司机全年保险**;缺省 false(司机档案页投保入口现行为零变化) |
| remark | string | 否 | 备注 |
请求示例(保险订单页司机路径):
```bash
curl -X POST "https://api.test.1814.love:9443/admin/fleet/drivers/{driverId}/insurance/purchase" \
-H "Authorization: Bearer {token}" -H "Content-Type: application/json" \
-d '{"planId":"2054773833342451714","coverageStartDate":"2026-07-01","coverageEndDate":"2027-06-30","bindAnnual":true}'
```
绑定效果(bindAnnual=true 出单受理成功后,后端自动完成,前端无需额外调用):司机档案 `insurance.type` 变 `annual`、保费/起止回填、`insuranceOrderId` 指向新保单、`annualSource` 变 `baoyou`;保单号(extPolicyNo)异步出单时为空,**承保回调后自动补填**。
## 2. 司机档案 insurance 块新增出参 `annualSource`
`GET /admin/fleet/drivers/{driverId}` 等 insurance 块:
| 字段 | 类型 | 说明 |
|---|---|---|
| **annualSource** | string | 🆕 年保来源:`manual`=车管手填自有年保单(默认)/ `baoyou`=保游网出单自动绑定;仅 type=annual 有意义;只读·入参忽略 |
**前端按 `annualSource=baoyou` 把档案编辑弹窗的年保四件套(保单号/年保费/起止)置为只读**——绑定态下这 4 个字段入参会被后端忽略(保持绑定值);保单号出单中可能为空串属合法态。若要把 baoyou 年险改成手填:先把类型切走(自动解绑)再切回 annual 手填。
## 3. 行为与错误码
| 场景 | 结果 |
|---|---|
| 选了未标司机可用的计划(CUSTOMER) | `540031` 该保险计划未标注为司机可用(测试服已实测) |
| 该司机保障期与已有年险/在途保单重叠 | `540032` 拒绝,提示先在司机档案处理 |
| 出单成功但本地绑定失败 | 🆕 `600206` 「保险出单成功但年险绑定失败,请勿重复投保…」——**前端务必原样展示该消息**(保单已生效,重复投保会被拦) |
| 出单失败(FAILED)/ 保单被退保(CANCELLED) | 后端自动解绑:档案保险回退 `none`(原 perTrip 计划不会恢复,需人工重选),前端无需处理 |
| 重复点击投保 | v3 幂等拦截(短窗内重复请求被拒),按错误提示处理即可 |
| 编辑档案时类型从 annual(baoyou) 切走 | 仅解绑(档案与保单脱钩),**不自动退保**——退保仍走保单列表/档案保单页手动操作 |
## 4. 保险订单列表呈现
司机年险出单后会以 `bizType=DRIVER`、`source=BAOYOU` 出现在保险订单列表(列表 source/bizType/bizId 出参见 11_3748 / 12_3765 changelog),与游客订单险共存。
@@ -0,0 +1,47 @@
# 【修改接口·管理后台】司机保单列表补 source 出参——MANUAL 年保单「下载/重传保单」按钮收敛
> 服务:hl-order-service-v3(8086/8186) + hl-fleet-service(8087) | 分支:dev-v3 | PR:#3765 | 已部署测试服并 4 项实测通过(2026-06-12)
> 背景:前端反馈——详情抽屉「下载保单/重传保单」按钮对 MANUAL 年保单仍显示,点击提示「保单生成中」不报错但语义偏。本次按约定把 source 带到按天保单列表 VO。
## ⚠️ 关键说明(前端动作)
1. **司机保单列表(`GET /admin/fleet/drivers/{driverId}/insurance/policies`)每行新增出参 `source`**:`BAOYOU`=保游网出单 / `MANUAL`=手工录入(司机年保档案联动)。
2. **前端请按 `source === 'MANUAL'` 隐藏「下载保单」「重传保单」按钮**——MANUAL 单无保游网电子保单,真相载体是司机档案附件里的纸质保单影印件。
3. **MANUAL 单保留在保单列表中**(确认结论:不该从列表消失——它是司机的真实保险记录,隐藏整行反而像没保险),仅 PDF 相关操作不可用。
4. **后端已加双保险**:即使按钮没藏住/直调接口,下载与重传对 MANUAL 单现在返回明确错误码 **540226**「手工录入的年保单无电子保单,请查看司机档案附件中的纸质保单影印件」(替代原「保单生成中请稍后」误导提示),前端可直接 toast `message`。
5. 「分享保单」按订单维度查,MANUAL 单天然不出现,无需处理。
## 1. 保单列表出参变更(实测示例)
`GET /admin/fleet/drivers/{driverId}/insurance/policies`
```json
{
"code": 200,
"data": [
{
"insuranceOrderId": "2068345678901234567",
"policyNo": "PICC2026X04",
"extPolicyNo": "PICC2026X04",
"extOrderNo": null,
"totalPremium": "3400.00",
"status": "INSURED",
"statusLabel": "已承保",
"source": "MANUAL", // 🆕 BAOYOU=保游网出单 MANUAL=手工录入年保;MANUAL 须隐藏下载/重传按钮
"coverageStartDate": "2026-01-01",
"coverageEndDate": "2026-12-31",
"insuredPersons": [ { "name": "巴特尔", "idCardNo": "152***********0002" } ]
}
]
}
```
## 2. PDF 入口错误码(后端兜底,实测)
| 调用 | 结果 |
|---|---|
| `GET /v3/admin/insurance/policy/{id}/download`(MANUAL 单) | `code=540226` 手工录入的年保单无电子保单… |
| `POST /v3/admin/insurance/policy/{id}/retry-upload`(MANUAL 单) | `code=540226` 同上 |
| BAOYOU 单两接口 | 行为不变 |
另:管理端「批量上传缺失保单PDF」已自动排除 MANUAL 单(后端内部优化,前端无感)。
@@ -0,0 +1,93 @@
# 【新增接口·管理后台+司机H5】司机自助 H5「已发放链接管理」5 端点——列表/导出/作废/重发短信/重新生成
> 服务:hl-fleet-service(8087/8187) + hl-user-service(8081/8181) | 分支:dev-v3 | PR:#3777+#3778(补丁) | 工单:#3775 | 已部署测试服并 13 项 E2E 实测通过(2026-06-12)
> 背景:API §4.6 此前未实现——车管发出去的 H5 录入链接看不到、不能作废、不能重发。本次补齐完整生命周期管理,同时把链接 URL 收口 Nacos、H5 init 补状态机出参。
> 对应原型:车管控制台「链接管理」页。
## ⚠️ 关键说明(前端动作)
1. **管理后台新增「已发放链接管理」页面**(5 个新端点,见 §1-§5),路径前缀 `/admin/fleet/h5/tokens`。
2. **链接格式变了**:所有生成的 H5 链接统一为 `https://hr.1814.love/driver-intake?t={token}`(参数名 **`?t=`**,与短信模板一致;原硬编码 `h5.hl-fleet.com/onboard?token=` 作废)。**H5 前端从页面 URL 读 `t` 参数**后调 init。
3. **H5 init(`GET /app/h5/driver-onboard/init`)出参新增 4 字段**(司机 H5 需按 `tokenState` 渲染失效文案,见 §6)。
4. **§4.1 生成链接出参新增 `pendingId`**(后续作废/重发/重新生成都以 pendingId 为操作键)。
5. **测试服公网已可直达 H5 接口**:nginx 已补 `/app/` 代理(此前 `/app/h5/*` 经 9443 会落到 SPA 页面)。
6. **已知外部阻塞(不影响接口联调)**:重发短信链路已全通(事件→通知中心→阿里云真实调用,send_log 落档),但阿里云模板 SMS_507390235 的 token 变量类型(链接参数)容不下 32 位 token 被拒发——**需 wx 在阿里云控制台调整模板变量规范后过审**,代码侧零改动。name 为空拒发已后端兜底(空→「师傅」)。
7. 60 秒内对同一链接重复点「重发」:接口返回成功但通知中心幂等拒发第二条(防轰炸),属预期。
## 1. 已发放链接列表(分页)
`GET /admin/fleet/h5/tokens?mode=&status=&keyword=&page=1&pageSize=20`
| 入参 | 必填 | 说明 |
|---|---|---|
| mode | 否 | new=新招 / renew=续签 |
| status | 否 | 派生 6 态:`VOIDED`已作废/`APPROVED`已通过/`REJECTED`已驳回/`SUBMITTED`已提交/`EXPIRED`已过期/`VALID_UNSUBMITTED`有效·未提交 |
| keyword | 否 | 模糊匹配 姓名 OR token(**不支持手机号**——加密存储无法模糊) |
实测出参(行):
```json
{
"pendingId": "2065414570750455809", // 操作键(字符串防精度丢失)
"mode": "new", "modeLabel": "新招",
"token": "182ee9dd884e46d8a628bb98a5695252",
"name": "", "phone": null, // 手机脱敏返回(138****2345),未填为 null
"createTime": "2026-06-12T20:45:29", "expireAt": "2026-06-19T20:45:29",
"submittedAt": null, "reviewStatus": "pending",
"status": "VALID_UNSUBMITTED", "statusLabel": "有效·未提交",
"url": "https://hr.1814.love/driver-intake?t=182ee9dd884e46d8a628bb98a5695252" // 直接复制发司机
}
```
## 2. 导出 CSV
`GET /admin/fleet/h5/tokens/export?mode=&status=&keyword=`(同条件,不分页)
返回 `text/csv;charset=UTF-8` 文件流(带 UTF-8 BOM,Excel 直开不乱码),列:`类型,token,姓名,手机(脱敏),生成时间,有效期至,状态,审核状态`,文件名 `h5_tokens_{时间戳}.csv`。前端 blob 下载即可。
## 3. 作废链接
`POST /admin/fleet/h5/tokens/{pendingId}/void` body(可选):`{ "reason": "司机信息有误" }`
- 仅「已通过」不可作废(**600304**);其余状态(含已驳回/已提交)均可作废;重复作废幂等返回成功
- 作废后司机端立即失效:H5 init 返 `tokenState=voided`、提交/OCR 被 600304 硬拦(实测联动通过)
## 4. 重发短信
`POST /admin/fleet/h5/tokens/{pendingId}/resend` body(可选):`{ "phone": "13808612345" }`(覆盖收件号,生成时没填手机的链接由此补)
- 仅「有效·未提交」「已驳回」可重发,否则 **600308**;入参与档案手机号均空 → **600307**
- **不刷新有效期**(要延长走重新生成)
- 出参仅 `{ "maskedPhone": "138****2345" }`——短信异步发出,**接口成功≠短信已到**,到达结果看通知中心发送日志
## 5. 重新生成
`POST /admin/fleet/h5/tokens/{pendingId}/regenerate`(无 body)
- 「已提交」「已通过」不可重新生成(**600309**);其余(含已过期/已作废)可
- 旧链接自动作废(审计留痕),返回**全新** pendingId/token/url/expireAt/qrCodeUrl(出参同 §4.1 生成)
- **新链接不自动发短信**——车管复制 url 或对新 pendingId 点重发
## 6. 司机 H5 init 出参新增 4 字段(H5 前端)
`GET /app/h5/driver-onboard/init?token=`
| 字段 | 说明 |
|---|---|
| tokenState | `fresh`首次可填/`editable`已提交待审可覆盖重提/`rejected_editable`已驳回可改重提/`expired`已过期/`voided`已作废/`consumed`已通过(终态)/`invalid`无效 |
| reviewStatus | pending / approved / rejected |
| rejectReason | 驳回原因(驳回相关态才有值,指导司机改哪) |
| lastSubmittedAt | 上次提交时间(已提交过才有值) |
- `tokenValid` 保留向后兼容(= tokenState ∈ fresh/editable/rejected_editable);**修了一个旧 bug**:审核通过后司机再打开,旧实现误返 tokenValid=true(填完 8 步提交才被拦),现在 init 即返 false + `consumed`
- H5 请按 tokenState 渲染失效文案(已作废/已过期/已通过 区分展示)
## 7. 错误码速览
| code | message |
|---|---|
| 600304 | 链接已作废(作废后的 H5 提交/OCR 也返此码) |
| 600307 | 无可用手机号 |
| 600308 | 仅有效未提交或已驳回的链接可重发 |
| 600309 | 已提交或已通过的链接不可重新生成 |
| 600402 | 待审核记录不存在 |
@@ -0,0 +1,29 @@
# 【修改接口·管理后台】H5 录入链接短链化——生成/列表出参新增 shortUrl + 公开短链跳转端点
> 服务:hl-fleet-service(8087/8187) + hl-user-service(8081/8181) | 分支:dev-v3 | PR:#3780 | 工单:#3779 | 已部署测试服并 5 项 E2E 实测通过(2026-06-12)
> 背景:阿里云短信模板的「链接参数」变量容不下 32 位 token 致重发短信拒发,wx 拍板短链解决;测试/正式域名按环境配置(Nacos 双键)。
## ⚠️ 关键说明(前端动作)
1. **§4.1 生成 / §4.6.5 重新生成 / §4.6.1 列表行 出参新增 `shortUrl`**(如 `https://web.test.1814.love:9443/s/umB0153d`,8 位短码):管理端「复制链接」建议优先复制 shortUrl(短信同款入口);**老数据行 shortUrl 可能为 null**(历史链接未补码,重发时后端自动懒补),为 null 时降级用 `url` 全链。
2. **H5 端零改动**:短链 302 跳回 `{H5页}?t={token}` 长链,H5 仍从 URL 读 `t` 调 init;无效短码跳 `?t=invalid`(init 渲染「链接无效」)。
3. **CSV 导出列不变**。
4. 重发短信的链路状态:fleet 已发 8 位 code 参数(send_log 实证),**待 wx 在阿里云控制台改模板 SMS_507390235**(固定 URL 换 /s/ 形式+变量 ${token}→${code})过审后短信即可真实出件;过渡期重发接口正常返回、短信渲染失败仅后台留痕。
## 1. 出参变更示例(实测)
`POST /admin/fleet/h5/token`
```json
{
"pendingId": "2065430143865667585",
"token": "32位长token...",
"url": "https://hr.1814.love/driver-intake?t={token}", // 全链(二维码/H5 直开用)
"shortUrl": "https://web.test.1814.love:9443/s/umB0153d", // 🆕 短链(短信同款,优先复制这个)
"expireAt": "2026-06-19T21:45:00", "qrCodeUrl": "data:image/png;base64,..."
}
```
## 2. 新公开端点(无鉴权,前端无需对接,知悉即可)
`GET /s/{code}`(nginx)→`/app/h5/s/{code}`(网关):302 跳 onboard 长链;限流 30 次/60s 防枚举。
@@ -0,0 +1,27 @@
# 【行为变更·管理后台+司机H5】司机驾驶证号必填(四入口收口)+ 驾驶证等级请补渲染(字段一直在返)
> 服务:hl-fleet-service(8087/8187) | 分支:dev-v3 | PR:#3783 | 工单:#3781 | 已部署测试服并 8 项 E2E 实测通过(2026-06-12)
> 背景:wx——「司机的驾驶证号必填 现有的司机数据都需要补 还有驾驶证等级也没显示」。
## ⚠️ 关键说明(前端动作)
1. **新增司机表单:驾驶证号/准驾车型/驾照有效期 三项改必填**(加 `*` 必填标记,对齐原型;发证机关仍选填)。缺任一项后端返 **400**(message 指明哪项)。
2. **编辑司机:新错误码 600207**「驾驶证号不能为空,请在编辑时补录」——只对**库内证号为空的存量档案**触发(编辑时必须补录明文证号才能保存,这就是存量补数机制);证号已有值的司机,编辑回传详情拿到的脱敏值(含 `*`)或干脆不传 license 块都照常放行(=未修改)。前端 toast message 即可,无需特判。
3. **驾驶证等级「没显示」是前端渲染缺口,后端字段一直在返,请补渲染**:
- 列表行:`licenseType`(如 "A2",测试服 20/20 司机有值)
- 详情:`license.type`;编辑表单等级下拉数据源=**字典 driving_license_class**(16 国标类:A1/A2/A3/B1/B2/C1/C2/C3/C4/C5/C6/D/E/F/M/N,sys_dict 已种,labels 如「A1(大型客车)」)
4. **批量导入**:新建行(身份证号未命中)驾照号/准驾车型/驾照有效期三列必填,缺→该行报错不阻断他行;**续签行留空=保持原值**(但库内证号也为空时该行报错);模板「填写说明」已同步。
5. **司机自助 H5 新招提交**:`licenseNo` 必填(缺失 400)——OCR 识别本就回填证号,正常流程无感;H5 表单驾驶证号输入框请加必填标记。
## 实测(测试服,8 项)
| 场景 | 结果 |
|---|---|
| 创建缺 license 块 / 缺证号 | 400 |
| 三件套齐全创建 | 200 |
| 存量缺号档案编辑不补号 / 回传脱敏串 | **600207** |
| 补明文证号编辑 | 200 |
| 证号有值后不传 license 块编辑 | 200(放行) |
| H5 submit/new 缺 licenseNo | 400 |
注:测试服现有 20 个司机证号/等级数据完整,600207 在真实缺号数据出现前不会触发。
@@ -0,0 +1,56 @@
# 【前端 Bug·管理后台】车辆批量导入:后端成功但前端误报「导入失败」(responseType=blob 读 responseText 抛错)
> 页面:车务管理 → 车辆档案 → 车辆列表 → 批量导入 | 接口:`POST /admin/fleet/vehicles/import` | 负责:mmg
> 严重度:P1(功能可用但误导用户重复导入,撞车牌唯一约束/重复绑常驻)
## 现象
用户用最新模板(12 列,含常驻司机手机号)批量导入 5 台车,前端弹「导入失败」,但**实际后端已全部成功**:
- DevTools Network 里 `import` 请求 Response:`code:200, insertedCount:5, errorCount:0, success:true`
- 车辆列表 `共 16 辆` → `共 21 辆`(+5),5 台车 + 常驻司机绑定全部落库正确
- Console 报错:`InvalidStateError: Failed to read the 'responseText' property from 'XMLHttpRequest'. The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob').`
## 根因(纯前端)
导入按钮的 XHR/axios 请求把 `responseType` 设成了 `'blob'`——几乎可以确定是从**同页「下载模板」按钮**的代码复制来的(下载模板返回 .xlsx 文件流,确实需要 `responseType:'blob'`)。但**导入接口返回的是 JSON**(`Content-Type: application/json`,`Result<VehicleImportRespVO>` 包络),前端拿到响应后去读 `responseText` 解析 JSON,而浏览器规定 `responseType` 为 `'blob'` 时禁止访问 `responseText` → 抛 `InvalidStateError` → 被 catch 当成请求失败 → 弹「导入失败」。
→ HTTP 其实是 200、业务也成功,**纯前端响应解析配置错误**,与后端无关。
## 后端契约(未变,供前端对照)
| 端点 | 方法 | 响应类型 | responseType 应设 |
|---|---|---|---|
| `/admin/fleet/vehicles/import` | POST(multipart 上传文件) | **JSON**(`Result<VehicleImportRespVO>`) | `''` 或 `'json'`(**不要 blob**) |
| `/admin/fleet/vehicles/import/template` | GET(下载模板) | **二进制 .xlsx 文件流**(`Content-Disposition` 附件) | `'blob'`(保持) |
导入成功响应示例(前端应据此渲染导入结果弹窗):
```json
{
"code": 200,
"message": "成功",
"data": {
"totalRows": 5,
"insertedCount": 5,
"updatedCount": 0,
"errorCount": 0,
"errors": [],
"warnedCount": 0,
"warnings": []
},
"success": true
}
```
部分失败时 `errors[]` 含 `{row, plate, msg}`、`warnings[]` 含 `{row, plate, field, msg}`,建议前端按这两个数组渲染「成功 N 条 / 失败 M 条(逐行原因)/ 警告 K 条」明细,而不是只弹一句成功或失败。
## 修复建议(前端)
1. **导入请求单独配置**:导入用默认 `responseType`(`''`/`'json'`),不要复用下载模板的 `blob` 配置——两个按钮的 axios 调用分开写。
2. **成功判定改看业务结果**:以 `data.errorCount`/`data.errors` 渲染明细,别只凭「请求是否抛异常」判断成败。
3. 回归:导入成功(全成)、部分失败(含 errors)、全失败 三种响应都要能正确解析渲染。
## 临时说明(给已踩坑的同学)
看到「导入失败」请先刷新车辆列表确认是否其实已导入——若已在列表里,说明是本 Bug,**不要重复导入**(重复上传同车牌会走 UPDATE 不会重复建,但若手动改了车牌重传会造成重复车 + 常驻司机 1:1 冲突报错)。
@@ -0,0 +1,46 @@
# 【前端缺口·管理后台】车辆档案列表缺「关键词搜索框」——后端 keyword 早已支持,前端补输入框即可
> 页面:车务管理 → 车辆档案 → 车辆列表 | 接口:`GET /admin/fleet/vehicles/page`(已上线,无需改动) | 负责:mmg
> 类型:前端补 UI(纯前端,后端零改动)
## 现象 / 诉求(wx)
车辆列表筛选区现在只有 4 个下拉框(所属车队 / 车型大类 / 所有权性质 / 生命周期),**没有文本搜索框**,车多了没法按车牌快速定位。诉求:至少能按车牌搜索。
## 结论:后端早就支持,是前端没放输入框
`GET /admin/fleet/vehicles/page` 的 **`keyword`** 入参已上线(API §2.1,v1.5.51 落地):**车牌 OR 车型名称 模糊匹配**(一个框同时搜车牌和车型)。前端只需在筛选区加一个搜索输入框,绑定到 `keyword` 查询参数即可,**后端不用任何改动**。
测试服实测(admin token 经网关):
| keyword | 命中 | 说明 |
|---|---|---|
| `蒙AD2001` | 1 条(蒙AD2001) | 车牌精确 |
| `蒙AD1` | 5 条(蒙AD1001~1005) | 车牌前缀 |
| `别克` | 5 条(含蒙AD2002/蒙C09E09 等别克GL8) | 车型名模糊 |
## 前端改法
筛选区加一个文本输入框(建议放在「所属车队」下拉前,或筛选区最左),placeholder 例如「车牌 / 车型」,绑定 `keyword`:
```
GET /admin/fleet/vehicles/page?pageNo=1&pageSize=24&keyword=蒙AD2001
```
- `keyword` 可选,传空 / 不传 = 不参与过滤(与现有 4 个下拉同口径,一起拼进 query)
- 与现有「搜索 / 重置」按钮联动:点搜索带上 keyword,点重置清空
- 后端已做 trim + 空白忽略,前端不必额外处理
## 入参全集(§2.1,供前端对照)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| keyword | string | 否 | **车牌 / 车型 模糊搜索(本次要加的输入框)** |
| fleet | string | 否 | 车队 own/coopA/coopB(已有下拉) |
| ownerType | string | 否 | 所有权 company/personal(已有下拉) |
| typeKey | string | 否 | 车型大类 key(已有下拉) |
| serviceStatus | string | 否 | 生命周期 ACTIVE/DISABLED(已有下拉) |
| vehicleStatus | string | 否 | 车辆状态 idle/busy/maint(对应「空闲/在用/维保中」tab) |
| pageNo / pageSize | int | 否 | 分页 |
> 注:司机档案列表(`/admin/fleet/drivers/page`)的 `keyword` 口径不同——姓名模糊 + 手机 11 位全号精确(AES 密文等值,不支持手机模糊),若司机列表也要加搜索框照此说明。
@@ -0,0 +1,53 @@
# 【后端核实回执·管理后台】保单按钮两处收敛 + 车辆导入弹窗映射——前端 SYNC-20260612-10 全部确认,无接口变更
> 服务:hl-order-service-v3(8086/8186) + hl-fleet-service(8087) | 对应前端:SYNC-20260612-10(commit f642b064) | 后端无代码改动,本文是核实回执(2026-06-12)
> 背景:前端回报「下载/重传保单」真实落点在保险订单台账页(非司机抽屉),已两处按 source 收敛;并修车辆导入结果弹窗字段映射;质疑 blob 归因。后端逐项核实如下。
## ⚠️ 关键说明
1. **前端两处收敛方案后端全部确认正确,双方版本在测试服已对齐**,前端无需再动。
2. 此前 changelog 12_3765 写按钮在「详情抽屉」系沿用最初反馈原话,实际落点在台账页——契约指引(按 `source` 收敛)两处通用,结论不变。
3. blob/InvalidStateError 议题双方归零关闭(见 §3)。
## 1. 保单按钮收敛——后端契约逐项核实(均实测)
| 前端收敛点 | 后端支撑 | 实测结论 |
|---|---|---|
| 台账页 MANUAL 行隐藏「下载/重传保单」 | `GET /v3/admin/insurance/list` 列表行 VO 自带 `source`(BAOYOU/MANUAL) | 测试服实测每行 source 非 null;直调下载/重传返 **540226** 兜底 |
| 台账页 MANUAL 行隐藏「退保」(上批已收敛) | 管理端退保接口拦 MANUAL | 返 **540224**「手工录入的年保单不支持退保」 |
| 司机抽屉 MANUAL 行隐藏「退保」+ 加「手工录入」标识 | `GET /admin/fleet/drivers/{driverId}/insurance/policies` 每行 `source` 字段即为此用 | 与 540224 守卫严丝合缝 |
台账列表实测示例(`GET /v3/admin/insurance/list?page=1&pageSize=10`):
```json
{
"insuranceOrderId": "2065360048397193217",
"source": "MANUAL", // 每行均返,非 null
"bizType": "DRIVER",
"status": "CANCELLED" // 该批 CANCELLED 是后端 E2E 清场数据,属正常
}
```
注意:**判断按钮显隐请只认 `source`,勿用 `bizType` 当代理**——司机行程险走保游网出单时 `bizType=DRIVER` 但 `source=BAOYOU`,有电子保单,下载/重传按钮应保留。
## 2. 车辆导入结果弹窗映射——前端重写目标字段与后端 VO 完全一致
后端 `VehicleImportRespVO` 真实字段(核实于当前 dev-v3):
| 字段 | 类型 | 含义 |
|---|---|---|
| `totalRows` | int | 数据总行数 |
| `insertedCount` | int | 新增成功数 |
| `updatedCount` | int | 更新成功数 |
| `errorCount` | int | 失败行数 |
| `errors` | array | 失败明细(行号+原因) |
| `warnedCount` | int | 警告行数 |
| `warnings` | array | 警告明细 |
前端旧映射(failed/errorRows/success/total)确实全部不存在于后端 VO,「导入成功 0 条」怪象由此而来,重写后正确。司机导入 `DriverImportRespVO` 字段结构同族,如需对照可看测试服 doc.html。
## 3. blob/InvalidStateError 议题关闭
- 前端全仓核查无 `responseType:'blob'` 配置;后端侧该归因同样无代码对应物——此前那条「前端Bug_车辆批量导入responseType-blob」changelog 的归因有误,以本回执为准。
- 真实病因即 §2 的弹窗字段映射 bug,已修。
- 若真机后续仍复现该 console 报错,排查方向是测试服部署的前端构建来源(是否旧构建残留),与双方当前代码无关。
@@ -0,0 +1,25 @@
# 【环境变更·全员】测试服 API 文档站(doc.html)登录改 Gitea 账号 SSO——登录一次 30 天免登录
> 站点:https://api.test.1814.love:9443/doc.html | 生效:2026-06-12 | 无 PR(测试服 nginx + oauth2-proxy 配置变更,不涉及业务代码)
> 已端到端实测:Gitea 登录→授权→文档加载→二次访问纯 Cookie 免登录
## ⚠️ 关键说明
1. **文档站专用账号(hulalv)停用**:访问 doc.html 不再弹浏览器账号密码框,改为跳转 Gitea 登录页,**用你自己的 Gitea(git.1814.love)账号登录**。
2. **浏览器已登录 Gitea 的话全程无感**:直接跳回文档页,一个键都不用按。
3. **首次使用会出现一次「授权 knife4j-api-docs-sso 访问您的帐户?」确认页**:点「应用授权」即可,每个账号只出现这一次。
4. **登录一次 30 天免登录**(Cookie 有效期 720h,期间自动静默续期),浏览器重启也不用重新登录。
5. **API 调用本身零影响**:/admin/、/mp/、/v3/ 等接口的认证方式不变,仅 doc.html、/webjars/、/v2/api-docs、/swagger-resources 四个文档路径换了认证。
## 1. 行为对照
| 场景 | 旧 | 新 |
|---|---|---|
| 打开 doc.html | 浏览器弹 Basic Auth 框,输文档专用账号 | 跳 Gitea 登录页(已登录 Gitea 则无感直进) |
| 浏览器重启后 | 重新弹框输密码 | Cookie 30 天内免登录 |
| 账号管理 | 共享一个 hulalv 账号 | 各自 Gitea 账号(cz/liutao/mmg/wx/yst 均可用) |
## 2. 遇到问题
- 跳转后 Gitea 登录不上:确认用的是 git.1814.love 的账号密码(忘记密码可在 Gitea 页面重置)。
- 登录后报错或循环跳转:联系 wx(服务端 oauth2-proxy 日志可查)。
@@ -0,0 +1,22 @@
# 【新增+修改接口·管理后台+司机H5】车务排查批量修复 11 项——待审详情端点/H5 车型下拉源/列表字段 Label 补齐/续签赛季 bug 修复
> 服务:hl-fleet-service(8087/8187) | 分支:dev-v3 | PR:#3785 | 工单:#3784 | 已部署测试服并 12 项 E2E 实测通过(2026-06-13)
> 背景:wx 指派排查「按逻辑应该有的小功能没有」(如输入框该用下拉搜索框),audit workflow 36 agents 五维度扫描+逐条对抗验证,确认 15 项中 11 项契约有据立即修。
## ⚠️ 关键说明(前端动作)
1. 🆕 **待审核单条详情** `GET /admin/fleet/drivers/pending/{id}`:审核抽屉数据源(证件原图 URL/驾照明细/紧急联系人/自带车块/驳回原因,PII 脱敏),不存在返 600402。**审核页"查看详情"抽屉可以接了**。
2. 🆕 **H5 init 下发 `vehicleTypeOptions`**(仅 mode=new):`[{typeKey,typeName,icon,models:[{modelName,seats}]}]`——H5 新招「常开车型」步骤的**唯一合法数据源,禁前端写死大类**;renew 模式不返。
3. **待审核列表新增出参**:`drivingYears/licenseClass/licenseNo(脱敏)/licenseExpire`(卡片直显初判)+ `modeLabel/reviewStatusLabel`(新招·续签/待审核·已通过·已驳回,不用再硬编码映射)。
4. **司机列表新增出参**:`insuranceTypeLabel`(全年保险/按行程投保/无保险)+ `insuranceAnnualEnd`(年保到期日,仅 annual 行有值);**详情 insurance 块新增** `typeLabel/annualSourceLabel`(手工录入/保游网出单)。
5. **司机列表新增入参** `onlyResidentUnbound=true`:仅返回未被任何车设为常驻的司机——**车辆表单选常驻司机的下拉数据源**(避免选了已占用司机保存才报 605022)。
6. **车辆新增/编辑 fleet/ownerType 行为变更**:后端经字典归一校验——中文标签(如「公司所有」「自有」)也能传、自动归一为字典值落库;非法值返 **100001**(原任意字符串直落库)。
7. **司机编辑新增入参** `blacklistReason`(可选≤256):仅本次把 season 转入 blacklist 时消费并自动落拉黑时间,**拉黑弹窗可以加原因输入框了**;详情/列表 blacklistReason 出参不再恒 null。
8. **vehicleSource 行为变更**:仅接受 own/company,其余值 400(admin 编辑+H5 提交两处)。
9. **续签赛季 bug 修复(行为变更)**:司机 H5 续签勾「今年休息」(continueSeason=false)后审核通过,season 现在正确落 **archived**(原 bug 无条件落 active);勾继续合作仍落 active+追加在册年。
## 实测(测试服 12 项)
详情端点 200+600402 / init 车型选项无 basePrice / 列表新字段 Label 全出 / onlyResidentUnbound 排除准确 / 中文标签归一+脏值 100001 / vehicleSource 脏值 400 / 拉黑原因落库回显 / 续签 false→archived 真链路(H5 提交→审核通过)。
注:另有 2 项排查发现待 wx 拍板(紧急联系人「关系」字典种子口径 / 司机标签聚合清单端点),拍板后另行通知。
@@ -0,0 +1,19 @@
# 【模板优化·管理后台】车辆/司机导入模板示例行图片列内嵌占位示例图
> 服务:hl-fleet-service(8087/8187) | 分支:dev-v3 | PR:#3790 | 工单:#3789 | 已部署测试服并下载实测通过(2026-06-13)
> 背景:wx——「下载模板应该有示例图片」。导入模板末 8 列为内联图列(#3769 起支持格内插图),但下载下来的模板示例行(黄色「示例-」行)这些图列是空白格,用户不知道要往这些格里插图、也不知道插完长什么样。
## ⚠️ 关键说明(前端)
**前端无需任何改动。** 模板下载端点(`GET /admin/fleet/vehicles/import/template`、`GET /admin/fleet/drivers/import/template`)契约/响应类型/调用方式完全不变——只是后端生成的 .xlsx 内容更友好了:示例行的图片列现在各内嵌一张「占位示例图」。
## 改了什么
- **车辆模板**(20 列,末 8 图列:行驶证正面照/副页照/外观照/内饰照/保险单据照/年检单据照/营运证照/其他附件照):黄色示例行的这 8 个图列各内嵌一张占位示例图。
- **司机模板**(23 列,末 8 图列:身份证照/驾驶证照/肖像照/健康证照/培训证书照/荣誉奖励照/从业资格证照/其他附件照):同样内嵌。
- 占位图是一张通用「图片占位」图标(灰色边框 + 太阳 + 远山,无文字),提示用户「这一列要在格内插入对应证件照片,插完就是覆盖这张占位图的样子」。
- **解析行为零变化**:示例行整行仍由首列「示例-」前缀在导入时自动跳过,内嵌的占位图既不会被回导成数据、也不会被抽取入库(双重隔离);用户照常从下一行开始填真实数据、在图列格内插真实照片。
## 实测(测试服)
下载车辆/司机模板各得 8 张占位图,锚定在示例行(第 2 行)的图片列上;占位图视觉正常(无乱码)。端点契约不变,零 DDL、零路由、零新端点。
@@ -0,0 +1,21 @@
# 【行为变更·管理后台】司机待审核列表只回真正提交的记录——过滤未提交空壳 + 已作废链接
> 服务:hl-fleet-service(8087/8187) | 分支:dev-v3 | PR:#3791 | 已部署测试服并 API 实测通过(2026-06-13)
> 背景:wx 反馈「待审核页数据全空」——卡片姓名/身份证/提交时间/照片全空。根因=列表把「司机点了 H5 链接但还没填写提交」的占位空壳、以及已作废链接也捞进了审核队列。
## ⚠️ 关键说明(前端动作)
1. **`GET /admin/fleet/drivers/pending` 行为变更(无需改前端代码,数据自动变干净)**:列表现在只返回**真正提交过且链接未作废**的记录,与「我的链接」派生态 `SUBMITTED` 同口径。两条恒生效基线过滤:
- `submitted_at IS NOT NULL`——排除「生成链接但司机未填写提交」的占位空壳(生成链接那一刻就落了一行 pending+未提交的占位行)
- `void_status='NORMAL'`——排除已作废链接(作废与审核正交,死链不进审核队列)
2. **现象解释**:测试服修复前待审核 tab 有 8 张全空卡片(全是未提交空壳),修复后为 0 条(当前确实没有真正提交待审的司机);已驳回 tab 从 6 条(含 1 条异常空壳)变 5 条真实记录。**待审核 tab 看起来"变空"是正确的**——空壳本就不该出现。
3. **「申请详情页」后端已就绪**:审核详情端点 `GET /admin/fleet/drivers/pending/{pendingId}`(PR#3785 已落)返回证件原图 URL / 驾照正副页 / 紧急联系人 / 自带车实拍照 / 备注(PII 脱敏),不存在返 600402。**审核卡片的「查看详情」抽屉可以接这个端点**看全量明细。
## 实测(测试服)
修复前: 待审核 8 条全 submittedAt=null 空壳 / 全部状态 15 条含空壳。
修复后: 待审核 0 条 / 全部状态 6 条(approved 1+rejected 5)全部 submittedAt 非空 / 已驳回 5 条真实记录(姓名+提交时间齐全)。
## 影响面
仅列表查询行为变更,approve/reject/详情端点不受影响;零接口签名变化、零 DDL、零路由。
@@ -0,0 +1,30 @@
# 【新增接口·管理后台】司机风控拉黑 + 解封两个独立端点——司机卡片可加「拉黑/解封」按钮
> 服务:hl-fleet-service(8087/8187) | 分支:dev-v3 | PR:#3792 | 已部署测试服并 API 往返实测通过(2026-06-13)
> 背景:wx 反馈「司机卡片没有拉黑按钮」。原先拉黑只能走通用编辑端点(PUT 设 season=blacklist),且全量 VO 前端不回传 attachments/tags 会误删、解封更是无任何端点。wx 拍板补独立端点。(车辆拉黑 wx 已撤回·看原型,本次只做司机)
## ⚠️ 关键说明(前端动作)
1. 🆕 **拉黑** `POST /admin/fleet/drivers/{driverId}/blacklist`
- 入参 body:`{"blacklistReason": "客诉原因..."}`(原因**可选**,≤256;不传后端落空串)
- 出参:`{"code":200,"message":"成功"}`
- 规则:active/pending/archived 司机均可拉黑;已是黑名单返 **600202**;司机不存在返 **600205**
- **司机卡片加「拉黑」按钮**(弹框让操作人填可选原因)调本端点。后端只定向写 season+拉黑原因+拉黑时间三列,**不碰附件/标签**(不再有误删风险)——比之前走编辑端点 PUT 的方案安全,请改用本端点。
2. 🆕 **解封** `POST /admin/fleet/drivers/{driverId}/unban`
- 入参:无 body(仅路径参数)
- 出参:`{"code":200,"message":"成功"}`
- 规则:当前必须是黑名单(否则返 **600208**「司机当前不是黑名单状态,无需解封」);解封后 season 回 **active** + 清空拉黑原因/时间
- **黑名单 tab 的司机加「解封」按钮**调本端点。
3. **拉黑/解封会联动车辆**:拉黑→该司机常驻个人车自动停用(service_status=DISABLED);解封→恢复 ACTIVE。
## ⚠️ 已知缺口(知会)
解封的「主管级权限」门禁**暂未加**(hl-fleet 当前无 RBAC 框架、hl-user 未配 fleet 角色),当前任何登录管理员都能解封,待 hl-user 配 supervisor 角色后接入。前端解封按钮可正常对接,权限收紧是后端后续动作。
## 实测(测试服往返)
拉黑(中文原因)→200+season=blacklist+原因落库 / 解封→200+season=active+原因清空 / 非黑名单再解封→600208 / 不存在司机→600205 / 重复拉黑→600202。
## 影响面
错误码新增 600208;网关 `/admin/fleet/**` 通配已覆盖;零 DDL。原 PR#3785 提到的「编辑端点 blacklistReason 入参」仍保留,但**拉黑按钮请改用本专用端点**(避免全量 VO 误删)。
@@ -0,0 +1,23 @@
# 【行为变更·管理后台】编辑司机·全年保险「保单号」从手填改为下拉关联该司机已出的保游网保单
> 服务:hl-fleet-service(8087/8187) | 分支:dev-v3 | PR:#3793 | 已部署测试服(下拉数据源端点 200 实测可达,完整投保流待前端联调)(2026-06-13)
> 背景:wx 反馈编辑司机弹窗「保险配置·全年保险」的保单号是手填输入框,应改为从该司机已出的保游网保单里下拉选择关联。wx 拍板:改下拉关联,保留手填兜底。
## ⚠️ 关键说明(前端动作)
1. **编辑弹窗「保单号」输入框 → 下拉/搜索选择器**:
- 下拉数据源 = `GET /admin/fleet/drivers/{driverId}/insurance/policies`(司机「我的保单」,已有端点);**仅 status=INSURED(已承保)/INSURING(在途出单中)可选**。
- 选中某保单后,把该保单的 `insuranceOrderId` 放进保存入参 `insurance.insuranceOrderId` 提交。
- 选中后**保单号/年保费/保障起止改为只读回显**(由后端按保单真值回填),前端不再手敲这四项。
2. **保存入参 `DriverInsuranceVO.insuranceOrderId` 已放开**(原「入参忽略」):
- `insurance.type=annual` 且传 `insuranceOrderId` → 后端按司机维度反查该保单,回填保单号/保费/起止 + 落 `annualSource=baoyou` + 关联 `insurance_order_id`。
- 横向越权守卫:传入的保单不属于该司机 / 状态不可关联 → 返 **600209**「关联的保游网保单不存在、不属于该司机或状态不可关联」。前端正常从该司机下拉选不会触发。
3. **手填路径保留兜底**(二选一,insuranceOrderId 优先):不传 `insuranceOrderId`、仅手填 `policyNo`+保费+起止时,仍走原手填路径(`annualSource=manual`,行为零变化),用于线下买的、保游网没有的保单。
## 实测(测试服)
下拉数据源端点 `/insurance/policies` code=200 可达;反查回填 + 600209 越权路径由单测覆盖(DriverServiceTest+4 / DriverAnnualPolicyLookupImplTest 5,fleet 全套 714 绿);完整「选保单→回填→保存」端到端需前端接入后联调。
## 影响面
错误码新增 600209;**零新增 Feign/DTO/order-v3 端点/Flyway/网关路由**(复用现有按司机查保单 Feign);后端架构用 driver 子域端口 + insurance 子域实现解环。
@@ -0,0 +1,38 @@
# 【后端已修·管理后台】投保下单「关联订单」下拉报「参数类型错误: id='list'」——后端给订单列表补了 `/list` 别名,前端无需再改
> 服务:hl-order-service-v3(OrderController) | 分支:dev-v3 | PR:#3798(已合并、已部署测试服双实例 8086/8186、网关 9443 往返实测通过) | 2026-06-13
> 背景:前端按上一条 changelog 把保险订单**列表**改成 `/v3/admin/insurance/list` 后,「保险订单」页投保下单弹窗里的**「关联订单」下拉**仍报红条 `参数类型错误: id='list'(需要 Long 类型)`,实际失败请求是 `GET /v3/admin/order/list?page=1&pageSize=20`。
## ⚠️ 关键说明
1. **这是和保险列表不同的另一个调用**:「关联订单」下拉搜的是**业务订单**,调的是 `GET /v3/admin/order/list`(order 模块),不是保险列表。
2. **根因**:order 模块的订单列表原本只挂在 RESTful 集合根 `GET /v3/admin/order`(没有 `/list`),详情是 `GET /v3/admin/order/{id}`;前端按「{模块}/list」习惯调 `/order/list` 时,`list` 落到 `/{id}` 上当 Long 解析失败 → 报 `id='list'`。order 模块是各 admin 列表里唯一用集合根的「异类」,所以前端必踩。
3. **后端已修(PR #3798)**:给订单列表同时挂载根 + `/list` 两条路径。**前端那条现成的 `GET /v3/admin/order/list` 调用现在直接返回 200,无需任何前端改动**,部署后刷新页面红条即消失。
## ⚠️ 对上一条 changelog 的修正
上一条(`13_前端修复_保险订单列表调错路径...`)我说「v3 全站 admin 列表统一 `{模块}/list`」——这对保险/合同/退款/评价/支付成立,但 **order 模块当时是个例外(用集合根)**,所以才有这次的 `/order/list` 报错。本次 PR #3798 把 order 也补上了 `/list`,**现在 `{模块}/list` 这个习惯对订单也成立了**,前端可放心统一用 `{base}/list`。
## 路径现状(部署后)
| 用途 | 可用路径 | 说明 |
|---|---|---|
| 保险订单列表 | `GET /v3/admin/insurance/list` | 上条已说明 |
| **业务订单列表(关联订单下拉用)** | `GET /v3/admin/order/list` ✅ 与 `GET /v3/admin/order` ✅ | 本次新增 `/list` 别名,两者等价 |
| 业务订单详情 | `GET /v3/admin/order/{id}`(id 为 Long) | 不变 |
| 订单关键词搜索 | `GET /v3/admin/order/list?keyword=xxx` | `keyword` 匹配 团号/客户姓名/产品名/订单号 任一字段 LIKE |
## 实测(测试服网关 https://api.test.1814.love:9443,PR #3798 部署后)
```
GET /v3/admin/order/list?page=1&pageSize=20 → {"code":200,"message":"成功","data":{"records":[],"total":0,...}} ✅ 不再报 id=list
GET /v3/admin/order?page=1&pageSize=20 → {"code":200,...} ✅ 回归正常
GET /v3/admin/order/list?page=1&pageSize=20&keyword=张 → {"code":200,...} ✅ 关键词搜索可用
GET /v3/admin/order/123 → {"code":581007,"message":"订单不存在"} ✅ 数字 id 仍正确解析(详情未受影响)
```
> 注:返回 `records:[] / total:0` 是测试库当前没有该 admin 可见的业务订单(数据条件,非接口问题);有真实订单时「关联订单」下拉即有数据。
## 影响面
仅 `OrderController.listOrders` 的 `@GetMapping` 由根改为 `@GetMapping({"", "/list"})`,单 handler 双路径;**零新增方法、零行为变化、无 DDL、无 Flyway、无新增错误码**,网关 `/v3/admin/order/**` 通配已覆盖。
@@ -0,0 +1,53 @@
# 【前端修复·管理后台】保险订单列表页报「参数类型错误: id='list'」——前端调错路径 `/orders/list`,应改为 `/list`
> 服务:hl-order-service-v3(保险模块 AdminInsuranceController) | 无 PR(前端调错 URL,后端契约正常无需改) | 测试服网关 9443 实测复现并确认(2026-06-13)
> 背景:wx 打开「保险管理 → 保险订单」页(`192.168.100.160:9527/insurance/orders`),页面顶部红条报 **「参数类型错误: id='list'(需要 Long 类型)」**。经网关实测复现,定位为前端列表接口 URL 写错。
## ⚠️ 关键说明(前端动作)
1. **根因:前端把保险订单列表调成了 `GET /v3/admin/insurance/orders/list`,这个路径后端不存在。**
- 后端只有 `GET /v3/admin/insurance/orders/{id}`(按 ID 查保险订单详情,`{id}` 是 Long 类型)。
- 前端那个 `.../orders/list` 请求里的 `list` 被 Spring 当成 `{id}` 去解析成 Long,解析失败 → 全局异常处理器返回「参数类型错误: id='list'(需要 Long 类型)」。
- 注意:本项目所有接口**恒返 HTTP 200**,业务错误码在响应体 `code` 字段里。所以 Network 面板看到的是 `200`,但 body 是 `{"code":400,"message":"参数类型错误..."}`——别被 200 误导,要看 body。
2. **正确的列表路径 = `GET /v3/admin/insurance/list`(不带 `/orders`)。**
- 这是 v3 全站 admin 列表的统一惯例 `{模块base}/list`:合同 `/v3/admin/contract/list`、退款政策 `/v3/admin/refund-policy/list`、评价 `/list`、支付 `/list`、保险方案 `/list`……保险订单列表同理就是 `/v3/admin/insurance/list`。
- 请把保险订单页的列表请求 URL 从 `…/insurance/orders/list` 改成 `…/insurance/list`,**入参/分页参数(page/pageSize/筛选项)完全不变**。
3. 详情/按订单查仍走 `/orders/...`,不要动:列表是 `/list`、详情是 `/orders/{id}`,这两者本身不冲突,冲突只来自前端给列表错误地拼了 `/orders/` 前缀。
## 路径对照表
| 用途 | 现状(错误) | 应改为(正确) |
|---|---|---|
| 保险订单**列表** | `GET /v3/admin/insurance/orders/list?page=1&pageSize=20` ❌ | `GET /v3/admin/insurance/list?page=1&pageSize=20` ✅ |
| 保险订单**详情** | — | `GET /v3/admin/insurance/orders/{id}`(id 为 Long) |
| 按业务订单查保险 | — | `GET /v3/admin/insurance/orders/by-order/{orderId}` |
## 实测(测试服网关 https://api.test.1814.love:9443)
错误路径(复现用户截图的报错):
```bash
curl -k "https://api.test.1814.love:9443/v3/admin/insurance/orders/list?page=1&pageSize=20" \
-H "Authorization: Bearer <adminToken>"
# → {"code":400,"message":"参数类型错误: id='list'(需要 Long 类型)","data":null,"success":false}
```
正确路径(返回真实订单数据):
```bash
curl -k "https://api.test.1814.love:9443/v3/admin/insurance/list?page=1&pageSize=20" \
-H "Authorization: Bearer <adminToken>"
# → {"code":200,"message":"成功","data":{"records":[
# {"insuranceOrderId":"2065360048397193217","policyNo":"PICC2026GUARD",
# "premium":3400.00,"insuredCount":1,"coverageStartDate":"2026-01-01",
# "coverageEndDate":"2026-12-31","status":"CANCELLED","statusLabel":"已退保", ...}
# ], "total":..., "page":1, "pageSize":20}}
```
## 结论
后端列表端点正常、契约就是 `/v3/admin/insurance/list`,**无需后端改动**。请前端把保险订单列表页的请求 URL 改为 `/v3/admin/insurance/list` 即可消除红条报错。
> 附:本页此前的「保险产品下拉为空」是另一个前端数据加载问题(后端 `/products/all` 实测返 10 个 ACTIVE 产品),详见同目录 `13_前端核实_保险下单页产品下拉空与司机险混淆-后端正常无需改-管理后台.md`。这两个都是该新页面接线/取数的前端问题。
@@ -0,0 +1,18 @@
# 【前端核实·管理后台】保险下单页「保险产品下拉空」是前端未加载——后端已返 10 个 ACTIVE 产品;此页与司机险是两套(同名异物)
> 服务:hl-order-service-v3(保险模块) | 无 PR(后端核实,无需改) | 测试服 API 实测(2026-06-13)
> 背景:wx 看「保险管理→保险订单→投保下单」弹窗,问「保险下单页面咋没改呢」,且产品下拉为空。经排查为两个独立认知点,后端无 bug。
## ⚠️ 关键说明
1. **「保险下单页面没改」= 同名异物混淆,此页本就不该跟着司机险改**:
- 这个「保险订单 / 投保下单」页走的是 **游客订单险**(order-v3 `AdminInsuranceController` `/v3/admin/insurance/purchase`,`PurchaseInsuranceRequest`,productId+planId 模型)。
- 而最近改的「司机险走保游网」(PR#3700:perTrip→insurancePlanId 必填、删 perDayRate 等)改的是 **fleet 司机档案页**的保险,是**另一套独立模型**。
- 两者「保险计划/insurancePlanId」**同名异物**(API 文档 v1.5.64 已做术语消歧)。所以投保下单页没跟着改是正确的。
2. **「保险产品下拉空」是前端问题,后端正常**:
- 测试服实测 `GET /v3/admin/insurance/products/all` 返 **code=200 + 10 个 status=ACTIVE 产品**(如「山河令(太保山东新)」)。后端产品列表端点工作正常、有数据。
- 截图里下拉空,是**前端未加载/未渲染**该端点数据。请前端检查投保下单弹窗的产品下拉是否正确调 `/v3/admin/insurance/products/all`、计划下拉调 `/v3/admin/insurance/products/{productId}/plans`。
## 结论
投保下单页端点/契约/产品计划下拉数据源后端全部正常,**无需后端改动**。产品下拉空请前端排查数据加载。
@@ -0,0 +1,45 @@
# 【前端BUG·司机录入H5】司机录入链接打不开:/driver-intake 公开路由被导航守卫误拦去登录页
> 端:hl-ui(司机自助录入 H5,fleet 二期) | 严重度:**P0**(整条司机自助录入前端不可用,阿里云短信模板因此过不了审) | 后端/基建已全部就绪,**仅差前端这一处** | 2026-06-13
---
## ✅ 2026-06-15 已解决(误报更正,前端无需改动)
**此前判断"前端导航守卫 bug"系误报——真因在后端 URL,已由后端修复,前端不用动。**
- 真因:① onboard 长链**缺 `/h5/` 前缀**(前端公开路由是 `/h5/driver-intake/:token`,后端却生成 `/driver-intake/...`,落到了非公开的 `/driver-intake`,被守卫正确拦去登录);② token 用 `?t=` 查询参数(应路径参数)。
- 修复(均后端侧):`buildOnboardUrl` 改路径参数(PR #3803)+ Nacos `onboard-base-url` → `https://web.test.1814.love:9443/h5/driver-intake`。
- 已验证:`web.test:9443/h5/driver-intake/{token}` 与 `hr.1814.love/h5/driver-intake/{token}` 均正常公开渲染录入表单。**`/h5/driver-intake/:token` 前端路由本就正常,守卫无 bug。** 阿里云短信模板已重提审核。
- **mmg 无需任何改动,可忽略下方原"问题一/问题二"。**
---
## ⚠️ 现象
司机点开录入短信里的链接,落地页**不是录入表单**,而是被重定向到**管理后台登录页**。阿里云短信模板 `SMS_508070093` 三次被拒,最新拒因「**根据您提供的链接,核实功能内容太少,无法判断实际内容**」——因为审核员打开链接看到的不是录入表单。
## 1. 问题一(P0 · 导航守卫误拦公开路由)—— **需前端修**
- 路由 `/driver-intake/:token` 的 `meta.requiresAuth` 已是 `false`(公开),但**全局导航守卫仍把未登录访问重定向到 `/login`**。
- **复现**:浏览器直接开 `https://web.test.1814.love:9443/driver-intake/{有效token}` → 立即跳 `https://web.test.1814.love:9443/login?redirect=/driver-intake/{token}`。
- 司机是 C 端、**没有后台账号**,这个页面必须公开放行。
- **精确定位(2026-06-15 补充)**:守卫代码是 `if (to.meta.requiresAuth !== false && !token) → 跳 Login`,即**守卫确实读 `meta.requiresAuth`**、`requiresAuth:false` 本应放行。但实测 `/driver-intake/{token}` 仍被拦,说明**部署在测试服 `/var/www/hl-admin` 的这份构建里,driver-intake 路由在运行时 `to.meta.requiresAuth` 并不等于 `false`**(源码里 grep 到过 `requiresAuth:!1`,但运行时没生效——疑似重复/陈旧路由定义,或该 build 未带上 `requiresAuth:false`)。
- **修法**:确认 `/driver-intake/:token` 路由 `meta.requiresAuth:false` 在**最终构建/部署**里真正生效(重新 build + 部署到 web.test),运行时该路由不应跳登录。
## 2. 问题二(URL token 参数格式契约不一致)—— **后端来对齐,前端无需动**
- 前端路由是 `/driver-intake/:token`(token 是**路径参数**)。
- 但后端 onboard 长链历史生成的是 `/driver-intake?t={token}`(**查询参数**),两者对不上、路由不匹配。
- **我(后端)改 `buildOnboardUrl` → 生成 `/driver-intake/{token}`,对齐你们现有路由**。前端这条不用动。(等问题一修好、表单能渲染后我同步改+联调。)
## 后端 / 基建现状(已就绪,仅说明,无需前端关心)
- `hr.1814.love` 已配**独立 Let's Encrypt 证书**(此前它没有独立配置、用了 aboutme 的证书导致域名不匹配,是阿里云最初拒因「链接无法打开」,已修)。
- 短链 `hr.1814.love/s/t{code}` → 转发回测试服解析 → 302 到 onboard 链接,已验证。
- `hr.1814.love/app/h5/**`(录入页后端接口)→ 转发回测试 fleet,`init?token=真token` 返 `200 success`(后端校验链路 OK)。
- 即:**后端全通,只要前端表单能在 `/driver-intake/{token}` 公开渲染,整条链路立刻打通**,我随即重提阿里云短信模板并收尾。
## 验收(前端修完后这样验)
浏览器开 `https://web.test.1814.love:9443/driver-intake/{管理后台生成的有效token}`(**不登录**)应直接渲染司机录入表单(身份证 / 驾驶证 / 行驶证等录入项),而不是跳登录页。修好后回执我,我立即改后端 URL 格式 + 联调 + 重提阿里云模板。
@@ -0,0 +1,53 @@
# 【🔴前端必改·管理后台】司机自助录入「生成专属链接」需加「手机号(必填)+姓名(选填)」输入框 —— 后端已合并部署测试服并四路实测通过(PR #3815 / 工单 #3814)
> 端:hl-ui(车务管理 → 司机自助录入;保险订单/司机档案投保区同源生成入口)| 服务:hl-fleet-service `H5TokenAdminController` §4.1 | PR #3815 已合并 dev-v3 + 部署测试服 | 实测 2026-06-15
> ⚠️ **破坏性改动**:新招生成 token **手机号已变必填**。前端当前若仍不带手机号调生成接口 → 返 **100001**,新招生成会用不了,**请尽快加输入框**。
## ⚠️ 关键说明
司机自助录入「已发放链接」列表姓名/手机长期为「-」、「发短信」无号可发。后端已补:生成 token 时落库联系人,列表显示、「发短信」可直达。**前端需在生成入口加录入框并带参**。设计(wx 2026-06-15 拍):**手动发短信 / 手机号必填、姓名选填 / 新招录入、续签自动取档案**。
## 1. 前端要做(两个 tab)
**新招(new)**:生成区加输入框
- 「手机号」**必填**(11 位,建议前端先做 `^1\d{10}$` 校验)
- 「姓名」选填
- 点「生成专属链接」时把 `phone` + `name` 一起传(见下端点)。
**续签(renew)**:**不要让车管重录**
- 选中司机后,姓名/手机由后端从所绑档案自动取,前端**无需传 phone/name**(传了也被后端忽略)。
- 如要展示,可只读/置灰显示该司机档案的姓名+脱敏手机(来源:司机列表项已有 name/phone)。
## 2. 端点契约(已部署实测)
`POST /admin/fleet/h5/token`(生成 token,base `/admin/fleet/h5`,网关 `/admin/fleet/**` 已覆盖)
| 字段 | 说明 |
|---|---|
| `mode` | `new`/`renew`(必填)|
| `phone` | 🆕 司机手机号。**新招必填(11位)**;续签可不传(取所绑档案) |
| `name` | 🆕 司机姓名。选填(新招录入);续签忽略(取所绑档案) |
| `targetDriverId` | 续签必填(老档案 id,字符串透传防精度丢失) |
| `expireDays` | 选填(new=7/renew=14) |
错误码:**100001** 新招缺手机号「新招生成必须录入手机号」 / **400** 手机号格式不正确 / 600205 续签司机不存在。
返回不变:`pendingId/token/url/shortUrl/expireAt/qrCodeUrl`。
## 3. 配套(已就绪,前端零额外改动)
- 「已发放链接」列表(`GET /admin/fleet/h5/tokens`)的 `name`/`phone`(脱敏) 现在会有值,直接显示即可。
- 「发短信」(`POST /admin/fleet/h5/tokens/{pendingId}/resend`)端点未变;因生成时已落手机号,现在能直接发到该号、短信问候语带姓名。
## 实测(测试服网关 9443)
```
新招 {"mode":"new","phone":"13812340001","name":"测试新招ABC"} → 200;列表 name=测试新招ABC phone=138****0001
新招 {"mode":"new"}(缺手机号) → 100001「新招生成必须录入手机号」
新招 {"mode":"new","phone":"123"}(格式错) → 400「手机号格式不正确」
续签 {"mode":"renew","targetDriverId":"<司机id>"} → 200;列表显示该司机档案 name/phone(巴特尔 135****5020)
```
## 验收
新招:填手机号(必填)+姓名(选填) → 生成 → 「已发放链接」显示姓名/手机 → 点「发短信」发到该号。续签:选司机 → 生成 → 自动显示档案姓名/手机,无需重录。
@@ -0,0 +1,144 @@
# 【行为变更·错误码·管理后台 + 司机H5】车务审计修复批次(PR #3818 / #3819)
> **PR**: #3818(审计修复)、#3819(分层重构 + 唯一键并发锁)
> **服务**: hl-fleet-service | **更新时间**: 2026-06-15
>
> **存放目录**: `changelogs-v2/2026-06/`
> **影响范围**: 管理后台「司机审核 / 司机档案编辑 / 价格日历」 + 司机自助 H5 入职(免登录端)
---
## ⚠️ 关键说明
本批是车务服务一次**全量代码质量审计修复**,绝大部分是**内部重构**(分层归位 / 并发锁 / 事务合并 / N+1 查询优化 / 注释口径),**对前端无契约变化**——**无新增/删除端点,无字段结构变化,无字段改名**。
本 changelog **只列前端可感知的变化**,分三类:
1. **新增 3 个错误码** + 既有错误码的**新触发场景** —— 前端需补提示文案。
2. **司机 H5 入职端点输入校验加固** —— 前端 H5 需补客户端校验 + 限流后重试提示。
3. **个别编辑/删除的行为修复** —— 修掉前端原本会踩到的误拦/误清。
⚠️ 不需要前端改字段映射,只需按下表补错误码文案 + H5 端补几处校验。
---
## 1. 新增错误码(前端需补提示文案)
| code | 名称 | 触发端点 | 触发场景 | 建议前端文案 |
|---|---|---|---|---|
| **600404** | RENEW_TARGET_SEASON_ILLEGAL | `POST /admin/fleet/drivers/pending/{pendingId}/approve` | 审核**续签**记录时,目标司机当前处于**黑名单**状态(防止通过续签审核绕过授权静默解封黑名单司机) | 「该司机已被拉黑,不能通过续签审核解封,请走解除黑名单流程」 |
| **600310** | APPROVED_CANNOT_VOID | `POST /admin/fleet/h5/tokens/{pendingId}/void` | 对**已通过审核**的入职链接点「作废」 | 「该链接对应的司机已审核通过,不可作废」 |
| **600311** | ONBOARD_MODE_MISMATCH | `POST /app/h5/driver-onboard/submit/new`、`POST /app/h5/driver-onboard/submit/renew` | 用**新招** token 打到「续签提交」端点,或用**续签** token 打到「新招提交」端点 | 「入职链接类型不匹配,请使用正确的链接重新进入」 |
**既有错误码的新触发场景**(前端文案可能已有,确认覆盖即可):
| code | 名称 | 端点 | 新增触发 |
|---|---|---|---|
| 600203 | PHONE_DUPLICATED | `…/pending/{pendingId}/approve` | 续签审核里司机改了手机号,且新手机号与另一在册司机重复 |
| 600503 | MODEL_NOT_FOUND | `DELETE /admin/fleet/pricing-calendar`(清除价格) | 传入不存在的车型 ID(之前静默成功删 0 行,现在明确报错) |
| 600501 | DATE_RANGE_INVALID | `DELETE /admin/fleet/pricing-calendar`(清除价格) | startDate 晚于 endDate(区间反转,之前静默无效,现在明确报错) |
---
## 2. 错误码语义修正(管理后台)
**端点**:`POST /admin/fleet/h5/tokens/{pendingId}/void`(作废入职链接)
- **旧行为**:对「已审核通过」的链接作废,返回 `600304`,消息「链接已作废」——与事实矛盾(该链接并未作废)。
- **新行为**:返回 **`600310`「已通过的链接不可作废」**。
- `600304`(LINK_VOIDED「链接已作废」)现在**只**用于校验真正已作废的链接。
> 前端:把「已通过不可作废」场景的错误码判断由 `600304` 改为 `600310`。
---
## 3. 司机 H5 入职端点输入校验加固(司机H5)
免登录 H5 端新增以下后端校验,前端最好同步补客户端校验提升体验:
### 3.1 证件 OCR 端点加文件校验 + 限流
**端点**:`POST /app/h5/driver-onboard/ocr/{step}`(multipart 上传证件照识别)
- **新增文件校验**:文件**非空** + **仅图片**(contentType `image/*`) + **≤ 10 MB**,不满足返 `100001`「参数非法: …」。
- **新增限流**:`@RateLimiter` **30 次 / 60 秒**(与短链端点一致),超限返限流提示。
```
# 反例:上传非图片或超大文件
POST /app/h5/driver-onboard/ocr/idcard (multipart, file=xxx.pdf)
→ { "code": 100001, "message": "参数非法: 仅支持图片格式(jpg/png/webp)" }
```
> 前端:上传前先校验类型/大小;遇限流(短时间多次点)给「操作过于频繁,请稍后再试」提示。
### 3.2 提交端点加 mode 守卫
- `POST /app/h5/driver-onboard/submit/new` 现要求 token 是**新招**类型,否则返 `600311`。
- `POST /app/h5/driver-onboard/submit/renew` 现要求 token 是**续签**类型,否则返 `600311`。
> 防止链接被错用到另一端点造成档案污染/数据丢弃。正常流程前端按 init 返回的 `mode` 走对应页面即不会触发。
### 3.3 新招提交「自带车」跨字段必填
**端点**:`POST /app/h5/driver-onboard/submit/new`
- `hasOwnVehicle = true` 时,`vehicle` 对象必须非空,且车牌 `plate`、车型 `model` 关键项非空,否则返 `100001`。
- 之前 `hasOwnVehicle=true` 而 `vehicle` 为空会落库为空白车辆字段,审核侧拿到矛盾数据需人工驳回。
### 3.4 续签提交 `continueSeason` 必填
**端点**:`POST /app/h5/driver-onboard/submit/renew`
- `continueSeason`(是否继续合作)现为 **`@NotNull` 必填**,缺失返 `400`「是否继续合作不能为空」。
- 之前缺失会被后端兜底当「归档」处理,可能误归档司机。
### 3.5 入职链接 URL 为路径参数(仅文档订正,无行为变化)
- 后端产出的入职链接一直是**路径参数**形式 `…/driver-intake/{token}`(对齐前端路由 `/driver-intake/:token`)。
- 本次仅把 Swagger 文档/示例里残留的旧 query 形式 `?t={token}` 订正为 `/{token}`,**实际行为未变**。前端按现有路由即可。
---
## 4. 行为修复(管理后台)
### 4.1 编辑「单次投保」司机不再被误拦
**端点**:`PUT /admin/fleet/drivers/{driverId}`
- **旧问题**:编辑一个 `insuranceType=perTrip` 的司机时,若只回传 `insuranceType` 而**未重发** `insurancePlanId`,会被 `100001` 误拦(即便库里已有合法 planId)。
- **新行为**:库里已有 planId 时,编辑不重发 planId **放行**;仅当库里也没有、入参也没有时才报必填。
### 4.2 编辑司机驾照不再误清有效期
**端点**:`PUT /admin/fleet/drivers/{driverId}`
- 编辑 license 块时,`licenseExpire`(驾照有效期)改为**入参非空才覆盖**(对齐同块其它字段),不再因前端缺省 `expire` 而把库里的有效期清成 NULL。
### 4.3 gender 字段口径统一
- 列表 / 详情的 `gender` 取值统一为 **`0=未知` `1=男` `2=女`**(之前列表文档漏了 `0`)。司机性别可能返回 `0`,前端按「未知」渲染。
---
## 5. 投保 / 退保幂等加固(管理后台)
**端点**:
- `POST /admin/fleet/drivers/{driverId}/insurance/purchase`(投保,真实出单扣费)
- `POST /admin/fleet/drivers/{driverId}/insurance/policies/{insuranceOrderId}/cancel`(退保)
- 这两个端点现已加**幂等 + 分布式锁**:短时间内**重复提交**(双击 / 弱网重试)会被拦截,返回「投保处理中,请勿重复提交」/「退保处理中,请勿重复提交」。
- 前端**无需改动**,但可借此移除自己的临时防双击逻辑(后端已兜底,不会再重复扣费)。
---
## 6. 内部变更(无前端影响,仅备查)
以下为本批的内部重构,**不影响任何接口契约**,列出仅供排查时参考:
- **分层重构(C5-B)**:司机/车辆/车型三子域的跨域数据访问改为 Port/Service 收口(消除循环依赖),读路径返回数据不变。
- **常驻车唯一键(C8)**:车辆 `uk_primary_driver` 单列唯一键改复合 `(primary_driver_id, deleted_at)` + 并发锁,修掉「软删车残留常驻导致新绑定报 500」的潜在问题。绑定/解绑接口行为不变。
- **价格日历并发**:四个价格写端点统一全局写锁,修掉并发「单改+批改」落重复记录致整页 500 的竞态。
- **司机列表标签查询 N+1 优化**:列表返回结构不变。
---
> 有疑问或需要补具体 curl 示例的端点,随时找后端(wx)。
@@ -0,0 +1,43 @@
# 【后端内部·无前端改动】团期已报名计数改为写入持久化,修复超卖 P0 B 阶段(PR #3839 / 工单 #3836)
> 端:无前端改动 | 服务:hl-order-service-v3 + hl-product-service-v2 | PR #3839 已合并 dev-v3 + 双实例部署实测 | 2026-06-15
## ⚠️ 关键说明
超卖 P0(#3820)B 阶段:将 `order_group_batch.enrolled_rooms / enrolled_people` 从死列改为写时维护的活跃计数器。product-v2 查团期库存时改从持久列读取,**不再实时扫 order_main**。
- **A 阶段(#3829)**:order-v3 新增 `GET /v3/internal/order/batch-stats` 实时聚合端点,product-v2 改接 v3(修复 v2 查 v3 订单得 0 的根因)。
- **B 阶段(#3839,本 PR)**:进一步将计数下沉到写端,消除循环扫表,enrolled 列成库存权威。
## 1. 变更内容
| 变更点 | 说明 |
|--------|------|
| `order_group_batch.enrolled_rooms` | 团期活跃订单数(1 单 = 1 房);创单 +1,取消 AFTER_COMMIT -1 |
| `order_group_batch.enrolled_people` | 活跃订单人数 Σ(adult+child+youngChild+baby);创单 +N,取消 -N |
| `OrderStatsService.batchStats()` | 改读 enrolled 持久列,不再扫 order_main |
| `GroupBatchEnrolledReconcileJob` | 每 5 分钟 + 每天 3:30 对账兜底,发现漂移 WARN 并修正 |
| `V20260615_002` Flyway 迁移 | order_main 加 `(product_batch_id, order_status)` 复合索引,加速对账/回填 |
## 2. 口径定义(四处同源)
- **活跃集** = `order_status != CANCELLED`(含 PENDING_PAY;COMPLETED 仍占名额)
- **enrolled_rooms** = 活跃订单条数(1 订单 = 1 房,不用 room_count 字段)
- **enrolled_people** = Σ(adult+child+youngChild+baby),null 按 0
## 3. 内部端点(Feign LB 直连,不过网关)
`POST /v3/internal/order/group-batch/backfill-enrolled` — 全量回填对账,幂等,返回修正漂移数。已在部署后执行,返回 0(无漂移)。
## 实测(测试服 2026-06-15)
```
GET /v3/internal/order/batch-stats?batchIds=999999,888888
→ {"999999":{"batchId":999999,"orderCount":0,"peopleCount":0},"888888":{...}} ✅
POST /v3/internal/order/group-batch/backfill-enrolled
→ {"code":200,"data":0}(无 GROUP 型活跃订单,enrolled 全零,无漂移) ✅
Flyway V20260615_002 idx_pbid_status 已落地:SHOW INDEX 确认 (product_batch_id,order_status) ✅
order-v3 双实例 8086/8186 均 UP,product-v2 UP ✅
```
@@ -0,0 +1,43 @@
# 【后端内部·含1项前端需知】今日提交代码审查批量修复(PR #3841 / 无工单)
> 端:基本后端内部,**1 项前端需知**(保险订单列表保费字段类型变更)| 服务:hl-order-service-v3 + hl-fleet-service | PR #3841 已合并 dev-v3 + 双实例部署实测 | 2026-06-15
## ⚠️ 关键说明
对 2026-06-15 全部后端提交做了多维代码审查,修复发现的 6 类可改进项。**绝大多数是后端内部加固**(并发守卫/破零/红线合规/测试补齐/注释订正),**唯一影响前端的是保险订单列表的保费字段从 JSON 数字改为字符串**。
## 1. 🔴 前端需知:保险订单列表保费字段 数字 → 字符串
`GET /v3/admin/insurance/list` 返回的 `premium`(保费)和 `totalPremium`(保费,与 premium 同值)两个字段,**由 JSON 数字改为 JSON 字符串**,与平台「金额一律 String」约定对齐(防大额精度丢失)。
| 字段 | 修复前 | 修复后 |
|------|--------|--------|
| `premium` | `10.80`(数字) | `"10.80"`(字符串) |
| `totalPremium` | `10.80`(数字) | `"10.80"`(字符串) |
```jsonc
// 实测响应片段(测试服 9443)
{"premium":"10.80","totalPremium":"10.80","policyHolderName":"内蒙古呼籁国际旅行社有限公司",
"planName":"10万计划","statusLabel":"已承保", ...}
```
**前端如对这两个字段做数值运算/严格类型比较,请按字符串处理**(`parseFloat` 或先转数值)。平台其他金额字段本就是字符串,此次是补齐一致性。其余字段不变。
## 2. 后端内部加固(前端无需关注)
| 模块 | 修复 |
|------|------|
| order-v3 改单 | 团期改单减人改走 decrementEnrolled(带 GREATEST 破零),与 +N/−N 写端口径统一 |
| order-v3 团期对账 | selectForReconcile 去 `.last("LIMIT")` 红线,改 selectPage 合规分页 |
| order-v3 房车打回 | 打回补 CAS 乐观锁守卫,防与并发 dispatch 丢失更新(TOCTOU);并正确释放 claimer |
| fleet 司机 | 补 2 个回归测试锁定 #3818 修复行为 |
| 注释订正 | 计数口径/短链码位数/错误码列表 三处 |
## 验证(测试服 2026-06-15)
```
order-v3 双实例 8086/8186 全新重启(23:08),/v3/internal/order/batch-stats 返 200 ✅
fleet 双实例 8087/8187 全新重启(23:09) ✅
保险列表 premium/totalPremium 实测返字符串 "10.80" ✅
order-v3 171 测试 + fleet DriverServiceTest 109 测试全绿,未触碰任何 Flyway 迁移
```
@@ -0,0 +1,29 @@
# 【行为优化·管理后台】保险「下载保单」改同步按需生成,去掉「保单生成中30秒后重试」轮询
> 端:hl-ui(保险订单 → 下载保单)| 服务:hl-order-service-v3 insurance | PR #3834 已合并 dev-v3 + 部署测试服 + 实测 | 2026-06-15
## ⚠️ 关键说明(前端体验变化)
「下载保单」`GET /v3/admin/insurance/policy/{id}/download` 行为优化:
- **旧**:PDF 还没上传 OSS 时,后端 fire-and-forget 异步补传 + 立刻返 `540310 保单生成中,约30秒后可重试`,**前端要等会儿再点一次(轮询)**。
- **新(同步按需生成)**:点下载时后端**同步**拉保游 PDF + 传 OSS,**直接把文件 URL 返回**。已承保订单**点一次、等几秒就拿到文件**,不用再重试轮询。
## 1. 前端需要配合的点
| 点 | 说明 |
|---|---|
| **响应可能慢几秒** | 同步拉 PDF 会让这个请求**阻塞几秒**(实测 1~3s)。前端点「下载」后**请显示 loading**,不要因为没秒回就当失败。 |
| **成功** | `code=200`,`data` = PDF 的 OSS URL,直接打开/下载即可。 |
| **仍可能返 540310** | 仅当保游侧 PDF 确实还没生成(罕见,正常已承保单下单后即可下)才返 `540310 保单生成中,稍后重试`——此时仍可稍后再点。**不再需要做高频自动轮询**,按需重试即可。 |
| **MANUAL 手工年保单** | 仍返 `540226`(无保游电子保单,真相在司机档案纸质附件),不变。 |
## 2. 契约不变
- 接口路径 / 入参 / 出参类型(`Result<String>`)**完全不变**,前端无需改调用方式,只需:① 加 loading;② 把原来的「自动轮询重试」简化成「按需重试」。
## 验收
已承保订单点「下载保单」:等几秒应直接得到 PDF 链接并下载成功(不再出现「稍后重试」让人反复点)。
> 注:测试环境保游异步出单产品的单一直停在「出单中」(保游测试不自动出单),**暂无保游真出单的已承保单可端到端验证下载成功路径**;后端代码路径(同步拉取 + 失败优雅兜底)已在线上验证。待保游真出单或换同步出单产品即可完整验证。
@@ -0,0 +1,31 @@
# 【行为修复+新增端点·管理后台】保险账户余额显示修复(不再¥0)+ 保险订单「刷新出单状态」端点
> 端:hl-ui(保险管理 → 余额展示 / 保险订单列表·详情)| 服务:hl-order-service-v3 insurance | PR #3827 已合并 dev-v3 + 部署测试服双实例 + 实测 | 2026-06-15
## 1. 保险账户余额显示修复(后端 bug,前端无需改)
- **现象**:保险余额一直显示 **¥0**。
- **根因**:保游 `/Pay/GetUserBalance` 返回 `{"IsSuccess":true,"Data":"198304.40"}`——`Data` **直接就是余额字符串**,后端原代码却取 `Data.Balance`(当嵌套对象),取不到返 0。
- **已修**:后端按 Data 文本直取(兼容旧嵌套格式)。`GET /v3/admin/insurance/balance` 现返真实余额(实测 **198304.4**)。
- **前端无需任何改动**,刷新即正确显示。
## 2. 🆕 新增「刷新出单状态」端点(可选给保险订单加按钮)
异步出单(保游 80099 受理)的保险订单会先处于「**出单中(INSURING)**」,等保游出单后才变「已承保」。新增一个主动对账端点,可让运营在订单页**手动点「刷新出单状态」**立即拉保游最新状态翻态(不用干等回调):
| 用途 | 方法 + 路径 | 入参/出参 |
|---|---|---|
| 刷新/同步出单状态 | `POST /v3/admin/insurance/orders/{id}/sync-status` | path `id`=保险订单ID;返回 `Result<InsuranceOrderDetailVO>`(刷新后的最新详情,含 status/statusLabel/policyNo);错误码 INSURANCE_ORDER_NOT_FOUND |
- **建议**:保险订单列表/详情,对「出单中」状态的单加一个「**刷新状态**」按钮,调本端点;返回的 detail 直接刷新该行/该详情。
- 行为:后端会查保游订单详情对账——保游已出单→翻「已承保」并回填保单号;已退保→「已退保」;仍待出单→保持「出单中」(不会误翻)。**仅对账,不会重复出单。**
- 网关 `/v3/admin/**` 已覆盖,无需后端/网关其它改动。
## 3. 说明(无需前端关心,仅背景)
- 后端已加**定时对账 job**(每 5 分钟自动扫「出单中」单查保游翻态),即使没人点按钮、保游回调也没到,出单中的单也会在保游出单后**自动**变已承保。手动端点只是让运营能立即刷新、不用等 5 分钟。
- 保游异步出单回调(DES 密钥)也已在测试环境配好作双保险。
## 验收
余额展示页应显示真实余额(非 ¥0)。保险订单「出单中」的单,点「刷新状态」(接 sync-status)后:保游已出单则变「已承保」+ 显示保单号;保游仍在出则保持「出单中」。
@@ -0,0 +1,60 @@
# 【前端调整·管理后台】保险计划「使用分类」打标弹窗:单选下拉 → 客人/司机 多选 —— 后端零改动,仍调同一端点
> 端:hl-ui(保险管理 → 保险产品 → 计划「设置使用分类」弹窗)| 服务:hl-order-service-v3 `AdminInsuranceController`(SRS §9.17.3)| **后端零改动(端点/入参/白名单一字不变)** | wx 2026-06-15 看到打标弹窗后要求「改为多选」
> 衔接:本条是 `15_催办_保险计划使用分类司机可用打标UI仍缺…` 的细化——打标弹窗你们已做出来(截图:单选下拉 客人/司机/通用),wx 要求把**单选改成多选**。
## ⚠️ 关键说明:为什么后端不用动(一句话)
后端 `usage_category` 是**单值**列,白名单只有三值 `CUSTOMER / DRIVER / BOTH`,而 **`BOTH(通用)` 的语义就是「客人和司机都适用」**。也就是说,这三值恰好是「客人 / 司机」两个基础项的**全部非空组合**:
| 多选勾了什么 | 等价的单值(提交给后端的 `usageCategory`) |
|---|---|
| 只勾 **客人** | `CUSTOMER` |
| 只勾 **司机** | `DRIVER` |
| **客人 + 司机 都勾** | `BOTH` |
| 一个都没勾 | ❌ 不允许,至少选一个(保持必填,等同原来下拉不能为空) |
所以「单选改多选」只是**前端的展示形态变化**:把原来的「客人/司机/通用」三选一下拉,换成「客人 / 司机」两个可多选的勾选项,提交前按上表换算成同一个 `usageCategory` 字符串。**调的端点、请求体、白名单、错误码全部不变**,后端无感。
## 1. 前端要改什么(只动这一个弹窗)
- 把「设置使用分类」弹窗里的**单选下拉**(客人/司机/通用 三选一)改成**多选**控件(多选下拉 / 复选框 / 多选 tag 均可),选项只留**客人(CUSTOMER)、司机(DRIVER)** 两个,**去掉「通用 BOTH」这个显式选项**(它被「两个都勾」替代)。
- **提交**:按上表把勾选集合换算成单个 `usageCategory` 值,仍调原端点(见第 2 节),请求体不变。
- **回显**(打开弹窗时根据当前 `usageCategory` 勾上):
- `CUSTOMER` → 勾【客人】
- `DRIVER` → 勾【司机】
- `BOTH` → 勾【客人】+【司机】
- 校验:至少勾一项才能提交(空集不允许),等价于原下拉的必填约束。
## 2. 端点不变(后端零改动,照旧调)
| 用途 | 方法 + 路径 | 入参 / 出参 |
|---|---|---|
| **打标(设使用分类)** | `PUT /v3/admin/insurance/plans/{planId}/usage-category` | body `{"usageCategory":"BOTH"}`;白名单 **CUSTOMER/DRIVER/BOTH**,非法值返 **540223**;返回 `Result<Void>` |
| **回显(读当前分类)** | `GET /v3/admin/insurance/products/all` | 每个产品 `plans[].usageCategory` ∈ CUSTOMER/DRIVER/BOTH,按上表反向勾选 |
`planId` 是雪花 id,**当字符串透传**(别转 JS Number 致科学计数法)。
## 3. 注意
- **不要新增/改后端字段**:后端不接受数组,仍是单个字符串值;「两个都选」请前端换算成 `BOTH` 再提交,别传 `["CUSTOMER","DRIVER"]`。
- 司机投保下拉口径不变:仍只列 `usageCategory ∈ {DRIVER, BOTH}` 的计划;客人端不收紧。改多选不影响这条口径——勾了「司机」(DRIVER 或 BOTH)的计划照常进司机下拉。
- 保游「同步产品」不覆盖本标注(增量护栏),放心标。
## curl 实测(测试服网关 9443,真 admin token;端点未变,仅复用验证)
```bash
# 「客人+司机都勾」→ 提交 BOTH
curl -k -X PUT "https://api.test.1814.love:9443/v3/admin/insurance/plans/2054773833342451714/usage-category" \
-H "Authorization: Bearer <adminToken>" -H "Content-Type: application/json" \
-d '{"usageCategory":"BOTH"}'
# → {"code":200,"success":true}
# 回显:读各计划当前分类,按映射表反向勾选
curl -k "https://api.test.1814.love:9443/v3/admin/insurance/products/all" -H "Authorization: Bearer <adminToken>"
# → data[].plans[].usageCategory ∈ CUSTOMER/DRIVER/BOTH
```
## 验收
打开某计划「设置使用分类」弹窗 → 改为多选两个勾选项(客人 / 司机)→ 同时勾上两个 → 保存 → 重新打开弹窗,两个应都为勾选态;用 `GET .../products/all` 看该计划 `usageCategory` 应为 `BOTH`。只勾「司机」时该值为 `DRIVER`,且计划出现在「司机投保 → 保险计划」下拉里。
@@ -0,0 +1,54 @@
# 【行为修复·管理后台】保险订单列表「投保人 / 保障期间 / 总保费」三列不再为空
> 端:hl-ui(保险管理 → 保险订单列表)| 服务:hl-order-service-v3 insurance | PR #3831 已合并 dev-v3 + 部署测试服双实例 + 实测 | 2026-06-15
## ⚠️ 关键说明
保险订单列表表格的「**投保人 / 保障期间 / 总保费**」三列此前全空。**后端数据一直是齐全的**(实测 premium=27.0、保障期 2026-06-16~2026-07-31 都有值),空的原因是**列表接口字段名与详情接口分叉**——前端列表表格复用了**详情接口的字段名**,而列表接口当时没给这些名。
本次**后端把列表接口的字段补齐成与详情接口同款**,前端**多数情况下无需改动**,刷新即可显示。
## 1. 列表接口 `GET /v3/admin/insurance/list` 现已返回的字段(已补齐)
| 列 | 现在可读的字段(任选其一,**同值**) | 实测值示例 |
|---|---|---|
| **投保人** | `policyHolderName` 🆕 | `内蒙古呼籁国际旅行社有限公司` |
| **总保费** | `totalPremium` 🆕 或 `premium` | `27.00` |
| **保障期间(开始)** | `startDate` 🆕 或 `coverageStartDate` | `2026-06-16` |
| **保障期间(结束)** | `endDate` 🆕 或 `coverageEndDate` | `2026-07-31` |
- 🆕 标记的是本次**新增**字段;之前列表只有 `premium` / `coverageStartDate` / `coverageEndDate`,且**完全没有** `policyHolderName`。
- 现在列表与详情接口(`GET /v3/admin/insurance/orders/{id}`)**字段名完全一致**,前端列表/详情可共用同一套字段读取,不会再出现「详情有、列表空」。
## 2. 「保单号」列显示「出单中,保单号生成中…」属正常
- 状态为「**出单中(INSURING)**」的订单,保游尚未出单,**本就没有保单号**,后端 `policyNo`/`extPolicyNo` 返回 `null` 是正确的。
- 前端对 null 显示占位文案没问题。出单成功后 `extPolicyNo` 会回填真实保单号。
- 建议:保单号列优先读 `extPolicyNo`(`policyNo` 是兼容字段,后续版本将废弃)。
## 3. 列表响应示例(实测,dev-v3 已部署)
```json
{
"code": 200,
"data": {
"records": [{
"insuranceOrderId": "2066402144482709506",
"extOrderNo": "BX2026061514071660000217",
"extPolicyNo": null, "policyNo": null,
"productName": "山河令(太保山东新)", "planName": "10万计划",
"policyHolderName": "内蒙古呼籁国际旅行社有限公司",
"premium": 27.00, "totalPremium": 27.00,
"insuredCount": 1,
"coverageStartDate": "2026-06-16", "coverageEndDate": "2026-07-31",
"startDate": "2026-06-16", "endDate": "2026-07-31",
"status": "INSURING", "statusLabel": "出单中",
"source": "BAOYOU", "bizType": "DRIVER"
}]
}
}
```
## 验收
保险订单列表「投保人」显示投保主体公司名(如「内蒙古呼籁国际旅行社有限公司」),「总保费」显示金额,「保障期间」显示起止日期。出单中的单「保单号」为空/占位属正常,出单后回填。
@@ -0,0 +1,24 @@
# 【字段类型对齐·管理后台】保险订单「详情」与「保费试算」金额字段改 String 序列化,与列表对齐
> 端:hl-ui(保险订单详情 / 投保试算)| 服务:hl-order-service-v3 insurance | PR #3842 已合并 dev-v3 + 部署测试服 + 实测 | 2026-06-15
## ⚠️ 关键说明(前端需对齐解析类型)
平台铁律:金额 JSON 出参一律用 **String**(避免大数/精度问题)。本次把保险几处遗漏的金额字段补齐为 String,**与列表口径一致**:
| 端点 | 字段 | 旧 | 新 |
|---|---|---|---|
| 详情 `GET /v3/admin/insurance/orders/{id}` | `totalPremium` / `premium` | JSON 数字 `10.80` | JSON 字符串 `"10.80"` |
| 投保试算 `InsuranceTrialPriceRespVO` | `premium` | JSON 数字 | JSON 字符串 |
> 列表 `GET /v3/admin/insurance/list` 的 `totalPremium`/`premium` 在上一版 (#3831) 已是 String。本次修复前,**列表返字符串、详情返数字**,前端复用同名字段会遇到类型不一致;现已统一。
## 1. 前端需要做的
- 详情页 / 试算结果里读 `totalPremium`、`premium` 时按**字符串**处理(与列表一致)。若之前对详情按 number 解析/做运算,请改成先 `Number(x)` 再算(或直接展示字符串)。
- 其余字段、路径、结构**不变**。
## 验证(测试服实测,过网关 9443 + 真 admin token)
- 列表 `/v3/admin/insurance/list`:`totalPremium`=`"10.80"`、`premium`=`"10.80"`(String)✅
- 详情 `/v3/admin/insurance/orders/{id}`:`totalPremium`=`"10.80"`、`premium`=`"10.80"`(String)✅ 两端一致
@@ -0,0 +1,52 @@
# 【🔴前端催办·管理后台】保险计划「使用分类(司机可用)」打标 UI 仍未做 —— 这是「司机投保」整条的卡点,后端端点齐全且已实测,只差前端这一个开关
> 端:hl-ui(保险管理 → 保险产品)| 服务:hl-order-service-v3 `AdminInsuranceController`(SRS §9.17.3)| **后端零改动(端点早已存在并实测可用)** | 测试服网关 9443 实测 2026-06-15
> ⚠️ 本条是**重复催办**:同一缺口已在 `13_…` / `15_司机投保保险计划下拉空…` 里作为"第 3 件事"提过,但至今未落实。wx 2026-06-15 再次确认「现在没有地方标记保险给司机用」,故单独拎出、升 P0 催办。
## ⚠️ 关键说明:为什么是卡点(一句话)
「保险订单 / 司机档案 → 投保下单 → 人员类型=司机」的「保险计划」下拉,**只列被标为"司机可用(DRIVER/BOTH)"的计划**(安全侧,防把客人计划误投给司机)。而所有保游同步进来的计划**默认都是 CUSTOMER(客人用)**——**没有任何 UI 能把计划标成司机可用 → 司机下拉永远空 → 司机投保功能运营层面用不起来**。
现在司机下拉里能看到「计划一 / 10万计划」,是后端排查时**临时手动标的 2 个测试样本**,不是运营能控的。**正式上线前,这个打标 UI 必须做**,否则运营每加一个司机险计划都得找后端改库。
## 1. 前端要补什么(唯一缺口,精确到位置)
在「**保险管理 → 保险产品**」里给**计划(plan)**加一个「使用分类」控件:
- **位置**:保险产品列表 → 点某产品(眼睛图标/详情)→ 该产品下的**计划列表**,每个计划一行加一个「使用分类」下拉或分段开关:**客人(CUSTOMER) / 司机(DRIVER) / 通用(BOTH)**。
- **粒度**:按**计划**标,不是按产品标(一个产品下不同计划可分别给客人/司机)。
- **默认**:未标的计划是 `CUSTOMER`,下拉显示"客人"。
- 标成 **司机** 或 **通用** 后,该计划立即出现在「司机投保」的保险计划下拉里。
## 2. 调这两个现成端点(后端零改动)
| 用途 | 方法 + 路径 | 入参 / 出参 |
|---|---|---|
| **打标(设使用分类)** | `PUT /v3/admin/insurance/plans/{planId}/usage-category` | body `{"usageCategory":"DRIVER"}`;白名单 **CUSTOMER/DRIVER/BOTH**,非法值返 **540223**;返回 `Result<Void>` |
| **回显(读当前分类)** | `GET /v3/admin/insurance/products/all` | 每个产品 `plans[].usageCategory` 即当前分类(用于渲染控件选中态);也可用 `GET /v3/admin/insurance/products/{productId}/plans` 按产品取计划 |
网关 `/v3/admin/**` 已覆盖路由,无需后端/网关任何改动。
## 3. 关键注意(避免踩坑)
- **保游"同步产品"不会覆盖本标注**:后端 `syncProducts` 是增量护栏,运营标过的 `usageCategory` 在下次同步后**保留**,不会被重置回 CUSTOMER。放心标。
- **司机下拉口径**:司机投保下拉只列 `usageCategory ∈ {DRIVER, BOTH}`;客人端维持现状(全列、不收紧)。
- `planId` 是雪花 id,**当字符串透传**(别转 JS Number,参考今天另一条续签 targetDriverId 科学计数法踩坑)。
## curl 实测(测试服网关 9443,真 admin token)
```bash
# 打标:把某计划标成司机可用
curl -k -X PUT "https://api.test.1814.love:9443/v3/admin/insurance/plans/2054773833342451714/usage-category" \
-H "Authorization: Bearer <adminToken>" -H "Content-Type: application/json" \
-d '{"usageCategory":"DRIVER"}'
# → {"code":200,"success":true}
# 回显:读各计划当前分类
curl -k "https://api.test.1814.love:9443/v3/admin/insurance/products/all" -H "Authorization: Bearer <adminToken>"
# → data[].plans[].usageCategory ∈ CUSTOMER/DRIVER/BOTH
```
## 验收
保险产品 → 某产品计划列表,把一个意外险计划「使用分类」改为「司机」→ 回到「投保下单 → 人员类型=司机 → 保险计划」下拉,该计划应出现。运营全程无需找后端。
@@ -0,0 +1,41 @@
# 【后端确认·司机H5】司机自助录入「链接+接口+提交」全链路免登录已就绪(PR #3803);唯一前瞻缺口=真实证件照/头像上传缺免登录 OSS 通道
> 端:hl-ui(司机自助录入 H5,fleet 二期)+ 后端 hl-fleet-service | 关联 PR #3803(onboard 长链补 `/h5/` 前缀,已合 dev-v3)| 测试服网关 9443 实测(2026-06-15)
> 结论:**当前无阻塞,前端无需立即改动**。本条只做两件事——①确认司机录入链接本就该免登录、现在确已免登录且能正常打开;②钉一个"做到真实拍照上传那步才会遇到"的后端缺口,避免遗忘。
## ⚠️ 关键说明(一句话)
司机自助录入链接**已经是免登录且能正常打开**——后端网关白名单 / 前端公开路由 / token 自校验全就绪。上一条 `13_…导航守卫误拦公开路由` 报的"前端守卫 bug"已确认是**误报**:真因是后端 onboard 长链缺 `/h5/` 前缀,**PR #3803 已修并验证,前端守卫无 bug、无需再动**。本条补充说明整条链路现状 + 标记唯一一个前瞻缺口。
## 1. 已就绪并实测(全程免登录,前端无需动)
| 环节 | 路径 | 鉴权 | 实测(2026-06-15,无任何登录 token)|
|---|---|---|---|
| 链接落地页 | `/h5/driver-intake/{token}` | 前端公开路由 | 200 渲染录入表单 ✓(PR #3803 已对齐前缀+路径参数)|
| 初始化 | `GET /app/h5/driver-onboard/init?token=` | 网关 `/app/h5/**` 免 JWT + token 自校验 | 200 返 8 步配置 + 车型选项 ✓ |
| OCR 识别 | `POST /app/h5/driver-onboard/ocr/{step}` | 同上 | 可调;stub 返固定假数据、**不存图**(#2797 待真实 OCR)|
| 新招/续签提交 | `POST /app/h5/driver-onboard/submit/{new,renew}` | 同上 | 可提交建档;**除 token、licenseNo(驾驶证号)外,含全部照片 URL 在内的字段当前全选填**,空照片也能提交进「待审核」|
| 短信短链 | `/app/h5/s/{code}` | 完全公开 302 | 跳转 OK |
实测示例(无登录态直接打):
```bash
curl -k "https://web.test.1814.love:9443/app/h5/driver-onboard/init?token=<有效token>"
# → {"code":200,"message":"成功","data":{"mode":"new","tokenValid":true,
# "tokenState":"fresh","stepConfig":{"totalSteps":8,...},"vehicleTypeOptions":[...]}}
```
## 2. 唯一前瞻缺口:真实证件照/头像上传缺免登录通道(做到那步前需后端先补)
**现在不阻塞**(照片字段全选填、OCR 是 stub),但等做"司机真实拍照上传证件照/头像"时会撞到:
- 现状:OCR 端点收到图片但 **stub 不存**(`H5OnboardService.ocr` 注释"file 暂不处理内容,stub 不读取");提交入参里的 `idCardFrontUrl / licenseFrontUrl / regFrontUrl / regBackUrl / exteriorUrls / interiorUrls / portraitUrl` 都是 OSS URL,需要先把图片传上去拿到 URL 才能回填。
- 设计(API-SPEC-FLEET §2.3/§3.6,line 776/1926):附件走**前端 STS 直传 OSS** 后回填 URL;真实 OCR 也改成入参 `ossUrl`。
- 缺口:后端**目前没有任何 STS 发证端点**(全仓 grep `sts` 主代码 0 命中),网关白名单也只放行了文件 **preview**、**未放行任何 upload**;现有 `/mp/file/upload` 需 C 端登录、`/admin/file/upload` 需管理端登录,**司机端(无任何账号)都用不了**。
- 结论:做"司机真实拍照上传"时,后端需补一个挂在 `/app/h5/` 下、token 自校验的**免登录上传或 STS 发证端点**(届时独立小工单)。
**请前端在排到"拍照上传"那步前先找后端对齐走法**:STS 前端直传 OSS(后端补免登录发证端点)vs 后端中转上传(后端补免登录 `/app/h5/.../upload`)。两种都需要后端先动,前端别先按需登录的 `/mp/file` 或 `/admin/file` 接。
## 验收(现状,可自测)
浏览器**不登录**开 `https://web.test.1814.love:9443/h5/driver-intake/{管理后台生成的有效token}` → 直接渲染录入表单;填完(**可不传照片**)提交 → 进「司机档案·待审核」。整条已通。
@@ -0,0 +1,59 @@
# 【新增接口·司机H5】真实拍照/证件照免登录上传 OSS 通道已补齐(PR #3823)
> 端:hl-ui(司机自助录入 H5,fleet 二期)+ 后端 hl-fleet-service | PR #3823(已合 dev-v3)| 测试服网关 9443 实测(2026-06-15)
> 关联上一条 `15_司机H5录入免登录已就绪PR3803-待补真实拍照上传OSS免登录通道-司机H5.md` 标记的「唯一前瞻缺口」——本条**正式补齐**,前端可以接「拍照上传」了。
## ⚠️ 关键说明(一句话)
新增免登录端点 `POST /app/h5/driver-onboard/upload`:司机**无需任何账号**,凭录入 token 即可把真实拍照/证件照传到 OSS 拿回**公开 URL**,再回填到提交入参的 `idCardFrontUrl / licenseFrontUrl / portraitUrl / regFrontUrl` 等字段。之前对齐的两条走法(STS 前端直传 vs 后端中转)后端**选了"后端中转"**——前端不用碰 OSS SDK、不用拿临时密钥,只管把文件 POST 给这个端点、拿返回的 `url` 即可。
## 1. 接口契约
| 项 | 内容 |
|---|---|
| 方法/路径 | `POST /app/h5/driver-onboard/upload` |
| 鉴权 | **免登录**(网关 `/app/h5/**` 白名单 + token 自校验),无需任何 JWT |
| Content-Type | `multipart/form-data` |
| 入参 `token` | 必填,录入链接 token(form 字段) |
| 入参 `file` | 必填,图片文件,**仅图片类型 ≤10MB** |
| 入参 `groupKey` | 选填,OSS 分组前缀,**默认 `fleet-driver`**(如需头像单独目录可传 `fleet-portrait` 等) |
| 返回 | `{ "url": "OSS 公开访问 URL" }` |
| 限流 | 30 次 / 60 秒(公开端点防刷,口径同 OCR) |
**错误码**:
| code | 含义 |
|---|---|
| 100001 | 文件为空 / 非图片 / 超 10MB |
| 600300 | token 无效 |
| 600301 | token 已过期 |
| 600302 | token 已使用 |
| 600304 | 链接已作废 |
## 2. 调用示例
```bash
# 上传一张证件照,拿回 OSS 公开 URL
curl -k -X POST "https://web.test.1814.love:9443/app/h5/driver-onboard/upload" \
-F "token=<录入链接token>" \
-F "file=@id_card_front.jpg" \
-F "groupKey=fleet-driver"
# → {"code":200,"message":"成功","data":{"url":"https://oss.../fleet-driver/2026/06/xxx.jpg"},"success":true}
```
前端典型流程:拍照/选图 → 调本端点拿 `url` → 把 `url` 填进对应字段(`idCardFrontUrl` 等)→ 最后一并提交 `submit/new` 或 `submit/renew`。多图(车辆外观/内饰 `exteriorUrls/interiorUrls`)逐张上传、各自拿 `url` 收进数组。
## 3. 实测(测试服 9443,2026-06-15)
| 场景 | 入参 | 实测返回 |
|---|---|---|
| 合法图片 + 无效 token | image/png + 伪 token | `code:600300`「邀请链接无效」✓(路由通 + 免登录无 401 + 文件校验过 + token 校验生效) |
| 非图片文件 | text/plain | `code:100001`「参数非法: 仅支持上传图片文件」✓(文件守门先于 token) |
真实 OSS 落盘走的是 user-service 文件服务现成直传链路(与车/司机批量导入内联图同一通道,已生产验证)。
## 4. 前端动作
- 排到「拍照上传」那步时,把图片 POST 到本端点,用返回的 `url` 回填字段即可。
- **不要**再接需登录的 `/mp/file/upload` 或 `/admin/file/upload`(司机端无账号用不了)。
- `groupKey` 一般不用传,默认 `fleet-driver` 即可;若想按类型分目录可自定义。
@@ -0,0 +1,32 @@
# 【契约收紧·管理后台】司机待审核列表 `reviewStatus` 删除已废弃幽灵态 `reviewing`
> 端:hl-ui(车管 → 司机待审核列表)| 服务:hl-fleet-service driver/review | PR #3840 已合并 dev-v3 + 部署测试服 + 实测 | 2026-06-15
## ⚠️ 关键说明
待审核列表 `GET /admin/fleet/drivers/pending` 的 `reviewStatus` 入参枚举**收紧**:
- **旧**:`@Pattern` 放行 `pending / reviewing / approved / rejected` 四值。但 `reviewing`(审核中)是设计已删除的**幽灵态**——状态机里从不写入该值,库中永无 `reviewing` 行。传 `reviewStatus=reviewing` 会**通过校验却恒返空列表**(`total=0`),误导排查。
- **新**:`reviewStatus` 仅接受 `pending / approved / rejected` 三值。传 `reviewing` 直接返 `code=400` 参数校验失败。
## 1. 前端需要确认的点
| 点 | 说明 |
|---|---|
| **审核状态 Tab** | 列表页 Tab 应只有 **待审核(pending) / 已通过(approved) / 已驳回(rejected)** 三个。若前端任何地方还会传 `reviewStatus=reviewing`,需移除——否则该请求现在返 400。 |
| **正常三值不受影响** | `pending` / `approved` / `rejected` 行为完全不变。 |
| **不传 = 全部** | `reviewStatus` 不传时返回全部(含两条隐式基线过滤:已提交 + 未作废),不变。 |
## 2. 契约不变项
- 路径 / 出参结构 / 分页参数 / 其余字段(modeLabel / reviewStatusLabel / photos 等)**完全不变**。
- 本次仅为入参枚举校验收紧,对齐 API §5.1 修正契约(审计 §17 条目2)。
## 验证(测试服实测,过网关 9443 + 真 admin token)
| 入参 | 结果 |
|---|---|
| `reviewStatus=reviewing` | `code=400` 参数校验失败 ✅ |
| `reviewStatus=pending` | `code=200` total=0 ✅ |
| `reviewStatus=approved` | `code=200` total=1 ✅ |
| 无 filter | `code=200` total=6 ✅ |
@@ -0,0 +1,43 @@
# 【前端接线 + 缺打标UI·管理后台】司机投保「保险计划」下拉空——后端端点全已存在,缺①计划没打「司机可用」标②前端没接对端点③缺打标入口UI
> 服务:hl-fleet-service(DriverInsuranceController,§13.7)+ hl-order-service-v3(计划打标)| 无 PR(端点全已存在,后端零改动)| 测试服实测(2026-06-15)
> 背景:wx 在「保险管理→保险订单→投保下单→人员类型=司机」选了司机后,「保险计划」下拉「无数据」,且找不到哪里能给计划设「司机可用」。wx 拍板:保险订单页 + 司机档案页**两个入口都要能给司机投保**。
## ⚠️ 关键判定:不是后端缺接口,是①没数据②前端没接对③缺一个打标UI
司机投保的 admin 端点**早已全部存在**(fleet DriverInsuranceController,base `/admin/fleet/drivers`)。**保险订单页和司机档案页用同一套 fleet 端点即可**(端点注释里已写明「保险订单页人员类型=司机路径传 bindAnnual=true」):
| 用途 | 现成端点(直接接,无需后端补)| 关键参数 |
|---|---|---|
| **司机可选计划下拉** | `GET /admin/fleet/drivers/insurance/plan-options` | 无参;只返 usageCategory=DRIVER/BOTH 的计划;返回 planId/planName/productName |
| **司机险投保** | `POST /admin/fleet/drivers/{driverId}/insurance/purchase` | body:planId(必填,下拉取)/coverageStartDate/coverageEndDate(必填)/remark(可选)/**bindAnnual**(保险订单页传 true=出单后自动绑为司机全年保险;档案页缺省 false)。**被保人后端按司机档案自动组装,前端不传** |
| 司机保单列表 | `GET /admin/fleet/drivers/{driverId}/insurance/policies` | 按司机列全部保单 |
| 司机险退保 | `POST /admin/fleet/drivers/{driverId}/insurance/policies/{insuranceOrderId}/cancel` | 仅人工误投手动退 |
## 为什么下拉空:一个计划都没被标「司机可用」
- 保险计划默认 `usageCategory=CUSTOMER`(客人用),司机下拉**只列 DRIVER/BOTH** 的(安全侧,防误投客人计划)。
- 实测:测试库 17 个计划**全是 CUSTOMER**,0 个司机可用 → 下拉必然空。
- 本次已**临时标 2 个意外险计划为 DRIVER 作可测样本**(「平安…专属意外险·计划一」+「山河令·10万计划」),现 `plan-options` 实测返 2 条。**正式哪些计划算司机可用应由运营自己定/标**(不是这 2 个写死)。
## 前端要做 3 件事
1. **保险订单页「人员类型=司机」**:「保险计划」下拉改调 `GET /admin/fleet/drivers/insurance/plan-options`(不要调 order 的 `/v3/admin/insurance/...`,那边没有司机专用下拉);「确认投保」改调 `POST /admin/fleet/drivers/{driverId}/insurance/purchase` 并传 `bindAnnual=true`;被保人列表那块**不用填**(后端按司机档案自动组装)。
2. **司机档案页投保**:同样调上面两个端点,`bindAnnual` 缺省 false(行为不变)。
3. 🆕 **加「设为司机可用」打标入口**(这是当前唯一缺的 UI):在「保险管理→保险产品/计划」页,每个计划加一个「使用分类」开关/下拉(客人 CUSTOMER / 司机 DRIVER / 通用 BOTH),调现成端点:
- `PUT /v3/admin/insurance/plans/{planId}/usage-category`,body `{"usageCategory":"DRIVER"}`(白名单 CUSTOMER/DRIVER/BOTH,非法返 540223)。
- 计划当前分类在产品详情 `GET /v3/admin/insurance/products/all` 的 `plans[].usageCategory` 里可读,用于回显。
- 标好后司机下拉就有数据,运营无需找后端。
## 实测(测试服网关 9443)
```
PUT /v3/admin/insurance/plans/2054773833342451714/usage-category {"usageCategory":"DRIVER"} → 200 成功
GET /admin/fleet/drivers/insurance/plan-options → code=200, 2 条
[{planId:2054773828716134401, planName:"计划一", productName:"平安…专属意外险(海拉尔)", usageCategory:"DRIVER"},
{planId:2054773833342451714, planName:"10万计划", productName:"山河令(太保山东新)", usageCategory:"DRIVER"}]
```
## 结论
后端**零改动**:司机投保 4 端点 + 计划打标端点全已存在并实测可用。缺口是**前端接线(下拉/投保改调 fleet 端点)+ 新增一个计划打标 UI**。投保正向流程会真扣保游账户余额,联调请只打到防御层(如未标计划计划 540031、重叠保障期 540032),勿真出单。
@@ -0,0 +1,36 @@
# 【行为/前端·管理后台】司机投保「保障期」默认应是短期且最多 90 天(保游无年期产品),别再默认 1 年
> 端:hl-ui(保险订单 / 投保下单 → 人员类型=司机)| 服务:hl-fleet-service + hl-order-service-v3 insurance(后端无改动,计划标记已调整)| wx 2026-06-15 拍板「司机险先用短期险打通」| 2026-06-15
## ⚠️ 关键背景:司机险目前只能短期(保游没有年期产品)
排查实测确认:**保游测试目录里没有任何 ≥365 天(1 年)的产品**——最长才 180 天(豪华版),司机可用的「10万计划」**最多 90 天**。所以司机年保(1 年)当前做不到,wx 拍板**先用短期险打通**。
- **后端已调整**:把投不了的「计划一」(费率只有 1 档、任何承保期都失败)**取消了「司机可用」标记**;现在司机投保的「保险计划」下拉**只剩「10万计划」**(可用,1–90 天)。
- 司机年保 1 年期待后续对接保游配年险,暂不在本次范围。
## 1. 前端要改什么
投保下单(人员类型=司机)的「保障开始 / 保障结束」:
1. **默认值从「1 年」改成短期**:现在默认是 `开始=明天, 结束=次年-1天`(≈364 天),这必然投保失败。改成短期默认,如 **开始=明天、结束=开始+29 天**(30 天)。
2. **承保期最多 90 天**:建议前端约束 `结束 - 开始 + 1 ≤ 90`,超 90 天直接拦下并提示「司机险最长 90 天」(否则提交必失败,保游返「承保天数不符」)。
3. 可选:弹窗加一句说明「司机险为短期意外险,最长 90 天」。
> 承保天数与保费对应(10万计划实测):1天¥1 / 30天¥10.8 / 90天¥48.4(保费后端算,前端不用管,可用试算接口预览)。
## 2. 后端契约(无变化,仅说明)
- 司机可选计划:`GET /admin/fleet/drivers/insurance/plan-options` → 现在只返「10万计划」(planId 2054773833342451714)。
- 投保:`POST /admin/fleet/drivers/{driverId}/insurance/purchase` body `{planId, coverageStartDate, coverageEndDate, remark, bindAnnual}` ——承保期超计划上限会返 **540030**「承保天数不符」(保游透传)。
## 验收
投保下单选司机 → 计划下拉只有「10万计划」→ 保障期默认是短期(≤90天)→ 确认投保成功(INSURING 受理)。把保障期手动设成 >90 天应被前端拦下或后端返 540030。
---
## 附:本次后端侧已做
- 取消「计划一」(planId ...828716134401) 的司机可用标记(PUT usage-category=CUSTOMER)——它保游配置坏的、投不了,避免运营/前端选到一直报错。
- 全表 45 个测试司机身份证已修为合法号(另见同日 changelog),投保不再卡身份证。
@@ -0,0 +1,34 @@
# 【前端BUG·司机续签】续签「生成链接」报「targetDriverId 格式错误」:前端把雪花司机 id 传成了科学计数法(精度丢失),应作字符串原样透传
> 端:hl-ui(车务管理 → 司机自助录入 → 「2026 赛季续签」tab,fleet 二期)| 严重度:**P0**(续签生成链接整功能不可用)| 后端测试服实测正确、**无需改动** | 2026-06-15
## ⚠️ 现象
「2026 赛季续签」选中司机(如吴师傅)点「生成链接」→ 顶部红条报 **400「请求数据格式错误:字段 [targetDriverId] 格式错误」**,链接生不出来。
## 根因(后端实测复现,确认是前端传值格式问题)
对 `POST /admin/fleet/h5/token` 的 `targetDriverId` 逐格式实测(测试服网关,真 admin token):
| 前端传的值 | 后端结果 |
|---|---|
| `"1916000000000000001"`(整数字符串)| ✅ 正常解析(进业务,返 600205 司机不存在)|
| `1916000000000000001`(数字)| ✅ 正常解析 |
| `""`(空字符串)| ✅ 按 null 处理(全局 Jackson 空串→null)|
| **`"1.916e18"`(科学计数法字符串)** | ❌ **400「targetDriverId 格式错误」← 与线上报错完全一致** |
| `1916000000000000001.0`(小数)| ✅ 解析(截断)|
**结论:前端把 19 位雪花司机 id 当成 JS Number 处理,丢了精度并序列化成了科学计数法字符串(`1.9..e18`)**,后端无法把它还原成精确 Long → 报格式错误。
- 后端对「整数字符串 / 数字」都能正确接收,**后端无需改动**。
- 后端**不应**接受科学计数法:到那一步 id 已经丢精度,硬收会查到错误的司机,必须由前端在源头保住精度。
## 前端修法
- `targetDriverId` **全程当字符串透传**:司机列表接口返回的 id 本就是字符串(后端对 > 2^53 的雪花已序列化为 String),前端**别 `Number()` / `parseFloat()` / `+id` / 算术运算**,原样塞进 generate 请求体。
- 自查:生成请求 payload 里 `targetDriverId` 应是 `"1916xxxxxxxxxxxxxxx"` 这种纯数字字符串,**不是** `1.9e18`、也不带小数点。
- 同类风险点排查:续签司机选择卡片绑定 id、其它带雪花 id 的请求体字段,统一按"字符串透传、不入数字类型"处理。
## 验收
「2026 赛季续签」选司机 → 生成链接 → 应正常返回 token / 二维码 / 短链,不再报「targetDriverId 格式错误」。
@@ -0,0 +1,192 @@
# 【契约核对·司机 H5】司机自助录入(新招/续签/OCR/init)字段名权威清单 — 逐字核对回执
> 端:司机 H5(自助录入)| 服务:hl-fleet-service `com.hulalv.fleet.h5` | 后端**零改动**(仅核对回执)| 2026-06-15
>
> 起因:前端反馈「硬必填字段已确定不会 400,但选填字段名是推断的」,请后端拿真实 VO 逐字核对。本文以**当前 dev-v3 代码实物**为准(非文档推断),逐项确认/纠正下列 5 个待核项。
## ⚠️ 关键说明(先看这 3 条,最容易踩)
1. **VO 类名两处纠正**:前端用的 `OcrRespVO` 实际叫 **`OcrResultVO`**;`InitRespVO` 实际叫 **`H5InitRespVO`**。`SubmitNewReqVO` / `SubmitRenewReqVO` 名字正确。
2. **驾龄字段是 `drivingYears`(Integer),不是 `years`**。
3. **🔴 准驾车型字段名「写读不一致」(后端真实如此,前端必须分别对待)**:
- **提交**(submit/new)和 **OCR 返回**(OcrResultVO)里叫 **`licenseClass`**;
- **续签预填**(init 的 prefill)里叫 **`licenseType`**。
- 即:续签场景前端读 `prefill.licenseType` 回显,但若进 submit 入参得用 `licenseClass` 字段名。这是两个不同 VO、历史命名差异,后端本次不动(动它要前后端联调,且你们已在按它编码)。续签提交本身**不收准驾车型**(见 §3),所以实际只影响「续签页准驾车型回显读 `licenseType`」一处。
---
## 1. submit/new 新招提交 — `POST /app/h5/driver-onboard/submit/new`
入参 `SubmitNewReqVO`(`@RequestBody`,application/json)。**硬必填只有 2 个**:`token`、`licenseNo`;**其余全选填**(不传不会 400)。
### 1.1 顶层字段(逐字)
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token` | String | ✅ @NotBlank | H5 邀请凭证(URL 透传) |
| `name` | String | 选填 | 姓名 |
| `phone` | String | 选填 | 手机号 11 位 |
| `gender` | String | 选填 | **性别编码字符串**:`1`=男 / `2`=女 / `0`=未知(取值来自字典 gender,提交时字典校验,非法报 **100001**) |
| `nation` | String | 选填 | 民族 |
| `drivingYears` | Integer | 选填 | **驾龄(年)— 注意不是 `years`** |
| `idCard` | String | 选填 | 身份证号 18 位 |
| `idCardFrontUrl` | String | 选填 | 身份证正面 OSS URL |
| `idCardBackUrl` | String | 选填 | 身份证背面 OSS URL ← **前端推断的名字正确** |
| `licenseNo` | String | ✅ @NotBlank | 驾照号(#3781 与表单创建口径对齐,缺失返 400) |
| `licenseClass` | String | 选填 | 准驾车型 A1/A2/B1/B2 等 |
| `licenseExpire` | String(date) | 选填 | 驾照有效期 `yyyy-MM-dd`(LocalDate) |
| `licenseFrontUrl` | String | 选填 | 驾照正页 OSS URL |
| `licenseBackUrl` | String | 选填 | 驾照副页 OSS URL ← **前端推断的名字正确** |
| `hasOwnVehicle` | Boolean | 选填 | 是否自带车 |
| `vehicle` | object | 选填 | 自带车信息(hasOwnVehicle=true 时填,见 §1.2) |
| `preferredCategory` | String | 选填 | 常开大类 key(如 suv/mpv/bus,取自 init 的 `vehicleTypeOptions[].typeKey`) |
| `preferredModel` | String | 选填 | 常开型号(取自 `vehicleTypeOptions[].models[].modelName`) |
| `vehicleSource` | String | 选填 | 车源:仅 `own` / `company`(@Pattern,其它值 400) |
| `vehicleNotes` | String | 选填 | 备注 |
| `emergency` | object | 选填 | 紧急联系人嵌套块(见 §1.3) |
| `portraitUrl` | String | 选填 | 本人正脸照 OSS URL(头像) |
### 1.2 `vehicle` 嵌套块(`SubmitVehicleVO`)
| 字段名 | 类型 | 说明 |
|---|---|---|
| `plate` | String | 车牌号 |
| `model` | String | 车型名称 |
| `seats` | Integer | 核定座位数(含驾驶员) |
| `annualInspectDate` | String(date) | 下次年检日期 `yyyy-MM-dd` |
| `regFrontUrl` | String | **行驶证**正面 OSS URL(注意是 `reg` 不是 license) |
| `regBackUrl` | String | **行驶证**副页 OSS URL |
| `exteriorUrls` | List\<String\> | 车外观照片 URL 列表 |
| `interiorUrls` | List\<String\> | 车内饰照片 URL 列表 |
### 1.3 `emergency` 嵌套块(`SubmitEmergencyVO`)
| 字段名 | 类型 | 说明 |
|---|---|---|
| `name` | String | 紧急联系人姓名 |
| `phone` | String | 紧急联系人手机号 11 位 |
| `relation` | String | 与司机的关系(如「父亲」,自由文本) |
### 1.4 返回 `SubmitRespVO`
```json
{ "pendingId": "1234567890123456789", "estimatedReviewHours": 24, "season": null }
```
- `pendingId`:雪花 ID,**字符串格式**(已 ToStringSerializer,按字符串收);`estimatedReviewHours`:新招=24;`season`:新招恒为 null。
- 错误码:400 参数校验 / **600300** token 无效 / **600301** token 已过期 / **600302** token 已使用 / **600200** 身份证已存在。
---
## 2. OCR 识别 — `POST /app/h5/driver-onboard/ocr/{step}`
### 2.1 step 步骤标识(路径参数,仅这 3 个合法值,其它返 400)
| step 值 | 用途 | 驾照即 §前端问的「ocr/license」 |
|---|---|---|
| `id-card` | 身份证 | |
| `license` | **驾照 ← 前端用的 `ocr/license` 路径正确** | ✅ |
| `reg-cert` | 行驶证 | |
### 2.2 入参(multipart/form-data,不是 JSON)
| 参数 | 必填 | 说明 |
|---|---|---|
| `token` | ✅ | form 参数 |
| `file` | ✅ | 图片文件,仅图片类型 ≤10MB(违反报 **100001**) |
| `side` | 选填 | `front` / `back`,默认 `front` |
### 2.3 返回 `OcrResultVO`(统一 VO,按 step 填对应字段,其余为 null)
| step | 该步会填的字段 |
|---|---|
| `id-card` | `name` / `idCard` / `gender`(1=男/2=女) / `nation` / `issuedBy`(签发机关) |
| `license` | `licenseNo` / `licenseClass` / `licenseExpire`(`yyyy-MM-dd`) |
| `reg-cert` | `plate` / `model` / `seats`(Integer) / `annualInspectDate`(`yyyy-MM-dd`) |
> 注意①:OCR 驾照返回的是 **`licenseClass`**(与 submit 一致,非 prefill 的 licenseType)。
> 注意②:**当前 OCR 是 stub**(`OcrStubService` 返回固定假数据,工单 #2797 真实 OCR 未接);字段名/契约已稳定,可照此编码,但识别值现在是假的。
> 错误码:400 step 非法 / **100001** 文件空/非图片/超 10MB / **600300** token 无效 / **600301** token 已过期。
---
## 3. submit/renew 续签提交 — `POST /app/h5/driver-onboard/submit/renew`
入参 `SubmitRenewReqVO`。**只填变更项**。
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token` | String | ✅ @NotBlank | H5 邀请凭证 |
| `continueSeason` | **Boolean** | ✅ @NotNull | **是否继续合作:`true`=继续 / `false`=今年休息 ← 前端按 boolean 传,正确** |
| `phoneChanged` | Boolean | 选填 | 手机号是否已变更 |
| `phone` | String | 选填 | 新手机号(phoneChanged=true 时填) |
| `primaryVehiclePlateChanged` | Boolean | 选填 | 常驻车是否已变更 |
| `primaryVehiclePlate` | String | 选填 | 新常驻车牌(…Changed=true 时填) |
| `licenseRenewed` | Boolean | 选填 | 驾照是否已续期 |
| `licenseExpire` | String(date) | 选填 | 新驾照有效期 `yyyy-MM-dd`(licenseRenewed=true 时填) |
| `licenseFrontUrl` | String | 选填 | 新驾照正页 URL |
| `licenseBackUrl` | String | 选填 | 新驾照副页 URL |
- 续签**不收准驾车型**字段(无 licenseClass/licenseType 入参),所以 §0 那条不一致只影响「预填回显」不影响续签提交。
- 返回 `SubmitRespVO`:`{ pendingId, estimatedReviewHours: 12, season: "pending" }`。
- 错误码:400 / **600300** / **600301** / **600302**。
---
## 4. init 初始化(含续签预填档案结构)— `GET /app/h5/driver-onboard/init?token={token}`
返回 `H5InitRespVO`(前端用名 `InitRespVO`,真实类名 `H5InitRespVO`)。
### 4.1 顶层字段
| 字段名 | 类型 | 说明 |
|---|---|---|
| `mode` | String | `new`=新招 / `renew`=续签(决定走 8 步还是 4 步) |
| `tokenValid` | Boolean | =`tokenState∈{fresh,editable,rejected_editable}`;false 时按 tokenState 渲染失效文案 |
| `tokenState` | String | 7 态:`fresh` / `editable` / `rejected_editable` / `expired` / `voided` / `consumed` / `invalid` |
| `reviewStatus` | String | `pending` / `approved` / `rejected`(token 不存在时 null) |
| `rejectReason` | String | 驳回原因(仅 rejected 相关态有值) |
| `lastSubmittedAt` | String(datetime) | 上次提交时间(未提交过 null) |
| `expireAt` | String(datetime) | token 过期时间 |
| `stepConfig` | object | `{ totalSteps: new=8/renew=4, stepNames: [...] }` |
| `prefill` | object | **续签预填档案(仅 mode=renew 有值,新招 null)见 §4.2** |
| `vehicleTypeOptions` | List\<object\> | 常开车型字典(**仅 mode=new 且 token 可编辑**,renew 为 null);第 5 步「常开车型」唯一合法数据源 |
### 4.2 `prefill` 续签预填结构(`RenewPrefillVO`)← 前端待核项「续签 init 预填档案结构」
| 字段名 | 类型 | 说明 |
|---|---|---|
| `name` | String | 司机姓名 |
| `phone` | String | 手机号**脱敏展示**(`138****1234`,仅展示,提交变更走 §3 的 phone) |
| `primaryVehiclePlate` | String | 常驻车车牌 |
| `licenseNo` | String | 驾照号**脱敏展示**(`150102******1234`) |
| `licenseType` | String | **准驾车型 ← 注意此处字段名是 `licenseType`,不是 licenseClass(见 §0 关键说明 3)** |
| `licenseExpire` | String(date) | 驾照有效期 `yyyy-MM-dd` |
| `licenseDaysLeft` | Long | 驾照距到期天数(前端展示续期提醒用) |
| `activeYears` | List\<Integer\> | 历次在册年份列表,如 `[2023,2024,2025]` |
### 4.3 `vehicleTypeOptions` 结构(仅新招用,`VehicleTypeOptionVO`)
```
[{ typeKey, typeName, icon, models: [{ modelName, seats }] }]
```
- 严禁带价格(basePrice 物理上不在该 VO,司机端不透出基准价);前端禁写死内置 typeKey(运营动态字典)。
---
## 5. 图片上传补充(前端可能也要)— `POST /app/h5/driver-onboard/upload`
multipart:`token`(必填) / `file`(图片≤10MB) / `groupKey`(可选,默认 fleet-driver);返回 `UploadRespVO` = `{ "url": "OSS公开URL" }`。所有 *Url 字段(idCardFrontUrl/licenseFrontUrl/portraitUrl/vehicle.regFrontUrl…)都回填这个 url。
---
## 核对结论汇总(对应前端 5 个待核项)
| 前端待核项 | 结论 |
|---|---|
| ① submit/new 选填字段名(drivingYears vs years、紧急联系人块) | 是 **`drivingYears`**;紧急联系人块字段名 `emergency.{name,phone,relation}`,全部按 §1.1/§1.3 |
| ② 照片 idCardBackUrl/licenseBackUrl | **推断正确**;另注意自带车行驶证是 `vehicle.regFrontUrl/regBackUrl`(reg 非 license) |
| ③ submit/renew continueSeason 类型 | **Boolean,正确**(@NotNull 必填) |
| ④ OCR ocr/license 步骤标识及返回字段名 | step=**`license`** 正确;返回字段见 §2.3(驾照填 licenseNo/licenseClass/licenseExpire);类名是 **OcrResultVO** |
| ⑤ 续签 init 预填档案结构 | 见 §4.2;**唯一坑:准驾车型在 prefill 里叫 `licenseType`** |
> 后端本次零代码改动;以上为 dev-v3 当前代码实物核对。若真机测试某选填项「没落库」,优先核对字段名是否与本清单一致(尤其 drivingYears、vehicle 内 reg* 命名、prefill.licenseType)。
@@ -0,0 +1,48 @@
# 【前端调整·管理后台】司机自助录入「发短信」按钮应直接发短信(调 resend 端点),别只复制链接
> 端:hl-ui(车务 → 司机自助录入 → 新招专属链接卡片「发短信」按钮)| 服务:hl-fleet-service `H5TokenAdminController`(§4.6.4,端点早已存在)| **后端零改动,且已端到端验证过真发到手机** | wx 2026-06-15 反馈「应该在页面中直接发送短信」
## ⚠️ 关键说明:现状 vs 应该
- **现状**:点「发短信」只是**前端把短链复制到剪贴板**(toast「短链已复制,可粘贴到短信/微信发送」),还要人工再粘到短信里发。
- **应该**:点「发短信」**后端直接把入职短信发到司机手机**——这个能力后端早就有(走通知中心 + 阿里云 SMS_508070093,短信内含短链)。**上次已端到端验证:真发到 185****2756(18547062756),收件人确认收到。**
设计上 generate 只生成不发短信,「发短信」(=§4.6.4 重发端点) 才真发。所以前端把「发短信」按钮接到下面这个现成端点即可。
## 1. 前端要改什么
把「发短信」按钮的点击动作**从「复制到剪贴板」改成「调 resend 端点真发短信」**,发送成功后弹 toast(如「短信已发送至 185****2756」)。
- URL 旁那个独立的「复制」按钮**保留**(人工粘到微信用),只改「发短信」这一个按钮的行为。
## 2. 调这个现成端点(后端零改动)
| 项 | 内容 |
|---|---|
| 方法 + 路径 | `POST /admin/fleet/h5/tokens/{pendingId}/resend` |
| pendingId | 取自「生成 token」(`POST /admin/fleet/h5/token`) 或列表项的 `pendingId`(雪花,**字符串**透传) |
| body(可选) | `{"phone":"13800001111"}` 覆盖默认收件号;**不传则用该链接生成时录入的手机号**(新招生成时手机号已必填,正常不用传) |
| 出参 | `Result<SendOnboardLinkRespVO>`:成功返**脱敏收件号**(用于 toast);短信经通知中心 afterCommit 异步发,出参不回投递结果(到达由 notification_send_log 承载) |
| 可发状态 | 仅 `VALID_UNSUBMITTED`(有效·未提交)/ `REJECTED`(已驳回)可发;其它状态返 600308 |
| 网关 | `/admin/fleet/**` 已覆盖,无需改网关 |
## 3. 错误码(前端按 code 提示)
- **600307** 该链接无可用手机号 → 提示「请先补录手机号」(可弹输入框,把手机号塞进 body.phone 重试)
- **600308** 当前状态不可发送(已提交/已通过/已作废)→ 提示对应状态
- **600402** 记录不存在
- 401 未登录
## curl 实测(测试服网关 9443,真 admin token;截图那条链接就是可发状态)
```bash
# 截图链接 token=5ce987cc... 对应 pendingId=2066367115152986113, status=VALID_UNSUBMITTED, phone=185****2756
curl -k -X POST "https://api.test.1814.love:9443/admin/fleet/h5/tokens/2066367115152986113/resend" \
-H "Authorization: Bearer <adminToken>" -H "Content-Type: application/json" -d '{}'
# → {"code":200,"success":true,"data":{... 脱敏收件号 ...}} 且司机手机真实收到入职短信(含短链)
# ⚠️ 联调注意: 这会真发一条短信(走阿里云,计费),请用你自己的测试号、别狂点
```
## 验收
点「发短信」→ 不再是复制提示,而是「短信已发送至 1xx****xxxx」;对应手机收到「【呼籁旅行】师傅您好,请点击完成司机入职信息录入:https://…/s/{码},N天内有效。」短信,点链接进司机入职登记表单。
@@ -0,0 +1,49 @@
# 【前端接线·管理后台】司机自助录入「已发放链接」等整块是前端写死/mock——后端 6 个端点早已存在,请直接接,无需后端补
> 服务:hl-fleet-service(H5TokenAdminController,FLEET v1.5 §4.1/§4.6) | 无 PR(后端端点早已存在并部署) | 测试服网关 9443 实测返回真实数据(2026-06-15)
> 背景:wx 在「车务管理→司机自助录入」页看「已发放链接」列表,指出这块是前端写死的,要求改走后端接口、没有就补。经核实**后端接口早已存在且可用**,前端当前展示的是 mock 数据未接线。
## ⚠️ 关键判定:前端在用写死数据,不是后端缺接口
截图「已发放链接」里 token 是 `kx7m9qz` / `ab3d8fh`(6–7 位短串)、二维码域名 `hr.elujiwo.com/driver-intake/kx7m9qz`(路径式)。而**后端真实数据**是:
```
GET /admin/fleet/h5/tokens?page=1&pageSize=5 (测试服实测 code=200)
records[0] = {
"pendingId": "2066323803964637186",
"mode": "new", "modeLabel": "新招",
"token": "18bf0d0208a7459684621727c4511109", // 32 位 UUID,不是 kx7m9qz
"name": "", "phone": "138****0000",
"createTime": "2026-06-15 08:56:00", "expireAt": "2026-07-15 08:56:00",
"status": "VALID_UNSUBMITTED", "statusLabel": "...",
"url": "https://hr.1814.love/driver-intake?t=18bf0d02...", // hr.1814.love + ?t=,不是 elujiwo.com
"shortUrl": "https://web.test.1814.love:9443/s/tRE4y8bc7" // 真实短链
}
```
token 长度、域名、链接格式全对不上 → **前端那几行是写死/mock 的,请替换为下列现成端点**。
## 现成端点全清单(base `/admin/fleet/h5`,网关 `/admin/fleet/**` 已覆盖,全部无需后端改动)
| # | 用途 | 方法 + 路径 | 关键说明 |
|---|------|-----------|---------|
| 1 | 生成录入 token(二维码/链接)| `POST /admin/fleet/h5/token` | 入参 mode(new/renew)/targetDriverId(renew必填)/phoneHint/expireDays;返回 token/url/**shortUrl**/qrCodeUrl(300×300 PNG Base64)/expireAt |
| 2 | **已发放链接列表**(红框这块)| `GET /admin/fleet/h5/tokens` | 过滤 mode/status(6派生态)/keyword(姓名或token);分页 page/pageSize;返回 `PageResult<H5TokenListItemRespVO>` |
| 3 | 导出 CSV | `GET /admin/fleet/h5/tokens/export` | 同列表入参无分页,返回 text/csv(UTF-8 BOM)|
| 4 | 作废链接 | `POST /admin/fleet/h5/tokens/{pendingId}/void` | 仅 APPROVED 不可作废;已 VOIDED 幂等;600402 不存在/600304 已通过 |
| 5 | 重发录入短信 | `POST /admin/fleet/h5/tokens/{pendingId}/resend` | 仅 VALID_UNSUBMITTED/REJECTED 可重发;走短链;600307 无手机号/600308 状态不可重发 |
| 6 | 重新生成链接 | `POST /admin/fleet/h5/tokens/{pendingId}/regenerate` | SUBMITTED/APPROVED 不可重生;作废旧+建新返新 token/qr;600309 已提交/已通过 |
## 列表项字段(H5TokenListItemRespVO,端点 #2 返回)
`pendingId`(String雪花) / `mode`+`modeLabel`(new=新招·renew=续签) / `token`(32位) / `name`(未提交为空串) / `phone`(脱敏 138****2345) / `createTime` / `expireAt` / `submittedAt`(未提交 null) / `reviewStatus`(pending/approved/rejected) / `status`(6派生态 VOIDED/APPROVED/REJECTED/SUBMITTED/EXPIRED/VALID_UNSUBMITTED) / `statusLabel`(中文) / `url`(可复制转发的完整长链) / `shortUrl`(短信实投短链,旧行无短码时 null,前端降级显示 url)。
## 前端动作
1. 「生成专属链接 + 二维码」改调 #1,二维码用返回的 `qrCodeUrl`、复制用 `url`、短信用 `shortUrl`(别再用 elujiwo.com 域名/短假 token)。
2. 「已发放链接」表改调 #2(替换写死的 3 行 mock),列直接映射上面字段;操作列「作废/重发/重新生成」接 #4/#5/#6,「导出」接 #3。
3. 状态列直接用后端 `statusLabel`(已是中文,6 态实时派生),不要前端自己算。
## 实测
`GET /admin/fleet/h5/tokens?page=1&pageSize=5` → code=200,返回多条真实 VALID_UNSUBMITTED 记录(32 位 token + hr.1814.love?t= 链接 + web.test 短链),数据真实可用。**后端无需任何改动。**
@@ -0,0 +1,54 @@
# 【性能·管理后台】投保下单「选择司机」搜索下拉改调轻量端点 GET /admin/fleet/drivers/options(别再用 /page)
> 端:hl-ui(保险订单 / 投保下单 → 人员类型=司机 → 「选择司机」搜索下拉)| 服务:hl-fleet-service `DriverController`(新增端点)| **后端已实现 + 部署测试服双实例 + 网关 9443 实测通过** | PR #3817 已合并 dev-v3 | 2026-06-15
> 背景:wx 反馈「选择司机」搜索下拉太慢、需限 10 条。排查发现下拉复用了**重型档案分页列表** `/admin/fleet/drivers/page`,作类型搜索框(每敲字一次请求)开销过大。已新增专用轻量端点,请前端切过去。
## ⚠️ 关键说明:为什么 /page 慢(一句话)
`/admin/fleet/drivers/page` 是司机**档案分页列表**,每次调用都干一堆下拉用不到的活:
1. **全表 `GROUP BY season` 聚合**(seasonCounts,和返回几条无关,每次必跑全表);
2. **N+1 标签查询**(每个司机单独查一次 tags);
3. 常驻车反查 IN 查 + 每行 activeYears 解析。
下拉只需要「姓名 + 脱敏手机号」,上面全是浪费。**光传 `pageSize=10` 治标不治本**(全表 seasonCounts + N+1 标签每次还在跑)。
## 1. 前端要改什么(只换数据源)
把「选择司机」搜索下拉的数据源**从 `/admin/fleet/drivers/page` 换成 `GET /admin/fleet/drivers/options`**。投保提交、保险计划下拉等其它逻辑都不变。
## 2. 新端点契约
| 项 | 内容 |
|---|---|
| 方法 + 路径 | `GET /admin/fleet/drivers/options` |
| 入参 | `keyword`(可选):**姓名模糊**;输入**完整 11 位手机号**则**精确匹配**(手机号 AES 加密存储、密文等值,**不支持手机号模糊/前缀搜**——这就是搜索框提示「11 位手机号」的原因)。`limit`(可选):默认 **10**,上限 **20**(超出封顶)。 |
| 出参 | `Result<List<{driverId, name, phone}>>`:`driverId`(雪花,**字符串**,别转 JS Number)/ `name` / `phone`(**脱敏** 135****5020)。**仅这三字段**,不再返 tags / 常驻车 / seasonCounts 等。 |
| 网关 | `/admin/fleet/**` 已覆盖,无需改网关。 |
## 3. 注意
- 下拉口径与原 `/page` 一致:返回全部未软删司机(不按赛季/状态收紧),keyword 同语义。
- 类型搜索框建议**输入时带 keyword 调用**(如防抖 300ms);不传 keyword 也会返回最新 10 条作首屏候选。
- 手机号要精确命中必须输满 11 位(密文等值),输前几位**搜不到**——属设计限制,请在交互上明确(提示已写「搜索司机姓名或11位手机号」即可)。
## curl 实测(测试服网关 9443,真 admin token)
```bash
# 默认 10 条
curl -k "https://api.test.1814.love:9443/admin/fleet/drivers/options?limit=10" \
-H "Authorization: Bearer <adminToken>"
# → code=200, data 10 条: [{"driverId":"2065272153565020161","name":"巴特尔","phone":"135****5020"}, ...]
# 姓名模糊
curl -k "https://api.test.1814.love:9443/admin/fleet/drivers/options?keyword=巴" -H "Authorization: Bearer <adminToken>"
# → code=200, 4 条(含 巴特尔/135****5020)
# limit 超限封顶 20
curl -k "https://api.test.1814.love:9443/admin/fleet/drivers/options?limit=999" -H "Authorization: Bearer <adminToken>"
# → code=200, 20 条
```
## 验收
「投保下单 → 司机 → 选择司机」下拉改调 `options` 后:键入姓名片段即时返候选(≤10 条,秒回,不再卡);输入完整 11 位手机号能精确命中;选中后 driverId 正确带入投保提交。
@@ -0,0 +1,331 @@
# 保险订单列表接口路径改名:/orders -> /list
- **变更类型**:修改接口(破坏性路径变更)
- **端类型**:管理后台
- **日期**:2026-06-16
- **关联 Issue**:[#3681](https://git.1814.love:8443/wx/HL/issues/3681)
- **PR**:[#3682](https://git.1814.love:8443/wx/HL/pulls/3682)
- **Commit**:[36b787692](https://git.1814.love:8443/wx/HL/commit/36b7876922caf9843b4c4911aa94a237a5fd9573)
- **后端负责人**:腰苏图
---
## 1 接口背景
前端保险模块全量切 v3 联调时,保险列表页整体 404。排查确认网关路由通、服务健康、Nacos 注册正常,真因是前端调用 GET /v3/admin/insurance/list,而后端原路径为 GET /v3/admin/insurance/orders,名称对不上。
本次将后端路径改为与前端对齐,不保留旧路径别名,旧路径 /orders 即时下线(再调返回 404)。
注意:/orders/{id}(详情)、/orders/by-order/{orderId}(按订单查)两个接口路径不变,本次仅修改列表接口。
---
## 2 变更清单
| # | 变更项 | 原来 | 现在 |
|---|--------|------|------|
| 1 | 接口路径 | GET /v3/admin/insurance/orders | GET /v3/admin/insurance/list |
| 2 | 旧路径状态 | 可用 | **已删除,调用返回 404** |
| 3 | 入参字段 | 无变化 | 无变化 |
| 4 | 出参字段 | 无变化 | 无变化 |
---
## 3 接口详情
| 项目 | 内容 |
|------|------|
| **方法 + 路径** | GET /v3/admin/insurance/list |
| **接口名** | 保险订单列表 |
| **认证** | 需要管理员 JWT Token(Header: Authorization: Bearer token) |
| **幂等性** | 查询接口,天然幂等 |
| **限流** | 无特殊限流,走网关全局限流 |
| **Content-Type** | Query String(无请求体) |
| **响应类型** | Result<PageResult<InsuranceOrderVO>> |
---
## 4 接口入参
### 4.1 Query 参数(全部可选,继承分页基类)
| 字段名 | 类型 | 必填 | 说明 | 示例 |
|--------|------|------|------|------|
| page | Integer | 否 | 页码,最小 1,默认 1 | 1 |
| pageSize | Integer | 否 | 每页条数,最小 1,最大 100,默认 20 | 20 |
| orderId | Long | 否 | 关联订单 ID | 1234567890 |
| policyNo | String | 否 | 保单号 | POL202605010001 |
| status | String | 否 | 保险状态,枚举值见第 6 节 | INSURED |
| insuredName | String | 否 | 被保人姓名(模糊匹配) | 张三 |
| insuranceProductId | Long | 否 | 保险产品 ID | 200 |
### 4.2 请求体
无(GET 接口,全部参数走 Query String)
---
## 5 出参字段
外层统一响应包装:
```json
{
"code": 200,
"msg": "success",
"data": {
"list": [ InsuranceOrderVO ],
"total": 100,
"page": 1,
"pageSize": 20
}
}
```
InsuranceOrderVO 字段明细:
| 字段名 | 类型 | 说明 |
|--------|------|------|
| insuranceOrderId | Long | 保险订单 ID |
| orderId | Long | 关联业务订单 ID |
| planId | Long | 保险计划 ID(指向 insurance_plan 表) |
| extOrderNo | String | 保游网订单号 |
| extPolicyNo | String | 保单号(保游网保单号),推荐使用此字段 |
| policyNo | String | 保单号(兼容字段,与 extPolicyNo 同值,后续版本将废弃,请改用 extPolicyNo) |
| productName | String | 保险产品名称 |
| planName | String | 保险计划名称 |
| policyHolderName | String | 投保人(投保主体公司名);列表页「投保人」列读此字段 |
| premium | BigDecimal | 保费金额(元) |
| totalPremium | BigDecimal | 保费金额(元),与 premium 同值,与详情 VO 字段名对齐 |
| insuredCount | Integer | 被保人数 |
| coverageStartDate | String(LocalDate) | 保障开始日期,格式 yyyy-MM-dd |
| coverageEndDate | String(LocalDate) | 保障结束日期,格式 yyyy-MM-dd |
| startDate | String(LocalDate) | 保障开始日期,与 coverageStartDate 同值,与详情 VO 字段名对齐 |
| endDate | String(LocalDate) | 保障结束日期,与 coverageEndDate 同值,与详情 VO 字段名对齐 |
| status | String | 保险状态枚举,见第 6 节 |
| statusLabel | String | 状态中文标签(如「已承保」) |
| policyPdfUrl | String / null | 保单 PDF 地址;INSURED 状态下异步回填,未回填或 OSS 未配置时为 null |
| source | String | 订单来源,见第 6 节 |
| bizType | String | 保单归属业务类型,见第 6 节 |
| bizId | String | 归属业务 ID(ORDER=订单 ID,DRIVER=司机 ID;雪花 ID 序列化为字符串防精度丢失) |
| createTime | String(LocalDateTime) | 投保时间,格式 yyyy-MM-dd HH:mm:ss |
---
## 6 枚举 / 数据字典
### 保险状态(status)
| 枚举值 | 中文标签 | 说明 |
|--------|----------|------|
| PENDING | 待投保 | 已创建,尚未发起投保 |
| INSURING | 投保中 | 已提交保游网,等待出单 |
| INSURED | 已投保 | 出单成功,保障生效 |
| CANCELLED | 已取消 | 已退保 |
| FAILED | 投保失败 | 投保流程异常 |
备注:入参 InsuranceQueryRequest.status 注解说明是 PENDING=待出单,出参 InsuranceOrderVO.status 注解说明是 PENDING=待投保,含义一致,「待出单」与「待投保」均指同一状态。
### 订单来源(source)
| 枚举值 | 说明 |
|--------|------|
| BAOYOU | 保游网出单 |
| MANUAL | 手工录入(司机年保档案联动) |
### 保单归属业务类型(bizType)
| 枚举值 | 说明 |
|--------|------|
| ORDER | 订单险(bizId = 订单 ID) |
| DRIVER | 司机险(bizId = 司机 ID) |
---
## 7 错误码
| HTTP 状态码 | code | 说明 | 触发场景 |
|-------------|------|------|---------|
| 200 | 200 | 成功 | 正常查询 |
| 400 | 400 | 参数校验失败 | page < 1 或 pageSize > 100 |
| **404** | **404** | **接口不存在** | **调用旧路径 GET /v3/admin/insurance/orders(已删除)** |
| 401 | 401 | 未认证 | JWT Token 缺失或过期 |
---
## 8 示例
### 8.1 典型成功示例
请求:
```
GET /v3/admin/insurance/list?page=1&pageSize=10&status=INSURED
Authorization: Bearer <admin-token>
```
响应:
```json
{
"code": 200,
"msg": "success",
"data": {
"list": [
{
"insuranceOrderId": "1934567890123456789",
"orderId": "1934567890000000001",
"planId": 10,
"extOrderNo": "BY2026060100001",
"extPolicyNo": "POL202606010001",
"policyNo": "POL202606010001",
"productName": "呼籁旅行意外险",
"planName": "标准计划",
"policyHolderName": "呼籁旅行有限公司",
"premium": 120.00,
"totalPremium": 120.00,
"insuredCount": 2,
"coverageStartDate": "2026-07-01",
"coverageEndDate": "2026-07-05",
"startDate": "2026-07-01",
"endDate": "2026-07-05",
"status": "INSURED",
"statusLabel": "已承保",
"policyPdfUrl": "https://oss.example.com/policy/POL202606010001.pdf",
"source": "BAOYOU",
"bizType": "ORDER",
"bizId": "1934567890000000001",
"createTime": "2026-06-01 10:30:00"
}
],
"total": 1,
"page": 1,
"pageSize": 10
}
}
```
### 8.2 边界情况示例(无匹配数据)
请求:
```
GET /v3/admin/insurance/list?page=1&pageSize=20&insuredName=不存在的人
Authorization: Bearer <admin-token>
```
响应:
```json
{
"code": 200,
"msg": "success",
"data": {
"list": [],
"total": 0,
"page": 1,
"pageSize": 20
}
}
```
### 8.3 业务失败示例——调旧路径返回 404
请求(旧路径,已下线):
```
GET /v3/admin/insurance/orders?page=1&pageSize=20
Authorization: Bearer <admin-token>
```
响应:
```json
{
"code": 404,
"msg": "No handler found for GET /v3/admin/insurance/orders",
"data": null
}
```
请务必将所有调用从 /orders 切换到 /list,旧路径无法回退,调用即 404。
---
## 9 业务边界
适用场景:
- 管理后台保险列表页分页查询
- 可按订单 ID、保单号、状态、被保人姓名、保险产品 ID 任意组合筛选
- 不传任何筛选条件时返回全量分页
不适用场景:
- 按订单 ID 获取该订单下所有保险单列表:使用 GET /v3/admin/insurance/orders/by-order/{orderId}(路径未变)
- 获取单条保险订单详情:使用 GET /v3/admin/insurance/orders/{id}(路径未变)
特殊边界:
- policyPdfUrl 在 INSURED 状态下异步回填,刚出单时可能为 null,前端需兼容 null 展示
- policyNo 为兼容字段,与 extPolicyNo 同值,后续将废弃,建议新代码统一改用 extPolicyNo
- premium 与 totalPremium 同值,与详情 VO 字段名对齐而保留双字段;coverageStartDate/startDate、coverageEndDate/endDate 同理
- bizId 为雪花 ID 序列化字符串(非 number),前端不要转 number(精度丢失)
---
## 10 修改前后对比
### 路径级对比
| 对比项 | 原来 | 现在 |
|--------|------|------|
| 列表接口路径 | GET /v3/admin/insurance/orders | GET /v3/admin/insurance/list |
| 旧路径是否可用 | 可用 | 不可用,返回 404 |
| 入参字段 | InsuranceQueryRequest | InsuranceQueryRequest(不变) |
| 出参字段 | InsuranceOrderVO | InsuranceOrderVO(不变) |
| 其他接口 | 不变 | 不变(详情、按订单查均未动) |
### 未改动接口(确认路径不变)
| 接口 | 路径 | 状态 |
|------|------|------|
| 保险订单详情 | GET /v3/admin/insurance/orders/{id} | 路径不变 |
| 按订单查保险列表 | GET /v3/admin/insurance/orders/by-order/{orderId} | 路径不变 |
---
## 11 影响评估 / 回滚
破坏兼容性:是。旧路径 GET /v3/admin/insurance/orders 调用即 404,无降级。
前端需要同步:是。将所有调用保险订单列表的请求 URL 从 /v3/admin/insurance/orders 改为 /v3/admin/insurance/list。
影响范围:
- 仅影响保险列表页的数据加载请求
- 详情页、按订单查保险等其他请求不受影响
回滚方案:
- 本次改动极小(仅 @GetMapping 注解值变更),如有问题可快速 revert PR #3682 重新部署
- 回滚后前端应切回旧路径 /v3/admin/insurance/orders
- 后端回滚与前端切换需同步进行,否则一端改完另一端未跟上仍会 404
---
## 12 注意事项
1. 立即切换路径:旧路径 GET /v3/admin/insurance/orders 已在 PR #3682 合并时同步删除,不存在过渡期,请尽快切换。
2. 仅列表路径变化:/orders/{id}(详情)和 /orders/by-order/{orderId}(按订单查)路径未变,不需要修改。
3. 字段无变化:入参 InsuranceQueryRequest 和出参 InsuranceOrderVO 的所有字段均未改动,切换路径后无需修改字段映射。
4. 双名字段:VO 中 policyNo/extPolicyNo、premium/totalPremium、coverageStartDate/startDate、coverageEndDate/endDate 均为同值双字段,新代码推荐使用后者(extPolicyNo、totalPremium、startDate、endDate),旧名称后续将废弃。
5. bizId 是字符串:雪花 ID 防精度丢失,不要用 JS Number 解析。
---
## 13 关联 / 联系人
| 项目 | 链接 / 内容 |
|------|------------|
| Issue | [#3681 保险订单列表接口 /orders 改名为 /list](https://git.1814.love:8443/wx/HL/issues/3681) |
| PR | [#3682 fix(order-v3/保险): 保险订单列表接口 /orders 改名为 /list](https://git.1814.love:8443/wx/HL/pulls/3682) |
| Merge Commit | [dc29cb08f](https://git.1814.love:8443/wx/HL/commit/dc29cb08fb6e127f7df375b174528046cdfe2efe) |
| 实现 Commit | [36b787692](https://git.1814.love:8443/wx/HL/commit/36b7876922caf9843b4c4911aa94a237a5fd9573) |
| 后端负责人 | 腰苏图 |
| 服务 | hl-order-service-v3(端口 8086) |
@@ -0,0 +1,30 @@
# 【后端·含前端需知】保险产品/计划/保障 VO 金额字段补转字符串(PR #3848 / 无工单)
> 端:含前端需知(保险产品配置相关接口金额字段类型)| 服务:hl-order-service-v3 | PR #3848 已合并 dev-v3 + 部署实测 | 2026-06-16
## ⚠️ 关键说明
承接 #3841(保险订单列表/详情 VO 的 premium/totalPremium 转字符串),本次**补齐保险 VO 包剩余 5 个金额字段**的字符串序列化,全包口径一致(与平台「金额一律 String」约定对齐,防大额精度丢失)。
## 前端需知:以下金额字段 数字 → 字符串
| VO / 端点 | 字段 | 含义 |
|-----------|------|------|
| InsuranceProductVO(`/v3/admin/insurance/products/{id}` 等) | `minPremium` / `maxPremium` | 最低/最高保费 |
| InsuranceProductVO.PlanItem(`/products/{id}/plans`) | `basePremium` | 基础保费(元/人/天) |
| InsuranceProductVO.RateItem | `premium` | 单人保费 |
| InsuranceCoverageVO | `coverageAmount` | 保额 |
前端如对这些字段做数值运算/严格类型比较,请按字符串处理。其余字段不变。
## 另:房车打回「懒清理」决策文档化(无行为改动,前端无关)
车务房务供应侧打回(rejectRequirement)的「不清理实配/不回置控单态、由重新提交时再同步」决策已在代码 javadoc 显式写明 + 核实安全(打回时无实配可清,控单态重提时统一重置)。纯文档,无接口/行为变化。
## 验证(测试服 2026-06-16)
```
order-v3 双实例 8086/8186 全新重启(09:01),业务端点 200 ✅
order-v3 113 测试全绿(InsuranceQueryServiceTest + RequirementServiceTest),未触碰 Flyway 迁移
序列化机制 #3841 已实测证实(premium→"10.80"),本次同一注解,行为一致
```
@@ -0,0 +1,42 @@
# 【后端内部·无前端影响】团期整团逐日配车/配房重配前置能力(PR #3862 #3863 / 工单 #3857 #3856)
> 端:纯后端内部(内部 Feign 端点 + 进程内事件,无前端接口)| 服务:hl-fleet-service + hl-order-service-v3 | PR #3862 #3863 已合并 dev-v3 + 双实例部署实测 | 2026-06-16
## ⚠️ 关键说明
订单调整 epic(#3643)剩余阶段 **G-2「团期改人数/资源后,整团逐日配车/配房实际重配」** 卡在 fleet/house 两个前置域缺口。本批补齐这两侧的**前置能力**(消费方 order-v3 core P-G 后续才接,本批无运行时触发点,**对前端零影响**)。
## 1. fleet 团期配车领域 + 整团逐日重配端点(PR #3862 / #3857)
fleet 此前是纯主数据服务,无任何派车/配车业务。本次从 0 建配车前置能力:
| 项 | 内容 |
|----|------|
| 新表 | `fleet_group_dispatch`(逐日派车:group_batch_id + trip_date + vehicle_id + driver_id + status + version,雪花 PK,软删,唯一索引含 deleted_at 支持软删重派)。Flyway `V20260616_002` |
| 新内部端点 | `POST /internal/fleet/dispatch/group-batch/reconfigure`(幂等):入参 groupBatchId + 逐日需求数组,出参 added/removed/kept/updated/aliveCount |
| 并发防护 | `@Idempotent` + `@Lock4j`(按 groupBatchId 串行)+ `@Version` 乐观锁 + 唯一索引兜底 |
| 差量语义 | 少补 / 多删软删留痕 / 同车换司机更新(不整团作废重配) |
> order-v3 侧 `FleetDispatchFeignClient` 对齐不在本批(由 order-v3 后续做)。内部端点走 Feign LB 不过网关,无网关路由变更。
## 2. house 团期整团逐日配房重配前置能力(PR #3863 / #3856)
house 域此前只有子订单(orderId)+逐日(dayNumber)粒度,无团期(groupBatchId)维度。本次补齐:
| 项 | 内容 |
|----|------|
| 新事件契约 | `GroupBatchBaselineChangedEvent`(进程内 Spring 事件,发布方 order-v3 core P-G 后续做) |
| 新监听器 | `HouseGroupBatchEventListener` AFTER_COMMIT 监听基准变更,失败只 log 不抛(降级) |
| 整团差量重配 | `reconcileGroupBatchAssignments(productBatchId, 新逐日需求)`:按 productBatchId 聚合子订单(剔已取消)、逐日按房数差量增减、减配拆行精确收敛 target 不过删、`@Lock4j` 按 productBatchId 串行 |
| ready 回填 | 新增 `GroupBatchService.markHotelReady`(跨域走 Service,house 不直写 groupbatch 表) |
> 无新增 Flyway(复用 `house_hotel_assignment` / `order_group_batch.hotel_ready`)。
## 验证(测试服 2026-06-16)
```
fleet 双实例 8087/8187 全新重启(11:25),flyway 20260616.002 success=1,fleet_group_dispatch 表已落库 ✅
order-v3 双实例 8086/8186 全新重启(11:22),新监听器/事件 bean 未致 context 失败 ✅
fleet 9 单测 + house 14 单测全绿;CR 两轮(含针对性复审)无 P0/P1
两侧均为前置能力,消费方未接,无运行时可触发行为可实测,boot 即闭环
```
@@ -0,0 +1,31 @@
# 【后端·需前端配合】司机软删联动作废其未消费续签 token + 续签「核对档案」需补「查不到档案」分支(PR #3868 / 工单 #3867)
> 端:后端行为修复 + **前端需配合**(H5 续签核对档案步)| 服务:hl-fleet-service | PR #3868 已合并 dev-v3 + 部署实测 | 2026-06-16
## ⚠️ 关键说明
修复「续签时查不到上赛季档案,却仍能进入下一步」。根因:续签 token 的目标司机被**软删**后,H5 init 的 `getRenewPrefill` 返 null(prefill 为空),但 token 仍 `tokenValid=true`、无任何「档案缺失」信号。
## 后端已做(行为变更)
司机被软删时(`DriverService.delete`),h5 域新增监听器联动**作废该司机所有未消费的续签 token**(mode=renew 且非 approved 非 voided)。作废后:
- H5 `init` 对该 token 返回 `tokenState=voided`
- H5 提交/校验(`validateToken`)抛 `LINK_VOIDED`(码 600304)
即:目标司机档案没了,续签链接自动失效。
## 前端需配合(mmg)
1. **现有失效处理已可兜底**:续签 token 被作废后 init 返 `tokenState=voided`,前端**现有的失效链接处理**会直接拦住「下一步」——这部分**无需新增代码**,只要确认续签流程也走 tokenState 失效判断即可。
2. **建议补「未查询到档案」友好分支**(可选增强):续签「核对档案」步当前写死「档案已由系统从上赛季自动同步」。建议增加判断——当 init 返回的续签预填 `prefill` 为空/缺失时,不显示「已同步」,改提示「未查询到您的档案,请联系车管重新生成链接」并禁用「下一步」,比通用「链接失效」更友好。
> 注:原型 `page_pending_h5.jsx` 续签「核对档案」步目前只有「已同步」单一状态,请一并在原型与真实 H5 补「档案缺失」分支。
## 验证(测试服 2026-06-16)
```
fleet 双实例 8087/8187 全新重启,Started 干净无 APPLICATION FAILED
27 单测全绿(作废/空操作/幂等/WrapperX 条件/监听器吞异常);CR CLEAN
域解耦:h5 监听器只操作 fleet_driver_pending,不碰 driver Mapper
```
@@ -0,0 +1,89 @@
# FLEET 接口契约审计修复(错误码补全 + 校验收紧 + 拉黑收口)— 修改接口 — 管理后台 / 司机端 H5
> 变更类型:⚠️ 部分行为收紧(含前端需配合的校验/调用方式变更)
> 端类型:管理后台(车务)+ 司机端 H5(OCR/入职)
> 日期:2026-06-16
> 服务:hl-fleet-service
> PR:https://git.1814.love:8443/wx/HL/pulls/3874
---
## 1. 背景
用接口契约语义审计工作流全量扫描车务(fleet)11 个 Controller,逐端点比对「Swagger `@ApiOperation` 声明的契约 ⨯ 实际实现 ⨯ 业务规则」,修复了 14 处「接口能跑但返回值/落库逻辑与契约不符」。其中**与前端对接相关**的列在下方。已部署测试服并实测通过(fleet 双实例健康、Flyway 迁移应用成功)。
绝大多数是**错误码补全**(实现真会抛、但 Swagger 之前漏列,前端按文档做错误处理时会落到「未知错误」兜底);另有几处**校验收紧 / 调用方式变更**,前端需配合。
---
## 2. 错误码补全(前端按 Swagger 对接错误处理时请补上这些业务码)
平台 HTTP 始终 200,业务码在 `Result.code`。以下错误码实现一直会抛,本次补进 Swagger notes:
| 接口 | 方法 | 路径 | 新增错误码 | 触发场景 |
|---|---|---|---|---|
| 删除车型型号 | DELETE | `/admin/fleet/vehicle-types/models/{modelId}` | **600107** | 型号已配置价格日历,禁删(请先清价格日历) |
| 编辑司机档案 | PUT | `/admin/fleet/drivers/{driverId}` | **600209** | 关联的保游网保单不存在/不属于该司机/状态不可关联 |
| 审核通过 | POST | `/admin/fleet/drivers/pending/{pendingId}/approve` | **605022** / **600404** / **600203** | 自带车常驻司机已被别车占用 / 续签目标司机为黑名单 / 续签改号撞他人手机号 |
| 批量改价格日历状态 | PUT | `/admin/fleet/pricing-calendar/{vehicleModelId}/status` | **600501** / **600502** | 日期范围非法 / 范围超 366 天 |
| 清除价格日历 | DELETE | `/admin/fleet/pricing-calendar/{vehicleModelId}` | **600502** | 范围超 366 天 |
| 司机险退保 | POST | `/admin/fleet/drivers/{driverId}/insurance/policies/{insuranceOrderId}/cancel` | **540224** | 手工录入的司机年保单禁退保,请在司机档案维护 |
| OCR 识别(H5) | POST | `/app/h5/driver-onboard/ocr/{step}` | **600303** / 600305 / 600306 / 600312 / 600313 | step 非法或证件识别失败 / 身份证 / 驾驶证 / 行驶证 识别失败 / 服务未就绪 |
> ⚠️ OCR 端点修正:原 Swagger 写「step 非法返回 **400**」是错的——实际返业务码 **600303**(HTTP 仍 200)。前端请按 `Result.code===600303` 判断,不要按 HTTP 400。
---
## 3. 行为变更(前端需配合)
### 3.1 编辑车型大类:typeKey 可不传(放宽,兼容性变更)
`PUT /admin/fleet/vehicle-types/{typeId}` 过去若不传 `typeKey` 会被必填校验打回 400;现已修正为**编辑时 typeKey 可不传(后端本就忽略不更新)**。前端编辑表单**不必再为过校验塞一个占位 typeKey**。新增(POST)仍必填 typeKey,不变。
### 3.2 车辆占用态 vehicleStatus:仅 maint 可人工设(收紧)
`POST/PUT /admin/fleet/vehicles` 的 `vehicleStatus` 过去前端可任意写 idle/busy/maint。占用态 `busy`/`idle` 是「按派单反算的缓存值」,**不允许前端手动设**。新规则:
| 操作 | 允许 | 拒绝(返 **600112** 占用态非法转移) |
|---|---|---|
| 新增 | 不传 / `idle` / `maint` | `busy` |
| 编辑 | 不传(保持原值)/ `idle↔maint`(送修、修好) | 设 `busy`;在用车(busy)被人工改 |
前端车辆表单:**只保留「送修(maint)/恢复(idle)」操作,去掉手动设 busy**;非法转移会收到 `600112`。
### 3.3 司机拉黑:收口到专用端点(收紧,调用方式变更)
`PUT /admin/fleet/drivers/{driverId}`(通用编辑)**不再支持** `season: active→blacklist`,传了会返 **100001**(赛季转移非法)。**拉黑必须走专用端点** `POST /admin/fleet/drivers/{driverId}/blacklist`(与解封走 `POST /unban` 同口径,二者均有幂等/锁保护)。前端拉黑入口请改调专用端点。
---
## 4. 其它
### 4.1 已发放链接导出 CSV:审核状态列中文化
`GET /admin/fleet/h5/tokens/export` 导出的 CSV「审核状态」列由英文码(pending/approved/rejected)改为中文(待审核/已通过/已驳回),与同表「类型」「状态」列一致。前端基本无感(导出文件给人看)。
### 4.2 生成入职链接:请前端做按钮防抖(无后端拦截)
`POST /admin/fleet/h5/token`(生成 token)**未加后端幂等**(因幂等键无法区分「双击」与「作废后合法重新生成/同司机多次邀请」)。**请前端在提交时做按钮 disable / loading 防抖**,避免车管双击落两条 pending 记录。
---
## 5. 前端 Action 清单
1. 补充第 2 节各端点的错误码文案/分支处理(尤其 OCR 的 `600303` 按业务码而非 HTTP 400 判断)。
2. 编辑车型大类表单:可不传 typeKey(去掉占位逻辑)。
3. 车辆表单:vehicleStatus 只保留「送修/恢复」(idle↔maint),去掉手动设 busy。
4. 司机拉黑入口:改调专用端点 `POST /drivers/{driverId}/blacklist`,通用编辑不要再传 `season=blacklist`。
5. 生成入职链接按钮:加防抖。
---
## 6. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3874(squash 合并 dev-v3,via api-contract-audit workflow) |
| 部署 | 已部署测试服并实测:fleet 4 端点网关 9443 + admin token 返 code:200;CSV 审核状态列实测为中文;Flyway V20260616_004(group_dispatch 软删唯一键加固)真库应用成功 |
| 本地测试 | mvn test 全绿(803 tests,含集成测试 H2 全链路) |
| 后端负责人 | wx |
@@ -0,0 +1,145 @@
# 产品服务接口契约审计修复(金额 String + 错误码补全 + 删除守卫 + 行程保障禁用端点)— 修改接口 — 管理后台 / 小程序
> 变更类型:⚠️ 部分行为收紧 + 1 个新增端点(含前端需配合的金额类型/校验/错误码变更)
> 端类型:管理后台(产品)+ 小程序(mp 产品/定制)
> 日期:2026-06-16
> 服务:hl-product-service-v2
> PR:https://git.1814.love:8443/wx/HL/pulls/3887
---
## ⚠️ 关键说明
用接口契约语义审计工作流全量扫描产品服务(hl-product-service-v2)全部 22 个 Controller,逐端点比对「Swagger `@ApiOperation` 声明的契约 ⨯ 实际实现 ⨯ 业务规则」,对抗复核实锤 **50 项**「接口能跑但返回值/落库逻辑与契约不符」并修复。已合并 dev-v3、部署测试服、网关 9443 + 真 admin token 实测金额字段已为 String、双实例健康、本地 1513 单测全绿。
下面只列**与前端对接相关**的变更。最影响前端的是第 1 节(金额字段统一为 JSON 字符串)和第 4 节(新增 1 个端点 + 校验收紧)。
---
## 1. 金额字段统一为 JSON 字符串(前端按字符串解析,影响面最广)
产品服务此前有 13 个响应 VO 的金额(BigDecimal)字段直接输出成 JSON 数字(如 `1980.00`),本次统一加 `@JsonSerialize(ToStringSerializer)`,改为输出**字符串**(如 `"1980.00"`),与平台其它服务及 mp 侧口径一致。
涉及端点(金额字段从 `number` → `string`):
| 端 | 端点 | 受影响金额字段 |
|---|---|---|
| admin | `GET /admin/product/item/{id}/schedule/list` | adultPrice/childPrice/toddlerDiscount/infantPrice/singleRoomDiff |
| admin | `GET /admin/product/item/{id}/pricing-calendar` | adultPrice/childPrice/toddlerDiscount/infantPrice |
| admin | `POST /admin/product/item/{id}/quote` | 全部单价/小计/总价/单房差等 |
| admin | `GET /admin/product/item/{id}/price-calendar` | adultSellPrice/childSellPrice/toddlerDiscount/infantPrice/singleRoomDiff |
| admin | `GET /admin/product/item/{id}/suggest-price` | adultPrice/childPrice/各项成本 |
| admin | `GET /admin/product/line/order-picker` | fromPrice |
| mp | `POST /mp/product/{id}/quote` | 全部金额字段 |
| mp | `GET /mp/product/{id}` | startPrice/depositAmount/档位 startPrice·depositAmount |
| mp | `GET /mp/product/{id}/schedules` | adultPrice/childPrice/toddlerDiscount/infantPrice |
| mp | `GET /mp/product/{id}/price-calendar` | adultPrice/childPrice |
| mp | `GET /mp/product-line/list`、`GET /mp/product-line/{lineId}/products` | startPrice |
| internal | `GET /internal/product/{productId}/group-quote`、`/internal/product/batch-brief` 等 | 报价金额字段 |
> 前端处理:金额一律按**字符串**接收(用于展示/`Number()`/`new Decimal()`)。绝大多数展示场景无感;若此前对金额字段做了数字运算,请改为先转数值。**里程(totalMileage/dailyMileage)等非金额字段不变,仍为数字。**
---
## 2. 错误码补全 + 规范化(前端按业务码做错误处理)
平台 HTTP 始终 200,业务码在 `Result.code`。以下为新增/规范化的业务错误码:
| 接口 | 方法 | 新增/变更错误码 | 触发场景 |
|---|---|---|---|
| 批量设置价格日历 | POST `/admin/product/item/{id}/price-calendar/batch` | **410110** | 档位序号不在产品已配置档位内(原来是通用 500,现为稳定业务码) |
| 温馨提示详情/编辑/删除 | `/admin/product/warm-tips/{tipsId}` | **440302** | 温馨提示不存在(原来是 404,现为业务码) |
| 删除服务标准模板 | DELETE `/admin/product/service-standard-template/{id}` | **440401** | 模板已被产品引用,禁止删除(见第 3 节) |
| 删除行程保障模板 | DELETE `/admin/travel-guarantee-template/{id}` | **440501** | 模板已被产品引用,禁止删除(见第 3 节) |
| 定制产品详情(mp) | `/internal/mp/product/custom-completed/{productId}` | **480304** | 定制产品不存在(原来是 404,现为业务码) |
| 创建/编辑产品线 | POST `/admin/product/line` | notes 补列 440103 / 430201 / 404 / 越权 | 装备模板不存在 / 管理员身份缺失 / 产品线不存在 / 无数据权限 |
| 删除预订条款 / 温馨提示 | DELETE `/admin/product/booking-terms/{id}`、`/warm-tips/{id}` | notes 补列 440201 / 440301 | 被产品引用时拒删(实现一直如此,本次补进文档) |
---
## 3. 删除模板引用守卫(收紧,新增拦截)
模板被产品引用时禁止删除(需先解绑),统一四类模板口径。预订条款 / 温馨提示此前已拦截;本次给**服务标准 / 行程保障**补上同样的守卫:
| 接口 | 被引用时返回 |
|---|---|
| DELETE `/admin/product/service-standard-template/{id}` | **440401**(该服务标准模板已被 N 个产品绑定,请先解除绑定再删除) |
| DELETE `/admin/travel-guarantee-template/{id}` | **440501**(该行程保障模板已被 N 个产品绑定,请先解除绑定再删除) |
> 前端处理:删除模板收到 440401/440501 时,提示用户「该模板已被 N 个产品绑定,请先解绑再删除」。
---
## 4. 行程保障模板:新增「启用/禁用」端点 + 保存校验收紧
### 4.1 新增端点(与温馨提示/预订条款一致)
```
PUT /admin/travel-guarantee-template/{id}/toggle?enabled=true|false
```
- 作用:启用/禁用行程保障模板。禁用后不再出现在产品设计的「启用下拉」(`listEnabled`,enabled=true 才返回)中。
- 此前行程保障模板缺禁用入口(启用态永远到不了),本次补齐。
- 请求示例:`PUT /admin/travel-guarantee-template/1001/toggle?enabled=false`,返回 `Result.success()`。
### 4.2 保存校验收紧
`POST /admin/travel-guarantee-template`:
- `items`(保障项列表)由「可空」改为**必填非空**(空数组会被拒绝)。
- 每个保障项的 `title`(标题)**必填非空**。
> 前端处理:行程保障模板表单提交前做非空校验(至少一个保障项 + 每项标题不空),避免后端 400。
---
## 5. 定制产品 C 端可见性收紧(mp)
`/internal/mp/product/custom-completed/{productId}`、`/custom-completed/batch`、`/custom-completed/all-page`(mp BFF 经 Feign 调用)此前未过滤状态,会把 DRAFT/待审核/已驳回等**未完成**定制产品也返回给 C 端。本次收紧为**仅返回 COMPLETED/ORDERED**(与定制产品 C 端可见性规则一致)。
> 前端影响:小程序定制产品浏览/详情页**不再出现未完成的定制产品**(此前是 bug)。
---
## 6. 其它前端相关
### 6.1 定制需求状态字典修正(mp)
`POST /mp/custom/submit`、`POST /mp/custom/{requestId}/cancel` 的 notes 状态字典此前写的是不存在的 `ACCEPTED/DESIGNING/QUOTED/COMPLETED`,与实际枚举对不上。实际状态字典为:
`PENDING(待处理) / PROCESSING(处理中) / REPLIED(已回复) / CONVERTED(已转化) / CANCELLED(已取消)`
取消可执行态为 **PENDING / PROCESSING**(此前 notes 误写 PENDING/ACCEPTED/DESIGNING)。
> 前端处理:定制需求状态码→中文映射按上面 5 个真实枚举值;「取消」按钮在 PENDING/PROCESSING 态可用。
### 6.2 班期「即将满额」状态已实现(mp)
`GET /mp/product/{id}/schedules` 的 `batchStatus` 此前字典里有 `NEARLY_FULL`(即将满额)但实现永不产出。本次实现:剩余名额 ≤ 容量 20% 时返回 `NEARLY_FULL`。前端可据此展示「即将满额」角标。
### 6.3 创建快照状态限制取消
`POST /admin/product/item/{productId}/snapshots` 此前 notes 称「仅 DRAFT/COMPLETED 可保存」,实际任意状态均可保存(同名/上限校验保留)。notes 已对齐实现。
---
## 7. 前端 Action 清单
1. **金额字段一律按字符串解析**(第 1 节),有数字运算的地方先转数值。
2. 补充第 2 节各业务错误码的文案/分支处理。
3. 删除服务标准/行程保障模板:处理 440401/440501「先解绑」提示(第 3 节)。
4. 行程保障模板:可接入新的启用/禁用端点 `PUT /{id}/toggle?enabled=`;保存表单加保障项/标题非空校验(第 4 节)。
5. 定制产品状态映射按真实枚举 PENDING/PROCESSING/REPLIED/CONVERTED/CANCELLED(第 6.1 节)。
6. 班期列表可展示「即将满额」(NEARLY_FULL) 态(第 6.2 节)。
---
## 8. 关联
| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3887(squash 合并 dev-v3,via api-contract-audit workflow) |
| 部署 | 已部署测试服并实测:product-v2 双实例健康;网关 9443 + admin token 调 `/admin/product/line/order-picker` 实测 `fromPrice` 已为字符串 `"3105.00"` |
| 本地测试 | mvn test 全绿(1513 tests,含 H2 集成测试) |
| 错误码段位 | 410110 / 440302 / 440401 / 440501 / 480304(预分配无撞号) |
| 后端负责人 | wx |
@@ -0,0 +1,36 @@
# 【漏洞修复+前端口径·管理后台】个人车失去常驻司机立即停用 + 司机「常驻车」展示口径
> 端:hl-ui 管理后台(车务)| 服务:hl-fleet-service | PR #3871 | 已合并 dev-v3 + 部署测试服 | 2026-06-16
## ⚠️ 关键说明
排查「司机/车 自有常驻 删除逻辑」时发现并修复一个生命周期漏洞,外加一条前端展示口径需对齐。
## 1. 个人车失去常驻司机 → 立即停用(后端修复,无接口变化)
**之前的漏洞**:删司机(或司机侧解绑/改绑常驻)后,车辆只清了常驻绑定、**没更新生命周期状态**。于是一台原本「在役 ACTIVE」的**个人车**失去常驻司机后停在 ACTIVE,而个人车又禁止手动启停,这台车的状态就卡死了。
**修复后**:个人车一旦失去常驻司机(删司机 / 解绑 / 改绑走掉 / 编辑清空常驻),`service_status` 自动置 **DISABLED(停用)**。
- 公司车不受影响(生命周期独立,可手动启停)。
- 个人车有常驻时仍随司机赛季联动(在册→ACTIVE,归档/拉黑→DISABLED)。
## 2. 司机「常驻车」展示请用 residentVehiclePlate(前端注意)
司机列表/详情接口返回两个车牌字段,含义不同,请用对:
| 字段 | 含义 | 建议 |
|---|---|---|
| `residentVehiclePlate` | **权威常驻车**(后端反查 fleet_vehicle.primary_driver_id 得到)| **「常驻车」请展示这个** |
| `primaryVehiclePlate` | 司机**自报参考车牌**(H5 填的,非权威绑定)| 仅作「自报参考」展示,或不展示 |
- `residentVehiclePlate` 是权威的:车一删/解绑,它**自动变空**,不会悬挂显示已删的车。
- `primaryVehiclePlate` 是司机自己填的文本参考,**不随车删除变化**(设计如此)。所以如果前端把它当「常驻车」显示,删了车后会看到一台不存在的车牌——这种地方请改用 `residentVehiclePlate`。
## 删除逻辑现状(顺带说明)
- **删司机**:软删司机 + 解绑其常驻车(车留下,个人车则按上面规则停用)+ 作废其年保台账/未消费续签 token。**不删车**。
- **删车**:软删车 + 释放常驻(清 primary_driver_id)。**不删司机**;司机的权威常驻(residentVehiclePlate)随之变空。
## 验证
- VehicleServiceTest +2(个人车解绑→DISABLED / 公司车不动),fleet 69 单测全绿;部署测试服双实例(14:48 新 jar)。
@@ -0,0 +1,36 @@
# 【行为打通·H5】司机入职「AI 自动识别」从假数据桩换成真阿里云 OCR(身份证/驾驶证/行驶证)
> 端:hl-ui H5(司机自助入职 → 拍证件 AI 识别)| 服务:hl-fleet-service h5 | PR #3854 / 工单 #2797 | 已合并 dev-v3 + 部署测试服 + 真图实测 | 2026-06-16
## ⚠️ 关键说明
司机入职 H5 的「拍证件 · AI 自动识别」`POST /app/h5/driver-onboard/ocr/{step}` 原来是**桩**——无论上传什么图,永远返回固定假数据(蒙A-12345 / 丰田汉兰达 / 150102199001011234)。现已接**真阿里云 OCR**,按上传的真实证件图识别。
**接口路径 / 入参 / 出参结构(OcrResultVO)完全不变**,前端无需改调用方式。变化只在「返回的是真识别值」。
## 1. 各步骤现在能识别到的字段(真图实测)
| step | 识别字段 | 实测(真图) |
|---|---|---|
| `id-card` 身份证 | name / idCard / gender / nation / issuedBy | 姓名/身份证号/性别(1男2女)/民族/签发机关 |
| `license` 驾驶证 | licenseNo / licenseClass / licenseExpire | 证号 / 准驾车型(如 C1D) / 有效期至 |
| `reg-cert` 行驶证 | plate / model | 车牌(京N99FF7) / 品牌型号(吉利美日牌MR7002BEV03) |
## 2. 识别不到、需用户手填的字段(前端注意)
- **行驶证 `annualInspectDate`(年检到期日)= null**:年检/检验记录在**行驶证副页**,正页识别接口不含此字段 → 该输入框请保持**可手填**,不要因 OCR 返 null 就当失败。
- **行驶证 `seats`(核定载客)= null**:行驶证正页不含核定载客(在副页),同样需手填。
- 其余识别到的字段建议**回填后仍允许用户修改**(OCR 偶有误差)。
## 3. 识别失败的表现(前端容错)
- 真识别失败(图太糊/非对应证件/服务波动)返回**业务错误码**:身份证 `600305` / 驾驶证 `600306` / 行驶证 `600312`,message=「xx识别失败,请重拍或手动填写」。
- 前端遇这些码:提示用户**重拍或手动填写**即可,**不要再用旧的假数据兜底**。
## 验证(测试服真图实测)
- 驾驶证真图 → `C1D` / 有效期 2021-01-12 ✅
- 行驶证真图 → 京N99FF7 / 吉利美日牌MR7002BEV03 ✅
- 身份证识别同样可用 ✅
> 注:测试环境阿里云「车辆物流识别」已开通(含驾驶证+行驶证识别)。正式环境上线前需在正式阿里云账号同样开通并配置,否则会回退到桩。
@@ -0,0 +1,26 @@
# 【前端待办·管理后台】司机列表「删除」按钮:后端接口已就绪,前端可放按钮
> 端:hl-ui 管理后台(车务 · 司机档案 · 司机列表卡片)| 服务:hl-fleet-service | 2026-06-16 | 无代码改动,纯能力告知
## ⚠️ 关键说明
司机列表卡片当前只有 **详情 / 派活 / 编辑 / 拉黑** 四个按钮,没有「删除」。后端**删除司机接口早已实现并在线**,前端可以放删除按钮直接调用。
## 接口契约
```
DELETE /admin/fleet/drivers/{driverId}
```
- **行为**:软删司机(不是物理删除);若该司机是 annual 年保司机,联动作废其 MANUAL 年保台账单;发域事件让车辆域解绑其常驻车(释放占位)。
- **返回**:`Result<Void>`,成功 `code=0`。
- **错误码**:`600205` 司机不存在。
## 前端建议
- 删除是危险操作,按钮建议**二次确认弹窗**(如「确认删除司机 张三?删除后不可恢复」)。
- 拉黑(`/blacklist`)与删除语义不同:拉黑是赛季状态流转、保留档案;删除是软删除整条档案。两个按钮可并存。
## 备注
- 后端尚有一条 TODO:派单模块落地后会补「该司机有未完成派单则拒删(600204)」的校验。当前阶段无此拦截,删除即生效。

某些文件未显示,因为此 diff 中更改的文件太多 显示更多