hl-api-changelog/changelogs-v2/2026-05/30_3272_资源退费说明CRUD模块_PR3273.md
yaosutu 1c6b38f548 docs(changelog): 资源退费说明 changelog 追加 settleScope 字典化用法说明 (PR #3291)
对应后端 PR #3291 (Issue #3290): settleScope 字段补字典化, 出参补 settleScopeLabel。

在原 30_3272_资源退费说明CRUD模块_PR3273.md 的 settleScope 枚举说明后追加:

- 用法 A: 直接用出参 settleScopeLabel (展示场景)
- 用法 B: 调字典接口 GET /internal/dict/data?dictType=order_refund_settle_scope
         拉下拉框选项 (编辑场景)
- 容错说明 + 字典元信息

前端零代码改动也能用 (用法 A); 编辑场景拉一个统一字典接口即可。
2026-06-01 10:14:39 +08:00

10 KiB

二期 v3资源退费说明 CRUD 模块(给司机行程单展示用)

服务: hl-resource-service PR: #3273 Issue: #3272 日期: 2026-05-30 影响: 🟢 新增能力。给运营在景区/活动详情下"维护退费说明"提供 CRUD 接口;最终用于行程单 PDF 渲染 + 核单 Step 5 录入对账。本期仅交付资源服务端,后续 PR 接入产品快照 + PDF + 核单。


总览(前端 mmg 必读)

每个景区SCENIC和活动ACTIVITY资源都可以挂一份"退费说明",包含资源级备注 + 多条退费明细(标题/金额/单位/备注/生效期)。

界面:景区 / 活动列表行加一个按钮 → 弹窗里调本期 3 个接口做 CRUD。

接口前缀/admin/refund-note/v3/ 前缀,因 resource-service 沿用一期路径风格;消费方仍是二期 v3 管理后台)。

本期不做:行程单 PDF 渲染、产品 ProductDetailVO 注入 refundNote、订单 OrderProductSnapshotContent 反序列化、核单 Step 5 录入对接。这些留后续 PR。


接口清单3 个)

1. 查询单资源的退费说明

GET /admin/refund-note?resourceType=SCENIC&resourceId=12345

入参query

字段 类型 必填 枚举 说明
resourceType string SCENIC / ACTIVITY 资源类型
resourceId long - 资源 ID字符串透传雪花

返回

{
  "code": 200,
  "data": {                              // 未配置时直接返 null,前端按 null 隐藏弹窗内容
    "noteId": "20596378108368322580",   // 雪花 ID 字符串透传
    "resourceType": "SCENIC",
    "resourceId": "12345",
    "intro": "苔藓为赠送项目,不退费",
    "items": [
      {
        "title": "成人未参加",
        "amount": 44.00,
        "unitLabel": "/人",                  // 展示文案,给人看
        "settleScope": "PER_PERSON",         // 结算粒度枚举,给规则引擎用
        "remark": "",
        "effectiveFrom": null,              // yyyy-MM-dd
        "effectiveTo": null
      },
      ...
    ],
    "createTime": "2026-05-30 10:15:00",
    "updateTime": "2026-05-30 10:15:00"
  }
}

枚举

  • settleScope
    • PER_PERSON 按人结算(默认)
    • PER_TEAM 按团结算(如寻龙诀 100/团 整团一次性)
    • PER_VEHICLE 按车辆结算(如卡丁车 2 人/辆,按辆数乘单价)

注意unitLabel"/人" / "/团" / "/辆")和 settleScope 职责不同

  • 卡丁车场景:unitLabel="/人"(给客户看是 120/人)+ settleScope=PER_VEHICLE(引擎按车辆数乘单价)
  • 两个字段独立维护,前端展示用 unitLabel,未来规则引擎用 settleScope

更新2026-06-01 PR #3291settleScope 字典化 + 出参补 settleScopeLabel 中文

后端已落字典 + 接口出参直接返中文,前端不用自己维护英文→中文映射。两种用法二选一:

用法 A直接用出参的 settleScopeLabel(展示场景推荐)

GET /admin/refund-note 返回的 items[] 每条新增 settleScopeLabel 字段

"items": [
  {
    "title": "成人未参加",
    "settleScope": "PER_PERSON",
    "settleScopeLabel": "按人",      // 🆕 后端字典拼装,直接展示
    ...
  }
]

列表 / 详情 UI 直接 {{ item.settleScopeLabel }} 渲染即可,无需自己映射。

用法 B调字典接口拉下拉框选项编辑场景推荐

管理后台编辑退费规则时,需要下拉框让运营选"按人/按团/按车"。调统一字典接口:

GET /internal/dict/data?dictType=order_refund_settle_scope
Authorization: Bearer <admin-token>

→ Result<List<SysDictDataDTO>>:
[
  { "dictValue": "PER_PERSON",  "dictLabel": "按人",  "sortOrder": 10 },
  { "dictValue": "PER_TEAM",    "dictLabel": "按团",  "sortOrder": 20 },
  { "dictValue": "PER_VEHICLE", "dictLabel": "按车",  "sortOrder": 30 }
]
  • 下拉框 option.label = dictLabeloption.value = dictValue
  • 提交时 req.items[].settleScope = dictValue(提交 settleScopeLabel 后端会忽略,label 由后端拼)
  • 建议前端全局缓存字典 5-10 分钟避免高频请求;如果有统一字典组件直接复用

容错(前端可忽略)

  • 字典服务异常 / 字典数据缺失 → settleScopeLabel = null,前端展示 fallback 用 settleScope 英文原值即可
  • 字典文案后续改了(如"按人" → "按人头")→ 运维改 sys_dict_data + 清 Redis 缓存即生效,后端无需重启,前端无需发版

字典元信息

