hl-api-changelog/changelogs/2026-04/2026-04-18-product-price-calendar-frontend-bug.md

8.7 KiB

前端 Bug 通知 — Step4 定价管理 新增价格区间不回显(前端只刷当前月)

  • 日期: 2026-04-18
  • 类型: 前端 Bug 修复指南(不涉及后端代码改动,后端无需重启
  • 涉及端: 管理后台 hl-ui产品编辑页 Step4 定价管理)
  • 后端服务: hl-product-service-v2后端已核实数据完全正确,无需改动
  • 优先级: P2
  • 关联任务: backend 仓库 docs/tasks/20260418_修复_产品定价新增价格区间不回显.md

一、问题描述

在产品编辑页 Step4「定价管理」tab 中:

  • 预期:在已有 2026-04 平日价区间的情况下,新增一段不同月份(如 2026-05-07 → 2026-05-17的价格区间,点"确认添加"后列表应立即回显新增区间
  • 实际:点"确认添加"后列表只显示原来 4 月那一条,新增的 5 月区间没有出现,看起来"加不上"

复现路径

  • 环境:测试服 192.168.100.160
  • 产品 ID2045345825172639746(游牧的森林-短途版,CORE 草稿)
  • 页面:产品编辑 → Step4 定价管理 → 选"轻奢"档位 tab
  • 前置:已有 2026-04-01 → 2026-04-30 平日价(成人 ¥4105 / 儿童 ¥1865
  • 操作:点 +添加区间 → 填 2026-05-07 → 2026-05-17 / 平日 / 轻奢 / 成人 ¥4725 / 儿童 ¥1725 → 确认添加
  • 结果:列表里看不到新加的 5 月区间

二、根因分析(后端已实证核实)

1. 后端 POST 已成功写入 DB实证 1服务日志

测试环境 hl-product-service-v2 日志(/opt/hulalv/logs/services/hl-product-service-v2/hl-product-service-v2-8083.log

12:40:40 价格日历批量设置成功, productId=2045345825172639746, 日期范围=2026-05-02-2026-05-22, 记录数=21
12:41:17 价格日历批量设置成功, productId=2045345825172639746, 日期范围=2026-05-09-2026-05-10, 记录数=2

后端全程零 ERROR / 零 WARN,所有 batch 写入返回 200 成功。

2. DB 真实有 5 月数据(实证 2数据库

hl_product_service.product_price_calendar 表实际记录:

range_id 月份 tier_seq 日期范围 成人/儿童 条数 deleted_at
2045361705738719233 2026-04 1 4/1-4/30 4105/1865 30 NULL
2045361802451058689 2026-04 2 4/1-4/30 7777/1000 30 NULL
2045361847678160898 2026-05 2 5/2-5/22 4865/1865 21 NULL
2045362006457733121 2026-05 1 5/9-5/10 4695/1695 2 NULL

5 月数据真实存在、未被软删。

3. 前端只 GET 当前月份(实证 3网关访问日志

hl-gateway-8080.log 关键序列(保存 5 月区间前后):

12:40:40.125 POST .../price-calendar/batch         ← 写入 5/2-5/22  ✓
12:40:40.379 GET  .../price-calendar?month=2026-04 ← 刷新只查 4 月 ❌
12:41:17.981 POST .../price-calendar/batch         ← 写入 5/9-5/10  ✓
12:41:18.239 GET  .../price-calendar?month=2026-04 ← 刷新只查 4 月 ❌

整个会话前端从未发起 month=2026-05 的 GET 请求 → 后端有数据但前端从不拉取。

真因

前端 Step4 定价管理「保存价格区间」的成功回调里,只刷新当前选中月份的数据。当用户新增的区间落在当前选中月之外的月份(包括跨月、纯异月)时:

  • POST batch 已正确入库
  • 但 GET 只请求当前月,新月份的数据不在响应里
  • 列表自然回显不出来

非后端 bug,纯前端刷新策略问题


三、涉及接口契约(不变,仅供前端 AI 自包含参考)

1. 批量保存价格区间

方法 POST
路径 /admin/product/item/{productId}/price-calendar/batch
鉴权 管理后台 token

Request Body(关键字段):

字段 类型 必填 说明
startDate string yyyy-MM-dd 区间起始日
endDate string yyyy-MM-dd 区间结束日
tierSeq int 档位序号1=经济 / 2=舒适 / 3=轻奢 / 4=高端 / 5=豪华)
priceType string WEEKDAY 平日 / WEEKEND 周末 / HOLIDAY 节假日
adultSellPrice decimal(12,2) 成人售价
childSellPrice decimal(12,2) 儿童售价
subChildDiscount decimal(12,2) 小童优惠额
infantPrice decimal(12,2) 幼童价
dailyStock int 每日库存

Response

{
  "code": 200,
  "data": {
    "rangeId": 2045361847678160898,
    "recordCount": 21
  }
}

关键:响应里返回的 rangeId 可用于精确识别本次落库的区间,便于前端定位需要刷新哪些月。

2. 按月查询价格日历

方法 GET
路径 /admin/product/item/{productId}/price-calendar?month=yyyy-MM

按月返回该月全部档位所有日期的明细(不按 tierSeq 过滤)。

Response

{
  "code": 200,
  "data": [
    {
      "date": "2026-05-07",
      "tierSeq": 3,
      "rangeId": 2045361847678160898,
      "priceType": "WEEKDAY",
      "adultSellPrice": 4725.00,
      "childSellPrice": 1725.00,
      "subChildDiscount": null,
      "infantPrice": null,
      "dailyStock": null
    }
  ]
}

四、前端修复建议(任选其一)

方案 A最小改动,推荐

保存成功后,根据本次保存的区间起止日期,计算覆盖的月份集合(同月 1 个,跨月 N 个),逐月 GET 并 merge 到本地状态。

伪代码:

async function onBatchSaved(payload) {
  // payload 是刚提交的请求体:{ startDate, endDate, tierSeq, ... }
  const startMonth = payload.startDate.slice(0, 7); // "2026-05"
  const endMonth   = payload.endDate.slice(0, 7);   // "2026-05"
  const months = enumerateMonths(startMonth, endMonth); // ["2026-05"] 或跨月 ["2026-05","2026-06"]

  // 同时 fetch 当前选中月(保留原有视图刷新)
  if (!months.includes(currentMonth.value)) months.push(currentMonth.value);

  const results = await Promise.all(
    months.map(m => api.getPriceCalendar(productId, m))
  );
  // 把所有月份的明细合并到本地状态,按区间聚合显示
  mergeIntoLocalState(results.flatMap(r => r.data));
}

并且,保存成功后建议自动把月份选择器切换到新区间的起始月startDate.slice(0,7)),这样用户能立即看到刚加的区间,不用手动切月。

方案 B粗暴但稳

保存成功后,无脑刷新「当前月 ± 6 个月」共 13 个月(或业务可见范围全部月份),用 Promise.all 批量 GET 后聚合。请求多但实现简单,适合日历视图用户经常切月的场景。

方案 C最稳妥

保存成功后:

  1. 清空本地所有缓存
  2. 把月份选择器切到 payload.startDate.slice(0, 7)
  3. 触发该月份的 GET 拉取

用户视觉上"跳到新区间所在月",能立即看到新数据。请求最少(只 1 次),但前端要做一次月份切换动画。

三方案对比

方案 请求数 UX 实现复杂度 推荐度
A 1~N按跨月数 留在原月 + 数据合并 ★★★★★
B ~13 留在原月 + 全量刷新 极低 ★★★
C 1 跳到新月 ★★★★

五、回归测试点(前端修完后自测)

  • 当前选中 4 月,新增 5 月区间,确认添加后能立即在列表/日历中看到新区间
  • 当前选中 5 月,新增 4 月区间,同上能立即看到
  • 跨月新增(如 5/28 → 6/3,确认添加后两个月的数据都能看到
  • 同月新增4 月内 4/15 → 4/20,确认添加后能立即看到
  • 多次连续新增不同月的区间,每次都能立即回显
  • 新增成功后,月份选择器切换到任意月,数据都正确

六、后端是否有配合改动

后端代码、接口路径、字段定义、返回结构、写入读取行为完全不变后端不会发版本,测试环境无需重启服务


七、可选优化(前端讨论后再决定,本次不做)

如果前端觉得"逐月 GET 合并"太繁琐,后端可以增加一个新接口(不影响现有接口):

  • GET /admin/product/item/{productId}/price-calendar/ranges —— 按 range_id 聚合返回区间列表(含 startDate/endDate/tierSeq/priceType/adultSellPrice/childSellPrice,不分月,一次拉完所有区间
  • 或者给现有 GET .../price-calendar 增加 startDate / endDate 可选参数支持任意日期范围查询

如有需求请前端在本 changelog 评论或单独提工单,后端再评估排期。本次不强制做,前端先按方案 A/B/C 之一修即可解决问题