Skip to content

Commit 437c25e

Browse files
committed
🐞 fix: 修复歌单删除逻辑
1 parent c3d3b2e commit 437c25e

File tree

15 files changed

+461
-379
lines changed

15 files changed

+461
-379
lines changed

src/components/Layout/Menu.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ const menuUpdate = (key: string, item: MenuOption) => {
423423
} else if (typeof key === "string" && key.startsWith("local-")) {
424424
// 检查是否为本地歌单(16位数字ID)
425425
const localId = key.replace("local-", "");
426-
const isLocalPlaylist = /^\d{16}$/.test(localId);
426+
const isLocalPlaylist = localStore.isLocalPlaylist(localId);
427427
if (isLocalPlaylist) {
428428
router.push({
429429
name: "playlist",
@@ -491,7 +491,7 @@ const checkMenuItem = () => {
491491
(playlist) => playlist?.id === playlistId,
492492
);
493493
// 是否为本地歌单
494-
const isLocalPlaylist = playlistId.toString().length === 16;
494+
const isLocalPlaylist = localStore.isLocalPlaylist(playlistId);
495495
if (!playlistId) menuActiveKey.value = "home";
496496
if (isUserPlaylist) {
497497
menuActiveKey.value = Number(playlistId);

src/components/List/CoverList.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@
104104
</div>
105105
<div v-else-if="loading" :class="['cover-list', 'loading', type]">
106106
<div class="cover-grid">
107-
<div v-for="item in loadingNum || 50" :key="item" :class="['cover-item', { 'no-cover': hiddenCover }]">
107+
<div
108+
v-for="item in loadingNum || 50"
109+
:key="item"
110+
:class="['cover-item', { 'no-cover': hiddenCover }]"
111+
>
108112
<div v-if="!hiddenCover" class="cover">
109113
<n-skeleton class="cover-img" />
110114
</div>
@@ -213,7 +217,7 @@ const playList = debounce(
213217
// 获取列表数据
214218
const getListData = async (id: number | string): Promise<SongType[]> => {
215219
// 判断是否为本地歌单
216-
const isLocalPlaylist = id.toString().length === 16;
220+
const isLocalPlaylist = localStore.isLocalPlaylist(id);
217221
218222
switch (props.type) {
219223
case "album": {

src/components/Modal/BatchList.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
deleteSongs(
6565
playListId,
6666
checkSongData.map((item) => item.id),
67+
{
68+
songName: checkSongData.length === 1 ? checkSongData[0].name : undefined,
69+
},
6770
)
6871
"
6972
>

src/components/Modal/UpdatePlaylist.vue

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
clearable
2323
/>
2424
</n-form-item>
25-
<n-form-item label="歌单分类" path="tags">
25+
<n-form-item v-if="!isLocal" label="歌单分类" path="tags">
2626
<n-select
2727
v-model:value="updateFormData.tags"
2828
:options="tagList"
@@ -41,7 +41,7 @@
4141
import type { CoverType } from "@/types/main";
4242
import type { FormInst, FormRules, SelectOption } from "naive-ui";
4343
import { textRule } from "@/utils/rules";
44-
import { useDataStore } from "@/stores";
44+
import { useDataStore, useLocalStore } from "@/stores";
4545
import { debounce, isEmpty, size } from "lodash-es";
4646
import { updatePlaylist } from "@/api/playlist";
4747
import { updateUserLikePlaylist } from "@/utils/auth";
@@ -56,11 +56,14 @@ interface UpdateFormType {
5656
const props = defineProps<{
5757
id: number;
5858
data: CoverType;
59+
/** 是否为本地歌单 */
60+
isLocal?: boolean;
5961
}>();
6062
6163
const emit = defineEmits<{ success: [] }>();
6264
6365
const dataStore = useDataStore();
66+
const localStore = useLocalStore();
6467
6568
// 是否为我喜欢
6669
const isLiked = computed(() => dataStore.userLikeData.playlists?.[0]?.id === props.id);
@@ -104,7 +107,23 @@ const toUpdatePlaylist = debounce(
104107
e.preventDefault();
105108
// 是否输入
106109
await updateFormRef.value?.validate((errors) => errors);
107-
// 新建歌单
110+
111+
// 本地歌单
112+
if (props.isLocal) {
113+
const success = await localStore.updateLocalPlaylist(props.id, {
114+
name: updateFormData.value.name,
115+
description: updateFormData.value.desc,
116+
});
117+
if (success) {
118+
emit("success");
119+
window.$message.success("本地歌单编辑成功");
120+
} else {
121+
window.$message.error("本地歌单编辑失败");
122+
}
123+
return;
124+
}
125+
126+
// 在线歌单
108127
const result = await updatePlaylist(
109128
props.id,
110129
updateFormData.value.name,

src/composables/useInit.ts

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import { useDataStore, useSettingStore, useShortcutStore, useStatusStore } from "@/stores";
2+
import { useEventListener } from "@vueuse/core";
3+
import { watch, onMounted } from "vue";
4+
import { openUserAgreement } from "@/utils/modal";
5+
import { debounce } from "lodash-es";
6+
import { isElectron } from "@/utils/env";
7+
import { usePlayerController } from "@/core/player/PlayerController";
8+
import { mediaSessionManager } from "@/core/player/MediaSessionManager";
9+
import { useDownloadManager } from "@/core/resource/DownloadManager";
10+
import { printVersion } from "@/utils/log";
11+
12+
/**
13+
* 应用初始化时需要执行的操作
14+
*/
15+
export const useInit = () => {
16+
// init pinia-data
17+
const dataStore = useDataStore();
18+
const statusStore = useStatusStore();
19+
const settingStore = useSettingStore();
20+
const shortcutStore = useShortcutStore();
21+
22+
const player = usePlayerController();
23+
const downloadManager = useDownloadManager();
24+
25+
// 事件监听
26+
initEventListener();
27+
28+
onMounted(async () => {
29+
// 检查并执行设置迁移
30+
settingStore.checkAndMigrate();
31+
// 打印版本信息
32+
printVersion();
33+
// 用户协议
34+
openUserAgreement();
35+
// 加载数据
36+
await dataStore.loadData();
37+
// 初始化 MediaSession
38+
mediaSessionManager.init();
39+
// 初始化播放器
40+
player.playSong({
41+
autoPlay: settingStore.autoPlay,
42+
seek: settingStore.memoryLastSeek ? statusStore.currentTime : 0,
43+
});
44+
// 同步播放模式
45+
player.playModeSyncIpc();
46+
// 初始化自动关闭定时器
47+
if (statusStore.autoClose.enable) {
48+
const { endTime, time } = statusStore.autoClose;
49+
const now = Date.now();
50+
if (endTime > now) {
51+
// 计算真实剩余时间
52+
const realRemainTime = Math.ceil((endTime - now) / 1000);
53+
player.startAutoCloseTimer(time, realRemainTime);
54+
} else {
55+
// 定时器已过期,重置状态
56+
statusStore.autoClose.enable = false;
57+
statusStore.autoClose.remainTime = time * 60;
58+
statusStore.autoClose.endTime = 0;
59+
}
60+
}
61+
if (isElectron) {
62+
// 注册全局快捷键
63+
shortcutStore.registerAllShortcuts();
64+
// 初始化下载管理器
65+
downloadManager.init();
66+
// 显示窗口
67+
window.electron.ipcRenderer.send("win-loaded");
68+
// 同步任务栏歌词状态
69+
window.electron.ipcRenderer.send("taskbar:toggle", statusStore.showTaskbarLyric);
70+
// 显示桌面歌词
71+
window.electron.ipcRenderer.send("toggle-desktop-lyric", statusStore.showDesktopLyric);
72+
// 检查更新
73+
if (settingStore.checkUpdateOnStart) window.electron.ipcRenderer.send("check-update");
74+
75+
// 监听任务栏歌词设置
76+
watch(
77+
() => settingStore.taskbarLyricMaxWidth,
78+
(val) => {
79+
window.electron.ipcRenderer.send("taskbar:set-max-width", val);
80+
},
81+
);
82+
83+
watch(
84+
() => settingStore.taskbarLyricShowCover,
85+
(val) => {
86+
window.electron.ipcRenderer.send("taskbar:set-show-cover", val);
87+
},
88+
);
89+
90+
watch(
91+
() => settingStore.taskbarLyricPosition,
92+
(val) => {
93+
window.electron.ipcRenderer.send("taskbar:set-position", val);
94+
},
95+
);
96+
97+
watch(
98+
() => settingStore.taskbarLyricShowWhenPaused,
99+
(val) => {
100+
window.electron.ipcRenderer.send("taskbar:set-show-when-paused", val);
101+
},
102+
);
103+
104+
watch(
105+
() => settingStore.taskbarLyricAutoShrink,
106+
(val) => {
107+
window.electron.ipcRenderer.send("taskbar:set-auto-shrink", val);
108+
},
109+
);
110+
111+
watch(
112+
() => [
113+
settingStore.taskbarLyricAnimationMode,
114+
settingStore.taskbarLyricSingleLineMode,
115+
settingStore.LyricFont,
116+
settingStore.globalFont,
117+
settingStore.taskbarLyricFontWeight,
118+
],
119+
() => {
120+
window.electron.ipcRenderer.send("taskbar:broadcast-settings", {
121+
animationMode: settingStore.taskbarLyricAnimationMode,
122+
singleLineMode: settingStore.taskbarLyricSingleLineMode,
123+
lyricFont: settingStore.LyricFont,
124+
globalFont: settingStore.globalFont,
125+
fontWeight: settingStore.taskbarLyricFontWeight,
126+
});
127+
},
128+
{ deep: true },
129+
);
130+
}
131+
});
132+
};
133+
134+
// 事件监听
135+
const initEventListener = () => {
136+
// 键盘事件
137+
useEventListener(window, "keydown", keyDownEvent);
138+
};
139+
140+
// 键盘事件
141+
const keyDownEvent = debounce((event: KeyboardEvent) => {
142+
const player = usePlayerController();
143+
const shortcutStore = useShortcutStore();
144+
const statusStore = useStatusStore();
145+
const target = event.target as HTMLElement;
146+
// 排除元素
147+
const extendsDom = ["input", "textarea"];
148+
if (extendsDom.includes(target.tagName.toLowerCase())) return;
149+
event.preventDefault();
150+
event.stopPropagation();
151+
// 获取按键信息
152+
const key = event.code;
153+
const isCtrl = event.ctrlKey || event.metaKey;
154+
const isShift = event.shiftKey;
155+
const isAlt = event.altKey;
156+
// 循环注册快捷键
157+
for (const shortcutKey in shortcutStore.shortcutList) {
158+
const shortcut = shortcutStore.shortcutList[shortcutKey];
159+
const shortcutParts = shortcut.shortcut.split("+");
160+
// 标志位
161+
let match = true;
162+
// 检查是否包含修饰键
163+
const hasCmdOrCtrl = shortcutParts.includes("CmdOrCtrl");
164+
const hasShift = shortcutParts.includes("Shift");
165+
const hasAlt = shortcutParts.includes("Alt");
166+
// 检查修饰键匹配
167+
if (hasCmdOrCtrl && !isCtrl) match = false;
168+
if (hasShift && !isShift) match = false;
169+
if (hasAlt && !isAlt) match = false;
170+
// 如果快捷键定义中没有修饰键,确保没有按下任何修饰键
171+
if (!hasCmdOrCtrl && !hasShift && !hasAlt) {
172+
if (isCtrl || isShift || isAlt) match = false;
173+
}
174+
// 检查实际按键
175+
const mainKey = shortcutParts.find(
176+
(part: string) => part !== "CmdOrCtrl" && part !== "Shift" && part !== "Alt",
177+
);
178+
if (mainKey !== key) match = false;
179+
if (match && shortcutKey) {
180+
console.log(shortcutKey, `快捷键触发: ${shortcut.name}`);
181+
switch (shortcutKey) {
182+
case "playOrPause":
183+
player.playOrPause();
184+
break;
185+
case "playPrev":
186+
player.nextOrPrev("prev");
187+
break;
188+
case "playNext":
189+
player.nextOrPrev("next");
190+
break;
191+
case "volumeUp":
192+
player.setVolume("up");
193+
break;
194+
case "volumeDown":
195+
player.setVolume("down");
196+
break;
197+
case "toggle-desktop-lyric":
198+
player.toggleDesktopLyric();
199+
break;
200+
case "openPlayer":
201+
// 打开播放界面(任意界面)
202+
statusStore.showFullPlayer = true;
203+
break;
204+
case "closePlayer":
205+
// 关闭播放界面(仅在播放界面时)
206+
if (statusStore.showFullPlayer) {
207+
statusStore.showFullPlayer = false;
208+
}
209+
break;
210+
case "openPlayList":
211+
// 打开播放列表(任意界面)
212+
statusStore.playListShow = !statusStore.playListShow;
213+
break;
214+
default:
215+
break;
216+
}
217+
}
218+
}
219+
}, 100);

src/composables/useSongMenu.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DropdownOption } from "naive-ui";
22
import { SongType } from "@/types/main";
3-
import { useStatusStore, useDataStore, useMusicStore, useSettingStore } from "@/stores";
3+
import { useStatusStore, useDataStore, useMusicStore, useSettingStore, useLocalStore } from "@/stores";
44
import { useDownloadManager } from "@/core/resource/DownloadManager";
55
import { usePlayerController } from "@/core/player/PlayerController";
66
import { renderIcon, copyData } from "@/utils/helper";
@@ -25,6 +25,7 @@ export const useSongMenu = () => {
2525
const settingStore = useSettingStore();
2626
const player = usePlayerController();
2727
const downloadManager = useDownloadManager();
28+
const localStore = useLocalStore();
2829

2930
// 删除本地歌曲
3031
const deleteLocalSong = (song: SongType, emit: (event: "removeSong", args: any[]) => void) => {
@@ -157,7 +158,7 @@ export const useSongMenu = () => {
157158
const isLocal = !!song?.path;
158159
const isLoginNormal = isLogin() === 1;
159160
const isCurrent = statusStore.playIndex === index;
160-
const isLocalPlaylist = playListId?.toString().length === 16;
161+
const isLocalPlaylist = localStore.isLocalPlaylist(playListId);
161162
const isUserPlaylist =
162163
(!!playListId && userPlaylistsData.some((pl) => pl.id === playListId)) || isLocalPlaylist;
163164
const isDownloading = dataStore.downloadingSongs.some((item) => item.song.id === song.id);
@@ -299,7 +300,11 @@ export const useSongMenu = () => {
299300
(isLocalPlaylist || isLoginNormal) &&
300301
!isCloud,
301302
props: {
302-
onClick: () => deleteSongs(playListId!, [song.id], () => emit("removeSong", [song.id])),
303+
onClick: () =>
304+
deleteSongs(playListId!, [song.id], {
305+
callback: () => emit("removeSong", [song.id]),
306+
songName: song.name,
307+
}),
303308
},
304309
icon: renderIcon("Delete"),
305310
},

0 commit comments

Comments
 (0)