- 둘째 기초 세부 줄 품 칸 = 서버 `원문`(0.871 그대로) · 금액 · 비목은 상자 합 몫 그대로 · 세부 고침도 원문 몫(머리 수량 · 화면배 안 나눔) - 더한 기초 머리 상자(새 `Sangeun_BaseHead`) — 기초마다 이름 · 수량(기준단위 몇 개) 칸 · [되돌림] · [기초 빼기] - 새 `logic/M02_Sangeun_Undo` — 뺀더한줄 기억 · 되살림(열쇠 당김 · 밂) · 처음수량 되돌림 · 넣을 때 처음수량 적음 - 되살림 띠에 뺀 더한줄도 · 일위대가 줄 패치 뺀더한줄 이음(RowSk · LinePatch) - 낡은 시험 고침: test_727 세부 고침 ÷수량 기대 → 원문 그대로 · test_717_2b 모델 인라인에 Undo 추가 - 새 시험 test_748_0_sk_undo(거울 helper_748_0)
86 lines
3.7 KiB
TypeScript
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.수량,
|
|
});
|
|
/* ── 순수 셈 끝 ── */
|