Files
Henry_Du 4ce4649aaf
Build VoiceHub FPK / build-fpk (push) Failing after 56m5s
Build and Push Docker Image / build-and-push (push) Canceled after 1h9m35s
初次提交
2026-09-06 08:19:02 +08:00

188 lines
5.3 KiB
TypeScript

import { db } from '~/drizzle/db'
import { cacheService } from '~~/server/services/cacheService'
import {
schedules,
songs,
systemSettings,
votes,
songCollaborators,
collaborationLogs
} from '~/drizzle/schema'
import { and, eq } from 'drizzle-orm'
export default defineEventHandler(async (event) => {
// 检查用户认证
const user = event.context.user
if (!user) {
throw createError({
statusCode: 401,
message: '需要登录才能撤回歌曲'
})
}
const body = await readBody(event)
if (!body.songId) {
throw createError({
statusCode: 400,
message: '歌曲ID不能为空'
})
}
// 查找歌曲
const songResult = await db.select().from(songs).where(eq(songs.id, body.songId)).limit(1)
const song = songResult[0]
if (!song) {
throw createError({
statusCode: 404,
message: '歌曲不存在'
})
}
// 检查是否是用户自己的投稿或联合投稿
const isRequester = song.requesterId === user.id
let isCollaborator = false
let collaboratorRecord = null
if (!isRequester) {
const collabResult = await db
.select()
.from(songCollaborators)
.where(and(eq(songCollaborators.songId, song.id), eq(songCollaborators.userId, user.id)))
.limit(1)
if (collabResult.length > 0) {
isCollaborator = true
collaboratorRecord = collabResult[0]
}
}
if (!isRequester && !isCollaborator && !['ADMIN', 'SUPER_ADMIN'].includes(user.role)) {
throw createError({
statusCode: 403,
message: '只能撤回自己的投稿或退出联合投稿'
})
}
// 检查歌曲是否已经播放
if (song.played) {
throw createError({
statusCode: 400,
message: '已播放的歌曲不能撤回'
})
}
// 检查歌曲是否已排期(只检查已发布的排期,草稿不算)
const scheduleResult = await db
.select()
.from(schedules)
.where(and(eq(schedules.songId, body.songId), eq(schedules.isDraft, false)))
.limit(1)
const schedule = scheduleResult[0]
if (schedule) {
throw createError({
statusCode: 400,
message: '已排期的歌曲不能撤回'
})
}
// 如果是联合投稿人撤回(退出)
if (isCollaborator && !isRequester && !['ADMIN', 'SUPER_ADMIN'].includes(user.role)) {
await db.delete(songCollaborators).where(eq(songCollaborators.id, collaboratorRecord.id))
// 记录日志
await db.insert(collaborationLogs).values({
collaboratorId: collaboratorRecord.id,
action: 'LEAVE',
operatorId: user.id,
ipAddress:
(event.node.req.headers['x-forwarded-for'] as string) || event.node.req.socket.remoteAddress
})
// 清除歌曲列表缓存
await cacheService.clearSongsCache()
return {
message: '已成功退出联合投稿',
songId: body.songId,
action: 'leave'
}
}
// 如果是主投稿人撤回(删除歌曲)
// 获取系统设置以检查限制类型
const settingsResult = await db.select().from(systemSettings).limit(1)
const settings = settingsResult[0]
const dailyLimit = settings?.dailySubmissionLimit || 0
const weeklyLimit = settings?.weeklySubmissionLimit || 0
// 检查撤销的歌曲是否在当前限制期间内(用于返还配额)
let canReturnQuota = false
const now = new Date()
if (dailyLimit > 0) {
// 检查是否在同一天
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate())
const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000)
if (song.createdAt >= startOfDay && song.createdAt < endOfDay) {
canReturnQuota = true
}
} else if (weeklyLimit > 0) {
// 检查是否在同一周(周一开始)
const startOfWeek = new Date(now)
const dayOfWeek = now.getDay()
const daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1 // 周一为一周开始
startOfWeek.setDate(now.getDate() - daysToSubtract)
startOfWeek.setHours(0, 0, 0, 0)
const endOfWeek = new Date(startOfWeek.getTime() + 7 * 24 * 60 * 60 * 1000)
if (song.createdAt >= startOfWeek && song.createdAt < endOfWeek) {
canReturnQuota = true
}
}
// 删除关联的联合投稿记录
await db.delete(songCollaborators).where(eq(songCollaborators.songId, body.songId))
// 删除歌曲的所有投票
await db.delete(votes).where(eq(votes.songId, body.songId))
// 如果有 hitRequestId,减少对应时段的已接纳数量
if (song.hitRequestId) {
try {
// 需要引入 requestTimes 和 sql
const { requestTimes } = await import('~/drizzle/schema')
const { sql } = await import('drizzle-orm')
await db
.update(requestTimes)
.set({
accepted: sql`GREATEST(0, accepted - 1)`
})
.where(eq(requestTimes.id, song.hitRequestId))
console.log(`已减少投稿时段 ${song.hitRequestId} 的接纳数量`)
} catch (error) {
console.error(`减少投稿时段接纳数量失败: ${error.message}`)
}
}
// 删除歌曲
await db.delete(songs).where(eq(songs.id, body.songId))
// 清除歌曲列表缓存
await cacheService.clearSongsCache()
console.log('[Cache] 歌曲缓存已清除(撤回歌曲)')
return {
message: canReturnQuota ? '歌曲已成功撤回,投稿配额已返还' : '歌曲已成功撤回',
songId: body.songId,
quotaReturned: canReturnQuota
}
})