feat(M02): 관리 화면 「구조물 조합」 — 나무가 주 · 표는 참조표 · 비고 · 전구간 · 합계 숨김(PLAN 26-7a~e)
- 화면 이름 「구조물집계표」 · 「구조물 집계 양식」 → 「구조물 조합」(좌측 줄 · 상세 제목 · 안내글) · 파일 이름 · 양식 키 · API 길 그대로 - 좌측 패널 「항목 나무」 컨테이너 없앰 — 페이지가 나무를 만들어 편집 칸 왼쪽(aside)에 붙임 · 「구조물 조합」일 때만 보임 · 오른쪽 클릭 · 찾기 · 표와 서로 고름 · 고치기 전 저장 물음 그대로 - 표 부품 lockHead — 열 더하기 · 분류N 더하기 · 열 지우기 단추 없음 · 머리 · 층 이름 고치기 없음(단위 · 일위대가 · 조회 후 선택은 그대로) - 비고 열 · 전구간 줄 · 합계 줄은 보일 문서에서만 뺌(comboView) · [저장] 때 저장본 것을 다시 끼움(comboMerge) · 양식 파일 · M02_Table_Fill 그대로 - 서버 — 화면 표 [저장](store.write screen=True)은 있던 항목의 경로 · 층 이름 · 빈 폴더를 저장본 그대로(tree.keep_paths · 브라우저 머리 안 받음) · 머리는 경로에서 다시 만듦 · 나무 고침 줄기 그대로 - 나무 같은 이름 409 는 「이미 있는 항목」 까닭 그대로 보임(판 다름 안내와 가름) - 시험 test_m02_combo_screen 3(숨김 · 되끼움 Node · 잠금 · 나무 자리) · test_m02_tree 표 저장 약속 새로 · 이름 · 잠금 기대값 고침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
This commit is contained in:
@@ -17,6 +17,8 @@ import {
|
||||
type StructureDoc,
|
||||
} from "./M02_MasterTemplete_Api_Fetch";
|
||||
import {
|
||||
comboMerge,
|
||||
comboView,
|
||||
createStructurePanel,
|
||||
pillsFor,
|
||||
STRUCTURE_TABLE,
|
||||
@@ -103,9 +105,11 @@ export function canEdit(layer: Layer, isAdmin: boolean): boolean {
|
||||
return layer === "project" || isAdmin;
|
||||
}
|
||||
|
||||
/** 페이지가 끼우는 것 — `top` = 편집 칸 맨 위 막대(회사용 읽기만 안내) · `onColumn` = 집계표에서 고른 열 */
|
||||
/** 페이지가 끼우는 것 — `top` = 편집 칸 맨 위 막대(회사용 읽기만 안내) · `onColumn` = 집계표에서 고른 열 ·
|
||||
* `aside` = 「구조물 조합」을 열 때만 편집 칸 왼쪽에 보임(항목 나무 · PLAN 26-7c) */
|
||||
export interface MainExtras {
|
||||
top?: HTMLElement;
|
||||
aside?: HTMLElement;
|
||||
onColumn?: (column: string | null) => void;
|
||||
}
|
||||
|
||||
@@ -125,7 +129,7 @@ export function createMain(
|
||||
const notice = el("div", { className: "m02-main__notice", attrs: { hidden: "" } });
|
||||
const host = el("div", { className: "m02-main__host" });
|
||||
const extra = el("div", { className: "m02-main__extra" }); // 표 밖 형제 자리 — 구조물 설계 컨테이너
|
||||
const root = el("div", {
|
||||
const column = el("div", {
|
||||
className: "m02-main",
|
||||
children: [
|
||||
...(extras.top ? [extras.top] : []),
|
||||
@@ -135,6 +139,15 @@ export function createMain(
|
||||
extra,
|
||||
],
|
||||
});
|
||||
// 왼쪽 나무(주) · 오른쪽 편집 칸 — 나무는 「구조물 조합」일 때만(`showAside`)
|
||||
const root = extras.aside
|
||||
? el("div", { className: "m02-shell", children: [extras.aside, column] })
|
||||
: column;
|
||||
const isCombo = (at: Selection | null): boolean =>
|
||||
!!at && at.kind === "table" && at.name === STRUCTURE_TABLE && at.layer !== "project";
|
||||
const showAside = (): void => {
|
||||
if (extras.aside) extras.aside.hidden = !isCombo(sel);
|
||||
};
|
||||
|
||||
let sel: Selection | null = null;
|
||||
let version = "";
|
||||
@@ -360,9 +373,11 @@ export function createMain(
|
||||
// 그 뒤 .열 을 그대로 읽으면 죽는다(2026-09-28 사용자 보고 — 열 고른 뒤 CAD
|
||||
// 불러오기 오류). getDoc() 뒤에도 옵셔널 체이닝을 이어야 한다.
|
||||
const columns = (): StructureColumn[] => sheet?.getDoc()?.열 ?? [];
|
||||
editor = create(host, doc, {
|
||||
// 「구조물 조합」 = 나무를 따라오는 참조표(26-7b · d) — 비고 · 전구간 · 합계 숨김 · 열 · 머리는 나무만
|
||||
editor = create(host, struct ? comboView(doc) : doc, {
|
||||
mode: at.layer === "project" ? "project" : "master",
|
||||
readOnly,
|
||||
lockHead: !!struct,
|
||||
onChange: () => (dirty = !readOnly),
|
||||
...(struct
|
||||
? {
|
||||
@@ -382,7 +397,11 @@ export function createMain(
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
if (struct) sheet = editor as SheetEditorHandle;
|
||||
if (!struct) return;
|
||||
const shown = editor as SheetEditorHandle;
|
||||
sheet = shown;
|
||||
// [저장]은 저장본의 숨긴 것을 다시 끼운 문서(서버가 머리를 경로에서 다시 만듦 · 26-7e)
|
||||
editor = { getDoc: () => comboMerge(loaded, shown.getDoc()), destroy: shown.destroy };
|
||||
return;
|
||||
}
|
||||
if (at.kind === "area" || at.kind === "material") {
|
||||
@@ -421,11 +440,12 @@ export function createMain(
|
||||
sel = next;
|
||||
onOpened?.();
|
||||
bar();
|
||||
showAside();
|
||||
if (!next) {
|
||||
title.textContent = L("M02_PickTemplate");
|
||||
return empty("");
|
||||
}
|
||||
title.textContent = next.label ?? next.name;
|
||||
title.textContent = isCombo(next) ? L("M02_KindTable") : (next.label ?? next.name); // 26-7a
|
||||
try {
|
||||
const got = await readTemplate(next.layer, next.kind, next.name, next.projectId);
|
||||
if (mine !== seq) return;
|
||||
@@ -501,6 +521,7 @@ export function createMain(
|
||||
sel = null;
|
||||
onOpened?.(); // 좌측 양식 · 열 줄 고름 지움
|
||||
bar();
|
||||
showAside();
|
||||
title.textContent = label;
|
||||
host.replaceChildren(node);
|
||||
return (d) => (dirty = d);
|
||||
@@ -544,6 +565,7 @@ export function createMain(
|
||||
if (sel && (await confirmLeave())) void open(sel);
|
||||
});
|
||||
bar();
|
||||
showAside();
|
||||
empty("");
|
||||
return { root, open, current: () => sel, confirmLeave, showView, openTable, settle };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user