auto: 2026-10-26 03:18 (ESD_LAPTOP)

This commit is contained in:
2026-10-26 03:18:32 +09:00
parent 7d08c04cb5
commit 08fc324e99
9 changed files with 89 additions and 13 deletions
+11 -2
View File
@@ -4,6 +4,7 @@
* 지점 = 경계점 목록 P0..Pn(연도 i = P(i) → P(i+1)) · 직전 종점 = 다음 시점이 모양 그대로.
* 조작(끌기 · 지도 누름 · 경위도 입력) = sessionStorage 캐시 · [저장] · [>] = PUT 정본(서버가 TM 셈)
* · [>] = 저장 성공 뒤 D03 · 자동저장 없음(CLAUDE.md 5장).
* 산림청이 아니면(지정 회사 = 보기만) 끌기 · 누름 · 입력 · [저장] 없음 · [>] = 그냥 D03.
* ========================================================================== */
import "./D02_PlanBase_UI_Style.css";
@@ -19,6 +20,7 @@ import { createPanelCard } from "@ui/ui_template_collapsible";
import { editMap, type MapPin } from "@ui/ui_template_kakao_map";
import { t } from "@ui/ui_template_locale";
import { mountGroupStep } from "../A00_Common/group_workflow";
import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch";
import { navigateTo } from "../A00_Common/router";
interface LonLat {
@@ -79,6 +81,7 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
let view: PointsView | null = null;
let points: Array<LonLat | null> = [];
let active: number | null = null; // 지도 누름이 놓을 지점
let editable = false; // 산림청만 고침
const years = (): number[] => (view ? view.years.map((y) => y.year) : []);
const pointName = (i: number): string => {
@@ -99,6 +102,7 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
center: () => KOREA_CENTER,
onMove: (key, lon, lat) => place(Number(key), { lon, lat }),
onClick: (lon, lat) => {
if (!editable) return;
if (active === null) return showToast(t("D02_Pick_Point"), "info");
place(active, { lon, lat });
},
@@ -115,7 +119,7 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
/** focus = 고친 지점(보기 밖이면 그리로) · 빈 값 = 보기 그대로 */
function drawMap(focus = ""): void {
const pins: MapPin[] = points.flatMap((p, i) =>
p ? [{ key: String(i), name: pointName(i), lon: p.lon, lat: p.lat, movable: true }] : [],
p ? [{ key: String(i), name: pointName(i), lon: p.lon, lat: p.lat, movable: editable }] : [],
);
const lines: Array<Array<[number, number]>> = [];
const colors: string[] = [];
@@ -142,6 +146,7 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
lat.placeholder = t("D02_Lat");
lon.value = p ? String(p.lon) : "";
lat.value = p ? String(p.lat) : "";
lon.disabled = lat.disabled = !editable;
lon.dataset.point = lat.dataset.point = String(i);
lon.dataset.axis = "lon";
lat.dataset.axis = "lat";
@@ -164,6 +169,7 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
},
});
pick.title = pick.ariaLabel = t("D02_Pick_Point");
pick.hidden = !editable;
const row = el("div", {
className: `d02-points__row${active === i ? " is-active" : ""}`,
children: [
@@ -227,15 +233,18 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
left.addEventListener("ui-step-nav", (event) => {
if ((event as CustomEvent<number>).detail !== 1) return;
event.stopPropagation();
if (!editable) return navigateTo(ROUTES.D03_PLAN_ANALYSIS);
void store().then((ok) => ok && navigateTo(ROUTES.D03_PLAN_ANALYSIS));
});
try {
editable = !!(await fetchSessionUser())?.is_forest_service;
save.hidden = !editable;
adopt(await request<PointsView>(`/projects/${projectId}/plan/points`));
const cached = JSON.parse(sessionStorage.getItem(cacheKey(projectId)) ?? "null") as {
points?: Array<LonLat | null>;
} | null;
if (cached?.points?.length === points.length) points = cached.points;
if (editable && cached?.points?.length === points.length) points = cached.points;
active = firstEmpty();
paint();
} catch (error) {