260 lines
7.8 KiB
TypeScript
260 lines
7.8 KiB
TypeScript
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, any>): 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: string = "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 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: string = "value", label: string = "label") {
|
|
let name = "";
|
|
let child = list.find(item => item[key] == value);
|
|
name = child ? child[label] : "";
|
|
return name;
|
|
}
|
|
|
|
export function filterDatetime(value: any, format: string = "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
|
|
var 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 (var 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;
|
|
}
|
|
|
|
|