修复设备模块导出报 TemplateRenderPolicy render error (500):签名图片缺失时用透明图兜底
- UserUtils 新增 orTransparentPicture / getFinalUserSignatureOrTransparent(按id/按姓名),签名未配置或签名文件缺失时返回全透明图片,原方法保留不动
- cnas-device 13 个 ServiceImpl 共 31 处签名渲染调用换用兜底方法,覆盖校准计划、核查计划及明细/对比、保养计划、使用授权、利用外部仪器、事故报告、报废、故障维修、点检、量值溯源等全部 Word 导出
- DeviceStateServiceImpl(停用/启用导出)4 处"签名缺失塞 null"改为透明图兜底,移除旧人名查询与中断抛出
| | |
| | | put("deviceAccidentReport", deviceAccidentReport); |
| | | put("device", finalDevice); |
| | | // 报告人签名 |
| | | put("reportUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getReportUserId())); |
| | | put("reportUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getReportUserId())); |
| | | // 评估人签名 |
| | | put("assessorUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getAssessorUserId())); |
| | | put("assessorUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getAssessorUserId())); |
| | | // 部门负责人签名 |
| | | put("departmentHeadUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getDepartmentHeadUserId())); |
| | | put("departmentHeadUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getDepartmentHeadUserId())); |
| | | // 技术负责人签名 |
| | | put("technicalDirectorUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getTechnicalDirectorUserId())); |
| | | put("technicalDirectorUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getTechnicalDirectorUserId())); |
| | | // 主任签名 |
| | | put("directorHeadUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getDepartmentHeadUserId())); |
| | | put("directorHeadUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getDepartmentHeadUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceBreakdownMaintenance", deviceBreakdownMaintenance); |
| | | put("device", finalDevice); |
| | | // 申请人签名 |
| | | put("applicantUrl", UserUtils.getFinalUserSignatureUrl(deviceBreakdownMaintenance.getApplicantUserId())); |
| | | put("applicantUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceBreakdownMaintenance.getApplicantUserId())); |
| | | // 部门负责人签名 |
| | | put("headUrl", UserUtils.getFinalUserSignatureUrl(deviceBreakdownMaintenance.getDepartmentHeadUserId())); |
| | | put("headUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceBreakdownMaintenance.getDepartmentHeadUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceCalibrationPlan", deviceCalibrationPlanDto); |
| | | put("deviceCalibrationPlanDetailDtoList", deviceCalibrationPlanDetailDtoList); |
| | | //获取编制人的签名地址 |
| | | put("organizationUrl", UserUtils.getFinalUserSignatureUrl(deviceCalibrationPlan.getRatifyUserId())); |
| | | put("organizationUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceCalibrationPlan.getRatifyUserId())); |
| | | //获取批准人的签名地址 |
| | | put("approvedUrl", UserUtils.getFinalUserSignatureUrl(deviceCalibrationPlan.getWriteUserId())); |
| | | put("approvedUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceCalibrationPlan.getWriteUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceExaminePlan", deviceExaminePlanDto); |
| | | put("deviceExaminePlanDetailsDtoList", deviceExaminePlanDetailsDtoList); |
| | | //获取核查人的签名地址 |
| | | put("writeUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExaminePlanDto.getWriteUserId())); |
| | | put("writeUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceExaminePlanDto.getWriteUserId())); |
| | | //获取审查人的签名地址 |
| | | put("reviewUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExaminePlanDto.getRatifyUserId())); |
| | | put("reviewUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceExaminePlanDto.getRatifyUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceExamineRecordContrast", deviceExamineRecordContrast); |
| | | put("deviceExamineRecordContrastDetailsDtoList", deviceExamineRecordContrastDetailsDtoList); |
| | | //获取核查人的签名地址 |
| | | put("checkerUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordContrast.getCheckerUserId())); |
| | | put("checkerUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceExamineRecordContrast.getCheckerUserId())); |
| | | //获取审查人的签名地址 |
| | | put("reviewUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordContrast.getReviewUserId())); |
| | | put("reviewUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceExamineRecordContrast.getReviewUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceExamineRecordDto", deviceExamineRecordDto); |
| | | put("deviceExamineRecordDetailList", deviceExamineRecordDetailList); |
| | | //获取核查人的签名地址 |
| | | put("checkerUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordDto.getCheckerUserId())); |
| | | put("checkerUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceExamineRecordDto.getCheckerUserId())); |
| | | //获取审查人的签名地址 |
| | | put("reviewUserUrl", UserUtils.getFinalUserSignatureUrl(deviceExamineRecordDto.getReviewUserId())); |
| | | put("reviewUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceExamineRecordDto.getReviewUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | new HashMap<String, Object>() {{ |
| | | put("deviceAccidentReport", deviceAccidentReport); |
| | | // 申请人签名 |
| | | put("applicantUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getApplicantUserId())); |
| | | put("applicantUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getApplicantUserId())); |
| | | // 部门负责人签名 |
| | | put("departmentHeadUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getDepartmentHeadUserId())); |
| | | put("departmentHeadUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getDepartmentHeadUserId())); |
| | | // 计量室人签名 |
| | | put("meteringRoomUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getMeteringRoomUserId())); |
| | | put("meteringRoomUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getMeteringRoomUserId())); |
| | | // 批准人签名 |
| | | put("approverUserUrl", UserUtils.getFinalUserSignatureUrl(deviceAccidentReport.getApproverUserId())); |
| | | put("approverUserUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceAccidentReport.getApproverUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceImpower", deviceImpowerDto); |
| | | put("deviceImpowerDetailsDtoList", deviceImpowerDetailsDtoList); |
| | | // 授权人地址 |
| | | put("auditUrl", UserUtils.getFinalUserSignatureUrl(deviceImpower.getAuditId())); |
| | | put("auditUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceImpower.getAuditId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceInspectionRecord", deviceInspectionRecordDto); |
| | | put("deviceInspectionRecordDetailsList", deviceInspectionRecordDetailsList); |
| | | put("device", device); |
| | | put("recorderUrl", UserUtils.getFinalUserSignatureUrl(deviceInspectionRecordDto.getRecorderId())); |
| | | put("reviewerUrl", UserUtils.getFinalUserSignatureUrl(deviceInspectionRecordDto.getReviewerId())); |
| | | put("recorderUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceInspectionRecordDto.getRecorderId())); |
| | | put("reviewerUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceInspectionRecordDto.getReviewerId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | } |
| | | deviceMaintenance.setMaintenanceContent(maintenanceContent.toString()); |
| | | // 添加维护人图片 |
| | | deviceMaintenance.setMaintenanceUserUrlRender(UserUtils.getFinalUserSignatureUrl(deviceMaintenance.getMaintenanceUserId())); |
| | | deviceMaintenance.setMaintenanceUserUrlRender(UserUtils.getFinalUserSignatureOrTransparent(deviceMaintenance.getMaintenanceUserId())); |
| | | |
| | | } |
| | | |
| | |
| | | put("deviceMaintenancePlan", deviceMaintenancePlan); |
| | | put("deviceMaintenancePlanDetailsDtoList", deviceMaintenancePlanDetailsDtoList); |
| | | // 编制人签名地址 |
| | | put("compilerUrl", UserUtils.getFinalUserSignatureUrl(deviceMaintenancePlan.getCompilerId())); |
| | | put("compilerUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceMaintenancePlan.getCompilerId())); |
| | | // 审核人签名地址 |
| | | put("auditUrl", UserUtils.getFinalUserSignatureUrl(deviceMaintenancePlan.getAuditId())); |
| | | put("auditUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceMaintenancePlan.getAuditId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | put("deviceScrapped", deviceScrapped); |
| | | put("device", finalDevice); |
| | | // 申请人签名 |
| | | put("applicantUrl", UserUtils.getFinalUserSignatureUrl(deviceScrapped.getApplicantUserId())); |
| | | put("applicantUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceScrapped.getApplicantUserId())); |
| | | // 部门负责人签名 |
| | | put("headUrl", UserUtils.getFinalUserSignatureUrl(deviceScrapped.getDepartmentHeadUserId())); |
| | | put("headUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceScrapped.getDepartmentHeadUserId())); |
| | | // 计量室签名 |
| | | put("metrologyRoomUrl", UserUtils.getFinalUserSignatureUrl(deviceScrapped.getMeteringRoomUserId())); |
| | | put("metrologyRoomUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceScrapped.getMeteringRoomUserId())); |
| | | // 批准人签名 |
| | | put("approverUrl", UserUtils.getFinalUserSignatureUrl(deviceScrapped.getApproverUserId())); |
| | | put("approverUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceScrapped.getApproverUserId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.deepoove.poi.XWPFTemplate; |
| | | import com.deepoove.poi.config.Configure; |
| | | import com.deepoove.poi.data.Pictures; |
| | | import com.ruoyi.basic.mapper.LaboratoryMapper; |
| | | import com.ruoyi.basic.pojo.Laboratory; |
| | | import com.ruoyi.common.core.domain.entity.User; |
| | | import com.ruoyi.device.dto.DeviceStateDto; |
| | | import com.ruoyi.device.mapper.DeviceStateMapper; |
| | | import com.ruoyi.device.pojo.DeviceState; |
| | | import com.ruoyi.device.service.DeviceStateService; |
| | | import com.ruoyi.framework.exception.ErrorException; |
| | | import com.ruoyi.system.mapper.UserMapper; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import com.ruoyi.inspect.util.UserUtils; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import jakarta.annotation.Resource; |
| | |
| | | |
| | | @Resource |
| | | private LaboratoryMapper laboratoryMapper; |
| | | |
| | | @Resource |
| | | private UserMapper userMapper; |
| | | |
| | | @Value("${file.path}") |
| | | private String imgUrl; |
| | | |
| | | @Override |
| | | public IPage<DeviceStateDto> getDeviceStatePage(Integer deviceId, Page page, String processNumber) { |
| | |
| | | laboratoryName = ""; |
| | | } |
| | | |
| | | //todo: 设备状态查询签名地址 暂时人名查询 |
| | | //获取申请人的签名地址 |
| | | String applicantUrl = null; |
| | | if (deviceStateDto.getSubmitOperatingPersonnel() != null) { |
| | | applicantUrl = userMapper.selectOne(Wrappers.<User>lambdaQuery() |
| | | .eq(User::getName, deviceStateDto.getSubmitOperatingPersonnel())) |
| | | .getSignatureUrl(); |
| | | if (StringUtils.isBlank(applicantUrl)) { |
| | | throw new ErrorException("找不到申请人的签名"); |
| | | } |
| | | } |
| | | |
| | | //获取部门负责人的签名地址 |
| | | String headOfDepartmentUrl = null; |
| | | if (deviceStateDto.getDepartmentNextPesponsible() != null) { |
| | | headOfDepartmentUrl = userMapper.selectOne(Wrappers.<User>lambdaQuery() |
| | | .eq(User::getName, deviceStateDto.getDepartmentNextPesponsible())) |
| | | .getSignatureUrl(); |
| | | if (StringUtils.isBlank(headOfDepartmentUrl)) { |
| | | throw new ErrorException("找不到部门负责人的签名"); |
| | | } |
| | | } |
| | | |
| | | //获取计量室复测人的签名地址 |
| | | String measurementRoomUrl = null; |
| | | if (deviceStateDto.getMeasuringRoomNextPesponsible() != null) { |
| | | measurementRoomUrl = userMapper.selectOne(Wrappers.<User>lambdaQuery() |
| | | .eq(User::getName, deviceStateDto.getMeasuringRoomNextPesponsible())) |
| | | .getSignatureUrl(); |
| | | if (StringUtils.isBlank(measurementRoomUrl)) { |
| | | throw new ErrorException("找不到计量室复测人的签名"); |
| | | } |
| | | } |
| | | |
| | | //获取批准人的签名地址 |
| | | String approvedUrl = null; |
| | | if (deviceStateDto.getApprovalNextPesponsible() != null) { |
| | | approvedUrl = userMapper.selectOne(Wrappers.<User>lambdaQuery() |
| | | .eq(User::getName, deviceStateDto.getApprovalNextPesponsible())) |
| | | .getSignatureUrl(); |
| | | if (StringUtils.isBlank(approvedUrl)) { |
| | | throw new ErrorException("找不到批准人的签名"); |
| | | } |
| | | } |
| | | |
| | | // 获取路径 |
| | | InputStream inputStream = this.getClass().getResourceAsStream("/static/word/device-status.docx"); |
| | | Configure configure = Configure.builder() |
| | | .build(); |
| | | String finalApplicantUrl = applicantUrl; // 申请人的签名地址 |
| | | String finalHeadOfDepartmentUrl = headOfDepartmentUrl; // 部门负责人的签名地址 |
| | | String finalMeasurementRoomUrl = measurementRoomUrl; // 计量室复测人的签名地址 |
| | | String finalApprovedUrl = approvedUrl; // 批准人的签名地址 |
| | | XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render( |
| | | new HashMap<String, Object>() {{ |
| | | put("deviceStateDto", deviceStateDto); |
| | | put("submitOperatingPersonnelUrl", StringUtils.isNotBlank(finalApplicantUrl) ? Pictures.ofLocal(imgUrl + "/" + finalApplicantUrl).create() : null); |
| | | put("departmentNextPesponsibleUrl", StringUtils.isNotBlank(finalHeadOfDepartmentUrl) ? Pictures.ofLocal(imgUrl + "/" + finalHeadOfDepartmentUrl).create() : null); |
| | | put("measuringRoomNextPesponsibleUrl", StringUtils.isNotBlank(finalMeasurementRoomUrl) ? Pictures.ofLocal(imgUrl + "/" + finalMeasurementRoomUrl).create() : null); |
| | | put("approvalNextPesponsibleUrl", StringUtils.isNotBlank(finalApprovedUrl) ? Pictures.ofLocal(imgUrl + "/" + finalApprovedUrl).create() : null); |
| | | // 签名兜底: 人员未配置签名或签名文件缺失时返回透明图片, 保证导出不因空图片报错 |
| | | put("submitOperatingPersonnelUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceStateDto.getSubmitOperatingPersonnel())); |
| | | put("departmentNextPesponsibleUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceStateDto.getDepartmentNextPesponsible())); |
| | | put("measuringRoomNextPesponsibleUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceStateDto.getMeasuringRoomNextPesponsible())); |
| | | put("approvalNextPesponsibleUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceStateDto.getApprovalNextPesponsible())); |
| | | put("laboratory", laboratoryName); |
| | | }}); |
| | | |
| | |
| | | put("deviceTraceabilityManagement", deviceTraceabilityManagement); |
| | | put("deviceTraceabilityManagementDetailsDtoList", deviceTraceabilityManagementDetailsDtoList); |
| | | // 编制人签名地址 |
| | | put("compilerUrl", UserUtils.getFinalUserSignatureUrl(deviceTraceabilityManagement.getCompilerId())); |
| | | put("compilerUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceTraceabilityManagement.getCompilerId())); |
| | | // 审核人签名地址 |
| | | put("auditUrl", UserUtils.getFinalUserSignatureUrl(deviceTraceabilityManagement.getAuditId())); |
| | | put("auditUrl", UserUtils.getFinalUserSignatureOrTransparent(deviceTraceabilityManagement.getAuditId())); |
| | | }}); |
| | | |
| | | try { |
| | |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.Base64; |
| | | |
| | | /** |
| | | * Author: yuan |
| | | * Date: 2024-12-17 星期二 10:35:50 |
| | |
| | | } |
| | | return StringUtils.isNotBlank(userSignatureUrl) ? Pictures.ofLocal(imgUrl + "/" + userSignatureUrl).create() : null; |
| | | } |
| | | |
| | | /** |
| | | * 全透明 1x1 PNG, 签名未配置/签名文件缺失时的兜底图片 |
| | | */ |
| | | private static final byte[] TRANSPARENT_PNG = Base64.getDecoder().decode( |
| | | "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY2BgYGAAAAAFAAGKM+MAAAAAAElFTkSuQmCC"); |
| | | |
| | | /** |
| | | * 图片值兜底: null 或本地图片读取失败(如签名文件缺失)时返回透明图片 |
| | | */ |
| | | public static PictureRenderData orTransparentPicture(PictureRenderData picture) { |
| | | if (picture != null) { |
| | | try { |
| | | byte[] data = picture.readPictureData(); |
| | | if (data != null && data.length > 0) { |
| | | return picture; |
| | | } |
| | | } catch (Exception ignored) { |
| | | } |
| | | } |
| | | return Pictures.ofBytes(TRANSPARENT_PNG).create(); |
| | | } |
| | | |
| | | /** |
| | | * 渲染Word用户签名对象(按人员id, 带兜底): 人员不存在或签名未配置/文件缺失时返回透明图片, 不抛错 |
| | | */ |
| | | public static PictureRenderData getFinalUserSignatureOrTransparent(Integer userId) { |
| | | try { |
| | | return orTransparentPicture(getFinalUserSignatureUrl(userId)); |
| | | } catch (Exception e) { |
| | | return Pictures.ofBytes(TRANSPARENT_PNG).create(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 渲染Word用户签名对象(按人员姓名, 带兜底): 人员不存在或签名未配置/文件缺失时返回透明图片, 不抛错 |
| | | */ |
| | | public static PictureRenderData getFinalUserSignatureOrTransparent(String userName) { |
| | | try { |
| | | return orTransparentPicture(getFinalUserSignatureUrl(userName)); |
| | | } catch (Exception e) { |
| | | return Pictures.ofBytes(TRANSPARENT_PNG).create(); |
| | | } |
| | | } |
| | | } |