import { isObject } from '@vue/shared'; import { cloneDeep } from 'lodash'; import type { RouteLocationNormalizedLoaded } from 'vue-router'; import { RouteLocationNormalized, useRoute } from 'vue-router'; import { watch } from 'vue'; import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'; import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading'; export function isExternal(path: string) { return /^(https?:|mailto:|tel:)/.test(path); } /** * @description 获取正确的路经 * @param {String} path 数据 */ export function getNormalPath(path: string) { if (path.length === 0 || !path || path == 'undefined') { return path; } const newPath = path.replace('//', '/'); const length = newPath.length; if (newPath[length - 1] === '/') { return newPath.slice(0, length - 1); } return newPath; } export const isEmpty = (value: unknown) => { return value == null && typeof value == 'undefined'; }; /** * @description对象格式化为Query语法 * @param { Object } params * @return {string} Query语法 */ export function objectToQuery(params: Record): string { let query = ''; for (const props of Object.keys(params)) { const value = params[props]; const part = encodeURIComponent(props) + '='; if (!isEmpty(value)) { if (isObject(value)) { for (const key of Object.keys(value)) { if (!isEmpty(value[key])) { const params = props + '[' + key + ']'; const subPart = encodeURIComponent(params) + '='; query += subPart + encodeURIComponent(value[key]) + '&'; } } } else { query += part + encodeURIComponent(value) + '&'; } } } return query.slice(0, -1); } export const addUnit = (value: string | number, unit = 'px') => { return !Object.is(Number(value), NaN) ? `${value}${unit}` : value; }; export function useWatchRoute(callback: (route: RouteLocationNormalizedLoaded) => void) { const route = useRoute(); watch( route, () => { callback(route); }, { immediate: true, }, ); return { route, }; } // declare type MessageType = '' | 'success' | 'warning' | 'info' | 'error'; export function confirm(msg: string, type: 'warning') { return ElMessageBox.confirm(msg, '温馨提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: type, }); } export function message(msg: string, type = 'success') { ElMessage[type](msg); } let loadingInstance = null; // 打开全局loading export function loading(msg: string) { loadingInstance = ElLoading.service({ lock: true, text: msg, }); } // 关闭全局loading export function closeLoading() { loadingInstance?.close(); } export const arrayToTree = ( data: any[], props = { id: 'id', parentId: 'pid', children: 'children' }, ) => { data = cloneDeep(data); const { id, parentId, children } = props; const result: any[] = []; const map = new Map(); data.forEach((item) => { map.set(item[id], item); const parent = map.get(item[parentId]); if (parent) { parent[children] = parent[children] ?? []; parent[children].push(item); } else { result.push(item); } }); return result; }; /** * @description 树转数组,队列实现广度优先遍历 * @param {Array} data 数据 * @param {Object} props `{ children: 'children' }` */ export const treeToArray = (data: any[], props = { children: 'children' }) => { data = cloneDeep(data); const { children } = props; const newData = []; const queue: any[] = []; data.forEach((child: any) => queue.push(child)); while (queue.length) { const item: any = queue.shift(); if (item[children]) { item[children].forEach((child: any) => queue.push(child)); delete item[children]; } newData.push(item); } return newData; }; /** * 数组转树型结构 */ export const buildTree = (array) => { const tree = {}; // 用于存储树形结构的临时对象 const result = []; // 最终的树形结构数组 array.forEach((item) => { tree[item.id] = { ...item, children: [] }; // 初始化树节点 }); array.forEach((item) => { if (item.parentId === 0) { result.push(tree[item.id]); // 根节点直接添加到结果数组 } else { tree[item.parentId].children.push(tree[item.id]); // 子节点添加到父节点的children数组 } }); return result; }; /*** * 递归查找 */ export const findTreeByPath = (tree, path, result = []) => { for (const node of tree) { if (node.path === path) { result.push(node); } if (node.children && node.children.length > 0) { findTreeByPath(node.children, path, result); } } return result; }; export const getComponentName = (route: RouteLocationNormalized) => { return route.matched[route.matched.length - 1]?.components?.default?.name; }; export function streamFileDownload(file: any, fileName = '文件名称.zip') { const blob = new Blob([file], { type: 'application/octet-stream;charset=UTF-8' }); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.style.display = 'none'; link.href = url; link.setAttribute('download', fileName); document.body.appendChild(link); link.click(); document.body.removeChild(link); // 下载完成移除元素 window.URL.revokeObjectURL(url); } export function filterName(list: any, value: any, key = 'value', label = 'label') { let name = ''; const child = list.find((item) => item[key] == value); name = child ? child[label] : ''; return name; } export function filterDatetime(value: any, format = 'yyyy-MM-dd') { if (value) { return dateFtt(format, new Date(parseInt(value))); } else { return ''; } } export function generateUUID() { if (typeof crypto === 'object') { if (typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') { const callback = (c: any) => { const num = Number(c); return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString( 16, ); }; return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback); } } let timestamp = new Date().getTime(); let performanceNow = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0; return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { let random = Math.random() * 16; if (timestamp > 0) { random = (timestamp + random) % 16 | 0; timestamp = Math.floor(timestamp / 16); } else { random = (performanceNow + random) % 16 | 0; performanceNow = Math.floor(performanceNow / 16); } return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16); }); } function dateFtt(fmt, date) { //author: meizz const o = { 'M+': date.getMonth() + 1, //月份 'd+': date.getDate(), //日 'h+': date.getHours(), //小时 'm+': date.getMinutes(), //分 's+': date.getSeconds(), //秒 'q+': Math.floor((date.getMonth() + 3) / 3), //季度 S: date.getMilliseconds(), //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); for (const k in o) if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace( RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length), ); return fmt; }