diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 32a22f5..81ce157 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -14,7 +14,8 @@
{
"title": "昆明大学生创业园展播系统",
"width": 1200,
- "height": 800
+ "height": 800,
+ "fullscreen": true
}
],
"security": {
diff --git a/src/pages/Admin.jsx b/src/pages/Admin.jsx
index e4e57c7..32c54b3 100644
--- a/src/pages/Admin.jsx
+++ b/src/pages/Admin.jsx
@@ -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);
- inp.value = '';
- addToast('上传完成');
- loadAll();
+ 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() {
-
+
+ {uploadProgress && (
+
+
+
+ {uploadProgress.fileName} ({uploadProgress.current}/{uploadProgress.total}) — {uploadProgress.percent}%
+
+
+ )}
diff --git a/src/pages/Screen.jsx b/src/pages/Screen.jsx
index 5a22126..97a0b0a 100644
--- a/src/pages/Screen.jsx
+++ b/src/pages/Screen.jsx
@@ -381,6 +381,9 @@ export default function Screen() {
{currentItem ? `${index + 1} / ${list.length}` : '0 / 0'}
+ {/* Watermark */}
+ 云南派音人工智能科技提供技术支持
+
{/* Sound Hint */}
声音
diff --git a/src/styles/admin.css b/src/styles/admin.css
index 7e4cc3f..0fa3245 100644
--- a/src/styles/admin.css
+++ b/src/styles/admin.css
@@ -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; }
diff --git a/src/styles/screen.css b/src/styles/screen.css
index a484898..f00a340 100644
--- a/src/styles/screen.css
+++ b/src/styles/screen.css
@@ -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;
+}
diff --git a/src/utils/api.js b/src/utils/api.js
index 38f09b6..15cceac 100644
--- a/src/utils/api.js
+++ b/src/utils/api.js
@@ -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);
+ });
}
}