feat(est-test): 블럭 파일로 저장하기·블럭 파일에서 붙여넣기
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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] 블럭 파일로 저장하기·블럭 파일에서 붙여넣기(원본 mnuBlockSaveToFile·mnuLoadFromFile) — 복사·잘라낸 행 묶음을 `.estblock.json`(종류 est-web-block-1, 표 이름·행)으로 내려받고, 파일을 읽어 같은 종류 화면에 붙여넣음(다른 공사로 옮기기).
|
||||
- 검증완료: 바인딩 시험 통과. ORCA 브라우저에서 자재 2행 복사 → 파일 저장(2,559 바이트) → 같은 내용 읽어 붙여넣기 30→32행, 잘못된 파일 거부, 샘플 복구.
|
||||
- [x] 인쇄 용지 A0·A1·B4 와 인쇄 기본양식(원본 TFRMSCHEDULE mnuA0~B4 · TFRMESTPREVIEW2 mnuFormatSave·mnuFromatOpen) — 용지 A4·A3·B4·A1·A0(A0·A1 은 mm 크기, 가로면 바꿔 씀), 인쇄 창 「기본양식저장」(용지·여백·글자·줄 수 등, 서식 고르기·본문 글 제외 — 양식 보관함 종류 print) · 「기본양식열기」.
|
||||
- 검증완료: 바인딩·양식 시험 3개 통과. ORCA 브라우저에서 A1 가로 → @page 841mm 594mm, 기본양식 저장 뒤 A4 로 바꾸고 열기 → A1 복원, 양식·설정 지워 복구.
|
||||
- [x] 원가계산서 내용 삭제·기본양식으로 저장(원본 TFRMWONGABASE popupContentDel A7 · popupSaveAsMain) — 원가계산서(W) 「선택 줄 내용 삭제」: 연결·금액·비율·요율·산출근거·자리 비움(이름·기호 유지, 재계산 없음). 양식 목록 「기본양식으로 저장」: 이름 「기본양식」 — 새 내역서를 만들 때 원가계산서로 씀.
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
<script defer src="native-doc-editor.js"></script>
|
||||
<script defer src="native-docs.js"></script>
|
||||
<script defer src="native-doc-forms.js"></script>
|
||||
<script defer src="native-block-file.js"></script>
|
||||
<script defer src="native-wonga-tools.js"></script>
|
||||
<script defer src="native-estimate-print.js"></script>
|
||||
<script defer src="native-xml-check.js"></script>
|
||||
@@ -131,7 +132,9 @@
|
||||
><button data-action="block-end">블럭 끝</button
|
||||
><button data-action="block-clear">블럭 해제</button
|
||||
><button data-action="select-all-rows">전체 선택</button
|
||||
><button data-action="block-del">블럭 삭제</button>
|
||||
><button data-action="block-del">블럭 삭제</button
|
||||
><button data-action="block-save-file">블럭 파일로 저장하기</button
|
||||
><button data-action="block-load-file">블럭 파일에서 붙여넣기</button>
|
||||
<hr />
|
||||
<button data-action="find">찾기·다음찾기(Ctrl+F)</button>
|
||||
<button data-action="multi-search">통합 검색(저장된 다른 작업)</button>
|
||||
|
||||
@@ -685,5 +685,7 @@ const EstActions = (() => {
|
||||
EstAttachments.install();
|
||||
EstStandard.install();
|
||||
}
|
||||
return { install, form, undo };
|
||||
const clip = () => ({ table: clipboardTable, rows: clipboard });
|
||||
const setClip = (table, rows) => ((clipboardTable = table), (clipboard = structuredClone(rows)));
|
||||
return { install, form, undo, clip, setClip };
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// 원본 「블럭 파일로 저장하기」(mnuBlockSaveToFile)·「블럭 파일에서 붙여넣기」(mnuLoadFromFile) — 복사·잘라낸 행 묶음을
|
||||
// 파일(.estblock.json)로 내려받고, 파일을 읽어 복사판에 올린 뒤 현재 화면에 붙여넣는다(같은 종류 자료만).
|
||||
const EstBlockFile = (() => {
|
||||
const KIND = "est-web-block-1";
|
||||
function save() {
|
||||
const { table, rows } = EstActions.clip();
|
||||
if (!rows.length) throw Error("먼저 행을 복사하거나 잘라내세요.");
|
||||
EstApp.download(
|
||||
`${EstApp.state.project.name || "블럭"}.${table}.estblock.json`,
|
||||
JSON.stringify({ kind: KIND, table, rows }, null, 1),
|
||||
);
|
||||
}
|
||||
function parse(text) {
|
||||
const data = JSON.parse(text);
|
||||
if (data?.kind !== KIND || !Array.isArray(data.rows) || !data.rows.length || !data.table)
|
||||
throw Error("블럭 파일이 아닙니다.");
|
||||
if (data.rows.some((r) => !r || typeof r !== "object" || Array.isArray(r)))
|
||||
throw Error("블럭 파일 행이 올바르지 않습니다.");
|
||||
return data;
|
||||
}
|
||||
function load(state) {
|
||||
const picker = document.createElement("input");
|
||||
picker.type = "file";
|
||||
picker.accept = ".json";
|
||||
picker.addEventListener("change", async () => {
|
||||
try {
|
||||
const file = picker.files[0];
|
||||
if (!file) return;
|
||||
const data = parse(await file.text());
|
||||
if (data.table !== state.view)
|
||||
throw Error("블럭 파일과 같은 종류의 자료 화면에서 붙여넣으세요.");
|
||||
EstActions.setClip(data.table, data.rows);
|
||||
document.querySelector('[data-action="paste-row"]')?.click();
|
||||
} catch (error) {
|
||||
state.notice = error.message;
|
||||
EstApp.render();
|
||||
}
|
||||
});
|
||||
picker.click();
|
||||
}
|
||||
function handle(name, state) {
|
||||
if (name === "block-save-file") save();
|
||||
else if (name === "block-load-file") load(state);
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
return { parse, handle };
|
||||
})();
|
||||
@@ -628,7 +628,8 @@ const EstBusinessActions = (() => {
|
||||
(typeof EstCodeChangeView !== "undefined" && EstCodeChangeView.handle(name, state, node)) ||
|
||||
(typeof EstSources !== "undefined" && EstSources.handle(name, state)) ||
|
||||
(typeof EstDocEditor !== "undefined" && EstDocEditor.handle(name, state, node)) ||
|
||||
(typeof EstDocForms !== "undefined" && EstDocForms.handle(name, state, node))
|
||||
(typeof EstDocForms !== "undefined" && EstDocForms.handle(name, state, node)) ||
|
||||
(typeof EstBlockFile !== "undefined" && EstBlockFile.handle(name, state))
|
||||
) {
|
||||
EstApp.render();
|
||||
} else if (name === "load-contract" || name === "load-bid") {
|
||||
|
||||
@@ -78,6 +78,7 @@ const allowed = new Set([
|
||||
"native-doc-editor.js",
|
||||
"native-docs.js",
|
||||
"native-doc-forms.js",
|
||||
"native-block-file.js",
|
||||
"native-wonga-tools.js",
|
||||
"native-estimate-print.js",
|
||||
"native-xml-check.js",
|
||||
|
||||
Reference in New Issue
Block a user