- 회사 정보 수정 API(PUT /dashboard/company) 및 수정 모달 신설, 회사 패널·회사 관리 표에 수정 진입점 추가 - 회사 등록·수정 입력칸 공용화 및 순서 조정 (사업자등록번호 > 회사명 > 대표자명 > 로고 > 주소) - 회사 등록 시 사업자번호·회사명으로 기존 회사 조회, 있으면 가입 신청으로 유도 - 주소 지도 미리보기 추가 — VWorld 주소검색·배경지도 타일을 서버가 중계(키 노출 방지), 지도 라이브러리 없이 타일 3x3 조합 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
73 lines
2.7 KiB
TypeScript
73 lines
2.7 KiB
TypeScript
import { API_BASE_URL } from "@config/config_frontend";
|
|
import { geocodeAddress } from "./B01_Dashboard_Api_Fetch";
|
|
|
|
/**
|
|
* 주소 지도 미리보기 (2026-09-06 사용자 지시).
|
|
*
|
|
* 지도 라이브러리를 얹지 않는다 — 배경지도 타일 3×3 장을 붙이고 가운데에 표식만 찍는다.
|
|
* 등록·수정 화면에서 "이 주소가 여기 맞나" 를 눈으로 보는 것이 목적이다.
|
|
*/
|
|
const ZOOM = 15;
|
|
const TILE = 256;
|
|
const GRID = 3;
|
|
|
|
function tileIndex(lat: number, lon: number): { x: number; y: number; dx: number; dy: number } {
|
|
const n = 2 ** ZOOM;
|
|
const rad = (lat * Math.PI) / 180;
|
|
const fx = ((lon + 180) / 360) * n;
|
|
const fy = ((1 - Math.log(Math.tan(rad) + 1 / Math.cos(rad)) / Math.PI) / 2) * n;
|
|
return { x: Math.floor(fx), y: Math.floor(fy), dx: fx - Math.floor(fx), dy: fy - Math.floor(fy) };
|
|
}
|
|
|
|
export function buildAddressMap(): {
|
|
root: HTMLElement;
|
|
show: (address: string) => Promise<void>;
|
|
} {
|
|
const root = document.createElement("div");
|
|
root.className = "b01-dashboard__map";
|
|
const note = document.createElement("p");
|
|
note.className = "b01-dashboard__modal-text";
|
|
note.textContent = "주소를 넣고 「지도 확인」을 누르십시오.";
|
|
root.append(note);
|
|
|
|
const show = async (address: string): Promise<void> => {
|
|
root.innerHTML = "";
|
|
if (!address.trim()) {
|
|
note.textContent = "주소를 먼저 입력하십시오.";
|
|
root.append(note);
|
|
return;
|
|
}
|
|
const point = await geocodeAddress(address).catch(() => null);
|
|
if (!point) {
|
|
note.textContent = "그 주소를 찾지 못했습니다. 도로명 또는 지번 주소로 다시 넣으십시오.";
|
|
root.append(note);
|
|
return;
|
|
}
|
|
const center = tileIndex(point.lat, point.lon);
|
|
const grid = document.createElement("div");
|
|
grid.className = "b01-dashboard__map-grid";
|
|
const half = Math.floor(GRID / 2);
|
|
for (let row = -half; row <= half; row += 1) {
|
|
for (let col = -half; col <= half; col += 1) {
|
|
const img = document.createElement("img");
|
|
img.src = `${API_BASE_URL}/dashboard/map/tile/${ZOOM}/${center.x + col}/${center.y + row}`;
|
|
img.width = TILE;
|
|
img.height = TILE;
|
|
img.alt = "";
|
|
grid.append(img);
|
|
}
|
|
}
|
|
const marker = document.createElement("span");
|
|
marker.className = "b01-dashboard__map-marker";
|
|
// 타일 판은 CSS 에서 절반으로 줄여 붙이므로 표식 자리도 절반으로 잡는다.
|
|
marker.style.left = `${(half + center.dx) * TILE * 0.5}px`;
|
|
marker.style.top = `${(half + center.dy) * TILE * 0.5}px`;
|
|
const frame = document.createElement("div");
|
|
frame.className = "b01-dashboard__map-frame";
|
|
frame.append(grid, marker);
|
|
root.append(frame);
|
|
};
|
|
|
|
return { root, show };
|
|
}
|