feat(377-2 B07 전개도): 좌측 「전개도」 카드 · 목록 · 단건 · 확정본 kind — 늘 카드 · 구조물 종류마다 하위 묶음(이름 줄 + 형태 단추) · 목록 맨 뒤 · 전개도 id 면 측점별 설계 실어 그림
- Router_Support _drawing_list 맨 뒤 development_list · _read_drawing 분기 · 확정본 kind development - Router 단건 = _designs_by_chainage · Schema · Api_Fetch kind development - UI_Development.ts 새 카드(groupPlanSheets 재사용) · test_311 접힘 대조에 전개도 카드(기본 펼침) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
This commit is contained in:
@@ -16,6 +16,7 @@ export interface DesignDrawingItem {
|
||||
| "landuse"
|
||||
| "plan_lidar"
|
||||
| "cross_standard"
|
||||
| "development"
|
||||
| "blank";
|
||||
label: string;
|
||||
chainage_m: number | null;
|
||||
@@ -112,6 +113,7 @@ export interface DesignDrawingResponse {
|
||||
| "landuse"
|
||||
| "plan_lidar"
|
||||
| "cross_standard"
|
||||
| "development"
|
||||
| "blank";
|
||||
label: string;
|
||||
drawing: CadDrawing;
|
||||
|
||||
@@ -252,7 +252,7 @@ def development_sheets(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
{
|
||||
"id": kind_id if index == 1 else f"{kind_id}_{index}",
|
||||
"kind_id": kind_id,
|
||||
"title": title,
|
||||
"title": title if index == 1 else f"{title} ({index})",
|
||||
"group": group,
|
||||
"form": form,
|
||||
"rows": chunk,
|
||||
@@ -290,15 +290,15 @@ def _read_json(path: Path) -> dict[str, Any]:
|
||||
def development_list(
|
||||
project_root: Path, manifest_drawings: dict[str, Any]
|
||||
) -> list[DesignDrawingItem]:
|
||||
"""좌측 「전개도」 카드 단추 — 장마다 한 줄(plan_kind = 묶음 · 형태 · 하위 묶음)."""
|
||||
"""좌측 「전개도」 카드 단추 — 장마다 한 줄 · 하위 묶음(plan_kind) = 구조물 종류."""
|
||||
return [
|
||||
DesignDrawingItem(
|
||||
id=sheet["id"],
|
||||
kind="development",
|
||||
label=sheet["title"],
|
||||
confirmed=bool(manifest_drawings.get(sheet["id"], {}).get("confirmed")),
|
||||
plan_kind=sheet["kind_id"],
|
||||
plan_kind_name=sheet["title"],
|
||||
plan_kind=f"development_{sheet['group']}",
|
||||
plan_kind_name=GROUPS[sheet["group"]],
|
||||
)
|
||||
for sheet in development_sheets(development_rows(project_root))
|
||||
]
|
||||
|
||||
@@ -27,6 +27,7 @@ from B06_Section.B06_Section_Repository import (
|
||||
get_project_standard_cross_section,
|
||||
merge_cross_section_design_by_round,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Development import DEVELOPMENT_ID
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
|
||||
CROSS_SHEET_ID,
|
||||
)
|
||||
@@ -341,6 +342,9 @@ async def get_design_drawing(
|
||||
if row
|
||||
else None
|
||||
)
|
||||
elif DEVELOPMENT_ID.fullmatch(drawing_id):
|
||||
# 전개도 — 추가 흙막이 단 수 · 포장 빈 폭을 측점별 설계에서 읽음(377)
|
||||
source_design = await _designs_by_chainage(route_id)
|
||||
elif PLAN_KIND_ID.fullmatch(drawing_id):
|
||||
# 계획평면도 — 정보 조각을 서버가 계산 · 파일로 두고 그 종류가 고른 것만 얹는다.
|
||||
context, reason = await load_drainage_context(project_id)
|
||||
|
||||
@@ -34,6 +34,11 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad_CulvertNote import (
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_CulvertNote import (
|
||||
station_no_label as station_no_label_upper,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Development import (
|
||||
DEVELOPMENT_ID,
|
||||
development_list,
|
||||
read_development,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Long import (
|
||||
build_longitudinal_drawing,
|
||||
longitudinal_chunks,
|
||||
@@ -243,6 +248,8 @@ def _drawing_list(project_root: Path, longitudinal_path: Path) -> list[DesignDra
|
||||
)
|
||||
)
|
||||
# 표준도(구조물도)는 2026-09-13 B08 「구조물도」 탭으로 이관 — 사용자 확정 ③, PLAN 3장 ④.
|
||||
# 전개도(요구 241 · 377) — 맨 뒤 · (구조물 종류 · 형태)마다 장
|
||||
drawings += development_list(project_root, manifest_drawings)
|
||||
_store_drawing_numbers(project_root, drawings)
|
||||
return drawings
|
||||
|
||||
@@ -480,6 +487,8 @@ def _read_drawing(
|
||||
kind = drawing_id # id와 kind가 같은 단장 도면
|
||||
elif PLAN_KIND_ID.fullmatch(drawing_id):
|
||||
kind = "plan"
|
||||
elif DEVELOPMENT_ID.fullmatch(drawing_id):
|
||||
kind = "development"
|
||||
else:
|
||||
kind = "longitudinal" if _LONG_ID.fullmatch(drawing_id) else "cross"
|
||||
label = str(manifest_entry.get("label") or drawing_id)
|
||||
@@ -531,6 +540,10 @@ def _read_drawing(
|
||||
None,
|
||||
)
|
||||
|
||||
if DEVELOPMENT_ID.fullmatch(drawing_id):
|
||||
# stored_design = 노선 전체 측점별 설계(추가 흙막이 단 수 · 포장 빈 폭)
|
||||
return read_development(project_root, longitudinal_path, drawing_id, stored_design)
|
||||
|
||||
if PLAN_KIND_ID.fullmatch(drawing_id):
|
||||
# stored_design = plan_kind_source()가 계산 · 저장한 조각 중 그 종류가 고른 것.
|
||||
if not isinstance(stored_design, dict):
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/* =============================================================================
|
||||
* B07_DesignDetail_UI_Development.ts
|
||||
* 좌측 「전개도」 카드(요구 241 · PLAN 377) — 늘 카드 · 구조물 종류마다 하위 묶음(이름 줄 + 형태 단추).
|
||||
*
|
||||
* 묶음 = `groupPlanSheets`(plan_kind = 구조물 종류 · plan_kind_name = 이름) 재사용 · 모양 = 평면도 묶음 class.
|
||||
* 단추 글 = 장 이름에서 종류 이름 · 「전개도」를 뺀 형태(전체 이름은 툴팁).
|
||||
* ========================================================================== */
|
||||
|
||||
import { createPanelCard } from "@ui/ui_template_collapsible";
|
||||
import type { DesignDrawingItem } from "./B07_DesignDetail_Api_Fetch";
|
||||
import { groupPlanSheets } from "./B07_DesignDetail_UI_PlanKinds";
|
||||
|
||||
/** 「관보호공 돌쌓기(찰) 전개도 (2)」 → 「돌쌓기(찰) (2)」 · 포장 「콘크리트포장 전개도」 → 「콘크리트포장」. */
|
||||
function shortLabel(label: string, kindName: string): string {
|
||||
const rest = label.replace(" 전개도", "");
|
||||
return rest.startsWith(`${kindName} `) ? rest.slice(kindName.length + 1) : rest;
|
||||
}
|
||||
|
||||
export function buildDevelopmentSection(
|
||||
items: DesignDrawingItem[],
|
||||
makeButton: (drawing: DesignDrawingItem, label: string) => HTMLButtonElement,
|
||||
collapsed = false,
|
||||
): HTMLElement {
|
||||
const section = createPanelCard(`전개도 ${items.length}`, collapsed);
|
||||
section.classList.add("b07-drawing-group");
|
||||
section.dataset.kind = "development";
|
||||
if (items.length === 0) {
|
||||
const empty = document.createElement("span");
|
||||
empty.className = "b07-plan-kind__name";
|
||||
empty.textContent = "종단 길이를 가진 구조물이 없습니다.";
|
||||
section.append(empty);
|
||||
return section;
|
||||
}
|
||||
for (const { kindId, name, sheets } of groupPlanSheets(items)) {
|
||||
const block = document.createElement("div");
|
||||
block.className = "b07-plan-kind";
|
||||
block.dataset.planKind = kindId;
|
||||
const title = document.createElement("span");
|
||||
title.className = "b07-plan-kind__name";
|
||||
title.textContent = name;
|
||||
block.append(title);
|
||||
for (const { drawing } of sheets) {
|
||||
const button = makeButton(drawing, shortLabel(drawing.label, name));
|
||||
button.title = drawing.label;
|
||||
block.append(button);
|
||||
}
|
||||
section.append(block);
|
||||
}
|
||||
return section;
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { attachCollapsible, createPanelCard } from "@ui/ui_template_collapsible"
|
||||
import { createButton, createInputField, showToast } from "@ui/ui_template_elements";
|
||||
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
|
||||
import type { CrossDesignInfo, DesignDrawingItem } from "./B07_DesignDetail_Api_Fetch";
|
||||
import { buildDevelopmentSection } from "./B07_DesignDetail_UI_Development";
|
||||
import { buildPlanSection } from "./B07_DesignDetail_UI_PlanKinds";
|
||||
import { openPlanManager, type PlanManageControls } from "./B07_DesignDetail_UI_PlanManage";
|
||||
|
||||
@@ -37,6 +38,8 @@ export const DRAWING_GROUPS: readonly {
|
||||
// 표준 횡단면도는 횡단도 묶음 맨 위 한 줄(93-5).
|
||||
{ label: "횡단도", kind: "cross" },
|
||||
{ label: "토적도(유토곡선)", kind: "mass_haul" },
|
||||
// 전개도(요구 241 · 377) — 늘 카드 · 구조물 종류마다 하위 묶음
|
||||
{ label: "전개도", kind: "development" },
|
||||
];
|
||||
|
||||
/** 311 기본 접힘 묶음 — 그 밖 묶음(토적도 등)은 기본 펼침. */
|
||||
@@ -120,6 +123,11 @@ export function buildDrawingSidePanel(
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (group.kind === "development") {
|
||||
const sheets = drawings.filter((item) => item.kind === "development");
|
||||
panel.append(buildDevelopmentSection(sheets, drawingButton, isFolded("development")));
|
||||
continue;
|
||||
}
|
||||
const items = group.kind
|
||||
? drawings.filter((item) => item.kind === group.kind)
|
||||
: group.idPrefix
|
||||
|
||||
@@ -207,7 +207,8 @@ def test_설계_없으면_단수_안_거름_목록(root):
|
||||
assert sheet["missing"] == 1 and len(sheet["rows"]) == 2
|
||||
items = dev.development_list(root, {})
|
||||
assert {i.kind for i in items} == {"development"}
|
||||
assert items[0].plan_kind == "development_pipe0"
|
||||
assert (items[0].plan_kind, items[0].plan_kind_name) == ("development_pipe", "관보호공")
|
||||
assert items[0].label == "관보호공 돌쌓기(찰) 전개도"
|
||||
|
||||
|
||||
def test_넘치면_2장():
|
||||
@@ -215,6 +216,7 @@ def test_넘치면_2장():
|
||||
sheets = dev.development_sheets(rows)
|
||||
assert [s["id"] for s in sheets] == ["development_soil3", "development_soil3_2"]
|
||||
assert [len(s["rows"]) for s in sheets] == [30, 5]
|
||||
assert sheets[1]["title"] == "흙막이 돌망태 전개도 (2)"
|
||||
|
||||
|
||||
def test_높이_빈칸_박스와_미입력_글_무늬_DXF(root):
|
||||
|
||||
@@ -64,6 +64,7 @@ def test_B07_첫_그림_접힘(out):
|
||||
"longitudinal": True,
|
||||
"cross": True,
|
||||
"mass_haul": False,
|
||||
"development": False, # 377 전개도 카드 — 기본 펼침
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +74,7 @@ def test_B07_다시_세워도_접힘_이어_받음(out):
|
||||
"longitudinal": True,
|
||||
"cross": False,
|
||||
"mass_haul": True,
|
||||
"development": False,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user