Files
Aislo/B09_Estimation/B09_Estimation_UI_Tabs_Summary.ts
T
eomsangdonandClaude Opus 5.5 3435922131 feat(B09·B08): 화면 낱말 실무 말로 · 번호 숨김 · ☰ 서랍 내 자료집 길(PLAN 703-4)
- B09 데이터 점검 → 내역 점검 · 공기 옵션 → 공사기간 조건 · 박스보기/호표보기 → 카드 보기/표 보기 ·
  하이퍼링크/팝업 → 탭 이동/곁 창 · 굳힌 단가 → 이 공사 단가 책 · 산식/요율 출처 → 계산식/요율 근거 ·
  빈 줄 → 금액 빈 줄 · 단가연결 칸 램프 → 단가연결 칸 ● · 새 산근 → 새 단가산출(산근) · 연결 없음 → 일위대가 없음
- 단가연결 창 종류 일위대가 사전조합 → 일위대가(자료집) · 일위대가 호표 → 이 공사 일위대가 · 단가산출 호표 →
  이 공사 단가산출 · 대가N/산근 N호표 → 일위대가 N호/단가산출 N호 · 구조물 조합 줄 번호(SS…) 숨김 ·
  넣을 값 창 제목 번호 → 알림 글 끝
- B08 조합 사본 · 조합 연결 · 노랑 램프 → 구조물 조합 · 구조물 조합 고르기 · 노랑 ●(locale_b4 B08_Quantity_* 글만 · 한시 브레인 승인)
- ☰ 서랍 · 진행 판 끝 「내 자료집(일위대가 · 구조물 조합)」 = M02 일위대가조합 개인 층(떠남 물음 뒤)
- 낡은 시험 글 고침(새 낱말): 143-1 · 157-2 · 182 · 203-1 · 204-2 · 304 · 311 · 701-3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 15:18:10 +09:00

99 lines
3.9 KiB
TypeScript

/* =============================================================================
* B09_Estimation_UI_Tabs_Summary.ts
* B09 집계표 넷(PLAN 145-5) — 재료비 · 노무비 · 경비 수량금액집계표 · 중기시간금액집계표(실무 엑셀 꼴).
*
* 값 = 서버 단독 역전개(`B09_Estimation_Summary` · GET 응답 `summary`) — 조작 중엔 안 바뀜 · [저장] 뒤 정본
* 끝수 = 총수량 ROUND 2 · 금액 ROUND(수량 × 단가, 0) · 줄 누름 = 단가를 낸 목록표 줄
* 고정 줄(705-1) 이음 없는 줄 = 집계에서 빠짐 — 안내 「고정 줄 n」(서버 `summary.fixed`)
* 경비 집계표 빈 까닭(166-5) = 산근 · 대가 어느 길도 경비 자원 줄을 안 냄(기계 → 중기 · 구역화물 → 자재)
* ========================================================================== */
import type { DataRow } from "@ui/ui_template_data_table";
import type { Row } from "./B09_Estimation_Calc_Base";
import {
blankRows,
money,
qty,
text,
type TabBuild,
type TabId,
type TabTable,
} from "./B09_Estimation_UI_Tabs";
const HINT = "줄을 누르면 목록표로 이동";
/** 안내 + 「빈 줄 n」(설계내역서와 같은 수 · 701-2 — 금액 모르는 줄은 집계에서 빠짐) */
const hint = (sheets: Row, payload: Row): string => {
const n = blankRows(sheets).length;
const fixed = Number((payload.summary || {}).fixed) || 0;
return [
HINT,
...(n ? [`금액 빈 줄 ${n} — 집계에서 빠짐(왼쪽 내역 점검)`] : []),
...(fixed ? [`고정 줄 ${fixed} — 이은 단가 없어 집계에서 빠짐`] : []),
].join(" · ");
};
/** 줄이 없을 때 표 위 맨 앞 안내 */
const EXPENSE_NONE = "경비 자원 없음";
function resourceTab(id: string, list: TabId, unitPrice: string, none = ""): TabBuild {
return ({ payload, sheets }): TabTable => {
const rows: DataRow[] = ((payload.summary || {})[id] || []).map((r: Row) => ({ ...r }));
const sum = rows.reduce((acc, r) => acc + (typeof r.amount === "number" ? r.amount : 0), 0);
return {
columns: [
qty("no", "호표", 0),
text("name", "명칭", 200),
text("spec", "규격", 140),
qty("qty", "수량", 2),
text("unit", "단위", 56),
money("price", unitPrice),
money("amount", "금액"),
text("note", "비고", 120),
],
rows,
total: rows.length ? { name: "계", amount: sum } : null,
frozen: 2,
hint: !rows.length && none ? `${none} · ${hint(sheets, payload)}` : hint(sheets, payload),
link: (i) => (rows[i] ? { tab: list, key: String(rows[i].key) } : null),
};
};
}
export const buildSumMaterial = resourceTab("sum_material", "material", "단가");
export const buildSumLabor = resourceTab("sum_labor", "labor", "단가");
export const buildSumExpense = resourceTab("sum_expense", "expense", "단가", EXPENSE_NONE);
export const buildSumMachine: TabBuild = ({ payload, sheets }): TabTable => {
const rows: DataRow[] = ((payload.summary || {}).sum_machine || []).map((r: Row) => ({ ...r }));
const add = (key: string) =>
rows.reduce((acc, r) => acc + (typeof r[key] === "number" ? (r[key] as number) : 0), 0);
return {
columns: [
qty("no", "호표", 0),
text("name", "명칭", 200),
text("spec", "규격", 120),
qty("qty", "수량", 2),
text("unit", "단위", 56),
money("sum", "합계"),
money("labor", "노무비"),
money("material", "재료비"),
money("expense", "경비"),
text("note", "비고", 120),
],
rows,
total: rows.length
? {
name: "계",
sum: add("sum"),
labor: add("labor"),
material: add("material"),
expense: add("expense"),
}
: null,
frozen: 2,
hint: hint(sheets, payload),
link: (i) => (rows[i] ? { tab: "machine", key: String(rows[i].key) } : null),
};
};