diff --git a/backend/api-gateway/src/main/java/com/datamate/gateway/filter/UserContextFilter.java b/backend/api-gateway/src/main/java/com/datamate/gateway/filter/UserContextFilter.java index a387a37..3577946 100644 --- a/backend/api-gateway/src/main/java/com/datamate/gateway/filter/UserContextFilter.java +++ b/backend/api-gateway/src/main/java/com/datamate/gateway/filter/UserContextFilter.java @@ -83,11 +83,13 @@ public class UserContextFilter implements GlobalFilter, Ordered { String userId = String.valueOf(claims.get("userId")); String username = claims.getSubject(); List roles = gatewayJwtUtils.getStringListClaim(claims, "roles"); + List permissions = gatewayJwtUtils.getStringListClaim(claims, "permissions"); ServerHttpRequest mutatedRequest = request.mutate() .header("X-User-Id", userId) .header("X-User-Name", username) .header("X-User-Roles", String.join(",", roles)) + .header("X-User-Permissions", String.join(",", permissions)) .build(); return chain.filter(exchange.mutate().request(mutatedRequest).build()); } diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeDirectoryApplicationService.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeDirectoryApplicationService.java index 84e3e56..141f920 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeDirectoryApplicationService.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeDirectoryApplicationService.java @@ -1,7 +1,9 @@ package com.datamate.datamanagement.application; +import com.datamate.common.auth.application.ResourceAccessService; import com.datamate.common.infrastructure.exception.BusinessAssert; import com.datamate.common.infrastructure.exception.CommonErrorCode; +import com.datamate.common.infrastructure.exception.SystemErrorCode; import com.datamate.datamanagement.common.enums.KnowledgeStatusType; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeItemDirectory; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeSet; @@ -32,17 +34,19 @@ public class KnowledgeDirectoryApplicationService { private final KnowledgeItemDirectoryRepository knowledgeItemDirectoryRepository; private final KnowledgeItemRepository knowledgeItemRepository; private final KnowledgeSetRepository knowledgeSetRepository; + private final ResourceAccessService resourceAccessService; @Transactional(readOnly = true) public List getKnowledgeDirectories(String setId, KnowledgeDirectoryQuery query) { BusinessAssert.notNull(query, CommonErrorCode.PARAM_ERROR); + requireAccessibleKnowledgeSet(setId); query.setSetId(setId); return knowledgeItemDirectoryRepository.findByCriteria(query); } public KnowledgeItemDirectory createKnowledgeDirectory(String setId, CreateKnowledgeDirectoryRequest request) { BusinessAssert.notNull(request, CommonErrorCode.PARAM_ERROR); - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); BusinessAssert.isTrue(!isReadOnlyStatus(knowledgeSet.getStatus()), DataManagementErrorCode.KNOWLEDGE_SET_STATUS_ERROR); @@ -71,7 +75,7 @@ public class KnowledgeDirectoryApplicationService { } public void deleteKnowledgeDirectory(String setId, String relativePath) { - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); BusinessAssert.isTrue(!isReadOnlyStatus(knowledgeSet.getStatus()), DataManagementErrorCode.KNOWLEDGE_SET_STATUS_ERROR); @@ -88,6 +92,15 @@ public class KnowledgeDirectoryApplicationService { return knowledgeSet; } + private KnowledgeSet requireAccessibleKnowledgeSet(String setId) { + KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + if (ResourceAccessService.CONFIDENTIAL_SENSITIVITY.equalsIgnoreCase(knowledgeSet.getSensitivity())) { + BusinessAssert.isTrue(resourceAccessService.canViewConfidential(), + SystemErrorCode.INSUFFICIENT_PERMISSIONS); + } + return knowledgeSet; + } + private boolean isReadOnlyStatus(KnowledgeStatusType status) { return status == KnowledgeStatusType.ARCHIVED || status == KnowledgeStatusType.DEPRECATED; } diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemApplicationService.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemApplicationService.java index 9c9e53a..1358693 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemApplicationService.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemApplicationService.java @@ -2,6 +2,7 @@ package com.datamate.datamanagement.application; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.datamate.common.auth.application.ResourceAccessService; import com.datamate.common.infrastructure.exception.BusinessAssert; import com.datamate.common.infrastructure.exception.BusinessException; import com.datamate.common.infrastructure.exception.CommonErrorCode; @@ -12,11 +13,11 @@ import com.datamate.datamanagement.common.enums.KnowledgeSourceType; import com.datamate.datamanagement.common.enums.KnowledgeStatusType; import com.datamate.datamanagement.domain.model.dataset.Dataset; import com.datamate.datamanagement.domain.model.dataset.DatasetFile; +import com.datamate.datamanagement.domain.model.dataset.Tag; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeItem; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeSet; import com.datamate.datamanagement.infrastructure.config.DataManagementProperties; import com.datamate.datamanagement.infrastructure.exception.DataManagementErrorCode; -import com.datamate.datamanagement.infrastructure.persistence.mapper.TagMapper; import com.datamate.datamanagement.infrastructure.persistence.repository.DatasetFileRepository; import com.datamate.datamanagement.infrastructure.persistence.repository.DatasetRepository; import com.datamate.datamanagement.infrastructure.persistence.repository.KnowledgeItemRepository; @@ -30,6 +31,7 @@ import com.datamate.datamanagement.interfaces.dto.KnowledgeItemResponse; import com.datamate.datamanagement.interfaces.dto.KnowledgeItemSearchQuery; import com.datamate.datamanagement.interfaces.dto.KnowledgeItemSearchResponse; import com.datamate.datamanagement.interfaces.dto.KnowledgeManagementStatisticsResponse; +import com.datamate.datamanagement.interfaces.dto.KnowledgeSetPagingQuery; import com.datamate.datamanagement.interfaces.dto.ReplaceKnowledgeItemFileRequest; import com.datamate.datamanagement.interfaces.dto.UpdateKnowledgeItemRequest; import com.datamate.datamanagement.interfaces.dto.UploadKnowledgeItemsRequest; @@ -56,12 +58,15 @@ import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * 知识条目应用服务 @@ -88,11 +93,11 @@ public class KnowledgeItemApplicationService { private final DatasetRepository datasetRepository; private final DatasetFileRepository datasetFileRepository; private final DataManagementProperties dataManagementProperties; - private final TagMapper tagMapper; private final KnowledgeItemPreviewService knowledgeItemPreviewService; + private final ResourceAccessService resourceAccessService; public KnowledgeItem createKnowledgeItem(String setId, CreateKnowledgeItemRequest request) { - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); BusinessAssert.isTrue(!isReadOnlyStatus(knowledgeSet.getStatus()), DataManagementErrorCode.KNOWLEDGE_SET_STATUS_ERROR); @@ -112,7 +117,7 @@ public class KnowledgeItemApplicationService { } public List uploadKnowledgeItems(String setId, UploadKnowledgeItemsRequest request) { - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); BusinessAssert.isTrue(!isReadOnlyStatus(knowledgeSet.getStatus()), DataManagementErrorCode.KNOWLEDGE_SET_STATUS_ERROR); @@ -176,7 +181,7 @@ public class KnowledgeItemApplicationService { } public KnowledgeItem updateKnowledgeItem(String setId, String itemId, UpdateKnowledgeItemRequest request) { - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, DataManagementErrorCode.KNOWLEDGE_ITEM_NOT_FOUND); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); @@ -199,6 +204,7 @@ public class KnowledgeItemApplicationService { } public void deleteKnowledgeItem(String setId, String itemId) { + requireAccessibleKnowledgeSet(setId); KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, DataManagementErrorCode.KNOWLEDGE_ITEM_NOT_FOUND); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); @@ -209,6 +215,7 @@ public class KnowledgeItemApplicationService { } public void deleteKnowledgeItems(String setId, DeleteKnowledgeItemsRequest request) { + requireAccessibleKnowledgeSet(setId); BusinessAssert.notNull(request, CommonErrorCode.PARAM_ERROR); List ids = request.getIds(); BusinessAssert.isTrue(CollectionUtils.isNotEmpty(ids), CommonErrorCode.PARAM_ERROR); @@ -231,6 +238,7 @@ public class KnowledgeItemApplicationService { @Transactional(readOnly = true) public KnowledgeItem getKnowledgeItem(String setId, String itemId) { + requireAccessibleKnowledgeSet(setId); KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, DataManagementErrorCode.KNOWLEDGE_ITEM_NOT_FOUND); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); @@ -239,6 +247,7 @@ public class KnowledgeItemApplicationService { @Transactional(readOnly = true) public PagedResponse getKnowledgeItems(String setId, KnowledgeItemPagingQuery query) { + requireAccessibleKnowledgeSet(setId); query.setSetId(setId); IPage page = new Page<>(query.getPage(), query.getSize()); page = knowledgeItemRepository.findByCriteria(page, query); @@ -248,19 +257,52 @@ public class KnowledgeItemApplicationService { @Transactional(readOnly = true) public KnowledgeManagementStatisticsResponse getKnowledgeManagementStatistics() { + boolean excludeConfidential = !resourceAccessService.canViewConfidential(); + String ownerFilterUserId = resourceAccessService.resolveOwnerFilterUserId(); + KnowledgeSetPagingQuery baseQuery = new KnowledgeSetPagingQuery(); KnowledgeManagementStatisticsResponse response = new KnowledgeManagementStatisticsResponse(); - response.setTotalKnowledgeSets(knowledgeSetRepository.count()); - long totalFiles = knowledgeItemRepository.countBySourceTypes(List.of( + long totalSets = knowledgeSetRepository.countByCriteria(baseQuery, ownerFilterUserId, excludeConfidential); + response.setTotalKnowledgeSets(totalSets); + + List accessibleSetIds = knowledgeSetRepository.listSetIdsByCriteria(baseQuery, ownerFilterUserId, excludeConfidential); + List accessibleSets = knowledgeSetRepository.listByIds(accessibleSetIds); + if (CollectionUtils.isEmpty(accessibleSets)) { + response.setTotalFiles(0L); + response.setTotalSize(0L); + response.setTotalTags(0L); + return response; + } + + List normalizedSetIds = accessibleSets.stream() + .map(KnowledgeSet::getId) + .filter(StringUtils::isNotBlank) + .toList(); + if (CollectionUtils.isEmpty(normalizedSetIds)) { + response.setTotalFiles(0L); + response.setTotalSize(0L); + response.setTotalTags(0L); + return response; + } + + long totalFiles = knowledgeItemRepository.countBySourceTypesAndSetIds(List.of( KnowledgeSourceType.DATASET_FILE, KnowledgeSourceType.FILE_UPLOAD - )); + ), normalizedSetIds); response.setTotalFiles(totalFiles); - long datasetFileSize = safeLong(knowledgeItemRepository.sumDatasetFileSize()); - long uploadFileSize = calculateUploadFileTotalSize(); + long datasetFileSize = safeLong(knowledgeItemRepository.sumDatasetFileSizeBySetIds(normalizedSetIds)); + long uploadFileSize = calculateUploadFileTotalSize(normalizedSetIds); response.setTotalSize(datasetFileSize + uploadFileSize); - response.setTotalTags(safeLong(tagMapper.countKnowledgeSetTags())); + + long totalTags = accessibleSets.stream() + .filter(Objects::nonNull) + .flatMap(set -> CollectionUtils.isEmpty(set.getTags()) ? Collections.emptyList().stream() : set.getTags().stream()) + .map(tag -> StringUtils.trimToNull(tag == null ? null : tag.getName())) + .filter(Objects::nonNull) + .collect(Collectors.toCollection(HashSet::new)) + .size(); + response.setTotalTags(totalTags); return response; } @@ -271,8 +313,9 @@ public class KnowledgeItemApplicationService { String keyword = StringUtils.trimToEmpty(query.getKeyword()); BusinessAssert.isTrue(StringUtils.isNotBlank(keyword), CommonErrorCode.PARAM_ERROR); + boolean excludeConfidential = !resourceAccessService.canViewConfidential(); IPage page = new Page<>(query.getPage(), query.getSize()); - IPage result = knowledgeItemRepository.searchFileItems(page, keyword); + IPage result = knowledgeItemRepository.searchFileItems(page, keyword, excludeConfidential); List responses = result.getRecords() .stream() .map(this::normalizeSearchResponse) @@ -281,7 +324,7 @@ public class KnowledgeItemApplicationService { } public List importKnowledgeItems(String setId, ImportKnowledgeItemsRequest request) { - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); BusinessAssert.isTrue(!isReadOnlyStatus(knowledgeSet.getStatus()), DataManagementErrorCode.KNOWLEDGE_SET_STATUS_ERROR); Dataset dataset = datasetRepository.getById(request.getDatasetId()); @@ -318,7 +361,7 @@ public class KnowledgeItemApplicationService { @Transactional(readOnly = true) public void exportKnowledgeItems(String setId, HttpServletResponse response) { BusinessAssert.notNull(response, CommonErrorCode.PARAM_ERROR); - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); List items = knowledgeItemRepository.findAllBySetId(setId); response.setContentType(EXPORT_CONTENT_TYPE); @@ -347,6 +390,7 @@ public class KnowledgeItemApplicationService { @Transactional(readOnly = true) public void downloadKnowledgeItemFile(String setId, String itemId, HttpServletResponse response) { BusinessAssert.notNull(response, CommonErrorCode.PARAM_ERROR); + requireAccessibleKnowledgeSet(setId); KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, DataManagementErrorCode.KNOWLEDGE_ITEM_NOT_FOUND); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); @@ -380,6 +424,7 @@ public class KnowledgeItemApplicationService { @Transactional(readOnly = true) public void previewKnowledgeItemFile(String setId, String itemId, HttpServletResponse response) { BusinessAssert.notNull(response, CommonErrorCode.PARAM_ERROR); + requireAccessibleKnowledgeSet(setId); KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, DataManagementErrorCode.KNOWLEDGE_ITEM_NOT_FOUND); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); @@ -441,7 +486,7 @@ public class KnowledgeItemApplicationService { } public KnowledgeItem replaceKnowledgeItemFile(String setId, String itemId, ReplaceKnowledgeItemFileRequest request) { - KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + KnowledgeSet knowledgeSet = requireAccessibleKnowledgeSet(setId); KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, DataManagementErrorCode.KNOWLEDGE_ITEM_NOT_FOUND); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); @@ -655,8 +700,8 @@ public class KnowledgeItemApplicationService { return item; } - private long calculateUploadFileTotalSize() { - List items = knowledgeItemRepository.findFileUploadItems(); + private long calculateUploadFileTotalSize(List setIds) { + List items = knowledgeItemRepository.findFileUploadItemsBySetIds(setIds); if (CollectionUtils.isEmpty(items)) { return 0L; } @@ -846,6 +891,18 @@ public class KnowledgeItemApplicationService { return knowledgeSet; } + /** + * 校验当前用户是否可访问指定知识集(含保密权限检查) + */ + private KnowledgeSet requireAccessibleKnowledgeSet(String setId) { + KnowledgeSet knowledgeSet = requireKnowledgeSet(setId); + if (ResourceAccessService.CONFIDENTIAL_SENSITIVITY.equalsIgnoreCase(knowledgeSet.getSensitivity())) { + BusinessAssert.isTrue(resourceAccessService.canViewConfidential(), + SystemErrorCode.INSUFFICIENT_PERMISSIONS); + } + return knowledgeSet; + } + private String buildExportFileName(String setId) { return EXPORT_FILE_PREFIX + setId + "_" + LocalDateTime.now().format(EXPORT_TIME_FORMATTER) + EXPORT_FILE_SUFFIX; } diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewService.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewService.java index 94c9d92..7589016 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewService.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewService.java @@ -1,13 +1,17 @@ package com.datamate.datamanagement.application; +import com.datamate.common.auth.application.ResourceAccessService; import com.datamate.common.infrastructure.exception.BusinessAssert; import com.datamate.common.infrastructure.exception.CommonErrorCode; +import com.datamate.common.infrastructure.exception.SystemErrorCode; import com.datamate.datamanagement.common.enums.KnowledgeContentType; import com.datamate.datamanagement.common.enums.KnowledgeItemPreviewStatus; import com.datamate.datamanagement.common.enums.KnowledgeSourceType; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeItem; +import com.datamate.datamanagement.domain.model.knowledge.KnowledgeSet; import com.datamate.datamanagement.infrastructure.config.DataManagementProperties; import com.datamate.datamanagement.infrastructure.persistence.repository.KnowledgeItemRepository; +import com.datamate.datamanagement.infrastructure.persistence.repository.KnowledgeSetRepository; import com.datamate.datamanagement.interfaces.dto.KnowledgeItemPreviewStatusResponse; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; @@ -38,8 +42,10 @@ public class KnowledgeItemPreviewService { private static final DateTimeFormatter PREVIEW_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; private final KnowledgeItemRepository knowledgeItemRepository; + private final KnowledgeSetRepository knowledgeSetRepository; private final DataManagementProperties dataManagementProperties; private final KnowledgeItemPreviewAsyncService knowledgeItemPreviewAsyncService; + private final ResourceAccessService resourceAccessService; private final ObjectMapper objectMapper = new ObjectMapper(); public KnowledgeItemPreviewStatusResponse getPreviewStatus(String setId, String itemId) { @@ -138,6 +144,14 @@ public class KnowledgeItemPreviewService { private KnowledgeItem requireKnowledgeItem(String setId, String itemId) { BusinessAssert.isTrue(StringUtils.isNotBlank(setId), CommonErrorCode.PARAM_ERROR); BusinessAssert.isTrue(StringUtils.isNotBlank(itemId), CommonErrorCode.PARAM_ERROR); + + KnowledgeSet knowledgeSet = knowledgeSetRepository.getById(setId); + BusinessAssert.notNull(knowledgeSet, CommonErrorCode.PARAM_ERROR); + if (ResourceAccessService.CONFIDENTIAL_SENSITIVITY.equalsIgnoreCase(knowledgeSet.getSensitivity())) { + BusinessAssert.isTrue(resourceAccessService.canViewConfidential(), + SystemErrorCode.INSUFFICIENT_PERMISSIONS); + } + KnowledgeItem knowledgeItem = knowledgeItemRepository.getById(itemId); BusinessAssert.notNull(knowledgeItem, CommonErrorCode.PARAM_ERROR); BusinessAssert.isTrue(Objects.equals(knowledgeItem.getSetId(), setId), CommonErrorCode.PARAM_ERROR); diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeSetApplicationService.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeSetApplicationService.java index 513ca9e..ff1257e 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeSetApplicationService.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeSetApplicationService.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.datamate.common.auth.application.ResourceAccessService; import com.datamate.common.infrastructure.exception.BusinessAssert; import com.datamate.common.infrastructure.exception.CommonErrorCode; +import com.datamate.common.infrastructure.exception.SystemErrorCode; import com.datamate.common.interfaces.PagedResponse; import com.datamate.datamanagement.common.enums.KnowledgeStatusType; import com.datamate.datamanagement.domain.model.dataset.Tag; @@ -46,9 +47,11 @@ public class KnowledgeSetApplicationService { public KnowledgeSet createKnowledgeSet(CreateKnowledgeSetRequest request) { BusinessAssert.isTrue(knowledgeSetRepository.findByName(request.getName()) == null, DataManagementErrorCode.KNOWLEDGE_SET_ALREADY_EXISTS); + assertCanUseSensitivity(request.getSensitivity()); KnowledgeSet knowledgeSet = KnowledgeConverter.INSTANCE.convertToKnowledgeSet(request); knowledgeSet.setId(UUID.randomUUID().toString()); + knowledgeSet.setSensitivity(normalizeSensitivity(knowledgeSet.getSensitivity())); if (knowledgeSet.getStatus() == null) { knowledgeSet.setStatus(KnowledgeStatusType.DRAFT); } @@ -67,6 +70,7 @@ public class KnowledgeSetApplicationService { KnowledgeSet knowledgeSet = knowledgeSetRepository.getById(setId); BusinessAssert.notNull(knowledgeSet, DataManagementErrorCode.KNOWLEDGE_SET_NOT_FOUND); resourceAccessService.assertOwnerAccess(knowledgeSet.getCreatedBy()); + assertConfidentialAccess(knowledgeSet); BusinessAssert.isTrue(!isReadOnlyStatus(knowledgeSet.getStatus()), DataManagementErrorCode.KNOWLEDGE_SET_STATUS_ERROR); @@ -106,7 +110,8 @@ public class KnowledgeSetApplicationService { knowledgeSet.setSourceType(request.getSourceType()); } if (request.getSensitivity() != null) { - knowledgeSet.setSensitivity(request.getSensitivity()); + assertCanUseSensitivity(request.getSensitivity()); + knowledgeSet.setSensitivity(normalizeSensitivity(request.getSensitivity())); } if (request.getMetadata() != null) { knowledgeSet.setMetadata(request.getMetadata()); @@ -123,6 +128,7 @@ public class KnowledgeSetApplicationService { KnowledgeSet knowledgeSet = knowledgeSetRepository.getById(setId); BusinessAssert.notNull(knowledgeSet, DataManagementErrorCode.KNOWLEDGE_SET_NOT_FOUND); resourceAccessService.assertOwnerAccess(knowledgeSet.getCreatedBy()); + assertConfidentialAccess(knowledgeSet); knowledgeSetRepository.removeById(setId); } @@ -131,6 +137,7 @@ public class KnowledgeSetApplicationService { KnowledgeSet knowledgeSet = knowledgeSetRepository.getById(setId); BusinessAssert.notNull(knowledgeSet, DataManagementErrorCode.KNOWLEDGE_SET_NOT_FOUND); resourceAccessService.assertOwnerAccess(knowledgeSet.getCreatedBy()); + assertConfidentialAccess(knowledgeSet); return knowledgeSet; } @@ -138,11 +145,33 @@ public class KnowledgeSetApplicationService { public PagedResponse getKnowledgeSets(KnowledgeSetPagingQuery query) { IPage page = new Page<>(query.getPage(), query.getSize()); String ownerFilterUserId = resourceAccessService.resolveOwnerFilterUserId(); - page = knowledgeSetRepository.findByCriteria(page, query, ownerFilterUserId); + boolean excludeConfidential = !resourceAccessService.canViewConfidential(); + page = knowledgeSetRepository.findByCriteria(page, query, ownerFilterUserId, excludeConfidential); List responses = KnowledgeConverter.INSTANCE.convertSetResponses(page.getRecords()); return PagedResponse.of(responses, page.getCurrent(), page.getTotal(), page.getPages()); } + private void assertConfidentialAccess(KnowledgeSet knowledgeSet) { + if (ResourceAccessService.CONFIDENTIAL_SENSITIVITY.equalsIgnoreCase(knowledgeSet.getSensitivity())) { + BusinessAssert.isTrue(resourceAccessService.canViewConfidential(), + SystemErrorCode.INSUFFICIENT_PERMISSIONS); + } + } + + private void assertCanUseSensitivity(String sensitivity) { + if (ResourceAccessService.CONFIDENTIAL_SENSITIVITY.equalsIgnoreCase(sensitivity)) { + BusinessAssert.isTrue(resourceAccessService.canViewConfidential(), + SystemErrorCode.INSUFFICIENT_PERMISSIONS); + } + } + + private String normalizeSensitivity(String sensitivity) { + if (!StringUtils.hasText(sensitivity)) { + return null; + } + return sensitivity.trim().toUpperCase(); + } + private boolean isReadOnlyStatus(KnowledgeStatusType status) { return status == KnowledgeStatusType.ARCHIVED || status == KnowledgeStatusType.DEPRECATED; } diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/mapper/KnowledgeItemMapper.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/mapper/KnowledgeItemMapper.java index 64972a8..0778274 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/mapper/KnowledgeItemMapper.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/mapper/KnowledgeItemMapper.java @@ -8,9 +8,12 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; +import java.util.List; + @Mapper public interface KnowledgeItemMapper extends BaseMapper { @Select(""" + """) - IPage searchFileItems(IPage page, @Param("keyword") String keyword); + IPage searchFileItems(IPage page, @Param("keyword") String keyword, + @Param("excludeConfidential") boolean excludeConfidential); @Select(""" + """) - Long sumDatasetFileSize(); + Long sumDatasetFileSizeBySetIds(@Param("setIds") List setIds); } diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeItemRepository.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeItemRepository.java index 6acad30..9dd36be 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeItemRepository.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeItemRepository.java @@ -2,11 +2,11 @@ package com.datamate.datamanagement.infrastructure.persistence.repository; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.repository.IRepository; -import com.baomidou.mybatisplus.core.metadata.IPage; import com.datamate.datamanagement.common.enums.KnowledgeSourceType; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeItem; import com.datamate.datamanagement.interfaces.dto.KnowledgeItemPagingQuery; import com.datamate.datamanagement.interfaces.dto.KnowledgeItemSearchResponse; + import java.util.List; /** @@ -19,13 +19,13 @@ public interface KnowledgeItemRepository extends IRepository { List findAllBySetId(String setId); - long countBySourceTypes(List sourceTypes); + long countBySourceTypesAndSetIds(List sourceTypes, List setIds); - List findFileUploadItems(); + List findFileUploadItemsBySetIds(List setIds); - IPage searchFileItems(IPage page, String keyword); + IPage searchFileItems(IPage page, String keyword, boolean excludeConfidential); - Long sumDatasetFileSize(); + Long sumDatasetFileSizeBySetIds(List setIds); boolean existsBySetIdAndRelativePath(String setId, String relativePath); diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeSetRepository.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeSetRepository.java index 4de8314..f650997 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeSetRepository.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/KnowledgeSetRepository.java @@ -5,11 +5,18 @@ import com.baomidou.mybatisplus.extension.repository.IRepository; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeSet; import com.datamate.datamanagement.interfaces.dto.KnowledgeSetPagingQuery; +import java.util.List; + /** * 知识集仓储接口 */ public interface KnowledgeSetRepository extends IRepository { KnowledgeSet findByName(String name); - IPage findByCriteria(IPage page, KnowledgeSetPagingQuery query, String createdBy); + IPage findByCriteria(IPage page, KnowledgeSetPagingQuery query, String createdBy, + boolean excludeConfidential); + + long countByCriteria(KnowledgeSetPagingQuery query, String createdBy, boolean excludeConfidential); + + List listSetIdsByCriteria(KnowledgeSetPagingQuery query, String createdBy, boolean excludeConfidential); } diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeItemRepositoryImpl.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeItemRepositoryImpl.java index e3aebbd..5dec7f0 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeItemRepositoryImpl.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeItemRepositoryImpl.java @@ -61,26 +61,37 @@ public class KnowledgeItemRepositoryImpl extends CrudRepository sourceTypes) { + public long countBySourceTypesAndSetIds(List sourceTypes, List setIds) { + if (sourceTypes == null || sourceTypes.isEmpty() || setIds == null || setIds.isEmpty()) { + return 0L; + } return knowledgeItemMapper.selectCount(new LambdaQueryWrapper() - .in(KnowledgeItem::getSourceType, sourceTypes)); + .in(KnowledgeItem::getSourceType, sourceTypes) + .in(KnowledgeItem::getSetId, setIds)); } @Override - public List findFileUploadItems() { + public List findFileUploadItemsBySetIds(List setIds) { + if (setIds == null || setIds.isEmpty()) { + return List.of(); + } return knowledgeItemMapper.selectList(new LambdaQueryWrapper() .eq(KnowledgeItem::getSourceType, KnowledgeSourceType.FILE_UPLOAD) - .select(KnowledgeItem::getId, KnowledgeItem::getContent, KnowledgeItem::getSourceFileId)); + .in(KnowledgeItem::getSetId, setIds) + .select(KnowledgeItem::getId, KnowledgeItem::getSetId, KnowledgeItem::getContent, KnowledgeItem::getSourceFileId)); } @Override - public IPage searchFileItems(IPage page, String keyword) { - return knowledgeItemMapper.searchFileItems(page, keyword); + public IPage searchFileItems(IPage page, String keyword, boolean excludeConfidential) { + return knowledgeItemMapper.searchFileItems(page, keyword, excludeConfidential); } @Override - public Long sumDatasetFileSize() { - return knowledgeItemMapper.sumDatasetFileSize(); + public Long sumDatasetFileSizeBySetIds(List setIds) { + if (setIds == null || setIds.isEmpty()) { + return 0L; + } + return knowledgeItemMapper.sumDatasetFileSizeBySetIds(setIds); } @Override diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeSetRepositoryImpl.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeSetRepositoryImpl.java index fa37e43..b443cd5 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeSetRepositoryImpl.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/infrastructure/persistence/repository/impl/KnowledgeSetRepositoryImpl.java @@ -3,6 +3,7 @@ package com.datamate.datamanagement.infrastructure.persistence.repository.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.repository.CrudRepository; +import com.datamate.common.auth.application.ResourceAccessService; import com.datamate.datamanagement.domain.model.knowledge.KnowledgeSet; import com.datamate.datamanagement.infrastructure.persistence.mapper.KnowledgeSetMapper; import com.datamate.datamanagement.infrastructure.persistence.repository.KnowledgeSetRepository; @@ -11,6 +12,9 @@ import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Repository; +import java.util.Collections; +import java.util.List; + /** * 知识集仓储实现类 */ @@ -25,25 +29,62 @@ public class KnowledgeSetRepositoryImpl extends CrudRepository findByCriteria(IPage page, KnowledgeSetPagingQuery query, String createdBy) { + public IPage findByCriteria(IPage page, KnowledgeSetPagingQuery query, String createdBy, + boolean excludeConfidential) { + LambdaQueryWrapper wrapper = buildCriteriaWrapper(query, createdBy, excludeConfidential); + wrapper.orderByDesc(KnowledgeSet::getCreatedAt); + return knowledgeSetMapper.selectPage(page, wrapper); + } + + @Override + public long countByCriteria(KnowledgeSetPagingQuery query, String createdBy, boolean excludeConfidential) { + return knowledgeSetMapper.selectCount(buildCriteriaWrapper(query, createdBy, excludeConfidential)); + } + + @Override + public List listSetIdsByCriteria(KnowledgeSetPagingQuery query, String createdBy, boolean excludeConfidential) { + LambdaQueryWrapper wrapper = buildCriteriaWrapper(query, createdBy, excludeConfidential) + .select(KnowledgeSet::getId) + .orderByDesc(KnowledgeSet::getCreatedAt); + List sets = knowledgeSetMapper.selectList(wrapper); + if (sets == null || sets.isEmpty()) { + return Collections.emptyList(); + } + return sets.stream().map(KnowledgeSet::getId).filter(StringUtils::isNotBlank).toList(); + } + + private LambdaQueryWrapper buildCriteriaWrapper(KnowledgeSetPagingQuery query, + String createdBy, + boolean excludeConfidential) { + KnowledgeSetPagingQuery safeQuery = query == null ? new KnowledgeSetPagingQuery() : query; + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() - .eq(query.getStatus() != null, KnowledgeSet::getStatus, query.getStatus()) - .eq(StringUtils.isNotBlank(query.getDomain()), KnowledgeSet::getDomain, query.getDomain()) - .eq(StringUtils.isNotBlank(query.getBusinessLine()), KnowledgeSet::getBusinessLine, query.getBusinessLine()) - .eq(StringUtils.isNotBlank(query.getOwner()), KnowledgeSet::getOwner, query.getOwner()) - .eq(StringUtils.isNotBlank(query.getSensitivity()), KnowledgeSet::getSensitivity, query.getSensitivity()) - .eq(query.getSourceType() != null, KnowledgeSet::getSourceType, query.getSourceType()) - .ge(query.getValidFrom() != null, KnowledgeSet::getValidFrom, query.getValidFrom()) - .le(query.getValidTo() != null, KnowledgeSet::getValidTo, query.getValidTo()) + .eq(safeQuery.getStatus() != null, KnowledgeSet::getStatus, safeQuery.getStatus()) + .eq(StringUtils.isNotBlank(safeQuery.getDomain()), KnowledgeSet::getDomain, safeQuery.getDomain()) + .eq(StringUtils.isNotBlank(safeQuery.getBusinessLine()), KnowledgeSet::getBusinessLine, safeQuery.getBusinessLine()) + .eq(StringUtils.isNotBlank(safeQuery.getOwner()), KnowledgeSet::getOwner, safeQuery.getOwner()) + .eq(safeQuery.getSourceType() != null, KnowledgeSet::getSourceType, safeQuery.getSourceType()) + .ge(safeQuery.getValidFrom() != null, KnowledgeSet::getValidFrom, safeQuery.getValidFrom()) + .le(safeQuery.getValidTo() != null, KnowledgeSet::getValidTo, safeQuery.getValidTo()) .eq(StringUtils.isNotBlank(createdBy), KnowledgeSet::getCreatedBy, createdBy); - if (StringUtils.isNotBlank(query.getKeyword())) { - wrapper.and(w -> w.like(KnowledgeSet::getName, query.getKeyword()) - .or() - .like(KnowledgeSet::getDescription, query.getKeyword())); + if (queryHasSensitivity(safeQuery)) { + wrapper.apply("UPPER(TRIM(sensitivity)) = {0}", normalizeSensitivity(safeQuery.getSensitivity())); } - for (String tagName : query.getTags()) { + if (excludeConfidential) { + wrapper.and(w -> w.isNull(KnowledgeSet::getSensitivity) + .or() + .apply("UPPER(TRIM(sensitivity)) != {0}", ResourceAccessService.CONFIDENTIAL_SENSITIVITY)); + } + + if (StringUtils.isNotBlank(safeQuery.getKeyword())) { + wrapper.and(w -> w.like(KnowledgeSet::getName, safeQuery.getKeyword()) + .or() + .like(KnowledgeSet::getDescription, safeQuery.getKeyword())); + } + + for (String tagName : safeQuery.getTags()) { wrapper.and(w -> w.apply("tags IS NOT NULL " + "AND JSON_VALID(tags) = 1 " + @@ -52,7 +93,15 @@ public class KnowledgeSetRepositoryImpl extends CrudRepository roles; + private final List permissions; - private RequestUserContext(String userId, String username, List roles) { + private RequestUserContext(String userId, String username, List roles, List permissions) { this.userId = userId; this.username = username; this.roles = roles == null ? Collections.emptyList() : List.copyOf(roles); + this.permissions = permissions == null ? Collections.emptyList() : List.copyOf(permissions); } - public static RequestUserContext of(String userId, String username, List roles) { - return new RequestUserContext(userId, username, roles); + public static RequestUserContext of(String userId, String username, List roles, List permissions) { + return new RequestUserContext(userId, username, roles, permissions); } public static RequestUserContext empty() { - return new RequestUserContext(null, null, Collections.emptyList()); + return new RequestUserContext(null, null, Collections.emptyList(), Collections.emptyList()); } public boolean hasRole(String roleCode) { @@ -36,5 +38,12 @@ public class RequestUserContext { } return roles.stream().anyMatch(role -> StringUtils.hasText(role) && Objects.equals(role.trim(), roleCode)); } + + public boolean hasPermission(String permissionCode) { + if (!StringUtils.hasText(permissionCode)) { + return false; + } + return permissions.stream().anyMatch(p -> StringUtils.hasText(p) && Objects.equals(p.trim(), permissionCode)); + } } diff --git a/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextHolder.java b/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextHolder.java index 2276553..c0bc6ee 100644 --- a/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextHolder.java +++ b/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextHolder.java @@ -42,6 +42,19 @@ public final class RequestUserContextHolder { .anyMatch(role -> StringUtils.hasText(role) && roleCode.equalsIgnoreCase(role.trim())); } + public static List getCurrentPermissions() { + List permissions = get().getPermissions(); + return permissions == null ? Collections.emptyList() : permissions; + } + + public static boolean hasPermission(String permissionCode) { + if (!StringUtils.hasText(permissionCode)) { + return false; + } + return getCurrentPermissions().stream() + .anyMatch(p -> StringUtils.hasText(p) && permissionCode.equals(p.trim())); + } + public static void clear() { USER_CONTEXT_HOLDER.remove(); } diff --git a/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextInterceptor.java b/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextInterceptor.java index aff3996..f187e8e 100644 --- a/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextInterceptor.java +++ b/backend/shared/domain-common/src/main/java/com/datamate/common/auth/infrastructure/context/RequestUserContextInterceptor.java @@ -18,13 +18,15 @@ public class RequestUserContextInterceptor implements HandlerInterceptor { private static final String HEADER_USER_ID = "X-User-Id"; private static final String HEADER_USER_NAME = "X-User-Name"; private static final String HEADER_USER_ROLES = "X-User-Roles"; + private static final String HEADER_USER_PERMISSIONS = "X-User-Permissions"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String userId = normalizeValue(request.getHeader(HEADER_USER_ID)); String username = normalizeValue(request.getHeader(HEADER_USER_NAME)); - List roleCodes = parseRoleCodes(request.getHeader(HEADER_USER_ROLES)); - RequestUserContextHolder.set(RequestUserContext.of(userId, username, roleCodes)); + List roleCodes = parseCommaSeparatedValues(request.getHeader(HEADER_USER_ROLES)); + List permissionCodes = parseCommaSeparatedValues(request.getHeader(HEADER_USER_PERMISSIONS)); + RequestUserContextHolder.set(RequestUserContext.of(userId, username, roleCodes, permissionCodes)); return true; } @@ -40,11 +42,11 @@ public class RequestUserContextInterceptor implements HandlerInterceptor { return value.trim(); } - private List parseRoleCodes(String roleHeader) { - if (!StringUtils.hasText(roleHeader)) { + private List parseCommaSeparatedValues(String header) { + if (!StringUtils.hasText(header)) { return Collections.emptyList(); } - return Arrays.stream(roleHeader.split(",")) + return Arrays.stream(header.split(",")) .map(String::trim) .filter(StringUtils::hasText) .toList(); diff --git a/frontend/src/pages/KnowledgeManagement/Home/KnowledgeManagementPage.tsx b/frontend/src/pages/KnowledgeManagement/Home/KnowledgeManagementPage.tsx index 143d7d0..0eee39e 100644 --- a/frontend/src/pages/KnowledgeManagement/Home/KnowledgeManagementPage.tsx +++ b/frontend/src/pages/KnowledgeManagement/Home/KnowledgeManagementPage.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { Card, Button, Table, Tooltip, Tag, App, Statistic } from "antd"; -import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; +import { DeleteOutlined, EditOutlined, LockOutlined } from "@ant-design/icons"; import { useNavigate } from "react-router"; import CardView from "@/components/CardView"; import { SearchControls } from "@/components/SearchControls"; @@ -15,8 +15,14 @@ import { knowledgeStatusOptions, mapKnowledgeSet, KnowledgeSetView, + sensitivityMap, + sensitivityOptions, } from "../knowledge-management.const"; -import { KnowledgeManagementStatistics, KnowledgeSet } from "../knowledge-management.model"; +import { + KnowledgeManagementStatistics, + KnowledgeSensitivityType, + KnowledgeSet, +} from "../knowledge-management.model"; import CreateKnowledgeSet from "../components/CreateKnowledgeSet"; import { createDatasetTagUsingPost, @@ -76,6 +82,11 @@ export default function KnowledgeManagementPage() { label: "状态", options: knowledgeStatusOptions, }, + { + key: "sensitivity", + label: "敏感级别", + options: sensitivityOptions, + }, { key: "tags", label: "标签", @@ -101,7 +112,16 @@ export default function KnowledgeManagementPage() { 30000, false, [], - 0 + 0, + (filters) => { + const sensitivity = Array.isArray(filters?.sensitivity) + ? (filters.sensitivity[0] as string | undefined) + : undefined; + if (!sensitivity || sensitivity === "all") { + return {}; + } + return { sensitivity: sensitivity.toUpperCase() }; + } ); const fetchStatistics = useCallback(async () => { @@ -204,6 +224,25 @@ export default function KnowledgeManagementPage() { {status?.label} ), }, + { + title: "敏感级别", + dataIndex: "sensitivity", + key: "sensitivity", + width: 100, + render: (sensitivity: string) => { + const normalized = sensitivity ? sensitivity.toUpperCase() : ""; + const meta = normalized ? sensitivityMap[normalized] : null; + if (!meta) return "-"; + return ( + : undefined} + > + {meta.label} + + ); + }, + }, { title: "领域", dataIndex: "domain", diff --git a/frontend/src/pages/KnowledgeManagement/components/CreateKnowledgeSet.tsx b/frontend/src/pages/KnowledgeManagement/components/CreateKnowledgeSet.tsx index 1b7dbf4..9057585 100644 --- a/frontend/src/pages/KnowledgeManagement/components/CreateKnowledgeSet.tsx +++ b/frontend/src/pages/KnowledgeManagement/components/CreateKnowledgeSet.tsx @@ -9,10 +9,11 @@ import { import { knowledgeSourceTypeOptions, knowledgeStatusOptions, - // sensitivityOptions, + sensitivityOptions, } from "../knowledge-management.const"; import { KnowledgeSet, + KnowledgeSensitivityType, KnowledgeStatusType, } from "../knowledge-management.model"; import { queryDatasetTagsUsingGet } from "@/pages/DataManagement/dataset.api"; @@ -65,7 +66,7 @@ export default function CreateKnowledgeSet({ validFrom: data.validFrom ? dayjs(data.validFrom) : null, validTo: data.validTo ? dayjs(data.validTo) : null, sourceType: data.sourceType, - sensitivity: data.sensitivity, + sensitivity: data.sensitivity?.toUpperCase() || undefined, tags: data.tags?.map((tag) => tag.name) || [], metadata: data.metadata, }); @@ -85,6 +86,9 @@ export default function CreateKnowledgeSet({ const payload = { ...values, + sensitivity: values.sensitivity + ? String(values.sensitivity).toUpperCase() + : undefined, validFrom, validTo, tags: values.tags || [], @@ -124,7 +128,11 @@ export default function CreateKnowledgeSet({ icon={} onClick={() => { form.resetFields(); - form.setFieldsValue({ status: KnowledgeStatusType.DRAFT, tags: [] }); + form.setFieldsValue({ + status: KnowledgeStatusType.DRAFT, + sensitivity: KnowledgeSensitivityType.INTERNAL, + tags: [], + }); setOpen(true); }} > @@ -170,9 +178,9 @@ export default function CreateKnowledgeSet({ - {/* - +
diff --git a/frontend/src/pages/KnowledgeManagement/knowledge-management.const.tsx b/frontend/src/pages/KnowledgeManagement/knowledge-management.const.tsx index f1ca99e..0236b2b 100644 --- a/frontend/src/pages/KnowledgeManagement/knowledge-management.const.tsx +++ b/frontend/src/pages/KnowledgeManagement/knowledge-management.const.tsx @@ -11,6 +11,7 @@ import { KnowledgeContentType, KnowledgeItem, KnowledgeSet, + KnowledgeSensitivityType, KnowledgeSourceType, KnowledgeStatusType, } from "./knowledge-management.model"; @@ -66,10 +67,22 @@ export const knowledgeSourceTypeOptions = [ { label: "文件上传", value: KnowledgeSourceType.FILE_UPLOAD }, ]; -// export const sensitivityOptions = [ -// { label: "敏感", value: "敏感" }, -// { label: "不敏感", value: "不敏感" }, -// ]; +export const sensitivityOptions = [ + { label: "公开", value: KnowledgeSensitivityType.PUBLIC }, + { label: "内部", value: KnowledgeSensitivityType.INTERNAL }, + { label: "保密", value: KnowledgeSensitivityType.CONFIDENTIAL }, +]; + +export type SensitivityMeta = { + label: string; + color: string; +}; + +export const sensitivityMap: Record = { + [KnowledgeSensitivityType.PUBLIC]: { label: "公开", color: "#52c41a" }, + [KnowledgeSensitivityType.INTERNAL]: { label: "内部", color: "#1677ff" }, + [KnowledgeSensitivityType.CONFIDENTIAL]: { label: "保密", color: "#f5222d" }, +}; export type KnowledgeSetView = { id: string; @@ -118,6 +131,7 @@ export type KnowledgeItemView = { }; export function mapKnowledgeSet(data: KnowledgeSet): KnowledgeSetView { + const normalizedSensitivity = data.sensitivity?.toUpperCase(); return { id: data.id, name: data.name, @@ -131,7 +145,7 @@ export function mapKnowledgeSet(data: KnowledgeSet): KnowledgeSetView { validFrom: data.validFrom, validTo: data.validTo, sourceType: data.sourceType, - sensitivity: data.sensitivity, + sensitivity: normalizedSensitivity, metadata: data.metadata, createdAt: data.createdAt ? formatDateTime(data.createdAt) : "", updatedAt: data.updatedAt ? formatDateTime(data.updatedAt) : "", @@ -142,6 +156,7 @@ export function mapKnowledgeSet(data: KnowledgeSet): KnowledgeSetView { } export function mapKnowledgeItem(data: KnowledgeItem): KnowledgeItemView { + const normalizedSensitivity = data.sensitivity?.toUpperCase(); return { id: data.id, setId: data.setId, @@ -156,7 +171,7 @@ export function mapKnowledgeItem(data: KnowledgeItem): KnowledgeItemView { validFrom: data.validFrom, validTo: data.validTo, sourceType: data.sourceType, - sensitivity: data.sensitivity, + sensitivity: normalizedSensitivity, sourceDatasetId: data.sourceDatasetId, sourceFileId: data.sourceFileId, relativePath: data.relativePath, diff --git a/frontend/src/pages/KnowledgeManagement/knowledge-management.model.ts b/frontend/src/pages/KnowledgeManagement/knowledge-management.model.ts index a870024..effc3b7 100644 --- a/frontend/src/pages/KnowledgeManagement/knowledge-management.model.ts +++ b/frontend/src/pages/KnowledgeManagement/knowledge-management.model.ts @@ -17,6 +17,12 @@ export enum KnowledgeSourceType { FILE_UPLOAD = "FILE_UPLOAD", } +export enum KnowledgeSensitivityType { + PUBLIC = "PUBLIC", + INTERNAL = "INTERNAL", + CONFIDENTIAL = "CONFIDENTIAL", +} + export interface KnowledgeTag { id: string; name: string; diff --git a/scripts/db/zz-auth-init.sql b/scripts/db/zz-auth-init.sql index be50058..0322a2c 100644 --- a/scripts/db/zz-auth-init.sql +++ b/scripts/db/zz-auth-init.sql @@ -99,7 +99,8 @@ VALUES ('perm-dm-read', 'module:data-management:read', '数据管理读取', 'da ('perm-content-use', 'module:content-generation:use', '内容生成功能使用', 'content-generation', 'use', '/api/content-generation/**', 'POST,PUT,PATCH', 1, 1), ('perm-user-manage', 'system:user:manage', '用户管理', 'system', 'manage-user', '/api/auth/users/**', 'GET,POST,PUT,PATCH,DELETE', 1, 1), ('perm-role-manage', 'system:role:manage', '角色管理', 'system', 'manage-role', '/api/auth/roles/**', 'GET,POST,PUT,PATCH,DELETE', 1, 1), - ('perm-perm-manage', 'system:permission:manage', '权限管理', 'system', 'manage-permission', '/api/auth/permissions/**', 'GET,POST,PUT,PATCH,DELETE', 1, 1); + ('perm-perm-manage', 'system:permission:manage', '权限管理', 'system', 'manage-permission', '/api/auth/permissions/**', 'GET,POST,PUT,PATCH,DELETE', 1, 1), + ('perm-km-view-confidential', 'knowledge:view-confidential', '允许查看保密知识', 'knowledge-management', 'view-confidential', '', '', 1, 1); -- 管理员拥有所有权限 INSERT IGNORE INTO t_auth_role_permissions (role_id, permission_id)