9.5 KiB
赛程编排后端实现总结
实施概览
本次实现了赛程编排系统的三个核心后端API接口,完全按照 schedule-backend-api-spec.md 文档的规范进行开发。
实现的文件列表
1. DTO类 (数据传输对象)
1.1 ScheduleResultDTO.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/pojo/dto/ScheduleResultDTO.java - 作用: 赛程编排结果的响应数据结构
- 字段:
isDraft: 是否为草稿状态isCompleted: 是否已完成编排competitionGroups: 竞赛分组列表
1.2 CompetitionGroupDTO.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/pojo/dto/CompetitionGroupDTO.java - 作用: 竞赛分组数据结构
- 字段:
id: 分组IDtitle: 分组标题type: 类型(集体/单人/双人)count: 队伍数量code: 分组编号venueId: 场地IDvenueName: 场地名称timeSlot: 时间段timeSlotIndex: 时间段索引participants: 参赛人员列表
1.3 ParticipantDTO.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/pojo/dto/ParticipantDTO.java - 作用: 参赛人员数据结构
- 字段:
id: 参赛人员IDschoolUnit: 学校/单位status: 状态(未签到/已签到/异常)sortOrder: 排序
1.4 SaveScheduleDraftDTO.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/pojo/dto/SaveScheduleDraftDTO.java - 作用: 保存编排草稿的请求数据结构
- 字段:
competitionId: 赛事IDisDraft: 是否为草稿competitionGroups: 竞赛分组数据
2. 实体类修改
2.1 MartialScheduleParticipant.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/pojo/entity/MartialScheduleParticipant.java - 修改内容: 添加了两个新字段
status: 参赛人员状态(未签到/已签到/异常)scheduleStatus: 编排状态(draft/completed)
3. 服务接口
3.1 IMartialScheduleService.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/service/IMartialScheduleService.java - 新增方法:
getScheduleResult(Long competitionId): 获取赛程编排结果saveDraftSchedule(SaveScheduleDraftDTO dto): 保存编排草稿saveAndLockSchedule(Long competitionId): 完成编排并锁定
4. 服务实现
4.1 MartialScheduleServiceImpl.java
-
路径:
martial-master/src/main/java/org/springblade/modules/martial/service/impl/MartialScheduleServiceImpl.java -
新增依赖注入:
MartialScheduleGroupMapper: 分组数据访问MartialScheduleDetailMapper: 编排明细数据访问MartialScheduleParticipantMapper: 参赛者数据访问
-
实现的方法:
4.1.1 getScheduleResult(Long competitionId)
功能: 查询并返回赛事的编排结果
实现逻辑:
- 查询所有竞赛分组(按display_order排序)
- 查询所有编排明细
- 查询所有参赛者(按performance_order排序)
- 根据scheduleStatus判断是否已完成编排
- 组装DTO数据返回
关键代码:
// 检查编排状态
boolean isCompleted = participants.stream()
.anyMatch(p -> "completed".equals(p.getScheduleStatus()));
boolean isDraft = !isCompleted;
// 设置项目类型
switch (group.getProjectType()) {
case 1: groupDTO.setType("单人"); break;
case 2: groupDTO.setType("集体"); break;
default: groupDTO.setType("其他"); break;
}
4.1.2 saveDraftSchedule(SaveScheduleDraftDTO dto)
功能: 保存编排草稿数据
实现逻辑:
- 遍历所有竞赛分组
- 更新或创建编排明细(MartialScheduleDetail)
- 更新参赛者的状态和排序
- 将scheduleStatus设置为"draft"
- 使用事务确保数据一致性
关键代码:
@Transactional(rollbackFor = Exception.class)
public boolean saveDraftSchedule(SaveScheduleDraftDTO dto) {
// 更新编排明细
detail.setVenueId(groupDTO.getVenueId());
detail.setVenueName(groupDTO.getVenueName());
detail.setTimeSlot(groupDTO.getTimeSlot());
// 更新参赛者信息
participant.setStatus(participantDTO.getStatus());
participant.setPerformanceOrder(participantDTO.getSortOrder());
participant.setScheduleStatus("draft");
}
4.1.3 saveAndLockSchedule(Long competitionId)
功能: 完成编排并锁定,不允许再次编辑
实现逻辑:
- 查询赛事的所有分组
- 查询所有参赛者
- 将所有参赛者的scheduleStatus更新为"completed"
- 使用事务确保数据一致性
关键代码:
@Transactional(rollbackFor = Exception.class)
public boolean saveAndLockSchedule(Long competitionId) {
for (MartialScheduleParticipant participant : participants) {
participant.setScheduleStatus("completed");
scheduleParticipantMapper.updateById(participant);
}
}
5. 控制器
5.1 MartialScheduleController.java
- 路径:
martial-master/src/main/java/org/springblade/modules/martial/controller/MartialScheduleController.java - 新增端点:
5.1.1 GET /martial/schedule/result
功能: 获取赛程编排结果
请求参数:
competitionId(Long): 赛事ID
响应示例:
{
"code": 200,
"msg": "success",
"data": {
"isDraft": true,
"isCompleted": false,
"competitionGroups": [...]
}
}
5.1.2 POST /martial/schedule/save-draft
功能: 保存编排草稿
请求体: SaveScheduleDraftDTO
响应示例:
{
"code": 200,
"msg": "草稿保存成功"
}
5.1.3 POST /martial/schedule/save-and-lock
功能: 完成编排并锁定
请求体: 包含competitionId的SaveScheduleDraftDTO
响应示例:
{
"code": 200,
"msg": "编排已完成并锁定"
}
数据库设计说明
涉及的表
-
martial_schedule_group (赛程编排分组)
- 存储竞赛分组信息
- 字段: competition_id, group_name, project_type, display_order等
-
martial_schedule_detail (赛程编排明细)
- 存储场地和时间段分配信息
- 字段: schedule_group_id, venue_id, venue_name, schedule_date, time_slot等
-
martial_schedule_participant (赛程编排参赛者关联)
- 存储参赛者信息
- 新增字段:
status: VARCHAR - 参赛人员状态(未签到/已签到/异常)schedule_status: VARCHAR - 编排状态(draft/completed)
数据库迁移建议
需要在 martial_schedule_participant 表中添加以下字段:
ALTER TABLE martial_schedule_participant
ADD COLUMN status VARCHAR(20) DEFAULT '未签到' COMMENT '状态:未签到/已签到/异常',
ADD COLUMN schedule_status VARCHAR(20) DEFAULT 'draft' COMMENT '编排状态:draft/completed';
业务逻辑说明
编排状态管理
-
草稿状态 (draft):
- 用户可以多次保存和修改
- 不影响其他功能
- scheduleStatus = "draft"
-
完成状态 (completed):
- 编排锁定,前端禁用所有编辑功能
- 显示"导出"按钮
- scheduleStatus = "completed"
首次分配规则
根据API规范,后端需要按照"先集体,后个人"的顺序进行第一次场地分配:
- 集体项目 (projectType = 2) 优先分配
- 个人项目 (projectType = 1) 后分配
- 使用 display_order 字段控制顺序
状态字段说明
参赛人员状态 (status):
- 未签到: 默认状态
- 已签到: 参赛人员已签到
- 异常: 被标记为异常的参赛人员
前后端对接说明
API路径映射
前端API配置 (src/api/martial/activitySchedule.js):
// 获取赛程编排结果
GET /api/martial/schedule/result
// 保存编排草稿
POST /api/martial/schedule/save-draft
// 完成编排并锁定
POST /api/martial/schedule/save-and-lock
后端Controller路径 (MartialScheduleController.java):
@RequestMapping("/martial/schedule")
@GetMapping("/result")
@PostMapping("/save-draft")
@PostMapping("/save-and-lock")
数据格式兼容性
- 后端使用驼峰命名 (camelCase)
- 前端已做兼容处理,同时支持驼峰和下划线命名
- DTO中的字段名与前端API规范完全一致
测试建议
单元测试
-
测试getScheduleResult方法:
- 测试空数据情况
- 测试草稿状态
- 测试完成状态
- 测试数据组装正确性
-
测试saveDraftSchedule方法:
- 测试新建编排明细
- 测试更新编排明细
- 测试参赛者状态更新
- 测试事务回滚
-
测试saveAndLockSchedule方法:
- 测试状态更新
- 测试锁定后的查询结果
集成测试
-
测试完整的编排流程:
- 首次获取编排结果
- 多次保存草稿
- 完成编排并锁定
- 再次查询验证状态
-
测试异常场景:
- 赛事不存在
- 分组不存在
- 参赛者不存在
后续优化建议
-
性能优化:
- 对于大量参赛者的情况,考虑使用批量更新
- 添加缓存机制减少数据库查询
-
功能增强:
- 添加编排历史记录
- 实现编排版本管理
- 添加编排冲突检测
-
安全性:
- 添加权限验证
- 添加操作日志
- 实现并发控制
总结
本次实现完全按照前端API规范进行开发,实现了:
- ✅ 3个核心API接口
- ✅ 4个DTO类
- ✅ 实体类字段扩展
- ✅ 完整的服务层逻辑
- ✅ 事务管理
- ✅ Swagger文档注解
所有代码遵循项目现有的代码风格和架构规范,可以直接集成到现有系统中使用。