Skip to content

Commit a0935c7

Browse files
committed
feat: 歌曲右键 添加不喜欢功能以过滤每日推荐歌曲
1 parent 258828f commit a0935c7

File tree

6 files changed

+123
-27
lines changed

6 files changed

+123
-27
lines changed

src/i18n/lang/en-US/songItem.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,23 @@ export default {
66
addToPlaylist: 'Add to Playlist',
77
favorite: 'Like',
88
unfavorite: 'Unlike',
9-
removeFromPlaylist: 'Remove from Playlist'
9+
removeFromPlaylist: 'Remove from Playlist',
10+
dislike: 'Dislike',
11+
undislike: 'Undislike',
1012
},
1113
message: {
1214
downloading: 'Downloading, please wait...',
1315
downloadFailed: 'Download failed',
1416
downloadQueued: 'Added to download queue',
1517
addedToNextPlay: 'Added to play next',
1618
getUrlFailed: 'Failed to get music download URL, please check if logged in'
19+
},
20+
dialog: {
21+
dislike:{
22+
title: 'Dislike',
23+
content: 'Are you sure you want to dislike this song?',
24+
positiveText: 'Dislike',
25+
negativeText: 'Cancel'
26+
}
1727
}
1828
};

src/i18n/lang/zh-CN/songItem.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,23 @@ export default {
66
addToPlaylist: '添加到歌单',
77
favorite: '喜欢',
88
unfavorite: '取消喜欢',
9-
removeFromPlaylist: '从歌单中删除'
9+
removeFromPlaylist: '从歌单中删除',
10+
dislike: '不喜欢',
11+
undislike: '取消不喜欢',
1012
},
1113
message: {
1214
downloading: '正在下载中,请稍候...',
1315
downloadFailed: '下载失败',
1416
downloadQueued: '已加入下载队列',
1517
addedToNextPlay: '已添加到下一首播放',
1618
getUrlFailed: '获取音乐下载地址失败,请检查是否登录'
19+
},
20+
dialog: {
21+
dislike: {
22+
title: '提示!',
23+
content: '确认不喜欢这首歌吗?再次进入将从每日推荐中排除。',
24+
positiveText: '不喜欢',
25+
negativeText: '取消'
26+
}
1727
}
1828
};

