commits
This commit is contained in:
@@ -1,94 +1,94 @@
|
||||
/**
|
||||
* 通用的别名路径解析工具
|
||||
* 用于在动态导入时解析 @ 别名路径
|
||||
*/
|
||||
|
||||
// 使用 import.meta.glob 预加载所有组件
|
||||
const viewsModules = import.meta.glob('../views/**/*.vue');
|
||||
|
||||
// 创建路径映射表
|
||||
const pathMap = new Map();
|
||||
|
||||
// 初始化路径映射
|
||||
Object.keys(viewsModules).forEach(relativePath => {
|
||||
// relativePath 示例: ../views/system/users.vue
|
||||
|
||||
// 统一去掉扩展名进行存储,方便各种格式匹配
|
||||
const baseNoExt = relativePath.replace('../views/', '').replace('.vue', '');
|
||||
const baseWithExt = relativePath.replace('../views/', '');
|
||||
|
||||
// 1. 存储标准路径
|
||||
pathMap.set(relativePath, viewsModules[relativePath]);
|
||||
// 2. 存储 @/views 路径
|
||||
pathMap.set(relativePath.replace('../views', '@/views'), viewsModules[relativePath]);
|
||||
// 3. 存储 /system/users 格式(不带扩展名)
|
||||
pathMap.set(`/${baseNoExt}`, viewsModules[relativePath]);
|
||||
// 4. 存储 system/users 格式(不带扩展名)
|
||||
pathMap.set(baseNoExt, viewsModules[relativePath]);
|
||||
// 5. 存储 /system/users.vue 格式(带扩展名)
|
||||
pathMap.set(`/${baseWithExt}`, viewsModules[relativePath]);
|
||||
// 6. 存储 system/users.vue 格式(带扩展名)
|
||||
pathMap.set(baseWithExt, viewsModules[relativePath]);
|
||||
});
|
||||
|
||||
/**
|
||||
* 解析别名路径为实际模块加载器
|
||||
* @param {string} path - 支持的路径格式:
|
||||
* - @/views/dashboard/index.vue (别名格式)
|
||||
* - /dashboard/index.vue (数据库格式,带前导斜杠)
|
||||
* - dashboard/index.vue (相对格式)
|
||||
* @returns {Function|null} 返回模块加载器函数,找不到时返回 null
|
||||
*/
|
||||
export function resolveComponent(path) {
|
||||
if (!path) return null;
|
||||
|
||||
// 预处理 path:去掉可能的 .vue 后缀统一查找
|
||||
const cleanPath = path.replace('.vue', '');
|
||||
|
||||
// 尝试直接匹配
|
||||
const loader = pathMap.get(path) || pathMap.get(cleanPath);
|
||||
if (loader) return loader;
|
||||
|
||||
// 数据库格式补全匹配 (针对 /system/users)
|
||||
const dbFormat = cleanPath.startsWith('/') ? cleanPath : `/${cleanPath}`;
|
||||
if (pathMap.get(dbFormat)) return pathMap.get(dbFormat);
|
||||
|
||||
// 模糊匹配:文件名匹配
|
||||
const fileName = cleanPath.split('/').pop();
|
||||
for (const [mappedPath, loader] of pathMap.entries()) {
|
||||
if (mappedPath.endsWith(`${fileName}.vue`) || mappedPath.endsWith(fileName)) {
|
||||
return loader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建组件加载器
|
||||
* @param {string} componentPath - 组件路径
|
||||
* @returns {Function} Vue 路由组件加载函数
|
||||
*/
|
||||
export function createComponentLoader(componentPath) {
|
||||
const loader = resolveComponent(componentPath);
|
||||
if (loader) return loader;
|
||||
|
||||
console.error(`❌ [路由错误] 未找到组件: ${componentPath}`);
|
||||
|
||||
// 返回一个标准的 Vue 组件对象,确保 Router 不报错
|
||||
return () => Promise.resolve({
|
||||
name: 'ComponentNotFound',
|
||||
render: () => {
|
||||
import('element-plus').then(El => El.ElMessage.error(`路径错误: ${componentPath}`));
|
||||
return h('div', { style: 'padding:20px; color:red;' }, `组件路径不存在: ${componentPath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有已加载的模块路径(用于调试)
|
||||
* @returns {Array<string>} 所有可用的路径列表
|
||||
*/
|
||||
export function getAllModulePaths() {
|
||||
return Array.from(pathMap.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的别名路径解析工具
|
||||
* 用于在动态导入时解析 @ 别名路径
|
||||
*/
|
||||
|
||||
// 使用 import.meta.glob 预加载所有组件
|
||||
const viewsModules = import.meta.glob('../views/**/*.vue');
|
||||
|
||||
// 创建路径映射表
|
||||
const pathMap = new Map();
|
||||
|
||||
// 初始化路径映射
|
||||
Object.keys(viewsModules).forEach(relativePath => {
|
||||
// relativePath 示例: ../views/system/users.vue
|
||||
|
||||
// 统一去掉扩展名进行存储,方便各种格式匹配
|
||||
const baseNoExt = relativePath.replace('../views/', '').replace('.vue', '');
|
||||
const baseWithExt = relativePath.replace('../views/', '');
|
||||
|
||||
// 1. 存储标准路径
|
||||
pathMap.set(relativePath, viewsModules[relativePath]);
|
||||
// 2. 存储 @/views 路径
|
||||
pathMap.set(relativePath.replace('../views', '@/views'), viewsModules[relativePath]);
|
||||
// 3. 存储 /system/users 格式(不带扩展名)
|
||||
pathMap.set(`/${baseNoExt}`, viewsModules[relativePath]);
|
||||
// 4. 存储 system/users 格式(不带扩展名)
|
||||
pathMap.set(baseNoExt, viewsModules[relativePath]);
|
||||
// 5. 存储 /system/users.vue 格式(带扩展名)
|
||||
pathMap.set(`/${baseWithExt}`, viewsModules[relativePath]);
|
||||
// 6. 存储 system/users.vue 格式(带扩展名)
|
||||
pathMap.set(baseWithExt, viewsModules[relativePath]);
|
||||
});
|
||||
|
||||
/**
|
||||
* 解析别名路径为实际模块加载器
|
||||
* @param {string} path - 支持的路径格式:
|
||||
* - @/views/dashboard/index.vue (别名格式)
|
||||
* - /dashboard/index.vue (数据库格式,带前导斜杠)
|
||||
* - dashboard/index.vue (相对格式)
|
||||
* @returns {Function|null} 返回模块加载器函数,找不到时返回 null
|
||||
*/
|
||||
export function resolveComponent(path) {
|
||||
if (!path) return null;
|
||||
|
||||
// 预处理 path:去掉可能的 .vue 后缀统一查找
|
||||
const cleanPath = path.replace('.vue', '');
|
||||
|
||||
// 尝试直接匹配
|
||||
const loader = pathMap.get(path) || pathMap.get(cleanPath);
|
||||
if (loader) return loader;
|
||||
|
||||
// 数据库格式补全匹配 (针对 /system/users)
|
||||
const dbFormat = cleanPath.startsWith('/') ? cleanPath : `/${cleanPath}`;
|
||||
if (pathMap.get(dbFormat)) return pathMap.get(dbFormat);
|
||||
|
||||
// 模糊匹配:文件名匹配
|
||||
const fileName = cleanPath.split('/').pop();
|
||||
for (const [mappedPath, loader] of pathMap.entries()) {
|
||||
if (mappedPath.endsWith(`${fileName}.vue`) || mappedPath.endsWith(fileName)) {
|
||||
return loader;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建组件加载器
|
||||
* @param {string} componentPath - 组件路径
|
||||
* @returns {Function} Vue 路由组件加载函数
|
||||
*/
|
||||
export function createComponentLoader(componentPath) {
|
||||
const loader = resolveComponent(componentPath);
|
||||
if (loader) return loader;
|
||||
|
||||
console.error(`❌ [路由错误] 未找到组件: ${componentPath}`);
|
||||
|
||||
// 返回一个标准的 Vue 组件对象,确保 Router 不报错
|
||||
return () => Promise.resolve({
|
||||
name: 'ComponentNotFound',
|
||||
render: () => {
|
||||
import('element-plus').then(El => El.ElMessage.error(`路径错误: ${componentPath}`));
|
||||
return h('div', { style: 'padding:20px; color:red;' }, `组件路径不存在: ${componentPath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有已加载的模块路径(用于调试)
|
||||
* @returns {Array<string>} 所有可用的路径列表
|
||||
*/
|
||||
export function getAllModulePaths() {
|
||||
return Array.from(pathMap.keys());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// 获取API基础URL,添加调试信息
|
||||
const apiBaseURL = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: apiBaseURL,
|
||||
timeout: 10000,
|
||||
withCredentials: false // JWT 不需要 Cookie
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// 对于有 body 的请求(POST、PUT、PATCH),确保设置 Content-Type
|
||||
if (config.data && ['post', 'put', 'patch'].includes(config.method?.toLowerCase())) {
|
||||
if (!config.headers['Content-Type'] && !config.headers['content-type']) {
|
||||
config.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
return response.data;
|
||||
},
|
||||
error => {
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
console.error('未授权,请重新登录');
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('userInfo');
|
||||
if (window.location.hash !== '#/login') {
|
||||
window.location.href = '#/login';
|
||||
}
|
||||
return Promise.reject(new Error('token无效'));
|
||||
case 404:
|
||||
console.error('请求的资源不存在');
|
||||
break;
|
||||
default:
|
||||
console.error('请求失败,请稍后再试');
|
||||
}
|
||||
} else if (error.request) {
|
||||
console.error('请求失败,请检查网络连接');
|
||||
} else {
|
||||
console.error('请求配置错误');
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
// 获取API基础URL,添加调试信息
|
||||
const apiBaseURL = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: apiBaseURL,
|
||||
timeout: 10000,
|
||||
withCredentials: false // JWT 不需要 Cookie
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// 对于有 body 的请求(POST、PUT、PATCH),确保设置 Content-Type
|
||||
if (config.data && ['post', 'put', 'patch'].includes(config.method?.toLowerCase())) {
|
||||
if (!config.headers['Content-Type'] && !config.headers['content-type']) {
|
||||
config.headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
return response.data;
|
||||
},
|
||||
error => {
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
console.error('未授权,请重新登录');
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('userInfo');
|
||||
if (window.location.hash !== '#/login') {
|
||||
window.location.href = '#/login';
|
||||
}
|
||||
return Promise.reject(new Error('token无效'));
|
||||
case 404:
|
||||
console.error('请求的资源不存在');
|
||||
break;
|
||||
default:
|
||||
console.error('请求失败,请稍后再试');
|
||||
}
|
||||
} else if (error.request) {
|
||||
console.error('请求失败,请检查网络连接');
|
||||
} else {
|
||||
console.error('请求配置错误');
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
Reference in New Issue
Block a user