优化拦截器

优化错误捕获
优化全局状态管理
配置全局公用类型
This commit is contained in:
tao
2025-12-19 15:54:26 +08:00
parent 71158afc35
commit 73dd0ae6b6
7 changed files with 141 additions and 53 deletions

39
src/api/common.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
export type ID = number | string;
export type IDS = (number | string)[];
export interface BaseEntity {
createBy?: string;
createTime?: string;
updateBy?: string;
updateTime?: string;
}
/**
* 分页查询参数
* @param pageNum 当前页
* @param pageSize 每页大小
* @param orderByColumn 排序字段
* @param isAsc 是否升序
*/
export interface PageQuery {
isAsc?: string;
orderByColumn?: string;
pageNum?: number;
pageSize?: number;
[key: string]: any;
}
export interface ApiResponse<T = any> {
code?: number;
msg?: string;
data?: T;
rows: T[];
total?: number;
token?: string;
img?: string;
uuid?: string;
captchaOnOff?: boolean;
}

View File

@@ -1,83 +1,91 @@
import axios from 'axios'; import axios from "axios";
import router from '@/router'; import router from "@/router";
import { getToken } from '@/utils/auth'; import { getToken, removeToken } from "@/utils/auth";
import { Modal, notification } from 'ant-design-vue'; import { Modal, notification } from "ant-design-vue";
import type { AxiosRequestConfig } from "axios"; import type { AxiosInstance, AxiosRequestConfig } from "axios";
import type { ApiResponse } from "@/api/common/model"; import type { ApiResponse } from "@/api/common";
const errCodeMap: { [key: string]: string } = { const errCodeMap: { [key: string]: string } = {
'403': '当前操作没有权限', "403": "当前操作没有权限",
'404': '访问资源不存在', "404": "访问资源不存在",
'default': '系统未知错误,请反馈给管理员' default: "系统未知错误,请反馈给管理员",
}; };
// 创建axios实例 // 创建axios实例
const service = axios.create({ const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 10000, timeout: 10000,
}); });
// 请求拦截器 // 请求拦截器
service.interceptors.request.use( service.interceptors.request.use(
config => { (config) => {
config.headers = config.headers || {}; config.headers = config.headers || {};
config.headers['Accept-Language'] = 'zh-CN'; config.headers["Accept-Language"] = "zh-CN";
const token = getToken(); const token = getToken();
if (token) { if (token) {
config.headers['Authorization'] = `Bearer ${token}`; config.headers["Authorization"] = `Bearer ${token}`;
} }
return config; return config;
}, },
error => { (error) => {
return Promise.reject(error); return Promise.reject(error);
} }
); );
// 响应拦截器 // 响应拦截器
service.interceptors.response.use( service.interceptors.response.use(
response => { (response) => {
// console.log(response); if (response.config.responseType === "blob") {
return response.data;
}
const code = response.data.code || 200; const code = response.data.code || 200;
const data = response.data; const data = response.data;
switch (code) { switch (code) {
case 200: case 200:
return data ?? response; return data;
case 401: case 401:
Modal.error({ Modal.error({
title: '系统提示', title: "系统提示",
content: '登录状态已过期,请重新登录', content: "登录状态已过期,请重新登录",
onOk: () => { onOk: () => {
router.push('/login') removeToken();
} router.replace("/login");
}) },
});
return Promise.reject(data); return Promise.reject(data);
default: default:
const errMsg = errCodeMap[code] || data.msg || errCodeMap['default'];
notification.error({ notification.error({
message: '请求错误', message: "请求错误",
description: errMsg, description: errCodeMap[code] || data?.msg || errCodeMap.default,
}); });
return Promise.reject(data); return Promise.reject(data);
} }
}, },
error => { (error) => {
error.message = error.code === "ECONNABORTED" ? '请求超时,请稍后重试' : error.message; if (!error.__handled) {
const message =
error.code === "ECONNABORTED"
? "请求超时,请稍后重试"
: error.message || "网络异常";
// 网络/服务器错误统一处理
notification.error({ notification.error({
message: "网络错误", message: "网络错误",
description: error.message, description: message,
}); });
error.__handled = true;
}
return Promise.reject(error); return Promise.reject(error);
} }
); );
// 类型检查
function request<T = any>(config: AxiosRequestConfig): Promise<ApiResponse<T>> { function request<T = any>(config: AxiosRequestConfig): Promise<ApiResponse<T>> {
return service(config) as unknown as Promise<ApiResponse<T>>; return service(config) as Promise<ApiResponse<T>>;
} }
export default request; export default request;
// export default service;

