v0.11.1: 权限体系重构 + AI管线优化 + 内容整理
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
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 { tools, categoryId } = body as {
|
||||
tools: { name: string; description?: string; websiteUrl?: string; logoUrl?: string; pricingModel?: string; pricingDetail?: string; features?: string[]; tags?: string[] }[];
|
||||
categoryId: number;
|
||||
};
|
||||
|
||||
if (!tools || !Array.isArray(tools) || tools.length === 0) {
|
||||
return NextResponse.json({ error: "tools 数组不能为空" }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!categoryId) {
|
||||
return NextResponse.json({ error: "categoryId 不能为空" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [existingPending, existingPublished] = await Promise.all([
|
||||
prisma.pendingTool.findMany({ select: { name: true, websiteUrl: true } }),
|
||||
prisma.tool.findMany({ select: { name: true, websiteUrl: true } }),
|
||||
]);
|
||||
|
||||
const allExisting = [...existingPending, ...existingPublished];
|
||||
const nameSet = new Set(allExisting.map((t) => t.name));
|
||||
const urlSet = new Set(allExisting.map((t) => t.websiteUrl).filter(Boolean) as string[]);
|
||||
const existingSlugs = await prisma.pendingTool.findMany({ select: { slug: true } });
|
||||
const slugSet = new Set(existingSlugs.map((s) => s.slug));
|
||||
|
||||
const toCreate: { name: string; slug: string; description: string | null; websiteUrl: string | null; logoUrl: string | null; categoryId: number | null; pricingModel: "free" | "freemium" | "paid" | "subscription"; pricingDetail: string | null; features: any; tags: any; sourceUrl: string }[] = [];
|
||||
const results: { name: string; status: string }[] = [];
|
||||
|
||||
for (const tool of tools) {
|
||||
const name = tool.name || "";
|
||||
if (!name || nameSet.has(name)) {
|
||||
results.push({ name: name || "未知", status: nameSet.has(name) ? "跳过-名称重复" : "跳过-名称为空" });
|
||||
continue;
|
||||
}
|
||||
const websiteUrl = tool.websiteUrl || "";
|
||||
if (websiteUrl && urlSet.has(websiteUrl)) {
|
||||
results.push({ name, status: "跳过-网址重复" });
|
||||
continue;
|
||||
}
|
||||
|
||||
let slug = 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);
|
||||
}
|
||||
if (slugSet.has(slug)) {
|
||||
slug = slug + "-" + Math.floor(Math.random() * 10000);
|
||||
}
|
||||
slugSet.add(slug);
|
||||
|
||||
toCreate.push({
|
||||
name,
|
||||
slug,
|
||||
description: tool.description || null,
|
||||
websiteUrl: websiteUrl || null,
|
||||
logoUrl: tool.logoUrl || null,
|
||||
categoryId,
|
||||
pricingModel: (tool.pricingModel as "free" | "freemium" | "paid" | "subscription") || "freemium",
|
||||
pricingDetail: tool.pricingDetail || null,
|
||||
features: tool.features || null,
|
||||
tags: tool.tags || null,
|
||||
sourceUrl: "AI发现",
|
||||
});
|
||||
|
||||
nameSet.add(name);
|
||||
if (websiteUrl) urlSet.add(websiteUrl);
|
||||
results.push({ name, status: "已导入" });
|
||||
}
|
||||
|
||||
if (toCreate.length > 0) {
|
||||
await prisma.$transaction(
|
||||
toCreate.map((data) =>
|
||||
prisma.pendingTool.create({ data })
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
total: tools.length,
|
||||
imported: results.filter((r) => r.status === "已导入").length,
|
||||
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