admin/config/test/application-custom.yml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
admin/src/main/resources/simhei.ttf | 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/pom.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/src/main/java/com/ruoyi/cwgl/controller/DispatchOrderController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/src/main/java/com/ruoyi/cwgl/service/IDispatchOrderService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/src/main/java/com/ruoyi/cwgl/service/impl/DispatchOrderServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/src/main/java/com/ruoyi/cwgl/utils/MultiPagePdfWithImageUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/src/main/java/com/ruoyi/cwgl/utils/simhei.ttf | 补丁 | 查看 | 原始文档 | blame | 历史 | |
service/src/main/resources/simhei.ttf | 补丁 | 查看 | 原始文档 | blame | 历史 | |
ui/admin-ui3/src/api/cwgl/dispatchOrder.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
ui/admin-ui3/src/views/cwgl/dispatchOrder/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
admin/config/test/application-custom.yml
@@ -55,11 +55,11 @@ log-slow-sql: true # 慢SQL记录 #redis 相关配置 redis: host: 127.0.0.1 #访问地址 port: 6379 #端口 password: 123456 #密码 host: 61.143.42.70 #访问地址 port: 7007 #端口 password: rd@123 #密码 timeout: 10s #超时时间 keyprefix: cwgl_test #存储key前缀,避免多套环境key相同 keyprefix: cwgl:test #存储key前缀,避免多套环境key相同 #swagger相关配置 swagger: enabled: true #是否开启 admin/src/main/resources/simhei.ttfBinary files differ
service/pom.xml
@@ -25,7 +25,11 @@ <artifactId>common</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13.3</version> </dependency> <!--持久化层模块--> <dependency> service/src/main/java/com/ruoyi/cwgl/controller/DispatchOrderController.java
@@ -2,8 +2,12 @@ import java.util.List; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.cwgl.domain.vo.DispatchOrderAttachmentVo; import com.ruoyi.cwgl.domain.vo.DispatchOrderItemVo; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; @@ -23,6 +27,8 @@ import com.ruoyi.cwgl.service.IDispatchOrderService; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.core.page.TableDataInfo; import javax.servlet.http.HttpServletResponse; /** * 调度单Controller @@ -73,6 +79,15 @@ return getDataTable(list); } @PreAuthorize("@ss.hasPermi('cwgl:dispatchOrder:attachment')") @GetMapping("/downAttachment") public void downAttachment(String no, HttpServletResponse response) throws Exception { String filePath = dispatchOrderService.downAttachment(no); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); FileUtils.setAttachmentResponseHeader(response, FileUtils.getName(filePath)); FileUtils.writeBytes(filePath, response.getOutputStream()); } /** * 导出调度单列表 * @param dispatchOrder 查询条件对象 @@ -100,6 +115,7 @@ /** * 获取调度单详细信息 */ service/src/main/java/com/ruoyi/cwgl/service/IDispatchOrderService.java
@@ -1,5 +1,6 @@ package com.ruoyi.cwgl.service; import java.io.FileNotFoundException; import java.util.List; import com.ruoyi.cwgl.domain.DispatchOrder; import com.baomidou.mybatisplus.extension.service.IService; @@ -118,4 +119,6 @@ * @return */ List<DispatchOrderAttachmentVo> selectDispatchOrderAttachment(String no); String downAttachment(String no) throws Exception; } service/src/main/java/com/ruoyi/cwgl/service/impl/DispatchOrderServiceImpl.java
@@ -1,6 +1,10 @@ package com.ruoyi.cwgl.service.impl; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.math.BigDecimal; @@ -12,7 +16,13 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.PageUtil; import com.github.pagehelper.Page; import com.itextpdf.text.Document; import com.itextpdf.text.Font; import com.itextpdf.text.PageSize; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfWriter; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.DateUtils; import javax.annotation.Resource; @@ -23,6 +33,7 @@ import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.cwgl.domain.vo.DispatchOrderVo; import com.ruoyi.cwgl.enums.FeeTypeEnums; import com.ruoyi.cwgl.utils.MultiPagePdfWithImageUtils; import org.springframework.beans.factory.annotation.Autowired; import com.ruoyi.cwgl.domain.DispatchOrderItem; @@ -476,4 +487,15 @@ public List<DispatchOrderAttachmentVo> selectDispatchOrderAttachment(String no) { return dispatchOrderMapper.selectDispatchOrderAttachment(no); } @DataSource(DataSourceType.CWSJ) @Override public String downAttachment(String no) throws Exception { List<DispatchOrderAttachmentVo> dispatchOrderAttachmentVos = selectDispatchOrderAttachment(no); return MultiPagePdfWithImageUtils.createPdf(dispatchOrderAttachmentVos, no); } } service/src/main/java/com/ruoyi/cwgl/utils/MultiPagePdfWithImageUtils.java
New file @@ -0,0 +1,186 @@ package com.ruoyi.cwgl.utils; import com.itextpdf.text.*; import com.itextpdf.text.pdf.*; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.cwgl.domain.vo.DispatchOrderAttachmentVo; import java.io.FileOutputStream; import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.UUID; public class MultiPagePdfWithImageUtils { public static String createPdf(List<DispatchOrderAttachmentVo> dispatchOrderAttachmentVos, String no) throws Exception { String fileName = no+ "_凭证_"+ UUID.randomUUID() +".pdf"; String path = RuoYiConfig.getDownloadPath() + fileName; Document document = new Document(PageSize.A4, 36, 36, 36, 36); PdfWriter writer = PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(path))); document.open(); BaseFont baseFont = BaseFont.createFont("simhei.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); Font font = new Font(baseFont, 11, Font.NORMAL); int totalPages = dispatchOrderAttachmentVos.size(); for (int i = 0; i < totalPages; i++) { if (i > 0) document.newPage(); DispatchOrderAttachmentVo dispatchOrderAttachmentVo = dispatchOrderAttachmentVos.get(i); String currency = Optional.ofNullable(dispatchOrderAttachmentVo.getCurrency()).orElse("人民币"); String currentStr; if ("人民币".equals(currency)){ currentStr = "总金额:港币 0;人民币:"+dispatchOrderAttachmentVo.getAccount()+";"; }else{ currentStr = "总金额:港币 "+dispatchOrderAttachmentVo.getAccount()+";人民币:0;"; } PdfPTable wrapperTable = new PdfPTable(1); wrapperTable.setWidthPercentage(100); wrapperTable.setKeepTogether(true); // ▶ 页眉表格 PdfPTable headerTable = new PdfPTable(2); headerTable.setWidthPercentage(100); headerTable.setWidths(new int[]{3, 2}); headerTable.addCell(createCell("调度单号:"+no, font)); headerTable.addCell(createCell(currentStr, font)); PdfPCell headerCell = new PdfPCell(headerTable); headerCell.setBorder(Rectangle.BOX); wrapperTable.addCell(headerCell); // ▶ 图片 Image image = Image.getInstance(new URL(dispatchOrderAttachmentVo.getImageUrl())); // 限制图片最大尺寸 float maxImgWidth = 500f; float maxImgHeight = 700f; image.scaleToFit(maxImgWidth, maxImgHeight); image.setAlignment(Image.ALIGN_CENTER); // 创建图片单元格并设置固定高度(确保整体表格不分页) PdfPCell imageCell = new PdfPCell(); imageCell.setPadding(10); imageCell.setBorder(Rectangle.BOX); imageCell.setFixedHeight(maxImgHeight + 20); // 加一点 padding 空间 imageCell.setHorizontalAlignment(Element.ALIGN_CENTER); imageCell.setVerticalAlignment(Element.ALIGN_MIDDLE); imageCell.addElement(image); wrapperTable.addCell(imageCell); // ▶ 页脚表格 PdfPTable footerTable = new PdfPTable(4); footerTable.setWidthPercentage(100); footerTable.setWidths(new int[]{3, 2, 2, 3}); footerTable.addCell(createCell("费用类:"+dispatchOrderAttachmentVo.getFeeItem(), font)); footerTable.addCell(createCell("金额:"+dispatchOrderAttachmentVo.getAccount(), font)); footerTable.addCell(createCell("币制:"+dispatchOrderAttachmentVo.getCurrency(), font)); footerTable.addCell(createCell("第 " + (i + 1) + " 页 / 共 " + totalPages + " 页", font)); PdfPCell footerCell = new PdfPCell(footerTable); footerCell.setBorder(Rectangle.BOX); wrapperTable.addCell(footerCell); // 添加总表格 document.add(wrapperTable); } document.close(); writer.close(); System.out.println("PDF 生成成功!"); return path; } public static void main(String[] args) throws Exception { Document document = new Document(PageSize.A4, 36, 36, 36, 36); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("bordered_receipt.pdf")); document.open(); BaseFont baseFont = BaseFont.createFont("simhei.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); Font font = new Font(baseFont, 11, Font.NORMAL); List<String> imageUrls = Arrays.asList( "https://xiongbenda-shengzheng.oss-cn-shenzhen.aliyuncs.com/cz/ImageViewServlet%20%281%29.gif", "https://xiongbenda-shengzheng.oss-cn-shenzhen.aliyuncs.com/cz/ImageViewServlet.gif" ); int totalPages = imageUrls.size(); for (int i = 0; i < totalPages; i++) { if (i > 0) document.newPage(); // ▶ 构造一个总表格(3行,1列),包住所有内容,控制边框与分页 PdfPTable wrapperTable = new PdfPTable(1); wrapperTable.setWidthPercentage(100); wrapperTable.setKeepTogether(true); // ▶ 页眉表格 PdfPTable headerTable = new PdfPTable(2); headerTable.setWidthPercentage(100); headerTable.setWidths(new int[]{3, 2}); headerTable.addCell(createCell("调度单号:LD2507260028", font)); headerTable.addCell(createCell("总金额:港币 280;人民币:0", font)); PdfPCell headerCell = new PdfPCell(headerTable); headerCell.setBorder(Rectangle.BOX); wrapperTable.addCell(headerCell); // ▶ 图片 Image image = Image.getInstance(new URL(imageUrls.get(i))); // 限制图片最大尺寸 float maxImgWidth = 500f; float maxImgHeight = 700f; image.scaleToFit(maxImgWidth, maxImgHeight); image.setAlignment(Image.ALIGN_CENTER); // 创建图片单元格并设置固定高度(确保整体表格不分页) PdfPCell imageCell = new PdfPCell(); imageCell.setPadding(10); imageCell.setBorder(Rectangle.BOX); imageCell.setFixedHeight(maxImgHeight + 20); // 加一点 padding 空间 imageCell.setHorizontalAlignment(Element.ALIGN_CENTER); imageCell.setVerticalAlignment(Element.ALIGN_MIDDLE); imageCell.addElement(image); wrapperTable.addCell(imageCell); // ▶ 页脚表格 PdfPTable footerTable = new PdfPTable(4); footerTable.setWidthPercentage(100); footerTable.setWidths(new int[]{3, 2, 2, 3}); footerTable.addCell(createCell("费用类:登记费 HKD", font)); footerTable.addCell(createCell("金额:250.00", font)); footerTable.addCell(createCell("币制:港币", font)); footerTable.addCell(createCell("第 " + (i + 1) + " 页 / 共 " + totalPages + " 页", font)); PdfPCell footerCell = new PdfPCell(footerTable); footerCell.setBorder(Rectangle.BOX); wrapperTable.addCell(footerCell); // 添加总表格 document.add(wrapperTable); } document.close(); writer.close(); System.out.println("PDF 生成成功!"); } // 默认左对齐、含内边距、含边框 private static PdfPCell createCell(String text, Font font) { PdfPCell cell = new PdfPCell(new Phrase(text, font)); cell.setPadding(6); cell.setHorizontalAlignment(Element.ALIGN_LEFT); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); return cell; } } service/src/main/java/com/ruoyi/cwgl/utils/simhei.ttfBinary files differ
service/src/main/resources/simhei.ttfBinary files differ
ui/admin-ui3/src/api/cwgl/dispatchOrder.ts
@@ -70,7 +70,14 @@ download('/cwgl/dispatchOrder/export2',query); }) } export const downloadFJ:requestType = (query) => { return request({ url: '/cwgl/dispatchOrder/downAttachment', method:'get', params:query, responseType: 'blob' }) } /** * 查询查看费用 */ ui/admin-ui3/src/views/cwgl/dispatchOrder/index.vue
@@ -39,6 +39,11 @@ class="attachment-image" /> </template> </avue-crud> <template #footer> <div class="dialog-footer"> <el-button type="primary" v-if="itemTableData2.length>0" @click="downPZ">下载凭证</el-button> </div> </template> </el-dialog> </basicContainer> @@ -52,13 +57,15 @@ exportDispatchOrder, getDispatchOrder, listDispatchOrder, updateDispatchOrder, cwglDispatchOrderItem, cwglDispatchOrderattAchment, exportDispatchOrder2 updateDispatchOrder, cwglDispatchOrderItem, cwglDispatchOrderattAchment, exportDispatchOrder2, downloadFJ } from "@/api/cwgl/dispatchOrder"; import useCurrentInstance from "@/utils/useCurrentInstance"; import { computed, reactive, ref, toRefs } from "vue"; import { PagesInterface, PageQueryInterface } from "@/utils/globalInterface"; import { usePagePlus } from "@/hooks/usePagePlus"; import { hasPermission } from "@/utils/permissionUtils"; import {blobValidate} from "@/utils/ruoyi"; import {saveAs} from "file-saver"; const { proxy } = useCurrentInstance(); const crudRef = ref(); @@ -378,6 +385,18 @@ queryParams.value = proxy.addDateRangeNew(queryParams.value, queryParams.value?.actualArrivalTimeRange, 'actualArrivalTime') || {}; exportDispatchOrder2(queryParams.value); } const downPZ =()=>{ downloadFJ({no:pageAttachment.value.no}).then(res=>{ console.log(res) const blob = new Blob([res]) console.log(blob) saveAs(blob, decodeURI(pageAttachment.value.no+"凭证.pdf")) }) } </script> <style lang="scss" scoped> .avue-dialog .el-dialog__body {