// +--------------------------------------------------------------------- // | CRMEB [ CRMEB赋能开发者,助力企业发展 ] // +--------------------------------------------------------------------- // | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved. // +--------------------------------------------------------------------- // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 // +--------------------------------------------------------------------- // | Author: CRMEB Team // +--------------------------------------------------------------------- import Cookies from 'js-cookie' // cookie保存的天数 import config from '@/config' import { forEach, hasOneOf, objEqual } from '@/libs/tools' import { cloneDeep } from 'lodash' const { title, useI18n } = config // 设置setCookies; // setToken export const setCookies = (key, val, cookieExpires) => { Cookies.set(key, val, { expires: cookieExpires || 1 }) } // 获取getCookies; // getToken export const getCookies = (key) => { return Cookies.get(key) } export const removeCookies = (key) => { return Cookies.remove(key) } export const hasChild = (item) => { return item.children && item.children.length !== 0 } const showThisMenuEle = (item, access) => { if (item.meta && item.meta.access && item.meta.access.length) { if (hasOneOf(item.meta.access, access)) return true else return false } else return true } /** * @param {Array} list 通过路由列表得到菜单列表 * @returns {Array} */ export const getMenuByRouter = (list, access) => { let res = [] forEach(list, item => { if (!item.meta || (item.meta && !item.meta.hideInMenu)) { let obj = { icon: (item.meta && item.meta.icon) || '', name: item.name, meta: item.meta } if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) { obj.children = getMenuByRouter(item.children, access) } if (item.meta && item.meta.href) obj.href = item.meta.href if (showThisMenuEle(item, access)) res.push(obj) } }) return res } /** * @param {Array} routeMetched 当前路由metched * @returns {Array} */ export const getBreadCrumbList = (route, homeRoute) => { let homeItem = { ...homeRoute, icon: homeRoute.meta.icon } let routeMetched = route.matched if (routeMetched.some(item => item.name === homeRoute.name)) return [homeItem] let res = routeMetched.filter(item => { return item.meta === undefined || !item.meta.hideInBread }).map(item => { let meta = { ...item.meta } if (meta.title && typeof meta.title === 'function') { meta.__titleIsFunction__ = true meta.title = meta.title(route) } let obj = { icon: (item.meta && item.meta.icon) || '', name: item.name, meta: meta } return obj }) res = res.filter(item => { return !item.meta.hideInMenu }) return [{ ...homeItem, to: homeRoute.path }, ...res] } export const getRouteTitleHandled = (route) => { let router = { ...route } let meta = { ...route.meta } let title = '' if (meta.title) { if (typeof meta.title === 'function') { meta.__titleIsFunction__ = true title = meta.title(router) } else title = meta.title } meta.title = title router.meta = meta return router } export const showTitle = (item, vm) => { let { title, __titleIsFunction__ } = item.meta if (!title) return if (useI18n) { if (title.includes('{{') && title.includes('}}') && useI18n) title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim()))) else if (__titleIsFunction__) title = item.meta.title else title = vm.$t(item.name) } else title = (item.meta && item.meta.title) || item.name return title } /** * @description 本地存储和获取标签导航列表 */ export const setTagNavListInLocalstorage = list => { localStorage.tagNaveList = JSON.stringify(list) } /** * @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项 */ export const getTagNavListFromLocalstorage = () => { const list = localStorage.tagNaveList return list ? JSON.parse(list) : [] } /** * @param {Array} routers 路由列表数组 * @description 用于找到路由列表中name为home的对象 */ export const getHomeRoute = (routers, homeName = 'home') => { let i = -1 let len = routers.length let homeRoute = {} while (++i < len) { let item = routers[i] if (item.children && item.children.length) { let res = getHomeRoute(item.children, homeName) if (res.name) return res } else { if (item.name === homeName) homeRoute = item } } return homeRoute } /** * @param {*} list 现有标签导航列表 * @param {*} newRoute 新添加的路由原信息对象 * @description 如果该newRoute已经存在则不再添加 */ export const getNewTagList = (list, newRoute) => { const { name, path, meta } = newRoute let newList = [...list] if (newList.findIndex(item => item.name === name) >= 0) return newList else newList.push({ name, path, meta }) return newList } /** * @param {*} access 用户权限数组,如 ['super_admin', 'admin'] * @param {*} route 路由列表 */ const hasAccess = (access, route) => { if (route.meta && route.meta.access) return hasOneOf(access, route.meta.access) else return true } /** * 权鉴 * @param {*} name 即将跳转的路由name * @param {*} access 用户权限数组 * @param {*} routes 路由列表 * @description 用户是否可跳转到该页 */ export const canTurnTo = (name, access, routes) => { const routePermissionJudge = (list) => { return list.some(item => { if (item.children && item.children.length) { return routePermissionJudge(item.children) } else if (item.name === name) { return hasAccess(access, item) } }) } return routePermissionJudge(routes) } /** * @param {String} url * @description 从URL中解析参数 */ export const getParams = url => { const keyValueArr = url.split('?')[1].split('&') let paramObj = {} keyValueArr.forEach(item => { const keyValue = item.split('=') paramObj[keyValue[0]] = keyValue[1] }) return paramObj } /** * @param {Array} list 标签列表 * @param {String} name 当前关闭的标签的name */ export const getNextRoute = (list, route) => { let res = {} if (list.length === 2) { res = getHomeRoute(list) } else { const index = list.findIndex(item => routeEqual(item, route)) if (index === list.length - 1) res = list[list.length - 2] else res = list[index + 1] } return res } /** * @param {Number} times 回调函数需要执行的次数 * @param {Function} callback 回调函数 */ export const doCustomTimes = (times, callback) => { let i = -1 while (++i < times) { callback(i) } } /** * @param {Object} file 从上传组件得到的文件对象 * @returns {Promise} resolve参数是解析后的二维数组 * @description 从Csv文件中解析出表格,解析成二维数组 */ export const getArrayFromFile = (file) => { let nameSplit = file.name.split('.') let format = nameSplit[nameSplit.length - 1] return new Promise((resolve, reject) => { let reader = new FileReader() reader.readAsText(file) // 以文本格式读取 let arr = [] reader.onload = function (evt) { let data = evt.target.result // 读到的数据 let pasteData = data.trim() arr = pasteData.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(row => { return row.split('\t') }).map(item => { return item[0].split(',') }) if (format === 'csv') resolve(arr) else reject(new Error('[Format Error]:你上传的不是Csv文件')) } }) } /** * @param {Array} array 表格数据二维数组 * @returns {Object} { columns, tableData } * @description 从二维数组中获取表头和表格数据,将第一行作为表头,用于在iView的表格中展示数据 */ export const getTableDataFromArray = (array) => { let columns = [] let tableData = [] if (array.length > 1) { let titles = array.shift() columns = titles.map(item => { return { title: item, key: item } }) tableData = array.map(item => { let res = {} item.forEach((col, i) => { res[titles[i]] = col }) return res }) } return { columns, tableData } } export const findNodeUpper = (ele, tag) => { if (ele.parentNode) { if (ele.parentNode.tagName === tag.toUpperCase()) { return ele.parentNode } else { return findNodeUpper(ele.parentNode, tag) } } } export const findNodeUpperByClasses = (ele, classes) => { let parentNode = ele.parentNode if (parentNode) { let classList = parentNode.classList if (classList && classes.every(className => classList.contains(className))) { return parentNode } else { return findNodeUpperByClasses(parentNode, classes) } } } export const findNodeDownward = (ele, tag) => { const tagName = tag.toUpperCase() if (ele.childNodes.length) { let i = -1 let len = ele.childNodes.length while (++i < len) { let child = ele.childNodes[i] if (child.tagName === tagName) return child else return findNodeDownward(child, tag) } } } export const showByAccess = (access, canViewAccess) => { return hasOneOf(canViewAccess, access) } /** * @description 根据name/params/query判断两个路由对象是否相等 * @param {*} route1 路由对象 * @param {*} route2 路由对象 */ export const routeEqual = (route1, route2) => { const params1 = route1.params || {} const params2 = route2.params || {} const query1 = route1.query || {} const query2 = route2.query || {} return (route1.name === route2.name) && objEqual(params1, params2) && objEqual(query1, query2) } /** * 判断打开的标签列表里是否已存在这个新添加的路由对象 */ export const routeHasExist = (tagNavList, routeItem) => { let len = tagNavList.length let res = false doCustomTimes(len, (index) => { if (routeEqual(tagNavList[index], routeItem)) res = true }) return res } export const localSave = (key, value) => { localStorage.setItem(key, value) } export const localRead = (key) => { return localStorage.getItem(key) || '' } // scrollTop animation export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => { if (!window.requestAnimationFrame) { window.requestAnimationFrame = ( window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { return window.setTimeout(callback, 1000 / 60) } ) } const difference = Math.abs(from - to) const step = Math.ceil(difference / duration * 50) const scroll = (start, end, step) => { if (start === end) { endCallback && endCallback() return } let d = (start + step > end) ? end : start + step if (start > end) { d = (start - step < end) ? end : start - step } if (el === window) { window.scrollTo(d, d) } else { el.scrollTop = d } window.requestAnimationFrame(() => scroll(d, end, step)) } scroll(from, to, step) } /** * @description 根据当前跳转的路由设置显示在浏览器标签的title * @param {Object} routeItem 路由对象 * @param {Object} vm Vue实例 */ export const setTitle = (routeItem, vm) => { const handledRoute = getRouteTitleHandled(routeItem) const pageTitle = showTitle(handledRoute, vm) const resTitle = pageTitle ? `${title} - ${pageTitle}` : title window.document.title = resTitle } export const R = (menuList, newOpenMenus) => { menuList.forEach(item => { let newMenu = {} for (let i in item) { if (i !== 'children') newMenu[i] = cloneDeep(item[i]) } newOpenMenus.push(newMenu) item.children && R(item.children, newOpenMenus) }) return newOpenMenus } export function getMenuopen (to, menuList) { const allMenus = [] menuList.forEach(menu => { const menus = transMenu(menu, []) allMenus.push({ path: menu.path, openNames: [] }) menus.forEach(item => allMenus.push(item)) }) const currentMenu = allMenus.find(item => item.path === to.path) return currentMenu ? currentMenu.openNames : [] } function transMenu (menu, openNames) { if (menu.children && menu.children.length) { const itemOpenNames = openNames.concat([menu.path]) return menu.children.reduce((all, item) => { all.push({ path: item.path, openNames: itemOpenNames }) const foundChildren = transMenu(item, itemOpenNames) return all.concat(foundChildren) }, []) } else { return [menu].map(item => { return { path: item.path, openNames: openNames } }) } } export function wss (wsSocketUrl) { let ishttps = document.location.protocol == 'https:'; if (ishttps) { return wsSocketUrl.replace('ws:', 'wss:'); } else { return wsSocketUrl.replace('wss:', 'ws:'); } }