엑셀 중수도 지도점검 데이터 확인

This commit is contained in:
leedj312
2025-07-16 19:27:24 +09:00
parent ea7536bea3
commit bd6dfd31fd
4 changed files with 309 additions and 143 deletions
@@ -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()));
};
@@ -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})`
);
}
});
}
})
}
+17
View File
@@ -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;
};
@@ -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 (
<>
<div>