Browse Source

删除硬编码路由关系提取

master
hejl 4 days ago
parent
commit
2957f66929
  1. 2
      gofaster/app/dist/renderer/js/index.js
  2. 226
      gofaster/app/plugins/route-mapping-plugin.js
  3. 294
      gofaster/app/src/renderer/modules/route-sync/RouteCollector.js
  4. 348
      gofaster/app/src/renderer/modules/route-sync/RouteMapper.js
  5. 223
      gofaster/app/src/renderer/modules/route-sync/RouteSyncTest.vue
  6. 80
      gofaster/app/src/renderer/modules/route-sync/RouteUtils.js
  7. 116
      gofaster/app/src/renderer/modules/route-sync/test-route-collection.js

2
gofaster/app/dist/renderer/js/index.js vendored

@ -17198,7 +17198,7 @@ __webpack_require__.r(__webpack_exports__); @@ -17198,7 +17198,7 @@ __webpack_require__.r(__webpack_exports__);
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ (() => {
/******/ __webpack_require__.h = () => ("17ce5f2ab3e9e20d")
/******/ __webpack_require__.h = () => ("28e4d2ceb1f57c26")
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */

226
gofaster/app/plugins/route-mapping-plugin.js

@ -4,7 +4,7 @@ import * as parser from '@babel/parser' @@ -4,7 +4,7 @@ import * as parser from '@babel/parser'
import traverse from '@babel/traverse'
import { parse } from '@vue/compiler-sfc'
// 路由映射插件 - 真正利用AST解析和Vite编译时关系
// 路由映射插件 - 基于AST解析获取实际存在的路由关系,不进行规则推断
export function routeMappingPlugin() {
return {
name: 'route-mapping',
@ -21,7 +21,7 @@ export function routeMappingPlugin() { @@ -21,7 +21,7 @@ export function routeMappingPlugin() {
this.analyzeASTAndViteRelations()
},
// 利用AST和Vite编译时API分析关系
// 利用AST解析获取实际存在的路由关系
analyzeASTAndViteRelations() {
try {
// 1. 分析路由配置的AST
@ -33,20 +33,21 @@ export function routeMappingPlugin() { @@ -33,20 +33,21 @@ export function routeMappingPlugin() {
// 3. 分析服务文件的AST
const serviceASTs = this.analyzeServiceASTs()
// 4. 建立真实的调用关系
// 4. 建立真实的调用关系(只基于AST分析)
const callRelations = this.buildCallRelations(routerAST, componentASTs, serviceASTs)
// 5. 生成真实的路由映射
// 5. 生成基于实际关系的路由映射
const routeMappings = this.generateRealRouteMappings(callRelations)
// 6. 生成映射文件
this.generateRouteMappingFile(routeMappings)
console.log('✅ AST和Vite编译时关系分析完成')
console.log('✅ 基于AST的实际路由关系分析完成')
} catch (error) {
console.error('❌ AST和Vite编译时关系分析失败:', error)
// 回退到简单分析
this.fallbackToSimpleAnalysis()
console.error('❌ AST路由关系分析失败:', error)
// AST分析失败时直接记录错误,不进行回退分析
console.error('❌ 路由映射生成失败,请检查代码结构和依赖')
throw error
}
},
@ -334,7 +335,7 @@ export function routeMappingPlugin() { @@ -334,7 +335,7 @@ export function routeMappingPlugin() {
return relations
},
// 生成真实的路由映射
// 生成基于实际关系的路由映射(不进行规则推断)
generateRealRouteMappings(callRelations) {
const mappings = {
mainRoutes: [],
@ -343,7 +344,7 @@ export function routeMappingPlugin() { @@ -343,7 +344,7 @@ export function routeMappingPlugin() {
callRelations: callRelations
}
// 生成主路由
// 生成主路由(基于实际路由配置)
callRelations.routes.forEach(route => {
mappings.mainRoutes.push({
path: route.path,
@ -355,7 +356,7 @@ export function routeMappingPlugin() { @@ -355,7 +356,7 @@ export function routeMappingPlugin() {
})
})
// 生成API映射
// 生成API映射(基于实际API调用)
callRelations.services.forEach((serviceAnalysis, serviceName) => {
const moduleName = this.extractModuleFromService(serviceName)
if (moduleName && serviceAnalysis.apiCalls.length > 0) {
@ -364,26 +365,25 @@ export function routeMappingPlugin() { @@ -364,26 +365,25 @@ export function routeMappingPlugin() {
}
})
// 生成子路由映射
// 生成子路由映射(基于实际调用关系)
mappings.subRouteMappings = this.generateSubRouteMappingsFromRelations(callRelations)
return mappings
},
// 从实调用构建API映射
// 从实际API调用构建API映射(不进行操作推断)
buildApiMappingFromRealCalls(apiCalls, moduleName) {
const operations = {}
const paths = []
apiCalls.forEach(call => {
const operation = this.inferOperationFromApiCall(call.path, call.method)
if (operation) {
operations[operation] = {
path: call.path,
method: call.method
}
paths.push(call.path)
// 使用实际的API路径作为操作名,不进行推断
const operationKey = `${call.method}_${call.path.replace(/[^a-zA-Z0-9]/g, '_')}`
operations[operationKey] = {
path: call.path,
method: call.method
}
paths.push(call.path)
})
const basePath = this.extractBasePath(paths)
@ -394,56 +394,38 @@ export function routeMappingPlugin() { @@ -394,56 +394,38 @@ export function routeMappingPlugin() {
}
},
// 从API调用推断操作
// 从API调用获取实际操作(不进行推断)
inferOperationFromApiCall(path, method) {
const pathLower = path.toLowerCase()
// 根据路径模式推断操作
if (path.includes('/:id') || path.includes('/{id}')) {
if (method === 'GET') return 'detail'
if (method === 'PUT') return 'update'
if (method === 'DELETE') return 'delete'
}
if (path.includes('/search')) return 'search'
if (path.includes('/filter')) return 'filter'
if (path.includes('/roles')) return 'getRoles'
if (path.includes('/permissions')) return 'getPermissions'
if (path.includes('/assign')) return 'assignRoles'
if (path.includes('/remove')) return 'removeRoles'
// 根据HTTP方法推断
if (method === 'GET' && !path.includes('/')) return 'list'
if (method === 'POST' && !path.includes('/')) return 'create'
if (method === 'PUT' && !path.includes('/')) return 'update'
if (method === 'DELETE' && !path.includes('/')) return 'delete'
// 默认操作名
return `${method.toLowerCase()}_${path.replace(/[^a-zA-Z0-9]/g, '_')}`
// 只返回实际存在的路径,不进行规则推断
return path
},
// 从关系生成子路由映射
// 从关系生成子路由映射(只基于实际存在的调用关系)
generateSubRouteMappingsFromRelations(callRelations) {
const subRouteMappings = {}
callRelations.callGraph.forEach((calls, componentName) => {
calls.forEach(call => {
if (call.type === 'service') {
const operation = this.inferOperationFromServiceMethod(call.method)
if (operation && operation !== 'list') {
// 找到对应的主路由
const mainRoute = callRelations.routes.find(route =>
route.component === componentName ||
route.name.toLowerCase().includes(componentName.toLowerCase())
)
// 只记录实际存在的服务调用,不生成预估的子路由
const serviceName = call.target
const methodName = call.method
// 检查服务是否真实存在
if (callRelations.services.has(serviceName)) {
const serviceAnalysis = callRelations.services.get(serviceName)
if (mainRoute) {
const subPath = `${mainRoute.path}/${operation}`
subRouteMappings[subPath] = {
mainRoute: mainRoute.path,
operation: operation
// 只记录实际存在的API调用
serviceAnalysis.apiCalls.forEach(apiCall => {
const key = `${componentName}_${serviceName}_${methodName}`
subRouteMappings[key] = {
component: componentName,
service: serviceName,
method: methodName,
apiPath: apiCall.path,
apiMethod: apiCall.method
}
}
})
}
}
})
@ -452,51 +434,9 @@ export function routeMappingPlugin() { @@ -452,51 +434,9 @@ export function routeMappingPlugin() {
return subRouteMappings
},
// 回退到简单分析
fallbackToSimpleAnalysis() {
console.log('⚠ 使用简单分析作为回退...')
const mappings = {
mainRoutes: [],
moduleApiMappings: {},
subRouteMappings: {},
method: 'simple-analysis'
}
// 简单的路由提取
const routerPath = resolve(__dirname, '../src/renderer/router/index.js')
if (fs.existsSync(routerPath)) {
const content = fs.readFileSync(routerPath, 'utf-8')
mappings.mainRoutes = this.simpleRouteExtraction(content)
}
this.generateRouteMappingFile(mappings)
console.log('✅ 简单分析完成')
},
// 简单的路由提取
simpleRouteExtraction(content) {
const routes = []
const routeRegex = /path:\s*['"`]([^'"`]+)['"`]/g
const nameRegex = /name:\s*['"`]([^'"`]+)['"`]/g
let match
while ((match = routeRegex.exec(content)) !== null) {
const path = match[1]
const nameMatch = nameRegex.exec(content)
const name = nameMatch ? nameMatch[1] : path.split('/').pop()
routes.push({
path,
name,
module: this.extractModuleFromPath(path),
description: this.generateDescription(name, this.extractModuleFromPath(path)),
type: this.determineRouteType(path, this.extractModuleFromPath(path))
})
}
return routes
},
// 查找组件文件
findComponentFiles() {
@ -579,34 +519,23 @@ export function routeMappingPlugin() { @@ -579,34 +519,23 @@ export function routeMappingPlugin() {
return null
},
// 从服务方法推断操作
// 从服务方法获取实际操作(不进行推断)
inferOperationFromServiceMethod(methodName) {
const methodMap = {
'getUsers': 'list',
'getUser': 'detail',
'createUser': 'create',
'updateUser': 'update',
'deleteUser': 'delete',
'getRoles': 'getRoles',
'getRole': 'detail',
'createRole': 'create',
'updateRole': 'update',
'deleteRole': 'delete',
'getPermissions': 'getPermissions'
}
return methodMap[methodName] || methodName
// 只返回实际存在的方法名,不进行硬编码映射
return methodName
},
// 从服务名提取模块名
// 从服务名提取模块名(基于实际文件路径)
extractModuleFromService(serviceName) {
const serviceMap = {
'userService': 'user-management',
'roleService': 'role-management',
'settingsService': 'system-settings'
// 通过实际文件路径来确定模块,而不是硬编码映射
const serviceFiles = this.findServiceFiles()
const serviceFile = serviceFiles.find(file => file.name === serviceName)
if (serviceFile) {
return serviceFile.module
}
return serviceMap[serviceName] || null
return null
},
// 提取basePath
@ -638,61 +567,40 @@ export function routeMappingPlugin() { @@ -638,61 +567,40 @@ export function routeMappingPlugin() {
return commonPrefix
},
// 从路径提取模块名
// 从路径提取模块名(基于实际路由配置)
extractModuleFromPath(path) {
if (path === '/' || path === '') return 'home'
const segments = path.split('/').filter(Boolean)
if (segments.length === 0) return 'home'
// 获取第一个段作为模块名
const module = segments[0]
// 映射模块名
const moduleMap = {
'user-management': 'user-management',
'role-management': 'role-management',
'settings': 'system-settings',
'user-profile': 'user-management',
'route-sync-test': 'route-sync'
}
return moduleMap[module] || module
// 获取第一个段作为模块名,不进行硬编码映射
return segments[0]
},
// 生成路由描述
// 生成路由描述(基于实际名称)
generateDescription(name, module) {
const descriptions = {
'home': '首页',
'user-management': '用户管理',
'role-management': '角色管理',
'system-settings': '系统设置',
'route-sync': '路由同步测试'
}
return descriptions[module] || `${name}页面`
// 只使用实际的路由名称,不进行硬编码描述
return `${name}页面`
},
// 确定路由类型
// 确定路由类型(基于实际路径)
determineRouteType(path, module) {
if (path === '/' || path === '') return 'home'
// 根据模块确定类型
const typeMap = {
'user-management': 'list',
'role-management': 'list',
'system-settings': 'form',
'route-sync': 'test'
// 基于实际路径结构确定类型,不进行硬编码映射
if (path.includes('/:') || path.includes('/{')) {
return 'detail'
}
return typeMap[module] || 'list'
return 'list'
},
// 生成路由映射文件
generateRouteMappingFile(routeMappings) {
const mappingContent = `// 自动生成的路由映射文件
// 此文件由 route-mapping-plugin 在构建时生成
// 基于AST解析和Vite编译时关系分析
// 基于AST解析获取实际存在的路由关系,不进行规则推断
// 请勿手动修改
export const mainRoutes = ${JSON.stringify(routeMappings.mainRoutes, null, 2)}
@ -723,7 +631,7 @@ export default { @@ -723,7 +631,7 @@ export default {
const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/generated-route-mapping.js')
fs.writeFileSync(outputPath, mappingContent, 'utf-8')
console.log(`✅ 基于AST解析的路由映射文件已生成: ${outputPath}`)
console.log(`✅ 基于AST实际路由关系的映射文件已生成: ${outputPath}`)
}
}
}

294
gofaster/app/src/renderer/modules/route-sync/RouteCollector.js

@ -1,13 +1,9 @@ @@ -1,13 +1,9 @@
// 路由收集器 - 收集前端路由信息
import router from '@/router'
import { RouteUtils } from './RouteUtils.js'
// 尝试导入生成的路由映射文件
let generatedMapping = null
try {
generatedMapping = require('./generated-route-mapping.js')
} catch (error) {
console.warn('⚠ 未找到生成的路由映射文件,使用默认收集逻辑')
}
// 加载生成的路由映射文件
const generatedMapping = RouteUtils.loadGeneratedMapping()
export class RouteCollector {
constructor() {
@ -23,9 +19,8 @@ export class RouteCollector { @@ -23,9 +19,8 @@ export class RouteCollector {
console.log('🔧 使用生成的路由映射文件')
this._collectFromGeneratedMapping()
} else {
console.log('🔧 使用默认路由收集逻辑')
this._collectFromRouter(router.getRoutes())
this._addPageOperationRoutes()
console.log('🔧 生成的路由映射文件不存在,无法收集路由')
console.warn('⚠ 请确保 route-mapping-plugin 已正确生成路由映射文件')
}
// 检查所有路由的模块信息
@ -45,8 +40,7 @@ export class RouteCollector { @@ -45,8 +40,7 @@ export class RouteCollector {
// 从生成的路由映射收集
_collectFromGeneratedMapping() {
if (!generatedMapping || !generatedMapping.mainRoutes) {
console.warn('⚠ 生成的路由映射文件无效,回退到默认逻辑')
this._collectFromRouter(router.getRoutes())
console.warn('⚠ 生成的路由映射文件无效,无法收集路由')
return
}
@ -63,289 +57,19 @@ export class RouteCollector { @@ -63,289 +57,19 @@ export class RouteCollector {
})
}
// 从Vue Router收集路由
_collectFromRouter(routes, parentPath = '') {
routes.forEach(route => {
console.log(`🔍 处理路由: path="${route.path}", parentPath="${parentPath}"`)
if (route.path && !route.path.startsWith('*')) {
const routeInfo = this._extractRouteInfo(route, parentPath)
if (routeInfo) {
console.log(`✅ 添加路由: ${routeInfo.path} -> 模块: ${routeInfo.module}`)
this.routes.push(routeInfo)
} else {
console.log(` 跳过路由: ${route.path}`)
}
}
// 递归处理子路由
if (route.children && route.children.length > 0) {
// 构建正确的父路径,避免双斜杠
let currentPath
if (parentPath && route.path) {
// 确保路径之间只有一个斜杠
currentPath = parentPath.endsWith('/') && route.path.startsWith('/')
? `${parentPath}${route.path.substring(1)}`
: `${parentPath}${route.path}`
} else {
currentPath = parentPath || route.path
}
console.log(`🔄 递归处理子路由,当前路径: ${currentPath}`)
this._collectFromRouter(route.children, currentPath)
}
})
}
// 添加页面内操作路由
_addPageOperationRoutes() {
console.log('🔍 开始添加页面内操作路由...')
// 用户管理页面的操作路由
this._addUserManagementOperations()
// 角色管理页面的操作路由
this._addRoleManagementOperations()
console.log('✅ 页面内操作路由添加完成')
}
// 添加用户管理页面的操作路由
_addUserManagementOperations() {
const userManagementRoute = this.routes.find(r => r.path === '/user-management')
if (!userManagementRoute) {
console.log('⚠ 未找到用户管理路由,跳过操作路由添加')
return
}
const operations = [
{
path: '/user-management/create',
name: 'CreateUser',
description: '新增用户',
operation: 'create'
},
{
path: '/user-management/edit',
name: 'EditUser',
description: '编辑用户',
operation: 'edit'
},
{
path: '/user-management/delete',
name: 'DeleteUser',
description: '删除用户',
operation: 'delete'
},
{
path: '/user-management/assign-roles',
name: 'AssignUserRoles',
description: '分配用户角色',
operation: 'assign-roles'
},
{
path: '/user-management/enable',
name: 'EnableUser',
description: '启用用户',
operation: 'enable'
},
{
path: '/user-management/disable',
name: 'DisableUser',
description: '禁用用户',
operation: 'disable'
}
]
operations.forEach(op => {
const operationRoute = {
path: op.path,
name: op.name,
component: 'UserManagementModal',
meta: { operation: op.operation },
module: 'user-management',
description: op.description,
isMenu: false,
sort: 0,
icon: '',
status: 1
}
console.log(`✅ 添加用户管理操作路由: ${op.path} -> ${op.description}`)
this.routes.push(operationRoute)
})
}
// 添加角色管理页面的操作路由
_addRoleManagementOperations() {
const roleManagementRoute = this.routes.find(r => r.path === '/role-management')
if (!roleManagementRoute) {
console.log('⚠ 未找到角色管理路由,跳过操作路由添加')
return
}
const operations = [
{
path: '/role-management/create',
name: 'CreateRole',
description: '新增角色',
operation: 'create'
},
{
path: '/role-management/edit',
name: 'EditRole',
description: '编辑角色',
operation: 'edit'
},
{
path: '/role-management/delete',
name: 'DeleteRole',
description: '删除角色',
operation: 'delete'
},
{
path: '/role-management/assign-permissions',
name: 'AssignRolePermissions',
description: '分配角色权限',
operation: 'assign-permissions'
}
]
operations.forEach(op => {
const operationRoute = {
path: op.path,
name: op.name,
component: 'RoleManagementModal',
meta: { operation: op.operation },
module: 'role-management',
description: op.description,
isMenu: false,
sort: 0,
icon: '',
status: 1
}
console.log(`✅ 添加角色管理操作路由: ${op.path} -> ${op.description}`)
this.routes.push(operationRoute)
})
}
// 提取路由信息
_extractRouteInfo(route, parentPath = '') {
// 构建完整路径,避免双斜杠
let fullPath
if (parentPath && route.path) {
// 确保路径之间只有一个斜杠
fullPath = parentPath.endsWith('/') && route.path.startsWith('/')
? `${parentPath}${route.path.substring(1)}`
: `${parentPath}${route.path}`
} else {
fullPath = parentPath || route.path
}
// 跳过通配符路径,但保留根路径的子路由
if (fullPath.includes('*')) {
return null
}
// 如果是根路径且没有子路由,跳过
if (fullPath === '/' && (!route.children || route.children.length === 0)) {
return null
}
return {
path: fullPath,
name: route.name || '',
component: route.component ? route.component.name || 'Unknown' : 'Unknown',
meta: route.meta || {},
module: this._extractModuleFromPath(fullPath),
description: this._generateDescription(route),
isMenu: this._isMenuRoute(route),
sort: route.meta?.sort || 0,
icon: route.meta?.icon || '',
status: 1
}
}
// 从路径中提取模块名
_extractModuleFromPath(path) {
// 移除开头的斜杠,并处理双斜杠
let cleanPath = path.startsWith('/') ? path.substring(1) : path
// 处理双斜杠情况
if (cleanPath.startsWith('/')) {
cleanPath = cleanPath.substring(1)
}
if (!cleanPath) {
console.log(`🔍 路径 "${path}" -> 模块 "core" (空路径)`)
return 'core'
}
// 分割路径
const parts = cleanPath.split('/')
const firstPart = parts[0]
// 映射常见的模块名
const moduleMap = {
'user-management': 'user-management',
'user-profile': 'user-management',
'role-management': 'role-management',
'settings': 'system-settings',
'system-settings': 'system-settings',
'route-sync-test': 'route-sync'
}
const module = moduleMap[firstPart] || firstPart
console.log(`🔍 路径 "${path}" -> 模块 "${module}" (firstPart: "${firstPart}")`)
return module
}
// 生成路由描述
_generateDescription(route) {
const name = route.name || ''
const path = route.path || ''
if (name) {
return `${name}页面`
}
// 根据路径生成描述
const pathParts = path.split('/').filter(p => p)
if (pathParts.length > 0) {
const lastPart = pathParts[pathParts.length - 1]
return `${lastPart}管理`
}
return '页面'
}
// 判断是否为菜单路由
_isMenuRoute(route) {
// 有name的路由通常是菜单路由
if (route.name) return true
// 有meta.menu的路由是菜单路由
if (route.meta && route.meta.menu) return true
// 没有子路由的路由通常是页面路由
if (!route.children || route.children.length === 0) return true
return false
return RouteUtils.extractModuleFromPath(path)
}
// 获取菜单路由
getMenuRoutes() {
return this.routes.filter(route => route.isMenu)
}
// 获取页面路由
getPageRoutes() {
return this.routes.filter(route => !route.isMenu)
return this.routes.filter(route => route.name && route.name !== '')
}
// 获取操作路由
getOperationRoutes() {
return this.routes.filter(route => route.meta && route.meta.operation)
return this.routes.filter(route => route.type && route.type !== 'list')
}
// 按模块分组路由

348
gofaster/app/src/renderer/modules/route-sync/RouteMapper.js

@ -1,73 +1,10 @@ @@ -1,73 +1,10 @@
// 路由映射器 - 将前端路由映射到后端API
import { RouteUtils } from './RouteUtils.js'
export class RouteMapper {
constructor() {
// 尝试导入生成的路由映射文件
let generatedMapping = null
try {
generatedMapping = require('./generated-route-mapping.js')
} catch (error) {
console.warn('⚠ 未找到生成的路由映射文件,使用默认API映射')
}
// 使用生成的API映射配置,如果没有则使用默认配置
this.defaultApiMappings = generatedMapping?.moduleApiMappings || {
'user-management': {
basePath: '/auth/admin/users',
operations: {
// 列表页面相关
list: { method: 'GET', path: '' },
search: { method: 'GET', path: '' },
filter: { method: 'GET', path: '' },
// 弹窗操作相关
create: { method: 'POST', path: '' },
update: { method: 'PUT', path: '/:id' },
delete: { method: 'DELETE', path: '/:id' },
detail: { method: 'GET', path: '/:id' },
// 角色分配相关
assignRoles: { method: 'POST', path: '/:id/roles' },
getRoles: { method: 'GET', path: '/roles' },
// 状态管理
enable: { method: 'PUT', path: '/:id/enable' },
disable: { method: 'PUT', path: '/:id/disable' }
}
},
'role-management': {
basePath: '/auth/roles',
operations: {
// 列表页面相关
list: { method: 'GET', path: '' },
search: { method: 'GET', path: '' },
// 弹窗操作相关
create: { method: 'POST', path: '' },
update: { method: 'PUT', path: '/:id' },
delete: { method: 'DELETE', path: '/:id' },
detail: { method: 'GET', path: '/:id' },
// 权限分配相关
assignPermissions: { method: 'POST', path: '/:id/permissions' },
getPermissions: { method: 'GET', path: '/permissions' }
}
},
'system-settings': {
basePath: '/auth/settings',
operations: {
list: { method: 'GET', path: '' },
update: { method: 'PUT', path: '' }
}
},
'route-sync': {
basePath: '/auth/route-sync',
operations: {
list: { method: 'GET', path: '' },
test: { method: 'POST', path: '/test' },
status: { method: 'GET', path: '/status' }
}
}
}
// 加载生成的路由映射文件
const generatedMapping = RouteUtils.loadGeneratedMapping()
// 保存子路由映射
this.subRouteMappings = generatedMapping?.subRouteMappings || {}
@ -119,189 +56,16 @@ export class RouteMapper { @@ -119,189 +56,16 @@ export class RouteMapper {
return mappings
}
// 获取模块的API配置
const apiConfig = this.defaultApiMappings[module]
if (!apiConfig) {
console.log(` 模块 "${module}" 没有预定义配置,使用默认映射`)
// 如果没有预定义配置,生成默认映射
mappings.push(this._createDefaultMapping(route))
return mappings
}
// 由于删除了硬编码的API映射,现在只生成基本的默认映射
console.log(`🔍 为模块 "${module}" 生成基本API映射`)
// 验证配置完整性
this._validateApiConfig(module, apiConfig)
console.log(`✅ 找到模块 "${module}" 的API配置:`, {
basePath: apiConfig.basePath,
operations: Object.keys(apiConfig.operations || {})
})
// 根据路由类型生成相应的API映射
const routeType = this._determineRouteType(route)
console.log(`🔍 路由类型: ${routeType}`)
// 为主路由添加子路由的操作
this._addSubRouteOperations(route, mappings)
switch (routeType) {
case 'list':
// 列表页面需要多个API支持
if (apiConfig.operations.list) {
const mapping = this._createApiMapping(route, apiConfig.operations.list)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.search) {
const mapping = this._createApiMapping(route, apiConfig.operations.search)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.filter) {
const mapping = this._createApiMapping(route, apiConfig.operations.filter)
if (mapping) mappings.push(mapping)
}
// 如果是用户管理,还需要角色相关的API
if (module === 'user-management' && apiConfig.operations.getRoles) {
const mapping = this._createApiMapping(route, apiConfig.operations.getRoles)
if (mapping) mappings.push(mapping)
}
break
case 'detail':
if (apiConfig.operations.detail) {
const mapping = this._createApiMapping(route, apiConfig.operations.detail)
if (mapping) mappings.push(mapping)
}
break
case 'form':
// 表单页面通常需要多个API
if (apiConfig.operations.create) {
const mapping = this._createApiMapping(route, apiConfig.operations.create)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.update) {
const mapping = this._createApiMapping(route, apiConfig.operations.update)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.detail) {
const mapping = this._createApiMapping(route, apiConfig.operations.detail)
if (mapping) mappings.push(mapping)
}
// 如果是用户管理,还需要角色相关的API
if (module === 'user-management' && apiConfig.operations.getRoles) {
const mapping = this._createApiMapping(route, apiConfig.operations.getRoles)
if (mapping) mappings.push(mapping)
}
break
case 'modal':
// 弹窗操作需要对应的CRUD API
if (apiConfig.operations.create) {
const mapping = this._createApiMapping(route, apiConfig.operations.create)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.update) {
const mapping = this._createApiMapping(route, apiConfig.operations.update)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.delete) {
const mapping = this._createApiMapping(route, apiConfig.operations.delete)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.detail) {
const mapping = this._createApiMapping(route, apiConfig.operations.detail)
if (mapping) mappings.push(mapping)
}
// 如果是用户管理,还需要角色相关的API
if (module === 'user-management') {
if (apiConfig.operations.getRoles) {
const mapping = this._createApiMapping(route, apiConfig.operations.getRoles)
if (mapping) mappings.push(mapping)
}
if (apiConfig.operations.assignRoles) {
const mapping = this._createApiMapping(route, apiConfig.operations.assignRoles)
if (mapping) mappings.push(mapping)
}
}
break
default:
console.log(` 未知路由类型 "${routeType}",使用默认映射`)
mappings.push(this._createDefaultMapping(route))
}
// 生成基本的CRUD API映射
mappings.push(this._createDefaultMapping(route))
console.log(`🔗 生成的映射数量: ${mappings.length}`)
return mappings
}
// 确定路由类型
_determineRouteType(route) {
const path = route.path.toLowerCase()
const name = route.name.toLowerCase()
// 检查是否是弹窗操作
if (path.includes('modal') || name.includes('modal')) return 'modal'
if (path.includes('dialog') || name.includes('dialog')) return 'modal'
if (path.includes('popup') || name.includes('popup')) return 'modal'
// 检查是否是表单操作
if (path.includes('form') || name.includes('form')) return 'form'
if (path.includes('create') || name.includes('create')) return 'form'
if (path.includes('edit') || name.includes('edit')) return 'form'
if (path.includes('add') || name.includes('add')) return 'form'
// 检查是否是详情页面
if (path.includes('detail') || name.includes('detail')) return 'detail'
if (path.includes('/:id') || path.includes('/edit')) return 'detail'
// 默认是列表页面
if (path.includes('list') || name.includes('list')) return 'list'
return 'list'
}
// 创建API映射
_createApiMapping(route, operation) {
// 安全检查
if (!operation) {
console.error(`❌ 操作配置为空,跳过创建映射: ${route.path}`)
return null
}
if (operation.path === undefined || !operation.method) {
console.error(`❌ 操作配置不完整,跳过创建映射: ${route.path}`, {
operation,
hasPath: operation.path !== undefined,
hasMethod: !!operation.method,
path: operation.path,
method: operation.method
})
return null
}
const module = route.module
const apiConfig = this.defaultApiMappings[module]
if (!apiConfig || !apiConfig.basePath) {
console.error(`❌ API配置不完整,跳过创建映射: ${route.path}`)
return null
}
const mapping = {
frontend_route: route.path,
backend_route: `${apiConfig.basePath}${operation.path}`,
http_method: operation.method,
module: module,
description: this._generateApiDescription(route, operation),
auth_group: this._getAuthGroup(operation.method),
status: 1
}
console.log(`🔗 创建API映射:`, mapping)
return mapping
}
// 创建默认映射
_createDefaultMapping(route) {
const mapping = {
@ -345,87 +109,7 @@ export class RouteMapper { @@ -345,87 +109,7 @@ export class RouteMapper {
// 从路径中提取模块名(备用方法)
_extractModuleFromPath(path) {
// 移除开头的斜杠,并处理双斜杠
let cleanPath = path.startsWith('/') ? path.substring(1) : path
// 处理双斜杠情况
if (cleanPath.startsWith('/')) {
cleanPath = cleanPath.substring(1)
}
if (!cleanPath) return 'core'
// 分割路径
const parts = cleanPath.split('/')
const firstPart = parts[0]
// 映射常见的模块名
const moduleMap = {
'user-management': 'user-management',
'user-profile': 'user-management',
'role-management': 'role-management',
'settings': 'system-settings',
'system-settings': 'system-settings',
'route-sync-test': 'route-sync'
}
return moduleMap[firstPart] || firstPart
}
// 添加自定义API映射规则
addApiMapping(module, config) {
this.defaultApiMappings[module] = config
}
// 获取模块的API映射配置
getApiMapping(module) {
return this.defaultApiMappings[module] || null
}
// 验证API配置的完整性
_validateApiConfig(module, apiConfig) {
if (!apiConfig.basePath) {
console.error(`❌ 模块 "${module}" 缺少 basePath`)
}
if (!apiConfig.operations) {
console.error(`❌ 模块 "${module}" 缺少 operations`)
return
}
Object.keys(apiConfig.operations).forEach(operationName => {
const operation = apiConfig.operations[operationName]
if (operation.path === undefined || !operation.method) {
console.error(`❌ 模块 "${module}" 的操作 "${operationName}" 配置不完整:`, {
hasPath: operation.path !== undefined,
hasMethod: !!operation.method,
path: operation.path,
method: operation.method
})
}
})
}
// 为主路由添加子路由的操作
_addSubRouteOperations(route, mappings) {
const module = route.module
// 查找该模块的所有子路由
Object.entries(this.subRouteMappings).forEach(([subRoutePath, mapping]) => {
if (mapping.mainRoute === route.path) {
console.log(`🔗 为主路由 ${route.path} 添加子路由操作: ${mapping.operation}`)
// 获取API配置
const apiConfig = this.defaultApiMappings[module]
if (apiConfig && apiConfig.operations[mapping.operation]) {
const operation = apiConfig.operations[mapping.operation]
const apiMapping = this._createApiMapping(route, operation)
if (apiMapping) {
mappings.push(apiMapping)
}
}
}
})
return RouteUtils.extractModuleFromPath(path)
}
// 验证映射的完整性
@ -443,17 +127,9 @@ export class RouteMapper { @@ -443,17 +127,9 @@ export class RouteMapper {
description: mapping.description
})
if (!mapping.frontend_route) {
errors.push(`映射 ${index}: 缺少前端路由`)
}
if (!mapping.backend_route) {
errors.push(`映射 ${index}: 缺少后端路由`)
}
if (!mapping.http_method) {
errors.push(`映射 ${index}: 缺少HTTP方法`)
}
if (!mapping.module) {
errors.push(`映射 ${index}: 缺少模块信息 - 前端路由: ${mapping.frontend_route}`)
const validation = RouteUtils.validateMapping(mapping, index)
if (!validation.isValid) {
errors.push(...validation.errors)
}
})

223
gofaster/app/src/renderer/modules/route-sync/RouteSyncTest.vue

@ -1,223 +0,0 @@ @@ -1,223 +0,0 @@
<template>
<div class="route-sync-test">
<h2>路由同步测试</h2>
<div class="test-section">
<h3>1. 路由收集测试</h3>
<button @click="testRouteCollection" :disabled="loading">测试路由收集</button>
<div v-if="routeCollectionResult" class="result">
<h4>收集结果:</h4>
<pre>{{ JSON.stringify(routeCollectionResult, null, 2) }}</pre>
</div>
</div>
<div class="test-section">
<h3>2. 路由映射测试</h3>
<button @click="testRouteMapping" :disabled="loading">测试路由映射</button>
<div v-if="routeMappingResult" class="result">
<h4>映射结果:</h4>
<pre>{{ JSON.stringify(routeMappingResult, null, 2) }}</pre>
</div>
</div>
<div class="test-section">
<h3>3. 路由同步测试</h3>
<button @click="testRouteSync" :disabled="loading">测试路由同步</button>
<div v-if="syncResult" class="result">
<h4>同步结果:</h4>
<pre>{{ JSON.stringify(syncResult, null, 2) }}</pre>
</div>
</div>
<div class="test-section">
<h3>4. 手动同步</h3>
<button @click="manualSync" :disabled="loading">手动同步</button>
<div v-if="manualSyncResult" class="result">
<h4>手动同步结果:</h4>
<pre>{{ JSON.stringify(manualSyncResult, null, 2) }}</pre>
</div>
</div>
<div class="loading" v-if="loading">
<p>正在执行测试...</p>
</div>
</div>
</template>
<script>
import { RouteCollector } from './RouteCollector'
import { RouteMapper } from './RouteMapper'
import { RouteSyncService } from './RouteSyncService'
import routeSyncManager from './RouteSyncManager'
export default {
name: 'RouteSyncTest',
data() {
return {
loading: false,
routeCollectionResult: null,
routeMappingResult: null,
syncResult: null,
manualSyncResult: null
}
},
methods: {
async testRouteCollection() {
this.loading = true
try {
const collector = new RouteCollector()
const routes = collector.collectRoutes()
this.routeCollectionResult = {
totalRoutes: routes.length,
routes: routes,
menuRoutes: collector.getMenuRoutes(),
routesByModule: collector.getRoutesByModule()
}
console.log('✅ 路由收集测试完成')
} catch (error) {
console.error('❌ 路由收集测试失败:', error)
this.routeCollectionResult = { error: error.message }
} finally {
this.loading = false
}
},
async testRouteMapping() {
this.loading = true
try {
const collector = new RouteCollector()
const routes = collector.collectRoutes()
const mapper = new RouteMapper()
const mappings = mapper.generateRouteMappings(routes)
const validation = mapper.validateMappings(mappings)
this.routeMappingResult = {
totalMappings: mappings.length,
mappings: mappings,
validation: validation,
isValid: validation.isValid
}
console.log('✅ 路由映射测试完成')
} catch (error) {
console.error('❌ 路由映射测试失败:', error)
this.routeMappingResult = { error: error.message }
} finally {
this.loading = false
}
},
async testRouteSync() {
this.loading = true
try {
const syncService = new RouteSyncService('http://localhost:8080')
const success = await syncService.syncRoutes()
this.syncResult = {
success: success,
syncStatus: syncService.getSyncStatus(),
syncStats: syncService.getSyncStats()
}
console.log('✅ 路由同步测试完成')
} catch (error) {
console.error('❌ 路由同步测试失败:', error)
this.syncResult = { error: error.message }
} finally {
this.loading = false
}
},
async manualSync() {
this.loading = true
try {
const success = await routeSyncManager.manualSync()
this.manualSyncResult = {
success: success,
syncStatus: routeSyncManager.getSyncStatus(),
syncStats: routeSyncManager.getSyncStats()
}
console.log('✅ 手动同步完成')
} catch (error) {
console.error('❌ 手动同步失败:', error)
this.manualSyncResult = { error: error.message }
} finally {
this.loading = false
}
}
}
}
</script>
<style scoped>
.route-sync-test {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.test-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #f9f9f9;
}
.test-section h3 {
margin-top: 0;
color: #333;
}
button {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
.result {
margin-top: 15px;
padding: 15px;
background-color: white;
border-radius: 4px;
border: 1px solid #ddd;
}
.result h4 {
margin-top: 0;
color: #333;
}
.result pre {
background-color: #f8f9fa;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
font-size: 12px;
line-height: 1.4;
}
.loading {
text-align: center;
padding: 20px;
color: #666;
}
</style>

80
gofaster/app/src/renderer/modules/route-sync/RouteUtils.js

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// 路由同步工具类 - 提供公共的工具方法
export class RouteUtils {
// 统一的模块名提取方法
static extractModuleFromPath(path) {
// 移除开头的斜杠,并处理双斜杠
let cleanPath = path.startsWith('/') ? path.substring(1) : path
// 处理双斜杠情况
if (cleanPath.startsWith('/')) {
cleanPath = cleanPath.substring(1)
}
if (!cleanPath) {
console.log(`🔍 路径 "${path}" -> 模块 "core" (空路径)`)
return 'core'
}
// 分割路径,直接使用第一部分作为模块名
const parts = cleanPath.split('/')
const firstPart = parts[0]
console.log(`🔍 路径 "${path}" -> 模块 "${firstPart}"`)
return firstPart
}
// 统一的文件导入方法
static loadGeneratedMapping() {
try {
const mapping = require('./generated-route-mapping.js')
console.log('✅ 成功加载生成的路由映射文件')
return mapping
} catch (error) {
console.warn('⚠ 未找到生成的路由映射文件')
return null
}
}
// 验证路由对象完整性
static validateRoute(route, index = 0) {
const errors = []
if (!route.path) {
errors.push(`路由 ${index}: 缺少路径信息`)
}
if (!route.module) {
errors.push(`路由 ${index}: 缺少模块信息`)
}
if (!route.description) {
errors.push(`路由 ${index}: 缺少描述信息`)
}
return {
isValid: errors.length === 0,
errors
}
}
// 验证映射对象完整性
static validateMapping(mapping, index = 0) {
const errors = []
if (!mapping.frontend_route) {
errors.push(`映射 ${index}: 缺少前端路由`)
}
if (!mapping.backend_route) {
errors.push(`映射 ${index}: 缺少后端路由`)
}
if (!mapping.http_method) {
errors.push(`映射 ${index}: 缺少HTTP方法`)
}
if (!mapping.module) {
errors.push(`映射 ${index}: 缺少模块信息`)
}
return {
isValid: errors.length === 0,
errors
}
}
}

116
gofaster/app/src/renderer/modules/route-sync/test-route-collection.js

@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
// 测试路由收集功能
import { RouteCollector } from './RouteCollector'
import { RouteMapper } from './RouteMapper'
import { RouteSyncService } from './RouteSyncService'
// 模拟路由数据(基于实际的路由结构)
const mockRoutes = [
{
path: '/',
component: { name: 'MainLayout' },
children: [
{
path: '',
name: 'Home',
component: { name: 'Home' }
},
{
path: '/user-management',
name: 'UserManagement',
component: { name: 'UserManagement' }
},
{
path: '/settings',
name: 'Settings',
component: { name: 'Settings' }
},
{
path: '/user-profile',
name: 'UserProfile',
component: { name: 'UserProfile' }
},
{
path: '/role-management',
name: 'RoleManagement',
component: { name: 'RoleManagement' }
}
]
}
]
// 测试路由收集
function testRouteCollection() {
console.log('🧪 开始测试路由收集...')
// 创建路由收集器
const collector = new RouteCollector()
// 模拟收集路由
collector.routes = []
collector._collectFromRouter(mockRoutes)
console.log('📋 收集到的路由:')
collector.routes.forEach((route, index) => {
console.log(`${index + 1}. ${route.path} (${route.name}) - ${route.module}`)
})
// 测试路由映射
const mapper = new RouteMapper()
const mappings = mapper.generateRouteMappings(collector.routes)
console.log('\n🔗 生成的路由映射:')
mappings.forEach((mapping, index) => {
console.log(`${index + 1}. ${mapping.frontendRoute} -> ${mapping.backendRoute} (${mapping.httpMethod})`)
})
return {
routes: collector.routes,
mappings: mappings
}
}
// 测试同步服务
async function testSyncService() {
console.log('\n🔄 开始测试同步服务...')
const syncService = new RouteSyncService('http://localhost:8080')
// 模拟收集路由
const collector = new RouteCollector()
collector.routes = []
collector._collectFromRouter(mockRoutes)
// 生成映射
const mapper = new RouteMapper()
const mappings = mapper.generateRouteMappings(collector.routes)
console.log(`📊 准备同步 ${mappings.length} 个路由映射`)
// 验证映射
const validation = mapper.validateMappings(mappings)
console.log(`✅ 映射验证: ${validation.isValid ? '通过' : '失败'}`)
if (!validation.isValid) {
console.log('❌ 验证错误:', validation.errors)
}
return {
isValid: validation.isValid,
mappings: mappings,
errors: validation.errors
}
}
// 导出测试函数
export { testRouteCollection, testSyncService }
// 如果直接运行此文件,执行测试
if (typeof window !== 'undefined') {
// 在浏览器环境中,将测试函数挂载到全局对象
window.testRouteCollection = testRouteCollection
window.testSyncService = testSyncService
console.log('🧪 路由收集测试函数已挂载到 window 对象')
console.log('使用方法:')
console.log(' testRouteCollection() - 测试路由收集')
console.log(' testSyncService() - 测试同步服务')
}
Loading…
Cancel
Save