Эх сурвалжийг харах

feat(game-event): 实现参赛队员数据导出功能

- 修改导出接口调用 exportData 方法处理导出数据
- 新增 exportData 方法用于处理导出数据的转换逻辑- 添加序号设置、队伍ID转名称、项目ID列表转名称列表功能
- 更新 GameAthleteVo 类适配导出字段展示- 升级 poi 和 poi-ooxml依赖版本至4.1.2
- 注释测试用例代码,优化单元格类型判断逻辑
- 调整 GameEventProjectVo 和 GameEventVo 导出字段配置
- 优化 GameTeamVo 导出字段及字典转换配置
zhou 2 долоо хоног өмнө
parent
commit
0ae318b803

+ 2 - 2
ruoyi-modules/ruoyi-game-event/pom.xml

@@ -108,12 +108,12 @@
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi</artifactId>
-            <version>3.17</version>
+            <version>4.1.2</version>
         </dependency>
         <dependency>
             <groupId>org.apache.poi</groupId>
             <artifactId>poi-ooxml</artifactId>
-            <version>3.17</version>
+            <version>4.1.2</version>
         </dependency>
         <dependency>
             <groupId>org.dromara</groupId>

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameAthleteController.java

@@ -67,7 +67,7 @@ public class GameAthleteController extends BaseController {
     @Log(title = "参赛队员", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(GameAthleteBo bo, HttpServletResponse response) {
-        List<GameAthleteVo> list = gameAthleteService.queryList(bo);
+        List<GameAthleteVo> list = gameAthleteService.exportData(bo);
         ExcelUtil.exportExcel(list, "参赛队员", GameAthleteVo.class, response);
     }
 

+ 299 - 299
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/TestPoi.java

@@ -20,308 +20,308 @@ public class TestPoi {
      * @return
      */
     public static void main(String[] args) throws IOException {
-        System.out.println(importData());
+//        System.out.println(importData());
     }
 
-    private static List<EnrollProjectVo> importData() throws IOException {
-        List<EnrollProjectVo> enrolls = new ArrayList<>();
-        File file = new File("D:\\poi_demo.xlsx");
-
-        try (FileInputStream fis = new FileInputStream(file);
-             Workbook workbook = new XSSFWorkbook(fis)) {
-
-            Sheet sheet = workbook.getSheetAt(0);
-
-            // 获取第一行(表头),用于获取项目名称
-            Row headerRow = sheet.getRow(2);
-            // 动态确定有效最大列数(去除表头末尾的空列)
-            int lastCellIndex = findValidLastColumnIndex(headerRow);
-            List<String> projectNames = new ArrayList<>();
-
-            // 从第6列(F列,索引5)开始收集项目名称
-            for (int i = 6; i < lastCellIndex; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell != null && cell.getStringCellValue() != null && !cell.getStringCellValue().trim().isEmpty()) {
-                    projectNames.add(cell.getStringCellValue().trim());
-                } else {
-                    projectNames.add("项目_" + i); // 防止空标题
-                }
-            }
-
-            // 从第3行开始读数据
-            for (int i = 3; i <= sheet.getLastRowNum(); i++) {
-                Row row = sheet.getRow(i);
-                if (row == null) continue;
-                if (isRowEmpty(row, 0, lastCellIndex)) {
-                    continue;
-                }
-
-                EnrollProjectVo enroll = new EnrollProjectVo();
-                Map<String, Boolean> selections = new LinkedHashMap<>(); // 保持顺序
-
-                // A列:姓名
-                Cell nameCell = row.getCell(0);
-                if (nameCell != null) {
-                    enroll.setName(getCellValueAsString(nameCell));
-                }
-
-                // B列:性别
-                Cell sexCell = row.getCell(1);
-                if (sexCell != null) {
-                    enroll.setSex(getCellValueAsString(sexCell));
-                }
-
-                // C列:年龄
-                Cell ageCell = row.getCell(2);
-                if (ageCell != null) {
-                    enroll.setAge(getCellValueAsString(ageCell));
-                }
-
-                // D列:队伍名称
-                Cell teamCell = row.getCell(3);
-                if (teamCell != null) {
-                    enroll.setTeamName(getCellValueAsString(teamCell));
-                }
-
-                // E列:领队
-                Cell leaderCell = row.getCell(4);
-                if (leaderCell != null) {
-                    enroll.setLeader(getCellValueAsString(leaderCell));
-                }
-
-                // F列:联系方式
-                Cell phoneCell = row.getCell(5);
-                if (phoneCell != null) {
-                    enroll.setPhone(getCellValueAsString(phoneCell));
-                }
-
-                // 从第6列开始读取项目名称
-                for (int j = 6; j < lastCellIndex; j++) {
-                    Cell cell = row.getCell(j);
-                    String projectName = projectNames.get(j - 6); // 对应项目名
-                    boolean selected = isCellSelected(cell);
-                    selections.put(projectName, selected);
-                }
-
-                enroll.setProjectSelections(selections);
-                enrolls.add(enroll);
-            }
-        }
-        return enrolls;
-    }
+//    private static List<EnrollProjectVo> importData() throws IOException {
+//        List<EnrollProjectVo> enrolls = new ArrayList<>();
+//        File file = new File("D:\\poi_demo.xlsx");
+//
+//        try (FileInputStream fis = new FileInputStream(file);
+//             Workbook workbook = new XSSFWorkbook(fis)) {
+//
+//            Sheet sheet = workbook.getSheetAt(0);
+//
+//            // 获取第一行(表头),用于获取项目名称
+//            Row headerRow = sheet.getRow(2);
+//            // 动态确定有效最大列数(去除表头末尾的空列)
+//            int lastCellIndex = findValidLastColumnIndex(headerRow);
+//            List<String> projectNames = new ArrayList<>();
+//
+//            // 从第6列(F列,索引5)开始收集项目名称
+//            for (int i = 6; i < lastCellIndex; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell != null && cell.getStringCellValue() != null && !cell.getStringCellValue().trim().isEmpty()) {
+//                    projectNames.add(cell.getStringCellValue().trim());
+//                } else {
+//                    projectNames.add("项目_" + i); // 防止空标题
+//                }
+//            }
+//
+//            // 从第3行开始读数据
+//            for (int i = 3; i <= sheet.getLastRowNum(); i++) {
+//                Row row = sheet.getRow(i);
+//                if (row == null) continue;
+//                if (isRowEmpty(row, 0, lastCellIndex)) {
+//                    continue;
+//                }
+//
+//                EnrollProjectVo enroll = new EnrollProjectVo();
+//                Map<String, Boolean> selections = new LinkedHashMap<>(); // 保持顺序
+//
+//                // A列:姓名
+//                Cell nameCell = row.getCell(0);
+//                if (nameCell != null) {
+//                    enroll.setName(getCellValueAsString(nameCell));
+//                }
+//
+//                // B列:性别
+//                Cell sexCell = row.getCell(1);
+//                if (sexCell != null) {
+//                    enroll.setSex(getCellValueAsString(sexCell));
+//                }
+//
+//                // C列:年龄
+//                Cell ageCell = row.getCell(2);
+//                if (ageCell != null) {
+//                    enroll.setAge(getCellValueAsString(ageCell));
+//                }
+//
+//                // D列:队伍名称
+//                Cell teamCell = row.getCell(3);
+//                if (teamCell != null) {
+//                    enroll.setTeamName(getCellValueAsString(teamCell));
+//                }
+//
+//                // E列:领队
+//                Cell leaderCell = row.getCell(4);
+//                if (leaderCell != null) {
+//                    enroll.setLeader(getCellValueAsString(leaderCell));
+//                }
+//
+//                // F列:联系方式
+//                Cell phoneCell = row.getCell(5);
+//                if (phoneCell != null) {
+//                    enroll.setPhone(getCellValueAsString(phoneCell));
+//                }
+//
+//                // 从第6列开始读取项目名称
+//                for (int j = 6; j < lastCellIndex; j++) {
+//                    Cell cell = row.getCell(j);
+//                    String projectName = projectNames.get(j - 6); // 对应项目名
+//                    boolean selected = isCellSelected(cell);
+//                    selections.put(projectName, selected);
+//                }
+//
+//                enroll.setProjectSelections(selections);
+//                enrolls.add(enroll);
+//            }
+//        }
+//        return enrolls;
+//    }
 
     // 辅助方法:将 Cell 转为字符串
-    private static String getCellValueAsString(Cell cell) {
-        if (cell == null) return "";
-
-        switch (cell.getCellType()) {
-            case Cell.CELL_TYPE_STRING:
-                return cell.getStringCellValue().trim();
-            case Cell.CELL_TYPE_NUMERIC:
-                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
-                    return cell.getDateCellValue().toString();
-                } else {
-                    return String.valueOf((int) cell.getNumericCellValue()); // 或者保留小数用 double
-                }
-            case Cell.CELL_TYPE_BOOLEAN:
-                return String.valueOf(cell.getBooleanCellValue());
-            default:
-                return "";
-        }
-    }
-
-    /**
-     * 判断单元格是否表示“已选择”
-     * 支持:是、yes、true、1、✔、✅、√ 等
-     */
-    private static boolean isCellSelected(Cell cell) {
-        if (cell == null) return false;
-
-        // 先检查单元格类型
-        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
-            return cell.getBooleanCellValue();
-        }
-        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
-            return cell.getNumericCellValue() == 1;
-        }
-
-        String value = getCellValueAsString(cell).trim().toLowerCase();
-        return !value.isEmpty() &&
-            (value.equals("是") || value.equals("yes") || value.equals("true") ||
-                value.equals("1") || value.contains("✔") || value.contains("✅") ||
-                value.contains("√") || value.equals("×"));
-    }
-
-    /**
-     * 判断某行在指定范围内是否为空(无有效数据)
-     *
-     * @param row      行对象
-     * @param startCol 起始列索引
-     * @param endCol   结束列索引(不包含)
-     * @return true 表示该行为空
-     */
-    private static boolean isRowEmpty(Row row, int startCol, int endCol) {
-        if (row == null) return true;
-
-        for (int i = startCol; i < endCol; i++) {
-            Cell cell = row.getCell(i);
-            if (cell != null) {
-                // 如果单元格不为null,检查其是否有非空值
-                String value = getCellValueAsString(cell);
-                if (value != null && !value.trim().isEmpty()) {
-                    return false; // 有有效数据
-                }
-            }
-        }
-        return true; // 所有列都为空
-    }
-
-    /**
-     * 找到行中最后一个“有效”单元格的索引(从右往左找第一个非空单元格)
-     *
-     * @param row 行对象
-     * @return 有效最大列索引(不包含),即 getLastCellNum() 的合理值
-     */
-    private static int findValidLastColumnIndex(Row row) {
-        if (row == null) return 0;
-
-        int lastCellNum = row.getLastCellNum(); // 物理最后一列
-        if (lastCellNum <= 0) return 0;
-
-        // 从右往左扫描,找到第一个非空单元格
-        for (int i = lastCellNum - 1; i >= 0; i--) {
-            Cell cell = row.getCell(i);
-            String value = getCellValueAsString(cell);
-            if (value != null && !value.trim().isEmpty()) {
-                return i + 1; // 返回有效列数(索引+1)
-            }
-        }
-        return 0; // 全为空
-    }
-
-    private static void export() {
-        //1.加载Excel模板文件
-        // String template = "template/enroll_template.xlsx";
-        String template = "D:\\enroll_template.xlsx";
-        System.out.println(template);
-        XSSFSheet sheet = null;
-        try (
-            // InputStream inputStream = TestPoi.class.getClassLoader().getResourceAsStream(template);
-            InputStream inputStream = new FileInputStream(template);
-            XSSFWorkbook xwb = new XSSFWorkbook(inputStream)) {
-            sheet = xwb.getSheetAt(0);
-            assert sheet != null;
-            //7列3行开始横着渲染 excel表对应6行2列
-            // 2. 获取默认赛事动态项目(赛事项目)
-            // Map<String, List<String>> projectMap = gameEventProjectService.mapProjectTypeAndProject(eventId);
-            Map<String, List<String>> projectMap = new HashMap<>();
-            projectMap.put("径赛项目", List.of("4*100米接力", "4*400米接力", "跳高"));
-            projectMap.put("田赛项目", List.of("跨栏", "接力", "50米"));
-
-            // 3. 渲染分类
-            int currentColumnIndex = 6;
-            Row row = sheet.getRow(2);
-            if (row == null) {
-                row = sheet.createRow(2);
-            }
-
-            for (Map.Entry<String, List<String>> entry : projectMap.entrySet()) {
-                String categoryName = entry.getKey();
-                List<String> projectList = entry.getValue();
-                int projectCount = projectList.size();
-                // 3.1 创建单元格并设置分类名称
-                Cell cell = row.createCell(currentColumnIndex);
-                cell.setCellValue(categoryName);
-
-                // 3.2 合并单元格:从 currentColumnIndex 开始,合并 projectCount 个单元格
-                int lastColumnIndex = currentColumnIndex + projectCount - 1;
-                CellRangeAddress region = new CellRangeAddress(2, 2, currentColumnIndex, lastColumnIndex);
-                sheet.addMergedRegion(region);
-
-                // 3.3 创建样式:边框 + 居中 + 加粗
-                CellStyle style = xwb.createCellStyle();
-                style.setBorderTop(BorderStyle.THIN);
-                style.setBorderBottom(BorderStyle.THIN);
-                style.setBorderLeft(BorderStyle.THIN);
-                style.setBorderRight(BorderStyle.THIN);
-                style.setTopBorderColor(IndexedColors.BLACK.getIndex());
-                style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
-                style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
-                style.setRightBorderColor(IndexedColors.BLACK.getIndex());
-
-                style.setAlignment(HorizontalAlignment.CENTER);
-                style.setVerticalAlignment(VerticalAlignment.CENTER);
-
-                // 字体加粗
-                Font font = xwb.createFont();
-                font.setBold(true);
-                style.setFont(font);
-
-                // 应用样式
-                cell.setCellStyle(style);
-
-                // 3.4  更新起始列:为下一个分类腾出位置
-                currentColumnIndex = lastColumnIndex + 1;
-            }
-
-            // 4. 渲染项目(在第4行,索引为3)
-            currentColumnIndex = 6;
-            Row projectRow = sheet.getRow(3);
-            if (projectRow == null) {
-                projectRow = sheet.createRow(3); // 如果第4行不存在,创建它
-            }
-            for (Map.Entry<String, List<String>> entry : projectMap.entrySet()) {
-                List<String> projectList = entry.getValue();
-                // 4.1 遍历当前分类下的每个项目
-                for (String projectName : projectList) {
-                    Cell cell = projectRow.createCell(currentColumnIndex);
-                    cell.setCellValue(projectName);
-
-                    // 3.3 创建样式:边框 + 居中 + 加粗
-                    CellStyle style = xwb.createCellStyle();
-                    style.setBorderTop(BorderStyle.THIN);
-                    style.setBorderBottom(BorderStyle.THIN);
-                    style.setBorderLeft(BorderStyle.THIN);
-                    style.setBorderRight(BorderStyle.THIN);
-                    style.setTopBorderColor(IndexedColors.BLACK.getIndex());
-                    style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
-                    style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
-                    style.setRightBorderColor(IndexedColors.BLACK.getIndex());
-
-                    style.setAlignment(HorizontalAlignment.CENTER);
-                    style.setVerticalAlignment(VerticalAlignment.CENTER);
-
-                    // 字体加粗
-                    Font font = xwb.createFont();
-                    font.setBold(true);
-                    style.setFont(font);
-
-                    // 应用样式
-                    cell.setCellStyle(style);
-
-                    // 移动到下一列
-                    currentColumnIndex++;
-                }
-            }
-
-            //3.将Excel文件通过Response输出
-            // 设置Excel文件路径
-            File target = new File("D:\\poi_demo.xlsx");
-            try {
-                // 创建指向该路径的输出流
-                FileOutputStream stream = new FileOutputStream(target);
-                // 将数据导出到Excel表格
-                xwb.write(stream);
-                // 关闭输出流
-                stream.close();
-            } catch (FileNotFoundException e) {
-                e.printStackTrace();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        } catch (IOException e) {
-            log.error("下载Excel模板异常,异常信息为:【{}】", e.getMessage(), e);
-        }
-    }
+//    private static String getCellValueAsString(Cell cell) {
+//        if (cell == null) return "";
+//
+//        switch (cell.getCellType()) {
+//            case Cell.CELL_TYPE_STRING:
+//                return cell.getStringCellValue().trim();
+//            case Cell.CELL_TYPE_NUMERIC:
+//                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
+//                    return cell.getDateCellValue().toString();
+//                } else {
+//                    return String.valueOf((int) cell.getNumericCellValue()); // 或者保留小数用 double
+//                }
+//            case Cell.CELL_TYPE_BOOLEAN:
+//                return String.valueOf(cell.getBooleanCellValue());
+//            default:
+//                return "";
+//        }
+//    }
+//
+//    /**
+//     * 判断单元格是否表示“已选择”
+//     * 支持:是、yes、true、1、✔、✅、√ 等
+//     */
+//    private static boolean isCellSelected(Cell cell) {
+//        if (cell == null) return false;
+//
+//        // 先检查单元格类型
+//        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
+//            return cell.getBooleanCellValue();
+//        }
+//        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
+//            return cell.getNumericCellValue() == 1;
+//        }
+//
+//        String value = getCellValueAsString(cell).trim().toLowerCase();
+//        return !value.isEmpty() &&
+//            (value.equals("是") || value.equals("yes") || value.equals("true") ||
+//                value.equals("1") || value.contains("✔") || value.contains("✅") ||
+//                value.contains("√") || value.equals("×"));
+//    }
+
+//    /**
+//     * 判断某行在指定范围内是否为空(无有效数据)
+//     *
+//     * @param row      行对象
+//     * @param startCol 起始列索引
+//     * @param endCol   结束列索引(不包含)
+//     * @return true 表示该行为空
+//     */
+//    private static boolean isRowEmpty(Row row, int startCol, int endCol) {
+//        if (row == null) return true;
+//
+//        for (int i = startCol; i < endCol; i++) {
+//            Cell cell = row.getCell(i);
+//            if (cell != null) {
+//                // 如果单元格不为null,检查其是否有非空值
+//                String value = getCellValueAsString(cell);
+//                if (value != null && !value.trim().isEmpty()) {
+//                    return false; // 有有效数据
+//                }
+//            }
+//        }
+//        return true; // 所有列都为空
+//    }
+//
+//    /**
+//     * 找到行中最后一个“有效”单元格的索引(从右往左找第一个非空单元格)
+//     *
+//     * @param row 行对象
+//     * @return 有效最大列索引(不包含),即 getLastCellNum() 的合理值
+//     */
+//    private static int findValidLastColumnIndex(Row row) {
+//        if (row == null) return 0;
+//
+//        int lastCellNum = row.getLastCellNum(); // 物理最后一列
+//        if (lastCellNum <= 0) return 0;
+//
+//        // 从右往左扫描,找到第一个非空单元格
+//        for (int i = lastCellNum - 1; i >= 0; i--) {
+//            Cell cell = row.getCell(i);
+//            String value = getCellValueAsString(cell);
+//            if (value != null && !value.trim().isEmpty()) {
+//                return i + 1; // 返回有效列数(索引+1)
+//            }
+//        }
+//        return 0; // 全为空
+//    }
+//
+//    private static void export() {
+//        //1.加载Excel模板文件
+//        // String template = "template/enroll_template.xlsx";
+//        String template = "D:\\enroll_template.xlsx";
+//        System.out.println(template);
+//        XSSFSheet sheet = null;
+//        try (
+//            // InputStream inputStream = TestPoi.class.getClassLoader().getResourceAsStream(template);
+//            InputStream inputStream = new FileInputStream(template);
+//            XSSFWorkbook xwb = new XSSFWorkbook(inputStream)) {
+//            sheet = xwb.getSheetAt(0);
+//            assert sheet != null;
+//            //7列3行开始横着渲染 excel表对应6行2列
+//            // 2. 获取默认赛事动态项目(赛事项目)
+//            // Map<String, List<String>> projectMap = gameEventProjectService.mapProjectTypeAndProject(eventId);
+//            Map<String, List<String>> projectMap = new HashMap<>();
+//            projectMap.put("径赛项目", List.of("4*100米接力", "4*400米接力", "跳高"));
+//            projectMap.put("田赛项目", List.of("跨栏", "接力", "50米"));
+//
+//            // 3. 渲染分类
+//            int currentColumnIndex = 6;
+//            Row row = sheet.getRow(2);
+//            if (row == null) {
+//                row = sheet.createRow(2);
+//            }
+//
+//            for (Map.Entry<String, List<String>> entry : projectMap.entrySet()) {
+//                String categoryName = entry.getKey();
+//                List<String> projectList = entry.getValue();
+//                int projectCount = projectList.size();
+//                // 3.1 创建单元格并设置分类名称
+//                Cell cell = row.createCell(currentColumnIndex);
+//                cell.setCellValue(categoryName);
+//
+//                // 3.2 合并单元格:从 currentColumnIndex 开始,合并 projectCount 个单元格
+//                int lastColumnIndex = currentColumnIndex + projectCount - 1;
+//                CellRangeAddress region = new CellRangeAddress(2, 2, currentColumnIndex, lastColumnIndex);
+//                sheet.addMergedRegion(region);
+//
+//                // 3.3 创建样式:边框 + 居中 + 加粗
+//                CellStyle style = xwb.createCellStyle();
+//                style.setBorderTop(BorderStyle.THIN);
+//                style.setBorderBottom(BorderStyle.THIN);
+//                style.setBorderLeft(BorderStyle.THIN);
+//                style.setBorderRight(BorderStyle.THIN);
+//                style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+//                style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+//                style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+//                style.setRightBorderColor(IndexedColors.BLACK.getIndex());
+//
+//                style.setAlignment(HorizontalAlignment.CENTER);
+//                style.setVerticalAlignment(VerticalAlignment.CENTER);
+//
+//                // 字体加粗
+//                Font font = xwb.createFont();
+//                font.setBold(true);
+//                style.setFont(font);
+//
+//                // 应用样式
+//                cell.setCellStyle(style);
+//
+//                // 3.4  更新起始列:为下一个分类腾出位置
+//                currentColumnIndex = lastColumnIndex + 1;
+//            }
+//
+//            // 4. 渲染项目(在第4行,索引为3)
+//            currentColumnIndex = 6;
+//            Row projectRow = sheet.getRow(3);
+//            if (projectRow == null) {
+//                projectRow = sheet.createRow(3); // 如果第4行不存在,创建它
+//            }
+//            for (Map.Entry<String, List<String>> entry : projectMap.entrySet()) {
+//                List<String> projectList = entry.getValue();
+//                // 4.1 遍历当前分类下的每个项目
+//                for (String projectName : projectList) {
+//                    Cell cell = projectRow.createCell(currentColumnIndex);
+//                    cell.setCellValue(projectName);
+//
+//                    // 3.3 创建样式:边框 + 居中 + 加粗
+//                    CellStyle style = xwb.createCellStyle();
+//                    style.setBorderTop(BorderStyle.THIN);
+//                    style.setBorderBottom(BorderStyle.THIN);
+//                    style.setBorderLeft(BorderStyle.THIN);
+//                    style.setBorderRight(BorderStyle.THIN);
+//                    style.setTopBorderColor(IndexedColors.BLACK.getIndex());
+//                    style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+//                    style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+//                    style.setRightBorderColor(IndexedColors.BLACK.getIndex());
+//
+//                    style.setAlignment(HorizontalAlignment.CENTER);
+//                    style.setVerticalAlignment(VerticalAlignment.CENTER);
+//
+//                    // 字体加粗
+//                    Font font = xwb.createFont();
+//                    font.setBold(true);
+//                    style.setFont(font);
+//
+//                    // 应用样式
+//                    cell.setCellStyle(style);
+//
+//                    // 移动到下一列
+//                    currentColumnIndex++;
+//                }
+//            }
+//
+//            //3.将Excel文件通过Response输出
+//            // 设置Excel文件路径
+//            File target = new File("D:\\poi_demo.xlsx");
+//            try {
+//                // 创建指向该路径的输出流
+//                FileOutputStream stream = new FileOutputStream(target);
+//                // 将数据导出到Excel表格
+//                xwb.write(stream);
+//                // 关闭输出流
+//                stream.close();
+//            } catch (FileNotFoundException e) {
+//                e.printStackTrace();
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//        } catch (IOException e) {
+//            log.error("下载Excel模板异常,异常信息为:【{}】", e.getMessage(), e);
+//        }
+//    }
 }
 

