白蚁-日志管理-excel导出

master
yangzhe123 2025-08-27 17:49:31 +08:00
parent a9466ce01b
commit a89571643c
3 changed files with 295 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gunshi.core.result.R; import com.gunshi.core.result.R;
import com.gunshi.project.hsz.entity.dto.ExportCommonDto;
import com.gunshi.project.hsz.entity.so.ByLogPageSo; import com.gunshi.project.hsz.entity.so.ByLogPageSo;
import com.gunshi.project.hsz.model.ByLog; import com.gunshi.project.hsz.model.ByLog;
import com.gunshi.project.hsz.model.ByLogDetail; import com.gunshi.project.hsz.model.ByLogDetail;
@ -16,6 +17,7 @@ import com.gunshi.project.hsz.validate.markers.Update;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -105,4 +107,12 @@ public class ByLogController extends AbstractCommonFileController {
public String getGroupId() { public String getGroupId() {
return "byLog"; return "byLog";
} }
@Operation(description = "日志导出")
@PostMapping("/export")
public void export(@RequestBody ExportCommonDto dto, HttpServletResponse response) {
List<ByLog> byLogs = byLogService.selectByIds(dto.getIds());
byLogService.exportToExcel(byLogs,response);
}
} }

View File

@ -30,4 +30,15 @@ public interface ByLogDetailMapper extends BaseMapper<ByLogDetail> {
""") """)
List<ByLogDetail> selectDetail(@Param("logId") Long id,@Param("dto") ByLogPageSo pageSo); List<ByLogDetail> selectDetail(@Param("logId") Long id,@Param("dto") ByLogPageSo pageSo);
@Select("""
select t1.id,t1.by_log_id,t1.pre_place_detail_id as ppdi,t1.pre_person,t1.pre_method,t1.pre_effect,
t2.detail_name as ppdn,t3.id as ppi,t3.pre_name as ppn
from by_log_detail t1
join pre_place_detail t2
on t1.pre_place_detail_id = t2.id
join pre_place t3
on t2.pre_id = t3.id
where t1.by_log_id = #{logId}
""")
List<ByLogDetail> selectDetailList(@Param("logId") Long id);
} }

View File

