feat(M02): 면적 값 고침이 저장 전 도면 패널 표에 바로 비침 · 이름 · 보내기 취소는 [저장] 때 서버가 기록(112-1·112-2)
- 112-1 면적 표 변환을 공용 파일(spreadsheet_area_table.ts)로 빼 서버 Node 와 브라우저가 한 벌로 씀 · 도면 패널이 칸 고침마다(값 바뀐 표만 · 펼친 동안만) CAD 연결 표 갈기를 보기 전용 갈음(preview)으로 보냄 - 112-2 보낸 범위 이름은 도면 [저장] 요청 안에서 서버가 면적 문서에 둠(놓기만 하고 저장 안 하면 안 생김) · [보내기 취소]는 화면에서만 빼고 면적 [저장] 때 서버가 연결표 줄 · 이름을 뺌 · /name · /unlink 길 삭제 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
This commit is contained in:
@@ -22,7 +22,8 @@ from M02_MasterTemplete.M02_Template_Layers import drawing_sheets
|
||||
logger = logging.getLogger(__name__)
|
||||
LINKS = "연결표"
|
||||
DROPPED = "지운연결"
|
||||
# common_util_spreadsheet_node.ts `NAME_GONE` 과 같은 글자 — 이름이 지워졌을 때 까닭
|
||||
CANCELS = "보내기취소" # 면적 [저장] 문서의 임시 칸 — 저장 안 함(112-2)
|
||||
# spreadsheet_area_table.ts `NAME_GONE` 과 같은 글자 — 이름이 지워졌을 때 까닭
|
||||
NAME_GONE = "이름없음"
|
||||
|
||||
|
||||
@@ -43,35 +44,69 @@ def to_table(
|
||||
return {k: got[0][k] for k in ("표", "시트", "범위", "값")}
|
||||
|
||||
|
||||
def define_name(column: str, sheet: str, rng: str, name: str) -> None:
|
||||
"""처음 도면으로 보낼 때(T 번호 정해진 뒤) 면적 시트에 보낸 범위 이름을 더함/갱신(104-1) —
|
||||
`applyLinked`(행열 넣기 · 지우기)가 이 이름을 그대로 따라가게 함."""
|
||||
book = store.read("area", column)["문서"]
|
||||
try:
|
||||
got = sheet_node.define_names([{"book": book, "시트": sheet, "범위": rng, "이름": name}])
|
||||
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("까닭"))
|
||||
def fresh_names(path: Any, doc: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""도면 [저장] 문서의 새 연결 줄(저장돼 있던 파일에 없던 `연결`) 중 `이름`이 있는 것 —
|
||||
면적 문서에 둘 이름(112-2)."""
|
||||
old: set[Any] = set()
|
||||
if path.is_file():
|
||||
old = {
|
||||
x.get("연결")
|
||||
for x in json.loads(path.read_bytes()).get(LINKS) or []
|
||||
if isinstance(x, dict)
|
||||
}
|
||||
rows = [x for x in doc.get(LINKS) or [] if isinstance(x, dict)]
|
||||
return [x for x in rows if x.get("이름") and x.get("연결") not in old]
|
||||
|
||||
|
||||
def define_names(column: str, rows: list[dict[str, Any]]) -> None:
|
||||
"""도면 [저장] 요청 안에서(112-2) 새 연결 줄의 보낸 범위 이름을 면적 시트에 더함/갱신(104-1) —
|
||||
`applyLinked`(행열 넣기 · 지우기)가 이 이름을 따라가게 함. 면적 문서가 없거나 못 풀면 건너뜀
|
||||
(이름 없는 연결은 적힌 범위로 감)."""
|
||||
path = store._path("area", column)
|
||||
with store._LOCK:
|
||||
atomic_write_json(path, got[0]["book"]) # 디스크 글 자체가 책(`store.read` 의 "문서")
|
||||
|
||||
|
||||
def unlink(column: str, 연결: str) -> None:
|
||||
"""이름표 메뉴 [보내기 취소](104-3) — 연결표에서 그 줄만 빼고 저장 · 도면 표(CAD 엔티티)는 그대로 남음
|
||||
(지우기는 도면에서 — `withLinks` 가 다음 저장 때 표 없는 기록을 거둠)."""
|
||||
path = store._path("structure", column)
|
||||
if not path.is_file():
|
||||
if not rows or not path.is_file():
|
||||
return
|
||||
book = json.loads(path.read_bytes())
|
||||
try:
|
||||
for row in rows:
|
||||
ask = {
|
||||
"book": book,
|
||||
"시트": row.get("시트"),
|
||||
"범위": row.get("범위"),
|
||||
"이름": row["이름"],
|
||||
}
|
||||
got = sheet_node.define_names([ask])[0]
|
||||
if got.get("ok"):
|
||||
book = got["book"]
|
||||
else:
|
||||
logger.warning(
|
||||
"보낸 범위 이름 건너뜀 %s %s — %s", column, row["이름"], got.get("까닭")
|
||||
)
|
||||
except sheet_node.RecalcError as e:
|
||||
logger.warning("보낸 범위 이름 건너뜀 %s — %s", column, e)
|
||||
return
|
||||
with store._LOCK:
|
||||
doc = json.loads(path.read_bytes())
|
||||
rows = doc.get(LINKS) or []
|
||||
kept = [x for x in rows if x.get("연결") != 연결]
|
||||
if len(kept) == len(rows):
|
||||
return
|
||||
doc[LINKS] = kept
|
||||
atomic_write_json(path, doc)
|
||||
atomic_write_json(path, book) # 디스크 글 자체가 책(`store.read` 의 "문서")
|
||||
|
||||
|
||||
def apply_cancels(column: str, doc: Any) -> tuple[Any, list[str]]:
|
||||
"""면적 [저장] 문서의 `보내기취소[]`(112-2 · 이름표 메뉴 [보내기 취소])를 떼어 냄 — 그 연결 줄의 `이름`을
|
||||
문서의 이름정의에서 뺌 → (문서, 연결 목록). 줄을 빼는 일은 `refresh_drawing(unlink=…)`."""
|
||||
if not isinstance(doc, dict) or CANCELS not in doc:
|
||||
return doc, []
|
||||
ids = [x for x in doc[CANCELS] or [] if isinstance(x, str)]
|
||||
doc = {k: v for k, v in doc.items() if k != CANCELS}
|
||||
path = store._path("structure", column)
|
||||
rows = json.loads(path.read_bytes()).get(LINKS) or [] if ids and path.is_file() else []
|
||||
names = {x.get("이름") for x in rows if isinstance(x, dict) and x.get("연결") in ids}
|
||||
names.discard(None)
|
||||
if names:
|
||||
doc["시트"] = [
|
||||
{**s, "이름정의": [n for n in s["이름정의"] if n.get("이름") not in names]}
|
||||
if isinstance(s, dict) and s.get("이름정의")
|
||||
else s
|
||||
for s in doc.get("시트") or []
|
||||
]
|
||||
return doc, ids
|
||||
|
||||
|
||||
def _style_link(entity: Any) -> Any:
|
||||
@@ -80,8 +115,10 @@ def _style_link(entity: Any) -> Any:
|
||||
return ((entity.get("shapeData") or {}).get("style") or {}).get("연결")
|
||||
|
||||
|
||||
def refresh_drawing(column: str) -> list[str]:
|
||||
def refresh_drawing(column: str, unlink: Any = ()) -> list[str]:
|
||||
"""지금 층 그 열 도면(모든 장)의 연결표마다 칸 글 다시 · 마지막 값 갱신 → 칸을 간 표의 `연결` 목록.
|
||||
`unlink` = 면적 [저장] 때 [보내기 취소]한 연결 — 그 줄을 연결표에서 뺌
|
||||
(도면 표는 남음 · 알림 없음 · 112-2).
|
||||
이름(104-1)이 있으면 그 이름이 지금 가리키는 범위로 `범위` 도 갱신 — 이름이 지워졌으면(범위가
|
||||
통째로 지워짐) 그 연결을 끊고(도면 표는 남음) `지운연결` 목록에 적어 다음에 열 때 알림."""
|
||||
try:
|
||||
@@ -91,8 +128,13 @@ def refresh_drawing(column: str) -> list[str]:
|
||||
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("연결")]
|
||||
every = [x for x in doc.get(LINKS) or [] if isinstance(x, dict) and x.get("연결")]
|
||||
links = [x for x in every if x["연결"] not in unlink]
|
||||
if not links:
|
||||
if len(links) != len(every): # 취소로 줄이 다 빠짐
|
||||
doc[LINKS] = links
|
||||
with store._LOCK:
|
||||
atomic_write_json(drawing, doc)
|
||||
return []
|
||||
book = json.loads(area.read_bytes())
|
||||
asks = [
|
||||
@@ -139,7 +181,7 @@ def refresh_drawing(column: str) -> list[str]:
|
||||
if dropped:
|
||||
doc[LINKS] = kept
|
||||
doc[DROPPED] = sorted(set(doc.get(DROPPED) or []) | set(dropped))
|
||||
elif len(kept) != len(links):
|
||||
elif len(kept) != len(every):
|
||||
doc[LINKS] = kept
|
||||
with store._LOCK:
|
||||
atomic_write_json(drawing, doc)
|
||||
|
||||
Reference in New Issue
Block a user