260710_0
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
/* B03 파일 입력 페이지 - 가로형 드롭존 + 슬롯 그리드 + 청크 업로드 */
|
||||
|
||||
import {
|
||||
CURRENT_PROJECT_ID_KEY,
|
||||
PROGRESS_UPDATE_INTERVAL_MS,
|
||||
@@ -9,15 +7,7 @@ import {
|
||||
UPLOAD_MAX_MB,
|
||||
} from "@config/config_frontend";
|
||||
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
|
||||
import {
|
||||
createButton,
|
||||
createCard,
|
||||
createTag,
|
||||
createWorkflowShell,
|
||||
hideLoadingOverlay,
|
||||
showLoadingOverlay,
|
||||
showToast,
|
||||
} from "@ui/ui_template_elements";
|
||||
import { createButton, createTag, createWorkflowShell, showToast } from "@ui/ui_template_elements";
|
||||
import {
|
||||
checkWF1AnalysisStatus,
|
||||
createUploadSession,
|
||||
@@ -27,6 +17,11 @@ import {
|
||||
} from "./B03_FileInput_Api_Fetch";
|
||||
import { navigateTo } from "../A00_Common/router";
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import {
|
||||
restoreB03ProjectState,
|
||||
saveB03UploadedFile,
|
||||
updateB03AnalysisState,
|
||||
} from "./B03_FileInput_State";
|
||||
import "./B03_FileInput_UI_Style.css";
|
||||
|
||||
type FileSlot = "las_laz" | "prj" | "tfw" | "tif" | "dxf";
|
||||
@@ -196,9 +191,8 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
});
|
||||
shell.root.classList.add("b03-file");
|
||||
|
||||
// 레이아웃 전면 리팩토링: 좌측/우측 패널 구분 없이 하나의 와이드 컴포넌트로 결합
|
||||
shell.leftPanel.remove(); // 기존 좁은 세로 영역 제거
|
||||
|
||||
shell.leftPanel.remove();
|
||||
|
||||
const contentContainer = document.createElement("div");
|
||||
contentContainer.className = "b03-file__main-layout";
|
||||
|
||||
@@ -247,8 +241,7 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
);
|
||||
const cssState = stateName === "failed" ? "error" : stateName;
|
||||
card.classList.add(`b03-file__card--${cssState}`);
|
||||
|
||||
// 배지 상태 연동 업데이트
|
||||
|
||||
const badgeContainer = card.querySelector<HTMLDivElement>(".b03-file__card-badge-container");
|
||||
if (badgeContainer) {
|
||||
badgeContainer.replaceChildren();
|
||||
@@ -542,16 +535,16 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
state.speedMbs > 0 ? (file.size - end) / 1024 / 1024 / state.speedMbs : null;
|
||||
|
||||
const stored: StoredUploadSession = {
|
||||
key: storageKey,
|
||||
projectId,
|
||||
slot: state.slot,
|
||||
fileName: file.name,
|
||||
fileSize: file.size,
|
||||
uploadSessionId: session,
|
||||
chunkSizeBytes,
|
||||
totalChunks,
|
||||
completedChunks: chunkIndex + 1,
|
||||
updatedAt: Date.now(),
|
||||
key: storageKey,
|
||||
projectId,
|
||||
slot: state.slot,
|
||||
fileName: file.name,
|
||||
fileSize: file.size,
|
||||
uploadSessionId: session,
|
||||
chunkSizeBytes,
|
||||
totalChunks,
|
||||
completedChunks: chunkIndex + 1,
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
localStorage.setItem(storageKey, JSON.stringify(stored));
|
||||
|
||||
@@ -564,6 +557,11 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
|
||||
const response = await finalizeUploadSession(projectId, session, totalChunks);
|
||||
localStorage.removeItem(storageKey);
|
||||
saveB03UploadedFile(projectId, {
|
||||
slot: state.slot,
|
||||
fileName: file.name,
|
||||
fileSize: file.size,
|
||||
});
|
||||
state.progressBytes = file.size;
|
||||
state.speedMbs =
|
||||
file.size / 1024 / 1024 / Math.max(0.001, (performance.now() - startedAt) / 1000);
|
||||
@@ -577,13 +575,11 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
||||
try {
|
||||
const status = await checkWF1AnalysisStatus(projectId);
|
||||
updateB03AnalysisState(projectId, status.status, status.progress_percent);
|
||||
if (status.status === "completed") {
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
// 상태 조회 실패는 무시하고 계속 폴링
|
||||
}
|
||||
// 5초마다 폴링 (최대 30분)
|
||||
} catch {}
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
}
|
||||
return false;
|
||||
@@ -599,24 +595,20 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
|
||||
pageError.textContent = "";
|
||||
const uploaded: UploadedFileResult[] = [];
|
||||
showLoadingOverlay();
|
||||
try {
|
||||
for (const state of targetStates) {
|
||||
uploaded.push(...(await uploadOneFile(activeProjectId, state)));
|
||||
}
|
||||
renderUploadResults(uploaded);
|
||||
showToast(L("B03_File_Upload_Success"), "success");
|
||||
hideLoadingOverlay();
|
||||
|
||||
// WF1 분석 상태 폴링 시작
|
||||
showToast("WF1 분석 진행 중... 완료되면 자동으로 이동합니다.", "info");
|
||||
showToast(L("B03_File_Analysis_InProgress"), "info");
|
||||
const analysisComplete = await pollWF1Analysis(activeProjectId);
|
||||
|
||||
if (analysisComplete) {
|
||||
// 분석 완료 시 B04 페이지로 이동
|
||||
navigateTo(ROUTES.B04_WF1_SURFACE);
|
||||
} else {
|
||||
showToast("분석이 진행 중입니다. 잠시 후 새로고침해주세요.", "warning");
|
||||
showToast(L("B03_File_Analysis_StillRunning"), "warning");
|
||||
}
|
||||
} catch (error) {
|
||||
const failed = targetStates.find((state) => state.uploadStatus === "uploading");
|
||||
@@ -624,8 +616,6 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
if (failed) showErrorMessage(failed.slot, detail);
|
||||
pageError.textContent = `${L("B03_File_Upload_Failed")} ${detail}`;
|
||||
showToast(L("B03_File_Upload_Failed"), "error");
|
||||
} finally {
|
||||
hideLoadingOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,5 +684,13 @@ export function renderB03FileInput(root: HTMLElement): void {
|
||||
for (const slot of slots.keys()) renderSlot(slot);
|
||||
void registerB03ServiceWorker();
|
||||
void detectPausedUploads();
|
||||
if (activeProjectId) {
|
||||
restoreB03ProjectState({
|
||||
projectId: activeProjectId,
|
||||
label: L("B03_File_Restore_State"),
|
||||
container: resumeBanner,
|
||||
poll: pollWF1Analysis,
|
||||
onComplete: () => navigateTo(ROUTES.B04_WF1_SURFACE),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user