Ver código fonte

feat(app): 添加客户端登录功能和项目状态管理

- 新增 ClientLoginBo 和 ClientLoginVo 数据传输对象
- 实现客户端登录验证逻辑,支持赛事ID、项目ID、密码和裁判号码验证
- 添加项目结束功能,允许将项目状态更新为已结束
- 修复 GameEventProject 中状态字段的注释说明
- 更新控制器映射,添加登录和结束项目接口
- 优化代码格式和注释文档
zhou 1 semana atrás
pai
commit
3c339fb04e

+ 29 - 7
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app_client/ToClientController.java

@@ -7,9 +7,11 @@ import org.dromara.common.log.annotation.Log;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.system.domain.GameEvent;
 import org.dromara.system.domain.GameEventProject;
+import org.dromara.system.domain.bo.ClientLoginBo;
 import org.dromara.system.domain.bo.ClientProjectSaveBo;
 import org.dromara.system.domain.bo.ScorePreviewUpdateBo;
 import org.dromara.system.domain.bo.ScoreSubmitBo;
+import org.dromara.system.domain.vo.ClientLoginVo;
 import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetVo;
 import org.dromara.system.service.app.IToClientService;
@@ -30,14 +32,12 @@ public class ToClientController {
     private final IToClientService toClientService;
 
     /**
-     * 赛事列表项添加/修改接口 (接口4)
+     * 客户端登录 (接口1)
      */
-    @Log(title = "app客户端添加/修改赛事项", businessType = BusinessType.UPDATE)
-    @RepeatSubmit()
-    @PostMapping("/eventSaveOrUpdate")
-    public R<Void> eventSaveOrUpdate(@Validated @RequestBody ClientProjectSaveBo bo) {
-        toClientService.saveOrUpdateEventFromClient(bo);
-        return R.ok();
+    @Log(title = "app客户端登录", businessType = BusinessType.OTHER)
+    @PostMapping("/login")
+    public R<ClientLoginVo> login(@Validated @RequestBody ClientLoginBo bo) {
+        return R.ok(toClientService.login(bo));
     }
 
     /**
@@ -58,6 +58,17 @@ public class ToClientController {
         return R.ok("删除任务已提交,正在后台处理");
     }
 
+    /**
+     * 赛事列表项添加/修改接口 (接口4)
+     */
+    @Log(title = "app客户端添加/修改赛事项", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PostMapping("/eventSaveOrUpdate")
+    public R<Void> eventSaveOrUpdate(@Validated @RequestBody ClientProjectSaveBo bo) {
+        toClientService.saveOrUpdateEventFromClient(bo);
+        return R.ok();
+    }
+
     /**
      * 项目列表接口 (接口5)
      */
@@ -85,6 +96,17 @@ public class ToClientController {
         return R.ok();
     }
 
+    /**
+     * 成绩记录单结束项目接口 (接口7)
+     */
+    @Log(title = "app客户端结束项目", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PostMapping("/endProject")
+    public R<Void> endProject(@RequestParam Long projectId) {
+        toClientService.endProject(projectId);
+        return R.ok();
+    }
+
     /**
      * 成绩预览列表查询 (接口8)
      */

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/GameEventProject.java

@@ -141,7 +141,7 @@ public class GameEventProject extends TenantEntity {
     private String gameStage;
 
     /**
-     * 状态(0正常 1停用
+     * 状态(0正常 1已结束
      */
     private String status;
 

+ 33 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/ClientLoginBo.java

@@ -0,0 +1,33 @@
+package org.dromara.system.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Data
+public class ClientLoginBo {
+
+    /**
+     * 赛事ID
+     */
+    @NotNull(message = "赛事ID不能为空")
+    private Long eventId;
+
+    /**
+     * 项目ID
+     */
+    @NotNull(message = "项目ID不能为空")
+    private Long projectId;
+
+    /**
+     * 密码
+     */
+    @NotBlank(message = "密码不能为空")
+    private String password;
+
+    /**
+     * 裁判号码
+     */
+    @NotBlank(message = "裁判号码不能为空")
+    private String refereeNumber;
+}

+ 22 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/ClientLoginVo.java

@@ -0,0 +1,22 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+@Data
+public class ClientLoginVo {
+
+    /**
+     * 是否登录成功 (true/false)
+     */
+    private Boolean success;
+
+    /**
+     * 裁判号码(即账号)
+     */
+    private String refereeNumber;
+    
+    /**
+     * 提示信息
+     */
+    private String message;
+}

+ 12 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/app/IToClientService.java

@@ -2,9 +2,11 @@ package org.dromara.system.service.app;
 
 import org.dromara.system.domain.GameEvent;
 import org.dromara.system.domain.GameEventProject;
+import org.dromara.system.domain.bo.ClientLoginBo;
 import org.dromara.system.domain.bo.ClientProjectSaveBo;
 import org.dromara.system.domain.bo.ScorePreviewUpdateBo;
 import org.dromara.system.domain.bo.ScoreSubmitBo;
+import org.dromara.system.domain.vo.ClientLoginVo;
 import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetVo;
 
@@ -12,6 +14,11 @@ import java.util.List;
 
 public interface IToClientService {
 
+    /**
+     * 客户端登录 (接口1)
+     */
+    ClientLoginVo login(ClientLoginBo bo);
+
     /**
      * 客户端同步赛事及项目信息 (接口4)
      *
@@ -44,6 +51,11 @@ public interface IToClientService {
      */
     void submitScoreSheet(ScoreSubmitBo bo);
 
+    /**
+     * 成绩记录单结束项目 (接口7)
+     */
+    void endProject(Long projectId);
+
     /**
      * 成绩预览列表查询 (接口8)
      */

+ 50 - 9
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/app/ToClientServiceImpl.java

@@ -9,6 +9,7 @@ import org.dromara.common.core.utils.StringUtils;
 import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.*;
 import org.dromara.system.domain.constant.ProjectClassification;
+import org.dromara.system.domain.vo.ClientLoginVo;
 import org.dromara.system.domain.vo.ScorePreviewVo;
 import org.dromara.system.domain.vo.ScoreSheetDetailVo;
 import org.dromara.system.domain.vo.ScoreSheetItemVo;
@@ -43,6 +44,28 @@ public class ToClientServiceImpl implements IToClientService {
     private final GameScoreMapper gameScoreMapper;
     private final GameAthleteMapper gameAthleteMapper;
 
+    @Override
+    public ClientLoginVo login(ClientLoginBo bo) {
+        ClientLoginVo vo = new ClientLoginVo();
+        GameReferee referee = Db.getOne(Wrappers.lambdaQuery(GameReferee.class)
+                .eq(GameReferee::getEventId, bo.getEventId())
+                .eq(GameReferee::getAccount, bo.getRefereeNumber())
+                .eq(GameReferee::getPassword, bo.getPassword())
+                .eq(GameReferee::getDelFlag, "0")
+                .last("LIMIT 1"));
+
+        if (referee == null) {
+            vo.setSuccess(false);
+            vo.setMessage("裁判号码或密码错误");
+            return vo;
+        }
+
+        vo.setSuccess(true);
+        vo.setRefereeNumber(referee.getAccount());
+        vo.setMessage("登录成功");
+        return vo;
+    }
+
     /**
      * 客户端同步赛事及项目信息 (接口4)
      *
@@ -192,7 +215,7 @@ public class ToClientServiceImpl implements IToClientService {
         return projectMapper.selectList(Wrappers.lambdaQuery(GameEventProject.class)
                 .eq(GameEventProject::getEventId, eventId)
                 .select(GameEventProject::getProjectId, GameEventProject::getProjectType,
-                        GameEventProject::getClassification, GameEventProject::getProjectName));
+                        GameEventProject::getClassification, GameEventProject::getProjectName, GameEventProject::getStatus));
     }
 
     @Override
@@ -282,7 +305,7 @@ public class ToClientServiceImpl implements IToClientService {
      * 将小数格式的成绩转换成时间格式显示
      *
      * @param decimalScore 以秒为单位的小数值
-     * @param format 格式 (HH:mm:ss.SSS 或 mm:ss.SSS)
+     * @param format       格式 (HH:mm:ss.SSS 或 mm:ss.SSS)
      * @return 时间格式字符串
      */
     private String convertDecimalToTimeScore(BigDecimal decimalScore, String format) {
@@ -364,7 +387,8 @@ public class ToClientServiceImpl implements IToClientService {
 
         if (!missingAthleteItems.isEmpty()) {
             // 预查是否存在,防止重复
-            Set<String> codes = missingAthleteItems.stream().map(ScoreSubmitItemBo::getAthleteCode).collect(Collectors.toSet());
+            Set<String> codes = missingAthleteItems.stream().map(ScoreSubmitItemBo::getAthleteCode)
+                    .collect(Collectors.toSet());
             List<GameAthlete> existAthletes = gameAthleteMapper.selectList(Wrappers.lambdaQuery(GameAthlete.class)
                     .eq(GameAthlete::getEventId, eventId)
                     .in(GameAthlete::getAthleteCode, codes)
@@ -394,8 +418,10 @@ public class ToClientServiceImpl implements IToClientService {
         // 3. 直接批量更新所有上传项的运动员信息 (不再预查对比,直接全量同步)
         List<GameAthlete> updateBatch = items.stream()
                 .map(item -> {
-                    Long aid = item.getAthleteId() != null ? item.getAthleteId() : athleteIdMap.get(item.getAthleteCode());
-                    if (aid == null) return null;
+                    Long aid = item.getAthleteId() != null ? item.getAthleteId()
+                            : athleteIdMap.get(item.getAthleteCode());
+                    if (aid == null)
+                        return null;
                     GameAthlete a = new GameAthlete();
                     a.setAthleteId(aid);
                     a.setTrackIndex(item.getTrackIndex());
@@ -409,8 +435,10 @@ public class ToClientServiceImpl implements IToClientService {
 
         // 4. 循环处理成绩录入 (统一使用 details 明细列表)
         for (ScoreSubmitItemBo item : items) {
-            Long athleteId = item.getAthleteId() != null ? item.getAthleteId() : athleteIdMap.get(item.getAthleteCode());
-            if (athleteId == null) continue;
+            Long athleteId = item.getAthleteId() != null ? item.getAthleteId()
+                    : athleteIdMap.get(item.getAthleteCode());
+            if (athleteId == null)
+                continue;
 
             Long teamId = item.getTeamId() != null ? item.getTeamId() : teamIdMap.get(item.getTeamName());
 
@@ -447,6 +475,17 @@ public class ToClientServiceImpl implements IToClientService {
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void endProject(Long projectId) {
+        GameEventProject project = projectMapper.selectById(projectId);
+        if (project == null) {
+            throw new RuntimeException("项目不存在");
+        }
+        project.setStatus("1");
+        projectMapper.updateById(project);
+    }
+
     @Override
     public List<ScorePreviewVo> getScorePreviewList(Long projectId) {
         List<ScorePreviewVo> list = baseMapper.selectScorePreviewList(projectId);
@@ -499,7 +538,8 @@ public class ToClientServiceImpl implements IToClientService {
         if (StringUtils.isNotBlank(project.getTimingFormat())) {
             list.forEach(item -> {
                 if (StringUtils.isNotBlank(item.getScore())) {
-                    item.setScore(convertDecimalToTimeScore(new BigDecimal(item.getScore()), project.getTimingFormat()));
+                    item.setScore(
+                            convertDecimalToTimeScore(new BigDecimal(item.getScore()), project.getTimingFormat()));
                 }
                 if (item.getDetails() != null) {
                     item.getDetails().forEach(detail -> {
@@ -624,7 +664,8 @@ public class ToClientServiceImpl implements IToClientService {
      * 支持普通数字和时间格式 (HH:mm:ss.SSS 或 mm:ss.SSS)
      */
     private BigDecimal parsePerformanceValue(String scoreStr) {
-        if (StringUtils.isBlank(scoreStr)) return null;
+        if (StringUtils.isBlank(scoreStr))
+            return null;
         scoreStr = scoreStr.trim();
         // 兼容时间格式
         if (scoreStr.contains(":")) {