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()
|
||||
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')
|
||||
|
||||
@ -12,6 +12,7 @@ const router = createRouter({
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'AppLayout',
|
||||
component: () => import('../layouts/AppLayout.vue'),
|
||||
meta: { requiresAuth: true },
|
||||
children: [
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { t } from '../i18n'
|
||||
import { registerToolRoute, unregisterToolRoute, syncToolRoutes, registerAllToolRoutes } from '../utils/dynamicRoutes'
|
||||
|
||||
export interface Tool {
|
||||
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(
|
||||
t => !hiddenDefaultToolIds.value.includes(t.id)
|
||||
).length
|
||||
@ -129,6 +130,11 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
tool.isDefault = false
|
||||
userTools.value.push(tool)
|
||||
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)
|
||||
// 重新分配 order
|
||||
const defaultToolsCount = getDefaultTools().filter(
|
||||
@ -151,6 +159,11 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
t.order = defaultToolsCount + index + 1
|
||||
})
|
||||
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)
|
||||
}
|
||||
|
||||
// 初始化工具路由(在应用启动时调用)
|
||||
function initToolRoutes(router: any) {
|
||||
registerAllToolRoutes(router, userTools.value)
|
||||
}
|
||||
|
||||
// 同步工具路由(移除不存在的,添加新的)
|
||||
function syncRoutes(router: any) {
|
||||
syncToolRoutes(router, userTools.value)
|
||||
}
|
||||
|
||||
return {
|
||||
userTools,
|
||||
hiddenDefaultToolIds,
|
||||
@ -192,7 +215,9 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
hideDefaultTool,
|
||||
showDefaultTool,
|
||||
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
|
||||
}
|
||||
|
||||
toolsStore.addUserTool(newTool)
|
||||
// 添加工具并注册路由
|
||||
toolsStore.addUserTool(newTool, router)
|
||||
message.success(t('Tool added successfully'))
|
||||
}
|
||||
|
||||
@ -475,7 +476,8 @@ function handleDeleteTool(tool: Tool) {
|
||||
positiveText: t('Delete'),
|
||||
negativeText: t('Cancel'),
|
||||
onPositiveClick: () => {
|
||||
toolsStore.deleteUserTool(tool.id)
|
||||
// 删除工具并移除路由
|
||||
toolsStore.deleteUserTool(tool.id, router)
|
||||
message.success(t('Tool deleted successfully'))
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user