diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index ad8874ac9..779a6e381 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -4,6 +4,7 @@ import { useWrStore } from "@/app/store"; import { fcltDiv, type chHeadType, + type rainChkZodType, } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import { ContentsDiv, @@ -18,12 +19,12 @@ import { } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Input } from "@common/components/ui"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { TableRow, TableHead } from "@common/components"; import React from "react"; import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import RainChkgdTable from "@/components/ui/table/rainChkgd/rainChkgdTable"; -import RswtChkgdTable from "@/components/ui/table/rswtChkgd/rswtChkgdTable"; +import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable"; +import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable"; import ChkgdModal from "@/components/ui/modal/chkgdModal/chkgdModal"; import ChkgdExcel from "@/components/ui/modal/chkgdExcel/chkgdExcel"; @@ -33,9 +34,6 @@ export const headMakeprfmnc = ( ) => { return ( <> - - - {upHeadList .map((head: TableUpperProps) => @@ -81,18 +79,31 @@ export const headMakeprfmnc = ( }; //----------------------- export default function Page() { + + const { rainChkgdn, code, rainChkInit,rainChkDetilUpdate } = useWrStore((state) => { + return state; + }); + + const {rainChk} =rainChkgdn const [isDetail, setIsDetail] = useState(false); const [isExcel, setIsExcel] = useState(false); - + const [searchTxt, setSearchTxt] = useState(); const [testObj, setTestObj] = useState({}); - - const [selFcltDiv, setSelFcltDiv] = useState("RST"); + const [updateRainDetail, setUpdateRainDetail] = useState([]); + const [selFcltDiv, setSelFcltDiv] = useState("RNB"); const cellClick = () => { - const ch = { bdstNm: "test", chckYmd: "2022-10-10" }; - setTestObj(ch); + if(searchTxt) + rainChkInit(searchTxt,'41') + }; + useEffect(() => { + if (!rainChkgdn.isInit) { + rainChkInit('2024','0'); + } + }, [rainChkgdn.isInit, rainChkInit]); + return (
@@ -103,8 +114,8 @@ export default function Page() { {}} + textValue={searchTxt??''} + setText={(e) => {setSearchTxt(e);}} /> { cellClick(); - setIsDetail(!isDetail); }} > 조회 @@ -130,7 +140,7 @@ export default function Page() { -
@@ -156,7 +166,7 @@ export default function Page() {
- {selFcltDiv === "RNB" ? : } + {selFcltDiv === "RNB" ? : }
diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index 43de52ff9..9b26b68f3 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -1,233 +1,408 @@ -import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import type { text } from "stream/consumers"; +import { + TEST_UUID, + type TableUpperProps, +} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { getFetch, postFectch, putFectch } from "@/components/lib/api"; import { z } from "zod"; +export const rainChkZod = z.object({ + chkgdnPk: z.number(), + bdstRuseFcltFk: z.number(), + chckYmd: z.string(), + prcsCpct: z.number(), + spwtPositn: z.string(), + regDt: z.string(), + rgtr: z.string(), + mdfcnDt: z.string().nullable(), + mdfr: z.string().nullable(), + flg: z.string(), + guideDetails: z.array( + z.object({ + chkgdnFk: z.number(), + utztnUsgCd: z.string(), + chckYmd: z.string(), + ym: z.string(), + splyUswtrUtztnQnt: z.number(), + ruseFcltUtztnQnt: z.number(), + flg: z.string(), + }) + ), + building: z.object({ + bdstInfoPk: z.number(), + ctpvCd: z.number(), + sggCd: z.number(), + daddr: z.string().nullable(), + bdstNm: z.string(), + frstArchPrmsnDt: z.string().nullable(), + archArea: z.number(), + regDt: z.string().nullable(), + rgtr: z.string().nullable(), + mdfcnDt: z.string().nullable(), + mdfr: z.string().nullable(), + }), + rainyDetails: z.array( + z.object({ + chkgdnFk: z.number(), + utztnUsgCd: z.string(), + ph: z.number(), + trbt: z.number(), + grssClfg: z.number(), + etc: z.string(), + vltnDt: z.string(), + vltnMttr: z.string(), + levyAmt: z.number(), + regDt: z.string(), + rgtr: z.string(), + mdfcnDt: z.string().nullable(), + mdfr: z.string().nullable(), + }) + ), +}); + +export type rainChkZodType = z.infer; + +export const rainRegExcel = z.object({ + bdstInfoPk: z.number().default(111111111), + chckYmd: z.date().default(new Date()), + file: z.instanceof(File).optional(), +}); + +export const fcltDiv = [ + { val: "RST", text: "중수도시설" }, + { val: "RNB", text: "빗물이용시설" }, +]; + +export type chHeadType = { + headNm: string; + text: string; + length: number; + rows?: number; +}; + +export const rainHeadNm: chHeadType[] = [ + { headNm: "useQuilty", text: "이용수질(필요시)", length: 4 }, + { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, + { headNm: "ruseWater", text: "연간보급수 이용량(m³)", length: 13 }, + { headNm: "detailQulity", text: "분기", length: 11 }, + { headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 }, + +]; + +export const rainChkgdnHeadList: TableUpperProps[] = [ + { id: "order", title: "순번", rowSpan: true }, + { id: "cityText", title: "시도", rowSpan: true }, + { id: "sggText", title: "시군구", rowSpan: true }, + { id: "bdstNm", title: "시설명", rowSpan: true }, + { id: "operMngCd", title: "운영관리형태", rowSpan: true }, + { id: "flowCheck", title: "유량측정방법", rowSpan: true }, + { id: "yearFee", title: "연간운영비(원/년)", rowSpan: true }, + { id: "rainDtnbaOpct", title: "빗물저류조용량(m³)", rowSpan: true }, + { id: "chckYmd", title: "점검일", rowSpan: true }, + { id: "utztnUsgCd", title: "이용용도" }, + { id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, + { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" }, + { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 1, type: "number" }, + { + id: "trbt", + title: "탁도", + upName: "useQuilty", + upSequnce: 2, + type: "number", + }, + { + id: "grssClfg", + title: "총대장균군수", + upName: "useQuilty", + upSequnce: 3, + type: "number", + }, + { + id: "etc", + title: "기타", + upName: "useQuilty", + upSequnce: 4, + type: "number", + }, + { + id: "vltnDt", + title: "부과일(위반일)", + upName: "feeHist", + upSequnce: 1, + type: "text", + }, + { + id: "vltnMttr", + title: "위반사항", + upName: "feeHist", + upSequnce: 2, + type: "text", + }, + { + id: "levyAmt", + title: "부과금액(천원)", + upName: "feeHist", + upSequnce: 3, + type: "number", + }, +]; + +export const ruseHeadList: TableUpperProps[] = [ + { id: "utztnUsgCd", title: "이용용도" }, + { id: "ruseTotal", title: "계", upName: "ruseWater", upSequnce: 1 }, + { id: "ruse01", title: "1월", upName: "ruseWater", upSequnce: 2 }, + { id: "ruse02", title: "2월", upName: "ruseWater", upSequnce: 3 }, + { id: "ruse03", title: "3월", upName: "ruseWater", upSequnce: 4 }, + { id: "ruse04", title: "4월", upName: "ruseWater", upSequnce: 5 }, + { id: "ruse05", title: "5월", upName: "ruseWater", upSequnce: 6 }, + { id: "ruse06", title: "6월", upName: "ruseWater", upSequnce: 7 }, + { id: "ruse07", title: "7월", upName: "ruseWater", upSequnce: 8 }, + { id: "ruse08", title: "8월", upName: "ruseWater", upSequnce: 9 }, + { id: "ruse09", title: "9월", upName: "ruseWater", upSequnce: 10 }, + { id: "ruse10", title: "10월", upName: "ruseWater", upSequnce: 11 }, + { id: "ruse11", title: "11월", upName: "ruseWater", upSequnce: 12 }, + { id: "ruse12", title: "12월", upName: "ruseWater", upSequnce: 13 }, +]; + +export const splHeadList: TableUpperProps[] = [ + { id: "utztnUsgCd", title: "이용용도" }, + { id: "splTotal", title: "계", upName: "splWater", upSequnce: 1 }, + { id: "spl01", title: "1월", upName: "splWater", upSequnce: 2 }, + { id: "spl02", title: "2월", upName: "splWater", upSequnce: 3 }, + { id: "spl03", title: "3월", upName: "splWater", upSequnce: 4 }, + { id: "spl04", title: "4월", upName: "splWater", upSequnce: 5 }, + { id: "spl05", title: "5월", upName: "splWater", upSequnce: 6 }, + { id: "spl06", title: "6월", upName: "splWater", upSequnce: 7 }, + { id: "spl07", title: "7월", upName: "splWater", upSequnce: 8 }, + { id: "spl08", title: "8월", upName: "splWater", upSequnce: 9 }, + { id: "spl09", title: "9월", upName: "splWater", upSequnce: 10 }, + { id: "spl10", title: "10월", upName: "splWater", upSequnce: 11 }, + { id: "spl11", title: "11월", upName: "splWater", upSequnce: 12 }, + { id: "spl12", title: "12월", upName: "splWater", upSequnce: 13 }, +]; + +export const rswtDetailHeadList: TableUpperProps[] = [ + { id: "utztnUsgTest", title: "이용용도" }, + { + id: "avre", + title: "평균", + upName: "detailQulity", + upSequnce: 1, + edit: true, + }, + { + id: "grssClfg", + title: "총대장균군수", + upName: "detailQulity", + upSequnce: 2, + edit: true, + }, + { + id: "combResdch", + title: "결합잔류염소", + upName: "detailQulity", + upSequnce: 3, + edit: true, + }, + { + id: "trbt", + title: "탁도", + upName: "detailQulity", + upSequnce: 4, + edit: true, + }, + { id: "bod", title: "BOD", upName: "detailQulity", upSequnce: 5, edit: true }, + { + id: "smll", + title: "냄새", + upName: "detailQulity", + upSequnce: 6, + edit: true, + }, + { + id: "crmty", + title: "색도", + upName: "detailQulity", + upSequnce: 7, + edit: true, + }, + { id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8, edit: true }, + { id: "tph", title: "T-P", upName: "detailQulity", upSequnce: 9, edit: true }, + { id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10, edit: true }, + { + id: "clIonQnt", + title: "염화물", + upName: "detailQulity", + upSequnce: 11, + edit: true, + }, +]; + + + +export type splRuseWaterType = { + utztnUsgCd: string; + splTotal: number; + spl01: number; + spl02: number; + spl03: number; + spl04: number; + spl05: number; + spl06: number; + spl07: number; + spl08: number; + spl09: number; + spl10: number; + spl11: number; + spl12: number; + ruseTotal: number; + ruse01: number; + ruse02: number; + ruse03: number; + ruse04: number; + ruse05: number; + ruse06: number; + ruse07: number; + ruse08: number; + ruse09: number; + ruse10: number; + ruse11: number; + ruse12: number; +}; -export const rainRegExcel =z.object({ - bdstInfoPk:z.number().default(111111111), - chckYmd:z.date().default(new Date()), - file: z.instanceof(File).optional() - - -}) - - -export const fcltDiv=[ - {val:'RST', text:'중수도시설'}, - {val:'RNB', text:'빗물이용시설'}, -] - - -export type chHeadType={ - headNm: string; - text: string; - length: number; - rows?: number; -} - -export const rainHeadNm:chHeadType[] = [ - {headNm:"useQuilty", text:"이용수질(필요시)" , length: 4}, - {headNm:"feeHist", text:"과태료 부과내역" , length: 3}, - {headNm:"subWater", text:"연간보급수 이용량(m³)" , length: 13}, - {headNm:"detailQulity", text:"분기" , length: 11} -] - -export const rainChkgdnHeadList:TableUpperProps[] = [ - { id: "cityText", title: "시도" }, - { id: "sggText", title: "시군구" }, - { id: "bdstNm", title: "시설명" }, - { id: "operMngCd", title: "운영관리형태" }, - { id: "flowCheck", title: "유량측정방법" }, - { id: "yearFee", title: "연간운영비(원/년)" }, - { id: "rainDtnbaOpct", title: "빗물저류조용량(m³)" }, - { id: "checkDay", title: "점검일" }, - { id: "utztnUsg", title: "이용용도" }, - - { id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, - { id: "rainUsg", title: "연간빗물이용량(m³)" }, - { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 1 }, - { id: "trbt", title: "탁도", upName: "useQuilty", upSequnce: 2 }, - { id: "grssClfg", title: "총대장균군수", upName: "useQuilty", upSequnce: 3 }, - { id: "etc", title: "기타", upName: "useQuilty", upSequnce: 4 }, - { id: "dayFee", title: "부과일(위반일)", upName: "feeHist", upSequnce: 1 }, - { id: "guilty", title: "위반사항", upName: "feeHist", upSequnce: 2 }, - { id: "fee", title: "부과금액(천원)", upName: "feeHist", upSequnce: 3 }, - ]; - -export const supWaterHeadList:TableUpperProps[] = [ - { id: "utztnUsgTest", title: "이용용도" }, - { id: "total", title: "계" ,upName: "subWater", upSequnce: 1 , edit:true}, - { id: "sub1", title: "1월" , upName: "subWater", upSequnce: 2 , edit:true}, - { id: "sub2", title: "2월", upName: "subWater", upSequnce: 3 , edit:true}, - { id: "sub3", title: "3월", upName: "subWater", upSequnce: 4 , edit:true}, - { id: "sub4", title: "4월", upName: "subWater", upSequnce: 5 , edit:true}, - { id: "sub5", title: "5월", upName: "subWater", upSequnce: 6 , edit:true}, - { id: "sub6", title: "6월", upName: "subWater", upSequnce: 7 , edit:true}, - { id: "sub7", title: "7월", upName: "subWater", upSequnce: 8 , edit:true}, - { id: "sub8", title: "8월", upName: "subWater", upSequnce: 9 , edit:true}, - { id: "sub9", title: "9월", upName: "subWater", upSequnce: 10, edit:true }, - { id: "sub10", title: "10월", upName: "subWater", upSequnce: 11 , edit:true}, - { id: "sub11", title: "11월", upName: "subWater", upSequnce: 12 , edit:true}, - { id: "sub12", title: "12월", upName: "subWater", upSequnce: 13 , edit:true}, - ] - - - export const rswtDetailHeadList:TableUpperProps[] = [ - { id: "utztnUsgTest", title: "이용용도" }, - { id: "avre", title: "평균" ,upName: "detailQulity", upSequnce: 1 , edit:true}, - { id: "grssClfg", title: "총대장균군수" , upName: "detailQulity", upSequnce: 2 , edit:true}, - { id: "combResdch", title: "결합잔류염소", upName: "detailQulity", upSequnce: 3 , edit:true}, - { id: "trbt", title: "탁도", upName: "detailQulity", upSequnce: 4 , edit:true}, - { id: "bod", title: "BOD", upName: "detailQulity", upSequnce: 5 , edit:true}, - { id: "smll", title: "냄새", upName: "detailQulity", upSequnce: 6 , edit:true}, - { id: "crmty", title: "색도", upName: "detailQulity", upSequnce: 7 , edit:true}, - { id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8 , edit:true}, - { id: "tph", title: "T-P", upName: "detailQulity", upSequnce: 9 , edit:true}, - { id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10, edit:true }, - { id: "clIonQnt", title: "염화물", upName: "detailQulity", upSequnce: 11 , edit:true}, - ] - - -export const supWaterData =[{ - utztnUsgTest:'test', - total:100, - sub1:10, - sub2:10, - sub3:10, - sub4:10, - sub5:10, - sub6:10, - sub7:10, - sub8:10, - sub9:10, - sub10:10, - sub11:10, - sub12:10, -}, -{ - utztnUsgTest:'test22', - total:10011, - sub1:101, - sub2:101, - sub3:101, - sub4:101, - sub5:101, - sub6:101, - sub7:101, - sub8:101, - sub9:101, - sub10:101, - sub11:101, - sub12:101, -} -] - -type supWaterDataType ={ - utztnUsgTest:string, - total:number, - sub1:number, - sub2:number, - sub3:number, - sub4:number, - sub5:number, - sub6:number, - sub7:number, - sub8:number, - sub9:number, - sub10:number, - sub11:number, - sub12:number, -} - - - - -// export const rainChkgdnHeadList:TableUpperProps[] = [ -// { id: "cityText", title: "시도" }, -// { id: "sggText", title: "시군구" }, -// { id: "bdstNm", title: "시설명" }, -// { id: "operMngCd", title: "운영관리형태" }, -// { id: "flowCheck", title: "유량측정방법" }, -// { id: "yearFee", title: "연간운영비(원/년)" }, -// { id: "rainDtnbaOpct", title: "빗물저류조용량(m³)" }, -// { id: "checkDay", title: "점검일" }, -// { id: "utztnUsg", title: "이용용도" }, -// { id: "sub1", title: "1월" , upName: "subWater", upSequnce: 1 }, -// { id: "sub2", title: "2월", upName: "subWater", upSequnce: 2 }, -// { id: "sub3", title: "3월", upName: "subWater", upSequnce: 3 }, -// { id: "sub4", title: "4월", upName: "subWater", upSequnce: 4 }, -// { id: "sub5", title: "5월", upName: "subWater", upSequnce: 5 }, -// { id: "sub6", title: "6월", upName: "subWater", upSequnce: 6 }, -// { id: "sub7", title: "7월", upName: "subWater", upSequnce: 7 }, -// { id: "sub8", title: "8월", upName: "subWater", upSequnce: 8 }, -// { id: "sub9", title: "9월", upName: "subWater", upSequnce: 9 }, -// { id: "sub10", title: "10월", upName: "subWater", upSequnce: 10 }, -// { id: "sub11", title: "11월", upName: "subWater", upSequnce: 11 }, -// { id: "sub12", title: "12월", upName: "subWater", upSequnce: 12 }, - -// { id: "rain1", title: "1월", upName: "yearRainWater", upSequnce: 1 }, -// { id: "rain2", title: "2월", upName: "yearRainWater", upSequnce: 2 }, -// { id: "rain3", title: "3월", upName: "yearRainWater", upSequnce: 3 }, -// { id: "rain4", title: "4월", upName: "yearRainWater", upSequnce: 4 }, -// { id: "rain5", title: "5월", upName: "yearRainWater", upSequnce: 5 }, -// { id: "rain6", title: "6월", upName: "yearRainWater", upSequnce: 6 }, -// { id: "rain7", title: "7월", upName: "yearRainWater", upSequnce: 7 }, -// { id: "rain8", title: "8월", upName: "yearRainWater", upSequnce: 8 }, -// { id: "rain9", title: "9월", upName: "yearRainWater", upSequnce: 9 }, -// { id: "rain10", title: "10월", upName: "yearRainWater", upSequnce: 10 }, -// { id: "rain11", title: "11월", upName: "yearRainWater", upSequnce: 11 }, -// { id: "rain12", title: "12월", upName: "yearRainWater", upSequnce: 12 }, - -// { id: "ph", title: "PH", upName: "useQuilty", upSequnce: 1 }, -// { id: "trbt", title: "탁도", upName: "useQuilty", upSequnce: 2 }, -// { id: "grssClfg", title: "총대장균군수", upName: "useQuilty", upSequnce: 3 }, -// { id: "etc", title: "기타", upName: "useQuilty", upSequnce: 4 }, - -// { id: "dayFee", title: "부과일(위반일)", upName: "feeHist", upSequnce: 1 }, -// { id: "guilty", title: "위반사항", upName: "feeHist", upSequnce: 2 }, -// { id: "fee", title: "부과금액(천원)", upName: "feeHist", upSequnce: 3 }, -// ]; - +const rainChk: rainChkZodType[] = []; export type rainChkgdnState = { rainChkgdn: { - rainChkgdnHeadList:TableUpperProps[] - rainHeadNm:chHeadType[] - supWaterHeadList:TableUpperProps[] - supWaterData:supWaterDataType[] - rswtDetailHeadList:TableUpperProps[] + rainChkgdnHeadList: TableUpperProps[]; + rainChk: rainChkZodType[]; + rainHeadNm: chHeadType[]; + ruseHeadList: TableUpperProps[]; + splHeadList: TableUpperProps[]; + rswtDetailHeadList: TableUpperProps[]; + isInit: boolean; }; }; type rainChkgdnActions = { - rainChkgdnInit: (sggCd:string, searchTxt:string, flag:string) => void ; - }; - - + rainChkInit: (sggCd: string, searchTxt: string) => void; + rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise; + rainChkGuidUpdate(rainChk: rainChkZodType): Promise; +}; + export type rainChkgdnType = rainChkgdnState & rainChkgdnActions; - export const rainChkgdnStateExport: rainChkgdnState = { - rainChkgdn: { - rainChkgdnHeadList:rainChkgdnHeadList, - rainHeadNm:rainHeadNm, - supWaterHeadList:supWaterHeadList, - supWaterData:supWaterData, - rswtDetailHeadList:rswtDetailHeadList, + rainChkgdn: { + rainChkgdnHeadList: rainChkgdnHeadList, + rainHeadNm: rainHeadNm, + rainChk: rainChk, + splHeadList:splHeadList, + ruseHeadList: ruseHeadList, + rswtDetailHeadList: rswtDetailHeadList, + isInit: false, }, }; +const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => { + + const chData=data.map((item) => { + item.mdfr = TEST_UUID; + + if (type === "rainyDetails") { + item.rainyDetails.forEach((item) => { + item.mdfr = TEST_UUID; + }); + } else { + } + }) + + return chData; + +}; + +const initFetch = async (txt: string | undefined, sgg: string | undefined) => { + const rainRes = await getFetch( + "wr", + `/reuseChk/rainy` + (txt ? `/${txt}` : "2024") + (sgg ? `/${sgg}` : "/0") + ); + const chRainRes = rainRes.map((item: rainChkZodType) => { + return { + ...item, + }; + }); + return chRainRes; +}; + export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( set: any ) => { return { - - rainChkgdnInit: async(sggCd:string, searchTxt:string ,flg:string ) =>{ - + rainChkInit: async (searchTxt: string, sggCd: string) => { + try { + const rainChkRes = await initFetch(searchTxt, sggCd); + + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + } catch (error) { + console.log(error); + } }, + rainChkDetilUpdate: async (rainChk: rainChkZodType[] ) => { + try { + const chData = await makeMdfrChk(rainChk, "rain", "rainDetil"); + + const res = await postFectch("/reuseChk/rainyExcel", rainChk); + if (res.ok) { + alert(" 수정이 완료되었습니다."); + } + + const rainChkRes = await initFetch('2024', '0'); + + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + } catch (error) { + console.log(error); + alert("수정에 실패하였습니다."); + } + }, + rainChkGuidUpdate: async (rainChk: rainChkZodType) => { + + try{ + + //const chData = await makeMdfrChk(rainChk, "guideDetails", "rainDetil"); + const res = await putFectch("/reuseChk/rainy", rainChk); + if (res.ok) { + alert(" 수정이 완료되었습니다."); + } + const rainChkRes = await initFetch('2024', '0'); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + }catch(error){ + console.log(error); + } + + + } + + }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 33b2228d3..55f203c19 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -97,6 +97,8 @@ export type TableUpperProps = { upSequnce?: number; edit?:boolean; visible?:boolean; + rowSpan?: true; + type?: string; }; export type TableTripleProps = { @@ -223,15 +225,10 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( try { const test =await makeRstr(data); - - - console.log("test ", test) const res = await postFectch("/reuseFc/rainyInfo", test); if(res.ok){ - if(data.chgBuilding.length > 0){ await res.json().then((resData: any) => { - const chPK = resData?.data?.bdstInfoPk const makeCh= resData.data.chgBuilding.map((item: chgBuilding) => ( { diff --git a/apps/wr/components/lib/api/index.ts b/apps/wr/components/lib/api/index.ts index 842ab5f88..15b6d9aff 100644 --- a/apps/wr/components/lib/api/index.ts +++ b/apps/wr/components/lib/api/index.ts @@ -21,6 +21,7 @@ export const getFetch = async( type:string , url: string) => { } export const postFectch = async (url: string, params: any) => { + const response = await fetch(DEV_URL_WR+url, { method: "POST", headers: { diff --git a/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx index 73e781487..96b324b3c 100644 --- a/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgdModal/chkgdModal.tsx @@ -2,152 +2,214 @@ import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; import { useWrStore } from "@/app/store"; import { ScrollArea, Title, UiTable } from "@common/business_components/ui"; import { Button } from "@common/components/ui"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; +import { GuideDetailsTable } from "../../table/chkgdTable/guideDetailTable/guideDetailTable"; +import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -export default function ChkgdModal({type, obj}:{type:string , obj:any} ){ +export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { + const { rainChkgdn, rainChkDetilUpdate, rainChkGuidUpdate } = useWrStore( + (state) => state + ); + const [guidData, setGuidData] = useState(); + const rswtnodeList = headMakeprfmnc( + rainChkgdn?.rswtDetailHeadList, + rainChkgdn?.rainHeadNm + ); + const { rainChk, ruseHeadList, splHeadList } = rainChkgdn; + const [updateData, setUpdateData] = useState(); - const { rainChkgdn} = useWrStore((state) => state); - + useEffect(() => { + const result = obj.guideDetails?.reduce((acc: any, cur: any) => { + const code = cur.utztnUsgCd; + const month = cur.ym?.slice(4); // "MM" + const ruseMonthKey = `ruse${month}`; + const splMonthKey = `spl${month}`; + const ruseValue = cur.ruseFcltUtztnQnt; + const splValue = cur.splyUswtrUtztnQnt; - const nodeList = headMakeprfmnc(rainChkgdn?.supWaterHeadList,rainChkgdn?.rainHeadNm ) ; - const rswtnodeList = headMakeprfmnc(rainChkgdn?.rswtDetailHeadList,rainChkgdn?.rainHeadNm ) ; + // 해당 utztnUsgCd 객체가 없으면 새로 생성 + let target = acc.find( + (it: { utztnUsgCd: string }) => it?.utztnUsgCd === code + ); + if (!target) { + target = { utztnUsgCd: code, ruseTotal: 0, splTotal: 0 }; + acc.push(target); + } - - useEffect(() =>{ - - },[rainChkgdn]) - - - const cellClick =(val:number|undefined, headId:string)=>{ - if(val!=undefined) - console.log(rainChkgdn.supWaterData[val]) + // 월별 값 누적 + target[ruseMonthKey] = (target[ruseMonthKey] ?? 0) + ruseValue; + target[splMonthKey] = (target[splMonthKey] ?? 0) + splValue; + // total 누적 + target.ruseTotal += ruseValue; + target.splTotal += splValue; + return acc; + }, []); + setGuidData(result); + }, [obj]); + const cellClick = (val: number | undefined, headId: string) => {}; + const setChGuidData = (data: splRuseWaterType[]) => { + if (data.length > 0) { + setUpdateData(data); } + }; - return( - <> - -
-
- -
-
-

{"○"+ obj.bdstNm + `(${obj.chckYmd})`}

+ const guidDataUpdate = () => { + const realGuideDetail = obj.guideDetails; - -
+ if (updateData === undefined || updateData.length === 0) return; + realGuideDetail.map((item: any) => { + const findObj = updateData.find( + (ch: any) => ch.utztnUsgCd === item.utztnUsgCd + ); - - { - cellClick(val, headId); - }} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } }> + const month = item.ym?.slice(4); - {nodeList} - + if (month === undefined || month === null) { + console.log("month ", month); + } + if (findObj) { + const ruseMonthKey = `ruse${month}` as keyof splRuseWaterType; + const splMonthKey = `spl${month}` as keyof splRuseWaterType; + if ( + findObj[ruseMonthKey] !== undefined && + findObj[splMonthKey] !== undefined + ) { + item.splyUswtrUtztnQnt = findObj[splMonthKey]; + item.ruseFcltUtztnQnt = findObj[ruseMonthKey]; - { - cellClick(val, headId); - }} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } }> - {nodeList} + return item; + } + } + }); + obj.guideDetails = realGuideDetail; - + rainChk.map((item: any) => { + if (item.chkgdnPk === obj.chkgdnPk) { + item.guideDetails = realGuideDetail; + } + }); + console.log("realGuideDetail", rainChk); - {type !=='RNB'? -
- { - cellClick(val, headId); - }} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } }> - {rswtnodeList} + rainChkGuidUpdate(obj); + }; - + return ( + <> +
+
+ +
+
+

+ {"○" + "" + `(${"11"})`} +

- { - cellClick(val, headId); - }} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } }> - {rswtnodeList} + +
- + + { + setChGuidData(data); + }} + /> - { - cellClick(val, headId); - }} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } }> - {rswtnodeList} + { + setChGuidData(data); + }} + /> - + {type !== "RNB" ? ( +
+ { + cellClick(val, headId); + }} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + > + {rswtnodeList} + - { - cellClick(val, headId); - }} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - } }> - {rswtnodeList} + { + cellClick(val, headId); + }} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + > + {rswtnodeList} + - -
- :<>} + { + cellClick(val, headId); + }} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + > + {rswtnodeList} + -
-
- - - - - ) - -} \ No newline at end of file + { + cellClick(val, headId); + }} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + > + {rswtnodeList} + +
+ ) : ( + <> + )} +
+
+ + ); +} diff --git a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx new file mode 100644 index 000000000..c38fc93d3 --- /dev/null +++ b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx @@ -0,0 +1,100 @@ +"use client"; +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; +import { useWrStore } from "@/app/store"; +import type { + rainChkZodType, + splRuseWaterType, +} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { + Input, + Table, + TableBody, + TableCell, + TableHeader, + TableRow, +} from "@common/components/ui"; +import { use, useEffect, useState } from "react"; + +export function GuideDetailsTable({ + chgRes, + headList, + type, + setChGuidData, +}: { + chgRes: splRuseWaterType[]; + headList: TableUpperProps[]; + type: string; + setChGuidData: (chgRes: splRuseWaterType[]) => void; +}) { + const { code, rainChkgdn } = useWrStore((state) => state); + const [guidData, setGuidData] = useState(); + + const nodeList = headMakeprfmnc(headList, rainChkgdn?.rainHeadNm); + + const handleChange = ( + rowIndex: number, + field: splRuseWaterType, + value: string | number + ) => { + if(Number(value) < 0 ||! Number(value)){ + value = 0; + }else{ + value = Number(value); + } + setGuidData((prevData) => + prevData?.map((row, index) => { + if (index === rowIndex) { + return { + ...row, + [field as any]: value, + }; + } + return row; + }) + ); + }; + const tableBody = (chgRes: splRuseWaterType[] | []) => { + return ( + <> + {chgRes.map((data, dataIndex) => ( + + {headList.map((head, headIndex) => ( + + + handleChange(dataIndex, head.id as any, e.target.value) + } + value={data[head.id as keyof splRuseWaterType] || ""} + /> + + ))} + + ))} + + ); + }; + useEffect(() => { + setGuidData(chgRes); + }, [chgRes]); + + + useEffect(() => { + setChGuidData(guidData??[] ); + + }, [guidData]); + + return ( + <> +
+ + {nodeList} + + {tableBody(guidData ?? [])} + +
+
+ + ); +} diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx new file mode 100644 index 000000000..f34efa467 --- /dev/null +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -0,0 +1,298 @@ +"use client"; +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; +import { useWrStore } from "@/app/store"; +import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { tableData } from "@/components/lib/func/commom"; +import { UiModal } from "@common/business_components/ui"; +import { + Checkbox, + Input, + Table, + TableBody, + TableCell, + TableHeader, + TableRow, +} from "@common/components/ui"; +import { useEffect, useState } from "react"; +import ChkgdModal from "../../../modal/chkgdModal/chkgdModal"; + +export const totalData = ( + makeTableData: any[], + headList: TableUpperProps[], + handleChange: ( + rowIndex: number, + field: keyof (typeof makeTableData)[0], + value: string | number + ) => void, + toggleSelection: (pk: number, checked: boolean) => void, + selectedIds: number[], + handleCellClick: (index: number, headId: string) => void +) => { + const mergeKeys = [ + "order", + "cityText", + "sggText", + "bdstNm", + "operMngCd", + "flowCheck", + "yearFee", + "rainDtnbaOpct", + "chckYmd", + ]; + + // rowspan된 셀 렌더링 여부 추적용 + const renderedMap = new Map>(); + return ( + <> + {makeTableData.map((row, rowIndex) => ( + + {headList.map((head) => { + const key = head.id; + const isMerged = head.rowSpan; + const value = row[key]; + + // 병합 대상이면 중복 렌더링 여부 판단 + if (isMerged) { + const renderedSet = renderedMap.get(key) ?? new Set(); + if (renderedSet.has(rowIndex)) return null; // 이미 렌더링된 셀은 skip + + const rowspan = row.rowspan ?? 1; + for (let i = 0; i < rowspan; i++) { + renderedSet.add(rowIndex + i); + } + renderedMap.set(key, renderedSet); + + return ( + + {key === "order" ? ( + + toggleSelection(row.chkgdnPk, checked === true) + } + > + ) : ( + value + )} + + ); + } + + // 기본 셀 + return ( + handleCellClick(rowIndex, head.id)} + > + {key === "totalSplyUswtrUtztnQnt" || + key === "totalRuseFcltUtztnQnt" || + key === "utztnUsgCd" ? ( + `${value}` + ) : ( + { + handleChange(rowIndex, head.id, e.target.value); + }} + value={value} + /> + )} + + ); + })} + + ))} + + ); +}; + +export const rightTableData = (rainChk: rainChkZodType[]) => { + // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 + const maketotal = rainChk.map((item: any) => { + const selectTotal = item.guideDetails.reduce((acc: any, cur: any) => { + const code = cur.utztnUsgCd; + const fk = cur.chkgdnFk; + + const key = `${fk}_${code}`; + acc[key] = acc[key] || { + totalSplyUswtrUtztnQnt: 0, + totalRuseFcltUtztnQnt: 0, + }; + + acc[key].totalSplyUswtrUtztnQnt += cur.splyUswtrUtztnQnt; + acc[key].totalRuseFcltUtztnQnt += cur.ruseFcltUtztnQnt; + + return acc; + }, {}); + + return selectTotal; // 모든 키: `${chkgdnFk}_${utztnUsgCd}` 형태 + }); + + // 2. 누계 정보들을 하나의 객체로 합치기 (평탄화) + const flatTotalMap = Object.assign({}, ...maketotal); + + // 3. rainyDetails에 누계 정보 주입 + + const updatedRainyDetails: any[] = []; + rainChk.forEach((rd: any) => { + const details = rd.rainyDetails.forEach((rainyItem: any) => { + const key = `${rainyItem.chkgdnFk}_${rainyItem.utztnUsgCd}`; + const totals = flatTotalMap[key] || { + totalSplyUswtrUtztnQnt: 0, + totalRuseFcltUtztnQnt: 0, + }; + + updatedRainyDetails.push({ + ...rd, + ...rd.building, + ...rainyItem, + ...totals, + rowspan: rd.rainyDetails?.length, + }); + }); + }); + + return updatedRainyDetails; +}; + +export default function RainChkgdTable({ + detailUp, +}: { + detailUp: (data: rainChkZodType[]) => void; +}) { + const { code, rainChkgdn } = useWrStore((state) => state); + const [makeTableData, setMakeTableData] = useState([]); + const { rainChk } = rainChkgdn; + const [selectedIds, setSelectedIds] = useState([]); + const [upRaintDetail, setUpRaintDetail] = useState([]); + const [isModal, setIsModal] = useState({open:false, data:{}}); + + const handleCellClick = (index: number, headId: string) => { + if ( + headId === "totalSplyUswtrUtztnQnt" || + headId === "totalRuseFcltUtztnQnt" + ) { + setIsModal({open:true, data: makeTableData[index]}); + } + }; + + const toggleSelection = (pk: number, checked: boolean) => { + setSelectedIds((prev) => + checked ? [...prev, pk] : prev.filter((item) => item !== pk) + ); + }; + const handleChange = ( + rowIndex: number, + field: keyof (typeof makeTableData)[0], + value: string | number + ) => { + setMakeTableData((prev) => + prev.map((row, idx) => + idx === rowIndex ? { ...row, [field]: value } : row + ) + ); + }; + + const nodeList = headMakeprfmnc( + rainChkgdn?.rainChkgdnHeadList, + rainChkgdn?.rainHeadNm + ); + + useEffect(() => { + const rainChg = rainChk.map((item: any) => { + const bud = tableData([item.building], { code }); + + return { + ...item, + ...bud[0], + rowspan: item.rainyDetails?.length, + }; + }); + + setMakeTableData(rightTableData(rainChg)); + }, [rainChk, code]); + + + + useEffect(() => { + const selectedData = makeTableData.filter((item) => + selectedIds.includes(item.chkgdnPk) + ); + if (selectedData.length > 1) { + const updateTableData = rainChk + .map((rc) => { + const newRainyDetail = rc.rainyDetails + .map((rd) => { + const findRain = selectedData.find( + (sd) => + rd.chkgdnFk === sd.chkgdnPk && rd.utztnUsgCd === sd.utztnUsgCd + ); + if (findRain != undefined) { + return { + ...rd, + ph: Number(findRain.ph), + trbt: Number(findRain.trbt), + grssClfg: Number(findRain.grssClfg), + etc: findRain.etc, + vltnDt: findRain.vltnDt, + vltnMttr: findRain.vltnMttr, + levyAmt: Number(findRain.levyAmt), + }; + } else { + return undefined; + } + }) + .filter(Boolean); + if (newRainyDetail[0] != undefined) { + return { + ...rc, + rainyDetails: newRainyDetail, + }; + } else { + return undefined; + } + }) + .filter(Boolean); + + setUpRaintDetail(updateTableData as rainChkZodType[]); + } + }, [makeTableData]); + + useEffect(() => { + detailUp(upRaintDetail); + }, [upRaintDetail]); + return ( + <> + + {nodeList} + + + {totalData( + makeTableData, + rainChkgdn.rainChkgdnHeadList, + handleChange, + toggleSelection, + selectedIds, + handleCellClick + )} + +
+ + { + setIsModal({ open:!open , data:{} }); + }} + bodyClass={"w-[80vw] max-w-none"} + body={} + > + + ); +} diff --git a/apps/wr/components/ui/table/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx similarity index 100% rename from apps/wr/components/ui/table/rswtChkgd/rswtChkgdTable.tsx rename to apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx diff --git a/apps/wr/components/ui/table/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/rainChkgd/rainChkgdTable.tsx deleted file mode 100644 index c663bf95b..000000000 --- a/apps/wr/components/ui/table/rainChkgd/rainChkgdTable.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client' - -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page"; -import { useWrStore } from "@/app/store"; -import { UiTable } from "@common/business_components/ui"; - -export default function RainChkgdTable() { - - const { code, rainChkgdn} = useWrStore((state) => state); - const nodeList = headMakeprfmnc(rainChkgdn?.rainChkgdnHeadList,rainChkgdn?.rainHeadNm ) ; - - - return( - - <> - {} } > - {nodeList} - - - ) - -} \ No newline at end of file diff --git a/packages/common/business_components/package.json b/packages/common/business_components/package.json index 5120980c2..1f02a708e 100644 --- a/packages/common/business_components/package.json +++ b/packages/common/business_components/package.json @@ -42,6 +42,7 @@ "recharts": "^2.15.1", "sonner": "^2.0.1", "tailwind-merge": "^3.0.1", + "xlsx": "^0.18.5", "zod": "^3.24.2" }, "devDependencies": { diff --git a/packages/common/business_components/src/ui/excel_download/index.tsx b/packages/common/business_components/src/ui/excel_download/index.tsx new file mode 100644 index 000000000..d1370b95c --- /dev/null +++ b/packages/common/business_components/src/ui/excel_download/index.tsx @@ -0,0 +1,16 @@ +import * as XLSX from 'xlsx'; + +type ExcelDownloadProps = { + data : JSON | JSON[]; + fileName : string; + sheetNameArray : string[]; +} + +export const downloadExcel = ({ data, fileName = new Date().getTime().toString()+'.xlsx', sheetNameArray = ["Sheet1"] }: ExcelDownloadProps) => { + const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); + //let buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }); + //XLSX.write(workbook, { bookType: "xlsx", type: "binary" }); + XLSX.writeFile(workbook, fileName+'.xlsx'); + }; \ No newline at end of file diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index c3022740d..e591be5b5 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -1,19 +1,21 @@ export * from "./chart"; export * from "./date_picker"; +export * from "./dialog_ui"; +export * from "./excel_download"; export * from "./file-upload"; export * from "./form"; export * from "./form_ui"; +export * from "./list_div"; +export * from "./main_content_div"; export * from "./scroll"; +export * from "./search_base_form"; export * from "./search_form"; +export * from "./search_form_left"; +export * from "./search_form_right"; export * from "./search_input"; export * from "./search_input_select"; export * from "./select"; -export * from "./table"; -export * from "./main_content_div"; -export * from "./title"; -export * from "./search_form_left"; -export * from "./search_form_right"; -export * from "./table_div"; -export * from "./list_div"; export * from "./tab"; -export * from "./dialog_ui" \ No newline at end of file +export * from "./table"; +export * from "./table_div"; +export * from "./title"; diff --git a/packages/common/business_components/src/ui/search_base_form/index.tsx b/packages/common/business_components/src/ui/search_base_form/index.tsx new file mode 100644 index 000000000..90ad0b05e --- /dev/null +++ b/packages/common/business_components/src/ui/search_base_form/index.tsx @@ -0,0 +1,140 @@ +import { Button } from "@common/components/ui"; +import { useCallback, useEffect, useState } from "react"; +import { SearchFormLeft, type EnvPartSelectDataType } from "../search_form_left"; +import { SearchFormRight } from "../search_form_right"; +import type { SelectDataType } from "../search_input_select"; +type SearchBaseType = { + leftChildren:React.ReactNode; + rightChildren:React.ReactNode; + selectSidoData?: SelectDataType[] | []; + selectSigunData?: SelectDataType[] | []; + selectRegionData?: SelectDataType[] | []; + selectUnitWaterShedData?: SelectDataType[] | []; + selectMiddleRegionData?: SelectDataType[] | []; + selectEnvPartData?: EnvPartSelectDataType[] | []; + queryClick:(returnType:ReturnType) => void; + excelClick:(returnType:ReturnType) => void; + initClick:() => void; + btnClass:string; + ref:React.RefObject; +} +export type ReturnType = { + partValue: string; + sidoValue: string; + sigunValue: string; + regionValue: string; + unitWaterShedValue: string; + middleRegionValue: string; + envPartValue: string; +} + + +function SearchBaseForm ({ + leftChildren, + rightChildren, + selectSidoData, + selectSigunData, + selectRegionData, + selectUnitWaterShedData, + selectMiddleRegionData, + selectEnvPartData, + btnClass, + queryClick, + excelClick, + initClick, + ref + }: SearchBaseType) { + const [partValue, setPartValue] = useState("A"); + const [sidoValue, setSidoValue] = useState("0"); + const [sigunValue, setSigunValue] = useState("0"); + const [regionValue, setRegionValue] = useState("0"); + const [untitWaterShedValue, setUntitWaterShedValue] = useState("0"); + const [middleRegionValue, setMiddleRegionValue] = useState("0"); + const [envPartValue, setEnvPartValue] = useState("0"); + const [resetTrigger, setResetTrigger] = useState(false); + const queryVal = () => { + console.log("조회버튼 클릭"); + queryClick({ + partValue: partValue, + sidoValue: sidoValue, + sigunValue: sigunValue, + regionValue: regionValue, + unitWaterShedValue: untitWaterShedValue, + middleRegionValue: middleRegionValue, + envPartValue: envPartValue, + }); + } + const initVal = useCallback(() => { + setResetTrigger(true); + initClick(); + }, [setResetTrigger, initClick]); + useEffect(() => { + if (resetTrigger) { + setResetTrigger(false); + } + }, [resetTrigger]); + const excelDownload = () => { + excelClick({ + partValue: partValue, + sidoValue: sidoValue, + sigunValue: sigunValue, + regionValue: regionValue, + unitWaterShedValue: untitWaterShedValue, + middleRegionValue: middleRegionValue, + envPartValue: envPartValue, + }) + }; + useEffect(() => { + if (ref && ref.current) { + const customRef = ref.current; + customRef.partValue = partValue; + customRef.sidoValue = sidoValue; + customRef.sigunValue = sigunValue; + customRef.regionValue = regionValue; + customRef.unitWaterShedValue = untitWaterShedValue; + customRef.middleRegionValue = middleRegionValue; + customRef.envPartValue = envPartValue; + } + }, [partValue, sidoValue, sigunValue, regionValue, untitWaterShedValue, middleRegionValue, envPartValue, ref]); + return ( +
+ + {leftChildren} + + + +
+ + +
+ {rightChildren} +
+
+ ) + } + + export { SearchBaseForm }; + \ No newline at end of file diff --git a/packages/common/business_components/src/ui/search_form_left/index.tsx b/packages/common/business_components/src/ui/search_form_left/index.tsx index 448f2df04..ec9e814f5 100644 --- a/packages/common/business_components/src/ui/search_form_left/index.tsx +++ b/packages/common/business_components/src/ui/search_form_left/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import type { SelectDataType } from '../search_input_select'; import { SelectBox } from '../select'; @@ -38,40 +38,44 @@ type SearchFormLeftProps = { setRtnEnvPartValue?: (value: string) => void; setRtnEnvPartSidoValue?: (value: string) => void; setRtnEnvPartSigunValue?: (value: string) => void; + resetTrigger?: boolean; } -type EnvPartSelectDataType = SelectDataType & { +export type EnvPartSelectDataType = SelectDataType & { adstDliStrCd: string, } const selectPartData:SelectDataType[] = [ - { text: "행정별", val: '0' }, - { text: "유역별", val: '01' }, - { text: "환경청별", val: '02' }, + { text: "행정별", val: 'A' }, + { text: "유역별", val: 'R' }, + { text: "환경청별", val: 'G' }, ]; -function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSigunValue, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue }: SearchFormLeftProps) { - const [partValue, setPartValue] = useState('0'); - const [showPart, setShowPart] = useState(''); +function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSigunValue, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false }: SearchFormLeftProps) { + /******************선택된 데이터******************/ + const [partValue, setPartValue] = useState('A'); + //행정별 시도 시군구 const [sidoValue, setSidoValue] = useState('0'); const [sigunValue, setSigunValue] = useState('0'); + //유역별 const [regionValue, setRegionValue] = useState('0'); const [unitWaterShedValue, setUnitWaterShedValue] = useState('0'); const [middleRegionValue, setMiddleRegionValue] = useState('0'); + //환경청별 시도 시군구 const [envPartValue, setEnvPartValue] = useState('0'); - const [envPartSidoValue, setEnvPartSidoValue] = useState('0'); - const [envPartSigunValue, setEnvPartSigunValue] = useState('0'); + // 환경청 + const [filteredEnvPartSigunDataSelected, setFilteredEnvPartSigunDataSelected] = useState([]); + /****************** 셀렉트 리스트 데이터. ******************/ + // 조회된 조건에 맞는 시도 시군 유역 const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]); const [filteredUnitWaterShedData, setFilteredUnitWaterShedData] = useState([{ text: "전체", val: '0' }]); const [filteredMiddleRegionData, setFilteredMiddleRegionData] = useState([{ text: "전체", val: '0' }]); - + // 조회된 조건에 맞는 환경청 시도 시군 const [filteredEnvPartData, setFilteredEnvPartData] = useState([{ text: "전체", val: '0', adstDliStrCd:'' }]); const [filteredEnvPartSidoData, setFilteredEnvPartSidoData] = useState([{ text: "전체", val: '0', adstDliStrCd:'' }]); const [filteredEnvPartSigunData, setFilteredEnvPartSigunData] = useState([{ text: "전체", val: '0' }]); - const [filteredEnvPartSigunDataSelected, setFilteredEnvPartSigunDataSelected] = useState([]); - // 시군구 세팅 const initializeSigunData = (sidoCd: string) => { if (sidoCd === '0') { @@ -153,12 +157,10 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel setRtnPartValue(val); } // 구분 - if(val == '01') { - setShowPart('01'); + if(val == 'R') { initializeMiddleRegionData('0'); initializeUnitWaterShedData('0'); - } else if(val == '02') { - setShowPart('02'); + } else if(val == 'G') { setFilteredEnvPartData([ { text: "전체", val: '0', adstDliStrCd:'' }, ...selectEnvPartData.filter((item: EnvPartSelectDataType) => item.val !== null && item.adstDliStrCd !== '') @@ -166,7 +168,6 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel setEnvPartValue('0'); initializeCityDataByEnvPartSido('0'); } else { - setShowPart('0'); initializeSigunData('0'); onSelectValue(selectSigunData[0]?.val || '0', 'sigun'); } @@ -224,7 +225,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel onSelectValue(filteredEnvPartSidoData[0]?.val || '0', 'envPartSido'); break; case 'envPartSido' : - setEnvPartSidoValue(val); + setSidoValue(val); if (setRtnEnvPartSidoValue) { setRtnEnvPartSidoValue(val); } @@ -232,29 +233,68 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel onSelectValue(filteredEnvPartSigunData[0]?.val || '0', 'envPartSigun'); break; case 'envPartSigun' : - setEnvPartSigunValue(val); + setSigunValue(val); if (setRtnEnvPartSigunValue) { setRtnEnvPartSigunValue(val); } break; } } - + + // 리셋 함수 + const resetAllValues = () => { + setPartValue('A'); + setSidoValue('0'); + setSigunValue('0'); + setRegionValue('0'); + setUnitWaterShedValue('0'); + setMiddleRegionValue('0'); + setEnvPartValue('0'); + + setFilteredSigunData([{ text: "전체", val: '0' }]); + setFilteredUnitWaterShedData([{ text: "전체", val: '0' }]); + setFilteredMiddleRegionData([{ text: "전체", val: '0' }]); + setFilteredEnvPartData([{ text: "전체", val: '0', adstDliStrCd: '' }]); + setFilteredEnvPartSidoData([{ text: "전체", val: '0', adstDliStrCd: '' }]); + setFilteredEnvPartSigunData([{ text: "전체", val: '0' }]); + + if (setRtnPartValue) setRtnPartValue('A'); + if (setRtnSidoValue) setRtnSidoValue('0'); + if (setRtnSigunValue) setRtnSigunValue('0'); + if (setRtnRegionValue) setRtnRegionValue('0'); + if (setRtnUnitWaterShedValue) setRtnUnitWaterShedValue('0'); + if (setRtnMiddleRegionValue) setRtnMiddleRegionValue('0'); + if (setRtnEnvPartValue) setRtnEnvPartValue('0'); + if (setRtnEnvPartSidoValue) setRtnEnvPartSidoValue('0'); + if (setRtnEnvPartSigunValue) setRtnEnvPartSigunValue('0'); + }; + + // 리셋 트리거 변경 감지 + useEffect(() => { + if (resetTrigger) { + resetAllValues(); + // 리셋 후 트리거를 false로 설정 + if (setRtnPartValue) { + setRtnPartValue('0'); + } + } + }, [resetTrigger]); + return ( isShowPart ? (
onSelectValue(val.toString(), 'part')} value={partValue} selectClass={undefined}/> - {showPart === '01' ? ( + {partValue === 'R' ? ( <> onSelectValue(val.toString(), 'region')} value={regionValue} selectClass={undefined}/> onSelectValue(val.toString(), 'unitWaterShed')} value={unitWaterShedValue} selectClass={undefined}/> onSelectValue(val.toString(), 'middleRegion')} value={middleRegionValue} selectClass={undefined}/> - ) : showPart === '02' ? ( + ) : partValue === 'G' ? ( <> onSelectValue(val.toString(), 'envPart')} value={envPartValue} selectClass={undefined}/> - onSelectValue(val.toString(), 'envPartSido')} value={envPartSidoValue} selectClass={undefined}/> - onSelectValue(val.toString(), 'envPartSigun')} value={envPartSigunValue} selectClass={undefined}/> + onSelectValue(val.toString(), 'envPartSido')} value={sidoValue} selectClass={undefined}/> + onSelectValue(val.toString(), 'envPartSigun')} value={sigunValue} selectClass={undefined}/> ) : ( <> diff --git a/packages/common/business_components/src/ui/search_form_left/searchFormLeft.md b/packages/common/business_components/src/ui/search_form_left/searchFormLeft.md index 18b95b13f..04531c27f 100644 --- a/packages/common/business_components/src/ui/search_form_left/searchFormLeft.md +++ b/packages/common/business_components/src/ui/search_form_left/searchFormLeft.md @@ -3,45 +3,41 @@ #### 1. 컴포넌트 호출방법 ```js import { SearchFormLeft } from "@common/business_components"; + ..... - { - setPartValue(value); - }} - setRtnSidoValue={(value) => { - setSidoValue(value); - }} - setRtnSigunValue={(value) => { - setSigunValue(value); - }} - setRtnRegionValue={(value) => { - setRegionValue(value); - }} - setRtnUnitWaterShedValue={(value) => { - setUntitWaterShedValue(value); - }} - setRtnMiddleRegionValue={(value) => { - setMiddleRegionValue(value); - }} - setRtnEnvPartValue={(value) => { - setEnvPartValue(value); - }} - setRtnEnvPartSidoValue={(value) => { - setEnvPartSidoValue(value); - }} - setRtnEnvPartSigunValue={(value) => { - setEnvPartSigunValue(value); - }} + +// state 지정 +const [partValue, setPartValue] = useState("0"); +const [sidoValue, setSidoValue] = useState("0"); +const [sigunValue, setSigunValue] = useState("0"); +const [regionValue, setRegionValue] = useState("0"); +const [untitWaterShedValue, setUntitWaterShedValue] = useState("0"); +const [middleRegionValue, setMiddleRegionValue] = useState("0"); +const [envPartValue, setEnvPartValue] = useState("0"); +const [envPartSidoValue, setEnvPartSidoValue] = useState("0"); +const [envPartSigunValue, setEnvPartSigunValue] = useState("0"); +const [resetTrigger, setResetTrigger] = useState(false); +..... + + + ```   ㆍisShowPart : 검색단에서 구분(행정별,유역별,환경청별) 세팅 여부(보일 경우 : Y, 아닐경우 : N 혹은 미첨부) @@ -73,7 +69,11 @@ import { SearchFormLeft } from "@common/business_components";   ㆍsetRtnEnvPartSidoValue : 선택한 환경청의 시도 set함수(조회시 페이지에서 사용) -  ㆍsetRtnEnvPartSidoValue : 선택한 환경청 시도의 시군구 set함수(조회시 페이지에서 사용) +  ㆍsetRtnEnvPartSigunValue : 선택한 환경청 시도의 시군구 set함수(조회시 페이지에서 사용) + +  ㆍresetTrigger : 초기화 trigger 변수 + + #### 2. 세팅방법 ```js @@ -318,8 +318,58 @@ const [middleRegionValue, setMiddleRegionValue] = useState("0"); const [envPartValue, setEnvPartValue] = useState("0"); const [envPartSidoValue, setEnvPartSidoValue] = useState("0"); const [envPartSigunValue, setEnvPartSigunValue] = useState("0"); +const [resetTrigger, setResetTrigger] = useState(false); - + +const resetVal = () => { + console.log('=== 초기화 ==='); + console.log(selectSidoData); + + // SelectBox 초기화 - 각 selectArray의 첫 번째 옵션 값 사용 + const initialPartValue = selectPartData[0]?.val || "0"; + const initialSidoValue = selectSidoData[0]?.val || "0"; + const initialSigunValue = selectSigunData[0]?.val || "0"; + const initialRegionValue = selectRegionData[0]?.val || "0"; + const initialUnitWaterShedValue = selectUnitWaterShedData[0]?.val || "0"; + const initialMiddleRegionValue = selectMiddleRegionData[0]?.val || "0"; + const initialEnvPartValue = selectEnvPartData[0]?.val || "0"; + const initialEnvPartSidoValue = selectEnvPartData[0]?.val || "0"; + const initialEnvPartSigunValue = selectEnvPartData[0]?.val || "0"; + + // 상태값 설정 + setPartValue(initialPartValue); + setSidoValue(initialSidoValue); + setSigunValue(initialSigunValue); + setRegionValue(initialRegionValue); + setUntitWaterShedValue(initialUnitWaterShedValue); + setMiddleRegionValue(initialMiddleRegionValue); + setEnvPartValue(initialEnvPartValue); + setEnvPartSidoValue(initialEnvPartSidoValue); + setEnvPartSigunValue(initialEnvPartSigunValue); + + // 리셋 후 트리거를 false로 설정 + setTimeout(() => { + setResetTrigger(false); + }, 0); + } + +// 조회 함수 +const chkVal = useCallback(() => { + setResetPage(true); + // 조회 funciton + searchFcltyQltyList(1); +}, [searchFcltyQltyList]); + +// 그리드 page 넘어갈 때 필요한 함수 +const handlePageChange = useCallback((page: number) => { + setResetPage(false); + searchFcltyQltyList(page); +}, [searchFcltyQltyList]); + +// 테이블 호출 컴포넌트 + index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upHeadList2} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange}> + + ``` diff --git a/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx b/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx new file mode 100644 index 000000000..cedc0bd7f --- /dev/null +++ b/packages/common/business_components/src/ui/table/HeadMakeColSpan.tsx @@ -0,0 +1,52 @@ +import { TableHead, TableRow } from "@common/components/ui"; + +interface TableUpperProps { + id: string; + title: string; + upName?: string; + upSequnce?: number; + row? : number; + rowSpan?: number; + colSpan?: number; +} + +const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => { + const maxRow = upHeadList.reduce((max, head) => Math.max(max, head.row || 0), 0); + return ( + <> + {Array.from({ length: maxRow + 1 }, (_, rowIndex) => ( + + {upHeadList.map((head: TableUpperProps) => { + if (head.row === rowIndex) { + return ( + + {head.title} + + ); + }else{ + return ( + + {head.title} + + ); + } + })} + + ))} + + ); +} + +export { HeadMakeColSpan }; diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index f6da92d7f..60c457544 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -1,18 +1,19 @@ -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components"; +import { Table, TableBody, TableCell, TableHeader, TableRow } from "@common/components"; import { useEffect, useState } from "react"; +import { HeadMakeColSpan } from "./HeadMakeColSpan"; import UiPageNations from "./uiPageNations"; type UiTableProps = { headName: React.ReactNode | undefined; - tableData: { [key: string]: string | number | boolean | object}[]; + tableData: { [key: string]:any}[]; headlist: UiHeadProps[]; pageSize: number; total: number; - children: React.ReactNode | undefined; cellClick : ((index:number|undefined, headId:string)=>void )| undefined; onPageChange: (page: number) => void; className?: string; resetPageNo?: boolean; + children?: React.ReactNode | undefined; } type UiHeadProps = { @@ -21,7 +22,7 @@ type UiHeadProps = { align?: string; } -export function UiTable({ tableData, headlist, pageSize, total, children, headName, cellClick, onPageChange, className = '', resetPageNo = false }: UiTableProps) { +export function UiTable({ tableData, headlist, pageSize, total, headName, children, cellClick, onPageChange, className = '', resetPageNo = false }: UiTableProps) { const [cur, setCur] = useState(1); const [idx, setIdx] = useState(-1); @@ -43,7 +44,7 @@ export function UiTable({ tableData, headlist, pageSize, total, children, headNa setIdx(index); } }; - + return ( <> {headName ?
@@ -51,31 +52,32 @@ export function UiTable({ tableData, headlist, pageSize, total, children, headNa
: <>}
+ {children?children: - {children ? <>{children} : - {headlist?.map((head) => ( - {head.title} - ))} - } - - - {tableData?.map((el: { [key: string]: string | number | boolean | object}, index) => ( - - {headlist?.map((head) => ( - handleCellClick(index, head.id)} - key={head.id + index} - > - {String(el[head.id] ?? '')} - - ))} - - ))} - + {children ? children : } + + } + + + {tableData.length > 0 ? tableData?.map((el: { [key: string]: any}, index) => ( + + {headlist?.map((head) => ( + head.id && head.id.length > 1 && ( + handleCellClick(index, head.id)} + key={`cell-${head.id}-${index}`} + > + {typeof el[head.id] === 'number' ? String(el[head.id]).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : String(el[head.id] ?? '')} + + ) + ))} + + )) : <>} +
{total <= 0 ? <> : }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82f59a6cd..62c43bac1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -266,6 +266,9 @@ importers: tailwind-merge: specifier: ^3.0.1 version: 3.0.2 + xlsx: + specifier: ^0.18.5 + version: 0.18.5 zod: specifier: ^3.24.2 version: 3.24.2 @@ -325,7 +328,7 @@ importers: specifier: ^15.14.0 version: 15.15.0 postcss: - specifier: ^8.5.1 + specifier: ^8.5.3 version: 8.5.3 prettier: specifier: ^3.4.2 @@ -3853,6 +3856,11 @@ packages: hasBin: true dev: true + /adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + dev: false + /ajv-formats@2.1.1(ajv@8.17.1): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -4236,6 +4244,14 @@ packages: /caniuse-lite@1.0.30001701: resolution: {integrity: sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==} + /cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + dev: false + /chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} @@ -4325,6 +4341,11 @@ packages: engines: {node: '>=6'} dev: false + /codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + dev: false + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -4402,6 +4423,12 @@ packages: typescript: 5.6.3 dev: true + /crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: false + /cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -5516,6 +5543,11 @@ packages: mime-types: 2.1.35 dev: false + /frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + dev: false + /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true @@ -7571,6 +7603,13 @@ packages: whatwg-url: 7.1.0 dev: true + /ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + dependencies: + frac: 1.1.2 + dev: false + /stable-hash@0.0.4: resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} dev: true @@ -8535,11 +8574,21 @@ packages: dependencies: isexe: 2.0.0 + /wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + dev: false + /word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} dev: true + /word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + dev: false + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -8569,6 +8618,20 @@ packages: optional: true dev: true + /xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + dev: false + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'}