✨ init Project
This commit is contained in:
		
							
								
								
									
										29
									
								
								src/utils/asyncRouter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/utils/asyncRouter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| const viewModules = import.meta.glob('../view/**/*.vue') | ||||
| const pluginModules = import.meta.glob('../plugin/**/*.vue') | ||||
|  | ||||
| export const asyncRouterHandle = (asyncRouter) => { | ||||
|   asyncRouter.forEach((item) => { | ||||
|     if (item.component && typeof item.component === 'string') { | ||||
|       item.meta.path = '/src/' + item.component | ||||
|       if (item.component.split('/')[0] === 'view') { | ||||
|         item.component = dynamicImport(viewModules, item.component) | ||||
|       } else if (item.component.split('/')[0] === 'plugin') { | ||||
|         item.component = dynamicImport(pluginModules, item.component) | ||||
|       } | ||||
|     } | ||||
|     if (item.children) { | ||||
|       asyncRouterHandle(item.children) | ||||
|     } | ||||
|   }) | ||||
| } | ||||
|  | ||||
| function dynamicImport(dynamicViewsModules, component) { | ||||
|   const keys = Object.keys(dynamicViewsModules) | ||||
|   const matchKeys = keys.filter((key) => { | ||||
|     const k = key.replace('../', '') | ||||
|     return k === component | ||||
|   }) | ||||
|   const matchKey = matchKeys[0] | ||||
|  | ||||
|   return dynamicViewsModules[matchKey] | ||||
| } | ||||
							
								
								
									
										6
									
								
								src/utils/btnAuth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/utils/btnAuth.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| import { useRoute } from 'vue-router' | ||||
| import { reactive } from 'vue' | ||||
| export const useBtnAuth = () => { | ||||
|   const route = useRoute() | ||||
|   return route.meta.btns || reactive({}) | ||||
| } | ||||
							
								
								
									
										4
									
								
								src/utils/bus.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/utils/bus.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| // using ES6 modules | ||||
| import mitt from 'mitt' | ||||
|  | ||||
| export const emitter = mitt() | ||||
							
								
								
									
										5
									
								
								src/utils/closeThisPage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/utils/closeThisPage.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import { emitter } from '@/utils/bus.js' | ||||
|  | ||||
| export const closeThisPage = () => { | ||||
|   emitter.emit('closeThisPage') | ||||
| } | ||||
							
								
								
									
										44
									
								
								src/utils/date.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/utils/date.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // 对Date的扩展,将 Date 转化为指定格式的String | ||||
| // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, | ||||
| // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) | ||||
| // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 | ||||
| // (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18 | ||||
| // eslint-disable-next-line no-extend-native | ||||
| Date.prototype.Format = function(fmt) { | ||||
|   const o = { | ||||
|     'M+': this.getMonth() + 1, // 月份 | ||||
|     'd+': this.getDate(), // 日 | ||||
|     'h+': this.getHours(), // 小时 | ||||
|     'm+': this.getMinutes(), // 分 | ||||
|     's+': this.getSeconds(), // 秒 | ||||
|     'q+': Math.floor((this.getMonth() + 3) / 3), // 季度 | ||||
|     'S': this.getMilliseconds() // 毫秒 | ||||
|   } | ||||
|   const reg = /(y+)/ | ||||
|   if (reg.test(fmt)) { | ||||
|     const t = reg.exec(fmt)[1] | ||||
|     fmt = fmt.replace( | ||||
|       t, | ||||
|       (this.getFullYear() + '').substring(4 - t.length) | ||||
|     ) | ||||
|   } | ||||
|   for (let k in o) { | ||||
|     const regx = new RegExp('(' + k + ')') | ||||
|     if (regx.test(fmt)) { | ||||
|       const t = regx.exec(fmt)[1] | ||||
|       fmt = fmt.replace( | ||||
|         t, | ||||
|         t.length === 1 ? o[k] : ('00' + o[k]).substring(('' + o[k]).length) | ||||
|       ) | ||||
|     } | ||||
|   } | ||||
|   return fmt | ||||
| } | ||||
|  | ||||
| export function formatTimeToStr(times, pattern) { | ||||
|   let d = new Date(times).Format('yyyy-MM-dd hh:mm:ss') | ||||
|   if (pattern) { | ||||
|     d = new Date(times).Format(pattern) | ||||
|   } | ||||
|   return d.toLocaleString() | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/utils/dictionary.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/utils/dictionary.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| import { useDictionaryStore } from '@/pinia/modules/dictionary' | ||||
| //  获取字典方法 使用示例 getDict('sex').then(res)  或者 async函数下 const res = await getDict('sex') | ||||
| export const getDict = async (type) => { | ||||
|   const dictionaryStore = useDictionaryStore() | ||||
|   await dictionaryStore.getDictionary(type) | ||||
|   return dictionaryStore.dictionaryMap[type] | ||||
| } | ||||
|  | ||||
| //  字典文字展示方法 | ||||
| export const showDictLabel = ( | ||||
|   dict, | ||||
|   code, | ||||
|   keyCode = 'value', | ||||
|   valueCode = 'label' | ||||
| ) => { | ||||
|   if (!dict) { | ||||
|     return '' | ||||
|   } | ||||
|   const dictMap = {} | ||||
|   dict.forEach((item) => { | ||||
|     if (Reflect.has(item, keyCode) && Reflect.has(item, valueCode)) { | ||||
|       dictMap[item[keyCode]] = item[valueCode] | ||||
|     } | ||||
|   }) | ||||
|   return Reflect.has(dictMap, code) ? dictMap[code] : '' | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/utils/doc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/utils/doc.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| export const toDoc = (url) => { | ||||
|   window.open(url, '_blank') | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/utils/downloadImg.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/utils/downloadImg.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| export const downloadImage = (imgsrc, name) => { | ||||
|   // 下载图片地址和图片名 | ||||
|   var image = new Image() | ||||
|   image.setAttribute('crossOrigin', 'anonymous') | ||||
|   image.onload = function () { | ||||
|     var canvas = document.createElement('canvas') | ||||
|     canvas.width = image.width | ||||
|     canvas.height = image.height | ||||
|     var context = canvas.getContext('2d') | ||||
|     context.drawImage(image, 0, 0, image.width, image.height) | ||||
|     var url = canvas.toDataURL('image/png') // 得到图片的base64编码数据 | ||||
|  | ||||
|     var a = document.createElement('a') // 生成一个a元素 | ||||
|     var event = new MouseEvent('click') // 创建一个单击事件 | ||||
|     a.download = name || 'photo' // 设置图片名称 | ||||
|     a.href = url // 将生成的URL设置为a.href属性 | ||||
|     a.dispatchEvent(event) // 触发a的单击事件 | ||||
|   } | ||||
|   image.src = imgsrc | ||||
| } | ||||
							
								
								
									
										17
									
								
								src/utils/event.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/utils/event.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| export function addEventListen(target, event, handler, capture = false) { | ||||
|   if ( | ||||
|     target.addEventListener && | ||||
|     typeof target.addEventListener === 'function' | ||||
|   ) { | ||||
|     target.addEventListener(event, handler, capture) | ||||
|   } | ||||
| } | ||||
|  | ||||
| export function removeEventListen(target, event, handler, capture = false) { | ||||
|   if ( | ||||
|     target.removeEventListener && | ||||
|     typeof target.removeEventListener === 'function' | ||||
|   ) { | ||||
|     target.removeEventListener(event, handler, capture) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/utils/fmtRouterTitle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/utils/fmtRouterTitle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| export const fmtTitle = (title, now) => { | ||||
|   const reg = /\$\{(.+?)\}/ | ||||
|   const reg_g = /\$\{(.+?)\}/g | ||||
|   const result = title.match(reg_g) | ||||
|   if (result) { | ||||
|     result.forEach((item) => { | ||||
|       const key = item.match(reg)[1] | ||||
|       const value = now.params[key] || now.query[key] | ||||
|       title = title.replace(item, value) | ||||
|     }) | ||||
|   } | ||||
|   return title | ||||
| } | ||||
							
								
								
									
										146
									
								
								src/utils/format.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/utils/format.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| import { formatTimeToStr } from '@/utils/date' | ||||
| import { getDict } from '@/utils/dictionary' | ||||
| import { ref } from 'vue' | ||||
|  | ||||
| export const formatBoolean = (bool) => { | ||||
|   if (bool !== null) { | ||||
|     return bool ? '是' : '否' | ||||
|   } else { | ||||
|     return '' | ||||
|   } | ||||
| } | ||||
| export const formatDate = (time) => { | ||||
|   if (time !== null && time !== '') { | ||||
|     var date = new Date(time) | ||||
|     return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss') | ||||
|   } else { | ||||
|     return '' | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const filterDict = (value, options) => { | ||||
|   const rowLabel = options && options.filter((item) => item.value === value) | ||||
|   return rowLabel && rowLabel[0] && rowLabel[0].label | ||||
| } | ||||
|  | ||||
| export const filterDataSource = (dataSource, value) => { | ||||
|   if (Array.isArray(value)) { | ||||
|     return value.map((item) => { | ||||
|       const rowLabel = dataSource && dataSource.find((i) => i.value === item) | ||||
|       return rowLabel?.label | ||||
|     }) | ||||
|   } | ||||
|   const rowLabel = dataSource && dataSource.find((item) => item.value === value) | ||||
|   return rowLabel?.label | ||||
| } | ||||
|  | ||||
| export const getDictFunc = async (type) => { | ||||
|   const dicts = await getDict(type) | ||||
|   return dicts | ||||
| } | ||||
|  | ||||
| const path = | ||||
|   import.meta.env.VITE_BASE_PATH + ':' + import.meta.env.VITE_SERVER_PORT + '/' | ||||
| export const ReturnArrImg = (arr) => { | ||||
|   const imgArr = [] | ||||
|   if (arr instanceof Array) { | ||||
|     // 如果是数组类型 | ||||
|     for (const arrKey in arr) { | ||||
|       if (arr[arrKey].slice(0, 4) !== 'http') { | ||||
|         imgArr.push(path + arr[arrKey]) | ||||
|       } else { | ||||
|         imgArr.push(arr[arrKey]) | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     // 如果不是数组类型 | ||||
|     if (arr?.slice(0, 4) !== 'http') { | ||||
|       imgArr.push(path + arr) | ||||
|     } else { | ||||
|       imgArr.push(arr) | ||||
|     } | ||||
|   } | ||||
|   return imgArr | ||||
| } | ||||
|  | ||||
| export const returnArrImg = ReturnArrImg | ||||
|  | ||||
| export const onDownloadFile = (url) => { | ||||
|   window.open(path + url) | ||||
| } | ||||
| const colorToHex = (u) => { | ||||
|   let e = u.replace('#', '').match(/../g) | ||||
|   for (let t = 0; t < 3; t++) e[t] = parseInt(e[t], 16) | ||||
|   return e | ||||
| } | ||||
|  | ||||
| const hexToColor = (u, e, t) => { | ||||
|   let a = [u.toString(16), e.toString(16), t.toString(16)] | ||||
|   for (let n = 0; n < 3; n++) a[n].length === 1 && (a[n] = `0${a[n]}`) | ||||
|   return `#${a.join('')}` | ||||
| } | ||||
| const generateAllColors = (u, e) => { | ||||
|   let t = colorToHex(u) | ||||
|   const target = [10, 10, 30] | ||||
|   for (let a = 0; a < 3; a++) t[a] = Math.floor(t[a] * (1 - e) + target[a] * e) | ||||
|   return hexToColor(t[0], t[1], t[2]) | ||||
| } | ||||
|  | ||||
| const generateAllLightColors = (u, e) => { | ||||
|   let t = colorToHex(u) | ||||
|   const target = [240, 248, 255] // RGB for blue white color | ||||
|   for (let a = 0; a < 3; a++) t[a] = Math.floor(t[a] * (1 - e) + target[a] * e) | ||||
|   return hexToColor(t[0], t[1], t[2]) | ||||
| } | ||||
|  | ||||
| function addOpacityToColor(u, opacity) { | ||||
|   let t = colorToHex(u) | ||||
|   return `rgba(${t[0]}, ${t[1]}, ${t[2]}, ${opacity})` | ||||
| } | ||||
|  | ||||
| export const setBodyPrimaryColor = (primaryColor, darkMode) => { | ||||
|   let fmtColorFunc = generateAllColors | ||||
|   if (darkMode === 'light') { | ||||
|     fmtColorFunc = generateAllLightColors | ||||
|   } | ||||
|  | ||||
|   document.documentElement.style.setProperty('--el-color-primary', primaryColor) | ||||
|   document.documentElement.style.setProperty( | ||||
|     '--el-color-primary-bg', | ||||
|     addOpacityToColor(primaryColor, 0.4) | ||||
|   ) | ||||
|   for (let times = 1; times <= 2; times++) { | ||||
|     document.documentElement.style.setProperty( | ||||
|       `--el-color-primary-dark-${times}`, | ||||
|       fmtColorFunc(primaryColor, times / 10) | ||||
|     ) | ||||
|   } | ||||
|   for (let times = 1; times <= 10; times++) { | ||||
|     document.documentElement.style.setProperty( | ||||
|       `--el-color-primary-light-${times}`, | ||||
|       fmtColorFunc(primaryColor, times / 10) | ||||
|     ) | ||||
|   } | ||||
|   document.documentElement.style.setProperty( | ||||
|     `--el-menu-hover-bg-color`, | ||||
|     addOpacityToColor(primaryColor, 0.2) | ||||
|   ) | ||||
| } | ||||
|  | ||||
| const baseUrl = ref(import.meta.env.VITE_BASE_API) | ||||
|  | ||||
| export const getBaseUrl = () => { | ||||
|   return baseUrl.value === '/' ? '' : baseUrl.value | ||||
| } | ||||
|  | ||||
| export const CreateUUID = () => { | ||||
|   let d = new Date().getTime() | ||||
|   if (window.performance && typeof window.performance.now === 'function') { | ||||
|     d += performance.now() | ||||
|   } | ||||
|   return '00000000-0000-0000-0000-000000000000'.replace(/0/g, (c) => { | ||||
|     const r = (d + Math.random() * 16) % 16 | 0 // d是随机种子 | ||||
|     d = Math.floor(d / 16) | ||||
|     return (c === '0' ? r : (r & 0x3) | 0x8).toString(16) | ||||
|   }) | ||||
| } | ||||
							
								
								
									
										126
									
								
								src/utils/image.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/utils/image.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| export default class ImageCompress { | ||||
|   constructor(file, fileSize, maxWH = 1920) { | ||||
|     this.file = file | ||||
|     this.fileSize = fileSize | ||||
|     this.maxWH = maxWH // 最大长宽 | ||||
|   } | ||||
|  | ||||
|   compress() { | ||||
|     // 压缩 | ||||
|     const fileType = this.file.type | ||||
|     const fileSize = this.file.size / 1024 | ||||
|     return new Promise((resolve) => { | ||||
|       const reader = new FileReader() | ||||
|       reader.readAsDataURL(this.file) | ||||
|       reader.onload = () => { | ||||
|         const canvas = document.createElement('canvas') | ||||
|         const img = document.createElement('img') | ||||
|         img.src = reader.result | ||||
|         img.onload = () => { | ||||
|           const ctx = canvas.getContext('2d') | ||||
|           const _dWH = this.dWH(img.width, img.height, this.maxWH) | ||||
|           canvas.width = _dWH.width | ||||
|           canvas.height = _dWH.height | ||||
|  | ||||
|           // 清空后, 重写画布 | ||||
|           ctx.clearRect(0, 0, canvas.width, canvas.height) | ||||
|           ctx.drawImage(img, 0, 0, canvas.width, canvas.height) | ||||
|  | ||||
|           const newImgData = canvas.toDataURL(fileType, 0.9) | ||||
|  | ||||
|           // 压缩宽高后的图像大小 | ||||
|           const newImgSize = this.fileSizeKB(newImgData) | ||||
|  | ||||
|           if (newImgSize > this.fileSize) { | ||||
|             console.log('图片尺寸太大!' + fileSize + ' >> ' + newImgSize) | ||||
|           } | ||||
|  | ||||
|           const blob = this.dataURLtoBlob(newImgData, fileType) | ||||
|           const nfile = new File([blob], this.file.name) | ||||
|           resolve(nfile) | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 长宽等比缩小 | ||||
|    * 图像的一边(长或宽)为最大目标值 | ||||
|    */ | ||||
|   dWH(srcW, srcH, dMax) { | ||||
|     const defaults = { | ||||
|       width: srcW, | ||||
|       height: srcH | ||||
|     } | ||||
|     if (Math.max(srcW, srcH) > dMax) { | ||||
|       if (srcW > srcH) { | ||||
|         defaults.width = dMax | ||||
|         defaults.height = Math.round(srcH * (dMax / srcW)) | ||||
|         return defaults | ||||
|       } else { | ||||
|         defaults.height = dMax | ||||
|         defaults.width = Math.round(srcW * (dMax / srcH)) | ||||
|         return defaults | ||||
|       } | ||||
|     } else { | ||||
|       return defaults | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   fileSizeKB(dataURL) { | ||||
|     let sizeKB = 0 | ||||
|     sizeKB = Math.round((dataURL.split(',')[1].length * 3) / 4 / 1024) | ||||
|     return sizeKB | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 转为Blob | ||||
|    */ | ||||
|   dataURLtoBlob(dataURL, fileType) { | ||||
|     const byteString = atob(dataURL.split(',')[1]) | ||||
|     let mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0] | ||||
|     const ab = new ArrayBuffer(byteString.length) | ||||
|     const ia = new Uint8Array(ab) | ||||
|     for (let i = 0; i < byteString.length; i++) { | ||||
|       ia[i] = byteString.charCodeAt(i) | ||||
|     } | ||||
|     if (fileType) { | ||||
|       mimeString = fileType | ||||
|     } | ||||
|     return new Blob([ab], { type: mimeString, lastModifiedDate: new Date() }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| const path = import.meta.env.VITE_FILE_API | ||||
| export const getUrl = (url) => { | ||||
|   if (url && url.slice(0, 4) !== 'http') { | ||||
|     if (path === '/') { | ||||
|       return url | ||||
|     } | ||||
|     if (url.slice(0, 1) === '/') { | ||||
|       return path + url | ||||
|     } | ||||
|     return path + '/' + url | ||||
|   } else { | ||||
|     return url | ||||
|   } | ||||
| } | ||||
|  | ||||
| const VIDEO_EXTENSIONS = ['.mp4', '.mov', '.webm', '.ogg'] | ||||
| const VIDEO_MIME_TYPES = ['video/mp4', 'video/webm', 'video/ogg'] | ||||
| const IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml'] | ||||
|  | ||||
| export const isVideoExt = (url) => { | ||||
|   const urlLower = url?.toLowerCase() || '' | ||||
|   return urlLower !== '' && VIDEO_EXTENSIONS.some(ext => urlLower.endsWith(ext)) | ||||
| } | ||||
|  | ||||
| export const isVideoMime = (type) => { | ||||
|   const typeLower = type?.toLowerCase() || '' | ||||
|   return typeLower !== '' && VIDEO_MIME_TYPES.includes(typeLower) | ||||
| } | ||||
|  | ||||
| export const isImageMime = (type) => { | ||||
|   const typeLower = type?.toLowerCase() || '' | ||||
|   return typeLower !== '' && IMAGE_MIME_TYPES.includes(typeLower) | ||||
| } | ||||
							
								
								
									
										9
									
								
								src/utils/page.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/utils/page.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| import { fmtTitle } from '@/utils/fmtRouterTitle' | ||||
| import config from '@/core/config' | ||||
| export default function getPageTitle(pageTitle, route) { | ||||
|   if (pageTitle) { | ||||
|     const title = fmtTitle(pageTitle, route) | ||||
|     return `${title} - ${config.appName}` | ||||
|   } | ||||
|   return `${config.appName}` | ||||
| } | ||||
							
								
								
									
										14
									
								
								src/utils/params.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/utils/params.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| import { useParamsStore } from '@/pinia/modules/params' | ||||
| /* | ||||
|  * 获取参数方法 使用示例 getParams('key').then(res)  或者 async函数下 const res = await getParams('key') | ||||
|  *   const res = ref('') | ||||
|  *   const fun = async () => { | ||||
|  *       res.value = await getParams('test') | ||||
|  *   } | ||||
|  *   fun() | ||||
|  */ | ||||
| export const getParams = async(key) => { | ||||
|     const paramsStore = useParamsStore() | ||||
|     await paramsStore.getParams(key) | ||||
|     return paramsStore.paramsMap[key] | ||||
| } | ||||
							
								
								
									
										172
									
								
								src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| import axios from 'axios' // 引入axios | ||||
| import { ElMessage, ElMessageBox } from 'element-plus' | ||||
| import { useUserStore } from '@/pinia/modules/user' | ||||
| import router from '@/router/index' | ||||
| import { ElLoading } from 'element-plus' | ||||
|  | ||||
| const service = axios.create({ | ||||
|   baseURL: import.meta.env.VITE_BASE_API, | ||||
|   timeout: 99999 | ||||
| }) | ||||
| let activeAxios = 0 | ||||
| let timer | ||||
| let loadingInstance | ||||
| const showLoading = ( | ||||
|   option = { | ||||
|     target: null | ||||
|   } | ||||
| ) => { | ||||
|   const loadDom = document.getElementById('gva-base-load-dom') | ||||
|   activeAxios++ | ||||
|   if (timer) { | ||||
|     clearTimeout(timer) | ||||
|   } | ||||
|   timer = setTimeout(() => { | ||||
|     if (activeAxios > 0) { | ||||
|       if (!option.target) option.target = loadDom | ||||
|       loadingInstance = ElLoading.service(option) | ||||
|     } | ||||
|   }, 400) | ||||
| } | ||||
|  | ||||
| const closeLoading = () => { | ||||
|   activeAxios-- | ||||
|   if (activeAxios <= 0) { | ||||
|     clearTimeout(timer) | ||||
|     loadingInstance && loadingInstance.close() | ||||
|   } | ||||
| } | ||||
| // http request 拦截器 | ||||
| service.interceptors.request.use( | ||||
|   (config) => { | ||||
|     if (!config.donNotShowLoading) { | ||||
|       showLoading(config.loadingOption) | ||||
|     } | ||||
|     const userStore = useUserStore() | ||||
|     config.headers = { | ||||
|       'Content-Type': 'application/json', | ||||
|       'x-token': userStore.token, | ||||
|       'x-user-id': userStore.userInfo.ID, | ||||
|       ...config.headers | ||||
|     } | ||||
|     return config | ||||
|   }, | ||||
|   (error) => { | ||||
|     if (!error.config.donNotShowLoading) { | ||||
|       closeLoading() | ||||
|     } | ||||
|     ElMessage({ | ||||
|       showClose: true, | ||||
|       message: error, | ||||
|       type: 'error' | ||||
|     }) | ||||
|     return error | ||||
|   } | ||||
| ) | ||||
|  | ||||
| // http response 拦截器 | ||||
| service.interceptors.response.use( | ||||
|   (response) => { | ||||
|     const userStore = useUserStore() | ||||
|     if (!response.config.donNotShowLoading) { | ||||
|       closeLoading() | ||||
|     } | ||||
|     if (response.headers['new-token']) { | ||||
|       userStore.setToken(response.headers['new-token']) | ||||
|     } | ||||
|     if (response.data.code === 0 || response.headers.success === 'true') { | ||||
|       if (response.headers.msg) { | ||||
|         response.data.msg = decodeURI(response.headers.msg) | ||||
|       } | ||||
|       return response.data | ||||
|     } else { | ||||
|       ElMessage({ | ||||
|         showClose: true, | ||||
|         message: response.data.msg || decodeURI(response.headers.msg), | ||||
|         type: 'error' | ||||
|       }) | ||||
|       return response.data.msg ? response.data : response | ||||
|     } | ||||
|   }, | ||||
|   (error) => { | ||||
|     if (!error.config.donNotShowLoading) { | ||||
|       closeLoading() | ||||
|     } | ||||
|  | ||||
|     if (!error.response) { | ||||
|       ElMessageBox.confirm( | ||||
|         ` | ||||
|         <p>检测到请求错误</p> | ||||
|         <p>${error}</p> | ||||
|         `, | ||||
|         '请求报错', | ||||
|         { | ||||
|           dangerouslyUseHTMLString: true, | ||||
|           distinguishCancelAndClose: true, | ||||
|           confirmButtonText: '稍后重试', | ||||
|           cancelButtonText: '取消' | ||||
|         } | ||||
|       ) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     switch (error.response.status) { | ||||
|       case 500: | ||||
|         ElMessageBox.confirm( | ||||
|           ` | ||||
|         <p>检测到接口错误${error}</p> | ||||
|         <p>错误码<span style="color:red"> 500 </span>:此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存</p> | ||||
|         `, | ||||
|           '接口报错', | ||||
|           { | ||||
|             dangerouslyUseHTMLString: true, | ||||
|             distinguishCancelAndClose: true, | ||||
|             confirmButtonText: '清理缓存', | ||||
|             cancelButtonText: '取消' | ||||
|           } | ||||
|         ).then(() => { | ||||
|           const userStore = useUserStore() | ||||
|           userStore.ClearStorage() | ||||
|           router.push({ name: 'Login', replace: true }) | ||||
|         }) | ||||
|         break | ||||
|       case 404: | ||||
|         ElMessageBox.confirm( | ||||
|           ` | ||||
|           <p>检测到接口错误${error}</p> | ||||
|           <p>错误码<span style="color:red"> 404 </span>:此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格</p> | ||||
|           `, | ||||
|           '接口报错', | ||||
|           { | ||||
|             dangerouslyUseHTMLString: true, | ||||
|             distinguishCancelAndClose: true, | ||||
|             confirmButtonText: '我知道了', | ||||
|             cancelButtonText: '取消' | ||||
|           } | ||||
|         ) | ||||
|         break | ||||
|       case 401: | ||||
|         ElMessageBox.confirm( | ||||
|           ` | ||||
|           <p>无效的令牌</p> | ||||
|           <p>错误码:<span style="color:red"> 401 </span>错误信息:${error}</p> | ||||
|           `, | ||||
|           '身份信息', | ||||
|           { | ||||
|             dangerouslyUseHTMLString: true, | ||||
|             distinguishCancelAndClose: true, | ||||
|             confirmButtonText: '重新登录', | ||||
|             cancelButtonText: '取消' | ||||
|           } | ||||
|         ).then(() => { | ||||
|           const userStore = useUserStore() | ||||
|           userStore.ClearStorage() | ||||
|           router.push({ name: 'Login', replace: true }) | ||||
|         }) | ||||
|         break | ||||
|     } | ||||
|  | ||||
|     return error | ||||
|   } | ||||
| ) | ||||
| export default service | ||||
							
								
								
									
										29
									
								
								src/utils/stringFun.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/utils/stringFun.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| /* eslint-disable */ | ||||
| export const toUpperCase = (str) => { | ||||
|   if (str[0]) { | ||||
|     return str.replace(str[0], str[0].toUpperCase()) | ||||
|   } else { | ||||
|     return '' | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const toLowerCase = (str) => { | ||||
|   if (str[0]) { | ||||
|     return str.replace(str[0], str[0].toLowerCase()) | ||||
|   } else { | ||||
|     return '' | ||||
|   } | ||||
| } | ||||
|  | ||||
| // 驼峰转换下划线 | ||||
| export const toSQLLine = (str) => { | ||||
|   if (str === 'ID') return 'ID' | ||||
|   return str.replace(/([A-Z])/g, '_$1').toLowerCase() | ||||
| } | ||||
|  | ||||
| // 下划线转换驼峰 | ||||
| export const toHump = (name) => { | ||||
|   return name.replace(/\_(\w)/g, function (all, letter) { | ||||
|     return letter.toUpperCase() | ||||
|   }) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user