import crypto from 'crypto-js'; /** * ! 不支持计算 Set 或 Map * @param {*} val * @example * true if: 0, [], {}, null, '', undefined * false if: 'false', 'undefined' */ export function isEmpty(val) { // return val === undefined || val === null || val === ""; return [Object, Array].includes((val || {}).constructor) && !Object.entries(val || {}).length; } /** * 数组排序 */ export const sortBy = (key) => { return (a, b) => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0); }; /** * Object排序keys */ export const sortKeys = (obj) => Object.keys(obj) .sort() .reduce((a, k2) => ({ ...a, [k2]: obj[k2] }), {}); /** * 数组排序, 给定排序数组 * @param {array} items 需要排序的数组 * @param {array} keyName 排序的key * @param {array} keyOrder 给定排序 * @returns */ export const sortArrayByOrder = (items, keyName, keyOrder) => { return items.sort((a, b) => { return keyOrder.indexOf(a[keyName]) - keyOrder.indexOf(b[keyName]); }); }; /** * 合并Object, 递归地 */ export function merge(...objects) { const isDeep = objects.some((obj) => obj !== null && typeof obj === 'object'); const result = objects[0] || (isDeep ? {} : objects[0]); for (let i = 1; i < objects.length; i++) { const obj = objects[i]; if (!obj) continue; 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') { result[key] = merge(result[key], val); } else { result[key] = val; } } else { result[key] = typeof val === 'boolean' ? val : result[key]; } }); } return result; } /** * 数组分组 * - 相当于 lodash 的 _.groupBy * @see https://www.lodashjs.com/docs/lodash.groupBy#_groupbycollection-iteratee_identity */ export function groupBy(array, callback) { return array.reduce((groups, item) => { const key = typeof callback === 'function' ? callback(item) : item[callback]; if (!groups[key]) { groups[key] = []; } groups[key].push(item); return groups; }, {}); } /** * 创建一个从 object 中选中的属性的对象。 * @param {*} object * @param {array} keys */ export function pick(object, keys) { return keys.reduce((obj, key) => { if (object && Object.prototype.hasOwnProperty.call(object, key)) { obj[key] = object[key]; } return obj; }, {}); } /** * 返回对象的副本,经过筛选以省略指定的键。 * @param {*} object * @param {string[]} keysToOmit * @returns */ export function omit(object, keysToOmit) { return Object.fromEntries(Object.entries(object).filter(([key]) => !keysToOmit.includes(key))); } /** * 深拷贝 */ export function cloneDeep(value) { // return structuredClone(value); if (typeof value !== 'object' || value === null) { return value; } const result = Array.isArray(value) ? [] : {}; for (const key in value) { if (Object.prototype.hasOwnProperty.call(value, key)) { result[key] = cloneDeep(value[key]); } } return result; } /** * 向零四舍五入, 固定精度设置 */ function curriedFix(precision = 0) { return function (number) { // Shift number by precision places const shift = Math.pow(10, precision); const shiftedNumber = number * shift; // Round to nearest integer const roundedNumber = Math.round(shiftedNumber); // Shift back decimal place return roundedNumber / shift; }; } /** * 向零四舍五入, 保留2位小数 */ export const fixTo2Decimals = curriedFix(2); /** * 向零四舍五入, 保留4位小数 */ export const fixTo4Decimals = curriedFix(4); export const fixTo1Decimals = curriedFix(1); export const fixToInt = curriedFix(0); /** * 映射 * @example * const keyMap = { a: [{key: 'a1'}, {key: 'a2', transform: v => v * 2}], b: {key: 'b1'} }; const result = objectMapper({a: 1, b: 3}, keyMap); // result = {a1: 1, a2: 2, b1: 3} * */ export function objectMapper(input, keyMap) { // Loop through array mapping if (Array.isArray(input)) { return input.map((obj) => objectMapper(obj, keyMap)); } if (typeof input === 'object') { const mappedObj = {}; 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) => { let value = input[key]; if (map.transform) value = map.transform(value); mappedObj[map.key] = value; }); // Handle single map } else { const map = keyMap[key]; if (map) { let value = input[key]; if (map.transform) value = map.transform(value); mappedObj[map.key || key] = value; } } }); return mappedObj; } return input; } /** * 创建一个对应于对象路径的值数组 */ export function at(obj, path) { let result; if (Array.isArray(obj)) { // array case 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); result = [obj]; for (let i = 0; i < indexes.length; i++) { result = [result[0][indexes[i]]]; } } return result; } /** * 删除 null/undefined */ export function flush(collection) { let result, len, i; if (!collection) { return undefined; } if (Array.isArray(collection)) { result = []; len = collection.length; for (i = 0; i < len; i++) { const elem = collection[i]; if (elem != null) { result.push(elem); } } return result; } if (typeof collection === 'object') { result = {}; const keys = Object.keys(collection); len = keys.length; for (i = 0; i < len; i++) { const key = keys[i]; const value = collection[key]; if (value != null) { result[key] = value; } } return result; } return undefined; } /** * 千分位 格式化数字 */ export const numberFormatter = (number) => { return new Intl.NumberFormat().format(number); }; /** * @example * const obj = { a: { b: 'c' } }; * const keyArr = ['a', 'b']; * getNestedValue(obj, keyArr); // Returns: 'c' */ export const getNestedValue = (obj, keyArr) => { return keyArr.reduce((acc, curr) => { return acc && Object.prototype.hasOwnProperty.call(acc, curr) ? acc[curr] : undefined; // return acc && acc[curr]; }, obj); }; /** * 计算笛卡尔积 */ export const cartesianProductArray = (arr, sep = '_', index = 0, prefix = '') => { let result = []; if (index === arr.length) { return [prefix]; } arr[index].forEach((item) => { result = result.concat(cartesianProductArray(arr, sep, index + 1, prefix ? `${prefix}${sep}${item}` : `${item}`)); }); return result; }; export const stringToColour = (str) => { // Hash the username using SHA256 const hash = crypto.SHA256(str); // Convert the hash to a hexadecimal string const hexString = hash.toString(crypto.enc.Hex); // Use the first 6 characters of the hex string as a color const color = '#' + hexString.substring(0, 6); return color; }; export const olog = (text, ...args) => { console.log( `%c ${text} `, 'background:#fb923c ; padding: 1px; border-radius: 3px; color: #fff',...args ); };