- B03 파일 카드 = 카드 부품 · [선택] · [×] = 단추 · 아이콘 단추 · 진행 막대 · 오류 띠 = 부품 - B03 현황 · 이어올리기 · 예정노선 바뀜 = 띠 알림 · LAS 없이 설계 = 켜기 · 노선 · 지형 제목 = 패널 머리 - B03 · B02 죽은 CSS 걷음 · 날 색 → 공통 값 · 가이드 촬영 선택자 · 지킴 시험 test_553_1_pages Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
93 lines
2.6 KiB
TypeScript
93 lines
2.6 KiB
TypeScript
import { createBanner } from "@ui/ui_template_banner";
|
|
|
|
export type B03AnalysisStatus = "pending" | "in_progress" | "completed" | "failed";
|
|
|
|
export interface B03StoredFileState {
|
|
slot: string;
|
|
fileName: string;
|
|
fileSize: number;
|
|
status: "completed" | "failed";
|
|
}
|
|
|
|
export interface B03ProjectState {
|
|
projectId: string;
|
|
uploadedAt: number;
|
|
files: B03StoredFileState[];
|
|
analysisStatus: B03AnalysisStatus;
|
|
analysisProgress: number;
|
|
lastCheckedAt: number;
|
|
}
|
|
|
|
function key(projectId: string): string {
|
|
return `b03_project_state_${projectId}`;
|
|
}
|
|
|
|
export function loadB03ProjectState(projectId: string): B03ProjectState | null {
|
|
const raw = localStorage.getItem(key(projectId));
|
|
if (!raw) return null;
|
|
try {
|
|
return JSON.parse(raw) as B03ProjectState;
|
|
} catch {
|
|
localStorage.removeItem(key(projectId));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function saveB03UploadedFile(
|
|
projectId: string,
|
|
file: { slot: string; fileName: string; fileSize: number },
|
|
): B03ProjectState {
|
|
const current = loadB03ProjectState(projectId);
|
|
const nextFiles = (current?.files ?? []).filter((item) => item.slot !== file.slot);
|
|
nextFiles.push({ ...file, status: "completed" });
|
|
const next: B03ProjectState = {
|
|
projectId,
|
|
uploadedAt: current?.uploadedAt ?? Date.now(),
|
|
files: nextFiles,
|
|
analysisStatus: "pending",
|
|
analysisProgress: 0,
|
|
lastCheckedAt: Date.now(),
|
|
};
|
|
localStorage.setItem(key(projectId), JSON.stringify(next));
|
|
return next;
|
|
}
|
|
|
|
export function updateB03AnalysisState(
|
|
projectId: string,
|
|
status: B03AnalysisStatus,
|
|
progress: number,
|
|
): B03ProjectState {
|
|
const current = loadB03ProjectState(projectId);
|
|
const next: B03ProjectState = {
|
|
projectId,
|
|
uploadedAt: current?.uploadedAt ?? Date.now(),
|
|
files: current?.files ?? [],
|
|
analysisStatus: status,
|
|
analysisProgress: progress,
|
|
lastCheckedAt: Date.now(),
|
|
};
|
|
localStorage.setItem(key(projectId), JSON.stringify(next));
|
|
return next;
|
|
}
|
|
|
|
export function restoreB03ProjectState(options: {
|
|
projectId: string;
|
|
label: string;
|
|
container: HTMLElement;
|
|
poll: (projectId: string) => Promise<boolean>;
|
|
onComplete: () => void;
|
|
}): void {
|
|
const state = loadB03ProjectState(options.projectId);
|
|
if (!state) return;
|
|
options.container.replaceChildren();
|
|
options.container.append(
|
|
createBanner({ tone: "info", text: `${options.label}: ${state.analysisProgress}%` }),
|
|
);
|
|
options.container.classList.add("is-visible");
|
|
if (state.analysisStatus === "in_progress" || state.analysisStatus === "pending") {
|
|
void options.poll(options.projectId).then((completed) => {
|
|
if (completed) options.onComplete();
|
|
});
|
|
}
|
|
}
|