|
|
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}`) |
|
|
} |
|
|
} |
|
|
}
|
|
|
|