first commit

This commit is contained in:
2026-09-11 01:45:04 +08:00
commit 0a8d60d87f
145 changed files with 40978 additions and 0 deletions
@@ -0,0 +1,94 @@
---
name: 穿搭列表卡片显示衣物拼图封面
overview: 修复「穿搭」列表卡片封面空白(只有铃铛占位):后端 OutfitItemResponse 增加 processed_image 字段并返回 CDN 图片 URL;前端 outfit 列表卡片封面改为最多 5 张衣物拼图网格,无图时回退铃铛占位。
todos:
- id: backend-outfit-image
content: 后端 dto/outfit.go 与 service/outfit.go 补 processed_image 组装链
status: completed
- id: backend-collect-image
content: 后端 collect.go 收藏列表 items 返回带图
status: completed
dependencies:
- backend-outfit-image
- id: frontend-cover-collage
content: 前端 models.ts 类型与 outfit 列表封面拼图渲染
status: completed
dependencies:
- backend-outfit-image
- id: verify-build-lint
content: 执行后端 go build 与前端 lint 验证
status: completed
dependencies:
- backend-outfit-image
- backend-collect-image
- frontend-cover-collage
---
## 产品概述
修复「穿搭」列表页卡片封面显示空白的问题:卡片封面目前只有铃铛占位图标和件数角标,应展示该穿搭的衣物平铺拼图(与穿搭详情页的拼图封面风格一致)。
## 核心功能
- 穿搭列表卡片封面展示最多 5 件衣物的抠图平铺拼图,衣物图片缺失时仍显示铃铛占位。
- 已收藏 tab 的穿搭卡片同样展示拼图封面。
- 列表数据一次性从后端带图返回,不在前端逐件请求衣物详情,避免 N+1 网络开销。
- 详情页、AI 推荐结果页等已有页面行为保持不变。
## 技术栈
- 后端:Go(沿用现有 Gin + GORM + COS 上传体系),复用 `upload.GetCosUrl` 将 COS key 转为可访问 CDN URL。
- 前端:微信小程序原生 TypeScript + WXML/WXSS,复用 `outfit-detail` 页已有的拼图封面样式模式。
## 实现方案
### 核心策略
后端在穿搭列表/详情/收藏的 `items` 响应中为每件衣物补充 `processed_image`(可访问 URL),前端列表卡片直接渲染最多 5 张拼图。选择后端带图而非前端逐件请求的理由:列表页每张卡片含多件衣物,前端 N+1 请求代价高;而后端 `buildOutfitListResponses` 本已批量查出全部衣物模型,补图片只是内存组装,无新增 SQL。
### 后端改动(/root/zt-closet-backend,3 个文件)
1. `internal/dto/outfit.go`:`OutfitItemResponse` 增加 `ProcessedImage string \`json:"processed_image"\``(与衣物详情响应字段名保持一致)。
2. `internal/service/outfit.go`:
- 新增 helper `buildOutfitItemResponse(c *mysqlmodel.Clothes) dto.OutfitItemResponse`:组装 `ClothesUUID` + `upload.GetCosUrl(c.ProcessedImage)`(空值不转换),需新增 import `pkg/upload`。
- `resolveOwnedClothes` 返回值改为 `([]int64, []dto.OutfitItemResponse, *errcode.Error)`,利用已查出的 `clothesList` 按请求顺序组装带图 items;`Create` 直接用 items 组装响应;`UpdateByUUID` 调用点以 `_` 忽略 items。
- `itemClothesUUIDs` 改造为 `itemResponses(ctx, outfitID) ([]dto.OutfitItemResponse, error)`:按 `OutfitItem` 明细顺序、`clothesID → Clothes` 映射组装带图 items;`GetByUUID` 相应更新。
- `buildOutfitListResponses`:`uuidByID` 改为 `clothesByID map[int64]mysqlmodel.Clothes`,按 `itemsByOutfit[o.ID]` 顺序组装 items。
- `buildOutfitCreateResponse(o *mysqlmodel.Outfit, items []dto.OutfitItemResponse)` 签名同步调整。
3. `internal/service/collect.go`:`CollectService.itemClothesUUIDs` 同样改为 `itemResponses` 返回带图 items,收藏列表 `/collect` 自动带图;新增 import `pkg/upload`。
### 前端改动(/root/zt-closet-wxmini-frontend,3 个文件)
4. `miniprogram/types/models.ts`:`OutfitItem.items` 数组元素增加 `processed_image: string`。
5. `miniprogram/pages/outfit/outfit.wxml`:`.cover` 内改为拼图网格——`wx:for="{{item.items}}" wx:key="clothes_uuid" wx:if="{{index < 5}}"`,有 `processed_image` 时渲染 `<image mode="aspectFit">`,否则铃铛占位;`items` 为空时保留居中大铃铛;`.cover-count` 件数角标保留。
6. `miniprogram/pages/outfit/outfit.wxss`:新增 `.cover-item`、`.cover-0~4`(absolute 定位 + 轻微旋转)、`.cover-img`、占位样式,尺寸适配 280rpx 高封面(约 150×190rpx 卡片),`.cover` 增加 `overflow: hidden`,风格参照 `outfit-detail.wxss` 17-67 行。
### 兼容性与性能
- `processed_image` 为新增 JSON 字段,向后兼容;详情页 `outfit-detail.ts` 仍需 `name` 字段,保持原 `/clothes/{uuid}` 请求逻辑不变。
- 列表组装维持现有批量查询路径(无 N+1),图片转换仅内存操作;`GetCosUrl` 生成签名 URL 为纯计算,无 IO。
- 衣物图片缺失(抠图失败/未处理)时 `processed_image` 为空,前端自动回退铃铛占位,无异常展示。
## 目录结构
```
/root/zt-closet-backend/
├── internal/dto/outfit.go # [MODIFY] OutfitItemResponse 增加 processed_image 字段
└── internal/service/
├── outfit.go # [MODIFY] helper 与响应组装链带图(Create/GetByUUID/List)
└── collect.go # [MODIFY] 收藏列表 items 带图
/root/zt-closet-wxmini-frontend/miniprogram/
├── types/models.ts # [MODIFY] OutfitItem.items 元素增加 processed_image
└── pages/outfit/
├── outfit.wxml # [MODIFY] 卡片封面改为最多 5 张拼图网格
└── outfit.wxss # [MODIFY] 新增拼图封面样式,适配 280rpx 高卡片
```
## 验证方式
- 后端:`cd /root/zt-closet-backend && go build ./...` 编译通过。
- 前端:对 `models.ts`、`outfit.wxml`、`outfit.wxss` 执行 lint 检查无新错误。
- 手工验证:小程序「穿搭」页两个 tab 的卡片封面应显示衣物拼图;衣物无图的旧数据回退铃铛。