Files
Aislo/B08_Quantity/B08_Quantity_UI_Earthwork.ts
T
eomsangdonandClaude Opus 5.5 5e25f418cc refactor(b08): 탭 표 자료 읽기 · 표 짜기를 화면 없는 파일로 꺼냄 — 구조물 집계표 · 자재 · 토공 · 수리 입력 · 거리이정표 · 화면은 같은 함수를 씀 · 동작 그대로 (302-3)
- 새 파일 = B08_Quantity_Summary_Table · Material_Tables · Earthwork_Tables · Hydro_Table · Milestone_Table
- 화면 UI 파일 = 불러오기 · 그리기만 · 옛 B08 시험 = 옮긴 글 자리 따라 읽는 파일 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
2026-10-13 08:03:23 +09:00

113 lines
4.7 KiB
TypeScript

/* =============================================================================
* B08_Quantity_UI_Earthwork.ts
* 토공 탭(PLAN 61-3 · 69-2 · 69-3) — 보조 탭 넷 = 토공집계표 · 토적표 · 평균운반거리 · 종방향 무대운반거리.
*
* GET …/quantity/earthwork 한 번(서버 단독 · 읽기만) — 네 장이 같은 응답을 나눠 그림.
* 토적표 = 줄 측점 · 칸 = 사용자 견본(절토 토사 · 연암 · 측구파기 토사 · 암 각 단면적 · 입적 ·
* 보정량 · 보정량계 · 성토 · 유용토 · 차인토량 · 누가토량 · 면고르기 · 지장목제거 · 제근 · 노면정리 각
* 거리 · 면적) · 맨 아래 합계 줄. 첫 측점은 앞이 없어 입적 · 면적이 빈 값(—).
* 표 = 공용 많은 자료 표(`ui_template_data_table` · PLAN 70) · 카드 안 · 나머지 셋은 `…_Earthwork_Sheets`.
* 절토 연암 · 경암 = 암 × 좌측 패널 비율 · 암 C = 비율 가중 — 조작 중 같은 식으로 바로 다시 셈
* (`…_Options_Calc` · PLAN 122 · 125-1).
* 자료 읽기 · 표 짜기 = `B08_Quantity_Earthwork_Tables`(화면 없음 · 인쇄 미리보기도 씀 · 302-3)
* ========================================================================== */
import { createButton, createCard } from "@ui/ui_template_elements";
import { createDataTable } from "@ui/ui_template_data_table";
import { footNote } from "./B08_Quantity_UI_Foot";
import {
EARTHWORK_SHEETS,
earthworkSheetOptions,
loadEarthwork,
type EarthworkTable,
} from "./B08_Quantity_Earthwork_Tables";
import {
renderEarthworkSummary,
renderFreeHaul,
renderHaulDistance,
} from "./B08_Quantity_UI_Earthwork_Sheets";
import { onOptionsChange } from "./B08_Quantity_UI_Options";
export function note(text: string): HTMLElement {
const p = document.createElement("p");
p.className = "ui-general-block__empty";
p.textContent = text;
return p;
}
/** 표 한 장 — 공용 컨테이너(카드) 안에 공용 표 · 아래 줄 · 맨 아래 안내 · 경고 줄(202-1) */
export function tableCard(
info: HTMLElement[],
table: HTMLElement,
after: HTMLElement[] = [],
): HTMLElement {
return createCard({ body: [table, ...after, ...info] });
}
function renderSheet(host: HTMLElement, table: EarthworkTable, interval: number): void {
if (!table.rows.length) {
host.replaceChildren(note("측점 단면적이 아직 없습니다 — 횡단 설계를 먼저 마치세요."));
return;
}
const flagged = table.rows.filter((row) => row.notes.length);
const info = [
footNote(
`노선 ${table.route_id}${table.confirmed ? "(확정)" : "(확정 전 최신 노선)"} · ` +
`측점 ${table.station_count} · 단위 m · ㎡ · ㎥`,
),
...(flagged.length ? [footNote(`* ${flagged[0].notes[0]} — ${flagged.length}곳`)] : []),
];
const grid = createDataTable({ ...earthworkSheetOptions(table, interval), fillViewport: true });
grid.root.dataset.b08Earthwork = "table";
host.replaceChildren(tableCard(info, grid.root));
}
const SHEETS = EARTHWORK_SHEETS;
type SheetId = (typeof SHEETS)[number]["id"];
export async function renderEarthwork(host: HTMLElement, projectId: string): Promise<void> {
host.replaceChildren(note("토공 수량을 만드는 중…"));
let loaded: Awaited<ReturnType<typeof loadEarthwork>>;
try {
loaded = await loadEarthwork(projectId);
} catch (error) {
host.replaceChildren(note(`토공 수량을 불러오지 못했습니다 — ${String(error)}`));
return;
}
const { table, interval, applyRock } = loaded;
const tabs = document.createElement("div");
tabs.className = "b08-quantity__tabs ui-subtabs b08-earthwork__tabs";
tabs.setAttribute("role", "tablist");
const view = document.createElement("div");
let current: SheetId = "summary";
const select = (picked: SheetId): void => {
current = picked;
tabs.replaceChildren(
...SHEETS.map(({ id, label }) => {
const button = createButton({
label,
variant: id === picked ? "filled" : "ghost",
size: "sm",
onClick: () => id !== picked && select(id),
});
button.setAttribute("role", "tab");
button.setAttribute("aria-selected", String(id === picked));
button.dataset.b08EarthworkSheet = id;
return button;
}),
);
if (picked === "sheet") renderSheet(view, table, interval);
else if (picked === "summary") renderEarthworkSummary(view, table);
else if (picked === "haul") renderHaulDistance(view, table);
else renderFreeHaul(view, table);
};
host.replaceChildren(tabs, view);
select("summary");
onOptionsChange(host, () => {
applyRock();
select(current);
});
}