perf(desktop): stream drag-upload and improve transfer status UX

This commit is contained in:
2026-02-18 19:50:34 +08:00
parent 09043e8059
commit d4818a78d3
4 changed files with 60 additions and 13 deletions

View File

@@ -70,7 +70,7 @@ const selectedFileName = ref("");
const searchKeyword = ref("");
const shares = ref<ShareItem[]>([]);
const transferTasks = ref<{ id: string; name: string; speed: string; progress: number; status: string }[]>([]);
const transferTasks = ref<{ id: string; name: string; speed: string; progress: number; status: string; note?: string }[]>([]);
const sharesLoading = ref(false);
const contextMenu = reactive({
visible: false,
@@ -280,17 +280,25 @@ function showToast(message: string, type = "info") {
}, 2500);
}
function prependTransferTask(task: { id: string; name: string; speed: string; progress: number; status: string }) {
function prependTransferTask(task: { id: string; name: string; speed: string; progress: number; status: string; note?: string }) {
transferTasks.value = [task, ...transferTasks.value.slice(0, 49)];
}
function updateTransferTask(
id: string,
patch: Partial<{ name: string; speed: string; progress: number; status: string }>,
patch: Partial<{ name: string; speed: string; progress: number; status: string; note?: string }>,
) {
transferTasks.value = transferTasks.value.map((task) => (task.id === id ? { ...task, ...patch } : task));
}
function getTaskStatusLabel(status: string) {
if (status === "uploading") return "上传中";
if (status === "downloading") return "下载中";
if (status === "done") return "已完成";
if (status === "failed") return "失败";
return status;
}
async function invokeBridge(command: string, payload: Record<string, any>) {
try {
return await invoke<BridgeResponse>(command, payload);
@@ -624,14 +632,15 @@ async function downloadSelected(target?: FileItem | null) {
});
if (nativeResponse.ok && nativeResponse.data?.success) {
updateTransferTask(taskId, { speed: "-", progress: 100, status: "done" });
updateTransferTask(taskId, { speed: "-", progress: 100, status: "done", note: "下载成功" });
const savedPath = nativeResponse.data?.savePath ? `\n${nativeResponse.data.savePath}` : "";
showToast(`下载完成${savedPath}`, "success");
return;
}
updateTransferTask(taskId, { speed: "-", progress: 0, status: "failed" });
showToast(nativeResponse.data?.message || "原生下载失败", "error");
const message = String(nativeResponse.data?.message || "原生下载失败");
updateTransferTask(taskId, { speed: "-", progress: 0, status: "failed", note: message });
showToast(message, "error");
}
function selectFile(item: FileItem) {
@@ -764,13 +773,16 @@ async function uploadDroppedFiles(paths: string[]) {
speed: "-",
progress: 100,
status: "done",
note: "上传成功",
});
} else {
dropState.failed += 1;
const message = String(response.data?.message || "上传失败");
updateTransferTask(taskId, {
speed: "-",
progress: 0,
status: "failed",
note: message,
});
}
}
@@ -802,7 +814,12 @@ async function registerDragDropListener() {
if (payload.type === "drop") {
dropState.active = false;
if (!canUseDragUpload()) return;
if (!canUseDragUpload()) {
if (authenticated.value) {
showToast("请先切换到“全部文件”页面再上传", "info");
}
return;
}
void uploadDroppedFiles(payload.paths || []);
}
});
@@ -995,7 +1012,8 @@ onBeforeUnmount(() => {
<div v-for="task in transferTasks" :key="task.id" class="task-row">
<div>
<strong>{{ task.name }}</strong>
<small>{{ task.id }} · {{ task.status }}</small>
<small>{{ task.id }} · {{ getTaskStatusLabel(task.status) }}</small>
<small v-if="task.note" class="task-note" :class="{ error: task.status === 'failed' }">{{ task.note }}</small>
</div>
<div class="task-right">
<span>{{ task.speed }}</span>
@@ -1639,9 +1657,19 @@ select:focus {
}
.task-row small {
display: block;
color: #647b94;
}
.task-note {
margin-top: 2px;
color: #5f7895;
}
.task-note.error {
color: #c24747;
}
.task-right {
display: grid;
gap: 6px;