- 优化界面全屏、视频上传进度条、视频自动裁切铺满屏幕

This commit is contained in:
Pine
2026-05-13 02:21:29 +08:00
parent aa857a5ff8
commit 1f3bd690f0
6 changed files with 116 additions and 9 deletions
+2 -1
View File
@@ -14,7 +14,8 @@
{
"title": "昆明大学生创业园展播系统",
"width": 1200,
"height": 800
"height": 800,
"fullscreen": true
}
],
"security": {
+20 -2
View File
@@ -156,6 +156,7 @@ export default function Admin() {
const [playState, setPlayState] = useState({ status: 'idle' });
const [previewItem, setPreviewItem] = useState(null);
const [toasts, setToasts] = useState([]);
const [uploadProgress, setUploadProgress] = useState(null);
const toastIdRef = useRef(0);
const volTimerRef = useRef(null);
@@ -259,10 +260,17 @@ export default function Admin() {
const inp = document.getElementById('fileInput');
const fileList = Array.from(inp.files);
if (fileList.length === 0) { addToast('请选择文件', 'error'); return; }
await api.uploadFiles(fileList);
try {
setUploadProgress({ percent: 0, fileName: fileList[0].name, current: 1, total: fileList.length });
await api.uploadFilesWithProgress(fileList, setUploadProgress);
setUploadProgress(null);
inp.value = '';
addToast('上传完成');
loadAll();
} catch (err) {
setUploadProgress(null);
addToast(err.message || '上传失败', 'error');
}
};
const handleAddUrl = async () => {
@@ -403,8 +411,18 @@ export default function Admin() {
<label>本地上传</label>
<div className="form-row">
<input type="file" id="fileInput" accept=".mp4,.mkv,.avi,.jpg,.jpeg,.png" multiple />
<button className="btn-accent" onClick={handleUpload}>上传</button>
<button className="btn-accent" onClick={handleUpload} disabled={uploadProgress !== null}>上传</button>
</div>
{uploadProgress && (
<div className="upload-progress">
<div className="progress-bar">
<div className="progress-fill" style={{ width: `${uploadProgress.percent}%` }}></div>
</div>
<span className="progress-text">
{uploadProgress.fileName} ({uploadProgress.current}/{uploadProgress.total}) {uploadProgress.percent}%
</span>
</div>
)}
</div>
<div className="form-group">
<label>远程 URL</label>
+3
View File
@@ -381,6 +381,9 @@ export default function Screen() {
<span className="sb-text">{currentItem ? `${index + 1} / ${list.length}` : '0 / 0'}</span>
</div>
{/* Watermark */}
<div className="watermark">云南派音人工智能科技提供技术支持</div>
{/* Sound Hint */}
<div id="soundHint" style={{ display: soundBlocked && loaded ? 'block' : 'none' }} onClick={enableSound}>
声音
+31
View File
@@ -949,6 +949,37 @@ button { font-family: "Poppins", "PingFang SC", sans-serif; cursor: pointer; tra
font-variant-numeric: tabular-nums;
}
/* ============ Upload Progress ============ */
.upload-progress {
margin-top: var(--space-12);
display: flex;
align-items: center;
gap: var(--space-12);
}
.progress-bar {
flex: 1;
height: 6px;
background: rgba(0,0,0,0.06);
border-radius: 3px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--primary);
border-radius: 3px;
transition: width 0.25s ease;
box-shadow: 0 0 8px rgba(0, 189, 125, 0.3);
}
.progress-text {
font-family: "JetBrains Mono", "SF Mono", "Consolas", monospace;
font-size: 11px;
font-weight: 500;
color: var(--text-dim);
white-space: nowrap;
flex-shrink: 0;
font-variant-numeric: tabular-nums;
}
/* ============ Responsive ============ */
@media (max-width: 768px) {
.login-card { padding: var(--space-24) var(--space-16) var(--space-32); margin: var(--space-12); max-width: none; }
+17 -2
View File
@@ -121,7 +121,7 @@
inset: 0;
width: 100vw;
height: 100vh;
object-fit: contain;
object-fit: cover;
background: transparent;
z-index: 3;
}
@@ -130,7 +130,7 @@
inset: 0;
width: 100vw;
height: 100vh;
object-fit: contain;
object-fit: cover;
background: transparent;
z-index: 3;
display: none;
@@ -429,3 +429,18 @@
font-variant-numeric: tabular-nums;
font-family: "SF Mono", "JetBrains Mono", "Consolas", monospace;
}
/* ============ Watermark ============ */
.watermark {
position: fixed;
bottom: 28px;
left: 28px;
z-index: 100;
font-size: 10px;
font-weight: 400;
color: rgba(255,255,255,0.2);
letter-spacing: 0.08em;
pointer-events: none;
user-select: none;
font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
}
+40 -1
View File
@@ -59,7 +59,46 @@ export async function uploadFiles(files) {
for (const file of files) {
const fd = new FormData();
fd.append('file', file);
await fetch(`${BASE}/upload`, { method: 'POST', body: fd });
const res = await fetch(`${BASE}/upload`, { method: 'POST', body: fd });
if (!res.ok) throw new Error(`上传失败 (${res.status})`);
}
}
export async function uploadFilesWithProgress(files, onProgress) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', `${BASE}/upload`);
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) {
onProgress({
percent: Math.round((e.loaded / e.total) * 100),
loaded: e.loaded,
total: e.total,
fileName: file.name,
current: i + 1,
total: files.length,
});
}
};
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve();
} else {
reject(new Error(`上传失败 (${xhr.status})`));
}
};
xhr.onerror = () => reject(new Error('网络错误,请检查连接'));
xhr.ontimeout = () => reject(new Error('上传超时'));
const fd = new FormData();
fd.append('file', file);
xhr.send(fd);
});
}
}