feat(security): add validation and access guards for martial APIs

This commit is contained in:
2026-02-15 17:05:54 +08:00
parent ea91304a3f
commit d047e87de8
15 changed files with 247 additions and 57 deletions
@@ -1,23 +1,24 @@
package org.springblade.modules.martial.controller; package org.springblade.modules.martial.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query; import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.MartialAthlete; import org.springblade.modules.martial.mapper.MartialAthleteMapper;
import org.springblade.modules.martial.pojo.dto.MartialCompetitionSubmitDTO;
import org.springblade.modules.martial.pojo.entity.MartialCompetition; import org.springblade.modules.martial.pojo.entity.MartialCompetition;
import org.springblade.modules.martial.service.IMartialAthleteService; import org.springblade.modules.martial.service.IMartialAthleteService;
import org.springblade.modules.martial.mapper.MartialAthleteMapper;
import org.springblade.modules.martial.service.IMartialCompetitionService; import org.springblade.modules.martial.service.IMartialCompetitionService;
import org.springblade.modules.system.pojo.entity.User; import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
@@ -27,8 +28,10 @@ import java.util.List;
* *
* @author BladeX * @author BladeX
*/ */
@Validated
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@RequestMapping("/martial/competition") @RequestMapping("/martial/competition")
@Tag(name = "赛事管理", description = "赛事信息管理接口") @Tag(name = "赛事管理", description = "赛事信息管理接口")
public class MartialCompetitionController extends BladeController { public class MartialCompetitionController extends BladeController {
@@ -44,7 +47,6 @@ public class MartialCompetitionController extends BladeController {
public R<MartialCompetition> detail(@RequestParam Long id) { public R<MartialCompetition> detail(@RequestParam Long id) {
MartialCompetition detail = competitionService.getById(id); MartialCompetition detail = competitionService.getById(id);
if (detail != null) { if (detail != null) {
// Count distinct participants by id_card
Long cnt = ((MartialAthleteMapper) martialAthleteService.getBaseMapper()).countDistinctParticipants(detail.getId()); Long cnt = ((MartialAthleteMapper) martialAthleteService.getBaseMapper()).countDistinctParticipants(detail.getId());
detail.setTotalParticipants(cnt != null ? cnt.intValue() : 0); detail.setTotalParticipants(cnt != null ? cnt.intValue() : 0);
} }
@@ -58,9 +60,8 @@ public class MartialCompetitionController extends BladeController {
@Operation(summary = "分页列表", description = "分页查询") @Operation(summary = "分页列表", description = "分页查询")
public R<IPage<MartialCompetition>> list(MartialCompetition competition, Query query) { public R<IPage<MartialCompetition>> list(MartialCompetition competition, Query query) {
IPage<MartialCompetition> pages = competitionService.page(Condition.getPage(query), Condition.getQueryWrapper(competition)); IPage<MartialCompetition> pages = competitionService.page(Condition.getPage(query), Condition.getQueryWrapper(competition));
List<MartialCompetition> pagelist = pages.getRecords(); List<MartialCompetition> pageList = pages.getRecords();
for (MartialCompetition martialCompetition : pagelist) { for (MartialCompetition martialCompetition : pageList) {
// Count distinct participants by id_card
Long cnt = ((MartialAthleteMapper) martialAthleteService.getBaseMapper()).countDistinctParticipants(martialCompetition.getId()); Long cnt = ((MartialAthleteMapper) martialAthleteService.getBaseMapper()).countDistinctParticipants(martialCompetition.getId());
martialCompetition.setTotalParticipants(cnt != null ? cnt.intValue() : 0); martialCompetition.setTotalParticipants(cnt != null ? cnt.intValue() : 0);
} }
@@ -71,8 +72,10 @@ public class MartialCompetitionController extends BladeController {
* 新增或修改 * 新增或修改
*/ */
@PostMapping("/submit") @PostMapping("/submit")
@Operation(summary = "新增或修改", description = "传入实体") @Operation(summary = "新增或修改", description = "传入提交DTO")
public R<MartialCompetition> submit(@RequestBody MartialCompetition competition) { public R<MartialCompetition> submit(@Valid @RequestBody MartialCompetitionSubmitDTO submitDTO) {
MartialCompetition competition = new MartialCompetition();
BeanUtils.copyProperties(submitDTO, competition);
competitionService.saveOrUpdate(competition); competitionService.saveOrUpdate(competition);
return R.data(competition); return R.data(competition);
} }
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
@@ -37,6 +38,7 @@ import org.springblade.modules.martial.mapper.MartialScheduleStatusMapper;
import org.springblade.modules.martial.mapper.MartialScheduleGroupMapper; import org.springblade.modules.martial.mapper.MartialScheduleGroupMapper;
import org.springblade.modules.martial.mapper.MartialScheduleParticipantMapper; import org.springblade.modules.martial.mapper.MartialScheduleParticipantMapper;
import org.springblade.modules.martial.mapper.MartialScheduleDetailMapper; import org.springblade.modules.martial.mapper.MartialScheduleDetailMapper;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -59,6 +61,7 @@ import java.util.stream.Collectors;
* @author BladeX * @author BladeX
*/ */
@Slf4j @Slf4j
@Validated
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/mini") @RequestMapping("/mini")
@@ -93,7 +96,7 @@ public class MartialMiniController extends BladeController {
*/ */
@PostMapping("/login") @PostMapping("/login")
@Operation(summary = "登录验证", description = "使用比赛编码和邀请码登录") @Operation(summary = "登录验证", description = "使用比赛编码和邀请码登录")
public R<MiniLoginVO> login(@RequestBody MiniLoginDTO dto) { public R<MiniLoginVO> login(@Valid @RequestBody MiniLoginDTO dto) {
return miniAuthService.login(dto); return miniAuthService.login(dto);
} }
@PostMapping("/score/submit") @PostMapping("/score/submit")
@@ -101,7 +104,7 @@ public class MartialMiniController extends BladeController {
public R submitScore( public R submitScore(
@RequestHeader(value = "Authorization", required = false) String authorization, @RequestHeader(value = "Authorization", required = false) String authorization,
@RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken, @RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken,
@RequestBody org.springblade.modules.martial.pojo.dto.MiniScoreSubmitDTO dto @Valid @RequestBody org.springblade.modules.martial.pojo.dto.MiniScoreSubmitDTO dto
) { ) {
if (dto == null) { if (dto == null) {
return R.fail("请求体不能为空"); return R.fail("请求体不能为空");
@@ -510,7 +513,25 @@ public class MartialMiniController extends BladeController {
*/ */
@PutMapping("/score/modify") @PutMapping("/score/modify")
@Operation(summary = "修改评分", description = "主裁判修改选手总分") @Operation(summary = "修改评分", description = "主裁判修改选手总分")
public R modifyScore(@RequestBody MiniScoreModifyDTO dto) { public R modifyScore(
@RequestHeader(value = "Authorization", required = false) String authorization,
@RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken,
@Valid @RequestBody MiniScoreModifyDTO dto
) {
JudgeAuthContext authContext = resolveJudgeAuthContext(authorization, bladeAuthToken);
if (authContext == null || authContext.getJudgeId() == null) {
return R.fail("登录状态无效或已过期");
}
if (!authContext.isChiefJudge()) {
log.warn("主裁判改分拒绝:无主裁判权限,judgeId={}, role={}, refereeType={}",
authContext.getJudgeId(), authContext.getRole(), authContext.getRefereeType());
return R.fail("无主裁判权限");
}
if (dto.getModifierId() != null && !dto.getModifierId().equals(authContext.getJudgeId())) {
log.warn("主裁判改分身份字段不匹配,已忽略请求体modifierIdpayloadModifierId={}, authJudgeId={}", dto.getModifierId(), authContext.getJudgeId());
}
// 向后兼容:忽略请求体 modifierId,以 token 身份为准
dto.setModifierId(authContext.getJudgeId());
boolean success = scoreService.modifyScoreByAdmin(dto); boolean success = scoreService.modifyScoreByAdmin(dto);
return success ? R.success("修改成功") : R.fail("修改失败"); return success ? R.success("修改成功") : R.fail("修改失败");
} }
@@ -803,7 +824,7 @@ public class MartialMiniController extends BladeController {
public R confirmByChiefJudge( public R confirmByChiefJudge(
@RequestHeader(value = "Authorization", required = false) String authorization, @RequestHeader(value = "Authorization", required = false) String authorization,
@RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken, @RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken,
@RequestBody ChiefJudgeConfirmDTO dto @Valid @RequestBody ChiefJudgeConfirmDTO dto
) { ) {
if (dto == null) { if (dto == null) {
return R.fail("参数错误"); return R.fail("参数错误");
@@ -838,7 +859,7 @@ public class MartialMiniController extends BladeController {
public R confirmByGeneralJudge( public R confirmByGeneralJudge(
@RequestHeader(value = "Authorization", required = false) String authorization, @RequestHeader(value = "Authorization", required = false) String authorization,
@RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken, @RequestHeader(value = "Blade-Auth", required = false) String bladeAuthToken,
@RequestBody GeneralJudgeConfirmDTO dto @Valid @RequestBody GeneralJudgeConfirmDTO dto
) { ) {
if (dto == null) { if (dto == null) {
return R.fail("参数错误"); return R.fail("参数错误");
@@ -4,12 +4,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Query; import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.MartialAthlete; import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.pojo.entity.MartialCompetition; import org.springblade.modules.martial.pojo.entity.MartialCompetition;
@@ -27,6 +30,7 @@ import org.springblade.modules.martial.service.IMartialRegistrationOrderService;
import org.springblade.modules.martial.service.IMartialTeamService; import org.springblade.modules.martial.service.IMartialTeamService;
import org.springblade.modules.martial.mapper.MartialTeamMemberMapper; import org.springblade.modules.martial.mapper.MartialTeamMemberMapper;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -35,6 +39,7 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@Validated
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/martial/registrationOrder") @RequestMapping("/martial/registrationOrder")
@@ -49,12 +54,14 @@ public class MartialRegistrationOrderController extends BladeController {
private final MartialTeamMemberMapper teamMemberMapper; private final MartialTeamMemberMapper teamMemberMapper;
@GetMapping("/detail") @GetMapping("/detail")
@PreAuth(RoleConstant.HAS_ROLE_USER)
@Operation(summary = "详情", description = "传入ID") @Operation(summary = "详情", description = "传入ID")
public R detail(@RequestParam Long id) { public R detail(@RequestParam Long id) {
return R.data(registrationOrderService.getDetailWithRelations(id)); return R.data(registrationOrderService.getDetailWithRelations(id));
} }
@GetMapping("/list") @GetMapping("/list")
@PreAuth(RoleConstant.HAS_ROLE_USER)
@Operation(summary = "分页列表", description = "分页查询当前用户的报名记录") @Operation(summary = "分页列表", description = "分页查询当前用户的报名记录")
public R<IPage<MartialRegistrationOrderVO>> list(MartialRegistrationOrder registrationOrder, Query query) { public R<IPage<MartialRegistrationOrderVO>> list(MartialRegistrationOrder registrationOrder, Query query) {
Long userId = AuthUtil.getUserId(); Long userId = AuthUtil.getUserId();
@@ -67,6 +74,7 @@ public class MartialRegistrationOrderController extends BladeController {
} }
@GetMapping("/organization-stats") @GetMapping("/organization-stats")
@PreAuth(RoleConstant.HAS_ROLE_USER)
@Operation(summary = "单位统计", description = "按单位统计运动员、项目、金额") @Operation(summary = "单位统计", description = "按单位统计运动员、项目、金额")
public R<List<OrganizationStatsVO>> getOrganizationStats(@RequestParam Long competitionId) { public R<List<OrganizationStatsVO>> getOrganizationStats(@RequestParam Long competitionId) {
log.info("获取单位统计: competitionId={}", competitionId); log.info("获取单位统计: competitionId={}", competitionId);
@@ -253,9 +261,10 @@ public class MartialRegistrationOrderController extends BladeController {
} }
@PostMapping("/submit") @PostMapping("/submit")
@PreAuth(RoleConstant.HAS_ROLE_USER)
@Operation(summary = "提交报名", description = "提交报名订单并关联选手或集体") @Operation(summary = "提交报名", description = "提交报名订单并关联选手或集体")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public R submit(@RequestBody RegistrationSubmitDTO dto) { public R submit(@Valid @RequestBody RegistrationSubmitDTO dto) {
log.info("=== 提交报名订单 ==="); log.info("=== 提交报名订单 ===");
log.info("订单号: {}", dto.getOrderNo()); log.info("订单号: {}", dto.getOrderNo());
log.info("赛事ID: {}", dto.getCompetitionId()); log.info("赛事ID: {}", dto.getCompetitionId());
@@ -2,18 +2,22 @@ package org.springblade.modules.martial.controller;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.secure.BladeUser; import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.annotation.PreAuth;
import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.modules.martial.config.ScheduleConfig; import org.springblade.modules.martial.config.ScheduleConfig;
import org.springblade.modules.martial.pojo.dto.MoveScheduleGroupDTO; import org.springblade.modules.martial.pojo.dto.MoveScheduleGroupDTO;
import org.springblade.modules.martial.pojo.dto.SaveScheduleDraftDTO; import org.springblade.modules.martial.pojo.dto.SaveScheduleDraftDTO;
import org.springblade.modules.martial.pojo.dto.ScheduleResultDTO; import org.springblade.modules.martial.pojo.dto.ScheduleResultDTO;
import org.springblade.modules.martial.service.IMartialScheduleArrangeService; import org.springblade.modules.martial.service.IMartialScheduleArrangeService;
import org.springblade.modules.martial.service.IMartialScheduleService; import org.springblade.modules.martial.service.IMartialScheduleService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.HashMap; import java.util.HashMap;
@@ -25,8 +29,10 @@ import java.util.Map;
* @author BladeX * @author BladeX
*/ */
@Slf4j @Slf4j
@Validated
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
@RequestMapping("/martial/schedule") @RequestMapping("/martial/schedule")
@Tag(name = "赛程编排管理", description = "赛程自动编排接口") @Tag(name = "赛程编排管理", description = "赛程自动编排接口")
public class MartialScheduleArrangeController extends BladeController { public class MartialScheduleArrangeController extends BladeController {
@@ -72,7 +78,7 @@ public class MartialScheduleArrangeController extends BladeController {
*/ */
@PostMapping("/save-draft") @PostMapping("/save-draft")
@Operation(summary = "保存编排草稿", description = "传入编排草稿数据") @Operation(summary = "保存编排草稿", description = "传入编排草稿数据")
public R saveDraftSchedule(@RequestBody SaveScheduleDraftDTO dto) { public R saveDraftSchedule(@Valid @RequestBody SaveScheduleDraftDTO dto) {
try { try {
boolean success = scheduleService.saveDraftSchedule(dto); boolean success = scheduleService.saveDraftSchedule(dto);
return success ? R.success("草稿保存成功") : R.fail("草稿保存失败"); return success ? R.success("草稿保存成功") : R.fail("草稿保存失败");
@@ -87,7 +93,7 @@ public class MartialScheduleArrangeController extends BladeController {
*/ */
@PostMapping("/save-and-lock") @PostMapping("/save-and-lock")
@Operation(summary = "完成编排并锁定", description = "传入赛事ID") @Operation(summary = "完成编排并锁定", description = "传入赛事ID")
public R saveAndLock(@RequestBody SaveScheduleDraftDTO dto) { public R saveAndLock(@Valid @RequestBody SaveScheduleDraftDTO dto) {
try { try {
BladeUser user = AuthUtil.getUser(); BladeUser user = AuthUtil.getUser();
String userId = user != null ? user.getUserName() : "system"; String userId = user != null ? user.getUserName() : "system";
@@ -120,7 +126,7 @@ public class MartialScheduleArrangeController extends BladeController {
*/ */
@PostMapping("/move-group") @PostMapping("/move-group")
@Operation(summary = "移动赛程分组", description = "将分组移动到指定场地和时间段") @Operation(summary = "移动赛程分组", description = "将分组移动到指定场地和时间段")
public R moveGroup(@RequestBody MoveScheduleGroupDTO dto) { public R moveGroup(@Valid @RequestBody MoveScheduleGroupDTO dto) {
try { try {
boolean success = scheduleService.moveScheduleGroup(dto); boolean success = scheduleService.moveScheduleGroup(dto);
return success ? R.success("分组移动成功") : R.fail("分组移动失败"); return success ? R.success("分组移动成功") : R.fail("分组移动失败");
@@ -154,7 +160,7 @@ public class MartialScheduleArrangeController extends BladeController {
*/ */
@PostMapping("/adjust-order") @PostMapping("/adjust-order")
@Operation(summary = "调整出场顺序", description = "调整参赛者的出场顺序") @Operation(summary = "调整出场顺序", description = "调整参赛者的出场顺序")
public R adjustOrder(@RequestBody org.springblade.modules.martial.pojo.dto.AdjustOrderDTO dto) { public R adjustOrder(@Valid @RequestBody org.springblade.modules.martial.pojo.dto.AdjustOrderDTO dto) {
try { try {
boolean success = scheduleService.adjustOrder(dto); boolean success = scheduleService.adjustOrder(dto);
return success ? R.success("顺序调整成功") : R.fail("顺序调整失败"); return success ? R.success("顺序调整成功") : R.fail("顺序调整失败");
@@ -169,7 +175,7 @@ public class MartialScheduleArrangeController extends BladeController {
*/ */
@PostMapping("/save-dispatch") @PostMapping("/save-dispatch")
@Operation(summary = "批量保存调度", description = "批量保存调度调整") @Operation(summary = "批量保存调度", description = "批量保存调度调整")
public R saveDispatch(@RequestBody org.springblade.modules.martial.pojo.dto.SaveDispatchDTO dto) { public R saveDispatch(@Valid @RequestBody org.springblade.modules.martial.pojo.dto.SaveDispatchDTO dto) {
try { try {
boolean success = scheduleService.saveDispatch(dto); boolean success = scheduleService.saveDispatch(dto);
return success ? R.success("调度保存成功") : R.fail("调度保存失败"); return success ? R.success("调度保存成功") : R.fail("调度保存失败");
@@ -1,6 +1,8 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
/** /**
@@ -15,18 +17,21 @@ public class AdjustOrderDTO {
/** /**
* 编排明细ID * 编排明细ID
*/ */
@NotNull(message = "编排明细ID不能为空")
@Schema(description = "编排明细ID") @Schema(description = "编排明细ID")
private Long detailId; private Long detailId;
/** /**
* 参赛者记录ID * 参赛者记录ID
*/ */
@NotNull(message = "参赛者记录ID不能为空")
@Schema(description = "参赛者记录ID") @Schema(description = "参赛者记录ID")
private Long participantId; private Long participantId;
/** /**
* 调整动作 * 调整动作
*/ */
@NotBlank(message = "调整动作不能为空")
@Schema(description = "调整动作(move_up=上移, move_down=下移, swap=交换)") @Schema(description = "调整动作(move_up=上移, move_down=下移, swap=交换)")
private String action; private String action;
@@ -1,6 +1,7 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -12,10 +13,11 @@ import java.math.BigDecimal;
@Schema(description = "主裁判确认评分DTO") @Schema(description = "主裁判确认评分DTO")
public class ChiefJudgeConfirmDTO { public class ChiefJudgeConfirmDTO {
@NotBlank(message = "成绩ID不能为空")
@Schema(description = "成绩ID") @Schema(description = "成绩ID")
private String resultId; private String resultId;
@Schema(description = "主裁判ID") @Schema(description = "主裁判ID(兼容字段,实际以后端token身份为准)")
private String chiefJudgeId; private String chiefJudgeId;
@Schema(description = "确认/修改后的分数(null表示直接确认原分数)") @Schema(description = "确认/修改后的分数(null表示直接确认原分数)")
@@ -1,6 +1,7 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -12,10 +13,11 @@ import java.math.BigDecimal;
@Schema(description = "总裁确认评分DTO") @Schema(description = "总裁确认评分DTO")
public class GeneralJudgeConfirmDTO { public class GeneralJudgeConfirmDTO {
@NotBlank(message = "成绩ID不能为空")
@Schema(description = "成绩ID") @Schema(description = "成绩ID")
private String resultId; private String resultId;
@Schema(description = "总裁ID") @Schema(description = "总裁ID(兼容字段,实际以后端token身份为准)")
private String generalJudgeId; private String generalJudgeId;
@Schema(description = "确认/修改后的分数(null表示直接确认原分数)") @Schema(description = "确认/修改后的分数(null表示直接确认原分数)")
@@ -0,0 +1,87 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 赛事提交DTO(用于替代实体直收,避免越权字段写入)
*/
@Data
@Schema(description = "赛事提交DTO")
public class MartialCompetitionSubmitDTO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "赛事ID(更新时传)")
private Long id;
@NotBlank(message = "赛事名称不能为空")
@Schema(description = "赛事名称")
private String competitionName;
@NotBlank(message = "赛事编码不能为空")
@Schema(description = "赛事编码")
private String competitionCode;
@Schema(description = "主办单位")
private String organizer;
@Schema(description = "地区")
private String location;
@Schema(description = "详细地点")
private String venue;
@Schema(description = "报名开始时间")
private LocalDateTime registrationStartTime;
@Schema(description = "报名结束时间")
private LocalDateTime registrationEndTime;
@Schema(description = "比赛开始时间")
private LocalDateTime competitionStartTime;
@Schema(description = "比赛结束时间")
private LocalDateTime competitionEndTime;
@Schema(description = "赛事简介")
private String introduction;
@Schema(description = "宣传图片(JSON数组)")
private String posterImages;
@Schema(description = "联系人")
private String contactPerson;
@Schema(description = "联系电话")
private String contactPhone;
@Schema(description = "联系邮箱")
private String contactEmail;
@Schema(description = "竞赛规则")
private String rules;
@Schema(description = "参赛要求")
private String requirements;
@Schema(description = "奖项设置")
private String awards;
@Schema(description = "规程文件(JSON数组)")
private String regulationFiles;
@Schema(description = "报名总人数")
private Integer totalParticipants;
@Schema(description = "报名总金额")
private BigDecimal totalAmount;
@Schema(description = "是否精品:1是,2否")
private Integer isCompeBoutique;
}
@@ -1,6 +1,7 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@@ -16,9 +17,11 @@ public class MiniLoginDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@NotBlank(message = "比赛编码不能为空")
@Schema(description = "比赛编码") @Schema(description = "比赛编码")
private String matchCode; private String matchCode;
@NotBlank(message = "邀请码不能为空")
@Schema(description = "邀请码") @Schema(description = "邀请码")
private String inviteCode; private String inviteCode;
@@ -1,6 +1,9 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@@ -17,18 +20,23 @@ public class MiniScoreModifyDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@NotNull(message = "选手ID不能为空")
@Schema(description = "选手ID") @Schema(description = "选手ID")
private Long athleteId; private Long athleteId;
@Schema(description = "修改者ID(主裁判ID") @Schema(description = "修改者ID(主裁判ID,兼容字段,实际以后端token身份为准")
private Long modifierId; private Long modifierId;
@NotNull(message = "修改后的分数不能为空")
@DecimalMin(value = "5.000", message = "修改分数不能低于5.000")
@DecimalMax(value = "10.000", message = "修改分数不能高于10.000")
@Schema(description = "修改后的分数") @Schema(description = "修改后的分数")
private BigDecimal modifiedScore; private BigDecimal modifiedScore;
@Schema(description = "修改原因/备注") @Schema(description = "修改原因/备注")
private String note; private String note;
@NotNull(message = "场地ID不能为空")
@Schema(description = "场地ID") @Schema(description = "场地ID")
private Long venueId; private Long venueId;
} }
@@ -1,6 +1,10 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@@ -20,12 +24,16 @@ public class MiniScoreSubmitDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@NotBlank(message = "选手ID不能为空")
@Schema(description = "选手ID") @Schema(description = "选手ID")
private String athleteId; private String athleteId;
@Schema(description = "评委ID") @Schema(description = "评委ID(兼容字段,实际以后端token身份为准)")
private String judgeId; private String judgeId;
@NotNull(message = "评分不能为空")
@DecimalMin(value = "5.000", message = "评分不能低于5.000")
@DecimalMax(value = "10.000", message = "评分不能高于10.000")
@Schema(description = "评分") @Schema(description = "评分")
private BigDecimal score; private BigDecimal score;
@@ -35,12 +43,15 @@ public class MiniScoreSubmitDTO implements Serializable {
@Schema(description = "备注") @Schema(description = "备注")
private String note; private String note;
@NotBlank(message = "项目ID不能为空")
@Schema(description = "项目ID") @Schema(description = "项目ID")
private String projectId; private String projectId;
@NotBlank(message = "赛事ID不能为空")
@Schema(description = "赛事ID") @Schema(description = "赛事ID")
private String competitionId; private String competitionId;
@NotBlank(message = "场地ID不能为空")
@Schema(description = "场地ID") @Schema(description = "场地ID")
private String venueId; private String venueId;
@@ -1,6 +1,8 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
/** /**
@@ -15,18 +17,22 @@ public class MoveScheduleGroupDTO {
/** /**
* 分组ID * 分组ID
*/ */
@NotNull(message = "分组ID不能为空")
@Schema(description = "分组ID") @Schema(description = "分组ID")
private Long groupId; private Long groupId;
/** /**
* 目标场地ID * 目标场地ID
*/ */
@NotNull(message = "目标场地ID不能为空")
@Schema(description = "目标场地ID") @Schema(description = "目标场地ID")
private Long targetVenueId; private Long targetVenueId;
/** /**
* 目标时间段索引 * 目标时间段索引
*/ */
@NotNull(message = "目标时间段索引不能为空")
@Min(value = 0, message = "目标时间段索引不能小于0")
@Schema(description = "目标时间段索引(0=第1天上午,1=第1天下午,2=第2天上午...)") @Schema(description = "目标时间段索引(0=第1天上午,1=第1天下午,2=第2天上午...)")
private Integer targetTimeSlotIndex; private Integer targetTimeSlotIndex;
@@ -1,6 +1,9 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -9,12 +12,15 @@ import java.math.BigDecimal;
@Schema(description = "报名提交数据") @Schema(description = "报名提交数据")
public class RegistrationSubmitDTO { public class RegistrationSubmitDTO {
@NotBlank(message = "订单号不能为空")
@Schema(description = "订单号") @Schema(description = "订单号")
private String orderNo; private String orderNo;
@NotNull(message = "赛事ID不能为空")
@Schema(description = "赛事ID") @Schema(description = "赛事ID")
private Long competitionId; private Long competitionId;
@NotBlank(message = "项目ID列表不能为空")
@Schema(description = "项目ID列表") @Schema(description = "项目ID列表")
private String projectIds; private String projectIds;
@@ -24,10 +30,12 @@ public class RegistrationSubmitDTO {
@Schema(description = "集体ID列表(集体项目)") @Schema(description = "集体ID列表(集体项目)")
private String teamIds; private String teamIds;
@NotBlank(message = "联系电话不能为空")
@Schema(description = "联系电话") @Schema(description = "联系电话")
private String contactPhone; private String contactPhone;
@NotNull(message = "总金额不能为空")
@DecimalMin(value = "0.00", message = "总金额不能为负数")
@Schema(description = "总金额") @Schema(description = "总金额")
private BigDecimal totalAmount; private BigDecimal totalAmount;
} }
@@ -1,6 +1,8 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@@ -17,18 +19,21 @@ public class SaveDispatchDTO {
/** /**
* 赛事ID * 赛事ID
*/ */
@NotNull(message = "赛事ID不能为空")
@Schema(description = "赛事ID") @Schema(description = "赛事ID")
private Long competitionId; private Long competitionId;
/** /**
* 调整列表 * 调整列表
*/ */
@Valid
@Schema(description = "调整列表") @Schema(description = "调整列表")
private List<DetailAdjustment> adjustments; private List<DetailAdjustment> adjustments;
/** /**
* 分组排序列表 * 分组排序列表
*/ */
@Valid
@Schema(description = "分组排序列表") @Schema(description = "分组排序列表")
private List<GroupOrder> groupOrders; private List<GroupOrder> groupOrders;
@@ -42,12 +47,14 @@ public class SaveDispatchDTO {
/** /**
* 编排明细ID * 编排明细ID
*/ */
@NotNull(message = "编排明细ID不能为空")
@Schema(description = "编排明细ID") @Schema(description = "编排明细ID")
private Long detailId; private Long detailId;
/** /**
* 参赛者列表 * 参赛者列表
*/ */
@Valid
@Schema(description = "参赛者列表") @Schema(description = "参赛者列表")
private List<ParticipantOrder> participants; private List<ParticipantOrder> participants;
@@ -63,24 +70,28 @@ public class SaveDispatchDTO {
/** /**
* 分组ID * 分组ID
*/ */
@NotNull(message = "分组ID不能为空")
@Schema(description = "分组ID") @Schema(description = "分组ID")
private Long groupId; private Long groupId;
/** /**
* 分组顺序 * 分组顺序
*/ */
@NotNull(message = "分组顺序不能为空")
@Schema(description = "分组顺序") @Schema(description = "分组顺序")
private Integer groupOrder; private Integer groupOrder;
/** /**
* 场地ID * 场地ID
*/ */
@NotNull(message = "场地ID不能为空")
@Schema(description = "场地ID") @Schema(description = "场地ID")
private Long venueId; private Long venueId;
/** /**
* 时间段索引 * 时间段索引
*/ */
@NotNull(message = "时间段索引不能为空")
@Schema(description = "时间段索引") @Schema(description = "时间段索引")
private Integer timeSlotIndex; private Integer timeSlotIndex;
@@ -96,12 +107,14 @@ public class SaveDispatchDTO {
/** /**
* 参赛者记录ID * 参赛者记录ID
*/ */
@NotNull(message = "参赛者记录ID不能为空")
@Schema(description = "参赛者记录ID") @Schema(description = "参赛者记录ID")
private Long id; private Long id;
/** /**
* 出场顺序 * 出场顺序
*/ */
@NotNull(message = "出场顺序不能为空")
@Schema(description = "出场顺序") @Schema(description = "出场顺序")
private Integer performanceOrder; private Integer performanceOrder;
@@ -1,6 +1,9 @@
package org.springblade.modules.martial.pojo.dto; package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@@ -20,6 +23,7 @@ public class SaveScheduleDraftDTO implements Serializable {
/** /**
* 赛事ID * 赛事ID
*/ */
@NotNull(message = "赛事ID不能为空")
@Schema(description = "赛事ID") @Schema(description = "赛事ID")
private Long competitionId; private Long competitionId;
@@ -32,6 +36,8 @@ public class SaveScheduleDraftDTO implements Serializable {
/** /**
* 竞赛分组数据 * 竞赛分组数据
*/ */
@NotEmpty(message = "竞赛分组数据不能为空")
@Valid
@Schema(description = "竞赛分组数据") @Schema(description = "竞赛分组数据")
private List<CompetitionGroupDTO> competitionGroups; private List<CompetitionGroupDTO> competitionGroups;