feat: 初始化项目脚手架
This commit is contained in:
9
.claude/ralph-loop.local.md
Normal file
9
.claude/ralph-loop.local.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
active: true
|
||||
iteration: 1
|
||||
max_iterations: 0
|
||||
completion_promise: null
|
||||
started_at: "2026-01-28T06:32:21Z"
|
||||
---
|
||||
|
||||
按照 doc/开发步骤文档.md 中的12个阶段完成 GameGroup 前端项目的完整开发,包括项目初始化、基础配置、组件开发、API服务层、状态管理、路由配置、页面开发、移动端适配和测试优化
|
||||
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
413
doc/README.md
Normal file
413
doc/README.md
Normal file
@@ -0,0 +1,413 @@
|
||||
# GameGroup 前端项目文档
|
||||
|
||||
**项目名称**: GameGroup 前端系统
|
||||
**项目版本**: v1.0
|
||||
**文档更新**: 2026-01-28
|
||||
|
||||
---
|
||||
|
||||
## 📚 文档目录
|
||||
|
||||
本目录包含 GameGroup 前端项目的所有设计文档和技术文档。
|
||||
|
||||
### 📁 目录结构
|
||||
|
||||
```
|
||||
doc/
|
||||
├── README.md # 本文档 - 文档导航
|
||||
├── api/ # API相关文档
|
||||
│ └── API文档.md # 后端API接口文档
|
||||
├── design/ # 设计文档
|
||||
│ ├── 01-前端架构设计.md # 前端技术架构
|
||||
│ ├── 02-UI-UX设计规范.md # 视觉设计规范
|
||||
│ ├── 03-组件设计文档.md # 组件库设计
|
||||
│ └── 04-页面设计文档.md # 页面设计
|
||||
└── 后端相关文档/
|
||||
├── 后端README.md # 后端项目说明
|
||||
└── 后端项目分析报告.md # 后端代码分析
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 项目概述
|
||||
|
||||
GameGroup 是一个游戏社群管理平台,为玩家提供小组管理、游戏预约、积分系统、竞猜等功能。前端项目采用现代化的技术栈,注重用户体验和性能优化。
|
||||
|
||||
### 核心功能模块
|
||||
|
||||
- **认证模块**: 用户注册、登录、令牌刷新
|
||||
- **用户中心**: 个人资料管理、设置
|
||||
- **小组管理**: 创建/加入小组、成员管理、权限控制
|
||||
- **游戏库**: 游戏浏览、搜索、筛选
|
||||
- **预约系统**: 创建预约、加入/退出预约、时间管理
|
||||
- **账目管理**: 账目记录、统计分析
|
||||
- **排班助手**: 空闲时间提交、共同时间查找
|
||||
- **荣誉墙**: 荣誉展示、时间轴
|
||||
- **资产管理**: 资产借用/归还、流转记录
|
||||
- **积分系统**: 积分查询、排行榜
|
||||
- **竞猜系统**: 创建竞猜、参与竞猜、结算
|
||||
|
||||
---
|
||||
|
||||
## 🛠 技术栈
|
||||
|
||||
### 核心技术
|
||||
|
||||
| 技术 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| Vue | 3.x | 渐进式JavaScript框架 |
|
||||
| TypeScript | 5.x | JavaScript超集,提供类型安全 |
|
||||
| Vite | 5.x | 下一代前端构建工具 |
|
||||
| Vue Router | 4.x | Vue官方路由管理器 |
|
||||
| Pinia | 2.x | Vue官方状态管理库 |
|
||||
| Element Plus | 最新 | Vue 3 UI组件库 |
|
||||
| Tailwind CSS | 3.x | 原子化CSS框架 |
|
||||
| Axios | 1.x | HTTP客户端 |
|
||||
| Vitest | 最新 | 单元测试框架 |
|
||||
|
||||
### 开发工具
|
||||
|
||||
- **包管理器**: pnpm / npm / yarn
|
||||
- **代码规范**: ESLint + Prettier
|
||||
- **Git Hooks**: Husky + lint-staged
|
||||
- **提交规范**: Commitlint
|
||||
|
||||
---
|
||||
|
||||
## 📖 文档说明
|
||||
|
||||
### 1. 前端架构设计 ([01-前端架构设计.md](design/01-前端架构设计.md))
|
||||
|
||||
**内容概览**:
|
||||
- 技术栈选型和理由
|
||||
- 项目架构设计(分层架构、模块化)
|
||||
- 目录结构规范
|
||||
- 状态管理方案
|
||||
- 路由设计
|
||||
- API请求层封装
|
||||
- 性能优化策略
|
||||
- 开发工具链配置
|
||||
- 测试方案
|
||||
- 部署方案
|
||||
|
||||
**适合人群**: 技术负责人、架构师、开发者
|
||||
|
||||
**阅读时间**: 30分钟
|
||||
|
||||
---
|
||||
|
||||
### 2. UI/UX设计规范 ([02-UI-UX设计规范.md](design/02-UI-UX设计规范.md))
|
||||
|
||||
**内容概览**:
|
||||
- 设计理念和核心价值
|
||||
- 视觉风格定位
|
||||
- 色彩系统(主色调、功能色、游戏主题色)
|
||||
- 字体系统(字体家族、大小、字重、行高)
|
||||
- 间距系统
|
||||
- 组件规范(按钮、卡片、输入框、徽章、头像等)
|
||||
- 动效规范(动画时长、缓动函数、常用动效)
|
||||
- 响应式设计(断点系统、响应式策略)
|
||||
- 无障碍设计(键盘导航、屏幕阅读器)
|
||||
- 设计资源和工具
|
||||
|
||||
**适合人群**: UI设计师、前端开发者
|
||||
|
||||
**阅读时间**: 45分钟
|
||||
|
||||
---
|
||||
|
||||
### 3. 组件设计文档 ([03-组件设计文档.md](design/03-组件设计文档.md))
|
||||
|
||||
**内容概览**:
|
||||
- 组件概述和分类
|
||||
- 基础组件(按钮、输入框、弹窗、卡片、表格等)
|
||||
- 业务组件(用户卡片、小组卡片、游戏卡片、预约卡片等)
|
||||
- 布局组件(主布局、导航栏、侧边栏)
|
||||
- 组件通信方式(Props/Emits、Provide/Inject、Event Bus)
|
||||
- 组件性能优化(懒加载、缓存、虚拟滚动)
|
||||
- 组件测试示例
|
||||
|
||||
**适合人群**: 前端开发者
|
||||
|
||||
**阅读时间**: 60分钟
|
||||
|
||||
---
|
||||
|
||||
### 4. 页面设计文档 ([04-页面设计文档.md](design/04-页面设计文档.md))
|
||||
|
||||
**内容概览**:
|
||||
- 页面架构和层级
|
||||
- 认证页面(登录、注册)
|
||||
- 首页布局和内容
|
||||
- 用户中心(个人资料、设置)
|
||||
- 小组管理(列表、详情、创建)
|
||||
- 游戏库(列表、详情)
|
||||
- 预约管理(列表、创建)
|
||||
- 积分排行榜
|
||||
- 荣誉墙
|
||||
- 响应式适配
|
||||
- 页面动效
|
||||
|
||||
**适合人群**: UI设计师、前端开发者、产品经理
|
||||
|
||||
**阅读时间**: 50分钟
|
||||
|
||||
---
|
||||
|
||||
### 5. API接口文档 ([api/API文档.md](api/API文档.md))
|
||||
|
||||
**内容概览**:
|
||||
- 完整的后端API接口文档
|
||||
- 请求方法、参数、响应格式
|
||||
- 认证说明
|
||||
- 错误码对照表
|
||||
- 13个模块的70+接口:
|
||||
- 认证相关
|
||||
- 用户管理
|
||||
- 小组管理
|
||||
- 游戏库
|
||||
- 预约管理
|
||||
- 账目管理
|
||||
- 排班助手
|
||||
- 黑名单管理
|
||||
- 荣誉墙
|
||||
- 资产管理
|
||||
- 积分系统
|
||||
- 竞猜系统
|
||||
- 系统接口
|
||||
|
||||
**适合人群**: 前端开发者、后端开发者
|
||||
|
||||
**阅读时间**: 按需查阅
|
||||
|
||||
---
|
||||
|
||||
### 6. 后端项目文档
|
||||
|
||||
#### 后端README ([后端README.md](后端README.md))
|
||||
|
||||
后端项目的总体介绍,包含:
|
||||
- 技术栈(NestJS + TypeScript + MySQL)
|
||||
- 项目结构
|
||||
- 开发指南
|
||||
- 部署说明
|
||||
|
||||
#### 后端项目分析报告 ([后端项目分析报告.md](后端项目分析报告.md))
|
||||
|
||||
后端代码的详细分析,包含:
|
||||
- 项目概览和架构
|
||||
- 项目优点
|
||||
- 需要修复的问题
|
||||
- 性能优化建议
|
||||
|
||||
**适合人群**: 前端开发者(了解后端实现)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 环境要求
|
||||
|
||||
- Node.js >= 18.0.0
|
||||
- pnpm >= 8.0.0 (推荐) 或 npm >= 9.0.0
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
# 使用pnpm(推荐)
|
||||
pnpm install
|
||||
|
||||
# 或使用npm
|
||||
npm install
|
||||
```
|
||||
|
||||
### 启动开发服务器
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
访问 http://localhost:5173
|
||||
|
||||
### 构建生产版本
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### 运行测试
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 开发规范
|
||||
|
||||
### Git提交规范
|
||||
|
||||
遵循 Conventional Commits 规范:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
**类型(type)**:
|
||||
- `feat`: 新功能
|
||||
- `fix`: 修复bug
|
||||
- `docs`: 文档更新
|
||||
- `style`: 代码格式调整(不影响功能)
|
||||
- `refactor`: 重构
|
||||
- `perf`: 性能优化
|
||||
- `test`: 测试相关
|
||||
- `chore`: 构建/工具链相关
|
||||
|
||||
**示例**:
|
||||
```
|
||||
feat(user): 添加用户头像上传功能
|
||||
|
||||
- 实现头像选择和裁剪
|
||||
- 添加上传进度显示
|
||||
- 支持预览功能
|
||||
|
||||
Closes #123
|
||||
```
|
||||
|
||||
### 代码规范
|
||||
|
||||
- **TypeScript**: 所有代码使用TypeScript编写
|
||||
- **组件命名**: PascalCase (UserCard.vue)
|
||||
- **文件命名**: kebab-case (user-profile.ts)
|
||||
- **变量命名**: camelCase (getUserInfo)
|
||||
- **常量命名**: UPPER_SNAKE_CASE (API_BASE_URL)
|
||||
|
||||
### 样式规范
|
||||
|
||||
- **优先使用**: Tailwind CSS工具类
|
||||
- **组件样式**: 使用scoped样式
|
||||
- **全局样式**: 放在src/assets/styles
|
||||
- **CSS变量**: 统一使用CSS变量定义主题
|
||||
|
||||
---
|
||||
|
||||
## 🎨 设计原则
|
||||
|
||||
### 核心设计理念
|
||||
|
||||
**活力与专业并重**
|
||||
- 融合游戏化元素与现代UI设计
|
||||
- 保持管理工具的专业性和可靠性
|
||||
|
||||
**用户为中心**
|
||||
- 简洁直观的操作流程
|
||||
- 清晰的信息层级
|
||||
- 即时的反馈机制
|
||||
|
||||
**性能优先**
|
||||
- 快速加载
|
||||
- 流畅动画
|
||||
- 高效交互
|
||||
|
||||
### 设计关键词
|
||||
|
||||
- **活力**: 充满动感,富有生命力
|
||||
- **简洁**: 去除冗余,聚焦核心
|
||||
- **直观**: 一目了然,易于理解
|
||||
- **有趣**: 愉悦体验,富有惊喜
|
||||
|
||||
---
|
||||
|
||||
## 📊 项目特色
|
||||
|
||||
### 1. 游戏化设计
|
||||
|
||||
- **游戏主题色**: 不同游戏类型使用不同颜色标识
|
||||
- **徽章系统**: 会员、在线状态、荣誉展示
|
||||
- **进度条**: 预约进度、积分进度可视化
|
||||
- **动画效果**: 流畅的微交互增强体验
|
||||
|
||||
### 2. 响应式设计
|
||||
|
||||
- **移动优先**: 从最小屏幕开始设计
|
||||
- **断点系统**: 6个响应式断点
|
||||
- **自适应布局**: 灵活的网格系统
|
||||
- **触摸优化**: 移动端友好的交互
|
||||
|
||||
### 3. 性能优化
|
||||
|
||||
- **代码分割**: 路由级和组件级代码分割
|
||||
- **虚拟滚动**: 长列表性能优化
|
||||
- **图片优化**: WebP格式、懒加载
|
||||
- **缓存策略**: 接口缓存、组件缓存
|
||||
|
||||
### 4. 开发体验
|
||||
|
||||
- **TypeScript**: 完整的类型定义
|
||||
- **热重载**: 即时的开发反馈
|
||||
- **组件库**: 基于Element Plus扩展
|
||||
- **测试**: Vitest单元测试
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
### 内部文档
|
||||
|
||||
- [后端项目文档](../gameGroupBE/doc/README.md)
|
||||
- [后端API文档](../gameGroupBE/doc/api/API文档.md)
|
||||
- [Swagger在线文档](http://localhost:3000/docs) (开发环境)
|
||||
|
||||
### 外部资源
|
||||
|
||||
- [Vue 3官方文档](https://cn.vuejs.org/)
|
||||
- [Vite官方文档](https://cn.vitejs.dev/)
|
||||
- [Pinia官方文档](https://pinia.vuejs.org/zh/)
|
||||
- [Element Plus文档](https://element-plus.org/zh-CN/)
|
||||
- [Tailwind CSS文档](https://tailwindcss.com/docs)
|
||||
|
||||
---
|
||||
|
||||
## 📝 文档维护
|
||||
|
||||
### 更新规范
|
||||
|
||||
文档应随项目演进持续更新,更新时需:
|
||||
|
||||
1. **保持格式统一**: 遵循Markdown规范
|
||||
2. **更新时间戳**: 在文档末尾更新时间
|
||||
3. **记录变更**: 在相关文档中记录重大变更
|
||||
4. **同步更新**: API文档与代码保持同步
|
||||
|
||||
### 文档负责人
|
||||
|
||||
- **架构文档**: 技术负责人
|
||||
- **设计文档**: UI/UX设计师
|
||||
- **组件文档**: 前端开发者
|
||||
- **API文档**: 后端开发者
|
||||
|
||||
---
|
||||
|
||||
## 💬 反馈与建议
|
||||
|
||||
如有文档相关问题或建议,请:
|
||||
|
||||
1. 在项目中提Issue
|
||||
2. 联系项目维护者
|
||||
3. 参与文档改进
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**最后更新**: 2026-01-28
|
||||
**维护团队**: GameGroup Frontend Team
|
||||
|
||||
---
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目文档仅供内部使用,包含敏感信息,请勿泄露给外部人员。
|
||||
1857
doc/api/API文档.md
Normal file
1857
doc/api/API文档.md
Normal file
File diff suppressed because it is too large
Load Diff
685
doc/design/01-前端架构设计.md
Normal file
685
doc/design/01-前端架构设计.md
Normal file
@@ -0,0 +1,685 @@
|
||||
# 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
|
||||
867
doc/design/02-UI-UX设计规范.md
Normal file
867
doc/design/02-UI-UX设计规范.md
Normal file
@@ -0,0 +1,867 @@
|
||||
# GameGroup UI/UX 设计规范
|
||||
|
||||
**项目名称**: GameGroup 前端系统
|
||||
**文档版本**: v1.0
|
||||
**更新时间**: 2026-01-28
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [1. 设计理念](#1-设计理念)
|
||||
- [2. 视觉风格](#2-视觉风格)
|
||||
- [3. 色彩系统](#3-色彩系统)
|
||||
- [4. 字体系统](#4-字体系统)
|
||||
- [5. 间距系统](#5-间距系统)
|
||||
- [6. 组件规范](#6-组件规范)
|
||||
- [7. 动效规范](#7-动效规范)
|
||||
- [8. 响应式设计](#8-响应式设计)
|
||||
- [9. 无障碍设计](#9-无障碍设计)
|
||||
- [10. 设计资源](#10-设计资源)
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计理念
|
||||
|
||||
### 1.1 核心价值
|
||||
|
||||
**活力与专业并重**
|
||||
- GameGroup作为游戏社群平台,既要体现游戏的活力与趣味性,又要保持管理工具的专业性与可靠性
|
||||
- 设计风格融合游戏化元素与现代UI设计,创造独特的视觉语言
|
||||
|
||||
**用户为中心**
|
||||
- 简洁直观的操作流程
|
||||
- 清晰的信息层级
|
||||
- 即时的反馈机制
|
||||
- 一致的交互体验
|
||||
|
||||
**性能优先**
|
||||
- 快速加载
|
||||
- 流畅动画
|
||||
- 高效交互
|
||||
|
||||
### 1.2 设计关键词
|
||||
|
||||
- **活力**: 充满动感,富有生命力
|
||||
- **简洁**: 去除冗余,聚焦核心
|
||||
- **直观**: 一目了然,易于理解
|
||||
- **有趣**: 愉悦体验,富有惊喜
|
||||
|
||||
---
|
||||
|
||||
## 2. 视觉风格
|
||||
|
||||
### 2.1 风格定位
|
||||
|
||||
**游戏化现代风格**
|
||||
|
||||
融合以下设计元素:
|
||||
- **游戏UI影响**: 动态卡片、徽章系统、进度条、成就展示
|
||||
- **现代扁平化**: 清晰的视觉层次,适度的阴影和渐变
|
||||
- **微交互动画**: 悬停效果、过渡动画、状态反馈
|
||||
- **高对比度**: 确保可读性和视觉冲击力
|
||||
|
||||
### 2.2 设计原则
|
||||
|
||||
#### 层次分明
|
||||
- 使用卡片容器分割内容
|
||||
- 利用阴影和z轴创建深度
|
||||
- 明确的视觉层级引导
|
||||
|
||||
#### 留白充足
|
||||
- 组件之间保持合理间距
|
||||
- 避免信息过载
|
||||
- 提升阅读舒适度
|
||||
|
||||
#### 一致性
|
||||
- 统一的视觉语言
|
||||
- 可预测的交互模式
|
||||
- 规范的设计系统
|
||||
|
||||
---
|
||||
|
||||
## 3. 色彩系统
|
||||
|
||||
### 3.1 主色调 (Primary Colors)
|
||||
|
||||
```css
|
||||
/* 主色 - 游戏紫 */
|
||||
--color-primary-50: #f5f3ff;
|
||||
--color-primary-100: #ede9fe;
|
||||
--color-primary-200: #ddd6fe;
|
||||
--color-primary-300: #c4b5fd;
|
||||
--color-primary-400: #a78bfa;
|
||||
--color-primary-500: #8b5cf6; /* 主色 */
|
||||
--color-primary-600: #7c3aed;
|
||||
--color-primary-700: #6d28d9;
|
||||
--color-primary-800: #5b21b6;
|
||||
--color-primary-900: #4c1d95;
|
||||
|
||||
/* 强调色 - 活力橙 */
|
||||
--color-accent-50: #fff7ed;
|
||||
--color-accent-100: #ffedd5;
|
||||
--color-accent-200: #fed7aa;
|
||||
--color-accent-300: #fdba74;
|
||||
--color-accent-400: #fb923c;
|
||||
--color-accent-500: #f97316; /* 强调色 */
|
||||
--color-accent-600: #ea580c;
|
||||
--color-accent-700: #c2410c;
|
||||
--color-accent-800: #9a3412;
|
||||
--color-accent-900: #7c2d12;
|
||||
```
|
||||
|
||||
### 3.2 中性色 (Neutral Colors)
|
||||
|
||||
```css
|
||||
/* 深色模式 */
|
||||
--color-gray-50: #f9fafb;
|
||||
--color-gray-100: #f3f4f6;
|
||||
--color-gray-200: #e5e7eb;
|
||||
--color-gray-300: #d1d5db;
|
||||
--color-gray-400: #9ca3af;
|
||||
--color-gray-500: #6b7280;
|
||||
--color-gray-600: #4b5563;
|
||||
--color-gray-700: #374151;
|
||||
--color-gray-800: #1f2937;
|
||||
--color-gray-900: #111827;
|
||||
|
||||
/* 浅色模式 */
|
||||
--color-text-primary: #1f2937;
|
||||
--color-text-secondary: #6b7280;
|
||||
--color-text-tertiary: #9ca3af;
|
||||
--color-bg-primary: #ffffff;
|
||||
--color-bg-secondary: #f9fafb;
|
||||
--color-bg-tertiary: #f3f4f6;
|
||||
--color-border: #e5e7eb;
|
||||
```
|
||||
|
||||
### 3.3 功能色 (Semantic Colors)
|
||||
|
||||
```css
|
||||
/* 成功 - 绿色 */
|
||||
--color-success-50: #f0fdf4;
|
||||
--color-success-100: #dcfce7;
|
||||
--color-success-500: #22c55e;
|
||||
--color-success-700: #15803d;
|
||||
|
||||
/* 警告 - 黄色 */
|
||||
--color-warning-50: #fffbeb;
|
||||
--color-warning-100: #fef3c7;
|
||||
--color-warning-500: #eab308;
|
||||
--color-warning-700: #a16207;
|
||||
|
||||
/* 错误 - 红色 */
|
||||
--color-error-50: #fef2f2;
|
||||
--color-error-100: #fee2e2;
|
||||
--color-error-500: #ef4444;
|
||||
--color-error-700: #b91c1c;
|
||||
|
||||
/* 信息 - 蓝色 */
|
||||
--color-info-50: #eff6ff;
|
||||
--color-info-100: #dbeafe;
|
||||
--color-info-500: #3b82f6;
|
||||
--color-info-700: #1d4ed8;
|
||||
```
|
||||
|
||||
### 3.4 游戏主题色
|
||||
|
||||
用于游戏相关的特殊标识和游戏化元素:
|
||||
|
||||
```css
|
||||
/* 游戏类型颜色 */
|
||||
--game-moba: #8b5cf6; /* MOBA - 紫色 */
|
||||
--game-fps: #ef4444; /* FPS - 红色 */
|
||||
--game-rpg: #22c55e; /* RPG - 绿色 */
|
||||
--game-strategy: #3b82f6; /* 策略 - 蓝色 */
|
||||
--game-racing: #f97316; /* 竞速 - 橙色 */
|
||||
--game-sports: #eab308; /* 体育 - 黄色 */
|
||||
--game-card: #ec4899; /* 卡牌 - 粉色 */
|
||||
--game-puzzle: #06b6d4; /* 益智 - 青色 */
|
||||
```
|
||||
|
||||
### 3.5 使用规范
|
||||
|
||||
#### 色彩搭配原则
|
||||
- **主色占比**: 60% - 用于主要操作、品牌标识
|
||||
- **中性色占比**: 30% - 用于背景、文本
|
||||
- **强调色占比**: 10% - 用于重点突出、引导注意
|
||||
|
||||
#### 对比度要求
|
||||
- 文本与背景对比度 ≥ 4.5:1 (WCAG AA标准)
|
||||
- 重要元素对比度 ≥ 7:1 (WCAG AAA标准)
|
||||
|
||||
---
|
||||
|
||||
## 4. 字体系统
|
||||
|
||||
### 4.1 字体家族
|
||||
|
||||
```css
|
||||
/* 主字体 - 思源黑体 (中文) + Inter (英文/数字) */
|
||||
--font-family-base: "Source Han Sans CN", "Inter", -apple-system,
|
||||
BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
||||
"Noto Sans", sans-serif;
|
||||
|
||||
/* 代码字体 */
|
||||
--font-family-mono: "JetBrains Mono", "Fira Code", "Courier New",
|
||||
monospace;
|
||||
|
||||
/* 数字字体 - 用于数据显示 */
|
||||
--font-family-number: "Inter", "Roboto Mono", monospace;
|
||||
```
|
||||
|
||||
### 4.2 字体大小
|
||||
|
||||
```css
|
||||
/* 标题 */
|
||||
--font-size-h1: 2.5rem; /* 40px */
|
||||
--font-size-h2: 2rem; /* 32px */
|
||||
--font-size-h3: 1.5rem; /* 24px */
|
||||
--font-size-h4: 1.25rem; /* 20px */
|
||||
--font-size-h5: 1.125rem; /* 18px */
|
||||
--font-size-h6: 1rem; /* 16px */
|
||||
|
||||
/* 正文 */
|
||||
--font-size-large: 1rem; /* 16px */
|
||||
--font-size-base: 0.875rem; /* 14px */
|
||||
--font-size-small: 0.75rem; /* 12px */
|
||||
--font-size-xs: 0.625rem; /* 10px */
|
||||
```
|
||||
|
||||
### 4.3 字重
|
||||
|
||||
```css
|
||||
--font-weight-light: 300;
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-semibold: 600;
|
||||
--font-weight-bold: 700;
|
||||
```
|
||||
|
||||
### 4.4 行高
|
||||
|
||||
```css
|
||||
--line-height-tight: 1.25;
|
||||
--line-height-normal: 1.5;
|
||||
--line-height-relaxed: 1.75;
|
||||
```
|
||||
|
||||
### 4.5 使用规范
|
||||
|
||||
| 元素 | 字体大小 | 字重 | 行高 |
|
||||
|------|---------|------|------|
|
||||
| 页面标题 | H1 (40px) | Bold (700) | 1.25 |
|
||||
| 区块标题 | H2 (32px) | Semibold (600) | 1.25 |
|
||||
| 卡片标题 | H4 (20px) | Semibold (600) | 1.5 |
|
||||
| 正文内容 | Base (14px) | Normal (400) | 1.5 |
|
||||
| 辅助文字 | Small (12px) | Normal (400) | 1.5 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 间距系统
|
||||
|
||||
### 5.1 间距尺度
|
||||
|
||||
采用4px基准的间距系统:
|
||||
|
||||
```css
|
||||
--spacing-0: 0;
|
||||
--spacing-1: 0.25rem; /* 4px */
|
||||
--spacing-2: 0.5rem; /* 8px */
|
||||
--spacing-3: 0.75rem; /* 12px */
|
||||
--spacing-4: 1rem; /* 16px */
|
||||
--spacing-5: 1.25rem; /* 20px */
|
||||
--spacing-6: 1.5rem; /* 24px */
|
||||
--spacing-8: 2rem; /* 32px */
|
||||
--spacing-10: 2.5rem; /* 40px */
|
||||
--spacing-12: 3rem; /* 48px */
|
||||
--spacing-16: 4rem; /* 64px */
|
||||
--spacing-20: 5rem; /* 80px */
|
||||
```
|
||||
|
||||
### 5.2 使用场景
|
||||
|
||||
| 场景 | 间距值 | 用途 |
|
||||
|------|--------|------|
|
||||
| 组件内边距 | spacing-4 (16px) | 按钮内边距、卡片内边距 |
|
||||
| 组件间距 | spacing-6 (24px) | 卡片之间的间距 |
|
||||
| 区块间距 | spacing-8 (32px) | 页面区块之间的间距 |
|
||||
| 页面边距 | spacing-6 (24px) | 内容与页面边缘的间距 |
|
||||
| 紧凑间距 | spacing-2 (8px) | 标签、徽章等小元素 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 组件规范
|
||||
|
||||
### 6.1 按钮 (Button)
|
||||
|
||||
#### 主要按钮 (Primary)
|
||||
```css
|
||||
/* 样式 */
|
||||
background: var(--color-primary-500);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
padding: 10px 20px;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
|
||||
/* 悬停 */
|
||||
background: var(--color-primary-600);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
||||
|
||||
/* 点击 */
|
||||
transform: translateY(0);
|
||||
```
|
||||
|
||||
#### 次要按钮 (Secondary)
|
||||
```css
|
||||
background: transparent;
|
||||
color: var(--color-primary-500);
|
||||
border: 2px solid var(--color-primary-500);
|
||||
border-radius: 8px;
|
||||
padding: 10px 20px;
|
||||
font-weight: 600;
|
||||
```
|
||||
|
||||
#### 文字按钮 (Text)
|
||||
```css
|
||||
background: transparent;
|
||||
color: var(--color-primary-500);
|
||||
padding: 8px 12px;
|
||||
font-weight: 500;
|
||||
|
||||
/* 悬停 */
|
||||
background: var(--color-primary-50);
|
||||
```
|
||||
|
||||
#### 尺寸规范
|
||||
- **Large**: 48px高度, 16px字体
|
||||
- **Medium**: 40px高度, 14px字体 (默认)
|
||||
- **Small**: 32px高度, 12px字体
|
||||
|
||||
### 6.2 卡片 (Card)
|
||||
|
||||
```css
|
||||
/* 基础卡片 */
|
||||
background: var(--color-bg-primary);
|
||||
border-radius: 12px;
|
||||
padding: var(--spacing-6);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s;
|
||||
|
||||
/* 悬停效果 */
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
```
|
||||
|
||||
#### 卡片类型
|
||||
- **基础卡片**: 标准卡片样式
|
||||
- **可点击卡片**: 带悬停效果
|
||||
- **游戏卡片**: 带封面图和标签
|
||||
|
||||
### 6.3 输入框 (Input)
|
||||
|
||||
```css
|
||||
/* 样式 */
|
||||
border: 2px solid var(--color-border);
|
||||
border-radius: 8px;
|
||||
padding: 10px 14px;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s;
|
||||
|
||||
/* 聚焦状态 */
|
||||
border-color: var(--color-primary-500);
|
||||
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);
|
||||
outline: none;
|
||||
|
||||
/* 错误状态 */
|
||||
border-color: var(--color-error-500);
|
||||
```
|
||||
|
||||
### 6.4 徽章 (Badge)
|
||||
|
||||
```css
|
||||
/* 基础样式 */
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
border-radius: 9999px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
|
||||
/* 类型 */
|
||||
.badge-primary { background: var(--color-primary-100); color: var(--color-primary-700); }
|
||||
.badge-success { background: var(--color-success-100); color: var(--color-success-700); }
|
||||
.badge-warning { background: var(--color-warning-100); color: var(--color-warning-700); }
|
||||
.badge-error { background: var(--color-error-100); color: var(--color-error-700); }
|
||||
```
|
||||
|
||||
### 6.5 头像 (Avatar)
|
||||
|
||||
```css
|
||||
/* 尺寸 */
|
||||
.avatar-xs { width: 24px; height: 24px; }
|
||||
.avatar-sm { width: 32px; height: 32px; }
|
||||
.avatar-md { width: 40px; height: 40px; }
|
||||
.avatar-lg { width: 56px; height: 56px; }
|
||||
.avatar-xl { width: 80px; height: 80px; }
|
||||
|
||||
/* 样式 */
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 2px solid var(--color-border);
|
||||
```
|
||||
|
||||
### 6.6 进度条 (Progress)
|
||||
|
||||
```css
|
||||
/* 容器 */
|
||||
height: 8px;
|
||||
background: var(--color-bg-tertiary);
|
||||
border-radius: 9999px;
|
||||
overflow: hidden;
|
||||
|
||||
/* 进度 */
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--color-primary-400), var(--color-primary-600));
|
||||
border-radius: 9999px;
|
||||
transition: width 0.3s;
|
||||
```
|
||||
|
||||
### 6.7 标签 (Tag)
|
||||
|
||||
用于游戏标签、技能标签等:
|
||||
|
||||
```css
|
||||
/* 样式 */
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
background: var(--color-bg-tertiary);
|
||||
color: var(--color-text-secondary);
|
||||
gap: 4px;
|
||||
|
||||
/* 游戏类型标签 - 不同颜色 */
|
||||
.tag-moba { background: var(--game-moba); color: white; }
|
||||
.tag-fps { background: var(--game-fps); color: white; }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 动效规范
|
||||
|
||||
### 7.1 动画时长
|
||||
|
||||
```css
|
||||
--duration-fast: 150ms;
|
||||
--duration-base: 200ms;
|
||||
--duration-slow: 300ms;
|
||||
--duration-slower: 500ms;
|
||||
```
|
||||
|
||||
### 7.2 缓动函数
|
||||
|
||||
```css
|
||||
/* 标准 */
|
||||
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
/* 进入 */
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
|
||||
/* 离开 */
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
|
||||
/* 弹性 */
|
||||
--ease-elastic: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
```
|
||||
|
||||
### 7.3 常用动效
|
||||
|
||||
#### 淡入淡出 (Fade)
|
||||
```css
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
```
|
||||
|
||||
#### 滑动 (Slide)
|
||||
```css
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 缩放 (Scale)
|
||||
```css
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 骨架屏加载 (Skeleton)
|
||||
```css
|
||||
@keyframes skeleton-loading {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
.skeleton {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--color-bg-tertiary) 25%,
|
||||
var(--color-bg-secondary) 50%,
|
||||
var(--color-bg-tertiary) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: skeleton-loading 1.5s infinite;
|
||||
}
|
||||
```
|
||||
|
||||
### 7.4 微交互
|
||||
|
||||
#### 按钮点击
|
||||
```css
|
||||
button:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
```
|
||||
|
||||
#### 卡片悬停
|
||||
```css
|
||||
.card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
```
|
||||
|
||||
#### 链接下划线动画
|
||||
```css
|
||||
.link {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.link::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background: var(--color-primary-500);
|
||||
transition: width var(--duration-base);
|
||||
}
|
||||
|
||||
.link:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 响应式设计
|
||||
|
||||
### 8.1 断点系统
|
||||
|
||||
```css
|
||||
/* 断点 */
|
||||
--breakpoint-xs: 0px; /* 手机竖屏 */
|
||||
--breakpoint-sm: 640px; /* 手机横屏 */
|
||||
--breakpoint-md: 768px; /* 平板竖屏 */
|
||||
--breakpoint-lg: 1024px; /* 平板横屏 / 小笔记本 */
|
||||
--breakpoint-xl: 1280px; /* 桌面 */
|
||||
--breakpoint-2xl: 1536px; /* 大屏幕 */
|
||||
```
|
||||
|
||||
### 8.2 响应式策略
|
||||
|
||||
#### 移动优先
|
||||
从最小屏幕开始设计,逐步增强:
|
||||
|
||||
```css
|
||||
/* 移动端 (默认) */
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 平板及以上 */
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 桌面 */
|
||||
@media (min-width: 1024px) {
|
||||
.container {
|
||||
padding: 32px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 隐藏元素
|
||||
```css
|
||||
/* 移动端隐藏 */
|
||||
.hidden-mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.hidden-mobile {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* 桌面端隐藏 */
|
||||
.hidden-desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.hidden-desktop {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 布局适配
|
||||
|
||||
#### 导航栏
|
||||
- **移动端**: 底部导航栏或汉堡菜单
|
||||
- **平板**: 侧边栏
|
||||
- **桌面**: 顶部导航 + 侧边栏
|
||||
|
||||
#### 网格系统
|
||||
```css
|
||||
/* 移动: 1列 */
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* 平板: 2列 */
|
||||
@media (min-width: 768px) {
|
||||
.grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
/* 桌面: 3-4列 */
|
||||
@media (min-width: 1024px) {
|
||||
.grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 无障碍设计
|
||||
|
||||
### 9.1 键盘导航
|
||||
|
||||
- **Tab顺序**: 逻辑清晰的焦点顺序
|
||||
- **焦点可见**: 明确的焦点样式
|
||||
- **快捷键**: 支持常用操作快捷键
|
||||
|
||||
```css
|
||||
/* 焦点样式 */
|
||||
*:focus-visible {
|
||||
outline: 2px solid var(--color-primary-500);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 屏幕阅读器
|
||||
|
||||
```html
|
||||
<!-- 语义化HTML -->
|
||||
<button aria-label="关闭对话框">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
||||
<!-- 图标 + 文字 -->
|
||||
<button>
|
||||
<svg aria-hidden="true">...</svg>
|
||||
<span>保存</span>
|
||||
</button>
|
||||
```
|
||||
|
||||
### 9.3 色盲友好
|
||||
|
||||
不仅依赖颜色传达信息:
|
||||
- 使用图标 + 颜色
|
||||
- 添加文字说明
|
||||
- 提供高对比度模式
|
||||
|
||||
---
|
||||
|
||||
## 10. 设计资源
|
||||
|
||||
### 10.1 设计工具
|
||||
|
||||
- **Figma**: 主要设计工具
|
||||
- **Iconify**: 图标库
|
||||
- **Coolors**: 配色方案生成
|
||||
- **Type Scale**: 字体比例计算
|
||||
|
||||
### 10.2 图标系统
|
||||
|
||||
推荐使用以下图标库:
|
||||
- **Heroicons**: 简洁现代
|
||||
- **Lucide Icons**: 统一风格
|
||||
- **Phosphor Icons**: 丰富选择
|
||||
|
||||
图标尺寸:
|
||||
- **XS**: 16px
|
||||
- **SM**: 20px
|
||||
- **MD**: 24px (默认)
|
||||
- **LG**: 32px
|
||||
- **XL**: 48px
|
||||
|
||||
### 10.3 图片规范
|
||||
|
||||
#### 头像
|
||||
- **尺寸**: 200x200px最小
|
||||
- **格式**: JPG/WebP
|
||||
- **质量**: 80%以上
|
||||
|
||||
#### 游戏封面
|
||||
- **尺寸**: 16:9比例
|
||||
- **最小宽度**: 640px
|
||||
- **格式**: WebP优先
|
||||
|
||||
#### 截图
|
||||
- **尺寸**: 原始分辨率
|
||||
- **格式**: WebP/PNG
|
||||
- **压缩**: 无损或有损80%
|
||||
|
||||
---
|
||||
|
||||
## 11. 组件示例
|
||||
|
||||
### 11.1 用户卡片
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="user-card">
|
||||
<div class="user-card__avatar">
|
||||
<img :src="user.avatar" :alt="user.username" />
|
||||
</div>
|
||||
<div class="user-card__info">
|
||||
<h4 class="user-card__name">{{ user.nickname || user.username }}</h4>
|
||||
<p class="user-card__role">{{ roleText }}</p>
|
||||
<div class="user-card__badges">
|
||||
<Badge v-if="user.isMember" type="primary">会员</Badge>
|
||||
<Badge v-if="isOnline" type="success">在线</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.user-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.user-card__avatar img {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.user-card__name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.user-card__role {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-secondary);
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 11.2 游戏卡片
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="game-card" @click="handleClick">
|
||||
<div class="game-card__cover">
|
||||
<img :src="game.coverUrl" :alt="game.name" />
|
||||
<div class="game-card__overlay">
|
||||
<Button type="primary" size="small">查看详情</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="game-card__content">
|
||||
<div class="game-card__tags">
|
||||
<Tag
|
||||
v-for="tag in game.tags"
|
||||
:key="tag"
|
||||
:type="getGameTagType(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</Tag>
|
||||
</div>
|
||||
<h4 class="game-card__title">{{ game.name }}</h4>
|
||||
<p class="game-card__players">
|
||||
{{ game.minPlayers }}-{{ game.maxPlayers }}人
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 总结
|
||||
|
||||
本设计规范确保:
|
||||
- ✅ **视觉一致性**: 统一的设计语言
|
||||
- ✅ **开发效率**: 规范化的组件库
|
||||
- ✅ **用户体验**: 直观友好的交互
|
||||
- ✅ **品牌识别**: 独特的视觉风格
|
||||
- ✅ **可维护性**: 系统化的设计系统
|
||||
|
||||
---
|
||||
|
||||
**文档维护**: 随产品迭代持续更新
|
||||
**最后更新**: 2026-01-28
|
||||
**设计负责**: Frontend Team
|
||||
1099
doc/design/03-组件设计文档.md
Normal file
1099
doc/design/03-组件设计文档.md
Normal file
File diff suppressed because it is too large
Load Diff
826
doc/design/04-页面设计文档.md
Normal file
826
doc/design/04-页面设计文档.md
Normal file
@@ -0,0 +1,826 @@
|
||||
# GameGroup 页面设计文档
|
||||
|
||||
**项目名称**: GameGroup 前端系统
|
||||
**文档版本**: v1.0
|
||||
**更新时间**: 2026-01-28
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [1. 页面架构](#1-页面架构)
|
||||
- [2. 认证页面](#2-认证页面)
|
||||
- [3. 首页](#3-首页)
|
||||
- [4. 用户中心](#4-用户中心)
|
||||
- [5. 小组管理](#5-小组管理)
|
||||
- [6. 游戏库](#6-游戏库)
|
||||
- [7. 预约管理](#7-预约管理)
|
||||
- [8. 积分排行](#8-积分排行)
|
||||
- [9. 荣誉墙](#9-荣誉墙)
|
||||
|
||||
---
|
||||
|
||||
## 1. 页面架构
|
||||
|
||||
### 1.1 页面层级
|
||||
|
||||
```
|
||||
页面层级
|
||||
├── 公共页面 (Public)
|
||||
│ ├── 登录页 (/login)
|
||||
│ ├── 注册页 (/register)
|
||||
│ └── 找回密码 (/forgot-password)
|
||||
│
|
||||
├── 主应用页面 (App)
|
||||
│ ├── 首页 (/)
|
||||
│ ├── 用户中心 (/user)
|
||||
│ │ ├── 个人资料 (/user/profile)
|
||||
│ │ └── 设置 (/user/settings)
|
||||
│ ├── 小组管理 (/groups)
|
||||
│ │ ├── 小组列表 (/groups)
|
||||
│ │ ├── 小组详情 (/groups/:id)
|
||||
│ │ └── 创建小组 (/groups/create)
|
||||
│ ├── 游戏库 (/games)
|
||||
│ │ ├── 游戏列表 (/games)
|
||||
│ │ └── 游戏详情 (/games/:id)
|
||||
│ ├── 预约管理 (/appointments)
|
||||
│ │ ├── 预约列表 (/appointments)
|
||||
│ │ └── 预约详情 (/appointments/:id)
|
||||
│ ├── 积分系统 (/points)
|
||||
│ │ ├── 我的积分 (/points/me)
|
||||
│ │ └── 排行榜 (/points/ranking)
|
||||
│ └── 荣誉墙 (/honors)
|
||||
│
|
||||
└── 管理页面 (Admin)
|
||||
├── 黑名单管理 (/admin/blacklist)
|
||||
└── 系统设置 (/admin/settings)
|
||||
```
|
||||
|
||||
### 1.2 布局模式
|
||||
|
||||
#### 主布局 (MainLayout)
|
||||
适用于大部分应用页面,包含:
|
||||
- 顶部导航栏
|
||||
- 侧边栏菜单
|
||||
- 主内容区域
|
||||
- 底部信息栏
|
||||
|
||||
#### 认证布局 (AuthLayout)
|
||||
适用于登录、注册页面:
|
||||
- 居中的表单卡片
|
||||
- 简洁的背景
|
||||
- 无导航栏
|
||||
|
||||
#### 空白布局 (EmptyLayout)
|
||||
适用于特殊页面:
|
||||
- 无导航
|
||||
- 无侧边栏
|
||||
- 全屏内容
|
||||
|
||||
---
|
||||
|
||||
## 2. 认证页面
|
||||
|
||||
### 2.1 登录页 (/login)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [Logo + GameGroup] │
|
||||
│ │
|
||||
│ ┌───────────────────┐ │
|
||||
│ │ │ │
|
||||
│ │ 登录表单 │ │
|
||||
│ │ │ │
|
||||
│ │ [账号] │ │
|
||||
│ │ [密码] │ │
|
||||
│ │ [登录按钮] │ │
|
||||
│ │ │ │
|
||||
│ │ 忘记密码? │ │
|
||||
│ │ 还没有账号?注册 │ │
|
||||
│ │ │ │
|
||||
│ └───────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 设计要点
|
||||
|
||||
- **视觉焦点**: 居中的表单卡片,阴影突出
|
||||
- **背景**: 使用渐变色或游戏主题图片
|
||||
- **动画**: 表单淡入动画
|
||||
- **交互**: 输入框焦点动画,按钮悬停效果
|
||||
|
||||
#### 表单字段
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 账号 | text | 是 | 用户名/邮箱/手机号 |
|
||||
| 密码 | password | 是 | 密码,支持显示切换 |
|
||||
| 记住我 | checkbox | 否 | 记住登录状态 |
|
||||
|
||||
#### 交互流程
|
||||
|
||||
1. 用户输入账号密码
|
||||
2. 点击登录或按Enter键
|
||||
3. 显示加载状态
|
||||
4. 登录成功 → 跳转到首页
|
||||
5. 登录失败 → 显示错误提示
|
||||
|
||||
---
|
||||
|
||||
### 2.2 注册页 (/register)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
与登录页类似,但表单字段更多。
|
||||
|
||||
#### 表单字段
|
||||
|
||||
| 字段 | 类型 | 必填 | 验证规则 |
|
||||
|------|------|------|----------|
|
||||
| 用户名 | text | 是 | 3-20字符,字母数字下划线 |
|
||||
| 邮箱 | email | 否 | 有效邮箱格式 |
|
||||
| 手机号 | tel | 否 | 11位手机号 |
|
||||
| 密码 | password | 是 | 6-20字符 |
|
||||
| 确认密码 | password | 是 | 与密码一致 |
|
||||
|
||||
#### 验证逻辑
|
||||
|
||||
- 实时验证: 失焦时验证单个字段
|
||||
- 提交验证: 提交时验证所有字段
|
||||
- 异步验证: 用户名唯一性检查
|
||||
|
||||
---
|
||||
|
||||
## 3. 首页
|
||||
|
||||
### 3.1 首页布局 (/)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [Logo] [导航菜单] [搜索] [用户] │
|
||||
├──────┬──────────────────────────────────────┤
|
||||
│ │ ┌────────────────────────────────┐ │
|
||||
│ │ │ 欢迎,XXX │ │
|
||||
│ 侧 │ │ 今日有3个预约待参加 │ │
|
||||
│ 边 │ └────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ 栏 │ ┌──────────┐ ┌──────────────────┐ │
|
||||
│ │ │我的小组 │ │ 即将开始的活动 │ │
|
||||
│ │ │ (5) │ │ • 王者荣耀今晚...│ │
|
||||
│ │ │ │ │ • 周末桌游局 │ │
|
||||
│ │ │[查看全部]│ │ • FPS竞技训练 │ │
|
||||
│ │ └──────────┘ └──────────────────┘ │
|
||||
│ │ │
|
||||
│ │ ┌────────────────────────────────┐ │
|
||||
│ │ │ 热门游戏 │ │
|
||||
│ │ │ [游戏卡片1][游戏卡片2]... │ │
|
||||
│ │ └────────────────────────────────┘ │
|
||||
│ │ │
|
||||
└──────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 首页内容区块
|
||||
|
||||
#### 欢迎卡片
|
||||
- 显示用户名
|
||||
- 显示今日待参加的预约数量
|
||||
- 快速跳转按钮
|
||||
|
||||
#### 我的小组
|
||||
- 显示小组数量
|
||||
- 显示3个最近活跃的小组卡片
|
||||
- "查看全部"链接
|
||||
|
||||
#### 即将开始的活动
|
||||
- 时间倒计时
|
||||
- 活动卡片列表
|
||||
- 快速加入按钮
|
||||
|
||||
#### 热门游戏
|
||||
- 横向滚动或网格布局
|
||||
- 游戏卡片展示
|
||||
- 点击跳转游戏详情
|
||||
|
||||
---
|
||||
|
||||
## 4. 用户中心
|
||||
|
||||
### 4.1 个人资料 (/user/profile)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [返回] 个人资料 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ [头像上传] │ │
|
||||
│ │ │ │
|
||||
│ │ 用户名: john_doe │ │
|
||||
│ │ 昵称: [编辑] │ │
|
||||
│ │ 邮箱: jo***@example.com │ │
|
||||
│ │ 手机: 138****8000 │ │
|
||||
│ │ │ │
|
||||
│ │ 会员状态: 是 [到期时间: 2026-12-31] │ │
|
||||
│ │ 注册时间: 2025-01-01 │ │
|
||||
│ │ 最后登录: 2026-01-28 10:00 │ │
|
||||
│ │ │ │
|
||||
│ │ [编辑资料] [修改密码] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 我的小组 (5) │ │
|
||||
│ │ [小组卡片列表] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 我的积分 │ │
|
||||
│ │ [小组选择] 当前积分: 1,250 │ │
|
||||
│ │ [积分历史] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 功能模块
|
||||
|
||||
1. **基本信息展示**
|
||||
- 头像、用户名、昵称
|
||||
- 邮箱、手机号(脱敏)
|
||||
- 会员状态、注册时间、最后登录
|
||||
|
||||
2. **编辑资料**
|
||||
- 弹窗表单
|
||||
- 头像上传
|
||||
- 昵称修改
|
||||
- 邮箱/手机号修改
|
||||
|
||||
3. **我的小组**
|
||||
- 卡片列表展示
|
||||
- 显示小组角色
|
||||
- 快速跳转
|
||||
|
||||
4. **我的积分**
|
||||
- 下拉选择小组
|
||||
- 显示当前积分
|
||||
- 积分历史入口
|
||||
|
||||
---
|
||||
|
||||
### 4.2 设置 (/user/settings)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [返回] 设置 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 通知设置 │ │
|
||||
│ │ [ ] 预约提醒 │ │
|
||||
│ │ [ ] 活动开始提醒 (提前15分钟) │ │
|
||||
│ │ [ ] 小组通知 │ │
|
||||
│ │ [ ] 积分变动通知 │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 隐私设置 │ │
|
||||
│ │ [ ] 显示在线状态 │ │
|
||||
│ │ [ ] 允许陌生人查看我的小组 │ │
|
||||
│ │ [ ] 允许陌生人查看我的积分 │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 外观设置 │ │
|
||||
│ │ 主题: [●]浅色 [ ]深色 [ ]跟随系统 │ │
|
||||
│ │ 语言: [简体中文 ▼] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 账号安全 │ │
|
||||
│ │ [修改密码] │ │
|
||||
│ │ [绑定手机] │ │
|
||||
│ │ [绑定邮箱] │ │
|
||||
│ │ [退出登录] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 小组管理
|
||||
|
||||
### 5.1 小组列表 (/groups)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 小组管理 [+ 创建小组] [搜索框] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [全部] [我创建的] [我加入的] │
|
||||
│ │
|
||||
│ ┌────────┐ ┌────────┐ ┌────────┐ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │小组卡片│ │小组卡片│ │小组卡片│ ... │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ └────────┘ └────────┘ └────────┘ │
|
||||
│ │
|
||||
│ ┌────────┐ ┌────────┐ ┌────────┐ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │小组卡片│ │小组卡片│ │小组卡片│ ... │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ └────────┘ └────────┘ └────────┘ │
|
||||
│ │
|
||||
│ [加载更多] 或 [分页器] │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 功能特性
|
||||
|
||||
- **筛选标签**: 全部/我创建的/我加入的
|
||||
- **搜索**: 支持按小组名称搜索
|
||||
- **排序**: 最新创建/成员最多/最活跃
|
||||
- **卡片展示**: 头像、名称、成员数、角色
|
||||
- **加载更多**: 无限滚动或分页
|
||||
|
||||
---
|
||||
|
||||
### 5.2 小组详情 (/groups/:id)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [←] 王者荣耀固定队 [编辑] [更多] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ [小组头像] 王者荣耀固定队 │ │
|
||||
│ │ 每晚8点开黑,欢迎加入 │ │
|
||||
│ │ 成员: 25/50 │ │
|
||||
│ │ [公告]本周六团建活动! │ │
|
||||
│ │ │ │
|
||||
│ │ [预约列表] [成员列表] [荣誉墙] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 即将开始的预约 │ │
|
||||
│ │ ┌─────────────────────────────────┐ │ │
|
||||
│ │ │ [游戏] 今晚开黑 │ │ │
|
||||
│ │ │ 今天 20:00-23:00 │ │ │
|
||||
│ │ │ 参与: 4/5 [加入] │ │ │
|
||||
│ │ └─────────────────────────────────┘ │ │
|
||||
│ │ ┌─────────────────────────────────┐ │ │
|
||||
│ │ │ [游戏] 周末排位赛 │ │ │
|
||||
│ │ │ 周六 14:00-18:00 │ │ │
|
||||
│ │ │ 参与: 8/10 [加入] │ │ │
|
||||
│ │ └─────────────────────────────────┘ │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 小组成员 (25) [管理成员] │ │
|
||||
│ │ [头像列表] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 小组积分排行 │ │
|
||||
│ │ 1. 用户A - 2,500积分 │ │
|
||||
│ │ 2. 用户B - 2,100积分 │ │
|
||||
│ │ 3. 用户C - 1,800积分 │ │
|
||||
│ │ ... │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [+ 创建预约] [查看全部预约] │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 功能模块
|
||||
|
||||
1. **小组基本信息**
|
||||
- 头像、名称、描述
|
||||
- 成员数/最大成员数
|
||||
- 公告
|
||||
- 角色(组长/管理员/成员)
|
||||
|
||||
2. **Tab切换**
|
||||
- 预约列表
|
||||
- 成员列表
|
||||
- 荣誉墙
|
||||
- 账目记录
|
||||
- 资产管理
|
||||
|
||||
3. **即将开始的预约**
|
||||
- 时间倒计时
|
||||
- 参与人数
|
||||
- 快速加入按钮
|
||||
|
||||
4. **小组成员**
|
||||
- 头像列表(前12个)
|
||||
- 在线状态
|
||||
- "管理成员"(管理员可见)
|
||||
|
||||
5. **积分排行**
|
||||
- Top10列表
|
||||
- 显示排名变化
|
||||
|
||||
---
|
||||
|
||||
### 5.3 创建小组 (/groups/create)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [←] 创建小组 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 小组名称 │ │
|
||||
│ │ [_________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ 小组描述 │ │
|
||||
│ │ [_________________________________] │ │
|
||||
│ │ [_________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ 小组头像 │ │
|
||||
│ │ [上传图片] │ │
|
||||
│ │ │ │
|
||||
│ │ 小组类型 │ │
|
||||
│ │ [●]普通小组 [ ]公会 │ │
|
||||
│ │ │ │
|
||||
│ │ 最大成员数 │ │
|
||||
│ │ [50▼] (会员可创建公会,上限500人) │ │
|
||||
│ │ │ │
|
||||
│ │ [取消] [创建小组] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 游戏库
|
||||
|
||||
### 6.1 游戏列表 (/games)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 游戏库 [搜索框] [筛选] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [标签筛选] MOBA(5) FPS(3) RPG(2) ... │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ [封面图] │ │ [封面图] │ │ [封面图] │ │
|
||||
│ │ 王者荣耀 │ │ 和平精英 │ │ 英雄联盟 │ │
|
||||
│ │ 5v5 MOBA│ │ 吃鸡FPS │ │ 5v5 MOBA │ │
|
||||
│ │ 10人 │ │ 100人 │ │ 10人 │ │
|
||||
│ │ iOS/And │ │ iOS/And │ │ PC │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ [封面图] │ │ [封面图] │ │ [封面图] │ │
|
||||
│ │ 游戏名称 │ │ 游戏名称 │ │ 游戏名称 │ ... │
|
||||
│ │ ... │ │ ... │ │ ... │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 功能特性
|
||||
|
||||
- **搜索**: 支持游戏名称搜索
|
||||
- **标签筛选**: 游戏类型标签
|
||||
- **平台筛选**: iOS/Android/PC/主机
|
||||
- **排序**: 热门/最新/名称
|
||||
- **卡片展示**: 封面图、名称、类型、人数、平台
|
||||
|
||||
---
|
||||
|
||||
### 6.2 游戏详情 (/games/:id)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [←] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ [游戏封面图 - 宽] │ │
|
||||
│ │ │ │
|
||||
│ │ 王者荣耀 │ │
|
||||
│ │ 5v5公平竞技游戏 │ │
|
||||
│ │ │ │
|
||||
│ │ [MOBA] [5v5] [iOS/Android] │ │
|
||||
│ │ │ │
|
||||
│ │ 人数: 1-10人 │ │
|
||||
│ │ │ │
|
||||
│ │ [创建预约] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 游戏描述 │ │
|
||||
│ │ 《王者荣耀》是腾讯第一3D英雄... │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 相关预约 │ │
|
||||
│ │ [预约卡片列表] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 预约管理
|
||||
|
||||
### 7.1 预约列表 (/appointments)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 预约管理 [+ 创建预约] [筛选] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [全部] [即将开始] [进行中] [已结束] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ [游戏图标] 今晚开黑 │ │
|
||||
│ │ 王者荣耀固定队 │ │
|
||||
│ │ 今天 20:00-23:00 │ │
|
||||
│ │ 参与: 4/5 ●即将开始 │ │
|
||||
│ │ [查看详情] [退出] │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ [游戏图标] 周末桌游局 │ │
|
||||
│ │ 周末休闲组 │ │
|
||||
│ │ 周六 14:00-18:00 │ │
|
||||
│ │ 参与: 6/8 ○未开始 │ │
|
||||
│ │ [查看详情] [退出] │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ...更多预约 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 状态标签
|
||||
|
||||
| 状态 | 标签 | 颜色 |
|
||||
|------|------|------|
|
||||
| open | 未开始 | 绿色 |
|
||||
| full | 已满 | 橙色 |
|
||||
| ongoing | 进行中 | 蓝色 |
|
||||
| finished | 已结束 | 灰色 |
|
||||
| cancelled | 已取消 | 红色 |
|
||||
|
||||
---
|
||||
|
||||
### 7.2 创建预约 (/appointments/create)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [←] 创建预约 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────┐ │
|
||||
│ │ 选择小组 │ │
|
||||
│ │ [下拉选择 - 王者荣耀固定组 ▼] │ │
|
||||
│ │ │ │
|
||||
│ │ 选择游戏 │ │
|
||||
│ │ [搜索游戏...] │ │
|
||||
│ │ [王者荣耀] [和平精英] ... │ │
|
||||
│ │ │ │
|
||||
│ │ 预约标题 │ │
|
||||
│ │ [_________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ 预约描述 │ │
|
||||
│ │ [_________________________________] │ │
|
||||
│ │ [_________________________________] │ │
|
||||
│ │ │ │
|
||||
│ │ 开始时间 结束时间 │ │
|
||||
│ │ [日期选择] [日期选择] │ │
|
||||
│ │ [时间选择] [时间选择] │ │
|
||||
│ │ │ │
|
||||
│ │ 最大参与人数 │ │
|
||||
│ │ [5▼] (根据游戏人数范围推荐) │ │
|
||||
│ │ │ │
|
||||
│ │ [取消] [创建预约] │ │
|
||||
│ └───────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 积分排行
|
||||
|
||||
### 8.1 积分排行榜 (/points/ranking/:groupId)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [←] 积分排行榜 - 王者荣耀固定队 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [本周] [本月] [总榜] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 🥇 [头像] 用户A │ │
|
||||
│ │ 2,500积分 ↑2 │ │
|
||||
│ │ 参与活动25次 MVP 10次 │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 🥈 [头像] 用户B │ │
|
||||
│ │ 2,100积分 ↓1 │ │
|
||||
│ │ 参与活动22次 MVP 8次 │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 🥉 [头像] 用户C │ │
|
||||
│ │ 1,800积分 - │ │
|
||||
│ │ 参与活动20次 MVP 5次 │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 4 [头像] 用户D │ │
|
||||
│ │ 1,500积分 ↑5 │ │
|
||||
│ │ 参与活动18次 MVP 3次 │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ...更多排名 │
|
||||
│ │
|
||||
│ 我的排名: 第15名 (800积分) │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 特效
|
||||
|
||||
- **Top3特殊样式**: 金银铜牌样式
|
||||
- **排名变化**: ↑↓箭头显示排名变化
|
||||
- **我的排名**: 底部固定显示
|
||||
|
||||
---
|
||||
|
||||
## 9. 荣誉墙
|
||||
|
||||
### 9.1 荣誉时间轴 (/honors/:groupId)
|
||||
|
||||
#### 页面布局
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ [←] 荣誉墙 - 王者荣耀固定队 │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 2026年 │ │
|
||||
│ │ ───────────────────────────────── │ │
|
||||
│ │ │ │
|
||||
│ │ 🏆 年度MVP │ │
|
||||
│ │ [头像][头像] │ │
|
||||
│ │ 用户A 用户B │ │
|
||||
│ │ │ │
|
||||
│ │ 🏆 最佳新人 │ │
|
||||
│ │ [头像] │ │
|
||||
│ │ 用户C │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 2025年12月 │ │
|
||||
│ │ ───────────────────────────────── │ │
|
||||
│ │ │ │
|
||||
│ │ 🏆 月度冠军 │ │
|
||||
│ │ [头像] │ │
|
||||
│ │ 用户A │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────┐ │
|
||||
│ │ 2025年11月 │ │
|
||||
│ │ ───────────────────────────────── │ │
|
||||
│ │ ... │ │
|
||||
│ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 荣誉类型
|
||||
|
||||
| 类型 | 图标 | 说明 |
|
||||
|------|------|------|
|
||||
| YEARLY | 🏆 | 年度荣誉 |
|
||||
| MONTHLY | 🥇 | 月度荣誉 |
|
||||
| WEEKLY | ⭐ | 周度荣誉 |
|
||||
| CUSTOM | 🎖️ | 自定义荣誉 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 响应式适配
|
||||
|
||||
### 10.1 移动端适配
|
||||
|
||||
#### 顶部导航
|
||||
- 桌面: 水平导航菜单
|
||||
- 移动: 汉堡菜单 + 抽屉式导航
|
||||
|
||||
#### 侧边栏
|
||||
- 桌面: 固定显示
|
||||
- 平板: 可折叠
|
||||
- 移动: 抽屉式侧边栏
|
||||
|
||||
#### 内容布局
|
||||
- 桌面: 3-4列网格
|
||||
- 平板: 2列网格
|
||||
- 移动: 1列堆叠
|
||||
|
||||
#### 卡片信息
|
||||
- 桌面: 完整信息展示
|
||||
- 移动: 精简信息,点击查看详情
|
||||
|
||||
---
|
||||
|
||||
## 11. 页面动效
|
||||
|
||||
### 11.1 页面切换动画
|
||||
|
||||
```css
|
||||
/* 淡入淡出 */
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* 滑动 */
|
||||
.slide-enter-active, .slide-leave-active {
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
.slide-enter-from {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
.slide-leave-to {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
```
|
||||
|
||||
### 11.2 列表动画
|
||||
|
||||
```css
|
||||
/* 列表项依次进入 */
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item {
|
||||
animation: slideInUp 0.3s ease-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.list-item:nth-child(1) { animation-delay: 0ms; }
|
||||
.list-item:nth-child(2) { animation-delay: 50ms; }
|
||||
.list-item:nth-child(3) { animation-delay: 100ms; }
|
||||
/* ... */
|
||||
```
|
||||
|
||||
### 11.3 加载动画
|
||||
|
||||
- **骨架屏**: 内容加载时显示
|
||||
- **Loading Spinner**: 按钮加载、异步操作
|
||||
- **进度条**: 页面顶部加载进度
|
||||
|
||||
---
|
||||
|
||||
## 12. 总结
|
||||
|
||||
本页面设计文档确保:
|
||||
- ✅ **一致性**: 统一的页面布局和交互模式
|
||||
- ✅ **易用性**: 直观的导航和操作流程
|
||||
- ✅ **美观性**: 精心设计的视觉呈现
|
||||
- ✅ **响应式**: 完美适配各种设备
|
||||
- ✅ **性能**: 流畅的页面加载和交互
|
||||
|
||||
---
|
||||
|
||||
**文档维护**: 随页面迭代持续更新
|
||||
**最后更新**: 2026-01-28
|
||||
1161
doc/design/05-移动端与跨平台方案.md
Normal file
1161
doc/design/05-移动端与跨平台方案.md
Normal file
File diff suppressed because it is too large
Load Diff
98
doc/后端README.md
Normal file
98
doc/后端README.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# GameGroup 项目文档目录
|
||||
|
||||
本目录包含 GameGroup 后端项目的所有文档。
|
||||
|
||||
## 📁 目录结构
|
||||
|
||||
```
|
||||
doc/
|
||||
├── api/ # API 相关文档
|
||||
│ └── API文档.md # 完整的 API 接口文档
|
||||
├── deployment/ # 部署相关文档
|
||||
│ ├── DEPLOYMENT.md # Docker 部署指南
|
||||
│ └── 部署指导文档.md # 详细部署说明
|
||||
├── development/ # 开发相关文档
|
||||
│ ├── PHASE5_OPTIMIZATION.md # 第五阶段优化计划
|
||||
│ ├── 修改记录.md # 项目修改记录
|
||||
│ └── 开发步骤文档.md # 完整的开发步骤文档
|
||||
└── testing/ # 测试相关文档
|
||||
└── test-summary.md # 测试总结报告
|
||||
```
|
||||
|
||||
## 📚 文档说明
|
||||
|
||||
### API 文档
|
||||
- **API文档.md**: 包含所有 API 接口的详细说明,包括请求方法、参数、响应格式等
|
||||
- 认证相关接口
|
||||
- 用户管理接口
|
||||
- 小组管理接口
|
||||
- 游戏库接口
|
||||
- 预约管理接口
|
||||
- 账目管理接口
|
||||
- 排班助手接口
|
||||
- 黑名单系统接口
|
||||
- 荣誉墙接口
|
||||
- 资产管理接口
|
||||
- 积分系统接口
|
||||
- 竞猜系统接口
|
||||
|
||||
### 部署文档
|
||||
- **DEPLOYMENT.md**: Docker 容器化部署指南
|
||||
- Docker 镜像构建
|
||||
- Docker Compose 配置
|
||||
- 环境变量配置
|
||||
- 部署步骤说明
|
||||
|
||||
- **部署指导文档.md**: 详细的部署指导
|
||||
- 服务器环境准备
|
||||
- 数据库配置
|
||||
- Redis 配置
|
||||
- 应用部署
|
||||
- 常见问题解决
|
||||
|
||||
### 开发文档
|
||||
- **开发步骤文档.md**: 项目开发完整流程
|
||||
- 第一阶段:项目初始化与基础配置
|
||||
- 第二阶段:核心基础设施
|
||||
- 第三阶段:核心业务模块开发
|
||||
- 第四阶段:高级功能模块
|
||||
- 第五阶段:集成与优化
|
||||
- 第六阶段:测试与部署
|
||||
|
||||
- **PHASE5_OPTIMIZATION.md**: 第五阶段优化计划
|
||||
- 性能优化策略
|
||||
- 缓存优化方案
|
||||
- 数据库优化
|
||||
- API 优化
|
||||
|
||||
- **修改记录.md**: 项目重要修改记录
|
||||
- 功能更新记录
|
||||
- Bug 修复记录
|
||||
- 重构记录
|
||||
|
||||
### 测试文档
|
||||
- **test-summary.md**: 测试总结报告
|
||||
- 单元测试统计
|
||||
- 测试覆盖率
|
||||
- 测试结果分析
|
||||
- 待修复问题列表
|
||||
|
||||
## 🔗 相关链接
|
||||
|
||||
- [项目 README](../README.md) - 项目总体介绍
|
||||
- [Swagger API 文档](http://localhost:3000/docs) - 在线 API 文档(开发环境)
|
||||
- [数据库初始化脚本](../database/init.sql) - 数据库表结构
|
||||
|
||||
## 📝 文档更新
|
||||
|
||||
文档最后更新时间:2025-12-19
|
||||
|
||||
如有文档更新需求,请按以下规范进行:
|
||||
1. 保持文档格式统一
|
||||
2. 更新文档末尾的更新时间
|
||||
3. 在修改记录中记录重大变更
|
||||
4. 保持 API 文档与代码同步
|
||||
|
||||
---
|
||||
|
||||
**注意**: 本目录下的所有文档均为项目内部文档,包含敏感信息,请勿泄露给外部人员。
|
||||
530
doc/后端项目分析报告.md
Normal file
530
doc/后端项目分析报告.md
Normal file
@@ -0,0 +1,530 @@
|
||||
# GameGroup 项目分析报告
|
||||
|
||||
**分析日期**: 2025-12-19
|
||||
**项目状态**: 第四阶段完成,第五阶段待进行
|
||||
**分析范围**: 代码架构、设计一致性、逻辑漏洞、数据完整性
|
||||
|
||||
---
|
||||
|
||||
## 📊 项目概览
|
||||
|
||||
### 基本信息
|
||||
- **项目名称**: GameGroup 后端系统
|
||||
- **技术栈**: NestJS 11 + TypeScript + MySQL 8.0 + Redis + TypeORM
|
||||
- **代码量**: ~26,500 行
|
||||
- **模块数量**: 12 个核心业务模块
|
||||
- **实体数量**: 15 个数据库实体
|
||||
- **API 接口**: 70+ 个 RESTful 接口
|
||||
- **测试覆盖**: 169 个测试(142 个通过,27 个失败)
|
||||
- **测试覆盖率**: ~84%
|
||||
|
||||
### 项目架构
|
||||
```
|
||||
src/
|
||||
├── common/ # 公共模块(装饰器、守卫、拦截器、管道、工具)
|
||||
├── config/ # 配置文件
|
||||
├── entities/ # 数据库实体
|
||||
└── modules/ # 业务模块(12个)
|
||||
├── auth/ # 认证模块
|
||||
├── users/ # 用户模块
|
||||
├── groups/ # 小组模块
|
||||
├── games/ # 游戏库模块
|
||||
├── appointments/# 预约模块
|
||||
├── ledgers/ # 账目模块
|
||||
├── schedules/ # 排班模块
|
||||
├── blacklist/ # 黑名单模块
|
||||
├── honors/ # 荣誉墙模块
|
||||
├── assets/ # 资产模块
|
||||
├── points/ # 积分模块
|
||||
└── bets/ # 竞猜模块
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 项目优点
|
||||
|
||||
### 1. 架构设计
|
||||
- ✅ **模块化设计**: 清晰的模块划分,职责明确
|
||||
- ✅ **分层架构**: Controller -> Service -> Repository,层次分明
|
||||
- ✅ **依赖注入**: 使用 NestJS 的 DI 容器,解耦良好
|
||||
- ✅ **配置管理**: 环境变量配置完善,支持多环境
|
||||
|
||||
### 2. 代码质量
|
||||
- ✅ **TypeScript**: 类型安全,减少运行时错误
|
||||
- ✅ **统一响应格式**: 标准化的 API 响应结构
|
||||
- ✅ **全局异常处理**: 统一的错误处理机制
|
||||
- ✅ **日志记录**: 完善的请求/响应日志
|
||||
|
||||
### 3. 安全性
|
||||
- ✅ **JWT 认证**: 基于 Token 的身份验证
|
||||
- ✅ **密码加密**: bcrypt 加密存储
|
||||
- ✅ **权限控制**: RBAC 角色权限管理
|
||||
- ✅ **参数验证**: class-validator 请求数据验证
|
||||
|
||||
### 4. 性能优化
|
||||
- ✅ **HTTP 压缩**: compression 中间件
|
||||
- ✅ **缓存机制**: 内存缓存服务
|
||||
- ✅ **数据库索引**: 关键字段索引优化
|
||||
- ✅ **连接池**: 数据库连接池配置
|
||||
|
||||
### 5. 开发体验
|
||||
- ✅ **Swagger 文档**: 自动生成 API 文档
|
||||
- ✅ **热重载**: 开发环境自动重启
|
||||
- ✅ **代码规范**: ESLint + Prettier
|
||||
- ✅ **单元测试**: Jest 测试框架
|
||||
|
||||
---
|
||||
|
||||
## 🔴 严重问题(必须修复)
|
||||
|
||||
### 1. 财务操作缺少事务管理 ⚠️
|
||||
|
||||
**严重程度**: 🔴 严重
|
||||
**影响范围**: 积分系统、竞猜系统、资产系统
|
||||
|
||||
**问题描述**:
|
||||
- [bets.service.ts:184-207](../src/modules/bets/bets.service.ts#L184-L207): 竞猜结算没有事务保护
|
||||
- [points.service.ts:32-73](../src/modules/points/points.service.ts#L32-L73): 积分操作没有事务保护
|
||||
- [assets.service.ts:215-226](../src/modules/assets/assets.service.ts#L215-L226): 资产借用没有事务保护
|
||||
|
||||
**风险**:
|
||||
- 如果操作过程中断,可能导致财务数据不一致
|
||||
- 部分用户收到积分,部分没有
|
||||
- 积分池总和不匹配
|
||||
|
||||
**修复方案**:
|
||||
```typescript
|
||||
async settleBet(appointmentId: string, winningOption: string) {
|
||||
await this.dataSource.transaction(async (manager) => {
|
||||
// 所有数据库操作使用 manager
|
||||
const bets = await manager.find(Bet, { ... });
|
||||
for (const bet of bets) {
|
||||
// 积分分配逻辑
|
||||
await manager.save(Point, { ... });
|
||||
await manager.save(Bet, { ... });
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**修复优先级**: 🔴 最高
|
||||
|
||||
---
|
||||
|
||||
### 2. 并发竞态条件 ⚠️
|
||||
|
||||
**严重程度**: 🔴 严重
|
||||
**影响范围**: 小组管理、预约管理、资产管理
|
||||
|
||||
**问题列表**:
|
||||
|
||||
#### 2.1 小组成员数竞态
|
||||
**位置**: [groups.service.ts:165-172](../src/modules/groups/groups.service.ts#L165-L172)
|
||||
|
||||
```typescript
|
||||
// ❌ 问题代码
|
||||
await this.groupMemberRepository.save(member);
|
||||
group.currentMembers += 1;
|
||||
await this.groupRepository.save(group);
|
||||
```
|
||||
|
||||
**风险**: 多个用户同时加入可能超过 `maxMembers` 限制
|
||||
|
||||
#### 2.2 预约人数竞态
|
||||
**位置**: [appointments.service.ts](../src/modules/appointments/appointments.service.ts)
|
||||
|
||||
**风险**: 预约人数可能超过 `maxParticipants`
|
||||
|
||||
#### 2.3 资产借用竞态
|
||||
**位置**: [assets.service.ts:215-217](../src/modules/assets/assets.service.ts#L215-L217)
|
||||
|
||||
```typescript
|
||||
// ❌ 问题代码
|
||||
asset.status = AssetStatus.IN_USE;
|
||||
await this.assetRepository.save(asset);
|
||||
```
|
||||
|
||||
**风险**: 多个用户可能同时借用同一资产
|
||||
|
||||
**修复方案**:
|
||||
```typescript
|
||||
// ✅ 原子更新
|
||||
await this.groupRepository
|
||||
.createQueryBuilder()
|
||||
.update(Group)
|
||||
.set({ currentMembers: () => 'currentMembers + 1' })
|
||||
.where('id = :id AND currentMembers < maxMembers', { id: groupId })
|
||||
.execute();
|
||||
|
||||
// 或者使用悲观锁
|
||||
const group = await this.groupRepository
|
||||
.createQueryBuilder('group')
|
||||
.setLock('pessimistic_write')
|
||||
.where('group.id = :id', { id: groupId })
|
||||
.getOne();
|
||||
```
|
||||
|
||||
**修复优先级**: 🔴 最高
|
||||
|
||||
---
|
||||
|
||||
### 3. 积分计算精度损失 ⚠️
|
||||
|
||||
**严重程度**: 🟡 中等
|
||||
**影响范围**: 竞猜系统
|
||||
|
||||
**问题位置**: [bets.service.ts:187](../src/modules/bets/bets.service.ts#L187)
|
||||
|
||||
```typescript
|
||||
// ❌ 问题代码
|
||||
const winAmount = Math.floor((bet.amount / winningTotal) * totalPool);
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- 使用 `Math.floor()` 会导致积分池积分无法完全分配
|
||||
- 示例:总池 100 积分,3 个赢家按 33:33:34 分配,实际可能只分配出 99 积分
|
||||
- 剩余积分丢失
|
||||
|
||||
**修复方案**:
|
||||
```typescript
|
||||
// ✅ 最后一个赢家获得剩余积分
|
||||
let distributedAmount = 0;
|
||||
const winningBets = bets.filter(b => b.betOption === winningOption);
|
||||
|
||||
for (let i = 0; i < winningBets.length; i++) {
|
||||
const bet = winningBets[i];
|
||||
let winAmount: number;
|
||||
|
||||
if (i === winningBets.length - 1) {
|
||||
// 最后一个赢家获得剩余所有积分
|
||||
winAmount = totalPool - distributedAmount;
|
||||
} else {
|
||||
winAmount = Math.floor((bet.amount / winningTotal) * totalPool);
|
||||
distributedAmount += winAmount;
|
||||
}
|
||||
|
||||
bet.winAmount = winAmount;
|
||||
}
|
||||
```
|
||||
|
||||
**修复优先级**: 🔴 高
|
||||
|
||||
---
|
||||
|
||||
## 🟡 中等问题(建议修复)
|
||||
|
||||
### 4. 权限检查模型不一致
|
||||
|
||||
**严重程度**: 🟡 中等
|
||||
**影响范围**: 黑名单模块、全局权限控制
|
||||
|
||||
**问题位置**: [blacklist.service.ts:105](../src/modules/blacklist/blacklist.service.ts#L105)
|
||||
|
||||
```typescript
|
||||
// ❌ 不一致的权限检查
|
||||
if (!user.isMember) {
|
||||
throw new ForbiddenException('需要会员权限');
|
||||
}
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- 黑名单审核使用 `user.isMember` 判断权限
|
||||
- 其他模块使用 `GroupMemberRole.ADMIN` 或 `GroupMemberRole.OWNER`
|
||||
- 权限模型混乱
|
||||
|
||||
**修复方案**:
|
||||
1. 统一使用基于角色的权限控制(RBAC)
|
||||
2. 定义清晰的权限层级
|
||||
3. 创建统一的权限检查装饰器
|
||||
|
||||
**修复优先级**: 🟡 中
|
||||
|
||||
---
|
||||
|
||||
### 5. 级联删除策略不明确
|
||||
|
||||
**严重程度**: 🟡 中等
|
||||
**影响范围**: 所有实体关系
|
||||
|
||||
**问题位置**: [point.entity.ts:20,27](../src/entities/point.entity.ts#L20)
|
||||
|
||||
```typescript
|
||||
// user 和 group 都设置了级联删除
|
||||
@ManyToOne(() => User, (user) => user.points, { onDelete: 'CASCADE' })
|
||||
@ManyToOne(() => Group, { onDelete: 'CASCADE' })
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- 删除用户时自动删除积分记录
|
||||
- 删除小组时也会删除积分记录
|
||||
- 数据清理策略不明确
|
||||
|
||||
**修复方案**:
|
||||
1. 明确级联删除策略
|
||||
2. 考虑使用软删除替代硬删除
|
||||
3. 添加数据归档机制
|
||||
|
||||
**修复优先级**: 🟡 中
|
||||
|
||||
---
|
||||
|
||||
### 6. 缓存一致性问题
|
||||
|
||||
**严重程度**: 🟡 中等
|
||||
**影响范围**: 所有使用缓存的服务
|
||||
|
||||
**问题位置**: [groups.service.ts:298-299](../src/modules/groups/groups.service.ts#L298-L299)
|
||||
|
||||
**问题**:
|
||||
- 只在更新时清除缓存
|
||||
- 删除操作未清除缓存
|
||||
- 可能返回已删除数据的缓存
|
||||
|
||||
**修复方案**:
|
||||
1. 在所有删除操作中添加缓存清除
|
||||
2. 实现统一的缓存管理策略
|
||||
3. 使用缓存键的版本控制
|
||||
|
||||
**修复优先级**: 🟡 中
|
||||
|
||||
---
|
||||
|
||||
### 7. 手动维护计数字段的风险
|
||||
|
||||
**严重程度**: 🟡 中等
|
||||
**影响范围**: 预约模块、小组模块
|
||||
|
||||
**问题位置**: [appointment.entity.ts:60-61](../src/entities/appointment.entity.ts#L60-L61)
|
||||
|
||||
```typescript
|
||||
@Column({ default: 0, comment: '当前参与人数' })
|
||||
currentParticipants: number;
|
||||
```
|
||||
|
||||
**问题**:
|
||||
- `currentParticipants` 字段手动维护
|
||||
- 如果应用崩溃,可能与实际值不一致
|
||||
- 需要定期校验
|
||||
|
||||
**修复方案**:
|
||||
1. 使用数据库查询实时计算(性能优化可用缓存)
|
||||
2. 添加定期校验任务修正数据
|
||||
3. 使用数据库触发器自动维护
|
||||
|
||||
**修复优先级**: 🟡 中
|
||||
|
||||
---
|
||||
|
||||
## 🟢 低优先级问题(可选修复)
|
||||
|
||||
### 8. 缺少实体级验证装饰器
|
||||
|
||||
**严重程度**: 🟢 低
|
||||
**影响范围**: 所有实体
|
||||
|
||||
**问题**:
|
||||
- 实体没有使用 `class-validator` 装饰器
|
||||
- 仅依赖数据库约束
|
||||
- 数据验证不够早期
|
||||
|
||||
**修复方案**:
|
||||
```typescript
|
||||
@Entity('users')
|
||||
export class User {
|
||||
@Column()
|
||||
@IsNotEmpty()
|
||||
@MinLength(3)
|
||||
username: string;
|
||||
|
||||
@Column()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
}
|
||||
```
|
||||
|
||||
**修复优先级**: 🟢 低
|
||||
|
||||
---
|
||||
|
||||
### 9. 错误消息不够具体
|
||||
|
||||
**严重程度**: 🟢 低
|
||||
**影响范围**: 所有服务
|
||||
|
||||
**问题**:
|
||||
- 很多地方抛出通用错误消息
|
||||
- 缺少具体上下文
|
||||
- 调试困难
|
||||
|
||||
**修复方案**:
|
||||
1. 提供更详细的错误信息
|
||||
2. 添加错误追踪 ID
|
||||
3. 记录完整的错误堆栈
|
||||
|
||||
**修复优先级**: 🟢 低
|
||||
|
||||
---
|
||||
|
||||
## 📋 修复建议实施计划
|
||||
|
||||
### 阶段一:紧急修复(1-2 天)
|
||||
|
||||
**优先级**: 🔴 最高
|
||||
**时间**: 2-3 小时
|
||||
|
||||
1. **添加事务管理**(1 小时)
|
||||
- bets.service.ts - 竞猜结算
|
||||
- points.service.ts - 积分操作
|
||||
- assets.service.ts - 资产借还
|
||||
|
||||
2. **修复并发竞态**(1-2 小时)
|
||||
- groups.service.ts - 小组成员数
|
||||
- appointments.service.ts - 预约人数
|
||||
- assets.service.ts - 资产状态
|
||||
|
||||
3. **修复积分计算**(30 分钟)
|
||||
- bets.service.ts - 积分分配算法
|
||||
|
||||
---
|
||||
|
||||
### 阶段二:重要改进(3-5 天)
|
||||
|
||||
**优先级**: 🟡 中等
|
||||
**时间**: 3-5 小时
|
||||
|
||||
1. **统一权限模型**(1-2 小时)
|
||||
- 创建统一权限检查装饰器
|
||||
- 替换所有硬编码权限检查
|
||||
- 添加权限测试
|
||||
|
||||
2. **优化缓存策略**(1 小时)
|
||||
- 实现统一缓存管理
|
||||
- 添加缓存失效策略
|
||||
- 缓存一致性测试
|
||||
|
||||
3. **明确删除策略**(1-2 小时)
|
||||
- 审查所有级联删除
|
||||
- 实现软删除机制
|
||||
- 数据归档策略
|
||||
|
||||
---
|
||||
|
||||
### 阶段三:代码质量提升(1 周)
|
||||
|
||||
**优先级**: 🟢 低
|
||||
**时间**: 2-3 小时
|
||||
|
||||
1. **添加验证装饰器**(1-2 小时)
|
||||
- 所有实体添加验证
|
||||
- DTO 同步验证
|
||||
|
||||
2. **改进错误处理**(1 小时)
|
||||
- 统一错误码
|
||||
- 详细错误信息
|
||||
- 错误追踪
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试建议
|
||||
|
||||
### 必须添加的测试
|
||||
|
||||
1. **并发测试**
|
||||
```typescript
|
||||
describe('并发测试', () => {
|
||||
it('多个用户同时加入小组', async () => {
|
||||
const promises = Array(10).fill(null).map(() =>
|
||||
groupsService.join(userId, groupId)
|
||||
);
|
||||
await Promise.all(promises);
|
||||
// 验证成员数不超过限制
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
2. **事务回滚测试**
|
||||
```typescript
|
||||
it('竞猜结算失败时回滚', async () => {
|
||||
jest.spyOn(pointRepository, 'save').mockRejectedValueOnce(
|
||||
new Error('Database error')
|
||||
);
|
||||
await expect(
|
||||
betsService.settleBet(appointmentId, winningOption)
|
||||
).rejects.toThrow();
|
||||
// 验证数据没有部分更新
|
||||
});
|
||||
```
|
||||
|
||||
3. **数据一致性测试**
|
||||
```typescript
|
||||
it('积分总和必须一致', async () => {
|
||||
const beforePool = await getTotalPool();
|
||||
await betsService.settleBet(appointmentId, winningOption);
|
||||
const afterPool = await getTotalPool();
|
||||
expect(afterPool).toEqual(beforePool);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 项目健康度评分
|
||||
|
||||
| 评估项 | 评分 | 说明 |
|
||||
|--------|------|------|
|
||||
| 架构设计 | ⭐⭐⭐⭐⭐ | 模块化设计优秀,职责清晰 |
|
||||
| 代码质量 | ⭐⭐⭐⭐ | TypeScript 类型安全,但缺少注释 |
|
||||
| 安全性 | ⭐⭐⭐⭐ | 认证授权完善,但需加强权限一致性 |
|
||||
| 性能 | ⭐⭐⭐⭐ | 有缓存和优化,但可进一步优化 |
|
||||
| 测试覆盖 | ⭐⭐⭐ | 84% 覆盖率,但缺少并发测试 |
|
||||
| 文档完善度 | ⭐⭐⭐⭐⭐ | 文档齐全,已整理到 doc 目录 |
|
||||
| **总体评分** | ⭐⭐⭐⭐ | **良好,需要修复关键问题** |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 后续建议
|
||||
|
||||
### 短期(1-2 周)
|
||||
1. ✅ 修复所有高优先级问题
|
||||
2. ✅ 添加并发测试
|
||||
3. ✅ 完善事务管理
|
||||
4. ✅ 提高测试覆盖率到 90%+
|
||||
|
||||
### 中期(1-2 个月)
|
||||
1. 实现软删除机制
|
||||
2. 添加数据归档功能
|
||||
3. 实现缓存预热策略
|
||||
4. 添加性能监控
|
||||
|
||||
### 长期(3-6 个月)
|
||||
1. 微服务拆分(如需要)
|
||||
2. 引入消息队列
|
||||
3. 实现分布式锁
|
||||
4. 添加链路追踪
|
||||
|
||||
---
|
||||
|
||||
## 📝 总结
|
||||
|
||||
GameGroup 项目整体架构设计合理,模块划分清晰,代码质量较高。但在以下方面需要改进:
|
||||
|
||||
**必须立即修复**:
|
||||
1. 财务操作缺少事务管理(可能导致财务数据不一致)
|
||||
2. 并发竞态条件(可能导致业务逻辑错误)
|
||||
3. 积分计算精度损失(可能导致积分丢失)
|
||||
|
||||
**建议尽快修复**:
|
||||
4. 权限模型不统一(可能导致权限漏洞)
|
||||
5. 缓存一致性问题(可能返回过期数据)
|
||||
6. 级联删除策略不明确(可能导致数据意外删除)
|
||||
|
||||
**可选改进**:
|
||||
7. 添加实体级验证装饰器
|
||||
8. 改进错误消息
|
||||
|
||||
建议按照优先级分阶段修复,每个修复都应有充分的测试覆盖。修复完成后,项目质量将显著提升。
|
||||
|
||||
---
|
||||
|
||||
**报告生成时间**: 2025-12-19
|
||||
**分析人员**: Claude Code
|
||||
**下次审查时间**: 修复完成后重新评估
|
||||
2800
doc/开发步骤文档.md
Normal file
2800
doc/开发步骤文档.md
Normal file
File diff suppressed because it is too large
Load Diff
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>GameGroup - 游戏社群管理平台</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
3189
package-lock.json
generated
Normal file
3189
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
package.json
Normal file
30
package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "gamegroup-fe",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.0",
|
||||
"vue-router": "^4.2.0",
|
||||
"pinia": "^2.1.0",
|
||||
"axios": "^1.6.0",
|
||||
"element-plus": "^2.5.0",
|
||||
"@element-plus/icons-vue": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
"vite": "^5.0.0",
|
||||
"vue-tsc": "^1.8.0",
|
||||
"typescript": "^5.3.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"postcss": "^8.4.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"sass": "^1.69.0"
|
||||
}
|
||||
}
|
||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
16
src/App.vue
Normal file
16
src/App.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 根组件
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
9
src/assets/styles/main.css
Normal file
9
src/assets/styles/main.css
Normal file
@@ -0,0 +1,9 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
body {
|
||||
@apply bg-gray-50 text-gray-900;
|
||||
}
|
||||
}
|
||||
17
src/constants/config.ts
Normal file
17
src/constants/config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// API 配置
|
||||
export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api'
|
||||
export const API_TIMEOUT = 15000
|
||||
|
||||
// 本地存储键
|
||||
export const STORAGE_KEYS = {
|
||||
ACCESS_TOKEN: 'access_token',
|
||||
REFRESH_TOKEN: 'refresh_token',
|
||||
USER_INFO: 'user_info'
|
||||
} as const
|
||||
|
||||
// 分页配置
|
||||
export const PAGINATION = {
|
||||
DEFAULT_PAGE: 1,
|
||||
DEFAULT_LIMIT: 20,
|
||||
MAX_LIMIT: 100
|
||||
} as const
|
||||
21
src/constants/enums.ts
Normal file
21
src/constants/enums.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// 用户角色
|
||||
export enum UserRole {
|
||||
OWNER = 'owner',
|
||||
ADMIN = 'admin',
|
||||
MEMBER = 'member'
|
||||
}
|
||||
|
||||
// 预约状态
|
||||
export enum AppointmentStatus {
|
||||
OPEN = 'open',
|
||||
FULL = 'full',
|
||||
CANCELLED = 'cancelled',
|
||||
FINISHED = 'finished'
|
||||
}
|
||||
|
||||
// 游戏平台
|
||||
export enum GamePlatform {
|
||||
PC = 'PC',
|
||||
MOBILE = 'Mobile',
|
||||
CONSOLE = 'Console'
|
||||
}
|
||||
9
src/main.ts
Normal file
9
src/main.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
// 样式
|
||||
import './assets/styles/main.css'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.mount('#app')
|
||||
16
src/types/api.ts
Normal file
16
src/types/api.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// 统一响应格式
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
// 分页响应
|
||||
export interface PageResponse<T> {
|
||||
items: T[]
|
||||
total: number
|
||||
page: number
|
||||
limit: number
|
||||
totalPages: number
|
||||
}
|
||||
21
src/types/appointment.ts
Normal file
21
src/types/appointment.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export interface AppointmentInfo {
|
||||
id: string
|
||||
title: string
|
||||
startTime: string
|
||||
endTime: string
|
||||
currentParticipants: number
|
||||
maxParticipants: number
|
||||
status: 'open' | 'full' | 'cancelled' | 'finished'
|
||||
game: {
|
||||
id: string
|
||||
name: string
|
||||
coverUrl: string
|
||||
}
|
||||
group: {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
isParticipant: boolean
|
||||
isCreator: boolean
|
||||
isFull: boolean
|
||||
}
|
||||
10
src/types/game.ts
Normal file
10
src/types/game.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface GameInfo {
|
||||
id: string
|
||||
name: string
|
||||
coverUrl: string
|
||||
description?: string
|
||||
tags: string[]
|
||||
minPlayers: number
|
||||
maxPlayers: number
|
||||
platform: string
|
||||
}
|
||||
19
src/types/group.ts
Normal file
19
src/types/group.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export interface GroupInfo {
|
||||
id: string
|
||||
name: string
|
||||
avatar: string
|
||||
description?: string
|
||||
currentMembers: number
|
||||
maxMembers: number
|
||||
myRole?: 'owner' | 'admin' | 'member'
|
||||
tags?: string[]
|
||||
createdAt?: string
|
||||
}
|
||||
|
||||
export interface CreateGroupParams {
|
||||
name: string
|
||||
description?: string
|
||||
avatar?: string
|
||||
maxMembers?: number
|
||||
tags?: string[]
|
||||
}
|
||||
12
src/types/user.ts
Normal file
12
src/types/user.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface UserInfo {
|
||||
id: string
|
||||
username: string
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
email?: string
|
||||
phone?: string
|
||||
role?: string
|
||||
isMember?: boolean
|
||||
isOnline?: boolean
|
||||
createdAt?: string
|
||||
}
|
||||
7
src/vite-env.d.ts
vendored
Normal file
7
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
51
tailwind.config.js
Normal file
51
tailwind.config.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/** @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: [],
|
||||
}
|
||||
31
tsconfig.json
Normal file
31
tsconfig.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
/* Path Mapping */
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
11
tsconfig.node.json
Normal file
11
tsconfig.node.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
36
vite.config.ts
Normal file
36
vite.config.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
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']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user