From 97ae4e012bc949cc7db2d43901ad73ec8246f47b Mon Sep 17 00:00:00 2001 From: shaohuzhang1 <80892890+shaohuzhang1@users.noreply.github.com> Date: Fri, 26 Dec 2025 14:29:43 +0800 Subject: [PATCH] feat: Retrieve the pagination list of resource relationships (#4570) --- apps/locales/en_US/LC_MESSAGES/django.po | 6 + apps/locales/zh_CN/LC_MESSAGES/django.po | 6 + apps/locales/zh_Hant/LC_MESSAGES/django.po | 6 + apps/system_manage/api/resource_mapping.py | 80 ++++++++++++ .../resource_mapping_serializers.py | 44 +++++++ .../sql/list_resource_mapping.sql | 12 ++ apps/system_manage/urls.py | 1 + apps/system_manage/views/__init__.py | 1 + apps/system_manage/views/resource_mapping.py | 37 ++++++ ui/src/api/workspace/resource-mapping.ts | 28 ++++ ui/src/components/resource_mapping/index.vue | 121 ++++++++++++++++++ ui/src/utils/dynamics-api/shared-api.ts | 3 + ui/src/views/model/component/ModelCard.vue | 21 ++- 13 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 apps/system_manage/api/resource_mapping.py create mode 100644 apps/system_manage/serializers/resource_mapping_serializers.py create mode 100644 apps/system_manage/sql/list_resource_mapping.sql create mode 100644 apps/system_manage/views/resource_mapping.py create mode 100644 ui/src/api/workspace/resource-mapping.ts create mode 100644 ui/src/components/resource_mapping/index.vue diff --git a/apps/locales/en_US/LC_MESSAGES/django.po b/apps/locales/en_US/LC_MESSAGES/django.po index 11347aacc..87ccbf363 100644 --- a/apps/locales/en_US/LC_MESSAGES/django.po +++ b/apps/locales/en_US/LC_MESSAGES/django.po @@ -8886,4 +8886,10 @@ msgid "Role IDs cannot be empty" msgstr "" msgid "Some roles do not exist" +msgstr "" + +msgid "Authorized pagination list for obtaining resources" +msgstr "" + +msgid "Resources mapping" msgstr "" \ No newline at end of file diff --git a/apps/locales/zh_CN/LC_MESSAGES/django.po b/apps/locales/zh_CN/LC_MESSAGES/django.po index 1f4e563e9..8dff225c8 100644 --- a/apps/locales/zh_CN/LC_MESSAGES/django.po +++ b/apps/locales/zh_CN/LC_MESSAGES/django.po @@ -9013,3 +9013,9 @@ msgstr "角色 ID 不能为空" msgid "Some roles do not exist" msgstr "部分角色不存在" + +msgid "Authorized pagination list for obtaining resources" +msgstr "获取资源的关系分页列表" + +msgid "Resources mapping" +msgstr "资源映射" \ No newline at end of file diff --git a/apps/locales/zh_Hant/LC_MESSAGES/django.po b/apps/locales/zh_Hant/LC_MESSAGES/django.po index fa0eb9148..4df8df837 100644 --- a/apps/locales/zh_Hant/LC_MESSAGES/django.po +++ b/apps/locales/zh_Hant/LC_MESSAGES/django.po @@ -9013,3 +9013,9 @@ msgstr "角色 ID 不能为空" msgid "Some roles do not exist" msgstr "部分角色不存在" + +msgid "Authorized pagination list for obtaining resources" +msgstr "獲取資源的關係分頁清單" + +msgid "Resources mapping" +msgstr "資源映射" \ No newline at end of file diff --git a/apps/system_manage/api/resource_mapping.py b/apps/system_manage/api/resource_mapping.py new file mode 100644 index 000000000..8539e099a --- /dev/null +++ b/apps/system_manage/api/resource_mapping.py @@ -0,0 +1,80 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎 + @file: resource_mapping.py + @date:2025/12/26 14:07 + @desc: +""" +from django.utils.translation import gettext_lazy as _ +from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import OpenApiParameter +from rest_framework import serializers + +from common.mixins.api_mixin import APIMixin + + +class ResourceMappingResponse(serializers.Serializer): + id = serializers.UUIDField(required=True, label="主键id") + target_id = serializers.CharField(required=True, label="被关联资源名称") + target_type = serializers.CharField(required=True, label="被关联资源类型") + source_id = serializers.CharField(required=True, label="关联资源Id") + source_type = serializers.CharField(required=True, label="关联资源类型") + name = serializers.CharField(required=True, label="名称") + desc = serializers.CharField(required=False, label="描述") + user_id = serializers.UUIDField(required=True, label="主键id") + + +class ResourceMappingAPI(APIMixin): + + @staticmethod + def get_parameters(): + return [ + OpenApiParameter( + name="workspace_id", + description="工作空间id", + type=OpenApiTypes.STR, + location='path', + required=True, + ), + OpenApiParameter( + name="source", + description="资源类型", + type=OpenApiTypes.STR, + location='path', + required=True, + ), + OpenApiParameter( + name="source_id", + description="资源id", + type=OpenApiTypes.STR, + location='path', + required=True, + ), + OpenApiParameter( + name="current_page", + description=_("Current page"), + type=OpenApiTypes.INT, + location='path', + required=True, + ), + OpenApiParameter( + name="page_size", + description=_("Page size"), + type=OpenApiTypes.INT, + location='path', + required=True, + ), + OpenApiParameter( + name="resource_name", + description="名称", + type=OpenApiTypes.STR, + location='query', + required=False + ), + + ] + + @staticmethod + def get_response(): + return ResourceMappingResponse(many=True) diff --git a/apps/system_manage/serializers/resource_mapping_serializers.py b/apps/system_manage/serializers/resource_mapping_serializers.py new file mode 100644 index 000000000..cdc2126bd --- /dev/null +++ b/apps/system_manage/serializers/resource_mapping_serializers.py @@ -0,0 +1,44 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎 + @file: workspace_user_resource_permission.py + @date:2025/4/28 17:17 + @desc: +""" +import os + +from django.db import models +from django.db.models import QuerySet +from django.utils.translation import gettext_lazy as _ +from rest_framework import serializers + +from common.db.search import native_page_search, get_dynamics_model +from common.utils.common import get_file_content +from maxkb.conf import PROJECT_DIR + + +class ResourceMappingSerializer(serializers.Serializer): + resource = serializers.CharField(required=True, label=_('resource')) + resource_id = serializers.UUIDField(required=True, label=_('resource Id')) + resource_name = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_('resource')) + + def get_query_set(self): + queryset = QuerySet(model=get_dynamics_model({ + 'name': models.CharField(), + 'target_id': models.CharField(), + "target_type": models.CharField() + })) + + queryset = queryset.filter(target_id=self.data.get('resource_id'), + target_type=self.data.get('resource')) + + if self.data.get('resource_name'): + queryset = queryset.filter(name__icontains=self.data.get('resource_name')) + + return queryset + + def page(self, current_page, page_size): + return native_page_search(current_page, page_size, self.get_query_set(), get_file_content( + os.path.join(PROJECT_DIR, "apps", "system_manage", + 'sql', 'list_resource_mapping.sql')), with_table_name=False) diff --git a/apps/system_manage/sql/list_resource_mapping.sql b/apps/system_manage/sql/list_resource_mapping.sql new file mode 100644 index 000000000..3c6a106e7 --- /dev/null +++ b/apps/system_manage/sql/list_resource_mapping.sql @@ -0,0 +1,12 @@ +WITH source_data_cte AS ( + SELECT 'APPLICATION' as source_type, id, "name", "desc","user_id" + FROM application + UNION ALL + SELECT 'KNOWLEDGE' as source_type, id, "name", "desc","user_id" + FROM knowledge) +SELECT rm.*, + sdc.* +FROM resource_mapping rm + LEFT JOIN source_data_cte sdc + ON rm.source_type = sdc.source_type + AND rm.source_id::uuid = sdc.id \ No newline at end of file diff --git a/apps/system_manage/urls.py b/apps/system_manage/urls.py index dfe873342..2938e6dbd 100644 --- a/apps/system_manage/urls.py +++ b/apps/system_manage/urls.py @@ -9,6 +9,7 @@ urlpatterns = [ path('workspace//user_resource_permission/user//resource///', views.WorkSpaceUserResourcePermissionView.Page.as_view()), path('workspace//resource_user_permission/resource//resource/', views.WorkspaceResourceUserPermissionView.as_view()), path('workspace//resource_user_permission/resource//resource///', views.WorkspaceResourceUserPermissionView.Page.as_view()), + path('workspace//resource_mapping////', views.ResourceMappingView.as_view()), path('email_setting', views.SystemSetting.Email.as_view()), path('profile', views.SystemProfile.as_view()), path('valid//', views.Valid.as_view()) diff --git a/apps/system_manage/views/__init__.py b/apps/system_manage/views/__init__.py index feb26cdba..b8af19c4b 100644 --- a/apps/system_manage/views/__init__.py +++ b/apps/system_manage/views/__init__.py @@ -10,3 +10,4 @@ from .user_resource_permission import * from .email_setting import * from .system_profile import * from .valid import * +from .resource_mapping import * diff --git a/apps/system_manage/views/resource_mapping.py b/apps/system_manage/views/resource_mapping.py new file mode 100644 index 000000000..a0aeb005a --- /dev/null +++ b/apps/system_manage/views/resource_mapping.py @@ -0,0 +1,37 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎虎 + @file: resource_mapping.py + @date:2025/12/25 15:28 + @desc: +""" + +from django.utils.translation import gettext_lazy as _ +from drf_spectacular.utils import extend_schema +from rest_framework.request import Request +from rest_framework.views import APIView + +from common import result +from common.auth import TokenAuth +from system_manage.api.resource_mapping import ResourceMappingAPI +from system_manage.serializers.resource_mapping_serializers import ResourceMappingSerializer + + +class ResourceMappingView(APIView): + authentication_classes = [TokenAuth] + + @extend_schema( + methods=['GET'], + description=_('Retrieve the pagination list of resource relationships'), + operation_id=_('Retrieve the pagination list of resource relationships'), # type: ignore + responses=ResourceMappingAPI.get_response(), + parameters=ResourceMappingAPI.get_parameters(), + tags=[_('Resources mapping')] # type: ignore + ) + def get(self, request: Request, workspace_id: str, resource: str, resource_id: str, current_page, page_size): + return result.success(ResourceMappingSerializer({ + 'resource': resource, + 'resource_id': resource_id, + 'resource_name': request.query_params.get('resource_name') + }).page(current_page, page_size)) diff --git a/ui/src/api/workspace/resource-mapping.ts b/ui/src/api/workspace/resource-mapping.ts new file mode 100644 index 000000000..aedd8965e --- /dev/null +++ b/ui/src/api/workspace/resource-mapping.ts @@ -0,0 +1,28 @@ +import { Result } from '@/request/Result' +import { get, put, post, del } from '@/request/index' +import type { Ref } from 'vue' +import type { pageRequest } from '@/api/type/common' +const prefix = '/workspace' + +/** + * 工作空间下各个资源的映射关系 + * @query 参数 + */ +const getResourceMapping: ( + workspace_id: string, + resource: string, + resource_id: string, + page: pageRequest, + params?: any, + loading?: Ref, +) => Promise> = (workspace_id, resource, resource_id, page, params, loading) => { + return get( + `${prefix}/${workspace_id}/resource_mapping/${resource}/${resource_id}/${page.current_page}/${page.page_size}`, + params, + loading, + ) +} + +export default { + getResourceMapping, +} diff --git a/ui/src/components/resource_mapping/index.vue b/ui/src/components/resource_mapping/index.vue new file mode 100644 index 000000000..08f8ad557 --- /dev/null +++ b/ui/src/components/resource_mapping/index.vue @@ -0,0 +1,121 @@ + + + diff --git a/ui/src/utils/dynamics-api/shared-api.ts b/ui/src/utils/dynamics-api/shared-api.ts index 3372a19b3..480def9dd 100644 --- a/ui/src/utils/dynamics-api/shared-api.ts +++ b/ui/src/utils/dynamics-api/shared-api.ts @@ -2,6 +2,7 @@ import knowledgeWorkspaceApi from '@/api/knowledge/knowledge' import documentWorkspaceApi from '@/api/knowledge/document' import paragraphWorkspaceApi from '@/api/knowledge/paragraph' import problemWorkspaceApi from '@/api/knowledge/problem' +import resourceMappingApi from '@/api/workspace/resource-mapping' import modelWorkspaceApi from '@/api/model/model' import toolWorkspaceApi from '@/api/tool/tool' import chatUserWorkspaceApi from '@/api/chat-user/chat-user' @@ -34,6 +35,7 @@ import workflowVersionResourceApi from '@/api/system-resource-management/workflo import chatLogResourceApi from '@/api/system-resource-management/chat-log' import resourceAuthorizationResourceApi from '@/api/system-resource-management/resource-authorization' import folderResourceApi from '@/api/system-resource-management/folder' + // 普通 API const workspaceApiMap = { knowledge: knowledgeWorkspaceApi, @@ -50,6 +52,7 @@ const workspaceApiMap = { chatLog: chatLogWorkspaceApi, resourceAuthorization: resourceAuthorizationWorkspaceApi, folder: folderWorkspaceApi, + resourceMapping: resourceMappingApi, } as any // 系统分享 API diff --git a/ui/src/views/model/component/ModelCard.vue b/ui/src/views/model/component/ModelCard.vue index 21a4d4eb4..8601991e6 100644 --- a/ui/src/views/model/component/ModelCard.vue +++ b/ui/src/views/model/component/ModelCard.vue @@ -104,10 +104,21 @@ {{ $t('views.model.modelForm.title.paramSetting') }} - + {{ $t('views.system.resourceAuthorization.title') }} + + + {{ $t('common.delete') }} + +