diff --git a/resources/tester/ui_checks/65_세월교_박스_물넘이.js b/resources/tester/ui_checks/65_세월교_박스_물넘이.js new file mode 100644 index 000000000..77fa22d7e --- /dev/null +++ b/resources/tester/ui_checks/65_세월교_박스_물넘이.js @@ -0,0 +1,93 @@ +/* 65 — B05 · B06 좌측 「구조물 배치」 세월교 · 박스암거 · 물넘이 포장(PLAN 65-1 ~ 65-5) + * 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트(검증_sub5) · 목록에 「세월교 1」 + * 부르는 법: orca eval --expression "window.__m65='단계'; $(cat 이 파일)" + * shape — 세월교 1 고름 → 상자 · 칸 · 램프 수 + * edit — 유입 흙막이(기본값 칸) · 유출 없음(램프 줄어듦) · 추가 흙막이 · 도수로 · [저장] + * verify — 다시 연 값 · 램프 수 + * newford — 새 세월교(관경 · 련 · 폭 · 높이 자동) · 새 물넘이(경사각 3 · 폭 · 높이) — 저장 안 함 + * 되돌림: 검증 프로젝트 파일을 미리 떠 둔 사본으로(스크립트 밖) + */ +(async () => { + const MODE = window.__m65 || "shape"; + const w = (ms) => new Promise((r) => setTimeout(r, ms)); + const until = async (fn, ms = 20000) => { + for (let t = 0; t < ms; t += 200) { + if (fn()) return true; + await w(200); + } + return false; + }; + const spec = () => + [...document.querySelectorAll(".b05-structure__spec")].find((n) => n.offsetParent !== null); + const box = (c, i = 0) => spec()?.querySelectorAll(`[data-spec-container="${c}"]`)[i]; + const ctl = (c, item, i = 0) => + box(c, i)?.querySelector(`[data-spec-item="${c}.${item}"]`)?.querySelector("select, input"); + const set = async (c, item, v, i = 0) => { + const el = ctl(c, item, i); + el.value = v; + el.dispatchEvent(new Event("change", { bubbles: true })); + await w(300); + }; + const rows = () => + [...document.querySelectorAll(".b05-route__irregular-list li")].filter((l) => l.offsetParent); + const row = (re) => rows().find((l) => re.test(l.textContent.trim())); + const lamps = (re) => row(re)?.querySelectorAll(".b05-route__lamps i").length ?? -1; + const pick = async (re) => { + await until(() => !!row(re)); + const li = row(re); + (li.querySelector("button") ?? li).click(); + await w(800); + await until(() => !!spec()); + await w(400); + }; + const shape = () => + [...spec().querySelectorAll("[data-spec-container]")].map((b) => ({ + c: b.dataset.specContainer, + legend: b.querySelector("legend")?.firstChild?.textContent, + items: [...b.querySelectorAll("[data-spec-item]")] + .filter((n) => !n.hidden) + .map((n) => [n.dataset.specItem, n.querySelector("select, input")?.value ?? ""]), + fields: [...b.querySelectorAll(".b05-route__field")] + .filter((n) => !n.hidden && n.offsetParent) + .map((n) => n.querySelector("span")?.textContent), + link: !!b.querySelector("[data-spec-link]"), + option: [...b.querySelectorAll(".b05-structure__half-pair button")].map( + (x) => `${x.textContent}${x.disabled ? "(끔)" : ""}`, + ), + })); + const out = { mode: MODE }; + const FORD = /세월교 1$/; + + if (MODE === "shape") { + await pick(FORD); + out.shape = shape(); + out.lamps = lamps(FORD); + } + if (MODE === "edit") { + await pick(FORD); + out.lampsBefore = lamps(FORD); + await set("inlet", "structure", "흙막이"); + out.inlet = shape().find((b) => b.c === "inlet"); + await set("outlet", "structure", "없음"); + await w(800); + out.outlet = shape().find((b) => b.c === "outlet"); + out.lampsAfterNone = lamps(FORD); + for (const c of ["soil_add", "chute_add"]) { + spec().querySelector(`[data-spec-add="${c}"]`)?.click(); + await w(400); + } + await set("chute_add", "structure", "도수로"); + await set("inlet", "length", "8"); + out.lampsAfterAdd = lamps(FORD); + out.edited = shape(); + document.querySelector('[data-dock-action="save"]').click(); + await w(500); + out.saved = await until(() => !document.querySelector(".ui-overlay.is-active"), 60000); + } + if (MODE === "verify") { + await pick(FORD); + out.reopened = shape(); + out.lamps = lamps(FORD); + } + return JSON.stringify(out); +})();