diff --git a/nflg-mobilebroken-admin/pom.xml b/nflg-mobilebroken-admin/pom.xml
index 3b4d44b6..c8932790 100644
--- a/nflg-mobilebroken-admin/pom.xml
+++ b/nflg-mobilebroken-admin/pom.xml
@@ -120,6 +120,11 @@
tinypinyin
2.0.3
+
+ org.apache.poi
+ poi-ooxml
+ 5.2.3
+
diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
index 867d0c40..0f3f1aa6 100644
--- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
+++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
@@ -23,6 +23,12 @@ import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
import com.nflg.mobilebroken.starter.annotation.MethodInfoMark;
import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.RegionUtil;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -39,7 +45,9 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
@@ -842,4 +850,309 @@ public class TicketController extends ControllerBase {
List datas = ticketService.exportSearch(request);
EecExcelUtil.export("工单报表", "sheet1", Convert.toList(AdminTicketReportVO.class, datas), response);
}
+
+ /**
+ * 导出工单详情为excel
+ * @param ticketId 工单编号
+ */
+ @GetMapping("/exportTicketExcel")
+ @ApiMark(moduleName = "工单管理", apiName = "导出工单详情为excel")
+ public void exportExcel(HttpServletResponse response,@Valid @RequestParam @NotNull Integer ticketId) throws Exception {
+ Ticket ticket = ticketService.getById(ticketId);
+ VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
+ Workbook workbook = new XSSFWorkbook();
+ Sheet sheet = workbook.createSheet("Sheet1");
+ sheet.setDefaultColumnWidth(8);
+ sheet.setDefaultRowHeightInPoints(20);
+ CellStyle centerStyle = getCenterStyle(workbook);
+ CellStyle normalStyle = getNormalStyle(workbook);
+ ClassPathResource resource = new ClassPathResource("images/logo.png");
+ InputStream inputStream = resource.getInputStream();
+ float height = 20;
+ byte[] imageBytes = IOUtils.toByteArray(inputStream);
+ int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
+ inputStream.close();
+ // 创建绘图对象
+ Drawing> drawing = sheet.createDrawingPatriarch();
+ // 创建锚点,用于定位图片位置
+ ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
+ anchor.setCol1(0); // 起始列(从 0 开始)
+ anchor.setRow1(0); // 起始行(从 0 开始)
+ anchor.setCol2(3); // 结束列
+ anchor.setRow2(1); // 结束行
+ // 插入图片
+ drawing.createPicture(anchor, pictureIdx);
+ //标题行
+ Row row0 = sheet.createRow(0);
+ row0.setHeightInPoints(25);
+ row0.createCell(0).setCellStyle(centerStyle);
+ addMergedRegion(sheet,0, 0, 0, 2);
+ addMergedRegion(sheet,0, 0, 3, 11);
+ createCell(row0, 3, getTitleStyle(workbook), "CSF系统问题解决方案");
+ //第一行
+ Row row1 = sheet.createRow(1);
+ row1.setHeightInPoints(height);
+ createCell(row1, 0, centerStyle, "主题");
+ addMergedRegion(sheet,1, 1, 1, 4);
+ createCell(row1, 1, normalStyle, ticket.getTitle());
+ createCell(row1, 5, centerStyle, "事故等级");
+ createCell(row1, 6, centerStyle, "一般" + (Objects.equals(ticket.getAccidentLevel(), Byte.valueOf("0")) ? "\u2611" : "\u2610"));
+ createCell(row1, 7, normalStyle, "");
+ createCell(row1, 8, centerStyle, "较严重" + (Objects.equals(ticket.getAccidentLevel(), Byte.valueOf("1")) ? "\u2611" : "\u2610"));
+ createCell(row1, 9, normalStyle, "");
+ createCell(row1, 10, centerStyle, "严重" + (Objects.equals(ticket.getAccidentLevel(), Byte.valueOf("2")) ? "\u2611" : "\u2610"));
+ createCell(row1, 11, normalStyle, "");
+ //第二行
+ Row row2 = sheet.createRow(2);
+ row2.setHeightInPoints(height);
+ createCell(row2, 0, centerStyle, "工单编号");
+ addMergedRegion(sheet,2, 2, 1, 4);
+ createCell(row2, 1, normalStyle, ticket.getNo());
+ createCell(row2, 5, centerStyle, "设备编号");
+ addMergedRegion(sheet,2, 2, 6, 11);
+ createCell(row2, 6, normalStyle, ticket.getDeviceNo());
+ //第三行
+ Row row3 = sheet.createRow(3);
+ createCell(row3, 0, centerStyle, "提交人");
+ addMergedRegion(sheet,3, 3, 1, 4);
+ AppUser user = appUserService.getById(ticket.getUserId());
+ createCell(row3, 1, normalStyle, user.getName());
+ createCell(row3, 5, centerStyle, "反馈日期");
+ addMergedRegion(sheet,3, 3, 6, 11);
+ createCell(row3, 6, normalStyle, DateTimeUtil.format(ticket.getCreateTime()));
+ //第四行
+ Row row4 = sheet.createRow(4);
+ row4.setHeightInPoints(height);
+ createCell(row4, 0, centerStyle, "设备地点");
+ addMergedRegion(sheet,4, 4, 1, 4);
+ createCell(row4, 1, normalStyle, ticket.getDeviceAddress());
+ createCell(row4, 5, centerStyle, "处理人员");
+ addMergedRegion(sheet,4, 4, 6, 11);
+ createCell(row4, 6, normalStyle, ticket.getHandleName());
+ //第五行
+ Row row5 = sheet.createRow(5);
+ row5.setHeightInPoints(height);
+ createCell(row5, 0, centerStyle, "问题类型");
+ addMergedRegion(sheet,5, 5, 1, 4);
+ createCell(row5, 1, normalStyle, ticket.getQuestion());
+ createCell(row5, 5, centerStyle, "问题部位");
+ addMergedRegion(sheet,5, 5, 6, 11);
+ createCell(row5, 6, normalStyle, ticket.getComponent());
+ //第六行
+ Row row6 = sheet.createRow(6);
+ row6.setHeightInPoints(height);
+ createCell(row6, 0, centerStyle, "问题描述");
+ addMergedRegion(sheet,6, 6, 1, 11);
+ createCell(row6, 1, normalStyle, ticket.getDescription());
+ //第七行
+ Row row7 = sheet.createRow(7);
+ row7.setHeightInPoints(height);
+ List images = new ArrayList<>();
+ if (StrUtil.isNotBlank(ticket.getAttachments())) {
+ StrUtil.split(ticket.getAttachments(), ",").forEach(item -> {
+ if (item.endsWith(".jpg") || item.endsWith(".png") || item.endsWith(".jpeg")) {
+ images.add(new FileInfo(item.substring(item.lastIndexOf("/") + 1), urlEncode(item)));
+ }
+ });
+ }
+ if (StrUtil.isNotBlank(ticket.getImages())) {
+ StrUtil.split(ticket.getImages(), ",").forEach(item -> {
+ images.add(new FileInfo(item.substring(item.lastIndexOf("/") + 1), item));
+ });
+ }
+ int rowIndex = 6;
+ int rows = images.size() % 2 == 0 ? images.size() / 2 : images.size() / 2 + 1;
+ if (rows > 1) {
+ addMergedRegion(sheet,rowIndex + 1, rowIndex + rows, 0, 0);
+ }
+ createCell(row7, 0, centerStyle, "案例照片");
+ if (rows == 0) {
+ addMergedRegion(sheet,rowIndex + 1, rowIndex + 1, 1, 5);
+ addMergedRegion(sheet,rowIndex + 1, rowIndex + 1, 6, 11);
+ rowIndex++;
+ } else {
+ for (int i = 0; i < images.size(); i++) {
+ if (i % 2 == 0) {
+ rowIndex++;
+ bindPic(images.get(i).getUrl(), workbook, sheet, rowIndex, 1, 6);
+ } else {
+ bindPic(images.get(i).getUrl(), workbook, sheet, rowIndex, 6, 12);
+ }
+ }
+ if (images.size() % 2 != 0) {
+ addMergedRegion(sheet,rowIndex, rowIndex, 6, 11);
+ }
+ }
+ rowIndex++;
+ Row row8 = sheet.createRow(rowIndex);
+ row8.setHeightInPoints(height);
+ addMergedRegion(sheet,rowIndex, rowIndex, 0, 11);
+ createCell(row8, 0, normalStyle, "根本原因分析");
+ rowIndex++;
+ Row row9 = sheet.createRow(rowIndex);
+ row9.setHeightInPoints(height);
+ addMergedRegion(sheet,rowIndex, rowIndex, 0, 11);
+ createCell(row9, 0, normalStyle, ticket.getReason());
+ //解决方案
+ List solutions = ticketSolutionService.lambdaQuery().eq(TicketSolution::getTicketId,ticketId).orderByAsc(TicketSolution::getId).list();
+ if (CollectionUtil.isNotEmpty(solutions)) {
+ Map> map=solutions.stream().collect(Collectors.groupingBy(TicketSolution::getDictionaryItemName, LinkedHashMap::new, Collectors.toList()));
+ for (Map.Entry> item : map.entrySet()) {
+ rowIndex++;
+ Row row10 = sheet.createRow(rowIndex);
+ row10.setHeightInPoints(height);
+ createCell(row10, 0, centerStyle, "No.");
+ addMergedRegion(sheet,rowIndex, rowIndex, 1, 6);
+ createCell(row10, 1, centerStyle, item.getKey());
+ createCell(row10, 7, centerStyle, "负责人");
+ createCell(row10, 8, centerStyle, "计划日期");
+ createCell(row10, 9, centerStyle, "确认日期");
+ addMergedRegion(sheet,rowIndex, rowIndex, 10, 11);
+ createCell(row10, 10, centerStyle, "备注");
+ for (int i = 0; i < item.getValue().size(); i++) {
+ rowIndex++;
+ TicketSolution solution = item.getValue().get(i);
+ Row row11 = sheet.createRow(rowIndex);
+ row11.setHeightInPoints(height);
+ createCell(row11, 0, centerStyle, String.valueOf(i + 1));
+ addMergedRegion(sheet,rowIndex, rowIndex, 1, 6);
+ createCell(row11, 1, normalStyle, solution.getDescription());
+ createCell(row11, 7, centerStyle, solution.getSuperintendent());
+ createCell(row11, 8, centerStyle, solution.getScheduleDate());
+ createCell(row11, 9, centerStyle, solution.getConfirmedDate());
+ addMergedRegion(sheet,rowIndex, rowIndex, 10, 11);
+ createCell(row11, 10, normalStyle, solution.getRemark());
+ }
+ }
+ }
+ //解决方案审核
+ List reviewDepartments = ticketSolutionAuditService.getByTicket(ticketId)
+ .stream()
+ .filter(vo -> StrUtil.isNotBlank(vo.getUserName()))
+ .collect(Collectors.toList());
+ if (CollectionUtil.isNotEmpty(reviewDepartments)) {
+ rowIndex++;
+ Row row12 = sheet.createRow(rowIndex);
+ row12.setHeightInPoints(height);
+ addMergedRegion(sheet,rowIndex, rowIndex, 0, 11);
+ createCell(row12, 0, normalStyle, "相关部门审核确认");
+ rowIndex++;
+ Row row13 = sheet.createRow(rowIndex);
+ row13.setHeightInPoints(height);
+ Row row14 = sheet.createRow(rowIndex + 1);
+ row14.setHeightInPoints(height);
+ for (int i = 0; i < reviewDepartments.size(); i++) {
+ SolutionReviewDepartmentVO reviewDepartment = reviewDepartments.get(i);
+ addMergedRegion(sheet,rowIndex, rowIndex, i * 2, i * 2 + 1);
+ createCell(row13, i * 2, centerStyle, reviewDepartment.getDeptName() + "(" + reviewDepartment.getUserName() + ")");
+ addMergedRegion(sheet,rowIndex + 1, rowIndex + 1, i * 2, i * 2 + 1);
+ createCell(row14, i * 2, centerStyle, Objects.isNull(reviewDepartment.getState()) ? "" : (Objects.equals(reviewDepartment.getState(), 1) ? "通过" : "不通过"));
+ }
+ }
+ response.setContentType("application/vnd.ms-excel");
+ response.setHeader("Content-Disposition", "attachment;filename=ticket.xlsx");
+ try (OutputStream outputStream = response.getOutputStream()) {
+ workbook.write(outputStream);
+ } finally {
+ workbook.close();
+ }
+ }
+
+ private void addMergedRegion(Sheet sheet,int firstRow, int lastRow, int firstCol, int lastCol){
+ CellRangeAddress region = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
+ sheet.addMergedRegion(region);
+ RegionUtil.setBorderBottom(BorderStyle.THIN, region, sheet);
+ RegionUtil.setBorderTop(BorderStyle.THIN, region, sheet);
+ RegionUtil.setBorderLeft(BorderStyle.THIN, region, sheet);
+ RegionUtil.setBorderRight(BorderStyle.THIN, region, sheet);
+ }
+
+ private void createCell(Row row,int index,CellStyle style,String value){
+ Cell cell =row.createCell(index);
+ cell.setCellValue(value);
+ cell.setCellStyle(style);
+ }
+
+ private void bindPic(String url, Workbook workbook,Sheet sheet, int rowIndex, int colStart, int colEnd){
+ try {
+ byte[] imageBytes;
+ try (InputStream inputStream = new URL(url).openStream()) {
+ imageBytes = IOUtils.toByteArray(inputStream);
+ }
+ int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
+ Drawing> drawing = sheet.createDrawingPatriarch();
+ addMergedRegion(sheet,rowIndex,rowIndex,colStart,colEnd-1);
+ ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
+ anchor.setCol1(colStart);
+ anchor.setRow1(rowIndex);
+ anchor.setCol2(colEnd);
+ anchor.setRow2(rowIndex+1);
+ drawing.createPicture(anchor, pictureIdx);
+ Row row = sheet.getRow(rowIndex);
+ if (row == null) {
+ row = sheet.createRow(rowIndex);
+ }
+ row.setHeightInPoints(200);
+ }catch (Exception ex){
+ log.error("图片加载失败",ex);
+ }
+ }
+
+ private CellStyle getNormalStyle(Workbook workbook){
+ CellStyle centerStyle = workbook.createCellStyle();
+ centerStyle.setAlignment(HorizontalAlignment.LEFT);
+ centerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+ Font normalFont = workbook.createFont();
+ normalFont.setFontName("DejaVu Sans"); // 设置字体名称
+ normalFont.setFontHeightInPoints((short) 8); // 设置字体大小(单位为点)
+ centerStyle.setFont(normalFont);
+ centerStyle.setBorderTop(BorderStyle.THIN); // 上边框
+ centerStyle.setBorderBottom(BorderStyle.THIN); // 下边框
+ centerStyle.setBorderLeft(BorderStyle.THIN); // 左边框
+ centerStyle.setBorderRight(BorderStyle.THIN); // 右边框
+ centerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框颜色
+ centerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框颜色
+ centerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框颜色
+ centerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框颜色
+ return centerStyle;
+ }
+
+ private CellStyle getCenterStyle(Workbook workbook){
+ CellStyle centerStyle = workbook.createCellStyle();
+ centerStyle.setAlignment(HorizontalAlignment.CENTER);
+ centerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+ Font normalFont = workbook.createFont();
+ normalFont.setFontName("DejaVu Sans"); // 设置字体名称
+ normalFont.setFontHeightInPoints((short) 8); // 设置字体大小(单位为点)
+ centerStyle.setFont(normalFont);
+ centerStyle.setBorderTop(BorderStyle.THIN); // 上边框
+ centerStyle.setBorderBottom(BorderStyle.THIN); // 下边框
+ centerStyle.setBorderLeft(BorderStyle.THIN); // 左边框
+ centerStyle.setBorderRight(BorderStyle.THIN); // 右边框
+ centerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框颜色
+ centerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框颜色
+ centerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框颜色
+ centerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框颜色
+ return centerStyle;
+ }
+
+ private CellStyle getTitleStyle(Workbook workbook){
+ CellStyle titleStyle = workbook.createCellStyle();
+ titleStyle.setAlignment(HorizontalAlignment.CENTER);
+ titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+ Font fontTitle = workbook.createFont();
+ fontTitle.setFontName("DejaVu Sans"); // 设置字体名称
+ fontTitle.setFontHeightInPoints((short) 15); // 设置字体大小(单位为点)
+ fontTitle.setBold(true);
+ titleStyle.setFont(fontTitle);
+ titleStyle.setBorderTop(BorderStyle.THIN); // 上边框
+ titleStyle.setBorderBottom(BorderStyle.THIN); // 下边框
+ titleStyle.setBorderLeft(BorderStyle.THIN); // 左边框
+ titleStyle.setBorderRight(BorderStyle.THIN); // 右边框
+ titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); // 上边框颜色
+ titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // 下边框颜色
+ titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); // 左边框颜色
+ titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); // 右边框颜色
+ return titleStyle;
+ }
}
\ No newline at end of file
diff --git a/nflg-mobilebroken-admin/src/main/resources/images/logo.png b/nflg-mobilebroken-admin/src/main/resources/images/logo.png
new file mode 100644
index 00000000..34ae65a8
Binary files /dev/null and b/nflg-mobilebroken-admin/src/main/resources/images/logo.png differ