文件
hl-api-changelog/changelogs/2026-04/2026-04-23_admin-unified-pricing-calendar.md

4.4 KiB

统一价格日历接口 /admin/product/item/{id}/pricing-calendar

日期: 2026-04-23 PR: #1290 (Closes #1286) 服务: hl-product-service-v2 类型: feat(新增接口,零破坏性)


背景

之前 admin 查价格日历需要分场景调两个不同接口:

  • CORE/CUSTOM → GET /admin/product/item/{id}/price-calendar
  • GROUP(小蒙马) → GET /admin/product/item/{id}/schedule/list

根因:GROUP 定价真相源是 group_tour_batch.adult_price(班期表),不走 product_price_calendar。前端要按 productType 分流调用。

本次新增统一入口,后端按 productType 聚合两种数据源,前端一个接口搞定。


新接口

GET /admin/product/item/{id}/pricing-calendar

Query 参数

  • month(可选):yyyy-MM,过滤月份。不传返全部
  • tierSeq(可选):档位序号,仅 CORE/CUSTOM 生效,GROUP 忽略

响应

{
  "code": 200,
  "data": {
    "productType": "CORE | GROUP | CUSTOM",
    "items": [
      { ... 统一条目 VO ... }
    ]
  }
}

统一条目 VO 字段表

字段 类型 CORE/CUSTOM GROUP
通用
date LocalDate 每日价格日 出发日(departureDate)
adultPrice BigDecimal adultSellPrice adultPrice
childPrice BigDecimal childSellPrice childPrice
toddlerDiscount BigDecimal ✅ ✅
infantPrice BigDecimal ✅ ✅
stock Integer dailyStock productStockLimit(无则 maxParticipants)
sold Integer sold enrolledCount
sellable Boolean dailyStock 空或 sold<stock batchStatus∈{ENROLLING,NEARLY_FULL}
CORE/CUSTOM 专属
id Long 日历记录主键 null
tierSeq Integer 档位序号 null
priceType String NORMAL/PEAK/HOLIDAY/SPECIAL null
rangeId Long 批量区间标识 null
GROUP 专属
batchId Long null 班期ID
batchNo String null 班期编号
batchName String null 班期名称
batchStatus String null ENROLLING/NEARLY_FULL/FULL/FINISHED/CANCELLING/CANCELLED
endDate LocalDate null 班期结束日
enrollmentDeadline LocalDate null 报名截止日
maxRooms Integer null 总房间数
bookedRooms Integer null 已预订房间数

前端渲染建议

const resp = await api.getUnifiedPricingCalendar(productId, { month, tierSeq });
switch (resp.data.productType) {
  case 'CORE':
  case 'CUSTOM':
    // 矩阵日历: 按 tierSeq × date 渲染档位 × 日期表格
    renderMatrixCalendar(resp.data.items);
    break;
  case 'GROUP':
    // 列表日历: 按出发日渲染班期卡片,显示 batchName/batchStatus/endDate
    renderBatchCalendar(resp.data.items);
    break;
}

示例

CORE 响应

{
  "productType": "CORE",
  "items": [
    {
      "date": "2026-05-01",
      "adultPrice": 1999.00,
      "childPrice": 999.00,
      "id": 1780000000000000001,
      "tierSeq": 1,
      "priceType": "NORMAL",
      "stock": 50,
      "sold": 10,
      "sellable": true,
      "batchId": null
    }
  ]
}

GROUP 响应

{
  "productType": "GROUP",
  "items": [
    {
      "date": "2026-07-06",
      "adultPrice": 4580.00,
      "childPrice": 2290.00,
      "batchId": 2043697199761584129,
      "batchNo": "Q202607062043697199757389826",
      "batchName": "7月暑期团",
      "batchStatus": "ENROLLING",
      "endDate": "2026-07-10",
      "stock": 25,
      "sold": 0,
      "sellable": true,
      "tierSeq": null,
      "priceType": null
    }
  ]
}

向后兼容

✅ 老接口保持不变:

  • GET /admin/product/item/{id}/price-calendar — 不动
  • GET /admin/product/item/{id}/schedule/list — 不动

前端可逐步迁移到新接口,无需一次性全量改造。


验证

测试服网关 7 场景全过:

  • CORE 全量 → 92 条 tierSeq/priceType 齐 ✅
  • GROUP 全量 → 4 条班期 batchId/batchStatus/endDate 齐 ✅
  • CUSTOM → 62 条走 CORE 分支 ✅
  • CORE/GROUP ?month=2026-05 → 正确过滤 ✅
  • CORE ?tierSeq=1 → 从 92 条过滤到 79 条 ✅
  • 老接口 /price-calendar → 92 条不变零回归 ✅

部署

测试服已部署: task a1ca3b50 success。 正式环境上线前无需任何 DDL,纯接口聚合。