文件
hl-api-changelog/changelogs-v2/2026-09/16_7770_团期列表补出团日期区间筛选与排序参数-修改接口-管理后台.md
2026-09-16 14:47:30 +08:00

12 KiB

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 7770 团期列表补出团日期区间筛选与排序参数 admin wx(GIT) 修改接口 deployed not_required verified mmg a9148fc9d13dedbccd2ad4f2a17b452172838efd 2026-09-16 GB-ADM-001 入参新增 departFrom / departTo / sortBy / sortOrder,均为可选;不传时行集与行序与改前逐条一致。出参不变。PR #7777 已合入 dev-v3(合并提交 791506985),已部署 TEST 并逐条取证。;前端 hl-admin a9148fc9 已实现:筛选条出团日期 daterange+排序 select 组合值拆分透传(空不落参),四参仅 001 透传 009 不带,显式排序月组跟随 records 首见序,checkpoint 全绿。 2026-09-16 dev-v3

团期列表补出团日期区间筛选与排序参数(修改接口)

服务: hl-order-service-v3 PR: #7777 Issue: #7770 日期: 2026-09-16 影响范围: 一个既有 GET 读接口的入参新增;出参不变、无新端点、无路由变化、无 DDL、无新增错误码


⚠️ 关键变化

🔵 纯新增可选入参,不传时行为与改前逐条一致。 团期列表此前只能按整月(month)筛出团日,搜索框里输日期搜不到;排序也写死。本次补上日期区间与排序两组参数。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 团期分页列表 GET /v3/admin/order/group-batch 修改接口 入参新增 departFrom、departTo、sortBy、sortOrder

三、接口详情

1. 团期分页列表 GET /v3/admin/order/group-batch

VO: GroupBatchListReqVO

使用场景

团期订单列表页的「期号 / 日期」搜索与列表排序。日期区间用于按出团日精确筛选,排序用于按出发日或报名截止日重排。

入参

字段 位置 类型 必填 约束 说明
departFrom query string 否 yyyy-MM-dd 新增。出团日区间起,含当日;非法串忽略该条件并记 warn,不报错
departTo query string 否 yyyy-MM-dd 新增。出团日区间止,含当日;口径同上
sortBy query string 否 departDate / enrollDeadline / createTime 新增。排序字段白名单,大小写不敏感;非白名单值回落默认排序并记 warn
sortOrder query string 否 asc / desc 新增。排序方向,大小写不敏感;缺省或非法值回落 asc

出参

字段 类型 说明
records array 出参结构本次无变化,逐字段沿用既有契约
total integer 命中总数,语义不变

请求示例

GET /v3/admin/order/group-batch?pageNo=1&pageSize=10&productId=2056947670512971778&departFrom=2026-12-01&departTo=2026-12-31&sortBy=departDate&sortOrder=asc
Authorization: Bearer <admin token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "groupBatchId": "2096495107078328322",
        "batchNo": "Q202612202096494989117677570",
        "batchLabel": "12",
        "departDate": "2026-12-20",
        "endDate": "2026-12-21",
        "batchStatus": "RESOURCE_PREPARING",
        "opsStage": "FORMED"
      }
    ],
    "total": 1,
    "page": 1,
    "pageSize": 10
  },
  "success": true
}

空数据 / 降级响应

区间与其他条件的交集为空时返回空列表,不报错。

{ "code": 200, "message": "成功", "data": { "records": [], "total": 0, "page": 1, "pageSize": 10 }, "success": true }

错误响应

{ "code": 401, "message": "Token无效或已过期", "data": null, "success": false }

非法日期串与非白名单排序字段不会产生错误响应,均按降级处理返回 200。

业务边界

  • departFrom / departTo 与 month 是两个独立条件,同时传取交集,互不覆盖。
  • 与 scope 同传是叠加(AND):scope=ONGOING 仍会把返团日已过的行剔掉,区间不会把它们捞回来。
  • 无出发日的行落不进任何区间,与 month 同口径。
  • 排序字段走枚举白名单,参数字符串不进 ORDER BY;排序结果按主键做次级排序,避免同值行跨页跳动。
  • 期号 batchLabel 不在白名单:它是字符串列,按字典序会把「第 10 期」排到「第 9 期」前;同产品内按 departDate 升序与期号升序等价。

