From d8e7adfe9ab5c502c852e8fa89421f738d184210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=8C=E5=85=88=E8=88=9C?= <2499071264@qq.com> Date: Fri, 30 Oct 2026 09:34:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=81=8C=E5=B7=A5=E6=85=B0=E9=97=AE=20?= =?UTF-8?q?=E6=95=B4=E6=94=B9=20=E8=A1=A5=E5=85=85=E6=97=A5=E5=BF=97?= =?UTF-8?q?=EF=BC=8C=E6=8E=92=E6=9F=A5=E8=81=8C=E5=B7=A5=E6=85=B0=E9=97=AE?= =?UTF-8?q?=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/base/utils/SysOfficeTemplateUtil.java | 19 +++++----- .../controller/CondolenceMineController.java | 36 +++++++++++++++---- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/budwk/app/base/utils/SysOfficeTemplateUtil.java b/src/main/java/com/budwk/app/base/utils/SysOfficeTemplateUtil.java index d458145..165f672 100644 --- a/src/main/java/com/budwk/app/base/utils/SysOfficeTemplateUtil.java +++ b/src/main/java/com/budwk/app/base/utils/SysOfficeTemplateUtil.java @@ -77,13 +77,7 @@ public class SysOfficeTemplateUtil { public PictureRenderData createPictureRenderData(int width, int height, String url) { try { byte[] bytes = getFileBytesByUrl(url); -// if (StrUtil.isBlank(url)) { -// return null; -// } -// int startIndex = url.indexOf("id=") + "id=".length(); -// String id = url.substring(startIndex); -// Sys_file sysFile = dao.fetch(Sys_file.class, id); -// byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath()); + log.info("[Office图片读取] 创建图片渲染数据,referenceLength={}, byteCount={}, width={}, height={}", StrUtil.nullToEmpty(url).length(), bytes == null ? null : bytes.length, width, height); ByteArrayPictureRenderData pictureRenderData = new ByteArrayPictureRenderData(bytes, PictureType.PNG); PictureStyle pictureStyle = new PictureStyle(); pictureStyle.setWidth(width); @@ -91,7 +85,7 @@ public class SysOfficeTemplateUtil { pictureRenderData.setPictureStyle(pictureStyle); return pictureRenderData; } catch (Exception e) { - log.error("文件转换PictureRenderData错误,文件路径:{},{}", url, e.getMessage()); + log.error("[Office图片读取] 创建图片渲染数据失败,referenceLength={}", StrUtil.nullToEmpty(url).length(), e); return null; } } @@ -140,13 +134,20 @@ public class SysOfficeTemplateUtil { public byte[] getFileBytesByUrl(String url) { try { if (StrUtil.isBlank(url)) { + log.warn("[Office图片读取] 图片引用为空"); return null; } int startIndex = url.indexOf("id=") + "id=".length(); String id = url.substring(startIndex); + String logFileId = url.contains("id=") ? id : "未识别id参数"; + log.info("[Office图片读取] 解析文件引用,fileId={}, hasIdParameter={}", logFileId, url.contains("id=")); Sys_file sysFile = dao.fetch(Sys_file.class, id); - return SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath()); + log.info("[Office图片读取] 查询文件记录,fileId={}, found={}, bucket={}, storagePathPresent={}", logFileId, sysFile != null, sysFile == null ? null : sysFile.getBucket(), sysFile != null && StrUtil.isNotBlank(sysFile.getStoragePath())); + byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath()); + log.info("[Office图片读取] 读取存储文件完成,fileId={}, byteCount={}", logFileId, bytes == null ? null : bytes.length); + return bytes; } catch (Exception e) { + log.error("[Office图片读取] 读取图片失败,referenceLength={}", StrUtil.nullToEmpty(url).length(), e); return null; } } diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java index 224e981..2c7369a 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/condolence/controller/CondolenceMineController.java @@ -32,6 +32,7 @@ import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.data.PictureRenderData; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; import org.nutz.aop.interceptor.ioc.TransAop; import org.nutz.dao.Cnd; import org.nutz.dao.Sqls; @@ -59,6 +60,7 @@ import java.util.List; * @Version 1.0 * @Description TODO */ +@Slf4j @IocBean @At("/platform/condolence/mine") @Api("职工慰问我的") @@ -157,6 +159,7 @@ public class CondolenceMineController { @ApiOperation("导出职工慰问申请表") @SaCheckPermission("condolence.mine") public void doExportApply(String id, HttpServletResponse response, Boolean print) throws Exception { + log.info("[职工慰问导出] 开始,applyId={}, userId={}, format={}", id, SecurityUtil.getUserId(), Boolean.TRUE.equals(print) ? "PDF" : "Word"); Condolence condolence = condolenceService.fetch(id); if (condolence == null) throw new BaseException("该条记录不存在"); if (!SecurityUtil.getUserId().equals(condolence.getCreatedBy())) { @@ -167,17 +170,22 @@ public class CondolenceMineController { if (instance == null || !ProcessInstanceStateEnum.FINISHED.getCode().equals(instance.getState())) { throw new BaseException("只能导出已完成的申请"); } + log.info("[职工慰问导出] 流程已完成,applyId={}, instanceId={}, state={}, applicantSignPresent={}", id, instance.getId(), instance.getState(), StrUtil.isNotBlank(condolence.getSignature())); NutMap docData = Lang.obj2nutmap(condolence); docData.put("payUserName", StrUtil.nullToEmpty(condolence.getBankUserName())); CondolenceType type = condolenceService.dao().fetch(CondolenceType.class, condolence.getType()); docData.put("typeName", type == null ? "" : type.getName()); - docData.put("signature", ""); + docData.put("signature", null); if (StrUtil.isNotBlank(condolence.getSignature())) { PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, condolence.getSignature()); if (signature == null) throw new BaseException("申请人签字图片读取失败"); docData.put("signature", signature); } fillApplyApprovals(docData, instance); + for (String field : List.of("signature", "firstApprovalSign", "secondApprovalSign", "thirdApprovalSign", "fourthApprovalSign")) { + Object value = docData.get(field); + log.info("[职工慰问导出] 渲染前图片字段,applyId={}, instanceId={}, field={}, valueType={}", id, instance.getId(), field, value == null ? "null" : value.getClass().getName()); + } String fileName = "重庆工贸职业技术学院职工慰问申请表_" + StrUtil.nullToEmpty(condolence.getHelpUserName()); try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc"); ByteArrayOutputStream templateOutput = new ByteArrayOutputStream(); @@ -185,18 +193,24 @@ public class CondolenceMineController { if (input == null) throw new BaseException("职工慰问申请表模板不存在"); com.aspose.words.Document document = new com.aspose.words.Document(input); document.save(templateOutput, com.aspose.words.SaveFormat.DOCX); + log.info("[职工慰问导出] 模板转换完成,applyId={}, templateBytes={}", id, templateOutput.size()); try (ByteArrayInputStream templateInput = new ByteArrayInputStream(templateOutput.toByteArray())) { XWPFTemplate.compile(templateInput).render(docData).writeAndClose(output); } + log.info("[职工慰问导出] Word渲染完成,applyId={}, outputBytes={}", id, output.size()); if (Boolean.TRUE.equals(print)) { try (ByteArrayInputStream wordInput = new ByteArrayInputStream(output.toByteArray()); ByteArrayOutputStream pdfOutput = new ByteArrayOutputStream()) { new com.aspose.words.Document(wordInput).save(pdfOutput, com.aspose.words.SaveFormat.PDF); + log.info("[职工慰问导出] PDF转换完成,applyId={}, outputBytes={}", id, pdfOutput.size()); CommonDownloadUtil.download(fileName + ".pdf", pdfOutput.toByteArray(), response); } } else { CommonDownloadUtil.download(fileName + ".docx", output.toByteArray(), response); } + } catch (Exception e) { + log.error("[职工慰问导出] 模板渲染或文件输出失败,applyId={}, instanceId={}, format={}", id, instance.getId(), Boolean.TRUE.equals(print) ? "PDF" : "Word", e); + throw e; } } @@ -206,29 +220,39 @@ public class CondolenceMineController { String[] fields = {"firstApproval", "secondApproval", "thirdApproval", "fourthApproval"}; List suffixes = List.of("Opinion", "Sign", "Year", "Month", "Day"); for (String field : fields) { - for (String suffix : suffixes) docData.put(field + suffix, ""); + for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : ""); } List tasks = condolenceService.dao().query(ProcessTask.class, Cnd.where("processInstanceId", "=", instance.getId()).asc("id")); + log.info("[职工慰问导出] 查询审批记录,applyId={}, instanceId={}, taskCount={}, expectedTaskKeys={}", instance.getBusinessNo(), instance.getId(), tasks.size(), List.of(taskKeys)); for (ProcessTask task : tasks) { ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId()); - if ("startTask".equals(task.getTaskName()) || (taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) { + log.info("[职工慰问导出] 审批记录,instanceId={}, taskId={}, taskKey={}, displayName={}, state={}, finishTime={}, isFirstTaskNode={}, matchedApproval={}", instance.getId(), task.getId(), task.getTaskName(), task.getDisplayName(), task.getTaskState(), task.getFinishTime(), taskVO.getExt() == null ? null : taskVO.getExt().get("isFirstTaskNode"), List.of(taskKeys).contains(task.getTaskName())); + if ("startTask".equals(task.getTaskName()) || (!List.of(taskKeys).contains(task.getTaskName()) + && taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) { + log.info("[职工慰问导出] 申请节点重置本轮审批字段,instanceId={}, taskId={}, taskKey={}", instance.getId(), task.getId(), task.getTaskName()); // 重新申请后,仅导出本轮审批记录。 for (String field : fields) { - for (String suffix : suffixes) docData.put(field + suffix, ""); + for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : ""); } continue; } for (int i = 0; i < taskKeys.length; i++) { if (!taskKeys[i].equals(task.getTaskName())) continue; - for (String suffix : suffixes) docData.put(fields[i] + suffix, ""); - if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) continue; + for (String suffix : suffixes) docData.put(fields[i] + suffix, "Sign".equals(suffix) ? null : ""); + if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) { + log.info("[职工慰问导出] 跳过未完成审批,instanceId={}, taskId={}, field={}, state={}", instance.getId(), task.getId(), fields[i], task.getTaskState()); + continue; + } Dict data = taskVO.getExt() == null ? Dict.create() : taskVO.getTaskFormData(); + log.info("[职工慰问导出] 读取审批表单,instanceId={}, taskId={}, field={}, formKeys={}, signPresent={}, signReferenceLength={}", instance.getId(), task.getId(), fields[i], data.keySet(), StrUtil.isNotBlank(data.getStr("sign")), StrUtil.nullToEmpty(data.getStr("sign")).length()); + if (StrUtil.isBlank(data.getStr("sign"))) log.warn("[职工慰问导出] 已完成审批缺少签名字段,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i]); docData.put(fields[i] + "Opinion", StrUtil.nullToEmpty(data.getStr("opinion"))); if (StrUtil.isNotBlank(data.getStr("sign"))) { PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, data.getStr("sign")); if (signature == null) throw new BaseException("审批签字图片读取失败"); docData.put(fields[i] + "Sign", signature); + log.info("[职工慰问导出] 审批签名填充完成,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i] + "Sign"); } docData.put(fields[i] + "Year", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy")); docData.put(fields[i] + "Month", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "M"));