feat: add download progress indicator for batch download

批量下载时显示创建下载任务的进度:
- 增加 downloadProgress 和 downloadTotal 状态
- 下载时显示进度条和计数
- 创建任务完成后自动关闭弹窗

Co-Authored-By: AI
This commit is contained in:
2026-04-09 12:38:49 +08:00
parent 86caa5765d
commit 449b5fe3a2
+40 -5
View File
@@ -49,9 +49,14 @@ export class ParseModalComp implements VanComponent {
formatIndex: State<number>
}[]> = van.state([])
/** 该属性用于在点击开始下载”按钮后使按钮变为禁用状态,防止多次点击 */
/** 该属性用于在点击开始下载”按钮后使按钮变为禁用状态,防止多次点击 */
downloadBtnDisabled = van.state(false)
/** 下载进度 */
downloadProgress = van.state(0)
downloadTotal = van.state(0)
isDownloading = van.state(false)
/** 下载类型:audio 仅音频,video 仅视频,merge 音视频合并 */
downloadType = van.state<'audio' | 'video' | 'merge'>('merge')
@@ -69,12 +74,13 @@ export class ParseModalComp implements VanComponent {
div({ class: () => `modal-dialog modal-xl modal-fullscreen-xl-down ${(this.totalCount.val + this.errorList.val.length) < 10 ? '' : 'modal-dialog-scrollable'}` },
div({ class: `modal-content` },
div({ class: `modal-header` },
div({ class: `h5 modal-title` }, () => allFinish.val ? '批量下载' : '批量解析'),
div({ class: `h5 modal-title` }, () => this.isDownloading.val ? '正在创建下载任务...' : (allFinish.val ? '批量下载' : '批量解析')),
button({ class: `btn-close`, 'data-bs-dismiss': `modal` })
),
div({ class: `modal-body vstack gap-3`, tabIndex: -1, style: 'outline: none;' },
this.ParseProgress(),
div({ class: 'vstack gap-2', hidden: () => this.errorList.val.length == 0 || !allFinish.val },
this.DownloadProgress(),
div({ class: 'vstack gap-2', hidden: () => this.errorList.val.length == 0 || !allFinish.val || this.isDownloading.val },
div({ class: 'text-danger' }, () => `以下 ${this.errorList.val.length} 个视频解析失败`),
() => div({ class: 'list-group' },
this.errorList.val.map(error => div({ class: 'list-group-item disabled' }, error))
@@ -133,8 +139,12 @@ export class ParseModalComp implements VanComponent {
const selectedPlayInfos = this.allPlayInfo.val.filter(info => info.selected.val)
const workRoute = this.option.workRoute
this.downloadBtnDisabled.val = true
this.isDownloading.val = true
this.downloadProgress.val = 0
this.downloadTotal.val = selectedPlayInfos.length
// 需要传递给服务器,需要创建下载任务的数据列表
createTask(selectedPlayInfos.map(info => {
createTask(selectedPlayInfos.map((info, index) => {
const badgeNotNum = !info.page.badge.match(/^\d+$/)
const isVideoMode = workRoute.videoInfoCardMode.val == 'video'
const cardTitle = workRoute.videoInfoCardData.val.title
@@ -175,16 +185,31 @@ export class ParseModalComp implements VanComponent {
...activeVideoInfo
})
})).then(() => {
this.downloadProgress.val = this.downloadTotal.val
setTimeout(() => {
workRoute.parseModal.hide()
}, 500)
}).catch(error => {
alert(error.message)
}).finally(() => {
this.downloadBtnDisabled.val = false
this.isDownloading.val = false
})
// 更新进度
const updateProgress = () => {
if (this.downloadProgress.val < this.downloadTotal.val) {
this.downloadProgress.val++
if (this.isDownloading.val) {
setTimeout(updateProgress, 50)
}
}
}
setTimeout(updateProgress, 100)
}
ParseProgress() {
return div({ class: 'vstack gap-3', hidden: () => this.totalCount.val == this.finishCount.val },
return div({ class: 'vstack gap-3', hidden: () => this.totalCount.val == this.finishCount.val || this.isDownloading.val },
div({ class: 'text-center fs-5' }, () => `正在解析,剩余 ${this.totalCount.val - this.finishCount.val}`),
div({ class: 'progress' }, div({
class: 'progress-bar progress-bar-striped progress-bar-animated',
@@ -193,6 +218,16 @@ export class ParseModalComp implements VanComponent {
)
}
DownloadProgress() {
return div({ class: 'vstack gap-3', hidden: () => !this.isDownloading.val },
div({ class: 'text-center fs-5' }, () => `正在创建下载任务 (${this.downloadProgress.val}/${this.downloadTotal.val})`),
div({ class: 'progress' }, div({
class: 'progress-bar progress-bar-striped progress-bar-animated',
style: () => `width: ${this.downloadProgress.val / this.downloadTotal.val * 100}%`
},)),
)
}
ListGroup() {
return () => div({ class: 'list-group', hidden: () => this.totalCount.val != this.finishCount.val },
this.allPlayInfo.val.filter(info => info.info)