Merge remote-tracking branches 'origin/main_laptop_1' and 'origin/sub_laptop_2' into sub_laptop_3

This commit is contained in:
2026-10-06 01:31:19 +09:00
3 changed files with 191 additions and 2 deletions
@@ -214,7 +214,7 @@
const li = $$(".b05-route__irregular-list li").find((l) =>
/배관 1$/.test(l.textContent.trim()),
);
const spec = () => $(".b05-structure__spec", sec);
const spec = () => $$(".b05-structure__spec", sec).find((n) => n.offsetParent !== null); // 명세 폼이 종류마다 여럿 — 보이는 것
(li.querySelector("button") ?? li).click();
await W(800);
if (!(spec() && spec().offsetParent !== null)) (li.querySelector("button") ?? li).click();
+189
View File
@@ -0,0 +1,189 @@
/* 52-13 — 명세 폼 예외 모음(배관 1 · BOX암거 · 세월교 1) — 빈 값 · 오가기 · 종류 바꾸기 · 여러 개
* 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트 · 목록에 「배관 1」 「세월교 1」 · 로그인 상태
* 부르는 법: 단계마다 한 번씩 — 앞에 `window.__m5213 = "단계";` 를 붙여
* cache → 저장 안 하고 B05 → B06 → B05 오가기(캐시 값 그대로) · 종류 바꾸기(배관 → BOX → 배관)
* pipe → 배관 길이 · 전 · 후 비움 + 흙막이 추가 셋 + 도수로/돌붙임 하나 → [저장]
* (orca reload) pipe_v → 다시 열기 · 흙막이 수 3 · 비운 칸 그대로
* bf → 258.12 를 BOX암거로(PUT) · 가로 비움 · 세월교 1 월류 폭 비움 → [저장]
* (orca reload) bf_v → 다시 열기 · 오류 없음
* restore → 원래 관 지점으로 되돌림(PUT) · 초안 비움
* 쓰는 것: 검증 프로젝트 pipe_points.json(되돌림 단계가 원래 값으로 다시 씀)
* 기대 수치: errors 0 · cache.same true · kind.leak 0 · soilCount 3 · 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", "");
for (let i = 0; i < 3; i++) {
spec().querySelector('[data-spec-add="soil_add"]').click();
await w(200);
}
for (let i = 0; i < 3; i++) {
await set("soil_add", "structure", "기슭막이", i);
await set("soil_add", "form", "콘크리트", i);
}
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);
})();
@@ -44,7 +44,7 @@
};
const pickKey = () =>
Object.keys(sessionStorage).find((k) => k.includes("structure-pick") && k.includes(PROJECT));
const PROJECT = "936be972-11bc-46c2-8bf3-b15d8de7df0d";
const PROJECT = localStorage.getItem("frd_current_project_id"); // 환경마다 검증 프로젝트가 다름
const picked = () => {
const raw = pickKey() ? sessionStorage.getItem(pickKey()) : null;
let sid = null;