Files
zt-closet-wxmini-frontend/.codebuddy/plans/穿搭页补全社区分段_83cc2406.md
T
2026-09-15 16:01:59 +08:00

206 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: 穿搭页补全社区分段
overview: 在穿搭 tab 新增「社区」分段,浏览所有用户公开的穿搭(作者信息、拼图封面、点赞/收藏数、场景与发布时间),并新增后端社区列表接口支撑。
design:
styleKeywords:
- iOS HIG
- 清爽克制
- 发丝分隔线
- 系统蓝
- 线性图标
fontSystem:
fontFamily: PingFang SC
heading:
size: 32rpx
weight: 600
subheading:
size: 28rpx
weight: 500
body:
size: 26rpx
weight: 400
colorSystem:
primary:
- "#007AFF"
- "#5856D6"
background:
- "#F2F2F7"
- "#FFFFFF"
text:
- "#000000"
- "#3C3C43"
- "#8E8E93"
- "#C7C7CC"
functional:
- "#FF2D55"
- "#34C759"
- "#FF9500"
- "#FF3B30"
todos:
- id: backend-community-api
content: 用 [subagent:code-explorer] 确认后端批量查询与计数模式;实现 GET /outfit/community 接口(DTO/DAO/Service/路由)并更新接口文档
status: completed
- id: frontend-community-data
content: models.ts 新增社区穿搭类型;outfit.ts 实现三态分段、社区取数、相对时间与详情跳转
status: completed
dependencies:
- backend-community-api
- id: frontend-community-ui
content: outfit.wxml/wxss 实现社区分段、作者行卡片、互动数据与空态样式
status: completed
dependencies:
- frontend-community-data
- id: verify-community
content: 运行 go build 与 tsc 类型检查,核对前后端字段契约与路由注册
status: completed
dependencies:
- backend-community-api
- frontend-community-ui
---
## 产品概述
为「纸条AI衣橱」小程序补全社区功能:在「穿搭」页现有「我的穿搭 / 已收藏」两个分段基础上,新增「社区」分段,让所有用户都能浏览其他用户公开的穿搭,并进入详情点赞、收藏,形成「公开到社区 → 他人浏览互动」的完整闭环。
## 核心功能
- 穿搭页分段控件扩展为三态:「我的穿搭 / 已收藏 / 社区」,切换即加载对应列表并重置分页
- 社区分段以卡片流展示其他用户公开的穿搭(仅展示已公开且审核通过、状态正常的穿搭)
- 社区卡片内容:作者头像与昵称(卡片顶部)、拼图式衣物封面与件数、穿搭名称、场景标签、点赞数与收藏数、相对发布时间
- 点击社区卡片进入他人视角的穿搭详情页,可点赞、收藏(复用现有详情页,不新增页面)
- 社区列表支持下拉刷新、上拉加载更多、骨架屏加载态与空态提示
- 社区分段隐藏「+ 创建穿搭 / AI 推荐」入口行(浏览场景不展示管理入口)
## 视觉与交互效果
延续现有 iOS HIG 风格:分组灰底、纯白卡片、发丝分隔线、系统蓝强调色。社区卡片在现有穿搭卡片结构上顶部新增作者行(圆形头像 + 昵称 + 右侧相对时间),底部 meta 行新增点赞、收藏两组互动数据,整体与「我的穿搭」卡片流视觉统一、切换分段有平滑过渡。
## 技术栈
- 前端:微信小程序原生 + TypeScript(沿用现有 webview 渲染与纯 WXSS 手写方案,不引入组件库)
- 后端:Go + Gin + GORM/MySQL(zt-closet-backend,新增接口沿用现有分层:router → handler → service → dao)
- 复用:前端 `request` 封装、`paged` 分页工具、`format.formatRelativeTime`、`logger`、`empty-state` 组件与图标库;后端 `PageRequest/PageResponse`、`normalizePage`、批量查询与批量组装模式
## 实现方案
### 总体策略
后端新增鉴权接口 `GET /outfit/community`:分页返回「其他用户已公开(is_public=2 且 audit_status=2 且 status=1)」的穿搭列表,聚合作者信息与点赞/收藏计数后一次性下发;前端将 `pages/outfit` 页扩展为三态分段,第三段对接新接口渲染社区卡片流,点击进入现有他人视角详情页(owner=0)。全程复用既有模式,不引入新架构、不新增页面、不改动 tabBar。
### 关键决策与理由
1. **接口路径 `GET /outfit/community`**:与既有 `GET /outfit/:uuid` 在同一 Gin 路由树共存是安全的——项目内已有完全相同形态的先例(`/notification/unread` 与 `/notification/:uuid` 共存且线上运行正常),Gin 1.12 静态路由优先匹配。
2. **排除本人的公开穿搭**(SQL 加 `user_id != 当前用户`):贴合用户「查看其他用户公开的穿搭」的表述,且避免与「我的穿搭」分段内容重复;后续如需包含自己,仅需去掉一个 WHERE 条件。
3. **互动数据由后端批量聚合下发**(like_count / collect_count):现有穿搭列表在前端逐条请求 `/like/:uuid`(一页 20 条即 20 次请求),社区列表直接使用后端聚合值,杜绝该 N+1 问题。
4. **后端批量组装杜绝 N+1**:复用 `buildOutfitListResponses` 的批量模式(一次性批量查明细 + 衣物),作者信息用已有 `UserGetByIDs`,点赞/收藏计数新增 `GROUP BY target_id` 批量方法;单页固定约 7 条 SQL,与页大小无关。
5. **社区卡片复用现有拼图封面结构**(cover-item 循环)与卡片骨架,仅新增作者行与互动数据块,模板通过 `activeTab === 2` 条件渲染差异部分,避免大段重复。
6. **仅社区分段隐藏入口按钮行**,「我的穿搭 / 已收藏」保持现状,控制改动面。
### 性能与可靠性
- 后端:分页 `page/page_size`(上限 50,`normalizePage` 规整),`ORDER BY id DESC` 走主键;批量计数对空列表短路,避免 `IN ()` 查询;错误统一返回现有错误码(19001 等),沿用 slog 日志风格。
- 前端:`page_size=20`、切换分段重置并丢弃过期响应(沿用现有 reqSeq 序号防乱序机制);辅助字段(相对时间)本地计算零请求;失败不打断主流程,仅记录 code 不打印敏感信息。
- 契约一致性:`created_at` 秒级时间戳(前端 `formatRelativeTime` 直接消费);`owner_avatar` 由后端 `upload.AvatarURL` 转为可访问 URL;`processed_image` 为完整 URL。
### 实施注意事项
- 后端仓库位于 `/root/zt-closet-backend`(不在前端工作区),当前存在未提交改动(收藏/通知修复),新代码只做追加、不动无关文件。
- 后端改动需用户自行部署后,前端指向线上域名(BASE_URL)才能联调。
- 前端不改 `app.json`、不改 `outfit-detail`、不改 tabBar;`outfit.json` 已引入所需组件,无需调整。
- 复用 `isOutfitPublicVisible` 的可见性口径(公开 2 + 审核通过 2 + 状态正常 1),保证社区列表与详情页可见性判定一致。
## 目录结构
后端 `/root/zt-closet-backend/`:
```
├── internal/dto/outfit.go # [MODIFY] 新增社区列表 DTO:OutfitCommunityListRequest(内嵌 PageRequest)/ OutfitCommunityListResponse(内嵌 PageResponse)/ OutfitCommunityItem(含 outfit_uuid、outfit_name、outfit_desc、scene、source、created_at、items、owner_name、owner_avatar、like_count、collect_count)
├── internal/mysqldao/outfit.go # [MODIFY] 新增 OutfitListCommunity(ctx, excludeUserID, page, pageSize):查询 is_public=2 AND audit_status=2 AND status=1 AND user_id != 本人,Count + Order("id DESC") 分页,参照 OutfitListByUserID 写法
├── internal/mysqldao/like.go # [MODIFY] 新增 LikeCountByTargets(ctx, likeType, targetIDs):SELECT target_id, COUNT(*) ... GROUP BY target_id(仅 status=1),空入参短路
├── internal/mysqldao/collect.go # [MODIFY] 新增 CollectCountByTargets 批量计数(同上模式)
├── internal/service/outfit.go # [MODIFY] 新增 CommunityList:normalizePage → 查列表 → 批量组装(复用 OutfitItemListByOutfitIDs + ClothesGetByIDs + UserGetByIDs + upload.AvatarURL + 批量计数),空列表直接返回空数组
├── internal/routers/api/v1/outfit.go # [MODIFY] 新增 Community handler(GetUserID → ShouldBindQuery → svc → ToResponse,与现有 List 写法一致)
├── internal/routers/router.go # [MODIFY] 鉴权组注册 auth.GET("/outfit/community", outfitHandler.Community)
└── 接口文档.md # [MODIFY] 新增社区列表接口章节;修正 FAQ「没有社区广场接口」的过时说明
```
前端 `/root/zt-closet-wxmini-frontend/`:
```
└── miniprogram/
├── types/models.ts # [MODIFY] 新增 CommunityOutfitItem 类型(与后端响应字段一一对应)
└── pages/outfit/
├── outfit.ts # [MODIFY] activeTab 扩展 0/1/2;fetchList 按分段选 /outfit、/collect、/outfit/community;社区项装饰(直接取 like_count/collect_count,计算相对时间 _time);onOutfitTap 社区项 owner=0;空态文案分支;日志沿用 logger
├── outfit.wxml # [MODIFY] 分段控件增加「社区」;entry-row 在社区分段隐藏;卡片新增作者行(社区分段)与收藏数、相对时间;状态标签仅非社区分段展示;空态文案分支
└── outfit.wxss # [MODIFY] 新增作者行、圆形头像(含 icon-user 占位)、昵称、时间、互动数据样式(延续现有 rpx 与色板)
```
## 关键代码结构
后端响应契约(新增到 `internal/dto/outfit.go`):
```
type OutfitCommunityListResponse struct {
PageResponse
List []OutfitCommunityItem `json:"list"`
}
type OutfitCommunityItem struct {
OutfitUUID string `json:"outfit_uuid"`
OutfitName string `json:"outfit_name"`
OutfitDesc string `json:"outfit_desc"`
Scene string `json:"scene"`
Source int8 `json:"source"`
CreatedAt int64 `json:"created_at"`
Items []OutfitItemResponse `json:"items"`
OwnerName string `json:"owner_name"`
OwnerAvatar string `json:"owner_avatar"`
LikeCount int64 `json:"like_count"`
CollectCount int64 `json:"collect_count"`
}
```
前端类型(新增到 `types/models.ts`):
```ts
export interface CommunityOutfitItem {
outfit_uuid: string
outfit_name: string
outfit_desc: string
scene: string
source: number
created_at: number
items: { clothes_uuid: string; processed_image: string }[]
owner_name: string
owner_avatar: string
like_count: number
collect_count: number
}
```
## 设计风格
延续项目既有 iOS HIG 视觉语言:分组灰底 #F2F2F7、纯白卡片(圆角 32rpx)、0.5px 发丝分隔线、系统蓝 #007AFF 强调色、SF Symbols 风格线性图标,清爽克制、以内容为中心,社区分段与现有分段无缝衔接。
## 分段控件
胶囊分段由两项扩展为三项「我的穿搭 / 已收藏 / 社区」,三项等宽;选中项为白色滑块 + 系统蓝加粗文字,未选中为 #3C3C43;切换带轻量过渡,样式沿用现有 .segment 规格(高 64rpx、圆角 16rpx)。
## 社区卡片
- 作者行(新增):左侧 56rpx 圆形头像(无头像回退浅灰底 icon-user 占位),昵称 26rpx 深色单行省略,右侧相对时间 22rpx 灰字
- 封面区:复用现有拼图 cover-item 错落摆放(最多 5 件)+ 右上角件数胶囊
- 信息区:穿搭名 32rpx 加粗单行省略,描述 26rpx 灰字最多两行
- 互动区(meta 行):左侧场景标签(tag-gray)与件数,右侧点赞(icon-heart)与收藏(icon-star)计数,图标 36rpx 灰字 22rpx,间距与现有卡片一致
## 状态设计
加载态复用骨架屏(sk-card 呼吸动画);社区空态复用 empty-state(title「还没有公开的穿搭」,desc「把喜欢的穿搭公开到社区,让大家看到你的搭配」,无按钮);列表底部「没有更多了」提示沿用现有样式;卡片按压态用现有 active 透明度反馈。
## Agent Extensions
### SubAgent
- **code-explorer**
- Purpose: 后端仓库(117 个 Go 文件)实现社区接口前,跨文件梳理 like/collect 数据模型、批量计数与批量组装模式、DTO/Handler 既有写法,确保新代码完全复用现有模式
- Expected outcome: 产出可复用的批量计数 SQL 模式与接口实现要点清单(表名、字段、既有工具函数位置),降低返工与不一致风险