合并 vue与cloud vue3 前端项目
This commit is contained in:
		
							
								
								
									
										15
									
								
								src/utils/auth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/utils/auth.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| import Cookies from 'js-cookie' | ||||
|  | ||||
| const TokenKey = 'Admin-Token' | ||||
|  | ||||
| export function getToken() { | ||||
|   return Cookies.get(TokenKey) | ||||
| } | ||||
|  | ||||
| export function setToken(token) { | ||||
|   return Cookies.set(TokenKey, token) | ||||
| } | ||||
|  | ||||
| export function removeToken() { | ||||
|   return Cookies.remove(TokenKey) | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/utils/dict.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/utils/dict.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| import useDictStore from '@/store/modules/dict' | ||||
| import { getDicts } from '@/api/system/dict/data' | ||||
|  | ||||
| /** | ||||
|  * 获取字典数据 | ||||
|  */ | ||||
| export function useDict(...args) { | ||||
|   const res = ref({}); | ||||
|   return (() => { | ||||
|     args.forEach((dictType, index) => { | ||||
|       res.value[dictType] = []; | ||||
|       const dicts = useDictStore().getDict(dictType); | ||||
|       if (dicts) { | ||||
|         res.value[dictType] = dicts; | ||||
|       } else { | ||||
|         getDicts(dictType).then(resp => { | ||||
|           res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass })) | ||||
|           useDictStore().setDict(dictType, res.value[dictType]); | ||||
|         }) | ||||
|       } | ||||
|     }) | ||||
|     return toRefs(res.value); | ||||
|   })() | ||||
| } | ||||
							
								
								
									
										15
									
								
								src/utils/dynamicTitle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/utils/dynamicTitle.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| import store from '@/store' | ||||
