Compare commits

...

2 Commits

  1. 15
      gofaster/app/dev-enhanced.ps1
  2. 6124
      gofaster/app/dist/renderer/js/index.js
  3. 2
      gofaster/app/package.json
  4. 1102
      gofaster/app/plugins/route-mapping-plugin.js
  5. 21
      gofaster/app/scripts/generate-route-mappings.js
  6. 16
      gofaster/app/src/renderer/main.js
  7. 548
      gofaster/app/src/renderer/modules/role-management/views/RoleApiTest.vue
  8. 14
      gofaster/app/src/renderer/modules/route-sync/RouteCollector.js
  9. 4
      gofaster/app/src/renderer/modules/route-sync/RouteConfig.js
  10. 57
      gofaster/app/src/renderer/modules/route-sync/RouteMapper.js
  11. 53
      gofaster/app/src/renderer/modules/route-sync/RouteSyncManager.js
  12. 352
      gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js
  13. 19
      gofaster/app/vue.config.js
  14. 23
      gofaster/dev-full.ps1
  15. 133
      gofaster/start-enhanced.ps1
  16. 92
      gofaster/test-route-sync-fix.ps1
  17. 88
      gofaster/test-route-sync-optimization.ps1

15
gofaster/app/dev-enhanced.ps1

@ -54,6 +54,21 @@ if (-not $crossEnvInstalled) { @@ -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

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

File diff suppressed because it is too large Load Diff

2
gofaster/app/package.json

@ -3,7 +3,7 @@ @@ -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",

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

File diff suppressed because it is too large Load Diff

21
gofaster/app/scripts/generate-route-mappings.js

@ -1,7 +1,26 @@ @@ -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()

16
gofaster/app/src/renderer/main.js

@ -165,8 +165,13 @@ async function startApp() { @@ -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() { @@ -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 方法不可用')

548
gofaster/app/src/renderer/modules/role-management/views/RoleApiTest.vue

@ -1,548 +0,0 @@ @@ -1,548 +0,0 @@
<template>
<div class="role-api-test">
<div class="page-header">
<h2>角色管理API测试</h2>
<div class="header-actions">
<button
class="btn btn-secondary"
@click="toggleTestMode"
:title="testMode ? '当前为测试模式(无需认证)' : '当前为正式模式(需要认证)'"
>
<i class="fas fa-flask"></i>
{{ testMode ? '测试模式' : '正式模式' }}
</button>
<button class="btn btn-primary" @click="runAllTests">
<i class="fas fa-play"></i> 运行所有测试
</button>
</div>
</div>
<div class="test-content">
<!-- API配置信息 -->
<div class="test-section">
<h3>API配置信息</h3>
<div class="config-info">
<div class="config-item">
<label>API基础地址:</label>
<span>{{ apiBaseUrl }}</span>
</div>
<div class="config-item">
<label>当前模式:</label>
<span :class="testMode ? 'test-mode' : 'prod-mode'">
{{ testMode ? '测试模式' : '正式模式' }}
</span>
</div>
<div class="config-item">
<label>API路径:</label>
<span>{{ currentApiPath }}</span>
</div>
</div>
</div>
<!-- 测试结果 -->
<div class="test-section">
<h3>测试结果</h3>
<div class="test-results">
<div
v-for="(result, index) in testResults"
:key="index"
class="test-result-item"
:class="result.status"
>
<div class="test-header">
<span class="test-name">{{ result.name }}</span>
<span class="test-status">{{ getStatusText(result.status) }}</span>
</div>
<div v-if="result.message" class="test-message">
{{ result.message }}
</div>
<div v-if="result.data" class="test-data">
<pre>{{ JSON.stringify(result.data, null, 2) }}</pre>
</div>
</div>
</div>
</div>
<!-- 手动测试 -->
<div class="test-section">
<h3>手动测试</h3>
<div class="manual-tests">
<div class="test-group">
<h4>获取角色列表</h4>
<button @click="testGetRoles" :disabled="testing">
{{ testing ? '测试中...' : '测试获取角色列表' }}
</button>
</div>
<div class="test-group">
<h4>创建角色</h4>
<div class="form-group">
<label>角色名称:</label>
<input v-model="testRole.name" type="text" placeholder="测试角色" />
</div>
<div class="form-group">
<label>角色代码:</label>
<input v-model="testRole.code" type="text" placeholder="TEST_ROLE" />
</div>
<div class="form-group">
<label>描述:</label>
<input v-model="testRole.description" type="text" placeholder="测试角色描述" />
</div>
<button @click="testCreateRole" :disabled="testing">
{{ testing ? '测试中...' : '测试创建角色' }}
</button>
</div>
<div class="test-group">
<h4>更新角色</h4>
<div class="form-group">
<label>角色ID:</label>
<input v-model="updateRoleId" type="number" placeholder="输入角色ID" />
</div>
<button @click="testUpdateRole" :disabled="testing || !updateRoleId">
{{ testing ? '测试中...' : '测试更新角色' }}
</button>
</div>
<div class="test-group">
<h4>删除角色</h4>
<div class="form-group">
<label>角色ID:</label>
<input v-model="deleteRoleId" type="number" placeholder="输入角色ID" />
</div>
<button @click="testDeleteRole" :disabled="testing || !deleteRoleId">
{{ testing ? '测试中...' : '测试删除角色' }}
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, reactive, computed, onMounted } from 'vue'
import { roleService } from '../services/roleService.js'
import { getFinalConfig } from '../../../../config/app.config.js'
export default {
name: 'RoleApiTest',
setup() {
const testing = ref(false)
const testMode = ref(false)
const testResults = ref([])
const updateRoleId = ref('')
const deleteRoleId = ref('')
const testRole = reactive({
name: '测试角色',
code: 'TEST_ROLE',
description: '这是一个测试角色'
})
const apiBaseUrl = computed(() => getFinalConfig().apiBaseUrl)
const currentApiPath = computed(() => testMode.value ? '/auth/roles/test' : '/auth/roles')
//
const toggleTestMode = () => {
testMode.value = roleService.toggleTestMode()
addTestResult('模式切换', 'success', `已切换到${testMode.value ? '测试' : '正式'}模式`)
}
//
const addTestResult = (name, status, message, data = null) => {
testResults.value.unshift({
name,
status,
message,
data,
timestamp: new Date().toLocaleString()
})
}
//
const getStatusText = (status) => {
const statusMap = {
'success': '成功',
'error': '失败',
'warning': '警告'
}
return statusMap[status] || status
}
//
const testGetRoles = async () => {
testing.value = true
try {
const response = await roleService.getRoles(1, 10)
if (response.code === 200) {
addTestResult('获取角色列表', 'success', '获取角色列表成功', response.data)
} else {
addTestResult('获取角色列表', 'error', `获取失败: ${response.message}`, response)
}
} catch (error) {
addTestResult('获取角色列表', 'error', `请求失败: ${error.message || error.error}`, error)
} finally {
testing.value = false
}
}
//
const testCreateRole = async () => {
testing.value = true
try {
const response = await roleService.createRole(testRole)
if (response.code === 200) {
addTestResult('创建角色', 'success', '创建角色成功', response.data)
} else {
addTestResult('创建角色', 'error', `创建失败: ${response.message}`, response)
}
} catch (error) {
addTestResult('创建角色', 'error', `请求失败: ${error.message || error.error}`, error)
} finally {
testing.value = false
}
}
//
const testUpdateRole = async () => {
if (!updateRoleId.value) {
addTestResult('更新角色', 'warning', '请输入角色ID')
return
}
testing.value = true
try {
const updateData = {
name: `${testRole.name}_更新`,
code: `${testRole.code}_UPDATED`,
description: `${testRole.description}_更新`
}
const response = await roleService.updateRole(updateRoleId.value, updateData)
if (response.code === 200) {
addTestResult('更新角色', 'success', '更新角色成功', response.data)
} else {
addTestResult('更新角色', 'error', `更新失败: ${response.message}`, response)
}
} catch (error) {
addTestResult('更新角色', 'error', `请求失败: ${error.message || error.error}`, error)
} finally {
testing.value = false
}
}
//
const testDeleteRole = async () => {
if (!deleteRoleId.value) {
addTestResult('删除角色', 'warning', '请输入角色ID')
return
}
testing.value = true
try {
const response = await roleService.deleteRole(deleteRoleId.value)
if (response.code === 200) {
addTestResult('删除角色', 'success', '删除角色成功', response.data)
} else {
addTestResult('删除角色', 'error', `删除失败: ${response.message}`, response)
}
} catch (error) {
addTestResult('删除角色', 'error', `请求失败: ${error.message || error.error}`, error)
} finally {
testing.value = false
}
}
//
const runAllTests = async () => {
addTestResult('测试开始', 'success', '开始运行所有API测试')
await testGetRoles()
await new Promise(resolve => setTimeout(resolve, 1000)) // 1
await testCreateRole()
await new Promise(resolve => setTimeout(resolve, 1000)) // 1
addTestResult('测试完成', 'success', '所有API测试已完成')
}
onMounted(() => {
testMode.value = roleService.getTestModeStatus()
addTestResult('页面加载', 'success', '角色管理API测试页面已加载')
})
return {
testing,
testMode,
testResults,
updateRoleId,
deleteRoleId,
testRole,
apiBaseUrl,
currentApiPath,
toggleTestMode,
testGetRoles,
testCreateRole,
testUpdateRole,
testDeleteRole,
runAllTests,
getStatusText
}
}
}
</script>
<style scoped>
.role-api-test {
padding: 20px;
height: 100%;
overflow-y: auto;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.page-header h2 {
margin: 0;
color: var(--text-primary);
}
.header-actions {
display: flex;
gap: 12px;
align-items: center;
}
.test-content {
max-width: 1200px;
}
.test-section {
background: var(--card-bg);
border-radius: 8px;
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 2px 8px var(--shadow-color);
}
.test-section h3 {
margin: 0 0 20px 0;
color: var(--text-primary);
font-size: 18px;
border-bottom: 2px solid var(--border-color);
padding-bottom: 8px;
}
.config-info {
display: grid;
gap: 12px;
}
.config-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background: var(--bg-secondary);
border-radius: 4px;
}
.config-item label {
font-weight: 500;
color: var(--text-primary);
}
.config-item span {
color: var(--text-secondary);
font-family: monospace;
}
.test-mode {
color: #ff9800 !important;
font-weight: bold;
}
.prod-mode {
color: #4caf50 !important;
font-weight: bold;
}
.test-results {
max-height: 400px;
overflow-y: auto;
}
.test-result-item {
margin-bottom: 16px;
padding: 16px;
border-radius: 6px;
border-left: 4px solid;
}
.test-result-item.success {
background: rgba(76, 175, 80, 0.1);
border-left-color: #4caf50;
}
.test-result-item.error {
background: rgba(244, 67, 54, 0.1);
border-left-color: #f44336;
}
.test-result-item.warning {
background: rgba(255, 152, 0, 0.1);
border-left-color: #ff9800;
}
.test-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.test-name {
font-weight: 500;
color: var(--text-primary);
}
.test-status {
font-size: 12px;
padding: 4px 8px;
border-radius: 4px;
font-weight: 500;
}
.test-result-item.success .test-status {
background: #4caf50;
color: white;
}
.test-result-item.error .test-status {
background: #f44336;
color: white;
}
.test-result-item.warning .test-status {
background: #ff9800;
color: white;
}
.test-message {
color: var(--text-secondary);
margin-bottom: 8px;
}
.test-data {
background: var(--bg-secondary);
padding: 12px;
border-radius: 4px;
overflow-x: auto;
}
.test-data pre {
margin: 0;
font-size: 12px;
color: var(--text-secondary);
}
.manual-tests {
display: grid;
gap: 24px;
}
.test-group {
padding: 16px;
background: var(--bg-secondary);
border-radius: 6px;
}
.test-group h4 {
margin: 0 0 16px 0;
color: var(--text-primary);
}
.form-group {
margin-bottom: 12px;
}
.form-group label {
display: block;
margin-bottom: 4px;
font-weight: 500;
color: var(--text-primary);
}
.form-group input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 4px;
background: var(--input-bg);
color: var(--input-text);
box-sizing: border-box;
}
.btn {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.btn-primary {
background: var(--accent-color);
color: white;
}
.btn-primary:hover {
background: var(--accent-hover);
}
.btn-secondary {
background: #757575;
color: white;
}
.btn-secondary:hover {
background: #616161;
}
.btn:hover {
opacity: 0.9;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
button {
background: var(--accent-color);
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
button:hover:not(:disabled) {
background: var(--accent-hover);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>

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

@ -11,14 +11,26 @@ export class RouteCollector { @@ -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 { @@ -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 []
}
}

4
gofaster/app/src/renderer/modules/route-sync/RouteConfig.js

@ -6,7 +6,9 @@ export const RouteConfig = { @@ -6,7 +6,9 @@ export const RouteConfig = {
'user-management': '用户管理',
'role-management': '角色管理',
'system-settings': '系统设置',
'route-sync': '路由同步测试'
'settings': '用户设置',
'user-profile': '个人资料',
'route-sync': '路由同步'
},
// 路由类型映射

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

@ -4,7 +4,7 @@ import { directRouteMappings } from './direct-route-mappings.js' @@ -4,7 +4,7 @@ import { directRouteMappings } from './direct-route-mappings.js'
export class RouteMapper {
constructor() {
this.defaultApiMappings = RouteConfig.defaultApiMappings
// 不再依赖硬编码的默认配置
}
// 生成路由映射
@ -29,29 +29,50 @@ export class RouteMapper { @@ -29,29 +29,50 @@ 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
// 如果是直接的API调用(type: 'api'),直接使用
if (apiCall.type === 'api' && apiCall.method && apiCall.path) {
return {
frontend_route: route.path,
backend_route: apiCall.path,
http_method: apiCall.method,
module: module,
operation: `${apiCall.method} ${apiCall.path}`,
service: 'direct',
method: apiCall.method,
path: apiCall.path
}
}
// 如果是服务调用(type: 'service'),需要进一步分析
if (apiCall.type === 'service' && apiCall.service && apiCall.method) {
// 这里应该已经被enhanceApiCallsWithServiceAnalysis处理过了
// 如果还是service类型,说明服务文件分析失败,使用默认映射
console.warn(` 服务调用 ${apiCall.service}.${apiCall.method} 无法解析为具体API`)
return null
}
return null
}
// 创建API映射
_createApiMapping(route, operation) {
const module = route.module

53
gofaster/app/src/renderer/modules/route-sync/RouteSyncManager.js

@ -3,6 +3,9 @@ import { RouteCollector } from './RouteCollector.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 { @@ -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 { @@ -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 { @@ -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 { @@ -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
}
}
}

352
gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js

@ -0,0 +1,352 @@ @@ -0,0 +1,352 @@
// 直接路由映射文件
// 此文件由 route-mapping-plugin 在构建时生成
// 包含路由配置分析结果和API收集结果
// 请勿手动修改
export const directRouteMappings = {
// 路由配置分析结果
routes: [
{
"path": "/",
"component": "MainLayout",
"module": "home",
"description": "首页"
},
{
"path": "/user-management",
"name": "UserManagement",
"component": "UserManagement",
"module": "user-management",
"description": "用户管理"
},
{
"path": "/settings",
"name": "Settings",
"component": "Settings",
"module": "settings",
"description": "用户设置"
},
{
"path": "/user-profile",
"name": "UserProfile",
"component": "UserProfile",
"module": "user-management",
"description": "用户管理"
},
{
"path": "/role-management",
"name": "RoleManagement",
"component": "RoleManagement",
"module": "role-management",
"description": "角色管理"
}
],
// API收集结果(包含页面关联和路径完善)
apiMappings: [
{
"module": "user-management",
"serviceName": "userService",
"servicePath": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\user-management\\services\\userService.js",
"apiMappings": [
{
"methodName": "getUsers",
"method": "GET",
"path": "/auth/admin/users",
"line": 51,
"callingComponents": [
{
"component": "UserManagement",
"path": "/user-management"
}
]
},
{
"methodName": "createUser",
"method": "POST",
"path": "/auth/admin/users",
"line": 73,
"callingComponents": [
{
"component": "UserManagement",
"path": "/user-management"
}
]
},
{
"methodName": "updateUser",
"method": "PUT",
"path": "/auth/admin/users/{Identifier}",
"line": 83,
"callingComponents": [
{
"component": "UserManagement",
"path": "/user-management"
}
]
},
{
"methodName": "deleteUser",
"method": "DELETE",
"path": "/auth/admin/users/{Identifier}",
"line": 93,
"callingComponents": [
{
"component": "UserManagement",
"path": "/user-management"
}
]
},
{
"methodName": "changePassword",
"method": "POST",
"path": "/auth/change-password",
"line": 113,
"callingComponents": [
{
"component": "PasswordChangeModal",
"path": "/"
}
]
},
{
"methodName": "getPasswordPolicy",
"method": "GET",
"path": "/auth/password-policy",
"line": 123,
"callingComponents": [
{
"component": "PasswordChangeModal",
"path": "/"
}
]
},
{
"methodName": "validatePassword",
"method": "POST",
"path": "/auth/validate-password",
"line": 133,
"callingComponents": [
{
"component": "PasswordChangeModal",
"path": "/"
}
]
},
{
"methodName": "getCaptcha",
"method": "GET",
"path": "/auth/captcha",
"line": 163,
"callingComponents": [
{
"component": "LoginModal",
"path": "/"
}
]
},
{
"methodName": "login",
"method": "POST",
"path": "/auth/login",
"line": 182,
"callingComponents": [
{
"component": "LoginModal",
"path": "/"
}
]
},
{
"methodName": "getCurrentUser",
"method": "GET",
"path": "/auth/userinfo",
"line": 245,
"callingComponents": [
{
"component": "UserProfile",
"path": "/user-profile"
}
]
},
{
"methodName": "changePassword",
"method": "POST",
"path": "/auth/change-password",
"line": 259,
"callingComponents": [
{
"component": "PasswordChangeModal",
"path": "/"
}
]
}
]
},
{
"module": "role-management",
"serviceName": "roleService",
"servicePath": "D:\\aigc\\manta\\gofaster\\app\\src\\renderer\\modules\\role-management\\services\\roleService.js",
"apiMappings": [
{
"methodName": "getRoles",
"method": "GET",
"path": "/auth/roles",
"line": 48,
"callingComponents": [
{
"component": "RoleManagement",
"path": "/role-management"
},
{
"component": "UserRoleAssignment",
"path": "/user-management"
}
]
},
{
"methodName": "getRole",
"method": "GET",
"path": "/auth/roles/{Identifier}",
"line": 60,
"callingComponents": [
{
"component": "PermissionManager",
"path": null
}
]
},
{
"methodName": "createRole",
"method": "POST",
"path": "/auth/roles",
"line": 70,
"callingComponents": [
{
"component": "RoleManagement",
"path": "/role-management"
}
]
},
{
"methodName": "updateRole",
"method": "PUT",
"path": "/auth/roles/{Identifier}",
"line": 80,
"callingComponents": [
{
"component": "RoleManagement",
"path": "/role-management"
},
{
"component": "PermissionManager",
"path": null
}
]
},
{
"methodName": "deleteRole",
"method": "DELETE",
"path": "/auth/roles/{Identifier}",
"line": 90,
"callingComponents": [
{
"component": "RoleManagement",
"path": "/role-management"
}
]
},
{
"methodName": "getPermissions",
"method": "GET",
"path": "/auth/permissions",
"line": 100,
"callingComponents": [
{
"component": "PermissionManager",
"path": null
},
{
"component": "RolePermissionAssignment",
"path": "/role-management"
}
]
},
{
"methodName": "assignRolesToUser",
"method": "POST",
"path": "/auth/roles/users/{Identifier}/assign",
"line": 110,
"callingComponents": [
{
"component": "UserRoleAssignment",
"path": "/user-management"
}
]
},
{
"methodName": "getUserRoles",
"method": "GET",
"path": "/auth/roles/users/{Identifier}",
"line": 122,
"callingComponents": [
{
"component": "UserRoleAssignment",
"path": "/user-management"
}
]
},
{
"methodName": "removeRolesFromUser",
"method": "DELETE",
"path": "/auth/roles/users/{Identifier}/remove",
"line": 132,
"callingComponents": [
{
"component": "UserRoleAssignment",
"path": "/user-management"
}
]
},
{
"methodName": "getRolePermissions",
"method": "GET",
"path": "/auth/permissions/roles/{Identifier}",
"line": 144,
"callingComponents": [
{
"component": "RolePermissionAssignment",
"path": "/role-management"
}
]
},
{
"methodName": "assignPermissionsToRole",
"method": "POST",
"path": "/auth/permissions/roles/{Identifier}/assign",
"line": 154,
"callingComponents": [
{
"component": "RolePermissionAssignment",
"path": "/role-management"
}
]
},
{
"methodName": "removePermissionsFromRole",
"method": "DELETE",
"path": "/auth/permissions/roles/{Identifier}/remove",
"line": 166,
"callingComponents": [
{
"component": "RolePermissionAssignment",
"path": "/role-management"
}
]
}
]
}
]
}
export default directRouteMappings

19
gofaster/app/vue.config.js

@ -32,6 +32,16 @@ module.exports = defineConfig({ @@ -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({ @@ -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,

23
gofaster/dev-full.ps1

@ -54,6 +54,29 @@ if (-not (Test-Path "app/node_modules")) { @@ -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) {

133
gofaster/start-enhanced.ps1

@ -0,0 +1,133 @@ @@ -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")

92
gofaster/test-route-sync-fix.ps1

@ -0,0 +1,92 @@ @@ -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

88
gofaster/test-route-sync-optimization.ps1

@ -0,0 +1,88 @@ @@ -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
Loading…
Cancel
Save