sd-webui-infinite-image-bro.../vue/src/App.vue

131 lines
3.2 KiB
Vue

<!-- eslint-disable no-empty -->
<script setup lang="ts">
import { onMounted, ref, nextTick, reactive, computed } from 'vue'
import { getUploadTaskStatus, greeting, upload, type UploadTaskStatus } from './api'
import { Task } from './util/pollTask'
const pollTask = ref<ReturnType<typeof createUploadPollTask>>()
const allTaskRecord = ref([] as UploadTaskStatus[])
onMounted(async () => {
await greeting()
})
const taskLatestInfo = reactive(new Map<string, UploadTaskStatus['info']>())
const logListEl = ref<HTMLDivElement>()
const logListScroll2bottom = async () => {
await nextTick()
const el = logListEl.value
if (el) {
el.scrollTop = el.scrollHeight
}
}
const createUploadPollTask = (id: string) => {
const task = Task.run({
action: () => getUploadTaskStatus(id),
pollInterval: 500,
validator (r) {
r.tasks.forEach(({ info }) => {
if (info.status === 'start') {
} else if (info.status == 'done') {
} else {
taskLatestInfo.set(info.id, info)
}
})
allTaskRecord.value.push(...r.tasks)
logListScroll2bottom()
return !r.running
}
})
return task
}
const onUploadBtnClick = async () => {
allTaskRecord.value = []
const { id } = await upload()
pollTask.value = createUploadPollTask(id)
pollTask.value.completedTask.then(() => {
pollTask.value = undefined
})
}
const max = computed(() => taskLatestInfo.size || 100)
const taskLatestInfoArr = computed(() => Array.from(taskLatestInfo))
const done = computed(() => pollTask.value?.task.isFinished)
const uploading = computed(() => pollTask.value?.task.isFinished === false)
const progress = computed(() => {
if (done.value) {
return max.value
}
return taskLatestInfoArr.value.filter(v => v[1].status === 'upload-success' || v[1].status === 'file-skipped' || v[1].status === 'upload-failed').length
})
const progressPercent = computed(() => progress.value * 100 / max.value)
</script>
<template>
<div class="container">
<div class="upload-progress-info" v-if="pollTask">
<progress :max="max" :value="progress" />
<div>
{{ progressPercent.toFixed(2) }} %
</div>
</div>
<div class="action-bar">
<a-button @click="onUploadBtnClick" :disabled="uploading">开始上传</a-button>
</div>
<div class="log-list" ref="logListEl" v-if="allTaskRecord.length">
<div v-for="msg, idx in allTaskRecord" :key="idx">
{{ msg.log }}
</div>
</div>
</div>
</template>
<style scoped>
.action-bar {
margin: 16px 0;
}
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.upload-progress-info {
display: flex;
flex-direction: row;
align-items: center;
}
.upload-progress-info>* {
margin-right: 8px;
}
.log-list {
max-height: 70vh;
flex: 1;
overflow: auto;
background-color: #f5f5f5;
/* 背景色 */
border: 1px solid #ccc;
/* 边框 */
padding: 10px;
/* 内边距 */
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.3);
/* 阴影 */
border-radius: 5px;
/* 圆角 */
font-size: 14px;
/* 字体大小 */
line-height: 1.5;
/* 行高 */
font-family: Arial, sans-serif;
/* 字体样式 */
color: #333;
/* 字体颜色 */
}
</style>
<style>
#baidu_netdisk_container {
max-height: 70vh;
}
</style>