/* ============================================================================= * M02_MasterTemplete_Sangeun_Tabs.ts * M02 단가산출(SK) 상세 보기 고르기(PLAN 799-2 · 804-2 · 804-6 · 요구 686-1) — 수식(첫 탭 · 줄 쌓기) · 단가산출 상세. * 수식 = 공용 줄 쌓기 화면(`A00_Common/line_stack_screen.ts` · M01 과 같은 꼴) — 길 앞머리만 M02 사본 길 * (`/m02/layers/{층}/sangeun/{키}/doc` · 802-4a) · 층 쓰기 권한 없으면 읽기만 * 저장(804-8 · `page` 있음 = 단가산출 화면) = 페이지 [저장] · [되돌림] 한 번에 — 탭 위 저장 단추 없음(M01 과 같음) * 옛 수식 문서 탭(802-4b-2)은 804-6 에 걷음 · 단가산출 상세 = 상세가 쥔 `editor`(수식일 때 숨김) * 저장 안 한 SK(일위대가 줄 모달 · 새 SK) = 「저장한 단가산출만」 글 * [단가 갱신] · [재생성](808-1 · 요구 701-3) = `tools` — 보기 고르기 옆 머리 줄(수식 보기일 때만) * ========================================================================== */ import { createSegment } from "@ui/ui_template_segment"; import { createStackScreen } from "../A00_Common/line_stack_screen"; import { el } from "@ui/ui_template_elements"; import { tl } from "../M01_MasterData/M01_MasterData_UI_LogicLab_Text"; import type { Layer } from "./M02_MasterTemplete_Api_Fetch"; type View = "stack" | "ho"; export interface SkEquationOptions { scope: { layer: Layer; owner: string | null }; edit: boolean; /** 수식 저장 · [단가 갱신] · [재생성] 뒤 그 SK 새 판 */ onSaved: (version: string) => void; /** 페이지가 저장 · 되돌림을 맡음(804-8) — 수식 고침 있음이 바뀔 때 부름 */ page?: () => void; } /** SK 수식 길 — 꼬리 물음(`/table?key=…`)에 주인 물음을 이어 붙임 */ export function skDocPath(scope: SkEquationOptions["scope"], key: string, path: string): string { const [tail, query] = path.split("?"); const ask = [query, scope.owner ? `owner=${encodeURIComponent(scope.owner)}` : ""] .filter(Boolean) .join("&"); const at = `/m02/layers/${scope.layer}/sangeun/${encodeURIComponent(key)}/doc${tail}`; return ask ? `${at}?${ask}` : at; } /** 보기 고르기 · 수식 그릇 — `editor` = 단가산출 상세 그릇(수식일 때 숨김) */ export function createSangeunTabs( editor: HTMLElement, opt: SkEquationOptions, ): { picker: HTMLElement; /** 수식 화면 단추([단가 갱신] · [재생성]) — 보기 고르기 옆(머리 줄) */ tools: HTMLElement; host: HTMLElement; /** 저장한 SK 키(빈 키 = 저장 전) */ draw: (key: string) => void; canLeave: () => Promise; dirty: () => boolean; save: () => Promise; discard: () => Promise; } { const tools = el("span", { className: "m02-sk__tools", attrs: { "data-sk-tools": "" } }); // [단가 갱신] · [재생성](808-1) const stack = createStackScreen({ base: "", admin: opt.edit, cache: "m02_sk_doc_drafts", copy: { route: (k, p) => skDocPath(opt.scope, k, p), onSaved: opt.onSaved }, scope: opt.scope, // 804-4 다른 단가산출 · 일위대가 복사 page: opt.page, tools, }); let key = ""; let view: View = "stack"; const show = (v: View): void => { view = v; stack.root.hidden = tools.hidden = v !== "stack"; editor.hidden = v !== "ho"; if (!editor.hidden) editor.dataset.view = v; }; const picker = createSegment({ options: [ { value: "stack", label: tl("View_Equation") }, { value: "ho", label: tl("Ho_Title") }, ], value: "stack", size: 32, ariaLabel: tl("View_Label"), onChange: (v) => { show(v as View); if (v === "stack") stack.draw(key, true); }, }); picker.root.dataset.skViews = ""; show("stack"); return { picker: picker.root, tools, host: el("div", { className: "m02-sk__views", children: [stack.root] }), draw: (k: string) => { key = k; // 문서 없는 줄(일위대가 로직 줄 모달 등 · 페이지 아님) = 단가산출 상세부터(808-1 · 수식은 문서가 있어야) if (!k && !opt.page && view === "stack") { picker.set("ho"); return show("ho"); } if (view === "stack") stack.draw(k); }, canLeave: () => stack.canLeave(), dirty: () => stack.dirty(), save: () => stack.save(), discard: () => stack.discard(), }; }