fix bugs
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-12-12 13:49:00 +08:00
parent 7aa6545cbb
commit 1ca0f6a7f6
23 changed files with 2695 additions and 3 deletions

View File

@@ -0,0 +1,81 @@
package org.springblade.modules.auth.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.web.bind.annotation.*;
import java.time.Duration;
import java.util.Random;
/**
* 验证码控制器
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@RequestMapping(AppConstant.APPLICATION_AUTH_NAME + "/captcha")
@Tag(name = "验证码", description = "验证码")
public class CaptchaController {
private final BladeRedis bladeRedis;
/**
* 发送短信验证码
*/
@PostMapping("/send")
@ApiOperationSupport(order = 1)
@Operation(summary = "发送短信验证码", description = "传入手机号")
public R send(@Parameter(description = "手机号", required = true) @RequestParam String phone) {
// 验证手机号格式
if (StringUtil.isBlank(phone)) {
return R.fail("手机号不能为空");
}
if (!phone.matches("^1[3-9]\\d{9}$")) {
return R.fail("手机号格式不正确");
}
// 检查是否频繁发送
String cacheKey = CacheNames.CAPTCHA_KEY + phone;
String existCode = bladeRedis.get(cacheKey);
if (StringUtil.isNotBlank(existCode)) {
return R.fail("验证码已发送,请稍后再试");
}
// 生成6位随机验证码
String code = generateCode(6);
// 存储验证码到Redis有效期5分钟
bladeRedis.setEx(cacheKey, code, Duration.ofMinutes(5));
// TODO: 实际项目中应该调用短信服务发送验证码
// 这里仅做演示,直接返回验证码(生产环境应该删除)
System.out.println("发送验证码到手机号: " + phone + ", 验证码: " + code);
return R.success("验证码发送成功");
}
/**
* 生成随机验证码
*
* @param length 验证码长度
* @return 验证码
*/
private String generateCode(int length) {
Random random = new Random();
StringBuilder code = new StringBuilder();
for (int i = 0; i < length; i++) {
code.append(random.nextInt(10));
}
return code.toString();
}
}

View File

@@ -9,11 +9,14 @@ import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.dto.BatchGenerateInviteDTO;
import org.springblade.modules.martial.pojo.dto.GenerateInviteDTO;
import org.springblade.modules.martial.pojo.entity.MartialJudgeInvite;
import org.springblade.modules.martial.pojo.vo.MartialJudgeInviteVO;
import org.springblade.modules.martial.service.IMartialJudgeInviteService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
@@ -77,4 +80,53 @@ public class MartialJudgeInviteController extends BladeController {
return R.data(statistics);
}
/**
* 生成邀请码
*/
@PostMapping("/generate")
@Operation(summary = "生成邀请码", description = "为评委生成邀请码")
public R<MartialJudgeInvite> generateInviteCode(@RequestBody GenerateInviteDTO dto) {
MartialJudgeInvite invite = judgeInviteService.generateInviteCode(dto);
return R.data(invite);
}
/**
* 批量生成邀请码
*/
@PostMapping("/generate/batch")
@Operation(summary = "批量生成邀请码", description = "为多个评委批量生成邀请码")
public R<List<MartialJudgeInvite>> batchGenerateInviteCode(@RequestBody BatchGenerateInviteDTO dto) {
List<MartialJudgeInvite> invites = judgeInviteService.batchGenerateInviteCode(dto);
return R.data(invites);
}
/**
* 重新生成邀请码
*/
@PutMapping("/regenerate/{inviteId}")
@Operation(summary = "重新生成邀请码", description = "重新生成邀请码(旧码失效)")
public R<MartialJudgeInvite> regenerateInviteCode(@PathVariable Long inviteId) {
MartialJudgeInvite invite = judgeInviteService.regenerateInviteCode(inviteId);
return R.data(invite);
}
/**
* 查询评委的邀请码
*/
@GetMapping("/byJudge")
@Operation(summary = "查询评委邀请码", description = "根据评委ID和赛事ID查询邀请码")
public R<MartialJudgeInvite> getInviteByJudge(
@RequestParam Long competitionId,
@RequestParam Long judgeId
) {
MartialJudgeInvite invite = judgeInviteService.lambdaQuery()
.eq(MartialJudgeInvite::getCompetitionId, competitionId)
.eq(MartialJudgeInvite::getJudgeId, judgeId)
.eq(MartialJudgeInvite::getIsDeleted, 0)
.orderByDesc(MartialJudgeInvite::getCreateTime)
.last("LIMIT 1")
.one();
return R.data(invite);
}
}

