[st] feat: 검증 결과 상세 그리드 및 차트 데이터 동기화
This commit is contained in:
@@ -13,6 +13,12 @@ interface HbVerificationDetailProps {
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
export interface AppliedFilter {
|
||||
sido: string | null;
|
||||
gugun: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
anlsSn,
|
||||
onBack,
|
||||
@@ -20,7 +26,11 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
const [selectedVrfcTrgtSn, setSelectedVrfcTrgtSn] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
const [selectedSido, setSelectedSido] = useState<string | null>(null);
|
||||
const [appliedFilter, setAppliedFilter] = useState<AppliedFilter>({
|
||||
sido: "",
|
||||
gugun: "",
|
||||
status: "",
|
||||
});
|
||||
const [selectedRowId, setSelectedRowId] = useState<number | null>(null);
|
||||
const [selectedTargetInfo, setSelectedTargetInfo] = useState<{
|
||||
statsNm: string;
|
||||
@@ -34,6 +44,11 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
vrfcTrgtNm: row.vrfcTrgtNm,
|
||||
});
|
||||
setSelectedRowId(null);
|
||||
setAppliedFilter({
|
||||
sido: "",
|
||||
gugun: "",
|
||||
status: "",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -76,8 +91,9 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
vrfcTrgtNm={
|
||||
selectedTargetInfo?.vrfcTrgtNm || ""
|
||||
}
|
||||
onSidoSelect={setSelectedSido}
|
||||
onFilterChange={setAppliedFilter}
|
||||
selectedRowId={selectedRowId}
|
||||
appliedFilter={appliedFilter}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-[0.5] flex-col gap-4 p-4 pt-[4.8rem]">
|
||||
@@ -89,7 +105,7 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
<ScatterChart
|
||||
anlsSn={anlsSn}
|
||||
vrfcTrgtSn={selectedVrfcTrgtSn}
|
||||
selectedSido={selectedSido}
|
||||
appliedFilter={appliedFilter}
|
||||
onPointClick={setSelectedRowId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
SelectValue,
|
||||
} from "@common/components";
|
||||
|
||||
import type { AppliedFilter } from "./HbVerificationDetail";
|
||||
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||
|
||||
@@ -26,14 +28,9 @@ interface RegionalGridProps {
|
||||
vrfcTrgtSn: string | null;
|
||||
statsNm: string;
|
||||
vrfcTrgtNm: string;
|
||||
onSidoSelect: (sido: string | null) => void;
|
||||
onFilterChange: (filter: AppliedFilter) => void;
|
||||
selectedRowId?: number | null;
|
||||
}
|
||||
|
||||
interface AppliedFilter {
|
||||
sido: string | null;
|
||||
gugun: string;
|
||||
status: string;
|
||||
appliedFilter: AppliedFilter;
|
||||
}
|
||||
|
||||
const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
@@ -41,19 +38,15 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
vrfcTrgtSn,
|
||||
statsNm,
|
||||
vrfcTrgtNm,
|
||||
onSidoSelect,
|
||||
onFilterChange,
|
||||
selectedRowId,
|
||||
appliedFilter,
|
||||
}) => {
|
||||
const [selectedSido, setSelectedSido] = useState<string>("");
|
||||
const [selectedGugun, setSelectedGugun] = useState<string>("");
|
||||
const [selectedStatus, setSelectedStatus] = useState<string>("");
|
||||
const [showAllOnEmptyFilter, setShowAllOnEmptyFilter] =
|
||||
useState<boolean>(true);
|
||||
const [appliedFilter, setAppliedFilter] = useState<AppliedFilter>({
|
||||
sido: "",
|
||||
gugun: "",
|
||||
status: "",
|
||||
});
|
||||
const [isDownloading, setIsDownloading] = useState<boolean>(false);
|
||||
|
||||
const [gridRowData, setGridRowData] = useState<
|
||||
@@ -244,8 +237,7 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
onSidoSelect(selectedSido);
|
||||
setAppliedFilter({
|
||||
onFilterChange({
|
||||
sido: selectedSido,
|
||||
gugun: selectedGugun,
|
||||
status: selectedStatus,
|
||||
@@ -254,11 +246,10 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
onSidoSelect(null);
|
||||
setSelectedSido("");
|
||||
setSelectedGugun("");
|
||||
setSelectedStatus("");
|
||||
setAppliedFilter({
|
||||
onFilterChange({
|
||||
sido: "",
|
||||
gugun: "",
|
||||
status: "",
|
||||
@@ -379,10 +370,10 @@ const RegionalGrid: React.FC<RegionalGridProps> = ({
|
||||
columnInfo={columnInfo}
|
||||
rowData={gridRowData}
|
||||
setRowData={setGridRowData}
|
||||
idFieldName="rsltSn"
|
||||
isExcelExport={false}
|
||||
isExcelImport={false}
|
||||
highlightedRowId={selectedRowId}
|
||||
idFieldName="rsltSn"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -26,6 +26,8 @@ import {
|
||||
import type { StAnlsRsltResponse } from "@/entities/statistics/model/statistics-analysis-result-interface";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import type { AppliedFilter } from "./HbVerificationDetail";
|
||||
|
||||
ChartJS.register(
|
||||
LinearScale,
|
||||
LineController,
|
||||
@@ -40,7 +42,7 @@ ChartJS.register(
|
||||
interface ScatterChartProps {
|
||||
anlsSn: number;
|
||||
vrfcTrgtSn: string | null;
|
||||
selectedSido: string | null;
|
||||
appliedFilter: AppliedFilter;
|
||||
onPointClick?: (rsltSn: number | null) => void;
|
||||
}
|
||||
|
||||
@@ -56,7 +58,7 @@ interface DataPoint extends LinePoint {
|
||||
const ScatterChart: React.FC<ScatterChartProps> = ({
|
||||
anlsSn,
|
||||
vrfcTrgtSn,
|
||||
selectedSido,
|
||||
appliedFilter,
|
||||
onPointClick,
|
||||
}) => {
|
||||
const { data: regionCodes } = useQuery({
|
||||
@@ -64,12 +66,17 @@ const ScatterChart: React.FC<ScatterChartProps> = ({
|
||||
queryFn: () => CodeApi.getCode("LAESECD"),
|
||||
});
|
||||
|
||||
const selectedSidoName = useMemo(() => {
|
||||
if (!selectedSido || !regionCodes) return null;
|
||||
return (
|
||||
regionCodes.find((c) => c.lwpoCd === selectedSido)?.lwpoCdNm || null
|
||||
);
|
||||
}, [regionCodes, selectedSido]);
|
||||
const filterNames = useMemo(() => {
|
||||
if (!regionCodes) return { sido: null, gugun: null };
|
||||
return {
|
||||
sido:
|
||||
regionCodes.find((c) => c.lwpoCd === appliedFilter.sido)
|
||||
?.lwpoCdNm || null,
|
||||
gugun:
|
||||
regionCodes.find((c) => c.lwpoCd === appliedFilter.gugun)
|
||||
?.lwpoCdNm || null,
|
||||
};
|
||||
}, [regionCodes, appliedFilter.sido, appliedFilter.gugun]);
|
||||
|
||||
const { data: resultData, isLoading: isLoadingGrid } = useStAnlsRsltList(
|
||||
anlsSn,
|
||||
@@ -85,7 +92,7 @@ const ScatterChart: React.FC<ScatterChartProps> = ({
|
||||
const chartConfig = useMemo(() => {
|
||||
if (!resultData || !chartData) return null;
|
||||
|
||||
const rawPoints = resultData.content ?? [];
|
||||
const rawPoints = (resultData.content ?? []) as StAnlsRsltResponse[];
|
||||
const boundaries = chartData.list ?? [];
|
||||
|
||||
const sortedBoundaries = [...boundaries].sort(
|
||||
@@ -106,7 +113,19 @@ const ScatterChart: React.FC<ScatterChartProps> = ({
|
||||
const outlierPoints: DataPoint[] = [];
|
||||
|
||||
rawPoints.forEach((item) => {
|
||||
if (selectedSidoName && item.sido !== selectedSidoName) {
|
||||
// Apply Filters (Sido, Gugun, Status)
|
||||
if (filterNames.sido && item.sido !== filterNames.sido) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filterNames.gugun && !filterNames.gugun.includes(item.gugun)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
appliedFilter.status &&
|
||||
item.otlrYn.toLowerCase() !== appliedFilter.status
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -230,7 +249,7 @@ const ScatterChart: React.FC<ScatterChartProps> = ({
|
||||
};
|
||||
|
||||
return { data, options };
|
||||
}, [resultData, chartData, selectedSidoName]);
|
||||
}, [resultData, chartData, filterNames, appliedFilter.status]);
|
||||
|
||||
return (
|
||||
<div className="relative flex-1 p-4">
|
||||
|
||||
Reference in New Issue
Block a user