Merge remote-tracking branch 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -28,6 +28,7 @@ export const FORD_PAVEMENT_SPEC: StructureSpec = {
|
||||
required: false,
|
||||
prefix: "ford_chute",
|
||||
link: "gfordpavechute",
|
||||
max: 1,
|
||||
items: [
|
||||
{
|
||||
id: "structure",
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
* design_structure_form.ts
|
||||
* 구조물 명세(`design_structure_spec`) 그리기 — B05 · B06 「구조물 배치」 칸이 같은 노드를 씀.
|
||||
*
|
||||
* · 필수 컨테이너 = 늘 보임(한 벌) · 선택 컨테이너 = [추가] 로 인스턴스를 늘리고 인스턴스마다 [빼기]
|
||||
* · 필수 컨테이너 = 늘 보임(한 벌) · 선택 컨테이너 = [추가] 로 인스턴스를 늘리고 인스턴스마다 [빼기] ·
|
||||
* `max` 에 차면 [추가] 숨김
|
||||
* · 항목: 고르기(상위 값에 따른 선택지 · 저장 키) · 숫자(맞물림 = 길이 · 전 · 후) · 글(손 입력) · 자동(읽기만)
|
||||
* · 인스턴스마다 「구조물 조합」 잇기 줄(`buildSummaryRow` · 고르기 모달 = 패널의 그룹 [고르기] 길 그대로) —
|
||||
* 값은 패널 `group_items` 에 `linkOf` 키로 둠(빼면 뒤 인스턴스 잇기를 한 칸씩 당김)
|
||||
@@ -216,7 +217,7 @@ export function createSpecForm(links: SpecLinks | null, hooks: SpecFormHooks = {
|
||||
for (const c of spec?.containers ?? []) {
|
||||
const list = (state[c.id] ??= c.required ? [{}] : []);
|
||||
list.forEach((values, index) => boxes.push(instanceBox(c, values, index)));
|
||||
if (c.required) continue;
|
||||
if (c.required || (c.max && list.length >= c.max)) continue;
|
||||
const add = document.createElement("button");
|
||||
add.type = "button";
|
||||
add.className = "b05-route__irregular-btn b05-structure__spec-add";
|
||||
|
||||
@@ -55,6 +55,7 @@ export const ETC_SPEC: StructureSpec = {
|
||||
required: false,
|
||||
prefix: "etc_detail",
|
||||
link: "getcdetail",
|
||||
max: 1,
|
||||
items: [{ id: "note", label: "비고", kind: "text" }],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* 구조물 명세 공용 틀(PLAN 52) — 화면 요소 없는 순수 규칙. 사용자 구조물 표 한 장 = 명세 한 벌.
|
||||
*
|
||||
* · 종류 = 기본 옵션(기준 측점 No + 거리 · 패널 위치 칸이 받음) + 컨테이너[] + 항목[]
|
||||
* · 컨테이너 = 제목 · 필수(늘 한 벌) / 선택([추가] · [빼기] · 여러 개)
|
||||
* · 컨테이너 = 제목 · 필수(늘 한 벌) / 선택([추가] · [빼기] · 여러 개 · `max` 면 그 수까지)
|
||||
* · 항목 꼴 = 고르기 · 숫자 · 글(손 입력 · 길이 상한 `TEXT_MAX`) · 자동(계산이 채움 · 저장 안 함) ·
|
||||
* 맞물림(길이 = 전 + 후)
|
||||
* · 상위 값에 따른 선택지 · 저장 키 = `by`(같은 컨테이너 안 상위 항목 값 → 갈래)
|
||||
@@ -53,6 +53,8 @@ export interface SpecContainer {
|
||||
required: boolean;
|
||||
/** 선택 컨테이너 저장 키 머리 — `{prefix}_{n}_{항목}`. */
|
||||
prefix?: string;
|
||||
/** 선택 컨테이너 개수 상한 — 차면 [추가] 숨김(옛 저장이 넘쳐도 다 보임). 없으면 여러 개. */
|
||||
max?: number;
|
||||
/** 구조물 조합 잇기 키 — 필수는 정의 그룹 id 그대로 · 선택은 뒤에 n. */
|
||||
link: string;
|
||||
items: SpecItem[];
|
||||
|
||||
@@ -83,6 +83,23 @@ if (process.argv[2] === "etc") {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// 선택 컨테이너 「하나만」(PLAN 52-17) — 종류.컨테이너 → max · 옛 저장 둘은 다 읽힘
|
||||
if (process.argv[2] === "max") {
|
||||
const max = {};
|
||||
for (const [type, spec] of Object.entries(STRUCTURE_SPECS))
|
||||
for (const c of spec.containers) if (!c.required) max[`${type}.${c.id}`] = c.max ?? null;
|
||||
const old = { ford_chute_1_structure: "도수로", ford_chute_2_structure: "돌붙임" };
|
||||
const state = s.readState(STRUCTURE_SPECS.ford_pavement, old);
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
max,
|
||||
oldTwo: state.chute.length,
|
||||
back: s.writeOptions(STRUCTURE_SPECS.ford_pavement, state),
|
||||
}),
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv[2] === "names") {
|
||||
process.stdout.write(JSON.stringify(s.nameTable(PIPE_SPEC)));
|
||||
process.exit(0);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""공용 틀 선택 컨테이너 「하나만」(max) — PLAN 52-17.
|
||||
|
||||
순수 규칙은 Node 헬퍼(`helper_52_structure_spec.cjs max`)가 돌림 ·
|
||||
화면([추가] 숨김)은 ORCA `ui_checks/52-3` · `52-10` · `52-1`.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def _run():
|
||||
proc = subprocess.run(
|
||||
["node", os.path.join(HERE, "helper_52_structure_spec.cjs"), "max"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=60,
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
return json.loads(proc.stdout)
|
||||
|
||||
|
||||
def test_하나만_컨테이너와_여러개_컨테이너():
|
||||
out = _run()
|
||||
assert out["max"] == {
|
||||
"pipe.soil_add": None,
|
||||
"pipe.chute_add": None,
|
||||
"ford_pavement.chute": 1,
|
||||
"etc.detail": 1,
|
||||
}
|
||||
|
||||
|
||||
def test_옛_저장_둘은_지우지_않음():
|
||||
out = _run()
|
||||
assert out["oldTwo"] == 2
|
||||
assert out["back"] == {"ford_chute_1_structure": "도수로", "ford_chute_2_structure": "돌붙임"}
|
||||
@@ -11,8 +11,8 @@
|
||||
* 포장 — containers ["detail"] · 상세 내용 · 포장사양 선택지 ["콘크리트"] · 높이 0.35 · 잇기 지정 ·
|
||||
* 종류 단위 잇기 줄 가림 · 옛 상세 칸(두께 · 줄눈 …) 안 보임 · 길이 · 전 · 후 칸 보임
|
||||
* 기타 — 「상세 종류 이름」 글 칸 = 「52-10 시험 기타」 · 목록 이름도 그 글 ·
|
||||
* 선택 컨테이너 「상세 내용」(52-14) 셋 추가 · 비고 글(길이 상한 100) · 1 · 3 잇기 · 2 빼기 →
|
||||
* 둘 남음(비고 ["52-14 비고", ""] · 잇기 둘 다 · 3 의 잇기가 2 로 당겨짐) · 종류 단위 잇기 줄 가림
|
||||
* 선택 컨테이너 「상세 내용」(52-14) 하나만(52-17) — 추가 → [추가] 없음 · 빼기 → 다시 보임 ·
|
||||
* 다시 추가 · 비고 「52-14 비고」(길이 상한 100) · 잇기 · 하나 남음 · 종류 단위 잇기 줄 가림
|
||||
* verify — 같은 값 · 같은 모양(B05 = B06)
|
||||
*/
|
||||
(async () => {
|
||||
@@ -161,28 +161,28 @@
|
||||
input.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
await w(200);
|
||||
// 52-14 — 상세 내용 셋 추가 · 비고 · 1 · 3 잇기 · 2 빼기
|
||||
for (let k = 0; k < 3; k++) {
|
||||
spec().querySelector('[data-spec-add="detail"]').click();
|
||||
await w(200);
|
||||
}
|
||||
// 52-14 · 52-17 — 상세 내용 하나만: 추가 → [추가] 없음 · 빼기 → 다시 보임 · 다시 추가 · 비고 · 잇기
|
||||
const addShown = () => !!spec().querySelector('[data-spec-add="detail"]');
|
||||
const notes = () => [...spec().querySelectorAll('[data-spec-item="detail.note"] input')];
|
||||
for (const [k, text] of [
|
||||
[0, "52-14 비고"],
|
||||
[1, "지울 것"],
|
||||
]) {
|
||||
notes()[k].value = text;
|
||||
notes()[k].dispatchEvent(new Event("change", { bubbles: true }));
|
||||
const note = async (text) => {
|
||||
notes()[0].value = text;
|
||||
notes()[0].dispatchEvent(new Event("change", { bubbles: true }));
|
||||
await w(200);
|
||||
}
|
||||
const pickBtns = () => [
|
||||
...spec().querySelectorAll('[data-spec-link] [data-b05-summary="pick"]'),
|
||||
];
|
||||
row.picked = await linkFirstLeaf(pickBtns()[0]);
|
||||
row.picked3 = await linkFirstLeaf(pickBtns()[2]);
|
||||
row.addedShape = shape(item.typeId);
|
||||
spec().querySelectorAll('[data-spec-remove="detail"]')[1].click();
|
||||
};
|
||||
spec().querySelector('[data-spec-add="detail"]').click();
|
||||
await w(200);
|
||||
row.addAfterOne = addShown();
|
||||
await note("지울 것");
|
||||
spec().querySelector('[data-spec-remove="detail"]').click();
|
||||
await w(300);
|
||||
row.addAfterRemove = addShown();
|
||||
spec().querySelector('[data-spec-add="detail"]').click();
|
||||
await w(200);
|
||||
await note("52-14 비고");
|
||||
row.picked = await linkFirstLeaf(
|
||||
spec().querySelector('[data-spec-link] [data-b05-summary="pick"]'),
|
||||
);
|
||||
row.addAfterReAdd = addShown();
|
||||
}
|
||||
Object.assign(row, shape(item.typeId), { phase: "edit" });
|
||||
sec().querySelector(".is-primary").click(); // 추가
|
||||
@@ -237,10 +237,12 @@
|
||||
!!etc &&
|
||||
!etc.missing &&
|
||||
etc.name === NAME &&
|
||||
JSON.stringify(etc.containers) === '["detail","detail"]' &&
|
||||
JSON.stringify(etc.legend) === '["상세 내용 1","상세 내용 2"]' &&
|
||||
JSON.stringify(etc.notes) === '["52-14 비고",""]' &&
|
||||
JSON.stringify(etc.containerLinks) === "[true,true]" &&
|
||||
JSON.stringify(etc.containers) === '["detail"]' &&
|
||||
JSON.stringify(etc.legend) === '["상세 내용 1"]' &&
|
||||
JSON.stringify(etc.notes) === '["52-14 비고"]' &&
|
||||
JSON.stringify(etc.containerLinks) === "[true]" &&
|
||||
(etc.phase !== "edit" ||
|
||||
(etc.addAfterOne === false && etc.addAfterRemove === true && etc.addAfterReAdd === false)) &&
|
||||
etc.noteMax === 100 &&
|
||||
!etc.typeSummaryVisible;
|
||||
return JSON.stringify(out);
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
* orca eval --expression "window.__m523='restore'; $(cat 이 파일)" → 원래 관 지점으로 되돌림(PUT) · 초안 비움
|
||||
* 쓰는 것: 검증 프로젝트 pipe_points.json(되돌림 단계가 원래 값으로 다시 씀)
|
||||
* 기대 수치(edit): 컨테이너 = 경사각도(필수) · [+ 도수로/돌붙임] · 옛 칸 안 보임 · 지난 정의 값 5 ·
|
||||
* 구조 선택지 도수로/돌붙임 · 각도 12.5 · 선택 둘 추가(돌붙임 · 도수로) · 잇기 경사각도 · 둘째 → 첫째 [빼기] ·
|
||||
* 남은 하나 = 도수로 · 잇기가 첫째로 당겨짐 · 저장 파일 = 도 · 인스턴스 키 · 옛 값 그대로
|
||||
* 구조 선택지 도수로/돌붙임 · 각도 12.5 · 하나 추가(돌붙임) → [추가] 없음(52-17) · 잇기 경사각도 · 도수로/돌붙임 ·
|
||||
* [빼기] → 잇기 풂 · [추가] 다시 보임 · 다시 추가(도수로) · 저장 파일 = 도 · 인스턴스 키 하나 · 옛 값 그대로
|
||||
* 기대 수치(verify): 저장 값 그대로 · 같은 그리기(B05 = B06)
|
||||
*/
|
||||
(async () => {
|
||||
@@ -151,21 +151,27 @@
|
||||
out.oldFieldsVisible = visibleKeys();
|
||||
out.stale = staleCount();
|
||||
await set(boxes("slope")[0], "slope", "angle", "12.5");
|
||||
// 52-17 — 하나만: 하나 넣으면 [추가] 없음 · 빼면 다시 보임
|
||||
const addShown = () => !!spec().querySelector('[data-spec-add="chute"]');
|
||||
spec().querySelector('[data-spec-add="chute"]').click();
|
||||
await w(300);
|
||||
spec().querySelector('[data-spec-add="chute"]').click();
|
||||
await w(300);
|
||||
out.addAfterOne = addShown();
|
||||
out.chuteChoices = [...ctl(boxes("chute")[0], "chute", "structure").options]
|
||||
.filter((o) => o.value)
|
||||
.map((o) => o.text);
|
||||
await set(boxes("chute")[0], "chute", "structure", "돌붙임");
|
||||
await set(boxes("chute")[1], "chute", "structure", "도수로");
|
||||
await pickLink(boxes("slope")[0]);
|
||||
await pickLink(boxes("chute")[1]);
|
||||
await pickLink(boxes("chute")[0]);
|
||||
out.beforeRemove = shape().map((b) => [b.legend, b.items, b.link]);
|
||||
boxes("chute")[0].querySelector('[data-spec-remove="chute"]').click();
|
||||
await w(400);
|
||||
out.afterRemove = shape().map((b) => [b.legend, b.items, b.link]);
|
||||
out.addAfterRemove = addShown();
|
||||
spec().querySelector('[data-spec-add="chute"]').click();
|
||||
await w(300);
|
||||
await set(boxes("chute")[0], "chute", "structure", "도수로");
|
||||
out.final = shape().map((b) => [b.legend, b.items, b.link]);
|
||||
out.addAfterReAdd = addShown();
|
||||
document.querySelector('[data-dock-action="save"]').click();
|
||||
await w(500);
|
||||
out.saved = await until(() => !document.querySelector(".ui-overlay.is-active"), 60000);
|
||||
|
||||
Reference in New Issue
Block a user