- 기초단가 표: 칸 나갈 때 즉시 저장 없앰 · 고친 칸·새 줄·지울 줄은 초안(sessionStorage z01-draft:base:{kind})에 쌓고 [저장] 한 번에 보냄 · [고친 것 버리기]·[줄 추가]·[줄 삭제]·[초기값으로] · 409 면 초안 지키고 알림 · 서버가 revision 을 줄 때만 고치기 단추 섬
- 옛 덮개 길(칸 단위 PUT · 고친 것 모아 보기 · 덮개 판정 표시)과 그 사전 글자 뺌 — 계약 1-0 에서 서버 쪽 삭제
- 공종 편집(Z01_MasterData_UI_WorkItem.ts · _WorkItem_Rows.ts): 왼쪽 목록(상태별 개수·검색) / 머리 / 구성 줄 표(갈래별 · 자원 찾기 = 기초단가 검색) / 품셈 원문 표+[주] 읽기 전용 / [저장]·[초기값으로]·[검수 완료] · 초안 열쇠 z01-draft:work_item:{key}
- 공종 API(sub_laptop_3 e1c71c3e) 모양에 맞춤 — 줄은 id + 계약 칸 열하나만 보냄(extra=forbid) · 저장·초기값 응답(새 GET 모양)으로 바로 다시 그림 · 저장된 고침(changed_columns·is_added) 표시
- 초안 순수 함수 Z01_MasterData_UI_Draft.ts + 시험 test_z01_master_draft.py
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0145cr1DMC5Ft8fouQSXtp69
80 lines
3.2 KiB
TypeScript
80 lines
3.2 KiB
TypeScript
/* =============================================================================
|
|
* Z01_MasterData_UI_Page.ts
|
|
* 마스터 데이터 — B03~B09 와 같은 틀: 좌측 도킹 사이드바(기초단가 · 마스터 트리) / 우측 표
|
|
*
|
|
* 시스템 관리자만(서버도 require_system_admin 으로 다시 막음) · 워크플로 밖 화면이라 진행단계
|
|
* 패널·프로젝트 이름은 안 세움 (2026-09-15 브레인 Z01 — 좌측 패널 양식 갈음 · 기초단가 칸).
|
|
* ========================================================================== */
|
|
|
|
import "@ui/ui_template_workflow_layout.css";
|
|
import { ROUTES } from "@config/config_frontend";
|
|
import { el, hideLoadingOverlay, showLoadingOverlay, showToast } from "@ui/ui_template_elements";
|
|
import { t as L } from "@ui/ui_template_locale";
|
|
import { createWorkflowOverlays } from "@ui/ui_template_overlay";
|
|
import { navigateTo } from "../A00_Common/router";
|
|
import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch";
|
|
import { fetchBaseKinds, fetchMasterTree, type MasterGroup } from "./Z01_MasterData_Api_Fetch";
|
|
import type { ServedKind } from "./Z01_MasterData_UI_Cells";
|
|
import { buildRowsView, type RowsView } from "./Z01_MasterData_UI_Rows";
|
|
import { buildSidePanel } from "./Z01_MasterData_UI_Side";
|
|
import { buildWorkItemView } from "./Z01_MasterData_UI_WorkItem";
|
|
import "./Z01_MasterData_UI_Style.css";
|
|
|
|
export async function renderZ01MasterData(root: HTMLElement): Promise<void> {
|
|
const user = await fetchSessionUser().catch(() => null);
|
|
if (user?.role !== "SYSTEM_ADMIN") {
|
|
showToast(L("Z01_MasterData_AdminOnly"), "error");
|
|
navigateTo(ROUTES.B01_ACCOUNT);
|
|
return;
|
|
}
|
|
showLoadingOverlay();
|
|
let groups: MasterGroup[] = [];
|
|
let kinds: ServedKind[] = [];
|
|
try {
|
|
[groups, kinds] = await Promise.all([fetchMasterTree(), fetchBaseKinds()]);
|
|
} catch (error) {
|
|
showToast(error instanceof Error ? error.message : L("Z01_MasterData_LoadFailed"), "error");
|
|
} finally {
|
|
hideLoadingOverlay();
|
|
}
|
|
root.innerHTML = "";
|
|
root.append(buildPage(groups, kinds));
|
|
}
|
|
|
|
function buildPage(groups: MasterGroup[], kinds: ServedKind[]): HTMLElement {
|
|
// 오른쪽은 표 보기 · 공종 편집 둘 중 하나 — 왼쪽에서 누른 쪽만 보임.
|
|
const rows = buildRowsView();
|
|
const items = buildWorkItemView();
|
|
items.root.hidden = true;
|
|
const swap = (showRows: boolean): void => {
|
|
rows.root.hidden = !showRows;
|
|
items.root.hidden = showRows;
|
|
};
|
|
const view: RowsView = {
|
|
root: rows.root,
|
|
show: (source) => {
|
|
swap(true);
|
|
rows.show(source);
|
|
},
|
|
};
|
|
const layout = el("div", { className: "ui-workflow-layout z01-master" });
|
|
const main = el("main", {
|
|
className: "ui-workflow-layout__main",
|
|
children: [rows.root, items.root],
|
|
});
|
|
const overlays = createWorkflowOverlays({
|
|
title: L("Z01_MasterData_Title"),
|
|
optionsContent: buildSidePanel(groups, kinds, view, (axis) => {
|
|
swap(false);
|
|
items.show(axis);
|
|
}),
|
|
showProjectName: false,
|
|
onOptionsOpenChange: (isOpen) => layout.classList.toggle("is-options-open", isOpen),
|
|
});
|
|
layout.append(
|
|
el("div", { className: "ui-workflow-layout__body", children: [main] }),
|
|
overlays.root,
|
|
);
|
|
return layout;
|
|
}
|