+ 30 - 14
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameAthleteVo.java

@@ -31,7 +31,7 @@ public class GameAthleteVo implements Serializable {
     /**
      * 主键
      */
-    // @ExcelProperty(value = "主键")
+//     @ExcelProperty(value = "Id")
     private Long athleteId;
 
     /**
@@ -55,13 +55,19 @@ public class GameAthleteVo implements Serializable {
     /**
      * 队伍ID
      */
-    @ExcelProperty(value = "队伍ID")
+//    @ExcelProperty(value = "队伍ID")
     private Long teamId;
 
+    /**
+     * 序号
+     */
+    @ExcelProperty(value = "序号")
+    private Integer rowNumber;
+
     /**
      * 运动员编号
      */
-    @ExcelProperty(value = "运动员编号")
+    @ExcelProperty(value = "号")
     private String athleteCode;
 
     /**
@@ -73,65 +79,75 @@ public class GameAthleteVo implements Serializable {
     /**
      * 性别
      */
-    @ExcelProperty(value = "性别")
+    @ExcelProperty(value = "性别", converter = ExcelDictConvert.class)
     @ExcelDictFormat(dictType = "sys_user_sex")
     private String gender;
 
+    /**
+     * 队伍名称
+     */
+    @ExcelProperty(value = "队伍")
+    private String teamName;
+
     /**
      * 年龄
      */
-    @ExcelProperty(value = "年龄")
+//    @ExcelProperty(value = "年龄")
     private Long age;
 
     /**
      * 单位
      */
-    @ExcelProperty(value = "单位")
+//    @ExcelProperty(value = "单位")
     private String unit;
 
     /**
      * 证件号
      */
-    @ExcelProperty(value = "证件号")
+//    @ExcelProperty(value = "证件号")
     private String idCard;
 
     /**
      * 芯片号
      */
-    @ExcelProperty(value = "芯片号")
+//    @ExcelProperty(value = "芯片号")
     private String chipCode;
 
     /**
      * 手机号
      */
-    @ExcelProperty(value = "手机号")
+//    @ExcelProperty(value = "手机号")
     private String phone;
 
     /**
      * 居住地址
      */
-    @ExcelProperty(value = "居住地址")
+//    @ExcelProperty(value = "居住地址")
     private String location;
 
     /**
      * T恤尺码
      */
-    @ExcelProperty(value = "T恤尺码")
+//    @ExcelProperty(value = "T恤尺码")
     private String tshirtSize;
 
     /**
      * 组别
      */
-    @ExcelProperty(value = "组别")
+//    @ExcelProperty(value = "组别")
     private String groupType;
 
     /**
      * 参与项目列表
      */
-    @ExcelProperty(value = "参与项目列表")
+//    @ExcelProperty(value = "参与项目列表")
     private String projectValue;
-
     private List<Long> projectList;
+    /**
+     * 项目名称列表(用于导出)
+     */
+    @ExcelProperty(value = "参与项目")
+    private String projectNames;
 
     /**
      * 状态(0正常 1停用)

+ 15 - 6
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameEventProjectVo.java

@@ -1,6 +1,8 @@
 package org.dromara.system.domain.vo;
 
 import java.util.Date;
+
+import cn.idev.excel.annotation.format.DateTimeFormat;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.dromara.system.domain.GameEventProject;
 import org.dromara.system.domain.bo.GameEventProjectBo;
@@ -40,7 +42,7 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 赛事ID
      */
-    @ExcelProperty(value = "赛事ID")
+//    @ExcelProperty(value = "赛事ID")
     private Long eventId;
 
     /**
@@ -65,7 +67,7 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 归类(0个人项目/1团体项目)
      */
-    @ExcelProperty(value = "归类")
+    @ExcelProperty(value = "归类", converter = ExcelDictConvert.class)
     @ExcelDictFormat(dictType = "game_project_classification")
     private String classification;
 
@@ -89,18 +91,21 @@ public class GameEventProjectVo implements Serializable {
      * 开始时间
      */
     @ExcelProperty(value = "开始时间")
+    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
     private Date startTime;
 
     /**
      * 结束时间
      */
     @ExcelProperty(value = "结束时间")
+    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
     private Date endTime;
 
     /**
      * 更新时间
      */
     @ExcelProperty(value = "更新时间")
+    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
 
     /**
@@ -118,6 +123,7 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 项目限报人数
      */
+    @ExcelProperty(value = "项目限报人数")
     private Integer limitPerson;
 
     /**
@@ -129,13 +135,14 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 排序方式
      */
-//    @ExcelProperty(value = "排序方式")
+    @ExcelProperty(value = "排序方式")
+    @ExcelDictFormat(readConverterExp = "0=升序,1=降序")
     private String orderType;
 
     /**
      * 计算规则
      */
-    @ExcelProperty(value = "计算规则")
+    @ExcelProperty(value = "计算规则", converter = ExcelDictConvert.class)
     @ExcelDictFormat(dictType = "game_score_type")
     private String scoreRule;
 
@@ -154,13 +161,15 @@ public class GameEventProjectVo implements Serializable {
     /**
      * 比赛轮次
      */
-    @ExcelProperty(value = "比赛轮次")
+    @ExcelProperty(value = "比赛轮次", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "game_round")
     private String gameRound;
 
     /**
      * 比赛阶段
      */
-    @ExcelProperty(value = "比赛阶段")
+    @ExcelProperty(value = "比赛阶段", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "game_stage")
     private String gameStage;
 
     /**

+ 5 - 3
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameEventVo.java

@@ -61,7 +61,7 @@ public class GameEventVo implements Serializable {
     /**
      * 用途
      */
-    @ExcelProperty(value = "用途")
+    @ExcelProperty(value = "用途", converter = ExcelDictConvert.class)
     @ExcelDictFormat(dictType = "game_event_purpose")
     private String purpose;
 
@@ -91,17 +91,19 @@ public class GameEventVo implements Serializable {
     /**
      * 赛事链接Url
      */
+    @ExcelProperty(value = "赛事链接")
     @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "eventUrl")
     private String eventUrlUrl;
     /**
      * 裁判码
      */
-    @ExcelProperty(value = "裁判码")
+//    @ExcelProperty(value = "裁判码")
     private String refereeUrl;
 
     /**
      * 裁判码Url
      */
+    @ExcelProperty(value = "裁判码")
     @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "refereeUrl")
     private String refereeUrlUrl;
     /**
@@ -125,7 +127,7 @@ public class GameEventVo implements Serializable {
      * 是否默认赛事(0=是,1=否)
      */
     @ExcelProperty(value = "是否默认赛事", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(dictType = "sys_yes_no")
+    @ExcelDictFormat(readConverterExp = "0=是,1=否")
     private String isDefault;
 
     /**

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

@@ -28,7 +28,7 @@ public class GameTeamVo implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
 
-//   @ExcelProperty(value = "主键")
+   @ExcelProperty(value = "队伍Id")
     private Long teamId;
 
     /**
@@ -45,6 +45,7 @@ public class GameTeamVo implements Serializable {
     /**
      * 排名分组名
      */
+    @ExcelProperty(value = "分组名", converter = ExcelDictConvert.class)
     private String rgName;
 
     /**

+ 88 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameAthleteServiceImpl.java

@@ -232,9 +232,97 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
                     vo.setProjectList(projects);
                 });
         });
+        
         return athleteList;
     }
 
+    /**
+     * 导出数据
+     */
+    public List<GameAthleteVo> exportData(GameAthleteBo bo) {
+        List<GameAthleteVo> athleteList = queryList(bo);
+        // 设置序号
+        setRowNumbers(athleteList);
+        // 转换队伍ID为队伍名称
+        convertTeamIdToName(athleteList);
+        
+        // 转换项目ID列表为项目名称列表
+        convertProjectIdsToNames(athleteList);
+
+        return athleteList;
+    }
+
+    /**
+     * 设置序号
+     */
+    private void setRowNumbers(List<GameAthleteVo> athleteList) {
+        IntStream.range(0, athleteList.size())
+        .forEach(i -> athleteList.get(i).setRowNumber(i + 1));
+    }
+
+    /**
+     * 将队伍ID转换为队伍名称
+     */
+    private void convertTeamIdToName(List<GameAthleteVo> athleteList) {
+        // 1. 收集所有队伍ID
+        Set<Long> teamIds = athleteList.stream()
+            .map(GameAthleteVo::getTeamId)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+        
+        // 2. 批量查询队伍信息
+        Map<Long, String> teamIdToNameMap = new HashMap<>();
+        if (CollUtil.isNotEmpty(teamIds)) {
+            LambdaQueryWrapper<GameTeam> wrapper = new LambdaQueryWrapper<>();
+            wrapper.in(GameTeam::getTeamId, teamIds);
+            List<GameTeam> teams = gameTeamMapper.selectList(wrapper);
+            teamIdToNameMap = teams.stream()
+                .collect(Collectors.toMap(GameTeam::getTeamId, GameTeam::getTeamName));
+        }
+        
+        // 3. 设置队伍名称
+        final Map<Long, String> finalTeamMap = teamIdToNameMap;
+        athleteList.forEach(athlete -> {
+            athlete.setTeamName(finalTeamMap.getOrDefault(athlete.getTeamId(), "未分配队伍"));
+        });
+    }
+
+    /**
+     * 将项目ID列表转换为项目名称列表
+     */
+    private void convertProjectIdsToNames(List<GameAthleteVo> athleteList) {
+        // 1. 收集所有项目ID
+        Set<Long> allProjectIds = new HashSet<>();
+        athleteList.forEach(athlete -> {
+            if (CollUtil.isNotEmpty(athlete.getProjectList())) {
+                allProjectIds.addAll(athlete.getProjectList());
+            }
+        });
+        
+        // 2. 批量查询项目信息
+        Map<Long, String> projectIdToNameMap = new HashMap<>();
+        if (CollUtil.isNotEmpty(allProjectIds)) {
+            LambdaQueryWrapper<GameEventProject> wrapper = new LambdaQueryWrapper<>();
+            wrapper.in(GameEventProject::getProjectId, allProjectIds);
+            List<GameEventProject> projects = gameEventProjectMapper.selectList(wrapper);
+            projectIdToNameMap = projects.stream()
+                .collect(Collectors.toMap(GameEventProject::getProjectId, GameEventProject::getProjectName));
+        }
+        
+        // 3. 设置项目名称列表
+        final Map<Long, String> finalProjectMap = projectIdToNameMap;
+        athleteList.forEach(athlete -> {
+            if (CollUtil.isNotEmpty(athlete.getProjectList())) {
+                List<String> projectNames = athlete.getProjectList().stream()
+                    .map(projectId -> finalProjectMap.getOrDefault(projectId, "未知项目"))
+                    .collect(Collectors.toList());
+                athlete.setProjectNames(String.join(",", projectNames));
+            } else {
+                athlete.setProjectNames("");
+            }
+        });
+    }
+
     private LambdaQueryWrapper<GameAthlete> buildQueryWrapper(GameAthleteBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<GameAthlete> lqw = Wrappers.lambdaQuery();

+ 6 - 6
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/IEnrollServiceImpl.java

@@ -374,15 +374,15 @@ public class IEnrollServiceImpl implements IEnrollService {
         if (cell == null) return "";
 
         switch (cell.getCellType()) {
-            case Cell.CELL_TYPE_STRING:
+            case STRING:
                 return cell.getStringCellValue().trim();
-            case Cell.CELL_TYPE_NUMERIC:
+            case NUMERIC:
                 if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                     return cell.getDateCellValue().toString();
                 } else {
                     return String.valueOf((int) cell.getNumericCellValue()); // 或者保留小数用 double
                 }
-            case Cell.CELL_TYPE_BOOLEAN:
+            case BOOLEAN:
                 return String.valueOf(cell.getBooleanCellValue());
             default:
                 return "";
@@ -397,10 +397,10 @@ public class IEnrollServiceImpl implements IEnrollService {
         if (cell == null) return false;
 
         // 先检查单元格类型
-        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
+        if (cell.getCellType() == CellType.BOOLEAN) {
             return cell.getBooleanCellValue();
         }
-        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
+        if (cell.getCellType() == CellType.NUMERIC) {
             return cell.getNumericCellValue() == 1;
         }
 
@@ -903,7 +903,7 @@ public class IEnrollServiceImpl implements IEnrollService {
         if (StringUtils.isNotBlank(enrollInfo.getAthleteCode())) {
             // 如果Excel中有号码,使用Excel中的号码
             athleteCode = enrollInfo.getAthleteCode().trim();
-            
+
             // 验证号码格式
             if (!isValidAthleteCode(athleteCode)) {
                 log.warn("运动员{}的号码格式不正确: {},将使用自动生成的号码", enrollInfo.getName(), athleteCode);