- 新增 4 个 UI 组件: PointsCard/ProductCard/CheckinCalendar/CheckinModal - 商城首页 V2: 积分卡 + 快捷操作 + 分类标签 + 商品网格 - 商品详情 V2: 大图 + 信息卡 + 库存/余额状态 + 底部操作栏 - TabBar 新增商城入口(5 Tab: 首页/健康/商城/助手/我的) - 设计原型 docs/design/mp-05-mall-v2.html + SPEC.md 交付包 - CLAUDE.md 安全规范加固: 新增 §3.7 安全规范 6 条 + Feature DoD 安全清单扩展
184 lines
9.0 KiB
Markdown
184 lines
9.0 KiB
Markdown
# 积分商城 V2 设计规格
|
||
|
||
> 来源: docs/design/mp-05-mall-v2.html | 平台: 微信小程序 (Taro) | 页面数: 3 | 生成: 2026-05-22
|
||
|
||
## 页面索引
|
||
|
||
| 页面 | 截图 | 路由 |
|
||
|------|------|------|
|
||
| 商城主页 |  | /pages/mall/index |
|
||
| 商品详情 |  | /pages/pkg-mall/product/index |
|
||
| 签到成功弹窗 |  | 弹窗 (商城主页内触发) |
|
||
|
||
## 一、Token 映射
|
||
|
||
| 原型值 | 项目 Token | 状态 |
|
||
|--------|-----------|------|
|
||
| #C4623A (T.pri) | `--tk-pri` / `$pri` | ✅ |
|
||
| #F0DDD4 (T.priL) | `--tk-pri-l` / `$pri-l` | ✅ |
|
||
| #8B3E1F (T.priD) | `--tk-pri-d` / `$pri-d` | ✅ |
|
||
| #F5F0EB (T.bg) | `$bg` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #FFFFFF (T.card) | `--tk-card-bg` / `$card` | ✅ |
|
||
| #EDE8E2 (T.surface) | `$surface-alt` (≈卡片白底) | ⚠️ 近似匹配 |
|
||
| #2D2A26 (T.tx) | `$tx` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #5A554F (T.tx2) | `$tx2` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #78716C (T.tx3) | `--tk-text-secondary` / `$tx3` | ✅ |
|
||
| #E8E2DC (T.bd) | `$bd` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #F0EBE5 (T.bdL) | `$bd-l` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #5B7A5E (T.acc) | `$acc` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #E8F0E8 (T.accL) | `$acc-l` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #C4873A (T.wrn) | `$wrn` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #FFF3E0 (T.wrnL) | `$wrn-l` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #B54A4A (T.dan) | `$dan` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| #FDEAEA (T.danL) | `$dan-l` | ⚠️ SCSS 变量,无 CSS Token |
|
||
| 16 (T.r) | `--tk-card-radius` / `$r` | ✅ |
|
||
| 12 (T.rSm) | `$r-sm` | ⚠️ SCSS 变量 |
|
||
| 20 (T.rPill) | `$r-pill` | ⚠️ SCSS 变量 |
|
||
| serif 字体 | `$serif` + `@mixin serif-number` | ⚠️ SCSS mixin |
|
||
| sans 字体 | `$sans` | ⚠️ SCSS 变量 |
|
||
|
||
> 状态标记: ✅ confirmed 直接使用 | ⚠️ pending 需 SCSS 变量引用 | ❌ unmatched 需硬编码或新建 Token
|
||
|
||
## 二、页面结构
|
||
|
||
### 1. 商城主页
|
||
|
||

