210210 :label =" $t('views.document.fileStatus.label')"
211211 width =" 130"
212212 >
213- <template #header >
214- <div >
215- <span >{{ $t('views.document.fileStatus.label') }}</span >
216- <el-dropdown trigger =" click" @command =" dropdownHandle" >
217- <el-button
218- style =" margin-top : 1px "
219- link
220- :type =" filterMethod['status'] ? 'primary' : ''"
221- >
222- <el-icon >
223- <Filter />
224- </el-icon >
225- </el-button >
226- <template #dropdown >
227- <el-dropdown-menu style =" width : 100px " >
228- <el-dropdown-item
229- :class =" filterMethod['status'] ? '' : 'is-active'"
230- :command =" beforeCommand('status', '')"
231- class =" justify-center"
232- >{{ $t('common.status.all') }}
233- </el-dropdown-item >
234- <el-dropdown-item
235- :class =" filterMethod['status'] === State.SUCCESS ? 'is-active' : ''"
236- class =" justify-center"
237- :command =" beforeCommand('status', State.SUCCESS)"
238- >{{ $t('common.status.success') }}
239- </el-dropdown-item >
240- <el-dropdown-item
241- :class =" filterMethod['status'] === State.FAILURE ? 'is-active' : ''"
242- class =" justify-center"
243- :command =" beforeCommand('status', State.FAILURE)"
244- >{{ $t('common.status.fail') }}
245- </el-dropdown-item >
246- <el-dropdown-item
247- :class ="
248- filterMethod['status'] === State.STARTED &&
249- filterMethod['task_type'] == TaskType.EMBEDDING
250- ? 'is-active'
251- : ''
252- "
253- class =" justify-center"
254- :command =" beforeCommand('status', State.STARTED, TaskType.EMBEDDING)"
255- >{{ $t('views.document.fileStatus.EMBEDDING') }}
256- </el-dropdown-item >
257- <el-dropdown-item
258- :class =" filterMethod['status'] === State.PENDING ? 'is-active' : ''"
259- class =" justify-center"
260- :command =" beforeCommand('status', State.PENDING)"
261- >{{ $t('views.document.fileStatus.PENDING') }}
262- </el-dropdown-item >
263- <el-dropdown-item
264- :class ="
265- filterMethod['status'] === State.STARTED &&
266- filterMethod['task_type'] === TaskType.GENERATE_PROBLEM
267- ? 'is-active'
268- : ''
269- "
270- class =" justify-center"
271- :command ="
272- beforeCommand('status', State.STARTED, TaskType.GENERATE_PROBLEM)
273- "
274- >{{ $t('views.document.fileStatus.GENERATE') }}
275- </el-dropdown-item >
276- </el-dropdown-menu >
277- </template >
278- </el-dropdown >
279- </div >
280- </template >
281213 <template #default =" { row } " >
282214 <StatusValue :status =" row.status" :status-meta =" row.status_meta" ></StatusValue >
283215 </template >
357289 </div >
358290 </template >
359291 </el-table-column >
292+ <el-table-column width =" 160" >
293+ <template #header >
294+ <div >
295+ <span >{{ $t('views.document.tag.label') }}</span >
296+ <el-dropdown trigger =" click" @visible-change =" handleTagVisibleChange" >
297+ <el-button
298+ style =" margin-top : 1px "
299+ link
300+ :type =" filterMethod['tags']?.length > 0 ? 'primary' : ''"
301+ >
302+ <el-icon >
303+ <Filter />
304+ </el-icon >
305+ </el-button >
306+ <template #dropdown >
307+ <div >
308+ <el-cascader-panel
309+ v-model =" tagFilterValue"
310+ :options =" tagFilterOptions"
311+ :props =" {
312+ multiple: true,
313+ checkStrictly: true,
314+ emitPath: false,
315+ showPrefix: false,
316+ }"
317+ @change =" (val: any) => dropdownHandle({ attr: 'tags', command: val })"
318+ />
319+ </div >
320+ </template >
321+ </el-dropdown >
322+ </div >
323+ </template >
324+ <template #default =" { row } " >
325+ <el-popover
326+ trigger =" hover"
327+ placement =" bottom"
328+ :disabled =" !row.tag_count"
329+ :width =" 160"
330+ >
331+ <div v-for =" tag in row.tags" :key =" tag.id" flex class =" pt-4" >
332+ <span class =" mr-8 color-input-placeholder" >{{ tag.key }}</span
333+ >{{ tag.value }}
334+ </div >
335+
336+ <template #reference >
337+ <el-space :size =" 4" >
338+ <el-button
339+ size =" small"
340+ style =" padding : 1px 6px "
341+ @click.stop =" openTagSettingDrawer(row)"
342+ :disabled =" !permissionPrecise.doc_tag(id)"
343+ >
344+ <AppIcon iconName =" app-tag" ></AppIcon >
345+ <span >{{ row.tag_count || 0 }}</span >
346+ </el-button >
347+ <el-button
348+ size =" small"
349+ plain
350+ style =" padding : 1px 6px ; border-style : dashed "
351+ :disabled =" !permissionPrecise.doc_tag(id)"
352+ @click.stop =" openAddTagDialog(row.id)"
353+ >
354+ <el-icon class =" color-secondary" ><Plus /></el-icon >
355+ <span class =" color-secondary" >{{ $t('views.document.tag.key') }}</span >
356+ </el-button >
357+ </el-space >
358+ </template >
359+ </el-popover >
360+ </template >
361+ </el-table-column >
360362 <el-table-column width =" 170" >
361363 <template #header >
362364 <div >
734736 :workspaceId =" knowledgeDetail?.workspace_id"
735737 />
736738 <GenerateRelatedDialog ref =" GenerateRelatedDialogRef" @refresh =" getList" :apiType =" apiType" />
737- <TagDrawer ref =" tagDrawerRef" />
738- <TagSettingDrawer ref =" tagSettingDrawerRef" />
739+ <TagDrawer ref =" tagDrawerRef" @tag-changed =" onTagChanged" />
740+ <TagSettingDrawer
741+ ref =" tagSettingDrawerRef"
742+ @refresh ="
743+ () => {
744+ onTagChanged()
745+ getList()
746+ }
747+ "
748+ />
739749 <AddTagDialog ref =" addTagDialogRef" @addTags =" addTags" :apiType =" apiType" />
740750 <!-- 执行详情 -->
741751 <ExecutionRecord ref =" ListActionRef" ></ExecutionRecord >
742752 </div >
743753</template >
744754<script setup lang="ts">
745- import { ref , onMounted , onBeforeUnmount , computed } from ' vue'
755+ import { ref , onMounted , onBeforeUnmount , computed , reactive } from ' vue'
746756import { useRouter , useRoute , onBeforeRouteLeave , onBeforeRouteUpdate } from ' vue-router'
747757import type { ElTable } from ' element-plus'
748758import ImportDocumentDialog from ' ./component/ImportDocumentDialog.vue'
@@ -1359,6 +1369,61 @@ function openGenerateDialog(row?: any) {
13591369 GenerateRelatedDialogRef .value .open (arr , ' document' )
13601370}
13611371
1372+ const tagFilterValue = ref <string []>([])
1373+ const tagFilterDirty = ref (false )
1374+ const tagFilterOptions = ref <any []>([])
1375+ const tagFilterLoaded = ref (false )
1376+ const tagFilterLoading = ref (false )
1377+
1378+ function buildTagCascaderOptions(tags : any []) {
1379+ const options = tags .map ((group : any ) => ({
1380+ label: group .key ,
1381+ value: group .key ,
1382+ children: (group .values || []).map ((item : any ) => ({
1383+ label: item .value ,
1384+ value: item .id , // 叶子节点 tag.id
1385+ })),
1386+ }))
1387+
1388+ options .push ({
1389+ label: t (' views.document.tag.noTag' ),
1390+ value: ' NO_TAG' ,
1391+ children: [],
1392+ })
1393+
1394+ return options
1395+ }
1396+
1397+ async function ensureTagFilterOptions(needRefresh = false ) {
1398+ // 非刷新 && 已加载 && 非脏数据
1399+ if (! needRefresh && tagFilterLoaded .value && ! tagFilterDirty .value ) return
1400+
1401+ try {
1402+ tagFilterLoading .value = true
1403+ const params = {}
1404+ const res: any = await loadSharedApi ({
1405+ type: ' knowledge' ,
1406+ systemType: apiType .value ,
1407+ isShared: isShared .value ,
1408+ }).getTags (id , params , tagFilterLoading )
1409+
1410+ tagFilterOptions .value = buildTagCascaderOptions (res ?.data || [])
1411+ tagFilterLoaded .value = true
1412+ tagFilterDirty .value = false
1413+ } finally {
1414+ tagFilterLoading .value = false
1415+ }
1416+ }
1417+
1418+ async function handleTagVisibleChange(visible : boolean ) {
1419+ if (! visible ) return
1420+ await ensureTagFilterOptions ()
1421+ }
1422+
1423+ function onTagChanged() {
1424+ tagFilterDirty .value = true
1425+ }
1426+
13621427const tagDrawerRef = ref ()
13631428function openTagDrawer() {
13641429 tagDrawerRef .value .open ()
@@ -1371,13 +1436,14 @@ function openTagSettingDrawer(doc: any) {
13711436
13721437const addTagDialogRef = ref ()
13731438
1374- function openAddTagDialog() {
1375- addTagDialogRef .value ?.open ()
1439+ function openAddTagDialog(rowId ? : string ) {
1440+ addTagDialogRef .value ?.open (rowId )
13761441}
13771442
1378- function addTags(tags : any ) {
1379- const arr: string [] = multipleSelection .value .map ((v ) => v .id )
1380-
1443+ function addTags(tags : any , rowId ? : string ) {
1444+ const arr: string [] = multipleSelection .value .length
1445+ ? multipleSelection .value .map ((v ) => v .id )
1446+ : [rowId ]
13811447 loadSharedApi ({ type: ' document' , systemType: apiType .value })
13821448 .postMulDocumentTags (id , { tag_ids: tags , document_ids: arr }, loading )
13831449 .then (() => {
@@ -1399,7 +1465,7 @@ onMounted(() => {
13991465 }
14001466 getList ()
14011467 // 初始化定时任务
1402- initInterval ()
1468+ // initInterval()
14031469})
14041470
14051471onBeforeUnmount (() => {
0 commit comments