Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Labor_RowSk.ts
T
eomsangdon 94e330a5f3 feat(748-0): 단가산출 둘째 기초 — 세부 품 M01 원문 · 머리 수량 칸 하나 · 되돌림 셋(기초 빼기 · 더한 항목 빼기 · 더한 항목 수량)
- 둘째 기초 세부 줄 품 칸 = 서버 `원문`(0.871 그대로) · 금액 · 비목은 상자 합 몫 그대로 · 세부 고침도 원문 몫(머리 수량 · 화면배 안 나눔)
- 더한 기초 머리 상자(새 `Sangeun_BaseHead`) — 기초마다 이름 · 수량(기준단위 몇 개) 칸 · [되돌림] · [기초 빼기]
- 새 `logic/M02_Sangeun_Undo` — 뺀더한줄 기억 · 되살림(열쇠 당김 · 밂) · 처음수량 되돌림 · 넣을 때 처음수량 적음
- 되살림 띠에 뺀 더한줄도 · 일위대가 줄 패치 뺀더한줄 이음(RowSk · LinePatch)
- 낡은 시험 고침: test_727 세부 고침 ÷수량 기대 → 원문 그대로 · test_717_2b 모델 인라인에 Undo 추가
- 새 시험 test_748_0_sk_undo(거울 helper_748_0)
2026-11-02 22:05:31 +09:00

109 lines
4.6 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete_Labor_RowSk.ts
* 일위대가 줄 모달 안 단가산출 상세 = 717-2b 단가산출(SK) 상세 「줄 모드」(PLAN 723-3 · 정함 4 · 5).
* · 줄 → 이름 없는 SK 문서(`lineDoc` · 고름 · 자재표시 = 바탕 줄 정체 cid) → `mountSangeunDetail` 그대로 얹음
* (보기 넷 · 공용 상세(724-1 `LogicLab_Ho`) 줄 모달 품 · 단가 덮개 · 줄 빼기 · 더하기 · 박스 옵션 · 입력 칩)
* · `take()` = [적용] 때 그 줄에 남길 것 — 패치 `{덮개, 뺀줄, 더한줄}`(M02 변경 항목 · M01 안 바뀜 · 내역 17-2) +
* 옵션(시험 입력 → 그 줄 `입력값` · 정함 5)
* · [단가산출로도 저장](기본 꺼짐) = `saveAsSk` — 개인 층 새 SK(`from-line`)
* ========================================================================== */
import { el } from "@ui/ui_template_elements";
import { createText } from "@ui/ui_template_text";
import { fetchAuto } from "../M01_MasterData/M01_MasterData_UI_Logic_Api";
import type { LaborRow } from "./M02_MasterTemplete_Labor_Api";
import { calcSangeun, sangeunFromLine, type SkScope } from "./M02_MasterTemplete_Sangeun_Cover";
import { mountSangeunDetail } from "./M02_MasterTemplete_Sangeun_Detail";
import { cleanPatch, lineDoc, needsIds, type LinePatch } from "./logic/M02_Sangeun_Cover_Model";
export interface RowSkHandle {
/** 고친 것(패치 · 옵션) — 없으면 null */
take: () => { patch: LinePatch | null; values: Record<string, string> } | null;
destroy: () => void;
}
const same = (a: unknown, b: unknown): boolean => JSON.stringify(a) === JSON.stringify(b);
/** 줄 모드 SK 상세를 `host` 에 — 바탕 줄 정체가 필요하면 먼저 셈 */
export function mountRowSk(
host: HTMLElement,
o: { row: LaborRow; scope: SkScope; title: string; unit: string; readOnly: boolean },
): RowSkHandle {
let handle: ReturnType<typeof mountSangeunDetail> | null = null;
let alive = true;
/** 자동값(상세가 빈 입력에 채움) — 손대지 않은 자동값은 줄에 안 남김(빈 값 = 자동값 그대로) */
let auto: Record<string, unknown> = {};
const before = cleanPatch(o.row.패치);
const values0 = Object.fromEntries(
Object.entries(o.row.입력값 ?? {}).map(([k, v]) => [k, String(v)]),
);
host.replaceChildren(createText("…", "muted"));
void (async () => {
let ids: string[] | null = null;
try {
if (needsIds(o.row))
ids = (await calcSangeun(o.scope, lineDoc(o.row, null, null))).정체 ?? null;
} catch {
ids = null; // 정체 못 받음 = 고름 · 자재표시 없이(셈 까닭은 상세가 보임)
}
if (!alive) return;
const doc = {
...lineDoc(o.row, ids, before),
...(before?.뺀더한줄 ? { 뺀더한줄: before.뺀더한줄 } : {}), // 되살림 기억(744-1 · 셈엔 안 듦)
이름: o.title,
단위: o.unit || "식",
};
const box = el("div", { attrs: { "data-row-sk": "" } });
host.replaceChildren(box);
handle = mountSangeunDetail(box, doc, {
layer: o.scope.layer,
owner: o.scope.owner,
readOnly: o.readOnly,
onChanged: () => undefined,
});
if (o.row.로직 && !o.row.참조) auto = await fetchAuto(o.row.로직).catch(() => ({}));
})();
return {
take: () => {
if (!handle) return null;
const d = handle.getDoc();
const patch = cleanPatch({
덮개: d.덮개 as LinePatch["덮개"],
뺀줄: d.뺀줄,
더한줄: d.더한줄,
뺀더한줄: d.뺀더한줄,
});
const values = o.row.참조
? values0
: Object.fromEntries(
Object.entries(handle.getValues()).filter(
([k, v]) =>
String(v).trim() !== "" &&
(k in values0 || auto[k] == null || String(auto[k]) !== String(v)),
),
);
return same(patch, before) && same(values, values0) ? null : { patch, values };
},
destroy: () => {
alive = false;
handle?.destroy();
},
};
}
/** [단가산출로도 저장] — 그 줄(고친 패치 포함)을 개인 층 새 SK 로 · 새 이름 돌려줌 ·
* 같은 내용 물음(733-3)에서 그것을 씀 = 그 키 · 취소 = null */
export async function saveAsSk(
row: LaborRow,
patch: LinePatch | null,
name: string,
unit: string,
): Promise<string | null> {
const line: Record<string, unknown> = { ...row };
delete line.패치;
delete line.수량;
if (patch) line.패치 = patch;
const got = await sangeunFromLine({ layer: "personal", owner: null }, line, name, unit || "식");
return got?.이름 ?? null;
}