Files
Aislo/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts
T
eomsangdonandClaude Opus 5 cc428d7e12 revert(B06): 절토 경사 법정 검사 폐기 — 암질을 횡단도에서 고르지 않음
사용자 확정(2026-09-07): 「연암과 경암 / 발파암과 리핑암 선택은 횡단도에서 선택 안함.
사유는 향후 설계내역에서 설계자가 직접 비율로 지정하기로 함. 암반 지정과 범위 애매모호한
경우가 있어. 실무자는 그렇게 하기로 판단함. 대신 경고부분은 삭제해주고 대신 각도를
사용자가 넣을수 있게 반영.」

**왜 폐기인가** — 판정이 서려면 측점마다 암질(연암·경암)을 못 박아야 하는데, 실무에서
암반 지정·범위가 애매해 그 못 박음 자체가 틀린 전제였음. 암 비율은 **설계내역 단계에서
설계자가 비율로** 넣음. 기준이 없으니 경고도 없음.

되돌린 것 — 1e596846(암질 선택) + 973128f7(별표2 경고). 카드 경고 배지 · 판정 모듈 ·
config 범위표 · context 필드 · 표준 패널 암질 칸 전부 사라짐.

⚠ **남긴 것** — `cut_slope_segments`(구간별 경사)는 지우지 않음. 소단 기하가 그 위에
서 있고 구간 경사를 아는 값이라 뒤에 쓸 자리가 있음. 4e7a4bf7(사면 구간 재료를 그린
경사비로 가름 — 무릎 위 라벨 13구간 오류 수정)도 남김. 검사와 무관하게 옳은 고침임.

시험 4건 — 되살아나지 않게 막는 쪽으로 다시 씀(판정 모듈 없음 · 카드 경고 없음 ·
암질 고르는 자리 없음 · **구간별 경사값은 남아 있음**).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 16:56:26 +09:00

143 lines
6.4 KiB
TypeScript

