/* ============================================================================= * M02_MasterTemplete_Labor_SkEdit.ts * 일위대가 단가산출(SK) 참조 줄 모달(PLAN 806-1 · 요구 698-2 · 689) — 일위대가 표(컨테이너 · 구조물 조합 한 부품)에서 * 단가산출 줄을 고르면 그 단가산출 문서를 그대로 엶 = M02 단가산출 상세(`Sangeun_Detail` · 첫 탭 「수식」 줄 쌓기) 부품 그대로. * · [저장] = 수식 저장(`flush`) → 그 SK 문서 저장(`saveTemplate` · 그 층 · 그 주인) → 닫음 → 부르는 쪽이 일위대가 금액을 다시 셈 * · 그 층을 못 고치면(위 층 · 남의 주인) 읽기만 · [저장] 없음 · 고친 것 있이 닫으면 물음(버리면 수식 캐시도 비움) * · 머리(808-1 · 요구 701-4 · 5) = 단가산출 페이지 머리와 같음 — 보기 고르기 · [단가 갱신] · [재생성] · [저장] · [닫기] * 짝 모달 = `Labor_RefEdit`(일위조합 SC 줄). * ========================================================================== */ import { createButton, el, showConfirmDialog, showToast } from "@ui/ui_template_elements"; import { openModal } from "@ui/ui_template_modal"; import { createText } from "@ui/ui_template_text"; import { readTemplate, saveTemplate, type Layer } from "./M02_MasterTemplete_Api_Fetch"; import type { LaborRef } from "./M02_MasterTemplete_Labor_Calc"; import { tc } from "./M02_MasterTemplete_Labor_Text"; import { mountSangeunDetail } from "./M02_MasterTemplete_Sangeun_Detail"; export interface SkEditOptions { ref: LaborRef; /** 「뒷채움돌 … 」 */ title: string; /** 일위대가 머리(이름 · 「1 ㎡ 당」) */ head: string; readOnly: boolean; /** 닫힘 — `saved` = 그 SK 문서를 저장함(부르는 쪽이 금액을 다시 셈) */ closed: (saved: boolean) => void; } /** 단가산출 줄인가 — SK 참조 줄만 이 모달(로직 줄 · SC 줄 · 고정 줄은 다른 길) */ export const isSkRef = (ref: LaborRef | undefined): ref is LaborRef => !!ref && ref.키.startsWith("SK-"); /** 열린 단가산출 모달 — 같은 줄을 빨리 두 번 눌러도 하나만(읽는 동안 늦게 열림) */ const opened = new Set(); export async function openSkEdit(opt: SkEditOptions): Promise { const layer = opt.ref.층 as Layer; const at = `${layer}/${opt.ref.주인 ?? ""}/${opt.ref.키}`; if (opened.has(at)) return; opened.add(at); let doc: unknown; let version: string; try { const got = await readTemplate(layer, "sangeun", opt.ref.키, null, opt.ref.주인); doc = got.문서; version = got.판 ?? ""; } catch (error) { opened.delete(at); return void showToast(error instanceof Error ? error.message : tc("Load_Failed"), "error"); } let dirty = false; let saved = false; let handle: ReturnType | null = null; const finish = (): void => { handle?.destroy(); // 고친 채 버리면 수식 캐시도 비움 opened.delete(at); opt.closed(saved); }; openModal({ title: opt.title, closeLabel: tc("In_Close"), dialogClass: "m02-modal m02-labsk", width: "1100px", wide: true, beforeClose: async () => { if (dirty && !saved && !(await showConfirmDialog(tc("Ref_Discard")))) return false; finish(); return true; }, mount: (body, close, head) => { const host = el("div", { attrs: { "data-labor-sk": opt.ref.키 } }); const slot = el("span", { className: "m02-main__tools" }); // 보기 고르기 · [단가 갱신] · [재생성](808-1 · 페이지 머리와 같음) handle = mountSangeunDetail(host, doc, { layer, owner: opt.ref.주인, readOnly: opt.readOnly, onChanged: (d) => (dirty = d && !opt.readOnly), onVersion: (v) => (version = v), // 수식 저장이 파일 판을 바꿈 — 문서 저장이 이어 받음 source: true, // 페이지와 같은 길 — 수식 저장 단추는 이 [저장] 한 번에 모임 slot, }); const ok = createButton({ label: tc("Save"), variant: "filled", onClick: () => void (async () => { if (!handle) return; try { await handle.flush(); await saveTemplate( layer, "sangeun", opt.ref.키, null, version, handle.getDoc(), opt.ref.주인, ); saved = true; showToast(tc("Saved"), "success"); close(); finish(); } catch (error) { showToast(error instanceof Error ? error.message : tc("Lib_SaveFailed"), "error"); } })(), }); ok.dataset.skSave = ""; body.append( createText(opt.head, "muted", 14), createText( opt.readOnly ? `${tc("Ref_Shared")} · ${tc("Ref_ReadOnly")}` : tc("Ref_Shared"), "hint", ), host, ); head.append(slot); if (!opt.readOnly) head.append(ok); // [저장] = 머리 [닫기] 왼쪽 }, }); }