dict_type order_refund_settle_scope
dict_name 退费明细结算粒度
字典数据 PER_PERSON→按人 / PER_TEAM→按团 / PER_VEHICLE→按车
字典存储 hl_user_service.sys_dict_data
缓存 key cache:dict:data:order_refund_settle_scope

2. 保存upsert 整块)

PUT /admin/refund-note

入参body

{
  "resourceType": "SCENIC",
  "resourceId": 12345,
  "intro": "苔藓为赠送项目,不退费",
  "items": [
    {
      "title": "成人未参加",      // 必填
      "amount": 44.00,           // 必填,>= 0赠送项填 0
      "unitLabel": "/人",         // 默认 "/人",可省略
      "settleScope": "PER_PERSON", // 默认 "PER_PERSON",可省略
      "remark": "",
      "effectiveFrom": null,
      "effectiveTo": null
    }
  ]
}

约束

  • resourceType:必须是 SCENIC / ACTIVITY
  • resourceId必须在 scenic_spot / activity 表存在且未软删,否则返 390805 "关联资源不存在"
  • items:至少 1 条,最多 50 条
  • items[].amount>= 0赠送项目填 0
  • items[].settleScope:必须是上述 3 枚举之一null 时默认 PER_PERSON
  • items[].effectiveFrom <= items[].effectiveTo(同时存在时)

返回

{ "code": 200, "data": "20596378108368322580" }   // 落库后的 noteId字符串透传

语义upsert——按 (resourceType, resourceId) 找现有记录,有则整块覆盖(不做 item 级 diff,无则 insert。

3. 软删整份

DELETE /admin/refund-note?resourceType=SCENIC&resourceId=12345

入参:同 GET。 返回{ "code": 200, "data": true }(不存在或已软删返 false,不报错

软删用主键自身写 deleted_at,UNIQUE KEY 永不撞键,支持同资源无限次"删→重建"。


错误码(段位 39080x

code 错误信息
390801 退费明细金额必须 ≥ 0
390802 退费明细生效起日不能晚于止日
390803 退费明细结算粒度非法: {0}
390804 退费说明资源类型非法: {0}
390805 关联资源不存在: type={0}, id={1}

非业务错误(参数校验失败)走通用 400。


业务边界

  • 资源类型:一期仅 SCENIC + ACTIVITY,其他资源(餐饮/酒店/物资等)有各自退订/退款政策,不复用本结构。
  • 一份生效同资源同时刻只有一份生效的退费说明DB 唯一键 (resource_type, resource_id, deleted_at) 保证)。
  • 关联校验:保存时校验 resourceId 在主资源表存在,防孤儿数据。
  • 资源软删后:本退费说明仍存在但孤儿(查不到对应资源),不主动清理;运营侧需手动删除。

数据示例(典型)

白桦林4 条规则)

{
  "resourceType": "SCENIC", "resourceId": 12345,
  "intro": "苔藓为赠送项目, 不退费",
  "items": [
    {"title": "儿童/学生/无证件未参加", "amount": 15, "unitLabel": "/人", "settleScope": "PER_PERSON"},
    {"title": "免票座电瓶车",         "amount": 30, "unitLabel": "/人", "settleScope": "PER_PERSON"},
    {"title": "白桦林未参加",         "amount": 44, "unitLabel": "/人", "settleScope": "PER_PERSON"},
    {"title": "桦树皮画未参加",       "amount": 50, "unitLabel": "/人", "settleScope": "PER_PERSON", "remark": "仅儿童"}
  ]
}

寻龙诀(按团结算)

{
  "resourceType": "ACTIVITY", "resourceId": 99999,
  "items": [
    {"title": "寻龙诀未参加", "amount": 100, "unitLabel": "/团", "settleScope": "PER_TEAM"}
  ]
}

卡丁车(按车结算,文案 /人)

{
  "resourceType": "ACTIVITY", "resourceId": 88888,
  "items": [
    {"title": "卡丁车未骑", "amount": 120, "unitLabel": "/人", "settleScope": "PER_VEHICLE",
     "remark": "2 人/辆共享单价"}
  ]
}

套娃(时间窗口)

{
  "resourceType": "SCENIC", "resourceId": 77777,
  "items": [
    {"title": "老人只看大马戏", "amount": 65,  "settleScope": "PER_PERSON"},
    {"title": "6/25 后没去或免票", "amount": 165, "settleScope": "PER_PERSON",
     "effectiveFrom": "2026-06-25", "effectiveTo": null}
  ]
}

影响评估

  • 后端:仅 hl-resource-service 新增 1 张表 resource_refund_note + 3 个 admin 接口,对其他业务零影响。
  • DBFlyway V20260529_002__create_resource_refund_note.sql 自动建表,重启服务后生效。
  • 前端:新增弹窗 UI建议在景区 / 活动详情页加按钮 → 弹窗 CRUD,完全独立的新页面,老页面不影响。

注意事项

  1. 雪花 ID 透传为字符串(noteId / resourceId),前端不要 Number()
  2. 资源软删后的退费说明不会自动清理,运营侧需先删退费说明再删资源(否则成孤儿数据)。
  3. 同资源不可有 2 份生效退费说明DB 唯一键约束)。
  4. 删除是软删,可同资源重建;不支持物理删除。

关联

  • Issue: #3272
  • PR: #3273 - feat(resource): 新增资源退费说明 CRUD 模块
  • Commit: ffae5ab90
  • 后续 PR(不在本期):
    • 产品服务 ProductDetailVO.NodeItem.refundNote 注入(参考 #3147 serviceStandard 模式)
    • 订单 OrderProductSnapshotContent 加 refundNote 反序列化10 行)
    • 行程单 PDF 渲染退费表(订单 v3 + PDF 服务)
    • 核单 Step 5 录入半结构化对接(可选)