Files
Aislo/B08_Quantity/B08_Quantity_UI_Earthwork_Sheets.ts
T
eomsangdonandClaude Opus 5.5 e857819d2e feat(B08): 토공 탭 — 보조 탭 넷(토공집계표 · 토적표 · 평균운반거리 · 종방향 무대운반거리) · 토적표 견본 칸 (PLAN 69-2 · 69-3)
- 토적표 칸 = 사용자 견본 32칸 · 보정량계 = 절토 보정량만 · 면 계열(면고르기 · 지장목제거 · 제근 · 노면정리) 거리 = B07 횡단 수량 함수 · 면적 = 앞뒤 평균 × 측점 거리
- 토공집계표 · 운반 시트 = 거창 실무 워크북 같은 이름 시트 칸 · 식 · Q · L = 저장된 유토곡선 배분(서버 · 읽기만)
- 시험 test_69_b08_earthwork_tabs.py · 보정량계 시험 정함대로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
2026-10-06 23:05:36 +09:00

134 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* B08_Quantity_UI_Earthwork_Sheets.ts
* 토공 보조 탭 셋(PLAN 69-2) — 토공집계표 · 평균운반거리 · 종방향 무대운반거리.
*
* 칸 · 식 = 거창 실무 워크북 같은 이름 시트 그대로 · 값은 서버가 셈(`…_Engine_Earthwork_Summary`).
* 운반 Q · L = 저장된 유토곡선 배분(B07 토적도와 같은 정본) — 없으면 그 사유만 보임.
* ========================================================================== */
import {
cell,
note,
tableCard,
type EarthworkTable,
type HaulList,
} from "./B08_Quantity_UI_Earthwork";
const fmt = (value: number | null | undefined): string =>
value == null || !Number.isFinite(value)
? "—"
: value.toLocaleString("ko-KR", { maximumFractionDigits: 2 });
function row(cells: HTMLElement[], className = ""): HTMLTableRowElement {
const tr = document.createElement("tr");
if (className) tr.className = className;
tr.append(...cells);
return tr;
}
function station(text: string, span?: { row?: number; col?: number }): HTMLElement {
const th = cell("th", text, span);
th.className = "b08-summary__station";
return th;
}
/** 토공집계표 — 구분 · 공종 · 규격 · 단위 · 계 · 비고 · 같은 구분은 한 칸으로 묶음 */
export function renderEarthworkSummary(host: HTMLElement, table: EarthworkTable): void {
const thead = document.createElement("thead");
thead.append(
row([station("구분"), ...["공종", "규격", "단위", "계", "비고"].map((t) => cell("th", t))]),
);
const tbody = document.createElement("tbody");
const rows = table.summary;
rows.forEach((item, i) => {
const cells: HTMLElement[] = [];
if (rows[i - 1]?.group !== item.group) {
let span = 1;
while (rows[i + span]?.group === item.group) span += 1;
cells.push(station(item.group, { row: span }));
}
const value = cell("td", fmt(item.value));
value.className = "b08-earthwork__num";
cells.push(cell("td", item.kind), cell("td", item.spec), cell("td", item.unit), value);
cells.push(cell("td", item.note));
tbody.append(row(cells));
});
const info = note(
"토적표 합계 · 평균운반거리 · 종방향 무대운반거리를 실무 토공집계표 식대로 묶음 · " +
"리핑암 = 연암 · 발파암 = 경암 · 구조물 쪽 줄은 구조물 수량에서(— = 아직 값 없음)",
);
host.replaceChildren(tableCard([info], "b08-earthwork__sheet", [thead, tbody]));
}
function haulNote(table: EarthworkTable): HTMLElement[] {
return table.haul_saved
? []
: [note("유토곡선 배분이 저장되지 않았습니다 — 횡단 설계 [확정] 뒤에 채워집니다.")];
}
/** 운반 시트 한 장 — 묶음마다 토량(Q) · 거리(L) · Q×L · 맨 아래 합계 · 아래 평균운반거리 줄 */
function haulSheet(
host: HTMLElement,
table: EarthworkTable,
groups: Array<[string, HaulList]>,
info: string,
): void {
const thead = document.createElement("thead");
thead.append(
row([station("번호", { row: 2 }), ...groups.map(([label]) => cell("th", label, { col: 3 }))]),
row(groups.flatMap(() => ["토량(Q)", "거리(L)", "Q×L"].map((t) => cell("th", t)))),
);
const count = Math.max(0, ...groups.map(([, list]) => list.rows.length));
const tbody = document.createElement("tbody");
for (let i = 0; i < count; i += 1) {
const cells = groups.flatMap(([, list]) => {
const item = list.rows[i];
return item ? [fmt(item.q), fmt(item.l), fmt(item.ql)] : ["", "", ""];
});
tbody.append(row([station(String(i + 1)), ...cells.map((t) => cell("td", t))]));
}
const tfoot = document.createElement("tfoot");
tfoot.append(
row(
[
station("합계"),
...groups.flatMap(([, list]) => [fmt(list.q), "", fmt(list.ql)].map((t) => cell("td", t))),
],
"b08-earthwork__total",
),
);
const averages = groups.map(([label, list], i) =>
note(
`${i + 1}) ${label} 평균운반거리: ${fmt(list.ql)} ÷ ${fmt(list.q)} = ${fmt(list.average_m)} M`,
),
);
const card = tableCard([note(info), ...haulNote(table)], "b08-earthwork__haul", [
thead,
tbody,
tfoot,
]);
card.append(...averages);
host.replaceChildren(card);
}
export function renderHaulDistance(host: HTMLElement, table: EarthworkTable): void {
haulSheet(
host,
table,
[
["덤프트럭", table.haul.dump_truck],
["불도우저", table.haul.dozer],
],
"유토곡선 배분의 덤프 · 도저 띠와 떨어진 구간 운반 · 평균 = ΣQ×L ÷ ΣQ (소수 둘째 자리) · 단위 ㎥ · m",
);
}
export function renderFreeHaul(host: HTMLElement, table: EarthworkTable): void {
haulSheet(
host,
table,
[["종방향무대", table.haul.free_haul]],
"유토곡선 배분의 무대(20 m 안) 띠 · 평균 = ΣQ×L ÷ ΣQ (소수 둘째 자리) · 단위 ㎥ · m",
);
}