Files
pingxiangcard/docs/superpowers/specs/2026-06-26-ui-ux-standardization-design.md
T
2026-06-26 09:05:59 +08:00

14 KiB
Raw Blame History

UI/UX 标准化设计规范

湖南12301文旅专区微信小程序(C端)
2026-06-26

背景

项目现有 35 个 .vue 文件,存在以下问题:

  • 双 token 系统冲突(uni.scss vs _tokens.scss)
  • 14 个页面自定义局部 SCSS 变量,绕过全局体系
  • 3 套字体族混用(SourceHanSerifCN / Noto Serif SC / 系统字体)
  • 55+ 种硬编码颜色值(4 种品牌蓝、4 种错误红、5 种背景灰)
  • 19 种字号仅 8 种有对应变量
  • 9 种按钮高度
  • mock 数据分散在各页面,格式不统一

目标:统一所有页面的字体、字号、颜色、间距、组件规范,以及 mock 数据管理方式,为后续后端 API 对接做好准备。

已确认的决策

决策项 选择 理由
颜色体系 uni.scss 体系 偏暖偏亮,#3c9cff 主色
字体族 思源宋体系 文化/旅游感强
模拟数据 集中管理 + 类型先行 对接 API 时页面零改动
执行节奏 基础设施先行 → 核心链路 → 剩余页面 风险最小

1. Token 体系统一

1.1 Source of Truth

  • 保留 src/uni.scss 作为唯一 token 文件(uni-app 自动注入到所有 <style lang="scss">)
  • _tokens.scss 中与 uni.scss 冲突的变量值改为直接引用 uni.scss 变量,或删除
  • 禁止任何页面在 <style> 中重新定义 $font、$primary、$text-main 等局部变量

1.2 字号体系

9 级字号,消灭所有游离值:

变量 值 场景
$font-size-xxs 18rpx 辅助标注、库存提示、角标
$font-size-xs 20rpx 标签、小徽标
$font-size-sm 24rpx 次要说明、辅助文字
$font-size-base 28rpx 正文、按钮文字
$font-size-lg 32rpx 卡片标题、区域小标题
$font-size-xl 36rpx 区域标题
$font-size-2xl 44rpx 页面大标题
$font-size-3xl 56rpx 大号展示数字
$font-size-display 72rpx 超大展示(极少使用)

游离值迁移对照:

原值 迁移到 理由
18rpx 新增 $font-size-xxs 使用频率高,值得单独层级
22rpx $font-size-xs (20rpx) 视觉差异极小
26rpx $font-size-base (28rpx) 正文统一 28rpx
30rpx $font-size-lg (32rpx) 卡片标题统一 32rpx
34rpx $font-size-xl (36rpx) 差异极小

1.3 字重

变量 值 场景
$font-weight-normal 400 正文、说明
$font-weight-medium 500 次要标题、按钮
$font-weight-bold 700 主标题、价格数字、强调

禁止使用 CSS 关键字 bold,统一用数字变量。

1.4 行高

变量 值 场景
$line-height-tight 1.25 标题
$line-height-normal 1.5 正文
$line-height-relaxed 1.75 长段落、说明文

2. 颜色体系

2.1 品牌 & 功能色

以 uni.scss 现有值为准,不做修改:

变量 值 用途
$uv-primary #3c9cff 主色/品牌蓝
$uv-error #e53935 错误/危险红
$uv-warning #f9ae3d 警告/橙
$uv-success #5ac725 成功/绿

2.2 中性色(文字 & 背景)

统一灰阶,替代现有 55+ 种硬编码灰值:

变量 值 用途
$color-text-primary #111111 标题、重要正文
$color-text-regular #333333 正文
$color-text-secondary #666666 次要说明
$color-text-placeholder #999999 占位符、禁用文字
$color-text-disabled #cccccc 不可操作文字
$color-bg-page #f3f4f6 页面背景
$color-bg-card #ffffff 卡片/模块背景
$color-bg-hover #f5f5f5 按压态背景
$color-border #eeeeee 分割线、边框

2.3 语义色

订单状态、标签等场景专用:

变量 值 用途
$color-price #e53935 价格红
$color-price-highlight #FFD600 促销亮黄(首页大卡专用)
$color-status-pending #ff9500 待处理/待支付
$color-status-success #00b42a 已完成/已支付
$color-status-cancel #86909c 已取消/已关闭

2.4 透明度规范

暗底白字(5 档):

rgba(255, 255, 255, 0.35)  — 最弱(信任标签等)
rgba(255, 255, 255, 0.55)  — 弱(次要说明)
rgba(255, 255, 255, 0.7)   — 中(描述文字)
rgba(255, 255, 255, 0.85)  — 强(正文)
rgba(255, 255, 255, 0.95)  — 最强(标题)

白底投影(3 档):

