Files
Aislo/E01_StabRegister/E01_StabRegister_UI_Page.ts
T
eomsangdonandClaude Opus 5.5 244a2bf8eb feat(528-2): 대시보드 표 종류 열 · 종류별 단계 막대 · 「받은 예정노선」 구역
- 프로젝트 표 「종류」 열(임도설계 · 예정노선 · 안정성평가 · 사방설계 · 칸 없음 = 임도)
- 단계 막대 = 종류별(ROAD B03~B09 그대로 · PLAN D02~D04 · STABILITY E02~E05) · 누름 = 그 단계 화면
- 받은 예정노선(회사관리자 · 사용자 · 받은 것 있을 때만) = 예정노선 · 연도 · 연결 상태 · 업데이트 배지 · [보기] = D02 · [연결] 자리만(531-3)
- E01 [등록] 고르기 칸 setError 없음 오류 걷음(목록 비면 단추 꺼짐)
- tsconfig D0* · E0* → 폴더 안까지(D0*/**/*) — 앞 판은 폴더 안 파일을 안 잡아 타입 검사가 빠졌음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 19:57:13 +09:00

99 lines
3.5 KiB
TypeScript

/* =============================================================================
* E01_StabRegister_UI_Page.ts
* E01 안정성평가 생성(요구서 345 4-1 · PLAN 528-2) — 대상 임도 고르기(GET /api/e01/source-candidates
* = 같은 회사 · B06 완료만) · 이름(손대기 전 = 「원본 이름 안정성평가」).
* [등록] = POST /api/e01/project → 현재 프로젝트 · E02 로.
* ========================================================================== */
import "../B02_ProjRegister/B02_ProjRegister_UI_Style.css";
import { API_BASE_URL, ROUTES } from "@config/config_frontend";
import {
createButton,
createCard,
createInputField,
createSelectField,
el,
} from "@ui/ui_template_elements";
import { createGeneralLayout } from "@ui/ui_template_general_layout";
import { createHelpButton } from "@ui/ui_template_help";
import { t } from "@ui/ui_template_locale";
import { createGroupProject } from "../A00_Common/group_workflow";
import { navigateTo } from "../A00_Common/router";
interface SourceProject {
project_id: string;
name: string;
region?: string | null;
project_year?: number | null;
}
export function renderE01StabRegister(root: HTMLElement): void {
const source = createSelectField({ label: t("DE_Reg_Source"), options: [] });
const name = createInputField({ label: t("DE_Reg_Name") });
const note = el("p", { className: "ui-general-block__empty" });
let sources: SourceProject[] = [];
let typed = false;
const autoName = (): string => {
const picked = sources.find((p) => p.project_id === source.select.value);
return picked ? `${picked.name} ${t("DE_New_Stability")}` : "";
};
name.input.addEventListener("input", () => (typed = name.input.value.trim() !== ""));
source.select.addEventListener("change", () => {
if (!typed) name.input.value = autoName();
});
const submitButton = createButton({
label: t("DE_Reg_Submit"),
variant: "filled",
onClick: () => {
// 목록이 비면 단추가 꺼져 있음 — 고른 값은 늘 있음
void createGroupProject(
"/e01/project",
{ project_name: name.input.value.trim() || null, source_project_id: source.select.value },
ROUTES.E02_STAB_GROUND,
);
},
});
submitButton.disabled = true;
void (async () => {
const response = await fetch(`${API_BASE_URL}/e01/source-candidates`, {
credentials: "include",
});
sources = response.ok
? ((await response.json()) as { projects: SourceProject[] }).projects
: [];
source.setOptions(
sources.map((p) => ({
value: p.project_id,
text: [p.name, p.region, p.project_year].filter(Boolean).join(" · "),
})),
);
note.textContent = sources.length ? "" : t("DE_Reg_SourceEmpty");
submitButton.disabled = !sources.length;
if (!typed) name.input.value = autoName();
})();
const grid = document.createElement("div");
grid.className = "b02-proj__grid";
grid.append(source.root, name.root);
const actions = document.createElement("div");
actions.className = "ui-general-block__actions b02-proj__actions";
actions.append(
createHelpButton(),
createButton({
label: t("Common_Btn_Cancel"),
variant: "ghost",
onClick: () => navigateTo(ROUTES.B01_ACCOUNT),
}),
submitButton,
);
const layout = createGeneralLayout({
pageClass: "b02-proj",
title: t("DE_Reg_StabTitle"),
subtitle: t("DE_Reg_StabSubtitle"),
content: createCard({ body: [grid, note, actions], raised: true }),
});
root.append(layout.root);
}