qwen_agent/skills/developing/ecommerce-storefront/apps/order-confirm.html
2026-05-23 13:53:10 +08:00

234 lines
9.7 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order Confirmation</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f7; padding: 20px; }
.order-card { background: #fff; border-radius: 16px; border: 1px solid #e5e5ea; overflow: hidden; max-width: 480px; margin: 0 auto; }
.order-header { padding: 20px 24px 16px; border-bottom: 1px solid #f0f0f0; }
.order-title { font-size: 20px; font-weight: 700; color: #1d1d1f; }
.order-id { font-size: 13px; color: #86868b; margin-top: 4px; }
.order-items { padding: 16px 24px; }
.order-item { display: flex; align-items: center; padding: 12px 0; border-bottom: 1px solid #f5f5f7; }
.order-item:last-child { border-bottom: none; }
.item-img { width: 48px; height: 48px; border-radius: 10px; object-fit: cover; background: #f0f0f0; margin-right: 12px; flex-shrink: 0; }
.item-img-placeholder { width: 48px; height: 48px; border-radius: 10px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex; align-items: center; justify-content: center; color: #fff; font-size: 18px; font-weight: 600; margin-right: 12px; flex-shrink: 0; }
.item-info { flex: 1; min-width: 0; }
.item-name { font-size: 15px; font-weight: 500; color: #1d1d1f; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item-qty { font-size: 13px; color: #86868b; margin-top: 2px; }
.item-price { font-size: 15px; font-weight: 600; color: #1d1d1f; flex-shrink: 0; margin-left: 12px; }
.order-summary { padding: 16px 24px; border-top: 1px solid #e5e5ea; background: #fafafa; }
.summary-row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 14px; color: #6e6e73; }
.summary-row.discount { color: #34c759; }
.summary-row.total { padding-top: 12px; margin-top: 8px; border-top: 1px solid #e5e5ea;
font-size: 18px; font-weight: 700; color: #1d1d1f; }
.payment-section { padding: 20px 24px; }
.payment-qr { display: flex; flex-direction: column; align-items: center; padding: 16px 0; }
.payment-qr img { width: 160px; height: 160px; border-radius: 8px; border: 1px solid #e5e5ea; }
.payment-qr-hint { font-size: 13px; color: #86868b; margin-top: 8px; }
.btn-row { display: flex; gap: 10px; }
.btn { flex: 1; padding: 14px; border: none; border-radius: 12px; font-size: 15px; font-weight: 600; cursor: pointer; transition: all 0.15s; }
.btn-primary { background: #0071e3; color: #fff; }
.btn-primary:hover { background: #0077ed; }
.btn-primary:active { background: #005bb5; }
.btn-secondary { background: #f5f5f7; color: #1d1d1f; border: 1px solid #d1d1d6; }
.btn-secondary:hover { background: #e8e8ed; }
.btn-link { background: #34c759; color: #fff; text-decoration: none; text-align: center; display: block; }
.btn-link:hover { background: #2db84d; }
.success-overlay { display: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0;
background: rgba(255,255,255,0.95); border-radius: 16px;
flex-direction: column; align-items: center; justify-content: center; }
.success-overlay.show { display: flex; }
.success-icon { font-size: 48px; margin-bottom: 12px; }
.success-text { font-size: 18px; font-weight: 600; color: #1d1d1f; }
.success-sub { font-size: 14px; color: #86868b; margin-top: 4px; }
.order-card-wrapper { position: relative; }
</style>
</head>
<body>
<div class="order-card-wrapper">
<div class="order-card" id="order-card"></div>
<div class="success-overlay" id="success-overlay">
<div class="success-icon" id="success-icon"></div>
<div class="success-text" id="success-text"></div>
<div class="success-sub" id="success-sub"></div>
</div>
</div>
<script>
(function () {
function esc(t) { var d = document.createElement('div'); d.textContent = t; return d.innerHTML; }
function render(payload) {
var card = document.getElementById('order-card');
card.innerHTML = '';
var order = payload.order || {};
var payment = payload.payment || {};
var currency = order.currency || '$';
// Header
var header = document.createElement('div');
header.className = 'order-header';
header.innerHTML = '<div class="order-title">' + esc(payload.title || 'Order Confirmation') + '</div>'
+ (order.order_id ? '<div class="order-id">Order #' + esc(order.order_id) + '</div>' : '');
card.appendChild(header);
// Items
var itemsDiv = document.createElement('div');
itemsDiv.className = 'order-items';
(order.items || []).forEach(function (item) {
var row = document.createElement('div');
row.className = 'order-item';
if (item.image) {
var img = document.createElement('img');
img.className = 'item-img';
img.src = item.image;
img.onerror = function () {
var ph = document.createElement('div');
ph.className = 'item-img-placeholder';
ph.textContent = (item.name || 'I').charAt(0).toUpperCase();
row.replaceChild(ph, img);
};
row.appendChild(img);
} else {
var ph = document.createElement('div');
ph.className = 'item-img-placeholder';
ph.textContent = (item.name || 'I').charAt(0).toUpperCase();
row.appendChild(ph);
}
var info = document.createElement('div');
info.className = 'item-info';
info.innerHTML = '<div class="item-name">' + esc(item.name || '') + '</div>'
+ '<div class="item-qty">x' + (item.quantity || 1) + '</div>';
row.appendChild(info);
var price = document.createElement('div');
price.className = 'item-price';
price.textContent = currency + ((item.price || 0) * (item.quantity || 1)).toFixed(2);
row.appendChild(price);
itemsDiv.appendChild(row);
});
card.appendChild(itemsDiv);
// Summary
var summary = document.createElement('div');
summary.className = 'order-summary';
if (order.subtotal !== undefined) {
summary.innerHTML += '<div class="summary-row"><span>Subtotal</span><span>' + currency + (order.subtotal || 0).toFixed(2) + '</span></div>';
}
if (order.tax) {
summary.innerHTML += '<div class="summary-row"><span>Tax</span><span>' + currency + order.tax.toFixed(2) + '</span></div>';
}
if (order.discount) {
summary.innerHTML += '<div class="summary-row discount"><span>Discount</span><span>-' + currency + order.discount.toFixed(2) + '</span></div>';
}
summary.innerHTML += '<div class="summary-row total"><span>Total</span><span>' + currency + (order.total || 0).toFixed(2) + '</span></div>';
card.appendChild(summary);
// Payment
var payDiv = document.createElement('div');
payDiv.className = 'payment-section';
if (payment.method === 'qrcode' && payment.qrcode_url) {
var qrDiv = document.createElement('div');
qrDiv.className = 'payment-qr';
qrDiv.innerHTML = '<img src="' + esc(payment.qrcode_url) + '" alt="Payment QR Code">'
+ '<div class="payment-qr-hint">Scan to pay</div>';
payDiv.appendChild(qrDiv);
}
var btnRow = document.createElement('div');
btnRow.className = 'btn-row';
// Cancel button
var cancelBtn = document.createElement('button');
cancelBtn.className = 'btn btn-secondary';
cancelBtn.textContent = 'Cancel';
cancelBtn.addEventListener('click', function () {
showOverlay('cancelled');
window.parent.postMessage({
type: 'mcp-app-response',
payload: { action: 'cancel', order_id: order.order_id || '' }
}, '*');
});
btnRow.appendChild(cancelBtn);
if (payment.method === 'link' && payment.payment_url) {
var linkBtn = document.createElement('a');
linkBtn.className = 'btn btn-link';
linkBtn.href = payment.payment_url;
linkBtn.target = '_blank';
linkBtn.rel = 'noopener';
linkBtn.textContent = payment.button_text || 'Pay Now';
linkBtn.addEventListener('click', function () {
setTimeout(function () {
showOverlay('confirmed');
window.parent.postMessage({
type: 'mcp-app-response',
payload: { action: 'confirm', order_id: order.order_id || '' }
}, '*');
}, 500);
});
btnRow.appendChild(linkBtn);
} else {
var confirmBtn = document.createElement('button');
confirmBtn.className = 'btn btn-primary';
confirmBtn.textContent = payment.button_text || 'Confirm Payment';
confirmBtn.addEventListener('click', function () {
showOverlay('confirmed');
window.parent.postMessage({
type: 'mcp-app-response',
payload: { action: 'confirm', order_id: order.order_id || '' }
}, '*');
});
btnRow.appendChild(confirmBtn);
}
payDiv.appendChild(btnRow);
card.appendChild(payDiv);
}
function showOverlay(type) {
var overlay = document.getElementById('success-overlay');
var icon = document.getElementById('success-icon');
var text = document.getElementById('success-text');
var sub = document.getElementById('success-sub');
if (type === 'confirmed') {
icon.textContent = '\u2705';
text.textContent = 'Payment Confirmed';
sub.textContent = 'Your order has been placed successfully!';
} else {
icon.textContent = '\u274C';
text.textContent = 'Order Cancelled';
sub.textContent = 'Your order has been cancelled.';
}
overlay.classList.add('show');
}
window.addEventListener('message', function (event) {
var msg = event.data;
if (msg && msg.type === 'mcp-app-data') {
document.getElementById('success-overlay').classList.remove('show');
render(msg.payload);
}
});
window.parent.postMessage({ type: 'mcp-app-ready' }, '*');
})();
</script>
</body>
</html>