2024-02-27 17:22:27 +08:00
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
import type { DataNode } from 'ant-design-vue/es/vc-tree-select/interface';
|
2024-03-22 16:47:44 +08:00
|
|
|
|
import { add, subtract, multiply, divide, bignumber, type BigNumber, format } from 'mathjs';
|
2024-02-27 17:22:27 +08:00
|
|
|
|
/**
|
|
|
|
|
* @description 处理首字母大写 abc => Abc
|
|
|
|
|
* @param str
|
|
|
|
|
*/
|
|
|
|
|
export const changeStr = (str: string) => {
|
|
|
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description 随机生成颜色
|
|
|
|
|
* @param {string} type
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
export const randomColor = (type: 'rgb' | 'hex' | 'hsl'): string => {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'rgb':
|
|
|
|
|
return window.crypto.getRandomValues(new Uint8Array(3)).toString();
|
|
|
|
|
case 'hex':
|
|
|
|
|
return `#${Math.floor(Math.random() * 0xffffff)
|
|
|
|
|
.toString(16)
|
|
|
|
|
.padStart(6, `${Math.random() * 10}`)}`;
|
|
|
|
|
case 'hsl':
|
|
|
|
|
// 在25-95%范围内具有饱和度,在85-95%范围内具有亮度
|
|
|
|
|
return [360 * Math.random(), `${100 * Math.random()}%`, `${100 * Math.random()}%`].toString();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 复制文本
|
|
|
|
|
* @param text
|
|
|
|
|
*/
|
|
|
|
|
export const copyText = (text: string) => {
|
|
|
|
|
const copyInput = document.createElement('input'); //创建一个input框获取需要复制的文本内容
|
|
|
|
|
copyInput.value = text;
|
|
|
|
|
document.body.appendChild(copyInput);
|
|
|
|
|
copyInput.select();
|
|
|
|
|
document.execCommand('copy');
|
|
|
|
|
copyInput.remove();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description 判断字符串是否是base64
|
|
|
|
|
* @param {string} str
|
|
|
|
|
*/
|
|
|
|
|
export const isBase64 = (str: string): boolean => {
|
|
|
|
|
if (str === '' || str.trim() === '') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
return btoa(atob(str)) == str;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// 对象转JSON
|
|
|
|
|
export const toJSON = (obj) => {
|
|
|
|
|
return JSON.stringify(obj, (_, value) => {
|
|
|
|
|
switch (true) {
|
|
|
|
|
case typeof value === 'undefined':
|
|
|
|
|
return 'undefined';
|
|
|
|
|
case typeof value === 'symbol':
|
|
|
|
|
return value.toString();
|
|
|
|
|
case typeof value === 'function':
|
|
|
|
|
return value.toString();
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* @description 是否是生产环境
|
|
|
|
|
*/
|
|
|
|
|
export const IS_PROD = import.meta.env.PROD;
|
|
|
|
|
export const IS_DEV = import.meta.env.DEV;
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* @description 格式化日期
|
|
|
|
|
* @param time
|
|
|
|
|
*/
|
|
|
|
|
export const formatDate = (time) => dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description 将一维数组转成树形结构数据
|
|
|
|
|
* @param items
|
|
|
|
|
* @param id
|
|
|
|
|
* @param link
|
|
|
|
|
*/
|
|
|
|
|
export const generateTree = (items, id = 0, link = 'parent') => {
|
|
|
|
|
return items
|
|
|
|
|
.filter((item) => item[link] == id)
|
|
|
|
|
.map((item) => ({
|
|
|
|
|
...item,
|
|
|
|
|
slots: { title: 'name' },
|
|
|
|
|
children: generateTree(items, item.departmentid),
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***
|
|
|
|
|
* @description 原生加密明文
|
|
|
|
|
* @param {string} plaintext
|
|
|
|
|
*/
|
|
|
|
|
// const encryption = (plaintext: string) =>
|
|
|
|
|
// isBase64(plaintext) ? plaintext : window.btoa(window.encodeURIComponent(plaintext));
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description 原生解密
|
|
|
|
|
* @param {string} ciphertext
|
|
|
|
|
*/
|
|
|
|
|
// const decryption = (ciphertext: string) =>
|
|
|
|
|
// isBase64(ciphertext) ? window.decodeURIComponent(window.atob(ciphertext)) : ciphertext;
|
|
|
|
|
|
|
|
|
|
// const viewsModules = import.meta.glob('../views/**/*.vue');
|
|
|
|
|
|
|
|
|
|
// /**
|
|
|
|
|
// *
|
|
|
|
|
// * @param {string} viewPath 页面的路径 `@/view/${viewPath}`
|
|
|
|
|
// * @param {string} viewFileName 页面文件 默认 index.vue
|
|
|
|
|
// */
|
|
|
|
|
// export const getAsyncPage = (viewPath: string, viewFileName = 'index') => {
|
|
|
|
|
// if (viewPath.endsWith('.vue')) {
|
|
|
|
|
// const p = `../views/${viewPath}`;
|
|
|
|
|
// const pathKey = Object.keys(viewsModules).find((key) => key === p)!;
|
|
|
|
|
// // console.log('viewsModules[pathKey]', viewsModules[pathKey]);
|
|
|
|
|
// return viewsModules[pathKey];
|
|
|
|
|
// } else {
|
|
|
|
|
// const p = `../views/${viewPath}/${viewFileName}.vue`;
|
|
|
|
|
// const pathKey = Object.keys(viewsModules).find((key) => key === p)!;
|
|
|
|
|
// // console.log('viewsModules[pathKey]', viewsModules[pathKey]);
|
|
|
|
|
// return viewsModules[pathKey];
|
|
|
|
|
// // return () => import(/* @vite-ignore */ `../views/${viewPath}/${viewFileName}.vue`);
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* / _ - 转换成驼峰并将view替换成空字符串
|
|
|
|
|
* @param {*} name name
|
|
|
|
|
*/
|
|
|
|
|
export const toHump = (name) => {
|
|
|
|
|
return name
|
|
|
|
|
.replace(/[-/_](\w)/g, (_, letter) => {
|
|
|
|
|
return letter.toUpperCase();
|
|
|
|
|
})
|
|
|
|
|
.replace('views', '');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** 模拟异步请求,实用性不高,主要用于demo模拟请求 */
|
|
|
|
|
export const waitTime = <T>(time = 100, data: any = true): Promise<T> => {
|
|
|
|
|
const { promise, resolve } = Promise.withResolvers<T>();
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
resolve(data);
|
|
|
|
|
}, time);
|
|
|
|
|
return promise;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function findPath<T extends Key>(
|
|
|
|
|
tree: Recordable[],
|
|
|
|
|
targetId: T,
|
|
|
|
|
field = 'id',
|
|
|
|
|
currentPath: T[] = [],
|
|
|
|
|
): T[] | null {
|
|
|
|
|
// 遍历树中的每个节点
|
|
|
|
|
for (const node of tree) {
|
|
|
|
|
// 将当前节点的 ID 添加到路径中
|
|
|
|
|
const path = [...currentPath, node[field]];
|
|
|
|
|
|
|
|
|
|
// 如果找到目标节点,返回路径
|
|
|
|
|
if (node.id === targetId) {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果当前节点有子节点,则递归查找子节点
|
|
|
|
|
if (node.children && node.children.length > 0) {
|
|
|
|
|
const childPath = findPath(node.children, targetId, field, path);
|
|
|
|
|
if (childPath) {
|
|
|
|
|
return childPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 没有找到目标节点,返回 null
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const str2tree = (str: string, treeData: DataNode[] = [], separator = ':') => {
|
|
|
|
|
return str.split(separator).reduce((prev, curr, currentIndex, arr) => {
|
|
|
|
|
const path = arr.slice(0, currentIndex + 1).join(':');
|
|
|
|
|
const index = prev.findIndex((item) => item?.path === path);
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
return prev[index].children;
|
|
|
|
|
} else {
|
|
|
|
|
const item: DataNode = {
|
|
|
|
|
// key: curr,
|
|
|
|
|
path,
|
|
|
|
|
value: curr,
|
|
|
|
|
label: curr,
|
|
|
|
|
children: [],
|
|
|
|
|
};
|
|
|
|
|
prev.push(item);
|
|
|
|
|
return item.children!;
|
|
|
|
|
}
|
|
|
|
|
}, treeData);
|
|
|
|
|
};
|
2024-03-22 16:47:44 +08:00
|
|
|
|
|
|
|
|
|
type CalclateOption = 'add' | 'subtract' | 'multiply' | 'divide';
|
|
|
|
|
export function calcNumber(
|
|
|
|
|
firstNumber: number,
|
|
|
|
|
secondNumber: number,
|
|
|
|
|
option: CalclateOption,
|
|
|
|
|
precision: number = 14,
|
|
|
|
|
): number {
|
|
|
|
|
let result: BigNumber;
|
|
|
|
|
switch (option) {
|
|
|
|
|
case 'add':
|
|
|
|
|
// 添加精度保留2位小数 add(bignumber(firstNumber), bignumber(secondNumber)).toNumber();
|
|
|
|
|
result = add(bignumber(firstNumber), bignumber(secondNumber));
|
|
|
|
|
break;
|
|
|
|
|
case 'subtract':
|
|
|
|
|
result = subtract(bignumber(firstNumber), bignumber(secondNumber));
|
|
|
|
|
break;
|
|
|
|
|
case 'multiply':
|
|
|
|
|
result = multiply(bignumber(firstNumber), bignumber(secondNumber)) as BigNumber;
|
|
|
|
|
break;
|
|
|
|
|
case 'divide':
|
|
|
|
|
result = divide(bignumber(firstNumber), bignumber(secondNumber)) as BigNumber;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return parseFloat(result.toFixed(precision));
|
|
|
|
|
}
|