You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

375 lines
13 KiB

import { resolve } from 'path'
import fs from 'fs'
// 路由映射插件
export function routeMappingPlugin() {
return {
name: 'route-mapping',
// 在构建开始时执行
buildStart() {
console.log('🔧 开始分析路由结构...')
this.analyzeRoutes()
},
// 在开发模式下也执行
configureServer(server) {
console.log('🔧 开发模式下分析路由结构...')
this.analyzeRoutes()
},
// 分析路由结构
analyzeRoutes() {
try {
const routerPath = resolve(__dirname, '../src/renderer/router/index.js')
const routerContent = fs.readFileSync(routerPath, 'utf-8')
// 解析路由配置
const routes = this.parseRoutes(routerContent)
// 生成主入口路由映射
const mainRoutes = this.generateMainRoutes(routes)
// 从实际服务文件中提取API映射
const moduleApiMappings = this.extractApiMappingsFromServices()
// 生成路由映射文件
this.generateRouteMappingFile(mainRoutes, moduleApiMappings)
console.log('✅ 路由映射分析完成')
} catch (error) {
console.error('❌ 路由映射分析失败:', error)
}
},
// 从实际服务文件中提取API映射
extractApiMappingsFromServices() {
const mappings = {}
// 用户管理服务
const userServicePath = resolve(__dirname, '../src/renderer/modules/user-management/services/userService.js')
console.log('🔍 检查用户服务文件路径:', userServicePath)
if (fs.existsSync(userServicePath)) {
console.log('✅ 找到用户服务文件')
const userServiceContent = fs.readFileSync(userServicePath, 'utf-8')
mappings['user-management'] = this.parseServiceFile(userServiceContent, 'user-management')
} else {
console.log('❌ 未找到用户服务文件')
}
// 角色管理服务
const roleServicePath = resolve(__dirname, '../src/renderer/modules/role-management/services/roleService.js')
console.log('🔍 检查角色服务文件路径:', roleServicePath)
if (fs.existsSync(roleServicePath)) {
console.log('✅ 找到角色服务文件')
const roleServiceContent = fs.readFileSync(roleServicePath, 'utf-8')
mappings['role-management'] = this.parseServiceFile(roleServiceContent, 'role-management')
} else {
console.log('❌ 未找到角色服务文件')
}
// 系统设置服务(如果存在)
const settingsServicePath = resolve(__dirname, '../src/renderer/modules/system-settings/services/settingsService.js')
console.log('🔍 检查系统设置服务文件路径:', settingsServicePath)
if (fs.existsSync(settingsServicePath)) {
console.log('✅ 找到系统设置服务文件')
const settingsServiceContent = fs.readFileSync(settingsServicePath, 'utf-8')
mappings['system-settings'] = this.parseServiceFile(settingsServiceContent, 'system-settings')
} else {
console.log('❌ 未找到系统设置服务文件')
}
console.log('🔍 从服务文件中提取的API映射:', mappings)
return mappings
},
// 解析服务文件中的API调用
parseServiceFile(content, moduleName) {
const operations = {}
console.log(`🔍 开始解析模块 "${moduleName}" 的服务文件...`)
// 匹配 api.get, api.post, api.put, api.delete 调用
const apiCallRegex = /api\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]/g
let match
let matchCount = 0
while ((match = apiCallRegex.exec(content)) !== null) {
const method = match[1].toUpperCase()
const path = match[2]
matchCount++
console.log(`🔍 找到API调用 ${matchCount}: ${method} ${path}`)
// 根据路径和方法推断操作类型
const operation = this.inferOperationFromPath(path, method)
if (operation) {
operations[operation] = {
path: path,
method: method
}
console.log(`✅ 映射操作: ${operation} -> ${method} ${path}`)
}
}
console.log(`📊 模块 "${moduleName}" 找到 ${matchCount} 个API调用,映射了 ${Object.keys(operations).length} 个操作`)
// 如果没有找到任何API调用,使用默认配置
if (Object.keys(operations).length === 0) {
console.log(` 模块 "${moduleName}" 未找到API调用,使用默认配置`)
return this.getDefaultApiMapping(moduleName)
}
// 提取basePath(取第一个路径的共同前缀)
const basePath = this.extractBasePath(Object.values(operations).map(op => op.path))
console.log(`🔍 提取的basePath: ${basePath}`)
return {
basePath: basePath,
operations: operations
}
},
// 从路径推断操作类型
inferOperationFromPath(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'
if (path.includes('/enable')) return 'enable'
if (path.includes('/disable')) return 'disable'
if (path.includes('/change-password')) return 'changePassword'
if (path.includes('/password-policy')) return 'getPasswordPolicy'
if (path.includes('/validate-password')) return 'validatePassword'
if (path.includes('/password-status')) return 'checkPasswordStatus'
if (path.includes('/captcha')) return 'getCaptcha'
if (path.includes('/login')) return 'login'
if (path.includes('/logout')) return 'logout'
if (path.includes('/current-user')) return 'getCurrentUser'
// 根据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, '_')}`
},
// 提取basePath
extractBasePath(paths) {
if (paths.length === 0) return ''
// 找到所有路径的共同前缀
const firstPath = paths[0]
let commonPrefix = ''
for (let i = 0; i < firstPath.length; i++) {
const char = firstPath[i]
if (paths.every(path => path[i] === char)) {
commonPrefix += char
} else {
break
}
}
// 如果找到了完整的前缀,返回它
if (commonPrefix && !commonPrefix.endsWith('/')) {
// 找到最后一个斜杠的位置
const lastSlashIndex = commonPrefix.lastIndexOf('/')
if (lastSlashIndex > 0) {
return commonPrefix.substring(0, lastSlashIndex + 1)
}
}
return commonPrefix
},
// 获取默认API映射(当无法从服务文件提取时)
getDefaultApiMapping(moduleName) {
const defaults = {
'user-management': {
basePath: '/auth/admin/users',
operations: {
list: { path: '', method: 'GET' },
create: { path: '', method: 'POST' },
update: { path: '/:id', method: 'PUT' },
delete: { path: '/:id', method: 'DELETE' },
detail: { path: '/:id', method: 'GET' }
}
},
'role-management': {
basePath: '/auth/roles',
operations: {
list: { path: '', method: 'GET' },
create: { path: '', method: 'POST' },
update: { path: '/:id', method: 'PUT' },
delete: { path: '/:id', method: 'DELETE' },
detail: { path: '/:id', method: 'GET' }
}
},
'system-settings': {
basePath: '/auth/settings',
operations: {
list: { path: '', method: 'GET' },
update: { path: '', method: 'PUT' }
}
}
}
return defaults[moduleName] || {
basePath: `/api/${moduleName}`,
operations: {
list: { path: '', method: 'GET' }
}
}
},
// 解析路由配置
parseRoutes(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)
})
}
return routes
},
// 从路径提取模块名
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
},
// 生成主入口路由
generateMainRoutes(routes) {
const mainRoutes = []
const processedModules = new Set()
routes.forEach(route => {
const module = route.module
// 只处理主入口路由,避免重复
if (!processedModules.has(module)) {
mainRoutes.push({
path: route.path,
name: route.name,
module: module,
description: this.generateDescription(route.name, module),
type: this.determineRouteType(route.path, module)
})
processedModules.add(module)
}
})
return mainRoutes
},
// 生成路由描述
generateDescription(name, module) {
const descriptions = {
'home': '首页',
'user-management': '用户管理',
'role-management': '角色管理',
'system-settings': '系统设置',
'route-sync': '路由同步测试'
}
return descriptions[module] || `${name}页面`
},
// 确定路由类型
determineRouteType(path, module) {
if (path === '/' || path === '') return 'home'
// 根据模块确定类型
const typeMap = {
'user-management': 'list',
'role-management': 'list',
'system-settings': 'form',
'route-sync': 'test'
}
return typeMap[module] || 'list'
},
// 生成路由映射文件
generateRouteMappingFile(mainRoutes, moduleApiMappings) {
const mappingContent = `// 自动生成的路由映射文件
// 此文件由 route-mapping-plugin 在构建时生成
// 请勿手动修改
export const mainRoutes = ${JSON.stringify(mainRoutes, null, 2)}
// 模块到API映射配置(从实际服务文件中提取)
export const moduleApiMappings = ${JSON.stringify(moduleApiMappings, null, 2)}
// 子路由到主路由的映射
export const subRouteMappings = {
'/user-management/create': { mainRoute: '/user-management', operation: 'create' },
'/user-management/edit': { mainRoute: '/user-management', operation: 'update' },
'/user-management/delete': { mainRoute: '/user-management', operation: 'delete' },
'/user-management/detail': { mainRoute: '/user-management', operation: 'detail' },
'/role-management/create': { mainRoute: '/role-management', operation: 'create' },
'/role-management/edit': { mainRoute: '/role-management', operation: 'update' },
'/role-management/delete': { mainRoute: '/role-management', operation: 'delete' },
'/role-management/detail': { mainRoute: '/role-management', operation: 'detail' }
}
export default {
mainRoutes,
moduleApiMappings,
subRouteMappings
}
`
const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/generated-route-mapping.js')
fs.writeFileSync(outputPath, mappingContent, 'utf-8')
console.log(`✅ 路由映射文件已生成: ${outputPath}`)
}
}
}