관제 화면 문구와 화물 패널 정리

This commit is contained in:
2026-06-07 02:23:32 +09:00
parent eecdb35541
commit fb4b0e4643
3 changed files with 220 additions and 169 deletions

View File

@@ -33,6 +33,7 @@ const elements = {
driversTab: document.getElementById("driversTab"),
locationsPanel: document.getElementById("locationsPanel"),
driversPanel: document.getElementById("driversPanel"),
mapPanel: document.querySelector(".map-panel"),
vehicleList: document.getElementById("vehicleList"),
mapMessage: document.getElementById("mapMessage"),
totalCount: document.getElementById("totalCount"),
@@ -1359,7 +1360,7 @@ function createDestinationMarkerElement(location) {
function createDestinationMarkerHtml(location) {
const metrics = getRouteMetrics(location);
const destinationName = getDestinationName(location) || "목적지";
const etaText = metrics ? formatEtaTime(metrics.estimatedArrivalAt) : "ETA";
const etaText = metrics ? formatEtaTime(metrics.estimatedArrivalAt) : "도착시간 미정";
return `
<span class="route-destination-pin">도착</span>
@@ -1380,7 +1381,7 @@ function refreshSelectedDetail(location) {
}
if (state.activeDetailMode === "cargo") {
renderCargoFocusPanel(location);
hideRouteFocusPanel();
showInfoOverlay(location);
return;
}
@@ -1436,14 +1437,14 @@ function renderMarkerActionPanel(location) {
const distance = metrics ? formatDistance(metrics.remainingDistanceKm) : "-";
const eta = metrics ? formatEtaTime(metrics.estimatedArrivalAt) : "-";
elements.markerActionEyebrow.textContent = "차량 선택";
elements.markerActionEyebrow.textContent = "차량";
elements.markerActionTitle.textContent = `${title} · ${vehicleType.label}`;
elements.markerActionMeta.textContent = [driver, status.label, formatSpeed(location.speed)].filter(Boolean).join(" · ");
elements.markerActionSummary.replaceChildren(
createMarkerActionSummaryItem("화물", getCargoSummary(location)),
createMarkerActionSummaryItem("목적지", getRouteSummary(location)),
createMarkerActionSummaryItem("남은 거리", distance),
createMarkerActionSummaryItem("도착 예정", eta)
createMarkerActionSummaryItem("도착 시간", eta)
);
}
@@ -1501,7 +1502,7 @@ function showVehicleCargo(location) {
hideMarkerActionPanel();
elements.historyDrawer.classList.add("is-hidden");
clearRouteOverlay();
renderCargoFocusPanel(location);
hideRouteFocusPanel();
render();
updateMarkerSelectionClasses();
showInfoOverlay(location);
@@ -1549,35 +1550,27 @@ function setRouteFocusContent(eyebrow, title, meta) {
elements.routeFocusMeta.textContent = meta;
}
function renderCargoFocusPanel(location) {
const vehicleType = getVehicleType(location);
const product = getCargoName(location) || "미등록";
const quantity = getCargoQuantity(location) || "수량 미등록";
const weight = getCargoWeight(location) || "중량 미등록";
const route = getRouteSummary(location);
setRouteFocusContent(
"화물 정보",
`${location.vehicleNo || location.driverId} · ${vehicleType.label}`,
`${product} · ${quantity} · ${weight} · ${route}`
);
function hideRouteFocusPanel() {
elements.routeFocusPanel.classList.remove("is-active");
setRouteFocusEyebrow("차량 정보");
elements.routeFocusTitle.textContent = "";
elements.routeFocusMeta.textContent = "";
}
function renderCurrentLocationPanel(location) {
const vehicleType = getVehicleType(location);
const coordinate = `${formatCoordinate(location.latitude)}, ${formatCoordinate(location.longitude)}`;
setRouteFocusContent(
"현재 위치",
"지도 중심",
`${location.vehicleNo || location.driverId} · ${vehicleType.label}`,
`${formatSpeed(location.speed)} · ${coordinate} · ${formatDateTime(location.receivedAt)}`
);
}
function renderRouteFocusPanel(location) {
setRouteFocusEyebrow("선택 경로");
setRouteFocusEyebrow("차량 정보");
if (!location) {
elements.routeFocusPanel.classList.remove("is-active");
elements.routeFocusTitle.textContent = "차량 선택";
elements.routeFocusMeta.textContent = "선택하면 경로와 도착 예정 시간이 표시됩니다.";
hideRouteFocusPanel();
return;
}
@@ -1615,7 +1608,7 @@ async function loadLocationHistory(location) {
state.activeDetailMode = "history";
hideMarkerActionPanel();
elements.historyDrawer.classList.remove("is-hidden");
elements.historyTitle.textContent = `${location.vehicleNo || location.driverId} 위치 이력`;
elements.historyTitle.textContent = `${location.vehicleNo || location.driverId} 수신 이력`;
elements.historySummary.textContent = "조회 중";
elements.historyList.replaceChildren();
@@ -1674,48 +1667,34 @@ function closeHistoryDrawer() {
}
function showInfoOverlay(location) {
if (!state.map || !state.mapProvider) return;
if (!elements.mapPanel) return;
if (shouldSuppressMapPopup()) {
if (shouldSuppressInfoPanel()) {
clearInfoOverlay();
return;
}
const status = getLocationStatus(location);
const content = createPopupElement(location, status);
const placement = getInfoPanelPlacement(location);
if (state.mapProvider === "leaflet") {
if (state.infoOverlay) {
state.infoOverlay
.setLatLng([location.latitude, location.longitude])
.setContent(content);
return;
}
state.infoOverlay = L.popup({
closeButton: true,
offset: [0, -24]
})
.setLatLng([location.latitude, location.longitude])
.setContent(content)
.openOn(state.map);
return;
if (!(state.infoOverlay instanceof HTMLElement)) {
clearInfoOverlay();
state.infoOverlay = document.createElement("section");
state.infoOverlay.setAttribute("aria-label", "화물 상세");
elements.mapPanel.append(state.infoOverlay);
}
const position = new kakao.maps.LatLng(location.latitude, location.longitude);
if (!state.infoOverlay) {
state.infoOverlay = new kakao.maps.CustomOverlay({ yAnchor: 1.35 });
}
state.infoOverlay.setContent(content);
state.infoOverlay.setPosition(position);
state.infoOverlay.setMap(state.map);
state.infoOverlay.className = `map-info-panel ${placement}`;
state.infoOverlay.replaceChildren(content);
}
function clearInfoOverlay() {
if (!state.infoOverlay) return;
if (typeof state.infoOverlay.setMap === "function") {
if (state.infoOverlay instanceof HTMLElement) {
state.infoOverlay.remove();
} else if (typeof state.infoOverlay.setMap === "function") {
state.infoOverlay.setMap(null);
} else if (state.mapProvider === "leaflet" && state.map?.closePopup) {
state.map.closePopup(state.infoOverlay);
@@ -1724,14 +1703,43 @@ function clearInfoOverlay() {
state.infoOverlay = null;
}
function shouldSuppressMapPopup() {
function shouldSuppressInfoPanel() {
return window.matchMedia("(max-width: 560px)").matches;
}
function getInfoPanelPlacement(location) {
const center = getCurrentMapCenter();
if (!center) return "is-top-right";
return location.longitude >= center.longitude ? "is-bottom-left" : "is-top-right";
}
function getCurrentMapCenter() {
if (!state.map || !state.mapProvider) return null;
if (state.mapProvider === "kakao" && typeof state.map.getCenter === "function") {
const center = state.map.getCenter();
return {
latitude: center.getLat(),
longitude: center.getLng()
};
}
if (state.mapProvider === "leaflet" && typeof state.map.getCenter === "function") {
const center = state.map.getCenter();
return {
latitude: center.lat,
longitude: center.lng
};
}
return null;
}
function createPopupElement(location, status) {
const vehicleType = getVehicleType(location);
const container = document.createElement("div");
container.className = "kakao-popup";
container.className = "map-info-card";
const title = document.createElement("strong");
title.className = "popup-title";
@@ -1775,12 +1783,10 @@ function createRouteInfoElement(location) {
return routeInfo;
}
const source = firstString(location.routeSource, location.routingProvider) || "simulated";
routeInfo.append(
createPopupRouteLine("남은 거리", formatDistance(metrics.remainingDistanceKm)),
createPopupRouteLine("예상 도착", formatEtaTime(metrics.estimatedArrivalAt)),
createPopupRouteLine("소요 시간", formatDuration(metrics.etaMinutes)),
createPopupRouteLine("경로", source === "simulated" ? "모의 경로" : source)
createPopupRouteLine("도착 시간", formatEtaTime(metrics.estimatedArrivalAt)),
createPopupRouteLine("남은 시간", formatDuration(metrics.etaMinutes))
);
return routeInfo;
}