diff --git a/frontend/components/dashboard/widgets/CargoListWidget.tsx b/frontend/components/dashboard/widgets/CargoListWidget.tsx
index 5c8682c6..0d763933 100644
--- a/frontend/components/dashboard/widgets/CargoListWidget.tsx
+++ b/frontend/components/dashboard/widgets/CargoListWidget.tsx
@@ -2,6 +2,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface CargoListWidgetProps {
element: DashboardElement;
@@ -47,7 +48,7 @@ export default function CargoListWidget({ element }: CargoListWidgetProps) {
try {
setLoading(true);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/CustomStatsWidget.tsx b/frontend/components/dashboard/widgets/CustomStatsWidget.tsx
index a42be32e..f2d5e2ff 100644
--- a/frontend/components/dashboard/widgets/CustomStatsWidget.tsx
+++ b/frontend/components/dashboard/widgets/CustomStatsWidget.tsx
@@ -9,6 +9,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface CustomStatsWidgetProps {
element?: DashboardElement;
@@ -77,7 +78,7 @@ export default function CustomStatsWidget({ element, refreshInterval = 60000 }:
// 쿼리 실행하여 통계 계산
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/CustomerIssuesWidget.tsx b/frontend/components/dashboard/widgets/CustomerIssuesWidget.tsx
index 56879e29..2af5caef 100644
--- a/frontend/components/dashboard/widgets/CustomerIssuesWidget.tsx
+++ b/frontend/components/dashboard/widgets/CustomerIssuesWidget.tsx
@@ -2,6 +2,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface CustomerIssuesWidgetProps {
element: DashboardElement;
@@ -49,7 +50,7 @@ export default function CustomerIssuesWidget({ element }: CustomerIssuesWidgetPr
try {
setLoading(true);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/DeliveryStatusSummaryWidget.tsx b/frontend/components/dashboard/widgets/DeliveryStatusSummaryWidget.tsx
index 0d517afd..673a857a 100644
--- a/frontend/components/dashboard/widgets/DeliveryStatusSummaryWidget.tsx
+++ b/frontend/components/dashboard/widgets/DeliveryStatusSummaryWidget.tsx
@@ -2,6 +2,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface DeliveryStatusSummaryWidgetProps {
element: DashboardElement;
@@ -39,7 +40,7 @@ export default function DeliveryStatusSummaryWidget({ element }: DeliveryStatusS
try {
setLoading(true);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/DeliveryStatusWidget.tsx b/frontend/components/dashboard/widgets/DeliveryStatusWidget.tsx
index 45b4f839..fd9fe7b2 100644
--- a/frontend/components/dashboard/widgets/DeliveryStatusWidget.tsx
+++ b/frontend/components/dashboard/widgets/DeliveryStatusWidget.tsx
@@ -3,6 +3,7 @@
import React, { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { RefreshCw, Package, TruckIcon, AlertTriangle, CheckCircle, Clock, XCircle } from "lucide-react";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface DeliveryItem {
id: string;
@@ -50,7 +51,7 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
}
try {
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -266,14 +267,13 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
};
// 필터링된 배송 목록
- const filteredDeliveries = selectedStatus === "all"
- ? deliveries
- : deliveries.filter((d) => d.status === selectedStatus);
+ const filteredDeliveries =
+ selectedStatus === "all" ? deliveries : deliveries.filter((d) => d.status === selectedStatus);
// 오늘 통계 계산
const today = new Date();
today.setHours(0, 0, 0, 0);
-
+
const todayStats = {
// 오늘 발송 건수 (created_at이 오늘인 것)
shipped: deliveries.filter((d: any) => {
@@ -293,22 +293,14 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
};
return (
-
+
{/* 헤더 */}
📦 배송 / 화물 처리 현황
-
- 마지막 업데이트: {lastUpdate.toLocaleTimeString("ko-KR")}
-
+
마지막 업데이트: {lastUpdate.toLocaleTimeString("ko-KR")}
-
@@ -316,60 +308,60 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
{/* 배송 상태 요약 */}
배송 상태 요약 (클릭하여 필터링)
-
+
setSelectedStatus("all")}
- className={`rounded-lg p-1.5 shadow-sm border-l-4 transition-all ${
+ className={`rounded-lg border-l-4 p-1.5 shadow-sm transition-all ${
selectedStatus === "all"
? "border-gray-900 bg-gray-100 ring-2 ring-gray-900"
: "border-gray-500 bg-white hover:bg-gray-50"
}`}
>
- 전체
+ 전체
{deliveries.length}
setSelectedStatus("in_transit")}
- className={`rounded-lg p-1.5 shadow-sm border-l-4 transition-all ${
+ className={`rounded-lg border-l-4 p-1.5 shadow-sm transition-all ${
selectedStatus === "in_transit"
? "border-blue-900 bg-blue-100 ring-2 ring-blue-900"
: "border-blue-500 bg-white hover:bg-blue-50"
}`}
>
- 배송중
+ 배송중
{statusStats.in_transit}
setSelectedStatus("delivered")}
- className={`rounded-lg p-1.5 shadow-sm border-l-4 transition-all ${
+ className={`rounded-lg border-l-4 p-1.5 shadow-sm transition-all ${
selectedStatus === "delivered"
? "border-green-900 bg-green-100 ring-2 ring-green-900"
: "border-green-500 bg-white hover:bg-green-50"
}`}
>
- 완료
+ 완료
{statusStats.delivered}
setSelectedStatus("delayed")}
- className={`rounded-lg p-1.5 shadow-sm border-l-4 transition-all ${
+ className={`rounded-lg border-l-4 p-1.5 shadow-sm transition-all ${
selectedStatus === "delayed"
? "border-red-900 bg-red-100 ring-2 ring-red-900"
: "border-red-500 bg-white hover:bg-red-50"
}`}
>
- 지연
+ 지연
{statusStats.delayed}
setSelectedStatus("pickup_waiting")}
- className={`rounded-lg p-1.5 shadow-sm border-l-4 transition-all ${
+ className={`rounded-lg border-l-4 p-1.5 shadow-sm transition-all ${
selectedStatus === "pickup_waiting"
? "border-yellow-900 bg-yellow-100 ring-2 ring-yellow-900"
: "border-yellow-500 bg-white hover:bg-yellow-50"
}`}
>
- 픽업 대기
+ 픽업 대기
{statusStats.pickup_waiting}
@@ -379,13 +371,13 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
오늘 처리 현황
-
-
발송 건수
+
+
발송 건수
{todayStats.shipped}
건
-
-
도착 건수
+
+
도착 건수
{todayStats.delivered}
건
@@ -394,7 +386,7 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
{/* 필터링된 화물 리스트 */}
-
+
{selectedStatus === "all" && `전체 화물 (${filteredDeliveries.length})`}
{selectedStatus === "in_transit" && `배송 중인 화물 (${filteredDeliveries.length})`}
@@ -402,31 +394,35 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
{selectedStatus === "delayed" && `지연 중인 화물 (${filteredDeliveries.length})`}
{selectedStatus === "pickup_waiting" && `픽업 대기 (${filteredDeliveries.length})`}
-
+
{filteredDeliveries.length === 0 ? (
{selectedStatus === "all" ? "화물이 없습니다" : "해당 상태의 화물이 없습니다"}
) : (
-
+
{filteredDeliveries.map((delivery) => (
-
+
-
{delivery.customer}
+
{delivery.customer}
{delivery.trackingNumber}
-
+
{getStatusText(delivery.status)}
-
+
경로:
- {delivery.origin} → {delivery.destination}
+
+ {delivery.origin} → {delivery.destination}
+
예정:
@@ -449,37 +445,37 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
{/* 고객 클레임/이슈 리포트 */}
-
+
고객 클레임/이슈 ({issues.filter((i) => i.status !== "resolved").length})
-
+
{issues.length === 0 ? (
-
- 이슈가 없습니다
-
+
이슈가 없습니다
) : (
-
+
{issues.map((issue) => (
-
+
-
{issue.customer}
+
{issue.customer}
{issue.trackingNumber}
-
+
{getIssueTypeText(issue.issueType)}
-
+
{getIssueStatusText(issue.status)}
-
+
{issue.description}
접수: {issue.reportedAt}
@@ -492,4 +488,3 @@ export default function DeliveryStatusWidget({ element, refreshInterval = 60000
);
}
-
diff --git a/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx b/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx
index bfc7d8a6..21fb96ff 100644
--- a/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx
+++ b/frontend/components/dashboard/widgets/DeliveryTodayStatsWidget.tsx
@@ -2,6 +2,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface DeliveryTodayStatsWidgetProps {
element: DashboardElement;
@@ -40,7 +41,7 @@ export default function DeliveryTodayStatsWidget({ element }: DeliveryTodayStats
try {
setLoading(true);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/ListSummaryWidget.tsx b/frontend/components/dashboard/widgets/ListSummaryWidget.tsx
index dd5362c5..a1613cdf 100644
--- a/frontend/components/dashboard/widgets/ListSummaryWidget.tsx
+++ b/frontend/components/dashboard/widgets/ListSummaryWidget.tsx
@@ -8,6 +8,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface ListSummaryWidgetProps {
element: DashboardElement;
@@ -128,7 +129,7 @@ export default function ListSummaryWidget({ element }: ListSummaryWidgetProps) {
setTableName(extractedTableName);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/MapSummaryWidget.tsx b/frontend/components/dashboard/widgets/MapSummaryWidget.tsx
index 683ccb56..58c49814 100644
--- a/frontend/components/dashboard/widgets/MapSummaryWidget.tsx
+++ b/frontend/components/dashboard/widgets/MapSummaryWidget.tsx
@@ -7,6 +7,7 @@ import { getWeather, WeatherData, getWeatherAlerts, WeatherAlert } from "@/lib/a
import { Cloud, CloudRain, CloudSnow, Sun, Wind, AlertTriangle } from "lucide-react";
import turfUnion from "@turf/union";
import { polygon } from "@turf/helpers";
+import { getApiUrl } from "@/lib/utils/apiUrl";
import "leaflet/dist/leaflet.css";
// Leaflet 아이콘 경로 설정 (엑박 방지)
@@ -72,80 +73,140 @@ const CITY_COORDINATES = [
{ name: "광주", lat: 35.1595, lng: 126.8526 },
{ name: "대전", lat: 36.3504, lng: 127.3845 },
{ name: "울산", lat: 35.5384, lng: 129.3114 },
- { name: "세종", lat: 36.4800, lng: 127.2890 },
+ { name: "세종", lat: 36.48, lng: 127.289 },
{ name: "제주", lat: 33.4996, lng: 126.5312 },
];
// 해상 구역 폴리곤 좌표 (기상청 특보 구역 기준 - 깔끔한 사각형)
const MARITIME_ZONES: Record
> = {
// 제주도 해역
- "제주도남부앞바다": [
- [33.25, 126.0], [33.25, 126.85], [33.0, 126.85], [33.0, 126.0]
+ 제주도남부앞바다: [
+ [33.25, 126.0],
+ [33.25, 126.85],
+ [33.0, 126.85],
+ [33.0, 126.0],
],
- "제주도남쪽바깥먼바다": [
- [33.15, 125.7], [33.15, 127.3], [32.5, 127.3], [32.5, 125.7]
+ 제주도남쪽바깥먼바다: [
+ [33.15, 125.7],
+ [33.15, 127.3],
+ [32.5, 127.3],
+ [32.5, 125.7],
],
- "제주도동부앞바다": [
- [33.4, 126.7], [33.4, 127.25], [33.05, 127.25], [33.05, 126.7]
+ 제주도동부앞바다: [
+ [33.4, 126.7],
+ [33.4, 127.25],
+ [33.05, 127.25],
+ [33.05, 126.7],
],
- "제주도남동쪽안쪽먼바다": [
- [33.3, 126.85], [33.3, 127.95], [32.65, 127.95], [32.65, 126.85]
+ 제주도남동쪽안쪽먼바다: [
+ [33.3, 126.85],
+ [33.3, 127.95],
+ [32.65, 127.95],
+ [32.65, 126.85],
],
- "제주도남서쪽안쪽먼바다": [
- [33.3, 125.35], [33.3, 126.45], [32.7, 126.45], [32.7, 125.35]
+ 제주도남서쪽안쪽먼바다: [
+ [33.3, 125.35],
+ [33.3, 126.45],
+ [32.7, 126.45],
+ [32.7, 125.35],
],
-
+
// 남해 해역
- "남해동부앞바다": [
- [34.65, 128.3], [34.65, 129.65], [33.95, 129.65], [33.95, 128.3]
+ 남해동부앞바다: [
+ [34.65, 128.3],
+ [34.65, 129.65],
+ [33.95, 129.65],
+ [33.95, 128.3],
],
- "남해동부안쪽먼바다": [
- [34.25, 127.95], [34.25, 129.75], [33.45, 129.75], [33.45, 127.95]
+ 남해동부안쪽먼바다: [
+ [34.25, 127.95],
+ [34.25, 129.75],
+ [33.45, 129.75],
+ [33.45, 127.95],
],
- "남해동부바깥먼바다": [
- [33.65, 127.95], [33.65, 130.35], [32.45, 130.35], [32.45, 127.95]
+ 남해동부바깥먼바다: [
+ [33.65, 127.95],
+ [33.65, 130.35],
+ [32.45, 130.35],
+ [32.45, 127.95],
],
-
+
// 동해 해역
- "경북북부앞바다": [
- [36.65, 129.2], [36.65, 130.1], [35.95, 130.1], [35.95, 129.2]
+ 경북북부앞바다: [
+ [36.65, 129.2],
+ [36.65, 130.1],
+ [35.95, 130.1],
+ [35.95, 129.2],
],
- "경북남부앞바다": [
- [36.15, 129.1], [36.15, 129.95], [35.45, 129.95], [35.45, 129.1]
+ 경북남부앞바다: [
+ [36.15, 129.1],
+ [36.15, 129.95],
+ [35.45, 129.95],
+ [35.45, 129.1],
],
- "동해남부남쪽안쪽먼바다": [
- [35.65, 129.35], [35.65, 130.65], [34.95, 130.65], [34.95, 129.35]
+ 동해남부남쪽안쪽먼바다: [
+ [35.65, 129.35],
+ [35.65, 130.65],
+ [34.95, 130.65],
+ [34.95, 129.35],
],
- "동해남부남쪽바깥먼바다": [
- [35.25, 129.45], [35.25, 131.15], [34.15, 131.15], [34.15, 129.45]
+ 동해남부남쪽바깥먼바다: [
+ [35.25, 129.45],
+ [35.25, 131.15],
+ [34.15, 131.15],
+ [34.15, 129.45],
],
- "동해남부북쪽안쪽먼바다": [
- [36.6, 129.65], [36.6, 130.95], [35.85, 130.95], [35.85, 129.65]
+ 동해남부북쪽안쪽먼바다: [
+ [36.6, 129.65],
+ [36.6, 130.95],
+ [35.85, 130.95],
+ [35.85, 129.65],
],
- "동해남부북쪽바깥먼바다": [
- [36.65, 130.35], [36.65, 132.15], [35.85, 132.15], [35.85, 130.35]
+ 동해남부북쪽바깥먼바다: [
+ [36.65, 130.35],
+ [36.65, 132.15],
+ [35.85, 132.15],
+ [35.85, 130.35],
],
-
+
// 강원 해역
- "강원북부앞바다": [
- [38.15, 128.4], [38.15, 129.55], [37.45, 129.55], [37.45, 128.4]
+ 강원북부앞바다: [
+ [38.15, 128.4],
+ [38.15, 129.55],
+ [37.45, 129.55],
+ [37.45, 128.4],
],
- "강원중부앞바다": [
- [37.65, 128.7], [37.65, 129.6], [36.95, 129.6], [36.95, 128.7]
+ 강원중부앞바다: [
+ [37.65, 128.7],
+ [37.65, 129.6],
+ [36.95, 129.6],
+ [36.95, 128.7],
],
- "강원남부앞바다": [
- [37.15, 128.9], [37.15, 129.85], [36.45, 129.85], [36.45, 128.9]
+ 강원남부앞바다: [
+ [37.15, 128.9],
+ [37.15, 129.85],
+ [36.45, 129.85],
+ [36.45, 128.9],
],
- "동해중부안쪽먼바다": [
- [38.55, 129.35], [38.55, 131.15], [37.25, 131.15], [37.25, 129.35]
+ 동해중부안쪽먼바다: [
+ [38.55, 129.35],
+ [38.55, 131.15],
+ [37.25, 131.15],
+ [37.25, 129.35],
],
- "동해중부바깥먼바다": [
- [38.6, 130.35], [38.6, 132.55], [37.65, 132.55], [37.65, 130.35]
+ 동해중부바깥먼바다: [
+ [38.6, 130.35],
+ [38.6, 132.55],
+ [37.65, 132.55],
+ [37.65, 130.35],
],
-
+
// 울릉도·독도
"울릉도.독도": [
- [37.7, 130.7], [37.7, 132.0], [37.4, 132.0], [37.4, 130.7]
+ [37.7, 130.7],
+ [37.7, 132.0],
+ [37.4, 132.0],
+ [37.4, 130.7],
],
};
@@ -156,10 +217,7 @@ const getDistance = (lat1: number, lng1: number, lat2: number, lng2: number): nu
const dLng = ((lng2 - lng1) * Math.PI) / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
- Math.cos((lat1 * Math.PI) / 180) *
- Math.cos((lat2 * Math.PI) / 180) *
- Math.sin(dLng / 2) *
- Math.sin(dLng / 2);
+ Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
};
@@ -235,7 +293,7 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) {
useEffect(() => {
console.log("🗺️ MapSummaryWidget 초기화");
console.log("🗺️ showWeatherAlerts:", element.chartConfig?.showWeatherAlerts);
-
+
// GeoJSON 데이터 로드
loadGeoJsonData();
@@ -390,7 +448,7 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) {
setTableName(extractedTableName);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -557,13 +615,15 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) {
)}
{/* 기상특보 영역 표시 (해상 - Polygon 레이어) - 개별 표시 */}
- {element.chartConfig?.showWeatherAlerts && weatherAlerts && weatherAlerts.length > 0 &&
+ {element.chartConfig?.showWeatherAlerts &&
+ weatherAlerts &&
+ weatherAlerts.length > 0 &&
weatherAlerts
.filter((alert) => MARITIME_ZONES[alert.location])
.map((alert, idx) => {
const coordinates = MARITIME_ZONES[alert.location];
const alertColor = getAlertColor(alert.severity);
-
+
return (
-
+
⚠️
{alert.location}
-
-
- {alert.title}
-
+
+
{alert.title}
{alert.description}
@@ -616,8 +690,7 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) {
);
- })
- }
+ })}
{/* 마커 표시 */}
{markers.map((marker, idx) => (
@@ -672,7 +745,7 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) {
{/* 범례 (특보가 있을 때만 표시) */}
{element.chartConfig?.showWeatherAlerts && weatherAlerts && weatherAlerts.length > 0 && (
-
+
기상특보
@@ -691,9 +764,7 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) {
약한 주의보
-
- 총 {weatherAlerts.length}건 발효 중
-
+
총 {weatherAlerts.length}건 발효 중
)}
diff --git a/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx b/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx
index 69629bd9..e5c67009 100644
--- a/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx
+++ b/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx
@@ -2,6 +2,7 @@
import React, { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface StatusSummaryWidgetProps {
element: DashboardElement;
@@ -180,7 +181,7 @@ export default function StatusSummaryWidget({
setTableName(extractedTableName);
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/TransportStatsWidget.tsx b/frontend/components/dashboard/widgets/TransportStatsWidget.tsx
index 39fa6651..47501e48 100644
--- a/frontend/components/dashboard/widgets/TransportStatsWidget.tsx
+++ b/frontend/components/dashboard/widgets/TransportStatsWidget.tsx
@@ -10,6 +10,7 @@
import { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface TransportStatsWidgetProps {
element?: DashboardElement;
@@ -53,7 +54,7 @@ export default function TransportStatsWidget({ element, refreshInterval = 60000
// 쿼리 실행하여 통계 계산
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/VehicleListWidget.tsx b/frontend/components/dashboard/widgets/VehicleListWidget.tsx
index d15d8ffa..701b46db 100644
--- a/frontend/components/dashboard/widgets/VehicleListWidget.tsx
+++ b/frontend/components/dashboard/widgets/VehicleListWidget.tsx
@@ -3,6 +3,7 @@
import React, { useState, useEffect } from "react";
import { RefreshCw, Truck, Navigation, Gauge } from "lucide-react";
import { Button } from "@/components/ui/button";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface Vehicle {
id: string;
@@ -35,11 +36,11 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
setIsLoading(false);
return;
}
-
+
const query = element.dataSource.query;
try {
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -109,7 +110,7 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
setSelectedStatus("all")}
- className={`whitespace-nowrap rounded-md px-3 py-1 text-xs font-medium transition-colors ${
+ className={`rounded-md px-3 py-1 text-xs font-medium whitespace-nowrap transition-colors ${
selectedStatus === "all" ? "bg-gray-900 text-white" : "bg-white text-gray-700 hover:bg-gray-100"
}`}
>
@@ -117,7 +118,7 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
setSelectedStatus("active")}
- className={`whitespace-nowrap rounded-md px-3 py-1 text-xs font-medium transition-colors ${
+ className={`rounded-md px-3 py-1 text-xs font-medium whitespace-nowrap transition-colors ${
selectedStatus === "active" ? "bg-green-500 text-white" : "bg-white text-gray-700 hover:bg-gray-100"
}`}
>
@@ -125,7 +126,7 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
setSelectedStatus("inactive")}
- className={`whitespace-nowrap rounded-md px-3 py-1 text-xs font-medium transition-colors ${
+ className={`rounded-md px-3 py-1 text-xs font-medium whitespace-nowrap transition-colors ${
selectedStatus === "inactive" ? "bg-yellow-500 text-white" : "bg-white text-gray-700 hover:bg-gray-100"
}`}
>
@@ -133,7 +134,7 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
setSelectedStatus("maintenance")}
- className={`whitespace-nowrap rounded-md px-3 py-1 text-xs font-medium transition-colors ${
+ className={`rounded-md px-3 py-1 text-xs font-medium whitespace-nowrap transition-colors ${
selectedStatus === "maintenance" ? "bg-orange-500 text-white" : "bg-white text-gray-700 hover:bg-gray-100"
}`}
>
@@ -141,7 +142,7 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
setSelectedStatus("warning")}
- className={`whitespace-nowrap rounded-md px-3 py-1 text-xs font-medium transition-colors ${
+ className={`rounded-md px-3 py-1 text-xs font-medium whitespace-nowrap transition-colors ${
selectedStatus === "warning" ? "bg-red-500 text-white" : "bg-white text-gray-700 hover:bg-gray-100"
}`}
>
@@ -170,7 +171,9 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
{vehicle.vehicle_name}
-
+
{getStatusText(vehicle.status)}
@@ -201,4 +204,3 @@ export default function VehicleListWidget({ element, refreshInterval = 30000 }:
);
}
-
diff --git a/frontend/components/dashboard/widgets/VehicleMapOnlyWidget.tsx b/frontend/components/dashboard/widgets/VehicleMapOnlyWidget.tsx
index 34f7a46b..1a41b815 100644
--- a/frontend/components/dashboard/widgets/VehicleMapOnlyWidget.tsx
+++ b/frontend/components/dashboard/widgets/VehicleMapOnlyWidget.tsx
@@ -4,6 +4,7 @@ import React, { useState, useEffect } from "react";
import dynamic from "next/dynamic";
import { Button } from "@/components/ui/button";
import { RefreshCw } from "lucide-react";
+import { getApiUrl } from "@/lib/utils/apiUrl";
import "leaflet/dist/leaflet.css";
// Leaflet 아이콘 경로 설정 (엑박 방지)
@@ -66,7 +67,7 @@ export default function VehicleMapOnlyWidget({ element, refreshInterval = 30000
}
try {
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
diff --git a/frontend/components/dashboard/widgets/VehicleStatusWidget.tsx b/frontend/components/dashboard/widgets/VehicleStatusWidget.tsx
index 3eaefdc6..bbf6ca53 100644
--- a/frontend/components/dashboard/widgets/VehicleStatusWidget.tsx
+++ b/frontend/components/dashboard/widgets/VehicleStatusWidget.tsx
@@ -3,6 +3,7 @@
import React, { useState, useEffect } from "react";
import { RefreshCw, TrendingUp, TrendingDown } from "lucide-react";
import { Button } from "@/components/ui/button";
+import { getApiUrl } from "@/lib/utils/apiUrl";
interface VehicleStatusWidgetProps {
element?: any; // 대시보드 요소 (dataSource 포함)
@@ -36,11 +37,11 @@ export default function VehicleStatusWidget({ element, refreshInterval = 30000 }
setIsLoading(false);
return;
}
-
+
const query = element.dataSource.query;
try {
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -150,53 +151,50 @@ export default function VehicleStatusWidget({ element, refreshInterval = 30000 }
가동률
-
- {activeRate}%
-
+
{activeRate}%
{/* 상태별 카드 */}
- {/* 운행 중 */}
-
-
-
-
운행
+ {/* 운행 중 */}
+
-
{statusData.active}
-
- {/* 대기 */}
-
-
-
-
대기
+ {/* 대기 */}
+
+
+
{statusData.inactive}
-
{statusData.inactive}
-
- {/* 정비 */}
-
-
-
-
정비
+ {/* 정비 */}
+
+
+
{statusData.maintenance}
-
{statusData.maintenance}
-
- {/* 고장 */}
-
-
-
-
고장
+ {/* 고장 */}
+
-
{statusData.warning}
-
);
}
-
diff --git a/frontend/components/dashboard/widgets/WorkHistoryWidget.tsx b/frontend/components/dashboard/widgets/WorkHistoryWidget.tsx
index ab333be6..1c8e0c28 100644
--- a/frontend/components/dashboard/widgets/WorkHistoryWidget.tsx
+++ b/frontend/components/dashboard/widgets/WorkHistoryWidget.tsx
@@ -10,6 +10,7 @@
import { useState, useEffect } from "react";
import { DashboardElement } from "@/components/admin/dashboard/types";
+import { getApiUrl } from "@/lib/utils/apiUrl";
import { WORK_TYPE_LABELS, WORK_STATUS_LABELS, WORK_STATUS_COLORS, WorkType, WorkStatus } from "@/types/workHistory";
interface WorkHistoryWidgetProps {
@@ -33,7 +34,7 @@ export default function WorkHistoryWidget({ element, refreshInterval = 60000 }:
// 쿼리가 설정되어 있으면 쿼리 실행
if (element.dataSource?.query) {
const token = localStorage.getItem("authToken");
- const response = await fetch("/api/dashboards/execute-query", {
+ const response = await fetch(getApiUrl("/api/dashboards/execute-query"), {
method: "POST",
headers: {
"Content-Type": "application/json",