Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Labor_SkEdit.ts
T
eomsangdonandClaude Opus 5.5 f5d3347d1e fix(808-1): 줄 쌓기 수정 3차 — 수량 칸 식 글 칸 + 출처 꼬리표 · 글꼴 M01 = M02 · M02 머리 [단가 갱신][재생성] · 일위대가 줄 모달 일원화
- 수량 칸(요구 701-1) = 늘 식 글 칸(Q_특별인부) + 출처 꼬리표(표 = 표 고르기) · 눌러도 안 바뀜 · 표 값 기호에 수 = 그 값만(직접 입력) · 꼬리표 한 곳(sourceTag)
- 글꼴(701-2) = 줄 쌓기 화면이 정함(14px · M02 가 부모 16px 을 받던 것)
- M02 머리(701-3) = [초기화] 와 [되돌림] 뜻 다름 → [초기화] 이름 「M01 값으로」 · [단가 갱신][재생성] = 보기 고르기 옆 머리 칸(수식 보기만)
- 일위대가 단가산출 줄 모달(701-5) = 페이지 머리와 같음(보기 고르기 · [단가 갱신] · [재생성] · [저장])
- 일위대가 로직 줄 모달(701-4 · 5) = 옛 [옵션] · [단가산출로도 저장] · [항목 추가] · [율 줄 추가] 걷음 · 보기 고르기 없이 상세만 + 안내(온 단가산출) ·
  줄 문서 키 SK-000000 이 수식 문서를 읽어 404 · 「못 읽음」 이던 것 고침
- 시험: test_804_7 낡은 소스 기대(꼬리표 조건 글) 고침 + 808-1 · test_806_1 808-1 모달

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 18:52:03 +09:00

123 lines
5.1 KiB
TypeScript

/* =============================================================================
* 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<string>();
export async function openSkEdit(opt: SkEditOptions): Promise<void> {
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<typeof mountSangeunDetail> | 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); // [저장] = 머리 [닫기] 왼쪽
},
});
}