From 437e0c331c383f98690d81d0c97dbb3528ee658c Mon Sep 17 00:00:00 2001 From: leeheejin Date: Wed, 29 Oct 2025 17:53:03 +0900 Subject: [PATCH] =?UTF-8?q?=EC=83=A4=EB=93=9C=EC=8B=9C=EC=98=8C=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=AB=99=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/app/globals.css | 6 + .../admin/dashboard/CanvasElement.tsx | 102 ++++++------- .../admin/dashboard/ChartConfigPanel.tsx | 58 +++---- .../admin/dashboard/DashboardCanvas.tsx | 4 +- .../admin/dashboard/DashboardDesigner.tsx | 16 +- .../admin/dashboard/DashboardSaveModal.tsx | 14 +- .../admin/dashboard/DashboardToolbar.tsx | 32 ++-- .../admin/dashboard/DashboardTopMenu.tsx | 14 +- .../admin/dashboard/DateFilterPanel.tsx | 18 +-- .../admin/dashboard/ElementConfigModal.tsx | 28 ++-- .../admin/dashboard/ElementConfigSidebar.tsx | 56 +++---- .../admin/dashboard/MapTestConfigPanel.tsx | 66 ++++---- .../admin/dashboard/MenuAssignmentModal.tsx | 2 +- .../admin/dashboard/MultiChartConfigPanel.tsx | 4 +- .../admin/dashboard/QueryEditor.tsx | 26 ++-- .../admin/dashboard/ResolutionSelector.tsx | 14 +- .../admin/dashboard/VehicleMapConfigPanel.tsx | 114 +++++++------- .../admin/dashboard/charts/Chart.tsx | 12 +- .../admin/dashboard/charts/ChartRenderer.tsx | 10 +- .../dashboard/charts/ComboChartComponent.tsx | 2 +- .../charts/StackedBarChartComponent.tsx | 2 +- .../dashboard/data-sources/ApiConfig.tsx | 42 +++--- .../data-sources/DataSourceSelector.tsx | 38 ++--- .../dashboard/data-sources/DatabaseConfig.tsx | 30 ++-- .../dashboard/data-sources/MultiApiConfig.tsx | 18 +-- .../data-sources/MultiDataSourceConfig.tsx | 6 +- .../data-sources/MultiDatabaseConfig.tsx | 18 +-- .../dashboard/widgets/CalendarSettings.tsx | 8 +- .../dashboard/widgets/CalendarWidget.tsx | 4 +- .../admin/dashboard/widgets/ClockSettings.tsx | 8 +- .../admin/dashboard/widgets/ClockWidget.tsx | 2 +- .../admin/dashboard/widgets/DigitalClock.tsx | 18 +-- .../dashboard/widgets/DriverListView.tsx | 80 +++++----- .../widgets/DriverManagementSettings.tsx | 4 +- .../widgets/DriverManagementWidget.tsx | 18 +-- .../admin/dashboard/widgets/ListWidget.tsx | 30 ++-- .../widgets/ListWidgetConfigModal.tsx | 42 +++--- .../widgets/ListWidgetConfigSidebar.tsx | 44 +++--- .../admin/dashboard/widgets/MonthView.tsx | 10 +- .../widgets/TodoWidgetConfigModal.tsx | 142 +++++++++--------- .../widgets/YardManagement3DWidget.tsx | 38 ++--- .../widgets/YardWidgetConfigModal.tsx | 2 +- .../widgets/YardWidgetConfigSidebar.tsx | 24 +-- .../CustomMetricConfigSidebar.tsx | 86 +++++------ .../admin/dashboard/widgets/driverUtils.ts | 40 ++--- .../widgets/list-widget/ColumnSelector.tsx | 28 ++-- .../widgets/list-widget/ListTableOptions.tsx | 14 +- .../list-widget/ManualColumnEditor.tsx | 24 +-- .../list-widget/UnifiedColumnEditor.tsx | 24 +-- .../widgets/yard-3d/MaterialAddModal.tsx | 20 +-- .../widgets/yard-3d/MaterialEditPanel.tsx | 22 +-- .../widgets/yard-3d/MaterialLibrary.tsx | 18 +-- .../widgets/yard-3d/Yard3DViewer.tsx | 40 ++--- .../dashboard/widgets/yard-3d/YardEditor.tsx | 48 +++--- .../yard-3d/YardElementConfigPanel.tsx | 10 +- .../widgets/yard-3d/YardLayoutCreateModal.tsx | 2 +- .../widgets/yard-3d/YardLayoutList.tsx | 20 +-- .../components/dashboard/DashboardViewer.tsx | 40 ++--- .../dashboard/widgets/BookingAlertWidget.tsx | 62 ++++---- .../dashboard/widgets/CalculatorWidget.tsx | 54 +++---- .../dashboard/widgets/CargoListWidget.tsx | 4 +- .../dashboard/widgets/ChartTestWidget.tsx | 2 +- .../widgets/CustomMetricTestWidget.tsx | 38 ++--- .../dashboard/widgets/CustomMetricWidget.tsx | 36 ++--- .../dashboard/widgets/CustomStatsWidget.tsx | 68 ++++----- .../widgets/CustomerIssuesWidget.tsx | 10 +- .../widgets/DeliveryStatusSummaryWidget.tsx | 52 +++---- .../widgets/DeliveryStatusWidget.tsx | 122 +++++++-------- .../widgets/DeliveryTodayStatsWidget.tsx | 30 ++-- .../dashboard/widgets/DocumentWidget.tsx | 56 +++---- .../dashboard/widgets/ExchangeWidget.tsx | 48 +++--- .../dashboard/widgets/ListSummaryWidget.tsx | 34 ++--- .../dashboard/widgets/MaintenanceWidget.tsx | 66 ++++---- .../dashboard/widgets/MapSummaryWidget.tsx | 14 +- .../dashboard/widgets/MapTestWidget.tsx | 52 +++---- .../dashboard/widgets/RiskAlertTestWidget.tsx | 34 ++--- .../dashboard/widgets/RiskAlertWidget.tsx | 18 +-- .../dashboard/widgets/StatusSummaryWidget.tsx | 40 ++--- .../dashboard/widgets/TaskWidget.tsx | 90 +++++------ .../dashboard/widgets/TodoWidget.tsx | 86 +++++------ .../widgets/TransportStatsWidget.tsx | 46 +++--- .../dashboard/widgets/VehicleListWidget.tsx | 52 +++---- .../widgets/VehicleMapOnlyWidget.tsx | 18 +-- .../dashboard/widgets/VehicleStatusWidget.tsx | 50 +++--- .../dashboard/widgets/WeatherMapWidget.tsx | 10 +- .../dashboard/widgets/WeatherWidget.tsx | 100 ++++++------ .../dashboard/widgets/WorkHistoryWidget.tsx | 30 ++-- 87 files changed, 1493 insertions(+), 1491 deletions(-) diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 03abcd11..6a01c5ea 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -28,6 +28,8 @@ --color-input: var(--input); --color-border: var(--border); --color-destructive: var(--destructive); + --color-success: var(--success); + --color-warning: var(--warning); --color-accent-foreground: var(--accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--muted-foreground); @@ -63,6 +65,8 @@ --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); + --success: oklch(0.647 0.176 142.5); + --warning: oklch(0.808 0.171 85.6); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); @@ -106,6 +110,8 @@ --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); + --success: oklch(0.697 0.17 142.5); + --warning: oklch(0.808 0.171 85.6); --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx index 23d51880..599718b9 100644 --- a/frontend/components/admin/dashboard/CanvasElement.tsx +++ b/frontend/components/admin/dashboard/CanvasElement.tsx @@ -26,124 +26,124 @@ import { // 위젯 동적 임포트 const WeatherWidget = dynamic(() => import("@/components/dashboard/widgets/WeatherWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const ExchangeWidget = dynamic(() => import("@/components/dashboard/widgets/ExchangeWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const CalculatorWidget = dynamic(() => import("@/components/dashboard/widgets/CalculatorWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const VehicleStatusWidget = dynamic(() => import("@/components/dashboard/widgets/VehicleStatusWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const VehicleListWidget = dynamic(() => import("@/components/dashboard/widgets/VehicleListWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const VehicleMapOnlyWidget = dynamic(() => import("@/components/dashboard/widgets/VehicleMapOnlyWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 범용 지도 위젯 (차량, 창고, 고객 등 모든 위치 위젯 통합) const MapSummaryWidget = dynamic(() => import("@/components/dashboard/widgets/MapSummaryWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 🧪 테스트용 지도 위젯 (REST API 지원) const MapTestWidget = dynamic(() => import("@/components/dashboard/widgets/MapTestWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 🧪 테스트용 지도 위젯 V2 (다중 데이터 소스) const MapTestWidgetV2 = dynamic(() => import("@/components/dashboard/widgets/MapTestWidgetV2"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 🧪 테스트용 차트 위젯 (다중 데이터 소스) const ChartTestWidget = dynamic(() => import("@/components/dashboard/widgets/ChartTestWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const ListTestWidget = dynamic( () => import("@/components/dashboard/widgets/ListTestWidget").then((mod) => ({ default: mod.ListTestWidget })), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }, ); const CustomMetricTestWidget = dynamic(() => import("@/components/dashboard/widgets/CustomMetricTestWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const RiskAlertTestWidget = dynamic(() => import("@/components/dashboard/widgets/RiskAlertTestWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 범용 상태 요약 위젯 (차량, 배송 등 모든 상태 위젯 통합) const StatusSummaryWidget = dynamic(() => import("@/components/dashboard/widgets/StatusSummaryWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 범용 목록 위젯 (차량, 기사, 제품 등 모든 목록 위젯 통합) - 다른 분 작업 중, 임시 주석 /* const ListSummaryWidget = dynamic(() => import("@/components/dashboard/widgets/ListSummaryWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); */ // 개별 위젯들 (주석 처리 - StatusSummaryWidget으로 통합됨) // const DeliveryStatusSummaryWidget = dynamic(() => import("@/components/dashboard/widgets/DeliveryStatusSummaryWidget"), { // ssr: false, -// loading: () =>
로딩 중...
, +// loading: () =>
로딩 중...
, // }); // const DeliveryTodayStatsWidget = dynamic(() => import("@/components/dashboard/widgets/DeliveryTodayStatsWidget"), { // ssr: false, -// loading: () =>
로딩 중...
, +// loading: () =>
로딩 중...
, // }); // const CargoListWidget = dynamic(() => import("@/components/dashboard/widgets/CargoListWidget"), { // ssr: false, -// loading: () =>
로딩 중...
, +// loading: () =>
로딩 중...
, // }); // const CustomerIssuesWidget = dynamic(() => import("@/components/dashboard/widgets/CustomerIssuesWidget"), { // ssr: false, -// loading: () =>
로딩 중...
, +// loading: () =>
로딩 중...
, // }); const RiskAlertWidget = dynamic(() => import("@/components/dashboard/widgets/RiskAlertWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const TaskWidget = dynamic(() => import("@/components/dashboard/widgets/TaskWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const BookingAlertWidget = dynamic(() => import("@/components/dashboard/widgets/BookingAlertWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); const DocumentWidget = dynamic(() => import("@/components/dashboard/widgets/DocumentWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 시계 위젯 임포트 @@ -160,25 +160,25 @@ import { Button } from "@/components/ui/button"; // 야드 관리 3D 위젯 const YardManagement3DWidget = dynamic(() => import("./widgets/YardManagement3DWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 작업 이력 위젯 const WorkHistoryWidget = dynamic(() => import("@/components/dashboard/widgets/WorkHistoryWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 커스텀 통계 카드 위젯 const CustomStatsWidget = dynamic(() => import("@/components/dashboard/widgets/CustomStatsWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); // 사용자 커스텀 카드 위젯 const CustomMetricWidget = dynamic(() => import("@/components/dashboard/widgets/CustomMetricWidget"), { ssr: false, - loading: () =>
로딩 중...
, + loading: () =>
로딩 중...
, }); interface CanvasElementProps { @@ -712,33 +712,33 @@ export function CanvasElement({ if (element.type === "chart") { switch (element.subtype) { case "bar": - return "bg-gradient-to-br from-indigo-400 to-purple-600"; + return "bg-gradient-to-br from-primary to-purple-500"; case "pie": - return "bg-gradient-to-br from-pink-400 to-red-500"; + return "bg-gradient-to-br from-destructive to-destructive/80"; case "line": - return "bg-gradient-to-br from-blue-400 to-cyan-400"; + return "bg-gradient-to-br from-primary to-primary/80"; default: - return "bg-gray-200"; + return "bg-muted"; } } else if (element.type === "widget") { switch (element.subtype) { case "exchange": - return "bg-gradient-to-br from-pink-400 to-yellow-400"; + return "bg-gradient-to-br from-warning to-warning/80"; case "weather": - return "bg-gradient-to-br from-cyan-400 to-indigo-800"; + return "bg-gradient-to-br from-primary to-primary/80"; case "clock": - return "bg-gradient-to-br from-teal-400 to-cyan-600"; + return "bg-gradient-to-br from-primary to-primary/80"; case "calendar": - return "bg-gradient-to-br from-indigo-400 to-purple-600"; + return "bg-gradient-to-br from-primary to-purple-500"; case "driver-management": - return "bg-gradient-to-br from-blue-400 to-indigo-600"; + return "bg-gradient-to-br from-primary to-primary"; case "list": - return "bg-gradient-to-br from-cyan-400 to-blue-600"; + return "bg-gradient-to-br from-primary to-primary/80"; default: - return "bg-gray-200"; + return "bg-muted"; } } - return "bg-gray-200"; + return "bg-muted"; }; // 드래그/리사이즈 중일 때는 임시 위치/크기 사용, 아니면 실제 값 사용 @@ -758,7 +758,7 @@ export function CanvasElement({
{element.customTitle || element.title} + {element.customTitle || element.title} ) : null}
@@ -817,7 +817,7 @@ export function CanvasElement({ {/* 색상 선택 패널 */} {showColorPicker && ( -
+
onCanvasBackgroundColorChange(e.target.value)} - className="h-10 w-16 border border-gray-300 rounded cursor-pointer" + className="h-10 w-16 border border-border rounded cursor-pointer" /> onCanvasBackgroundColorChange(e.target.value)} placeholder="#ffffff" - className="flex-1 px-2 py-1 text-sm border border-gray-300 rounded" + className="flex-1 px-2 py-1 text-sm border border-border rounded" />
@@ -89,7 +89,7 @@ export function DashboardToolbar({ onClearCanvas, onSaveLayout, canvasBackground diff --git a/frontend/components/admin/dashboard/DashboardTopMenu.tsx b/frontend/components/admin/dashboard/DashboardTopMenu.tsx index 71a9615f..14a2283a 100644 --- a/frontend/components/admin/dashboard/DashboardTopMenu.tsx +++ b/frontend/components/admin/dashboard/DashboardTopMenu.tsx @@ -265,13 +265,13 @@ export function DashboardTopMenu({ }; return ( -
+
{/* 좌측: 대시보드 제목 */}
{dashboardTitle && (
- {dashboardTitle} - 편집 중 + {dashboardTitle} + 편집 중
)}
@@ -287,7 +287,7 @@ export function DashboardTopMenu({ /> )} -
+
{/* 배경색 선택 */} {onBackgroundColorChange && ( @@ -295,7 +295,7 @@ export function DashboardTopMenu({ @@ -349,7 +349,7 @@ export function DashboardTopMenu({ )} -
+
{/* 차트 선택 */} @@ -104,12 +104,12 @@ export function DateFilterPanel({ config, dateColumns, onChange }: DateFilterPan ))} -

감지된 날짜 컬럼: {dateColumns.join(", ")}

+

감지된 날짜 컬럼: {dateColumns.join(", ")}

{/* 빠른 선택 */}
- +
@@ -298,9 +298,9 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave, onPreview {/* 진행 상황 표시 - 간단한 위젯과 헤더 전용 위젯은 표시 안 함 */} {!isSimpleWidget && !isHeaderOnlyWidget && ( -
+
-
+
단계 {currentStep} / 2: {currentStep === 1 ? "데이터 소스 선택" : "데이터 설정 및 차트 설정"}
@@ -356,9 +356,9 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave, onPreview onConfigChange={handleChartConfigChange} /> ) : ( -
+
-
데이터를 가져온 후 지도 설정이 표시됩니다
+
데이터를 가져온 후 지도 설정이 표시됩니다
) @@ -373,9 +373,9 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave, onPreview query={dataSource.query} /> ) : ( -
+
-
데이터를 가져온 후 차트 설정이 표시됩니다
+
데이터를 가져온 후 차트 설정이 표시됩니다
)} @@ -387,7 +387,7 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave, onPreview )} {/* 모달 푸터 */} -
+
{queryResult && {queryResult.rows.length}개 데이터 로드됨}
diff --git a/frontend/components/admin/dashboard/ElementConfigSidebar.tsx b/frontend/components/admin/dashboard/ElementConfigSidebar.tsx index b8d838f2..32a45a49 100644 --- a/frontend/components/admin/dashboard/ElementConfigSidebar.tsx +++ b/frontend/components/admin/dashboard/ElementConfigSidebar.tsx @@ -291,31 +291,31 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem return (
{/* 헤더 */} -
+
- {element.title} + {element.title}
{/* 본문: 스크롤 가능 영역 */}
{/* 기본 설정 카드 */} -
-
기본 설정
+
+
기본 설정
{/* 커스텀 제목 입력 */}
@@ -325,20 +325,20 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem onChange={(e) => setCustomTitle(e.target.value)} onKeyDown={(e) => e.stopPropagation()} placeholder="위젯 제목" - className="focus:border-primary focus:ring-primary/20 h-8 w-full rounded border border-gray-200 bg-gray-50 px-2 text-xs placeholder:text-gray-400 focus:bg-white focus:ring-1 focus:outline-none" + className="focus:border-primary focus:ring-primary/20 h-8 w-full rounded border border-border bg-muted px-2 text-xs placeholder:text-muted-foreground focus:bg-background focus:ring-1 focus:outline-none" />
{/* 헤더 표시 옵션 */} -
@@ -346,7 +346,7 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem {/* 다중 데이터 소스 위젯 */} {isMultiDataSourceWidget && ( <> -
+
+
- +
-
+
타일맵 설정 (선택사항)
기본 VWorld 타일맵 사용 중
@@ -403,11 +403,11 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem {/* 차트 위젯: 차트 설정 */} {element.subtype === "chart" && ( -
+
- +
-
차트 설정
+
차트 설정
{testResults.size > 0 ? `${testResults.size}개 데이터 소스 • X축, Y축, 차트 타입 설정` @@ -439,24 +439,24 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem {/* 헤더 전용 위젯이 아닐 때만 데이터 소스 표시 */} {!isHeaderOnlyWidget && !isMultiDataSourceWidget && ( -
-
데이터 소스
+
+
데이터 소스
handleDataSourceTypeChange(value as "database" | "api")} className="w-full" > - + 데이터베이스 REST API @@ -552,9 +552,9 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem {/* 데이터 로드 상태 */} {queryResult && ( -
-
- +
+
+ {queryResult.rows.length}개 데이터 로드됨
@@ -564,10 +564,10 @@ export function ElementConfigSidebar({ element, isOpen, onClose, onApply }: Elem
{/* 푸터: 적용 버튼 */} -
+
diff --git a/frontend/components/admin/dashboard/MapTestConfigPanel.tsx b/frontend/components/admin/dashboard/MapTestConfigPanel.tsx index b5be7a35..38d60e5b 100644 --- a/frontend/components/admin/dashboard/MapTestConfigPanel.tsx +++ b/frontend/components/admin/dashboard/MapTestConfigPanel.tsx @@ -123,9 +123,9 @@ export function MapTestConfigPanel({ config, queryResult, onConfigChange }: MapT
{/* 타일맵 URL 설정 (외부 커넥션 또는 직접 입력) */}
-