优化图文页
This commit is contained in:
+86
-54
@@ -1,13 +1,16 @@
|
||||
import { json } from '@/lib/json';
|
||||
import { getFileUrl } from '@/lib/minio';
|
||||
import { prisma } from '@/lib/prisma'; // 你的 Prisma 客户端实例
|
||||
import { NextResponse } from 'next/server';
|
||||
import { json } from "@/lib/json";
|
||||
import { getFileUrl } from "@/lib/minio";
|
||||
import { prisma } from "@/lib/prisma"; // 你的 Prisma 客户端实例
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
const { searchParams } = new URL(req.url);
|
||||
const q = (searchParams.get('q') || '').trim();
|
||||
const page = Math.max(1, Number(searchParams.get('page') || 1));
|
||||
const limit = Math.min(50, Math.max(1, Number(searchParams.get('limit') || 20)));
|
||||
const q = (searchParams.get("q") || "").trim();
|
||||
const page = Math.max(1, Number(searchParams.get("page") || 1));
|
||||
const limit = Math.min(
|
||||
50,
|
||||
Math.max(1, Number(searchParams.get("limit") || 20)),
|
||||
);
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
if (!q) {
|
||||
@@ -24,7 +27,7 @@ export async function GET(req: Request) {
|
||||
{
|
||||
id: string;
|
||||
awemeId: string;
|
||||
type: 'video' | 'image';
|
||||
type: "video" | "image";
|
||||
rank: number;
|
||||
snippet: string;
|
||||
}[]
|
||||
@@ -86,9 +89,11 @@ export async function GET(req: Request) {
|
||||
`;
|
||||
|
||||
// 查询总数(参数化,避免注入)
|
||||
const totalRows = await prisma.$queryRaw<{
|
||||
count: number;
|
||||
}[]>`
|
||||
const totalRows = await prisma.$queryRaw<
|
||||
{
|
||||
count: number;
|
||||
}[]
|
||||
>`
|
||||
WITH tsq AS (
|
||||
SELECT websearch_to_tsquery('zhcfg', ${q}) AS query
|
||||
)
|
||||
@@ -104,61 +109,88 @@ export async function GET(req: Request) {
|
||||
`;
|
||||
|
||||
// 分离视频和图文ID
|
||||
const videoIds = rows.filter(r => r.type === 'video').map(r => r.awemeId);
|
||||
const imagePostIds = rows.filter(r => r.type === 'image').map(r => r.awemeId);
|
||||
const videoIds = rows
|
||||
.filter((r) => r.type === "video")
|
||||
.map((r) => r.awemeId);
|
||||
const imagePostIds = rows
|
||||
.filter((r) => r.type === "image")
|
||||
.map((r) => r.awemeId);
|
||||
|
||||
// 批量查询视频元信息
|
||||
const videos = videoIds.length > 0 ? (await prisma.video.findMany({
|
||||
where: { aweme_id: { in: videoIds } },
|
||||
select: {
|
||||
aweme_id: true,
|
||||
desc: true,
|
||||
cover_url: true,
|
||||
video_url: true,
|
||||
duration_ms: true,
|
||||
author: true
|
||||
},
|
||||
})).map(v => (
|
||||
{ ...v, cover_url: getFileUrl(v.cover_url || ''),
|
||||
author: { ...v.author, avatar_url: getFileUrl(v.author.avatar_url || '') },
|
||||
video_url: getFileUrl(v.video_url || '') })
|
||||
) : [];
|
||||
const videos =
|
||||
videoIds.length > 0
|
||||
? (
|
||||
await prisma.video.findMany({
|
||||
where: { aweme_id: { in: videoIds } },
|
||||
select: {
|
||||
aweme_id: true,
|
||||
desc: true,
|
||||
cover_url: true,
|
||||
video_url: true,
|
||||
duration_ms: true,
|
||||
author: true,
|
||||
},
|
||||
})
|
||||
).map((v) => ({
|
||||
...v,
|
||||
cover_url: getFileUrl(v.cover_url || ""),
|
||||
author: {
|
||||
...v.author,
|
||||
avatar_url: getFileUrl(v.author.avatar_url || ""),
|
||||
},
|
||||
video_url: getFileUrl(v.video_url || ""),
|
||||
}))
|
||||
: [];
|
||||
|
||||
// 批量查询图文元信息
|
||||
const imagePosts = imagePostIds.length > 0 ? (await prisma.imagePost.findMany({
|
||||
where: { aweme_id: { in: imagePostIds } },
|
||||
select: {
|
||||
aweme_id: true,
|
||||
desc: true,
|
||||
author: true,
|
||||
images: {
|
||||
orderBy: { order: 'asc' },
|
||||
take: 1,
|
||||
select: {
|
||||
url: true,
|
||||
width: true,
|
||||
height: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
})).map(ip => ({
|
||||
...ip,
|
||||
author: { ...ip.author, avatar_url: getFileUrl(ip.author.avatar_url || '') },
|
||||
cover_url: ip.images[0] ? getFileUrl(ip.images[0].url) : null,
|
||||
})) : [];
|
||||
const imagePosts =
|
||||
imagePostIds.length > 0
|
||||
? (
|
||||
await prisma.imagePost.findMany({
|
||||
where: { aweme_id: { in: imagePostIds } },
|
||||
select: {
|
||||
aweme_id: true,
|
||||
desc: true,
|
||||
author: true,
|
||||
images: {
|
||||
orderBy: { order: "asc" },
|
||||
take: 1,
|
||||
select: {
|
||||
url: true,
|
||||
width: true,
|
||||
height: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
).map((ip) => ({
|
||||
...ip,
|
||||
author: {
|
||||
...ip.author,
|
||||
avatar_url: getFileUrl(ip.author.avatar_url || ""),
|
||||
},
|
||||
cover_url: ip.images[0] ? getFileUrl(ip.images[0].url) : null,
|
||||
}))
|
||||
: [];
|
||||
|
||||
return json({
|
||||
results: rows.map(r => ({
|
||||
results: rows.map((r) => ({
|
||||
...r,
|
||||
video: r.type === 'video' ? videos.find(v => v.aweme_id === r.awemeId) : undefined,
|
||||
imagePost: r.type === 'image' ? imagePosts.find(ip => ip.aweme_id === r.awemeId) : undefined,
|
||||
video:
|
||||
r.type === "video"
|
||||
? videos.find((v) => v.aweme_id === r.awemeId)
|
||||
: undefined,
|
||||
imagePost:
|
||||
r.type === "image"
|
||||
? imagePosts.find((ip) => ip.aweme_id === r.awemeId)
|
||||
: undefined,
|
||||
})),
|
||||
total: totalRows?.[0]?.count ?? 0,
|
||||
page,
|
||||
limit,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Search error:', err);
|
||||
return NextResponse.json({ error: 'Search failed' }, { status: 500 });
|
||||
console.error("Search error:", err);
|
||||
return NextResponse.json({ error: "Search failed" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user