From fc961e294641daab0bb0995daa9061b00986168d Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 28 Aug 2026 15:14:44 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[as]=20feat:=20=ED=95=84=EC=88=98=EC=B2=A8?= =?UTF-8?q?=EB=B6=80=ED=8C=8C=EC=9D=BC=EA=B4=80=EB=A6=AC=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EB=8B=A4=EC=9D=B4=EC=96=BC=EB=A1=9C=EA=B7=B8=20>?= =?UTF-8?q?=20=EC=96=91=EC=8B=9D=ED=8C=8C=EC=9D=BC=20=EC=B2=A8=EB=B6=80=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/esntl-atch-file-form-dialog.tsx | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx b/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx index a45862486..58ee1ca6b 100644 --- a/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx +++ b/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useId, useState } from "react"; +import { useEffect, useId, useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { Paperclip, X } from "lucide-react"; @@ -61,6 +61,7 @@ function EsntlAtchFileFormDialog({ onSubmit, }: EsntlAtchFileFormDialogProps) { const formId = useId(); + const atchFileGroupIdRef = useRef(""); const [uploadedFiles, setUploadedFiles] = useState([]); const { register, handleSubmit, reset, setValue, watch } = useForm({ @@ -75,13 +76,16 @@ function EsntlAtchFileFormDialog({ const docSeComCd = watch("docSeComCd"); const esntlAtchYn = watch("esntlAtchYn"); - const atchFileGroupId = watch("atchFileGroupId"); const { uploadFileAsync, isUploading, uploads } = useTus({ onSuccess: (atflCd, atflId, _file, fileKey) => { if (!atflCd || !atflId) return; - setValue("atchFileGroupId", atflCd, { shouldDirty: true }); + if (!atchFileGroupIdRef.current) { + atchFileGroupIdRef.current = atflCd; + setValue("atchFileGroupId", atflCd, { shouldDirty: true }); + } + setUploadedFiles((prev) => prev.map((item) => (item.fileKey === fileKey ? { ...item, atflCd, atflId } : item)), ); @@ -107,6 +111,7 @@ function EsntlAtchFileFormDialog({ })); setUploadedFiles(initialFiles); + atchFileGroupIdRef.current = initial.atchFileGroupId ?? ""; reset({ docSeComCd: initial.docSeComCd ?? "", esntlAtchFileNm: initial.esntlAtchFileNm ?? "", @@ -118,6 +123,7 @@ function EsntlAtchFileFormDialog({ } setUploadedFiles([]); + atchFileGroupIdRef.current = ""; reset({ docSeComCd: "", esntlAtchFileNm: "", @@ -132,15 +138,20 @@ function EsntlAtchFileFormDialog({ for (const file of Array.from(files)) { const fileKey = createUploadKey(file); - const existingAtflCd = atchFileGroupId || uploadedFiles.find((item) => item.atflCd)?.atflCd; + const existingAtflCd = atchFileGroupIdRef.current; setUploadedFiles((prev) => [...prev, { fileName: file.name, fileKey }]); try { - await uploadFileAsync(file, { + const atflCd = await uploadFileAsync(file, { fileKey, metadata: existingAtflCd ? { atflCd: existingAtflCd } : undefined, }); + + if (!existingAtflCd) { + atchFileGroupIdRef.current = atflCd; + setValue("atchFileGroupId", atflCd, { shouldDirty: true }); + } } catch { // onError callback handles cleanup } @@ -164,7 +175,8 @@ function EsntlAtchFileFormDialog({ const nextFiles = uploadedFiles.filter((_, index) => index !== fileIndex); setUploadedFiles(nextFiles); - const nextGroupId = nextFiles.find((item) => item.atflCd)?.atflCd ?? ""; + const nextGroupId = nextFiles[0]?.atflCd ?? ""; + atchFileGroupIdRef.current = nextGroupId; setValue("atchFileGroupId", nextGroupId, { shouldDirty: true }); } From bf9a34cbe84a2b9f0e93cbcf7579237f44135e9a Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 28 Aug 2026 15:55:05 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[st]=20feat:=20=ED=95=98=EC=88=98=EB=8F=84?= =?UTF-8?q?=20=ED=86=B5=EA=B3=84=20=EA=B2=80=EC=A6=9D=20>=20=EC=8B=9C?= =?UTF-8?q?=EB=8F=84/=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=EC=85=80=EB=A0=89?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20'=EC=A0=84=EC=B2=B4'=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../verification/ImrVerificationHistory.tsx | 30 ++++-- .../StatisticsVerificationReport.tsx | 94 ++++++++++++++----- .../detail/HbVerificationDetail.tsx | 4 +- .../verification/detail/RegionalGrid.tsx | 39 +++++--- .../st/src/entities/statistics/api/queries.ts | 2 +- 5 files changed, 120 insertions(+), 49 deletions(-) diff --git a/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx b/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx index 304fea591..3470a62d6 100644 --- a/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx +++ b/apps/st/src/components/statistics/verification/ImrVerificationHistory.tsx @@ -72,6 +72,7 @@ type DateRangeValue = { }; const EMPTY_DATA: never[] = []; +const REGION_ALL_VALUE = "ALL"; function getImrDetailGridColumnInfo(statsCd: string): ColumnInfo { const visible = @@ -104,8 +105,8 @@ const ImrVerificationHistory = () => { : ""; // Area A Search States - const [searchSido, setSearchSido] = useState(""); - const [searchSigungu, setSearchSigungu] = useState(""); + const [searchSido, setSearchSido] = useState(REGION_ALL_VALUE); + const [searchSigungu, setSearchSigungu] = useState(REGION_ALL_VALUE); const [searchStatsYr, setSearchStatsYr] = useState(defaultYear); const [searchStatsCd, setSearchStatsCd] = useState(""); const [dateRange, setDateRange] = useState({ @@ -248,12 +249,12 @@ const ImrVerificationHistory = () => { vrfcMthdCd: "IMR", sort: "anlsSn,desc", }; - if (searchSido !== "") { + if (searchSido !== "" && searchSido !== REGION_ALL_VALUE) { const selectedSggBsnmCd = sigunguOptions.find( (item) => item.gugun === searchSigungu, )?.bsnmCd; params.sewerBzmnCd = - searchSigungu !== "" + searchSigungu !== "" && searchSigungu !== REGION_ALL_VALUE ? (selectedSggBsnmCd ?? "") : selectedSidoBsnmCd; } @@ -271,8 +272,8 @@ const ImrVerificationHistory = () => { }; const handleReset = () => { - setSearchSido(""); - setSearchSigungu(""); + setSearchSido(REGION_ALL_VALUE); + setSearchSigungu(REGION_ALL_VALUE); setSearchStatsCd(""); const defaultRange = { from: dayjs().subtract(1, "month").toDate(), @@ -410,13 +411,16 @@ const ImrVerificationHistory = () => { value={searchSido} onValueChange={(val) => { setSearchSido(val); - setSearchSigungu(""); + setSearchSigungu(REGION_ALL_VALUE); }} > - + + + 전체 + {sidoOptions.map((opt) => ( { onChange( value, diff --git a/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx b/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx index b8e5a3cd4..ed17b417b 100644 --- a/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx +++ b/apps/st/src/components/statistics/verification/detail/HbVerificationDetail.tsx @@ -40,8 +40,8 @@ const HbVerificationDetail: React.FC = ({ ); const [checkedSns, setCheckedSns] = useState([]); const [appliedFilter, setAppliedFilter] = useState({ - sido: "", - gugun: "", + sido: "ALL", + gugun: "ALL", status: "", }); const [selectedRowId, setSelectedRowId] = useState(null); diff --git a/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx b/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx index eeea43b3a..8eee4ec1a 100644 --- a/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx +++ b/apps/st/src/components/statistics/verification/detail/RegionalGrid.tsx @@ -26,6 +26,7 @@ import type { AppliedFilter } from "./HbVerificationDetail"; import DataGrid from "@/components/module/DataGrid"; const EMPTY_ADST_LIST: AdstZoneResponseDto[] = []; +const REGION_ALL_VALUE = "ALL"; interface RegionalGridProps { anlsSn: number; @@ -53,7 +54,10 @@ const RegionalGrid: React.FC = ({ >([]); const { data: sidoData } = useStAnlsSidoCombo(); - const { data: gugunData } = useStAnlsSigunguCombo(appliedFilter.sido ?? ""); + const sidoCd = appliedFilter.sido ?? ""; + const { data: gugunData } = useStAnlsSigunguCombo( + sidoCd !== REGION_ALL_VALUE ? sidoCd : "", + ); const sidoOptions = sidoData ?? EMPTY_ADST_LIST; const gugunOptions = gugunData ?? EMPTY_ADST_LIST; @@ -66,14 +70,14 @@ const RegionalGrid: React.FC = ({ let data = (resultData?.content ?? []) as StAnlsRsltResponse[]; { const sidoCd = appliedFilter.sido; - if (sidoCd) { + if (sidoCd && sidoCd !== REGION_ALL_VALUE) { data = data.filter((item) => item.admdstCd.startsWith(sidoCd.slice(0, 2)), ); } const gugunCd = appliedFilter.gugun; - if (gugunCd) { + if (gugunCd && gugunCd !== REGION_ALL_VALUE) { data = data.filter((item) => item.admdstCd === gugunCd); } @@ -107,13 +111,17 @@ const RegionalGrid: React.FC = ({ }, [resultData, appliedFilter]); const handleSidoChange = (val: string) => { - onFilterChange({ ...appliedFilter, sido: val, gugun: "" }); + onFilterChange({ + ...appliedFilter, + sido: val, + gugun: REGION_ALL_VALUE, + }); }; const handleReset = () => { onFilterChange({ - sido: "", - gugun: "", + sido: REGION_ALL_VALUE, + gugun: REGION_ALL_VALUE, status: "", }); }; @@ -156,13 +164,16 @@ const RegionalGrid: React.FC = ({