From 43d69d38d1a9229e141b43136f98702d55f5525a Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Sat, 20 Jun 2026 10:16:55 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E6=97=A9=E9=B8=9F?= =?UTF-8?q?=E4=BC=98=E6=83=A0=E8=AE=A1=E5=88=92=E7=AE=A1=E7=90=86=20CRUD?= =?UTF-8?q?=20=E6=8E=A5=E5=8F=A3=20changelog=EF=BC=88=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=EF=BC=8CPR=20#4076=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...鸟优惠计划管理CRUD接口-新增接口-管理后台.md | 339 ++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 changelogs-v2/2026-06/20_4076_早鸟优惠计划管理CRUD接口-新增接口-管理后台.md diff --git a/changelogs-v2/2026-06/20_4076_早鸟优惠计划管理CRUD接口-新增接口-管理后台.md b/changelogs-v2/2026-06/20_4076_早鸟优惠计划管理CRUD接口-新增接口-管理后台.md new file mode 100644 index 0000000..1f9f8c5 --- /dev/null +++ b/changelogs-v2/2026-06/20_4076_早鸟优惠计划管理CRUD接口-新增接口-管理后台.md @@ -0,0 +1,339 @@ +# 早鸟优惠计划管理 CRUD 接口(管理后台) + +- **端类型**:管理后台 +- **变更类型**:新增接口 +- **日期**:2026-06-20 +- **PR**:[#4076](https://git.1814.love:8443/wx/HL/pulls/4076) +- **负责人**:yst(腰苏图) + +--- + +## 接口背景 + +早鸟优惠(Early Bird Discount)是订单 v3 新增的优惠机制,允许管理员为指定产品配置日期区间 x 人数区间 x 折扣方式三维优惠计划。下单时系统自动匹配最优方案并应用优惠。 + +本次(PR #4076)新增管理后台侧 CRUD 6 个接口,供管理员对早鸟计划进行增删改查、启停操作。 + +--- + +## 变更清单 + +| # | 方法 | 路径 | 说明 | +|---|------|------|------| +| 1 | GET | /v3/admin/order/early-bird/list | 早鸟计划分页列表 | +| 2 | GET | /v3/admin/order/early-bird/{planId} | 早鸟计划详情 | +| 3 | POST | /v3/admin/order/early-bird | 创建早鸟计划 | +| 4 | PUT | /v3/admin/order/early-bird/{planId} | 修改早鸟计划(不影响已下单订单) | +| 5 | DELETE | /v3/admin/order/early-bird/{planId} | 删除早鸟计划 | +| 6 | PUT | /v3/admin/order/early-bird/{planId}/toggle | 启用 / 禁用早鸟计划 | + +全部为新增接口,无前版存量接口被替换。 +--- + +## 接口详情 + +| 项目 | 说明 | +|------|------| +| **认证** | 需要管理后台 JWT Token(Authorization: Bearer token) | +| **Base URL** | /v3/admin/order/early-bird | +| **幂等性** | POST 创建非幂等(同参数可重复创建多个计划);PUT 修改按 planId 幂等覆盖 | +| **限流** | 无独立限流规则,走全局网关限流 | +| **内容类型** | 请求体 Content-Type: application/json;GET 请求均为 Query 参数 | + +--- + +## 接口入参 + +### 4.1 GET /v3/admin/order/early-bird/list — 分页列表 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| pageNo | Integer | 是 | 页码,从 1 开始 | +| pageSize | Integer | 是 | 每页条数,建议 10 / 20 | + +### 4.2 GET /v3/admin/order/early-bird/{planId} — 详情 + +路径参数 planId(Long):早鸟计划 ID。 + +### 4.3 POST /v3/admin/order/early-bird — 创建 + +请求体(EarlyBirdPlanSaveReqVO): + +| 字段 | 类型 | 必填 | 校验规则 | 说明 | +|------|------|------|----------|------| +| planName | String | 是 | NotBlank | 计划名称 | +| remark | String | 否 | 无 | 优惠描述 | +| discountType | String | 否 | 枚举三选一 | 折扣方式,默认 AMOUNT_TOTAL(见枚举节) | +| discountAmount | BigDecimal | 条件必填 | AMOUNT_PER_PERSON 或 AMOUNT_TOTAL 时必填 | 优惠金额(元) | +| discountPercent | BigDecimal | 条件必填 | PERCENT 时必填,值区间 (0, 100) 开区间 | 折扣率,80=8折(非立减百分比) | +| priority | Integer | 否 | >=0,默认 0 | 优先级,同区间多命中时大者优先 | +| minPeople | Integer | 是 | >=1 | 最低适用人数(含) | +| maxPeople | Integer | 否 | >=1 且 >=minPeople | 最高适用人数(含),不填=不限 | +| startDate | LocalDate | 是 | yyyy-MM-dd | 生效开始日期 | +| endDate | LocalDate | 是 | yyyy-MM-dd,需 >=startDate | 生效结束日期 | +| productIds | List | 否 | 无 | 关联产品 ID 列表,空=不限产品 | +| applicableTravelerTypes | List | 否 | 枚举值见下 | 适用人群 code 列表,空=后端自动填充成人+儿童+小童(排婴儿) | + +### 4.4 PUT /v3/admin/order/early-bird/{planId} — 修改 + +路径参数 planId(Long)。请求体与 4.3 完全一致,全字段覆盖更新。修改不影响已下单订单中已匹配的早鸟优惠。 + +### 4.5 DELETE /v3/admin/order/early-bird/{planId} — 删除 + +路径参数 planId(Long)。无请求体。 + +### 4.6 PUT /v3/admin/order/early-bird/{planId}/toggle — 启用 / 禁用 + +| 参数 | 类型 | 位置 | 说明 | +|------|------|------|------| +| planId | Long | Path | 早鸟计划 ID | +| enabled | Boolean | Query | true=启用;false=禁用 | + +禁用后该计划不再参与下单时自动匹配。 +--- + +## 出参字段 + +所有接口返回 Result 包装,成功 code=200。列表接口返回 Result>,创建/详情返回 Result,修改/删除/toggle 返回 Result。 + +### EarlyBirdPlanVO 字段表 + +| 字段 | 类型 | 说明 | +|------|------|------| +| planId | Long(字符串序列化) | 计划 ID,雪花 ID,前端用字符串接收防精度丢失 | +| planName | String | 计划名称 | +| remark | String | 优惠描述,可为 null | +| discountType | String | 折扣方式枚举 code | +| discountAmount | BigDecimal | 优惠金额,PERCENT 类型时为 null | +| discountPercent | BigDecimal | 折扣率(0~100),非 PERCENT 时为 null;80=8折 | +| priority | Integer | 优先级 | +| minPeople | Integer | 最低适用人数(含) | +| maxPeople | Integer | 最高适用人数(含),null=不限 | +| peopleRangeText | String | 后端拼好的人数区间文案,如 3-5 人 / 3 人及以上 | +| discountText | String | 后端拼好的折扣说明,如 每人立减 100 元 / 整单立减 500 元 / 8 折优惠 | +| startDate | LocalDate(yyyy-MM-dd) | 生效开始日期 | +| endDate | LocalDate(yyyy-MM-dd) | 生效结束日期 | +| enabled | Boolean | 是否启用 | +| applicableTravelerTypes | List | 适用人群 code 列表;配置为空时后端回填 [ADULT, CHILD, YOUNG_CHILD] | +| applicableTravelerTypesText | String | 后端拼好的适用人群文案,如 成人/儿童/小童 | +| productIds | List | 关联产品 ID 列表,空=不限产品 | +| productNames | List | 关联产品名称,下标与 productIds 对齐;产品已删除时填 产品[ID]已删除 | +| products | List<{productId:Long, name:String}> | 关联产品结构化列表 | +| createTime | LocalDateTime | 创建时间 | +| updateTime | LocalDateTime | 最后更新时间 | + +--- + +## 枚举 / 数据字典 + +### discountType — 折扣方式 + +| code | 中文 | 计算说明 | +|------|------|----------| +| AMOUNT_PER_PERSON | 每人立减 | 优惠金额 = discountAmount x 计费人数 | +| AMOUNT_TOTAL | 整单立减(默认) | 优惠金额 = discountAmount | +| PERCENT | 按比例打折 | 优惠金额 = 总价 x (100 - discountPercent) / 100 | + +discountPercent 语义:值为折扣率,80 表示 8折,不是打 8 折的优惠百分比。立减额 = 总价 x (100 - 80) / 100 = 总价 x 0.2。 + +### applicableTravelerTypes — 适用人群 + +| code | 中文 | 人数匹配规则 | +|------|------|------------| +| ADULT | 成人 | 计入人数 | +| CHILD | 儿童 | 计入人数 | +| YOUNG_CHILD | 小童 | 计入人数 | +| BABY | 婴儿 | 默认不计入人数,需显式配置才计入 | + +人数匹配口径:命中方案的 applicableTravelerTypes 中包含哪几类,就统计哪几类的人数判断是否满足 minPeople/maxPeople 区间。默认配置排除婴儿。 + +--- + +## 错误码 + +早鸟模块错误码段位:581600 – 581699 + +| 错误码 | 说明 | 触发场景 | +|--------|------|----------| +| 581600 | 早鸟计划不存在 | planId 查不到对应记录 | +| 581601 | 早鸟计划已禁用 | 对已禁用计划执行不允许操作 | +| 581602 | 当前日期不在有效期内 | 当前日期早于 startDate 或晚于 endDate | +| 581603 | 人数不满足最低人数要求({0}) | 计费人数 < minPeople,{0} 为最低人数阈值 | +| 581604 | 人数超过最高人数限制({0}) | 计费人数 > maxPeople,{0} 为最高人数阈值 | +| 581605 | PERCENT 时折扣率不能为空 | discountType=PERCENT 但 discountPercent 未传 | +| 581606 | {0} 类型时优惠金额不能为空 | 立减类型但 discountAmount 未传,{0} 为类型名 | +| 581607 | 最高人数不能小于最低人数 | maxPeople < minPeople | +| 581608 | 结束日期不能早于开始日期 | endDate < startDate | +| 581609 | 适用人群包含非法取值:{0} | applicableTravelerTypes 有不在枚举范围的 code | +| 581610 | 产品已存在生效时间与人数区间重叠的早鸟计划,不能重复创建或启用 | 同产品同时间段同人数区间已有启用计划 | +--- + +## 示例 + +### 8.1 典型成功 — 创建早鸟计划(整单立减) + +POST /v3/admin/order/early-bird,Content-Type: application/json + +请求体: + + { + "planName": "暑期早鸟立减300", + "remark": "7月出发整单立减300元", + "discountType": "AMOUNT_TOTAL", + "discountAmount": 300, + "priority": 10, + "minPeople": 2, + "maxPeople": 6, + "startDate": "2026-07-01", + "endDate": "2026-07-31", + "productIds": [1900000000001, 1900000000002], + "applicableTravelerTypes": ["ADULT", "CHILD", "YOUNG_CHILD"] + } + +响应: + + { + "code": 200, + "msg": "success", + "data": { + "planId": "1920000000001234", + "planName": "暑期早鸟立减300", + "remark": "7月出发整单立减300元", + "discountType": "AMOUNT_TOTAL", + "discountAmount": 300.00, + "discountPercent": null, + "priority": 10, + "minPeople": 2, + "maxPeople": 6, + "peopleRangeText": "2-6 人", + "discountText": "整单立减 300 元", + "startDate": "2026-07-01", + "endDate": "2026-07-31", + "enabled": true, + "applicableTravelerTypes": ["ADULT", "CHILD", "YOUNG_CHILD"], + "applicableTravelerTypesText": "成人/儿童/小童", + "productIds": [1900000000001, 1900000000002], + "productNames": ["云南大理亲子7日游", "丽江雪山5日徒步"], + "products": [ + {"productId": 1900000000001, "name": "云南大理亲子7日游"}, + {"productId": 1900000000002, "name": "丽江雪山5日徒步"} + ], + "createTime": "2026-06-20T10:00:00", + "updateTime": "2026-06-20T10:00:00" + } + } + +### 8.2 边界情况 — 折扣率类计划(不限人数、不限产品) + +maxPeople 不传=不限;productIds 不传=不限产品;applicableTravelerTypes 不传=后端回填默认值。 + +请求体: + + { + "planName": "年底全产品9折", + "discountType": "PERCENT", + "discountPercent": 90, + "minPeople": 1, + "startDate": "2026-12-01", + "endDate": "2026-12-31" + } + +响应: + + { + "code": 200, + "msg": "success", + "data": { + "planId": "1920000000001235", + "planName": "年底全产品9折", + "remark": null, + "discountType": "PERCENT", + "discountAmount": null, + "discountPercent": 90.00, + "priority": 0, + "minPeople": 1, + "maxPeople": null, + "peopleRangeText": "1 人及以上", + "discountText": "9 折优惠", + "startDate": "2026-12-01", + "endDate": "2026-12-31", + "enabled": true, + "applicableTravelerTypes": ["ADULT", "CHILD", "YOUNG_CHILD"], + "applicableTravelerTypesText": "成人/儿童/小童", + "productIds": [], + "productNames": [], + "products": [], + "createTime": "2026-06-20T11:00:00", + "updateTime": "2026-06-20T11:00:00" + } + } + +### 8.3 业务失败 — 产品时间区间人数区间重叠(581610) + +该产品+时间段+人数区间已有另一启用计划。请求体: + + { + "planName": "冲突测试计划", + "discountType": "AMOUNT_TOTAL", + "discountAmount": 100, + "minPeople": 2, + "maxPeople": 5, + "startDate": "2026-07-01", + "endDate": "2026-07-15", + "productIds": [1900000000001] + } + +响应: + + { + "code": 581610, + "msg": "产品已存在生效时间与人数区间重叠的早鸟计划,不能重复创建或启用", + "data": null + } +--- + +## 业务边界 + +**适用场景**:管理员新建/修改/删除早鸟优惠配置;对已有计划快速启停;查询当前所有早鸟计划状态。 + +**不适用场景**:小程序用户侧查看早鸟优惠(走 internal Feign 接口);下单时自动匹配优惠(订单服务内部逻辑,前端无需干预);修改不追溯已下单订单中已应用的优惠金额。 + +**特殊边界**: + +- 同一产品在同一时间段+人数区间内只允许存在一个启用状态的计划(581610);禁用状态不参与冲突检测 +- discountPercent=80 表示 8折,不是优惠 80%;前端展示需转换为 X折格式 +- planId 为雪花 ID,JSON 已序列化为字符串,前端用字符串类型接收 +- applicableTravelerTypes 传空或不传,后端自动填充默认值 [ADULT, CHILD, YOUNG_CHILD] 并持久化 + +--- + +## 修改前后对比 + +新增接口,无前版对比。 + +--- + +## 影响评估 / 回滚 + +新增接口,不影响存量功能,无需回滚策略。如需下线,在网关层屏蔽 /v3/admin/order/early-bird 前缀即可。 + +--- + +## 注意事项 + +1. discountPercent 语义陷阱:80=8折,不是立减 80%。前端展示请转换为 X折,勿直接显示 80%。 +2. planId 雪花 ID 序列化:响应中已序列化为字符串;调用修改/删除/toggle 时路径参数直接传字符串即可。 +3. applicableTravelerTypes 回填:创建时不传或传空,后端自动填充默认值并持久化;详情/列表返回实际存储值(不再是空数组)。 +4. toggle 启用触发重叠校验(581610):将已禁用计划重新启用时,若同时间+人数区间已有其他启用计划,会拒绝启用。 +5. PUT 修改是全字段覆盖,不支持 PATCH 语义,未传的选填字段会被重置为 null/默认值。 +6. productNames/products 降级:关联产品已删除时,productNames 对应位置返回 产品[ID]已删除,前端按需降级处理。 + +--- + +## 关联 / 联系人 + +| 项目 | 内容 | +|------|------| +| PR | [#4076 早鸟优惠管理后台 CRUD](https://git.1814.love:8443/wx/HL/pulls/4076) | +| 后端负责人 | yst(腰苏图) | +| 变更服务 | hl-order-service-v3 |