|
|
|
@@ -0,0 +1,202 @@
|
|
|
|
|
/* 52-1 — B05 · B06 좌측 「구조물 배치」 배관 = 사용자 구조물 표 01 명세(컨테이너 다섯)
|
|
|
|
|
* 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트(sub5_검증) · 목록에 「배관 1」
|
|
|
|
|
* 부르는 법: 단계마다 한 번씩 — 앞에 `window.__m521 = "단계";` 를 붙여
|
|
|
|
|
* orca eval --expression "window.__m521='edit'; $(cat 이 파일)" → 고치고 [저장] (원래 관 지점은 sessionStorage 에 둠)
|
|
|
|
|
* (orca reload 로 다시 열기)
|
|
|
|
|
* orca eval --expression "window.__m521='verify'; $(cat 이 파일)" → 다시 연 값 · B06 같은 그리기 · 관 길이
|
|
|
|
|
* orca eval --expression "window.__m521='restore'; $(cat 이 파일)" → 원래 관 지점으로 되돌림(PUT) · 초안 비움
|
|
|
|
|
* 쓰는 것: 검증 프로젝트 pipe_points.json(되돌림 단계가 원래 값으로 다시 씀)
|
|
|
|
|
* 기대 수치(edit): kinds 5 · required 3 늘 보임 · formBasin I형/L형/ㄷ형 · formSoil 6 · split 길이 7 ·
|
|
|
|
|
* soilAdd 둘 → 하나 빼면 하나(콘크리트) · chute 하나(돌붙임) · 잇기 유입 지정 · 유출 지정 뒤 풂
|
|
|
|
|
* 기대 수치(verify): 저장 값 그대로 · 같은 그리기(B05 = B06) · 관 길이 수(B06)
|
|
|
|
|
*/
|
|
|
|
|
(async () => {
|
|
|
|
|
const MODE = window.__m521 || "edit";
|
|
|
|
|
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 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.querySelector(".b05-structure__spec");
|
|
|
|
|
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 labels = (c, item) => [...ctl(c, item).options].filter((o) => o.value).map((o) => o.text);
|
|
|
|
|
const pickPipe = async () => {
|
|
|
|
|
await until(() => document.querySelectorAll(".b05-route__irregular-list li").length > 0);
|
|
|
|
|
const li = [...document.querySelectorAll(".b05-route__irregular-list li")].find((l) =>
|
|
|
|
|
/배관 1$/.test(l.textContent.trim()),
|
|
|
|
|
);
|
|
|
|
|
// 다시 열면 고른 것이 복원돼 있음 — 누르면 풀리므로 풀렸으면 한 번 더(재선택 = 해제)
|
|
|
|
|
(li.querySelector("button") ?? li).click();
|
|
|
|
|
await w(800);
|
|
|
|
|
if (!(spec() && spec().offsetParent !== null)) (li.querySelector("button") ?? li).click();
|
|
|
|
|
await until(() => spec() && spec().offsetParent !== null);
|
|
|
|
|
await w(500);
|
|
|
|
|
};
|
|
|
|
|
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]")].map((n) => n.dataset.specItem),
|
|
|
|
|
link: b.querySelector(".b05-structure__summary-name")?.textContent,
|
|
|
|
|
}));
|
|
|
|
|
const linkName = (c, i = 0) =>
|
|
|
|
|
box(c, i).querySelector(".b05-structure__summary-name").classList.contains("is-assigned");
|
|
|
|
|
const pickLink = async (c) => {
|
|
|
|
|
box(c).querySelector('[data-b05-summary="pick"]').click();
|
|
|
|
|
await until(() => document.querySelector(".ui-item-picker__tree .ui-tree__row"));
|
|
|
|
|
// 첫 잎까지 펼침
|
|
|
|
|
for (let k = 0; k < 8; k++) {
|
|
|
|
|
const rows = [...document.querySelectorAll(".ui-item-picker__tree .ui-tree__row")];
|
|
|
|
|
const leaf = rows.find((r) => !r.classList.contains("is-branch"));
|
|
|
|
|
if (leaf) {
|
|
|
|
|
leaf.click();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
const closed = rows.find((r) => r.querySelector(".ui-tree__caret")?.textContent === "▸");
|
|
|
|
|
closed?.click();
|
|
|
|
|
await w(300);
|
|
|
|
|
}
|
|
|
|
|
await w(300);
|
|
|
|
|
[...document.querySelectorAll(".ui-item-picker__actions button")]
|
|
|
|
|
.find((b) => b.textContent.includes("적용"))
|
|
|
|
|
.click();
|
|
|
|
|
await w(500);
|
|
|
|
|
};
|
|
|
|
|
const out = { mode: MODE };
|
|
|
|
|
|
|
|
|
|
if (MODE === "edit") {
|
|
|
|
|
const before = await fetchApi.fetchDetailPipePoints(projectId);
|
|
|
|
|
sessionStorage.setItem("__521_original", JSON.stringify(before.pipe_points));
|
|
|
|
|
await pickPipe();
|
|
|
|
|
const s0 = shape();
|
|
|
|
|
out.kinds =
|
|
|
|
|
s0.filter((b) => ["pipe", "inlet", "outlet"].includes(b.c)).length +
|
|
|
|
|
spec().querySelectorAll("[data-spec-add]").length;
|
|
|
|
|
out.required = ["pipe", "inlet", "outlet"].every((c) => box(c)?.offsetParent !== null);
|
|
|
|
|
out.addButtons = [...spec().querySelectorAll("[data-spec-add]")].map((b) => b.textContent);
|
|
|
|
|
// 형태 선택지가 구조를 따름
|
|
|
|
|
await set("inlet", "structure", "집수정");
|
|
|
|
|
out.formBasin = labels("inlet", "form");
|
|
|
|
|
await set("inlet", "structure", "기슭막이");
|
|
|
|
|
out.formSoil = labels("inlet", "form");
|
|
|
|
|
await set("inlet", "form", "돌망태");
|
|
|
|
|
// 길이 = 전 + 후 — 길이 10 · 전 3 → 후 7 · 이어서 후 4 → 길이 7(전 · 후를 지킴)
|
|
|
|
|
await set("inlet", "length", "10");
|
|
|
|
|
await set("inlet", "before", "3");
|
|
|
|
|
out.splitAfter = ctl("inlet", "after").value;
|
|
|
|
|
await set("inlet", "after", "4");
|
|
|
|
|
out.splitLength = ctl("inlet", "length").value;
|
|
|
|
|
// 선택 컨테이너 — 흙막이 추가 둘 → 첫째 뺌 · 도수로/돌붙임 하나
|
|
|
|
|
spec().querySelector('[data-spec-add="soil_add"]').click();
|
|
|
|
|
await w(200);
|
|
|
|
|
spec().querySelector('[data-spec-add="soil_add"]').click();
|
|
|
|
|
await w(200);
|
|
|
|
|
await set("soil_add", "structure", "기슭막이", 0);
|
|
|
|
|
await set("soil_add", "form", "바자", 0);
|
|
|
|
|
await set("soil_add", "structure", "기슭막이", 1);
|
|
|
|
|
await set("soil_add", "form", "콘크리트", 1);
|
|
|
|
|
out.soilAddTwo = spec().querySelectorAll('[data-spec-container="soil_add"]').length;
|
|
|
|
|
out.soilFormsSoilAdd = labels("soil_add", "form").length;
|
|
|
|
|
box("soil_add", 0).querySelector('[data-spec-remove="soil_add"]').click();
|
|
|
|
|
await w(300);
|
|
|
|
|
out.soilAddAfterRemove = [...spec().querySelectorAll('[data-spec-container="soil_add"]')].map(
|
|
|
|
|
(b, i) => [
|
|
|
|
|
b.querySelector("legend").firstChild.textContent,
|
|
|
|
|
ctl("soil_add", "form", i).value,
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
spec().querySelector('[data-spec-add="chute_add"]').click();
|
|
|
|
|
await w(200);
|
|
|
|
|
await set("chute_add", "structure", "돌붙임");
|
|
|
|
|
out.chuteChoices = labels("chute_add", "structure");
|
|
|
|
|
// 구조물 조합 잇기 — 유입 지정 · 유출 지정 뒤 풂
|
|
|
|
|
await pickLink("inlet");
|
|
|
|
|
out.linkInlet = linkName("inlet");
|
|
|
|
|
await pickLink("outlet");
|
|
|
|
|
out.linkOutletPicked = linkName("outlet");
|
|
|
|
|
box("outlet").querySelector('[data-b05-summary="clear"]').click();
|
|
|
|
|
await w(300);
|
|
|
|
|
out.linkOutletCleared = !linkName("outlet");
|
|
|
|
|
// [저장]
|
|
|
|
|
document.querySelector('[data-dock-action="save"]').click();
|
|
|
|
|
await w(500);
|
|
|
|
|
out.saved = await until(() => !document.querySelector(".ui-overlay.is-active"), 60000);
|
|
|
|
|
const after = await fetchApi.fetchDetailPipePoints(projectId);
|
|
|
|
|
const p = after.pipe_points.find((x) => x.chainage_m > 80 && x.chainage_m < 90); // 배관 1 = 4+5
|
|
|
|
|
out.file = p && {
|
|
|
|
|
options: p.options,
|
|
|
|
|
group_items: Object.keys(p.group_items ?? {}),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MODE === "verify") {
|
|
|
|
|
await pickPipe();
|
|
|
|
|
out.reopened = {
|
|
|
|
|
inlet: ["structure", "form", "length", "before", "after"].map((k) => ctl("inlet", k).value),
|
|
|
|
|
soilAdd: [...spec().querySelectorAll('[data-spec-container="soil_add"]')].map(
|
|
|
|
|
(_, i) => ctl("soil_add", "form", i).value,
|
|
|
|
|
),
|
|
|
|
|
chute: ctl("chute_add", "structure").value,
|
|
|
|
|
linkInlet: linkName("inlet"),
|
|
|
|
|
linkOutlet: linkName("outlet"),
|
|
|
|
|
};
|
|
|
|
|
const b05 = shape();
|
|
|
|
|
out.b05Length = ctl("pipe", "length").value;
|
|
|
|
|
location.hash = "#/b06-section";
|
|
|
|
|
await until(() => location.hash.includes("b06"), 5000);
|
|
|
|
|
await w(6000);
|
|
|
|
|
await pickPipe();
|
|
|
|
|
const b06 = shape();
|
|
|
|
|
out.sameDrawing = JSON.stringify(b05) === JSON.stringify(b06);
|
|
|
|
|
if (!out.sameDrawing) out.diff = { b05, b06 };
|
|
|
|
|
out.b06Length = ctl("pipe", "length").value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MODE === "restore") {
|
|
|
|
|
const original = JSON.parse(sessionStorage.getItem("__521_original") || "null");
|
|
|
|
|
if (!original) return JSON.stringify({ error: "원래 값 없음" });
|
|
|
|
|
const keys = [
|
|
|
|
|
"chainage_m",
|
|
|
|
|
"source",
|
|
|
|
|
"facility",
|
|
|
|
|
"start_m",
|
|
|
|
|
"end_m",
|
|
|
|
|
"options",
|
|
|
|
|
"summary_item",
|
|
|
|
|
"group_items",
|
|
|
|
|
];
|
|
|
|
|
const points = original.map((p) =>
|
|
|
|
|
Object.fromEntries(
|
|
|
|
|
keys.filter((k) => p[k] !== undefined && p[k] !== null).map((k) => [k, p[k]]),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
await fetchApi.saveDetailPipePoints(projectId, points);
|
|
|
|
|
for (const k of Object.keys(sessionStorage))
|
|
|
|
|
if (k.startsWith("aislo:draft:pipes:") || k === "__521_original")
|
|
|
|
|
sessionStorage.removeItem(k);
|
|
|
|
|
const now = await fetchApi.fetchDetailPipePoints(projectId);
|
|
|
|
|
const pick = (list) =>
|
|
|
|
|
JSON.stringify(list.map((p) => [p.chainage_m, p.options ?? {}, p.group_items ?? {}]));
|
|
|
|
|
out.restored = pick(now.pipe_points) === pick(original);
|
|
|
|
|
}
|
|
|
|
|
return JSON.stringify(out);
|
|
|
|
|
})();
|