Files
gamegroup_fe/doc/design/01-前端架构设计.md

686 lines
17 KiB
Markdown
Raw Normal View History

2026-01-28 14:35:43 +08:00
# GameGroup 前端架构设计文档
**项目名称**: GameGroup 前端系统
**文档版本**: v1.0
**更新时间**: 2026-01-28
---
## 📋 目录
- [1. 项目概述](#1-项目概述)
- [2. 技术栈选型](#2-技术栈选型)
- [3. 项目架构](#3-项目架构)
- [4. 目录结构](#4-目录结构)
- [5. 核心设计原则](#5-核心设计原则)
- [6. 状态管理](#6-状态管理)
- [7. 路由设计](#7-路由设计)
- [8. API请求层](#8-api请求层)
- [9. 性能优化](#9-性能优化)
---
## 1. 项目概述
GameGroup 是一个游戏社群管理平台,为玩家提供小组管理、游戏预约、积分系统、竞猜等功能。前端项目采用现代化的技术栈,注重用户体验和性能优化。
### 核心功能模块
- **认证模块**: 用户注册、登录、令牌刷新
- **用户中心**: 个人资料管理、设置
- **小组管理**: 创建/加入小组、成员管理、权限控制
- **游戏库**: 游戏浏览、搜索、筛选
- **预约系统**: 创建预约、加入/退出预约、时间管理
- **账目管理**: 账目记录、统计分析
- **排班助手**: 空闲时间提交、共同时间查找
- **荣誉墙**: 荣誉展示、时间轴
- **资产管理**: 资产借用/归还、流转记录
- **积分系统**: 积分查询、排行榜
- **竞猜系统**: 创建竞猜、参与竞猜、结算
---
## 2. 技术栈选型
### 核心框架
```json
{
"framework": "Vue 3",
"buildTool": "Vite",
"language": "TypeScript",
"router": "Vue Router 4",
"stateManagement": "Pinia",
"uiFramework": "Element Plus / Ant Design Vue",
"cssFramework": "Tailwind CSS / UnoCSS",
"http": "Axios"
}
```
### 选型理由
#### Vue 3 + TypeScript
- **组合式 API**: 更好的逻辑复用和代码组织
- **类型安全**: TypeScript提供完整的类型推导和检查
- **性能提升**: 更小的包体积、更快的渲染
- **生态成熟**: 丰富的插件和工具支持
#### Vite
- **极速开发**: 基于ESM的即时热更新
- **快速构建**: Rollup打包,生产环境优化
- **现代化**: 原生支持ES模块、TypeScript、JSX
#### Pinia
- **Vue 3官方推荐**: 替代Vuex的下一代状态管理
- **类型友好**: 完整的TypeScript支持
- **轻量简洁**: API设计简洁,学习成本低
- **Devtools**: 优秀的开发者工具集成
#### Vue Router 4
- **官方路由**: Vue生态标准路由方案
- **动态路由**: 支持路由级代码分割
- **导航守卫**: 完善的权限控制
---
## 3. 项目架构
### 3.1 分层架构
```
┌─────────────────────────────────────┐
│ Presentation Layer │
│ (Components / Views / Layouts) │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Business Logic Layer │
│ (Composables / Stores / Hooks) │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Data Access Layer │
│ (API Services / Local Storage) │
└─────────────────────────────────────┘
```
### 3.2 模块化设计
每个功能模块包含:
- **Views**: 页面级组件
- **Components**: 模块内组件
- **Composables**: 业务逻辑复用
- **Stores**: 状态管理
- **API**: 接口请求
- **Types**: TypeScript类型定义
- **Utils**: 工具函数
---
## 4. 目录结构
```
GameGroupFE/
├── public/ # 静态资源
│ ├── favicon.ico
│ └── ...
├── src/
│ ├── assets/ # 资源文件
│ │ ├── images/ # 图片
│ │ ├── icons/ # 图标
│ │ └── styles/ # 全局样式
│ │ ├── variables.scss # 样式变量
│ │ ├── mixins.scss # 样式混入
│ │ └── global.scss # 全局样式
│ ├── components/ # 公共组件
│ │ ├── common/ # 通用组件
│ │ │ ├── Button/
│ │ │ ├── Input/
│ │ │ ├── Modal/
│ │ │ └── Loading/
│ │ ├── business/ # 业务组件
│ │ │ ├── UserCard/
│ │ │ ├── GroupCard/
│ │ │ └── GameCard/
│ │ └── layout/ # 布局组件
│ │ ├── Header/
│ │ ├── Sidebar/
│ │ └── Footer/
│ ├── composables/ # 组合式函数
│ │ ├── useAuth.ts # 认证相关
│ │ ├── useRequest.ts # 请求封装
│ │ ├── usePagination.ts # 分页逻辑
│ │ └── useWebSocket.ts # WebSocket
│ ├── stores/ # Pinia状态管理
│ │ ├── auth.ts # 认证状态
│ │ ├── user.ts # 用户状态
│ │ ├── group.ts # 小组状态
│ │ └── app.ts # 应用状态
│ ├── api/ # API接口
│ │ ├── index.ts # Axios配置
│ │ ├── auth.ts # 认证接口
│ │ ├── user.ts # 用户接口
│ │ ├── group.ts # 小组接口
│ │ └── ...
│ ├── router/ # 路由配置
│ │ ├── index.ts # 路由入口
│ │ ├── routes/ # 路由模块
│ │ └── guards.ts # 路由守卫
│ ├── views/ # 页面视图
│ │ ├── auth/ # 认证相关页面
│ │ │ ├── Login.vue
│ │ │ └── Register.vue
│ │ ├── home/ # 首页
│ │ │ └── index.vue
│ │ ├── user/ # 用户中心
│ │ │ ├── Profile.vue
│ │ │ └── Settings.vue
│ │ ├── group/ # 小组管理
│ │ │ ├── List.vue
│ │ │ ├── Detail.vue
│ │ │ └── Create.vue
│ │ ├── game/ # 游戏库
│ │ ├── appointment/ # 预约管理
│ │ └── ...
│ ├── types/ # TypeScript类型定义
│ │ ├── api.ts # API响应类型
│ │ ├── user.ts # 用户类型
│ │ ├── group.ts # 小组类型
│ │ └── ...
│ ├── utils/ # 工具函数
│ │ ├── request.ts # 请求工具
│ │ ├── storage.ts # 存储工具
│ │ ├── format.ts # 格式化工具
│ │ └── validate.ts # 验证工具
│ ├── constants/ # 常量定义
│ │ ├── enums.ts # 枚举
│ │ └── config.ts # 配置
│ ├── directives/ # 自定义指令
│ │ └── permission.ts
│ ├── App.vue # 根组件
│ └── main.ts # 应用入口
├── tests/ # 测试文件
│ ├── unit/ # 单元测试
│ └── e2e/ # E2E测试
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
├── .eslintrc.cjs # ESLint配置
├── .prettierrc # Prettier配置
├── tsconfig.json # TypeScript配置
├── vite.config.ts # Vite配置
├── tailwind.config.js # Tailwind配置
└── package.json # 项目配置
```
---
## 5. 核心设计原则
### 5.1 组件设计原则
#### 单一职责原则
每个组件只负责一个功能,保持组件的独立性和可复用性。
#### 组合优于继承
使用组合式API和props/events进行组件通信,避免复杂的继承关系。
#### 容器组件与展示组件分离
- **容器组件**: 处理业务逻辑和状态管理
- **展示组件**: 纯UI渲染,通过props接收数据
### 5.2 代码规范
#### 命名规范
- **组件**: PascalCase (UserCard.vue)
- **文件**: kebab-case (user-profile.ts)
- **变量/函数**: camelCase (getUserInfo)
- **常量**: UPPER_SNAKE_CASE (API_BASE_URL)
- **类型/接口**: PascalCase (UserProfile)
#### 文件组织
- 一个文件只导出一个主要内容
- 相关文件放在同一目录
- 使用index.ts统一导出
#### 注释规范
```typescript
/**
* 获取用户信息
* @param userId - 用户ID
* @returns 用户信息对象
*/
async function getUserInfo(userId: string): Promise<User> {
// 实现
}
```
---
## 6. 状态管理
### 6.1 Pinia Store设计
#### 模块化Store
每个业务模块创建独立的Store:
```typescript
// stores/user.ts
export const useUserStore = defineStore('user', () => {
// State
const userInfo = ref<UserInfo | null>(null)
const isLoading = ref(false)
// Getters
const isLoggedIn = computed(() => !!userInfo.value)
// Actions
async function fetchUserInfo() {
isLoading.value = true
try {
const data = await userApi.getProfile()
userInfo.value = data
} finally {
isLoading.value = false
}
}
return {
userInfo,
isLoading,
isLoggedIn,
fetchUserInfo
}
})
```
#### 全局Store
应用级别的状态:
```typescript
// stores/app.ts
export const useAppStore = defineStore('app', () => {
const theme = ref<Theme>('light')
const language = ref<Language>('zh-CN')
const sidebarCollapsed = ref(false)
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
return {
theme,
language,
sidebarCollapsed,
toggleTheme
}
})
```
### 6.2 持久化策略
使用`pinia-plugin-persistedstate`实现状态持久化:
```typescript
// pinia.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
export default pinia
```
---
## 7. 路由设计
### 7.1 路由结构
```typescript
// router/index.ts
const routes: RouteRecordRaw[] = [
{
path: '/login',
name: 'Login',
component: () => import('@/views/auth/Login.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: 'groups',
name: 'GroupList',
component: () => import('@/views/group/List.vue')
},
{
path: 'groups/:id',
name: 'GroupDetail',
component: () => import('@/views/group/Detail.vue')
},
// 更多路由...
]
}
]
```
### 7.2 路由守卫
```typescript
// router/guards.ts
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()
}
})
```
---
## 8. API请求层
### 8.1 Axios封装
```typescript
// api/index.ts
import axios from 'axios'
import { ElMessage } from 'element-plus'
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 15000
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
const authStore = useAuthStore()
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response) => {
const { code, message, data } = response.data
if (code === 0) {
return data
} else {
ElMessage.error(message || '请求失败')
return Promise.reject(new Error(message))
}
},
(error) => {
if (error.response?.status === 401) {
// Token过期,刷新Token或跳转登录
const authStore = useAuthStore()
authStore.logout()
}
return Promise.reject(error)
}
)
export default service
```
### 8.2 API模块化
```typescript
// api/user.ts
import request from './index'
export const userApi = {
// 获取用户信息
getProfile() {
return request.get<UserInfo>('/users/me')
},
// 更新用户信息
updateProfile(data: UpdateProfileDto) {
return request.put<UserInfo>('/users/me', data)
},
// 修改密码
changePassword(data: ChangePasswordDto) {
return request.put('/users/me/password', data)
}
}
```
---
## 9. 性能优化
### 9.1 代码分割
#### 路由级代码分割
使用动态import实现路由懒加载:
```typescript
{
path: '/groups',
component: () => import('@/views/group/List.vue')
}
```
#### 组件级代码分割
```vue
<script setup>
import { defineAsyncComponent } from 'vue'
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
</script>
```
### 9.2 资源优化
#### 图片优化
- 使用WebP格式
- 实现懒加载
- 响应式图片
#### 依赖优化
- Tree-shaking
- 按需引入组件库
- 使用轻量级替代方案
### 9.3 渲染优化
#### 虚拟滚动
长列表使用虚拟滚动:
```vue
<template>
<VirtualList
:items="largeList"
:item-height="50"
:visible-height="600"
/>
</template>
```
#### 防抖与节流
```typescript
import { useDebounceFn } from '@vueuse/core'
const search = useDebounceFn((keyword: string) => {
// 执行搜索
}, 300)
```
### 9.4 缓存策略
#### 接口缓存
```typescript
// api/cache.ts
const cache = new Map()
export async function cachedFetch<T>(
key: string,
fetcher: () => Promise<T>,
ttl = 60000
): Promise<T> {
const cached = cache.get(key)
if (cached && Date.now() - cached.time < ttl) {
return cached.data
}
const data = await fetcher()
cache.set(key, { data, time: Date.now() })
return data
}
```
#### 组件缓存
```vue
<KeepAlive :include="['GroupList', 'GameList']">
<RouterView />
</KeepAlive>
```
---
## 10. 开发工具链
### 10.1 代码质量
- **ESLint**: 代码规范检查
- **Prettier**: 代码格式化
- **Stylelint**: 样式规范检查
- **TypeScript**: 类型检查
### 10.2 Git规范
- **Husky**: Git hooks
- **lint-staged**: 暂存文件检查
- **Commitlint**: 提交信息规范
### 10.3 CI/CD
- **GitHub Actions**: 自动化部署
- **Vercel/Netlify**: 前端托管
---
## 11. 测试策略
### 11.1 单元测试
使用Vitest进行单元测试:
```typescript
// tests/utils/format.test.ts
import { describe, it, expect } from 'vitest'
import { formatDate } from '@/utils/format'
describe('formatDate', () => {
it('should format date correctly', () => {
const date = new Date('2026-01-28')
expect(formatDate(date)).toBe('2026-01-28')
})
})
```
### 11.2 组件测试
使用Vue Test Utils:
```typescript
import { mount } from '@vue/test-utils'
import Button from '@/components/common/Button/Button.vue'
describe('Button', () => {
it('renders text', () => {
const wrapper = mount(Button, {
slots: { default: 'Click me' }
})
expect(wrapper.text()).toBe('Click me')
})
})
```
---
## 12. 部署方案
### 12.1 构建配置
```typescript
// vite.config.ts
export default defineConfig({
build: {
target: 'es2015',
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false,
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks: {
'vendor': ['vue', 'vue-router', 'pinia'],
'ui': ['element-plus']
}
}
}
}
})
```
### 12.2 环境变量
```bash
# .env.development
VITE_API_BASE_URL=http://localhost:3000/api
# .env.production
VITE_API_BASE_URL=https://api.gamegroup.com/api
```
---
## 13. 总结
本架构设计遵循以下原则:
- ✅ 模块化: 清晰的模块划分,职责明确
- ✅ 可维护性: 规范的代码组织,易于维护
- ✅ 可扩展性: 灵活的架构设计,便于扩展
- ✅ 性能优化: 多层次的优化策略
- ✅ 开发体验: 完善的工具链支持
---
**文档维护**: 本文档应随项目演进持续更新
**最后更新**: 2026-01-28