diff --git a/server/api/open/schedules.get.ts b/server/api/open/schedules.get.ts index eee3ee3..4231a28 100644 --- a/server/api/open/schedules.get.ts +++ b/server/api/open/schedules.get.ts @@ -21,6 +21,32 @@ import { type VisibilitySettingsLike } from '~~/server/utils/schedule-visibility' +/** + * 批量统计歌曲票数。 + * + * 该接口有缓存分支和数据库分支两条路径,此前字段互不一致 + * (序列号只在缓存分支有、票数只在数据库分支有)。统一由本函数提供票数, + * 保证把缓存开关、Redis 开关怎么组合,输出结构都一致。 + */ +async function buildVoteCountMap(songIds: number[]): Promise> { + const map = new Map() + if (songIds.length === 0) return map + + const rows = await db + .select({ + songId: votes.songId, + count: sql`count(*)` + }) + .from(votes) + .where(inArray(votes.songId, songIds)) + .groupBy(votes.songId) + + rows.forEach((row) => { + map.set(row.songId, Number(row.count)) + }) + return map +} + export default defineEventHandler(async (event) => { try { const query = getQuery(event) @@ -85,6 +111,10 @@ export default defineEventHandler(async (event) => { } filteredSchedules = applyVisibilityFilter(filteredSchedules) + const voteCounts = await buildVoteCountMap( + filteredSchedules.map((s: any) => s.song?.id).filter(Boolean) + ) + // 转换为开放API格式 const result = { success: true, @@ -101,7 +131,8 @@ export default defineEventHandler(async (event) => { semester: schedule.song.semester, cover: schedule.song.cover, musicPlatform: schedule.song.musicPlatform, - musicId: schedule.song.musicId + musicId: schedule.song.musicId, + voteCount: voteCounts.get(schedule.song.id) || 0 }, playTime: schedule.playTime ? { @@ -141,6 +172,11 @@ export default defineEventHandler(async (event) => { if (redisData) { const filteredRedisData = applyVisibilityFilter(redisData) + + const voteCounts = await buildVoteCountMap( + filteredRedisData.map((s: any) => s.song?.id).filter(Boolean) + ) + // 转换为开放API格式 const result = { success: true, @@ -157,7 +193,8 @@ export default defineEventHandler(async (event) => { semester: schedule.song.semester, cover: schedule.song.cover, musicPlatform: schedule.song.musicPlatform, - musicId: schedule.song.musicId + musicId: schedule.song.musicId, + voteCount: voteCounts.get(schedule.song.id) || 0 }, playTime: schedule.playTime ? { @@ -322,24 +359,7 @@ export default defineEventHandler(async (event) => { }) } - // 统计每首歌的票数。 - // 该接口的缓存分支(本文件上方)会返回 voteCount,数据库分支此前漏了, - // 导致两条分支字段不一致,这里补齐。 - const voteCountsMap = new Map() - if (songIds.length > 0) { - const voteCountsData = await db - .select({ - songId: votes.songId, - count: sql`count(*)` - }) - .from(votes) - .where(inArray(votes.songId, songIds)) - .groupBy(votes.songId) - - voteCountsData.forEach((row) => { - voteCountsMap.set(row.songId, Number(row.count)) - }) - } + const voteCountsMap = await buildVoteCountMap(songIds) // 格式化数据 const formattedSchedules = schedulesData.map((schedule) => {