feat(b09): 원가계산 화면 새 틀 — 설계내역서·일위대가·단가산출근거 탭(실무 서식 · 내역 → 호표 → 산근 들어가기)
- 틀 B09_Estimation_UI_Shell: 탭 줄과 등록만 · 탭마다 파일 하나(계약 _Shell_Types) - 설계내역서: 실무 열(합계/노무/재료/경비 단가·금액) · 머리글 접기·레벨 고르개 · 줄 누르면 제 N 호표 · 단산 N 단추 · 미확정 빨간 테두리 - 일위대가·단가산출근거: 목록표(내역에 처음 쓰인 차례) + 본표 · 줄 누르면 하위 호표·산근·중기로 · 자취 눌러 되돌아감 · Q 식 글자 그대로 - 옛 탭 여섯(원가계산서·중기·관급사급·기초자료·설계서 구성·산출기초)은 옛 코드 그대로 이어 붙임 — 새 탭 파일이 서면 등록 한 줄씩 바꿈 - 본표 합계 줄 = 호표 성분 소계 원 미만 절사 값 · 비율 줄 금액도 0.1원 절사 표시 - 사전 ui_template_locale_b3 새 벌(b2 700줄 넘음) - 검증: ORCA 검증 프로젝트 — 본체 122,848,989 · 지장목제거 865·15,460,837 · 제 9 호표 합계 1,708 = 산근 8호표 합계 1,708 · 옛 탭 여섯 다 뜸 · 접기 53→51·레벨1 11줄 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/* =============================================================================
|
||||
* B09_Estimation_UI_Tab_PriceBasis.ts
|
||||
* B09 단가산출근거 탭 — 목록표 + 단가산출근거 (STmate `단가산출근거목록표` · `wM_Edit_San` 보기 · PLAN 12장 1차)
|
||||
*
|
||||
* - 목록표 = 내역 일위대가가 품은 D 만, **내역에 처음 쓰인 차례**로 「산근 N호표」(내역 비고 「단산 N」과 한 번호).
|
||||
* - 본표 줄의 비고에 Q 식·품셈 근거를 **글자 그대로** 보임(서버 줄 `note`).
|
||||
* - 「부르는 호표」 칸의 글을 누르면 그 일위대가표로 되돌아 들어감.
|
||||
* - Q 식 편집은 2차(브레인 판정).
|
||||
* ========================================================================== */
|
||||
|
||||
import type { B09Tab, B09TabContext } from "./B09_Estimation_UI_Shell_Types";
|
||||
import { renderDetail } from "./B09_Estimation_UI_Detail";
|
||||
import { L, el, hint, linkButton, sheetTable } from "./B09_Estimation_UI_Sheet";
|
||||
import { listHead, listRow } from "./B09_Estimation_UI_Tab_UnitPrice";
|
||||
import { loadBill, type BillDto } from "./B09_Estimation_UI_Store";
|
||||
|
||||
let selected = "";
|
||||
|
||||
function draw(ctx: B09TabContext, bill: BillDto): void {
|
||||
const entries = bill.price_basis.entries;
|
||||
const page = el("div", "b09s-split");
|
||||
const { wrap, tbody } = sheetTable(listHead(L("B09_Sheet_Col_Basis")));
|
||||
const detail = el("div", "b09s-split");
|
||||
for (const entry of entries) {
|
||||
const row = {
|
||||
...entry,
|
||||
label: `${L("B09_Sheet_Basis_Long")} ${entry.number}${L("B09_Sheet_Basis_Suffix")}`,
|
||||
};
|
||||
const tr = listRow(row, entry.unit_price_krw ?? "", entry.code === selected);
|
||||
const note = tr.lastElementChild as HTMLElement;
|
||||
for (const code of entry.unit_price_codes ?? []) {
|
||||
const sheet = bill.unit_price_sheet.entries.find((item) => item.code === code);
|
||||
if (sheet) note.append(linkButton(sheet.label, () => ctx.open("unit_price", code)));
|
||||
}
|
||||
tr.addEventListener("click", () => {
|
||||
selected = entry.code;
|
||||
ctx.body.replaceChildren();
|
||||
draw(ctx, bill);
|
||||
});
|
||||
tbody.append(tr);
|
||||
}
|
||||
page.append(el("div", "b09s-title", L("B09_Sheet_BasisList")), wrap);
|
||||
if (entries.length === 0) page.append(hint(L("B09_Sheet_EmptyList")));
|
||||
page.append(detail);
|
||||
ctx.body.append(page);
|
||||
if (!selected) {
|
||||
detail.append(hint(L("B09_Sheet_PickSheet")));
|
||||
return;
|
||||
}
|
||||
const picked = entries.find((entry) => entry.code === selected);
|
||||
const label = picked
|
||||
? `${L("B09_Sheet_Basis_Long")} ${picked.number}${L("B09_Sheet_Basis_Suffix")}`
|
||||
: selected;
|
||||
renderDetail(ctx, detail, "price_basis", selected, label);
|
||||
}
|
||||
|
||||
export const priceBasisTab: B09Tab = {
|
||||
key: "price_basis",
|
||||
label: () => L("B09_Estimation_Tab_PriceBasis"),
|
||||
render(ctx, arg) {
|
||||
if (!ctx.projectId) {
|
||||
ctx.body.append(hint(L("B09_Sheet_NoProject")));
|
||||
return;
|
||||
}
|
||||
if (arg) selected = arg;
|
||||
ctx.body.append(hint(L("B09_Sheet_Loading")));
|
||||
loadBill(ctx.projectId)
|
||||
.then((bill) => {
|
||||
ctx.body.replaceChildren();
|
||||
draw(ctx, bill);
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
ctx.body.replaceChildren(hint(`${L("B09_Sheet_LoadFailed")} ${error.message}`, true));
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user