물재이용 사례관리 엑셀 등록 유효성 검사 및 저장 로직 변경
This commit is contained in:
@@ -6,18 +6,18 @@ import { excelDownload, getCity } from "@/components/lib/func/commom";
|
||||
import RuseCaseMngExcel from "@/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal";
|
||||
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
|
||||
import {
|
||||
ContentsDiv,
|
||||
filePickedBlobArray,
|
||||
SearchDiv,
|
||||
SearchFormLeft,
|
||||
SearchFormRight,
|
||||
SearchInput,
|
||||
SelectBox,
|
||||
Title,
|
||||
UiModal,
|
||||
UiTable,
|
||||
type SelectDataType,
|
||||
type SheetParameter,
|
||||
ContentsDiv,
|
||||
filePickedBlobArray,
|
||||
SearchDiv,
|
||||
SearchFormLeft,
|
||||
SearchFormRight,
|
||||
SearchInput,
|
||||
SelectBox,
|
||||
Title,
|
||||
UiModal,
|
||||
UiTable,
|
||||
type SelectDataType,
|
||||
type SheetParameter,
|
||||
} from "@common/business_components/ui";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import { Button, Label } from "@common/components/ui";
|
||||
@@ -26,277 +26,294 @@ import toast, { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function RuseCaseMng() {
|
||||
const { code, ruseCaseMng, selectRuseCaseMng, ruseCaseMngInit } = useWrStore((state) => state);
|
||||
const { ruseCaseMngList, status, count, excelList } = ruseCaseMng;
|
||||
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>([]);
|
||||
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
|
||||
const { code, ruseCaseMng, selectRuseCaseMng, ruseCaseMngInit } = useWrStore(
|
||||
(state) => state
|
||||
);
|
||||
const { ruseCaseMngList, status, count, excelList } = ruseCaseMng;
|
||||
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>([]);
|
||||
const [objSearch, setObjSearch] = useState<objSearchType>({
|
||||
sgg: "",
|
||||
city: "",
|
||||
});
|
||||
|
||||
const [sidoCd, setSidoCd] = useState<string>("");
|
||||
const [sigunguCd, setSigunguCd] = useState<string>("");
|
||||
// const [selectUtz, setSelectUtz] = useState<string[] | []>(["조경용수"]);
|
||||
const [selectUtz, setSelectUtz] = useState<string>("");
|
||||
const [name, setName] = useState<string>("");
|
||||
const [resetPage, isResetPage] = useState(false);
|
||||
const { t } = useTranslation('base');
|
||||
const [sidoCd, setSidoCd] = useState<string>("");
|
||||
const [sigunguCd, setSigunguCd] = useState<string>("");
|
||||
// const [selectUtz, setSelectUtz] = useState<string[] | []>(["조경용수"]);
|
||||
const [selectUtz, setSelectUtz] = useState<string>("");
|
||||
const [name, setName] = useState<string>("");
|
||||
const [resetPage, isResetPage] = useState(false);
|
||||
const { t } = useTranslation("base");
|
||||
|
||||
// 물재이용사례 조회
|
||||
const searchRuseCaseMng = async (isExcel: boolean, pageNo: number, pageSize: number) => {
|
||||
await selectRuseCaseMng(
|
||||
isExcel,
|
||||
pageNo,
|
||||
pageSize,
|
||||
sidoCd ?? "",
|
||||
sigunguCd ?? "",
|
||||
selectUtz ?? "",
|
||||
name ?? ""
|
||||
);
|
||||
// 엑셀 등록 모달
|
||||
const [isExcelOpen, setIsExcelOpen] = useState<boolean>(false);
|
||||
|
||||
// 물재이용사례 조회
|
||||
|
||||
useEffect(() => {
|
||||
ruseCaseMngInit();
|
||||
}, []);
|
||||
|
||||
// 시도 선택
|
||||
const getSelCity = (val: string | number) => {
|
||||
const cityValue = String(val);
|
||||
const cityText = code.cityCd.find(
|
||||
(item: { val: string; text: string }) => item.val === cityValue
|
||||
)?.text;
|
||||
setSidoCd(cityText || "");
|
||||
const data = getCity(cityValue, code.sggCd);
|
||||
setSelectSgg(data);
|
||||
setObjSearch({ city: cityValue, sgg: "" });
|
||||
};
|
||||
|
||||
// 시군구 선택
|
||||
const getSgg = (val: string | number) => {
|
||||
const sggValue = String(val);
|
||||
const sggText = selectSgg?.find(
|
||||
(item: { val: string; text: string }) => item.val === sggValue
|
||||
)?.text;
|
||||
setSigunguCd(sggText || "");
|
||||
setObjSearch({ ...objSearch, sgg: String(val) });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (excelList !== undefined && excelList.length === 0) {
|
||||
toast.error(t("excelDownErrMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
ruseCaseMngInit();
|
||||
}, [])
|
||||
|
||||
// 시도 선택
|
||||
const getSelCity = (val: string | number) => {
|
||||
const cityValue = String(val);
|
||||
const cityText = code.cityCd.find((item: { val: string; text: string }) => item.val === cityValue)?.text;
|
||||
setSidoCd(cityText || "");
|
||||
const data = getCity(cityValue, code.sggCd);
|
||||
setSelectSgg(data);
|
||||
setObjSearch({ city: cityValue, sgg: "" });
|
||||
};
|
||||
|
||||
// 시군구 선택
|
||||
const getSgg = (val: string | number) => {
|
||||
const sggValue = String(val);
|
||||
const sggText = selectSgg?.find((item: { val: string; text: string }) => item.val === sggValue)?.text;
|
||||
setSigunguCd(sggText || "");
|
||||
setObjSearch({ ...objSearch, sgg: String(val) });
|
||||
};
|
||||
|
||||
// 엑셀 등록 모달
|
||||
const [isExcelOpen, setIsExcelOpen] = useState<{
|
||||
isModal: boolean;
|
||||
}>({ isModal: false });
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (excelList !== undefined && excelList.length === 0) {
|
||||
toast.error(t('excelDownErrMsg'));
|
||||
return;
|
||||
}
|
||||
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
// 받은 파일 바인너리 처리
|
||||
const blobRet = await response.arrayBuffer();
|
||||
if(excelList){
|
||||
const excelData1 = excelList.map((item) => {
|
||||
return [
|
||||
item.ruseBizNm,
|
||||
item.bizBgngDate,
|
||||
item.bizEndDate,
|
||||
item.splyFcltKnd,
|
||||
item.splyFcltNm,
|
||||
item.splyFcltCpct,
|
||||
item.dmdFcltNm,
|
||||
item.dmdFcltAddr,
|
||||
item.ruseFcltCpct,
|
||||
item.ruseFcltPplLen,
|
||||
item.ruseFcltUsg,
|
||||
item.ruseFcltSplyCpct,
|
||||
item.ruseFcltPrcsMsrc,
|
||||
item.grnteWqUsg,
|
||||
item.grnteWqGrssClfg,
|
||||
item.grnteWqCombResdch,
|
||||
item.grnteWqTrbt,
|
||||
item.grnteWqBod,
|
||||
item.grnteWqSmll,
|
||||
item.grnteWqCrmty,
|
||||
item.grnteWqTn,
|
||||
item.grnteWqTp,
|
||||
item.grnteWqPh,
|
||||
item.grnteWqClIonQnt,
|
||||
item.grnteWqCndctStat,
|
||||
item.grnteWqRmrk,
|
||||
item.reqBizGrssCst,
|
||||
item.reqBizReuseFcltCst,
|
||||
item.reqBizPplCst,
|
||||
item.reqBizArchCst,
|
||||
item.reqBizMchnCst,
|
||||
item.reqBizMtrngCst,
|
||||
item.reqBizGisCst,
|
||||
item.reqBizCctvCst,
|
||||
item.reqBizCmcnCst,
|
||||
item.reqBizWstCst,
|
||||
item.reqBizDesignCst,
|
||||
item.reqBizSpvsCst,
|
||||
item.reqBizSbsdCst,
|
||||
item.reqBizEtc,
|
||||
item.prcmPlanGrssCst,
|
||||
item.prcmPlanNlep,
|
||||
item.prcmPlanLcep,
|
||||
item.prcmPlanBrdnCst,
|
||||
item.prcmPlanEcqrRt,
|
||||
item.clclnGrssCst,
|
||||
item.clclnNlep,
|
||||
item.clclnLcep,
|
||||
item.clclnBrdnCst,
|
||||
item.clclnEcqrRt,
|
||||
];
|
||||
});
|
||||
|
||||
const sheetParameter: SheetParameter[] = [
|
||||
{
|
||||
data: excelData1,
|
||||
headerNum: 2,
|
||||
headerRange: 'A1:AX1',
|
||||
sheetName: '물재이용사례',
|
||||
startCol: 'A'
|
||||
}
|
||||
];
|
||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||
await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter);
|
||||
}
|
||||
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
// 받은 파일 바인너리 처리
|
||||
const blobRet = await response.arrayBuffer();
|
||||
if (excelList) {
|
||||
const excelData1 = excelList.map((item) => {
|
||||
return [
|
||||
item.ruseBizNm,
|
||||
item.bizBgngDate,
|
||||
item.bizEndDate,
|
||||
item.splyFcltKnd,
|
||||
item.splyFcltNm,
|
||||
item.splyFcltCpct,
|
||||
item.dmdFcltNm,
|
||||
item.dmdFcltAddr,
|
||||
item.ruseFcltCpct,
|
||||
item.ruseFcltPplLen,
|
||||
item.ruseFcltUsg,
|
||||
item.ruseFcltSplyCpct,
|
||||
item.ruseFcltPrcsMsrc,
|
||||
item.grnteWqUsg,
|
||||
item.grnteWqGrssClfg,
|
||||
item.grnteWqCombResdch,
|
||||
item.grnteWqTrbt,
|
||||
item.grnteWqBod,
|
||||
item.grnteWqSmll,
|
||||
item.grnteWqCrmty,
|
||||
item.grnteWqTn,
|
||||
item.grnteWqTp,
|
||||
item.grnteWqPh,
|
||||
item.grnteWqClIonQnt,
|
||||
item.grnteWqCndctStat,
|
||||
item.grnteWqRmrk,
|
||||
item.reqBizGrssCst,
|
||||
item.reqBizReuseFcltCst,
|
||||
item.reqBizPplCst,
|
||||
item.reqBizArchCst,
|
||||
item.reqBizMchnCst,
|
||||
item.reqBizMtrngCst,
|
||||
item.reqBizGisCst,
|
||||
item.reqBizCctvCst,
|
||||
item.reqBizCmcnCst,
|
||||
item.reqBizWstCst,
|
||||
item.reqBizDesignCst,
|
||||
item.reqBizSpvsCst,
|
||||
item.reqBizSbsdCst,
|
||||
item.reqBizEtc,
|
||||
item.prcmPlanGrssCst,
|
||||
item.prcmPlanNlep,
|
||||
item.prcmPlanLcep,
|
||||
item.prcmPlanBrdnCst,
|
||||
item.prcmPlanEcqrRt,
|
||||
item.clclnGrssCst,
|
||||
item.clclnNlep,
|
||||
item.clclnLcep,
|
||||
item.clclnBrdnCst,
|
||||
item.clclnEcqrRt,
|
||||
];
|
||||
});
|
||||
|
||||
const sheetParameter: SheetParameter[] = [
|
||||
{
|
||||
data: excelData1,
|
||||
headerNum: 2,
|
||||
headerRange: "A1:AX1",
|
||||
sheetName: "물재이용사례",
|
||||
startCol: "A",
|
||||
},
|
||||
];
|
||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||
await filePickedBlobArray(blobRet, "물재이용사례현황", sheetParameter);
|
||||
}
|
||||
});
|
||||
}, [excelList]);
|
||||
|
||||
}, [excelList])
|
||||
|
||||
// 양식받기
|
||||
const sampleDownLoad = () => {
|
||||
excelDownload(
|
||||
[[]],
|
||||
"물재이용사례 관리 등록양식",
|
||||
"sample_ruseCaseMng.xlsx",
|
||||
"A1:AX1",
|
||||
2
|
||||
);
|
||||
useEffect(() => {
|
||||
if (status === 200) {
|
||||
setIsExcelOpen(false);
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 200) {
|
||||
setIsExcelOpen({ isModal: false });
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContentsDiv>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="col-span-4">
|
||||
<Title title={"물재이용사례 관리"} />
|
||||
<SearchDiv>
|
||||
<SearchFormLeft>
|
||||
<div className="col-span-8 flex flex-row items-center">
|
||||
<SelectBox
|
||||
className="col-span-2 w-1/3 h-full text-2xl"
|
||||
label="시도"
|
||||
selectClass={""}
|
||||
selectArray={code.cityCd || []}
|
||||
onSelectValue={getSelCity}
|
||||
/>
|
||||
<SelectBox
|
||||
className="col-span-2 w-1/3 h-full text-2xl ml-4"
|
||||
label="시군구"
|
||||
selectClass={""}
|
||||
selectArray={selectSgg || []}
|
||||
onSelectValue={getSgg}
|
||||
/>
|
||||
<SelectBox
|
||||
className="col-span-2 w-1/3 h-full text-2xl ml-4"
|
||||
label="용도"
|
||||
selectClass={""}
|
||||
selectArray={ruseUtzType}
|
||||
onSelectValue={(val) => {
|
||||
if (val) setSelectUtz(String(val));
|
||||
}}
|
||||
value={selectUtz || ruseUtzType[0]?.val}
|
||||
/>
|
||||
<Label className="w-28 text-xl ml-4 mr-6">
|
||||
{"수요처명"}
|
||||
</Label>
|
||||
<SearchInput
|
||||
className={"col-span-2 w-1/3 text-2xl"}
|
||||
label=""
|
||||
textValue={name}
|
||||
setText={(e) => {
|
||||
setName(e);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</SearchFormLeft>
|
||||
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2">
|
||||
<div className="space-y">
|
||||
<div className="flex flex-row space-x-2">
|
||||
<Button size={"sm"} onClick={() => {
|
||||
searchRuseCaseMng(false, 1, 10);
|
||||
isResetPage(true);
|
||||
}}>
|
||||
조회
|
||||
</Button>
|
||||
<Button size={"sm"} onClick={() => { setIsExcelOpen({ isModal: true }); }}>
|
||||
엑셀등록
|
||||
</Button>
|
||||
<Button size={"sm"} onClick={() => {
|
||||
selectRuseCaseMng(
|
||||
true,
|
||||
1,
|
||||
count,
|
||||
sidoCd ?? "",
|
||||
sigunguCd ?? "",
|
||||
selectUtz ?? "",
|
||||
name ?? ""
|
||||
);
|
||||
// download()
|
||||
|
||||
|
||||
}} className={"green"}>
|
||||
다운로드
|
||||
</Button>
|
||||
<Button size={"sm"} onClick={() => { sampleDownLoad() }}>
|
||||
양식받기
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</SearchFormRight>
|
||||
</SearchDiv>
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<ContentsDiv>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="col-span-4">
|
||||
<Title title={"물재이용사례 관리"} />
|
||||
<SearchDiv>
|
||||
<SearchFormLeft>
|
||||
<div className="col-span-8 flex flex-row items-center">
|
||||
<SelectBox
|
||||
className="col-span-2 w-1/3 h-full text-2xl"
|
||||
label="시도"
|
||||
selectClass={""}
|
||||
selectArray={code.cityCd || []}
|
||||
onSelectValue={getSelCity}
|
||||
/>
|
||||
<SelectBox
|
||||
className="col-span-2 w-1/3 h-full text-2xl ml-4"
|
||||
label="시군구"
|
||||
selectClass={""}
|
||||
selectArray={selectSgg || []}
|
||||
onSelectValue={getSgg}
|
||||
/>
|
||||
<SelectBox
|
||||
className="col-span-2 w-1/3 h-full text-2xl ml-4"
|
||||
label="용도"
|
||||
selectClass={""}
|
||||
selectArray={ruseUtzType}
|
||||
onSelectValue={(val) => {
|
||||
if (val) setSelectUtz(String(val));
|
||||
}}
|
||||
value={selectUtz || ruseUtzType[0]?.val}
|
||||
/>
|
||||
<Label className="w-28 text-xl ml-4 mr-6">{"수요처명"}</Label>
|
||||
<SearchInput
|
||||
className={"col-span-2 w-1/3 text-2xl"}
|
||||
label=""
|
||||
textValue={name}
|
||||
setText={(e) => {
|
||||
setName(e);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-6 gap-4">
|
||||
<div className="col-span-6">
|
||||
<ListDiv className="overflow-x-auto">
|
||||
<div className="w-[350%]">
|
||||
<UiTable
|
||||
headName={"물재이용사례 현황"}
|
||||
tableData={ruseCaseMngList}
|
||||
headlist={ruseCaseMng.ruseHeadList}
|
||||
pageSize={20}
|
||||
total={count}
|
||||
cellClick={undefined}
|
||||
onPageChange={(pageNo: number) => {
|
||||
searchRuseCaseMng(false, pageNo, 10);
|
||||
isResetPage(false)
|
||||
}}
|
||||
resetPageNo={resetPage}
|
||||
/>
|
||||
</div>
|
||||
</ListDiv>
|
||||
</div>
|
||||
</SearchFormLeft>
|
||||
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2">
|
||||
<div className="space-y">
|
||||
<div className="flex flex-row space-x-2">
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
selectRuseCaseMng(
|
||||
false,
|
||||
1,
|
||||
10,
|
||||
sidoCd ?? "",
|
||||
sigunguCd ?? "",
|
||||
selectUtz ?? "",
|
||||
name ?? ""
|
||||
);
|
||||
|
||||
isResetPage(true);
|
||||
}}
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
setIsExcelOpen(true);
|
||||
}}
|
||||
>
|
||||
엑셀등록
|
||||
</Button>
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
selectRuseCaseMng(
|
||||
true,
|
||||
1,
|
||||
count,
|
||||
sidoCd ?? "",
|
||||
sigunguCd ?? "",
|
||||
selectUtz ?? "",
|
||||
name ?? ""
|
||||
);
|
||||
// download()
|
||||
}}
|
||||
className={"green"}
|
||||
>
|
||||
다운로드
|
||||
</Button>
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
excelDownload(
|
||||
[[]],
|
||||
"물재이용사례 관리 등록양식",
|
||||
"sample_ruseCaseMng.xlsx",
|
||||
"A1:AX1",
|
||||
2
|
||||
);
|
||||
}}
|
||||
>
|
||||
양식받기
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ContentsDiv>
|
||||
<Toaster position="top-center" />
|
||||
{/* 엑셀 등록 모달 */}
|
||||
<UiModal
|
||||
open={isExcelOpen.isModal}
|
||||
onOpenChange={() => {
|
||||
setIsExcelOpen({ isModal: !isExcelOpen.isModal })
|
||||
}}
|
||||
bodyClass={"w-[35vw] max-w-none"}
|
||||
body={<RuseCaseMngExcel />}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
</SearchFormRight>
|
||||
</SearchDiv>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-6 gap-4">
|
||||
<div className="col-span-6">
|
||||
<ListDiv className="overflow-x-auto">
|
||||
<div className="w-[350%]">
|
||||
<UiTable
|
||||
headName={"물재이용사례 현황"}
|
||||
tableData={ruseCaseMngList}
|
||||
headlist={ruseCaseMng.ruseHeadList}
|
||||
pageSize={20}
|
||||
total={count}
|
||||
cellClick={undefined}
|
||||
onPageChange={(pageNo: number) => {
|
||||
selectRuseCaseMng(
|
||||
false,
|
||||
pageNo,
|
||||
10,
|
||||
sidoCd ?? "",
|
||||
sigunguCd ?? "",
|
||||
selectUtz ?? "",
|
||||
name ?? ""
|
||||
);
|
||||
isResetPage(false);
|
||||
}}
|
||||
resetPageNo={resetPage}
|
||||
/>
|
||||
</div>
|
||||
</ListDiv>
|
||||
</div>
|
||||
</div>
|
||||
</ContentsDiv>
|
||||
<Toaster position="top-center" />
|
||||
{/* 엑셀 등록 모달 */}
|
||||
<UiModal
|
||||
open={isExcelOpen}
|
||||
onOpenChange={() => {
|
||||
setIsExcelOpen(!isExcelOpen );
|
||||
}}
|
||||
bodyClass={"w-[35vw] max-w-none"}
|
||||
body={<RuseCaseMngExcel setIsExcelOpen={setIsExcelOpen} />}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,93 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const reUseCaseExcel = z.object({
|
||||
file: z.any()
|
||||
file: z.any(),
|
||||
});
|
||||
|
||||
type nameMap = {
|
||||
[key: string]: string;
|
||||
export interface ruseCaseMngExcelProps {
|
||||
ruseBizNm: string;
|
||||
bizBgngDate: string;
|
||||
bizEndDate: string;
|
||||
splyFcltKnd: string;
|
||||
splyFcltNm: string;
|
||||
splyFcltCpct: number | 0 | "";
|
||||
dmdFcltNm: string;
|
||||
dmdFcltAddr: string;
|
||||
ruseFcltCpct: number | 0 | "";
|
||||
ruseFcltPplLen: string;
|
||||
ruseFcltUsg: string;
|
||||
ruseFcltSplyCpct: number | 0 | "";
|
||||
ruseFcltPrcsMsrc: string;
|
||||
grnteWqUsg: string;
|
||||
grnteWqGrssClfg: number | 0 | "";
|
||||
grnteWqCombResdch: number | 0 | "";
|
||||
grnteWqTrbt: string;
|
||||
grnteWqBod: string;
|
||||
grnteWqSmll: string;
|
||||
grnteWqCrmty: string;
|
||||
grnteWqTn: string;
|
||||
grnteWqTp: string;
|
||||
grnteWqPh: string;
|
||||
grnteWqClIonQnt: string;
|
||||
grnteWqCndctStat: string;
|
||||
grnteWqRmrk: string;
|
||||
reqBizReuseFcltCst: number | 0 | "";
|
||||
reqBizPplCst: number | 0 | "";
|
||||
reqBizArchCst: number | 0 | "";
|
||||
reqBizMchnCst: number | 0 | "";
|
||||
reqBizMtrngCst: number | 0 | "";
|
||||
reqBizGisCst: number | 0 | "";
|
||||
reqBizCctvCst: number | 0 | "";
|
||||
reqBizCmcnCst: number | 0 | "";
|
||||
reqBizWstCst: number | 0 | "";
|
||||
reqBizDesignCst: number | 0 | "";
|
||||
reqBizSpvsCst: number | 0 | "";
|
||||
reqBizSbsdCst: number | 0 | "";
|
||||
reqBizEtc: string;
|
||||
reqBizGrssCst: number | 0 | "";
|
||||
prcmPlanNlep: number | 0 | "";
|
||||
prcmPlanLcep: number | 0 | "";
|
||||
prcmPlanBrdnCst: number | 0 | "";
|
||||
prcmPlanEcqrRt: number | 0 | "";
|
||||
prcmPlanGrssCst: number | 0 | "";
|
||||
clclnNlep: number | 0 | "";
|
||||
clclnLcep: number | 0 | "";
|
||||
clclnBrdnCst: number | 0 | "";
|
||||
clclnEcqrRt: number | 0 | "";
|
||||
clclnGrssCst: number | 0 | "";
|
||||
}
|
||||
|
||||
type nameMap = {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
export const reUseCaseNames: nameMap = {
|
||||
"사업명": "ruseBizNm",
|
||||
"사업시작일": "bizBgngDate",
|
||||
"사업종료일": "bizEndDate",
|
||||
"공급처_시설종류": "splyFcltKnd",
|
||||
"공급처명": "splyFcltNm",
|
||||
사업명: "ruseBizNm",
|
||||
사업시작일: "bizBgngDate",
|
||||
사업종료일: "bizEndDate",
|
||||
공급처_시설종류: "splyFcltKnd",
|
||||
공급처명: "splyFcltNm",
|
||||
"공급처_시설용량(㎥/일)": "splyFcltCpct",
|
||||
"수요처명": "dmdFcltNm",
|
||||
"수요처_주소": "dmdFcltAddr",
|
||||
수요처명: "dmdFcltNm",
|
||||
수요처_주소: "dmdFcltAddr",
|
||||
"재이용시설_시설용량(㎥/일)": "ruseFcltCpct",
|
||||
"재이용시설_관로(km)": "ruseFcltPplLen",
|
||||
"재이용시설_용도": "ruseFcltUsg",
|
||||
재이용시설_용도: "ruseFcltUsg",
|
||||
"재이용시설_공급량(㎥/일)": "ruseFcltSplyCpct",
|
||||
"재이용시설_처리공법": "ruseFcltPrcsMsrc",
|
||||
"보증수질_용도별": "grnteWqUsg",
|
||||
"보증수질_총대장균군수": "grnteWqGrssClfg",
|
||||
"보증수질_결합잔류염소": "grnteWqCombResdch",
|
||||
"보증수질_탁도": "grnteWqTrbt",
|
||||
재이용시설_처리공법: "ruseFcltPrcsMsrc",
|
||||
보증수질_용도별: "grnteWqUsg",
|
||||
보증수질_총대장균군수: "grnteWqGrssClfg",
|
||||
보증수질_결합잔류염소: "grnteWqCombResdch",
|
||||
보증수질_탁도: "grnteWqTrbt",
|
||||
"보증수질_생물학적산소요구량(BOD)(mg/L)": "grnteWqBod",
|
||||
"보증수질_냄새": "grnteWqSmll",
|
||||
보증수질_냄새: "grnteWqSmll",
|
||||
"보증수질_색도(도)": "grnteWqCrmty",
|
||||
"보증수질_총질소(T-N)(mg/L)": "grnteWqTn",
|
||||
"보증수질_총인(T-P)(mg/L)": "grnteWqTp",
|
||||
"보증수질_수소이온농도(pH)": "grnteWqPh",
|
||||
"보증수질_염화물": "grnteWqClIonQnt",
|
||||
"보증수질_전기전도도": "grnteWqCndctStat",
|
||||
"보증수질_비고": "grnteWqRmrk",
|
||||
보증수질_염화물: "grnteWqClIonQnt",
|
||||
보증수질_전기전도도: "grnteWqCndctStat",
|
||||
보증수질_비고: "grnteWqRmrk",
|
||||
"소요사업비_총(백만원)": "reqBizGrssCst",
|
||||
"소요사업비_토목_재이용시설(백만원)": "reqBizReuseFcltCst",
|
||||
"소요사업비_토목_관로(백만원)": "reqBizPplCst",
|
||||
@@ -58,52 +111,189 @@ export const reUseCaseNames: nameMap = {
|
||||
"사업비 정산_국비(백만원)": "clclnNlep",
|
||||
"사업비 정산_지방비(백만원)": "clclnLcep",
|
||||
"사업비 정산_원인자부담(백만원)": "clclnBrdnCst",
|
||||
"사업비 정산_국고비율(백만원)": "clclnEcqrRt"
|
||||
}
|
||||
"사업비 정산_국고비율(백만원)": "clclnEcqrRt",
|
||||
};
|
||||
|
||||
// interface PbnstSttnItem {
|
||||
// rvbsn: string;
|
||||
// lgbsn: number;
|
||||
// mdmbsn?: string;
|
||||
// rgnNm?: string;
|
||||
// sido?: number;
|
||||
// gugun?: number;
|
||||
// bscFctNm?: string;
|
||||
// efflWqltStndrdNm?: string;
|
||||
// fctCpc?: number;
|
||||
// tel?: string;
|
||||
// ruseUtztnFcltNm?: string;
|
||||
// fcltCpct?: number;
|
||||
// splyExtraCpct?: number;
|
||||
// ruseCpct?: number;
|
||||
// usageTotal?: number;
|
||||
// inUsage?: number;
|
||||
// outUsage?: number;
|
||||
// }
|
||||
type FieldRule =
|
||||
| { kind: "string"; max: number; required?: boolean; pattern?: RegExp }
|
||||
| { kind: "int"; digits: number; required?: boolean }
|
||||
| {
|
||||
kind: "decimal";
|
||||
intDigits: number;
|
||||
fracDigits: number;
|
||||
required?: boolean;
|
||||
};
|
||||
|
||||
// export const excelPbnstSttnParsing = (data: PbnstSttnItem[]): string[][] => {
|
||||
// const excelExportData: string[][] = [];
|
||||
export const ruseExcelRules: Record<keyof ruseCaseMngExcelProps, FieldRule> = {
|
||||
ruseBizNm: { kind: "string", max: 150, required: true },
|
||||
bizBgngDate: { kind: "string", max: 6, required: true },
|
||||
bizEndDate: { kind: "string", max: 6 },
|
||||
splyFcltKnd: { kind: "string", max: 50 },
|
||||
splyFcltNm: { kind: "string", max: 150, required: true },
|
||||
splyFcltCpct: { kind: "int", digits: 14 },
|
||||
dmdFcltNm: { kind: "string", max: 150, required: true },
|
||||
dmdFcltAddr: { kind: "string", max: 1000 },
|
||||
ruseFcltCpct: { kind: "int", digits: 14 },
|
||||
ruseFcltPplLen: { kind: "string", max: 50 },
|
||||
ruseFcltUsg: { kind: "string", max: 150 },
|
||||
ruseFcltSplyCpct: { kind: "int", digits: 14 },
|
||||
ruseFcltPrcsMsrc: { kind: "string", max: 50 },
|
||||
grnteWqUsg: { kind: "string", max: 50 },
|
||||
grnteWqGrssClfg: { kind: "int", digits: 10 },
|
||||
grnteWqCombResdch: { kind: "decimal", intDigits: 5, fracDigits: 3 },
|
||||
grnteWqTrbt: { kind: "string", max: 10 },
|
||||
grnteWqBod: { kind: "string", max: 10 },
|
||||
grnteWqSmll: { kind: "string", max: 10 },
|
||||
grnteWqCrmty: { kind: "string", max: 10 },
|
||||
grnteWqTn: { kind: "string", max: 10 },
|
||||
grnteWqTp: { kind: "string", max: 10 },
|
||||
grnteWqPh: { kind: "string", max: 10 },
|
||||
grnteWqClIonQnt: { kind: "string", max: 10 },
|
||||
grnteWqCndctStat: { kind: "string", max: 10 },
|
||||
grnteWqRmrk: { kind: "string", max: 1000 },
|
||||
reqBizReuseFcltCst: { kind: "int", digits: 14 },
|
||||
reqBizPplCst: { kind: "int", digits: 14 },
|
||||
reqBizArchCst: { kind: "int", digits: 14 },
|
||||
reqBizMchnCst: { kind: "int", digits: 14 },
|
||||
reqBizMtrngCst: { kind: "int", digits: 14 },
|
||||
reqBizGisCst: { kind: "int", digits: 14 },
|
||||
reqBizCctvCst: { kind: "int", digits: 14 },
|
||||
reqBizCmcnCst: { kind: "int", digits: 14 },
|
||||
reqBizWstCst: { kind: "int", digits: 14 },
|
||||
reqBizDesignCst: { kind: "int", digits: 14 },
|
||||
reqBizSpvsCst: { kind: "int", digits: 14 },
|
||||
reqBizSbsdCst: { kind: "int", digits: 14 },
|
||||
reqBizEtc: { kind: "string", max: 1000 },
|
||||
reqBizGrssCst: { kind: "int", digits: 14 },
|
||||
prcmPlanNlep: { kind: "int", digits: 14 },
|
||||
prcmPlanLcep: { kind: "int", digits: 14 },
|
||||
prcmPlanBrdnCst: { kind: "int", digits: 14 },
|
||||
prcmPlanEcqrRt: { kind: "decimal", intDigits: 3, fracDigits: 2 },
|
||||
prcmPlanGrssCst: { kind: "int", digits: 14 },
|
||||
clclnNlep: { kind: "int", digits: 14 },
|
||||
clclnLcep: { kind: "int", digits: 14 },
|
||||
clclnBrdnCst: { kind: "int", digits: 14 },
|
||||
clclnEcqrRt: { kind: "decimal", intDigits: 3, fracDigits: 2 },
|
||||
clclnGrssCst: { kind: "int", digits: 14 },
|
||||
};
|
||||
|
||||
// data.forEach((item) => {
|
||||
// excelExportData.push([
|
||||
// item.rvbsn,
|
||||
// String(item.lgbsn),
|
||||
// item.mdmbsn ?? "",
|
||||
// item.rgnNm ?? "",
|
||||
// String(item.sido ?? ""),
|
||||
// String(item.gugun ?? ""),
|
||||
// String(item.bscFctNm ?? ""),
|
||||
// String(item.efflWqltStndrdNm ?? ""),
|
||||
// String(item.fctCpc ?? ""),
|
||||
// String(item.tel ?? ""),
|
||||
// String(item.ruseUtztnFcltNm ?? ""),
|
||||
// String(item.fcltCpct ?? ""),
|
||||
// String(item.splyExtraCpct ?? ""),
|
||||
// String(item.ruseCpct ?? ""),
|
||||
// String(item.usageTotal ?? ""),
|
||||
// String(item.inUsage ?? ""),
|
||||
// String(item.outUsage ?? ""),
|
||||
// ])
|
||||
// })
|
||||
// return excelExportData;
|
||||
// };
|
||||
const notStringTrim = (str: any) => (str == null ? "" : String(str)).trim();
|
||||
const stripNum = (str: string) => str.replace(/,/g, "").replace(/%/g, "");
|
||||
|
||||
// 2024.9 / 2024.09 / 202409 → YYYYMM
|
||||
const isDateCheck = (raw: any) => {
|
||||
const isDate = notStringTrim(raw);
|
||||
return stripNum(isDate)
|
||||
.replace(/[^0-9]/g, "")
|
||||
.slice(0, 6);
|
||||
};
|
||||
|
||||
const parseIntLike = (raw: any, digits: number): number | "" => {
|
||||
const s = stripNum(notStringTrim(raw));
|
||||
if (!s || !/^\d+$/.test(s) || s.length > digits) return "";
|
||||
return Number(s);
|
||||
};
|
||||
|
||||
const parseDecLike = (
|
||||
raw: any,
|
||||
intDigits: number,
|
||||
fracDigits: number
|
||||
): number | "" => {
|
||||
const isData = stripNum(String(raw ?? "").trim());
|
||||
|
||||
// 빈값은 실패
|
||||
if (!isData) return "";
|
||||
|
||||
// 허용: "123" / "123.45" / ".45" / "0.45"
|
||||
if (!/^\d*(\.\d+)?$/.test(isData)) return "";
|
||||
|
||||
let num = isData.split(".")[0];
|
||||
if (num === "") num = "0";
|
||||
|
||||
const fraction = isData.split(".")[1] ?? "";
|
||||
|
||||
// 정수부가 비었으면 0으로 보정 → ".123" → "0.123"
|
||||
|
||||
// 자리수 체크
|
||||
if ((num && num.length > intDigits) || fraction.length > fracDigits)
|
||||
return "";
|
||||
|
||||
return Number(`${num}${fraction ? "." + fraction : ""}`);
|
||||
};
|
||||
|
||||
export function mapAndValidateRow(
|
||||
item: Record<string, unknown>,
|
||||
base: ruseCaseMngExcelProps
|
||||
): { ok: boolean; errors: string[]; value?: ruseCaseMngExcelProps } {
|
||||
const out: ruseCaseMngExcelProps = { ...base };
|
||||
const errors: string[] = [];
|
||||
const bizNm = notStringTrim(item?.["사업명"]); //에러 메시지 표출용
|
||||
|
||||
for (const [header, dest] of Object.entries(reUseCaseNames) as [
|
||||
string,
|
||||
keyof ruseCaseMngExcelProps,
|
||||
][]) {
|
||||
const rule = ruseExcelRules[dest];
|
||||
let raw = item?.[header];
|
||||
|
||||
// 빈/대시 → ''
|
||||
if (
|
||||
raw == null ||
|
||||
notStringTrim(raw) === "" ||
|
||||
notStringTrim(raw) === "-"
|
||||
) {
|
||||
(out as any)[dest] = "";
|
||||
if (rule.required) errors.push(`${bizNm} =>[${header}] 필수값 누락`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dest === "bizBgngDate" || dest === "bizEndDate") {
|
||||
raw = isDateCheck(raw);
|
||||
}
|
||||
|
||||
if (rule.kind === "string") {
|
||||
const value = notStringTrim(raw);
|
||||
if (rule.required && !value) errors.push(`${bizNm} =>[${header}] 필수값`);
|
||||
if (value && rule.max && value.length > rule.max)
|
||||
errors.push(`${bizNm} =>[${header}] 최대 ${rule.max}자 초과`);
|
||||
if (value && rule.pattern && !rule.pattern.test(value))
|
||||
errors.push(`${bizNm} =>[${header}] 형식 오류`);
|
||||
(out as any)[dest] = value;
|
||||
} else if (rule.kind === "int") {
|
||||
const n = parseIntLike(raw, rule.digits);
|
||||
if (n === "") {
|
||||
if (rule.required)
|
||||
errors.push(`${bizNm} =>[${header}] 정수 ${rule.digits}자리 이내 필요`);
|
||||
(out as any)[dest] = "";
|
||||
} else {
|
||||
(out as any)[dest] = n;
|
||||
}
|
||||
} else {
|
||||
// decimal
|
||||
const n = parseDecLike(raw, rule.intDigits, rule.fracDigits);
|
||||
if (n === "") {
|
||||
if (rule.required)
|
||||
errors.push(
|
||||
`[${header}] 소수(정수부≤${rule.intDigits}, 소수부≤${rule.fracDigits}) 필요`
|
||||
);
|
||||
(out as any)[dest] = "";
|
||||
} else {
|
||||
(out as any)[dest] = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // PK 필수(가독성용)
|
||||
// (["bizBgngDate", "ruseBizNm", "splyFcltNm", "dmdFcltNm"] as const).forEach(
|
||||
// (key) => {
|
||||
// const objValue=Object.entries(reUseCaseNames).find(([,val]) => val === key);
|
||||
// if (!notStringTrim(out[key]) &&objValue) errors.push(`${bizNm} =>[PK] ${objValue[0]} 필수`);
|
||||
// }
|
||||
// );
|
||||
|
||||
return {
|
||||
ok: errors.length === 0,
|
||||
errors,
|
||||
value: errors.length ? undefined : out,
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { fetchType, getFetchWithCount, postFectch } from "@/components/lib/api";
|
||||
import { toast } from "react-hot-toast";
|
||||
import type { TableUpperProps } from "../../common/type/header";
|
||||
import { ruseCaseHeadListExport } from "./headList";
|
||||
import type { ruseCaseMngExcelProps } from "./excel";
|
||||
export type ruseCaseState = {
|
||||
ruseCaseMng: {
|
||||
ruseHeadList: TableUpperProps[];
|
||||
@@ -12,73 +13,53 @@ export type ruseCaseState = {
|
||||
};
|
||||
};
|
||||
|
||||
export interface ruseCaseMngExcelProps {
|
||||
ruseBizNm: string,
|
||||
bizBgngDate: string,
|
||||
bizEndDate: string,
|
||||
splyFcltKnd: string,
|
||||
splyFcltNm: string,
|
||||
splyFcltCpct: number | 0 | '',
|
||||
dmdFcltNm: string,
|
||||
dmdFcltAddr: string,
|
||||
ruseFcltCpct: number | 0 | '',
|
||||
ruseFcltPplLen: string,
|
||||
ruseFcltUsg: string,
|
||||
ruseFcltSplyCpct: number | 0 | '',
|
||||
ruseFcltPrcsMsrc: string,
|
||||
grnteWqUsg: string,
|
||||
grnteWqGrssClfg: number | 0 | '',
|
||||
grnteWqCombResdch: number | 0 | '',
|
||||
grnteWqTrbt: string,
|
||||
grnteWqBod: string,
|
||||
grnteWqSmll: string,
|
||||
grnteWqCrmty: string,
|
||||
grnteWqTn: string,
|
||||
grnteWqTp: string,
|
||||
grnteWqPh: string,
|
||||
grnteWqClIonQnt: string,
|
||||
grnteWqCndctStat: string,
|
||||
grnteWqRmrk: string,
|
||||
reqBizReuseFcltCst: number | 0 | '',
|
||||
reqBizPplCst: number | 0 | '',
|
||||
reqBizArchCst: number | 0 | '',
|
||||
reqBizMchnCst: number | 0 | '',
|
||||
reqBizMtrngCst: number | 0 | '',
|
||||
reqBizGisCst: number | 0 | '',
|
||||
reqBizCctvCst: number | 0 | '',
|
||||
reqBizCmcnCst: number | 0 | '',
|
||||
reqBizWstCst: number | 0 | '',
|
||||
reqBizDesignCst: number | 0 | '',
|
||||
reqBizSpvsCst: number | 0 | '',
|
||||
reqBizSbsdCst: number | 0 | '',
|
||||
reqBizEtc: string,
|
||||
reqBizGrssCst: number | 0 | '',
|
||||
prcmPlanNlep: number | 0 | '',
|
||||
prcmPlanLcep: number | 0 | '',
|
||||
prcmPlanBrdnCst: number | 0 | '',
|
||||
prcmPlanEcqrRt: number | 0 | '',
|
||||
prcmPlanGrssCst: number | 0 | '',
|
||||
clclnNlep: number | 0 | '',
|
||||
clclnLcep: number | 0 | '',
|
||||
clclnBrdnCst: number | 0 | '',
|
||||
clclnEcqrRt: number | 0 | '',
|
||||
clclnGrssCst: number | 0 | '',
|
||||
}
|
||||
|
||||
type ruseCaseActions = {
|
||||
ruseCaseMngInit: () => void;
|
||||
selectRuseCaseMng: (isExcel: boolean, pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => Promise<void>;
|
||||
selectRuseCaseMng: (
|
||||
isExcel: boolean,
|
||||
pageNo: number,
|
||||
pageSize: number,
|
||||
sidoCd: string,
|
||||
sigunguCd: string,
|
||||
usageCd: string,
|
||||
name: string
|
||||
) => Promise<void>;
|
||||
insertRuseCaseMng: (data: any) => Promise<void>;
|
||||
};
|
||||
|
||||
export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => {
|
||||
const tailUrl = '/' + pageNo + '/' + pageSize + ((sigunguCd !== '전체' && sigunguCd !== '') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd ? `/${usageCd}` : '/0') + (name ? `/${name}` : '');
|
||||
const resp = await getFetchWithCount(fetchType.WR, `/reuseFc/pubFcRuseCase${tailUrl}`);
|
||||
const fetchSearchRuseCaseMng = async (
|
||||
pageNo: number,
|
||||
pageSize: number,
|
||||
sidoCd: string,
|
||||
sigunguCd: string,
|
||||
usageCd: string,
|
||||
name: string
|
||||
) => {
|
||||
const tailUrl =
|
||||
"/" +
|
||||
pageNo +
|
||||
"/" +
|
||||
pageSize +
|
||||
(sigunguCd !== "전체" && sigunguCd !== ""
|
||||
? `/${sigunguCd}`
|
||||
: sidoCd != "전체" && sidoCd != ""
|
||||
? `/${sidoCd}`
|
||||
: `/0`) +
|
||||
(usageCd ? `/${usageCd}` : "/0") +
|
||||
(name ? `/${name}` : "");
|
||||
const resp = await getFetchWithCount(
|
||||
fetchType.WR,
|
||||
`/reuseFc/pubFcRuseCase${tailUrl}`
|
||||
);
|
||||
return { data: resp.data, count: resp.count };
|
||||
};
|
||||
|
||||
export const fetchInsertRuseCaseMng = async (data: any) => {
|
||||
const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR);
|
||||
const fetchInsertRuseCaseMng = async (data: any) => {
|
||||
const response = await postFectch(
|
||||
"/reuseFc/pubFcRuseCase",
|
||||
data,
|
||||
fetchType.WR
|
||||
);
|
||||
return { data: response.data, status: response.status };
|
||||
};
|
||||
|
||||
@@ -99,7 +80,10 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
||||
) => {
|
||||
return {
|
||||
ruseCaseMngInit: async () => {
|
||||
const res = await getFetchWithCount(fetchType.WR, `/reuseFc/pubFcRuseCase/1/10/0/0`);
|
||||
const res = await getFetchWithCount(
|
||||
fetchType.WR,
|
||||
`/reuseFc/pubFcRuseCase/1/10/0/0`
|
||||
);
|
||||
set((state: ruseCaseState) => ({
|
||||
ruseCaseMng: {
|
||||
...state.ruseCaseMng,
|
||||
@@ -108,8 +92,23 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
||||
},
|
||||
}));
|
||||
},
|
||||
selectRuseCaseMng: async (isExcel: boolean, pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => {
|
||||
const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name);
|
||||
selectRuseCaseMng: async (
|
||||
isExcel: boolean,
|
||||
pageNo: number,
|
||||
pageSize: number,
|
||||
sidoCd: string,
|
||||
sigunguCd: string,
|
||||
usageCd: string,
|
||||
name: string
|
||||
) => {
|
||||
const res = await fetchSearchRuseCaseMng(
|
||||
pageNo,
|
||||
pageSize,
|
||||
sidoCd,
|
||||
sigunguCd,
|
||||
usageCd,
|
||||
name
|
||||
);
|
||||
if (isExcel) {
|
||||
set((state: ruseCaseState) => {
|
||||
return {
|
||||
@@ -117,7 +116,7 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
||||
ruseCaseMng: {
|
||||
...state.ruseCaseMng,
|
||||
count: res.count,
|
||||
excelList: res.data
|
||||
excelList: res.data,
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -133,18 +132,27 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
||||
},
|
||||
|
||||
insertRuseCaseMng: async (data: any) => {
|
||||
const response = await fetchInsertRuseCaseMng(data);
|
||||
if (response.status === 200) {
|
||||
toast.success("물재이용사례 등록이 완료되었습니다. ");
|
||||
} else {
|
||||
try {
|
||||
const response = await fetchInsertRuseCaseMng(data);
|
||||
if (response.status === 200) {
|
||||
toast.success("물재이용사례 등록이 완료되었습니다. ");
|
||||
const res = await getFetchWithCount(
|
||||
fetchType.WR,
|
||||
`/reuseFc/pubFcRuseCase/1/10/0/0`
|
||||
);
|
||||
set((state: ruseCaseState) => ({
|
||||
ruseCaseMng: {
|
||||
...state.ruseCaseMng,
|
||||
ruseCaseMngList: res.data,
|
||||
count: res.count,
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
toast.error("물재이용사례 등록에 실패하였습니다. ");
|
||||
}
|
||||
set((state: ruseCaseState) => ({
|
||||
ruseCaseMng: {
|
||||
...state.ruseCaseMng,
|
||||
status: response.status,
|
||||
},
|
||||
}));
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -158,7 +158,6 @@ export default function ChkgdExcel({
|
||||
];
|
||||
const issues: string[] = [];
|
||||
|
||||
console.log('listTotalData ', listTotalData)
|
||||
rswtExcelDataCheck(listTotalData,issues)
|
||||
|
||||
if (issues && issues.length > 0) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { coRegExcel } from "@/app/store/matDmd/coSttn/headList";
|
||||
import { reUseCaseNames } from "@/app/store/matDmd/ruseCaseMng/excel";
|
||||
import type { ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/index";
|
||||
import { mapAndValidateRow, type ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/excel";
|
||||
import { showConfirmToast } from "@/components/lib/func/commom";
|
||||
import { filePicked, Title } from "@common/business_components/ui";
|
||||
import { Form } from "@common/business_components/ui/form";
|
||||
import { Button, Input } from "@common/components/ui";
|
||||
@@ -10,7 +10,7 @@ import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import type { z } from "zod";
|
||||
|
||||
export default function RuseCaseMngExcel() {
|
||||
export default function RuseCaseMngExcel({setIsExcelOpen}:{setIsExcelOpen: (isOpen:boolean)=>void}) {
|
||||
const { insertRuseCaseMng } = useWrStore((state) => state);
|
||||
const form = useForm<z.infer<typeof coRegExcel>>({
|
||||
resolver: zodResolver(coRegExcel),
|
||||
@@ -23,6 +23,7 @@ export default function RuseCaseMngExcel() {
|
||||
filePicked(file, 0).then((res: unknown) => {
|
||||
try {
|
||||
const newArray: ruseCaseMngExcelProps[] = []
|
||||
const isError:string[][] = []
|
||||
const dataArray = Array.isArray(res) ? res : [];
|
||||
dataArray.forEach((item: Record<string, unknown>) => {
|
||||
const object: ruseCaseMngExcelProps = {
|
||||
@@ -78,49 +79,74 @@ export default function RuseCaseMngExcel() {
|
||||
clclnGrssCst: 0,
|
||||
};
|
||||
|
||||
Object.keys(reUseCaseNames).forEach((key: string) => {
|
||||
if (item && reUseCaseNames[key] !== undefined) {
|
||||
const mappedKey = reUseCaseNames[key];
|
||||
if (mappedKey && object.hasOwnProperty(mappedKey)) {
|
||||
let value;
|
||||
|
||||
if(value === "-"){
|
||||
value = '';
|
||||
}
|
||||
if(key === "사업시작일" || key === "사업종료일"){
|
||||
if(item[key]?.toString().split(".")[1]?.length === 1){
|
||||
value = `${item[key]?.toString().split(".")[0] || ""}${item[key]?.toString().split(".")[1]?.length === 1 ? "0" : ""}${item[key]?.toString().split(".")[1] || ""}`
|
||||
}else{
|
||||
value = `${item[key]?.toString().split(".")[0] || ""}${item[key]?.toString().split(".")[1] || ""}`
|
||||
}
|
||||
}else if(key === "재이용시설_관로(km)" || key?.toString().includes("보증수질_")){
|
||||
value = item[key]?.toString().trim() || '';
|
||||
}else{
|
||||
if(item[key]?.toString().includes("%") && Number(item[key]?.toString().replaceAll("%", ""))){
|
||||
value = item[key]?.toString().replaceAll("%", "");
|
||||
}else{
|
||||
value = item[key];
|
||||
}
|
||||
}
|
||||
const parsingExcel= mapAndValidateRow(item, object);
|
||||
// Object.keys(reUseCaseNames).forEach((key: string) => {
|
||||
// if (item && reUseCaseNames[key] !== undefined) {
|
||||
// const mappedKey = reUseCaseNames[key];
|
||||
// if (mappedKey && object.hasOwnProperty(mappedKey)) {
|
||||
// let value;
|
||||
|
||||
if(value === null || value?.toString().trim() === "-" || value?.toString().trim() === ""){
|
||||
if (typeof object[mappedKey as keyof ruseCaseMngExcelProps] === 'number') {
|
||||
(object as unknown as Record<string, unknown>)[mappedKey] = '';
|
||||
} else {
|
||||
(object as unknown as Record<string, unknown>)[mappedKey] = '';
|
||||
}
|
||||
}else if (typeof object[mappedKey as keyof ruseCaseMngExcelProps] === 'number' && Number(value?.toString().replaceAll("%", "").replaceAll(",", ""))) {
|
||||
(object as unknown as Record<string, unknown>)[mappedKey] = Number(value?.toString().replaceAll("%", "").replaceAll(",", ""));
|
||||
}else{
|
||||
(object as unknown as Record<string, unknown>)[mappedKey] = value?.toString().trim() || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
newArray.push(object);
|
||||
// if(value === "-"){
|
||||
// value = '';
|
||||
// }
|
||||
// if(key === "사업시작일" || key === "사업종료일"){
|
||||
// if(item[key]?.toString().split(".")[1]?.length === 1){
|
||||
// value = `${item[key]?.toString().split(".")[0] || ""}${item[key]?.toString().split(".")[1]?.length === 1 ? "0" : ""}${item[key]?.toString().split(".")[1] || ""}`
|
||||
// }else{
|
||||
// value = `${item[key]?.toString().split(".")[0] || ""}${item[key]?.toString().split(".")[1] || ""}`
|
||||
// }
|
||||
// }else if(key === "재이용시설_관로(km)" || key?.toString().includes("보증수질_")){
|
||||
// value = item[key]?.toString().trim() || '';
|
||||
// }else{
|
||||
// if(item[key]?.toString().includes("%") && Number(item[key]?.toString().replaceAll("%", ""))){
|
||||
// value = item[key]?.toString().replaceAll("%", "");
|
||||
// }else{
|
||||
// value = item[key];
|
||||
// }
|
||||
// }
|
||||
|
||||
// if(value === null || value?.toString().trim() === "-" || value?.toString().trim() === ""){
|
||||
// if (typeof object[mappedKey as keyof ruseCaseMngExcelProps] === 'number') {
|
||||
// (object as unknown as Record<string, unknown>)[mappedKey] = '';
|
||||
// } else {
|
||||
// (object as unknown as Record<string, unknown>)[mappedKey] = '';
|
||||
// }
|
||||
// }else if (typeof object[mappedKey as keyof ruseCaseMngExcelProps] === 'number' && Number(value?.toString().replaceAll("%", "").replaceAll(",", ""))) {
|
||||
// (object as unknown as Record<string, unknown>)[mappedKey] = Number(value?.toString().replaceAll("%", "").replaceAll(",", ""));
|
||||
// }else{
|
||||
// (object as unknown as Record<string, unknown>)[mappedKey] = value?.toString().trim() || '';
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
if(parsingExcel.ok&&parsingExcel.value){
|
||||
newArray.push(parsingExcel.value);
|
||||
}else if(parsingExcel.errors){
|
||||
isError.push(parsingExcel.errors);
|
||||
}
|
||||
});
|
||||
console.log("newArray : ", newArray);
|
||||
insertRuseCaseMng(newArray);
|
||||
if(isError.length > 0){
|
||||
const errorLength = 10;
|
||||
let isErrorCount=0;
|
||||
isError.forEach((err) => {
|
||||
err.forEach((error) =>{
|
||||
isErrorCount++;
|
||||
if(isErrorCount < errorLength){
|
||||
showConfirmToast(error)
|
||||
}
|
||||
})
|
||||
})
|
||||
return;
|
||||
}else if(newArray.length === 0){
|
||||
alert("업로드할 데이터가 없습니다.");
|
||||
return;
|
||||
}else if(newArray.length > 0){
|
||||
insertRuseCaseMng(newArray);
|
||||
setIsExcelOpen(false);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user