fix: 修复批量导入裁判时venueId和projects参数丢失问题

- BatchGenerateInviteDTO添加venueId和projects字段
- batchGenerateInviteCode方法传递venueId和projects给generateDto
- MartialMiniController添加competitionId参数过滤选手
- 新增RegistrationSubmitDTO

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-26 15:44:29 +08:00
parent 67908a4dd0
commit dca5e5050f
71 changed files with 225 additions and 33 deletions

View File

@@ -42,6 +42,48 @@ services:
networks: networks:
- martial-network - martial-network
# MinIO 对象存储
minio:
image: minio/minio:RELEASE.2024-12-18T13-15-44Z
container_name: minio
environment:
MINIO_ROOT_USER: "JohnSion"
MINIO_ROOT_PASSWORD: "v!*BTket4oagDdw"
TZ: "Asia/Shanghai"
command: server /data --console-address ":9001"
volumes:
- ./minio_data:/data
ports:
- "9000:9000"
- "9001:9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- martial-network
# MinIO 初始化 - 创建桶和设置策略
minio-init:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
entrypoint: >
sh -c "
mc alias set local http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD} &&
mc mb -p local/assets || true &&
mc anonymous set download local/assets || true
"
environment:
MINIO_ROOT_USER: "JohnSion"
MINIO_ROOT_PASSWORD: "v!*BTket4oagDdw"
restart: "no"
networks:
- martial-network
# 后端应用 # 后端应用
martial-api: martial-api:
build: build:
@@ -52,11 +94,9 @@ services:
environment: environment:
SPRING_PROFILE: dev SPRING_PROFILE: dev
JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseG1GC" JAVA_OPTS: "-Xms512m -Xmx1024m -XX:+UseG1GC"
# 覆盖数据库连接配置
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/martial_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/martial_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: 123456 SPRING_DATASOURCE_PASSWORD: 123456
# 覆盖 Redis 连接配置
SPRING_DATA_REDIS_HOST: redis SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379 SPRING_DATA_REDIS_PORT: 6379
SPRING_DATA_REDIS_PASSWORD: 123456 SPRING_DATA_REDIS_PASSWORD: 123456

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
{"version":"1","format":"xl-single","id":"7aa712c5-97fa-4608-aafd-5e91b82dcaaa","xl":{"version":"3","this":"a0620b80-1f59-4689-8995-4d5bcde4044d","sets":[["a0620b80-1f59-4689-8995-4d5bcde4044d"]],"distributionAlgo":"SIPMOD+PARITY"}}

Binary file not shown.

View File

