Fix tool route registration and page refresh issues
This commit is contained in:
parent
82dc1bfc7e
commit
ea874654bd
@ -29,7 +29,6 @@ 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()
|
||||
|
||||
@ -190,15 +190,39 @@ const router = createRouter({
|
||||
]
|
||||
})
|
||||
|
||||
// 路由守卫
|
||||
router.beforeEach(async (to, _from, next) => {
|
||||
const authStore = useAuthStore()
|
||||
|
||||
// 初始化认证状态(内部会检查cookie是否过期)
|
||||
if (!authStore.isAuthenticated) {
|
||||
await authStore.initAuth()
|
||||
}
|
||||
|
||||
if (to.path.startsWith('/tools/') && to.name !== 'Tools' && to.name !== 'RemoveBackground') {
|
||||
const routeExists = to.matched.length > 0 || router.getRoutes().some(r => {
|
||||
const fullPath = r.path.startsWith('/') ? r.path : `/${r.path}`
|
||||
return fullPath === to.path
|
||||
})
|
||||
|
||||
if (!routeExists) {
|
||||
const { useToolsStore } = await import('../../shared/stores/tools')
|
||||
const toolsStore = useToolsStore()
|
||||
toolsStore.initToolRoutes(router)
|
||||
|
||||
const routeExistsAfter = router.getRoutes().some(r => {
|
||||
const fullPath = r.path.startsWith('/') ? r.path : `/${r.path}`
|
||||
return fullPath === to.path
|
||||
})
|
||||
|
||||
if (routeExistsAfter) {
|
||||
next({ ...to, replace: true })
|
||||
return
|
||||
} else {
|
||||
next('/tools')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
|
||||
next('/login')
|
||||
} else if (to.path === '/login' && authStore.isLoggedIn) {
|
||||
|
||||
@ -101,25 +101,20 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
const userTools = ref<Tool[]>(loadUserTools())
|
||||
const hiddenDefaultToolIds = ref<string[]>(loadHiddenDefaultTools())
|
||||
|
||||
// 合并显示所有工具:默认工具 + 用户工具
|
||||
const allTools = computed(() => {
|
||||
// 获取默认工具(排除隐藏的)
|
||||
const defaultTools = getDefaultTools()
|
||||
.filter(tool => !hiddenDefaultToolIds.value.includes(tool.id))
|
||||
.map(tool => ({ ...tool, isDefault: true }))
|
||||
|
||||
// 用户工具
|
||||
const userToolsList = [...userTools.value]
|
||||
.map(tool => ({ ...tool, isDefault: false }))
|
||||
|
||||
// 合并并排序:默认工具在前,用户工具在后,各自按order排序
|
||||
return [
|
||||
...defaultTools.sort((a, b) => (a.order ?? 0) - (b.order ?? 0)),
|
||||
...userToolsList.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
||||
]
|
||||
})
|
||||
|
||||
// 获取隐藏的默认工具列表
|
||||
const hiddenTools = computed(() => {
|
||||
return getDefaultTools()
|
||||
.filter(tool => hiddenDefaultToolIds.value.includes(tool.id))
|
||||
@ -148,7 +143,6 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户工具
|
||||
function updateUserTool(toolId: string, updates: Partial<Tool>) {
|
||||
const index = userTools.value.findIndex(t => t.id === toolId)
|
||||
if (index >= 0) {
|
||||
@ -161,18 +155,12 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
async function deleteUserTool(toolId: string, router?: Router) {
|
||||
const tool = userTools.value.find(t => t.id === toolId)
|
||||
|
||||
console.log('删除工具:', { toolId, tool, fromMarketplace: tool?.fromMarketplace, marketplaceId: tool?.marketplaceId, toolName: tool?.toolName, componentPath: tool?.componentPath })
|
||||
|
||||
// 确定工具名称(tool_name):优先使用 toolName,否则从 componentPath 提取
|
||||
let toolName: string | null = null
|
||||
|
||||
if (tool) {
|
||||
// 优先使用 toolName(实际的 tool_name,用于文件系统)
|
||||
if (tool.toolName) {
|
||||
toolName = tool.toolName
|
||||
}
|
||||
// 否则从 componentPath 提取工具名称(格式:tools/{tool_name}/{tool_name}.vue)
|
||||
else if (tool.componentPath) {
|
||||
} else if (tool.componentPath) {
|
||||
const match = tool.componentPath.match(/tools\/([^\/]+)\//)
|
||||
if (match && match[1]) {
|
||||
toolName = match[1]
|
||||
@ -180,27 +168,19 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了工具名称,尝试删除文件系统
|
||||
if (toolName) {
|
||||
try {
|
||||
console.log('调用后端API删除工具文件,工具名称:', toolName)
|
||||
// 调用后端API删除工具文件
|
||||
const response = await axios.post(`/jingrow/uninstall-tool/${toolName}`, {}, {
|
||||
await axios.post(`/jingrow/uninstall-tool/${toolName}`, {}, {
|
||||
headers: {
|
||||
...get_session_api_headers()
|
||||
}
|
||||
})
|
||||
console.log('删除工具文件成功:', response.data)
|
||||
} catch (error: any) {
|
||||
console.error('删除工具文件失败:', error.response?.data || error.message || '未知错误')
|
||||
// 即使删除文件失败,也继续删除store中的工具
|
||||
}
|
||||
} else {
|
||||
console.log('无法确定工具名称,跳过文件删除')
|
||||
}
|
||||
|
||||
userTools.value = userTools.value.filter(t => t.id !== toolId)
|
||||
// 重新分配 order
|
||||
const defaultToolsCount = getDefaultTools().filter(
|
||||
t => !hiddenDefaultToolIds.value.includes(t.id)
|
||||
).length
|
||||
@ -209,13 +189,11 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
})
|
||||
saveUserTools(userTools.value)
|
||||
|
||||
// 移除路由(如果提供了 router)
|
||||
if (tool && tool.routeName && router) {
|
||||
unregisterToolRoute(router, tool.routeName)
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏默认工具
|
||||
function hideDefaultTool(toolId: string) {
|
||||
if (!hiddenDefaultToolIds.value.includes(toolId)) {
|
||||
hiddenDefaultToolIds.value.push(toolId)
|
||||
@ -223,13 +201,11 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 显示隐藏的默认工具
|
||||
function showDefaultTool(toolId: string) {
|
||||
hiddenDefaultToolIds.value = hiddenDefaultToolIds.value.filter(id => id !== toolId)
|
||||
saveHiddenDefaultTools(hiddenDefaultToolIds.value)
|
||||
}
|
||||
|
||||
// 更新用户工具顺序
|
||||
function updateUserToolsOrder(newOrder: Tool[]) {
|
||||
const defaultToolsCount = getDefaultTools().filter(
|
||||
t => !hiddenDefaultToolIds.value.includes(t.id)
|
||||
@ -243,7 +219,6 @@ export const useToolsStore = defineStore('tools', () => {
|
||||
saveUserTools(userTools.value)
|
||||
}
|
||||
|
||||
// 初始化工具路由(在应用启动时调用)
|
||||
function initToolRoutes(router: Router) {
|
||||
registerAllToolRoutes(router, userTools.value)
|
||||
}
|
||||
|
||||
@ -1,115 +1,65 @@
|
||||
/**
|
||||
* 动态路由管理工具
|
||||
* 用于动态注册和移除工具路由
|
||||
*/
|
||||
|
||||
import type { Router, RouteRecordRaw } from 'vue-router'
|
||||
import type { Tool } from '../stores/tools'
|
||||
|
||||
/**
|
||||
* 将 snake_case 转换为 PascalCase
|
||||
*/
|
||||
function snakeToPascal(snakeStr: string): string {
|
||||
const components = snakeStr.split('_')
|
||||
return components.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 tool_name 生成 routeName(PascalCase)
|
||||
*/
|
||||
function generateRouteName(toolName: string): string {
|
||||
return snakeToPascal(toolName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 tool_name 生成 routePath(约定:tools/{tool_name})
|
||||
*/
|
||||
function generateRoutePath(toolName: string): string {
|
||||
return `tools/${toolName}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保工具具有 routeName 和 routePath(如果缺失则自动生成)
|
||||
* 优先使用 tool.marketplaceId(即 tool_name),如果没有则使用 tool.name(工具显示名称)
|
||||
* 这样从市场安装的工具会使用 tool_name,手动添加的工具会使用 name
|
||||
*/
|
||||
export function ensureToolRoutes(tool: Tool): Tool {
|
||||
// 确定基础名称:优先使用 marketplaceId(即 tool_name,稳定标识符),如果没有则使用 name(工具显示名称),最后回退到 id
|
||||
const baseName = tool.marketplaceId || tool.name || tool.id
|
||||
const routeNameBase = tool.marketplaceId || tool.name || tool.id
|
||||
const routePathBase = tool.toolName || tool.marketplaceId || tool.name || tool.id
|
||||
|
||||
// 如果没有 routeName,基于基础名称生成
|
||||
if (!tool.routeName) {
|
||||
tool.routeName = generateRouteName(baseName)
|
||||
tool.routeName = generateRouteName(routeNameBase)
|
||||
}
|
||||
|
||||
// 如果没有 routePath,基于基础名称生成
|
||||
if (!tool.routePath) {
|
||||
tool.routePath = generateRoutePath(baseName)
|
||||
tool.routePath = generateRoutePath(routePathBase)
|
||||
}
|
||||
|
||||
return tool
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态注册工具路由
|
||||
* @param router Vue Router 实例
|
||||
* @param tool 工具定义
|
||||
* @param componentPath 组件路径(相对于 src/views)
|
||||
*/
|
||||
export function registerToolRoute(
|
||||
router: Router,
|
||||
tool: Tool,
|
||||
componentPath?: string
|
||||
): boolean {
|
||||
// 确保工具具有 routeName 和 routePath
|
||||
const toolWithRoutes = ensureToolRoutes({ ...tool })
|
||||
|
||||
// 如果没有 routeName,无法注册路由
|
||||
if (!toolWithRoutes.routeName) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查路由是否已存在
|
||||
if (router.hasRoute(toolWithRoutes.routeName)) {
|
||||
console.warn(`Route ${toolWithRoutes.routeName} already exists, skipping registration`)
|
||||
return false
|
||||
}
|
||||
|
||||
// 确定组件路径和路由路径
|
||||
// componentPath 格式:tools/{tool_name}/{tool_name}.vue(相对于 src/views)
|
||||
// 需要转换为相对于当前文件的路径:../../views/tools/{tool_name}/{tool_name}.vue
|
||||
let finalComponentPath: string
|
||||
if (componentPath) {
|
||||
// 如果 componentPath 已经是相对于 src/views 的路径(如 tools/test_tool/test_tool.vue)
|
||||
// 需要转换为相对于当前文件的路径
|
||||
finalComponentPath = `../../views/${componentPath}`
|
||||
} else if (toolWithRoutes.componentPath) {
|
||||
// 如果 tool 对象中有 componentPath
|
||||
finalComponentPath = `../../views/${toolWithRoutes.componentPath}`
|
||||
} else {
|
||||
// 默认路径:使用 toolName 或 id
|
||||
const toolDirName = toolWithRoutes.toolName || toolWithRoutes.id
|
||||
finalComponentPath = `../../views/tools/${toolDirName}/${toolDirName}.vue`
|
||||
}
|
||||
const routePath = toolWithRoutes.routePath || `tools/${toolWithRoutes.toolName || toolWithRoutes.id}`
|
||||
|
||||
// 创建路由配置,添加组件加载错误处理
|
||||
console.log(`Registering tool route:`, {
|
||||
routeName: toolWithRoutes.routeName,
|
||||
routePath,
|
||||
componentPath: finalComponentPath,
|
||||
toolName: toolWithRoutes.toolName,
|
||||
id: toolWithRoutes.id
|
||||
})
|
||||
|
||||
const route: RouteRecordRaw = {
|
||||
path: routePath,
|
||||
name: toolWithRoutes.routeName,
|
||||
component: () => {
|
||||
console.log(`Loading tool component from: ${finalComponentPath}`)
|
||||
return import(finalComponentPath).catch((error) => {
|
||||
console.error(`Failed to load tool component: ${finalComponentPath}`, error)
|
||||
// 返回一个简单的错误组件,显示详细错误信息
|
||||
return {
|
||||
name: 'ToolComponentError',
|
||||
template: `
|
||||
@ -130,10 +80,7 @@ export function registerToolRoute(
|
||||
}
|
||||
|
||||
try {
|
||||
// 将路由添加到 AppLayout 的 children 下
|
||||
// AppLayout 路由应该在应用启动时已存在
|
||||
router.addRoute('AppLayout', route)
|
||||
console.log(`Tool route registered: ${toolWithRoutes.routeName} -> ${routePath}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error(`Failed to register tool route ${toolWithRoutes.routeName}:`, error)
|
||||
@ -141,11 +88,6 @@ export function registerToolRoute(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除工具路由
|
||||
* @param router Vue Router 实例
|
||||
* @param routeName 路由名称
|
||||
*/
|
||||
export function unregisterToolRoute(router: Router, routeName: string): boolean {
|
||||
if (!router.hasRoute(routeName)) {
|
||||
return false
|
||||
@ -153,7 +95,6 @@ export function unregisterToolRoute(router: Router, routeName: string): boolean
|
||||
|
||||
try {
|
||||
router.removeRoute(routeName)
|
||||
console.log(`Tool route removed: ${routeName}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error(`Failed to remove tool route ${routeName}:`, error)
|
||||
@ -161,19 +102,10 @@ export function unregisterToolRoute(router: Router, routeName: string): boolean
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册所有用户工具的路由
|
||||
* @param router Vue Router 实例
|
||||
* @param tools 工具列表
|
||||
*/
|
||||
export function registerAllToolRoutes(router: Router, tools: Tool[]): void {
|
||||
// 过滤出用户工具(routeName 会在 registerToolRoute 中自动生成)
|
||||
const routeTools = tools.filter(t => !t.isDefault)
|
||||
|
||||
routeTools.forEach(tool => {
|
||||
registerToolRoute(router, tool)
|
||||
registerToolRoute(router, tool, tool.componentPath)
|
||||
})
|
||||
|
||||
console.log(`Registered ${routeTools.length} tool routes`)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user