파일 업로드 구조 개선

This commit is contained in:
dohyeons
2025-11-05 15:39:02 +09:00
parent 63b6e89435
commit 8489ff03c2
3 changed files with 215 additions and 83 deletions

View File

@@ -26,80 +26,108 @@ import {
// 위젯 동적 임포트
const WeatherWidget = dynamic(() => import("@/components/dashboard/widgets/WeatherWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const ExchangeWidget = dynamic(() => import("@/components/dashboard/widgets/ExchangeWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const CalculatorWidget = dynamic(() => import("@/components/dashboard/widgets/CalculatorWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const VehicleStatusWidget = dynamic(() => import("@/components/dashboard/widgets/VehicleStatusWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const VehicleListWidget = dynamic(() => import("@/components/dashboard/widgets/VehicleListWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const VehicleMapOnlyWidget = dynamic(() => import("@/components/dashboard/widgets/VehicleMapOnlyWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 범용 지도 위젯 (차량, 창고, 고객 등 모든 위치 위젯 통합)
const MapSummaryWidget = dynamic(() => import("@/components/dashboard/widgets/MapSummaryWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 🧪 테스트용 지도 위젯 (REST API 지원)
const MapTestWidget = dynamic(() => import("@/components/dashboard/widgets/MapTestWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 🧪 테스트용 지도 위젯 V2 (다중 데이터 소스)
const MapTestWidgetV2 = dynamic(() => import("@/components/dashboard/widgets/MapTestWidgetV2"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 🧪 테스트용 차트 위젯 (다중 데이터 소스)
const ChartTestWidget = dynamic(() => import("@/components/dashboard/widgets/ChartTestWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const ListTestWidget = dynamic(
() => import("@/components/dashboard/widgets/ListTestWidget").then((mod) => ({ default: mod.ListTestWidget })),
{
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
},
);
const CustomMetricTestWidget = dynamic(() => import("@/components/dashboard/widgets/CustomMetricTestWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const RiskAlertTestWidget = dynamic(() => import("@/components/dashboard/widgets/RiskAlertTestWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 범용 상태 요약 위젯 (차량, 배송 등 모든 상태 위젯 통합)
const StatusSummaryWidget = dynamic(() => import("@/components/dashboard/widgets/StatusSummaryWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 범용 목록 위젯 (차량, 기사, 제품 등 모든 목록 위젯 통합) - 다른 분 작업 중, 임시 주석
@@ -128,22 +156,30 @@ const StatusSummaryWidget = dynamic(() => import("@/components/dashboard/widgets
const RiskAlertWidget = dynamic(() => import("@/components/dashboard/widgets/RiskAlertWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const TaskWidget = dynamic(() => import("@/components/dashboard/widgets/TaskWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const BookingAlertWidget = dynamic(() => import("@/components/dashboard/widgets/BookingAlertWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
const DocumentWidget = dynamic(() => import("@/components/dashboard/widgets/DocumentWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 시계 위젯 임포트
@@ -160,25 +196,33 @@ import { Button } from "@/components/ui/button";
// 야드 관리 3D 위젯
const YardManagement3DWidget = dynamic(() => import("./widgets/YardManagement3DWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 작업 이력 위젯
const WorkHistoryWidget = dynamic(() => import("@/components/dashboard/widgets/WorkHistoryWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 커스텀 통계 카드 위젯
const CustomStatsWidget = dynamic(() => import("@/components/dashboard/widgets/CustomStatsWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
// 사용자 커스텀 카드 위젯
const CustomMetricWidget = dynamic(() => import("@/components/dashboard/widgets/CustomMetricWidget"), {
ssr: false,
loading: () => <div className="flex h-full items-center justify-center text-sm text-muted-foreground"> ...</div>,
loading: () => (
<div className="text-muted-foreground flex h-full items-center justify-center text-sm"> ...</div>
),
});
interface CanvasElementProps {
@@ -758,7 +802,7 @@ export function CanvasElement({
<div
ref={elementRef}
data-element-id={element.id}
className={`absolute min-h-[120px] min-w-[120px] cursor-move overflow-hidden rounded-lg border-2 bg-background shadow-lg ${isSelected ? "border-primary ring-2 ring-primary/20" : "border-border"} ${isDragging || isResizing ? "transition-none" : "transition-all duration-150"} `}
className={`bg-background absolute min-h-[120px] min-w-[120px] cursor-move overflow-hidden rounded-lg border-2 shadow-lg ${isSelected ? "border-primary ring-primary/20 ring-2" : "border-border"} ${isDragging || isResizing ? "transition-none" : "transition-all duration-150"} `}
style={{
left: displayPosition.x,
top: displayPosition.y,
@@ -809,7 +853,7 @@ export function CanvasElement({
)}
{/* 제목 */}
{!element.type || element.type !== "chart" ? (
<span className="text-xs font-bold text-foreground">{element.customTitle || element.title}</span>
<span className="text-foreground text-xs font-bold">{element.customTitle || element.title}</span>
) : null}
</div>
<div className="flex gap-1">
@@ -817,7 +861,7 @@ export function CanvasElement({
<Button
variant="ghost"
size="icon"
className="element-close hover:bg-destructive h-5 w-5 text-muted-foreground hover:text-white"
className="element-close hover:bg-destructive text-muted-foreground h-5 w-5 hover:text-white"
onClick={handleRemove}
onMouseDown={(e) => e.stopPropagation()}
title="삭제"
@@ -831,9 +875,9 @@ export function CanvasElement({
<div className="relative h-[calc(100%-32px)] px-2 pb-2">
{element.type === "chart" ? (
// 차트 렌더링
<div className="h-full w-full bg-background">
<div className="bg-background h-full w-full">
{isLoadingData ? (
<div className="flex h-full w-full items-center justify-center text-muted-foreground">
<div className="text-muted-foreground flex h-full w-full items-center justify-center">
<div className="text-center">
<div className="border-primary mx-auto mb-2 h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" />
<div className="text-sm"> ...</div>
@@ -921,7 +965,12 @@ export function CanvasElement({
) : element.type === "widget" && element.subtype === "status-summary" ? (
// 커스텀 상태 카드 - 범용 위젯
<div className="widget-interactive-area h-full w-full">
<StatusSummaryWidget element={element} title="상태 요약" icon="📊" bgGradient="from-background to-primary/10" />
<StatusSummaryWidget
element={element}
title="상태 요약"
icon="📊"
bgGradient="from-background to-primary/10"
/>
</div>
) : /* element.type === "widget" && element.subtype === "list-summary" ? (
// 커스텀 목록 카드 - 범용 위젯 (다른 분 작업 중 - 임시 주석)
@@ -1106,7 +1155,7 @@ function ResizeHandle({ position, onMouseDown }: ResizeHandleProps) {
return (
<div
className={`resize-handle absolute h-3 w-3 border border-white bg-success ${getPositionClass()} `}
className={`resize-handle bg-success absolute h-3 w-3 border border-white ${getPositionClass()} `}
onMouseDown={(e) => onMouseDown(e, position)}
/>
);