/* ============================================================================= * M02_DF_Sample.ts * 단가산출 흐름도 견본 — 처음 열었을 때 바로 보고 따라 만들 견본(`_sample/*.json` · 손으로 짬) * ① 돌쌓기 메쌓기(인력) — 변수 · 품표 · 증가율표 · 인력 → 표 찾기 · 높이 할증(직렬) · 품 × 노임(병렬) → 노무비 * ② 지반 가르기 — 같은 굴착량이 「조건 통과」 선 둘(지반 = 토사 / ≠ 토사)로 굴삭기 · 브레이커에 감 → 경비 * ③ 흄관 관경 조건 찾기 — 재료 자리(조건 찾기 · 규격에 관경 포함) → 본수 × 단가 → 재료비 * ④ 다른 로직 잇기 — 작업량 로직(⑤) 출력 → 장비 시간 → 경비 * ⑤ 덤프트럭 시간당 작업량(값) — ④ 가 부르는 다른 로직 * 견본은 읽기만 — `sampleLoad` 는 「복사해서 열기」 사본(key 없음 · 저장하면 `_data` 에 새 번호). * 입력 값(노임 · 표 · 재료)은 견본에 안 들고 열 때 · 저장 때 마스터에서 받음. * 모양 = `M02_DF_Model` CfLogic(선 규칙 · 재료 방식 · 다른 로직 입력 포함) · 알약 이름 규칙 — 정함 * `docs/raw/M01_쉬운단가/흐름도_정함.md` 1 · 4~7 · 12. 이 폴더째 지워도 됨. * ========================================================================== */ import { currentLanguageIndex } from "@ui/ui_template_locale"; import type { CfLogic } from "./M02_DF_Model"; const FILES = import.meta.glob("./_sample/*.json", { eager: true, import: "default" }); /** 견본마다 한 줄 설명 — [한, 영] */ const NOTE: Record = { masonry: [ "변수 · 품표 · 증가율표 · 인력 → 표 찾기 · 높이 할증 → 품 × 노임 → 노무비", "Variables, tables and labor → lookup, height surcharge → crew × wage → labor cost", ], ground: [ "지반이 토사면 굴삭기로 · 아니면 브레이커로 — 조건 통과 선 둘 → 경비", "Soil goes to the excavator, rock to the breaker — two gate lines → expense", ], hume: [ "관경으로 흄관 품목을 찾음(재료 자리 · 규격에 관경 포함) → 본수 × 단가 → 재료비", "Pipe size picks the hume pipe item (spec contains size) → count × price → material cost", ], linked: [ "작업량 로직의 출력을 받아 장비 시간 → 경비", "Takes the output of a productivity logic → machine hours → expense", ], value: [ "q · f · E · Cm → 60 × q × f × E ÷ Cm → 값(시간당 작업량)", "q, f, E, Cm → 60 × q × f × E ÷ Cm → value (output per hour)", ], }; /** 보여 줄 차례 */ const ORDER = ["masonry", "ground", "hume", "linked", "value"]; export interface CfSampleItem { /** 파일 이름(확장자 뺌) */ id: string; name: string; resultUnit: string; /** 쉬운 말 한 줄 */ note: string; } const idOf = (path: string): string => path.replace(/^.*\//, "").replace(/\.json$/, ""); const byId = (): Map => new Map(Object.entries(FILES).map(([path, lg]) => [idOf(path), lg])); /** 견본 목록 — 정한 차례 먼저 · 나머지는 이름 차례 */ export function sampleList(): CfSampleItem[] { const all = byId(); const rank = (id: string): number => (ORDER.includes(id) ? ORDER.indexOf(id) : ORDER.length); return [...all.entries()] .sort(([a, x], [b, y]) => rank(a) - rank(b) || x.name.localeCompare(y.name)) .map(([id, lg]) => ({ id, name: lg.name, resultUnit: lg.resultUnit, note: NOTE[id]?.[currentLanguageIndex === 1 ? 1 : 0] ?? "", })); } /** 견본 하나 「복사해서 열기」 — 깊은 사본 · key 없음(저장하면 서버가 새 번호) · 없으면 null */ export function sampleLoad(id: string): CfLogic | null { const lg = byId().get(id); return lg ? { ...(JSON.parse(JSON.stringify(lg)) as CfLogic), key: null } : null; }