From 0b10f9553c3d717e1fc86c43a305dbeabec83b20 Mon Sep 17 00:00:00 2001 From: saopig1 <4x7sw862st@gmail.com> Date: Fri, 17 Jul 2026 01:29:00 +0800 Subject: [PATCH] feat(#119): saved queues web UI + behavior-settings toggles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Settings → 行为设置: two new toggles (保存/加载播放清单, 单曲直接播放不清空队列) that round-trip savedQueuesEnabled / playKeepsQueue and keep the nav gate in sync. - New "已存队列" page (/saved-queues): save the current queue (with a 共享 option), load (replace) / append / delete saved queues; renders a "feature disabled" state on 403 so it degrades gracefully when the flag is off. - Nav entry gated on the savedQueuesEnabled store flag (hidden for guests). - useSavedQueues API composable + a pure, unit-tested list/ownership helper. Co-Authored-By: Claude Fable 5 --- web/src/App.vue | 3 + web/src/components/Navbar.vue | 6 + web/src/composables/savedQueues.test.ts | 34 +++ web/src/composables/savedQueues.ts | 27 +++ web/src/composables/useSavedQueues.ts | 52 ++++ web/src/router/index.ts | 1 + web/src/stores/player.ts | 16 ++ web/src/views/SavedQueues.vue | 301 ++++++++++++++++++++++++ web/src/views/Settings.vue | 48 ++++ 9 files changed, 488 insertions(+) create mode 100644 web/src/composables/savedQueues.test.ts create mode 100644 web/src/composables/savedQueues.ts create mode 100644 web/src/composables/useSavedQueues.ts create mode 100644 web/src/views/SavedQueues.vue diff --git a/web/src/App.vue b/web/src/App.vue index ea8c0e9..17cced8 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -166,6 +166,9 @@ onMounted(async () => { // Search or Playlist render hearts correctly without first visiting Home. // (fire-and-forget; fetchFavorites swallows the 401 when not yet logged in.) playerStore.fetchFavorites(); + // Non-critical: reads savedQueuesEnabled so the nav entry can show/hide. + // Guests get a 403 (swallowed) → the entry stays hidden for them. + if (!session.isGuest.value) playerStore.fetchBotSettings(); syncTimer = setInterval(() => playerStore.syncElapsed(), 3000); mobileRaf = requestAnimationFrame(updateMobileProgress); // Reconcile the dedicated-link scope only after the bot list is known: the diff --git a/web/src/components/Navbar.vue b/web/src/components/Navbar.vue index 67bbc85..28f9b19 100644 --- a/web/src/components/Navbar.vue +++ b/web/src/components/Navbar.vue @@ -7,6 +7,12 @@ 搜索 音乐库 播放历史 + 已存队列