Files

349 lines
13 KiB
HTML
Raw Permalink Normal View History

2026-01-11 18:14:42 +08:00
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>支付订单</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
<style>
:root {
--bg-body: #f8fafc;
--primary: #0f172a;
--accent: #3b82f6;
}
body {
background: var(--bg-body);
padding-bottom: 120px;
font-family: -apple-system, sans-serif;
color: #334155;
}
/* 顶部导航 */
.nav-header {
position: fixed; top: 0; left: 0; right: 0; height: 50px;
background: #fff; display: flex; align-items: center; justify-content: space-between;
padding: 0 16px; z-index: 1000; box-shadow: 0 1px 0 rgba(0,0,0,0.05);
}
.nav-title { font-size: 16px; font-weight: 600; }
.btn-back { border: none; background: transparent; font-size: 20px; padding: 0; }
/* 通用卡片 */
.section-card {
background: #fff; margin: 16px; padding: 16px; border-radius: 16px;
box-shadow: 0 1px 2px rgba(0,0,0,0.02);
}
.card-header {
font-size: 14px; font-weight: 700; margin-bottom: 12px; display: flex; align-items: center;
}
.card-header i { margin-right: 6px; color: #64748b; font-size: 16px; }
/* 订单金额 */
.amount-display {
text-align: center; padding: 24px 0;
}
.amount-label {
font-size: 13px; color: #94a3b8; margin-bottom: 8px;
}
.amount-value {
font-size: 36px; font-weight: 800; color: var(--primary);
}
/* 商品简要信息 */
.product-summary {
display: flex; align-items: center; margin-bottom: 12px;
}
.product-summary:last-child { margin-bottom: 0; }
.summary-img {
width: 50px; height: 50px; border-radius: 8px; object-fit: cover;
background: #f1f5f9; margin-right: 12px; flex-shrink: 0;
}
.summary-info { flex: 1; }
.summary-name {
font-size: 14px; font-weight: 600; color: var(--primary);
margin-bottom: 2px;
}
.summary-detail {
font-size: 12px; color: #94a3b8;
}
.summary-price {
font-size: 14px; font-weight: 600; color: var(--primary);
}
/* 支付方式 */
.pay-option {
display: flex; align-items: center; padding: 16px; border-radius: 12px;
border: 2px solid #f1f5f9; margin-bottom: 12px; cursor: pointer;
transition: all 0.2s; background: #fff;
}
.pay-option:last-child { margin-bottom: 0; }
.pay-option:hover {
border-color: var(--accent);
background: #f8fafc;
}
.pay-option.selected {
border-color: var(--primary);
background: #f8fafc;
}
.pay-icon {
font-size: 32px; margin-right: 16px; width: 40px; text-align: center;
}
.pay-wechat { color: #07c160; }
.pay-alipay { color: #1677ff; }
.pay-info { flex: 1; }
.pay-name {
font-size: 15px; font-weight: 600; color: var(--primary);
margin-bottom: 2px;
}
.pay-desc {
font-size: 12px; color: #94a3b8;
}
.pay-radio {
width: 20px; height: 20px; accent-color: var(--primary);
}
/* 底部操作栏 */
.bottom-bar {
position: fixed; bottom: 0; left: 0; right: 0;
background: #fff; padding: 12px 20px 30px;
box-shadow: 0 -4px 16px rgba(0,0,0,0.05);
display: flex; justify-content: space-between; align-items: center; z-index: 100;
}
.total-area { display: flex; flex-direction: column; align-items: flex-end; }
.total-label { font-size: 12px; color: #64748b; }
.total-val { font-size: 24px; font-weight: 800; color: var(--primary); }
.btn-pay {
background: var(--primary); color: #fff; border: none;
padding: 14px 40px; border-radius: 12px; font-weight: 600; font-size: 16px;
}
.btn-pay:active { transform: scale(0.98); opacity: 0.9; }
.btn-pay:disabled { background: #cbd5e1; }
</style>
</head>
<body>
<!-- 顶部导航 -->
<div class="nav-header">
<button class="btn-back" onclick="history.back()"><i class="bi bi-arrow-left"></i></button>
<span class="nav-title">支付订单</span>
<div style="width: 24px;"></div>
</div>
<div style="height: 50px;"></div>
<!-- 订单金额 -->
<div class="section-card">
<div class="amount-display">
<div class="amount-label">需支付</div>
<div class="amount-value" id="totalAmount">¥0.00</div>
</div>
</div>
<!-- 商品简要信息 -->
<div class="section-card">
<div class="card-header"><i class="bi bi-bag-fill"></i> 订单商品</div>
<div id="productList"></div>
</div>
<!-- 支付方式 -->
<div class="section-card">
<div class="card-header"><i class="bi bi-credit-card-fill"></i> 选择支付方式</div>
<label class="pay-option" id="payWechat">
<i class="bi bi-wechat pay-icon pay-wechat"></i>
<div class="pay-info">
<div class="pay-name">微信支付</div>
<div class="pay-desc">推荐使用微信支付</div>
</div>
<input type="radio" name="payMethod" value="wechat" class="pay-radio" checked>
</label>
<label class="pay-option" id="payAlipay">
<i class="bi bi-alipay pay-icon pay-alipay"></i>
<div class="pay-info">
<div class="pay-name">支付宝</div>
<div class="pay-desc">安全便捷的支付方式</div>
</div>
<input type="radio" name="payMethod" value="alipay" class="pay-radio">
</label>
</div>
<!-- 底部操作栏 -->
<div class="bottom-bar">
<div class="total-area">
<span class="total-label">合计</span>
<span class="total-val" id="bottomTotal">¥0.00</span>
</div>
<button class="btn-pay" onclick="submitPayment()">立即支付</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="/static/js/ui-enhancements.js"></script>
<script src="/static/js/custom-modal.js"></script>
<script>
let orderId = null;
let orderData = null;
// 初始化
(async () => {
// 从URL获取订单ID
const params = new URLSearchParams(location.search);
orderId = params.get('orderId');
if (!orderId) {
alert('订单ID不存在');
history.back();
return;
}
try {
await loadOrderDetail();
} catch(e) {
console.error('初始化失败:', e);
alert('页面加载失败,请刷新重试');
}
})();
// 加载订单详情
async function loadOrderDetail() {
try {
const res = await fetch(`/order/orders/${orderId}`, { credentials: 'include' });
if (!res.ok) {
throw new Error(`HTTP错误: ${res.status}`);
}
const data = await res.json();
console.log('订单详情响应:', data);
if (data.code === 200 && data.data) {
orderData = data.data;
console.log('订单数据:', orderData);
renderOrder();
} else {
const errorMsg = data.message || '加载订单失败';
console.error('加载订单失败:', errorMsg, data);
alert(errorMsg);
history.back();
}
} catch(e) {
console.error('加载订单详情失败:', e);
alert('加载失败: ' + (e.message || '网络错误'));
history.back();
}
}
function renderOrder() {
if (!orderData || !orderData.order) {
alert('订单数据异常');
history.back();
return;
}
const order = orderData.order;
const items = orderData.items || [];
const productImages = orderData.productImages || {};
// 显示金额
const totalAmount = order.totalAmount || 0;
document.getElementById('totalAmount').textContent = '¥' + totalAmount.toFixed(2);
document.getElementById('bottomTotal').textContent = '¥' + totalAmount.toFixed(2);
// 显示商品列表最多显示3个超过显示"等X件商品"
if (items.length === 0) {
document.getElementById('productList').innerHTML = '<div class="text-center text-muted small py-2">暂无商品信息</div>';
} else {
const displayItems = items.slice(0, 3);
const moreCount = items.length - 3;
let html = '';
displayItems.forEach(item => {
if (!item) return;
const productId = item.productId || item.id;
const image = (productImages && productImages[productId]) || '/static/images/default.jpg';
const productName = item.productName || '商品';
const specName = item.specName || '';
const quantity = item.quantity || 1;
const price = item.price || 0;
html += `
<div class="product-summary">
<img src="${image}" class="summary-img" alt="${productName}">
<div class="summary-info">
<div class="summary-name">${productName}</div>
<div class="summary-detail">${specName ? specName + ' ' : ''}x${quantity}</div>
</div>
<div class="summary-price">¥${parseFloat(price).toFixed(2)}</div>
</div>
`;
});
if (moreCount > 0) {
html += `<div class="text-center text-muted small mt-2">等${items.length}件商品</div>`;
}
document.getElementById('productList').innerHTML = html;
}
// 绑定支付方式选择
document.querySelectorAll('input[name="payMethod"]').forEach(radio => {
radio.addEventListener('change', function() {
document.querySelectorAll('.pay-option').forEach(opt => {
opt.classList.remove('selected');
});
if (this.value === 'wechat') {
document.getElementById('payWechat').classList.add('selected');
} else {
document.getElementById('payAlipay').classList.add('selected');
}
});
});
// 默认选中微信支付
document.getElementById('payWechat').classList.add('selected');
}
// 提交支付
async function submitPayment() {
const payMethod = document.querySelector('input[name="payMethod"]:checked').value;
const btn = document.querySelector('.btn-pay');
// 确认支付
const confirmed = await new Promise((resolve) => {
if (typeof confirmAction !== 'undefined') {
confirmAction('确认支付?', '确认支付', '确认', '取消').then(resolve);
} else {
resolve(confirm('确认支付?'));
}
});
if (!confirmed) return;
btn.disabled = true;
btn.textContent = '支付中...';
try {
const res = await fetch(`/order/${orderId}/pay`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ paymentMethod: payMethod }),
credentials: 'include'
});
const d = await res.json();
if (d.code === 200) {
// 跳转到支付成功页面
const order = orderData && orderData.order ? orderData.order : {};
const orderNo = order.orderNo || '';
const amount = order.totalAmount || 0;
window.location.href = `/payment-success.html?orderId=${orderId}&orderNo=${orderNo}&amount=${amount}`;
} else {
alert(d.message || '支付失败');
btn.disabled = false;
btn.textContent = '立即支付';
}
} catch(e) {
console.error(e);
alert('支付失败,请重试');
btn.disabled = false;
btn.textContent = '立即支付';
}
}
</script>
</body>
</html>