package jnpf.fileStorage.dms; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.base.ActionResult; import jnpf.dms.DmsResourceApi; import jnpf.dmsEntity.storage.approval.DmsApprovedBatch; import jnpf.dmsEntity.storage.approval.DmsApprovedItem; import jnpf.dmsEntity.storage.form.DmsApprovedRegistrationForm; import jnpf.dmsEntity.storage.form.DmsApprovedRegistrationCallback; import jnpf.dmsEntity.storage.form.DmsApprovedRegistrationCallback.StoredFile; import jnpf.dmsEntity.storage.form.DmsFileUploadRegisterForm; import jnpf.exception.DataException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.util.Objects; @Service @RequiredArgsConstructor public class DmsWorkflowFileCreateService { private static final String SERVICE_ID = "jnpf-file"; private final DmsResourceApi dmsResourceApi; private final DmsFileStorageService fileStorageService; private final DmsCommonFileReader commonFileReader; private final DmsApprovalPageMergeService approvalPageMergeService; private final DmsQianpiyeDocxWriter qianpiyeDocxWriter; private final ObjectMapper json; /** DMS owns source data and registration progress; file only consumes the pushed set. */ @AuditLog(action = "DMS_WORKFLOW_REGISTER_APPROVED", bizCodeExpr = "#form.taskId") public DmsApprovedBatch process(DmsApprovedRegistrationForm form, String auditBizSign) { if (form.getBatchId() == null || form.getSourceDigest() == null || form.getFiles() == null || form.getFiles().isEmpty()) throw new DataException("DMS推送的登记批次不完整"); DmsApprovedRegistrationCallback callback = new DmsApprovedRegistrationCallback(); callback.setTenantId(form.getTenantId()); callback.setAttemptToken(form.getAttemptToken()); callback.setBatchId(form.getBatchId()); callback.setSourceDigest(form.getSourceDigest()); for (DmsApprovedItem item : form.getFiles()) { if (item == null || item.getDocumentId() == null || item.getFileVersionId() == null) throw new DataException("DMS推送的文件缺少登记ID"); if ("REUSE".equals(item.getChangeType())) continue; if (!"CREATE".equals(item.getChangeType()) && !"REVISE".equals(item.getChangeType())) throw new DataException("DMS推送的文件操作类型无效"); StoredFile stored = new StoredFile(); stored.setSourceKey(item.getSourceKey()); stored.setFileJson(item.getFileJson()); stored.setContent(commonFileReader.withFile(singleFileUrl(item.getFileJson()), item.getFileJson(), item.getDocumentName(), file -> store(item, file))); callback.getFiles().add(stored); } DmsApprovedBatch accepted = requireBatch(dmsResourceApi.registerWorkflowUpload( SERVICE_ID, auditBizSign, callback), form); if (!form.getBatchId().equals(accepted.getId()) || !Objects.equals(form.getSourceDigest(), accepted.getSourceDigest()) || !("WAITING".equals(accepted.getStatus()) || "APPLIED".equals(accepted.getStatus()))) throw new DataException("DMS未返回完整的登记确认结果"); return accepted; } private DmsFileUploadRegisterForm store(DmsApprovedItem item, MultipartFile file) { String approvalPage = item.getQianpiyeFiles() == null || item.getQianpiyeFiles().isBlank() ? item.getApprovalPageFileJson() : item.getQianpiyeFiles(); MultipartFile source = isDocx(file) && item.getApprovalValuesByTag() != null && approvalPage != null && !approvalPage.isBlank() ? approvalPageMergeService.withoutApprovalPages(file) : file; MultipartFile renderedFile = isDocx(file) && item.getApprovalValuesByTag() != null ? qianpiyeDocxWriter.render(source, item.getApprovalValuesByTag(), item.getApprovalFlowVersionId()) : file; if (approvalPage == null || approvalPage.isBlank() || !isDocx(file)) { return fileStorageService.storeWorkflowContent( item.getDocumentId(), item.getFileVersionId(), renderedFile); } return commonFileReader.withFile(singleFileUrl(approvalPage), approvalPage, "签批页", page -> { MultipartFile rendered = isDocx(page) ? qianpiyeDocxWriter.render( page, item.getApprovalValuesByTag(), item.getApprovalFlowVersionId()) : page; return fileStorageService.storeWorkflowContent(item.getDocumentId(), item.getFileVersionId(), approvalPageMergeService.replaceOrPrepend(renderedFile, rendered)); }); } private boolean isDocx(MultipartFile file) { String name = file == null ? null : file.getOriginalFilename(); return name != null && name.toLowerCase(java.util.Locale.ROOT).endsWith(".docx"); } private DmsApprovedBatch requireBatch(ActionResult result, DmsApprovedRegistrationForm form) { if (result == null || !Integer.valueOf(200).equals(result.getCode()) || result.getData() == null) throw new DataException(result == null ? "DMS文件登记无响应" : result.getMsg()); DmsApprovedBatch batch = result.getData(); if (!form.getSourceId().trim().equals(batch.getFlowId()) || !form.getTaskId().trim().equals(batch.getTaskId()) || !Objects.equals(form.getAuditType(), batch.getAuditType())) throw new DataException("DMS返回的批准批次与请求不匹配"); return batch; } String singleFileUrl(String fileJson) { try { JsonNode value = json.readTree(fileJson); if (value.isArray()) { if (value.size() != 1) throw new DataException("每个主文件或记录必须有且只有一个文件"); value = value.get(0); } String url = value.path("url").asText(null); if (url == null || url.isBlank()) throw new DataException("审核附件缺少URL"); return url; } catch (DataException e) { throw e; } catch (Exception e) { throw new DataException("审核附件格式不正确"); } } }