- M02 SK 「수식」 탭 = M01 과 같은 공용 화면(`createDocScreen` · 길 앞머리만 `/m02/layers/{층}/sangeun/{키}/doc`) — 옛 M02 수식 나무 화면(`_Sangeun_Equation.ts` · 796-2b · 2c · 2e · 800 · 801 꼴) 걷음
· 옵션 = SK 문서 값(저장) · [단가 갱신] · [재생성](미리 셈 → 알림 계 전 → 후 · 버리는 것 → 저장) · 「M01 새 판 있음」 배지(`formula_doc_copy.ts`)
· 단가산출 연결 펼침 머리 「연결 / 끊음」 · [연결 끊기] · [다시 잇기] · 끊은 문서 안 줄 그 자리 고침(`formula_doc_sub.ts`) · 저장 몸 {문서, 끊음, 판}
· 층 쓰기 권한 없음 = 읽기만(옵션 잠금 · 단추 없음 · 「읽기만」) · 판 바뀜 409 = 사본 같으면 새 판으로 한 번 더 · 저장 뒤 페이지 판 · 상세 탭 `수식` 칸 새로
· 저장 안 한 SK(일위대가 줄 모달) = 「저장한 단가산출만」 글
- 서버 — 수식 길 답에 `연결`(화면 캐시 기록 · `M02_Doc_Screen.record`) · 연결 후보 · 표 길(층 읽기 · M01 후보 · 표 그대로 · main 등록)
- 꺼진 줄(요구 663-1 마저) — 곱 인수 하나가 선택으로 꺼진 0(만약 0 갈래 · 식 줄 기호면 그 식으로 거침)이면 숨김 · 입력 · 글 0 은 그대로
· 판정을 순수 파일로(`common_util_formula_doc_view.ts` · Node 로 시험) · 1,518 문서 기본 옵션 꺼짐 158 → 203 줄(꺼진 줄 금액 모두 0) · GC000211 폼타이 아님 = 세 규격 줄 모두
- 화면 파일 700 줄 — 고침 함수 · 옵션 가로 · 연결 펼침을 새 파일로(`formula_doc_edit` · `_options` · `_sub`)
- 시험 test_802_4b2(5 · 헬퍼 helper_802_4b2_off.cjs) · 옛 시험 둘 고침 — test_793_3b · test_796_2b 가 걷은 옛 M02 수식 화면 글을 읽음 → 없음 확인으로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
/* =============================================================================
|
|
* formula_doc_edit.ts
|
|
* 수식 문서 고침(PLAN 802-3 · 802-4b-2) — 식 줄 · 금액 줄 · 값 식 숫자 고침을 문서에 얹음(화면 · fetch 없음)
|
|
* 수식 화면(`formula_doc_screen.ts`)과 끊은 단가산출 블록(`formula_doc_sub.ts`)이 같은 고침을 씀
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
goodId,
|
|
splitId,
|
|
tidy,
|
|
varId,
|
|
type DocVar,
|
|
type FormulaDoc,
|
|
type MoneyLine,
|
|
} from "../common_util/common_util_formula_doc";
|
|
import { swapLit } from "./formula_doc_render";
|
|
|
|
/** 머리 = 식 — 첫 「=」(비교 ==, <=, >=, != 빼고) */
|
|
export function splitLine(text: string): [string | null, string] {
|
|
const m = /^([^=<>!]*?)\s*(?<![<>!=])=(?!=)\s*([\s\S]*)$/.exec(text);
|
|
if (!m) return [null, text.trim()];
|
|
return [m[1].trim(), m[2].trim()];
|
|
}
|
|
|
|
export const tidyText = (t: string): string => (t.trim() ? tidy(t.trim()) : "");
|
|
|
|
/** 기호 정의 — 없으면 「식」 갈래로 새로 */
|
|
export function ensureVar(d: FormulaDoc, id: string): DocVar {
|
|
const have = (d.변수 ??= []).find((v) => varId(v) === id);
|
|
if (have) return have;
|
|
const [기호, 아래, 위] = splitId(id);
|
|
const v: DocVar = { 열쇠: id, 기호, 아래, 위, 이름: "", 단위: "", 연결: { 갈래: "식" } };
|
|
d.변수.push(v);
|
|
return v;
|
|
}
|
|
|
|
/** 식 줄 i 를 글로 — 빈 글 = 줄 지움 · 머리 바뀜 = 식 갈래 정의도 같이 */
|
|
export function editLine(d: FormulaDoc, i: number, text: string): void {
|
|
const lines = (d.식 ??= []);
|
|
const line = lines[i];
|
|
if (!line) return;
|
|
if (!text.trim()) {
|
|
lines.splice(i, 1);
|
|
return;
|
|
}
|
|
const [h, body] = splitLine(text);
|
|
const old = String(line.기호 ?? "");
|
|
if (h !== null && h !== old) {
|
|
line.기호 = h;
|
|
const was = (d.변수 ?? []).find((v) => varId(v) === old && (v.연결?.갈래 ?? "식") === "식");
|
|
if (was && goodId(h) && !(d.변수 ?? []).some((v) => varId(v) === h)) {
|
|
const [기호, 아래, 위] = splitId(h);
|
|
Object.assign(was, { 기호, 아래, 위 });
|
|
}
|
|
}
|
|
line.식 = tidyText(body);
|
|
}
|
|
|
|
/** 금액 줄 i 고침(null = 지움) — 단가 · 수량 글은 다듬음 · 빈 수량 = 칸 뺌 */
|
|
export function editMoney(d: FormulaDoc, i: number, patch: Partial<MoneyLine> | null): void {
|
|
const lines = (d.금액 ??= []);
|
|
if (!patch) {
|
|
lines.splice(i, 1);
|
|
return;
|
|
}
|
|
const line = lines[i];
|
|
if (!line) return;
|
|
for (const [k, v] of Object.entries(patch)) {
|
|
const text = typeof v === "string" && (k === "단가" || k === "수량") ? tidyText(v) : v;
|
|
if (k === "수량" && text === "") delete line.수량;
|
|
else (line as Record<string, unknown>)[k] = text;
|
|
}
|
|
}
|
|
|
|
/** 값 식 숫자 고침 — 식 줄 · 금액 줄 단가 · 수량 글의 at 번째 수 */
|
|
export function editLit(
|
|
d: FormulaDoc,
|
|
target: "line" | "price" | "qty",
|
|
i: number,
|
|
at: number,
|
|
value: number,
|
|
): void {
|
|
if (target === "line") {
|
|
const line = d.식?.[i];
|
|
if (line) line.식 = swapLit(String(line.식 ?? ""), at, value);
|
|
return;
|
|
}
|
|
const line = d.금액?.[i];
|
|
if (!line) return;
|
|
const slot = target === "price" ? "단가" : "수량";
|
|
line[slot] = swapLit(String(line[slot] ?? ""), at, value);
|
|
}
|