export+sidebar: กรองตามรายคนที่เลือกดูครบทั้งจอและ export + REDACTION คงไว้เสมอ (คำขอผู้ใช้ 2026-09-22)
export PDF (F8): - route รับ ?user=<userId> เพิ่ม: กรอง annotation ตาม userId นั้น ยกเว้น REDACTION ติดไปเสมอ (D4 — กล่องดำหาย = เนื้อหาที่ปิดกั้นกลับมาอ่านได้) และ bookmarks → PDF outline กรองตามผู้บันทึกด้วย (หัวข้อแม่โดนกรองแต่ลูกยังอยู่ ลูกขึ้น root ตามตรรกะ buildOutline เดิม) ไม่ส่ง param = ทั้งหมด เหมือนเดิม - ชื่อไฟล์เติมชื่อผู้ใช้ท้าย: <title>-annotated-<ชื่อ>.pdf — ชื่อจาก user_name ที่ mirror ในตาราง (ไม่รับ text จาก client) ผ่าน encodeRFC5987 รองรับชื่อไทย - PDFViewer handleExportPdf: resolve filter ปัจจุบันก่อนยิง route (mine → user.userId) ส่ง &user= เมื่อไม่ใช่ ทุกคน จอ (F4): - visibleAnnotations คง REDACTION ของทุกคนไว้เสมอแม้กรองดูของคนอื่น — สูตรเดียวกับ export: กันเนื้อหาที่ปิดกั้นกลับมาอ่านได้บนจอ (เดิมหายไปตาม filter) และจอตรงกับ ไฟล์ export / ผลค้นหา F14 (visibleSearchResults) ใช้สูตรเดียวกัน - sidebar แท็บ Bookmark กรองตามเจ้าของหมายเหตุเหมือน annotation (เดิม F4 คุมแค่ annotation — bug report 2026-09-22): ต้นไม้ ตามหัวข้อ มุมมอง ตามหน้า ตัวเลข แท็บ และ badge จำนวนลูก ใช้ visibleBookmarks ชุดเดียวกัน — ลูกที่แม่โดนกรองขึ้น root เหมือน export; empty state แยก ไม่มีที่คั่นหน้าของเจ้าของหมายเหตุที่เลือก ออกจากไฟล์ว่างจริง - popup ย้ายหัวข้อ (movableTo) และ bookmarkById ยังเห็นต้นไม้เต็ม — ย้ายไปใต้หัวข้อ ของคนอื่นได้ตามเดิม verify: tsc + Playwright e2e (สร้าง redaction จริงเป็น user1 → สลับ user3 กรองของ ตัวเอง: rect ดำของ user1 ยัง render ครบ, tab Bookmark (10)→(2) และแถวต้นไม้ 2 ตรง DB เป๊ะ, ลบ redaction ทดสอบทิ้งจน DB เหลือ 0) + export จริง 4 filter นับ PDF outline ตรงจำนวน bookmarks ของผู้ใช้นั้นใน DB ทุกแบบ — sync docs/PLAN-FEAT.md §F8 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
9ba8f0a8ec
commit
0aef3ff028
4 changed files with 73 additions and 16 deletions
|
|
@ -14,7 +14,7 @@ import {
|
|||
type PDFPage,
|
||||
type PDFRef,
|
||||
} from "pdf-lib";
|
||||
import { asc, eq, inArray } from "drizzle-orm";
|
||||
import { and, asc, eq, inArray } from "drizzle-orm";
|
||||
|
||||
import { db } from "@/db";
|
||||
import { PdfPathError, readPublicPdf } from "@/lib/server-pdf";
|
||||
|
|
@ -274,9 +274,21 @@ export async function GET(req: Request) {
|
|||
.from(annotations)
|
||||
.where(eq(annotations.fileId, fileId))
|
||||
.orderBy(asc(annotations.createdAt));
|
||||
// F4: export ตาม filter รายคนที่กำลังดู (?user=<userId> จาก sidebar — ไม่ส่ง = ทั้งหมด)
|
||||
// REDACTION ติดไปเสมอแม้กรองคนอื่น (D4 — กล่องดำหายไป = เนื้อหาที่ปิดกั้นกลับมาอ่านได้)
|
||||
const userParam = url.searchParams.get("user");
|
||||
const filteredRows = userParam
|
||||
? rows.filter((r) => r.userId === userParam || r.type === "REDACTION")
|
||||
: rows;
|
||||
// ชื่อผู้ใช้เติมท้ายชื่อไฟล์ (mirror ในตาราง — ไม่รับ text จาก client) — กรองแล้ว
|
||||
// ผู้นั้นยังไม่มีรายการเลย = ใช้ userId ตรง ๆ
|
||||
const filterName = userParam
|
||||
? (rows.find((r) => r.userId === userParam && r.userName)?.userName ??
|
||||
userParam)
|
||||
: null;
|
||||
// sort แยกตามชนิดก่อนวาด (stable ภายในชนิดด้วย createdAt) — กัน REDACTION เก่าโดน
|
||||
// HIGHLIGHT/DRAW ที่สร้างทีหลังทับจนข้อความง้ำกลับมาอ่านได้ (D4)
|
||||
const dtos = rows
|
||||
const dtos = filteredRows
|
||||
.map(toAnnotationDTO)
|
||||
.sort((a, b) => TYPE_ORDER[a.type] - TYPE_ORDER[b.type]);
|
||||
|
||||
|
|
@ -634,10 +646,16 @@ export async function GET(req: Request) {
|
|||
|
||||
// bookmarks → PDF outline (แผง Bookmarks ของ reader กดกระโดดไปหน้า + yOffset)
|
||||
// เรียงตามลำดับหน้าเหมือน sidebar (byPageOrder ของ N5: หน้า → ตำแหน่งบนหน้า → เวลาสร้าง)
|
||||
// กรองตามรายคนเหมือน annotation (คำขอผู้ใช้ 2026-09-22) — หัวข้อแม่โดนกรองแต่ลูกยังอยู่
|
||||
// ลูกขึ้น root (buildOutline จัดการ parent หายเคสนี้อยู่แล้ว)
|
||||
const bookmarkRows = await db
|
||||
.select()
|
||||
.from(bookmarks)
|
||||
.where(eq(bookmarks.fileId, fileId))
|
||||
.where(
|
||||
userParam
|
||||
? and(eq(bookmarks.fileId, fileId), eq(bookmarks.userId, userParam))
|
||||
: eq(bookmarks.fileId, fileId),
|
||||
)
|
||||
.orderBy(
|
||||
asc(bookmarks.pageIndex),
|
||||
asc(bookmarks.yOffset),
|
||||
|
|
@ -646,7 +664,9 @@ export async function GET(req: Request) {
|
|||
buildOutline(doc, bookmarkRows);
|
||||
|
||||
const out = await doc.save();
|
||||
const filename = encodeRFC5987(`${file.title}-annotated.pdf`);
|
||||
const filename = encodeRFC5987(
|
||||
`${file.title}-annotated${filterName ? `-${filterName}` : ""}.pdf`,
|
||||
);
|
||||
return new Response(new Uint8Array(out), {
|
||||
headers: {
|
||||
"content-type": "application/pdf",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue