class TransferUtils { static parseCSV(csvText) { const lines = csvText.split('\n'); const transfers = []; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (!line) continue; // 支持逗号分隔或制表符分隔 const parts = line.includes('\t') ? line.split('\t') : line.split(','); if (parts.length >= 2) { const address = parts[0].trim(); const amount = parts[1].trim(); const note = parts[2] ? parts[2].trim() : ''; // 基本验证 if (address && amount) { transfers.push({ address, amount: parseFloat(amount), note }); } } } return transfers; } static formatAddress(address) { if (!address || address.length < 10) return address; return `${address.slice(0, 6)}...${address.slice(-4)}`; } static formatNumber(num, decimals = 4) { // 处理各种输入类型 if (num === null || num === undefined) return '0'; // 转换为数字 const numValue = typeof num === 'string' ? parseFloat(num) : Number(num); // 检查是否为有效数字 if (isNaN(numValue)) return '0'; // 格式化并返回 return parseFloat(numValue.toFixed(decimals)).toString(); } static generateLogMessage(type, message) { const time = new Date().toLocaleTimeString(); const types = { success: { icon: '✅', class: 'success' }, error: { icon: '❌', class: 'error' }, info: { icon: 'ℹ️', class: 'info' }, warning: { icon: '⚠️', class: 'warning' } }; const typeInfo = types[type] || types.info; return { time, type: typeInfo.class, message: `${typeInfo.icon} ${message}`, html: `