feat(m02): 카드 · 면적 도면 패널 미리보기 탭 고르기 · 카드 저장 문서 전체(105-3)

- 카드 도면 미리보기 = mountStructureSheets(공용 탭 줄 · pickTabs 고르기만) · 「장 n」 배지 지움
- 카드 저장 = getDoc() 모든 장 — 2장 보다 Ctrl+S 해도 1장 그대로
- 면적 상세 오른쪽 도면 패널도 탭(고르기만 · 보내기는 지금 장)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015KYZ2HWWdUwZWYnn3tQz7X
This commit is contained in:
2026-10-08 16:22:18 +09:00
co-authored by Claude Opus 5.5
parent 01d819bfb6
commit 36fc3d6c3b
6 changed files with 60 additions and 55 deletions
@@ -1,7 +1,7 @@
/* =============================================================================
* M02_MasterTemplete_AreaDrawing.ts
* 면적산출 상세 오른쪽 「도면」 패널 몸(PLAN 47-6) — 그 열 구조물 도면을 보기 · 고르기(고치기 없음).
* 처음 펼 때 읽고 그림 — 접힌 채 iframe 을 띄우지 않음.
* 처음 펼 때 읽고 그림 — 접힌 채 iframe 을 띄우지 않음. 여러 장 = 공용 탭 줄 고르기만(105-3 · 보내기는 지금 장).
* 83-3 — 머리 [면적산출로 보내기] = CAD 에 고른 범위 요청(`aislo:b08:export-table-request`) → 받은 표 자료
* (`aislo:b08:export-table` · CAD `integration/aislo-table-export.ts`)를 `onTable` 로(새 시트 만들기는 부른 쪽).
* CAD 명령 TOAREA 로 보낸 것도 같은 길. 고칠 수 없는 면적(읽기 층)이면 단추 없음.
@@ -9,7 +9,7 @@
import { createButton, el } from "@ui/ui_template_elements";
import { readTemplate, type Layer, type StructureDoc } from "./M02_MasterTemplete_Api_Fetch";
import { mountDrawingTemplate, type DrawingTemplateDoc } from "./M02_MasterTemplete_Drawing";
import { mountStructureSheets } from "./M02_MasterTemplete_Drawing";
import type { DrawingTable } from "./M02_MasterTemplete_AreaFromDrawing";
const TEXT = {
@@ -96,7 +96,8 @@ export function createAreaDrawing(
if (!doc?.도면) return note(TEXT.none);
stage.replaceChildren();
// 보기 전용 + 고르기(누름 · 끌기) — 미리보기(끌기 = 화면 옮기기)는 고르기가 꺼져 있어 안 씀
view = mountDrawingTemplate(stage, doc.도면 as unknown as DrawingTemplateDoc, {
const sheets = doc as unknown as Parameters<typeof mountStructureSheets>[1];
view = mountStructureSheets(stage, sheets, {
readOnly: true,
name: `preview:${column}`,
layer,
@@ -105,6 +106,7 @@ export function createAreaDrawing(
noArea: true,
frame: true,
noImport: true,
pickTabs: true,
});
frame = stage.querySelector("iframe");
if (frame) hideChrome(frame);
@@ -87,25 +87,6 @@
box-shadow: 0 4px 16px rgb(0 0 0 / 25%);
}
/* 카드 미리보기 「장 n」(82-2) — 1장만 보이는 여러 장 도면 */
.m02-drawing:has(> .m02-drawing__sheets) {
position: relative;
}
.m02-drawing__sheets {
position: absolute;
z-index: 3;
top: 6px;
right: 8px;
padding: 1px 8px;
border: 1px solid var(--color-border);
border-radius: 10px;
background: var(--color-surface-raised);
color: var(--color-text-secondary);
font-size: 11px;
pointer-events: none;
}
/* 탭 줄(82-1) — 그림 칸에 붙임 */
.m02-drawing > .cad-tabs {
margin-bottom: calc(-1 * var(--spacing-8));
@@ -58,6 +58,8 @@ export interface DrawingTemplateOptions {
frameNumber?: string;
/** 탭 줄(82-1) — 그림 칸 바로 위에 놓음 */
tabs?: HTMLElement;
/** 여러 장 탭 줄은 고르기만(105-3 카드 · 면적 도면 패널) — 추가 · 이름 · 지우기 · 끌기 없음 */
pickTabs?: boolean;
}
const RECOVERY_PREFIX = "OPEN_WEB_CAD__RECOVERY__";
@@ -439,7 +441,8 @@ export function mountStructureSheets(
);
const tabs: CadTabs<DrawingTemplateDoc> = createCadTabs<DrawingTemplateDoc>({
features: readOnly ? {} : { add: true, rename: true, remove: true, reorder: true },
features:
readOnly || options.pickTabs ? {} : { add: true, rename: true, remove: true, reorder: true },
capture: async () => {
const got = await drawing.getDoc();
if (placing && placed(got, placing.link)) placing = null;
@@ -485,7 +488,7 @@ export function mountStructureSheets(
);
retitle();
tabs.set(tabs.tabs(), FIRST_TAB); // 풍선 글을 그림
if (readOnly && !more.length) tabs.element.hidden = true; // 볼 장이 하나 — 줄 없음
if ((readOnly || options.pickTabs) && !more.length) tabs.element.hidden = true; // 볼 장이 하나 — 줄 없음
const drawing = mountDrawingTemplate(container, doc.도면, {
...options,
@@ -2,7 +2,8 @@
* M02_MasterTemplete_DrawingCard.ts
* 항목 카드 「도면 정보」 미리보기 — 고칠 수 있으면 메뉴(제목줄 · 리본 · 패널 · 상태줄) 없이
* **단축키로 그리기 · 고치기**(전체 편집기 [도면 수정]과 같은 웹캐드 · 같은 단축키) · 카드 [저장]
* (전체 편집기와 같은 저장 길 = 그 항목 구조물 도면 파일 `도면` 칸만 갈아 끼움 · PLAN 31-4).
* (전체 편집기와 같은 저장 길 = 그 항목 구조물 도면 파일 `도면` · `더한장` 칸을 갈아 끼움 · PLAN 31-4).
* 여러 장은 공용 탭 줄(고르기만 · 105-3) — 저장은 지금 탭이 아니라 문서 전체(`getDoc`).
* [저장] · ? · 점(●) · 알림 글은 공용 카드 틀(`M02_MasterTemplete_CardShell` · 31-7) — 여기는 CAD 와 저장 길만.
* 고칠 수 없으면(읽기 층 · 저장 길 없는 자료 자리) 예전처럼 보기만.
* CAD 앱은 안 고침 — 메뉴는 같은 출처 iframe 에 스타일을 얹어 숨김.
@@ -11,10 +12,9 @@
import type { StructureDoc } from "./M02_MasterTemplete_Api_Fetch";
import type { SaveControl } from "./M02_MasterTemplete_CardShell";
import {
mountDrawingTemplate,
type DrawingTemplateDoc,
type DrawingTemplateHandle,
mountStructureSheets,
type DrawingTemplateOptions,
type StructureSheetsHandle,
} from "./M02_MasterTemplete_Drawing";
import type { ItemSource } from "./M02_MasterTemplete_ItemSource";
@@ -70,9 +70,11 @@ function mountStructure(
source: Where,
column: string,
hooks?: Pick<DrawingTemplateOptions, "onChanged" | "onSave">,
): DrawingTemplateHandle {
): StructureSheetsHandle {
const edit = !!hooks;
const handle = mountDrawingTemplate(host, doc.도면 as unknown as DrawingTemplateDoc, {
const sheets = doc as unknown as Parameters<typeof mountStructureSheets>[1];
// 여러 장(82-2) = 공용 탭 줄 고르기만(105-3) · 도각 `{{도면번호}}` = 장 도번
const handle = mountStructureSheets(host, sheets, {
readOnly: !edit,
name: `preview:${column}`, // 자동백업 칸은 전체 편집 화면과 갈라 둠
layer: source.layer,
@@ -82,21 +84,12 @@ function mountStructure(
originMarker: true, // 좌표 0,0 기준점 십자
noArea: true, // 작도 영역 칸 없음
frame: true, // 도각 = 보여주기만 · 외곽 좌하단 (0,0)(56장)
frameNumber: doc.도번, // 도각 `{{도면번호}}` = 1장 도번(82-2)
noImport: true, // 파일 불러오기는 도면 상세에서만(47-2)
pickTabs: true,
...hooks,
});
const frame = host.querySelector("iframe");
if (frame) hideChrome(frame, edit ? HIDE_EDIT : HIDE_VIEW);
// 여러 장(82-2) — 미리보기는 1장 · 장 수만 알림(다른 장은 도면 상세 탭에서)
const sheets = 1 + (doc.더한장?.length ?? 0);
if (sheets > 1) {
const badge = document.createElement("span");
badge.className = "m02-drawing__sheets";
badge.textContent = `장 ${sheets}`;
badge.title = `1장을 보는 중 · 모두 ${sheets}장 — 다른 장은 도면 상세에서`;
host.querySelector(".m02-drawing")?.append(badge);
}
return handle;
}
@@ -112,7 +105,7 @@ export function mountDrawingView(
}
export interface DrawingCardOptions {
/** 구조물 도면 문서 통째(`도번` · `도면` …) — 저장은 `도면` 칸만 갈아 끼움 */
/** 구조물 도면 문서 통째(`도번` · `도면` …) — 저장은 `도면` · `더한장` 칸만 갈아 끼움 */
doc: StructureDoc;
/** 읽은 판 — 저장 때 보냄(다르면 409) */
version: string | null;
@@ -136,10 +129,11 @@ export function mountDrawingCard(host: HTMLElement, opt: DrawingCardOptions): Dr
let doc = opt.doc;
let version = opt.version ?? "";
/** 전체 편집기 [저장]과 같은 길 — 읽은 문서에 `도면` 만 갈아 끼워 그 항목 파일에(실패는 던짐) */
async function doSave(drawing?: DrawingTemplateDoc): Promise<void> {
/** 전체 편집기 [저장]과 같은 길 — 읽은 문서에 `도면` · `더한장`(모든 장)을 갈아 끼워 그 항목 파일에
* (실패는 던짐) · CAD Ctrl+S 가 넘기는 지금 탭 장은 안 씀 — 2장 보다 저장해도 1장 그대로(105-3) */
async function doSave(): Promise<void> {
if (!write) return;
const next = { ...doc, 도면: (drawing ?? (await handle.getDoc())) as StructureDoc["도면"] };
const next = { ...doc, ...((await handle.getDoc()) as Pick<StructureDoc, "도면" | "더한장">) };
version = (await write("structure", opt.column, version, next)).판;
doc = next;
}
@@ -152,7 +146,7 @@ export function mountDrawingCard(host: HTMLElement, opt: DrawingCardOptions): Dr
edit
? {
onChanged: (dirty: boolean) => opt.saver.mark(dirty),
onSave: (drawing: DrawingTemplateDoc) => void opt.saver.run(() => doSave(drawing)),
onSave: () => void opt.saver.run(() => doSave()),
}
: undefined,
);