# 星册首页“更多”按钮恢复设计 > ★ **MVP 优先**:本次仅恢复旧版星册首页“每组预览 3 张 + 超出显示更多”的既有行为,不引入新分页框架、不修改前端布局。 ## 方案概述(必读) ### 要解决的问题 **业务问题** - 星册首页的原创、典藏和活动分组均不再显示“更多”按钮。 - 用户无法从首页进入对应分类的完整藏品列表。 **技术问题** - `assetService` 迁移后,分组构建器返回全部藏品,并把 `AssetGroup.HasMore`、`GradeSection.HasMore` 固定为 `false`。 - protobuf 的 `false` 字段可能因 `omitempty` 不出现在 JSON 中,前端 `v-if="group.has_more"` 和 `v-if="gradeItem.has_more"` 均不成立。 - 当前分组构建器同时被首页 `GetMyAssets` 和查看更多 `GetAssetsByType` 复用,不能直接统一截断,否则查看更多页面也只能拿到前三张。 ### 整体实现路径 1. 为共享分组构建器增加预览上限参数,约 0.5 小时。 2. 首页传入固定上限 3,查看更多传入 0(不限),约 0.5 小时。 3. 补充首页截断和查看更多完整返回测试,约 1 小时。 4. 执行 assetService、gateway 相关测试和全服务预编译,约 0.5 小时。 预计总工作量:约 2.5 小时。 ### 关键决策 - **恢复旧版 `HomePageSize = 3` 行为**:用户已确认每个分组或等级最多预览 3 张。 - **统一按点赞数选取首页前三张**:原创、典藏、活动均使用 `models.Asset.LikeCount` 按点赞数降序;点赞数相同时按 `asset_id` 升序,沿用项目排行榜的稳定排序口径。 - **后端计算 `has_more`**:保证 API 契约真实,避免前端下载全部数据后再截断。 - **参数化复用现有构建器**:首页限制 3,查看更多限制 0,避免复制三套分组逻辑。 - **不修改前端模板**:现有 `v-if` 在后端返回正确字段后即可工作。 ### 核心架构图(TL;DR) ```text GET /api/v1/starbook/home │ ▼ GetMyAssets ── previewLimit=3 ──► group builders │ ├─ items[:3] ├─ total_count=真实数量 └─ has_more=(真实数量 > 3) GET /api/v1/starbook/items │ ▼ GetAssetsByType ── previewLimit=0 ──► 同一组 builders │ ├─ items=全部匹配项 └─ 不因首页规则截断 ``` ## 文档说明 - **适用范围**:星册首页分组预览和“更多”入口。 - **不包含**:前端布局重做、数据库查询级分页重构、新增缓存。 - **前置版本**:`starbookService` 已删除,相关能力已迁移到 `assetService`。 - **历史依据**:旧版 `starbookService` 使用 `HomePageSize = 3`,原创按等级截断并计算 `has_more`。 - **目标读者**:后端开发、前端联调和测试人员。 ## 1. 当前行为与根因 `StarbookContent.vue` 已正确消费以下字段: - 原创:`gradeItem.has_more` - 典藏/活动:`group.has_more` 问题位于 `assetService/service/asset_service.go`:三个分组构建器返回所有项目,并把 `HasMore` 固定为 `false`。因此前端不需要增加兜底逻辑,修复应落在 API 数据生产端。 ## 2. 分组构建器接口 三个构建器增加 `previewLimit int` 参数: ```go buildRegularGroupForAssets(..., previewLimit int) *pb.AssetGroup buildCollectionGroupForAssets(..., previewLimit int) *pb.AssetGroup buildActivityGroupForAssets(..., previewLimit int) *pb.AssetGroup ``` 参数语义: - `previewLimit > 0`:先按 `models.Asset.LikeCount DESC, Asset.ID ASC` 排序,再最多保留指定数量;`has_more` 表示是否有项目被本次预览截断。 - `previewLimit <= 0`:不截断,用于查看更多接口;分组和等级的 `has_more` 必须为 `false`,避免把“无限制模式”错误解释成仍有未返回项目。 定义首页常量: ```go const homePreviewLimit = 3 ``` 不增加配置文件或环境变量;该值是已确认的固定产品规则。 ## 3. 首页数据规则 ### 3.1 原创藏品 原创按 `grade` 独立计算: 1. 只统计能关联到真实 `Asset` 的有效注册记录。 2. 每个等级使用关联到的 `models.Asset.LikeCount` 按点赞数降序排序;点赞数相同时按 `Asset.ID` 升序,不能使用可能漂移的 `AssetRegistry.LikeCount`。 3. 每个等级最多返回 3 张。 4. `GradeSection.TotalCount` 为该等级有效项目总数。 5. `GradeSection.HasMore = previewLimit > 0 && TotalCount > previewLimit`。 6. `AssetGroup.HasMore` 为任一等级 `HasMore=true`。 7. 保持现有 grade 降序输出。 ### 3.2 典收藏品 1. 构建有效项目列表。 2. 使用关联到的 `models.Asset.LikeCount` 按点赞数降序排序;点赞数相同时按 `Asset.ID` 升序,不能使用 `AssetRegistry.LikeCount`。 3. 首页最多返回前三张。 4. `TotalCount` 为有效项目总数。 5. `HasMore = previewLimit > 0 && TotalCount > previewLimit`。 ### 3.3 活动藏品 规则与典藏一致:使用 `models.Asset.LikeCount` 按点赞数降序并以 `Asset.ID ASC` 稳定并列顺序,有效项目总数超过 3 时截断并返回 `HasMore=true`。 ## 4. 查看更多数据规则 `GetAssetsByType` 调用构建器时传 `previewLimit=0`: - 不执行首页前三张截断。 - 保留当前 type/category/grade 过滤逻辑。 - 返回结果沿用首页的统一排序:`models.Asset.LikeCount DESC, Asset.ID ASC`。 - 返回所有匹配分组项目,确保首页点击“更多”后能看到完整数据。 - 本次不扩展数据库级分页;现有接口的分页字段行为不在此次修复范围内。 ## 5. 前端行为 `frontend/pages/components/StarbookContent.vue` 不需要修改: - 原创继续使用 `v-if="gradeItem.has_more"`。 - 典藏和活动继续使用 `v-if="group.has_more"`。 - `processGroupsWithValidUrls` 的深拷贝会保留值为 `true` 的 `has_more` 字段。 验收行为: | 实际数量 | 首页显示数量 | “更多”按钮 | |---:|---:|---| | 0 | 0 | 不显示 | | 1–3 | 1–3 | 不显示 | | 4+ | 3 | 显示 | ## 6. 测试设计 ### 6.1 Service 单元测试 至少覆盖: 1. 原创某等级 3 张:返回 3 张,等级和外层 `has_more=false`。 2. 原创某等级 4 张:首页按 `Asset.LikeCount DESC, Asset.ID ASC` 返回前三张,`total_count=4`,等级和外层 `has_more=true`。 3. 典藏 4 张:首页按 `Asset.LikeCount DESC, Asset.ID ASC` 返回前三张,`total_count=4`,`has_more=true`。 4. 活动 4 张:首页按 `Asset.LikeCount DESC, Asset.ID ASC` 返回前三张,`total_count=4`,`has_more=true`。 5. 点赞来源口径:故意让 `AssetRegistry.LikeCount` 与 `Asset.LikeCount` 相反,断言排序严格采用 `Asset.LikeCount`。 6. 查看更多模式 4 张:按同一规则返回全部 4 张,分组/等级 `has_more=false`,不受首页上限影响。 7. 边界值 `previewLimit=3`:数量为 0、1、3、4 时分别验证返回数量和 `has_more`,防止 off-by-one。 8. 注册记录找不到对应资产时:无效记录不应制造错误的 `total_count` 或 `has_more`。 9. 多个原创等级中仅一个等级超过 3 张:仅该等级 `has_more=true`,外层 `AssetGroup.HasMore=true`。 ### 6.2 回归验证 - 运行 assetService 相关 service/provider 测试。 - 运行 Starbook gateway controller 测试。 - 编译 gateway 和 assetService。 - 按 `dev.sh` 服务列表预编译全部后端服务。 - 检查 `GetMyAssets` 与 `GetAssetsByType` 的调用方,确认二者分别传入 3 和 0。 ## 7. 错误处理与兼容性 - 不改变 protobuf 字段或 REST 响应结构。 - 不改变身份校验和 type/category/grade 过滤规则。 - 空分组维持现有行为。 - `has_more=false` 仍可能被 JSON 省略,前端将其视为假值,符合预期;只有需要按钮时必须返回 `true`。 ## 8. 实施文件 预计修改: - `backend/services/assetService/service/asset_service.go` - 对应的 assetService 测试文件(优先复用现有测试文件) 预计不修改: - `frontend/pages/components/StarbookContent.vue` - `backend/proto/asset.proto` - 生成的 protobuf 文件 - 数据库与 migration ## 9. 非目标与后续项 本次明确不做: - 数据库查询层的真实分页与 limit/offset 下推。 - 首页排序规则重构。 - collection/activity 的分类结构重构。 - 前端“更多”按钮样式调整。 如果单个用户藏品数量显著超过当前 `GetByOwner(..., 1000, 0)` 上限,应另立任务把首页预览下推到 repository 查询层;这不影响本次恢复既有按钮行为。