Merge remote-tracking branch 'origin/sub_laptop_3' into sub_laptop_1

This commit is contained in:
2026-10-05 19:08:37 +09:00
9 changed files with 316 additions and 13 deletions
@@ -19,7 +19,13 @@ import {
showToast,
} from "@ui/ui_template_elements";
import { openModal } from "@ui/ui_template_modal";
import { getActiveOwner, type Layer, type StructureDoc } from "./M02_MasterTemplete_Api_Fetch";
import {
getActiveOwner,
readTemplate,
type Layer,
type StructureDoc,
} from "./M02_MasterTemplete_Api_Fetch";
import type { LinkOptions } from "../A00_Common/spreadsheet/spreadsheet";
import type { Selection } from "./M02_MasterTemplete_UI_Main";
/** 표 칸 하나(CAD `TableCell` 꼴에서 쓰는 것만) */
@@ -71,6 +77,8 @@ const TEXT = {
noPlace: "이 도면 화면은 표 놓기를 아직 못 함",
stale: "면적산출 값이 바뀐 표 {n}개",
update: "업데이트",
tag: "{id} 도면",
tip: "도면 표 {id} 로 보낸 범위 {range} · 글자 {size}",
updated: "표 {n}개를 지금 면적 값으로 바꿈 — [저장]하면 남음",
} as const;
@@ -112,6 +120,22 @@ const sameValues = (a: Record<string, string> = {}, b: Record<string, string> =
return ka.length === Object.keys(b).length && ka.every((k) => a[k] === b[k]);
};
/** 면적 시트에 겹쳐 보일 「도면으로 보낸 범위」 — 같은 열 도면 `연결표` 에서(받기 실패 = 없음 · 조용히) */
export async function sentRanges(at: Selection): Promise<NonNullable<LinkOptions["표시범위"]>> {
try {
const got = await readTemplate(at.layer, "structure", at.name, at.projectId);
const rows = (got.문서 as StructureDoc | undefined)?.연결표 ?? [];
return rows.map((row) => ({
시트: row.시트,
범위: row.범위,
이름: fill(TEXT.tag, "id", row.연결),
설명: fill(fill(fill(TEXT.tip, "id", row.연결), "range", row.범위), "size", row.글자크기),
}));
} catch {
return [];
}
}
export interface AreaToDrawingOptions {
/** 같은 페이지에서 그 열 도면 상세를 엶(`UI_Main.open`) */
open: (sel: Selection) => Promise<void>;
@@ -160,7 +160,9 @@ export async function pillsFor(
...(p.자재 ? { 자재: p.자재 } : {}),
고정: true,
}));
return 항목.length ? { links: { 항목, 모드: "입력" } } : none(TEXT.noPills);
// 받기 성공 = 목록 확정 — 이 목록에 없는 연결 알약만 ⚠(받기 실패 때는 표시 안 함)
const links: LinkOptions = { 항목, 모드: "입력", 확정: true };
return 항목.length ? { links } : { ...none(TEXT.noPills), links };
} catch (error) {
return none(fill(TEXT.pillsFailed, why(error)));
}
@@ -28,7 +28,7 @@ import {
} from "./M02_MasterTemplete_Structure";
import { askSettle } from "./M02_MasterTemplete_TreePanel_Dialogs";
import { buildAreaPanel, type AreaPanel } from "./M02_MasterTemplete_AreaPanel";
import { createAreaToDrawing } from "./M02_MasterTemplete_AreaToDrawing";
import { createAreaToDrawing, sentRanges } from "./M02_MasterTemplete_AreaToDrawing";
import { detailHelp, HELP_TITLE } from "./M02_MasterTemplete_CardHelp";
import { helpParts } from "./M02_MasterTemplete_CardShell";
import { isPrecombo } from "./M02_MasterTemplete_UI_Side_Precombo";
@@ -274,13 +274,14 @@ export function createMain(
): Promise<void> {
const mine = seq;
try {
const [{ createSpreadsheet }, pills] = await Promise.all([
const [{ createSpreadsheet }, pills, sent] = await Promise.all([
import("../A00_Common/spreadsheet/spreadsheet"),
pillsFor(kind, at.name),
sentRanges(at), // 도면으로 보낸 범위 — 시트 위 점선 테두리
]);
if (mine !== seq) return;
if (pills.notice) showNotice([pills.notice]);
const links: LinkOptions = pills.links;
const links: LinkOptions = { ...pills.links, 표시범위: sent };
const handle: SpreadsheetHandle = createSpreadsheet(
host,
doc as Parameters<typeof createSpreadsheet>[1],