diff --git a/server/api/auth/login.post.ts b/server/api/auth/login.post.ts index 2113caf..8646551 100644 --- a/server/api/auth/login.post.ts +++ b/server/api/auth/login.post.ts @@ -210,6 +210,9 @@ export default defineEventHandler(async (event) => { return { success: true, + // 供小程序 / App 等非浏览器客户端取用: + // 后续请求带 Authorization: Bearer 即可(见 server/middleware/auth.ts) + token, user: { id: user.id, username: user.username, diff --git a/server/api/open/schedules.get.ts b/server/api/open/schedules.get.ts index 9744bd4..eee3ee3 100644 --- a/server/api/open/schedules.get.ts +++ b/server/api/open/schedules.get.ts @@ -1,6 +1,14 @@ import { createError, defineEventHandler, getQuery } from 'h3' import { db } from '~/drizzle/db' -import { playTimes, schedules, songCollaborators, songs, systemSettings, users } from '~/drizzle/schema' +import { + playTimes, + schedules, + songCollaborators, + songs, + systemSettings, + users, + votes +} from '~/drizzle/schema' import { and, asc, desc, eq, gte, inArray, like, lt, or, sql } from 'drizzle-orm' import { formatDateTime } from '~/utils/timeUtils' import { openApiCache } from '~~/server/utils/open-api-cache' @@ -220,6 +228,8 @@ export default defineEventHandler(async (event) => { .select({ id: schedules.id, playDate: schedules.playDate, + sequence: schedules.sequence, + played: schedules.played, createdAt: schedules.createdAt, updatedAt: schedules.updatedAt, song: { @@ -312,6 +322,25 @@ 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 formattedSchedules = schedulesData.map((schedule) => { const collaborators = collaboratorsMap.get(schedule.song.id) || [] @@ -320,6 +349,8 @@ export default defineEventHandler(async (event) => { id: schedule.id, playDate: schedule.playDate, playDateFormatted: formatDateTime(schedule.playDate), + sequence: schedule.sequence, + played: schedule.played, semester: schedule.song.semester, song: { id: schedule.song.id, @@ -328,6 +359,7 @@ export default defineEventHandler(async (event) => { cover: schedule.song.cover, musicPlatform: schedule.song.musicPlatform, musicId: schedule.song.musicId, + voteCount: voteCountsMap.get(schedule.song.id) || 0, played: schedule.song.played, playedAt: schedule.song.playedAt, requestedAt: formatDateTime(schedule.song.createdAt), diff --git a/server/api/open/songs.get.ts b/server/api/open/songs.get.ts index 2abe519..a16033a 100644 --- a/server/api/open/songs.get.ts +++ b/server/api/open/songs.get.ts @@ -73,12 +73,16 @@ export default defineEventHandler(async (event) => { played: song.played || false, playedAt: song.playedAt, createdAt: song.createdAt, + // 缓存中 requester 可能是姓名字符串(formattedSongs 即如此),也可能已是对象, + // 两种都要兼容,否则缓存命中时会返回 { name: undefined, ... } requester: song.requester - ? { - name: song.requester.name, - grade: song.requester.grade, - class: song.requester.class - } + ? typeof song.requester === 'string' + ? { name: song.requester, grade: null, class: null } + : { + name: song.requester.name, + grade: song.requester.grade, + class: song.requester.class + } : null })), pagination: { @@ -337,7 +341,7 @@ export default defineEventHandler(async (event) => { const normalApiResult = { success: true, data: { - songs: songsWithDetails, + songs: formattedSongs, total, pagination: { page, @@ -351,7 +355,7 @@ export default defineEventHandler(async (event) => { await cache.set(normalApiCacheKey, normalApiResult, 180) // 3分钟缓存 console.log( - `[OpenAPI Cache] 歌曲数据已缓存到普通API缓存: ${normalApiCacheKey},数量: ${songsWithDetails.length}` + `[OpenAPI Cache] 歌曲数据已缓存到普通API缓存: ${normalApiCacheKey},数量: ${formattedSongs.length}` ) // 可选:也缓存到开放API专用缓存(保留原有逻辑,但优先级较低)