# 湖南12301文旅综合平台 — 第一迭代实施计划 > **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:** 搭建用户端分包架构和基础层,实现年卡浏览→购买→激活→入园码的核心业务流程。 **Architecture:** 由底向上分两阶段实施。Phase 1 搭建分包路由、API 层、Store 和共享组件;Phase 2 实现 8 个用户端页面(首页/年卡列表/详情/购买/激活/入园码/绑定/个人中心)。小程序启动默认进入用户端,微信授权登录,模拟支付。 **Tech Stack:** uni-app + Vue 3 + TypeScript + Pinia + uni-ui + Vite --- ## 文件结构 ### 新增文件 | 文件路径 | 职责 | |----------|------| | `src/config/index.ts` | 环境配置(baseURL 读取) | | `.env.local` | 本地开发环境变量 | | `.env.dev` | 开发环境变量 | | `.env.uat` | 预发布环境变量 | | `src/api/types.ts` | 共享 TypeScript 类型定义 | | `src/api/card.ts` | 年卡接口 | | `src/api/order.ts` | 订单/支付接口 | | `src/store/card.ts` | 年卡 Pinia Store | | `src/components/card-item.vue` | 年卡卡片共享组件 | | `src/components/empty-state.vue` | 空状态共享组件 | | `src/packages/user/pages/index/index.vue` | 用户端首页(宫格式) | | `src/packages/user/pages/card/list.vue` | 年卡列表 | | `src/packages/user/pages/card/detail.vue` | 年卡详情 | | `src/packages/user/pages/card/buy.vue` | 确认购买(模拟支付) | | `src/packages/user/pages/card/activate.vue` | 激活年卡 | | `src/packages/user/pages/card/qrcode.vue` | 入园码(卡片式) | | `src/packages/user/pages/card/bind.vue` | 绑定年卡 | | `src/packages/user/pages/profile/index.vue` | 用户端个人中心 | | `src/static/tabbar/home.png` | TabBar 首页图标(占位) | | `src/static/tabbar/home-active.png` | TabBar 首页选中图标(占位) | | `src/static/tabbar/profile.png` | TabBar 我的图标(占位) | | `src/static/tabbar/profile-active.png` | TabBar 我的选中图标(占位) | ### 修改文件 | 文件路径 | 改动 | |----------|------| | `src/api/request.ts` | 重写:baseURL 从 config 读取,清理错误处理 | | `src/api/user.ts` | 改造:新增 wxLogin,调整类型 | | `src/api/index.ts` | 更新 barrel 导出 | | `src/store/user.ts` | 改造:新增 wxLogin action,新增 refreshToken | | `src/pages.json` | 重写:分包路由 + TabBar 指向用户端 | | `src/pages/index/index.vue` | 改造:自动跳转到用户端首页 | | `src/pages/login/login.vue` | 改造:微信授权登录 | | `src/App.vue` | 改造:启动时检查登录状态 | | `vite.config.ts` | 新增环境变量相关配置 | ### 删除文件(可选,不影响功能) | 文件路径 | 原因 | |----------|------| | `src/pages/profile/profile.vue` | 被用户端个人中心替代 | | `src/pages/logs/logs.vue` | 非业务页面,不再需要 | --- ## Task 1:环境配置 **Files:** - Create: `src/config/index.ts` - Create: `.env.local` - Create: `.env.dev` - Create: `.env.uat` - Modify: `vite.config.ts` - [ ] **Step 1:创建环境配置文件** 创建 `.env.local`: ``` VITE_API_BASE_URL=http://localhost:80 VITE_APP_TITLE=湖南12301文旅专区 ``` 创建 `.env.dev`: ``` VITE_API_BASE_URL=https://dscp-dev.hn12301.net VITE_APP_TITLE=湖南12301文旅专区 ``` 创建 `.env.uat`: ``` VITE_API_BASE_URL=https://dscp-uat.hn12301.net VITE_APP_TITLE=湖南12301文旅专区 ``` - [ ] **Step 2:创建 config/index.ts** 创建 `src/config/index.ts`: ```typescript /** * 环境配置 * 根据 Vite 环境变量读取 API 基础地址等配置 */ /** API 基础地址(含 /manage-api 前缀) */ export const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:80' /** API 接口前缀 */ export const API_PREFIX = '/manage-api' /** 完整 API 基础路径 */ export const API_BASE = `${BASE_URL}${API_PREFIX}` /** 应用标题 */ export const APP_TITLE = import.meta.env.VITE_APP_TITLE || '湖南12301文旅专区' /** Token 存储键名 */ export const TOKEN_KEY = 'app_token' /** Refresh Token 存储键名 */ export const REFRESH_TOKEN_KEY = 'app_refresh_token' ``` - [ ] **Step 3:添加 env.d.ts 类型声明** 在 `src/env.d.ts` 中追加 Vite 环境变量类型声明(如果文件已有内容则追加): ```typescript /// interface ImportMetaEnv { readonly VITE_API_BASE_URL: string readonly VITE_APP_TITLE: string } interface ImportMeta { readonly env: ImportMetaEnv } ``` - [ ] **Step 4:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:无新增类型错误(config/index.ts 编译通过)。 - [ ] **Step 5:提交** ```bash git add src/config/ .env.local .env.dev .env.uat src/env.d.ts git commit -m "feat: 添加多环境配置(local/dev/uat)" ``` --- ## Task 2:重写 API 请求层 **Files:** - Modify: `src/api/request.ts`(完全重写) - [ ] **Step 1:重写 request.ts** 将 `src/api/request.ts` 替换为以下内容: ```typescript import { API_BASE, TOKEN_KEY } from '../config' /** 请求选项 */ interface RequestOptions { url: string method?: 'GET' | 'POST' | 'PUT' | 'DELETE' data?: any header?: Record needToken?: boolean } /** 后端统一响应格式 */ interface ResponseData { code: number msg: string data: T errcode: number errmsg: string } /** 从本地存储获取 token */ function getToken(): string { return uni.getStorageSync(TOKEN_KEY) || '' } /** 保存 token 到本地存储 */ function setToken(token: string): void { uni.setStorageSync(TOKEN_KEY, token) } /** 移除本地存储中的 token */ function removeToken(): void { uni.removeStorageSync(TOKEN_KEY) } /** 通用请求函数 */ function request(options: RequestOptions): Promise { return new Promise((resolve, reject) => { const { url, method = 'GET', data, needToken = true } = options const header: Record = { 'Content-Type': 'application/json', ...options.header } // 自动注入 Bearer Token if (needToken) { const token = getToken() if (token) { header['Authorization'] = `Bearer ${token}` } } // 拼接完整 URL const fullUrl = url.startsWith('http') ? url : `${API_BASE}${url}` uni.request({ url: fullUrl, method, data, header, success: (res: any) => { const result = res.data as ResponseData // HTTP 状态码检查 if (res.statusCode === 401 || result?.code === 401) { removeToken() uni.showToast({ title: '登录已过期,请重新登录', icon: 'none' }) // 延迟跳转,让 toast 先显示 setTimeout(() => { uni.navigateTo({ url: '/pages/login/login' }) }, 1500) reject(new Error('未授权')) return } if (res.statusCode >= 200 && res.statusCode < 300) { // 业务状态码检查:code === 200 或 errcode === 0 均视为成功 if (result.code === 200 || result.errcode === 0) { resolve(result.data as T) } else { const errMsg = result.msg || result.errmsg || '请求失败' uni.showToast({ title: errMsg, icon: 'none' }) reject(new Error(errMsg)) } } else { uni.showToast({ title: '网络错误', icon: 'none' }) reject(new Error(`HTTP ${res.statusCode}`)) } }, fail: (err: any) => { uni.showToast({ title: '网络连接失败', icon: 'none' }) reject(err) } }) }) } function get(url: string, data?: any, needToken = true): Promise { return request({ url, method: 'GET', data, needToken }) } function post(url: string, data?: any, needToken = true): Promise { return request({ url, method: 'POST', data, needToken }) } function put(url: string, data?: any, needToken = true): Promise { return request({ url, method: 'PUT', data, needToken }) } function del(url: string, data?: any, needToken = true): Promise { return request({ url, method: 'DELETE', data, needToken }) } export { request, get, post, put, del, getToken, setToken, removeToken } ``` - [ ] **Step 2:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:无类型错误。 - [ ] **Step 3:提交** ```bash git add src/api/request.ts git commit -m "refactor: 重写 request.ts,baseURL 从环境配置读取" ``` --- ## Task 3:定义共享类型 + 改造用户 API **Files:** - Create: `src/api/types.ts` - Modify: `src/api/user.ts` - Modify: `src/api/index.ts` - [ ] **Step 1:创建共享类型定义** 创建 `src/api/types.ts`: ```typescript /** 用户信息 */ export interface UserInfo { id: number nickname: string avatarUrl: string phone?: string } /** 微信登录结果 */ export interface WxLoginResult { accessToken: string refreshToken: string userId: number } /** 账号密码登录参数(降级方案) */ export interface LoginParams { username: string password: string } /** 年卡基本信息 */ export interface CardInfo { id: string name: string price: number originalPrice: number coverImage: string description: string scenicCount: number } /** 年卡详情 */ export interface CardDetail extends CardInfo { benefits: string[] scenicSpots: ScenicSpot[] validDays: number detail: string } /** 景区信息 */ export interface ScenicSpot { id: string name: string image: string address?: string } /** 我的年卡 */ export interface MyCard { id: string cardId: string cardName: string coverImage: string userName: string expireDate: string status: 'active' | 'expired' | 'inactive' } /** 激活年卡参数 */ export interface ActivateParams { realName: string idCard: string phone: string } /** 入园码信息 */ export interface QrCodeInfo { qrCode: string expireTime: string cardName: string userName: string expireDate: string } /** 订单信息 */ export interface OrderInfo { id: string cardId: string cardName: string price: number status: 'pending' | 'paid' | 'cancelled' createTime: string } /** 创建订单参数 */ export interface CreateOrderParams { cardId: string } /** 模拟支付结果 */ export interface MockPayResult { success: boolean orderId: string } ``` - [ ] **Step 2:改造用户 API** 将 `src/api/user.ts` 替换为: ```typescript import { get, post } from './request' import type { UserInfo, WxLoginResult, LoginParams } from './types' /** 微信授权登录 */ export function wxLogin(code: string): Promise { return post('/auth/wx-login', { code }, false) } /** 账号密码登录(降级方案) */ export function login(params: LoginParams): Promise { return post('/auth/login', params, false) } /** 获取当前用户信息 */ export function getUserInfo(): Promise { return get('/user/info') } export type { UserInfo, WxLoginResult, LoginParams } ``` - [ ] **Step 3:更新 barrel 导出** 将 `src/api/index.ts` 替换为: ```typescript export * from './types' export * from './user' export * from './card' export * from './order' export { get, post, put, del, getToken, setToken, removeToken } from './request' ``` 注意:`card` 和 `order` 模块在后续 Task 中创建,此处先写好导出,暂时会导致编译警告,Task 4/5 完成后即可消除。 - [ ] **Step 4:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:可能有关于 card/order 模块未找到的警告(Task 4/5 会消除)。 - [ ] **Step 5:提交** ```bash git add src/api/types.ts src/api/user.ts src/api/index.ts git commit -m "feat: 定义共享类型,改造用户 API(新增 wxLogin)" ``` --- ## Task 4:创建年卡 API 模块 **Files:** - Create: `src/api/card.ts` - [ ] **Step 1:创建 card.ts** 创建 `src/api/card.ts`: ```typescript import { get, post } from './request' import type { CardInfo, CardDetail, MyCard, ActivateParams, QrCodeInfo } from './types' /** 获取年卡列表 */ export function getCardList(params?: { keyword?: string; category?: string }): Promise { return get('/card/list', params) } /** 获取年卡详情 */ export function getCardDetail(id: string): Promise { return get('/card/detail', { id }) } /** 激活年卡 */ export function activateCard(cardId: string, data: ActivateParams): Promise { return post('/card/activate', { cardId, ...data }) } /** 绑定年卡 */ export function bindCard(cardNo: string): Promise { return post('/card/bind', { cardNo }) } /** 获取我的年卡列表 */ export function getMyCards(): Promise { return get('/card/my-list') } /** 获取入园码 */ export function getEntryQrCode(cardId: string): Promise { return get('/card/qrcode', { cardId }) } ``` - [ ] **Step 2:提交** ```bash git add src/api/card.ts git commit -m "feat: 新增年卡 API 模块" ``` --- ## Task 5:创建订单 API 模块 **Files:** - Create: `src/api/order.ts` - [ ] **Step 1:创建 order.ts** 创建 `src/api/order.ts`: ```typescript import { get, post } from './request' import type { OrderInfo, CreateOrderParams, MockPayResult } from './types' /** 创建订单 */ export function createOrder(data: CreateOrderParams): Promise { return post('/order/create', data) } /** 模拟支付(第一版替代微信支付) */ export function mockPay(orderId: string): Promise { return post('/order/mock-pay', { orderId }) } /** 获取订单列表 */ export function getOrderList(params?: { status?: string }): Promise { return get('/order/list', params) } /** 获取订单详情 */ export function getOrderDetail(id: string): Promise { return get('/order/detail', { id }) } ``` - [ ] **Step 2:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:API 相关类型错误全部消除。 - [ ] **Step 3:提交** ```bash git add src/api/order.ts git commit -m "feat: 新增订单 API 模块(含模拟支付)" ``` --- ## Task 6:改造 User Store + 创建 Card Store **Files:** - Modify: `src/store/user.ts`(重写) - Create: `src/store/card.ts` - [ ] **Step 1:重写 user store** 将 `src/store/user.ts` 替换为: ```typescript import { defineStore } from 'pinia' import { ref, computed } from 'vue' import { getToken, setToken, removeToken } from '../api/request' import { wxLogin as apiWxLogin, login as apiLogin, getUserInfo as apiGetUserInfo } from '../api/user' import type { UserInfo, LoginParams } from '../api/types' import { TOKEN_KEY, REFRESH_TOKEN_KEY } from '../config' export const useUserStore = defineStore('user', () => { const token = ref(getToken()) const refreshToken = ref(uni.getStorageSync(REFRESH_TOKEN_KEY) || '') const userInfo = ref(null) const isLogin = computed(() => !!token.value) /** 微信授权登录 */ async function wxLogin() { // #ifdef MP-WEIXIN const loginRes = await new Promise((resolve, reject) => { uni.login({ provider: 'weixin', success: resolve, fail: reject }) }) const result = await apiWxLogin(loginRes.code) token.value = result.accessToken refreshToken.value = result.refreshToken setToken(result.accessToken) uni.setStorageSync(REFRESH_TOKEN_KEY, result.refreshToken) return result // #endif // #ifdef H5 throw new Error('H5 登录暂未开放,请在微信小程序中使用') // #endif } /** 账号密码登录(降级方案) */ async function login(params: LoginParams) { const result = await apiLogin(params) token.value = result.accessToken refreshToken.value = result.refreshToken setToken(result.accessToken) uni.setStorageSync(REFRESH_TOKEN_KEY, result.refreshToken) return result } /** 获取用户信息 */ async function fetchUserInfo() { if (!token.value) return const info = await apiGetUserInfo() userInfo.value = info return info } /** 退出登录 */ function logout() { token.value = '' refreshToken.value = '' userInfo.value = null removeToken() uni.removeStorageSync(REFRESH_TOKEN_KEY) } return { token, refreshToken, userInfo, isLogin, wxLogin, login, fetchUserInfo, logout } }) ``` - [ ] **Step 2:创建 card store** 创建 `src/store/card.ts`: ```typescript import { defineStore } from 'pinia' import { ref } from 'vue' import * as cardApi from '../api/card' import type { CardInfo, CardDetail, MyCard, ActivateParams, QrCodeInfo } from '../api/types' export const useCardStore = defineStore('card', () => { const cardList = ref([]) const currentCard = ref(null) const myCards = ref([]) const loading = ref(false) /** 获取年卡列表 */ async function fetchCardList(params?: { keyword?: string; category?: string }) { loading.value = true try { cardList.value = await cardApi.getCardList(params) } finally { loading.value = false } } /** 获取年卡详情 */ async function fetchCardDetail(id: string) { loading.value = true try { currentCard.value = await cardApi.getCardDetail(id) } finally { loading.value = false } } /** 获取我的年卡 */ async function fetchMyCards() { myCards.value = await cardApi.getMyCards() } /** 激活年卡 */ async function activateCard(cardId: string, data: ActivateParams) { return await cardApi.activateCard(cardId, data) } /** 绑定年卡 */ async function bindCard(cardNo: string) { return await cardApi.bindCard(cardNo) } /** 获取入园码 */ async function getEntryQrCode(cardId: string): Promise { return await cardApi.getEntryQrCode(cardId) } return { cardList, currentCard, myCards, loading, fetchCardList, fetchCardDetail, fetchMyCards, activateCard, bindCard, getEntryQrCode } }) ``` - [ ] **Step 3:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:Store 相关文件无类型错误。 - [ ] **Step 4:提交** ```bash git add src/store/user.ts src/store/card.ts git commit -m "feat: 改造 user store(微信登录),新增 card store" ``` --- ## Task 7:创建共享组件 **Files:** - Create: `src/components/card-item.vue` - Create: `src/components/empty-state.vue` - [ ] **Step 1:创建 card-item 组件** 创建 `src/components/card-item.vue`: ```vue ``` - [ ] **Step 2:创建 empty-state 组件** 创建 `src/components/empty-state.vue`: ```vue ``` - [ ] **Step 3:提交** ```bash git add src/components/ git commit -m "feat: 新增 card-item 和 empty-state 共享组件" ``` --- ## Task 8:创建 TabBar 图标 + 重写路由配置 **Files:** - Create: `src/static/tabbar/home.png` - Create: `src/static/tabbar/home-active.png` - Create: `src/static/tabbar/profile.png` - Create: `src/static/tabbar/profile-active.png` - Modify: `src/pages.json`(完全重写) - [ ] **Step 1:生成 TabBar 占位图标** TabBar 图标必须是图片文件。使用以下命令生成 4 个简单的 SVG 占位图标并转换为 PNG(或直接用在线占位图服务): ```bash mkdir -p src/static/tabbar # 使用 base64 编码的最小 PNG 图标(81x81 像素,灰色/蓝色) # home.png - 灰色首页图标 echo "iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAKElEQVR42u3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAAAAAADcGlJRAAH0fVWIAAAAAElFTkSuQmCC" | base64 -d > src/static/tabbar/home.png # home-active.png - 蓝色首页图标 echo "iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAKElEQVR42u3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAAAAAADcGlJRAAH0fVWIAAAAAElFTkSuQmCC" | base64 -d > src/static/tabbar/home-active.png # profile.png - 灰色我的图标 cp src/static/tabbar/home.png src/static/tabbar/profile.png # profile-active.png - 蓝色我的图标 cp src/static/tabbar/home-active.png src/static/tabbar/profile-active.png ``` > **注意**:以上是占位 PNG。正式环境中应替换为设计师提供的图标文件(建议 81×81px)。 - [ ] **Step 2:重写 pages.json** 将 `src/pages.json` 替换为: ```json { "easycom": { "autoscan": true, "custom": { "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" } }, "pages": [ { "path": "pages/index/index", "style": { "navigationBarTitleText": "湖南12301" } }, { "path": "pages/login/login", "style": { "navigationBarTitleText": "登录" } } ], "subPackages": [ { "root": "packages/user", "pages": [ { "path": "pages/index/index", "style": { "navigationBarTitleText": "文旅专区" } }, { "path": "pages/card/list", "style": { "navigationBarTitleText": "年卡列表" } }, { "path": "pages/card/detail", "style": { "navigationBarTitleText": "年卡详情" } }, { "path": "pages/card/buy", "style": { "navigationBarTitleText": "确认购买" } }, { "path": "pages/card/activate", "style": { "navigationBarTitleText": "激活年卡" } }, { "path": "pages/card/qrcode", "style": { "navigationBarTitleText": "入园码" } }, { "path": "pages/card/bind", "style": { "navigationBarTitleText": "绑定年卡" } }, { "path": "pages/profile/index", "style": { "navigationBarTitleText": "个人中心" } } ] } ], "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "湖南12301", "navigationBarBackgroundColor": "#FFFFFF", "backgroundColor": "#F5F5F5" }, "tabBar": { "color": "#7A7E83", "selectedColor": "#4A90D9", "borderStyle": "white", "backgroundColor": "#ffffff", "list": [ { "pagePath": "packages/user/pages/index/index", "text": "首页", "iconPath": "static/tabbar/home.png", "selectedIconPath": "static/tabbar/home-active.png" }, { "pagePath": "packages/user/pages/profile/index", "text": "我的", "iconPath": "static/tabbar/profile.png", "selectedIconPath": "static/tabbar/profile-active.png" } ] } } ``` - [ ] **Step 3:验证编译** 运行: ```bash cd zhy-test && npx uni -p mp-weixin 2>&1 | head -30 ``` 预期:编译启动成功,无路由配置错误。(可用 Ctrl+C 停止) - [ ] **Step 4:提交** ```bash git add src/pages.json src/static/tabbar/ git commit -m "feat: 重写路由配置,添加分包和 TabBar" ``` --- ## Task 9:改造入口页和登录页 **Files:** - Modify: `src/pages/index/index.vue`(重写为自动跳转) - Modify: `src/pages/login/login.vue`(改造为微信登录) - Modify: `src/App.vue`(添加启动登录检查) - [ ] **Step 1:改造入口页为自动跳转** 将 `src/pages/index/index.vue` 替换为: ```vue ``` - [ ] **Step 2:改造登录页为微信授权登录** 将 `src/pages/login/login.vue` 替换为: ```vue ``` - [ ] **Step 3:改造 App.vue 添加启动检查** 将 `src/App.vue` 替换为: ```vue ``` - [ ] **Step 4:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:入口页和登录页无类型错误。 - [ ] **Step 5:提交** ```bash git add src/pages/index/index.vue src/pages/login/login.vue src/App.vue git commit -m "feat: 改造入口页(自动跳转)和登录页(微信授权登录)" ``` --- ## Task 10:用户端首页(宫格式) **Files:** - Create: `src/packages/user/pages/index/index.vue` - [ ] **Step 1:创建用户端首页** 创建 `src/packages/user/pages/index/index.vue`: ```vue ``` - [ ] **Step 2:验证编译** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 | head -20 ``` 预期:无类型错误。 - [ ] **Step 3:提交** ```bash git add src/packages/user/pages/index/ git commit -m "feat: 用户端首页(宫格式布局 + 推荐年卡)" ``` --- ## Task 11:年卡列表页 **Files:** - Create: `src/packages/user/pages/card/list.vue` - [ ] **Step 1:创建年卡列表页** 创建 `src/packages/user/pages/card/list.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/card/list.vue git commit -m "feat: 年卡列表页(搜索 + 分类筛选)" ``` --- ## Task 12:年卡详情页 **Files:** - Create: `src/packages/user/pages/card/detail.vue` - [ ] **Step 1:创建年卡详情页** 创建 `src/packages/user/pages/card/detail.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/card/detail.vue git commit -m "feat: 年卡详情页(封面 + 权益 + 景区 + 购买按钮)" ``` --- ## Task 13:确认购买页(模拟支付) **Files:** - Create: `src/packages/user/pages/card/buy.vue` - [ ] **Step 1:创建确认购买页** 创建 `src/packages/user/pages/card/buy.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/card/buy.vue git commit -m "feat: 确认购买页(模拟支付流程)" ``` --- ## Task 14:激活年卡页 **Files:** - Create: `src/packages/user/pages/card/activate.vue` - [ ] **Step 1:创建激活年卡页** 创建 `src/packages/user/pages/card/activate.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/card/activate.vue git commit -m "feat: 激活年卡页(实名表单 + 验证)" ``` --- ## Task 15:入园码页(卡片式) **Files:** - Create: `src/packages/user/pages/card/qrcode.vue` - [ ] **Step 1:创建入园码页** 创建 `src/packages/user/pages/card/qrcode.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/card/qrcode.vue git commit -m "feat: 入园码页(卡片式 + 60秒自动刷新)" ``` --- ## Task 16:绑定年卡页 **Files:** - Create: `src/packages/user/pages/card/bind.vue` - [ ] **Step 1:创建绑定年卡页** 创建 `src/packages/user/pages/card/bind.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/card/bind.vue git commit -m "feat: 绑定年卡页" ``` --- ## Task 17:用户端个人中心 **Files:** - Create: `src/packages/user/pages/profile/index.vue` - [ ] **Step 1:创建用户端个人中心** 创建 `src/packages/user/pages/profile/index.vue`: ```vue ``` - [ ] **Step 2:提交** ```bash git add src/packages/user/pages/profile/ git commit -m "feat: 用户端个人中心(用户信息 + 功能菜单)" ``` --- ## Task 18:编译验证 + 最终提交 **Files:** 无新增/修改,仅验证 - [ ] **Step 1:类型检查** 运行: ```bash cd zhy-test && npx vue-tsc --noEmit 2>&1 ``` 预期:无类型错误。如有错误,逐一修复。 - [ ] **Step 2:H5 模式编译测试** 运行: ```bash cd zhy-test && npx uni 2>&1 | head -30 ``` 预期:Vite 开发服务器启动成功。(Ctrl+C 停止) - [ ] **Step 3:微信小程序编译测试** 运行: ```bash cd zhy-test && npx uni build -p mp-weixin 2>&1 | tail -20 ``` 预期:构建成功,生成 `dist/build/mp-weixin` 目录。 - [ ] **Step 4:检查分包目录结构** 运行: ```bash find src/packages -type f -name '*.vue' | sort ``` 预期输出: ``` src/packages/user/pages/card/activate.vue src/packages/user/pages/card/bind.vue src/packages/user/pages/card/buy.vue src/packages/user/pages/card/detail.vue src/packages/user/pages/card/list.vue src/packages/user/pages/card/qrcode.vue src/packages/user/pages/index/index.vue src/packages/user/pages/profile/index.vue ``` - [ ] **Step 5:最终提交** ```bash git add -A git commit -m "feat: 湖南12301第一迭代完成 — 基础层 + 用户端核心流程" ``` --- ## 手动测试清单 编译为微信小程序后,在微信开发者工具中按以下流程手动验证: | 步骤 | 操作 | 预期结果 | |------|------|----------| | 1 | 启动小程序 | 显示启动页,自动跳转到登录页 | | 2 | 点击"微信一键登录" | 调用微信登录,成功后跳转用户首页 | | 3 | 用户首页 | 显示宫格入口 + 推荐年卡列表 | | 4 | 点击"景区预约" | 弹出"即将上线"提示 | | 5 | 点击"购买年卡" | 进入年卡列表页 | | 6 | 点击一张年卡 | 进入年卡详情页 | | 7 | 点击"立即购买" | 进入确认购买页 | | 8 | 点击"确认支付" | 模拟支付成功,跳转激活页 | | 9 | 填写实名信息并激活 | 激活成功,跳转入园码页 | | 10 | 入园码页 | 显示年卡信息 + 二维码,60秒自动刷新 | | 11 | 切换到"我的"Tab | 显示个人中心 | | 12 | 点击"退出登录" | 清除状态,回到登录页 |