From 425d618b73ff8efd80ca72d5a58f48398a7c29fb Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 31 Aug 2026 22:08:59 +0900 Subject: [PATCH] =?UTF-8?q?refactor(b08):=20=EC=88=98=EB=9F=89=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=86=A0=ED=83=80=EC=9E=85=EC=9D=84=20B08=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=EB=A1=9C=20=EC=9D=B4=EA=B4=80=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EC=95=B1=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EC=8B=A3?= =?UTF-8?q?=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - B07_DesignDetail_Quantity_Proto.py → B08_Quantity/B08_Quantity_Proto.py (git mv) - B07 라우터 include 2줄 원복, B08_Quantity_Router.py에 include - B08_Quantity_UI_Page.ts: 준비 중 셸 → createWorkflowLayout + 보고서 iframe 본문 - 접근: 대시보드 워크플로 칩 또는 #/b08-quantity (수량산출 칩은 stage 가드 적용) Co-Authored-By: Claude Opus 5 (1M context) --- B07_DesignDetail/B07_DesignDetail_Router.py | 5 -- .../B08_Quantity_Proto.py | 4 +- B08_Quantity/B08_Quantity_Router.py | 5 ++ B08_Quantity/B08_Quantity_UI_Page.ts | 55 ++++++++++++++++--- 4 files changed, 54 insertions(+), 15 deletions(-) rename B07_DesignDetail/B07_DesignDetail_Quantity_Proto.py => B08_Quantity/B08_Quantity_Proto.py (99%) diff --git a/B07_DesignDetail/B07_DesignDetail_Router.py b/B07_DesignDetail/B07_DesignDetail_Router.py index 34f239fe..3a01ed65 100644 --- a/B07_DesignDetail/B07_DesignDetail_Router.py +++ b/B07_DesignDetail/B07_DesignDetail_Router.py @@ -50,11 +50,6 @@ from config.config_db import get_db_pool logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/projects", tags=["B07 Design Detail"]) -# 수량 산출 프로토타입 (처분 가능) — 파일 삭제 시 아래 2줄도 함께 지운다. -from B07_DesignDetail.B07_DesignDetail_Quantity_Proto import proto_router # noqa: E402 - -router.include_router(proto_router) - _CROSS_ID = re.compile(r"^cross_(\d+)m$") _LONG_ID = re.compile(r"^longitudinal(?:_(\d+))?$") diff --git a/B07_DesignDetail/B07_DesignDetail_Quantity_Proto.py b/B08_Quantity/B08_Quantity_Proto.py similarity index 99% rename from B07_DesignDetail/B07_DesignDetail_Quantity_Proto.py rename to B08_Quantity/B08_Quantity_Proto.py index a8e315c3..778cb387 100644 --- a/B07_DesignDetail/B07_DesignDetail_Quantity_Proto.py +++ b/B08_Quantity/B08_Quantity_Proto.py @@ -1,6 +1,6 @@ -"""B07 수량 산출 프로토타입 (처분 가능 — disposable). +"""B08 수량 산출 프로토타입 (처분 가능 — disposable). -사용자 평가용 시안이다. 이 파일 + `B07_DesignDetail_Router.py`의 include 2줄이 전부라 +사용자 평가용 시안이다. 이 파일 + `B08_Quantity_Router.py`의 include 2줄이 전부라 마음에 안 들면 그대로 지우면 된다. 정본을 읽기만 하고 어디에도 쓰지 않는다. 페이지: GET /api/projects/quantity-proto/page — 프로젝트 목록 diff --git a/B08_Quantity/B08_Quantity_Router.py b/B08_Quantity/B08_Quantity_Router.py index 65af9f4b..12d6b85b 100644 --- a/B08_Quantity/B08_Quantity_Router.py +++ b/B08_Quantity/B08_Quantity_Router.py @@ -17,6 +17,11 @@ from config.config_db import get_db_pool logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/projects", tags=["B08 Quantity"]) +# 수량 산출 프로토타입 (처분 가능) — B08_Quantity_Proto.py 삭제 시 아래 2줄도 함께 지운다. +from B08_Quantity.B08_Quantity_Proto import proto_router # noqa: E402 + +router.include_router(proto_router) + @router.post("/{project_id}/quantity/confirm") async def confirm_quantity(project_id: UUID) -> JSONResponse: diff --git a/B08_Quantity/B08_Quantity_UI_Page.ts b/B08_Quantity/B08_Quantity_UI_Page.ts index c6463b8d..6bd569ee 100644 --- a/B08_Quantity/B08_Quantity_UI_Page.ts +++ b/B08_Quantity/B08_Quantity_UI_Page.ts @@ -2,23 +2,29 @@ * B08_Quantity_UI_Page.ts * 로그인 후 08: 5차 워크플로우 (수량 산출) * - * ⚠️ 본문 준비 중 — 워크플로우 셸 + 좌측 [확정] 버튼만 구성. + * ⚠️ 프로토타입 단계 — 본문은 서버 렌더 수량 보고서(B08_Quantity_Proto.py)를 + * iframe으로 싣는다. 평가 후 폐기/본구현 판단 (처분 가능 구성). * 확정 = 워크플로 stage 5(QUANTITY) 완료 처리 후 B09 설계도서로 이동. - * 수량 본문(B06 종횡단 기반 산출)은 후속 계획에서 구현한다. * ========================================================================== */ import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale"; import { createButton, showToast } from "@ui/ui_template_elements"; +import { createWorkflowLayout } from "@ui/ui_template_workflow_layout"; import { API_BASE_URL, CURRENT_PROJECT_ID_KEY } from "@config/config_frontend"; -import { renderPendingWorkflow, workflowSteps } from "../A00_Common/b_page_scaffold"; -import { goToWorkflowStage, WORKFLOW_STEP_ROUTES } from "../A00_Common/b_workflow_nav"; +import { workflowSteps } from "../A00_Common/b_page_scaffold"; +import { + fetchWorkflowState, + goToWorkflowStage, + WORKFLOW_STEP_ROUTES, + type WorkflowState, +} from "../A00_Common/b_workflow_nav"; /** locale 헬퍼 */ function L(key: keyof typeof ui_locales): string { return ui_locales[key][currentLanguageIndex]; } -/** stage 5(QUANTITY) 완료 요청 — 본문 미구현 상태의 유일한 백엔드 연동. */ +/** stage 5(QUANTITY) 완료 요청. */ async function confirmQuantityStage(projectId: string): Promise { const response = await fetch( `${API_BASE_URL}/projects/${encodeURIComponent(projectId)}/quantity/confirm`, @@ -29,14 +35,15 @@ async function confirmQuantityStage(projectId: string): Promise { } } -/** 좌측 패널: 준비 중 안내 + 하단 [확정] 액션 행 (다른 워크플로우 페이지와 동일 배치). */ +/** 좌측 패널: 프로토 안내 + 하단 [확정] 액션 행 (다른 워크플로우 페이지와 동일 배치). */ function buildQuantitySidePanel(projectId: string | null): HTMLElement { const panel = document.createElement("div"); panel.className = "b08-quantity__panel"; const note = document.createElement("p"); note.className = "b08-quantity__pending-note"; - note.textContent = L("B08_Quantity_Side_Pending"); + note.textContent = + "수량 산출 프로토타입 — 정본 일람과 원단위(참조 전용) 산출근거를 표시합니다."; panel.append(note); const confirmButton = createButton({ @@ -67,15 +74,47 @@ function buildQuantitySidePanel(projectId: string | null): HTMLElement { return panel; } +/** 본문: 서버 렌더 수량 보고서 iframe (프로젝트 미선택 시 목록 페이지). */ +function buildQuantityMain(projectId: string | null): HTMLElement { + const wrap = document.createElement("div"); + wrap.style.cssText = "height:100%;min-height:480px;display:flex;"; + const frame = document.createElement("iframe"); + frame.title = "수량 산출 프로토타입"; + frame.style.cssText = "flex:1;width:100%;border:0;background:#fff;"; + frame.src = projectId + ? `${API_BASE_URL}/projects/quantity-proto/page/${encodeURIComponent(projectId)}` + : `${API_BASE_URL}/projects/quantity-proto/page`; + wrap.append(frame); + return wrap; +} + /* ----------------------------------------------------------------------------- * 페이지 진입점 * -------------------------------------------------------------------------- */ export async function renderB08Quantity(root: HTMLElement): Promise { const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY); - await renderPendingWorkflow(root, { + let workflowState: WorkflowState | undefined; + if (projectId) { + try { + workflowState = await fetchWorkflowState(projectId); + } catch { + /* 조회 실패 시 stages 미전달 → 전체 이동 허용 */ + } + } + const layout = createWorkflowLayout({ title: L("B08_Quantity_Title"), steps: workflowSteps(), activeStep: 5, leftPanel: buildQuantitySidePanel(projectId), + mainContent: buildQuantityMain(projectId), + stages: workflowState?.stages, + currentStage: workflowState?.current_stage, + routes: WORKFLOW_STEP_ROUTES, + onStepClick: (stepIndex) => { + if (projectId) + goToWorkflowStage(projectId, WORKFLOW_STEP_ROUTES[stepIndex]); + }, }); + layout.root.classList.add("b-scaffold-wf"); + root.append(layout.root); }