From 16e345997a002e1bef8d94c140d787a57bdb656a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 9 Oct 2026 23:59:07 +0900 Subject: [PATCH] =?UTF-8?q?chore(plan):=2010-9=20=EB=84=B7=EC=A7=B8=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=20=EC=9B=90=EB=AC=B8=20=C2=B7=20=EC=A1=B0?= =?UTF-8?q?=EC=82=AC=20K=20=C2=B7=20L=20=C2=B7=20M=20=C2=B7=20N(162~166?= =?UTF-8?q?=EC=9E=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LLCk2y5xE8YGVgjbTntWsY --- docs/raw/요구_1009_4/사용자요구_1009_4.md | 23 +++ docs/raw/요구_1009_4/조사_K_B06상세노면공.md | 104 +++++++++++ .../raw/요구_1009_4/조사_L_B08모달콘크리트.md | 106 ++++++++++++ docs/raw/요구_1009_4/조사_M_M02자재구분.md | 61 +++++++ .../요구_1009_4/조사_N_B09내역요율재료비.md | 162 ++++++++++++++++++ 5 files changed, 456 insertions(+) create mode 100644 docs/raw/요구_1009_4/사용자요구_1009_4.md create mode 100644 docs/raw/요구_1009_4/조사_K_B06상세노면공.md create mode 100644 docs/raw/요구_1009_4/조사_L_B08모달콘크리트.md create mode 100644 docs/raw/요구_1009_4/조사_M_M02자재구분.md create mode 100644 docs/raw/요구_1009_4/조사_N_B09내역요율재료비.md diff --git a/docs/raw/요구_1009_4/사용자요구_1009_4.md b/docs/raw/요구_1009_4/사용자요구_1009_4.md new file mode 100644 index 000000000..d6e59a8cd --- /dev/null +++ b/docs/raw/요구_1009_4/사용자요구_1009_4.md @@ -0,0 +1,23 @@ +# 사용자 요구 (2026-10-09 밤 넷째 · 원문 그대로) + +계획서 = `PLAN.md` 162장부터 · 분석 = 같은 폴더 `분석_정함.md` · 조사 = 같은 폴더 `조사_*.md`. +사용자 지시 = 「위 내용을 너가 직접 분석하여 상세계획서를 작성하고 코더들에게 작업지시할 것」 · 1 · 4 · 5 는 브레인이 직접 확인. + +``` +1. 다음 검토용 B06에서 횡단도의 상세에 표현되는 그림에 팬동작과 줌인아웃을 마우스로 할수 있어야해. 팬은 마우스 중간버튼, 줌인아웃은 마우스 스크롤이야. 그리고 하단 테이블의 항목을 선정할때 하이라이트 색상은 붉은 계통으로 가는데 문제는 하단테이블의 선택이 제대로 표현이 안되는것같아. 직접 확인해봐. 스크롤과 팬동작은 캐드 화면 제어를 참고하면 됨. +2. B08의 구조물집계표로 접근하는 모달창의 상단에 연결에 대한 정보들이 한행씩 표현되고 있는데 문제는 행이 많아질경우 하단의 내용이 많이 밀리게됨. 컴팩트하게 표현되게 변경. 그리고 여기서는 도면보다는 일위대가와 면적산출 정보가 더 중요하니 레이아웃 조절해주고 결국 3개의 컨테이너에 들어가 있는 정보들은 프로젝트에 복사해서 가져갈텐데 수정이 필요해보여. 다시말하면 마스터/회사/개인의 정보를 수정하는게 아니라 프로젝트의 구조물조합의 정보 수정이 필요하다는 말이야. 다음으로 프로젝트를 운용하는 과정에서 마스터가 업데이트 된 경우가 있을것같은데 이때는 업데이트 버튼이 있으면 좋을것같아. 이건 상단의 선택,연결끊기와 같이 존재하면 될것같아. +3. M02의 구조물 조합의 일위대가에서 자재의 경우 품셈에 물려있는 자재의 경우 자재구분에서 일반항목은 삭제, 다음으로 항목의 기본값은 사급, 별도계상, 운반비 포함이 기본값임. 이때 별도계상이 되면 운반비는 비활성화 처리가 되어야함. +4. B06의 횡단도에 노면공이 여러 횡단도를 거치면서 구조물 선택과 횡단도 선택에 제대로 선택이 안되는 현상이 여전히 발생되고 있음. 너가 직접 확인하고 개선 할것. +5. B08 자재탭에서 콘크리트소요자재집계표가 재대로 표현안되는 이유를 확인하고 개선할것. 직접 확인 +6. B09의 총괄설계내역서 탭의 요육을 제비율표를 보고 자동으로 값을 넣어주고 사용자가 수정할 수도 있게 해야하는건 아닌지. +7. B09의 설계내역서에서 하위행들은 일단 수량을 입력할수있게 변경해주고 일위대가나 단가산출로직에서 선택할 수 있어야함.(구조물공의 경우 자동으로 계산되는게 맞을것같음). 추가로 테이블에는 마우스 우클릭으로 행을 자유롭게 추가하고 할수 있어야하고 항목을 일위대가나 단가산출을 연결하여 사용할수 있어야함. 하지만 이때 연결된 정보들은 일위대가목록표, 일위대가표, 단가산출근거목록표, 단가산출근거에 표현되어야함. +8. 재료비 목록표에는 B08의 총괄자재수량집계표의 목록과 수량값을 가져오는 이때 합계 열의 값을 가져오고 단가를 곱해서 열마다 총액이 존재해야함. +9. 이때 자재단가대비표에서는 재료비목록표에 사용할 단가를 비교하는 테이블로 통상 같은 행의 비교군중 낮은가격으로 선택하나 추가 열 항목으로 견적가가 들어와야함. 이때 견적은 사용자에게 입력하게되는데 이때는 견적서 첨부복수파일도 있으니 자리를 만들어 둘것. 거기에따라 견적가가 높더라도 견적가를 선택하여 재료비목록표의 단가를 사용할 수 있음. +10. 경비수량금액집계표의 내용이 없는 사유 확인 + +위내용을 너가 직접 분석하여 상세계획서를 작성하고 코더들에게 작업지시할 것. +``` + +``` +추가로 일위대가표의 금액들이 일위대가목록표에 업데이트가 안되는 이유확인 후 반영 +``` diff --git a/docs/raw/요구_1009_4/조사_K_B06상세노면공.md b/docs/raw/요구_1009_4/조사_K_B06상세노면공.md new file mode 100644 index 000000000..6dd71d3a4 --- /dev/null +++ b/docs/raw/요구_1009_4/조사_K_B06상세노면공.md @@ -0,0 +1,104 @@ +# 조사 K — B06 [상세] 그림 팬 · 줌 · 표 강조 · 노면공 고름 (10-9 넷째 · 읽기 전용 조사 에이전트) + +약칭 `B06_Section/B06_Section_` + DT `UI_Cross_Detail.ts` · DTC `UI_Style_Cross_Detail.css` · DPK `UI_Cross_Detail_Pick.ts` · DP `UI_Cross_Design_Pick.ts` · CV `UI_Cross_View.ts` · CVZ `UI_Cross_View_Zoom.ts` · AX `UI_Cross_Axes.ts` · AR `UI_Cross_Areas.ts` · DS `UI_Cross_Design_Surface.ts` · SV `UI_Section_View.ts` · SVP `UI_Section_View_Profile.ts` · SPN `UI_Page_Structures_Panel.ts` · SPS `UI_Page_Structures_Selection.ts` · PK `UI_Page_Structure_Pick.ts` · SS `Section_Store.ts` · CSA `UI_Style_Cross_Areas.css` · CSC `UI_Style_Cross.css` · CCC `UI_Style_Cross_Controls.css` / ZP `A00_Common/b_svg_zoom_pan.ts` · SEL `A00_Common/design/design_selection.ts` · DVC `A00_Common/design/design_view_cross.ts` · DVP `A00_Common/design/design_view_profile.ts` · B5P `B05_Profile/B05_Profile_UI_Structures_Panel.ts` · B5C `B05_Profile/B05_Profile_UI_Structures_Panel_Commit.ts` · PAV `common_util/common_util_structure_pavement.ts` · TH `ui_template/ui_template_theme.css` · MD `ui_template/ui_template_modal.ts` · CAD `B07_DesignDetail/openwebcad/src/inputController/` · T `resources/tester/` + +## 0. 코드 지도 + +| 요구 | 손댈 층 | 계산 자리(5장) | 저장 | +|---|---|---|---| +| K1 팬 · 줌 | DT · DTC (+ ZP 재사용) | 화면만 | 없음(창 안 상태) | +| K2 표 → 강조 | DTC (+ DPK · DT) | 화면만 | 없음 | +| K4 노면공 고름 | SPN · SV (+ DVC 안 고침) | 화면만 | `structure-pick` 세션(SEL) | + +## K1. [상세] 그림 팬(가운데 단추) · 줌(휠 · 커서 중심) + +- 지금 그림: 카드 SVG 를 **통째 복제**(DT:173-178 `cloneNode(true)`) → 복제엔 이벤트 없음 · 클래스 · 속성만. 원본 = `viewBox 0 0 W H` + `width/height` 픽셀(CV:354-363 · `data-px-per-m`) · 배경 rect · 축 레이어 `g.b06-chart__axes`(CV:369-381 · 줌마다 다시 그림) · `clipPath#b06-cross-clip-{측점}` + 클립 그룹 안 `g.b06-chart__plot-layer`(CV:386-398 · 줌 · 팬은 이 레이어 `transform` 만) · 십자 marker(틀). 복제는 CSS 로 `100% × 100%`(DTC:56-60 · viewBox 그대로라 비율 유지 · 남는 쪽 여백). +- 카드 줌 상태(`cardZoomStates` CV:628-641)가 복제에 **그대로 묻어 옴**(plot-layer transform · marker 역배율) — 모달은 그 위에 제 배율을 얹는 꼴. +- 복제엔 `clipPath` id 가 원본과 **같음**(문서에 id 둘) — 지금도 그렇고 모양이 같아 티 안 남(추정 · 그대로 둠). +- CAD 참고: 휠 = 늘 줌 · 커서 고정 · **당기면 확대**(`deltaY > 0` · CAD `input-wheel.ts`:13-23 · `input-controller.ts`:269-276) · 가운데 단추 = 팬(`mousedown` 에서 preventDefault · :278-283 · 이동 :232-239) · `auxclick` 막음(:110-113). 같은 규칙이 **이미 공용 조각** ZP 에 있음 — `wheelZoom: true` 면 커서 아래 지점 고정 · 당기면 확대(ZP:191-205 · 계수 1.15/0.87) · 가운데 단추 팬 + 자동 스크롤 막기(ZP:142-170) · 더블클릭 원복(ZP:214-217) · 상태 `initial/onChange`(ZP:62-65). 카드는 `wheelZoom:false`(CVZ:61 · 목록 훑기 때문) — 모달은 창 하나라 켜도 됨. +- 고칠 자리(DT `paint`): + ⓐ 복제의 **자식 전부를 `` 하나로 감쌈**(배경 · 축 · 클립 그룹 · 십자까지) → `attachSvgZoomPan({ svg: 복제, layer: 그 g, widthPx/heightPx = viewBox, pad: CROSS_PAD, wheelZoom: true, maxScale: 16, content: 넓게(예 −W~2W · −H~2H · 1배에서도 팬 되게 — 없으면 ZP:107-121 이 1배 팬을 0 으로 묶음), initial: state.zoom, onChange: state.zoom = … })` — 그림 전체가 한 장처럼 움직여 축 · 눈금 값이 어긋나지 않음(카드처럼 도형층만 밀면 축을 다시 못 그림 — AX 입력값이 복제에 없음) · 선 굵기는 `non-scaling-stroke`(CSC:108-113) 라 그대로 · 글자는 같이 커짐(CAD 와 같음). + ⓑ `refreshCrossDetail` → `paint` 재복제(DT:233-240) 때 ⓐ 를 다시 걸고 `state.zoom` 을 `initial` 로 넘김(조작 중 배율 유지). + ⓒ 되돌리기 — 더블클릭 원복은 공짜(ZP:214) · 단추 = `buildZoomControls(handle)`(CVZ:73-101 · `[+ − ⤢]` · `width` 안 넘기면 배율만) 를 `cad` 에 붙임 + DTC `.b06-detail__cad { position: relative }`(CCC:214-224 가 absolute 우상단) → 추천 둘 다(카드와 같은 손맛). + ⓓ DTC — 복제 svg 를 `width:auto; height:auto; max-width/height:100%; aspect-ratio: W/H; margin:auto`(DT 가 inline `aspect-ratio` 한 줄) → ZP 가 쓰는 `getBoundingClientRect` 비율(ZP:163-165 · 197-199)이 viewBox 와 같아져 커서 고정 · 팬 속도가 정확(지금 `100%×100%` 는 여백만큼 어긋남). +- 다른 조작과 부딪힘: 복제엔 보라 선 · 면적 띠 리스너가 없고(DTC:113-116 손가락도 지움) 150-4 강조는 클래스만 갈아 끼움(DPK:47-68 · `querySelectorAll` 은 감싼 g 안도 찾음) → 안 부딪힘. 좌클릭은 ZP 가 안 씀(ZP:150) · 팬 끝 클릭은 전파 막음(ZP:188-190) · 모달 막 닫기는 막 자체 누름만(MD:52) → 안전. +- 재사용: ZP · CVZ `buildZoomControls` · CCC 단추 CSS · `CROSS_PAD`. +- 시험: T `test_150_detail_pick.py` 에 소스 단정 추가(DT `attachSvgZoomPan` · `wheelZoom: true` · `buildZoomControls` · DTC `position: relative` · `aspect-ratio`) · 기존 5건 그대로. 공용 수학은 T `test_cross_pan_bounds.mjs` 가 이미 봄. +- 위험: 1배 아래 축소 없음(ZP:125 하한 1 · 필요하면 `minScale` 한 칸 — B05 계획노선 횡단도 같은 조각이라 기본값은 그대로) · 카드가 확대된 채면 복제도 확대된 채 시작(더블클릭은 모달 배율만 원복) · DT 240 → 약 265줄. +- 크기: 작음. +- 추천: ⓐ~ⓓ(감싼 g + ZP `wheelZoom` + `[+ − ⤢]` + 비율 CSS). + +## K2. [상세] 표 줄 누름 → 그림 붉은 강조가 안 보임 + +- 배선(150-4): 칸 키 = 짝 있는 칸만 `data-key`(DT:79-80 · 이름 th · 값 td 둘 다) → 누름 위임 `closest("[data-key]")`(DT:163-168 · 같은 칸 다시 = 끔) → `showPicked`(DT:156-162) = 칸 `is-picked` + 복제 안 `highlightDetail`(DPK:47-68 · 묻어 온 `.is-active` 전부 지우고 대상만 켬) · 재복제 · 표 재수신 때도 다시(DT:177 · 197). 줄(`tr`) 고름 표시는 **없음** — `is-focus` 없음 · 칸 둘만 `is-picked`. +- **가설 ① (주 원인 · 추정)** 10 키(측구 둘 · 층따기 · 면고르기 둘 · 지장목 둘 · 파종 · 살포 · 노면다짐)의 강조 = 보라 판정 선 `.b06-chart__design-hit.is-active` = `color-mix(--color-royal-amethyst 45%)`(CSA:159-162) → 모달 어두운 바탕(#111 · DTC:34-53)에서 **밝은 테마 값 #3e0079(TH:21)** 45% = 거의 안 보임. DTC 가 다크 토큰을 덮지만 amethyst · chart 색은 안 덮음. 확인: ORCA eval `getComputedStyle(document.querySelector('.b06-detail__cad .b06-chart__design-hit.is-active')).stroke`. +- 가설 ② 칸 고름 표시 = hover 와 **같은 색**(DTC:97-100 · primary 18%) → 눌린 칸과 손 올린 칸이 구별 안 됨 · 붉은 계통도 아님. +- 가설 ③ 대상 요소가 **그 카드에 없는 칸**은 눌러도 그림 변화 0(칸 색만) — 아래 표의 「없을 때」. +- 항목별 강조 표(키 22 = DPK:17-36 · 표 배치 `B07_DesignDetail_Engine_Cad_Table.py`:25-56): + +| 표 칸(키) | 그림 대상(복제 안) | 지금 색(모달) | 없을 때 = 눌러도 그림 변화 0 | +|---|---|---|---| +| 지반고 · 계획고 · 성토고 · 절토고 | 중심 십자 `g.b06-chart__center`(CV·Frame:42) | 노랑 `--color-warning`(DTC:103-106) · 보임 | 늘 있음 | +| 깍기 토사 `cut_soil` | 면적 띠 `g.b06-chart__area--cut_soil`(AR:210-229) | 주황 28% 채움(CSA:111) · 옅음 | 절토 면적 0 | +| 깍기 암석 `cut_rock` | `--cut_rock`(+ `--cut_rr/br`) | 초록/보라 28%(CSA:118-128) | 암 경계 없음(`soilDepth` null · AR:198-213) 또는 절토 0 | +| 쌓기 `embankment` | `--fill` | 파랑 28%(CSA:130) | 성토 면적 0 | +| 사토장 `spoil_fill` | `.b06-chart__spoil-fill` 선 | 굵기만 4(DTC:108-110) · 색 그대로 | 사토장 없음 | +| 측구 토사 · 암석 | 판정 선 중 측구 구역(DPK:39-44 · `both_fill` 로 되돌려 남는 cut) | **가설 ①** | 측구 끔 · 설계 없음 · 구조물에 가린 조각 | +| 층따기 · 면고르기 성토 · 지장목 성토 · 성토파종 | 판정 선 fill 구역(넷이 **같은 선**) | 가설 ① | 성토 사면 없음 | +| 면고르기 절토 · 지장목 절토 · 절토살포 | 판정 선 cut_slope 구역(셋 같은 선) | 가설 ① | 절토 쪽 없음(`section_mode`) | +| 노면다짐 `road_compaction` | 판정 선 road 구역(노견 사이) | 가설 ① | 설계 없음 | +| 편책 · 제근 · 표토제거 둘 | 없음(늘 빈칸) | 누름 없음(키 없음 · 손가락 없음) | — | + +- 그룹 칸 「깍기 · 측구 · 쌓기 · 면고르기 …」(rowspan th)은 키 없음 → 눌러도 반응 없음(의도 · 사용자는 누를 만함 · 추정). +- 고칠 자리: DTC 에 모달 전용 강조 한 묶음 — `.b06-detail__cad .is-active` 계열을 **모두 `--color-danger`(#ff5f57 · DTC:45)** 로: 면적 띠 채움 35% + 테두리 2 · 판정 선 `stroke: color-mix(danger 70%)` 굵기 9 · 십자 danger · 사토장 danger 굵기 3(CSA 는 안 건드림 · 카드 색 그대로) · 칸 `.is-picked` = danger 18% + `box-shadow: inset 0 0 0 1px danger` · hover 는 더 옅게(8%) → 가설 ①②. 가설 ③ 은 선택: `paint` 뒤 복제에서 대상 유무를 재 `data-empty`(DPK 에 `presentKeys(svg, design)` 한 함수 · 판정 선 구역은 `lineZone` 재사용) → DTC 회색 · 손가락 없음(약 12줄 · 추천 넣음 — 「눌렀는데 아무 일 없음」이 사라짐). +- 재사용: DPK 짝 표 · `lineZone` · DTC 토큰 덮기 꼴. +- 시험: T `test_150_detail_pick.py` 소스 단정(DTC danger 강조 4 선택자 · `is-picked` ≠ hover) · 가설 ③ 넣으면 `helper_150_detail_pick.cjs` 에 `presentKeys` 사례(띠 없는 가짜 svg → cut_rock 빠짐) · `test_138_cross_detail` 그대로. +- 위험: 판정 선 굵기 9 는 겹친 조각(측구 ↔ 사면 꺾임)에서 서로 덮음(카드 7 과 같은 결) · 성토 네 칸이 같은 선 = 구별 안 됨(값 근거가 같은 면이라 의도 · 추정) · 카드 쪽 CSA 안 건드리므로 카드 모습 변화 없음. +- 크기: 작음(CSS) + 작음(가설 ③). +- 추천: DTC 붉은 강조 한 묶음 + 가설 ③ `data-empty`. + +## K4. 노면공이 여러 횡단도를 거칠 때 구조물 · 횡단도 고름 + +- 152-5 뒤 구조: 노면공 고름 = 범위 카드 **포장층** `is-active`(SV:239-262 `applySpan` · DS:71-85 종류 · 시작 · 끝 일치 · 겹침은 하나) · `--span` 테두리는 G 군 외만 · 포장층 범위 표식은 서버(`common_util_structure_pavement.py`) · 초안이면 브라우저가 다시 얹음(SS:71-81 · PAV:58-105 · min/max 정규화라 뒤집힌 시작 · 끝도 일치). 카드 누름 → `resolveSelection` ③ 「덮는 구조물」에서 G 군 뺌(SEL:81-98 · SPN:161-164 `coverable` · SPN:531-545 `showAtChainage`). +- 고름 전달 뼈대: 카드 고름 → SV:273-291 → 측점 리스너 DVC:384-408 → `showAtChainage` → 폼(B5P:626-636 `selectById` = `loadForm` → **늘 `onSelect` 되부름** B5C:94-158 · null 은 편집 중일 때만 `resetForm` → `onSelect(null)`) → SPN:205-213 `onSelect` = `focusChainage`(DVC:119-126 anchor 가까운 카드) → **`markStructure`(span 켬 · DVC:194 · SV:543-548)** → 리스너 끝에 `selectMark(mark, false)`(DVC:401-402 · span **끔**) → 그러므로 모든 길이 「리스너가 끔 → 뒤따르는 `markStructure` 가 다시 켬」 **되감기 순서에 기댐**(아래 표). 종단 알약 유지 53-1(SVP:270-284 `markedId` 덮으면 지킴) 은 그 뒤 `profile.selectMark(null)` 이 다시 끔. +- 길마다 끝 상태(코드 추적 · 화면 미확인): + +| 길 | 조작 | 거치는 자리 | 끝 상태(지금) | 어긋날 만한 곳 | +|---|---|---|---|---| +| ① 범위 안 카드 누름(관 · 벽 없음) | 카드 좌클릭 | SV:283 → DVC:393 `showAtChainage`(preferred null) → SEL ③ G 뺌 → `selectById(null)` → `resetForm` → `onSelect(null)` → `markStructure(null)` → DVC:395 세션 sid 비움 → `selectMark(null,false)` | 카드 고름 · **노면공 목록 · 포장층 · 알약 · 세션 전부 풀림** | 152-5 정함대로지만 사용자 체감 = 「횡단도 누르면 구조물 고름이 사라짐」(추정 · 「여전히」의 실체) | +| ② 목록 · 종단 알약 → 노면공 | 좌측 목록 / 아래 알약(SVP:199-213 → SPN:530 `selectById`) | `loadForm` → `onSelect` → `focusChainage(anchor)` → 리스너 → `showAtChainage`(preferred = id) ① byId → `selectById` 재진입 → `onSelect` 재진입 → 같은 카드 reveal → `markStructure`(켬) → 리스너 `selectMark(id,false)`(끔) → 바깥 `onSelect` 의 `markStructure`(다시 켬) | 가까운 카드 1 + 범위 포장층 + 알약 + 세션 sid ✓ | 가까운 카드가 **이미 고른 카드**면 리스너 안 돎 → 세션 sid 갱신 안 됨(SPN `onSelect` 는 세션을 안 적음 · B05 로 가면 옛 값) · anchor 는 B5C:370 가 범위 안으로 가둠 | +| ③ 범위 안 관 · 흙막이 누름 | 카드 벽 · 관 좌클릭 | SPS:70-87 → `showAtChainage(owner)` → SEL ② 관 먼저 → `markStructure(pipe-…)` → 리스너(벽 고름 표시) | 관 폼 · 알약 = 관 · 포장층 풀림 | 노면공으로 **안 튐**(② 관이 ③ 보다 앞) · 독립 흙막이는 ③ 점형 ±0.51 로 열림 | +| ④ B05 알약 → B06 | B05 알약(DVP:111-114 세션 sid) → B06 진입 DVC:562-570 → PK:42-81 byId → 범위 **첫 카드** | `prefer(sid)` → `focusStation` → 리스너 ① byId → `selectById` → `onSelect` → `focusChainage(anchor)` → anchor 카드 ≠ 첫 카드면 **카드 한 번 더 옮김** → … → `selectMark(id,false)`(끔) → DVC:483-485 `selectStructure(sid)` 재고름 → `markStructure`(켬) | 포장층 + 알약 ✓ · 세션 at = 첫 카드 · 고른 카드 = anchor 카드(둘이 다르면 튐) | 되감기 세 겹 · `selectStructure` 없으면 포장층 안 켜짐 | +| ⑤ 겹친 노면공 둘 | 목록에서 둘째 | ② 와 같음 · DS:71-85 종류 · 시작 · 끝 일치 층만 | 둘째 층만 `is-active` | 같은 종류 · 같은 범위 둘(중복)은 둘 다 켜짐 · 카드 누름은 ① 과 같음 | + +- 고칠 자리(⬜ (가) 면): + ⓐ SPN `showAtChainage`(531-545) — `hit` 이 {관 없음 · 구조물 없음} 이고 세션 sid(`readSelection`) 구조물이 G 군(`!coverable`) 이며 `coversChainage(entry, chainageM)` 이면 `selectById(null)` 안 부르고 `{ chainageM, structureId: 그 id }` 돌려줌(약 6줄 · chainageM null 은 제외 → 카드 해제는 지금처럼 모두 풂). + ⓑ SV `selectMark`(543-548) — `spanMarkId = span || G군(structureId) ? structureId : null`(`spanMarks` · `spanTypes` 로 판정 · 2줄) → 포장층 강조는 카드 테두리가 아니므로 137-4 「카드 하나만」과 안 부딪힘 · ②④ 의 되감기 의존도 사라짐. + ⓒ DVC 는 안 고침(684줄 · 700 위험) — `mark = opened.structureId` 가 ⓐ 로 노면공이 되어 세션 · 알약이 저절로 맞음. +- 재사용: SEL `coversChainage` · `readSelection` · SV `spanTypes`. +- 시험: T `test_152_5_pavement_pick.py` + `helper_152_5_pavement_pick.cjs` 에 사례(세션 sid = 노면공 · 범위 안 측점 · 관 없음 → 유지 / 범위 밖 → 풂 / 관 있으면 관) · `test_106_span_highlight_wording.py`:39-45 소스 단정(`selectMark(mark, false)` 줄 그대로) · `test_b05_b06_selection_single` 통과 확인. +- 브레인 ORCA 재현 차례(노면공 하나가 카드 3장 이상 걸치는 노선): + 1. 좌측 목록 노면공 누름 → 기대: 카드 1 빨강 테두리 · 범위 카드 포장층 빨강 · 아래 알약 켬 — eval `document.querySelectorAll('.b06-chart__pavement.is-active').length`(= 범위 카드 수) · `.b06-cross-card--span` 0 · 세션 `structure-pick` sid. + 2. 범위 안 **관 없는** 다른 카드 누름 → 지금: 포장층 0 · 목록 풀림 · 알약 꺼짐 · sid 없음(= ①). + 3. 범위 안 관 카드의 벽 누름 → 관 폼 · 알약 관 · 포장층 0(= ③). + 4. 아래 종단 노면공 알약 누름 → 1 과 같아야(= ②). + 5. B05 로 가 노면공 알약 → B06 복귀 → 1 과 같아야 · 고른 카드가 범위 첫 카드에서 anchor 카드로 튀는지(= ④). + 6. 같은 측점에 노면공 둘 → 목록 둘째 → 그 층만(= ⑤). +- 위험: ⓐ 는 벽 고름의 `selectionAt`(SPN:519-526) 과 갈래가 다름(안 건드림) · 카드 재누름(해제) 은 전부 풂 그대로 · B05 쪽 `resolveSelection` 은 `coverable` 없이 옛 길(변화 없음). +- 크기: 중간(SPN + SV + 시험). +- ⬜ 범위 안 카드(관 · 벽 없음) 누름 — (가) 노면공 고름 **유지** · 카드만 옮김 (나) 노면공 다시 엶(152-5 되돌림) (다) 지금(모두 풂) → 추천 (가). + +## 고칠 파일 목록 + +| 파일 | 지금 줄 | 요구 | 700 | +|---|---|---|---| +| `B06_Section/B06_Section_UI_Cross_Detail.ts` | 240 | K1(감싼 g · ZP · 단추 · 상태) · K2(`data-empty`) | 여유 | +| `B06_Section/B06_Section_UI_Style_Cross_Detail.css` | 116 | K1(relative · aspect-ratio) · K2(붉은 강조 · picked ≠ hover · empty) | 여유 | +| `B06_Section/B06_Section_UI_Cross_Detail_Pick.ts` | 68 | K2(`presentKeys` · 선택) | 여유 | +| `B06_Section/B06_Section_UI_Page_Structures_Panel.ts` | 548 | K4 ⓐ | 여유 | +| `B06_Section/B06_Section_UI_Section_View.ts` | 578 | K4 ⓑ | 여유 | +| `A00_Common/design/design_view_cross.ts` | 684 | 안 고침 | ⚠ 임박 | +| `A00_Common/b_svg_zoom_pan.ts` | 220 | 안 고침(`minScale` 은 선택) | 여유 | +| T `test_150_detail_pick.py` · `helper_150_detail_pick.cjs` | — | K1 · K2 단정 | — | +| T `test_152_5_pavement_pick.py` · `helper_152_5_pavement_pick.cjs` | — | K4 사례 | — | +| T `test_106_span_highlight_wording.py` | — | K4 소스 단정 유지 확인 | — | diff --git a/docs/raw/요구_1009_4/조사_L_B08모달콘크리트.md b/docs/raw/요구_1009_4/조사_L_B08모달콘크리트.md new file mode 100644 index 000000000..a05dc1409 --- /dev/null +++ b/docs/raw/요구_1009_4/조사_L_B08모달콘크리트.md @@ -0,0 +1,106 @@ +# 조사 L — B08 구조물도 모달(연결 칸 · 카드 배치 · 사본 고침 · [업데이트]) · 자재 탭 콘크리트소요 (10-9 밤 · 읽기 전용 조사 에이전트) + +줄임 = `B08/` → `B08_Quantity/B08_Quantity_` · `M02/` → `M02_MasterTemplete/` · `picker*` → `ui_template/ui_template_item_picker*.ts` · 「추정」 = 코드 · 실자료로 못 굳힌 판단. +실자료(읽기만 · 서버 함수 직접 부름 · DB 읽기만) = 검증_sub6 `storage/1/3/2a505e36…` — 사본 6(모두 「기슭막이 메쌓기 · ㄷ2ㄷ」 계열 · 측점 85.05 그룹 4 · 173.09 그룹 2) · 관 지점 11 · 미연결 10. + +## L2-a. 「조합 연결」 칸 컴팩트 + +- 현재 — `B08/UI_Link.ts:78-130` = 시설마다 제목 `

` 한 줄 + 칸마다 `div.b08-link__slot` 한 줄(이름 · 상태 · [선택] [연결 끊기]) · CSS `B08/UI_Drawing.css:53-79`(3열 grid · 왼쪽 들여쓰기) · 모달 몸통은 세로 flex(`ui_template_modal.css:56-66`) → 칸 줄 수만큼 카드가 아래로 밀림. 실자료 85.05 = 본체 1 + 그룹 4 = 5줄 · 173.09 = 3줄 → 8줄쯤(≈ 260px · 카드 높이는 `calc(94vh - 14rem)` 고정이라 창 안에서 스크롤). +- 고칠 자리(추천 갈래) — 화면만. + - `UI_Link.ts` — 시설 제목 + 칸 줄 → 「시설명 › 칸명 · 상태」 칩 하나(`span` 묶음) · 칩 속에 단추 셋(ghost · sm) · 칩들은 `flex-wrap` 한 줄에 여러 개 · 섹션에 `ui-collapsible` + 제목 `ui-collapsible__title`(공용 `attachCollapsible` · `ui_template_collapsible.ts` · 테마 CSS `ui_template_theme.css:433-456` 캐럿 그림) · 처음 펼침/접힘 = 미연결 칸 있으면 펼침 · 모두 연결이면 접힘(추정 · 사용자 취향 저장은 안 둠). + - `UI_Drawing.css` — `.b08-link__slot` grid → 칩 꼴(`inline-flex` · 테두리 · 간격) · `.b08-link` 칩 줄 `flex-wrap`. +- 재사용 — `attachCollapsible` · 공용 테마 `.ui-collapsible` · `createButton` ghost(156-3 양식 그대로 · 크기만 `sm` 로 — test_156_1:97 「`size: "sm"` 없음」 판정 손봄). +- 시험 — `test_156_1_b08_unlink.py:91-103`(화면 글 판정 — 칩 · 접기 글로 바꿈) · `test_61_2_b08_structure_sheets.py:45`(로케일 키). +- 위험 — 칩이 좁으면 긴 조합 이름이 잘림(`slot.item.name` → 툴팁 `title` 로) · [닫기]와 「같은 양식」(156-3)이 `sm` 로 바뀜. +- 크기 — 작음. +- ⬜ 물음 — 칩 꼴만(가) · 칩 + 접기(나) — 추천 (나)(모두 연결된 보통 때는 한 줄 제목만). + +## L2-b. 카드 셋 배치 — 일위대가 · 면적산출 넓게 · 도면 좁게 + +- 현재 — `B08/UI_Drawing.css:41-45` `.b08-sheets .m02-struct` = `3fr 2fr 2fr`(도면 · 일위대가 · 면적산출 · DOM 차례 = `M02/ItemCards.ts:337` info → labor → sheets) · 높이 `max(480px, 94vh − 14rem)` 한 줄 · 960px 아래 1열. +- 고칠 자리 — CSS 한 줄: `2fr 3fr 3fr` 로 비율만 바꿈(가) · 더하기 도면을 맨 오른쪽(`:first-child { order: 3 }`)(가′) · 도면을 아래 줄 전체 폭(2열 grid + 둘째 줄 · 카드 높이를 둘로 나눔)(나). +- 재사용 — 그대로(`m02-struct` 격자 · 카드 높이 변수). +- 시험 — `test_156_1_b08_unlink.py:111`(`3fr 2fr 2fr` 글 판정 → 새 비율). +- 위험 — (나)는 카드 높이 둘 합이 창을 넘어 모달 안 스크롤 · CAD 미리보기가 작아지면 도각 글이 작게(보기만이라 괜찮음 · 추정). +- 크기 — (가) 아주 작음 · (나) 작음. +- ⬜ 물음 — (가) 한 줄 2:3:3(도면 왼쪽 그대로) · (가′) 2:3:3 + 도면 맨 오른쪽 · (나) 도면 아래 — 추천 (가′). + +## L2-c. 세 카드 = 프로젝트 사본 고침 + +- 현재(보기만) — `B08/UI_Drawing.ts:112-118` `createItemCards({editable: false, onEdit 없음, labor: () => undefined})` · 자료 자리 `sourceOf`(:57-80) = 읽기 · 일위대가 읽기 · 셈만 · `write` 없음 → 카드 [수정] · [저장] 모두 숨김(`M02/ItemCards.ts:326,352-364` · `DrawingCard.ts:62-63`). +- 프로젝트 사본 자리에 이미 있는 쓰기 길: + +| 부분 | 길 | 파일:줄 | 상태 | +|---|---|---|---| +| 도면 · 면적 · 입력값 · 고른자재 | `PUT /api/projects/{id}/items/{폴더}/{종류}` {판, 내용} · 판 다르면 409 · 면적은 서버 재계산 · manifest `고침 true` | `M02/M02_Project_Items_Router.py:185-194` · `M02_Item_Copy.py:181-200` · 화면 `picker_project.ts:187-196` `write` | 됨 | +| 일위대가(담은로직 · 자재) | 같은 PUT — 서버가 400 「일위대가는 원본 층에서 고침 — 프로젝트는 넣을 값만」 | `M02_Item_Copy.py:168-170` `check` · 머리글 :17 · 142-1 · `설계_정함.md` 1절 | 막힘(정책) | +| 편집 화면(사본 전용) | 카드 [수정] → 모달 안 편집 화면 = 도면 CAD · 면적 스프레드시트(알약 = 사본 일위대가 알약 고정) · 넣을 값 카드 → `items.write` | `picker_edit.ts:49-216` `createEditView(EditRequest, onBack)` · `picker_detail.ts:300-331` | 됨 — B08 [선택] → 고르기 모달 → 카드 [수정] 으로 지금도 사본 고침 가능(`UI_Link.ts:39-44` `structureId: slot.copy` = 사본 폴더) | +| M02 카드 안 고침(`source.write` · `sheetEdit` · `laborWritable`) | 층 길(`saveTemplate(layer…)`)로만 — 일위대가 [저장] `ItemCards.ts:328-336` · 면적 연결 저장 `Labor_Detail.ts:679-685` 모두 층 API | 사본엔 없음 | + +- 고칠 자리(추천 갈래 (가) = 편집 화면 재사용 · 서버 안 고침) + - `B08/UI_Drawing.ts` — `editable: () => true` · `onEdit(kind)` → 모달 몸통을 `createEditView({kind, row, info, items, projectId}, onBack)` 로 바꿔치기(고르기 모달 `picker.ts:322-331` 과 같은 꼴) · `labor: () => edit("inputs")`(넣을 값) · [뒤로] → 몸통 되돌리고 그 조합 카드 `load` 다시 · `row` = `copy.항목` + `경로: copy.경로`(제목은 `itemName` = 경로 글) · `info` = `{폴더: copy.폴더, 원본: copy.항목}`(편집 화면은 `info.폴더` 만 씀). + - 로케일 b4 — 없음(편집 화면 글은 `picker_edit.ts` TEXT 그대로 · 한글만). +- 반영되는 길 — 사본 파일이 곧 정본: B08 집계표 값은 설계 값 + 사본 「있음」만 봄(`B08/Router_Summary.py:473-503` · 사본 내용 안 읽음 → 집계표 숫자 변화 없음) · 자재 탭 단위수량 기본은 부를 때마다 `copies.calc`(사본 일위대가 · 입력값 · 면적)로 다시 셈(`Router_Material.py:100-114,173-198` · 저장본 없음) · B09 호표 · 산근 · 재료비는 부를 때마다 `linked_snapshots` 폴더를 직접 읽음(`B09_Estimation_Labor_Source.py:329-337` · `Linked.py:67` · `Sangeun.py:501` · 저장본 없음 · 추정 = B09 화면 캐시는 `designRequestSeq` 류 세션 캐시뿐) → 다음 읽기에 바로. 모달 안 카드는 [뒤로] 뒤 `load` 로 새로. +- 판(version) · 「마스터가 바뀜」 관계 — 판 = 파일 내용 해시(`M02_Item_Source.version_of`) · 쓰면 manifest `고침 true · 고친날`(`list_items` 「고침 있음」 배지 `picker_detail.ts:220`) · 「마스터가 바뀜」 = manifest `원본판` ≠ 지금 원본을 다시 모은 판(`M02_Item_Copy.py:89-95` · 사본 고침과 무관) · 둘은 따로 뜸 · [재적용]은 고침을 덮고 `고침 false`. +- 재사용 — `createEditView`(그대로) · `projectItems.write`(판 들고 있음 · 409 까닭 그대로) · `withCopyValues` · 161-1 `sourceOf`. +- 시험 — 고칠 = `test_61_2_b08_structure_sheets.py:28-33` `test_read_only`(「write · method 없음 · editable false」 판정 뒤집음) · `test_161_1_b08_labor_card.py:15`(`editable: () => false`) · 새 = 모달 [수정] 셋이 `createEditView` 로 · 뒤로 뒤 카드 다시 읽음 · 서버 안 고침(`saveTemplate` 없음 그대로). +- 위험 — 편집 화면 CAD(`mountDrawingTemplate` · `layer: "project"`)가 모달 몸통 높이에 맞는지(고르기 모달 CSS `ui-item-picker__edit-*` 는 그 모달 클래스 안 · B08 `b08-sheets` 에 같은 높이 규칙 몇 줄 필요 · 추정) · 편집 중 [닫기] → `leave()` 물음을 `beforeClose` 에 이어야 함 · 161-1 「보기 전용」 한 줄 머리글 갱신. +- 크기 — (가) 작음~중간(UI_Drawing +40줄 · CSS +10). +- (나) 일위대가 담은로직 · 자재까지 사본에서 고침(정책 뒤집기) — 서버 `check` 풀기 + 사본 일위대가 쓰기 함수(문서 → `labor_doc_rows` 로 로직 줄 · 알약 · 참조사본 다시 + `단가.json` 묶음 재수집 `prices.collect` · `build_source` 뒷부분 `M02_Item_Source.py:156-170` 과 같은 몸) + `ItemSource.labor.write` 추가 · `ItemCards.saveLabor` 를 자료 자리 길로 · `Labor_Detail.saveArea`(:679-685) 에 면적 쓰기 주입 · 참조 줄 읽기 전용 조건(`:453` `ref.층 !== opt.layer`) · 자재 추가 개인 층 조건(`:521`) 손봄 — 크기 큼 · `Labor_Detail.ts` 692줄(700 위험) · 142-1 · 설계_정함 「프로젝트는 넣을 값만」 뒤집음. +- ⬜ 물음 — (가) 지금 정책대로 도면 · 면적 · 넣을 값만 모달에서 바로(편집 화면 재사용) · (나) 일위대가 담은로직 · 자재까지 사본에서 — 추천 (가) 먼저 · (나)는 사용자가 「일위대가 로직까지」 라 하면 따로 장. + +## L2-d. [업데이트] = [재적용] 재사용 · 「마스터가 바뀜」 표시 + +- 현재 — [재적용] = 고르기 모달 오른쪽 상태 줄 단추(`picker_detail.ts:223-226,257-271`) → 확인 창(「고친 도면 · 면적산출이 원본 것으로 덮임 · 넣은 값은 같은 키면 남음」 :90-91) → `projectItems.reapply(info)`(`picker_project.ts:205-224` · `POST …/items/{폴더}/reapply`) → 서버 `M02_Item_Copy.reapply`(:240-279) = 원본 다시 모아 전부 덮음 · 입력값 · 고른자재는 같은 로직 · 같은 입력 이름만 살림 · `덮임`(달라진 도면 · 면적 · 일위대가) 돌려줌 · manifest `원본판 · 가져온날 · 가져온이` 새로 · `고침 false` → 알림 「재적용했음 — 덮인 것: …」. 「마스터가 바뀜」 · 「원본이 없어짐」 배지 = `list_items` 의 `마스터바뀜 · 원본없음`(`M02_Item_Copy.py:98-130` · 사본마다 원본 다시 모아 판 비교 · `?folder=` 하나만 = 156-2 0.43초 → 0.06초). +- B08 쪽에 없는 것 — 집계 응답 `linked`(`B08/Summary_Data.ts:33-39` · `M02_Item_Snapshot.linked_snapshots` :417-438 「원본 층과 대조 안 함」)에 판 비교 없음 → 모달이 따로 `projectItems.list(slot.copy)` 를 불러야 앎. +- 고칠 자리(추천) + - `B08/UI_Link.ts` — 연결된 칸마다 [업데이트] 단추(ghost · [선택] · [연결 끊기] 옆) · 칩 그린 뒤 뒤에서 `items.list(slot.copy)` → `마스터바뀜` 이면 배지 「마스터가 바뀜」 + 단추 켬 · `고침` 이면 배지 「고침 있음」 · `원본없음` 이면 꺼짐 · 바뀜 없으면 꺼짐(툴팁 「원본과 같음」) · 누름 = 초안 막기(`hasPendingDesign` 은 필요 없음 — 사본만 바뀜 · 추정) → 확인 창(`reapplyAsk` 글 + 고침 있으면 「이 사본에서 고친 것이 덮임」 한 줄) → `items.reapply(info)` → 알림(덮인 부분 이름) → 모달 닫고 `onLinked()`(집계표 · 카드 다시 · [선택]과 같은 흐름). + - 로케일 b4 — `B08_Quantity_Link_Update` · `_UpdateTip` · `_UpdateAsk` · `_UpdateDone` · `_UpdateFailed` · `_Changed`(마스터가 바뀜) · `_Edited`(고침 있음) · `_Gone`. + - `UI_Drawing.css` — 배지 색(경고 = 테마 변수). +- 재사용 — `projectItems.list(folder)` · `reapply` · 서버 그대로(고칠 것 없음) · 확인 글 = `picker_detail.ts` TEXT 와 같은 뜻(그 파일 TEXT 는 export 안 됨 → b4 키). +- 시험 — 새 `test_162_x`(화면 글: 단추 셋 · `list(slot.copy)` · `reapply(` · 확인 창 · `onLinked`) · `test_item_picker_detail.py:81-88`(서버 길 그대로) · `test_156_1`. +- 위험 — 칸 6개면 `list` 6번(첫 0.4초씩 · 뒤 0.06초 · 156-2) → 그린 뒤 비동기 · 단추는 알기 전 꺼 둠 · 사용자가 고친 사본(도면 · 면적 · (나)면 일위대가)이 통째 덮임 → 확인 창 필수 · 되돌리기 없음(`_지난/` 보관은 지울 때만 · 조사 E 2절) · 같은 항목을 고른 다른 시설 사본은 따로(칸마다 눌러야 함 — 「전부 업데이트」 는 안 둠 · 추정). +- 크기 — 작음~중간(UI_Link +45줄 · 로케일 +8 · CSS +8). +- ⬜ 물음 — [업데이트] 늘 보이되 바뀜 없으면 꺼짐(가) · 바뀜 때만 보임(나) — 추천 (가)(사용자 원문 「선택 · 연결끊기와 같이 존재」). + +## L5. 자재 탭 콘크리트소요자재집계표가 빈 까닭 — 실측 + +- 실측(2a505e36 · `material_sheets` 직접 부름 · 쓰기 없음) + - 집계표 열 7(흙막이 돌쌓기(찰) 1.5 = 10 m · 흙막이 콘크리트 1.5 = 10 m · 관매설 Φ1000 12 m · 커플링 1 · 세월교 월류 폭 10 · 본체 1 · 날개벽 유입 1) · 저장된 사용자 값 `overrides` = 모두 빈 것. + - 자재수량 열 4 = 콘크리트(기계) · 파형강관 Φ1000 · 모르터 1:3 · MT023984 토목용부직포(160-4 두 열 보임 ✓) · 사본 단위수량 = 부직포 2.61 두 열뿐(흙막이 콘크리트 · 날개벽 유입) · 계 = 부직포 28.71 · 관 12 · **콘크리트(기계) · 모르터 1:3 계 없음**. + - 콘크리트소요 5줄 모두 `qty None` · 배합 상수는 들어 있음(c40 323 · .456 · .612 …) · `concrete.total = {}` → 총괄 시멘트 · 모래 · 자갈 없음 · 총괄 = 파형강관 12 · 커플링 1 · 부직포 28.71(맞춤 없음 끝 줄) 셋. +- 빈 까닭(가설 → 판정) + +| 가설 | 판정 | 근거 | +|---|---|---| +| 손값 넣기 전엔 0 | 확인(절반) | 두 열 단위수량 전부 빈칸 → `sums` 에 키 없음 → `pulled` 없음 → 줄 qty None(`Material_Calc.py:303-337`). 손값 넣으면 바로 채워짐(test_160_4 검산) | +| 사본에 콘크리트 자재가 없음 | 확인(근본) | 사본 6 = 기슭막이 메쌓기 · ㄷ2ㄷ(담은로직 = 메쌓기 · 터파기 · 되메우기 · 자갈채집 · 막돌 · 큰돌 채집 · 굴착기 · 중기운반 · 사전조합 참조 둘) · 로직 재료 = 「주연료 할증 ℓ」 하나(연료 → 뺌 160-3) · 자재 = 부직포 → 콘크리트 · 모르터 ㎥ 원천이 아예 없음. 「흙막이 콘크리트 H=1.5」 열의 조합(grv6lny 기슭막이 ㄷ2ㄷ)도 돌쌓기 로직뿐(콘크리트 열 이름과 조합 내용이 어긋남 — 검증 프로젝트 자료 탓 · 사용자 프로젝트는 다를 수 있음 · 추정) | +| 열 이름 맞춤 실패 | 아님 | `unmatched` = 부직포 하나뿐 · 콘크리트 열은 고정 키 | +| 저장 전 반영 안 됨 | 아님 | 손값은 캐시 + 짝 계산으로 바로(`UI_Material.ts:338-352`) | +| 표 머리만 있고 줄 없음 | 확인(화면) | `concreteTable` `shown(rows, qty != null ‖ amounts 값)`(`UI_Material.ts:194`) → 5줄 전부 숨김 → 공용 표 = 머리 + 계 줄(빈칸)만(`ui_template_data_table.ts:208-223` 빈 줄 안내 없음) · 배합 칸(`per:`)도 줄이 없어 못 고침 · 아래 「빈 칸 까닭」 = 「단위수량 빈 줄 4개 — 자재수량 탭에서 넣음」 + 집계표 알림 4줄(콘크리트 열 이름은 안 짚음) · 「2공구 엑셀 손값과 다름 …」 한 줄은 보임 | + +- 브레인 ORCA 로 볼 것 — 자재 › 콘크리트소요 = 머리(구분 · 규격 · 수량 · 시멘트 · 모래 · 자갈) + 「계」 줄 빈칸 · 위 안내 셋(BASIS · HINTS · 빈 칸 까닭) · 아래 엑셀 손값 다름 한 줄 · 자재수량 탭에서 흙막이 콘크리트 줄 「콘크리트 › 기계 ㎥」 칸에 손값을 넣으면 콘크리트소요 Φ40 줄 · 총괄 시멘트 · 모래 · 자갈 줄이 즉시 생김. +- 고칠 자리(추천 갈래 (가) 화면) + - `B08/UI_Material.ts:192-236` `concreteTable` — 숨김 거름을 뺌(5줄 늘 보임 · 수량 빈칸 · 배합 고침 가능) 또는 원천 있는 줄(c40 · m13)만 늘 보임 · 「빈 칸 까닭」(:314-326)에 콘크리트 전용 한 줄 「콘크리트(기계) · 모르터 1:3 단위수량 빈칸 — 자재수량 탭 그 열에 넣음 · 사본 일위대가에 콘크리트 자재 없음」(`sums` 에 두 키 없을 때 · `MaterialSheets.quantity.total` 로 판정 · 짝 계산 안 건드림). + - (나) 뿌리 = 사본 로직 줄 수량(콘크리트 타설 · 비비기 ㎥)을 콘크리트(기계) 열로 올리는 로직 맞춤 표(146-3 · J4 (나)) — 이 프로젝트엔 그런 로직이 없어 지금은 효과 없음. +- 재사용 — `shown` 도우미 · `note` · `MaterialSheets` 꼴 그대로. +- 시험 — `test_143_3_b08_material_cards.py:14`(「값 없는 줄 숨김」 — 콘크리트 예외로) · `test_121`(화면 연결 :225) · `test_160_4` 그대로 · 새 판정(콘크리트 줄 5 늘 · 까닭 글). +- 위험 — 다른 두 표(총괄 · 자재수량)는 숨김 그대로라 꼴이 다름 · 143-3 「값 없는 줄은 숨김」 안내 글(`HIDDEN`)을 콘크리트 표에선 뺌. +- 크기 — (가) 아주 작음(UI_Material +10줄). +- ⬜ 물음 — (가) 콘크리트 5줄 늘 보임 + 까닭 한 줄 · (가′) 원천 있는 두 줄(Φ40 · 1:3)만 늘 보임 — 추천 (가)(배합 고침 자리 · 엑셀 꼴 그대로 5줄). + +## 고칠 파일 목록 + +| 파일 | 지금 줄 | 고친 뒤(추정) | 요구 | 700 위험 | +|---|---|---|---|---| +| `B08_Quantity/B08_Quantity_UI_Link.ts` | 130 | ~200 | L2-a · L2-d | 없음 | +| `B08_Quantity/B08_Quantity_UI_Drawing.ts` | 175 | ~220 | L2-c(가) | 없음 | +| `B08_Quantity/B08_Quantity_UI_Drawing.css` | 79 | ~115 | L2-a · b · c · d | 없음 | +| `ui_template/ui_template_locale_b4.ts` | 84 | ~100 | L2-a · L2-d | 없음 | +| `B08_Quantity/B08_Quantity_UI_Material.ts` | 388 | ~400 | L5(가) | 없음 | +| `ui_template/ui_template_item_picker_edit.ts` | 216 | 그대로(재사용) | L2-c | — | +| `M02_MasterTemplete/M02_Item_Copy.py` | 409 | (나) 때만 ~450 | L2-c(나) | 없음 | +| `M02_MasterTemplete/M02_MasterTemplete_ItemSource.ts` · `ItemCards.ts` | 49 · 567 | (나) 때만 ~55 · ~585 | L2-c(나) | 없음 | +| `M02_MasterTemplete/M02_MasterTemplete_Labor_Detail.ts` | 692 | (나) 때만 ~700 | L2-c(나) | **있음** — 면적 쓰기 주입은 `Labor_Detail_*.ts` 곁 파일로 | +| 서버(`M02_Project_Items_Router.py` · `Router_Material.py` · `Material_Calc.py/.ts`) | — | 그대로 | L2-d · L5(가) | — | +| 시험 — `test_156_1`(:97 · :111) · `test_61_2`(:28-33) · `test_161_1`(:15) · `test_143_3`(:14) + 새 `test_162_*` | — | — | — | — | diff --git a/docs/raw/요구_1009_4/조사_M_M02자재구분.md b/docs/raw/요구_1009_4/조사_M_M02자재구분.md new file mode 100644 index 000000000..a87078ce0 --- /dev/null +++ b/docs/raw/요구_1009_4/조사_M_M02자재구분.md @@ -0,0 +1,61 @@ +# 조사 M — M02 일위대가 자재 세 칸 기본값 · 「일반」 삭제 · 별도계상 ↔ 운반비 (사용자 M3) + +원문 = 「품셈에 물려 있는 자재의 경우 자재구분에서 일반 항목 삭제 · 기본값 = 사급 · 별도계상 · 운반비 포함 · 별도계상이면 운반비 비활성화」. +앞 기록 = 148-4(`docs/raw/plans/2026-10-09_plan_147-155_*.md:26` · 커밋 d205866f5) · 조사 B3(`docs/raw/요구_1009_2/조사_B_M02자재.md:39-58` · 물음 5 = 처음 값 ① 빈 「—」 로 감). + +## M3-1. 현재 + +- 선택지 한 벌 = 서버 `M02_Labor_Doc.py:48-52` `MARKS`(자재구분 일반 · 관급 · 사급 / 별도계상 별도계상 · 직접계산 / 운반비 포함 · 미포함) ↔ 화면 `Labor_Api.ts:142-146` `MAT_MARKS`(글자 같음 — 시험이 대조 `test_m02_labor_mat_marks.py:127-130`). +- 처음 값 = 없음. 드롭다운 첫 항목 `{ value: "", text: "—" }`(`Labor_MatMarks.ts:52`) · 글 갈래 빈 = 「—」(`:47`) · 빈 값 고르면 칸 지움(`setMark` `:66-69`). +- 저장 꼴 — 사용자 자재 = 줄 덧칸 세 키(`Doc.py:160-168` `marks(one)` 허용 값만 · `Api.ts:206-212` `cleanMarks`) · 로직 자재 = 로직 줄 `자재표시 {호표 차례: {세 칸}}`(`Doc.py:141-143,220-230` `_mat_marks` 차례가 재료 줄인 것만 · `Api.ts:158-164` `cleanShown`). 빈 칸 · 틀린 값 = 조용히 버림(400 아님). +- 두 줄 갈래 같은 부품 — 사용자 줄 `Labor_Rows.ts:601`(손잡이 `RowHandlers.mark` `:220`) · 로직 자재 줄 `Labor_LogicMats.ts:147-150`(`LogicMatHandlers.mark` `:30`) → 둘 다 `markCells(value, set?)`(`Labor_MatMarks.ts:37-63`). `set` 없으면 글만. +- 손잡이 = `Labor_Detail.ts:386-393` `markMat` · `markLogicMat`(화면 캐시만 · 다시 그림 없음 · 로직 자재 줄 손잡이는 구조물 일위대가만 `:237` · 사전조합(`lib`)은 글만) · 읽기 전용 갈래 `Labor_View.ts:96-99`(AreaPanel 고르기 창) = 글. +- 드롭다운 부품 = 공용 `createSelectField`(`ui_template/ui_template_elements.ts:156-183` · 손잡이 `{root, select, setOptions}` · `opts.disabled` 처음 한 번 · `select.disabled` 로 언제든). +- 사본 — `build_source`(`M02_Item_Source.py:133-160` · `labor_doc_rows :92-100`)가 층 문서를 날것으로 `줄` 에 담음 → 세 칸이 사본 `일위대가.json` 에 그대로. 읽는 곳 없음 — B08(`B08_Quantity_Router_Material.py:159-169` 코드 · 수량만) · B09(`B09_Estimation_Labor_Source.py:265-269` calc 답 `자재` = 코드 · 수량만 · `Sangeun` · `Linked` 는 로직 키만). +- B09 관급 · 별도 = 프로젝트 `user_values.json materials[키].supply`(`B09_Estimation_Store.py:7,87-88` · `SUPPLY = ("관급", "별도")` `Calc_Base.py:33,153`) — 사용자가 B09 에서 직접 표시 · M02 세 칸을 안 읽음(145 · 155 모두). 뜻 = 대가 안 0원(`Calc_Labor.py:45-46`) · 자재대 · 관급 단락(`Calc_Bill.py:89-94`). +- 저장된 자료 = `storage/1/10/templates/labor/item1.json:17-22` 하나(사급 · 별도계상 · 미포함 명시) — 148-4 가 오늘 들어가 옛 문서 거의 없음. + +## M3-2. 고칠 자리 + +- 기본값 한 벌 — 서버 `Doc.py` `MARKS` 곁 `MARK_DEFAULT`(사급 · 별도계상 · 포함) ↔ 화면 `Api.ts` `MAT_MARK_DEFAULT`(같은 글자 · 시험 대조 한 줄 보탬). +- 「저장 없이도 보임」 = 읽을 때 기본(저장은 그대로 비움) — 화면 `markCells :42` `value[key] ?? DEFAULT[key]` · 글 갈래 `:47` 빈 = 기본 글(「—」 없어짐) · 드롭다운 `:52` 「—」 항목 지움 · `setMark :66-69` 그대로(고른 값은 명시 저장 — 기본값이라도 지우지 않음 · 빈 값 길은 안 쓰임). 서버 `clean` 은 채우지 않음(`marks` · `_mat_marks` 허용 값만 그대로) · 서버 읽는 쪽을 위한 `mark_of(one, key)` 한 줄(빈 = `MARK_DEFAULT`) — 지금 부르는 데는 없음 · B09 가 엮을 때 그걸로. +- 「일반」 삭제(로직 자재 줄) — `markCells` 에 `logic` 깃발 하나(`LogicMats.ts:147` 에서 참) → 자재구분 선택지에서 일반 뺌. 서버 `_mat_marks :226-228` 일반이면 자재구분 키 버림(→ 기본 사급). 사용자 줄은 ⬜ 물음 1 대로 — 같이 빼면 깃발 없이 `MAT_MARKS.자재구분` 에서 일반을 지우고 서버 `MARKS` 도 같이(옛 값 일반 = 버림 → 사급). +- 별도계상 ↔ 운반비 비활성 — `markCells` 안에서만: 세 `select` 를 묶어 두고 별도계상 바뀔 때 운반비 `select.disabled = (별도계상)` · 처음 그릴 때도 같은 판정. 값은 그대로(「포함」 고정 · 지우지 않음 · 저장도 그대로) — 서버 · 손잡이(`Labor_Detail.ts:386-393`) 안 고침 · 다시 그림 없음. 글 갈래 = 글 그대로(비활성 표시 없음). +- 좁은 화면 `data-label`(`Labor.css:408-416`) · 칸 CSS(`:208-222`) 그대로 — disabled 꼴은 공용 `ui-select` 몫. +- 사본 · B08 · B09 · `Labor_View` · `Labor_Rows` · `Labor_LogicMats` · `Labor_Detail` · `Labor_Text` — 고칠 것 없음(「—」 글 키 없음 · 손잡이 그대로). + +## M3-3. 재사용 + +- `createSelectField` 손잡이 `select`(disabled 토글) · `kindPick`(134-1 드롭다운 꼴) · `MARKS` ↔ `MAT_MARKS` 거울 시험 꼴(`test_m02_labor_mat_marks.py:127-130`). + +## M3-4. 시험 + +- `test_m02_labor_mat_marks.py` 고침 — `:119` 「—」 항목 검사 → 없음 검사 · 새 셋 = (a) 서버 `mark_of` 빈 = 기본 · 허용 값 = 그대로 (b) `_mat_marks` 자재구분 일반 → 키 없음(→ 기본 사급) · 사용자 줄은 ⬜ 1 대로 (c) 소스 검사 = `MAT_MARK_DEFAULT` 글자 = `MARK_DEFAULT` · `disabled` 묶음 한 줄 있음 · 로직 줄 선택지에 「일반」 없음. +- 함께 돌릴 것 = `test_m02_labor_doc` · `promote_flag` · `logic_mats` · `calc_mirror`(금액 무관 그대로) · `card_shell` · `item_labor` · Node 헬퍼 `helper_m02_labor_normalize.cjs`(`normalizeLabor` 만 거침 — 기본값은 화면 그릴 때라 헬퍼 답은 그대로 빈 칸) · typecheck. + +## M3-5. 위험 + +- 뜻 바뀜 — 빈 값이 「미정 —」 에서 「사급 · 별도계상 · 포함」 으로. 읽는 곳이 없어 지금 영향 0 · 옛 문서 하나(`item1.json`)는 명시값. 뒤에 B09 가 M02 세 칸을 `supply` 첫 값으로 엮으면(조사 B3 이음 한 줄) **기본 별도계상 = 모든 자재가 대가 안 0원 · 자재대 단락** — 엮는 날 그 뜻을 사용자와 다시 맞춤(엮지 않는 한 무관). +- 로직 줄 옛 값 「일반」 = 서버가 버려 사급으로 읽힘(허용 값 줄이는 길 = 134-1 `승격` 꼴 · 저장 안 막힘). +- 운반비 비활성이 화면 안에서만 — 서버는 별도계상 + 미포함도 받음(값 그대로 보관). 뜻 판정은 읽는 쪽(`mark_of`) 몫 — 별도계상이면 운반비 무시. +- `Labor_MatMarks.ts` 78줄 → ~100 · `Labor_Doc.py` 607 → ~615 · 그 밖 700 위험 없음(`Labor_Detail.ts` 692 안 건드림). + +## M3-6. 크기 + +작음 — 파일 넷(부품 하나 · 타입 하나 · 서버 하나 · 시험 하나). + +## ⬜ 물음 + +- ⬜ 1 직접 넣은 자재 줄(사용자 자재 · [자재 추가])도 「일반」 삭제 · 같은 기본값? 원문은 「품셈에 물려 있는 자재」 = 로직 자재 줄만. ① 로직 줄만(사용자 줄 일반 남김 · 깃발 하나) ② 두 줄 다(선택지 한 벌 · 서버 `MARKS` 도 일반 뺌) — 추천 ②(한 벌 · 깃발 없음 · 「일반」 뜻이 사급과 겹침) · 갈래가 갈려 사용자 확인. + +## 고칠 파일 목록 + +| 파일 | 할 것 | 줄(지금 → 추정) | +|---|---|---| +| `M02_MasterTemplete/M02_MasterTemplete_Labor_MatMarks.ts` | 기본값 보임 · 「—」 지움 · 일반 뺌(로직 줄 깃발 또는 한 벌) · 별도계상 ↔ 운반비 disabled | 78 → ~100 | +| `M02_MasterTemplete/M02_MasterTemplete_Labor_Api.ts` | `MAT_MARK_DEFAULT`(⬜ 1 ② 면 `MAT_MARKS.자재구분` 일반 뺌) | 297 → ~300 | +| `M02_MasterTemplete/M02_Labor_Doc.py` | `MARK_DEFAULT` · `mark_of` · `_mat_marks` 일반 버림(⬜ 1 ② 면 `MARKS` 일반 뺌) · 머리 글 `:23-24` | 607 → ~615 | +| `M02_MasterTemplete/M02_MasterTemplete_Labor_LogicMats.ts` | ⬜ 1 ① 일 때만 — `markCells` 에 로직 깃발 | 158 → ~159 | +| `resources/tester/test_m02_labor_mat_marks.py` | 「—」 검사 바꿈 · 기본 · 일반 · disabled 셋 | 130 → ~160 | + +안 고침: `Labor_Detail.ts` · `Labor_Rows.ts` · `Labor_View.ts` · `Labor_Text.ts` · `Labor.css` · `M02_Item_Source.py` · B08 · B09(`supply` 는 따로) · `resources/master_data`. diff --git a/docs/raw/요구_1009_4/조사_N_B09내역요율재료비.md b/docs/raw/요구_1009_4/조사_N_B09내역요율재료비.md new file mode 100644 index 000000000..f491bd5f3 --- /dev/null +++ b/docs/raw/요구_1009_4/조사_N_B09내역요율재료비.md @@ -0,0 +1,162 @@ +# 조사 N — B09 요율 자동 · 설계내역서 손 줄 · 재료비목록표 · 견적가 · 경비집계표 · 일위대가목록표 (10-9 넷째 · 읽기 전용 조사 에이전트) + +파일 = `B09_Estimation/` 아래 · 머리 `B09_Estimation_` 생략 · 기준 = 랩탑 메인 HEAD 35d6b68c4 · 원문 = `사용자요구_1009_4.md` 6~10 + 브레인 추가 N11 · 엑셀 = `resources/knowledge/original/실무문서/2024년 간선임도(기번3-울진.대흥)(공통)/1. 설계원본/01 내역자료/2024년 간선임도사업(기번3).xlsx`(openpyxl 읽기 전용 · 셀 = `탭!셀`) · 실측 = `storage/1/3/2a505e36-…`(읽기 스크립트 · 사본 6 · M01 만 · DB 안 씀 → B08 수량은 못 읽음) · 「추정」 = 코드 · 자료로 확인 못 한 판단 · 지난 기록 = 144 · 145(`plans/2026-10-09_plan_134-145_*.md:111-130`) · 155(`…147-155_*.md:89-95`) · 157(`…156-159_후속.md:16-25`) · 조사 F · F 부록 · H · `요구_1009/분석_정함.md` 144 · 145. + +## 0. 한 줄 결론 +- N6 요율 = 후보 글만 보이고 값은 사용자 손입력(빈칸 시작) · 고르는 값 칸(추정가격 · 공기 · 공종)은 저장 칸만 있고 화면 없음 → M01 표를 압축해 짝 셈이 자동으로 고르고 사용자 값이 앞섬. +- N7 설계내역서 = 서버가 B08 로 짠 고정 줄(토공 17 · 구조물 열 · 운반 6)만 · 수량 · 줄 손질 저장 칸 없음 → `user_values.json › bill` 에 손 줄 · 수량 덮어쓰기 · 연결(대가 · 산근 키) · 우클릭 메뉴는 공용 지도 메뉴 재사용. +- N8 재료비목록표 = 대비표 적용 단가만(수량 · 총액 없음) · B08 총괄 줄은 이미 들어옴(단가 빈칸) → 수량 · 총액 열 둘 더함. +- N9 대비표 = 출처 6 · 최저 자동 · 손 수 입력 · 관급/별도 → 「견적」 출처 열 + 적용 출처 고르기 + 견적서 파일 자리(새 upload 길 · 저장 = `B09_Estimation/v1/quotes/`). +- N10 경비집계표 빈 까닭 = 설계상 구멍 — 어느 원천도 「경비」 자원 줄을 안 냄(기계는 중기 · 구역화물은 자재) · 실측 경비 자원 0 · 시험은 합성 줄만 잼. +- N11 목록표 ≠ 일위대가표 = 어긋남 없음(같은 셈 한 벌 · 실측 6 블록 모두 같음) · 보이는 차이 = 빈칸 규칙(한 줄이라도 빈칸 → 블록 합 빈칸 · 줄 금액은 보임) → 「아는 줄 합 + 빈 줄 n」 꼴로. + +## N6. 총괄설계내역서 요율 자동 + 사용자 고침 +- 현재(요율 칸이 채워지는 길): + - `Rates.py:30-47` `rate_candidates` = M01 `요율_조달청제비율.json` 줄마다 **글 한 줄**(「M01 RT000008 18.3~21%(구간 · 고르는 값 사용자)」) · 값 안 고름 · lru_cache · `Router.py:98` payload `rate_candidates`. + - 요율 값 = `user.estimate.rates{줄 키: %}` 만(`Store.py:98-100`) · 빈칸 시작 · `Calc_Total.py:72-73` `rate = rates_in` · `_pct` :58-60 빈칸이면 그 줄 빈칸 · 소계도 빈칸(145-4 규칙) · TS 짝 `Calc_Total.ts:54`. + - 고르는 값 = `Store.py:28-31` `estimated_price` · `duration_days` · `work_type` 저장 칸 **있음** · 화면 입력 칸 **없음**(`UI_Tabs_Total.ts:29-36` HAND = 기초액 · 이윤 보정 · 부가세 조정 · 조달수수료율 · 간접재료비 · 작업설 뿐) · 어디서도 안 읽음. + - 화면 = `UI_Tabs_Total.ts:91-96` rateRow(요율 칸 · 후보 글 칸) · :143-146 열 · :153-156 editable · :40-55 editEstimate(빈칸 = 지움). +- M01 자료 꼴(19 줄 · 다섯 갈래 · 값 전수 읽음): + - 단일 `rate_percent` — RT000001 산재 3.56 · 03 건강 3.595 · 05 장기요양 13.14 · 11 퇴직 2.3 · 12 임금 0.09 · 13 석면 0.006 · 19 부가세 10. + - `brackets[direct_cost_bracket × duration_bracket × work_type]` — 08 간접노무비(60줄 · civil 18.9~21.0) · 09 기타경비(60줄 · civil 5.5~8.1) · 구간 = 직접공사비 5(lt_1 · 1_to_5 · 5_to_30 · 30_to_100 · gte_100 **billion = 십억** — 17 번 basis 글) × 공기 4(≤183 · 184~365 · 366~1095 · ≥1096 일) × 공종 3(civil · landscape · industrial). + - `brackets[estimated_price_bracket]` — 17 일반관리비(종합 표 lt_5 8.0 · 5_to_30 6.5 · 30_to_100 5.0 · gte_100 4.5 + 전문 표) · 18 이윤(15 · 12 · 10 · 9) · 14 하도급(0.081 …). + - 02 고용 = 추정금액 등급 8(below_official_threshold 1.01 ~ gte_140 1.57) · 06 안전 = `target_amount_bracket × work_type` + `base_amount_krw`(civil lt_500M 3.15 · 500M_to_5B 2.53 + 3,300,000 · gte_5B 2.6 · 관리자 2.73) · 07 기초액 = 06 안 · 04 연금 `annual_rates[year]`(2026 4.75 … 2032 6.25) · 10 환경 `forest_road_selection_status: pending`(road 0.9 · other_civil_work 0.8) · 15 기계대여 general_construction civil_general 0.4 · 16 이행보증 = 식 글(임도 비대상). + - `처리규칙` = 끝수 · 안전 A/B · 관급 — 지금 `Calc_Total.py` 와 같음(거울 시험 글 `test_b09_rate_rules_mirror.py` 는 파일 없음 · `B09_Estimation_Statutory` 는 `tmp/old_code` 만). +- 엑셀 꼴: 총괄 `M49~M64` 요율 14 손입력 · `N55` 기초액 5,349,000 · `I62` 이윤 보정 905,980 · `O66` 수수료 375,160 · 식 = `D49 =ROUNDDOWN(E48*M49/100,0)` 꼴 · 2024 값 = 14.5 · 3.56 · 1.01 · 3.545 · 12.95 · 4.5 · 1.86 · 6 · 0.8 · 0.4 · 6 · 15 · 10 — 2026 표와 다름(간노 14.5 ↔ 18.9~21 · 건강 3.545 ↔ 3.595 · 연금 4.5 ↔ 4.75 · 안전 1.86 ↔ 2.53) → 자동값으로 엑셀 총공사비는 안 맞음(연도 차 · 정상) · 꼴(밑수 · 끝수)만 같음. +- 자동 고르기 규칙(짝 셈 안 · 입력 = 추정가격 · 공기 · 연도 · 직접공사비 = 가.순공사비계 · 안전 대상액 = 재료비 + 직노(+ 관급 ÷ 1.1 · 이미 `Calc_Total.py:92-97`)): + | 줄 | 구간 키 | 고르는 값 | 임도 기본 | + |---|---|---|---| + | 간접노무비 · 기타경비 | direct_cost × duration × civil | 순공사비계 · 공기(일) | 공종 = 토목 고정(`제비율.md:37-48` 「임도 = 토목공사 확정」) | + | 일반관리비 · 이윤 · 하도급 | estimated_price | 추정가격 | 종합(토목) 표 | + | 고용 | estimated_amount 등급 | 추정가격 | 140억 미만 = 1.01 | + | 안전 | target_amount × civil (+ 기초액) | 대상액(셈) | 5~50억 = 2.53 + 3,300,000 → 기초액 손입력 칸은 자동값 위에 사용자 덮어씀 | + | 연금 | year | 연도(오늘 해 · 입력 없음) | 2026 4.75 | + | 환경 | pending | 선택 칸(도로 · 그 밖) | ⬜ | + | 산재 · 건강 · 장기요양 · 부가세 · 기계대여 · 퇴직 · 임금 · 석면 | 단일 | - | 그대로 | +- 고칠 자리: + - `Rates.py` — 후보 글 옆에 **압축 표** `rate_table{RT 키: {갈래, 줄[{조건…, pct, base}]}}` 하나 더 내어 payload `rate_table`(서버가 파일 읽는 유일한 곳 그대로 · `Calc_Total` 「파일 · M01 안 읽음」 규칙 지킴). + - `Calc_Total.py:68-73` · `Calc_Total.ts:54` 짝 — `pick_rates(table, ctx)` → 줄마다 `{rate, from: 자동 | 사용자, why: 「직접공사비 10억 미만 · 공기 183일 이하 · 토목」}` · `rate = 사용자 값 ?? 자동` · 자동도 없으면 빈칸(145-4 규칙 그대로) · 구간 밑수가 빈칸(순공사비계 None)이면 그 줄 자동 없음. + - `Store.py:28-38` — `environment_kind`(도로 · 그 밖) 한 칸 더 · `work_type` 글 칸은 그대로(안 씀 · 추정) · `estimated_price` · `duration_days` 그대로. + - `UI_Tabs_Total.ts` — 맨 위 「요율 고르는 값」 줄 셋(추정가격 · 공사기간(일) · 환경보전비 공종 — 손입력 열) · 요율 칸 = 자동값 보이기 + 「요율 후보」 열 → 「출처」(자동 까닭 글 · 「사용자」) · 사용자가 지우면 자동으로 돌아감(지금은 빈칸). + - `Router.py:98` payload `rate_table` 한 줄 · `UI_Shell.ts:132` computeTotal 인자 셋째. +- 재사용: `rate_candidates` 글 그대로(출처 열) · `_pct` · 끝수 · 안전 A/B 셈 그대로 · 공용 표 손입력 칸 꼴(:144). +- 시험: `test_145_4_b09_total_calc.py:73-95` 엑셀 검산(요율을 입력으로 줌 → 그대로) · :104 빈칸 규칙 → 「자동 없음 = 빈칸」 으로 · :127 후보 글 → 표 꼴 · 새 = 구간 고르기 7 경우(10억 경계 · 183일 경계 · 추정가격 50억 · 안전 5억 경계 + 기초액 · 연금 2026 · 환경 선택 · 사용자 값이 앞섬) · 거울 :150 에 같은 경우 · :164 화면 칸. +- 위험: 요율 빈칸 규칙이 바뀜(자동이 채워지니 소계가 바로 생김 — 추정가격 · 공기 빈칸이면 간노 · 기타경비 · 일반관리비 · 이윤 · 고용 자동 없음 → 그 소계 빈칸은 그대로) · 2024 엑셀과 값 다름을 화면 안내 한 줄 · `Calc_Total.py` 161 → ~230 안전. +- 크기: 중간. +- ⬜ 물음 1: 환경보전비 공종 — ① 그 밖의 토목 0.8 기본 + 선택 칸(엑셀 울진 0.8) ② 도로 0.9 기본 — 추천 ①. + +## N7. 설계내역서 — 수량 입력 · 일위대가 · 산근 연결 · 우클릭 줄 손질 +- 현재(줄 원천 · 145-3 · 155-3): + - `Bill_Items.py:25-43` EARTH 17(토공 고정 · B08 토공집계표 짝 · 1.1 준비공 3 = 원천 없음) · :87-113 `structure_items`(B08 구조물 집계표 열마다 · `ref dg_list` · `owners{사본 주인: 값}`) · :116-138 HAUL 6(B08 총괄자재 합) · :141-148 → `inputs.bill.items`(`Router.py:88`) · :151-154 `hopyo_prices` = **빈 묶음**(쓰이지 않음 → `Calc_Bill.py:144` `hopyo = {}` · ref 없는 줄 단가 빈칸). + - `Calc_Bill.py:135-239` 짝 — 구조물 열은 `split_by_block`(:110-132 · 주인 → 대가 블록 · `price_of(owner)` = `Calc_Labor.daega_price` :192-204) · 토공 · 운반 = `hopyo.get(ref.key)` → None · 자재대 · 관급 = 대비표 표시(:84-104) · 수수료 줄 · 제목 합 :189-219(「빈 줄 n」) · TS 짝 `Calc_Bill.ts:59 · 78 · 103 · 129`. + - 화면 `UI_Tabs_Bill.ts:22-63` — 고칠 칸 = 수수료 율(:51) 뿐 · 줄 누름 = ref 탭(:58-61) · 우클릭 없음 · 공용 표 `createDataTable`(`ui_template_data_table.ts:234-294`) 에 contextmenu 갈고리 없음(click · change 만). + - 손 줄 저장 자리 = 없음 — `Store.py:77-101` `clean_user` = materials · estimate 만. + - 호표 번호 — 대가 = `Labor_Source.py:338-340` 차례(조합 → 사전조합 → 품셈 · 처음 본 차례 · id = 내용 해시 `DG:…`) · 산근 = `Sangeun.py:287-293` `Solver.add` 첫 등장(키 `SG:로직:해시` · `uses` = 주인) · 대가 → 산근 이음 = 키(`Calc_Labor.py:164-166`). +- 엑셀 꼴: 설계내역서 A 공종 · B 명칭 · C 규격 · D 수량(손입력 137) · E 단위 · F/G 합계 · H/I 노무 · J/K 재료 · L/M 경비 · N 비고(「대가 5호표」 · 「산근 13호표」 · 「자재 28」) · 단가 = 목록표 식(`H57 =일위대가목록표!F…` · `=단가산출근거목록표!…` · `=재료비목록표!E…`) · 금액 ROUNDDOWN 0 · 제목 = SUMIF. +- 고칠 자리: + - `Store.py` — `user.bill = {qty: {줄 키: 수}, rows: [{key: "손:…", section, name, spec, unit, qty, ref: {tab: dg | sg | material, key} | null, logic: {code, given, rate, picks} | null}]}` · `clean_user` 다듬기(모르는 칸 버림 · 수만). + - `Bill_Items.py` — `bill_items(b08, user)` 에 손 줄 덧붙임(`kind item` · 공종 = 고른 절) · `hopyo_prices` 자리 채움 대신 짝 쪽에서 읽음(아래). + - `Calc_Bill.py` · `.ts` 짝 — ① 수량 = `user.bill.qty[key]` 가 있으면 그 값(없으면 B08 · 지우면 B08) · 구조물 줄(`st:`)은 자동 그대로(수정 불가 · 지시) ② 단가 = `ref.tab` 따라 `sheets.daega`(목록 합계) · `sg_list` · `compare.applied` 에서 읽는 `price_of(ref)` 하나(지금 `hopyo` dict + owner 함수 둘 → 하나) · 비고 = 「대가 n」 · 「산근 n호표」 · 「자재 n」. + - 새 산근(M01 로직 고르기) — `Sangeun.py:496-504` `build` entries 에 손 줄 로직 `(owner="손:줄키", src{code, given, rate, picks})` 더함(`Solver.add` 그대로 · whole = `M02_Item_Prices.master()` :36 · 번호 = 사본 산근 뒤) · 서버 단독이라 [저장] 뒤 반영(산근 탭 안내 그대로). + - 새 대가(M02 서고 일위대가 문서) — `Labor_Source.py:208-239` `precombo` 에 서고 문서(`M02_Labor_Ref.read_ref` :88) 넣으면 블록 · 차례 「사전조합」 자리 → 기존 번호 밀림(줄 키는 블록 id 라 연결은 안 끊김 · 비고 번호만) — ⬜2 따라. + - 화면 — 새 파일 `UI_Tabs_Bill_Edit.ts`(우클릭 메뉴 · 고르기 창 · 손 줄 입력 폼) · `UI_Tabs_Bill.ts` editable = 수량(구조물 · 제목 · 수수료 빼고) + 손 줄 명칭 · 규격 · 단위 · `UI_Shell.ts:194-222` makeTable 뒤 표 root 에 contextmenu 듣기(:212 tip 꼴 · 공용 표 안 고침). +- 재사용: 우클릭 = `ui_template_context_menu.ts`(MapContextMenu · open(x, y, items) · 전역 하나 · B04 · B05 · M02 나무가 씀) · 브라우저 기본 메뉴는 이미 막힘(`ui_template_native_menu.ts:10` B 영역) · 로직 고르기 = `M02_MasterTemplete_Labor_Pick.ts:57` `openLogicPicker(done, lib?)`(M01 로직 + 서고 단가승격 · 일위조합 한 목록 · 거름) · 입력값 = `M02_MasterTemplete_Labor_Input.ts:53` `openLaborInput({logic, values, rate, done})` · 142-1 카드 `openItemPicker`(`ui_template_item_picker.ts:118`) = 구조물 조합 항목 고르기 → 구조물공 자동 셈 몫이라 손 줄엔 안 맞음 · 이미 있는 호표 고르기 = `ui_template_find_list`(Labor_Pick 이 씀 · 작은 목록 창 · 추정) · 절 고르기 = `SECTIONS`(`Calc_Bill.py:27-42`). +- 시험: `test_145_3_b09_bill.py:90`(호표 단가 줄) · :197 거울 · :218 블록 나누기 그대로 · 새 = 수량 덮어쓰기(B08 값 · 사용자 값 · 지움) · 손 줄 더하기 · 지우기 · 연결 dg · sg · material 단가 · 구조물 줄 수량 못 바꿈 · 새 산근 번호 = 사본 뒤 · 네 탭(대가 목록 · 대가 · 산근 목록 · 산근)에 실림(`test_145_1` collect 꼴) · `Store` clean_user bill · 거울. +- 위험: 손 줄 키가 호표 번호가 아니라 블록 id · 산근 키라 번호 바뀌어도 안 끊김 · 새 산근 · 대가는 서버 단독 → 조작 중엔 「[저장] 뒤」 · `UI_Tabs_Bill.ts` 63 → 새 파일로 나눔 · `Calc_Bill.py` 248 → ~290 안전. +- 크기: 큼. +- ⬜ 물음 2: 손 줄 연결 대상 — ① 이미 있는 대가 · 산근 호표 + M01 로직(새 산근 · 입력값 모달) 먼저 · M02 서고 일위대가 문서는 뒤 ② 셋 다 한 번에 — 추천 ①(「일위대가나 단가산출로직에서 선택」 = 목록표 호표 + 로직으로 읽음 · 추정). + +## N8. 재료비목록표 = B08 총괄자재 목록 + 합계 × 단가 +- 현재: `Calc_Base.py:171-174` `material_sheet(compare)` = 대비표 줄 그대로(no · key · name · spec · unit · supply · origin · **price 만**) · `UI_Tabs_Base.ts:171-191`(호표 · 명칭 · 규격 · 단위 · 단가 · 관급별도 · 비고) · 수량 · 금액 열 없음 · TS 짝 `Calc_Base.ts:145`. + - B08 줄은 이미 들어옴 — `Prices.py:210-230` `b08_material_rows`(총괄 `sheets.material.rows` 중 `amount` 있는 줄 → 키 `b08:…` · `origin B08` · prices {} · `qty` = amount) · :250 materials = 사본 자원 줄 + B08 줄 → 대비표 · 재료비목록표에 **단가 빈칸**(사용자 손입력) · 144 안내 글. + - 서버 길(이미 있음): `Router.py:44-58` `_b08` → `B08_Quantity_Router_Material.material_sheets`(:236-240 · 160-3 뒤) → `sheets.material.rows`(`B08_Quantity_Material_Calc.py:382-395` — key · group(이름) · spec · unit · qty · surcharge · **amount = 할증 뒤 끝수 = 「합계」 열** · 맞춤 없는 사본 자재 :363 끝 줄(키 = MT 코드 또는 `이름|단위`) · 채집석 공제 줄 :359 `DEDUCT_KEY`). + - 실측 2a505e36: 사본 자원 자재 3(MO000002 경유 · MO000001 · MT003848 토목용부직포 — M01 값 없음 → 적용 단가 빈칸) · B08 줄은 DB 길이라 이번 스크립트로 못 읽음. +- 엑셀 꼴: 재료비목록표 A 호표 B 명칭 C 규격 D 단위 E 단가(`=자재단가대비표!O5`) F 비고 — 수량 · 금액 열 **없음** · 수량 × 단가는 재료비수량금액집계표(D 수량 · F 단가 · G `=ROUND(D4*F4,0)`) → 사용자 요구 = 목록표에 수량(B08 합계) · 총액 열을 더하는 엑셀 밖 꼴. +- 고칠 자리: + - `Calc_Base.py:171-174` · `.ts:145` 짝 — `material_sheet(compare, qty_of)` 에 `qty`(B08 amount · 사본 자원 줄은 빈칸) · `amount = ROUND(qty × price, 0)`(집계표 자리 · ⬜3) · 단가 · 수량 하나라도 빈칸 → 빈칸. + - `Prices.py:210-230` — 채집석 공제 줄(`DEDUCT_KEY` · 뺄 양) 거름 · 키가 MT 코드인 맞춤 없는 줄(`b08:MT…`)은 사본 자원 줄과 같은 자재 → 같은 줄에 qty 만 얹음(두 줄 안 만듦 · 추정) · 커플링 · 파형강관 줄은 관급 표시 사용자 몫 그대로. + - `UI_Tabs_Base.ts:171-191` — 열 「수량(B08 합계)」 · 「총액」 · 합계 줄(총액 합) · 안내 「수량 = B08 총괄자재수량집계표 합계(할증 포함)」. +- 재사용: `_b08` · `b08_material_rows` · 공용 표 total 줄(집계표 탭 :45 꼴). +- 시험: `test_144_b09_base_calc.py:122`(최저 · 사용자 · 관급) + 거울 :168 · `test_145_3_b09_bill.py:35-40` B08 줄 fixture → 수량 · 총액 단정 · 공제 줄 거름 · MT 코드 줄 합침. +- 위험: 재료비목록표 총액 합 ≠ 설계내역서 재료비(목록표 = B08 수량 × 단가 · 내역 = 호표 전개) → 안내 글로 구분 · 작음. +- 크기: 작음. +- ⬜ 물음 3: 총액 끝수 — ① ROUND 0(엑셀 집계표 자리) ② ROUNDDOWN 0(내역 금액 자리) — 추천 ①. + +## N9. 자재단가대비표 — 견적가 열 · 견적 고르기 · 견적서 첨부 자리 +- 현재: 출처 열 6 = `Calc_Base.py:30` SOURCES(관급 · 물가정보 · 물가자료 · 유통물가 · 거래가격 · 유가) ← `Prices.py:28` MT_SOURCES + 유가(:77-100 `material_input` prices · pages) · 최저 = :128-135 `lowest`(0 · 빈칸 뺌 · 같으면 앞 칸) · 적용 = :147-150(`user.materials[key].applied` 수 → 「사용자」 · 아니면 최저) · 관급/별도 = `supply`(:153) · 저장 = `Store.py:85-90`(applied · supply 만) · 화면 `UI_Tabs_Base.ts:104-169`(번호 · 품명 · 규격 · 단위 · 출처 6 × (단가 · 면) · 최저 · 적용 단가 · 출처 · 관급별도 · 적용 칸 손입력 :148-158 · 관급별도 칸 누름 돌림 :159-167) · TS 짝 `Calc_Base.ts:29 · 109 · 134-135`. +- 엑셀 꼴: E/F 조달 · G/H 물가정보 · I/J 물가자료 · K/L 적산정보 · **M/N 견적단가(단가 · 페이지)** · O/P 적용(단가 · 출처 글 「조달 · 물정 · 물자 · 적산 · 견적」) · Q 비고 · 숨은 T 이전단가 · U/V/W 최소단가(`V5 = MIN(IF(E=0,MAX,E), …, IF(M=0,MAX,M))` — **견적 포함 · 0 제외**) · 견적 줄 7(전기뇌관 3,920 · 폭약 12,712 · 자갈 21,000 · 모래 29,000 · 국가지점번호판 520,000 · 파쇄암 44,000 · 면목 142 「인터넷」) · 적용 O = 손입력(46줄 모두 최소와 같음 · 견적만 있는 줄 = 견적). +- 고칠 자리: + - `Calc_Base.py` · `.ts` 짝 — SOURCES 끝에 「견적」 · 값 = `user.materials[key].quote`(수) · 면 = `quote_page`(글) · `lowest` 는 견적 포함(엑셀 MIN 꼴 · ⬜4) · `pick`(출처 이름 · 「견적」) 있으면 `applied = prices[pick]`(견적이 높아도) · 손 수 `applied` 는 그대로(「사용자」) · 차례 = pick › applied 수 › 최저. + - `Store.py:85-90` — quote · quote_page · pick · files[{name, size, at}] 다듬기. + - `UI_Tabs_Base.ts:104-169` — 「견적」 단가 · 면 칸 = 손입력 · 「출처」 칸 누름 = 돌림(자동 → 관급 → … → 견적 · `SUPPLY_NEXT` :104 꼴) · 「견적서」 칸 = 「n 파일」 누름 → 작은 모달(새 파일 `UI_Tabs_Base_Quote.ts` · 목록 · 올리기 input multiple · 지우기 · 여러 파일) — 자리만. + - 파일 길(새 · `Router_Quotes.py` 추천) — `POST /api/projects/{id}/estimation/quotes/{자재 키}`(multipart · 여러 파일) · `GET …/quotes/{키}/{이름}`(FileResponse) · `DELETE` · 저장 = `B09_Estimation/v1/quotes/{키}/{이름}`(`Store.folder` :41 아래 · 키 · 이름 경로 검사) · 메타 = `user_values.json › materials[키].files`(DB 표 없음 · 추정 권장). +- 재사용: 올리기 = `B03_FileInput_Engine.save_upload_stream`(:69 · 크기 한도 · 임시 → 교체) · 경로 검사 꼴 :62 · 다른 페이지 「프로젝트 첨부」 꼴 = 없음(B03 입력 파일 = DB 메타 + 분석 · B01 회사 자산 = DB 표 + storage · B07 frame import = 바로 파싱) → B09 독자 길 · 모달 = `ui_template_modal.openModal`(Labor_Input 이 씀). +- 시험: `test_144_b09_base_calc.py:122` 에 견적 최저 · pick 견적(높아도) · 손 수 우선 + 거울 :168 · `Store` 다듬기 · 새 upload 시험(TestClient · 임시 storage · 두 파일 · 지움 · 경로 탈출 400). +- 위험: 대비표 열 7 × 2 + 견적서 = 폭(가로 스크롤 · 공용 표 frozen 2) · `UI_Tabs_Base.ts` 275 → 모달은 새 파일 · `Calc_Base.py` 320 → ~345 안전. +- 크기: 중간. +- ⬜ 물음 4: 견적가를 최저 자동에 — ① 포함(엑셀 MIN 식 · 견적만 있는 줄 = 견적 자동) ② 제외(사용자가 pick 할 때만) — 추천 ①. + +## N10. 경비수량금액집계표가 빈 까닭 +- 현재(그 탭이 읽는 것): `UI_Tabs_Summary.ts:55` ← payload `summary.sum_expense` ← `Summary.py:121-130` `_resource_sheet(used["expense"], sheets["expense"])` · `used` = :47-66 `totals`(내역 항목 × 호표 전개 :29-45) · 호표 구성 = :158-160 `hopyo_lines` = 산근 블록 + 대가 블록 줄을 :144-155 `block_lines` 가 `LINE_KIND`(:134-141 labor · material · expense · machine · sangeun · daega)로 거름 → **kind == "expense" 줄만 경비집계표**. +- 「expense」 kind 를 내는 원천 = **없음**(거름이 아니라 원천 설계 구멍): + - `Sangeun.py:377-418` `_line` — 인력 → labor · 재료 → material(**비목이 「경비」여도 kind material** :410-418 · 금액만 expense 칸) · 로직 → machine · sangeun(:420-437) · 덧줄 → extra(:449 · LINE_KIND 밖) · 빈 줄 blank. + - `Labor_Source.py:127-158` `_engine_line` — labor · material · machine · sangeun · pct · blank · 조합 자재 줄 material(:265-269). + - 대가 블록 `Calc_Labor.py:43-46` 재료 줄 = 비목 무시(material 칸) ↔ 산근 `_line` 은 비목 칸 → 같은 로직이 블록 꼴에 따라 비목이 다름(작은 어긋남). +- 실측 2a505e36(읽기 스크립트 · 사본 6 · M01 만): 호표 구성 줄 = labor 21 · machine 19 · material 3 · hopyo 23 · **expense 0** · 비목 경비 줄 = 덧줄 「제잡비 노무비의 %」 하나(608.4 · kind extra → 자원 아님) → 원천 비어 있음 + 갈래 없음 둘 다 · 거름 버그 아님. +- 시험 = `test_145_5_b09_summary.py:57` 합성 줄 `{"kind": "expense", "key": "E16"}` 로 678,345 통과 — 실제 코드가 못 내는 줄을 재서 기준이 변경을 안 잼. +- 엑셀 꼴: 경비수량금액집계표 2줄 — 16 구역화물자동차 5톤(20km 이내) 11.03 회 × 61,500(`=경비목록표!E19` 회 단가 손입력) = 678,345(ROUND 0) · 21 덤프자동덮개 24톤 243.89 천원 × 1,794(`E24` 손료 기준가) = 437,539 · 경비목록표 23 = 기계 손료 기준가(천원) 22 + 회 단가 1 · 집계표 = 산근이 경비목록표 줄을 **직접** 부른 것(중기사용료 안 거침). +- Aislo 짝: 구역화물 = M01 `재료_자재품목` MT023366~(구역화물 n톤 · n km · 재료) → 재료비 쪽 · 덤프자동덮개 = M01 `기계.json` EQ000078~80(덤프트럭 자동덮개시설 · 손료만) → 중기목록표 블록 → 중기시간금액집계표 · M01 로직 호표 줄 비목 「경비」 = 재료 3(GF000002 작업로 설치 · 56 어린나무 가꾸기 · 76 방제 벌목조재 — 체인톱 손료 · 임도 조합엔 없음) → 지금은 재료비집계표로 감. +- 고칠 자리(갈래 둘): + - ① 안내만 — `UI_Tabs_Summary.ts:55` 경비 탭 hint 「경비 자원 줄 없음 — 기계 = 중기시간금액집계표 · 구역화물 등 = 재료비 · 비목 경비 자재는 다음」 · `test_145_5` 합성 expense 줄에 「실제 원천 없음」 주석. + - ② 경비 갈래 — `Sangeun.py:410-418` 비목 경비 재료 줄 → `kind expense`(ref tab expense) · `Labor_Source.py:147-151` 같은 판정 · `Calc_Labor.py:43-46` expense 갈래(단가 = 대비표 적용) · `Calc_Base.py:117-125` 경비목록표에 비목 경비 자재 줄 덧붙임(엑셀 꼴 = 기계 + 회 단가) · `Summary` 그대로 · 집계표 안내. +- 재사용: `LINE_KIND` · `_resource_sheet` 그대로. +- 시험: ① 없음(안내) · ② 새 = 비목 경비 재료 줄 → 산근 · 대가 · 경비목록표 · 경비집계표 한 바퀴 + `test_145_5:57` 을 실제 블록 꼴로. +- 위험: ② 는 경비목록표 꼴(기계 손료표)에 자재 줄이 섞임 · 임도 조합에 그런 줄이 아직 없어 화면 확인 거리 없음. +- 크기: ① 작음 · ② 중간. +- ⬜ 물음 5: — ① 안내 한 줄 + 시험 주석(지금 자료엔 경비 자원 0) ② 비목 경비 자재 줄을 경비 갈래로 — 추천 ①(② 는 임도 조합에 그런 로직이 들어올 때). + +## N11. 일위대가표 금액이 일위대가목록표에 안 올라오는 까닭 +- 현재(목록표 칸이 읽는 것): `UI_Tabs_Labor.ts:39-60` `buildDaegaList` ← `sheets.daega` · :62-139 `buildDaegaBlocks` ← `sheets.daega_blocks` · 둘 다 `UI_Shell.ts:114-134` `computeSheets` 한 벌 → `Calc_Labor.py:126-189`(`.ts:128-177`) `compute_labor` — 목록 :168-183 = 블록 :159-167 의 같은 값(`sum · labor · material · expense`) → 같은 셈 안에서 어긋날 길 없음 · 사본 저장값 · 캐시 · 옛 사본 · 호표 번호 · 브라우저/서버 차 모두 아님(거울 `test_145_2:192`). +- 실측 2a505e36(읽기 스크립트 · 같은 호표 목록 vs 블록 합계): + | 호표 | 꼴 | 목록 합계 | 블록 합계 | 같음 | 아는 줄 금액 합 | 빈 줄 | + |---|---|---|---|---|---|---| + | 대가1 | 조합 기슭막이 메쌓기 1.2m | 329,796 | 329,796 | ○ | 329,797 | - | + | 대가2 | 조합 기슭막이 메쌓기 1.2m | 빈칸 | 빈칸 | ○ | 279,449 | 큰돌 채집(산근 · 수량 없음 — 면적 알약) · 토목용부직포(자재 · 적용 단가 없음 MT003848) | + | 대가3 | 조합 | 555,702 | 555,702 | ○ | 555,704 | - | + | 대가4 | 조합 기슭막이 ㄷ2ㄷ | 빈칸 | 빈칸 | ○ | 0 | 줄 5 모두 수량 없음 | + | 대가5 | 사전조합 | 292,953 | 292,953 | ○ | 292,953 | - | + | 대가6 | 품셈 돌쌓기 메쌓기(인력) | 79,279 | 79,279 | ○ | 79,280 | - | +- 까닭 = 빈칸 규칙 — `Calc_Labor.py:112-115`(`.ts` 같은 자리) 블록 비목 합 = `total(줄 금액)` → 한 줄이라도 빈칸이면 비목 합 · 합계 None(머리글 :17) → 목록표 네 칸 빈칸 · 일위대가표 「합계」 줄(:105-112)도 빈칸 · 그 위 줄들은 금액이 보임(대가2 = 279,449 어치) → 「표 금액이 목록에 안 올라옴」 으로 보임 · 원인 줄 = 면적산출 알약 수량 없음(B06 면적 미입력) · 자재 적용 단가 없음(M01 값 없음 → 대비표 손입력). +- 고칠 자리: `Calc_Labor.py:112-123` · `.ts` 짝 — 비목 합 = 아는 줄 합(ROUNDDOWN 0) + `blank` n(설계내역서 제목 줄 꼴 `Calc_Bill.py:189-219` 그대로) · 목록 :168-183 에 `blank` · `why`(첫 빈 줄 까닭) · `daega_price` :192-204 는 `blank > 0` 이면 None 그대로(내역 단가 · 원가로 안 번짐) · `UI_Tabs_Labor.ts` 목록 「비고」 열 「빈 줄 n — 까닭」 · 블록 합계 줄 note · `daega_owners` 그대로. +- 재사용: `gap` 목록(이미 줄마다 까닭 :89-93) · 공용 표. +- 시험: `test_145_2_b09_labor_calc.py:149` 빈칸 규칙 → 「아는 줄 합 + blank n · daega_price None」 으로 · :110 엑셀 검산 그대로 · :192 거울 경우에 빈 줄 하나 섞음 · `test_145_3:120` 제목 합 그대로. +- 위험: 작음 · `Calc_Labor.py` 204 → ~215. +- 크기: 작음. +- ⬜ 물음 6: 블록 합 — ① 아는 줄 합 + 「빈 줄 n」(내역 · 원가엔 안 넘김) ② 빈칸 그대로 + 비고 까닭만 — 추천 ①. + +## 고칠 파일 목록 + +| 파일 | 요구 | 줄 수(지금 → 예상) | 700 | +|---|---|---|---| +| `B09_Estimation_Rates.py` | N6 | 47 → ~120 | 안전 | +| `B09_Estimation_Calc_Total.py` · `.ts`(짝) | N6 | 161 · 148 → ~230 · ~220 | 안전 | +| `B09_Estimation_UI_Tabs_Total.ts` | N6 | 224 → ~270 | 안전 | +| `B09_Estimation_Store.py` | N6 · N7 · N9 | 111 → ~160 | 안전 | +| `B09_Estimation_Router.py` | N6 · N7 | 128 → ~160 · 견적서 길은 새 `Router_Quotes.py`(~90) | 안전 | +| `B09_Estimation_Bill_Items.py` | N7 | 154 → ~200 | 안전 | +| `B09_Estimation_Calc_Bill.py` · `.ts`(짝) | N7 | 248 · 238 → ~290 · ~280 | 안전 | +| `B09_Estimation_UI_Tabs_Bill.ts` + 새 `UI_Tabs_Bill_Edit.ts` | N7 | 63 → ~110 + ~200 | 안전 | +| `B09_Estimation_Sangeun.py` | N7(손 산근) | 504 → ~540 | 안전(가장 큼) | +| `B09_Estimation_Labor_Source.py` | N7 ⬜2 ② 때만 | 340 → ~370 | 안전 | +| `B09_Estimation_UI_Shell.ts` | N6 · N7 | 315 → ~330 | 안전 | +| `B09_Estimation_Prices.py` | N8 | 255 → ~275 | 안전 | +| `B09_Estimation_Calc_Base.py` · `.ts`(짝) | N8 · N9 | 320 · 289 → ~350 · ~320 | 안전 | +| `B09_Estimation_UI_Tabs_Base.ts` + 새 `UI_Tabs_Base_Quote.ts` | N8 · N9 | 275 → ~330 + ~120 | 안전 | +| `B09_Estimation_Calc_Labor.py` · `.ts`(짝) | N11 (· N10 ②) | 204 · 192 → ~215 · ~205 | 안전 | +| `B09_Estimation_UI_Tabs_Labor.ts` | N11 | 139 → ~150 | 안전 | +| `B09_Estimation_UI_Tabs_Summary.ts` | N10 ① | 88 → ~92 | 안전 | +| `B09_Estimation_Summary.py` | N10 ② 때만 | 160 → ~165 | 안전 | +| 시험 `test_145_4` · `test_145_3` · `test_144_b09_base_calc` · `test_145_2` · `test_145_5` · `test_144_b09_skeleton` + 새 시험(N6 구간 · N7 손 줄 · N9 upload) | 전부 | - | - | + +- 안 고침: `Linked.py` · `Sangeun_Text.py` · `UI_Tabs_Sangeun*.ts` · `UI_Tabs.ts`(탭 차례) · 공용 표 `ui_template_data_table.ts`(contextmenu 는 표 밖에서 붙임) · `M02_*` · `B08_*` · `resources/master_data`. +- 겹침: `Calc_Base` 짝(N8 · N9) · `Store.py`(N6 · N7 · N9) · `Calc_Labor` 짝(N11 · N10 ②) → 한 창이 차례로(N11 → N8 → N9 → N6 → N7 · N10 은 안내만) 추천.