v0.11.1: 权限体系重构 + AI管线优化 + 内容整理
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { requireAdmin } from "@/lib/admin-auth";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const authError = await requireAdmin();
|
||||
if (authError) return authError;
|
||||
|
||||
try {
|
||||
const body = await request.json();
|
||||
const ids: number[] = body.ids;
|
||||
|
||||
if (!Array.isArray(ids) || ids.length === 0) {
|
||||
return NextResponse.json({ error: "ids数组不能为空" }, { status: 400 });
|
||||
}
|
||||
|
||||
const pendings = await prisma.pendingTool.findMany({
|
||||
where: { id: { in: ids } },
|
||||
include: { category: { select: { id: true } } },
|
||||
});
|
||||
|
||||
if (pendings.length === 0) {
|
||||
return NextResponse.json({ success: true, total: ids.length, published: 0, skipped: ids.length, details: [] });
|
||||
}
|
||||
|
||||
const existingNames = await prisma.tool.findMany({
|
||||
where: { name: { in: pendings.map((p) => p.name) } },
|
||||
select: { name: true },
|
||||
});
|
||||
const nameSet = new Set(existingNames.map((t) => t.name));
|
||||
|
||||
const existingUrls = pendings.filter((p) => p.websiteUrl).map((p) => p.websiteUrl!);
|
||||
let urlSet = new Set<string>();
|
||||
if (existingUrls.length > 0) {
|
||||
const urlMatches = await prisma.tool.findMany({
|
||||
where: { websiteUrl: { in: existingUrls } },
|
||||
select: { websiteUrl: true },
|
||||
});
|
||||
urlSet = new Set(urlMatches.map((t) => t.websiteUrl));
|
||||
}
|
||||
|
||||
const toPublish: typeof pendings = [];
|
||||
const results: { id: number; name: string; status: string }[] = [];
|
||||
const skipIds: number[] = [];
|
||||
|
||||
for (const pending of pendings) {
|
||||
if (nameSet.has(pending.name)) {
|
||||
skipIds.push(pending.id);
|
||||
results.push({ id: pending.id, name: pending.name, status: "跳过-已存在同名工具" });
|
||||
continue;
|
||||
}
|
||||
if (pending.websiteUrl && urlSet.has(pending.websiteUrl)) {
|
||||
skipIds.push(pending.id);
|
||||
results.push({ id: pending.id, name: pending.name, status: "跳过-已存在同网址工具" });
|
||||
continue;
|
||||
}
|
||||
toPublish.push(pending);
|
||||
}
|
||||
|
||||
if (skipIds.length > 0) {
|
||||
await prisma.pendingTool.deleteMany({ where: { id: { in: skipIds } } });
|
||||
}
|
||||
|
||||
if (toPublish.length === 0) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
total: ids.length,
|
||||
published: 0,
|
||||
skipped: results.length,
|
||||
details: results,
|
||||
});
|
||||
}
|
||||
|
||||
const candidateSlugs = toPublish.map((p) => {
|
||||
let slug = p.name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\u4e00-\u9fff]+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
if (!slug || /^[\u4e00-\u9fff-]+$/.test(slug)) {
|
||||
slug = "tool-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
|
||||
}
|
||||
return slug;
|
||||
});
|
||||
|
||||
const slugConflicts = new Set(
|
||||
(await prisma.tool.findMany({
|
||||
where: { slug: { in: candidateSlugs } },
|
||||
select: { slug: true },
|
||||
})).map((t) => t.slug)
|
||||
);
|
||||
|
||||
const toolsData = toPublish.map((pending, i) => {
|
||||
let slug = candidateSlugs[i];
|
||||
if (slugConflicts.has(slug)) {
|
||||
slug = slug + "-" + Math.floor(Math.random() * 10000);
|
||||
}
|
||||
|
||||
return {
|
||||
name: pending.name,
|
||||
slug,
|
||||
description: pending.description || "",
|
||||
websiteUrl: pending.websiteUrl || "",
|
||||
logoUrl: pending.logoUrl,
|
||||
categoryId: pending.categoryId || 1,
|
||||
pricingModel: (pending.pricingModel || "freemium") as "free" | "freemium" | "paid" | "subscription",
|
||||
pricingDetail: pending.pricingDetail,
|
||||
features: pending.features ?? undefined,
|
||||
tags: pending.tags ?? undefined,
|
||||
status: "published" as const,
|
||||
};
|
||||
});
|
||||
|
||||
const published = toolsData.length;
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.tool.createMany({ data: toolsData });
|
||||
await tx.pendingTool.deleteMany({
|
||||
where: { id: { in: toPublish.map((p) => p.id) } },
|
||||
});
|
||||
});
|
||||
|
||||
for (const pending of toPublish) {
|
||||
results.push({ id: pending.id, name: pending.name, status: "已发布" });
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
total: ids.length,
|
||||
published,
|
||||
skipped: results.filter((r) => r.status !== "已发布").length,
|
||||
details: results,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error as { message?: string };
|
||||
return NextResponse.json({ error: err.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user