perf(desktop): stream drag-upload and improve transfer status UX
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user