feat(b09): 운반 단가 모달 · 로직 미리보기 길 (253-3)
- POST /api/projects/{id}/estimation/logic-preview — 로직 한 산근을 프로젝트 단가로 풀어 계산 절차 글 · 단가(저장 안 함)
- 「운반 단가」 모달 — 단가산출 이름 · [변경] · [다른 종류] · 옵션 값(로직 입력 + 사이클 입력 · 표 고르기 CC000054~058) · 계산 절차(사이클 식 + 미리보기)
- 여는 곳 = B08 거리이정표 표 우클릭 [단가연결] · B09 설계내역서 운반공 줄 단가연결 · 운반 항목에 거리(dist)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
[저장] — 사용자 값 · 책에 없는 새 단가 줄만 굳힘 → 서버가 정본으로 다시 셈
|
||||
POST /api/projects/{id}/estimation/prices
|
||||
[단가 갱신] — 수요 단가 전부를 지금 M01 값으로 새로 굳힘
|
||||
POST /api/projects/{id}/estimation/logic-preview {code, given, rate, picks}
|
||||
「운반 단가」 모달 계산 절차(253-3) — 그 로직 한 산근을 프로젝트 단가로 풀어 글 줄 · 단가 ·
|
||||
저장 안 함(`render_sangeun_text` 를 `Sangeun.Solver` 로)
|
||||
POST /api/projects/{id}/estimation/library {kind, layer, owner, key}
|
||||
설계내역서 연결 고르기(204-2) — 서고 구조물조합 · 사전조합을 프로젝트 사본으로
|
||||
(있으면 그대로) → {폴더, 만듦, key = 대가 블록 id, payload} ·
|
||||
@@ -25,7 +28,7 @@ from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from B08_Quantity.B08_Quantity_Haul import haul_rows
|
||||
from B08_Quantity.B08_Quantity_Milestone_Calc import compute_milestone
|
||||
@@ -206,6 +209,43 @@ async def refresh_prices(project_id: UUID) -> dict[str, Any]:
|
||||
return await payload(project_id, root)
|
||||
|
||||
|
||||
class PreviewBody(BaseModel):
|
||||
code: str = Field(min_length=1, max_length=40)
|
||||
given: dict[str, Any] = Field(default_factory=dict)
|
||||
rate: float | None = None
|
||||
picks: dict[str, Any] | None = None
|
||||
|
||||
|
||||
def logic_preview(root: Path, body: PreviewBody) -> dict[str, Any]:
|
||||
"""로직 한 산근 미리보기 — 단가 = 굳힌 책(없는 줄 = 지금 M01) · 사용자 대비표 고름."""
|
||||
src = {"code": body.code, "given": sangeun._clean_given(body.given), "rate": body.rate,
|
||||
"picks": body.picks} # fmt: skip
|
||||
hands = [("preview", "미리보기", src)]
|
||||
keys = sangeun.hand_resource_keys({"haul_refs": {"preview": {"tab": "logic", **src}}})
|
||||
user = store.read_user(root)
|
||||
base = compute_base(prices.build_inputs(store.read_book(root), keys), user)
|
||||
block = sangeun.Solver(base).add(sangeun.hand_whole(hands), src, None)
|
||||
text = [
|
||||
*block["head"],
|
||||
*(t for ln in block["lines"] for t in ln.get("text") or []),
|
||||
block["foot"],
|
||||
]
|
||||
return {
|
||||
"name": block["name"],
|
||||
"lines": [t for t in text if t],
|
||||
"unit": block["unit"],
|
||||
"price": block["sum"],
|
||||
"parts": {p: block[p] for p in sangeun.PARTS},
|
||||
"why": block["why"],
|
||||
}
|
||||
|
||||
|
||||
@router.post("/{project_id}/estimation/logic-preview")
|
||||
async def preview_logic(project_id: UUID, body: PreviewBody) -> dict[str, Any]:
|
||||
root = await _project_root(project_id)
|
||||
return await asyncio.to_thread(logic_preview, root, body)
|
||||
|
||||
|
||||
class LibraryBody(BaseModel):
|
||||
kind: str
|
||||
layer: str
|
||||
|
||||
Reference in New Issue
Block a user