import type { SkuConfig, SkuList } from '@/services/prod/prod-manager'; /** * @param str 需要转驼峰的下划线字符串 * @returns 字符串驼峰 */ export const underlineToHump = (str: string): string => { if (!str) return ''; return str.replace(/-(\w)/g, (_, letter: string) => { return letter.toUpperCase(); }); }; export const setCssVar = ( prop: string, val: any, dom = document.documentElement, ) => { dom.style.setProperty(prop, val); }; /** * @param str 需要转下划线的驼峰字符串 * @returns 字符串下划线 */ export const humpToUnderline = (str: string): string => { return str.replace(/([A-Z])/g, '-$1').toLowerCase(); }; // copy to vben-admin const objectToString = Object.prototype.toString; export const is = (val: unknown, type: string) => { return objectToString.call(val) === `[object ${type}]`; }; export const isDef = (val?: T): val is T => { return typeof val !== 'undefined'; }; export const isUnDef = (val?: T): val is T => { return !isDef(val); }; export const isObject = (val: any): val is Record => { return val !== null && is(val, 'Object'); }; export const isEmpty = (val: any): boolean => { if (val === null || val === undefined || typeof val === 'undefined') { return true; } if (isArray(val) || isString(val)) { return val.length === 0; } if (val instanceof Map || val instanceof Set) { return val.size === 0; } if (isObject(val)) { return Object.keys(val).length === 0; } return false; }; export const isDate = (val: unknown): val is Date => { return is(val, 'Date'); }; export const isNull = (val: unknown): val is null => { return val === null; }; export const isNullAndUnDef = (val: unknown): val is null | undefined => { return isUnDef(val) && isNull(val); }; export const isNullOrUnDef = (val: unknown): val is null | undefined => { return isUnDef(val) || isNull(val); }; export const isNumber = (val: unknown): val is number => { return is(val, 'Number'); }; export const isPromise = (val: unknown): val is Promise => { return ( is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch) ); }; export const isString = (val: unknown): val is string => { return is(val, 'String'); }; export const isFunction = (val: unknown): val is (...args: any[]) => any => { return typeof val === 'function'; }; export const isBoolean = (val: unknown): val is boolean => { return is(val, 'Boolean'); }; export const isRegExp = (val: unknown): val is RegExp => { return is(val, 'RegExp'); }; export const isArray = (val: any): val is Array => { return val && Array.isArray(val); }; export const isWindow = (val: any): val is Window => { return typeof window !== 'undefined' && is(val, 'Window'); }; export const isElement = (val: unknown): val is Element => { return isObject(val) && !!val.tagName; }; export const isMap = (val: unknown): val is Map => { return is(val, 'Map'); }; export const isServer = typeof window === 'undefined'; export const isClient = !isServer; export const isUrl = (path: string): boolean => { // fix:修复hash路由无法跳转的问题 const reg = /(((^https?:(?:\/\/)?)(?:[-:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%#/.\w-_]*)?\??(?:[-+=&%@.\w_]*)#?(?:[\w]*))?)$/; return reg.test(path); }; export const isDark = (): boolean => { return window.matchMedia('(prefers-color-scheme: dark)').matches; }; // 是否是图片链接 export const isImgPath = (path: string): boolean => { return /(https?:\/\/|data:image\/).*?\.(png|jpg|jpeg|gif|svg|webp|ico)/gi.test( path, ); }; export const isEmptyVal = (val: any): boolean => { return val === '' || val === null || val === undefined; }; export const isExternal = (path: string): boolean => { return /https?/.test(path); }; /** * 查找数组对象的某个下标 * @param {Array} ary 查找的数组 * @param {Functon} fn 判断的方法 */ // eslint-disable-next-line export const findIndex = (ary: Array, fn: Fn): number => { if (ary.findIndex) { return ary.findIndex(fn); } let index = -1; ary.some((item: T, i: number, ary: Array) => { const ret: T = fn(item, i, ary); if (ret) { index = i; return true; } return false; }); return index; }; // 笛卡尔积函数 function cartesianProduct(...arrays: T[][]): T[][] { return arrays.reduce( (acc, curr) => { const result: T[][] = []; acc.forEach((a) => { curr.forEach((c) => { result.push([...a, c]); }); }); return result; }, [[]] as T[][], ); } export function generateSkuTableData(data: SkuConfig[]): SkuList[] { // 过滤掉prodPropValues为空的配置 const validData = data.filter((config) => config.prodPropValues.length > 0); // 如果所有配置都被过滤掉了,返回空数组 if (validData.length === 0) { return []; } const propValueArrays = validData.map((config) => config.prodPropValues); const combinations = cartesianProduct<{ propValue: string; valueId?: number; state?: number; isExist?: number; }>(...propValueArrays); return combinations.map((combination, index) => { const skuItem: SkuList = { skuName: combination.map((item) => item.propValue).join(','), basePrice: 0, isSpecs: index === 0 ? 1 : 0, status: 1, stocks: 0, isShelf: 1, // propIds: combination.map((item) => item.valueId).join(",") }; // 只添加有效配置的动态属性 validData.forEach((config, configIndex) => { (skuItem as any)[config.propName] = combination[configIndex].propValue; }); return skuItem; }); } // 根据删除的SKU规格更新data状态 function updateDataByDeletedSku( data: SkuConfig[], deletedSkuName: string, ): SkuConfig[] { // 解析删除的SKU名称,获取各个属性值 const deletedValues = deletedSkuName.split(',').map((v) => v.trim()); // 深拷贝data以避免修改原数据 const updatedData = JSON.parse(JSON.stringify(data)) as SkuConfig[]; // 遍历每个属性配置 updatedData.forEach((config, configIndex) => { if (configIndex < deletedValues.length) { const targetValue = deletedValues[configIndex]; // 找到对应的属性值并设置为失效 config.prodPropValues.forEach( (propValue: { propValue: string; state?: number; isExist?: number; }) => { if (propValue.propValue === targetValue) { propValue.state = 0; // 设置为失效 propValue.isExist = 0; // 设置为不存在 } }, ); } }); return updatedData; } // 批量处理多个删除的SKU function _updateDataByDeletedSkus( data: SkuConfig[], deletedSkuNames: string[], ): SkuConfig[] { let updatedData = JSON.parse(JSON.stringify(data)) as SkuConfig[]; deletedSkuNames.forEach((skuName) => { updatedData = updateDataByDeletedSku(updatedData, skuName); }); return updatedData; } // 根据属性名和属性值直接设置失效状态 function _updateDataByPropValue( data: SkuConfig[], propName: string, propValue: string, state: 0 | 1 = 0, ): SkuConfig[] { const updatedData = JSON.parse(JSON.stringify(data)) as SkuConfig[]; const targetConfig = updatedData.find( (config) => config.propName === propName, ); if (targetConfig) { const targetPropValue = targetConfig.prodPropValues.find( (pv: { propValue: string; state?: number; isExist?: number; isExpire?: number; }) => pv.propValue === propValue, ); if (targetPropValue) { targetPropValue.state = state; targetPropValue.isExist = state; } } return updatedData; } // 重新生成有效的SKU列表(过滤掉失效的属性值) export function generateValidSkuTableData(data: SkuConfig[]): SkuList[] { console.log(data); // 过滤出有效的属性值 const validData = data .map((config) => ({ ...config, prodPropValues: config.prodPropValues.filter( (pv: { isExpire: number }) => pv.isExpire === 0, ), })) .filter((config) => config.prodPropValues.length > 0); if (validData.length === 0) { return []; } const propValueArrays = validData.map((config) => config.prodPropValues); const combinations = cartesianProduct<{ propValue: string; valueId?: number; state?: number; isExist?: number; isExpire?: number; }>(...propValueArrays); return combinations.map((combination) => { const skuItem: SkuList = { skuName: combination.map((item) => item.propValue).join(','), properties: combination.map((item) => item.propValue).join(','), basePrice: 0, isSpecs: 0, status: 1, stocks: 0, stocksFlg: 1, isShelf: 1, isExist: combination.some((item) => item.isExist) ? 1 : 0, }; validData.forEach((config, configIndex) => { (skuItem as any)[config.propName] = combination[configIndex].propValue; }); return skuItem; }); } export const 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 = Date.now(); 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); }); };