- {data.inptBgngYmd} ~ {data.inptEndYmd}
+ <>
+
+
+
+ 이번 주 주요 일정
+
+
+
+ 현재 진행 상태
+
+
+ {
+ CURRENT_STATUS_LABEL_MAP[
+ data.currentSe as keyof typeof CURRENT_STATUS_LABEL_MAP
+ ]
+ }
+
-
-
- 검증기간
+
+
+
+ {data.inptSeCd}차 입력기간
+
+
+ {dayjs(data.inptBgngYmd).format(
+ "YYYY.MM.DD",
+ )}{" "}
+ ~{" "}
+ {dayjs(data.inptEndYmd).format(
+ "YYYY.MM.DD",
+ )}
+
-
- {data.vrfcBgngYmd} ~ {data.vrfcEndYmd}
+
+
+ {data.vrfcSeCd}차 검증기간
+
+
+ {dayjs(data.vrfcBgngYmd).format(
+ "YYYY.MM.DD",
+ )}{" "}
+ ~{" "}
+ {dayjs(data.vrfcEndYmd).format(
+ "YYYY.MM.DD",
+ )}
+
-
+ >
)}
diff --git a/apps/st/src/pages/statistics/ui/panels/stats-submission-panel.tsx b/apps/st/src/pages/statistics/ui/panels/stats-submission-panel.tsx
index 23fe0c963..f973f4e9e 100644
--- a/apps/st/src/pages/statistics/ui/panels/stats-submission-panel.tsx
+++ b/apps/st/src/pages/statistics/ui/panels/stats-submission-panel.tsx
@@ -1,8 +1,14 @@
"use client";
-import { useDashboardStatsSubmissionRate } from "@/entities/statistics";
+import { Frown, Laugh, Meh, OctagonAlert, OctagonX, Smile } from "lucide-react";
+
+import {
+ useDashboardEcptReqCount,
+ useDashboardStatsSubmissionRate,
+ useDashboardVrfcErrCount,
+} from "@/entities/statistics";
import type { DashboardSearchParams } from "@/entities/statistics/model/dashboard/dashboard-interface";
-import { LoadingWithAnimation } from "@common/components";
+import { LoadingWithAnimation, Progress } from "@common/components";
import { useDragHandle } from "../sortable-panel";
@@ -10,70 +16,147 @@ interface StatsSubmissionPanelProps {
params: DashboardSearchParams | null;
}
+const STATUS_LEVEL_TEXT_COLOR = {
+ GREAT: "text-blue-500",
+ GOOD: "text-green-500",
+ WARNING: "text-yellow-500",
+ BAD: "text-red-500",
+};
+
+const STATUS_LEVEL_EMOJI = {
+ GREAT:
,
+ GOOD:
,
+ WARNING:
,
+ BAD:
,
+};
+
export function StatsSubmissionPanel({ params }: StatsSubmissionPanelProps) {
const { dragHandleProps, isDragging } = useDragHandle();
const { data, isLoading, error } = useDashboardStatsSubmissionRate(params);
+ const vrfcErrQuery = useDashboardVrfcErrCount(params);
+ const ecptReqQuery = useDashboardEcptReqCount(params);
return (
-
-
+ {/*
-
통계입력현황
-
-
- {isLoading && (
-
- )}
- {error && (
-
- 데이터를 불러올 수 없습니다.
-
- )}
- {data && (
-
- {/* TBD: statusLevel별 이모지 매핑 규칙 필요 */}
-
-
- {/* TBD: statusLevel 값에 따른 이모지 표시 */}
- {data.statusLevel === "GOOD"
- ? "😊"
- : data.statusLevel === "WARNING"
- ? "⚠️"
- : "📊"}
+
통계입력현황
+ */}
+
+
+
+
통계입력현황
+ {isLoading && (
+
-
- {data.statusLevel}
+ )}
+ {error && (
+
+ 데이터를 불러올 수 없습니다.
-
+ )}
+
+ {data && (
+
+ {/* 통계제출률 상태 이모지 */}
+
+ {
+ STATUS_LEVEL_EMOJI[
+ data.statusLevel as keyof typeof STATUS_LEVEL_EMOJI
+ ]
+ }
+
- {/* 통계제출률 프로그레스바 */}
-
-
-
통계제출률
-
- {data.submissionRate?.toFixed(1)}%
-
+ {/* 통계제출률 프로그레스바 */}
+
+
+
+ 통계제출률
+
+
+ {data.submissionRate?.toFixed(
+ 1,
+ )}
+ %
+
+ ({data.submittedCount}/
+ {data.totalCount})
+
+
+
+
+
+
+ )}
+
+
+
+
+ 검증오류 및 예외
+
+
+ {/* 검증오류 수 카드 */}
+
+
+
+ 검증오류 수
+
+ {vrfcErrQuery.isLoading && (
+
-
+ )}
+ {vrfcErrQuery.error && (
+
+ 데이터를 불러올 수 없습니다.
+
+ )}
+ {vrfcErrQuery.data && (
+
+ {vrfcErrQuery.data.vrfcErrCount.toLocaleString()}
+
+ )}
-
-
-
제출: {data.submittedCount}
-
전체: {data.totalCount}
+
+ {/* 예외신청 수 카드 */}
+
+
+
+ 예외신청 수
+
+ {ecptReqQuery.isLoading && (
+
-
+ )}
+ {ecptReqQuery.error && (
+
+ 데이터를 불러올 수 없습니다.
+
+ )}
+ {ecptReqQuery.data && (
+
+ {ecptReqQuery.data.ecptReqCount.toLocaleString()}
+
+ )}
- )}
+
);
diff --git a/apps/st/src/pages/statistics/ui/panels/unsubmit-panel.tsx b/apps/st/src/pages/statistics/ui/panels/unsubmit-panel.tsx
index d8c1fc832..fae349694 100644
--- a/apps/st/src/pages/statistics/ui/panels/unsubmit-panel.tsx
+++ b/apps/st/src/pages/statistics/ui/panels/unsubmit-panel.tsx
@@ -15,23 +15,20 @@ export function UnSubmitPanel({ params }: UnSubmitPanelProps) {
const { data, isLoading, error } = useDashboardUnSubmitCount(params);
return (
-
+
-
미제출 지표
+ 미제출 지표
{data && (
-
+
{data.unSubmitCount}건
)}
-
+
{isLoading && (
@@ -51,11 +48,11 @@ export function UnSubmitPanel({ params }: UnSubmitPanelProps) {
미제출 지표가 없습니다.
) : (
-
+
{data.unSubmitList.map((item) => (
{item.statsNm}
diff --git a/apps/st/src/pages/statistics/ui/panels/vrfc-err-panel.tsx b/apps/st/src/pages/statistics/ui/panels/vrfc-err-panel.tsx
index 2a753196c..58fb11477 100644
--- a/apps/st/src/pages/statistics/ui/panels/vrfc-err-panel.tsx
+++ b/apps/st/src/pages/statistics/ui/panels/vrfc-err-panel.tsx
@@ -20,15 +20,15 @@ export function VrfcErrPanel({ params }: VrfcErrPanelProps) {
const ecptReqQuery = useDashboardEcptReqCount(params);
return (
-
+
-
검증오류 및 예외
+ 검증오류 및 예외
-
+
{/* 검증오류 수 카드 */}
diff --git a/apps/st/src/pages/statistics/ui/panels/vrfc-report-panel.tsx b/apps/st/src/pages/statistics/ui/panels/vrfc-report-panel.tsx
index 193e71a37..51834d857 100644
--- a/apps/st/src/pages/statistics/ui/panels/vrfc-report-panel.tsx
+++ b/apps/st/src/pages/statistics/ui/panels/vrfc-report-panel.tsx
@@ -2,6 +2,11 @@
import { useDashboardVrfcReport } from "@/entities/statistics";
import type { DashboardSearchParams } from "@/entities/statistics/model/dashboard/dashboard-interface";
+import {
+ Badge,
+ type BadgeProps,
+ LoadingWithAnimation,
+} from "@common/components";
import { useDragHandle } from "../sortable-panel";
@@ -9,79 +14,107 @@ interface VrfcReportPanelProps {
params: DashboardSearchParams | null;
}
+const TYPE_CODE_NAME_MAP: Record
= {
+ NV: "일반",
+ IMR: "I-MR",
+};
+
+const TYPE_CODE_COLOR_MAP: Record = {
+ NV: "gray",
+ IMR: "red",
+};
+
export function VrfcReportPanel({ params }: VrfcReportPanelProps) {
const { dragHandleProps, isDragging } = useDragHandle();
const { data, isLoading, error } = useDashboardVrfcReport(params);
return (
-
+
-
이상치 선별보고서
+ 이상치 선별보고서
-
+
{isLoading && (
-
로딩 중...
+
)}
{error && (
-
+
데이터를 불러올 수 없습니다.
)}
{data && (
-
+
{/* TBD: typeCounts 표시 방법 (탭? 필터?) */}
{data.typeCounts &&
Object.keys(data.typeCounts).length > 0 && (
{Object.entries(data.typeCounts).map(
([type, count]) => (
-
- {type}: {count}
-
+ {TYPE_CODE_NAME_MAP[type]}:{" "}
+ {count}
+
),
)}
)}
{/* TBD: 테이블 컬럼 정의, 증감 표시 방법 */}
-
+
{data.list.length === 0 ? (
-
+
이상치 항목이 없습니다.
) : (
-
+
{data.list.map((item, index) => (
-
-
+
+
{item.statsNm}
-
- {/* TBD: vrfcCd 값별 표시 레이블 */}
-
- {item.vrfcCd}
+
+ {
+ TYPE_CODE_NAME_MAP[
+ item.vrfcCd
+ ]
+ }
+
-
-
+
+
{item.admdstNm}
{/* TBD: 증감 표시 방법 (nowVlCn - compVlCn 계산?) */}
- 현재: {item.nowVlCn} / 비교:{" "}
- {item.compVlCn}
+ 현재: {item.nowVlCn ?? "-"}{" "}
+ / 비교:{" "}
+ {item.compVlCn ?? "-"}
{/* TBD: 등급/점수/단계/업데이트 시각 필드 미제공 */}
diff --git a/apps/st/src/pages/statistics/ui/statistics-page.tsx b/apps/st/src/pages/statistics/ui/statistics-page.tsx
index e50f90a0d..131ab95dd 100644
--- a/apps/st/src/pages/statistics/ui/statistics-page.tsx
+++ b/apps/st/src/pages/statistics/ui/statistics-page.tsx
@@ -37,14 +37,14 @@ const StatisticsPage = () => {
// 탭이 없으면 Dashboard 표시
if (tabs.length === 0) {
return (
-
+
);
}
return (
-
+
{tabs.map((tab) => {
// 렌더링 시점에 컴포넌트가 없으면 바로 로드
if (!componentCache.current.has(tab.id)) {