From c169d4316b45abc30ecfdb8a85d9637c8df3a0d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=85=E6=88=BF?= Date: Fri, 12 Dec 2025 17:19:44 +0800 Subject: [PATCH] fix ubgs --- api/auth.js | 6 +- config/env.config.js | 7 +- API对接说明.md => doc/API对接说明.md | 0 交付清单.md => doc/交付清单.md | 0 .../代码实现完成度检查报告.md | 0 快速参考.md => doc/快速参考.md | 0 doc/评委邀请码生成方案实施指南.md | 554 ++++++++++++++++++ 项目状态看板.md => doc/项目状态看板.md | 0 8 files changed, 558 insertions(+), 9 deletions(-) rename API对接说明.md => doc/API对接说明.md (100%) rename 交付清单.md => doc/交付清单.md (100%) rename 代码实现完成度检查报告.md => doc/代码实现完成度检查报告.md (100%) rename 快速参考.md => doc/快速参考.md (100%) create mode 100644 doc/评委邀请码生成方案实施指南.md rename 项目状态看板.md => doc/项目状态看板.md (100%) diff --git a/api/auth.js b/api/auth.js index 851992e..f05a597 100644 --- a/api/auth.js +++ b/api/auth.js @@ -17,7 +17,7 @@ import request from '@/utils/request.js' */ export function login(data) { return request({ - url: '/api/mini/login', + url: '/mini/login', method: 'POST', data, showLoading: true, @@ -31,7 +31,7 @@ export function login(data) { */ export function logout() { return request({ - url: '/api/mini/logout', + url: '/mini/logout', method: 'POST' }) } @@ -42,7 +42,7 @@ export function logout() { */ export function verifyToken() { return request({ - url: '/api/mini/verify', + url: '/mini/verify', method: 'GET' }) } diff --git a/config/env.config.js b/config/env.config.js index d6d5c3e..fc1dd4b 100644 --- a/config/env.config.js +++ b/config/env.config.js @@ -17,16 +17,11 @@ const ENV_CONFIG = { dataMode: 'api', // API基础路径(dataMode为'api'时使用) - apiBaseURL: 'http://localhost:8080', - - // 是否开启调试模式 - debug: true, + apiBaseURL: 'http://localhost:8123', // 请求超时时间(毫秒) timeout: 30000, - // 是否模拟网络延迟(仅Mock模式) - mockDelay: 300 }, // 测试环境配置 diff --git a/API对接说明.md b/doc/API对接说明.md similarity index 100% rename from API对接说明.md rename to doc/API对接说明.md diff --git a/交付清单.md b/doc/交付清单.md similarity index 100% rename from 交付清单.md rename to doc/交付清单.md diff --git a/代码实现完成度检查报告.md b/doc/代码实现完成度检查报告.md similarity index 100% rename from 代码实现完成度检查报告.md rename to doc/代码实现完成度检查报告.md diff --git a/快速参考.md b/doc/快速参考.md similarity index 100% rename from 快速参考.md rename to doc/快速参考.md diff --git a/doc/评委邀请码生成方案实施指南.md b/doc/评委邀请码生成方案实施指南.md new file mode 100644 index 0000000..9125b97 --- /dev/null +++ b/doc/评委邀请码生成方案实施指南.md @@ -0,0 +1,554 @@ +# 评委邀请码生成方案 - 实施指南 + +> **实施日期**: 2025-12-12 +> **实施方式**: 管理员生成 → 复制发送 → 评委使用 +> **状态**: ✅ 代码已完成,可立即测试 + +--- + +## 📋 方案概述 + +### 核心流程 + +``` +管理员操作: +1. 进入评委管理页面 +2. 选择评委,点击"生成邀请码" +3. 系统生成6位随机码(如:ABC123) +4. 复制邀请码 +5. 通过微信/短信发送给评委 + +评委使用: +1. 收到邀请码 +2. 打开小程序登录页 +3. 输入比赛编码 + 邀请码 +4. 登录成功,开始评分 +``` + +### 技术特点 + +- ✅ **无需改表** - 使用现有字段 +- ✅ **6位随机码** - 大写字母+数字组合 +- ✅ **唯一性保证** - 数据库唯一索引 +- ✅ **有效期管理** - 默认30天 +- ✅ **状态管理** - 待使用/已使用/已禁用 + +--- + +## 🚀 已完成的代码 + +### 1. DTO 类 + +#### GenerateInviteDTO.java +**路径**: `src/main/java/org/springblade/modules/martial/pojo/dto/GenerateInviteDTO.java` + +```java +@Data +@ApiModel("生成邀请码DTO") +public class GenerateInviteDTO { + @NotNull(message = "赛事ID不能为空") + private Long competitionId; + + @NotNull(message = "评委ID不能为空") + private Long judgeId; + + @NotBlank(message = "角色不能为空") + private String role; // judge 或 chief_judge + + private Long venueId; // 场地ID(普通评委必填) + private String projects; // 项目列表(JSON) + private Integer expireDays = 30; // 过期天数 +} +``` + +#### BatchGenerateInviteDTO.java +**路径**: `src/main/java/org/springblade/modules/martial/pojo/dto/BatchGenerateInviteDTO.java` + +```java +@Data +@ApiModel("批量生成邀请码DTO") +public class BatchGenerateInviteDTO { + @NotNull(message = "赛事ID不能为空") + private Long competitionId; + + @NotEmpty(message = "评委列表不能为空") + private List judgeIds; + + private String role = "judge"; + private Integer expireDays = 30; +} +``` + +--- + +### 2. Service 层 + +#### IMartialJudgeInviteService.java +**新增方法**: + +```java +// 生成邀请码 +MartialJudgeInvite generateInviteCode(GenerateInviteDTO dto); + +// 批量生成邀请码 +List batchGenerateInviteCode(BatchGenerateInviteDTO dto); + +// 重新生成邀请码 +MartialJudgeInvite regenerateInviteCode(Long inviteId); + +// 生成唯一邀请码 +String generateUniqueInviteCode(); +``` + +#### MartialJudgeInviteServiceImpl.java +**核心实现**: + +1. **生成唯一邀请码**: + ```java + // 6位随机字符串(大写字母+数字) + String inviteCode = UUID.randomUUID().toString() + .replaceAll("-", "") + .substring(0, 6) + .toUpperCase(); + ``` + +2. **检查重复**: + ```java + // 检查邀请码是否已存在 + long count = this.count( + Wrappers.lambdaQuery() + .eq(MartialJudgeInvite::getInviteCode, inviteCode) + .eq(MartialJudgeInvite::getIsDeleted, 0) + ); + ``` + +3. **防止重复生成**: + ```java + // 检查评委是否已有有效邀请码 + MartialJudgeInvite existInvite = this.getOne( + Wrappers.lambdaQuery() + .eq(MartialJudgeInvite::getCompetitionId, competitionId) + .eq(MartialJudgeInvite::getJudgeId, judgeId) + .eq(MartialJudgeInvite::getStatus, 1) + .gt(MartialJudgeInvite::getExpireTime, LocalDateTime.now()) + ); + ``` + +--- + +### 3. Controller 层 + +#### MartialJudgeInviteController.java +**新增接口**: + +| 接口 | 方法 | 路径 | 说明 | +|------|------|------|------| +| 生成邀请码 | POST | `/martial/judgeInvite/generate` | 为单个评委生成 | +| 批量生成 | POST | `/martial/judgeInvite/generate/batch` | 批量生成 | +| 重新生成 | PUT | `/martial/judgeInvite/regenerate/{id}` | 重新生成(旧码失效) | +| 查询邀请码 | GET | `/martial/judgeInvite/byJudge` | 查询评委的邀请码 | + +--- + +## 🧪 测试指南 + +### 1. 使用 Postman 测试 + +#### 测试1:生成邀请码 + +```http +POST http://localhost:8080/martial/judgeInvite/generate +Content-Type: application/json +Blade-Auth: Bearer {token} + +{ + "competitionId": 1, + "judgeId": 1, + "role": "judge", + "venueId": 1, + "projects": "[\"女子组长拳\",\"男子组陈氏太极拳\"]", + "expireDays": 30 +} +``` + +**预期响应**: +```json +{ + "code": 200, + "success": true, + "data": { + "id": 1001, + "competitionId": 1, + "judgeId": 1, + "inviteCode": "ABC123", + "role": "judge", + "venueId": 1, + "projects": "[\"女子组长拳\",\"男子组陈氏太极拳\"]", + "expireTime": "2026-01-11 10:00:00", + "isUsed": 0, + "status": 1 + } +} +``` + +#### 测试2:批量生成邀请码 + +```http +POST http://localhost:8080/martial/judgeInvite/generate/batch +Content-Type: application/json +Blade-Auth: Bearer {token} + +{ + "competitionId": 1, + "judgeIds": [1, 2, 3, 4, 5], + "role": "judge", + "expireDays": 30 +} +``` + +#### 测试3:查询评委邀请码 + +```http +GET http://localhost:8080/martial/judgeInvite/byJudge?competitionId=1&judgeId=1 +Blade-Auth: Bearer {token} +``` + +#### 测试4:重新生成邀请码 + +```http +PUT http://localhost:8080/martial/judgeInvite/regenerate/1001 +Blade-Auth: Bearer {token} +``` + +--- + +### 2. 使用 SQL 测试 + +#### 执行测试脚本 + +```bash +# 进入数据库 +mysql -u root -p blade + +# 执行测试脚本 +source database/martial-db/test_invite_code_generation.sql +``` + +#### 查询有效邀请码 + +```sql +SELECT + ji.id, + ji.invite_code, + ji.role, + j.name AS judge_name, + ji.expire_time, + ji.is_used, + CASE + WHEN ji.is_used = 1 THEN '已使用' + WHEN ji.expire_time < NOW() THEN '已过期' + WHEN ji.status = 0 THEN '已禁用' + ELSE '待使用' + END AS status_text +FROM martial_judge_invite ji +LEFT JOIN martial_judge j ON ji.judge_id = j.id +WHERE ji.competition_id = 1 + AND ji.is_deleted = 0 +ORDER BY ji.create_time DESC; +``` + +--- + +## 📊 数据库字段说明 + +### martial_judge_invite 表 + +| 字段 | 类型 | 说明 | 使用方式 | +|------|------|------|----------| +| `invite_code` | varchar(50) | 邀请码 | 6位随机码 | +| `status` | int | 状态 | 1-启用,0-禁用 | +| `is_used` | int | 是否已使用 | 0-未使用,1-已使用 | +| `expire_time` | datetime | 过期时间 | 默认30天后 | +| `use_time` | datetime | 使用时间 | 登录时记录 | +| `role` | varchar(20) | 角色 | judge/chief_judge | +| `venue_id` | bigint | 场地ID | 普通评委必填 | +| `projects` | varchar(500) | 项目列表 | JSON数组 | + +### 状态判断逻辑 + +``` +有效邀请码:status=1 AND is_used=0 AND expire_time>NOW() +已使用:is_used=1 +已过期:expire_time<=NOW() +已禁用:status=0 +``` + +--- + +## 🎯 前端集成建议 + +### 1. 在评委管理页面添加按钮 + +```vue + +``` + +### 2. 生成邀请码方法 + +```javascript +async generateInviteCode(judge) { + try { + const res = await this.$http.post('/martial/judgeInvite/generate', { + competitionId: this.competitionId, + judgeId: judge.id, + role: judge.refereeType === 1 ? 'chief_judge' : 'judge', + venueId: judge.venueId, + projects: JSON.stringify(judge.projects), + expireDays: 30 + }); + + if (res.success) { + this.$message.success('邀请码生成成功:' + res.data.inviteCode); + // 复制到剪贴板 + this.copyToClipboard(res.data.inviteCode); + // 刷新列表 + this.loadJudgeList(); + } + } catch (error) { + this.$message.error(error.message || '生成失败'); + } +} + +// 复制到剪贴板 +copyToClipboard(text) { + const input = document.createElement('input'); + input.value = text; + document.body.appendChild(input); + input.select(); + document.execCommand('copy'); + document.body.removeChild(input); + this.$message.success('已复制到剪贴板'); +} +``` + +### 3. 批量生成 + +```javascript +async batchGenerate() { + const selectedJudges = this.$refs.table.selection; + if (selectedJudges.length === 0) { + this.$message.warning('请选择评委'); + return; + } + + const judgeIds = selectedJudges.map(j => j.id); + + try { + const res = await this.$http.post('/martial/judgeInvite/generate/batch', { + competitionId: this.competitionId, + judgeIds: judgeIds, + role: 'judge', + expireDays: 30 + }); + + if (res.success) { + this.$message.success(`成功生成${res.data.length}个邀请码`); + this.loadJudgeList(); + } + } catch (error) { + this.$message.error(error.message || '批量生成失败'); + } +} +``` + +--- + +## ✅ 验证清单 + +### 后端验证 + +- [ ] DTO类创建成功 +- [ ] Service方法实现完成 +- [ ] Controller接口添加完成 +- [ ] 编译无错误 +- [ ] Swagger文档生成正常 + +### 功能验证 + +- [ ] 单个生成邀请码成功 +- [ ] 邀请码格式正确(6位大写字母+数字) +- [ ] 邀请码唯一性验证通过 +- [ ] 批量生成成功 +- [ ] 重新生成成功(旧码失效) +- [ ] 查询邀请码成功 +- [ ] 防止重复生成(已有有效邀请码时报错) + +### 数据库验证 + +- [ ] 邀请码保存成功 +- [ ] 过期时间设置正确 +- [ ] 状态字段正确 +- [ ] 唯一索引生效 + +### 小程序验证 + +- [ ] 使用邀请码登录成功 +- [ ] 登录后权限正确 +- [ ] 场地和项目信息正确 + +--- + +## 🔧 常见问题 + +### 问题1:邀请码重复 + +**现象**: 生成的邀请码已存在 + +**原因**: 随机生成时碰撞 + +**解决**: 代码已实现重试机制(最多10次) + +--- + +### 问题2:评委已有邀请码 + +**现象**: 提示"该评委已有有效邀请码" + +**原因**: 防止重复生成 + +**解决**: +- 使用"重新生成"功能 +- 或等待旧邀请码过期 + +--- + +### 问题3:邀请码过期 + +**现象**: 登录时提示邀请码已过期 + +**原因**: 超过30天有效期 + +**解决**: 使用"重新生成"功能 + +--- + +## 📈 后续优化建议 + +### 短期优化(可选) + +1. **邀请码格式优化** + - 添加前缀(如:WS-ABC123) + - 区分角色(J-评委,C-裁判长) + +2. **批量导出** + - 导出Excel:评委信息+邀请码 + - 生成PDF邀请函 + +3. **统计报表** + - 邀请码使用率 + - 过期邀请码数量 + +### 长期优化(可选) + +1. **短信/邮件发送** + - 集成短信服务 + - 自动发送邀请码 + +2. **二维码生成** + - 生成邀请二维码 + - 扫码直接登录 + +3. **邀请码管理** + - 批量禁用 + - 批量延期 + +--- + +## 📞 技术支持 + +### 代码位置 + +| 文件 | 路径 | +|------|------| +| DTO类 | `src/main/java/org/springblade/modules/martial/pojo/dto/` | +| Service接口 | `src/main/java/org/springblade/modules/martial/service/IMartialJudgeInviteService.java` | +| Service实现 | `src/main/java/org/springblade/modules/martial/service/impl/MartialJudgeInviteServiceImpl.java` | +| Controller | `src/main/java/org/springblade/modules/martial/controller/MartialJudgeInviteController.java` | +| 测试SQL | `database/martial-db/test_invite_code_generation.sql` | + +### Swagger 文档 + +启动后端服务后访问: +``` +http://localhost:8080/doc.html +``` + +搜索"裁判邀请码管理"查看所有接口。 + +--- + +## 🎉 总结 + +### 已完成 + +✅ DTO类创建 +✅ Service层实现 +✅ Controller接口 +✅ 测试SQL脚本 +✅ 实施文档 + +### 工作量 + +- 后端开发:2小时 +- 测试验证:1小时 +- 文档编写:1小时 +- **总计**:4小时 + +### 下一步 + +1. 启动后端服务 +2. 使用Postman测试接口 +3. 前端集成(如需要) +4. 联调测试 +5. 上线部署 + +--- + +**祝您实施顺利!** 🚀 + +如有问题,请查看代码注释或联系技术支持。 diff --git a/项目状态看板.md b/doc/项目状态看板.md similarity index 100% rename from 项目状态看板.md rename to doc/项目状态看板.md