- 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>
131 lines
5.0 KiB
TypeScript
131 lines
5.0 KiB
TypeScript
/* =============================================================================
|
|
* B09_Estimation_UI_Tabs_Labor.ts
|
|
* B09 대가 탭 둘(PLAN 145-2) — 일위대가목록표 · 일위대가표(실무 엑셀 꼴 · 값 = `B09_Estimation_Calc_Labor`).
|
|
*
|
|
* 목록표 = 호표 한 줄(합계 · 노무비 · 재료비 · 경비) · 줄 누름 = 그 블록으로
|
|
* 일위대가표 = 공용 일위대가 격자(704-3 · `ui_template_hopyo_grid` · 머리 · [품셈 인용] · 줄 · 합계 · 줄 꼬리표) ·
|
|
* 줄 누름 = 단가를 낸 탭 · 줄(대가 줄 = 그 블록)
|
|
* 줄 꼴(155-2) = 머리 · 합계 굵게(`is-title`) · 인용 · 줄 = 들여쓰기 「ㄴ」(2단 · 겹 대가는 안 펼침)
|
|
* 연결된 구조물 조합 사본이 없으면 빈 표 「연결 없음」
|
|
* 빈 줄(166-6) = 합계 = 아는 줄 합 · 옆 「빈 줄 n」 · 풍선 = 빈 줄 이름 · 내역 단가엔 안 넘김
|
|
* ========================================================================== */
|
|
|
|
import type { DataRow } from "@ui/ui_template_data_table";
|
|
import type { Row } from "./B09_Estimation_Calc_Base";
|
|
import {
|
|
blockLevel,
|
|
money,
|
|
text,
|
|
type Link,
|
|
type TabBuild,
|
|
type TabId,
|
|
type TabTable,
|
|
} from "./B09_Estimation_UI_Tabs";
|
|
import { raw } from "./B09_Estimation_UI_Tabs_Sangeun";
|
|
import { HOPYO_TAG, hopyoCellClass, hopyoGrid } from "@ui/ui_template_hopyo_grid";
|
|
|
|
const EMPTY =
|
|
"일위대가 없음 — 이 공사에 고른 구조물 조합이 없음 · B05 · B06 에서 구조물 조합을 고르고 [저장] · 또는 설계내역서 오른쪽 재료 창고";
|
|
const BLANK = "빈 줄은 금액을 모르는 줄(합계는 아는 줄만)";
|
|
/** 「빈 줄 n」 작은 글 · 풍선 = 빈 줄 이름 */
|
|
const blankNote = (b: Row): string => (b.blank ? `빈 줄 ${b.blank}` : "");
|
|
const blankTip = (b: Row | undefined): string | null =>
|
|
b?.blank ? `빈 줄 — ${(b.blank_names as string[]).join(" · ")}` : null;
|
|
|
|
/** 블록 줄 → 단가를 낸 탭 */
|
|
const LINE_TAB: Record<string, TabId> = {
|
|
labor: "labor",
|
|
material: "material",
|
|
machine: "machine",
|
|
daega: "dg",
|
|
sangeun: "sg",
|
|
};
|
|
|
|
export const buildDaegaList: TabBuild = ({ sheets }): TabTable | string => {
|
|
const rows: DataRow[] = (sheets.daega || []).map((r: Row) => ({
|
|
...r,
|
|
no: `대가${r.no}`,
|
|
blank_note: blankNote(r),
|
|
}));
|
|
if (!rows.length) return EMPTY;
|
|
return {
|
|
columns: [
|
|
text("no", "호표", 80),
|
|
text("kind", "꼴", 70),
|
|
text("name", "명칭", 240),
|
|
text("spec", "규격", 200),
|
|
text("unit", "단위", 56),
|
|
money("sum", "합계"),
|
|
text("blank_note", "", 64),
|
|
money("labor", "노무비"),
|
|
money("material", "재료비"),
|
|
money("expense", "경비"),
|
|
],
|
|
rows,
|
|
frozen: 3,
|
|
hint: `줄을 누르면 그 블록으로 이동 · ${BLANK}`,
|
|
link: (i: number): Link | null => (rows[i] ? { tab: "dg", key: String(rows[i].key) } : null),
|
|
tip: (i, key) =>
|
|
key === "spec"
|
|
? raw(rows[i]?.spec, rows[i]?.spec_raw)
|
|
: key === "blank_note" || key === "sum"
|
|
? blankTip(rows[i])
|
|
: null,
|
|
};
|
|
};
|
|
|
|
export const buildDaegaBlocks: TabBuild = ({ sheets }): TabTable | string => {
|
|
const blocks: Row[] = sheets.daega_blocks || [];
|
|
if (!blocks.length) return EMPTY;
|
|
// 704-3 — 공용 일위대가 격자(M02 카드 · 상세와 같은 열 · 줄 꼴) · 값 = 서버 `Calc_Labor` 그대로
|
|
const grid = hopyoGrid(
|
|
blocks.map((b) => ({
|
|
key: b.id,
|
|
no: b.no,
|
|
name: b.name,
|
|
spec: b.spec,
|
|
spec_raw: b.spec_raw,
|
|
unit: b.unit,
|
|
kind: b.kind,
|
|
cite: b.cite,
|
|
total: { sum: b.sum, labor: b.labor, material: b.material, expense: b.expense },
|
|
blank: b.blank ?? 0,
|
|
blank_names: b.blank_names ?? [],
|
|
lines: b.lines.map((ln: Row) => ({
|
|
name: ln.name || "",
|
|
spec: ln.spec || "",
|
|
spec_raw: ln.spec_raw,
|
|
qty: ln.qty,
|
|
unit: ln.unit || "",
|
|
prices: { sum: ln.price, ...ln.prices },
|
|
amounts: { sum: ln.amount, ...ln.amounts },
|
|
note: ln.ref_no || ln.why || "",
|
|
tag: ln.kind === "fixed" ? HOPYO_TAG.fix : HOPYO_TAG.pum, // 705-1 고정 줄
|
|
})),
|
|
})),
|
|
);
|
|
const { rows, titles } = grid;
|
|
const links: Array<Link | null> = rows.map((_, i) => {
|
|
const at = grid.at.get(i);
|
|
const ln: Row | undefined = at && blocks[at[0]].lines[at[1]];
|
|
const tab = ln && LINE_TAB[ln.kind];
|
|
return tab && ln.key ? { tab, key: String(ln.key) } : null;
|
|
});
|
|
return {
|
|
columns: grid.columns,
|
|
rows,
|
|
frozen: 1,
|
|
hint: `줄을 누르면 단가를 낸 탭으로 이동 · ${BLANK}`,
|
|
link: (i: number) => links[i] ?? null,
|
|
rowClass: (i: number) => (titles.has(i) ? "is-title" : null),
|
|
cellClass: (i: number, key: string) => hopyoCellClass(rows, i, key),
|
|
level: blockLevel("name", (i) => titles.has(i)),
|
|
tip: (i: number, key: string) =>
|
|
key === "spec"
|
|
? raw(rows[i]?.spec, rows[i]?.spec_raw)
|
|
: key === "note" || key === "sum"
|
|
? blankTip(rows[i])
|
|
: null,
|
|
};
|
|
};
|