491 lines
12 KiB
JavaScript
491 lines
12 KiB
JavaScript
|
|
/*
|
|||
|
|
* @Descripttion:
|
|||
|
|
* @Author: zenghua.wang
|
|||
|
|
* @Date: 2022-02-23 21:12:37
|
|||
|
|
* @LastEditors: wzh 1048523306@qq.com
|
|||
|
|
* @LastEditTime: 2024-12-17 11:55:31
|
|||
|
|
*/
|
|||
|
|
import dayjs from 'dayjs';
|
|||
|
|
|
|||
|
|
import { cloneDeep } from 'lodash';
|
|||
|
|
import { Base64 } from 'js-base64';
|
|||
|
|
import JsZip from 'jszip';
|
|||
|
|
import JsZipUtils from 'jszip-utils';
|
|||
|
|
import { saveAs } from 'file-saver';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @Title 防抖:指在一定时间内,多次触发同一个事件,只执行最后一次操作
|
|||
|
|
* @param {*} fn
|
|||
|
|
* @param {*} delay
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export function debounce(fn, delay) {
|
|||
|
|
let timer = null;
|
|||
|
|
return function (...args) {
|
|||
|
|
clearTimeout(timer);
|
|||
|
|
timer = setTimeout(() => {
|
|||
|
|
fn.apply(this, args);
|
|||
|
|
}, delay);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* @Title 节流:指在一定时间内,多次触发同一个事件,只执行第一次操作
|
|||
|
|
* @param {*} fn
|
|||
|
|
* @param {*} delay
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export function throttle(fn, delay) {
|
|||
|
|
let timer = null;
|
|||
|
|
return function (...args) {
|
|||
|
|
if (!timer) {
|
|||
|
|
timer = setTimeout(() => {
|
|||
|
|
fn.apply(this, args);
|
|||
|
|
timer = null;
|
|||
|
|
}, delay);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
/**
|
|||
|
|
* @Title 判断是否 empty,返回ture
|
|||
|
|
* @param {*} val:null 'null' undefined 'undefined' 0 '0' "" 返回true
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const isEmpty = (val) => {
|
|||
|
|
if (val && parseInt(val) === 0) return false;
|
|||
|
|
if (typeof val === 'undefined' || val === 'null' || val == null || val === 'undefined' || val === undefined || val === '') {
|
|||
|
|
return true;
|
|||
|
|
} else if (typeof val === 'object' && Object.keys(val).length === 0) {
|
|||
|
|
return true;
|
|||
|
|
} else if (val instanceof Array && val.length === 0) {
|
|||
|
|
return true;
|
|||
|
|
} else {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 深度拷贝对象
|
|||
|
|
* @param {*} obj
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const deepClone = (obj = {}) => {
|
|||
|
|
return cloneDeep(obj);
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 将number转换为px
|
|||
|
|
* @param {*} val
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const setPx = (val) => {
|
|||
|
|
if (isEmpty(val)) return '';
|
|||
|
|
return typeof val === 'number' ? `${val}px` : val;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 设置字典值
|
|||
|
|
* @param {*} columns
|
|||
|
|
* @param {*} key
|
|||
|
|
* @param {*} data
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const setDicData = (columns, key, data = []) => {
|
|||
|
|
if (isEmpty(data)) return;
|
|||
|
|
const len = columns.length;
|
|||
|
|
for (let i = 0; i < len; i++) {
|
|||
|
|
if (columns[i]?.prop === key) {
|
|||
|
|
columns[i]['dicData'] = data;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 求字段lable
|
|||
|
|
* @param {*} tree
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const setDicLabel = (dicData, value) => {
|
|||
|
|
let label = value;
|
|||
|
|
if (isEmpty(dicData)) return label;
|
|||
|
|
const len = dicData.length;
|
|||
|
|
for (let i = 0; i < len; i++) {
|
|||
|
|
if (dicData[i]?.value === value) {
|
|||
|
|
label = dicData[i].label;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return label;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 数组交集
|
|||
|
|
* @param {*} arr1
|
|||
|
|
* @param {*} arr2
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const intersectionArray = (arr1 = [], arr2 = []) => {
|
|||
|
|
return arr1.filter((item) => arr2.includes(item));
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 数组并集
|
|||
|
|
* @param {*} arr1
|
|||
|
|
* @param {*} arr2
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const unionArray = (arr1 = [], arr2 = []) => {
|
|||
|
|
return Array.from(new Set([...arr1, ...arr2]));
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 数组差集
|
|||
|
|
* @param {*} arr1
|
|||
|
|
* @param {*} arr2
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const differenceArray = (arr1 = [], arr2 = []) => {
|
|||
|
|
const s = new Set(arr2);
|
|||
|
|
return arr1.filter((x) => !s.has(x));
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 加密
|
|||
|
|
* @param {*} n
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const encode = (n, flag = false) => {
|
|||
|
|
if (flag) {
|
|||
|
|
return (
|
|||
|
|
((e) => {
|
|||
|
|
let t = e.length.toString();
|
|||
|
|
for (let n = 10 - t.length; n > 0; n--) t = '0' + t;
|
|||
|
|
return t;
|
|||
|
|
})(n) +
|
|||
|
|
((e) => {
|
|||
|
|
const t = Base64.encode(e).split('');
|
|||
|
|
for (let n = 0; n < Math.floor(e.length / 100 + 1); n++) t.splice(100 * n + 1, 0, 3);
|
|||
|
|
return t.join('');
|
|||
|
|
})(n)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
return n;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 解密
|
|||
|
|
* @param {*} e
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const decode = (e, flag = false) => {
|
|||
|
|
if (flag) {
|
|||
|
|
try {
|
|||
|
|
const t = Number(e.substr(0, 10));
|
|||
|
|
const n = e.substr(10).split('');
|
|||
|
|
for (let i = 0, s = 0; s < Math.floor(t / 100) + 1; s++) {
|
|||
|
|
n.splice(100 * s + 1 - i, 1);
|
|||
|
|
i++;
|
|||
|
|
}
|
|||
|
|
const o = Base64.decode(n.join(''));
|
|||
|
|
return o;
|
|||
|
|
} catch (error) {
|
|||
|
|
return e;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return e;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 图片转base64
|
|||
|
|
* @param {*} file
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const imageToBase64 = (file) => {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
const reader = new FileReader();
|
|||
|
|
reader.readAsDataURL(file);
|
|||
|
|
reader.onload = () => {
|
|||
|
|
resolve(reader.result);
|
|||
|
|
};
|
|||
|
|
reader.onerror = reject;
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title bufferToBase64
|
|||
|
|
* @param {*} buffer
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const bufferToBase64 = (buffer) => {
|
|||
|
|
return 'data:image/jpeg;base64,' + window.btoa(new Uint8Array(buffer).reduce((data, byte) => data + String.fromCharCode(byte), ''));
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title blob转json
|
|||
|
|
* @param {*} file
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const blobToJSON = (blob) => {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
const reader = new FileReader();
|
|||
|
|
reader.readAsText(blob, 'utf-8');
|
|||
|
|
reader.onload = () => {
|
|||
|
|
const res = !isEmpty(reader.result) ? JSON.parse(reader.result) : reader.result;
|
|||
|
|
resolve(res);
|
|||
|
|
};
|
|||
|
|
reader.onerror = reject;
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 将array转化为树
|
|||
|
|
* @param tree
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const getTree = (tree = []) => {
|
|||
|
|
tree.forEach((item) => {
|
|||
|
|
delete item.children;
|
|||
|
|
});
|
|||
|
|
const map = {};
|
|||
|
|
tree.forEach((item) => {
|
|||
|
|
map[item.id] = item;
|
|||
|
|
});
|
|||
|
|
const arr = [];
|
|||
|
|
tree.forEach((item) => {
|
|||
|
|
const parent = map[item.parentId];
|
|||
|
|
if (parent) {
|
|||
|
|
(parent.children || (parent.children = [])).push(item);
|
|||
|
|
} else {
|
|||
|
|
arr.push(item);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return arr;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 获取路由中的参数
|
|||
|
|
* @param name
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const getUrlQuery = (name) => {
|
|||
|
|
const url = window.location.href;
|
|||
|
|
const hash = url.substring(url.indexOf('#') + 1);
|
|||
|
|
const searchIndex = hash.indexOf('?');
|
|||
|
|
const search = searchIndex !== -1 ? hash.substring(searchIndex + 1) : '';
|
|||
|
|
const usp = new URLSearchParams(search);
|
|||
|
|
return usp.get(name);
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 将字符串url参数转换为Object
|
|||
|
|
* @param {*} url
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const param2Obj = (url) => {
|
|||
|
|
return (url) => Object.fromEntries(new URLSearchParams(url));
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 将Object参数转换为字符串
|
|||
|
|
* @param {*} json
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const obj2Param = (json) => {
|
|||
|
|
if (!json) return '';
|
|||
|
|
return Object.keys(json)
|
|||
|
|
.map((key) => {
|
|||
|
|
if (isEmpty(json[key])) return '';
|
|||
|
|
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]);
|
|||
|
|
})
|
|||
|
|
.join('&');
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 获取静态资源文件
|
|||
|
|
* @param {*} url
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const getAssetsFile = (url) => {
|
|||
|
|
return new URL(`../assets/images/${url}`, import.meta.url);
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* 文件下载
|
|||
|
|
* @param {*} url
|
|||
|
|
* @param {*} fileName
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const dowloadFile = async (options = { url: '', files: null, fileName: '' }) => {
|
|||
|
|
const { url, files, fileName } = options;
|
|||
|
|
const chunkSize = 1 * 1024 * 1024;
|
|||
|
|
const jszip = new JsZip();
|
|||
|
|
|
|||
|
|
function chunkFile(file, chunkSize) {
|
|||
|
|
let chunks = [];
|
|||
|
|
let fileSize = file.size;
|
|||
|
|
let currentPos = 0;
|
|||
|
|
while (currentPos < fileSize) {
|
|||
|
|
let endPos = currentPos + chunkSize;
|
|||
|
|
if (endPos > fileSize) {
|
|||
|
|
endPos = fileSize;
|
|||
|
|
}
|
|||
|
|
chunks.push(file.slice(currentPos, endPos));
|
|||
|
|
currentPos = endPos;
|
|||
|
|
}
|
|||
|
|
return chunks;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function dowloadLink(content, fileName) {
|
|||
|
|
const blob = new Blob([content]);
|
|||
|
|
if ('download' in document.createElement('a')) {
|
|||
|
|
const elink = document.createElement('a');
|
|||
|
|
elink.download = fileName;
|
|||
|
|
elink.style.display = 'none';
|
|||
|
|
elink.href = URL.createObjectURL(blob);
|
|||
|
|
document.body.appendChild(elink);
|
|||
|
|
elink.click();
|
|||
|
|
URL.revokeObjectURL(elink.href);
|
|||
|
|
document.body.removeChild(elink);
|
|||
|
|
} else {
|
|||
|
|
navigator.msSaveBlob(blob, fileName);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
if (!isEmpty(options?.url)) {
|
|||
|
|
JsZipUtils.getBinaryContent(url, (err, file) => {
|
|||
|
|
if (err) {
|
|||
|
|
return reject(err);
|
|||
|
|
}
|
|||
|
|
jszip
|
|||
|
|
.loadAsync(file)
|
|||
|
|
.then((zip) => {
|
|||
|
|
return zip.generateAsync({ type: 'blob' });
|
|||
|
|
})
|
|||
|
|
.then((blob) => {
|
|||
|
|
saveAs(blob, `${fileName}.zip`);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
// if (files.type === 'binary/octet-stream') {
|
|||
|
|
// dowloadLink(files, fileName);
|
|||
|
|
// return;
|
|||
|
|
// }
|
|||
|
|
let chunks = null;
|
|||
|
|
if (files.size > chunkSize) {
|
|||
|
|
chunks = chunkFile(files, chunkSize);
|
|||
|
|
}
|
|||
|
|
const fileType = files.type.split('/')[1];
|
|||
|
|
const newFile = files.type === 'binary/octet-stream' ? fileName : `${fileName}.${fileType}`;
|
|||
|
|
if (chunks) {
|
|||
|
|
let count = 1;
|
|||
|
|
chunks.forEach(function (chunk) {
|
|||
|
|
jszip.file(newFile, chunk, { binary: true });
|
|||
|
|
count++;
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
jszip.file(`${fileName}.${fileType}`, files, { binary: true });
|
|||
|
|
}
|
|||
|
|
jszip.generateAsync({ type: 'blob' }).then((blob) => {
|
|||
|
|
saveAs(blob, `${fileName}.zip`);
|
|||
|
|
resolve(true);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 模拟休眠
|
|||
|
|
* @param {*} duration
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const sleep = (duration = 0) =>
|
|||
|
|
new Promise((resolve) => {
|
|||
|
|
setTimeout(resolve, duration);
|
|||
|
|
});
|
|||
|
|
/**
|
|||
|
|
* @Title 创建id
|
|||
|
|
* @param {*} prefix
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const createId = (prefix) => {
|
|||
|
|
const val = Date.now() + Math.ceil(Math.random() * 99999);
|
|||
|
|
return isEmpty(prefix) ? val : prefix + '-' + val;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 生成数据
|
|||
|
|
* @param {*} duration
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const mockData = (item = {}, len = 1) => {
|
|||
|
|
const list = [];
|
|||
|
|
for (let i = 0; i < len; i++) {
|
|||
|
|
let temp = { ...item, id: createId() };
|
|||
|
|
list.push(temp);
|
|||
|
|
}
|
|||
|
|
return list;
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 日期格式化
|
|||
|
|
* @param {*} date
|
|||
|
|
* @param {*} format
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const dateFormat = (datetime, formater = 'YYYY-MM-DD hh:mm:ss') => {
|
|||
|
|
if (datetime instanceof Date || datetime) {
|
|||
|
|
return dayjs(datetime).format(formater);
|
|||
|
|
} else {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 字符串转日期
|
|||
|
|
* @param {*} str
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const toDate = (str) => {
|
|||
|
|
return !isEmpty(str) ? dayjs(str) : dayjs();
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title 字符串转日期
|
|||
|
|
* @param {*} str
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const getDate = (num, type, formater = 'YYYY-MM-DD', start = true) => {
|
|||
|
|
const date = dayjs().subtract(num, type);
|
|||
|
|
return start ? date.startOf(type).format(formater) : date.endOf(type).format(formater);
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title: 获取时间差
|
|||
|
|
* @param start
|
|||
|
|
* @param end
|
|||
|
|
* @param type
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const getDiffTime = (start, end, type) => {
|
|||
|
|
const startTime = dayjs(start);
|
|||
|
|
const endTime = dayjs(end);
|
|||
|
|
const duration = endTime.diff(startTime);
|
|||
|
|
let diff = 0;
|
|||
|
|
switch (type) {
|
|||
|
|
case 'DD': {
|
|||
|
|
diff = duration / (1000 * 60 * 60 * 24);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 'HH': {
|
|||
|
|
diff = duration / (1000 * 60 * 60);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
case 'mm': {
|
|||
|
|
diff = duration / (1000 * 60);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return Math.round(diff);
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title: 开始日期
|
|||
|
|
* @param last
|
|||
|
|
* @param type
|
|||
|
|
* @param formater
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const startDate = (num, type = 'month', formater = 'YYYY-MM-DD HH:mm:ss') => {
|
|||
|
|
if (num === 'now') return dayjs().format(formater);
|
|||
|
|
if (typeof num === 'string') return dayjs(num).startOf(type).format(formater);
|
|||
|
|
return num === 0 ? dayjs().startOf(type).format(formater) : dayjs().subtract(num, type).startOf(type).format(formater);
|
|||
|
|
};
|
|||
|
|
/**
|
|||
|
|
* @Title: 结束日期
|
|||
|
|
* @param num
|
|||
|
|
* @param type
|
|||
|
|
* @param formater
|
|||
|
|
* @returns
|
|||
|
|
*/
|
|||
|
|
export const endDate = (num = 0, type = 'month', formater = 'YYYY-MM-DD HH:mm:ss') => {
|
|||
|
|
if (num === 'now') return dayjs().format(formater);
|
|||
|
|
if (typeof num === 'string') return dayjs(num).endOf(type).format(formater);
|
|||
|
|
return num === 0 ? dayjs().endOf(type).format(formater) : dayjs().subtract(num, type).endOf(type).format(formater);
|
|||
|
|
};
|