Parcourir la source

fix: 处理确认书导出下面图标乱飘逸的问题

luofeiyun il y a 2 semaines
Parent
commit
7f4a92739b

+ 49 - 1
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/order/OtcTradeOrderController.java

@@ -46,6 +46,8 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.IOUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -60,6 +62,7 @@ import javax.annotation.security.PermitAll;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
@@ -658,7 +661,52 @@ public class OtcTradeOrderController {
         response.setContentType("application/vnd.ms-excel");
         response.setHeader("Content-Disposition", "attachment; filename=" + tempFile.getName());
         InputStream is = Files.newInputStream(tempFile.toPath());
-        IOUtils.copy(is, response.getOutputStream());
+
+        Workbook workbook = new XSSFWorkbook(is);
+        Sheet sheet = workbook.getSheetAt(0);
+
+        InputStream logo = getClass().getClassLoader().getResourceAsStream("templates/logo.png");
+        byte[] bytes = org.apache.poi.util.IOUtils.toByteArray(logo);
+        // 读取图片文件到byte数组
+        int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
+        logo.close();
+
+        // 创建drawing patriarch和anchor对象
+        CreationHelper helper = workbook.getCreationHelper();
+        Drawing drawing = sheet.createDrawingPatriarch();
+        ClientAnchor anchor = helper.createClientAnchor();
+
+        int lastRowNum = sheet.getLastRowNum();
+        int rowNum = 0;
+        for(int i = 0; i <= lastRowNum; i++) {
+            Row row = sheet.getRow(i);
+            if(row != null) {
+                Cell cell = row.getCell(0);
+                if(cell != null) {
+                    if(cell.getStringCellValue().equals("a")) {
+                        rowNum = i;
+                        break;
+                    }
+                }
+            }
+        }
+        // 设置图片位置和大小(例如,放在A1单元格)
+        anchor.setCol1(6); // Column A
+        anchor.setRow1(rowNum); // Row 1
+        anchor.setDx1(10); // 水平偏移量(相对于锚点的像素)
+        anchor.setDy1(10);
+
+        // 创建图片对象并设置到workbook中
+        Picture pict = drawing.createPicture(anchor, pictureIdx);
+        pict.resize(); // 根据anchor调整图片大小
+
+        // 关闭流并保存文件
+        FileOutputStream out = new FileOutputStream(tempFile.toPath().toString());
+        workbook.write(out);
+        out.close();
+        workbook.close();
+        InputStream is1 = Files.newInputStream(tempFile.toPath());
+        IOUtils.copy(is1, response.getOutputStream());
     }
 
 

+ 2 - 1
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/OtcTradeOrderService.java

@@ -21,6 +21,7 @@ import com.yc.ship.module.trade.dal.dataobject.order.TradeDetailBaseDO;
 
 import javax.validation.Valid;
 import java.io.File;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.util.List;
 
