Files
Aislo/B06_Section/B06_Section_UI_Cross_FillSlope_Notice.ts
T
eomsangdonandClaude Opus 5.5 702f3e68d9 fix(B06): 포장 단추 지움 · 포장 = 노면공 범위만 · 포장 권장 알림 줄(138-1)
- 서버 paved_at 저장값 인자 지움 · enforce_pavement_ranges 켬↔끔 양쪽 · 단건 계산도 범위 규칙
- 브라우저 재계산 pavedBySpecs(같은 규칙) · CARRY_INPUT_KEYS 에서 paved 뺌
- 카드 「⚠ 포장 권장」 배지 → 알림 줄 「⚠ 포장 권장 · n측점」 · 로케일 정리

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
2026-10-09 14:47:39 +09:00

96 lines
3.9 KiB
TypeScript

/* =============================================================================
* B06_Section_UI_Cross_FillSlope_Notice.ts
* 성토사면 5m 초과 **경고 줄** — 횡단 카드 목록 위 요약 한 줄 + 펼치면 측점 목록
* (2026-09-14 브레인 승인 (나)). 판정은 `_Cross_FillSlope_Warn`, 여기는 그리기만.
* 측점을 누르면 그 카드로 간다. 경고만 — 구조물을 세우거나 값을 바꾸지 않는다.
* ⭐ 2026-09-15 — 그 밑에 사면길이 3m 초과 **소단 검토 정보 한 줄**(경고 모양 아님 · 브레인 ③).
* ⭐ 138-1 — 「⚠ 포장 권장 · n측점」 줄(B05 법정 경사 제안 · 포장 범위 밖 측점 · 옛 카드 배지 자리).
* ========================================================================== */
import type { CrossSection } from "./B06_Section_Api_Fetch";
import { BERM_INFO_TEXT, bermReviewStations } from "./B06_Section_UI_Cross_Berm_Info";
import { fillSlopeLengths, slopeRunLengths } from "./B06_Section_UI_Cross_Fit";
import {
FILL_SLOPE_WARN_TEXT,
fillSlopeWarnings,
type FillSlopeWarning,
} from "./B06_Section_UI_Cross_FillSlope_Warn";
import { L, stationLabel } from "./B06_Section_UI_Section_Common";
import { pavedBySpecs } from "./B06_Section_Cross_Refresh";
export interface FillSlopeNotice {
root: HTMLElement;
/** 측점 설계가 바뀔 때마다 부른다 — 펼침 상태는 그대로 둔다. */
update: (sections: ReadonlyArray<CrossSection>, stationInterval: number) => void;
}
function noticeBlock(className: string): {
root: HTMLDetailsElement;
fill: (head: string, rows: FillSlopeWarning[], stationInterval: number) => void;
} {
const root = document.createElement("details");
root.className = className;
root.hidden = true;
const summary = document.createElement("summary");
const list = document.createElement("div");
list.className = "b06-section__notice-list";
root.append(summary, list);
return {
root,
fill(head, rows, stationInterval) {
root.hidden = !rows.length;
summary.textContent = `${head} · ${rows.length}측점`;
list.replaceChildren(
...rows.map(({ section, sides }) => {
const button = document.createElement("button");
button.type = "button";
const parts = sides.map(({ side, lengthM, open }) => {
const label = L(side === "left" ? "B06_Design_Ditch_Left" : "B06_Design_Ditch_Right");
return `${label} ${open ? "≥" : ""}${lengthM.toFixed(2)}m`;
});
button.textContent =
`${stationLabel(section.chainage_m, stationInterval)} ${parts.join(" · ")}`.trim();
button.dataset.stationId = section.station_id;
return button;
}),
);
},
};
}
export function createFillSlopeNotice(onPick: (stationId: string) => void): FillSlopeNotice {
const root = document.createElement("div");
const warn = noticeBlock("b06-section__notice");
const info = noticeBlock("b06-section__notice b06-section__notice--info");
const pave = noticeBlock("b06-section__notice");
pave.root.title = L("B06_Design_Paved_Suggested");
root.append(warn.root, pave.root, info.root);
root.addEventListener("click", (event) => {
const id = (event.target as HTMLElement).closest("button")?.dataset.stationId;
if (id) onPick(id);
});
return {
root,
update(sections, stationInterval) {
warn.fill(
`⚠ ${FILL_SLOPE_WARN_TEXT}`,
fillSlopeWarnings(sections, fillSlopeLengths),
stationInterval,
);
pave.fill(
`⚠ ${L("B06_Notice_PaveSuggested")}`,
sections
.filter((section) => section.design?.pavement_suggested && !pavedBySpecs(section))
.map((section) => ({ section, sides: [] })),
stationInterval,
);
info.fill(
`ⓘ ${BERM_INFO_TEXT}`,
bermReviewStations(sections, slopeRunLengths),
stationInterval,
);
},
};
}