- 4개 catalog(eventStatuses/enforcementResults/enforcementActions/patrolStatuses)에 intent 필드 추가 + getXxxIntent() 헬퍼 신규 - statusIntent.ts 공통 유틸: 한글/영문 상태 문자열 → BadgeIntent 매핑 + getRiskIntent(0-100) 점수 기반 매핑 - 모든 Badge className="..." 패턴을 intent prop으로 치환: - admin (AuditLogs/AccessControl/SystemConfig/NoticeManagement/DataHub) - ai-operations (AIModelManagement/MLOpsPage) - enforcement (EventList/EnforcementHistory) - field-ops (AIAlert) - detection (GearIdentification) - patrol (PatrolRoute/FleetOptimization) - parent-inference (ParentExclusion) - statistics (ExternalService/ReportManagement) - surveillance (MapControl) - risk-assessment (EnforcementPlan) - monitoring (SystemStatusPanel — ServiceCard statusColor → statusIntent 리팩토) - dashboard (Dashboard PatrolStatusBadge) 이제 Badge의 테마별 팔레트(라이트 파스텔 + 다크 translucent)가 자동 적용되며, 쇼케이스에서 palette 조정 시 모든 Badge 사용처에 일관되게 반영됨.
59 lines
3.9 KiB
TypeScript
59 lines
3.9 KiB
TypeScript
import { useTranslation } from 'react-i18next';
|
|
import { Badge } from '@shared/components/ui/badge';
|
|
import { PageContainer, PageHeader } from '@shared/components/layout';
|
|
import { DataTable, type DataColumn } from '@shared/components/common/DataTable';
|
|
import { getStatusIntent } from '@shared/constants/statusIntent';
|
|
import type { BadgeIntent } from '@lib/theme/variants';
|
|
import { Globe } from 'lucide-react';
|
|
|
|
/* SFR-14: 외부 서비스(예보·경보) 제공 결과 연계 */
|
|
|
|
interface Service { id: string; name: string; target: string; type: string; format: string; cycle: string; privacy: string; status: string; calls: string; [key: string]: unknown; }
|
|
const DATA: Service[] = [
|
|
{ id: 'EXT-01', name: '위험도 지도 제공', target: '해수부', type: 'API', format: 'JSON', cycle: '1시간', privacy: '비식별', status: '운영', calls: '12,450' },
|
|
{ id: 'EXT-02', name: '의심 선박 목록', target: '해수부', type: 'API', format: 'JSON', cycle: '실시간', privacy: '비식별', status: '운영', calls: '8,320' },
|
|
{ id: 'EXT-03', name: '단속 통계', target: '수협', type: '파일', format: 'Excel', cycle: '일 1회', privacy: '익명화', status: '운영', calls: '365' },
|
|
{ id: 'EXT-04', name: '어구 현황', target: '해양조사원', type: 'API', format: 'JSON', cycle: '6시간', privacy: '공개', status: '테스트', calls: '540' },
|
|
{ id: 'EXT-05', name: '경보 이력', target: '기상청', type: 'API', format: 'XML', cycle: '실시간', privacy: '비공개', status: '계획', calls: '-' },
|
|
];
|
|
const cols: DataColumn<Service>[] = [
|
|
{ key: 'id', label: 'ID', width: '70px', render: v => <span className="text-hint font-mono text-[10px]">{v as string}</span> },
|
|
{ key: 'name', label: '서비스명', sortable: true, render: v => <span className="text-heading font-medium">{v as string}</span> },
|
|
{ key: 'target', label: '제공 대상', width: '80px', sortable: true },
|
|
{ key: 'type', label: '방식', width: '50px', align: 'center', render: v => <Badge intent="cyan" size="sm">{v as string}</Badge> },
|
|
{ key: 'format', label: '포맷', width: '60px', align: 'center' },
|
|
{ key: 'cycle', label: '갱신주기', width: '70px' },
|
|
{ key: 'privacy', label: '정보등급', width: '70px', align: 'center',
|
|
render: v => {
|
|
const p = v as string;
|
|
const intent: BadgeIntent = p === '비공개' ? 'critical' : p === '비식별' ? 'warning' : p === '익명화' ? 'info' : 'success';
|
|
return <Badge intent={intent} size="xs">{p}</Badge>;
|
|
} },
|
|
{ key: 'status', label: '상태', width: '60px', align: 'center', sortable: true,
|
|
render: v => { const s = v as string; return <Badge intent={getStatusIntent(s)} size="xs">{s}</Badge>; } },
|
|
{ key: 'calls', label: '호출 수', width: '70px', align: 'right', render: v => <span className="text-heading font-bold">{v as string}</span> },
|
|
];
|
|
|
|
export function ExternalService() {
|
|
const { t } = useTranslation('statistics');
|
|
return (
|
|
<PageContainer>
|
|
<PageHeader
|
|
icon={Globe}
|
|
iconColor="text-green-400"
|
|
title={t('externalService.title')}
|
|
description={t('externalService.desc')}
|
|
demo
|
|
/>
|
|
<div className="flex gap-2">
|
|
{[{ 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 => (
|
|
<div key={k.l} className="flex-1 flex items-center gap-2 px-3 py-2 rounded-xl border border-border bg-card">
|
|
<span className={`text-base font-bold ${k.c}`}>{k.v}</span><span className="text-[9px] text-hint">{k.l}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<DataTable data={DATA} columns={cols} pageSize={10} searchPlaceholder="서비스명, 대상기관 검색..." searchKeys={['name', 'target']} exportFilename="외부서비스연계" />
|
|
</PageContainer>
|
|
);
|
|
}
|