Commit 38245bd442863a55fcb4f06b05e4c864545828e9

Authored by yibo
1 parent af536bdd

Replace preview modal with inline video player per row

The modal (previous commit) meant an extra click and a popup just to
see the clip. Swap it for a native <video controls preload="none">
directly in the 预览 column — preload="none" keeps the 361-row table
from firing off thumbnails for every row on load, and clicking the
player's own play button starts it right there, no dialog involved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DUiYs6UjxDMkfvnjtsKFo
Showing 1 changed file with 3 additions and 20 deletions
admin.html
@@ -25,9 +25,7 @@ @@ -25,9 +25,7 @@
25 .count-hint { color: var(--muted); font-size: 12px; margin-bottom: 10px; } 25 .count-hint { color: var(--muted); font-size: 12px; margin-bottom: 10px; }
26 .channel-tabs { display: flex; gap: 8px; margin-bottom: 14px; } 26 .channel-tabs { display: flex; gap: 8px; margin-bottom: 14px; }
27 .channel-tabs button.active { background: var(--accent); color: #fff; border-color: var(--accent); } 27 .channel-tabs button.active { background: var(--accent); color: #fff; border-color: var(--accent); }
28 - #previewDialog { padding: 0; border: none; border-radius: var(--radius); background: #000; }  
29 - #previewDialog::backdrop { background: rgba(0,0,0,.6); }  
30 - #previewDialog video { display: block; max-width: 80vw; max-height: 80vh; } 28 + td.preview video { display: block; width: 180px; max-height: 200px; background: #000; border-radius: 4px; }
31 </style> 29 </style>
32 </head> 30 </head>
33 <body> 31 <body>
@@ -103,10 +101,6 @@ @@ -103,10 +101,6 @@
103 </div> 101 </div>
104 </main> 102 </main>
105 103
106 -<dialog id="previewDialog">  
107 - <video id="previewVideo" controls autoplay></video>  
108 -</dialog>  
109 -  
110 <script> 104 <script>
111 // Redirect to login whenever any /api/admin/* call comes back 401 (T6 auth 105 // Redirect to login whenever any /api/admin/* call comes back 401 (T6 auth
112 // gate) — a single interceptor instead of touching every fetch call site. 106 // gate) — a single interceptor instead of touching every fetch call site.
@@ -208,7 +202,7 @@ function render() { @@ -208,7 +202,7 @@ function render() {
208 <td class="name"><input data-field="promptEn" value="${escapeHtml(c.promptEn || "")}" /></td> 202 <td class="name"><input data-field="promptEn" value="${escapeHtml(c.promptEn || "")}" /></td>
209 <td class="prompt"><textarea data-field="fullPrompt">${escapeHtml(c.fullPrompt || "")}</textarea></td> 203 <td class="prompt"><textarea data-field="fullPrompt">${escapeHtml(c.fullPrompt || "")}</textarea></td>
210 <td><input data-field="videoUrl" value="${escapeHtml(c.videoUrl || "")}" placeholder="留空=保持原有播放源" /></td> 204 <td><input data-field="videoUrl" value="${escapeHtml(c.videoUrl || "")}" placeholder="留空=保持原有播放源" /></td>
211 - <td><button class="secondary" data-preview="${c.id}">▶ 预览</button></td> 205 + <td class="preview"><video controls preload="none" src="${videoHref(c)}"></video></td>
212 <td> 206 <td>
213 <select data-field="channel"> 207 <select data-field="channel">
214 <option value="video" ${c.channel === "dance" ? "" : "selected"}>视频直播间</option> 208 <option value="video" ${c.channel === "dance" ? "" : "selected"}>视频直播间</option>
@@ -233,7 +227,7 @@ function render() { @@ -233,7 +227,7 @@ function render() {
233 <td class="name">${escapeHtml(c.promptEn || "")}</td> 227 <td class="name">${escapeHtml(c.promptEn || "")}</td>
234 <td class="prompt" title="${escapeHtml(c.fullPrompt || "")}">${escapeHtml((c.fullPrompt || "").slice(0, 80))}${(c.fullPrompt || "").length > 80 ? "…" : ""}</td> 228 <td class="prompt" title="${escapeHtml(c.fullPrompt || "")}">${escapeHtml((c.fullPrompt || "").slice(0, 80))}${(c.fullPrompt || "").length > 80 ? "…" : ""}</td>
235 <td><a class="video-link" href="${videoHref(c)}" target="_blank">${videoHref(c)}</a></td> 229 <td><a class="video-link" href="${videoHref(c)}" target="_blank">${videoHref(c)}</a></td>
236 - <td><button class="secondary" data-preview="${c.id}">▶ 预览</button></td> 230 + <td class="preview"><video controls preload="none" src="${videoHref(c)}"></video></td>
237 <td>${c.channel === "dance" ? "跳舞直播间" : "视频直播间"}</td> 231 <td>${c.channel === "dance" ? "跳舞直播间" : "视频直播间"}</td>
238 <td>${escapeHtml(traceability(c))}</td> 232 <td>${escapeHtml(traceability(c))}</td>
239 <td>${c.duration ?? "-"}s</td> 233 <td>${c.duration ?? "-"}s</td>
@@ -267,12 +261,6 @@ function render() { @@ -267,12 +261,6 @@ function render() {
267 } 261 }
268 }) 262 })
269 ); 263 );
270 - tbody.querySelectorAll("[data-preview]").forEach((b) =>  
271 - b.addEventListener("click", () => {  
272 - previewVideo.src = videoHref(rows.find((c) => c.id === b.dataset.preview));  
273 - previewDialog.showModal();  
274 - })  
275 - );  
276 tbody.querySelectorAll("[data-del]").forEach((b) => 264 tbody.querySelectorAll("[data-del]").forEach((b) =>
277 b.addEventListener("click", async () => { 265 b.addEventListener("click", async () => {
278 if (!confirm("确认删除这条片段?(如果来自 H3 Console 会同步从那边删除)")) return; 266 if (!confirm("确认删除这条片段?(如果来自 H3 Console 会同步从那边删除)")) return;
@@ -293,11 +281,6 @@ document.querySelectorAll(&quot;th[data-sort]&quot;).forEach((th) =&gt; { @@ -293,11 +281,6 @@ document.querySelectorAll(&quot;th[data-sort]&quot;).forEach((th) =&gt; {
293 }); 281 });
294 }); 282 });
295 283
296 -const previewDialog = document.getElementById("previewDialog");  
297 -const previewVideo = document.getElementById("previewVideo");  
298 -previewDialog.addEventListener("click", (e) => { if (e.target === previewDialog) previewDialog.close(); });  
299 -previewDialog.addEventListener("close", () => { previewVideo.pause(); previewVideo.src = ""; });  
300 -  
301 document.getElementById("searchInput").addEventListener("input", render); 284 document.getElementById("searchInput").addEventListener("input", render);
302 document.getElementById("sourceFilter").addEventListener("change", render); 285 document.getElementById("sourceFilter").addEventListener("change", render);
303 286