Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 145 additions & 9 deletions packages/component/src/Classification.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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']

Expand Down Expand Up @@ -105,6 +112,13 @@ const dialogConfig = ref<DialogConfig>({
})
const isSelectedNoTag = ref(false)

// Sort state
const sortField = ref<SortField>('name')
const sortOrder = ref<SortOrder>('asc')

// Panel width state
const panelWidth = ref(240)

const priorityOptions = [
{
value: 1,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -704,7 +806,16 @@ defineExpose({
</script>

<template>
<div v-show="props.visible" class="classification bg-light rounded-xl">
<div
v-show="props.visible"
v-resize.right="{
minWidth: 240,
maxWidth: 480,
onResize: handleResize,
}"
class="classification bg-light rounded-xl"
:style="{ width: `${panelWidth}px` }"
>
<div class="classification-header">
<div class="h-8 flex align-center my-2 p-2 gap-1" style="--btn-space: 0">
<el-button text @click="toggle">
Expand All @@ -715,6 +826,11 @@ defineExpose({
<div class="fs-6 flex-1">
<span>{{ comTitle }}</span>
</div>
<SortDropdown
v-model:sort-field="sortField"
v-model:sort-order="sortOrder"
:is-task="type === 'dataflow'"
/>
<el-button
text
:class="{ 'is-active': showSearch }"
Expand Down Expand Up @@ -749,7 +865,7 @@ defineExpose({
show-checkbox
:props="treeProps"
:expand-on-click-node="false"
:data="treeData"
:data="sortedTreeData"
:filter-node-method="filterNode"
:render-after-expand="false"
:indent="8"
Expand All @@ -774,15 +890,22 @@ defineExpose({
>folder-close</VIcon
>
<el-icon v-else><i-lucide-tag /></el-icon>
<span class="table-label" :title="data.value">{{
<OverflowTooltip
:text="data.value"
:hide-after="0"
placement="left"
class="text-truncate"
/>
<!-- <span class="table-label" :title="data.value">{{
data.value
}}</span>
}}</span> -->

<el-tooltip
v-if="data.priority && priorityOptions[data.priority - 1]"
placement="top"
:show-after="350"
:hide-after="0"
:enterable="false"
:content="
$t('public_tag_priority_tip', {
val: priorityOptions[data.priority - 1].label,
Expand Down Expand Up @@ -945,11 +1068,24 @@ defineExpose({
position: relative;
display: flex;
flex-direction: column;
width: 213px;
width: 240px;
user-select: none;
box-sizing: border-box;
border-top: none;
background: var(--color-white);
// Resize handle indicator (iOS style)
&::before {
content: '';
position: absolute;
right: -3px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 36px;
border-radius: 10px;
background-color: lab(90.952% 0 -0.0000119209);
pointer-events: none;
}
.btn-expand {
// padding: 2px 3px;
// color: var(--text-light);
Expand Down
Loading
Loading