Files
shrimp-server/examples/basic-admin/web/src/composables/useTableUrlSync.ts
T
wc24 27a2348815 demo: 加 Vue 前端到 examples/basic-admin/web
为了端到端验证 Shrimp 框架,把 hand-admin 前端拷进 examples/basic-admin/web
作为临时演示用前端,@shrimp alias 直接指向同仓 src/,免构建。

修改要点:
- web/vite.config.ts: @shrimp 改成 ../../../src; proxy /admin-api 到 :3100
- web/tsconfig.json: 同步 @shrimp 路径; 删掉 hand-server-2 的 paths
- web/src/locales: 删掉 matter_*/zerobase 业务 key
- web/src/module: 删掉 matter_*/zerobase 业务 vue,只留 user/role/FieldRelativeTime
- examples/basic-admin/index.ts:
  - mount 到 /admin-api/* 而不是 /api/*
  - 加 /config /login /me 端点 (mock super-admin operator,固定 token)
  - DemoShrimp 子类覆盖 getMenuTree 用模块自身 label
  - MemoryShrimpCrud 的 getRelatedCrud 手动 wire 到 crudRegistry,
    populate 才能跑 (后续 70→90 改进项)

curl 已验证 /config /login /me /product/list 全通,tagIds_label 正确旁挂。
2026-05-23 15:28:10 +08:00

99 lines
3.3 KiB
TypeScript

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<Record<string, any>>({})
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<string, any> = {}
for (const [k, v] of Object.entries(route.query)) {
if (!TABLE_QUERY_KEYS.includes(k)) preserved[k] = v
}
const query: Record<string, any> = { ...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<string, any> = {}
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,
}
}