@@ -143,7 +144,7 @@ public interface OtcTradeOrderService {
     /**
      * 生成确认单
      */
-    File createConfirmaction(Long id, Double totalMoney);
+    File createConfirmaction(Long id, Double totalMoney) throws IOException;
 
     CommonResult<?> orderRead(Long orderId);
 

+ 150 - 106
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/OtcTradeOrderServiceImpl.java

@@ -8,7 +8,10 @@ import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.EasyExcelFactory;
 import com.alibaba.excel.ExcelWriter;
 import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.metadata.data.ImageData;
+import com.alibaba.excel.metadata.data.WriteCellData;
 import com.alibaba.excel.util.DateUtils;
+import com.alibaba.excel.util.FileUtils;
 import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
 import com.alibaba.excel.write.merge.AbstractMergeStrategy;
 import com.alibaba.excel.write.metadata.WriteSheet;
@@ -31,6 +34,7 @@ import com.yc.ship.framework.common.util.collection.CollectionUtils;
 import com.yc.ship.framework.common.util.object.BeanUtils;
 import com.yc.ship.framework.common.util.object.ObjectUtils;
 import com.yc.ship.framework.dict.core.DictFrameworkUtils;
+import com.yc.ship.framework.excel.core.merge.MergeStrategy;
 import com.yc.ship.framework.ip.core.utils.AreaUtils;
 import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
 import com.yc.ship.framework.security.core.LoginUser;
@@ -136,9 +140,13 @@ import com.yc.ship.module.trade.utils.AgencyAuthUtils;
 import com.yc.ship.module.trade.utils.excel.ExcelStyleHandler;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 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.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jetbrains.annotations.NotNull;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
@@ -146,8 +154,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.io.File;
-import java.io.InputStream;
+import java.io.*;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
@@ -3418,112 +3425,149 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
 
     @Override
     public File createConfirmaction(Long id, Double totalMoney) {
-        TradeOrderConfirmationVO orderConfirmation = getOrderConfirmation(id);
-        InputStream template = getClass().getClassLoader().getResourceAsStream("templates/confirmation_template.xlsx");
-        String tmpFile = "/tmp/" + orderConfirmation.getId() + ".xlsx";
-        ExcelWriter excelWriter = EasyExcel.write(tmpFile).withTemplate(template).build();
-        ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcelFactory.writerSheet();
-        // 需要合并单元格的writeSheet
-        WriteSheet writeSheet = excelWriterSheetBuilder.registerWriteHandler(new MergeStrategy()).build();
-        FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
-
-        // 订单信息
-        Map<String, Object> orderData = new HashMap<>();
-        orderData.put("orderNo", orderConfirmation.getOrderNo());
-        orderData.put("shipName", orderConfirmation.getShipName());
-        orderData.put("shipNameEn", orderConfirmation.getShipNameEn());
-        orderData.put("groupNo", orderConfirmation.getGroupNo());
-        orderData.put("sourceName", orderConfirmation.getSourceName());
-        orderData.put("linkMan", orderConfirmation.getLinkMan());
-        orderData.put("linkMobile", orderConfirmation.getLinkMobile());
-        orderData.put("amount", orderConfirmation.getAmount());
-        orderData.put("remark", orderConfirmation.getRemark());
-
-        VoyageRespVO voyage = orderConfirmation.getVoyage();
-        //此处改为订单号最后的序号,如CJXLY-20260526-YC-13订单,登船序号应为13
-        String[] split = orderConfirmation.getOrderNo().split("-");
-        String split1 = split[split.length - 1];
-        orderData.put("voyageCode", split1);
-
-        orderData.put("boardingTime", DateUtil.format(Date.from(voyage.getBoardingTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
-        orderData.put("startTime", DateUtil.format(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
-        orderData.put("leaveTime", DateUtil.format(Date.from(voyage.getLeaveTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
-
-        ResourceRouteDO resourceRouteDO = orderConfirmation.getResourceRouteDO();
-        String resourceRoute = "重庆-宜昌";
-        String resourceRouteEn = "Chongqing-Yichang";
-        if (resourceRouteDO != null && resourceRouteDO.getDirection() != null && resourceRouteDO.getDirection() == 1) {
-            resourceRoute = "宜昌-重庆";
-            resourceRouteEn = "Yichang-Chongqing";
-        }
-        orderData.put("resourceRoute", resourceRoute);
-        orderData.put("resourceRouteEn", resourceRouteEn);
-
-        // 房型信息
-        List<Map<String, Object>> roomData = new ArrayList<>();
-        List<TradeOrderConfirmationCountryRespVO> countryList = orderConfirmation.getCountryList();
-        if (countryList != null) {
-            countryList.forEach(item -> {
-                String roomModelName = item.getRoomModelName();
-                if (item.getFloor() == null) {
-                    if ("leader".equals(item.getType())) {
-                        roomModelName = roomModelName + "(领队)";
-                    } else if ("with".equals(item.getType())) {
-                        roomModelName = roomModelName + "(陪同)";
+        try {
+            TradeOrderConfirmationVO orderConfirmation = getOrderConfirmation(id);
+            InputStream template = getClass().getClassLoader().getResourceAsStream("templates/confirmation_template.xlsx");
+            String tmpFile = "/tmp/" + orderConfirmation.getId() + ".xlsx";
+            ExcelWriter excelWriter = EasyExcel.write(tmpFile).withTemplate(template).build();
+            ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcelFactory.writerSheet();
+            // 需要合并单元格的writeSheet
+            WriteSheet writeSheet = excelWriterSheetBuilder.registerWriteHandler(new MergeStrategy()).build();
+            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
+
+            // 订单信息
+            Map<String, Object> orderData = new HashMap<>();
+            orderData.put("orderNo", orderConfirmation.getOrderNo());
+            orderData.put("shipName", orderConfirmation.getShipName());
+            orderData.put("shipNameEn", orderConfirmation.getShipNameEn());
+            orderData.put("groupNo", orderConfirmation.getGroupNo());
+            orderData.put("sourceName", orderConfirmation.getSourceName());
+            orderData.put("linkMan", orderConfirmation.getLinkMan());
+            orderData.put("linkMobile", orderConfirmation.getLinkMobile());
+            orderData.put("amount", orderConfirmation.getAmount());
+            orderData.put("remark", orderConfirmation.getRemark());
+
+            VoyageRespVO voyage = orderConfirmation.getVoyage();
+            //此处改为订单号最后的序号,如CJXLY-20260526-YC-13订单,登船序号应为13
+            String[] split = orderConfirmation.getOrderNo().split("-");
+            String split1 = split[split.length - 1];
+            orderData.put("voyageCode", split1);
+
+            orderData.put("boardingTime", DateUtil.format(Date.from(voyage.getBoardingTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
+            orderData.put("startTime", DateUtil.format(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
+            orderData.put("leaveTime", DateUtil.format(Date.from(voyage.getLeaveTime().atZone(ZoneOffset.ofHours(8)).toInstant()), "yyyy-MM-dd HH:mm"));
+
+            ResourceRouteDO resourceRouteDO = orderConfirmation.getResourceRouteDO();
+            String resourceRoute = "重庆-宜昌";
+            String resourceRouteEn = "Chongqing-Yichang";
+            if (resourceRouteDO != null && resourceRouteDO.getDirection() != null && resourceRouteDO.getDirection() == 1) {
+                resourceRoute = "宜昌-重庆";
+                resourceRouteEn = "Yichang-Chongqing";
+            }
+            orderData.put("resourceRoute", resourceRoute);
+            orderData.put("resourceRouteEn", resourceRouteEn);
+
+            // 房型信息
+            List<Map<String, Object>> roomData = new ArrayList<>();
+            List<TradeOrderConfirmationCountryRespVO> countryList = orderConfirmation.getCountryList();
+            if (countryList != null) {
+                countryList.forEach(item -> {
+                    String roomModelName = item.getRoomModelName();
+                    if (item.getFloor() == null) {
+                        if ("leader".equals(item.getType())) {
+                            roomModelName = roomModelName + "(领队)";
+                        } else if ("with".equals(item.getType())) {
+                            roomModelName = roomModelName + "(陪同)";
+                        }
+                    } else {
+                        roomModelName = roomModelName + "(" + item.getFloor() + "F)";
                     }
-                } else {
-                    roomModelName = roomModelName + "(" + item.getFloor() + "F)";
-                }
-                Map<String, Object> room = new HashMap<>();
-                room.put("roomModelName", roomModelName);
-                room.put("countryName", item.getNationalityName());
-                room.put("personTypeDes", getPersonTypeDes1(item.getType()));
-                room.put("personTypeDesEn", getPersonTypeDesEn1(item.getType()));
-                room.put("qty", item.getNum());
-                room.put("price", item.getActualPrice());
-                room.put("realMoney", item.getActualPrice().multiply(new BigDecimal(item.getNum())));
-                roomData.add(room);
-            });
+                    Map<String, Object> room = new HashMap<>();
+                    room.put("roomModelName", roomModelName);
+                    room.put("countryName", item.getNationalityName());
+                    room.put("personTypeDes", getPersonTypeDes1(item.getType()));
+                    room.put("personTypeDesEn", getPersonTypeDesEn1(item.getType()));
+                    room.put("qty", item.getNum());
+                    room.put("price", item.getActualPrice());
+                    room.put("realMoney", item.getActualPrice().multiply(new BigDecimal(item.getNum())));
+                    roomData.add(room);
+                });
+            }
+            orderData.put("countryDes", orderConfirmation.getCountryDesc());
+            orderData.put("useRoomTotalDesc", orderConfirmation.getUseRoomTotalDesc());
+            TradeOrderTotalVO summary = orderConfirmation.getSummary();
+            if (summary != null) {
+                orderData.put("roomModelDes", summary.getUseRoomTotalNum());
+            } else {
+                orderData.put("roomModelDes", 0);
+            }
+
+            orderData.put("totalMoney", totalMoney);
+            orderData.put("creatorName", orderConfirmation.getCreatorName());
+            orderData.put("auditorName", orderConfirmation.getAuditorName());
+            orderData.put("firstDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(orderConfirmation.getCreateTime().atZone(ZoneOffset.ofHours(8)).toInstant()), 7), "yyyy-MM-dd"));
+            orderData.put("lastDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), -21), "yyyy-MM-dd"));
+            orderData.put("today", DateUtil.format(new Date(), "yyyy-MM-dd"));
+
+            // 游客信息
+            List<Map<String, Object>> tradeVisitorData = new ArrayList<>();
+            List<TradeVisitorDO> tradeVisitorList = orderConfirmation.getTradeVisitorList();
+            for (int i = 0; i < tradeVisitorList.size(); i++) {
+                Map<String, Object> item = new HashMap<>();
+                TradeVisitorDO tradeVisitorDO = tradeVisitorList.get(i);
+                item.put("index", String.valueOf((i + 1)));
+                item.put("name", StringUtils.isEmpty(tradeVisitorDO.getName()) ? "" : tradeVisitorDO.getName());
+                item.put("nationality", StringUtils.isEmpty(tradeVisitorDO.getNationalityName()) ? "" : tradeVisitorDO.getNationalityName());
+                item.put("gender", (tradeVisitorDO.getGender() == null || tradeVisitorDO.getGender() == 0) ? "女" : "男");
+                item.put("dob", StringUtils.isEmpty(tradeVisitorDO.getBirthday()) ? "" : tradeVisitorDO.getBirthday());
+                item.put("credentialTypeName", DictFrameworkUtils.getDictDataLabel(DictTypeConstants.VISITOR_CREDENTIAL_TYPE, tradeVisitorDO.getCredentialType()));
+                item.put("idno", StringUtils.isEmpty(tradeVisitorDO.getCredentialNo()) ? "" : tradeVisitorDO.getCredentialNo());
+                tradeVisitorData.add(item);
+            }
+
+            // 填充单条数据
+            excelWriter.fill(orderData, writeSheet);
+            // 填充列表数据
+            excelWriter.fill(new FillWrapper("room", roomData), fillConfig, writeSheet);
+            excelWriter.fill(new FillWrapper("visitor", tradeVisitorData), fillConfig, writeSheet);
+            excelWriter.finish();
+            File file = new File(tmpFile);
+//            drawImage(file);
+            return file;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
         }
-        orderData.put("countryDes", orderConfirmation.getCountryDesc());
-        orderData.put("useRoomTotalDesc", orderConfirmation.getUseRoomTotalDesc());
-        TradeOrderTotalVO summary = orderConfirmation.getSummary();
-        if (summary != null) {
-            orderData.put("roomModelDes", summary.getUseRoomTotalNum());
-        } else {
-            orderData.put("roomModelDes", 0);
-        }
-
-        orderData.put("totalMoney", totalMoney);
-        orderData.put("creatorName", orderConfirmation.getCreatorName());
-        orderData.put("auditorName", orderConfirmation.getAuditorName());
-        orderData.put("firstDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(orderConfirmation.getCreateTime().atZone(ZoneOffset.ofHours(8)).toInstant()), 7), "yyyy-MM-dd"));
-        orderData.put("lastDate", DateUtil.format(org.apache.commons.lang3.time.DateUtils.addDays(Date.from(voyage.getStartTime().atZone(ZoneOffset.ofHours(8)).toInstant()), -21), "yyyy-MM-dd"));
-        orderData.put("today", DateUtil.format(new Date(), "yyyy-MM-dd"));
-
-        // 游客信息
-        List<Map<String, Object>> tradeVisitorData = new ArrayList<>();
-        List<TradeVisitorDO> tradeVisitorList = orderConfirmation.getTradeVisitorList();
-        for (int i = 0; i < tradeVisitorList.size(); i++) {
-            Map<String, Object> item = new HashMap<>();
-            TradeVisitorDO tradeVisitorDO = tradeVisitorList.get(i);
-            item.put("index", String.valueOf((i + 1)));
-            item.put("name", StringUtils.isEmpty(tradeVisitorDO.getName()) ? "" : tradeVisitorDO.getName());
-            item.put("nationality", StringUtils.isEmpty(tradeVisitorDO.getNationalityName()) ? "" : tradeVisitorDO.getNationalityName());
-            item.put("gender", (tradeVisitorDO.getGender() == null || tradeVisitorDO.getGender() == 0) ? "女" : "男");
-            item.put("dob", StringUtils.isEmpty(tradeVisitorDO.getBirthday()) ? "" : tradeVisitorDO.getBirthday());
-            item.put("credentialTypeName", DictFrameworkUtils.getDictDataLabel(DictTypeConstants.VISITOR_CREDENTIAL_TYPE, tradeVisitorDO.getCredentialType()));
-            item.put("idno", StringUtils.isEmpty(tradeVisitorDO.getCredentialNo()) ? "" : tradeVisitorDO.getCredentialNo());
-            tradeVisitorData.add(item);
-        }
-
-        // 填充单条数据
-        excelWriter.fill(orderData, writeSheet);
-        // 填充列表数据
-        excelWriter.fill(new FillWrapper("room", roomData), fillConfig, writeSheet);
-        excelWriter.fill(new FillWrapper("visitor", tradeVisitorData), fillConfig, writeSheet);
-        excelWriter.finish();
-        return new File(tmpFile);
+    }
+
+    public void drawImage(File excelFilePath) throws IOException, InvalidFormatException {
+        Workbook workbook = new XSSFWorkbook(excelFilePath);
+        Sheet sheet = workbook.getSheetAt(0);
+
+        InputStream logo = getClass().getClassLoader().getResourceAsStream("templates/logo.png");
+        byte[] bytes = IOUtils.toByteArray(logo);
+        // 读取图片文件到byte数组
+        int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
+        logo.close();
+
+        // 创建drawing patriarch和anchor对象
+        CreationHelper helper = workbook.getCreationHelper();
+        Drawing drawing = sheet.createDrawingPatriarch();
+        ClientAnchor anchor = helper.createClientAnchor();
+
+        int lastRowNum = sheet.getLastRowNum();
+        // 设置图片位置和大小(例如,放在A1单元格)
+        anchor.setCol1(5); // Column A
+        anchor.setRow1(lastRowNum); // Row 1
+
+        // 创建图片对象并设置到workbook中
+        Picture pict = drawing.createPicture(anchor, pictureIdx);
+        pict.resize(); // 根据anchor调整图片大小
+
+        // 关闭流并保存文件
+        FileOutputStream out = new FileOutputStream(excelFilePath);
+        workbook.write(out);
+        out.close();
+        workbook.close();
     }
 
     @Override

BIN
ship-module-trade/ship-module-trade-biz/src/main/resources/templates/confirmation_template.xlsx


BIN
ship-module-trade/ship-module-trade-biz/src/main/resources/templates/logo.png