import { asc, eq } from "drizzle-orm"; import { db } from "@/db"; import { annotations, files, toAnnotationDTO } from "@/db/schema"; import { annotationNote, annotationPreviewText, annotationTypeLabel } from "@/utils/annotation-display"; import { csvField } from "@/utils/csv"; import { encodeRFC5987 } from "@/utils/pdf-export"; // Export สรุปหมายเหตุเป็น CSV (F16/D3) — ข้อมูลเดียวกับหน้าสรุป (F15) // ขึ้นต้นด้วย UTF-8 BOM เพื่อให้ Excel ภาษาไทยอ่านถูกต้อง (RFC 4180: ครอบ field // ด้วย double quote, ขึ้นบรรทัดใหม่ด้วย CRLF) const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; export async function GET(req: Request) { const fileId = new URL(req.url).searchParams.get("fileId") ?? ""; if (!UUID_RE.test(fileId)) { return new Response("fileId ไม่ถูกต้อง", { status: 400 }); } const [file] = await db.select().from(files).where(eq(files.id, fileId)); if (!file) return new Response("ไม่พบไฟล์นี้", { status: 404 }); const rows = await db .select() .from(annotations) .where(eq(annotations.fileId, fileId)) .orderBy(asc(annotations.pageIndex), asc(annotations.createdAt)); const header = ["หน้า", "ชนิด", "ผู้เขียน", "ข้อความ", "โน้ต", "สร้างเมื่อ"]; const lines = rows.map((row) => { const a = toAnnotationDTO(row); return [ String(a.pageIndex + 1), annotationTypeLabel(a), a.userName, annotationPreviewText(a), annotationNote(a), new Date(a.createdAt).toLocaleString("th-TH", { timeZone: "Asia/Bangkok" }), ] .map(csvField) .join(","); }); //  = UTF-8 BOM — ต้องเป็นตัวแรกสุดของไฟล์เสมอ const csv = `${[header.map(csvField).join(","), ...lines].join("\r\n")}\r\n`; const filename = encodeRFC5987(`${file.title}-summary.csv`); return new Response(csv, { headers: { "content-type": "text/csv; charset=utf-8", "content-disposition": `attachment; filename="summary.csv"; filename*=UTF-8''${filename}`, }, }); }