@@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController; import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tool.api.R; import org.springblade.core.tool.api.R;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesAttachment; import org.springblade.modules.martial.pojo.entity.MartialCompetitionAttachment;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesChapter; import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesChapter;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesContent; import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesContent;
import org.springblade.modules.martial.pojo.vo.MartialCompetitionRulesVO; import org.springblade.modules.martial.pojo.vo.MartialCompetitionRulesVO;
@@ -45,8 +45,8 @@ public class MartialCompetitionRulesController extends BladeController {
*/ */
@GetMapping("/attachment/list") @GetMapping("/attachment/list")
@Operation(summary = "获取附件列表", description = "管理端获取附件列表") @Operation(summary = "获取附件列表", description = "管理端获取附件列表")
public R<List<MartialCompetitionRulesAttachment>> getAttachmentList(@RequestParam Long competitionId) { public R<List<MartialCompetitionAttachment>> getAttachmentList(@RequestParam Long competitionId) {
List<MartialCompetitionRulesAttachment> list = rulesService.getAttachmentList(competitionId); List<MartialCompetitionAttachment> list = rulesService.getAttachmentList(competitionId);
return R.data(list); return R.data(list);
} }
@@ -55,7 +55,7 @@ public class MartialCompetitionRulesController extends BladeController {
*/ */
@PostMapping("/attachment/save") @PostMapping("/attachment/save")
@Operation(summary = "保存附件", description = "新增或修改附件") @Operation(summary = "保存附件", description = "新增或修改附件")
public R saveAttachment(@RequestBody MartialCompetitionRulesAttachment attachment) { public R saveAttachment(@RequestBody MartialCompetitionAttachment attachment) {
return R.status(rulesService.saveAttachment(attachment)); return R.status(rulesService.saveAttachment(attachment));
} }

View File

@@ -328,6 +328,7 @@ public class MartialMiniController extends BladeController {
@RequestParam Integer refereeType, @RequestParam Integer refereeType,
@RequestParam(required = false) Long projectId, @RequestParam(required = false) Long projectId,
@RequestParam(required = false) Long venueId, @RequestParam(required = false) Long venueId,
@RequestParam(required = false) Long competitionId,
@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size @RequestParam(defaultValue = "10") Integer size
) { ) {
@@ -335,6 +336,11 @@ public class MartialMiniController extends BladeController {
LambdaQueryWrapper<MartialAthlete> athleteQuery = new LambdaQueryWrapper<>(); LambdaQueryWrapper<MartialAthlete> athleteQuery = new LambdaQueryWrapper<>();
athleteQuery.eq(MartialAthlete::getIsDeleted, 0); athleteQuery.eq(MartialAthlete::getIsDeleted, 0);
// 按比赛ID过滤重要确保只显示当前比赛的选手
if (competitionId != null) {
athleteQuery.eq(MartialAthlete::getCompetitionId, competitionId);
}
if (projectId != null) { if (projectId != null) {
athleteQuery.eq(MartialAthlete::getProjectId, projectId); athleteQuery.eq(MartialAthlete::getProjectId, projectId);
} }

View File

@@ -1,23 +1,34 @@
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.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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 lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
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.Condition;
import org.springblade.core.mp.support.Query; import org.springblade.core.mp.support.Query;
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.utils.Func; import org.springblade.core.tool.utils.Func;
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
import org.springblade.modules.martial.pojo.entity.MartialRegistrationOrder; import org.springblade.modules.martial.pojo.entity.MartialRegistrationOrder;
import org.springblade.modules.martial.pojo.dto.RegistrationSubmitDTO;
import org.springblade.modules.martial.service.IMartialAthleteService;
import org.springblade.modules.martial.service.IMartialRegistrationOrderService; import org.springblade.modules.martial.service.IMartialRegistrationOrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
/** /**
* 报名订单 控制器 * 报名订单 控制器
* *
* @author BladeX * @author BladeX
*/ */
@Slf4j
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/martial/registrationOrder") @RequestMapping("/martial/registrationOrder")
@@ -25,6 +36,7 @@ import org.springframework.web.bind.annotation.*;
public class MartialRegistrationOrderController extends BladeController { public class MartialRegistrationOrderController extends BladeController {
private final IMartialRegistrationOrderService registrationOrderService; private final IMartialRegistrationOrderService registrationOrderService;
private final IMartialAthleteService athleteService;
/** /**
* 详情 * 详情
@@ -37,22 +49,93 @@ public class MartialRegistrationOrderController extends BladeController {
} }
/** /**
* 分页列表 * 分页列表 - 只返回当前用户的报名记录
*/ */
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "分页列表", description = "分页查询") @Operation(summary = "分页列表", description = "分页查询当前用户的报名记录")
public R<IPage<MartialRegistrationOrder>> list(MartialRegistrationOrder registrationOrder, Query query) { public R<IPage<MartialRegistrationOrder>> list(MartialRegistrationOrder registrationOrder, Query query) {
IPage<MartialRegistrationOrder> pages = registrationOrderService.page(Condition.getPage(query), Condition.getQueryWrapper(registrationOrder)); // 获取当前登录用户ID
Long userId = AuthUtil.getUserId();
// 构建查询条件 - 只查询当前用户的订单
LambdaQueryWrapper<MartialRegistrationOrder> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(MartialRegistrationOrder::getUserId, userId);
// 如果传入了状态参数,添加状态过滤
if (registrationOrder.getStatus() != null) {
queryWrapper.eq(MartialRegistrationOrder::getStatus, registrationOrder.getStatus());
}
// 按创建时间倒序
queryWrapper.orderByDesc(MartialRegistrationOrder::getCreateTime);
// 分页查询
IPage<MartialRegistrationOrder> page = new Page<>(query.getCurrent(), query.getSize());
IPage<MartialRegistrationOrder> pages = registrationOrderService.page(page, queryWrapper);
return R.data(pages); return R.data(pages);
} }
/** /**
* 新增或修改 * 提交报名订单
* 接收前端传来的 athleteIds 和 projectIds更新选手的 orderId
*/ */
@PostMapping("/submit") @PostMapping("/submit")
@Operation(summary = "新增或修改", description = "传入实体") @Operation(summary = "提交报名", description = "提交报名订单并关联选手")
public R submit(@RequestBody MartialRegistrationOrder registrationOrder) { @Transactional(rollbackFor = Exception.class)
return R.status(registrationOrderService.saveOrUpdate(registrationOrder)); public R submit(@RequestBody RegistrationSubmitDTO dto) {
log.info("=== 提交报名订单 ===");
log.info("订单号: {}", dto.getOrderNo());
log.info("赛事ID: {}", dto.getCompetitionId());
log.info("项目IDs: {}", dto.getProjectIds());
log.info("选手IDs: {}", dto.getAthleteIds());
log.info("联系电话: {}", dto.getContactPhone());
log.info("总金额: {}", dto.getTotalAmount());
// 1. 创建订单实体
MartialRegistrationOrder order = new MartialRegistrationOrder();
order.setOrderNo(dto.getOrderNo());
order.setCompetitionId(dto.getCompetitionId());
order.setContactPhone(dto.getContactPhone());
order.setTotalAmount(dto.getTotalAmount());
order.setUserId(AuthUtil.getUserId());
order.setUserName(AuthUtil.getUserName());
// 解析选手ID列表
List<Long> athleteIds = Func.toLongList(dto.getAthleteIds());
order.setTotalParticipants(athleteIds.size());
// 2. 保存订单
boolean saved = registrationOrderService.save(order);
if (!saved) {
return R.fail("创建订单失败");
}
Long orderId = order.getId();
log.info("订单创建成功订单ID: {}", orderId);
// 3. 解析项目ID列表
List<Long> projectIds = Func.toLongList(dto.getProjectIds());
Long firstProjectId = projectIds.isEmpty() ? null : projectIds.get(0);
// 4. 更新选手的 orderId、competitionId 和 projectId
if (!athleteIds.isEmpty()) {
LambdaUpdateWrapper<MartialAthlete> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(MartialAthlete::getId, athleteIds)
.set(MartialAthlete::getOrderId, orderId)
.set(MartialAthlete::getCompetitionId, dto.getCompetitionId());
// 如果只有一个项目设置项目ID
if (firstProjectId != null) {
updateWrapper.set(MartialAthlete::getProjectId, firstProjectId);
}
boolean updated = athleteService.update(updateWrapper);
log.info("更新选手关联,选手数量: {}, 更新结果: {}", athleteIds.size(), updated);
}
// 5. 返回订单信息
return R.data(order);
} }
/** /**

View File

@@ -25,4 +25,10 @@ public class BatchGenerateInviteDTO {
@Schema(description = "过期天数默认30天") @Schema(description = "过期天数默认30天")
private Integer expireDays = 30; private Integer expireDays = 30;
@Schema(description = "场地ID")
private Long venueId;
@Schema(description = "项目ID列表JSON字符串")
private String projects;
} }

View File

@@ -0,0 +1,53 @@
package org.springblade.modules.martial.pojo.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 报名提交DTO
*
* @author BladeX
*/
@Data
@Schema(description = "报名提交数据")
public class RegistrationSubmitDTO {
/**
* 订单号
*/
@Schema(description = "订单号")
private String orderNo;
/**
* 赛事ID
*/
@Schema(description = "赛事ID")
private Long competitionId;
/**
* 项目ID列表逗号分隔
*/
@Schema(description = "项目ID列表")
private String projectIds;
/**
* 选手ID列表逗号分隔
*/
@Schema(description = "选手ID列表")
private String athleteIds;
/**
* 联系电话
*/
@Schema(description = "联系电话")
private String contactPhone;
/**
* 总金额
*/
@Schema(description = "总金额")
private BigDecimal totalAmount;
}

View File

@@ -16,7 +16,7 @@
*/ */
package org.springblade.modules.martial.service; package org.springblade.modules.martial.service;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesAttachment; import org.springblade.modules.martial.pojo.entity.MartialCompetitionAttachment;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesChapter; import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesChapter;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesContent; import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesContent;
import org.springblade.modules.martial.pojo.vo.MartialCompetitionRulesVO; import org.springblade.modules.martial.pojo.vo.MartialCompetitionRulesVO;
@@ -44,7 +44,7 @@ public interface IMartialCompetitionRulesService {
* @param competitionId 赛事ID * @param competitionId 赛事ID
* @return 附件列表 * @return 附件列表
*/ */
List<MartialCompetitionRulesAttachment> getAttachmentList(Long competitionId); List<MartialCompetitionAttachment> getAttachmentList(Long competitionId);
/** /**
* 保存附件 * 保存附件
@@ -52,7 +52,7 @@ public interface IMartialCompetitionRulesService {
* @param attachment 附件信息 * @param attachment 附件信息
* @return 是否成功 * @return 是否成功
*/ */
boolean saveAttachment(MartialCompetitionRulesAttachment attachment); boolean saveAttachment(MartialCompetitionAttachment attachment);
/** /**
* 删除附件 * 删除附件

View File

@@ -21,11 +21,11 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springblade.core.tool.utils.DateUtil; import org.springblade.core.tool.utils.DateUtil;
import org.springblade.modules.martial.mapper.MartialCompetitionMapper; import org.springblade.modules.martial.mapper.MartialCompetitionMapper;
import org.springblade.modules.martial.mapper.MartialCompetitionRulesAttachmentMapper; import org.springblade.modules.martial.mapper.MartialCompetitionAttachmentMapper;
import org.springblade.modules.martial.mapper.MartialCompetitionRulesChapterMapper; import org.springblade.modules.martial.mapper.MartialCompetitionRulesChapterMapper;
import org.springblade.modules.martial.mapper.MartialCompetitionRulesContentMapper; import org.springblade.modules.martial.mapper.MartialCompetitionRulesContentMapper;
import org.springblade.modules.martial.pojo.entity.MartialCompetition; import org.springblade.modules.martial.pojo.entity.MartialCompetition;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesAttachment; import org.springblade.modules.martial.pojo.entity.MartialCompetitionAttachment;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesChapter; import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesChapter;
import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesContent; import org.springblade.modules.martial.pojo.entity.MartialCompetitionRulesContent;
import org.springblade.modules.martial.pojo.vo.MartialCompetitionRulesVO; import org.springblade.modules.martial.pojo.vo.MartialCompetitionRulesVO;
@@ -47,7 +47,7 @@ import java.util.stream.Collectors;
public class MartialCompetitionRulesServiceImpl implements IMartialCompetitionRulesService { public class MartialCompetitionRulesServiceImpl implements IMartialCompetitionRulesService {
private final MartialCompetitionMapper competitionMapper; private final MartialCompetitionMapper competitionMapper;
private final MartialCompetitionRulesAttachmentMapper attachmentMapper; private final MartialCompetitionAttachmentMapper attachmentMapper;
private final MartialCompetitionRulesChapterMapper chapterMapper; private final MartialCompetitionRulesChapterMapper chapterMapper;
private final MartialCompetitionRulesContentMapper contentMapper; private final MartialCompetitionRulesContentMapper contentMapper;
@@ -63,7 +63,7 @@ public class MartialCompetitionRulesServiceImpl implements IMartialCompetitionRu
} }
// 获取附件列表 // 获取附件列表
List<MartialCompetitionRulesAttachment> attachments = getAttachmentList(competitionId); List<MartialCompetitionAttachment> attachments = getAttachmentList(competitionId);
List<MartialCompetitionRulesVO.AttachmentVO> attachmentVOList = attachments.stream() List<MartialCompetitionRulesVO.AttachmentVO> attachmentVOList = attachments.stream()
.map(this::convertToAttachmentVO) .map(this::convertToAttachmentVO)
.collect(Collectors.toList()); .collect(Collectors.toList());
@@ -89,16 +89,17 @@ public class MartialCompetitionRulesServiceImpl implements IMartialCompetitionRu
} }
@Override @Override
public List<MartialCompetitionRulesAttachment> getAttachmentList(Long competitionId) { public List<MartialCompetitionAttachment> getAttachmentList(Long competitionId) {
LambdaQueryWrapper<MartialCompetitionRulesAttachment> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<MartialCompetitionAttachment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MartialCompetitionRulesAttachment::getCompetitionId, competitionId) wrapper.eq(MartialCompetitionAttachment::getCompetitionId, competitionId)
.eq(MartialCompetitionRulesAttachment::getStatus, 1) .eq(MartialCompetitionAttachment::getAttachmentType, "rules")
.orderByAsc(MartialCompetitionRulesAttachment::getOrderNum); .eq(MartialCompetitionAttachment::getStatus, 1)
.orderByAsc(MartialCompetitionAttachment::getOrderNum);
return attachmentMapper.selectList(wrapper); return attachmentMapper.selectList(wrapper);
} }
@Override @Override
public boolean saveAttachment(MartialCompetitionRulesAttachment attachment) { public boolean saveAttachment(MartialCompetitionAttachment attachment) {
if (attachment.getId() == null) { if (attachment.getId() == null) {
return attachmentMapper.insert(attachment) > 0; return attachmentMapper.insert(attachment) > 0;
} else { } else {
@@ -186,7 +187,7 @@ public class MartialCompetitionRulesServiceImpl implements IMartialCompetitionRu
/** /**
* 转换为附件VO * 转换为附件VO
*/ */
private MartialCompetitionRulesVO.AttachmentVO convertToAttachmentVO(MartialCompetitionRulesAttachment attachment) { private MartialCompetitionRulesVO.AttachmentVO convertToAttachmentVO(MartialCompetitionAttachment attachment) {
MartialCompetitionRulesVO.AttachmentVO vo = new MartialCompetitionRulesVO.AttachmentVO(); MartialCompetitionRulesVO.AttachmentVO vo = new MartialCompetitionRulesVO.AttachmentVO();
vo.setId(attachment.getId()); vo.setId(attachment.getId());
vo.setName(attachment.getFileName()); vo.setName(attachment.getFileName());

View File

@@ -167,6 +167,8 @@ public class MartialJudgeInviteServiceImpl extends ServiceImpl<MartialJudgeInvit
generateDto.setJudgeId(judgeId); generateDto.setJudgeId(judgeId);
generateDto.setRole(dto.getRole()); generateDto.setRole(dto.getRole());
generateDto.setExpireDays(dto.getExpireDays()); generateDto.setExpireDays(dto.getExpireDays());
generateDto.setVenueId(dto.getVenueId());
generateDto.setProjects(dto.getProjects());
MartialJudgeInvite invite = generateInviteCode(generateDto); MartialJudgeInvite invite = generateInviteCode(generateDto);
invites.add(invite); invites.add(invite);

View File

@@ -127,15 +127,15 @@ oss:
#租户模式 #租户模式
tenant-mode: true tenant-mode: true
#oss服务地址 #oss服务地址
endpoint: http://120.197.149.12:9000 endpoint: http://minio:9000
#oss转换服务地址用于内网上传后将返回地址改为转换的外网地址 #oss转换服务地址用于内网上传后将返回地址改为转换的外网地址
transform-endpoint: http://localhost:9000 transform-endpoint: https://martial-oss.aitisai.com
#访问key #访问key
access-key: AKIAIOSFODNN7EXAMPLE access-key: JohnSion
#密钥key #密钥key
secret-key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY secret-key: v!*BTket4oagDdw
#存储桶 #存储桶
bucket-name: equipment bucket-name: assets
#第三方登陆配置 #第三方登陆配置
social: social: