settledIn/src/utils/util.js

593 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Cookies from "js-cookie";
// cookie保存的天数
import { forEach, hasOneOf, objEqual } from "@/libs/tools";
import { cloneDeep } from "lodash";
const title = "";
// 设置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);
};
// 保留两位小数;
// num
export function toFixedNoRounding(num) {
return Math.floor(num * 100) / 100;
}
/**
* 从cookie中移除指定的键值对
* @param {string} key - 要移除的键名
* @returns {boolean} - 移除成功返回true否则返回false
*/
export const removeCookies = key => {
return Cookies.remove(key);
};
/**
* 判断一个菜单项是否有子菜单
* @param {object} item - 菜单项对象
* @returns {boolean} - 有子菜单返回true否则返回false
*/
export const hasChild = item => {
return item.children && item.children.length !== 0;
};
/**
* 判断当前用户是否有权限访问该菜单项
* @param {object} item - 菜单项对象
* @param {array} access - 用户拥有的权限列表
* @returns {boolean} - 有权限返回true否则返回false
*/
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) => {
console.log(homeRoute);
let homeItem = {
...homeRoute
};
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];
};
/**
* 获取处理后的路由标题
* @param {Object} route - 路由对象
* @returns {Object} - 处理后的路由对象
*/
export const getRouteTitleHandled = route => {
// 克隆路由对象和元数据对象
let router = { ...route };
let meta = { ...route.meta };
let title = "";
// 判断元数据对象中是否存在标题属性
if (meta.title) {
// 如果标题属性是函数类型则调用该函数并将结果赋值给title
if (typeof meta.title === "function") {
meta.__titleIsFunction__ = true;
title = meta.title(router);
} else title = meta.title;
}
// 将处理后的标题赋值给元数据对象中的title属性
meta.title = title;
// 将处理后的元数据对象赋值给路由对象中的meta属性
router.meta = meta;
// 返回处理后的路由对象
return router;
};
/**
* 显示路由标题
* @param {Object} item - 当前路由对象
* @param {Object} vm - Vue实例对象
* @returns {string|undefined} - 返回路由标题字符串或undefined
*/
export const showTitle = (item, vm) => {
// 从路由元数据中获取标题和标题是否为函数的标志
let { title, __titleIsFunction__ } = item.meta;
// 如果没有标题则直接返回
if (!title) return;
// 如果标题不存在,则从路由对象中获取名称作为标题
title = (item.meta && item.meta.title) || item.name;
// 返回标题字符串
return title;
};
/**
* @description 本地存储和获取标签导航列表
*/
export const setTagNavListInLocalstorage = list => {
localStorage.setItem("tagNaveList", JSON.stringify(list));
};
/**
* @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
*/
export const getTagNavListFromLocalstorage = () => {
const list = localStorage.getItem("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.path === path) >= 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 从二维数组中获取表头和表格数据,将第一行作为表头,用于在表格中展示数据
*/
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
};
};
/**
* 查找元素的上一个指定标签名的父节点
* @param {Element} ele - 要查找的元素
* @param {string} tag - 指定的标签名
* @returns {Element|undefined} - 返回找到的父节点或 undefined
*/
export const findNodeUpper = (ele, tag) => {
// 如果元素存在父节点
if (ele.parentNode) {
// 如果父节点的标签名与指定标签名相同
if (ele.parentNode.tagName === tag.toUpperCase()) {
// 返回父节点
return ele.parentNode;
} else {
// 递归查找父节点的父节点
return findNodeUpper(ele.parentNode, tag);
}
}
};
/**
* 根据类名查找元素的上级节点
* @param {HTMLElement} ele - 目标元素
* @param {string[]} classes - 目标类名数组
* @returns {HTMLElement|null} - 返回符合条件的上级节点,若不存在则返回 null
*/
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);
}
}
};
/**
* 从当前元素向下查找指定标签名的子元素
* @param {HTMLElement} ele - 当前元素
* @param {string} tag - 目标标签名
* @returns {HTMLElement|undefined} - 返回找到的子元素或 undefined
*/
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);
}
}
};
/**
* 根据用户权限判断是否可以查看某个页面或操作
* @param {Array} access - 当前用户的权限数组
* @param {Array} canViewAccess - 可以查看的权限数组
* @returns {Boolean} - 是否可以查看
*/
export const showByAccess = (access, canViewAccess) => {
// 调用 hasOneOf 函数判断当前用户是否有查看权限
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) => {
let winTitle = localStorage.getItem("ADMIN_TITLE") || title;
const handledRoute = getRouteTitleHandled(routeItem);
const pageTitle = showTitle(handledRoute, vm);
const resTitle = pageTitle ? `${winTitle} - ${pageTitle}` : winTitle;
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;
};
/**
* 获取当前菜单打开状态
* @param {Object} to - 当前路由对象
* @param {Array} menuList - 菜单列表
* @returns {Array} - 当前菜单打开状态数组
*/
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 : [];
}
/**
* 将菜单转换为可展开的形式
* @param {Object} menu - 菜单对象
* @param {Array} openNames - 已打开的菜单路径数组
* @returns {Array} - 可展开的菜单数组
*/
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:");
}
}