Sfoglia il codice sorgente

feat(large-screen): 添加大屏展示功能支持赛事信息和成绩查询

- 新增 GlobalConfigVo 类用于存储大屏全局配置信息
- 实现 ILargeScreenService 接口提供大屏数据获取功能
- 创建 LargeScreenController 控制器暴露大屏相关 API 接口
- 开发 LargeScreenMapper 数据访问层处理成绩查询逻辑
- 配置 MyBatis XML 映射文件实现个人和团队成绩查询
- 实现 LargeScreenServiceImpl 业务逻辑处理类
- 添加多个 VO 类支持大屏展示的数据结构定义
- 集成租户助手忽略多租户限制以支持大屏公共访问
- 提供赛事项目列表和个人/团队成绩查询接口
zhou 1 giorno fa
parent
commit
a24282157c

+ 62 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/largeScreenDisplay/LargeScreenController.java

@@ -0,0 +1,62 @@
+package org.dromara.system.controller.largeScreenDisplay;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.LargeScreenAPI.GlobalConfigVo;
+import org.dromara.system.domain.LargeScreenAPI.PersonalResultListVo;
+import org.dromara.system.domain.LargeScreenAPI.ProjectListVo;
+import org.dromara.system.domain.LargeScreenAPI.TeamResultListVo;
+import org.dromara.system.service.app.ILargeScreenService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 大屏展示接口
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/api/v1/screen/")
+public class LargeScreenController {
+
+    private final ILargeScreenService largeScreenService;
+
+    /**
+     * 1.大屏全局基础信息接口
+     */
+    @RequestMapping("/global-config")
+    public R<GlobalConfigVo> globalConfig(@RequestParam("tournament_id") @NotNull(message = "赛事Id不能为空") Long tournamentId) {
+        return R.ok(TenantHelper.ignore(() -> largeScreenService.getGlobalConfig(tournamentId)));
+    }
+
+    /**
+     * 2.赛事项目列表接口
+     */
+    @RequestMapping("/event-list")
+    public R<ProjectListVo> projectList(@RequestParam("tournament_id") @NotNull(message = "赛事Id不能为空") Long tournamentId) {
+        return R.ok(TenantHelper.ignore(() -> largeScreenService.getProjectList(tournamentId)));
+    }
+
+    /**
+     * 3.赛事成绩接口--个人
+     */
+    @RequestMapping("/event-result/personal")
+    public R<PersonalResultListVo> athleteScore(@RequestParam("tournament_id") @NotNull(message = "赛事Id不能为空") Long tournamentId,
+                                                @RequestParam("event_id") @NotNull(message = "项目Id不能为空") Long eventId) {
+        return R.ok(TenantHelper.ignore(() -> largeScreenService.getAthleteScore(tournamentId, eventId)));
+    }
+
+    /**
+     * 4.赛事成绩接口--团队
+     */
+    @RequestMapping("/event-result/team")
+    public R<TeamResultListVo> teamScore(@RequestParam("tournament_id") @NotNull(message = "赛事Id不能为空") Long tournamentId,
+                                         @RequestParam("event_id") @NotNull(message = "项目Id不能为空") Long eventId) {
+        return R.ok(TenantHelper.ignore(() -> largeScreenService.getTeamScore(tournamentId, eventId)));
+    }
+
+}

+ 28 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/GlobalConfigVo.java

@@ -0,0 +1,28 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+public class GlobalConfigVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主办方/机构名称 | "中国田径协会"
+     */
+    private String org_name;
+    /**
+     * 主办方 Logo 图片绝对/相对地址。如果为空,前端将使用默认的 CSS 动态渲染徽标。 | "https://example.com/logo.png"
+     */
+    private String logo_url;
+    /**
+     * 顶部大屏总标题,显示在最醒目的中央位置。 | "北京市第十七届运动会 (高校组) 田径项目比赛" |
+     */
+    private String tournament_name;
+
+
+}

+ 23 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/PersonalResultListVo.java

