Merge commit 'c2f02108e4544d79f631562912f9e5707177e648' into iipbs/wr/dev
iipbs_wr / build (push) Waiting to run

This commit is contained in:
leedj312
2025-05-06 23:11:03 +09:00
52 changed files with 2614 additions and 1871 deletions
@@ -13,7 +13,6 @@ import {
UiTable,
} from "@common/business_components";
import { Button } from "@common/components";
import { headMakeColSpan } from "../rainReg/page";
import ListDiv from "@common/business_components/ui/list_div";
import { useEffect, useState } from "react";
import { tableData } from "@/components/lib/func/commom";
@@ -22,6 +21,7 @@ import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import BdstChgModal from "@/components/ui/modal/bdstChgModal/bdstChgModal";
import { BdstReg } from "@/components/ui/modal/bdstRegModal/bdstRegModal";
import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg";
import { headMakeColSpan } from "../rainReg/TableHead";
export default function Home() {
const { code, htdfl, initHtdfl } = useWrStore((state) => state);
@@ -0,0 +1,30 @@
import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { TableRow, TableHead } from "@common/components/ui";
export const headMakeColSpan = (upHeadList: TableUpperProps[]) => {
return (
<>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
!head.upSequnce ? (
<TableHead rowSpan={2} key={head.id}>
{head.title}
</TableHead>
) : head.upName === "upChangeRe" && head.upSequnce === 1 ? (
<TableHead key={head.id} rowSpan={1} colSpan={3}>
{"중축 개축 재축 "}
</TableHead>
) : null
)}
</TableRow>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
head.upName === "upChangeRe" ? (
<TableHead key={head.id}>{head.title}</TableHead>
) : null
)}
</TableRow>
</>
);
};
@@ -1,12 +1,11 @@
"use client";
import { useWrStore } from "@/app/store";
import type {
chgBuilding,
customRainBdst,
TableUpperProps,
import {
type chgBuilding,
type customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { tableData } from "@/components/lib/func/commom";
import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm";
import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm";
import BdstChgModal from "@/components/ui/modal/bdstChgModal/bdstChgModal";
import { BdstReg } from "@/components/ui/modal/bdstRegModal/bdstRegModal";
import {
@@ -21,46 +20,17 @@ import {
UiTable,
} from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, TableHead, TableRow } from "@common/components";
import { Button } from "@common/components";
import { useEffect, useState } from "react";
export const headMakeColSpan = (upHeadList: TableUpperProps[]) => {
return (
<>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
!head.upSequnce ? (
<TableHead rowSpan={2} key={head.id}>
{head.title}
</TableHead>
) : head.upName === "upChangeRe" && head.upSequnce === 1 ? (
<TableHead key={head.id} rowSpan={1} colSpan={3}>
{"중축 개축 재축 "}
</TableHead>
) : null
)}
</TableRow>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
head.upName === "upChangeRe" ? (
<TableHead key={head.id}>{head.title}</TableHead>
) : null
)}
</TableRow>
</>
);
};
//-------------------------------------------------------------------------------------------------------
export default function Home() {
const { rain, code, init } = useWrStore((state) => {
const { rain, code, initRain, rainSearch, getRainData } = useWrStore((state) => {
return state;
});
const { rainRes } = rain;
const [rainForm, setRainForm] = useState<customRainBdst>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [pageNation, setPageNation] = useState(1);
const [bdstTable, setbdstTable] = useState<customRainBdst[]>();
const [searchTxt, setSearchTxt] = useState<string>();
const [bdstChgProps, setBdstChgProps] = useState<{
@@ -68,16 +38,24 @@ export default function Home() {
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
const nodeList = headMakeColSpan(rain.upHeadList);
useEffect(() => {
if (!rain.isInit) {
init(undefined);
initRain('41');
}
}, [rain.isInit, init]);
}, [rain.isInit, initRain]);
useEffect(() => {
if (code.sggCd.length > 0) {
setbdstTable(tableData(rainRes, { code }));
const rainData = tableData(rainRes, { code }).map(
(item: customRainBdst) => {
return {
...item,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
};
}
);
setbdstTable(rainData);
}
}, [code, rainRes]);
const cellClick: (val: number | undefined, headId: string) => void = (
@@ -103,8 +81,9 @@ export default function Home() {
};
useEffect(() => {
console.log("rainForm", rainForm);
}, [rainForm]);
console.log("getPageNation", pageNation);
getRainData(pageNation, "41");
}, [pageNation]);
return (
<>
@@ -115,7 +94,7 @@ export default function Home() {
<SearchDiv>
<SearchFormLeft>
<SearchInput
className="col-span-3 my-7"
className={" col-span-3 my-7 !text-3xl"}
label="건물명"
textValue={searchTxt || ""}
setText={(e) => {
@@ -123,24 +102,24 @@ export default function Home() {
}}
/>
</SearchFormLeft>
<SearchFormRight >
<SearchFormRight>
<div className="flex flex-row space-x-2">
<Button
className=""
size={"sm"}
onClick={(e) => {
init(searchTxt || "");
}}
>
조회
</Button>
<Button
size={"sm"}
className=""
onClick={() => setIsNewReg(!issNewReg)}
>
신규등록
</Button>
<Button
className=""
size={"sm"}
onClick={(e) => {
rainSearch(searchTxt || "", pageNation, "41");
}}
>
조회
</Button>
<Button
size={"sm"}
className=""
onClick={() => setIsNewReg(!issNewReg)}
>
신규등록
</Button>
</div>
</SearchFormRight>
</SearchDiv>
@@ -148,19 +127,19 @@ export default function Home() {
</div>
<div className="h-screen grid grid-cols-6 gap-4 !overflow-y-scroll">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="h-full min-h-0">
<ListDiv className="h-full min-h-0">
<ScrollArea className="h-[60vh]">
<UiTable
tableData={bdstTable || []}
headlist={rain.upHeadList}
pageSize={100}
total={10}
pageSize={20}
total={10000}
headName={"○건축물 목록"}
cellClick={(val, headId) => {
cellClick(val, headId);
}}
onPageChange={setPageNation}
>
{nodeList}
</UiTable>
</ScrollArea>
</ListDiv>
@@ -176,7 +155,7 @@ export default function Home() {
</div>
<UiModal
body={<BdstReg moType="RNB"></BdstReg>}
bodyClass="w-[90vw] max-w-none"
bodyClass="w-[30vw] max-w-none"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
@@ -14,37 +14,46 @@ import {
} from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components";
import { headMakeColSpan } from "../rainReg/page";
import { useEffect, useState } from "react";
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
import { tableData } from "@/components/lib/func/commom";
import RswtrRegForm from "@/components/ui/form/fcltReg/rswtrReg/rswtrRegForm";
import BdstChgModal from "@/components/ui/modal/bdstChgModal/bdstChgModal";
import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { headMakeColSpan } from "../rainReg/TableHead";
export default function Home() {
const { code, rswt, initRswt } = useWrStore((state) => state);
const nodeList = headMakeColSpan(rswt.upHeadList);
const { code, rswt, initRswt ,rswtBdstSearch,getRswtBdstData} = useWrStore((state) => state);
const [rswtForm, setRswtForm] = useState<customRswtBdst>();
const [searchTxt, setSearchTxt] = useState<string>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [pageNation, setPageNation] = useState(1);
const [bdstTable, setbdstTable] = useState<customRswtBdst[]>();
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
const { rswtRes } = rswt;
useEffect(() => {
if (!rswt.isInit) {
initRswt(undefined);
initRswt('41');
}
}, [rswt.isInit, initRswt]);
useEffect(() => {
if (code.sggCd.length > 0) {
setbdstTable(tableData(rswtRes, { code }));
const rswtData = tableData(rswtRes, { code }).map(
(item: customRswtBdst) => {
return {
...item,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd
};
}
);
console.log(rswtData)
setbdstTable(rswtData);
}
}, [code, rswtRes]);
const cellClick: (val: number | undefined, headId: string) => void = (
@@ -69,6 +78,10 @@ export default function Home() {
const bdstChgModal = (chgBuilding: chgBuilding[]) => {
setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
};
useEffect(() => {
getRswtBdstData(pageNation, "41");
}, [pageNation]);
return (
<>
@@ -93,7 +106,7 @@ export default function Home() {
size={"sm"}
className="mr-4 "
onClick={(e) => {
initRswt(searchTxt || "");
rswtBdstSearch(searchTxt || "",pageNation,'41');
}}
>
조회
@@ -117,12 +130,12 @@ export default function Home() {
<UiTable
tableData={bdstTable || []}
headlist={rswt.upHeadList}
pageSize={100}
total={10}
pageSize={20}
total={10000}
headName={"○건축물 목록"}
cellClick={cellClick}
>
{nodeList}
cellClick={cellClick}
onPageChange={setPageNation}
>
</UiTable>
</ListDiv>
</div>
@@ -17,10 +17,10 @@ import HeadChModal from "@/components/ui/modal/headChModal/headChModal";
import { useState } from "react";
export default function PbnstSttn() {
const { code, sttnCommon } = useWrStore((state) => state);
const { code, rainSttn } = useWrStore((state) => state);
const [isChHead, setIsChHead] = useState(false);
const nodeList = headMakeprfmnc(sttnCommon.pbnSttHeadList, sttnCommon.pbnSttHeadNm);
const nodeList = headMakeprfmnc(rainSttn.pbnSttHeadList, rainSttn.pbnSttHeadNm);
return (
<>
@@ -113,7 +113,7 @@ export default function PbnstSttn() {
<UiTable
headName={undefined}
tableData={[]}
headlist={sttnCommon.pbnSttHeadList}
headlist={rainSttn.pbnSttHeadList}
pageSize={0}
total={0}
cellClick={undefined}
+114 -194
View File
@@ -1,217 +1,137 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import { excelDownload, tableData } from "@/components/lib/func/commom";
import HeadChModal from "@/components/ui/modal/headChModal/headChModal";
import {
ContentsDiv,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SelectBox,
SearchBaseForm,
Title,
UiModal,
UiTable,
type ReturnType
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, TableHead, TableRow } from "@common/components/ui";
import { useEffect, useState } from "react";
import type {
TableTripleProps,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { tableData } from "@/components/lib/func/commom";
import HeadChModal from "@/components/ui/modal/headChModal/headChModal";
export const headMakeTriple = (
upHeadList: TableTripleProps[],
makeHeadNm: chHeadType[],
rowCount: number = 2
) => {
return (
<>
{Array.from({ length: rowCount }).map((_, i) => (
<TableRow key={i}>
{
upHeadList
.filter((head: TableTripleProps) => head.visible == true)
.map((head: TableTripleProps) =>
!head.upSequnce[i] ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
rowSpan={2}
key={head.id}
>
{head.title}
</TableHead>
) : head.upSequnce[i] === 1 ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
rowSpan={1}
colSpan={
makeHeadNm.find((ch) => ch.headNm === head.upName[i])
?.length
}
>
{makeHeadNm.find((ch) => ch.headNm === head.upName[i])?.text}
</TableHead>
) : null
)}
</TableRow>
))}
<TableRow>
{upHeadList
.map((head: TableTripleProps) =>
makeHeadNm.find((ch) => ch.headNm === head?.upName[1] && head.visible ==true ) ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
>
{head.title}
</TableHead>
) : null
)}
</TableRow>
</>
);
};
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
export default function RainSttn() {
const { code, rain, init, sttnCommon } = useWrStore((state) => state);
const { rainRes } = rain;
const { code, rainSttn, rainSttnSearch } =
useWrStore((state) => state);
const { rainSttnRes } = rainSttn;
const [isChHead, setIsChHead] = useState(false);
const [bdstTable, setBdstTable] = useState<any[]>();
const [tableHead, setTableHead] = useState<any[]>([]);
let nodeList = headMakeTriple(
sttnCommon.rainSttHeadList,
sttnCommon.rainSttHeadNm
);
const ref = useRef<ReturnType>({} as ReturnType);
const [bdstTable, setBdstTable] = useState<customRainBdst[]>();
useEffect(() => {
if (!rain.isInit) {
init(undefined);
}
}, [rain.isInit, init]);
useEffect(() => {
if (code.sggCd.length > 0) {
const data = tableData(rainRes, { code });
// data 는 위 JSON 객체라고 가정
console.log("sttnCommon " , sttnCommon.rainSttHeadList)
const unVisibleHead = sttnCommon.rainSttHeadList.filter(
(item: TableTripleProps) => item.visible === false
);
console.log("unVisibleHead " , unVisibleHead)
const chData = data
.map((item:any) =>({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].rainyObj
})).filter((item:any) => item.rainyObj !== undefined)
console.log("chData " , chData)
setBdstTable( chData);
if (!rainSttn.isInit) {
let con
if (ref.current.sigunValue != '0') {
con = ref.current.sigunValue
}else{
con = ref.current.sidoValue
}
}, [code, rainRes,sttnCommon]);
rainSttnSearch('1', '20' ,con);
}
}, [rainSttn.isInit, rainSttnSearch]);
useEffect(() => {
if (rainSttnRes.length > 0 && code.cityCd.length>0) {
const data = tableData(rainSttnRes, { code });
const chData = data
.map((item: any) => ({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].rainyObj,
// cityText:item.cityText,
// sggText:item.sggText,
// bdstNm: item.bdstNm,
// daddr:item.daddr,
// bdstUsgCd:item.bdstUsgCd,
// frstArchPrmsnDt:item.frstArchPrmsnDt,
// archArea:item.archArea,
// lawTrgtYn:item.lawTrgtYn,
// instlCmptnDt:item.instlCmptnDt,
// instlCst:item.instlCst,
}))
.filter((item: any) => item.rainyObj !== undefined);
setBdstTable(chData);
}
}, [code, rainSttnRes, rainSttn.rainSttHeadList]);
useEffect(() =>{
console.log(rainSttn.rainSttNodeList)
},[rainSttn.rainSttNodeList])
useEffect(() => {
if(rainSttn.excelList.length>0){
if (rainSttn.excelList.length === 0) return;
excelDownload(rainSttn.excelList , '빗물재이용시설 현황','sample_rainSttn.xlsx')
}
}, [rainSttn.excelList]);
const excelClick = useCallback((returnType:ReturnType) => {
let con
if (returnType.sigunValue != '0') {
con = returnType.sigunValue
}else{
con = returnType.sidoValue
}
rainSttnSearch('1', '10000' ,con);
},[rainSttnSearch]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"빗물재이용 시설 현황"} />
<SearchDiv>
<SearchFormLeft>
<SelectBox
className={"col-span-2 w-full h-full text-2xl"}
label={"권역"}
selectClass={""}
selectArray={code.yn}
onSelectValue={() => {}}
value={""}
/>
<SelectBox
className={"col-span-2 w-full h-full text-2xl"}
label={"단위유역"}
selectClass={""}
selectArray={code.yn}
onSelectValue={() => {}}
value={""}
/>
<SelectBox
className={"col-span-2 w-full h-full text-2xl"}
label={"중권역"}
selectClass={""}
selectArray={code.yn}
onSelectValue={() => {}}
value={""}
/>
<SelectBox
className={"col-span-2 w-full h-full text-2xl"}
label={"환경청"}
selectClass={""}
selectArray={code.yn}
onSelectValue={() => {}}
value={""}
/>
<SelectBox
className={"col-span-2 w-full h-full text-2xl"}
label={"시도"}
selectClass={""}
selectArray={code.yn}
onSelectValue={() => {}}
value={""}
/>
<SelectBox
className={"col-span-2 w-full h-full text-2xl"}
label={"시군구"}
selectClass={""}
selectArray={code.yn}
onSelectValue={() => {}}
value={""}
/>
</SearchFormLeft>
<SearchFormRight>
<div className="space-y">
{/* 첫 줄: 버튼 3개 */}
<div className="flex flex-row space-x-2">
<Button size={"sm"} onClick={(e) => {}}>
조회
</Button>
<Button size={"sm"} onClick={() => {}}>
다운로드
</Button>
</div>
<div className="flex flex-row space-x-2 pt-3">
<Button
size={"sm"}
color="green"
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={
<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
let con
if (returnType.sigunValue != '0') {
con = returnType.sigunValue
}else{
con = returnType.sidoValue
}
rainSttnSearch('1', '20' ,con);
}}
excelClick={excelClick}
initClick={function (): void {}}
btnClass={btnClass}
ref={ref}
/>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
@@ -220,7 +140,8 @@ export default function RainSttn() {
<UiTable
headName={[]}
tableData={bdstTable || []}
headlist={sttnCommon.rainSttHeadList}
children={<HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList}/>}
headlist={rainSttn.rainSttHeadList}
pageSize={0}
total={0}
cellClick={undefined}
@@ -228,18 +149,17 @@ export default function RainSttn() {
throw new Error("Function not implemented.");
}}
>
{nodeList}
</UiTable>
</ListDiv>
</div>
</div>
<UiModal
<UiModal
open={isChHead}
onOpenChange={() => {
setIsChHead(!isChHead);
}}
bodyClass={""}
body={<HeadChModal type={'rain'}/>}
body={<HeadChModal type={"rain"} />}
/>
</ContentsDiv>
</>
@@ -0,0 +1,53 @@
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { TableHead, TableRow } from "@common/components/ui";
export const headMakeprfmnc = (
upHeadList: TableUpperProps[],
makeHeadNm: chHeadType[]
) => {
return (
<>
<TableRow>
{upHeadList
.map((head: TableUpperProps) =>
!head.upSequnce ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
rowSpan={2}
key={head.id}
>
{head.title}
</TableHead>
) : head.upSequnce === 1 ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
rowSpan={1}
colSpan={
makeHeadNm.find((ch) => ch.headNm === head.upName)?.length
}
>
{makeHeadNm.find((ch) => ch.headNm === head.upName)?.text}
</TableHead>
) : null
)}
</TableRow>
<TableRow>
{upHeadList
.filter((data) => data.visible != false)
.map((head: TableUpperProps) =>
makeHeadNm.find((ch) => ch.headNm === head.upName) ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
>
{head.title}
</TableHead>
) : null
)}
</TableRow>
</>
);
};
@@ -3,13 +3,13 @@
import { useWrStore } from "@/app/store";
import {
fcltDiv,
type chHeadType,
type rainChkZodType,
type rainChkZodType
} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { excelDownload } from "@/components/lib/func/commom";
import ChkgdExcel from "@/components/ui/modal/chkgdExcel/chkgdExcel";
import ChkgdModal from "@/components/ui/modal/chkgdModal/chkgdModal";
import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable";
import RainChkgdTableModal from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTableModal";
import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable";
import {
ContentsDiv,
@@ -22,85 +22,63 @@ import {
UiModal
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { TableHead, TableRow } from "@common/components";
import { Button } from "@common/components/ui";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
export const headMakeprfmnc = (
upHeadList: TableUpperProps[],
makeHeadNm: chHeadType[]
) => {
return (
<>
<TableRow>
{upHeadList
.map((head: TableUpperProps) =>
!head.upSequnce ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
rowSpan={2}
key={head.id}
>
{head.title}
</TableHead>
) : head.upSequnce === 1 ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
rowSpan={1}
colSpan={
makeHeadNm.find((ch) => ch.headNm === head.upName)?.length
}
>
{makeHeadNm.find((ch) => ch.headNm === head.upName)?.text}
</TableHead>
) : null
)}
</TableRow>
<TableRow>
{upHeadList
.filter((data) => data.visible != false)
.map((head: TableUpperProps) =>
makeHeadNm.find((ch) => ch.headNm === head.upName) ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
>
{head.title}
</TableHead>
) : null
)}
</TableRow>
</>
);
};
//-----------------------
export default function Page() {
const { rainChkgdn, rainChkInit,rainChkDetilUpdate } = useWrStore((state) => {
const { code, rainChkgdn, rainChkInit,rainChkDetilUpdate, rainChkDelete , rainChkExcelDownload } = useWrStore((state) => {
return state;
});
const [isDetail, setIsDetail] = useState(false);
const [isExcel, setIsExcel] = useState(false);
const [isRegExcel, setIsRegExcel] = useState(false);
const [searchTxt, setSearchTxt] = useState<string>();
const [testObj, setTestObj] = useState({});
const [updateRainDetail, setUpdateRainDetail] = useState<rainChkZodType[]>([]);
const [deleteIdx, setDeleteIdx ] = useState<number[]> ([]);
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
const [isModal, setIsModal] = useState({
open: false,
data: {},
});
const cellClick = () => {
if(searchTxt)
rainChkInit(searchTxt,'41')
rainChkInit(searchTxt,'0')
};
useEffect(() => {
if (!rainChkgdn.isInit) {
rainChkInit('2024','0');
setIsModal({data:{}, open:rainChkgdn.isModalClose })
setIsRegExcel(false)
}
}, [rainChkgdn.isInit, rainChkInit]);
useEffect(() => {
excelDownload(rainChkgdn.excelList ,'빗물이용시설 지도점검','sample_rainy.xlsx', 'A1:AN1');
}, [rainChkgdn.excelList]);
const excelClick= useCallback(()=>{
rainChkExcelDownload(code.cityCd, code.sggCd);
}, [rainChkExcelDownload, code.cityCd, code.sggCd]);
const handleClick = useCallback((data:any) => {
if(data) setIsModal({ open: true, data: data });
}, [isModal]);
const clickDelete=(data:number[])=>{
if(data.length>0){
data.forEach((data) =>{
rainChkDelete( String(data) )
})
}
}
return (
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
@@ -109,7 +87,7 @@ export default function Page() {
<SearchDiv>
<SearchFormLeft>
<SearchInput
className="col-span-3 my-7"
className="col-span-3 my-7 !text-xl"
label=" 지도점검년도"
textValue={searchTxt??''}
setText={(e) => {setSearchTxt(e);}}
@@ -134,7 +112,7 @@ export default function Page() {
>
조회
</Button>
<Button size={"sm"} onClick={() => {}}>
<Button size={"sm"} onClick={() => { clickDelete(deleteIdx) }}>
삭제
</Button>
<Button size={"sm"} onClick={() => { rainChkDetilUpdate( updateRainDetail as rainChkZodType[]) }}>
@@ -142,15 +120,13 @@ export default function Page() {
</Button>
</div>
<div className="flex flex-row space-x-2 pt-3">
<Button size={"sm"} onClick={() => {}}>
<Button size={"sm"} onClick={() => {setIsRegExcel(!isRegExcel)}}>
결과등록
</Button>
<Button
color="green"
size={"sm"}
onClick={() => {
setIsExcel(!isDetail);
}}
onClick={excelClick}
>
양식받기
</Button>
@@ -163,24 +139,25 @@ export default function Page() {
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
{selFcltDiv === "RNB" ? <RainChkgdTable detailUp={setUpdateRainDetail} /> : <RswtChkgdTable />}
{selFcltDiv === "RNB" ? <RainChkgdTable deleteData={setDeleteIdx} detailUp={setUpdateRainDetail} handleClick={handleClick} /> : <RswtChkgdTable />}
</ListDiv>
</div>
</div>
<UiModal
open={isDetail}
onOpenChange={setIsDetail}
bodyClass={"w-[40vw] max-w-none"}
body={<ChkgdModal type={selFcltDiv} obj={testObj}></ChkgdModal>}
/>
open={isModal.open}
onOpenChange={() => {
setIsModal({ open: !open, data: {} });
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal type={"RNB"} obj={isModal.data} />}
></UiModal>
<UiModal
open={isExcel}
onOpenChange={setIsExcel}
open={isRegExcel}
onOpenChange={setIsRegExcel}
bodyClass={"w-[40vw] max-w-none"}
body={<ChkgdExcel type={selFcltDiv}></ChkgdExcel>}
/>
<Toaster position="top-center" />
</ContentsDiv>
);
}
+85 -90
View File
@@ -1,38 +1,37 @@
import { getFetch } from "@/components/lib/api";
import type { EnvPartSelectDataType, SelectDataType } from "@common/business_components/ui";
// Description: 공통코드
export type selectArray = {
text: string;
val: string | number;
adstDliStrCd?: string
};
export const yn :selectArray[]=[
export const btnClass= "p-4 m-2 text-white rounded-sm text-lg font-medium "
const yn :SelectDataType[]=[
{val:'Y', text:'Y'},
{val:'N', text:'N'},
]
//공통 건축물 용도
export const bdstUsgCd: selectArray[] = [
{ val: 1, text: "운동장" },
{ val: 2, text: "체육관" },
{ val: 3, text: "공공업무시설" },
{ val: 4, text: "공공기관의청사" },
{ val: 5, text: "아파트" },
{ val: 6, text: "연립주택" },
{ val: 7, text: "다세대주택" },
{ val: 8, text: "기숙사" },
{ val: 9, text: "초등학교" },
{ val: 10, text: "중학교" },
{ val: 11, text: "고등학교" },
{ val: 12, text: "전문대학" },
{ val: 13, text: "대학및대학교" },
{ val: 14, text: "골프장" },
{ val: 15, text: "대규모점포" },
{ val: 16, text: "기타" },
const bdstUsgCd: SelectDataType[] = [
{ val: '-1', text: "확인불가" },
{ val: '1', text: "운동장" },
{ val: '2', text: "체육관" },
{ val: '3', text: "공공업무시설" },
{ val: '4', text: "공공기관의청사" },
{ val: '5', text: "아파트" },
{ val: '6', text: "연립주택" },
{ val: '7', text: "다세대주택" },
{ val: '8', text: "기숙사" },
{ val: '9', text: "초등학교" },
{ val: '10', text: "중학교" },
{ val: '11', text: "고등학교" },
{ val: '12', text: "전문대학" },
{ val: '13', text: "대학및대학교" },
{ val: '14', text: "골프장" },
{ val: '15', text: "대규모점포" },
{ val: '16', text: "기타" },
];
//빗물 집수면 종류 용도
export const rainFcltCd = [
const rainFcltCd = [
{ val: "1", text: "지붕" },
{ val: "2", text: "건물옥상" },
{ val: "3", text: "골프장 연못" },
@@ -45,36 +44,36 @@ export const rainFcltCd = [
{ val: "10", text: "확인불가" },
];
// 중수도 필수 원수종류
export const rswtBdstType: selectArray[] = [
{ text: "숙박업", val: 17 },
{ text: "목욕장업", val: 18 },
{ text: "공장", val: 19 },
{ text: "발전시설", val: 20 },
{ text: "관광단지개발사업", val: 21 },
{ text: "도시개발사업", val: 22 },
{ text: "산업단지개발사업", val: 23 },
{ text: "택지개발사업", val: 24 },
{ text: "대규모점포(대형마트)", val: 25 },
{ text: "대규모점포(전문점)", val: 26 },
{ text: "대규모점포(백화점)", val: 27 },
{ text: "대규모점포(쇼핑센터)", val: 28 },
{ text: "대규모점포(복합쇼핑몰)", val: 29 },
{ text: "물류시설", val: 30 },
{ text: "운수시설(여객자동차터미널)", val: 31 },
{ text: "운수시설(철도시설)", val: 32 },
{ text: "운수시설(공항시설)", val: 33 },
{ text: "운수시설(항만시설)", val: 34 },
{ text: "업무시설(공공업무시설)", val: 35 },
{ text: "업무시설(금융업소)", val: 36 },
{ text: "업무시설(사무소)", val: 37 },
{ text: "업무시설(결혼상담소 등 소개업소)", val: 38 },
{ text: "업무시설(출판사)", val: 39 },
{ text: "업무시설(신문사)", val: 40 },
{ text: "업무시설(오피스텔)", val: 41 },
{ text: "교정시설", val: 42 },
{ text: "방송국", val: 43 },
{ text: "전신전화국", val: 44 },
{ text: "기타", val: 45 },
const rswtBdstType: SelectDataType[] = [
{ text: "숙박업", val: "17" },
{ text: "목욕장업", val: "18" },
{ text: "공장", val: "19" },
{ text: "발전시설", val: "20" },
{ text: "관광단지개발사업", val: "21" },
{ text: "도시개발사업", val: "22" },
{ text: "산업단지개발사업", val: "23" },
{ text: "택지개발사업", val: "24" },
{ text: "대규모점포(대형마트)", val: "25" },
{ text: "대규모점포(전문점)", val: "26" },
{ text: "대규모점포(백화점)", val: "27" },
{ text: "대규모점포(쇼핑센터)", val: "28" },
{ text: "대규모점포(복합쇼핑몰)", val: "29" },
{ text: "물류시설", val: "30" },
{ text: "운수시설(여객자동차터미널)", val: "31" },
{ text: "운수시설(철도시설)", val: "32" },
{ text: "운수시설(공항시설)", val: "33" },
{ text: "운수시설(항만시설)", val: "34" },
{ text: "업무시설(공공업무시설)", val: "35" },
{ text: "업무시설(금융업소)", val: "36" },
{ text: "업무시설(사무소)", val: "37" },
{ text: "업무시설(결혼상담소 등 소개업소)", val: "38" },
{ text: "업무시설(출판사)", val: "39" },
{ text: "업무시설(신문사)", val: "40" },
{ text: "업무시설(오피스텔)", val: "41" },
{ text: "교정시설", val: "42" },
{ text: "방송국", val: "43" },
{ text: "전신전화국", val: "44" },
{ text: "기타", val: "45" }
];
const orgwtKndCd = [
@@ -85,7 +84,7 @@ const orgwtKndCd = [
{ text: "기타", val: "5" },
];
export const chBuCd = [
const chBuCd = [
{ val: "증축", text: "증축" },
{ val: "개축", text: "개축" },
{ val: "재축", text: "재축" },
@@ -96,23 +95,17 @@ export const chBuCd = [
export type comCodeState = {
code: {
isInit: boolean;
chBuCd:selectArray[]
rainFcltCd: selectArray[];
bdstUsgCd: selectArray[];
cityCd: selectArray[];
sggCd: selectArray[];
rvbsnCd:selectArray[];
mdmbsnCd:selectArray[];
lgbsnCd:selectArray[];
lclgvrnmntCd:selectArray[];
orgwtKndCd:selectArray[];
yn:selectArray[];
chBuCd:SelectDataType[]
rainFcltCd: SelectDataType[];
bdstUsgCd: SelectDataType[];
cityCd: SelectDataType[];
sggCd: SelectDataType[];
rvbsnCd:SelectDataType[];
mdmbsnCd:SelectDataType[];
lgbsnCd:SelectDataType[];
lclgvrnmntCd:EnvPartSelectDataType[];
orgwtKndCd:SelectDataType[];
yn:SelectDataType[];
};
};
@@ -121,7 +114,7 @@ export type comCodeType = comCodeState & comCodeActions;
export const getSggCd = async (set: any) => {
const sgg = await getFetch("common", "/addr/sgg");
const sggCd = sgg.map((item: any) => ({
val: Number(item.adstDstrCd),
val:item.adstDstrCd,
text: item.gugun,
}));
set((state: comCodeState) => ({
@@ -134,10 +127,10 @@ export const getSggCd = async (set: any) => {
export const getCityCd = async (set: any) => {
const city = await getFetch("common", "/addr/city");
const cityCd = city.map((item: any) => ({
val: Number(item.adstDstrCd),
val: item.adstDstrCd,
text: item.sido,
}));
cityCd.unshift({val:0,text:'전체'})
cityCd.unshift({val:'0',text:'전체'})
set((state: comCodeState) => ({
code: {
...state.code,
@@ -151,10 +144,10 @@ export const getRegionCd = async (set: any) => {
try{
const rvbsn = await getFetch("common", "/addr/sarea");
const rvbsnCd = rvbsn.map((item: any) => ({
val: Number(item.rvbsnCd),
val: item.rvbsnCd,
text: item.rvbsn,
}));
rvbsnCd.unshift({val:0,text:'전체'})
rvbsnCd.unshift({val:'0',text:'전체'})
set((state: comCodeState) => ({
code: {
...state.code,
@@ -171,10 +164,10 @@ export const getMiddleRegionCd = async (set: any) => {
try{
const mdmbsn = await getFetch("common", "/addr/midArea");
const mdmbsnCd = mdmbsn.map((item: any) => ({
val: Number(item.rvbsnCd),
val: item.rvbsnCd,
text: item.mdmbsn,
}));
mdmbsnCd.unshift({val:0,text:'전체'})
mdmbsnCd.unshift({val:'0',text:'전체'})
set((state: comCodeState) => ({
code: {
...state.code,
@@ -192,10 +185,10 @@ export const getUnitWaterShedCd =async (set: any) => {
try{
const lgbsn = await getFetch("common", "/addr/largeArea");
const lgbsnCd = lgbsn.map((item: any) => ({
val: Number(item.rvbsnCd),
val: item.rvbsnCd,
text: item.lgbsn,
}));
lgbsnCd.unshift({val:0,text:'전체'})
lgbsnCd.unshift({val:'0',text:'전체'})
set((state: comCodeState) => ({
code: {
...state.code,
@@ -214,11 +207,12 @@ export const getEnvPartCd =async (set: any) => {
try{
const lclgvrnmnt = await getFetch('common', '/addr/govArea');
const lclgvrnmntCd = lclgvrnmnt.map((item: any) => ({
val: Number(item.lclgvrnmntCd),
val: item.lclgvrnmntCd,
text: item.lclgvrnmntNm,
adstDliStrCd:item.adstDliStrCd
adstDliStrCd: item.adstDliStrCd || ''
}));
lclgvrnmntCd.unshift({val:0,text:'전체' ,adstDliStrCd:''})
lclgvrnmntCd.unshift({val:'0',text:'전체' ,adstDliStrCd: '' })
set((state: comCodeState) => ({
code: {
...state.code,
@@ -245,7 +239,8 @@ export const comCodeStateExport: comCodeState = {
mdmbsnCd:[],
lgbsnCd:[],
lclgvrnmntCd:[],
yn:yn
yn:yn,
},
};
@@ -262,13 +257,13 @@ export const codeActionExport: (set: any) => comCodeActions = (set: any) => {
const sgg = await getFetch("common", "/addr/sgg");
const sggCd = sgg.map((item: any) => ({
val: Number(item.adstDstrCd),
val: item.adstDstrCd,
text: item.gugun,
}));
const city = await getFetch("common", "/addr/city");
const cityCd = city.map((item: any) => ({
val: Number(item.adstDstrCd),
val: item.adstDstrCd,
text: item.sido,
}));
@@ -281,11 +276,11 @@ export const codeActionExport: (set: any) => comCodeActions = (set: any) => {
}));
},
divCityCd: async(cd: number) => {
divCityCd: async(cd: string) => {
set((state: comCodeState) => ({
code: {
...state.code,
sggCd:state.code.sggCd.filter((item) => { return Number(item.val.toString().slice(0,2)) === cd }),
sggCd:state.code.sggCd.filter((item) => { return item.val.toString().slice(0,2) === cd }),
},
}));
},
+23
View File
@@ -0,0 +1,23 @@
export type CommonTableProps = {
id: string;
title: string;
upName?: string;
upSequnce?: number;
row?: number;
rowSpan?: number;
colSpan?: number;
visible?: boolean;
};
export type TableUpperProps = {
id: string;
title: string;
upName?: string;
upSequnce?: number;
edit?:boolean;
visible?:boolean;
rowSpan?: true;
type?: string;
};
@@ -0,0 +1,133 @@
import type { SelectDataType } from "@common/business_components";
import type { rainChkZodType } from ".";
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { excelSerialToDateString } from "@/components/lib/func/commom";
const useTypes = [
"조경용수",
"청소화장실용수",
"세척살수용수",
"농업용수",
"공업용수",
"친수용수",
"기타",
];
export type Buildingtype = {
bdstInfoPk: number;
ctpvCd: 1;
sggCd: 1001;
daddr: "string3";
bdstNm: "string";
frstArchPrmsnDt: "2025-03-25";
archArea: 0;
regDt: "2025-04-16";
rgtr: null;
mdfcnDt: "2025-04-16";
mdfr: null;
};
export const buildingToExcelType = (
buildings: Buildingtype[],
sidoCode: SelectDataType[],
sggCdoe: SelectDataType[]
) => {
const excelData: string[][] = [];
buildings.forEach((building) => {
useTypes.forEach((useType) => {
excelData.push([
building.bdstInfoPk.toString(),
sidoCode.find((sido) => sido.val === building.ctpvCd.toString())
?.text || "",
sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text ||
"",
building.daddr,
building.bdstNm,
"",
"",
"",
"",
useType,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
]);
});
});
return excelData;
};
export const excelToRainChkData = (
excelData: any,
year: string,
) => {
const rainChkgdData: rainChkZodType[] = excelData.map((item: any) => {
const makeGuidDetail = Array.from({ length: 12 }, (_, i) => {
let month = `${i + 1}`;
const splyData = item[`보급_${month}월`];
const ruseData = item[`빗물_${month}월`];
if (month.length < 2) month = "0" + month;
return {
utztnUsgCd: item["이용용도"],
ym: year + month,
chckYmd: item["점검일"] ,
splyUswtrUtztnQnt: splyData !== "" ? splyData : 0,
ruseFcltUtztnQnt: ruseData !== "" ? ruseData : 0,
flg: "RNB",
};
});
return {
bdstRuseFcltFk: Number(item["NO"]),
chckYmd: item["점검일"] ,
spwtPositn: item["유량측정방법"],
rgtr: TEST_UUID,
oilqMeasMthd: item["운영관리형태"],
anlOperCst: Number(item["연간운영비(원/년)"])??0,
operMngCd: item["유량측정방법"],
guideDetails: makeGuidDetail,
rainyDetails: [
{
utztnUsgCd: item["이용용도"],
ph: Number(item["PH"])??0,
trbt: Number(item["탁도"])??0,
grssClfg: Number(item["총대장균군수"])??0,
etc: item["기타"] ?? "", // 필드 누락 방지
vltnDt: item["과태료 부과일(위반일)"],
vltnMttr: item["위반사항"],
levyAmt: Number(item["과태료부과금액(천원)"])??0,
rgtr: TEST_UUID,
},
],
};
});
return rainChkgdData;
};
@@ -2,30 +2,35 @@ import {
TEST_UUID,
type TableUpperProps,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { getFetch, postFectch, putFectch } from "@/components/lib/api";
import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api";
import type { SelectDataType } from "@common/business_components/ui";
import { z } from "zod";
import { buildingToExcelType, excelToRainChkData } from "./excel";
import toast from "react-hot-toast";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
const guideDetail=z.object({
chkgdnFk: z.number().nullable(),
utztnUsgCd: z.string(),
chckYmd: z.string(),
ym: z.string(),
splyUswtrUtztnQnt: z.number(),
ruseFcltUtztnQnt: z.number(),
flg: z.string(),
})
export const rainChkZod = z.object({
chkgdnPk: z.number(),
chkgdnPk: z.number().nullable(),
bdstRuseFcltFk: z.number(),
chckYmd: z.string(),
prcsCpct: z.number(),
spwtPositn: z.string(),
regDt: z.string(),
rgtr: z.string(),
prcsCpct: z.number().nullable(),
spwtPositn: z.string().nullable(),
regDt: z.string().nullable(),
rgtr: z.string().nullable(),
mdfcnDt: z.string().nullable(),
mdfr: z.string().nullable(),
flg: z.string(),
flg: z.string().nullable(),
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(),
})
guideDetail
),
building: z.object({
bdstInfoPk: z.number(),
@@ -39,20 +44,20 @@ export const rainChkZod = z.object({
rgtr: z.string().nullable(),
mdfcnDt: z.string().nullable(),
mdfr: z.string().nullable(),
}),
}).nullable() ,
rainyDetails: z.array(
z.object({
chkgdnFk: z.number(),
chkgdnFk: z.number().nullable(),
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(),
ph: z.number().nullable(),
trbt: z.number().nullable(),
grssClfg: z.number().nullable(),
etc: z.string().nullable(),
vltnDt: z.string().nullable(),
vltnMttr: z.string().nullable(),
levyAmt: z.number().nullable(),
regDt: z.string().nullable(),
rgtr: z.string().nullable(),
mdfcnDt: z.string().nullable(),
mdfr: z.string().nullable(),
})
@@ -63,9 +68,22 @@ export type rainChkZodType = z.infer<typeof rainChkZod>;
export const rainRegExcel = z.object({
bdstInfoPk: z.number().default(111111111),
chckYmd: z.date().default(new Date()),
file: z.instanceof(File).optional(),
});
chckYr: z.string()
.default("")
.refine(
(year) => year.length === 0 || /^\d{4}$/.test(year),
{ message: "4자리 연도만 입력하세요" }
)
.refine(
(year) => {
if (year.length === 0) return true; // 빈 문자열은 통과
const numYear = Number(year);
return !isNaN(numYear) && numYear <= new Date().getFullYear();
},
{ message: "현재 년도보다 높은 수를 입력할 수 없습니다." }
),
file: z.instanceof(File).optional(),
});
export const fcltDiv = [
{ val: "RST", text: "중수도시설" },
@@ -88,15 +106,16 @@ export const rainHeadNm: chHeadType[] = [
];
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: "oilqMeasMthd", title: "유량측정방법", rowSpan: true },
{ id: "anlOperCst", title: "연간운영비(원/년)", rowSpan: true },
{ id: "dtfcltCpct", title: "빗물저류조용량(m³)", rowSpan: true },
{ id: "chckYmd", title: "점검일", rowSpan: true },
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" },
@@ -283,6 +302,8 @@ export type rainChkgdnState = {
splHeadList: TableUpperProps[];
rswtDetailHeadList: TableUpperProps[];
isInit: boolean;
isModalClose:boolean;
excelList:[];
};
};
@@ -290,6 +311,9 @@ type rainChkgdnActions = {
rainChkInit: (sggCd: string, searchTxt: string) => void;
rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise<void>;
rainChkGuidUpdate(rainChk: rainChkZodType): Promise<void>;
rainChkExcelDownload(sidoCode: SelectDataType[],sggCode: SelectDataType[]): Promise<void>
rainChkExcelDataUPload(excelData:rainChkZodType[]) : Promise<void>
rainChkDelete(chkgdnPk:string) :Promise<void>
};
export type rainChkgdnType = rainChkgdnState & rainChkgdnActions;
@@ -303,6 +327,8 @@ export const rainChkgdnStateExport: rainChkgdnState = {
ruseHeadList: ruseHeadList,
rswtDetailHeadList: rswtDetailHeadList,
isInit: false,
isModalClose:false,
excelList:[]
},
};
@@ -340,6 +366,37 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
set: any
) => {
return {
rainChkExcelDownload:async(sidoCode:SelectDataType[], sggCode:SelectDataType[])=>{
const data = await getFetch(fetchType.WR, "/reuseFc/building/RNB/0")
// const excelList = buildingToExcelType(data, sidoCode, sggCode);
const excelList = buildingToExcelType(data, sidoCode, sggCode);
set((state: rainChkgdnState) => ({
rainChkgdn: {
...state.rainChkgdn,
excelList:excelList
},
}));
},
rainChkExcelDataUPload: async(excelData:rainChkZodType[] ) =>{
try{
const res = await postFectch("/reuseChk/rainyExcel", excelData);
if (res.ok) {
ToastFormUi({body:"지도점검 등록이 완료되었습니다. " ,title:'지도점검 등록'})
}
const rainChkRes = await initFetch('2024', '0');
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
}catch(error){
console.log(error);
ToastFormUi({body:"지도점검 등록이 실패되었습니다." ,title:'지도점검 등록'})
}
},
rainChkInit: async (searchTxt: string, sggCd: string) => {
try {
const rainChkRes = await initFetch(searchTxt, sggCd);
@@ -361,11 +418,9 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
const res = await postFectch("/reuseChk/rainyExcel", rainChk);
if (res.ok) {
alert(" 수정이 완료되었습니다.");
ToastFormUi({body:"지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. " ,title:'지도점검 수정'})
}
const rainChkRes = await initFetch('2024', '0');
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
@@ -379,13 +434,11 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
}
},
rainChkGuidUpdate: async (rainChk: rainChkZodType) => {
try{
//const chData = await makeMdfrChk(rainChk, "guideDetails", "rainDetil");
const res = await putFectch("/reuseChk/rainy", rainChk);
if (res.ok) {
alert(" 수정이 완료되었습니다.");
ToastFormUi({body:"지도점검 수질 및 과태료 수정이 완료되었습니다. " ,title:'지도점검 수정'})
}
const rainChkRes = await initFetch('2024', '0');
return set((state: rainChkgdnState) => ({
@@ -400,6 +453,30 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
}
},
rainChkDelete: async (chkgdnPk:string) =>{
try{
const res = await deleteFectch(`/reuseChk/rainy/${chkgdnPk}`,'');
if(res.ok){
ToastFormUi({body:"삭제가 완료되었습니다. " ,title:'지도점검 삭제'})
}
const rainChkRes = await initFetch('2024', '0');
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
}catch(error){
ToastFormUi({body:"삭제를 실패했습니다.. " ,title:'지도점검 삭제'})
}
}
@@ -1,5 +1,5 @@
import { getFetch, postFectch, putFectch } from "@/components/lib/api";
import { upHeadList, type bdstAll, type chgBuilding, type TableUpperProps } from "../rainReg";
import { upHeadList, type chgBuilding, type TableUpperProps } from "../rainReg";
import { z } from "zod";
import { makeMdfr, makeRstr } from "../bdstReg";
@@ -1,11 +1,8 @@
import type { selectArray } from "@/app/store/common/code";
import { getFetch, postFectch, putFectch } from "@/components/lib/api";
import { z } from "zod";
import { makeMdfr, makeRstr } from "../bdstReg";
export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e'
export const rainZod = z.object({
bdstInfoPk: z.number().optional(),
ctpvCd: z.number().default(0),
@@ -23,11 +20,11 @@ export const rainZod = z.object({
bdstRuseFcltPk: z.number().nullish(),
bdstInfoFk:z.number().nullish(),
instlCmptnDt: z.coerce.date().default(() => new Date()),
instlCst: z.number().default(0),
instlCst: z.number().nullish(),
operMngCd: z.string().optional().default(""),
anlOperCst: z.number().default(0),
instlCstSprtYn: z.string().default(""),
instlCstSprtAmt: z.number().nullish(),
instlCstSprtAmt: z.number().nullish(),
grntchBdstCertYn: z.enum(["Y", "N"]).nullish(),
grntchBdstCertYr: z.string().default("")
.refine((year)=> year.length===0 || /^\d{4}$/.test(year),{
@@ -35,7 +32,7 @@ export const rainZod = z.object({
}),
grntchBdstCertNo: z.string().default(""),
grntchBdstCertGrd: z.string().default(""),
crgRdctYn: z.enum(["Y", "N"]), // 안쓰는 값
crgRdctYn: z.enum(["Y", "N"]).nullish(), // 안쓰는 값
crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
@@ -75,8 +72,6 @@ export const rainZod = z.object({
).default([])
});
export type chgBuilding={
bdstInfoFk?: number|null,
archChgPrmsnDt?: Date,
@@ -85,11 +80,7 @@ export type chgBuilding={
rgtr?:string|null;
mdfr?:string|null;
}
export type customRainBdst = z.infer<typeof rainZod>
export type TableUpperProps = {
id: string;
title: string;
@@ -101,54 +92,38 @@ export type TableUpperProps = {
type?: string;
};
export type TableTripleProps = {
id: string;
title: string;
upName: string[];
upSequnce: number[];
edit?:boolean;
visible?:boolean;
};
export const upHeadList: TableUpperProps[] = [
{ id: "cityText", title: "시도" },
{ id: "sggText", title: "시군구" },
{ id: "bdstNm", title: "시설명" },
{ id: "daddr", title: "위치" },
{ id: "bdsgUsgText", title: "건축물용도" },
// { id: "bdstUsgCd", title: "건축물용도" },
{ id: "frstArchPrmsnDt", title: "최초건축허가일" },
{ id: "archArea", title: "건축면적" },
{ id: "lawTrgtYn", title: "법적의무대상여부" },
{ id: "bdstChgYn", title: "건축물변경여부" },
// { id: "archChgPrmsnDt", title: "허가일", upName: "upChangeRe", upSequnce: 2 },
// { id: "archChgArea", title: "면적", upName: "upChangeRe", upSequnce: 3 },
];
const rainRes: customRainBdst[] = [];
export const selectClass = "w-full h-full text-2xl";
const selectYN = [
{ text: "Y", val: "1" },
{ text: "N", val: "2" },
];
export const selectClass = "w-full h-full !text-2xl";
export type rainFacState = {
rain: {
isInit: boolean;
upHeadList: TableUpperProps[];
selectYN: selectArray[];
rainRes: customRainBdst[];
// regRainForm:customRainBdst,
};
};
type rainFacSActions = {
init: (txt:string|undefined) => void;
rainSearTxt: (txt:string) => void;
rainReg: (data: customRainBdst) => void;
rainUpdate: (data: customRainBdst) => void;
initRain: (code:string|number) => void;
getRainData:(pageNation:number, code:string|number) =>void;
rainSearch: (txt:string,pageNation:number,code:string|number) => void;
rainBdstReg: (data: customRainBdst, code:string|number) => void;
rainBdstUpdate: (data: customRainBdst, code:string|number) => void;
};
export type rainFacType = rainFacState & rainFacSActions;
@@ -158,37 +133,42 @@ export const rainFacStateExport: rainFacState = {
isInit: false,
rainRes: rainRes,
upHeadList: upHeadList,
selectYN: selectYN,
//regRainForm:regRainForm,
},
};
const initFetch = async (txt:string|undefined) => {
const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/20/41` +(txt? `/${txt}`:''));
const chRainRes = rainRes.map((item: customRainBdst) => {
return {
...item,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
} })
return chRainRes;
const initFetch = async (code:string|number) => {
const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/20/${code}`);
return rainRes;
};
export const rainFacActionsExport: (set: any) => rainFacSActions = (
set: any
) => {
return {
init: async (txt:string|undefined) => {
getRainData: async(pageNation:number, code:string|number) =>{
try{
const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/${pageNation}/20/${code}`);
// 여기서 상태 업데이트
return set((state: rainFacState) => ({
...state,
rain: {
...state.rain,
rainRes: rainRes,
isInit: false,
},
}));
}catch(e){
console.log(e)
}
},
initRain: async (code:string|number) => {
try {
// 파라이터 수정 통합관리자 =0, 시관리자=시코드, 시군구 관리자= 시군구 코드 를 세번째 파라미터로 지정 / 건축물 서치가 있을경우 4번째 파라미터로 던지기 즉 1/20/42(서울시)/영현빌딩 이런식으로)
const rainRes = await initFetch(txt);
const rainRes = await initFetch(code);
// 여기서 상태 업데이트
return set((state: rainFacState) => ({
...state,
@@ -200,14 +180,12 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
}));
} catch (error) {
console.log("error", error);
} finally {
console.log("finally");
}
}
},
rainSearTxt: async(txt:string) =>{
rainSearch: async(txt:string,pageNation:number) =>{
try{
const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/1/20/41` +(txt? `/${txt}`:''))
const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/41` +(txt? `/${txt}`:''))
set((state: rainFacState) => {
return {
rain: {
@@ -221,7 +199,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
console.log("error", erTxt)
}
},
rainReg: async (data: customRainBdst) => {
rainBdstReg: async (data: customRainBdst,code:string|number) => {
try {
const test =await makeRstr(data);
@@ -248,7 +226,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
alert("등록이 완료되었습니다.");
}
}
const rainRes = await initFetch(undefined);
const rainRes = await initFetch(code);
set((state: rainFacState) => ({
...state,
rain: {
@@ -263,18 +241,15 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
} finally {
}
},
rainUpdate: async (data: customRainBdst) => {
rainBdstUpdate: async (data: customRainBdst,code:string|number) => {
try {
const chData =await makeMdfr(data);
const res = await putFectch("/reuseFc/rainyInfo", chData);
console.log('rainUpdate', res);
if(res.ok){
alert(" 수정이 완료되었습니다.")
}
const rainRes = await initFetch(undefined);
const rainRes = await initFetch(code);
set((state: rainFacState) => ({
...state,
rain: {
@@ -1,5 +1,5 @@
import { getFetch, postFectch, putFectch } from "@/components/lib/api";
import { upHeadList, type chgBuilding, type TableUpperProps } from "../rainReg";
import { upHeadList, type chgBuilding, type TableUpperProps } from "../rainReg";
import { z } from "zod";
import { makeMdfr, makeRstr } from "../bdstReg";
@@ -15,73 +15,77 @@ export const rswtZod = z.object({
archArea: z.number().default(0),
archChgArea: z.number().default(0),
rgtr:z.string().nullish().default(null),
mdfr:z.string().nullish().default(null),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
reuseBuilding: z.array(
z.object({
bdstRuseFcltPk: z.number().nullish(),
bdstInfoFk: z.number().nullish(),
instlCmptnDt: z.coerce.date().default(() => new Date()),
instlCst: z.number().default(0),
operMngCd: z.string().nullish().default(""),
reuseBuilding: z
.array(
z.object({
bdstRuseFcltPk: z.number().nullish(),
bdstInfoFk: z.number().nullish(),
instlCmptnDt: z.coerce.date().default(() => new Date()),
instlCst: z.number().default(0),
operMngCd: z.string().nullish().default(""),
anlOperCst: z.number().default(0),
instlCstSprtYn: z.enum(["Y", "N"]),
instlCstSprtAmt: z.number().default(0),
anlOperCst: z.number().default(0),
instlCstSprtYn: z.enum(["Y", "N"]),
instlCstSprtAmt: z.number().default(0),
grntchBdstCertYn: z.enum(["Y", "N"]),
grntchBdstCertYr: z.string().default("")
.refine((year)=> year.length===0 ||/^\d{4}$/.test(year),{
message:'4자리 연도만 입력하세요'
}),
grntchBdstCertNo: z.string().default(""),
grntchBdstCertGrd: z.string().default(""),
crgRdctYn: z.enum(["Y", "N"]), // 안쓰는 값
crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
bdstUsgCd: z.number().default(0),
lawTrgtYn: z.string().default(""),
rgtr:z.string().nullish().default(null),
mdfr:z.string().nullish().default(null),
grntchBdstCertYn: z.enum(["Y", "N"]),
grntchBdstCertYr: z
.string()
.default("")
.refine((year) => year.length === 0 || /^\d{4}$/.test(year), {
message: "4자리 연도만 입력하세요",
}),
grntchBdstCertNo: z.string().default(""),
grntchBdstCertGrd: z.string().default(""),
rswtrObj: z.object({
bdstRuseFcltFk: z.number().nullish(),
wtrUsqty: z.number().default(0),
oblgTrgtWtrUsqty: z.number().nullish().default(0),
orgwtKndCd: z.string().default(""),
filtrTrtmfctProcs: z.string().default(""),
filtrTrtmfctUsgCd: z.string().default(""),
rswtrUsqty: z.number().default(0),
altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(),//안쓰는값
altUswtrKndCd: z.string().default(""),//안쓰는값
altUswtrUtztnQnt: z.number().default(0),//안쓰는값
altUswtrIdntyMthdCd: z.string().default(""),//안쓰는값
rgtr:z.string().nullish().default(null),
mdfr:z.string().nullish().default(null),
}).default({})
})
).default([]),
crgRdctYn: z.enum(["Y", "N"]), // 안쓰는 값
crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
bdstUsgCd: z.number().default(0),
lawTrgtYn: z.string().default(""),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
rswtrObj: z
.object({
bdstRuseFcltFk: z.number().nullish(),
wtrUsqty: z.number().default(0),
oblgTrgtWtrUsqty: z.number().nullish().default(0),
orgwtKndCd: z.string().default(""),
filtrTrtmfctProcs: z.string().default(""),
filtrTrtmfctUsgCd: z.string().default(""),
rswtrUsqty: z.number().default(0),
altUswtrUtztnYn: z.enum(["Y", "N"]).nullish(), //안쓰는값
altUswtrKndCd: z.string().default(""), //안쓰는값
altUswtrUtztnQnt: z.number().default(0), //안쓰는값
altUswtrIdntyMthdCd: z.string().default(""), //안쓰는값
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
})
.default({}),
})
)
.default([]),
chgBuilding: z
.array(
z.object({
bdstInfoFk: z.number().nullish(),
archChgPrmsnDt: z.coerce.date() ,
archChgArea: z.string().default("-"),
bdstChgNm: z.string().default(""),
rgtr:z.string().nullish().default(null),
mdfr:z.string().nullish().default(null),
})
)
.default([]),
.array(
z.object({
bdstInfoFk: z.number().nullish(),
archChgPrmsnDt: z.coerce.date(),
archChgArea: z.string().default("-"),
bdstChgNm: z.string().default(""),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
})
)
.default([]),
});
export type customRswtBdst = z.infer<typeof rswtZod>
export type customRswtBdst = z.infer<typeof rswtZod>;
const rswtRes: customRswtBdst[] = [];
@@ -93,9 +97,11 @@ export type rswtFacState = {
};
};
type rswtFacSActions = {
initRswt: (txt: string | undefined) => void;
rswtUpdate: (data: customRswtBdst) => void;
rswtReg: (data: customRswtBdst) => void;
initRswt: (code:string|number) => void;
rswtBdstUpdate: (data: customRswtBdst,code:string|number) => void;
getRswtBdstData:(pageNation:number, code:string|number) =>void;
rswtBdstSearch:(txt:string,pageNation:number, code:string|number) =>void;
rswtBdstReg: (data: customRswtBdst,code:string|number) => void;
};
export type rswtFacType = rswtFacState & rswtFacSActions;
@@ -108,25 +114,58 @@ export const rswtFacStateExport: rswtFacState = {
},
};
const initFetch = async (txt: string | undefined) => {
const rswtRes =await getFetch(
const initFetch = async (code:string|number) => {
const rswtRes = await getFetch(
"wr",
`/reuseFc/waterreuseFc/1/20/41` + (txt ? `/${txt}` : "")
);
const chRswtRes = rswtRes.map((item: customRswtBdst) => {
return {
...item,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
} })
return chRswtRes;
`/reuseFc/waterreuseFc/1/20/${code}`)
return rswtRes;
};
export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
set: any
) => {
return {
initRswt: async (txt: string | undefined) => {
rswtBdstSearch: async(txt:string,pageNation:number,code:string|number) =>{
try{
const rswtRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/${code}` +(txt? `/${txt}`:''))
set((state: rswtFacState) => {
return {
...state,
rswt: {
...state.rswt,
rswtRes: rswtRes,
isInit: false,
},
};
})}
catch(erTxt){
console.log("error", erTxt)
}
},
getRswtBdstData: async (pageNation: number, code: string | number) => {
try {
const rswtRes = await initFetch(txt);
const rswtRes = await getFetch(
"wr",
`/reuseFc/waterreuseFc/${pageNation}/20/${code}`
);
console.log(pageNation)
// 여기서 상태 업데이트
return set((state: rswtFacState) => ({
...state,
rswt: {
...state.rswt,
rswtRes: rswtRes,
isInit: false,
},
}));
} catch (e) {
console.log(e);
}
},
initRswt: async (code: string | number) => {
try {
const rswtRes = await initFetch(code);
return set((state: rswtFacState) => ({
...state,
rswt: {
@@ -139,71 +178,72 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
console.log(error);
}
},
rswtUpdate: async (data: customRswtBdst) => {
try {
const chData=await makeMdfr(data)
const res = await putFectch("/reuseFc/waterreuseFc", chData);
if (res.ok) {
alert("등록이 완료되었습니다.");
}
const rswtRes = await initFetch(undefined);
set((state: rswtFacState) => ({
...state,
rain: {
...state.rswt,
rswtRes: rswtRes,
isInit: false,
},
}));
} catch (errorUpdate) {
alert("업데이트 오류입니다. " + (errorUpdate instanceof Error ? errorUpdate.message : ""));
} finally {
}
rswtBdstUpdate: async (data: customRswtBdst, code:string|number) => {
try {
const chData = await makeMdfr(data);
const res = await putFectch("/reuseFc/waterreuseFc", chData);
if (res.ok) {
alert("등록이 완료되었습니다.");
}
const rswtRes = await initFetch(code);
set((state: rswtFacState) => ({
...state,
rain: {
...state.rswt,
rswtRes: rswtRes,
isInit: false,
},
}));
} catch (errorUpdate) {
alert(
"업데이트 오류입니다. " +
(errorUpdate instanceof Error ? errorUpdate.message : "")
);
} finally {
}
},
rswtReg: async (data: customRswtBdst) => {
try {
const chData=await makeRstr(data)
const res = await postFectch("/reuseFc/waterreuseFc", chData);
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) => ({
...item,
bdstInfoFk: chPK,
})
);
const chch = postFectch("/reuseFc/chgBuilding", makeCh);
return chch;
rswtBdstReg: async (data: customRswtBdst,code:string|number) => {
try {
const chData = await makeRstr(data);
const res = await postFectch("/reuseFc/waterreuseFc", chData);
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) => ({
...item,
bdstInfoFk: chPK,
})
.then((chch: any) => {
if (chch.ok) {
alert("등록이 완료되었습니다.");
}
});
}else{
alert("등록이 완료되었습니다.");
}
}
const rainRes = await initFetch(undefined);
set((state: rswtFacState) => ({
...state,
rain: {
...state.rswt,
rswtRes: rswtRes,
isInit: false,
},
}));
} catch (e) {
console.log("e", e);
alert("등록 오류입니다.");
} finally {
);
const chch = postFectch("/reuseFc/chgBuilding", makeCh);
return chch;
})
.then((chch: any) => {
if (chch.ok) {
alert("등록이 완료되었습니다.");
}
});
} else {
alert("등록이 완료되었습니다.");
}
},
}
const rainRes = await initFetch(code);
set((state: rswtFacState) => ({
...state,
rain: {
...state.rswt,
rswtRes: rswtRes,
isInit: false,
},
}));
} catch (e) {
console.log("e", e);
alert("등록 오류입니다.");
} finally {
}
},
};
};
@@ -0,0 +1,169 @@
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { TableUpperProps } from "../../fcltReg/rainReg";
export const pbnSttHeadNmExport: chHeadType[] = [
{ headNm: "catchment", text: "유역", length: 3 },
{ headNm: "adminDiv", text: "행정구역", length: 2 },
{ headNm: "rusSup", text: "재이용수공급가능량", length: 3 },
{ headNm: "yearResult", text: "연간실적정보(m³)", length: 3 },
{ headNm: "mngInfo", text: "운영정보", length: 4 },
];
// id는 다확인해야함
export const pbnSttHeadListExport: TableUpperProps[] = [
{ id: "a", title: "권역", upName: "catchment", upSequnce: 1, visible: true },
{
id: "aaa",
title: "단위유역",
upName: "catchment",
upSequnce: 2,
visible: true,
},
{
id: "aaaa",
title: "중권역",
upName: "catchment",
upSequnce: 3,
visible: false,
},
{ id: "operMngCd", title: "환경청", visible: true },
{
id: "cityText",
title: "시도",
upName: "adminDiv",
upSequnce: 1,
visible: false,
},
{
id: "sggText",
title: "시군구",
upName: "adminDiv",
upSequnce: 2,
visible: true,
},
{ id: "bdnstNm", title: "시설명", visible: true },
{ id: "locDiv", title: "지역구분", visible: true },
{ id: "phone", title: "전화번호", visible: true },
{ id: "fcltQuantity", title: "시설용량(톤/일)", visible: true },
{ id: "rusNm", title: "재이용시설명", visible: true },
{
id: "fcltCpct",
title: "시설용량(m³/일)",
upName: "rusSup",
upSequnce: 1,
visible: true,
},
{
id: "trbt",
title: "하수처리량(m³/일)",
upName: "rusSup",
upSequnce: 2,
visible: true,
},
{
id: "ruseCpct",
title: "재이용량(m³/일)",
upName: "rusSup",
upSequnce: 3,
visible: true,
},
{
id: "total",
title: "합계",
upName: "yearResult",
upSequnce: 1,
visible: true,
},
{
id: "ithlWtr",
title: "장내용수",
upName: "yearResult",
upSequnce: 2,
visible: true,
},
{
id: "othlWtr",
title: "장외용수",
upName: "yearResult",
upSequnce: 3,
visible: true,
},
{
id: "mngMeth",
title: "운영방식",
upName: "mngInfo",
upSequnce: 1,
visible: true,
},
{
id: "rprtvBzenty",
title: "대행업체",
upName: "mngInfo",
upSequnce: 2,
visible: true,
},
{
id: "firstDay",
title: "시작일",
upName: "mngInfo",
upSequnce: 3,
visible: true,
},
{
id: "LastDay",
title: "종료일",
upName: "mngInfo",
upSequnce: 4,
visible: true,
},
];
// 참고용 지워야함.
// rainChSttnHead: async (checkList: string[], type: string) => {
// const headList =
// type === "pbn"
// ? pbnSttHeadList
// : type === "rain"
// ? rainSttHeadList
// : null;
// let chNm = type === "pbn" ? pbnSttHeadNm : rainSttNodeList;
// headList?.forEach((item) => {
// if (checkList.find((ch) => ch === item.id)) {
// item.visible = false;
// if (item.upName) {
// const upNames = Array.isArray(item.upName)
// ? item.upName
// : [item.upName];
// upNames?.forEach((up) => {
// chNm.find((ch) => {
// if (ch.headNm === up) {
// ch.length = ch.length - 1;
// }
// });
// });
// }
// }
// });
// set((state: rainSttnState) => ({
// sttnCommon: {
// ...state.sttnCommon,
// pbnSttHeadList:
// type === "pbn" ? headList : state.sttnCommon.pbnSttHeadList,
// rainSttHeadList:
// type === "rain" ? headList : state.sttnCommon.rainSttHeadList,
// rainSttNodeList:
// type === "rain" ? chNm : state.sttnCommon.rainSttNodeList,
// pbnSttHeadNm: type === "rain" ? chNm : state.sttnCommon.pbnSttHeadNm,
// },
// }));
// },
// };
// };
@@ -0,0 +1,33 @@
import type { customRainBdst } from "../../fcltReg/rainReg";
export const excelSttnParsing = (data: customRainBdst[]): string[][] => {
const excelExportData: string[][] = [];
data.forEach((item) => {
excelExportData.push([
String(item.ctpvCd),
String(item.sggCd),
item.bdstNm ?? "",
item.daddr ?? "",
String(item.bdstInfoPk ?? ""),
String(item.frstArchPrmsnDt ?? ""),
String(item.archArea ?? ""),
String(item.reuseBuilding?.[0]?.lawTrgtYn ?? ""),
String(item.reuseBuilding?.[0]?.instlCmptnDt ?? ""),
String(item.reuseBuilding?.[0]?.instlCst ?? ""),
item.reuseBuilding?.[0]?.rainyObj?.pntfColKnd ?? "",
String(item.reuseBuilding?.[0]?.rainyObj?.pntfColArea ?? ""),
String(item.reuseBuilding?.[0]?.rainyObj?.filtrTrtmfctYn ?? ""),
String(item.reuseBuilding?.[0]?.rainyObj?.filtrTrtmfctCpct ?? ""),
String(item.reuseBuilding?.[0]?.rainyObj?.filtrTrtmfctPrs ?? ""),
String(item.reuseBuilding?.[0]?.rainyObj?.dtfcltCpct ?? ""),
String(item.reuseBuilding?.[0]?.instlCstSprtYn ?? ""),
String(item.reuseBuilding?.[0]?.instlCstSprtAmt ?? ""),
String(item.reuseBuilding?.[0]?.grntchBdstCertYn ?? ""),
String(item.reuseBuilding?.[0]?.grntchBdstCertYr ?? ""),
String(item.reuseBuilding?.[0]?.grntchBdstCertNo ?? ""),
String(item.reuseBuilding?.[0]?.grntchBdstCertGrd ?? "")
]);
});
return excelExportData;
};
@@ -0,0 +1,420 @@
import { z } from "zod";
export const rainSttnHeadListType = z.array(
z.object({
id: z.string(),
title: z.string(),
visible: z.boolean(),
})
);
export const rainSttHeadListExport: z.infer<typeof rainSttnHeadListType> = [
{
id: "cityText",
title: "시도",
visible: true,
},
{
id: "sggText",
title: "시군구",
visible: true,
},
{
id: "bdstNm",
title: "건축물명",
visible: true,
},
{
id: "daddr",
title: "주소",
visible: true,
},
{
id: "bdstUsgCd",
title: "건축물용도코드",
visible: true,
},
{
id: "frstArchPrmsnDt",
title: "최초건축허가일시",
visible: true,
},
{
id: "archArea",
title: "건축면적",
visible: true,
},
{
id: "lawTrgtYn",
title: "법적의무대상여부",
visible: true,
},
{
id: "instlCmptnDt",
title: "설치완료일시",
visible: true,
},
{
id: "instlCst",
title: "설치비용",
visible: true,
},
{
id: "pntfColKnd",
title: "집수지점종류",
visible: true,
},
{
id: "pntfColArea",
title: "집수지점면적",
visible: true,
},
{
id: "dtfcltCpct",
title: "저류조용량",
visible: true,
},
{
id: "filtrTrtmfctYn",
title: "여과처리시설유무",
visible: true,
},
{
id: "filtrTrtmfctCpct",
title: "여과처리시설용량",
visible: true,
},
{
id: "filtrTrtmfctPrs",
title: "여과처리시설처리공정",
visible: true,
},
{
id: "instlCstSprtYn",
title: "설치지원비용여부",
visible: true,
},
{
id: "instlCstSprtAmt",
title: "설치지원비용",
visible: true,
},
{
id: "grntchBdstCertYn",
title: "녹색건축물인증여부",
visible: true,
},
{
id: "grntchBdstCertYr",
title: "녹색건축물인증년도",
visible: true,
},
{
id: "grntchBdstCertNo",
title: "녹색건축물인증번호",
visible: true,
},
{
id: "grntchBdstCertGrd",
title: "녹색건축물인증등급",
visible: true,
},
];
// id는 다확인해야함
export const rainSttNodeListExport: CommonTableProps[] = [
{
id: "bdnstInfo",
title: "1.건축물정보",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 9,
},
{
id: "rainFcltInfo",
title: "2.빗물이용시설정보",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 7,
},
{
id: "insenInfo",
title: "3.인센티브 정보",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 6,
},
{
id: "adminDiv",
title: "행정구역",
visible: true,
row: 2,
upName:'bdnstInfo',
rowSpan: 1,
colSpan: 2,
},
// 3번째줄 시작
{
id: "cityText",
title: "시도",
visible: true,
upName:'adminDiv',
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "sggText",
title: "시군구",
visible: true,
upName:'adminDiv',
row: 3,
rowSpan: 1,
colSpan: 1,
},
// 2번째 줄
// 1번째 줄 건축물정보 아래의 행으로 만들 헤더
{
id: "bdstNm",
title: "건축물명",
visible: true,
upName:'bdnstInfo',
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "daddr",
title: "주소",
visible: true,
upName:'bdnstInfo',
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "bdstUsgCd",
title: "건축물용도코드",
upName:'bdnstInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "frstArchPrmsnDt",
title: "최초건축허가일시",
upName:'bdnstInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "archArea",
title: "건축면적",
upName:'bdnstInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "lawTrgtYn",
title: "법적의무대상여부",
upName:'bdnstInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "instlCmptnDt",
title: "설치완료일시",
upName:'bdnstInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "instlCst",
title: "설치비용",
upName:'rainFcltInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "pntfCol",
title: "집수면",
upName:'rainFcltInfo',
visible: true,
row: 2,
rowSpan: 1,
colSpan: 2,
},
{
id: "pntfColKnd",
title: "집수지점종류",
upName:'pntfCol',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "pntfColArea",
title: "집수지점면적",
upName:'pntfCol',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "dtfcltCpct",
title: "저류조용량",
upName:'rainFcltInfo',
visible: true,
row: 2,
rowSpan: 2,
colSpan: 1,
},
{
id: "filtrTrtmfctYn",
title: "여과처리시설유무",
upName:'filtrTrtmfct',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "filtrTrtmfctCpct",
title: "여과처리시설용량",
upName:'filtrTrtmfct',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "filtrTrtmfctPrs",
title: "여과처리시설처리공정",
upName:'filtrTrtmfct',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "filtrTrtmfct",
title: "여과등 처리시설",
visible: true,
upName:'insenInfo',
row: 2,
rowSpan: 1,
colSpan: 3,
},
{
id: "instlCstSprtYn",
title: "설치지원비용여부",
upName:'instlCstSprt',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "instlCstSprtAmt",
title: "설치지원비용",
upName:'instlCstSprt',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "instlCstSprt",
title: "설치비지원",
upName:'insenInfo',
visible: true,
row: 2,
rowSpan: 1,
colSpan: 2,
},
{
id: "grntchBdstCertYn",
title: "녹색건축물인증여부",
upName:'grntchBdstCert',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "grntchBdstCertYr",
title: "녹색건축물인증년도",
upName:'grntchBdstCert',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "grntchBdstCertNo",
title: "녹색건축물인증번호",
upName:'grntchBdstCert',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "grntchBdstCertGrd",
title: "녹색건축물인증등급",
upName:'grntchBdstCert',
visible: true,
row: 3,
rowSpan: 1,
colSpan: 1,
},
{
id: "grntchBdstCert",
title: "녹색건축물인증",
upName:'insenInfo',
visible: true,
row: 2,
rowSpan: 1,
colSpan: 4,
},
];
@@ -0,0 +1,163 @@
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { fetchType, getFetch } from "@/components/lib/api";
import {
type customRainBdst,
} from "../../fcltReg/rainReg";
import { excelSttnParsing } from "./excel";
import {
rainSttHeadListExport,
rainSttnHeadListType,
rainSttNodeListExport,
} from "./headList";
import type { z } from "zod";
import type { CommonTableProps } from "@/app/store/common/type/headder";
// 테이블 헤드 리스트
const rainSttNodeList = rainSttNodeListExport;
const rainSttHeadList = rainSttHeadListExport;
const rainSttnRes: customRainBdst[] = [];
const visibleHeadList = (falseHeads:CommonTableProps[], orgNodeList:CommonTableProps[])=>{
const visibleHeads = orgNodeList.map((node) => {
const copyNode = {...node}
falseHeads.forEach((head)=>{
if(copyNode.id ===head.id)
copyNode.visible = head.visible
})
return copyNode;
})
return visibleHeads
}
const getColspanReductionMap = (falseHeads:CommonTableProps[], orgList:CommonTableProps[]):Record<string, number> => {
const reduceMap:Record<string, number> = {};
falseHeads.forEach(head => {
const node = orgList.find(n => n.id === head.id);
if (node?.upName) {
reduceMap[node.upName] = (reduceMap[node.upName] || 0) + 1;
if (node.row&& node.row >= 3) {
const upperUpName = orgList.find(n => n.id === node.upName)?.upName;
if (upperUpName) {
reduceMap[upperUpName] = (reduceMap[upperUpName] || 0) + 1;
}
}
}
});
return reduceMap;
};
// colSpan 반영 및 visible 처리
const applyColspanReduction = (
orgList: CommonTableProps[],
reduceMap: Record<string, number>
): CommonTableProps[] => {
return orgList.map(node => {
const newNode: CommonTableProps = { ...node };
const reduceCount = reduceMap[node.id];
if (
newNode.colSpan !== undefined &&
reduceCount !== undefined &&
typeof newNode.colSpan === "number"
) {
newNode.colSpan -= reduceCount;
if (newNode.colSpan <= 0) {
newNode.visible = false;
}
}
return newNode;
});
};
// 일단 헤더가 3개 이상인경우 visible 처리를 위해서 공통함수로 작업
export const controlHeadView = (headList:CommonTableProps[], orgNodeList:CommonTableProps[] ) =>{
const falseHeads = headList.filter((item) => item.visible == false);
const viewHeadList = visibleHeadList(falseHeads, orgNodeList)
const reduceMap= getColspanReductionMap( falseHeads,viewHeadList)
return applyColspanReduction(viewHeadList,reduceMap);
}
export type rainSttnState = {
rainSttn: {
rainSttnRes: customRainBdst[];
rainSttHeadList: CommonTableProps[];
rainSttNodeList: CommonTableProps[];
excelList: [];
isInit: boolean;
};
};
type rainSttnActions = {
rainSttnSearch: (page: string, total: string, con: string) => void;
rainChSttnHead: (
headList: z.infer<typeof rainSttnHeadListType>,
) => void;
};
export type rainSttnType = rainSttnState & rainSttnActions;
export const rainSttnStateExport: rainSttnState = {
rainSttn: {
rainSttHeadList: rainSttHeadList,
rainSttNodeList: rainSttNodeList,
rainSttnRes: rainSttnRes,
excelList: [],
isInit: false,
},
};
export const rainSttnActionsExport: (set: any) => rainSttnActions = (
set: any
) => {
return {
rainSttnSearch: async (page: string, total: string, con: string) => {
try {
const rainSttnRes = await getFetch(
fetchType.WR,
`/reuseFc/rainyInfoList/${page}/${total}/${con}`
);
if (Number(total) > 9000) {
const rainExcel = excelSttnParsing(rainSttnRes);
set((state: rainSttnState) => {
return {
...state,
rainSttn: {
...state.rainSttn,
excelList: rainExcel,
},
};
});
} else
set((state: rainSttnState) => {
return {
...state,
rainSttn: {
...state.rainSttn,
rainSttnRes: rainSttnRes,
isInit: false,
},
};
});
} catch (erTxt) {
console.log("error", erTxt);
}
},
rainChSttnHead: async (
headList: z.infer<typeof rainSttnHeadListType>
) => {
const changeNodeList= controlHeadView(headList,rainSttNodeList)
return set((state: rainSttnState) => ({
rainSttn: {
...state.rainSttn,
rainSttHeadList: headList,
rainSttNodeList: changeNodeList,
},
}));
},
};
};
@@ -1,406 +0,0 @@
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import {
upHeadList,
type TableTripleProps,
type TableUpperProps,
} from "../../fcltReg/rainReg";
export const pbnSttHeadNm: chHeadType[] = [
{ headNm: "catchment", text: "유역", length: 3 },
{ headNm: "adminDiv", text: "행정구역", length: 2 },
{ headNm: "rusSup", text: "재이용수공급가능량", length: 3 },
{ headNm: "yearResult", text: "연간실적정보(m³)", length: 3 },
{ headNm: "mngInfo", text: "운영정보", length: 4 },
];
// id는 다확인해야함
export const pbnSttHeadList: TableUpperProps[] = [
{ id: "a", title: "권역", upName: "catchment", upSequnce: 1, visible: true },
{
id: "aaa",
title: "단위유역",
upName: "catchment",
upSequnce: 2,
visible: true,
},
{
id: "aaaa",
title: "중권역",
upName: "catchment",
upSequnce: 3,
visible: false,
},
{ id: "operMngCd", title: "환경청", visible: true },
{
id: "cityText",
title: "시도",
upName: "adminDiv",
upSequnce: 1,
visible: false,
},
{
id: "sggText",
title: "시군구",
upName: "adminDiv",
upSequnce: 2,
visible: true,
},
{ id: "bdnstNm", title: "시설명", visible: true },
{ id: "locDiv", title: "지역구분", visible: true },
{ id: "phone", title: "전화번호", visible: true },
{ id: "fcltQuantity", title: "시설용량(톤/일)", visible: true },
{ id: "rusNm", title: "재이용시설명", visible: true },
{
id: "fcltCpct",
title: "시설용량(m³/일)",
upName: "rusSup",
upSequnce: 1,
visible: true,
},
{
id: "trbt",
title: "하수처리량(m³/일)",
upName: "rusSup",
upSequnce: 2,
visible: true,
},
{
id: "ruseCpct",
title: "재이용량(m³/일)",
upName: "rusSup",
upSequnce: 3,
visible: true,
},
{
id: "total",
title: "합계",
upName: "yearResult",
upSequnce: 1,
visible: true,
},
{
id: "ithlWtr",
title: "장내용수",
upName: "yearResult",
upSequnce: 2,
visible: true,
},
{
id: "othlWtr",
title: "장외용수",
upName: "yearResult",
upSequnce: 3,
visible: true,
},
{
id: "mngMeth",
title: "운영방식",
upName: "mngInfo",
upSequnce: 1,
visible: true,
},
{
id: "rprtvBzenty",
title: "대행업체",
upName: "mngInfo",
upSequnce: 2,
visible: true,
},
{
id: "firstDay",
title: "시작일",
upName: "mngInfo",
upSequnce: 3,
visible: true,
},
{
id: "LastDay",
title: "종료일",
upName: "mngInfo",
upSequnce: 4,
visible: true,
},
];
export const rainSttHeadNm: chHeadType[] = [
{ headNm: "bdnstInfo", text: "1.건축물정보", length: 9 },
{ headNm: "rainFcltInfo", text: "2.빗물이용시설정보", length: 7 },
{ headNm: "fcltMngInfo", text: "3.시설운영및 이용정보", length: 2 },
{ headNm: "insenInfo", text: "4.인센티브 정보", length: 9 },
{ headNm: "adminDiv", text: "행정구역", length: 2 },
{ headNm: "pntfCol", text: "집수면", length: 2 },
{ headNm: "filtrTrtmfct", text: "여과등 처리시설", length: 3 },
{ headNm: "instlCstSprt", text: "설치비지원", length: 2 },
{ headNm: "crgRdct", text: "요금감면", length: 3 },
{ headNm: "grntchBdstCert", text: "녹색건축물인증여부", length: 4 },
];
// id는 다확인해야함
export const rainSttHeadList: TableTripleProps[] = [
{
id: "ctpvCd",
title: "시도",
visible: true,
upName: ["bdnstInfo", "adminDiv"],
upSequnce: [1, 1],
},
{
id: "sggCd",
title: "시군구",
visible: true,
upName: ["bdnstInfo", "adminDiv"],
upSequnce: [2, 2],
},
{
id: "bdstNm",
title: "건축물명",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [3],
},
{
id: "daddr",
title: "주소",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [4],
},
{
id: "bdstUsgCd",
title: "건축물용도코드",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [5],
},
{
id: "frstArchPrmsnDt",
title: "최초건축허가일시",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [6],
},
{
id: "archArea",
title: "건축면적",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [7],
},
{
id: "lawTrgtYn",
title: "법적의무대상여부",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [8],
},
{
id: "instlCmptnDt",
title: "설치완료일시",
visible: true,
upName: ["bdnstInfo"],
upSequnce: [9],
},
{
id: "instlCst",
title: "설치비용",
visible: true,
upName: ["rainFcltInfo"],
upSequnce: [1],
},
{
id: "pntfColKnd",
title: "접수지점종류",
visible: true,
upName: ["rainFcltInfo", "pntfCol"],
upSequnce: [2, 1],
},
{
id: "pntfColArea",
title: "접수지점면적",
visible: true,
upName: ["rainFcltInfo", "pntfCol"],
upSequnce: [3, 2],
},
{
id: "filtrTrtmfctYn",
title: "여과처리시설유무",
visible: true,
upName: ["rainFcltInfo", "filtrTrtmfct"],
upSequnce: [4, 1],
},
{
id: "filtrTrtmfctCpct",
title: "여과처리시설용량",
visible: true,
upName: ["rainFcltInfo", "filtrTrtmfct"],
upSequnce: [5, 2],
},
{
id: "filtrTrtmfctPrs",
title: "여과처리시설처리공정",
visible: true,
upName: ["rainFcltInfo", "filtrTrtmfct"],
upSequnce: [6, 3],
},
{
id: "dtfcltCpct",
title: "저류조용량",
visible: true,
upName: ["rainFcltInfo"],
upSequnce: [7],
},
{
id: "operMngCd",
title: "운영관리코드",
visible: true,
upName: ["fcltMngInfo"],
upSequnce: [1],
},
{
id: "annRnwtQty",
title: "연간빗물운영량",
visible: true,
upName: ["fcltMngInfo"],
upSequnce: [2],
},
{
id: "instlCstSprtYn",
title: "설치지원비용여부",
visible: true,
upName: ["insenInfo", "instlCstSprt"],
upSequnce: [1, 1],
},
{
id: "instlCstSprtAmt",
title: "설치지원비용",
visible: true,
upName: ["insenInfo", "instlCstSprt"],
upSequnce: [2, 2],
},
{
id: "crgRdctYn",
title: "감면여부",
visible: true,
upName: ["insenInfo", "crgRdct"],
upSequnce: [3, 1],
}, // 확인필요
{
id: "crgRdctBss",
title: "감면근거",
visible: true,
upName: ["insenInfo", "crgRdct"],
upSequnce: [4, 2],
}, // 확인필요
{
id: "crgRdctAmt",
title: "감면금액",
visible: true,
upName: ["insenInfo", "crgRdct"],
upSequnce: [5, 3],
}, // 확인필요
{
id: "grntchBdstCertYn",
title: "녹색건축물인증여부",
visible: true,
upName: ["insenInfo", "grntchBdstCert"],
upSequnce: [6, 1],
},
{
id: "grntchBdstCertYr",
title: "녹색건축물인증년도",
visible: true,
upName: ["insenInfo", "grntchBdstCert"],
upSequnce: [7, 2],
},
{
id: "grntchBdstCertNo",
title: "녹색건축물인증번호",
visible: true,
upName: ["insenInfo", "grntchBdstCert"],
upSequnce: [8, 3],
},
{
id: "grntchBdstCertGrd",
title: "녹색건축물인증등급",
visible: true,
upName: ["insenInfo", "grntchBdstCert"],
upSequnce: [9, 4],
},
];
export type sttnState = {
sttnCommon: {
pbnSttHeadList: TableUpperProps[];
pbnSttHeadNm: chHeadType[];
rainSttHeadList: TableTripleProps[];
rainSttHeadNm: chHeadType[];
};
};
type sttnActions = {
chSttnHead: (checkList: string[], type: string) => void;
pbnSttnInit: (sggCd: string, searchTxt: string, flg: string) => void;
};
export type sttnType = sttnState & sttnActions;
export const sttnStateExport: sttnState = {
sttnCommon: {
pbnSttHeadList: pbnSttHeadList,
pbnSttHeadNm: pbnSttHeadNm,
rainSttHeadList: rainSttHeadList,
rainSttHeadNm: rainSttHeadNm,
},
};
export const sttnActionsExport: (set: any) => sttnActions = (set: any) => {
return {
pbnSttnInit: async (sggCd: string, searchTxt: string, flg: string) => {},
chSttnHead: async (checkList: string[], type: string) => {
const headList =
type === "pbn"
? pbnSttHeadList
: type === "rain"
? rainSttHeadList
: null;
let chNm = type === "pbn" ? pbnSttHeadNm : rainSttHeadNm;
headList?.forEach((item) => {
if (checkList.find((ch) => ch === item.id)) {
item.visible = false;
if (item.upName) {
const upNames = Array.isArray(item.upName) ? item.upName : [item.upName];
upNames?.forEach((up) => {
chNm.find((ch) => {
if (ch.headNm === up) {
ch.length = ch.length - 1;
}
}
);
})
}
}
});
set((state: sttnState) => ({
sttnCommon: {
...state.sttnCommon,
pbnSttHeadList: type === "pbn" ? headList : state.sttnCommon.pbnSttHeadList,
rainSttHeadList: type === "rain" ? headList : state.sttnCommon.rainSttHeadList,
rainSttHeadNm: type === "rain" ? chNm : state.sttnCommon.rainSttHeadNm,
pbnSttHeadNm: type === "rain" ? chNm : state.sttnCommon.pbnSttHeadNm,
},
}));
},
};
};
+30 -30
View File
@@ -1,4 +1,20 @@
import { createStore } from "zustand/vanilla";
import { codeActionExport, comCodeStateExport, getCityCd, getEnvPartCd, getMiddleRegionCd, getRegionCd, getSggCd, getUnitWaterShedCd, type comCodeState, type comCodeType } from "./common/code";
import {
matDmdActionsExport,
matDmdStateExport,
type matDmdState,
type matDmdType,
} from "./matDmd";
import { rainChkgdnActionsExport, rainChkgdnStateExport, type rainChkgdnState, type rainChkgdnType } from "./prfmncReg/chkgdnReg/rainChkgdn";
import { rswtChkgdnActionsExport, rswtChkgdnStateExport, type rswtChkgdnState, type rswtChkgdnType } from "./prfmncReg/chkgdnReg/rswrtChkgdn";
import { bdstActionsExport, bdstStateExport, type bdstFulType, type bdstState } from "./ruseFcltMng/fcltReg/bdstReg";
import {
htdflFacActionsExport,
htdflFacStateExport,
type htdflFacState,
type htdflFacType,
} from "./ruseFcltMng/fcltReg/htdflReg";
import {
pubFacActionsExport,
pubFacStateExport,
@@ -17,23 +33,7 @@ import {
type rswtFacState,
type rswtFacType,
} from "./ruseFcltMng/fcltReg/rswtReg";
import {
matDmdActionsExport,
matDmdStateExport,
type matDmdState,
type matDmdType,
} from "./matDmd";
import {
htdflFacActionsExport,
htdflFacStateExport,
type htdflFacState,
type htdflFacType,
} from "./ruseFcltMng/fcltReg/htdflReg";
import { codeActionExport, comCodeStateExport, getCityCd, getEnvPartCd, getMiddleRegionCd, getRegionCd, getSggCd, getUnitWaterShedCd, type comCodeState, type comCodeType } from "./common/code";
import { bdstActionsExport, bdstStateExport, type bdstFulType, type bdstState } from "./ruseFcltMng/fcltReg/bdstReg";
import { rainChkgdnActionsExport, rainChkgdnStateExport, type rainChkgdnState, type rainChkgdnType } from "./prfmncReg/chkgdnReg/rainChkgdn";
import { rswtChkgdnActionsExport, rswtChkgdnStateExport, type rswtChkgdnState, type rswtChkgdnType } from "./prfmncReg/chkgdnReg/rswrtChkgdn";
import { sttnActionsExport, sttnStateExport, type sttnState, type sttnType } from "./ruseFcltMng/fcltSttn/sttn";
import { rainSttnActionsExport, rainSttnStateExport, type rainSttnState, type rainSttnType } from "./ruseFcltMng/fcltSttn/rainSttn";
export type WrStore = comCodeType&
pubFacType &
@@ -44,7 +44,7 @@ export type WrStore = comCodeType&
bdstFulType&
rainChkgdnType&
rswtChkgdnType&
sttnType
rainSttnType
;
export const StoreZus = (
@@ -57,7 +57,7 @@ export const StoreZus = (
bdstState &
rainChkgdnState&
rswtChkgdnState&
sttnState
rainSttnState
= {
...comCodeStateExport,
...pubFacStateExport,
@@ -68,15 +68,15 @@ export const StoreZus = (
...bdstStateExport,
...rainChkgdnStateExport,
...rswtChkgdnStateExport,
...sttnStateExport
...rainSttnStateExport
}
) => {
return createStore<WrStore>()((set) => {
getSggCd(set),
getCityCd(set),
getRegionCd(set),
getMiddleRegionCd(set),
getUnitWaterShedCd(set),
getSggCd(set);
getCityCd(set);
getRegionCd(set);
getMiddleRegionCd(set);
getUnitWaterShedCd(set)
getEnvPartCd(set)
return {
...initState,
@@ -85,11 +85,11 @@ export const StoreZus = (
...rswtFacActionsExport(set),
...matDmdActionsExport(set),
...htdflFacActionsExport(set),
...codeActionExport(set),
...bdstActionsExport(set),
...rainChkgdnActionsExport(set),
...rswtChkgdnActionsExport(set),
...sttnActionsExport(set)
...codeActionExport(set),
...bdstActionsExport(set),
...rainChkgdnActionsExport(set),
...rswtChkgdnActionsExport(set),
...rainSttnActionsExport(set)
};
});
};
+3 -3
View File
@@ -1,11 +1,11 @@
//8880
import { DEV_URL_FO, DEV_URL_WR } from "../config/";
import { DEV_URL_FO, DEV_URL_WR } from "../config/";
export const fetchType={COMMON: "common", WR: "wr"}
export const getFetch = async( type:string , url: string) => {
const div = type === 'common' ? DEV_URL_FO : DEV_URL_WR
const div = type === fetchType.COMMON ? DEV_URL_FO : DEV_URL_WR
const response = await fetch( div+url , {
method: "GET",
headers: {
+2 -2
View File
@@ -1,14 +1,14 @@
const LOCAL_PORT = "3000";
const DEV_PORT = "11080";
const DEV_PORT_NEW="8882"
const DEV_PORT_NEW="11082"
export const LOCAL_URL_WR = `http://localhost:${LOCAL_PORT}/api/v1`;
export const DEV_URL_WR = `http://con.mind-one.co.kr:${DEV_PORT}/api/v1`;
//export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_FO}/api/v1`;
export const DEV_URL_FO = `http://192.168.1.193:${DEV_PORT_NEW}/api/v1`;
export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_NEW}/api/v1`;
+142
View File
@@ -0,0 +1,142 @@
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui";
export const rightTableData = (rainChk: rainChkZodType[]) => {
// 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기
const maketotal = rainChk.map((item: rainChkZodType) => {
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: rainChkZodType) => {
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 const chRowspanTable = (
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
) => {
// rowspan된 셀 렌더링 여부 추적용
const renderedMap = new Map<string, Set<number>>();
return (
<>
{makeTableData.map((row, rowIndex) => (
<TableRow key={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<number>();
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 (
<TableCell
key={key}
rowSpan={rowspan}
className="align-middle text-center whitespace-nowrap"
>
{key === "order" ? (
<Checkbox
checked={selectedIds.includes(row.chkgdnPk)}
onCheckedChange={(checked) =>
toggleSelection(row.chkgdnPk, checked === true)
}
></Checkbox>
) : (
value
)}
</TableCell>
);
}
// 기본 셀
return (
<TableCell
key={key}
className="text-center whitespace-nowrap"
onClick={() => handleCellClick(rowIndex, head.id)}
>
{key === "totalSplyUswtrUtztnQnt" ||
key === "totalRuseFcltUtztnQnt" ||
key === "utztnUsgCd" ? (
`${value}`
) : (
<Input
className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`}
type={head.type}
onChange={(e) => {
handleChange(rowIndex, head.id, e.target.value);
}}
value={value}
/>
)}
</TableCell>
);
})}
</TableRow>
))}
</>
);
};
-49
View File
@@ -1,49 +0,0 @@
import type { comCodeState, selectArray } from "@/app/store/common/code";
export const getCity = (val: string, sggCd: selectArray[]) => {
const data = sggCd
.filter((item) => String(item.val).substring(0, 2) === val)
.map((item) => ({
val: item.val,
text: item.text // 한국어 텍스트
}));
return data
};
// cd text 넣기
export const tableData = ( data: any,code:comCodeState)=>{
const chCode = code.code;
return data?.map((item: { sggCd: string; ctpvCd: string; reuseBuilding: { lawTrgtYn: any , bdstUsgCd:any}[]; }) => {
let returnData = {};
const sggText = chCode.sggCd.find(
(cd) => cd.val === item.sggCd
)?.text;
const cityText = chCode.cityCd.find(
(cd) => cd.val === item.ctpvCd
)?.text;
if (item?.reuseBuilding?.length >0) {
const bdsgUsgText = chCode.bdstUsgCd.find(
(cd) =>cd.val === item?.reuseBuilding[0]?.bdstUsgCd
)?.text
const lawTrgtYn = item?.reuseBuilding[0]?.lawTrgtYn
returnData= { ...item, sggText: sggText, cityText: cityText ,bdsgUsgText:bdsgUsgText ,lawTrgtYn:lawTrgtYn};
}else{
returnData= { ...item, sggText: sggText, cityText: cityText};
}
// console.log(" returnData ", returnData)
return returnData;
});
}
+85
View File
@@ -0,0 +1,85 @@
import type { comCodeState, } from "@/app/store/common/code";
import { filePickedBlob, type SelectDataType } from "@common/business_components/ui";
export const getCity = (val: string, sggCd: SelectDataType[]) => {
const data = sggCd
.filter((item) => String(item.val).substring(0, 2) === val)
.map((item) => ({
val: item.val,
text: item.text // 한국어 텍스트
}));
return data
};
// cd text 넣기
export const tableData = ( data: any,code:comCodeState)=>{
const chCode = code.code;
return data?.map((item: { sggCd: string; ctpvCd: string; reuseBuilding: { lawTrgtYn: any , bdstUsgCd:any}[]; }) => {
let returnData = {};
const sggText = chCode.sggCd.find(
(cd) => cd.val === String(item.sggCd)
)?.text;
const cityText = chCode.cityCd.find(
(cd) => cd.val === String(item.ctpvCd)
)?.text;
console
.log(item?.reuseBuilding)
if (item?.reuseBuilding?.length >0) {
const bdsgUsgText = chCode.bdstUsgCd.find(
(cd) =>Number(cd.val) === item?.reuseBuilding[0]?.bdstUsgCd
)?.text
const lawTrgtYn = item?.reuseBuilding[0]?.lawTrgtYn
console
.log(bdsgUsgText)
returnData= { ...item, sggText: sggText??'없음', cityText: cityText??'없음' ,bdsgUsgText:bdsgUsgText ,lawTrgtYn:lawTrgtYn};
}else{
returnData= { ...item, sggText: sggText??'없음', cityText: cityText??'없음'};
}
return returnData;
});
}
export const excelDownload =(excelList: [][], fileNm:string ,sampleFile:string, headerRange='A1:V3') =>{
if (excelList.length === 0) return;
fetch(`/${sampleFile}`, {})
.then(async (response) => {
if (!response.ok) {
throw Error(response.statusText)
}
// 받은 파일 바인너리 처리
const blobRet = await response.arrayBuffer()
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
await filePickedBlob(blobRet, excelList,fileNm, 4,headerRange)
})
}
// onchange 텍스트를 숫자로 and ,제거
export const handleCommaNumberChange = (
e: React.ChangeEvent<HTMLInputElement>,
onChange: (value: number | "") => void
) => {
const raw = e.target.value.replace(/,/g, "");
if (!/^\d*$/.test(raw)) return;
onChange(raw === "" ? "" : Number(raw));
};
// 숫자입력시 , 삽입
export const formatCommaNumber = (
value: number | string | undefined | null
): string => {
if (value === undefined || value === null || value === "") return "";
return Number(value).toLocaleString();
};
@@ -1,9 +1,18 @@
import { useWrStore } from "@/app/store";
import type { selectArray } from "@/app/store/common/code";
import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { getCity } from "@/components/lib/func/commom";
import {
formatCommaNumber,
getCity,
handleCommaNumberChange,
} from "@/components/lib/func/commom";
import type { objSearchType } from "@/components/ui/modal/bdstRegModal/bdstRegModal";
import { FormField, FormUi, DatePicker, SelectBox } from "@common/business_components";
import {
FormField,
FormUi,
DatePicker,
SelectBox,
} from "@common/business_components";
import { Button, Input } from "@common/components";
import { useEffect, useRef, useState } from "react";
import { useFieldArray } from "react-hook-form";
@@ -30,49 +39,46 @@ export default function BdstReg({ form }: { form: any }) {
if (fields.length > 0) {
remove(fields.length - 1);
}
};
};
const [selectSgg, setSelectSgg] = useState<selectArray[] | undefined>()
const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""});
const getSelCity = (val: string) => {
const data= getCity(val,code.sggCd)
setSelectSgg(data);
const sgg =form.getValues('sggCd')
const [selectSgg, setSelectSgg] = useState<selectArray[] | undefined>();
const [objSearch, setObjSearch] = useState<objSearchType>({
sgg: "",
city: "",
});
setObjSearch({ city:val , sgg:''})
};
const getSgg = (val: string | number) => {
const getSelCity = (val: string) => {
const data = getCity(val, code.sggCd);
setSelectSgg(data);
const sgg = form.getValues("sggCd");
const sgg =form.getValues('sggCd')
setObjSearch({...objSearch,sgg: val!=''?String(val):sgg })
};
setObjSearch({ city: val, sgg: "" });
};
useEffect(()=>{
const city =form.getValues('ctpvCd')
const sgg =form.getValues('sggCd')
setObjSearch({city:city , sgg:sgg })
}, [selectSgg])
const getSgg = (val: string | number) => {
const sgg = form.getValues("sggCd");
setObjSearch({ ...objSearch, sgg: val != "" ? String(val) : sgg });
};
useEffect(() => {
const city = form.getValues("ctpvCd");
const sgg = form.getValues("sggCd");
setObjSearch({ city: city, sgg: sgg });
}, [selectSgg]);
useEffect(() => {
const subscription = form.form?.watch((value: any) => {
console.log('vale', value)
console.log("vale", value);
});
return () => subscription?.unsubscribe();
}, [form.form]);
const safeDate = (value: any): Date | undefined => {
const date = new Date(value);
return isNaN(date.getTime()) ? undefined : date;
};
return (
<>
<h1 className="bg-gray-400 text-xl text-center border-2 p-2 mt-4 pl-6">
@@ -86,19 +92,15 @@ export default function BdstReg({ form }: { form: any }) {
render={({ field }) => (
<FormUi label="시도">
<SelectBox
className="col-span-3 "
label={""}
selectClass={selectClass}
selectArray={code.cityCd}
onSelectValue={(val)=>{
getSelCity(String(val))
field.onChange(Number(val) );
}
}
value={field.value}
className="col-span-3 "
label={""}
selectClass={selectClass}
selectArray={code.cityCd}
onSelectValue={(val) => {
getSelCity(String(val));
field.onChange(Number(val));
}}
value={field.value}
/>
</FormUi>
)}
@@ -111,16 +113,15 @@ export default function BdstReg({ form }: { form: any }) {
render={({ field }) => (
<FormUi label="시군구">
<SelectBox
className="col-span-3"
label={""}
selectClass={selectClass}
selectArray={selectSgg? selectSgg:code.sggCd || []}
onSelectValue={(val) =>{
getSgg(val)
field.onChange(Number(val))
}}
value={field.value}
className="col-span-3"
label={""}
selectClass={selectClass}
selectArray={selectSgg ? selectSgg : code.sggCd || []}
onSelectValue={(val) => {
getSgg(val);
field.onChange(Number(val));
}}
value={field.value}
/>
</FormUi>
)}
@@ -135,7 +136,7 @@ export default function BdstReg({ form }: { form: any }) {
render={({ field }) => (
<FormUi label="건축물명">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="text"
{...field}
@@ -151,7 +152,7 @@ export default function BdstReg({ form }: { form: any }) {
render={({ field }) => (
<FormUi label="위치">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="search"
{...field}
@@ -186,16 +187,14 @@ export default function BdstReg({ form }: { form: any }) {
name="frstArchPrmsnDt"
render={({ field }) => (
<FormUi label="최초건축허가일">
<DatePicker
mode={"single"}
field={{
value: field.value|| new Date(),
onChange: (date: Date | undefined) =>
field.onChange(date),
}}
selectClass={selectClass}
></DatePicker>
<DatePicker
mode={"single"}
field={{
value: field.value || new Date(),
onChange: (date: Date | undefined) => field.onChange(date),
}}
selectClass={'w-full'}
></DatePicker>
</FormUi>
)}
/>
@@ -207,14 +206,13 @@ export default function BdstReg({ form }: { form: any }) {
render={({ field }) => (
<FormUi label="건축면적(m³)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
{...field}
onChange={(e) => {
const value = e.target.value;
field.onChange(value === "" ? "" : Number(value));
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -249,7 +247,7 @@ export default function BdstReg({ form }: { form: any }) {
이력추가
</Button>
<Button
type="button"
type="button"
className="rounded-lg bg-red-500 text-white"
onClick={removeLastItem}
>
@@ -270,7 +268,6 @@ export default function BdstReg({ form }: { form: any }) {
selectClass={selectClass}
label={""}
selectArray={code.chBuCd}
onSelectValue={(val) => {
field.onChange(val);
}}
@@ -286,15 +283,15 @@ export default function BdstReg({ form }: { form: any }) {
name={`chgBuilding.${index}.archChgPrmsnDt`}
render={({ field }) => (
<FormUi label="허가일">
<DatePicker
mode={"single"}
field={{
value: safeDate(field.value) || new Date(),
onChange: (date: Date | undefined) =>
field.onChange(date),
}}
selectClass={selectClass}
></DatePicker>
<DatePicker
mode={"single"}
field={{
value: safeDate(field.value) || new Date(),
onChange: (date: Date | undefined) =>
field.onChange(date),
}}
selectClass={'w-full'}
></DatePicker>
</FormUi>
)}
/>
@@ -306,12 +303,13 @@ export default function BdstReg({ form }: { form: any }) {
render={({ field }) => (
<FormUi label="면적">
<Input
className=""
className={selectClass}
placeholder="-"
type="text"
value={ field.value??"-"}
onChange={(e) => field.onChange((e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -18,6 +18,10 @@ import {
} from "@/app/store/ruseFcltMng/fcltReg/htdflReg";
import { useEffect } from "react";
import BdstReg from "../bdstReg/bdstReg";
import {
formatCommaNumber,
handleCommaNumberChange,
} from "@/components/lib/func/commom";
export default function HtdflRegForm({
htdflForm,
@@ -35,19 +39,19 @@ export default function HtdflRegForm({
defaultValues: defaultValues,
});
const onSubmit=(values: z.infer<typeof hdtflZod>)=> {
const onSubmit = (values: z.infer<typeof hdtflZod>) => {
if (isModal) {
htdflReg(values);
} else {
htdflUpdate(values);
}
}
};
const onSelectValue = (val: string | number) => {
console.log(val);
};
const cleanHtdflData=(raw: any): z.infer<typeof hdtflZod> =>{
const cleanHtdflData = (raw: any): z.infer<typeof hdtflZod> => {
return {
...raw,
frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null),
@@ -70,16 +74,12 @@ export default function HtdflRegForm({
},
})),
};
}
};
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
useEffect(() => {
if (hdtflZod) form.reset(cleanHtdflData(htdflForm));
}, [htdflForm]);
@@ -91,26 +91,24 @@ export default function HtdflRegForm({
<div>
<div className="grid grid-cols-12">
<h1 className="pl-3 text-xl col-span-10">○온배수 시설 정보</h1>
<Button size={"sm"} type="submit" className="col-start-12 col-span-1">
<Button
size={"sm"}
type="submit"
className="col-start-12 col-span-1"
>
저장
</Button>
</div>
</div>
{ isModal && htdflForm != undefined ? (
<BdstReg form={form} />
) : (
<></>
)}
{isModal ? (
<h1 className="pl-3 text-xl col-span-10 mt-4 ">
○ 중수도 시설 정보{" "}
</h1>
) : (
<></>
)}
{isModal && htdflForm != undefined ? <BdstReg form={form} /> : <></>}
{isModal ? (
<h1 className="pl-3 text-xl col-span-10 mt-4 ">
○ 중수도 시설 정보{" "}
</h1>
) : (
<></>
)}
<div className="grid grid-cols-6 gap-2 mt-4 pl-6">
<div className="col-span-2">
@@ -120,7 +118,7 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="발전유형(코드정비후 수정)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="text"
value={field.value ?? ""}
@@ -138,13 +136,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="설비용량">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="text"
value={field.value ?? 0}
onChange={(e) => {
field.onChange(Number(e.target.value));
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -183,7 +181,7 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="원수취수 지점(코드정비후 수정)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="text"
value={field.value ?? 0}
@@ -202,7 +200,7 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="원수발생 공정">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? ""}
@@ -219,13 +217,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="취수구 온도">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? 0}
type="text"
onChange={(e) => {
field.onChange(Number(e.target.value));
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -238,11 +236,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="발생량(m³/년)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -273,11 +273,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="처리시설 용량(m³/년)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -308,11 +310,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="이용량(m³/년)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -325,7 +329,7 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="이용용도">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="text"
value={field.value ?? ""}
@@ -351,10 +355,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="총대장균군">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -368,10 +375,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="총질소">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -387,10 +397,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="결합잔류염소">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -404,10 +417,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="총인">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -423,10 +439,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="탁도">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -440,10 +459,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="수소이온농도">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -459,10 +481,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="생물학적 산소요구량">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -476,10 +501,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="염화물">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -495,10 +523,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="냄새">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -512,10 +543,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="전기전도도">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -531,10 +565,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="색도">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -548,10 +585,13 @@ export default function HtdflRegForm({
render={({ field }) => (
<FormUi label="배출구온도">
<Input
className={selectClass}
placeholder="10"
type="text"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -15,6 +15,7 @@ import { useEffect, useState } from "react";
import { useForm, useWatch, type UseFormReturn } from "react-hook-form";
import { z } from "zod";
import BdstReg from "../bdstReg/bdstReg";
import { formatCommaNumber, handleCommaNumberChange } from "@/components/lib/func/commom";
export default function RainRegForm({
rainForm,
@@ -23,7 +24,7 @@ export default function RainRegForm({
rainForm: customRainBdst;
isModal: boolean;
}) {
const { code, rainReg, rainUpdate, rain } = useWrStore((state) => state);
const { code, rainBdstReg, rainBdstUpdate, rain } = useWrStore((state) => state);
const { rainFcltCd } = code;
const defaultValues: z.infer<typeof rainZod> = rainZod.parse({});
@@ -87,9 +88,9 @@ useEffect(() =>{
const onSubmit =(values: z.infer<typeof rainZod>)=> {
if (isModal) {
rainReg(values);
rainBdstReg(values ,'41');
} else {
rainUpdate(values);
rainBdstUpdate(values, '41');
}
}
@@ -101,7 +102,7 @@ useEffect(() =>{
const inputClass = '!text-lg'
return (
<div className="">
@@ -109,7 +110,7 @@ useEffect(() =>{
<form onSubmit={form.handleSubmit(onSubmit)}>
<div>
<div className="grid grid-cols-12">
<h1 className="pl-3 text-xl col-span-10">
<h1 className="pl-3 !text-lg col-span-10">
{isModal ? "○건축물 운영정보" : "○ 빗물이용시설 정보"}
</h1>
<Button type="submit" className="mr-4 rounded-lg col-span-2">
@@ -145,7 +146,7 @@ useEffect(() =>{
: new Date(), // Provide a default Date value
onChange: (date) => field.onChange(date),
}}
selectClass={""}
selectClass={'w-full'}
/>
</FormUi>
)}
@@ -159,13 +160,11 @@ useEffect(() =>{
render={({ field }) => (
<FormUi label="설치비">
<Input
className=""
placeholder="1,000,000"
type="number"
value={field.value ?? 0}
onChange={(e) => {
field.onChange(e.target.value === "" ? "" : Number(e.target.value));
}}
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {handleCommaNumberChange(e, field.onChange) }}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -207,11 +206,11 @@ useEffect(() =>{
render={({ field }) => (
<FormUi label="면적(m³)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {handleCommaNumberChange(e, field.onChange) }}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -248,11 +247,11 @@ useEffect(() =>{
render={({ field }) => (
<FormUi label="용량(m³/일)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {handleCommaNumberChange(e, field.onChange) }}
value={formatCommaNumber(field.value)}
readOnly={filtrTrtmfctYn!=='Y'}
/>
@@ -267,7 +266,7 @@ useEffect(() =>{
render={({ field }) => (
<FormUi label="처리공정">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? ""}
@@ -314,15 +313,12 @@ useEffect(() =>{
render={({ field }) => (
<FormUi label="지원금액(원)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
onChange={(e) => {
const value = e.target.value;
field.onChange(value === "" ? "" : Number(value));
}}
value={field.value ?? 0}
readOnly={instlCstSprtYn!=='Y'}
type="text"
onChange={(e) => {handleCommaNumberChange(e, field.onChange) }}
value={formatCommaNumber(field.value)}
readOnly={instlCstSprtYn !== 'Y'}
/>
</FormUi>
)}
@@ -358,7 +354,7 @@ useEffect(() =>{
name="reuseBuilding.0.grntchBdstCertYr"
render={({ field }) => (
<FormUi label="인증년도">
<Input className="" placeholder="2024" type="" value={field.value ?? ""}
<Input className={selectClass} placeholder="2024" type="" value={field.value ?? ""}
onChange={field.onChange}
readOnly={grntchBdstCertYn!=='Y'}/>
@@ -373,7 +369,7 @@ useEffect(() =>{
render={({ field }) => (
<FormUi label="인증번호">
<Input
className=""
className={selectClass}
placeholder="ab1234678"
type=""
value={field.value ?? ""}
@@ -390,7 +386,7 @@ useEffect(() =>{
name="reuseBuilding.0.grntchBdstCertGrd"
render={({ field }) => (
<FormUi label="인증등급">
<Input className="" placeholder="A" type="" value={field.value ?? ""}
<Input className={selectClass} placeholder="A" type="" value={field.value ?? ""}
onChange={field.onChange}
readOnly={grntchBdstCertYn!=='Y'}
/>
@@ -9,8 +9,8 @@ import {
} from "@common/business_components/ui";
import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { useWrStore } from "@/app/store";
import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
@@ -19,6 +19,10 @@ import {
} from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
import { useEffect } from "react";
import BdstReg from "../bdstReg/bdstReg";
import {
formatCommaNumber,
handleCommaNumberChange,
} from "@/components/lib/func/commom";
export default function RswtrRegForm({
rswtForm,
@@ -27,78 +31,69 @@ export default function RswtrRegForm({
rswtForm: customRswtBdst;
isModal: boolean;
}) {
const { rswt, code ,rswtUpdate,rswtReg} = useWrStore((state) => state);
const { rswt, code, rswtBdstUpdate, rswtBdstReg } = useWrStore((state) => state);
const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({});
const form = useForm<z.infer<typeof rswtZod>>({
resolver: zodResolver(rswtZod),
defaultValues: defaultValues,
})
});
const [grntchBdstCertYn, instlCstSprtYn,filtrTrtmfctProcs] = form.watch([
const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs] = form.watch([
"reuseBuilding.0.grntchBdstCertYn",
"reuseBuilding.0.instlCstSprtYn",
"reuseBuilding.0.rswtrObj.filtrTrtmfctProcs",
]);
const onSubmit =(values: z.infer<typeof rswtZod>) => {
const onSubmit = (values: z.infer<typeof rswtZod>) => {
if (isModal) {
rswtReg(values);
} else {
rswtUpdate(values);
}
}
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> =>{
rswtBdstReg(values,'41');
} else {
rswtBdstUpdate(values,'41');
}
};
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => {
return {
...raw,
frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt||null),
archChgPrmsnDt: raw?.archChgPrmsnDt ? new Date(raw?.archChgPrmsnDt) : null,
frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null),
archChgPrmsnDt: raw?.archChgPrmsnDt
? new Date(raw?.archChgPrmsnDt)
: null,
reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({
...item,
instlCmptnDt: new Date(item?.instlCmptnDt),
operMngCd: item?.operMngCd ?? "", // null → ""
grntchBdstCertYr: typeof item?.grntchBdstCertYr === "string"
? item?.grntchBdstCertYr
: "", // null → ""
grntchBdstCertYr:
typeof item?.grntchBdstCertYr === "string"
? item?.grntchBdstCertYr
: "", // null → ""
rswtrObj: {
...item?.rswtrObj
}
}))
...item?.rswtrObj,
},
})),
};
}
};
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
useEffect(() => {
console.log("filtrTrtmfctProcs ", filtrTrtmfctProcs);
if (grntchBdstCertYn === "N") {
form.setValue("reuseBuilding.0.grntchBdstCertYr", "");
form.setValue("reuseBuilding.0.grntchBdstCertNo", "");
form.setValue("reuseBuilding.0.grntchBdstCertGrd", "");
} else if (instlCstSprtYn === "N") {
form.setValue("reuseBuilding.0.instlCstSprtAmt", 0);
}
}, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs]);
useEffect(() =>{
console.log("filtrTrtmfctProcs ", filtrTrtmfctProcs)
if(grntchBdstCertYn ==='N'){
form.setValue('reuseBuilding.0.grntchBdstCertYr' ,"" )
form.setValue('reuseBuilding.0.grntchBdstCertNo' ,"" )
form.setValue('reuseBuilding.0.grntchBdstCertGrd' ,"" )
}else if(instlCstSprtYn ==='N'){
form.setValue('reuseBuilding.0.instlCstSprtAmt' ,0 )
}
},[grntchBdstCertYn,instlCstSprtYn,filtrTrtmfctProcs ])
useEffect(() => {
if(rswtZod)
form.reset( cleanRswtData(rswtForm))
useEffect(() => {
if (rswtZod) form.reset(cleanRswtData(rswtForm));
}, [rswtForm]);
return (
<div className="">
<Form {...form}>
@@ -106,20 +101,18 @@ useEffect(() => {
{/* <div className="flex justify-between items-center mx-3"> */}
<div>
<div className="grid grid-cols-12">
<h1 className="pl-3 text-xl col-span-10">
○ 중수도 시설 정보
</h1>
<Button size={"sm"} type="submit" className="col-start-12 col-span-1">
<h1 className="pl-3 text-xl col-span-10">○ 중수도 시설 정보</h1>
<Button
size={"sm"}
type="submit"
className="col-start-12 col-span-1"
>
저장
</Button>
</div>
</div>
{isModal && rswtForm != undefined ? (
<BdstReg form={form} />
) : (
<></>
)}
{isModal && rswtForm != undefined ? <BdstReg form={form} /> : <></>}
{isModal ? (
<h1 className="pl-3 text-xl col-span-10 mt-4 ">
○ 중수도 시설 정보{" "}
@@ -160,11 +153,13 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="설치비">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
value={field.value ?? ""}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -179,11 +174,13 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="물사용량(m³)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -197,11 +194,13 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="의무대상 물사용량(m³)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
value={field.value ?? 0}
onChange={(e) => field.onChange(Number(e.target.value))}
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
@@ -240,7 +239,7 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="주요처리공정">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type=""
value={field.value ?? ""}
@@ -286,14 +285,14 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="지원금액(원)">
<Input
className=""
className={selectClass}
placeholder="1,000,000"
type="number"
value={field.value ?? 0}
type="text"
onChange={(e) => {
field.onChange(Number(e.target.value));
handleCommaNumberChange(e, field.onChange);
}}
readOnly={instlCstSprtYn!=='Y'}
value={formatCommaNumber(field.value)}
readOnly={instlCstSprtYn !== "Y"}
/>
</FormUi>
)}
@@ -330,13 +329,13 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="인증년도">
<Input
className=""
className={selectClass}
placeholder="2024"
type="text"
{...field}
value={field.value ?? ""}
onChange={field.onChange}
readOnly={grntchBdstCertYn!=='Y'}
readOnly={grntchBdstCertYn !== "Y"}
/>
</FormUi>
)}
@@ -349,13 +348,12 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="인증번호">
<Input
className=""
className={selectClass}
placeholder="ab1234678"
type=""
value={field.value ?? ""}
onChange={field.onChange}
readOnly={grntchBdstCertYn!=='Y'}
readOnly={grntchBdstCertYn !== "Y"}
/>
</FormUi>
)}
@@ -368,13 +366,12 @@ useEffect(() => {
render={({ field }) => (
<FormUi label="인증등급">
<Input
className=""
className={selectClass}
placeholder="A"
type=""
value={field.value ?? ""}
onChange={field.onChange}
readOnly={grntchBdstCertYn!=='Y'}
readOnly={grntchBdstCertYn !== "Y"}
/>
</FormUi>
)}
@@ -1,20 +1,19 @@
"use client";
import { headMakeColSpan } from "@/app/ruseFcltMng/fcltReg/rainReg/page";
import { useWrStore } from "@/app/store";
import {
selectClass,
type customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { ScrollArea, SelectBox, UiTable } from "@common/business_components";
import { ScrollArea, SelectBox, UiTable, type SelectDataType } from "@common/business_components";
import { Button, Input, Label } from "@common/components";
import { useEffect, useState } from "react";
import RainRegForm from "../../form/fcltReg/rainReg/rainRegForm";
import { type selectArray } from "@/app/store/common/code";
import { getCity, tableData } from "@/components/lib/func/commom";
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
import HtdflRegForm from "../../form/fcltReg/htdflReg/htdflRegForm";
import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg";
import RswtrRegForm from "../../form/fcltReg/rswtrReg/rswtrRegForm";
import { headMakeColSpan } from "@/app/ruseFcltMng/fcltReg/rainReg/TableHead";
export type objSearchType = {
sgg: string|number;
@@ -40,7 +39,7 @@ export function BdstReg<T extends MoType>({ moType }: BdstRegProps<T>) {
const [bdstTable, setbdstTable] = useState<BdstTypeMap[T][]>();
const [rainBdstForm, setRainBdstForm] = useState<BdstTypeMap[T]>({} as BdstTypeMap[T]);
const [searchTxt, setSearchTxt] = useState<string>()
const [selectSgg, setSelectSgg] = useState<selectArray[] | []>()
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""});
const getSelCity = (val: string | number) => {
@@ -1,4 +1,6 @@
import { rainRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { useWrStore } from "@/app/store";
import { rainChkZod, rainRegExcel, type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { excelToRainChkData } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel";
import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
DatePicker,
@@ -9,17 +11,20 @@ import {
FormUi,
Title,
} from "@common/business_components/ui";
import { Button } from "@common/components/ui";
import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast, { Toaster } from "react-hot-toast";
import type { z } from "zod";
import { ToastFormUi } from "../../toast/toastFromUi";
export default function ChkgdExcel({ type }: { type: string }) {
const [files, setFiles] = useState(null);
const [dmdDate, setDmdDate] = useState(new Date());
const { rainChkExcelDataUPload } = useWrStore((state) => {
return state;
});
const [files, setFiles] = useState<File[] | null>(null);
const [excelData , setExcelData] = useState<rainChkZodType[]>()
const defaultValues: z.infer<typeof rainRegExcel> = rainRegExcel.parse({});
const form = useForm<z.infer<typeof rainRegExcel>>({
@@ -27,22 +32,40 @@ export default function ChkgdExcel({ type }: { type: string }) {
defaultValues: defaultValues,
});
const onChangeDate = (val: Date | undefined) => {
if (val) setDmdDate(val);
};
useEffect(() => {
if (files) {
const file = files[0];
if(file) filePicked(file,1).then((res) => console.log(res));
}else{
if (files) {
const file = files[0];
if(form.getValues("chckYr").length<1 ){
ToastFormUi({body:"파일업로드 이전에 등록년도를 작성해주세요 " ,title:'지도점검 등록'})
setFiles(null)
return
}
if (file)
filePicked(file, 0).then((res) => {
if (res !== undefined)
setExcelData(excelToRainChkData(res, form.getValues("chckYr")))
});
}
}, [files]);
const onSubmit =(values: z.infer<typeof rainRegExcel>)=> {
if(values.chckYr ===''){
ToastFormUi({body:"등록년도를 작성해주세요" ,title:'지도점검 등록'})
return
}else if(excelData ===undefined || excelData?.length === 0 ){
ToastFormUi({body:"빈 파일 및 파일 오류 입니다." ,title:'지도점검 등록'})
return
}
}, [files])
if (excelData) {
rainChkExcelDataUPload(excelData);
}
}
return (
<>
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<div>
<Title
title={
@@ -57,25 +80,22 @@ export default function ChkgdExcel({ type }: { type: string }) {
{"○점검정보 입력"}
</h3>
<Button className="">저장</Button>
<Button className="" type="submit">
저장
</Button>
</div>
<div>
<FormField
control={form.control}
name="chckYmd"
name="chckYr"
render={({ field }) => (
<FormUi label="점검일자">
<DatePicker
mode="single"
field={{
value:
field.value && !isNaN(new Date(field.value).getTime())
? new Date(field.value)
: new Date(), // Provide a default Date value
onChange: (date) => field.onChange(date),
}}
selectClass={selectClass}
<FormUi label="등록년도">
<Input
className={`text-3xl`}
type="text"
value={field.value}
onChange={field.onChange}
/>
</FormUi>
)}
@@ -87,16 +107,20 @@ export default function ChkgdExcel({ type }: { type: string }) {
render={({ field }) => (
<FormUi label="점검결과 파일">
<FileUpload
files={field.value}
setFiles={setFiles}
files={files || []}
setFiles={(files: File[] | null ) => {
if(files) setFiles(files)
} }
fileTypes="xlsx"
></FileUpload>
</FormUi>
)}
/>
</div>
</form>
</Form>
</div>
</>
);
}
@@ -1,10 +1,10 @@
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, useState } from "react";
import { GuideDetailsTable } from "../../table/chkgdTable/guideDetailTable/guideDetailTable";
import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
const { rainChkgdn, rainChkDetilUpdate, rainChkGuidUpdate } = useWrStore(
@@ -1,43 +1,44 @@
import { useWrStore } from "@/app/store";
import type { TableProps } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg";
import type { TableTripleProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { rainSttnHeadListType } from "@/app/store/ruseFcltMng/fcltSttn/rainSttn/headList";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@common/business_components/ui";
import { Button, Checkbox } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
export default function HeadChModal({type }:{type: string }) {
const { sttnCommon ,chSttnHead} = useWrStore((state) => state);
const { rainSttn ,rainChSttnHead} = useWrStore((state) => state);
const { rainSttHeadList,pbnSttHeadList } =sttnCommon;
let items = rainSttHeadList.map(item => ({id:item.id, label:item.title}));
const { rainSttHeadList, rainSttNodeList } =rainSttn;
let items = rainSttHeadList.map(item => ({id:item.id, title:item.title, val:item.visible }));
const FormSchema = z.object({
data: z.array(z.string()).refine((value) => value.some((item) => item), {
message: "최소한 하나를 선택해주시길 바랍니다.",
}),
})
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
data: [],
},
})
const onSubmit = (val : z.infer<typeof FormSchema>) =>{
if(val?.data.length > 0)
chSttnHead(val?.data, 'rain')
// const FormSchema =
// z.object({
// id: z.string().refine((value) => value.some((item) => item), {
// message: "최소한 하나를 선택해주시길 바랍니다.",
// }),
// visible: z.boolean()
// })
const form = useForm<z.infer<typeof rainSttnHeadListType>>({
resolver: zodResolver(rainSttnHeadListType),
defaultValues: [],
})
useEffect(() =>{
form.reset(rainSttHeadList)
},[rainSttHeadList])
const onSubmit = (headList : z.infer<typeof rainSttnHeadListType> ) =>{
rainChSttnHead(headList)
}
return (
@@ -45,57 +46,41 @@ export default function HeadChModal({type }:{type: string }) {
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="data"
render={() => (
<FormItem>
<div className="mb-4">
<FormLabel className="text-2xl"> 조회항목 설정</FormLabel>
<h3>조회항목 설정</h3>
</div>
{items.map((item) => (
{items.map((item,index) => (
<FormField
key={item.id}
key={`${index}.id`}
control={form.control}
name="data"
name={`${index}.visible`}
render={({ field }) =>
{
return (
<FormItem
key={item.id}
key={`${index}.id`+'item'}
className="flex flex-row items-start space-x-3 space-y-0"
>
<FormControl>
<Checkbox
checked={field.value?.includes(item.id)}
checked={field.value}
onCheckedChange={(checked) =>
{
return checked
? field.onChange([...field.value, item.id])
: field.onChange(
field.value?.filter(
(value) => value !== item.id
)
);
}
field.onChange(checked);
return;
}
}
/>
</FormControl>
<FormLabel className="text-xl">
{item.label}
{item.title}
</FormLabel>
</FormItem>
);
}}
/>
))}
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">항목 표출 변경</Button>
</form>
</Form>
@@ -1,8 +1,7 @@
"use client";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
import { useWrStore } from "@/app/store";
import type {
rainChkZodType,
splRuseWaterType,
} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
@@ -30,7 +29,6 @@ export function GuideDetailsTable({
const { code, rainChkgdn } = useWrStore((state) => state);
const [guidData, setGuidData] = useState<splRuseWaterType[]>();
const nodeList = headMakeprfmnc(headList, rainChkgdn?.rainHeadNm);
const handleChange = (
rowIndex: number,
@@ -89,7 +87,7 @@ export function GuideDetailsTable({
<>
<div className={`card !m-[1.2rem] !p-0r `}>
<Table variant="secondary">
<TableHeader className="font-bold">{nodeList}</TableHeader>
<TableHeader className="font-bold">{headMakeprfmnc(headList, rainChkgdn?.rainHeadNm)}</TableHeader>
<TableBody >
{tableBody(guidData ?? [])}
</TableBody>
@@ -1,188 +1,31 @@
"use client";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
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,
chRowspanTable,
rightTableData
} from "@/components/lib/func/TableData";
import {
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<string, Set<number>>();
return (
<>
{makeTableData.map((row, rowIndex) => (
<TableRow key={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<number>();
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 (
<TableCell
key={key}
rowSpan={rowspan}
className="align-middle text-center whitespace-nowrap"
>
{key === "order" ? (
<Checkbox
checked={selectedIds.includes(row.chkgdnPk)}
onCheckedChange={(checked) =>
toggleSelection(row.chkgdnPk, checked === true)
}
></Checkbox>
) : (
value
)}
</TableCell>
);
}
// 기본 셀
return (
<TableCell
key={key}
className="text-center whitespace-nowrap"
onClick={() => handleCellClick(rowIndex, head.id)}
>
{key === "totalSplyUswtrUtztnQnt" ||
key === "totalRuseFcltUtztnQnt" ||
key === "utztnUsgCd" ? (
`${value}`
) : (
<Input
className={`${head.type === "number" ? "text-right" : "text-center"} text-3xl`}
type={head.type}
onChange={(e) => {
handleChange(rowIndex, head.id, e.target.value);
}}
value={value}
/>
)}
</TableCell>
);
})}
</TableRow>
))}
</>
);
};
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;
};
import { useCallback, useEffect, useState } from "react";
export default function RainChkgdTable({
detailUp,
detailUp,
handleClick=() => {},
deleteData
}: {
detailUp: (data: rainChkZodType[]) => void;
handleClick?: (data:any) => void;
deleteData:(selectedIds:number[])=>void
}) {
const { code, rainChkgdn } = useWrStore((state) => state);
const [makeTableData, setMakeTableData] = useState<any[]>([]);
const { rainChk } = rainChkgdn;
const [selectedIds, setSelectedIds] = useState<number[]>([]);
const [upRaintDetail, setUpRaintDetail] = useState<rainChkZodType[]>([]);
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)
@@ -193,48 +36,60 @@ export default function RainChkgdTable({
field: keyof (typeof makeTableData)[0],
value: string | number
) => {
setMakeTableData((prev) =>
prev.map((row, idx) =>
idx === rowIndex ? { ...row, [field]: value } : row
prev.map((row, idx) => {
return idx === rowIndex ? { ...row, [field]: value } : row
}
)
);
};
const nodeList = headMakeprfmnc(
rainChkgdn?.rainChkgdnHeadList,
rainChkgdn?.rainHeadNm
);
const handleCellClick= useCallback((index: number, headId: string) => {
if (
headId === "totalSplyUswtrUtztnQnt" ||
headId === "totalRuseFcltUtztnQnt"
) {
handleClick(makeTableData[index])
}
},[makeTableData, handleClick]);
useEffect(() => {
const rainChg = rainChk.map((item: any) => {
setSelectedIds([])// 셀렉트 초기화를 위한 작업
const rainChg = rainChkgdn.rainChk.map((item: any) => {
const bud = tableData([item.building], { code });
return {
...item,
...bud[0],
rowspan: item.rainyDetails?.length,
};
});
setMakeTableData(rightTableData(rainChg));
}, [rainChk, code]);
const tableTotalData = rightTableData(rainChg)
setMakeTableData(tableTotalData);
}, [rainChkgdn.rainChk, code]);
useEffect(() => {
const selectedData = makeTableData.filter((item) =>
selectedIds.includes(item.chkgdnPk)
);
if (selectedData.length > 1) {
const updateTableData = rainChk
//데이터를 평탄화 한것중에 체크박스 선택한 테이블만 선택
const selectedData = makeTableData.filter((item) =>selectedIds.includes(item.chkgdnPk));
if (selectedData.length > 0) {
const updateTableData = rainChkgdn.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) {
console.log(findRain)
return {
...rd,
ph: Number(findRain.ph),
@@ -260,39 +115,47 @@ export default function RainChkgdTable({
}
})
.filter(Boolean);
setUpRaintDetail(updateTableData as rainChkZodType[]);
}
}, [makeTableData]);
}, [makeTableData,selectedIds]);
useEffect(() => {
detailUp(upRaintDetail);
}, [upRaintDetail]);
useEffect(() =>{
if(selectedIds.length >0){
// 삭제를 위한 데이터 삽입
deleteData(selectedIds )
}
},[selectedIds])
useEffect(() => {
},[])
return (
<>
<Table variant="secondary">
<TableHeader className="font-bold">{nodeList}</TableHeader>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(
rainChkgdn?.rainChkgdnHeadList,
rainChkgdn?.rainHeadNm
)}
</TableHeader>
<TableBody>
{totalData(
makeTableData,
rainChkgdn.rainChkgdnHeadList,
handleChange,
toggleSelection,
selectedIds,
handleCellClick
)}
</TableBody>
</Table>
<UiModal
open={isModal.open}
onOpenChange={() => {
setIsModal({ open:!open , data:{} });
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal type={"RNB"} obj={isModal.data} />}
></UiModal>
</>
<TableBody>
{chRowspanTable(
makeTableData,
rainChkgdn.rainChkgdnHeadList,
handleChange,
toggleSelection,
selectedIds,
handleCellClick
)}
</TableBody>
</Table>
);
}
@@ -1,6 +1,6 @@
'use client'
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/page";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
import { useWrStore } from "@/app/store";
import { UiTable } from "@common/business_components/ui";
+37 -46
View File
@@ -1,55 +1,46 @@
import { Button } from "@common/components/ui";
import Link from "next/link";
import toast from "react-hot-toast";
interface toastFormType {
body: string;
title: string;
url?: string;
buttonName?: string;
}
export function ToastFormUi(body:string,title:string,url:string,buttonName:string){
export function ToastFormUi({ body, title, url, buttonName }: toastFormType) {
//const router = useRouter();
return(
toast.custom((t) => (
<div
className={`${
t.visible ? 'animate-enter' : 'animate-leave'
} w-4/12 h-40 bg-white shadow-lg rounded-lg pointer-events-auto flex ring-1 ring-black ring-opacity-5`}
>
<div className="w-full flex-1 py-10">
<div className="flex items-start">
<div className="flex-shrink-0 pt-0.5">
</div>
<div className="ml-3 flex-1">
<p className="text-xl font-medium underline">
{title}
</p>
<p className="mt-1 text-2xl">
{body}
</p>
</div>
</div>
</div>
<div className="flex py-20">
<Button
size='sm'
onClick={() => toast.dismiss(t.id)}
>
<Link href={url}> {buttonName}</Link>
</Button>
</div>
<div className="flex pl-4 pr-4 py-20">
<Button
onClick={() => toast.dismiss(t.id)}
size='sm'
>
닫기
</Button>
return toast.custom((t) => (
<div
className={`${
t.visible ? "animate-enter" : "animate-leave"
} w-4/12 h-40 bg-white shadow-lg rounded-lg pointer-events-auto flex ring-1 ring-black ring-opacity-5`}
>
<div className="w-full flex-1 py-10">
<div className="flex items-start">
<div className="flex-shrink-0 pt-0.5"></div>
<div className="ml-3 flex-1">
<p className="text-xl font-medium underline">{title}</p>
<p className="mt-1 text-2xl">{body}</p>
</div>
</div>
))
)
}
</div>
<div className="flex py-20">
{url && buttonName ? (
<Button size="sm" onClick={() => toast.dismiss(t.id)}>
<Link href={url}> {buttonName}</Link>
</Button>
) : (
<></>
)}
</div>
<div className="flex pl-4 pr-4 py-20">
<Button onClick={() => toast.dismiss(t.id)} size="sm">
닫기
</Button>
</div>
</div>
));
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -5,7 +5,7 @@ import presetConfig from "../../tailwind.config.preset";
export default {
presets: [presetConfig],
content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx,mdx}",
"../../packages/common/business_components/src/ui/**/*.{js,ts,jsx,tsx,mdx}",
@@ -43,6 +43,7 @@
"sonner": "^2.0.1",
"tailwind-merge": "^3.0.1",
"xlsx": "^0.18.5",
"xlsx-populate": "^1.21.0",
"zod": "^3.24.2"
},
"devDependencies": {
@@ -58,6 +59,7 @@
"@storybook/test": "^8.5.3",
"@storybook/theming": "^8.5.5",
"@vitejs/plugin-react": "^4.3.4",
"@xlsx/xlsx-populate": "^0.0.8",
"autoprefixer": "^10.4.20",
"eslint": "^9.17.0",
"eslint-plugin-react-hooks": "^5.0.0",
@@ -0,0 +1,24 @@
import * as XlsxPopulate from '@xlsx/xlsx-populate';
export const excelStyle = async (data: ArrayBuffer, range: string = "A1:V3", fileNm:string) => {
console.log("excelStyle", data, range, fileNm);
const workbook = await XlsxPopulate.Workbook.fromData(data);
const rangeCells = workbook.activeSheet(0)?.sheet(0)?.range(range);
console.log(rangeCells);
rangeCells?.style((styleQ)=>{
console.log(styleQ);
styleQ.fill({ type: "solid", color: {rgb:"9bc1e7"} });
styleQ.borderEach( { style: "thin", color: { rgb: "FFFFFF" } } );
styleQ.wrapText(true);
// styleQ.fontColor({rgb:"FFFFFF"});
styleQ.fontSize(15);
styleQ.horizontalAlignment("center");
styleQ.verticalAlignment("center");
styleQ.bold(true);
});
const outputData = await workbook.output("array-buffer");
const blob = new Blob([outputData], { type: "application/octet-stream" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = fileNm+".xlsx";
link.click();
}
@@ -0,0 +1,86 @@
import * as XLSX from 'xlsx';
import { excelStyle } from './excelStyle';
type ExcelDownloadProps = {
data: JSON | JSON[];
fileName: string;
sheetNameArray: string[];
headerRange: string;
}
export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3'}: 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]);
excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName);
};
export const filePicked=(oFile: File, headerNum:number=0):Promise<JSON | undefined> =>{
// Create A File Reader HTML5
const reader = new FileReader();
return new Promise<JSON | undefined>((resolve, reject) => {
// Ready The Event For When A File Gets Selected
reader.onload = function (e) {
const data = e.target?.result;
if (!data) {
console.error("Failed to read file: e.target.result is null");
resolve(undefined);
return;
}
//셀데이터에서 데이트 형식으로 입력하면 yyyymmdd 형식으로 변환
const wb = XLSX.read(data, { type: 'binary', cellDates: true, dateNF: "yyyymmdd" });
let jsonXls: JSON | undefined;
// Loop Over Each Sheet
wb.SheetNames.forEach(function (sheetName,index ) {
// Obtain The Current Row As CSV
// 일단 첫번째 시트만 읽을 수 있도록 수정
if(index ===0){
const sheet = wb.Sheets[sheetName];
if (sheet) {
jsonXls = XLSX.utils.sheet_to_json(sheet, { range: headerNum, raw:false }) as unknown as JSON;
} else {
console.error(`Sheet "${sheetName}" is undefined.`);
}
}
});
resolve(jsonXls);
};
reader.onerror = function () {
console.error("Error reading file");
reject(undefined);
};
// Tell JS To Start Reading The File.. You could delay this if desired
reader.readAsBinaryString(oFile);
});
}
export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, headerNum:number=0, headerRange='A1:V3'):Promise<JSON | undefined> =>{ // Create A File Reader HTML5
return new Promise<JSON | undefined>(() => {
// Ready The Event For When A File Gets Selected
const wb = XLSX.read(oFile, { type: 'binary' });
// Loop Over Each Sheet
wb.SheetNames.forEach(async function (sheetName, index) {
// Obtain The Current Row As CSV
if(index==0){
const sheet = wb.Sheets[sheetName];
if (sheet) {
//오리진 확인 test 필요
// const sheet = XLSX.utils.json_to_sheet(data);
XLSX.utils.sheet_add_aoa(sheet, data, { origin: 'A'+headerNum });
// XLSX.utils.book_append_sheet(wb, sheet, 'test');
await excelStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), headerRange, fileNm)
} else {
console.error(`Sheet "${sheetName}" is undefined.`);
}
}
});
});
}
@@ -1,52 +0,0 @@
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');
};
export const filePicked=(oFile: File, headerNum:number=0):Promise<JSON | undefined> =>{
// Create A File Reader HTML5
const reader = new FileReader();
return new Promise<JSON | undefined>((resolve, reject) => {
// Ready The Event For When A File Gets Selected
reader.onload = function (e) {
const data = e.target?.result;
if (!data) {
console.error("Failed to read file: e.target.result is null");
resolve(undefined);
return;
}
const wb = XLSX.read(data, { type: 'binary' });
let jsonXls: JSON | undefined;
// Loop Over Each Sheet
wb.SheetNames.forEach(function (sheetName) {
// Obtain The Current Row As CSV
const sheet = wb.Sheets[sheetName];
if (sheet) {
jsonXls = XLSX.utils.sheet_to_json(sheet, { range: headerNum }) as unknown as JSON;
} else {
console.error(`Sheet "${sheetName}" is undefined.`);
}
});
resolve(jsonXls);
};
reader.onerror = function () {
console.error("Error reading file");
reject(undefined);
};
// Tell JS To Start Reading The File.. You could delay this if desired
reader.readAsBinaryString(oFile);
});
}
@@ -6,14 +6,22 @@ const dropZoneConfig = {
maxSize: 1024 * 1024 * 4,
multiple: true,
};
interface FileUploadProps {
files: File[]; // 파일 배열
setFiles: (files: File[] | null) => void; // 파일 배열 세터
fileTypes?: string; // 옵션 (파일 확장자 문자열)
}
export const FileUpload =
(({ ...props }) => {
({ files, setFiles, fileTypes }: FileUploadProps) => {
return (
<FileUploader
value={props.files}
onValueChange={props.setFiles}
value={files}
onValueChange={setFiles}
dropzoneOptions={dropZoneConfig}
acceptName={props?.fileTypes}
acceptName={fileTypes}
className="relative bg-background rounded-lg p-2"
>
<FileInput
@@ -23,18 +31,18 @@ export const FileUpload =
<div className="flex items-center justify-center flex-col p-8 w-full ">
<CloudUpload className='text-gray-500 w-10 h-10' />
<p className="mb-1 text-sm text-gray-500 dark:text-gray-400">
<span className="font-semibold">Click to upload</span>
&nbsp; or drag and drop
<span className="font-semibold">클릭 후 업로드 </span>
&nbsp; 혹은 파일을 드래그 해주세요
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
{!props?.fileTypes?"SVG, PNG, JPG, GIF":props?.fileTypes}
{!fileTypes?"SVG, PNG, JPG, GIF":fileTypes}
</p>
</div>
</FileInput>
<FileUploaderContent>
{props.files &&
props.files.length > 0 &&
props.files.map((file:File, i:number) => (
{files&&
files.length > 0 &&
files.map((file:File, i:number) => (
<FileUploaderItem key={i} index={i}>
<Paperclip className="h-4 w-4 stroke-current" />
<span>{file.name}</span>
@@ -43,4 +51,4 @@ export const FileUpload =
</FileUploaderContent>
</FileUploader>
)
})
}
@@ -1,7 +1,7 @@
export * from "./chart";
export * from "./date_picker";
export * from "./dialog_ui";
export * from "./excel_download";
export * from "./excel";
export * from "./file-upload";
export * from "./form";
export * from "./form_ui";
@@ -19,3 +19,4 @@ export * from "./tab";
export * from "./table";
export * from "./table_div";
export * from "./title";
@@ -13,6 +13,7 @@ type SearchBaseType = {
selectMiddleRegionData?: SelectDataType[] | [];
selectEnvPartData?: EnvPartSelectDataType[] | [];
queryClick:(returnType:ReturnType) => void;
excelName?:string;
excelClick:(returnType:ReturnType) => void;
initClick:() => void;
btnClass:string;
@@ -39,6 +40,7 @@ function SearchBaseForm ({
selectMiddleRegionData,
selectEnvPartData,
btnClass,
excelName,
queryClick,
excelClick,
initClick,
@@ -120,7 +122,7 @@ function SearchBaseForm ({
</SearchFormLeft>
<SearchFormRight>
<Button className={btnClass} color="green" onClick={excelDownload}>
엑셀다운로드
{excelName?excelName:"엑셀다운로드"}
</Button>
<div>
<Button className={btnClass} onClick={initVal}>
@@ -8,16 +8,20 @@ interface TableUpperProps {
row? : number;
rowSpan?: number;
colSpan?: number;
visible?:boolean;
}
const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => {
const maxRow = upHeadList.reduce((max, head) => Math.max(max, head.row || 0), 0);
const maxRow = upHeadList?.reduce((max, head) => Math.max(max, head.row || 0), 0);
//upHeadList.forEach((item) => item.visible ?item.visible:true)
if(maxRow == 0){
return (
<>
<TableRow className="bg-gray-50">
{upHeadList.map((head: TableUpperProps) => {
{upHeadList
.filter((item) => item.visible != false)
.map((head: TableUpperProps) => {
return (
<TableHead
key={head.id}
@@ -38,7 +42,9 @@ const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => {
<>
{Array.from({ length: maxRow + 1 }, (_, rowIndex) => (
<TableRow key={rowIndex+ " headerRow"} className="bg-gray-50">
{upHeadList.map((head: TableUpperProps) => {
{upHeadList
.filter((item) => item.visible != false)
.map((head: TableUpperProps) => {
if (head.row === rowIndex) {
return (
<TableHead
@@ -20,6 +20,7 @@ type UiHeadProps = {
id: string;
title: string;
align?: string;
visible?:boolean;
}
export function UiTable({ tableData, headlist, pageSize, total, headName, children, cellClick, onPageChange, className = '', resetPageNo = false }: UiTableProps) {
@@ -58,7 +59,9 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
<TableBody className='text-center'>
{tableData.length > 0 ? tableData?.map((el: { [key: string]: any}, index) => (
<TableRow key={`row-${index}`}>
{headlist?.map((head) => (
{headlist
.filter((item) => item.visible != false)
.map((head) => (
head.id && head.id.length > 1 && (
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${