mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 02:47:45 +08:00
refactor: 继续拆分大型模块并增强模块注册健壮性
后端: - chat_handler_base 错误处理函数提取到 chat_error_utils 子模块 - CLI mixin 引入 CliHandlerProtocol 协议类改善类型标注 - aware_scheduler 拆分为 _candidate_builder 和 _candidate_sorter 子模块 - usage recording 拆分为 _billing_integration 和 _recording_helpers 子模块 - ModuleRegistry 添加循环依赖检测,将写操作从查询方法分离到 reconcile_module_state - 修正 plugin manager 入度注释 前端: - 路由守卫逻辑拆分为独立 guards 模块 - ProviderManagement 拆分为 TableHeader/TableRow/BalanceCell/MobileCard 子组件 - SystemSettings 拆分为多个 Section 子组件和 composables - 提取 useEndpointStatus/useProviderBalance/useProviderFilters composables 测试适配重构后的子模块结构
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
import type { useAuthStore } from '@/stores/auth'
|
||||
import type { useModuleStore } from '@/stores/modules'
|
||||
import { log } from '@/utils/logger'
|
||||
|
||||
/**
|
||||
* 检查管理员权限和管理端模块可用性。
|
||||
* @returns 重定向路径,或 null 表示通过
|
||||
*/
|
||||
export async function checkAdminAccess(
|
||||
to: RouteLocationNormalized,
|
||||
authStore: ReturnType<typeof useAuthStore>,
|
||||
moduleStore: ReturnType<typeof useModuleStore>
|
||||
): Promise<string | null> {
|
||||
const isAdmin = authStore.user?.role === 'admin'
|
||||
if (!isAdmin) {
|
||||
log.warn('Non-admin user attempted to access admin page, redirecting to user dashboard')
|
||||
return '/dashboard'
|
||||
}
|
||||
|
||||
// 检查路由链中是否有模块要求
|
||||
const moduleName = to.matched.find(record => record.meta.module)?.meta.module as
|
||||
| string
|
||||
| undefined
|
||||
if (!moduleName) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 确保模块状态已加载
|
||||
if (!moduleStore.loaded) {
|
||||
try {
|
||||
await moduleStore.fetchModules()
|
||||
} catch (error) {
|
||||
// fail-close: 获取模块状态失败时拒绝访问
|
||||
log.warn('Failed to fetch modules status, denying access', { error })
|
||||
return '/admin/dashboard'
|
||||
}
|
||||
}
|
||||
|
||||
// 如果模块不可用(未部署),重定向到管理员首页
|
||||
// 注意:只检查 available,不检查 enabled/active,允许管理员配置未启用的模块
|
||||
if (!moduleStore.isAvailable(moduleName)) {
|
||||
log.warn(`Module ${moduleName} is not available, redirecting to admin dashboard`)
|
||||
return '/admin/dashboard'
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { useAuthStore } from '@/stores/auth'
|
||||
import { log } from '@/utils/logger'
|
||||
|
||||
/**
|
||||
* 判断错误是否为网络错误
|
||||
*/
|
||||
function isNetworkError(error: any): boolean {
|
||||
return !error.response || error.message?.includes('Network') || error.message?.includes('timeout')
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保用户信息已加载。如果有 token 但未加载用户信息,尝试获取。
|
||||
* @returns true 如果用户已认证,false 如果认证失败
|
||||
*/
|
||||
export async function ensureUserLoaded(
|
||||
authStore: ReturnType<typeof useAuthStore>
|
||||
): Promise<boolean> {
|
||||
if (authStore.token && !authStore.user) {
|
||||
try {
|
||||
await authStore.fetchCurrentUser()
|
||||
} catch (error: any) {
|
||||
// 区分网络错误和认证错误
|
||||
if (isNetworkError(error)) {
|
||||
log.warn('Network error while fetching user info, keeping session', {
|
||||
error: error?.message
|
||||
})
|
||||
} else if (error.response?.status === 401) {
|
||||
log.info('Authentication failed, clearing session')
|
||||
authStore.logout()
|
||||
} else {
|
||||
log.warn('Failed to fetch user info, but keeping session', { error: error?.message })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !!authStore.token
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
import type { useAuthStore } from '@/stores/auth'
|
||||
|
||||
/**
|
||||
* 处理已认证用户访问首页时的重定向。
|
||||
* @returns 重定向路径,null 表示不需要重定向,空字符串表示放行(不跳转)
|
||||
*/
|
||||
export function resolveHomeRedirect(
|
||||
to: RouteLocationNormalized,
|
||||
from: RouteLocationNormalized,
|
||||
authStore: ReturnType<typeof useAuthStore>
|
||||
): string | null {
|
||||
if (to.path !== '/') {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!authStore.isAuthenticated) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 已登录用户如果是从dashboard返回首页、刷新首页、或者有returnTo参数,允许访问首页
|
||||
const isFromApp =
|
||||
from.path.startsWith('/dashboard') || from.path.startsWith('/admin') || from.path === '/'
|
||||
if (to.query.returnTo || isFromApp) {
|
||||
return ''
|
||||
}
|
||||
|
||||
// 已登录用户首次访问首页(非返回/刷新场景),根据角色跳转到对应仪表盘
|
||||
const isAdmin = authStore.user?.role === 'admin'
|
||||
const redirectPath = sessionStorage.getItem('redirectPath')
|
||||
if (redirectPath && redirectPath !== '/') {
|
||||
sessionStorage.removeItem('redirectPath')
|
||||
return redirectPath
|
||||
}
|
||||
|
||||
return isAdmin ? '/admin/dashboard' : '/dashboard'
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export { ensureUserLoaded } from './authGuard'
|
||||
export { resolveHomeRedirect } from './homeGuard'
|
||||
export { checkAdminAccess } from './adminGuard'
|
||||
export { checkModuleAccess } from './moduleGuard'
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
import type { useModuleStore } from '@/stores/modules'
|
||||
import { log } from '@/utils/logger'
|
||||
|
||||
/**
|
||||
* 检查非管理端路由的模块激活状态。
|
||||
* @returns 重定向路径,或 null 表示通过
|
||||
*/
|
||||
export async function checkModuleAccess(
|
||||
to: RouteLocationNormalized,
|
||||
moduleStore: ReturnType<typeof useModuleStore>
|
||||
): Promise<string | null> {
|
||||
// 检查路由链中是否有模块要求
|
||||
const moduleName = to.matched.find(record => record.meta.module)?.meta.module as
|
||||
| string
|
||||
| undefined
|
||||
if (!moduleName) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 确保模块状态已加载
|
||||
if (!moduleStore.loaded) {
|
||||
try {
|
||||
await moduleStore.fetchModules()
|
||||
} catch (error) {
|
||||
// fail-close: 获取模块状态失败时拒绝访问
|
||||
log.warn('Failed to fetch modules status, denying access', { error })
|
||||
return '/dashboard'
|
||||
}
|
||||
}
|
||||
|
||||
// 用户侧需要检查模块是否激活(active),而不仅仅是可用(available)
|
||||
if (!moduleStore.isActive(moduleName)) {
|
||||
log.warn(`Module ${moduleName} is not active, redirecting to user dashboard`)
|
||||
return '/dashboard'
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user