From d8aa49e4173b9fa949c07e9b5328429367f61cd0 Mon Sep 17 00:00:00 2001 From: huangge1199 Date: Wed, 15 May 2024 10:07:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=93=E5=8C=85=E5=8E=8B=E7=BC=A9=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8setup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 17 ++++-- src/plugins/cache.js | 77 +++++++++++++++++++++++++ src/utils/errorCode.js | 6 ++ src/utils/request.js | 107 +++++++++++++++++++++++++++++++++++ vite.config.js | 58 +++++++++++++++---- vite/plugins/auto-import.js | 12 ++++ vite/plugins/compression.js | 28 +++++++++ vite/plugins/index.js | 13 +++++ vite/plugins/setup-extend.js | 5 ++ 9 files changed, 308 insertions(+), 15 deletions(-) create mode 100644 src/plugins/cache.js create mode 100644 src/utils/errorCode.js create mode 100644 src/utils/request.js create mode 100644 vite/plugins/auto-import.js create mode 100644 vite/plugins/compression.js create mode 100644 vite/plugins/index.js create mode 100644 vite/plugins/setup-extend.js diff --git a/package.json b/package.json index de95243..f2d17bb 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,23 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build:prod": "vite build", + "build:stage": "vite build --mode staging", "preview": "vite preview", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", "format": "prettier --write src/" }, "dependencies": { - "element-plus": "^2.7.3", "vue": "^3.4.21", - "vue-router": "^4.3.0" + "vue-router": "^4.3.0", + "element-plus": "^2.7.3", + "@element-plus/icons-vue": "^2.3.1", + "@vueup/vue-quill": "1.2.0", + "axios": "^1.6.8", + "unplugin-auto-import": "^0.17.5", + "unplugin-vue-setup-extend-plus": "^1.0.1", + "vite-plugin-compression": "^0.5.1", + "vuex": "^4.1.0" }, "devDependencies": { "@rushstack/eslint-patch": "^1.8.0", @@ -22,6 +30,7 @@ "eslint": "^8.57.0", "eslint-plugin-vue": "^9.23.0", "prettier": "^3.2.5", - "vite": "^5.2.8" + "vite": "^5.2.8", + "babel-polyfill": "^6.26.0" } } diff --git a/src/plugins/cache.js b/src/plugins/cache.js new file mode 100644 index 0000000..a6b9fb2 --- /dev/null +++ b/src/plugins/cache.js @@ -0,0 +1,77 @@ +const sessionCache = { + set(key, value) { + if (!sessionStorage) { + return + } + if (key != null && value != null) { + sessionStorage.setItem(key, value) + } + }, + get(key) { + if (!sessionStorage) { + return null + } + if (key == null) { + return null + } + return sessionStorage.getItem(key) + }, + setJSON(key, jsonValue) { + if (jsonValue != null) { + this.set(key, JSON.stringify(jsonValue)) + } + }, + getJSON(key) { + const value = this.get(key) + if (value != null) { + return JSON.parse(value) + } + }, + remove(key) { + sessionStorage.removeItem(key) + } +} +const localCache = { + set(key, value) { + if (!localStorage) { + return + } + if (key != null && value != null) { + localStorage.setItem(key, value) + } + }, + get(key) { + if (!localStorage) { + return null + } + if (key == null) { + return null + } + return localStorage.getItem(key) + }, + setJSON(key, jsonValue) { + if (jsonValue != null) { + this.set(key, JSON.stringify(jsonValue)) + } + }, + getJSON(key) { + const value = this.get(key) + if (value != null) { + return JSON.parse(value) + } + }, + remove(key) { + localStorage.removeItem(key) + } +} + +export default { + /** + * 会话级缓存 + */ + session: sessionCache, + /** + * 本地缓存 + */ + local: localCache +} diff --git a/src/utils/errorCode.js b/src/utils/errorCode.js new file mode 100644 index 0000000..93e34d6 --- /dev/null +++ b/src/utils/errorCode.js @@ -0,0 +1,6 @@ +export default { + 401: '认证失败,无法访问系统资源', + 403: '当前操作没有权限', + 404: '访问资源不存在', + default: '系统未知错误,请反馈给管理员' +} diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..813015f --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,107 @@ +import axios from 'axios' +import { ElNotification, ElMessage } from 'element-plus' +import errorCode from '@/utils/errorCode' +import cache from '@/plugins/cache' + +axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' +// 创建axios实例 +const service = axios.create({ + // axios中请求配置有baseURL选项,表示请求URL公共部分 + baseURL: import.meta.env.VITE_APP_BASE_API, + // 超时 + timeout: 10000 +}) + +// request拦截器 +service.interceptors.request.use( + (config) => { + // 是否需要防止数据重复提交 + const isRepeatSubmit = (config.headers || {}).repeatSubmit === false + // get请求映射params参数 + if (config.method === 'get' && config.params) { + let url = config.url + '?' + tansParams(config.params) + url = url.slice(0, -1) + config.params = {} + config.url = url + } + if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { + const requestObj = { + url: config.url, + data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, + time: new Date().getTime() + } + const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小 + const limitSize = 5 * 1024 * 1024 // 限制存放数据5M + if (requestSize >= limitSize) { + console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。') + return config + } + const sessionObj = cache.session.getJSON('sessionObj') + if (sessionObj === undefined || sessionObj === null || sessionObj === '') { + cache.session.setJSON('sessionObj', requestObj) + } else { + const s_url = sessionObj.url // 请求地址 + const s_data = sessionObj.data // 请求数据 + const s_time = sessionObj.time // 请求时间 + const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交 + if ( + s_data === requestObj.data && + requestObj.time - s_time < interval && + s_url === requestObj.url + ) { + const message = '数据正在处理,请勿重复提交' + console.warn(`[${s_url}]: ` + message) + return Promise.reject(new Error(message)) + } else { + cache.session.setJSON('sessionObj', requestObj) + } + } + } + return config + }, + (error) => { + console.log(error) + Promise.reject(error) + } +) + +// 响应拦截器 +service.interceptors.response.use( + (res) => { + // 未设置状态码则默认成功状态 + const code = res.data.code || 200 + // 获取错误信息 + const msg = errorCode[code] || res.data.msg || errorCode['default'] + // 二进制数据则直接返回 + if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') { + return res.data + } + if (code === 500) { + ElMessage({ message: msg, type: 'error' }) + return Promise.reject(new Error(msg)) + } else if (code === 601) { + ElMessage({ message: msg, type: 'warning' }) + return Promise.reject(new Error(msg)) + } else if (code !== 200) { + ElNotification.error({ title: msg }) + return Promise.reject('error') + } else { + return Promise.resolve(res.data) + } + }, + (error) => { + console.log('err' + error) + let { message } = error + if (message == 'Network Error') { + message = '后端接口连接异常' + } else if (message.includes('timeout')) { + message = '系统接口请求超时' + } else if (message.includes('Request failed with status code')) { + message = '系统接口' + message.substr(message.length - 3) + '异常' + } + ElMessage({ message: message, type: 'error', duration: 5 * 1000 }) + return Promise.reject(error) + } +) + +export default service diff --git a/vite.config.js b/vite.config.js index 5c45e1d..aaa9867 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,16 +1,52 @@ -import { fileURLToPath, URL } from 'node:url' - -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' +import { defineConfig, loadEnv } from 'vite' +import createVitePlugins from './vite/plugins' +import path from 'path' // https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - vue(), - ], - resolve: { - alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)) +export default defineConfig(({ mode, command }) => { + const env = loadEnv(mode, process.cwd()) + const { VITE_APP_ENV } = env + return { + base: VITE_APP_ENV === 'production' ? '/' : '/', + plugins: createVitePlugins(env, command === 'build'), + resolve: { + alias: { + // 设置路径 + '~': path.resolve(__dirname, './'), + // 设置别名 + '@': path.resolve(__dirname, './src') + }, + extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] + }, + server: { + port: 7777, + host: true, + open: true, + proxy: { + // https://cn.vitejs.dev/config/#server-proxy + '/dev-api': { + target: 'http://localhost:6789', + // target: 'http://117.62.238.129:6789', + changeOrigin: true, + rewrite: (p) => p.replace(/^\/dev-api/, '') + } + } + }, + css: { + postcss: { + plugins: [ + { + postcssPlugin: 'internal:charset-removal', + AtRule: { + charset: (atRule) => { + if (atRule.name === 'charset') { + atRule.remove(); + } + } + } + } + ] + } } } }) diff --git a/vite/plugins/auto-import.js b/vite/plugins/auto-import.js new file mode 100644 index 0000000..a5d3576 --- /dev/null +++ b/vite/plugins/auto-import.js @@ -0,0 +1,12 @@ +import autoImport from 'unplugin-auto-import/vite' + +export default function createAutoImport() { + return autoImport({ + imports: [ + 'vue', + 'vue-router', + 'pinia' + ], + dts: false + }) +} diff --git a/vite/plugins/compression.js b/vite/plugins/compression.js new file mode 100644 index 0000000..e90aaec --- /dev/null +++ b/vite/plugins/compression.js @@ -0,0 +1,28 @@ +import compression from 'vite-plugin-compression' + +export default function createCompression(env) { + const { VITE_BUILD_COMPRESS } = env + const plugin = [] + if (VITE_BUILD_COMPRESS) { + const compressList = VITE_BUILD_COMPRESS.split(',') + if (compressList.includes('gzip')) { + // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 + plugin.push( + compression({ + ext: '.gz', + deleteOriginFile: false + }) + ) + } + if (compressList.includes('brotli')) { + plugin.push( + compression({ + ext: '.br', + algorithm: 'brotliCompress', + deleteOriginFile: false + }) + ) + } + } + return plugin +} diff --git a/vite/plugins/index.js b/vite/plugins/index.js new file mode 100644 index 0000000..208ab6a --- /dev/null +++ b/vite/plugins/index.js @@ -0,0 +1,13 @@ +import vue from '@vitejs/plugin-vue' + +import createAutoImport from './auto-import' +import createCompression from './compression' +import createSetupExtend from './setup-extend' + +export default function createVitePlugins(viteEnv, isBuild = false) { + const vitePlugins = [vue()] + vitePlugins.push(createAutoImport()) + vitePlugins.push(createSetupExtend()) + isBuild && vitePlugins.push(...createCompression(viteEnv)) + return vitePlugins +} diff --git a/vite/plugins/setup-extend.js b/vite/plugins/setup-extend.js new file mode 100644 index 0000000..ed8342e --- /dev/null +++ b/vite/plugins/setup-extend.js @@ -0,0 +1,5 @@ +import setupExtend from 'unplugin-vue-setup-extend-plus/vite' + +export default function createSetupExtend() { + return setupExtend({}) +}