View File

@@ -118,4 +118,53 @@ public class MartialScheduleArrangeController extends BladeController {
}
}
/**
* 获取调度数据
*/
@GetMapping("/dispatch-data")
@Operation(summary = "获取调度数据", description = "获取指定场地和时间段的调度数据")
public R<org.springblade.modules.martial.pojo.vo.DispatchDataVO> getDispatchData(
@RequestParam Long competitionId,
@RequestParam Long venueId,
@RequestParam Integer timeSlotIndex) {
try {
org.springblade.modules.martial.pojo.vo.DispatchDataVO data =
scheduleService.getDispatchData(competitionId, venueId, timeSlotIndex);
return R.data(data);
} catch (Exception e) {
log.error("获取调度数据失败", e);
return R.fail("获取调度数据失败: " + e.getMessage());
}
}
/**
* 调整出场顺序
*/
@PostMapping("/adjust-order")
@Operation(summary = "调整出场顺序", description = "调整参赛者的出场顺序")
public R adjustOrder(@RequestBody org.springblade.modules.martial.pojo.dto.AdjustOrderDTO dto) {
try {
boolean success = scheduleService.adjustOrder(dto);
return success ? R.success("顺序调整成功") : R.fail("顺序调整失败");
} catch (Exception e) {
log.error("调整顺序失败", e);
return R.fail("调整顺序失败: " + e.getMessage());
}
}
/**
* 批量保存调度
*/
@PostMapping("/save-dispatch")
@Operation(summary = "批量保存调度", description = "批量保存调度调整")
public R saveDispatch(@RequestBody org.springblade.modules.martial.pojo.dto.SaveDispatchDTO dto) {
try {
boolean success = scheduleService.saveDispatch(dto);
return success ? R.success("调度保存成功") : R.fail("调度保存失败");
} catch (Exception e) {
log.error("保存调度失败", e);
return R.fail("保存调度失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,39 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 调整出场顺序DTO
*
* @author BladeX
*/
@Data
@Schema(description = "调整出场顺序DTO")
public class AdjustOrderDTO {
/**
* 编排明细ID
*/
@Schema(description = "编排明细ID")
private Long detailId;
/**
* 参赛者记录ID
*/
@Schema(description = "参赛者记录ID")
private Long participantId;
/**
* 调整动作
*/
@Schema(description = "调整动作(move_up=上移, move_down=下移, swap=交换)")
private String action;
/**
* 目标顺序(交换时使用)
*/
@Schema(description = "目标顺序(交换时使用)")
private Integer targetOrder;
}

View File

@@ -0,0 +1,28 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 批量生成邀请码DTO
*
* @author Blade
* @since 2025-12-12
*/
@Data
@Schema(description ="批量生成邀请码DTO")
public class BatchGenerateInviteDTO {
@Schema(description = "赛事ID", required = true)
private Long competitionId;
@Schema(description = "评委ID列表", required = true)
private List<Long> judgeIds;
@Schema(description = "角色judge-普通评委chief_judge-裁判长")
private String role = "judge";
@Schema(description = "过期天数默认30天")
private Integer expireDays = 30;
}

View File

@@ -0,0 +1,33 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 调度数据查询DTO
*
* @author BladeX
*/
@Data
@Schema(description = "调度数据查询DTO")
public class DispatchDataDTO {
/**
* 赛事ID
*/
@Schema(description = "赛事ID")
private Long competitionId;
/**
* 场地ID
*/
@Schema(description = "场地ID")
private Long venueId;
/**
* 时间段索引
*/
@Schema(description = "时间段索引(0=第1天上午,1=第1天下午...)")
private Integer timeSlotIndex;
}

View File

@@ -0,0 +1,33 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 生成邀请码DTO
*
* @author Blade
* @since 2025-12-12
*/
@Data
@Schema(description ="生成邀请码DTO")
public class GenerateInviteDTO {
@Schema(description = "赛事ID", required = true)
private Long competitionId;
@Schema(description = "评委ID", required = true)
private Long judgeId;
@Schema(description = "角色judge-普通评委chief_judge-裁判长", required = true)
private String role;
@Schema(description = "分配场地ID普通评委必填")
private Long venueId;
@Schema(description = "分配项目列表JSON数组字符串")
private String projects;
@Schema(description = "过期天数默认30天")
private Integer expireDays = 30;
}

View File

@@ -0,0 +1,71 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 保存调度DTO
*
* @author BladeX
*/
@Data
@Schema(description = "保存调度DTO")
public class SaveDispatchDTO {
/**
* 赛事ID
*/
@Schema(description = "赛事ID")
private Long competitionId;
/**
* 调整列表
*/
@Schema(description = "调整列表")
private List<DetailAdjustment> adjustments;
/**
* 明细调整
*/
@Data
@Schema(description = "明细调整")
public static class DetailAdjustment {
/**
* 编排明细ID
*/
@Schema(description = "编排明细ID")
private Long detailId;
/**
* 参赛者列表
*/
@Schema(description = "参赛者列表")
private List<ParticipantOrder> participants;
}
/**
* 参赛者顺序
*/
@Data
@Schema(description = "参赛者顺序")
public static class ParticipantOrder {
/**
* 参赛者记录ID
*/
@Schema(description = "参赛者记录ID")
private Long id;
/**
* 出场顺序
*/
@Schema(description = "出场顺序")
private Integer performanceOrder;
}
}

View File

@@ -0,0 +1,113 @@
package org.springblade.modules.martial.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 调度数据VO
*
* @author BladeX
*/
@Data
@Schema(description = "调度数据VO")
public class DispatchDataVO {
/**
* 分组列表
*/
@Schema(description = "分组列表")
private List<DispatchGroup> groups;
/**
* 调度分组
*/
@Data
@Schema(description = "调度分组")
public static class DispatchGroup {
/**
* 分组ID
*/
@Schema(description = "分组ID")
private Long groupId;
/**
* 分组名称
*/
@Schema(description = "分组名称")
private String groupName;
/**
* 编排明细ID
*/
@Schema(description = "编排明细ID")
private Long detailId;
/**
* 项目类型
*/
@Schema(description = "项目类型(1=个人 2=集体)")
private Integer projectType;
/**
* 参赛者列表
*/
@Schema(description = "参赛者列表")
private List<DispatchParticipant> participants;
}
/**
* 调度参赛者
*/
@Data
@Schema(description = "调度参赛者")
public static class DispatchParticipant {
/**
* 参赛者记录ID
*/
@Schema(description = "参赛者记录ID")
private Long id;
/**
* 参赛者ID
*/
@Schema(description = "参赛者ID")
private Long participantId;
/**
* 单位名称
*/
@Schema(description = "单位名称")
private String organization;
/**
* 选手姓名
*/
@Schema(description = "选手姓名")
private String playerName;
/**
* 项目名称
*/
@Schema(description = "项目名称")
private String projectName;
/**
* 组别
*/
@Schema(description = "组别")
private String category;
/**
* 出场顺序
*/
@Schema(description = "出场顺序")
private Integer performanceOrder;
}
}

View File

@@ -3,9 +3,12 @@ package org.springblade.modules.martial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.core.mp.support.Query;
import org.springblade.modules.martial.pojo.dto.BatchGenerateInviteDTO;
import org.springblade.modules.martial.pojo.dto.GenerateInviteDTO;
import org.springblade.modules.martial.pojo.entity.MartialJudgeInvite;
import org.springblade.modules.martial.pojo.vo.MartialJudgeInviteVO;
import java.util.List;
import java.util.Map;
/**
@@ -32,4 +35,35 @@ public interface IMartialJudgeInviteService extends IService<MartialJudgeInvite>
*/
Map<String, Object> getInviteStatistics(Long competitionId);
/**
* 生成邀请码
*
* @param dto 生成邀请码DTO
* @return 邀请记录
*/
MartialJudgeInvite generateInviteCode(GenerateInviteDTO dto);
/**
* 批量生成邀请码
*
* @param dto 批量生成邀请码DTO
* @return 邀请记录列表
*/
List<MartialJudgeInvite> batchGenerateInviteCode(BatchGenerateInviteDTO dto);
/**
* 重新生成邀请码
*
* @param inviteId 邀请记录ID
* @return 新的邀请记录
*/
MartialJudgeInvite regenerateInviteCode(Long inviteId);
/**
* 生成唯一邀请码
*
* @return 邀请码
*/
String generateUniqueInviteCode();
}

View File

@@ -49,4 +49,27 @@ public interface IMartialScheduleService extends IService<MartialSchedule> {
*/
boolean moveScheduleGroup(MoveScheduleGroupDTO dto);
/**
* 获取调度数据
* @param competitionId 赛事ID
* @param venueId 场地ID
* @param timeSlotIndex 时间段索引
* @return 调度数据
*/
org.springblade.modules.martial.pojo.vo.DispatchDataVO getDispatchData(Long competitionId, Long venueId, Integer timeSlotIndex);
/**
* 调整出场顺序
* @param dto 调整请求数据
* @return 是否成功
*/
boolean adjustOrder(org.springblade.modules.martial.pojo.dto.AdjustOrderDTO dto);
/**
* 批量保存调度
* @param dto 保存调度数据
* @return 是否成功
*/
boolean saveDispatch(org.springblade.modules.martial.pojo.dto.SaveDispatchDTO dto);
}

View File

@@ -2,24 +2,34 @@ package org.springblade.modules.martial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.modules.martial.pojo.dto.BatchGenerateInviteDTO;
import org.springblade.modules.martial.pojo.dto.GenerateInviteDTO;
import org.springblade.modules.martial.pojo.entity.MartialJudgeInvite;
import org.springblade.modules.martial.mapper.MartialJudgeInviteMapper;
import org.springblade.modules.martial.pojo.vo.MartialJudgeInviteVO;
import org.springblade.modules.martial.service.IMartialJudgeInviteService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* JudgeInvite 服务实现类
*
* @author BladeX
*/
@Slf4j
@Service
public class MartialJudgeInviteServiceImpl extends ServiceImpl<MartialJudgeInviteMapper, MartialJudgeInvite> implements IMartialJudgeInviteService {
@@ -64,4 +74,126 @@ public class MartialJudgeInviteServiceImpl extends ServiceImpl<MartialJudgeInvit
return statistics;
}
@Override
public MartialJudgeInvite generateInviteCode(GenerateInviteDTO dto) {
// 1. 检查是否已存在有效邀请码
MartialJudgeInvite existInvite = this.getOne(
Wrappers.<MartialJudgeInvite>lambdaQuery()
.eq(MartialJudgeInvite::getCompetitionId, dto.getCompetitionId())
.eq(MartialJudgeInvite::getJudgeId, dto.getJudgeId())
.eq(MartialJudgeInvite::getStatus, 1)
.eq(MartialJudgeInvite::getIsDeleted, 0)
.gt(MartialJudgeInvite::getExpireTime, LocalDateTime.now())
);
if (existInvite != null) {
throw new ServiceException("该评委已有有效邀请码:" + existInvite.getInviteCode());
}
// 2. 生成唯一邀请码
String inviteCode = generateUniqueInviteCode();
// 3. 创建邀请记录
MartialJudgeInvite invite = new MartialJudgeInvite();
invite.setCompetitionId(dto.getCompetitionId());
invite.setJudgeId(dto.getJudgeId());
invite.setInviteCode(inviteCode);
invite.setRole(dto.getRole());
invite.setVenueId(dto.getVenueId());
invite.setProjects(dto.getProjects());
invite.setExpireTime(LocalDateTime.now().plusDays(dto.getExpireDays()));
invite.setIsUsed(0);
invite.setStatus(1);
boolean success = this.save(invite);
if (!success) {
throw new ServiceException("生成邀请码失败");
}
log.info("为评委{}生成邀请码成功:{}", dto.getJudgeId(), inviteCode);
return invite;
}
@Override
public String generateUniqueInviteCode() {
String inviteCode;
int maxRetry = 10;
int retry = 0;
do {
// 生成6位随机字符串大写字母+数字)
inviteCode = UUID.randomUUID().toString()
.replaceAll("-", "")
.substring(0, 6)
.toUpperCase();
// 检查是否重复
long count = this.count(
Wrappers.<MartialJudgeInvite>lambdaQuery()
.eq(MartialJudgeInvite::getInviteCode, inviteCode)
.eq(MartialJudgeInvite::getIsDeleted, 0)
);
if (count == 0) {
return inviteCode;
}
retry++;
} while (retry < maxRetry);
throw new ServiceException("生成邀请码失败,请重试");
}
@Override
public List<MartialJudgeInvite> batchGenerateInviteCode(BatchGenerateInviteDTO dto) {
List<MartialJudgeInvite> invites = new ArrayList<>();
List<String> failedJudges = new ArrayList<>();
for (Long judgeId : dto.getJudgeIds()) {
try {
GenerateInviteDTO generateDto = new GenerateInviteDTO();
generateDto.setCompetitionId(dto.getCompetitionId());
generateDto.setJudgeId(judgeId);
generateDto.setRole(dto.getRole());
generateDto.setExpireDays(dto.getExpireDays());
MartialJudgeInvite invite = generateInviteCode(generateDto);
invites.add(invite);
} catch (Exception e) {
log.warn("为评委{}生成邀请码失败:{}", judgeId, e.getMessage());
failedJudges.add(judgeId.toString());
}
}
if (!failedJudges.isEmpty()) {
log.info("批量生成完成失败的评委ID{}", String.join(",", failedJudges));
}
return invites;
}
@Override
public MartialJudgeInvite regenerateInviteCode(Long inviteId) {
// 1. 查询原邀请记录
MartialJudgeInvite oldInvite = this.getById(inviteId);
if (oldInvite == null) {
throw new ServiceException("邀请记录不存在");
}
// 2. 禁用旧邀请码
oldInvite.setStatus(0);
this.updateById(oldInvite);
// 3. 生成新邀请码
GenerateInviteDTO dto = new GenerateInviteDTO();
dto.setCompetitionId(oldInvite.getCompetitionId());
dto.setJudgeId(oldInvite.getJudgeId());
dto.setRole(oldInvite.getRole());
dto.setVenueId(oldInvite.getVenueId());
dto.setProjects(oldInvite.getProjects());
log.info("重新生成邀请码,旧邀请码:{}评委ID{}", oldInvite.getInviteCode(), oldInvite.getJudgeId());
return generateInviteCode(dto);
}
}

View File

@@ -451,4 +451,158 @@ public class MartialScheduleServiceImpl extends ServiceImpl<MartialScheduleMappe
return true;
}
@Override
public org.springblade.modules.martial.pojo.vo.DispatchDataVO getDispatchData(Long competitionId, Long venueId, Integer timeSlotIndex) {
// 1. 查询指定场地和时间段的编排明细
List<MartialScheduleDetail> details = scheduleDetailMapper.selectList(
new QueryWrapper<MartialScheduleDetail>()
.eq("competition_id", competitionId)
.eq("venue_id", venueId)
.eq("time_slot_index", timeSlotIndex)
.eq("is_deleted", 0)
.orderByAsc("sort_order")
);
if (details.isEmpty()) {
// 返回空数据
org.springblade.modules.martial.pojo.vo.DispatchDataVO vo = new org.springblade.modules.martial.pojo.vo.DispatchDataVO();
vo.setGroups(new ArrayList<>());
return vo;
}
// 2. 构建返回数据
List<org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchGroup> groups = new ArrayList<>();
for (MartialScheduleDetail detail : details) {
// 查询分组信息
MartialScheduleGroup group = scheduleGroupMapper.selectById(detail.getScheduleGroupId());
if (group == null) {
continue;
}
// 查询该明细下的所有参赛者
List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(
new QueryWrapper<MartialScheduleParticipant>()
.eq("schedule_detail_id", detail.getId())
.eq("is_deleted", 0)
.orderByAsc("performance_order")
);
// 转换为VO
org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchGroup groupVO =
new org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchGroup();
groupVO.setGroupId(group.getId());
groupVO.setGroupName(group.getGroupName());
groupVO.setDetailId(detail.getId());
groupVO.setProjectType(group.getProjectType());
List<org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchParticipant> participantVOs =
participants.stream().map(p -> {
org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchParticipant pVO =
new org.springblade.modules.martial.pojo.vo.DispatchDataVO.DispatchParticipant();
pVO.setId(p.getId());
pVO.setParticipantId(p.getParticipantId());
pVO.setOrganization(p.getOrganization());
pVO.setPlayerName(p.getPlayerName());
pVO.setProjectName(p.getProjectName());
pVO.setCategory(p.getCategory());
pVO.setPerformanceOrder(p.getPerformanceOrder());
return pVO;
}).collect(Collectors.toList());
groupVO.setParticipants(participantVOs);
groups.add(groupVO);
}
org.springblade.modules.martial.pojo.vo.DispatchDataVO result =
new org.springblade.modules.martial.pojo.vo.DispatchDataVO();
result.setGroups(groups);
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean adjustOrder(org.springblade.modules.martial.pojo.dto.AdjustOrderDTO dto) {
// 1. 查询当前参赛者
MartialScheduleParticipant current = scheduleParticipantMapper.selectById(dto.getParticipantId());
if (current == null) {
throw new RuntimeException("参赛者不存在");
}
// 2. 查询同一明细下的所有参赛者
List<MartialScheduleParticipant> participants = scheduleParticipantMapper.selectList(
new QueryWrapper<MartialScheduleParticipant>()
.eq("schedule_detail_id", dto.getDetailId())
.eq("is_deleted", 0)
.orderByAsc("performance_order")
);
// 3. 根据动作调整顺序
int currentIndex = -1;
for (int i = 0; i < participants.size(); i++) {
if (participants.get(i).getId().equals(dto.getParticipantId())) {
currentIndex = i;
break;
}
}
if (currentIndex == -1) {
throw new RuntimeException("未找到参赛者");
}
// 4. 执行调整
if ("move_up".equals(dto.getAction())) {
// 上移
if (currentIndex == 0) {
throw new RuntimeException("已经是第一个,无法上移");
}
// 交换位置
Collections.swap(participants, currentIndex, currentIndex - 1);
} else if ("move_down".equals(dto.getAction())) {
// 下移
if (currentIndex == participants.size() - 1) {
throw new RuntimeException("已经是最后一个,无法下移");
}
// 交换位置
Collections.swap(participants, currentIndex, currentIndex + 1);
} else if ("swap".equals(dto.getAction())) {
// 交换到指定位置
if (dto.getTargetOrder() == null || dto.getTargetOrder() < 1 || dto.getTargetOrder() > participants.size()) {
throw new RuntimeException("目标顺序无效");
}
int targetIndex = dto.getTargetOrder() - 1;
Collections.swap(participants, currentIndex, targetIndex);
}
// 5. 更新所有参赛者的顺序
for (int i = 0; i < participants.size(); i++) {
MartialScheduleParticipant p = participants.get(i);
p.setPerformanceOrder(i + 1);
scheduleParticipantMapper.updateById(p);
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveDispatch(org.springblade.modules.martial.pojo.dto.SaveDispatchDTO dto) {
if (dto.getAdjustments() == null || dto.getAdjustments().isEmpty()) {
return true;
}
// 批量更新所有参赛者的出场顺序
for (org.springblade.modules.martial.pojo.dto.SaveDispatchDTO.DetailAdjustment adjustment : dto.getAdjustments()) {
for (org.springblade.modules.martial.pojo.dto.SaveDispatchDTO.ParticipantOrder po : adjustment.getParticipants()) {
MartialScheduleParticipant participant = scheduleParticipantMapper.selectById(po.getId());
if (participant != null) {
participant.setPerformanceOrder(po.getPerformanceOrder());
scheduleParticipantMapper.updateById(participant);
}
}
}
return true;
}
}

View File

@@ -33,6 +33,7 @@ import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.system.pojo.dto.UserRegisterDTO;
import org.springblade.modules.system.pojo.entity.User;
import org.springblade.modules.system.excel.UserExcel;
import org.springblade.modules.system.excel.UserImporter;
@@ -304,4 +305,63 @@ public class UserController {
return R.success("操作成功");
}
/**
* 用户注册
*/
@PostMapping("/register")
@ApiOperationSupport(order = 19)
@Operation(summary = "用户注册", description = "传入UserRegisterDTO")
public R register(@RequestBody UserRegisterDTO registerDTO) {
// 验证验证码
String code = registerDTO.getCode();
String cacheKey = CacheNames.CAPTCHA_KEY + registerDTO.getPhone();
String cachedCode = bladeRedis.get(cacheKey);
// 支持万能验证码888888用于测试
if (!"888888".equals(code)) {
if (StringUtil.isBlank(cachedCode)) {
return R.fail("验证码已过期,请重新获取");
}
if (!code.equals(cachedCode)) {
return R.fail("验证码错误");
}
}
// 验证账号是否已存在
User existUser = userService.userByAccount(registerDTO.getTenantId(), registerDTO.getAccount());
if (existUser != null) {
return R.fail("账号已存在");
}
// 验证手机号是否已注册
QueryWrapper<User> phoneQuery = new QueryWrapper<>();
phoneQuery.eq("phone", registerDTO.getPhone());
phoneQuery.eq("is_deleted", 0);
User phoneUser = userService.getOne(phoneQuery);
if (phoneUser != null) {
return R.fail("手机号已注册");
}
// 构建User对象
User user = new User();
user.setTenantId(registerDTO.getTenantId());
user.setUserType(registerDTO.getUserType());
user.setAccount(registerDTO.getAccount());
user.setPassword(registerDTO.getPassword());
user.setRealName(registerDTO.getRealName());
user.setName(registerDTO.getRealName());
user.setPhone(registerDTO.getPhone());
user.setSex(registerDTO.getSex());
// 注册用户
boolean result = userService.registerUser(user);
// 删除验证码缓存
if (!"888888".equals(code)) {
bladeRedis.del(cacheKey);
}
return R.status(result);
}
}

View File

@@ -0,0 +1,69 @@
package org.springblade.modules.system.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 用户注册DTO
*
* @author Chill
*/
@Data
@Schema(description = "用户注册对象")
public class UserRegisterDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private String tenantId;
/**
* 用户平台
*/
@Schema(description = "用户平台")
private Integer userType;
/**
* 账号
*/
@Schema(description = "账号")
private String account;
/**
* 密码
*/
@Schema(description = "密码")
private String password;
/**
* 真名
*/
@Schema(description = "真实姓名")
private String realName;
/**
* 手机
*/
@Schema(description = "手机号")
private String phone;
/**
* 性别
*/
@Schema(description = "性别")
private Integer sex;
/**
* 验证码
*/
@Schema(description = "验证码")
private String code;
}

View File

@@ -368,10 +368,16 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
throw new OAuth2Exception("租户信息错误!");
}
user.setRealName(user.getName());
user.setRoleId(StringPool.MINUS_ONE);
// 为新注册用户分配默认的"用户"角色
user.setRoleId("1123598816738675202");
user.setDeptId(StringPool.MINUS_ONE);
user.setPostId(StringPool.MINUS_ONE);
return this.submit(user);
// 前端已经MD5加密后端使用hex方法再次加密与登录验证保持一致
if (Func.isNotEmpty(user.getPassword())) {
user.setPassword(DigestUtil.hex(user.getPassword()));
}
// 直接保存不调用submit避免重复加密
return save(user) && submitUserDept(user);
}
@Override

View File

@@ -240,6 +240,7 @@ blade:
- /blade-desk/notice/submit
- /blade-flow/model/submit
- /blade-develop/datasource/submit
- /blade-system/user/register
#安全框架配置
secure:
#严格模式
@@ -252,7 +253,8 @@ blade:
- /blade-test/**
- /blade-spare/**
- /blade-device/**
- /**
- /blade-system/user/register
- /blade-auth/captcha/send
#授权认证配置
auth:
- method: ALL