feat(m02-df): 흐름도 견본 넷 — 지반 가르기(조건 통과 선 둘) · 흄관 조건 찾기(재료 자리) · 다른 로직 잇기 · 메쌓기

- _sample/ground.json · hume.json · linked.json 새로 · rate.json 뺌(견본 넷에 없음) · value.json 은 linked 가 부르는 작업량 로직
- M02_DF_Sample.ts 목록 차례 · 쉬운 말 한 줄
- 시험 test_m02_df_sample.py — 모양 · 선 규칙 · 재료 방식 · 다른 로직 입력 · 출처 사슬 · 값(내부 확인)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BU9gbNE3aWFUvE61pS2WGt
This commit is contained in:
2026-10-01 19:46:46 +09:00
co-authored by Claude Opus 5.5
parent 92ffd41bc5
commit e2abd5a3c2
6 changed files with 1149 additions and 257 deletions
+22 -9
View File
@@ -1,13 +1,15 @@
/* =============================================================================
* M02_DF_Sample.ts
* 단가산출 다이어그램 견본 — 처음 열었을 때 바로 보고 따라 만들 견본 셋(`_sample/*.json` · 손으로 짬)
* ① 돌쌓기 메쌓기(인력) — 변수 · 품표 · 증가율표 · 인력 → 함수(표 찾기 · 높이 할증 · 직렬 · 병렬) → 출력 노무비
* ② 공구손료(비율) — 노무비 × 율 → 출력 재료비
* ③ 덤프트럭 시간당 작업량(값) — 변수 넷 → 함수 하나 → 출력 값
* 단가산출 흐름도 견본 — 처음 열었을 때 바로 보고 따라 만들 견본(`_sample/*.json` · 손으로 짬)
* ① 돌쌓기 메쌓기(인력) — 변수 · 품표 · 증가율표 · 인력 → 표 찾기 · 높이 할증(직렬) · 품 × 노임(병렬) → 노무비
* ② 지반 가르기 — 같은 굴착량이 「조건 통과」 선 둘(지반 = 토사 / ≠ 토사)로 굴삭기 · 브레이커에 감 → 경비
* ③ 흄관 관경 조건 찾기 — 재료 자리(조건 찾기 · 규격에 관경 포함) → 본수 × 단가 → 재료비
* ④ 다른 로직 잇기 — 작업량 로직(⑤) 출력 → 장비 시간 → 경비
* ⑤ 덤프트럭 시간당 작업량(값) — ④ 가 부르는 다른 로직
* 견본은 읽기만 — `sampleLoad` 는 「복사해서 열기」 사본(key 없음 · 저장하면 `_data` 에 새 번호).
* 입력 값(노임 · 표)은 견본에 안 들고 열 때 · 저장 때 마스터에서 받음(정함 「계산」).
* 모양 = `M02_DF_Model` CfLogic · 알약 이름 규칙(입력 = 요소 이름 · 「표」 · 변수 이름 / 함수 = inputs[].port ·
* output.name / 출력 = 「값」) — 정함 `docs/raw/M01_쉬운단가/원가다이어그램_정함.md` 11. 이 폴더째 지워도 됨.
* 입력 값(노임 · 표 · 재료)은 견본에 안 들고 열 때 · 저장 때 마스터에서 받음.
* 모양 = `M02_DF_Model` CfLogic(선 규칙 · 재료 방식 · 다른 로직 입력 포함) · 알약 이름 규칙 — 정함
* `docs/raw/M01_쉬운단가/흐름도_정함.md` 1 · 4~7 · 12. 이 폴더째 지워도 됨.
* ========================================================================== */
import { currentLanguageIndex } from "@ui/ui_template_locale";
@@ -21,7 +23,18 @@ const NOTE: Record<string, readonly [string, string]> = {
"변수 · 품표 · 증가율표 · 인력 → 표 찾기 · 높이 할증 → 품 × 노임 → 노무비",
"Variables, tables and labor → lookup, height surcharge → crew × wage → labor cost",
],
rate: ["노무비 × 공구손료율 → 재료비", "Labor cost × small-tools rate → material 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)",
@@ -29,7 +42,7 @@ const NOTE: Record<string, readonly [string, string]> = {
};
/** 보여 줄 차례 */
const ORDER = ["masonry", "rate", "value"];
const ORDER = ["masonry", "ground", "hume", "linked", "value"];
export interface CfSampleItem {
/** 파일 이름(확장자 뺌) */
@@ -0,0 +1,423 @@
{
"key": "SAMPLE-ground",
"name": "견본 · 지반에 따라 굴삭기 / 브레이커",
"resultUnit": "원/㎥",
"boxes": [
{
"id": "in-ground",
"kind": "input",
"name": "지반 · 굴착량",
"color": "#2f80ed",
"unit": "-",
"x": 40,
"y": 60,
"input": {
"mode": "variable",
"elements": [],
"variables": [
{
"name": "지반",
"type": "choice",
"unit": "-",
"example": "토사",
"choices": ["토사", "암"]
},
{
"name": "굴착량",
"type": "number",
"unit": "㎥",
"example": 100
}
]
}
},
{
"id": "in-cost",
"kind": "input",
"name": "장비 시간당 경비",
"color": "#2f80ed",
"unit": "원/시간",
"x": 40,
"y": 300,
"input": {
"mode": "variable",
"elements": [],
"variables": [
{
"name": "굴삭기 시간당 경비",
"type": "number",
"unit": "원/시간",
"example": 60000
},
{
"name": "브레이커 시간당 경비",
"type": "number",
"unit": "원/시간",
"example": 80000
}
]
}
},
{
"id": "fn-exc",
"kind": "function",
"name": "굴삭기로 파기",
"color": "#7b4fd6",
"unit": "원",
"x": 380,
"y": 40,
"func": {
"sheet": {
"id": "s-fn-exc",
"이름": "굴삭기로 파기",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "굴착량"
},
"C2": {
"값": "받는 값 · 지반이 토사일 때만 옴"
},
"A3": {
"값": "시간당 경비"
},
"C3": {
"값": "받는 값 · 원/시간"
},
"A4": {
"값": "시간당 작업량"
},
"B4": {
"값": 30
},
"C4": {
"값": "㎥/시간 · 고침"
},
"A5": {
"값": "작업 시간"
},
"B5": {
"식": "B2/B4"
},
"C5": {
"값": "시간"
},
"A6": {
"값": "굴삭기 경비"
},
"B6": {
"식": "B5*B3"
},
"C6": {
"값": "원"
}
}
},
"inputs": [
{
"port": "굴착량",
"cell": "B2"
},
{
"port": "시간당 경비",
"cell": "B3"
}
],
"variables": [],
"output": {
"cell": "B6",
"name": "굴삭기 경비",
"unit": "원"
}
}
},
{
"id": "fn-brk",
"kind": "function",
"name": "브레이커로 깨기",
"color": "#7b4fd6",
"unit": "원",
"x": 380,
"y": 300,
"func": {
"sheet": {
"id": "s-fn-brk",
"이름": "브레이커로 깨기",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "굴착량"
},
"C2": {
"값": "받는 값 · 지반이 토사가 아닐 때만 옴"
},
"A3": {
"값": "시간당 경비"
},
"C3": {
"값": "받는 값 · 원/시간"
},
"A4": {
"값": "시간당 작업량"
},
"B4": {
"값": 8
},
"C4": {
"값": "㎥/시간 · 고침"
},
"A5": {
"값": "작업 시간"
},
"B5": {
"식": "B2/B4"
},
"C5": {
"값": "시간"
},
"A6": {
"값": "브레이커 경비"
},
"B6": {
"식": "B5*B3"
},
"C6": {
"값": "원"
}
}
},
"inputs": [
{
"port": "굴착량",
"cell": "B2"
},
{
"port": "시간당 경비",
"cell": "B3"
}
],
"variables": [],
"output": {
"cell": "B6",
"name": "브레이커 경비",
"unit": "원"
}
}
},
{
"id": "fn-sum",
"kind": "function",
"name": "1㎥ 경비",
"color": "#7b4fd6",
"unit": "원/㎥",
"x": 720,
"y": 170,
"func": {
"sheet": {
"id": "s-fn-sum",
"이름": "1㎥ 경비",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "굴삭기 경비"
},
"C2": {
"값": "받는 값 · 안 오면 빈 칸 = 0"
},
"A3": {
"값": "브레이커 경비"
},
"C3": {
"값": "받는 값 · 안 오면 빈 칸 = 0"
},
"A4": {
"값": "굴착량"
},
"C4": {
"값": "받는 값 · ㎥"
},
"A5": {
"값": "1㎥ 경비"
},
"B5": {
"식": "(B2+B3)/B4"
},
"C5": {
"값": "둘 중 온 것 ÷ 굴착량"
}
}
},
"inputs": [
{
"port": "굴삭기 경비",
"cell": "B2"
},
{
"port": "브레이커 경비",
"cell": "B3"
},
{
"port": "굴착량",
"cell": "B4"
}
],
"variables": [],
"output": {
"cell": "B5",
"name": "1㎥ 경비",
"unit": "원/㎥"
}
}
},
{
"id": "out-exp",
"kind": "output",
"name": "경비",
"color": "#27ae60",
"unit": "원/㎥",
"x": 1040,
"y": 170,
"output": {
"cost": "경비",
"unit": "원/㎥",
"round": {
"places": 1,
"method": "버림"
}
}
}
],
"links": [
{
"id": "l1",
"from": {
"box": "in-ground",
"name": "굴착량"
},
"to": {
"box": "fn-exc",
"name": "굴착량"
},
"rule": {
"kind": "gate",
"from": {
"box": "in-ground",
"name": "지반"
},
"op": "=",
"value": "토사"
}
},
{
"id": "l2",
"from": {
"box": "in-ground",
"name": "굴착량"
},
"to": {
"box": "fn-brk",
"name": "굴착량"
},
"rule": {
"kind": "gate",
"from": {
"box": "in-ground",
"name": "지반"
},
"op": "≠",
"value": "토사"
}
},
{
"id": "l3",
"from": {
"box": "in-cost",
"name": "굴삭기 시간당 경비"
},
"to": {
"box": "fn-exc",
"name": "시간당 경비"
}
},
{
"id": "l4",
"from": {
"box": "in-cost",
"name": "브레이커 시간당 경비"
},
"to": {
"box": "fn-brk",
"name": "시간당 경비"
}
},
{
"id": "l5",
"from": {
"box": "fn-exc",
"name": "굴삭기 경비"
},
"to": {
"box": "fn-sum",
"name": "굴삭기 경비"
}
},
{
"id": "l6",
"from": {
"box": "fn-brk",
"name": "브레이커 경비"
},
"to": {
"box": "fn-sum",
"name": "브레이커 경비"
}
},
{
"id": "l7",
"from": {
"box": "in-ground",
"name": "굴착량"
},
"to": {
"box": "fn-sum",
"name": "굴착량"
}
},
{
"id": "l8",
"from": {
"box": "fn-sum",
"name": "1㎥ 경비"
},
"to": {
"box": "out-exp",
"name": "값"
}
}
],
"userElements": []
}
@@ -0,0 +1,207 @@
{
"key": "SAMPLE-hume",
"name": "견본 · 흄관 관경 조건 찾기",
"resultUnit": "원/m",
"boxes": [
{
"id": "in-size",
"kind": "input",
"name": "관경 · 연장",
"color": "#2f80ed",
"unit": "-",
"x": 40,
"y": 60,
"input": {
"mode": "variable",
"elements": [],
"variables": [
{
"name": "관경",
"type": "choice",
"unit": "mm",
"example": 600,
"choices": [400, 450, 500, 600, 700, 800, 900, 1000, 1100, 1200]
},
{
"name": "연장",
"type": "number",
"unit": "m",
"example": 10
}
]
}
},
{
"id": "in-pipe",
"kind": "input",
"name": "흄관",
"color": "#2f80ed",
"unit": "본",
"x": 40,
"y": 300,
"input": {
"mode": "group",
"group": "재료",
"variables": [],
"elements": [
{
"ref": "MT014991",
"name": "흄관",
"spec": "Φ600mm",
"unit": "본",
"mode": "rule",
"scope": {
"구분": "관·이음관",
"상세구분": "흄관",
"찾는말": "접속흄관"
},
"rule": {
"field": "규격",
"op": "포함",
"from": {
"box": "in-size",
"name": "관경"
}
},
"default": "MT014991",
"slot": "흄관"
}
]
}
},
{
"id": "fn-pipe",
"kind": "function",
"name": "흄관 재료비",
"color": "#7b4fd6",
"unit": "원/m",
"x": 380,
"y": 160,
"func": {
"sheet": {
"id": "s-fn-pipe",
"이름": "흄관 재료비",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "연장"
},
"C2": {
"값": "받는 값 · m"
},
"A3": {
"값": "흄관 단가"
},
"C3": {
"값": "받는 값 · 원/본(관경으로 찾은 품목)"
},
"A4": {
"값": "1본 길이"
},
"B4": {
"값": 2.5
},
"C4": {
"값": "m · 고침"
},
"A5": {
"값": "본수"
},
"B5": {
"식": "ROUNDUP(B2/B4,0)"
},
"C5": {
"값": "올림"
},
"A6": {
"값": "1m 재료비"
},
"B6": {
"식": "B5*B3/B2"
},
"C6": {
"값": "본수 × 단가 ÷ 연장"
}
}
},
"inputs": [
{
"port": "연장",
"cell": "B2"
},
{
"port": "흄관 단가",
"cell": "B3"
}
],
"variables": [],
"output": {
"cell": "B6",
"name": "1m 재료비",
"unit": "원/m"
}
}
},
{
"id": "out-mat",
"kind": "output",
"name": "재료비",
"color": "#27ae60",
"unit": "원/m",
"x": 720,
"y": 160,
"output": {
"cost": "재료비",
"unit": "원/m",
"round": {
"places": 1,
"method": "버림"
}
}
}
],
"links": [
{
"id": "l1",
"from": {
"box": "in-size",
"name": "연장"
},
"to": {
"box": "fn-pipe",
"name": "연장"
}
},
{
"id": "l2",
"from": {
"box": "in-pipe",
"name": "흄관"
},
"to": {
"box": "fn-pipe",
"name": "흄관 단가"
}
},
{
"id": "l3",
"from": {
"box": "fn-pipe",
"name": "1m 재료비"
},
"to": {
"box": "out-mat",
"name": "값"
}
}
],
"userElements": []
}
@@ -0,0 +1,302 @@
{
"key": "SAMPLE-linked",
"name": "견본 · 다른 로직 잇기(작업량 → 장비 시간)",
"resultUnit": "원/㎥",
"boxes": [
{
"id": "in-logic",
"kind": "input",
"name": "덤프트럭 시간당 작업량",
"color": "#2f80ed",
"unit": "㎥/시간",
"x": 40,
"y": 60,
"input": {
"mode": "logic",
"elements": [],
"variables": [],
"logic": {
"key": "value",
"name": "견본 · 덤프트럭 시간당 작업량(값)",
"outputs": [
{
"name": "시간당 작업량",
"unit": "㎥/시간"
}
],
"designs": [
{
"name": "q",
"unit": "㎥"
},
{
"name": "f",
"unit": "-"
},
{
"name": "E",
"unit": "-"
},
{
"name": "Cm",
"unit": "분"
}
]
}
}
},
{
"id": "in-var",
"kind": "input",
"name": "운반량 · 경비",
"color": "#2f80ed",
"unit": "-",
"x": 40,
"y": 300,
"input": {
"mode": "variable",
"elements": [],
"variables": [
{
"name": "운반량",
"type": "number",
"unit": "㎥",
"example": 120
},
{
"name": "덤프트럭 시간당 경비",
"type": "number",
"unit": "원/시간",
"example": 50000
}
]
}
},
{
"id": "fn-hours",
"kind": "function",
"name": "운반 시간",
"color": "#7b4fd6",
"unit": "시간",
"x": 380,
"y": 60,
"func": {
"sheet": {
"id": "s-fn-hours",
"이름": "운반 시간",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "시간당 작업량"
},
"C2": {
"값": "받는 값 · 다른 로직 출력"
},
"A3": {
"값": "운반량"
},
"C3": {
"값": "받는 값 · ㎥"
},
"A4": {
"값": "운반 시간"
},
"B4": {
"식": "B3/B2"
},
"C4": {
"값": "운반량 ÷ 시간당 작업량"
}
}
},
"inputs": [
{
"port": "시간당 작업량",
"cell": "B2"
},
{
"port": "운반량",
"cell": "B3"
}
],
"variables": [],
"output": {
"cell": "B4",
"name": "운반 시간",
"unit": "시간",
"round": {
"places": 2,
"method": "반올림"
}
}
}
},
{
"id": "fn-cost",
"kind": "function",
"name": "1㎥ 운반 경비",
"color": "#7b4fd6",
"unit": "원/㎥",
"x": 700,
"y": 180,
"func": {
"sheet": {
"id": "s-fn-cost",
"이름": "1㎥ 운반 경비",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "운반 시간"
},
"C2": {
"값": "받는 값 · 시간"
},
"A3": {
"값": "시간당 경비"
},
"C3": {
"값": "받는 값 · 원/시간"
},
"A4": {
"값": "운반량"
},
"C4": {
"값": "받는 값 · ㎥"
},
"A5": {
"값": "1㎥ 운반 경비"
},
"B5": {
"식": "B2*B3/B4"
},
"C5": {
"값": "시간 × 경비 ÷ 운반량"
}
}
},
"inputs": [
{
"port": "운반 시간",
"cell": "B2"
},
{
"port": "시간당 경비",
"cell": "B3"
},
{
"port": "운반량",
"cell": "B4"
}
],
"variables": [],
"output": {
"cell": "B5",
"name": "1㎥ 운반 경비",
"unit": "원/㎥"
}
}
},
{
"id": "out-exp",
"kind": "output",
"name": "경비",
"color": "#27ae60",
"unit": "원/㎥",
"x": 1020,
"y": 180,
"output": {
"cost": "경비",
"unit": "원/㎥",
"round": {
"places": 1,
"method": "버림"
}
}
}
],
"links": [
{
"id": "l1",
"from": {
"box": "in-logic",
"name": "시간당 작업량"
},
"to": {
"box": "fn-hours",
"name": "시간당 작업량"
}
},
{
"id": "l2",
"from": {
"box": "in-var",
"name": "운반량"
},
"to": {
"box": "fn-hours",
"name": "운반량"
}
},
{
"id": "l3",
"from": {
"box": "fn-hours",
"name": "운반 시간"
},
"to": {
"box": "fn-cost",
"name": "운반 시간"
}
},
{
"id": "l4",
"from": {
"box": "in-var",
"name": "덤프트럭 시간당 경비"
},
"to": {
"box": "fn-cost",
"name": "시간당 경비"
}
},
{
"id": "l5",
"from": {
"box": "in-var",
"name": "운반량"
},
"to": {
"box": "fn-cost",
"name": "운반량"
}
},
{
"id": "l6",
"from": {
"box": "fn-cost",
"name": "1㎥ 운반 경비"
},
"to": {
"box": "out-exp",
"name": "값"
}
}
],
"userElements": []
}
@@ -1,146 +0,0 @@
{
"key": "SAMPLE-rate",
"name": "견본 · 공구손료(비율)",
"resultUnit": "원",
"boxes": [
{
"id": "in-var",
"kind": "input",
"name": "바탕 값",
"color": "#2f80ed",
"unit": "-",
"x": 40,
"y": 80,
"input": {
"mode": "variable",
"elements": [],
"variables": [
{
"name": "노무비",
"type": "number",
"unit": "원",
"example": 100000
},
{
"name": "공구손료율",
"type": "number",
"unit": "%",
"example": 3
}
]
}
},
{
"id": "fn-rate",
"kind": "function",
"name": "공구손료",
"color": "#7b4fd6",
"unit": "원",
"x": 340,
"y": 80,
"func": {
"sheet": {
"id": "cf-tool",
"이름": "공구손료",
"칸": {
"A1": {
"값": "이름"
},
"B1": {
"값": "값"
},
"C1": {
"값": "설명"
},
"A2": {
"값": "노무비"
},
"C2": {
"값": "받는 값 · 원"
},
"A3": {
"값": "공구손료율"
},
"C3": {
"값": "받는 값 · %"
},
"A4": {
"값": "공구손료"
},
"B4": {
"식": "B2*B3/100"
},
"C4": {
"값": "노무비 × 율 ÷ 100"
}
}
},
"inputs": [
{
"port": "노무비",
"cell": "B2"
},
{
"port": "공구손료율",
"cell": "B3"
}
],
"variables": [],
"output": {
"cell": "B4",
"name": "공구손료",
"unit": "원"
}
}
},
{
"id": "out-mat",
"kind": "output",
"name": "재료비",
"color": "#27ae60",
"unit": "원",
"x": 640,
"y": 80,
"output": {
"cost": "재료비",
"unit": "원"
}
}
],
"links": [
{
"id": "l1",
"from": {
"box": "in-var",
"name": "노무비"
},
"to": {
"box": "fn-rate",
"name": "노무비"
}
},
{
"id": "l2",
"from": {
"box": "in-var",
"name": "공구손료율"
},
"to": {
"box": "fn-rate",
"name": "공구손료율"
}
},
{
"id": "l3",
"from": {
"box": "fn-rate",
"name": "공구손료"
},
"to": {
"box": "out-mat",
"name": "값"
}
}
],
"userElements": []
}