[st] feat: 통계 검증 상세 자료 다운로드 작업 및 QA 반영
This commit is contained in:
@@ -180,7 +180,8 @@ const HbStatisticsVerification = () => {
|
||||
const params: StAnlsMstSearchParams = {
|
||||
page: historyPagination.pageIndex,
|
||||
size: historyPagination.pageSize,
|
||||
sort: "anlsSn,desc",
|
||||
sort: "anlsSn,desc",
|
||||
vrfcMthdCd: "HB",
|
||||
};
|
||||
|
||||
if (appliedHistoryDateRange?.from) {
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import { useState } from "react";
|
||||
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
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";
|
||||
import type {
|
||||
VerificationTargetManagementResponse,
|
||||
VerificationTargetManagementSearchParams,
|
||||
} from "@/entities/statistics/model/verification-target-management-interface";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
@@ -15,17 +26,10 @@ import {
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@common/components";
|
||||
import { CodeSelect } from "@/entities/code/ui/code-select";
|
||||
import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import type {
|
||||
VerificationTargetManagementSearchParams,
|
||||
VerificationTargetManagementResponse,
|
||||
} from "@/entities/statistics/model/verification-target-management-interface";
|
||||
|
||||
import { VerificationTargetDialog } from "./VerificationTargetDialog";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
|
||||
const TAB_CONFIG = {
|
||||
HB: { value: "HB", label: "H-B", columnInfo: hbArticleColumnInfo },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import type { StAnlsDtlResponse } from "@/entities/statistics/model/statistics-analysis-detail-interface";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import Indicators from "./Indicators";
|
||||
@@ -20,6 +21,18 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
null,
|
||||
);
|
||||
const [selectedSido, setSelectedSido] = useState<string | null>(null);
|
||||
const [selectedTargetInfo, setSelectedTargetInfo] = useState<{
|
||||
statsNm: string;
|
||||
vrfcTrgtNm: string;
|
||||
} | null>(null);
|
||||
|
||||
const handleTargetSelect = (row: StAnlsDtlResponse) => {
|
||||
setSelectedVrfcTrgtSn(String(row.vrfcTrgtSn));
|
||||
setSelectedTargetInfo({
|
||||
statsNm: row.statsNm,
|
||||
vrfcTrgtNm: row.vrfcTrgtNm,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
@@ -44,7 +57,7 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
<VerificationList
|
||||
anlsSn={anlsSn}
|
||||
selectedVrfcTrgtSn={selectedVrfcTrgtSn}
|
||||
onSelect={setSelectedVrfcTrgtSn}
|
||||
onSelect={handleTargetSelect}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -57,6 +70,10 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
<RegionalGrid
|
||||
anlsSn={anlsSn}
|
||||
vrfcTrgtSn={selectedVrfcTrgtSn}
|
||||
statsNm={selectedTargetInfo?.statsNm || ""}
|
||||
vrfcTrgtNm={
|
||||
selectedTargetInfo?.vrfcTrgtNm || ""
|
||||
}
|
||||
selectedSido={selectedSido}
|
||||
onSidoSelect={setSelectedSido}
|
||||
/>
|
||||
|
||||
@@ -23,6 +23,8 @@ import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||
interface RegionalGridProps {
|
||||
anlsSn: number;
|
||||
vrfcTrgtSn: string | null;
|
||||
statsNm: string;
|
||||
vrfcTrgtNm: string;
|
||||
selectedSido: string | null;
|
||||
onSidoSelect: (sido: string | null) => void;
|
||||
}
|
||||
@@ -36,6 +38,8 @@ interface AppliedFilter {
|
||||
const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
anlsSn,
|
||||
vrfcTrgtSn,
|
||||
statsNm,
|
||||
vrfcTrgtNm,
|
||||
selectedSido,
|
||||
onSidoSelect,
|
||||
}) => {
|
||||
@@ -48,6 +52,7 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
gugun: "",
|
||||
status: "",
|
||||
});
|
||||
const [isDownloading, setIsDownloading] = useState<boolean>(false);
|
||||
|
||||
const [gridRowData, setGridRowData] = useState<
|
||||
Record<string, string | number>[]
|
||||
@@ -256,6 +261,31 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
setShowAllOnEmptyFilter(true);
|
||||
};
|
||||
|
||||
const handleDownload = async () => {
|
||||
if (!vrfcTrgtSn) return;
|
||||
setIsDownloading(true);
|
||||
|
||||
try {
|
||||
const blob = await stAnlsRsltApi.downloadExcel(
|
||||
anlsSn,
|
||||
Number(vrfcTrgtSn),
|
||||
);
|
||||
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `분석결과_${statsNm}-${vrfcTrgtNm}.xlsx`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
} catch (error) {
|
||||
console.error("Failed to download excel", error);
|
||||
} finally {
|
||||
setIsDownloading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex justify-between">
|
||||
@@ -310,8 +340,20 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
초기화
|
||||
</Button>
|
||||
<Button onClick={handleSearch}>조회</Button>
|
||||
<Button color="green" onClick={() => {}}>
|
||||
다운로드
|
||||
<Button
|
||||
color="green"
|
||||
onClick={handleDownload}
|
||||
disabled={!vrfcTrgtSn || isDownloading}
|
||||
>
|
||||
{isDownloading ? (
|
||||
<div className="flex w-[4.8rem] items-center justify-center">
|
||||
<div className="relative size-[2rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
"다운로드"
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Chart as ChartJS,
|
||||
Legend,
|
||||
LinearScale,
|
||||
LineController,
|
||||
LineElement,
|
||||
PointElement,
|
||||
ScatterController,
|
||||
@@ -21,11 +22,12 @@ import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
ChartJS.register(
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineController,
|
||||
LineElement,
|
||||
Tooltip,
|
||||
Legend,
|
||||
PointElement,
|
||||
ScatterController,
|
||||
Legend,
|
||||
Tooltip,
|
||||
zoomPlugin,
|
||||
);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { DataTable } from "@common/components";
|
||||
interface VerificationListProps {
|
||||
anlsSn: number;
|
||||
selectedVrfcTrgtSn: string | null;
|
||||
onSelect: (vrfcTrgtSn: string) => void;
|
||||
onSelect: (row: StAnlsDtlResponse) => void;
|
||||
}
|
||||
|
||||
const VerificationList: React.FC<VerificationListProps> = ({
|
||||
@@ -101,7 +101,9 @@ const VerificationList: React.FC<VerificationListProps> = ({
|
||||
data: rowData,
|
||||
columns,
|
||||
state: {
|
||||
rowSelection: selectedVrfcTrgtSn ? { [selectedVrfcTrgtSn]: true } : {},
|
||||
rowSelection: selectedVrfcTrgtSn
|
||||
? { [selectedVrfcTrgtSn]: true }
|
||||
: {},
|
||||
},
|
||||
enableMultiRowSelection: false,
|
||||
getRowId: (row) => String(row.vrfcTrgtSn),
|
||||
@@ -109,13 +111,13 @@ const VerificationList: React.FC<VerificationListProps> = ({
|
||||
});
|
||||
|
||||
const handleRowClick = (row: StAnlsDtlResponse) => {
|
||||
onSelect(String(row.vrfcTrgtSn));
|
||||
onSelect(row);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedVrfcTrgtSn && rowData.length > 0) {
|
||||
const firstTargetSn = rowData[0]?.vrfcTrgtSn;
|
||||
if (firstTargetSn) onSelect(String(firstTargetSn));
|
||||
const firstRow = rowData[0];
|
||||
if (firstRow) onSelect(firstRow);
|
||||
}
|
||||
}, [selectedVrfcTrgtSn, rowData, onSelect]);
|
||||
|
||||
@@ -132,13 +134,15 @@ const VerificationList: React.FC<VerificationListProps> = ({
|
||||
</div>
|
||||
)}
|
||||
{!isLoading && rowData.length > 0 && (
|
||||
<DataTable
|
||||
table={table}
|
||||
variant="secondary"
|
||||
onRowClick={handleRowClick}
|
||||
viewPagination={false}
|
||||
className="whitespace-nowrap text-[1.2rem] [&_td]:!px-2 [&_th]:!px-2"
|
||||
/>
|
||||
<div className="rounded-md border">
|
||||
<DataTable
|
||||
table={table}
|
||||
variant="secondary"
|
||||
onRowClick={handleRowClick}
|
||||
viewPagination={false}
|
||||
className="whitespace-nowrap text-[1.2rem] [&_td]:!px-2 [&_th]:!px-2"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -31,6 +31,20 @@ export class StAnlsRsltApiService {
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async downloadExcel(
|
||||
anlsSn: number,
|
||||
vrfcTrgtSn: number,
|
||||
): Promise<Blob> {
|
||||
const response = await client.get<Blob>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_RSLT}/excel-down/${anlsSn}/${vrfcTrgtSn}`,
|
||||
{
|
||||
responseType: "blob",
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const stAnlsRsltApi = new StAnlsRsltApiService();
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface StAnlsMstSearchParams extends PageableParams {
|
||||
jobUuid?: string;
|
||||
verifyDtStart?: string;
|
||||
verifyDtEnd?: string;
|
||||
vrfcMthdCd?: string;
|
||||
}
|
||||
|
||||
export interface StAnlsOutlierDataResponse {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ValueType } from "realgrid";
|
||||
import type { ColumnInfo } from "@rsone/components";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
export const hbArticleColumnInfo: ColumnInfo = {
|
||||
columns: [
|
||||
@@ -31,6 +31,15 @@ export const hbArticleColumnInfo: ColumnInfo = {
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
},
|
||||
{
|
||||
name: "ipcrCntVl",
|
||||
fieldName: "ipcrCntVl",
|
||||
header: { text: "μ" },
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: "#,##0.##",
|
||||
},
|
||||
{
|
||||
name: "pctlCrtrVl",
|
||||
fieldName: "pctlCrtrVl",
|
||||
@@ -78,6 +87,7 @@ export const hbArticleColumnInfo: ColumnInfo = {
|
||||
"vrfcTrgtNm",
|
||||
"tblNm",
|
||||
"colNm",
|
||||
"ipcrCntVl",
|
||||
"pctlCrtrVl",
|
||||
"scopCntCntVl",
|
||||
"thrsCntVl",
|
||||
|
||||
Reference in New Issue
Block a user