- 새 Hopyo_SheetSk: 탭(역할) 따라 오른쪽 판 바꿈 · 일위대가표 = 호표 목록 그대로 · 단가산출표 · 상세 = 마법사 단가산출 칸 좁은 꼴 한 벌(처음 올 때 지음 · 다른 층 · 권한 없음 = 보기만) · 시트 칸 → 목록 강조 · 목록 줄 → 지금 탭 블록 자리 - WizardSk: 좁은 꼴 옵션 · 부름 칸(일위대가 n 곳 · 일위대가 밖) · 거르기(전체 · 안 · 밖 · 고를 줄 있음) · 같은 캐시 두 벌 맞춤 알림 · 옮김 뒤 HOPYO_BUILT(열린 엑셀 보기 칠 다시) - SkPick: 줄 0 블록 = 「줄 없음」 확인 막음 · 거르기 · 끝내기 글 재료에 일위대가 밖 수 - SheetNav: role · blockAt · spotOf 내보냄 · SheetMap: 판정 없음 글 → 「일위대가 밖」 - Wizard [끝내기]: 막지 않음 · 물음창에 안 옮긴 단가산출 n(일위대가 밖 m) - 시험: 새 test_627_sheet_sk(판 바꿈 · 목록 지음 · 줄 0 막음 · 캐시 공유) · test_778_5 끝내기 재료 꼴에 밖 칸 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
169 lines
6.9 KiB
JavaScript
169 lines
6.9 KiB
JavaScript
/* 778-5 D-5 마법사 단가산출 줄 고름 헬퍼 — `logic/Hopyo_SkPick`(순수) · `Hopyo_SkApi`(몸) 를 트랜스파일해 Node 로 돌림 ·
|
|
* fetch 대역(부른 길 · 몸 모음) · stdin = {blocks} · stdout = JSON.
|
|
* 780-2 — stdin `{sheetSk: {...}}` = 엑셀 보기 오른쪽 판 바꾸기(`Hopyo_SheetSk`) · 단가산출 칸 · 시트 막대 · 판은 가짜. */
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const made = []; // 가짜 단가산출 칸 — 지은 인자 · 강조
|
|
const fakeEl = () => ({
|
|
hidden: false,
|
|
attrs: {},
|
|
kids: [],
|
|
setAttribute(k, v) {
|
|
this.attrs[k] = v;
|
|
},
|
|
append(x) {
|
|
this.kids.push(x);
|
|
},
|
|
});
|
|
const STUBS = {
|
|
"@config/config_frontend": { API_BASE_URL: "/api", ROUTES: {} },
|
|
"@ui/ui_template_elements": {
|
|
el: (tag, o = {}) => ({ ...fakeEl(), tag, className: o.className }),
|
|
},
|
|
"./M02_MasterTemplete_Hopyo_WizardSk": {
|
|
sangeunStep: (scope, key, file, onChange, o) => {
|
|
const step = {
|
|
args: { scope, key, file, o: { ...o, onRow: !!o.onRow } },
|
|
marks: [],
|
|
onRow: o.onRow,
|
|
};
|
|
made.push(step);
|
|
return { root: fakeEl(), mark: (n) => step.marks.push(n) };
|
|
},
|
|
},
|
|
};
|
|
const stub = new Proxy({}, { get: () => () => {} });
|
|
const { loadTs } = makeLoader({
|
|
root: ROOT,
|
|
requireFor: (full) => (request) => {
|
|
if (STUBS[request]) return STUBS[request];
|
|
if (request.startsWith(".") && !request.endsWith(".css"))
|
|
return loadTs(`${path.resolve(path.dirname(full), request)}.ts`);
|
|
return stub;
|
|
},
|
|
});
|
|
global.sessionStorage = { getItem: () => null, setItem: () => {}, removeItem: () => {} };
|
|
|
|
(async () => {
|
|
const input = JSON.parse(fs.readFileSync(0, "utf8"));
|
|
if (input.sheetSk) return process.stdout.write(JSON.stringify(sheetSk(input.sheetSk)));
|
|
const { blocks } = input;
|
|
const calls = [];
|
|
global.fetch = async (url, init = {}) => {
|
|
calls.push({
|
|
url,
|
|
method: init.method ?? "GET",
|
|
body: init.body ? JSON.parse(init.body) : null,
|
|
});
|
|
return { status: 200, ok: true, json: async () => ({ 판정: blocks, 만듦: [], 못만듦: [] }) };
|
|
};
|
|
const M02 = path.join(ROOT, "M02_MasterTemplete");
|
|
const sk = loadTs(path.join(M02, "logic", "M02_MasterTemplete_Hopyo_SkPick.ts"));
|
|
const api = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_SkApi.ts"));
|
|
const [a, b, c] = blocks; // a = 고를 줄 2 · b = 옮길 수 있음 · c = 못 이음(하위)
|
|
const out = {};
|
|
let d = sk.emptyDraft();
|
|
out.start = blocks.map((x) => ({
|
|
번: x.번,
|
|
판정: sk.verdictOf(x, {}),
|
|
확인켜짐: sk.canConfirm(x, {}),
|
|
}));
|
|
out.emptyBody = sk.sureBody(d, blocks); // 아무것도 안 눌렀으면 몸 비움(자동 확인 없음)
|
|
d = sk.setSure(d, a, true); // 고를 줄 남은 블록 = 안 켜짐
|
|
out.sureBlocked = d.확인;
|
|
d = sk.setPick(d, a.번, 1, { 노임: "LB000099" }); // 작업반장 → 다른 노임
|
|
out.half = {
|
|
판정: sk.verdictOf(a, sk.picksOf(d, a.번)),
|
|
켜짐: sk.canConfirm(a, sk.picksOf(d, a.번)),
|
|
};
|
|
d = sk.setPick(d, a.번, 2, { 자재: "MT000123" });
|
|
d = sk.setPick(d, a.번, 3, { 뺌: "우리에 없음" });
|
|
out.view = a.줄.map((l) => sk.lineView(l, sk.picksOf(d, a.번)[String(l.차례)]));
|
|
out.full = {
|
|
판정: sk.verdictOf(a, sk.picksOf(d, a.번)),
|
|
켜짐: sk.canConfirm(a, sk.picksOf(d, a.번)),
|
|
};
|
|
d = sk.setSure(d, a, true);
|
|
d = sk.setSure(d, b, true);
|
|
d = sk.setSure(d, c, true); // 못 이음 남음 = 안 켜짐
|
|
out.sure = d.확인;
|
|
out.body = sk.sureBody(d, blocks);
|
|
out.wait = sk.waiting(d, blocks);
|
|
// 고름 지우면 확인에서 빠짐(tidy)
|
|
out.tidy = sk.tidy(sk.setPick(d, a.번, 2, null), blocks).확인;
|
|
// 캐시 글 왕복 · 틀린 글
|
|
out.round = sk.readDraft(JSON.stringify(d));
|
|
out.bad = sk.readDraft("{엉터리");
|
|
out.cand = {
|
|
L: sk.candPick("L", { 키: "LB000001", 이름: "작업반장" }),
|
|
X: sk.candPick("X", { 키: "EQ000019", 이름: "굴착기" }),
|
|
M: sk.candPick("M", { 자재: "MT000001", 이름: "시멘트" }),
|
|
R: sk.candPick("R", { 기준: "노무비", 비목: "경비" }),
|
|
Mbad: sk.candPick("M", { 키: "LB000001" }),
|
|
text: sk.candText({ 이름: "합판", 규격: "12mm", 단위: "장" }),
|
|
};
|
|
await api.judgeSangeun({ layer: "personal", owner: null }, "HP-000001");
|
|
await api.judgeSangeun({ layer: "personal", owner: null }, "HP-000001", out.body);
|
|
out.calls = calls;
|
|
// 780-2 일위대가 안 · 밖 · 줄 0 블록 — 거르기 · 판정 · 확인 막음 · 끝내기 글 재료
|
|
const more = [
|
|
{ ...a, 부름: [3, 7] },
|
|
{ ...b, 부름: [] },
|
|
{ ...b, 번: 9, 부름: [], 줄: [] },
|
|
{ ...c, 부름: [12], 만든: "SK-000001" },
|
|
];
|
|
const e = more[2];
|
|
let d2 = sk.setSure(sk.emptyDraft(), e, true);
|
|
out.empty = {
|
|
판정: sk.verdictOf(e, {}),
|
|
켜짐: sk.canConfirm(e, {}),
|
|
확인: d2.확인,
|
|
몸: sk.sureBody({ 고름: {}, 확인: [9] }, more),
|
|
};
|
|
d2 = sk.emptyDraft();
|
|
out.filter = Object.fromEntries(
|
|
["all", "in", "out", "open"].map((f) => [f, sk.filterBlocks(more, d2, f).map((x) => x.번)]),
|
|
);
|
|
out.old = sk.filterBlocks(blocks, d2, "out").length; // 옛 서버(부름 없음) = 모두 안
|
|
out.wait2 = sk.waiting(d2, more);
|
|
process.stdout.write(JSON.stringify(out));
|
|
})().catch((error) => {
|
|
process.stderr.write(String(error?.stack ?? error));
|
|
process.exit(1);
|
|
});
|
|
|
|
/** 780-2 판 바꾸기 — 탭(역할) 차례로 고름 · 판 숨김 · 칸 지음 한 번 · 강조 · 줄 누름 뛰기 */
|
|
function sheetSk({ same, canWrite, picks }) {
|
|
const M02 = path.join(ROOT, "M02_MasterTemplete");
|
|
const { createSheetSk } = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_SheetSk.ts"));
|
|
const roles = { s1: "일위대가표", s2: "단가산출표", s3: "단가산출상세" };
|
|
const jumps = [];
|
|
const nav = {
|
|
role: (sheet) => roles[sheet],
|
|
blockAt: (sheet, row) =>
|
|
sheet === "s2" ? row - 4 : sheet === "s3" ? Math.floor(row / 10) : null,
|
|
spotOf: (no, role) => ({ 시트: role === "단가산출표" ? "s2" : "s3", 행: [no, no + 1] }),
|
|
jumpTo: (sheet, rows) => jumps.push([sheet, rows]),
|
|
};
|
|
const toggled = [];
|
|
const side = {
|
|
hidden: false,
|
|
after: () => {},
|
|
parentElement: { classList: { toggle: (c, on) => toggled.push([c, on]) } },
|
|
};
|
|
const scope = { layer: "personal", owner: null };
|
|
const target = same ? scope : { layer: "company", owner: null };
|
|
const p = createSheetSk({ scope, key: "HP-000001", 파일: "a.xls", target, canWrite, nav, side });
|
|
const seen = [];
|
|
for (const [sheet, cell] of picks) {
|
|
p.at({ 시트: sheet, 칸: cell });
|
|
seen.push({ 호표판숨김: side.hidden, 단가판숨김: p.root.hidden, 지음: made.length });
|
|
if (sheet === "s2" && made[0]) made[0].onRow(8); // 목록 줄 누름(단가산출표 탭)
|
|
if (sheet === "s3" && made[0]) made[0].onRow(8); // 상세 탭
|
|
}
|
|
return { seen, toggled, made: made.map((m) => ({ args: m.args, marks: m.marks })), jumps };
|
|
}
|