🦄 refactor: 重构代码将 Vuex替换为 Pinia

集成 Pinia 状态管理
This commit is contained in:
alger
2025-03-19 22:48:28 +08:00
parent 4fa5ed0ca6
commit e355341596
40 changed files with 1170 additions and 494 deletions
+7 -36
View File
@@ -1,11 +1,10 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted } from 'vue';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { isElectron } from '@/utils';
import { useSettingsStore } from '@/store/modules/settings';
const store = useStore();
const settingsStore = useSettingsStore();
const { locale } = useI18n();
const languages = [
@@ -13,40 +12,12 @@ const languages = [
{ label: 'English', value: 'en-US' }
];
console.log('locale', locale);
// 使用计算属性来获取当前语言
const currentLanguage = computed({
get: () => store.state.setData.language || 'zh-CN',
set: (value: string) => {
handleLanguageChange(value);
}
});
// 当语言改变时的处理函数
const handleLanguageChange = (value: string) => {
// 更新 i18n locale
locale.value = value;
// 通过 mutation 更新 store
store.commit('setLanguage', value);
// 通知主进程语言已更改
if (isElectron) {
window.electron.ipcRenderer.send('change-language', value);
}
};
// 监听来自主进程的语言切换事件
const handleSetLanguage = (_: any, value: string) => {
handleLanguageChange(value);
};
onMounted(() => {
if (isElectron) {
window.electron.ipcRenderer.on('set-language', handleSetLanguage);
}
});
onUnmounted(() => {
if (isElectron) {
window.electron.ipcRenderer.removeListener('set-language', handleSetLanguage);
get: () => locale.value,
set: (value) => {
settingsStore.setLanguage(value);
}
});
</script>
+4 -4
View File
@@ -87,16 +87,16 @@
<script setup lang="ts">
import { computed, onUnmounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { getMusicDetail } from '@/api/music';
import SongItem from '@/components/common/SongItem.vue';
import { usePlayerStore } from '@/store/modules/player';
import { getImgUrl, isMobile, setAnimationClass, setAnimationDelay } from '@/utils';
import PlayBottom from './common/PlayBottom.vue';
const { t } = useI18n();
const store = useStore();
const playerStore = usePlayerStore();
const props = withDefaults(
defineProps<{
@@ -236,13 +236,13 @@ const loadFullPlaylist = async () => {
// 处理播放
const handlePlay = async () => {
// 先使用当前已加载的歌曲开始播放
store.commit('setPlayList', displayedSongs.value.map(formatSong));
playerStore.setPlayList(displayedSongs.value.map(formatSong));
// 在后台加载完整播放列表
loadFullPlaylist().then(() => {
// 加载完成后,更新播放列表为完整列表
if (completePlaylist.value.length > 0) {
store.commit('setPlayList', completePlaylist.value.map(formatSong));
playerStore.setPlayList(completePlaylist.value.map(formatSong));
}
});
};
+9 -5
View File
@@ -191,9 +191,9 @@
import { NButton, NIcon, NSlider, NTooltip } from 'naive-ui';
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { getMvUrl } from '@/api/mv';
import { usePlayerStore } from '@/store/modules/player';
import { IMvItem } from '@/type/mv';
const { t } = useI18n();
@@ -222,7 +222,7 @@ const emit = defineEmits<{
(e: 'prev', loading: (value: boolean) => void): void;
}>();
const store = useStore();
const playerStore = usePlayerStore();
const mvUrl = ref<string>();
const playMode = ref<PlayMode>(PLAY_MODE.Auto);
@@ -359,8 +359,8 @@ const loadMvUrl = async (mv: IMvItem) => {
const handleClose = () => {
emit('update:show', false);
if (store.state.playMusicUrl) {
store.commit('setIsPlay', true);
if (playerStore.playMusicUrl) {
playerStore.setIsPlay(true);
}
};
@@ -543,7 +543,11 @@ watch(showControls, (newValue) => {
}
});
const isMobile = computed(() => store.state.isMobile);
const isMobile = computed(() => false); // TODO: 从 settings store 获取
const handlePlay = () => {
playerStore.setIsPlay(true);
};
</script>
<style scoped lang="scss">
@@ -90,14 +90,14 @@
<script setup lang="ts">
import { useDateFormat } from '@vueuse/core';
import { ref, watch } from 'vue';
import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { getArtistAlbums, getArtistDetail, getArtistTopSongs } from '@/api/artist';
import { getMusicDetail } from '@/api/music';
import SearchItem from '@/components/common/SearchItem.vue';
import SongItem from '@/components/common/SongItem.vue';
import { usePlayerStore, useSettingsStore } from '@/store';
import { IArtist } from '@/type/artist';
import { getImgUrl } from '@/utils';
@@ -105,11 +105,17 @@ import PlayBottom from './PlayBottom.vue';
const { t } = useI18n();
const settingsStore = useSettingsStore();
const playerStore = usePlayerStore();
const currentArtistId = computed({
get: () => settingsStore.currentArtistId,
set: (val) => settingsStore.setCurrentArtistId(val as number)
});
const modelValue = defineModel<boolean>('show', { required: true });
const store = useStore();
const activeTab = ref('songs');
const currentArtistId = ref<number>();
// 歌手信息
const artistInfo = ref<IArtist>();
@@ -134,7 +140,7 @@ const albumPage = ref({
});
watch(modelValue, (newVal) => {
store.commit('setShowArtistDrawer', newVal);
settingsStore.setShowArtistDrawer(newVal);
});
const loading = ref(false);
// 加载歌手信息
@@ -260,8 +266,7 @@ const formatPublishTime = (time: number) => {
};
const handlePlay = () => {
store.commit(
'setPlayList',
playerStore.setPlayList(
songs.value.map((item) => ({
...item,
picUrl: item.al.picUrl
@@ -1,7 +1,7 @@
<template>
<div class="download-drawer-trigger">
<n-badge :value="downloadingCount" :max="99" :show="downloadingCount > 0">
<n-button circle @click="store.commit('setShowDownloadDrawer', true)">
<n-button circle @click="settingsStore.showDownloadDrawer = true">
<template #icon>
<i class="iconfont ri-download-cloud-2-line"></i>
</template>
@@ -179,9 +179,10 @@ import type { ProgressStatus } from 'naive-ui';
import { useMessage } from 'naive-ui';
import { computed, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { getMusicDetail } from '@/api/music';
import { usePlayerStore } from '@/store/modules/player';
import { useSettingsStore } from '@/store/modules/settings';
// import { audioService } from '@/services/audioService';
import { getImgUrl } from '@/utils';
@@ -208,11 +209,14 @@ interface DownloadedItem {
}
const message = useMessage();
const store = useStore();
const playerStore = usePlayerStore();
const settingsStore = useSettingsStore();
const showDrawer = computed({
get: () => store.state.showDownloadDrawer,
set: (val) => store.commit('setShowDownloadDrawer', val)
get: () => settingsStore.showDownloadDrawer,
set: (val) => {
settingsStore.showDownloadDrawer = val;
}
});
const downloadList = ref<DownloadItem[]>([]);
@@ -224,10 +228,6 @@ const downList = computed(() => {
return (downloadedList.value as DownloadedItem[]).reverse();
});
// 获取播放状态
// const play = computed(() => store.state.play as boolean);
// const currentMusic = computed(() => store.state.playMusic);
// 计算下载中的任务数量
const downloadingCount = computed(() => {
return downloadList.value.filter((item) => item.status === 'downloading').length;
@@ -343,51 +343,11 @@ const confirmDelete = async () => {
};
// 播放音乐
// const handlePlayMusic = async (item: DownloadedItem) => {
// // 确保路径正确编码
// const encodedPath = encodeURIComponent(item.path);
// const localUrl = `local://${encodedPath}`;
// const musicInfo = {
// name: item.filename,
// id: item.id,
// url: localUrl,
// playMusicUrl: localUrl,
// picUrl: item.picUrl,
// ar: item.ar || [{ name: '本地音乐' }],
// song: {
// artists: item.ar || [{ name: '本地音乐' }]
// },
// al: {
// picUrl: item.picUrl || '/images/default_cover.png'
// }
// };
// // 如果是当前播放的音乐,则切换播放状态
// if (currentMusic.value?.id === item.id) {
// if (play.value) {
// audioService.getCurrentSound()?.pause();
// store.commit('setPlayMusic', false);
// } else {
// audioService.getCurrentSound()?.play();
// store.commit('setPlayMusic', true);
// }
// return;
// }
// // 播放新的音乐
// store.commit('setPlay', musicInfo);
// store.commit('setPlayMusic', true);
// store.commit('setIsPlay', true);
// store.commit(
// 'setPlayList',
// downloadedList.value.map((item) => ({
// ...item,
// playMusicUrl: `local://${encodeURIComponent(item.path)}`
// }))
// );
// };
const handlePlay = async (musicInfo: SongResult) => {
await playerStore.setPlay(musicInfo);
playerStore.setPlayMusic(true);
playerStore.setIsPlay(true);
};
// 获取已下载音乐列表
const refreshDownloadedList = async () => {
@@ -522,7 +482,7 @@ onMounted(() => {
});
const handleDrawerClose = () => {
store.commit('setShowDownloadDrawer', false);
settingsStore.showDownloadDrawer = false;
};
</script>
@@ -3,10 +3,13 @@
</template>
<script setup lang="ts">
import { useStore } from 'vuex';
import { computed } from 'vue';
import { usePlayerStore } from '@/store/modules/player';
const playerStore = usePlayerStore();
const isPlay = computed(() => playerStore.isPlay);
const store = useStore();
const isPlay = computed(() => store.state.isPlay as boolean);
defineProps({
height: {
type: String,
@@ -110,12 +110,13 @@
import { useMessage } from 'naive-ui';
import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { createPlaylist, updatePlaylistTracks } from '@/api/music';
import { getUserPlaylist } from '@/api/user';
import { useUserStore } from '@/store';
import { getImgUrl } from '@/utils';
const store = useUserStore();
const { t } = useI18n();
const props = defineProps<{
modelValue: boolean;
@@ -127,7 +128,6 @@ const emit = defineEmits(['update:modelValue']);
const message = useMessage();
const playlists = ref<any[]>([]);
const creating = ref(false);
const store = useStore();
const isCreating = ref(false);
const formValue = ref({
@@ -151,7 +151,7 @@ const toggleCreateForm = () => {
// 获取用户歌单
const fetchUserPlaylists = async () => {
try {
const { user } = store.state;
const { user } = store;
if (!user?.userId) {
message.error(t('comp.playlistDrawer.loginFirst'));
emit('update:modelValue', false);
+12 -8
View File
@@ -40,11 +40,10 @@
</template>
<script setup lang="ts">
import { useStore } from 'vuex';
import { getAlbum, getListDetail } from '@/api/list';
import MvPlayer from '@/components/MvPlayer.vue';
import { audioService } from '@/services/audioService';
import { usePlayerStore } from '@/store/modules/player';
import { IMvItem } from '@/type/mv';
import { getImgUrl } from '@/utils';
@@ -72,6 +71,8 @@ const songList = ref<any[]>([]);
const showPop = ref(false);
const listInfo = ref<any>(null);
const playerStore = usePlayerStore();
const getCurrentMv = () => {
return {
id: props.item.id,
@@ -79,8 +80,6 @@ const getCurrentMv = () => {
} as unknown as IMvItem;
};
const store = useStore();
const handleClick = async () => {
listInfo.value = null;
if (props.item.type === '专辑') {
@@ -108,12 +107,17 @@ const handleClick = async () => {
}
if (props.item.type === 'mv') {
store.commit('setIsPlay', false);
store.commit('setPlayMusic', false);
audioService.getCurrentSound()?.pause();
showPop.value = true;
handleShowMv(getCurrentMv());
}
};
const handleShowMv = async (item: IMvItem) => {
playerStore.setIsPlay(false);
playerStore.setPlayMusic(false);
audioService.getCurrentSound()?.pause();
showPop.value = true;
currentMv.value = item;
};
</script>
<style scoped lang="scss">
+15 -13
View File
@@ -90,10 +90,10 @@ import type { MenuOption } from 'naive-ui';
import { NImage, NText, useMessage } from 'naive-ui';
import { computed, h, inject, ref, useTemplateRef } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { getSongUrl } from '@/hooks/MusicListHook';
import { audioService } from '@/services/audioService';
import { usePlayerStore, useSettingsStore } from '@/store';
import type { SongResult } from '@/type/music';
import { getImgUrl, isElectron } from '@/utils';
import { getImageBackground } from '@/utils/linearColor';
@@ -120,11 +120,13 @@ const props = withDefaults(
}
);
const store = useStore();
const playerStore = usePlayerStore();
const settingsStore = useSettingsStore();
const message = useMessage();
const play = computed(() => store.state.play as boolean);
const playMusic = computed(() => store.state.playMusic);
const play = computed(() => playerStore.isPlay);
const playMusic = computed(() => playerStore.playMusic);
const playLoading = computed(
() => playMusic.value.id === props.item.id && playMusic.value.playLoading
);
@@ -356,31 +358,31 @@ const imageLoad = async () => {
const playMusicEvent = async (item: SongResult) => {
if (playMusic.value.id === item.id) {
if (play.value) {
store.commit('setPlayMusic', false);
playerStore.setPlayMusic(false);
audioService.getCurrentSound()?.pause();
} else {
store.commit('setPlayMusic', true);
playerStore.setPlayMusic(true);
audioService.getCurrentSound()?.play();
}
return;
}
await store.commit('setPlay', item);
store.commit('setIsPlay', true);
await playerStore.setPlay(item);
playerStore.isPlay = true;
emits('play', item);
};
// 判断是否已收藏
const isFavorite = computed(() => {
return store.state.favoriteList.includes(props.item.id);
return playerStore.favoriteList.includes(props.item.id);
});
// 切换收藏状态
const toggleFavorite = async (e: Event) => {
e.stopPropagation();
if (isFavorite.value) {
store.commit('removeFromFavorite', props.item.id);
playerStore.removeFromFavorite(props.item.id);
} else {
store.commit('addToFavorite', props.item.id);
playerStore.addToFavorite(props.item.id);
}
};
@@ -390,7 +392,7 @@ const toggleSelect = () => {
};
const handleArtistClick = (id: number) => {
store.commit('setCurrentArtistId', id);
settingsStore.currentArtistId = id;
};
// 获取歌手列表(最多显示5个)
@@ -400,7 +402,7 @@ const artists = computed(() => {
// 添加到下一首播放
const handlePlayNext = () => {
store.commit('addToNextPlay', props.item);
playerStore.addToNextPlay(props.item);
message.success(t('songItem.message.addedToNextPlay'));
};
</script>
+8 -24
View File
@@ -73,8 +73,8 @@
import { marked } from 'marked';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { useSettingsStore } from '@/store/modules/settings';
import { checkUpdate, getProxyNodes, UpdateResult } from '@/utils/update';
import config from '../../../../package.json';
@@ -87,7 +87,13 @@ marked.setOptions({
gfm: true // 启用 GitHub 风格的 Markdown
});
const showModal = ref(false);
const settingsStore = useSettingsStore();
const showModal = computed({
get: () => settingsStore.showUpdateModal,
set: (val) => settingsStore.setShowUpdateModal(val)
});
const updateInfo = ref<UpdateResult>({
hasUpdate: false,
latestVersion: '',
@@ -95,28 +101,6 @@ const updateInfo = ref<UpdateResult>({
releaseInfo: null
});
const store = useStore();
// 添加计算属性
const showUpdateModalState = computed({
get: () => store.state.showUpdateModal,
set: (val) => store.commit('setShowUpdateModal', val)
});
// 替换原来的 watch
watch(showUpdateModalState, (newVal) => {
if (newVal) {
showModal.value = true;
}
});
watch(
() => showModal.value,
(newVal) => {
showUpdateModalState.value = newVal;
}
);
// 解析 Markdown
const parsedReleaseNotes = computed(() => {
if (!updateInfo.value.releaseInfo?.body) return '';
@@ -24,15 +24,15 @@
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { getRecommendMusic } from '@/api/home';
import SongItem from '@/components/common/SongItem.vue';
import { usePlayerStore } from '@/store/modules/player';
import type { IRecommendMusic } from '@/type/music';
import { setAnimationClass, setAnimationDelay } from '@/utils';
const { t } = useI18n();
const store = useStore();
const playerStore = usePlayerStore();
// 推荐歌曲
const recommendMusic = ref<IRecommendMusic>();
const loading = ref(false);
@@ -51,7 +51,9 @@ onMounted(() => {
});
const handlePlay = () => {
store.commit('setPlayList', recommendMusic.value?.result);
if (recommendMusic.value?.result) {
playerStore.setPlayList(recommendMusic.value.result);
}
};
</script>