|
|
|
@ -1,149 +1,63 @@
@@ -1,149 +1,63 @@
|
|
|
|
|
// 路由同步服务 - 负责与后端API通信并同步路由信息
|
|
|
|
|
import { RouteCollector } from './RouteCollector' |
|
|
|
|
import { RouteMapper } from './RouteMapper' |
|
|
|
|
import axios from 'axios' |
|
|
|
|
|
|
|
|
|
// 路由同步服务
|
|
|
|
|
export class RouteSyncService { |
|
|
|
|
constructor(apiBaseUrl = 'http://localhost:8080') { |
|
|
|
|
this.apiBaseUrl = apiBaseUrl |
|
|
|
|
this.routeCollector = new RouteCollector() |
|
|
|
|
this.routeMapper = new RouteMapper() |
|
|
|
|
this.syncStatus = { |
|
|
|
|
lastSync: null, |
|
|
|
|
totalRoutes: 0, |
|
|
|
|
syncedRoutes: 0, |
|
|
|
|
errors: [] |
|
|
|
|
} |
|
|
|
|
this.axios = axios.create({ |
|
|
|
|
baseURL: apiBaseUrl, |
|
|
|
|
timeout: 10000 |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 执行路由同步
|
|
|
|
|
async syncRoutes() { |
|
|
|
|
// 同步路由到后端
|
|
|
|
|
async syncRoutes(routeMappings) { |
|
|
|
|
try { |
|
|
|
|
console.log('🔄 开始同步前端路由到后端...') |
|
|
|
|
|
|
|
|
|
// 1. 收集前端路由
|
|
|
|
|
const frontendRoutes = this.routeCollector.collectRoutes() |
|
|
|
|
console.log(`📋 收集到 ${frontendRoutes.length} 个前端路由:`, frontendRoutes) |
|
|
|
|
|
|
|
|
|
// 检查每个路由的模块信息
|
|
|
|
|
frontendRoutes.forEach((route, index) => { |
|
|
|
|
console.log(`🔍 路由 ${index}: path="${route.path}", module="${route.module}", name="${route.name}"`) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 2. 生成路由映射
|
|
|
|
|
const routeMappings = this.routeMapper.generateRouteMappings(frontendRoutes) |
|
|
|
|
console.log(`🔗 生成 ${routeMappings.length} 个路由映射:`, routeMappings) |
|
|
|
|
|
|
|
|
|
// 3. 验证映射
|
|
|
|
|
console.log('🔍 开始验证路由映射...') |
|
|
|
|
const validation = this.routeMapper.validateMappings(routeMappings) |
|
|
|
|
console.log('🔍 验证结果:', validation) |
|
|
|
|
if (!validation.isValid) { |
|
|
|
|
console.error('❌ 路由映射验证失败:', validation.errors) |
|
|
|
|
|
|
|
|
|
// 详细显示失败的映射
|
|
|
|
|
const failedMappings = routeMappings.filter((_, index) =>
|
|
|
|
|
validation.errors.some(error => error.includes(`映射 ${index}:`)) |
|
|
|
|
) |
|
|
|
|
console.error('❌ 失败的映射详情:') |
|
|
|
|
failedMappings.forEach((mapping, index) => { |
|
|
|
|
console.error(` 映射 ${index}:`, { |
|
|
|
|
frontend_route: mapping.frontend_route, |
|
|
|
|
backend_route: mapping.backend_route, |
|
|
|
|
http_method: mapping.http_method, |
|
|
|
|
module: mapping.module, |
|
|
|
|
description: mapping.description |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.syncStatus.errors = validation.errors |
|
|
|
|
return false |
|
|
|
|
if (!routeMappings || routeMappings.length === 0) { |
|
|
|
|
return { success: false, errors: ['没有路由映射需要同步'] } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按模块分组路由映射
|
|
|
|
|
const moduleGroups = this._groupMappingsByModule(routeMappings) |
|
|
|
|
|
|
|
|
|
// 4. 同步到后端
|
|
|
|
|
const syncResult = await this._syncToBackend(routeMappings) |
|
|
|
|
|
|
|
|
|
// 5. 更新同步状态
|
|
|
|
|
this.syncStatus = { |
|
|
|
|
lastSync: new Date(), |
|
|
|
|
totalRoutes: frontendRoutes.length, |
|
|
|
|
syncedRoutes: routeMappings.length, |
|
|
|
|
errors: syncResult.errors || [] |
|
|
|
|
const results = { |
|
|
|
|
success: true, |
|
|
|
|
errors: [], |
|
|
|
|
details: {} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
console.log(`✅ 路由同步完成: ${syncResult.success} 个成功, ${syncResult.errors?.length || 0} 个错误`) |
|
|
|
|
return syncResult.success > 0 |
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('❌ 路由同步失败:', error) |
|
|
|
|
this.syncStatus.errors.push(error.message) |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 同步到后端
|
|
|
|
|
async _syncToBackend(routeMappings) { |
|
|
|
|
const results = { |
|
|
|
|
success: 0, |
|
|
|
|
errors: [] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按模块分组处理,避免重复同步
|
|
|
|
|
const moduleGroups = this._groupMappingsByModule(routeMappings) |
|
|
|
|
|
|
|
|
|
for (const [module, mappings] of Object.entries(moduleGroups)) { |
|
|
|
|
try { |
|
|
|
|
console.log(`🔄 同步模块 "${module}" 的 ${mappings.length} 个映射...`) |
|
|
|
|
|
|
|
|
|
// 构建前台路由数据
|
|
|
|
|
const frontendRouteData = this._buildFrontendRouteData(module, mappings) |
|
|
|
|
|
|
|
|
|
const response = await fetch(`${this.apiBaseUrl}/api/frontend-routes/batch-sync`, { |
|
|
|
|
method: 'POST', |
|
|
|
|
headers: { |
|
|
|
|
'Content-Type': 'application/json', |
|
|
|
|
// 这里可以添加认证头
|
|
|
|
|
// 'Authorization': `Bearer ${token}`
|
|
|
|
|
}, |
|
|
|
|
body: JSON.stringify(frontendRouteData) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
if (!response.ok) { |
|
|
|
|
const errorText = await response.text() |
|
|
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const result = await response.json() |
|
|
|
|
console.log(`✅ 模块 "${module}" 同步成功:`, result) |
|
|
|
|
|
|
|
|
|
// 检查后端响应格式
|
|
|
|
|
if (result.code === 200 && result.message) { |
|
|
|
|
results.success += mappings.length |
|
|
|
|
} else { |
|
|
|
|
console.warn(`⚠️ 模块 "${module}" 同步响应异常:`, result) |
|
|
|
|
results.errors.push({ |
|
|
|
|
module, |
|
|
|
|
error: '同步响应异常', |
|
|
|
|
details: result |
|
|
|
|
}) |
|
|
|
|
// 逐个模块同步
|
|
|
|
|
for (const [module, mappings] of Object.entries(moduleGroups)) { |
|
|
|
|
try { |
|
|
|
|
const result = await this._syncModule(module, mappings) |
|
|
|
|
results.details[module] = result |
|
|
|
|
|
|
|
|
|
if (!result.success) { |
|
|
|
|
results.success = false |
|
|
|
|
results.errors.push(...result.errors) |
|
|
|
|
} |
|
|
|
|
} catch (error) { |
|
|
|
|
results.success = false |
|
|
|
|
results.errors.push(`模块 "${module}" 同步失败: ${error.message}`) |
|
|
|
|
results.details[module] = { success: false, error: error.message } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`❌ 模块 "${module}" 同步失败:`, error) |
|
|
|
|
results.errors.push({ |
|
|
|
|
module, |
|
|
|
|
error: error.message |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return results |
|
|
|
|
} catch (error) { |
|
|
|
|
return { |
|
|
|
|
success: false, |
|
|
|
|
errors: [`同步失败: ${error.message}`] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return results |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按模块分组映射
|
|
|
|
|
_groupMappingsByModule(routeMappings) { |
|
|
|
|
_groupMappingsByModule(mappings) { |
|
|
|
|
const groups = {} |
|
|
|
|
|
|
|
|
|
routeMappings.forEach(mapping => { |
|
|
|
|
mappings.forEach(mapping => { |
|
|
|
|
const module = mapping.module |
|
|
|
|
if (!groups[module]) { |
|
|
|
|
groups[module] = [] |
|
|
|
@ -154,28 +68,63 @@ export class RouteSyncService {
@@ -154,28 +68,63 @@ export class RouteSyncService {
|
|
|
|
|
return groups |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 构建前台路由数据
|
|
|
|
|
// 同步单个模块
|
|
|
|
|
async _syncModule(module, mappings) { |
|
|
|
|
try { |
|
|
|
|
// 构建前端路由数据
|
|
|
|
|
const frontendRouteData = this._buildFrontendRouteData(module, mappings) |
|
|
|
|
|
|
|
|
|
if (frontendRouteData.length === 0) { |
|
|
|
|
return { success: false, errors: [`模块 "${module}" 没有有效的前端路由数据`] } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 发送到后端
|
|
|
|
|
const response = await this.axios.post('/api/frontend-routes/batch-sync', frontendRouteData) |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
success: true, |
|
|
|
|
data: response.data, |
|
|
|
|
count: frontendRouteData.length |
|
|
|
|
} |
|
|
|
|
} catch (error) { |
|
|
|
|
if (error.response) { |
|
|
|
|
return { |
|
|
|
|
success: false, |
|
|
|
|
errors: [`HTTP ${error.response.status}: ${error.response.data?.message || error.message}`] |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
return { |
|
|
|
|
success: false, |
|
|
|
|
errors: [`网络错误: ${error.message}`] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 构建前端路由数据
|
|
|
|
|
_buildFrontendRouteData(module, mappings) { |
|
|
|
|
// 按前台路由分组
|
|
|
|
|
const frontendRouteGroups = {} |
|
|
|
|
|
|
|
|
|
mappings.forEach(mapping => { |
|
|
|
|
const frontendRoute = mapping.frontend_route |
|
|
|
|
|
|
|
|
|
if (!frontendRouteGroups[frontendRoute]) { |
|
|
|
|
frontendRouteGroups[frontendRoute] = { |
|
|
|
|
path: frontendRoute, |
|
|
|
|
name: frontendRoute.split('/').pop() || 'default', |
|
|
|
|
component: 'Unknown', |
|
|
|
|
name: this._extractRouteName(frontendRoute), |
|
|
|
|
component: this._generateComponent(frontendRoute, module), |
|
|
|
|
module: module, |
|
|
|
|
description: mapping.description, |
|
|
|
|
sort: 0, |
|
|
|
|
description: this._generateDescription(frontendRoute, module), |
|
|
|
|
sort: this._generateSort(frontendRoute, module), |
|
|
|
|
type: this._determineRouteType(frontendRoute, module), |
|
|
|
|
backend_routes: [] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 检查是否已存在相同的后台路由
|
|
|
|
|
// 检查是否已存在相同的后端路由
|
|
|
|
|
const existingRoute = frontendRouteGroups[frontendRoute].backend_routes.find( |
|
|
|
|
route => route.backend_route === mapping.backend_route && route.http_method === mapping.http_method |
|
|
|
|
route => route.backend_route === mapping.backend_route &&
|
|
|
|
|
route.http_method === mapping.http_method |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if (!existingRoute) { |
|
|
|
@ -183,138 +132,93 @@ export class RouteSyncService {
@@ -183,138 +132,93 @@ export class RouteSyncService {
|
|
|
|
|
backend_route: mapping.backend_route, |
|
|
|
|
http_method: mapping.http_method, |
|
|
|
|
module: module, |
|
|
|
|
description: mapping.description |
|
|
|
|
description: mapping.operation || 'unknown' |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
console.log(`⚠️ 跳过重复的后台路由: ${mapping.backend_route} (${mapping.http_method})`) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 转换为数组格式(批量同步期望数组)
|
|
|
|
|
return Object.values(frontendRouteGroups) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 同步单个映射(保留原有方法,用于兼容)
|
|
|
|
|
async _syncSingleMapping(mapping) { |
|
|
|
|
try { |
|
|
|
|
console.log(`🔄 同步映射: ${mapping.frontend_route} -> ${mapping.backend_route}`) |
|
|
|
|
|
|
|
|
|
// 构建前台路由数据
|
|
|
|
|
const frontendRouteData = { |
|
|
|
|
path: mapping.frontend_route, |
|
|
|
|
name: mapping.frontend_route.split('/').pop() || 'default', |
|
|
|
|
component: 'Unknown', |
|
|
|
|
module: mapping.module, |
|
|
|
|
description: mapping.description, |
|
|
|
|
sort: 0, |
|
|
|
|
backend_routes: [{ |
|
|
|
|
backend_route: mapping.backend_route, |
|
|
|
|
http_method: mapping.http_method, |
|
|
|
|
module: mapping.module, |
|
|
|
|
description: mapping.description |
|
|
|
|
}] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const response = await fetch(`${this.apiBaseUrl}/api/frontend-routes/sync`, { |
|
|
|
|
method: 'POST', |
|
|
|
|
headers: { |
|
|
|
|
'Content-Type': 'application/json', |
|
|
|
|
// 这里可以添加认证头
|
|
|
|
|
// 'Authorization': `Bearer ${token}`
|
|
|
|
|
}, |
|
|
|
|
body: JSON.stringify(frontendRouteData) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
if (!response.ok) { |
|
|
|
|
const errorText = await response.text() |
|
|
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const result = await response.json() |
|
|
|
|
console.log(`✅ 同步成功: ${mapping.frontend_route} -> ${mapping.backend_route}`, result) |
|
|
|
|
|
|
|
|
|
// 检查后端响应格式
|
|
|
|
|
if (result.code === 200 && result.message) { |
|
|
|
|
return true |
|
|
|
|
} else { |
|
|
|
|
console.warn(`⚠️ 同步响应异常:`, result) |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`❌ 同步映射失败: ${mapping.frontend_route} -> ${mapping.backend_route}`, error) |
|
|
|
|
throw error |
|
|
|
|
// 提取路由名称
|
|
|
|
|
_extractRouteName(path) { |
|
|
|
|
if (path === '/' || path === '') return 'Home' |
|
|
|
|
|
|
|
|
|
const segments = path.split('/').filter(Boolean) |
|
|
|
|
if (segments.length === 0) return 'Home' |
|
|
|
|
|
|
|
|
|
const lastSegment = segments[segments.length - 1] |
|
|
|
|
return lastSegment.charAt(0).toUpperCase() + lastSegment.slice(1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 生成描述
|
|
|
|
|
_generateDescription(path, module) { |
|
|
|
|
const descriptions = { |
|
|
|
|
'home': '首页', |
|
|
|
|
'user-management': '用户管理', |
|
|
|
|
'role-management': '角色管理', |
|
|
|
|
'system-settings': '系统设置', |
|
|
|
|
'route-sync': '路由同步测试' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return descriptions[module] || `${this._extractRouteName(path)}页面` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取同步状态
|
|
|
|
|
getSyncStatus() { |
|
|
|
|
return { |
|
|
|
|
...this.syncStatus, |
|
|
|
|
isSynced: this.syncStatus.lastSync !== null && this.syncStatus.errors.length === 0 |
|
|
|
|
// 确定路由类型
|
|
|
|
|
_determineRouteType(path, module) { |
|
|
|
|
if (path === '/' || path === '') return 'home' |
|
|
|
|
|
|
|
|
|
const typeMap = { |
|
|
|
|
'user-management': 'list', |
|
|
|
|
'role-management': 'list', |
|
|
|
|
'system-settings': 'form', |
|
|
|
|
'route-sync': 'test' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return typeMap[module] || 'list' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取前端路由信息
|
|
|
|
|
getFrontendRoutes() { |
|
|
|
|
return this.routeCollector.collectRoutes() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取路由映射
|
|
|
|
|
getRouteMappings() { |
|
|
|
|
const frontendRoutes = this.routeCollector.collectRoutes() |
|
|
|
|
return this.routeMapper.generateRouteMappings(frontendRoutes) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按模块获取路由
|
|
|
|
|
getRoutesByModule() { |
|
|
|
|
return this.routeCollector.getRoutesByModule() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取菜单路由
|
|
|
|
|
getMenuRoutes() { |
|
|
|
|
return this.routeCollector.getMenuRoutes() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取操作路由
|
|
|
|
|
getOperationRoutes() { |
|
|
|
|
return this.routeCollector.getOperationRoutes() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 添加自定义API映射
|
|
|
|
|
addApiMapping(module, config) { |
|
|
|
|
this.routeMapper.addApiMapping(module, config) |
|
|
|
|
// 生成组件名称
|
|
|
|
|
_generateComponent(path, module) { |
|
|
|
|
if (path === '/' || path === '') return 'Home' |
|
|
|
|
|
|
|
|
|
const segments = path.split('/').filter(Boolean) |
|
|
|
|
if (segments.length === 0) return 'Home' |
|
|
|
|
|
|
|
|
|
const lastSegment = segments[segments.length - 1] |
|
|
|
|
const componentName = lastSegment.charAt(0).toUpperCase() + lastSegment.slice(1) |
|
|
|
|
|
|
|
|
|
// 特殊处理某些路径
|
|
|
|
|
if (path === '/route-sync') { |
|
|
|
|
return 'RouteSync' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return componentName |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 设置API基础URL
|
|
|
|
|
setApiBaseUrl(url) { |
|
|
|
|
this.apiBaseUrl = url |
|
|
|
|
// 生成排序值
|
|
|
|
|
_generateSort(path, module) { |
|
|
|
|
const sortMap = { |
|
|
|
|
'home': 1, |
|
|
|
|
'user-management': 10, |
|
|
|
|
'role-management': 20, |
|
|
|
|
'system-settings': 30, |
|
|
|
|
'route-sync': 100 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return sortMap[module] || 50 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 手动触发同步
|
|
|
|
|
async manualSync() { |
|
|
|
|
console.log('🔄 手动触发路由同步...') |
|
|
|
|
return await this.syncRoutes() |
|
|
|
|
async manualSync(routeMappings) { |
|
|
|
|
return await this.syncRoutes(routeMappings) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取同步统计信息
|
|
|
|
|
getSyncStats() { |
|
|
|
|
const frontendRoutes = this.routeCollector.collectRoutes() |
|
|
|
|
const routeMappings = this.routeMapper.generateRouteMappings(frontendRoutes) |
|
|
|
|
const routesByModule = this.routeCollector.getRoutesByModule() |
|
|
|
|
const operationRoutes = this.routeCollector.getOperationRoutes() |
|
|
|
|
|
|
|
|
|
// 获取同步状态
|
|
|
|
|
getSyncStatus() { |
|
|
|
|
return { |
|
|
|
|
frontendRoutes: frontendRoutes.length, |
|
|
|
|
routeMappings: routeMappings.length, |
|
|
|
|
modules: Object.keys(routesByModule).length, |
|
|
|
|
operationRoutes: operationRoutes.length, |
|
|
|
|
moduleStats: Object.keys(routesByModule).map(module => ({ |
|
|
|
|
module, |
|
|
|
|
routes: routesByModule[module].length |
|
|
|
|
})), |
|
|
|
|
lastSync: this.syncStatus.lastSync, |
|
|
|
|
errors: this.syncStatus.errors.length |
|
|
|
|
apiBaseUrl: this.apiBaseUrl, |
|
|
|
|
isConnected: true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|