From b3f5cc2b7b5b75b1050d63c1a3b255c517e635c6 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 12 Nov 2026 13:12:34 +0900 Subject: [PATCH] =?UTF-8?q?feat(est-test):=20=EC=82=B0=EC=B6=9C=20?= =?UTF-8?q?=EC=A4=84=20=EC=9E=98=EB=9D=BC=EB=82=B4=EA=B8=B0=C2=B7=EB=B3=B5?= =?UTF-8?q?=EC=82=AC=C2=B7=EB=B6=99=EC=97=AC=EB=84=A3=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- tools/est-test/PLAN.md | 2 ++ tools/est-test/native-quantity-sheets.js | 32 ++++++++++++++++++++++-- tools/est-test/native-quantity.cjs | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/tools/est-test/PLAN.md b/tools/est-test/PLAN.md index dae997c8d..d8e7085c5 100644 --- a/tools/est-test/PLAN.md +++ b/tools/est-test/PLAN.md @@ -487,6 +487,8 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD - 남음: 구성비·요율 전환(CalcBase), 약어 표시(SName), 제비율 기준 문서 보기(원본 한글 파일). - [x] 수량산출서 검색·전체보기(원본 TFRMMULLANG btnSerch·btnAllDisplay — 빈칸·|·괄호 무시 포함 검색) — 고르기 줄을 `native-quantity-sheets.js` 로 옮겨 700줄 제한 유지. - 검증완료: `test_est_quantity_sheets.py` 검색 시험 포함 수량 시험 22개 통과. ORCA 브라우저에서 「집수」 검색 → 항목에 집수정이 있는 「배수」만·선택 이동, 전체보기 → 3개 복귀, 샘플 복구. + - [x] 산출 줄 잘라내기·복사·붙여넣기(원본 TFRMMULWORD popCut·popCopy·popPaste) — 산출 줄마다 복사·잘라내기·아래 붙여넣기. 붙일 때 수량 지정 표지를 떼고 글만(같은 항목이 두 번 잡히지 않게), 수량 지정된 줄은 잘라내기 거부. + - 검증완료: 산출서·수량 흐름·바인딩 시험 22개 통과. ORCA 브라우저에서 표지 있는 줄 복사 → 아래 붙여넣기(표지 없음), 표지 줄 잘라내기 거부, 샘플 복구. - [x] 수량산출서 엑셀형식 전환(원본 TFRMMULLANG popSetMode — DataKind 로 편집기 교체) — 산출서 화면 「엑셀형식으로」: 엑셀 시트가 없으면 빈 시트를 만들어 엑셀형으로, 「일반형식으로」는 엑셀 내용을 보관한 채 끄고 셀 연결 수량을 쓰지 않음. 바꾼 산출서는 ESTX 저장 거부(JSON). - 검증완료: 엑셀·산출서·바인딩 시험 11개 통과. ORCA 브라우저에서 새 산출서 → 엑셀형식(격자 160칸) → A1 =2*3 → 6, 일반형식으로 → 격자 숨김·보관, 샘플 복구. - 제외(원본에서도 쓰지 않거나 외부 프로그램): 제비율 적용기준 보기(설치 폴더 한글 문서를 한글 프로그램으로 열 뿐, 그림 3장), 엑셀물량 열기(Microsoft Excel 을 COM 으로 열 뿐 EST 로 읽지 않음), 플러스 일위대가로 변환(메뉴에 걸리지 않아 원본에서 실행 불가). diff --git a/tools/est-test/native-quantity-sheets.js b/tools/est-test/native-quantity-sheets.js index c2734d28a..9c0f64371 100644 --- a/tools/est-test/native-quantity-sheets.js +++ b/tools/est-test/native-quantity-sheets.js @@ -188,10 +188,38 @@ const EstQuantitySheets = (() => { else free(sheet, index, start, editor.value); }, false); } else if (name === "excel-mode") excelMode(state); - else return false; + else if (["quantity-row-copy", "quantity-row-cut", "quantity-row-paste"].includes(name)) { + // 산출 줄 잘라내기·복사·붙여넣기(TFRMMULWORD popCut·popCopy·popPaste) — 붙일 때 수량 지정 표지는 떼고 글만 + const sheet = state.project.quantitySheets?.find((s) => s.Code === state.quantitySheet), + index = Number(node.dataset.index); + if (!sheet?.rows?.[index]) throw Error("산출 줄을 고르세요."); + if (name === "quantity-row-paste") { + if (!state.quantityClip?.length) throw Error("복사한 산출 줄이 없습니다."); + EstApp.change( + () => sheet.rows.splice(index + 1, 0, ...rowsToPaste(state.quantityClip)), + false, + ); + } else { + if (name === "quantity-row-cut" && sheet.rows[index].markers?.length) + throw Error("수량으로 지정된 줄은 먼저 지정 해제하세요."); + state.quantityClip = [structuredClone(sheet.rows[index])]; + if (name === "quantity-row-cut") EstApp.change(() => sheet.rows.splice(index, 1), false); + else state.notice = "산출 줄을 복사했습니다."; + } + } else return false; return true; } + function rowsToPaste(rows) { + return rows.map((row) => { + const copy = structuredClone(row); + copy.LineData = EstText.encode(EstText.display(copy.LineData).split(RESULT).join("")); + delete copy.markers; + delete copy.PkID; + return copy; + }); + } + // 엑셀형 수량산출서(원본 TFRMMULEXCEL) — 편집 화면은 native-excel-view.js. // 엑셀형식(popSetMode): 원본은 DataKind 를 바꿔 편집기를 갈아끼움 — 웹은 빈 엑셀 시트를 만들거나 끄고 켬(내용은 보관). function excelView(sheet) { @@ -222,5 +250,5 @@ const EstQuantitySheets = (() => { }, false); } - return { copy, move, mark, free, excelView, matches, selector, handle }; + return { copy, move, mark, free, rowsToPaste, excelView, matches, selector, handle }; })(); diff --git a/tools/est-test/native-quantity.cjs b/tools/est-test/native-quantity.cjs index 8fa90437b..f0ffd7ccf 100644 --- a/tools/est-test/native-quantity.cjs +++ b/tools/est-test/native-quantity.cjs @@ -325,7 +325,7 @@ const EstQuantity = (() => { { esc, number, byId } = EstApp; byId("work-content").innerHTML = selector(state) + - `
${output.items.map((item, index) => ``).join("")}
산출코드품명규격단위저장 수량재계산 수량연결 내역코드끝수 처리작업
${esc(item.Code)}${number(sheet.items[index]?.GN ?? 0)}${number(item.GN)}${targetSelect(state.project, item, "sheet", index)}${formatSelect(sheet.items[index], index)}
${typeof EstQuantitySheets !== "undefined" ? EstQuantitySheets.excelView(sheet) : ""}

${esc(output.errors.join(" / "))} 산출 행의 결과 표지로 수량 항목을 연결합니다. 신규 산출서와 지원되지 않는 원본 구조 변경은 JSON으로 저장합니다.

${sheet.rows.map((row, index) => ``).join("")}
줄산출근거 편집작업
${index + 1}
`; + `
${output.items.map((item, index) => ``).join("")}
산출코드품명규격단위저장 수량재계산 수량연결 내역코드끝수 처리작업
${esc(item.Code)}${number(sheet.items[index]?.GN ?? 0)}${number(item.GN)}${targetSelect(state.project, item, "sheet", index)}${formatSelect(sheet.items[index], index)}
${typeof EstQuantitySheets !== "undefined" ? EstQuantitySheets.excelView(sheet) : ""}

${esc(output.errors.join(" / "))} 산출 행의 결과 표지로 수량 항목을 연결합니다. 신규 산출서와 지원되지 않는 원본 구조 변경은 JSON으로 저장합니다.

${sheet.rows.map((row, index) => ``).join("")}
줄산출근거 편집작업
${index + 1}
`; } // 원본 수량목록 자리수 메뉴(mnuAuto·mnuTrunc·mnuUp·mnuRound): 결과 코드 뒤 방식(1 반올림·2 절사·3 올림)+자리수. function resultFormat(code) {