Files
wordpress-theme-aksrt/assets/js/order-center.js
T

277 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Knowledge-payment order center interactions.
*
* @package AKSRT
*/
(function () {
"use strict";
var page = document.querySelector("[data-aksrt-order-center]");
if (!page || !window.aksrtData) return;
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 toast(message) {
if (window.AksrtToast && typeof window.AksrtToast.show === "function") {
window.AksrtToast.show(message);
return;
}
window.alert(message);
}
function restRoot() {
return String(aksrtData.siteUrl || "").replace(/\/$/, "") + "/wp-json/aksrt/v1";
}
function request(path, body, method) {
var options = {
method: method || "POST",
credentials: "same-origin",
headers: { "X-WP-Nonce": aksrtData.restNonce || "" }
};
if (body !== undefined) {
options.headers["Content-Type"] = "application/json";
options.body = JSON.stringify(body || {});
}
return fetch(restRoot() + path, options).then(function (response) {
return response.json().catch(function () {
return { success: false, message: "请求失败(HTTP " + response.status + ")" };
});
});
}
function orderPath(orderNumber, suffix) {
return "/orders/" + encodeURIComponent(orderNumber || "") + (suffix || "");
}
function escapeHtml(value) {
return String(value == null ? "" : value)
.replace(/&/g, "&amp;").replace(/</g, "&lt;")
.replace(/>/g, "&gt;").replace(/\"/g, "&quot;")
.replace(/'/g, "&#39;");
}
function formatMoney(order) {
var amount = Number(order && order.amount || 0);
return order && order.is_points
? escapeHtml(order.currency_symbol || "积分") + " " + Math.round(amount)
: "¥" + amount.toFixed(2);
}
function closeDetail() {
if (detailModal) detailModal.hidden = true;
detailOrderNumber = "";
document.documentElement.classList.remove("aksrt-modal-open");
}
function renderDetail(order) {
if (!detailBody || !detailFooter) return;
var actions = order.actions || {};
var image = order.image || "";
var title = order.product_name || "订单";
var status = order.status_group || "closed";
var html = '<div class="aksrt-order-detail__hero is-' + escapeHtml(status) + '">';
html += '<span class="aksrt-order-detail__status-pill is-' + escapeHtml(status) + '">' + escapeHtml(order.status_label || "") + "</span>";
html += '<strong class="aksrt-order-detail__hero-amount">' + formatMoney(order) + "</strong></div>";
html += '<div class="aksrt-order-detail__product">';
html += image ? '<img class="aksrt-order-detail__thumb" src="' + escapeHtml(image) + '" alt="">' : '<span class="aksrt-order-detail__thumb aksrt-order-detail__thumb--empty"><i class="fas fa-book-open"></i></span>';
html += '<div><strong class="aksrt-order-detail__product-title">' + escapeHtml(title) + "</strong>";
html += '<span class="aksrt-order-detail__product-meta">' + escapeHtml(order.product_type_label || "") + "</span></div></div>";
html += '<dl class="aksrt-order-detail__list">';
[["订单编号", order.order_number], ["创建时间", order.created_at], ["支付时间", order.paid_at || "—"]].forEach(function (row) {
html += "<div><dt>" + escapeHtml(row[0]) + "</dt><dd>" + escapeHtml(row[1] || "—") + "</dd></div>";
});
html += "</dl>";
detailBody.innerHTML = html;
var footer = '<button class="btn-outline" type="button" data-aksrt-order-detail-close>关闭</button>';
if (actions.can_cancel) footer += '<button class="btn-ghost" type="button" data-aksrt-order-cancel="' + escapeHtml(order.order_number) + '">关闭订单</button>';
if (actions.can_pay) footer += '<button class="btn-primary" type="button" data-aksrt-order-pay="' + escapeHtml(order.order_number) + '" data-aksrt-order-method="' + escapeHtml((order.payment_method || {}).value || "") + '">继续支付</button>';
if (actions.can_open && order.permalink) footer += '<a class="btn-primary" href="' + escapeHtml(order.permalink) + '">' + escapeHtml(order.entitlement_label || "打开已购内容") + "</a>";
detailFooter.innerHTML = footer;
}
function openDetail(orderNumber) {
if (!detailModal || !detailBody) return;
detailOrderNumber = orderNumber;
detailBody.innerHTML = '<p class="muted-2-color">加载中…</p>';
detailFooter.innerHTML = "";
detailModal.hidden = false;
document.documentElement.classList.add("aksrt-modal-open");
request(orderPath(orderNumber), undefined, "GET").then(function (result) {
if (orderNumber !== detailOrderNumber) return;
if (!result.success || !result.data) {
detailBody.innerHTML = '<p class="c-red">' + escapeHtml(result.message || "订单不存在") + "</p>";
return;
}
renderDetail(result.data);
}).catch(function () {
detailBody.innerHTML = '<p class="c-red">网络错误,请稍后重试</p>';
});
}
function currentViewPath() {
var params = new URLSearchParams(window.location.search);
var allowed = ["order_status", "order_type", "order_number", "order_page"];
var query = new URLSearchParams();
allowed.forEach(function (key) { if (params.get(key)) query.set(key, params.get(key)); });
return "/orders/view" + (query.toString() ? "?" + query.toString() : "");
}
function actionHtml(order) {
var actions = order.actions || {};
var html = '<button class="btn-outline" type="button" data-aksrt-order-detail="' + escapeHtml(order.order_number) + '">订单详情</button>';
if (actions.can_cancel) html += '<button class="btn-ghost" type="button" data-aksrt-order-cancel="' + escapeHtml(order.order_number) + '">关闭订单</button>';
if (actions.can_pay) html += '<button class="btn-primary" type="button" data-aksrt-order-pay="' + escapeHtml(order.order_number) + '" data-aksrt-order-method="' + escapeHtml((order.payment_method || {}).value || '') + '">继续支付</button>';
if (actions.can_open && order.permalink) html += '<a class="btn-primary is-entitlement" href="' + escapeHtml(order.permalink) + '">' + escapeHtml(order.entitlement_label || '打开已购内容') + '</a>';
return html;
}
function cardHtml(order) {
var image = order.image
? '<img class="aksrt-orders-page__card-img" src="' + escapeHtml(order.image) + '" alt="">'
: '<div class="aksrt-orders-page__card-art" aria-hidden="true"><i class="fas fa-book-open"></i></div>';
var countdown = Number(order.time_left || 0) > 0
? '<span class="aksrt-orders-page__countdown" data-aksrt-order-countdown="' + Number(order.time_left) + '"></span>'
: '';
return '<article class="aksrt-orders-page__card" data-aksrt-order-card="' + escapeHtml(order.order_number) + '" data-order-status="' + escapeHtml(order.status_group || '') + '">' +
'<div class="aksrt-orders-page__card-rail"><span>' + escapeHtml(order.product_type_label || '') + '</span><time>' + escapeHtml(order.created_at || '') + '</time><span class="aksrt-orders-page__card-status is-' + escapeHtml(order.status_group || '') + '">' + escapeHtml(order.status_label || '') + '</span></div>' +
'<div class="aksrt-orders-page__card-main">' + image + '<div class="aksrt-orders-page__card-copy"><h3>' + escapeHtml(order.product_name || '订单') + '</h3><p>订单号 ' + escapeHtml(order.order_number) + '</p></div><div class="aksrt-orders-page__card-value"><strong>' + formatMoney(order) + '</strong><span>实付</span></div></div>' +
'<footer class="aksrt-orders-page__card-actions">' + countdown + actionHtml(order) + '</footer></article>';
}
function renderStats(stats) {
var root = page.querySelector('[data-aksrt-order-stats]');
if (!root) return;
root.innerHTML = '<div class="aksrt-orders-page__stat"><span>全部</span><strong>' + Number(stats.total || 0) + '</strong></div>' +
'<div class="aksrt-orders-page__stat"><span>待支付</span><strong class="is-pending">' + Number(stats.pending || 0) + '</strong></div>' +
'<div class="aksrt-orders-page__stat"><span>已生效</span><strong class="is-completed">' + Number(stats.completed || 0) + '</strong></div>';
}
function renderPagination(view) {
var existing = page.querySelector('.aksrt-orders-page__pagination');
if (existing) existing.remove();
if (Number(view.total_pages || 1) <= 1) return;
var root = document.createElement('nav');
root.className = 'aksrt-orders-page__pagination';
root.setAttribute('aria-label', '订单分页');
var base = new URL(window.location.href);
for (var i = 1; i <= Number(view.total_pages); i++) {
base.searchParams.set('order_page', String(i));
var link = document.createElement('a');
link.className = 'aksrt-orders-page__page-chip' + (i === Number(view.page) ? ' is-active' : '');
link.href = base.toString();
link.textContent = String(i);
root.appendChild(link);
}
var list = page.querySelector('[data-aksrt-order-list]');
if (list) list.after(root);
}
function renderView(view) {
renderStats(view.stats || {});
var list = page.querySelector('[data-aksrt-order-list]');
if (!list) return;
var items = Array.isArray(view.items) ? view.items : [];
if (!items.length) {
list.innerHTML = '<div class="aksrt-orders-page__empty"><i class="fas fa-receipt" aria-hidden="true"></i><h3>没有匹配的订单</h3><p>换个条件试试,或清除当前筛选。</p></div>';
list.classList.add('is-empty');
} else {
list.classList.remove('is-empty');
list.innerHTML = items.map(cardHtml).join('');
}
renderPagination(view);
if (detailOrderNumber) {
var detail = items.filter(function (item) { return item.order_number === detailOrderNumber; })[0];
if (detail) renderDetail(detail); else closeDetail();
}
updateCountdowns();
}
function refreshView() {
return request(currentViewPath(), undefined, "GET").then(function (result) {
if (!result.success || !result.data) throw new Error(result.message || "刷新失败");
renderView(result.data);
return result.data;
}).catch(function (error) {
toast(error.message || "订单状态已变更,请刷新后查看");
});
}
function startPayment(button) {
var number = button.getAttribute("data-aksrt-order-pay") || "";
var method = button.getAttribute("data-aksrt-order-method") || "";
if (!number) return;
button.disabled = true;
request(orderPath(number, "/pay"), method ? { payment_method: method } : {}).then(function (result) {
if (!result.success) throw new Error(result.message || "支付失败");
var data = result.data || {};
if (data.redirect && data.payment_url) {
window.location.assign(data.payment_url);
return;
}
toast(data.message || "支付成功");
refreshView();
}).catch(function (error) {
button.disabled = false;
toast(error.message || "网络错误,请稍后重试");
});
}
function closeOrder(button) {
var number = button.getAttribute("data-aksrt-order-cancel") || "";
if (!number) return;
if (button.getAttribute("data-aksrt-confirm") !== "true") {
button.setAttribute("data-aksrt-confirm", "true");
button.textContent = "确认关闭";
return;
}
button.disabled = true;
request(orderPath(number, "/cancel")).then(function (result) {
if (!result.success) throw new Error(result.message || "关闭订单失败");
toast("订单已关闭");
refreshView();
}).catch(function (error) {
button.disabled = false;
button.removeAttribute("data-aksrt-confirm");
button.textContent = "关闭订单";
toast(error.message || "网络错误,请稍后重试");
});
}
function updateCountdowns() {
page.querySelectorAll("[data-aksrt-order-countdown]").forEach(function (node) {
var value = Math.max(0, Number(node.getAttribute("data-aksrt-order-countdown") || 0) - 1);
node.setAttribute("data-aksrt-order-countdown", String(value));
node.textContent = value ? "剩余支付时间 " + value + " 秒" : "订单即将关闭";
});
}
page.addEventListener("click", function (event) {
var filterToggle = event.target.closest("[data-aksrt-orders-filter-toggle]");
if (filterToggle) {
var panel = page.querySelector("[data-aksrt-orders-filter-panel]");
var expanded = filterToggle.getAttribute("aria-expanded") === "true";
filterToggle.setAttribute("aria-expanded", String(!expanded));
if (panel) panel.hidden = expanded;
return;
}
var detail = event.target.closest("[data-aksrt-order-detail]");
if (detail) { openDetail(detail.getAttribute("data-aksrt-order-detail")); return; }
if (event.target.closest("[data-aksrt-order-detail-close]")) { closeDetail(); return; }
var pay = event.target.closest("[data-aksrt-order-pay]");
if (pay) { startPayment(pay); return; }
var cancel = event.target.closest("[data-aksrt-order-cancel]");
if (cancel) closeOrder(cancel);
});
document.addEventListener("keydown", function (event) {
if (event.key === "Escape" && detailModal && !detailModal.hidden) closeDetail();
});
window.setInterval(updateCountdowns, 1000);
}());