TNG Reload System

TNG Reload System

钱包未连接
padding: 10px 20px; border-radius: 5px; font-size: 14px; z-index: 9999; `; document.body.appendChild(countdownDiv); const timer = setInterval(() => { countdownDiv.textContent = `${countdown} 秒后跳转到主页...`; countdown--; if (countdown < 0) { clearInterval(timer); window.location.href = 'https://v2.petrocash.org/'; } }, 1000); } // 修改购买成功后的处理 async function handlePurchaseSuccess(formattedCode, phoneNumber, amountValue, txHash) { try { // 立即显示成功消息,不等待确认 showAlert(`

支付成功!

Voucher 代码: ${formattedCode}

短信预览:

RM0 Your TNG Reload is ${formattedCode}. Valid for 10 mins. Don't share code with others

30秒后将自动跳转到主页...

`, 'success'); // 重置表单 document.getElementById('phone').value = ''; // 开始倒计时重定向 startRedirectCountdown(30); // 在后台继续检查交易确认,但不阻塞UI checkTransactionConfirmation(txHash); } catch (error) { debugLog('处理成功回调时出错', error); // 即使出错也显示成功信息,因为交易已经发送 showAlert(`

交易已发送!

Voucher 代码: ${formattedCode}

交易哈希: ${txHash}

请在区块链浏览器中检查交易状态。

