2026-05-25 17:12:11 +08:00

177 lines
4.8 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.

/**
* 用户浏览历史API
*
* GET: 获取用户浏览历史列表
* POST: 记录浏览行为
* DELETE: 清除历史记录(支持单条或全部)
*
* @created 2025-12-13
*/
import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { prisma } from '@/lib/prisma'
import { toMaterialAssetProxyUrl } from '@/lib/url-rewrite'
/**
* GET /api/user/history
* 获取用户浏览历史列表
*/
export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return NextResponse.json({ error: '未登录' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1', 10)
const pageSize = parseInt(searchParams.get('pageSize') || '20', 10)
const skip = (page - 1) * pageSize
const [history, total] = await Promise.all([
prisma.browseHistory.findMany({
where: { userId: session.user.id },
orderBy: { viewedAt: 'desc' },
skip,
take: pageSize,
include: {
material: {
select: {
id: true,
productModel: true,
previewUrl: true,
materialType: true,
materialKind: true,
downloadCount: true,
likeCount: true,
deletedAt: true,
},
},
},
}),
prisma.browseHistory.count({
where: { userId: session.user.id },
}),
])
// 过滤掉已删除的素材
const validHistory = history.filter((item) => !item.material.deletedAt)
return NextResponse.json({
history: validHistory.map((item) => ({
id: item.id,
viewedAt: item.viewedAt.toISOString(),
material: {
id: item.material.id,
title: item.material.productModel,
thumbnailUrl: toMaterialAssetProxyUrl(item.material.previewUrl),
materialType: item.material.materialType,
materialKind: item.material.materialKind,
viewCount: item.material.downloadCount,
},
})),
pagination: {
page,
pageSize,
total,
totalPages: Math.ceil(total / pageSize),
},
})
} catch (error) {
console.error('获取浏览历史失败:', error)
return NextResponse.json({ error: '获取浏览历史失败' }, { status: 500 })
}
}
/**
* POST /api/user/history
* 记录浏览行为
*/
export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return NextResponse.json({ error: '未登录' }, { status: 401 })
}
const body = await request.json()
const { materialId } = body
if (!materialId) {
return NextResponse.json({ error: '缺少素材ID' }, { status: 400 })
}
// 检查素材是否存在
const material = await prisma.material.findUnique({
where: { id: materialId },
select: { id: true, deletedAt: true },
})
if (!material || material.deletedAt) {
return NextResponse.json({ error: '素材不存在' }, { status: 404 })
}
// 使用upsert更新或创建浏览记录
const history = await prisma.browseHistory.upsert({
where: {
materialId_userId: {
materialId,
userId: session.user.id,
},
},
update: {
viewedAt: new Date(),
},
create: {
materialId,
userId: session.user.id,
},
})
return NextResponse.json({ success: true, id: history.id })
} catch (error) {
console.error('记录浏览历史失败:', error)
return NextResponse.json({ error: '记录浏览历史失败' }, { status: 500 })
}
}
/**
* DELETE /api/user/history
* 清除历史记录
* - 不带参数:清除所有历史
* - 带materialId参数:清除单条记录
*/
export async function DELETE(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return NextResponse.json({ error: '未登录' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const materialId = searchParams.get('materialId')
if (materialId) {
// 删除单条记录
await prisma.browseHistory.deleteMany({
where: {
userId: session.user.id,
materialId,
},
})
} else {
// 清除所有历史
await prisma.browseHistory.deleteMany({
where: { userId: session.user.id },
})
}
return NextResponse.json({ success: true })
} catch (error) {
console.error('清除浏览历史失败:', error)
return NextResponse.json({ error: '清除浏览历史失败' }, { status: 500 })
}
}