Files
Aislo/B09_Estimation/draft/B09_Draft_Print_Drawings.ts
T
eomsangdonandClaude Opus 5.5 f4889352f9 feat(b09-print): 인쇄 미리보기 도면 PDF — B07 도면 + 구조물 조합 도면 · 도각 크기 쪽 · 숨긴 층 뺌 · 벡터 · 한글 (302-2)
- 길 = GET /api/projects/{id}/print/drawings · POST /api/projects/{id}/print/drawings-pdf {ids?} (draft 라우터 · 로그인 · 회사 · 프로젝트 권한 스스로)
- 차례 = B07 도면번호 → 구조물 조합 도면(도번 차례 · 도번마다 한 번 · 더한장)
- B07 = B07 단건 조회 그대로(확정본 · 미확정 조립) · 미확정 횡단 장 구조물 = 화면 TS 를 서버 Node 로(번들 tmp · package.json 안 건드림)
- 쪽 = 도각 양식 실치수(A1 840×594) · 색 = openwebcad 밝은 바탕 규칙 · 글 = 맑은 고딕 심음(subset) · 그림 = data URL 넣음 · 못 넣은 수 = 응답 머리
- 화면 쪽 = fetchDrawingList · fetchDrawingsPdf(약속 꼴) · skippedImagesOf
- requirements = PyMuPDF · ezdxf

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
2026-10-13 08:01:47 +09:00

60 lines
2.5 KiB
TypeScript

/* =============================================================================
* B09_Draft_Print_Drawings.ts
* 인쇄 미리보기 도면 영역(PLAN 302-2) — 서버가 만든 목록 · PDF 를 그대로 받음(보는 것 = 받는 것).
* 차례 = B07 도면번호 → 구조물 조합 도면(도번마다 한 번) · 서버 `B09_Draft_Print_Drawings_Router.py`
* PDF 머리 X-Aislo-Skipped-Images = 못 넣은 그림 {id: 수} → `skippedImagesOf(blob)`
* ========================================================================== */
import { API_BASE_URL } from "@config/config_frontend";
import type { DrawingItem, FetchDrawingList, FetchDrawingsPdf } from "./B09_Draft_Print_Types";
/** 도면 한 장 — 약속 꼴(id · name = label) + 서버가 주는 칸 */
export interface PrintDrawingItem extends DrawingItem {
source: "b07" | "structure";
kind: string;
label: string;
number: string;
confirmed: boolean;
paper: string | null;
/** PDF 를 만들어야 셈 — 목록에서는 null */
images_skipped: number | null;
}
async function failure(response: Response): Promise<Error> {
const body = (await response.json().catch(() => null)) as { message?: string } | null;
return new Error(body?.message ?? `HTTP ${response.status}`);
}
export const fetchDrawingList: FetchDrawingList = async (projectId) => {
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/print/drawings`, {
credentials: "include",
});
if (!response.ok) throw await failure(response);
const items = (await response.json()) as Omit<PrintDrawingItem, "name">[];
return items.map((item): PrintDrawingItem => ({ ...item, name: item.label }));
};
const skipped = new WeakMap<Blob, Record<string, number>>();
export const fetchDrawingsPdf: FetchDrawingsPdf = async (projectId, ids) => {
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/print/drawings-pdf`, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(ids ? { ids } : {}),
});
if (!response.ok) throw await failure(response);
const blob = await response.blob();
try {
skipped.set(blob, JSON.parse(response.headers.get("X-Aislo-Skipped-Images") ?? "{}"));
} catch {
/* 머리가 깨졌으면 빠진 그림 없음으로 */
}
return blob;
};
/** 그 PDF 에서 못 넣은 그림 {도면 id: 수} — 없으면 빈 꼴 */
export function skippedImagesOf(blob: Blob): Record<string, number> {
return skipped.get(blob) ?? {};
}