2026-05-15 12:48:36 +08:00

104 lines
3.1 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { prisma } from '@/lib/prisma'
import {
buildMaterialWhereFromSearchParams,
MaterialQueryError,
} from '@/lib/material-query'
export async function GET(request: NextRequest) {
const session = await getServerSession(authOptions)
if (!session?.user || !(session.user as any).id) {
return NextResponse.json({ error: '未登录', code: 'UNAUTHORIZED' }, { status: 401 })
}
const searchParams = request.nextUrl.searchParams
const q = searchParams.get('q')
if (!q || q.trim().length < 1) {
return NextResponse.json({ suggestions: [] })
}
const keyword = q.trim()
try {
const { where: visibleWhere, empty } = await buildMaterialWhereFromSearchParams(
new URLSearchParams(),
session.user as any,
)
if (empty) {
return NextResponse.json({ suggestions: [] })
}
const withVisibleWhere = (fieldWhere: any) => ({
AND: [
visibleWhere,
fieldWhere,
],
})
// 并行查询三个字段的前缀匹配和模糊匹配
// 为了性能,我们只取 DISTINCT 的值,并限制数量
// 使用 Promise.all 并行查询
const [spuResults, authorResults, sceneResults] = await Promise.all([
// SPU 型号建议
prisma.material.findMany({
where: withVisibleWhere({
productModel: { contains: keyword, mode: 'insensitive' },
}),
select: { productModel: true },
distinct: ['productModel'],
take: 5
}),
// 作者建议
prisma.material.findMany({
where: withVisibleWhere({
authorName: { contains: keyword, mode: 'insensitive' },
}),
select: { authorName: true },
distinct: ['authorName'],
take: 3
}),
// 场景建议
prisma.material.findMany({
where: withVisibleWhere({
sceneName: { contains: keyword, mode: 'insensitive' },
}),
select: { sceneName: true },
distinct: ['sceneName'],
take: 3
})
])
// 合并结果并去重
const suggestionsSet = new Set<string>()
const suggestions: Array<{ type: 'spu' | 'author' | 'scene', value: string }> = []
const addSuggestion = (type: 'spu' | 'author' | 'scene', value: string) => {
if (value && !suggestionsSet.has(value) && value.toLowerCase().includes(keyword.toLowerCase())) {
suggestionsSet.add(value)
suggestions.push({ type, value })
}
}
spuResults.forEach(i => addSuggestion('spu', i.productModel))
authorResults.forEach(i => addSuggestion('author', i.authorName))
sceneResults.forEach(i => addSuggestion('scene', i.sceneName))
return NextResponse.json({ suggestions: suggestions.slice(0, 10) })
} catch (error) {
if (error instanceof MaterialQueryError) {
return NextResponse.json(
{ error: error.message, code: error.code },
{ status: error.status },
)
}
console.error('Search suggestions error:', error)
return NextResponse.json({ suggestions: [] }, { status: 500 })
}
}