feat(fetch):add download progress bar
parent
d667d97f62
commit
63ad80b0bc
|
@ -19,3 +19,18 @@ export async function fetchUrlFile(
|
|||
console.log("on create download task: ", taskID);
|
||||
return taskID;
|
||||
}
|
||||
|
||||
type DownloadTask = {
|
||||
filename: string;
|
||||
pathname: string;
|
||||
progress: number;
|
||||
savedSize: number;
|
||||
taskID: string;
|
||||
totalSize: number;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export async function queryDownloadTask(taskID: string): Promise<DownloadTask> {
|
||||
const res = await fetchURL(`/api/download/${taskID}`, {});
|
||||
return await res.json();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
@keyup.enter="submit"
|
||||
v-model.trim="fetchUrl"
|
||||
tabindex="1"
|
||||
:disabled="isDownloading"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -24,6 +25,7 @@
|
|||
@keyup.enter="submit"
|
||||
v-model.trim="saveName"
|
||||
tabindex="2"
|
||||
:disabled="isDownloading"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -33,7 +35,7 @@
|
|||
@click="layoutStore.closeHovers"
|
||||
:aria-label="t('buttons.cancel')"
|
||||
:title="t('buttons.cancel')"
|
||||
tabindex="3"
|
||||
tabindex="4"
|
||||
>
|
||||
{{ t("buttons.cancel") }}
|
||||
</button>
|
||||
|
@ -42,11 +44,22 @@
|
|||
:aria-label="t('buttons.create')"
|
||||
:title="t('buttons.create')"
|
||||
@click="submit"
|
||||
tabindex="2"
|
||||
tabindex="3"
|
||||
:disabled="isDownloading"
|
||||
>
|
||||
{{ t("buttons.create") }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="progress > 0" class="material-progress-container">
|
||||
<div
|
||||
class="material-progress-bar"
|
||||
id="downloadProgress"
|
||||
:style="{ width: Math.floor(progress * 100) + '%' }"
|
||||
></div>
|
||||
<div class="material-progress-label">
|
||||
{{ (progress * 100).toFixed(1) + "%" }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -54,7 +67,7 @@
|
|||
import { useLayoutStore } from "@/stores/layout.ts";
|
||||
import { useFileStore } from "@/stores/file.ts";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { inject, ref, watch } from "vue";
|
||||
import { computed, inject, onMounted, ref, watch } from "vue";
|
||||
import url from "@/utils/url.ts";
|
||||
import { fetcher as api } from "@/api";
|
||||
import { useRoute } from "vue-router";
|
||||
|
@ -70,6 +83,11 @@ const { t } = useI18n();
|
|||
const fetchUrl = ref<string>("");
|
||||
const saveName = ref<string>("");
|
||||
const taskID = ref<string>("");
|
||||
const progress = ref<number>(0);
|
||||
|
||||
const isDownloading = computed(() => {
|
||||
return taskID.value !== "" && progress.value < 1 && progress.value > 0;
|
||||
});
|
||||
|
||||
watch(fetchUrl, (value) => {
|
||||
try {
|
||||
|
@ -113,8 +131,20 @@ const submit = async (event: Event) => {
|
|||
$showError(e);
|
||||
}
|
||||
}
|
||||
layoutStore.closeHovers();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
setInterval(async () => {
|
||||
if (!taskID.value) return;
|
||||
const task = await api.queryDownloadTask(taskID.value);
|
||||
if (!task) return;
|
||||
console.log("fetch task info", task);
|
||||
progress.value = task.progress;
|
||||
if (task.progress >= 1) {
|
||||
taskID.value = "";
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -503,3 +503,32 @@ html[dir="rtl"] .credits {
|
|||
text-align: right;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.material-progress-container {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.material-progress-bar {
|
||||
height: 100%;
|
||||
background-color: #2196F3; /* Material蓝色 */
|
||||
width: 0%;
|
||||
transition: width 0.3s ease;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.material-progress-label {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
Loading…
Reference in New Issue