Merge remote-tracking branch 'origin/sub_laptop_2' into sub_laptop_3

This commit is contained in:
2026-10-27 20:06:11 +09:00
4 changed files with 49 additions and 2 deletions
+21 -2
View File
@@ -4,6 +4,7 @@
* 조작(끌기 · 지도 누름 · 경위도 입력) = sessionStorage 캐시 · [저장] · [>] = PUT 정본(서버가 TM 셈)
* · [>] = 저장 성공 뒤 D03 · 자동저장 없음(CLAUDE.md 5장).
* 산림청이 아니면(지정 회사 = 보기만) 끌기 · 누름 · 입력 · [저장] 없음 · [>] = 그냥 D03.
* 지도 [일반][위성](560-3) = 카카오 HYBRID · 고른 값 = 화면 취향(`aislo:pref:`) 기억.
* ========================================================================== */
import "./D02_PlanBase_UI_Style.css";
@@ -18,8 +19,10 @@ import {
} from "@ui/ui_template_elements";
import { createPanelCard } from "@ui/ui_template_collapsible";
import { createText } from "@ui/ui_template_text";
import { editMap, type MapPin } from "@ui/ui_template_kakao_map";
import { editMap, type MapPin, type MapType } from "@ui/ui_template_kakao_map";
import { createSegment } from "@ui/ui_template_segment";
import { t } from "@ui/ui_template_locale";
import { readByKey, writeByKey } from "../A00_Common/b_page_state";
import { mountGroupStep } from "../A00_Common/group_workflow";
import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch";
import { navigateTo } from "../A00_Common/router";
@@ -40,6 +43,7 @@ interface PointsView {
const KOREA_CENTER: [number, number] = [127.8, 36.3];
const DIGITS = 7; // 경위도 소수 7 자리 ≈ 1 cm
const PREF_MAP_TYPE = "aislo:pref:d02.map.type";
const cacheKey = (projectId: string): string => `d02_points_${projectId}`;
@@ -103,7 +107,22 @@ export async function renderD02PlanBase(root: HTMLElement): Promise<void> {
place(active, { lon, lat });
},
});
mapHost.append(map.root);
const mapType = (readByKey(PREF_MAP_TYPE) === "HYBRID" ? "HYBRID" : "ROADMAP") as MapType;
map.setType(mapType);
const typePick = createSegment({
options: [
{ value: "ROADMAP", label: t("D02_Map_Normal") },
{ value: "HYBRID", label: t("D02_Map_Satellite") },
],
value: mapType,
ariaLabel: t("D02_Map_Type"),
onChange: (value) => {
map.setType(value as MapType);
writeByKey(PREF_MAP_TYPE, value);
},
});
typePick.root.classList.add("d02-map__type");
mapHost.append(map.root, typePick.root);
function place(index: number, at: LonLat): void {
points[index] = { lon: +at.lon.toFixed(DIGITS), lat: +at.lat.toFixed(DIGITS) };
+9
View File
@@ -1,8 +1,17 @@
/* D02 기준 지정(529-3 · 560-2) — 메인 지도 = 본문 높이 가득 · 좌 시점 · 종점 표 */
.d02-map {
position: relative;
height: calc(100dvh - var(--app-header-h));
}
/* 560-3 바탕 [일반][위성] — 지도 위 오른쪽 위 */
.d02-map__type {
position: absolute;
top: var(--spacing-8);
right: var(--spacing-8);
z-index: 2;
}
.d02-map .ui-kakao-map,
.d02-map .ui-kakao-map__box {
height: 100%;
+16
View File
@@ -6,6 +6,7 @@
* (.env JS 키 · 공개용 · 도메인 등록으로 막힘) · 키 없음 · 못 뜸 = 안내 한 줄 + 사진 올리기
* 길 선 = 부르는 쪽이 준 [위도, 경도] 목록 · 처음 한 번만 맞춤(153 · 그 뒤 보기 그대로)
* (244-10) SDK 못 받음(도메인 미등록 401) = 지금 주소(location.origin) 등록 안내 한 줄
* (560-3) 바탕 종류 = `setType("ROADMAP" | "HYBRID")`(위성 + 지명) · 단추는 부르는 쪽 부품
* ========================================================================== */
import "./ui_template_kakao_map.css";
@@ -29,6 +30,7 @@ interface KMap {
relayout(): void;
getBounds(): { contain(p: LatLng): boolean };
panTo(p: LatLng): void;
setMapTypeId(id: number): void;
}
interface KOverlay {
setMap(map: KMap | null): void;
@@ -52,8 +54,12 @@ interface KakaoMaps {
addListener(target: object, type: string, fn: (e: { latLng: LatLng }) => void): void;
};
CustomOverlay: new (o: { position: LatLng; content: HTMLElement; yAnchor: number }) => KOverlay;
MapTypeId: Record<MapType, number>;
}
/** 바탕 지도 종류 — 일반 · 위성 + 지명 */
export type MapType = "ROADMAP" | "HYBRID";
let sdk: Promise<KakaoMaps> | null = null;
/** SDK 한 번 싣기 — 키 없음 · 못 받음 = NO_MAP 으로 거절(다음 부름 때 다시) */
@@ -111,6 +117,8 @@ export interface EditMap {
colors?: string[],
focus?: string,
) => void;
/** 바탕 종류(지도가 아직 없으면 만들 때 씀) */
setType: (type: MapType) => void;
}
/** 고르는 지도 — 움직일 표지 끌기 = onMove · 지도 누름 = onClick(있을 때만) · 점 없으면 center(경도, 위도) */
@@ -126,6 +134,8 @@ export function editMap(opts: {
let map: KMap | null = null;
let drawn: KOverlay[] = [];
let fitted = false; // 153 — 처음 한 번만 맞춤 · 그 뒤 고름 · 끌기는 보기(중심 · 줌) 그대로
let type: MapType = "ROADMAP";
let mapTypes: KakaoMaps["MapTypeId"] | null = null;
const set = (
pins: MapPin[],
@@ -147,6 +157,8 @@ export function editMap(opts: {
box.hidden = false;
if (!map) {
map = new maps.Map(box, { center: first, level: 7 });
mapTypes = maps.MapTypeId;
map.setMapTypeId(mapTypes[type]);
if (opts.onClick)
maps.event.addListener(map, "click", (e) =>
opts.onClick!(e.latLng.getLng(), e.latLng.getLat()),
@@ -222,5 +234,9 @@ export function editMap(opts: {
return {
root: el("div", { className: "ui-kakao-map", children: [hint, box] }),
set,
setType: (next) => {
type = next;
if (map && mapTypes) map.setMapTypeId(mapTypes[next]);
},
};
}
+3
View File
@@ -129,6 +129,9 @@ export const ui_locales_de = {
D02_Lat: ["위도", "Lat"],
D02_Pick_Point: ["지도에 놓을 지점 고르기", "Pick the point to place on the map"],
D02_Map_Hint: ["지도를 눌러 지점을 놓습니다.", "Click the map to place a point."],
D02_Map_Type: ["바탕 지도", "Base map"],
D02_Map_Normal: ["일반", "Map"],
D02_Map_Satellite: ["위성", "Satellite"],
D02_View_Only: [
"보기 전용 — 지점은 산림청만 고칩니다.",
"View only — only the Forest Service edits points.",