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")); diff --git a/src/main/resources/static/components/plugins/sysUpload/h5Index.vue b/src/main/resources/static/components/plugins/sysUpload/h5Index.vue index 6eb5dff..35bd0f8 100644 --- a/src/main/resources/static/components/plugins/sysUpload/h5Index.vue +++ b/src/main/resources/static/components/plugins/sysUpload/h5Index.vue @@ -9,6 +9,7 @@ progress :accept="accept" :max-count="upload_number" + :upload-text="upload_text" title="" description="" tip="" @@ -50,6 +51,11 @@ module.exports = { default: 1, required: false }, + upload_text: { + type: String, + default: "", + required: false + }, // 上传返回id或url upload_result_type: { type: String, @@ -101,6 +107,7 @@ module.exports = { this.fileList = val.map((v) => { return { ...v, + file: v.file || { name: v.name }, status: null, isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()) } @@ -118,6 +125,7 @@ module.exports = { this.fileList = val.map((v) => { return { ...v, + file: v.file || { name: v.name }, url: v.url ? v.url : v.response?.data, isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()), status: null @@ -171,8 +179,8 @@ module.exports = { f.url = resp.data f.response = resp f.percentage = 100 - f.isImage = true - delete f.file + f.isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(f.name.split(".").pop().toLowerCase()) + f.file = { name: f.name } delete f.content } else { f.status = "fail" diff --git a/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc b/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc index 6a9e468..699800e 100644 Binary files a/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc and b/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc differ diff --git a/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.docx b/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.docx new file mode 100644 index 0000000..d4ccba2 Binary files /dev/null and b/src/main/resources/templates/condolence/重庆工贸职业技术学院职工慰问申请表.docx differ diff --git a/src/main/resources/templates/diffucult/重庆工贸职业技术学院困难帮扶补助表.doc b/src/main/resources/templates/difficulty_apply/重庆工贸职业技术学院困难帮扶补助表.doc similarity index 100% rename from src/main/resources/templates/diffucult/重庆工贸职业技术学院困难帮扶补助表.doc rename to src/main/resources/templates/difficulty_apply/重庆工贸职业技术学院困难帮扶补助表.doc diff --git a/src/main/resources/templates/difficulty_apply/重庆工贸职业技术学院困难帮扶补助表.docx b/src/main/resources/templates/difficulty_apply/重庆工贸职业技术学院困难帮扶补助表.docx new file mode 100644 index 0000000..4b07b48 Binary files /dev/null and b/src/main/resources/templates/difficulty_apply/重庆工贸职业技术学院困难帮扶补助表.docx differ diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/condolence/apply/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/condolence/apply/index.html index 581a025..4ab1df2 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/condolence/apply/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/condolence/apply/index.html @@ -55,7 +55,7 @@ layout("/layouts/platform.html"){ --> - + - + - - + - + + + + type="textarea" :rows="3" resize="none"> @@ -238,7 +240,10 @@ layout("/layouts/platform.html"){ payUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }], type: [{ required: true, message: "必填", trigger: ["change", "blur"] }], way: [{ required: true, message: "必填", trigger: ["change", "blur"] }], - money: [{ required: true, message: "必填", trigger: ["change", "blur"] }], + money: [ + { required: true, message: "请填写慰问金额", trigger: ["change", "blur"] }, + { validator: (rule, value, callback) => callback(this.validateMoney(value) ? undefined : new Error("慰问金额须大于0且不超过10000元,最多两位小数")), trigger: ["change", "blur"] } + ], occurTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }], child: [{ required: true, message: "必填", trigger: ["change", "blur"] }], hospital: [{ required: true, message: "必填", trigger: ["change", "blur"] }], @@ -247,14 +252,20 @@ layout("/layouts/platform.html"){ hospitalBy: [{ required: true, message: "必填", trigger: ["change", "blur"] }], deadImmediateFamily: [{ required: true, message: "必填", trigger: ["change", "blur"] }], remark: [{ required: true, message: "必填", trigger: ["change", "blur"] }], - files: [{ required: true, message: "必填", trigger: ["change", "blur"] }], + files: [{ required: true, type: "array", min: 1, max: 5, message: "请上传1至5个附件", trigger: ["change", "blur"] }], signature: [{ required: true, message: "必填", trigger: ["change", "blur"] }], handlerUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }], - certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }], - bankCardNumber: [{ required: true, message: "必填", trigger: ["change", "blur"] }], + // certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }], + bankCardNumber: [ + { required: true, message: "请填写银行卡号或对公账户号", trigger: ["change", "blur"] }, + { pattern: /^[0-9]{6,30}$/, message: "收款账户须为6至30位数字(银行卡号或对公账户号)", trigger: ["change", "blur"] } + ], bankUserName: [{ required: true, message: "必填", trigger: ["change", "blur"] }], bankOfDeposit: [{ required: true, message: "必填", trigger: ["change", "blur"] }], - thisYearHospitalizationNum: [{ required: true, message: "必填", trigger: ["change", "blur"] }], + thisYearHospitalizationNum: [ + { required: true, message: "必填", trigger: ["change", "blur"] }, + { type: "integer", min: 0, max: 10000, message: "住院次数须为0至10000的整数", trigger: ["change", "blur"] } + ], leaveHospitalTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }], hospitalizationTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }], }, @@ -268,6 +279,9 @@ layout("/layouts/platform.html"){ } }, methods: { + validateMoney(value) { + return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000 + }, createRemoteMethod(options) { return (keyword) => { this.selectQueryUser(keyword, options) diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/condolence/type/basicForm.js b/src/main/resources/views/platform/zhgh/staffbenefit/condolence/type/basicForm.js index ae1fe12..dad3941 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/condolence/type/basicForm.js +++ b/src/main/resources/views/platform/zhgh/staffbenefit/condolence/type/basicForm.js @@ -37,12 +37,12 @@ const basicForm = { 不上传 --> - - - - - - + + + 是 + 否 + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/difficulthelp/apply/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/difficulthelp/apply/index.html index 0767aa6..c0df35c 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/difficulthelp/apply/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/difficulthelp/apply/index.html @@ -26,7 +26,7 @@ layout("/layouts/platform.html"){ - +