feat(M01): 관리자 화면 로직 칸 — 일위대가표(호표) 고치기 · 시험 계산 · 요소 찾기 창
- 화면: 왼쪽 로직 목록(원문·장·이름 찾기·막힘) / 가운데 머리·받을 값·호표·중간 값·덧줄·끝수 / 오른쪽 시험 계산 - 고친 것은 캐시에 쌓고 [저장] 한 번에 · [고친 것 버리기] · 줄 더하기·지우기 · 로직 새로 만들기·지우기 - 진입은 mountM01Logic(host) — 공용 진입 파일(sub_laptop_3 몫)이 한 줄로 붙임 - 서버: 로직 하나에 단가 자동(prices) · 요소 찾기(GET /elements) · 저장 전 시험 계산(calc 에 row·file) - 계약 문서 갱신 · 시험 1개 더함(9개 통과) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
This commit is contained in:
@@ -173,7 +173,8 @@ def logic(book: str, key: str) -> dict:
|
||||
continue
|
||||
for row in data.get("줄") or []:
|
||||
if str(row.get("열쇠")) == key:
|
||||
reasons = cm.mf.check_logic(cm.mf.Master(files), book, row)[0]
|
||||
whole = cm.mf.Master(files)
|
||||
reasons = cm.mf.check_logic(whole, book, row)[0]
|
||||
_, version = read(name)
|
||||
return {
|
||||
"file": name,
|
||||
@@ -181,15 +182,67 @@ def logic(book: str, key: str) -> dict:
|
||||
"logic": row,
|
||||
"blocked": bool(reasons),
|
||||
"reasons": reasons,
|
||||
"prices": _prices(whole, row),
|
||||
}
|
||||
raise StoreError(404, f"없는 로직 「{book}:{key}」")
|
||||
|
||||
|
||||
def _brief(ref: str, row: dict) -> dict:
|
||||
return {"ref": ref, **{k: row.get(k) for k in ("이름", "규격", "단위", "값", "값칸")}}
|
||||
|
||||
|
||||
def _prices(whole, row: dict) -> dict:
|
||||
"""호표 요소 → 요소 줄 요약(단가 자동 칸) · `{이름}` 낀 열쇠·하위 로직은 계산 때 정해짐."""
|
||||
out = {}
|
||||
for item in row.get("호표") or []:
|
||||
ref = str(item.get("요소", ""))
|
||||
if item.get("종류") != "로직" and "{" not in ref:
|
||||
try:
|
||||
out[ref] = _brief(ref, whole.get(ref))
|
||||
except cm.mf.FormulaError:
|
||||
out[ref] = None
|
||||
return out
|
||||
|
||||
|
||||
def elements(group: str, q: str, limit: int) -> dict:
|
||||
"""요소 찾기 창 — 그룹 전체에서 이름·열쇠 찾기 · `ref` 는 식에 그대로 넣는 `그룹:원문:열쇠`."""
|
||||
if group not in cm.mf.GROUPS:
|
||||
raise StoreError(404, f"없는 그룹 「{group}」")
|
||||
hits = []
|
||||
for name, data in cm.load(folder=FOLDER).items():
|
||||
if data.get("그룹") != group:
|
||||
continue
|
||||
for row in data.get(items_key(data)) or []:
|
||||
if _hit(row, q):
|
||||
ref = f"{group}:{data.get('원문')}:{row.get('열쇠')}"
|
||||
hits.append({**_brief(ref, row), "file": name})
|
||||
return {"total": len(hits), "items": hits[: min(max(limit, 1), 200)]}
|
||||
|
||||
|
||||
# ── 시험 계산 ──────────────────────────────────────────────────────────
|
||||
def calc(book: str, key: str, inputs: dict) -> dict:
|
||||
def _swap(files: dict, book: str, key: str, row: dict, file: str | None) -> None:
|
||||
"""저장 전 시험 — 메모리 사본에서 그 로직을 고친 줄로 바꿈(없으면 `file` 에 더함)."""
|
||||
row = _dec(row)
|
||||
for name, data in _logic_files(files):
|
||||
if data.get("원문") == book:
|
||||
items = data.get("줄") or []
|
||||
for i, old in enumerate(items):
|
||||
if str(old.get("열쇠")) == key:
|
||||
items[i] = row
|
||||
return
|
||||
if file not in files or files[file].get("그룹") != "로직":
|
||||
raise StoreError(404, f"없는 로직 파일 「{file}」")
|
||||
files[file].setdefault("줄", []).append(row)
|
||||
|
||||
|
||||
def calc(book: str, key: str, inputs: dict, row: dict | None = None, file: str | None = None):
|
||||
given = {k: _dec(v) for k, v in inputs.items()}
|
||||
files = cm.load(folder=FOLDER)
|
||||
if row is not None:
|
||||
_swap(files, book, key, row, file)
|
||||
key = str(row.get("열쇠", key))
|
||||
try:
|
||||
result = cm.calc(cm.load(folder=FOLDER), f"{book}:{key}", given)
|
||||
result = cm.calc(files, f"{book}:{key}", given)
|
||||
except (cm.mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueError) as e:
|
||||
return {"ok": False, "reason": str(e) or type(e).__name__}
|
||||
if "결과" in result:
|
||||
|
||||
Reference in New Issue
Block a user