class BatchTransferApp { constructor() { this.transferData = []; this.transferResults = []; this.isTransferring = false; this.isTokenTransfer = false; this.tokenInfo = null; this.initElements(); this.initEventListeners(); this.initUI(); } initElements() { // 钱包相关 this.connectWalletBtn = document.getElementById('connectWallet'); this.disconnectWalletBtn = document.getElementById('disconnectWallet'); this.walletInfo = document.getElementById('connectedInfo'); this.accountAddress = document.getElementById('accountAddress'); this.walletBalance = document.getElementById('walletBalance'); this.networkInfo = document.getElementById('networkInfo'); // 转账类型 this.transferTypeRadios = document.querySelectorAll('input[name="transferType"]'); this.tokenConfig = document.getElementById('tokenConfig'); this.tokenAddress = document.getElementById('tokenAddress'); this.loadTokenInfoBtn = document.getElementById('loadTokenInfo'); this.tokenInfoElement = document.getElementById('tokenInfo'); this.tokenName = document.getElementById('tokenName'); this.tokenSymbol = document.getElementById('tokenSymbol'); this.tokenBalance = document.getElementById('tokenBalance'); // 上传相关 this.transferInput = document.getElementById('transferInput'); this.parseDataBtn = document.getElementById('parseData'); this.clearInputBtn = document.getElementById('clearInput'); this.dataPreview = document.getElementById('dataPreview'); this.dataTable = document.getElementById('dataTable'); this.dataCount = document.getElementById('dataCount'); this.clearDataBtn = document.getElementById('clearData'); // 汇总信息 this.totalCount = document.getElementById('totalCount'); this.totalAmount = document.getElementById('totalAmount'); this.amountUnit = document.getElementById('amountUnit'); this.estimatedGas = document.getElementById('estimatedGas'); this.totalCost = document.getElementById('totalCost'); // 高级设置 this.delayTime = document.getElementById('delayTime'); this.gasLimit = document.getElementById('gasLimit'); this.gasPrice = document.getElementById('gasPrice'); // 转账按钮 this.startTransferBtn = document.getElementById('startTransfer'); this.stopTransferBtn = document.getElementById('stopTransfer'); // 进度相关 this.progressSection = document.getElementById('progressSection'); this.progressFill = document.getElementById('progressFill'); this.progressInfo = document.getElementById('progressInfo'); this.progressPercent = document.getElementById('progressPercent'); this.successCount = document.getElementById('successCount'); this.failedCount = document.getElementById('failedCount'); this.pendingCount = document.getElementById('pendingCount'); // 日志相关 this.transferLog = document.getElementById('transferLog'); this.clearLogBtn = document.getElementById('clearLog'); // 模态框 this.confirmModal = document.getElementById('confirmModal'); this.confirmCount = document.getElementById('confirmCount'); this.confirmAmount = document.getElementById('confirmAmount'); this.confirmGas = document.getElementById('confirmGas'); this.confirmBalance = document.getElementById('confirmBalance'); this.confirmCheck = document.getElementById('confirmCheck'); this.cancelTransferBtn = document.getElementById('cancelTransfer'); this.executeTransferBtn = document.getElementById('executeTransfer'); this.modalCloseBtn = document.querySelector('.modal-close'); } initEventListeners() { // 钱包连接 this.connectWalletBtn.addEventListener('click', () => this.connectWallet()); this.disconnectWalletBtn.addEventListener('click', () => this.disconnectWallet()); // 转账类型切换 this.transferTypeRadios.forEach(radio => { radio.addEventListener('change', (e) => { if (e.target.checked) { this.onTransferTypeChange(e.target.value); } }); }); // Token相关 this.loadTokenInfoBtn.addEventListener('click', () => this.loadTokenInfo()); this.tokenAddress.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.loadTokenInfo(); } }); // 数据输入 this.parseDataBtn.addEventListener('click', () => this.parseTransferData()); this.clearInputBtn.addEventListener('click', () => this.clearInput()); this.transferInput.addEventListener('keydown', (e) => { // Ctrl/Cmd + Enter 快捷键解析数据 if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { this.parseTransferData(); } }); // 清空数据 if (this.clearDataBtn) { this.clearDataBtn.addEventListener('click', () => this.clearData()); } // 转账控制 this.startTransferBtn.addEventListener('click', () => this.showConfirmModal()); this.stopTransferBtn.addEventListener('click', () => this.stopTransfer()); // 日志控制 this.clearLogBtn.addEventListener('click', () => this.clearLog()); // 配置变化 this.delayTime.addEventListener('change', () => this.updateSummary()); this.gasLimit.addEventListener('change', () => this.updateSummary()); // 模态框 this.confirmCheck.addEventListener('change', (e) => { this.executeTransferBtn.disabled = !e.target.checked; }); this.cancelTransferBtn.addEventListener('click', () => this.hideModal()); this.executeTransferBtn.addEventListener('click', () => this.executeTransfer()); this.modalCloseBtn.addEventListener('click', () => this.hideModal()); // 点击模态框外部关闭 this.confirmModal.addEventListener('click', (e) => { if (e.target === this.confirmModal) { this.hideModal(); } }); } initUI() { this.updateUI(); // 尝试恢复钱包连接 this.restoreWalletConnection(); // 定期更新Gas价格 setInterval(() => { if (window.BatchTransfer.provider) { this.updateGasPrice(); } }, 30000); } async restoreWalletConnection() { try { // 检查是否有保存的钱包连接状态 const wasConnected = localStorage.getItem('walletConnected'); if (wasConnected === 'true' && window.ethereum) { // 尝试自动连接 const accounts = await window.ethereum.request({ method: 'eth_accounts' }); if (accounts && accounts.length > 0) { // 钱包已授权,自动连接 await this.connectWallet(); } } } catch (error) { console.log('无法恢复钱包连接:', error); localStorage.removeItem('walletConnected'); } } async connectWallet() { try { this.addLog('正在连接钱包...', 'info'); const account = await window.BatchTransfer.connectWallet(); // 保存连接状态到localStorage localStorage.setItem('walletConnected', 'true'); // 更新UI this.connectWalletBtn.style.display = 'none'; this.walletInfo.style.display = 'flex'; this.accountAddress.textContent = window.TransferUtils.formatAddress(account); // 获取余额和网络信息 await this.updateWalletInfo(); this.addLog('钱包连接成功', 'success'); } catch (error) { this.addLog(`连接失败: ${error.message}`, 'error'); alert(`连接钱包失败: ${error.message}`); } } async disconnectWallet() { await window.BatchTransfer.disconnectWallet(); // 清除保存的连接状态 localStorage.removeItem('walletConnected'); // 重置UI this.connectWalletBtn.style.display = 'block'; this.walletInfo.style.display = 'none'; // 检查networkInfo元素是否存在(因为我们已经从页面移除了它) if (this.networkInfo) { this.networkInfo.textContent = '未连接'; } this.gasPrice.value = '0'; this.addLog('已断开钱包连接', 'info'); } async updateWalletInfo() { try { // 更新余额 const balance = await window.BatchTransfer.getWalletBalance(); this.walletBalance.textContent = window.TransferUtils.formatNumber(balance, 4); // 更新网络信息(如果元素存在) if (this.networkInfo) { const network = await window.BatchTransfer.getNetworkInfo(); this.networkInfo.textContent = `${network.name} (Chain ID: ${network.chainId})`; } // 更新Gas价格 await this.updateGasPrice(); } catch (error) { console.error('更新钱包信息失败:', error); } } async updateGasPrice() { try { const gasPrice = await window.BatchTransfer.getGasPrice(); console.log('获取到的Gas价格 (Gwei):', gasPrice); this.gasPrice.value = window.TransferUtils.formatNumber(parseFloat(gasPrice), 2); console.log('设置的Gas价格值:', this.gasPrice.value); this.updateSummary(); } catch (error) { console.error('获取Gas价格失败:', error); } } onTransferTypeChange(type) { this.isTokenTransfer = (type === 'token'); if (this.isTokenTransfer) { // 显示Token配置 this.tokenConfig.style.display = 'block'; // 更新Gas Limit默认值 this.gasLimit.value = '65000'; this.amountUnit.textContent = 'Token'; } else { // 隐藏Token配置 this.tokenConfig.style.display = 'none'; this.tokenInfoElement.style.display = 'none'; // 恢复BNB转账的Gas Limit this.gasLimit.value = '21000'; this.amountUnit.textContent = 'BNB'; // 清空token信息 this.tokenInfo = null; } this.updateSummary(); } async loadTokenInfo() { const address = this.tokenAddress.value.trim(); if (!address) { alert('请输入Token合约地址'); return; } if (!window.BatchTransfer.provider) { alert('请先连接钱包'); return; } try { this.addLog('正在加载Token信息...', 'info'); this.loadTokenInfoBtn.disabled = true; this.loadTokenInfoBtn.innerHTML = ' 加载中...'; // 加载Token合约 const tokenInfo = await window.BatchTransfer.loadTokenContract(address); // 获取Token余额 const balance = await window.BatchTransfer.getTokenBalance(); // 更新UI this.tokenName.textContent = tokenInfo.name; this.tokenSymbol.textContent = tokenInfo.symbol; this.tokenBalance.textContent = window.TransferUtils.formatNumber(parseFloat(balance), 4); this.tokenInfoElement.style.display = 'block'; this.tokenInfo = tokenInfo; // 更新金额单位 this.amountUnit.textContent = tokenInfo.symbol; this.addLog(`Token加载成功: ${tokenInfo.name} (${tokenInfo.symbol})`, 'success'); // 更新汇总信息 this.updateSummary(); } catch (error) { this.addLog(`加载Token失败: ${error.message}`, 'error'); alert(`加载Token失败: ${error.message}`); this.tokenInfoElement.style.display = 'none'; } finally { this.loadTokenInfoBtn.disabled = false; this.loadTokenInfoBtn.innerHTML = ' 加载'; } } loadCSVFile(file) { const reader = new FileReader(); reader.onload = (e) => { try { const csvText = e.target.result; this.transferData = window.TransferUtils.parseCSV(csvText); // 验证数据 const errors = window.BatchTransfer.validateTransferData(this.transferData); if (errors.length > 0) { this.addLog('CSV文件解析错误:', 'error'); errors.forEach(error => this.addLog(error, 'error')); alert(`发现${errors.length}个错误,请检查CSV文件格式`); return; } // 显示数据预览 this.dataPreview.style.display = 'block'; // 更新表格显示 this.updateDataTable(); // 更新汇总信息 this.updateSummary(); this.addLog(`成功加载 ${this.transferData.length} 条转账记录`, 'success'); } catch (error) { this.addLog(`解析CSV文件失败: ${error.message}`, 'error'); alert('解析CSV文件失败,请检查文件格式'); } }; reader.onerror = () => { this.addLog('读取文件失败', 'error'); }; reader.readAsText(file); } parseTransferData() { const inputText = this.transferInput.value.trim(); if (!inputText) { alert('请输入转账数据'); return; } try { // 使用相同的CSV解析函数 this.transferData = window.TransferUtils.parseCSV(inputText); // 验证数据 const errors = window.BatchTransfer.validateTransferData(this.transferData); if (errors.length > 0) { this.addLog('数据解析错误:', 'error'); errors.forEach(error => this.addLog(error, 'error')); alert(`发现${errors.length}个错误,请检查数据格式\n\n格式:地址,金额,备注\n示例:0x123...,0.1,用户A`); return; } // 显示数据预览 this.dataPreview.style.display = 'block'; // 更新表格显示 this.updateDataTable(); // 更新汇总信息 this.updateSummary(); this.addLog(`成功解析 ${this.transferData.length} 条转账记录`, 'success'); } catch (error) { this.addLog(`解析数据失败: ${error.message}`, 'error'); alert('解析数据失败,请检查数据格式\n\n格式:地址,金额,备注\n示例:0x123...,0.1,用户A'); } } clearInput() { this.transferInput.value = ''; this.clearData(); } updateDataTable() { const tbody = this.dataTable.querySelector('tbody'); tbody.innerHTML = ''; this.transferData.forEach((item, index) => { const row = document.createElement('tr'); row.innerHTML = `
暂无日志