Files
Aislo/common_util/common_util_line_stack_unit.ts
T
eomsangdonandClaude Opus 5.5 badc24c0cc fix(845-2): 단가산출 단위 표시 규칙 한 벌 · 기계 산출근거 겹분수 중간 줄로 나눔
- 단위 규칙 한 벌(common_util_line_stack_unit) — 왼쪽 값 칸 · 식 줄 · 옵션 · 오른쪽 산출근거 · 기계 제어 구역 · 기계 보기가 같이 씀
  · 메타 단위(구분 따름 · 수(…) · 원문 단위 없음) 안 그림 · %(설명) = % · 10^-7 = 10⁻⁷ · 기계 칸 연결 = 기계 표 칸 단위 · 코드 값 쉼표 없음
- 비목 · 금액 줄 = 「단가 원/단위 × (수량 식) 단위 = 금액 원」 · 소계 · 합계 · 계 = 원 · 단가 · 수량 한 덩이(줄 바뀜에 단위 안 떨어짐)
- 기계경비식 겹분수 → 중간 줄(상여 · 휴지 · 손료계수 · common_util_line_stack_frac) · 한 줄 분수 한 층
- 기계 제어 구역 단위 = 칸 밖 바로 뒤 · 기계 보기 오른쪽 = 박기 전 기계 칸 단위
- 휴대폰 폭(560 px 밑) 산출근거 금액 칸 넷 걷음(가로 넘침 0) · 분수 줄 위아래 여유
- 전수 1,520 표시 탓 43,218 → 0 · 기계 겹분수 2 층 넘는 줄 1,040 → 0 · 금액 · 식 · 문서 자료 불변(그리기만)
- 시험 test_845_2_unit_show(차린 줄 글 전수 지킴) · shownUnit 걷음(규칙 한 벌로)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-15 22:44:36 +09:00

89 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* common_util_line_stack_unit.ts
* 단가산출 단위 그리는 규칙 한 벌(PLAN 845-2 · 요구 880) — 왼쪽 편집 · 오른쪽 산출근거 · 기계 제어 구역 · 기계 보기가 같이 씀
* ㉠ 값 줄 = 값 뒤 단위(`varUnit`) ㉡ 식 줄 = 결과 값 뒤만(식 가운데 숫자 뒤 없음)
* ㉢ 비목 · 금액 줄 = 「단가 원/단위 × (수량 식) 단위 = 금액 원」(`moneyUnits` — 수량이 식이면 괄호로 식 전체에 단위) ·
* 소계 · 합계 = 원(머리 [원/㎥] = 결과 하나당)
* ㉣ 무차원 = 빈 칸 ㉤ 율 = %(「%(인력품 대비)」 등 설명 괄호 뗌) ㉥ 왼쪽 값 칸 = 칸 바로 뒤 한 자리
* 메타 단위(「구분 따름」 · 「줄 따름」 · 「수(…)」 · 「원문 단위 없음」) = 단위 아님 → 안 그림 · 「10^-7」 = 10⁻⁷
* 기계 칸 연결(요소 `EQ:` 칸) 변수 = 변수 단위가 빈 칸이면 기계 표 칸 단위(`MACHINE_UNIT` — 기계 표 빌더 · 내 기계와 같은 글)
* 그리기만 — 자료 · 식 · 금액 불변 · 화면 없음(시험이 Node 로 돌림)
* ========================================================================== */
import type { DocVar, MoneyLine, Node } from "./common_util_formula_doc";
/** 기계 표 칸 단위(`build_기계_건설품셈.py` UNIT · `M02_MyMachine.py` UNITS 와 같은 글) */
export const MACHINE_UNIT: Record<string, string> = {
가격: "천원",
내용시간: "시간",
연간표준가동시간: "시간",
상각비계수: "10^-7/시간",
정비비계수: "10^-7/시간",
관리비계수: "10^-7/시간",
손료계수: "10^-7/시간",
주연료: "ℓ/hr",
전력: "kWh/hr",
잡재료율: "%",
잡품: "%",
조종원: "인/일",
인력: "인/일",
노무비: "원/시간",
재료비: "원/시간",
경비: "원/시간",
};
/** 금액 · 소계 · 합계 단위 */
export const AMOUNT_UNIT = "원";
/** 자료 단위 글 → 화면 단위(메타 = 빈 글) */
export function unitText(u: unknown): string {
const s = String(u ?? "").trim();
if (!s || /따름|원문 단위 없음/.test(s) || /^수(\(| 또는|$)/.test(s)) return "";
return s.replace(/^%\(.*\)$/, "%").replace(/10\^-7/g, "10⁻⁷");
}
/** 기계 칸 이름의 화면 단위 */
export const machineUnit = (col: string): string => unitText(MACHINE_UNIT[col]);
/** 변수 화면 단위 — 변수 단위 › 기계 칸 연결이면 기계 표 칸 단위 */
export function varUnit(v: DocVar | undefined): string {
const own = unitText(v?.단위);
if (own) return own;
const k = v?.연결;
return k?.갈래 === "요소" && /^EQ:/.test(String(k.키 ?? "")) && k.칸 ? machineUnit(k.칸) : "";
}
const HIDE = new Set(["반올림", "올림", "버림"]);
/** 한 덩이(기호 · 수 · 칸 — 감싸개 안 한 덩이 포함) */
export function isAtom(n: Node | null | undefined): boolean {
if (!n) return false;
if (n[0] === "call" && HIDE.has(n[1]) && n[2].length >= 1 && n[2].length <= 2)
return isAtom(n[2][0]);
return n[0] === "var" || n[0] === "num" || n[0] === "field" || n[0] === "str";
}
export interface MoneyUnits {
/** 단가 뒤(원/시간 · 원/인 …) — 단가가 한 덩이이고 수량이 있을 때만 */
price: string;
/** 수량 식 뒤 */
qty: string;
/** 수량 식을 괄호로 감쌈(식이고 단위가 있을 때) */
wrap: boolean;
}
/** 금액 줄 단위 자리(㉢) — `priceVar` = 단가 기호 변수 · `sub` = 묶음 · 단가산출 줄이 부르는 문서 */
export function moneyUnits(
line: MoneyLine,
price: Node | null,
qty: Node | null,
priceVar?: DocVar,
sub?: { 결과단위?: string } | null,
): MoneyUnits {
const has = line.수량 !== undefined && line.수량 !== null && line.수량 !== "";
const q = has ? unitText(line.단위) : "";
const wrap = !!q && !!qty && !isAtom(qty);
const own = [sub?.결과단위, priceVar?.단위].map(unitText).find((u) => u.startsWith("원"));
const p = has && isAtom(price) ? (own ?? (q ? `${AMOUNT_UNIT}/${q}` : "")) : "";
return { price: p, qty: q, wrap };
}