From bf1788ae5eb0b63e1072d6f58ec1c62ec3cb471f Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Fri, 22 May 2026 18:20:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(order-v2):=20admin=20=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=88=97=E8=A1=A8+=E8=AF=A6=E6=83=85=E7=BB=BC=E5=90=88?= =?UTF-8?q?=E6=94=B9=E9=80=A0=20(=E6=90=9C=E7=B4=A2/=E6=8E=92=E5=BA=8F/?= =?UTF-8?q?=E8=A1=8C=E7=A8=8B/=E7=8A=B6=E6=80=81=20tab)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 覆盖今日 4 PR: - PR #2903 详情新增 itinerary (景点+酒店 按天) - PR #2906 列表 keyword 加联系电话 + 排序加 depositAmount - PR #2909 完整 11 位手机号精确加密匹配 (修 #2906 假阳性) - PR #2914 displayStatus 参数对齐原型 5 tab (修待出行 0 单 BUG) 前端动作: - 搜索框 placeholder 提示完整手机号 - 排序下拉新增"订金金额" - tab 切换迁到 displayStatus 参数 - 详情页"行程概览"段渲染 itinerary 字段 向后兼容: 不读新字段/不传新参数行为完全不变。 关联: Closes #2899 #2905 #2908 #2912 --- ...2_feat_admin_order_list_detail_overhaul.md | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 changelogs/2026-05/22_feat_admin_order_list_detail_overhaul.md diff --git a/changelogs/2026-05/22_feat_admin_order_list_detail_overhaul.md b/changelogs/2026-05/22_feat_admin_order_list_detail_overhaul.md new file mode 100644 index 0000000..67c590b --- /dev/null +++ b/changelogs/2026-05/22_feat_admin_order_list_detail_overhaul.md @@ -0,0 +1,225 @@ +# feat(order-v2): /admin/order/list + /admin/order/{id} 综合改造(搜索 / 排序 / 详情行程 / 状态 tab) + +> **仓库**: HL (后端 hl-order-service-v2) +> **关联 PR/Issue**: PR #2903 / #2906 / #2909 / #2914(Closes #2899 #2905 #2908 #2912) +> **日期**: 2026-05-22 +> **影响范围**: 管理后台「订单管理」列表 + 详情 +> **接收方**: mmg (前端) +> **前端**: **需要改动 — 搜索框 placeholder / 排序下拉新增订金 / tab 切换迁到 displayStatus / 详情页渲染行程概览** + +--- + +## 🚨 关键变化总览 + +| 维度 | 改动 | 前端动作 | +|---|---|---| +| 搜索 keyword | 现支持 **完整 11 位手机号精确匹配**(加密列等值),姓名/订单号/产品名仍 LIKE | placeholder 加"完整手机号" | +| 列表排序 | 新增 `depositAmount`(订金金额)排序 | 排序下拉加"订金金额"选项 | +| 列表 tab 筛选 | 新增 `displayStatus` 参数,**原型 5 tab 必须用这个**(status 是内部细粒度,对不上 tab) | tab 切换的 status 参数改名为 `displayStatus` | +| 订单详情 | 新增 `itinerary` 字段(行程按天结构化,含景点 + 酒店) | 详情页"行程概览"段渲染 | + +--- + +## 一、`GET /admin/order/list` 搜索框(keyword) + +### 改前 + +`keyword` 对 4 字段做 LIKE 模糊匹配:`orderNo` / `contactName` / `productName`(联系电话 LIKE 是一次预备改造,对加密列实际无效)。 + +### 改后 + +| 输入 | 行为 | +|---|---| +| 完整 11 位手机号(如 `17600545225`) | **后端加密后等值匹配 contact_phone 密文列** → 精确命中所有持此号订单 | +| 部分手机号(如 `176`、`5225`) | 不识别为手机号,不查 contact_phone(部分号匹不到加密订单是天然限制) | +| 姓名(`米明光`) | 仍 LIKE 模糊匹配 contact_name | +| 订单号(`HL20260509`) | 仍 LIKE 模糊匹配 order_no | +| 产品名(`冻干粉`) | 仍 LIKE 模糊匹配 product_name | +| 不传 / 空 | 不过滤(行为不变) | + +### 前端建议 + +搜索框 placeholder 改为类似: + +``` +姓名 / 完整手机号 / 订单号 / 产品名 +``` + +不要再写"手机号"模糊(部分手机号匹不到,会误导用户)。 + +--- + +## 二、`GET /admin/order/list` 排序(sortField) + +### 改后枚举 + +| sortField | sortOrder | 含义 | +|---|---|---| +| `createTime` | desc(默认) / asc | 创建时间 | +| `departureDate` | desc / asc | 出发日期 | +| `totalPrice` | desc / asc | 订单金额 | +| `depositAmount` ⭐ | desc / asc | **订金金额(新增)** | +| 不传 / 未知值 | — | 兜底按 createTime DESC | + +### 前端建议 + +排序下拉选项追加"订金金额(高→低)/(低→高)",业务场景是财务对账(找订金大但未付尾款的订单优先催)。 + +--- + +## 三、`GET /admin/order/list` 订单 tab 筛选 ⚠️ 重要 + +### 改前 + +只有 `status` 参数(匹配内部 `OrderStatus` 枚举 11 状态)。**原型"待出行" tab 传 `status=PENDING_DEPARTURE` 命中 0 单**(数据库实际分散在 DEPOSIT_PAID / CONFIRMED 等状态)。 + +### 改后 + +新增 `displayStatus` 参数,与 `status` 并存(AND 联合)。**原型 5 tab 必须用 `displayStatus`**: + +| 原型 Tab | 前端传 `displayStatus` 值 | 后端命中范围 | +|---|---|---| +| 全部 | (不传) | 所有未删除订单 | +| 待支付 | `PENDING_PAY` | 内部 status = PENDING_PAY | +| **待出行** | `PENDING_DEPARTURE` | **折叠** DEPOSIT_PAID / PAID / CONFIRMED / PENDING_BALANCE / PENDING_DEPARTURE 5 个内部状态 | +| 待评价 | `PENDING_REVIEW` | (状态机决定) | +| 已完成 | `COMPLETED` | 内部 status = COMPLETED(且已评价) | +| 售后中 | `AFTER_SALE` | **折叠** REFUNDING / 部分 REFUNDED | +| 已取消 | `CANCELLED` | **折叠** CANCELLED / 部分 REFUNDED | + +### 前端动作 + +按 tab 切换的参数从 `status` 改为 `displayStatus`。两个值的枚举不一样,**千万不要混用** —— 把内部 `status=PENDING_DEPARTURE` 当成 tab 传过去会拿到 0 单。 + +### 测试服实测对照 + +| 请求 | 命中 | +|---|---| +| `?displayStatus=PENDING_DEPARTURE` | **8 单** ⭐ | +| `?displayStatus=CANCELLED` | 26 单 | +| `?displayStatus=AFTER_SALE` | 2 单 | +| `?status=PENDING_DEPARTURE`(错用法) | 0 单 ❌ | + +--- + +## 四、`GET /admin/order/{orderId}` 详情新增 `itinerary` 字段 + +### 字段结构 + +`OrderDetailVO` 新增: + +```typescript +itinerary: OrderItineraryDayVO[] // 全部天数,不截断 + +OrderItineraryDayVO { + dayNumber: number // 1, 2, 3... + dayTitle: string // "京都·古都漫步" + route: string // "大阪 → 京都" + attractions: ItineraryAttractionVO[] // 当天 SCENIC + ACTIVITY 节点 + hotels: ItineraryHotelVO[] // 当天酒店(已按订单档位 tierSeq 过滤) +} + +ItineraryAttractionVO { + resourceId: string // Long 序列化为字符串 + name: string // "清水寺" + nodeType: 'SCENIC' | 'ACTIVITY' + startTime: string | null // "09:30" + durationMinutes: number | null + description: string | null + coverImageUrl: string | null +} + +ItineraryHotelVO { + hotelId: string + hotelName: string // "京都八坂町京町家" + roomTypeName: string // "豪华双床房" +} +``` + +### 注意点 + +- **数据来源是订单下单时固化的产品快照**,不会随产品变化 +- 老订单(快照 key 是 `itineraryDays`)也兼容解析 +- 快照损坏时 `itinerary` 返回空数组(不会让整个详情接口挂) +- `hotels` 已经按订单 `tierSeq` 过滤 —— 不要担心一天显示 3 档候选酒店 + +### 真实示例(订单 `HL20260509114457-6539`) + +```json +{ + "itinerary": [ + { + "dayNumber": 1, + "dayTitle": "京都古都漫步", + "route": "海拉尔区 → 额尔古纳市", + "attractions": [ + { + "name": "中俄边境公路(卡线)", + "nodeType": "SCENIC", + "description": "沿额尔古纳河蜿蜒前行约200公里...", + "coverImageUrl": "https://hlgl-test.oss.../62943d9b....jpg" + }, + { + "name": "驯鹿拉车体验", + "nodeType": "ACTIVITY", + "description": "..." + } + // ... 一天可能 6-7 个节点 + ], + "hotels": [ + { "hotelName": "呼伦贝尔香格里拉大酒店", "roomTypeName": "普通标间" } + ] + } + // ... 多天行程 + ] +} +``` + +### 前端建议 + +详情页"行程概览"段: +- 按 `dayNumber` 排序,渲染 D1 / D2 / D3... +- 每天先 `route` + `dayTitle`,下面 `attractions` 列表 + `hotels` 列表(末日可能 `hotels` 为空,正常) +- `attractions` 可按 `nodeType` 分组("景点 SCENIC" / "活动 ACTIVITY"),也可不分组直接列 +- `coverImageUrl` 是 OSS 完整 URL 可直接 `` + +--- + +## 五、向后兼容 + +| 老前端不传新参数 / 不读新字段 | 行为 | +|---|---| +| 仅用 `status`(不用 `displayStatus`) | 完全不变(仍按内部状态 eq) | +| 不读 `itinerary` | 完全不变(多了字段不影响其他) | +| 不传 `sortField=depositAmount` | 完全不变 | +| keyword 输部分手机号 | 不影响其他字段 LIKE 命中(只是不再误命中加密列的明文残留) | + +--- + +## 六、错误码 / 异常 + +无新增错误码。所有改动都是请求参数扩展或响应字段新增。 + +--- + +## 七、测试建议(前端联调时验证) + +| 验证项 | 操作 | 期望 | +|---|---|---| +| 完整手机号搜 | 搜 `17600545225` | 精确命中(如有该号订单) | +| 部分号搜 | 搜 `176` | 不命中加密订单(只命中订单号/姓名/产品名含 "176" 的) | +| 订金排序 | sortField=depositAmount&sortOrder=desc | 单调递减 | +| 待出行 tab | displayStatus=PENDING_DEPARTURE | 应命中(测试服 8 单) | +| 详情行程 | 打开任一已下单订单详情 | itinerary 非空数组 | +| 不传新参数 | 老接口调用方式 | 行为完全不变 | + +--- + +## 八、关联 + +- PR #2903(itinerary)→ commit `c8f34411a` +- PR #2906(搜索+排序)→ commit `689d47013` +- PR #2909(手机号精确匹配,修 #2906 假阳性)→ commit `fbf803b1b` +- PR #2914(displayStatus 修待出行 tab)→ commit `8be30a562c` +- Issue #2899 / #2905 / #2908 / #2912 已全部 closed +- 负责人:yst(后端)