merge: sub_laptop_5 52-14 — 충돌(이름 줄 꼴 표 tag) = 메인 쪽(text · bool 다 있음) · 겹친 text 키 하나 뺌
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJqWQpoB1RE7hiaQ2wH8qV
This commit is contained in:
@@ -56,6 +56,33 @@ if (process.argv[2] === "road") {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// 기타(PLAN 52-14) — 선택 컨테이너 「상세 내용」 비고 글 · 길이 상한 · 비우기 · 이름 표
|
||||
if (process.argv[2] === "etc") {
|
||||
const spec = STRUCTURE_SPECS.etc;
|
||||
const old = { name: "배수판", etc_detail_2_note: "옛 비고", etc_detail_5_note: "둘째" };
|
||||
const state = s.readState(spec, old);
|
||||
const edited = JSON.parse(JSON.stringify(state));
|
||||
edited.detail[0].note = " 새 비고 ";
|
||||
edited.detail[1].note = "";
|
||||
edited.detail.push({ note: "가".repeat(s.TEXT_MAX + 30) });
|
||||
const out = s.writeOptions(spec, edited);
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
same: spec === road.ETC_SPEC,
|
||||
containers: spec.containers.map((c) => [c.id, c.title, c.required, c.prefix, c.link]),
|
||||
items: spec.containers[0].items.map((i) => [i.id, i.label, i.kind]),
|
||||
state,
|
||||
edited: out,
|
||||
max: s.TEXT_MAX,
|
||||
longLen: out.etc_detail_3_note?.length ?? 0,
|
||||
keys: s.specKeys(spec),
|
||||
names: s.nameTable(spec),
|
||||
links: [1, 2].map((n) => s.linkOf(spec.containers[0], n)),
|
||||
}),
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.argv[2] === "names") {
|
||||
process.stdout.write(JSON.stringify(s.nameTable(PIPE_SPEC)));
|
||||
process.exit(0);
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""공용 틀 글 손 입력 · 기타 선택 컨테이너 · 기타 이름 = 집계 건 이름 — PLAN 52-14.
|
||||
|
||||
순수 규칙은 Node 헬퍼(`helper_52_structure_spec.cjs etc`)가 돌림 ·
|
||||
화면은 ORCA `ui_checks/52-10_노면공_기타.js`(52-14 덧).
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from M02_MasterTemplete import M02_Table_Fill as fill
|
||||
from M02_MasterTemplete.M02_Table_Fill_Spec import SPEC_CONTAINERS, container_rows, etc_label
|
||||
from resources.tester.test_structures_summary_snapshot import ( # noqa: F401 — world 고정물
|
||||
MS,
|
||||
RV,
|
||||
_save,
|
||||
world,
|
||||
)
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
ROOT = os.path.dirname(os.path.dirname(HERE))
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def out():
|
||||
proc = subprocess.run(
|
||||
["node", os.path.join(HERE, "helper_52_structure_spec.cjs"), "etc"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=60,
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
return json.loads(proc.stdout)
|
||||
|
||||
|
||||
def test_기타_선택_컨테이너_상세_내용(out):
|
||||
assert out["same"] is True
|
||||
assert out["containers"] == [["detail", "상세 내용", False, "etc_detail", "getcdetail"]]
|
||||
assert out["items"] == [["note", "비고", "text"]]
|
||||
assert out["links"] == ["getcdetail1", "getcdetail2"]
|
||||
|
||||
|
||||
def test_글_저장_비우기_길이_상한(out):
|
||||
assert out["state"] == {"detail": [{"note": "옛 비고"}, {"note": "둘째"}]} # n 차례대로 당김
|
||||
edited = out["edited"]
|
||||
assert edited["etc_detail_1_note"] == "새 비고" # 앞뒤 빈칸 뺌
|
||||
assert edited["etc_detail_2_note"] == "" # 비운 인스턴스도 자리를 지킴(잇기 · 집계 줄)
|
||||
assert out["longLen"] == out["max"] == 100
|
||||
assert out["keys"] == {"keys": [], "prefixes": ["etc_detail_"]}
|
||||
|
||||
|
||||
def test_이름_표에_글_항목(out):
|
||||
assert out["names"] == {"detail": "상세 내용", "detail.note": "비고"}
|
||||
|
||||
|
||||
def test_기타_이름이_집계_건_이름():
|
||||
assert etc_label("etc", {"name": " 배수판 "}) == {"그룹": "배수판"}
|
||||
assert etc_label("etc", {"name": ""}) == {"그룹": "기타"}
|
||||
assert etc_label("etc", {}) == {"그룹": "기타"}
|
||||
assert etc_label("pipe", {"name": "x"}) == {}
|
||||
item = {
|
||||
"type_id": "etc",
|
||||
"options": {"name": "배수판", "etc_detail_1_note": "왼쪽", "etc_detail_2_note": ""},
|
||||
"복사본": "st1",
|
||||
"그룹": "배수판",
|
||||
}
|
||||
rows = container_rows(item, {"getcdetail1": RV, "getcdetail2": MS})
|
||||
assert [r["그룹"] for r in rows] == ["배수판 1", "배수판 2"]
|
||||
assert [r["복사본"] for r in rows] == ["st1__getcdetail1", "st1__getcdetail2"]
|
||||
assert [r["summary_item"] for r in rows] == [RV, MS]
|
||||
assert rows[0]["options"]["note"] == "왼쪽"
|
||||
|
||||
|
||||
def test_집계_모음에_기타_이름과_컨테이너_건(world): # noqa: F811 — 고정물
|
||||
root = world["root"]
|
||||
etc = {
|
||||
"structure_id": "etc1",
|
||||
"type_id": "etc",
|
||||
"placement": "point",
|
||||
"chainage_m": 60.0,
|
||||
"options": {"name": "배수판", "etc_detail_1_note": "왼쪽"},
|
||||
"group_items": {"getcdetail1": RV},
|
||||
}
|
||||
blank = {**etc, "structure_id": "etc2", "chainage_m": 80.0, "options": {"name": ""}}
|
||||
_save(root, [etc, blank], [])
|
||||
items = {i["복사본"]: i for i in fill.collect_items(root)}
|
||||
assert items["etc1"]["그룹"] == "배수판"
|
||||
assert items["etc1__getcdetail1"]["그룹"] == "배수판 1"
|
||||
assert items["etc1__getcdetail1"]["summary_item"] == RV
|
||||
assert items["etc2"]["그룹"] == "기타"
|
||||
|
||||
|
||||
def test_서버_컨테이너_표는_기타_명세와_짝():
|
||||
with open(
|
||||
os.path.join(ROOT, "A00_Common/design/design_structure_road.ts"), encoding="utf-8"
|
||||
) as f:
|
||||
text = f.read()
|
||||
found = re.findall(
|
||||
r'title: "([^"]+)",\s*required: false,\s*prefix: "(\w+)",\s*link: "(\w+)"', text
|
||||
)
|
||||
assert [(p, link, t) for t, p, link in found] == list(SPEC_CONTAINERS["etc"])
|
||||
@@ -10,7 +10,9 @@
|
||||
* 기대 수치:
|
||||
* 포장 — containers ["detail"] · 상세 내용 · 포장사양 선택지 ["콘크리트"] · 높이 0.35 · 잇기 지정 ·
|
||||
* 종류 단위 잇기 줄 가림 · 옛 상세 칸(두께 · 줄눈 …) 안 보임 · 길이 · 전 · 후 칸 보임
|
||||
* 기타 — 「상세 종류 이름」 글 칸 = 「52-10 시험 기타」 · 목록 이름도 그 글 · 종류 단위 잇기 줄 보임 · 지정
|
||||
* 기타 — 「상세 종류 이름」 글 칸 = 「52-10 시험 기타」 · 목록 이름도 그 글 ·
|
||||
* 선택 컨테이너 「상세 내용」(52-14) 셋 추가 · 비고 글(길이 상한 100) · 1 · 3 잇기 · 2 빼기 →
|
||||
* 둘 남음(비고 ["52-14 비고", ""] · 잇기 둘 다 · 3 의 잇기가 2 로 당겨짐) · 종류 단위 잇기 줄 가림
|
||||
* verify — 같은 값 · 같은 모양(B05 = B06)
|
||||
*/
|
||||
(async () => {
|
||||
@@ -75,6 +77,13 @@
|
||||
paveSpec: specCtl("spec")?.value ?? null,
|
||||
height: specCtl("height")?.value ?? null,
|
||||
containerLink: !!boxes[0]?.querySelector(".b05-structure__summary-name.is-assigned"),
|
||||
containerLinks: boxes.map(
|
||||
(b) => !!b.querySelector(".b05-structure__summary-name.is-assigned"),
|
||||
),
|
||||
notes: boxes.map(
|
||||
(b) => b.querySelector('[data-spec-item="detail.note"] input')?.value ?? null,
|
||||
),
|
||||
noteMax: spec()?.querySelector('[data-spec-item="detail.note"] input')?.maxLength ?? null,
|
||||
typeSummaryVisible: vis(typeSummary()),
|
||||
typeSummaryAfterPosition: after === typeSummary(),
|
||||
typeLink: !!typeSummary().querySelector(".b05-structure__summary-name.is-assigned"),
|
||||
@@ -152,7 +161,28 @@
|
||||
input.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
await w(200);
|
||||
row.picked = await linkFirstLeaf(typeSummary().querySelector('[data-b05-summary="pick"]'));
|
||||
// 52-14 — 상세 내용 셋 추가 · 비고 · 1 · 3 잇기 · 2 빼기
|
||||
for (let k = 0; k < 3; k++) {
|
||||
spec().querySelector('[data-spec-add="detail"]').click();
|
||||
await w(200);
|
||||
}
|
||||
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 }));
|
||||
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();
|
||||
await w(300);
|
||||
}
|
||||
Object.assign(row, shape(item.typeId), { phase: "edit" });
|
||||
sec().querySelector(".is-primary").click(); // 추가
|
||||
@@ -207,9 +237,11 @@
|
||||
!!etc &&
|
||||
!etc.missing &&
|
||||
etc.name === NAME &&
|
||||
etc.containers.length === 0 &&
|
||||
etc.typeSummaryVisible &&
|
||||
etc.typeSummaryAfterPosition &&
|
||||
etc.typeLink;
|
||||
JSON.stringify(etc.containers) === '["detail","detail"]' &&
|
||||
JSON.stringify(etc.legend) === '["상세 내용 1","상세 내용 2"]' &&
|
||||
JSON.stringify(etc.notes) === '["52-14 비고",""]' &&
|
||||
JSON.stringify(etc.containerLinks) === "[true,true]" &&
|
||||
etc.noteMax === 100 &&
|
||||
!etc.typeSummaryVisible;
|
||||
return JSON.stringify(out);
|
||||
})();
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
/** 구조물집계표 채움 줄 수(전구간 고정 줄 뺌) — 52-1b. */
|
||||
const filledRows = async () =>
|
||||
(await m02Api.readFilled(projectId, "구조물집계표")).문서.줄.filter((r) => !r.고정).length;
|
||||
const spec = () => document.querySelector(".b05-structure__spec");
|
||||
// 명세 폼은 둘(관 시설 · 일반 구조물 52-10) — 보이는 것
|
||||
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");
|
||||
|
||||
Reference in New Issue
Block a user