Files
Aislo/M02_MasterTemplete/logic/M02_Sangeun_Undo.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

86 lines
3.7 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete/logic/M02_Sangeun_Undo.ts
* 단가산출(SK) 되돌리기 기억(PLAN 744-1 서버 · 748-0 화면) — 더한 기초 · 더한 항목 빼기 → 문서 `뺀더한줄`
* `[{차례, 줄}]`(되살림 = 그 차례에 다시 끼움) · 더한 항목 수량 → `처음수량`(넣을 때 값) 되돌림.
* 더한줄 지움 · 끼움 때 뒤 더한줄 열쇠 `add:#j[/…]`(덮개 · 고름 · 자재표시)를 한 칸씩 당김 · 밂.
* 금액은 늘 서버가 셈 — 여기는 문서 칸 옮김만 · 화면 · fetch · sessionStorage 없음(`CLAUDE.md` 4장).
* ========================================================================== */
import type { SkAdded, SkDoc } from "./M02_Sangeun_Cover_Model";
/* ── 순수 셈 ── */
const KEYED = ["덮개", "고름", "자재표시"] as const;
const KEY_RE = /^add:#(\d+)(.*)$/;
/** 문서 열쇠 맵의 `add:#j…` 를 옮김 — `drop` = 지운 j(그 열쇠는 버림) · 뒤 j 는 한 칸 당김 / `push` = 끼운 j 부터 한 칸 밂 */
function moveKeys(doc: SkDoc, mode: { drop: number } | { push: number }): void {
for (const name of KEYED) {
const map = doc[name] as Record<string, unknown> | undefined;
if (!map) continue;
const out: Record<string, unknown> = {};
for (const [key, value] of Object.entries(map)) {
const hit = KEY_RE.exec(key);
if (!hit) {
out[key] = value;
continue;
}
const j = Number(hit[1]);
if ("drop" in mode) {
if (j === mode.drop) continue;
out[j > mode.drop ? `add:#${j - 1}${hit[2]}` : key] = value;
} else out[j >= mode.push ? `add:#${j + 1}${hit[2]}` : key] = value;
}
(doc as Record<string, unknown>)[name] = out;
}
}
/** 더한줄 k 를 빼고 기억에 둠 — 이름은 되살림 띠 글(서버가 저장 때 다시 적음) */
export function forgetAdd(doc: SkDoc, k: number, name: string): void {
const one = doc.더한줄?.[k];
if (!one) return;
doc.뺀더한줄 = [
...(doc.뺀더한줄 ?? []),
{ 차례: k, 줄: JSON.parse(JSON.stringify({ ...one, ...(name ? { 이름: name } : {}) })) },
];
doc.더한줄 = (doc.더한줄 ?? []).filter((_, i) => i !== k);
moveKeys(doc, { drop: k });
}
/** 기억 n 번째를 그 차례에 다시 끼움(차례가 줄 수보다 크면 맨 끝) */
export function reviveAdd(doc: SkDoc, n: number): void {
const gone = doc.뺀더한줄?.[n];
if (!gone) return;
const list = [...(doc.더한줄 ?? [])];
const at = Math.min(Math.max(gone.차례, 0), list.length);
list.splice(at, 0, gone.줄);
doc.더한줄 = list;
moveKeys(doc, { push: at });
const rest = (doc.뺀더한줄 ?? []).filter((_, i) => i !== n);
if (rest.length) doc.뺀더한줄 = rest;
else delete doc.뺀더한줄;
}
/** 되살림 띠 글 — 줄 이름 · 없으면 로직 · 요소 · 참조 키 */
export function goneName(one: SkAdded): string {
const ref = (one.참조 as { 키?: string } | undefined)?.키;
return String(one.이름 || one.로직 || one.요소 || ref || "");
}
/** 더한줄 수량 고침 — 처음 값(옛 문서엔 없음)을 먼저 적어 둠 */
export function setQty(one: SkAdded, qty: number): void {
one.처음수량 ??= one.수량;
one.수량 = qty;
}
/** 더한줄 수량 처음 값으로 — 처음 값 모르면 그대로 */
export function resetQty(one: SkAdded): void {
if (one.처음수량 != null) one.수량 = one.처음수량;
}
/** 넣을 때 수량 적어 둠 */
export const withFirst = <T extends { 수량: number }>(line: T): T & { 처음수량: number } => ({
...line,
처음수량: line.수량,
});
/* ── 순수 셈 끝 ── */