From 8ed92aa21db9559c295bc3ccc6504346040e87f1 Mon Sep 17 00:00:00 2001 From: hejl Date: Fri, 5 Sep 2025 11:02:48 +0800 Subject: [PATCH] =?UTF-8?q?=E8=83=BD=E6=AD=A3=E5=B8=B8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E6=98=A0=E5=B0=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gofaster/app/dist/renderer/js/index.js | 900 ++++++++++++++++- gofaster/app/package.json | 11 +- gofaster/app/plugins/route-mapping-plugin.js | 911 ++++++++---------- .../app/scripts/generate-route-mappings.js | 14 + .../modules/route-sync/RouteCollector.js | 25 +- .../modules/route-sync/RouteMapper.js | 59 +- gofaster/app/vue.config.js | 4 + 7 files changed, 1315 insertions(+), 609 deletions(-) create mode 100644 gofaster/app/scripts/generate-route-mappings.js diff --git a/gofaster/app/dist/renderer/js/index.js b/gofaster/app/dist/renderer/js/index.js index ca787b5..7835303 100644 --- a/gofaster/app/dist/renderer/js/index.js +++ b/gofaster/app/dist/renderer/js/index.js @@ -13819,7 +13819,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RouteCollector: () => (/* binding */ RouteCollector) /* harmony export */ }); -Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()); +/* harmony import */ var _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./direct-route-mappings.js */ "./src/renderer/modules/route-sync/direct-route-mappings.js"); /* harmony import */ var _RouteConfig_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./RouteConfig.js */ "./src/renderer/modules/route-sync/RouteConfig.js"); // 路由收集器 - 收集前端路由信息 @@ -13835,24 +13835,21 @@ class RouteCollector { collectRoutes() { try { // 从生成的路由映射文件收集 - if (!Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()) || !Array.isArray(Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()))) { + if (!_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings || !_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings.pageMappings) { console.warn('⚠️ 生成的路由映射文件格式不正确') return [] } - // 转换为主入口路由格式 - const frontendRoutes = Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()).map(route => { - // 确保模块信息正确 - if (!route.module) { - route.module = _RouteConfig_js__WEBPACK_IMPORTED_MODULE_1__.RouteUtils.extractModuleFromPath(route.path) - } - + // 从页面映射中提取路由信息 + const frontendRoutes = _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_0__.directRouteMappings.pageMappings.map(mapping => { return { - path: route.path, - name: route.name, - module: route.module, - description: route.description || route.name, - type: route.type || 'list' + path: mapping.route, + name: mapping.routeName, + module: mapping.module, + description: `${mapping.routeName}页面`, + type: 'list', + component: mapping.component, + apiCalls: mapping.apiCalls } }) @@ -14038,7 +14035,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ RouteMapper: () => (/* binding */ RouteMapper) /* harmony export */ }); /* harmony import */ var _RouteConfig_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./RouteConfig.js */ "./src/renderer/modules/route-sync/RouteConfig.js"); -Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()); +/* harmony import */ var _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./direct-route-mappings.js */ "./src/renderer/modules/route-sync/direct-route-mappings.js"); // 路由映射器 - 将前端路由映射到后端API @@ -14120,42 +14117,57 @@ class RouteMapper { // 获取子路由映射 _getSubRouteMapping(routePath) { try { - return Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }())[routePath] || null + // 从新的直接映射文件中查找 + if (_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__.directRouteMappings && _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__.directRouteMappings.pageMappings) { + const pageMapping = _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__.directRouteMappings.pageMappings.find(p => p.route === routePath) + if (pageMapping && pageMapping.apiCalls) { + return { + route: routePath, + apiCalls: pageMapping.apiCalls + } + } + } + return null } catch (error) { return null } } - // 获取模块的API配置 - 合并生成的文件和默认配置 + // 获取模块的API配置 - 基于直接映射关系 _getApiConfigForModule(module) { let apiConfig = null - // 首先尝试从生成的路由映射文件获取 + // 从直接映射文件中获取API调用信息 try { - if (Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()) && Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }())[module]) { - apiConfig = { ...Object(function webpackMissingModule() { var e = new Error("Cannot find module './generated-route-mapping.js'"); e.code = 'MODULE_NOT_FOUND'; throw e; }())[module] } + if (_direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__.directRouteMappings && _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__.directRouteMappings.pageMappings) { + const moduleMappings = _direct_route_mappings_js__WEBPACK_IMPORTED_MODULE_1__.directRouteMappings.pageMappings.filter(p => p.module === module) + if (moduleMappings.length > 0) { + const operations = {} + moduleMappings.forEach(mapping => { + mapping.apiCalls.forEach(apiCall => { + const operationKey = `${apiCall.type}_${apiCall.service || apiCall.method}_${apiCall.method || apiCall.path}` + operations[operationKey] = { + path: apiCall.path || `/${apiCall.service}/${apiCall.method}`, + method: apiCall.method || 'GET' + } + }) + }) + + if (Object.keys(operations).length > 0) { + apiConfig = { + basePath: '/api', + operations: operations + } + } + } } } catch (error) { - // 如果获取失败,使用默认配置 + console.warn('获取直接映射配置失败:', error) } - // 如果没有从生成文件获取到,使用默认配置 + // 如果没有从直接映射获取到,使用默认配置 if (!apiConfig) { apiConfig = { ...this.defaultApiMappings[module] } - } else { - // 合并默认配置中的缺失操作 - const defaultConfig = this.defaultApiMappings[module] - if (defaultConfig && defaultConfig.operations) { - if (!apiConfig.operations) { - apiConfig.operations = {} - } - // 只添加生成文件中没有的操作 - Object.keys(defaultConfig.operations).forEach(operation => { - if (!apiConfig.operations[operation]) { - apiConfig.operations[operation] = defaultConfig.operations[operation] - } - }) - } } return apiConfig @@ -14467,6 +14479,820 @@ class RouteSyncService { } +/***/ }), + +/***/ "./src/renderer/modules/route-sync/direct-route-mappings.js": +/*!******************************************************************!*\ + !*** ./src/renderer/modules/route-sync/direct-route-mappings.js ***! + \******************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ apiPathMappings: () => (/* binding */ apiPathMappings), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), +/* harmony export */ directRouteMappings: () => (/* binding */ directRouteMappings), +/* harmony export */ moduleMappings: () => (/* binding */ moduleMappings) +/* harmony export */ }); +// 第一阶段:直接路由-API映射关系 +// 此文件由 route-mapping-plugin 在构建时生成 +// 收集页面和弹窗组件的直接API调用关系 +// 请勿手动修改 + +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 + } +} + +// 按模块分组的映射 +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路径分组的映射 +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 + } + } + ] + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (directRouteMappings); + + /***/ }), /***/ "./src/renderer/modules/route-sync/index.js": @@ -15821,7 +16647,7 @@ __webpack_require__.r(__webpack_exports__); /******/ /******/ /* webpack/runtime/getFullHash */ /******/ (() => { -/******/ __webpack_require__.h = () => ("a79c70d541afd8fd") +/******/ __webpack_require__.h = () => ("914b31636596a80a") /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ diff --git a/gofaster/app/package.json b/gofaster/app/package.json index a219653..b4e2f8b 100644 --- a/gofaster/app/package.json +++ b/gofaster/app/package.json @@ -3,11 +3,12 @@ "version": "1.0.0", "main": "src/main/index.js", "scripts": { - "dev": "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": "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": "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", - "electron:serve": "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 .", - "build:vue": "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", + "prebuild": "node scripts/generate-route-mappings.js", + "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", + "electron:serve": "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 .", + "build:vue": "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", "dev:enhanced": "powershell -ExecutionPolicy Bypass -File dev-enhanced.ps1", "dev:enhanced-bat": "dev-enhanced.bat", "dev:debug": "cross-env VUE_CLI_BABEL_TRANSPILE_MODULES=false VUE_CLI_MODERN_BUILD=false VUE_CLI_SERVICE_CONFIG_PATH=vue.config.js DEBUG=* vue-cli-service build --mode development --verbose && electron .", diff --git a/gofaster/app/plugins/route-mapping-plugin.js b/gofaster/app/plugins/route-mapping-plugin.js index 2b569de..321daef 100644 --- a/gofaster/app/plugins/route-mapping-plugin.js +++ b/gofaster/app/plugins/route-mapping-plugin.js @@ -1,108 +1,86 @@ -import { resolve } from 'path' -import { readFileSync, existsSync, readdirSync } from 'fs' -import fs from 'fs' -import * as parser from '@babel/parser' -import traverse from '@babel/traverse' -import { parse } from '@vue/compiler-sfc' +const { resolve } = require('path') +const { readFileSync, existsSync, readdirSync } = require('fs') +const fs = require('fs') +const parser = require('@babel/parser') +const traverse = require('@babel/traverse').default +const { parse } = require('@vue/compiler-sfc') -// 路由映射插件 - 基于AST解析获取实际存在的路由关系,不进行规则推断 -export function routeMappingPlugin() { +// 第一阶段路由映射插件 - 收集直接映射关系 +function routeMappingPlugin() { return { - name: 'route-mapping', + name: 'route-mapping-phase1', - // 在构建开始时执行 + // Webpack插件接口 + apply(compiler) { + const self = this + + // 在编译开始前就生成映射文件 + compiler.hooks.beforeCompile.tapAsync('RouteMappingPlugin', (params, callback) => { + console.log('🔧 第一阶段:开始收集直接路由-API映射关系...') + try { + self.collectDirectMappings() + callback() + } catch (error) { + console.error('❌ 路由映射插件执行失败:', error) + callback(error) + } + }) + + // 备用钩子,确保在beforeRun时也执行 + compiler.hooks.beforeRun.tapAsync('RouteMappingPlugin', (compilation, callback) => { + console.log('🔧 第一阶段:开始收集直接路由-API映射关系...') + try { + self.collectDirectMappings() + callback() + } catch (error) { + console.error('❌ 路由映射插件执行失败:', error) + callback(error) + } + }) + }, + + // Vite插件接口 buildStart() { - console.log('🔧 开始分析AST和Vite编译时关系...') - this.analyzeASTAndViteRelations() + console.log('🔧 第一阶段:开始收集直接路由-API映射关系...') + this.collectDirectMappings() }, // 在开发模式下也执行 configureServer(server) { - console.log('🔧 开发模式下分析AST和Vite编译时关系...') - this.analyzeASTAndViteRelations() + console.log('🔧 开发模式下收集直接映射关系...') + this.collectDirectMappings() }, - // 利用AST解析获取实际存在的路由关系 - analyzeASTAndViteRelations() { + // 收集直接映射关系 + collectDirectMappings() { try { - // 1. 分析路由配置的AST - const routerAST = this.analyzeRouterAST() - - // 2. 分析组件文件的AST - const componentASTs = this.analyzeComponentASTs() + // 1. 分析路由配置 + const routes = this.analyzeRoutes() - // 3. 分析服务文件的AST - const serviceASTs = this.analyzeServiceASTs() + // 2. 分析页面组件(第一层) + const pageMappings = this.analyzePageComponents(routes) - // 4. 建立真实的调用关系(只基于AST分析) - const callRelations = this.buildCallRelations(routerAST, componentASTs, serviceASTs) + // 3. 分析弹窗组件(第二层) + const modalMappings = this.analyzeModalComponents() - // 5. 生成基于实际关系的路由映射 - const routeMappings = this.generateRealRouteMappings(callRelations) + // 4. 生成映射文件 + this.generateMappingFile(pageMappings, modalMappings) - // 6. 生成映射文件 - this.generateRouteMappingFile(routeMappings) - - console.log('✅ 基于AST的实际路由关系分析完成') + console.log('✅ 第一阶段直接映射关系收集完成') } catch (error) { - console.error('❌ AST路由关系分析失败:', error) - // AST分析失败时直接记录错误,不进行回退分析 - console.error('❌ 路由映射生成失败,请检查代码结构和依赖') + console.error('❌ 直接映射关系收集失败:', error) throw error } }, - // 从模块配置中读取模块名称(同步,基于AST解析 config.js) - readModuleNamesFromConfig() { - try { - const configPath = resolve(__dirname, '../src/renderer/modules/config.js') - if (!existsSync(configPath)) { - return [] - } - - const code = readFileSync(configPath, 'utf-8') - const ast = parser.parse(code, { sourceType: 'module' }) - const modules = [] - - traverse(ast, { - ExportNamedDeclaration(path) { - const decl = path.node.declaration - if (decl && decl.type === 'VariableDeclaration') { - decl.declarations.forEach(d => { - if ( - d.id && d.id.name === 'MODULE_CONFIG' && - d.init && d.init.type === 'ObjectExpression' - ) { - d.init.properties.forEach(prop => { - if (prop.type === 'ObjectProperty') { - if (prop.key.type === 'Identifier') { - modules.push(prop.key.name) - } else if (prop.key.type === 'StringLiteral') { - modules.push(prop.key.value) - } - } - }) - } - }) - } - } - }) - - return modules - } catch (e) { - console.warn('⚠️ 读取 MODULE_CONFIG 失败,使用默认模块集合: ', e.message) - return [] - } - }, - - // 分析路由AST - analyzeRouterAST() { + // 分析路由配置 + analyzeRoutes() { const routerPath = resolve(__dirname, '../src/renderer/router/index.js') - if (!fs.existsSync(routerPath)) { + if (!existsSync(routerPath)) { throw new Error('Router file not found') } - const routerContent = fs.readFileSync(routerPath, 'utf-8') + const routerContent = readFileSync(routerPath, 'utf-8') const ast = parser.parse(routerContent, { sourceType: 'module', plugins: ['jsx'] @@ -110,8 +88,8 @@ export function routeMappingPlugin() { const routes = [] + const self = this traverse(ast, { - // 查找路由配置对象 ObjectExpression(path) { const properties = path.node.properties let route = {} @@ -124,427 +102,401 @@ export function routeMappingPlugin() { route.name = prop.value.value } if (prop.key && prop.key.name === 'component' && prop.value) { - route.component = this.extractComponentName(prop.value) + route.component = self.extractComponentName(prop.value) } }) if (route.path) { - route.module = this.extractModuleFromPath(route.path) + route.module = self.extractModuleFromPath(route.path) routes.push(route) } } }) - return { routes, ast } + return routes }, - - // 分析组件AST - analyzeComponentASTs() { - const componentASTs = new Map() - const componentFiles = this.findComponentFiles() - - componentFiles.forEach(componentFile => { - try { - const content = fs.readFileSync(componentFile.path, 'utf-8') - - if (componentFile.path.endsWith('.vue')) { - // 解析Vue文件 - const { descriptor } = parse(content) - const scriptContent = descriptor.script?.content || '' - - if (scriptContent) { - const scriptAST = parser.parse(scriptContent, { - sourceType: 'module', - plugins: ['jsx'] - }) - - const analysis = this.analyzeVueComponentAST(scriptAST, componentFile.name) - componentASTs.set(componentFile.name, { - ...analysis, - file: componentFile, - template: descriptor.template?.content || '' - }) - } - } else { - // 解析JS文件 - const ast = parser.parse(content, { - sourceType: 'module', - plugins: ['jsx'] - }) - - const analysis = this.analyzeJavaScriptComponentAST(ast, componentFile.name) - componentASTs.set(componentFile.name, { - ...analysis, - file: componentFile + + // 分析页面组件(第一层) + analyzePageComponents(routes) { + const pageMappings = [] + + routes.forEach(route => { + if (route.component) { + const componentAnalysis = this.analyzeComponent(route.component, route.path) + if (componentAnalysis && componentAnalysis.apiCalls.length > 0) { + pageMappings.push({ + route: route.path, + routeName: route.name, + component: route.component, + module: route.module, + layer: 'page', + apiCalls: componentAnalysis.apiCalls, + methods: componentAnalysis.methods }) } - } catch (error) { - console.warn(`⚠️ 解析组件文件失败: ${componentFile.path}`, error.message) } }) - return componentASTs + return pageMappings }, - - // 分析服务AST - analyzeServiceASTs() { - const serviceASTs = new Map() - const serviceFiles = this.findServiceFiles() - - serviceFiles.forEach(serviceFile => { - try { - const content = fs.readFileSync(serviceFile.path, 'utf-8') - const ast = parser.parse(content, { - sourceType: 'module', - plugins: ['jsx'] - }) - - const analysis = this.analyzeServiceAST(ast, serviceFile.name) - serviceASTs.set(serviceFile.name, { - ...analysis, - file: serviceFile + + // 分析弹窗组件(第二层) + analyzeModalComponents() { + const modalMappings = [] + const modalFiles = this.findModalFiles() + + modalFiles.forEach(modalFile => { + const analysis = this.analyzeComponent(modalFile.name, modalFile.path) + if (analysis && analysis.apiCalls.length > 0) { + modalMappings.push({ + component: modalFile.name, + path: modalFile.path, + module: modalFile.module, + layer: 'modal', + apiCalls: analysis.apiCalls, + methods: analysis.methods }) - } catch (error) { - console.warn(`⚠️ 解析服务文件失败: ${serviceFile.path}`, error.message) } }) - return serviceASTs + return modalMappings }, - - // 分析Vue组件AST - analyzeVueComponentAST(ast, componentName) { - const analysis = { - imports: [], - exports: [], - methods: [], - serviceCalls: [], - events: [] + + // 分析单个组件 + analyzeComponent(componentName, componentPath) { + try { + let filePath = componentPath + + // 如果是组件名,需要找到对应的文件 + if (!filePath || !existsSync(filePath)) { + filePath = this.findComponentFile(componentName) + } + + if (!filePath || !existsSync(filePath)) { + console.warn(`⚠️ 组件文件未找到: ${componentName}`) + return null + } + + const content = readFileSync(filePath, 'utf-8') + + if (filePath.endsWith('.vue')) { + return this.analyzeVueComponent(content, componentName) + } else { + return this.analyzeJavaScriptComponent(content, componentName) + } + } catch (error) { + console.warn(`⚠️ 分析组件失败: ${componentName}`, error.message) + return null + } + }, + + // 分析Vue组件 + analyzeVueComponent(content, componentName) { + const { descriptor } = parse(content) + const scriptContent = descriptor.script?.content || '' + + if (!scriptContent) { + return { apiCalls: [], methods: [] } } + const ast = parser.parse(scriptContent, { + sourceType: 'module', + plugins: ['jsx'] + }) + + return this.extractApiCallsFromAST(ast, componentName) + }, + + // 分析JavaScript组件 + analyzeJavaScriptComponent(content, componentName) { + const ast = parser.parse(content, { + sourceType: 'module', + plugins: ['jsx'] + }) + + return this.extractApiCallsFromAST(ast, componentName) + }, + + // 从AST中提取API调用 + extractApiCallsFromAST(ast, componentName) { + const apiCalls = [] + const methods = [] + + const self = this traverse(ast, { - // 查找import语句 - ImportDeclaration(path) { - const importSpecifiers = path.node.specifiers - importSpecifiers.forEach(specifier => { - if (specifier.type === 'ImportSpecifier') { - analysis.imports.push({ - name: specifier.imported.name, - local: specifier.local.name, - source: path.node.source.value - }) - } - }) - }, - // 查找方法定义 FunctionDeclaration(path) { if (path.node.id) { - analysis.methods.push(path.node.id.name) + methods.push(path.node.id.name) } }, // 查找箭头函数 ArrowFunctionExpression(path) { if (path.parent && path.parent.type === 'VariableDeclarator' && path.parent.id) { - analysis.methods.push(path.parent.id.name) + methods.push(path.parent.id.name) } }, - // 查找服务调用 + // 查找API调用 CallExpression(path) { - if (path.node.callee && path.node.callee.type === 'MemberExpression') { - const object = path.node.callee.object - const property = path.node.callee.property - - if (object && property && object.name && property.name) { - // 检查是否是服务调用 - const serviceName = object.name - const methodName = property.name - - if (serviceName.endsWith('Service')) { - analysis.serviceCalls.push({ - service: serviceName, - method: methodName, - arguments: path.node.arguments.map(arg => this.extractArgumentValue(arg)) - }) - } - } + const callInfo = self.extractApiCall(path) + if (callInfo) { + apiCalls.push(callInfo) } } }) - return analysis - }, - - // 分析JavaScript组件AST - analyzeJavaScriptComponentAST(ast, componentName) { - return this.analyzeVueComponentAST(ast, componentName) + return { apiCalls, methods } }, - - // 分析服务AST - analyzeServiceAST(ast, serviceName) { - const analysis = { - exports: [], - methods: [], - apiCalls: [], - imports: [] - } - - traverse(ast, { - // 查找export语句 - ExportNamedDeclaration(path) { - if (path.node.declaration && path.node.declaration.type === 'VariableDeclarator') { - analysis.exports.push(path.node.declaration.id.name) - } - }, + + // 提取API调用信息 + extractApiCall(path) { + const node = path.node + const self = this + + // 检查是否是服务调用 (service.method()) + if (node.callee && node.callee.type === 'MemberExpression') { + const object = node.callee.object + const property = node.callee.property - // 查找方法定义 - FunctionDeclaration(path) { - if (path.node.id) { - analysis.methods.push(path.node.id.name) + if (object && property && object.name && property.name) { + // 检查是否是服务调用 + if (object.name.endsWith('Service') || object.name === 'api' || object.name === 'axios') { + return { + type: 'service', + service: object.name, + method: property.name, + arguments: node.arguments.map(arg => self.extractArgumentValue(arg)), + line: node.loc?.start?.line || 0 + } } - }, + } + } + + // 检查是否是直接的API调用 (api.get, api.post等) + if (node.callee && node.callee.type === 'MemberExpression') { + const object = node.callee.object + const property = node.callee.property - // 查找API调用 - CallExpression(path) { - if (path.node.callee && path.node.callee.type === 'MemberExpression') { - const object = path.node.callee.object - const property = path.node.callee.property + if (object && property) { + if (object.name === 'api' || object.name === 'axios' || object.name === 'http') { + const method = property.name + const args = node.arguments - if (object && property) { - // 检查是否是API调用 - if (object.name === 'api' || object.name === 'axios' || object.name === 'http') { - const method = property.name - const args = path.node.arguments - - if (args.length > 0 && args[0].type === 'StringLiteral') { - analysis.apiCalls.push({ - method: method.toUpperCase(), - path: args[0].value, - arguments: args.slice(1).map(arg => this.extractArgumentValue(arg)) - }) - } + if (args.length > 0 && args[0].type === 'StringLiteral') { + return { + type: 'api', + method: method.toUpperCase(), + path: args[0].value, + arguments: args.slice(1).map(arg => self.extractArgumentValue(arg)), + line: node.loc?.start?.line || 0 } } } } - }) - - return analysis - }, - - // 建立调用关系 - buildCallRelations(routerAST, componentASTs, serviceASTs) { - const relations = { - routes: routerAST.routes, - components: new Map(), - services: new Map(), - callGraph: new Map(), - imports: new Map() - } - - // 建立组件关系 - componentASTs.forEach((analysis, componentName) => { - relations.components.set(componentName, { - ...analysis, - serviceDependencies: analysis.serviceCalls.map(call => call.service) - }) - }) - - // 建立服务关系 - serviceASTs.forEach((analysis, serviceName) => { - relations.services.set(serviceName, { - ...analysis, - apiEndpoints: analysis.apiCalls - }) - }) - - // 建立调用图 - componentASTs.forEach((componentAnalysis, componentName) => { - const calls = [] - - componentAnalysis.serviceCalls.forEach(call => { - calls.push({ - type: 'service', - target: call.service, - method: call.method, - component: componentName - }) - }) - - relations.callGraph.set(componentName, calls) - }) - - return relations - }, - - // 生成基于实际关系的路由映射(不进行规则推断) - generateRealRouteMappings(callRelations) { - const mappings = { - mainRoutes: [], - moduleApiMappings: {}, - subRouteMappings: {}, - callRelations: callRelations } - // 生成主路由(基于实际路由配置) - callRelations.routes.forEach(route => { - mappings.mainRoutes.push({ - path: route.path, - name: route.name, - module: route.module, - description: this.generateDescription(route.name, route.module), - type: this.determineRouteType(route.path, route.module), - component: route.component - }) - }) - - // 生成API映射(基于实际API调用) - callRelations.services.forEach((serviceAnalysis, serviceName) => { - const moduleName = this.extractModuleFromService(serviceName) - if (moduleName && serviceAnalysis.apiCalls.length > 0) { - const apiMapping = this.buildApiMappingFromRealCalls(serviceAnalysis.apiCalls, moduleName) - mappings.moduleApiMappings[moduleName] = apiMapping - } - }) - - // 生成子路由映射(基于实际调用关系) - mappings.subRouteMappings = this.generateSubRouteMappingsFromRelations(callRelations) - - return mappings + return null }, - - // 从实际API调用构建API映射(不进行操作推断) - buildApiMappingFromRealCalls(apiCalls, moduleName) { - const operations = {} - const paths = [] - - apiCalls.forEach(call => { - // 使用实际的API路径作为操作名,不进行推断 - const operationKey = `${call.method}_${call.path.replace(/[^a-zA-Z0-9]/g, '_')}` - operations[operationKey] = { - path: call.path, - method: call.method + + // 从模块配置中读取模块名称 + readModuleNamesFromConfig() { + try { + const configPath = resolve(__dirname, '../src/renderer/modules/config.js') + if (!existsSync(configPath)) { + return [] } - paths.push(call.path) - }) - - const basePath = this.extractBasePath(paths) - - return { - basePath: basePath, - operations: operations - } - }, - - // 从API调用获取实际操作(不进行推断) - inferOperationFromApiCall(path, method) { - // 只返回实际存在的路径,不进行规则推断 - return path - }, - - // 从关系生成子路由映射(只基于实际存在的调用关系) - generateSubRouteMappingsFromRelations(callRelations) { - const subRouteMappings = {} - - callRelations.callGraph.forEach((calls, componentName) => { - calls.forEach(call => { - if (call.type === 'service') { - // 只记录实际存在的服务调用,不生成预估的子路由 - const serviceName = call.target - const methodName = call.method - - // 检查服务是否真实存在 - if (callRelations.services.has(serviceName)) { - const serviceAnalysis = callRelations.services.get(serviceName) - - // 只记录实际存在的API调用 - serviceAnalysis.apiCalls.forEach(apiCall => { - const key = `${componentName}_${serviceName}_${methodName}` - subRouteMappings[key] = { - component: componentName, - service: serviceName, - method: methodName, - apiPath: apiCall.path, - apiMethod: apiCall.method + + const code = readFileSync(configPath, 'utf-8') + const ast = parser.parse(code, { sourceType: 'module' }) + const modules = [] + + traverse(ast, { + ExportNamedDeclaration(path) { + const decl = path.node.declaration + if (decl && decl.type === 'VariableDeclaration') { + decl.declarations.forEach(d => { + if ( + d.id && d.id.name === 'MODULE_CONFIG' && + d.init && d.init.type === 'ObjectExpression' + ) { + d.init.properties.forEach(prop => { + if (prop.type === 'ObjectProperty') { + if (prop.key.type === 'Identifier') { + modules.push(prop.key.name) + } else if (prop.key.type === 'StringLiteral') { + modules.push(prop.key.value) + } + } + }) } }) } } }) - }) - - return subRouteMappings - }, - - - - - // 查找组件文件 - findComponentFiles() { - const componentFiles = [] - let moduleDirs = this.readModuleNamesFromConfig() - if (!moduleDirs || moduleDirs.length === 0) { - throw new Error('未能从 MODULE_CONFIG 读取到任何模块,请检查 app/src/renderer/modules/config.js 中的 MODULE_CONFIG 配置') + return modules + } catch (e) { + console.warn('⚠️ 读取 MODULE_CONFIG 失败,使用默认模块集合: ', e.message) + return [] } - + }, + + // 查找弹窗文件 + findModalFiles() { + const modalFiles = [] + const moduleDirs = this.readModuleNamesFromConfig() + moduleDirs.forEach(moduleName => { - const viewsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/views`) const componentsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/components`) - - if (existsSync(viewsPath)) { - const files = readdirSync(viewsPath).filter(f => f.endsWith('.vue')) + + if (existsSync(componentsPath)) { + const files = readdirSync(componentsPath).filter(f => + f.endsWith('.vue') && (f.toLowerCase().includes('modal') || f.toLowerCase().includes('dialog')) + ) files.forEach(file => { - componentFiles.push({ + modalFiles.push({ name: file.replace('.vue', ''), - path: resolve(viewsPath, file), - module: moduleName, - type: 'view' + path: resolve(componentsPath, file), + module: moduleName }) }) } + }) + + return modalFiles + }, + // 查找组件文件 + findComponentFile(componentName) { + const moduleDirs = this.readModuleNamesFromConfig() + + for (const moduleName of moduleDirs) { + // 查找views目录 + const viewsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/views`) + if (existsSync(viewsPath)) { + const files = readdirSync(viewsPath).filter(f => f.endsWith('.vue')) + const matchingFile = files.find(f => f.replace('.vue', '') === componentName) + if (matchingFile) { + return resolve(viewsPath, matchingFile) + } + } + + // 查找components目录 + const componentsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/components`) if (existsSync(componentsPath)) { const files = readdirSync(componentsPath).filter(f => f.endsWith('.vue')) - files.forEach(file => { - componentFiles.push({ - name: file.replace('.vue', ''), - path: resolve(componentsPath, file), - module: moduleName, - type: 'component' - }) - }) + const matchingFile = files.find(f => f.replace('.vue', '') === componentName) + if (matchingFile) { + return resolve(componentsPath, matchingFile) + } } - }) + } + + return null + }, + + // 生成映射文件 + generateMappingFile(pageMappings, modalMappings) { + const mappingContent = `// 第一阶段:直接路由-API映射关系 +// 此文件由 route-mapping-plugin 在构建时生成 +// 收集页面和弹窗组件的直接API调用关系 +// 请勿手动修改 + +export const directRouteMappings = { + // 第一层:页面组件的数据操作API + pageMappings: ${JSON.stringify(pageMappings, null, 2)}, + + // 第二层:弹窗组件的数据操作API + modalMappings: ${JSON.stringify(modalMappings, null, 2)}, + + // 分析信息 + 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)} + } +} + +// 按模块分组的映射 +export const moduleMappings = ${JSON.stringify(this.groupMappingsByModule(pageMappings, modalMappings), null, 2)} - return componentFiles +// 按API路径分组的映射 +export const apiPathMappings = ${JSON.stringify(this.groupMappingsByApiPath(pageMappings, modalMappings), null, 2)} + +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}`) + console.log(`📊 统计信息:`) + console.log(` - 页面组件: ${pageMappings.length} 个`) + 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)} 个`) }, - - // 查找服务文件 - findServiceFiles() { - const serviceFiles = [] - let moduleDirs = this.readModuleNamesFromConfig() - if (!moduleDirs || moduleDirs.length === 0) { - throw new Error('未能从 MODULE_CONFIG 读取到任何模块,请检查 app/src/renderer/modules/config.js 中的 MODULE_CONFIG 配置') - } - moduleDirs.forEach(moduleName => { - const servicesPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/services`) - if (existsSync(servicesPath)) { - const files = readdirSync(servicesPath).filter(f => f.endsWith('.js')) - files.forEach(file => { - serviceFiles.push({ - name: file.replace('.js', ''), - path: resolve(servicesPath, file), - module: moduleName - }) - }) + // 按模块分组映射 + groupMappingsByModule(pageMappings, modalMappings) { + const grouped = {} + + // 分组页面映射 + pageMappings.forEach(mapping => { + const module = mapping.module || 'unknown' + if (!grouped[module]) { + grouped[module] = { pages: [], modals: [] } + } + grouped[module].pages.push(mapping) + }) + + // 分组弹窗映射 + modalMappings.forEach(mapping => { + const module = mapping.module || 'unknown' + if (!grouped[module]) { + grouped[module] = { pages: [], modals: [] } } + grouped[module].modals.push(mapping) }) + + return grouped + }, - return serviceFiles + // 按API路径分组映射 + groupMappingsByApiPath(pageMappings, modalMappings) { + const grouped = {} + + const addToGroup = (mapping, layer) => { + mapping.apiCalls.forEach(apiCall => { + let key = '' + if (apiCall.type === 'api') { + key = `${apiCall.method} ${apiCall.path}` + } else if (apiCall.type === 'service') { + key = `${apiCall.service}.${apiCall.method}` + } + + if (key) { + if (!grouped[key]) { + grouped[key] = { pages: [], modals: [] } + } + grouped[key][layer].push({ + component: mapping.component, + module: mapping.module, + route: mapping.route || mapping.path, + apiCall: apiCall + }) + } + }) + } + + pageMappings.forEach(mapping => addToGroup(mapping, 'pages')) + modalMappings.forEach(mapping => addToGroup(mapping, 'modals')) + + return grouped }, // 提取组件名称 @@ -569,119 +521,16 @@ export function routeMappingPlugin() { return null }, - // 从服务方法获取实际操作(不进行推断) - inferOperationFromServiceMethod(methodName) { - // 只返回实际存在的方法名,不进行硬编码映射 - return methodName - }, - - // 从服务名提取模块名(基于实际文件路径) - extractModuleFromService(serviceName) { - // 通过实际文件路径来确定模块,而不是硬编码映射 - const serviceFiles = this.findServiceFiles() - const serviceFile = serviceFiles.find(file => file.name === serviceName) - - if (serviceFile) { - return serviceFile.module - } - - return null - }, - - // 提取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 - }, - - // 从路径提取模块名(基于实际路由配置) + // 从路径提取模块名 extractModuleFromPath(path) { if (path === '/' || path === '') return 'home' const segments = path.split('/').filter(Boolean) if (segments.length === 0) return 'home' - // 获取第一个段作为模块名,不进行硬编码映射 return segments[0] - }, - - // 生成路由描述(基于实际名称) - generateDescription(name, module) { - // 只使用实际的路由名称,不进行硬编码描述 - return `${name}页面` - }, - - // 确定路由类型(基于实际路径) - determineRouteType(path, module) { - if (path === '/' || path === '') return 'home' - - // 基于实际路径结构确定类型,不进行硬编码映射 - if (path.includes('/:') || path.includes('/{')) { - return 'detail' - } - - return 'list' - }, - - // 生成路由映射文件 - generateRouteMappingFile(routeMappings) { - const mappingContent = `// 自动生成的路由映射文件 -// 此文件由 route-mapping-plugin 在构建时生成 -// 基于AST解析获取实际存在的路由关系,不进行规则推断 -// 请勿手动修改 - -export const mainRoutes = ${JSON.stringify(routeMappings.mainRoutes, null, 2)} - -// 模块到API映射配置(从AST解析提取) -export const moduleApiMappings = ${JSON.stringify(routeMappings.moduleApiMappings, null, 2)} - -// 子路由到主路由的映射(从调用关系提取) -export const subRouteMappings = ${JSON.stringify(routeMappings.subRouteMappings, null, 2)} - -// 分析方法和结果 -export const analysisInfo = ${JSON.stringify({ - method: routeMappings.method || 'ast-analysis', - timestamp: new Date().toISOString(), - hasCallRelations: !!routeMappings.callRelations, - componentCount: routeMappings.callRelations?.components?.size || 0, - serviceCount: routeMappings.callRelations?.services?.size || 0 -}, null, 2)} - -export default { - mainRoutes, - moduleApiMappings, - subRouteMappings, - analysisInfo -} -` - - const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/generated-route-mapping.js') - fs.writeFileSync(outputPath, mappingContent, 'utf-8') - - console.log(`✅ 基于AST实际路由关系的映射文件已生成: ${outputPath}`) } } } + +module.exports = { routeMappingPlugin } diff --git a/gofaster/app/scripts/generate-route-mappings.js b/gofaster/app/scripts/generate-route-mappings.js new file mode 100644 index 0000000..b437c96 --- /dev/null +++ b/gofaster/app/scripts/generate-route-mappings.js @@ -0,0 +1,14 @@ +const { routeMappingPlugin } = require('../plugins/route-mapping-plugin.js') + +// 独立运行路由映射生成 +console.log('🔧 独立生成路由映射文件...') + +try { + const plugin = routeMappingPlugin() + plugin.collectDirectMappings() + console.log('✅ 路由映射文件生成完成') +} catch (error) { + console.error('❌ 路由映射文件生成失败:', error) + process.exit(1) +} + diff --git a/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js b/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js index 9460403..b3402e4 100644 --- a/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js +++ b/gofaster/app/src/renderer/modules/route-sync/RouteCollector.js @@ -1,5 +1,5 @@ // 路由收集器 - 收集前端路由信息 -import { mainRoutes } from './generated-route-mapping.js' +import { directRouteMappings } from './direct-route-mappings.js' import { RouteUtils } from './RouteConfig.js' // 路由收集器 @@ -12,24 +12,21 @@ export class RouteCollector { collectRoutes() { try { // 从生成的路由映射文件收集 - if (!mainRoutes || !Array.isArray(mainRoutes)) { + if (!directRouteMappings || !directRouteMappings.pageMappings) { console.warn('⚠️ 生成的路由映射文件格式不正确') return [] } - // 转换为主入口路由格式 - const frontendRoutes = mainRoutes.map(route => { - // 确保模块信息正确 - if (!route.module) { - route.module = RouteUtils.extractModuleFromPath(route.path) - } - + // 从页面映射中提取路由信息 + const frontendRoutes = directRouteMappings.pageMappings.map(mapping => { return { - path: route.path, - name: route.name, - module: route.module, - description: route.description || route.name, - type: route.type || 'list' + path: mapping.route, + name: mapping.routeName, + module: mapping.module, + description: `${mapping.routeName}页面`, + type: 'list', + component: mapping.component, + apiCalls: mapping.apiCalls } }) diff --git a/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js b/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js index a137ef3..19a6959 100644 --- a/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js +++ b/gofaster/app/src/renderer/modules/route-sync/RouteMapper.js @@ -1,6 +1,6 @@ // 路由映射器 - 将前端路由映射到后端API import { RouteUtils, RouteConfig } from './RouteConfig.js' -import { subRouteMappings, moduleApiMappings } from './generated-route-mapping.js' +import { directRouteMappings } from './direct-route-mappings.js' export class RouteMapper { constructor() { @@ -79,42 +79,57 @@ export class RouteMapper { // 获取子路由映射 _getSubRouteMapping(routePath) { try { - return subRouteMappings[routePath] || null + // 从新的直接映射文件中查找 + if (directRouteMappings && directRouteMappings.pageMappings) { + const pageMapping = directRouteMappings.pageMappings.find(p => p.route === routePath) + if (pageMapping && pageMapping.apiCalls) { + return { + route: routePath, + apiCalls: pageMapping.apiCalls + } + } + } + return null } catch (error) { return null } } - // 获取模块的API配置 - 合并生成的文件和默认配置 + // 获取模块的API配置 - 基于直接映射关系 _getApiConfigForModule(module) { let apiConfig = null - // 首先尝试从生成的路由映射文件获取 + // 从直接映射文件中获取API调用信息 try { - if (moduleApiMappings && moduleApiMappings[module]) { - apiConfig = { ...moduleApiMappings[module] } + if (directRouteMappings && directRouteMappings.pageMappings) { + const moduleMappings = directRouteMappings.pageMappings.filter(p => p.module === module) + if (moduleMappings.length > 0) { + const operations = {} + moduleMappings.forEach(mapping => { + mapping.apiCalls.forEach(apiCall => { + const operationKey = `${apiCall.type}_${apiCall.service || apiCall.method}_${apiCall.method || apiCall.path}` + operations[operationKey] = { + path: apiCall.path || `/${apiCall.service}/${apiCall.method}`, + method: apiCall.method || 'GET' + } + }) + }) + + if (Object.keys(operations).length > 0) { + apiConfig = { + basePath: '/api', + operations: operations + } + } + } } } catch (error) { - // 如果获取失败,使用默认配置 + console.warn('获取直接映射配置失败:', error) } - // 如果没有从生成文件获取到,使用默认配置 + // 如果没有从直接映射获取到,使用默认配置 if (!apiConfig) { apiConfig = { ...this.defaultApiMappings[module] } - } else { - // 合并默认配置中的缺失操作 - const defaultConfig = this.defaultApiMappings[module] - if (defaultConfig && defaultConfig.operations) { - if (!apiConfig.operations) { - apiConfig.operations = {} - } - // 只添加生成文件中没有的操作 - Object.keys(defaultConfig.operations).forEach(operation => { - if (!apiConfig.operations[operation]) { - apiConfig.operations[operation] = defaultConfig.operations[operation] - } - }) - } } return apiConfig diff --git a/gofaster/app/vue.config.js b/gofaster/app/vue.config.js index 012ced8..c76e866 100644 --- a/gofaster/app/vue.config.js +++ b/gofaster/app/vue.config.js @@ -1,5 +1,6 @@ const path = require('path') const { defineConfig } = require('@vue/cli-service') +const { routeMappingPlugin } = require('./plugins/route-mapping-plugin.js') // 设置环境变量 process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = 'false' @@ -161,6 +162,9 @@ module.exports = defineConfig({ }, chainWebpack: config => { + // 添加路由映射插件 + config.plugin('route-mapping').use(routeMappingPlugin()) + // 强制禁用所有sourcemap,避免eval config.devtool(false)