75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { db } from '~/drizzle/db'
|
|
import { cardCodes } from '~/drizzle/schema'
|
|
import { and, count, desc, eq, ilike, or } from 'drizzle-orm'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const user = event.context.user
|
|
if (!user) {
|
|
throw createError({ statusCode: 401, message: '未授权访问' })
|
|
}
|
|
if (!['SONG_ADMIN', 'ADMIN', 'SUPER_ADMIN'].includes(user.role)) {
|
|
throw createError({ statusCode: 403, message: '权限不足' })
|
|
}
|
|
|
|
try {
|
|
const query = getQuery(event)
|
|
const status = typeof query.status === 'string' ? query.status.trim().toUpperCase() : ''
|
|
const keyword = typeof query.q === 'string' ? query.q.trim() : ''
|
|
const page = Math.max(1, Number.parseInt(String(query.page || '1'), 10) || 1)
|
|
const limitInput = Number.parseInt(String(query.limit || '10'), 10) || 10
|
|
const limit = Math.min(100, Math.max(1, limitInput))
|
|
const offset = (page - 1) * limit
|
|
|
|
const conditions = [] as any[]
|
|
if (status) {
|
|
conditions.push(eq(cardCodes.status, status as any))
|
|
}
|
|
if (keyword) {
|
|
conditions.push(
|
|
or(
|
|
ilike(cardCodes.code, `%${keyword}%`),
|
|
ilike(cardCodes.note, `%${keyword}%`)
|
|
)
|
|
)
|
|
}
|
|
|
|
let queryBuilder = db.select().from(cardCodes)
|
|
let countQueryBuilder = db.select({ count: count() }).from(cardCodes)
|
|
if (conditions.length > 0) {
|
|
queryBuilder = queryBuilder.where(and(...conditions))
|
|
countQueryBuilder = countQueryBuilder.where(and(...conditions))
|
|
}
|
|
|
|
const [result, totalResult, statsRows] = await Promise.all([
|
|
queryBuilder.orderBy(desc(cardCodes.createdAt)).limit(limit).offset(offset),
|
|
countQueryBuilder,
|
|
db.select({ status: cardCodes.status, count: count() }).from(cardCodes).groupBy(cardCodes.status)
|
|
])
|
|
|
|
const stats = { total: 0, available: 0, locked: 0, redeemed: 0 }
|
|
for (const row of statsRows) {
|
|
const value = Number(row.count || 0)
|
|
stats.total += value
|
|
if (row.status === 'AVAILABLE') stats.available = value
|
|
if (row.status === 'LOCKED') stats.locked = value
|
|
if (row.status === 'REDEEMED') stats.redeemed = value
|
|
}
|
|
|
|
const total = Number(totalResult[0]?.count || 0)
|
|
return {
|
|
success: true,
|
|
data: result,
|
|
pagination: {
|
|
page,
|
|
limit,
|
|
total,
|
|
totalPages: Math.max(1, Math.ceil(total / limit))
|
|
},
|
|
stats
|
|
}
|
|
} catch (err) {
|
|
console.error('获取点歌券列表失败', err)
|
|
throw createError({ statusCode: 500, message: '获取点歌券列表失败' })
|
|
}
|
|
})
|