Files
MemeStudio/app/api/wx-users/[id]/route.ts
2026-05-01 08:44:56 +08:00

108 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { auth } from '@/lib/auth'
import { compareSortKey } from '@/lib/sort-key'
export const dynamic = 'force-dynamic'
// GET /api/wx-users/[id] - Get a wx user and all levels with completion state
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const session = await auth.api.getSession({
headers: request.headers,
})
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { id } = await params
// levelProgress 这里不按 sortKey 排——MySQL collation 不可靠。
// 下面用 progress 的 Map 按需组合,最终顺序由 levels 的 JS 排序决定。
const user = await prisma.wxUser.findUnique({
where: { id },
select: {
id: true,
openid: true,
sessionKey: true,
nickname: true,
avatarUrl: true,
stamina: true,
staminaUpdatedAt: true,
createdAt: true,
updatedAt: true,
levelProgress: {
select: {
id: true,
userId: true,
levelId: true,
completedAt: true,
timeSpent: true,
},
},
},
})
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 })
}
// sortKey 排序必须在 JS 侧做,避免大小写不敏感 collation 带来的顺序错乱
const levels = await prisma.level.findMany({
select: {
id: true,
answer: true,
sortKey: true,
sortOrder: true,
createdAt: true,
},
})
levels.sort((a, b) => {
const c = compareSortKey(a.sortKey, b.sortKey)
if (c !== 0) return c
if (a.sortOrder !== b.sortOrder) return a.sortOrder - b.sortOrder
return a.createdAt.getTime() - b.createdAt.getTime()
})
const progressByLevelId = new Map(
user.levelProgress.map((progress) => [progress.levelId, progress])
)
return NextResponse.json({
id: user.id,
openid: user.openid,
sessionKey: user.sessionKey,
nickname: user.nickname,
avatarUrl: user.avatarUrl,
stamina: user.stamina,
staminaUpdatedAt: user.staminaUpdatedAt,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
completedLevelCount: user.levelProgress.length,
// 按 sortKey 排序后,数组下标即连续的 sortOrder小程序端契约不变
assignedLevels: levels.map((level, index) => {
const progress = progressByLevelId.get(level.id)
return {
id: level.id,
answer: level.answer,
sortOrder: index,
completed: Boolean(progress),
progressId: progress?.id || null,
completedAt: progress?.completedAt || null,
}
}),
})
} catch (error) {
console.error('Error fetching wx user:', error)
return NextResponse.json(
{ error: 'Failed to fetch wx user' },
{ status: 500 }
)
}
}