80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/db";
|
|
import { getActiveAccountId } from "@/lib/account-context";
|
|
import { apiRouteErrorResponse } from "@/lib/auth/api";
|
|
import { requireUserAccountScope } from "@/lib/auth/user-scope";
|
|
|
|
function escapeCsv(value: string): string {
|
|
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
return `"${value.replace(/"/g, '""')}"`;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export async function GET(request: Request) {
|
|
try {
|
|
const { searchParams } = new URL(request.url);
|
|
const topicId = searchParams.get("topicId");
|
|
const accountId = await getActiveAccountId();
|
|
const { where: accountWhere } = await requireUserAccountScope(accountId);
|
|
|
|
const drafts = await prisma.draft.findMany({
|
|
where: {
|
|
sortOrder: { not: null },
|
|
...accountWhere,
|
|
...(topicId ? { topicId } : {}),
|
|
},
|
|
orderBy: [{ sortOrder: "asc" }, { createdAt: "desc" }],
|
|
});
|
|
|
|
const headers = [
|
|
"序號",
|
|
"主題標籤",
|
|
"切角",
|
|
"Hook",
|
|
"貼文內文",
|
|
"參考重點",
|
|
"配圖說明",
|
|
"參考來源",
|
|
"撰寫理由",
|
|
"狀態",
|
|
"建立時間",
|
|
];
|
|
|
|
const rows = drafts.map((draft) => {
|
|
const sources: string[] = [];
|
|
if (draft.sources) {
|
|
try {
|
|
sources.push(...(JSON.parse(draft.sources) as string[]));
|
|
} catch {
|
|
sources.push(draft.sources);
|
|
}
|
|
}
|
|
return [
|
|
String(draft.sortOrder ?? ""),
|
|
draft.searchTag ?? "",
|
|
draft.angle ?? "",
|
|
draft.hook ?? "",
|
|
draft.text,
|
|
draft.referenceNotes ?? "",
|
|
draft.imageBrief ?? "",
|
|
sources.join(" | "),
|
|
draft.rationale ?? "",
|
|
draft.status,
|
|
new Date(draft.createdAt).toLocaleString("zh-TW"),
|
|
].map(escapeCsv);
|
|
});
|
|
|
|
const csv = [headers.join(","), ...rows.map((r) => r.join(","))].join("\n");
|
|
const bom = "\uFEFF";
|
|
|
|
return new NextResponse(bom + csv, {
|
|
headers: {
|
|
"Content-Type": "text/csv; charset=utf-8",
|
|
"Content-Disposition": `attachment; filename="content-matrix-${Date.now()}.csv"`,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
return apiRouteErrorResponse(error, "matrix/export");
|
|
}
|
|
} |