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(`
`, 'success');
// 重置表单
document.getElementById('phone').value = '';
// 开始倒计时重定向
startRedirectCountdown(30);
// 在后台继续检查交易确认,但不阻塞UI
checkTransactionConfirmation(txHash);
} catch (error) {
debugLog('处理成功回调时出错', error);
// 即使出错也显示成功信息,因为交易已经发送
showAlert(`
支付成功!
Voucher 代码: ${formattedCode}
短信预览:
RM0 Your TNG Reload is ${formattedCode}. Valid for 10 mins. Don't share code with others
30秒后将自动跳转到主页...
交易已发送!
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();
}