pref: 优化下载任务进度条的性能

This commit is contained in:
lanyeeee
2026-02-10 04:16:30 +08:00
parent b988e9ff15
commit e8702fb734
7 changed files with 101 additions and 54 deletions
+6
View File
@@ -4,8 +4,14 @@ import App from './App.vue'
import 'virtual:uno.css'
import 'lazysizes'
import 'lazysizes/plugins/parent-fit/ls.parent-fit'
import VueScan, { type VueScanOptions } from 'z-vue-scan'
const pinia = createPinia()
const app = createApp(App)
const isProduction = import.meta.env.PROD
if (!isProduction) {
app.use<VueScanOptions>(VueScan, {})
}
app.use(pinia).mount('#app')
@@ -1,6 +1,6 @@
<script setup lang="tsx">
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch } from 'vue'
import { SelectionArea, SelectionEvent } from '@viselect/vue'
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch, useTemplateRef } from 'vue'
import { PartialSelectionOptions, SelectionArea, SelectionEvent } from '@viselect/vue'
import { commands } from '../../../bindings.ts'
import { DropdownOption, NIcon } from 'naive-ui'
import { PhChecks, PhTrash, PhArrowClockwise } from '@phosphor-icons/vue'
@@ -10,9 +10,13 @@ import { ProgressData } from '../DownloadPane.vue'
const store = useStore()
const selectionOptions: PartialSelectionOptions = {
selectables: '.selectable',
features: { deselectOnBlur: true },
boundaries: '.completed-progresses-selection-container',
}
const selectionAreaRef = useTemplateRef('selectionAreaRef')
const selectedIds = ref<Set<string>>(new Set())
const selectionAreaRef = ref<InstanceType<typeof SelectionArea>>()
const progressRefs = ref<InstanceType<typeof DownloadProgress>[]>([])
const { dropdownX, dropdownY, dropdownShowing, dropdownOptions, showDropdown } = useDropdown()
const completedProgresses = computed<[string, DeepReadonly<ProgressData>][]>(() =>
@@ -152,41 +156,35 @@ defineExpose({
<template>
<div class="h-full flex flex-col overflow-auto">
<SelectionArea
ref="selectionAreaRef"
class="h-full flex flex-col selection-container px-2"
:options="{ selectables: '.selectable', features: { deselectOnBlur: true } }"
@contextmenu="showDropdown"
@move="updateSelectedIds"
@start="unselectAll">
<SelectionArea ref="selectionAreaRef" :options="selectionOptions" @move="updateSelectedIds" @start="unselectAll" />
<div class="completed-progresses-selection-container h-full flex flex-col px-2" @contextmenu="showDropdown">
<div class="animate-pulse text-violet">左键拖动进行框选右键打开菜单</div>
<DownloadProgress
v-for="[taskId, p] in currentPageProgresses"
:key="taskId"
:p="p"
v-model:selected-ids="selectedIds"
ref="progressRefs"
:data-key="taskId"
:class="['selectable', selectedIds.has(taskId) ? 'selected shadow-md' : 'hover:bg-gray-1']" />
<n-dropdown
placement="bottom-start"
trigger="manual"
:x="dropdownX"
:y="dropdownY"
:options="dropdownOptions"
:show="dropdownShowing"
:on-clickoutside="() => (dropdownShowing = false)" />
</SelectionArea>
:p="p"
v-model:selected-ids="selectedIds" />
</div>
<n-dropdown
placement="bottom-start"
trigger="manual"
:x="dropdownX"
:y="dropdownY"
:options="dropdownOptions"
:show="dropdownShowing"
:on-clickoutside="() => (dropdownShowing = false)" />
</div>
</template>
<style scoped>
.selection-container {
.completed-progresses-selection-container {
@apply select-none overflow-auto;
}
.selection-container .selected {
.completed-progresses-selection-container .selected {
@apply bg-[rgb(204,232,255)];
}
</style>
@@ -1,6 +1,6 @@
<script setup lang="tsx">
import { path } from '@tauri-apps/api'
import { commands, DownloadTaskState } from '../../../bindings.ts'
import { commands } from '../../../bindings.ts'
import { useStore } from '../../../store.ts'
import {
PhWarningCircle,
@@ -55,7 +55,9 @@ async function handleProgressDoubleClick() {
}
}
function stateToStatus(state: DownloadTaskState): ProgressProps['status'] {
const progressStatus = computed<ProgressProps['status']>(() => {
const state = props.p.state
if (state === 'Completed') {
return 'success'
} else if (state === 'Paused') {
@@ -65,9 +67,11 @@ function stateToStatus(state: DownloadTaskState): ProgressProps['status'] {
} else {
return 'default'
}
}
})
const colorClass = computed<string>(() => {
const state = props.p.state
function stateToColorClass(state: DownloadTaskState) {
if (state === 'Downloading') {
return 'text-blue-500'
} else if (state === 'Pending') {
@@ -81,7 +85,7 @@ function stateToColorClass(state: DownloadTaskState) {
}
return ''
}
})
async function showMp4InFileManager(episodeDir: string, filename: string) {
if (store.config === undefined) {
@@ -145,7 +149,8 @@ function handleModifyClick() {
<template>
<div
class="p-2 mb-2 rounded-lg flex flex-col border border-solid border-gray-2"
class="selectable p-2 mb-2 rounded-lg flex flex-col border border-solid border-gray-2"
:class="selectedIds.has(p.task_id) ? 'selected shadow-md' : 'hover:bg-gray-1'"
@contextmenu="handleProgressContextMenu"
@dblclick="handleProgressDoubleClick">
<div class="flex">
@@ -254,7 +259,7 @@ function handleModifyClick() {
:up-avatar="p.up_avatar"
:up-uid="p.up_uid" />
<div v-if="p.state !== 'Completed'" :class="[stateToColorClass(p.state), 'flex items-center w-100']">
<div v-if="p.state !== 'Completed'" :class="[colorClass, 'flex items-center w-100']">
<n-icon :size="22">
<PhCloudArrowDown v-if="p.state === 'Downloading'" />
<PhClock v-else-if="p.state === 'Pending'" />
@@ -264,7 +269,7 @@ function handleModifyClick() {
<span class="whitespace-nowrap mr-2">{{ p.stateIndicator }}</span>
<n-progress
v-if="p.taskIndicator !== ''"
:status="stateToStatus(p.state)"
:status="progressStatus"
:percentage="p.percentage"
:processing="p.state === 'Downloading'">
{{ p.taskIndicator }}
@@ -1,6 +1,6 @@
<script setup lang="tsx">
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch } from 'vue'
import { SelectionArea, SelectionEvent } from '@viselect/vue'
import { ref, watchEffect, computed, nextTick, DeepReadonly, watch, useTemplateRef } from 'vue'
import { PartialSelectionOptions, SelectionArea, SelectionEvent } from '@viselect/vue'
import { commands } from '../../../bindings.ts'
import { DropdownOption, NIcon } from 'naive-ui'
import { PhPause, PhChecks, PhTrash, PhCaretRight, PhArrowClockwise } from '@phosphor-icons/vue'
@@ -10,9 +10,13 @@ import { ProgressData } from '../DownloadPane.vue'
const store = useStore()
const selectionOptions: PartialSelectionOptions = {
selectables: '.selectable',
features: { deselectOnBlur: true },
boundaries: '.uncompleted-progresses-selection-container',
}
const selectionAreaRef = useTemplateRef('selectionAreaRef')
const selectedIds = ref<Set<string>>(new Set())
const selectionAreaRef = ref<InstanceType<typeof SelectionArea>>()
const progressRefs = ref<InstanceType<typeof DownloadProgress>[]>([])
const { dropdownX, dropdownY, dropdownShowing, dropdownOptions, showDropdown } = useDropdown()
const uncompletedProgresses = computed<[string, DeepReadonly<ProgressData>][]>(() =>
@@ -210,13 +214,8 @@ defineExpose({
<template>
<div class="h-full flex flex-col overflow-auto">
<SelectionArea
ref="selectionAreaRef"
class="h-full flex flex-col selection-container px-2"
:options="{ selectables: '.selectable', features: { deselectOnBlur: true } }"
@contextmenu="showDropdown"
@move="updateSelectedIds"
@start="unselectAll">
<SelectionArea ref="selectionAreaRef" :options="selectionOptions" @move="updateSelectedIds" @start="unselectAll" />
<div class="h-full flex flex-col uncompleted-progresses-selection-container px-2" @contextmenu="showDropdown">
<div class="flex">
<span class="animate-pulse text-violet">
左键拖动进行框选右键打开菜单双击暂停/继续失败的任务也可以继续
@@ -226,12 +225,10 @@ defineExpose({
<DownloadProgress
v-for="[taskId, p] in currentPageProgresses"
:key="taskId"
:p="p"
v-model:selected-ids="selectedIds"
ref="progressRefs"
:data-key="taskId"
:class="['selectable ', selectedIds.has(taskId) ? 'selected shadow-md' : 'hover:bg-gray-1']" />
</SelectionArea>
:p="p"
v-model:selected-ids="selectedIds" />
</div>
<n-dropdown
placement="bottom-start"
@@ -245,11 +242,11 @@ defineExpose({
</template>
<style scoped>
.selection-container {
.uncompleted-progresses-selection-container {
@apply select-none overflow-auto;
}
.selection-container .selected {
.uncompleted-progresses-selection-container .selected {
@apply bg-[rgb(204,232,255)];
}
</style>
+9 -1
View File
@@ -38,8 +38,16 @@ function useProgresses() {
// 将 `_progresses` 的内容更新到 `progresses` 中,并触发重新渲染
const updateProgressesOnFrame = () => {
const newProgressesMap = new Map<string, ProgressData>()
for (const [key, value] of _progresses.entries()) {
newProgressesMap.set(key, { ...value })
const progressData = progresses.value.get(key)
if (progressData !== undefined) {
Object.assign(progressData, value)
newProgressesMap.set(key, progressData)
} else {
newProgressesMap.set(key, { ...value })
}
}
progresses.value = newProgressesMap