From 288aa2c29b597ec2d36d248cb9206607fa991676 Mon Sep 17 00:00:00 2001 From: zhangzhanwei Date: Fri, 27 Feb 2026 17:07:17 +0800 Subject: [PATCH] feat: Document List - Tag Optimization --- apps/knowledge/serializers/document.py | 18 ++ apps/knowledge/sql/list_document.sql | 27 ++- apps/knowledge/views/document.py | 4 + ui/src/locales/lang/en-US/views/document.ts | 1 + ui/src/locales/lang/zh-CN/views/document.ts | 1 + ui/src/locales/lang/zh-Hant/views/document.ts | 1 + ui/src/views/document/index.vue | 220 ++++++++++++------ ui/src/views/document/tag/MulAddTagDialog.vue | 9 +- ui/src/views/document/tag/TagDrawer.vue | 22 +- .../views/document/tag/TagSettingDrawer.vue | 3 + 10 files changed, 218 insertions(+), 88 deletions(-) diff --git a/apps/knowledge/serializers/document.py b/apps/knowledge/serializers/document.py index 540cf65c5ca..5aa7d806244 100644 --- a/apps/knowledge/serializers/document.py +++ b/apps/knowledge/serializers/document.py @@ -392,16 +392,34 @@ class Query(serializers.Serializer): status = serializers.CharField(required=False, label=_('status'), allow_null=True, allow_blank=True) order_by = serializers.CharField(required=False, label=_('order by'), allow_null=True, allow_blank=True) tag = serializers.CharField(required=False, label=_('tag'), allow_null=True, allow_blank=True) + tag_ids = serializers.ListField(child=serializers.UUIDField(),allow_null=True,required=False,allow_empty=True) + no_tag = serializers.BooleanField(required=False,default=False, allow_null=True) def get_query_set(self): query_set = QuerySet(model=Document) query_set = query_set.filter(**{'knowledge_id': self.data.get("knowledge_id")}) + + tag_ids = self.data.get('tag_ids') + no_tag = self.data.get('no_tag') if 'name' in self.data and self.data.get('name') is not None: query_set = query_set.filter(**{'name__icontains': self.data.get('name')}) if 'hit_handling_method' in self.data and self.data.get('hit_handling_method') not in [None, '']: query_set = query_set.filter(**{'hit_handling_method': self.data.get('hit_handling_method')}) if 'is_active' in self.data and self.data.get('is_active') is not None: query_set = query_set.filter(**{'is_active': self.data.get('is_active')}) + if no_tag and tag_ids: + matched_doc_ids = QuerySet(DocumentTag).filter(tag_id__in=tag_ids).values_list('document_id', flat=True) + tagged_doc_ids = QuerySet(DocumentTag).values_list('document_id', flat=True) + query_set = query_set.filter( + Q(id__in=matched_doc_ids) | ~Q(id__in=tagged_doc_ids) + ) + elif no_tag: + tagged_doc_ids = QuerySet(DocumentTag).values_list('document_id', flat=True) + query_set = query_set.exclude(id__in=tagged_doc_ids) + elif tag_ids: + matched_doc_ids = QuerySet(DocumentTag).filter(tag_id__in=tag_ids).values_list('document_id', flat=True) + query_set = query_set.filter(id__in=matched_doc_ids) + if 'status' in self.data and self.data.get('status') is not None: task_type = self.data.get('task_type') status = self.data.get('status') diff --git a/apps/knowledge/sql/list_document.sql b/apps/knowledge/sql/list_document.sql index 8b7891bf6e6..7ba7d741051 100644 --- a/apps/knowledge/sql/list_document.sql +++ b/apps/knowledge/sql/list_document.sql @@ -1,11 +1,28 @@ SELECT * from ( SELECT - "document".* , - to_json("document"."meta") as meta, - to_json("document"."status_meta") as status_meta, - (SELECT "count"("id") FROM "paragraph" WHERE document_id="document"."id") as "paragraph_count" + "document".*, + to_json("document"."meta") as meta, + to_json("document"."status_meta") as status_meta, + (SELECT "count"("id") FROM "paragraph" WHERE document_id = "document"."id") as "paragraph_count", + tag_agg.tag_count as "tag_count", + COALESCE(tag_agg.tags, '[]'::json) as "tags" FROM - "document" "document" + "document" "document" +LEFT JOIN LATERAL ( + SELECT + COUNT(*)::int as tag_count, + json_agg( + json_build_object( + 'id', "tag"."id", + 'key', "tag"."key", + 'value', "tag"."value" + ) + ORDER BY "tag"."key", "tag"."value" + ) as tags + FROM "document_tag" "document_tag" + INNER JOIN "tag" "tag" ON "tag"."id" = "document_tag"."tag_id" + WHERE "document_tag"."document_id" = "document"."id" +) tag_agg ON TRUE ${document_custom_sql} ) temp ${order_by_query} \ No newline at end of file diff --git a/apps/knowledge/views/document.py b/apps/knowledge/views/document.py index b87565bd40e..757e9fdb35e 100644 --- a/apps/knowledge/views/document.py +++ b/apps/knowledge/views/document.py @@ -639,6 +639,8 @@ class Page(APIView): [PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()], CompareConstants.AND), ) def get(self, request: Request, workspace_id: str, knowledge_id: str, current_page: int, page_size: int): + raw_tags = request.query_params.getlist("tags[]") + return result.success(DocumentSerializers.Query( data={ 'workspace_id': workspace_id, @@ -646,6 +648,8 @@ def get(self, request: Request, workspace_id: str, knowledge_id: str, current_pa 'folder_id': request.query_params.get('folder_id'), 'name': request.query_params.get('name'), 'tag': request.query_params.get('tag'), + 'tag_ids': [tag for tag in raw_tags if tag != 'NO_TAG'], + 'no_tag': 'NO_TAG' in raw_tags, 'desc': request.query_params.get("desc"), 'user_id': request.query_params.get('user_id'), 'status': request.query_params.get('status'), diff --git a/ui/src/locales/lang/en-US/views/document.ts b/ui/src/locales/lang/en-US/views/document.ts index feb4bfcaa8e..9f8fa284abb 100644 --- a/ui/src/locales/lang/en-US/views/document.ts +++ b/ui/src/locales/lang/en-US/views/document.ts @@ -103,6 +103,7 @@ export default { key: 'Tag', value: 'Value', addTag: 'Add Tag', + noTag: 'No Tag', setting: 'Tag Settings', create: 'Create Tag', createValue: 'Create Tag Value', diff --git a/ui/src/locales/lang/zh-CN/views/document.ts b/ui/src/locales/lang/zh-CN/views/document.ts index 3ee22b21a28..ec8be3b642b 100644 --- a/ui/src/locales/lang/zh-CN/views/document.ts +++ b/ui/src/locales/lang/zh-CN/views/document.ts @@ -98,6 +98,7 @@ export default { key: '标签', value: '标签值', addTag: '添加标签', + noTag: '无标签', addValue: '添加标签值', setting: '标签设置', create: '创建标签', diff --git a/ui/src/locales/lang/zh-Hant/views/document.ts b/ui/src/locales/lang/zh-Hant/views/document.ts index 3209d3a96b2..9c737c2311e 100644 --- a/ui/src/locales/lang/zh-Hant/views/document.ts +++ b/ui/src/locales/lang/zh-Hant/views/document.ts @@ -99,6 +99,7 @@ export default { label: '標籤管理', key: '標籤', value: '標籤值', + noTag: '無標籤', addTag: '添加標籤', setting: '標籤設置', create: '創建標籤', diff --git a/ui/src/views/document/index.vue b/ui/src/views/document/index.vue index c9ed1f765dc..93ca7b74954 100644 --- a/ui/src/views/document/index.vue +++ b/ui/src/views/document/index.vue @@ -210,74 +210,6 @@ :label="$t('views.document.fileStatus.label')" width="130" > - @@ -357,6 +289,76 @@ + + + +