From b15a945bf836fa6a5f011d22ee8396567262a5de Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 8 Oct 2026 12:10:50 +0900 Subject: [PATCH] =?UTF-8?q?feat(M02):=20=EB=A9=B4=EC=A0=81=20=E2=86=92=20?= =?UTF-8?q?=EB=8F=84=EB=A9=B4=20=ED=91=9C=20=EC=97=AC=EB=9F=AC=20=EC=9E=A5?= =?UTF-8?q?=20=E2=80=94=20=EC=83=88=20T=EB=B2=88=ED=98=B8=20=EB=AA=A8?= =?UTF-8?q?=EB=93=A0=20=EC=9E=A5=20=C2=B7=20=EC=97=B0=EA=B2=B0=ED=91=9C=20?= =?UTF-8?q?=EC=9E=A5=20=C2=B7=20=EC=A0=80=EC=9E=A5=20=EB=95=8C=20=EB=AA=A8?= =?UTF-8?q?=EB=93=A0=20=EC=9E=A5=20=ED=91=9C(82-3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK --- .../M02_MasterTemplete_AreaToDrawing.ts | 25 +++++++++++++------ resources/tester/test_m02_area_to_drawing.py | 21 +++++++++++++--- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/M02_MasterTemplete/M02_MasterTemplete_AreaToDrawing.ts b/M02_MasterTemplete/M02_MasterTemplete_AreaToDrawing.ts index da16b9918..e3221c45c 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_AreaToDrawing.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_AreaToDrawing.ts @@ -8,6 +8,8 @@ * 표 style.연결 = 연결 · 도면에서 지운 표는 기록에서 뺌(면적 [저장] 때 서버가 칸 글 · 값을 다시 적음 · 41-1) * ③ 도면을 열 때 — 연결표마다 지금 면적 값과 마지막 값이 다르면 알림 한 줄 + [업데이트](`updateTable`) * ④ 표 여러 개 — id 마다 한 줄 + * ⑤ 여러 장(82-3) — 놓을 장 = 지금 탭 · 새 T번호 = 모든 장에서 안 쓴 것 · 연결표 줄 `장` = 표가 놓인 장id + * (1장 = 빈 값) · 안 실린 장 표 갱신 = 도면 손잡이(받아 둔 장) · 면적 [저장] 때는 서버가 모든 장 * ========================================================================== */ import { API_BASE_URL } from "@config/config_frontend"; @@ -108,6 +110,12 @@ async function fetchTable(layer: Layer, column: string, spec: LinkSpec): Promise return data as AreaTable; } +/** 장마다 `[장id, entities]` — 1장 = 빈 값(서버 `drawing_sheets` 와 같음) */ +const sheetsOf = (doc: StructureDoc): [string, unknown[]][] => [ + ["", doc.도면?.entities ?? []], + ...(doc.더한장 ?? []).map((s): [string, unknown[]] => [s.장id, s.도면?.entities ?? []]), +]; + const isTable = (e: unknown): e is TableEntityJson => !!e && typeof e === "object" && (e as { type?: unknown }).type === "Table"; const linkOf = (e: TableEntityJson): string | null => { @@ -241,7 +249,8 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing { /** 다음 연결 id — 기록 · 도면 표지에 없는 가장 작은 T번호 */ const nextId = (doc: StructureDoc, taken: Set): string => { for (const row of doc.연결표 ?? []) taken.add(row.연결); - for (const e of doc.도면?.entities ?? []) if (isTable(e)) taken.add(linkOf(e) ?? ""); + for (const [, entities] of sheetsOf(doc)) + for (const e of entities) if (isTable(e)) taken.add(linkOf(e) ?? ""); let n = 1; while (taken.has(`T${n}`)) n += 1; return `T${n}`; @@ -323,12 +332,14 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing { waiting = false; const old = new Map((doc.연결표 ?? []).map((row) => [row.연결, row])); const rows: TableLink[] = []; - for (const e of doc.도면?.entities ?? []) { - if (!isTable(e)) continue; - const id = linkOf(e); - const row = id ? (old.get(id) ?? fresh.get(id)) : undefined; - if (!id || !row || rows.some((r) => r.연결 === id)) continue; - rows.push({ ...row, 값: latest.get(id) ?? row.값 }); + for (const [sheet, entities] of sheetsOf(doc)) { + for (const e of entities) { + if (!isTable(e)) continue; + const id = linkOf(e); + const row = id ? (old.get(id) ?? fresh.get(id)) : undefined; + if (!id || !row || rows.some((r) => r.연결 === id)) continue; + rows.push({ ...row, 장: sheet, 값: latest.get(id) ?? row.값 }); + } } // 기록이 없던 도면은 칸을 안 만듦(옛 문서 그대로) return rows.length || doc.연결표 ? { ...doc, 연결표: rows } : doc; diff --git a/resources/tester/test_m02_area_to_drawing.py b/resources/tester/test_m02_area_to_drawing.py index b0e1a1923..ff11fa2bd 100644 --- a/resources/tester/test_m02_area_to_drawing.py +++ b/resources/tester/test_m02_area_to_drawing.py @@ -112,6 +112,16 @@ globalThis.fetch = async (url, init) => { await slot.kids[0].on.click(); await new Promise((r) => setTimeout(r, 20)); ad.onDrawing(handle, { ...area, kind: "structure", name: "item2" }, drawing([])); + const other = placed.length - before; + // 여러 장(82-3) — 둘째 장 T2 가 있으니 새 표는 T3 · 저장 연결표 줄 장 = 표가 놓인 장id + ad.select({ 시트: "산출", 칸: "A1", 범위: "A1" }); + await slot.kids[0].on.click(); + await new Promise((r) => setTimeout(r, 20)); + const multi = drawing([table([["a"]], { 연결: "T1" })], [old]); + multi.더한장 = [{ 장id: "s2", 이름: "2장", 도면: { entities: [table([["b"]], { 연결: "T2" })] } }]; + ad.onDrawing(handle, { ...area, kind: "structure" }, multi); + const multiId = placed.at(-1)[1]; + const multiSaved = ad.withLinks({ ...multi, 연결표: [old, { ...old, 연결: "T2" }] }).연결표.map((r) => [r.연결, r.장]); // 빈 칸만 고른 범위 — 크기를 묻기 전에 막고 알림 · 도면 안 엶 now = [["", " "]]; const openedBefore = opened.length; @@ -119,7 +129,7 @@ globalThis.fetch = async (url, init) => { await slot.kids[0].on.click(); await new Promise((r) => setTimeout(r, 20)); const empty = { opened: opened.length - openedBefore, toast: toasts.at(-1) }; - console.log(JSON.stringify({ ro, buttons: slot.kids.length, sent, placed, notice: notice.map((x) => (typeof x === "string" ? x : x.label)), saved: saved.연결표, plain: "연결표" in plain, other: placed.length - before, waitPlaced, waitDropped, waitSaved: ad.waiting(), empty })); + console.log(JSON.stringify({ ro, buttons: slot.kids.length, sent, placed, notice: notice.map((x) => (typeof x === "string" ? x : x.label)), saved: saved.연결표, multiId, multiSaved, plain: "연결표" in plain, other, waitPlaced, waitDropped, waitSaved: ad.waiting(), empty })); })(); """ @@ -161,12 +171,17 @@ def test_다시_열면_다름_알림과_업데이트(got): def test_저장_연결표는_남은_표만(got): now = {"s1!B2": "1.5", "s1!C2": "2"} assert got["saved"] == [ - {"연결": "T1", "시트": "s1", "범위": "A1:A1", "글자크기": 3, "값": now}, # [업데이트] 값 - {"연결": "T2", "시트": "s1", "범위": "B2:C2", "글자크기": 2.5, "값": now}, + {"연결": "T1", "장": "", "시트": "s1", "범위": "A1:A1", "글자크기": 3, "값": now}, + {"연결": "T2", "장": "", "시트": "s1", "범위": "B2:C2", "글자크기": 2.5, "값": now}, ] assert got["plain"] is False +def test_여러_장_새_번호는_모든_장에서_안_쓴_것_연결표_장(got): + assert got["multiId"] == "T3" + assert got["multiSaved"] == [["T1", ""], ["T2", "s2"]] + + def test_다른_열_도면에는_안_놓음(got): assert got["other"] == 0