View File

@@ -12,3 +12,14 @@
background-color: #8B8B8B; background-color: #8B8B8B;
border-radius: 32px; border-radius: 32px;
} }
.hide-scrollbar {
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
/* 隐藏滚动条 - Firefox */
scrollbar-width: none;
/* 隐藏滚动条 - IE/Edge */
-ms-overflow-style: none;
}

View File

@@ -1,16 +1,16 @@
import { defineStore } from 'pinia'; import Cookies from "js-cookie";
import { ref } from 'vue'; import { defineStore } from "pinia";
import { useRouter } from 'vue-router'; import { ref } from "vue";
import Cookies from 'js-cookie'; import { useRoute, useRouter } from "vue-router";
import { message } from 'ant-design-vue'; import { message } from "ant-design-vue";
import { useUserStore } from './user'; import { useUserStore } from "./user";
import { login } from '@/api/system'; import { login, logout as logoutApi } from "@/api/system";
import type { LoginInfo } from '@/api/system/model'; import { TokenKey as TOKEN_KEY } from "@/utils/auth";
import type { LoginInfo } from "@/api/system/model";
const TOKEN_KEY = 'token'; export const useAuthStore = defineStore("auth", () => {
const route = useRoute();
export const useAuthStore = defineStore('auth', () => {
const router = useRouter(); const router = useRouter();
const userStore = useUserStore(); const userStore = useUserStore();
@@ -34,12 +34,13 @@ export const useAuthStore = defineStore('auth', () => {
if (res.code === 200) { if (res.code === 200) {
setToken(res.token as string); setToken(res.token as string);
await userStore.fetchUserInfo(); await userStore.fetchUserInfo();
message.success('登录成功'); message.success("登录成功");
await router.push('/'); const redirect = route.query.redirect || "/";
router.replace(redirect as string);
return res; return res;
} else { } else {
// 抛出错误,让调用方处理 // 抛出错误,让调用方处理
throw new Error(res.msg || '登录失败'); throw new Error(res.msg || "登录失败");
} }
} catch (error) { } catch (error) {
throw error; throw error;
@@ -50,11 +51,11 @@ export const useAuthStore = defineStore('auth', () => {
async function logout() { async function logout() {
// 在实际应用中,这里可以调用后端的退出登录接口 // 在实际应用中,这里可以调用后端的退出登录接口
// await doLogoutApi(); await logoutApi();
clearToken(); clearToken();
userStore.clearUserInfo(); userStore.clearUserInfo();
await router.push('/login'); await router.push("/login");
message.success('已成功退出'); message.success("已成功退出");
} }
return { return {

View File

@@ -1,2 +1,3 @@
export * from './auth'; export * from './auth';
export * from './user'; export * from './user';
export * from './pwo';

28
src/store/pwo.ts Normal file
View File

@@ -0,0 +1,28 @@
import { defineStore } from "pinia";
import { ref, reactive } from "vue";
import { message } from "ant-design-vue";
export const usePwoStore = defineStore("pwo", () => {
const code = ref('');
const currentJob = ref({});
function setCode(traceOrderCode: string) {
code.value = traceOrderCode;
}
function setCurrentJob(job: any) {
currentJob.value = job;
}
function getCurrentJob() {
return currentJob.value;
}
return {
code,
currentJob,
setCode,
setCurrentJob,
getCurrentJob,
}
});

View File

@@ -1,6 +1,6 @@
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
const TokenKey = 'Admin-Token' export const TokenKey = 'Admin-Token'
export function getToken() { export function getToken() {
return Cookies.get(TokenKey) return Cookies.get(TokenKey)