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="성과지표" /> -
+
); }