import { ref, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' export interface UseTableUrlSyncOptions { pageSize: number } export function useTableUrlSync(options: UseTableUrlSyncOptions) { const route = useRoute() const router = useRouter() const currentPage = ref(1) const currentPageSize = ref(options.pageSize) const keyword = ref('') const searchKeyword = ref('') const currentSortBy = ref('') const currentSortOrder = ref<'asc' | 'desc'>('asc') const filterData = ref>({}) function restoreFromQuery() { const q = route.query if (q.page) currentPage.value = Number(q.page) || 1 if (q.pageSize) currentPageSize.value = Number(q.pageSize) || options.pageSize if (q.keyword) { keyword.value = String(q.keyword) searchKeyword.value = String(q.keyword) } if (q.sortBy) currentSortBy.value = String(q.sortBy) if (q.sortOrder && (q.sortOrder === 'asc' || q.sortOrder === 'desc')) { currentSortOrder.value = q.sortOrder } if (q.filter) { try { const parsed = JSON.parse(String(q.filter)) if (typeof parsed === 'object' && parsed !== null) { filterData.value = parsed } } catch { /* ignore invalid JSON */ } } } // 表格自身管理的 query key,sync 时只覆盖这几个,其它保留(如 ?id= 子表父记录、自定义参数) const TABLE_QUERY_KEYS = ['page', 'pageSize', 'keyword', 'sortBy', 'sortOrder', 'filter'] function syncToQuery() { const preserved: Record = {} for (const [k, v] of Object.entries(route.query)) { if (!TABLE_QUERY_KEYS.includes(k)) preserved[k] = v } const query: Record = { ...preserved } if (currentPage.value > 1) query.page = String(currentPage.value) if (currentPageSize.value !== options.pageSize) query.pageSize = String(currentPageSize.value) if (searchKeyword.value) query.keyword = searchKeyword.value if (currentSortBy.value) { query.sortBy = currentSortBy.value query.sortOrder = currentSortOrder.value } const cleanFilter: Record = {} for (const [key, val] of Object.entries(filterData.value)) { if (val === '' || val === null || val === undefined) continue if (Array.isArray(val) && val.length === 0) continue cleanFilter[key] = val } if (Object.keys(cleanFilter).length > 0) { query.filter = JSON.stringify(cleanFilter) } router.replace({ query }) } let isRestoring = false watch( [currentPage, currentPageSize, searchKeyword, currentSortBy, currentSortOrder, filterData], () => { if (!isRestoring) { syncToQuery() } }, { deep: true } ) function restore() { isRestoring = true restoreFromQuery() isRestoring = false } return { currentPage, currentPageSize, keyword, searchKeyword, currentSortBy, currentSortOrder, filterData, restore, } }