feat(shop): complete storefront archive, seller edit, revenue
Wire product cat/tag archives to settings-driven sort and AJAX paging, seller product options/video/params editing, revenue withdraw form and order review submit — finishing remaining shop frontend gaps after buy-path.
This commit is contained in:
1 parent
5a8f08db8a
commit
f3db6c89cc
17 files changed
+1024
-248
No files matched your search
@@ -280,16 +280,47 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Review — jump to product if possible
|
||||
// Review submit modal
|
||||
var reviewBtn = event.target.closest("[data-aksrt-order-review]");
|
||||
if (reviewBtn) {
|
||||
var reviewOrder = reviewBtn.getAttribute("data-aksrt-order-review");
|
||||
var card = reviewBtn.closest("[data-aksrt-order-card]");
|
||||
var productLink = card ? card.querySelector("a[href*='product']") : null;
|
||||
if (productLink && productLink.href) {
|
||||
window.location.href = productLink.href + (productLink.href.indexOf("#") >= 0 ? "" : "#reviews");
|
||||
} else {
|
||||
showToast("请到商品详情页评价");
|
||||
var productId = 0;
|
||||
if (card) {
|
||||
var firstItem = card.querySelector("[data-product-id]");
|
||||
if (firstItem) productId = Number(firstItem.getAttribute("data-product-id") || 0);
|
||||
}
|
||||
if (!productId) {
|
||||
// try parse from item title block dataset if present
|
||||
var any = card ? card.querySelector(".aksrt-orders-page__card-item") : null;
|
||||
if (any && any.getAttribute("data-product-id")) {
|
||||
productId = Number(any.getAttribute("data-product-id") || 0);
|
||||
}
|
||||
}
|
||||
if (!reviewOrder) return;
|
||||
var content = window.prompt("请输入评价内容(可选)", "好评!");
|
||||
if (content === null) return;
|
||||
var rating = window.prompt("商品评分 1-5", "5");
|
||||
var r = Math.max(1, Math.min(5, parseInt(rating || "5", 10) || 5));
|
||||
reviewBtn.disabled = true;
|
||||
request("/shop/frontend/orders/" + reviewOrder + "/review", {
|
||||
product_id: productId,
|
||||
content: content || "好评!",
|
||||
rating_product: r,
|
||||
rating_service: r,
|
||||
rating_shipping: r
|
||||
}).then(function (result) {
|
||||
reviewBtn.disabled = false;
|
||||
if (!result || !result.success) {
|
||||
showToast((result && result.message) || "评价失败");
|
||||
return;
|
||||
}
|
||||
showToast(result.message || "评价已提交");
|
||||
updateCardStatus(findOrderCard(reviewOrder), "completed", "已完成");
|
||||
}).catch(function () {
|
||||
reviewBtn.disabled = false;
|
||||
showToast("网络错误");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+140
-32
@@ -1,44 +1,152 @@
|
||||
/**
|
||||
* AKSRT Product Archive — 商品归档页交互
|
||||
*
|
||||
* 处理商品分类/标签归档页的筛选、排序和加载更多。
|
||||
* Product archive — sort + AJAX load more.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
var grid = document.getElementById('aksrt-product-grid');
|
||||
if (!grid) return;
|
||||
var root = document.querySelector("[data-aksrt-product-archive]");
|
||||
if (!root) return;
|
||||
|
||||
// 商品卡片懒加载图片观察器
|
||||
if ('IntersectionObserver' in window) {
|
||||
var imgObserver = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.isIntersecting) {
|
||||
var img = entry.target;
|
||||
if (img.dataset.src) {
|
||||
img.src = img.dataset.src;
|
||||
img.removeAttribute('data-src');
|
||||
}
|
||||
imgObserver.unobserve(img);
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '200px' });
|
||||
function restBase() {
|
||||
var site = (window.aksrtData && aksrtData.siteUrl) ? String(aksrtData.siteUrl).replace(/\/$/, "") : "";
|
||||
return site + "/wp-json/aksrt/v1";
|
||||
}
|
||||
|
||||
grid.querySelectorAll('img[data-src]').forEach(function (img) {
|
||||
imgObserver.observe(img);
|
||||
});
|
||||
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 countEl = root.querySelector("[data-aksrt-archive-count]");
|
||||
var loadMoreBtn = root.querySelector("[data-aksrt-shop-load-more]");
|
||||
var state = {
|
||||
taxonomy: root.getAttribute("data-taxonomy") || "",
|
||||
termId: Number(root.getAttribute("data-term-id") || 0),
|
||||
orderby: root.getAttribute("data-orderby") || "date",
|
||||
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 fetchArchive(page, orderby, replace) {
|
||||
if (state.loading) return Promise.resolve();
|
||||
state.loading = true;
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.disabled = true;
|
||||
loadMoreBtn.textContent = "加载中...";
|
||||
}
|
||||
|
||||
// 商品卡片 hover 效果增强
|
||||
grid.querySelectorAll('.aksrt-product-card').forEach(function (card) {
|
||||
card.addEventListener('mouseenter', function () {
|
||||
this.classList.add('aksrt-product-card--hover');
|
||||
var qs = new URLSearchParams();
|
||||
qs.set("taxonomy", state.taxonomy);
|
||||
qs.set("term_id", String(state.termId));
|
||||
qs.set("page", String(page));
|
||||
qs.set("orderby", orderby || state.orderby);
|
||||
|
||||
return fetch(restBase() + "/shop/frontend/products/archive?" + qs.toString(), {
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: {
|
||||
"X-WP-Nonce": (window.aksrtData && aksrtData.restNonce) || "",
|
||||
},
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (result) {
|
||||
state.loading = false;
|
||||
if (!result || !result.success || !result.data) {
|
||||
toast((result && result.message) || "加载失败");
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.disabled = false;
|
||||
loadMoreBtn.textContent = "加载更多";
|
||||
}
|
||||
return;
|
||||
}
|
||||
var data = result.data;
|
||||
state.page = Number(data.page || page);
|
||||
state.maxPages = Number(data.max_pages || 1);
|
||||
state.orderby = data.orderby || state.orderby;
|
||||
root.setAttribute("data-page", String(state.page));
|
||||
root.setAttribute("data-max-pages", String(state.maxPages));
|
||||
root.setAttribute("data-orderby", state.orderby);
|
||||
|
||||
if (countEl && typeof data.total !== "undefined") {
|
||||
countEl.textContent = "共 " + data.total + " 件商品";
|
||||
}
|
||||
|
||||
if (grid) {
|
||||
if (replace) {
|
||||
grid.innerHTML = data.html || "";
|
||||
} else if (data.html) {
|
||||
grid.insertAdjacentHTML("beforeend", data.html);
|
||||
}
|
||||
}
|
||||
|
||||
root.querySelectorAll("[data-aksrt-shop-orderby]").forEach(function (a) {
|
||||
a.classList.toggle("is-active", a.getAttribute("data-aksrt-shop-orderby") === state.orderby);
|
||||
});
|
||||
card.addEventListener('mouseleave', function () {
|
||||
this.classList.remove('aksrt-product-card--hover');
|
||||
});
|
||||
});
|
||||
|
||||
if (loadMoreBtn) {
|
||||
var hasMore = state.page < state.maxPages;
|
||||
loadMoreBtn.style.display = hasMore ? "" : "none";
|
||||
loadMoreBtn.disabled = false;
|
||||
loadMoreBtn.textContent = "加载更多";
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
state.loading = false;
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.disabled = false;
|
||||
loadMoreBtn.textContent = "加载更多";
|
||||
}
|
||||
toast("网络错误");
|
||||
});
|
||||
}
|
||||
|
||||
root.addEventListener("click", function (e) {
|
||||
var sort = e.target.closest("[data-aksrt-shop-orderby]");
|
||||
if (sort && root.contains(sort)) {
|
||||
e.preventDefault();
|
||||
var orderby = sort.getAttribute("data-aksrt-shop-orderby") || "date";
|
||||
if (orderby === state.orderby && state.paging === "ajax") return;
|
||||
state.orderby = orderby;
|
||||
state.autoLoads = 0;
|
||||
try {
|
||||
var u = new URL(window.location.href);
|
||||
u.searchParams.set("shop_orderby", orderby);
|
||||
u.searchParams.delete("paged");
|
||||
window.history.replaceState({}, "", u.toString());
|
||||
} catch (err) {}
|
||||
fetchArchive(1, orderby, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var more = e.target.closest("[data-aksrt-shop-load-more]");
|
||||
if (more && root.contains(more)) {
|
||||
e.preventDefault();
|
||||
if (state.page >= state.maxPages) return;
|
||||
fetchArchive(state.page + 1, state.orderby, 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, false);
|
||||
});
|
||||
}, { rootMargin: "240px" });
|
||||
io.observe(loadMoreBtn);
|
||||
}
|
||||
})();
|
||||
@@ -320,25 +320,43 @@
|
||||
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(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(/\r?\n/)
|
||||
.map(function (line) {
|
||||
return line.trim();
|
||||
})
|
||||
.split(String.fromCharCode(10))
|
||||
.map(function (line) { return line.replace(/\r/g, "").trim(); })
|
||||
.filter(Boolean);
|
||||
|
||||
var payload = {
|
||||
@@ -351,9 +369,7 @@
|
||||
categories: selectedMultiValues(form.querySelector('select[name="categories[]"]')),
|
||||
tags: String(formData.get("tags") || "")
|
||||
.split(",")
|
||||
.map(function (tag) {
|
||||
return tag.trim();
|
||||
})
|
||||
.map(function (tag) { return tag.trim(); })
|
||||
.filter(Boolean),
|
||||
image: String(formData.get("image") || "").trim(),
|
||||
gallery: gallery,
|
||||
@@ -361,6 +377,14 @@
|
||||
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";
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Creator revenue / withdraw form.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var page = document.querySelector("[data-aksrt-revenue-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();
|
||||
});
|
||||
}
|
||||
|
||||
var form = page.querySelector("[data-aksrt-withdraw-form]");
|
||||
var msg = page.querySelector("[data-aksrt-withdraw-msg]");
|
||||
var balanceEl = page.querySelector("[data-aksrt-revenue-balance]");
|
||||
var list = page.querySelector("[data-aksrt-withdraw-list]");
|
||||
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
var fd = new FormData(form);
|
||||
var amount = Number(fd.get("amount") || 0);
|
||||
var method = String(fd.get("method") || "alipay");
|
||||
var account = String(fd.get("account_info") || "").trim();
|
||||
var min = Number(page.getAttribute("data-min-amount") || 50);
|
||||
if (amount < min) {
|
||||
if (msg) {
|
||||
msg.hidden = false;
|
||||
msg.textContent = "最低提现金额为 " + min;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!account) {
|
||||
if (msg) {
|
||||
msg.hidden = false;
|
||||
msg.textContent = "请填写收款账户信息";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var btn = form.querySelector('button[type="submit"]');
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.textContent = "提交中...";
|
||||
}
|
||||
|
||||
rest("/shop/frontend/revenue/withdraw", "POST", {
|
||||
amount: amount,
|
||||
method: method,
|
||||
account_info: account,
|
||||
})
|
||||
.then(function (result) {
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = "提交提现申请";
|
||||
}
|
||||
if (!result || !result.success) {
|
||||
if (msg) {
|
||||
msg.hidden = false;
|
||||
msg.textContent = (result && result.message) || "提现失败";
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (msg) {
|
||||
msg.hidden = false;
|
||||
msg.textContent = result.message || "提现申请已提交";
|
||||
}
|
||||
if (balanceEl && result.data && typeof result.data.balance !== "undefined") {
|
||||
balanceEl.textContent = "¥" + Number(result.data.balance).toFixed(2);
|
||||
}
|
||||
if (list && result.data) {
|
||||
var item = document.createElement("div");
|
||||
item.className = "aksrt-revenue-page__item";
|
||||
item.innerHTML =
|
||||
"<div><strong>¥" +
|
||||
Number(result.data.amount || amount).toFixed(2) +
|
||||
"</strong><span>" +
|
||||
method +
|
||||
"</span></div><div><span>pending</span><time>just now</time></div>";
|
||||
list.insertBefore(item, list.firstChild);
|
||||
}
|
||||
form.reset();
|
||||
})
|
||||
.catch(function () {
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = "提交提现申请";
|
||||
}
|
||||
if (msg) {
|
||||
msg.hidden = false;
|
||||
msg.textContent = "网络错误";
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
Reference in new issue
Block a user