feat: add tag filtering and input support in document search functionality

v3.2
CaptainB 2025-10-21 10:37:49 +08:00
parent 349402b2d8
commit c31142eeab
6 changed files with 52 additions and 10 deletions

View File

@ -389,6 +389,7 @@ class DocumentSerializers(serializers.Serializer):
task_type = serializers.IntegerField(required=False, label=_('task type')) task_type = serializers.IntegerField(required=False, label=_('task type'))
status = serializers.CharField(required=False, label=_('status'), allow_null=True, allow_blank=True) 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) 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)
def get_query_set(self): def get_query_set(self):
query_set = QuerySet(model=Document) query_set = QuerySet(model=Document)
@ -414,6 +415,12 @@ class DocumentSerializers(serializers.Serializer):
query_set = query_set.filter(status__icontains=status) query_set = query_set.filter(status__icontains=status)
else: else:
query_set = query_set.filter(status__iregex='^[2n]*$') query_set = query_set.filter(status__iregex='^[2n]*$')
if 'tag' in self.data and self.data.get('tag') not in [None, '']:
tag_name = self.data.get('tag')
document_id_list = QuerySet(DocumentTag).filter(
Q(tag__key__icontains=tag_name) | Q(tag__value__icontains=tag_name)
).values_list('document_id', flat=True)
query_set = query_set.filter(id__in=document_id_list)
order_by = self.data.get('order_by', '') order_by = self.data.get('order_by', '')
order_by_query_set = QuerySet(model=get_dynamics_model( order_by_query_set = QuerySet(model=get_dynamics_model(
{'char_length': models.CharField(), 'paragraph_count': models.IntegerField(), {'char_length': models.CharField(), 'paragraph_count': models.IntegerField(),

View File

@ -597,6 +597,7 @@ class DocumentView(APIView):
'knowledge_id': knowledge_id, 'knowledge_id': knowledge_id,
'folder_id': request.query_params.get('folder_id'), 'folder_id': request.query_params.get('folder_id'),
'name': request.query_params.get('name'), 'name': request.query_params.get('name'),
'tag': request.query_params.get('tag'),
'desc': request.query_params.get("desc"), 'desc': request.query_params.get("desc"),
'user_id': request.query_params.get('user_id'), 'user_id': request.query_params.get('user_id'),
'status': request.query_params.get('status'), 'status': request.query_params.get('status'),

View File

@ -114,6 +114,7 @@ export default {
'After deletion, resources using this tag will have the tag removed. Please proceed with caution!', 'After deletion, resources using this tag will have the tag removed. Please proceed with caution!',
requiredMessage1: 'Please enter a tag', requiredMessage1: 'Please enter a tag',
requiredMessage2: 'Please enter a value', requiredMessage2: 'Please enter a value',
requiredMessage3: 'Please enter a tag or value',
}, },
table: { table: {
name: 'Document Name', name: 'Document Name',

View File

@ -109,6 +109,7 @@ export default {
deleteTip: '删除后使用该标签的资源将会删除该标签,请谨慎操作!', deleteTip: '删除后使用该标签的资源将会删除该标签,请谨慎操作!',
requiredMessage1: '请输入标签', requiredMessage1: '请输入标签',
requiredMessage2: '请输入标签值', requiredMessage2: '请输入标签值',
requiredMessage3: '请输入标签或标签值',
}, },
table: { table: {
name: '文件名称', name: '文件名称',

View File

@ -111,6 +111,7 @@ export default {
deleteTip: '刪除後使用該標籤的資源將會刪除該標籤,請謹慎操作!', deleteTip: '刪除後使用該標籤的資源將會刪除該標籤,請謹慎操作!',
requiredMessage1: '請輸入標籤', requiredMessage1: '請輸入標籤',
requiredMessage2: '請輸入標籤值', requiredMessage2: '請輸入標籤值',
requiredMessage3: '請輸入標籤或標籤值',
}, },
table: { table: {
name: '文件名稱', name: '文件名稱',

View File

@ -104,15 +104,34 @@
</el-dropdown> </el-dropdown>
</template> </template>
</div> </div>
<div> <div class="flex">
<el-input <div class="flex-between complex-search">
v-model="filterText" <el-select
:placeholder="$t('common.searchBar.placeholder')" class="complex-search__left"
prefix-icon="Search" v-model="search_type"
class="w-240" style="width: 120px"
@change="getList" @change="search_type_change"
clearable >
/> <el-option :label="$t('dynamicsForm.tag.label')" value="tag" />
<el-option :label="$t('views.tool.form.toolName.label')" value="name" />
</el-select>
<el-input
v-if="search_type === 'name'"
v-model="search_form.name"
@change="refresh"
:placeholder="$t('common.searchBar.placeholder')"
style="width: 220px"
clearable
/>
<el-input
v-if="search_type === 'tag'"
v-model="search_form.tag"
@change="refresh"
:placeholder="$t('views.document.tag.requiredMessage3')"
style="width: 220px"
clearable
/>
</div>
<el-button @click="openTagDrawer" class="ml-12"> <el-button @click="openTagDrawer" class="ml-12">
{{ $t('views.document.tag.label') }} {{ $t('views.document.tag.label') }}
</el-button> </el-button>
@ -781,6 +800,12 @@ const getTaskState = (status: string, taskType: number) => {
return taskType - 1 > statusList.length + 1 ? 'n' : statusList[taskType - 1] return taskType - 1 > statusList.length + 1 ? 'n' : statusList[taskType - 1]
} }
const search_type = ref('name')
const search_form = ref<any>({
name: '',
tag: '',
})
const beforePagination = computed(() => common.paginationConfig[storeKey]) const beforePagination = computed(() => common.paginationConfig[storeKey])
const beforeSearch = computed(() => common.search[storeKey]) const beforeSearch = computed(() => common.search[storeKey])
const embeddingContentDialogRef = ref<InstanceType<typeof EmbeddingContentDialog>>() const embeddingContentDialogRef = ref<InstanceType<typeof EmbeddingContentDialog>>()
@ -1184,11 +1209,13 @@ function handleSortChange({ prop, order }: { prop: string; order: string }) {
function getList(bool?: boolean) { function getList(bool?: boolean) {
const param = { const param = {
...(filterText.value && { name: filterText.value }),
...filterMethod.value, ...filterMethod.value,
order_by: orderBy.value, order_by: orderBy.value,
folder_id: folderId, folder_id: folderId,
} }
if (search_form.value[search_type.value]) {
param[search_type.value] = search_form.value[search_type.value]
}
loadSharedApi({ type: 'document', isShared: isShared.value, systemType: apiType.value }) loadSharedApi({ type: 'document', isShared: isShared.value, systemType: apiType.value })
.getDocumentPage(id as string, paginationConfig.value, param, bool ? undefined : loading) .getDocumentPage(id as string, paginationConfig.value, param, bool ? undefined : loading)
.then((res: any) => { .then((res: any) => {
@ -1197,6 +1224,10 @@ function getList(bool?: boolean) {
}) })
} }
const search_type_change = () => {
search_form.value = { name: '', tag: '' }
}
function getDetail() { function getDetail() {
loadSharedApi({ type: 'knowledge', isShared: isShared.value, systemType: apiType.value }) loadSharedApi({ type: 'knowledge', isShared: isShared.value, systemType: apiType.value })
.getKnowledgeDetail(id, loading) .getKnowledgeDetail(id, loading)