diff --git a/admin.html b/admin.html index ae298e3..ec53b57 100644 --- a/admin.html +++ b/admin.html @@ -23,6 +23,8 @@ .row-4 { display: grid; grid-template-columns: 1fr 1fr 1.6fr 100px; gap: 14px; } .sort-arrow { font-size: 10px; } .count-hint { color: var(--muted); font-size: 12px; margin-bottom: 10px; } + .channel-tabs { display: flex; gap: 8px; margin-bottom: 14px; } + .channel-tabs button.active { background: var(--accent); color: #fff; border-color: var(--accent); } @@ -37,6 +39,11 @@
+
+ + +
+
@@ -46,6 +53,13 @@
+ + +
+
@@ -70,6 +84,7 @@ 名称(英) Prompt 视频地址 + 直播间 溯源(人物×衣服×参考视频) 时长 点赞 @@ -103,6 +118,13 @@ let danceRefs = []; let editingId = null; let sortKey = "createdAt"; let sortDir = -1; +// 视频直播间(live.html) / 跳舞直播间(dance.html) 是两条独立的产品线, +// 素材各自的排播池互不共享(architecture.md 2.1),所以后台也分开管理。 +let activeChannel = "video"; + +function inChannel(c) { + return activeChannel === "dance" ? c.channel === "dance" : c.channel !== "dance"; +} function escapeHtml(s) { const div = document.createElement("div"); @@ -142,7 +164,7 @@ function traceability(c) { function filteredSorted() { const q = document.getElementById("searchInput").value.trim().toLowerCase(); const source = document.getElementById("sourceFilter").value; - let rows = library.slice(); + let rows = library.filter(inChannel); if (q) rows = rows.filter((c) => c.prompt.toLowerCase().includes(q) || (c.promptEn || "").toLowerCase().includes(q) || (c.fullPrompt || "").toLowerCase().includes(q) || c.id.toLowerCase().includes(q)); if (source) rows = rows.filter((c) => c.source === source); rows.sort((a, b) => { @@ -160,7 +182,10 @@ function videoHref(c) { function render() { const rows = filteredSorted(); - document.getElementById("countHint").textContent = `共 ${library.length} 条,当前筛选 ${rows.length} 条`; + const channelTotal = library.filter(inChannel).length; + document.getElementById("countHint").textContent = `本直播间共 ${channelTotal} 条,当前筛选 ${rows.length} 条`; + document.getElementById("tabVideo").classList.toggle("active", activeChannel === "video"); + document.getElementById("tabDance").classList.toggle("active", activeChannel === "dance"); document.querySelectorAll("th[data-sort]").forEach((th) => { th.innerHTML = th.textContent.replace(/ ?[▲▼]$/, "") + (th.dataset.sort === sortKey ? ` ${sortDir === 1 ? "▲" : "▼"}` : ""); }); @@ -175,6 +200,12 @@ function render() { + + + ${escapeHtml(traceability(c))} ${c.duration ?? "-"}s ${c.likes || 0} @@ -193,6 +224,7 @@ function render() { ${escapeHtml(c.promptEn || "")} ${escapeHtml((c.fullPrompt || "").slice(0, 80))}${(c.fullPrompt || "").length > 80 ? "…" : ""} ${videoHref(c)} + ${c.channel === "dance" ? "跳舞直播间" : "视频直播间"} ${escapeHtml(traceability(c))} ${c.duration ?? "-"}s ${c.likes || 0} @@ -248,6 +280,17 @@ document.querySelectorAll("th[data-sort]").forEach((th) => { document.getElementById("searchInput").addEventListener("input", render); document.getElementById("sourceFilter").addEventListener("change", render); +document.getElementById("tabVideo").addEventListener("click", () => { + activeChannel = "video"; + document.getElementById("newChannel").value = "video"; + render(); +}); +document.getElementById("tabDance").addEventListener("click", () => { + activeChannel = "dance"; + document.getElementById("newChannel").value = "dance"; + render(); +}); + document.getElementById("addBtn").addEventListener("click", async () => { const errorBox = document.getElementById("addError"); errorBox.hidden = true; @@ -256,6 +299,7 @@ document.getElementById("addBtn").addEventListener("click", async () => { const videoUrl = document.getElementById("newVideoUrl").value.trim(); const fullPrompt = document.getElementById("newFullPrompt").value.trim(); const duration = Number(document.getElementById("newDuration").value) || null; + const channel = document.getElementById("newChannel").value; if (!prompt || !videoUrl) { errorBox.hidden = false; errorBox.textContent = "名称和视频地址必填"; @@ -264,7 +308,7 @@ document.getElementById("addBtn").addEventListener("click", async () => { const res = await fetch("/api/admin/library", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ prompt, promptEn, videoUrl, fullPrompt, duration }), + body: JSON.stringify({ prompt, promptEn, videoUrl, fullPrompt, duration, channel }), }); if (res.ok) { document.getElementById("newPrompt").value = "";