feat(web-admin): add useColumnSort for CRM date headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-09-08 21:47:37 +08:00
1 parent f14a96b28d
commit 58b5d9d7de
2 files changed
+106

No files matched your search

@@ -0,0 +1,29 @@
import { describe, expect, it } from 'vitest'
import { nextSortState } from './useColumnSort'
describe('nextSortState', () => {
it('sets asc when empty', () => {
expect(nextSortState(null, null, 'createTime', 'asc')).toEqual({
sortField: 'createTime',
sortOrder: 'asc'
})
})
it('clears when same field and same order', () => {
expect(nextSortState('createTime', 'asc', 'createTime', 'asc')).toEqual({
sortField: null,
sortOrder: null
})
})
it('switches order on same field', () => {
expect(nextSortState('createTime', 'asc', 'createTime', 'desc')).toEqual({
sortField: 'createTime',
sortOrder: 'desc'
})
})
it('replaces field', () => {
expect(nextSortState('createTime', 'asc', 'dealTime', 'desc')).toEqual({
sortField: 'dealTime',
sortOrder: 'desc'
})
})
})
@@ -0,0 +1,77 @@
import { computed, ref, watch, type Ref } from 'vue'
export type SortOrder = 'asc' | 'desc'
export function nextSortState(
currentField: string | null,
currentOrder: SortOrder | null,
prop: string,
order: SortOrder
): { sortField: string | null; sortOrder: SortOrder | null } {
if (currentField === prop && currentOrder === order) {
return { sortField: null, sortOrder: null }
}
return { sortField: prop, sortOrder: order }
}
export function useColumnSort(options?: { onChange?: () => void }) {
const sortField = ref<string | null>(null)
const sortOrder = ref<SortOrder | null>(null)
const hasActiveSort = computed(() => Boolean(sortField.value && sortOrder.value))
function setSort(prop: string, order: SortOrder) {
const next = nextSortState(sortField.value, sortOrder.value, prop, order)
sortField.value = next.sortField
sortOrder.value = next.sortOrder
options?.onChange?.()
}
function clearSort() {
if (!sortField.value && !sortOrder.value) return
sortField.value = null
sortOrder.value = null
options?.onChange?.()
}
function isSortActive(prop: string, order?: SortOrder) {
if (!sortField.value || sortField.value !== prop) return false
if (order == null) return true
return sortOrder.value === order
}
function toQueryParams(): Record<string, string> {
if (!sortField.value || !sortOrder.value) return {}
return { sortField: sortField.value, sortOrder: sortOrder.value }
}
function onColumnHidden(prop: string) {
if (sortField.value === prop) clearSort()
}
function watchVisibleColumns(visibleProps: Ref<string[]>) {
watch(
visibleProps,
(next, prev) => {
if (!prev) return
const nextSet = new Set(next || [])
for (const p of prev) {
if (!nextSet.has(p)) onColumnHidden(p)
}
},
{ deep: true }
)
}
return {
sortField,
sortOrder,
hasActiveSort,
setSort,
clearSort,
isSortActive,
toQueryParams,
onColumnHidden,
watchVisibleColumns
}
}