# 【修改接口·管理后台】退费说明融合进资源编辑接口(景区 / 活动 / 服务) > **PR**: #3407(工单 #3406) > **服务**: hl-resource-service | **更新时间**: 2026-06-03 > > **存放目录**: `changelogs-v2/2026-06/` > **影响范围**: 管理后台「资源管理 / 景区·游玩项目·服务」编辑页(基本信息) > **状态**: 已合并 dev-v3 + 测试服部署双实例 + API 实测三类通过 --- ## ⚠️ 关键说明 退费说明**不再走独立的** `/admin/refund-note` 接口,已**融合进资源编辑接口**——前端在景区/活动/服务编辑页里直接编辑退费说明,随资源一起保存、随详情一起回显,**一个接口搞定**。 - **覆盖三类资源**:景区 SCENIC、游玩项目 ACTIVITY、**服务 SERVICE(本次新增支持)**。 - **详情** `GET` 响应新增 `refundNote` 字段(未配置为 `null`)。 - **保存** `POST`(新建) / `PUT`(编辑) 请求体新增 `refundNote` 字段,三态语义见 §3.2。 - **独立接口 `/admin/refund-note` 仍保留**(向后兼容 + 订单快照内部仍用),但前端**改用融合接口**,不要再调独立接口。 > 替代说明:本文取代 `03_3389_...` changelog 中「退费说明接入(独立接口)」一节。前端**按本文融合接口接入**,勿按旧文的 `/admin/refund-note` 独立接口接。 --- ## 1. 背景 退费说明(resource_refund_note)此前是独立 CRUD 模块(`/admin/refund-note`),前端要单独调一套接口维护。运营反馈应在资源编辑页里直接配,故融合进资源的详情/保存接口。同时把适用资源从「景区+活动」扩展到「景区+活动+**服务**」。 --- ## 2. 变更清单 | # | 资源 | 详情(回显 refundNote) | 保存(含 refundNote) | |---|------|------|------| | 1 | 景区 Scenic | GET `/admin/scenic/spot/{scenicId}` | POST `/admin/scenic/spot`、PUT `/admin/scenic/spot/{scenicId}` | | 2 | 游玩项目 Activity | GET `/admin/activity/item/{activityId}` | POST `/admin/activity/item`、PUT `/admin/activity/item/{activityId}` | | 3 | 服务 Service(**新增**) | GET `/admin/service/item/{serviceId}` | POST `/admin/service/item`、PUT `/admin/service/item/{serviceId}` | > 列表接口(`/spots`、`/items`)**不返回** refundNote(避免 N+1),退费说明只在单条详情里有。 --- ## 3. 接口详情 ### 3.1 详情回显 三类资源的详情响应(`ScenicSpotVO` / `ActivityVO` / `ServiceItemVO`)新增字段: | 字段 | 类型 | 说明 | |---|---|---| | `refundNote` | object \| null | 退费说明;该资源未配置时为 `null` | | `refundNote.noteId` | string | 退费说明 ID(雪花,String 透传防精度丢失) | | `refundNote.intro` | string | 资源级备注 | | `refundNote.items[]` | array | 退费明细(见 §6.2) | | `refundNote.createTime` / `updateTime` | datetime | — | ### 3.2 保存(三态语义) 三类资源的新建/编辑请求体新增 `refundNote`(类型 `RefundNoteEmbedReqVO`,见 §6.1)。后端按 `refundNote` 是否传、items 是否为空分三态处理: | 入参 refundNote | 行为 | |---|---| | **不传**(字段缺省 / null) | 保持该资源现有退费说明**不动** | | 传了,`items` **为空数组或不传** | **删除**该资源退费说明(清空语义) | | 传了,`items` **非空** | **整块 upsert**(连 intro 一起覆盖) | > 编辑接口是字段级更新:只传 `refundNote` 即可单独维护退费说明,不影响其它字段。 ### 3.3 示例(以景区为例,活动/服务同理换路径) **保存退费说明**(PUT 只传 refundNote,其它字段不动): ```bash curl -X PUT -H "Authorization: Bearer " -H "Content-Type: application/json" \ -d '{ "refundNote": { "intro": "苔藓为赠送项目,不退费", "items": [ { "title": "成人未参加", "amount": 50.00, "settleScope": "PER_PERSON", "unitLabel": "/人", "remark": "仅限成人" } ] } }' \ "https://api.test.1814.love:9443/admin/scenic/spot/3001000000000000019" ``` **详情回显**(GET,data 节选): ```json { "code": 200, "data": { "scenicId": "3001000000000000019", "name": "中俄边境公路(卡线)", "refundNote": { "noteId": "20596378108368322580", "intro": "苔藓为赠送项目,不退费", "items": [ { "title": "成人未参加", "amount": 50.00, "settleScope": "PER_PERSON", "settleScopeLabel": "按人", "unitLabel": "/人", "remark": "仅限成人" } ], "createTime": "2026-06-03 17:30:00", "updateTime": "2026-06-03 17:30:00" } } } ``` **清空退费说明**(PUT 传空 items): ```bash curl -X PUT -H "Authorization: Bearer " -H "Content-Type: application/json" \ -d '{ "refundNote": { "items": [] } }' \ "https://api.test.1814.love:9443/admin/scenic/spot/3001000000000000019" # 之后 GET,data.refundNote 为 null ``` --- ## 6. 数据结构 ### 6.1 `refundNote` 请求体(`RefundNoteEmbedReqVO`) 前端只传 intro + items,`resourceType` / `resourceId` 由后端从当前资源上下文回填,前端无需传。 | 字段 | 类型 | 必填 | 校验 | 说明 | |---|---|---|---|---| | `intro` | string | ❌ | `@Size(max=255)` | 资源级备注 | | `items` | array | ❌ | `@Size(max=50)` | 退费明细;空/不传=清空 | ### 6.2 退费明细项(`items[]` / `RefundNoteItemVO`) | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `title` | string | ✅ | 展示标题,如「成人未参加」 | | `amount` | BigDecimal | ✅ | 退费金额(赠送项目填 0,不可为负) | | `unitLabel` | string | ❌ | 展示文案 /人 /团 /辆 | | `settleScope` | string | ❌ | 结算粒度 PER_PERSON / PER_TEAM / PER_VEHICLE | | `settleScopeLabel` | string | — | 结算粒度中文(出参后端拼字典 order_refund_settle_scope,入参可省) | | `remark` | string | ❌ | 备注 | | `effectiveFrom` / `effectiveTo` | date | ❌ | 规则生效起止(null=无限制;同传时 from≤to) | --- ## 9. 业务边界 - ✅ **三态语义统一**:不传=不动 / 空 items=删除 / 非空=upsert(三类资源一致)。 - ✅ **同事务**:退费说明与资源主表在同一事务保存,主表失败则退费说明回滚。 - ✅ **列表不返回 refundNote**:仅单条详情回显,避免列表 N+1。 - ✅ **settleScopeLabel 后端拼**:出参按字典 `order_refund_settle_scope` 回填中文,字典异常时 fallback 为 null,不影响主流程。 - ✅ **独立接口保留**:`/admin/refund-note`(GET/PUT/DELETE)仍可用,订单快照内部仍取退费说明;前端改用融合接口即可。 - ✅ **items 上限 50**:与独立端点对齐。 --- ## 11. 影响评估 - **是否破坏向后兼容**:否(详情新增字段、保存新增可选字段;独立接口未删)。 - **前端是否必须同步**:是(要在编辑页接入退费说明子表单,改用融合接口)。 - **影响已有数据**:无(存量退费说明照常,独立接口与融合接口读写同一张表)。 --- ## 12. 注意事项 - **改用融合接口**:前端不要再调 `/admin/refund-note` 独立接口(虽保留但即将不维护)。 - **清空靠空 items**:要删退费说明就传 `refundNote:{items:[]}`,不是不传(不传=不动)。 - **Long 主键 String**:`refundNote.noteId` 为 String,勿当 Number 解析。 - **服务也支持了**:服务资源(ServiceItem)本次起可配退费说明,与景区/活动一致。 --- ## 13. 关联 - 取代:`03_3389_资源默认收费+收费否禁价格日历+退费说明接入-管理后台.md` 的「退费说明(独立接口)」一节。 - 后端负责人:@wx - 前端对接(管理后台):mmg