refactor(B08,B09): 폴더째 old_code 로 옮기고 빈 화면 둘만 남김 (PLAN 7-3)
B08_Quantity 86 · B09_Estimation 111 파일을 old_code/ 로 옮김(지우지 않음). 화면은 메뉴·주소·단계 막대만 남은 빈 틀 둘 — main.py 라우터 13 개는 끊음. B07 이 빌려 쓰던 비탈 길이·면적은 필요한 함수만 B07_DesignDetail_Engine_SlopeGeometry 로 옮겨 적음(면적 적분·노면 면적·측점 묶음은 안 옮김) · 시험 하나를 새로 둠. B07 구조물도 조립(Cad_StandardSheet)은 2026-09-13 에 이미 도면 목록에서 빠져 부르는 곳이 없어 old_code 로 같이 보냄 — 구조물 그림은 되살리지 않음. B06 구조물 몫 조회는 빈 값으로 두어 화면이 그대로 서게 함. B08·B09 를 부르던 시험 25 개도 old_code/resources/tester 로 옮김. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
/* =============================================================================
|
||||
* B09_Estimation_UI_Tab_UnitPrice.ts
|
||||
* B09 일위대가 탭 — 목록표 + 일위대가표 (STmate `일위대가목록표` · `wM_Edit_iLWi` 보기 · PLAN 12장 1차)
|
||||
*
|
||||
* - 목록표 = 내역에 쓰인 호표만, **내역에 처음 쓰인 차례**로 「제 N 호표」(번호는 서버가 낼 때마다 매김).
|
||||
* - 줄을 누르면 아래에 그 호표의 일위대가표 — 호표 안 줄(하위 호표·단산·중기)을 누르면 더 들어감.
|
||||
* - 구조물도 호표는 B08 구조물도 탭의 일위대가 표가 본표 — 여기선 금액·안내만.
|
||||
* - 편집(구성행 수정)은 2차 — B09 에 수정 저장 자리가 아직 없음(브레인 판정).
|
||||
* ========================================================================== */
|
||||
|
||||
import type { B09Tab, B09TabContext } from "./B09_Estimation_UI_Shell_Types";
|
||||
import { renderDetail } from "./B09_Estimation_UI_Detail";
|
||||
import {
|
||||
L,
|
||||
el,
|
||||
hint,
|
||||
numberCell,
|
||||
sheetTable,
|
||||
unconfirmedBadge,
|
||||
won,
|
||||
} from "./B09_Estimation_UI_Sheet";
|
||||
import { loadBill, type BillDto, type SheetEntryDto } from "./B09_Estimation_UI_Store";
|
||||
|
||||
let selected = "";
|
||||
|
||||
/** 목록표 머리 — 호표 · 명칭 · 규격 · 단위 · 합계 · 노무비 · 재료비 · 경비 · 비고(실무 목록표). */
|
||||
export function listHead(first: string): HTMLElement {
|
||||
const thead = el("thead");
|
||||
const tr = el("tr");
|
||||
for (const label of [
|
||||
first,
|
||||
L("B09_Sheet_Col_Name"),
|
||||
L("B09_Sheet_Col_Spec"),
|
||||
L("B09_Sheet_Col_Unit"),
|
||||
L("B09_Sheet_Col_Total"),
|
||||
L("B09_Sheet_Col_Labor"),
|
||||
L("B09_Sheet_Col_Material"),
|
||||
L("B09_Sheet_Col_Expense"),
|
||||
L("B09_Sheet_Col_Note"),
|
||||
]) {
|
||||
tr.append(el("th", "", label));
|
||||
}
|
||||
thead.append(tr);
|
||||
return thead;
|
||||
}
|
||||
|
||||
export function listRow(entry: SheetEntryDto, total: string, isSelected: boolean): HTMLElement {
|
||||
const tr = el("tr", `is-clickable${isSelected ? " is-selected" : ""}`);
|
||||
tr.append(
|
||||
el("td", "", entry.label),
|
||||
el("td", "", entry.name),
|
||||
el("td", "", entry.spec),
|
||||
el("td", "", entry.unit),
|
||||
numberCell(won(total)),
|
||||
numberCell(won(entry.labor_krw)),
|
||||
numberCell(won(entry.material_krw)),
|
||||
numberCell(won(entry.expense_krw)),
|
||||
);
|
||||
const note = el("td", "b09s-note");
|
||||
if (entry.unconfirmed) {
|
||||
note.append(unconfirmedBadge(entry.unconfirmed));
|
||||
tr.classList.add("is-manual");
|
||||
}
|
||||
tr.append(note);
|
||||
return tr;
|
||||
}
|
||||
|
||||
function labelFor(bill: BillDto, code: string): string {
|
||||
const entry = bill.unit_price_sheet.entries.find((item) => item.code === code);
|
||||
if (entry) return entry.label;
|
||||
return code.startsWith("X-") ? `${L("B09_Sheet_Machine")} ${code.slice(2)}` : code;
|
||||
}
|
||||
|
||||
function draw(ctx: B09TabContext, bill: BillDto): void {
|
||||
const entries = bill.unit_price_sheet.entries;
|
||||
const page = el("div", "b09s-split");
|
||||
const { wrap, tbody } = sheetTable(listHead(L("B09_Sheet_Col_Sheet")));
|
||||
const detail = el("div", "b09s-split");
|
||||
const select = (code: string): void => {
|
||||
selected = code;
|
||||
ctx.body.replaceChildren();
|
||||
draw(ctx, bill);
|
||||
};
|
||||
for (const entry of entries) {
|
||||
const tr = listRow(entry, entry.total_krw ?? "", entry.code === selected);
|
||||
tr.addEventListener("click", () => select(entry.code));
|
||||
tbody.append(tr);
|
||||
}
|
||||
page.append(el("div", "b09s-title", L("B09_Sheet_UnitPriceList")), 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);
|
||||
if (picked?.source === "structure") {
|
||||
detail.append(el("div", "b09s-title", `${picked.label} ${picked.name} · ${picked.spec}`));
|
||||
detail.append(hint(L("B09_Sheet_StructureSheet")));
|
||||
return;
|
||||
}
|
||||
renderDetail(ctx, detail, "unit_price", selected, labelFor(bill, selected));
|
||||
}
|
||||
|
||||
export const unitPriceTab: B09Tab = {
|
||||
key: "unit_price",
|
||||
label: () => L("B09_Estimation_Tab_UnitPrice"),
|
||||
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