From f2dc3a0386bdacf3f8e1521110f24798919c35eb Mon Sep 17 00:00:00 2001 From: Feynman Date: Wed, 4 Feb 2026 23:15:27 +0800 Subject: [PATCH] feat(Classification.vue): implement sorting and panel width adjustments - Added sorting functionality for classification items based on name, priority, and created time. - Introduced a panel width state with dynamic resizing capabilities. - Updated Vuex store to persist sorting and panel width settings. - Enhanced UI with a SortDropdown component and OverflowTooltip for better data display. - Localized new sort-related strings in English, Simplified Chinese, and Traditional Chinese. --- packages/component/src/Classification.vue | 154 +++++++++++++++++-- packages/component/src/SortDropdown.vue | 158 ++++++++++++++++++++ packages/component/src/locale/lang/en.js | 9 ++ packages/component/src/locale/lang/zh-CN.js | 9 ++ packages/component/src/locale/lang/zh-TW.js | 9 ++ packages/component/src/store.js | 39 +++++ packages/types/src/daas-auto-imports.d.ts | 2 + packages/types/src/daas-components.d.ts | 2 + 8 files changed, 373 insertions(+), 9 deletions(-) create mode 100644 packages/component/src/SortDropdown.vue diff --git a/packages/component/src/Classification.vue b/packages/component/src/Classification.vue index e2f4e058a..1862af8ba 100644 --- a/packages/component/src/Classification.vue +++ b/packages/component/src/Classification.vue @@ -13,14 +13,21 @@ import { fetchUserGroups, patchUserGroupById, } from '@tap/api/core/user-groups' - import { useI18n } from '@tap/i18n' import { ElMessage } from 'element-plus' + import { computed, nextTick, onMounted, ref, watch } from 'vue' import { useStore } from 'vuex' import VIcon from './base/VIcon.vue' +import vResize from './directives/resize' import { Modal } from './modal' +import { OverflowTooltip } from './overflow-tooltip' +import SortDropdown from './SortDropdown.vue' import type { RenderContentContext, TreeInstance, TreeKey } from 'element-plus' +import './directives/resize/index.scss' + +type SortField = 'name' | 'priority' | 'createdTime' +type SortOrder = 'asc' | 'desc' type Node = RenderContentContext['node'] @@ -105,6 +112,13 @@ const dialogConfig = ref({ }) const isSelectedNoTag = ref(false) +// Sort state +const sortField = ref('name') +const sortOrder = ref('asc') + +// Panel width state +const panelWidth = ref(240) + const priorityOptions = [ { value: 1, @@ -178,6 +192,29 @@ const setPanelFlag = (payload: { panelFlag: boolean; type: string }) => { store.commit('classification/setPanelFlag', payload) } +const setSort = (payload: { + sortField?: SortField + sortOrder?: SortOrder + type: string +}) => { + store.commit('classification/setSort', payload) +} + +const setPanelWidthToStore = (payload: { + panelWidth: number + type: string +}) => { + store.commit('classification/setPanelWidth', payload) +} + +const handleResize = ({ newVal }: { newVal: number }) => { + panelWidth.value = newVal + setPanelWidthToStore({ + panelWidth: newVal, + type: props.viewPage || '', + }) +} + const toggle = () => { const _isExpand = !isExpand.value isExpand.value = _isExpand @@ -338,6 +375,45 @@ const formatData = (items: TreeNode[]): TreeNode[] => { return [] } +// 排序函数 +const sortNodes = (nodes: TreeNode[]): TreeNode[] => { + const sorted = [...nodes].sort((a, b) => { + let compareValue = 0 + + switch (sortField.value) { + case 'name': + compareValue = (a.value || '').localeCompare(b.value || '') + break + case 'priority': { + // priority 值越小优先级越高,没有 priority 的排在最后 + const aPriority = (a as any).priority ?? 999 + const bPriority = (b as any).priority ?? 999 + compareValue = aPriority - bPriority + break + } + case 'createdTime': { + const aTime = a.last_updated ? new Date(a.last_updated).getTime() : 0 + const bTime = b.last_updated ? new Date(b.last_updated).getTime() : 0 + compareValue = aTime - bTime + break + } + } + + return sortOrder.value === 'asc' ? compareValue : -compareValue + }) + + // 递归排序子节点 + return sorted.map((node) => ({ + ...node, + children: node.children ? sortNodes(node.children) : undefined, + })) +} + +// 排序后的树数据 +const sortedTreeData = computed(() => { + return sortNodes(treeData.value) +}) + const filterNode = (value: string, data: TreeNode) => { if (!value) return true return data.value.includes(value) @@ -651,33 +727,59 @@ watch(filterText, (val) => { tree.value?.filter(val) }) +// Watch sort changes and persist to store +watch([sortField, sortOrder], ([newSortField, newSortOrder]) => { + setSort({ + sortField: newSortField, + sortOrder: newSortOrder, + type: props.viewPage || '', + }) +}) + // Lifecycle onMounted(() => { - // 是否默认打开/是否有选择tag + // 是否默认打开/是否有选择tag/排序规则/面板宽度 let flag = false let tags: string[] = [] + let storedSortField: SortField = 'name' + let storedSortOrder: SortOrder = 'asc' + let storedPanelWidth = 240 + switch (props.viewPage) { case 'connections': flag = connections.value?.panelFlag tags = connections.value?.classification - + storedSortField = connections.value?.sortField || 'name' + storedSortOrder = connections.value?.sortOrder || 'asc' + storedPanelWidth = connections.value?.panelWidth || 240 break case 'migrate': flag = migrate.value?.panelFlag tags = migrate.value?.classification + storedSortField = migrate.value?.sortField || 'name' + storedSortOrder = migrate.value?.sortOrder || 'asc' + storedPanelWidth = migrate.value?.panelWidth || 240 break case 'sync': flag = sync.value?.panelFlag tags = sync.value?.classification - + storedSortField = sync.value?.sortField || 'name' + storedSortOrder = sync.value?.sortOrder || 'asc' + storedPanelWidth = sync.value?.panelWidth || 240 break case 'inspect': flag = inspect.value?.panelFlag tags = inspect.value?.classification + storedSortField = inspect.value?.sortField || 'name' + storedSortOrder = inspect.value?.sortOrder || 'asc' + storedPanelWidth = inspect.value?.panelWidth || 240 break } isExpand.value = flag + sortField.value = storedSortField + sortOrder.value = storedSortOrder + panelWidth.value = storedPanelWidth getData((data) => { if (flag) { @@ -704,7 +806,16 @@ defineExpose({