package jnpf.dmsService; import jnpf.base.UserInfo; import jnpf.dmsEntity.operationlog.entity.DmsFileOperationLogEntity; import jnpf.dmsEntity.operationlog.enums.DmsFileOperationType; import jnpf.dmsEntity.operationlog.vo.DmsFileOperationLogItemVO; import jnpf.dmsEntity.operationlog.vo.DmsFileOperationLogPageVO; import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity; import jnpf.dmsEntity.permission.enums.DmsPermissionAction; import jnpf.dmsEntity.permission.enums.DmsResourceType; import jnpf.dmsMapper.DmsFileOperationLogMapper; import jnpf.dmsMapper.DmsFileVersionMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.dmsPermission.DmsPermissionError; import jnpf.dmsPermission.DmsPermissionException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Collections; import java.util.UUID; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class DmsFileOperationLogService { private static final int DEFAULT_PAGE_SIZE = 10; private static final int MAX_PAGE_SIZE = 50; private static final int MAX_KEYWORD_LENGTH = 100; private final DmsCurrentIdentity currentIdentity; private final DmsPermissionDecisionService decisionService; private final DmsFileVersionMapper fileVersionMapper; private final DmsFileOperationLogMapper operationLogMapper; public void recordUpload(UserInfo user, String tenantId, UUID documentId, UUID fileVersionId, String fileName, String serviceId, String sourceId) { record(user, tenantId, documentId, fileVersionId, fileName, DmsFileOperationType.UPLOAD, "UPLOAD:" + serviceId + ":" + sourceId); } public void recordRevision(UserInfo user, String tenantId, UUID documentId, UUID fileVersionId, String fileName, String serviceId, String sourceId) { record(user, tenantId, documentId, fileVersionId, fileName, DmsFileOperationType.REVISION, "REVISION:" + serviceId + ":" + sourceId); } public void recordView(UserInfo user, String tenantId, UUID documentId, UUID fileVersionId, String fileName, UUID operationId) { record(user, tenantId, documentId, fileVersionId, fileName, DmsFileOperationType.VIEW, "VIEW:" + operationId); } public void recordDownload(UserInfo user, String tenantId, UUID documentId, UUID fileVersionId, String fileName, UUID operationId) { record(user, tenantId, documentId, fileVersionId, fileName, DmsFileOperationType.DOWNLOAD, "DOWNLOAD:" + operationId); } @Transactional(readOnly = true) public DmsFileOperationLogPageVO page(UUID fileVersionId, String keyword, Integer requestedPage, Integer requestedSize) { UserInfo user = currentIdentity.requireUser(); String tenantId = currentIdentity.tenantId(user); decisionService.requireAllowed(DmsResourceType.FILE_VERSION, fileVersionId, DmsPermissionAction.READ); DmsFileVersionEntity version = fileVersionMapper.selectByTenantAndId(tenantId, fileVersionId); if (version == null) { throw DmsPermissionException.of(DmsPermissionError.RESOURCE_NOT_FOUND, "文件版本不存在"); } String normalizedKeyword = normalizeKeyword(keyword); int currentPage = requestedPage == null || requestedPage < 1 ? 1 : requestedPage; int pageSize = requestedSize == null || requestedSize < 1 ? DEFAULT_PAGE_SIZE : Math.min(requestedSize, MAX_PAGE_SIZE); long offset = (long) (currentPage - 1) * pageSize; long total = operationLogMapper.countByDocument(tenantId, version.getDocumentId(), normalizedKeyword); DmsFileOperationLogPageVO result = new DmsFileOperationLogPageVO(); result.setCurrentPage(currentPage); result.setPageSize(pageSize); result.setTotal(total); if (offset >= total) { result.setList(Collections.emptyList()); return result; } result.setList(operationLogMapper.selectByDocument(tenantId, version.getDocumentId(), normalizedKeyword, pageSize, offset).stream() .map(this::toItem) .collect(Collectors.toList())); return result; } private void record(UserInfo user, String tenantId, UUID documentId, UUID fileVersionId, String fileName, DmsFileOperationType type, String operationKey) { String operatorName = displayName(user); DmsFileOperationLogEntity log = new DmsFileOperationLogEntity(); log.setTenantId(tenantId.trim()); log.setDocumentId(documentId); log.setFileVersionId(fileVersionId); log.setOperationCode(type.name()); log.setOperationKey(operationKey); log.setOperatorUserId(user.getUserId().trim()); log.setOperatorName(operatorName); log.setFileName(fileName.trim()); log.setOperationContent("用户" + operatorName + type.getActionText() + ":" + fileName.trim()); operationLogMapper.insertIgnore(log); } private DmsFileOperationLogItemVO toItem(DmsFileOperationLogEntity entity) { DmsFileOperationLogItemVO result = new DmsFileOperationLogItemVO(); result.setId(entity.getId()); result.setOperationCode(entity.getOperationCode()); result.setOperationContent(entity.getOperationContent()); result.setOccurredAt(entity.getOccurredAt()); return result; } private String displayName(UserInfo user) { String userName = trimToNull(user.getUserName()); if (userName != null) { return userName; } String account = trimToNull(user.getUserAccount()); return account != null ? account : user.getUserId().trim(); } private String normalizeKeyword(String keyword) { String normalized = trimToNull(keyword); if (normalized != null && normalized.length() > MAX_KEYWORD_LENGTH) { throw DmsPermissionException.of(DmsPermissionError.INVALID_REQUEST, "日志搜索关键字不能超过 " + MAX_KEYWORD_LENGTH + " 个字符"); } return normalized; } private String trimToNull(String value) { return value == null || value.trim().isEmpty() ? null : value.trim(); } }