feat(app): 推荐流支持分类过滤

This commit is contained in:
Zhou Weidong committed 2026-10-21 18:23:57 +08:00
1 parent 0e8fb1582d
commit 8f35160b56
12 files changed
+255 -24

No files matched your search

+4 -1
View File
@@ -167,7 +167,7 @@ app.register.max-per-device-per-day
| --- | --- | --- |
| GET | `/app/home/feed` | 首页:轮播 + 分区,卡片带 `preview` 可播预览集与 `language` 语种 |
| GET | `/app/discover/feed` | 发现页分区 |
| GET | `/app/feed?types=ANIME,LIVE&cursor=&size=20` | 推荐流;按内容类型多选过滤,游标翻页 |
| GET | `/app/feed?types=ANIME,LIVE&categoryId=7&cursor=&size=20` | 推荐流;支持内容类型与分类叠加过滤,游标翻页 |
| GET | `/app/categories` | 分类列表 |
| GET | `/app/dramas/{id}` | 详情(含剧集列表,免费集带**已签名**播放地址) |
| GET | `/app/search?keyword=&pageIndex=&pageSize=` | 搜索已上线短剧:按标题/简介模糊匹配,分页返回卡片列表 |
@@ -188,7 +188,10 @@ app.register.max-per-device-per-day
- `types` 可选,逗号分隔,支持 `ANIME`、`LIVE` 或多选 `ANIME,LIVE`;不传或空值返回全部已上线内容。
过滤按 `drama_types` 整词匹配,多标签剧可被多个类型同时命中。
- `categoryId` 可选;不传返回全部分类。传入后按 `category_ids` 整词匹配,
可与 `types` 叠加,只返回同时命中内容类型和分类的已上线短剧。
- `cursor` 可选,上一页返回的 `nextCursor`;`size` 默认 20,最大 50。
游标短剧必须同时满足已上线、内容类型命中和分类命中,否则返回空列表。
- 排序:`recommend_weight DESC NULLS LAST, view_count DESC, id DESC`。
- 返回 `Result<CursorResult<AppDramaCardVO>>`,卡片字段与首页一致,包含互动计数、`preview`、`language`、`dramaType`。
+86
View File
@@ -0,0 +1,86 @@
# K96 剧场页服务端分类分页
## 目标
- `/app/feed` 支持按分类过滤,并与内容类型过滤叠加。
- 剧场页「全部」展示全部已上线短剧,任意分类展示该分类全部已上线短剧。
- 列表使用游标分页,切分类优先命中缓存,支持静默刷新、加载更多和失败重试。
## 分支
- FruitServer:`feat/k96-feed-category`
- ReelShort:`feat/k96-theater-feed`
## A. FruitServer
1. `AppCatalogController.feed` 增加可选 `Long categoryId` 并传给服务层。
2. `AppCatalogService.feed` 增加 `categoryId`,传给
`DramaService.listPublishedFeed`。
3. `DramaService.listPublishedFeed` 增加 `categoryId`:
- 非空时使用 `DramaMultiTagSupport.applyCategoryIdTokens`
按 `category_ids` 整词匹配。
- 游标 marker 必须同时满足已上线、内容类型命中和分类命中,否则返回空列表。
4. 补充服务层、控制器契约测试:
- 仅 categoryId。
- categoryId + types。
- 分类游标翻页。
- marker 分类不命中返回空。
5. 更新 `docs/api-phase1.md` 的 `/app/feed` 参数和分类过滤说明。
门禁:`mvn test` 全模块通过。
## B. ReelShort
### B1. API 与仓库
- `CatalogApi.feed` 增加可选 `String? categoryId`,非空才拼 query。
- `CatalogRepository.fetchFeed` 同步参数,HTTP 实现透传。
### B2. TheaterFeedController
- 新增 `lib/core/data/services/theater_feed_controller.dart`。
- 按 `String? categoryId` 独立缓存状态:
`dramas / cursor / hasMore / loaded / loading / loadingMore / lastError /
requestSeq / inFlight`。
- `select(id)` 同步切分类;有数据先渲染并静默刷新,无数据时加载。
- `loadMore` 游标追加并按 id 去重;`hasMore=false` 停止。
- `refreshCurrent` 失败保留旧数据;切换回失败分类自动重试。
- 单请求 10 秒超时,响应写回发起分类,requestSeq 仅处理同分类顺序。
### B3. 剧场接入
- `DiscoverPage` 创建并持有 TheaterFeedController,初始请求「全部」。
- 「全部」和分类 chips 的网格统一读取 `theater.dramas`,不再使用
`categories.feed.dramas` / `dramasOf`。
- `_selectCategory` 同时更新 `DiscoverLogic.selectedCategoryId` 和
`theater.select(categoryId)`。
- 滚动剩余不足 400px 时触发 `loadMore`;搜索模式不触发剧场分页。
- 下拉刷新并行执行 `categories.load()` 和 `theater.refreshCurrent()`。
- 无缓存首屏显示转圈;空、失败和重试保持既有剧场视觉。
### B4. 测试
- TheaterFeedController:
- 全部使用空 categoryId,分类使用对应 id。
- 缓存切回不闪烁。
- 分页去重、hasMore=false 停止。
- 失败保留旧数据、失败分类切回自动重试。
- 剧场 widget:
- 点击分类请求对应 categoryId。
- 接近底部触发下一页。
- 搜索、下拉刷新与既有布局不回归。
门禁:`dart analyze lib test` 零告警、`flutter test` 全过、
`flutter build apk --debug` 成功。
## Git
- FruitServer 提交:`feat(app): 推荐流支持分类过滤`
- ReelShort 提交:`feat(theater): 剧场分类列表服务端分页`
- 两仓库作者:`Zhou Weidong <502333560@qq.com>`,禁止 `git add -A`。
- 各自 `--no-ff` 合回 `develop` 并 push,两仓库 PROGRESS 留痕。
## 约束
- 全程中文;不改 specs、ReelShortWeb,不改首页 K94/K95 已交付逻辑。
- 不安装或操作真机;完成后停住等待验收。
+39
View File
@@ -24253,3 +24253,42 @@ Running Gradle task 'assembleDebug'... 27.6s
`838ca2c` 的代码差异为空。
- 本地分支 `fix/k95.2-poster-transition` 已删除;远端原本不存在该分支。
- K95、K95.1 成果保持不变;未实现其他改动,未安装或操作真机。
## 2026-10-21 K96 剧场页服务端分类分页
- 已完整读取 K96 `docs/plans/INBOX.md`。
- 已从最新 `origin/develop` 创建 FruitServer `feat/k96-feed-category` 与
ReelShort `feat/k96-theater-feed`。
- 已先写计划 `docs/plans/2026-10-21-K96-theater-feed.md`,覆盖分类参数、
category_ids 整词匹配、游标 marker 三重校验、客户端分类缓存分页和剧场接入。
- 已完成 `/app/feed` 可选 `categoryId`:可与 `types` 叠加;游标 marker 必须同时满足
已上线、类型命中和分类命中,否则返回空列表。
- 已补分类单独过滤、分类 + 类型、分类游标和 marker 不匹配测试,并更新
`docs/api-phase1.md`。
- 客户端已完成 Catalog API 分类参数、TheaterFeedController、分类缓存/静默刷新、
游标追加去重、10 秒超时与滚动加载;剧场「全部 / 分类」已改用 `/app/feed`,
搜索与首页 K94/K95 逻辑未改。
门禁原始输出:
```text
$ mvn test
[INFO] fruitshorts-app-api ................................ SUCCESS
[INFO] BUILD SUCCESS
[INFO] Total time: 15.436 s
$ dart analyze lib test
Analyzing lib, test...
No issues found!
$ flutter test --no-pub
00:52 +553: All tests passed!
$ flutter build apk --debug
Running Gradle task 'assembleDebug'... 24.8s
✓ Built build/app/outputs/flutter-apk/app-debug.apk
```
解读:FruitServer 全部 14 个 Reactor 模块通过,app-api 99 项测试全过;
ReelShort 静态分析零告警、553 项测试全过、debug APK 构建成功。
`pubspec.lock` 已还原,无依赖变更;未安装或操作真机。