-
-
일반 검증 목록
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
일반 검증 목록
+
+
+ {isLoading && (
+
+ )}
+ {isLoading ? null
+ :
+ vrfcMasterData.length > 0 ?
+
handleVrfcMasterRowClick(value)} />
+ :
+
+
+
+ }
+
+
+
diff --git a/apps/st/src/components/statistics/verification/HbStatisticsVerification.tsx b/apps/st/src/components/statistics/verification/HbStatisticsVerification.tsx
index 07c2663c9..3bb9d22af 100644
--- a/apps/st/src/components/statistics/verification/HbStatisticsVerification.tsx
+++ b/apps/st/src/components/statistics/verification/HbStatisticsVerification.tsx
@@ -15,19 +15,17 @@ import { ENDPOINT } from "@/shared/config";
import { useAlertStore } from "@/shared/lib";
import type { ApiErrorResponse } from "@/shared/model";
import { CodeSelect } from "@/entities/code";
-import { analysisApi } from "@/entities/statistics/api/analysis-api";
-import { analysisHistoryApi } from "@/entities/statistics/api/analysis-history-api";
-import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
-import type {
- StAnlsMstResponse,
- StAnlsMstSearchParams,
- StAnlsOutlierListResponse,
-} from "@/entities/statistics/model/analysis-history-interface";
import type {
AnalysisRequestPayload,
AnalysisResponseDto,
-} from "@/entities/statistics/model/analysis-interface";
-import { verificationHistoryColumns } from "@/entities/statistics/model/verification-history-columns";
+ StAnlsMstResponse,
+ StAnlsMstSearchParams,
+ StAnlsOutlierListResponse,
+} from "@/entities/statistics";
+import { verificationHistoryColumns } from "@/entities/statistics";
+import { analysisApi } from "@/entities/statistics/api/analysis-api";
+import { analysisHistoryApi } from "@/entities/statistics/api/analysis-history-api";
+import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
import type { VerificationTargetCodeResponse } from "@/entities/statistics/model/verification-target-management-interface";
import {
Button,
@@ -228,11 +226,7 @@ const HbStatisticsVerification = () => {
state: {
pagination: historyPagination,
},
- onPaginationChange: (updater) => {
- setHistoryPagination((prev) =>
- typeof updater === "function" ? updater(prev) : updater,
- );
- },
+ onPaginationChange: setHistoryPagination,
meta: {
onOutlierCellClick: (row: StAnlsMstResponse) => {
setOutlierDialog({ open: true, anlsSn: row.anlsSn });
diff --git a/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx b/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx
new file mode 100644
index 000000000..f6f76077b
--- /dev/null
+++ b/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx
@@ -0,0 +1,520 @@
+"use client";
+
+import { useEffect, useMemo, useState } from "react";
+import { Line } from "react-chartjs-2";
+
+import { useQuery } from "@tanstack/react-query";
+import {
+ getCoreRowModel,
+ getPaginationRowModel,
+ useReactTable,
+} from "@tanstack/react-table";
+import type { ChartOptions } from "chart.js";
+import {
+ CategoryScale,
+ Chart as ChartJS,
+ Legend,
+ LinearScale,
+ LineElement,
+ PointElement,
+ Title,
+ Tooltip as ChartTooltip,
+} from "chart.js";
+import dayjs from "dayjs";
+
+import { ENDPOINT } from "@/shared/config";
+import { CodeApi, CodeSelect } from "@/entities/code";
+import type {
+ StAnlsMstResponse,
+ StAnlsMstSearchParams,
+ StAnlsRsltResponse,
+} from "@/entities/statistics";
+import {
+ imrDetailGridColumnInfo,
+ imrVerificationHistoryColumns,
+} from "@/entities/statistics";
+import { analysisHistoryApi } from "@/entities/statistics/api/analysis-history-api";
+import { imrApi } from "@/entities/statistics/api/imr-api";
+import { stAnlsRsltApi } from "@/entities/statistics/api/statistics-analysis-result-api";
+import {
+ Button,
+ DataTable,
+ DateRangePicker,
+ Label,
+ LoadingWithAnimation,
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@common/components";
+
+import DataGrid from "@/components/module/DataGrid";
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ ChartTooltip,
+ Legend,
+);
+
+type DateRangeValue = {
+ from: Date;
+ to?: Date;
+};
+
+const EMPTY_DATA: never[] = [];
+
+const ImrVerificationHistory = () => {
+ // Area A Search States
+ const [searchSido, setSearchSido] = useState
("");
+ const [searchSigungu, setSearchSigungu] = useState("");
+ const [searchStatsCd, setSearchStatsCd] = useState("");
+ const [dateRange, setDateRange] = useState({
+ from: dayjs().subtract(1, "month").toDate(),
+ to: dayjs().toDate(),
+ });
+ const [appliedSearchParams, setAppliedSearchParams] =
+ useState({
+ page: 0,
+ size: 10,
+ vrfcMthdCd: "IMR",
+ sort: "anlsSn,desc",
+ });
+
+ // Selected States
+ const [selectedHistory, setSelectedHistory] =
+ useState(null);
+ const [selectedDetail, setSelectedDetail] =
+ useState(null);
+
+ // Area B Grid State
+ const [gridRowData, setGridRowData] = useState<
+ Record[]
+ >([]);
+
+ // Area A Pagination
+ const [historyPagination, setHistoryPagination] = useState({
+ pageIndex: 0,
+ pageSize: 10,
+ });
+
+ // Codes for Filter
+ const { data: lwpoCodes } = useQuery({
+ queryKey: [ENDPOINT.CMS_SERVICE.CODE, "LAESECD"],
+ queryFn: () => CodeApi.getCode("LAESECD"),
+ });
+
+ const sidoOptions = useMemo(() => {
+ if (!lwpoCodes) return [];
+ return lwpoCodes.filter(
+ (c) => c.lwpoCd.startsWith("G3") && c.lwpoCd.length === 4,
+ );
+ }, [lwpoCodes]);
+
+ const sigunguOptions = useMemo(() => {
+ if (!lwpoCodes || searchSido === "") return [];
+ return lwpoCodes.filter(
+ (c) => c.lwpoCd.startsWith(searchSido) && c.lwpoCd.length === 7,
+ );
+ }, [lwpoCodes, searchSido]);
+
+ // Area A Data Fetching
+ const { data: historyData } = useQuery({
+ queryKey: [
+ ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST,
+ appliedSearchParams,
+ historyPagination,
+ ],
+ queryFn: () =>
+ analysisHistoryApi.getAnalysisHistoryList({
+ ...appliedSearchParams,
+ page: historyPagination.pageIndex,
+ size: historyPagination.pageSize,
+ }),
+ });
+
+ const historyTable = useReactTable({
+ data: historyData?.content ?? EMPTY_DATA,
+ columns: imrVerificationHistoryColumns,
+ getRowId: (row) => String(row.anlsSn),
+ getCoreRowModel: getCoreRowModel(),
+ getPaginationRowModel: getPaginationRowModel(),
+ manualPagination: true,
+ pageCount: historyData?.totalPages ?? 0,
+ state: {
+ pagination: historyPagination,
+ rowSelection: selectedHistory
+ ? { [selectedHistory.anlsSn]: true }
+ : {},
+ },
+ onPaginationChange: setHistoryPagination,
+ });
+
+ // Area B Data Fetching
+ const { data: detailData, isLoading: isDetailLoading } = useQuery({
+ queryKey: [
+ ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_RSLT,
+ selectedHistory?.anlsSn,
+ ],
+ queryFn: () =>
+ stAnlsRsltApi.getImrResultList(selectedHistory!.anlsSn, {
+ page: 0,
+ size: 100,
+ sort: "rsltSn,asc",
+ }),
+ enabled: !!selectedHistory,
+ });
+
+ useEffect(() => {
+ if (!detailData || !detailData.content) {
+ setGridRowData([]);
+ return;
+ }
+ const mapped = detailData.content.map((item) => ({
+ ...item,
+ statsNm: selectedHistory?.vrfcTrgtNm ?? "-",
+ }));
+ setGridRowData(mapped as unknown as Record[]);
+ }, [detailData, selectedHistory]);
+
+ // Area C Data Fetching
+ const { data: chartData, isLoading: isChartLoading } = useQuery({
+ queryKey: [
+ "imr-log",
+ selectedHistory?.anlsSn,
+ selectedDetail?.vrfcTrgtSn,
+ selectedDetail?.admdstCd,
+ ],
+ queryFn: () =>
+ imrApi.getOutliersLog({
+ anlsSn: selectedHistory!.anlsSn,
+ vrfcTrgtSn: selectedDetail!.vrfcTrgtSn,
+ admdstCd: selectedDetail!.admdstCd,
+ }),
+ enabled: !!selectedHistory && !!selectedDetail,
+ });
+
+ const handleSearch = () => {
+ const params: StAnlsMstSearchParams = {
+ vrfcMthdCd: "IMR",
+ sort: "anlsSn,desc",
+ };
+ if (searchSido !== "")
+ params.sewerBzmnCd =
+ searchSigungu !== "" ? searchSigungu : searchSido;
+ if (searchStatsCd) params.statsCd = searchStatsCd;
+ if (dateRange?.from)
+ params.verifyDtStart = dayjs(dateRange.from).format("YYYY-MM-DD");
+ if (dateRange?.to)
+ params.verifyDtEnd = dayjs(dateRange.to).format("YYYY-MM-DD");
+
+ setAppliedSearchParams(params);
+ setHistoryPagination((prev) => ({ ...prev, pageIndex: 0 }));
+ setSelectedHistory(null);
+ setSelectedDetail(null);
+ };
+
+ const handleReset = () => {
+ setSearchSido("");
+ setSearchSigungu("");
+ setSearchStatsCd("");
+ const defaultRange = {
+ from: dayjs().subtract(1, "month").toDate(),
+ to: dayjs().toDate(),
+ };
+ setDateRange(defaultRange);
+ };
+
+ const chartOptions: ChartOptions<"line"> = useMemo(
+ () => ({
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ position: "top" as const,
+ labels: {
+ font: {
+ size: 12,
+ },
+ },
+ },
+ title: {
+ display: true,
+ text: selectedDetail
+ ? `${selectedDetail.fcltNm} - I-MR 분석 차트`
+ : "I-MR 분석 차트",
+ font: {
+ size: 16,
+ weight: "bold",
+ },
+ },
+ },
+ scales: {
+ y: {
+ beginAtZero: false,
+ title: {
+ display: true,
+ text: "수치",
+ },
+ },
+ x: {
+ title: {
+ display: true,
+ text: "연도",
+ },
+ },
+ },
+ }),
+ [selectedDetail],
+ );
+
+ const lineChartData = useMemo(() => {
+ if (!chartData || !chartData.history) return null;
+
+ const labels = chartData.history.map((h) => String(h.year));
+ const actualData = chartData.history.map((h) => h.x);
+ const uclData = chartData.history.map((h) => h.ucl);
+ const lclData = chartData.history.map((h) => h.lcl);
+ const predictedData = chartData.history.map((h) => h.predicted);
+
+ return {
+ labels,
+ datasets: [
+ {
+ label: "실측치 (X)",
+ data: actualData,
+ borderColor: "rgb(75, 192, 192)",
+ backgroundColor: "rgba(75, 192, 192, 0.5)",
+ tension: 0.1,
+ pointRadius: 4,
+ pointHoverRadius: 6,
+ },
+ {
+ label: "상한선 (UCL)",
+ data: uclData,
+ borderColor: "rgb(255, 99, 132)",
+ backgroundColor: "rgba(255, 99, 132, 0.2)",
+ borderDash: [5, 5],
+ pointStyle: "false",
+ fill: false,
+ },
+ {
+ label: "하한선 (LCL)",
+ data: lclData,
+ borderColor: "rgb(54, 162, 235)",
+ backgroundColor: "rgba(54, 162, 235, 0.2)",
+ borderDash: [5, 5],
+ pointStyle: "false",
+ fill: false,
+ },
+ {
+ label: "예측치 (Predicted)",
+ data: predictedData,
+ borderColor: "rgb(153, 102, 255)",
+ backgroundColor: "rgba(153, 102, 255, 0.5)",
+ borderDash: [2, 2],
+ pointStyle: "false",
+ fill: false,
+ },
+ ],
+ };
+ }, [chartData]);
+
+ return (
+
+ {/* 영역 A: 검증 이력 그리드 + 검색 필터 */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setDateRange(
+ val
+ ? { from: val.from!, to: val.to }
+ : undefined,
+ )
+ }
+ className="w-[20rem]"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setSelectedHistory(row);
+ setSelectedDetail(null);
+ }}
+ viewPagination={true}
+ className="[&_td]:!p-0"
+ />
+
+
+
+
+ {/* 영역 B: 상세 데이터 그리드 */}
+
+
+
+ 이상치 데이터
+
+
+
+
+ {isDetailLoading ? (
+
+ ) : !selectedHistory || gridRowData.length === 0 ? (
+
+ {!selectedHistory
+ ? "항목을 선택해주세요."
+ : "표시할 항목이 없습니다."}
+
+ ) : (
+
{
+ if (!e.rowId) return;
+ const row = detailData?.content?.find(
+ (item) =>
+ String(item.rsltSn) ===
+ String(e.rowId),
+ );
+ if (row) setSelectedDetail(row);
+ }}
+ />
+ )}
+
+
+
+ {/* 영역 C: Line Chart */}
+
+
+ 검증 결과 차트
+
+
+ {isChartLoading ? (
+
+
+
+ ) : lineChartData ? (
+
+ ) : (
+
+ 상세 데이터를 선택하면 차트가 표시됩니다.
+
+ )}
+
+
+
+
+ );
+};
+
+export default ImrVerificationHistory;
diff --git a/apps/st/src/components/statistics/verification/VerificationArticleManagement.tsx b/apps/st/src/components/statistics/verification/VerificationArticleManagement.tsx
index d919a6823..ec4f2b082 100644
--- a/apps/st/src/components/statistics/verification/VerificationArticleManagement.tsx
+++ b/apps/st/src/components/statistics/verification/VerificationArticleManagement.tsx
@@ -7,12 +7,12 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
import { CodeSelect } from "@/entities/code/ui/code-select";
-import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
import {
hbArticleColumnInfo,
imrArticleColumnInfo,
validationArticleColumnInfo,
-} from "@/entities/statistics/model/verification-article-column";
+} from "@/entities/statistics";
+import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
import type {
VerificationTargetManagementResponse,
VerificationTargetManagementSearchParams,
diff --git a/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx b/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx
index a9e267506..4ec8b3a39 100644
--- a/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx
+++ b/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx
@@ -1,6 +1,6 @@
import React, { useState } from "react";
-import type { StAnlsDtlResponse } from "@/entities/statistics/model/statistics-analysis-detail-interface";
+import type { StAnlsDtlResponse } from "@/entities/statistics";
import { Button } from "@common/components";
import Indicators from "./Indicators";
@@ -26,6 +26,7 @@ const HbVerificationDetail: React.FC = ({
const [selectedVrfcTrgtSn, setSelectedVrfcTrgtSn] = useState(
null,
);
+ const [checkedSns, setCheckedSns] = useState([]);
const [appliedFilter, setAppliedFilter] = useState({
sido: "",
gugun: "",
@@ -53,20 +54,23 @@ const HbVerificationDetail: React.FC = ({
return (
-
-
-
- 검증 상세
-
+
+
+
+
+ 검증 상세
+
+
+
@@ -75,6 +79,8 @@ const HbVerificationDetail: React.FC = ({
anlsSn={anlsSn}
selectedVrfcTrgtSn={selectedVrfcTrgtSn}
onSelect={handleTargetSelect}
+ checkedSns={checkedSns}
+ onCheck={setCheckedSns}
/>
diff --git a/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx b/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx
index 1a691283d..a932cfb3e 100644
--- a/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx
+++ b/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx
@@ -1,13 +1,13 @@
import React, { useEffect, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
-import { ValueType } from "realgrid";
import { ENDPOINT } from "@/shared/config";
import { CodeApi } from "@/entities/code/api/code-service";
+import type { StAnlsRsltResponse } from "@/entities/statistics";
import { useStAnlsRsltList } from "@/entities/statistics/api/queries";
import { stAnlsRsltApi } from "@/entities/statistics/api/statistics-analysis-result-api";
-import type { StAnlsRsltResponse } from "@/entities/statistics/model/statistics-analysis-result-interface";
+import { regionalGridColumnInfo as columnInfo } from "@/entities/statistics/model/regional-grid-columns";
import {
Button,
LoadingWithAnimation,
@@ -21,7 +21,6 @@ import {
import type { AppliedFilter } from "./HbVerificationDetail";
import DataGrid from "@/components/module/DataGrid";
-import type { ColumnInfo } from "@/components/type/DataGrid.type";
interface RegionalGridProps {
anlsSn: number;
@@ -113,7 +112,7 @@ const RegionalGrid: React.FC
= ({
if (appliedFilter.status) {
data = data.filter(
(item) =>
- item.otlrYn.toLowerCase() === appliedFilter.status,
+ item.otlrYnCd.toLowerCase() === appliedFilter.status,
);
}
}
@@ -133,7 +132,7 @@ const RegionalGrid: React.FC = ({
const mappedData = data.map((item) => ({
...item,
- otlrYn: mapOtlrToLabel(item.otlrYn),
+ otlrYn: mapOtlrToLabel(item.otlrYnCd),
}));
setGridRowData(
@@ -148,89 +147,6 @@ const RegionalGrid: React.FC = ({
gugunOptions,
]);
- const columnInfo: ColumnInfo = useMemo(
- () => ({
- columns: [
- {
- name: "sido",
- fieldName: "sido",
- header: { text: "시도" },
- width: 80,
- },
- {
- name: "gugun",
- fieldName: "gugun",
- header: { text: "구군" },
- width: 80,
- },
- {
- name: "admdstNm",
- fieldName: "admdstNm",
- header: { text: "행정구역" },
- width: 100,
- },
- {
- name: "prvyrVl",
- fieldName: "prvyrVl",
- header: { text: "이전년도" },
- width: 80,
- valueType: ValueType.NUMBER,
- dataFormat: "#,##0",
- },
- {
- name: "cryrVl",
- fieldName: "cryrVl",
- header: { text: "당해년도" },
- width: 80,
- valueType: ValueType.NUMBER,
- dataFormat: "#,##0",
- },
- {
- name: "chgRt",
- fieldName: "chgRt",
- header: { text: "R" },
- width: 60,
- valueType: ValueType.NUMBER,
- dataFormat: "#,##0.00",
- },
- {
- name: "trsfRt",
- fieldName: "trsfRt",
- header: { text: "S" },
- width: 60,
- valueType: ValueType.NUMBER,
- dataFormat: "#,##0.00",
- },
- {
- name: "otlrTrsfRt",
- fieldName: "otlrTrsfRt",
- header: { text: "E" },
- width: 60,
- valueType: ValueType.NUMBER,
- dataFormat: "#,##0.00",
- },
- {
- name: "otlrYn",
- fieldName: "otlrYn",
- header: { text: "상태" },
- width: 60,
- },
- ],
- columnLayout: [
- "sido",
- "gugun",
- "admdstNm",
- "prvyrVl",
- "cryrVl",
- "chgRt",
- "trsfRt",
- "otlrTrsfRt",
- "otlrYn",
- ],
- }),
- [],
- );
-
const handleSidoChange = (val: string) => {
setSelectedSido(val);
setSelectedGugun("");
@@ -331,6 +247,7 @@ const RegionalGrid: React.FC = ({
정상
이상치
+ 제외
diff --git a/apps/st/src/components/statistics/verification/detail/ScatterChart.tsx b/apps/st/src/components/statistics/verification/detail/ScatterChart.tsx
index 3f020ab93..57eba1445 100644
--- a/apps/st/src/components/statistics/verification/detail/ScatterChart.tsx
+++ b/apps/st/src/components/statistics/verification/detail/ScatterChart.tsx
@@ -19,11 +19,11 @@ import zoomPlugin from "chartjs-plugin-zoom";
import { ENDPOINT } from "@/shared/config";
import { CodeApi } from "@/entities/code/api/code-service";
+import type { StAnlsRsltResponse } from "@/entities/statistics";
import {
useStAnlsChartData,
useStAnlsRsltList,
} from "@/entities/statistics/api/queries";
-import type { StAnlsRsltResponse } from "@/entities/statistics/model/statistics-analysis-result-interface";
import { LoadingWithAnimation } from "@common/components";
import type { AppliedFilter } from "./HbVerificationDetail";
@@ -124,7 +124,7 @@ const ScatterChart: React.FC
= ({
if (
appliedFilter.status &&
- item.otlrYn.toLowerCase() !== appliedFilter.status
+ item.otlrYnCd.toLowerCase() !== appliedFilter.status
) {
return;
}
@@ -135,7 +135,7 @@ const ScatterChart: React.FC = ({
item,
};
- if (item.otlrYn === "0") {
+ if (item.otlrYnCd === "0") {
normalPoints.push(pt);
} else {
outlierPoints.push(pt);
diff --git a/apps/st/src/components/statistics/verification/detail/VerificationList.tsx b/apps/st/src/components/statistics/verification/detail/VerificationList.tsx
index 5c2f89065..3966b3131 100644
--- a/apps/st/src/components/statistics/verification/detail/VerificationList.tsx
+++ b/apps/st/src/components/statistics/verification/detail/VerificationList.tsx
@@ -1,45 +1,29 @@
import React, { useEffect, useMemo } from "react";
import { useQuery } from "@tanstack/react-query";
-import {
- type ColumnDef,
- getCoreRowModel,
- useReactTable,
-} from "@tanstack/react-table";
+import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { ENDPOINT } from "@/shared/config";
+import type { StAnlsDtlResponse } from "@/entities/statistics";
+import { getVerificationListColumns } from "@/entities/statistics";
import { stAnlsDtlApi } from "@/entities/statistics/api/statistics-analysis-detail-api";
-import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
-import type { StAnlsDtlResponse } from "@/entities/statistics/model/statistics-analysis-detail-interface";
import { DataTable } from "@common/components";
interface VerificationListProps {
anlsSn: number;
selectedVrfcTrgtSn: string | null;
onSelect: (row: StAnlsDtlResponse) => void;
+ checkedSns: string[];
+ onCheck: (checkedSns: string[], rows: StAnlsDtlResponse[]) => void;
}
const VerificationList: React.FC = ({
anlsSn,
selectedVrfcTrgtSn,
onSelect,
+ checkedSns,
+ onCheck,
}) => {
- const { data: verificationTargetCodes } = useQuery({
- queryKey: [ENDPOINT.STATVERIFY_SERVICE.VRFCTGT_MNG, "codes"],
- queryFn: () =>
- verificationTargetManagementApi.getVerificationTargetCodes(),
- });
-
- const targetCodeMap = useMemo(() => {
- const map = new Map();
- if (verificationTargetCodes) {
- verificationTargetCodes.forEach((item) => {
- map.set(item.vrfcTrgtSn, item.vrfcTrgtNm);
- });
- }
- return map;
- }, [verificationTargetCodes]);
-
const { data: detailData, isLoading } = useQuery({
queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL, "list", anlsSn],
queryFn: () =>
@@ -51,50 +35,9 @@ const VerificationList: React.FC = ({
return (detailData?.content ?? []) as StAnlsDtlResponse[];
}, [detailData]);
- const columns: ColumnDef[] = useMemo(
- () => [
- {
- header: "통계 년도",
- accessorKey: "statsYr",
- },
- {
- header: "통계 항목",
- accessorKey: "statsNm",
- },
- {
- header: "검증 항목",
- accessorKey: "vrfcTrgtNm",
- },
- {
- header: "μ",
- accessorKey: "ipcrCntVl",
- },
- {
- header: "Percentile",
- accessorKey: "pctlCrtrVl",
- },
- {
- header: "A",
- accessorKey: "scopAjmtCntVl",
- },
- {
- header: "C",
- accessorKey: "thrsCntVl",
- },
- {
- header: "정상건수",
- accessorKey: "nmlDataNocs",
- },
- {
- header: "제외건수",
- accessorKey: "exclDataNocs",
- },
- {
- header: "이상건수",
- accessorKey: "otlrDataNocs",
- },
- ],
- [targetCodeMap],
+ const columns = useMemo(
+ () => getVerificationListColumns({ rowData, checkedSns, onCheck }),
+ [rowData, checkedSns, onCheck],
);
const table = useReactTable({
@@ -134,15 +77,13 @@ const VerificationList: React.FC = ({
)}
{!isLoading && rowData.length > 0 && (
-
-
-
+
)}
);
diff --git a/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx b/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx
new file mode 100644
index 000000000..b0e81c08f
--- /dev/null
+++ b/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx
@@ -0,0 +1,147 @@
+import { useState, useEffect } from "react";
+
+import {
+ Button,
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+ DialogClose,
+ Label,
+ Input,
+} from "@common/components";
+import { CodeSelect } from "@/entities/code";
+import { useAlertStore } from "@/shared/lib";
+import { useConfirm } from "@frontend-opensource/use-react-hooks";
+import { getUserInfo } from "../../../../../../../packages/common/components/src/api";
+import { LoadingWithAnimation } from "@common/components";
+
+import { generalverificationApiService } from "@/entities/statistics/api/general-verification-service";
+
+import type { GeneralverificationList } from "@/entities/statistics/model/general-verification-interface";
+
+interface CopyDialogProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ children?: React.ReactNode;
+ row?: GeneralverificationList;
+ /** 수정/등록 성공 시 부모에서 목록 재조회 등 실행 */
+ onSuccess?: () => void;
+}
+
+const CopyDialog = ({
+ children,
+ open,
+ onOpenChange,
+ row,
+ onSuccess,
+ ...props
+}: CopyDialogProps) => {
+
+ const [selectedCode, setSelectedCode] = useState