@@ -0,0 +1,23 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 个人赛事成绩列表大屏展示对象
+ */
+@Data
+public class PersonalResultListVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成绩记录列表
+     */
+    private List<PersonalResultVo> results;
+
+}

+ 63 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/PersonalResultVo.java

@@ -0,0 +1,63 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 个人赛事成绩大屏展示对象
+ */
+@Data
+public class PersonalResultVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成绩记录的唯一主键 ID。
+     */
+    private String id;
+
+    /**
+     * 运动员名次。排名前三的将会自动渲染金银铜牌。
+     */
+    private Integer rank;
+
+    /**
+     * 运动员参赛号码牌。
+     */
+    private String number;
+
+    /**
+     * 运动员姓名。
+     */
+    private String name;
+
+    /**
+     * 运动员所属单位或学校。
+     */
+    private String unit;
+
+    /**
+     * 所属组别。
+     */
+    private String group;
+
+    /**
+     * 最终成绩。可以为秒数、高度或距离的字符串形式。
+     */
+    private String score;
+
+    /**
+     * 获得的总积分。
+     */
+    private BigDecimal points;
+
+    /**
+     * 备注说明,如果超出长度大屏会自动滚动或截断。无备注留空字符串。
+     */
+    private String remark;
+
+}

+ 28 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/ProjectListVo.java

@@ -0,0 +1,28 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 赛事大屏子项目赛程列表展示对象
+ */
+@Data
+public class ProjectListVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * (可选) 统计出的本次赛事总场次数。如果有此值,大屏将显示 "共 `total_events` 场";
+     * 如果不传,前端默认根据 `list` 数组的数量自动计算。 | 10
+     */
+    private Integer total_events;
+    /**
+     * 赛程列表
+     */
+    private List<ProjectVo> list;
+
+}

+ 42 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/ProjectVo.java

@@ -0,0 +1,42 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 赛事大屏子项目赛程展示对象
+ */
+@Data
+public class ProjectVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 赛事项目的唯一标识符,后续通过此ID请求该赛事项目的成绩排行。
+     */
+    private String event_id;
+
+    /**
+     * 子赛事具体名称。
+     */
+    private String event_name;
+
+    /**
+     * 赛事项目类型。固定枚举值:personal(个人赛) 或 team(团队赛)。
+     */
+    private String type;
+
+    /**
+     * 场地等附加信息说明,显示在大屏右上方。
+     */
+    private String info;
+
+    /**
+     * (可选) 当前赛事属于第几场。
+     */
+    private Integer session_index;
+
+}

+ 23 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/TeamResultListVo.java

@@ -0,0 +1,23 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 团队赛事成绩列表大屏展示对象
+ */
+@Data
+public class TeamResultListVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成绩记录列表
+     */
+    private List<TeamResultVo> results;
+
+}

+ 58 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/LargeScreenAPI/TeamResultVo.java

@@ -0,0 +1,58 @@
+package org.dromara.system.domain.LargeScreenAPI;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 团队赛事成绩大屏展示对象
+ */
+@Data
+public class TeamResultVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成绩记录的唯一主键 ID。
+     */
+    private String id;
+
+    /**
+     * 队伍名次。
+     */
+    private Integer rank;
+
+    /**
+     * 团队参赛号。
+     */
+    private String number;
+
+    /**
+     * 队伍/代表团名称。
+     */
+    private String unit;
+
+    /**
+     * 队伍所属组别。
+     */
+    private String group;
+
+    /**
+     * 团队完赛成绩。
+     */
+    private String score;
+
+    /**
+     * 团队获得的总积分。
+     */
+    private BigDecimal total_score;
+
+    /**
+     * 备注说明。
+     */
+    private String remark;
+
+}

+ 22 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/app/LargeScreenMapper.java

