|
|
@@ -26,6 +26,24 @@ import java.util.Map;
|
|
|
import java.util.Collection;
|
|
|
import java.util.Set;
|
|
|
import java.util.stream.Collectors;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import jakarta.servlet.http.HttpServletResponse;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFRow;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFCell;
|
|
|
+import org.apache.poi.ss.usermodel.CellStyle;
|
|
|
+import org.apache.poi.ss.usermodel.Font;
|
|
|
+import org.apache.poi.ss.usermodel.BorderStyle;
|
|
|
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
|
|
+import org.apache.poi.ss.usermodel.VerticalAlignment;
|
|
|
+import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import org.dromara.xg.domain.XgDormBed;
|
|
|
+import org.dromara.xg.mapper.XgDormBedMapper;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.OutputStream;
|
|
|
|
|
|
/**
|
|
|
* 宿舍房间信息Service业务层处理
|
|
|
@@ -41,6 +59,7 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
|
|
private final XgDormRoomMapper baseMapper;
|
|
|
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
|
|
private final XgSysDeptMapper xgSysDeptMapper;
|
|
|
+ private final XgDormBedMapper xgDormBedMapper;
|
|
|
|
|
|
/**
|
|
|
* 查询宿舍房间信息
|
|
|
@@ -312,4 +331,265 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
|
|
return Set.of();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出住宿清单(宿舍卡片式布局)
|
|
|
+ *
|
|
|
+ * @param params 导出参数
|
|
|
+ * @param response HTTP响应对象
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void exportAccommodationList(Map<String, Object> params, HttpServletResponse response) {
|
|
|
+ try {
|
|
|
+ // 解析参数
|
|
|
+ Long buildingId = Long.valueOf(params.get("buildingId").toString());
|
|
|
+ String buildingName = params.get("buildingName").toString();
|
|
|
+ String buildingType = params.get("buildingType").toString();
|
|
|
+ String buildingTypeText = "1".equals(buildingType) ? "男生楼" : "女生楼";
|
|
|
+
|
|
|
+ // 解析JSON字符串
|
|
|
+ String accommodationDataJson = params.get("accommodationData").toString();
|
|
|
+ ObjectMapper objectMapper = new ObjectMapper();
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, Object> accommodationData = objectMapper.readValue(accommodationDataJson, Map.class);
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, Object> buildingInfo = (Map<String, Object>) accommodationData.get("buildingInfo");
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ List<Map<String, Object>> floorDataList = (List<Map<String, Object>>) accommodationData.get("floorData");
|
|
|
+
|
|
|
+ // 创建Excel工作簿
|
|
|
+ try (XSSFWorkbook workbook = new XSSFWorkbook()) {
|
|
|
+ XSSFSheet sheet = workbook.createSheet(buildingName + "住宿清单");
|
|
|
+
|
|
|
+ // 创建样式
|
|
|
+ CellStyle titleStyle = createTitleStyle(workbook);
|
|
|
+ CellStyle headerStyle = createHeaderStyle(workbook);
|
|
|
+ CellStyle dataStyle = createDataStyle(workbook);
|
|
|
+ CellStyle roomNameStyle = createRoomNameStyle(workbook);
|
|
|
+
|
|
|
+ int currentRow = 0;
|
|
|
+
|
|
|
+ // 添加标题
|
|
|
+ XSSFRow titleRow = sheet.createRow(currentRow++);
|
|
|
+ XSSFCell titleCell = titleRow.createCell(0);
|
|
|
+ titleCell.setCellValue(buildingName + " " + buildingTypeText + " 住宿清单");
|
|
|
+ titleCell.setCellStyle(titleStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 19)); // 合并20列
|
|
|
+ currentRow++; // 空行
|
|
|
+
|
|
|
+ // 处理每个楼层
|
|
|
+ for (Map<String, Object> floorData : floorDataList) {
|
|
|
+ Integer floorNum = (Integer) floorData.get("floorNum");
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ List<Map<String, Object>> rooms = (List<Map<String, Object>>) floorData.get("rooms");
|
|
|
+
|
|
|
+ if (rooms == null || rooms.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加楼层标题
|
|
|
+ XSSFRow floorRow = sheet.createRow(currentRow++);
|
|
|
+ XSSFCell floorCell = floorRow.createCell(0);
|
|
|
+ floorCell.setCellValue("第" + floorNum + "层");
|
|
|
+ floorCell.setCellStyle(headerStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow - 1, currentRow - 1, 0, 19));
|
|
|
+ currentRow++; // 空行
|
|
|
+
|
|
|
+ // 按4个宿舍一行进行分组处理
|
|
|
+ for (int i = 0; i < rooms.size(); i += 4) {
|
|
|
+ int endIndex = Math.min(i + 4, rooms.size());
|
|
|
+ List<Map<String, Object>> roomGroup = rooms.subList(i, endIndex);
|
|
|
+
|
|
|
+ // 处理当前组的宿舍
|
|
|
+ currentRow = processRoomGroup(sheet, roomGroup, currentRow, roomNameStyle, headerStyle,
|
|
|
+ dataStyle);
|
|
|
+ currentRow += 2; // 组间空行
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置列宽 (4个宿舍,每个宿舍4列,宿舍间3个空列,共19列)
|
|
|
+ for (int i = 0; i < 20; i++) {
|
|
|
+ sheet.setColumnWidth(i, 15 * 256); // 15个字符宽度
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置响应头
|
|
|
+ String fileName = buildingName + "_住宿清单_" + System.currentTimeMillis() + ".xlsx";
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ response.setHeader("Content-Disposition",
|
|
|
+ "attachment; filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\"");
|
|
|
+
|
|
|
+ // 输出Excel文件
|
|
|
+ try (OutputStream outputStream = response.getOutputStream()) {
|
|
|
+ workbook.write(outputStream);
|
|
|
+ outputStream.flush();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("导出住宿清单失败", e);
|
|
|
+ throw new RuntimeException("导出住宿清单失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理一组宿舍(最多4个)
|
|
|
+ */
|
|
|
+ private int processRoomGroup(XSSFSheet sheet, List<Map<String, Object>> roomGroup, int startRow,
|
|
|
+ CellStyle roomNameStyle, CellStyle headerStyle, CellStyle dataStyle) {
|
|
|
+ int currentRow = startRow;
|
|
|
+
|
|
|
+ // 宿舍名称行
|
|
|
+ XSSFRow roomNameRow = sheet.createRow(currentRow++);
|
|
|
+ for (int i = 0; i < roomGroup.size(); i++) {
|
|
|
+ Map<String, Object> room = roomGroup.get(i);
|
|
|
+ String roomName = (String) room.get("roomName");
|
|
|
+
|
|
|
+ // 每个宿舍占4列,宿舍之间增加1列间隔 (i * 5)
|
|
|
+ int startCol = i * 5;
|
|
|
+
|
|
|
+ // 为整个合并区域的所有单元格创建并设置样式
|
|
|
+ for (int col = startCol; col <= startCol + 3; col++) {
|
|
|
+ XSSFCell cell = roomNameRow.createCell(col);
|
|
|
+ cell.setCellStyle(roomNameStyle);
|
|
|
+ if (col == startCol) {
|
|
|
+ cell.setCellValue(roomName); // 只在第一个单元格设置值
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow - 1, currentRow - 1, startCol, startCol + 3));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 表头行
|
|
|
+ XSSFRow headerRow = sheet.createRow(currentRow++);
|
|
|
+ String[] headers = { "床位", "姓名", "班级", "备注" };
|
|
|
+ for (int i = 0; i < roomGroup.size(); i++) {
|
|
|
+ for (int j = 0; j < headers.length; j++) {
|
|
|
+ // 每个宿舍占4列,宿舍之间增加1列间隔 (i * 5)
|
|
|
+ XSSFCell headerCell = headerRow.createCell(i * 5 + j);
|
|
|
+ headerCell.setCellValue(headers[j]);
|
|
|
+ headerCell.setCellStyle(headerStyle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算最大床位数
|
|
|
+ int maxBeds = roomGroup.stream()
|
|
|
+ .mapToInt(room -> {
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ List<Map<String, Object>> beds = (List<Map<String, Object>>) room.get("beds");
|
|
|
+ return beds != null ? beds.size() : 0;
|
|
|
+ })
|
|
|
+ .max()
|
|
|
+ .orElse(0);
|
|
|
+
|
|
|
+ // 床位数据行
|
|
|
+ for (int bedIndex = 0; bedIndex < maxBeds; bedIndex++) {
|
|
|
+ XSSFRow dataRow = sheet.createRow(currentRow++);
|
|
|
+
|
|
|
+ for (int roomIndex = 0; roomIndex < roomGroup.size(); roomIndex++) {
|
|
|
+ Map<String, Object> room = roomGroup.get(roomIndex);
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ List<Map<String, Object>> beds = (List<Map<String, Object>>) room.get("beds");
|
|
|
+
|
|
|
+ if (beds != null && bedIndex < beds.size()) {
|
|
|
+ Map<String, Object> bed = beds.get(bedIndex);
|
|
|
+
|
|
|
+ // 每个宿舍占4列,宿舍之间增加1列间隔 (roomIndex * 5)
|
|
|
+ // 床位
|
|
|
+ XSSFCell bedNameCell = dataRow.createCell(roomIndex * 5);
|
|
|
+ bedNameCell.setCellValue((String) bed.get("bedName"));
|
|
|
+ bedNameCell.setCellStyle(dataStyle);
|
|
|
+
|
|
|
+ // 姓名
|
|
|
+ XSSFCell studentNameCell = dataRow.createCell(roomIndex * 5 + 1);
|
|
|
+ studentNameCell.setCellValue((String) bed.get("studentName"));
|
|
|
+ studentNameCell.setCellStyle(dataStyle);
|
|
|
+
|
|
|
+ // 班级
|
|
|
+ XSSFCell classNameCell = dataRow.createCell(roomIndex * 5 + 2);
|
|
|
+ classNameCell.setCellValue((String) bed.get("className"));
|
|
|
+ classNameCell.setCellStyle(dataStyle);
|
|
|
+
|
|
|
+ // 备注
|
|
|
+ XSSFCell remarkCell = dataRow.createCell(roomIndex * 5 + 3);
|
|
|
+ remarkCell.setCellValue((String) bed.get("bedRemark"));
|
|
|
+ remarkCell.setCellStyle(dataStyle);
|
|
|
+ } else {
|
|
|
+ // 空床位
|
|
|
+ for (int j = 0; j < 4; j++) {
|
|
|
+ XSSFCell emptyCell = dataRow.createCell(roomIndex * 5 + j);
|
|
|
+ emptyCell.setCellValue("");
|
|
|
+ emptyCell.setCellStyle(dataStyle);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return currentRow;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建标题样式
|
|
|
+ */
|
|
|
+ private CellStyle createTitleStyle(XSSFWorkbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 16);
|
|
|
+ style.setFont(font);
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建表头样式
|
|
|
+ */
|
|
|
+ private CellStyle createHeaderStyle(XSSFWorkbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建数据样式
|
|
|
+ */
|
|
|
+ private CellStyle createDataStyle(XSSFWorkbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建宿舍名称样式
|
|
|
+ */
|
|
|
+ private CellStyle createRoomNameStyle(XSSFWorkbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 14);
|
|
|
+ style.setFont(font);
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
}
|