Przeglądaj źródła

预览及下载soc模板

Zimo 6 godzin temu
rodzic
commit
8152ce2347

+ 80 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/qhse/soc/IotSocSummaryController.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.pms.controller.admin.qhse.soc;
 
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.net.URLEncodeUtil;
 import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
@@ -11,16 +13,26 @@ import cn.iocoder.yudao.module.pms.controller.admin.qhse.soc.vo.IotSocSummaryRes
 import cn.iocoder.yudao.module.pms.controller.admin.qhse.soc.vo.IotSocSummarySaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.qhse.soc.IotSocSummaryDO;
 import cn.iocoder.yudao.module.pms.service.qhse.soc.IotSocSummaryService;
+import cn.iocoder.yudao.module.pms.util.SafetyObservationCardGenerator;
+import com.google.common.collect.ImmutableList;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import liquibase.repackaged.org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import javax.annotation.security.PermitAll;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.List;
 
@@ -91,4 +103,72 @@ public class IotSocSummaryController {
                         BeanUtils.toBean(list, IotSocSummaryRespVO.class));
     }
 
+
+    // 1. 下载接口:前端直接调用,触发文件下载
+    @GetMapping("/safety-card/download/{id}")
+    @PermitAll
+    public ResponseEntity<ByteArrayResource> downloadSafetyCard(@PathVariable("id") Long id) throws Exception {
+        IotSocSummaryDO iotSocSummary = iotSocSummaryService.getIotSocSummary(id);
+        String person = iotSocSummary.getUserName();
+        String date = DateUtil.format(iotSocSummary.getObservationDate(), "yyyy-MM-dd HH:mm:ss");
+        String remark = iotSocSummary.getRemark();
+        // 1. 构建生成参数(实际业务中需从前端/数据库获取checkItems)
+        List<SafetyObservationCardGenerator.CheckItem> checkItems = buildCheckItems(); // 替换为实际业务逻辑
+
+        // 1. 生成文件字节流(你原有逻辑)
+        byte[] docBytes = SafetyObservationCardGenerator.generateCardToBytes(checkItems, person, date, remark);
+
+        // 2. 【关键修复】中文文件名必须 URL 编码!!!
+        String fileName = "行为安全观察与沟通卡" + StringUtils.substring(date, 0, 10) + person + ".docx";
+        String encodeFileName = URLEncodeUtil.encode(fileName); // Hutool编码
+
+        // 3. 正确设置响应头
+        HttpHeaders headers = new HttpHeaders();
+        headers.add(HttpHeaders.CONTENT_DISPOSITION,
+                "attachment; filename=\"" + encodeFileName + "\""); // 加引号更规范
+        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+
+        return ResponseEntity.ok()
+                .headers(headers)
+                .contentLength(docBytes.length)
+                .body(new ByteArrayResource(docBytes));
+    }
+
+
+    // 2. 预览接口:供KKFileView调用(核心:返回文件流,不触发下载)
+    @GetMapping("/safety-card/preview/{id}")
+    @PermitAll
+    public ResponseEntity<InputStreamResource> previewSafetyCard(@PathVariable("id") Long id) throws Exception {
+        IotSocSummaryDO iotSocSummary = iotSocSummaryService.getIotSocSummary(id);
+        String person = iotSocSummary.getUserName();
+        String date = DateUtil.format(iotSocSummary.getObservationDate(), "yyyy-MM-dd HH:mm:ss");
+        String remark = iotSocSummary.getRemark();
+        // 1. 构建生成参数
+        List<SafetyObservationCardGenerator.CheckItem> checkItems = buildCheckItems(); // 替换为实际业务逻辑
+
+        // 2. 动态生成文档字节数组
+        byte[] docBytes = SafetyObservationCardGenerator.generateCardToBytes(checkItems, person, date, remark);
+        ByteArrayInputStream bais = new ByteArrayInputStream(docBytes);
+        InputStreamResource resource = new InputStreamResource(bais);
+
+        // 3. 设置响应头(关键:不设置attachment,让KKFileView能读取流)
+        HttpHeaders headers = new HttpHeaders();
+        headers.add(HttpHeaders.CONTENT_TYPE, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+        // 可选:设置缓存(根据业务需求)
+        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
+
+        return ResponseEntity.ok()
+                .headers(headers)
+                .contentLength(docBytes.length)
+                .body(resource);
+    }
+
+    // 示例:构建检查项(实际业务中需从前端参数/数据库获取)
+    private List<SafetyObservationCardGenerator.CheckItem> buildCheckItems() {
+        return ImmutableList.of(
+                new SafetyObservationCardGenerator.CheckItem("个人防护", "头部", "Personal Protection Equipment", "Head"),
+                new SafetyObservationCardGenerator.CheckItem("规范操作", "其他", "Tools and Equipment", "Other"),
+                new SafetyObservationCardGenerator.CheckItem("作业场所", "地面滑(水/雨/雪/油污等)", "Housekeeping", "Slippery floor (Water / Rain / Snow / Oil etc.)")
+        );
+    }
 }

+ 18 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/util/SafetyObservationCardGenerator.java

@@ -7,6 +7,7 @@ import org.apache.poi.xwpf.usermodel.*;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
 import org.springframework.core.io.ClassPathResource;
 
+import java.io.ByteArrayOutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -14,7 +15,7 @@ import java.math.BigInteger;
 import java.util.List;
 
 public class SafetyObservationCardGenerator {
-    static class CheckItem {
+    public static class CheckItem {
         private String parent;          // 中文父项(如:个人防护)
         private String child;           // 中文子项(如:头部)
         private String englishParent;   // 英文父项(如:Personal Protection Equipment)
@@ -383,6 +384,22 @@ public class SafetyObservationCardGenerator {
         return text;
     }
 
+    public static byte[] generateCardToBytes(List<CheckItem> checkItems, String person, String date, String remark) throws Exception {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (XWPFDocument document = new XWPFDocument()) {
+            // 复用原有生成逻辑
+            generateChineseTable(document, checkItems, person, date, remark);
+            document.createParagraph();
+            generateEnglishTable(document, checkItems, person, date, remark);
+            // 写入字节流
+            document.write(bos);
+            return bos.toByteArray();
+        } finally {
+            bos.close();
+        }
+    }
+
+
     // 测试方法 - 新增person、date、remark参数示例
     public static void main(String[] args) {
         // 示例:勾选 个人防护-头部(对应英文Head)、规范操作-其他(对应英文Other)、作业场所-地面滑(对应英文Slippery floor)