- 새 Hopyo_Check(확인 창 · 본 칸 · 모달) — 상태 색 · 체크 제안 · 우리 로직 여럿 · 배 · 몫 · 옵션 · 품 비교 · 뺌 · 원문 보기 · 캐시 m02-hopyo-check · 셈 중 3 초 다시 읽음 · 최신 응답만 - 새 Hopyo_Choose(고르기 창 · 후보 판정 · 여럿 고름 · 몫 · 찾기 글 미리 넣음) · 새 Hopyo_Ledger(장부 화면 · 고친 것 캐시 · [저장] 때만 PUT) - 고침 View(호표 하나 = 확인 창) · Sheet(펼침 뒤 한 번 · 하위 호표 먼저) · Pick(확인된 것 바로 참조 · 아니면 확인 창) · Api(3-3 꼴 · 만들기 몸 · 장부 길) · Side([별칭 장부]) · css · Labor_Pick(query) - 없앰 saveHopyoMemory · [확정] · [같음 모두 확정] · [근거 맞음 모두 확정] · 바로 만들기 - 시험 test_m02_hopyo_screen.py 새로 · helper_m02_hopyo_check.cjs 새 · pick · seam 도우미 손질 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
123 lines
5.4 KiB
JavaScript
123 lines
5.4 KiB
JavaScript
/* M02 일위대가 실무자료(324-4 · 338-3) 헬퍼 — `M02_MasterTemplete_Hopyo_Pick.ts`(고르기 창 「실무 호표」 덧줄) ·
|
|
* `M02_MasterTemplete_Hopyo_Choose.ts` 글 도우미 · `M02_MasterTemplete_Hopyo_Sheet.ts` 엑셀 보기 창 도우미(329 · 행 → 호표)를
|
|
* 트랜스파일해 Node 로 돌림 · fetch 대역이 부른 길 · 몸을 모음 ·
|
|
* stdin = {rows, built} · stdout = {calls, kinds, rows, picked, project, view, sheet} JSON. */
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const STUBS = { "@config/config_frontend": { API_BASE_URL: "/api" } };
|
|
// 고르기 창 · 자재 창 · 입력 창 · 원문 창은 DOM · 모듈 메타를 씀 — 대역(글 도우미만 시험)
|
|
const STUB_FILES = [
|
|
"M02_MasterTemplete_Labor_Pick",
|
|
"M02_Material_Pick",
|
|
"M02_MasterTemplete_Labor_Api",
|
|
"M02_MasterTemplete_Labor_Input",
|
|
"M01_MasterData_UI_LogicLab_Source",
|
|
];
|
|
const stub = new Proxy({}, { get: (_t, k) => (k === "currentLanguageIndex" ? () => 0 : () => {}) });
|
|
const cache = new Map();
|
|
function loadTs(file) {
|
|
const full = path.resolve(file);
|
|
if (cache.has(full)) return cache.get(full);
|
|
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(full, box.exports);
|
|
const localRequire = (request) => {
|
|
if (STUBS[request]) return STUBS[request];
|
|
if (STUB_FILES.some((name) => request.endsWith(name))) return stub;
|
|
if (request.startsWith(".") && !request.endsWith(".css"))
|
|
return loadTs(`${path.resolve(path.dirname(full), request)}.ts`);
|
|
return stub;
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
|
return box.exports;
|
|
}
|
|
|
|
(async () => {
|
|
const input = JSON.parse(fs.readFileSync(0, "utf8"));
|
|
const calls = [];
|
|
global.fetch = async (url, init = {}) => {
|
|
calls.push({
|
|
url,
|
|
method: init.method ?? "GET",
|
|
body: init.body ? JSON.parse(init.body) : null,
|
|
});
|
|
const body = url.includes("/hopyo-picks") ? { 줄: input.rows } : input.built;
|
|
return { status: 200, ok: true, json: async () => body };
|
|
};
|
|
const M02 = path.join(ROOT, "M02_MasterTemplete");
|
|
const pick = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Pick.ts"));
|
|
const picked = [];
|
|
const lib = {
|
|
layer: "company",
|
|
owner: "7",
|
|
pick: (ref, name, alias) => picked.push({ ref, name, alias }),
|
|
};
|
|
const wrapped = pick.withHopyo(lib);
|
|
const rows = (await wrapped.more()).map(({ onPick: _, ...r }) => r);
|
|
await pick.pickHopyo(input.rows[0], lib);
|
|
const project = pick.withHopyo({ ...lib, layer: "project" });
|
|
const view = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Choose.ts"));
|
|
const sheet = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Sheet.ts"));
|
|
const api = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Api.ts"));
|
|
await api.readHopyoGrid({ layer: "company", owner: "7" }, "HP-000001");
|
|
const spans = [
|
|
{ 번: 3, 이름: "임도표지석", 행: [20, 24] },
|
|
{ 번: 4, 이름: "배수관", 행: [25, 30] },
|
|
];
|
|
const out = {
|
|
calls,
|
|
kinds: wrapped.kindFilter.map((k) => k.value),
|
|
rows,
|
|
picked,
|
|
project: project.more === undefined && project.kindFilter === undefined,
|
|
view: {
|
|
target: [
|
|
view.targetText({ 로직: "GF000101", 이름: "구조물터파기", 단위: "㎥" }),
|
|
view.targetText({ 자재: "MT1", 이름: "레미콘", 규격: "25-21-120", 단위: "㎥" }),
|
|
view.targetText({ 호표: 46, 단위: "㎡" }),
|
|
],
|
|
inputs: view.inputsText({ 횟수: "4회사용시", 지역: "서울" }, ["보정작업"]),
|
|
},
|
|
basis: (() => {
|
|
const hit = {
|
|
조항: ["건설 공통 3-2-1"],
|
|
직종: ["특별인부"],
|
|
단위: true,
|
|
점수: 1.65,
|
|
까닭: "조항 같음 · 직종 특별인부 · 단위 맞음",
|
|
};
|
|
const half = { ...hit, 직종: [] };
|
|
const trade = { 출처: [["건설품셈", "3-2-1"]], 직종: ["특별인부", "보통인부"], 행: [1, 1] };
|
|
const plain = { ...trade, 직종: ["보통인부"] };
|
|
return {
|
|
ok: [hit, half, { ...hit, 단위: false }, { ...hit, 까닭: "앞 마디 같음" }, undefined].map(
|
|
(b) => view.basisOk(b, trade),
|
|
),
|
|
// 엑셀 직종이 보통인부뿐 · 없음(기계) = 직종 안 봄
|
|
plain: [view.basisOk(half, plain), view.basisOk(half, { ...trade, 직종: [] })],
|
|
tag: [hit, half, undefined].map(view.basisTag),
|
|
source: [
|
|
view.sourceText({ 출처: [["건설표준품셈", "3-2-1"]], 직종: ["특별인부"], 행: [93, 101] }),
|
|
view.sourceText({ 출처: [], 직종: [], 행: [7, 7] }),
|
|
view.sourceText(undefined),
|
|
],
|
|
};
|
|
})(),
|
|
sheet: {
|
|
at: [19, 20, 22, 24, 25, 30, 31].map((row) => sheet.hopyoAtRow(spans, row)),
|
|
span: sheet.spanText([20, 24], sheet.lastColumn({ 칸: { A1: {}, N24: {} }, 열: { O: {} } })),
|
|
last: [sheet.lastColumn({ 칸: { Z9: {}, AA1: {} } }), sheet.lastColumn({ 칸: {} })],
|
|
rows: [sheet.rowsText(4345), sheet.rowsText([93, 101])],
|
|
},
|
|
};
|
|
process.stdout.write(JSON.stringify(out));
|
|
})().catch((error) => {
|
|
process.stderr.write(String(error?.stack ?? error));
|
|
process.exit(1);
|
|
});
|