feat: 实现成绩计算引擎、比赛日流程和导出打印功能
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
本次提交完成了武术比赛系统的核心功能模块,包括: ## 1. 成绩计算引擎 (Tasks 1.1-1.8) ✅ - 实现多裁判评分平均分计算(去最高/最低分) - 支持难度系数应用 - 自动排名算法(支持并列) - 奖牌自动分配(金银铜) - 成绩复核机制 - 成绩发布/撤销审批流程 ## 2. 比赛日流程功能 (Tasks 2.1-2.6) ✅ - 运动员签到/检录系统 - 评分有效性验证(范围检查0-10分) - 异常分数警告机制(偏差>2.0) - 异常情况记录和处理 - 检录长角色权限管理 - 比赛状态流转管理 ## 3. 导出打印功能 (Tasks 3.1-3.4) ✅ - 成绩单Excel导出(EasyExcel) - 运动员名单Excel导出 - 赛程表Excel导出 - 证书生成(HTML模板+数据接口) ## 4. 单元测试 ✅ - MartialResultServiceTest: 10个测试用例 - MartialScoreServiceTest: 10个测试用例 - MartialAthleteServiceTest: 14个测试用例 - 测试通过率: 100% (34/34) ## 技术实现 - 使用BigDecimal进行精度计算(保留3位小数) - EasyExcel实现Excel导出 - HTML证书模板(支持浏览器打印为PDF) - JUnit 5 + Mockito单元测试框架 ## 新增文件 - 3个新控制器:MartialExportController, MartialExceptionEventController, MartialJudgeProjectController - 3个Excel VO类:ResultExportExcel, AthleteExportExcel, ScheduleExportExcel - CertificateVO证书数据对象 - 证书HTML模板 - 3个测试类(676行测试代码) - 任务文档(docs/tasks/) - 数据库迁移脚本 ## 项目进度 已完成: 64% (18/28 任务) - ✅ 成绩计算引擎: 100% - ✅ 比赛日流程: 100% - ✅ 导出打印功能: 80% 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
241
docs/tasks/02-比赛日流程功能.md
Normal file
241
docs/tasks/02-比赛日流程功能.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# 比赛日流程功能 - 详细任务清单
|
||||
|
||||
**优先级:** P1(重要)
|
||||
**预计工时:** 4天
|
||||
**负责人:** 待分配
|
||||
**创建时间:** 2025-11-30
|
||||
|
||||
---
|
||||
|
||||
## 📋 任务概述
|
||||
|
||||
比赛日流程功能包括运动员签到检录、评分验证、异常处理等关键环节。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 任务列表
|
||||
|
||||
### 任务 2.1:运动员签到/检录系统 🔴
|
||||
|
||||
**状态:** 未开始
|
||||
**工时:** 1.5天
|
||||
|
||||
#### 需求描述
|
||||
- 运动员签到功能
|
||||
- 更新比赛状态(待出场 → 进行中 → 已完成)
|
||||
- 检录员角色权限管理
|
||||
|
||||
#### 实现要点
|
||||
```java
|
||||
// MartialAthleteServiceImpl.java
|
||||
public void checkIn(Long athleteId, Long scheduleId) {
|
||||
MartialAthlete athlete = this.getById(athleteId);
|
||||
|
||||
// 更新运动员状态:待出场 → 进行中
|
||||
athlete.setCompetitionStatus(1); // 进行中
|
||||
this.updateById(athlete);
|
||||
|
||||
// 更新赛程运动员关联状态
|
||||
MartialScheduleAthlete scheduleAthlete = scheduleAthleteService.getOne(
|
||||
new QueryWrapper<MartialScheduleAthlete>()
|
||||
.eq("schedule_id", scheduleId)
|
||||
.eq("athlete_id", athleteId)
|
||||
);
|
||||
scheduleAthlete.setIsCompleted(0); // 未完成
|
||||
scheduleAthleteService.updateById(scheduleAthlete);
|
||||
}
|
||||
|
||||
public void completePerformance(Long athleteId) {
|
||||
MartialAthlete athlete = this.getById(athleteId);
|
||||
athlete.setCompetitionStatus(2); // 已完成
|
||||
this.updateById(athlete);
|
||||
}
|
||||
```
|
||||
|
||||
#### API接口
|
||||
- `POST /martial/athlete/checkin` - 签到
|
||||
- `POST /martial/athlete/complete` - 完成比赛
|
||||
|
||||
---
|
||||
|
||||
### 任务 2.2:评分有效性验证 🔴
|
||||
|
||||
**状态:** 未开始
|
||||
**工时:** 0.5天
|
||||
|
||||
#### 需求描述
|
||||
- 分数范围检查(5.000 - 10.000)
|
||||
- 评分提交前验证
|
||||
- 异常分数提示
|
||||
|
||||
#### 实现要点
|
||||
```java
|
||||
// MartialScoreServiceImpl.java
|
||||
public boolean validateScore(BigDecimal score) {
|
||||
BigDecimal MIN_SCORE = new BigDecimal("5.000");
|
||||
BigDecimal MAX_SCORE = new BigDecimal("10.000");
|
||||
|
||||
return score.compareTo(MIN_SCORE) >= 0
|
||||
&& score.compareTo(MAX_SCORE) <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(MartialScore score) {
|
||||
// 验证分数范围
|
||||
if (!validateScore(score.getScore())) {
|
||||
throw new ServiceException("分数必须在5.000-10.000之间");
|
||||
}
|
||||
|
||||
return super.save(score);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2.3:异常分数警告机制 🔴
|
||||
|
||||
**状态:** 未开始
|
||||
**工时:** 1天
|
||||
|
||||
#### 需求描述
|
||||
- 检测离群值(与其他裁判差距过大)
|
||||
- 生成警告提示
|
||||
- 记录异常日志
|
||||
|
||||
#### 实现要点
|
||||
```java
|
||||
public void checkAnomalyScore(MartialScore newScore) {
|
||||
// 获取同一运动员的其他裁判评分
|
||||
List<MartialScore> scores = this.list(
|
||||
new QueryWrapper<MartialScore>()
|
||||
.eq("athlete_id", newScore.getAthleteId())
|
||||
.eq("project_id", newScore.getProjectId())
|
||||
.ne("judge_id", newScore.getJudgeId())
|
||||
);
|
||||
|
||||
if (scores.size() < 2) {
|
||||
return; // 评分数量不足,无法判断
|
||||
}
|
||||
|
||||
// 计算其他裁判的平均分
|
||||
BigDecimal avgScore = scores.stream()
|
||||
.map(MartialScore::getScore)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
.divide(new BigDecimal(scores.size()), 3, RoundingMode.HALF_UP);
|
||||
|
||||
// 判断偏差
|
||||
BigDecimal diff = newScore.getScore().subtract(avgScore).abs();
|
||||
if (diff.compareTo(new BigDecimal("1.000")) > 0) {
|
||||
// 偏差超过1.0分,记录警告
|
||||
log.warn("异常评分:裁判{}给运动员{}打分{},偏离平均分{}超过1.0",
|
||||
newScore.getJudgeName(),
|
||||
newScore.getAthleteId(),
|
||||
newScore.getScore(),
|
||||
avgScore
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2.4:异常情况记录和处理 🔴
|
||||
|
||||
**状态:** 未开始
|
||||
**工时:** 0.5天
|
||||
|
||||
#### 需求描述
|
||||
- 新建异常事件表
|
||||
- 记录异常类型、处理结果
|
||||
- 支持查询统计
|
||||
|
||||
#### 数据库表设计
|
||||
```sql
|
||||
CREATE TABLE martial_exception_event (
|
||||
id BIGINT PRIMARY KEY,
|
||||
competition_id BIGINT NOT NULL COMMENT '赛事ID',
|
||||
schedule_id BIGINT COMMENT '赛程ID',
|
||||
athlete_id BIGINT COMMENT '运动员ID',
|
||||
event_type INT COMMENT '事件类型 1-器械故障 2-受伤 3-评分争议 4-其他',
|
||||
event_description VARCHAR(500) COMMENT '事件描述',
|
||||
handler_name VARCHAR(50) COMMENT '处理人',
|
||||
handle_result VARCHAR(500) COMMENT '处理结果',
|
||||
handle_time DATETIME COMMENT '处理时间',
|
||||
status INT DEFAULT 0 COMMENT '状态 0-待处理 1-已处理',
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_deleted INT DEFAULT 0
|
||||
) COMMENT '异常事件表';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2.5:检录长角色权限管理 🔴
|
||||
|
||||
**状态:** 未开始
|
||||
**工时:** 0.5天
|
||||
|
||||
#### 需求描述
|
||||
- 定义检录长角色
|
||||
- 赋予特殊权限(处理异常、调整赛程)
|
||||
- 集成现有权限系统
|
||||
|
||||
#### 实现要点
|
||||
- 利用 BladeX 框架的角色权限系统
|
||||
- 新增角色:`ROLE_REFEREE_CHIEF`
|
||||
- 权限:异常处理、成绩复核申请
|
||||
|
||||
---
|
||||
|
||||
### 任务 2.6:比赛状态流转管理 🔴
|
||||
|
||||
**状态:** 未开始
|
||||
**工时:** 0.5天
|
||||
|
||||
#### 需求描述
|
||||
- 状态机管理运动员比赛状态
|
||||
- 防止非法状态转换
|
||||
- 记录状态变更日志
|
||||
|
||||
#### 状态流转图
|
||||
```
|
||||
待出场(0) → 进行中(1) → 已完成(2)
|
||||
↓ ↓
|
||||
已取消 暂停/异常
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Controller 层接口
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/martial/athlete")
|
||||
public class MartialAthleteController {
|
||||
|
||||
@PostMapping("/checkin")
|
||||
@Operation(summary = "运动员签到")
|
||||
public R checkIn(@RequestParam Long athleteId, @RequestParam Long scheduleId) {
|
||||
athleteService.checkIn(athleteId, scheduleId);
|
||||
return R.success("签到成功");
|
||||
}
|
||||
|
||||
@PostMapping("/complete")
|
||||
@Operation(summary = "完成比赛")
|
||||
public R complete(@RequestParam Long athleteId) {
|
||||
athleteService.completePerformance(athleteId);
|
||||
return R.success("已标记为完成");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 验收标准
|
||||
|
||||
- [ ] 签到功能正常,状态更新准确
|
||||
- [ ] 评分验证有效拦截非法分数
|
||||
- [ ] 异常分数警告机制生效
|
||||
- [ ] 异常事件可记录和查询
|
||||
- [ ] 权限控制符合设计
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user