四、契约约束与正确调用方式

  • 四个参数全部可选,不传即完全保持改前行为,前端可增量接入。
  • 想按日期搜索请用 departFrom / departTo,不要指望 keyword——它只模糊匹配班期编号与名称。
  • 要整月仍可继续用 month;与区间同传时请自行确认两者取交集后的预期。
  • 排序只认白名单三个值,传别的不会报错但会被忽略,前端不要据此做「排序失败」提示。

六、边界行为

  • 非法日期串(如 2026-13-45、abc):忽略该条件、记 warn、返回 200,行集等同于不传。
  • sortOrder 传非 asc/desc:回落 asc 并记 warn。
  • sortBy 传注入串:不命中白名单,回落默认排序,字符串不进 SQL。
  • 合并基底(productId 有值,内存分页)与 DB 基底(productId 缺省)两条路径的筛选与排序语义一致;未指定排序时分别保持既有的出发日升序与建团时间倒序。

六.6、修改前后对比

能力 改前 改后
按出团日筛选 只有 month,整月粒度 增加 departFrom / departTo 任意区间,与 month 取交集
排序 写死(合并基底出发日升序 / DB 基底建团时间倒序) 可传 sortBy + sortOrder,白名单三字段,未传时与改前一致
出参 — 无变化

六.7、影响评估

  • 前端:纯增量可选入参,不传无影响。
  • 后端:新增条件走既有 Wrapper 的 geIfPresent / leIfPresent,未引入新查询路径;排序由实体方法引用生成列名,无注入面。
  • 数据:无表变更、无 Flyway、无写链路。
  • 兼容性:无字段删除或改名,出参与错误码零变化。

七、不影响范围

  • 出参结构、分页语义、权限码、网关路由均未变化。
  • 团期详情 GB-ADM-002、统计条 GB-ADM-009、子订单列表 GB-ADM-003 未改动。
  • 既有入参 deadlineFrom / deadlineTo 的解析行为保持原样(非法值仍按既有方式处理),本次未一并调整。
  • 小程序端接口零影响。

八、测试环境已验证

