白蚁-日志管理-excel导出
parent
a9466ce01b
commit
a89571643c
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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\"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue