/* ============================================================================= * common_util_line_stack_draft.ts * 줄 쌓기 기계 창 초안(PLAN 827-1) — 문서 칸 `내기계초안` 다루기(화면 · fetch 없음). * 초안 하나 = {표지 「EQP초안-N」, 키?(고칠 내 기계), 본뜬?(바탕 키), 줄(내 기계 몸), 시간당?(목록 금액 · 식 키)} * 줄 입력 기계='개인 EQP초안-N' 이 가리킴 · 단가산출 [저장] 때 서버가 만들기 · 고침 · 키 바꿈 * (짝 = `M02_MasterTemplete/M02_MyMachine_Draft.py` — 칸 이름 · 표지 꼴) * ========================================================================== */ import { varId, type FormulaDoc } from "./common_util_formula_doc"; import { repick, type Picked } from "./common_util_line_stack_pick"; export const DRAFT_FIELD = "내기계초안"; const TAG = /EQP초안-\d+/g; export interface DraftItem { 표지: string; 키?: string; 본뜬?: string; 줄: { 이름: string; 규격: string; 방식: string; 값?: Record; 시간당?: object }; 시간당?: { ok: boolean; 계?: number; 로직?: string | null }; } type Holder = FormulaDoc & { [DRAFT_FIELD]?: DraftItem[] }; export const draftsOf = (doc: FormulaDoc | null | undefined): DraftItem[] => ((doc as Holder | null | undefined)?.[DRAFT_FIELD] ?? []).filter(Boolean); /** 기계 입력 글(따옴표 뗌)이 초안인지 */ export const isDraftNo = (no: string | null | undefined): boolean => /^개인 EQP초안-\d+$/.test(no ?? ""); let last = Date.now() % 1_000_000_000; /** 새 표지 — 세션 안 겹치지 않게(캐시에 남은 옛 초안 값과 안 섞임) */ export const newTag = (): string => `EQP초안-${++last}`; /** 문서가 안 쓰는 초안은 뺌 · 다 빠지면 칸 지움 */ export function pruneDrafts(doc: FormulaDoc): void { const box = doc as Holder; if (!box[DRAFT_FIELD]) return; const { [DRAFT_FIELD]: list, ...rest } = box; const used = new Set(JSON.stringify(rest).match(TAG) ?? []); const keep = (list ?? []).filter((d) => used.has(d.표지)); if (keep.length) box[DRAFT_FIELD] = keep; else delete box[DRAFT_FIELD]; } /** 초안을 줄 `i`(단가 기호 `id`)에 끼움 — 내 기계 고침이면 이 문서에서 그 기계를 가리키던 줄 모두 초안으로 */ export function putDraft(doc: FormulaDoc, i: number, id: string, item: DraftItem, p: Picked): void { const arg = p.입력?.기계 ?? ""; if (item.키) { const was = `'개인 ${item.키}'`; for (const v of doc.변수 ?? []) { const l = v.연결; if (l?.갈래 === "단가산출" && l.입력?.기계 === was) { l.입력 = { ...l.입력, 기계: arg }; l.키 = p.키; } } } repick(doc, i, id, "기계", p); const box = doc as Holder; box[DRAFT_FIELD] = [...draftsOf(doc).filter((d) => d.표지 !== item.표지), item]; pruneDrafts(doc); } /** 기계 줄 연결 → 지금 기계 입력 글(따옴표 뗌) · 옵션 기호(`S_굴착기`)면 그 옵션 값 · 없음 = null */ export function machineNow( doc: FormulaDoc, link: { 갈래?: string; 입력?: Record }, ): string | null { const arg = link.갈래 === "단가산출" ? String(link.입력?.기계 ?? "").trim() : ""; if (!arg) return null; if (/^'.*'$/.test(arg)) return arg.slice(1, -1); const val = (doc.변수 ?? []).find((x) => varId(x) === arg)?.연결?.값; return val === undefined || val === null || String(val) === "" ? null : String(val); }