@@ -0,0 +1,22 @@
+package org.dromara.system.mapper.app;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.system.domain.LargeScreenAPI.PersonalResultVo;
+import org.dromara.system.domain.LargeScreenAPI.TeamResultVo;
+
+import java.util.List;
+
+@Mapper
+public interface LargeScreenMapper {
+
+    /**
+     * 获取赛事成绩--个人
+     */
+    List<PersonalResultVo> getAthleteScore(@Param("tournamentId") Long tournamentId, @Param("eventId") Long eventId);
+
+    /**
+     * 赛事成绩--团队
+     */
+    List<TeamResultVo> getTeamScore(@Param("tournamentId") Long tournamentId, @Param("eventId") Long eventId);
+}

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

@@ -0,0 +1,32 @@
+package org.dromara.system.service.app;
+
+import org.dromara.system.domain.LargeScreenAPI.GlobalConfigVo;
+import org.dromara.system.domain.LargeScreenAPI.ProjectListVo;
+import org.dromara.system.domain.LargeScreenAPI.PersonalResultListVo;
+import org.dromara.system.domain.LargeScreenAPI.TeamResultListVo;
+
+/**
+ * 大屏展示服务接口
+ */
+public interface ILargeScreenService {
+
+    /**
+     * 获取大屏全局配置
+     */
+    GlobalConfigVo getGlobalConfig(Long tournamentId);
+
+    /**
+     * 获取赛事项目列表
+     */
+    ProjectListVo getProjectList(Long tournamentId);
+
+    /**
+     * 获取个人赛事成绩
+     */
+    PersonalResultListVo getAthleteScore(Long tournamentId, Long eventId);
+
+    /**
+     * 获取团队赛事成绩
+     */
+    TeamResultListVo getTeamScore(Long tournamentId, Long eventId);
+}

+ 98 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/app/LargeScreenServiceImpl.java

@@ -0,0 +1,98 @@
+package org.dromara.system.service.impl.app;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.system.domain.GameEvent;
+import org.dromara.system.domain.GameEventProject;
+import org.dromara.system.domain.LargeScreenAPI.*;
+import org.dromara.system.domain.constant.ProjectClassification;
+import org.dromara.system.mapper.GameEventMapper;
+import org.dromara.system.mapper.GameEventProjectMapper;
+import org.dromara.system.mapper.app.LargeScreenMapper;
+import org.dromara.system.service.app.ILargeScreenService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class LargeScreenServiceImpl implements ILargeScreenService {
+
+    private final GameEventMapper gameEventMapper;
+    private final GameEventProjectMapper projectMapper;
+    private final LargeScreenMapper baseMapper;
+
+
+
+    /**
+     * 大屏全局基础信息接口
+     */
+    @Override
+    public GlobalConfigVo getGlobalConfig(Long tournamentId) {
+        GameEvent event = gameEventMapper.selectOne(Wrappers.lambdaQuery(GameEvent.class)
+            .eq(GameEvent::getEventId, tournamentId)
+            .select(GameEvent::getUnit, GameEvent::getRegisterUrl, GameEvent::getEventName)
+        );
+        if (event != null) {
+            GlobalConfigVo vo = new GlobalConfigVo();
+            vo.setOrg_name(event.getUnit());
+            vo.setTournament_name(event.getEventName());
+            vo.setLogo_url(event.getRegisterUrl());
+            return vo;
+        }
+        return null;
+    }
+
+    /**
+     * 赛事项目列表接口
+     */
+    @Override
+    public ProjectListVo getProjectList(Long tournamentId) {
+        List<GameEventProject> projectList = projectMapper.selectList(Wrappers.lambdaQuery(GameEventProject.class)
+            .eq(GameEventProject::getEventId, tournamentId)
+            .orderByDesc(GameEventProject::getStartTime, GameEventProject::getCreateTime)
+            .select(GameEventProject::getProjectId, GameEventProject::getProjectName, GameEventProject::getClassification, GameEventProject::getLocation)
+        );
+        /** 组装数据解构 */
+        ProjectListVo vo = new ProjectListVo();
+        vo.setTotal_events(projectList.size());
+        if (!projectList.isEmpty()){
+            AtomicInteger indexCounter = new AtomicInteger(1);
+            vo.setList(projectList.stream().map(project -> {
+                ProjectVo projectVo = new ProjectVo();
+                projectVo.setEvent_id(project.getProjectId().toString());
+                projectVo.setEvent_name(project.getProjectName());
+                projectVo.setType(ProjectClassification.TEAM.getValue().equals(project.getClassification()) ? "team" : "personal");
+                projectVo.setInfo(project.getLocation());
+                projectVo.setSession_index(indexCounter.getAndIncrement());
+                return projectVo;
+            }).toList());
+        }
+        return vo;
+    }
+
+    /**
+     * 赛事成绩接口--个人
+     */
+    @Override
+    public PersonalResultListVo getAthleteScore(Long tournamentId, Long eventId) {
+        PersonalResultListVo vo = new PersonalResultListVo();
+        List<PersonalResultVo> results = baseMapper.getAthleteScore(tournamentId, eventId);
+        vo.setResults(results != null ? results : List.of());
+        return vo;
+    }
+
+    /**
+     * 赛事成绩接口--团队
+     */
+    @Override
+    public TeamResultListVo getTeamScore(Long tournamentId, Long eventId) {
+        TeamResultListVo vo = new TeamResultListVo();
+        List<TeamResultVo> results = baseMapper.getTeamScore(tournamentId, eventId);
+        vo.setResults(results != null ? results : List.of());
+        return vo;
+    }
+}

