feat: remove shop feature (Phase 2)
Delete all shop domain classes, controllers, schema builders, templates, JS/CSS, admin SPA pages, and shop-only payment classes (Shipping, AfterSale, Discount). Remove shop-only DB table definitions (product_variant, after_sale, order_shipping, card_key) from migrator and add their DROP to uninstall.php. Clean up shared files: - Remove aksrt_product CPT + taxonomies from Setup.php - Remove shop rewrite rules/query vars/template redirect from SetupPart2.php - Remove shop widget areas from SetupPart1.php - Remove shop enqueues from ScriptsPart1b.php - Remove sepakerator-aksrt-shop from SetupPart2.php - Remove get_shop_settings facade (delete ForumShop.php, clean DomainGroups.php) - Remove ORDER_PRODUCT_SHOP constant from DomainModel.php - Remove Shop::class fallback branches from UserOrders.php, OrderCenterRest.php - Remove shipping/after-sale branches from OrderRepositoryAdmin.php, PayMenus.php, PayOrders.php - Remove shop product widgets from widgets-register.php - Remove cart page from template-registry.php, routing.php, ScriptsPart2.php - Remove cart UI from sidebar-nav.php, profile-orders.php, sidebar-orders.php - Clean up order-center.js (remove rebuy/cartUrl/receipt/after-sale handlers) - Remove aksrt_get_cart_page_url/product_page/product_edit from transactions.php - Clean up aksrt_product_cat references in Coupon.php, PayCoupons.php Shared payment/order/credits/content-pay stack fully retained.
This commit is contained in:
1 parent
2bbd7c01a3
commit
1d2505356e
103 files changed
+46
-21267
No files matched your search
@@ -1,483 +0,0 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var page = document.querySelector("[data-aksrt-cart-page]");
|
||||
if (!page || !window.aksrtData) {
|
||||
return;
|
||||
}
|
||||
|
||||
function restBase() {
|
||||
return ((aksrtData.siteUrl || "").replace(/\/$/, "")) + "/wp-json/aksrt/v1";
|
||||
}
|
||||
function rest(path, method, body) {
|
||||
var opts = {
|
||||
method: method || "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { "X-WP-Nonce": aksrtData.restNonce || "" }
|
||||
};
|
||||
if (body !== undefined) {
|
||||
opts.headers["Content-Type"] = "application/json";
|
||||
opts.body = JSON.stringify(body);
|
||||
}
|
||||
return fetch(restBase() + path, opts).then(function (r) { return r.json(); });
|
||||
}
|
||||
function ordersUrl() {
|
||||
return aksrtData.ordersUrl || (aksrtData.routes && aksrtData.routes.orders) || "/";
|
||||
}
|
||||
function shopHomeUrl() {
|
||||
return (aksrtData.routes && aksrtData.routes.home) || aksrtData.siteUrl || "/";
|
||||
}
|
||||
var cartItems = [];
|
||||
var currencySymbol = page.getAttribute("data-currency-symbol") || "¥";
|
||||
var itemsEl = page.querySelector("[data-aksrt-cart-items]");
|
||||
var subtotalEl = page.querySelector("[data-aksrt-summary-subtotal]");
|
||||
var shippingEl = page.querySelector("[data-aksrt-summary-shipping]");
|
||||
var discountEl = page.querySelector("[data-aksrt-summary-discount]");
|
||||
var totalEl = page.querySelector("[data-aksrt-summary-total]");
|
||||
var previewMessageEl = page.querySelector("[data-aksrt-preview-message]");
|
||||
var createBtn = page.querySelector("[data-aksrt-create-order]");
|
||||
var previewBtn = page.querySelector("[data-aksrt-preview-checkout]");
|
||||
|
||||
var previewState = null;
|
||||
var searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
function getCart() { return cartItems; }
|
||||
function setCart(items) { cartItems = Array.isArray(items) ? items : []; }
|
||||
|
||||
function money(value) {
|
||||
return currencySymbol + Number(value || 0).toFixed(2);
|
||||
}
|
||||
|
||||
function selectedValue(name) {
|
||||
var checked = page.querySelector('input[name="' + name + '"]:checked');
|
||||
return checked ? checked.value : "";
|
||||
}
|
||||
|
||||
function getPayload() {
|
||||
var items = getCart().map(function (item) {
|
||||
return {
|
||||
product_id: Number(item.product_id || item.id || 0),
|
||||
quantity: Number(item.qty || item.quantity || 1),
|
||||
options_string: item.options_string || ""
|
||||
};
|
||||
}).filter(function (item) {
|
||||
return item.product_id > 0;
|
||||
});
|
||||
|
||||
return {
|
||||
items: items,
|
||||
coupon_code: (page.querySelector("[data-aksrt-coupon-code]") || {}).value || "",
|
||||
shipping_method: selectedValue("aksrt_cart_shipping"),
|
||||
address_id: Number(selectedValue("aksrt_cart_address") || 0),
|
||||
payment_method: selectedValue("aksrt_cart_payment"),
|
||||
customer_note: (page.querySelector("[data-aksrt-customer-note]") || {}).value || ""
|
||||
};
|
||||
}
|
||||
|
||||
function renderCart() {
|
||||
var items = getCart();
|
||||
if (!items.length) {
|
||||
itemsEl.innerHTML = '' +
|
||||
'<div class="aksrt-cart-page__empty">' +
|
||||
'<i class="fas fa-shopping-cart" aria-hidden="true"></i>' +
|
||||
"<p>购物车为空,去商品页添加想购买的内容。</p>" +
|
||||
'<a href="' + shopHomeUrl() + '" class="btn-outline btn-sm">继续浏览</a>' +
|
||||
"</div>";
|
||||
subtotalEl.textContent = money(0);
|
||||
shippingEl.textContent = money(0);
|
||||
discountEl.textContent = "-" + money(0);
|
||||
totalEl.textContent = money(0);
|
||||
createBtn.disabled = true;
|
||||
previewState = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var total = 0;
|
||||
var html = "";
|
||||
items.forEach(function (item, index) {
|
||||
var qty = Number(item.qty || item.quantity || 1);
|
||||
var price = Number(item.unit_price != null ? item.unit_price : (item.price != null ? item.price : (item.product && item.product.price) || 0));
|
||||
var lineTotal = Number(item.line_total != null ? item.line_total : qty * price);
|
||||
total += lineTotal;
|
||||
var title = item.title || (item.product && item.product.title) || "商品";
|
||||
var image = item.image || (item.product && item.product.image) || "";
|
||||
var opts = item.options_label || item.options_string || "";
|
||||
|
||||
html += '' +
|
||||
'<article class="aksrt-cart-page__item" data-cart-index="' + index + '" data-product-id="' + Number(item.product_id || item.id || 0) + '" data-options-string="' + String(item.options_string || "").replace(/"/g, """) + '">' +
|
||||
(image ? '<img class="aksrt-cart-page__item-image" src="' + image + '" alt="">' : '<div class="aksrt-cart-page__item-image aksrt-cart-page__item-image--placeholder"><i class="fas fa-box"></i></div>') +
|
||||
'<div class="aksrt-cart-page__item-main">' +
|
||||
'<h3>' + title + "</h3>" +
|
||||
(opts ? "<small>" + opts + "</small>" : "") +
|
||||
'<p>' + money(price) + "</p>" +
|
||||
"</div>" +
|
||||
'<div class="aksrt-cart-page__item-qty">' +
|
||||
'<button type="button" data-qty-action="dec">-</button>' +
|
||||
"<span>" + qty + "</span>" +
|
||||
'<button type="button" data-qty-action="inc">+</button>' +
|
||||
"</div>" +
|
||||
'<strong class="aksrt-cart-page__item-total">' + money(lineTotal) + "</strong>" +
|
||||
'<button type="button" class="aksrt-cart-page__item-remove" data-qty-action="remove"><i class="fas fa-trash"></i></button>' +
|
||||
"</article>";
|
||||
});
|
||||
|
||||
itemsEl.innerHTML = html;
|
||||
subtotalEl.textContent = money(total);
|
||||
|
||||
if (!previewState) {
|
||||
shippingEl.textContent = money(0);
|
||||
discountEl.textContent = "-" + money(0);
|
||||
totalEl.textContent = money(total);
|
||||
}
|
||||
}
|
||||
|
||||
function setSummary(data) {
|
||||
previewState = data || null;
|
||||
subtotalEl.textContent = money((data && data.subtotal) || 0);
|
||||
shippingEl.textContent = money((data && data.shipping_fee) || 0);
|
||||
discountEl.textContent = "-" + money((data && data.discount) || 0);
|
||||
totalEl.textContent = money((data && data.total) || 0);
|
||||
createBtn.disabled = !data;
|
||||
}
|
||||
|
||||
function request(path, body) { return rest(path, "POST", body || {}); }
|
||||
|
||||
function previewCheckout() {
|
||||
var payload = getPayload();
|
||||
if (!payload.items.length) {
|
||||
previewMessageEl.textContent = "请先添加商品后再试算。";
|
||||
return;
|
||||
}
|
||||
|
||||
previewBtn.disabled = true;
|
||||
previewMessageEl.textContent = "正在试算订单...";
|
||||
|
||||
request("/shop/frontend/checkout/preview", payload)
|
||||
.then(function (result) {
|
||||
if (!result.success) {
|
||||
setSummary(null);
|
||||
previewMessageEl.textContent = result.message || "试算失败。";
|
||||
return;
|
||||
}
|
||||
|
||||
setSummary(result.data);
|
||||
previewMessageEl.textContent = "已完成试算,可直接创建订单。";
|
||||
})
|
||||
.catch(function () {
|
||||
setSummary(null);
|
||||
previewMessageEl.textContent = "网络错误,请稍后重试。";
|
||||
})
|
||||
.finally(function () {
|
||||
previewBtn.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
function createOrder() {
|
||||
var payload = getPayload();
|
||||
if (!previewState) {
|
||||
previewCheckout();
|
||||
return;
|
||||
}
|
||||
|
||||
createBtn.disabled = true;
|
||||
request("/shop/frontend/orders", payload)
|
||||
.then(function (result) {
|
||||
if (!result.success) {
|
||||
previewMessageEl.textContent = result.message || "订单创建失败。";
|
||||
createBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var orderNumber = (result.data && result.data.order_number) || "";
|
||||
var nextOrdersUrl = ordersUrl() + (String(ordersUrl()).indexOf("?") >= 0 ? "&" : "?") + "order_status=pending";
|
||||
|
||||
if (!orderNumber) {
|
||||
window.location.href = nextOrdersUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 立即发起支付:跳转型网关直接前往第三方,余额型同步完成。
|
||||
request("/shop/frontend/orders/" + orderNumber + "/pay", {})
|
||||
.then(function (pay) {
|
||||
var data = (pay && pay.data) || {};
|
||||
if (pay && pay.success && data.redirect && data.payment_url && /^https?:\/\//i.test(data.payment_url)) {
|
||||
window.location.href = data.payment_url;
|
||||
return;
|
||||
}
|
||||
// 二维码 / 余额 / 失败:统一回订单中心处理(含 ?payment 提示)。
|
||||
window.location.href = nextOrdersUrl;
|
||||
})
|
||||
.catch(function () {
|
||||
window.location.href = nextOrdersUrl;
|
||||
});
|
||||
})
|
||||
.catch(function () {
|
||||
previewMessageEl.textContent = "网络错误,请稍后重试。";
|
||||
createBtn.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
page.addEventListener("click", function (event) {
|
||||
var actionButton = event.target.closest("[data-qty-action]");
|
||||
if (actionButton) {
|
||||
var itemEl = actionButton.closest("[data-cart-index]");
|
||||
if (!itemEl) return;
|
||||
var productId = Number(itemEl.getAttribute("data-product-id") || 0);
|
||||
var optionsString = itemEl.getAttribute("data-options-string") || "";
|
||||
var action = actionButton.getAttribute("data-qty-action");
|
||||
var path = "/shop/frontend/cart/add";
|
||||
var body = { product_id: productId, options_string: optionsString, count: 1 };
|
||||
if (action === "dec") {
|
||||
path = "/shop/frontend/cart/reduce";
|
||||
} else if (action === "remove") {
|
||||
path = "/shop/frontend/cart/remove";
|
||||
body = { product_id: productId, options_string: optionsString };
|
||||
} else if (action !== "inc") {
|
||||
return;
|
||||
}
|
||||
rest(path, "POST", body).then(function (result) {
|
||||
if (!result || !result.success) {
|
||||
window.alert((result && result.message) || "操作失败");
|
||||
return;
|
||||
}
|
||||
setSummary(null);
|
||||
loadServerCart();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-clear-cart]")) {
|
||||
rest("/shop/frontend/cart/empty", "POST", {}).then(function () {
|
||||
setSummary(null);
|
||||
loadServerCart();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-preview-checkout]")) {
|
||||
previewCheckout();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-create-order]")) {
|
||||
createOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
var resumeButton = event.target.closest("[data-aksrt-resume-order]");
|
||||
if (resumeButton) {
|
||||
window.location.href = ordersUrl() + (String(ordersUrl()).indexOf("?") >= 0 ? "&" : "?") + "order_status=pending";
|
||||
}
|
||||
});
|
||||
|
||||
function loadServerCart() {
|
||||
return rest("/shop/frontend/cart", "GET").then(function (result) {
|
||||
var items = (result && result.success && result.data && result.data.items) ? result.data.items : [];
|
||||
items = items.map(function (it) {
|
||||
it.qty = it.quantity || it.qty || 1;
|
||||
it.price = it.unit_price != null ? it.unit_price : (it.product && it.product.price) || 0;
|
||||
it.title = it.title || (it.product && it.product.title) || "商品";
|
||||
it.image = it.image || (it.product && it.product.image) || "";
|
||||
return it;
|
||||
});
|
||||
setCart(items);
|
||||
renderCart();
|
||||
}).catch(function () {
|
||||
setCart([]);
|
||||
renderCart();
|
||||
});
|
||||
}
|
||||
|
||||
var couponInput = page.querySelector("[data-aksrt-coupon-code]");
|
||||
if (couponInput && searchParams.has("coupon")) {
|
||||
couponInput.value = searchParams.get("coupon") || "";
|
||||
}
|
||||
|
||||
/* ── Address Book Management ── */
|
||||
|
||||
var addressModal = page.querySelector("[data-aksrt-address-modal]");
|
||||
var addressForm = page.querySelector("[data-aksrt-address-form]");
|
||||
var addressList = page.querySelector("[data-aksrt-address-list]");
|
||||
var addressTitle = page.querySelector("[data-aksrt-address-modal-title]");
|
||||
|
||||
function openAddressModal(mode, address) {
|
||||
if (!addressModal || !addressForm) return;
|
||||
addressForm.reset();
|
||||
addressForm.querySelector('[name="address_id"]').value = "";
|
||||
|
||||
if (mode === "edit" && address) {
|
||||
addressTitle.textContent = "编辑地址";
|
||||
addressForm.querySelector('[name="address_id"]').value = address.id || "";
|
||||
addressForm.querySelector('[name="name"]').value = address.name || "";
|
||||
addressForm.querySelector('[name="phone"]').value = address.phone || "";
|
||||
addressForm.querySelector('[name="province"]').value = address.province || "";
|
||||
addressForm.querySelector('[name="city"]').value = address.city || "";
|
||||
addressForm.querySelector('[name="district"]').value = address.district || "";
|
||||
addressForm.querySelector('[name="address"]').value = address.address || "";
|
||||
addressForm.querySelector('[name="is_default"]').checked = !!address.is_default;
|
||||
} else {
|
||||
addressTitle.textContent = "新增地址";
|
||||
}
|
||||
|
||||
addressModal.hidden = false;
|
||||
}
|
||||
|
||||
function closeAddressModal() {
|
||||
if (addressModal) addressModal.hidden = true;
|
||||
}
|
||||
|
||||
function refreshAddressList() {
|
||||
fetch(restBase() + "/shop/frontend/address", {
|
||||
headers: { "X-WP-Nonce": aksrtData.restNonce }
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (result) {
|
||||
if (!result.success || !addressList) return;
|
||||
var addresses = (result.data && result.data.addresses) || [];
|
||||
renderAddressList(addresses);
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function renderAddressList(addresses) {
|
||||
if (!addressList) return;
|
||||
if (!addresses.length) {
|
||||
addressList.innerHTML =
|
||||
'<div class="aksrt-cart-page__address-empty" data-aksrt-address-empty>' +
|
||||
'<i class="fas fa-map-marker-alt" aria-hidden="true"></i>' +
|
||||
"<p>暂无收货地址,请先新增。</p>" +
|
||||
"</div>";
|
||||
return;
|
||||
}
|
||||
|
||||
var html = "";
|
||||
addresses.forEach(function (addr, index) {
|
||||
html +=
|
||||
'<div class="aksrt-cart-page__option-card aksrt-cart-page__address-card" data-aksrt-address-card="' + addr.id + '">' +
|
||||
'<label class="aksrt-cart-page__address-label">' +
|
||||
'<input type="radio" name="aksrt_cart_address" value="' + addr.id + '"' + (index === 0 || addr.is_default ? " checked" : "") + ">" +
|
||||
'<span class="aksrt-cart-page__option-body">' +
|
||||
"<strong>" + escHtml(addr.name) + (addr.is_default ? ' <span class="aksrt-cart-page__default-tag">默认</span>' : "") + "</strong>" +
|
||||
"<span>" + escHtml(addr.phone) + "</span>" +
|
||||
"<span>" + escHtml(addr.full_text) + "</span>" +
|
||||
"</span></label>" +
|
||||
'<div class="aksrt-cart-page__address-actions">' +
|
||||
'<button type="button" class="btn-ghost btn-xs" data-aksrt-address-edit="' + addr.id + '">编辑</button>' +
|
||||
'<button type="button" class="btn-ghost btn-xs" data-aksrt-address-delete="' + addr.id + '">删除</button>' +
|
||||
(addr.is_default ? "" : '<button type="button" class="btn-ghost btn-xs" data-aksrt-address-set-default="' + addr.id + '">设为默认</button>') +
|
||||
"</div></div>";
|
||||
});
|
||||
addressList.innerHTML = html;
|
||||
}
|
||||
|
||||
function escHtml(str) {
|
||||
var div = document.createElement("div");
|
||||
div.appendChild(document.createTextNode(str || ""));
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function getAddressById(id) {
|
||||
var cards = addressList ? addressList.querySelectorAll("[data-aksrt-address-card]") : [];
|
||||
var found = null;
|
||||
cards.forEach(function (card) {
|
||||
if (String(card.getAttribute("data-aksrt-address-card")) === String(id)) {
|
||||
var body = card.querySelector(".aksrt-cart-page__option-body");
|
||||
if (body) {
|
||||
var spans = body.querySelectorAll("span");
|
||||
var strong = body.querySelector("strong");
|
||||
found = {
|
||||
id: id,
|
||||
name: strong ? strong.textContent.replace("默认", "").trim() : "",
|
||||
phone: spans[0] ? spans[0].textContent : "",
|
||||
full_text: spans[1] ? spans[1].textContent : ""
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
// Address event delegation
|
||||
page.addEventListener("click", function (event) {
|
||||
if (event.target.closest("[data-aksrt-address-add]")) {
|
||||
openAddressModal("add");
|
||||
return;
|
||||
}
|
||||
|
||||
var editBtn = event.target.closest("[data-aksrt-address-edit]");
|
||||
if (editBtn) {
|
||||
var editId = editBtn.getAttribute("data-aksrt-address-edit");
|
||||
var addr = getAddressById(editId);
|
||||
openAddressModal("edit", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
var deleteBtn = event.target.closest("[data-aksrt-address-delete]");
|
||||
if (deleteBtn) {
|
||||
var deleteId = deleteBtn.getAttribute("data-aksrt-address-delete");
|
||||
if (!confirm("确定删除该地址吗?")) return;
|
||||
rest("/shop/frontend/address/" + deleteId, "DELETE").then(function (result) {
|
||||
if (!result || !result.success) {
|
||||
alert((result && result.message) || "删除失败。");
|
||||
return;
|
||||
}
|
||||
refreshAddressList();
|
||||
}).catch(function () { alert("网络错误。"); });
|
||||
return;
|
||||
}
|
||||
|
||||
var defaultBtn = event.target.closest("[data-aksrt-address-set-default]");
|
||||
if (defaultBtn) {
|
||||
var defaultId = defaultBtn.getAttribute("data-aksrt-address-set-default");
|
||||
request("/shop/frontend/address/" + defaultId + "/default", {}).then(function (result) {
|
||||
if (!result.success) {
|
||||
alert(result.message || "设置失败。");
|
||||
return;
|
||||
}
|
||||
refreshAddressList();
|
||||
}).catch(function () { alert("网络错误。"); });
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-address-modal-close]") || event.target.classList.contains("aksrt-modal__overlay")) {
|
||||
closeAddressModal();
|
||||
}
|
||||
});
|
||||
|
||||
if (addressForm) {
|
||||
addressForm.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
var formData = new FormData(addressForm);
|
||||
var addressId = formData.get("address_id");
|
||||
var payload = {
|
||||
name: (formData.get("name") || "").trim(),
|
||||
phone: (formData.get("phone") || "").trim(),
|
||||
province: (formData.get("province") || "").trim(),
|
||||
city: (formData.get("city") || "").trim(),
|
||||
district: (formData.get("district") || "").trim(),
|
||||
address: (formData.get("address") || "").trim(),
|
||||
is_default: formData.get("is_default") === "1"
|
||||
};
|
||||
|
||||
if (!payload.name || !payload.phone || !payload.address) {
|
||||
alert("请填写必填项。");
|
||||
return;
|
||||
}
|
||||
|
||||
var url = addressId
|
||||
? "/shop/frontend/address/" + addressId
|
||||
: "/shop/frontend/address";
|
||||
|
||||
request(url, payload).then(function (result) {
|
||||
if (!result.success) {
|
||||
alert(result.message || "保存失败。");
|
||||
return;
|
||||
}
|
||||
closeAddressModal();
|
||||
refreshAddressList();
|
||||
}).catch(function () { alert("网络错误。"); });
|
||||
});
|
||||
}
|
||||
|
||||
loadServerCart();
|
||||
})();
|
||||
+1
-226
@@ -89,10 +89,6 @@
|
||||
return suffix ? base + suffix : base;
|
||||
}
|
||||
|
||||
function cartUrl() {
|
||||
return aksrtData.cartUrl || (aksrtData.routes && aksrtData.routes.cart) || "/";
|
||||
}
|
||||
|
||||
/* ── Order review modal (zibll 1:1) ── */
|
||||
var STAR_SVG =
|
||||
'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>';
|
||||
@@ -434,7 +430,7 @@
|
||||
badge.textContent = statusLabel || newStatus;
|
||||
}
|
||||
// Hide action buttons that are no longer relevant
|
||||
var actions = card.querySelectorAll("[data-aksrt-order-pay], [data-aksrt-order-cancel], [data-aksrt-order-after-sale], [data-aksrt-order-receipt], [data-aksrt-order-rebuy]");
|
||||
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";
|
||||
}
|
||||
@@ -640,21 +636,9 @@
|
||||
// Two-step cancel inside the modal — no window.confirm.
|
||||
footer += '<button type="button" class="btn-ghost" data-aksrt-order-cancel="' + escapeHtml(order.order_number) + '" data-aksrt-cancel-step="1">关闭订单</button>';
|
||||
}
|
||||
if (actions.can_receipt) {
|
||||
footer += '<button type="button" class="btn-primary" data-aksrt-order-receipt="' + escapeHtml(order.order_number) + '">确认收货</button>';
|
||||
}
|
||||
if (actions.can_review) {
|
||||
footer += '<button type="button" class="btn-primary c-green" data-aksrt-order-review="' + escapeHtml(order.order_number) + '">评价</button>';
|
||||
}
|
||||
if (actions.can_pay) {
|
||||
footer += '<button type="button" class="btn-primary" data-aksrt-order-pay="' + escapeHtml(order.order_number) + '" data-aksrt-order-method="' + escapeHtml((payment && payment.value) || "") + '">立即支付</button>';
|
||||
}
|
||||
if (actions.can_after_sale) {
|
||||
footer += '<button type="button" class="btn-outline" data-aksrt-order-after-sale="' + escapeHtml(order.order_number) + '">申请售后</button>';
|
||||
}
|
||||
if (actions.can_rebuy) {
|
||||
footer += '<button type="button" class="btn-outline" data-aksrt-order-rebuy="' + escapeHtml(order.order_number) + '">再次购买</button>';
|
||||
}
|
||||
if (actions.can_view_product && order.permalink) {
|
||||
footer += '<a class="btn-ghost" href="' + escapeHtml(order.permalink) + '">查看商品</a>';
|
||||
}
|
||||
@@ -695,70 +679,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ── After-Sale Modal ── */
|
||||
var afterSaleModal = page.querySelector("[data-aksrt-aftersale-modal]");
|
||||
var afterSaleForm = page.querySelector("[data-aksrt-aftersale-form]");
|
||||
var afterSaleOrderInput = afterSaleForm ? afterSaleForm.querySelector('[name="order_number"]') : null;
|
||||
|
||||
function openAfterSaleModal(orderNumber) {
|
||||
if (!afterSaleModal || !afterSaleForm) {
|
||||
showToast("售后表单加载失败,请刷新页面后重试。");
|
||||
return;
|
||||
}
|
||||
afterSaleForm.reset();
|
||||
if (afterSaleOrderInput) afterSaleOrderInput.value = orderNumber;
|
||||
afterSaleModal.hidden = false;
|
||||
}
|
||||
|
||||
function closeAfterSaleModal() {
|
||||
if (afterSaleModal) afterSaleModal.hidden = true;
|
||||
}
|
||||
|
||||
if (afterSaleForm) {
|
||||
afterSaleForm.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
var formData = new FormData(afterSaleForm);
|
||||
var orderNumber = formData.get("order_number");
|
||||
var reason = (formData.get("reason") || "").trim();
|
||||
if (!reason) {
|
||||
showToast("请填写售后原因。");
|
||||
return;
|
||||
}
|
||||
|
||||
var submitBtn = afterSaleForm.querySelector('button[type="submit"]');
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = "提交中...";
|
||||
}
|
||||
|
||||
request(orderPath(orderNumber, "/after-sale"), {
|
||||
type: formData.get("type") || "refund",
|
||||
reason: reason,
|
||||
note: (formData.get("note") || "").trim()
|
||||
}).then(function (result) {
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = "提交售后";
|
||||
}
|
||||
if (!result.success) {
|
||||
showToast(result.message || "提交售后失败。");
|
||||
return;
|
||||
}
|
||||
closeAfterSaleModal();
|
||||
showToast("售后申请已提交。");
|
||||
// Local refresh: update card status
|
||||
var card = findOrderCard(orderNumber);
|
||||
updateCardStatus(card, "refunded", "已退款");
|
||||
}).catch(function () {
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = "提交售后";
|
||||
}
|
||||
showToast("网络错误,请稍后重试。");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ── Countdown timer ── */
|
||||
function updateCountdowns() {
|
||||
var nodes = page.querySelectorAll("[data-aksrt-order-countdown]");
|
||||
@@ -808,56 +728,6 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Confirm receipt
|
||||
var receiptBtn = event.target.closest("[data-aksrt-order-receipt]");
|
||||
if (receiptBtn) {
|
||||
var receiptOrder = receiptBtn.getAttribute("data-aksrt-order-receipt");
|
||||
if (!receiptOrder) return;
|
||||
if (!window.confirm("确认已收到货物?")) return;
|
||||
receiptBtn.disabled = true;
|
||||
request(orderPath(receiptOrder, "/confirm-receipt"), {})
|
||||
.then(function (result) {
|
||||
receiptBtn.disabled = false;
|
||||
if (!result || !result.success) {
|
||||
showToast((result && result.message) || "确认收货失败");
|
||||
return;
|
||||
}
|
||||
showToast("已确认收货");
|
||||
updateCardStatus(findOrderCard(receiptOrder), "completed", "已完成");
|
||||
if (detailOrderNumber === receiptOrder) {
|
||||
closeOrderDetailModal();
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
receiptBtn.disabled = false;
|
||||
showToast("网络错误");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Rebuy
|
||||
var rebuyBtn = event.target.closest("[data-aksrt-order-rebuy]");
|
||||
if (rebuyBtn) {
|
||||
var rebuyOrder = rebuyBtn.getAttribute("data-aksrt-order-rebuy");
|
||||
if (!rebuyOrder) return;
|
||||
rebuyBtn.disabled = true;
|
||||
request(orderPath(rebuyOrder, "/rebuy"), {})
|
||||
.then(function (result) {
|
||||
rebuyBtn.disabled = false;
|
||||
if (!result || !result.success) {
|
||||
showToast((result && result.message) || "再次购买失败");
|
||||
return;
|
||||
}
|
||||
showToast("已加入购物车");
|
||||
window.location.href = cartUrl();
|
||||
})
|
||||
.catch(function () {
|
||||
rebuyBtn.disabled = false;
|
||||
showToast("网络错误");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Review modal (zibll order_comment_modal 1:1 UX)
|
||||
var reviewBtn = event.target.closest("[data-aksrt-order-review]");
|
||||
if (reviewBtn) {
|
||||
@@ -992,103 +862,8 @@
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// After-Sale
|
||||
var afterSaleButton = event.target.closest("[data-aksrt-order-after-sale]");
|
||||
if (afterSaleButton) {
|
||||
var afterSaleOrderNumber = afterSaleButton.getAttribute("data-aksrt-order-after-sale");
|
||||
closeOrderDetailModal();
|
||||
openAfterSaleModal(afterSaleOrderNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
/**
|
||||
* Product archive — cat filter + sort + AJAX load more (zibll ajax-next UX).
|
||||
*
|
||||
* Uses REST /shop/frontend/products/archive and optional AksrtAjaxList events.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var root = document.querySelector("[data-aksrt-product-archive]");
|
||||
if (!root) return;
|
||||
|
||||
function restBase() {
|
||||
var site = window.aksrtData && aksrtData.siteUrl ? String(aksrtData.siteUrl).replace(/\/$/, "") : "";
|
||||
return site + "/wp-json/aksrt/v1";
|
||||
}
|
||||
|
||||
function toast(msg) {
|
||||
if (typeof window.aksrtToast === "function") {
|
||||
window.aksrtToast(msg);
|
||||
return;
|
||||
}
|
||||
if (window.console) console.log(msg);
|
||||
}
|
||||
|
||||
var grid = root.querySelector("[data-aksrt-product-grid], #aksrt-product-grid");
|
||||
var pager = root.querySelector("[data-aksrt-ajaxpager], .ajaxpager");
|
||||
var countEl = root.querySelector("[data-aksrt-archive-count]");
|
||||
var headerHost = root.querySelector("[data-aksrt-ajax-header]");
|
||||
var loadMoreBtn = root.querySelector("[data-aksrt-shop-load-more]");
|
||||
var loader = root.querySelector("[data-aksrt-ajax-loader], .post_ajax_loader");
|
||||
|
||||
var state = {
|
||||
taxonomy: root.getAttribute("data-taxonomy") || "",
|
||||
termId: Number(root.getAttribute("data-term-id") || 0),
|
||||
orderby: root.getAttribute("data-orderby") || "date",
|
||||
order: (root.getAttribute("data-order") || "DESC").toUpperCase(),
|
||||
page: Number(root.getAttribute("data-page") || 1),
|
||||
maxPages: Number(root.getAttribute("data-max-pages") || 1),
|
||||
paging: root.getAttribute("data-paging") || "number",
|
||||
ias: root.getAttribute("data-ias") === "1",
|
||||
iasMax: Number(root.getAttribute("data-ias-max") || 5),
|
||||
loading: false,
|
||||
autoLoads: 0,
|
||||
};
|
||||
|
||||
function showLoader(on) {
|
||||
if (loader) {
|
||||
loader.hidden = !on;
|
||||
loader.style.display = on ? "" : "none";
|
||||
loader.classList.toggle("is-loading", !!on);
|
||||
}
|
||||
if (pager) pager.classList.toggle("is-ajax-loading", !!on);
|
||||
}
|
||||
|
||||
function updateLoadMore(hasMore) {
|
||||
var pag = root.querySelector(".ajax-pag");
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.style.display = hasMore ? "" : "none";
|
||||
loadMoreBtn.disabled = false;
|
||||
loadMoreBtn.textContent = hasMore ? "加载更多" : "没有更多了";
|
||||
if (!hasMore) loadMoreBtn.classList.add("ajax-nomore");
|
||||
else loadMoreBtn.classList.remove("ajax-nomore");
|
||||
}
|
||||
if (pag) pag.style.display = hasMore ? "" : "none";
|
||||
}
|
||||
|
||||
function syncOrderbyActive() {
|
||||
root.querySelectorAll("[data-aksrt-shop-orderby]").forEach(function (a) {
|
||||
var key = a.getAttribute("data-aksrt-shop-orderby") || "";
|
||||
var active = key === state.orderby;
|
||||
a.classList.toggle("is-active", active);
|
||||
a.classList.toggle("focus-color", active && key === "price");
|
||||
});
|
||||
}
|
||||
|
||||
function fetchArchive(page, orderby, order, replace, termId) {
|
||||
if (state.loading) return Promise.resolve();
|
||||
state.loading = true;
|
||||
showLoader(true);
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.disabled = true;
|
||||
loadMoreBtn.textContent = "加载中…";
|
||||
}
|
||||
|
||||
var qs = new URLSearchParams();
|
||||
qs.set("taxonomy", state.taxonomy);
|
||||
qs.set("term_id", String(typeof termId === "number" ? termId : state.termId));
|
||||
qs.set("page", String(page));
|
||||
qs.set("orderby", orderby || state.orderby);
|
||||
if ((orderby || state.orderby) === "price") {
|
||||
qs.set("order", order || state.order || "ASC");
|
||||
}
|
||||
|
||||
var container = pager || grid || root;
|
||||
try {
|
||||
container.dispatchEvent(
|
||||
new CustomEvent("post_ajax.before", {
|
||||
bubbles: true,
|
||||
detail: { page: page, orderby: orderby || state.orderby, replace: !!replace },
|
||||
})
|
||||
);
|
||||
} catch (e0) {}
|
||||
|
||||
return fetch(restBase() + "/shop/frontend/products/archive?" + qs.toString(), {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"X-WP-Nonce": (window.aksrtData && aksrtData.restNonce) || "",
|
||||
"X-AKSRT-Ajax": "list",
|
||||
},
|
||||
})
|
||||
.then(function (r) {
|
||||
return r.json();
|
||||
})
|
||||
.then(function (result) {
|
||||
state.loading = false;
|
||||
showLoader(false);
|
||||
if (!result || !result.success || !result.data) {
|
||||
toast((result && result.message) || "加载失败");
|
||||
updateLoadMore(state.page < state.maxPages);
|
||||
return;
|
||||
}
|
||||
var data = result.data;
|
||||
state.page = Number(data.page || page);
|
||||
state.maxPages = Number(data.max_pages || 1);
|
||||
state.orderby = data.orderby || state.orderby;
|
||||
state.order = String(data.order || state.order || "DESC").toUpperCase();
|
||||
if (typeof termId === "number" && termId > 0) {
|
||||
state.termId = termId;
|
||||
}
|
||||
if (data.term && data.term.id) {
|
||||
state.termId = Number(data.term.id);
|
||||
}
|
||||
root.setAttribute("data-page", String(state.page));
|
||||
root.setAttribute("data-max-pages", String(state.maxPages));
|
||||
root.setAttribute("data-orderby", state.orderby);
|
||||
root.setAttribute("data-order", state.order);
|
||||
root.setAttribute("data-term-id", String(state.termId));
|
||||
|
||||
if (countEl && typeof data.total !== "undefined") {
|
||||
countEl.textContent = "共 " + data.total + " 件商品";
|
||||
}
|
||||
var titleEl = root.querySelector("[data-aksrt-archive-title]");
|
||||
if (titleEl && data.term && data.term.name) {
|
||||
titleEl.textContent = data.term.name;
|
||||
}
|
||||
var descEl = root.querySelector("[data-aksrt-archive-desc]");
|
||||
if (descEl && data.term) {
|
||||
descEl.textContent = data.term.description || "";
|
||||
descEl.style.display = data.term.description ? "" : "none";
|
||||
}
|
||||
|
||||
if (headerHost && data.header_html) {
|
||||
// Keep title/count; replace filter widget if present.
|
||||
var existingFilter = headerHost.querySelector("[data-aksrt-shop-cat-filter], .shop-cat-filter");
|
||||
var tmp = document.createElement("div");
|
||||
tmp.innerHTML = data.header_html;
|
||||
var nextFilter = tmp.querySelector("[data-aksrt-shop-cat-filter], .shop-cat-filter") || tmp.firstElementChild;
|
||||
if (existingFilter && nextFilter) {
|
||||
existingFilter.replaceWith(nextFilter);
|
||||
} else if (!existingFilter && nextFilter) {
|
||||
headerHost.appendChild(nextFilter);
|
||||
}
|
||||
}
|
||||
|
||||
var html = data.html || data.empty_html || "";
|
||||
if (grid) {
|
||||
if (replace) {
|
||||
grid.innerHTML = html;
|
||||
} else if (html) {
|
||||
grid.insertAdjacentHTML("beforeend", html);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.paginate_html) {
|
||||
var oldPag = root.querySelector(".ajax-pag");
|
||||
var wrap = document.createElement("div");
|
||||
wrap.innerHTML = data.paginate_html;
|
||||
var nextPag = wrap.firstElementChild;
|
||||
if (oldPag && nextPag) oldPag.replaceWith(nextPag);
|
||||
else if (!oldPag && nextPag && pager) pager.appendChild(nextPag);
|
||||
loadMoreBtn = root.querySelector("[data-aksrt-shop-load-more]");
|
||||
}
|
||||
|
||||
syncOrderbyActive();
|
||||
updateLoadMore(!!data.has_more || state.page < state.maxPages);
|
||||
|
||||
try {
|
||||
container.dispatchEvent(
|
||||
new CustomEvent("post_ajax.ed", {
|
||||
bubbles: true,
|
||||
detail: { page: state.page, replace: !!replace, data: data },
|
||||
})
|
||||
);
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("aksrt:posts:rendered", {
|
||||
bubbles: true,
|
||||
detail: { container: grid, replace: !!replace },
|
||||
})
|
||||
);
|
||||
} catch (e1) {}
|
||||
})
|
||||
.catch(function () {
|
||||
state.loading = false;
|
||||
showLoader(false);
|
||||
updateLoadMore(state.page < state.maxPages);
|
||||
toast("网络错误");
|
||||
});
|
||||
}
|
||||
|
||||
function pushUrl(orderby, order, termUrl) {
|
||||
try {
|
||||
var u = termUrl ? new URL(termUrl, window.location.origin) : new URL(window.location.href);
|
||||
if (orderby) u.searchParams.set("orderby", orderby);
|
||||
else u.searchParams.delete("orderby");
|
||||
u.searchParams.delete("shop_orderby");
|
||||
if (orderby === "price" && order) u.searchParams.set("order", order);
|
||||
else u.searchParams.delete("order");
|
||||
u.searchParams.delete("paged");
|
||||
window.history.replaceState({}, "", u.toString());
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
root.addEventListener("click", function (e) {
|
||||
// Category / sort links with ajax-next — intercept for REST (richer payload).
|
||||
var termLink = e.target.closest("[data-aksrt-shop-term].ajax-next, a.ajax-next[data-aksrt-shop-term]");
|
||||
if (termLink && root.contains(termLink)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var tid = Number(termLink.getAttribute("data-aksrt-shop-term") || 0);
|
||||
var href = termLink.getAttribute("href") || "";
|
||||
state.autoLoads = 0;
|
||||
if (tid > 0) state.termId = tid;
|
||||
pushUrl(state.orderby, state.order, href);
|
||||
var rt = termLink.getAttribute("route-title");
|
||||
if (rt) {
|
||||
try {
|
||||
document.title = rt;
|
||||
} catch (e2) {}
|
||||
}
|
||||
fetchArchive(1, state.orderby, state.order, true, tid);
|
||||
return;
|
||||
}
|
||||
|
||||
var sort = e.target.closest("[data-aksrt-shop-orderby]");
|
||||
if (sort && root.contains(sort) && sort.tagName === "A") {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var orderby = sort.getAttribute("data-aksrt-shop-orderby") || "date";
|
||||
var nextOrder = sort.getAttribute("data-aksrt-shop-order") || "";
|
||||
if (orderby === "price") {
|
||||
if (state.orderby === "price" && nextOrder) {
|
||||
state.order = nextOrder.toUpperCase();
|
||||
} else if (state.orderby !== "price") {
|
||||
state.order = "ASC";
|
||||
} else {
|
||||
state.order = state.order === "ASC" ? "DESC" : "ASC";
|
||||
}
|
||||
}
|
||||
if (orderby === state.orderby && orderby !== "price" && state.paging === "ajax") return;
|
||||
state.orderby = orderby;
|
||||
state.autoLoads = 0;
|
||||
pushUrl(orderby, state.order);
|
||||
fetchArchive(1, orderby, state.order, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var more = e.target.closest("[data-aksrt-shop-load-more]");
|
||||
if (more && root.contains(more)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (state.page >= state.maxPages) return;
|
||||
fetchArchive(state.page + 1, state.orderby, state.order, false);
|
||||
}
|
||||
});
|
||||
|
||||
if (state.paging === "ajax" && state.ias && "IntersectionObserver" in window && loadMoreBtn) {
|
||||
var io = new IntersectionObserver(
|
||||
function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) return;
|
||||
if (state.loading || state.page >= state.maxPages) return;
|
||||
if (state.iasMax > 0 && state.autoLoads >= state.iasMax) return;
|
||||
state.autoLoads += 1;
|
||||
fetchArchive(state.page + 1, state.orderby, state.order, false);
|
||||
});
|
||||
},
|
||||
{ rootMargin: "240px" }
|
||||
);
|
||||
io.observe(loadMoreBtn);
|
||||
}
|
||||
})();
|
||||
@@ -1,407 +0,0 @@
|
||||
/**
|
||||
* Product purchase page — options selector + server cart.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function restBase() {
|
||||
var root = (window.aksrtData && aksrtData.siteUrl) ? String(aksrtData.siteUrl).replace(/\/$/, "") : "";
|
||||
return root + "/wp-json/aksrt/v1";
|
||||
}
|
||||
|
||||
function restNonce() {
|
||||
return (window.aksrtData && aksrtData.restNonce) || "";
|
||||
}
|
||||
|
||||
function toast(msg, type) {
|
||||
if (typeof window.aksrtToast === "function") {
|
||||
window.aksrtToast(msg, type || "info");
|
||||
return;
|
||||
}
|
||||
if (window.aksrt && typeof aksrt.notyf === "function") {
|
||||
aksrt.notyf(msg, { type: type || "info" });
|
||||
return;
|
||||
}
|
||||
window.alert(msg);
|
||||
}
|
||||
|
||||
function rest(path, method, body) {
|
||||
var opts = {
|
||||
method: method || "GET",
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
"X-WP-Nonce": restNonce(),
|
||||
},
|
||||
};
|
||||
if (body !== undefined) {
|
||||
opts.headers["Content-Type"] = "application/json";
|
||||
opts.body = JSON.stringify(body);
|
||||
}
|
||||
return fetch(restBase() + path, opts).then(function (r) {
|
||||
return r.json();
|
||||
});
|
||||
}
|
||||
|
||||
function money(value, payModo) {
|
||||
var n = Number(value || 0).toFixed(2);
|
||||
return payModo === "points" ? n : "¥" + n;
|
||||
}
|
||||
|
||||
/* ── Product page ── */
|
||||
var productPage = document.querySelector("[data-aksrt-product-page]");
|
||||
if (productPage) {
|
||||
var quantityInput = productPage.querySelector("[data-aksrt-quantity]");
|
||||
var productId = Number(productPage.getAttribute("data-product-id") || 0);
|
||||
var titleEl = productPage.querySelector(".aksrt-product-page__title");
|
||||
var imageEl = productPage.querySelector(".aksrt-product-page__primary-image img");
|
||||
var priceEl = productPage.querySelector("[data-aksrt-dynamic-price], .aksrt-product-page__price");
|
||||
var stockEl = productPage.querySelector("[data-aksrt-stock-display]");
|
||||
var couponEl = productPage.querySelector("[data-aksrt-product-coupon]");
|
||||
var optionsRoot = productPage.querySelector("[data-aksrt-options-selector]");
|
||||
var optionResult = productPage.querySelector("[data-aksrt-option-result]");
|
||||
var selectedLabelsEl = productPage.querySelector("[data-aksrt-selected-labels]");
|
||||
var resolvedPriceEl = productPage.querySelector("[data-aksrt-resolved-price]");
|
||||
var resolvedStockEl = productPage.querySelector("[data-aksrt-resolved-stock]");
|
||||
var payModo = productPage.getAttribute("data-pay-modo") || "0";
|
||||
var basePrice = Number(productPage.getAttribute("data-base-price") || 0);
|
||||
var baseStock = Number(productPage.getAttribute("data-base-stock") || 0);
|
||||
var selectedByGroup = {};
|
||||
var groupCount = optionsRoot
|
||||
? optionsRoot.querySelectorAll(".aksrt-product-page__option-group").length
|
||||
: 0;
|
||||
|
||||
function currentOptionsKey() {
|
||||
if (!groupCount) return "";
|
||||
var labels = [];
|
||||
for (var i = 0; i < groupCount; i++) {
|
||||
if (!selectedByGroup[i]) return null;
|
||||
labels.push(selectedByGroup[i].label);
|
||||
}
|
||||
return labels.join("|");
|
||||
}
|
||||
|
||||
function resolveSelection() {
|
||||
if (!groupCount) {
|
||||
return {
|
||||
key: "",
|
||||
labels: "",
|
||||
price: basePrice,
|
||||
stock: baseStock,
|
||||
image: "",
|
||||
};
|
||||
}
|
||||
var key = currentOptionsKey();
|
||||
if (key === null) return null;
|
||||
|
||||
var price = basePrice;
|
||||
var image = "";
|
||||
var labels = [];
|
||||
for (var i = 0; i < groupCount; i++) {
|
||||
var sel = selectedByGroup[i];
|
||||
labels.push(sel.label);
|
||||
price += Number(sel.priceChange || 0);
|
||||
if (sel.image) image = sel.image;
|
||||
}
|
||||
return {
|
||||
key: key,
|
||||
labels: labels.join(" / "),
|
||||
price: Math.max(0, price),
|
||||
stock: baseStock,
|
||||
image: image,
|
||||
};
|
||||
}
|
||||
|
||||
function paintSelection() {
|
||||
var resolved = resolveSelection();
|
||||
if (!resolved) {
|
||||
if (optionResult) optionResult.hidden = true;
|
||||
return;
|
||||
}
|
||||
if (priceEl) {
|
||||
if (groupCount && productPage.getAttribute("data-price-range") === "1" && currentOptionsKey() === null) {
|
||||
/* keep range until complete selection */
|
||||
} else {
|
||||
priceEl.textContent = money(resolved.price, payModo) + (payModo === "points" ? "" : "");
|
||||
if (payModo === "points" && priceEl.querySelector("small") === null) {
|
||||
/* leave as-is */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stockEl && resolved.stock > -1) {
|
||||
stockEl.textContent = String(resolved.stock);
|
||||
}
|
||||
if (quantityInput && resolved.stock > 0) {
|
||||
quantityInput.setAttribute("max", String(resolved.stock));
|
||||
if (Number(quantityInput.value) > resolved.stock) {
|
||||
quantityInput.value = String(resolved.stock);
|
||||
}
|
||||
}
|
||||
if (imageEl && resolved.image) {
|
||||
imageEl.setAttribute("src", resolved.image);
|
||||
}
|
||||
if (optionResult) {
|
||||
optionResult.hidden = false;
|
||||
if (selectedLabelsEl) selectedLabelsEl.textContent = resolved.labels;
|
||||
if (resolvedPriceEl) resolvedPriceEl.textContent = money(resolved.price, payModo);
|
||||
if (resolvedStockEl) {
|
||||
resolvedStockEl.textContent =
|
||||
resolved.stock <= -1 ? "库存充足" : "库存 " + resolved.stock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (optionsRoot) {
|
||||
optionsRoot.addEventListener("click", function (event) {
|
||||
var btn = event.target.closest("[data-option-group]");
|
||||
if (!btn || !optionsRoot.contains(btn)) return;
|
||||
var group = btn.getAttribute("data-option-group");
|
||||
var label = btn.getAttribute("data-option-label") || "";
|
||||
var priceChange = Number(btn.getAttribute("data-price-change") || 0);
|
||||
var image = btn.getAttribute("data-option-image") || "";
|
||||
|
||||
optionsRoot
|
||||
.querySelectorAll('[data-option-group="' + group + '"]')
|
||||
.forEach(function (el) {
|
||||
el.classList.remove("is-active");
|
||||
});
|
||||
btn.classList.add("is-active");
|
||||
selectedByGroup[group] = { label: label, priceChange: priceChange, image: image };
|
||||
paintSelection();
|
||||
});
|
||||
}
|
||||
|
||||
function ensureOptionsSelected() {
|
||||
if (!groupCount) return true;
|
||||
if (currentOptionsKey() === null) {
|
||||
toast("请先选择商品规格", "warning");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function addToServerCart(replaceQty) {
|
||||
if (!window.aksrtData || !aksrtData.isLoggedIn) {
|
||||
window.location.href = (aksrtData && aksrtData.routes && aksrtData.routes.login) || "/";
|
||||
return;
|
||||
}
|
||||
if (!ensureOptionsSelected()) return;
|
||||
|
||||
var qty = Number(quantityInput ? quantityInput.value : 1) || 1;
|
||||
var optionsString = currentOptionsKey() || "";
|
||||
var body = {
|
||||
product_id: productId,
|
||||
options_string: optionsString,
|
||||
count: qty,
|
||||
};
|
||||
|
||||
rest("/shop/frontend/cart/add", "POST", body)
|
||||
.then(function (result) {
|
||||
if (!result || !result.success) {
|
||||
toast((result && (result.message || result.error)) || "加入购物车失败", "error");
|
||||
return;
|
||||
}
|
||||
toast("已加入购物车", "success");
|
||||
if (replaceQty) {
|
||||
var cartUrl = new URL(
|
||||
(window.aksrtData && (aksrtData.cartUrl || (aksrtData.routes && aksrtData.routes.cart))) || "/",
|
||||
window.location.origin
|
||||
);
|
||||
if (couponEl && couponEl.value) {
|
||||
cartUrl.searchParams.set("coupon", couponEl.value);
|
||||
}
|
||||
window.location.href = cartUrl.toString();
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
toast("网络错误,请稍后重试", "error");
|
||||
});
|
||||
}
|
||||
|
||||
productPage.addEventListener("click", function (event) {
|
||||
var qtyBtn = event.target.closest("[data-aksrt-qty-action]");
|
||||
if (qtyBtn && quantityInput) {
|
||||
var action = qtyBtn.getAttribute("data-aksrt-qty-action");
|
||||
var current = Number(quantityInput.value || 1);
|
||||
var max = Number(quantityInput.getAttribute("max") || 999);
|
||||
quantityInput.value = action === "inc" ? Math.min(max, current + 1) : Math.max(1, current - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-add-cart]")) {
|
||||
addToServerCart(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-buy-now]")) {
|
||||
addToServerCart(true);
|
||||
return;
|
||||
}
|
||||
|
||||
var thumb = event.target.closest("[data-aksrt-product-thumb]");
|
||||
if (thumb && imageEl) {
|
||||
imageEl.setAttribute("src", thumb.getAttribute("data-aksrt-product-thumb"));
|
||||
return;
|
||||
}
|
||||
|
||||
var videoBtn = event.target.closest("[data-aksrt-product-video]");
|
||||
if (videoBtn) {
|
||||
var url = videoBtn.getAttribute("data-aksrt-product-video");
|
||||
if (url) window.open(url, "_blank", "noopener");
|
||||
return;
|
||||
}
|
||||
|
||||
var favBtn = event.target.closest("[data-aksrt-toggle-fav]");
|
||||
if (favBtn) {
|
||||
if (!window.aksrtData || !aksrtData.isLoggedIn) {
|
||||
window.location.href = (aksrtData && aksrtData.routes && aksrtData.routes.login) || "/";
|
||||
return;
|
||||
}
|
||||
var pid = Number(favBtn.getAttribute("data-aksrt-toggle-fav") || productId);
|
||||
rest("/shop/frontend/products/" + pid + "/favorite", "POST", {})
|
||||
.then(function (result) {
|
||||
if (!result || !result.success) {
|
||||
toast((result && result.message) || "操作失败", "error");
|
||||
return;
|
||||
}
|
||||
var active = !!(result.data && result.data.is_favorite);
|
||||
productPage.querySelectorAll("[data-aksrt-toggle-fav]").forEach(function (btn) {
|
||||
btn.classList.toggle("is-active", active);
|
||||
});
|
||||
toast((result.message) || (active ? "已收藏" : "已取消收藏"), "success");
|
||||
})
|
||||
.catch(function () {
|
||||
toast("网络错误", "error");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var tabBtn = event.target.closest("[data-aksrt-product-tab]");
|
||||
if (tabBtn) {
|
||||
var tab = tabBtn.getAttribute("data-aksrt-product-tab");
|
||||
productPage.querySelectorAll("[data-aksrt-product-tab]").forEach(function (b) {
|
||||
b.classList.toggle("is-active", b === tabBtn);
|
||||
});
|
||||
productPage.querySelectorAll("[data-aksrt-product-panel]").forEach(function (panel) {
|
||||
panel.hidden = panel.getAttribute("data-aksrt-product-panel") !== tab;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-aksrt-show-params]")) {
|
||||
var paramsModal = productPage.querySelector("[data-aksrt-params-modal]");
|
||||
if (paramsModal) paramsModal.hidden = false;
|
||||
return;
|
||||
}
|
||||
if (event.target.closest("[data-aksrt-show-services]")) {
|
||||
var servicesModal = productPage.querySelector("[data-aksrt-services-modal]");
|
||||
if (servicesModal) servicesModal.hidden = false;
|
||||
return;
|
||||
}
|
||||
if (event.target.closest("[data-aksrt-close-modal]")) {
|
||||
var modal = event.target.closest("[data-aksrt-params-modal], [data-aksrt-services-modal], .aksrt-modal");
|
||||
if (modal) modal.hidden = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ── Product editor (seller) ── */
|
||||
var editor = document.querySelector("[data-aksrt-product-editor]");
|
||||
if (!editor || !window.aksrtData) {
|
||||
return;
|
||||
}
|
||||
|
||||
var form = editor.querySelector("[data-aksrt-product-form]");
|
||||
var messageEl = editor.querySelector("[data-aksrt-product-editor-message]");
|
||||
if (!form) return;
|
||||
|
||||
function selectedMultiValues(select) {
|
||||
if (!select) return [];
|
||||
return Array.prototype.slice
|
||||
.call(select.options)
|
||||
.filter(function (option) { return option.selected; })
|
||||
.map(function (option) { return Number(option.value || 0); })
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function parseOptionsText(text) {
|
||||
var groups = [];
|
||||
String(text || "").split(String.fromCharCode(10)).forEach(function (line) {
|
||||
line = line.replace(/\r/g, "").trim();
|
||||
if (!line) return;
|
||||
var parts = line.split("|");
|
||||
if (parts.length < 2) return;
|
||||
var name = parts[0].trim();
|
||||
var values = [];
|
||||
parts.slice(1).join("|").split(",").forEach(function (chunk) {
|
||||
chunk = chunk.trim();
|
||||
if (!chunk) return;
|
||||
var segs = chunk.split(":");
|
||||
var label = (segs[0] || "").trim();
|
||||
if (!label) return;
|
||||
values.push({ label: label, price_change: Number(segs[1] || 0), image: "" });
|
||||
});
|
||||
if (name && values.length) {
|
||||
groups.push({ name: name, view_mode: "list", values: values });
|
||||
}
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
var formData = new FormData(form);
|
||||
var productId = Number(editor.getAttribute("data-product-id") || 0);
|
||||
var gallery = String(formData.get("gallery") || "")
|
||||
.split(String.fromCharCode(10))
|
||||
.map(function (line) { return line.replace(/\r/g, "").trim(); })
|
||||
.filter(Boolean);
|
||||
|
||||
var payload = {
|
||||
title: String(formData.get("title") || "").trim(),
|
||||
price: Number(formData.get("price") || 0),
|
||||
stock: Number(formData.get("stock") || 0),
|
||||
excerpt: String(formData.get("excerpt") || ""),
|
||||
content: String(formData.get("content") || ""),
|
||||
status: String(formData.get("status") || "draft"),
|
||||
categories: selectedMultiValues(form.querySelector('select[name="categories[]"]')),
|
||||
tags: String(formData.get("tags") || "")
|
||||
.split(",")
|
||||
.map(function (tag) { return tag.trim(); })
|
||||
.filter(Boolean),
|
||||
image: String(formData.get("image") || "").trim(),
|
||||
gallery: gallery,
|
||||
shipping_mode: String(formData.get("shipping_mode") || "express"),
|
||||
shipping_fee: Number(formData.get("shipping_fee") || 0),
|
||||
after_sale_policy: String(formData.get("after_sale_policy") || ""),
|
||||
support_refund: formData.get("support_refund") === "1",
|
||||
options: parseOptionsText(formData.get("options_text") || ""),
|
||||
start_price: Number(formData.get("start_price") || 0),
|
||||
pay_modo: String(formData.get("pay_modo") || "0"),
|
||||
product_params: String(formData.get("product_params") || ""),
|
||||
product_video: String(formData.get("product_video") || "")
|
||||
.split(String.fromCharCode(10))
|
||||
.map(function (line) { return line.replace(/\r/g, "").trim(); })
|
||||
.filter(Boolean)
|
||||
};
|
||||
|
||||
var path = productId > 0 ? "/shop/frontend/products/" + productId : "/shop/frontend/products";
|
||||
if (messageEl) messageEl.textContent = "正在保存商品...";
|
||||
|
||||
rest(path, "POST", payload)
|
||||
.then(function (result) {
|
||||
if (!result.success) {
|
||||
if (messageEl) messageEl.textContent = result.message || "保存失败。";
|
||||
return;
|
||||
}
|
||||
var centerUrl = aksrtData.userCenterUrl || "/";
|
||||
if (messageEl) messageEl.textContent = "商品已保存,正在返回用户中心...";
|
||||
window.location.href = centerUrl;
|
||||
})
|
||||
.catch(function () {
|
||||
if (messageEl) messageEl.textContent = "网络错误,请稍后重试。";
|
||||
});
|
||||
});
|
||||
})();
|
||||
Reference in new issue
Block a user