feat(M02): 원문 다운로드 — 제목 행 단추 · pdf 통째 길(책 이름만) · 원문 읽기 M02 대리 길(85-4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
/* =============================================================================
|
||||
* M01_MasterData_UI_LogicLab_Source.ts
|
||||
* 원문 보기(품셈 본문 절) — 출처 글로 서버가 찾음(`GET /m01/logic/source`) · 늦게 온 답은 버림
|
||||
* M01 로직 상세 「원문」 패널 · M02 일위대가 상세 「원문」 패널(47-4)이 같이 씀
|
||||
* M01 로직 상세 「원문」 패널 · M02 일위대가 상세 「원문」 패널(47-4)이 같이 씀 ·
|
||||
* 길은 부르는 쪽이 줌(85-4 · M02 = `/m02/logic-lib/source` + 제목 행 [원문 다운로드] pdf 통째)
|
||||
* ========================================================================== */
|
||||
|
||||
import { currentLanguageIndex } from "@ui/ui_template_locale";
|
||||
@@ -16,6 +17,7 @@ const TEXT = {
|
||||
From: ["출처", "Source"],
|
||||
NoSource: ["출처 없음", "No source"],
|
||||
Near: ["{v} 절이 없어 위 절", "No {v} section — showing the parent"],
|
||||
Download: ["원문 다운로드", "Download source"],
|
||||
} as const;
|
||||
|
||||
const ts = (key: keyof typeof TEXT, v = ""): string =>
|
||||
@@ -70,15 +72,38 @@ export interface SourceView {
|
||||
show(src: string): void;
|
||||
}
|
||||
|
||||
export function createSourceView(): SourceView {
|
||||
/** 출처 글 → 원문 pdf 책(85-4) — 모르면 null */
|
||||
const bookOf = (src: string): string | null =>
|
||||
src.startsWith("건설품셈") ? "건설" : src.startsWith("산림품셈") ? "산림" : null;
|
||||
|
||||
export interface SourceViewOptions {
|
||||
/** 원문 절 길(기본 M01 `/m01/logic/source` — 시스템 관리자) */
|
||||
path?: string;
|
||||
/** 원문 pdf 길(`?book=`) — 주면 제목 행 오른쪽 [원문 다운로드] */
|
||||
pdf?: string;
|
||||
}
|
||||
|
||||
export function createSourceView(opts: SourceViewOptions = {}): SourceView {
|
||||
const body = el("div", { className: "m01lab-src__body" });
|
||||
const title = el("strong", { className: "m02-dfp__title" });
|
||||
const download = opts.pdf
|
||||
? (el("a", {
|
||||
className: "ui-btn ui-btn--ghost ui-btn--sm",
|
||||
text: ts("Download"),
|
||||
attrs: { download: "", "data-source-pdf": "" },
|
||||
}) as HTMLAnchorElement)
|
||||
: null;
|
||||
let shown: string | null = null;
|
||||
|
||||
const show = (src: string): void => {
|
||||
if (shown === src) return;
|
||||
shown = src;
|
||||
title.textContent = src || ts("NoSource");
|
||||
if (download) {
|
||||
const book = bookOf(src);
|
||||
download.hidden = !book;
|
||||
download.href = book ? `${API_BASE_URL}${opts.pdf}?${new URLSearchParams({ book })}` : "";
|
||||
}
|
||||
body.replaceChildren(el("p", { className: "m01-logic__muted", text: ts("Loading") }));
|
||||
const none = (): void =>
|
||||
body.replaceChildren(
|
||||
@@ -86,9 +111,12 @@ export function createSourceView(): SourceView {
|
||||
el("p", { className: "m01-logic__muted", text: `${ts("From")} · ${src || "—"}` }),
|
||||
);
|
||||
if (!src.trim()) return none();
|
||||
void fetch(`${API_BASE_URL}/m01/logic/source?${new URLSearchParams({ src })}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
void fetch(
|
||||
`${API_BASE_URL}${opts.path ?? "/m01/logic/source"}?${new URLSearchParams({ src })}`,
|
||||
{
|
||||
credentials: "include",
|
||||
},
|
||||
)
|
||||
.then((r) => (r.ok ? (r.json() as Promise<{ found: Found[] }>) : { found: [] }))
|
||||
.catch(() => ({ found: [] as Found[] }))
|
||||
.then(({ found }) => {
|
||||
@@ -115,5 +143,8 @@ export function createSourceView(): SourceView {
|
||||
});
|
||||
};
|
||||
|
||||
return { root: el("div", { className: "m01lab-src", children: [title, body] }), show };
|
||||
const head = download
|
||||
? el("div", { className: "m02-dfp__head", children: [title, download] })
|
||||
: title;
|
||||
return { root: el("div", { className: "m01lab-src", children: [head, body] }), show };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user