/** * AKSRT Order Center — v2.0 * * 前台订单中心交互: * - 支付 / 取消 / 售后:操作成功后局部刷新订单卡片,不再整页 reload * - 倒计时 * - Toast 通知替代 window.alert * * @package AKSRT */ (function () { "use strict"; var page = document.querySelector("[data-aksrt-order-center]"); if (!page || !window.aksrtData) { return; } /* ── Toast helper ── */ function showToast(text, duration) { duration = duration || 2500; var container = document.getElementById("toast-container"); if (!container) { container = document.createElement("div"); container.id = "toast-container"; container.style.cssText = "position:fixed;bottom:24px;right:24px;z-index:99999;display:flex;flex-direction:column-reverse;gap:10px;pointer-events:none;"; document.body.appendChild(container); } var toast = document.createElement("div"); toast.style.cssText = "pointer-events:auto;display:flex;align-items:center;gap:8px;padding:10px 20px;background:rgba(0,0,0,0.78);backdrop-filter:blur(12px);color:#fff;font-family:var(--font-ui);font-size:14px;font-weight:500;border-radius:100px;box-shadow:0 4px 20px rgba(0,0,0,0.2);animation:aksrtToastIn 0.35s cubic-bezier(0.22,1,0.36,1) forwards;white-space:nowrap;"; toast.textContent = text; container.appendChild(toast); setTimeout(function () { toast.style.animation = "aksrtToastOut 0.4s ease forwards"; setTimeout(function () { if (toast.parentNode) toast.parentNode.removeChild(toast); }, 400); }, duration); } // Inject toast keyframes if not present if (!document.getElementById("aksrt-toast-keyframes")) { var style = document.createElement("style"); style.id = "aksrt-toast-keyframes"; style.textContent = "@keyframes aksrtToastIn{0%{opacity:0;transform:translateY(16px) scale(0.92)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes aksrtToastOut{0%{opacity:1;transform:translateY(0) scale(1)}100%{opacity:0;transform:translateY(8px) scale(0.95)}}"; document.head.appendChild(style); } /* ── REST helper ── */ function restRoot() { return ((aksrtData.siteUrl || "").replace(/\/$/, "")) + "/wp-json/aksrt/v1"; } function request(path, body, method) { var opts = { method: method || "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", "X-WP-Nonce": (aksrtData && aksrtData.restNonce) || "" } }; if (body !== undefined) { opts.body = JSON.stringify(body || {}); } return fetch(restRoot() + path, opts).then(function (response) { return response.text().then(function (text) { var data = {}; try { data = text ? JSON.parse(text) : {}; } catch (e) { data = { success: false, message: response.status === 404 ? "支付接口未找到(404),请刷新页面或联系管理员。" : ("请求失败(HTTP " + response.status + ")") }; } if (typeof data.success === "undefined" && response.ok === false) { data.success = false; data.message = data.message || data.code || ("HTTP " + response.status); } return data; }); }); } function orderPath(orderNumber, suffix) { var base = "/shop/frontend/orders/" + encodeURIComponent(orderNumber || ""); return suffix ? base + suffix : base; } /* ── Order review modal (zibll 1:1) ── */ var STAR_SVG = ''; var SCORE_LABELS = ["", "非常差", "较差", "一般", "较好", "非常好"]; function formatRemain(sec) { sec = Math.max(0, sec | 0); var d = Math.floor(sec / 86400); var h = Math.floor((sec % 86400) / 3600); var m = Math.floor((sec % 3600) / 60); var s = sec % 60; function z(n) { return n < 10 ? "0" + n : String(n); } if (d > 0) return d + "天" + z(h) + ":" + z(m) + ":" + z(s); return z(h) + ":" + z(m) + ":" + z(s); } function bindShopScore(root) { if (!root) return; root.querySelectorAll("[data-aksrt-score-box], .shop-score-box").forEach(function (box) { if (box.dataset.scoreBound === "1") return; box.dataset.scoreBound = "1"; var iconBox = box.querySelector(".score-icon"); var textBox = box.querySelector(".score-text"); var input = box.querySelector(".score-input"); if (!iconBox) return; var value = parseInt(box.getAttribute("score-value") || (input && input.value) || "0", 10) || 0; var html = ""; for (var i = 1; i <= 5; i++) { html += '' + STAR_SVG + ""; } iconBox.innerHTML = html; function paint(score, hover) { iconBox.querySelectorAll(".icon-star").forEach(function (star) { var s = parseInt(star.getAttribute("data-score"), 10) || 0; star.classList.toggle("active", !hover && s <= score); star.classList.toggle("hover", !!hover && s <= score); }); if (textBox) textBox.textContent = SCORE_LABELS[score] || ""; } paint(value, false); iconBox.addEventListener("mouseover", function (e) { var star = e.target.closest(".icon-star"); if (!star || !iconBox.contains(star)) return; paint(parseInt(star.getAttribute("data-score"), 10) || 0, true); }); iconBox.addEventListener("mouseleave", function () { var cur = parseInt(box.getAttribute("score-value") || "0", 10) || 0; paint(cur, false); }); iconBox.addEventListener("click", function (e) { var star = e.target.closest(".icon-star"); if (!star || !iconBox.contains(star)) return; var score = parseInt(star.getAttribute("data-score"), 10) || 0; box.setAttribute("score-value", String(score)); if (input) input.value = String(score); paint(score, false); }); }); } function bindReviewImages(form) { var preview = form.querySelector("[data-aksrt-review-preview]"); var fileInput = form.querySelector("[data-aksrt-review-file]"); var addBtn = form.querySelector("[data-aksrt-review-add]"); if (!preview || !fileInput) return; var max = parseInt(preview.getAttribute("data-max") || "6", 10) || 6; var files = []; function render() { preview.querySelectorAll(".preview-item").forEach(function (n) { n.remove(); }); files.forEach(function (item, idx) { var node = document.createElement("div"); node.className = "preview-item"; node.innerHTML = ''; node.querySelector("img").src = item.url; node.querySelector(".remove").addEventListener("click", function (e) { e.preventDefault(); e.stopPropagation(); if (item.url && item.url.indexOf("blob:") === 0) { try { URL.revokeObjectURL(item.url); } catch (err) {} } files.splice(idx, 1); render(); }); preview.insertBefore(node, addBtn); }); if (addBtn) addBtn.style.display = files.length >= max ? "none" : ""; form._aksrtReviewFiles = files.slice(); } function onPick() { if (files.length >= max) return; fileInput.click(); } if (addBtn) { addBtn.addEventListener("click", onPick); addBtn.addEventListener("keydown", function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onPick(); } }); } fileInput.addEventListener("change", function () { var list = Array.prototype.slice.call(fileInput.files || []); list.forEach(function (file) { if (files.length >= max) return; if (!file.type || file.type.indexOf("image/") !== 0) return; files.push({ file: file, url: URL.createObjectURL(file) }); }); fileInput.value = ""; render(); }); form._aksrtReviewFiles = []; render(); } function bindReviewCountdown(root) { var el = root.querySelector("[data-aksrt-review-countdown]"); if (!el) return; var remain = parseInt(el.getAttribute("data-aksrt-review-countdown") || "0", 10) || 0; if (remain <= 0) return; el.textContent = formatRemain(remain); var timer = window.setInterval(function () { remain -= 1; if (remain <= 0) { window.clearInterval(timer); el.textContent = "交易已关闭"; return; } el.textContent = formatRemain(remain); }, 1000); root._aksrtReviewTimer = timer; } function fileToDataUrl(file) { return new Promise(function (resolve, reject) { var reader = new FileReader(); reader.onload = function () { resolve(String(reader.result || "")); }; reader.onerror = function () { reject(new Error("read failed")); }; reader.readAsDataURL(file); }); } function openOrderReviewModal(orderNumber, triggerBtn) { if (!window.AksrtRemoteModal || typeof window.AksrtRemoteModal.openRemote !== "function") { showToast("评价组件未加载"); return; } if (triggerBtn) triggerBtn.disabled = true; var url = restRoot() + orderPath(orderNumber, "/review-modal"); window.AksrtRemoteModal.openRemote({ url: url, className: "modal-mini full-sm", height: 380, mobileBottom: true }).then(function (shell) { if (triggerBtn) triggerBtn.disabled = false; if (!shell) return; var form = shell.querySelector("[data-aksrt-order-review-form]"); if (!form) return; bindShopScore(shell); bindReviewImages(form); bindReviewCountdown(shell); form.addEventListener("submit", function (e) { e.preventDefault(); var errBox = form.querySelector("[data-aksrt-review-error]"); function showErr(msg) { if (errBox) { errBox.hidden = false; errBox.textContent = msg; } else { showToast(msg); } } if (errBox) { errBox.hidden = true; errBox.textContent = ""; } var productId = parseInt(form.getAttribute("data-product-id") || "0", 10) || 0; var needShipping = form.getAttribute("data-need-shipping") === "1"; var scoreProduct = parseInt((form.querySelector('input[name="score[product]"]') || {}).value || "0", 10) || 0; var scoreService = parseInt((form.querySelector('input[name="score[service]"]') || {}).value || "0", 10) || 0; var scoreShipping = parseInt((form.querySelector('input[name="score[shipping]"]') || {}).value || "0", 10) || 0; if (scoreProduct < 1 || scoreService < 1) { showErr("请对商品进行评分"); return; } if (needShipping && scoreShipping < 1) { showErr("请对物流服务进行评分"); return; } var comment = (form.querySelector('textarea[name="comment"]') || {}).value || ""; var submitBtn = form.querySelector("[data-aksrt-review-submit]"); if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = "提交中…"; } var pending = form._aksrtReviewFiles || []; Promise.all(pending.map(function (item) { return item.file ? fileToDataUrl(item.file) : Promise.resolve(item.url || ""); })).then(function (images) { images = images.filter(Boolean); return request(orderPath(orderNumber, "/review"), { product_id: productId, content: comment, rating_product: scoreProduct, rating_service: scoreService, rating_shipping: needShipping ? scoreShipping : scoreService, images: images }); }).then(function (result) { if (submitBtn) { submitBtn.disabled = false; submitBtn.innerHTML = ' 确认提交'; } if (!result || !result.success) { showErr((result && result.message) || "评价失败"); return; } showToast((result.message) || "评价成功"); if (window.AksrtRemoteModal) window.AksrtRemoteModal.close(); var card = findOrderCard(orderNumber); updateCardStatus(card, "completed", "已完成"); if (card) { var btn = card.querySelector("[data-aksrt-order-review]"); if (btn) btn.remove(); } }).catch(function () { if (submitBtn) { submitBtn.disabled = false; submitBtn.innerHTML = ' 确认提交'; } showErr("网络错误"); }); }); }).catch(function (err) { if (triggerBtn) triggerBtn.disabled = false; showToast((err && err.message) || "无法打开评价"); }); } /* ── 扫码支付弹层(微信 Native code_url 等)── */ function showPaymentQr(content, orderNumber) { var existing = document.getElementById("aksrt-pay-qr-overlay"); if (existing) existing.remove(); var overlay = document.createElement("div"); overlay.id = "aksrt-pay-qr-overlay"; overlay.style.cssText = "position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.5);"; var qrImg = ""; if (window.AksrtShare && typeof window.AksrtShare.buildQrDataUrl === "function") { var dataUrl = window.AksrtShare.buildQrDataUrl(content, 220); if (dataUrl) { qrImg = '支付二维码'; } } if (!qrImg) { qrImg = '

' + String(content).replace(/[<>&]/g, "") + "

"; } var card = document.createElement("div"); card.style.cssText = "background:#fff;border-radius:12px;padding:24px;max-width:300px;text-align:center;box-shadow:0 10px 40px rgba(0,0,0,0.2);"; card.innerHTML = '

请扫码完成支付

' + qrImg + '

支付完成后本页将自动更新

' + ''; overlay.appendChild(card); document.body.appendChild(overlay); function close() { overlay.remove(); } overlay.addEventListener("click", function (e) { if (e.target === overlay) close(); }); card.querySelector("#aksrt-pay-qr-close").addEventListener("click", function () { close(); // 关闭后查询订单是否已到账 if (orderNumber) { request(orderPath(orderNumber), {}, "GET").then(function () { window.location.reload(); }).catch(function () {}); } }); } /* ── 第三方支付返回提示(?payment=success|pending|cancelled)── */ (function paymentReturnNotice() { var params = new URLSearchParams(window.location.search); var pay = params.get("payment"); if (!pay) return; var map = { success: "支付成功!", pending: "支付处理中,到账后将自动更新。", cancelled: "支付已取消。", fail: "支付失败,请重试。" }; showToast(map[pay] || "支付状态:" + pay, 3500); })(); /* ── Local card refresh helpers ── */ function findOrderCard(orderNumber) { return page.querySelector('[data-aksrt-order-card="' + orderNumber + '"]'); } function escapeHtml(value) { return String(value == null ? "" : value) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function formatMoney(order) { var amount = Number(order && order.amount != null ? order.amount : 0); if (order && order.is_points) { var symbol = order.currency_symbol || "积分"; return escapeHtml(symbol) + " " + Math.round(amount); } return "¥" + amount.toFixed(2); } /** Plain money for table cells (formatMoney already escapes). */ function formatMoneyText(order) { var amount = Number(order && order.amount != null ? order.amount : 0); if (order && order.is_points) { var symbol = order.currency_symbol || "积分"; return String(symbol) + " " + Math.round(amount); } return "¥" + amount.toFixed(2); } function updateCardStatus(card, newStatus, statusLabel) { if (!card) return; if (newStatus) { card.setAttribute("data-order-status", newStatus); } var badge = card.querySelector(".aksrt-orders-page__card-status, .aksrt-orders-page__item-badge"); if (badge) { badge.textContent = statusLabel || newStatus; } // Hide action buttons that are no longer relevant var actions = card.querySelectorAll("[data-aksrt-order-pay], [data-aksrt-order-cancel]"); for (var i = 0; i < actions.length; i++) { actions[i].style.display = "none"; } // Hide countdown if present var countdown = card.querySelector("[data-aksrt-order-countdown]"); if (countdown) { countdown.style.display = "none"; } } /* ── Order detail modal ── */ var detailModal = page.querySelector("[data-aksrt-order-detail-modal]"); var detailBody = page.querySelector("[data-aksrt-order-detail-body]"); var detailFooter = page.querySelector("[data-aksrt-order-detail-footer]"); var detailOrderNumber = ""; function closeOrderDetailModal() { if (detailModal) detailModal.hidden = true; detailOrderNumber = ""; document.documentElement.classList.remove("aksrt-modal-open"); } document.addEventListener("keydown", function (event) { if (event.key === "Escape" && detailModal && !detailModal.hidden) { closeOrderDetailModal(); } }); function openOrderDetailModal(orderNumber) { if (!detailModal || !detailBody || !detailFooter) { showToast("订单详情组件未加载"); return; } detailOrderNumber = orderNumber || ""; detailBody.innerHTML = '

加载中…

'; detailFooter.innerHTML = ""; detailModal.hidden = false; document.documentElement.classList.add("aksrt-modal-open"); request(orderPath(orderNumber), undefined, "GET").then(function (result) { var order = null; if (result && result.data && result.data.order_number) { order = result.data; } else if (result && result.data && result.data.data && result.data.data.order_number) { order = result.data.data; } else if (result && result.order_number) { order = result; } if (result && result.success === false) { detailBody.innerHTML = '

' + escapeHtml((result && result.message) || "加载失败") + "

"; return; } if (!order || !order.order_number) { detailBody.innerHTML = '

订单不存在

'; return; } renderOrderDetail(order); }).catch(function () { detailBody.innerHTML = '

网络错误,请稍后重试

'; }); } function renderOrderDetail(order) { if (!detailBody || !detailFooter) return; var actions = (order && order.actions) || {}; var payment = order.payment_method || {}; var paymentLabel = payment.label || payment.value || "—"; var qty = order.quantity || 1; if ((!qty || qty < 1) && order.items && order.items.length) { qty = 0; order.items.forEach(function (item) { qty += Math.max(1, parseInt(item.quantity || item.qty || 1, 10) || 1); }); } if (!qty || qty < 1) qty = 1; var status = order.status || ""; var statusLabel = order.status_label || status || "—"; var statusClass = "is-" + String(status).replace(/[^a-z0-9_-]/gi, "-"); var title = order.product_name || (order.product && order.product.title) || "订单"; var image = order.image || (order.product && order.product.image) || ""; if (!image && order.items && order.items.length && order.items[0].image) { image = order.items[0].image; } var orderNo = order.order_number || "—"; // Meta fields only — amount lives in hero; type is already on the list card. var rows = [ { key: "qty", label: "数量", value: "×" + String(qty) }, { key: "no", label: "订单编号", value: orderNo, copyable: true }, { key: "created", label: "创建时间", value: order.created_at || "—" }, { key: "paid", label: "支付时间", value: order.paid_at || "—" }, { key: "pay", label: "支付方式", value: paymentLabel } ]; if (Number(order.shipping_fee || 0) > 0) { rows.push({ key: "ship", label: "运费", value: "¥" + Number(order.shipping_fee || 0).toFixed(2) }); } if (Number(order.discount || 0) > 0) { rows.push({ key: "disc", label: "优惠", value: "-¥" + Number(order.discount || 0).toFixed(2), accent: "discount" }); } if (order.customer_note) { rows.push({ key: "note", label: "备注", value: order.customer_note }); } var html = ""; html += '
'; html += '
'; html += ' ' + escapeHtml(statusLabel) + ""; if (order.product_type_label) { html += ' ' + escapeHtml(order.product_type_label) + ""; } html += "
"; html += '
'; html += ' 应付金额'; html += ' ' + escapeHtml(formatMoneyText(order)) + ""; html += "
"; html += "
"; html += '
'; if (image) { html += ''; } else { html += ''; } html += '
'; html += '
' + escapeHtml(title) + "
"; html += '
'; html += ' 数量 ' + escapeHtml(String(qty)) + ""; if (paymentLabel && paymentLabel !== "—") { html += ' '; html += ' ' + escapeHtml(paymentLabel) + ""; } html += "
"; html += "
"; html += "
"; html += '
'; html += '

订单信息

'; html += '
'; rows.forEach(function (row) { html += '
'; html += '
' + escapeHtml(row.label) + '
'; html += '
'; html += '' + escapeHtml(row.value) + ""; if (row.copyable && orderNo && orderNo !== "—") { html += '"; } html += "
"; html += "
"; }); html += "
"; if (order.items && order.items.length > 1) { html += '
'; html += '

商品明细

'; html += '
"; } if (order.timeline && order.timeline.length) { // Newest first for a natural "latest activity on top" feel. var timeline = order.timeline.slice().reverse(); html += '
'; html += '

订单进度

'; html += '
    '; timeline.forEach(function (tl, idx) { html += '
  1. '; html += ''; html += '
    '; html += '' + escapeHtml(tl.label || "") + ""; html += '"; html += "
  2. "; }); html += "
"; } detailBody.innerHTML = html; var footer = ""; // Status-aware footer. Top-right ✕ is the only generic dismiss control. if (actions.can_cancel) { // Two-step cancel inside the modal — no window.confirm. footer += ''; } if (actions.can_pay) { footer += ''; } if (actions.can_view_product && order.permalink) { footer += '查看商品'; } if (footer === "") { footer = ''; } detailFooter.innerHTML = footer; } function copyOrderNumber(code, trigger) { if (!code) return; function done() { showToast("已复制订单号"); if (trigger) { trigger.classList.add("is-copied"); window.setTimeout(function () { trigger.classList.remove("is-copied"); }, 1200); } } if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(code).then(done).catch(function () { showToast(code); }); return; } try { var ta = document.createElement("textarea"); ta.value = code; ta.setAttribute("readonly", ""); ta.style.position = "fixed"; ta.style.opacity = "0"; document.body.appendChild(ta); ta.select(); document.execCommand("copy"); document.body.removeChild(ta); done(); } catch (e) { showToast(code); } } /* ── Countdown timer ── */ function updateCountdowns() { var nodes = page.querySelectorAll("[data-aksrt-order-countdown]"); for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var value = Number(node.getAttribute("data-aksrt-order-countdown") || 0); if (!value) continue; value -= 1; node.setAttribute("data-aksrt-order-countdown", String(value)); node.textContent = value > 0 ? "剩余支付时间 " + value + " 秒" : "待支付已超时,请重新发起。"; } } setInterval(updateCountdowns, 1000); /* ── Event delegation ── */ page.addEventListener("click", function (event) { // Order detail open var detailBtn = event.target.closest("[data-aksrt-order-detail]"); if (detailBtn && !event.target.closest("[data-aksrt-order-detail-modal]")) { var detailOrder = detailBtn.getAttribute("data-aksrt-order-detail"); if (detailOrder) openOrderDetailModal(detailOrder); return; } // Copy order number inside detail modal var copyBtn = event.target.closest("[data-aksrt-copy-order]"); if (copyBtn) { event.preventDefault(); copyOrderNumber(copyBtn.getAttribute("data-aksrt-copy-order") || "", copyBtn); return; } // Order detail close if (event.target.closest("[data-aksrt-order-detail-close]")) { closeOrderDetailModal(); return; } // Timeline toggle var timelineToggle = event.target.closest("[data-aksrt-toggle-timeline]"); if (timelineToggle) { var timeline = timelineToggle.closest("[data-aksrt-timeline]"); var body = timeline ? timeline.querySelector(".aksrt-orders-page__timeline-body") : null; if (body) body.hidden = !body.hidden; return; } // Review modal (zibll order_comment_modal 1:1 UX) var reviewBtn = event.target.closest("[data-aksrt-order-review]"); if (reviewBtn) { var reviewOrder = reviewBtn.getAttribute("data-aksrt-order-review"); if (!reviewOrder) return; closeOrderDetailModal(); openOrderReviewModal(reviewOrder, reviewBtn); return; } // Pay var payButton = event.target.closest("[data-aksrt-order-pay]"); if (payButton) { var payOrderNumber = payButton.getAttribute("data-aksrt-order-pay"); // 支付方式取订单创建时选定的方式(按钮 data 属性可覆盖); // 留空则由服务端使用订单存储的 payment_method。 var payMethod = payButton.getAttribute("data-aksrt-order-method") || ""; var payLabel = payButton.textContent || "去支付"; payButton.disabled = true; payButton.textContent = "处理中..."; request(orderPath(payOrderNumber, "/pay"), payMethod ? { payment_method: payMethod } : {}) .then(function (result) { if (!result.success) { payButton.disabled = false; payButton.textContent = payLabel; showToast(result.message || "支付失败。"); return; } var data = result.data || {}; // 跳转/扫码型网关:到第三方支付页或展示二维码,订单仍为待支付, // 由回调确认到账。 if (data.redirect) { if (data.payment_url && /^https?:\/\//i.test(data.payment_url)) { window.location.href = data.payment_url; return; } if (data.qr_content || data.payment_url) { showPaymentQr(data.qr_content || data.payment_url, payOrderNumber); payButton.disabled = false; payButton.textContent = "已下单,待支付"; return; } } // 同步型网关(站内余额):已到账。 showToast("支付成功!"); var card = findOrderCard(payOrderNumber); updateCardStatus(card, "paid", "已支付"); if (detailOrderNumber === payOrderNumber) { closeOrderDetailModal(); } }) .catch(function () { payButton.disabled = false; payButton.textContent = payLabel; showToast("网络错误,请稍后重试。"); }); return; } // Cancel — two-step in detail modal (关闭订单 → 确认取消), list card same. var cancelButton = event.target.closest("[data-aksrt-order-cancel]"); if (cancelButton) { var cancelOrderNumber = cancelButton.getAttribute("data-aksrt-order-cancel"); if (!cancelOrderNumber) return; // First click: transform into "确认取消" (no browser confirm dialog). var step = cancelButton.getAttribute("data-aksrt-cancel-step") || "1"; if (step !== "2") { cancelButton.setAttribute("data-aksrt-cancel-step", "2"); cancelButton.classList.remove("btn-ghost"); cancelButton.classList.add("btn-primary", "is-cancel-confirm"); cancelButton.textContent = "确认取消"; // Auto-reset if user doesn't confirm within a few seconds. if (cancelButton._aksrtCancelReset) { window.clearTimeout(cancelButton._aksrtCancelReset); } cancelButton._aksrtCancelReset = window.setTimeout(function () { if (!cancelButton.isConnected) return; if (cancelButton.getAttribute("data-aksrt-cancel-step") !== "2") return; cancelButton.setAttribute("data-aksrt-cancel-step", "1"); cancelButton.classList.add("btn-ghost"); cancelButton.classList.remove("btn-primary", "is-cancel-confirm"); // Detail modal uses "关闭订单"; list cards use "取消". var inDetail = !!(detailModal && detailModal.contains(cancelButton)); cancelButton.textContent = inDetail ? "关闭订单" : "取消"; }, 5000); return; } if (cancelButton._aksrtCancelReset) { window.clearTimeout(cancelButton._aksrtCancelReset); cancelButton._aksrtCancelReset = null; } cancelButton.disabled = true; cancelButton.textContent = "取消中..."; request(orderPath(cancelOrderNumber, "/cancel")) .then(function (result) { if (!result.success) { cancelButton.disabled = false; cancelButton.setAttribute("data-aksrt-cancel-step", "1"); cancelButton.classList.add("btn-ghost"); cancelButton.classList.remove("btn-primary", "is-cancel-confirm"); var inDetailFail = !!(detailModal && detailModal.contains(cancelButton)); cancelButton.textContent = inDetailFail ? "关闭订单" : "取消"; showToast(result.message || "取消失败。"); return; } showToast("订单已取消。"); var card = findOrderCard(cancelOrderNumber); updateCardStatus(card, "cancelled", "已取消"); if (detailOrderNumber === cancelOrderNumber) { // Refresh modal body with cancelled timeline, then close shortly. if (result.data && result.data.order) { renderOrderDetail(result.data.order); } window.setTimeout(function () { closeOrderDetailModal(); }, 600); } }) .catch(function () { cancelButton.disabled = false; cancelButton.setAttribute("data-aksrt-cancel-step", "1"); cancelButton.classList.add("btn-ghost"); cancelButton.classList.remove("btn-primary", "is-cancel-confirm"); var inDetailErr = !!(detailModal && detailModal.contains(cancelButton)); cancelButton.textContent = inDetailErr ? "关闭订单" : "取消"; showToast("网络错误,请稍后重试。"); }); return; } }); /* ── Coupon wallet ── */ var couponRoot = page.querySelector("[data-aksrt-coupon-wallet-list]"); if (couponRoot) { request("/shop/frontend/coupons").then(function (result) { var items = (result && result.data && result.data.items) || (result && result.items) || []; // normalize success envelope if (result && result.data && result.data.data && result.data.data.items) { items = result.data.data.items; } if (result && result.success && result.data && result.data.items) { items = result.data.items; } // handle this success() wrapper: {success,data:{items}} if (Array.isArray(result && result.data)) items = result.data; if (!items.length && result && result.data && Array.isArray(result.data.items)) { items = result.data.items; } // fallback parse try { if (!items.length && result && result.data && result.data.data) { items = result.data.data.items || []; } } catch (e) {} if (!items || !items.length) { couponRoot.innerHTML = '

暂无可用优惠券

'; return; } var html = '
'; items.forEach(function (c) { var val = c.type === "percent" ? (c.value + "%") : ("¥" + Number(c.value || 0).toFixed(2)); html += '
'; html += '
' + val + '
'; html += '
' + (c.code || "") + '
'; if (c.min_amount > 0) { html += '
满 ¥' + Number(c.min_amount).toFixed(2) + ' 可用
'; } if (c.expires_at) { html += '
有效期至 ' + c.expires_at + '
'; } html += ''; html += '
'; }); html += '
'; couponRoot.innerHTML = html; }).catch(function () { couponRoot.innerHTML = '

加载失败

'; }); page.addEventListener("click", function (e) { var b = e.target.closest("[data-aksrt-copy-coupon]"); if (!b) return; var code = b.getAttribute("data-aksrt-copy-coupon") || ""; if (!code) return; if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(code).then(function () { showToast("已复制 " + code); }); } else { showToast(code); } }); } })();