kindergarten_java/reading-platform-frontend/src/api/index.ts
Claude Opus 4.6 c90873bea9 Merge remote-tracking branch 'origin/master' and complete two-tier structure refactoring
合并同事的远程更新:
- 多地点登录支持功能
- 资源库管理优化
- 数据看板修复
- 视频预览功能
- 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>
2026-03-17 16:59:06 +08:00

124 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
},
};