优化图文页

This commit is contained in:
2026-04-28 17:11:42 +08:00
parent 674c202264
commit 040273586b
69 changed files with 3939 additions and 2302 deletions
+29 -17
View File
@@ -1,7 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import type { FeedItem, FeedResponse } from '@/app/types/feed';
import { getFileUrl } from '@/lib/minio';
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import type { FeedItem, FeedResponse } from "@/app/types/feed";
import { getFileUrl } from "@/lib/minio";
// Contract
// Inputs: search params { before?: ISOString, limit?: number }
@@ -9,25 +9,25 @@ import { getFileUrl } from '@/lib/minio';
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const limitParam = searchParams.get('limit');
const beforeParam = searchParams.get('before');
const limitParam = searchParams.get("limit");
const beforeParam = searchParams.get("before");
const limit = Math.min(Math.max(Number(limitParam ?? '24'), 1), 60); // 1..60
const limit = Math.min(Math.max(Number(limitParam ?? "24"), 1), 60); // 1..60
const before = beforeParam ? new Date(beforeParam) : null;
// fetch chunk from both tables
const [videos, posts] = await Promise.all([
prisma.video.findMany({
where: before ? { created_at: { lt: before } } : undefined,
orderBy: { created_at: 'desc' },
orderBy: { created_at: "desc" },
take: limit,
include: { author: true },
}),
prisma.imagePost.findMany({
where: before ? { created_at: { lt: before } } : undefined,
orderBy: { created_at: 'desc' },
orderBy: { created_at: "desc" },
take: limit,
include: { author: true, images: { orderBy: { order: 'asc' }, take: 1 } },
include: { author: true, images: { orderBy: { order: "asc" }, take: 1 } },
}),
]);
@@ -38,11 +38,15 @@ export async function GET(req: NextRequest) {
created_at: v.created_at,
desc: v.desc,
video_url: getFileUrl(v.video_url),
cover_url: getFileUrl(v.cover_url ?? 'default_cover.png'),
cover_url: getFileUrl(v.cover_url ?? "default_cover.png"),
width: v.width ?? null,
height: v.height ?? null,
author: { nickname: v.author.nickname, avatar_url: getFileUrl(v.author.avatar_url ?? ''), sec_uid: v.author.sec_uid },
likes: Number(v.digg_count)
author: {
nickname: v.author.nickname,
avatar_url: getFileUrl(v.author.avatar_url ?? ""),
sec_uid: v.author.sec_uid,
},
likes: Number(v.digg_count),
})),
...posts.map((p) => ({
type: "image" as const,
@@ -52,13 +56,21 @@ export async function GET(req: NextRequest) {
cover_url: getFileUrl(p.images?.[0]?.url ?? null),
width: p.images?.[0]?.width ?? null,
height: p.images?.[0]?.height ?? null,
author: { nickname: p.author.nickname, avatar_url: getFileUrl(p.author.avatar_url ?? ''), sec_uid: p.author.sec_uid },
likes: Number(p.digg_count)
author: {
nickname: p.author.nickname,
avatar_url: getFileUrl(p.author.avatar_url ?? ""),
sec_uid: p.author.sec_uid,
},
likes: Number(p.digg_count),
})),
].sort((a, b) => +new Date(b.created_at) - +new Date(a.created_at))
]
.sort((a, b) => +new Date(b.created_at) - +new Date(a.created_at))
.slice(0, limit);
const nextCursor = merged.length > 0 ? new Date(merged[merged.length - 1].created_at as any).toISOString() : null;
const nextCursor =
merged.length > 0
? new Date(merged[merged.length - 1].created_at as any).toISOString()
: null;
const payload: FeedResponse = { items: merged, nextCursor };
return NextResponse.json(payload);
}