Files
martial-admin-mini/doc/评委邀请码生成方案实施指南.md
2025-12-12 17:19:44 +08:00

555 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 评委邀请码生成方案 - 实施指南
> **实施日期**: 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<Long> judgeIds;
private String role = "judge";
private Integer expireDays = 30;
}
```
---
### 2. Service 层
#### IMartialJudgeInviteService.java
**新增方法**:
```java
// 生成邀请码
MartialJudgeInvite generateInviteCode(GenerateInviteDTO dto);
// 批量生成邀请码
List<MartialJudgeInvite> 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.<MartialJudgeInvite>lambdaQuery()
.eq(MartialJudgeInvite::getInviteCode, inviteCode)
.eq(MartialJudgeInvite::getIsDeleted, 0)
);
```
3. **防止重复生成**:
```java
// 检查评委是否已有有效邀请码
MartialJudgeInvite existInvite = this.getOne(
Wrappers.<MartialJudgeInvite>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
<template>
<el-table :data="judgeList">
<el-table-column label="操作">
<template #default="{ row }">
<!-- 生成邀请码按钮 -->
<el-button
v-if="!row.inviteCode"
type="primary"
size="small"
@click="generateInviteCode(row)"
>
生成邀请码
</el-button>
<!-- 显示邀请码 -->
<div v-else>
<el-tag>{{ row.inviteCode }}</el-tag>
<el-button
type="text"
size="small"
@click="copyInviteCode(row.inviteCode)"
>
复制
</el-button>
<el-button
type="text"
size="small"
@click="regenerateInviteCode(row)"
>
重新生成
</el-button>
</div>
</template>
</el-table-column>
</el-table>
</template>
```
### 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. 上线部署
---
**祝您实施顺利!** 🚀
如有问题,请查看代码注释或联系技术支持。