src/renderer/components/common/SongItem.vue

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
<script lang="ts" setup>
135135
import { cloneDeep } from 'lodash';
136136
import type { MenuOption } from 'naive-ui';
137-
import { NEllipsis, NImage, useMessage } from 'naive-ui';
137+
import { NEllipsis, NImage, useMessage, useDialog } from 'naive-ui';
138138
import { computed, h, inject, ref, useTemplateRef } from 'vue';
139139
import { useI18n } from 'vue-i18n';
140140
@@ -307,7 +307,13 @@ const dropdownOptions = computed<MenuOption[]>(() => {
307307
h('i', {
308308
class: `iconfont ${isFavorite.value ? 'ri-heart-fill text-red-500' : 'ri-heart-line'}`
309309
})
310-
}
310+
},
311+
// 不喜欢
312+
{
313+
label: isDislike.value ? t('songItem.menu.undislike') : t('songItem.menu.dislike'),
314+
key: 'dislike',
315+
icon: () => h('i', { class: `iconfont ${isDislike.value ? 'ri-dislike-fill text-green-500': 'ri-dislike-line'}` })
316+
},
311317
];
312318
313319
if (props.canRemove) {
@@ -343,18 +349,30 @@ const handleMenuClick = (e: MouseEvent) => {
343349
344350
const handleSelect = (key: string | number) => {
345351
showDropdown.value = false;
346-
if (key === 'download') {
347-
downloadMusic();
348-
} else if (key === 'playNext') {
349-
handlePlayNext();
350-
} else if (key === 'addToPlaylist') {
351-
openPlaylistDrawer?.(props.item.id);
352-
} else if (key === 'favorite') {
353-
toggleFavorite(new Event('click'));
354-
} else if (key === 'play') {
355-
playMusicEvent(props.item);
356-
} else if (key === 'remove') {
357-
emits('remove-song', props.item.id);
352+
switch (key) {
353+
case 'download':
354+
downloadMusic();
355+
break;
356+
case 'playNext':
357+
handlePlayNext();
358+
break;
359+
case 'addToPlaylist':
360+
openPlaylistDrawer?.(props.item.id);
361+
break;
362+
case 'favorite':
363+
toggleFavorite(new Event('click'));
364+
break;
365+
case 'play':
366+
playMusicEvent(props.item);
367+
break;
368+
case 'remove':
369+
emits('remove-song', props.item.id);
370+
break;
371+
case 'dislike':
372+
toggleDislike(new Event('click'));
373+
break;
374+
default:
375+
break;
358376
}
359377
};
360378
@@ -463,6 +481,12 @@ const isFavorite = computed(() => {
463481
return playerStore.favoriteList.includes(numericId);
464482
});
465483
484+
const isDislike = computed(() => {
485+
// 将id转换为number,兼容B站视频ID
486+
const numericId = typeof props.item.id ==='string'? parseInt(props.item.id, 10) : props.item.id;
487+
return playerStore.dislikeList.includes(numericId);
488+
})
489+
466490
// 切换收藏状态
467491
const toggleFavorite = async (e: Event) => {
468492
e.stopPropagation();
@@ -475,6 +499,24 @@ const toggleFavorite = async (e: Event) => {
475499
playerStore.addToFavorite(numericId);
476500
}
477501
};
502+
const dialog = useDialog();
503+
const toggleDislike = async (e: Event) => {
504+
e.stopPropagation();
505+
if (isDislike.value) {
506+
playerStore.removeFromDislikeList(props.item.id);
507+
return;
508+
}
509+
dialog.warning({
510+
title: t('songItem.dialog.dislike.title'),
511+
content: t('songItem.dialog.dislike.content'),
512+
positiveText: t('songItem.dialog.dislike.positiveText'),
513+
negativeText: t('songItem.dialog.dislike.negativeText'),
514+
onPositiveClick: () => {
515+
playerStore.addToDislikeList(props.item.id);
516+
}
517+
});
518+
519+
}
478520
479521
// 切换选择状态
480522
const toggleSelect = () => {

src/renderer/components/home/TopBanner.vue

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
<div class="mt-2">
3333
<p
34-
v-for="item in dayRecommendData?.dailySongs.slice(0, 5)"
34+
v-for="item in getDisplayDaySongs.slice(0, 5)"
3535
:key="item.id"
3636
class="text-el"
3737
>
@@ -250,13 +250,16 @@ const loadArtistData = async () => {
250250
// 加载不需要登录的数据
251251
const loadNonUserData = async () => {
252252
try {
253-
254-
// 获取每日推荐
255-
try {
253+
// 获取每日推荐
254+
try {
256255
const {
257256
data: { data: dayRecommend }
258257
} = await getDayRecommend();
259-
dayRecommendData.value = dayRecommend as unknown as IDayRecommend;
258+
const dayRecommendSource = dayRecommend as unknown as IDayRecommend;
259+
dayRecommendData.value = {
260+
...dayRecommendSource,
261+
dailySongs: dayRecommendSource.dailySongs.filter((song: any) =>!playerStore.dislikeList.includes(song.id))
262+
};
260263
} catch (error) {
261264
console.error('获取每日推荐失败:', error);
262265
}
@@ -288,14 +291,20 @@ const loadUserData = async () => {
288291
const handleArtistClick = (id: number) => {
289292
navigateToArtist(id);
290293
};
294+
const getDisplayDaySongs = computed(() => {
295+
if(!dayRecommendData.value){
296+
return [];
297+
}
298+
return dayRecommendData.value.dailySongs.filter((song) => !playerStore.dislikeList.includes(song.id));
299+
})
291300
292301
const showDayRecommend = () => {
293302
if (!dayRecommendData.value?.dailySongs) return;
294303
295304
navigateToMusicList(router, {
296305
type: 'dailyRecommend',
297306
name: t('comp.recommendSinger.songlist'),
298-
songList: dayRecommendData.value.dailySongs,
307+
songList: getDisplayDaySongs.value,
299308
canRemove: false
300309
});
301310
};

src/renderer/store/modules/player.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ export const usePlayerStore = defineStore('player', () => {
388388
const playMode = ref(getLocalStorageItem('playMode', 0));
389389
const musicFull = ref(false);
390390
const favoriteList = ref<Array<number | string>>(getLocalStorageItem('favoriteList', []));
391+
const dislikeList = ref<Array<number | string>>(getLocalStorageItem('dislikeList', []));
391392
const savedPlayProgress = ref<number | undefined>();
392393
const showSleepTimer = ref(false); // 定时弹窗
393394
// 添加播放列表抽屉状态
@@ -1031,6 +1032,16 @@ export const usePlayerStore = defineStore('player', () => {
10311032
localStorage.setItem('favoriteList', JSON.stringify(favoriteList.value));
10321033
};
10331034

1035+
const addToDislikeList = (id: number | string) => {
1036+
dislikeList.value.push(id);
1037+
localStorage.setItem('dislikeList', JSON.stringify(dislikeList.value));
1038+
}
1039+
1040+
const removeFromDislikeList = (id: number | string) => {
1041+
dislikeList.value = dislikeList.value.filter(existingId => existingId!== id);
1042+
localStorage.setItem('dislikeList', JSON.stringify(dislikeList.value));
1043+
}
1044+
10341045
const removeFromPlayList = (id: number | string) => {
10351046
const index = playList.value.findIndex((item) => item.id === id);
10361047
if (index === -1) return;
@@ -1324,6 +1335,7 @@ export const usePlayerStore = defineStore('player', () => {
13241335
musicFull,
13251336
savedPlayProgress,
13261337
favoriteList,
1338+
dislikeList,
13271339
playListDrawerVisible,
13281340

13291341
// 定时关闭相关
@@ -1358,6 +1370,8 @@ export const usePlayerStore = defineStore('player', () => {
13581370
addToFavorite,
13591371
removeFromFavorite,
13601372
removeFromPlayList,
1373+
addToDislikeList,
1374+
removeFromDislikeList,
13611375
playAudio,
13621376
reparseCurrentSong,
13631377
setPlayListDrawerVisible,

src/renderer/views/music/MusicListPage.vue

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ onMounted(() => {
238238
});
239239
240240
// 从 pinia 或路由参数获取数据
241+
242+
// 从路由参数获取
243+
const routeId = route.params.id as string;
244+
const routeType = route.query.type as string;
245+
241246
const initData = () => {
242247
// 优先从 pinia 获取数据
243248
if (musicStore.currentMusicList) {
@@ -251,9 +256,7 @@ const initData = () => {
251256
return;
252257
}
253258
254-
// 从路由参数获取
255-
const routeId = route.params.id as string;
256-
const routeType = route.query.type as string;
259+
257260
258261
if (routeId) {
259262
// 这里根据 type 和 id 加载数据
@@ -323,14 +326,22 @@ const getCoverImgUrl = computed(() => {
323326
return '';
324327
});
325328
329+
const getDisplaySongs = computed(() => {
330+
if(routeType === 'dailyRecommend') {
331+
return displayedSongs.value.filter((song) => !playerStore.dislikeList.includes(song.id));
332+
}else {
333+
return displayedSongs.value;
334+
}
335+
})
336+
326337
// 过滤歌曲列表
327338
const filteredSongs = computed(() => {
328339
if (!searchKeyword.value) {
329-
return displayedSongs.value;
340+
return getDisplaySongs.value;
330341
}
331342
332343
const keyword = searchKeyword.value.toLowerCase().trim();
333-
return displayedSongs.value.filter((song) => {
344+
return getDisplaySongs.value.filter((song) => {
334345
const songName = song.name?.toLowerCase() || '';
335346
const albumName = song.al?.name?.toLowerCase() || '';
336347
const artists = song.ar || song.artists || [];

0 commit comments

Comments
 (0)