部署:dev-v3 @ 791506985(本 PR #7777 的合并提交),2026-09-16 11:47:47~11:49:18 滚动部署双实例成功,task e68e54cd,exit_code=0。

验证环境:https://api.test.1814.love:9443(真实网关,admin token)+ TEST MySQL 直连对照。

对照口径说明:order_group_batch 裸表 198 行,其中 deleted_at IS NULL 为 132 行,与接口 scope=ALL 的 total=132 一致,故下列 SQL 对照均带软删过滤。

AC-1 departFrom / departTo 单独传,行集与 SQL COUNT 一致

区间 接口 total SELECT COUNT(*) … WHERE depart_date BETWEEN ? AND ? AND deleted_at IS NULL 结果
2026-12-01 ~ 2026-12-31 18 18 ✅
2026-12-10 ~ 2026-12-20 7 7 ✅
2027-03-01 ~ 2027-03-31 0 0 ✅

返回的 18 个 groupBatchId 全部存在于表中且未软删,departDate 全落在区间内(2026-12-01 ~ 2026-12-27)。

AC-2 与 month 取交集

组合 接口 total SQL 结果
month=2026-12 ∩ [2026-12-10, 2026-12-20] 7 7 ✅ 交集非空
month=2026-12 ∩ [2027-01-01, 2027-01-31] 0 0 ✅ 交集为空

(month=2026-12 单独为 18 行,区间单独为 7 行,交集 7 行——确为取交集而非互相覆盖。)

AC-3 与 scope 叠加(AND)

区间 [2026-09-01, 2027-01-31] 跨越今天:

scope total
ALL 128
ONGOING 122
FINISHED 6

ONGOING(122) + FINISHED(6) = 128 = ALL(128) ✅;且仅 scope=ONGOING 不带区间为 126 行,加区间后降为 122 行,证明区间是在 scope 之上再过滤而非覆盖 ✅

AC-4 非法日期串被忽略,返回 200 且行集等同于不传

departFrom code total 与不传(132)一致
2026-13-45 200 132 ✅
abc 200 132 ✅
2026/12/01 200 132 ✅

均未抛 400,服务端记 warn 后忽略该条件 ✅

AC-5 sortBy 白名单升降序

sortBy asc desc
departDate ✅ 30/30 非空且升序(首 2026-09-05) ✅ 降序(首 2027-04-15)
enrollDeadline ✅ 30/30 非空且升序(首 2026-09-04) ✅ 降序(首 2027-04-14)
createTime ✅ 见下 ✅ 见下

createTime 不在响应字段中,故翻页取满全部 132 行 groupBatchId 后回表查 create_time 验证:asc/desc 两侧回表命中 132/132、各自严格单调,行集相同且互为逆序,首尾对称(2026-08-18 18:56:01 ↔ 2026-09-16 10:21:35)✅

AC-6 非白名单 / 注入串回落默认排序,且不进 SQL

对 sortBy=depart_date; DROP TABLE order_group_batch 连打 5 次,同时以部署面板 SSE 日志流抓取 order-v3 primary 日志(该段 444 行,含 18 条 Preparing: SQL)。

服务端打出回落 WARN:

WARN c.h.o.groupbatch.helper.GroupBatchListSortResolver [traceId=210663af876044f8]
 - 团期列表排序字段不在白名单,回落默认排序: sortBy=depart_date; DROP TABLE order_group_batch

对应的团期列表 SQL 的排序子句为:

==> Preparing: SELECT group_batch_id,product_batch_id,product_id,… FROM order_group_batch
    WHERE deleted_at IS NULL ORDER BY create_time DESC LIMIT ?

注入串未出现在任何 Preparing: 行中(含 DROP TABLE 的日志行共 3 行,全部是上述 GroupBatchListSortResolver 的 WARN 日志,其中含 Preparing: 的 0 行、含 ORDER BY 的 0 行)。全流 ORDER BY 子句枚举均为合法列(create_time / traveler_id / flow_id / day_number / received_at 等),无一含注入串 ✅

batchLabel(非白名单)与 1=1 OR 同样回落默认排序、返回 200、total 132;注入串发出后 order_group_batch 仍为 198 行,表未受影响 ✅

AC-7 老调用兼容:不传任何新参数时行集与顺序逐条一致

对部署前后同一组请求比对 total 与 groupBatchId 序列:

用例 total(前→后) 行序逐条一致
GB001 productId+opsStage+scope 2 → 2 ✅ ✅
GB001 productId only 11 → 11 ✅ ✅
GB001 DB 基底 132 → 132 ✅ ✅
GB001 DB 基底 scope=ALL 132 → 132 ✅ ✅
GB001 DB 基底 第 2 页 132 → 132 ✅ ✅

5/5 行集与行序与改动前逐条一致 ✅

AC-8 / AC-9 单测与全量

  • 单测:GroupBatchListSortResolverTest 7 例(含注入串不命中白名单且比较器为 null)、GroupBatchMergedRowsServiceTest +5 例(两端含、与 month 交集、交集为空、与 scope 叠加、无出发日排除)、GroupBatchQueryServiceTest +2 例(区间透传 Mapper、非法日期串忽略不抛)。均为 JUnit5 + Mockito,未用 @SpringBootTest。
  • 全量:合并前在含 #7776 的最新 dev-v3 基底上重跑 Half A(com.hulalv.order.**):Tests run: 7524, Failures: 0, Errors: 0, Skipped: 0, BUILD SUCCESS,514 个测试类,0 次 OOM。例数自洽:7510(基底)+ 14(本单新增)= 7524。Half B(其余包)3888 / 0 / 0 / 7。

十、相关文档

  • 差异来源:需求分析/测试发现问题.md 模块 1
  • 原型出处:需求分析/2026-09-11-团期模块需求分析.md §1.2

关联 / 联系人

  • 后端:wx
  • 前端:mmg