// 播放页评论:只读列表 + 「查看更多评论」追加翻页 (function () { var commentsRoot = document.querySelector("[data-play-comments]"); if (!commentsRoot) return; var listEl = document.querySelector("[data-comment-list]"); var totalEl = document.querySelector("[data-comment-total-label]"); var moreBtn = document.querySelector("[data-comment-more]"); var loadingMore = false; var PAGE_SIZE = 4; function toast(message, type) { if (typeof window.showToast === "function") { window.showToast(message, type); return; } } function toInt(v, fallback) { var n = parseInt(v, 10); return isNaN(n) ? fallback || 0 : n; } function escapeHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function getPageSize() { return Math.max( 1, toInt(commentsRoot.getAttribute("data-comment-size"), PAGE_SIZE) ); } function getPage() { return Math.max( 1, toInt(commentsRoot.getAttribute("data-comment-page"), 1) ); } function getLoaded() { if (!listEl) return 0; return listEl.querySelectorAll(".play-comment:not(.play-comment--empty)").length; } function setPagerState(page, loaded, total) { if (page != null) commentsRoot.setAttribute("data-comment-page", String(page)); if (loaded != null) commentsRoot.setAttribute("data-comment-loaded", String(loaded)); if (total != null) commentsRoot.setAttribute("data-comment-total", String(total)); syncMoreButton(total != null ? total : toInt(commentsRoot.getAttribute("data-comment-total"), 0)); } function syncMoreButton(total) { if (!moreBtn) return; var loaded = getLoaded(); var hasMore = total > loaded; if (hasMore) { moreBtn.hidden = false; moreBtn.removeAttribute("hidden"); } else { moreBtn.hidden = true; moreBtn.setAttribute("hidden", ""); } } function formatTime(raw) { var s = String(raw || "").trim(); if (!s) return "刚刚"; var d = new Date(s); if (isNaN(d.getTime())) return s; return ( d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate() + " " + String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0") ); } function renderCommentItem(item) { item = item || {}; var avatar = String(item.userAvatar || "").trim(); var name = escapeHtml(item.userName || "匿名用户"); var text = escapeHtml(item.text || ""); var time = escapeHtml(formatTime(item.createdAt)); var like = toInt(item.countLike, 0); var avatarHtml = avatar ? '' : ''; var children = Array.isArray(item.children) ? item.children : []; var replies = children .map(function (child) { var cName = escapeHtml(child.userName || "用户"); var replyTo = child.replyUserName ? " 回复 " + escapeHtml(child.replyUserName) : ""; return ( '
' + cName + replyTo + ":" + escapeHtml(child.text || "") + "
" ); }) .join(""); var commentId = escapeHtml(item.id || ""); return ( '
  • ' + avatarHtml + '
    ' + '
    ' + '' + name + "" + '' + time + "" + "
    " + '

    ' + text + "

    " + replies + '
    ' + '' + '' + "" + escapeHtml(like) + "" + "" + "
  • " ); } function getLoadedIds() { var ids = Object.create(null); if (!listEl) return ids; listEl.querySelectorAll(".play-comment[data-comment-id]").forEach(function (el) { var id = String(el.getAttribute("data-comment-id") || "").trim(); if (id) ids[id] = true; }); return ids; } function updateTotal(n) { if (!totalEl) return; totalEl.textContent = n > 0 ? n + " 条" : "暂无评论"; } // 下一页追加到现有列表底部,不替换已展示评论。 function appendList(list, totalCount) { if (!listEl) return; list = Array.isArray(list) ? list : []; var total = typeof totalCount === "number" ? totalCount : toInt(commentsRoot.getAttribute("data-comment-total"), 0); if (typeof totalCount === "number") { updateTotal(totalCount); } if (!list.length) { setPagerState(getPage(), getLoaded(), total); return; } var empty = listEl.querySelector(".play-comment--empty"); if (empty) empty.remove(); var existing = getLoadedIds(); var fresh = list.filter(function (item) { var id = String((item && item.id) || "").trim(); return id && !existing[id]; }); if (!fresh.length) { setPagerState(getPage(), getLoaded(), total); return; } var wrap = document.createElement("ul"); wrap.innerHTML = fresh.map(renderCommentItem).join(""); var nodes = []; while (wrap.firstChild) { nodes.push(wrap.firstChild); listEl.appendChild(wrap.firstChild); } if (typeof window.initLazyImages === "function") { nodes.forEach(function (node) { if (node && node.nodeType === 1) window.initLazyImages(node); }); window.initLazyImages(listEl); } setPagerState(getPage(), getLoaded(), total); } function fetchCommentPage(pageNum) { if (!window.HttpRequest || typeof window.HttpRequest.get !== "function") { return Promise.reject(new Error("评论服务未就绪")); } var objectId = toInt(commentsRoot.getAttribute("data-object-id"), 0); var objectType = toInt(commentsRoot.getAttribute("data-object-type"), 10); if (objectId <= 0) return Promise.reject(new Error("缺少评论对象")); var pageSize = getPageSize(); return window.HttpRequest.get("/api/comment/list", { params: { objectId: objectId, objectType: objectType, pageNum: pageNum, pageSize: pageSize, sortOrder: 1, }, }).then(function (res) { if (!res || Number(res.code) !== 200 || !res.data) { throw new Error((res && (res.tip || res.msg)) || "加载失败"); } return res.data; }); } function loadMoreComments() { if (loadingMore || !moreBtn) return; var nextPage = getPage() + 1; loadingMore = true; moreBtn.disabled = true; fetchCommentPage(nextPage) .then(function (data) { var list = data.list || []; var total = toInt(data.totalCount, 0); commentsRoot.setAttribute("data-comment-page", String(nextPage)); // 只追加,绝不 renderList 整表替换 appendList(list, total); }) .catch(function (err) { toast((err && err.message) || "加载失败,请稍后重试", "error"); }) .finally(function () { loadingMore = false; if (moreBtn) moreBtn.disabled = false; }); } if (moreBtn) { moreBtn.addEventListener("click", function (event) { event.preventDefault(); loadMoreComments(); }); } })();