/* 52-13 — 명세 폼 예외 모음(배관 1 · BOX암거 · 세월교 1) — 빈 값 · 오가기 · 종류 바꾸기 · 여러 개 * 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트 · 목록에 「배관 1」 「세월교 1」 · 로그인 상태 * 부르는 법: 단계마다 한 번씩 — 앞에 `window.__m5213 = "단계";` 를 붙여 * cache → 저장 안 하고 B05 → B06 → B05 오가기(캐시 값 그대로) · 종류 바꾸기(배관 → BOX → 배관) * pipe → 배관 길이 · 전 · 후 비움 + 도수로/돌붙임 하나 → [저장](흙막이 = 유출 단 수 · [추가] 없음 · 54-1) * (orca reload) pipe_v → 다시 열기 · 흙막이 수 = 저장 전 그대로 · 비운 칸 그대로 * bf → 258.12 를 BOX암거로(PUT) · 가로 비움 · 세월교 1 월류 폭 비움 → [저장] * (orca reload) bf_v → 다시 열기 · 오류 없음 * restore → 원래 관 지점으로 되돌림(PUT) · 초안 비움 * 쓰는 것: 검증 프로젝트 pipe_points.json(되돌림 단계가 원래 값으로 다시 씀) * 기대 수치: errors 0 · cache.same true · kind.leak 0 · soilCount pipe = pipe_v · soilAdd 0 · inletBlank 빈 칸 셋 · restored true * (배관 도수로/돌붙임 [추가] 는 하나 뒤에도 보임 — 「하나만」은 물넘이 포장 · 기타만 · 52-3 · 52-10) */ (async () => { const MODE = window.__m5213 || "cache"; 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 errors = []; const onErr = (e) => errors.push(String(e.message ?? e.reason ?? e)); window.addEventListener("error", onErr); window.addEventListener("unhandledrejection", onErr); const projectId = localStorage.getItem("frd_current_project_id"); const modUrl = (part) => performance .getEntriesByType("resource") .map((e) => e.name) .filter((n) => n.includes(part)) .pop(); const fetchApi = await import(modUrl("/B04_PreProcess/B04_PreProcess_Api_Fetch.ts")); 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(200); }; const clearDrafts = () => { for (const k of Object.keys(sessionStorage)) if (k.startsWith("aislo:draft:pipes:")) sessionStorage.removeItem(k); }; const pick = async (re) => { const find = () => [...document.querySelectorAll(".b05-route__irregular-list li")].find((l) => re.test(l.textContent.trim()), ); await until(() => !!find()); const li = find(); (li.querySelector("button") ?? li).click(); await until(() => !!spec(), 6000); if (!spec()) (li.querySelector("button") ?? li).click(); await until(() => !!spec()); await w(500); }; const save = async () => { document.querySelector('[data-dock-action="save"]').click(); await w(500); return until(() => !document.querySelector(".ui-overlay.is-active"), 60000); }; const items = () => [...spec().querySelectorAll("[data-spec-item]")].map((n) => n.dataset.specItem); const point = async (lo, hi) => (await fetchApi.fetchDetailPipePoints(projectId)).pipe_points.find( (p) => p.chainage_m > lo && p.chainage_m < hi, ); const out = { mode: MODE }; if (MODE === "cache") { await pick(/배관 1$/); await set("inlet", "structure", "기슭막이"); await set("inlet", "length", "12"); out.before = ctl("inlet", "length").value; location.hash = "#/b06-section"; await w(7000); location.hash = "#/b05-profile"; await w(7000); await pick(/배관 1$/); out.after = ctl("inlet", "length")?.value; out.same = out.before === out.after; clearDrafts(); } if (MODE === "pipe") { sessionStorage.setItem( "__5213_original", JSON.stringify((await fetchApi.fetchDetailPipePoints(projectId)).pipe_points), ); await pick(/배관 1$/); await set("inlet", "structure", "기슭막이"); await set("inlet", "form", "돌망태"); await set("inlet", "length", ""); await set("inlet", "before", ""); await set("inlet", "after", ""); out.soilAdd = spec().querySelectorAll('[data-spec-add="soil_add"]').length; spec().querySelector('[data-spec-add="chute_add"]').click(); await w(200); await set("chute_add", "structure", "돌붙임"); out.soilCount = spec().querySelectorAll('[data-spec-container="soil_add"]').length; out.saved = await save(); const p = await point(80, 90); out.file = p && p.options; } if (MODE === "pipe_v") { await pick(/배관 1$/); out.soilCount = spec().querySelectorAll('[data-spec-container="soil_add"]').length; out.chuteAdd = !!spec().querySelector('[data-spec-add="chute_add"]'); out.inletBlank = ["length", "before", "after"].map((k) => ctl("inlet", k)?.value); } if (MODE === "bf") { const orig = (await fetchApi.fetchDetailPipePoints(projectId)).pipe_points; if (!sessionStorage.getItem("__5213_original")) sessionStorage.setItem("__5213_original", JSON.stringify(orig)); const pts = JSON.parse(JSON.stringify(orig)).map((p) => Math.abs(p.chainage_m - 258.12) < 0.05 ? { ...p, facility: "box_culvert", options: { body_width_m: 3, body_height_m: 2.5 } } : p, ); await fetchApi.saveDetailPipePoints(projectId, pts); clearDrafts(); out.ready = true; } if (MODE === "bf_edit") { await pick(/BOX암거$/); await set("body", "size", "사용자 입력"); await set("body", "width", ""); out.boxSaved = await save(); out.boxFile = (await point(250, 260))?.options; await pick(/세월교 1$/); await set("ford", "width", ""); out.fordSaved = await save(); out.fordFile = (await point(170, 176))?.options; } if (MODE === "bf_v") { await pick(/BOX암거$/); out.box = { size: ctl("body", "size")?.value, width: ctl("body", "width")?.value }; await pick(/세월교 1$/); out.ford = { width: ctl("ford", "width")?.value, height: ctl("ford", "height")?.value }; } if (MODE === "kind") { const sec = document.querySelector(".b05-structure-section"); const sel = () => sec.querySelectorAll(".b05-structure__grid select"); const fire = (el, v) => { el.value = v; el.dispatchEvent(new Event("change", { bubbles: true })); }; const seen = {}; for (const t of ["pipe", "box_culvert", "pipe"]) { fire(sel()[0], "A"); await w(300); fire(sel()[1], t); await w(600); seen[t + "#" + Object.keys(seen).length] = items().join(","); } const vals = Object.values(seen); out.seen = vals; out.leak = vals[0] === vals[2] && !/body\./.test(vals[0]) && !/pipe\./.test(vals[1]) ? 0 : 1; } if (MODE === "restore") { const original = JSON.parse(sessionStorage.getItem("__5213_original") || "null"); if (!original) return JSON.stringify({ error: "원래 값 없음" }); await fetchApi.saveDetailPipePoints(projectId, original); clearDrafts(); sessionStorage.removeItem("__5213_original"); const now = (await fetchApi.fetchDetailPipePoints(projectId)).pipe_points; out.restored = JSON.stringify(now.map((p) => [p.chainage_m, p.facility ?? null, p.options ?? null])) === JSON.stringify(original.map((p) => [p.chainage_m, p.facility ?? null, p.options ?? null])); } out.errors = errors; return JSON.stringify(out); })();