diff --git a/package.json b/package.json index 21b9543..0ac64d8 100644 --- a/package.json +++ b/package.json @@ -30,14 +30,11 @@ "crypto-js": "4.2.0", "echarts": "6.0.0", "element-plus": "2.13.5", - "file-saver": "2.0.5", "highlight.js": "11.11.1", "image-conversion": "2.1.1", - "js-cookie": "3.0.5", "jsencrypt": "3.5.4", "nprogress": "0.2.0", "pinia": "3.0.4", - "screenfull": "6.0.2", "vue": "3.5.30", "vue-cropper": "1.1.4", "vue-i18n": "11.3.0", @@ -47,15 +44,11 @@ "vxe-table": "4.18.1" }, "devDependencies": { - "@iconify/json": "^2.2.448", "@types/crypto-js": "4.2.2", - "@types/file-saver": "2.0.7", - "@types/js-cookie": "3.0.6", "@types/node": "^25.4.0", "@types/nprogress": "0.2.3", "@unocss/preset-attributify": "66.6.6", - "@unocss/preset-icons": "66.6.6", - "@unocss/preset-uno": "66.6.6", + "@unocss/preset-wind3": "66.6.6", "@vitejs/plugin-vue": "6.0.4", "@vue/compiler-sfc": "3.5.30", "@vue/eslint-config-prettier": "10.2.0", @@ -70,7 +63,6 @@ "typescript": "~5.9.3", "unocss": "66.6.6", "unplugin-auto-import": "21.0.0", - "unplugin-icons": "23.0.1", "unplugin-vue-components": "31.0.0", "unplugin-vue-setup-extend-plus": "1.0.1", "vite": "7.3.1", diff --git a/src/components/IconSelect/index.vue b/src/components/IconSelect/index.vue index 4be0219..e7d0e24 100644 --- a/src/components/IconSelect/index.vue +++ b/src/components/IconSelect/index.vue @@ -9,8 +9,8 @@ diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index f61deec..1982f01 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -85,7 +85,7 @@ import { useSettingsStore } from '@/store/modules/settings'; import { useNoticeStore } from '@/store/modules/notice'; import notice from './notice/index.vue'; import router from '@/router'; -import { ElMessageBoxOptions } from 'element-plus/es/components/message-box/src/message-box.type'; +import type { ElMessageBoxOptions } from 'element-plus'; import { NavTypeEnum } from '@/enums/NavTypeEnum'; import Logo from "@/layout/components/Sidebar/Logo.vue"; import TopBar from './TopBar/index.vue'; diff --git a/src/permission.ts b/src/permission.ts index fb60b07..d1480d9 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -1,6 +1,6 @@ import { to as tos } from 'await-to-js'; import router from './router'; -import NProgress from 'nprogress'; +import * as NProgressModule from 'nprogress'; import 'nprogress/nprogress.css'; import { getToken } from '@/utils/auth'; import { isHttp, isPathMatch } from '@/utils/validate'; @@ -10,6 +10,8 @@ import { useSettingsStore } from '@/store/modules/settings'; import { usePermissionStore } from '@/store/modules/permission'; import { ElMessage } from 'element-plus/es'; +const NProgress = ('default' in NProgressModule ? NProgressModule.default : NProgressModule) as typeof NProgressModule; + NProgress.configure({ showSpinner: false }); const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*']; diff --git a/src/plugins/download.ts b/src/plugins/download.ts index ef66b3a..3c86e5a 100644 --- a/src/plugins/download.ts +++ b/src/plugins/download.ts @@ -1,12 +1,12 @@ import axios from 'axios'; -import FileSaver from 'file-saver'; import errorCode from '@/utils/errorCode'; import { blobValidate } from '@/utils/ruoyi'; -import { LoadingInstance } from 'element-plus/es/components/loading/src/loading'; import { globalHeaders } from '@/utils/request'; +import { saveBlob } from '@/utils/save'; +import type { LoadingInstance } from 'element-plus'; const baseURL = import.meta.env.VITE_APP_BASE_API; -let downloadLoadingInstance: LoadingInstance; +let downloadLoadingInstance: LoadingInstance | undefined; export default { async oss(ossId: string | number) { const url = baseURL + '/resource/oss/download/' + ossId; @@ -21,15 +21,15 @@ export default { const isBlob = blobValidate(res.data); if (isBlob) { const blob = new Blob([res.data], { type: 'application/octet-stream' }); - FileSaver.saveAs(blob, decodeURIComponent(res.headers['download-filename'] as string)); + saveBlob(blob, decodeURIComponent(res.headers['download-filename'] as string)); } else { this.printErrMsg(res.data); } - downloadLoadingInstance.close(); + downloadLoadingInstance?.close(); } catch (r) { console.error(r); ElMessage.error('下载文件出现错误,请联系管理员!'); - downloadLoadingInstance.close(); + downloadLoadingInstance?.close(); } }, async zip(url: string, name: string) { @@ -45,15 +45,15 @@ export default { const isBlob = blobValidate(res.data); if (isBlob) { const blob = new Blob([res.data], { type: 'application/zip' }); - FileSaver.saveAs(blob, name); + saveBlob(blob, name); } else { this.printErrMsg(res.data); } - downloadLoadingInstance.close(); + downloadLoadingInstance?.close(); } catch (r) { console.error(r); ElMessage.error('下载文件出现错误,请联系管理员!'); - downloadLoadingInstance.close(); + downloadLoadingInstance?.close(); } }, async printErrMsg(data: any) { diff --git a/src/plugins/modal.ts b/src/plugins/modal.ts index a8b0548..7abcc20 100644 --- a/src/plugins/modal.ts +++ b/src/plugins/modal.ts @@ -1,6 +1,6 @@ -import { MessageBoxData } from 'element-plus'; -import { LoadingInstance } from 'element-plus/es/components/loading/src/loading'; -let loadingInstance: LoadingInstance; +import type { LoadingInstance, MessageBoxData } from 'element-plus'; + +let loadingInstance: LoadingInstance | undefined; export default { // 消息提示 msg(content: any) { @@ -76,6 +76,6 @@ export default { }, // 关闭遮罩层 closeLoading() { - loadingInstance.close(); + loadingInstance?.close(); } }; diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts index 8217146..2f3aa6e 100644 --- a/src/utils/crypto.ts +++ b/src/utils/crypto.ts @@ -1,4 +1,6 @@ -import CryptoJS from 'crypto-js'; +import * as CryptoJSModule from 'crypto-js'; + +const CryptoJS = ('default' in CryptoJSModule ? CryptoJSModule.default : CryptoJSModule) as typeof CryptoJSModule; /** * 随机生成32位的字符串 @@ -26,7 +28,7 @@ export const generateAesKey = () => { * 加密base64 * @returns {string} */ -export const encryptBase64 = (str: CryptoJS.lib.WordArray) => { +export const encryptBase64 = (str: CryptoJSModule.lib.WordArray) => { return CryptoJS.enc.Base64.stringify(str); }; @@ -43,7 +45,7 @@ export const decryptBase64 = (str: string) => { * @param aesKey * @returns {string} */ -export const encryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray) => { +export const encryptWithAes = (message: string, aesKey: CryptoJSModule.lib.WordArray) => { const encrypted = CryptoJS.AES.encrypt(message, aesKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 @@ -57,7 +59,7 @@ export const encryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray) * @param aesKey * @returns {string} */ -export const decryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray) => { +export const decryptWithAes = (message: string, aesKey: CryptoJSModule.lib.WordArray) => { const decrypted = CryptoJS.AES.decrypt(message, aesKey, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 diff --git a/src/utils/jsencrypt.ts b/src/utils/jsencrypt.ts index 42de5a0..a1e92db 100644 --- a/src/utils/jsencrypt.ts +++ b/src/utils/jsencrypt.ts @@ -1,4 +1,4 @@ -import JSEncrypt from 'jsencrypt'; +import { JSEncrypt } from 'jsencrypt'; // 密钥对生成 http://web.chacuo.net/netrsakeypair const publicKey = import.meta.env.VITE_APP_RSA_PUBLIC_KEY; diff --git a/src/utils/request.ts b/src/utils/request.ts index cd16fb1..fd343af 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -5,15 +5,15 @@ import { tansParams, blobValidate } from '@/utils/ruoyi'; import cache from '@/plugins/cache'; import { HttpStatus } from '@/enums/RespEnum'; import { errorCode } from '@/utils/errorCode'; -import { LoadingInstance } from 'element-plus/es/components/loading/src/loading'; -import FileSaver from 'file-saver'; import { getLanguage } from '@/lang'; import { encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64 } from '@/utils/crypto'; import { encrypt, decrypt } from '@/utils/jsencrypt'; import router from '@/router'; +import { saveBlob } from '@/utils/save'; +import type { LoadingInstance } from 'element-plus'; const encryptHeader = 'encrypt-key'; -let downloadLoadingInstance: LoadingInstance; +let downloadLoadingInstance: LoadingInstance | undefined; // 是否显示重新登录 export const isRelogin = { show: false }; export const globalHeaders = () => { @@ -193,7 +193,7 @@ export function download(url: string, params: any, fileName: string) { const isLogin = blobValidate(resp); if (isLogin) { const blob = new Blob([resp]); - FileSaver.saveAs(blob, fileName); + saveBlob(blob, fileName); } else { const blob = new Blob([resp]); const resText = await blob.text(); @@ -201,11 +201,11 @@ export function download(url: string, params: any, fileName: string) { const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']; ElMessage.error(errMsg); } - downloadLoadingInstance.close(); + downloadLoadingInstance?.close(); }).catch((r: any) => { console.error(r); ElMessage.error('下载文件出现错误,请联系管理员!'); - downloadLoadingInstance.close(); + downloadLoadingInstance?.close(); }); } // 导出 axios 实例 diff --git a/src/utils/save.ts b/src/utils/save.ts new file mode 100644 index 0000000..6cb0502 --- /dev/null +++ b/src/utils/save.ts @@ -0,0 +1,13 @@ +export function saveBlob(blob: Blob, fileName: string) { + const downloadLink = document.createElement('a'); + const objectUrl = URL.createObjectURL(blob); + + downloadLink.href = objectUrl; + downloadLink.download = fileName; + downloadLink.rel = 'noopener'; + downloadLink.click(); + + setTimeout(() => { + URL.revokeObjectURL(objectUrl); + }, 40_000); +} diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index da8c5bc..d22844c 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -267,7 +267,7 @@ drag > - +
将文件拖到此处,或点击上传