package jnpf.dmsService; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.base.UserInfo; import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity; import jnpf.dmsEntity.permission.enums.DmsPermissionAction; import jnpf.dmsEntity.permission.enums.DmsResourceType; import jnpf.dmsEntity.storage.form.DmsFileExtendValidityForm; import jnpf.dmsEntity.storage.form.DmsFileExtendValidityForm.FileRequest; import jnpf.dmsMapper.DmsDocumentMapper; import jnpf.dmsMapper.DmsFileVersionMapper; import jnpf.dmsMapper.DmsVersionStateMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.exception.DataException; import jnpf.flowable.entity.TaskEntity; import jnpf.flowable.enums.TaskStatusEnum; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import java.util.UUID; @Service @RequiredArgsConstructor public class DmsFileValidityService { private final DmsCurrentIdentity currentIdentity; private final DmsPermissionDecisionService decisionService; private final DmsWorkflowFileActivationService workflowService; private final DmsFileVersionMapper fileVersionMapper; private final DmsDocumentMapper documentMapper; private final DmsVersionStateMapper versionStateMapper; private final DmsFileValidityProjection projection; private final DmsBusinessLifecycleGuard businessOccupancy; @Transactional(rollbackFor = Exception.class) @AuditLog(action = "UPDATE", label = "批量调整文件有效期", bizModule = "DMS", bizType = "DMS_FILE_VERSION", bizCodeExpr = "", bizCodeRequired = false, targetTable = "dms_version_states", targetIdExpr = "#p0.files[0].fileVersionId", targetIdsExpr = "#p0.files.![fileVersionId]", extraExpr = "{'sourceId': #p0.sourceId, 'taskId': #p0.taskId, 'files': #p0.files}") public void extendValidity(DmsFileExtendValidityForm form) { validateRequest(form); UserInfo user = currentIdentity.requireUser(); String tenantId = currentIdentity.tenantId(user); boolean withWorkflow = form.getSourceId() != null && !form.getSourceId().trim().isEmpty(); if (withWorkflow) { TaskEntity task = workflowService.requireTask(form.getSourceId().trim(), form.getTaskId().trim()); if (!TaskStatusEnum.PASSED.getCode().equals(task.getStatus())) { throw new DataException("流程任务尚未审核通过,不能更新有效期"); } } businessOccupancy.guardValidity(tenantId,withWorkflow ? form.getTaskId().trim() : null, form.getFiles().stream().map(f->f.getFileVersionId().toString()).toList()); Set documentIds = new TreeSet<>(); for (FileRequest file : form.getFiles()) { decisionService.requireAllowed(DmsResourceType.FILE_VERSION, file.getFileVersionId(), DmsPermissionAction.UPDATE); DmsFileVersionEntity version = fileVersionMapper.selectByTenantAndId(tenantId, file.getFileVersionId()); if (version == null) { throw new DataException("文件版本不存在:" + file.getFileVersionId()); } documentIds.add(version.getDocumentId()); } // 按统一顺序锁定文档,与修订、激活互斥,避免并发批次反向加锁。 for (UUID documentId : documentIds) { if (documentMapper.selectByTenantAndIdForUpdate(tenantId, documentId) == null) { throw new DataException("文件所属文档不存在:" + documentId); } } for (FileRequest file : form.getFiles()) { int updated = versionStateMapper.updateCurrentEffectiveTo(tenantId, file.getFileVersionId(), file.getEffectiveTo()); if (updated != 1) { throw new DataException("文件有效期更新失败:" + file.getFileVersionId() + ",文件已过期或不是现行有效版本,或新截止时间未延长"); } projection.apply(tenantId, file.getFileVersionId(), file.getEffectiveTo(), user.getUserId()); } } private void validateRequest(DmsFileExtendValidityForm form) { if (form == null || form.getFiles() == null || form.getFiles().isEmpty()) { throw new DataException("文件请求列表不能为空"); } if (!form.isWorkflowPairValid()) { throw new DataException("sourceId和taskId必须同时提供或同时为空"); } Set ids = new HashSet<>(); for (FileRequest file : form.getFiles()) { if (file == null || file.getFileVersionId() == null || file.getEffectiveTo() == null) { throw new DataException("文件版本ID和有效期至不能为空"); } if (!ids.add(file.getFileVersionId())) { throw new DataException("文件版本ID不能重复:" + file.getFileVersionId()); } } } }