rgba(0, 0, 0, 0.04)  — 轻投影(卡片)
rgba(0, 0, 0, 0.08)  — 中投影(浮层)
rgba(0, 0, 0, 0.12)  — 重投影(弹窗)

2.5 硬编码颜色迁移对照

现有硬编码值 迁移到
#111, #1A1A1A, #222 $color-text-primary
#333 $color-text-regular
#666 $color-text-secondary
#999, #888888 $color-text-placeholder
#cccccc, #BBBBBB, #dadbde $color-text-disabled
#e5e7eb, #E2E8F0 $color-border
#f7f8fa, #f5f5f5, #f7f7f7, #FAFAFA, #F8FAFC $color-bg-page
#fff, #ffffff, #FFFFFF $color-bg-card
#e53935, #EF4444, #f53f3f, #E74C3C $uv-error 或 $color-price
#3c9cff, #0052FF, #4A90D9, #4D7CFF $uv-primary
#5ac725, #10B981, #00b42a $uv-success 或 $color-status-success
#f9ae3d, #F59E0B, #ff9500, #ff7d00 $uv-warning 或 $color-status-pending

3. 字体族 & 排版

3.1 字体声明

$font-family-display: 'SourceHanSerifCN', '思源宋体', 'STSong', serif;
$font-family-body: -apple-system, 'PingFang SC', 'Helvetica Neue', sans-serif;
  • $font-family-display:标题、品牌名、卡名等装饰性文字
  • $font-family-body:正文、按钮、表单、说明文字(默认字体,加载快)

全局在 App.vue 中声明 font-family: $font-family-body,仅需要装饰性的元素单独指定 $font-family-display。

3.2 字号场景对照

场景 变量 值
页面大标题 $font-size-2xl 44rpx
区域标题 $font-size-xl 36rpx
卡片标题 $font-size-lg 32rpx
正文/按钮 $font-size-base 28rpx
次要说明 $font-size-sm 24rpx
辅助标注/标签 $font-size-xs 20rpx
极小文字/角标 $font-size-xxs 18rpx

4. 组件规范

4.1 按钮

从 9 种高度收敛到 3 种:

尺寸 高度 字号 场景
sm 64rpx $font-size-sm (24rpx) 列表内操作、小按钮
md 80rpx $font-size-base (28rpx) 页面内主要操作
lg 96rpx $font-size-lg (32rpx) 底部固定栏、支付按钮
  • 统一圆角 $radius-full(胶囊形)
  • 主操作:$uv-primary 填充色 + 白色文字
  • 次要操作:描边样式(border $uv-primary + $uv-primary 文字)
  • 按压态:transform: scale(0.95) + transition: transform $transition-fast

4.2 卡片

