fix(orders): load user center assets before panel navigation

This commit is contained in:
kate522 committed 2026-08-12 16:48:40 +08:00
1 parent 01e9a0f4ca
commit 651c5f28f8
5 files changed
+265 -254

No files matched your search

+164 -122
View File
@@ -3,19 +3,10 @@
*
* @package AKSRT
*/
(function () {
"use strict";
var page = document.querySelector("[data-aksrt-order-center]");
if (!page) return;
if (!window.AksrtModalRuntime.isRolloutEnabled("order")) return;
var detailOrderNumber = "";
var detailAutoRefreshStarted = false;
var detailSession = null;
var detailReplacement = false;
var detailReplacementSession = null;
var instances = new WeakMap();
function toast(message, type) {
window.AksrtToast(message, type || "info");
@@ -50,15 +41,6 @@
: "¥" + amount.toFixed(2);
}
function activeDetail(number) {
return detailOrderNumber === number
&& !!detailSession
&& !detailSession.closed
&& detailSession.options
&& detailSession.options.kind === "orders"
&& window.AksrtModalRuntime.getActive() === detailSession.shell;
}
function orderTag(orderNumber) {
return "order:" + String(orderNumber || "").toLowerCase();
}
@@ -71,6 +53,15 @@
window.AksrtModalRuntime.invalidate(tags);
}
function activeDetail(state, number) {
return state.detailOrderNumber === number
&& !!state.detailSession
&& !state.detailSession.closed
&& state.detailSession.options
&& state.detailSession.options.kind === "orders"
&& window.AksrtModalRuntime.getActive() === state.detailSession.shell;
}
function detailSkeleton() {
return '<div class="aksrt-order-detail__skeleton" aria-live="polite" aria-busy="true">' +
'<span class="aksrt-modal-runtime__skeleton-line is-wide"></span>' +
@@ -79,7 +70,7 @@
'</div>';
}
function renderDetail(order, session) {
function renderDetail(state, order, session) {
var allowedActions = order.allowed_actions || {};
var reconciliation = order.reconciliation || {};
var image = order.image || "";
@@ -112,7 +103,7 @@
session.content.innerHTML = html;
}
function detailOptions(orderNumber, refresh) {
function detailOptions(state, orderNumber, refresh) {
return {
url: orderPath(orderNumber, refresh ? "/refresh" : ""),
method: refresh ? "POST" : "GET",
@@ -124,20 +115,20 @@
cacheTags: ["orders", orderTag(orderNumber)],
skeleton: detailSkeleton(),
onState: function (_, session) {
if (orderNumber === detailOrderNumber) detailSession = session;
if (orderNumber === state.detailOrderNumber) state.detailSession = session;
},
renderData: function (data, session) {
if (orderNumber !== detailOrderNumber) return false;
detailSession = session;
if (orderNumber !== state.detailOrderNumber || !instances.has(state.root)) return false;
state.detailSession = session;
if (!data || typeof data !== "object") {
session.content.innerHTML = '<p class="c-red">订单不存在</p>';
return;
}
renderDetail(data, session);
if (!refresh && !detailAutoRefreshStarted && data.reconciliation && data.reconciliation.state === "refresh_available") {
detailAutoRefreshStarted = true;
renderDetail(state, data, session);
if (!refresh && !state.detailAutoRefreshStarted && data.reconciliation && data.reconciliation.state === "refresh_available") {
state.detailAutoRefreshStarted = true;
window.setTimeout(function () {
if (activeDetail(orderNumber)) refreshDetail(orderNumber);
if (activeDetail(state, orderNumber)) refreshDetail(state, orderNumber);
}, 0);
}
},
@@ -147,27 +138,27 @@
};
}
function openDetail(orderNumber) {
function openDetail(state, orderNumber) {
if (!orderNumber) return;
detailSession = null;
detailReplacement = false;
detailReplacementSession = null;
detailOrderNumber = orderNumber;
detailAutoRefreshStarted = false;
window.AksrtModalRuntime.openRemote(detailOptions(orderNumber, false));
state.detailSession = null;
state.detailReplacement = false;
state.detailReplacementSession = null;
state.detailOrderNumber = orderNumber;
state.detailAutoRefreshStarted = false;
window.AksrtModalRuntime.openRemote(detailOptions(state, orderNumber, false));
}
function refreshDetail(orderNumber) {
if (!orderNumber || !activeDetail(orderNumber)) return;
detailReplacement = true;
detailReplacementSession = detailSession;
var refreshPromise = window.AksrtModalRuntime.openRemote(detailOptions(orderNumber, true));
function refreshDetail(state, orderNumber) {
if (!orderNumber || !activeDetail(state, orderNumber)) return;
state.detailReplacement = true;
state.detailReplacementSession = state.detailSession;
var refreshPromise = window.AksrtModalRuntime.openRemote(detailOptions(state, orderNumber, true));
refreshPromise.then(function () {
detailReplacement = false;
detailReplacementSession = null;
state.detailReplacement = false;
state.detailReplacementSession = null;
}, function () {
detailReplacement = false;
detailReplacementSession = null;
state.detailReplacement = false;
state.detailReplacementSession = null;
});
}
@@ -196,21 +187,21 @@
? '<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>';
'<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]");
function renderStats(state, stats) {
var root = state.root.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>';
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");
function renderPagination(state, view) {
var existing = state.root.querySelector(".aksrt-orders-page__pagination");
if (existing) existing.remove();
if (Number(view.total_pages || 1) <= 1) return;
var root = document.createElement("nav");
@@ -225,13 +216,21 @@
link.textContent = String(i);
root.appendChild(link);
}
var list = page.querySelector("[data-aksrt-order-list]");
var list = state.root.querySelector("[data-aksrt-order-list]");
if (list) list.after(root);
}
function renderView(view) {
renderStats(view.stats || {});
var list = page.querySelector("[data-aksrt-order-list]");
function updateCountdowns(state) {
state.root.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 + " 秒" : "订单即将关闭";
});
}
function renderView(state, view) {
renderStats(state, view.stats || {});
var list = state.root.querySelector("[data-aksrt-order-list]");
if (!list) return;
var items = Array.isArray(view.items) ? view.items : [];
if (!items.length) {
@@ -241,14 +240,14 @@
list.classList.remove("is-empty");
list.innerHTML = items.map(cardHtml).join("");
}
renderPagination(view);
updateCountdowns();
renderPagination(state, view);
updateCountdowns(state);
}
function refreshView() {
function refreshView(state) {
return request(currentViewPath(), undefined, "GET").then(function (result) {
if (!result || !result.data) throw new Error("刷新失败");
renderView(result.data);
renderView(state, result.data);
return result.data;
}).catch(function (error) {
toast(errorMessage(error, "订单状态已变更,请刷新后查看"));
@@ -256,7 +255,7 @@
});
}
function startPayment(button) {
function startPayment(state, button) {
var number = button.getAttribute("data-aksrt-order-pay") || "";
var method = button.getAttribute("data-aksrt-order-method") || "";
if (!number || button.disabled) return;
@@ -269,15 +268,15 @@
return;
}
toast(data.message || "支付成功", "success");
refreshView();
if (activeDetail(number)) openDetail(number);
refreshView(state);
if (activeDetail(state, number)) openDetail(state, number);
}).catch(function (error) {
button.disabled = false;
toast(errorMessage(error, "网络错误,请稍后重试"), "error");
});
}
function closeOrder(button) {
function closeOrder(state, button) {
var number = button.getAttribute("data-aksrt-order-cancel") || "";
if (!number || button.disabled) return;
if (button.getAttribute("data-aksrt-confirm") !== "true") {
@@ -290,8 +289,8 @@
var data = result.data || {};
invalidateOrder(number, data.order);
toast("订单已关闭", "success");
refreshView();
if (activeDetail(number)) openDetail(number);
refreshView(state);
if (activeDetail(state, number)) openDetail(state, number);
}).catch(function (error) {
button.disabled = false;
button.removeAttribute("data-aksrt-confirm");
@@ -300,61 +299,104 @@
});
}
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 + " 秒" : "订单即将关闭";
function closest(target, selector) {
return target && target.closest ? target.closest(selector) : null;
}
function initRoot(root) {
if (instances.has(root) || !window.AksrtModalRuntime.isRolloutEnabled("order")) return;
var state = {
root: root,
detailOrderNumber: "",
detailAutoRefreshStarted: false,
detailSession: null,
detailReplacement: false,
detailReplacementSession: null,
countdownTimer: null,
};
state.onRootClick = function (event) {
var filterToggle = closest(event.target, "[data-aksrt-orders-filter-toggle]");
if (filterToggle && root.contains(filterToggle)) {
var panel = root.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 = closest(event.target, "[data-aksrt-order-detail]");
if (detail && root.contains(detail)) { openDetail(state, detail.getAttribute("data-aksrt-order-detail")); return; }
var pay = closest(event.target, "[data-aksrt-order-pay]");
if (pay && root.contains(pay)) { event.preventDefault(); startPayment(state, pay); return; }
var cancel = closest(event.target, "[data-aksrt-order-cancel]");
if (cancel && root.contains(cancel)) { event.preventDefault(); closeOrder(state, cancel); }
};
state.onModalClose = function (event) {
var detail = event && event.detail ? event.detail : {};
if (!state.detailSession || detail.session !== state.detailSession) return;
if (detail.reason === "replace" && state.detailReplacement && detail.session === state.detailReplacementSession) return;
state.detailSession = null;
state.detailOrderNumber = "";
state.detailAutoRefreshStarted = false;
state.detailReplacement = false;
state.detailReplacementSession = null;
};
state.onDocumentClick = function (event) {
if (!state.detailSession || window.AksrtModalRuntime.getActive() !== state.detailSession.shell) return;
var refresh = closest(event.target, "[data-aksrt-order-refresh]");
if (refresh) {
event.preventDefault();
refreshDetail(state, refresh.getAttribute("data-aksrt-order-refresh") || "");
return;
}
var pay = closest(event.target, "[data-aksrt-order-pay]");
if (pay && !root.contains(pay)) {
event.preventDefault();
startPayment(state, pay);
return;
}
var cancel = closest(event.target, "[data-aksrt-order-cancel]");
if (cancel && !root.contains(cancel)) {
event.preventDefault();
closeOrder(state, cancel);
}
};
root.addEventListener("click", state.onRootClick);
document.addEventListener("aksrt:modal:close", state.onModalClose);
document.addEventListener("click", state.onDocumentClick);
state.countdownTimer = window.setInterval(function () { updateCountdowns(state); }, 1000);
instances.set(root, state);
}
function rootsIn(root) {
if (!root) return [];
var roots = [];
if (root.matches && root.matches("[data-aksrt-order-center]")) roots.push(root);
if (root.querySelectorAll) root.querySelectorAll("[data-aksrt-order-center]").forEach(function (item) { roots.push(item); });
return roots;
}
function init(root) {
rootsIn(root || document).forEach(initRoot);
}
function destroy(root) {
rootsIn(root).forEach(function (item) {
var state = instances.get(item);
if (!state) return;
if (activeDetail(state, state.detailOrderNumber)) window.AksrtModalRuntime.close("replace");
item.removeEventListener("click", state.onRootClick);
document.removeEventListener("aksrt:modal:close", state.onModalClose);
document.removeEventListener("click", state.onDocumentClick);
window.clearInterval(state.countdownTimer);
instances.delete(item);
});
}
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; }
var pay = event.target.closest("[data-aksrt-order-pay]");
if (pay) { event.preventDefault(); startPayment(pay); return; }
var cancel = event.target.closest("[data-aksrt-order-cancel]");
if (cancel) { event.preventDefault(); closeOrder(cancel); }
});
document.addEventListener("aksrt:modal:close", function (event) {
var detail = event && event.detail ? event.detail : {};
if (!detailSession || detail.session !== detailSession) return;
if (detail.reason === "replace" && detailReplacement && detail.session === detailReplacementSession) return;
detailSession = null;
detailOrderNumber = "";
detailAutoRefreshStarted = false;
detailReplacement = false;
detailReplacementSession = null;
});
document.addEventListener("click", function (event) {
var refresh = event.target.closest("[data-aksrt-order-refresh]");
if (refresh) {
event.preventDefault();
refreshDetail(refresh.getAttribute("data-aksrt-order-refresh") || "");
return;
}
var pay = event.target.closest("[data-aksrt-order-pay]");
if (pay && !page.contains(pay)) {
event.preventDefault();
startPayment(pay);
return;
}
var cancel = event.target.closest("[data-aksrt-order-cancel]");
if (cancel && !page.contains(cancel)) {
event.preventDefault();
closeOrder(cancel);
}
});
window.setInterval(updateCountdowns, 1000);
window.AKSRTOrderCenter = { init: init, destroy: destroy };
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === "function") {
window.AksrtFrontend.register("aksrt-order-center", init);
}
init(document);
}());
+9
View File
@@ -77,6 +77,9 @@
if (target._aksrtPanelRequest) return target._aksrtPanelRequest;
var restUrl = (window.aksrtData && (window.aksrtData.restUrl || window.aksrtData.apiUrl)) || cfg.restUrl || '';
if (!restUrl) return Promise.reject(new Error('rest-unavailable'));
if (name === 'orders' && (!window.AKSRTOrderCenter || typeof window.AKSRTOrderCenter.init !== 'function')) {
return Promise.reject(new Error('orders-initializer-unavailable'));
}
target.classList.add('is-loading');
var url = restUrl.replace(/\/$/, '') + '/user-center/panel/' + encodeURIComponent(name);
if (name === 'creator') {
@@ -91,7 +94,13 @@
}).then(function(response) {
return response.json().then(function(payload) {
if (!response.ok || !payload || !payload.success || !payload.data || typeof payload.data.html !== 'string') throw new Error('panel-load-failed');
if (name === 'orders' && window.AKSRTOrderCenter && typeof window.AKSRTOrderCenter.destroy === 'function') {
window.AKSRTOrderCenter.destroy(target);
}
target.innerHTML = payload.data.html;
if (window.AksrtFrontend && typeof window.AksrtFrontend.rehydrate === 'function') {
window.AksrtFrontend.rehydrate(target, 'ajax');
}
target.dataset.panelLoaded = 'true';
});
}).finally(function() {