diff --git a/apps/wr/app/map/newWindowPopup.tsx b/apps/wr/app/map/newWindowPopup.tsx index ebfcac1ca..777c3dcf2 100644 --- a/apps/wr/app/map/newWindowPopup.tsx +++ b/apps/wr/app/map/newWindowPopup.tsx @@ -2,12 +2,11 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { excelDownload } from "@/components/lib/func/commom"; -import { Title, UiTable, UITab, ContentsDiv } from '@common/business_components'; +import { Title, UiTable, UITab } from '@common/business_components'; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import { Button } from "@common/components/ui"; import React, { useCallback, useState, useEffect } from 'react'; import NewWindowPortal from '@/app/map/newWindowPortal'; -import PbnstPrfmncSttnPopup from "@/app/map/pbnstPrfmncSttnPopup"; import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; import type { chgBuilding, customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; @@ -16,6 +15,7 @@ import RswtrPrfmncsSttnPopup from "@/app/map/rswtrPrfmncSttnPopup"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import HtdflPrfmncSttnPopup from "@/app/map/htdflPrfmncSttnPopup"; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import { getFetch } from "@/components/lib/api"; interface NewWindowPopupProps { featureData: any; @@ -24,13 +24,6 @@ interface NewWindowPopupProps { onClose: () => void; } -// 탭 -const TABS = [ - { val: "0", text: "재이용시설1" }, - { val: "1", text: "재이용시설2" }, - { val: "2", text: "재이용시설n" }, -]; - // 데이터의 속성(key)을 사용자에게 보여줄 한글 이름으로 변환하기 위한 맵 // 실제 데이터에 맞게 이 부분을 확장해야 합니다. const propertyNameMap: { [key: string]: string } = { @@ -47,9 +40,10 @@ const NewWindowPopup: React.FC = ({ checkedLayersData = [], onClose }) => { - const [activeTab, setActiveTab] = useState(TABS[0]?.val ?? "0"); + const [tabData, setTabData] = useState<{ id: string; name: string; data: any }[]>([]); + const [activeTab, setActiveTab] = useState('0'); // swcho : useState의 true, false 값 변경하여 목록, 상태 테스트 하였음 - const [showDetailView, setShowDetailView] = useState(true); // 상세정보 화면 표시 상태 추가 + const [showDetailView, setShowDetailView] = useState(false); // 상세정보 화면 표시 상태 추가 // onClose 함수를 useCallback으로 메모이제이션 const memoizedOnClose = useCallback(() => { @@ -67,6 +61,7 @@ const NewWindowPopup: React.FC = ({ } = useWrStore((state) => state); const [bdstTable, setBdstTable] = useState(); const [pageNation, setPageNation] = useState(1); + const [pbnstRuseFcltPk, setPbnstRuseFcltPk] = useState(''); const [pbnDetaileData, setPbnDetaileData] = useState<{ isModal: boolean; data: customPbnst; @@ -107,10 +102,6 @@ const NewWindowPopup: React.FC = ({ return null; } - // 2. RuseMngTable에 필요한 tableData를 생성합니다. (단일 행 데이터) - const tableData = [featureData]; - console.log("tableData", tableData); - // 물재이용시설 cellClick 이벤트 (상세정보) const pbnstCellClick = (index: number | undefined) => { if ( @@ -118,20 +109,93 @@ const NewWindowPopup: React.FC = ({ pbnstSttn.pbnstSttnRes && pbnstSttn.pbnstSttnRes[index] ) { - const pbnstRuseFcltPk = pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk; - getPbnStnDetail(pbnstRuseFcltPk); + setPbnstRuseFcltPk(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk); + fetchpbnstDetail(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk) + setActiveTab(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk) + setShowDetailView(true); // 상세정보 화면 표시 상태 변경 } }; - useEffect(() => { - setBdstTable(pbnstSttn.pbnstSttnRes); - }, [pbnstSttn.pbnstSttnRes]); + useEffect(() => { + if (!pbnstSttn.isInit) { + pbnSttnInit("1", "13",{ + partValue: "A", + sidoValue: "0", + sigunValue: "", + regionValue: "", + unitWaterShedValue: "", + middleRegionValue: "", + envPartValue: "", + sidoText: "", + sigunText: "" + }, String(new Date().getFullYear())); + } + }, [pbnstSttn.isInit]); + + useEffect(() => { + setBdstTable(pbnstSttn.pbnstSttnRes); + }, [pbnstSttn.pbnstSttnRes]); + +// 재이용시설 상세정보 + const setTabDataFunc = (res:any, pk:string) => { + setTabData((prev) => { + if (prev.some((tab) => tab.id === pk)) { + return prev; // 이미 존재하는 탭이면 추가하지 않음 + } + return [...prev, { id: pk, name: `재이용시설 ${prev.length + 1}`, data: res }]; + }); + } + // 재이용시설 조회 + const fetchpbnstDetail = async (featureCd: string) => { + try { + const response = await getFetch("wr", `/reuseFc/pubFc/${featureCd}`); + // 중복 데이터 추가 방지 + setTabDataFunc(response, featureCd); + } catch (error) { + console.error("Error fetching data:", error); + } + }; + // 재이용시설 페이징처리 관련 함수 + const onPageChangeHandler = useCallback((page: number) => { + pbnstSttnSearch( + String(page), + String(13), + { + partValue: "A", + sidoValue: "0", + sigunValue: "", + regionValue: "", + unitWaterShedValue: "", + middleRegionValue: "", + envPartValue: "", + sidoText: "", + sigunText: "", + }, + "", + String(new Date().getFullYear()) + ); + }, []); + // useEffect(() => { + // if (featureData) { + // const selectedVal = featureData.getProperties(); + // const featureCd = selectedVal?.swtrmt_fclt_cd; + // if (featureCd && featureCd !== pbnstRuseFcltPk) { + // setPbnstRuseFcltPk(featureCd); // 현재 호출된 featureCd 저장 + // setActiveTab(featureCd) + // fetchpbnstDetail(featureCd); // 상세정보 가져오기 + // } + // } + // }, [featureData]); useEffect(() => { - if (pbnstSttn.pbnstDetail.pbnstRuseFcltPk) setShowDetailView(true); + if (pbnstSttn.pbnstDetail) { + setPbnDetaileData({ + isModal: true, + data: pbnstSttn.pbnstDetail, + }); + } }, [pbnstSttn.pbnstDetail]); - // 빗물재이용시설 cellClick 이벤트 (상세정보) const rainCellClick = (index: number | undefined, headId: string) => { if ( @@ -183,7 +247,8 @@ const NewWindowPopup: React.FC = ({ const hasWaterTreatmentLayer = checkedLayersData.some(layer => layer.data?.lyrNm?.includes('하수처리') || layer.data?.lyrNm?.includes('재이용시설') ); - + const actTabData = tabData.find((tab) => tab.id === activeTab); + console.log('tavbData',actTabData) // swcho : true, false 값 변경하여 시설 변경하여 테스트하였음 // 재이용시설 const isPbnst = true; @@ -193,182 +258,181 @@ const NewWindowPopup: React.FC = ({ const isRswt = false; // 온배수시설 const isHtdfl = false; - - - return ( -
- {/* 체크된 레이어가 없는 경우 (재이용시설 목록) */} - {isPbnst && ( + if (isPbnst) { + if (showDetailView) { + // 재이용시설 상세 + return ( <> - {showDetailView ? ( - // 재이용시설 상세 - <> -
- - </div> - <div className="flex justify-between items-center mb-8"> - <UITab - defaultValue={TABS[0]?.val} - tabList={TABS.map((tab) => ({ - value: tab.val, - label: tab.text, - onClick: () => setActiveTab(tab.val), - }))} - children={undefined} - /> - </div> - <PbnstSttnModal - data={pbnDetaileData.data || ({} as customPbnst)} - titleVisible={false} - /> - <PbnstPrfmncSttnPopup isVisible={false} /> - </> - ) : ( - // 재이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='하수재이용시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> - } - headlist={pbnstSttn.pbnstSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - pbnstCellClick(index); - }} - onPageChange={setPageNation} - /> - </> - )} + <div className="flex justify-between items-center mb-4"> + <Title title="하수재이용시설 상세정보" /> + </div> + <div className="flex justify-between items-center mb-8"> + <UITab + defaultValue={activeTab} + tabList={tabData.map((tab) => ({ + value: tab.id, + label: tab.name, + onClick: () => setActiveTab(tab.id), + }))} + children={undefined} + /> + </div> + <PbnstSttnModal + data={tabData.find((tab) => tab.id === activeTab)?.data[0] || ({} as customPbnst)} + titleVisible={false} + /> </> - )} - {/* 빗물이용시설 */} - {isRain && ( + ); + } else { + // 재이용시설 목록 + return ( <> - {showDetailView ? ( - // 빗물이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='빗물이용시설 상세정보' /> - </div> - <RainPrfmncSttnPopup rainForm={rainDetailModal.data as customRainBdst} isModal={false} /> - {/* TODO: 지도 점검 결과 현황 추가 할 것 */} - </> - ) : ( - // 빗물이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='빗물이용시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={rainTable || []} - children={ - <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> - } - headlist={rainSttn.rainSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - rainCellClick(index ?? undefined, headId) - }} - onPageChange={setPageNation} - /> - </> - )} + <div className="flex justify-between items-center"> + <Title title="하수재이용시설 현황" /> + <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> + </div> + <UiTable + headName={[]} + tableData={bdstTable || []} + children={<HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} />} + headlist={pbnstSttn.pbnstSttHeadList} + pageSize={20} + total={100000} + cellClick={(index: number | undefined, headId: string) => { + pbnstCellClick(index); + }} + onPageChange={onPageChangeHandler} + /> </> - )} - {/* 중수도시설 */} - {isRswt && ( + ); + } + } + + if (isRain) { + if (showDetailView) { + // 빗물이용시설 상세 + return ( <> - {showDetailView ? ( - // 재이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='중수도시설 상세정보' /> - </div> - <RswtrPrfmncsSttnPopup rswtForm={rswtrDetailModal.data as customRswtBdst} isModal={false} /> - {/* TODO: 지도 점검 결과 현황 추가 할 것 */} - </> - ) : ( - // 재이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='중수도시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={rswtrTable || []} - children={ - <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> - } - headlist={rswtSttn.rswtSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - rswtCellClick(index, headId); - }} - onPageChange={setPageNation} - /> - </> - )} + <div className="flex justify-between items-center mb-4"> + <Title title="빗물이용시설 상세정보" /> + </div> + <RainPrfmncSttnPopup rainForm={rainDetailModal.data as customRainBdst} isModal={false} /> </> - )} - {/* 온배수시설 */} - {isHtdfl && ( + ); + } else { + // 빗물이용시설 목록 + return ( <> - {showDetailView ? ( - // 재이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='온배수시설 상세정보' /> - </div> - {/* <HtdflPrfmncSttnPopup htdflForm={htdflDetailModal.data as customHtdflBdst} isModal={false} /> */} - <HtdflPrfmncSttnPopup htdflForm={htdflDetailModal.data as customHtdflBdst} isModal={false} /> - </> - ) : ( - // 재이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='온배수시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> - } - headlist={htdflSttn.htdflSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - htdflCellClick(index ?? undefined, headId); - }} - onPageChange={setPageNation} - /> - </> - )} + <div className="flex justify-between items-center"> + <Title title="빗물이용시설 현황" /> + <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> + </div> + <UiTable + headName={[]} + tableData={rainTable || []} + children={<HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} />} + headlist={rainSttn.rainSttHeadList} + pageSize={20} + total={100000} + cellClick={(index: number | undefined, headId: string) => { + rainCellClick(index ?? undefined, headId); + }} + onPageChange={setPageNation} + /> </> - )} - </div> - ); + ); + } + } + + if (isRswt) { + if (showDetailView) { + // 중수도시설 상세 + return ( + <> + <div className="flex justify-between items-center mb-4"> + <Title title="중수도시설 상세정보" /> + </div> + <RswtrPrfmncsSttnPopup rswtForm={rswtrDetailModal.data as customRswtBdst} isModal={false} /> + </> + ); + } else { + // 중수도시설 목록 + return ( + <> + <div className="flex justify-between items-center"> + <Title title="중수도시설 현황" /> + <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> + </div> + <UiTable + headName={[]} + tableData={rswtrTable || []} + children={<HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} />} + headlist={rswtSttn.rswtSttHeadList} + pageSize={20} + total={100000} + cellClick={(index: number | undefined, headId: string) => { + rswtCellClick(index, headId); + }} + onPageChange={setPageNation} + /> + </> + ); + } + } + + if (isHtdfl) { + if (showDetailView) { + // 온배수시설 상세 + return ( + <> + <div className="flex justify-between items-center mb-4"> + <Title title="온배수시설 상세정보" /> + </div> + <HtdflPrfmncSttnPopup htdflForm={htdflDetailModal.data as customHtdflBdst} isModal={false} /> + </> + ); + } else { + // 온배수시설 목록 + return ( + <> + <div className="flex justify-between items-center"> + <Title title="온배수시설 현황" /> + <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> + </div> + <UiTable + headName={[]} + tableData={htdflTable || []} + children={<HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} />} + headlist={htdflSttn.htdflSttHeadList} + pageSize={20} + total={100000} + cellClick={(index: number | undefined, headId: string) => { + htdflCellClick(index ?? undefined, headId); + }} + onPageChange={setPageNation} + /> + </> + ); + } + } + + return null; // 조건에 맞는 콘텐츠가 없을 경우 }; return ( diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index 033d3a23d..328bb8b88 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -315,7 +315,7 @@ export default function Page() { </Tooltip> </TooltipProvider> - + <Button size={"sm"} onClick={() => { @@ -344,7 +344,7 @@ export default function Page() { rainChkData={rainChkgdn.rainChk} pageNation={rainPageNation} onPageChange={rainPageChange} - /> + pageCount={rainChkgdn.rainChkCount} /> ) : ( <RswtChkgdTable detaiRswtlUpdate={setUpdateRSwtDetail} @@ -353,6 +353,7 @@ export default function Page() { rswtChkData={rswtChkgdn.rswtChkRes} pageNation={rswtPageNation} onPageChange={rswtPageChange} + pageCount={rswtChkgdn.rswtChkCount} /> )} </ListDiv> diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index 8960f468d..60040833b 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -1,6 +1,8 @@ "use client"; import { useWrStore } from "@/app/store"; +import { commonCd, rainPageSize } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; +import { rswtPageSize } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { excelDownload, yearOptions @@ -39,6 +41,8 @@ export default function Page() { }); const [selFcltDiv, setSelFcltDiv] = useState("RNB"); + const [rainPageNation, setRainPageNation] = useState(1); + const [rswtPageNation, setRswtPageNation] = useState(1); const [isModal, setIsModal] = useState({ open: false, data: {}, @@ -47,29 +51,43 @@ export default function Page() { const cellClick = () => { if (searchYear) { if (selFcltDiv === "RNB") { - rainChkSttnSearch(searchYear, "0"); + rainChkSttnSearch(rainPageNation, rainPageSize, searchYear, commonCd); } else { - rswtChkSttnSearch(searchYear, "0"); + rswtChkSttnSearch(rswtPageNation, rswtPageSize, searchYear, commonCd); } } }; + const rainPageChange = (pageNo: number) => { + if (pageNo > 0) { + setRainPageNation(pageNo); + rainChkSttnInit(pageNo, rainPageSize, searchYear, commonCd); + } + }; + + const rswtPageChange = (pageNo: number) => { + if (pageNo > 0) { + setRswtPageNation(pageNo); + rswtChkSttnInit(pageNo, rswtPageSize, searchYear, commonCd); + } + }; + useEffect(() => { if (!rainChkSttn.isInit) { isRainSttn(true) - rainChkSttnInit(new Date().getFullYear().toString(), "0"); + rainChkSttnInit(1, rainPageSize, new Date().getFullYear().toString(), commonCd); setIsModal({ data: {}, open: false }); } - }, [rainChkSttn.isInit, rainChkSttnInit]); + }, [rainChkSttn.isInit, rainChkSttnInit, rainPageSize]); useEffect(() => { - if (!rswtChkSttn.isInit) { setIsModal({ data: {}, open: false }); - rswtChkSttnInit(new Date().getFullYear().toString(), "0"); + rswtChkSttnInit(1, rswtPageSize, new Date().getFullYear().toString(), commonCd); isRswtSttn(true) } - }, [rswtChkSttn.isInit, rswtChkSttnInit]) + }, [rswtChkSttn.isInit, rswtChkSttnInit, rswtPageSize]) + const handleClick = useCallback( @@ -163,6 +181,9 @@ export default function Page() { detailUp={() => { }} handleClick={handleClick} rainChkData={rainChkSttn.rainChkRes} + pageNation={rainPageNation} + onPageChange={rainPageChange} + pageCount={rainChkSttn.rainChkCount} /> ) : ( <RswtChkgdTable @@ -170,6 +191,9 @@ export default function Page() { deleteRswtData={() => { }} handleRswtClick={handleClick} rswtChkData={rswtChkSttn.rswtChkRes} + pageNation={rswtPageNation} + onPageChange={rswtPageChange} + pageCount={rswtChkSttn.rswtChkCount} /> )} </ListDiv> @@ -181,7 +205,7 @@ export default function Page() { setIsModal({ open: !open, data: {} }); }} bodyClass={"w-[80vw] max-w-none"} - body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />} + body={<ChkgdModal type={selFcltDiv} obj={isModal.data} setIsModal={() => { }} />} ></UiModal> <Toaster position="top-center" /> </ContentsDiv> diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index c6683accb..801e638a3 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -24,7 +24,7 @@ import { import type { TableUpperProps } from "@/app/store/common/type/header"; import toast from "react-hot-toast"; -export const rainPageSize = 10; +export const rainPageSize = 5; export const commonCd = "41"; export type rainChkZodType = z.infer<typeof rainChkZod>; @@ -132,7 +132,6 @@ const initFetch = async ( ) => { const currentYear = new Date().getFullYear().toString(); - console.log("cnt ", cnt); const rainRes = await getCountFetch( "wr", `/reuseChk/rainy` + @@ -142,7 +141,6 @@ const initFetch = async ( (sgg ? `/${sgg}` : "/0") ); - console.log(" rainRes ", rainRes); return rainRes; }; @@ -193,7 +191,6 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( toast.error("지도점검 등록이 실패되었습니다."); } } catch (error) { - console.log(error); toast.error("지도점검 등록이 실패되었습니다."); } finally { set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: false } })); diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx index 6edee720b..b875e4cba 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx @@ -28,7 +28,7 @@ import { type chHeadType } from "../rainChkgdn/headList"; import type { TableUpperProps } from "@/app/store/common/type/header"; import toast from "react-hot-toast"; -export const rswtPageSize = 10; +export const rswtPageSize = 5; const rswtChkHeadList = rswtChkHeadListExport; const rswtDetailHeadList = rswtDetailHeadListExport; @@ -43,7 +43,6 @@ export type rswtChkgdnState = { rswtChkgdn: { rswtChkHeadList: TableUpperProps[]; rswtDetailHeadList: TableUpperProps[]; - rswtHeadNm: chHeadType[]; excelList: SheetParameter[]; rswtChkRes: rswtChkZodType[]; @@ -235,7 +234,6 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( try { set((state: rswtChkgdnType) => ( { rswtChkgdn: { ...state.rswtChkgdn, isLoading: true } })); - console.log('excelData ', excelData) const res = await postFectch("/reuseChk/reuseWater", excelData); if (res.ok) { ToastFormUi({ diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx index bbbb3a61e..895f096ef 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx @@ -1,8 +1,8 @@ import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import { getFetch } from "@/components/lib/api"; +import { getCountFetch, getFetch } from "@/components/lib/api"; import type { SelectDataType } from "@common/business_components/ui"; import { rainChkgdnHeadSttnExport, ruseSttnHeadListExport, splSttnHeadListExport } from "./headList"; -import { rainMainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; +import { rainMainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { buildingExcelRainSttn } from "./excel"; import type { TableUpperProps } from "@/app/store/common/type/header"; @@ -24,20 +24,21 @@ export type rainChkSttnState = { rainChkRes: rainChkZodType[]; fcltDiv: SelectDataType[]; rainChkgdnHeadList: TableUpperProps[]; - rainHeadNm:chHeadType[]; + rainHeadNm: chHeadType[]; ruseHeadList: TableUpperProps[]; splHeadList: TableUpperProps[]; - sttnExcelList:[] + sttnExcelList: [] isInit: boolean; - isSttn:boolean; + isSttn: boolean; + rainChkCount: number; }; }; type rainChkSttnActions = { - rainChkSttnInit: (searchTxt: string, sggCd: string) => void; - rainChkSttnSearch: (searchTxt: string, sggCd: string) => void; - isRainSttn:(isSttn:boolean) => void; - getRainSttnExcel:(excelList:rainChkZodType[]) => void; + rainChkSttnInit: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void; + rainChkSttnSearch: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void; + isRainSttn: (isSttn: boolean) => void; + getRainSttnExcel: (excelList: rainChkZodType[]) => void; }; export type rainChkSttnType = rainChkSttnState & rainChkSttnActions; @@ -49,18 +50,23 @@ export const rainChkSttnStateExport: rainChkSttnState = { rainChkgdnHeadList: rainChkgdnHeadList, ruseHeadList: ruseHeadList, splHeadList: splHeadList, - rainHeadNm:rainHeadNm, + rainHeadNm: rainHeadNm, isInit: false, - sttnExcelList:[], - isSttn:false, + sttnExcelList: [], + isSttn: false, + rainChkCount: 1, }, }; -const initFetch = async (txt: string | undefined, sgg: string | undefined) => { +const initFetch = async (pageNo: number, cnt: number, txt: string | undefined, sgg: string | undefined) => { const currentYear = new Date().getFullYear().toString(); - const rainRes = await getFetch( + const rainRes = await getCountFetch( "wr", - `/reuseChk/rainy/` + (txt ? `${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0") + `/reuseChk/rainy` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/5") + + (txt ? `/${txt}` : `/${currentYear}`) + + (sgg ? `/${sgg}` : "/0") ); return rainRes; }; @@ -68,48 +74,50 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = ( set: any ) => { return { - rainChkSttnInit: async (searchTxt: string, sggCd: string) => { + rainChkSttnInit: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => { try { - const rainChkRes = await initFetch(searchTxt, sggCd); + const rainChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); return set((state: rainChkSttnState) => ({ ...state, rainChkSttn: { ...state.rainChkSttn, - rainChkRes:rainChkRes + rainChkRes: rainChkRes.data, + rainChkCount: rainChkRes.count, + isSttn: true }, })); } catch (error) { console.log(error); } }, - rainChkSttnSearch: async (searchTxt: string, sggCd: string) => { + rainChkSttnSearch: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => { try { - const rainChkRes = await initFetch(searchTxt, sggCd); + const rainChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); return set((state: rainChkSttnState) => ({ ...state, rainChkSttn: { ...state.rainChkSttn, - rainChkRes:rainChkRes + rainChkRes: rainChkRes }, })); } catch (error) { console.log(error); } - },isRainSttn :(isSttn:boolean) =>{ + }, isRainSttn: (isSttn: boolean) => { try { return set((state: rainChkSttnState) => ({ ...state, rainChkSttn: { ...state.rainChkSttn, - isSttn:isSttn + isSttn: isSttn }, })); } catch (error) { console.log(error); } - },getRainSttnExcel: async (excelList:rainChkZodType[]) => { + }, getRainSttnExcel: async (excelList: rainChkZodType[]) => { try { const excelData = buildingExcelRainSttn(excelList) @@ -118,7 +126,7 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = ( ...state, rainChkSttn: { ...state.rainChkSttn, - sttnExcelList:excelData + sttnExcelList: excelData }, })); } catch (error) { diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx index cd95ef1fc..519cd39b2 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx @@ -3,7 +3,7 @@ import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headL import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; -import { getFetch } from "@/components/lib/api"; +import { getCountFetch, getFetch } from "@/components/lib/api"; import { buildingExcelRswtSttn } from "./excel"; const rswtChkHeadList = rswtChkSttnHeadListExport; @@ -20,14 +20,15 @@ export type rswtChkSttnState = { rswtChkRes: rswtChkZodType[]; isInit: boolean; isSttn: boolean; + rswtChkCount: number; }; }; type rswtChkSttnActions = { - rswtChkSttnInit: (searchTxt: string, sggCd: string) => void; + rswtChkSttnInit: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void; isRswtSttn: (isSttn: boolean) => void; getRswtSttnExcel: (excelList: rswtChkZodType[]) => void; - rswtChkSttnSearch: (searchTxt: string, sggCd: string) => void; + rswtChkSttnSearch: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void; }; export type rswtChkSttnType = rswtChkSttnState & rswtChkSttnActions; @@ -41,15 +42,18 @@ export const rswtChkStateExport: rswtChkSttnState = { rswtChkRes: [], isInit: false, isSttn: false, + rswtChkCount: 1, }, }; -const initFetch = async (year: string | undefined, sgg: string | undefined) => { +const initFetch = async (pageNo: number, cnt: number, year: string | undefined, sgg: string | undefined) => { const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await getFetch( + const rswtChkRes = await getCountFetch( "wr", - `/reuseChk/reuseWater/` + - (year ? `${year}` : currentYear) + + `/reuseChk/reuseWater` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/20") + + (year ? `/${year}` : `/${currentYear}`) + (sgg ? `/${sgg}` : "/0") ); return rswtChkRes; @@ -60,14 +64,15 @@ export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = ( set: any ) => { return { - rswtChkSttnInit: async (searchTxt: string, sggCd: string) => { + rswtChkSttnInit: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => { try { - const rswtChkRes = await initFetch(searchTxt, sggCd); + const rswtChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); return set((state: rswtChkSttnState) => ({ ...state, rswtChkSttn: { ...state.rswtChkSttn, - rswtChkRes: rswtChkRes, + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, isInit: false, }, })); @@ -104,15 +109,16 @@ export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = ( console.log(error); } }, - rswtChkSttnSearch: async (searchTxt: string, sggCd: string) => { + rswtChkSttnSearch: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => { try { - const rswtChkRes = await initFetch(searchTxt, sggCd); + const rswtChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); return set((state: rswtChkSttnState) => ({ ...state, rswtChkSttn: { ...state.rswtChkSttn, - rswtChkRes: rswtChkRes + rswtChkRes: rswtChkRes.data, + rswtChkCount: rswtChkRes.count, }, })); } catch (error) { diff --git a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx index d62406e9f..515c74490 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx @@ -1,16 +1,14 @@ import { useWrStore } from "@/app/store"; -import { ScrollArea, Title } from "@common/business_components/ui"; -import { Button } from "@common/components/ui"; -import { useEffect, useState } from "react"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; -import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable"; +import type { TableUpperProps } from "@/app/store/common/type/header"; import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtrPolutionsZode } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList"; +import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable"; +import { ScrollArea, Title } from "@common/business_components/ui"; +import { Button } from "@common/components/ui"; +import React, { useEffect, useState } from "react"; import type { z } from "zod"; -import React from "react"; -import type { TableUpperProps } from "@/app/store/common/type/header"; -export default function ChkgdModal({ type, obj ,setIsModal }: { type: string; obj: any , setIsModal:(open:boolean)=>void}) { +export default function ChkgdModal({ type, obj, setIsModal }: { type: string; obj: any, setIsModal: (open: boolean) => void }) { const { rainChkgdn, rswtChkgdn, @@ -253,7 +251,8 @@ export default function ChkgdModal({ type, obj ,setIsModal }: { type: string; ob </div> <div className="flex justify-between"> <h3 className="text-2xl font-bold text-gray-900 mt-2 ml-6"> - {`(${obj.bdstNm})`} + {type === "RNB" + ? `(${obj.bdstNm})` : `(${obj.building.bdstNm})`} </h3> {!rainChkSttn.isSttn ? ( <Button className="" onClick={allDataUpdate}> @@ -273,7 +272,7 @@ export default function ChkgdModal({ type, obj ,setIsModal }: { type: string; ob <GuideDetailsTable chgRes={guidData || []} headList={headList.splHeadList} - upheadList={type === "RNB"? rainChkgdn.rainSplHeadNm :rswtChkgdn.rswtSplHeadNm} + upheadList={type === "RNB" ? rainChkgdn.rainSplHeadNm : rswtChkgdn.rswtSplHeadNm} type={""} setChGuidData={(data) => { setChGuidData(data); @@ -287,7 +286,7 @@ export default function ChkgdModal({ type, obj ,setIsModal }: { type: string; ob <GuideDetailsTable chgRes={guidData || []} headList={headList.ruseHeadList} - upheadList={type === "RNB"? rainChkgdn.rainRuseHeadNm :rswtChkgdn.rswtRuseHeadNm} + upheadList={type === "RNB" ? rainChkgdn.rainRuseHeadNm : rswtChkgdn.rswtRuseHeadNm} type={""} setChGuidData={(data) => { setChGuidData(data); diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index c6daac3b6..687b27611 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -25,6 +25,7 @@ export default function RainChkgdTable({ rainChkData, pageNation, onPageChange, + pageCount, }: { detailUp: (data: rainChkZodType[]) => void; handleClick?: (data: any) => void; @@ -32,6 +33,7 @@ export default function RainChkgdTable({ rainChkData?: rainChkZodType[]; pageNation: number; onPageChange: (page: number) => void; + pageCount: number; }) { const { code, rainChkgdn, rainChkSttn, getRainSttnExcel } = useWrStore((state) => state); const [makeTableData, setMakeTableData] = useState<any[]>([]); @@ -74,7 +76,7 @@ export default function RainChkgdTable({ useEffect(() => { setSelectedIds([])// 셀렉트 초기화를 위한 작업 - if (rainChkData&&rainChkData.length>0) { + if (rainChkData && rainChkData.length > 0) { const rainChg = rainChkData?.map((item: any) => { const bud = tableData([item.building], { code }); @@ -86,7 +88,7 @@ export default function RainChkgdTable({ }); setMakeTableData(rainChkTableData(rainChg)); - }else{ + } else { setMakeTableData([]); } }, [rainChkData, code]); @@ -170,14 +172,8 @@ export default function RainChkgdTable({ }) } - }, [rainChkSttn.isSttn, rainChkgdn.rainChkgdnHeadList, rainChkSttn.rainChkgdnHeadList]); - - useEffect(() =>{ - console.log('rainChkgdn.count ', rainChkgdn.rainChkCount) - },[rainChkgdn.rainChkCount]) - return ( <> <LoadingOverlay isLoading={rainChkgdn.isLoading}></LoadingOverlay> @@ -202,7 +198,7 @@ export default function RainChkgdTable({ </TableBody> </Table> <UiPageNations - total={rainChkgdn.rainChkCount||20} + total={pageCount} cur={pageNation} pageSize={rainPageSize} onPageChange={onPageChange} diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index 5264dcdee..e71238706 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -25,6 +25,7 @@ export default function RswtChkgdTable({ rswtChkData, pageNation, onPageChange, + pageCount, }: { detaiRswtlUpdate: (data: rswtrChkDetailsZodType[]) => void; handleRswtClick?: (data: any) => void; @@ -32,6 +33,7 @@ export default function RswtChkgdTable({ rswtChkData: rswtChkZodType[]; pageNation: number; onPageChange: (page: number) => void; + pageCount: number; }) { const { code, rswtChkgdn, rswtChkSttn, rswtChkgdnInit, rswtChkPolAndGuide, getRswtSttnExcel } = useWrStore( (state) => state @@ -152,7 +154,7 @@ export default function RswtChkgdTable({ </TableBody> </Table> <UiPageNations - total={rswtChkgdn.rswtChkCount} + total={pageCount} cur={pageNation} pageSize={rswtPageSize} onPageChange={onPageChange} diff --git a/apps/wr/public/images/map/layericon/Layer_Select_BTN.png b/apps/wr/public/images/map/layericon/Layer_Select_BTN.png new file mode 100644 index 000000000..1e810feaf Binary files /dev/null and b/apps/wr/public/images/map/layericon/Layer_Select_BTN.png differ diff --git a/apps/wr/public/sample_ruseCaseMng.xlsx b/apps/wr/public/sample_ruseCaseMng.xlsx index 3a88e0623..96027d557 100644 Binary files a/apps/wr/public/sample_ruseCaseMng.xlsx and b/apps/wr/public/sample_ruseCaseMng.xlsx differ diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js index 6d46e77aa..977f21b2b 100644 --- a/packages/common/business_components/src/ui/map/Gis.js +++ b/packages/common/business_components/src/ui/map/Gis.js @@ -1,5 +1,6 @@ import { Search } from 'lucide-react'; import OlMap from 'ol/Map'; +import Overlay from 'ol/Overlay'; import View from 'ol/View'; import { defaults as defaultControls, OverviewMap } from 'ol/control'; import { defaults } from 'ol/interaction'; @@ -7,6 +8,7 @@ import * as olProj from 'ol/proj'; import { register } from 'ol/proj/proj4'; import proj4 from 'proj4'; import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { createRoot } from 'react-dom/client'; import GisLonLat from './GisLonLat'; import GisMapToggle from './GisMapToggle'; import GisSelect from './GisSelect'; @@ -14,11 +16,27 @@ import GisToolBar from './GisToolBar'; import GisTree from './GisTree'; import './lib/css/gis.common.css'; import GisApp from './lib/gis.core'; +// import FacilityInfoPopup from './FacilityInfoPopup'; export const GisContext = createContext({ gisCore: null, gisMap: null, treeData: null, checkedLayerIds: null }); export const useGisContext = () => useContext(GisContext); -function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = false, isMiniMap = false, setIsOpen, setFeatureData, featureData, searchView: SearchView, detailView: DetailView, onFeatureSelect, setIsSearchModalOpen }) { +function Gis({ + isOpen, + gisMaps, + isSearchModalOpen, + treeData = [], + isSearch = false, + isMiniMap = false, + setIsOpen, + setFeatureData, + featureData, + searchView: SearchView, + detailView: DetailView, + onFeatureSelect, + setIsSearchModalOpen, + onCheckedLayersChange +}) { const mapRef = useRef(); const [mapObject, setMapObject] = useState({}); const [tabVisible, setTabVisible] = useState(true); @@ -28,13 +46,21 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []); const mapInstanceRef = useRef(null); const checkedLayerIds = useRef([]); + + // 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가 + // const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]); + // const facilityOverlaysRef = useRef([]); + // 체크된 레이어 상태 관리 + const [checkedLayers, setCheckedLayers] = useState([]); + const [checkedLayersData, setCheckedLayersData] = useState([]); + let gisMap = null; const closePopup = () => { setIsOpen(false); // 팝업 닫기 setFeatureData(null) }; - // SearchModal, GisContent 등에서 호출 + // Feature Click Event const handleFeatureSelect = useCallback((data) => { gisMap = mapInstanceRef.current; @@ -89,8 +115,10 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal setFeatureData(data); setIsOpen(true); setIsSearchModalOpen(false); + onFeatureSelect?.(data); // 선택된 피쳐 데이터 콜백 호출 }, [mapInstanceRef]); + // 지도 생성 및 초기화 useEffect(() => { if (!mapRef.current) return; if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단 @@ -104,7 +132,7 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal ]); register(proj4); - //맵 생성 + // OpenLayers 지도 객체 생성 const map = new OlMap({ layers: [gisCore.baseLayers['base'], gisCore.baseLayers['satellite']], renderer: 'webgl', @@ -132,7 +160,7 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal gisMaps.current = map - //미니맵 + // 미니맵 추가 if (isMiniMap) { const overviewMap = new OverviewMap({ layers: [GisApp.Module.core.baseMiniMapLayers['base']], @@ -147,6 +175,7 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal map.addControl(overviewMap); } + // 스케일 컨트롤 및 베이스 레이어 설정 gisCore.__proto__.map = map; gisCore.scaleControl(); gisCore.changeBaseLayer('base'); @@ -154,16 +183,20 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal mapInstanceRef.current = map; // 생성 완료 플래그 설정 }, []); + // treeData 변경 시 레이어 코드 생성 useEffect(() => { if (!treeData || treeData.length === 0) return; + // 기존 오버레이 및 레이어 모두 삭제 gisCore.deleteAllOverlay(); gisCore.deleteAllLayer(); + // 트리 데이터를 레이어 코드 객체로 변환 const layerCode = gisCore.convertLayerInfosToLayerCode(treeData, 'lyrSn'); - GisApp.layerCode = layerCode; + GisApp.layerCode = layerCode; // 전역 레이어 코드 설정 //setTreeData(data); + // 편집 가능한 레이어 목록 생성 const layerItems = getLayerItems(layerCode); //setEditLayerItems(prev => [...layerItems]) }, [treeData]); @@ -193,31 +226,161 @@ function Gis({ isOpen, gisMaps, isSearchModalOpen, treeData = [], isSearch = fal } } + // // 데이터 로드 및 팝업 생성 로직 + // useEffect(() => { + // if (!mapInstanceRef.current) return; // 맵이 생성되지 않았으면 실행 안 함 + + // // 1. 팝업 데이터 가져오기 (feature.js의 getData와 유사) + // const fetchPopupData = async () => { + // // 실제 API 호출 로직으로 대체해야 합니다. + // // 예시: const response = await yourApiService.getFcltyWtCnt(); + // // setFacilityInfoPopupData(response.data); + + // // 임시 목업 데이터 + // const mockData = [ + // { ftrIdn: 1, ftrCde: 'SA206', bplcNm: '처리장A', fcltyUseYn: 'Y', x: 127.005, y: 37.282, aCnt: 10, cCnt: 5, eCnt: 3, mCnt: 8, iCnt: 2 }, + // { ftrIdn: 2, ftrCde: 'SA112', bplcNm: '처리장B', fcltyUseYn: 'N', x: 127.010, y: 37.285, aCnt: 8, cCnt: 4, eCnt: 2, mCnt: 6, iCnt: 1 } + // ]; + // setFacilityInfoPopupData(mockData); + // }; + + // fetchPopupData(); + + // }, [mapInstanceRef.current]); // 맵 인스턴스가 생성된 후 한 번만 실행 + + // // 데이터가 변경되면 오버레이를 생성/업데이트하는 로직 + // useEffect(() => { + // const map = mapInstanceRef.current; + // if (!map || facilityInfoPopupData.length === 0) return; + + // // 기존 오버레이 정리 + // facilityOverlaysRef.current.forEach(overlay => map.removeOverlay(overlay)); + // facilityOverlaysRef.current = []; + + // facilityInfoPopupData.forEach(data => { + // const popupId = `${data.ftrIdn}_${data.ftrCde}`; + + // // 팝업을 담을 div 엘리먼트 생성 + // const popupElement = document.createElement('div'); + // popupElement.id = popupId; + + // // OpenLayers Overlay 생성 + // const position = olProj.transform([Number(data.x), Number(data.y)], GisApp.FROM_PROJ, GisApp.TO_PROJ); + // const overlay = new Overlay({ + // element: popupElement, + // position: position, + // offset: [-75, -210], // 팝업 너비의 절반, 높이만큼 오프셋 조정 + // positioning: 'bottom-center', + // className: 'facility-popup-overlay' // 필요시 공통 클래스 추가 + // }); + + // map.addOverlay(overlay); + // facilityOverlaysRef.current.push(overlay); + + // // React 컴포넌트를 popupElement에 렌더링 + // const root = createRoot(popupElement); + // root.render(<FacilityInfoPopup data={data} />); + // }); + + // // 초기 가시성 업데이트 + // updatePopupVisibility(); + + // }, [facilityInfoPopupData]); // 팝업 데이터가 변경될 때마다 실행 + + // // 레이어 가시성에 따라 팝업 가시성을 제어하는 함수 + // const updatePopupVisibility = useCallback(() => { + // const map = mapInstanceRef.current; + // if (!map) return; + + // const visibleLayers = new Set(); + // map.getLayers().forEach(layer => { + // if (layer.getVisible()) { + // // feature.js의 로직처럼 typeName이나 ftrCde를 사용해 필터링 + // const typeName = layer.get('typeName'); + // if (typeName === 'VW_WTL_FCLTY_AS') { // 예시 레이어 이름 + // visibleLayers.add(layer.get('ftrCde')); + // } + // } + // }); + + // facilityOverlaysRef.current.forEach(overlay => { + // const element = overlay.getElement(); + // const ftrCde = element.querySelector('table')?.classList[0]; // FacilityPopup의 클래스에서 ftrCde 가져오기 + + // if (visibleLayers.has(ftrCde)) { + // element.style.display = ''; + // } else { + // element.style.display = 'none'; + // } + // }); + // }, []); + + // GisTree에서 체크 상태가 변경될 때 이 함수를 호출하도록 연결해야 합니다. + // 예시: GisTree 컴포넌트에 onCheck 콜백을 추가하고, 그 콜백에서 이 함수를 호출 + // useEffect(() => { + // // 레이어 가시성이 변경될 때마다 팝업 가시성 업데이트 + // const map = mapInstanceRef.current; + // if (!map) return; + + // const handleLayerVisibilityChange = () => { + // updatePopupVisibility(); + // }; + + // map.getLayers().on('change:length', handleLayerVisibilityChange); + // map.getLayers().forEach(layer => { + // layer.on('change:visible', handleLayerVisibilityChange); + // }); + + // return () => { + // // 클린업 + // map.getLayers().un('change:length', handleLayerVisibilityChange); + // map.getLayers().forEach(layer => { + // layer.un('change:visible', handleLayerVisibilityChange); + // }); + // }; + // }, [updatePopupVisibility]); + + // 체크된 레이어 정보를 처리하는 함수 + const handleCheckedLayersChange = useCallback((checkedIds, checkedNodesData) => { + setTimeout(() => { + setCheckedLayers(checkedIds); + setCheckedLayersData(checkedNodesData); + onCheckedLayersChange?.(checkedIds, checkedNodesData); + }, 0); + }, [onCheckedLayersChange]); + return ( <> <GisContext.Provider value={{ gisCore, gisMap: mapInstanceRef.current, treeData, checkedLayerIds }}> <div className="h-[calc(100vh-10rem)] flex relative"> <div ref={mapRef} className="gis-map flex-1 relative" style={{ height: '100%', padding: 0 }} /> - <GisTree visible={tabVisible} setVisible={setTabVisible} /> + <GisTree + visible={tabVisible} + setVisible={setTabVisible} + onCheckedChange={handleCheckedLayersChange} + /> {/* <GisContent onFeatureSelect={handleFeatureSelect} isSearch={isSearch} isSearchModalOpen={isSearchModalOpen} setIsSearchModalOpen={setIsSearchModalOpen} /> */} - {/* isSearchModalOpen이 true면 visible=false로 팝업 숨김 */} + {/* DetailView가 존재할 때만 렌더링 isSearchModalOpen이 true면 visible=false로 팝업 숨김 */} {isOpen && featureData && !isSearchModalOpen && ( <DetailView featureData={featureData} onClose={closePopup} // 닫기 콜백 전달 /> )} - <SearchView - open={isSearchModalOpen} - onOpenChange={setIsSearchModalOpen} - onFeatureSelect={onFeatureSelect} - /> + {/* SearchView가 존재할 때만 렌더링 */} + {SearchView && ( + <SearchView + open={isSearchModalOpen} + onOpenChange={setIsSearchModalOpen} + onFeatureSelect={handleFeatureSelect} + /> + )} <GisLonLat /> <GisToolBar /> <GisMapToggle /> - <GisSelect onFeatureSelect={onFeatureSelect} /> + <GisSelect onFeatureSelect={handleFeatureSelect} /> </div> {isSearch && (