161161 </n-flex >
162162 </template >
163163 </n-modal >
164-
165- <!-- 批量下载进度通知 -->
166- <Teleport to =" body" >
167- <Transition name =" slide-fade" >
168- <div
169- v-if =" batchDownloadState.isDownloading"
170- class =" batch-download-notification"
171- :class =" { 'is-hovered': isNotificationHovered }"
172- @mouseenter =" isNotificationHovered = true"
173- @mouseleave =" isNotificationHovered = false"
174- >
175- <n-card content-style =" padding: 16px;" :bordered =" false" >
176- <n-flex vertical :size =" 12" >
177- <n-flex justify =" space-between" align =" center" >
178- <n-text strong >批量下载中</n-text >
179- <n-text depth =" 3" style =" font-size : 12px " >
180- {{ batchDownloadState.processed }}/{{ batchDownloadState.total }}
181- </n-text >
182- </n-flex >
183-
184- <n-text style =" font-size : 13px " ellipsis >
185- 正在下载: {{ batchDownloadState.currentSong }}
186- </n-text >
187-
188- <n-progress
189- type =" line"
190- :percentage =" batchDownloadState.percent"
191- :show-indicator =" false"
192- processing
193- status =" success"
194- style =" height : 6px "
195- />
196-
197- <n-flex justify =" space-between" style =" font-size : 12px " >
198- <n-text depth =" 3" >
199- {{ batchDownloadState.transferred }} / {{ batchDownloadState.totalSize }}
200- </n-text >
201- <n-text depth =" 3" >
202- 成功: {{ batchDownloadState.success }}
203- </n-text >
204- </n-flex >
205- </n-flex >
206- </n-card >
207- </div >
208- </Transition >
209- </Teleport >
210164 </div >
211165</template >
212166
@@ -226,18 +180,17 @@ import {
226180 NInputGroup ,
227181 NButton ,
228182 NAlert ,
229- NCard ,
230- NProgress ,
231183 NText ,
232184 NFlex ,
233185} from " naive-ui" ;
234- import { useLocalStore , useSettingStore } from " @/stores" ;
186+ import { useLocalStore , useSettingStore , useDataStore } from " @/stores" ;
235187import { isElectron } from " @/utils/env" ;
236188import { songLevelData , getSongLevelsData } from " @/utils/meta" ;
237189import { downloadSong } from " @/utils/download" ;
238190
239191const localStore = useLocalStore ();
240192const settingStore = useSettingStore ();
193+ const dataStore = useDataStore ();
241194
242195interface DataType {
243196 key? : number ;
@@ -269,19 +222,6 @@ const showQualityModal = ref(false);
269222const selectedQuality = ref <SongLevelType >(" h" );
270223const downloadPath = ref <string >(settingStore .downloadPath );
271224
272- // 批量下载状态
273- const batchDownloadState = reactive ({
274- isDownloading: false ,
275- total: 0 ,
276- processed: 0 ,
277- success: 0 ,
278- currentSong: " " ,
279- percent: 0 ,
280- transferred: " 0MB" ,
281- totalSize: " 0MB" ,
282- });
283- const isNotificationHovered = ref (false );
284-
285225// 音质选项
286226const qualityOptions = computed (() => {
287227 // 批量下载时,默认显示所有常用音质选项
@@ -474,23 +414,26 @@ const executeBatchDownload = async (songs: SongType[]) => {
474414 if (! songs .length ) return ;
475415
476416 // 重置状态
477- batchDownloadState .isDownloading = true ;
478- batchDownloadState .total = songs .length ;
479- batchDownloadState .processed = 0 ;
480- batchDownloadState .success = 0 ;
481- batchDownloadState .percent = 0 ;
482- batchDownloadState .transferred = " 0MB" ;
483- batchDownloadState .totalSize = " 0MB" ;
417+ dataStore . batchDownload .isDownloading = true ;
418+ dataStore . batchDownload .total = songs .length ;
419+ dataStore . batchDownload .processed = 0 ;
420+ dataStore . batchDownload .success = 0 ;
421+ dataStore . batchDownload .percent = 0 ;
422+ dataStore . batchDownload .transferred = " 0MB" ;
423+ dataStore . batchDownload .totalSize = " 0MB" ;
484424
485425 let failCount = 0 ;
486426 const failedSongs: SongType [] = [];
487427
488428 // 监听下载进度
489- const onProgress = (_event : any , progress : { percent: number ; transferredBytes: number ; totalBytes: number }) => {
429+ const onProgress = (
430+ _event : any ,
431+ progress : { percent: number ; transferredBytes: number ; totalBytes: number },
432+ ) => {
490433 const { percent, transferredBytes, totalBytes } = progress ;
491- batchDownloadState .percent = Number ((percent * 100 ).toFixed (0 ));
492- batchDownloadState .transferred = (transferredBytes / 1024 / 1024 ).toFixed (2 ) + " MB" ;
493- batchDownloadState .totalSize = (totalBytes / 1024 / 1024 ).toFixed (2 ) + " MB" ;
434+ dataStore . batchDownload .percent = Number ((percent * 100 ).toFixed (0 ));
435+ dataStore . batchDownload .transferred = (transferredBytes / 1024 / 1024 ).toFixed (2 ) + " MB" ;
436+ dataStore . batchDownload .totalSize = (totalBytes / 1024 / 1024 ).toFixed (2 ) + " MB" ;
494437 };
495438
496439 if (isElectron ) {
@@ -499,7 +442,7 @@ const executeBatchDownload = async (songs: SongType[]) => {
499442
500443 try {
501444 for (const song of songs ) {
502- batchDownloadState .currentSong = song .name ;
445+ dataStore . batchDownload .currentSong = song .name ;
503446 try {
504447 const result = await downloadSong ({
505448 song ,
@@ -509,7 +452,7 @@ const executeBatchDownload = async (songs: SongType[]) => {
509452 });
510453
511454 if (result .success ) {
512- batchDownloadState .success ++ ;
455+ dataStore . batchDownload .success ++ ;
513456 if (result .skipped ) {
514457 window .$notification .create ({
515458 title: " 已跳过重复文件" ,
@@ -531,32 +474,50 @@ const executeBatchDownload = async (songs: SongType[]) => {
531474 failCount ++ ;
532475 failedSongs .push (song );
533476 } finally {
534- batchDownloadState .processed ++ ;
477+ dataStore . batchDownload .processed ++ ;
535478 // Reset progress for next song
536- batchDownloadState .percent = 0 ;
537- batchDownloadState .transferred = " 0MB" ;
538- batchDownloadState .totalSize = " 0MB" ;
479+ dataStore . batchDownload .percent = 0 ;
480+ dataStore . batchDownload .transferred = " 0MB" ;
481+ dataStore . batchDownload .totalSize = " 0MB" ;
539482 }
540483 }
541484
542485 if (failCount > 0 ) {
543486 window .$dialog .warning ({
544487 title: " 下载完成,但有部分失败" ,
545- content : () => h (" div" , [
546- h (" div" , { style: " margin-bottom: 10px" }, ` ${batchDownloadState .success } 首下载成功,${failCount } 首下载失败。 ` ),
547- h (" div" , { style: " max-height: 200px; overflow-y: auto; background: rgba(0,0,0,0.05); padding: 8px; border-radius: 4px;" }, [
548- h (" div" , { style: " font-weight: bold; margin-bottom: 4px" }, " 失败列表:" ),
549- ... failedSongs .map (s => h (" div" , { style: " font-size: 12px" }, ` ${s .name } - ${isArray (s .artists ) ? s .artists [0 ]?.name : s .artists || ' 未知歌手' } ` ))
550- ])
551- ]),
488+ content : () =>
489+ h (" div" , [
490+ h (
491+ " div" ,
492+ { style: " margin-bottom: 10px" },
493+ ` ${dataStore .batchDownload .success } 首下载成功,${failCount } 首下载失败。 ` ,
494+ ),
495+ h (
496+ " div" ,
497+ {
498+ style:
499+ " max-height: 200px; overflow-y: auto; background: rgba(0,0,0,0.05); padding: 8px; border-radius: 4px;" ,
500+ },
501+ [
502+ h (" div" , { style: " font-weight: bold; margin-bottom: 4px" }, " 失败列表:" ),
503+ ... failedSongs .map ((s ) =>
504+ h (
505+ " div" ,
506+ { style: " font-size: 12px" },
507+ ` ${s .name } - ${isArray (s .artists ) ? s .artists [0 ]?.name : s .artists || " 未知歌手" } ` ,
508+ ),
509+ ),
510+ ],
511+ ),
512+ ]),
552513 positiveText: " 重试失败歌曲" ,
553514 negativeText: " 取消" ,
554515 onPositiveClick : () => {
555516 executeBatchDownload (failedSongs );
556517 },
557518 });
558519 } else {
559- window .$message .success (` 批量下载完成,共 ${batchDownloadState .success } 首 ` );
520+ window .$message .success (` 批量下载完成,共 ${dataStore . batchDownload .success } 首 ` );
560521 }
561522 } catch (error ) {
562523 console .error (" Batch download error:" , error );
@@ -565,7 +526,7 @@ const executeBatchDownload = async (songs: SongType[]) => {
565526 if (isElectron ) {
566527 window .electron .ipcRenderer .removeListener (" download-progress" , onProgress );
567528 }
568- batchDownloadState .isDownloading = false ;
529+ dataStore . batchDownload .isDownloading = false ;
569530 }
570531};
571532 </script >
@@ -577,35 +538,4 @@ const executeBatchDownload = async (songs: SongType[]) => {
577538.range-input {
578539 width : 100px ;
579540}
580-
581- .batch-download-notification {
582- position : fixed ;
583- bottom : 24px ;
584- right : 24px ;
585- z-index : 9999 ;
586- width : 320px ;
587- transition : all 0.3s ease ;
588-
589- & .is-hovered {
590- opacity : 0 ;
591- transform : translateY (10px );
592- pointer-events : none ;
593- }
594-
595- :deep (.n-card ) {
596- box-shadow : 0 8px 32px rgba (0 , 0 , 0 , 0.12 );
597- border : 1px solid rgba (255 , 255 , 255 , 0.1 );
598- }
599- }
600-
601- .slide-fade-enter-active ,
602- .slide-fade-leave-active {
603- transition : all 0.3s ease ;
604- }
605-
606- .slide-fade-enter-from ,
607- .slide-fade-leave-to {
608- transform : translateY (20px );
609- opacity : 0 ;
610- }
611541 </style >
0 commit comments