forked from datawhale/whale-town-end
chore: 清理旧文件和更新项目配置
- 删除旧的DTO文件(已迁移到对应业务模块) - 删除旧的测试目录结构 - 删除过时的API目录 - 更新package.json配置 - 移除不再使用的文件
This commit is contained in:
106
CONTRIBUTORS.md
106
CONTRIBUTORS.md
@@ -1,106 +0,0 @@
|
|||||||
# 贡献者名单
|
|
||||||
|
|
||||||
感谢所有为 Whale Town 项目做出贡献的开发者们!🎉
|
|
||||||
|
|
||||||
## 核心贡献者
|
|
||||||
|
|
||||||
### 🏆 主要维护者
|
|
||||||
|
|
||||||
**moyin** - 主要维护者
|
|
||||||
- Gitea: [@moyin](https://gitea.xinghangee.icu/moyin)
|
|
||||||
- Email: xinghang_a@proton.me
|
|
||||||
- 提交数: **66 commits**
|
|
||||||
- 主要贡献:
|
|
||||||
- 🚀 项目架构设计与初始化
|
|
||||||
- 🔐 完整用户认证系统实现
|
|
||||||
- 📧 邮箱验证系统设计与开发
|
|
||||||
- 🗄️ Redis缓存服务(文件存储+真实Redis双模式)
|
|
||||||
- 📝 完整的API文档系统(Swagger UI + OpenAPI)
|
|
||||||
- 🧪 测试框架搭建与114个测试用例编写
|
|
||||||
- 📊 高性能日志系统集成(Pino)
|
|
||||||
- 🔧 项目配置优化与部署方案
|
|
||||||
- 🐛 验证码TTL重置关键问题修复
|
|
||||||
- 📚 完整的项目文档体系建设
|
|
||||||
|
|
||||||
### 🌟 核心开发者
|
|
||||||
|
|
||||||
**angjustinl** - 核心开发者
|
|
||||||
- Gitea: [@ANGJustinl](https://gitea.xinghangee.icu/ANGJustinl)
|
|
||||||
- GitHub: [@ANGJustinl](https://github.com/ANGJustinl)
|
|
||||||
- Email: 96008766+ANGJustinl@users.noreply.github.com
|
|
||||||
- 提交数: **2 commits**
|
|
||||||
- 主要贡献:
|
|
||||||
- 🔄 邮箱验证流程重构与优化
|
|
||||||
- 💾 基于内存的用户服务实现
|
|
||||||
- 🛠️ API响应处理改进
|
|
||||||
- 🧪 测试用例完善与错误修复
|
|
||||||
- 📚 系统架构优化
|
|
||||||
|
|
||||||
**jianuo** - 核心开发者
|
|
||||||
- Gitea: [@jianuo](https://gitea.xinghangee.icu/jianuo)
|
|
||||||
- Email: 32106500027@e.gzhu.edu.cn
|
|
||||||
- 提交数: **6 commits**
|
|
||||||
- 主要贡献:
|
|
||||||
- 🎛️ **管理员后台系统** - 完整的前后端管理界面开发
|
|
||||||
- 📊 **日志管理功能** - 运行时日志查看与下载系统
|
|
||||||
- 🔐 **管理员认证系统** - 独立Token认证与权限控制
|
|
||||||
- 🧪 **单元测试完善** - 管理员功能测试用例编写
|
|
||||||
- ⚙️ **TypeScript配置优化** - Node16模块解析配置
|
|
||||||
- 🐳 **Docker部署优化** - 容器化部署问题修复
|
|
||||||
- 📖 **技术栈文档更新** - 项目技术栈说明完善
|
|
||||||
|
|
||||||
## 贡献统计
|
|
||||||
|
|
||||||
| 贡献者 | 提交数 | 主要领域 | 贡献占比 |
|
|
||||||
|--------|--------|----------|----------|
|
|
||||||
| moyin | 66 | 架构设计、核心功能、文档、测试 | 88% |
|
|
||||||
| jianuo | 6 | 管理员后台、日志系统、部署优化 | 8% |
|
|
||||||
| angjustinl | 2 | 功能优化、测试、重构 | 3% |
|
|
||||||
|
|
||||||
## 项目里程碑
|
|
||||||
|
|
||||||
### 2025年12月
|
|
||||||
- **12月17日**: 项目初始化,完成基础架构搭建
|
|
||||||
- **12月17日**: 实现完整的用户认证系统
|
|
||||||
- **12月17日**: 完成API文档系统集成
|
|
||||||
- **12月17日**: 实现邮箱验证系统
|
|
||||||
- **12月17日**: 修复验证码TTL重置关键问题
|
|
||||||
- **12月18日**: angjustinl重构邮箱验证流程,引入内存用户服务
|
|
||||||
- **12月18日**: jianuo修复Docker部署问题
|
|
||||||
- **12月18日**: 完成测试用例修复和优化
|
|
||||||
- **12月19日**: jianuo开发管理员后台系统
|
|
||||||
- **12月20日**: jianuo完善日志管理功能
|
|
||||||
- **12月21日**: jianuo添加管理员后台单元测试
|
|
||||||
- **12月22日**: 管理员后台功能合并到主分支
|
|
||||||
|
|
||||||
## 如何成为贡献者
|
|
||||||
|
|
||||||
我们欢迎所有形式的贡献!无论是:
|
|
||||||
|
|
||||||
- 🐛 **Bug修复** - 发现并修复问题
|
|
||||||
- ✨ **新功能** - 添加有价值的功能
|
|
||||||
- 📚 **文档改进** - 完善项目文档
|
|
||||||
- 🧪 **测试用例** - 提高代码覆盖率
|
|
||||||
- 🎨 **代码优化** - 改进代码质量
|
|
||||||
- 💡 **建议反馈** - 提出改进建议
|
|
||||||
|
|
||||||
### 贡献流程
|
|
||||||
|
|
||||||
1. Fork 项目到你的Gitea账户
|
|
||||||
2. 创建功能分支:`git checkout -b feature/your-feature`
|
|
||||||
3. 提交你的更改:`git commit -m "feat:添加新功能"`
|
|
||||||
4. 推送到分支:`git push origin feature/your-feature`
|
|
||||||
5. 创建Pull Request
|
|
||||||
|
|
||||||
### 贡献规范
|
|
||||||
|
|
||||||
请在贡献前阅读:
|
|
||||||
- [AI辅助开发规范指南](./docs/AI辅助开发规范指南.md)
|
|
||||||
- [后端开发规范](./docs/backend_development_guide.md)
|
|
||||||
- [Git提交规范](./docs/git_commit_guide.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**再次感谢所有贡献者的辛勤付出!** 🙏
|
|
||||||
|
|
||||||
*如果你的名字没有出现在列表中,请联系我们或提交PR更新此文件。*
|
|
||||||
418
DEPLOYMENT.md
418
DEPLOYMENT.md
@@ -1,418 +0,0 @@
|
|||||||
# 🚀 Whale Town 部署指南
|
|
||||||
|
|
||||||
本文档详细说明如何部署 Whale Town 像素游戏后端服务到生产环境。
|
|
||||||
|
|
||||||
## 📋 前置要求
|
|
||||||
|
|
||||||
### 基础环境
|
|
||||||
- **Node.js** 18+ (推荐 20.x LTS)
|
|
||||||
- **pnpm** 包管理器
|
|
||||||
- **MySQL** 8.0+
|
|
||||||
- **Redis** 6.0+ (可选,支持文件存储模式)
|
|
||||||
- **PM2** 进程管理器(推荐)
|
|
||||||
- **Nginx** 反向代理(推荐)
|
|
||||||
|
|
||||||
### 新增要求 (管理员后台)
|
|
||||||
- **Web服务器** (Nginx/Apache) - 用于前端管理界面
|
|
||||||
- **SSL证书** (推荐) - 保护管理后台安全
|
|
||||||
|
|
||||||
## 部署步骤
|
|
||||||
|
|
||||||
### 1. 服务器环境准备
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 安装 Node.js (使用 NodeSource 仓库)
|
|
||||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
|
||||||
sudo apt-get install -y nodejs
|
|
||||||
|
|
||||||
# 安装 pnpm
|
|
||||||
curl -fsSL https://get.pnpm.io/install.sh | sh
|
|
||||||
source ~/.bashrc
|
|
||||||
|
|
||||||
# 安装 PM2
|
|
||||||
npm install -g pm2
|
|
||||||
|
|
||||||
# 安装 MySQL
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install mysql-server
|
|
||||||
sudo mysql_secure_installation
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 克隆项目
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 创建项目目录
|
|
||||||
sudo mkdir -p /var/www
|
|
||||||
cd /var/www
|
|
||||||
|
|
||||||
# 克隆项目(替换为你的实际仓库地址)
|
|
||||||
git clone https://gitea.xinghangee.icu/datawhale/whale-town-end.git
|
|
||||||
cd whale-town-end
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 配置环境
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 复制环境配置文件
|
|
||||||
cp .env.production.example .env.production
|
|
||||||
|
|
||||||
# 编辑环境配置(填入实际的数据库信息)
|
|
||||||
nano .env.production
|
|
||||||
|
|
||||||
# 复制部署脚本
|
|
||||||
cp deploy.sh.example deploy.sh
|
|
||||||
chmod +x deploy.sh
|
|
||||||
|
|
||||||
# 编辑部署脚本(修改路径配置)
|
|
||||||
nano deploy.sh
|
|
||||||
|
|
||||||
# 复制 webhook 处理器
|
|
||||||
cp webhook-handler.js.example webhook-handler.js
|
|
||||||
|
|
||||||
# 编辑 webhook 处理器(修改密钥和路径)
|
|
||||||
nano webhook-handler.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 数据库设置
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 登录 MySQL
|
|
||||||
sudo mysql -u root -p
|
|
||||||
|
|
||||||
# 创建数据库和用户
|
|
||||||
CREATE DATABASE pixel_game_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
CREATE USER 'pixel_game'@'localhost' IDENTIFIED BY 'your_secure_password';
|
|
||||||
GRANT ALL PRIVILEGES ON pixel_game_db.* TO 'pixel_game'@'localhost';
|
|
||||||
FLUSH PRIVILEGES;
|
|
||||||
EXIT;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 安装依赖和构建
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 安装后端依赖
|
|
||||||
pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# 安装前端依赖 (新增)
|
|
||||||
cd client
|
|
||||||
pnpm install --frozen-lockfile
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# 构建后端
|
|
||||||
pnpm run build
|
|
||||||
|
|
||||||
# 构建前端管理界面 (新增)
|
|
||||||
cd client
|
|
||||||
pnpm run build
|
|
||||||
cd ..
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 启动服务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 使用 PM2 启动应用
|
|
||||||
pm2 start ecosystem.config.js --env production
|
|
||||||
|
|
||||||
# 保存 PM2 配置
|
|
||||||
pm2 save
|
|
||||||
|
|
||||||
# 设置开机自启
|
|
||||||
pm2 startup
|
|
||||||
# 按照提示执行显示的命令
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. 配置 Nginx
|
|
||||||
|
|
||||||
#### 方案一: 分离部署 (推荐)
|
|
||||||
|
|
||||||
创建后端API配置:
|
|
||||||
```bash
|
|
||||||
sudo nano /etc/nginx/sites-available/whale-town-api
|
|
||||||
```
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name api.whaletown.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:3000;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection 'upgrade';
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_cache_bypass $http_upgrade;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
创建前端管理界面配置:
|
|
||||||
```bash
|
|
||||||
sudo nano /etc/nginx/sites-available/whale-town-admin
|
|
||||||
```
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name admin.whaletown.com;
|
|
||||||
root /var/www/whale-town-end/client/dist;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# SPA路由支持
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# API代理
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://api.whaletown.com/;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 静态资源缓存
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
|
||||||
expires 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方案二: 单域名部署
|
|
||||||
|
|
||||||
创建统一配置:
|
|
||||||
```bash
|
|
||||||
sudo nano /etc/nginx/sites-available/whale-town-unified
|
|
||||||
```
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name whaletown.com;
|
|
||||||
|
|
||||||
# API接口
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass http://localhost:3000/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 管理后台
|
|
||||||
location /admin/ {
|
|
||||||
alias /var/www/whale-town-end/client/dist/;
|
|
||||||
try_files $uri $uri/ /admin/index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 主站点 (可选)
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:3000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
启用配置:
|
|
||||||
```bash
|
|
||||||
# 启用站点
|
|
||||||
sudo ln -s /etc/nginx/sites-available/whale-town-* /etc/nginx/sites-enabled/
|
|
||||||
|
|
||||||
# 测试配置
|
|
||||||
sudo nginx -t
|
|
||||||
|
|
||||||
# 重载配置
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔒 SSL证书配置 (推荐)
|
|
||||||
|
|
||||||
### 使用 Let's Encrypt
|
|
||||||
```bash
|
|
||||||
# 安装 Certbot
|
|
||||||
sudo apt install certbot python3-certbot-nginx
|
|
||||||
|
|
||||||
# 为API域名申请证书
|
|
||||||
sudo certbot --nginx -d api.whaletown.com
|
|
||||||
|
|
||||||
# 为管理后台申请证书
|
|
||||||
sudo certbot --nginx -d admin.whaletown.com
|
|
||||||
|
|
||||||
# 设置自动续期
|
|
||||||
sudo crontab -e
|
|
||||||
# 添加: 0 12 * * * /usr/bin/certbot renew --quiet
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎛️ 管理员后台配置
|
|
||||||
|
|
||||||
### 环境变量配置
|
|
||||||
在 `.env.production` 中添加:
|
|
||||||
```bash
|
|
||||||
# 管理员Token配置 (必须)
|
|
||||||
ADMIN_TOKEN_SECRET=your_super_strong_random_secret_at_least_32_chars
|
|
||||||
ADMIN_TOKEN_TTL_SECONDS=28800
|
|
||||||
|
|
||||||
# 首次部署启用管理员引导
|
|
||||||
ADMIN_BOOTSTRAP_ENABLED=true
|
|
||||||
ADMIN_USERNAME=admin
|
|
||||||
ADMIN_PASSWORD=YourStrongPassword123!
|
|
||||||
ADMIN_NICKNAME=系统管理员
|
|
||||||
|
|
||||||
# CORS配置 (如果前后端分离)
|
|
||||||
CORS_ORIGIN=https://admin.whaletown.com
|
|
||||||
```
|
|
||||||
|
|
||||||
### 访问管理后台
|
|
||||||
- **地址**: https://admin.whaletown.com
|
|
||||||
- **默认账号**: admin / YourStrongPassword123!
|
|
||||||
|
|
||||||
**⚠️ 重要**: 首次登录后立即修改密码并关闭引导功能 (`ADMIN_BOOTSTRAP_ENABLED=false`)
|
|
||||||
|
|
||||||
## 📡 Gitea Webhook 配置
|
|
||||||
1. 在 Gitea 仓库中进入 **Settings** → **Webhooks**
|
|
||||||
3. 配置:
|
|
||||||
- **Target URL**: `http://your-server.com:9000/webhook` 或 `http://your-domain.com/webhook`
|
|
||||||
- **HTTP Method**: `POST`
|
|
||||||
- **POST Content Type**: `application/json`
|
|
||||||
- **Secret**: 与 `webhook-handler.js` 中的 `SECRET` 一致
|
|
||||||
- **Trigger On**: 选择 `Push events`
|
|
||||||
- **Branch filter**: `main`
|
|
||||||
|
|
||||||
## ✅ 验证部署
|
|
||||||
|
|
||||||
### 基础服务检查
|
|
||||||
```bash
|
|
||||||
# 检查PM2服务状态
|
|
||||||
pm2 status
|
|
||||||
|
|
||||||
# 检查后端API
|
|
||||||
curl http://localhost:3000/
|
|
||||||
curl http://localhost:3000/api-docs
|
|
||||||
|
|
||||||
# 检查前端管理界面
|
|
||||||
curl -I https://admin.whaletown.com
|
|
||||||
```
|
|
||||||
|
|
||||||
### 管理员后台测试
|
|
||||||
```bash
|
|
||||||
# 测试管理员登录API
|
|
||||||
curl -X POST https://api.whaletown.com/admin/auth/login \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"identifier":"admin","password":"YourStrongPassword123!"}'
|
|
||||||
|
|
||||||
# 访问管理界面
|
|
||||||
# 浏览器打开: https://admin.whaletown.com
|
|
||||||
```
|
|
||||||
|
|
||||||
### 功能验证清单
|
|
||||||
- [ ] 后端API服务正常响应
|
|
||||||
- [ ] API文档可访问
|
|
||||||
- [ ] 前端管理界面加载正常
|
|
||||||
- [ ] 管理员登录功能正常
|
|
||||||
- [ ] 用户管理功能正常
|
|
||||||
- [ ] 日志查看功能正常
|
|
||||||
- [ ] SSL证书配置正确
|
|
||||||
|
|
||||||
## 🔧 常用命令
|
|
||||||
|
|
||||||
### 服务管理
|
|
||||||
```bash
|
|
||||||
# 重启后端服务
|
|
||||||
pm2 restart whale-town-end
|
|
||||||
|
|
||||||
# 重启前端服务 (如果使用PM2托管)
|
|
||||||
pm2 restart whale-town-admin
|
|
||||||
|
|
||||||
# 查看服务日志
|
|
||||||
pm2 logs whale-town-end --lines 100
|
|
||||||
pm2 logs whale-town-admin --lines 100
|
|
||||||
|
|
||||||
# 手动部署
|
|
||||||
bash deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 更新部署
|
|
||||||
```bash
|
|
||||||
# 更新后端
|
|
||||||
git pull origin main
|
|
||||||
pnpm install
|
|
||||||
pnpm run build
|
|
||||||
pm2 reload whale-town-end
|
|
||||||
|
|
||||||
# 更新前端管理界面
|
|
||||||
cd client
|
|
||||||
git pull origin main
|
|
||||||
pnpm install
|
|
||||||
pnpm run build
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
cd ..
|
|
||||||
```
|
|
||||||
|
|
||||||
### 日志管理
|
|
||||||
```bash
|
|
||||||
# 查看应用日志
|
|
||||||
tail -f logs/app.log
|
|
||||||
|
|
||||||
# 查看管理员操作日志
|
|
||||||
tail -f logs/admin.log
|
|
||||||
|
|
||||||
# 查看Nginx日志
|
|
||||||
sudo tail -f /var/log/nginx/access.log
|
|
||||||
sudo tail -f /var/log/nginx/error.log
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚨 故障排除
|
|
||||||
|
|
||||||
### 后端服务问题
|
|
||||||
**服务无法启动**
|
|
||||||
- 检查环境变量配置 (`cat .env.production`)
|
|
||||||
- 检查数据库连接 (`mysql -u pixel_game -p`)
|
|
||||||
- 查看PM2日志 (`pm2 logs whale-town-end`)
|
|
||||||
- 检查端口占用 (`netstat -tlnp | grep 3000`)
|
|
||||||
|
|
||||||
**管理员登录失败**
|
|
||||||
- 验证 `ADMIN_TOKEN_SECRET` 配置
|
|
||||||
- 检查管理员账号是否创建
|
|
||||||
- 查看后端错误日志
|
|
||||||
- 确认密码复杂度要求
|
|
||||||
|
|
||||||
### 前端管理界面问题
|
|
||||||
**界面无法访问**
|
|
||||||
- 检查前端构建是否成功 (`ls -la client/dist/`)
|
|
||||||
- 验证Nginx配置 (`sudo nginx -t`)
|
|
||||||
- 检查域名解析
|
|
||||||
- 查看Nginx错误日志
|
|
||||||
|
|
||||||
**API请求失败**
|
|
||||||
- 检查CORS配置
|
|
||||||
- 验证API代理设置
|
|
||||||
- 确认后端服务状态
|
|
||||||
- 检查防火墙规则
|
|
||||||
|
|
||||||
### 数据库连接问题
|
|
||||||
**连接失败**
|
|
||||||
- 检查MySQL服务状态 (`sudo systemctl status mysql`)
|
|
||||||
- 验证数据库用户权限
|
|
||||||
- 检查网络连接
|
|
||||||
- 确认数据库配置
|
|
||||||
|
|
||||||
### SSL证书问题
|
|
||||||
**证书验证失败**
|
|
||||||
- 检查证书有效期 (`sudo certbot certificates`)
|
|
||||||
- 验证域名解析
|
|
||||||
- 重新申请证书 (`sudo certbot --nginx -d your-domain.com`)
|
|
||||||
|
|
||||||
### 性能问题
|
|
||||||
**响应缓慢**
|
|
||||||
- 检查系统资源使用 (`htop`, `df -h`)
|
|
||||||
- 优化数据库查询
|
|
||||||
- 配置Redis缓存
|
|
||||||
- 启用Nginx压缩
|
|
||||||
|
|
||||||
### 日志文件过大
|
|
||||||
**磁盘空间不足**
|
|
||||||
- 配置日志轮转 (`sudo nano /etc/logrotate.d/whale-town`)
|
|
||||||
- 清理旧日志文件
|
|
||||||
- 监控磁盘使用情况
|
|
||||||
138
TESTING.md
138
TESTING.md
@@ -1,138 +0,0 @@
|
|||||||
# 测试指南
|
|
||||||
|
|
||||||
本项目支持**无数据库和无邮件服务器**的测试模式,让你可以快速验证所有功能!
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
|
||||||
|
|
||||||
### 1. 环境配置
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 复制环境配置文件
|
|
||||||
cp .env.example .env
|
|
||||||
```
|
|
||||||
|
|
||||||
默认配置已经设置为测试模式,无需修改即可使用。
|
|
||||||
|
|
||||||
### 2. 启动服务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 安装依赖
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# 启动开发服务器
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 运行测试
|
|
||||||
|
|
||||||
**Windows (PowerShell):**
|
|
||||||
```powershell
|
|
||||||
.\test-api.ps1
|
|
||||||
```
|
|
||||||
|
|
||||||
**Linux/macOS:**
|
|
||||||
```bash
|
|
||||||
./test-api.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**自定义参数:**
|
|
||||||
```bash
|
|
||||||
# Windows
|
|
||||||
.\test-api.ps1 -BaseUrl "http://localhost:3000" -TestEmail "custom@example.com"
|
|
||||||
|
|
||||||
# Linux/macOS
|
|
||||||
./test-api.sh "http://localhost:3000" "custom@example.com"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 测试功能
|
|
||||||
|
|
||||||
测试脚本会验证以下功能:
|
|
||||||
|
|
||||||
- ✅ **邮箱验证码发送** - 生成6位数验证码
|
|
||||||
- ✅ **邮箱验证码验证** - 验证码校验和清理
|
|
||||||
- ✅ **用户注册** - 完整的用户注册流程
|
|
||||||
- ✅ **用户登录** - 用户名/邮箱/手机号登录
|
|
||||||
|
|
||||||
## 🔧 测试模式特性
|
|
||||||
|
|
||||||
- 🗄️ **Redis 文件存储** - 使用 `redis-data/redis.json` 存储验证码
|
|
||||||
- 📧 **邮件测试模式** - 邮件内容输出到控制台,无需真实SMTP
|
|
||||||
- 💾 **内存用户存储** - 无需数据库,用户数据存储在内存中
|
|
||||||
- 🔄 **自动切换** - 根据配置自动选择存储模式
|
|
||||||
|
|
||||||
## 📊 单元测试
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 运行所有单元测试
|
|
||||||
npm test
|
|
||||||
|
|
||||||
# 监听模式
|
|
||||||
npm run test:watch
|
|
||||||
|
|
||||||
# 生成覆盖率报告
|
|
||||||
npm run test:cov
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🌐 生产环境配置
|
|
||||||
|
|
||||||
要切换到生产环境,编辑 `.env` 文件:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 启用数据库(取消注释并填入真实数据)
|
|
||||||
DB_HOST=your_mysql_host
|
|
||||||
DB_PORT=3306
|
|
||||||
DB_USERNAME=your_db_username
|
|
||||||
DB_PASSWORD=your_db_password
|
|
||||||
DB_NAME=your_db_name
|
|
||||||
|
|
||||||
# 启用真实Redis(取消注释并设置)
|
|
||||||
USE_FILE_REDIS=false
|
|
||||||
REDIS_HOST=your_redis_host
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_PASSWORD=your_redis_password
|
|
||||||
|
|
||||||
# 启用邮件服务(取消注释并填入真实数据)
|
|
||||||
EMAIL_HOST=smtp.gmail.com
|
|
||||||
EMAIL_PORT=587
|
|
||||||
EMAIL_USER=your_email@gmail.com
|
|
||||||
EMAIL_PASS=your_app_password
|
|
||||||
EMAIL_FROM="Whale Town Game" <noreply@whaletown.com>
|
|
||||||
|
|
||||||
# 生产环境设置
|
|
||||||
NODE_ENV=production
|
|
||||||
LOG_LEVEL=info
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔍 故障排除
|
|
||||||
|
|
||||||
### 服务启动失败
|
|
||||||
- 检查端口3000是否被占用
|
|
||||||
- 确认Node.js版本 >= 18.0.0
|
|
||||||
- 运行 `npm install` 重新安装依赖
|
|
||||||
|
|
||||||
### 测试脚本执行失败
|
|
||||||
- 确认服务器正在运行
|
|
||||||
- 检查防火墙设置
|
|
||||||
- 在Linux/macOS上确保脚本有执行权限:`chmod +x test-api.sh`
|
|
||||||
|
|
||||||
### Redis文件存储问题
|
|
||||||
- 检查 `redis-data` 目录权限
|
|
||||||
- 确认 `USE_FILE_REDIS=true` 设置正确
|
|
||||||
|
|
||||||
### 邮件测试模式问题
|
|
||||||
- 确认邮件配置为注释状态
|
|
||||||
- 检查服务器控制台日志输出
|
|
||||||
|
|
||||||
## 📝 测试数据
|
|
||||||
|
|
||||||
测试完成后,你可以查看:
|
|
||||||
|
|
||||||
- `redis-data/redis.json` - 验证码存储数据
|
|
||||||
- 服务器控制台 - 邮件内容输出
|
|
||||||
- 测试脚本输出 - API响应结果
|
|
||||||
|
|
||||||
## 🎯 下一步
|
|
||||||
|
|
||||||
- 查看 [API 文档](http://localhost:3000/api-docs) 了解更多接口
|
|
||||||
- 阅读 [开发规范](./docs/backend_development_guide.md) 开始开发
|
|
||||||
- 使用 [AI 辅助指南](./docs/AI辅助开发规范指南.md) 提高开发效率
|
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
"@nestjs/platform-socket.io": "^10.4.20",
|
"@nestjs/platform-socket.io": "^10.4.20",
|
||||||
"@nestjs/schedule": "^4.1.2",
|
"@nestjs/schedule": "^4.1.2",
|
||||||
"@nestjs/swagger": "^11.2.3",
|
"@nestjs/swagger": "^11.2.3",
|
||||||
|
"@nestjs/throttler": "^6.5.0",
|
||||||
"@nestjs/typeorm": "^11.0.0",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@nestjs/websockets": "^10.4.20",
|
"@nestjs/websockets": "^10.4.20",
|
||||||
"@types/archiver": "^7.0.0",
|
"@types/archiver": "^7.0.0",
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* 管理员相关 DTO
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 定义管理员登录与用户密码重置的请求结构
|
|
||||||
* - 使用 class-validator 进行参数校验
|
|
||||||
*
|
|
||||||
* @author jianuo
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsNotEmpty, IsString, MinLength } from 'class-validator';
|
|
||||||
|
|
||||||
export class AdminLoginDto {
|
|
||||||
@ApiProperty({ description: '登录标识符(用户名/邮箱/手机号)', example: 'admin' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
identifier: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '密码', example: 'Admin123456' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminResetPasswordDto {
|
|
||||||
@ApiProperty({ description: '新密码(至少8位,包含字母和数字)', example: 'NewPass1234' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
@MinLength(8)
|
|
||||||
new_password: string;
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
/**
|
|
||||||
* 管理员相关响应 DTO
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 为 Swagger 提供明确的响应结构定义
|
|
||||||
* - 与 AdminService 返回结构保持一致
|
|
||||||
*
|
|
||||||
* @author jianuo
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
class AdminInfoDto {
|
|
||||||
@ApiProperty({ example: '1' })
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'admin' })
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '管理员' })
|
|
||||||
nickname: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 9 })
|
|
||||||
role: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminLoginDataDto {
|
|
||||||
@ApiProperty({ type: AdminInfoDto })
|
|
||||||
admin: AdminInfoDto;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '管理员访问Token(用于Authorization Bearer)' })
|
|
||||||
access_token: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '过期时间戳(毫秒)', example: 1766102400000 })
|
|
||||||
expires_at: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminLoginResponseDto {
|
|
||||||
@ApiProperty({ example: true })
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ type: AdminLoginDataDto, required: false })
|
|
||||||
data?: AdminLoginDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '管理员登录成功' })
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: 'ADMIN_LOGIN_FAILED' })
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminUserDto {
|
|
||||||
@ApiProperty({ example: '1' })
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'user1' })
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '小明' })
|
|
||||||
nickname: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: 'user1@example.com', nullable: true })
|
|
||||||
email?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: false })
|
|
||||||
email_verified: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: '+8613800138000', nullable: true })
|
|
||||||
phone?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: 'https://example.com/avatar.png', nullable: true })
|
|
||||||
avatar_url?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 1 })
|
|
||||||
role: number;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '2025-12-19T00:00:00.000Z' })
|
|
||||||
created_at: Date;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '2025-12-19T00:00:00.000Z' })
|
|
||||||
updated_at: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminUsersDataDto {
|
|
||||||
@ApiProperty({ type: [AdminUserDto] })
|
|
||||||
users: AdminUserDto[];
|
|
||||||
|
|
||||||
@ApiProperty({ example: 100 })
|
|
||||||
limit: number;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 0 })
|
|
||||||
offset: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminUsersResponseDto {
|
|
||||||
@ApiProperty({ example: true })
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ type: AdminUsersDataDto, required: false })
|
|
||||||
data?: AdminUsersDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '用户列表获取成功' })
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: 'ADMIN_USERS_FAILED' })
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminUserDataDto {
|
|
||||||
@ApiProperty({ type: AdminUserDto })
|
|
||||||
user: AdminUserDto;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminUserResponseDto {
|
|
||||||
@ApiProperty({ example: true })
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ type: AdminUserDataDto, required: false })
|
|
||||||
data?: AdminUserDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '用户信息获取成功' })
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminCommonResponseDto {
|
|
||||||
@ApiProperty({ example: true })
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
data?: any;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '密码重置成功' })
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: 'ADMIN_OPERATION_FAILED' })
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AdminRuntimeLogsDataDto {
|
|
||||||
@ApiProperty({ example: 'dev.log' })
|
|
||||||
file: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '日志文件最后更新时间(ISO)', example: '2025-12-19T19:10:15.000Z' })
|
|
||||||
updated_at: string;
|
|
||||||
|
|
||||||
@ApiProperty({ type: [String], description: '日志行(按时间顺序,越靠后越新)' })
|
|
||||||
lines: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminRuntimeLogsResponseDto {
|
|
||||||
@ApiProperty({ example: true })
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ type: AdminRuntimeLogsDataDto, required: false })
|
|
||||||
data?: AdminRuntimeLogsDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '运行日志获取成功' })
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, example: 'ADMIN_OPERATION_FAILED' })
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* 应用状态响应 DTO
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 定义应用状态接口的响应格式
|
|
||||||
* - 提供 Swagger 文档生成支持
|
|
||||||
*
|
|
||||||
* @author angjustinl
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-17
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 应用状态响应 DTO
|
|
||||||
*/
|
|
||||||
export class AppStatusResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '服务名称',
|
|
||||||
example: 'Pixel Game Server',
|
|
||||||
type: String
|
|
||||||
})
|
|
||||||
service: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '服务版本',
|
|
||||||
example: '1.0.0',
|
|
||||||
type: String
|
|
||||||
})
|
|
||||||
version: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '运行状态',
|
|
||||||
example: 'running',
|
|
||||||
enum: ['running', 'starting', 'stopping', 'error'],
|
|
||||||
type: String
|
|
||||||
})
|
|
||||||
status: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '当前时间戳',
|
|
||||||
example: '2025-12-17T15:00:00.000Z',
|
|
||||||
type: String,
|
|
||||||
format: 'date-time'
|
|
||||||
})
|
|
||||||
timestamp: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '运行时间(秒)',
|
|
||||||
example: 3600,
|
|
||||||
type: Number,
|
|
||||||
minimum: 0
|
|
||||||
})
|
|
||||||
uptime: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '运行环境',
|
|
||||||
example: 'development',
|
|
||||||
enum: ['development', 'production', 'test'],
|
|
||||||
type: String
|
|
||||||
})
|
|
||||||
environment: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '存储模式',
|
|
||||||
example: 'memory',
|
|
||||||
enum: ['database', 'memory'],
|
|
||||||
type: String
|
|
||||||
})
|
|
||||||
storage_mode: 'database' | 'memory';
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/**
|
|
||||||
* 通用错误响应 DTO
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 定义统一的错误响应格式
|
|
||||||
* - 提供 Swagger 文档生成支持
|
|
||||||
*
|
|
||||||
* @author angjustinl
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-17
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用错误响应 DTO
|
|
||||||
*/
|
|
||||||
export class ErrorResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'HTTP 状态码',
|
|
||||||
example: 500,
|
|
||||||
type: Number
|
|
||||||
})
|
|
||||||
statusCode: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误消息',
|
|
||||||
example: 'Internal server error',
|
|
||||||
type: String
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误发生时间',
|
|
||||||
example: '2025-12-17T15:00:00.000Z',
|
|
||||||
type: String,
|
|
||||||
format: 'date-time'
|
|
||||||
})
|
|
||||||
timestamp: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求路径',
|
|
||||||
example: '/api/status',
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
path?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'INTERNAL_ERROR',
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error?: string;
|
|
||||||
}
|
|
||||||
@@ -1,374 +0,0 @@
|
|||||||
/**
|
|
||||||
* 登录业务数据传输对象
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 定义登录相关API的请求数据结构
|
|
||||||
* - 提供数据验证规则和错误提示
|
|
||||||
* - 确保API接口的数据格式一致性
|
|
||||||
*
|
|
||||||
* @author moyin
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-17
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
IsString,
|
|
||||||
IsEmail,
|
|
||||||
IsPhoneNumber,
|
|
||||||
IsNotEmpty,
|
|
||||||
Length,
|
|
||||||
IsOptional,
|
|
||||||
Matches,
|
|
||||||
IsNumberString
|
|
||||||
} from 'class-validator';
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录请求DTO
|
|
||||||
*/
|
|
||||||
export class LoginDto {
|
|
||||||
/**
|
|
||||||
* 登录标识符
|
|
||||||
* 支持用户名、邮箱或手机号登录
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '登录标识符,支持用户名、邮箱或手机号',
|
|
||||||
example: 'testuser',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 100
|
|
||||||
})
|
|
||||||
@IsString({ message: '登录标识符必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '登录标识符不能为空' })
|
|
||||||
@Length(1, 100, { message: '登录标识符长度需在1-100字符之间' })
|
|
||||||
identifier: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户密码',
|
|
||||||
example: 'password123',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 128
|
|
||||||
})
|
|
||||||
@IsString({ message: '密码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '密码不能为空' })
|
|
||||||
@Length(1, 128, { message: '密码长度需在1-128字符之间' })
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册请求DTO
|
|
||||||
*/
|
|
||||||
export class RegisterDto {
|
|
||||||
/**
|
|
||||||
* 用户名
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户名,只能包含字母、数字和下划线',
|
|
||||||
example: 'testuser',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 50,
|
|
||||||
pattern: '^[a-zA-Z0-9_]+$'
|
|
||||||
})
|
|
||||||
@IsString({ message: '用户名必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '用户名不能为空' })
|
|
||||||
@Length(1, 50, { message: '用户名长度需在1-50字符之间' })
|
|
||||||
@Matches(/^[a-zA-Z0-9_]+$/, { message: '用户名只能包含字母、数字和下划线' })
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '密码,必须包含字母和数字,长度8-128字符',
|
|
||||||
example: 'password123',
|
|
||||||
minLength: 8,
|
|
||||||
maxLength: 128
|
|
||||||
})
|
|
||||||
@IsString({ message: '密码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '密码不能为空' })
|
|
||||||
@Length(8, 128, { message: '密码长度需在8-128字符之间' })
|
|
||||||
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '密码必须包含字母和数字' })
|
|
||||||
password: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 昵称
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户昵称',
|
|
||||||
example: '测试用户',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 50
|
|
||||||
})
|
|
||||||
@IsString({ message: '昵称必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '昵称不能为空' })
|
|
||||||
@Length(1, 50, { message: '昵称长度需在1-50字符之间' })
|
|
||||||
nickname: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮箱(可选)
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱地址(可选)',
|
|
||||||
example: 'test@example.com',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsEmail({}, { message: '邮箱格式不正确' })
|
|
||||||
email?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手机号(可选)
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '手机号码(可选)',
|
|
||||||
example: '+8613800138000',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsPhoneNumber(null, { message: '手机号格式不正确' })
|
|
||||||
phone?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮箱验证码(当提供邮箱时必填)
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱验证码,当提供邮箱时必填',
|
|
||||||
example: '123456',
|
|
||||||
pattern: '^\\d{6}$',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ message: '验证码必须是字符串' })
|
|
||||||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
|
||||||
email_verification_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GitHub OAuth登录请求DTO
|
|
||||||
*/
|
|
||||||
export class GitHubOAuthDto {
|
|
||||||
/**
|
|
||||||
* GitHub用户ID
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'GitHub用户ID',
|
|
||||||
example: '12345678',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 100
|
|
||||||
})
|
|
||||||
@IsString({ message: 'GitHub ID必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: 'GitHub ID不能为空' })
|
|
||||||
@Length(1, 100, { message: 'GitHub ID长度需在1-100字符之间' })
|
|
||||||
github_id: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户名
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'GitHub用户名',
|
|
||||||
example: 'octocat',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 50
|
|
||||||
})
|
|
||||||
@IsString({ message: '用户名必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '用户名不能为空' })
|
|
||||||
@Length(1, 50, { message: '用户名长度需在1-50字符之间' })
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 昵称
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'GitHub显示名称',
|
|
||||||
example: 'The Octocat',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 50
|
|
||||||
})
|
|
||||||
@IsString({ message: '昵称必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '昵称不能为空' })
|
|
||||||
@Length(1, 50, { message: '昵称长度需在1-50字符之间' })
|
|
||||||
nickname: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮箱(可选)
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'GitHub邮箱地址(可选)',
|
|
||||||
example: 'octocat@github.com',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsEmail({}, { message: '邮箱格式不正确' })
|
|
||||||
email?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 头像URL(可选)
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'GitHub头像URL(可选)',
|
|
||||||
example: 'https://github.com/images/error/octocat_happy.gif',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ message: '头像URL必须是字符串' })
|
|
||||||
avatar_url?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 忘记密码请求DTO
|
|
||||||
*/
|
|
||||||
export class ForgotPasswordDto {
|
|
||||||
/**
|
|
||||||
* 邮箱或手机号
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱或手机号',
|
|
||||||
example: 'test@example.com',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 100
|
|
||||||
})
|
|
||||||
@IsString({ message: '标识符必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '邮箱或手机号不能为空' })
|
|
||||||
@Length(1, 100, { message: '标识符长度需在1-100字符之间' })
|
|
||||||
identifier: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重置密码请求DTO
|
|
||||||
*/
|
|
||||||
export class ResetPasswordDto {
|
|
||||||
/**
|
|
||||||
* 邮箱或手机号
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱或手机号',
|
|
||||||
example: 'test@example.com',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 100
|
|
||||||
})
|
|
||||||
@IsString({ message: '标识符必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '邮箱或手机号不能为空' })
|
|
||||||
@Length(1, 100, { message: '标识符长度需在1-100字符之间' })
|
|
||||||
identifier: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '6位数字验证码',
|
|
||||||
example: '123456',
|
|
||||||
pattern: '^\\d{6}$'
|
|
||||||
})
|
|
||||||
@IsString({ message: '验证码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '验证码不能为空' })
|
|
||||||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
|
||||||
verification_code: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新密码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '新密码,必须包含字母和数字,长度8-128字符',
|
|
||||||
example: 'newpassword123',
|
|
||||||
minLength: 8,
|
|
||||||
maxLength: 128
|
|
||||||
})
|
|
||||||
@IsString({ message: '新密码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '新密码不能为空' })
|
|
||||||
@Length(8, 128, { message: '新密码长度需在8-128字符之间' })
|
|
||||||
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '新密码必须包含字母和数字' })
|
|
||||||
new_password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改密码请求DTO
|
|
||||||
*/
|
|
||||||
export class ChangePasswordDto {
|
|
||||||
/**
|
|
||||||
* 用户ID
|
|
||||||
* 实际应用中应从JWT令牌中获取,这里为了演示放在请求体中
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户ID(实际应用中应从JWT令牌中获取)',
|
|
||||||
example: '1'
|
|
||||||
})
|
|
||||||
@IsNumberString({}, { message: '用户ID必须是数字字符串' })
|
|
||||||
@IsNotEmpty({ message: '用户ID不能为空' })
|
|
||||||
user_id: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 旧密码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '当前密码',
|
|
||||||
example: 'oldpassword123',
|
|
||||||
minLength: 1,
|
|
||||||
maxLength: 128
|
|
||||||
})
|
|
||||||
@IsString({ message: '旧密码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '旧密码不能为空' })
|
|
||||||
@Length(1, 128, { message: '旧密码长度需在1-128字符之间' })
|
|
||||||
old_password: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新密码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '新密码,必须包含字母和数字,长度8-128字符',
|
|
||||||
example: 'newpassword123',
|
|
||||||
minLength: 8,
|
|
||||||
maxLength: 128
|
|
||||||
})
|
|
||||||
@IsString({ message: '新密码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '新密码不能为空' })
|
|
||||||
@Length(8, 128, { message: '新密码长度需在8-128字符之间' })
|
|
||||||
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '新密码必须包含字母和数字' })
|
|
||||||
new_password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮箱验证请求DTO
|
|
||||||
*/
|
|
||||||
export class EmailVerificationDto {
|
|
||||||
/**
|
|
||||||
* 邮箱地址
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱地址',
|
|
||||||
example: 'test@example.com'
|
|
||||||
})
|
|
||||||
@IsEmail({}, { message: '邮箱格式不正确' })
|
|
||||||
@IsNotEmpty({ message: '邮箱不能为空' })
|
|
||||||
email: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '6位数字验证码',
|
|
||||||
example: '123456',
|
|
||||||
pattern: '^\\d{6}$'
|
|
||||||
})
|
|
||||||
@IsString({ message: '验证码必须是字符串' })
|
|
||||||
@IsNotEmpty({ message: '验证码不能为空' })
|
|
||||||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
|
||||||
verification_code: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送邮箱验证码请求DTO
|
|
||||||
*/
|
|
||||||
export class SendEmailVerificationDto {
|
|
||||||
/**
|
|
||||||
* 邮箱地址
|
|
||||||
*/
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱地址',
|
|
||||||
example: 'test@example.com'
|
|
||||||
})
|
|
||||||
@IsEmail({}, { message: '邮箱格式不正确' })
|
|
||||||
@IsNotEmpty({ message: '邮箱不能为空' })
|
|
||||||
email: string;
|
|
||||||
}
|
|
||||||
@@ -1,395 +0,0 @@
|
|||||||
/**
|
|
||||||
* 登录业务响应数据传输对象
|
|
||||||
*
|
|
||||||
* 功能描述:
|
|
||||||
* - 定义登录相关API的响应数据结构
|
|
||||||
* - 提供Swagger文档生成支持
|
|
||||||
* - 确保API响应的数据格式一致性
|
|
||||||
*
|
|
||||||
* @author moyin
|
|
||||||
* @version 1.0.0
|
|
||||||
* @since 2025-12-17
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户信息响应DTO
|
|
||||||
*/
|
|
||||||
export class UserInfoDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户ID',
|
|
||||||
example: '1'
|
|
||||||
})
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户名',
|
|
||||||
example: 'testuser'
|
|
||||||
})
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户昵称',
|
|
||||||
example: '测试用户'
|
|
||||||
})
|
|
||||||
nickname: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '邮箱地址',
|
|
||||||
example: 'test@example.com',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
email?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '手机号码',
|
|
||||||
example: '+8613800138000',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
phone?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '头像URL',
|
|
||||||
example: 'https://example.com/avatar.jpg',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
avatar_url?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户角色',
|
|
||||||
example: 1
|
|
||||||
})
|
|
||||||
role: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '创建时间',
|
|
||||||
example: '2025-12-17T10:00:00.000Z'
|
|
||||||
})
|
|
||||||
created_at: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录响应数据DTO
|
|
||||||
*/
|
|
||||||
export class LoginResponseDataDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '用户信息',
|
|
||||||
type: UserInfoDto
|
|
||||||
})
|
|
||||||
user: UserInfoDto;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '访问令牌',
|
|
||||||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
|
||||||
})
|
|
||||||
access_token: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '刷新令牌',
|
|
||||||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
refresh_token?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '是否为新用户',
|
|
||||||
example: false,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
is_new_user?: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '登录成功'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录响应DTO
|
|
||||||
*/
|
|
||||||
export class LoginResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功',
|
|
||||||
example: true
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应数据',
|
|
||||||
type: LoginResponseDataDto,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
data?: LoginResponseDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '登录成功'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'LOGIN_FAILED',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册响应DTO
|
|
||||||
*/
|
|
||||||
export class RegisterResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功',
|
|
||||||
example: true
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应数据',
|
|
||||||
type: LoginResponseDataDto,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
data?: LoginResponseDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '注册成功'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'REGISTER_FAILED',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GitHub OAuth响应DTO
|
|
||||||
*/
|
|
||||||
export class GitHubOAuthResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功',
|
|
||||||
example: true
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应数据',
|
|
||||||
type: LoginResponseDataDto,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
data?: LoginResponseDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: 'GitHub登录成功'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'GITHUB_OAUTH_FAILED',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 忘记密码响应数据DTO
|
|
||||||
*/
|
|
||||||
export class ForgotPasswordResponseDataDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '验证码(仅用于演示,实际应用中不应返回)',
|
|
||||||
example: '123456',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
verification_code?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '是否为测试模式',
|
|
||||||
example: true,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
is_test_mode?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 忘记密码响应DTO
|
|
||||||
*/
|
|
||||||
export class ForgotPasswordResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功',
|
|
||||||
example: false,
|
|
||||||
examples: {
|
|
||||||
success: {
|
|
||||||
summary: '真实发送成功',
|
|
||||||
value: true
|
|
||||||
},
|
|
||||||
testMode: {
|
|
||||||
summary: '测试模式',
|
|
||||||
value: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应数据',
|
|
||||||
type: ForgotPasswordResponseDataDto,
|
|
||||||
required: false,
|
|
||||||
examples: {
|
|
||||||
success: {
|
|
||||||
summary: '真实发送成功',
|
|
||||||
value: {
|
|
||||||
verification_code: '123456',
|
|
||||||
is_test_mode: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
testMode: {
|
|
||||||
summary: '测试模式',
|
|
||||||
value: {
|
|
||||||
verification_code: '059174',
|
|
||||||
is_test_mode: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
data?: ForgotPasswordResponseDataDto;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。',
|
|
||||||
examples: {
|
|
||||||
success: {
|
|
||||||
summary: '真实发送成功',
|
|
||||||
value: '验证码已发送,请查收'
|
|
||||||
},
|
|
||||||
testMode: {
|
|
||||||
summary: '测试模式',
|
|
||||||
value: '⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'TEST_MODE_ONLY',
|
|
||||||
examples: {
|
|
||||||
success: {
|
|
||||||
summary: '真实发送成功',
|
|
||||||
value: null
|
|
||||||
},
|
|
||||||
testMode: {
|
|
||||||
summary: '测试模式',
|
|
||||||
value: 'TEST_MODE_ONLY'
|
|
||||||
},
|
|
||||||
failed: {
|
|
||||||
summary: '发送失败',
|
|
||||||
value: 'SEND_CODE_FAILED'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用响应DTO(用于重置密码、修改密码等)
|
|
||||||
*/
|
|
||||||
export class CommonResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功',
|
|
||||||
example: true
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '操作成功'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'OPERATION_FAILED',
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试模式邮件验证码响应DTO by angjustinl 2025-12-17
|
|
||||||
*/
|
|
||||||
export class TestModeEmailVerificationResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功(测试模式下为false)',
|
|
||||||
example: false
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应数据',
|
|
||||||
example: {
|
|
||||||
verification_code: '059174',
|
|
||||||
is_test_mode: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
data: {
|
|
||||||
verification_code: string;
|
|
||||||
is_test_mode: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: 'TEST_MODE_ONLY'
|
|
||||||
})
|
|
||||||
error_code: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成功发送邮件验证码响应DTO
|
|
||||||
*/
|
|
||||||
export class SuccessEmailVerificationResponseDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: '请求是否成功',
|
|
||||||
example: true
|
|
||||||
})
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应数据',
|
|
||||||
example: {
|
|
||||||
verification_code: '123456',
|
|
||||||
is_test_mode: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
data: {
|
|
||||||
verification_code: string;
|
|
||||||
is_test_mode: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '响应消息',
|
|
||||||
example: '验证码已发送,请查收'
|
|
||||||
})
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: '错误代码',
|
|
||||||
example: null,
|
|
||||||
required: false
|
|
||||||
})
|
|
||||||
error_code?: string;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user