feat: 迁移自定义功能至 1.5.9.9 版本

包含音乐源限制、CI 防 OOM 优化、数据库连接池优化、管理端权限及 UI 细节定制等功能
This commit is contained in:
2026-09-12 19:26:42 +08:00
parent 34f0679117
commit 1106aeea6c
161 changed files with 18963 additions and 27900 deletions
+52 -114
View File
@@ -8,7 +8,7 @@ import {
songCollaborators,
songReplayRequests
} from '~/drizzle/schema'
import { and, asc, count, countDistinct, eq, gte, lt, inArray, desc } from 'drizzle-orm'
import { and, asc, count, eq, gte, lt, inArray, desc } from 'drizzle-orm'
export default defineEventHandler(async (event) => {
// 检查用户身份验证和权限
@@ -79,7 +79,6 @@ export default defineEventHandler(async (event) => {
playTimeId: schedules.playTimeId,
isDraft: schedules.isDraft,
publishedAt: schedules.publishedAt,
replayRequestId: schedules.replayRequestId,
songId: schedules.songId,
songTitle: songs.title,
songArtist: songs.artist,
@@ -88,8 +87,6 @@ export default defineEventHandler(async (event) => {
songCover: songs.cover,
songMusicPlatform: songs.musicPlatform,
songMusicId: songs.musicId,
songDurationSeconds: songs.durationSeconds,
songCardCodeId: songs.cardCodeId,
songSemester: songs.semester,
songCreatedAt: songs.createdAt,
requesterName: users.name,
@@ -180,11 +177,11 @@ export default defineEventHandler(async (event) => {
const replayRequestersMap = new Map()
if (songIds.length > 0) {
// 获取每首歌的重播申请数量(统计 PENDING 和 FULFILLED 状态,按申请人去重)
// 获取每首歌的重播申请数量(统计 PENDING 和 FULFILLED 状态)
const replayCountsData = await db
.select({
songId: songReplayRequests.songId,
count: countDistinct(songReplayRequests.userId)
count: count(songReplayRequests.id)
})
.from(songReplayRequests)
.where(
@@ -210,10 +207,7 @@ export default defineEventHandler(async (event) => {
class: users.class
},
status: songReplayRequests.status,
createdAt: songReplayRequests.createdAt,
preferredPlayTimeId: songReplayRequests.preferredPlayTimeId,
submissionNote: songReplayRequests.submissionNote,
submissionNotePublic: songReplayRequests.submissionNotePublic
createdAt: songReplayRequests.createdAt
})
.from(songReplayRequests)
.innerJoin(users, eq(songReplayRequests.userId, users.id))
@@ -225,19 +219,12 @@ export default defineEventHandler(async (event) => {
)
.orderBy(desc(songReplayRequests.createdAt))
// 每首歌按用户去重(保留最新一条),只保留前5个申请人
const seenRequesterIds = new Map()
replayRequestersData.forEach((r) => {
if (!replayRequestersMap.has(r.songId)) {
replayRequestersMap.set(r.songId, [])
seenRequesterIds.set(r.songId, new Set())
}
const seen = seenRequesterIds.get(r.songId)
if (seen.has(r.user.id)) {
return
}
// 只保留前5个
if (replayRequestersMap.get(r.songId).length < 5) {
seen.add(r.user.id)
replayRequestersMap.get(r.songId).push({
id: r.user.id,
name: r.user.name || '未知用户',
@@ -249,69 +236,36 @@ export default defineEventHandler(async (event) => {
})
}
// 获取重播申请元数据(按 ID 索引,展示时排期按 replayRequestId 取对应记录)
const replayMetadataByIdMap = new Map<number, { submissionNote: string | null; submissionNotePublic: boolean; submissionNotePublicStatus: string | null; preferredPlayTimeId: number | null }>()
if (songIds.length > 0) {
const replayMetaData = await db
.select()
.from(songReplayRequests)
.where(
and(
inArray(songReplayRequests.songId, songIds),
inArray(songReplayRequests.status, ['PENDING', 'FULFILLED'])
)
)
for (const row of replayMetaData) {
replayMetadataByIdMap.set(row.id, {
submissionNote: row.submissionNote,
submissionNotePublic: row.submissionNotePublic,
submissionNotePublicStatus: row.submissionNotePublicStatus,
preferredPlayTimeId: row.preferredPlayTimeId
})
}
}
// 格式化响应数据
const formattedSchedules = schedulesData.map((schedule) => {
const dateOnly = schedule.playDate
// 处理投稿人姓名消歧
// 处理投稿人显示:班级 + 姓名
let requesterName = schedule.requesterName || 'Unknown User'
const sameNameUsers = nameToUsers.get(requesterName)
if (sameNameUsers && sameNameUsers.length > 1) {
if (schedule.requesterGrade) {
const sameGradeUsers = sameNameUsers.filter(
(u: { id: number; name: string | null; grade: string | null; class: string | null }) =>
u.grade === schedule.requesterGrade
)
if (sameGradeUsers.length > 1 && schedule.requesterClass) {
requesterName = `${requesterName}(${schedule.requesterGrade} ${schedule.requesterClass})`
} else {
requesterName = `${requesterName}(${schedule.requesterGrade})`
}
}
const requesterClassParts: string[] = []
if (schedule.requesterGrade) requesterClassParts.push(String(schedule.requesterGrade))
if (schedule.requesterClass) requesterClassParts.push(String(schedule.requesterClass))
const requesterClassInfo = requesterClassParts.join(' ').trim()
if (requesterClassInfo && requesterName) {
requesterName = `${requesterClassInfo} ${requesterName}`
} else if (requesterClassInfo) {
requesterName = requesterClassInfo
}
// 辅助函数:格式化显示名称 (用于联合投稿人)
const formatDisplayName = (userObj: any) => {
if (!userObj || !userObj.name) return '未知用户'
let displayName = userObj.name
const formatClassInfo = (userObj: any) => {
if (!userObj) return ''
const parts: string[] = []
if (userObj.grade) parts.push(String(userObj.grade))
if (userObj.class) parts.push(String(userObj.class))
return parts.join(' ').trim()
}
const sameNameUsers = nameToUsers.get(displayName)
if (sameNameUsers && sameNameUsers.length > 1) {
if (userObj.grade) {
const sameGradeUsers = sameNameUsers.filter((u: any) => u.grade === userObj.grade)
if (sameGradeUsers.length > 1 && userObj.class) {
displayName = `${displayName}(${userObj.grade} ${userObj.class})`
} else {
displayName = `${displayName}(${userObj.grade})`
}
}
}
return displayName
const formatDisplayName = (userObj: any) => {
if (!userObj) return '未知用户'
const name = userObj.name ? String(userObj.name).trim() : ''
const classInfo = formatClassInfo(userObj)
if (!name) return classInfo || '未知用户'
return classInfo ? `${classInfo} ${name}` : name
}
const collaborators = collaboratorsMap.get(schedule.songId) || []
@@ -324,11 +278,8 @@ export default defineEventHandler(async (event) => {
}))
// 获取重播申请信息
const linkedReplayRequestId = schedule.replayRequestId || null
const replayRequestCount = linkedReplayRequestId
? replayRequestCountsMap.get(schedule.songId) || 0
: 0
const replayRequesters = linkedReplayRequestId ? replayRequestersMap.get(schedule.songId) || [] : []
const replayRequestCount = replayRequestCountsMap.get(schedule.songId) || 0
const replayRequesters = replayRequestersMap.get(schedule.songId) || []
const formattedReplayRequesters = replayRequesters.map((r: any) => ({
id: r.id,
name: r.name,
@@ -338,8 +289,8 @@ export default defineEventHandler(async (event) => {
status: r.status
}))
// 只有正式绑定了重播申请的排期才按重播展示;草稿排期不提前暴露申请信息
const isReplaySong = linkedReplayRequestId !== null
// 判断是否为重播:有重播申请(PENDING 或 FULFILLED)
const isReplaySong = replayRequestCount > 0
return {
id: schedule.id,
@@ -347,7 +298,6 @@ export default defineEventHandler(async (event) => {
updatedAt: schedule.updatedAt,
playDate: dateOnly.toISOString().split('T')[0],
sequence: schedule.sequence || 1,
replayRequestId: linkedReplayRequestId,
played: schedule.played || false,
playTimeId: schedule.playTimeId,
// 草稿状态信息
@@ -363,39 +313,27 @@ export default defineEventHandler(async (event) => {
enabled: schedule.playTimeEnabled
}
: null,
song: (() => {
const replayMeta = linkedReplayRequestId ? replayMetadataByIdMap.get(linkedReplayRequestId) : null
const hasReplayMeta = !!replayMeta
return {
id: schedule.songId,
title: schedule.songTitle,
artist: schedule.songArtist,
requester: requesterName,
requesterId: schedule.songRequesterId,
requesterGrade: schedule.requesterGrade || null,
requesterClass: schedule.requesterClass || null,
collaborators: formattedCollaborators,
voteCount: voteCountMap.get(schedule.songId) || 0,
played: schedule.songPlayed || false,
cover: schedule.songCover || null,
cardCodeId: schedule.songCardCodeId || null,
musicPlatform: schedule.songMusicPlatform || null,
musicId: schedule.songMusicId || null,
durationSeconds: schedule.songDurationSeconds || null,
semester: schedule.songSemester || null,
createdAt: schedule.songCreatedAt,
submissionNote: hasReplayMeta ? replayMeta.submissionNote : null,
submissionNotePublic: hasReplayMeta ? replayMeta.submissionNotePublic : false,
submissionNotePublicStatus: hasReplayMeta ? (replayMeta.submissionNotePublicStatus || null) : null,
hasSubmissionNote: hasReplayMeta && !!replayMeta.submissionNote,
preferredPlayTimeId: hasReplayMeta ? replayMeta.preferredPlayTimeId : null,
// 重播申请信息
replayRequestCount: isReplaySong ? replayRequestCount : 0,
replayRequesters: isReplaySong ? formattedReplayRequesters : [],
isReplay: isReplaySong
}
})()
song: {
id: schedule.songId,
title: schedule.songTitle,
artist: schedule.songArtist,
requester: requesterName,
requesterId: schedule.songRequesterId,
requesterGrade: schedule.requesterGrade || null,
requesterClass: schedule.requesterClass || null,
collaborators: formattedCollaborators,
voteCount: voteCountMap.get(schedule.songId) || 0,
played: schedule.songPlayed || false,
cover: schedule.songCover || null,
musicPlatform: schedule.songMusicPlatform || null,
musicId: schedule.songMusicId || null,
semester: schedule.songSemester || null,
createdAt: schedule.songCreatedAt,
// 重播申请信息
replayRequestCount: isReplaySong ? replayRequestCount : 0,
replayRequesters: isReplaySong ? formattedReplayRequesters : [],
isReplay: isReplaySong // 只有已播放过且有重播申请的才标记为重播
}
}
})