logo和配置修改
This commit is contained in:
@@ -1,307 +0,0 @@
|
||||
(function () {
|
||||
var mask = document.getElementById("coinDialog");
|
||||
if (!mask) return;
|
||||
|
||||
var balanceEls = mask.querySelectorAll("[data-coin-balance]");
|
||||
var costEls = mask.querySelectorAll("[data-coin-cost]");
|
||||
var payBtn = mask.querySelector("[data-coin-dialog-pay]");
|
||||
var loading = false;
|
||||
var paying = false;
|
||||
|
||||
function formatCoins(n) {
|
||||
var num = Number(n);
|
||||
if (!Number.isFinite(num) || num < 0) num = 0;
|
||||
return String(Math.floor(num));
|
||||
}
|
||||
|
||||
function setBalance(n) {
|
||||
var text = formatCoins(n);
|
||||
balanceEls.forEach(function (el) {
|
||||
el.textContent = text;
|
||||
});
|
||||
}
|
||||
|
||||
function setCost(n) {
|
||||
var text = formatCoins(n);
|
||||
costEls.forEach(function (el) {
|
||||
el.textContent = text;
|
||||
});
|
||||
}
|
||||
|
||||
function toast(message, type) {
|
||||
if (typeof window.showToast === "function") {
|
||||
window.showToast(message, type);
|
||||
return;
|
||||
}
|
||||
window.alert(message);
|
||||
}
|
||||
|
||||
function openLogin() {
|
||||
var loginOpen = document.querySelector("[data-login-dialog-open]");
|
||||
if (loginOpen) loginOpen.click();
|
||||
}
|
||||
|
||||
function goToCoinRecharge() {
|
||||
window.location.href = "/deposit/coin/";
|
||||
}
|
||||
|
||||
function isInsufficientBalance(res) {
|
||||
if (!res) return false;
|
||||
if (Number(res.code) === 20004) return true;
|
||||
var message = String(res.tip || res.msg || "");
|
||||
return /(?:金币|余额).{0,6}不足|不足.{0,6}(?:金币|余额)/.test(message);
|
||||
}
|
||||
|
||||
function resolvePlayletId(trigger) {
|
||||
if (trigger) {
|
||||
var fromTrigger = Number(trigger.getAttribute("data-playlet-id") || 0);
|
||||
if (fromTrigger > 0) return fromTrigger;
|
||||
}
|
||||
var fromMask = Number(mask.getAttribute("data-playlet-id") || 0);
|
||||
if (fromMask > 0) return fromMask;
|
||||
var playPage =
|
||||
document.querySelector("[data-play-page]") ||
|
||||
document.querySelector(".play-page");
|
||||
if (playPage) {
|
||||
var fromPage = Number(playPage.getAttribute("data-playlet-id") || 0);
|
||||
if (fromPage > 0) return fromPage;
|
||||
}
|
||||
var player = document.querySelector("[data-play-player]");
|
||||
if (player) {
|
||||
var fromPlayer = Number(player.getAttribute("data-playlet-id") || 0);
|
||||
if (fromPlayer > 0) return fromPlayer;
|
||||
}
|
||||
var likeBtn = document.querySelector("[data-playlet-id]");
|
||||
if (likeBtn) {
|
||||
var fromBtn = Number(likeBtn.getAttribute("data-playlet-id") || 0);
|
||||
if (fromBtn > 0) return fromBtn;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function resolvePlayletSlug(trigger) {
|
||||
if (trigger) {
|
||||
var fromTrigger = String(trigger.getAttribute("data-playlet-slug") || "").trim();
|
||||
if (fromTrigger) return fromTrigger;
|
||||
}
|
||||
var fromMask = String(mask.getAttribute("data-playlet-slug") || "").trim();
|
||||
if (fromMask) return fromMask;
|
||||
var playPage =
|
||||
document.querySelector("[data-play-page]") ||
|
||||
document.querySelector(".play-page");
|
||||
if (playPage) {
|
||||
var fromPage = String(playPage.getAttribute("data-playlet-slug") || "").trim();
|
||||
if (fromPage) return fromPage;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function buildPlayHref(playletId, chapterId) {
|
||||
if (!playletId || !chapterId) return "";
|
||||
var slug = resolvePlayletSlug(null);
|
||||
var key = slug || String(playletId);
|
||||
return "/play/" + encodeURIComponent(key) + "/" + chapterId + "/";
|
||||
}
|
||||
|
||||
function isOnPlayPage() {
|
||||
return !!(
|
||||
document.querySelector("[data-play-page]") ||
|
||||
document.querySelector(".play-page")
|
||||
);
|
||||
}
|
||||
|
||||
function afterUnlockSuccess(playletId, chapterId, data) {
|
||||
var detail = {
|
||||
playletId: playletId,
|
||||
chapterId: chapterId,
|
||||
balance: data && typeof data.balance === "number" ? data.balance : null,
|
||||
canWatch: !!(data && data.canWatch),
|
||||
unlocked: !!(data && data.unlocked),
|
||||
};
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("play:chapter-unlocked", { detail: detail })
|
||||
);
|
||||
if (
|
||||
isOnPlayPage() &&
|
||||
typeof window.playAfterChapterUnlock === "function"
|
||||
) {
|
||||
window.playAfterChapterUnlock(detail);
|
||||
return;
|
||||
}
|
||||
var href = buildPlayHref(playletId, chapterId);
|
||||
if (href) {
|
||||
window.location.href = href;
|
||||
}
|
||||
}
|
||||
|
||||
function setPaying(on) {
|
||||
paying = !!on;
|
||||
if (!payBtn) return;
|
||||
payBtn.disabled = paying;
|
||||
payBtn.classList.toggle("is-loading", paying);
|
||||
payBtn.setAttribute("aria-busy", paying ? "true" : "false");
|
||||
}
|
||||
|
||||
function fetchBalance() {
|
||||
if (!window.HttpRequest) {
|
||||
setBalance(0);
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
return window.HttpRequest.get("/api/auth/getInfo")
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200 || !res.data) {
|
||||
if (res && res.code === 401) {
|
||||
openLogin();
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "获取余额失败");
|
||||
}
|
||||
var recharge = res.data.recharge;
|
||||
setBalance(recharge);
|
||||
if (window.CookieUtil && CookieUtil.setAuthSession) {
|
||||
CookieUtil.setAuthSession(res.data);
|
||||
}
|
||||
return Number(recharge) || 0;
|
||||
})
|
||||
.catch(function (err) {
|
||||
setBalance(0);
|
||||
toast((err && err.message) || "获取余额失败", "error");
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
function unlockAndPlay() {
|
||||
if (paying) return;
|
||||
if (!window.HttpRequest) {
|
||||
toast("网络模块未就绪", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
var chapterId = Number(mask.getAttribute("data-chapter-id") || 0);
|
||||
var playletId = Number(mask.getAttribute("data-playlet-id") || 0);
|
||||
var cost = Number(mask.getAttribute("data-single-coins") || 0);
|
||||
var balance = Number(
|
||||
(balanceEls[0] && balanceEls[0].textContent) || 0
|
||||
);
|
||||
|
||||
if (!chapterId || !playletId) {
|
||||
toast("缺少剧集信息,请刷新后重试", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Number.isFinite(balance) && Number.isFinite(cost) && balance < cost) {
|
||||
goToCoinRecharge();
|
||||
return;
|
||||
}
|
||||
|
||||
setPaying(true);
|
||||
window.HttpRequest.post("/api/playlet/chapter/unlock", {
|
||||
chapterId: chapterId,
|
||||
playletId: playletId,
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
if (res && res.code === 401) {
|
||||
closeDialog();
|
||||
openLogin();
|
||||
return;
|
||||
}
|
||||
if (isInsufficientBalance(res)) {
|
||||
goToCoinRecharge();
|
||||
return;
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "解锁失败");
|
||||
}
|
||||
var data = res.data || {};
|
||||
if (typeof data.balance === "number") {
|
||||
setBalance(data.balance);
|
||||
if (window.CookieUtil && CookieUtil.setAuthSession) {
|
||||
CookieUtil.setAuthSession({ recharge: data.balance });
|
||||
}
|
||||
}
|
||||
toast((res && res.tip) || "解锁成功", "success");
|
||||
closeDialog();
|
||||
afterUnlockSuccess(
|
||||
Number(data.playletId) || playletId,
|
||||
Number(data.chapterId) || chapterId,
|
||||
data
|
||||
);
|
||||
})
|
||||
.catch(function (err) {
|
||||
toast((err && err.message) || "解锁失败,请稍后重试", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
setPaying(false);
|
||||
});
|
||||
}
|
||||
|
||||
function openDialog(event) {
|
||||
if (event) event.preventDefault();
|
||||
var trigger =
|
||||
event && event.target && event.target.closest
|
||||
? event.target.closest("[data-coin-dialog-open]")
|
||||
: null;
|
||||
var singleCoins = trigger
|
||||
? Number(trigger.getAttribute("data-single-coins") || 0)
|
||||
: 0;
|
||||
setCost(singleCoins);
|
||||
if (trigger) {
|
||||
mask.setAttribute(
|
||||
"data-chapter-id",
|
||||
trigger.getAttribute("data-chapter-id") || ""
|
||||
);
|
||||
mask.setAttribute("data-single-coins", String(singleCoins || 0));
|
||||
mask.setAttribute(
|
||||
"data-playlet-id",
|
||||
String(resolvePlayletId(trigger) || "")
|
||||
);
|
||||
mask.setAttribute("data-playlet-slug", resolvePlayletSlug(trigger));
|
||||
} else if (!mask.getAttribute("data-playlet-id")) {
|
||||
mask.setAttribute("data-playlet-id", String(resolvePlayletId(null) || ""));
|
||||
}
|
||||
|
||||
mask.classList.add("is-open");
|
||||
document.body.style.overflow = "hidden";
|
||||
|
||||
if (loading) return;
|
||||
loading = true;
|
||||
fetchBalance().finally(function () {
|
||||
loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
mask.classList.remove("is-open");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
if (event.target.closest("[data-coin-dialog-open]")) {
|
||||
openDialog(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-coin-dialog-close]")) {
|
||||
closeDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-coin-dialog-pay]")) {
|
||||
event.preventDefault();
|
||||
unlockAndPlay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target === mask) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && mask.classList.contains("is-open")) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
window.openCoinDialog = openDialog;
|
||||
window.closeCoinDialog = closeDialog;
|
||||
})();
|
||||
@@ -1,481 +0,0 @@
|
||||
/**
|
||||
* 充值页:套餐 / 支付方式互斥选择,按套餐 payMethods 刷新;提交走 VIP/金币下单。
|
||||
* VIP: POST /api/vip/pay 金币: POST /api/coin/buy
|
||||
* 支付方式严格使用接口返回的 payMethods,不造假默认渠道。
|
||||
*/
|
||||
(function () {
|
||||
var submitting = false;
|
||||
var confirmMask = document.querySelector("[data-deposit-confirm]");
|
||||
var confirmMethods = document.querySelector("[data-deposit-confirm-methods]");
|
||||
var confirmSubmit = document.querySelector("[data-deposit-confirm-submit]");
|
||||
var bodyOverflowBeforeConfirm = "";
|
||||
|
||||
function toast(message, type) {
|
||||
if (window.AuthAPI && typeof AuthAPI.toast === "function") {
|
||||
AuthAPI.toast(message, type || "info");
|
||||
return;
|
||||
}
|
||||
if (typeof showToast === "function") showToast(message, type || "info");
|
||||
}
|
||||
|
||||
function bindExclusive(root, selector, activeClass) {
|
||||
var scope = root || document;
|
||||
var nodes = scope.querySelectorAll(selector);
|
||||
if (!nodes.length) return;
|
||||
nodes.forEach(function (node) {
|
||||
node.addEventListener("click", function () {
|
||||
nodes.forEach(function (item) {
|
||||
item.classList.remove(activeClass);
|
||||
});
|
||||
node.classList.add(activeClass);
|
||||
syncPayTypeAcross(node.getAttribute("data-pay-type") || "");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function syncPayTypeAcross(payType) {
|
||||
if (!payType) return;
|
||||
document.querySelectorAll("[data-pay-type]").forEach(function (el) {
|
||||
var match = String(el.getAttribute("data-pay-type") || "") === String(payType);
|
||||
if (el.classList.contains("deposit-pay-btn")) {
|
||||
el.classList.toggle("deposit-pay-btn--active", match);
|
||||
}
|
||||
if (el.classList.contains("deposit-mobile-pay")) {
|
||||
el.classList.toggle("deposit-mobile-pay--active", match);
|
||||
}
|
||||
if (el.classList.contains("deposit-confirm-method")) {
|
||||
el.classList.toggle("is-active", match);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parsePayMethods(raw) {
|
||||
if (!raw) return [];
|
||||
try {
|
||||
var list = JSON.parse(raw);
|
||||
if (!Array.isArray(list)) return [];
|
||||
return list
|
||||
.map(function (item) {
|
||||
return {
|
||||
type: String((item && item.type) || "").trim(),
|
||||
typeName: String((item && (item.typeName || item.type)) || "").trim(),
|
||||
};
|
||||
})
|
||||
.filter(function (item) {
|
||||
return item.type || item.typeName;
|
||||
});
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function currentPayType() {
|
||||
var active =
|
||||
document.querySelector(".deposit-confirm-method.is-active[data-pay-type]") ||
|
||||
document.querySelector(".deposit-pay-btn--active[data-pay-type]") ||
|
||||
document.querySelector(".deposit-mobile-pay--active[data-pay-type]");
|
||||
return active ? String(active.getAttribute("data-pay-type") || "") : "";
|
||||
}
|
||||
|
||||
function currentPackage() {
|
||||
return (
|
||||
document.querySelector(".deposit-mobile-pkg--active[data-package-id]") ||
|
||||
document.querySelector(".deposit-package--active[data-package-id]")
|
||||
);
|
||||
}
|
||||
|
||||
function renderPayButtons(container, className, activeClass, methods, preferType) {
|
||||
if (!container) return;
|
||||
var list = Array.isArray(methods) ? methods : [];
|
||||
if (!list.length) {
|
||||
container.innerHTML = '<div class="deposit-package-empty">暂无可用支付方式</div>';
|
||||
return;
|
||||
}
|
||||
var prefer = preferType || "";
|
||||
var activeType = prefer;
|
||||
if (!list.some(function (item) { return item.type === prefer; })) {
|
||||
activeType = list[0] ? list[0].type : "";
|
||||
}
|
||||
container.innerHTML = list
|
||||
.map(function (item) {
|
||||
var isActive = item.type === activeType;
|
||||
return (
|
||||
'<button class="' +
|
||||
className +
|
||||
(isActive ? " " + activeClass : "") +
|
||||
'" type="button" data-pay-type="' +
|
||||
escapeAttr(item.type) +
|
||||
'">' +
|
||||
escapeHtml(item.typeName || item.type) +
|
||||
"</button>"
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
bindExclusive(container, "." + className.split(" ").join("."), activeClass);
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
return String(text || "")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
|
||||
function escapeAttr(text) {
|
||||
return escapeHtml(text).replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function payMethodVisual(item) {
|
||||
var value = String((item && (item.typeName || item.type)) || "").toLowerCase();
|
||||
if (/支付宝|alipay/.test(value)) {
|
||||
return { kind: "alipay", icon: "/static/images/figma-dialogs/alipay.svg" };
|
||||
}
|
||||
if (/微信|wechat|weixin|wxpay/.test(value)) {
|
||||
return { kind: "wechat", icon: "/static/images/figma-dialogs/wechat.svg" };
|
||||
}
|
||||
if (/usdt|tether/.test(value)) {
|
||||
return { kind: "usdt", icon: "/static/images/figma-dialogs/usdt.svg" };
|
||||
}
|
||||
return { kind: "other", icon: "" };
|
||||
}
|
||||
|
||||
function renderConfirmMethods(methods, preferType) {
|
||||
if (!confirmMethods) return "";
|
||||
var list = Array.isArray(methods) ? methods : [];
|
||||
var activeType = preferType || (list[0] && list[0].type) || "";
|
||||
if (!list.some(function (item) { return item.type === activeType; })) {
|
||||
activeType = (list[0] && list[0].type) || "";
|
||||
}
|
||||
confirmMethods.innerHTML = list.map(function (item) {
|
||||
var visual = payMethodVisual(item);
|
||||
var icon = visual.icon
|
||||
? '<img src="' + visual.icon + '" alt="" />'
|
||||
: '<span aria-hidden="true">¥</span>';
|
||||
return '<button class="deposit-confirm-method' +
|
||||
(item.type === activeType ? ' is-active' : '') +
|
||||
'" type="button" data-pay-type="' + escapeAttr(item.type) + '">' +
|
||||
'<span class="deposit-confirm-method-copy"><span class="deposit-confirm-method-icon deposit-confirm-method-icon--' + visual.kind + '">' + icon + '</span>' +
|
||||
'<span class="deposit-confirm-method-name">' + escapeHtml(item.typeName || item.type) + '</span></span>' +
|
||||
'<span class="deposit-confirm-method-check" aria-hidden="true">✓</span></button>';
|
||||
}).join("");
|
||||
confirmMethods.querySelectorAll(".deposit-confirm-method").forEach(function (button) {
|
||||
button.addEventListener("click", function () {
|
||||
syncPayTypeAcross(button.getAttribute("data-pay-type") || "");
|
||||
});
|
||||
});
|
||||
syncPayTypeAcross(activeType);
|
||||
return activeType;
|
||||
}
|
||||
|
||||
function hasPayMethods(el) {
|
||||
var target = el || currentPackage();
|
||||
if (!target) return false;
|
||||
return parsePayMethods(target.getAttribute("data-pay-methods")).length > 0;
|
||||
}
|
||||
|
||||
function syncPayMethods(el) {
|
||||
var methods = parsePayMethods(el.getAttribute("data-pay-methods"));
|
||||
var prefer = currentPayType();
|
||||
renderPayButtons(
|
||||
document.querySelector("[data-deposit-pay-pc]"),
|
||||
"deposit-pay-btn",
|
||||
"deposit-pay-btn--active",
|
||||
methods,
|
||||
prefer
|
||||
);
|
||||
renderPayButtons(
|
||||
document.querySelector("[data-deposit-pay-mobile]"),
|
||||
"deposit-mobile-pay",
|
||||
"deposit-mobile-pay--active",
|
||||
methods,
|
||||
prefer
|
||||
);
|
||||
}
|
||||
|
||||
function syncPackageActive(kind, packageId) {
|
||||
document.querySelectorAll(".deposit-package, .deposit-mobile-pkg").forEach(function (el) {
|
||||
var match =
|
||||
String(el.getAttribute("data-package-id") || "") === String(packageId) &&
|
||||
String(el.getAttribute("data-package-kind") || "") === String(kind);
|
||||
el.classList.toggle("deposit-package--active", match && el.classList.contains("deposit-package"));
|
||||
el.classList.toggle(
|
||||
"deposit-mobile-pkg--active",
|
||||
match && el.classList.contains("deposit-mobile-pkg")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function updateSubmitButtons(price, loading) {
|
||||
var canPay = hasPayMethods(currentPackage());
|
||||
var disabled = !!loading || !canPay;
|
||||
var pkg = currentPackage();
|
||||
var packageName = pkg ? String(pkg.getAttribute("data-package-name") || "").trim() : "";
|
||||
var text;
|
||||
if (loading) {
|
||||
text = "支付中...";
|
||||
} else if (!canPay) {
|
||||
text = "暂无支付方式";
|
||||
} else {
|
||||
text = "立即支付 ¥" + (price || "0");
|
||||
}
|
||||
document.querySelectorAll("[data-deposit-submit]").forEach(function (btn) {
|
||||
btn.disabled = disabled;
|
||||
btn.classList.toggle("is-loading", !!loading);
|
||||
btn.classList.toggle("is-disabled", !canPay && !loading);
|
||||
if (btn.classList.contains("deposit-pc-submit")) {
|
||||
btn.textContent = loading ? "支付中..." : canPay ? "立即支付 ¥" + (price || "0") : "暂无支付方式";
|
||||
} else {
|
||||
btn.textContent = loading ? "支付中..." : canPay ? "支付 ¥" + (price || "0") + " 充值金币" : text;
|
||||
}
|
||||
});
|
||||
document.querySelectorAll("[data-deposit-selected-note]").forEach(function (node) {
|
||||
node.textContent = packageName
|
||||
? "已选择 " + packageName + " · 点击后选择支付方式"
|
||||
: "请选择金币套餐";
|
||||
});
|
||||
}
|
||||
|
||||
function onPackageClick(el) {
|
||||
var kind = el.getAttribute("data-package-kind") || "";
|
||||
var id = el.getAttribute("data-package-id") || "";
|
||||
var price = el.getAttribute("data-price") || "0";
|
||||
syncPackageActive(kind, id);
|
||||
syncPayMethods(el);
|
||||
updateSubmitButtons(price, false);
|
||||
}
|
||||
|
||||
function openPayUrl(data) {
|
||||
var url = data && data.payUrl ? String(data.payUrl).trim() : "";
|
||||
if (!url) {
|
||||
toast("未获取到支付链接", "error");
|
||||
return;
|
||||
}
|
||||
var mode = String((data && data.payUrlMode) || "").toLowerCase();
|
||||
var openNew =
|
||||
!!(data && data.isOpenNewBrowser) ||
|
||||
mode === "new" ||
|
||||
mode === "blank" ||
|
||||
mode === "external";
|
||||
if (openNew) {
|
||||
var win = window.open(url, "_blank");
|
||||
if (!win) {
|
||||
window.location.href = url;
|
||||
}
|
||||
return;
|
||||
}
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
function ensureLoggedIn() {
|
||||
if (window.CookieUtil && CookieUtil.isLoggedIn()) return true;
|
||||
toast("请先登录后再支付", "error");
|
||||
var loginURL = "/login/return/deposit/";
|
||||
if (typeof window.openLoginDialog === "function") {
|
||||
var opened = window.openLoginDialog();
|
||||
if (opened && typeof opened.then === "function") {
|
||||
opened.catch(function () {
|
||||
window.location.href = loginURL;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
window.location.href = loginURL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function closePayConfirm() {
|
||||
if (!confirmMask) return;
|
||||
confirmMask.classList.remove("is-open");
|
||||
confirmMask.setAttribute("aria-hidden", "true");
|
||||
document.body.style.overflow = bodyOverflowBeforeConfirm;
|
||||
}
|
||||
|
||||
function openPayConfirm() {
|
||||
if (submitting || !confirmMask) return;
|
||||
if (!ensureLoggedIn()) return;
|
||||
var pkg = currentPackage();
|
||||
if (!pkg) {
|
||||
toast("请选择套餐", "error");
|
||||
return;
|
||||
}
|
||||
var methods = parsePayMethods(pkg.getAttribute("data-pay-methods"));
|
||||
if (!methods.length) {
|
||||
toast("当前套餐暂无可用支付方式", "error");
|
||||
return;
|
||||
}
|
||||
var packageName = String(pkg.getAttribute("data-package-name") || "金币套餐").trim();
|
||||
var price = String(pkg.getAttribute("data-price") || "0").trim();
|
||||
var nameEl = confirmMask.querySelector("[data-deposit-confirm-name]");
|
||||
var priceEl = confirmMask.querySelector("[data-deposit-confirm-price]");
|
||||
if (nameEl) nameEl.textContent = packageName;
|
||||
if (priceEl) priceEl.textContent = price;
|
||||
renderConfirmMethods(methods, currentPayType());
|
||||
bodyOverflowBeforeConfirm = document.body.style.overflow;
|
||||
document.body.style.overflow = "hidden";
|
||||
confirmMask.classList.add("is-open");
|
||||
confirmMask.setAttribute("aria-hidden", "false");
|
||||
}
|
||||
|
||||
function submitPay() {
|
||||
if (submitting) return;
|
||||
if (!window.HttpRequest) {
|
||||
toast("请求组件未加载", "error");
|
||||
return;
|
||||
}
|
||||
if (!ensureLoggedIn()) return;
|
||||
|
||||
var pkg = currentPackage();
|
||||
if (!pkg) {
|
||||
toast("请选择套餐", "error");
|
||||
return;
|
||||
}
|
||||
var packageId = Number(pkg.getAttribute("data-package-id") || 0);
|
||||
var kind = String(pkg.getAttribute("data-package-kind") || "");
|
||||
var price = pkg.getAttribute("data-price") || "0";
|
||||
var payMode = currentPayType();
|
||||
if (!packageId || (kind !== "vip" && kind !== "coin")) {
|
||||
toast("套餐无效,请重新选择", "error");
|
||||
return;
|
||||
}
|
||||
if (!payMode) {
|
||||
toast("请选择支付方式", "error");
|
||||
return;
|
||||
}
|
||||
if (!hasPayMethods(pkg)) {
|
||||
toast("当前套餐暂无可用支付方式", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
var api = kind === "coin" ? "/api/coin/buy" : "/api/vip/pay";
|
||||
submitting = true;
|
||||
updateSubmitButtons(price, true);
|
||||
if (confirmSubmit) {
|
||||
confirmSubmit.disabled = true;
|
||||
confirmSubmit.textContent = "支付中...";
|
||||
}
|
||||
|
||||
HttpRequest.post(api, { packageId: packageId, payMode: payMode })
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200 || !res.data) {
|
||||
var err = new Error((res && (res.tip || res.msg)) || "发起支付失败");
|
||||
err.code = res && res.code;
|
||||
throw err;
|
||||
}
|
||||
openPayUrl(res.data);
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (err && err.code === 401) {
|
||||
toast("请先登录后再支付", "error");
|
||||
if (typeof window.openLoginDialog === "function") {
|
||||
var opened = window.openLoginDialog();
|
||||
if (opened && typeof opened.then === "function") {
|
||||
opened.catch(function () {
|
||||
window.location.href = "/login/return/deposit/";
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
toast((err && err.message) || "发起支付失败", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
submitting = false;
|
||||
updateSubmitButtons(price, false);
|
||||
if (confirmSubmit) {
|
||||
confirmSubmit.disabled = false;
|
||||
confirmSubmit.textContent = "去支付";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bindExclusive(document, ".deposit-pay-btn", "deposit-pay-btn--active");
|
||||
bindExclusive(document, ".deposit-mobile-pay", "deposit-mobile-pay--active");
|
||||
|
||||
document.querySelectorAll(".deposit-package[data-package-id]").forEach(function (node) {
|
||||
node.addEventListener("click", function () {
|
||||
onPackageClick(node);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".deposit-mobile-pkg[data-package-id]").forEach(function (node) {
|
||||
node.addEventListener("click", function () {
|
||||
onPackageClick(node);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-deposit-submit]").forEach(function (btn) {
|
||||
btn.addEventListener("click", openPayConfirm);
|
||||
});
|
||||
|
||||
if (confirmSubmit) confirmSubmit.addEventListener("click", submitPay);
|
||||
document.querySelectorAll("[data-deposit-confirm-close]").forEach(function (button) {
|
||||
button.addEventListener("click", closePayConfirm);
|
||||
});
|
||||
if (confirmMask) {
|
||||
confirmMask.addEventListener("click", function (event) {
|
||||
if (event.target === confirmMask) closePayConfirm();
|
||||
});
|
||||
}
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && confirmMask && confirmMask.classList.contains("is-open")) {
|
||||
closePayConfirm();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var active =
|
||||
document.querySelector(".deposit-mobile-pkg--active[data-price]") ||
|
||||
document.querySelector(".deposit-package--active[data-price]");
|
||||
if (active) {
|
||||
syncPayMethods(active);
|
||||
updateSubmitButtons(active.getAttribute("data-price") || "0", false);
|
||||
} else {
|
||||
updateSubmitButtons("0", false);
|
||||
}
|
||||
|
||||
// /deposit/coin 时滚动到金币充值区域(套餐默认选中由 SSR 完成)
|
||||
(function scrollPreferCoin() {
|
||||
if (!/\/deposit\/coin\/?$/i.test(window.location.pathname || "")) return;
|
||||
var isMobile = window.matchMedia("(max-width: 767px)").matches;
|
||||
var target = isMobile
|
||||
? document.getElementById("depositCoinMobileTitle")
|
||||
: document.getElementById("depositCoinGroup");
|
||||
if (!target) return;
|
||||
setTimeout(function () {
|
||||
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}, 80);
|
||||
})();
|
||||
|
||||
function formatRecharge(value) {
|
||||
var n = Number(value);
|
||||
if (!isFinite(n) || n < 0) n = 0;
|
||||
return String(Math.floor(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
function syncDepositRecharge(value) {
|
||||
var text = formatRecharge(value);
|
||||
document.querySelectorAll("[data-deposit-recharge]").forEach(function (el) {
|
||||
el.textContent = text;
|
||||
});
|
||||
}
|
||||
|
||||
function refreshDepositWallet() {
|
||||
if (!window.CookieUtil || !CookieUtil.isLoggedIn() || !window.HttpRequest) {
|
||||
return;
|
||||
}
|
||||
var session = CookieUtil.getAuthSession();
|
||||
if (session && session.recharge != null && session.recharge !== "") {
|
||||
syncDepositRecharge(session.recharge);
|
||||
}
|
||||
HttpRequest.get("/api/auth/getInfo")
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200 || !res.data) return;
|
||||
if (CookieUtil.setAuthSession) CookieUtil.setAuthSession(res.data);
|
||||
syncDepositRecharge(res.data.recharge);
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
refreshDepositWallet();
|
||||
})();
|
||||
+24
-704
@@ -120,239 +120,18 @@
|
||||
})();
|
||||
|
||||
(function () {
|
||||
// detail.js 同步执行早于 defer 的 request.js,需等 HttpRequest 就绪后再绑定
|
||||
function toast(message, type) {
|
||||
if (typeof window.showToast === "function") {
|
||||
window.showToast(message, type);
|
||||
return;
|
||||
}
|
||||
window.alert(message);
|
||||
}
|
||||
// 付费剧集:不再站内解锁,统一引导下载 APP
|
||||
var lockedEpisodes = document.querySelectorAll("[data-episode-locked]");
|
||||
if (!lockedEpisodes.length) return;
|
||||
|
||||
function bindLikeActions() {
|
||||
var likeBtns = document.querySelectorAll("[data-detail-like]");
|
||||
if (!likeBtns.length) return;
|
||||
if (!window.HttpRequest || typeof window.HttpRequest.post !== "function") {
|
||||
if (!bindLikeActions._retried) {
|
||||
bindLikeActions._retried = true;
|
||||
window.addEventListener("load", bindLikeActions, { once: true });
|
||||
lockedEpisodes.forEach(function (el) {
|
||||
el.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
if (typeof window.openDownloadApp === "function") {
|
||||
window.openDownloadApp();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bindLikeActions._bound) return;
|
||||
bindLikeActions._bound = true;
|
||||
|
||||
function applyLikeUI(isLike, countLike) {
|
||||
var liked = Number(isLike) === 1;
|
||||
likeBtns.forEach(function (btn) {
|
||||
btn.classList.toggle("detail-action--active", liked);
|
||||
btn.classList.toggle("detail-h5-top-btn--active", liked);
|
||||
btn.classList.toggle("detail-h5-like--active", liked);
|
||||
btn.classList.toggle("play-h5-side-item--active", liked);
|
||||
btn.setAttribute("data-liked", liked ? "1" : "2");
|
||||
btn.setAttribute("aria-pressed", liked ? "true" : "false");
|
||||
if (countLike != null) {
|
||||
btn.setAttribute("data-count-like", String(countLike));
|
||||
}
|
||||
var label = btn.querySelector("[data-detail-like-label]");
|
||||
if (label) {
|
||||
if (btn.getAttribute("data-like-label-mode") === "state") {
|
||||
label.textContent = liked ? "已点赞" : "点赞";
|
||||
} else {
|
||||
var n = countLike != null ? countLike : btn.getAttribute("data-count-like");
|
||||
label.textContent = String(n == null || n === "" ? 0 : n);
|
||||
}
|
||||
}
|
||||
var h5Icon = btn.querySelector("[data-h5-like-icon]");
|
||||
if (h5Icon) {
|
||||
h5Icon.src = liked
|
||||
? "/static/images/h5_liked.svg"
|
||||
: "/static/images/like.svg";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
likeBtns.forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
if (btn.getAttribute("data-liking") === "1") return;
|
||||
var playletId = Number(btn.getAttribute("data-playlet-id") || 0);
|
||||
if (!playletId) return;
|
||||
|
||||
var likedNow = Number(btn.getAttribute("data-liked") || 2) === 1;
|
||||
var countNow = Number(btn.getAttribute("data-count-like") || 0);
|
||||
if (Number.isNaN(countNow)) countNow = 0;
|
||||
var nextLike = !likedNow;
|
||||
var nextCount = Math.max(0, countNow + (nextLike ? 1 : -1));
|
||||
|
||||
likeBtns.forEach(function (item) {
|
||||
item.setAttribute("data-liking", "1");
|
||||
item.disabled = true;
|
||||
});
|
||||
applyLikeUI(nextLike ? 1 : 2, nextCount);
|
||||
|
||||
window.HttpRequest.post("/api/playlet/like/set", {
|
||||
id: playletId,
|
||||
isLike: nextLike,
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
if (res && res.code === 401) {
|
||||
var loginOpen = document.querySelector(
|
||||
"[data-login-dialog-open]"
|
||||
);
|
||||
if (loginOpen) loginOpen.click();
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "操作失败");
|
||||
}
|
||||
var data = res.data || {};
|
||||
applyLikeUI(
|
||||
data.isLike != null ? data.isLike : nextLike ? 1 : 2,
|
||||
data.countLike != null ? data.countLike : nextCount
|
||||
);
|
||||
})
|
||||
.catch(function (err) {
|
||||
applyLikeUI(likedNow ? 1 : 2, countNow);
|
||||
toast((err && err.message) || "操作失败,请稍后重试", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
likeBtns.forEach(function (item) {
|
||||
item.removeAttribute("data-liking");
|
||||
item.disabled = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", bindLikeActions, { once: true });
|
||||
} else {
|
||||
bindLikeActions();
|
||||
}
|
||||
})();
|
||||
|
||||
(function () {
|
||||
function toast(message, type) {
|
||||
if (typeof window.showToast === "function") {
|
||||
window.showToast(message, type);
|
||||
return;
|
||||
}
|
||||
window.alert(message);
|
||||
}
|
||||
|
||||
function bindCollectActions() {
|
||||
var collectBtns = document.querySelectorAll("[data-detail-collect]");
|
||||
if (!collectBtns.length) return;
|
||||
if (!window.HttpRequest || typeof window.HttpRequest.post !== "function") {
|
||||
if (!bindCollectActions._retried) {
|
||||
bindCollectActions._retried = true;
|
||||
window.addEventListener("load", bindCollectActions, { once: true });
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bindCollectActions._bound) return;
|
||||
bindCollectActions._bound = true;
|
||||
|
||||
function applyCollectUI(isCollect, countCollect) {
|
||||
var collected = Number(isCollect) === 1;
|
||||
collectBtns.forEach(function (btn) {
|
||||
btn.classList.toggle("detail-action--active", collected);
|
||||
btn.classList.toggle("detail-h5-collect--active", collected);
|
||||
btn.classList.toggle("detail-h5-top-btn--active", collected);
|
||||
btn.classList.toggle("play-h5-side-item--active", collected);
|
||||
btn.classList.toggle("is-collected", collected);
|
||||
btn.setAttribute("data-collected", collected ? "1" : "2");
|
||||
btn.setAttribute("aria-pressed", collected ? "true" : "false");
|
||||
if (countCollect != null) {
|
||||
btn.setAttribute("data-count-collect", String(countCollect));
|
||||
}
|
||||
var label = btn.querySelector("[data-detail-collect-label]");
|
||||
if (label) {
|
||||
if (btn.classList.contains("detail-h5-collect")) {
|
||||
var n = countCollect != null
|
||||
? countCollect
|
||||
: btn.getAttribute("data-count-collect");
|
||||
label.textContent = String(n == null || n === "" ? 0 : n);
|
||||
} else {
|
||||
label.textContent = collected ? "已收藏" : "收藏";
|
||||
}
|
||||
}
|
||||
var h5Icon = btn.querySelector("[data-h5-collect-icon]");
|
||||
if (h5Icon) {
|
||||
if (btn.classList.contains("detail-h5-top-btn")) {
|
||||
h5Icon.src = collected
|
||||
? "/static/images/h5_collected.svg?v=2"
|
||||
: "/static/images/collect.svg";
|
||||
} else if (btn.classList.contains("play-h5-side-item")) {
|
||||
h5Icon.src = collected
|
||||
? "/static/images/h5_collected.svg?v=2"
|
||||
: "/static/images/collect.svg";
|
||||
} else {
|
||||
h5Icon.src = collected
|
||||
? "/static/images/h5_detail_collected.svg"
|
||||
: "/static/images/h5_detail_collect.svg";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
collectBtns.forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
if (btn.getAttribute("data-collecting") === "1") return;
|
||||
var playletId = Number(btn.getAttribute("data-playlet-id") || 0);
|
||||
if (!playletId) return;
|
||||
|
||||
var collectedNow = Number(btn.getAttribute("data-collected") || 2) === 1;
|
||||
var countNow = Number(btn.getAttribute("data-count-collect") || 0);
|
||||
if (Number.isNaN(countNow)) countNow = 0;
|
||||
var nextCollect = !collectedNow;
|
||||
var nextCount = Math.max(0, countNow + (nextCollect ? 1 : -1));
|
||||
|
||||
collectBtns.forEach(function (item) {
|
||||
item.setAttribute("data-collecting", "1");
|
||||
item.disabled = true;
|
||||
});
|
||||
applyCollectUI(nextCollect ? 1 : 2, nextCount);
|
||||
|
||||
window.HttpRequest.post("/api/playlet/collect/set", {
|
||||
id: playletId,
|
||||
isCollect: nextCollect,
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
if (res && res.code === 401) {
|
||||
var loginOpen = document.querySelector(
|
||||
"[data-login-dialog-open]"
|
||||
);
|
||||
if (loginOpen) loginOpen.click();
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "操作失败");
|
||||
}
|
||||
var data = res.data || {};
|
||||
applyCollectUI(
|
||||
data.isCollect != null ? data.isCollect : nextCollect ? 1 : 2,
|
||||
data.countCollect != null ? data.countCollect : nextCount
|
||||
);
|
||||
})
|
||||
.catch(function (err) {
|
||||
applyCollectUI(collectedNow ? 1 : 2, countNow);
|
||||
toast((err && err.message) || "操作失败,请稍后重试", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
collectBtns.forEach(function (item) {
|
||||
item.removeAttribute("data-collecting");
|
||||
item.disabled = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", bindCollectActions, { once: true });
|
||||
} else {
|
||||
bindCollectActions();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
(function () {
|
||||
@@ -593,15 +372,6 @@
|
||||
return formatCommentTime(raw);
|
||||
}
|
||||
|
||||
function formatCompactCount(n) {
|
||||
n = Number(n);
|
||||
if (!n || n < 0 || Number.isNaN(n)) return "0";
|
||||
if (n < 10000) return String(n);
|
||||
var v = n / 10000;
|
||||
if (v >= 10) return Math.floor(v) + "w";
|
||||
return (Math.round(v * 10) / 10) + "w";
|
||||
}
|
||||
|
||||
function avatarURL(url) {
|
||||
url = String(url || "").trim();
|
||||
return url || DEFAULT_AVATAR;
|
||||
@@ -614,10 +384,7 @@
|
||||
}
|
||||
|
||||
function renderDetailComment(item, playPcMode) {
|
||||
var liked = Number(item.isLike) === 1;
|
||||
var avatar = avatarURL(item.userAvatar);
|
||||
var commentId = item.id;
|
||||
var parentsId = Number(item.parentsId || 0) || Number(commentId);
|
||||
var avatarHtml = item.userAvatar
|
||||
? '<img class="detail-comment-avatar lazy" src="' +
|
||||
PLACEHOLDER +
|
||||
@@ -627,9 +394,6 @@
|
||||
escapeHtml((item.userName || "匿名用户") + "的头像") +
|
||||
'" />'
|
||||
: '<img class="detail-comment-avatar" src="' + DEFAULT_AVATAR + '" alt="匿名用户头像" />';
|
||||
var likeIcon = liked
|
||||
? "/static/images/like_solid.svg"
|
||||
: "/static/images/like_hollow.svg";
|
||||
var textHtml = escapeHtml(item.text || "");
|
||||
if (item.replyUserName) {
|
||||
textHtml =
|
||||
@@ -691,11 +455,7 @@
|
||||
}
|
||||
return (
|
||||
'<div class="detail-comment" data-comment-id="' +
|
||||
escapeHtml(commentId) +
|
||||
'" data-parents-id="' +
|
||||
escapeHtml(parentsId) +
|
||||
'" data-user-name="' +
|
||||
escapeHtml(item.userName || "匿名用户") +
|
||||
escapeHtml(item.id) +
|
||||
'">' +
|
||||
avatarHtml +
|
||||
'<div class="detail-comment-body">' +
|
||||
@@ -709,27 +469,6 @@
|
||||
'<span class="detail-comment-time">' +
|
||||
escapeHtml(formatCommentTime(item.createdAt)) +
|
||||
"</span>" +
|
||||
'<button class="detail-comment-like' +
|
||||
(liked ? " detail-comment-like--active" : "") +
|
||||
'" type="button" aria-label="点赞" data-comment-like="' +
|
||||
escapeHtml(commentId) +
|
||||
'" data-liked="' +
|
||||
(liked ? "1" : "2") +
|
||||
'">' +
|
||||
'<img src="' +
|
||||
likeIcon +
|
||||
'" alt="点赞" />' +
|
||||
'<span data-like-count>' +
|
||||
escapeHtml(item.countLike == null ? 0 : item.countLike) +
|
||||
"</span>" +
|
||||
"</button>" +
|
||||
'<button class="detail-comment-reply-label" type="button" data-comment-reply="' +
|
||||
escapeHtml(commentId) +
|
||||
'" data-parents-id="' +
|
||||
escapeHtml(parentsId) +
|
||||
'" data-reply-name="' +
|
||||
escapeHtml(item.userName || "匿名用户") +
|
||||
'">回复</button>' +
|
||||
"</div>" +
|
||||
repliesHtml +
|
||||
"</div></div>"
|
||||
@@ -737,10 +476,8 @@
|
||||
}
|
||||
|
||||
function renderPlayComment(item) {
|
||||
var liked = Number(item.isLike) === 1;
|
||||
var avatar = avatarURL(item.userAvatar);
|
||||
var commentId = item.id;
|
||||
var parentsId = Number(item.parentsId || 0) || Number(commentId);
|
||||
var children = Array.isArray(item.children) ? item.children : [];
|
||||
var replyCount = Number(item.commentCount || children.length || 0);
|
||||
var avatarHtml = item.userAvatar
|
||||
@@ -752,9 +489,6 @@
|
||||
escapeHtml((item.userName || "匿名用户") + "的头像") +
|
||||
'" />'
|
||||
: '<img class="play-comment-avatar" src="' + DEFAULT_AVATAR + '" alt="匿名用户头像" />';
|
||||
var likeIcon = liked
|
||||
? "/static/images/h5_liked.svg"
|
||||
: "/static/images/like_hollow.svg";
|
||||
var textHtml = escapeHtml(item.text || "");
|
||||
if (item.replyUserName) {
|
||||
textHtml =
|
||||
@@ -807,10 +541,6 @@
|
||||
return (
|
||||
'<div class="play-comment-item" data-comment-id="' +
|
||||
escapeHtml(commentId) +
|
||||
'" data-parents-id="' +
|
||||
escapeHtml(parentsId) +
|
||||
'" data-user-name="' +
|
||||
escapeHtml(item.userName || "匿名用户") +
|
||||
'">' +
|
||||
avatarHtml +
|
||||
'<div class="play-comment-body">' +
|
||||
@@ -825,30 +555,7 @@
|
||||
'<span class="play-comment-time">' +
|
||||
escapeHtml(formatRelativeTime(item.createdAt)) +
|
||||
"</span>" +
|
||||
'<button class="play-comment-reply-action" type="button" data-comment-reply="' +
|
||||
escapeHtml(commentId) +
|
||||
'" data-parents-id="' +
|
||||
escapeHtml(parentsId) +
|
||||
'" data-reply-name="' +
|
||||
escapeHtml(item.userName || "匿名用户") +
|
||||
'">回复</button>' +
|
||||
"</div>" +
|
||||
'<button class="play-comment-like' +
|
||||
(liked ? " play-comment-like--active" : "") +
|
||||
'" type="button" aria-label="点赞" data-comment-like="' +
|
||||
escapeHtml(commentId) +
|
||||
'" data-liked="' +
|
||||
(liked ? "1" : "2") +
|
||||
'" data-like-raw="' +
|
||||
escapeHtml(item.countLike == null ? 0 : item.countLike) +
|
||||
'">' +
|
||||
'<img src="' +
|
||||
likeIcon +
|
||||
'" alt="点赞" />' +
|
||||
'<span data-like-count>' +
|
||||
escapeHtml(formatCompactCount(item.countLike)) +
|
||||
"</span>" +
|
||||
"</button>" +
|
||||
"</div>" +
|
||||
repliesHtml +
|
||||
"</div></div>"
|
||||
@@ -887,18 +594,12 @@
|
||||
var scope = sheetRoot || section;
|
||||
var listEl = section.querySelector("[data-comment-list]");
|
||||
var moreBtn = section.querySelector("[data-comment-more]");
|
||||
var composerInput =
|
||||
scope.querySelector(".play-comment-composer-input") ||
|
||||
scope.querySelector(".detail-comment-composer-input");
|
||||
var composerCount = scope.querySelector(".detail-comment-composer-count");
|
||||
var titleEl = section.querySelector("[data-comment-title]");
|
||||
var sendBtn = scope.querySelector("[data-comment-send]");
|
||||
var sortBtns = scope.querySelectorAll("[data-comment-sort]");
|
||||
var sheetTitle = sheetRoot
|
||||
? sheetRoot.querySelector("[data-play-comment-title]")
|
||||
: document.querySelector("[data-play-comment-title]");
|
||||
var sideCount = document.querySelector("[data-play-comment-count]");
|
||||
var iconSend = !!(sendBtn && sendBtn.classList.contains("play-comment-composer-emoji"));
|
||||
|
||||
if (section.getAttribute("data-comment-inited") === "1") return;
|
||||
section.setAttribute("data-comment-inited", "1");
|
||||
@@ -910,169 +611,11 @@
|
||||
var page = 0;
|
||||
var total = 0;
|
||||
var loading = false;
|
||||
var sending = false;
|
||||
var replyTarget = null; // { parentsId, replyCommentId, replyName }
|
||||
var inlineSending = false;
|
||||
|
||||
function getObjectId() {
|
||||
return Number(section.getAttribute("data-comment-object-id") || 0);
|
||||
}
|
||||
|
||||
function clearReplyTarget() {
|
||||
replyTarget = null;
|
||||
if (!scope) return;
|
||||
var boxes = scope.querySelectorAll("[data-comment-inline-composer]");
|
||||
Array.prototype.forEach.call(boxes, function (el) {
|
||||
el.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function setReplyTarget(parentsId, replyCommentId, replyName, anchorEl) {
|
||||
parentsId = Number(parentsId || 0);
|
||||
replyCommentId = Number(replyCommentId || 0);
|
||||
if (!parentsId || !replyCommentId || !anchorEl) return;
|
||||
|
||||
var root =
|
||||
anchorEl.closest(commentItemSelector()) ||
|
||||
anchorEl.closest("[data-comment-id]");
|
||||
if (!root || !scope.contains(root)) return;
|
||||
|
||||
// 再次点击同一条:关闭内联输入框
|
||||
var existingOnRoot = root.querySelector("[data-comment-inline-composer]");
|
||||
if (
|
||||
existingOnRoot &&
|
||||
replyTarget &&
|
||||
replyTarget.replyCommentId === replyCommentId
|
||||
) {
|
||||
clearReplyTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
clearReplyTarget();
|
||||
replyTarget = {
|
||||
parentsId: parentsId,
|
||||
replyCommentId: replyCommentId,
|
||||
replyName: replyName || "用户",
|
||||
};
|
||||
|
||||
var meta =
|
||||
root.querySelector(".detail-comment-meta") ||
|
||||
root.querySelector(".play-comment-meta");
|
||||
var body =
|
||||
root.querySelector(".detail-comment-body") ||
|
||||
root.querySelector(".play-comment-body") ||
|
||||
root;
|
||||
var box = document.createElement("div");
|
||||
box.className = sheetMode
|
||||
? "play-comment-inline-composer"
|
||||
: "detail-comment-inline-composer";
|
||||
box.setAttribute("data-comment-inline-composer", "");
|
||||
var placeholder = "回复 @" + replyTarget.replyName + "…";
|
||||
if (sheetMode) {
|
||||
box.innerHTML =
|
||||
'<div class="play-comment-reply-hint" data-comment-reply-hint>' +
|
||||
"<span>回复 @" +
|
||||
escapeHtml(replyTarget.replyName) +
|
||||
"</span>" +
|
||||
'<button type="button" data-comment-reply-cancel>取消</button>' +
|
||||
"</div>" +
|
||||
'<div class="play-comment-inline-row">' +
|
||||
'<input class="play-comment-inline-input" type="text" maxlength="200" placeholder="' +
|
||||
escapeHtml(placeholder) +
|
||||
'" data-comment-inline-input autocomplete="off" />' +
|
||||
'<button class="play-comment-inline-send" type="button" data-comment-inline-send>发送</button>' +
|
||||
"</div>";
|
||||
} else {
|
||||
box.innerHTML =
|
||||
'<div class="detail-comment-reply-hint" data-comment-reply-hint>' +
|
||||
"<span>回复 @" +
|
||||
escapeHtml(replyTarget.replyName) +
|
||||
"</span>" +
|
||||
'<button type="button" data-comment-reply-cancel>取消</button>' +
|
||||
"</div>" +
|
||||
'<textarea class="detail-comment-inline-input" maxlength="200" rows="2" placeholder="' +
|
||||
escapeHtml(placeholder) +
|
||||
'" data-comment-inline-input></textarea>' +
|
||||
'<div class="detail-comment-inline-footer">' +
|
||||
'<button class="detail-comment-inline-send" type="button" data-comment-inline-send>发表回复</button>' +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
if (meta && meta.parentNode === body) {
|
||||
if (meta.nextSibling) {
|
||||
body.insertBefore(box, meta.nextSibling);
|
||||
} else {
|
||||
body.appendChild(box);
|
||||
}
|
||||
} else {
|
||||
body.appendChild(box);
|
||||
}
|
||||
|
||||
var inlineInput = box.querySelector("[data-comment-inline-input]");
|
||||
if (inlineInput) {
|
||||
inlineInput.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function sendInlineReply(box) {
|
||||
if (!box || inlineSending || !replyTarget) return;
|
||||
var objectId = getObjectId();
|
||||
if (!objectId) return;
|
||||
var input = box.querySelector("[data-comment-inline-input]");
|
||||
var btn = box.querySelector("[data-comment-inline-send]");
|
||||
if (!input) return;
|
||||
var text = String(input.value || "").trim();
|
||||
if (!text) {
|
||||
toast("请输入评论内容", "error");
|
||||
return;
|
||||
}
|
||||
if (Array.from(text).length > 200) {
|
||||
toast("评论最多 200 字", "error");
|
||||
return;
|
||||
}
|
||||
inlineSending = true;
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.classList.add("is-loading");
|
||||
}
|
||||
input.disabled = true;
|
||||
var payload = {
|
||||
objectId: objectId,
|
||||
objectType: objectType,
|
||||
text: text,
|
||||
parentsId: replyTarget.parentsId,
|
||||
replyCommentId:
|
||||
replyTarget.replyCommentId > 0
|
||||
? replyTarget.replyCommentId
|
||||
: replyTarget.parentsId,
|
||||
};
|
||||
window.HttpRequest.post("/api/comment/send", payload)
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
if (res && res.code === 401) {
|
||||
var loginOpen = document.querySelector(
|
||||
"[data-login-dialog-open]"
|
||||
);
|
||||
if (loginOpen) loginOpen.click();
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "发表失败");
|
||||
}
|
||||
clearReplyTarget();
|
||||
toast("发布成功,评论审核后才会展示", "success");
|
||||
})
|
||||
.catch(function (err) {
|
||||
toast((err && err.message) || "发表失败,请稍后重试", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
inlineSending = false;
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove("is-loading");
|
||||
}
|
||||
if (input) input.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
function commentItemSelector() {
|
||||
return sheetMode ? ".play-comment-item" : ".detail-comment";
|
||||
}
|
||||
@@ -1089,32 +632,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function applyLikeUI(btn, isLike, countLike) {
|
||||
var liked = Number(isLike) === 1;
|
||||
btn.classList.toggle("detail-comment-like--active", liked);
|
||||
btn.classList.toggle("play-comment-like--active", liked);
|
||||
btn.setAttribute("data-liked", liked ? "1" : "2");
|
||||
var img = btn.querySelector("img");
|
||||
if (img) {
|
||||
if (sheetMode) {
|
||||
img.src = liked
|
||||
? "/static/images/h5_liked.svg"
|
||||
: "/static/images/like_hollow.svg";
|
||||
} else {
|
||||
img.src = liked
|
||||
? "/static/images/like_solid.svg"
|
||||
: "/static/images/like_hollow.svg";
|
||||
}
|
||||
}
|
||||
var countEl = btn.querySelector("[data-like-count]");
|
||||
if (countEl && countLike != null) {
|
||||
btn.setAttribute("data-like-raw", String(countLike));
|
||||
countEl.textContent = sheetMode
|
||||
? formatCompactCount(countLike)
|
||||
: String(countLike);
|
||||
}
|
||||
}
|
||||
|
||||
function syncSortActive() {
|
||||
sortBtns.forEach(function (item) {
|
||||
var active = Number(item.getAttribute("data-comment-sort")) === sortOrder;
|
||||
@@ -1140,7 +657,6 @@
|
||||
var emptyClass = sheetMode
|
||||
? "section-empty play-comment-empty"
|
||||
: "section-empty";
|
||||
clearReplyTarget();
|
||||
listEl.innerHTML =
|
||||
'<div class="' +
|
||||
emptyClass +
|
||||
@@ -1179,7 +695,6 @@
|
||||
updateTitleCount();
|
||||
|
||||
if (replace) {
|
||||
clearReplyTarget();
|
||||
if (!rows.length) {
|
||||
showEmpty("暂无评论");
|
||||
return;
|
||||
@@ -1225,15 +740,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (composerInput && composerCount) {
|
||||
var syncCount = function () {
|
||||
composerCount.textContent =
|
||||
Array.from(composerInput.value).length + " / 200";
|
||||
};
|
||||
composerInput.addEventListener("input", syncCount);
|
||||
syncCount();
|
||||
}
|
||||
|
||||
syncSortActive();
|
||||
|
||||
sortBtns.forEach(function (btn) {
|
||||
@@ -1251,149 +757,27 @@
|
||||
});
|
||||
});
|
||||
|
||||
if (sendBtn && composerInput) {
|
||||
var sendBtnDefaultText = sendBtn.textContent || "发表评论";
|
||||
sendBtn.addEventListener("click", function () {
|
||||
var objectId = getObjectId();
|
||||
if (sending || !objectId) return;
|
||||
var text = String(composerInput.value || "").trim();
|
||||
if (!text) {
|
||||
toast("请输入评论内容", "error");
|
||||
return;
|
||||
}
|
||||
if (Array.from(text).length > 200) {
|
||||
toast("评论最多 200 字", "error");
|
||||
return;
|
||||
}
|
||||
sending = true;
|
||||
sendBtn.disabled = true;
|
||||
sendBtn.classList.add("is-loading");
|
||||
if (!iconSend) sendBtn.textContent = "发表中";
|
||||
composerInput.disabled = true;
|
||||
var payload = {
|
||||
objectId: objectId,
|
||||
objectType: objectType,
|
||||
text: text,
|
||||
parentsId: 0,
|
||||
replyCommentId: 0,
|
||||
};
|
||||
window.HttpRequest.post("/api/comment/send", payload)
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
if (res && res.code === 401) {
|
||||
var loginOpen = document.querySelector(
|
||||
"[data-login-dialog-open]"
|
||||
);
|
||||
if (loginOpen) loginOpen.click();
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "发表失败");
|
||||
}
|
||||
composerInput.value = "";
|
||||
if (composerCount) composerCount.textContent = "0 / 200";
|
||||
toast("发布成功,评论审核后才会展示", "success");
|
||||
// 与 PC 一致:发表后不强制刷新列表(审核后才可见)
|
||||
})
|
||||
.catch(function (err) {
|
||||
toast((err && err.message) || "发表失败,请稍后重试", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
sending = false;
|
||||
sendBtn.disabled = false;
|
||||
sendBtn.classList.remove("is-loading");
|
||||
if (!iconSend) sendBtn.textContent = sendBtnDefaultText;
|
||||
composerInput.disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
if (sheetMode) {
|
||||
composerInput.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
sendBtn.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
scope.addEventListener("click", function (e) {
|
||||
var cancel =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-comment-reply-cancel]")
|
||||
: null;
|
||||
if (cancel) {
|
||||
e.preventDefault();
|
||||
clearReplyTarget();
|
||||
return;
|
||||
}
|
||||
var inlineSend =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-comment-inline-send]")
|
||||
: null;
|
||||
if (inlineSend && scope.contains(inlineSend)) {
|
||||
e.preventDefault();
|
||||
var box = inlineSend.closest("[data-comment-inline-composer]");
|
||||
sendInlineReply(box);
|
||||
return;
|
||||
}
|
||||
var repliesToggle =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-comment-replies-toggle]")
|
||||
: null;
|
||||
if (repliesToggle && scope.contains(repliesToggle)) {
|
||||
e.preventDefault();
|
||||
var repliesBox = repliesToggle.closest(".detail-comment-replies");
|
||||
if (!repliesBox) return;
|
||||
var expanded = repliesToggle.getAttribute("aria-expanded") === "true";
|
||||
expanded = !expanded;
|
||||
repliesToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
repliesToggle.textContent = replyToggleLabel(
|
||||
expanded,
|
||||
repliesToggle.getAttribute("data-reply-count")
|
||||
);
|
||||
var hiddenItems = repliesBox.querySelectorAll("[data-reply-collapsed-item]");
|
||||
Array.prototype.forEach.call(hiddenItems, function (el) {
|
||||
el.hidden = !expanded;
|
||||
});
|
||||
return;
|
||||
}
|
||||
var replyBtn =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-comment-reply]")
|
||||
: null;
|
||||
if (!replyBtn || !scope.contains(replyBtn)) return;
|
||||
if (!repliesToggle || !scope.contains(repliesToggle)) return;
|
||||
e.preventDefault();
|
||||
var replyCommentId = Number(replyBtn.getAttribute("data-comment-reply") || 0);
|
||||
var parentsId = Number(replyBtn.getAttribute("data-parents-id") || 0);
|
||||
var replyName = replyBtn.getAttribute("data-reply-name") || "用户";
|
||||
if (!parentsId) {
|
||||
var root =
|
||||
replyBtn.closest("[data-parents-id]") ||
|
||||
replyBtn.closest("[data-comment-id]");
|
||||
if (root) {
|
||||
parentsId = Number(
|
||||
root.getAttribute("data-parents-id") ||
|
||||
root.getAttribute("data-comment-id") ||
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!replyCommentId) return;
|
||||
if (!parentsId) parentsId = replyCommentId;
|
||||
setReplyTarget(parentsId, replyCommentId, replyName, replyBtn);
|
||||
});
|
||||
|
||||
scope.addEventListener("keydown", function (e) {
|
||||
if (e.key !== "Enter") return;
|
||||
var input =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-comment-inline-input]")
|
||||
: null;
|
||||
if (!input || !scope.contains(input)) return;
|
||||
if (input.tagName === "TEXTAREA" && !e.ctrlKey && !e.metaKey) return;
|
||||
e.preventDefault();
|
||||
var box = input.closest("[data-comment-inline-composer]");
|
||||
sendInlineReply(box);
|
||||
var repliesBox = repliesToggle.closest(".detail-comment-replies");
|
||||
if (!repliesBox) return;
|
||||
var expanded = repliesToggle.getAttribute("aria-expanded") === "true";
|
||||
expanded = !expanded;
|
||||
repliesToggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
repliesToggle.textContent = replyToggleLabel(
|
||||
expanded,
|
||||
repliesToggle.getAttribute("data-reply-count")
|
||||
);
|
||||
var hiddenItems = repliesBox.querySelectorAll("[data-reply-collapsed-item]");
|
||||
Array.prototype.forEach.call(hiddenItems, function (el) {
|
||||
el.hidden = !expanded;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1403,70 +787,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (listEl) {
|
||||
listEl.addEventListener("click", function (e) {
|
||||
var btn =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-comment-like]")
|
||||
: null;
|
||||
if (!btn || !listEl.contains(btn)) return;
|
||||
var commentId = Number(btn.getAttribute("data-comment-like") || 0);
|
||||
if (!commentId) return;
|
||||
if (btn.getAttribute("data-liking") === "1") return;
|
||||
|
||||
var likedNow = Number(btn.getAttribute("data-liked") || 2) === 1;
|
||||
var nextLike = !likedNow;
|
||||
var rawAttr = btn.getAttribute("data-like-raw");
|
||||
var countEl = btn.querySelector("[data-like-count]");
|
||||
var prevCount = Number(
|
||||
rawAttr != null
|
||||
? rawAttr
|
||||
: countEl && countEl.textContent
|
||||
? countEl.textContent
|
||||
: 0
|
||||
);
|
||||
if (Number.isNaN(prevCount)) prevCount = 0;
|
||||
|
||||
btn.setAttribute("data-liking", "1");
|
||||
btn.disabled = true;
|
||||
applyLikeUI(
|
||||
btn,
|
||||
nextLike ? 1 : 2,
|
||||
Math.max(0, prevCount + (nextLike ? 1 : -1))
|
||||
);
|
||||
|
||||
window.HttpRequest.post("/api/comment/like/set", {
|
||||
commentId: commentId,
|
||||
isLike: nextLike,
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
if (res && res.code === 401) {
|
||||
var loginOpen = document.querySelector(
|
||||
"[data-login-dialog-open]"
|
||||
);
|
||||
if (loginOpen) loginOpen.click();
|
||||
}
|
||||
throw new Error((res && (res.tip || res.msg)) || "操作失败");
|
||||
}
|
||||
var data = res.data || {};
|
||||
applyLikeUI(
|
||||
btn,
|
||||
data.isLike != null ? data.isLike : nextLike ? 1 : 2,
|
||||
data.countLike != null ? data.countLike : null
|
||||
);
|
||||
})
|
||||
.catch(function (err) {
|
||||
applyLikeUI(btn, likedNow ? 1 : 2, prevCount);
|
||||
toast((err && err.message) || "操作失败,请稍后重试", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
btn.removeAttribute("data-liking");
|
||||
btn.disabled = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!listEl || !getObjectId()) {
|
||||
if (listEl) showEmpty("暂无评论");
|
||||
return;
|
||||
|
||||
@@ -7,20 +7,6 @@
|
||||
js: "/static/js/pages/downloadAppDialog.js?v=4",
|
||||
open: "openDownloadAppDialog",
|
||||
},
|
||||
login: {
|
||||
endpoint: "/ui/dialog/login",
|
||||
elementId: "loginDialog",
|
||||
css: "/static/css/loginDialog.css?v=2",
|
||||
js: "/static/js/pages/loginDialog.js?v=3",
|
||||
open: "openLoginDialog",
|
||||
},
|
||||
register: {
|
||||
endpoint: "/ui/dialog/register",
|
||||
elementId: "registerDialog",
|
||||
css: "/static/css/registerDialog.css?v=2",
|
||||
js: "/static/js/pages/registerDialog.js?v=2",
|
||||
open: "openRegisterDialog",
|
||||
},
|
||||
};
|
||||
var pending = Object.create(null);
|
||||
var stubOpeners = Object.create(null);
|
||||
@@ -141,26 +127,6 @@
|
||||
return pending[name];
|
||||
}
|
||||
|
||||
function loginFallbackURL() {
|
||||
var redirect = "";
|
||||
try {
|
||||
redirect = global.location.pathname || "/";
|
||||
} catch (e) {
|
||||
redirect = "/";
|
||||
}
|
||||
var url = "/login/";
|
||||
if (
|
||||
typeof redirect === "string" &&
|
||||
redirect.charAt(0) === "/" &&
|
||||
redirect.charAt(1) !== "/" &&
|
||||
redirect !== "/" &&
|
||||
redirect.indexOf("/?auth=") !== 0
|
||||
) {
|
||||
url = "/login/return" + redirect;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function openDialog(name, value) {
|
||||
return ensureDialog(name)
|
||||
.then(function () {
|
||||
@@ -171,15 +137,6 @@
|
||||
return opener(value);
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (name === "login") {
|
||||
try {
|
||||
var params = new URLSearchParams(global.location.search || "");
|
||||
// 已在登录入口仍失败时避免死循环跳转
|
||||
if (params.get("auth") !== "login") {
|
||||
global.location.href = loginFallbackURL();
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
@@ -196,12 +153,6 @@
|
||||
function triggerName(target) {
|
||||
if (!target || !target.closest) return "";
|
||||
if (target.closest("[data-download-app-open]")) return "download";
|
||||
if (target.closest("[data-register-dialog-open], a[href=\"#register\"], a[href=\"/register/\"]")) {
|
||||
return "register";
|
||||
}
|
||||
if (target.closest("[data-login-dialog-open], a[href=\"#login\"], a[href=\"/login/\"]")) {
|
||||
return "login";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -222,22 +173,23 @@
|
||||
openDialog(name).catch(function () {});
|
||||
}, true);
|
||||
|
||||
function openFromLocation() {
|
||||
var params = new URLSearchParams(global.location.search || "");
|
||||
var auth = params.get("auth");
|
||||
if (auth === "login" || auth === "register") {
|
||||
openDialog(auth).catch(function () {});
|
||||
return;
|
||||
}
|
||||
if (global.location.hash === "#login") openDialog("login").catch(function () {});
|
||||
if (global.location.hash === "#register") openDialog("register").catch(function () {});
|
||||
function appDownloadURL() {
|
||||
var el = document.querySelector("[data-app-download-url]");
|
||||
var url = el ? (el.getAttribute("data-app-download-url") || "").trim() : "";
|
||||
return url || "/download-app/";
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", openFromLocation, { once: true });
|
||||
} else {
|
||||
openFromLocation();
|
||||
// 付费内容统一入口:移动端直接跳下载地址,PC 弹下载二维码。
|
||||
function openDownloadApp() {
|
||||
if (isMobileViewport()) {
|
||||
global.location.href = appDownloadURL();
|
||||
return Promise.resolve();
|
||||
}
|
||||
return openDialog("download").catch(function () {
|
||||
global.location.href = appDownloadURL();
|
||||
});
|
||||
}
|
||||
|
||||
global.ensureDialog = ensureDialog;
|
||||
global.openDownloadApp = openDownloadApp;
|
||||
})(window);
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/**
|
||||
* 修改密码:POST /api/auth/profile { oldPassword, newPassword }
|
||||
*/
|
||||
(function () {
|
||||
var form = document.querySelector("[data-edit-password-form]");
|
||||
if (!form) return;
|
||||
|
||||
var currentInput = form.querySelector("[data-edit-password-current]");
|
||||
var newInput = form.querySelector("[data-edit-password-new]");
|
||||
var confirmInput = form.querySelector("[data-edit-password-confirm]");
|
||||
var submitBtn = form.querySelector("[data-edit-password-submit]");
|
||||
|
||||
document.querySelectorAll("[data-password-toggle]").forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
var id = btn.getAttribute("data-password-toggle");
|
||||
var input = id ? document.getElementById(id) : null;
|
||||
if (!input) return;
|
||||
var show = input.type === "password";
|
||||
input.type = show ? "text" : "password";
|
||||
btn.textContent = show ? "隐藏" : "显示";
|
||||
});
|
||||
});
|
||||
|
||||
function getField(name) {
|
||||
return form.querySelector('[data-edit-password-field="' + name + '"]');
|
||||
}
|
||||
|
||||
function setFieldError(name, message) {
|
||||
var field = getField(name);
|
||||
if (!field) return;
|
||||
var error = field.querySelector("[data-edit-password-error]");
|
||||
field.classList.toggle("is-error", !!message);
|
||||
if (error) {
|
||||
if (message) {
|
||||
error.hidden = false;
|
||||
error.textContent = message;
|
||||
} else {
|
||||
error.hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearErrors() {
|
||||
setFieldError("current", "");
|
||||
setFieldError("new", "");
|
||||
setFieldError("confirm", "");
|
||||
}
|
||||
|
||||
function isValidLength(value) {
|
||||
return value.length >= 4 && value.length <= 16;
|
||||
}
|
||||
|
||||
function toast(message, type) {
|
||||
if (window.AuthAPI) AuthAPI.toast(message, type);
|
||||
else if (typeof showToast === "function") showToast(message, type);
|
||||
}
|
||||
|
||||
function validate() {
|
||||
clearErrors();
|
||||
var current = (currentInput && currentInput.value) || "";
|
||||
var next = (newInput && newInput.value) || "";
|
||||
var confirm = (confirmInput && confirmInput.value) || "";
|
||||
var ok = true;
|
||||
|
||||
if (!current) {
|
||||
setFieldError("current", "请输入当前密码");
|
||||
ok = false;
|
||||
} else if (!isValidLength(current)) {
|
||||
setFieldError("current", "当前密码需为 4–16 个字符");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
setFieldError("new", "请输入新密码");
|
||||
ok = false;
|
||||
} else if (!isValidLength(next)) {
|
||||
setFieldError("new", "新密码需为 4–16 个字符");
|
||||
ok = false;
|
||||
} else if (next === current) {
|
||||
setFieldError("new", "新密码不能与当前密码相同");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!confirm) {
|
||||
setFieldError("confirm", "请再次输入新密码");
|
||||
ok = false;
|
||||
} else if (confirm !== next) {
|
||||
setFieldError("confirm", "两次输入的新密码不一致");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok) return null;
|
||||
return { oldPassword: current, newPassword: next };
|
||||
}
|
||||
|
||||
[currentInput, newInput, confirmInput].forEach(function (input) {
|
||||
if (!input) return;
|
||||
input.addEventListener("input", function () {
|
||||
var field = input.closest("[data-edit-password-field]");
|
||||
if (!field) return;
|
||||
var name = field.getAttribute("data-edit-password-field");
|
||||
setFieldError(name, "");
|
||||
});
|
||||
});
|
||||
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
var payload = validate();
|
||||
if (!payload) return;
|
||||
if (!window.AuthAPI || !window.HttpRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (submitBtn) submitBtn.disabled = true;
|
||||
|
||||
AuthAPI.updateProfile(payload)
|
||||
.then(function () {
|
||||
toast("密码修改成功", "success");
|
||||
setTimeout(function () {
|
||||
window.location.href = "/setting/";
|
||||
}, 400);
|
||||
})
|
||||
.catch(function (err) {
|
||||
var tip = (err && err.message) || "修改失败,请稍后重试";
|
||||
if (/旧|当前|原密码|old/i.test(tip)) {
|
||||
setFieldError("current", tip);
|
||||
return;
|
||||
}
|
||||
if (/新密码|new/i.test(tip)) {
|
||||
setFieldError("new", tip);
|
||||
return;
|
||||
}
|
||||
toast(tip, "error");
|
||||
})
|
||||
.finally(function () {
|
||||
if (submitBtn) submitBtn.disabled = false;
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,68 +0,0 @@
|
||||
(function () {
|
||||
var form = document.querySelector("[data-edit-profile-form]");
|
||||
var nickInput = document.querySelector("[data-edit-profile-nickname]");
|
||||
var bioInput = document.querySelector("[data-edit-profile-bio]");
|
||||
var submitBtn = document.querySelector("[data-edit-profile-submit]");
|
||||
if (!form) return;
|
||||
|
||||
var originalNick = nickInput ? String(nickInput.value || "").trim() : "";
|
||||
var originalBio = bioInput ? String(bioInput.value || "").trim() : "";
|
||||
|
||||
function toast(message, type) {
|
||||
if (window.AuthAPI) AuthAPI.toast(message, type);
|
||||
else if (typeof showToast === "function") showToast(message, type);
|
||||
}
|
||||
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
if (!window.AuthAPI || !window.HttpRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nick = nickInput ? String(nickInput.value || "").trim() : "";
|
||||
var bio = bioInput ? String(bioInput.value || "").trim() : "";
|
||||
if (!nick) {
|
||||
toast("请输入昵称", "error");
|
||||
return;
|
||||
}
|
||||
if (nick.length > 20) {
|
||||
toast("昵称最多 20 个字符", "error");
|
||||
return;
|
||||
}
|
||||
if (bio.length > 120) {
|
||||
toast("个人简介最多 120 个字符", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
var nickChanged = nick !== originalNick;
|
||||
var bioChanged = bio !== originalBio;
|
||||
if (!nickChanged && !bioChanged) {
|
||||
toast("暂无修改", "info");
|
||||
return;
|
||||
}
|
||||
|
||||
var payload = {};
|
||||
if (nickChanged) payload.nickName = nick;
|
||||
if (bioChanged) payload.introduction = bio;
|
||||
if (!payload.nickName && !payload.introduction) {
|
||||
toast(bioChanged ? "请填写个人简介或修改昵称" : "暂无修改", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (submitBtn) submitBtn.disabled = true;
|
||||
|
||||
AuthAPI.updateProfile(payload)
|
||||
.then(function () {
|
||||
toast("保存成功", "success");
|
||||
setTimeout(function () {
|
||||
window.location.href = "/setting/";
|
||||
}, 400);
|
||||
})
|
||||
.catch(function (err) {
|
||||
toast((err && err.message) || "保存失败", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
if (submitBtn) submitBtn.disabled = false;
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -495,23 +495,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function requireLogin() {
|
||||
if (window.CookieUtil && CookieUtil.isLoggedIn()) return true;
|
||||
toast("请先登录后再提交反馈", "error");
|
||||
var loginURL = "/login/return/feedback/";
|
||||
if (typeof window.openLoginDialog === "function") {
|
||||
var opened = window.openLoginDialog();
|
||||
if (opened && typeof opened.then === "function") {
|
||||
opened.catch(function () {
|
||||
window.location.href = loginURL;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
window.location.href = loginURL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function uploadAllImages() {
|
||||
if (!selectedFiles.length) return Promise.resolve([]);
|
||||
if (!window.AuthAPI || typeof AuthAPI.uploadImage !== "function") {
|
||||
@@ -548,7 +531,6 @@
|
||||
return;
|
||||
}
|
||||
if (submitBtn && submitBtn.classList.contains("is-loading")) return;
|
||||
if (!requireLogin()) return;
|
||||
|
||||
var activeTypeChip = document.querySelector("[data-feedback-type-option].is-active");
|
||||
var type = parseInt(
|
||||
@@ -647,18 +629,6 @@
|
||||
clearFiles();
|
||||
})
|
||||
.catch(function (err) {
|
||||
if (err && err.code === 401) {
|
||||
toast("请先登录后再提交反馈", "error");
|
||||
if (typeof window.openLoginDialog === "function") {
|
||||
var opened = window.openLoginDialog();
|
||||
if (opened && typeof opened.then === "function") {
|
||||
opened.catch(function () {
|
||||
window.location.href = "/login/return/feedback/";
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
toast((err && err.message) || "提交失败", "error");
|
||||
})
|
||||
.finally(function () {
|
||||
|
||||
@@ -93,142 +93,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
var DEFAULT_AVATAR = "/static/images/avatar.png";
|
||||
var PLACEHOLDER = "/static/images/placeholder.png?v=2";
|
||||
|
||||
function usableAvatar(url) {
|
||||
var u = String(url || "").trim();
|
||||
if (!u) return "";
|
||||
if (/^https?:\/\//i.test(u) || u.indexOf("/static/") === 0) return u;
|
||||
return "";
|
||||
}
|
||||
|
||||
function setAvatarImg(img, url) {
|
||||
if (!img) return;
|
||||
var src = usableAvatar(url);
|
||||
img.removeAttribute("data-decrypted");
|
||||
if (src && typeof shouldDecryptImage === "function" && shouldDecryptImage(src)) {
|
||||
img.classList.add("lazy");
|
||||
img.src = PLACEHOLDER;
|
||||
img.setAttribute("data-src", src);
|
||||
} else {
|
||||
img.classList.remove("lazy");
|
||||
img.removeAttribute("data-src");
|
||||
img.src = src || DEFAULT_AVATAR;
|
||||
}
|
||||
}
|
||||
|
||||
function refreshDecrypt(root) {
|
||||
if (typeof window.initLazyImages === "function") {
|
||||
window.initLazyImages(root || document);
|
||||
}
|
||||
}
|
||||
|
||||
/** 用 cookie 登录态同步 header-account */
|
||||
function parseExpireTime(value) {
|
||||
if (value == null || value === "") return NaN;
|
||||
if (typeof value === "number") {
|
||||
return value < 1e12 ? value * 1000 : value;
|
||||
}
|
||||
var text = String(value).trim();
|
||||
if (!text) return NaN;
|
||||
if (/^\d+$/.test(text)) {
|
||||
var num = Number(text);
|
||||
return num < 1e12 ? num * 1000 : num;
|
||||
}
|
||||
return Date.parse(text);
|
||||
}
|
||||
|
||||
// vipType≠0 且 currentVipExpire 未过期(与 91ly 一致)
|
||||
function isVipActive(user) {
|
||||
if (!user) return false;
|
||||
var type = Number(user.vipType);
|
||||
if (!type || type === 0) return false;
|
||||
var expireMs = parseExpireTime(user.currentVipExpire);
|
||||
if (!isFinite(expireMs) || expireMs <= 0) return false;
|
||||
return expireMs > Date.now();
|
||||
}
|
||||
|
||||
function syncHeaderVip(session) {
|
||||
var active = isVipActive(session);
|
||||
document.querySelectorAll("[data-header-vip], [data-header-vip-sep]").forEach(function (el) {
|
||||
el.hidden = !active;
|
||||
});
|
||||
}
|
||||
|
||||
function syncHeaderAccount() {
|
||||
var account = document.querySelector("[data-header-account]");
|
||||
if (!account || !window.CookieUtil) return;
|
||||
|
||||
// 有 token 即展示个人信息(含游客)
|
||||
var loggedIn = CookieUtil.isLoggedIn();
|
||||
var session = loggedIn ? CookieUtil.getAuthSession() : null;
|
||||
var nameEl = account.querySelector("[data-header-username]");
|
||||
|
||||
if (loggedIn && session) {
|
||||
var displayName =
|
||||
session.nickName || session.accountNo || session.email || "用户";
|
||||
var avatar = usableAvatar(session.avatar);
|
||||
|
||||
account.href = "/user-center/";
|
||||
account.removeAttribute("data-login-dialog-open");
|
||||
|
||||
var guest = account.querySelector("[data-header-guest-avatar]");
|
||||
if (guest) guest.remove();
|
||||
|
||||
var photo = account.querySelector("[data-header-avatar]");
|
||||
if (!photo) {
|
||||
photo = document.createElement("img");
|
||||
photo.className = "account-avatar-photo";
|
||||
photo.setAttribute("data-header-avatar", "");
|
||||
photo.alt = displayName + "的头像";
|
||||
account.insertBefore(photo, nameEl || account.firstChild);
|
||||
}
|
||||
setAvatarImg(photo, avatar);
|
||||
|
||||
if (nameEl) {
|
||||
nameEl.textContent = displayName;
|
||||
nameEl.classList.add("account-label--logged");
|
||||
}
|
||||
|
||||
refreshDecrypt(account.parentElement || document);
|
||||
syncHeaderVip(session);
|
||||
return;
|
||||
}
|
||||
|
||||
account.href = "#login";
|
||||
account.setAttribute("data-login-dialog-open", "");
|
||||
|
||||
var loggedPhoto = account.querySelector("[data-header-avatar]");
|
||||
if (loggedPhoto) loggedPhoto.remove();
|
||||
if (!account.querySelector("[data-header-guest-avatar]")) {
|
||||
var wrap = document.createElement("div");
|
||||
wrap.className = "account-avatar";
|
||||
wrap.setAttribute("data-header-guest-avatar", "");
|
||||
wrap.innerHTML =
|
||||
'<img class="account-avatar-ring" src="' +
|
||||
DEFAULT_AVATAR +
|
||||
'" alt="未登录用户头像" />' +
|
||||
'<div class="account-avatar-body"></div>' +
|
||||
'<div class="account-avatar-head"></div>';
|
||||
account.insertBefore(wrap, nameEl || account.firstChild);
|
||||
}
|
||||
if (nameEl) {
|
||||
nameEl.textContent = "未登录";
|
||||
nameEl.classList.remove("account-label--logged");
|
||||
}
|
||||
|
||||
syncHeaderVip(null);
|
||||
}
|
||||
|
||||
syncHeaderAccount();
|
||||
window.syncHeaderAccount = syncHeaderAccount;
|
||||
document.addEventListener("auth:login", function () {
|
||||
syncHeaderAccount();
|
||||
});
|
||||
document.addEventListener("auth:logout", function () {
|
||||
syncHeaderAccount();
|
||||
});
|
||||
|
||||
document.addEventListener(
|
||||
"click",
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
* 观看历史页:清空记录
|
||||
*/
|
||||
(function () {
|
||||
var clearBtns = document.querySelectorAll("[data-history-clear]");
|
||||
var confirmMask = document.querySelector("[data-history-confirm]");
|
||||
var confirmCancelBtns = document.querySelectorAll(
|
||||
"[data-history-confirm-cancel]"
|
||||
);
|
||||
var confirmOkBtn = document.querySelector("[data-history-confirm-ok]");
|
||||
var clearing = false;
|
||||
|
||||
function toast(message, type) {
|
||||
if (window.AuthAPI && typeof window.AuthAPI.toast === "function") {
|
||||
window.AuthAPI.toast(message, type);
|
||||
}
|
||||
}
|
||||
|
||||
function openClearConfirm() {
|
||||
if (!confirmMask) return;
|
||||
confirmMask.hidden = false;
|
||||
confirmMask.removeAttribute("hidden");
|
||||
confirmMask.classList.add("is-open");
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
function closeClearConfirm() {
|
||||
if (!confirmMask) return;
|
||||
confirmMask.classList.remove("is-open");
|
||||
confirmMask.hidden = true;
|
||||
confirmMask.setAttribute("hidden", "");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
function clearHistory() {
|
||||
if (clearing) return;
|
||||
if (!window.HttpRequest) {
|
||||
toast("清空失败,请稍后重试", "error");
|
||||
return;
|
||||
}
|
||||
clearing = true;
|
||||
window.HttpRequest.post("/api/playlet/history/clear")
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200) {
|
||||
throw new Error((res && (res.tip || res.msg)) || "清空失败");
|
||||
}
|
||||
window.location.reload();
|
||||
})
|
||||
.catch(function (err) {
|
||||
clearing = false;
|
||||
toast((err && err.message) || "清空失败,请稍后重试", "error");
|
||||
});
|
||||
}
|
||||
|
||||
clearBtns.forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
openClearConfirm();
|
||||
});
|
||||
});
|
||||
|
||||
confirmCancelBtns.forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
closeClearConfirm();
|
||||
});
|
||||
});
|
||||
|
||||
if (confirmMask) {
|
||||
confirmMask.addEventListener("click", function (e) {
|
||||
if (e.target === confirmMask) closeClearConfirm();
|
||||
});
|
||||
}
|
||||
|
||||
if (confirmOkBtn) {
|
||||
confirmOkBtn.addEventListener("click", function () {
|
||||
closeClearConfirm();
|
||||
clearHistory();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (e.key !== "Escape") return;
|
||||
if (!confirmMask || !confirmMask.classList.contains("is-open")) return;
|
||||
closeClearConfirm();
|
||||
});
|
||||
})();
|
||||
@@ -1,236 +0,0 @@
|
||||
(function () {
|
||||
var mask = document.getElementById("loginDialog");
|
||||
if (!mask) return;
|
||||
|
||||
var form = mask.querySelector("[data-login-dialog-form]");
|
||||
var accountInput = mask.querySelector("[data-login-account]");
|
||||
var passwordInput = mask.querySelector("[data-login-password]");
|
||||
var submitBtn = mask.querySelector("[data-login-submit]");
|
||||
var defaultSubmitText = (submitBtn && submitBtn.textContent) || "登录";
|
||||
|
||||
function setSubmitting(loading) {
|
||||
if (!submitBtn) return;
|
||||
submitBtn.disabled = !!loading;
|
||||
submitBtn.classList.toggle("is-loading", !!loading);
|
||||
submitBtn.setAttribute("aria-busy", loading ? "true" : "false");
|
||||
submitBtn.textContent = loading ? "登录中..." : defaultSubmitText;
|
||||
}
|
||||
|
||||
function getField(name) {
|
||||
return mask.querySelector('[data-login-field="' + name + '"]');
|
||||
}
|
||||
|
||||
function setFieldError(name, message) {
|
||||
var field = getField(name);
|
||||
if (!field) return;
|
||||
var control = field.querySelector("[data-login-control]");
|
||||
var error = field.querySelector("[data-login-error]");
|
||||
if (control) control.classList.add("is-error");
|
||||
if (error) {
|
||||
error.textContent = message;
|
||||
error.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
function clearFieldError(name) {
|
||||
var field = getField(name);
|
||||
if (!field) return;
|
||||
var control = field.querySelector("[data-login-control]");
|
||||
var error = field.querySelector("[data-login-error]");
|
||||
if (control) control.classList.remove("is-error");
|
||||
if (error) error.hidden = true;
|
||||
}
|
||||
|
||||
function clearAllErrors() {
|
||||
clearFieldError("account");
|
||||
clearFieldError("password");
|
||||
}
|
||||
|
||||
function isValidLength(value) {
|
||||
return value.length >= 4 && value.length <= 16;
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
var account = (accountInput && accountInput.value.trim()) || "";
|
||||
var password = (passwordInput && passwordInput.value) || "";
|
||||
var valid = true;
|
||||
|
||||
clearAllErrors();
|
||||
|
||||
if (!account) {
|
||||
setFieldError("account", "账号格式不正确,请输入有效账号");
|
||||
valid = false;
|
||||
} else if (!window.AuthAPI || !AuthAPI.isValidLoginAccount(account)) {
|
||||
setFieldError("account", "账号格式不正确,请输入有效账号");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
setFieldError("password", "密码错误,请检查后重新输入");
|
||||
valid = false;
|
||||
} else if (!isValidLength(password)) {
|
||||
setFieldError("password", "密码错误,请检查后重新输入");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) return null;
|
||||
return { account: account, password: password };
|
||||
}
|
||||
|
||||
function mapServerError(err) {
|
||||
var tip = (err && err.message) || "登录失败,请稍后重试";
|
||||
if (/密码|password/i.test(tip)) {
|
||||
setFieldError("password", tip);
|
||||
return;
|
||||
}
|
||||
if (/账号|账户|用户|邮箱|account|email|不存在|错误/i.test(tip)) {
|
||||
setFieldError("account", tip);
|
||||
return;
|
||||
}
|
||||
if (window.AuthAPI) AuthAPI.toast(tip, "error");
|
||||
else if (typeof showToast === "function") showToast(tip, "error");
|
||||
}
|
||||
|
||||
function openDialog(event) {
|
||||
if (event) event.preventDefault();
|
||||
if (typeof window.closeRegisterDialog === "function") {
|
||||
window.closeRegisterDialog();
|
||||
}
|
||||
clearAllErrors();
|
||||
mask.classList.add("is-open");
|
||||
document.body.style.overflow = "hidden";
|
||||
return true;
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
mask.classList.remove("is-open");
|
||||
clearAllErrors();
|
||||
if (!document.getElementById("registerDialog") || !document.getElementById("registerDialog").classList.contains("is-open")) {
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
}
|
||||
|
||||
function setLoginErrors(errors) {
|
||||
clearAllErrors();
|
||||
if (!errors) return;
|
||||
if (errors.account) setFieldError("account", errors.account);
|
||||
if (errors.password) setFieldError("password", errors.password);
|
||||
}
|
||||
|
||||
if (form) {
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
if (submitBtn && submitBtn.classList.contains("is-loading")) return;
|
||||
var payload = validateForm();
|
||||
if (!payload) return;
|
||||
if (!window.AuthAPI || !window.HttpRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
|
||||
AuthAPI.login(payload)
|
||||
.then(function () {
|
||||
AuthAPI.toast("登录成功", "success");
|
||||
closeDialog();
|
||||
setTimeout(function () {
|
||||
goAfterAuth();
|
||||
}, 400);
|
||||
})
|
||||
.catch(function (err) {
|
||||
setSubmitting(false);
|
||||
mapServerError(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isSafeRedirect(path) {
|
||||
return typeof path === "string" && path.charAt(0) === "/" && path.charAt(1) !== "/";
|
||||
}
|
||||
|
||||
function goAfterAuth() {
|
||||
var bodyRedirect = document.body && document.body.getAttribute("data-auth-redirect");
|
||||
if (isSafeRedirect(bodyRedirect)) {
|
||||
window.location.href = bodyRedirect;
|
||||
return;
|
||||
}
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var redirect = params.get("redirect");
|
||||
if (isSafeRedirect(redirect)) {
|
||||
window.location.href = redirect;
|
||||
return;
|
||||
}
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function consumeAuthQuery(kind) {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (params.get("auth") !== kind) return false;
|
||||
params.delete("auth");
|
||||
var qs = params.toString();
|
||||
var next = window.location.pathname + (qs ? "?" + qs : "") + window.location.hash;
|
||||
window.history.replaceState(null, "", next);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (accountInput) {
|
||||
accountInput.addEventListener("input", function () {
|
||||
clearFieldError("account");
|
||||
});
|
||||
}
|
||||
|
||||
if (passwordInput) {
|
||||
passwordInput.addEventListener("input", function () {
|
||||
clearFieldError("password");
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
var openEl = event.target.closest("[data-login-dialog-open]");
|
||||
if (openEl) {
|
||||
openDialog(event);
|
||||
return;
|
||||
}
|
||||
|
||||
var loginLink = event.target.closest('a[href="/login/"], a[href="#login"]');
|
||||
if (loginLink) {
|
||||
openDialog(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-login-dialog-close]")) {
|
||||
closeDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-login-dialog-eye]")) {
|
||||
var btn = event.target.closest("[data-login-dialog-eye]");
|
||||
var input = document.getElementById("loginDialogPassword");
|
||||
var img = btn.querySelector("img");
|
||||
if (!input || !img) return;
|
||||
var show = input.type === "password";
|
||||
input.type = show ? "text" : "password";
|
||||
img.src = show ? "/static/images/eye_open.svg" : "/static/images/eye_close.svg";
|
||||
btn.setAttribute("aria-label", show ? "隐藏密码" : "显示密码");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target === mask) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && mask.classList.contains("is-open")) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
window.openLoginDialog = openDialog;
|
||||
window.closeLoginDialog = closeDialog;
|
||||
window.setLoginDialogErrors = setLoginErrors;
|
||||
|
||||
if ((document.body && document.body.getAttribute("data-auth-mode") === "login") || consumeAuthQuery("login")) {
|
||||
openDialog();
|
||||
}
|
||||
})();
|
||||
+43
-255
@@ -437,46 +437,6 @@
|
||||
applyPlaySpeed(dp, currentPlaySpeed());
|
||||
}
|
||||
|
||||
// 复用同一 meta 对象:bindVideoEvents 只绑一次,切集时就地更新字段即可生效。
|
||||
var playTrackerMeta = {
|
||||
media_id: "",
|
||||
video_id: "",
|
||||
video_title: "",
|
||||
video_type_id: "playlet",
|
||||
video_type_name: "短剧",
|
||||
video_content_type: "playlet",
|
||||
recommend_trace_id: "",
|
||||
video_tag_key: "",
|
||||
video_tag_name: "",
|
||||
};
|
||||
var playViewTracked = false;
|
||||
|
||||
function syncPlayTrackerMeta() {
|
||||
var root = document.querySelector("[data-play-page]");
|
||||
var ds = (root && root.dataset) || {};
|
||||
var player = document.querySelector("[data-play-player]");
|
||||
var pds = (player && player.dataset) || {};
|
||||
var episode = ds.playEpisode || "";
|
||||
playTrackerMeta.media_id = ds.playletId || "";
|
||||
playTrackerMeta.video_id = ds.playletId || "";
|
||||
playTrackerMeta.video_title = ds.playTitle || "";
|
||||
playTrackerMeta.video_type_id = "playlet";
|
||||
playTrackerMeta.video_type_name = ds.playTag || "短剧";
|
||||
playTrackerMeta.video_content_type = "playlet";
|
||||
playTrackerMeta.recommend_trace_id = "";
|
||||
playTrackerMeta.video_tag_key = pds.chapterId || "";
|
||||
playTrackerMeta.video_tag_name = episode ? "第" + episode + "集" : "";
|
||||
return playTrackerMeta;
|
||||
}
|
||||
|
||||
function bindPlayTracker(dp) {
|
||||
if (!dp || !window.tracker || typeof window.tracker.bindVideoEvents !== "function") {
|
||||
return;
|
||||
}
|
||||
syncPlayTrackerMeta();
|
||||
window.tracker.bindVideoEvents(dp, playTrackerMeta);
|
||||
}
|
||||
|
||||
function nextEpisodeElement() {
|
||||
var active = document.querySelector(".play-ep-grid .play-ep--active");
|
||||
if (!active) return null;
|
||||
@@ -607,7 +567,6 @@
|
||||
var player = container.closest(".play-player");
|
||||
bindPlayerPoster(playDp, player);
|
||||
bindH265Fallback(playDp, source);
|
||||
bindPlayTracker(playDp);
|
||||
setupDesktopPlayerControls(playDp);
|
||||
return playDp;
|
||||
} catch (e) {
|
||||
@@ -681,7 +640,7 @@
|
||||
if (id > 0 && next.getAttribute("data-play-switch") != null) {
|
||||
return id;
|
||||
}
|
||||
// 付费/VIP 锁定集:返回 id 以便弹窗
|
||||
// 付费锁定集:返回 id 以便引导下载 APP
|
||||
if (id > 0) return id;
|
||||
}
|
||||
next = next.nextElementSibling;
|
||||
@@ -721,14 +680,17 @@
|
||||
if (dp && typeof dp.on === "function") {
|
||||
dp.on("timeupdate", updateNextCountdown);
|
||||
dp.on("ended", function () {
|
||||
markCurrentEpisodeWatched();
|
||||
var chapterId = findNextChapterId();
|
||||
setNextCountdownVisible(false, 3);
|
||||
if (chapterId) switchToChapter(chapterId, { autoplay: true });
|
||||
if (!chapterId) return;
|
||||
if (isLockedEpisode(chapterId)) {
|
||||
openDownloadApp();
|
||||
return;
|
||||
}
|
||||
switchToChapter(chapterId, { autoplay: true });
|
||||
});
|
||||
dp.on("play", function () {
|
||||
applyPlaySpeed(dp, currentPlaySpeed());
|
||||
markCurrentEpisodeWatched();
|
||||
updateNextCountdown();
|
||||
});
|
||||
dp.on("seeked", updateNextCountdown);
|
||||
@@ -770,26 +732,6 @@
|
||||
(playPage && playPage.getAttribute("data-play-episode")) || 0
|
||||
);
|
||||
var switchingChapter = false;
|
||||
var lastWatchReportKey = "";
|
||||
|
||||
function reportChapterWatch() {
|
||||
if (!currentChapterId || !window.HttpRequest) return;
|
||||
if (window.CookieUtil && !window.CookieUtil.isLoggedIn()) return;
|
||||
var key = String(playletId || 0) + ":" + currentChapterId;
|
||||
if (key === lastWatchReportKey) return;
|
||||
lastWatchReportKey = key;
|
||||
var body = { chapterId: currentChapterId };
|
||||
if (playletId) body.playletId = playletId;
|
||||
window.HttpRequest.post("/api/playlet/chapter/watch/report", body).catch(
|
||||
function () {
|
||||
/* 静默失败:未登录/网络错误不打断播放 */
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function markCurrentEpisodeWatched() {
|
||||
reportChapterWatch();
|
||||
}
|
||||
|
||||
function padEpisode(n) {
|
||||
var num = Number(n) || 0;
|
||||
@@ -802,92 +744,42 @@
|
||||
return "/play/" + encodeURIComponent(key) + "/" + chapterId + "/";
|
||||
}
|
||||
|
||||
function resolvePayGate(chapter, el) {
|
||||
if (chapter) {
|
||||
if (chapter.canWatch || chapter.isUnlocked) return 0;
|
||||
if (chapter.needUnlock) return 1;
|
||||
if (chapter.needVip) return 2;
|
||||
var payType = Number(chapter.payType || 0);
|
||||
if (payType === 1 || payType === 2) return payType;
|
||||
return 0;
|
||||
}
|
||||
if (el) {
|
||||
if (el.getAttribute("data-can-watch") === "1") return 0;
|
||||
if (el.getAttribute("data-need-unlock") === "1") return 1;
|
||||
if (el.getAttribute("data-need-vip") === "1") return 2;
|
||||
if (el.getAttribute("data-coin-dialog-open") != null) return 1;
|
||||
if (el.getAttribute("data-vip-dialog-open") != null) return 2;
|
||||
return Number(el.getAttribute("data-pay-type") || 0);
|
||||
}
|
||||
return 0;
|
||||
function isChapterLocked(chapter) {
|
||||
if (!chapter) return false;
|
||||
if (chapter.canWatch || chapter.isUnlocked) return false;
|
||||
if (chapter.needUnlock || chapter.needVip) return true;
|
||||
// 与服务端 PlayletChapterData.AllowWatch 保持一致:仅免费集可直接播放。
|
||||
return Number(chapter.payType || 0) !== 0;
|
||||
}
|
||||
|
||||
function resolveUnlockCost(chapter, el) {
|
||||
if (chapter) {
|
||||
if (Number(chapter.costCoins) > 0) return Number(chapter.costCoins);
|
||||
if (Number(chapter.singleCoins) > 0) return Number(chapter.singleCoins);
|
||||
}
|
||||
if (el) return Number(el.getAttribute("data-single-coins") || 0);
|
||||
return 0;
|
||||
function isLockedEpisode(chapterId) {
|
||||
chapterId = Number(chapterId) || 0;
|
||||
if (!chapterId) return false;
|
||||
return !!document.querySelector(
|
||||
'[data-play-locked][data-chapter-id="' + chapterId + '"]'
|
||||
);
|
||||
}
|
||||
|
||||
function openPayForChapter(el, chapter) {
|
||||
var payGate = resolvePayGate(chapter, el);
|
||||
if (payGate === 1) {
|
||||
if (typeof window.openCoinDialog === "function") {
|
||||
var coinTrigger = document.createElement("button");
|
||||
coinTrigger.setAttribute("data-coin-dialog-open", "");
|
||||
coinTrigger.setAttribute(
|
||||
"data-chapter-id",
|
||||
String((chapter && chapter.id) || (el && el.getAttribute("data-chapter-id")) || "")
|
||||
);
|
||||
coinTrigger.setAttribute(
|
||||
"data-playlet-id",
|
||||
String(
|
||||
(chapter && chapter.playletId) ||
|
||||
playletId ||
|
||||
(el && el.getAttribute("data-playlet-id")) ||
|
||||
""
|
||||
)
|
||||
);
|
||||
coinTrigger.setAttribute(
|
||||
"data-single-coins",
|
||||
String(resolveUnlockCost(chapter, el))
|
||||
);
|
||||
coinTrigger.style.display = "none";
|
||||
document.body.appendChild(coinTrigger);
|
||||
coinTrigger.click();
|
||||
coinTrigger.remove();
|
||||
}
|
||||
return true;
|
||||
// 付费剧集统一引导下载 APP(移动端跳转下载地址,PC 弹出下载二维码)。
|
||||
function openDownloadApp() {
|
||||
if (typeof window.openDownloadApp === "function") {
|
||||
return window.openDownloadApp();
|
||||
}
|
||||
if (payGate === 2) {
|
||||
var vipBtn = document.querySelector("[data-vip-dialog-open]");
|
||||
if (vipBtn) vipBtn.click();
|
||||
else if (typeof window.openVipDialog === "function") {
|
||||
window.openVipDialog();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function updateEpisodeActive(chapterId) {
|
||||
document.querySelectorAll(".play-ep").forEach(function (el) {
|
||||
var isActive = Number(el.getAttribute("data-chapter-id") || 0) === chapterId;
|
||||
el.classList.toggle("play-ep--active", isActive);
|
||||
var coin = el.querySelector(".play-ep-coin");
|
||||
var lock = el.querySelector(".play-ep-lock");
|
||||
if (coin) coin.style.display = isActive ? "none" : "";
|
||||
if (lock) lock.style.display = isActive ? "none" : "";
|
||||
});
|
||||
document.querySelectorAll(".play-ep-sheet-item").forEach(function (el) {
|
||||
var isActive =
|
||||
Number(el.getAttribute("data-chapter-id") || 0) === chapterId;
|
||||
el.classList.toggle("play-ep-sheet-item--active", isActive);
|
||||
var coin = el.querySelector(".play-ep-sheet-coin");
|
||||
var lock = el.querySelector(".play-ep-sheet-lock");
|
||||
if (coin) coin.hidden = isActive;
|
||||
if (lock) lock.hidden = isActive;
|
||||
});
|
||||
syncDesktopNextControl();
|
||||
@@ -897,7 +789,6 @@
|
||||
var ep = Number(chapter.currentEpisode) || 0;
|
||||
currentEpisode = ep;
|
||||
currentChapterId = Number(chapter.id) || currentChapterId;
|
||||
lastWatchReportKey = "";
|
||||
if (playPage) {
|
||||
playPage.setAttribute("data-play-episode", String(ep));
|
||||
}
|
||||
@@ -922,10 +813,6 @@
|
||||
player.setAttribute("data-chapter-id", String(chapter.id || ""));
|
||||
player.setAttribute("data-playlet-id", String(playletId || chapter.playletId || ""));
|
||||
player.setAttribute("data-pay-type", String(chapter.payType || 0));
|
||||
player.setAttribute(
|
||||
"data-single-coins",
|
||||
String(resolveUnlockCost(chapter, null))
|
||||
);
|
||||
player.setAttribute(
|
||||
"data-can-watch",
|
||||
chapter.canWatch || chapter.isUnlocked ? "1" : "0"
|
||||
@@ -935,10 +822,6 @@
|
||||
chapter.needUnlock ? "1" : "0"
|
||||
);
|
||||
player.setAttribute("data-need-vip", chapter.needVip ? "1" : "0");
|
||||
player.setAttribute(
|
||||
"data-is-unlocked",
|
||||
chapter.isUnlocked ? "1" : "0"
|
||||
);
|
||||
}
|
||||
|
||||
var commentCount = document.querySelector("[data-play-comment-count]");
|
||||
@@ -976,6 +859,8 @@
|
||||
container.setAttribute("data-url", videoUrl || "");
|
||||
if (playCover) container.setAttribute("data-cover", playCover);
|
||||
player.insertBefore(container, player.firstChild);
|
||||
var lockedCta = player.querySelector("[data-play-locked-cta]");
|
||||
if (lockedCta) lockedCta.remove();
|
||||
var playBtn = player.querySelector("[data-play-poster-play]");
|
||||
if (!playBtn) {
|
||||
playBtn = document.createElement("button");
|
||||
@@ -1016,24 +901,18 @@
|
||||
throw new Error((res && (res.tip || res.msg)) || "加载失败");
|
||||
}
|
||||
var chapter = res.data;
|
||||
var payGate = resolvePayGate(chapter, null);
|
||||
if (payGate !== 0 && !options.skipPayCheck) {
|
||||
openPayForChapter(null, chapter);
|
||||
if (isChapterLocked(chapter)) {
|
||||
openDownloadApp();
|
||||
return;
|
||||
}
|
||||
var videoUrl = resolvePlayUrl(chapter.videoUrl || "");
|
||||
if (!videoUrl) {
|
||||
if (payGate !== 0) {
|
||||
openPayForChapter(null, chapter);
|
||||
return;
|
||||
}
|
||||
throw new Error("暂无播放地址");
|
||||
}
|
||||
|
||||
currentChapterId = Number(chapter.id) || chapterId;
|
||||
updateEpisodeActive(currentChapterId);
|
||||
updateChapterMeta(chapter);
|
||||
markCurrentEpisodeWatched();
|
||||
|
||||
if (!options.skipHistory) {
|
||||
var href = buildPlayHref(currentChapterId);
|
||||
@@ -1049,8 +928,6 @@
|
||||
|
||||
if (playDp && typeof playDp.switchVideo === "function") {
|
||||
switchPlayerVideo(playDp, videoOption);
|
||||
syncPlayTrackerMeta();
|
||||
bindPlayTracker(playDp);
|
||||
} else {
|
||||
ensurePlayerContainer(chapter.videoUrl || "");
|
||||
playDp = initDPlayer();
|
||||
@@ -1078,69 +955,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function markEpisodeUnlocked(chapterId) {
|
||||
chapterId = Number(chapterId) || 0;
|
||||
if (!chapterId) return;
|
||||
var href = buildPlayHref(chapterId);
|
||||
document
|
||||
.querySelectorAll(
|
||||
'.play-ep[data-chapter-id="' +
|
||||
chapterId +
|
||||
'"], .play-ep-sheet-item[data-chapter-id="' +
|
||||
chapterId +
|
||||
'"]'
|
||||
)
|
||||
.forEach(function (el) {
|
||||
el.removeAttribute("data-coin-dialog-open");
|
||||
el.removeAttribute("data-vip-dialog-open");
|
||||
el.removeAttribute("data-single-coins");
|
||||
el.setAttribute("data-play-switch", "");
|
||||
el.setAttribute("href", href || "javascript:;");
|
||||
var coin = el.querySelector(
|
||||
".play-ep-coin, .play-ep-sheet-coin"
|
||||
);
|
||||
if (coin) coin.remove();
|
||||
var lock = el.querySelector(
|
||||
".play-ep-lock, .play-ep-sheet-lock"
|
||||
);
|
||||
if (lock) lock.remove();
|
||||
});
|
||||
|
||||
var player = document.querySelector("[data-play-player]");
|
||||
if (
|
||||
player &&
|
||||
Number(player.getAttribute("data-chapter-id") || 0) === chapterId
|
||||
) {
|
||||
player.setAttribute("data-pay-type", "0");
|
||||
player.setAttribute("data-can-watch", "1");
|
||||
player.setAttribute("data-need-unlock", "0");
|
||||
player.setAttribute("data-need-vip", "0");
|
||||
player.setAttribute("data-is-unlocked", "1");
|
||||
player.removeAttribute("data-single-coins");
|
||||
}
|
||||
}
|
||||
|
||||
function playAfterChapterUnlock(detail) {
|
||||
detail = detail || {};
|
||||
var chapterId = Number(detail.chapterId) || 0;
|
||||
if (!chapterId) return;
|
||||
if (detail.playletId) {
|
||||
playletId = Number(detail.playletId) || playletId;
|
||||
if (playPage) {
|
||||
playPage.setAttribute("data-playlet-id", String(playletId));
|
||||
}
|
||||
}
|
||||
markEpisodeUnlocked(chapterId);
|
||||
switchToChapter(chapterId, {
|
||||
force: true,
|
||||
skipPayCheck: true,
|
||||
autoplay: true,
|
||||
replace: true,
|
||||
});
|
||||
}
|
||||
|
||||
window.playAfterChapterUnlock = playAfterChapterUnlock;
|
||||
|
||||
function bindEpisodeSwitch() {
|
||||
document.addEventListener("click", function (e) {
|
||||
var el =
|
||||
@@ -1154,12 +968,27 @@
|
||||
switchToChapter(chapterId, { autoplay: true });
|
||||
});
|
||||
|
||||
document.addEventListener("click", function (e) {
|
||||
var el =
|
||||
e.target && e.target.closest
|
||||
? e.target.closest("[data-play-locked], [data-play-download-app]")
|
||||
: null;
|
||||
if (!el) return;
|
||||
e.preventDefault();
|
||||
openDownloadApp();
|
||||
});
|
||||
|
||||
window.addEventListener("popstate", function (e) {
|
||||
var match = String(window.location.pathname || "").match(/\/play\/[^/]+\/(\d+)\/?$/);
|
||||
var chapterId =
|
||||
(e.state && e.state.chapterId) ||
|
||||
Number((match && match[1]) || 0);
|
||||
if (!chapterId) return;
|
||||
if (isLockedEpisode(chapterId)) {
|
||||
// 回退到付费集:交给服务端渲染下载 APP 引导,避免自动跳转。
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
switchToChapter(chapterId, {
|
||||
autoplay: true,
|
||||
skipHistory: true,
|
||||
@@ -1176,14 +1005,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function maybeOpenPayDialog() {
|
||||
var player = document.querySelector("[data-play-player]");
|
||||
if (!player) return;
|
||||
var hasVideo = !!player.querySelector(".dplayer-video[data-url]");
|
||||
if (hasVideo) return;
|
||||
openPayForChapter(player, null);
|
||||
}
|
||||
|
||||
function bindSidebarRanges() {
|
||||
var ranges = document.querySelectorAll("[data-play-ep-ranges] .play-ep-range");
|
||||
var episodes = document.querySelectorAll("[data-play-ep-grid] .play-ep");
|
||||
@@ -1349,44 +1170,11 @@
|
||||
window.alert(message);
|
||||
}
|
||||
|
||||
function trackPlayView() {
|
||||
if (playViewTracked || !window.tracker || typeof window.tracker.videoEvent !== "function") return;
|
||||
var meta = syncPlayTrackerMeta();
|
||||
if (!meta.video_id) return;
|
||||
playViewTracked = true;
|
||||
window.tracker.videoEvent({
|
||||
media_id: meta.media_id,
|
||||
video_id: meta.video_id,
|
||||
video_title: meta.video_title,
|
||||
video_type_id: meta.video_type_id,
|
||||
video_type_name: meta.video_type_name,
|
||||
video_content_type: meta.video_content_type,
|
||||
recommend_trace_id: meta.recommend_trace_id,
|
||||
video_tag_key: meta.video_tag_key,
|
||||
video_tag_name: meta.video_tag_name,
|
||||
video_behavior_key: "video_view",
|
||||
video_behavior_name: "视频展示",
|
||||
});
|
||||
}
|
||||
|
||||
function bindTrackingWhenReady(dp) {
|
||||
function activateTracking() {
|
||||
bindPlayTracker(dp || playDp);
|
||||
trackPlayView();
|
||||
}
|
||||
activateTracking();
|
||||
if (!window.__trackerReady) {
|
||||
window.addEventListener("tracker:ready", activateTracking, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
function boot() {
|
||||
var dp = initDPlayer();
|
||||
bindH5PlayerUI(dp);
|
||||
bindSidebarRanges();
|
||||
bindEpisodeSwitch();
|
||||
maybeOpenPayDialog();
|
||||
bindTrackingWhenReady(dp);
|
||||
if (typeof window.initLazyImages === "function") {
|
||||
window.initLazyImages(document.querySelector(".play-page") || document);
|
||||
}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
(function () {
|
||||
var mask = document.getElementById("registerDialog");
|
||||
if (!mask) return;
|
||||
|
||||
var form = mask.querySelector("[data-register-dialog-form]");
|
||||
var accountInput = mask.querySelector("[data-register-account]");
|
||||
var passwordInput = mask.querySelector("[data-register-password]");
|
||||
var confirmInput = mask.querySelector("[data-register-password-confirm]");
|
||||
var submitBtn = mask.querySelector("[data-register-submit]");
|
||||
var defaultSubmitText = (submitBtn && submitBtn.textContent) || "立即注册";
|
||||
|
||||
function setSubmitting(loading) {
|
||||
if (!submitBtn) return;
|
||||
submitBtn.disabled = !!loading;
|
||||
submitBtn.classList.toggle("is-loading", !!loading);
|
||||
submitBtn.setAttribute("aria-busy", loading ? "true" : "false");
|
||||
submitBtn.textContent = loading ? "注册中..." : defaultSubmitText;
|
||||
}
|
||||
|
||||
function getField(name) {
|
||||
return mask.querySelector('[data-register-field="' + name + '"]');
|
||||
}
|
||||
|
||||
function setFieldError(name, message) {
|
||||
var field = getField(name);
|
||||
if (!field) return;
|
||||
var control = field.querySelector("[data-register-control]");
|
||||
var error = field.querySelector("[data-register-error]");
|
||||
if (control) control.classList.add("is-error");
|
||||
if (error) {
|
||||
error.textContent = message;
|
||||
error.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
function clearFieldError(name) {
|
||||
var field = getField(name);
|
||||
if (!field) return;
|
||||
var control = field.querySelector("[data-register-control]");
|
||||
var error = field.querySelector("[data-register-error]");
|
||||
if (control) control.classList.remove("is-error");
|
||||
if (error) error.hidden = true;
|
||||
}
|
||||
|
||||
function clearAllErrors() {
|
||||
clearFieldError("account");
|
||||
clearFieldError("password");
|
||||
clearFieldError("password_confirm");
|
||||
}
|
||||
|
||||
function isValidLength(value) {
|
||||
return value.length >= 4 && value.length <= 16;
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
var account = (accountInput && accountInput.value.trim()) || "";
|
||||
var password = (passwordInput && passwordInput.value) || "";
|
||||
var confirm = (confirmInput && confirmInput.value) || "";
|
||||
var valid = true;
|
||||
|
||||
clearAllErrors();
|
||||
|
||||
if (!account) {
|
||||
setFieldError("account", "请输入账号");
|
||||
valid = false;
|
||||
} else if (!isValidLength(account)) {
|
||||
setFieldError("account", "账号需为 4–16 个字符");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
setFieldError("password", "请输入密码");
|
||||
valid = false;
|
||||
} else if (!isValidLength(password)) {
|
||||
setFieldError("password", "密码需为 4–16 个字符");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!confirm) {
|
||||
setFieldError("password_confirm", "请再次输入密码");
|
||||
valid = false;
|
||||
} else if (confirm !== password) {
|
||||
setFieldError("password_confirm", "两次输入的密码不一致");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) return null;
|
||||
return { accountNo: account, password: password };
|
||||
}
|
||||
|
||||
function mapServerError(err) {
|
||||
var tip = (err && err.message) || "注册失败,请稍后重试";
|
||||
var code = err && err.code;
|
||||
if (code === 5005 || /已存在|重复|占用/.test(tip)) {
|
||||
setFieldError("account", tip);
|
||||
return;
|
||||
}
|
||||
if (/密码|password/i.test(tip)) {
|
||||
setFieldError("password", tip);
|
||||
return;
|
||||
}
|
||||
if (window.AuthAPI) AuthAPI.toast(tip, "error");
|
||||
else if (typeof showToast === "function") showToast(tip, "error");
|
||||
}
|
||||
|
||||
function openDialog(event) {
|
||||
if (event) event.preventDefault();
|
||||
if (typeof window.closeLoginDialog === "function") {
|
||||
window.closeLoginDialog();
|
||||
}
|
||||
clearAllErrors();
|
||||
mask.classList.add("is-open");
|
||||
document.body.style.overflow = "hidden";
|
||||
return true;
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
mask.classList.remove("is-open");
|
||||
clearAllErrors();
|
||||
if (!document.getElementById("loginDialog") || !document.getElementById("loginDialog").classList.contains("is-open")) {
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (form) {
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
if (submitBtn && submitBtn.classList.contains("is-loading")) return;
|
||||
var payload = validateForm();
|
||||
if (!payload) return;
|
||||
if (!window.AuthAPI || !window.HttpRequest) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
|
||||
AuthAPI.register(payload)
|
||||
.then(function () {
|
||||
AuthAPI.toast("注册成功", "success");
|
||||
closeDialog();
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 400);
|
||||
})
|
||||
.catch(function (err) {
|
||||
setSubmitting(false);
|
||||
mapServerError(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function consumeAuthQuery(kind) {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
if (params.get("auth") !== kind) return false;
|
||||
params.delete("auth");
|
||||
var qs = params.toString();
|
||||
var next = window.location.pathname + (qs ? "?" + qs : "") + window.location.hash;
|
||||
window.history.replaceState(null, "", next);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (accountInput) {
|
||||
accountInput.addEventListener("input", function () {
|
||||
clearFieldError("account");
|
||||
});
|
||||
}
|
||||
if (passwordInput) {
|
||||
passwordInput.addEventListener("input", function () {
|
||||
clearFieldError("password");
|
||||
});
|
||||
}
|
||||
if (confirmInput) {
|
||||
confirmInput.addEventListener("input", function () {
|
||||
clearFieldError("password_confirm");
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
var openEl = event.target.closest("[data-register-dialog-open]");
|
||||
if (openEl) {
|
||||
openDialog(event);
|
||||
return;
|
||||
}
|
||||
|
||||
var registerLink = event.target.closest('a[href="/register/"], a[href="#register"]');
|
||||
if (registerLink) {
|
||||
openDialog(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-register-dialog-close]")) {
|
||||
closeDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target === mask) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && mask.classList.contains("is-open")) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
window.openRegisterDialog = openDialog;
|
||||
window.closeRegisterDialog = closeDialog;
|
||||
|
||||
if ((document.body && document.body.getAttribute("data-auth-mode") === "register") || consumeAuthQuery("register")) {
|
||||
openDialog();
|
||||
}
|
||||
})();
|
||||
@@ -1,34 +0,0 @@
|
||||
(function () {
|
||||
document.querySelectorAll(".setting-switch").forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
var on = btn.classList.toggle("setting-switch--on");
|
||||
btn.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
});
|
||||
});
|
||||
|
||||
var logoutBtn = document.querySelector("[data-auth-logout]");
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener("click", function () {
|
||||
function done() {
|
||||
if (window.AuthAPI && typeof AuthAPI.markGuestLogout === "function") {
|
||||
AuthAPI.markGuestLogout();
|
||||
}
|
||||
if (window.CookieUtil && typeof CookieUtil.clearAuth === "function") {
|
||||
CookieUtil.clearAuth();
|
||||
}
|
||||
try {
|
||||
document.dispatchEvent(new CustomEvent("auth:logout"));
|
||||
} catch (e) {}
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
if (window.HttpRequest) {
|
||||
HttpRequest.post("/api/auth/logout", {})
|
||||
.catch(function () {})
|
||||
.then(done);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
@@ -1,161 +0,0 @@
|
||||
(function () {
|
||||
function parseExpireTime(value) {
|
||||
if (value == null || value === "") return NaN;
|
||||
if (typeof value === "number") {
|
||||
return value < 1e12 ? value * 1000 : value;
|
||||
}
|
||||
var text = String(value).trim();
|
||||
if (!text) return NaN;
|
||||
if (/^\d+$/.test(text)) {
|
||||
var num = Number(text);
|
||||
return num < 1e12 ? num * 1000 : num;
|
||||
}
|
||||
return Date.parse(text);
|
||||
}
|
||||
|
||||
function isVipActive(user) {
|
||||
if (!user) return false;
|
||||
var type = Number(user.vipType);
|
||||
if (!type || type === 0) return false;
|
||||
var expireMs = parseExpireTime(user.currentVipExpire);
|
||||
if (!isFinite(expireMs) || expireMs <= 0) return false;
|
||||
return expireMs > Date.now();
|
||||
}
|
||||
|
||||
function vipTypeLabel(vipType) {
|
||||
var type = Number(vipType);
|
||||
if (type === 1) return "月卡会员";
|
||||
if (type === 2) return "年卡会员";
|
||||
return "普通会员";
|
||||
}
|
||||
|
||||
function vipDisplayLabel(user) {
|
||||
var name = user && String(user.showCardName || "").trim();
|
||||
if (name) return name;
|
||||
return vipTypeLabel(user && user.vipType);
|
||||
}
|
||||
|
||||
function vipExpireText(raw) {
|
||||
var ms = parseExpireTime(raw);
|
||||
if (!isFinite(ms) || ms <= 0) return "";
|
||||
var d = new Date(ms);
|
||||
var y = d.getFullYear();
|
||||
var m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
var day = String(d.getDate()).padStart(2, "0");
|
||||
return "有效期至 " + y + "/" + m + "/" + day;
|
||||
}
|
||||
|
||||
function formatRecharge(value) {
|
||||
var n = Number(value);
|
||||
if (!isFinite(n) || n < 0) n = 0;
|
||||
return String(Math.floor(n)).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
function syncUserCenterRecharge(value) {
|
||||
var text = formatRecharge(
|
||||
value != null
|
||||
? value
|
||||
: CookieUtil.getAuthSession() && CookieUtil.getAuthSession().recharge,
|
||||
);
|
||||
var pc = document.querySelector("[data-user-center-recharge]");
|
||||
if (pc) pc.textContent = text;
|
||||
var hint = document.querySelector("[data-user-center-recharge-hint]");
|
||||
if (hint) hint.textContent = text + "金币";
|
||||
}
|
||||
|
||||
function syncUserCenterID(value) {
|
||||
var id = String(value == null ? "" : value).trim();
|
||||
if (!id) return;
|
||||
document.querySelectorAll("[data-user-center-id]").forEach(function (el) {
|
||||
el.textContent = el.getAttribute("data-id-layout") === "pc"
|
||||
? "ID:" + id
|
||||
: "ID " + id;
|
||||
});
|
||||
}
|
||||
|
||||
function refreshUserCenterWallet() {
|
||||
if (!window.CookieUtil || !CookieUtil.isLoggedIn()) return;
|
||||
syncUserCenterRecharge();
|
||||
if (!window.HttpRequest) return;
|
||||
HttpRequest.get("/api/auth/getInfo")
|
||||
.then(function (res) {
|
||||
if (!res || res.code !== 200 || !res.data) return;
|
||||
if (CookieUtil.setAuthSession) CookieUtil.setAuthSession(res.data);
|
||||
syncUserCenterID(res.data.userId);
|
||||
syncUserCenterRecharge(res.data.recharge);
|
||||
syncUserCenterVip();
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
function syncUserCenterVip() {
|
||||
if (!window.CookieUtil || !CookieUtil.isLoggedIn()) return;
|
||||
var session = CookieUtil.getAuthSession();
|
||||
var active = isVipActive(session);
|
||||
var label = active ? vipDisplayLabel(session) : "";
|
||||
var expire = active
|
||||
? vipExpireText(session && session.currentVipExpire)
|
||||
: "";
|
||||
|
||||
var pc = document.querySelector("[data-user-center-vip]");
|
||||
if (pc) {
|
||||
pc.classList.toggle("user-center-vip-card--active", active);
|
||||
var status = pc.querySelector("[data-vip-status]");
|
||||
var expireEl = pc.querySelector("[data-vip-expire]");
|
||||
var action = pc.querySelector("[data-vip-action]");
|
||||
if (status) {
|
||||
status.textContent = active ? "尊享 VIP 会员" : "尚未开通会员";
|
||||
}
|
||||
if (expireEl) {
|
||||
if (active && expire) {
|
||||
expireEl.hidden = false;
|
||||
expireEl.style.display = "";
|
||||
expireEl.textContent = expire;
|
||||
} else {
|
||||
expireEl.hidden = true;
|
||||
expireEl.style.display = "none";
|
||||
expireEl.textContent = "";
|
||||
}
|
||||
}
|
||||
if (action) {
|
||||
if (active) {
|
||||
action.hidden = true;
|
||||
action.style.display = "none";
|
||||
} else {
|
||||
action.hidden = false;
|
||||
action.style.display = "";
|
||||
action.textContent = "立即开通 →";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mobile = document.querySelector("[data-user-center-mobile-vip]");
|
||||
if (mobile) {
|
||||
mobile.classList.toggle("user-center-mobile-vip--active", active);
|
||||
var title = mobile.querySelector("[data-mobile-vip-title]");
|
||||
var desc = mobile.querySelector("[data-mobile-vip-desc]");
|
||||
var btn = mobile.querySelector("[data-mobile-vip-btn]");
|
||||
if (title) title.textContent = active ? label : "开通黄果短剧会员";
|
||||
if (desc) {
|
||||
desc.textContent = active
|
||||
? expire || "全场免费看 · 热门短剧抢先看"
|
||||
: "全场免费看 · 热门短剧抢先看";
|
||||
}
|
||||
if (btn) {
|
||||
btn.hidden = false;
|
||||
btn.style.display = "";
|
||||
if (active) {
|
||||
btn.textContent = "续费会员";
|
||||
} else {
|
||||
btn.textContent = "立即开通";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncUserCenterVip();
|
||||
refreshUserCenterWallet();
|
||||
window.syncUserCenterVip = syncUserCenterVip;
|
||||
window.syncUserCenterID = syncUserCenterID;
|
||||
window.syncUserCenterRecharge = syncUserCenterRecharge;
|
||||
})();
|
||||
@@ -1,52 +0,0 @@
|
||||
(function () {
|
||||
var mask = document.getElementById("vipDialog");
|
||||
if (!mask) return;
|
||||
|
||||
function openDialog(event) {
|
||||
if (event) event.preventDefault();
|
||||
mask.classList.add("is-open");
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
mask.classList.remove("is-open");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
function isVipLockedEpisode(target) {
|
||||
var episode = target.closest(
|
||||
".detail-episode, .play-ep, .play-ep-sheet-item, .detail-h5-ep-item"
|
||||
);
|
||||
if (!episode) return false;
|
||||
// 金币解锁走 coinDialog,不在此打开 VIP 弹窗
|
||||
if (episode.hasAttribute("data-coin-dialog-open")) return false;
|
||||
return !!episode.querySelector(
|
||||
".detail-episode-lock[src*='vip'], .detail-episode-vip, .play-ep-lock[src*='vip'], .play-ep-sheet-lock[src*='vip'], .detail-h5-ep-lock[src*='vip']"
|
||||
);
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (event) {
|
||||
if (event.target.closest("[data-vip-dialog-open]") || isVipLockedEpisode(event.target)) {
|
||||
openDialog(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.closest("[data-vip-dialog-close]")) {
|
||||
closeDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target === mask) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Escape" && mask.classList.contains("is-open")) {
|
||||
closeDialog();
|
||||
}
|
||||
});
|
||||
|
||||
window.openVipDialog = openDialog;
|
||||
window.closeVipDialog = closeDialog;
|
||||
})();
|
||||
Reference in New Issue
Block a user