update 重构 彻底删除proxy用法 改为vue3官方推荐写法

This commit is contained in:
疯狂的狮子Li
2026-04-10 13:07:37 +08:00
parent eb62402423
commit 9acf52e8a7
144 changed files with 1264 additions and 1082 deletions

11
src/utils/api-types.ts Normal file
View File

@@ -0,0 +1,11 @@
/**
* 与 `src/utils/request` 拦截器一致:resolve 的是若依风格 JSON `{ code, msg, data }`。
* axios 1.13 + TS6 下避免从 `axios` 拉已移除的 AxiosPromise。
*/
export interface RuoYiAjaxResult<T = unknown> {
code?: number;
msg?: string;
data?: T;
}
export type AxiosPromise<T = unknown> = Promise<RuoYiAjaxResult<T>>;

View File

@@ -1,4 +1,5 @@
import { JSEncrypt } from 'jsencrypt';
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey = import.meta.env.VITE_APP_RSA_PUBLIC_KEY;

View File

@@ -16,7 +16,7 @@ export async function resolveOssContent(html: string): Promise<string> {
const matches = [...html.matchAll(OSS_MARKER_RE)];
if (matches.length === 0) return html;
const ossIds = [...new Set(matches.map((m) => m[1]))];
const ossIds = [...new Set(matches.map(m => m[1]))];
try {
const res = await listByIds(ossIds.join(','));

View File

@@ -1,5 +1,5 @@
import { CSSProperties } from 'vue';
import VueTypes, { createTypes, toValidableType, VueTypeValidableDef, VueTypesInterface } from 'vue-types';
import type { CSSProperties } from 'vue';
import VueTypes, { createTypes, toValidableType, type VueTypesInterface, type VueTypeValidableDef } from 'vue-types';
type PropTypes = VueTypesInterface & {
readonly style: VueTypeValidableDef<CSSProperties>;

View File

@@ -1,9 +1,9 @@
import { getMessageBox } from '@/api/system/message';
import { ElNotification } from 'element-plus';
import type { MessageVO } from '@/api/system/message/types';
import { getMessageBox } from '@/api/system/message';
import { useNoticeStore } from '@/store/modules/notice';
import { useUserStore } from '@/store/modules/user';
import { getToken } from '@/utils/auth';
import { ElNotification } from 'element-plus';
import { useNoticeStore } from '@/store/modules/notice';
import { isMessageRead } from '@/utils/message-read';
import { parsePushMessage, resolveNoticeGroup, resolveNoticeTitle, shouldAppendNotice } from '@/utils/push-message';

View File

@@ -1,16 +1,19 @@
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import type { LoadingInstance } from 'element-plus';
import axiosModule from 'axios';
import { HttpStatus } from '@/enums/RespEnum';
import { getLanguage } from '@/lang';
import cache from '@/plugins/cache';
import router from '@/router';
import { useUserStore } from '@/store/modules/user';
import { getToken } from '@/utils/auth';
import { tansParams, blobValidate } from '@/utils/ruoyi';
import cache from '@/plugins/cache';
import { HttpStatus } from '@/enums/RespEnum';
import { decryptBase64, decryptWithAes, encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
import { errorCode } from '@/utils/errorCode';
import { getLanguage } from '@/lang';
import { encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64 } from '@/utils/crypto';
import { encrypt, decrypt } from '@/utils/jsencrypt';
import router from '@/router';
import { decrypt, encrypt } from '@/utils/jsencrypt';
import { blobValidate, tansParams } from '@/utils/ruoyi';
import { saveBlob } from '@/utils/save';
import type { LoadingInstance } from 'element-plus';
/** axios 1.13 + TS6:默认导出在类型上会被解析为不可调用的 export= 形态 */
const axios = axiosModule as any;
const encryptHeader = 'encrypt-key';
let downloadLoadingInstance: LoadingInstance | undefined;
@@ -95,7 +98,7 @@ const service = axios.create({
// 请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
(config: any) => {
// 对应国际化资源文件后缀
config.headers['Content-Language'] = getLanguage();
@@ -164,7 +167,7 @@ service.interceptors.request.use(
// 响应拦截器
service.interceptors.response.use(
(res: AxiosResponse) => {
(res: any) => {
if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
// 加密后的 AES 秘钥
const keyStr = res.headers[encryptHeader];
@@ -192,25 +195,35 @@ service.interceptors.response.use(
if (code === 401) {
// prettier-ignore
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
isRelogin.show = false;
useUserStore().logout().then(() => {
router.replace({
path: '/login',
query: {
redirect: encodeURIComponent(router.currentRoute.value.fullPath || '/')
}
})
});
}).catch(() => {
isRelogin.show = false;
});
}
isRelogin.show = true;
ElMessageBox.confirm(
"登录状态已过期,您可以继续留在该页面,或者重新登录",
"系统提示",
{
confirmButtonText: "重新登录",
cancelButtonText: "取消",
type: "warning",
},
)
.then(() => {
isRelogin.show = false;
useUserStore()
.logout()
.then(() => {
router.replace({
path: "/login",
query: {
redirect: encodeURIComponent(
router.currentRoute.value.fullPath || "/",
),
},
});
});
})
.catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
} else if (code === HttpStatus.SERVER_ERROR) {
ElMessage({ message: msg, type: 'error' });
@@ -238,31 +251,35 @@ export function download(url: string, params: any, fileName: string) {
background: 'rgba(0, 0, 0, 0.7)'
});
// prettier-ignore
return service.post(url, params, {
transformRequest: [
(params: any) => {
return tansParams(params);
}
],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob'
}).then(async (resp: any) => {
const isLogin = blobValidate(resp);
if (isLogin) {
const blob = new Blob([resp]);
saveBlob(blob, fileName);
} else {
const blob = new Blob([resp]);
const resText = await blob.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];
ElMessage.error(errMsg);
}
downloadLoadingInstance?.close();
}).catch((r: any) => {
console.error(r);
downloadLoadingInstance?.close();
});
return service
.post(url, params, {
transformRequest: [
(params: any) => {
return tansParams(params);
},
],
headers: { "Content-Type": "application/x-www-form-urlencoded" },
responseType: "blob",
})
.then(async (resp: any) => {
const isLogin = blobValidate(resp);
if (isLogin) {
const blob = new Blob([resp]);
saveBlob(blob, fileName);
} else {
const blob = new Blob([resp]);
const resText = await blob.text();
const rspObj = JSON.parse(resText);
const errMsg =
errorCode[rspObj.code] || rspObj.msg || errorCode["default"];
ElMessage.error(errMsg);
}
downloadLoadingInstance?.close();
})
.catch((r: any) => {
console.error(r);
downloadLoadingInstance?.close();
});
}
// 导出 axios 实例
export default service;

View File

@@ -8,16 +8,13 @@ const easeInOutQuad = (t: number, b: number, c: number, d: number) => {
};
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
const requestAnimFrame = (function () {
return (
window.requestAnimationFrame ||
(window as any).webkitRequestAnimationFrame ||
(window as any).mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
}
);
})();
const requestAnimFrame = (() =>
window.requestAnimationFrame ||
(window as any).webkitRequestAnimationFrame ||
(window as any).mozRequestAnimationFrame ||
(callback => {
window.setTimeout(callback, 1000 / 60);
}))();
/**
* Because it's so fucking difficult to detect the scrolling element, just move them all
@@ -46,7 +43,7 @@ export const scrollTo = (to: number, duration: number, callback?: any) => {
const increment = 20;
let currentTime = 0;
duration = typeof duration === 'undefined' ? 500 : duration;
const animateScroll = function () {
const animateScroll = () => {
// increment the time
currentTime += increment;
// find the value with the quadratic in-out easing function