/* ============================================================================= * M02_MasterTemplete_Hopyo_Import.ts * 일위대가 불러오기 본 칸 보기(PLAN 785-4 · 요구 642-11 — 마법사 `Hopyo_Wizard` 갈음 · 가운데 상세 페이지 없음) — * 왼쪽 [불러오기] → 층 · 파일 고름 → 올림(`Hopyo_Side`) → 바로 이 보기: * · 머리 막대 = 엑셀 보기 몸(`Hopyo_Sheet` — 시트 · 호표 · 검산 · 연결)의 머리에 층 · [끝내기]를 덧붙임 * · 아래 = 엑셀(탭 셋) + 오른쪽 호표 · 단가산출 목록(`Hopyo_Sheet` · `Hopyo_SheetSk`) · 만들기 = 호표 줄 [내 일위대가로](807-1) * · [끝내기] = 물음(안 만든 단가산출 알림) → 서버가 이번 HP · 격자 저장본 지움 · * 만든 일위대가 · 단가산출(엑셀 사본 걷고 출처만) · 별칭 장부 남음 · 옛 「안 이은 줄」 띠는 785-7 에서 지움(판정 「고를 것」) * · 작업 중 = 이 화면 동안만(743-1) — 화면 떠남(`leave` · 페이지 닫음) = 이 화면에서 올리거나 이은 파일 지움 · * 하루 지난 것은 서버가 지움 · 엑셀 자료는 보관하지 않음(필요하면 다시 올림) * ========================================================================== */ import { createBadge } from "@ui/ui_template_badge"; import { createButton, el, showConfirmDialog, showToast } from "@ui/ui_template_elements"; import { t as L } from "@ui/ui_template_locale"; import { createText } from "@ui/ui_template_text"; import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch"; import { deleteHopyo, type HopyoFile, type HopyoScope } from "./M02_MasterTemplete_Hopyo_Api"; import type { HopyoSheetBody } from "./M02_MasterTemplete_Hopyo_Sheet"; import { accessFor, type ManageLayer } from "./M02_MasterTemplete_Layer"; import "./M02_MasterTemplete_Hopyo.css"; export const LAYERS: { layer: ManageLayer; text: string }[] = [ { layer: "personal", text: "개인" }, { layer: "company", text: "회사" }, { layer: "system", text: "마스터" }, ]; export const layerText = (layer: string): string => LAYERS.find((x) => x.layer === layer)?.text ?? layer; const why = (error: unknown): string => (error instanceof Error ? error.message : String(error)); /** 쓸 수 있는 자기 층(개인 · 회사 · 마스터 차례) */ export async function writableLayers(): Promise { const user = await fetchSessionUser().catch(() => null); return LAYERS.map((x) => x.layer).filter((layer) => accessFor(layer, null, user).canWrite); } export interface HopyoImportArgs { layer: ManageLayer; file: HopyoFile; /** [끝내기] 로 올린 파일을 지웠음 */ onEnded: () => void; } export interface HopyoImport { root: HTMLElement; /** 화면 떠남 — 이 화면에서 올리거나 이은 파일 지움(743-1) */ leave: () => void; /** 안 옮긴 고름 — 판정 고름 캐시 걷음(809-1) 뒤 늘 거짓 */ dirty: () => boolean; } export function buildHopyoImport(a: HopyoImportArgs): HopyoImport { const { layer, file } = a; const scope: HopyoScope = { layer, owner: null }; let held = true; let body: HopyoSheetBody | null = null; const root = el("div", { className: "m02-hopyo-import", attrs: { "data-hopyo-import": file.키 }, children: [createText("엑셀을 읽는 중…", "muted", 14)], }); const leave = (): void => { window.removeEventListener("pagehide", leave); if (!held) return; held = false; void deleteHopyo(scope, file.키, true).catch(() => {}); body?.destroy(); }; window.addEventListener("pagehide", leave); // ── 머리 막대에 덧붙일 것 ── const finish = createButton({ label: "끝내기", variant: "filled", size: 28, onClick: () => void end() }); // prettier-ignore finish.dataset.hopyoFinish = ""; const layerNote = createBadge(`${layerText(layer)} 층`, "neutral"); async function end(): Promise { finish.disabled = true; const w = body?.skCount(); // 안 옮긴 단가산출(일위대가 밖 포함) — 묻기만 const ok = await showConfirmDialog( `「${file.파일}」 불러오기를 끝냄 — 올린 파일(엑셀 결과 · 격자 · 블록 풀이)을 지움 · 만든 일위대가 · 단가산출(출처만 남김)과 별칭 장부는 남음 · 같은 엑셀은 필요하면 다시 올림` + (w?.블록 ? ` · ${L("M02_SkUnmoved").replace("{n}", String(w.블록)).replace("{m}", String(w.밖))}` : ""), // 780-2 막지 않음 "끝내기", ); if (!ok) return void (finish.disabled = false); try { const out = (await deleteHopyo(scope, file.키)) as { 만든?: number }; held = false; window.removeEventListener("pagehide", leave); body?.destroy(); showToast(`끝냄 — 만든 일위대가 · 단가산출 ${out.만든 ?? 0} · 올린 파일 지움`, "success"); } catch (error) { showToast(why(error), "error"); finish.disabled = false; return; } a.onEnded(); } // ── 몸 — 엑셀 보기 몸을 바로 담음(스프레드시트는 열 때 불러옴) ── void import("./M02_MasterTemplete_Hopyo_Sheet") .then((m) => { if (!held) return; const view = m.buildHopyoSheet({ scope, key: file.키, 파일: file.파일, target: scope, canWrite: true, headExtra: [layerNote, finish], }); body = view; root.replaceChildren(...view.parts); }) .catch((error: unknown) => root.replaceChildren(createText(why(error), "muted", 14))); return { root, leave, dirty: () => false, }; }