From 68f29c8ea8f958b58ca8216c329eebb31a8bbdbd Mon Sep 17 00:00:00 2001 From: Atdunbg Date: Fri, 29 May 2026 21:13:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8B=86=E5=88=86=20App.vue=20?= =?UTF-8?q?=E4=B8=BA=E7=8B=AC=E7=AB=8B=E7=BB=84=E4=BB=B6=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=A4=9A=E9=A1=B9=E6=95=B7=E8=A1=8D=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 提取 TitleBar、Sidebar、RoamDrawer、CloseModal 四个组件 - App.vue 从 676 行精简至 238 行,职责更清晰 - 修复评论点赞无限+1:改为基于服务端 liked 字段切换 - 修复评论点赞无防重复:添加 likingSet 锁 - 修复评论点赞用本地缓存:likedIds 改为从服务端 likelist API 同步 - 删除 likedIds 写 localStorage 的 watch - 播放失败/FM加载失败/减少推荐失败添加 showToast 用户提示 - 抽屉遮罩下标题栏按钮保持原色(z-10 提升至遮罩之上) --- src/App.vue | 458 ++---------------------------- src/components/CloseModal.vue | 69 +++++ src/components/CommentSection.vue | 40 ++- src/components/RoamDrawer.vue | 245 ++++++++++++++++ src/components/Sidebar.vue | 184 ++++++++++++ src/components/TitleBar.vue | 43 +++ src/stores/player.ts | 23 +- 7 files changed, 594 insertions(+), 468 deletions(-) create mode 100644 src/components/CloseModal.vue create mode 100644 src/components/RoamDrawer.vue create mode 100644 src/components/Sidebar.vue create mode 100644 src/components/TitleBar.vue diff --git a/src/App.vue b/src/App.vue index e0c4ba6..0a3b1ef 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,130 +1,9 @@ - - diff --git a/src/components/CloseModal.vue b/src/components/CloseModal.vue new file mode 100644 index 0000000..6c4defe --- /dev/null +++ b/src/components/CloseModal.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/components/CommentSection.vue b/src/components/CommentSection.vue index f477046..c32394d 100644 --- a/src/components/CommentSection.vue +++ b/src/components/CommentSection.vue @@ -1,32 +1,34 @@ @@ -47,6 +49,7 @@ import IconHeart from '~icons/lucide/heart' const props = defineProps<{ type: number id: number + darkMode?: boolean }>() const comments = ref([]) @@ -104,22 +107,29 @@ function loadMore() { fetchComments() } +const likingSet = ref(new Set()) + async function likeComment(cid: number) { + if (likingSet.value.has(cid)) return + const target = comments.value.find(c => c.commentId === cid) + if (!target) return + const liked = !!target.liked + likingSet.value.add(cid) try { await invoke('comment_like', { query: { - t: 1, + t: liked ? 0 : 1, type: props.type, id: props.id, cid } }) - const target = comments.value.find(c => c.commentId === cid) - if (target) { - target.likedCount++ - } + target.liked = !liked + target.likedCount += liked ? -1 : 1 } catch (e) { console.error(e) + } finally { + likingSet.value.delete(cid) } } diff --git a/src/components/RoamDrawer.vue b/src/components/RoamDrawer.vue new file mode 100644 index 0000000..08920e2 --- /dev/null +++ b/src/components/RoamDrawer.vue @@ -0,0 +1,245 @@ + + + + + diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue new file mode 100644 index 0000000..233dfb1 --- /dev/null +++ b/src/components/Sidebar.vue @@ -0,0 +1,184 @@ + + + diff --git a/src/components/TitleBar.vue b/src/components/TitleBar.vue new file mode 100644 index 0000000..bf25087 --- /dev/null +++ b/src/components/TitleBar.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/stores/player.ts b/src/stores/player.ts index bfc20be..6b57363 100644 --- a/src/stores/player.ts +++ b/src/stores/player.ts @@ -20,14 +20,6 @@ function loadRecentLocal(): Song[] { return []; } -function loadLikedIdsFromStorage(): Set { - try { - const raw = localStorage.getItem('liked_ids'); - if (raw) return new Set(JSON.parse(raw)); - } catch { /* 忽略 */ } - return new Set(); -} - export const usePlayerStore = defineStore('player', () => { const currentSong = ref(null); const playing = ref(false); @@ -53,7 +45,7 @@ export const usePlayerStore = defineStore('player', () => { const recentLocal = ref(loadRecentLocal()); const MAX_RECENT = 200; - const likedIds = ref>(loadLikedIdsFromStorage()); + const likedIds = ref>(new Set()); function emitPlaybackState() { const song = currentSong.value; @@ -82,7 +74,9 @@ export const usePlayerStore = defineStore('player', () => { const data = JSON.parse(json); const ids: number[] = data.ids || data.data?.ids || []; likedIds.value = new Set(ids); - } catch { /* 忽略 */ } + } catch (e) { + console.error('加载喜欢列表失败', e); + } } async function toggleLike(songId: number) { @@ -111,10 +105,6 @@ export const usePlayerStore = defineStore('player', () => { localStorage.setItem('recent_local', JSON.stringify(val)); }, { deep: true }); - watch(likedIds, (val) => { - localStorage.setItem('liked_ids', JSON.stringify([...val])); - }, { deep: true }); - const isFmMode = ref(false); const fmQueue: Song[] = []; let fmNextCallback: (() => void) | null = null; @@ -171,6 +161,7 @@ export const usePlayerStore = defineStore('player', () => { await invoke('fm_trash', { query: { id: songId, time: 25 } }); } catch (e) { console.error('fm_trash 失败', e); + showToast('减少推荐失败', 'error'); } await nextFm(); } @@ -254,6 +245,7 @@ export const usePlayerStore = defineStore('player', () => { } catch (e) { console.error('FM播放失败', e); playing.value = false; + showToast('FM 播放失败', 'error'); if (fmNextCallback) { fmNextCallback(); } else { @@ -373,6 +365,7 @@ export const usePlayerStore = defineStore('player', () => { } catch (e) { console.error('播放失败', e); playing.value = false; + showToast('播放失败,请稍后重试', 'error'); } } @@ -576,6 +569,7 @@ export const usePlayerStore = defineStore('player', () => { } } catch (e) { console.error(e); + showToast('FM 加载失败', 'error'); } return false; } @@ -600,6 +594,7 @@ async function loadFm() { } } catch (e) { console.error('FM加载失败', e); + showToast('FM 加载失败', 'error'); } }