17 tasks across 3 phases: - Phase 1 (Tasks 1-8): Infrastructure (tokens, types, mock, cleanup) - Phase 2 (Tasks 9-12): Core pages (index, card list/detail, buy) - Phase 3 (Tasks 13-17): Remaining pages and components Co-Authored-By: Claude <noreply@anthropic.com>
1265 lines
36 KiB
Markdown
1265 lines
36 KiB
Markdown
# UI/UX 标准化实施计划
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** 统一所有页面的设计 token、类型定义和 mock 数据管理,为后端 API 对接做好准备。
|
||
|
||
**Architecture:** 分三步执行。第1步建立基础设施(token 统一 + 类型 + mock 层),不改任何页面视觉。第2步迁移核心链路(首页→年卡→购买→订单)。第3步迁移剩余页面和组件。
|
||
|
||
**Tech Stack:** uni-app 3.0 + Vue 3 + TypeScript + Pinia + SCSS
|
||
|
||
## Global Constraints
|
||
|
||
- 颜色体系统一使用 `uni.scss` 的 `$uv-*` 变量(`$uv-primary: #3c9cff`)
|
||
- 字体族:标题 `$font-family-display`(思源宋体),正文 `$font-family-body`(系统字体)
|
||
- 禁止在页面 `<style>` 中定义局部 `$font`、`$primary`、`$text-main` 等变量
|
||
- 禁止 `font-weight: bold` 关键字,必须用 `$font-weight-bold`
|
||
- 禁止硬编码颜色值(如 `#333`),必须用全局变量
|
||
- 禁止硬编码间距值(如 `padding: 20rpx`),必须用 `$spacing-*`
|
||
- 禁止在页面中硬编码业务数据,必须从 `mock/` 或 `api/` import
|
||
- 验证方式:`pnpm run dev:mp-weixin` 构建通过 + `pnpm run type-check` 通过
|
||
|
||
## File Structure
|
||
|
||
### 新建文件
|
||
```
|
||
src/mock/index.ts — USE_MOCK 开关
|
||
src/mock/images.ts — 占位图片 URL 常量
|
||
src/mock/scenic.ts — 景区 mock(42 条)
|
||
src/mock/scenic-detail.ts — 景区详情 mock(8 条)
|
||
src/mock/order.ts — 订单 mock(6 条)
|
||
src/mock/reserve.ts — 预约记录 mock(6 条)
|
||
src/mock/notice.ts — 公告 mock(5 条)
|
||
src/mock/store.ts — Mock 内存状态管理
|
||
src/api/scenic.ts — 景区 API 函数
|
||
src/api/order.ts — 订单 API 函数
|
||
src/api/reserve.ts — 预约 API 函数
|
||
```
|
||
|
||
### 修改文件
|
||
```
|
||
src/uni.scss — 新增缺失变量
|
||
src/styles/_tokens.scss — 对齐 uni.scss 值
|
||
src/api/types.ts — 补全业务类型
|
||
src/App.vue — 全局样式
|
||
.env.local / .env.dev / .env.uat — 新增 VITE_USE_MOCK
|
||
9 个页面 — 删除局部 SCSS 变量
|
||
~25 个页面/组件 — 迁移硬编码值
|
||
```
|
||
|
||
---
|
||
|
||
# Phase 1: 基础设施(不改页面视觉)
|
||
|
||
---
|
||
|
||
### Task 1: 更新 uni.scss — 补齐缺失变量
|
||
|
||
**Files:**
|
||
- Modify: `src/uni.scss:71-83`(字号区域)
|
||
- Modify: `src/uni.scss:51`(`$uv-tips-color` 后插入 `$uv-placeholder-color`)
|
||
- Modify: `src/uni.scss:65-67`(渐变后插入语义色)
|
||
|
||
**Interfaces:**
|
||
- Produces: `$font-size-xxs`, `$font-size-4xl`, `$uv-placeholder-color`, `$color-price`, `$color-price-highlight`, `$color-status-pending`, `$color-status-success`, `$color-status-cancel`
|
||
|
||
- [ ] **Step 1: 新增 `$font-size-xxs` 和 `$font-size-4xl`**
|
||
|
||
在 `src/uni.scss` 的字号区域(第 75 行 `$font-size-xs` 之前),插入:
|
||
|
||
```scss
|
||
$font-size-xxs: 18rpx;
|
||
```
|
||
|
||
在 `$font-size-3xl: 56rpx;`(第 82 行)之后、`$font-size-display: 72rpx;` 之前,插入:
|
||
|
||
```scss
|
||
$font-size-4xl: 64rpx;
|
||
```
|
||
|
||
- [ ] **Step 2: 新增 `$uv-placeholder-color`**
|
||
|
||
在 `$uv-tips-color: #666666;`(第 51 行)之后插入:
|
||
|
||
```scss
|
||
$uv-placeholder-color: #999999;
|
||
```
|
||
|
||
- [ ] **Step 3: 新增语义色变量**
|
||
|
||
在 `$gradient-accent` 定义(第 67 行)之后插入:
|
||
|
||
```scss
|
||
// Semantic colors (价格/状态)
|
||
$color-price: $uv-error;
|
||
$color-price-highlight: #FFD600;
|
||
$color-status-pending: #ff9500;
|
||
$color-status-success: #00b42a;
|
||
$color-status-cancel: #86909c;
|
||
```
|
||
|
||
- [ ] **Step 4: 修改 `$font-family-body`**
|
||
|
||
将第 72 行:
|
||
```scss
|
||
$font-family-body: 'SourceHanSerifCN', '思源宋体', -apple-system, 'PingFang SC', sans-serif;
|
||
```
|
||
改为:
|
||
```scss
|
||
$font-family-body: -apple-system, 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||
```
|
||
|
||
- [ ] **Step 5: 验证编译**
|
||
|
||
Run: `pnpm run dev:mp-weixin`
|
||
Expected: 构建成功,无 SCSS 编译错误
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add src/uni.scss
|
||
git commit -m "feat(tokens): add missing variables to uni.scss
|
||
|
||
- \$font-size-xxs (18rpx), \$font-size-4xl (64rpx)
|
||
- \$uv-placeholder-color (#999999)
|
||
- Semantic colors: \$color-price, \$color-status-*
|
||
- Change \$font-family-body to system fonts"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 2: 对齐 _tokens.scss 与 uni.scss
|
||
|
||
**Files:**
|
||
- Modify: `src/styles/_tokens.scss`(全文替换变量值)
|
||
|
||
**Interfaces:**
|
||
- Consumes: Task 1 产生的所有 uni.scss 变量
|
||
- Produces: 与 uni.scss 值一致的 `_tokens.scss`
|
||
|
||
- [ ] **Step 1: 替换 _tokens.scss 全文**
|
||
|
||
将 `src/styles/_tokens.scss` 全文替换为以下内容(所有颜色值对齐 uni.scss,字体对齐思源宋体系):
|
||
|
||
```scss
|
||
// ============================================
|
||
// Design Tokens — Aligned with uni.scss
|
||
// ============================================
|
||
// ⚠️ 所有值必须与 src/uni.scss 保持一致
|
||
// uni.scss 是 source of truth,此文件仅为 main.scss 的兼容层
|
||
|
||
// === COLORS ===
|
||
|
||
// Brand accent
|
||
$color-accent: #3c9cff;
|
||
$color-accent-secondary: #398ade;
|
||
$color-accent-foreground: #FFFFFF;
|
||
|
||
// Semantic
|
||
$color-success: #5ac725;
|
||
$color-warning: #f9ae3d;
|
||
$color-error: #e53935;
|
||
|
||
// Neutrals
|
||
$color-background: #f3f4f6;
|
||
$color-foreground: #111111;
|
||
$color-muted: #f4f4f5;
|
||
$color-muted-foreground: #333333;
|
||
$color-border: #eeeeee;
|
||
$color-card: #FFFFFF;
|
||
$color-ring: #3c9cff;
|
||
|
||
// Semantic (价格/状态)
|
||
$color-price: #e53935;
|
||
$color-price-highlight: #FFD600;
|
||
$color-status-pending: #ff9500;
|
||
$color-status-success: #00b42a;
|
||
$color-status-cancel: #86909c;
|
||
|
||
// Gradients
|
||
$gradient-accent: linear-gradient(135deg, #{$color-accent}, #{$color-accent-secondary});
|
||
|
||
// === TYPOGRAPHY ===
|
||
|
||
$font-family-display: 'SourceHanSerifCN', '思源宋体', serif;
|
||
$font-family-body: -apple-system, 'PingFang SC', 'Helvetica Neue', sans-serif;
|
||
$font-family-mono: 'Menlo', 'Monaco', 'Courier New', monospace;
|
||
|
||
$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-title: 38rpx;
|
||
$font-size-2xl: 44rpx;
|
||
$font-size-3xl: 56rpx;
|
||
$font-size-4xl: 64rpx;
|
||
$font-size-display: 72rpx;
|
||
|
||
$font-weight-normal: 400;
|
||
$font-weight-medium: 500;
|
||
$font-weight-bold: 700;
|
||
|
||
$line-height-tight: 1.2;
|
||
$line-height-normal: 1.5;
|
||
$line-height-relaxed: 1.75;
|
||
|
||
// === SPACING (rpx) ===
|
||
|
||
$spacing-0: 0;
|
||
$spacing-1: 8rpx;
|
||
$spacing-2: 16rpx;
|
||
$spacing-3: 24rpx;
|
||
$spacing-4: 32rpx;
|
||
$spacing-5: 40rpx;
|
||
$spacing-6: 48rpx;
|
||
$spacing-8: 64rpx;
|
||
$spacing-10: 80rpx;
|
||
$spacing-12: 96rpx;
|
||
$spacing-16: 128rpx;
|
||
$spacing-20: 160rpx;
|
||
|
||
// === BORDER RADIUS ===
|
||
|
||
$radius-sm: 8rpx;
|
||
$radius-base: 16rpx;
|
||
$radius-lg: 24rpx;
|
||
$radius-xl: 32rpx;
|
||
$radius-2xl: 48rpx;
|
||
$radius-full: 9999rpx;
|
||
|
||
// === SHADOWS ===
|
||
|
||
$shadow-sm: 0 2rpx 8rpx rgba(15, 23, 42, 0.04);
|
||
$shadow-base: 0 4rpx 16rpx rgba(15, 23, 42, 0.08);
|
||
$shadow-lg: 0 8rpx 32rpx rgba(15, 23, 42, 0.12);
|
||
$shadow-xl: 0 16rpx 48rpx rgba(15, 23, 42, 0.16);
|
||
$shadow-accent: 0 8rpx 24rpx rgba(60, 156, 255, 0.25);
|
||
|
||
// === TRANSITIONS ===
|
||
|
||
$transition-fast: 150ms ease;
|
||
$transition-base: 250ms ease;
|
||
$transition-slow: 400ms ease;
|
||
|
||
// === Z-INDEX ===
|
||
|
||
$z-base: 0;
|
||
$z-dropdown: 100;
|
||
$z-sticky: 200;
|
||
$z-modal: 300;
|
||
$z-toast: 400;
|
||
|
||
// === BORDER ===
|
||
|
||
$border-width: 1rpx;
|
||
|
||
// ============================================
|
||
// Legacy $uni-* compatibility (for uni-ui)
|
||
// ============================================
|
||
|
||
$uni-color-primary: $color-accent;
|
||
$uni-color-success: $color-success;
|
||
$uni-color-warning: $color-warning;
|
||
$uni-color-error: $color-error;
|
||
$uni-text-color: $color-foreground;
|
||
$uni-text-color-inverse: #FFFFFF;
|
||
$uni-text-color-grey: $color-muted-foreground;
|
||
$uni-text-color-placeholder: #999999;
|
||
$uni-text-color-disable: #c8c9cc;
|
||
$uni-bg-color: $color-background;
|
||
$uni-bg-color-grey: $color-muted;
|
||
$uni-bg-color-hover: #f1f1f1;
|
||
$uni-bg-color-mask: rgba(0, 0, 0, 0.4);
|
||
$uni-border-color: $color-border;
|
||
$uni-font-size-sm: $font-size-sm;
|
||
$uni-font-size-base: $font-size-base;
|
||
$uni-font-size-lg: $font-size-lg;
|
||
$uni-font-size-title: 40rpx;
|
||
$uni-font-size-subtitle: $font-size-xl;
|
||
$uni-font-size-paragraph: $font-size-base;
|
||
$uni-img-size-sm: 40rpx;
|
||
$uni-img-size-base: 52rpx;
|
||
$uni-img-size-lg: 80rpx;
|
||
$uni-border-radius-sm: $radius-sm;
|
||
$uni-border-radius-base: $radius-base;
|
||
$uni-border-radius-lg: $radius-lg;
|
||
$uni-border-radius-circle: 50%;
|
||
$uni-spacing-row-sm: 10rpx;
|
||
$uni-spacing-row-base: 20rpx;
|
||
$uni-spacing-row-lg: 30rpx;
|
||
$uni-spacing-col-sm: 8rpx;
|
||
$uni-spacing-col-base: 16rpx;
|
||
$uni-spacing-col-lg: 24rpx;
|
||
$uni-opacity-disabled: 0.3;
|
||
$uni-color-title: $color-foreground;
|
||
$uni-color-subtitle: $color-muted-foreground;
|
||
$uni-color-paragraph: $color-muted-foreground;
|
||
```
|
||
|
||
- [ ] **Step 2: 验证编译**
|
||
|
||
Run: `pnpm run dev:mp-weixin`
|
||
Expected: 构建成功,`main.scss` 中的 `$color-background`、`$color-foreground`、`$font-family-body` 使用新值
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add src/styles/_tokens.scss
|
||
git commit -m "refactor(tokens): align _tokens.scss with uni.scss values
|
||
|
||
All color, typography, and spacing values now match uni.scss.
|
||
Added semantic colors and \$font-size-xxs/\$font-size-4xl."
|
||
```
|
||
|
||
---
|
||
|
||
### Task 3: 扩展 types.ts 业务类型
|
||
|
||
**Files:**
|
||
- Modify: `src/api/types.ts`
|
||
|
||
**Interfaces:**
|
||
- Produces: `ScenicSession`, `ReserveRecord`, `Notice`, `QuickAction`, `Announcement`, `PageResult<T>`, `PageQuery`, `OrderDetail`, `FaqItem`
|
||
|
||
- [ ] **Step 1: 在 types.ts 末尾追加新类型**
|
||
|
||
在 `src/api/types.ts` 文件末尾(`MockPayResult` 接口之后)追加:
|
||
|
||
```typescript
|
||
/** 景区场次 */
|
||
export interface ScenicSession {
|
||
id: number
|
||
scenicId: number
|
||
date: string
|
||
startTime: string
|
||
endTime: string
|
||
stock: number
|
||
remainStock: number
|
||
}
|
||
|
||
/** 预约记录 */
|
||
export interface ReserveRecord {
|
||
id: number
|
||
scenicId: number
|
||
scenicName: string
|
||
date: string
|
||
session: string
|
||
status: 'pending' | 'confirmed' | 'cancelled' | 'used'
|
||
userName?: string
|
||
maskedId?: string
|
||
cardType?: string
|
||
cardNo?: string
|
||
applyTime?: string
|
||
cancelTime?: string
|
||
verifyTime?: string
|
||
verifyPhoto?: string
|
||
}
|
||
|
||
/** 公告 */
|
||
export interface Notice {
|
||
id: number
|
||
title: string
|
||
content: string
|
||
body?: string
|
||
publishTime: string
|
||
isTop: boolean
|
||
}
|
||
|
||
/** 首页快捷入口 */
|
||
export interface QuickAction {
|
||
id: number
|
||
icon: string
|
||
label: string
|
||
path: string
|
||
}
|
||
|
||
/** 首页弹窗公告 */
|
||
export interface Announcement {
|
||
id: number
|
||
type?: string
|
||
typeLabel?: string
|
||
title: string
|
||
date?: string
|
||
content: string
|
||
body?: string
|
||
}
|
||
|
||
/** 订单详情 */
|
||
export interface OrderDetail extends OrderInfo {
|
||
orderNo?: string
|
||
payTime?: string
|
||
payChannel?: string
|
||
redeemCode?: string
|
||
activatedTime?: string
|
||
refundedTime?: string
|
||
originalPrice?: number
|
||
cardType?: string
|
||
}
|
||
|
||
/** FAQ 条目 */
|
||
export interface FaqItem {
|
||
q: string
|
||
a: Array<{ text: string; highlight?: boolean; copy?: string }>
|
||
}
|
||
|
||
/** 分页结果 */
|
||
export interface PageResult<T> {
|
||
list: T[]
|
||
total: number
|
||
page: number
|
||
pageSize: number
|
||
}
|
||
|
||
/** 分页请求参数 */
|
||
export interface PageQuery {
|
||
page: number
|
||
pageSize: number
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 验证类型检查**
|
||
|
||
Run: `pnpm run type-check`
|
||
Expected: 无类型错误
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add src/api/types.ts
|
||
git commit -m "feat(types): add ScenicSession, ReserveRecord, Notice, FaqItem, PageResult types"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 4: 创建 Mock 基础设施
|
||
|
||
**Files:**
|
||
- Create: `src/mock/index.ts`
|
||
- Create: `src/mock/images.ts`
|
||
- Create: `src/mock/store.ts`
|
||
- Modify: `.env.local`, `.env.dev`, `.env.uat`
|
||
|
||
**Interfaces:**
|
||
- Produces: `USE_MOCK` 常量、占位图片常量、`orderStore`/`reserveStore` 响应式数据
|
||
|
||
- [ ] **Step 1: 添加环境变量**
|
||
|
||
在 `.env.local`、`.env.dev`、`.env.uat` 末尾各追加一行:
|
||
|
||
```
|
||
VITE_USE_MOCK=true
|
||
```
|
||
|
||
- [ ] **Step 2: 创建 `src/mock/index.ts`**
|
||
|
||
```typescript
|
||
/** Mock 数据开关 — 由 .env 文件的 VITE_USE_MOCK 控制 */
|
||
export const USE_MOCK = import.meta.env.VITE_USE_MOCK === 'true'
|
||
```
|
||
|
||
- [ ] **Step 3: 创建 `src/mock/images.ts`**
|
||
|
||
从现有页面中收集所有 Unsplash URL,集中管理。实现时从 `src/pages/index/index.vue`、`src/pages/scenic-list/` 等文件提取所有图片 URL,按用途命名:
|
||
|
||
```typescript
|
||
// 景区封面占位图
|
||
export const IMG_SCENIC_1 = 'https://images.unsplash.com/...' // 从 index.vue hotSpots 提取
|
||
export const IMG_SCENIC_2 = 'https://images.unsplash.com/...'
|
||
// ... 每个现有 Unsplash URL 对应一个常量
|
||
|
||
// 头像占位图
|
||
export const IMG_AVATAR_DEFAULT = 'https://...'
|
||
|
||
// 年卡 Banner
|
||
export const IMG_CARD_BANNER = 'https://...'
|
||
|
||
// 通用占位
|
||
export const IMG_PLACEHOLDER = 'https://...'
|
||
```
|
||
|
||
> 实现时从各页面 `<script>` 中提取实际的 Unsplash URL,不要发明新 URL。
|
||
|
||
- [ ] **Step 4: 创建 `src/mock/store.ts`**
|
||
|
||
```typescript
|
||
import { ref } from 'vue'
|
||
import type { OrderInfo, ReserveRecord } from '@/api/types'
|
||
import { mockOrders } from './order'
|
||
import { mockReserves } from './reserve'
|
||
|
||
export const orderStore = ref<OrderInfo[]>([...mockOrders])
|
||
export const reserveStore = ref<ReserveRecord[]>([...mockReserves])
|
||
|
||
export function updateOrderStatus(orderId: string, status: OrderInfo['status']) {
|
||
const order = orderStore.value.find(o => o.id === orderId)
|
||
if (order) order.status = status
|
||
}
|
||
|
||
export function addReserve(record: Omit<ReserveRecord, 'id'>) {
|
||
const id = Math.max(...reserveStore.value.map(r => r.id), 0) + 1
|
||
reserveStore.value.push({ ...record, id })
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 5: 验证**
|
||
|
||
Run: `pnpm run type-check`
|
||
Expected: mock 文件无类型错误
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
```bash
|
||
git add src/mock/ .env.local .env.dev .env.uat
|
||
git commit -m "feat(mock): create mock infrastructure with USE_MOCK switch"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 5: 迁移 Mock 数据到 mock/ 目录
|
||
|
||
**Files:**
|
||
- Create: `src/mock/scenic.ts` — 从 `scenic-list.vue` 提取 42 条景区数据
|
||
- Create: `src/mock/scenic-detail.ts` — 从 `scenic-detail.vue` 提取 8 条详情
|
||
- Create: `src/mock/order.ts` — 从 `order-list.vue` 提取 6 条订单
|
||
- Create: `src/mock/reserve.ts` — 从 `reserve-list.vue` 提取 6 条预约
|
||
- Create: `src/mock/notice.ts` — 从 `notice-list.vue` 提取 5 条公告
|
||
|
||
**Interfaces:**
|
||
- Consumes: Task 3 的 `Scenic`, `OrderInfo`, `ReserveRecord`, `Notice` 类型
|
||
- Produces: `mockScenicList`, `mockScenicDetails`, `mockOrders`, `mockReserves`, `mockNotices`
|
||
|
||
- [ ] **Step 1: 创建 `src/mock/scenic.ts`**
|
||
|
||
从 `src/pages/scenic-list/scenic-list.vue` 第 247-337 行提取 `scenicList` 数组和筛选选项(`regionOptions`、`levelOptions`、`cardTypeOptions`),转换为符合 `ScenicSpot` 类型。
|
||
|
||
> **类型对齐注意**:现有 `ScenicSpot` 的 `id` 是 `string` 类型。如果 scenic-list.vue 中使用数字 id,在 mock 中转为 `String(id)`。保持 `ScenicSpot` 接口不变,后续对接 API 时再统一调整。
|
||
|
||
```typescript
|
||
import type { ScenicSpot } from '@/api/types'
|
||
import { IMG_SCENIC_1 /* ... */ } from './images'
|
||
|
||
export const mockScenicList: ScenicSpot[] = [
|
||
// 从 scenic-list.vue 提取的 42 条数据
|
||
// 保持原始字段值,image 字段使用 images.ts 常量
|
||
]
|
||
|
||
export const regionOptions = [
|
||
// 从 scenic-list.vue 提取
|
||
]
|
||
|
||
export const levelOptions = [
|
||
// 从 scenic-list.vue 提取
|
||
]
|
||
```
|
||
|
||
> 实现时逐条复制 scenic-list.vue 中的数据,确保 42 条完整。
|
||
|
||
- [ ] **Step 2: 创建 `src/mock/scenic-detail.ts`**
|
||
|
||
从 `src/pages/scenic-detail/scenic-detail.vue` 第 172-181 行提取 `scenicData` 数组(8 条详情)。
|
||
|
||
- [ ] **Step 3: 创建 `src/mock/order.ts`**
|
||
|
||
从 `src/pages/order/order-list.vue` 第 151-158 行提取 `orders` 数组(6 条订单)。
|
||
|
||
```typescript
|
||
import type { OrderDetail } from '@/api/types'
|
||
|
||
export const mockOrders: OrderDetail[] = [
|
||
// 从 order-list.vue 提取的 6 条数据
|
||
]
|
||
```
|
||
|
||
- [ ] **Step 4: 创建 `src/mock/reserve.ts`**
|
||
|
||
从 `src/pages/reserve/reserve-list.vue` 第 228-235 行提取 `records` 数组(6 条预约记录)。
|
||
|
||
- [ ] **Step 5: 创建 `src/mock/notice.ts`**
|
||
|
||
从 `src/pages/notice-list/notice-list.vue` 第 47-53 行提取 `notices` 数组(5 条公告)。
|
||
|
||
- [ ] **Step 6: 验证类型检查**
|
||
|
||
Run: `pnpm run type-check`
|
||
Expected: 所有 mock 文件类型正确
|
||
|
||
- [ ] **Step 7: Commit**
|
||
|
||
```bash
|
||
git add src/mock/
|
||
git commit -m "feat(mock): extract all hardcoded data into mock/ modules
|
||
|
||
- scenic: 42 items from scenic-list.vue
|
||
- scenic-detail: 8 items from scenic-detail.vue
|
||
- order: 6 items from order-list.vue
|
||
- reserve: 6 items from reserve-list.vue
|
||
- notice: 5 items from notice-list.vue"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 6: 创建 API 函数层
|
||
|
||
**Files:**
|
||
- Create: `src/api/scenic.ts`
|
||
- Create: `src/api/order.ts`
|
||
- Create: `src/api/reserve.ts`
|
||
|
||
**Interfaces:**
|
||
- Consumes: Task 4 的 `USE_MOCK`、Task 5 的 mock 数据、Task 3 的类型
|
||
- Produces: `getScenicList()`, `getScenicDetail()`, `getOrderList()`, `getOrderDetail()`, `getReserveList()` 等函数
|
||
|
||
- [ ] **Step 1: 创建 `src/api/scenic.ts`**
|
||
|
||
```typescript
|
||
import { USE_MOCK } from '@/mock'
|
||
import { mockScenicList } from '@/mock/scenic'
|
||
import { mockScenicDetails } from '@/mock/scenic-detail'
|
||
import type { ScenicSpot } from './types'
|
||
import { get } from './request'
|
||
|
||
/** 获取景区列表 */
|
||
export function getScenicList(): Promise<ScenicSpot[]> {
|
||
if (USE_MOCK) return Promise.resolve(mockScenicList)
|
||
return get<ScenicSpot[]>('/mp-api/scenic/list')
|
||
}
|
||
|
||
/** 获取景区详情 */
|
||
export function getScenicDetail(id: string): Promise<ScenicSpot | undefined> {
|
||
if (USE_MOCK) {
|
||
return Promise.resolve(mockScenicDetails.find(s => s.id === id))
|
||
}
|
||
return get<ScenicSpot>(`/mp-api/scenic/detail?id=${id}`)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 创建 `src/api/order.ts`**
|
||
|
||
```typescript
|
||
import { USE_MOCK } from '@/mock'
|
||
import { mockOrders } from '@/mock/order'
|
||
import { orderStore } from '@/mock/store'
|
||
import type { OrderDetail, OrderInfo, CreateOrderParams, MockPayResult } from './types'
|
||
import { get, post } from './request'
|
||
|
||
/** 获取订单列表 */
|
||
export function getOrderList(): Promise<OrderInfo[]> {
|
||
if (USE_MOCK) return Promise.resolve(orderStore.value)
|
||
return get<OrderInfo[]>('/mp-api/order/list')
|
||
}
|
||
|
||
/** 获取订单详情 */
|
||
export function getOrderDetail(id: string): Promise<OrderDetail | undefined> {
|
||
if (USE_MOCK) {
|
||
return Promise.resolve(mockOrders.find(o => o.id === id))
|
||
}
|
||
return get<OrderDetail>(`/mp-api/order/detail?id=${id}`)
|
||
}
|
||
|
||
/** 创建订单 */
|
||
export function createOrder(params: CreateOrderParams): Promise<{ orderId: string }> {
|
||
if (USE_MOCK) {
|
||
return Promise.resolve({ orderId: `mock_${Date.now()}` })
|
||
}
|
||
return post<{ orderId: string }>('/mp-api/order/create', params)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: 创建 `src/api/reserve.ts`**
|
||
|
||
```typescript
|
||
import { USE_MOCK } from '@/mock'
|
||
import { reserveStore } from '@/mock/store'
|
||
import type { ReserveRecord } from './types'
|
||
import { get, post } from './request'
|
||
|
||
/** 获取预约记录列表 */
|
||
export function getReserveList(): Promise<ReserveRecord[]> {
|
||
if (USE_MOCK) return Promise.resolve(reserveStore.value)
|
||
return get<ReserveRecord[]>('/mp-api/reserve/list')
|
||
}
|
||
|
||
/** 创建预约 */
|
||
export function createReserve(params: Omit<ReserveRecord, 'id' | 'status'>): Promise<{ id: number }> {
|
||
if (USE_MOCK) {
|
||
const id = Math.max(...reserveStore.value.map(r => r.id), 0) + 1
|
||
reserveStore.value.push({ ...params, id, status: 'pending' })
|
||
return Promise.resolve({ id })
|
||
}
|
||
return post<{ id: number }>('/mp-api/reserve/create', params)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 4: 验证类型检查**
|
||
|
||
Run: `pnpm run type-check`
|
||
Expected: 无类型错误
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add src/api/scenic.ts src/api/order.ts src/api/reserve.ts
|
||
git commit -m "feat(api): add scenic, order, reserve API functions with mock fallback"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 7: 更新 App.vue 全局样式
|
||
|
||
**Files:**
|
||
- Modify: `src/App.vue`(`<style>` 部分)
|
||
|
||
- [ ] **Step 1: 更新 App.vue 的 page 全局样式**
|
||
|
||
`main.scss` 中已有 `page { ... }` 定义,且 `_tokens.scss` 已在 Task 2 中对齐。验证 `main.scss` 的 `page` 样式是否生效:
|
||
|
||
```scss
|
||
// main.scss 已有(无需修改):
|
||
page {
|
||
background-color: $color-background; // → #f3f4f6
|
||
color: $color-foreground; // → #111111
|
||
font-family: $font-family-body; // → -apple-system, 'PingFang SC'...
|
||
font-size: $font-size-base; // → 28rpx
|
||
line-height: $line-height-normal; // → 1.5
|
||
}
|
||
```
|
||
|
||
确认 `App.vue` 的 `<style>` 中 import 了 `main.scss`(当前已有 `@import './styles/main.scss'`)。
|
||
|
||
如果 `App.vue` 中有重复的 `page { min-height: 100vh }` 样式,保留它(与 main.scss 不冲突)。
|
||
|
||
- [ ] **Step 2: 验证**
|
||
|
||
Run: `pnpm run dev:mp-weixin`
|
||
Expected: 构建成功,微信开发者工具中页面背景和字体符合规范
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add src/App.vue
|
||
git commit -m "chore: verify App.vue global styles aligned with token system"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 8: 清理 9 个页面的局部 SCSS 变量
|
||
|
||
**Files:**
|
||
- Modify: `src/pages/faq/faq.vue`(删除 lines 243-249 的局部变量)
|
||
- Modify: `src/pages/order/order-list.vue`(删除 lines 232-240)
|
||
- Modify: `src/pages/order/order-detail.vue`(删除 lines 225-234)
|
||
- Modify: `src/pages/qrcode/index.vue`(删除 lines 249-250)
|
||
- Modify: `src/pages/card-buy/card-buy.vue`(删除 lines 85-90)
|
||
- Modify: `src/pages/reserve/reserve-success.vue`(删除 lines 122-130)
|
||
- Modify: `src/pages/card-bind/card-bind.vue`(删除 lines 270-279)
|
||
- Modify: `src/pages/reserve/reserve-index.vue`(删除 lines 229-238)
|
||
- Modify: `src/pages/reserve/reserve-list.vue`(删除 lines 305-313)
|
||
|
||
**Interfaces:**
|
||
- Consumes: Task 1 的 uni.scss 全局变量
|
||
|
||
每个文件的变量映射关系:
|
||
|
||
| 局部变量 | 全局替换为 | 值 |
|
||
|---------|----------|-----|
|
||
| `$font` | `$font-family-body` | 系统字体 |
|
||
| `$primary` | `$uv-primary` | `#3c9cff` |
|
||
| `$text-main` | `$uv-main-color` | `#111111` |
|
||
| `$text-label` | `$uv-main-color` | `#222222`→`#111111`(合并) |
|
||
| `$text-body` | `$uv-content-color` | `#333333` |
|
||
| `$text-hint` | `$uv-tips-color` | `#666666` |
|
||
| `$text-weak` | `$uv-placeholder-color` | `#999999` |
|
||
| `$divider` | `$uv-border-color` | `#eeeeee` |
|
||
| `$card-radius` | `$radius-lg` | `24rpx` |
|
||
| `$accent` | `$uv-primary` | `#3c9cff` |
|
||
|
||
> 注意:`$bar-height: 120rpx` 是组件特定值,保留为局部变量。
|
||
|
||
- [ ] **Step 1: 逐文件删除局部变量定义块**
|
||
|
||
对每个文件:
|
||
1. 删除 `<style>` 开头的局部变量定义行(`$font: ...;` 到 `$divider: ...;` 等)
|
||
2. 在 `<style>` 内全文搜索替换:
|
||
- `$font` → `$font-family-body`(注意不要替换 `$font-size` 等前缀匹配)
|
||
- `$primary` → `$uv-primary`(注意不要替换 `$primary-dark` 先处理)
|
||
- `$text-main` → `$uv-main-color`
|
||
- `$text-label` → `$uv-main-color`(合并到主色)
|
||
- `$text-body` → `$uv-content-color`
|
||
- `$text-hint` → `$uv-tips-color`
|
||
- `$text-weak` → `$uv-placeholder-color`
|
||
- `$divider` → `$uv-border-color`
|
||
- `$card-radius` → `$radius-lg`
|
||
- `$accent` → `$uv-primary`
|
||
3. **特殊处理 card-bind.vue**:`$primary-dark: #e89a2a` 是 bug(值是金色 `#e89a2a`,不是蓝色)。检查该变量在样式中的使用场景:
|
||
- 如果用于金色/警告相关样式 → 替换为 `$uv-warning-dark`(`#f1a532`)
|
||
- 如果用于主色深蓝相关样式 → 替换为 `$uv-primary-dark`(`#398ade`)
|
||
|
||
- [ ] **Step 2: 验证编译**
|
||
|
||
Run: `pnpm run dev:mp-weixin`
|
||
Expected: 构建成功,所有 9 个页面视觉无回退
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add src/pages/
|
||
git commit -m "refactor: remove local SCSS variables from 9 pages
|
||
|
||
Replace with global uni.scss tokens:
|
||
\$font → \$font-family-body
|
||
\$primary → \$uv-primary
|
||
\$text-* → \$uv-main-color/\$uv-content-color/\$uv-tips-color/\$uv-placeholder-color
|
||
\$divider → \$uv-border-color
|
||
\$card-radius → \$radius-lg"
|
||
```
|
||
|
||
---
|
||
|
||
# Phase 2: 核心链路迁移(4 个页面 + 相关组件)
|
||
|
||
> **迁移检查清单**(每个页面必须执行全部 6 项):
|
||
> 1. 删除局部 SCSS 变量(已在 Task 8 处理)
|
||
> 2. 硬编码颜色值 → 全局变量(见 spec 2.5 迁移对照表)
|
||
> 3. 硬编码字号 → 对应 `$font-size-*` 变量(见 spec 1.2 游离值迁移表)
|
||
> 4. 硬编码间距 → 对应 `$spacing-*` 变量
|
||
> 5. 模板中硬编码数据 → import mock 数据
|
||
> 6. `font-weight: bold` → `$font-weight-bold`,硬编码过渡 → `$transition-*`
|
||
|
||
---
|
||
|
||
### Task 9: 迁移首页 (index.vue)
|
||
|
||
**Files:**
|
||
- Modify: `src/pages/index/index.vue`
|
||
|
||
**当前状态**:已使用 SCSS 变量,但有部分硬编码值需修正。
|
||
|
||
- [ ] **Step 1: 颜色迁移**
|
||
|
||
搜索替换(在 `<style>` 中):
|
||
- `#e53935` → `$color-price`(价格场景)或 `$uv-error`(错误场景)
|
||
- `#FFD600` → `$color-price-highlight`(促销价,已有)
|
||
- `rgba(255, 255, 255, ...)` → 按 spec 2.4 规范保留(暗底白字透明度已是标准值)
|
||
- `rgba(60, 156, 255, ...)` → 保留(品牌蓝透明度变体)
|
||
|
||
- [ ] **Step 2: 字号迁移**
|
||
|
||
- `font-size: 22rpx` → `$font-size-xs`(20rpx)
|
||
- `font-size: 144rpx` → 保留(首页大卡促销数字,特殊值)
|
||
|
||
- [ ] **Step 3: 模板数据迁移**
|
||
|
||
将 `<script>` 中的硬编码数据替换为 import:
|
||
- `hotSpots` 数组 → `import { mockScenicList } from '@/mock/scenic'`(取前 6 条)
|
||
- `announcements` 数组 → `import { mockNotices } from '@/mock/notice'`
|
||
- `quickActions` 数组 → 保留(UI 配置,非业务数据)
|
||
|
||
- [ ] **Step 4: 验证**
|
||
|
||
Run: `pnpm run dev:mp-weixin`
|
||
Expected: 首页视觉无回退,数据正常显示
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add src/pages/index/
|
||
git commit -m "refactor(index): migrate hardcoded values to design tokens and mock data"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 10: 迁移年卡列表 (card/list.vue)
|
||
|
||
**Files:**
|
||
- Modify: `src/packages/user/pages/card/list.vue`
|
||
|
||
**当前状态**:已使用 SCSS 变量,少量硬编码。
|
||
|
||
- [ ] **Step 1: 颜色迁移**
|
||
|
||
- `#fff` → `$color-card`
|
||
- `rgba(48, 49, 51, ...)` → 保留(暗底渐变,特殊视觉效果)
|
||
- `rgba(255, 255, 255, 0.8)` → 保留(暗底白字标准透明度)
|
||
|
||
- [ ] **Step 2: 间距迁移**
|
||
|
||
无关键间距值需要迁移(已有 token 化),保留 icon/decoration 的硬编码像素值。
|
||
|
||
- [ ] **Step 3: 验证并提交**
|
||
|
||
```bash
|
||
git add src/packages/user/pages/card/list.vue
|
||
git commit -m "refactor(card/list): migrate remaining hardcoded colors to tokens"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 11: 迁移年卡详情 (card/detail.vue)
|
||
|
||
**Files:**
|
||
- Modify: `src/packages/user/pages/card/detail.vue`
|
||
|
||
**当前状态**:大量硬编码值(13 种颜色、22 种字号/间距、4 个 `font-weight: bold`)。
|
||
|
||
- [ ] **Step 1: 颜色迁移**
|
||
|
||
| 硬编码值 | 替换为 |
|
||
|---------|--------|
|
||
| `#ddd` | `$uv-border-color` |
|
||
| `#fff` | `$color-card` |
|
||
| `#333` | `$uv-content-color` |
|
||
| `#e53935` | `$color-price` |
|
||
| `#ccc` | `$uv-disabled-color` |
|
||
| `#666` | `$uv-tips-color` |
|
||
| `#eee` | `$uv-border-color` |
|
||
| `#999` | `$uv-placeholder-color` |
|
||
|
||
- [ ] **Step 2: 字号迁移**
|
||
|
||
| 硬编码值 | 替换为 |
|
||
|---------|--------|
|
||
| `36rpx` | `$font-size-xl` |
|
||
| `44rpx` | `$font-size-2xl` |
|
||
| `26rpx` | `$font-size-base`(28rpx,向上取整) |
|
||
| `30rpx` | `$font-size-lg`(32rpx) |
|
||
| `28rpx` | `$font-size-base` |
|
||
| `24rpx` | `$font-size-sm` |
|
||
| `22rpx` | `$font-size-xs`(20rpx) |
|
||
|
||
- [ ] **Step 3: 间距迁移**
|
||
|
||
| 硬编码值 | 替换为 |
|
||
|---------|--------|
|
||
| `24rpx` | `$spacing-3` |
|
||
| `30rpx` | `$spacing-4`(32rpx) |
|
||
| `16rpx` | `$spacing-2` |
|
||
| `12rpx` | `$spacing-2`(16rpx,向上取整) |
|
||
| `8rpx` | `$spacing-1` |
|
||
| `20rpx` | `$spacing-3`(24rpx) |
|
||
|
||
- [ ] **Step 4: font-weight 迁移**
|
||
|
||
全部 `font-weight: bold` → `font-weight: $font-weight-bold`
|
||
|
||
- [ ] **Step 5: 验证并提交**
|
||
|
||
```bash
|
||
git add src/packages/user/pages/card/detail.vue
|
||
git commit -m "refactor(card/detail): migrate all hardcoded values to design tokens"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 12: 迁移购买流程 (card/buy.vue + card-buy.vue)
|
||
|
||
**Files:**
|
||
- Modify: `src/packages/user/pages/card/buy.vue`
|
||
- Modify: `src/pages/card-buy/card-buy.vue`
|
||
|
||
- [ ] **Step 1: 迁移 `packages/card/buy.vue`**
|
||
|
||
颜色迁移(同 Task 11 对照表):
|
||
- `#f5f5f5` → `$uv-bg-color`
|
||
- `#fff` → `$color-card`
|
||
- `#333` → `$uv-content-color`
|
||
- `#e53935` → `$color-price`
|
||
- `#eeeeee` → `$uv-border-color`
|
||
- `#666` → `$uv-tips-color`
|
||
- `#3c9cff` → `$uv-primary`
|
||
- `#999` → `$uv-placeholder-color`
|
||
- `#eee` → `$uv-border-color`
|
||
- `#e5e7eb` → `$uv-border-color`
|
||
|
||
字号迁移:
|
||
- `30rpx` → `$font-size-lg`
|
||
- `28rpx` → `$font-size-base`
|
||
- `36rpx` → `$font-size-xl`
|
||
- `32rpx` → `$font-size-lg`
|
||
- `22rpx` → `$font-size-xs`
|
||
- `40rpx` → `$font-size-xl`(36rpx,向下取整)
|
||
|
||
间距迁移:
|
||
- `20rpx` → `$spacing-3`(24rpx)
|
||
- `24rpx` → `$spacing-3`
|
||
- `30rpx` → `$spacing-4`(32rpx)
|
||
- `16rpx` → `$spacing-2`
|
||
|
||
`font-weight: bold` → `$font-weight-bold`(4 处)
|
||
|
||
- [ ] **Step 2: 迁移 `pages/card-buy/card-buy.vue`**
|
||
|
||
删除局部变量(已在 Task 8 处理)。
|
||
|
||
颜色迁移:
|
||
- `#ffffff` → `$color-card`
|
||
- `#e53935` → `$color-price`
|
||
- `rgba(0, 0, 0, 0.06)` → 保留(投影变体)
|
||
- `rgba(60, 156, 255, 0.3)` → 保留(品牌蓝投影)
|
||
|
||
字号迁移:
|
||
- `26rpx` → `$font-size-base`(28rpx)
|
||
- `28rpx` → `$font-size-base`
|
||
- `38rpx` → `$font-size-xl`(36rpx)
|
||
- `22rpx` → `$font-size-xs`(20rpx)
|
||
|
||
`font-weight: 700` → `$font-weight-bold`(3 处)
|
||
|
||
过渡迁移:
|
||
- `all 0.2s ease` → `all $transition-fast`
|
||
|
||
- [ ] **Step 3: 验证并提交**
|
||
|
||
```bash
|
||
git add src/packages/user/pages/card/buy.vue src/pages/card-buy/
|
||
git commit -m "refactor(card/buy): migrate purchase flow to design tokens"
|
||
```
|
||
|
||
---
|
||
|
||
# Phase 3: 剩余页面迁移
|
||
|
||
---
|
||
|
||
### Task 13: 迁移订单页面
|
||
|
||
**Files:**
|
||
- Modify: `src/pages/order/order-list.vue`
|
||
- Modify: `src/pages/order/order-detail.vue`
|
||
|
||
- [ ] **Step 1: 迁移 order-list.vue**
|
||
|
||
局部变量已删除(Task 8)。
|
||
|
||
颜色迁移:
|
||
- 搜索所有 `#111`/`#222` → `$uv-main-color`
|
||
- `#333` → `$uv-content-color`
|
||
- `#666` → `$uv-tips-color`
|
||
- `#999` → `$uv-placeholder-color`
|
||
- `#eeeeee` → `$uv-border-color`
|
||
- `#ff9500` → `$color-status-pending`
|
||
- `#00b42a` → `$color-status-success`
|
||
- `#86909c` → `$color-status-cancel`
|
||
- `#f53f3f` → `$uv-error`
|
||
|
||
字号迁移(`26rpx` → `$font-size-base`,其他按对照表)。
|
||
|
||
模板数据迁移:
|
||
- `orders` ref 数组 → `import { getOrderList } from '@/api/order'`,`onLoad` 中调用
|
||
|
||
- [ ] **Step 2: 迁移 order-detail.vue**
|
||
|
||
同 order-list.vue 的颜色/字号迁移。
|
||
|
||
模板数据迁移:
|
||
- `mockOrders` 数组 → `import { getOrderDetail } from '@/api/order'`
|
||
|
||
- [ ] **Step 3: 验证并提交**
|
||
|
||
```bash
|
||
git add src/pages/order/
|
||
git commit -m "refactor(order): migrate order pages to design tokens and API layer"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 14: 迁移预约页面
|
||
|
||
**Files:**
|
||
- Modify: `src/pages/reserve/reserve-index.vue`
|
||
- Modify: `src/pages/reserve/reserve-list.vue`
|
||
- Modify: `src/pages/reserve/reserve-success.vue`
|
||
|
||
- [ ] **Step 1: 迁移 reserve-list.vue**
|
||
|
||
局部变量已删除(Task 8)。
|
||
颜色/字号迁移同订单页面模式。
|
||
状态颜色:`pending` → `$color-status-pending`,`used`/`auto_used` → `$color-status-success`,`cancelled` → `$color-status-cancel`。
|
||
模板数据迁移:`records` → `import { getReserveList } from '@/api/reserve'`。
|
||
|
||
- [ ] **Step 2: 迁移 reserve-index.vue**
|
||
|
||
局部变量已删除(Task 8)。
|
||
颜色/字号迁移同上。
|
||
模板数据:`scenic`、`userInfo`、`mockStocks`、`sessionMap` → 后续对接 API 时替换,当前保留。
|
||
|
||
- [ ] **Step 3: 迁移 reserve-success.vue**
|
||
|
||
局部变量已删除(Task 8)。
|
||
颜色/字号迁移同上。
|
||
|
||
- [ ] **Step 4: 验证并提交**
|
||
|
||
```bash
|
||
git add src/pages/reserve/
|
||
git commit -m "refactor(reserve): migrate reserve pages to design tokens"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 15: 迁移剩余页面
|
||
|
||
**Files:**
|
||
- `src/pages/login/login.vue` — 已有 SCSS 变量,少量硬编码
|
||
- `src/pages/login/agreement.vue` — 已有 SCSS 变量
|
||
- `src/pages/login/privacy.vue` — 已有 SCSS 变量
|
||
- `src/pages/profile/index.vue` — 已有 SCSS 变量
|
||
- `src/pages/qrcode/index.vue` — 局部变量已删除(Task 8)
|
||
- `src/pages/faq/faq.vue` — 局部变量已删除(Task 8)
|
||
- `src/pages/card-bind/card-bind.vue` — 局部变量已删除(Task 8)
|
||
- `src/pages/notice-list/notice-list.vue` — 混合状态
|
||
- `src/pages/scenic-detail/scenic-detail.vue` — 已有 SCSS 变量
|
||
- `src/pages/scenic-list/scenic-list.vue` — 已有 SCSS 变量
|
||
- `src/pages/union-buy/union-buy.vue` — 已有 SCSS 变量
|
||
- `src/pages/usage-guide/usage-guide.vue` — 纯图片页面
|
||
- `src/packages/user/pages/card/activate.vue` — 硬编码字体
|
||
- `src/packages/user/pages/card/bind.vue` — 硬编码字体
|
||
- `src/packages/user/pages/card/qrcode.vue` — 硬编码字体
|
||
|
||
- [ ] **Step 1: 逐文件迁移**
|
||
|
||
对每个文件执行 6 项检查清单:
|
||
1. ~~删除局部变量~~(已在 Task 8 处理)
|
||
2. 硬编码颜色 → 全局变量
|
||
3. 硬编码字号 → `$font-size-*`
|
||
4. 硬编码间距 → `$spacing-*`
|
||
5. 模板数据 → mock import(notice-list、qrcode、faq)
|
||
6. `font-weight: bold` → `$font-weight-bold`
|
||
|
||
**分包页面特殊处理**(activate/bind/qrcode):
|
||
- 这些文件使用 `font-family: 'SourceHanSerifCN'...` 硬编码字符串
|
||
- 替换为 `font-family: $font-family-display`(标题)或 `$font-family-body`(正文)
|
||
|
||
**notice-list 数据迁移**:
|
||
- `notices` 数组 → `import { mockNotices } from '@/mock/notice'`
|
||
|
||
**qrcode 数据迁移**:
|
||
- `userCards` 数组 → 保留(需用户登录后从 API 获取)
|
||
|
||
- [ ] **Step 2: 验证并提交**
|
||
|
||
```bash
|
||
git add src/pages/ src/packages/
|
||
git commit -m "refactor: migrate remaining pages to design tokens"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 16: 迁移公共组件
|
||
|
||
**Files:**
|
||
- Modify: `src/components/card-item.vue` — 从纯 CSS 改为 SCSS
|
||
- Modify: `src/components/empty-state.vue` — 从纯 CSS 改为 SCSS
|
||
- Modify: `src/components/McGlass.vue` — 从纯 CSS 改为 SCSS
|
||
|
||
- [ ] **Step 1: 迁移 card-item.vue**
|
||
|
||
将 `<style scoped>` 改为 `<style lang="scss" scoped>`。
|
||
|
||
颜色迁移:
|
||
| 硬编码值 | 替换为 |
|
||
|---------|--------|
|
||
| `#fff` | `$color-card` |
|
||
| `#eee` | `$uv-border-color` |
|
||
| `#333` | `$uv-content-color` |
|
||
| `#999` | `$uv-placeholder-color` |
|
||
| `#E74C3C` | `$color-price` |
|
||
| `#ccc` | `$uv-disabled-color` |
|
||
| `#4A90D9` | `$uv-primary` |
|
||
| `#E8F0FE` | `$uv-primary-light` |
|
||
|
||
字号迁移:
|
||
| 硬编码值 | 替换为 |
|
||
|---------|--------|
|
||
| `30rpx` | `$font-size-lg` |
|
||
| `24rpx` | `$font-size-sm` |
|
||
| `32rpx` | `$font-size-lg` |
|
||
| `22rpx` | `$font-size-xs` |
|
||
|
||
间距迁移:
|
||
| 硬编码值 | 替换为 |
|
||
|---------|--------|
|
||
| `16rpx` | `$spacing-2` |
|
||
| `20rpx` | `$spacing-3`(24rpx) |
|
||
| `8rpx` | `$spacing-1` |
|
||
| `4rpx` | 保留(极小装饰值) |
|
||
| `12rpx` | `$spacing-2`(16rpx) |
|
||
|
||
圆角迁移:
|
||
- `16rpx` → `$radius-base`
|
||
- `20rpx` → `$radius-base`(16rpx,向下取整)
|
||
|
||
`font-weight: bold` → `$font-weight-bold`(2 处)
|
||
|
||
- [ ] **Step 2: 迁移 empty-state.vue**
|
||
|
||
改为 `<style lang="scss" scoped>`。
|
||
|
||
颜色迁移:
|
||
- `#999` → `$uv-placeholder-color`
|
||
- `#4A90D9` → `$uv-primary`
|
||
- `#E8F0FE` → `$uv-primary-light`
|
||
|
||
字号/间距迁移:
|
||
- `80rpx`(icon) → 保留(装饰尺寸)
|
||
- `28rpx` → `$font-size-base`
|
||
- `40rpx` → `$spacing-5`
|
||
- `20rpx` → `$spacing-3`(24rpx)
|
||
- `30rpx` → `$spacing-4`(32rpx)
|
||
- `12rpx` → `$spacing-2`(16rpx)
|
||
|
||
圆角:`30rpx` → `$radius-full`
|
||
|
||
- [ ] **Step 3: 迁移 McGlass.vue**
|
||
|
||
改为 `<style lang="scss" scoped>`。
|
||
|
||
- rgba 值保留(毛玻璃效果的特殊视觉值)
|
||
- `24rpx` 圆角 → `$radius-lg`
|
||
- backdrop-filter 值保留
|
||
|
||
- [ ] **Step 4: 验证并提交**
|
||
|
||
```bash
|
||
git add src/components/
|
||
git commit -m "refactor(components): migrate card-item, empty-state, McGlass to SCSS tokens"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 17: 最终验证
|
||
|
||
- [ ] **Step 1: TypeScript 类型检查**
|
||
|
||
Run: `pnpm run type-check`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 2: 全量构建**
|
||
|
||
Run: `pnpm run dev:mp-weixin`
|
||
Expected: 构建成功
|
||
|
||
- [ ] **Step 3: 视觉回归检查**
|
||
|
||
在微信开发者工具中逐页检查:
|
||
- 首页:轮播、景区卡片、超级玩家卡价格(¥98 亮黄色)
|
||
- 年卡列表/详情:布局、颜色、字号
|
||
- 购买流程:价格显示、按钮样式
|
||
- 订单列表/详情:状态标签颜色
|
||
- 预约页面:表单、列表
|
||
- 个人中心、登录页
|
||
|
||
- [ ] **Step 4: 清理遗留**
|
||
|
||
- 删除 `src/data/scenic-spots.ts`(已被 `mock/scenic.ts` 替代)
|
||
- 确认无残留的局部 `$font`/`$primary` 定义:`grep -r '\$font:' src/pages/ src/packages/`
|
||
- 确认无残留的 `font-weight: bold`:`grep -r 'font-weight: bold' src/`
|
||
|
||
- [ ] **Step 5: 最终提交**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "chore: final verification and cleanup after UI/UX standardization"
|
||
```
|