feat(802-3): M01 단가산출 기초 수식 문서 화면 — 왼쪽 기호 식 · 오른쪽 값 식 · 빈 문서 시작 · 연결 고르기
- 공용 화면 A00_Common/formula_doc_*(M01 · 뒤에 M02 = 길 앞머리만 바꿈) — 옛 수식 나무 화면은 M01 에서 걷음(M02 는 그대로) - 보이는 수식 그 자리 고침(공용 editEq · 전체 고르기 = 한 줄 글) · 분수 · 첨자 · 만약 = 탄 갈래만 · 반올림 자리 숨김 · 값 식 단위 - 값 식 숫자 누름 = 그 자리 값 · 기호 값 누름 = 정의 줄 · 정의 영역 = 기호 : 이름 — 연결(키 · 값 · 단위 없음 · 탄 갈래로 닿는 기호만) - 새 기호 = 정의 필요 → 숫자 · 선택 · 입력 · 요소 · 표 · 단가산출 · 식 연결 · 기호 · 첨자 · 이름 고침 · 정의 지움 - 금액 = 경쟁사 꼴 이름 : 단가 × 수량 = 금액 · 묶음 하나 = 계 · 둘 이상 = 가. 이름 소계 + 합계 · 단가산출 연결 펼침 = 그 문서 식 · 값 식 - 셈 = 브라우저 계산기 즉시 · 연결 값 = 서버 기록 캐시(common_util_formula_doc_cache.ts ↔ master_doc_record.py) · 없는 연결만 뒤에서 미리 셈 - 서버 길 GET /api/m01/logic/doc · POST preview · save(서버가 정본으로 다시 셈 · 수식 문서 파일에 씀) · links · GET table (M01_MasterData_Doc.py) - 연결 대상 안 고른 연결(표 · 요소 · 단가산출) = 연결 끊김 표지(파이썬 · TS 짝 가드 — 서버 500 걷음) - 시험 test_802_3_doc_screen 11(읽기 · 빈 문서 · 저장 = 서버 다시 셈 · 관리자 아니면 막힘 · 지움 견딤 · 표지 갈래 · 후보) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -285,7 +285,9 @@ class _Run:
|
||||
return Stop(f"「{name}」 연결 갈래 「{kind}」", "연결 꼴", name)
|
||||
|
||||
def sub(self, payload: dict, name: str):
|
||||
key = payload["키"]
|
||||
key = str(payload.get("키") or "")
|
||||
if not key: # 고르는 중 — 표지(예외 아님) · 짝 TS sub
|
||||
raise Broken("단가산출 고르지 않음")
|
||||
if key in self.stack or len(self.stack) > DEEP:
|
||||
return Stop(f"단가산출 부름 돌고 돎 — {' → '.join([*self.stack, key])}", "순환", name)
|
||||
doc = self.links.doc(key)
|
||||
|
||||
@@ -122,6 +122,8 @@ class Links:
|
||||
raise mc.Broken(str(e)) from None
|
||||
|
||||
def table(self, p: dict):
|
||||
if not p.get("표") or not p.get("칸"): # 고르는 중 — 표지(예외 아님)
|
||||
raise mc.Broken("표 · 칸 고르지 않음")
|
||||
table = self._get(p["표"])
|
||||
if "줄" not in table or "조건" not in table:
|
||||
raise mc.Broken(f"「{p['표']}」 표 아님")
|
||||
@@ -135,6 +137,8 @@ class Links:
|
||||
return _cell(row[p["칸"]], p["칸"])
|
||||
|
||||
def element(self, p: dict):
|
||||
if not p.get("키") and p.get("재료") is None: # 고르는 중 — 표지(예외 아님)
|
||||
raise mc.Broken("요소 고르지 않음")
|
||||
env = {}
|
||||
if p.get("지역") is not None:
|
||||
env[mm.REGION] = p["지역"]
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""수식 문서 연결 기록 — 화면 캐시로 싣는 연결 값(PLAN 802-3 · 꼴 `_수식문서_틀.md`).
|
||||
|
||||
서버 셈(`master_doc_calc.calc`)이 쓴 요소 값 · 표 · 단가산출 문서를 적어 화면에 실음 —
|
||||
브라우저가 같은 계산기(`common_util_formula_doc_calc.ts`)로 네트워크 없이 다시 셈.
|
||||
화면 짝 = `common_util/common_util_formula_doc_cache.ts`(기록 → `DocLinks`).
|
||||
- 요소 = 부른 꼴(payload) 그대로 + {값 | 빈 | 끊김}
|
||||
- 표 = 표 통째(조건 · 값칸 · 줄) — 옵션 · 입력이 바뀌어도 화면이 줄을 찾음 · 표 아님 = {끊김}
|
||||
- 단가산출 = 문서 통째(없으면 null)
|
||||
`prefetch` = 식 · 옵션과 무관하게 글로 적힌 표 · 단가산출 키를 미리 담음(구멍 `{…}` 든 키는 셈 때만).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import master_doc_calc as mc
|
||||
import master_formula as mf
|
||||
|
||||
|
||||
class Rec:
|
||||
"""`Links` 를 감싸 부른 연결을 적음 — `out()` = 화면 캐시."""
|
||||
|
||||
def __init__(self, links):
|
||||
self.links = links
|
||||
self.요소: dict[str, dict] = {}
|
||||
self.표: dict[str, dict | None] = {}
|
||||
self.문서: dict[str, dict | None] = {}
|
||||
self.이름: dict[str, str] = {}
|
||||
|
||||
def element(self, p: dict):
|
||||
key = repr(sorted(p.items(), key=lambda kv: kv[0]))
|
||||
try:
|
||||
got = self.links.element(p)
|
||||
except mc.Gap as e:
|
||||
self.요소[key] = {"p": p, "빈": str(e)}
|
||||
raise
|
||||
except mc.Broken as e:
|
||||
self.요소[key] = {"p": p, "끊김": str(e)}
|
||||
raise
|
||||
self.요소[key] = {"p": p, "값": got}
|
||||
return got
|
||||
|
||||
def see_table(self, ref: str) -> None:
|
||||
if ref in self.표:
|
||||
return
|
||||
try:
|
||||
table = self.links.master.get(ref)
|
||||
except mf.FormulaError as e:
|
||||
self.표[ref] = {"끊김": str(e)}
|
||||
return
|
||||
if "줄" not in table or "조건" not in table:
|
||||
self.표[ref] = {"끊김": f"「{ref}」 표 아님"}
|
||||
return
|
||||
keep = ("키", "원문번호", "이름", "조건", "범위규칙", "값칸", "줄")
|
||||
self.표[ref] = {k: table[k] for k in keep if k in table}
|
||||
|
||||
def table(self, p: dict):
|
||||
self.see_table(str(p.get("표")))
|
||||
return self.links.table(p)
|
||||
|
||||
def doc(self, key: str):
|
||||
got = self.links.doc(key)
|
||||
self.문서[key] = got
|
||||
return got
|
||||
|
||||
def name(self, ref: str) -> None:
|
||||
"""키 → 이름(화면 연결 글 · DB 키는 안 보임)."""
|
||||
if not ref or "{" in ref or ref in self.이름:
|
||||
return
|
||||
doc = self.links.docs.get(ref)
|
||||
if doc is not None:
|
||||
self.이름[ref] = str(doc.get("이름") or "")
|
||||
return
|
||||
try:
|
||||
row = self.links.master.get(ref)
|
||||
except mf.FormulaError:
|
||||
return
|
||||
self.이름[ref] = " ".join(str(x) for x in (row.get("이름"), row.get("규격")) if x)
|
||||
|
||||
def prefetch(self, doc: dict, seen: set | None = None) -> None:
|
||||
seen = set() if seen is None else seen
|
||||
for v in doc.get("변수") or []:
|
||||
link = v.get("연결") or {}
|
||||
kind, ref = link.get("갈래"), str(link.get("키") or link.get("표") or "")
|
||||
if kind in ("표", "요소", "단가산출"):
|
||||
self.name(ref)
|
||||
if not ref or "{" in ref:
|
||||
continue
|
||||
if kind == "표":
|
||||
self.see_table(ref)
|
||||
elif kind == "단가산출" and ref not in seen:
|
||||
seen.add(ref)
|
||||
sub = self.doc(ref)
|
||||
if sub:
|
||||
self.prefetch(sub, seen)
|
||||
|
||||
def out(self) -> dict:
|
||||
return {
|
||||
"요소": list(self.요소.values()),
|
||||
"표": self.표,
|
||||
"문서": self.문서,
|
||||
"이름": self.이름,
|
||||
}
|
||||
Reference in New Issue
Block a user