Files
Aislo/B08_Quantity/B08_Quantity_UI_Page.ts
T
eomsangdonandClaude Fable 5 6e195afb69 feat(B07,B08): 워크플로 순서 교환 — 상세설계를 수량산출 앞으로
횡단설계(B06) 다음을 상세설계 → 수량산출 → 설계도서 순으로 재배열하고,
폴더 번호가 흐름과 일치하도록 이름을 맞바꾼다.

- B08_DesignDetail → B07_DesignDetail, B07_Quantity → B08_Quantity
  (파일 접두어·식별자·라우트·locale 키 전량 스왑)
- STAGE_KEYS 4=DESIGN_DETAIL, 5=QUANTITY 스왑 + 라우터 stage 리터럴 교체
- CAD 마운트 /b08-cad → /b07-cad (main.py·vite proxy·iframe URL),
  openwebcad Toolbar 라벨 B07로 수정 후 재빌드
- 유지: openwebcad postMessage 프로토콜 aislo:b08:*·패키지명(내부 식별자)
- 기존 프로젝트 storage 폴더 rename + project_manifest 갱신,
  DB project_workflow_stages stage_no 4↔5 행 스왑 완료

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 16:16:46 +09:00

82 lines
3.2 KiB
TypeScript

/* =============================================================================
* B08_Quantity_UI_Page.ts
* 로그인 후 08: 5차 워크플로우 (수량 산출)
*
* ⚠️ 본문 준비 중 — 워크플로우 셸 + 좌측 [확정] 버튼만 구성.
* 확정 = 워크플로 stage 5(QUANTITY) 완료 처리 후 B09 설계도서로 이동.
* 수량 본문(B06 종횡단 기반 산출)은 후속 계획에서 구현한다.
* ========================================================================== */
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
import { createButton, showToast } from "@ui/ui_template_elements";
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";
/** locale 헬퍼 */
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
}
/** stage 5(QUANTITY) 완료 요청 — 본문 미구현 상태의 유일한 백엔드 연동. */
async function confirmQuantityStage(projectId: string): Promise<void> {
const response = await fetch(
`${API_BASE_URL}/projects/${encodeURIComponent(projectId)}/quantity/confirm`,
{ method: "POST", credentials: "include" },
);
if (!response.ok) {
throw new Error(`quantity confirm failed: ${response.status}`);
}
}
/** 좌측 패널: 준비 중 안내 + 하단 [확정] 액션 행 (다른 워크플로우 페이지와 동일 배치). */
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");
panel.append(note);
const confirmButton = createButton({
label: L("B08_Quantity_Btn_Confirm"),
variant: "filled",
onClick: () => {
if (!projectId) {
showToast(L("B08_Quantity_Confirm_Failed"), "error");
return;
}
confirmButton.disabled = true;
confirmQuantityStage(projectId)
.then(() => {
showToast(L("B08_Quantity_Confirm_Success"), "success");
goToWorkflowStage(projectId, WORKFLOW_STEP_ROUTES[6]);
})
.catch(() => {
showToast(L("B08_Quantity_Confirm_Failed"), "error");
confirmButton.disabled = false;
});
},
});
const actions = document.createElement("div");
actions.className = "b08-quantity__actions ui-sidebar-actions";
actions.append(confirmButton);
panel.append(actions);
return panel;
}
/* -----------------------------------------------------------------------------
* 페이지 진입점
* -------------------------------------------------------------------------- */
export async function renderB08Quantity(root: HTMLElement): Promise<void> {
const projectId = localStorage.getItem(CURRENT_PROJECT_ID_KEY);
await renderPendingWorkflow(root, {
title: L("B08_Quantity_Title"),
steps: workflowSteps(),
activeStep: 5,
leftPanel: buildQuantitySidePanel(projectId),
});
}