@ -6,16 +6,25 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.project.hsz.entity.so.ByLogPageSo; import com.gunshi.project.hsz.entity.so.ByLogPageSo;
import com.gunshi.project.hsz.mapper.AppVersionRecordMapper;
import com.gunshi.project.hsz.mapper.ByLogDetailMapper; import com.gunshi.project.hsz.mapper.ByLogDetailMapper;
import com.gunshi.project.hsz.mapper.ByLogMapper; import com.gunshi.project.hsz.mapper.ByLogMapper;
import com.gunshi.project.hsz.model.*; import com.gunshi.project.hsz.model.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.BatchResult; import org.apache.ibatis.executor.BatchResult;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -64,4 +73,268 @@ public class ByLogService extends ServiceImpl<ByLogMapper, ByLog> {
} }
return byLogPage; return byLogPage;
} }
public List<ByLog> selectByIds(List<Long> ids) {
LambdaQueryWrapper<ByLog> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(ByLog::getId, ids);
List<ByLog> byLogs = this.baseMapper.selectList(queryWrapper);
byLogs.stream().forEach(o ->{
List<ByLogDetail> details = byLogDetailMapper.selectDetailList(o.getId());
o.setDetails(details);
});
return byLogs;
}
// 核心导出方法(无冗余)
public void exportToExcel(List<ByLog> byLogs, HttpServletResponse response) {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("白蚁防治日志");
// 1. 合并创建所有样式原5个样式方法→1个
StyleGroup styles = createAllStyles(workbook);
// 2. 创建标题行(逻辑不变)
createHeaderRow(sheet, styles.headerStyle);
// 3. 填充数据(序号计数器直接在循环内维护,减少参数传递)
fillDataWithMerge(sheet, styles, byLogs);
// 4. 调整列宽(逻辑不变)
adjustColumnWidth(sheet);
// 5. 响应处理(逻辑不变)
String fileName = "白蚁-日志管理" + System.currentTimeMillis();
try {
setResponseHeaders(response, fileName);
workbook.write(response.getOutputStream());
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static class StyleGroup {
CellStyle headerStyle;
CellStyle dataStyle;
CellStyle detailStyle;
CellStyle dateStyle;
CellStyle dateTimeStyle; // 原分散创建,现在统一封装
StyleGroup(CellStyle headerStyle, CellStyle dataStyle, CellStyle detailStyle,
CellStyle dateStyle, CellStyle dateTimeStyle) {
this.headerStyle = headerStyle;
this.dataStyle = dataStyle;
this.detailStyle = detailStyle;
this.dateStyle = dateStyle;
this.dateTimeStyle = dateTimeStyle;
}
}
// 统一创建所有样式原createHeaderStyle/createDataStyle等合并
private StyleGroup createAllStyles(Workbook workbook) {
// 1. 基础数据样式
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setAlignment(HorizontalAlignment.CENTER);
dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
// 2. 表头样式
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.cloneStyleFrom(dataStyle);
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short) 12);
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 3. 详情样式
CellStyle detailStyle = workbook.createCellStyle();
detailStyle.cloneStyleFrom(dataStyle);
detailStyle.setAlignment(HorizontalAlignment.LEFT);
detailStyle.setWrapText(true); // 自动换行
// 4. 日期样式
CreationHelper createHelper = workbook.getCreationHelper();
CellStyle dateStyle = workbook.createCellStyle();
dateStyle.cloneStyleFrom(dataStyle);
dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-MM-dd"));
// 5. 日期时间样式
CellStyle dateTimeStyle = workbook.createCellStyle();
dateTimeStyle.cloneStyleFrom(dataStyle);
dateTimeStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
return new StyleGroup(headerStyle, dataStyle, detailStyle, dateStyle, dateTimeStyle);
}
private void createHeaderRow(Sheet sheet, CellStyle headerStyle) {
Row headerRow = sheet.createRow(0);
String[] headers = {
"序号", "日志名称", "防治日期", "填报时间", "总费用(元)", "备注",
"防治部位", "防治点", "防治人员", "防治方法", "防治效果"
};
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
}
}
private void fillDataWithMerge(Sheet sheet, StyleGroup styles, List<ByLog> dataList) {
int currentRow = 1;
int logSerialNumber = 1; // 序号
for (ByLog log : dataList) {
int detailCount = log.getDetails() != null ? log.getDetails().size() : 0;
int rowSpan = Math.max(detailCount, 1);
Row row = sheet.createRow(currentRow);
// 1. 序号
Cell cell0 = row.createCell(0);
cell0.setCellValue(logSerialNumber);
cell0.setCellStyle(styles.dataStyle);
if (rowSpan > 1) sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow + rowSpan - 1, 0, 0));
// 2. 日志名称
Cell cell1 = row.createCell(1);
cell1.setCellValue(log.getLogName() != null ? log.getLogName() : "");
cell1.setCellStyle(styles.dataStyle);
if (rowSpan > 1) sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow + rowSpan - 1, 1, 1));
// 3. 防治日期
Cell cell2 = row.createCell(2);
if (log.getPreDate() != null) {
cell2.setCellValue(log.getPreDate());
cell2.setCellStyle(styles.dateStyle);
} else {
cell2.setCellValue("");
cell2.setCellStyle(styles.dataStyle);
}
if (rowSpan > 1) sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow + rowSpan - 1, 2, 2));
// 4. 填报时间
Cell cell3 = row.createCell(3);
if (log.getFillTime() != null) {
cell3.setCellValue(log.getFillTime());
cell3.setCellStyle(styles.dateTimeStyle); // 精简:不再临时创建样式
} else {
cell3.setCellValue("");
cell3.setCellStyle(styles.dataStyle);
}
if (rowSpan > 1) sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow + rowSpan - 1, 3, 3));
// 5. 总费用
Cell cell4 = row.createCell(4);
CellStyle currencyStyle = sheet.getWorkbook().createCellStyle();
currencyStyle.cloneStyleFrom(styles.dataStyle);
currencyStyle.setDataFormat((short) 0x27); // 货币格式
if (log.getTotalCost() != null) {
cell4.setCellValue(log.getTotalCost().doubleValue());
} else {
cell4.setCellValue(0);
}
cell4.setCellStyle(currencyStyle);
if (rowSpan > 1) sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow + rowSpan - 1, 4, 4));
Cell cell5 = row.createCell(5);
cell5.setCellValue(log.getRemark() != null ? log.getRemark() : "");
cell5.setCellStyle(styles.dataStyle);
if (rowSpan > 1) sheet.addMergedRegion(new CellRangeAddress(currentRow, currentRow + rowSpan - 1, 5, 5));
if (detailCount > 0) {
fillDetailInfo(row, log.getDetails().get(0), styles.detailStyle);
for (int i = 1; i < detailCount; i++) {
Row detailRow = sheet.createRow(currentRow + i);
for (int col = 0; col <= 5; col++) {
Cell emptyCell = detailRow.createCell(col);
emptyCell.setCellValue("");
if (col == 2) {
emptyCell.setCellStyle(styles.dateStyle); // 防治日期列:用日期样式
} else if (col == 3) {
emptyCell.setCellStyle(styles.dateTimeStyle); // 填报时间列:用日期时间样式
} else if (col == 4) {
emptyCell.setCellStyle(currencyStyle); // 总费用列:用货币样式
} else {
emptyCell.setCellStyle(styles.dataStyle); // 其他列:用基础数据样式
}
}
fillDetailInfo(detailRow, log.getDetails().get(i), styles.detailStyle);
}
} else {
for (int i = 6; i <= 10; i++) {
Cell cell = row.createCell(i);
cell.setCellValue("");
cell.setCellStyle(styles.detailStyle);
}
}
currentRow += rowSpan;
logSerialNumber++; // 序号自增
}
}
private void fillDetailInfo(Row row, ByLogDetail detail, CellStyle style) {
createCell(row, 6, detail.getPpdn(), style); // 防治部位
createCell(row, 7, detail.getPpn(), style); // 防治点
createCell(row, 8, detail.getPrePerson(), style); // 防治人员
createCell(row, 9, detail.getPreMethod(), style); // 防治方法
createCell(row, 10, detail.getPreEffect(), style); // 防治效果
}
private void createCell(Row row, int column, Object value, CellStyle style) {
Cell cell = row.createCell(column);
if (value == null) {
cell.setCellValue("");
} else if (value instanceof String) {
cell.setCellValue((String) value);
} else if (value instanceof Number) {
// 精简合并Long/Integer处理Number是它们的父类
cell.setCellValue(value.toString());
} else if (value instanceof BigDecimal) {
cell.setCellValue(((BigDecimal) value).doubleValue());
} else if (value instanceof Date) {
cell.setCellValue((Date) value);
// 日期样式统一复用StyleGroup逻辑此处简化
CellStyle dateCellStyle = row.getSheet().getWorkbook().createCellStyle();
dateCellStyle.cloneStyleFrom(style);
dateCellStyle.setDataFormat(row.getSheet().getWorkbook().getCreationHelper()
.createDataFormat().getFormat("yyyy-MM-dd"));
cell.setCellStyle(dateCellStyle);
} else {
cell.setCellValue(value.toString());
}
cell.setCellStyle(style);
}
// 列宽调整(逻辑不变)
private void adjustColumnWidth(Sheet sheet) {
int[] columnWidths = {
8 * 256, // 序号
25 * 256, // 日志名称
15 * 256, // 防治日期
25 * 256, // 填报时间
15 * 256, // 总费用
30 * 256, // 备注
20 * 256, // 防治部位
20 * 256, // 防治点
15 * 256, // 防治人员
20 * 256, // 防治方法
15 * 256 // 防治效果
};
for (int i = 0; i < columnWidths.length; i++) {
sheet.setColumnWidth(i, columnWidths[i]);
}
}
// 响应头设置(逻辑不变)
private void setResponseHeaders(HttpServletResponse response, String fileName) throws IOException {
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + encodedFileName + ".xlsx\"");
}
} }