|
||
|
||
布局层级(从上到下):
|
||
|
||
1. **导航栏** — 返回箭头 + 标题「积分商城」(serif 26px 700)
|
||
2. **积分卡片** — 渐变背景 (`linear-gradient(135deg, $pri, $pri-d)`) + 装饰圆
|
||
- 左侧:标签「我的积分」13px + 余额数字 serif 42px 700 + 连续签到天数 12px
|
||
- 右侧:签到按钮 (pill, `rgba(255,255,255,0.2)` bg + border)
|
||
- 阴影:`0 8px 24px rgba(196,98,58,0.25)`
|
||
3. **快捷操作栏** — 三等分圆形图标(52×52)+ 文字标签
|
||
- 签到打卡:$acc 绿底 + `0 4px 12px rgba(91,122,94,0.3)` 阴影
|
||
- 积分任务:$pri 橙底 + `0 4px 12px rgba(196,98,58,0.3)` 阴影
|
||
- 兑换记录:$wrn 黄底 + `0 4px 12px rgba(196,135,58,0.3)` 阴影
|
||
4. **分割线** — 1px $bd
|
||
5. **分类标签** — Pill tabs(全部/实物/服务券/权益)
|
||
- 默认:$surface 背景 + $tx2 文字
|
||
- 激活:$pri 背景 + #fff 文字 + `0 2px 8px rgba(196,98,58,0.25)` 阴影
|
||
6. **商品网格** — 2列 grid, gap 12px
|
||
- 商品卡片:白底 + $r-sm 圆角 + `0 2px 8px rgba(0,0,0,0.04)` 阴影
|
||
- 商品图:1:1 占位(按 type 分色:physical=$priL, service=$accL, privilege=$wrnL)
|
||
- 标签角标:top:8 left:8, 热门=$dan, 新品=$acc
|
||
- 已兑完遮罩:`rgba(255,255,255,0.7)` + 「已兑完」文字
|
||
- 商品信息:名称 (14px 600, 2行截断, 高40px) + 积分价格 (serif 18px 700 $pri) + 原价划线 ($tx3)
|
||
- 库存紧张标签:$wrnL 背景 + $wrn 文字
|
||
|
||
### 2. 商品详情页
|
||
|
||

|
||
|
||
布局层级(从上到下):
|
||
|
||
1. **导航栏** — 返回箭头 + 标题「商品详情」(17px 600)
|
||
2. **商品大图** — 4:3 比例, 圆角 $r, 按类型分色背景
|
||
3. **商品信息卡** — 白底 + $r 圆角 + padding 20px
|
||
- 类型标签行:tag badge ($dan/$acc) + type badge ($accL bg)
|
||
- 标题:20px 700 $tx
|
||
- 积分价格:serif 28px 700 $pri + 原价划线 14px $tx3
|
||
- 描述:13px $tx3, line-height 1.6
|
||
4. **库存/余额卡** — 白底 + $r 圆角
|
||
- 库存状态行:标签 $tx2 + 值 (充足=$acc / 紧张=$wrn / 售罄=$dan)
|
||
- 积分余额行:标签 $tx2 + 值 (充足=$acc / 不足=$dan)
|
||
5. **温馨提示** — $wrnL 背景 + $wrn 文字, $r-sm 圆角
|
||
6. **底部操作栏** — 固定底部, 白底 + top border $bd
|
||
- 左侧:需要积分 (serif 22px 700 $pri)
|
||
- 右侧:兑换按钮 (pill, 充足=$pri bg+阴影, 不足=$bd bg+$tx3 text, cursor: not-allowed)
|
||
|
||
### 3. 签到成功弹窗
|
||
|
||

