# 早鸟优惠多档 + 订单级立减（小程序产品详情）

**日期**：2026-04-20
**PR**：无（纯文档更正，代码语义一直是订单立减）
**影响**：小程序产品详情页 早鸟展示

---

## 核心结论（给前端的一句话）

`/mp/product/detail` 的 `earlyBirdLadder` 字段**已经支持「一个产品多档早鸟」**，每档的折扣语义是**订单总立减**（不是每人减），可以直接按阶梯画。

---

## 业务语义（最重要）

早鸟优惠 = **订单总立减固定金额**，**不是**每人立减。

### 举例

- 满 3 人订单立减 **300 元**（订单总价减 300，不论 3 人还是 30 人）
- 满 4 人订单立减 **500 元**

这在 `earlyBirdLadder` 里是**两个 item**，前端按 `minPeople` 升序画阶梯：

```jsonc
// GET /mp/product/detail?productId=xxx
{
  "earlyBirdTip": "最低订单总价优惠 300 元（共 2 档早鸟方案）",   // 概览，首屏标签用
  "earlyBirdLadder": [
    {
      "planId": 1001,
      "planName": "满3人早鸟",
      "minPeople": 3,
      "maxPeople": 3,                       // 档位上限（含），下一档 4 人以上不归它管
      "peopleRangeText": "3 人",
      "discountText": "满 3 人订单总价优惠 300 元",   // ⭐ 订单级立减
      "startDate": "2026-04-01",
      "endDate": "2026-12-31"
    },
    {
      "planId": 1002,
      "planName": "满4人早鸟",
      "minPeople": 4,
      "maxPeople": null,                    // null = 不限上限
      "peopleRangeText": "4 人及以上",
      "discountText": "满 4 人订单总价优惠 500 元",
      "startDate": "2026-04-01",
      "endDate": "2026-12-31"
    }
  ]
}
```

## 字段清单

| 字段 | 类型 | 说明 |
|---|---|---|
| `earlyBirdTip` | `String` | 概览文案（无人数上下文），无绑定返 `null` |
| `earlyBirdLadder` | `List<EarlyBirdLadderItem>` | 阶梯数组，按 `minPeople` 升序，无绑定返 `[]` |
| `earlyBirdLadder[].planId` | `Long` | 早鸟计划 ID |
| `earlyBirdLadder[].planName` | `String` | 计划名（管理端命名，展示可选） |
| `earlyBirdLadder[].minPeople` | `Integer` | 最低人数（含）|
| `earlyBirdLadder[].maxPeople` | `Integer\|null` | 最高人数（含），null 表示不限 |
| `earlyBirdLadder[].peopleRangeText` | `String` | 人数区间文案，如 "3-5 人" / "4 人及以上" |
| `earlyBirdLadder[].discountText` | `String` | **订单总立减**文案，如 "满 3 人订单总价优惠 300 元" |
| `earlyBirdLadder[].startDate` | `LocalDate` | 下单日期窗口起 |
| `earlyBirdLadder[].endDate` | `LocalDate` | 下单日期窗口止 |

## 前端展示建议

### 产品详情 —— 早鸟阶梯卡片

```
🐦 早鸟优惠                   最低订单总价优惠 300 元
┌─────────────────────────────────┐
│ 3 人                -300 元     │   ← earlyBirdLadder[0]
│ 4 人及以上          -500 元     │   ← earlyBirdLadder[1]
└─────────────────────────────────┘
生效：2026-04-01 至 2026-12-31
```

- 用 `peopleRangeText` + `discountText` 拼行
- 如果只想展示金额不展示文案，从 `discountText` 里正则抽数字即可，但直接用 `discountText` 最稳（后端拼好的）

### 下单前匹配

- 下单时按选中人数 `n`，在 `earlyBirdLadder` 里找第一个满足 `minPeople ≤ n ≤ (maxPeople ?? ∞)` 的 item
- 展示"预计优惠 X 元"给用户，X 直接取这一档的金额（不再乘人数）
- 最终折扣以后端订单接口返回的 `OrderDiscount` 为准（前端只做预估展示）

## 不是（防误读）

- ❌ 不是"每人立减 X 元"—— 之前 Entity 注释里 `"优惠金额（元/人）"` 是过期文档，实际金额计算在 `OrderFinanceService.tryApplyEarlyBirdDiscount` 里**没有乘人数**
- ❌ 不是"订单总价按折扣比例打折"—— 是固定金额直减
- ❌ 不是"每个人都减 X 元"—— 订单总价减一次 X 元

## 单选 / 多档的关系

- 一个产品可以绑定**多个**早鸟计划（通过 `product_early_bird_plan` 关联表）
- 每个计划一档，前端合并展示成阶梯
- 运营侧在管理端配置：每档的 `minPeople` + `discountAmount` + 生效日期

## 已知注释问题（后端会修，不影响接口）

- `EarlyBirdPlan.java:25` 注释 "元/人" 会改成 "订单总立减金额（元）"
- `EarlyBirdPlanDTO.java:25` 注释会明确 "订单优惠金额"
- `EarlyBirdLadderItemDTO.java:31` 示例会从 "每人立减 100 元" 改为 "订单总价优惠 300 元"

前端**不用等这个 PR**，接口响应结构不变，语义本来就是订单立减。
