[st] feat: 검증 대상 목록 수정

This commit is contained in:
2026-03-05 17:47:59 +09:00
parent a5aa6bfdf4
commit 90ebabd5bd
3 changed files with 141 additions and 85 deletions
@@ -49,7 +49,9 @@ import type {
} from "@/entities/statistics/model/analysis-history-interface";
import { ENDPOINT } from "@/shared/config";
import { useAlertStore } from "@/shared/lib";
import { CodeApi } from "@/entities/code";
import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
import type { VerificationTargetCodeResponse } from "@/entities/statistics/model/verification-target-management-interface";
import { CodeSelect } from "@/entities/code";
type DateRangeValue = {
from?: Date;
@@ -78,7 +80,7 @@ function getDefaultHistoryDateRange(): DateRangeValue {
}
function getVerificationYearOptions(): string[] {
const currentYear = new Date().getFullYear();
const currentYear = dayjs().year();
const startYear = 2017;
const endYear = currentYear - 1;
if (endYear < startYear) return [];
@@ -116,6 +118,7 @@ const HbStatisticsVerification = () => {
open: false,
anlsSn: null,
});
const [selectedStatsCd, setSelectedStatsCd] = useState<string>("");
const defaultHistoryDateRange = useMemo(
() => getDefaultHistoryDateRange(),
@@ -133,14 +136,22 @@ const HbStatisticsVerification = () => {
pageSize: 10,
});
const { data: statsItemList } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.CODE, "STITEM"],
queryFn: async () => {
const response = await CodeApi.getCode("STITEM");
return response;
},
const { data: verificationTargetCodes } = useQuery<
VerificationTargetCodeResponse[]
>({
queryKey: [ENDPOINT.STATVERIFY_SERVICE.VRFCTGT_MNG, "codes"],
queryFn: () =>
verificationTargetManagementApi.getVerificationTargetCodes(),
});
const filteredVerificationTargetCodes = useMemo(() => {
return verificationTargetCodes?.filter((item) =>
selectedStatsCd
? item.vrfcTrgtSn.startsWith(selectedStatsCd)
: true,
);
}, [verificationTargetCodes, selectedStatsCd]);
const { data: analysisHistory } = useQuery({
queryKey: [
ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST,
@@ -329,26 +340,50 @@ const HbStatisticsVerification = () => {
<div className="card card-border flex flex-col gap-6">
{/* 검증 종류 선택 */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-4 pl-2">
<span className="text-[1.3rem] font-medium text-label">
검증 방식
</span>
<RadioGroup
value={verifyType}
onValueChange={(value) =>
setVerifyType(value as VerifyType)
}
className="flex items-center gap-4"
>
<label className="flex cursor-pointer items-center gap-2 text-label">
<RadioGroupItem value="ALL" />
<span>일괄 검증</span>
</label>
<label className="flex cursor-pointer items-center gap-2 text-label">
<RadioGroupItem value="SELECT" />
<span>선택 검증</span>
</label>
</RadioGroup>
<div className="flex items-center gap-6">
<div className="flex items-center gap-4 pl-2">
<Label className="text-[1.3rem] font-medium text-label">
검증 년도
</Label>
<Select
value={formState.verificationYear}
onValueChange={(value) =>
handleFormChange("verificationYear", value)
}
>
<SelectTrigger className="w-[10rem] flex-1">
<SelectValue />
</SelectTrigger>
<SelectContent>
{yearOptions.map((year) => (
<SelectItem key={year} value={year}>
{year}년
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex items-center gap-4 pl-2">
<Label className="text-[1.3rem] font-medium text-label">
검증 방식
</Label>
<RadioGroup
value={verifyType}
onValueChange={(value) =>
setVerifyType(value as VerifyType)
}
className="flex items-center gap-4"
>
<label className="flex cursor-pointer items-center gap-2 text-label">
<RadioGroupItem value="ALL" />
<span>일괄 검증</span>
</label>
<label className="flex cursor-pointer items-center gap-2 text-label">
<RadioGroupItem value="SELECT" />
<span>선택 검증</span>
</label>
</RadioGroup>
</div>
</div>
<div className="flex justify-center gap-4">
<Button
@@ -378,38 +413,65 @@ const HbStatisticsVerification = () => {
<h4 className="mb-3 rounded bg-gray-100 px-4 py-2 text-[1.4rem] font-medium">
검증 대상
</h4>
<div className="space-y-4 p-2">
<div className="mb-3 flex items-center gap-4 px-4">
<Label className="text-[1.3rem] font-medium text-label">
통계항목
</Label>
<CodeSelect
upCd="STITEM"
onValueChange={setSelectedStatsCd}
className="w-[24rem]"
/>
<Button
type="button"
color="gray"
className="h-[3.2rem] px-4 text-[1.3rem]"
onClick={() => setSelectedStatsCd("")}
>
초기화
</Button>
</div>
<div className="max-h-[16rem] space-y-4 overflow-auto rounded-md border p-4">
{verifyType === "SELECT" &&
statsItemList &&
statsItemList.length > 0 && (
<div className="grid grid-cols-3 gap-4">
{statsItemList.map((item) => (
filteredVerificationTargetCodes &&
filteredVerificationTargetCodes.length > 0 ? (
<div className="grid grid-cols-3 gap-4">
{filteredVerificationTargetCodes.map(
(item) => (
<div
key={item.lwpoCd}
key={item.vrfcTrgtSn}
className="flex items-center gap-2"
>
<Checkbox
id={item.lwpoCd}
id={item.vrfcTrgtSn}
checked={selectedTargets.includes(
item.lwpoCd,
item.vrfcTrgtSn,
)}
onCheckedChange={() =>
handleTargetToggle(
item.lwpoCd,
item.vrfcTrgtSn,
)
}
/>
<Label
htmlFor={item.lwpoCd}
htmlFor={
item.vrfcTrgtSn
}
className="cursor-pointer text-label"
>
{item.lwpoCdNm}
{item.vrfcTrgtNm}
</Label>
</div>
))}
</div>
)}
),
)}
</div>
) : (
<div className="flex items-center justify-center py-4">
<p className="text-[1.3rem] text-muted-foreground">
검증 대상이 없습니다.
</p>
</div>
)}
</div>
</div>
{/* //검증 대상 */}
@@ -482,35 +544,6 @@ const HbStatisticsVerification = () => {
className="flex-1"
/>
</div>
<div className="flex items-center gap-4">
<Label className="w-32 text-label">
검증 년도
</Label>
<Select
value={formState.verificationYear}
onValueChange={(value) =>
handleFormChange(
"verificationYear",
value,
)
}
>
<SelectTrigger className="flex-1">
<SelectValue />
</SelectTrigger>
<SelectContent>
{yearOptions.map((year) => (
<SelectItem
key={year}
value={year}
>
{year}년
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>
{/* //검증 변수 */}
@@ -519,21 +552,23 @@ const HbStatisticsVerification = () => {
</div>
<div className="mt-10 px-4 pb-8">
<h3 className="mb-2 px-2 text-[1.5rem] font-semibold text-title">
<h3 className="mb-4 px-2 text-[1.6rem] font-semibold text-title">
검증 이력
</h3>
<div className="mb-4 flex items-center gap-4 px-2">
<span className="text-[1.3rem] font-medium text-label">
검증일시
</span>
<DateRangePicker
value={historyDateRange as any}
defaultValue={defaultHistoryDateRange as any}
onValueChange={(value) =>
setHistoryDateRange((value as any) ?? undefined)
}
className="max-w-[26rem]"
/>
<div className="card card-border !m-0 !mb-2 flex justify-between">
<div className="flex items-center gap-4 px-2">
<span className="text-[1.3rem] font-medium text-label">
검증일시
</span>
<DateRangePicker
value={historyDateRange as any}
defaultValue={defaultHistoryDateRange as any}
onValueChange={(value) =>
setHistoryDateRange((value as any) ?? undefined)
}
className="max-w-[26rem]"
/>
</div>
<div className="flex gap-2">
<Button
type="button"
@@ -2,6 +2,7 @@ import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
VerificationTargetCodeResponse,
VerificationTargetManagementService,
VerificationTargetManagementSearchParams,
VerificationTargetManagementListApiResponse,
@@ -43,6 +44,18 @@ export class VerificationTargetManagementApiService implements VerificationTarge
return response.data;
}
/**
* 검증 대상 코드 목록 조회
*/
public async getVerificationTargetCodes(): Promise<
VerificationTargetCodeResponse[]
> {
const response = await client.get<VerificationTargetCodeResponse[]>(
`${ENDPOINT.STATVERIFY_SERVICE.VRFCTGT_MNG}/code`,
);
return response.data;
}
/**
* 검증 대상 등록
* @param request 등록 요청 데이터
@@ -1,6 +1,12 @@
import type { PageableList } from "@/shared/model";
import type { ApiResponse } from "./statistics-interface";
// 검증 대상 코드 응답 DTO
export interface VerificationTargetCodeResponse {
vrfcTrgtSn: string;
vrfcTrgtNm: string;
}
// 검증 대상 관리 응답 DTO
export interface VerificationTargetManagementResponse {
vrfcTrgtSn: number; // 검증 대상 일련번호
@@ -90,6 +96,8 @@ export interface VerificationTargetManagementService {
vrfcTrgtSn: number,
): Promise<VerificationTargetManagementDetailApiResponse>;
getVerificationTargetCodes(): Promise<VerificationTargetCodeResponse[]>;
saveVerificationTargetManagement(
request: VerificationTargetManagementSaveRequest,
): Promise<VerificationTargetManagementSaveApiResponse>;