diff --git a/changelogs/2026-04/2026-04-18-resource-pagination-and-search-fixes.md b/changelogs/2026-04/2026-04-18-resource-pagination-and-search-fixes.md new file mode 100644 index 0000000..827c72f --- /dev/null +++ b/changelogs/2026-04/2026-04-18-resource-pagination-and-search-fixes.md @@ -0,0 +1,211 @@ +# 资源模块分页与搜索修复(素材 limit 参数 + 活动/餐厅/服务按城市搜索) + +- **日期**: 2026-04-18 +- **服务**: hl-resource-service(端口 8082) +- **类型**: BUG 修复(非破坏性,向后兼容) +- **优先级**: P2 +- **前端影响**: **无需改代码**,但会有"分页不再多算空页 / 搜索匹配范围扩大"的观感变化 +- **关联 PR**: #798、#806 +- **关联 Issue**: #797、#804 + +--- + +## 总览 + +本次合并两个修复到 dev,都在 `hl-resource-service`: + +| PR | 影响接口 | 问题 | 修复 | +|---|---|---|---| +| #798 | `GET /admin/material/list` | 前端传 `?limit=12` 后端不识别,始终按默认 `pageSize=20` 返回 | `pageSize` 字段追加 `@JsonAlias("limit")`,并新增 `setLimit` setter | +| #806 | `GET /admin/activity/items`、`GET /admin/restaurant/items`、`GET /admin/service/items` | `keyword` 只匹配名称/描述/亮点,搜"呼伦贝尔"等城市名匹配不到 | `keyword` like 条件扩展到省/市/区(或地址)字段 | + +> ⚠️ `GET /admin/scenic/spots`(景区列表)**未改动**,保持原行为(按用户要求)。 + +--- + +## 修复一:素材列表支持 `limit` 参数(PR #798) + +### 影响接口 + +``` +GET /admin/material/list +``` + +### 现象对比 + +**修复前**: + +``` +请求: GET /admin/material/list?page=1&limit=12&categoryCode=product&fileType=image +响应: { "data": { "records": [...共 20 条...], "total": 56, "page": 1, "pageSize": 20 } } +``` + +- 前端本来就在传 `?limit=12`,但后端字段名叫 `pageSize`,不识别 `limit`,直接走默认值 20 +- 前端计算 `总页数 = ceil(total / limit) = ceil(56 / 12) = 5`,但实际后端按 pageSize=20 返回 → 真实页数只有 3 +- 用户点到第 4、5 页 → `records` 为空数组,体验是"后面几页是空的" + +**修复后**: + +``` +请求: GET /admin/material/list?page=1&limit=12&categoryCode=product&fileType=image +响应: { "data": { "records": [...共 12 条...], "total": 56, "page": 1, "pageSize": 12 } } +``` + +- `limit` 被后端识别,`pageSize` 回传为请求的 `limit` 值 +- 前端分页控件算出的页数与后端实际页数一致,不再出现空页 + +**行为保持不变**: + +- 前端如果传 `?pageSize=15` → 后端仍按 15 处理(原行为) +- 同时传 `?pageSize=20&limit=12` → 以 `limit=12` 为准(`@JsonAlias` 会覆盖同名字段,不建议前端同时传) +- 不传任何分页参数 → 默认 `pageSize=20` + +### 前端适配 + +- **无需改代码**。前端本来就传 `limit`,之前是无效参数,现在生效 +- **观感变化**:分页器的页数显示可能"变少了",那是因为之前的页数是虚高的;真实数据没变 +- 若前端之前为了兼容"后面是空页"写过判断(如跳到最后一页发现是空就回退),可以保留,不会有副作用 + +### 接口契约 + +**请求**: + +``` +GET /admin/material/list?page=1&limit=12&categoryCode=product&fileType=image +Authorization: Bearer {token} +tenant-id: {租户ID} +``` + +常用查询参数: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| page | Integer | 否 | 页码,默认 1 | +| pageSize / limit | Integer | 否 | 每页条数,默认 20;**两个名字后端都认**,推荐 `pageSize` | +| categoryCode | String | 否 | 素材分类码(例:`product`) | +| fileType | String | 否 | 文件类型(例:`image`) | + +**响应**: + +```json +{ + "code": 200, + "message": "成功", + "data": { + "records": [ /* 素材对象列表 */ ], + "total": 56, + "page": 1, + "pageSize": 12 + }, + "success": true +} +``` + +--- + +## 修复二:活动/餐厅/服务列表 `keyword` 支持省市区模糊搜索(PR #806) + +### 影响接口 + +| 接口 | 模块 | 说明 | +|------|------|------| +| `GET /admin/activity/items` | 游玩项目 | 活动列表(按 keyword / cityKeyword 检索) | +| `GET /admin/restaurant/items` | 餐厅 | 餐厅列表 | +| `GET /admin/service/items` | 服务 | 服务项列表 | + +> `GET /admin/scenic/spots`(景区)**未改**,保持原行为。 + +### 现象对比 + +**修复前**(以 activity 为例): + +``` +请求: GET /admin/activity/items?keyword=呼伦贝尔&page=1&pageSize=20 +响应: { "data": { "records": [], "total": 0, ... } } ← 0 条 +``` + +- `keyword` 只 like 匹配 `name` / `description` / `highlights` 三个字段 +- 如果一条活动名字叫"草原骑马"、描述里没写"呼伦贝尔",就算它 city 是"呼伦贝尔",也搜不到 + +**修复后**: + +``` +请求: GET /admin/activity/items?keyword=呼伦贝尔&page=1&pageSize=20 +响应: { "data": { "records": [...呼伦贝尔下面的活动...], "total": 18, ... } } +``` + +- `keyword` like 匹配范围扩大到 **名称 + 描述 + 亮点 + 省 + 市 + 区** +- 搜"海拉尔"、"内蒙古"、"额尔古纳"等都会命中对应地名的记录 + +### 各接口的 keyword 匹配字段 + +| 接口 | 修复前 keyword 匹配字段 | 修复后 keyword 匹配字段 | +|------|-------------------------|-------------------------| +| `/admin/activity/items` | name, description, highlights | name, description, highlights, **province, city, district** | +| `/admin/restaurant/items` | name, description, highlights | name, description, highlights, **province, city, district** | +| `/admin/service/items` | name, description, highlights | name, description, highlights, **province, city, address** *(service_item 表无 district 字段,用 address 代替)* | + +### 与 `cityKeyword` 的关系 + +- `cityKeyword` 是三个接口已有的**独立参数**,仍然只按 city 字段模糊匹配 +- 前端若同时传 `keyword` 和 `cityKeyword`,两者是 **AND** 组合(都要满足),行为不变 +- 建议前端保持现有用法不动;单独搜框用 `keyword` 即可覆盖绝大多数场景 + +### 前端适配 + +- **无需改代码**。`keyword` 参数名、类型、返回结构完全不变 +- **观感变化**:同一个 keyword 在活动/餐厅/服务列表里可能比以前多返回一些结果(因为多匹配了省/市/区字段),这是预期内的 +- 若前端文案里显式写了"按名称/描述搜索",建议改成更宽松的"按名称、描述、地点搜索"(可选,非强制) + +### 接口契约(以 activity 为例,另两个类似) + +**请求**: + +``` +GET /admin/activity/items?keyword=呼伦贝尔&page=1&pageSize=20 +Authorization: Bearer {token} +tenant-id: {租户ID} +``` + +常用查询参数(均为可选): + +| 参数 | 类型 | 说明 | +|------|------|------| +| keyword | String | 关键词(**本次扩展**:名称/描述/亮点/省/市/区) | +| cityKeyword | String | 仅按城市匹配(未变) | +| page | Integer | 页码,默认 1 | +| pageSize | Integer | 每页条数,默认 20 | + +**响应结构**:保持原样,不赘述。 + +--- + +## 向后兼容性 + +- ✅ 接口路径、请求参数名、响应字段结构、HTTP code、业务 code **完全不变** +- ✅ 前端已有代码无需任何修改 +- ✅ 景区接口未动 +- ⚠️ 两个修复会带来"分页页数更准"和"搜索结果变多"的观感变化,属于预期行为 + +--- + +## 重启服务 + +> **仅需重启** `hl-resource-service`(端口 8082) + +- **测试环境**:通过 Deploy Panel 重启(参考 `memory/deploy-panel.md`) +- **正式环境**:本次**先不上正式** +- **DDL 变更**:无 +- **配置变更**:无 + +--- + +## 关联信息 + +| 项 | 值 | +|---|---| +| PR #798 | fix(resource): 素材列表分页兼容前端 limit 参数 → dev | +| PR #806 | fix(resource): 活动/餐厅/服务列表 keyword 支持省市区模糊搜索 → dev | +| Issue #797 | 素材列表 limit 参数不生效导致分页虚高 | +| Issue #804 | 活动/餐厅/服务按城市名搜索匹配不到 | +| 服务 | hl-resource-service(8082) |