fix: align login and home routing with leaudit backend
This commit is contained in:
@@ -664,7 +664,7 @@ export async function getUserRoutesByRole(
|
||||
// 注意:Authorization 头会由 axios 拦截器自动添加(从 localStorage 读取)
|
||||
// 但为了确保使用正确的 token,这里仍然显式传递
|
||||
const response = await apiRequest<BackendRoutesResponse>(
|
||||
'/rbac/user/routes', // endpoint (第一个参数)
|
||||
'/api/rbac/user/routes', // endpoint (第一个参数)
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@@ -678,6 +678,12 @@ export async function getUserRoutesByRole(
|
||||
// 检查响应是否成功
|
||||
if (response.error) {
|
||||
console.error('❌ [User Routes] API 请求失败:', response.error);
|
||||
|
||||
if (response.status === 404) {
|
||||
console.warn('⚠️ [User Routes] 后端路由权限接口未落地,回退到静态菜单');
|
||||
return buildFallbackRoutes(roleKey);
|
||||
}
|
||||
|
||||
// 🔑 如果是令牌过期错误,标记需要重定向到登录页
|
||||
const isTokenExpired = response.error.includes('令牌已过期') ||
|
||||
response.error.includes('令牌') ||
|
||||
@@ -702,6 +708,10 @@ export async function getUserRoutesByRole(
|
||||
// 检查响应数据
|
||||
if (!response.data) {
|
||||
console.error('❌ [User Routes] 后端未返回数据');
|
||||
if (response.status === 404) {
|
||||
console.warn('⚠️ [User Routes] 后端路由权限接口未落地,回退到静态菜单');
|
||||
return buildFallbackRoutes(roleKey);
|
||||
}
|
||||
if (typeof window !== 'undefined') {
|
||||
toastService.error("获取路由数据失败");
|
||||
}
|
||||
@@ -998,6 +1008,7 @@ export function mapUserRoleToRoleKey(userRole: string): string {
|
||||
const roleMapping: Record<string, string> = {
|
||||
'common': 'common',
|
||||
'admin': 'admin',
|
||||
'provincial_admin': 'admin',
|
||||
'deptLeader': 'deptLeader',
|
||||
'groupLeader': 'groupLeader',
|
||||
// 添加常见的后端角色映射
|
||||
@@ -1009,4 +1020,23 @@ export function mapUserRoleToRoleKey(userRole: string): string {
|
||||
|
||||
// 如果找不到映射,返回 userRole 本身(假设后端已经返回了正确的 role_key)
|
||||
return roleMapping[userRole] || userRole || 'common';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于静态菜单数据构造后备结果。
|
||||
*/
|
||||
function buildFallbackRoutes(roleKey: string): {
|
||||
success: boolean;
|
||||
data: MenuItem[];
|
||||
permissionMap: Record<string, string[]>;
|
||||
} {
|
||||
const mappedRoleKey = mapUserRoleToRoleKey(roleKey);
|
||||
const fallbackMenus = FALLBACK_MENU_DATA[mappedRoleKey] || FALLBACK_MENU_DATA.common;
|
||||
const permissionMap: Record<string, string[]> = {};
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: fallbackMenus,
|
||||
permissionMap,
|
||||
};
|
||||
}
|
||||
|
||||
+23
-104
@@ -1,4 +1,3 @@
|
||||
import { postgrestGet, type PostgrestParams } from "../postgrest-client";
|
||||
import { apiRequest } from "../axios-client";
|
||||
// import dayjs from 'dayjs';
|
||||
|
||||
@@ -202,7 +201,7 @@ export async function getHomeData(reviewType?: string | null, userId?: string |
|
||||
export interface AreaConfig {
|
||||
area: string; // 地区名称
|
||||
enabled: boolean; // 是否启用
|
||||
sort_order: number; // 排序顺序
|
||||
sortOrder: number; // 排序顺序
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,11 +211,13 @@ export interface EntryModule {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string | null;
|
||||
path: string | null;
|
||||
areas: AreaConfig[]; // 修改为对象数组
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
document_types?: Array<{
|
||||
targetPath: string | null;
|
||||
routePath: string | null;
|
||||
iconPath: string | null;
|
||||
sortOrder: number;
|
||||
requiresDocumentTypes: boolean;
|
||||
areas: AreaConfig[];
|
||||
documentTypes: Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
code: string | null;
|
||||
@@ -225,119 +226,38 @@ export interface EntryModule {
|
||||
|
||||
/**
|
||||
* 获取用户可访问的入口模块
|
||||
* @param userArea 用户所属地区
|
||||
* @param token JWT token
|
||||
* @returns 入口模块列表
|
||||
*/
|
||||
export async function getEntryModules(userRole: string | null | undefined, userArea: string | null | undefined, token?: string): Promise<EntryModule[]> {
|
||||
export async function getEntryModules(token?: string): Promise<EntryModule[]> {
|
||||
try {
|
||||
if (!userRole || !userArea) {
|
||||
console.warn('⚠️ [getEntryModules] 用户角色或地区为空,返回空模块列表');
|
||||
if (!token) {
|
||||
console.warn('⚠️ [getEntryModules] JWT 为空,返回空模块列表');
|
||||
return [];
|
||||
}
|
||||
|
||||
// console.log('🔍 [getEntryModules] 查询地区:', userArea);
|
||||
|
||||
// 查询 entry_modules 表,获取所有模块(在客户端进行过滤)
|
||||
const params: PostgrestParams = {
|
||||
select: 'id,name,description,path,areas,created_at,updated_at',
|
||||
filter: {}
|
||||
};
|
||||
|
||||
const modulesResponse = await postgrestGet('/api/postgrest/proxy/entry_modules', { ...params, token });
|
||||
const modulesResponse = await apiRequest<EntryModule[]>(
|
||||
'/api/home/entry-modules',
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (modulesResponse.error) {
|
||||
console.error('❌ [getEntryModules] 查询入口模块失败:', modulesResponse.error);
|
||||
return [];
|
||||
}
|
||||
|
||||
const allModules = extractApiData<EntryModule[]>(modulesResponse.data);
|
||||
if (!allModules || allModules.length === 0) {
|
||||
const modules = extractApiData<EntryModule[]>(modulesResponse.data);
|
||||
if (!modules || modules.length === 0) {
|
||||
console.warn('⚠️ [getEntryModules] 未找到任何入口模块');
|
||||
return [];
|
||||
}
|
||||
|
||||
// 🔑 在客户端过滤:只保留包含用户地区且已启用的模块
|
||||
const modules = allModules.filter(module => {
|
||||
// 省级管理员可以看到所有模块
|
||||
if (userRole === 'provincial_admin') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查 areas 数组中是否存在匹配的地区配置
|
||||
if (!module.areas || !Array.isArray(module.areas)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 查找用户地区的配置
|
||||
const areaConfig = module.areas.find(config =>
|
||||
config.area === userArea && config.enabled === true
|
||||
);
|
||||
|
||||
return !!areaConfig; // 找到且启用才返回 true
|
||||
});
|
||||
|
||||
if (modules.length === 0) {
|
||||
console.warn('⚠️ [getEntryModules] 未找到已启用的入口模块');
|
||||
return [];
|
||||
}
|
||||
|
||||
// console.log(`✅ [getEntryModules] 找到 ${modules.length} 个已启用的入口模块`);
|
||||
|
||||
// 为每个模块查询关联的 document_types
|
||||
const modulesWithTypes = await Promise.all(
|
||||
modules.map(async (module) => {
|
||||
try {
|
||||
const typesParams: PostgrestParams = {
|
||||
select: 'id,name,code',
|
||||
filter: {
|
||||
entry_module_id: `eq.${module.id}`
|
||||
}
|
||||
};
|
||||
|
||||
const typesResponse = await postgrestGet('/api/postgrest/proxy/document_types', { ...typesParams, token });
|
||||
|
||||
if (typesResponse.error) {
|
||||
console.error(`❌ [getEntryModules] 查询模块 ${module.id} 的文档类型失败:`, typesResponse.error);
|
||||
return { ...module, document_types: [] };
|
||||
}
|
||||
|
||||
const documentTypes = extractApiData<Array<{ id: number; name: string; code: string | null }>>(typesResponse.data);
|
||||
|
||||
return {
|
||||
...module,
|
||||
document_types: documentTypes || []
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`❌ [getEntryModules] 处理模块 ${module.id} 时出错:`, error);
|
||||
return { ...module, document_types: [] };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// console.log('✅ [getEntryModules] 入口模块数据(含文档类型):', JSON.stringify(modulesWithTypes));
|
||||
|
||||
// 默认会多加一个 智慧法务助手 入口 默认所有人都可以用,看到
|
||||
modulesWithTypes.push({
|
||||
"id": 0,
|
||||
"name": "智慧法务助手",
|
||||
"description": "智慧法务助手",
|
||||
"path": "entryModule/assistant",
|
||||
"areas": [],
|
||||
"created_at": "2025-11-18T21:33:33.857417+08:00",
|
||||
"updated_at": "2025-11-18T22:28:51.819722+08:00",
|
||||
"document_types": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "空",
|
||||
"code": "空"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return modulesWithTypes;
|
||||
return modules;
|
||||
} catch (error) {
|
||||
console.error('❌ [getEntryModules] 获取入口模块失败:', error instanceof Error ? error.message : String(error));
|
||||
return [];
|
||||
@@ -525,4 +445,3 @@ export async function getTopRiskUsers(
|
||||
return { available: false, total: 0, items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export interface LoginResponse {
|
||||
* @returns 登录响应(包含 JWT token)
|
||||
*/
|
||||
export async function loginWithOAuth(loginData: LoginRequest): Promise<LoginResponse> {
|
||||
const loginUrl = `${API_BASE_URL}/auth/login`;
|
||||
const loginUrl = `${API_BASE_URL}/api/auth/login`;
|
||||
|
||||
console.log("📝 [Login Client] 调用后端 OAuth 登录接口:", loginUrl);
|
||||
|
||||
@@ -116,7 +116,7 @@ export async function loginWithPassword(
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<LoginResponse> {
|
||||
const loginUrl = `${API_BASE_URL}/auth/login`;
|
||||
const loginUrl = `${API_BASE_URL}/api/auth/login`;
|
||||
|
||||
console.log("📝 [Login Client] 调用后端密码登录接口:", loginUrl);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user