From c28faf3bc5e1076d48883840e054519ff6402cc5 Mon Sep 17 00:00:00 2001 From: hejl Date: Fri, 5 Sep 2025 13:51:01 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B7=AF=E7=94=B1=E6=94=B6=E9=9B=86=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gofaster/app/dev-enhanced.ps1 | 15 + gofaster/app/dist/renderer/js/index.js | 184 +++- gofaster/app/package.json | 2 +- gofaster/app/plugins/route-mapping-plugin.js | 194 ++++- .../app/scripts/generate-route-mappings.js | 21 +- gofaster/app/src/renderer/main.js | 16 +- .../modules/route-sync/RouteCollector.js | 14 + .../modules/route-sync/RouteConfig.js | 2 +- .../modules/route-sync/RouteMapper.js | 97 ++- .../modules/route-sync/RouteSyncManager.js | 53 +- .../route-sync/direct-route-mappings.js | 796 ++++++++++++++++++ gofaster/app/vue.config.js | 19 +- gofaster/dev-full.ps1 | 23 + gofaster/start-enhanced.ps1 | 133 +++ gofaster/test-route-sync-fix.ps1 | 92 ++ gofaster/test-route-sync-optimization.ps1 | 88 ++ 16 files changed, 1675 insertions(+), 74 deletions(-) create mode 100644 gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js create mode 100644 gofaster/start-enhanced.ps1 create mode 100644 gofaster/test-route-sync-fix.ps1 create mode 100644 gofaster/test-route-sync-optimization.ps1 diff --git a/gofaster/app/dev-enhanced.ps1 b/gofaster/app/dev-enhanced.ps1 index 42c9d54..7d5f8e4 100644 --- a/gofaster/app/dev-enhanced.ps1 +++ b/gofaster/app/dev-enhanced.ps1 @@ -54,6 +54,21 @@ if (-not $crossEnvInstalled) { Write-Host "✅ 依赖检查完成" -ForegroundColor Green Write-Host "" +# 生成路由映射文件 +Write-Host "🔧 生成路由映射文件..." -ForegroundColor Yellow +try { + node scripts/generate-route-mappings.js + if ($LASTEXITCODE -ne 0) { + Write-Host "❌ 路由映射生成失败" -ForegroundColor Red + exit 1 + } + Write-Host "✅ 路由映射生成成功" -ForegroundColor Green +} catch { + Write-Host "❌ 路由映射生成失败: $($_.Exception.Message)" -ForegroundColor Red + exit 1 +} +Write-Host "" + # 选择运行模式 if ($Debug) { Write-Host "🐛 调试模式启动..." -ForegroundColor Magenta diff --git a/gofaster/app/dist/renderer/js/index.js b/gofaster/app/dist/renderer/js/index.js index 7835303..8f5e635 100644 --- a/gofaster/app/dist/renderer/js/index.js +++ b/gofaster/app/dist/renderer/js/index.js @@ -12207,8 +12207,13 @@ async function startApp() { // 4. 初始化路由同步管理器 console.log('🔄 初始化路由同步管理器...') - // 创建路由同步管理器实例 - const routeSyncManager = new _modules_route_sync__WEBPACK_IMPORTED_MODULE_6__["default"]() + // 使用单例模式创建路由同步管理器实例 + const routeSyncManager = _modules_route_sync__WEBPACK_IMPORTED_MODULE_6__["default"].getInstance({ + apiBaseUrl: 'http://localhost:8080', + autoSync: true, + syncInterval: 5 * 60 * 1000, // 5分钟 + retryAttempts: 3 + }) console.log('✅ 路由同步管理器实例创建成功:', routeSyncManager) // 检查RouteSyncService是否可用 @@ -12220,12 +12225,7 @@ async function startApp() { } if (routeSyncManager && typeof routeSyncManager.initialize === 'function') { - await routeSyncManager.initialize({ - apiBaseUrl: 'http://localhost:8080', - autoSync: true, - syncInterval: 5 * 60 * 1000, // 5分钟 - retryAttempts: 3 - }) + await routeSyncManager.initialize() console.log('✅ 路由同步管理器初始化完成') } else { console.error('❌ routeSyncManager 或 initialize 方法不可用') @@ -13834,14 +13834,26 @@ class RouteCollector { // 收集路由 collectRoutes() { try { + console.log('🔄 开始收集路由...') + console.log('📊 directRouteMappings:', _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings) + console.log('📊 directRouteMappings类型:', typeof _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings) + console.log('📊 directRouteMappings是否为undefined:', _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings === undefined) + // 从生成的路由映射文件收集 if (!_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings || !_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings.pageMappings) { console.warn('⚠️ 生成的路由映射文件格式不正确') + console.log('🔍 调试信息:') + console.log(' - directRouteMappings:', _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings) + console.log(' - pageMappings:', _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings?.pageMappings) + console.log(' - 导入是否成功:', _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings !== undefined) return [] } + console.log(`📊 找到 ${_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings.pageMappings.length} 个页面映射`) + // 从页面映射中提取路由信息 const frontendRoutes = _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings.pageMappings.map(mapping => { + console.log(`📋 处理页面映射: ${mapping.route} (${mapping.component})`) return { path: mapping.route, name: mapping.routeName, @@ -13854,9 +13866,11 @@ class RouteCollector { }) this.routes = frontendRoutes + console.log(`✅ 成功收集到 ${frontendRoutes.length} 个前端路由`) return frontendRoutes } catch (error) { console.error('❌ 从生成的路由映射文件收集路由失败:', error) + console.error('错误堆栈:', error.stack) return [] } } @@ -13910,7 +13924,7 @@ const RouteConfig = { 'user-management': '用户管理', 'role-management': '角色管理', 'system-settings': '系统设置', - 'route-sync': '路由同步测试' + 'route-sync': '路由同步' }, // 路由类型映射 @@ -14042,7 +14056,7 @@ __webpack_require__.r(__webpack_exports__); class RouteMapper { constructor() { - this.defaultApiMappings = _RouteConfig_js__WEBPACK_IMPORTED_MODULE_0__.RouteConfig.defaultApiMappings + // 不再依赖硬编码的默认配置 } // 生成路由映射 @@ -14067,29 +14081,90 @@ class RouteMapper { return mappings } - // 检查是否有子路由映射 - const subRouteMapping = this._getSubRouteMapping(route.path) - if (subRouteMapping) { - const mapping = this._createApiMapping(route, subRouteMapping.operation) - if (mapping) { - mappings.push(mapping) - } + // 只使用从direct-route-mappings.js中获取的API调用信息 + if (route.apiCalls && route.apiCalls.length > 0) { + route.apiCalls.forEach(apiCall => { + const mapping = this._createApiMappingFromDirectCall(route, apiCall) + if (mapping) { + mappings.push(mapping) + } + }) } else { - // 生成基本API映射 - const apiConfig = this._getApiConfigForModule(module) - if (apiConfig && apiConfig.operations) { - Object.keys(apiConfig.operations).forEach(operation => { - const mapping = this._createApiMapping(route, operation) - if (mapping) { - mappings.push(mapping) - } - }) - } + console.warn(`⚠️ 路由 ${route.path} 没有API调用信息`) } return mappings } + // 从直接API调用创建映射 + _createApiMappingFromDirectCall(route, apiCall) { + const module = route.module + + if (!apiCall || !apiCall.service || !apiCall.method) { + return null + } + + // 根据服务类型和方法生成后端路由 + let backendRoute = '/api' + let httpMethod = 'GET' + + if (apiCall.service === 'userService') { + backendRoute = '/api/users' + if (apiCall.method === 'getUsers') { + httpMethod = 'GET' + } else if (apiCall.method === 'createUser') { + httpMethod = 'POST' + } else if (apiCall.method === 'updateUser') { + httpMethod = 'PUT' + backendRoute = '/api/users/:id' + } else if (apiCall.method === 'deleteUser') { + httpMethod = 'DELETE' + backendRoute = '/api/users/:id' + } else if (apiCall.method === 'getCurrentUser') { + httpMethod = 'GET' + backendRoute = '/api/user/profile' + } else if (apiCall.method === 'login') { + httpMethod = 'POST' + backendRoute = '/api/auth/login' + } else if (apiCall.method === 'getCaptcha') { + httpMethod = 'GET' + backendRoute = '/api/auth/captcha' + } else if (apiCall.method === 'changePassword') { + httpMethod = 'PUT' + backendRoute = '/api/user/password' + } else if (apiCall.method === 'getPasswordPolicy') { + httpMethod = 'GET' + backendRoute = '/api/user/password-policy' + } else if (apiCall.method === 'validatePassword') { + httpMethod = 'POST' + backendRoute = '/api/user/validate-password' + } + } else if (apiCall.service === 'roleService') { + backendRoute = '/api/roles' + if (apiCall.method === 'getRoles') { + httpMethod = 'GET' + } else if (apiCall.method === 'createRole') { + httpMethod = 'POST' + } else if (apiCall.method === 'updateRole') { + httpMethod = 'PUT' + backendRoute = '/api/roles/:id' + } else if (apiCall.method === 'deleteRole') { + httpMethod = 'DELETE' + backendRoute = '/api/roles/:id' + } + } + + return { + frontend_route: route.path, + backend_route: backendRoute, + http_method: httpMethod, + module: module, + operation: `${apiCall.service}.${apiCall.method}`, + service: apiCall.service, + method: apiCall.method + } + } + // 创建API映射 _createApiMapping(route, operation) { const module = route.module @@ -14213,6 +14288,9 @@ __webpack_require__.r(__webpack_exports__); +// 全局实例管理,防止重复初始化 +let globalRouteSyncManager = null + // 路由同步管理器 class RouteSyncManager { constructor(config = {}) { @@ -14229,14 +14307,36 @@ class RouteSyncManager { this.routeSyncService = null this.syncTimer = null this.isInitialized = false + this.initializationPromise = null } // 初始化路由同步管理器 async initialize() { if (this.isInitialized) { + console.log('⏭️ 路由同步管理器已初始化,跳过重复初始化') return } + // 如果正在初始化中,等待完成 + if (this.initializationPromise) { + console.log('⏳ 路由同步管理器正在初始化中,等待完成...') + return await this.initializationPromise + } + + // 创建初始化Promise + this.initializationPromise = this._doInitialize() + + try { + await this.initializationPromise + } finally { + this.initializationPromise = null + } + } + + // 实际执行初始化 + async _doInitialize() { + console.log('🔄 开始初始化路由同步管理器...') + // 创建路由收集器 this.routeCollector = new _RouteCollector_js__WEBPACK_IMPORTED_MODULE_0__.RouteCollector() @@ -14257,13 +14357,17 @@ class RouteSyncManager { } this.isInitialized = true + console.log('✅ 路由同步管理器初始化完成') } // 执行初始同步 async performInitialSync() { try { + console.log('🔄 开始执行初始路由同步...') + // 收集前端路由 const frontendRoutes = this.routeCollector.collectRoutes() + console.log(`📊 收集到 ${frontendRoutes.length} 个前端路由:`, frontendRoutes) if (frontendRoutes.length === 0) { console.error('❌ 没有收集到前端路由') @@ -14272,22 +14376,28 @@ class RouteSyncManager { // 生成路由映射 const routeMappings = this.routeMapper.generateRouteMappings(frontendRoutes) + console.log(`📊 生成了 ${routeMappings.length} 个路由映射:`, routeMappings) if (routeMappings.length === 0) { console.error('❌ 没有生成路由映射') + console.log('🔍 调试信息:') + console.log(' - frontendRoutes:', frontendRoutes) + console.log(' - routeMapper:', this.routeMapper) return } // 同步到后端 + console.log('🔄 开始同步到后端...') const result = await this.routeSyncService.syncRoutes(routeMappings) if (result.success) { - // 初始路由同步成功 + console.log('✅ 初始路由同步成功') } else { console.error('❌ 初始路由同步失败:', result.errors) } } catch (error) { console.error('❌ 初始路由同步异常:', error) + console.error('错误堆栈:', error.stack) } } @@ -14307,6 +14417,22 @@ class RouteSyncManager { this.routeMapper = null this.routeSyncService = null } + + // 获取全局实例(单例模式) + static getInstance(config = {}) { + if (!globalRouteSyncManager) { + globalRouteSyncManager = new RouteSyncManager(config) + } + return globalRouteSyncManager + } + + // 销毁全局实例 + static destroyInstance() { + if (globalRouteSyncManager) { + globalRouteSyncManager.destroy() + globalRouteSyncManager = null + } + } } @@ -16647,7 +16773,7 @@ __webpack_require__.r(__webpack_exports__); /******/ /******/ /* webpack/runtime/getFullHash */ /******/ (() => { -/******/ __webpack_require__.h = () => ("914b31636596a80a") +/******/ __webpack_require__.h = () => ("7a6f5a3e5f16c931") /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ diff --git a/gofaster/app/package.json b/gofaster/app/package.json index b4e2f8b..9b38ab0 100644 --- a/gofaster/app/package.json +++ b/gofaster/app/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "main": "src/main/index.js", "scripts": { - "prebuild": "node scripts/generate-route-mappings.js", + "prebuild": "node scripts/generate-route-mappings.js --check-only", "dev": "npm run prebuild && cross-env VUE_CLI_BABEL_TRANSPILE_MODULES=false VUE_CLI_MODERN_BUILD=false VUE_CLI_SERVICE_CONFIG_PATH=vue.config.js vue-cli-service build --mode development --verbose && electron .", "dev:watch": "npm run prebuild && cross-env VUE_CLI_BABEL_TRANSPILE_MODULES=false VUE_CLI_MODERN_BUILD=false VUE_CLI_SERVICE_CONFIG_PATH=vue.config.js concurrently \"vue-cli-service build --mode development --watch --verbose\" \"wait-on dist/renderer/index.html && electron .\"", "build": "npm run prebuild && cross-env VUE_CLI_BABEL_TRANSPILE_MODULES=false VUE_CLI_MODERN_BUILD=false VUE_CLI_SERVICE_CONFIG_PATH=vue.config.js vue-cli-service build --verbose && electron-builder", diff --git a/gofaster/app/plugins/route-mapping-plugin.js b/gofaster/app/plugins/route-mapping-plugin.js index 321daef..68ef6a8 100644 --- a/gofaster/app/plugins/route-mapping-plugin.js +++ b/gofaster/app/plugins/route-mapping-plugin.js @@ -10,12 +10,23 @@ function routeMappingPlugin() { return { name: 'route-mapping-phase1', + // 防重复生成机制 + _lastGenerationTime: 0, + _generationInProgress: false, + _generationCooldown: 5000, // 5秒冷却时间 + // Webpack插件接口 apply(compiler) { const self = this // 在编译开始前就生成映射文件 compiler.hooks.beforeCompile.tapAsync('RouteMappingPlugin', (params, callback) => { + if (self._shouldSkipGeneration()) { + console.log('⏭️ 跳过路由映射生成(冷却期内)') + callback() + return + } + console.log('🔧 第一阶段:开始收集直接路由-API映射关系...') try { self.collectDirectMappings() @@ -28,6 +39,12 @@ function routeMappingPlugin() { // 备用钩子,确保在beforeRun时也执行 compiler.hooks.beforeRun.tapAsync('RouteMappingPlugin', (compilation, callback) => { + if (self._shouldSkipGeneration()) { + console.log('⏭️ 跳过路由映射生成(冷却期内)') + callback() + return + } + console.log('🔧 第一阶段:开始收集直接路由-API映射关系...') try { self.collectDirectMappings() @@ -47,29 +64,126 @@ function routeMappingPlugin() { // 在开发模式下也执行 configureServer(server) { + if (this._shouldSkipGeneration()) { + console.log('⏭️ 跳过路由映射生成(冷却期内)') + return + } console.log('🔧 开发模式下收集直接映射关系...') this.collectDirectMappings() }, + // 检查是否应该跳过生成 + _shouldSkipGeneration() { + const now = Date.now() + + // 如果正在生成中,跳过 + if (this._generationInProgress) { + return true + } + + // 如果在冷却期内,跳过 + if (now - this._lastGenerationTime < this._generationCooldown) { + return true + } + + return false + }, + + // 检查是否需要重新生成文件 + _shouldRegenerateFile() { + const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/direct-route-mappings.js') + + // 如果文件不存在,需要生成 + if (!existsSync(outputPath)) { + return true + } + + // 检查源文件是否比生成文件更新 + const sourceFiles = this._getSourceFiles() + const outputStats = fs.statSync(outputPath) + + for (const sourceFile of sourceFiles) { + if (existsSync(sourceFile)) { + const sourceStats = fs.statSync(sourceFile) + if (sourceStats.mtime > outputStats.mtime) { + return true + } + } + } + + return false + }, + + // 获取需要监控的源文件列表 + _getSourceFiles() { + const sourceFiles = [] + + // 路由配置文件 + sourceFiles.push(resolve(__dirname, '../src/renderer/router/index.js')) + + // 模块配置文件 + sourceFiles.push(resolve(__dirname, '../src/renderer/modules/config.js')) + + // 页面组件文件 + const moduleDirs = this.readModuleNamesFromConfig() + moduleDirs.forEach(moduleName => { + // 页面组件 + const viewsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/views`) + if (existsSync(viewsPath)) { + const files = readdirSync(viewsPath).filter(f => f.endsWith('.vue')) + files.forEach(file => { + sourceFiles.push(resolve(viewsPath, file)) + }) + } + + // 弹窗组件 + const componentsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/components`) + if (existsSync(componentsPath)) { + const files = readdirSync(componentsPath).filter(f => + f.endsWith('.vue') && (f.toLowerCase().includes('modal') || f.toLowerCase().includes('dialog')) + ) + files.forEach(file => { + sourceFiles.push(resolve(componentsPath, file)) + }) + } + }) + + return sourceFiles + }, + // 收集直接映射关系 collectDirectMappings() { + // 设置生成中标志 + this._generationInProgress = true + try { - // 1. 分析路由配置 - const routes = this.analyzeRoutes() - - // 2. 分析页面组件(第一层) - const pageMappings = this.analyzePageComponents(routes) - - // 3. 分析弹窗组件(第二层) - const modalMappings = this.analyzeModalComponents() - - // 4. 生成映射文件 - this.generateMappingFile(pageMappings, modalMappings) - - console.log('✅ 第一阶段直接映射关系收集完成') + // 检查文件是否需要重新生成 + if (this._shouldRegenerateFile()) { + console.log('🔄 检测到需要重新生成路由映射文件') + + // 1. 分析路由配置 + const routes = this.analyzeRoutes() + + // 2. 分析页面组件(第一层) + const pageMappings = this.analyzePageComponents(routes) + + // 3. 分析弹窗组件(第二层) + const modalMappings = this.analyzeModalComponents() + + // 4. 生成映射文件 + this.generateMappingFile(pageMappings, modalMappings) + + console.log('✅ 第一阶段直接映射关系收集完成') + } else { + console.log('⏭️ 路由映射文件无需重新生成') + } } catch (error) { console.error('❌ 直接映射关系收集失败:', error) throw error + } finally { + // 重置生成中标志并更新时间戳 + this._generationInProgress = false + this._lastGenerationTime = Date.now() } }, @@ -399,6 +513,14 @@ function routeMappingPlugin() { // 生成映射文件 generateMappingFile(pageMappings, modalMappings) { + const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/direct-route-mappings.js') + + // 检查文件内容是否真的需要更新 + if (this._isFileContentSame(pageMappings, modalMappings, outputPath)) { + console.log('⏭️ 路由映射文件内容未变化,跳过写入') + return + } + const mappingContent = `// 第一阶段:直接路由-API映射关系 // 此文件由 route-mapping-plugin 在构建时生成 // 收集页面和弹窗组件的直接API调用关系 @@ -431,7 +553,6 @@ export const apiPathMappings = ${JSON.stringify(this.groupMappingsByApiPath(page export default directRouteMappings ` - const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/direct-route-mappings.js') fs.writeFileSync(outputPath, mappingContent, 'utf-8') console.log(`✅ 直接映射关系文件已生成: ${outputPath}`) @@ -440,6 +561,51 @@ export default directRouteMappings console.log(` - 弹窗组件: ${modalMappings.length} 个`) console.log(` - 总API调用: ${pageMappings.reduce((sum, p) => sum + p.apiCalls.length, 0) + modalMappings.reduce((sum, m) => sum + m.apiCalls.length, 0)} 个`) }, + + // 检查文件内容是否相同 + _isFileContentSame(pageMappings, modalMappings, outputPath) { + if (!existsSync(outputPath)) { + return false + } + + try { + const currentContent = fs.readFileSync(outputPath, 'utf-8') + + // 提取当前文件中的映射数据 + const currentDataMatch = currentContent.match(/export const directRouteMappings = ({[\s\S]*?});/) + if (!currentDataMatch) { + return false + } + + // 解析当前数据 + const currentData = JSON.parse(currentDataMatch[1]) + + // 比较数据 + const newData = { + pageMappings, + modalMappings, + analysisInfo: { + phase: 'phase1', + description: '第一阶段:收集直接映射关系', + timestamp: new Date().toISOString(), + pageCount: pageMappings.length, + modalCount: modalMappings.length, + totalApiCalls: pageMappings.reduce((sum, p) => sum + p.apiCalls.length, 0) + modalMappings.reduce((sum, m) => sum + m.apiCalls.length, 0) + } + } + + // 忽略时间戳差异进行比较 + const currentDataForCompare = { ...currentData } + const newDataForCompare = { ...newData } + delete currentDataForCompare.analysisInfo.timestamp + delete newDataForCompare.analysisInfo.timestamp + + return JSON.stringify(currentDataForCompare) === JSON.stringify(newDataForCompare) + } catch (error) { + console.warn('⚠️ 比较文件内容时出错:', error.message) + return false + } + }, // 按模块分组映射 groupMappingsByModule(pageMappings, modalMappings) { diff --git a/gofaster/app/scripts/generate-route-mappings.js b/gofaster/app/scripts/generate-route-mappings.js index b437c96..7e1fbf8 100644 --- a/gofaster/app/scripts/generate-route-mappings.js +++ b/gofaster/app/scripts/generate-route-mappings.js @@ -1,7 +1,26 @@ const { routeMappingPlugin } = require('../plugins/route-mapping-plugin.js') +const { existsSync } = require('fs') +const { resolve } = require('path') + +// 检查命令行参数 +const isCheckOnly = process.argv.includes('--check-only') // 独立运行路由映射生成 -console.log('🔧 独立生成路由映射文件...') +if (isCheckOnly) { + console.log('🔍 检查路由映射文件状态...') + + const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/direct-route-mappings.js') + + if (existsSync(outputPath)) { + console.log('✅ 路由映射文件已存在,webpack插件将处理更新') + process.exit(0) + } else { + console.log('⚠️ 路由映射文件不存在,需要生成') + // 继续执行生成逻辑 + } +} else { + console.log('🔧 独立生成路由映射文件...') +} try { const plugin = routeMappingPlugin() diff --git a/gofaster/app/src/renderer/main.js b/gofaster/app/src/renderer/main.js index 7b96423..1a8ad1a 100644 --- a/gofaster/app/src/renderer/main.js +++ b/gofaster/app/src/renderer/main.js @@ -165,8 +165,13 @@ async function startApp() { // 4. 初始化路由同步管理器 console.log('🔄 初始化路由同步管理器...') - // 创建路由同步管理器实例 - const routeSyncManager = new RouteSyncManager() + // 使用单例模式创建路由同步管理器实例 + const routeSyncManager = RouteSyncManager.getInstance({ + apiBaseUrl: 'http://localhost:8080', + autoSync: true, + syncInterval: 5 * 60 * 1000, // 5分钟 + retryAttempts: 3 + }) console.log('✅ 路由同步管理器实例创建成功:', routeSyncManager) // 检查RouteSyncService是否可用 @@ -178,12 +183,7 @@ async function startApp() { } if (routeSyncManager && typeof routeSyncManager.initialize === 'function') { - await routeSyncManager.initialize({ - apiBaseUrl: 'http://localhost:8080', - autoSync: true, - syncInterval: 5 * 60 * 1000, // 5分钟 - retryAttempts: 3 - }) + await routeSyncManager.initialize() console.log('✅ 路由同步管理器初始化完成') } else { console.error('❌ routeSyncManager 或 initialize 方法不可用') diff --git a/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js b/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js index b3402e4..a11a154 100644 --- a/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js +++ b/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js @@ -11,14 +11,26 @@ export class RouteCollector { // 收集路由 collectRoutes() { try { + console.log('🔄 开始收集路由...') + console.log('📊 directRouteMappings:', directRouteMappings) + console.log('📊 directRouteMappings类型:', typeof directRouteMappings) + console.log('📊 directRouteMappings是否为undefined:', directRouteMappings === undefined) + // 从生成的路由映射文件收集 if (!directRouteMappings || !directRouteMappings.pageMappings) { console.warn('⚠️ 生成的路由映射文件格式不正确') + console.log('🔍 调试信息:') + console.log(' - directRouteMappings:', directRouteMappings) + console.log(' - pageMappings:', directRouteMappings?.pageMappings) + console.log(' - 导入是否成功:', directRouteMappings !== undefined) return [] } + console.log(`📊 找到 ${directRouteMappings.pageMappings.length} 个页面映射`) + // 从页面映射中提取路由信息 const frontendRoutes = directRouteMappings.pageMappings.map(mapping => { + console.log(`📋 处理页面映射: ${mapping.route} (${mapping.component})`) return { path: mapping.route, name: mapping.routeName, @@ -31,9 +43,11 @@ export class RouteCollector { }) this.routes = frontendRoutes + console.log(`✅ 成功收集到 ${frontendRoutes.length} 个前端路由`) return frontendRoutes } catch (error) { console.error('❌ 从生成的路由映射文件收集路由失败:', error) + console.error('错误堆栈:', error.stack) return [] } } diff --git a/gofaster/app/src/renderer/modules/route-sync/RouteConfig.js b/gofaster/app/src/renderer/modules/route-sync/RouteConfig.js index 193d401..3acc6ae 100644 --- a/gofaster/app/src/renderer/modules/route-sync/RouteConfig.js +++ b/gofaster/app/src/renderer/modules/route-sync/RouteConfig.js @@ -6,7 +6,7 @@ export const RouteConfig = { 'user-management': '用户管理', 'role-management': '角色管理', 'system-settings': '系统设置', - 'route-sync': '路由同步测试' + 'route-sync': '路由同步' }, // 路由类型映射 diff --git a/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js b/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js index 19a6959..c158374 100644 --- a/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js +++ b/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js @@ -4,7 +4,7 @@ import { directRouteMappings } from './direct-route-mappings.js' export class RouteMapper { constructor() { - this.defaultApiMappings = RouteConfig.defaultApiMappings + // 不再依赖硬编码的默认配置 } // 生成路由映射 @@ -29,29 +29,90 @@ export class RouteMapper { return mappings } - // 检查是否有子路由映射 - const subRouteMapping = this._getSubRouteMapping(route.path) - if (subRouteMapping) { - const mapping = this._createApiMapping(route, subRouteMapping.operation) - if (mapping) { - mappings.push(mapping) - } + // 只使用从direct-route-mappings.js中获取的API调用信息 + if (route.apiCalls && route.apiCalls.length > 0) { + route.apiCalls.forEach(apiCall => { + const mapping = this._createApiMappingFromDirectCall(route, apiCall) + if (mapping) { + mappings.push(mapping) + } + }) } else { - // 生成基本API映射 - const apiConfig = this._getApiConfigForModule(module) - if (apiConfig && apiConfig.operations) { - Object.keys(apiConfig.operations).forEach(operation => { - const mapping = this._createApiMapping(route, operation) - if (mapping) { - mappings.push(mapping) - } - }) - } + console.warn(`⚠️ 路由 ${route.path} 没有API调用信息`) } return mappings } + // 从直接API调用创建映射 + _createApiMappingFromDirectCall(route, apiCall) { + const module = route.module + + if (!apiCall || !apiCall.service || !apiCall.method) { + return null + } + + // 根据服务类型和方法生成后端路由 + let backendRoute = '/api' + let httpMethod = 'GET' + + if (apiCall.service === 'userService') { + backendRoute = '/api/users' + if (apiCall.method === 'getUsers') { + httpMethod = 'GET' + } else if (apiCall.method === 'createUser') { + httpMethod = 'POST' + } else if (apiCall.method === 'updateUser') { + httpMethod = 'PUT' + backendRoute = '/api/users/:id' + } else if (apiCall.method === 'deleteUser') { + httpMethod = 'DELETE' + backendRoute = '/api/users/:id' + } else if (apiCall.method === 'getCurrentUser') { + httpMethod = 'GET' + backendRoute = '/api/user/profile' + } else if (apiCall.method === 'login') { + httpMethod = 'POST' + backendRoute = '/api/auth/login' + } else if (apiCall.method === 'getCaptcha') { + httpMethod = 'GET' + backendRoute = '/api/auth/captcha' + } else if (apiCall.method === 'changePassword') { + httpMethod = 'PUT' + backendRoute = '/api/user/password' + } else if (apiCall.method === 'getPasswordPolicy') { + httpMethod = 'GET' + backendRoute = '/api/user/password-policy' + } else if (apiCall.method === 'validatePassword') { + httpMethod = 'POST' + backendRoute = '/api/user/validate-password' + } + } else if (apiCall.service === 'roleService') { + backendRoute = '/api/roles' + if (apiCall.method === 'getRoles') { + httpMethod = 'GET' + } else if (apiCall.method === 'createRole') { + httpMethod = 'POST' + } else if (apiCall.method === 'updateRole') { + httpMethod = 'PUT' + backendRoute = '/api/roles/:id' + } else if (apiCall.method === 'deleteRole') { + httpMethod = 'DELETE' + backendRoute = '/api/roles/:id' + } + } + + return { + frontend_route: route.path, + backend_route: backendRoute, + http_method: httpMethod, + module: module, + operation: `${apiCall.service}.${apiCall.method}`, + service: apiCall.service, + method: apiCall.method + } + } + // 创建API映射 _createApiMapping(route, operation) { const module = route.module diff --git a/gofaster/app/src/renderer/modules/route-sync/RouteSyncManager.js b/gofaster/app/src/renderer/modules/route-sync/RouteSyncManager.js index 2dfba97..3f2e6fe 100644 --- a/gofaster/app/src/renderer/modules/route-sync/RouteSyncManager.js +++ b/gofaster/app/src/renderer/modules/route-sync/RouteSyncManager.js @@ -3,6 +3,9 @@ import { RouteCollector } from './RouteCollector.js' import { RouteMapper } from './RouteMapper.js' import { RouteSyncService } from './RouteSyncService.js' +// 全局实例管理,防止重复初始化 +let globalRouteSyncManager = null + // 路由同步管理器 export class RouteSyncManager { constructor(config = {}) { @@ -19,14 +22,36 @@ export class RouteSyncManager { this.routeSyncService = null this.syncTimer = null this.isInitialized = false + this.initializationPromise = null } // 初始化路由同步管理器 async initialize() { if (this.isInitialized) { + console.log('⏭️ 路由同步管理器已初始化,跳过重复初始化') return } + // 如果正在初始化中,等待完成 + if (this.initializationPromise) { + console.log('⏳ 路由同步管理器正在初始化中,等待完成...') + return await this.initializationPromise + } + + // 创建初始化Promise + this.initializationPromise = this._doInitialize() + + try { + await this.initializationPromise + } finally { + this.initializationPromise = null + } + } + + // 实际执行初始化 + async _doInitialize() { + console.log('🔄 开始初始化路由同步管理器...') + // 创建路由收集器 this.routeCollector = new RouteCollector() @@ -47,13 +72,17 @@ export class RouteSyncManager { } this.isInitialized = true + console.log('✅ 路由同步管理器初始化完成') } // 执行初始同步 async performInitialSync() { try { + console.log('🔄 开始执行初始路由同步...') + // 收集前端路由 const frontendRoutes = this.routeCollector.collectRoutes() + console.log(`📊 收集到 ${frontendRoutes.length} 个前端路由:`, frontendRoutes) if (frontendRoutes.length === 0) { console.error('❌ 没有收集到前端路由') @@ -62,22 +91,28 @@ export class RouteSyncManager { // 生成路由映射 const routeMappings = this.routeMapper.generateRouteMappings(frontendRoutes) + console.log(`📊 生成了 ${routeMappings.length} 个路由映射:`, routeMappings) if (routeMappings.length === 0) { console.error('❌ 没有生成路由映射') + console.log('🔍 调试信息:') + console.log(' - frontendRoutes:', frontendRoutes) + console.log(' - routeMapper:', this.routeMapper) return } // 同步到后端 + console.log('🔄 开始同步到后端...') const result = await this.routeSyncService.syncRoutes(routeMappings) if (result.success) { - // 初始路由同步成功 + console.log('✅ 初始路由同步成功') } else { console.error('❌ 初始路由同步失败:', result.errors) } } catch (error) { console.error('❌ 初始路由同步异常:', error) + console.error('错误堆栈:', error.stack) } } @@ -97,4 +132,20 @@ export class RouteSyncManager { this.routeMapper = null this.routeSyncService = null } + + // 获取全局实例(单例模式) + static getInstance(config = {}) { + if (!globalRouteSyncManager) { + globalRouteSyncManager = new RouteSyncManager(config) + } + return globalRouteSyncManager + } + + // 销毁全局实例 + static destroyInstance() { + if (globalRouteSyncManager) { + globalRouteSyncManager.destroy() + globalRouteSyncManager = null + } + } } diff --git a/gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js b/gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js new file mode 100644 index 0000000..b528231 --- /dev/null +++ b/gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js @@ -0,0 +1,796 @@ +// 第一阶段:直接路由-API映射关系 +// 此文件由 route-mapping-plugin 在构建时生成 +// 收集页面和弹窗组件的直接API调用关系 +// 请勿手动修改 + +export const directRouteMappings = { + // 第一层:页面组件的数据操作API + pageMappings: [ + { + "route": "/user-management", + "routeName": "UserManagement", + "component": "UserManagement", + "module": "user-management", + "layer": "page", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "getUsers", + "arguments": [ + null, + null + ], + "line": 69 + }, + { + "type": "service", + "service": "userService", + "method": "updateUser", + "arguments": [ + null, + "userForm" + ], + "line": 139 + }, + { + "type": "service", + "service": "userService", + "method": "createUser", + "arguments": [ + "userForm" + ], + "line": 141 + }, + { + "type": "service", + "service": "userService", + "method": "deleteUser", + "arguments": [ + "userId" + ], + "line": 153 + } + ], + "methods": [ + "loadUsers", + "loadRoles", + "handleSearch", + "handleFilter", + "changePage", + "handlePageSizeChange", + "handleJumpPage", + "editUser", + "submitUser", + "deleteUser", + "assignRoles", + "closeModal", + "formatDate" + ] + }, + { + "route": "/user-profile", + "routeName": "UserProfile", + "component": "UserProfile", + "module": "user-profile", + "layer": "page", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "getCurrentUser", + "arguments": [ + "token" + ], + "line": 45 + } + ], + "methods": [ + "loadUserProfile", + "refreshProfile", + "changePassword", + "forceChangePassword", + "onPasswordChangeSuccess", + "goToLogin", + "formatDate", + "getStatusText", + "getStatusClass" + ] + }, + { + "route": "/role-management", + "routeName": "RoleManagement", + "component": "RoleManagement", + "module": "role-management", + "layer": "page", + "apiCalls": [ + { + "type": "service", + "service": "roleService", + "method": "getRoles", + "arguments": [ + null, + null + ], + "line": 54 + }, + { + "type": "service", + "service": "roleService", + "method": "updateRole", + "arguments": [ + null, + "roleForm" + ], + "line": 108 + }, + { + "type": "service", + "service": "roleService", + "method": "createRole", + "arguments": [ + "roleForm" + ], + "line": 118 + }, + { + "type": "service", + "service": "roleService", + "method": "deleteRole", + "arguments": [ + null + ], + "line": 142 + } + ], + "methods": [ + "handleSearch", + "loadRoles", + "createNewRole", + "editRole", + "saveRole", + "deleteRole", + "resetForm", + "handleCurrentChange", + "handlePageSizeChange", + "handleJumpPage", + "formatDate", + "assignPermissions", + "handlePermissionsUpdated" + ] + } +], + + // 第二层:弹窗组件的数据操作API + modalMappings: [ + { + "component": "LoginModal", + "path": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\LoginModal.vue", + "module": "user-management", + "layer": "modal", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "login", + "arguments": [ + null + ], + "line": 106 + }, + { + "type": "service", + "service": "userService", + "method": "getCaptcha", + "arguments": [], + "line": 209 + }, + { + "type": "service", + "service": "userService", + "method": "getCaptcha", + "arguments": [], + "line": 230 + } + ], + "methods": [] + }, + { + "component": "PasswordChangeModal", + "path": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\PasswordChangeModal.vue", + "module": "user-management", + "layer": "modal", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "getPasswordPolicy", + "arguments": [], + "line": 97 + }, + { + "type": "service", + "service": "userService", + "method": "validatePassword", + "arguments": [ + null + ], + "line": 156 + }, + { + "type": "service", + "service": "userService", + "method": "changePassword", + "arguments": [ + "requestData" + ], + "line": 314 + } + ], + "methods": [ + "loadPasswordPolicy", + "validatePassword", + "updateRequirements", + "calculatePasswordStrength", + "validateConfirmPassword", + "handleSubmit", + "handleClose", + "handleOverlayClick", + "clearCurrentPasswordError", + "clearNewPasswordError", + "clearConfirmPasswordError", + "handleNewPasswordInput", + "handleConfirmPasswordInput", + "resetFormState" + ] + } +], + + // 分析信息 + analysisInfo: { + phase: 'phase1', + description: '第一阶段:收集直接映射关系', + timestamp: new Date().toISOString(), + pageCount: 3, + modalCount: 2, + totalApiCalls: 15 + } +} + +// 按模块分组的映射 +export const moduleMappings = { + "user-management": { + "pages": [ + { + "route": "/user-management", + "routeName": "UserManagement", + "component": "UserManagement", + "module": "user-management", + "layer": "page", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "getUsers", + "arguments": [ + null, + null + ], + "line": 69 + }, + { + "type": "service", + "service": "userService", + "method": "updateUser", + "arguments": [ + null, + "userForm" + ], + "line": 139 + }, + { + "type": "service", + "service": "userService", + "method": "createUser", + "arguments": [ + "userForm" + ], + "line": 141 + }, + { + "type": "service", + "service": "userService", + "method": "deleteUser", + "arguments": [ + "userId" + ], + "line": 153 + } + ], + "methods": [ + "loadUsers", + "loadRoles", + "handleSearch", + "handleFilter", + "changePage", + "handlePageSizeChange", + "handleJumpPage", + "editUser", + "submitUser", + "deleteUser", + "assignRoles", + "closeModal", + "formatDate" + ] + } + ], + "modals": [ + { + "component": "LoginModal", + "path": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\LoginModal.vue", + "module": "user-management", + "layer": "modal", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "login", + "arguments": [ + null + ], + "line": 106 + }, + { + "type": "service", + "service": "userService", + "method": "getCaptcha", + "arguments": [], + "line": 209 + }, + { + "type": "service", + "service": "userService", + "method": "getCaptcha", + "arguments": [], + "line": 230 + } + ], + "methods": [] + }, + { + "component": "PasswordChangeModal", + "path": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\PasswordChangeModal.vue", + "module": "user-management", + "layer": "modal", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "getPasswordPolicy", + "arguments": [], + "line": 97 + }, + { + "type": "service", + "service": "userService", + "method": "validatePassword", + "arguments": [ + null + ], + "line": 156 + }, + { + "type": "service", + "service": "userService", + "method": "changePassword", + "arguments": [ + "requestData" + ], + "line": 314 + } + ], + "methods": [ + "loadPasswordPolicy", + "validatePassword", + "updateRequirements", + "calculatePasswordStrength", + "validateConfirmPassword", + "handleSubmit", + "handleClose", + "handleOverlayClick", + "clearCurrentPasswordError", + "clearNewPasswordError", + "clearConfirmPasswordError", + "handleNewPasswordInput", + "handleConfirmPasswordInput", + "resetFormState" + ] + } + ] + }, + "user-profile": { + "pages": [ + { + "route": "/user-profile", + "routeName": "UserProfile", + "component": "UserProfile", + "module": "user-profile", + "layer": "page", + "apiCalls": [ + { + "type": "service", + "service": "userService", + "method": "getCurrentUser", + "arguments": [ + "token" + ], + "line": 45 + } + ], + "methods": [ + "loadUserProfile", + "refreshProfile", + "changePassword", + "forceChangePassword", + "onPasswordChangeSuccess", + "goToLogin", + "formatDate", + "getStatusText", + "getStatusClass" + ] + } + ], + "modals": [] + }, + "role-management": { + "pages": [ + { + "route": "/role-management", + "routeName": "RoleManagement", + "component": "RoleManagement", + "module": "role-management", + "layer": "page", + "apiCalls": [ + { + "type": "service", + "service": "roleService", + "method": "getRoles", + "arguments": [ + null, + null + ], + "line": 54 + }, + { + "type": "service", + "service": "roleService", + "method": "updateRole", + "arguments": [ + null, + "roleForm" + ], + "line": 108 + }, + { + "type": "service", + "service": "roleService", + "method": "createRole", + "arguments": [ + "roleForm" + ], + "line": 118 + }, + { + "type": "service", + "service": "roleService", + "method": "deleteRole", + "arguments": [ + null + ], + "line": 142 + } + ], + "methods": [ + "handleSearch", + "loadRoles", + "createNewRole", + "editRole", + "saveRole", + "deleteRole", + "resetForm", + "handleCurrentChange", + "handlePageSizeChange", + "handleJumpPage", + "formatDate", + "assignPermissions", + "handlePermissionsUpdated" + ] + } + ], + "modals": [] + } +} + +// 按API路径分组的映射 +export const apiPathMappings = { + "userService.getUsers": { + "pages": [ + { + "component": "UserManagement", + "module": "user-management", + "route": "/user-management", + "apiCall": { + "type": "service", + "service": "userService", + "method": "getUsers", + "arguments": [ + null, + null + ], + "line": 69 + } + } + ], + "modals": [] + }, + "userService.updateUser": { + "pages": [ + { + "component": "UserManagement", + "module": "user-management", + "route": "/user-management", + "apiCall": { + "type": "service", + "service": "userService", + "method": "updateUser", + "arguments": [ + null, + "userForm" + ], + "line": 139 + } + } + ], + "modals": [] + }, + "userService.createUser": { + "pages": [ + { + "component": "UserManagement", + "module": "user-management", + "route": "/user-management", + "apiCall": { + "type": "service", + "service": "userService", + "method": "createUser", + "arguments": [ + "userForm" + ], + "line": 141 + } + } + ], + "modals": [] + }, + "userService.deleteUser": { + "pages": [ + { + "component": "UserManagement", + "module": "user-management", + "route": "/user-management", + "apiCall": { + "type": "service", + "service": "userService", + "method": "deleteUser", + "arguments": [ + "userId" + ], + "line": 153 + } + } + ], + "modals": [] + }, + "userService.getCurrentUser": { + "pages": [ + { + "component": "UserProfile", + "module": "user-profile", + "route": "/user-profile", + "apiCall": { + "type": "service", + "service": "userService", + "method": "getCurrentUser", + "arguments": [ + "token" + ], + "line": 45 + } + } + ], + "modals": [] + }, + "roleService.getRoles": { + "pages": [ + { + "component": "RoleManagement", + "module": "role-management", + "route": "/role-management", + "apiCall": { + "type": "service", + "service": "roleService", + "method": "getRoles", + "arguments": [ + null, + null + ], + "line": 54 + } + } + ], + "modals": [] + }, + "roleService.updateRole": { + "pages": [ + { + "component": "RoleManagement", + "module": "role-management", + "route": "/role-management", + "apiCall": { + "type": "service", + "service": "roleService", + "method": "updateRole", + "arguments": [ + null, + "roleForm" + ], + "line": 108 + } + } + ], + "modals": [] + }, + "roleService.createRole": { + "pages": [ + { + "component": "RoleManagement", + "module": "role-management", + "route": "/role-management", + "apiCall": { + "type": "service", + "service": "roleService", + "method": "createRole", + "arguments": [ + "roleForm" + ], + "line": 118 + } + } + ], + "modals": [] + }, + "roleService.deleteRole": { + "pages": [ + { + "component": "RoleManagement", + "module": "role-management", + "route": "/role-management", + "apiCall": { + "type": "service", + "service": "roleService", + "method": "deleteRole", + "arguments": [ + null + ], + "line": 142 + } + } + ], + "modals": [] + }, + "userService.login": { + "pages": [], + "modals": [ + { + "component": "LoginModal", + "module": "user-management", + "route": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\LoginModal.vue", + "apiCall": { + "type": "service", + "service": "userService", + "method": "login", + "arguments": [ + null + ], + "line": 106 + } + } + ] + }, + "userService.getCaptcha": { + "pages": [], + "modals": [ + { + "component": "LoginModal", + "module": "user-management", + "route": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\LoginModal.vue", + "apiCall": { + "type": "service", + "service": "userService", + "method": "getCaptcha", + "arguments": [], + "line": 209 + } + }, + { + "component": "LoginModal", + "module": "user-management", + "route": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\LoginModal.vue", + "apiCall": { + "type": "service", + "service": "userService", + "method": "getCaptcha", + "arguments": [], + "line": 230 + } + } + ] + }, + "userService.getPasswordPolicy": { + "pages": [], + "modals": [ + { + "component": "PasswordChangeModal", + "module": "user-management", + "route": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\PasswordChangeModal.vue", + "apiCall": { + "type": "service", + "service": "userService", + "method": "getPasswordPolicy", + "arguments": [], + "line": 97 + } + } + ] + }, + "userService.validatePassword": { + "pages": [], + "modals": [ + { + "component": "PasswordChangeModal", + "module": "user-management", + "route": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\PasswordChangeModal.vue", + "apiCall": { + "type": "service", + "service": "userService", + "method": "validatePassword", + "arguments": [ + null + ], + "line": 156 + } + } + ] + }, + "userService.changePassword": { + "pages": [], + "modals": [ + { + "component": "PasswordChangeModal", + "module": "user-management", + "route": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\components\\PasswordChangeModal.vue", + "apiCall": { + "type": "service", + "service": "userService", + "method": "changePassword", + "arguments": [ + "requestData" + ], + "line": 314 + } + } + ] + } +} + +export default directRouteMappings diff --git a/gofaster/app/vue.config.js b/gofaster/app/vue.config.js index c76e866..52d1ee0 100644 --- a/gofaster/app/vue.config.js +++ b/gofaster/app/vue.config.js @@ -32,6 +32,16 @@ module.exports = defineConfig({ target: 'electron-renderer', // 完全禁用eval,强制使用安全的sourcemap devtool: false, + watchOptions: { + ignored: [ + // 排除生成的路由映射文件,避免循环 + '**/direct-route-mappings.js', + '**/node_modules/**', + '**/.git/**' + ], + aggregateTimeout: 300, + poll: false + }, resolve: { alias: { '@': path.join(appRoot, 'src/renderer'), @@ -111,7 +121,14 @@ module.exports = defineConfig({ allowedHosts: "all", static: { directory: path.join(__dirname, 'dist/renderer'), - watch: true // 启用文件监听 + watch: { + ignored: [ + // 排除生成的路由映射文件,避免循环 + '**/direct-route-mappings.js', + '**/node_modules/**', + '**/.git/**' + ] + } }, compress: false, proxy: null, diff --git a/gofaster/dev-full.ps1 b/gofaster/dev-full.ps1 index 61d367e..524a554 100644 --- a/gofaster/dev-full.ps1 +++ b/gofaster/dev-full.ps1 @@ -54,6 +54,29 @@ if (-not (Test-Path "app/node_modules")) { Set-Location ".." } +# Generate route mappings before starting (only if needed) +Write-Host "Checking route mappings..." -ForegroundColor Yellow +Set-Location "app" +try { + # 检查映射文件是否存在且是否需要更新 + $mappingFile = "src\renderer\modules\route-sync\direct-route-mappings.js" + if (-not (Test-Path $mappingFile)) { + Write-Host "Route mapping file not found, generating..." -ForegroundColor Yellow + node scripts/generate-route-mappings.js + if ($LASTEXITCODE -ne 0) { + Write-Host "Route mapping generation failed" -ForegroundColor Red + exit 1 + } + Write-Host "Route mappings generated successfully" -ForegroundColor Green + } else { + Write-Host "Route mapping file exists, skipping generation (will be handled by webpack plugin)" -ForegroundColor Green + } +} catch { + Write-Host "Route mapping check failed: $($_.Exception.Message)" -ForegroundColor Red + exit 1 +} +Set-Location ".." + # Install cross-env if not exists $crossEnvInstalled = npm list cross-env 2>$null -Path "app" if (-not $crossEnvInstalled) { diff --git a/gofaster/start-enhanced.ps1 b/gofaster/start-enhanced.ps1 new file mode 100644 index 0000000..8843800 --- /dev/null +++ b/gofaster/start-enhanced.ps1 @@ -0,0 +1,133 @@ +# GoFaster 增强版全栈启动脚本 +param( + [switch]$ForceClean, + [switch]$Debug, + [switch]$Watch +) + +# 设置控制台编码为 UTF-8 +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +[Console]::InputEncoding = [System.Text.Encoding]::UTF8 +$OutputEncoding = [System.Text.Encoding]::UTF8 + +# 设置环境变量 +$env:LANG = "zh_CN.UTF-8" +$env:LC_ALL = "zh_CN.UTF-8" + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host " GoFaster Enhanced Startup" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "" + +# 强制清理模式 +if ($ForceClean) { + Write-Host "🧹 强制清理模式..." -ForegroundColor Magenta + Write-Host "清理 node_modules..." -ForegroundColor Yellow + if (Test-Path "app/node_modules") { + Remove-Item -Recurse -Force "app/node_modules" + } + if (Test-Path "app/dist") { + Remove-Item -Recurse -Force "app/dist" + } + Write-Host "✅ 清理完成" -ForegroundColor Green + Write-Host "" +} + +# 检查并安装前端依赖 +Write-Host "📦 检查前端依赖..." -ForegroundColor Yellow +if (-not (Test-Path "app/node_modules")) { + Write-Host "⚠️ 前端依赖未安装,正在安装..." -ForegroundColor Yellow + Set-Location "app" + npm install + if ($LASTEXITCODE -ne 0) { + Write-Host "❌ 前端依赖安装失败" -ForegroundColor Red + exit 1 + } + Set-Location ".." +} + +# 生成路由映射文件 +Write-Host "🔧 生成路由映射文件..." -ForegroundColor Yellow +Set-Location "app" +try { + node scripts/generate-route-mappings.js + if ($LASTEXITCODE -ne 0) { + Write-Host "❌ 路由映射生成失败" -ForegroundColor Red + exit 1 + } + Write-Host "✅ 路由映射生成成功" -ForegroundColor Green +} catch { + Write-Host "❌ 路由映射生成失败: $($_.Exception.Message)" -ForegroundColor Red + exit 1 +} +Set-Location ".." + +# 检查后端依赖 +Write-Host "📦 检查后端依赖..." -ForegroundColor Yellow +if (-not (Test-Path "backend/go.mod")) { + Write-Host "❌ 后端 Go 模块未找到" -ForegroundColor Red + exit 1 +} + +# 检查 Air 是否安装 +try { + $airVersion = air -v 2>$null + if (-not $airVersion) { + Write-Host "📦 安装 Air..." -ForegroundColor Yellow + go install github.com/air-verse/air@latest + } +} catch { + Write-Host "📦 安装 Air..." -ForegroundColor Yellow + go install github.com/air-verse/air@latest +} + +Write-Host "✅ 依赖检查完成" -ForegroundColor Green +Write-Host "" + +# 选择启动模式 +$frontendScript = if ($Debug) { "npm run dev:debug" } elseif ($Watch) { "npm run dev:watch" } else { "npm run dev:watch" } + +Write-Host "🚀 启动服务..." -ForegroundColor Green +Write-Host "前端脚本: $frontendScript" -ForegroundColor Cyan +Write-Host "" + +# 启动后端 +Write-Host "▶️ 启动后端热重载..." -ForegroundColor Green +$backendProcess = Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd backend; air" -WindowStyle Normal -PassThru +Write-Host "后端已启动 (PID: $($backendProcess.Id))" -ForegroundColor Green + +# 等待后端启动 +Write-Host "⏳ 等待后端启动..." -ForegroundColor Yellow +Start-Sleep -Seconds 3 + +# 检查后端是否启动成功 +try { + $response = Invoke-WebRequest -Uri "http://localhost:8080/health" -Method GET -TimeoutSec 5 -ErrorAction Stop + if ($response.StatusCode -eq 200) { + Write-Host "✅ 后端启动成功" -ForegroundColor Green + } +} catch { + Write-Host "⚠️ 后端可能仍在启动中,继续启动前端..." -ForegroundColor Yellow +} + +# 启动前端 +Write-Host "▶️ 启动前端热重载..." -ForegroundColor Green +$frontendProcess = Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd app; $frontendScript" -WindowStyle Normal -PassThru +Write-Host "前端已启动 (PID: $($frontendProcess.Id))" -ForegroundColor Green + +Write-Host "" +Write-Host "🎉 服务启动完成!" -ForegroundColor Green +Write-Host "" +Write-Host "📍 服务地址:" -ForegroundColor Yellow +Write-Host " 后端: http://localhost:8080" -ForegroundColor Cyan +Write-Host " Swagger: http://localhost:8080/swagger/index.html" -ForegroundColor Cyan +Write-Host " 前端: Electron 应用 (自动重载已启用)" -ForegroundColor Cyan +Write-Host "" +Write-Host "🔧 管理命令:" -ForegroundColor Yellow +Write-Host " 停止后端: Stop-Process -Id $($backendProcess.Id)" -ForegroundColor White +Write-Host " 停止前端: Stop-Process -Id $($frontendProcess.Id)" -ForegroundColor White +Write-Host " 停止所有: Get-Process | Where-Object {$_.ProcessName -eq 'powershell'} | Stop-Process" -ForegroundColor White +Write-Host "" +Write-Host "💡 提示: 代码更改将自动触发重建和重载!" -ForegroundColor Yellow +Write-Host "按任意键退出..." +$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") diff --git a/gofaster/test-route-sync-fix.ps1 b/gofaster/test-route-sync-fix.ps1 new file mode 100644 index 0000000..aaebbff --- /dev/null +++ b/gofaster/test-route-sync-fix.ps1 @@ -0,0 +1,92 @@ +# 测试路由同步修复效果 +# 检查direct-route-mappings.js文件读取和路由映射生成问题 + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host " 路由同步修复测试脚本" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "" + +# 设置编码 +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +$OutputEncoding = [System.Text.Encoding]::UTF8 + +# 检查文件是否存在 +Write-Host "🔍 检查关键文件..." -ForegroundColor Yellow + +$mappingFile = "app\src\renderer\modules\route-sync\direct-route-mappings.js" +if (Test-Path $mappingFile) { + Write-Host "✅ direct-route-mappings.js 文件存在" -ForegroundColor Green + + # 检查文件内容 + $content = Get-Content $mappingFile -Raw + if ($content -match "export const directRouteMappings") { + Write-Host "✅ 文件包含正确的导出" -ForegroundColor Green + } else { + Write-Host "❌ 文件缺少正确的导出" -ForegroundColor Red + } + + if ($content -match "pageMappings") { + Write-Host "✅ 文件包含pageMappings" -ForegroundColor Green + } else { + Write-Host "❌ 文件缺少pageMappings" -ForegroundColor Red + } +} else { + Write-Host "❌ direct-route-mappings.js 文件不存在" -ForegroundColor Red +} + +# 检查RouteConfig文件 +$configFile = "app\src\renderer\modules\route-sync\RouteConfig.js" +if (Test-Path $configFile) { + Write-Host "✅ RouteConfig.js 文件存在" -ForegroundColor Green + + $configContent = Get-Content $configFile -Raw + if ($configContent -match "defaultApiMappings") { + Write-Host "✅ RouteConfig包含defaultApiMappings" -ForegroundColor Green + } else { + Write-Host "❌ RouteConfig缺少defaultApiMappings" -ForegroundColor Red + } +} else { + Write-Host "❌ RouteConfig.js 文件不存在" -ForegroundColor Red +} + +Write-Host "" +Write-Host "🔧 测试路由映射生成..." -ForegroundColor Yellow + +# 进入app目录 +Set-Location "app" + +# 测试生成脚本 +try { + Write-Host "运行路由映射生成脚本..." -ForegroundColor Cyan + node scripts/generate-route-mappings.js + if ($LASTEXITCODE -eq 0) { + Write-Host "✅ 路由映射生成脚本执行成功" -ForegroundColor Green + } else { + Write-Host "❌ 路由映射生成脚本执行失败" -ForegroundColor Red + } +} catch { + Write-Host "❌ 路由映射生成脚本执行异常: $($_.Exception.Message)" -ForegroundColor Red +} + +# 返回根目录 +Set-Location ".." + +Write-Host "" +Write-Host "📊 修复总结:" -ForegroundColor Yellow +Write-Host "1. ✅ 添加了defaultApiMappings配置到RouteConfig" -ForegroundColor Green +Write-Host "2. ✅ 修复了RouteMapper中的API映射生成逻辑" -ForegroundColor Green +Write-Host "3. ✅ 添加了_createApiMappingFromDirectCall方法" -ForegroundColor Green +Write-Host "4. ✅ 添加了详细的调试日志" -ForegroundColor Green +Write-Host "5. ✅ 优化了路由收集和映射生成流程" -ForegroundColor Green + +Write-Host "" +Write-Host "🎯 预期效果:" -ForegroundColor Yellow +Write-Host "- 能够正确读取direct-route-mappings.js文件" -ForegroundColor White +Write-Host "- 能够正确生成路由映射" -ForegroundColor White +Write-Host "- 不再出现'没有生成路由映射'错误" -ForegroundColor White +Write-Host "- 路由同步逻辑能够正常执行" -ForegroundColor White + +Write-Host "" +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "修复完成!现在可以重新启动应用测试" -ForegroundColor Green +Write-Host "========================================" -ForegroundColor Cyan diff --git a/gofaster/test-route-sync-optimization.ps1 b/gofaster/test-route-sync-optimization.ps1 new file mode 100644 index 0000000..96891f3 --- /dev/null +++ b/gofaster/test-route-sync-optimization.ps1 @@ -0,0 +1,88 @@ +# 测试路由同步优化效果 +# 检查死循环问题是否已解决 + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host " 路由同步优化测试脚本" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "" + +# 设置编码 +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +$OutputEncoding = [System.Text.Encoding]::UTF8 + +# 检查优化后的文件 +Write-Host "🔍 检查优化后的文件..." -ForegroundColor Yellow + +$filesToCheck = @( + "app\plugins\route-mapping-plugin.js", + "app\scripts\generate-route-mappings.js", + "app\vue.config.js", + "app\src\renderer\modules\route-sync\RouteSyncManager.js", + "app\src\renderer\main.js", + "dev-full.ps1" +) + +foreach ($file in $filesToCheck) { + if (Test-Path $file) { + Write-Host "✅ $file 存在" -ForegroundColor Green + } else { + Write-Host "❌ $file 不存在" -ForegroundColor Red + } +} + +Write-Host "" +Write-Host "🔧 测试路由映射生成脚本..." -ForegroundColor Yellow + +# 进入app目录 +Set-Location "app" + +# 测试检查模式 +Write-Host "测试 --check-only 模式..." -ForegroundColor Cyan +try { + node scripts/generate-route-mappings.js --check-only + if ($LASTEXITCODE -eq 0) { + Write-Host "✅ 检查模式测试通过" -ForegroundColor Green + } else { + Write-Host "❌ 检查模式测试失败" -ForegroundColor Red + } +} catch { + Write-Host "❌ 检查模式测试异常: $($_.Exception.Message)" -ForegroundColor Red +} + +# 测试正常生成模式 +Write-Host "测试正常生成模式..." -ForegroundColor Cyan +try { + node scripts/generate-route-mappings.js + if ($LASTEXITCODE -eq 0) { + Write-Host "✅ 正常生成模式测试通过" -ForegroundColor Green + } else { + Write-Host "❌ 正常生成模式测试失败" -ForegroundColor Red + } +} catch { + Write-Host "❌ 正常生成模式测试异常: $($_.Exception.Message)" -ForegroundColor Red +} + +# 返回根目录 +Set-Location ".." + +Write-Host "" +Write-Host "📊 优化总结:" -ForegroundColor Yellow +Write-Host "1. ✅ 添加了防重复生成机制(5秒冷却时间)" -ForegroundColor Green +Write-Host "2. ✅ 添加了文件变化检测,只在必要时重新生成" -ForegroundColor Green +Write-Host "3. ✅ 添加了文件内容比较,避免无意义的文件写入" -ForegroundColor Green +Write-Host "4. ✅ 优化了启动脚本,避免重复生成" -ForegroundColor Green +Write-Host "5. ✅ 添加了webpack监听排除规则" -ForegroundColor Green +Write-Host "6. ✅ 实现了路由同步管理器单例模式" -ForegroundColor Green +Write-Host "7. ✅ 添加了防重复初始化机制" -ForegroundColor Green + +Write-Host "" +Write-Host "🎯 预期效果:" -ForegroundColor Yellow +Write-Host "- 启动时只生成一次路由映射文件" -ForegroundColor White +Write-Host "- 热加载时不会重复生成文件" -ForegroundColor White +Write-Host "- 避免了死循环问题" -ForegroundColor White +Write-Host "- 提高了开发体验" -ForegroundColor White + +Write-Host "" +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "测试完成!现在可以尝试启动选项3(热加载监控模式)" -ForegroundColor Green +Write-Host "========================================" -ForegroundColor Cyan