| import defaultSettings from '@/settings' | ||||
| import useSettingsStore from '@/store/modules/settings' | ||||
|  | ||||
| /** | ||||
|  * 动态修改标题 | ||||
|  */ | ||||
| export function useDynamicTitle() { | ||||
|   const settingsStore = useSettingsStore(); | ||||
|   if (settingsStore.dynamicTitle) { | ||||
|     document.title = settingsStore.title + ' - ' + defaultSettings.title; | ||||
|   } else { | ||||
|     document.title = defaultSettings.title; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										6
									
								
								src/utils/errorCode.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/utils/errorCode.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| export default { | ||||
|   '401': '认证失败,无法访问系统资源', | ||||
|   '403': '当前操作没有权限', | ||||
|   '404': '访问资源不存在', | ||||
|   'default': '系统未知错误,请反馈给管理员' | ||||
| } | ||||
							
								
								
									
										390
									
								
								src/utils/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								src/utils/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,390 @@ | ||||
| import { parseTime } from './ruoyi' | ||||
|  | ||||
| /** | ||||
|  * 表格时间格式化 | ||||
|  */ | ||||
| export function formatDate(cellValue) { | ||||
|   if (cellValue == null || cellValue == "") return ""; | ||||
|   var date = new Date(cellValue)  | ||||
|   var year = date.getFullYear() | ||||
|   var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 | ||||
|   var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()  | ||||
|   var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()  | ||||
|   var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()  | ||||
|   var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() | ||||
|   return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {number} time | ||||
|  * @param {string} option | ||||
|  * @returns {string} | ||||
|  */ | ||||
| export function formatTime(time, option) { | ||||
|   if (('' + time).length === 10) { | ||||
|     time = parseInt(time) * 1000 | ||||
|   } else { | ||||
|     time = +time | ||||
|   } | ||||
|   const d = new Date(time) | ||||
|   const now = Date.now() | ||||
|  | ||||
|   const diff = (now - d) / 1000 | ||||
|  | ||||
|   if (diff < 30) { | ||||
|     return '刚刚' | ||||
|   } else if (diff < 3600) { | ||||
|     // less 1 hour | ||||
|     return Math.ceil(diff / 60) + '分钟前' | ||||
|   } else if (diff < 3600 * 24) { | ||||
|     return Math.ceil(diff / 3600) + '小时前' | ||||
|   } else if (diff < 3600 * 24 * 2) { | ||||
|     return '1天前' | ||||
|   } | ||||
|   if (option) { | ||||
|     return parseTime(time, option) | ||||
|   } else { | ||||
|     return ( | ||||
|       d.getMonth() + | ||||
|       1 + | ||||
|       '月' + | ||||
|       d.getDate() + | ||||
|       '日' + | ||||
|       d.getHours() + | ||||
|       '时' + | ||||
|       d.getMinutes() + | ||||
|       '分' | ||||
|     ) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} url | ||||
|  * @returns {Object} | ||||
|  */ | ||||
| export function getQueryObject(url) { | ||||
|   url = url == null ? window.location.href : url | ||||
|   const search = url.substring(url.lastIndexOf('?') + 1) | ||||
|   const obj = {} | ||||
|   const reg = /([^?&=]+)=([^?&=]*)/g | ||||
|   search.replace(reg, (rs, $1, $2) => { | ||||
|     const name = decodeURIComponent($1) | ||||
|     let val = decodeURIComponent($2) | ||||
|     val = String(val) | ||||
|     obj[name] = val | ||||
|     return rs | ||||
|   }) | ||||
|   return obj | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} input value | ||||
|  * @returns {number} output value | ||||
|  */ | ||||
| export function byteLength(str) { | ||||
|   // returns the byte length of an utf8 string | ||||
|   let s = str.length | ||||
|   for (var i = str.length - 1; i >= 0; i--) { | ||||
|     const code = str.charCodeAt(i) | ||||
|     if (code > 0x7f && code <= 0x7ff) s++ | ||||
|     else if (code > 0x7ff && code <= 0xffff) s += 2 | ||||
|     if (code >= 0xDC00 && code <= 0xDFFF) i-- | ||||
|   } | ||||
|   return s | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {Array} actual | ||||
|  * @returns {Array} | ||||
|  */ | ||||
| export function cleanArray(actual) { | ||||
|   const newArray = [] | ||||
|   for (let i = 0; i < actual.length; i++) { | ||||
|     if (actual[i]) { | ||||
|       newArray.push(actual[i]) | ||||
|     } | ||||
|   } | ||||
|   return newArray | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {Object} json | ||||
|  * @returns {Array} | ||||
|  */ | ||||
| export function param(json) { | ||||
|   if (!json) return '' | ||||
|   return cleanArray( | ||||
|     Object.keys(json).map(key => { | ||||
|       if (json[key] === undefined) return '' | ||||
|       return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) | ||||
|     }) | ||||
|   ).join('&') | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} url | ||||
|  * @returns {Object} | ||||
|  */ | ||||
| export function param2Obj(url) { | ||||
|   const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') | ||||
|   if (!search) { | ||||
|     return {} | ||||
|   } | ||||
|   const obj = {} | ||||
|   const searchArr = search.split('&') | ||||
|   searchArr.forEach(v => { | ||||
|     const index = v.indexOf('=') | ||||
|     if (index !== -1) { | ||||
|       const name = v.substring(0, index) | ||||
|       const val = v.substring(index + 1, v.length) | ||||
|       obj[name] = val | ||||
|     } | ||||
|   }) | ||||
|   return obj | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} val | ||||
|  * @returns {string} | ||||
|  */ | ||||
| export function html2Text(val) { | ||||
|   const div = document.createElement('div') | ||||
|   div.innerHTML = val | ||||
|   return div.textContent || div.innerText | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Merges two objects, giving the last one precedence | ||||
|  * @param {Object} target | ||||
|  * @param {(Object|Array)} source | ||||
|  * @returns {Object} | ||||
|  */ | ||||
| export function objectMerge(target, source) { | ||||
|   if (typeof target !== 'object') { | ||||
|     target = {} | ||||
|   } | ||||
|   if (Array.isArray(source)) { | ||||
|     return source.slice() | ||||
|   } | ||||
|   Object.keys(source).forEach(property => { | ||||
|     const sourceProperty = source[property] | ||||
|     if (typeof sourceProperty === 'object') { | ||||
|       target[property] = objectMerge(target[property], sourceProperty) | ||||
|     } else { | ||||
|       target[property] = sourceProperty | ||||
|     } | ||||
|   }) | ||||
|   return target | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {HTMLElement} element | ||||
|  * @param {string} className | ||||
|  */ | ||||
| export function toggleClass(element, className) { | ||||
|   if (!element || !className) { | ||||
|     return | ||||
|   } | ||||
|   let classString = element.className | ||||
|   const nameIndex = classString.indexOf(className) | ||||
|   if (nameIndex === -1) { | ||||
|     classString += '' + className | ||||
|   } else { | ||||
|     classString = | ||||
|       classString.substr(0, nameIndex) + | ||||
|       classString.substr(nameIndex + className.length) | ||||
|   } | ||||
|   element.className = classString | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} type | ||||
|  * @returns {Date} | ||||
|  */ | ||||
| export function getTime(type) { | ||||
|   if (type === 'start') { | ||||
|     return new Date().getTime() - 3600 * 1000 * 24 * 90 | ||||
|   } else { | ||||
|     return new Date(new Date().toDateString()) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {Function} func | ||||
|  * @param {number} wait | ||||
|  * @param {boolean} immediate | ||||
|  * @return {*} | ||||
|  */ | ||||
| export function debounce(func, wait, immediate) { | ||||
|   let timeout, args, context, timestamp, result | ||||
|  | ||||
|   const later = function() { | ||||
|     // 据上一次触发时间间隔 | ||||
|     const last = +new Date() - timestamp | ||||
|  | ||||
|     // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait | ||||
|     if (last < wait && last > 0) { | ||||
|       timeout = setTimeout(later, wait - last) | ||||
|     } else { | ||||
|       timeout = null | ||||
|       // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 | ||||
|       if (!immediate) { | ||||
|         result = func.apply(context, args) | ||||
|         if (!timeout) context = args = null | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return function(...args) { | ||||
|     context = this | ||||
|     timestamp = +new Date() | ||||
|     const callNow = immediate && !timeout | ||||
|     // 如果延时不存在,重新设定延时 | ||||
|     if (!timeout) timeout = setTimeout(later, wait) | ||||
|     if (callNow) { | ||||
|       result = func.apply(context, args) | ||||
|       context = args = null | ||||
|     } | ||||
|  | ||||
|     return result | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This is just a simple version of deep copy | ||||
|  * Has a lot of edge cases bug | ||||
|  * If you want to use a perfect deep copy, use lodash's _.cloneDeep | ||||
|  * @param {Object} source | ||||
|  * @returns {Object} | ||||
|  */ | ||||
| export function deepClone(source) { | ||||
|   if (!source && typeof source !== 'object') { | ||||
|     throw new Error('error arguments', 'deepClone') | ||||
|   } | ||||
|   const targetObj = source.constructor === Array ? [] : {} | ||||
|   Object.keys(source).forEach(keys => { | ||||
|     if (source[keys] && typeof source[keys] === 'object') { | ||||
|       targetObj[keys] = deepClone(source[keys]) | ||||
|     } else { | ||||
|       targetObj[keys] = source[keys] | ||||
|     } | ||||
|   }) | ||||
|   return targetObj | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {Array} arr | ||||
|  * @returns {Array} | ||||
|  */ | ||||
| export function uniqueArr(arr) { | ||||
|   return Array.from(new Set(arr)) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @returns {string} | ||||
|  */ | ||||
| export function createUniqueString() { | ||||
|   const timestamp = +new Date() + '' | ||||
|   const randomNum = parseInt((1 + Math.random()) * 65536) + '' | ||||
|   return (+(randomNum + timestamp)).toString(32) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Check if an element has a class | ||||
|  * @param {HTMLElement} elm | ||||
|  * @param {string} cls | ||||
|  * @returns {boolean} | ||||
|  */ | ||||
| export function hasClass(ele, cls) { | ||||
|   return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Add class to element | ||||
|  * @param {HTMLElement} elm | ||||
|  * @param {string} cls | ||||
|  */ | ||||
| export function addClass(ele, cls) { | ||||
|   if (!hasClass(ele, cls)) ele.className += ' ' + cls | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Remove class from element | ||||
|  * @param {HTMLElement} elm | ||||
|  * @param {string} cls | ||||
|  */ | ||||
| export function removeClass(ele, cls) { | ||||
|   if (hasClass(ele, cls)) { | ||||
|     const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') | ||||
|     ele.className = ele.className.replace(reg, ' ') | ||||
|   } | ||||
| } | ||||
|  | ||||
| export function makeMap(str, expectsLowerCase) { | ||||
|   const map = Object.create(null) | ||||
|   const list = str.split(',') | ||||
|   for (let i = 0; i < list.length; i++) { | ||||
|     map[list[i]] = true | ||||
|   } | ||||
|   return expectsLowerCase | ||||
|     ? val => map[val.toLowerCase()] | ||||
|     : val => map[val] | ||||
| } | ||||
|   | ||||
| export const exportDefault = 'export default ' | ||||
|  | ||||
| export const beautifierConf = { | ||||
|   html: { | ||||
|     indent_size: '2', | ||||
|     indent_char: ' ', | ||||
|     max_preserve_newlines: '-1', | ||||
|     preserve_newlines: false, | ||||
|     keep_array_indentation: false, | ||||
|     break_chained_methods: false, | ||||
|     indent_scripts: 'separate', | ||||
|     brace_style: 'end-expand', | ||||
|     space_before_conditional: true, | ||||
|     unescape_strings: false, | ||||
|     jslint_happy: false, | ||||
|     end_with_newline: true, | ||||
|     wrap_line_length: '110', | ||||
|     indent_inner_html: true, | ||||
|     comma_first: false, | ||||
|     e4x: true, | ||||
|     indent_empty_lines: true | ||||
|   }, | ||||
|   js: { | ||||
|     indent_size: '2', | ||||
|     indent_char: ' ', | ||||
|     max_preserve_newlines: '-1', | ||||
|     preserve_newlines: false, | ||||
|     keep_array_indentation: false, | ||||
|     break_chained_methods: false, | ||||
|     indent_scripts: 'normal', | ||||
|     brace_style: 'end-expand', | ||||
|     space_before_conditional: true, | ||||
|     unescape_strings: false, | ||||
|     jslint_happy: true, | ||||
|     end_with_newline: true, | ||||
|     wrap_line_length: '110', | ||||
|     indent_inner_html: true, | ||||
|     comma_first: false, | ||||
|     e4x: true, | ||||
|     indent_empty_lines: true | ||||
|   } | ||||
| } | ||||
|  | ||||
| // 首字母大小 | ||||
| export function titleCase(str) { | ||||
|   return str.replace(/( |^)[a-z]/g, L => L.toUpperCase()) | ||||
| } | ||||
|  | ||||
| // 下划转驼峰 | ||||
| export function camelCase(str) { | ||||
|   return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase()) | ||||
| } | ||||
|  | ||||
| export function isNumberStr(str) { | ||||
|   return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) | ||||
| } | ||||
|   | ||||
							
								
								
									
										30
									
								
								src/utils/jsencrypt.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/utils/jsencrypt.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' | ||||
|  | ||||
| // 密钥对生成 http://web.chacuo.net/netrsakeypair | ||||
|  | ||||
| const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + | ||||
|   'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' | ||||
|  | ||||
| const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' + | ||||
|   '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' + | ||||
|   'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' + | ||||
|   'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' + | ||||
|   'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' + | ||||
|   'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' + | ||||
|   'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' + | ||||
|   'UP8iWi1Qw0Y=' | ||||
|  | ||||
| // 加密 | ||||
| export function encrypt(txt) { | ||||
|   const encryptor = new JSEncrypt() | ||||
|   encryptor.setPublicKey(publicKey) // 设置公钥 | ||||
|   return encryptor.encrypt(txt) // 对数据进行加密 | ||||
| } | ||||
|  | ||||
| // 解密 | ||||
| export function decrypt(txt) { | ||||
|   const encryptor = new JSEncrypt() | ||||
|   encryptor.setPrivateKey(privateKey) // 设置私钥 | ||||
|   return encryptor.decrypt(txt) // 对数据进行解密 | ||||
| } | ||||
|  | ||||
							
								
								
									
										51
									
								
								src/utils/permission.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/utils/permission.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| import useUserStore from '@/store/modules/user' | ||||
|  | ||||
| /** | ||||
|  * 字符权限校验 | ||||
|  * @param {Array} value 校验值 | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function checkPermi(value) { | ||||
|   if (value && value instanceof Array && value.length > 0) { | ||||
|     const permissions = useUserStore().permissions | ||||
|     const permissionDatas = value | ||||
|     const all_permission = "*:*:*"; | ||||
|  | ||||
|     const hasPermission = permissions.some(permission => { | ||||
|       return all_permission === permission || permissionDatas.includes(permission) | ||||
|     }) | ||||
|  | ||||
|     if (!hasPermission) { | ||||
|       return false | ||||
|     } | ||||
|     return true | ||||
|   } else { | ||||
|     console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) | ||||
|     return false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 角色权限校验 | ||||
|  * @param {Array} value 校验值 | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function checkRole(value) { | ||||
|   if (value && value instanceof Array && value.length > 0) { | ||||
|     const roles = useUserStore().roles | ||||
|     const permissionRoles = value | ||||
|     const super_admin = "admin"; | ||||
|  | ||||
|     const hasRole = roles.some(role => { | ||||
|       return super_admin === role || permissionRoles.includes(role) | ||||
|     }) | ||||
|  | ||||
|     if (!hasRole) { | ||||
|       return false | ||||
|     } | ||||
|     return true | ||||
|   } else { | ||||
|     console.error(`need roles! Like checkRole="['admin','editor']"`) | ||||
|     return false | ||||
|   } | ||||
| } | ||||
							
								
								
									
										148
									
								
								src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | ||||
| import axios from 'axios' | ||||
| import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus' | ||||
| import { getToken } from '@/utils/auth' | ||||
| import errorCode from '@/utils/errorCode' | ||||
| import { tansParams, blobValidate } from '@/utils/ruoyi' | ||||
| import cache from '@/plugins/cache' | ||||
| import { saveAs } from 'file-saver' | ||||
| import useUserStore from '@/store/modules/user' | ||||
|  | ||||
| let downloadLoadingInstance; | ||||
| // 是否显示重新登录 | ||||
| export let isRelogin = { show: false }; | ||||
|  | ||||
| axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' | ||||
| // 对应国际化资源文件后缀 | ||||
| axios.defaults.headers['Content-Language'] = 'zh_CN' | ||||
| // 创建axios实例 | ||||
| const service = axios.create({ | ||||
|   // axios中请求配置有baseURL选项,表示请求URL公共部分 | ||||
|   baseURL: import.meta.env.VITE_APP_BASE_API, | ||||
|   // 超时 | ||||
|   timeout: 10000 | ||||
| }) | ||||
|  | ||||
| // request拦截器 | ||||
| service.interceptors.request.use(config => { | ||||
|   // 是否需要设置 token | ||||
|   const isToken = (config.headers || {}).isToken === false | ||||
|   // 是否需要防止数据重复提交 | ||||
|   const isRepeatSubmit = (config.headers || {}).repeatSubmit === false | ||||
|   if (getToken() && !isToken) { | ||||
|     config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 | ||||
|   } | ||||
|   // 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 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 === 401) { | ||||
|       if (!isRelogin.show) { | ||||
|         isRelogin.show = true; | ||||
|         ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { | ||||
|           isRelogin.show = false; | ||||
|           useUserStore().logOut().then(() => { | ||||
|             location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index'; | ||||
|           }) | ||||
|       }).catch(() => { | ||||
|         isRelogin.show = false; | ||||
|       }); | ||||
|     } | ||||
|       return Promise.reject('无效的会话,或者会话已过期,请重新登录。') | ||||
|     } else 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 function download(url, params, filename, config) { | ||||
|   downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", }) | ||||
|   return service.post(url, params, { | ||||
|     transformRequest: [(params) => { return tansParams(params) }], | ||||
|     headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | ||||
|     responseType: 'blob', | ||||
|     ...config | ||||
|   }).then(async (data) => { | ||||
|     const isBlob = blobValidate(data); | ||||
|     if (isBlob) { | ||||
|       const blob = new Blob([data]) | ||||
|       saveAs(blob, filename) | ||||
|     } else { | ||||
|       const resText = await data.text(); | ||||
|       const rspObj = JSON.parse(resText); | ||||
|       const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] | ||||
|       ElMessage.error(errMsg); | ||||
|     } | ||||
|     downloadLoadingInstance.close(); | ||||
|   }).catch((r) => { | ||||
|     console.error(r) | ||||
|     ElMessage.error('下载文件出现错误,请联系管理员!') | ||||
|     downloadLoadingInstance.close(); | ||||
|   }) | ||||
| } | ||||
|  | ||||
| export default service | ||||
							
								
								
									
										246
									
								
								src/utils/ruoyi.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								src/utils/ruoyi.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,246 @@ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * 通用js方法封装处理 | ||||
|  * Copyright (c) 2019 ruoyi | ||||
|  */ | ||||
|  | ||||
| // 日期格式化 | ||||
| export function parseTime(time, pattern) { | ||||
|   if (arguments.length === 0 || !time) { | ||||
|     return null | ||||
|   } | ||||
|   const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' | ||||
|   let date | ||||
|   if (typeof time === 'object') { | ||||
|     date = time | ||||
|   } else { | ||||
|     if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { | ||||
|       time = parseInt(time) | ||||
|     } else if (typeof time === 'string') { | ||||
|       time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), ''); | ||||
|     } | ||||
|     if ((typeof time === 'number') && (time.toString().length === 10)) { | ||||
|       time = time * 1000 | ||||
|     } | ||||
|     date = new Date(time) | ||||
|   } | ||||
|   const formatObj = { | ||||
|     y: date.getFullYear(), | ||||
|     m: date.getMonth() + 1, | ||||
|     d: date.getDate(), | ||||
|     h: date.getHours(), | ||||
|     i: date.getMinutes(), | ||||
|     s: date.getSeconds(), | ||||
|     a: date.getDay() | ||||
|   } | ||||
|   const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { | ||||
|     let value = formatObj[key] | ||||
|     // Note: getDay() returns 0 on Sunday | ||||
|     if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } | ||||
|     if (result.length > 0 && value < 10) { | ||||
|       value = '0' + value | ||||
|     } | ||||
|     return value || 0 | ||||
|   }) | ||||
|   return time_str | ||||
| } | ||||
|  | ||||
| // 表单重置 | ||||
| export function resetForm(refName) { | ||||
|   if (this.$refs[refName]) { | ||||
|     this.$refs[refName].resetFields(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // 添加日期范围 | ||||
| export function addDateRange(params, dateRange, propName) { | ||||
|   let search = params; | ||||
|   search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}; | ||||
|   dateRange = Array.isArray(dateRange) ? dateRange : []; | ||||
|   if (typeof (propName) === 'undefined') { | ||||
|     search.params['beginTime'] = dateRange[0]; | ||||
|     search.params['endTime'] = dateRange[1]; | ||||
|   } else { | ||||
|     search.params['begin' + propName] = dateRange[0]; | ||||
|     search.params['end' + propName] = dateRange[1]; | ||||
|   } | ||||
|   return search; | ||||
| } | ||||
|  | ||||
| // 回显数据字典 | ||||
| export function selectDictLabel(datas, value) { | ||||
|   if (value === undefined) { | ||||
|     return ""; | ||||
|   } | ||||
|   var actions = []; | ||||
|   Object.keys(datas).some((key) => { | ||||
|     if (datas[key].value == ('' + value)) { | ||||
|       actions.push(datas[key].label); | ||||
|       return true; | ||||
|     } | ||||
|   }) | ||||
|   if (actions.length === 0) { | ||||
|     actions.push(value); | ||||
|   } | ||||
|   return actions.join(''); | ||||
| } | ||||
|  | ||||
| // 回显数据字典(字符串数组) | ||||
| export function selectDictLabels(datas, value, separator) { | ||||
|   if (value === undefined || value.length ===0) { | ||||
|     return ""; | ||||
|   } | ||||
|   if (Array.isArray(value)) { | ||||
|     value = value.join(","); | ||||
|   } | ||||
|   var actions = []; | ||||
|   var currentSeparator = undefined === separator ? "," : separator; | ||||
|   var temp = value.split(currentSeparator); | ||||
|   Object.keys(value.split(currentSeparator)).some((val) => { | ||||
|     var match = false; | ||||
|     Object.keys(datas).some((key) => { | ||||
|       if (datas[key].value == ('' + temp[val])) { | ||||
|         actions.push(datas[key].label + currentSeparator); | ||||
|         match = true; | ||||
|       } | ||||
|     }) | ||||
|     if (!match) { | ||||
|       actions.push(temp[val] + currentSeparator); | ||||
|     } | ||||
|   }) | ||||
|   return actions.join('').substring(0, actions.join('').length - 1); | ||||
| } | ||||
|  | ||||
| // 字符串格式化(%s ) | ||||
| export function sprintf(str) { | ||||
|   var args = arguments, flag = true, i = 1; | ||||
|   str = str.replace(/%s/g, function () { | ||||
|     var arg = args[i++]; | ||||
|     if (typeof arg === 'undefined') { | ||||
|       flag = false; | ||||
|       return ''; | ||||
|     } | ||||
|     return arg; | ||||
|   }); | ||||
|   return flag ? str : ''; | ||||
| } | ||||
|  | ||||
| // 转换字符串,undefined,null等转化为"" | ||||
| export function parseStrEmpty(str) { | ||||
|   if (!str || str == "undefined" || str == "null") { | ||||
|     return ""; | ||||
|   } | ||||
|   return str; | ||||
| } | ||||
|  | ||||
| // 数据合并 | ||||
| export function mergeRecursive(source, target) { | ||||
|   for (var p in target) { | ||||
|     try { | ||||
|       if (target[p].constructor == Object) { | ||||
|         source[p] = mergeRecursive(source[p], target[p]); | ||||
|       } else { | ||||
|         source[p] = target[p]; | ||||
|       } | ||||
|     } catch (e) { | ||||
|       source[p] = target[p]; | ||||
|     } | ||||
|   } | ||||
|   return source; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 构造树型结构数据 | ||||
|  * @param {*} data 数据源 | ||||
|  * @param {*} id id字段 默认 'id' | ||||
|  * @param {*} parentId 父节点字段 默认 'parentId' | ||||
|  * @param {*} children 孩子节点字段 默认 'children' | ||||
|  */ | ||||
| export function handleTree(data, id, parentId, children) { | ||||
|   let config = { | ||||
|     id: id || 'id', | ||||
|     parentId: parentId || 'parentId', | ||||
|     childrenList: children || 'children' | ||||
|   }; | ||||
|  | ||||
|   var childrenListMap = {}; | ||||
|   var nodeIds = {}; | ||||
|   var tree = []; | ||||
|  | ||||
|   for (let d of data) { | ||||
|     let parentId = d[config.parentId]; | ||||
|     if (childrenListMap[parentId] == null) { | ||||
|       childrenListMap[parentId] = []; | ||||
|     } | ||||
|     nodeIds[d[config.id]] = d; | ||||
|     childrenListMap[parentId].push(d); | ||||
|   } | ||||
|  | ||||
|   for (let d of data) { | ||||
|     let parentId = d[config.parentId]; | ||||
|     if (nodeIds[parentId] == null) { | ||||
|       tree.push(d); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (let t of tree) { | ||||
|     adaptToChildrenList(t); | ||||
|   } | ||||
|  | ||||
|   function adaptToChildrenList(o) { | ||||
|     if (childrenListMap[o[config.id]] !== null) { | ||||
|       o[config.childrenList] = childrenListMap[o[config.id]]; | ||||
|     } | ||||
|     if (o[config.childrenList]) { | ||||
|       for (let c of o[config.childrenList]) { | ||||
|         adaptToChildrenList(c); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return tree; | ||||
| } | ||||
|  | ||||
| /** | ||||
| * 参数处理 | ||||
| * @param {*} params  参数 | ||||
| */ | ||||
| export function tansParams(params) { | ||||
|   let result = '' | ||||
|   for (const propName of Object.keys(params)) { | ||||
|     const value = params[propName]; | ||||
|     var part = encodeURIComponent(propName) + "="; | ||||
|     if (value !== null && value !== "" && typeof (value) !== "undefined") { | ||||
|       if (typeof value === 'object') { | ||||
|         for (const key of Object.keys(value)) { | ||||
|           if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { | ||||
|             let params = propName + '[' + key + ']'; | ||||
|             var subPart = encodeURIComponent(params) + "="; | ||||
|             result += subPart + encodeURIComponent(value[key]) + "&"; | ||||
|           } | ||||
|         } | ||||
|       } else { | ||||
|         result += part + encodeURIComponent(value) + "&"; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return result | ||||
| } | ||||
|  | ||||
|  | ||||
| // 返回项目路径 | ||||
| export function getNormalPath(p) { | ||||
|   if (p.length === 0 || !p || p == 'undefined') { | ||||
|     return p | ||||
|   }; | ||||
|   let res = p.replace('//', '/') | ||||
|   if (res[res.length - 1] === '/') { | ||||
|     return res.slice(0, res.length - 1) | ||||
|   } | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| // 验证是否为blob格式 | ||||
| export function blobValidate(data) { | ||||
|   return data.type !== 'application/json' | ||||
| } | ||||
							
								
								
									
										58
									
								
								src/utils/scroll-to.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/utils/scroll-to.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| Math.easeInOutQuad = function(t, b, c, d) { | ||||
|   t /= d / 2 | ||||
|   if (t < 1) { | ||||
|     return c / 2 * t * t + b | ||||
|   } | ||||
|   t-- | ||||
|   return -c / 2 * (t * (t - 2) - 1) + b | ||||
| } | ||||
|  | ||||
| // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts | ||||
| var requestAnimFrame = (function() { | ||||
|   return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } | ||||
| })() | ||||
|  | ||||
| /** | ||||
|  * Because it's so fucking difficult to detect the scrolling element, just move them all | ||||
|  * @param {number} amount | ||||
|  */ | ||||
| function move(amount) { | ||||
|   document.documentElement.scrollTop = amount | ||||
|   document.body.parentNode.scrollTop = amount | ||||
|   document.body.scrollTop = amount | ||||
| } | ||||
|  | ||||
| function position() { | ||||
|   return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {number} to | ||||
|  * @param {number} duration | ||||
|  * @param {Function} callback | ||||
|  */ | ||||
| export function scrollTo(to, duration, callback) { | ||||
|   const start = position() | ||||
|   const change = to - start | ||||
|   const increment = 20 | ||||
|   let currentTime = 0 | ||||
|   duration = (typeof (duration) === 'undefined') ? 500 : duration | ||||
|   var animateScroll = function() { | ||||
|     // increment the time | ||||
|     currentTime += increment | ||||
|     // find the value with the quadratic in-out easing function | ||||
|     var val = Math.easeInOutQuad(currentTime, start, change, duration) | ||||
|     // move the document.body | ||||
|     move(val) | ||||
|     // do the animation unless its over | ||||
|     if (currentTime < duration) { | ||||
|       requestAnimFrame(animateScroll) | ||||
|     } else { | ||||
|       if (callback && typeof (callback) === 'function') { | ||||
|         // the animation is done so lets callback | ||||
|         callback() | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   animateScroll() | ||||
| } | ||||
							
								
								
									
										49
									
								
								src/utils/theme.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/utils/theme.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| // 处理主题样式 | ||||
| export function handleThemeStyle(theme) { | ||||
| 	document.documentElement.style.setProperty('--el-color-primary', theme) | ||||
| 	for (let i = 1; i <= 9; i++) { | ||||
| 		document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(theme, i / 10)}`) | ||||
| 	} | ||||
| 	for (let i = 1; i <= 9; i++) { | ||||
| 		document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // hex颜色转rgb颜色 | ||||
| export function hexToRgb(str) { | ||||
| 	str = str.replace('#', '') | ||||
| 	let hexs = str.match(/../g) | ||||
| 	for (let i = 0; i < 3; i++) { | ||||
| 		hexs[i] = parseInt(hexs[i], 16) | ||||
| 	} | ||||
| 	return hexs | ||||
| } | ||||
|  | ||||
| // rgb颜色转Hex颜色 | ||||
| export function rgbToHex(r, g, b) { | ||||
| 	let hexs = [r.toString(16), g.toString(16), b.toString(16)] | ||||
| 	for (let i = 0; i < 3; i++) { | ||||
| 		if (hexs[i].length == 1) { | ||||
| 			hexs[i] = `0${hexs[i]}` | ||||
| 		} | ||||
| 	} | ||||
| 	return `#${hexs.join('')}` | ||||
| } | ||||
|  | ||||
| // 变浅颜色值 | ||||
| export function getLightColor(color, level) { | ||||
| 	let rgb = hexToRgb(color) | ||||
| 	for (let i = 0; i < 3; i++) { | ||||
| 		rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]) | ||||
| 	} | ||||
| 	return rgbToHex(rgb[0], rgb[1], rgb[2]) | ||||
| } | ||||
|  | ||||
| // 变深颜色值 | ||||
| export function getDarkColor(color, level) { | ||||
| 	let rgb = hexToRgb(color) | ||||
| 	for (let i = 0; i < 3; i++) { | ||||
| 		rgb[i] = Math.floor(rgb[i] * (1 - level)) | ||||
| 	} | ||||
| 	return rgbToHex(rgb[0], rgb[1], rgb[2]) | ||||
| } | ||||
							
								
								
									
										93
									
								
								src/utils/validate.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/utils/validate.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| /** | ||||
|  * 判断url是否是http或https  | ||||
|  * @param {string} path | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
|  export function isHttp(url) { | ||||
|   return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1 | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 判断path是否为外链 | ||||
|  * @param {string} path | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
|  export function isExternal(path) { | ||||
|   return /^(https?:|mailto:|tel:)/.test(path) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} str | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function validUsername(str) { | ||||
|   const valid_map = ['admin', 'editor'] | ||||
|   return valid_map.indexOf(str.trim()) >= 0 | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} url | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function validURL(url) { | ||||
|   const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ | ||||
|   return reg.test(url) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} str | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function validLowerCase(str) { | ||||
|   const reg = /^[a-z]+$/ | ||||
|   return reg.test(str) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} str | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function validUpperCase(str) { | ||||
|   const reg = /^[A-Z]+$/ | ||||
|   return reg.test(str) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} str | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function validAlphabets(str) { | ||||
|   const reg = /^[A-Za-z]+$/ | ||||
|   return reg.test(str) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} email | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function validEmail(email) { | ||||
|   const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ | ||||
|   return reg.test(email) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {string} str | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function isString(str) { | ||||
|   if (typeof str === 'string' || str instanceof String) { | ||||
|     return true | ||||
|   } | ||||
|   return false | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @param {Array} arg | ||||
|  * @returns {Boolean} | ||||
|  */ | ||||
| export function isArray(arg) { | ||||
|   if (typeof Array.isArray === 'undefined') { | ||||
|     return Object.prototype.toString.call(arg) === '[object Array]' | ||||
|   } | ||||
|   return Array.isArray(arg) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 疯狂的狮子li
					疯狂的狮子li