Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
/* 54-26 — B05 · B06 좌측 「구조물 배치」 사면안정 표 09(흙막이 · 옹벽 · 소단)
|
||||
* 시작 화면: B05 종단설계(#/b05-profile) · 검증 프로젝트(랩탑_보조)
|
||||
* 부르는 법: 단계마다 한 번씩 — 앞에 `window.__m5426 = "단계";` 를 붙여
|
||||
* seed → 원래 목록을 sessionStorage 에 두고 흙막이(20+0 · 잇기 하나) · 소단을 심음(PUT) · 그 뒤 orca reload
|
||||
* check → 세 종류 컨테이너 1(이름) · 칸 = 표대로 · 밖 칸 0 · 잇기 1 · 램프 · 형태 선택지 6/1
|
||||
* B05 에서 한 번(값을 sessionStorage 에 둠) · B06(#/b06-section) 에서 한 번(B05 = B06)
|
||||
* split → 흙막이 길이 10 · 전 3 → 후 7(B05 · 실시간 반영 · 저장 안 함)
|
||||
* height → B06 — 좌측 높이 1.8 · 2.3 → 20+0 횡단 벽 그림 높이(H=) 같은 값
|
||||
* save → [저장] — 파일 = 형태 · 길이 10 · 전 3 · 후 7 · 높이 2.3 · 그 뒤 orca reload
|
||||
* verify → 다시 연 흙막이 칸 = 파일 값(B05 · B06 각각)
|
||||
* restore → 원래 목록으로 되돌림(PUT) · 초안 비움
|
||||
* 쓰는 것: 검증 프로젝트 structures.json(되돌림 단계가 원래 값으로 다시 씀)
|
||||
*/
|
||||
(async () => {
|
||||
const MODE = window.__m5426 || "check";
|
||||
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 api = await import(modUrl("/B05_Profile/B05_Profile_Api_Structures.ts"));
|
||||
const LINK = { layer: "system", owner: null, key: "SS000001", name: "54-26 잇기" };
|
||||
const KINDS = {
|
||||
soil_guard: ["gsoilgdetail", "흙막이", /흙막이$/, 6], // 심은 것 하나 · 전 3 이면 19+17~20+7
|
||||
retaining_wall: ["gretaindetail", "옹벽", /^10\+0~10\+10옹벽/, 1],
|
||||
berm: ["gbermdetail", "상세 내용", /^28\+0~28\+10소단/, 0],
|
||||
};
|
||||
const TABLE = {
|
||||
soil_guard: ["form", "length_m", "height_m", "before_m", "after_m"],
|
||||
retaining_wall: ["wall_form", "length_m", "height_m", "before_m", "after_m"],
|
||||
berm: ["width_m", "height_m"],
|
||||
};
|
||||
const section = () => document.querySelector(".b05-structure-section");
|
||||
const selects = () => section().querySelectorAll(".b05-structure__grid select");
|
||||
const visible = (n) => n.offsetParent !== null;
|
||||
const listItem = (re) =>
|
||||
[...document.querySelectorAll(".b05-route__irregular-list li")].find((l) =>
|
||||
re.test(l.textContent.trim()),
|
||||
);
|
||||
const open = async (re) => {
|
||||
await until(() => listItem(re));
|
||||
const li = listItem(re);
|
||||
(li.querySelector("button") ?? li).click();
|
||||
await w(800);
|
||||
if (!selects()[1].value) (li.querySelector("button") ?? li).click(); // 재선택 = 해제 — 한 번 더
|
||||
await until(() => !!selects()[1].value);
|
||||
await w(400);
|
||||
};
|
||||
const reset = async () => {
|
||||
section().querySelector(".b05-route__irregular-actions button:last-child").click();
|
||||
await w(400);
|
||||
};
|
||||
const field = (key) =>
|
||||
section().querySelector(
|
||||
`[data-option-keys="${key}"] input, [data-option-keys="${key}"] select`,
|
||||
);
|
||||
const set = async (key, value) => {
|
||||
const input = field(key);
|
||||
input.value = String(value);
|
||||
input.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
await w(500);
|
||||
};
|
||||
const shape = (type) => {
|
||||
const boxes = [...section().querySelectorAll("[data-b05-group]")].filter(visible);
|
||||
const box = boxes[0];
|
||||
const form = box?.querySelector(
|
||||
'[data-option-keys="form"] select, [data-option-keys="wall_form"] select',
|
||||
);
|
||||
return {
|
||||
boxes: boxes.map((b) => `${b.dataset.b05Group}:${b.querySelector("legend")?.textContent}`),
|
||||
fields: box
|
||||
? [...box.querySelectorAll("[data-option-keys]")].map((n) => n.dataset.optionKeys)
|
||||
: [],
|
||||
loose: [...section().querySelectorAll("[data-option-keys]")].filter(
|
||||
(n) => !n.closest("[data-b05-group]") && visible(n),
|
||||
).length,
|
||||
links: box ? box.querySelectorAll(".b05-structure__summary").length : 0,
|
||||
twoRow: box ? box.querySelectorAll("[data-b05-summary=row]").length : 0,
|
||||
link: box?.querySelector(".b05-structure__summary-name")?.value.trim(),
|
||||
choices: form ? [...form.options].filter((o) => o.value).map((o) => o.textContent) : [],
|
||||
lamps: [...(listItem(KINDS[type][2])?.querySelectorAll(".b05-route__lamps > *") ?? [])].map(
|
||||
(d) => d.className,
|
||||
),
|
||||
};
|
||||
};
|
||||
const ok = (type, s) =>
|
||||
s.boxes.length === 1 &&
|
||||
s.boxes[0] === `${KINDS[type][0]}:${KINDS[type][1]}` &&
|
||||
JSON.stringify(s.fields) === JSON.stringify(TABLE[type]) &&
|
||||
s.loose === 0 &&
|
||||
s.links === 1 &&
|
||||
s.twoRow === 1 &&
|
||||
s.choices.length === KINDS[type][3] &&
|
||||
s.lamps.length === 1;
|
||||
const save = async () => {
|
||||
document.querySelector('[data-dock-action="save"]').click();
|
||||
await w(500);
|
||||
return until(() => !document.querySelector(".ui-overlay.is-active"), 60000);
|
||||
};
|
||||
const soilFile = async () =>
|
||||
(await api.fetchStructures(projectId)).structures.find((s) => s.type_id === "soil_guard");
|
||||
const out = { mode: MODE, page: location.hash };
|
||||
|
||||
if (MODE === "seed") {
|
||||
const now = await api.fetchStructures(projectId);
|
||||
sessionStorage.setItem("__5426_original", JSON.stringify(now.structures));
|
||||
const add = (type_id, at, options, extra = {}) => ({
|
||||
structure_id: null,
|
||||
type_id,
|
||||
placement: "interval",
|
||||
chainage_m: at,
|
||||
start_m: at,
|
||||
end_m: at + 10,
|
||||
options: { length_m: 10, before_m: 0, after_m: 10, ...options },
|
||||
memo: "54-26",
|
||||
...extra,
|
||||
});
|
||||
const next = [
|
||||
...now.structures,
|
||||
add(
|
||||
"soil_guard",
|
||||
400,
|
||||
{ form: "돌쌓기(찰)", height_m: 1.5 },
|
||||
{ group_items: { gsoilgdetail: LINK } },
|
||||
),
|
||||
add("berm", 560, { width_m: 1, height_m: 5 }),
|
||||
];
|
||||
await api.saveStructures(projectId, now.revision, next);
|
||||
for (const k of Object.keys(sessionStorage))
|
||||
if (k.includes("draft:structures") || k.includes("result:section-detail"))
|
||||
sessionStorage.removeItem(k);
|
||||
out.seeded = (await api.fetchStructures(projectId)).structures
|
||||
.filter((s) => s.type_id in KINDS)
|
||||
.map((s) => s.type_id);
|
||||
}
|
||||
|
||||
if (MODE === "check") {
|
||||
await until(() => document.querySelectorAll(".b05-route__irregular-list li").length > 0);
|
||||
const r = {};
|
||||
for (const [type, [, , re]] of Object.entries(KINDS)) {
|
||||
await open(re);
|
||||
r[type] = shape(type);
|
||||
r[type].ok = ok(type, r[type]);
|
||||
}
|
||||
await reset();
|
||||
out.allOk = Object.values(r).every((s) => s.ok);
|
||||
out.read = r;
|
||||
if (!location.hash.includes("b06")) sessionStorage.setItem("__5426_b05", JSON.stringify(r));
|
||||
else out.sameAsB05 = sessionStorage.getItem("__5426_b05") === JSON.stringify(r);
|
||||
}
|
||||
|
||||
if (MODE === "split") {
|
||||
await open(KINDS.soil_guard[2]);
|
||||
await set("length_m", 10);
|
||||
await set("before_m", 3);
|
||||
out.after = field("after_m").value;
|
||||
out.ok = Number(out.after) === 7;
|
||||
}
|
||||
|
||||
if (MODE === "height") {
|
||||
// 독립 벽 조정창은 위치 전용(8-29 지시) — 높이 = 좌측 칸 하나 · 횡단 그림이 그 값을 따라감
|
||||
await open(KINDS.soil_guard[2]);
|
||||
await w(1500);
|
||||
const card = () =>
|
||||
[...document.querySelectorAll(".b06-cross-card")].find((c) =>
|
||||
/^\s*20\+0400\.0m/.test(c.textContent),
|
||||
);
|
||||
const drawn = () => {
|
||||
const tip = card()?.querySelector(".b06-chart__culvert-revet title")?.textContent ?? "";
|
||||
return Number(tip.match(/H=([\d.]+)m/)?.[1]);
|
||||
};
|
||||
const near = (a, b) => Math.abs(a - b) < 0.01;
|
||||
out.steps = [];
|
||||
for (const h of [1.8, 2.3]) {
|
||||
await set("height_m", h);
|
||||
await until(() => near(drawn(), h), 8000);
|
||||
out.steps.push({ left: Number(field("height_m").value), drawn: drawn() });
|
||||
}
|
||||
out.ok = out.steps.every((s) => near(s.left, s.drawn));
|
||||
}
|
||||
|
||||
if (MODE === "save") {
|
||||
out.saved = await save();
|
||||
const soil = await soilFile();
|
||||
out.file = soil.options;
|
||||
out.ok =
|
||||
soil.options.form === "돌쌓기(찰)" &&
|
||||
soil.options.length_m === 10 &&
|
||||
soil.options.before_m === 3 &&
|
||||
soil.options.after_m === 7 &&
|
||||
soil.options.height_m === 2.3 &&
|
||||
JSON.stringify(soil.group_items) === JSON.stringify({ gsoilgdetail: LINK });
|
||||
}
|
||||
|
||||
if (MODE === "verify") {
|
||||
await open(KINDS.soil_guard[2]);
|
||||
const soil = await soilFile();
|
||||
out.form = TABLE.soil_guard.map((k) => field(k).value);
|
||||
out.file = TABLE.soil_guard.map((k) => String(soil.options[k]));
|
||||
out.ok = out.form.every((v, i) => Number(v) === Number(out.file[i]) || v === out.file[i]);
|
||||
await reset();
|
||||
}
|
||||
|
||||
if (MODE === "restore") {
|
||||
const original = JSON.parse(sessionStorage.getItem("__5426_original") || "null");
|
||||
if (!original) return JSON.stringify({ error: "원래 값 없음" });
|
||||
const now = await api.fetchStructures(projectId);
|
||||
await api.saveStructures(projectId, now.revision, original);
|
||||
for (const k of Object.keys(sessionStorage))
|
||||
if (
|
||||
k.includes("draft:structures") ||
|
||||
k.includes("result:section-detail") ||
|
||||
k.startsWith("__5426_")
|
||||
)
|
||||
sessionStorage.removeItem(k);
|
||||
const after = await api.fetchStructures(projectId);
|
||||
const key = (list) =>
|
||||
JSON.stringify(
|
||||
list.map((s) => [
|
||||
s.type_id,
|
||||
s.start_m,
|
||||
s.chainage_m,
|
||||
s.end_m,
|
||||
s.options,
|
||||
s.group_items ?? null,
|
||||
]),
|
||||
);
|
||||
out.restored = key(after.structures) === key(original);
|
||||
}
|
||||
return JSON.stringify(out);
|
||||
})();
|
||||
Reference in New Issue
Block a user