[st] - fix: 오류 수정 및 누락 기능 추가

This commit is contained in:
2026-05-18 11:03:43 +09:00
parent 8384743a30
commit b508568e86
21 changed files with 1121 additions and 518 deletions
@@ -1,6 +1,6 @@
"use client";
import { useCallback } from "react";
import { useCallback, useState } from "react";
import { useQueries } from "@tanstack/react-query";
import { useTabStore as useGridTabStore } from "@rsone/components";
@@ -19,16 +19,30 @@ import {
Badge,
type BadgeProps,
LoadingWithAnimation,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@common/components";
type VerificationReportTabKey = "NV" | "IMR" | "HB";
const VERIFICATION_REPORT_TABS: { value: VerificationReportTabKey; label: string }[] = [
{ value: "NV", label: "일반" },
{ value: "IMR", label: "I-MR" },
{ value: "HB", label: "HB" },
];
const TYPE_CODE_COLOR_MAP: Record<string, BadgeProps["color"]> = {
NV: "gray",
IMR: "red",
HB: "blue",
};
const TYPE_CODE_NAME_MAP: Record<string, string> = {
NV: "일반",
IMR: "I-MR",
HB: "HB",
};
type VerificationSelectionReportProps = {
@@ -46,6 +60,7 @@ const VerificationSelectionReport = ({
(s) => s.setPendingInputTab,
);
const alert = useAlertStore((s) => s.setMessage);
const [activeTab, setActiveTab] = useState<VerificationReportTabKey>("NV");
const statsYr = String(dayjs().year() - 1);
@@ -57,7 +72,7 @@ const VerificationSelectionReport = ({
prcsYnList: "0",
};
const [nvQuery, imrQuery] = useQueries({
const [nvQuery, imrQuery, hbQuery] = useQueries({
queries: [
{
queryKey: [
@@ -91,14 +106,34 @@ const VerificationSelectionReport = ({
vrfcMthdCd: "IMR",
}),
},
{
queryKey: [
"verificationResultList",
statsYr,
"HB",
baseRequest.pbcpAprvYn,
baseRequest.page,
baseRequest.size,
baseRequest.prcsYnList,
],
queryFn: () =>
statisticsApi.getVerificationResultList({
...baseRequest,
vrfcMthdCd: "HB",
}),
},
],
});
const isLoading = nvQuery.isLoading || imrQuery.isLoading;
const error = nvQuery.error ?? imrQuery.error;
const isLoading =
nvQuery.isLoading || imrQuery.isLoading || hbQuery.isLoading;
const error = nvQuery.error ?? imrQuery.error ?? hbQuery.error;
const nvList = nvQuery.data?.data?.verifyResultList ?? [];
const imrList = imrQuery.data?.data?.verifyResultList ?? [];
const listsByTab: Record<VerificationReportTabKey, VerificationResultReportItem[]> = {
NV: nvQuery.data?.data?.verifyResultList ?? [],
IMR: imrQuery.data?.data?.verifyResultList ?? [],
HB: hbQuery.data?.data?.verifyResultList ?? [],
};
const openInputFromStatsCd = useCallback(
(item: VerificationResultReportItem) => {
@@ -147,68 +182,61 @@ const VerificationSelectionReport = ({
],
);
const renderSection = (
typeCode: "IMR" | "NV",
const renderResultList = (
typeCode: VerificationReportTabKey,
items: VerificationResultReportItem[],
) => (
<section className="flex min-h-0 flex-1 flex-col rounded-sm border border-border h-[50rem]">
<div className="flex items-center justify-between border-b border-border px-3 py-2">
<Badge color={TYPE_CODE_COLOR_MAP[typeCode]} className="rounded-full px-2 py-1 text-lg">
{TYPE_CODE_NAME_MAP[typeCode]} {items.length}
</Badge>
</div>
<div className="min-h-0 flex-1 overflow-y-auto p-2">
{items.length === 0 ? (
<div className="flex h-full min-h-[8rem] items-center justify-center text-lg text-muted-foreground">
항목이 없습니다.
</div>
) : (
<div className="space-y-2 tracking-tight">
{items.map((item) => (
<div
key={`${typeCode}-${item.vrfcSn}`}
role="button"
tabIndex={0}
className="flex flex-col rounded-sm border border-border p-3 cursor-pointer hover:bg-gray-100"
onClick={() => openInputFromStatsCd(item)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
openInputFromStatsCd(item);
<div className="min-h-0 flex-1 overflow-y-auto p-2">
{items.length === 0 ? (
<div className="flex h-full min-h-[8rem] items-center justify-center text-lg text-muted-foreground">
항목이 없습니다.
</div>
) : (
<div className="space-y-2 tracking-tight">
{items.map((item) => (
<div
key={`${typeCode}-${item.vrfcSn}`}
role="button"
tabIndex={0}
className="flex flex-col rounded-sm border border-border p-3 cursor-pointer hover:bg-gray-100"
onClick={() => openInputFromStatsCd(item)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
openInputFromStatsCd(item);
}
}}
>
<div className="mb-2 flex items-center justify-between">
<span className="font-medium">
{item.statsNm}
</span>
<Badge
color={
TYPE_CODE_COLOR_MAP[item.vrfcMthdCd] ??
"gray"
}
}}
>
<div className="mb-2 flex items-center justify-between">
<span className="font-medium">
{item.statsNm}
</span>
<Badge
color={
TYPE_CODE_COLOR_MAP[item.vrfcMthdCd] ??
"gray"
}
className="text-sm"
>
{TYPE_CODE_NAME_MAP[item.vrfcMthdCd] ??
item.vrfcMthdNm}
</Badge>
</div>
<p className="text-lg text-muted-foreground">
{item.rsnExpln}
</p>
<div className="flex justify-between text-lg text-muted-foreground">
<span>{item.admdstNm}</span>
<span>
현재: {item.nowVlCn ?? "-"} / 비교:{" "}
{item.compVlCn ?? "-"}
</span>
</div>
className="text-sm"
>
{TYPE_CODE_NAME_MAP[item.vrfcMthdCd] ??
item.vrfcMthdNm}
</Badge>
</div>
))}
</div>
)}
</div>
</section>
<p className="text-lg text-muted-foreground">
{item.rsnExpln}
</p>
<div className="flex justify-between text-lg text-muted-foreground">
<span>{item.admdstNm}</span>
<span>
현재: {item.nowVlCn ?? "-"} / 비교:{" "}
{item.compVlCn ?? "-"}
</span>
</div>
</div>
))}
</div>
)}
</div>
);
return (
@@ -246,10 +274,42 @@ const VerificationSelectionReport = ({
</div>
)}
{!isLoading && !error && (
<div className="grid grid-rows-2 gap-6">
{renderSection("IMR", imrList)}
{renderSection("NV", nvList)}
</div>
<section className="flex min-h-0 flex-1 flex-col h-[85rem]">
<Tabs
value={activeTab}
onValueChange={(value) =>
setActiveTab(value as VerificationReportTabKey)
}
className="flex min-h-0 flex-1 flex-col h-full"
variant="default"
>
<TabsList className="grid w-full grid-cols-3 p-1">
{VERIFICATION_REPORT_TABS.map((tab) => (
<TabsTrigger
key={tab.value}
value={tab.value}
className="!px-2 !py-2 text-[1.3rem] whitespace-normal"
>
{tab.label} ({listsByTab[tab.value].length})
</TabsTrigger>
))}
</TabsList>
{VERIFICATION_REPORT_TABS.map((tab) => (
<TabsContent
key={tab.value}
value={tab.value}
className="mt-0 flex min-h-0 flex-1 flex-col p-0 data-[state=inactive]:hidden"
>
{activeTab === tab.value
? renderResultList(
tab.value,
listsByTab[tab.value],
)
: null}
</TabsContent>
))}
</Tabs>
</section>
)}
</div>
</div>