feat(ux): after-sale multi-step, ban appeal, message types, coupon wallet

Orders center gains after-sale tickets (return ship/cancel/timeline),
coupon wallet list, ban-appeal page, and expanded message center tabs.
This commit is contained in:
2026-07-18 22:48:08 +08:00
parent 3a883bc3d0
commit 1337664ed3
15 changed files with 999 additions and 37 deletions
+29
View File
@@ -0,0 +1,29 @@
/**
* Ban appeal page styles.
* @package AKSRT
*/
.aksrt-ban-appeal .form-control {
width: 100%;
box-sizing: border-box;
padding: 8px 10px;
border: 1px solid var(--main-border-color, #ddd);
border-radius: 6px;
}
.aksrt-ban-appeal .mb15 { margin-bottom: 15px; }
.aksrt-ban-appeal .but.c-blue {
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--focus-color, #2f6df6);
color: #fff;
border: 0;
border-radius: 6px;
padding: 10px 16px;
cursor: pointer;
}
.aksrt-ban-appeal .c-red { color: #e74c3c; }
.aksrt-ban-appeal .muted-box {
background: var(--surface-2, #f5f6f7);
border-radius: 8px;
padding: 12px;
}
+86
View File
@@ -92,3 +92,89 @@
.aksrt-orders-page__tabs {
margin-top: 4px;
}
/* After-sale multi-step + coupon wallet */
.aksrt-orders-page__extra-nav {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0 0 12px;
}
.aksrt-orders-page__extra-link {
padding: 6px 12px;
border-radius: 999px;
background: var(--surface-2, #f3f4f6);
color: inherit;
text-decoration: none;
font-size: 13px;
}
.aksrt-orders-page__extra-link.is-active {
background: var(--focus-color, var(--color-primary));
color: #fff;
}
.aksrt-as-list { display: grid; gap: 12px; }
.aksrt-as-card {
border: 1px solid var(--main-border-color, #eee);
border-radius: 10px;
padding: 14px;
background: var(--main-bg-color, #fff);
}
.aksrt-as-card__head {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
margin-bottom: 6px;
}
.aksrt-as-card__status {
margin-left: auto;
color: var(--focus-color, #2f6df6);
font-weight: 600;
}
.aksrt-as-timeline {
margin: 10px 0 0;
padding-left: 18px;
color: var(--muted-2-color, #888);
font-size: 12px;
}
.aksrt-as-card__actions {
display: flex;
gap: 8px;
margin-top: 10px;
}
.aksrt-coupon-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 12px;
}
.aksrt-coupon-card {
border: 1px dashed var(--focus-color, #2f6df6);
border-radius: 10px;
padding: 12px;
background: color-mix(in srgb, var(--focus-color, #2f6df6) 6%, #fff);
}
.aksrt-coupon-card__value {
font-size: 20px;
font-weight: 700;
color: var(--focus-color, #2f6df6);
}
.aksrt-coupon-card__code {
font-family: ui-monospace, monospace;
margin: 6px 0;
}
.aksrt-coupon-card__meta {
font-size: 12px;
color: var(--muted-2-color, #888);
margin-bottom: 4px;
}
.aksrt-orders-page__field { margin-bottom: 12px; }
.aksrt-orders-page__input,
.aksrt-orders-page__select,
.aksrt-orders-page__textarea {
width: 100%;
box-sizing: border-box;
padding: 8px 10px;
border: 1px solid var(--main-border-color, #ddd);
border-radius: 6px;
}
+44
View File
@@ -0,0 +1,44 @@
/**
* Ban appeal form submit.
* @package AKSRT
*/
(function () {
'use strict';
function ajaxUrl() {
if (window.aksrtData && window.aksrtData.ajaxUrl) return window.aksrtData.ajaxUrl;
if (window._win && window._win.ajax_url) return window._win.ajax_url;
return '/wp-admin/admin-ajax.php';
}
function toast(msg) {
if (window.aksrt && typeof window.aksrt.toast === 'function') {
window.aksrt.toast(msg);
return;
}
window.alert(msg);
}
function init() {
var form = document.querySelector('.aksrt-ban-appeal-form');
if (!form) return;
form.addEventListener('submit', function (e) {
e.preventDefault();
var btn = form.querySelector('button[type="submit"]');
if (btn) btn.disabled = true;
var fd = new FormData(form);
if (!fd.get('action')) fd.set('action', 'aksrt_ban_appeal_submit');
fetch(ajaxUrl(), { method: 'POST', body: fd, credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data || data.error) {
toast((data && data.msg) || '提交失败');
return;
}
toast(data.msg || '提交成功');
if (data.reload) window.setTimeout(function () { location.reload(); }, 400);
})
.catch(function () { toast('网络错误'); })
.finally(function () { if (btn) btn.disabled = false; });
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();
+143 -2
View File
@@ -617,9 +617,150 @@
return;
}
// Close modal
if (event.target.closest("[data-aksrt-aftersale-modal-close]") || (event.target.classList && event.target.classList.contains("aksrt-modal__overlay"))) {
// Return shipping
var returnShipBtn = event.target.closest("[data-aksrt-return-ship]");
if (returnShipBtn) {
openReturnShipModal(returnShipBtn.getAttribute("data-aksrt-return-ship"));
return;
}
// Cancel after-sale ticket
var asCancelBtn = event.target.closest("[data-aksrt-as-cancel]");
if (asCancelBtn) {
var tid = asCancelBtn.getAttribute("data-aksrt-as-cancel");
if (!tid || !window.confirm("确认取消该售后申请?")) return;
asCancelBtn.disabled = true;
request("/shop/frontend/after-sale/" + tid + "/cancel", { reason: "" })
.then(function (result) {
asCancelBtn.disabled = false;
if (!result || !result.success) {
showToast((result && result.message) || "取消失败");
return;
}
showToast(result.message || "已取消售后");
window.location.reload();
})
.catch(function () {
asCancelBtn.disabled = false;
showToast("网络错误");
});
return;
}
// Close after-sale modal
if (event.target.closest("[data-aksrt-aftersale-modal-close]") || (event.target.classList && event.target.classList.contains("aksrt-modal__overlay") && event.target.closest("[data-aksrt-aftersale-modal]"))) {
closeAfterSaleModal();
return;
}
// Close return-ship modal
if (event.target.closest("[data-aksrt-return-ship-close]") || (event.target.classList && event.target.classList.contains("aksrt-modal__overlay") && event.target.closest("[data-aksrt-return-ship-modal]"))) {
closeReturnShipModal();
}
});
/* ── Return shipping modal ── */
var returnShipModal = page.querySelector("[data-aksrt-return-ship-modal]");
var returnShipForm = page.querySelector("[data-aksrt-return-ship-form]");
function openReturnShipModal(ticketId) {
if (!returnShipModal || !returnShipForm) return;
returnShipForm.reset();
var idInput = returnShipForm.querySelector('[name="ticket_id"]');
if (idInput) idInput.value = ticketId || "";
returnShipModal.hidden = false;
}
function closeReturnShipModal() {
if (returnShipModal) returnShipModal.hidden = true;
}
if (returnShipForm) {
returnShipForm.addEventListener("submit", function (event) {
event.preventDefault();
var fd = new FormData(returnShipForm);
var tid = fd.get("ticket_id");
var carrier = (fd.get("carrier") || "").trim();
var tracking = (fd.get("tracking_no") || "").trim();
if (!carrier || !tracking) {
showToast("请填写快递公司与运单号");
return;
}
var btn = returnShipForm.querySelector('button[type="submit"]');
if (btn) { btn.disabled = true; }
request("/shop/frontend/after-sale/" + tid + "/return-shipping", {
carrier: carrier,
tracking_no: tracking
}).then(function (result) {
if (btn) btn.disabled = false;
if (!result || !result.success) {
showToast((result && result.message) || "提交失败");
return;
}
closeReturnShipModal();
showToast(result.message || "退货物流已提交");
window.location.reload();
}).catch(function () {
if (btn) btn.disabled = false;
showToast("网络错误");
});
});
}
/* ── 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 = '<p class="muted-2-color">暂无可用优惠券</p>';
return;
}
var html = '<div class="aksrt-coupon-grid">';
items.forEach(function (c) {
var val = c.type === "percent" ? (c.value + "%") : ("¥" + Number(c.value || 0).toFixed(2));
html += '<div class="aksrt-coupon-card">';
html += '<div class="aksrt-coupon-card__value">' + val + '</div>';
html += '<div class="aksrt-coupon-card__code">' + (c.code || "") + '</div>';
if (c.min_amount > 0) {
html += '<div class="aksrt-coupon-card__meta">满 ¥' + Number(c.min_amount).toFixed(2) + ' 可用</div>';
}
if (c.expires_at) {
html += '<div class="aksrt-coupon-card__meta">有效期至 ' + c.expires_at + '</div>';
}
html += '<button type="button" class="btn-outline btn-sm" data-aksrt-copy-coupon="' + (c.code || "") + '">复制券码</button>';
html += '</div>';
});
html += '</div>';
couponRoot.innerHTML = html;
}).catch(function () {
couponRoot.innerHTML = '<p class="muted-2-color">加载失败</p>';
});
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);
}
});
}
})();