diff --git a/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/RemoteFileService.java b/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/RemoteFileService.java index 237f7ee..b5d4dd2 100644 --- a/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/RemoteFileService.java +++ b/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/RemoteFileService.java @@ -47,6 +47,15 @@ public interface RemoteFileService @PostMapping(value = "/uploadMinio1", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R uploadMinio1(@RequestPart(value = "file") MultipartFile file,@RequestPart(value = "fileName") String fileName); + /** + * 上传文件 + * + * @param file 文件信息 + * @return 结果 + */ + @PostMapping(value = "/uploadMinioPDF", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R uploadMinioPDF(@RequestPart(value = "file") MultipartFile file,@RequestPart(value = "fileName") String fileName); + /** * 上传文件 * @@ -59,5 +68,4 @@ public interface RemoteFileService @PostMapping(value = "/uploadMinioCar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R uploadMinioCar(@RequestPart(value = "file") MultipartFile file); - } diff --git a/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/factory/RemoteFileFallbackFactory.java b/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/factory/RemoteFileFallbackFactory.java index 343bf51..47bd659 100644 --- a/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/factory/RemoteFileFallbackFactory.java +++ b/dcsoft-api/dcsoft-api-system/src/main/java/com/dcsoft/system/api/factory/RemoteFileFallbackFactory.java @@ -42,6 +42,11 @@ public class RemoteFileFallbackFactory implements FallbackFactory uploadMinioPDF(MultipartFile file, String fileName) { + return null; + } + @Override public R uploadMinios(MultipartFile file,String fileName) { diff --git a/dcsoft-modules/dcsoft-file/src/main/java/com/dcsoft/file/controller/SysFileController.java b/dcsoft-modules/dcsoft-file/src/main/java/com/dcsoft/file/controller/SysFileController.java index 27a632a..fc82563 100644 --- a/dcsoft-modules/dcsoft-file/src/main/java/com/dcsoft/file/controller/SysFileController.java +++ b/dcsoft-modules/dcsoft-file/src/main/java/com/dcsoft/file/controller/SysFileController.java @@ -65,6 +65,9 @@ public class SysFileController @Value("${minio.bucket-name1}") private String bucketName1; + @Value("${minio.bucket-name3}") + private String bucketName3; + @Autowired private IAlgoService algoService; @@ -158,6 +161,27 @@ public class SysFileController } + /** + * 文件上传请求 + */ + @PostMapping("uploadMinioPDF") + public R uploadMinioPDF(MultipartFile file, String fileName) { + + try { + // 上传并返回访问地址 + String fileNames = FileUploadUtils.uploadMinio(file, bucketName3, fileName); + SysFile sysFile = new SysFile(); + sysFile.setName(FileUtils.getName(fileNames)); + fileNames = fileNames.replace(miniourl, miniogwurl); + sysFile.setUrl(fileNames); + return R.ok(sysFile); + } catch (Exception e) { + log.error("上传文件失败", e); + return R.fail(e.getMessage()); + } + } + + /** * 文件上传请求 diff --git a/dcsoft-modules/dcsoft-system/pom.xml b/dcsoft-modules/dcsoft-system/pom.xml index 6e096aa..6e62c9d 100644 --- a/dcsoft-modules/dcsoft-system/pom.xml +++ b/dcsoft-modules/dcsoft-system/pom.xml @@ -122,6 +122,25 @@ 5.3.3 + + com.itextpdf + itextpdf + 5.5.10 + + + com.itextpdf + itext-asian + 5.2.0 + + + org.springframework.boot + spring-boot-starter-web + + + javax.servlet + javax.servlet-api + 4.0.1 + diff --git a/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/utils/ByteArrayMultipartFile.java b/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/utils/ByteArrayMultipartFile.java new file mode 100644 index 0000000..08c45b5 --- /dev/null +++ b/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/utils/ByteArrayMultipartFile.java @@ -0,0 +1,56 @@ +package com.dcsoft.system.utils; + +import org.springframework.web.multipart.MultipartFile; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ByteArrayMultipartFile implements MultipartFile { + private final byte[] content; + private final String filename; + + public ByteArrayMultipartFile(byte[] content, String filename) { + this.content = content; + this.filename = filename; + } + + @Override + public String getName() { + return filename; + } + + @Override + public String getOriginalFilename() { + return filename; + } + + @Override + public String getContentType() { + return "application/pdf"; + } + + @Override + public boolean isEmpty() { + return content == null || content.length == 0; + } + + @Override + public long getSize() { + return content.length; + } + + @Override + public byte[] getBytes() throws IOException { + return content; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(content); + } + + @Override + public void transferTo(java.io.File dest) throws IOException, IllegalStateException { + throw new UnsupportedOperationException("Not implemented"); + } +} \ No newline at end of file diff --git a/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/utils/PdfHeaderFooterEvent.java b/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/utils/PdfHeaderFooterEvent.java new file mode 100644 index 0000000..d44ace2 --- /dev/null +++ b/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/utils/PdfHeaderFooterEvent.java @@ -0,0 +1,44 @@ +package com.dcsoft.system.utils; + +import com.itextpdf.text.pdf.PdfPageEventHelper; +import com.itextpdf.text.*; +import com.itextpdf.text.pdf.*; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class PdfHeaderFooterEvent extends PdfPageEventHelper { + + + /** + * 重写页面结束时间 分别添加页眉、页脚 + */ + @Override + public void onEndPage(PdfWriter writer, Document docment){ + try{ + this.addPageFooter(writer, docment); + }catch(Exception e){ + log.error("添加页脚出错", e); + } + } + + /* + /** + * 页脚 + */ + private void addPageFooter(PdfWriter writer, Document docment){ + try { + //创建字体 + BaseFont fs = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); + Font font = new Font(fs, 10); + Phrase pageNumberPh = new Phrase("- " + writer.getPageNumber() + " -",font); + float center = writer.getPageSize().getRight()/2; + float bottom = writer.getPageSize().getBottom() + 10; + ColumnText.showTextAligned(writer.getDirectContent(),Element.ALIGN_CENTER,pageNumberPh,center,bottom,0); + }catch (Exception e) { + throw new RuntimeException(e); + } + + } + +} diff --git a/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/visitor/controller/VisCarryStuffController.java b/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/visitor/controller/VisCarryStuffController.java index 38a263a..d74a680 100644 --- a/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/visitor/controller/VisCarryStuffController.java +++ b/dcsoft-modules/dcsoft-system/src/main/java/com/dcsoft/system/visitor/controller/VisCarryStuffController.java @@ -1,10 +1,13 @@ package com.dcsoft.system.visitor.controller; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.dcsoft.common.core.constant.CacheConstants; import com.dcsoft.common.core.constant.Constants; +import com.dcsoft.common.core.domain.R; import com.dcsoft.common.core.enums.ExamineEnum; import com.dcsoft.common.core.exception.ServiceException; import com.dcsoft.common.core.utils.CollUtil; @@ -18,31 +21,47 @@ import com.dcsoft.common.log.enums.BusinessType; import com.dcsoft.common.redis.service.RedisService; import com.dcsoft.common.security.annotation.RequiresPermissions; import com.dcsoft.common.sms.config.properties.SmsProperties; +import com.dcsoft.system.api.RemoteFileService; +import com.dcsoft.system.api.domain.SysFile; import com.dcsoft.system.api.domain.SysUser; import com.dcsoft.system.domain.SysPeople; import com.dcsoft.system.domain.vo.IdNamelVo; import com.dcsoft.system.service.ISysDictDataService; import com.dcsoft.system.service.ISysPeopleService; import com.dcsoft.system.service.impl.SysUserServiceImpl; +import com.dcsoft.system.utils.ByteArrayMultipartFile; +import com.dcsoft.system.utils.PdfHeaderFooterEvent; import com.dcsoft.system.utils.UuidUtil; import com.dcsoft.system.visitor.domain.*; import com.dcsoft.system.visitor.service.IVisCarryStuffService; import com.dcsoft.system.visitor.service.IVisVisitorExamineService; import com.dcsoft.system.visitor.service.IVisitorService; +import com.itextpdf.text.*; +import com.itextpdf.text.pdf.BaseFont; +import com.itextpdf.text.pdf.PdfPCell; +import com.itextpdf.text.pdf.PdfPTable; +import com.itextpdf.text.pdf.PdfWriter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; import java.util.*; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import com.itextpdf.text.Image; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfGState; +import com.itextpdf.text.pdf.PdfPageEventHelper; +import com.itextpdf.text.pdf.PdfWriter; @Slf4j @RestController @@ -82,6 +101,9 @@ public class VisCarryStuffController extends BaseController { @Value("${sms.parkName:'兴安智慧园区'}") private String parkName; + @Autowired + private RemoteFileService remoteFileService; + @GetMapping("/list") public TableDataInfo list(VisExitOutVo vo) { @@ -339,7 +361,11 @@ public class VisCarryStuffController extends BaseController { // 申请人发送短信(审核通过) SysUser sysUser = sysUserServiceImpl.selectUserById(stuffVo.getUserId()); - visitorController.sendMessage(sysUser.getPhonenumber(), "1", parkName, smsProperties.getTemplate2()); + try { + visitorController.sendMessage(sysUser.getPhonenumber(), "1", parkName, smsProperties.getTemplate2()); + } catch (Exception e) { + log.error("短信发送异常:", e); + } } } @@ -369,7 +395,11 @@ public class VisCarryStuffController extends BaseController { // 申请人发送短信(审核不通过) SysUser sysUser = sysUserServiceImpl.selectUserById(stuffVo.getUserId()); - visitorController.sendMessage(sysUser.getPhonenumber(), "1", parkName, smsProperties.getTemplate3()); + try { + visitorController.sendMessage(sysUser.getPhonenumber(), "1", parkName, smsProperties.getTemplate3()); + } catch (Exception e) { + log.error("短信发送异常:", e); + } } visCarryStuffService.updateStaff(vo); @@ -453,4 +483,187 @@ public class VisCarryStuffController extends BaseController { return toAjax(true); } + + /** + * 根据ID查询出门记录并生成PDF + */ + @GetMapping("/exportPdf/{id}") + public AjaxResult exportPdf(@PathVariable("id") Long id) { + try { + //查询主数据 + VisExitOutVo visExitOutVo = visCarryStuffService.selectVisExitOutById(id); + //查询物品信息列表 + VisStuffInfoVo visStuffInfoVo = new VisStuffInfoVo(); + visStuffInfoVo.setExitId(id); + List stuffList = visCarryStuffService.selectStuffList(visStuffInfoVo); + if (CollUtil.isNotEmpty(stuffList)) { + //处理字典 + Map map = dictDataService.queryDictData("vis_out_stuff_type"); + stuffList.forEach(stuff -> { + if (StrUtil.isNotBlank(stuff.getType())) { + stuff.setTypeName(map.get(stuff.getType())); + } + }); + } + + // 创建PDF文档 + Document document = new Document(new RectangleReadOnly(842F, 595F)); + document.setMargins(60, 60, 72, 72); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter writer = PdfWriter.getInstance(document, baos); + + // 添加水印事件处理器 + writer.setPageEvent(new PdfWatermark()); + + document.open(); + + // 设置中文字体 + BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); + Font contentFont = new Font(bfChinese, 10, Font.NORMAL); + Font titleFont = new Font(bfChinese, 14, Font.BOLD); + + // 上半部分:表单样式 + Paragraph title = new Paragraph("出门证详情", titleFont); + title.setAlignment(Element.ALIGN_CENTER); + document.add(title); + document.add(new Paragraph("\n")); + + // 创建表单表格(4列,每行两个字段) + PdfPTable formTable = new PdfPTable(4); + formTable.setWidthPercentage(90); + formTable.setSpacingBefore(10f); + formTable.setHorizontalAlignment(Element.ALIGN_CENTER); + + // 添加表单内容(每行两个字段) + addFormRow(formTable, "出门证编号:", visExitOutVo.getExitPermitNo(), contentFont); + addFormRow(formTable, "申请人姓名:", visExitOutVo.getName(), contentFont); + addFormRow(formTable, "申请单位:", visExitOutVo.getVisitingUnit(), contentFont); + addFormRow(formTable, "申请日期:", DateUtil.format(visExitOutVo.getVisTime(), DatePattern.NORM_DATE_PATTERN), contentFont); + addFormRow(formTable, "事由:", visExitOutVo.getReason(), contentFont); + + document.add(formTable); + document.add(new Paragraph("\n\n")); + + // 下半部分:表格数据 + Paragraph tableTitle = new Paragraph("物资信息", titleFont); + tableTitle.setAlignment(Element.ALIGN_CENTER); + document.add(tableTitle); + document.add(new Paragraph("\n")); + + // 创建数据表格 + float[] widths = {15f, 15f, 15f, 15f, 15f, 15f, 15f, 15f}; + PdfPTable dataTable = new PdfPTable(widths); + dataTable.setWidthPercentage(100); + dataTable.setSpacingBefore(10f); + + // 添加表头 + addTableHeader(dataTable, contentFont); + + // 添加表格数据 + if(CollUtil.isNotEmpty(stuffList)){ + for (VisStuffInfoVo vo : stuffList) { + addTableRow(dataTable, vo, contentFont); + } + } + + document.add(dataTable); + document.close(); + + // 转换为MultipartFile并上传 + String fileName = "exit_record_" + id + ".pdf"; + MultipartFile multipartFile = new ByteArrayMultipartFile(baos.toByteArray(), fileName); + R uploadResult = remoteFileService.uploadMinioPDF(multipartFile, fileName); + + return success(uploadResult.getData()); + } catch (Exception e) { + log.error("生成PDF异常:", e); + throw new ServiceException("生成PDF失败"); + } + } + + // 添加表单行(两个字段) + private void addFormRow(PdfPTable table, String label1, String value1, Font font) { + // 第一个字段标签 + PdfPCell labelCell1 = new PdfPCell(new Paragraph(label1, font)); + labelCell1.setBorder(Rectangle.NO_BORDER); + labelCell1.setHorizontalAlignment(Element.ALIGN_RIGHT); + labelCell1.setVerticalAlignment(Element.ALIGN_MIDDLE); + labelCell1.setPaddingRight(5); + table.addCell(labelCell1); + + // 第一个字段值 + PdfPCell valueCell1 = new PdfPCell(new Paragraph(value1 != null ? value1 : "", font)); + valueCell1.setBorder(Rectangle.NO_BORDER); + valueCell1.setHorizontalAlignment(Element.ALIGN_LEFT); + table.addCell(valueCell1); + } + + // 添加表格表头 + private void addTableHeader(PdfPTable table, Font font) { + String[] headers = {"物品名称", "规格型号", "物品类型", "数量", "用途", "是否返厂", "返厂时间", "返厂数量"}; + for (String header : headers) { + PdfPCell cell = new PdfPCell(new Paragraph(header, font)); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setVerticalAlignment(Element.ALIGN_MIDDLE); + cell.setFixedHeight(25); + table.addCell(cell); + } + } + + // 添加表格行数据 + private void addTableRow(PdfPTable table, VisStuffInfoVo vo, Font font) { + String backTime = vo.getBackTime() != null ? + DateUtil.format(vo.getBackTime(), DatePattern.NORM_DATE_PATTERN) : ""; + String isBack = vo.getIsBack() == 1 ? "是" : "否"; + + table.addCell(createCell(vo.getName(), font)); + table.addCell(createCell(vo.getModel(), font)); + table.addCell(createCell(vo.getTypeName(), font)); + table.addCell(createCell(vo.getNumber() == null ? "" : String.valueOf(vo.getNumber()), font)); + table.addCell(createCell(vo.getPurpose(), font)); + table.addCell(createCell(isBack, font)); + table.addCell(createCell(backTime, font)); + table.addCell(createCell(vo.getBackNumber() == null ? "" : String.valueOf(vo.getBackNumber()), font)); + } + + // 创建表格单元格 + private PdfPCell createCell(String text, Font font) { + PdfPCell cell = new PdfPCell(new Paragraph(text != null ? text : "", font)); + cell.setHorizontalAlignment(Element.ALIGN_CENTER); + cell.setVerticalAlignment(Element.ALIGN_MIDDLE); + cell.setFixedHeight(20); + return cell; + } + + // 水印处理类 + private static class PdfWatermark extends PdfPageEventHelper { + @Override + public void onEndPage(PdfWriter writer, Document document) { + try { + // 加载公章图片 + Image seal = Image.getInstance("http://81.68.71.142:9000/others/gz/111.png"); + + // 设置水印位置(右下角) + float x = document.right() - seal.getScaledWidth() - 50; + float y = document.bottom() + 50; + + // 设置透明度 + PdfContentByte canvas = writer.getDirectContentUnder(); + seal.setAbsolutePosition(x, y); + seal.scaleAbsolute(100, 100); // 调整大小 + canvas.saveState(); + PdfGState gs = new PdfGState(); + gs.setFillOpacity(0.5f); // 设置透明度 + canvas.setGState(gs); + canvas.addImage(seal); + canvas.restoreState(); + } catch (Exception e) { + log.error("添加水印异常:", e); + } + } + } + } + +