圆角:$radius-lg (24rpx)
投影:$shadow-base → 0 4rpx 16rpx rgba(0, 0, 0, 0.04)
内边距:$spacing-4 (32rpx)
卡片间距:$spacing-3 (24rpx)
背景:$color-bg-card (#ffffff)

4.3 箭头/Chevron

统一一种实现:

  • 尺寸:12rpx × 12rpx
  • border-width:2rpx
  • 颜色:$color-text-placeholder
  • 右箭头:transform: rotate(45deg)
  • 下箭头:transform: rotate(135deg)

4.4 间距规则

只允许使用以下变量,禁止硬编码间距值:

变量 值 场景
$spacing-1 8rpx 图标与文字间隙
$spacing-2 16rpx 紧凑元素间距
$spacing-3 24rpx 列表项间距、卡片间距
$spacing-4 32rpx 区域内容边距
$spacing-5 40rpx 区块间距
$spacing-6 48rpx 页面顶部/底部安全区
$spacing-8 64rpx 大区块分隔

4.5 圆角规则

变量 值 场景
$radius-sm 8rpx 标签、小徽标
$radius-md 16rpx 输入框、小卡片
$radius-lg 24rpx 卡片、弹窗
$radius-full 9999rpx 胶囊按钮、圆形头像

4.6 投影规则

变量 值 场景
$shadow-sm 0 2rpx 8rpx rgba(0,0,0,0.04) 轻投影
$shadow-base 0 4rpx 16rpx rgba(0,0,0,0.04) 卡片默认
$shadow-lg 0 8rpx 32rpx rgba(0,0,0,0.08) 浮层、弹窗

4.7 过渡动画

变量 值 场景
$transition-fast 150ms ease 按压、hover
$transition-base 250ms ease 展开/收起、淡入淡出

禁止使用 0.15s ease、0.2s ease 等硬编码值。


5. 类型定义 & Mock 数据

5.1 文件结构

src/
├── api/
│   ├── types.ts              # 所有业务类型(唯一来源)
│   ├── request.ts            # HTTP 封装(已有,不动)
│   ├── scenic.ts             # 景区接口
│   ├── card.ts               # 年卡接口
│   ├── order.ts              # 订单接口
│   ├── user.ts               # 用户接口(已有,补充类型)
│   └── reserve.ts            # 预约接口
├── mock/
│   ├── index.ts              # 统一导出 + USE_MOCK 开关
│   ├── scenic.ts             # 景区 mock
│   ├── card.ts               # 年卡 mock
│   ├── order.ts              # 订单 mock
│   ├── reserve.ts            # 预约记录 mock
│   ├── notice.ts             # 公告 mock
│   └── images.ts             # 占位图片 URL 常量

5.2 types.ts 业务类型

interface Scenic {
  id: number
  name: string
  cover: string
  address: string
  lat: number
  lng: number
  openTime: string
  description: string
  ticketPrice: number
  freeTimes: number
}

interface ScenicSession {
  id: number
  scenicId: number
  date: string
  startTime: string
  endTime: string
  stock: number
  remainStock: number
}

interface Card {
  id: number
  name: string
  price: number
  originalPrice: number
  cover: string
  benefits: string
  scenicIds: number[]
}

interface Order {
  id: number
  cardId: number
  cardName: string
  amount: number
  status: 'pending' | 'paid' | 'cancelled' | 'closed'
  payTime: string | null
  createTime: string
}

interface OrderDetail extends Order {
  orderNo: string
  userId: number
  userName: string
  phone: string
  payMethod: string
}

interface ReserveRecord {
  id: number
  scenicId: number
  scenicName: string
  date: string
  session: string
  status: 'pending' | 'confirmed' | 'cancelled' | 'used'
}

interface Notice {
  id: number
  title: string
  content: string
  publishTime: string
  isTop: boolean
}

interface QuickAction {
  id: number
  icon: string
  label: string
  path: string
}

interface Announcement {
  id: number
  title: string
  content: string
}

5.3 Mock 切换机制

// mock/index.ts
export const USE_MOCK = import.meta.env.VITE_USE_MOCK === 'true'

// api/scenic.ts
import { USE_MOCK } from '@/mock'
import { mockScenicList } from '@/mock/scenic'
import type { Scenic[] } from './types'

export function getScenicList(): Promise<Scenic[]> {
  if (USE_MOCK) return Promise.resolve(mockScenicList)
  return request.get('/mp-api/scenic/list')
}
  • .env 文件中 VITE_USE_MOCK=true 控制开关
  • 对接 API 时改为 false,页面代码零改动

5.4 占位图片规范

统一收到 mock/images.ts:

export const IMG_SCENIC_COVER = 'https://images.unsplash.com/...'
export const IMG_AVATAR = 'https://...'
export const IMG_CARD_BANNER = 'https://...'
// ...

对接 API 后这些常量直接废弃,不影响页面代码。


6. 执行计划

第1步:基础设施(不改任何页面)

序号 任务 验证方式
1.1 清理 uni.scss:补齐 $font-size-xxs、语义色、行高、字体族变量 编译通过
1.2 处理 _tokens.scss:冲突值改为引用 uni.scss 或删除 编译通过,无变量冲突
1.3 api/types.ts 补全所有业务 interface pnpm run type-check 通过
1.4 创建 src/mock/ 目录,迁移所有硬编码数据,实现 USE_MOCK 开关 mock 数据可正常 import
1.5 App.vue 全局字体声明统一为 $font-family-body 构建预览正常
1.6 删除 14 个页面中的局部 $font、$primary、$text-main 等变量声明 编译通过

第2步:核心链路迁移(4 个页面)

迁移页面:首页 → 年卡列表 → 年卡详情 → 购买/订单

每页迁移清单:

  1. 删除局部 SCSS 变量,改用全局 token
  2. 硬编码颜色值 → 全局变量
  3. 硬编码字号 → 对应 $font-size-* 变量
  4. 硬编码间距 → 对应 $spacing-* 变量
  5. 模板中硬编码数据 → import mock 数据
  6. 组件样式对齐规范(按钮高度、卡片圆角、箭头样式)

验证:pnpm run dev:mp-weixin 构建 + 微信开发者工具预览,确认视觉无回退。

第3步:剩余页面迁移(~27 个页面)

  • 同样 6 项清单逐页执行
  • 分包页面(packages/user/pages/card/)6 个文件同步处理
  • 纯 CSS 组件(card-item.vue、empty-state.vue、McGlass.vue)改为 SCSS + 全局变量

7. 迁移规则(禁止项)

  • ❌ 禁止在 <style> 中定义 $font、$primary、$text-main 等局部变量
  • ❌ 禁止使用 font-weight: bold 关键字,必须用 $font-weight-bold
  • ❌ 禁止硬编码颜色值(如 #333、#666),必须用全局变量
  • ❌ 禁止硬编码间距值(如 padding: 20rpx),必须用 $spacing-*
  • ❌ 禁止在页面中硬编码业务数据,必须从 mock/ 或 api/ import
  • ❌ 禁止使用 0.15s ease 等硬编码过渡值,必须用 $transition-*