- common_util_spreadsheet_node.ts areaTable: 시트 · 범위 → CAD 표 객체(표시 글 = formatValue · cellStyleAt · 병합 → colSpan/rowSpan · 범위 밖 병합 잘라냄 · 숨긴 행열 뺌 · 가로 정렬 · 굵게 · 열 너비 · 행 높이 비율 · 칸 수 한도 · 칸 key 「시트id!A1」 · style.연결 빈 글)
- 파이썬은 부르기만(common_util_spreadsheet.area_tables · 새 M02_Area_Table.py)
- POST /api/m02/layers/{층}/area/{열}/table {시트, 범위, 글자크기} → {표, 시트, 범위, 값} · 저장 안 함 · 층 읽기 권한
- 면적 저장(Store.write · 비우기 · 복사 · 프로젝트 층 길) 뒤 그 열 도면 연결표마다 표 칸 글 다시 · 마지막 값 갱신 · 표 없으면 기록 둠
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
85 lines
3.6 KiB
Python
85 lines
3.6 KiB
Python
"""면적산출 범위 → 도면 표(PLAN 41-1) — 변환은 Node 번들 한 벌(`common_util_spreadsheet_node.ts`
|
|
`areaTable` · 화면 표시 글과 같은 코드) · 여기는 부르기 · 도면 표 맞춤만(파이썬 이식 없음).
|
|
|
|
도면 문서(`structure/<열>.json`) 맨 위 `연결표` = `[{연결, 시트, 범위, 글자크기, 값}]` — 도면 표
|
|
`shapeData.style.연결` 이 `연결` 과 같은 표를 면적 [저장] 때 칸 글로 다시 적음(자리 · 크기 그대로 ·
|
|
칸 수가 바뀌면 열 너비 · 행 높이도 새로) · `값` = 마지막 칸 글(`{시트id!A1: 글}` · 다름 알림용).
|
|
도면에 그 표가 없으면 기록은 그대로 둠. 층 = `store.at(층 폴더)` · 권한은 부르는 쪽.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
from typing import Any
|
|
|
|
from common_util import common_util_spreadsheet as sheet_node
|
|
from common_util.common_util_json import atomic_write_json
|
|
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
|
|
|
logger = logging.getLogger(__name__)
|
|
LINKS = "연결표"
|
|
|
|
|
|
def to_table(column: str, sheet: str, rng: str, font: float | None = None) -> dict[str, Any]:
|
|
"""그 열 면적산출(저장본) 시트 · 범위 → `{표, 시트, 범위, 값}` — 저장 안 함 · 못 바꾸면 400."""
|
|
book = store.read("area", column)["문서"]
|
|
try:
|
|
got = sheet_node.area_tables([{"book": book, "시트": sheet, "범위": rng, "글자크기": font}])
|
|
except sheet_node.RecalcError as e:
|
|
raise store.StoreError(503, str(e)) from e
|
|
if not got[0].get("ok"):
|
|
raise store.StoreError(400, got[0].get("까닭"))
|
|
return {k: got[0][k] for k in ("표", "시트", "범위", "값")}
|
|
|
|
|
|
def _style_link(entity: Any) -> Any:
|
|
if not isinstance(entity, dict) or entity.get("type") != "Table":
|
|
return None
|
|
return ((entity.get("shapeData") or {}).get("style") or {}).get("연결")
|
|
|
|
|
|
def refresh_drawing(column: str) -> list[str]:
|
|
"""지금 층 그 열 도면의 연결표마다 칸 글 다시 · 마지막 값 갱신 → 칸을 간 표의 `연결` 목록."""
|
|
try:
|
|
drawing, area = store._path("structure", column), store._path("area", column)
|
|
except store.StoreError:
|
|
return []
|
|
if not drawing.is_file() or not area.is_file():
|
|
return []
|
|
doc = json.loads(drawing.read_bytes())
|
|
links = [x for x in doc.get(LINKS) or [] if isinstance(x, dict) and x.get("연결")]
|
|
if not links:
|
|
return []
|
|
book = json.loads(area.read_bytes())
|
|
asks = [
|
|
{"book": book, "시트": x.get("시트"), "범위": x.get("범위"), "글자크기": x.get("글자크기")}
|
|
for x in links
|
|
]
|
|
try:
|
|
results = sheet_node.area_tables(asks)
|
|
except sheet_node.RecalcError as e:
|
|
logger.warning("도면 표 맞춤 건너뜀 %s — %s", column, e)
|
|
return []
|
|
entities = (doc.get("도면") or {}).get("entities") or []
|
|
done: list[str] = []
|
|
for link, got in zip(links, results):
|
|
if not got.get("ok"):
|
|
continue
|
|
link["값"] = got["값"]
|
|
new = got["표"]["shapeData"]
|
|
for entity in entities:
|
|
if _style_link(entity) != link["연결"]:
|
|
continue
|
|
shape = entity["shapeData"]
|
|
if (len(shape.get("rowHeights") or []), len(shape.get("columnWidths") or [])) != (
|
|
len(new["rowHeights"]),
|
|
len(new["columnWidths"]),
|
|
):
|
|
shape["rowHeights"], shape["columnWidths"] = new["rowHeights"], new["columnWidths"]
|
|
shape["cells"] = new["cells"]
|
|
done.append(link["연결"])
|
|
with store._LOCK:
|
|
atomic_write_json(drawing, doc)
|
|
return done
|