+ 47 - 0
ruoyi-modules/ruoyi-game-event/src/main/resources/mapper/system/app/LargeScreenMapper.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.app.LargeScreenMapper">
+    <!--  获取个人赛事成绩    -->
+    <select id="getAthleteScore" resultType="org.dromara.system.domain.LargeScreenAPI.PersonalResultVo">
+        SELECT
+            gs.score_id as id,
+            gs.score_rank as rank,
+            ga.athlete_code as number,
+            ga.name as name,
+            gt.team_name as unit,
+            rg.rg_name as `group`,
+            gs.individual_performance as score,
+            gs.score_point as points,
+            gs.remark as remark
+        FROM game_score gs
+            INNER JOIN game_athlete ga ON gs.athlete_id = ga.athlete_id AND ga.del_flag = '0'
+            LEFT JOIN game_team gt ON gs.team_id = gt.team_id AND gt.del_flag = '0'
+            LEFT JOIN game_rank_group rg ON rg.rg_id = gt.rg_id AND rg.del_flag = '0'
+        WHERE gs.event_id = #{tournamentId}
+            AND gs.project_id = #{eventId}
+            AND gs.del_flag = '0'
+        ORDER BY gs.score_rank ASC, gs.score_id DESC
+    </select>
+    <!--  获取团队赛事成绩    -->
+    <select id="getTeamScore" resultType="org.dromara.system.domain.LargeScreenAPI.TeamResultVo">
+        SELECT
+            MAX(gs.score_id) as id,
+            MAX(gs.score_rank) as rank,
+            MAX(ga.athlete_code) as number,
+            gt.team_name as unit,
+            rg.rg_name as `group`,
+            MAX(gs.team_performance) as score,
+            MAX(gs.score_point) as total_score,
+            MAX(gs.remark) as remark
+        FROM game_score gs
+            JOIN game_athlete ga ON gs.athlete_id = ga.athlete_id AND ga.del_flag = '0'
+            JOIN game_team gt ON gs.team_id = gt.team_id AND gt.del_flag = '0'
+            JOIN game_rank_group rg ON rg.rg_id = gt.rg_id AND rg.del_flag = '0'
+        WHERE gs.event_id = #{tournamentId} AND gs.project_id = #{eventId} AND gs.del_flag = '0'
+        group by gs.team_id, gt.team_name, rg.rg_name
+        ORDER BY rank ASC, id DESC
+    </select>
+
+</mapper>