|
||
|
||
布局层级:
|
||
|
||
1. **半透明遮罩** — `rgba(0,0,0,0.4)`, 全屏覆盖
|
||
2. **弹窗卡片** — 居中, 宽 320px, 白底 + $r 圆角 + `0 20px 60px rgba(0,0,0,0.15)` 阴影
|
||
- **顶部装饰区** — 渐变背景 ($pri→$priD) + 装饰圆
|
||
- 「签到成功」16px rgba(255,255,255,0.8)
|
||
- 积分数 serif 36px 700 #fff + 「积分」14px
|
||
- 连续天数 13px rgba(255,255,255,0.65)
|
||
- **7天日历** — 7 列等宽 (36×36 圆形)
|
||
- 已签到:$accL bg + 绿色勾 (今日=$pri bg + 2px border + 阴影)
|
||
- 未签到:$surface bg + 6px 灰色圆点
|
||
- 下方标签:周X (11px)
|
||
- **激励提示** — $accL bg + $acc 勾图标 + 文字
|
||
- **关闭按钮** — 全宽 pill, $pri bg + #fff text + 阴影
|
||
|
||
## 三、组件映射
|
||
|
||
| 原型元素 | 推荐组件 | 来源 | 备注 |
|
||
|----------|---------|------|------|
|
||
| 页面容器 | `PageShell` | @components/ui | padding="none" safeBottom=false |
|
||
| 商品卡片 | `ContentCard` | @components/ui | variant="elevated" activeFeedback="opacity" |
|
||
| 分类标签 | `TabFilter` | @components/ui | variant="pill" tabs=[全部,实物,服务券,权益] |
|
||
| 兑换按钮 | `PrimaryButton` | @components/ui | disabled 时灰显 |
|
||
| 库存标签 | `StatusTag` | @components/ui | warning/error/default 状态 |
|
||
| 列表项 | `ListItem` | @components/ui | 商品详情信息行 |
|
||
| 积分卡片区域 | `GradientHeader` | @components/ui | 包裹积分余额展示 |
|
||
| 空数据/加载 | `EmptyState` / `LoadingCard` | @components | 已有 |
|
||
|
||
> ⚠️ **需新建**:
|
||
> - `PointsCard` — 积分余额展示卡(渐变背景 + 装饰圆 + 签到按钮)
|
||
> - `ProductCard` — 商品卡片(图片占位 + 信息区 + 标签 + 库存提示)
|
||
> - `CheckinCalendar` — 7天签到日历(圆形进度点 + 今日高亮)
|
||
> - `CheckinModal` — 签到成功弹窗(遮罩 + 卡片 + 日历 + 关闭)
|
||
|
||
## 四、交互规格
|
||
|
||
| 元素 | 交互 | 触发 | 反馈 | 备注 |
|
||
|------|------|------|------|------|
|
||
| 分类标签 | 切换筛选 | tap tab | 高亮样式切换 + 列表重新渲染 | 调用 `fetchProducts(1, type, true)` |
|
||
| 商品卡片 | 跳转详情 | tap card | opacity 反馈 → `safeNavigateTo` | 库存=0 时 toast「已兑完」 |
|
||
| 签到按钮 | 触发签到 | tap | loading → 成功/失败 toast | 成功后弹出 CheckinModal |
|
||
| 快捷操作 | 跳转页面 | tap icon | opacity 反馈 | 签到打卡 / 积分任务(TODO) / 兑换记录 |
|
||
| 兑换按钮 | 提交兑换 | tap button | loading → 确认弹窗 → 结果 | 积分不足时 disabled |
|
||
| 签到弹窗 | 关闭 | tap「我知道了」 | 弹窗消失 + 刷新积分数据 | 动画 fadeOut |
|
||
| 列表加载 | 上拉加载 | scroll to bottom | Loading 组件追加 | `useReachBottom` + 分页 |
|
||
|
||
## 五、状态变体
|
||
|
||
- **无档案状态**: 显示 EmptyState 组件,提示去建档,隐藏积分卡片和商品列表
|
||
- **空商品列表**: EmptyState icon='礼' text='暂无商品'
|
||
- **已签到**: 签到按钮变为低对比度「已签到」,不可再次点击
|
||
- **库存紧张**: 商品卡片底部显示 $wrnL 标签「仅剩N件」
|
||
- **已兑完**: 商品图区域叠加半透明遮罩 + 「已兑完」文字,点击 toast 提示
|
||
- **积分不足**: 详情页兑换按钮灰显 disabled,余额显示红色「不足」
|
||
|
||
## 六、样式清单
|
||
|
||
### 颜色用法汇总
|
||
- 渐变卡片: `linear-gradient(135deg, $pri, $priD)`
|
||
- 商品类型色: physical=$priL, service=$accL, privilege=$wrnL
|
||
- 标签色: 热门=$dan, 新品=$acc
|
||
- 库存色: 充足=$acc, 紧张=$wrn, 售罄=$dan
|
||
|
||
### 尺寸规格
|
||
- 积分卡片: padding 24px, borderRadius $r (16px)
|
||
- 快捷图标: 52×52 圆形, 间距 space-around
|
||
- 商品卡片: grid 2列, gap 12px, borderRadius $r-sm (12px)
|
||
- 商品图: 1:1 (主页) / 4:3 (详情), borderRadius $r-sm
|
||
- Pill 按钮: borderRadius $r-pill (20px), padding 7px 18px (tabs) / 14px 32px (CTA)
|
||
- 弹窗: 宽 320px, 7天日历项 36×36
|
||
|
||
### 字号规格
|
||
- 积分余额: serif 42px 700 (主页) / 36px 700 (弹窗) / 28px 700 (详情)
|
||
- 页面标题: serif 26px 700
|
||
- 商品名: 14px 600, 2行截断
|
||
- 商品价格: serif 18px 700 $pri
|
||
- 分类标签: 14px (激活 600 / 默认 400)
|
||
- 快捷标签: 12px 500
|
||
- 辅助文字: 13px / 12px / 11px
|
||
|
||
---
|
||
|
||
> 此规格由 design-handoff skill 自动生成。实施时请:
|
||
> 1. 先阅读截图建立视觉印象
|
||
> 2. 按 Token 映射表使用项目 Token(✅ 标记的直接用)
|
||
> 3. 优先使用"组件映射"中列出的已有组件
|
||
> 4. 参考"交互规格"实现对应的交互逻辑
|
||
> 5. "需新建"的组件参考截图和布局描述从头实现
|