From 0331bb4db2066a96cff0efe769894e066b2c87c2 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 20 Sep 2026 23:14:02 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat(M01):=20=EC=86=8C=EC=9A=94=EB=9F=89/?= =?UTF-8?q?=EA=B3=84=EC=88=98=20=E3=80=8C=EC=93=B0=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=E3=80=8D=20=ED=82=A4=EB=A5=BC=20=EB=88=84=EB=A5=B4?= =?UTF-8?q?=EB=A9=B4=20=EB=A1=9C=EC=A7=81=20=ED=83=AD=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B7=B8=20=EB=A1=9C=EC=A7=81=20=EB=B0=94=EB=A1=9C=20=EC=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logic_Page 에 openKey 초기 인자 + LogicHandle.openKey 추가(이미 연 뒤에도 재호출 가능) Page.ts 는 복사 안내 대신 로직 탭 전환과 동시에 그 로직을 엶 --- .../M01_MasterData_UI_Logic_Page.ts | 23 ++++++++++++++++++- M01_MasterData/M01_MasterData_UI_Page.ts | 17 ++++++-------- ui_template/ui_template_locale_m1.ts | 4 ---- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/M01_MasterData/M01_MasterData_UI_Logic_Page.ts b/M01_MasterData/M01_MasterData_UI_Logic_Page.ts index 92589788..0de623fd 100644 --- a/M01_MasterData/M01_MasterData_UI_Logic_Page.ts +++ b/M01_MasterData/M01_MasterData_UI_Logic_Page.ts @@ -27,6 +27,7 @@ import { type ElementBrief, type LogicFile, type LogicRow, + type LogicSummary, type SaveFile, } from "./M01_MasterData_UI_Logic_Api"; import { buildCalc } from "./M01_MasterData_UI_Logic_Calc"; @@ -68,7 +69,16 @@ function loadDrafts(): Record { } } -export async function mountM01Logic(host: HTMLElement, side: SideHandle): Promise { +export interface LogicHandle { + /** 밖(요소 화면)에서 이 키를 바로 엶 — 소요량·계수 표의 「쓰는 로직」 눌렀을 때. */ + openKey: (key: string) => Promise; +} + +export async function mountM01Logic( + host: HTMLElement, + side: SideHandle, + openKey?: string, +): Promise { let drafts = loadDrafts(); let files: LogicFile[] = []; let opened: Opened | null = null; @@ -220,6 +230,8 @@ export async function mountM01Logic(host: HTMLElement, side: SideHandle): Promis } }; + let allLogics: LogicSummary[] = []; + const reload = async (): Promise => { const [logics, logicFiles, subs] = await Promise.all([ fetchLogics(), @@ -227,6 +239,7 @@ export async function mountM01Logic(host: HTMLElement, side: SideHandle): Promis fetchLogicSubs(), ]); files = logicFiles; + allLogics = logics; list.setItems(logics); // 왼쪽 「전체」 + 구분 → 상세구분 거름 — 고르면 목록으로 돌아와 그 범위만 filterHost.replaceChildren( @@ -390,11 +403,19 @@ export async function mountM01Logic(host: HTMLElement, side: SideHandle): Promis side.logicHost.replaceChildren(filterHost); show(null); showLoadingOverlay(); + const openKeyOn = async (key: string): Promise => { + const found = allLogics.find((x) => x.키 === key); + if (found) await open(logicId(found.구분, found.키), found.구분, found.키); + else showToast(tx("Load_Failed"), "error"); + }; + try { await reload(); + if (openKey) await openKeyOn(openKey); } catch (error) { showToast(error instanceof Error ? error.message : tx("Load_Failed"), "error"); } finally { hideLoadingOverlay(); } + return { openKey: openKeyOn }; } diff --git a/M01_MasterData/M01_MasterData_UI_Page.ts b/M01_MasterData/M01_MasterData_UI_Page.ts index 61a863fc..2dab4fc7 100644 --- a/M01_MasterData/M01_MasterData_UI_Page.ts +++ b/M01_MasterData/M01_MasterData_UI_Page.ts @@ -33,6 +33,7 @@ import { type Pick, } from "./M01_MasterData_UI_Side"; import { renderTables } from "./M01_MasterData_UI_Tables"; +import type { LogicHandle } from "./M01_MasterData_UI_Logic_Page"; import "./M01_MasterData_UI_Style.css"; const TABLE_GROUPS = ["소요량", "계수"]; @@ -174,13 +175,9 @@ function buildPage(): HTMLElement { return [L("M01_Stale").replace("{value}", stale.map(fileLabel).join(", ")), again]; }; - /** 로직 탭으로 전환 — `key` 가 있으면 들고 가서 로직 목록 찾기 칸에 넣으라고 안내 - * (로직 목록이 직접 그 키를 열지는 못함 — 로직 부분은 sub1 담당 파일). */ - const notifyLogicKey = (key: string): void => { - navigator.clipboard?.writeText(key).catch(() => undefined); - showToast(L("M01_LogicKeyCopy").replace("{value}", key), "success"); - }; + let logicHandle: LogicHandle | null = null; + /** 로직 탭으로 전환 — `key` 가 있으면 그 로직을 바로 엶. */ const openLogicTab = (key?: string): void => { if (key) setPendingLogicKey(key); dispose(); @@ -188,14 +185,14 @@ function buildPage(): HTMLElement { current = null; showMode("logic"); if (logicMounted) { - if (key) notifyLogicKey(key); + const pending = takePendingLogicKey(); + if (pending) void logicHandle?.openKey(pending); return; } logicMounted = true; - void import("./M01_MasterData_UI_Logic_Page").then((m) => { - void m.mountM01Logic(logicHost, side); + void import("./M01_MasterData_UI_Logic_Page").then(async (m) => { const pending = takePendingLogicKey(); - if (pending) notifyLogicKey(pending); + logicHandle = await m.mountM01Logic(logicHost, side, pending ?? undefined); }); }; diff --git a/ui_template/ui_template_locale_m1.ts b/ui_template/ui_template_locale_m1.ts index 3b4af4f0..3d0af7c7 100644 --- a/ui_template/ui_template_locale_m1.ts +++ b/ui_template/ui_template_locale_m1.ts @@ -64,10 +64,6 @@ export const ui_locales_m1 = { M01_TableUsage: ["용도", "Usage"], M01_TableUsageLogicCount: ["로직 {value}개", "{value} logic rules"], M01_OpenLogic: ["눌러 로직 탭으로", "Click to jump to the Logic tab"], - M01_LogicKeyCopy: [ - "로직 탭으로 이동 — 키 {value} 복사함(찾기에 붙여넣을 것)", - "Switched to Logic tab — copied key {value} (paste it into the search box)", - ], M01_GroupLabor: ["인력", "Labor"], M01_GroupMaterial: ["재료", "Materials"], M01_GroupMachine: ["기계", "Machines"], From a7643887ca9f90e88af7df637bdda650baba18c2 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 20 Sep 2026 23:14:48 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat(master=5Fdata):=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=EC=97=90=20=EC=84=A4=EB=AA=85=20=EC=B9=B8?= =?UTF-8?q?=20=C2=B7=20=EC=82=B0=EB=A6=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=8C=80=EC=83=81=2010=EA=B0=9C=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=84=A4=EB=AA=85=20=EC=B1=84=EC=9B=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `_틀.md` 7장 — 입력 칸 목록과 `설명`(쉬운 말 한 줄) · `시험입력` · 고르기 후보 단위 거르기 · 조건 값의 `{입력}` 자리 - 테스트 컨테이너 대상 10개 로직의 입력 97개에 설명 채움 — 서버는 줄을 그대로 내려보내 화면 도움말로 쓸 수 있음 - 로직_건설품셈_09장_미장공사.json 머리에 겹친 「부문」 칸 지움 - 시험 하나 더함 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj --- resources/master_data/_틀.md | 14 ++- .../로직_건설품셈_09장_미장공사.json | 1 - .../로직_산림품셈_07장_집재_및_운재.json | 9 +- .../master_data/로직_산림품셈_09장_토공.json | 3 +- .../로직_산림품셈_10장_자재․장비_운반.json | 4 +- .../로직_산림품셈_12장_철근콘크리트.json | 86 ++++++++++++++++++- .../로직_산림품셈_13장_구조물.json | 10 +-- resources/tester/test_masterdata_check.py | 23 +++++ 8 files changed, 132 insertions(+), 18 deletions(-) diff --git a/resources/master_data/_틀.md b/resources/master_data/_틀.md index 39c34268..6c597c12 100644 --- a/resources/master_data/_틀.md +++ b/resources/master_data/_틀.md @@ -182,8 +182,13 @@ "출처": "산림품셈 13-4-1", "소유": "공용", "입력": [ - { "이름": "뒷길이", "단위": "㎝" }, - { "이름": "돌", "고르기": ["견치돌", "깬돌", "깬잡석", "호박돌 및 야면석"] } + { "이름": "뒷길이", "설명": "쌓을 돌의 뒤쪽 길이", "단위": "㎝" }, + { + "이름": "돌", + "설명": "쌓을 돌 종류", + "고르기": ["견치돌", "깬돌", "깬잡석", "호박돌 및 야면석"], + "출처": "산림품셈 13-4-1" + } ], "중간": [{ "이름": "증가율", "식": "…" }], "호표": [{ "종류": "인력", "요소": "LB000002", "단위": "인", "수량": "…", "비목": "노무비" }], @@ -217,13 +222,18 @@ - 구분·상세구분 = 자재품목 줄의 같은 이름 칸과 똑같이 적음(묶음 목록은 `ref/_묶음_자재품목.md`). - 규격 조건 = 원문이 규격을 밝힌 것만 좁힘 — 낱말이 **모두** 든 줄이 후보(「D300」 · 「D300 B종」) · 대소문자·빈칸·`φ` 는 안 가림. 원문이 규격을 안 밝히면 칸을 두지 않음. - 대표 줄 = 관리자가 고른 자재품목 키 — 시험 계산이 그 줄의 값을 씀. 조건 밖 키는 검사가 잡음. +- 후보는 **호표 줄 단위와 같은 자재품목 줄만** — 단위가 다르면 다른 물건(우드칩 ㎥ · 원목후로링 ㎡). 조건 안 줄이 모두 다른 단위면 `check_master 단위` 가 알림. +- 조건 값에 `{입력}` 을 넣을 수 있음 — `"규격": "{관경}"` 은 계산 때 입력값으로 채워짐(검사에서는 그 칸을 뺌). - 대표가 없으면 시험 계산은 **조건 안 값 있는 첫 줄** · 로직 입력 `자재지역` 이 있으면 이름에 그 지역이 든 줄부터(레미콘·골재처럼 지역이 갈리는 품목). - 실제 줄 고르기는 프로젝트 몫 — 후보 목록은 `GET /api/m01/materials`(화면·테스트 컨테이너가 같이 씀). - 옛 방식(품셈재료 키 `MP…` · 자재품목 키 `MT…`)도 그대로 돎 — 품셈재료 `고르기` 칸이 빈 줄(연결이 이미 있는 줄 · 짝 못 찾은 줄)과 `{이름}` 이 낀 원문번호 줄은 계속 옛 방식. - 근거가 덜 선 줄은 `비고` 칸에 적음 — 「환산 근거 미확인」. +- 입력 칸 = `이름`(반드시) · `설명` · `단위` · `고르기`·`범위`(둘 중 하나까지) · `출처`(원문 절) · `비고` · `시험입력`은 줄 머리에 따로. +- `설명` = 설계자에게 보일 **쉬운 말 한 줄** — 무엇을 넣는 칸인지만(명사형 · 계산 방법·근거는 `비고`·`출처` 로). 화면은 이름 옆 도움말로 씀. - 입력에 원문 범위가 있으면 `범위: [아래, 위]` · 기본값 두지 않음. - `소유` = 공용 · 개인(뒤 단계 자리). +- `시험입력` = 일괄 시험 계산 전용 칸(`check_master 계산전부`) — 설계 입력이 없으면 못 도는 로직에 원문 표 첫 규격·자재지역을 한 벌 둠. 정본 계산은 화면이 준 값만 씀. ## 8. 변수 · 식 diff --git a/resources/master_data/로직_건설품셈_09장_미장공사.json b/resources/master_data/로직_건설품셈_09장_미장공사.json index 211c0a45..cf9012c5 100644 --- a/resources/master_data/로직_건설품셈_09장_미장공사.json +++ b/resources/master_data/로직_건설품셈_09장_미장공사.json @@ -3,7 +3,6 @@ "원문": "건설품셈", "부문": "건축", "차례": 37, - "부문": "건축", "판": "2026", "줄": [ { diff --git a/resources/master_data/로직_산림품셈_07장_집재_및_운재.json b/resources/master_data/로직_산림품셈_07장_집재_및_운재.json index 2e7746a1..34e87b70 100644 --- a/resources/master_data/로직_산림품셈_07장_집재_및_운재.json +++ b/resources/master_data/로직_산림품셈_07장_집재_및_운재.json @@ -528,12 +528,13 @@ "비고": "해석: 건설기계조종원·운전기사 = 건설노임 건설기계운전사(1048) · 해석: 할증을 인력 · 연료 · 손료(가동일)에 함께 곱함 · 해석: 우드그래플 소모성경비(2-1-3) = Q × (트랙 보강 + 블레이드·실린더) 원/ha ÷ 집재재적 · 기계손료 못 넣음 — 기계 열쇠 「2-2-3 동력상하차기, 임업용 굴착기(우드그래플)」 에 쉼표(식이 열쇠를 끊음) · 경계값(아래 끝 수 그대로)은 못 찾음 — 범위규칙 「이하 · 이상 · 두 수는 양 끝 포함」 을 엔진이 「이하」로만 읽음 · 할인·할증 못 넣음 — 1-4-5 경사도(값 칸 「할인·할증률」) · 1-4-13 주행 장애물 상태(조건 빈칸) — 칸 이름 · 범위규칙 문법", "시험입력": {"최대집재거리": 40.0, "집재재적": 60.0}, "입력": [ - { "이름": "최대집재거리", "단위": "m" }, - { "이름": "집재재적", "단위": "㎥/ha" }, - { "이름": "원목길이", "단위": "m", "고르기": [1.2, 1.8, 2.1, 2.7, 3.6] }, - { "이름": "잔존목", "고르기": ["잔존목 100본 이상 130본 이하", "잔존목 71본 이상 100본 미만", "해당 없음"] }, + { "이름": "최대집재거리", "설명": "집재 장비에서 가장 먼 원목까지의 거리", "단위": "m" }, + { "이름": "집재재적", "설명": "1ha 에서 집재할 통나무 부피", "단위": "㎥/ha" }, + { "이름": "원목길이", "설명": "한 토막 통나무 길이", "단위": "m", "고르기": [1.2, 1.8, 2.1, 2.7, 3.6] }, + { "이름": "잔존목", "설명": "베지 않고 남긴 나무가 있는지", "고르기": ["잔존목 100본 이상 130본 이하", "잔존목 71본 이상 100본 미만", "해당 없음"] }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", diff --git a/resources/master_data/로직_산림품셈_09장_토공.json b/resources/master_data/로직_산림품셈_09장_토공.json index 5d5d4886..605bcfe0 100644 --- a/resources/master_data/로직_산림품셈_09장_토공.json +++ b/resources/master_data/로직_산림품셈_09장_토공.json @@ -1200,6 +1200,7 @@ "입력": [ { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", @@ -1221,7 +1222,7 @@ "전남광주" ] }, - { "이름": "보정작업", "고르기": ["해당 없음", "암석작업(연암・보통암・경암)", "전석섞인토사"] } + { "이름": "보정작업", "설명": "흙이 무르거나 좁아 능률이 떨어지는 작업인지", "고르기": ["해당 없음", "암석작업(연암・보통암・경암)", "전석섞인토사"] } ], "중간": [{ "이름": "작업량", "식": "로직(GF000118)" }], "호표": [ diff --git a/resources/master_data/로직_산림품셈_10장_자재․장비_운반.json b/resources/master_data/로직_산림품셈_10장_자재․장비_운반.json index 084ac18a..7b753bc7 100644 --- a/resources/master_data/로직_산림품셈_10장_자재․장비_운반.json +++ b/resources/master_data/로직_산림품셈_10장_자재․장비_운반.json @@ -156,9 +156,10 @@ "소유": "공용", "비고": "해석: N = 시간당 운반 횟수 · 1회 = 기계 1/N 시간 · t2 는 「운반시간 참조」 — 설계자 입력(분) · To=㎝-(t1+t3) 쓰는 곳 원문에 없음 · 자주식은 제외(주)", "입력": [ - { "이름": "t2", "단위": "분" }, + { "이름": "t2", "설명": "한 번 싣고 내리는 데 드는 시간", "단위": "분" }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", @@ -183,6 +184,7 @@ }, { "이름": "운반수단", + "설명": "장비를 실어 나르는 차 종류", "고르기": [ "트레일러운반(20TON)", "트럭운반(10.5TON)" diff --git a/resources/master_data/로직_산림품셈_12장_철근콘크리트.json b/resources/master_data/로직_산림품셈_12장_철근콘크리트.json index 4630a5dc..54b68dc9 100644 --- a/resources/master_data/로직_산림품셈_12장_철근콘크리트.json +++ b/resources/master_data/로직_산림품셈_12장_철근콘크리트.json @@ -430,6 +430,7 @@ "입력": [ { "이름": "횟수", + "설명": "거푸집 합판을 몇 번 돌려 쓰는지", "고르기": [ "1회사용시", "2회사용시", @@ -441,12 +442,14 @@ }, { "이름": "합판", + "설명": "거푸집에 쓸 합판 품목", "고르기": [ "MT000018" ] }, { "이름": "각재", + "설명": "거푸집을 받치는 나무 품목", "고르기": [ "MT000339", "MT000338" @@ -454,6 +457,7 @@ }, { "이름": "철선", + "설명": "거푸집을 묶는 철선 품목", "고르기": [ "MT000199", "MT000204", @@ -463,6 +467,7 @@ }, { "이름": "못", + "설명": "거푸집에 쓸 못 품목", "고르기": [ "MT000246", "MT000247", @@ -472,17 +477,20 @@ }, { "이름": "박리제", + "설명": "거푸집을 떼기 쉽게 바르는 기름 품목", "고르기": [ "MT000447" ] }, { "이름": "높이할증", + "설명": "높은 곳 작업이라 더 드는 품 비율", "단위": "%", "출처": "산림품셈 12-4 주" }, { "이름": "소형할증", + "설명": "규모가 작아 더 드는 품 비율", "단위": "%", "범위": [ 0, @@ -492,6 +500,7 @@ }, { "이름": "폼타이", + "설명": "거푸집을 마주 당겨 묶는 폼타이를 쓰는지", "고르기": [ "아님", "사용" @@ -1683,6 +1692,7 @@ "입력": [ { "이름": "관경", + "설명": "묻을 관의 안지름", "단위": "㎜", "고르기": [ 800, @@ -1692,14 +1702,17 @@ }, { "이름": "기초콘크리트량", + "설명": "관 1m 를 받치는 콘크리트 부피", "단위": "㎥/m" }, { "이름": "거푸집면적", + "설명": "거푸집을 대는 넓이", "단위": "㎡/m" }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", @@ -1724,12 +1737,14 @@ }, { "이름": "합판", + "설명": "거푸집에 쓸 합판 품목", "고르기": [ "MT000018" ] }, { "이름": "각재", + "설명": "거푸집을 받치는 나무 품목", "고르기": [ "MT000339", "MT000338" @@ -1737,6 +1752,7 @@ }, { "이름": "철선", + "설명": "거푸집을 묶는 철선 품목", "고르기": [ "MT000199", "MT000204", @@ -1746,6 +1762,7 @@ }, { "이름": "못", + "설명": "거푸집에 쓸 못 품목", "고르기": [ "MT000246", "MT000247", @@ -1755,17 +1772,20 @@ }, { "이름": "박리제", + "설명": "거푸집을 떼기 쉽게 바르는 기름 품목", "고르기": [ "MT000447" ] }, { "이름": "높이할증", + "설명": "높은 곳 작업이라 더 드는 품 비율", "단위": "%", "출처": "산림품셈 12-4 주" }, { "이름": "소형할증", + "설명": "규모가 작아 더 드는 품 비율", "단위": "%", "범위": [ 0, @@ -1775,13 +1795,14 @@ }, { "이름": "폼타이", + "설명": "거푸집을 마주 당겨 묶는 폼타이를 쓰는지", "고르기": [ "아님", "사용" ], "출처": "산림품셈 12-4 주⑦" }, - {"이름": "자재지역", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} + {"이름": "자재지역", "설명": "레미콘·골재 값을 가져올 시·군", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} ], "중간": [], "호표": [ @@ -1869,6 +1890,7 @@ "입력": [ { "이름": "관경", + "설명": "묻을 관의 안지름", "단위": "㎜", "고르기": [ 800, @@ -1878,14 +1900,17 @@ }, { "이름": "기초콘크리트량", + "설명": "관 1m 를 받치는 콘크리트 부피", "단위": "㎥/m" }, { "이름": "거푸집면적", + "설명": "거푸집을 대는 넓이", "단위": "㎡/m" }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", @@ -1910,12 +1935,14 @@ }, { "이름": "합판", + "설명": "거푸집에 쓸 합판 품목", "고르기": [ "MT000018" ] }, { "이름": "각재", + "설명": "거푸집을 받치는 나무 품목", "고르기": [ "MT000339", "MT000338" @@ -1923,6 +1950,7 @@ }, { "이름": "철선", + "설명": "거푸집을 묶는 철선 품목", "고르기": [ "MT000199", "MT000204", @@ -1932,6 +1960,7 @@ }, { "이름": "못", + "설명": "거푸집에 쓸 못 품목", "고르기": [ "MT000246", "MT000247", @@ -1941,17 +1970,20 @@ }, { "이름": "박리제", + "설명": "거푸집을 떼기 쉽게 바르는 기름 품목", "고르기": [ "MT000447" ] }, { "이름": "높이할증", + "설명": "높은 곳 작업이라 더 드는 품 비율", "단위": "%", "출처": "산림품셈 12-4 주" }, { "이름": "소형할증", + "설명": "규모가 작아 더 드는 품 비율", "단위": "%", "범위": [ 0, @@ -1961,13 +1993,14 @@ }, { "이름": "폼타이", + "설명": "거푸집을 마주 당겨 묶는 폼타이를 쓰는지", "고르기": [ "아님", "사용" ], "출처": "산림품셈 12-4 주⑦" }, - {"이름": "자재지역", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} + {"이름": "자재지역", "설명": "레미콘·골재 값을 가져올 시·군", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} ], "중간": [], "호표": [ @@ -2204,22 +2237,27 @@ "입력": [ { "이름": "콘크리트량", + "설명": "부어 넣을 콘크리트 부피", "단위": "㎥" }, { "이름": "거푸집면적", + "설명": "거푸집을 대는 넓이", "단위": "㎡" }, { "이름": "기초잡석량", + "설명": "바닥에 까는 잡석 부피", "단위": "㎥" }, { "이름": "철근량", + "설명": "넣을 철근 무게", "단위": "ton" }, { "이름": "성토부", + "설명": "흙을 쌓아 올린 자리인지", "고르기": [ "아님", "성토부 날개벽" @@ -2228,12 +2266,14 @@ }, { "이름": "합판", + "설명": "거푸집에 쓸 합판 품목", "고르기": [ "MT000018" ] }, { "이름": "각재", + "설명": "거푸집을 받치는 나무 품목", "고르기": [ "MT000339", "MT000338" @@ -2241,6 +2281,7 @@ }, { "이름": "철선", + "설명": "거푸집을 묶는 철선 품목", "고르기": [ "MT000199", "MT000204", @@ -2250,6 +2291,7 @@ }, { "이름": "못", + "설명": "거푸집에 쓸 못 품목", "고르기": [ "MT000246", "MT000247", @@ -2259,17 +2301,20 @@ }, { "이름": "박리제", + "설명": "거푸집을 떼기 쉽게 바르는 기름 품목", "고르기": [ "MT000447" ] }, { "이름": "높이할증", + "설명": "높은 곳 작업이라 더 드는 품 비율", "단위": "%", "출처": "산림품셈 12-4 주" }, { "이름": "소형할증", + "설명": "규모가 작아 더 드는 품 비율", "단위": "%", "범위": [ 0, @@ -2279,6 +2324,7 @@ }, { "이름": "폼타이", + "설명": "거푸집을 마주 당겨 묶는 폼타이를 쓰는지", "고르기": [ "아님", "사용" @@ -2287,6 +2333,7 @@ }, { "이름": "소형가산", + "설명": "규모가 작아 더 드는 철근 품 비율", "단위": "%", "범위": [ 0, @@ -2296,6 +2343,7 @@ }, { "이름": "결속선", + "설명": "철근을 묶는 철선 품목", "고르기": [ "MT000209", "MT000174" @@ -2303,6 +2351,7 @@ }, { "이름": "브레이커", + "설명": "굳은 땅을 깨는 장비 규격", "고르기": [ "아님", "브레이커 사용" @@ -2311,6 +2360,7 @@ }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", @@ -2335,6 +2385,7 @@ }, { "이름": "보정작업", + "설명": "흙이 무르거나 좁아 능률이 떨어지는 작업인지", "고르기": [ "해당 없음", "암석작업(연암・보통암・경암)", @@ -2342,7 +2393,7 @@ ], "출처": "건설품셈 공통 8-1-7 1" }, - {"이름": "자재지역", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} + {"이름": "자재지역", "설명": "레미콘·골재 값을 가져올 시·군", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} ], "중간": [], "호표": [ @@ -2926,34 +2977,42 @@ "입력": [ { "이름": "구체콘크리트량", + "설명": "맨홀 몸통 콘크리트 부피", "단위": "㎥" }, { "이름": "버림콘크리트량", + "설명": "바닥 고르기용 얇은 콘크리트 부피", "단위": "㎥" }, { "이름": "원형거푸집_기초및슬라브면적", + "설명": "둥근 맨홀 바닥·뚜껑 거푸집 넓이", "단위": "㎡" }, { "이름": "원형거푸집_벽체면적", + "설명": "둥근 맨홀 벽 거푸집 넓이", "단위": "㎡" }, { "이름": "거푸집면적", + "설명": "거푸집을 대는 넓이", "단위": "㎡" }, { "이름": "철근량", + "설명": "넣을 철근 무게", "단위": "ton" }, { "이름": "사다리량", + "설명": "맨홀 안 사다리 무게", "단위": "ton" }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", @@ -2978,12 +3037,14 @@ }, { "이름": "합판", + "설명": "거푸집에 쓸 합판 품목", "고르기": [ "MT000018" ] }, { "이름": "각재", + "설명": "거푸집을 받치는 나무 품목", "고르기": [ "MT000339", "MT000338" @@ -2991,6 +3052,7 @@ }, { "이름": "철선", + "설명": "거푸집을 묶는 철선 품목", "고르기": [ "MT000199", "MT000204", @@ -3000,6 +3062,7 @@ }, { "이름": "못", + "설명": "거푸집에 쓸 못 품목", "고르기": [ "MT000246", "MT000247", @@ -3009,17 +3072,20 @@ }, { "이름": "박리제", + "설명": "거푸집을 떼기 쉽게 바르는 기름 품목", "고르기": [ "MT000447" ] }, { "이름": "높이할증", + "설명": "높은 곳 작업이라 더 드는 품 비율", "단위": "%", "출처": "산림품셈 12-4 주" }, { "이름": "소형할증", + "설명": "규모가 작아 더 드는 품 비율", "단위": "%", "범위": [ 0, @@ -3029,6 +3095,7 @@ }, { "이름": "폼타이", + "설명": "거푸집을 마주 당겨 묶는 폼타이를 쓰는지", "고르기": [ "아님", "사용" @@ -3037,6 +3104,7 @@ }, { "이름": "소형가산", + "설명": "규모가 작아 더 드는 철근 품 비율", "단위": "%", "범위": [ 0, @@ -3046,12 +3114,13 @@ }, { "이름": "결속선", + "설명": "철근을 묶는 철선 품목", "고르기": [ "MT000209", "MT000174" ] }, - {"이름": "자재지역", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} + {"이름": "자재지역", "설명": "레미콘·골재 값을 가져올 시·군", "비고": "시·군 이름 — 레미콘·골재 시중물가 후보를 고름"} ], "중간": [], "호표": [ @@ -3205,6 +3274,7 @@ "입력": [ { "이름": "작업조", + "설명": "한 조에 몇 사람이 붙는지", "고르기": [ "무근콘크리트", "철근콘크리트" @@ -3212,6 +3282,7 @@ }, { "이름": "슬럼프", + "설명": "콘크리트가 묽은 정도", "고르기": [ "8~12cm", "15cm", @@ -3220,6 +3291,7 @@ }, { "이름": "시설유형", + "설명": "타설할 구조물 종류", "고르기": [ "Type-Ⅰ", "Type-Ⅱ", @@ -3230,6 +3302,7 @@ }, { "이름": "현장조건", + "설명": "차가 대기 좋은 자리인지", "고르기": [ "Type-Ⅰ", "Type-Ⅱ", @@ -3239,6 +3312,7 @@ }, { "이름": "재세팅", + "설명": "펌프차를 자리 옮겨 다시 세우는 횟수", "고르기": [ "아님", "펌프차 이동 및 재세팅" @@ -3247,6 +3321,7 @@ }, { "이름": "진동기", + "설명": "콘크리트를 다지는 진동기 종류", "고르기": [ "사용", "미사용" @@ -3255,6 +3330,7 @@ }, { "이름": "타설방법", + "설명": "콘크리트를 붓는 방법", "고르기": [ "붐 타설", "배관 타설" @@ -3263,6 +3339,7 @@ }, { "이름": "펌프차", + "설명": "쓸 펌프차 규격", "고르기": [ "4504-0032", "4504-0036", @@ -3275,6 +3352,7 @@ }, { "이름": "지역", + "설명": "기계 경비를 셈할 노임 지역", "고르기": [ "전국평균", "전국", diff --git a/resources/master_data/로직_산림품셈_13장_구조물.json b/resources/master_data/로직_산림품셈_13장_구조물.json index d657eb14..15cc131b 100644 --- a/resources/master_data/로직_산림품셈_13장_구조물.json +++ b/resources/master_data/로직_산림품셈_13장_구조물.json @@ -291,11 +291,11 @@ "비고": "「원문에 없는 조합: 뒷길이=25 · 돌=견치돌 · 쌓기=골쌓기 / 뒷길이=25 · 돌=견치돌 · 쌓기=켜쌓기 / 뒷길이=25 · 돌=깬돌 · 쌓기=골쌓기 / 뒷길이=25 · 돌=깬돌 · 쌓기=켜쌓기 / 뒷길이=30 · 돌=견치돌 · 쌓기=골쌓기 외 5」", "시험입력": {"높이": 4.0, "돌": "깬잡석"}, "입력": [ - { "이름": "뒷길이", "단위": "㎝", "고르기": [25, 30, 35, 45, 55, 60, 75] }, - { "이름": "돌", "고르기": ["견치돌", "깬돌", "깬잡석", "호박돌 및 야면석"] }, - { "이름": "쌓기", "고르기": ["골쌓기", "켜쌓기"] }, - { "이름": "높이", "단위": "m" }, - { "이름": "초과증가율", "단위": "%", "범위": [80, 100] } + { "이름": "뒷길이", "설명": "쌓을 돌의 뒤쪽 길이", "단위": "㎝", "고르기": [25, 30, 35, 45, 55, 60, 75] }, + { "이름": "돌", "설명": "쌓을 돌 종류", "고르기": ["견치돌", "깬돌", "깬잡석", "호박돌 및 야면석"] }, + { "이름": "쌓기", "설명": "돌을 어긋나게 쌓는지 줄 맞춰 쌓는지", "고르기": ["골쌓기", "켜쌓기"] }, + { "이름": "높이", "설명": "쌓는 벽 높이", "단위": "m" }, + { "이름": "초과증가율", "설명": "기준 높이를 넘어 더 드는 품 비율", "단위": "%", "범위": [80, 100] } ], "중간": [ { diff --git a/resources/tester/test_masterdata_check.py b/resources/tester/test_masterdata_check.py index baebd194..16c362be 100644 --- a/resources/tester/test_masterdata_check.py +++ b/resources/tester/test_masterdata_check.py @@ -961,3 +961,26 @@ def test_고르기_조건의_입력_자리_채움(whole): assert mf.check_pick(whole, "시험", cond) == [] 채움 = {k: mf.fill(v, {"관경": Decimal(800)}) for k, v in cond.items()} assert mm.candidates(whole, 채움, None, "m") + + +TEST_KEYS = ( + "GF000181", + "GF000177", + "GF000173", + "GF000174", + "GF000160", + "GF000182", + "GF000069", + "GF000219", + "GF000119", + "GF000137", +) + + +def test_테스트_대상_로직_입력에_설명(whole): + """화면 도움말 — 테스트 컨테이너 대상 10 개는 입력마다 쉬운 말 한 줄.""" + for key in TEST_KEYS: + specs = whole.logic(key).get("입력") or [] + assert specs, key + 빈칸 = [s["이름"] for s in specs if not str(s.get("설명") or "").strip()] + assert 빈칸 == [], (key, 빈칸)