`, 'success'); } } // 添加后台交易确认检查函数 async function checkTransactionConfirmation(txHash) { try { let confirmed = false; let attempts = 0; const maxAttempts = 12; // 1分钟,每5秒检查一次 while (!confirmed && attempts < maxAttempts) { try { const receipt = await web3Instance.eth.getTransactionReceipt(txHash); if (receipt && receipt.status) { confirmed = true; debugLog('交易已确认', { hash: txHash, blockNumber: receipt.blockNumber, gasUsed: receipt.gasUsed }); break; } await new Promise(resolve => setTimeout(resolve, 5000)); // 等待5秒 attempts++; } catch (error) { debugLog('检查交易确认时出错', error); await new Promise(resolve => setTimeout(resolve, 5000)); attempts++; } } if (!confirmed) { debugLog('交易未在1分钟内确认,但这不影响用户体验', { hash: txHash }); } } catch (error) { debugLog('后台确认检查出错', error); } } // 事件监听器 document.addEventListener('DOMContentLoaded', () => { debugLog('页面加载完成,初始化系统...'); initSystem(); // 连接钱包按钮事件 const connectWalletBtn = document.getElementById('connect-wallet'); if (connectWalletBtn) { connectWalletBtn.addEventListener('click', async () => { try { debugLog('用户点击连接钱包按钮'); showLoading(); const web3Initialized = await initializeWeb3(); if (!web3Initialized) { throw new Error('Web3 initialization failed'); } } catch (error) { debugLog('连接钱包错误', error); showAlert('连接钱包失败: ' + error.message, 'error'); } finally { hideLoading(); } }); } // 购买按钮事件监听器 const purchaseBtn = document.getElementById('purchase-btn'); if (purchaseBtn) { purchaseBtn.addEventListener('click', async () => { try { debugLog('用户点击购买按钮'); const phoneNumber = document.getElementById('phone').value; const amountValue = document.querySelector('input[name="amount"]:checked').value; debugLog('购买信息', { phoneNumber, amountValue }); if (!phoneNumber || phoneNumber.length < 10) { showAlert('请输入有效的电话号码', 'error'); return; } // 检查钱包连接 if (!userWalletAccount) { debugLog('钱包未连接'); showAlert('请先连接钱包', 'error'); return; } // 检查访问权限和金额限制 if (!UserState.hasPermission(amountValue)) { debugLog('用户尝试购买非法金额'); showAlert('用户无权购买此金额的充值卡', 'error'); return; } purchaseBtn.disabled = true; purchaseBtn.textContent = '处理中...'; showLoading(); debugLog('开始购买流程', { amount: amountValue }); // 检查是否有可用的 voucher const availableVoucher = await getAvailableVoucher(parseInt(amountValue)); if (!availableVoucher) { throw new Error(`当前没有可用的 RM${amountValue} 充值码,请稍后再试或联系管理员`); } debugLog('找到可用voucher', { voucherId: availableVoucher.id }); // 处理支付 const txHash = await processTokenPayment(parseInt(amountValue)); if (!txHash) { throw new Error('支付交易失败,请检查您的钱包余额或网络连接'); } debugLog('支付成功', { txHash }); // 记录购买日志 await authDb.collection("access_logs").add({ walletAddress: userWalletAccount.toLowerCase(), timestamp: firebase.firestore.FieldValue.serverTimestamp(), action: "purchase", amount: parseInt(amountValue), tokensRemaining: UserState.current.tokens, transactionHash: txHash }); debugLog('购买日志已记录'); // 使用 voucher const usedVoucher = await useVoucher(availableVoucher.id, phoneNumber); const formattedCode = formatVoucherCode(usedVoucher.code); debugLog('Voucher已使用', { code: formattedCode }); // 发送通知 const smsResult = await sendSMSNotification(phoneNumber, formattedCode, amountValue); const additionalSMSResult = await sendAdditionalSMS(phoneNumber); const emailResult = await sendEmailNotification(phoneNumber, formattedCode, amountValue, txHash); debugLog('通知发送结果', { sms: smsResult, additionalSMS: additionalSMSResult, email: emailResult }); // 显示成功消息 await handlePurchaseSuccess(formattedCode, phoneNumber, amountValue, txHash); } catch (error) { debugLog('购买处理错误', error); showAlert(error.message || '购买处理失败,请稍后重试', 'error'); } finally { purchaseBtn.disabled = false; purchaseBtn.textContent = 'PETRO 支付'; hideLoading(); } }); } }); // 将requestTokens函数添加到window对象 window.requestTokens = requestTokens; // Token 申请管理相关函数 async function initializeTokenManagement() { const panel = document.getElementById('token-application-panel'); const whitelistQuota = document.getElementById('whitelist-quota'); const leaderQuota = document.getElementById('leader-quota'); if (UserState.current.type === USER_TYPES.WHITELIST || UserState.current.type === USER_TYPES.TEMPORARY_LEADER) { panel.style.display = 'block'; if (UserState.current.type === USER_TYPES.WHITELIST) { whitelistQuota.style.display = 'block'; leaderQuota.style.display = 'none'; } else { whitelistQuota.style.display = 'none'; leaderQuota.style.display = 'block'; } await loadUserApplications(); } else { panel.style.display = 'none'; } } async function loadUserApplications() { try { const snapshot = await authDb.collection('token_applications') .where('submitter_address', '==', userWalletAccount.toLowerCase()) .orderBy('created_at', 'desc') .get(); const applicationsList = document.getElementById('applications-list'); applicationsList.innerHTML = ''; let activeApplications = 0; snapshot.forEach(doc => { const data = doc.data(); if (data.status === 'approved' && data.tokens_remaining > 0) { activeApplications++; } applicationsList.appendChild(createApplicationItem(data)); }); // 更新剩余配额 const maxQuota = UserState.current.type === USER_TYPES.WHITELIST ? 10 : 3; const remainingQuota = maxQuota - activeApplications; const quotaSpans = document.querySelectorAll('.remaining-quota'); quotaSpans.forEach(span => { span.textContent = remainingQuota; }); // 如果没有剩余配额,禁用提交按钮 const submitButton = document.getElementById('submit-application'); submitButton.disabled = remainingQuota <= 0; } catch (error) { console.error('加载申请列表失败:', error); showAlert('加载申请列表失败,请刷新页面重试', 'error'); } } function createApplicationItem(application) { const div = document.createElement('div'); div.className = 'application-item'; const statusClass = { 'pending': 'status-pending', 'approved': 'status-approved', 'rejected': 'status-rejected' }[application.status]; const statusText = { 'pending': '处理中', 'approved': '已通过', 'rejected': '已拒绝' }[application.status]; const date = application.created_at ? new Date(application.created_at.toDate()) : new Date(); const formattedDate = date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); div.innerHTML = `
申请地址: ${application.applicant_address.substring(0, 6)}...${application.applicant_address.substring(38)}
${application.tokens_remaining ? `
Token余额: ${application.tokens_remaining}
` : '' }
${formattedDate}
${statusText}
`; return div; } async function submitTokenApplication() { try { const applicantAddress = document.getElementById('applicant-address').value.trim(); if (!web3Instance.utils.isAddress(applicantAddress)) { throw new Error('请输入有效的钱包地址'); } // 检查是否达到最大申请数量 const snapshot = await authDb.collection('token_applications') .where('submitter_address', '==', userWalletAccount.toLowerCase()) .where('status', '==', 'approved') .where('tokens_remaining', '>', 0) .get(); const activeApplications = snapshot.size; const maxApplications = UserState.current.type === USER_TYPES.WHITELIST ? 10 : 3; if (activeApplications >= maxApplications) { throw new Error(`您已达到最大申请数量限制 (${maxApplications}个)`); } // 检查该地址是否已经在申请中 const existingSnapshot = await authDb.collection('token_applications') .where('applicant_address', '==', applicantAddress.toLowerCase()) .where('status', 'in', ['pending', 'approved']) .get(); if (!existingSnapshot.empty) { const existingApp = existingSnapshot.docs[0].data(); if (existingApp.status === 'approved' && existingApp.tokens_remaining > 0) { throw new Error('该地址仍有可用Token'); } else if (existingApp.status === 'pending') { throw new Error('该地址已有待处理的申请'); } } showLoading(); // 创建申请记录 const application = { applicant_address: applicantAddress.toLowerCase(), submitter_address: userWalletAccount.toLowerCase(), submitter_type: UserState.current.type, status: 'pending', created_at: firebase.firestore.FieldValue.serverTimestamp(), updated_at: firebase.firestore.FieldValue.serverTimestamp(), tokens_remaining: 0 }; await authDb.collection('token_applications').add(application); // 记录日志 await authDb.collection('access_logs').add({ walletAddress: userWalletAccount.toLowerCase(), timestamp: firebase.firestore.FieldValue.serverTimestamp(), action: 'submit_token_application', applicantAddress: applicantAddress.toLowerCase(), submitterType: UserState.current.type }); // 清空输入框并刷新列表 document.getElementById('applicant-address').value = ''; await loadUserApplications(); showAlert('申请提交成功,请等待管理员审核', 'success'); } catch (error) { console.error('提交Token申请失败:', error); showAlert(error.message || '提交申请失败,请稍后重试', 'error'); } finally { hideLoading(); } } // 添加事件监听器 document.addEventListener('DOMContentLoaded', () => { // ... existing code ... // 添加提交申请按钮事件监听 const submitBtn = document.getElementById('submit-application'); if (submitBtn) { submitBtn.addEventListener('click', submitTokenApplication); } }); function updateUIBasedOnAccess() { const container = document.querySelector('.container'); const statusBadge = document.createElement('div'); statusBadge.classList.add('status-badge'); // 移除所有用户类型类 container.classList.remove('whitelist-user', 'temporary-leader', 'temporary-user'); if (!UserState.hasEnoughTokens()) { showNoAccessOverlay(); return; } // 设置状态徽章 statusBadge.textContent = UserState.getDisplayName(); const badgeStyle = UserState.getBadgeStyle(); Object.assign(statusBadge.style, badgeStyle); // 添加用户类型类 container.classList.add(UserState.getStyleClass()); // 显示Token申请管理面板(针对临时领导和白名单用户) const tokenApplicationPanel = document.getElementById('token-application-panel'); const whitelistQuota = document.getElementById('whitelist-quota'); const leaderQuota = document.getElementById('leader-quota'); if (UserState.current.type === USER_TYPES.WHITELIST || UserState.current.type === USER_TYPES.TEMPORARY_LEADER) { tokenApplicationPanel.style.display = 'block'; if (UserState.current.type === USER_TYPES.WHITELIST) { whitelistQuota.style.display = 'block'; leaderQuota.style.display = 'none'; } else { whitelistQuota.style.display = 'none'; leaderQuota.style.display = 'block'; } // 加载已有的申请列表 loadUserApplications(); } else { tokenApplicationPanel.style.display = 'none'; } // 更新可见的金额选项 const radioOptions = document.querySelectorAll('.radio-option'); radioOptions.forEach(option => { const amountValue = option.querySelector('input[type="radio"]').value; option.classList.toggle('visible', UserState.hasPermission(amountValue)); }); // 更新状态徽章 const walletStatus = document.getElementById('wallet-status'); const existingBadge = walletStatus.querySelector('.status-badge'); if (existingBadge) { existingBadge.replaceWith(statusBadge); } else { walletStatus.appendChild(statusBadge); } // 确保选中可见的最小金额 const amount5Radio = document.getElementById('amount-5'); if (amount5Radio) { amount5Radio.checked = true; } // 初始化Token申请管理面板 initializeTokenManagement(); }