Merge remote-tracking branch 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -138,6 +138,7 @@ def _with_group_items(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
복사본 `{구조물 id}__{그룹 id}`. 정의된 그룹만(미지정 그룹 = 「미지정」 알림에 셈) · 정의가 사라진
|
||||
그룹 연결은 기록에만 남고 표에 안 들어감."""
|
||||
from common_util.common_util_summary_item import GROUP_JOIN
|
||||
from M02_MasterTemplete.M02_Table_Fill_Spec import container_rows
|
||||
from M02_MasterTemplete.StructOptions.M02_SO_Groups import groups_of
|
||||
|
||||
defined = groups_of()
|
||||
@@ -154,6 +155,7 @@ def _with_group_items(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
"그룹": group["name"],
|
||||
}
|
||||
)
|
||||
out.extend(container_rows(item, links)) # 선택 컨테이너마다 한 건(PLAN 52-1b)
|
||||
return out
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
"""집계표 채움 — 구조물 명세 선택 컨테이너마다 한 건 더(PLAN 52-1b).
|
||||
|
||||
선택 컨테이너 인스턴스(옵션 `{머리}_{n}_{항목}`)마다 같은 구조물 · 자리에 한 건 —
|
||||
집계 항목 = 잇기 `group_items[{잇기}{n}]` · 복사본 `{구조물 id}__{잇기}{n}` · 옵션 = 그 컨테이너 값.
|
||||
열 바인딩이 읽는 칸이 갈래마다 달라(독립 기슭막이 `form` · `length_m` … · 관 `{유입|유출}_revet_*`)
|
||||
컨테이너 값을 그 칸들에 함께 얹음 — 어느 출처로 읽어도 그 컨테이너 값.
|
||||
짝: `A00_Common/design/design_structure_pipe.ts` 선택 컨테이너(머리 · 잇기 · 제목) — 시험이 대조.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from common_util.common_util_summary_item import GROUP_JOIN
|
||||
|
||||
#: 종류 → 선택 컨테이너 (머리, 잇기, 제목)
|
||||
SPEC_CONTAINERS: dict[str, tuple[tuple[str, str, str], ...]] = {
|
||||
"pipe": (
|
||||
("soil_add", "gsoiladd", "흙막이 추가"),
|
||||
("chute_add", "gchuteadd", "도수로/돌붙임"),
|
||||
),
|
||||
}
|
||||
_TEXT = ("structure", "form")
|
||||
|
||||
|
||||
def _as_options(values: dict[str, Any]) -> dict[str, Any]:
|
||||
"""컨테이너 값 → 열이 읽는 칸 — 구조 = `structure` · `{쪽}_type` ·
|
||||
나머지 = 맨 칸 + `{쪽}_revet_*`."""
|
||||
out: dict[str, Any] = {}
|
||||
for item, value in values.items():
|
||||
if item == "structure":
|
||||
out.update(structure=value, inlet_type=value, outlet_type=value)
|
||||
continue
|
||||
name = item if item in _TEXT else f"{item}_m"
|
||||
out[name] = value
|
||||
for side in ("inlet", "outlet"):
|
||||
out[f"{side}_revet_{name}"] = value
|
||||
return out
|
||||
|
||||
|
||||
def container_rows(item: dict[str, Any], links: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""한 구조물의 선택 컨테이너 인스턴스마다 한 건(n 차례) — 컨테이너 없는 종류는 빈 목록."""
|
||||
rows: list[dict[str, Any]] = []
|
||||
for prefix, link, title in SPEC_CONTAINERS.get(item["type_id"], ()):
|
||||
head = re.compile(rf"^{prefix}_(\d+)_(.+)$")
|
||||
found: dict[int, dict[str, Any]] = {}
|
||||
for key, value in item["options"].items():
|
||||
hit = head.match(key)
|
||||
if hit:
|
||||
found.setdefault(int(hit.group(1)), {})[hit.group(2)] = value
|
||||
for n in sorted(found):
|
||||
gid = f"{link}{n}"
|
||||
rows.append(
|
||||
{
|
||||
**item,
|
||||
"options": {**item["options"], **_as_options(found[n])},
|
||||
"summary_item": links.get(gid),
|
||||
"복사본": f"{item['복사본']}{GROUP_JOIN}{gid}",
|
||||
"그룹": f"{title} {n}",
|
||||
}
|
||||
)
|
||||
return rows
|
||||
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""배관 남은 연동 — PLAN 52-1b.
|
||||
|
||||
못박는 것
|
||||
- 집계표: 선택 컨테이너(흙막이 추가 · 도수로/돌붙임)마다 한 건 — 잇기 `{link}{n}` 항목 ·
|
||||
그 컨테이너 값.
|
||||
- 짝: 서버 컨테이너 표(머리 · 잇기) = 배관 명세 TS.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
from M02_MasterTemplete import M02_Table_Fill as fill
|
||||
from M02_MasterTemplete.M02_Table_Fill_Spec import SPEC_CONTAINERS, container_rows
|
||||
from resources.tester.test_structures_summary_snapshot import ( # noqa: F401 — world 고정물
|
||||
MS,
|
||||
PIPE,
|
||||
RV,
|
||||
_pipe,
|
||||
_save,
|
||||
world,
|
||||
)
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
ROOT = os.path.dirname(os.path.dirname(HERE))
|
||||
SOIL = {
|
||||
"soil_add_1_structure": "기슭막이",
|
||||
"soil_add_1_form": "바자",
|
||||
"soil_add_1_length": 6,
|
||||
"soil_add_1_height": 2,
|
||||
"soil_add_2_structure": "기슭막이",
|
||||
"chute_add_1_structure": "돌붙임",
|
||||
}
|
||||
|
||||
|
||||
def test_컨테이너마다_한_건_잇기와_그_값():
|
||||
item = {"type_id": "pipe", "options": {"pipe_diameter_mm": 1000, **SOIL}, "복사본": "pipe@40.0"}
|
||||
rows = container_rows(item, {"gsoiladd1": RV, "gchuteadd1": MS})
|
||||
assert [r["그룹"] for r in rows] == ["흙막이 추가 1", "흙막이 추가 2", "도수로/돌붙임 1"]
|
||||
assert [r["복사본"] for r in rows] == [
|
||||
"pipe@40.0__gsoiladd1",
|
||||
"pipe@40.0__gsoiladd2",
|
||||
"pipe@40.0__gchuteadd1",
|
||||
]
|
||||
assert [r["summary_item"] for r in rows] == [RV, None, MS]
|
||||
first = rows[0]["options"]
|
||||
assert first["length_m"] == first["inlet_revet_length_m"] == first["outlet_revet_length_m"] == 6
|
||||
assert (
|
||||
first["form"] == first["outlet_revet_form"] == "바자" and first["outlet_type"] == "기슭막이"
|
||||
)
|
||||
assert first["pipe_diameter_mm"] == 1000 # 구조물 옵션은 그대로
|
||||
assert container_rows({"type_id": "masonry_dry", "options": SOIL, "복사본": "st0"}, {}) == []
|
||||
# 옛 값 — 컨테이너 없는 옛 관 · 인스턴스 없는 잇기는 줄 없음
|
||||
old = {"type_id": "pipe", "options": {"inlet_revet_length_m": 5}, "복사본": "pipe@9.0"}
|
||||
assert container_rows(old, {"gsoiladd9": RV}) == []
|
||||
|
||||
|
||||
def test_집계표_채움에_컨테이너_줄(world):
|
||||
"""흙막이 추가 1 → 돌기슭막이 열(rv) 6 m · 관 본체 · 미지정 컨테이너는 표에 안 듦."""
|
||||
root, system = world["root"], world["system"]
|
||||
point = {**_pipe(PIPE), "group_items": {"gsoiladd1": RV}}
|
||||
point["options"] = {**point["options"], **SOIL}
|
||||
_save(root, [], [point])
|
||||
table = json.loads((system / "table/구조물집계표.json").read_text("utf-8"))
|
||||
doc = fill.fill_table(root, table)
|
||||
values = [row["값"] for row in doc["줄"] if not row.get("고정")]
|
||||
rv = [v for row in values for k, v in row.items() if k.split("|")[0] == "rv"]
|
||||
assert rv == [6]
|
||||
copies = [i["복사본"] for i in fill.collect_items(root)]
|
||||
assert "pipe@40.0__gsoiladd1" in copies and "pipe@40.0__gchuteadd1" in copies
|
||||
|
||||
|
||||
def test_서버_컨테이너_표는_배관_명세와_짝():
|
||||
with open(
|
||||
os.path.join(ROOT, "A00_Common/design/design_structure_pipe.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["pipe"])
|
||||
@@ -9,6 +9,8 @@
|
||||
* 기대 수치(edit): kinds 5 · required 3 늘 보임 · formBasin I형/L형/ㄷ형 · formSoil 6 · split 길이 7 ·
|
||||
* soilAdd 둘 → 하나 빼면 하나(콘크리트) · chute 하나(돌붙임) · 잇기 유입 지정 · 유출 지정 뒤 풂
|
||||
* 기대 수치(verify): 저장 값 그대로 · 같은 그리기(B05 = B06) · 관 길이 수(B06)
|
||||
* 52-1b: edit 가 흙막이 추가 · 도수로/돌붙임 컨테이너도 이음 → verify 집계표 줄 = 처음 + 3
|
||||
* (유입 잇기 1 · 컨테이너마다 1)
|
||||
*/
|
||||
(async () => {
|
||||
const MODE = window.__m521 || "edit";
|
||||
@@ -28,6 +30,15 @@
|
||||
.filter((n) => n.includes(part))
|
||||
.pop();
|
||||
const fetchApi = await import(modUrl("/B04_PreProcess/B04_PreProcess_Api_Fetch.ts"));
|
||||
const m02Api = await import(
|
||||
modUrl("/B04_PreProcess/B04_PreProcess_Api_Fetch.ts").replace(
|
||||
/B04_PreProcess\/B04_PreProcess_Api_Fetch\.ts.*$/,
|
||||
"M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts",
|
||||
)
|
||||
);
|
||||
/** 구조물집계표 채움 줄 수(전구간 고정 줄 뺌) — 52-1b. */
|
||||
const filledRows = async () =>
|
||||
(await m02Api.readFilled(projectId, "구조물집계표")).문서.줄.filter((r) => !r.고정).length;
|
||||
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) =>
|
||||
@@ -86,6 +97,8 @@
|
||||
if (MODE === "edit") {
|
||||
const before = await fetchApi.fetchDetailPipePoints(projectId);
|
||||
sessionStorage.setItem("__521_original", JSON.stringify(before.pipe_points));
|
||||
out.baseRows = await filledRows();
|
||||
sessionStorage.setItem("__521_baseRows", String(out.baseRows));
|
||||
await pickPipe();
|
||||
const s0 = shape();
|
||||
out.kinds =
|
||||
@@ -128,6 +141,10 @@
|
||||
await w(200);
|
||||
await set("chute_add", "structure", "돌붙임");
|
||||
out.chuteChoices = labels("chute_add", "structure");
|
||||
// 52-1b — 컨테이너마다 구조물 조합 잇기(집계표 한 줄씩)
|
||||
await pickLink("soil_add");
|
||||
await pickLink("chute_add");
|
||||
out.linkContainers = [linkName("soil_add"), linkName("chute_add")];
|
||||
// 구조물 조합 잇기 — 유입 지정 · 유출 지정 뒤 풂
|
||||
await pickLink("inlet");
|
||||
out.linkInlet = linkName("inlet");
|
||||
@@ -169,6 +186,8 @@
|
||||
out.sameDrawing = JSON.stringify(b05) === JSON.stringify(b06);
|
||||
if (!out.sameDrawing) out.diff = { b05, b06 };
|
||||
out.b06Length = ctl("pipe", "length").value;
|
||||
out.baseRows = Number(sessionStorage.getItem("__521_baseRows"));
|
||||
out.rows = await filledRows();
|
||||
}
|
||||
|
||||
if (MODE === "restore") {
|
||||
@@ -191,7 +210,7 @@
|
||||
);
|
||||
await fetchApi.saveDetailPipePoints(projectId, points);
|
||||
for (const k of Object.keys(sessionStorage))
|
||||
if (k.startsWith("aislo:draft:pipes:") || k === "__521_original")
|
||||
if (k.startsWith("aislo:draft:pipes:") || k.startsWith("__521_"))
|
||||
sessionStorage.removeItem(k);
|
||||
const now = await fetchApi.fetchDetailPipePoints(projectId);
|
||||
const pick = (list) =>
|
||||
|
||||
Reference in New Issue
Block a user