implement dynamic route registration for tools
This commit is contained in:
parent
2c030be331
commit
712bb7242d
@ -29,4 +29,13 @@ import { useAuthStore } from '../shared/stores/auth'
|
|||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
authStore.initAuth()
|
authStore.initAuth()
|
||||||
|
|
||||||
|
// 初始化动态工具路由 - 使用 router.isReady() 确保路由已完全初始化
|
||||||
|
import { useToolsStore } from '../shared/stores/tools'
|
||||||
|
router.isReady().then(() => {
|
||||||
|
const toolsStore = useToolsStore()
|
||||||
|
toolsStore.initToolRoutes(router)
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('Failed to initialize tool routes:', error)
|
||||||
|
})
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
@ -12,6 +12,7 @@ const router = createRouter({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
name: 'AppLayout',
|
||||||
component: () => import('../layouts/AppLayout.vue'),
|
component: () => import('../layouts/AppLayout.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { t } from '../i18n'
|
import { t } from '../i18n'
|
||||||
|
import { registerToolRoute, unregisterToolRoute, syncToolRoutes, registerAllToolRoutes } from '../utils/dynamicRoutes'
|
||||||
|
|
||||||
export interface Tool {
|
export interface Tool {
|
||||||
id: string
|
id: string
|
||||||
@ -120,7 +121,7 @@ export const useToolsStore = defineStore('tools', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 添加用户工具
|
// 添加用户工具
|
||||||
function addUserTool(tool: Tool) {
|
function addUserTool(tool: Tool, router?: any, componentPath?: string) {
|
||||||
const defaultToolsCount = getDefaultTools().filter(
|
const defaultToolsCount = getDefaultTools().filter(
|
||||||
t => !hiddenDefaultToolIds.value.includes(t.id)
|
t => !hiddenDefaultToolIds.value.includes(t.id)
|
||||||
).length
|
).length
|
||||||
@ -129,6 +130,11 @@ export const useToolsStore = defineStore('tools', () => {
|
|||||||
tool.isDefault = false
|
tool.isDefault = false
|
||||||
userTools.value.push(tool)
|
userTools.value.push(tool)
|
||||||
saveUserTools(userTools.value)
|
saveUserTools(userTools.value)
|
||||||
|
|
||||||
|
// 如果是路由类型工具,注册路由(如果提供了 router)
|
||||||
|
if (tool.type === 'route' && tool.routeName && router) {
|
||||||
|
registerToolRoute(router, tool, componentPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新用户工具
|
// 更新用户工具
|
||||||
@ -141,7 +147,9 @@ export const useToolsStore = defineStore('tools', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除用户工具
|
// 删除用户工具
|
||||||
function deleteUserTool(toolId: string) {
|
function deleteUserTool(toolId: string, router?: any) {
|
||||||
|
const tool = userTools.value.find(t => t.id === toolId)
|
||||||
|
|
||||||
userTools.value = userTools.value.filter(t => t.id !== toolId)
|
userTools.value = userTools.value.filter(t => t.id !== toolId)
|
||||||
// 重新分配 order
|
// 重新分配 order
|
||||||
const defaultToolsCount = getDefaultTools().filter(
|
const defaultToolsCount = getDefaultTools().filter(
|
||||||
@ -151,6 +159,11 @@ export const useToolsStore = defineStore('tools', () => {
|
|||||||
t.order = defaultToolsCount + index + 1
|
t.order = defaultToolsCount + index + 1
|
||||||
})
|
})
|
||||||
saveUserTools(userTools.value)
|
saveUserTools(userTools.value)
|
||||||
|
|
||||||
|
// 如果是路由类型工具,移除路由(如果提供了 router)
|
||||||
|
if (tool?.type === 'route' && tool.routeName && router) {
|
||||||
|
unregisterToolRoute(router, tool.routeName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 隐藏默认工具
|
// 隐藏默认工具
|
||||||
@ -181,6 +194,16 @@ export const useToolsStore = defineStore('tools', () => {
|
|||||||
saveUserTools(userTools.value)
|
saveUserTools(userTools.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化工具路由(在应用启动时调用)
|
||||||
|
function initToolRoutes(router: any) {
|
||||||
|
registerAllToolRoutes(router, userTools.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步工具路由(移除不存在的,添加新的)
|
||||||
|
function syncRoutes(router: any) {
|
||||||
|
syncToolRoutes(router, userTools.value)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userTools,
|
userTools,
|
||||||
hiddenDefaultToolIds,
|
hiddenDefaultToolIds,
|
||||||
@ -192,7 +215,9 @@ export const useToolsStore = defineStore('tools', () => {
|
|||||||
hideDefaultTool,
|
hideDefaultTool,
|
||||||
showDefaultTool,
|
showDefaultTool,
|
||||||
updateUserToolsOrder,
|
updateUserToolsOrder,
|
||||||
getDefaultTools
|
getDefaultTools,
|
||||||
|
initToolRoutes,
|
||||||
|
syncRoutes
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
159
apps/jingrow/frontend/src/shared/utils/dynamicRoutes.ts
Normal file
159
apps/jingrow/frontend/src/shared/utils/dynamicRoutes.ts
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/**
|
||||||
|
* 动态路由管理工具
|
||||||
|
* 用于动态注册和移除工具路由
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Router, RouteRecordRaw } from 'vue-router'
|
||||||
|
import type { Tool } from '../stores/tools'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态注册工具路由
|
||||||
|
* @param router Vue Router 实例
|
||||||
|
* @param tool 工具定义
|
||||||
|
* @param componentPath 组件路径(相对于 src/views)
|
||||||
|
*/
|
||||||
|
export function registerToolRoute(
|
||||||
|
router: Router,
|
||||||
|
tool: Tool,
|
||||||
|
componentPath?: string
|
||||||
|
): boolean {
|
||||||
|
if (tool.type !== 'route' || !tool.routeName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查路由是否已存在
|
||||||
|
if (router.hasRoute(tool.routeName)) {
|
||||||
|
console.warn(`Route ${tool.routeName} already exists, skipping registration`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确定组件路径
|
||||||
|
// 1. 如果提供了 componentPath,使用它
|
||||||
|
// 2. 如果工具有 componentPath 属性,使用它
|
||||||
|
// 3. 默认使用 tools/{routeName}.vue
|
||||||
|
const finalComponentPath =
|
||||||
|
componentPath ||
|
||||||
|
(tool as any).componentPath ||
|
||||||
|
`../../views/tools/${tool.routeName}.vue`
|
||||||
|
|
||||||
|
// 构建路由路径
|
||||||
|
// 默认使用 tools/{id},但可以通过 tool.routePath 自定义
|
||||||
|
const routePath = (tool as any).routePath || `tools/${tool.id}`
|
||||||
|
|
||||||
|
// 创建路由配置,添加组件加载错误处理
|
||||||
|
const route: RouteRecordRaw = {
|
||||||
|
path: routePath,
|
||||||
|
name: tool.routeName,
|
||||||
|
component: () => import(finalComponentPath).catch((error) => {
|
||||||
|
console.error(`Failed to load tool component: ${finalComponentPath}`, error)
|
||||||
|
// 返回一个简单的错误组件
|
||||||
|
return {
|
||||||
|
template: '<div style="padding: 20px; text-align: center;"><h3>Component Not Found</h3><p>Failed to load: {{ path }}</p></div>',
|
||||||
|
data() {
|
||||||
|
return { path: finalComponentPath }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: true,
|
||||||
|
toolId: tool.id,
|
||||||
|
toolName: tool.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 将路由添加到 AppLayout 的 children 下
|
||||||
|
// 如果 AppLayout 路由不存在,尝试添加到根路由
|
||||||
|
if (router.hasRoute('AppLayout')) {
|
||||||
|
router.addRoute('AppLayout', route)
|
||||||
|
} else {
|
||||||
|
// 查找父路由(path 为 '/' 的路由)
|
||||||
|
const parentRoute = router.getRoutes().find((r: any) => r.path === '/' && r.name !== 'Login')
|
||||||
|
if (parentRoute) {
|
||||||
|
router.addRoute(parentRoute.name || parentRoute.path, route)
|
||||||
|
} else {
|
||||||
|
// 如果找不到父路由,直接添加到根路由
|
||||||
|
router.addRoute(route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(`Tool route registered: ${tool.routeName} -> ${routePath}`)
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to register tool route ${tool.routeName}:`, error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除工具路由
|
||||||
|
* @param router Vue Router 实例
|
||||||
|
* @param routeName 路由名称
|
||||||
|
*/
|
||||||
|
export function unregisterToolRoute(router: Router, routeName: string): boolean {
|
||||||
|
if (!router.hasRoute(routeName)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
router.removeRoute(routeName)
|
||||||
|
console.log(`Tool route removed: ${routeName}`)
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to remove tool route ${routeName}:`, error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册所有用户工具的路由
|
||||||
|
* @param router Vue Router 实例
|
||||||
|
* @param tools 工具列表
|
||||||
|
*/
|
||||||
|
export function registerAllToolRoutes(router: Router, tools: Tool[]): void {
|
||||||
|
const routeTools = tools.filter(t => t.type === 'route' && t.routeName && !t.isDefault)
|
||||||
|
|
||||||
|
routeTools.forEach(tool => {
|
||||||
|
registerToolRoute(router, tool)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(`Registered ${routeTools.length} tool routes`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步工具路由(移除不存在的工具路由,添加新的工具路由)
|
||||||
|
* @param router Vue Router 实例
|
||||||
|
* @param currentTools 当前工具列表
|
||||||
|
*/
|
||||||
|
export function syncToolRoutes(router: Router, currentTools: Tool[]): void {
|
||||||
|
// 获取所有已注册的路由
|
||||||
|
const registeredRoutes = router.getRoutes()
|
||||||
|
|
||||||
|
// 找出所有工具路由(通过 meta.toolId 识别)
|
||||||
|
const toolRoutes = registeredRoutes.filter((route) =>
|
||||||
|
route.meta?.toolId && !route.meta?.isDefault
|
||||||
|
)
|
||||||
|
|
||||||
|
// 当前应该存在的工具路由名称
|
||||||
|
const currentRouteNames = new Set(
|
||||||
|
currentTools
|
||||||
|
.filter(t => t.type === 'route' && t.routeName && !t.isDefault)
|
||||||
|
.map(t => t.routeName!)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 移除不再存在的工具路由
|
||||||
|
toolRoutes.forEach((route) => {
|
||||||
|
if (route.name && typeof route.name === 'string' && !currentRouteNames.has(route.name)) {
|
||||||
|
unregisterToolRoute(router, route.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加新的工具路由
|
||||||
|
currentTools
|
||||||
|
.filter(t => t.type === 'route' && t.routeName && !t.isDefault)
|
||||||
|
.forEach(tool => {
|
||||||
|
if (tool.routeName && !router.hasRoute(tool.routeName)) {
|
||||||
|
registerToolRoute(router, tool)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
@ -444,7 +444,8 @@ function handleSaveTool() {
|
|||||||
isDefault: false
|
isDefault: false
|
||||||
}
|
}
|
||||||
|
|
||||||
toolsStore.addUserTool(newTool)
|
// 添加工具并注册路由
|
||||||
|
toolsStore.addUserTool(newTool, router)
|
||||||
message.success(t('Tool added successfully'))
|
message.success(t('Tool added successfully'))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +476,8 @@ function handleDeleteTool(tool: Tool) {
|
|||||||
positiveText: t('Delete'),
|
positiveText: t('Delete'),
|
||||||
negativeText: t('Cancel'),
|
negativeText: t('Cancel'),
|
||||||
onPositiveClick: () => {
|
onPositiveClick: () => {
|
||||||
toolsStore.deleteUserTool(tool.id)
|
// 删除工具并移除路由
|
||||||
|
toolsStore.deleteUserTool(tool.id, router)
|
||||||
message.success(t('Tool deleted successfully'))
|
message.success(t('Tool deleted successfully'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user