From 23992f5d37d26040da654840aaab5549c8daa694 Mon Sep 17 00:00:00 2001 From: swcho Date: Thu, 29 May 2025 14:48:43 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=B9=A8=EC=9E=85=EC=88=98=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D,=20RDII=20=EB=B6=84=EC=84=9D=20API=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/lib/utils/excelToJson.ts | 74 +++++++++++-------- apps/sn/app/ii/irsetting/page.tsx | 23 +++--- apps/sn/app/ii/rdii/page.tsx | 18 ++--- 3 files changed, 62 insertions(+), 53 deletions(-) diff --git a/apps/sn/app/components/lib/utils/excelToJson.ts b/apps/sn/app/components/lib/utils/excelToJson.ts index 2ed697139..837b099cc 100644 --- a/apps/sn/app/components/lib/utils/excelToJson.ts +++ b/apps/sn/app/components/lib/utils/excelToJson.ts @@ -1,11 +1,11 @@ -export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e' +export const TEST_UUID = '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e' import { z } from "zod"; // "YYYY-MM-DDTHH:MM:SS" 형식으로 포맷팅 하는 함수 function parseAndFormatDateTimeToISOCompatibleString( dateInput: string, timeInputForMDY: string | null, - inputType: 'YYYY-MM-DD_H:MM' | 'M/D/YYYY_H:MM' + inputType: 'YYYY-MM-DD_H:MM' | 'M/D/YYYY_H:MM' | 'M/D/YY_H:MM' ): string | null { let year: number, month: number, day: number, hours: number, minutes: number; let datePartStr: string; @@ -31,8 +31,8 @@ function parseAndFormatDateTimeToISOCompatibleString( } else if (inputType === 'M/D/YYYY_H:MM') { datePartStr = String(dateInput); // "M/D/YYYY" if (!timeInputForMDY) { - console.warn(`Time input is missing for ${inputType}:`, dateInput); - return null; + console.warn(`Time input is missing for ${inputType}:`, dateInput); + return null; } timePartStr = String(timeInputForMDY); // "H:MM" @@ -41,10 +41,31 @@ function parseAndFormatDateTimeToISOCompatibleString( console.warn(`Invalid date format for ${inputType} (datePart):`, datePartStr); return null; } - // Note: Order for M/D/YYYY is month, day, year month = parseInt(dateParts[0] ?? '', 10); day = parseInt(dateParts[1] ?? '', 10); year = parseInt(dateParts[2] ?? '', 10); + } else if (inputType === 'M/D/YY_H:MM') { // "M/D/YY H:MM" 형식 처리 + const parts = String(dateInput).split(' '); + if (parts.length !== 2) { + console.warn(`Invalid dateTime format for ${inputType} (split space):`, dateInput); + return null; + } + datePartStr = parts[0] ?? ""; // "M/D/YY" + timePartStr = parts[1] ?? ""; // "H:MM" + + const dateParts = datePartStr.split('/'); + if (dateParts.length !== 3) { + console.warn(`Invalid date format for ${inputType} (datePart):`, datePartStr); + return null; + } + month = parseInt(dateParts[0] ?? '', 10); + day = parseInt(dateParts[1] ?? '', 10); + year = parseInt(dateParts[2] ?? '', 10); + + // YY to YYYY conversion (assuming 2000s) + if (year < 100) { + year += 2000; + } } else { console.warn("Invalid inputType for date parsing."); return null; @@ -64,31 +85,30 @@ function parseAndFormatDateTimeToISOCompatibleString( return null; } - // "YYYY-MM-DDTHH:MM:SS" 형식으로 포맷팅 - 공통 로직 + // "YYYY-MM-DD HH:MM:SS" 형식으로 포맷팅 - 공통 로직 const formattedYear = String(year).padStart(4, '0'); // 연도는 4자리로 보장 (M/D/YYYY의 경우) const formattedMonth = String(month).padStart(2, '0'); const formattedDay = String(day).padStart(2, '0'); const formattedHours = String(hours).padStart(2, '0'); const formattedMinutes = String(minutes).padStart(2, '0'); - // 초는 00으로 고정, 'T'를 사용하여 Date 생성자 호환성 확보 return `${formattedYear}-${formattedMonth}-${formattedDay} ${formattedHours}:${formattedMinutes}:00`; } // 수용가-맨홀 매칭결과 (수정 필요) export const MatchingResultZod = z.object({ - anls_sn: z.number(), // 분석 일련번호 - mhl_mng_no: z.string(), // 맨홀 번호 (임시값이라 추후 수정 필요) - rcptr_no: z.string(), // 수용가 번호 + anlsSn: z.number(), // 분석 일련번호 + mhlMngNo: z.string(), // 맨홀 번호 (임시값이라 추후 수정 필요) + rcptrNo: z.string(), // 수용가 번호 }); export type MatchingResultZodType = z.infer; export const excelToMatchingResultData = (excelData: any) => { const MatchingResultData: MatchingResultZodType[] = excelData.map((item: any) => { return { - anls_sn: Number(item["NO"]), - mhl_mng_no: String(item["FTR_IDN"]), // (임시값이라 추후 수정 필요) - rcptr_no: String(item["수용가"]), + anlsSn: Number(item["NO"]), + mhlMngNo: String(item["FTR_IDN"]), // (임시값이라 추후 수정 필요) + rcptrNo: String(item["수용가"]), }; }).filter((el: any) => el !== undefined); return MatchingResultData; @@ -97,7 +117,7 @@ export const excelToMatchingResultData = (excelData: any) => { // 시간패턴 export const timePatternZod = z.object({ - hr_id: z.number(), // 시간 + hrId: z.number(), // 시간 rt: z.number().nullish(), // 비율 }); export type timePatternZodType = z.infer; @@ -105,7 +125,7 @@ export const excelToTimePatternData = (excelData: any) => { const timePatternData: timePatternZodType[] = excelData.map((item: any) => { return { - hr_id: Number(item["시간"]), + hrId: Number(item["시간"]), rt: Number(item["비율"]), }; }).filter((el: any) => el !== undefined); @@ -115,30 +135,22 @@ export const excelToTimePatternData = (excelData: any) => { // 유량자료 export const flowRateZod = z.object({ - ppl_mng_no: z.string(), // 관로번호 - mtrng_dt: z.string(), // 시간 + pplMngNo: z.string(), // 관로번호 + mtrngDt: z.string(), // 시간 oilq: z.number().nullish(), // 유량(㎥/h) }); export type flowRateZodType = z.infer; export const excelToFlowRateData = (excelData: any) => { const flowRateData: flowRateZodType[] = excelData.map((item: any) => { - const dateTimeStr = String(item["시간"]); // "YYYY-MM-DD H:MM" 형식 (예: "2025-02-23 8:50") + const dateTimeStr = String(item["시간"]); // "M/D/YY H:MM" 형식 (예: "2/23/25 0:10") - const formattedDateTime = parseAndFormatDateTimeToISOCompatibleString(dateTimeStr, null, 'YYYY-MM-DD_H:MM'); + const formattedDateTime = parseAndFormatDateTimeToISOCompatibleString(dateTimeStr, null, 'M/D/YY_H:MM'); if (!formattedDateTime) return undefined; - const dateObject = new Date(formattedDateTime); - const mtrngDtValue = !isNaN(dateObject.getTime()) ? dateObject.toISOString() : null; - - if (!mtrngDtValue) { - console.warn("Failed to create Date object for flowRateData:", formattedDateTime); - return undefined; - } - return { - ppl_mng_no: String(item["관로번호"]), - mtrng_dt: mtrngDtValue, + pplMngNo: String(item["관로번호"]), + mtrngDt: formattedDateTime, oilq: Number(item["유량(㎥/h)"]), }; }).filter((el: any) => el !== undefined); @@ -148,7 +160,7 @@ export const excelToFlowRateData = (excelData: any) => { // 강우자료 (수정 필요) export const rainZod = z.object({ - mtrng_dt: z.string(), // 날짜 + 시간 + mtrngDt: z.string(), // 날짜 + 시간 amrf: z.number().nullish(), // 강우량(mm) }); export type rainZodType = z.infer; @@ -162,7 +174,7 @@ export const excelToRainData = (excelData: any) => { if (!formattedForRainZod) return undefined; return { - mtrng_dt: formattedForRainZod, + mtrngDt: formattedForRainZod, amrf: Number(item["강우량(mm)"]), }; }).filter((el: any) => el !== undefined); diff --git a/apps/sn/app/ii/irsetting/page.tsx b/apps/sn/app/ii/irsetting/page.tsx index 985a527c4..6c3952d90 100644 --- a/apps/sn/app/ii/irsetting/page.tsx +++ b/apps/sn/app/ii/irsetting/page.tsx @@ -121,6 +121,7 @@ const IrSetting = () => { console.log("Submitting combined analysis data to backend:", analysisData); // 추후 API 엔드포인트에 맞게 URL 수정 필요 const data = await postData('v1/inftwtAnls', analysisData); + console.log("Response from backend:", data); if (data.ok) { alert("분석 데이터가 성공적으로 제출되었습니다."); resetAllForms(); // 성공 시 폼 초기화 함수 호출 @@ -149,22 +150,19 @@ const IrSetting = () => { return; } - // filePickers 구성 시 uploadedFilesData의 file 객체 사용 const filePickers = [ // filePicked 유틸리티가 File 객체를 직접 받는지, ArrayBuffer 등을 받는지 확인 필요 // 여기서는 File 객체를 받고, 내부적으로 ArrayBuffer로 변환하여 parser에 전달한다고 가정 { file: file2, parser: excelToMatchingResultData }, { file: file3, parser: excelToTimePatternData }, { file: file4, parser: excelToFlowRateData } - // 오수관망도 파일은 파싱 대상이 아닐 수 있으므로, 필요에 따라 추가/제외 ]; try { const parsedResults = await Promise.all( filePickers.map(async ({ file, parser }) => { - if (!file || !file.file) return null; // fileInfo 객체 및 file 객체 null 체크 + if (!file || !file.file) return null; - // filePicked 함수에 File 객체와 headerNum 전달 const jsonData = await filePicked(file.file, 0); if (jsonData === undefined) { @@ -173,12 +171,11 @@ const IrSetting = () => { fileName: file.file.name, atflCd: file.atflCd, atflId: file.atflId, - parsedData: null // 또는 적절한 기본값 + parsedData: null }; } // jsonData를 각 parser 함수로 처리 - // parser 함수가 filePicked가 반환하는 JSON 형식을 직접 처리한다고 가정 const parsedDataBySpecificFunction = parser(jsonData); return { @@ -197,12 +194,12 @@ const IrSetting = () => { // 새로운 JSON 데이터 생성 const combinedAnalysisData = { - enoCd: select1, // 환경청코드 - ctpvCd: select2, // 시도코드 - sggCd: select3, // 시군구코드 - swageTmplntCd: select4, // 하수처리장코드 - swtrmtZoneCd: select5, // 하수처리구역코드 - aplcnYmd: new Date(selectedDate).toISOString().substring(0, 7).replace("-", ""), // 적용연월 + enoCd: "select1", // 환경청코드 + ctpvCd: "select2", // 시도코드 + sggCd: "select3", // 시군구코드 + swageTmplntCd: "select4", // 하수처리장코드 + swtrmtZoneCd: "select5", // 하수처리구역코드 + aplcnYm: new Date(selectedDate).toISOString().substring(0, 7).replace("-", ""), // 적용연월 dtrwSwtcRt: parseFloat(input1) || null, // 오수전환율 (숫자로 변환) anlsInfo: input2, // 분석정보 atflCd: file1?.atflCd, // 첨부파일CD (오수관망도) @@ -235,7 +232,7 @@ const IrSetting = () => { form={form} onSubmitEvent={() => { }} graphBtn={false} - searchBox={{ title: '분석 대장지역 선택' }} > + searchBox={{ title: '분석 대상지역 선택' }} >
{ }} graphBtn={false} > + { }} graphBtn={false} > {[