/** * 通用工具函数 */ /** * 判断值是否有意义(非空、非空字符串、非空数组) */ export function hasValue(v: unknown): boolean { if (v == null) return false; if (Array.isArray(v)) return v.length > 0 && v.some((item) => item != null); if (typeof v === 'string') return v.trim() !== ''; return true; } /** * 判断值是否为空(null、undefined、空字符串) */ export function isEmptyValue(v: unknown): boolean { return v == null || (typeof v === 'string' && v.trim() === ''); } /** * 安全转换值(带异常处理和默认值) */ export function safeTransform(value: T, transform?: (v: T) => unknown): T | unknown { if (!transform) return value; try { return transform(value) ?? value; } catch { return value; } } /** * 生成唯一 ID */ export function uniqueId(prefix = ''): string { const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 8); return prefix ? `${prefix}_${id}` : id; } /** * 简易深拷贝(基于 JSON,适用于纯数据对象) */ export function deepClone(value: T): T { return JSON.parse(JSON.stringify(value)); } /** * 防抖 */ export function debounce any>(fn: T, wait = 300) { let timer: ReturnType | null = null; const debounced = (...args: Parameters) => { if (timer) clearTimeout(timer); timer = setTimeout(() => fn(...args), wait); }; debounced.cancel = () => { if (timer) clearTimeout(timer); timer = null; }; return debounced; } /** * 节流 */ export function throttle any>(fn: T, wait = 300) { let lastTime = 0; return (...args: Parameters) => { const now = Date.now(); if (now - lastTime >= wait) { lastTime = now; fn(...args); } }; } /** * 格式化日期 */ export function formatDate(date: Date | string | number, format = 'YYYY-MM-DD HH:mm:ss'): string { const d = new Date(date); if (Number.isNaN(d.getTime())) return ''; const pad = (n: number) => String(n).padStart(2, '0'); const map: Record = { YYYY: String(d.getFullYear()), MM: pad(d.getMonth() + 1), DD: pad(d.getDate()), HH: pad(d.getHours()), mm: pad(d.getMinutes()), ss: pad(d.getSeconds()), }; return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => map[match]); } /** * 树形数据扁平化 */ export interface TreeNode { id: string | number; children?: TreeNode[]; [key: string]: any; } export function flattenTree(tree: T[]): T[] { const result: T[] = []; const stack = [...tree].reverse(); while (stack.length) { const node = stack.pop() as T; result.push(node); if (node.children?.length) { stack.push(...(node.children as T[]).reverse()); } } return result; }