feat(payment): rebuild order details and asset records
This commit is contained in:
@@ -74,7 +74,6 @@
|
||||
var map = {
|
||||
pending: { icon: "fa-clock", desc: "订单已生成,请在有效期内完成支付" },
|
||||
paid: { icon: "fa-check-circle", desc: "支付已完成,相关权益已发放至账户" },
|
||||
refunding: { icon: "fa-hourglass-half", desc: "退款申请已受理,正在处理中" },
|
||||
refunded: { icon: "fa-undo-alt", desc: "退款已完成,款项将原路退回" },
|
||||
closed: { icon: "fa-times-circle", desc: "订单已关闭,如有需要可重新下单" },
|
||||
};
|
||||
@@ -106,6 +105,26 @@
|
||||
return "<div><dt>" + escapeHtml(label) + "</dt><dd>" + cell + "</dd></div>";
|
||||
}
|
||||
|
||||
function gatewayResultText(value) {
|
||||
if (!value) return "";
|
||||
var result = value;
|
||||
if (typeof value === "string") {
|
||||
try { result = JSON.parse(value); } catch (_) { return String(value); }
|
||||
}
|
||||
if (!result || typeof result !== "object") return String(result);
|
||||
var labels = { succeeded: "退款成功", failed: "渠道明确拒绝", pending: "渠道处理中", unknown: "结果待确认" };
|
||||
var parts = [];
|
||||
if (result.status) parts.push(labels[String(result.status)] || String(result.status));
|
||||
if (result.message) parts.push(String(result.message));
|
||||
if (result.refund_id) parts.push("退款单号 " + String(result.refund_id));
|
||||
return parts.join(" · ") || "渠道暂未提供可读结果";
|
||||
}
|
||||
|
||||
function afterSaleAmount(value, order) {
|
||||
var amount = String(value == null ? "" : value);
|
||||
return order && order.is_points ? amount + " " + String(order.currency_symbol || "积分") : "¥" + amount;
|
||||
}
|
||||
|
||||
function renderDetail(state, order, session) {
|
||||
var allowedActions = order.allowed_actions || {};
|
||||
var reconciliation = order.reconciliation || {};
|
||||
@@ -145,15 +164,29 @@
|
||||
html += '<h4 class="aksrt-order-detail__group-title">交易信息</h4>';
|
||||
html += '<dl class="aksrt-order-detail__list">';
|
||||
[
|
||||
["流水号", order.order_number],
|
||||
["订单号", order.order_number],
|
||||
["支付方式", paymentMethodText(order)],
|
||||
["创建时间", order.created_at],
|
||||
["支付时间", order.paid_at],
|
||||
].forEach(function (row) {
|
||||
html += detailRow(row[0], row[1], row[0] === "流水号");
|
||||
html += detailRow(row[0], row[1], row[0] === "订单号");
|
||||
});
|
||||
html += "</dl></section>";
|
||||
|
||||
var afterSales = Array.isArray(order.after_sales) ? order.after_sales : [];
|
||||
if (afterSales.length) {
|
||||
html += '<section class="aksrt-order-detail__group"><h4 class="aksrt-order-detail__group-title">售后记录</h4><ul class="aksrt-order-detail__after-sales">';
|
||||
afterSales.forEach(function (item) {
|
||||
var labels = { pending: "待审核", processing: "处理中", approved: "已通过", rejected: "已拒绝", cancelled: "已取消", completed: "已完成" };
|
||||
html += "<li><strong>" + escapeHtml(labels[item.status] || item.status || "") + "</strong><span>" + escapeHtml(item.reason || "") + "</span><small>退款金额:" + escapeHtml(afterSaleAmount(item.refund_amount, order)) + "</small>";
|
||||
if (item.admin_note) html += "<small>处理备注:" + escapeHtml(item.admin_note) + "</small>";
|
||||
if (item.gateway_result) html += "<small>渠道结果:" + escapeHtml(gatewayResultText(item.gateway_result)) + "</small>";
|
||||
if (item.status === "pending") html += '<button class="btn-ghost" type="button" data-aksrt-after-sale-cancel="' + escapeHtml(order.order_number) + '">取消申请</button>';
|
||||
html += "</li>";
|
||||
});
|
||||
html += "</ul></section>";
|
||||
}
|
||||
|
||||
if (reconciliation.state === "refresh_available") {
|
||||
html += '<div class="aksrt-order-detail__refresh-state" role="status">';
|
||||
html += '<i class="fa fas fa-info-circle" aria-hidden="true"></i>';
|
||||
@@ -166,6 +199,7 @@
|
||||
html += '<button class="btn-outline" type="button" data-aksrt-modal-close>关闭</button>';
|
||||
if (allowedActions.can_cancel) html += '<button class="btn-ghost" type="button" data-aksrt-order-cancel="' + escapeHtml(order.order_number) + '">关闭订单</button>';
|
||||
if (allowedActions.can_pay) html += '<button class="btn-primary" type="button" data-aksrt-order-pay="' + escapeHtml(order.order_number) + '" data-aksrt-order-method="' + escapeHtml(paymentMethod.value || "") + '">继续支付</button>';
|
||||
if (allowedActions.can_after_sale) html += '<form class="aksrt-order-detail__after-sale-form" data-aksrt-after-sale-form="' + escapeHtml(order.order_number) + '"><label>申请售后原因<textarea name="reason" required maxlength="2000" rows="3"></textarea></label><button class="btn-ghost" type="submit">提交售后申请</button></form>';
|
||||
html += "</footer>";
|
||||
|
||||
session.content.innerHTML = html;
|
||||
@@ -244,6 +278,7 @@
|
||||
var html = '<button class="btn-outline" type="button" data-aksrt-order-detail="' + escapeHtml(order.order_number) + '">订单详情</button>';
|
||||
if (allowedActions.can_cancel) html += '<button class="btn-ghost" type="button" data-aksrt-order-cancel="' + escapeHtml(order.order_number) + '">关闭订单</button>';
|
||||
if (allowedActions.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 (allowedActions.can_after_sale) html += '<button class="btn-outline" type="button" data-aksrt-order-detail="' + escapeHtml(order.order_number) + '">申请售后</button>';
|
||||
return html;
|
||||
}
|
||||
|
||||
@@ -256,7 +291,7 @@
|
||||
: "";
|
||||
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>" +
|
||||
'<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>";
|
||||
}
|
||||
|
||||
@@ -265,7 +300,10 @@
|
||||
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-paid">' + Number(stats.paid || 0) + "</strong></div>";
|
||||
'<div class="aksrt-orders-page__stat"><span>已支付</span><strong class="is-paid">' + Number(stats.paid || 0) + "</strong></div>" +
|
||||
'<div class="aksrt-orders-page__stat"><span>已退款</span><strong>' + Number(stats.refunded || 0) + "</strong></div>" +
|
||||
'<div class="aksrt-orders-page__stat"><span>已关闭</span><strong>' + Number(stats.closed || 0) + "</strong></div>" +
|
||||
'<div class="aksrt-orders-page__stat"><span>售后待处理</span><strong>' + Number(stats.after_sale_pending || 0) + "</strong></div>";
|
||||
var pendingCount = state.root.querySelector('[data-aksrt-order-filter="status"][data-aksrt-order-filter-value="pending"] .aksrt-orders-page__filter-count');
|
||||
if (pendingCount) {
|
||||
pendingCount.textContent = String(Number(stats.pending || 0));
|
||||
@@ -428,7 +466,7 @@
|
||||
if (!value) return;
|
||||
var icon = button.querySelector("i");
|
||||
var settle = function (ok) {
|
||||
notyf(ok ? "流水号已复制" : "复制失败,请手动选择复制", ok ? "success" : "danger");
|
||||
notyf(ok ? "订单号已复制" : "复制失败,请手动选择复制", ok ? "success" : "danger");
|
||||
if (!ok) return;
|
||||
button.classList.add("is-copied");
|
||||
if (icon) icon.className = "fa fas fa-check";
|
||||
@@ -517,12 +555,42 @@
|
||||
if (cancel && root.contains(cancel)) { event.preventDefault(); closeOrder(state, cancel); }
|
||||
};
|
||||
state.onRootSubmit = function (event) {
|
||||
var afterSaleForm = closest(event.target, "[data-aksrt-after-sale-form]");
|
||||
if (afterSaleForm) {
|
||||
event.preventDefault();
|
||||
var number = afterSaleForm.getAttribute("data-aksrt-after-sale-form") || "";
|
||||
var reason = afterSaleForm.querySelector("[name=reason]");
|
||||
if (!number || !reason || !String(reason.value || "").trim()) return;
|
||||
request(orderPath(number, "/after-sale"), { reason: String(reason.value).trim() }, "POST", window.AksrtRequest.createIdempotencyKey()).then(function () {
|
||||
notyf("售后申请已提交", "success");
|
||||
invalidateOrder(number);
|
||||
openDetail(state, number);
|
||||
refreshView(state);
|
||||
}).catch(function (error) { notyf(errorMessage(error, "售后申请提交失败"), "danger"); });
|
||||
return;
|
||||
}
|
||||
var form = closest(event.target, "[data-aksrt-orders-search]");
|
||||
if (!form || !root.contains(form)) return;
|
||||
event.preventDefault();
|
||||
var input = form.querySelector("#aksrt-order-number");
|
||||
loadView(state, { orderNumber: input ? String(input.value || "").trim() : "", page: 1 });
|
||||
};
|
||||
state.onDocumentSubmit = function (event) {
|
||||
var afterSaleForm = closest(event.target, "[data-aksrt-after-sale-form]");
|
||||
if (!afterSaleForm || root.contains(afterSaleForm) || event.__aksrtAfterSaleHandled) return;
|
||||
var number = afterSaleForm.getAttribute("data-aksrt-after-sale-form") || "";
|
||||
if (!activeDetail(state, number)) return;
|
||||
event.__aksrtAfterSaleHandled = true;
|
||||
event.preventDefault();
|
||||
var reason = afterSaleForm.querySelector("[name=reason]");
|
||||
if (!number || !reason || !String(reason.value || "").trim()) return;
|
||||
request(orderPath(number, "/after-sale"), { reason: String(reason.value).trim() }, "POST", window.AksrtRequest.createIdempotencyKey()).then(function () {
|
||||
notyf("售后申请已提交", "success");
|
||||
invalidateOrder(number);
|
||||
openDetail(state, number);
|
||||
refreshView(state);
|
||||
}).catch(function (error) { notyf(errorMessage(error, "售后申请提交失败"), "danger"); });
|
||||
};
|
||||
state.onModalClose = function (event) {
|
||||
var detail = event && event.detail ? event.detail : {};
|
||||
if (!state.detailSession || detail.session !== state.detailSession) return;
|
||||
@@ -533,6 +601,25 @@
|
||||
state.detailReplacementSession = null;
|
||||
};
|
||||
state.onDocumentClick = function (event) {
|
||||
var afterSaleCancel = closest(event.target, "[data-aksrt-after-sale-cancel]");
|
||||
if (afterSaleCancel && !event.__aksrtAfterSaleCancelHandled) {
|
||||
var afterSaleNumber = afterSaleCancel.getAttribute("data-aksrt-after-sale-cancel") || "";
|
||||
if (activeDetail(state, afterSaleNumber)) {
|
||||
event.__aksrtAfterSaleCancelHandled = true;
|
||||
event.preventDefault();
|
||||
afterSaleCancel.disabled = true;
|
||||
request(orderPath(afterSaleNumber, "/after-sale"), undefined, "DELETE", window.AksrtRequest.createIdempotencyKey()).then(function () {
|
||||
notyf("售后申请已取消", "success");
|
||||
invalidateOrder(afterSaleNumber);
|
||||
openDetail(state, afterSaleNumber);
|
||||
refreshView(state);
|
||||
}).catch(function (error) {
|
||||
afterSaleCancel.disabled = false;
|
||||
notyf(errorMessage(error, "取消申请失败"), "danger");
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!state.detailSession || window.AksrtModalRuntime.getActive() !== state.detailSession.shell) return;
|
||||
var copy = closest(event.target, "[data-aksrt-order-copy]");
|
||||
if (copy) {
|
||||
@@ -561,6 +648,7 @@
|
||||
|
||||
root.addEventListener("click", state.onRootClick);
|
||||
root.addEventListener("submit", state.onRootSubmit);
|
||||
document.addEventListener("submit", state.onDocumentSubmit);
|
||||
document.addEventListener("aksrt:modal:close", state.onModalClose);
|
||||
document.addEventListener("click", state.onDocumentClick);
|
||||
state.countdownTimer = window.setInterval(function () { updateCountdowns(state); }, 1000);
|
||||
@@ -586,6 +674,7 @@
|
||||
if (activeDetail(state, state.detailOrderNumber)) window.AksrtModalRuntime.close("replace");
|
||||
item.removeEventListener("click", state.onRootClick);
|
||||
item.removeEventListener("submit", state.onRootSubmit);
|
||||
document.removeEventListener("submit", state.onDocumentSubmit);
|
||||
document.removeEventListener("aksrt:modal:close", state.onModalClose);
|
||||
document.removeEventListener("click", state.onDocumentClick);
|
||||
window.clearInterval(state.countdownTimer);
|
||||
|
||||
Reference in New Issue
Block a user