diff --git a/tools/est-test/PLAN.md b/tools/est-test/PLAN.md index 9948c58f1..72194e9a8 100644 --- a/tools/est-test/PLAN.md +++ b/tools/est-test/PLAN.md @@ -489,6 +489,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] 검색 결과 근거자료보기(원본 TfrmFoundDetail btnClose 0xefa7e8) — 통합 검색 결과의 일위·단산·기계 줄 「근거」: 그 작업의 호표 세부 줄(단산은 산출근거 글)과 총액·노무·재료·경비, 「적용」은 그 결과를 고르고 검색 창으로(가져오기는 검색 창에서). 고른 결과는 창을 오가도 유지. + - 검증완료: 바인딩·통합 검색 시험 통과. ORCA 브라우저에서 「거푸집」 일위 → 「[합판거푸집]의 근거자료보기」 총액 53,029·노무 38,289·재료 14,740·세부 6줄, 적용 → 그 결과 체크. - [x] ES 정보(원본 mnuESInfo → TfrmESInfo 0x10b838c) — 기준시점·비교시점·최종기성일·선급금지급일(기본 오늘)·선급금지급액을 `project.esInfo` 에 기록(원본 [EscInfo] SDATE·CDATE·ACDATE·PreDATE·PreCost). 원본도 ES 제출 파일 작성에만 씀 — 웹 물가변동 계산과 잇지 않음, ESTX 에는 남지 않음. - 검증완료: 바인딩 시험 통과. ORCA 브라우저에서 기본 오늘 · 기준시점 2025-01-15·선급금 1,000,000 저장 → 다시 열면 그대로, 지워 복구. - [x] 설계참고철(Main Data)과 단가 범위 검색(원본 TfrmMainTableList 「MAIN DATA(설계참고철) 추가 및 삭제」 · TfrmFolderSerch 「Main Data에서 검색」·범위 검색 0xefefb0) — 통합 검색 「설계참고철 관리」에서 저장된 작업 중 최대 10개 지정(양식 보관함 종류 options), 검색위치 「설계참고철」이면 그 작업만, 검색어 「a~b」·숫자 하나는 단가 범위·같음. 원본의 검색중지는 서버 검색이 바로 끝나 두지 않음. diff --git a/tools/est-test/native-business-actions.js b/tools/est-test/native-business-actions.js index f2a9610ed..74f69f46f 100644 --- a/tools/est-test/native-business-actions.js +++ b/tools/est-test/native-business-actions.js @@ -612,7 +612,7 @@ const EstBusinessActions = (() => { (typeof EstCleanup !== "undefined" && EstCleanup.handle(name, state)) || (typeof EstNameReg !== "undefined" && EstNameReg.handle(name, state)) || (typeof EstTidy !== "undefined" && EstTidy.handle(name, state)) || - (typeof EstMultiSearch !== "undefined" && EstMultiSearch.handle(name, state)) || + (typeof EstMultiSearch !== "undefined" && EstMultiSearch.handle(name, state, node)) || (typeof EstDocs !== "undefined" && EstDocs.handle(name, state, node)) || (typeof EstWongaTools !== "undefined" && EstWongaTools.handle(name, state)) || (typeof EstEstimatePrint !== "undefined" && EstEstimatePrint.handle(name, state)) || diff --git a/tools/est-test/native-multi-search.js b/tools/est-test/native-multi-search.js index 2ba87dc96..c98b7416b 100644 --- a/tools/est-test/native-multi-search.js +++ b/tools/est-test/native-multi-search.js @@ -18,7 +18,7 @@ const EstMultiSearch = (() => { const rows = saved.hits .map( (h, i) => - `${esc(h.project)}${esc(h.label)}${esc(h.Code)}${esc(h.Name)}${esc(h.Size)}${esc(h.Unite)}${EstApp.number(h.price)}`, + `${[103, 104, 105].includes(h.kind) ? `` : ""}${esc(h.project)}${esc(h.label)}${esc(h.Code)}${esc(h.Name)}${esc(h.Size)}${esc(h.Unite)}${EstApp.number(h.price)}`, ) .join(""); EstApp.showDialog( @@ -27,7 +27,11 @@ const EstMultiSearch = (() => { ); } - async function run(name, state) { + async function run(name, state, node) { + if (name === "multi-search-detail") return detail(state, Number(node.dataset.i)); + if (name === "multi-search-pick") + (state.multiSearch.picked ||= new Set()).add(Number(node.dataset.i)); + if (name === "multi-search-pick" || name === "multi-search-back") return form(state); if (name === "main-list") return mainForm(state); if (name === "main-list-save") { await mainSave(); @@ -50,6 +54,7 @@ const EstMultiSearch = (() => { } if (state.project.id) params.set("exclude", state.project.id); Object.assign(saved, await EstApp.api(`/api/search?${params}`)); + saved.picked = new Set(); form(state); } else if (name === "multi-search-take") { const picked = [...document.querySelectorAll('#dialog-content [name="ms-hit"]:checked')].map( @@ -105,16 +110,50 @@ const EstMultiSearch = (() => { body: JSON.stringify({ kind: "options", name: MAIN, data: { ids } }), }); } + // 근거자료보기(TfrmFoundDetail): 찾은 일위·단산·기계 호표의 세부 줄과 총액·노무·재료·경비, 「적용」 = 그 결과를 고름 + const BODY = { 103: "HeadMainDat", 104: "CostMainDat", 105: "MachMainDat" }; + async function detail(state, i) { + remember(state); + const hit = state.multiSearch.hits[i], + project = await EstApp.api(`/api/projects/${hit.id}`), + { esc, number } = EstApp, + rows = project.tables[BODY[hit.kind]] || [], + group = EstNative.groups(rows).get(hit.Code); + if (!group) throw Error("근거 자료를 찾지 못했습니다."); + const head = group.rows[0], + body = group.rows + .slice(1) + .map((r) => + hit.kind === 104 + ? `${esc(EstText.clean(r.LineData || ""))}` + : `${esc(r.Code)}${esc(r.Name)}${esc(r.Size)}${esc(r.Unite)}${number(r.GN)}`, + ) + .join(""); + EstApp.showDialog( + `[${hit.Name}]의 근거자료보기`, + `

총 액 : ${number(head.TC)} · 노무비 : ${number(head.NC)} · 재료비 : ${number(head.GC)} · 경 비 : ${number(head.JC)}

${body}
`, + ); + } + function remember(state) { + const boxes = document.querySelectorAll('#dialog-content [name="ms-hit"]'); + if (boxes.length) + state.multiSearch.picked = new Set( + [...boxes].filter((n) => n.checked).map((n) => Number(n.value)), + ); + } const names = new Set([ "multi-search", "multi-search-run", "multi-search-take", "main-list", "main-list-save", + "multi-search-detail", + "multi-search-pick", + "multi-search-back", ]); - function handle(name, state) { + function handle(name, state, node) { if (!names.has(name)) return false; - run(name, state).catch((error) => { + run(name, state, node).catch((error) => { state.notice = error.message; EstApp.render(); });