170 lines
5.1 KiB
TypeScript
170 lines
5.1 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { db } from "@/lib/db";
|
|
import { generatedImage, user } from "@/lib/db/schema";
|
|
import { eq, desc, sql, and, gte, lte, like, or } from "drizzle-orm";
|
|
import { auth } from "@/app/(auth)/auth";
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
const session = await auth();
|
|
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
// 检查是否为管理员
|
|
const currentUser = await db.query.user.findFirst({
|
|
where: eq(user.id, session.user.id),
|
|
});
|
|
|
|
if (currentUser?.role !== "admin") {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
// 获取查询参数
|
|
const searchParams = request.nextUrl.searchParams;
|
|
const page = Number.parseInt(searchParams.get("page") || "1");
|
|
const pageSize = Number.parseInt(searchParams.get("pageSize") || "200");
|
|
const offset = (page - 1) * pageSize;
|
|
const search = searchParams.get("search") || "";
|
|
const startDate = searchParams.get("startDate");
|
|
const endDate = searchParams.get("endDate");
|
|
|
|
// 构建查询条件
|
|
const conditions = [];
|
|
|
|
if (search) {
|
|
// 搜索用户名或邮箱
|
|
const matchingUsers = await db
|
|
.select({ id: user.id })
|
|
.from(user)
|
|
.where(or(
|
|
like(user.name, `%${search}%`),
|
|
like(user.email, `%${search}%`)
|
|
));
|
|
|
|
if (matchingUsers.length > 0) {
|
|
const userIds = matchingUsers.map(u => u.id);
|
|
conditions.push(sql`${generatedImage.userId} IN (${sql.join(userIds.map(id => sql`${id}`), sql`, `)})`);
|
|
} else {
|
|
// 没有匹配的用户,返回空结果
|
|
return NextResponse.json({
|
|
images: [],
|
|
pagination: { page, pageSize, total: 0, totalPages: 0 }
|
|
});
|
|
}
|
|
}
|
|
|
|
if (startDate) {
|
|
conditions.push(gte(generatedImage.createdAt, new Date(startDate)));
|
|
}
|
|
|
|
if (endDate) {
|
|
const end = new Date(endDate);
|
|
end.setHours(23, 59, 59, 999);
|
|
conditions.push(lte(generatedImage.createdAt, end));
|
|
}
|
|
|
|
const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
|
|
|
|
// 查询总数
|
|
const countResult = await db
|
|
.select({ count: sql<number>`count(*)::int` })
|
|
.from(generatedImage)
|
|
.where(whereClause);
|
|
|
|
const total = countResult[0]?.count || 0;
|
|
|
|
// 查询图片列表(包含用户信息)
|
|
const images = await db
|
|
.select({
|
|
id: generatedImage.id,
|
|
userId: generatedImage.userId,
|
|
userName: user.name,
|
|
userEmail: user.email,
|
|
userDepartment: user.department,
|
|
thumbnailUrl: generatedImage.thumbnailUrl,
|
|
originalUrl: generatedImage.originalUrl,
|
|
imageSize: generatedImage.imageSize,
|
|
prompt: generatedImage.prompt,
|
|
modelId: generatedImage.modelId,
|
|
isFeatured: generatedImage.isFeatured,
|
|
featuredAt: generatedImage.featuredAt,
|
|
createdAt: generatedImage.createdAt,
|
|
chatId: generatedImage.chatId,
|
|
})
|
|
.from(generatedImage)
|
|
.leftJoin(user, eq(generatedImage.userId, user.id))
|
|
.where(whereClause)
|
|
.orderBy(desc(generatedImage.createdAt))
|
|
.limit(pageSize)
|
|
.offset(offset);
|
|
|
|
const totalPages = Math.ceil(total / pageSize);
|
|
|
|
return NextResponse.json({
|
|
images,
|
|
pagination: { page, pageSize, total, totalPages }
|
|
});
|
|
} catch (error) {
|
|
console.error("[Admin Images API] Error:", error);
|
|
return NextResponse.json({ error: "Failed to fetch images" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
// PATCH: 设置/取消图片精选
|
|
export async function PATCH(request: NextRequest) {
|
|
try {
|
|
const session = await auth();
|
|
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
// 检查是否为管理员
|
|
const currentUser = await db.query.user.findFirst({
|
|
where: eq(user.id, session.user.id),
|
|
});
|
|
|
|
if (currentUser?.role !== "admin") {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const body = await request.json();
|
|
const { imageId, isFeatured } = body;
|
|
|
|
if (!imageId) {
|
|
return NextResponse.json({ error: "Image ID is required" }, { status: 400 });
|
|
}
|
|
|
|
// 更新精选状态
|
|
const updateData: Record<string, unknown> = {
|
|
isFeatured: Boolean(isFeatured),
|
|
};
|
|
|
|
if (isFeatured) {
|
|
updateData.featuredAt = new Date();
|
|
updateData.featuredBy = session.user.id;
|
|
} else {
|
|
updateData.featuredAt = null;
|
|
updateData.featuredBy = null;
|
|
}
|
|
|
|
await db
|
|
.update(generatedImage)
|
|
.set(updateData)
|
|
.where(eq(generatedImage.id, imageId));
|
|
|
|
console.log(`[Admin Images API] Image ${imageId} featured status set to ${isFeatured} by ${session.user.id}`);
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: isFeatured ? "已添加到精选" : "已取消精选"
|
|
});
|
|
} catch (error) {
|
|
console.error("[Admin Images API] PATCH Error:", error);
|
|
return NextResponse.json({ error: "Failed to update featured status" }, { status: 500 });
|
|
}
|
|
}
|
|
|