Files
Aislo/B01_Dashboard/B01_Dashboard_Map.py
T
eomsangdonandClaude Opus 5 bca78ee6bd feat(B01): 회사 정보 수정 화면·중복 조회·주소 지도 미리보기
- 회사 정보 수정 API(PUT /dashboard/company) 및 수정 모달 신설, 회사 패널·회사 관리 표에 수정 진입점 추가
- 회사 등록·수정 입력칸 공용화 및 순서 조정 (사업자등록번호 > 회사명 > 대표자명 > 로고 > 주소)
- 회사 등록 시 사업자번호·회사명으로 기존 회사 조회, 있으면 가입 신청으로 유도
- 주소 지도 미리보기 추가 — VWorld 주소검색·배경지도 타일을 서버가 중계(키 노출 방지), 지도 라이브러리 없이 타일 3x3 조합

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 11:29:00 +09:00

60 lines
2.0 KiB
Python

"""회사 주소 지도 — VWorld 주소검색·배경지도 타일 (2026-09-06 사용자 지시).
이미 쓰던 VWorld 키를 그대로 쓴다. 키가 화면으로 새지 않게 타일도 서버가 받아 넘긴다.
"""
from __future__ import annotations
import asyncio
import json
import urllib.parse
import urllib.request
from typing import Any
from B04_PreProcess.B04_PreProcess_Engine_VWorld import VWORLD_API_KEY
_GEOCODE_URL = "https://api.vworld.kr/req/address"
_TILE_URL = "http://api.vworld.kr/req/wmts/1.0.0/{key}/Base/{z}/{y}/{x}.png"
def _fetch(url: str, timeout: int = 5) -> bytes:
request = urllib.request.Request(url, headers={"User-Agent": "Aislo/1.0"})
with urllib.request.urlopen(request, timeout=timeout) as response:
return response.read()
def _geocode_sync(address: str) -> dict[str, Any] | None:
"""도로명으로 먼저 찾고, 없으면 지번으로 다시 찾는다."""
for address_type in ("ROAD", "PARCEL"):
query = urllib.parse.urlencode(
{
"service": "address",
"request": "getcoord",
"version": "2.0",
"crs": "epsg:4326",
"address": address,
"refine": "true",
"simple": "false",
"format": "json",
"type": address_type,
"key": VWORLD_API_KEY,
}
)
try:
body = json.loads(_fetch(f"{_GEOCODE_URL}?{query}").decode("utf-8"))
except Exception:
continue
point = (body.get("response") or {}).get("result", {}).get("point")
if point:
return {"lon": float(point["x"]), "lat": float(point["y"])}
return None
async def geocode_address(address: str) -> dict[str, Any] | None:
return await asyncio.to_thread(_geocode_sync, address.strip())
async def fetch_base_tile(z: int, x: int, y: int) -> bytes:
url = _TILE_URL.format(key=VWORLD_API_KEY, z=z, y=y, x=x)
return await asyncio.to_thread(_fetch, url)