369 lines
12 KiB
JavaScript
369 lines
12 KiB
JavaScript
// 全局变量
|
||
let currentProduct = null;
|
||
let currentOrder = null;
|
||
|
||
// DOM 元素
|
||
const productPrice = document.getElementById('product-price');
|
||
const quantityInput = document.getElementById('quantity');
|
||
const totalPriceElement = document.getElementById('total-price');
|
||
const orderForm = document.getElementById('orderForm');
|
||
const orderModal = document.getElementById('orderModal');
|
||
const paymentStatus = document.getElementById('paymentStatus');
|
||
|
||
// 初始化
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
loadProductData();
|
||
setupEventListeners();
|
||
});
|
||
|
||
// 加载产品数据
|
||
async function loadProductData() {
|
||
try {
|
||
const response = await fetch('/api/products');
|
||
const products = await response.json();
|
||
|
||
// 使用第一个产品作为展示产品
|
||
const productId = Object.keys(products)[0];
|
||
currentProduct = { id: productId, ...products[productId] };
|
||
|
||
// 更新界面
|
||
document.getElementById('product-name').textContent = currentProduct.name;
|
||
document.getElementById('product-description').textContent = currentProduct.description;
|
||
document.getElementById('product-price').textContent = currentProduct.price.toFixed(2);
|
||
|
||
updateTotalPrice();
|
||
} catch (error) {
|
||
console.error('加载产品数据失败:', error);
|
||
alert('加载产品信息失败,请刷新页面重试');
|
||
}
|
||
}
|
||
|
||
// 设置事件监听器
|
||
function setupEventListeners() {
|
||
// 数量控制
|
||
document.getElementById('decrease-qty').addEventListener('click', () => {
|
||
const current = parseInt(quantityInput.value) || 1;
|
||
if (current > 1) {
|
||
quantityInput.value = current - 1;
|
||
updateTotalPrice();
|
||
}
|
||
});
|
||
|
||
document.getElementById('increase-qty').addEventListener('click', () => {
|
||
const current = parseInt(quantityInput.value) || 1;
|
||
if (current < 999) {
|
||
quantityInput.value = current + 1;
|
||
updateTotalPrice();
|
||
}
|
||
});
|
||
|
||
// 数量输入变化
|
||
quantityInput.addEventListener('input', updateTotalPrice);
|
||
quantityInput.addEventListener('change', validateQuantity);
|
||
|
||
// 表单提交
|
||
orderForm.addEventListener('submit', handleOrderSubmit);
|
||
|
||
// 模态框控制
|
||
document.getElementById('closeModal').addEventListener('click', closeOrderModal);
|
||
document.getElementById('pay-now-btn').addEventListener('click', handlePayNow);
|
||
|
||
// 支付状态检查
|
||
document.getElementById('check-status-btn').addEventListener('click', checkPaymentStatus);
|
||
|
||
// 点击模态框外部关闭
|
||
orderModal.addEventListener('click', (e) => {
|
||
if (e.target === orderModal) {
|
||
closeOrderModal();
|
||
}
|
||
});
|
||
}
|
||
|
||
// 更新总价
|
||
function updateTotalPrice() {
|
||
if (!currentProduct) return;
|
||
|
||
const quantity = parseInt(quantityInput.value) || 1;
|
||
const total = (currentProduct.price * quantity).toFixed(2);
|
||
totalPriceElement.textContent = `$${total}`;
|
||
}
|
||
|
||
// 验证数量
|
||
function validateQuantity() {
|
||
const value = parseInt(quantityInput.value);
|
||
if (isNaN(value) || value < 1) {
|
||
quantityInput.value = 1;
|
||
} else if (value > 999) {
|
||
quantityInput.value = 999;
|
||
}
|
||
updateTotalPrice();
|
||
}
|
||
|
||
// 处理订单提交
|
||
async function handleOrderSubmit(e) {
|
||
e.preventDefault();
|
||
|
||
if (!currentProduct) {
|
||
alert('产品信息加载中,请稍后重试');
|
||
return;
|
||
}
|
||
|
||
// 获取表单数据
|
||
const formData = new FormData(orderForm);
|
||
const orderData = {
|
||
product_id: currentProduct.id,
|
||
quantity: parseInt(formData.get('quantity')),
|
||
customer_name: formData.get('customer_name').trim(),
|
||
customer_email: formData.get('customer_email').trim(),
|
||
customer_phone: formData.get('customer_phone').trim(),
|
||
shipping_address: formData.get('shipping_address').trim()
|
||
};
|
||
|
||
// 验证必填字段
|
||
if (!orderData.customer_name || !orderData.shipping_address) {
|
||
alert('请填写姓名和收货地址');
|
||
return;
|
||
}
|
||
|
||
// 禁用提交按钮
|
||
const submitBtn = document.getElementById('submit-order');
|
||
const btnText = submitBtn.querySelector('.btn-text');
|
||
const btnLoading = submitBtn.querySelector('.btn-loading');
|
||
|
||
submitBtn.disabled = true;
|
||
btnText.style.display = 'none';
|
||
btnLoading.style.display = 'inline';
|
||
|
||
try {
|
||
// 创建订单
|
||
const response = await fetch('/api/orders', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(orderData)
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
currentOrder = {
|
||
...orderData,
|
||
order_id: result.order_id,
|
||
total_amount: result.total_amount
|
||
};
|
||
|
||
showOrderModal();
|
||
} else {
|
||
throw new Error(result.error || '订单创建失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('创建订单失败:', error);
|
||
alert('创建订单失败: ' + error.message);
|
||
} finally {
|
||
// 恢复提交按钮
|
||
submitBtn.disabled = false;
|
||
btnText.style.display = 'inline';
|
||
btnLoading.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// 显示订单确认模态框
|
||
function showOrderModal() {
|
||
if (!currentOrder) return;
|
||
|
||
// 填充订单信息
|
||
document.getElementById('modal-order-id').textContent = currentOrder.order_id;
|
||
document.getElementById('modal-product-name').textContent = currentProduct.name;
|
||
document.getElementById('modal-quantity').textContent = currentOrder.quantity;
|
||
document.getElementById('modal-total-price').textContent = `$${currentOrder.total_amount.toFixed(2)} USDT`;
|
||
document.getElementById('modal-address').textContent = currentOrder.shipping_address;
|
||
|
||
orderModal.style.display = 'flex';
|
||
}
|
||
|
||
// 关闭订单模态框
|
||
function closeOrderModal() {
|
||
orderModal.style.display = 'none';
|
||
}
|
||
|
||
// 处理支付
|
||
async function handlePayNow() {
|
||
if (!currentOrder) return;
|
||
|
||
try {
|
||
// 创建支付
|
||
const response = await fetch('/api/payment/create', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
order_id: currentOrder.order_id
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
// 检查是否为手动支付模式
|
||
if (result.manual_mode) {
|
||
// 关闭模态框,跳转到手动支付页面
|
||
closeOrderModal();
|
||
window.location.href = result.payment_url;
|
||
} else {
|
||
// 关闭模态框,直接跳转到UPay支付页面
|
||
closeOrderModal();
|
||
|
||
// 显示跳转提示
|
||
const jumpTip = document.createElement('div');
|
||
jumpTip.innerHTML = `
|
||
<div style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 9999; display: flex; align-items: center; justify-content: center;">
|
||
<div style="background: white; padding: 30px; border-radius: 10px; text-align: center;">
|
||
<h3>正在跳转到支付页面...</h3>
|
||
<p>请在新页面完成USDT支付</p>
|
||
<div style="margin: 20px 0;">
|
||
<div style="width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #667eea; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto;"></div>
|
||
</div>
|
||
<button onclick="this.parentElement.parentElement.remove(); showPaymentStatus();" style="background: #667eea; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer;">我已完成支付</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
document.body.appendChild(jumpTip);
|
||
|
||
// 3秒后跳转到UPay支付页面
|
||
setTimeout(() => {
|
||
window.location.href = result.payment_url;
|
||
}, 3000);
|
||
}
|
||
} else {
|
||
throw new Error(result.error || '创建支付失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('创建支付失败:', error);
|
||
alert('创建支付失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// 显示支付状态页面
|
||
function showPaymentStatus() {
|
||
if (!currentOrder) return;
|
||
|
||
document.getElementById('status-order-id').textContent = currentOrder.order_id;
|
||
document.getElementById('status-amount').textContent = currentOrder.total_amount.toFixed(2);
|
||
|
||
paymentStatus.style.display = 'flex';
|
||
|
||
// 开始监听支付状态
|
||
startPaymentStatusCheck();
|
||
}
|
||
|
||
// 开始支付状态检查
|
||
function startPaymentStatusCheck() {
|
||
// 每10秒检查一次支付状态
|
||
const checkInterval = setInterval(async () => {
|
||
const status = await checkPaymentStatus();
|
||
if (status === 'finished' || status === 'failed') {
|
||
clearInterval(checkInterval);
|
||
}
|
||
}, 10000);
|
||
}
|
||
|
||
// 检查支付状态
|
||
async function checkPaymentStatus() {
|
||
if (!currentOrder) return;
|
||
|
||
try {
|
||
const response = await fetch(`/api/orders/${currentOrder.order_id}`);
|
||
const order = await response.json();
|
||
|
||
const statusIcon = document.getElementById('status-icon');
|
||
const statusTitle = document.getElementById('status-title');
|
||
const statusMessage = document.getElementById('status-message');
|
||
|
||
switch (order.payment_status) {
|
||
case 'finished':
|
||
statusIcon.innerHTML = '<div class="success-icon">✓</div>';
|
||
statusTitle.textContent = '支付成功!';
|
||
statusMessage.textContent = '您的订单已确认,我们将尽快处理并发货。';
|
||
break;
|
||
case 'failed':
|
||
case 'expired':
|
||
statusIcon.innerHTML = '<div class="error-icon">✗</div>';
|
||
statusTitle.textContent = '支付失败';
|
||
statusMessage.textContent = '支付未完成或已过期,请重新下单。';
|
||
break;
|
||
case 'confirming':
|
||
statusTitle.textContent = '支付确认中...';
|
||
statusMessage.textContent = '我们已收到您的支付,正在等待区块链确认。';
|
||
break;
|
||
default:
|
||
statusTitle.textContent = '等待支付...';
|
||
statusMessage.textContent = '请完成USDT支付,我们正在等待您的交易。';
|
||
}
|
||
|
||
return order.payment_status;
|
||
} catch (error) {
|
||
console.error('检查支付状态失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 工具函数:验证邮箱
|
||
function validateEmail(email) {
|
||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
return emailRegex.test(email);
|
||
}
|
||
|
||
// 工具函数:验证电话号码
|
||
function validatePhone(phone) {
|
||
const phoneRegex = /^[\d\s\-\+\(\)]+$/;
|
||
return phoneRegex.test(phone);
|
||
}
|
||
|
||
// 管理员登录相关函数
|
||
function showAdminLogin() {
|
||
document.getElementById('adminLoginModal').style.display = 'flex';
|
||
document.getElementById('adminPassword').focus();
|
||
}
|
||
|
||
function closeAdminLogin() {
|
||
document.getElementById('adminLoginModal').style.display = 'none';
|
||
document.getElementById('adminPassword').value = '';
|
||
document.getElementById('loginError').style.display = 'none';
|
||
}
|
||
|
||
function verifyAdminPassword() {
|
||
const password = document.getElementById('adminPassword').value;
|
||
const errorDiv = document.getElementById('loginError');
|
||
|
||
if (password === '223388') {
|
||
// 密码正确,跳转到管理页面
|
||
window.location.href = '/admin.html';
|
||
} else {
|
||
// 密码错误
|
||
errorDiv.textContent = '密码错误,请重新输入';
|
||
errorDiv.style.display = 'block';
|
||
document.getElementById('adminPassword').value = '';
|
||
document.getElementById('adminPassword').focus();
|
||
}
|
||
}
|
||
|
||
// 键盘事件监听
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
closeAdminLogin();
|
||
}
|
||
});
|
||
|
||
// 管理员登录密码框回车事件
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const adminPasswordInput = document.getElementById('adminPassword');
|
||
if (adminPasswordInput) {
|
||
adminPasswordInput.addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
verifyAdminPassword();
|
||
}
|
||
});
|
||
}
|
||
}); |