- 좌측 「구조물 집계 양식」 아래 「항목 나무」 카드(세 층 공용 · 깊이 자유 · 검색 · 키보드 위아래 · 펼침 · F2 · Delete)
- 항목 누름 → 표 그 열 고름 + 카드 넷 · 표에서 열 고름 → 나무 표시
- 나무 고침 POST /api/m02/layers/{층}/tree · 판 409 다시 읽고 알림 · 저장 안 한 표 고침은 저장/버림/취소 물음
- 읽기만 층은 메뉴 · 키 없음 · 나무 메뉴 자리는 sub5 의 ui_template_tree 그대로
- 시험 test_m02_treepanel 8 · test_m02_layer_screen 문구 맞춤
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D2nUMUMTsqm93PbQtipo6c
89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
/* =============================================================================
|
|
* M02_MasterTemplete_UI_Page.ts
|
|
* 마스터 템플릿 · 구조물 관리 화면 — 좌측 도킹 패널(양식 목록) / 우측 편집 칸(표·도면 부품)
|
|
*
|
|
* 층 = 주소 인자 `?layer=personal|company`(없으면 시스템) — 같은 화면 한 벌.
|
|
* 화면은 로그인만 확인 — 고치기는 층별 권한일 때만 켬(서버도 막음 · `M02_MasterTemplete_Layer.ts`).
|
|
* ========================================================================== */
|
|
|
|
import "@ui/ui_template_workflow_layout.css";
|
|
import { el } from "@ui/ui_template_elements";
|
|
import { createWorkflowOverlays } from "@ui/ui_template_overlay";
|
|
import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch";
|
|
import { setActiveLayer } from "./M02_MasterTemplete_Api_Fetch";
|
|
import {
|
|
accessFor,
|
|
buildNeedCompany,
|
|
buildReadOnlyBar,
|
|
layerFromHash,
|
|
titleOf,
|
|
} from "./M02_MasterTemplete_Layer";
|
|
import { STRUCTURE_TABLE } from "./M02_MasterTemplete_Structure";
|
|
import { createMain, type Selection } from "./M02_MasterTemplete_UI_Main";
|
|
import { buildSide } from "./M02_MasterTemplete_UI_Side";
|
|
import "./M02_MasterTemplete_UI_Style.css";
|
|
|
|
export async function renderM02MasterTemplate(root: HTMLElement): Promise<void> {
|
|
const user = await fetchSessionUser().catch(() => null);
|
|
const layer = layerFromHash();
|
|
setActiveLayer(layer);
|
|
const access = accessFor(layer, user);
|
|
if (access.needCompany) {
|
|
root.replaceChildren(buildNeedCompany());
|
|
return;
|
|
}
|
|
const isAdmin = access.canWrite; // 이 층을 고칠 수 있나(하위 부품의 「관리자」 = 같은 뜻)
|
|
// 회사용을 읽기만 볼 때 — 안내 + [개인용으로 복사]
|
|
const readOnlyBar = layer === "company" && !isAdmin ? buildReadOnlyBar(user) : null;
|
|
const main = createMain(
|
|
isAdmin,
|
|
() => void side.refresh(),
|
|
() => side.paint(),
|
|
{
|
|
top: readOnlyBar?.root,
|
|
onColumn: (column) => {
|
|
readOnlyBar?.setColumn(column);
|
|
side.selectItem(column);
|
|
},
|
|
},
|
|
);
|
|
// 첫 화면 · 닫은 뒤(양식 지움 · 자재 조합 상세 닫음) = 구조물집계표 — 빈 화면 없음
|
|
const home: Selection = {
|
|
layer,
|
|
projectId: null,
|
|
kind: "table",
|
|
name: STRUCTURE_TABLE,
|
|
};
|
|
const side = buildSide({
|
|
layer,
|
|
isAdmin,
|
|
onOpen: (sel) => void main.open(sel ?? home),
|
|
getOpen: main.current,
|
|
confirmLeave: main.confirmLeave,
|
|
showView: main.showView,
|
|
tree: {
|
|
onPick: (item) => void main.openTable(layer, item.열),
|
|
settle: main.settle,
|
|
onChanged: (colId) => main.openTable(layer, colId, true),
|
|
},
|
|
});
|
|
|
|
const layout = el("div", { className: "ui-workflow-layout m02-master" });
|
|
const overlays = createWorkflowOverlays({
|
|
title: titleOf(layer),
|
|
optionsContent: el("div", { className: "m02-master__side", children: [side.root] }),
|
|
showProjectName: false,
|
|
onOptionsOpenChange: (isOpen) => layout.classList.toggle("is-options-open", isOpen),
|
|
});
|
|
layout.append(
|
|
el("div", {
|
|
className: "ui-workflow-layout__body",
|
|
children: [el("main", { className: "ui-workflow-layout__main", children: [main.root] })],
|
|
}),
|
|
overlays.root,
|
|
);
|
|
root.innerHTML = "";
|
|
root.append(layout);
|
|
void main.open(home);
|
|
}
|