/* ============================================================================= * M02_MasterTemplete_Labor_SangeunModal.ts * 일위대가 줄 [단가산출 보기] 모달(PLAN 717-3 · 724-1 · 요구서 내역12 4장 4 · 16 · 24 · 내역 16 · 17-2) — * 구조물 조합 일위대가 상세(`Labor_Detail`)의 로직 줄 · 단가산출(SK) 참조 줄 하나의 단가산출을 보고 그 일위대가에서만 고침. * · 위 = 일위대가 머리(「1 ㎡ 당」) · 이 줄 수량 * · 몸 = 단가산출 상세 줄 모드(`Labor_RowSk` — 717-2b 보기 넷 · 공용 상세 줄 모달 그 자리 고침) * · [적용] = 그 일위대가 줄 칸 `패치 {덮개, 뺀줄, 더한줄}`(M02 변경 항목 · M01 안 바뀜) · 화면 캐시(저장은 페이지 [저장]) · * 적용 안 하고 닫으면 물음 * · [단가산출로 저장] = 개인 층 새 SK(이름 받음 · `from-line`) · 일위대가가 자기 개인 층이면 그 줄을 새 SK 참조 줄로 * ========================================================================== */ import { createButton, el, showToast } from "@ui/ui_template_elements"; import { askConfirm, askText, openModal } from "@ui/ui_template_modal"; import { createText } from "@ui/ui_template_text"; import { currentLanguageIndex } from "@ui/ui_template_locale"; import type { LaborRow } from "./M02_MasterTemplete_Labor_Api"; import { mountRowSk, saveAsSk } from "./M02_MasterTemplete_Labor_RowSk"; import type { SkScope } from "./M02_MasterTemplete_Sangeun_Cover"; import type { LinePatch } from "./logic/M02_Sangeun_Cover_Model"; const TEXT = { Title: ["단가산출", "Unit-price build-up"], Qty: ["이 줄 수량", "Line quantity"], Apply: ["적용", "Apply"], ToSk: ["단가산출로 저장", "Save as unit-price build-up"], AskName: ["새 단가산출 이름(내 개인 층)", "New build-up name (my layer)"], Saved: ["{k} 저장함(내 개인 층)", "{k} saved (my layer)"], Replaced: ["이 줄을 {k} 참조로 바꿈 — [저장]으로 남김", "Line now refers to {k} — press [Save]"], Discard: ["적용 안 한 고침이 있음 — 버리고 닫을까?", "Discard unapplied edits?"], Close: ["닫기", "Close"], ReadOnly: ["읽기만 — 고친 값은 [단가산출로 저장]으로만 남김", "Read only — use [Save as]"], } as const satisfies Record; const t = (k: keyof typeof TEXT): string => TEXT[k][currentLanguageIndex as 0 | 1] ?? TEXT[k][0]; export interface RowSangeunOptions { /** 그 일위대가 층(셈 길 · 참조 위 층 검사) */ scope: SkScope; row: LaborRow; /** 줄 이름(로직 키 · 이름) */ title: string; /** 일위대가 머리(이름 · 「1 ㎡ 당」) */ head: string; /** 이 줄 지금 수량 글(「수기 5 ㎥」) */ qty: string; /** 줄 결과 단위(분모 · SK 단위 기본) */ unit: string; readOnly: boolean; /** [적용] — 그 줄 패치(null = 고침 없음) */ apply: (patch: LinePatch | null) => void; /** [단가산출로 저장] 뒤 그 줄을 새 SK 참조 줄로(없으면 안 바꿈) */ replace?: (row: LaborRow) => void; } export function openRowSangeun(o: RowSangeunOptions): void { const info = el("div", { className: "m02-std-sheet__body", attrs: { "data-sk-head": "" }, children: [ createText(o.head, "muted", 14), createText(`${o.title} · ${t("Qty")} ${o.qty}`, "muted", 14), ...(o.readOnly ? [createText(t("ReadOnly"), "hint")] : []), ], }); const host = el("div", { attrs: { "data-sk-body": "" } }); // 읽기만이어도 고쳐 볼 수 있음([단가산출로 저장]으로만 남김) — 717-3 그대로 const sk = mountRowSk(host, { row: o.row, scope: o.scope, title: o.title, unit: o.unit, readOnly: false, }); /** 지금 패치(고침 없으면 그 줄 원래 패치) */ const now = (): LinePatch | null => { const got = sk.take(); return got ? got.patch : (o.row.패치 ?? null); }; let close = (): void => {}; let done = false; const applyBtn = createButton({ label: t("Apply"), variant: "filled", onClick: () => { if (sk.take()) o.apply(now()); done = true; close(); }, }); applyBtn.dataset.skApply = ""; applyBtn.hidden = o.readOnly; const saveBtn = createButton({ label: t("ToSk"), variant: "ghost", onClick: async () => { const name = (await askText({ message: t("AskName"), value: o.title }))?.trim(); if (!name) return; try { const key = await saveAsSk(o.row, now(), name, o.unit); if (!key) return; // 같은 내용 물음 취소(733-3) showToast(t("Saved").replace("{k}", key), "success"); if (!o.replace) return; o.replace({ 로직: "", 입력값: {}, 메모: null, 별칭: null, 수량: o.row.수량, 참조: { 층: "personal", 주인: null, 키: key }, }); showToast(t("Replaced").replace("{k}", key), "info"); done = true; close(); } catch (error) { showToast(error instanceof Error ? error.message : String(error), "error"); } }, }); saveBtn.dataset.skSave = ""; ({ close } = openModal({ title: `${t("Title")} — ${o.title}`, closeLabel: t("Close"), width: "1100px", wide: true, actions: [saveBtn, applyBtn], beforeClose: async () => { if (!done && sk.take() && !(await askConfirm({ message: t("Discard"), danger: true }))) return false; sk.destroy(); return true; }, mount: (body) => body.append(info, host), })); }