Merge branch 'PingChuan' into shiy-login

# Conflicts:
#	app/config/api-config.ts
fix: 1. 修复无法加载数据的问题:没有从入口页中进来会缺少数据。
2. 加强后端接口关于token的校验错误和权限校验错误的管理。

feat: 1. 对接后端的数据看板的接口。
2. 将系统设置单独抽出来作为管理员的固定一个入口。
This commit is contained in:
2025-11-22 15:57:22 +08:00
27 changed files with 1972 additions and 643 deletions
+76 -15
View File
@@ -493,11 +493,11 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
*/
export async function getUserRoutesByRole(roleKey: string, jwt?: string, includeHidden: boolean = false): Promise<{ success: boolean; data?: MenuItem[]; error?: string; shouldRedirectToHome?: boolean }> {
try {
// console.log(`🔍 [User Routes] 获取用户路由,角色: ${roleKey}`);
// console.log(`🔍 [User Routes] 获取用户路由,角色: ${roleKey}, JWT前20字符: ${jwt?.substring(0, 20)}`);
if (!jwt) {
console.error('❌ [User Routes] JWT token 未提供');
toastService.error("认证信息缺失,请重新登录");
// 不显示 toast,让 root loader 处理重定向
return { success: false, error: "JWT token 未提供", shouldRedirectToHome: true };
}
@@ -519,15 +519,34 @@ export async function getUserRoutesByRole(roleKey: string, jwt?: string, include
// 检查响应是否成功
if (response.error) {
console.error('❌ [User Routes] API 请求失败:', response.error);
toastService.error(response.error);
return { success: false, error: response.error, shouldRedirectToHome: true };
// 🔑 如果是令牌过期错误,标记需要重定向到登录页
const isTokenExpired = response.error.includes('令牌已过期') ||
response.error.includes('令牌') ||
response.error.includes('token') ||
response.error.includes('expired') ||
response.error.includes('认证') ||
response.error.includes('401');
console.log('🔍 [User Routes] 错误检测:', {
error: response.error,
isTokenExpired,
willRedirect: isTokenExpired
});
// 只在客户端显示toast(服务端调用时跳过)
if (!isTokenExpired && typeof window !== 'undefined') {
toastService.error(response.error);
}
return { success: false, error: response.error, shouldRedirectToHome: isTokenExpired };
}
// 检查响应数据
if (!response.data) {
console.error('❌ [User Routes] 后端未返回数据');
toastService.error("获取路由数据失败");
return { success: false, error: "后端未返回数据", shouldRedirectToHome: true };
if (typeof window !== 'undefined') {
toastService.error("获取路由数据失败");
}
return { success: false, error: "后端未返回数据", shouldRedirectToHome: false };
}
const backendResponse = response.data;
@@ -535,23 +554,45 @@ export async function getUserRoutesByRole(roleKey: string, jwt?: string, include
// 检查业务状态码(后端使用 code: 0 表示成功)
if (backendResponse.code !== 0 && backendResponse.code !== 200) {
console.error(`❌ [User Routes] 后端返回错误: ${backendResponse.msg}`);
toastService.error(backendResponse.msg || "获取路由权限失败");
return { success: false, error: backendResponse.msg || "获取路由权限失败", shouldRedirectToHome: true };
// 🔑 如果是令牌过期错误,标记需要重定向到登录页
const isTokenExpired = backendResponse.msg?.includes('令牌已过期') ||
backendResponse.msg?.includes('令牌') ||
backendResponse.msg?.includes('token') ||
backendResponse.msg?.includes('expired') ||
backendResponse.msg?.includes('认证') ||
backendResponse.msg?.includes('401');
console.log('🔍 [User Routes] 业务错误检测:', {
msg: backendResponse.msg,
code: backendResponse.code,
isTokenExpired,
willRedirect: isTokenExpired
});
// 只在客户端显示toast
if (!isTokenExpired && typeof window !== 'undefined') {
toastService.error(backendResponse.msg || "获取路由权限失败");
}
return { success: false, error: backendResponse.msg || "获取路由权限失败", shouldRedirectToHome: isTokenExpired };
}
// 检查数据完整性
if (!backendResponse.data || !Array.isArray(backendResponse.data.routes)) {
console.error('❌ [User Routes] 后端未返回路由数据');
toastService.error("未获取到路由权限,请联系管理员配置");
return { success: false, error: "后端未返回路由数据", shouldRedirectToHome: true };
if (typeof window !== 'undefined') {
toastService.error("未获取到路由权限,请联系管理员配置");
}
return { success: false, error: "后端未返回路由数据", shouldRedirectToHome: false };
}
const routes = backendResponse.data.routes;
if (routes.length === 0) {
console.log(`⚠️ [User Routes] 用户没有分配任何路由权限`);
toastService.error("您的角色没有分配任何路由权限,请联系管理员配置");
return { success: false, error: "用户没有分配任何路由权限", shouldRedirectToHome: true };
if (typeof window !== 'undefined') {
toastService.error("您的角色没有分配任何路由权限,请联系管理员配置");
}
return { success: false, error: "用户没有分配任何路由权限", shouldRedirectToHome: false };
}
// console.log('🔍 [User Routes] 后端返回的原始路由数据:', JSON.stringify(routes, null, 2));
@@ -568,11 +609,31 @@ export async function getUserRoutesByRole(roleKey: string, jwt?: string, include
} catch (error) {
console.error("❌ [User Routes] 获取用户路由时发生错误:", error);
toastService.error("获取用户路由时发生错误,请稍后再试");
const errorMessage = error instanceof Error ? error.message : String(error);
// 🔑 如果是认证相关错误,标记需要重定向到登录页
const isAuthError = errorMessage.includes('令牌') ||
errorMessage.includes('token') ||
errorMessage.includes('expired') ||
errorMessage.includes('认证') ||
errorMessage.includes('401') ||
errorMessage.includes('403');
console.log('🔍 [User Routes] 异常错误检测:', {
errorMessage,
isAuthError,
willRedirect: isAuthError
});
// 只在客户端显示toast
if (!isAuthError && typeof window !== 'undefined') {
toastService.error("获取用户路由时发生错误,请稍后再试");
}
return {
success: false,
error: `获取用户路由失败: ${error instanceof Error ? error.message : String(error)}`,
shouldRedirectToHome: true
error: `获取用户路由失败: ${errorMessage}`,
shouldRedirectToHome: isAuthError
};
}
}