/* =============================================================================
* B06_Section_UI_Cross_Card_Chrome.ts
* 횡단 카드의 **껍데기**(제목행·하단 정보행)만 떼어 낸 조립기 (2026-09-03 · 700줄 제한).
*
* 카드 본체(`_UI_Cross_View`)는 SVG 도면과 조작을 맡고, 도면과 무관한 머리·꼬리는 여기서
* 만든다. 여기 있는 것은 전부 **읽어서 붙이는 값**이라 카드 상태(줌·선택)를 건드리지 않는다.
* ========================================================================== */
import type { CrossSection } from "./B06_Section_Api_Fetch";
import type { RockBoundaryControl } from "./B06_Section_UI_Cross_Design";
import {
buildDesignControls,
buildRockBoundaryControl,
sectionModeLabel,
} from "./B06_Section_UI_Cross_Design";
import { type FillSlopeLength, fillSlopeLengths } from "./B06_Section_UI_Cross_Fit";
import {
type DesignChangeHandler,
L,
stationLabel,
structureDisplayName,
} from "./B06_Section_UI_Section_Common";
/**
* 성토사면 경사길이 표기 칸 — 성토측이 없으면 null.
*
* 값은 **구조물이 끊기 전 본래 사면**(정본 설계선 기준)이라, 기슭막이·집수정이 선 측점도
* 표준 횡단의 사면 길이를 그대로 보여 준다(2026-09-03 사용자 지시).
*/
function fillSlopeInfo(section: CrossSection): HTMLElement | null {
const lengths = fillSlopeLengths(section);
const sides = (["left", "right"] as const).filter((side) => lengths[side] !== null);
if (!sides.length) return null;
const both = sides.length > 1;
const info = document.createElement("span");
info.className = "b06-cross-card__fillslope";
info.textContent = `${L("B06_Cross_FillSlope")} ${sides
.map((side) => {
const length = lengths[side] as FillSlopeLength;
// 계산 반폭 안에서 원지반을 못 만난 사면은 거기까지만 잰 하한값이라 「≥」로 구분한다.
const value = `${length.open ? "≥" : ""}${length.lengthM.toFixed(2)}m`;
if (!both) return value;
const label = L(side === "left" ? "B06_Design_Ditch_Left" : "B06_Design_Ditch_Right");
return `${label} ${value}`;
})
.join(" · ")}`;
info.title = L("B06_Cross_FillSlope_Tip");
return info;
}
/**
* 카드 제목행을 만들어 카드에 붙인다(설계 조작이 있으면 조작 바까지).
*
* 1행 구조(E-2/E-3): 측점 위치표기 → 지반유형 → 단면유형 pill → 구조물 → 측점정보.
*/
export function appendCardHeader(
card: HTMLElement,
section: CrossSection,
stationInterval: number,
onDesignChange?: DesignChangeHandler,
): void {
const header = document.createElement("header");
const title = document.createElement("div");
title.className = "b06-cross-card__title";
const label = document.createElement("strong");
label.textContent = stationLabel(section.chainage_m, stationInterval);
const chainage = document.createElement("span");
chainage.textContent = `${section.chainage_m.toFixed(1)}m`;
title.append(label, chainage);
// 단면유형 pill(자동 판정, 읽기 전용) — 구조물 pill과 동일 표기, 좌측 배치(E-3).
const modePill = document.createElement("span");
modePill.className = "b06-cross-card__mode";
modePill.textContent = sectionModeLabel(section.design?.section_mode);
modePill.title = L("B06_Design_Mode_Legend");
const meta = document.createElement("div");
meta.className = "b06-cross-card__meta";
// 사면이 계산 반폭 끝까지 원지반을 못 만난 측점 — 면적이 거기서 잘려 유토곡선까지
// 그 값을 쌓는다. 계산은 손대지 않고 사실만 알린다(2026-09-03 사용자 확정).
if (section.design?.slope_unclosed) {
const openSlope = document.createElement("span");
openSlope.className = "b06-cross-card__warning";
openSlope.textContent = `⚠ ${L("B06_Cross_SlopeUnclosed")}`;
openSlope.title = L("B06_Cross_SlopeUnclosed_Tip");
meta.append(openSlope);
}
const structureName = section.structure;
if (structureName) {
const structure = document.createElement("span");
structure.className = "b06-cross-card__structure";
// 배수관은 관종·관경(`파형강관 D1200`)이 아니라 표시 이름 하나로 적는다
// (2026-09-03 사용자 지시). 관종·관경은 툴팁에 남긴다.
structure.textContent = structureDisplayName(structureName);
structure.title = `구조물: ${structureName}`;
meta.append(structure);
}
// 측점 종류는 시·종점(BP/EP)만 적는다 — "일반측점"은 대다수라 정보가 없다(2026-08-02 사용자 지시).
if (section.kind === "bp" || section.kind === "ep") {
const kind = document.createElement("span");
kind.textContent = L(
section.kind === "ep" ? "B06_Profile_View_Kind_EP" : "B06_Profile_View_Kind_BP",
);
meta.append(kind);
}
// 성토사면 경사길이는 **행 우측 끝**(2026-09-03 사용자 지시) — meta 가 제목행의 오른쪽
// 끝이므로 그 마지막 칸에 붙인다.
const fillSlope = fillSlopeInfo(section);
if (fillSlope) meta.append(fillSlope);
// 단면유형 pill은 지반유형 우측·우측 맞춤으로 배치(1번). 좌측 구분선은 지반유형 세그먼트에 준다(3번).
modePill.classList.add("b06-cross-card__mode--right");
header.append(title);
if (onDesignChange) {
const controls = buildDesignControls(section, onDesignChange);
controls.groundSegment.classList.add("b06-cross-card__ground");
header.append(controls.groundSegment, modePill, meta);
card.append(header, controls.bar);
return;
}
header.append(modePill, meta);
card.append(header);
}
/** 하단 정보행 — 중심고와 (암 지반일 때) 암 경계선 제어. */
export function appendCardFooter(
card: HTMLElement,
section: CrossSection,
rockBoundary?: RockBoundaryControl,
): void {
const footer = document.createElement("footer");
const center = document.createElement("span");
center.textContent = `${L("B06_Profile_View_CenterElevation")} ${section.center_z?.toFixed(2) ?? "-"}m`;
footer.append(center);
// 암 경계선 제어는 하단 정보 행 가운데(2026-08-02) — 암 지반만.
if (rockBoundary && section.design?.geometry_preset === "rock") {
const rockControl = buildRockBoundaryControl(section, rockBoundary);
rockControl.classList.add("b06-cross-card__rockb");
footer.append(rockControl);
}
card.append(footer);
}