# GameGroup 前端开发步骤文档 **项目名称**: GameGroupFE **文档版本**: v1.0 **创建时间**: 2026-01-28 **技术栈**: Vue 3 + TypeScript + Vite + Pinia + Vue Router + Element Plus + Tailwind CSS --- ## 📋 目录 - [阶段一:项目初始化](#阶段一项目初始化) - [阶段二:基础配置](#阶段二基础配置) - [阶段三:目录结构创建](#阶段三目录结构创建) - [阶段四:基础组件开发](#阶段四基础组件开发) - [阶段五:布局组件开发](#阶段五布局组件开发) - [阶段六:业务组件开发](#阶段六业务组件开发) - [阶段七:API服务层](#阶段七api服务层) - [阶段八:状态管理](#阶段八状态管理) - [阶段九:路由配置](#阶段九路由配置) - [阶段十:页面开发](#阶段十页面开发) - [阶段十一:移动端适配](#阶段十一移动端适配) - [阶段十二:测试与优化](#阶段十二测试与优化) --- ## 阶段一:项目初始化 ### 步骤 1.1:创建 Vite 项目 ```bash # 在项目根目录执行 cd /home/congsh/CodeSpace/GameGroupFE npm create vite@latest . -- --template vue-ts ``` **验证**: 检查是否生成以下文件 - [ ] `package.json` - [ ] `vite.config.ts` - [ ] `tsconfig.json` - [ ] `src/main.ts` - [ ] `src/App.vue` - [ ] `index.html` ### 步骤 1.2:安装核心依赖 ```bash npm install vue@^3.4.0 npm install vue-router@^4.2.0 npm install pinia@^2.1.0 npm install axios@^1.6.0 npm install element-plus@^2.5.0 npm install @element-plus/icons-vue@^2.3.0 ``` **验证**: 检查 `package.json` 中的 dependencies - [ ] vue: ^3.4.0 - [ ] vue-router: ^4.2.0 - [ ] pinia: ^2.1.0 - [ ] axios: ^1.6.0 - [ ] element-plus: ^2.5.0 ### 步骤 1.3:安装开发依赖 ```bash # Tailwind CSS npm install -D tailwindcss@^3.4.0 postcss@^8.4.0 autoprefixer@^10.4.0 # TypeScript 类型 npm install -D @types/node@^20.0.0 # 代码规范工具 npm install -D eslint@^8.56.0 prettier@^3.1.0 # Sass 支持 npm install -D sass@^1.69.0 ``` **验证**: 检查 `package.json` 中的 devDependencies - [ ] tailwindcss: ^3.4.0 - [ ] postcss: ^8.4.0 - [ ] autoprefixer: ^10.4.0 - [ ] @types/node: ^20.0.0 - [ ] sass: ^1.69.0 ### 步骤 1.4:初始化 Tailwind CSS ```bash npx tailwindcss init -p ``` **验证**: 检查是否生成以下文件 - [ ] `tailwind.config.js` - [ ] `postcss.config.js` ### 步骤 1.5:初始化 Git ```bash git init git add . git commit -m "feat: 初始化项目脚手架" ``` **验证**: 检查 `.git` 目录是否存在 --- ## 阶段二:基础配置 ### 步骤 2.1:配置 Vite 编辑 `vite.config.ts`: ```typescript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': resolve(__dirname, 'src') } }, server: { port: 5173, proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } }, build: { target: 'es2015', outDir: 'dist', assetsDir: 'assets', sourcemap: false, minify: 'terser', rollupOptions: { output: { manualChunks: { vendor: ['vue', 'vue-router', 'pinia'], ui: ['element-plus'] } } } } }) ``` **验证**: 执行 `npm run dev`,确认开发服务器正常启动 ### 步骤 2.2:配置 TypeScript 编辑 `tsconfig.json`,添加路径别名: ```json { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"] } } } ``` **验证**: 在 `.vue` 文件中测试导入 `import { xxx } from '@/utils'` ### 步骤 2.3:配置 Tailwind CSS 编辑 `tailwind.config.js`: ```javascript /** @type {import('tailwindcss').Config} */ export default { content: [ "./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}", ], theme: { extend: { colors: { primary: { 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', }, accent: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', }, }, spacing: { '1': '0.25rem', '2': '0.5rem', '3': '0.75rem', '4': '1rem', '5': '1.25rem', '6': '1.5rem', '8': '2rem', '10': '2.5rem', '12': '3rem', '16': '4rem', '20': '5rem', }, }, }, plugins: [], } ``` 编辑 `src/assets/styles/main.css`: ```css @tailwind base; @tailwind components; @tailwind utilities; @layer base { body { @apply bg-gray-50 text-gray-900; } } ``` **验证**: 在 `src/main.ts` 中引入样式,检查页面样式是否生效 ### 步骤 2.4:配置 Element Plus 编辑 `src/main.ts`: ```typescript import { createApp } from 'vue' import App from './App.vue' import router from './router' import { createPinia } from 'pinia' // Element Plus import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import * as ElementPlusIconsVue from '@element-plus/icons-vue' // 样式 import './assets/styles/main.css' const app = createApp(App) // 注册所有图标 for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } app.use(createPinia()) app.use(router) app.use(ElementPlus) app.mount('#app') ``` **验证**: 在页面中测试 `` 组件是否正常显示 --- ## 阶段三:目录结构创建 ### 步骤 3.1:创建完整目录结构 ```bash mkdir -p src/assets/{images,icons,styles} mkdir -p src/components/{common,business,layout} mkdir -p src/composables mkdir -p src/stores mkdir -p src/api mkdir -p src/router mkdir -p src/views/{auth,home,user,group,game,appointment,ledger,schedule,honor,asset,points,bet} mkdir -p src/types mkdir -p src/utils mkdir -p src/constants mkdir -p src/directives mkdir -p public ``` **验证**: 检查目录结构是否完整创建 ### 步骤 3.2:创建基础文件 ```bash # 创建类型定义文件 touch src/types/api.ts touch src/types/user.ts touch src/types/group.ts touch src/types/game.ts touch src/types/appointment.ts # 创建常量文件 touch src/constants/enums.ts touch src/constants/config.ts # 创建工具函数 touch src/utils/request.ts touch src/utils/storage.ts touch src/utils/format.ts touch src/utils/validate.ts # 创建API文件 touch src/api/index.ts touch src/api/auth.ts touch src/api/user.ts touch src/api/group.ts touch src/api/game.ts touch src/api/appointment.ts ``` **验证**: 确认所有文件都已创建 --- ## 阶段四:基础组件开发 ### 步骤 4.1:Button 按钮 创建 `src/components/common/Button/Button.vue`: ```vue ``` **验证**: 在页面中使用 ``,检查样式和交互 ### 步骤 4.2:Input 输入框 创建 `src/components/common/Input/Input.vue`: ```vue ``` **验证**: 测试输入、清除、禁用等功能 ### 步骤 4.3:Modal 弹窗 创建 `src/components/common/Modal/Modal.vue`: ```vue ``` **验证**: 测试弹窗的打开、关闭、点击遮罩关闭等功能 ### 步骤 4.4:Card 卡片 创建 `src/components/common/Card/Card.vue`: ```vue ``` **验证**: 测试卡片的悬停、点击效果 ### 步骤 4.5:其他基础组件 使用相同模式创建: - [ ] `Loading` - 加载组件 - [ ] `Avatar` - 头像组件 - [ ] `Badge` - 徽章组件 - [ ] `Tag` - 标签组件 --- ## 阶段五:布局组件开发 ### 步骤 5.1:MainLayout 主布局 创建 `src/components/layout/MainLayout.vue`: ```vue ``` ### 步骤 5.2:AppHeader 顶部导航 创建 `src/components/layout/AppHeader.vue`: ```vue ``` ### 步骤 5.3:AppSidebar 侧边栏 创建 `src/components/layout/AppSidebar.vue`: ```vue ``` **验证**: 检查布局组件是否正确显示和响应 --- ## 阶段六:业务组件开发 ### 步骤 6.1:UserCard 用户卡片 创建 `src/components/business/UserCard/UserCard.vue`: ```vue ``` ### 步骤 6.2:GroupCard 小组卡片 创建 `src/components/business/GroupCard/GroupCard.vue`: ```vue ``` ### 步骤 6.3:GameCard 游戏卡片 创建 `src/components/business/GameCard/GameCard.vue`: ```vue ``` ### 步骤 6.4:AppointmentCard 预约卡片 创建 `src/components/business/AppointmentCard/AppointmentCard.vue`: ```vue ``` **验证**: 测试所有业务组件的显示和交互 --- ## 阶段七:API服务层 ### 步骤 7.1:配置 Axios 创建 `src/utils/request.ts`: ```typescript import axios, { AxiosInstance, AxiosError, AxiosResponse } from 'axios' import { ElMessage } from 'element-plus' // 创建 axios 实例 const service: AxiosInstance = axios.create({ baseURL: '/api', timeout: 15000, headers: { 'Content-Type': 'application/json' } }) // 请求拦截器 service.interceptors.request.use( (config) => { // 从 localStorage 获取 token const token = localStorage.getItem('access_token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, (error) => { return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( (response: AxiosResponse) => { const { code, message, data } = response.data if (code === 0) { return data } else { ElMessage.error(message || '请求失败') return Promise.reject(new Error(message)) } }, (error: AxiosError) => { if (error.response?.status === 401) { ElMessage.error('登录已过期,请重新登录') localStorage.removeItem('access_token') localStorage.removeItem('refresh_token') window.location.href = '/login' } else { ElMessage.error(error.message || '网络错误') } return Promise.reject(error) } ) export default service ``` ### 步骤 7.2:定义API类型 创建 `src/types/api.ts`: ```typescript // 统一响应格式 export interface ApiResponse { code: number message: string data: T timestamp: number } // 分页响应 export interface PageResponse { items: T[] total: number page: number limit: number totalPages: number } ``` ### 步骤 7.3:创建认证API 创建 `src/api/auth.ts`: ```typescript import request from '@/utils/request' export interface LoginParams { account: string password: string } export interface RegisterParams { username: string password: string email?: string phone?: string } export interface LoginResponse { user: UserInfo accessToken: string refreshToken: string } export const authApi = { // 登录 login(params: LoginParams) { return request.post('/auth/login', params) }, // 注册 register(params: RegisterParams) { return request.post('/auth/register', params) }, // 刷新令牌 refreshToken(refreshToken: string) { return request.post<{ accessToken: string; refreshToken: string }>('/auth/refresh', { refreshToken }) } } ``` ### 步骤 7.4:创建用户API 创建 `src/api/user.ts`: ```typescript import request from '@/utils/request' export const userApi = { // 获取当前用户信息 getProfile() { return request.get('/users/me') }, // 获取指定用户信息 getUserInfo(id: string) { return request.get(`/users/${id}`) }, // 更新用户信息 updateProfile(data: Partial) { return request.put('/users/me', data) }, // 修改密码 changePassword(data: { oldPassword: string; newPassword: string }) { return request.put('/users/me/password', data) } } ``` ### 步骤 7.5:创建小组API 创建 `src/api/group.ts`: ```typescript import request from '@/utils/request' export const groupApi = { // 创建小组 create(data: CreateGroupParams) { return request.post('/groups', data) }, // 加入小组 join(data: { groupId: string; nickname?: string }) { return request.post('/groups/join', data) }, // 获取我的小组列表 getMyGroups() { return request.get('/groups/my') }, // 获取小组详情 getGroupDetail(id: string) { return request.get(`/groups/${id}`) }, // 更新小组信息 updateGroup(id: string, data: Partial) { return request.put(`/groups/${id}`, data) }, // 退出小组 leaveGroup(id: string) { return request.delete(`/groups/${id}/leave`) }, // 解散小组 dissolveGroup(id: string) { return request.delete(`/groups/${id}`) } } ``` **验证**: 测试API调用是否正常,检查请求和响应格式 --- ## 阶段八:状态管理 ### 步骤 8.1:创建认证Store 创建 `src/stores/auth.ts`: ```typescript import { defineStore } from 'pinia' import { ref, computed } from 'vue' import { authApi } from '@/api/auth' import type { UserInfo } from '@/types/user' export const useAuthStore = defineStore('auth', () => { // State const userInfo = ref(null) const accessToken = ref('') const refreshToken = ref('') // Getters const isLoggedIn = computed(() => !!accessToken.value && !!userInfo.value) // Actions async function login(account: string, password: string) { const data = await authApi.login({ account, password }) userInfo.value = data.user accessToken.value = data.accessToken refreshToken.value = data.refreshToken // 保存到 localStorage localStorage.setItem('access_token', data.accessToken) localStorage.setItem('refresh_token', data.refreshToken) } async function register(params: { username: string password: string email?: string phone?: string }) { const data = await authApi.register(params) userInfo.value = data.user accessToken.value = data.accessToken refreshToken.value = data.refreshToken localStorage.setItem('access_token', data.accessToken) localStorage.setItem('refresh_token', data.refreshToken) } function logout() { userInfo.value = null accessToken.value = '' refreshToken.value = '' localStorage.removeItem('access_token') localStorage.removeItem('refresh_token') } function initAuth() { const token = localStorage.getItem('access_token') const refresh = localStorage.getItem('refresh_token') if (token) { accessToken.value = token } if (refresh) { refreshToken.value = refresh } } return { userInfo, accessToken, refreshToken, isLoggedIn, login, register, logout, initAuth } }) ``` ### 步骤 8.2:创建应用Store 创建 `src/stores/app.ts`: ```typescript import { defineStore } from 'pinia' import { ref } from 'vue' export const useAppStore = defineStore('app', () => { const theme = ref<'light' | 'dark'>('light') const sidebarCollapsed = ref(false) const loading = ref(false) function toggleTheme() { theme.value = theme.value === 'light' ? 'dark' : 'light' } function toggleSidebar() { sidebarCollapsed.value = !sidebarCollapsed.value } function setLoading(value: boolean) { loading.value = value } return { theme, sidebarCollapsed, loading, toggleTheme, toggleSidebar, setLoading } }) ``` **验证**: 测试状态管理是否正常工作 --- ## 阶段九:路由配置 ### 步骤 9.1:配置路由 创建 `src/router/index.ts`: ```typescript import { createRouter, createWebHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' import { useAuthStore } from '@/stores/auth' const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: () => import('@/views/auth/Login.vue'), meta: { requiresAuth: false } }, { path: '/register', name: 'Register', component: () => import('@/views/auth/Register.vue'), meta: { requiresAuth: false } }, { path: '/', component: () => import('@/components/layout/MainLayout.vue'), meta: { requiresAuth: true }, children: [ { path: '', name: 'Home', component: () => import('@/views/home/index.vue') }, { path: 'user/profile', name: 'UserProfile', component: () => import('@/views/user/Profile.vue') }, { path: 'user/settings', name: 'UserSettings', component: () => import('@/views/user/Settings.vue') }, { path: 'groups', name: 'GroupList', component: () => import('@/views/group/List.vue') }, { path: 'groups/create', name: 'GroupCreate', component: () => import('@/views/group/Create.vue') }, { path: 'groups/:id', name: 'GroupDetail', component: () => import('@/views/group/Detail.vue') }, { path: 'games', name: 'GameList', component: () => import('@/views/game/List.vue') }, { path: 'games/:id', name: 'GameDetail', component: () => import('@/views/game/Detail.vue') }, { path: 'appointments', name: 'AppointmentList', component: () => import('@/views/appointment/List.vue') }, { path: 'appointments/create', name: 'AppointmentCreate', component: () => import('@/views/appointment/Create.vue') }, { path: 'points/ranking/:groupId', name: 'PointsRanking', component: () => import('@/views/points/Ranking.vue') }, { path: 'honors/:groupId', name: 'Honors', component: () => import('@/views/honor/Timeline.vue') } ] } ] const router = createRouter({ history: createWebHistory(), routes }) // 路由守卫 router.beforeEach((to, from, next) => { const authStore = useAuthStore() const requiresAuth = to.meta.requiresAuth !== false if (requiresAuth && !authStore.isLoggedIn) { next({ name: 'Login', query: { redirect: to.fullPath } }) } else { next() } }) export default router ``` **验证**: 测试路由导航和权限控制是否正常 --- ## 阶段十:页面开发 ### 步骤 10.1:登录页面 创建 `src/views/auth/Login.vue`: ```vue ``` **验证**: 测试登录功能和表单验证 ### 步骤 10.2:注册页面 创建 `src/views/auth/Register.vue`: ```vue ``` **验证**: 测试注册功能和表单验证 ### 步骤 10.3:首页 创建 `src/views/home/index.vue`: ```vue ``` **验证**: 测试首页数据显示和导航跳转 ### 步骤 10.4:小组列表页 创建 `src/views/group/List.vue`: ```vue ``` **验证**: 测试小组列表显示和筛选功能 ### 步骤 10.5:创建其他页面 按照相同模式创建以下页面: - [ ] `src/views/user/Profile.vue` - 个人资料 - [ ] `src/views/user/Settings.vue` - 设置 - [ ] `src/views/group/Create.vue` - 创建小组 - [ ] `src/views/group/Detail.vue` - 小组详情 - [ ] `src/views/game/List.vue` - 游戏列表 - [ ] `src/views/game/Detail.vue` - 游戏详情 - [ ] `src/views/appointment/List.vue` - 预约列表 - [ ] `src/views/appointment/Create.vue` - 创建预约 - [ ] `src/views/points/Ranking.vue` - 积分排行榜 - [ ] `src/views/honor/Timeline.vue` - 荣誉墙时间轴 --- ## 阶段十一:移动端适配 ### 步骤 11.1:创建移动端布局 创建 `src/components/layout/MobileLayout.vue`: ```vue ``` ### 步骤 11.2:添加响应式断点 在 `tailwind.config.js` 中确认移动端断点: ```javascript theme: { screens: { 'xs': '0px', 'sm': '640px', 'md': '768px', 'lg': '1024px', 'xl': '1280px', '2xl': '1536px' } } ``` ### 步骤 11.3:优化移动端触摸 确保按钮最小触摸目标为 44px × 44px: ```scss // 移动端按钮优化 @media (max-width: 768px) { .g-button { min-height: 44px; min-width: 44px; } } ``` **验证**: 在不同设备尺寸下测试页面显示效果 --- ## 阶段十二:测试与优化 ### 步骤 12.1:功能测试清单 - [ ] 认证功能 - [ ] 登录成功 - [ ] 登录失败处理 - [ ] 注册成功 - [ ] 注册验证 - [ ] Token 刷新 - [ ] 退出登录 - [ ] 用户中心 - [ ] 查看个人资料 - [ ] 编辑个人资料 - [ ] 修改密码 - [ ] 设置功能 - [ ] 小组管理 - [ ] 创建小组 - [ ] 加入小组 - [ ] 查看小组详情 - [ ] 编辑小组信息 - [ ] 退出小组 - [ ] 成员管理 - [ ] 游戏库 - [ ] 游戏列表展示 - [ ] 游戏搜索 - [ ] 游戏筛选 - [ ] 查看游戏详情 - [ ] 预约系统 - [ ] 创建预约 - [ ] 查看预约列表 - [ ] 加入预约 - [ ] 退出预约 - [ ] 预约状态管理 ### 步骤 12.2:性能优化 - [ ] 启用路由懒加载 - [ ] 组件按需加载 - [ ] 图片懒加载 - [ ] 长列表虚拟滚动 - [ ] 防抖和节流 - [ ] 代码分割 ### 步骤 12.3:响应式测试 测试设备: - [ ] iPhone SE (375px) - [ ] iPhone 12 Pro (390px) - [ ] iPad (768px) - [ ] iPad Pro (1024px) - [ ] Desktop (1920px) ### 步骤 12.4:构建和部署 ```bash # 构建生产版本 npm run build # 预览构建结果 npm run preview # 检查构建文件大小 ls -lh dist/ ``` **验证**: 确认构建输出正常,文件大小合理 --- ## 附录:开发规范 ### A.1 命名规范 - **组件文件**: PascalCase (UserCard.vue) - **普通文件**: kebab-case (user-profile.ts) - **变量/函数**: camelCase (getUserInfo) - **常量**: UPPER_SNAKE_CASE (API_BASE_URL) - **类型/接口**: PascalCase (UserProfile) ### A.2 代码组织 ```vue ``` ### A.3 Git提交规范 ```bash feat: 新功能 fix: 修复bug docs: 文档更新 style: 代码格式调整 refactor: 重构 test: 测试相关 chore: 构建/工具相关 ``` --- ## 总结 本文档提供了 GameGroup 前端项目的完整开发步骤,涵盖从项目初始化到部署上线的全过程。 **预计开发周期**: 55个工作日(约11周) **关键里程碑**: - Week 1-2: 项目初始化、基础组件、布局 - Week 3-5: 核心业务模块(认证、用户、小组、游戏) - Week 6-8: 高级功能模块(预约、积分、荣誉等) - Week 9-10: 移动端适配、性能优化 - Week 11: 测试、修复、部署 **持续更新**: 本文档应随开发进度持续更新和完善。 --- **文档维护**: Frontend Team **创建时间**: 2026-01-28 **最后更新**: 2026-01-28