|
|
|
@ -139,7 +139,6 @@ export function formatPercent(number) {
|
|
|
|
|
return Math.round(number * 100) + "%";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ! 不支持计算 Set 或 Map
|
|
|
|
|
* @param {*} val
|
|
|
|
@ -154,14 +153,14 @@ export function isEmpty(val) {
|
|
|
|
|
/**
|
|
|
|
|
* 数组排序
|
|
|
|
|
*/
|
|
|
|
|
export const sortBy = (key) => {
|
|
|
|
|
export const sortBy = key => {
|
|
|
|
|
return (a, b) => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Object排序keys
|
|
|
|
|
*/
|
|
|
|
|
export const sortKeys = (obj) =>
|
|
|
|
|
export const sortKeys = obj =>
|
|
|
|
|
Object.keys(obj)
|
|
|
|
|
.sort()
|
|
|
|
|
.reduce((a, k2) => ({ ...a, [k2]: obj[k2] }), {});
|
|
|
|
@ -182,7 +181,7 @@ export const sortArrayByOrder = (items, keyName, keyOrder) => {
|
|
|
|
|
* 合并Object, 递归地
|
|
|
|
|
*/
|
|
|
|
|
export function merge(...objects) {
|
|
|
|
|
const isDeep = objects.some((obj) => obj !== null && typeof obj === 'object');
|
|
|
|
|
const isDeep = objects.some(obj => obj !== null && typeof obj === "object");
|
|
|
|
|
|
|
|
|
|
const result = objects[0] || (isDeep ? {} : objects[0]);
|
|
|
|
|
|
|
|
|
@ -191,19 +190,19 @@ export function merge(...objects) {
|
|
|
|
|
|
|
|
|
|
if (!obj) continue;
|
|
|
|
|
|
|
|
|
|
Object.keys(obj).forEach((key) => {
|
|
|
|
|
Object.keys(obj).forEach(key => {
|
|
|
|
|
const val = obj[key];
|
|
|
|
|
|
|
|
|
|
if (isDeep) {
|
|
|
|
|
if (Array.isArray(val)) {
|
|
|
|
|
result[key] = [].concat(Array.isArray(result[key]) ? result[key] : [result[key]], val);
|
|
|
|
|
} else if (typeof val === 'object') {
|
|
|
|
|
} else if (typeof val === "object") {
|
|
|
|
|
result[key] = merge(result[key], val);
|
|
|
|
|
} else {
|
|
|
|
|
result[key] = val;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result[key] = typeof val === 'boolean' ? val : result[key];
|
|
|
|
|
result[key] = typeof val === "boolean" ? val : result[key];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -218,7 +217,7 @@ export function merge(...objects) {
|
|
|
|
|
*/
|
|
|
|
|
export function groupBy(array = [], callback) {
|
|
|
|
|
return array.reduce((groups, item) => {
|
|
|
|
|
const key = typeof callback === 'function' ? callback(item) : item[callback];
|
|
|
|
|
const key = typeof callback === "function" ? callback(item) : item[callback];
|
|
|
|
|
|
|
|
|
|
if (!groups[key]) {
|
|
|
|
|
groups[key] = [];
|
|
|
|
@ -258,7 +257,7 @@ export function omit(object, keysToOmit) {
|
|
|
|
|
*/
|
|
|
|
|
export function cloneDeep(value) {
|
|
|
|
|
// return structuredClone(value);
|
|
|
|
|
if (typeof value !== 'object' || value === null) {
|
|
|
|
|
if (typeof value !== "object" || value === null) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -315,20 +314,20 @@ export const fixToInt = curriedFix(0);
|
|
|
|
|
export function objectMapper(input, keyMap) {
|
|
|
|
|
// Loop through array mapping
|
|
|
|
|
if (Array.isArray(input)) {
|
|
|
|
|
return input.map((obj) => objectMapper(obj, keyMap));
|
|
|
|
|
return input.map(obj => objectMapper(obj, keyMap));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof input === 'object') {
|
|
|
|
|
if (typeof input === "object") {
|
|
|
|
|
const mappedObj = {};
|
|
|
|
|
|
|
|
|
|
Object.keys(input).forEach((key) => {
|
|
|
|
|
Object.keys(input).forEach(key => {
|
|
|
|
|
// Keep original keys not in keyMap
|
|
|
|
|
if (!keyMap[key]) {
|
|
|
|
|
mappedObj[key] = input[key];
|
|
|
|
|
}
|
|
|
|
|
// Handle array of maps
|
|
|
|
|
if (Array.isArray(keyMap[key])) {
|
|
|
|
|
keyMap[key].forEach((map) => {
|
|
|
|
|
keyMap[key].forEach(map => {
|
|
|
|
|
let value = input[key];
|
|
|
|
|
if (map.transform) value = map.transform(value);
|
|
|
|
|
mappedObj[map.key] = value;
|
|
|
|
@ -358,14 +357,14 @@ export function at(obj, path) {
|
|
|
|
|
let result;
|
|
|
|
|
if (Array.isArray(obj)) {
|
|
|
|
|
// array case
|
|
|
|
|
const indexes = path.split('.').map((i) => parseInt(i));
|
|
|
|
|
const indexes = path.split(".").map(i => parseInt(i));
|
|
|
|
|
result = [];
|
|
|
|
|
for (let i = 0; i < indexes.length; i++) {
|
|
|
|
|
result.push(obj[indexes[i]]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// object case
|
|
|
|
|
const indexes = path.split('.').map((i) => i);
|
|
|
|
|
const indexes = path.split(".").map(i => i);
|
|
|
|
|
result = [obj];
|
|
|
|
|
for (let i = 0; i < indexes.length; i++) {
|
|
|
|
|
result = [result[0][indexes[i]]];
|
|
|
|
@ -392,7 +391,7 @@ export function flush(collection) {
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
if (typeof collection === 'object') {
|
|
|
|
|
if (typeof collection === "object") {
|
|
|
|
|
result = {};
|
|
|
|
|
const keys = Object.keys(collection);
|
|
|
|
|
len = keys.length;
|
|
|
|
@ -411,7 +410,7 @@ export function flush(collection) {
|
|
|
|
|
/**
|
|
|
|
|
* 千分位 格式化数字
|
|
|
|
|
*/
|
|
|
|
|
export const numberFormatter = (number) => {
|
|
|
|
|
export const numberFormatter = number => {
|
|
|
|
|
return new Intl.NumberFormat().format(number);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -431,30 +430,30 @@ export const getNestedValue = (obj, keyArr) => {
|
|
|
|
|
/**
|
|
|
|
|
* 计算笛卡尔积
|
|
|
|
|
*/
|
|
|
|
|
export const cartesianProductArray = (arr, sep = '_', index = 0, prefix = '') => {
|
|
|
|
|
export const cartesianProductArray = (arr, sep = "_", index = 0, prefix = "") => {
|
|
|
|
|
let result = [];
|
|
|
|
|
if (index === arr.length) {
|
|
|
|
|
return [prefix];
|
|
|
|
|
}
|
|
|
|
|
arr[index].forEach((item) => {
|
|
|
|
|
arr[index].forEach(item => {
|
|
|
|
|
result = result.concat(cartesianProductArray(arr, sep, index + 1, prefix ? `${prefix}${sep}${item}` : `${item}`));
|
|
|
|
|
});
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const stringToColour = (str) => {
|
|
|
|
|
var hash = 0
|
|
|
|
|
export const stringToColour = str => {
|
|
|
|
|
var hash = 0;
|
|
|
|
|
for (let i = 0; i < str.length; i++) {
|
|
|
|
|
hash = str.charCodeAt(i) + ((hash << 5) - hash)
|
|
|
|
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
|
|
|
}
|
|
|
|
|
var colour = '#'
|
|
|
|
|
var colour = "#";
|
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
|
var value = (hash >> (i * 8)) & 0xff
|
|
|
|
|
value = (value % 150) + 50
|
|
|
|
|
colour += ('00' + value.toString(16)).substr(-2)
|
|
|
|
|
}
|
|
|
|
|
return colour
|
|
|
|
|
var value = (hash >> (i * 8)) & 0xff;
|
|
|
|
|
value = (value % 150) + 50;
|
|
|
|
|
colour += ("00" + value.toString(16)).substr(-2);
|
|
|
|
|
}
|
|
|
|
|
return colour;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const debounce = (func, wait, immediate) => {
|
|
|
|
|
var timeout;
|
|
|
|
@ -468,44 +467,41 @@ export const debounce = (func, wait, immediate) => {
|
|
|
|
|
if (!immediate) func.apply(context, args);
|
|
|
|
|
}, wait);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const removeFormattingChars = (str) => {
|
|
|
|
|
export const removeFormattingChars = str => {
|
|
|
|
|
const regex = /[\r\n\t\v\f]/g;
|
|
|
|
|
str = str.replace(regex, ' ');
|
|
|
|
|
str = str.replace(regex, " ");
|
|
|
|
|
// Replace more than four consecutive spaces with a single space
|
|
|
|
|
str = str.replace(/\s{4,}/g, ' ');
|
|
|
|
|
str = str.replace(/\s{4,}/g, " ");
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const olog = (text, ...args) => {
|
|
|
|
|
console.log(
|
|
|
|
|
`%c ${text} `,
|
|
|
|
|
'background:#fb923c ; padding: 1px; border-radius: 3px; color: #fff',...args
|
|
|
|
|
);
|
|
|
|
|
console.log(`%c ${text} `, "background:#fb923c ; padding: 1px; border-radius: 3px; color: #fff", ...args);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const sanitizeFilename = (str) => {
|
|
|
|
|
export const sanitizeFilename = str => {
|
|
|
|
|
// Remove whitespace and replace with hyphens
|
|
|
|
|
str = str.replace(/\s+/g, '-');
|
|
|
|
|
str = str.replace(/\s+/g, "-");
|
|
|
|
|
// Remove invalid characters and replace with hyphens
|
|
|
|
|
str = str.replace(/[^a-zA-Z0-9.-]/g, '-');
|
|
|
|
|
str = str.replace(/[^a-zA-Z0-9.-]/g, "-");
|
|
|
|
|
// Replace consecutive hyphens with a single hyphen
|
|
|
|
|
str = str.replace(/-+/g, '-');
|
|
|
|
|
str = str.replace(/-+/g, "-");
|
|
|
|
|
// Trim leading and trailing hyphens
|
|
|
|
|
str = str.replace(/^-+|-+$/g, '');
|
|
|
|
|
str = str.replace(/^-+|-+$/g, "");
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const formatBytes = (bytes, decimals = 2) => {
|
|
|
|
|
if (bytes === 0) return '';
|
|
|
|
|
if (bytes === 0) return "";
|
|
|
|
|
|
|
|
|
|
const k = 1024;
|
|
|
|
|
const dm = decimals < 0 ? 0 : decimals;
|
|
|
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
|
|
|
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
|
|
|
|
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
|
|
|
|
};
|
|
|
|
|
export const calcCacheSizes = async () => {
|
|
|
|
|
try {
|
|
|
|
@ -514,14 +510,14 @@ export const calcCacheSizes = async () => {
|
|
|
|
|
let indexedDBSize = 0;
|
|
|
|
|
|
|
|
|
|
// 1. Get the service worker cache size
|
|
|
|
|
if ('caches' in window) {
|
|
|
|
|
if ("caches" in window) {
|
|
|
|
|
const cacheNames = await caches.keys();
|
|
|
|
|
for (const name of cacheNames) {
|
|
|
|
|
const cache = await caches.open(name);
|
|
|
|
|
const requests = await cache.keys();
|
|
|
|
|
for (const request of requests) {
|
|
|
|
|
const response = await cache.match(request);
|
|
|
|
|
swCacheSize += Number(response.headers.get('Content-Length')) || 0;
|
|
|
|
|
swCacheSize += Number(response.headers.get("Content-Length")) || 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -555,17 +551,17 @@ export const calcCacheSizes = async () => {
|
|
|
|
|
|
|
|
|
|
return { swCacheSize, diskCacheSize, indexedDBSize, totalSize: Number(swCacheSize) + Number(diskCacheSize) + indexedDBSize };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error getting cache sizes:', error);
|
|
|
|
|
console.error("Error getting cache sizes:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const clearAllCaches = async (cb) => {
|
|
|
|
|
export const clearAllCaches = async cb => {
|
|
|
|
|
try {
|
|
|
|
|
// 1. Clear the service worker cache
|
|
|
|
|
if ('caches' in window) {
|
|
|
|
|
if ("caches" in window) {
|
|
|
|
|
// if (navigator.serviceWorker) {
|
|
|
|
|
const cacheNames = await caches.keys();
|
|
|
|
|
await Promise.all(cacheNames.map((name) => caches.delete(name)));
|
|
|
|
|
await Promise.all(cacheNames.map(name => caches.delete(name)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. Clear the disk cache (HTTP cache)
|
|
|
|
@ -577,38 +573,43 @@ export const clearAllCaches = async (cb) => {
|
|
|
|
|
|
|
|
|
|
// 3. Clear the IndexedDB cache
|
|
|
|
|
const indexedDBNames = await window.indexedDB.databases();
|
|
|
|
|
await Promise.all(indexedDBNames.map((dbName) => window.indexedDB.deleteDatabase(dbName.name)));
|
|
|
|
|
await Promise.all(indexedDBNames.map(dbName => window.indexedDB.deleteDatabase(dbName.name)));
|
|
|
|
|
|
|
|
|
|
// Unregister the service worker
|
|
|
|
|
const registration = await navigator.serviceWorker.getRegistration();
|
|
|
|
|
if (registration) {
|
|
|
|
|
await registration.unregister();
|
|
|
|
|
console.log('Service worker unregistered');
|
|
|
|
|
console.log("Service worker unregistered");
|
|
|
|
|
} else {
|
|
|
|
|
console.log('No service worker registered');
|
|
|
|
|
console.log("No service worker registered");
|
|
|
|
|
}
|
|
|
|
|
if (typeof cb === 'function' ) {
|
|
|
|
|
if (typeof cb === "function") {
|
|
|
|
|
cb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error clearing caches or unregistering service worker:', error);
|
|
|
|
|
console.error("Error clearing caches or unregistering service worker:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const loadScript = (src) => {
|
|
|
|
|
export const loadScript = src => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const script = document.createElement('script');
|
|
|
|
|
script.type = 'text/javascript';
|
|
|
|
|
const script = document.createElement("script");
|
|
|
|
|
script.type = "text/javascript";
|
|
|
|
|
script.onload = resolve;
|
|
|
|
|
script.onerror = reject;
|
|
|
|
|
script.crossOrigin = 'anonymous';
|
|
|
|
|
script.crossOrigin = "anonymous";
|
|
|
|
|
script.src = src;
|
|
|
|
|
if (document.head.append) {
|
|
|
|
|
document.head.append(script);
|
|
|
|
|
} else {
|
|
|
|
|
document.getElementsByTagName('head')[0].appendChild(script);
|
|
|
|
|
document.getElementsByTagName("head")[0].appendChild(script);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//格式化为冒号时间,2010转为20:10
|
|
|
|
|
export const formatColonTime = text => {
|
|
|
|
|
const hours = text.substring(0, 2);
|
|
|
|
|
const minutes = text.substring(2);
|
|
|
|
|
return `${hours}:${minutes}`;
|
|
|
|
|
};
|
|
|
|
|