feat: 完善首页#20
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
该 PR 主要围绕“完善首页”展开:重构首页为可落地的内容聚合页(头部问候/统计、Hero 推荐、快捷入口、发现区块等),并补齐与之配套的能力(每日推荐页、心动模式、播放/收藏统计、随机本地曲库抽取、搜索快捷键、若干 UI 组件增强)。
Changes:
- 重构首页信息架构:新增首页头部/hero/继续聆听/发现区块等 composables,并接入每日推荐与本地随机内容。
- 新增「每日推荐」页面与路由,同时在 data store 引入按天归档缓存(IndexedDB)。
- 新增“心动模式”、播放/收藏统计链路(renderer 采集 → preload API → 主进程 IPC → SQLite 落库/聚合),并补齐随机抽歌与搜索快捷键等交互。
Reviewed changes
Copilot reviewed 67 out of 71 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/navigate.ts | 精简跳转歌单页注释说明。 |
| src/stores/status.ts | 新增 searchOpen/heartMode 状态并持久化 heartMode。 |
| src/stores/queue.ts | 新增批量插入队列 API(一次性切片+落盘)。 |
| src/stores/history.ts | load 改为并发复用 Promise;record 改为 async 并确保先 load。 |
| src/stores/data.ts | 新增每日推荐归档缓存、今日/历史暴露与 ensureDailyRecommend。 |
| src/router/index.ts | 新增 /daily 路由页面。 |
| src/pages/Streaming/Artists.vue | CoverList 歌手卡最小尺寸调整。 |
| src/pages/Search.vue | CoverList 歌手卡最小尺寸调整。 |
| src/pages/Liked.vue | 未登录态 UI 简化,移除跳转登录按钮逻辑。 |
| src/pages/Home.vue | 首页整体重构:头部、Hero、快捷入口、继续聆听、发现区块等。 |
| src/pages/Favorites.vue | CoverList min-size 按 tab 动态调整。 |
| src/pages/Daily.vue | 新增每日推荐页:今日/历史切换、刷新、批量管理入口。 |
| src/pages/Cloud.vue | 未登录态 UI 简化,移除跳转登录按钮逻辑。 |
| src/i18n/locales/zh-CN.json | 新增 home/daily/heartMode/hotkey 文案,清理未使用 key。 |
| src/i18n/locales/en-US.json | 同步新增 home/daily/heartMode/hotkey 文案,清理未使用 key。 |
| src/core/player/stats.ts | 新增播放统计采集器(会话计时、track ended 结算、beforeunload 刷盘)。 |
| src/core/player/index.ts | 接入播放统计、心动模式播放入口、批量插入队列、心动模式下禁用洗牌切换。 |
| src/core/player/events.ts | ended 分支结算播放统计,并避免重复调用 autoClose.onTrackEnded。 |
| src/core/hotkey/registry.ts | 新增 view.openSearch 动作处理(打开搜索弹窗)。 |
| src/composables/useMultiSelect.ts | “添加到队列”改为批量插入以降低卡顿。 |
| src/composables/useHeartMode.ts | 新增心动模式入口(登录校验、取种子、拉智能列表、切入播放)。 |
| src/composables/useFloatingPlayerBar.ts | 新增悬浮播放栏状态与底部留白常量。 |
| src/composables/useFavorite.ts | 收藏/取消收藏时记录统计事件(favorite_history)。 |
| src/composables/home/useQuickActions.ts | 新增首页快捷入口(手气/日推/心动/FM 占位)。 |
| src/composables/home/useHomeHeader.ts | 新增首页头部问候语、副标题候选池、统计摘要展示。 |
| src/composables/home/useHomeDiscover.ts | 新增首页发现区块聚合拉取与 30min 模块级缓存。 |
| src/composables/home/useDailyRecommend.ts | 新增首页 Hero 来源(daily/liked/local)与播放/入队操作。 |
| src/composables/home/useContinueListening.ts | 新增“反复聆听/继续聆听”区块(top tracks + 阈值标题)。 |
| src/components/ui/SMenu.vue | 菜单项新增 trailing 行尾自定义渲染。 |
| src/components/ui/SImg.vue | 容器增加 isolate 以优化层叠/滤镜隔离。 |
| src/components/ui/SCard.vue | 新增 radius/flush,hoverable 增强,样式调整。 |
| src/components/ui/SButton.vue | variantClass 对非法 type 兜底到 default。 |
| src/components/player/PlayerControls.vue | 洗牌键与心动模式退出复用同一入口,并更新图标逻辑。 |
| src/components/player/Lyrics/renderer.css | 移除部分 backface-visibility/filter 常驻,调整合成策略。 |
| src/components/player/Lyrics/index.vue | 移除调试 log。 |
| src/components/player/Lyrics/engine/index.ts | blur/filter 仅在需要时挂载;补充动画清理触发条件。 |
| src/components/player/FullPlayer/PlayerBackground.vue | 背景模糊由 backdrop-filter 改为图片 filter。 |
| src/components/player/FullPlayer/index.vue | 同步心动模式/洗牌按钮图标与行为。 |
| src/components/list/SongList.vue | 悬浮播放栏下增大虚拟列表底部 padding。 |
| src/components/list/CoverList.vue | 支持非虚拟网格模式;虚拟模式底部 padding 适配悬浮播放栏;拆出 CoverCard。 |
| src/components/list/CoverCard.vue | 新增封面卡组件复用封面/信息渲染。 |
| src/components/layout/SideBar.vue | “喜欢”菜单项增加 trailing 心动模式按钮入口。 |
| src/components/layout/NavSearch.vue | 搜索弹窗开关迁移到 status.searchOpen(支持快捷键打开)。 |
| src/assets/icons/play-order.svg | 新增播放顺序图标资源。 |
| src/assets/icons/heart-mode.svg | 新增心动模式图标资源。 |
| src/apis/recommend/netease.ts | 新增日推/心动模式/首页发现区块请求封装与 CoverItem 转换。 |
| shared/types/stats.ts | 新增 StatsApi 及播放/收藏统计相关类型。 |
| shared/types/library.ts | LibraryApi 增加随机取歌接口声明。 |
| shared/types/hotkey.ts | HotkeyActionId 增加 view.openSearch。 |
| shared/defaults/hotkeys.ts | 新增默认快捷键 Ctrl/Cmd+F 打开搜索。 |
| index.html | 启动页字体声明格式化。 |
| electron/preload/index.ts | 暴露 stats API 与 library 随机取歌 IPC。 |
| electron/preload/index.d.ts | window.api 增加 stats 类型声明。 |
| electron/main/window/main.ts | thumbar 初始化时机改为 did-finish-load。 |
| electron/main/services/thumbar.ts | 窗口 show 时重新下发任务栏按钮,closed 时清理监听。 |
| electron/main/ipc/stats.ts | 新增 stats IPC(recordPlay/recordFavorite/getStatsSummary/getTopTracks)。 |
| electron/main/ipc/player.ts | 元数据下发增加 coverUrl;远端封面拉取逻辑整理。 |
| electron/main/ipc/library.ts | 新增随机取歌 IPC handler。 |
| electron/main/ipc/index.ts | 注册 stats IPC。 |
| electron/main/database/queries.ts | 新增随机取歌 SQL 查询。 |
| electron/main/database/playStats.ts | 新增播放/收藏统计写入与聚合查询实现。 |
| electron/main/database/index.ts | 新增 isDbOpen;初始化时建 play_history/favorite_history 表与索引。 |
| electron/main/apis/netease/modules/top_artists.ts | 新增热门歌手模块。 |
| electron/main/apis/netease/modules/recommend_songs.ts | 新增每日推荐歌曲模块。 |
| electron/main/apis/netease/modules/recommend_resource.ts | 新增每日推荐/专属歌单模块。 |
| electron/main/apis/netease/modules/playmode_intelligence.ts | 新增心动模式/智能播放模块。 |
| electron/main/apis/netease/modules/personalized.ts | 新增通用推荐歌单模块。 |
| electron/main/apis/netease/modules/index.ts | 聚合新增的 netease modules。 |
| electron/main/apis/netease/modules/album_new.ts | 新增新碟上架模块。 |
| electron/main/apis/netease/index.ts | 将 playmode_intelligence 加入不可缓存集合。 |
| components.d.ts | 注册新增组件与图标的自动类型声明。 |
Comment on lines
+600
to
+609
| export const insertManyToQueue = (items: readonly Track[]): number => { | ||
| if (items.length === 0) return 0; | ||
| const status = useStatusStore(); | ||
| const seen = new Set(queue.queue.value.map((track) => track.id)); | ||
| const fresh: Track[] = []; | ||
| for (const item of items) { | ||
| if (seen.has(item.id)) continue; | ||
| seen.add(item.id); | ||
| fresh.push(item); | ||
| } |
Comment on lines
+46
to
+52
| /** 当前选中的天键 */ | ||
| const selectedKey = ref("today"); | ||
|
|
||
| /** 当前选中的天,选不中时回落到首项 */ | ||
| const selectedDay = computed<DayView | null>( | ||
| () => days.value.find((day) => day.key === selectedKey.value) ?? days.value[0] ?? null, | ||
| ); |
Comment on lines
+6
to
+12
| /** 每日推荐归档 IndexedDB 缓存键 */ | ||
| const DAILY_RECOMMEND_KEY = "daily-recommend-archive"; | ||
| /** 每日推荐归档保留天数 */ | ||
| const MAX_DAILY_ARCHIVE = 14; | ||
|
|
||
| const cacheDb = localforage.createInstance({ name: "splayer", storeName: "data-cache" }); | ||
|
|
Comment on lines
+67
to
+80
| /** 随机取一首曲目,库为空时返回 null */ | ||
| export const getRandomTrack = (): Track | null => { | ||
| const row = getDb().prepare("SELECT * FROM tracks ORDER BY RANDOM() LIMIT 1").get() as | ||
| | TrackRow | ||
| | undefined; | ||
| return row ? rowToTrack(row) : null; | ||
| }; | ||
|
|
||
| /** 随机取多首曲目 */ | ||
| export const getRandomTracks = (limit: number): Track[] => { | ||
| const rows = getDb() | ||
| .prepare("SELECT * FROM tracks ORDER BY RANDOM() LIMIT ?") | ||
| .all(limit) as TrackRow[]; | ||
| return rows.map(rowToTrack); |
Comment on lines
+127
to
+134
| // 随机取多首曲目 | ||
| ipcMain.handle("library:getRandomTracks", (_event, limit: number) => { | ||
| try { | ||
| return { success: true, data: getRandomTracks(limit) }; | ||
| } catch (_error) { | ||
| return { success: false, error: ErrorCode.UNKNOWN }; | ||
| } | ||
| }); |
Comment on lines
+77
to
+85
| export const insertManyToQueue = (items: Track[], index: number): void => { | ||
| if (items.length === 0) return; | ||
| const list = queue.value; | ||
| const safeIndex = Math.max(0, Math.min(index, list.length)); | ||
| queue.value = [...list.slice(0, safeIndex), ...items, ...list.slice(safeIndex)]; | ||
| if (originalQueue.value) { | ||
| originalQueue.value = [...originalQueue.value, ...items]; | ||
| } | ||
| save(); |
Comment on lines
+12
to
+25
| /** 每日推荐逻辑日切换时刻:每日 6:00 更新,0-6 点仍算前一天 */ | ||
| const DAILY_REFRESH_HOUR = 6; | ||
|
|
||
| /** 每日推荐逻辑日 key */ | ||
| const todayKey = (): string => | ||
| new Date(Date.now() - DAILY_REFRESH_HOUR * 3600 * 1000).toDateString(); | ||
|
|
||
| /** 一天的每日推荐 */ | ||
| export interface DailyRecommendEntry { | ||
| /** 本地日期 key(Date.toDateString(),可被 new Date() 解析回 Date) */ | ||
| date: string; | ||
| /** 当天推荐曲目 */ | ||
| tracks: Track[]; | ||
| } |
Comment on lines
+35
to
+41
| for (const entry of data.dailyHistory) { | ||
| result.push({ | ||
| key: entry.date, | ||
| date: new Date(entry.date), | ||
| tracks: entry.tracks, | ||
| isToday: false, | ||
| }); |
Comment on lines
+452
to
+456
| // 私人 FM | ||
| if (status.fmMode) { | ||
| const next = await fm.next(); | ||
| if (next) await loadTrack(next); | ||
| return; |
Comment on lines
+67
to
+82
| /** 随机取一首曲目,库为空时返回 null */ | ||
| export const getRandomTrack = (): Track | null => { | ||
| const row = getDb().prepare("SELECT * FROM tracks ORDER BY RANDOM() LIMIT 1").get() as | ||
| | TrackRow | ||
| | undefined; | ||
| return row ? rowToTrack(row) : null; | ||
| }; | ||
|
|
||
| /** 随机取多首曲目 */ | ||
| export const getRandomTracks = (limit: number): Track[] => { | ||
| const safe = Math.max(0, Math.min(limit | 0, 500)); | ||
| if (safe === 0) return []; | ||
| const rows = getDb() | ||
| .prepare("SELECT * FROM tracks ORDER BY RANDOM() LIMIT ?") | ||
| .all(safe) as TrackRow[]; | ||
| return rows.map(rowToTrack); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.