diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index 96ba32288..6d6ef18a6 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -1,6 +1,11 @@ import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { SelectDataType } from "@common/business_components"; import type { rainChkZodType } from "."; +import { + isInvalidDate, + isInvalidNumber, + parseRawValue, +} from "@/components/lib/func/excelFunc"; export const useTypes = [ "조경용수", "청소화장실용수", @@ -82,9 +87,11 @@ export const buildingToExcelType = ( return excelData; }; -export const excelToRainChkData = (excelData: any, year: string) => { +export const excelToRainChkData = (excelData: any, year: string) => { // const errors: string[] = []; - const rainChkgdData: rainChkZodType[] = excelData + const issues: string[] = []; + + const rainChkgdData: rainChkZodType[] = excelData .map((item: any) => { if (item["점검일"] !== undefined) { const checkYmd = item["점검일"].replace(/\./g, ""); @@ -94,15 +101,15 @@ export const excelToRainChkData = (excelData: any, year: string) => { } const makeGuidDetail = Array.from({ length: 12 }, (_, i) => { let month = `${i + 1}`; - const splyData = item[`대체_${month}월`]; - const ruseData = item[`빗물_${month}월`]; + const splyData = parseRawValue(item[`대체_${month}월`]); + const ruseData = parseRawValue(item[`빗물_${month}월`]); if (month.length < 2) month = "0" + month; return { utztnUsgCd: item["이용용도"], ym: year + month, chckYmd: checkYmd, - splyUswtrUtztnQnt: Number(splyData) || 0, - ruseFcltUtztnQnt: Number(ruseData) || 0, + splyUswtrUtztnQnt: splyData, + ruseFcltUtztnQnt: ruseData, flg: "RNB", }; }); @@ -115,19 +122,18 @@ export const excelToRainChkData = (excelData: any, year: string) => { spwtPositn: item["유량측정방법"] ?? "", rgtr: TEST_UUID, oilqMeasMthd: item["운영관리형태"] ?? "", - anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, + anlOperCst: parseRawValue(item["연간운영비(원/년)"]), operMngCd: item["유량측정방법"] ?? "", guideDetails: makeGuidDetail, rainyDetails: [ { - utztnUsgCd: item["이용용도"] ?? "", - ph: Number(item["PH"] || 0), - trbt: Number(item["탁도"] || 0), - grssClfg: Number(item["총대장균군수"] || 0), + utztnUsgCd: item["이용용도"], + trbt: parseRawValue(item["탁도"]), + grssClfg: parseRawValue(item["총대장균군수"]), etc: item["기타"] || "", // 필드 누락 방지 vltnDt: vltnDt || "-", vltnMttr: item["위반사항"] || "-", - levyAmt: Number(item["과태료부과금액(천원)"] || 0), + levyAmt: parseRawValue(item["과태료부과금액(천원)"]), rgtr: TEST_UUID, }, ], @@ -137,46 +143,61 @@ export const excelToRainChkData = (excelData: any, year: string) => { }) .filter((el: any) => el !== undefined); - - //return rainChkgdData; - const issues: string[] = []; - if (rainChkgdData.length > 0) { rainChkgdData.forEach((rain: any) => { - const defaultMessage =`[시설명: ${rain.bdstNm}, 점검일: ${rain.chckYmd}, 이용용도: ${rain.guideDetails[0]?.utztnUsgCd}] 항목에서 ` - + const defaultMessage = `[시설명: ${rain.bdstNm}, 점검일: ${rain.chckYmd}, 이용용도: ${rain.guideDetails[0]?.utztnUsgCd}] 항목에서 `; if (rain.chckYmd && isInvalidDate(rain.chckYmd)) { - issues.push(defaultMessage+`점검일: 날짜 형식 아님 (${rain.chckYmd})`); + issues.push( + defaultMessage + `점검일: 날짜 형식 아님 (${rain.chckYmd})` + ); } - if (rain.anlOperCst && isInvalidNumber(rain.anlOperCst)) { - issues.push(defaultMessage+` 연간운영비(원/년): 숫자 형식 아님 (${rain.anlOperCst})`); + if (rain.anlOperCst.length > 2 && isInvalidNumber(rain.anlOperCst)) { + issues.push( + defaultMessage + + ` 연간운영비(원/년): 숫자 형식 아님 (${rain.anlOperCst})` + ); } rain.rainyDetails?.forEach((key) => { - if (isInvalidNumber(key.ph)) { - issues.push(defaultMessage+`PH: 숫자 형식 아님 (${key.ph})`); - } else if (isInvalidNumber(key.trbt)) { - issues.push(defaultMessage+`탁도: 숫자 형식 아님 (${key.trbt})`); - } else if (isInvalidNumber(key.grssClfg)) { - issues.push(defaultMessage+`총대장균군수: 숫자 형식 아님 (${key.grssClfg})`); - } else if (isInvalidNumber(key.levyAmt)) { - issues.push(defaultMessage+`과태료부과금액(천원): 숫자 형식 아님 (${key.levyAmt})`); - } else if (isInvalidDate(key.vltnDt)) { - issues.push(defaultMessage+`과태료 부과일(위반일): 날짜 형식 아님 (${key.vltnDt})`); + if (key.ph?.length > 1 && isInvalidNumber(key.ph)) { + issues.push(defaultMessage + `PH: 숫자 형식 아님 (${key.ph})`); + } + if (key.trbt?.length > 1 && isInvalidNumber(key.trbt)) { + issues.push(defaultMessage + `탁도: 숫자 형식 아님 (${key.trbt})`); + } + if (key.grssClfg?.length > 1 && isInvalidNumber(key.grssClfg)) { + issues.push( + defaultMessage + `총대장균군수: 숫자 형식 아님 (${key.grssClfg})` + ); + } + if (key.levyAmt?.length > 1 && isInvalidNumber(key.levyAmt)) { + issues.push( + defaultMessage + + `과태료부과금액(천원): 숫자 형식 아님 (${key.levyAmt})` + ); + } + if (key.vltnDt?.length > 2 && isInvalidDate(key.vltnDt)) { + issues.push( + defaultMessage + + `과태료 부과일(위반일): 날짜 형식 아님 (${key.vltnDt})` + ); } }); rain.guideDetails?.forEach((guide) => { const mm = guide.ym.substring(4); if (isInvalidNumber(guide.splyUswtrUtztnQnt)) { issues.push( - defaultMessage+`대체_${mm}: 숫자 형식 아님 (${guide.splyUswtrUtztnQnt})` + defaultMessage + + `대체_${mm}: 숫자 형식 아님 (${guide.splyUswtrUtztnQnt})` ); } if (isInvalidNumber(guide.ruseFcltUtztnQnt)) { - issues.push(defaultMessage+`빗물_${mm}: 숫자 형식 아님 (${guide.ruseFcltUtztnQnt})`); + issues.push( + defaultMessage + + `빗물_${mm}: 숫자 형식 아님 (${guide.ruseFcltUtztnQnt})` + ); } }); - }); } @@ -185,16 +206,4 @@ export const excelToRainChkData = (excelData: any, year: string) => { } return { rainChkgdData, issues: [] }; - - //return rainChkgdData; -}; - -// ✨ 오류 검사 - 가공된 데이터 기준 -const isInvalidNumber = (val: any) => { - return !val !== undefined && val !== null && val !== "" && isNaN(Number(val)); -}; - -const isInvalidDate = (val: any) => { - //yyyymmdd 즉 20201212 이런형식만 허용 - return !(typeof val === "string" && /^\d{8}$/.test(val.trim())); }; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx index aa79a2b10..262b1cb30 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx @@ -2,6 +2,11 @@ import type { SelectDataType } from "@common/business_components/ui"; import { useTypes, type Buildingtype } from "../rainChkgdn/excel"; import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { rswtChkZodType } from "."; +import { + isInvalidDate, + isInvalidNumber, + parseRawValue, +} from "@/components/lib/func/excelFunc"; export const rswtMakeExcelSample = ( buildings: Buildingtype[], @@ -125,17 +130,20 @@ export const rswtMakeExcelSample = ( return excelSite; }; -export const excelToRswtGuideData = (excelData: any, year: string) => { - const rainChkgdData: rswtChkZodType[] = excelData +export const excelToRswtGuideData = ( + excelData: any, + year: string, + issues: string[] +) => { + const rswtChkgdData: rswtChkZodType[] = excelData .map((item: any) => { if (item["점검일"] !== undefined) { + const checkYmd = item["점검일"].replace(/\./g, ""); - const checkYmd = item["점검일"].replace(/\./g, "") - const makeGuidDetail = Array.from({ length: 12 }, (_, i) => { let month = `${i + 1}`; - const splyData = item[`대체수_${month}월`]; - const rswtData = item[`중수_${month}월`]; + const splyData = parseRawValue(item[`대체수_${month}월`]); + const rswtData = parseRawValue(item[`중수_${month}월`]); if (month.length < 2) month = "0" + month; return { ym: year + month, @@ -144,85 +152,91 @@ export const excelToRswtGuideData = (excelData: any, year: string) => { ruseFcltUtztnQnt: rswtData !== "" ? rswtData : 0, }; }); - - return { - bdstRuseFcltSn: Number(item["NO"]), - operMngCd: item["운영관리형태"], - anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, - prcsCpct: item["처리용량(m³)"], - spwtPositn: item["채수지점"], - chckYmd:checkYmd, - utztnUsgCd: item["이용용도"], - guideDetails: makeGuidDetail, - rgtr: TEST_UUID, - mdfr: TEST_UUID, - - }; + if (checkYmd.length > 7) { + return { + bdstRuseFcltSn: Number(item["NO"]), + operMngCd: item["운영관리형태"], + anlOperCst: parseRawValue(item[`연간운영비(원/년)`]), + prcsCpct: parseRawValue(item[`처리용량(m³)`]), + spwtPositn: item["채수지점"], + chckYmd: checkYmd, + utztnUsgCd: item["이용용도"], + guideDetails: makeGuidDetail, + rgtr: TEST_UUID, + mdfr: TEST_UUID, + }; + } } }) .filter((el: any) => el !== undefined); - return rainChkgdData; + + if (rswtChkgdData.length > 0) { + rswtExcelDataCheck(rswtChkgdData,issues) + } + + if (issues.length > 0) { + return { data: [], issues }; + } + + return { data:rswtChkgdData, issues: [] }; }; -export const excelToRswtPolution = (excelData: any) => { - const rainChkgdData: rswtChkZodType[] = excelData +export const excelToRswtPolution = (excelData: any, issues: string[]) => { + const rswtChkgdData: rswtChkZodType[] = excelData .map((item: any) => { if (item["점검일"] !== undefined) { - - const checkYmd = item["점검일"].replace(/\./g, "") - let vltnDt = item["과태료 부과일(위반일)"] - if (vltnDt !== undefined) { - vltnDt = vltnDt .replace(/\./g, "") + const checkYmd = item["점검일"].replace(/\./g, ""); + let vltnDt = item["과태료 부과일(위반일)"]; + if (vltnDt !== undefined) { + vltnDt = vltnDt.replace(/\./g, ""); } - const makePoluttion = Array.from({ length: 4 }, (_, i) => { - const quarter = `${i+1}`; - const grssClfgUswtr = item[`${quarter}분기_총대장균군수`]; - const combResdch = item[`${quarter}분기_결합잔류염소`]; - const trbt = item[`${quarter}분기_탁도`]; - const bod = item[`${quarter}분기_BOD`]; - const smll = item[`${quarter}분기_냄새`]; - const crmty = item[`${quarter}분기_색도`]; - const tph = item[`${quarter}분기_T-P`]; - const tn = item[`${quarter}분기_T-N`]; - const ph = item[`${quarter}분기_PH`]; - const clIonQnt = item[`${quarter}분기_염화물`]; - + const quarter = `${i + 1}`; + const grssClfgUswtr = parseRawValue( + item[`${quarter}분기_총대장균군수`] + ); + const combResdch = parseRawValue(item[`${quarter}분기_결합잔류염소`]); + const trbt = parseRawValue(item[`${quarter}분기_탁도`]); + const bod = parseRawValue(item[`${quarter}분기_BOD`]); + const smll = parseRawValue(item[`${quarter}분기_냄새`]); + const crmty = parseRawValue(item[`${quarter}분기_색도`]); + const tph = parseRawValue(item[`${quarter}분기_T-P`]); + const tn = parseRawValue(item[`${quarter}분기_T-N`]); + const ph = parseRawValue(item[`${quarter}분기_PH`]); + const clIonQnt = parseRawValue(item[`${quarter}분기_염화물`]); return { - node: quarter, chckYmd: checkYmd, - grssClfgUswtr: grssClfgUswtr !== "" ? grssClfgUswtr : 0, - combResdch: combResdch !== "" ? combResdch : 0, - trbt: trbt !== "" ? trbt : 0, - bod: bod !== "" ? bod : 0, - smll: smll !== "" ? smll : 0, - crmty: crmty !== "" ? crmty : 0, - tph: tph !== "" ? tph : 0, - tn: tn !== "" ? tn : 0, - ph: ph !== "" ? ph : 0, - clIonQnt: clIonQnt !== "" ? clIonQnt : 0, + grssClfgUswtr: grssClfgUswtr, + combResdch: combResdch, + trbt: trbt, + bod: bod, + smll: smll, + crmty: crmty, + tph: tph, + tn: tn, + ph: ph, + clIonQnt: clIonQnt, rgtr: TEST_UUID, mdfr: TEST_UUID, }; }); - return { bdstRuseFcltSn: Number(item["NO"]), chckYmd: checkYmd, utztnUsgCd: item["이용용도"], operMngCd: item["운영관리형태"], - anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, - prcsCpct: item["처리용량(m³)"], - spwtPositn: item["채수지점"], - rswtrPollutions: makePoluttion, + anlOperCst: parseRawValue(item["연간운영비(원/년)"]), + prcsCpct: parseRawValue(item["처리용량(m³)"]), + spwtPositn: item["채수지점"], + rswtrPollutions: makePoluttion, rgtr: TEST_UUID, mdfr: TEST_UUID, rswtrDetails: [ - { + { utztnUsgCd: item["이용용도"], - vltnDt:vltnDt, + vltnDt: vltnDt, vltnMttr: item["위반사항"], levyAmt: Number(item["과태료 부과금액(천원)"]) ?? 0, rgtr: TEST_UUID, @@ -233,5 +247,118 @@ export const excelToRswtPolution = (excelData: any) => { } }) .filter((el: any) => el !== undefined); - return rainChkgdData; + if (rswtChkgdData.length > 0) { + rswtExcelDataCheck(rswtChkgdData,issues) + } + + if (issues.length > 0) { + return { data: [], issues }; + } + + return { data:rswtChkgdData, issues: [] }; }; + + +const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{ + rswtChkgdData.forEach((rswt: any) => { + const defaultMessage = `*중수도 수질 [NO: ${rswt.bdstRuseFcltSn}, 점검일: ${rswt.chckYmd}, 이용용도: ${rswt.utztnUsgCd}] 항목에서 `; + + if (rswt.chckYmd && isInvalidDate(rswt.chckYmd)) { + issues.push( + defaultMessage + `점검일: 날짜 형식 아님 (${rswt.chckYmd})` + ); + } + if (rswt.anlOperCst.length > 2 && isInvalidNumber(rswt.anlOperCst)) { + issues.push( + defaultMessage + + ` 연간운영비(원/년): 숫자 형식 아님 (${rswt.anlOperCst})` + ); + } + if (rswt.prcsCpct.length > 2 && isInvalidNumber(rswt.prcsCpct)) { + issues.push( + defaultMessage + ` 처리용량(m³): 숫자 형식 아님 (${rswt.prcsCpct})` + ); + } + if (rswt?.rswtrPollutions && rswt?.rswtrPollutions.length > 0) { + rswt.rswtrPollutions.forEach((pol) => { + if (isInvalidNumber(pol.grssClfgUswtr)) { + issues.push( + defaultMessage + + `${pol.node}분기_총대장균군수: 숫자 형식 아님 (${pol.grssClfgUswtr})` + ); + } + if (isInvalidNumber(pol.combResdch)) { + issues.push( + defaultMessage + + `${pol.node}분기_결합잔류염소: 숫자 형식 아님 (${pol.combResdch})` + ); + } + if (isInvalidNumber(pol.trbt)) { + issues.push( + defaultMessage + + `${pol.node}분기_탁도: 숫자 형식 아님 (${pol.trbt})` + ); + } + if (isInvalidNumber(pol.bod)) { + issues.push( + defaultMessage + + `${pol.node}분기_BOD: 숫자 형식 아님 (${pol.bod})` + ); + } + if (isInvalidNumber(pol.smll)) { + issues.push( + defaultMessage + + `${pol.node}분기_냄새: 숫자 형식 아님 (${pol.smll})` + ); + } + if (isInvalidNumber(pol.crmty)) { + issues.push( + defaultMessage + + `${pol.node}분기_색도: 숫자 형식 아님 (${pol.crmty})` + ); + } + if (isInvalidNumber(pol.tph)) { + issues.push( + defaultMessage + + `${pol.node}분기_T-P: 숫자 형식 아님 (${pol.tph})` + ); + } + if (isInvalidNumber(pol.tn)) { + issues.push( + defaultMessage + `${pol.node}분기_T-N: 숫자 형식 아님 (${pol.tn})` + ); + } + if (isInvalidNumber(pol.ph)) { + issues.push( + defaultMessage + `${pol.node}분기_PH: 숫자 형식 아님 (${pol.ph})` + ); + + if (isInvalidNumber(pol.clIonQnt)) { + issues.push( + defaultMessage + + `${pol.node}분기_PH: 숫자 형식 아님 (${pol.clIonQnt})` + ); + } + } + }); + } + if (rswt?.rswtrDetails && rswt?.rswtrDetails.length > 0) { + rswt?.rswtrDetails.forEach((key) => { + if (key.levyAmt?.length > 1 && isInvalidNumber(key.levyAmt)) { + issues.push( + defaultMessage + + `과태료부과금액(천원): 숫자 형식 아님 (${key.levyAmt})` + ); + } + if (key.vltnDt?.length > 2 && isInvalidDate(key.vltnDt)) { + issues.push( + defaultMessage + + `과태료 부과일(위반일): 날짜 형식 아님 (${key.vltnDt})` + ); + } + }); + } + }) + + +} \ No newline at end of file diff --git a/apps/wr/components/lib/func/excelFunc.tsx b/apps/wr/components/lib/func/excelFunc.tsx new file mode 100644 index 000000000..2383bdbb3 --- /dev/null +++ b/apps/wr/components/lib/func/excelFunc.tsx @@ -0,0 +1,17 @@ +// ✨ 오류 검사 - 가공된 데이터 기준 +export const isInvalidNumber = (val: any) => { + return val !== undefined && val !== null && val !== "" && isNaN(Number(val)); + }; + + export const isInvalidDate = (val: any) => { + //yyyymmdd 즉 20201212 이런형식만 허용 + return !(typeof val === "string" && /^\d{8}$/.test(val.trim())); + }; + + export const parseRawValue = (val: any): number | string => { + if (val === "" || val === undefined || val === null) return 0; + if (typeof val === "string" && ["보류", "N/A"].includes(val.trim())) + return val; + return !isNaN(val) && val !== " " ? Number(val) : val; + }; + \ No newline at end of file diff --git a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx index 011c43cf1..46e6c5d30 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx @@ -34,7 +34,6 @@ export default function ChkgdExcel({ setYearChange: (year: string) => void; }) { const { - rainChkgdn, rainChkExcelDataUPload, rswtChkExceDataUpload, setRainChkLoading, @@ -97,8 +96,9 @@ export default function ChkgdExcel({ form.getValues("chckYr") ); if (excelData.issues && excelData.issues.length > 0) { - excelData.issues.forEach((err) => { + excelData.issues.some((err, index) => { showConfirmToast(err); + return index === 4; // true 반환 시 반복 종료 }); clearFile(); } else { @@ -110,48 +110,61 @@ export default function ChkgdExcel({ }); } else if (type === "RST") { filePickedArray(file, 0).then((res) => { + let issues: string[] = []; + if (res && res?.length > 1) { const guideData = excelToRswtGuideData( res[0], - form.getValues("chckYr") + form.getValues("chckYr"), + issues ); - const polutionData = excelToRswtPolution(res[1]); + const polutionData = excelToRswtPolution(res[1], issues); - const keyGenerator = (item: rswtChkZodType) => - `${item.bdstRuseFcltSn}|${item.chckYmd}|${item.utztnUsgCd}`; - const totalData: rswtChkZodType[] = guideData.map((guide) => { - const fusion = polutionData.find( - (polution) => - guide.bdstRuseFcltSn === polution.bdstRuseFcltSn && - guide.chckYmd === polution.chckYmd && - guide.utztnUsgCd === polution.utztnUsgCd + issues = [...guideData.issues, ...polutionData.issues]; + + if (issues && issues.length > 0) { + issues.some((err, index) => { + showConfirmToast(err); + return index === 6; // true 반환 시 반복 종료 + }); + clearFile(); + } else { + const keyGenerator = (item: rswtChkZodType) => + `${item.bdstRuseFcltSn}|${item.chckYmd}|${item.utztnUsgCd}`; + const totalData: rswtChkZodType[] = guideData.data.map( + (guide) => { + const fusion = polutionData.data.find( + (polution) => + guide.bdstRuseFcltSn === polution.bdstRuseFcltSn && + guide.chckYmd === polution.chckYmd && + guide.utztnUsgCd === polution.utztnUsgCd + ); + + if (fusion) { + return { + ...guide, + rswtrPollutions: fusion?.rswtrPollutions, + rswtrDetails: fusion?.rswtrDetails, + }; + } else { + return { + ...guide, + }; + } + } + ); + const guideKey = new Set(guideData.data.map(keyGenerator)); + const onlypolution = polutionData.data.filter( + (item) => !guideKey.has(keyGenerator(item)) ); - if (fusion) { - return { - ...guide, - rswtrPollutions: fusion?.rswtrPollutions, - rswtrDetails: fusion?.rswtrDetails, - }; - } else { - return { - ...guide, - }; - } - }); + const listTotalData: rswtChkZodType[] = [ + ...totalData, + ...onlypolution, + ]; - const guideKey = new Set(guideData.map(keyGenerator)); - - const onlypolution = polutionData.filter( - (item) => !guideKey.has(keyGenerator(item)) - ); - - const listTotalData: rswtChkZodType[] = [ - ...totalData, - ...onlypolution, - ]; - - setExcelRswtData(listTotalData); + setExcelRswtData(listTotalData); + } } }); } @@ -202,7 +215,7 @@ export default function ChkgdExcel({ } } }; - + return ( <>