From 50bc502251cae4d80abb5676f454c27cd5488b4e Mon Sep 17 00:00:00 2001 From: jangwoong Date: Fri, 22 May 2026 16:02:34 +0900 Subject: [PATCH] =?UTF-8?q?[as=20instl]=20=20=20=EA=B8=B0=ED=83=80=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EA=B7=B8=EB=A3=B9=20ID=20=EB=8F=99?= =?UTF-8?q?=EC=9D=BC=ED=95=98=EA=B2=8C=20=EC=97=85=EB=A1=9C=EB=93=9C=20?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/instl-sncn/ui/cnfm-regist-page.tsx | 139 +++++++++++++++--- 1 file changed, 120 insertions(+), 19 deletions(-) diff --git a/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx b/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx index df6e713fd..188a80b2a 100644 --- a/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx @@ -124,9 +124,20 @@ function CnfmRegistPage() { const [privacyAgree, setPrivacyAgree] = useState<"Y" | "N">("N"); /* ── 기타 첨부파일 ── */ - type EtcFile = { id: number; name: string; ext: string; size: string; uploader: string }; + type EtcFile = { + id: string; + name: string; + ext: string; + size: string; + uploader: string; + atflCd: string; + atflId: string; + }; const [etcFiles, setEtcFiles] = useState([]); const [etcNoticeOpen, setEtcNoticeOpen] = useState(true); + const [etcFileGroupId, setEtcFileGroupId] = useState(""); + const [etcUploading, setEtcUploading] = useState(false); + const etcFileGroupIdRef = useRef(""); /* ── 필수 첨부파일 ── */ const { data: requiredAttachmentDefs = [] } = useQuery({ @@ -227,6 +238,93 @@ function CnfmRegistPage() { e.target.value = ""; }; + const toFileSizeText = (size: number): string => + size > 1024 * 1024 ? `${(size / 1024 / 1024).toFixed(1)}MB` : `${(size / 1024).toFixed(0)}KB`; + + const uploadEtcFile = (file: File): Promise => + new Promise((resolve, reject) => { + let uploadedAtflCd = ""; + let uploadedAtflId = ""; + + const upload = new Upload(file, { + endpoint: `${PROXY_HOST}${ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD}`, + chunkSize: 10 * 1024 * 1024, + headers: { + [CLAIM_NAME]: getCookie(CLAIM_NAME) ?? "", + [AUTH_USER_ID]: getCookie(AUTH_USER_ID) ?? "", + }, + metadata: { + filename: file.name, + filetype: file.type, + atflCd: etcFileGroupIdRef.current || "", + }, + onError(error: Error) { + reject(error); + }, + onAfterResponse(_req: unknown, res: HttpResponse) { + const fileInfo = res.getHeader("X-File-Info"); + if (typeof fileInfo !== "string") return; + + const parsed = JSON.parse(fileInfo) as { atflCd?: string; atflId?: string }; + uploadedAtflCd = parsed.atflCd ?? ""; + uploadedAtflId = parsed.atflId ?? ""; + + if (uploadedAtflCd) { + etcFileGroupIdRef.current = uploadedAtflCd; + setEtcFileGroupId((prev) => prev || uploadedAtflCd); + } + }, + onSuccess() { + const ext = file.name.includes(".") ? file.name.split(".").pop() ?? "" : ""; + resolve({ + id: uploadedAtflId || `${Date.now()}_${Math.random()}`, + name: file.name, + ext, + size: toFileSizeText(file.size), + uploader: "(로그인 사용자)", + atflCd: uploadedAtflCd, + atflId: uploadedAtflId, + }); + }, + }); + + upload.start(); + }); + + const handleEtcFilesChange = async (e: React.ChangeEvent) => { + const files = Array.from(e.target.files ?? []); + if (files.length === 0) return; + + setEtcUploading(true); + const uploadedRows: EtcFile[] = []; + const failedNames: string[] = []; + + for (const file of files) { + try { + const uploaded = await uploadEtcFile(file); + uploadedRows.push(uploaded); + } catch (error) { + console.error("기타 첨부파일 업로드 실패", error); + failedNames.push(file.name); + } + } + + if (uploadedRows.length > 0) { + setEtcFiles((prev) => [...prev, ...uploadedRows]); + if (!etcFileGroupId && uploadedRows[0].atflCd) { + setEtcFileGroupId(uploadedRows[0].atflCd); + etcFileGroupIdRef.current = uploadedRows[0].atflCd; + } + } + + if (failedNames.length > 0) { + alert(`일부 파일 업로드에 실패했습니다. (${failedNames.join(", ")})`); + } + + setEtcUploading(false); + e.target.value = ""; + }; + /* ── 체크리스트 ── */ type CheckResultVal = "Y" | "N" | null; const [checkResults, setCheckResults] = useState>({}); @@ -560,7 +658,7 @@ function CnfmRegistPage() { dsgnrTelno, dsgnrOgdpNm: dsgnrPsitn, dsgnrEmlAddr, - atchFileGroupId: "", + atchFileGroupId: etcFileGroupId, prgrsSttsComCd, prgrsSttsCdNm: "", regDt: "", @@ -1202,29 +1300,23 @@ function CnfmRegistPage() { type="text" className="cnfm-input min-w-0 flex-1" placeholder="첨부문서를 등록해주세요" + value={ + etcUploading + ? "업로드 중..." + : etcFiles.length > 0 + ? `${etcFiles.length}개 파일 등록됨` + : "" + } readOnly /> @@ -1259,7 +1351,16 @@ function CnfmRegistPage() {