合并同事的远程更新: - 多地点登录支持功能 - 资源库管理优化 - 数据看板修复 - 视频预览功能 - KidsMode增强 两层结构重构完成: - 数据库迁移 V28(course_collection、course_collection_package) - 后端实体、Service、Controller实现 - 前端API类型和组件重构 - 修复冲突文件:CHANGELOG.md、components.d.ts、TeacherLessonController.java Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||
import { message } from 'ant-design-vue';
|
||
|
||
// 创建axios实例
|
||
const request: AxiosInstance = axios.create({
|
||
baseURL: '/api', // 使用 /api 作为统一前缀,超管端路径包含 /v1
|
||
timeout: 30000,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
});
|
||
|
||
// 请求拦截器
|
||
request.interceptors.request.use(
|
||
(config) => {
|
||
const token = localStorage.getItem('token');
|
||
if (token) {
|
||
config.headers.Authorization = `Bearer ${token}`;
|
||
}
|
||
return config;
|
||
},
|
||
(error) => {
|
||
return Promise.reject(error);
|
||
}
|
||
);
|
||
|
||
// 响应拦截器
|
||
request.interceptors.response.use(
|
||
(response: AxiosResponse) => {
|
||
const { data } = response;
|
||
// 如果是标准响应格式 { code, message, data }
|
||
if (typeof data === 'object' && data !== null && 'code' in data) {
|
||
// 业务错误码非 200 时抛出错误
|
||
if (data.code !== 200) {
|
||
const error: any = new Error(data.message || '请求失败');
|
||
error.response = response;
|
||
error.code = data.code;
|
||
return Promise.reject(error);
|
||
}
|
||
// 返回 data 字段
|
||
return data.data;
|
||
}
|
||
// 否则直接返回响应数据
|
||
return data;
|
||
},
|
||
(error) => {
|
||
const { response } = error;
|
||
|
||
if (response) {
|
||
const { status, data } = response;
|
||
|
||
switch (status) {
|
||
case 401:
|
||
message.error('登录已过期,请重新登录');
|
||
localStorage.removeItem('token');
|
||
localStorage.removeItem('user');
|
||
localStorage.removeItem('role');
|
||
localStorage.removeItem('name');
|
||
window.location.href = '/login';
|
||
break;
|
||
case 403:
|
||
// 区分 token 过期/无效和权限不足的场景
|
||
// 如果是 token 问题导致的 403,跳转到登录页
|
||
if (data && typeof data === 'object' && 'code' in data) {
|
||
const errorCode = data.code;
|
||
// token 过期或无效时跳转到登录页
|
||
if (errorCode === 401 || errorCode === 403) {
|
||
message.error(data.message || '登录已过期,请重新登录');
|
||
localStorage.removeItem('token');
|
||
localStorage.removeItem('user');
|
||
localStorage.removeItem('role');
|
||
localStorage.removeItem('name');
|
||
window.location.href = '/login';
|
||
break;
|
||
}
|
||
}
|
||
// 其他情况视为权限不足,显示提示但不跳转
|
||
message.error(data?.message || '没有权限访问');
|
||
break;
|
||
case 404:
|
||
message.error('请求的资源不存在');
|
||
break;
|
||
case 500:
|
||
message.error(data?.message || '服务器错误');
|
||
break;
|
||
default:
|
||
message.error(data?.message || '请求失败');
|
||
}
|
||
} else if (error.code === 'ECONNABORTED') {
|
||
message.error('请求超时');
|
||
} else {
|
||
message.error('网络错误');
|
||
}
|
||
|
||
return Promise.reject(error);
|
||
}
|
||
);
|
||
|
||
// 导出请求方法
|
||
export default request;
|
||
|
||
// 通用请求方法
|
||
export const http = {
|
||
get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||
return request.get(url, config);
|
||
},
|
||
|
||
post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||
return request.post(url, data, config);
|
||
},
|
||
|
||
put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||
return request.put(url, data, config);
|
||
},
|
||
|
||
delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
||
return request.delete(url, config);
|
||
},
|
||
|
||
patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
||
return request.patch(url, data, config);
|
||
},
|
||
};
|