Skip to content

Commit 2173f19

Browse files
committed
✨ feat: 完善本地模式
1 parent 315e053 commit 2173f19

9 files changed

Lines changed: 176 additions & 35 deletions

File tree

src/components/Layout/Menu.vue

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,55 @@ const menuOptions = computed<MenuOption[] | MenuGroupOption[]>(() => {
242242
{
243243
key: "local",
244244
link: "local",
245-
label: "本地歌曲",
245+
label: "音乐库",
246246
show: isElectron,
247247
icon: renderIcon("FolderMusic"),
248248
},
249+
{
250+
key: "local-albums",
251+
link: "local-albums",
252+
label: "专辑",
253+
show:
254+
isElectron &&
255+
(localStore.localSongs?.length > 0 || settingStore.localFilesPath?.length > 0),
256+
icon: renderIcon("Album"),
257+
},
258+
{
259+
key: "local-artists",
260+
link: "local-artists",
261+
label: "艺术家",
262+
show:
263+
isElectron &&
264+
(localStore.localSongs?.length > 0 || settingStore.localFilesPath?.length > 0),
265+
icon: renderIcon("Person"),
266+
},
267+
{
268+
key: "divider",
269+
type: "divider",
270+
show: localPlaylistMenu.value.length > 0,
271+
},
272+
// 本地歌单
273+
{
274+
key: "local-playlists",
275+
show: localPlaylistMenu.value.length > 0,
276+
icon: statusStore.menuCollapsed ? renderIcon("PlaylistAdd") : undefined,
277+
label: () =>
278+
h("div", { class: "user-list" }, [
279+
h(NText, { depth: 3 }, () => "本地歌单"),
280+
h(NButton, {
281+
type: "tertiary",
282+
round: true,
283+
strong: true,
284+
secondary: true,
285+
renderIcon: renderIcon("Add"),
286+
onclick: (event: Event) => {
287+
event.stopPropagation();
288+
openCreatePlaylist(true);
289+
},
290+
}),
291+
]),
292+
children: [...localPlaylistMenu.value],
293+
},
249294
];
250295
});
251296
@@ -341,12 +386,15 @@ const menuUpdate = (key: string, item: MenuOption) => {
341386
query: { id: item.key },
342387
});
343388
} else if (typeof key === "string" && key.startsWith("local-")) {
344-
// 本地歌单
389+
// 检查是否为本地歌单(16位数字ID)
345390
const localId = key.replace("local-", "");
346-
router.push({
347-
name: "playlist",
348-
query: { id: localId },
349-
});
391+
const isLocalPlaylist = /^\d{16}$/.test(localId);
392+
if (isLocalPlaylist) {
393+
router.push({
394+
name: "playlist",
395+
query: { id: localId },
396+
});
397+
}
350398
} else {
351399
switch (key) {
352400
case "like-songs":
@@ -377,18 +425,26 @@ const checkMenuItem = () => {
377425
// 处理路由名称
378426
const prefixMap = [
379427
{ prefix: "discover-", name: "discover" },
380-
{ prefix: "local-", name: "local" },
428+
// 本地模式下不合并 local- 前缀的路由
429+
{ prefix: "local-", name: "local", skipInLocalMode: true },
381430
{ prefix: "like-", name: "like", exclude: "like-songs" },
382431
{ prefix: "download-", name: "download" },
383432
];
384433
for (const item of prefixMap) {
434+
if (item.skipInLocalMode && !settingStore.useOnlineService) continue;
385435
if (routerName.startsWith(item.prefix) && (!item.exclude || routerName !== item.exclude)) {
386436
routerName = item.name;
387437
break;
388438
}
389439
}
390440
// 显示菜单
391441
menuRef.value?.showOption(routerName);
442+
// 本地模式下处理
443+
if (!settingStore.useOnlineService) {
444+
if (routerName === "local-songs" || routerName === "local-folders") {
445+
routerName = "local";
446+
}
447+
}
392448
// 高亮菜单
393449
switch (routerName) {
394450
case "playlist": {
@@ -424,6 +480,15 @@ const openHeartMode = debounce(() => player.toggleShuffle("heartbeat"), 1000, {
424480
trailing: false,
425481
});
426482
483+
// 本地模式下自动展开本地歌单
484+
onMounted(() => {
485+
if (!settingStore.useOnlineService && localPlaylistMenu.value.length > 0) {
486+
if (!settingStore.menuExpandedKeys.includes("local-playlists")) {
487+
settingStore.menuExpandedKeys.push("local-playlists");
488+
}
489+
}
490+
});
491+
427492
// 监听路由
428493
watch(
429494
() => [router.currentRoute.value, dataStore.userLikeData.playlists],

src/components/Layout/Nav.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<!-- 主内容 -->
1717
<n-flex class="nav-main">
1818
<!-- 搜索 -->
19-
<SearchInp />
19+
<SearchInp v-if="settingStore.useOnlineService" />
2020
<!-- 可拖拽 -->
2121
<div class="nav-drag" />
2222
<!-- 用户 -->

src/components/Menu/SongListMenu.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<script setup lang="ts">
1919
import type { SongType } from "@/types/main";
2020
import { NAlert, type DropdownOption } from "naive-ui";
21-
import { useStatusStore, useDataStore, useMusicStore } from "@/stores";
21+
import { useStatusStore, useDataStore, useMusicStore, useSettingStore } from "@/stores";
2222
import { useDownloadManager } from "@/core/resource/DownloadManager";
2323
import { renderIcon, copyData } from "@/utils/helper";
2424
import { deleteCloudSong, importCloudSong } from "@/api/cloud";
@@ -43,6 +43,7 @@ const statusStore = useStatusStore();
4343
4444
const player = usePlayerController();
4545
const downloadManager = useDownloadManager();
46+
const settingStore = useSettingStore();
4647
4748
// 右键菜单数据
4849
const dropdownX = ref<number>(0);
@@ -242,6 +243,7 @@ const openDropdown = (
242243
{
243244
key: "search",
244245
label: "同名搜索",
246+
show: settingStore.useOnlineService,
245247
props: {
246248
onClick: () => router.push({ name: "search", query: { keyword: song.name } }),
247249
},

src/components/Player/MainPlayer.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ const songMoreOptions = computed<DropdownOption[]>(() => {
282282
{
283283
key: "search",
284284
label: "同名搜索",
285+
show: settingStore.useOnlineService,
285286
props: {
286287
onClick: () => router.push({ name: "search", query: { keyword: song.name } }),
287288
},

src/components/Setting/GeneralSetting.vue

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,17 +290,19 @@
290290
<script setup lang="ts">
291291
import type { SelectOption } from "naive-ui";
292292
import { useDataStore, useMusicStore, useSettingStore, useStatusStore } from "@/stores";
293-
import { isDev, isElectron } from "@/utils/env";
293+
import { isElectron } from "@/utils/env";
294294
import { isEmpty } from "lodash-es";
295295
import themeColor from "@/assets/data/themeColor.json";
296296
import { openSidebarHideManager, openHomePageSectionManager, openFontManager } from "@/utils/modal";
297297
import { sendRegisterProtocol } from "@/utils/protocol";
298298
import { getCoverColor } from "@/utils/color";
299+
import { usePlayerController } from "@/core/player/PlayerController";
299300
300301
const dataStore = useDataStore();
301302
const musicStore = useMusicStore();
302303
const settingStore = useSettingStore();
303304
const statusStore = useStatusStore();
305+
const player = usePlayerController();
304306
305307
// 是否开启在线服务
306308
const useOnlineService = ref(settingStore.useOnlineService);
@@ -333,9 +335,11 @@ const modeChange = (val: boolean) => {
333335
content: "确定开启软件的在线服务?更改将在热重载后生效!",
334336
positiveText: "开启",
335337
negativeText: "取消",
336-
onPositiveClick: () => {
338+
onPositiveClick: async () => {
337339
useOnlineService.value = true;
338340
settingStore.useOnlineService = true;
341+
// 清空播放列表
342+
await player.cleanPlayList();
339343
// 清理播放数据
340344
dataStore.$reset();
341345
musicStore.$reset();
@@ -349,21 +353,22 @@ const modeChange = (val: boolean) => {
349353
} else {
350354
window.$dialog.warning({
351355
title: "关闭在线服务",
352-
content:
353-
"确定关闭软件的在线服务?将关闭包括搜索、登录、在线音乐播放等在内的全部在线服务,并且将会退出登录状态,软件将会变为本地播放器!更改将在重启后生效!",
356+
content: "确定关闭软件的在线服务?关闭后将只能播放本地音乐!更改将在热重载后生效!",
354357
positiveText: "关闭",
355358
negativeText: "取消",
356-
onPositiveClick: () => {
359+
onPositiveClick: async () => {
357360
useOnlineService.value = false;
358361
settingStore.useOnlineService = false;
362+
// 清空播放列表
363+
await player.cleanPlayList();
359364
// 清理播放数据
360365
dataStore.$reset();
361366
musicStore.$reset();
362367
// 清空本地数据
363368
localStorage.removeItem("data-store");
364369
localStorage.removeItem("music-store");
365-
// 重启
366-
if (!isDev) window.electron.ipcRenderer.send("win-restart");
370+
// 热重载
371+
window.location.reload();
367372
},
368373
onNegativeClick: () => {
369374
useOnlineService.value = true;

src/composables/List/useListScroll.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ export const useListScroll = () => {
77
/**
88
* 处理列表滚动
99
*/
10-
const handleListScroll = (e: Event) => {
11-
const scrollTop = (e.target as HTMLElement).scrollTop;
12-
listScrolling.value = scrollTop > 10;
13-
};
10+
const handleListScroll = useThrottleFn(
11+
(e: Event) => {
12+
const scrollTop = (e.target as HTMLElement).scrollTop;
13+
listScrolling.value = scrollTop > 10;
14+
},
15+
100,
16+
true,
17+
);
1418

1519
/**
1620
* 重置滚动状态

src/views/Local/albums.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,15 @@
4040
import type { SongType } from "@/types/main";
4141
import { useLocalStore } from "@/stores";
4242
import { some } from "lodash-es";
43+
import { usePlayerController } from "@/core/player/PlayerController";
4344
4445
const props = defineProps<{ data: SongType[] }>();
4546
4647
const localStore = useLocalStore();
48+
const player = usePlayerController();
49+
50+
// 播放事件总线
51+
const localPlayEventBus = useEventBus("local-play");
4752
4853
// 专辑数据
4954
const chooseAlbum = ref<string>("");
@@ -85,6 +90,13 @@ const handleRemoveSong = (ids: number[]) => {
8590
localStore.updateLocalSong(updatedSongs);
8691
};
8792
93+
// 监听播放事件
94+
const router = useRouter();
95+
localPlayEventBus.on(() => {
96+
if (router.currentRoute.value?.name !== "local-albums") return;
97+
player.updatePlayList(albumSongs.value);
98+
});
99+
88100
watch(
89101
() => chooseAlbum.value,
90102
(val) => {

src/views/Local/artists.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,16 @@
3131
import type { SongType } from "@/types/main";
3232
import { useLocalStore, useSettingStore } from "@/stores";
3333
import { isArray, some } from "lodash-es";
34+
import { usePlayerController } from "@/core/player/PlayerController";
3435
3536
const props = defineProps<{ data: SongType[] }>();
3637
3738
const localStore = useLocalStore();
3839
const settingStore = useSettingStore();
40+
const player = usePlayerController();
41+
42+
// 播放事件总线
43+
const localPlayEventBus = useEventBus("local-play");
3944
4045
// 歌手数据
4146
const chooseArtist = ref<string>("");
@@ -90,6 +95,13 @@ const handleRemoveSong = (ids: number[]) => {
9095
localStore.updateLocalSong(updatedSongs);
9196
};
9297
98+
// 监听播放事件
99+
const router = useRouter();
100+
localPlayEventBus.on(() => {
101+
if (router.currentRoute.value?.name !== "local-artists") return;
102+
player.updatePlayList(artistSongs.value);
103+
});
104+
93105
watch(
94106
() => chooseArtist.value,
95107
(val) => {

0 commit comments

Comments
 (0)