diff --git a/apps/st/src/components/statistics/verification/VerificationTargetDialog.tsx b/apps/st/src/components/statistics/verification/VerificationTargetDialog.tsx index b59606c25..3c6043b27 100644 --- a/apps/st/src/components/statistics/verification/VerificationTargetDialog.tsx +++ b/apps/st/src/components/statistics/verification/VerificationTargetDialog.tsx @@ -1,12 +1,17 @@ "use client"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; +import { Search } from "lucide-react"; import { CodeSelect } from "@/entities/code/ui/code-select"; -import type { VerificationTargetManagementResponse } from "@/entities/statistics/model/verification-target-management-interface"; +import type { + NumericColumnDto, + VerificationTargetManagementResponse, +} from "@/entities/statistics/model/verification-target-management-interface"; +import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service"; import { type VerificationTargetManagementFormData, verificationTargetManagementSchema, @@ -23,6 +28,7 @@ import { TableBody, TableCell, TableHead, + TableHeader, TableRow, } from "@common/components"; @@ -45,7 +51,7 @@ export function VerificationTargetDialog({ onSave, onDelete, }: VerificationTargetDialogProps) { - const { control, handleSubmit, reset } = + const { control, handleSubmit, reset, getValues, setValue } = useForm({ resolver: zodResolver(verificationTargetManagementSchema), defaultValues: data || { @@ -60,6 +66,11 @@ export function VerificationTargetDialog({ }, }); + const [isColumnDialogOpen, setIsColumnDialogOpen] = useState(false); + const [numericColumns, setNumericColumns] = useState( + [], + ); + useEffect(() => { if (open) { reset( @@ -90,321 +101,459 @@ export function VerificationTargetDialog({ } } + async function handleSearchTableMetadata() { + const statsCd = getValues("statsCd"); + if (!statsCd) { + alert("통계항목을 선택해주세요."); + return; + } + + try { + const metadata = + await verificationTargetManagementApi.getTableInfo(statsCd); + + setValue("schmNm", metadata.schmNm, { shouldValidate: true }); + setValue("tblNm", metadata.tblNm, { shouldValidate: true }); + + if (metadata.pkColumns && metadata.pkColumns.length > 0) { + setValue("pkColNm", metadata.pkColumns.join(", "), { + shouldValidate: true, + }); + } + + setNumericColumns(metadata.numericColumns || []); + setIsColumnDialogOpen(true); + } catch (error) { + alert("테이블 정보를 조회하는 중 오류가 발생했습니다."); + console.error(error); + } + } + + function handleSelectColumn(colNm: string) { + setValue("colNm", colNm, { shouldValidate: true }); + setIsColumnDialogOpen(false); + } + return ( - - - - - {data ? "검증 항목 상세" : "검증 항목 등록"} - - + <> + + + + + {data ? "검증 항목 상세" : "검증 항목 등록"} + + -
- - - - - 통계항목 - - - ( -
- -
- )} - /> -
- - 검증명 - - - ( - +
+ + + + 통계항목 + + +
+ ( + + )} /> - )} - /> - - - - - - 스키마명 - - - ( -
- -
- )} - /> -
- - 테이블명 - - - ( -
- -
- )} - /> -
-
- - - - 컬럼명 - - - ( -
- -
- )} - /> -
- - PK 키 - - - ( -
- -
- )} - /> -
-
- - {tabValue !== "IMR" && ( - - - 중요도 계수(μ) + +
+
+ + 검증명 ( + + )} + /> + +
+ + + + 스키마명 + + + (
- field.onChange( - e.target.value - ? Number( - e - .target - .value, - ) - : null, - ) - } - placeholder="(0 ~ 1, 0.1 단위)" + {...field} + placeholder="스키마명" />
)} />
- - 백분위수 기준값(pct) + + 테이블명 (
- field.onChange( - e.target.value - ? Number( - e - .target - .value, - ) - : null, - ) - } - placeholder="(0 ~ 0.5, 0.1 단위)" + {...field} + placeholder="테이블명" />
)} />
- )} - {tabValue !== "IMR" && ( - - 스케일 조정 계수(A) + + 컬럼명 - ( -
+
+ ( - field.onChange( - e.target.value - ? Number( - e - .target - .value, - ) - : null, - ) - } - placeholder="(0 ~ 1, 0.01 단위)" + {...field} + placeholder="컬럼명" + className="flex-1" /> -
- )} - /> + )} + /> + +
- - 임계 계수(c) + + PK 키 (
- field.onChange( - e.target.value - ? Number( - e - .target - .value, - ) - : null, - ) - } - placeholder="(0 ~ 100, 1 단위)" + {...field} + placeholder="PK 키" />
)} />
- )} -
-
- - - {data && ( + {tabValue !== "IMR" && ( + + + 중요도 계수(μ) + + + ( +
+ + field.onChange( + e.target + .value + ? Number( + e + .target + .value, + ) + : null, + ) + } + placeholder="(0 ~ 1, 0.1 단위)" + /> +
+ )} + /> +
+ + 백분위수 기준값(pct) + + + ( +
+ + field.onChange( + e.target + .value + ? Number( + e + .target + .value, + ) + : null, + ) + } + placeholder="(0 ~ 0.5, 0.1 단위)" + /> +
+ )} + /> +
+
+ )} + + {tabValue !== "IMR" && ( + + + 스케일 조정 계수(A) + + + ( +
+ + field.onChange( + e.target + .value + ? Number( + e + .target + .value, + ) + : null, + ) + } + placeholder="(0 ~ 1, 0.01 단위)" + /> +
+ )} + /> +
+ + 임계 계수(c) + + + ( +
+ + field.onChange( + e.target + .value + ? Number( + e + .target + .value, + ) + : null, + ) + } + placeholder="(0 ~ 100, 1 단위)" + /> +
+ )} + /> +
+
+ )} + + + + - )} - - - -
-
+ {data && ( + + )} + + + +
+
+ + + + + 숫자형 컬럼 목록 + +
+ + + + + 컬럼명 + + + 데이터 타입 + + + 코멘트 + + + 선택 + + + + + {numericColumns.length === 0 ? ( + + + 조회된 숫자형 컬럼이 없습니다. + + + ) : ( + numericColumns.map((col, idx) => ( + + + {col.columnName} + + + {col.dataType} + + + {col.columnComment} + + + + + + )) + )} + +
+
+
+
+ ); } diff --git a/apps/st/src/entities/statistics/api/verification-target-management-service.ts b/apps/st/src/entities/statistics/api/verification-target-management-service.ts index f7430c28b..1cad4c110 100644 --- a/apps/st/src/entities/statistics/api/verification-target-management-service.ts +++ b/apps/st/src/entities/statistics/api/verification-target-management-service.ts @@ -12,6 +12,7 @@ import type { VerificationTargetManagementUpdateRequest, VerificationTargetManagementUpdateApiResponse, VerificationTargetManagementDeleteApiResponse, + TableMetadataResponse, } from "../model/verification-target-management-interface"; export class VerificationTargetManagementApiService implements VerificationTargetManagementService { @@ -44,6 +45,18 @@ export class VerificationTargetManagementApiService implements VerificationTarge return response.data; } + /** + * 테이블 메타데이터 조회 + * @param statsCd 통계항목 코드 + */ + public async getTableInfo(statsCd: string): Promise { + const response = await client.get( + `${ENDPOINT.STATVERIFY_SERVICE.VRFCTGT_MNG}/table-info`, + { params: { statsCd } }, + ); + return response.data; + } + /** * 검증 대상 코드 목록 조회 */ diff --git a/apps/st/src/entities/statistics/model/verification-target-management-interface.ts b/apps/st/src/entities/statistics/model/verification-target-management-interface.ts index 5a7df41fd..b09454f99 100644 --- a/apps/st/src/entities/statistics/model/verification-target-management-interface.ts +++ b/apps/st/src/entities/statistics/model/verification-target-management-interface.ts @@ -1,4 +1,17 @@ import type { PageableList } from "@/shared/model"; + +export interface NumericColumnDto { + columnName: string; + dataType: string; + columnComment: string; +} + +export interface TableMetadataResponse { + schmNm: string; + tblNm: string; + pkColumns: string[]; + numericColumns: NumericColumnDto[]; +} import type { ApiResponse } from "./statistics-interface"; // 검증 대상 코드 응답 DTO