diff --git a/frontend/src/features/ai-operations/AIAssistant.tsx b/frontend/src/features/ai-operations/AIAssistant.tsx
index a25d190..3358903 100644
--- a/frontend/src/features/ai-operations/AIAssistant.tsx
+++ b/frontend/src/features/ai-operations/AIAssistant.tsx
@@ -2,6 +2,7 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { MessageSquare, Send, Bot, User, BookOpen, Shield, AlertTriangle, FileText, ExternalLink } from 'lucide-react';
import { sendChatMessage } from '@/services/chatApi';
@@ -75,11 +76,13 @@ export function AIAssistant() {
};
return (
-
-
-
{t('assistant.title')}
-
{t('assistant.desc')}
-
+
+
{/* 대화 이력 사이드바 */}
@@ -150,6 +153,6 @@ export function AIAssistant() {
-
+
);
}
diff --git a/frontend/src/features/ai-operations/AIModelManagement.tsx b/frontend/src/features/ai-operations/AIModelManagement.tsx
index ed45269..8c20d1e 100644
--- a/frontend/src/features/ai-operations/AIModelManagement.tsx
+++ b/frontend/src/features/ai-operations/AIModelManagement.tsx
@@ -2,6 +2,7 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardContent, CardHeader, CardTitle } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { DataTable, type DataColumn } from '@shared/components/common/DataTable';
import {
Brain, Settings, Zap, Activity, TrendingUp, BarChart3,
@@ -248,29 +249,21 @@ export function AIModelManagement() {
const currentModel = MODELS.find((m) => m.status === '운영중')!;
return (
-
- {/* 헤더 */}
-
-
-
-
- {t('modelManagement.title')}
-
- ⚠데모 데이터 (백엔드 API 미구현)
-
-
-
- {t('modelManagement.desc')}
-
-
-
+
+
운영 모델: {currentModel.version}
Accuracy {currentModel.accuracy}%
-
-
+ }
+ />
{/* KPI */}
@@ -994,6 +987,6 @@ export function AIModelManagement() {
)}
-
+
);
}
diff --git a/frontend/src/features/ai-operations/MLOpsPage.tsx b/frontend/src/features/ai-operations/MLOpsPage.tsx
index 4091cba..8d8661a 100644
--- a/frontend/src/features/ai-operations/MLOpsPage.tsx
+++ b/frontend/src/features/ai-operations/MLOpsPage.tsx
@@ -2,6 +2,7 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { getModelStatusIntent, getQualityGateIntent, getExperimentIntent, MODEL_STATUSES, QUALITY_GATE_STATUSES, EXPERIMENT_STATUSES } from '@shared/constants/modelDeploymentStatuses';
import {
Cpu, Brain, Database, GitBranch, Activity, RefreshCw, Server, Shield,
@@ -111,18 +112,14 @@ export function MLOpsPage() {
const [selectedLLM, setSelectedLLM] = useState(0);
return (
-
-
-
-
- {t('mlops.title')}
-
- ⚠데모 데이터 (백엔드 API 미구현)
-
-
-
{t('mlops.desc')}
-
-
+
+
{/* 탭 */}
@@ -562,6 +559,6 @@ export function MLOpsPage() {
)}
-
+
);
}
diff --git a/frontend/src/features/parent-inference/LabelSession.tsx b/frontend/src/features/parent-inference/LabelSession.tsx
index 9a027ad..dca7f28 100644
--- a/frontend/src/features/parent-inference/LabelSession.tsx
+++ b/frontend/src/features/parent-inference/LabelSession.tsx
@@ -2,6 +2,9 @@ import { useEffect, useState, useCallback } from 'react';
import { Tag, X, Loader2 } from 'lucide-react';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { Button } from '@shared/components/ui/button';
+import { Select } from '@shared/components/ui/select';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { useAuth } from '@/app/auth/AuthContext';
import {
fetchLabelSessions,
@@ -85,23 +88,32 @@ export function LabelSession() {
};
return (
-
-
-
-
학습 세션
-
정답 라벨링 → prediction 모델 학습 데이터로 활용
-
-
-
-
-
-
+
+
+
+
+ >
+ }
+ />
@@ -180,6 +192,6 @@ export function LabelSession() {
)}
-
+
);
}
diff --git a/frontend/src/features/parent-inference/ParentExclusion.tsx b/frontend/src/features/parent-inference/ParentExclusion.tsx
index 489d018..3454877 100644
--- a/frontend/src/features/parent-inference/ParentExclusion.tsx
+++ b/frontend/src/features/parent-inference/ParentExclusion.tsx
@@ -2,6 +2,9 @@ import { useEffect, useState, useCallback } from 'react';
import { Ban, RotateCcw, Loader2, Globe, Layers } from 'lucide-react';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { Button } from '@shared/components/ui/button';
+import { Select } from '@shared/components/ui/select';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { useAuth } from '@/app/auth/AuthContext';
import {
fetchExclusions,
@@ -102,25 +105,31 @@ export function ParentExclusion() {
};
return (
-
-
-
-
모선 후보 제외
-
GROUP/GLOBAL 스코프로 잘못된 후보를 차단합니다.
-
-
-
-
-
-
+
+
+
+
+ >
+ }
+ />
{/* 신규 등록: GROUP */}
@@ -226,6 +235,6 @@ export function ParentExclusion() {
)}
-
+
);
}
diff --git a/frontend/src/features/parent-inference/ParentReview.tsx b/frontend/src/features/parent-inference/ParentReview.tsx
index 5fac710..167a47e 100644
--- a/frontend/src/features/parent-inference/ParentReview.tsx
+++ b/frontend/src/features/parent-inference/ParentReview.tsx
@@ -1,7 +1,10 @@
import { useEffect, useState, useCallback } from 'react';
-import { CheckCircle, XCircle, RotateCcw, Loader2 } from 'lucide-react';
+import { CheckCircle, XCircle, RotateCcw, Loader2, GitMerge } from 'lucide-react';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { Button } from '@shared/components/ui/button';
+import { Select } from '@shared/components/ui/select';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { useAuth } from '@/app/auth/AuthContext';
import {
fetchReviewList,
@@ -97,34 +100,26 @@ export function ParentReview() {
};
return (
-
-
-
-
모선 확정/거부
-
- 추론된 모선 후보를 확정/거부합니다. 권한: parent-inference-workflow:parent-review (UPDATE)
-
-
-
-
-
-
-
+
+
+
+
+ >
+ }
+ />
{/* 신규 등록 폼 (테스트용) */}
{canUpdate && (
@@ -267,6 +262,6 @@ export function ParentReview() {
)}
-
+
);
}
diff --git a/frontend/src/features/statistics/ExternalService.tsx b/frontend/src/features/statistics/ExternalService.tsx
index 546b416..c53401f 100644
--- a/frontend/src/features/statistics/ExternalService.tsx
+++ b/frontend/src/features/statistics/ExternalService.tsx
@@ -1,8 +1,8 @@
import { useTranslation } from 'react-i18next';
-import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { DataTable, type DataColumn } from '@shared/components/common/DataTable';
-import { Globe, Shield, Clock, BarChart3, ExternalLink, Lock, Unlock } from 'lucide-react';
+import { Globe } from 'lucide-react';
/* SFR-14: 외부 서비스(예보·경보) 제공 결과 연계 */
@@ -31,16 +31,14 @@ const cols: DataColumn[] = [
export function ExternalService() {
const { t } = useTranslation('statistics');
return (
-
-
-
- {t('externalService.title')}
-
- ⚠데모 데이터 (백엔드 API 미구현)
-
-
-
{t('externalService.desc')}
-
+
+
{[{ l: '운영 서비스', v: DATA.filter(d => d.status === '운영').length, c: 'text-green-400' }, { l: '테스트', v: DATA.filter(d => d.status === '테스트').length, c: 'text-blue-400' }, { l: '총 호출', v: '21,675', c: 'text-heading' }].map(k => (
@@ -49,6 +47,6 @@ export function ExternalService() {
))}
-
+
);
}
diff --git a/frontend/src/features/statistics/ReportManagement.tsx b/frontend/src/features/statistics/ReportManagement.tsx
index f9fee79..5934b1f 100644
--- a/frontend/src/features/statistics/ReportManagement.tsx
+++ b/frontend/src/features/statistics/ReportManagement.tsx
@@ -2,12 +2,14 @@ import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { Button } from '@shared/components/ui/button';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { ExcelExport } from '@shared/components/common/ExcelExport';
import { PrintButton } from '@shared/components/common/PrintButton';
import { FileUpload } from '@shared/components/common/FileUpload';
import { SaveButton } from '@shared/components/common/SaveButton';
import { SearchInput } from '@shared/components/common/SearchInput';
-import { Plus, Download, Clock, MapPin, Upload, X } from 'lucide-react';
+import { FileText, Plus, Upload, X, Clock, MapPin, Download } from 'lucide-react';
interface Report {
id: string;
@@ -37,40 +39,40 @@ export function ReportManagement() {
);
return (
-
-
-
-
- {t('reports.title')}
-
- ⚠데모 데이터 (백엔드 API 미구현)
-
-
-
{t('reports.desc')}
-
-
-
-
[]}
- columns={[
- { key: 'id', label: '보고서번호' }, { key: 'name', label: '선박명' },
- { key: 'type', label: '유형' }, { key: 'status', label: '상태' },
- { key: 'date', label: '일시' }, { key: 'evidence', label: '증거수' },
- ]}
- filename="보고서목록"
- />
-
-
-
-
-
+
+
+
+ []}
+ columns={[
+ { key: 'id', label: '보고서번호' }, { key: 'name', label: '선박명' },
+ { key: 'type', label: '유형' }, { key: 'status', label: '상태' },
+ { key: 'date', label: '일시' }, { key: 'evidence', label: '증거수' },
+ ]}
+ filename="보고서목록"
+ />
+
+
+ }>
+ 새 보고서
+
+ >
+ }
+ />
{/* 증거 파일 업로드 */}
{showUpload && (
@@ -186,6 +188,6 @@ export function ReportManagement() {
)}
-
+
);
}
diff --git a/frontend/src/features/statistics/Statistics.tsx b/frontend/src/features/statistics/Statistics.tsx
index 099d29b..726661f 100644
--- a/frontend/src/features/statistics/Statistics.tsx
+++ b/frontend/src/features/statistics/Statistics.tsx
@@ -2,6 +2,8 @@ import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Card, CardContent } from '@shared/components/ui/card';
import { Badge } from '@shared/components/ui/badge';
+import { Button } from '@shared/components/ui/button';
+import { PageContainer, PageHeader } from '@shared/components/layout';
import { DataTable, type DataColumn } from '@shared/components/common/DataTable';
import { BarChart3, Download } from 'lucide-react';
import { BarChart, AreaChart } from '@lib/charts';
@@ -140,22 +142,18 @@ export function Statistics() {
});
return (
-
-
-
-
-
- {t('statistics.title')}
-
-
- {t('statistics.desc')}
-
-
-
-
+
+ }>
+ 보고서 생성
+
+ }
+ />
{loading && (
@@ -242,6 +240,6 @@ export function Statistics() {
searchPlaceholder="지표명 검색..."
exportFilename="성과지표"
/>
-
+
);
}