From 2c6327bc3a51eec44e3e689c522ed4939b9d90bd Mon Sep 17 00:00:00 2001 From: leedj312 Date: Mon, 4 Aug 2025 13:07:52 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=ED=95=98=EC=88=98=EC=9E=AC=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=8B=9C=EC=84=A4=20=EC=B0=A8=EC=88=98=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EB=B2=84=ED=8A=BC=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B9=97=EB=AC=BC=20=EC=A7=80=EB=8F=84=EC=A0=90=EA=B2=80=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=9C=A0=ED=98=95=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20(ph)=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chkgdnReg/rainChkgdn/headList.tsx | 2 +- apps/wr/components/lib/func/TableData.tsx | 194 +++++++++++++----- apps/wr/components/lib/func/commom.tsx | 10 + .../fcltReg/pbnstReg/buseReg/bugRegForm.tsx | 71 ++++--- .../buseWaterQulity/buseWaterQulity.tsx | 1 - .../chkgdTable/rainChkgd/rainChkgdTable.tsx | 15 +- apps/wr/public/locales/ko/message.json | 3 +- 7 files changed, 204 insertions(+), 92 deletions(-) diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx index d216b88f6..44d039d7f 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx @@ -63,7 +63,7 @@ export const rainChkZod = z.object({ z.object({ chkgdnSn: z.number().nullable(), utztnUsgCd: z.string(), - ph: z.number().nullable(), + ph:z.string().nullish(), trbt: z.number().nullable(), grssClfg: z.number().nullable(), etc: z.string().nullable(), diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index 192bc43c3..629281f02 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -2,8 +2,17 @@ import { numSize } from "@/app/store/common/code/basicCode"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; -import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui"; -import { formatCommaNumber, handleCommaNumberChange } from "./commom"; +import { + Checkbox, + Input, + TableCell, + TableRow, +} from "@common/components/ui"; +import { + formatCommaNumber, + handleCommaNumberChange, +} from "./commom"; +import moment from "moment"; export const rainChkTableData = (chkData: rainChkZodType[]) => { // 1. chkgdnSn + utztnUsgCd 기준 누계 정보 만들기 @@ -57,9 +66,7 @@ export const rswtChkTableData = (chkData: rswtChkZodType[]) => { // 1. chkgdnSn + utztnUsgCd 기준 누계 정보 만들기 const makeRswtData: any[] = []; - if (chkData && chkData.length > 0) { - chkData?.forEach((root) => { root.rswtrDetails.forEach((detail) => { let flatRswtChk = {}; @@ -96,20 +103,19 @@ export const chRowspanTable = ( toggleSelection: (pk: number, checked: boolean) => void, selectedIds: number[], handleCellClick: (index: number, headId: string) => void, - disable? : boolean + disable?: boolean ) => { - let order = 0 + let order = 0; // rowspan된 셀 렌더링 여부 추적용 const renderedMap = new Map>(); return ( <> {/* {makeTableData.map((row, rowIndex) => ( */} - {makeTableData && makeTableData.length > 0 ? (makeTableData.map((row, rowIndex) => ( - - {headList - .map((head) => { - + {makeTableData && makeTableData.length > 0 ? ( + makeTableData.map((row, rowIndex) => ( + + {headList.map((head) => { const key = head.id; const isMerged = head.mergeCell; const value = row[key]; @@ -118,7 +124,6 @@ export const chRowspanTable = ( if (isMerged) { const renderedSet = renderedMap.get(key) ?? new Set(); if (renderedSet.has(rowIndex)) { - return null; // 이미 렌더링된 셀은 skip } @@ -143,13 +148,13 @@ export const chRowspanTable = ( > ) : key === "order" ? ( ++order + ) : // value + ["anlOperCst", "dtfcltCpct", "prcsCpct"].includes( + head.id + ) ? ( + formatCommaNumber(value) ) : ( - // value - (["anlOperCst", "dtfcltCpct", "prcsCpct"].includes(head.id)) ? ( - formatCommaNumber(value) - ) : ( - <>{value} - ) + <>{value} )} ); @@ -163,23 +168,48 @@ export const chRowspanTable = ( onClick={() => handleCellClick(rowIndex, head.id)} > {head.edit === true ? ( - (["levyAmt", "anlOperCst", "dtfcltCpct", "prcsCpct"].includes(head.id)) ? ( + [ + "levyAmt", + "anlOperCst", + "dtfcltCpct", + "prcsCpct", + ].includes(head.id) ? ( { - handleCommaNumberChange(e, val => - handleChange(rowIndex, head.id, val)) + handleCommaNumberChange(e, (val) => + handleChange(rowIndex, head.id, val) + ); }} value={formatCommaNumber(value) || ""} disabled={!selectedIds.includes(row.chkgdnSn)} maxLength={numSize} onInput={(e: React.ChangeEvent) => { - if (head.type === 'number' && e.target.value.length > numSize) { + if ( + head.type === "number" && + e.target.value.length > numSize + ) { e.target.value = e.target.value.slice(0, numSize); } }} /> + ) : ["vltnDt"].includes(head.id) ? ( + { + // 브라우저에서 선택한 값은 "YYYY-MM-DD" + const rawDate = e.target.value; // e.g. "2025-06-01" + const yyyymmdd = moment(rawDate).format("YYYYMMDD"); + handleChange(rowIndex, head.id, yyyymmdd); + }} + value={ + value + ? moment(value, "YYYYMMDD").format("YYYY-MM-DD") + : "" + } + disabled={!selectedIds.includes(row.chkgdnSn)} + /> ) : ( ) => { - if (head.type === 'number' && e.target.value.length > numSize) { + if ( + head.type === "number" && + e.target.value.length > numSize + ) { e.target.value = e.target.value.slice(0, numSize); } }} /> ) + ) : [ + "totalSplyUswtrUtztnQnt", + "totalRuseFcltUtztnQnt", + "splyUswtrUtztnQnt", + "ruseFcltUtztnQnt", + "levyAmt", + ].includes(head.id) ? ( + + {formatCommaNumber(value)} + ) : ( - (["totalSplyUswtrUtztnQnt", "totalRuseFcltUtztnQnt", "splyUswtrUtztnQnt", "ruseFcltUtztnQnt", "levyAmt"].includes(head.id)) ? ( - - {formatCommaNumber(value)} - - ) : ( - <>{value} - ) + <>{value} )} ); })} - - ))) : ( + + )) + ) : ( - + 조회된 결과가 없습니다. @@ -221,16 +273,17 @@ export const chRowspanTable = ( ); }; -export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean) => { +export const headVisibleChange = ( + headList: TableUpperProps[], + isEdit: boolean +) => { return headList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; - if (head.id === 'checkBox') { - head.visible = false + if (head.edit !== undefined) head.edit = isEdit; + if (head.id === "checkBox") { + head.visible = false; } - }); -} +}; const handleChange = ( rowIndex: number, @@ -253,8 +306,6 @@ const handleChange = ( }) ); }; -; - export const InputTableBody = ( chgRes: any[] | [], headList: TableUpperProps[], @@ -289,8 +340,10 @@ export const InputTableBody = ( return ( {headList.map((head, headIndex) => { - const isTextColumn = head.id === '구분' || head.id === '용수명'; - const textAlignClass = isTextColumn ? 'text-center' : 'text-right'; + const isTextColumn = head.id === "구분" || head.id === "용수명"; + const textAlignClass = isTextColumn + ? "text-center" + : "text-right"; // 총합계 행이면 "구분"에서 colSpan=2로 병합 if ( @@ -318,8 +371,13 @@ export const InputTableBody = ( // 총합계 행의 나머지 셀에도 색상 적용 if (data["구분"] === 0 || data["용수명"] === 0) { return ( - - {Number(data[head.id]) ? formatCommaNumber(data[head.id as keyof any]) : data[head.id as keyof any] ?? ""} + + {Number(data[head.id]) + ? formatCommaNumber(data[head.id as keyof any]) + : (data[head.id as keyof any] ?? "")} ); } @@ -328,21 +386,35 @@ export const InputTableBody = ( const rowSpan = getRowSpan(chgRes, head.id, dataIndex); if (rowSpan === 0) return null; return ( - - {Number(data[head.id]) ? formatCommaNumber(data[head.id as keyof any]) : data[head.id as keyof any] ?? ""} + + {Number(data[head.id]) + ? formatCommaNumber(data[head.id as keyof any]) + : (data[head.id as keyof any] ?? "")} ); } // 기본 셀 // return head.edit === true && data.edit !== false ? ( return isEditable && head.edit === true && data.edit !== false ? ( - + - handleCommaNumberChange(e, val => - handleChange(dataIndex, head.id, String(val), setInputData) + handleCommaNumberChange(e, (val) => + handleChange( + dataIndex, + head.id, + String(val), + setInputData + ) ) } value={formatCommaNumber(data[head.id as keyof any]) ?? ""} @@ -350,15 +422,20 @@ export const InputTableBody = ( /> ) : ( - +
- {Number(data[head.id]) ? formatCommaNumber(data[head.id as keyof any]) : data[head.id as keyof any] ?? ""} + {Number(data[head.id]) + ? formatCommaNumber(data[head.id as keyof any]) + : (data[head.id as keyof any] ?? "")}
); @@ -368,11 +445,14 @@ export const InputTableBody = ( })} {chgRes.length === 0 && ( - + 조회된 결과가 없습니다. )} ); -}; \ No newline at end of file +}; diff --git a/apps/wr/components/lib/func/commom.tsx b/apps/wr/components/lib/func/commom.tsx index fef689f46..7ba13e72a 100644 --- a/apps/wr/components/lib/func/commom.tsx +++ b/apps/wr/components/lib/func/commom.tsx @@ -150,6 +150,15 @@ export const formatCommaNumber = ( return num.toLocaleString(); }; +//내가 쓰는 값이 숫자이냐 아니냐 +export const isNumeric =(value: string) => { + if(value&&value.length>0){ + return value?.trim() !== "" && !isNaN(Number(value)); + }else{ + return false + } +} + export const getCityOrSgg = (ref: RefObject) => { let con; if (ref.current != null) @@ -163,6 +172,7 @@ export const getCityOrSgg = (ref: RefObject) => { export const safeDate = (value: any): Date | undefined => { const date = new Date(value); + console.log(' date ', date) return isNaN(date.getTime()) ? undefined : date; }; diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx index 0fb24366a..e3eaf4365 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx @@ -24,10 +24,11 @@ import { SelectBox } from "@common/business_components"; import { DatePicker, FormUi, UiModal } from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; import { Button, Input, Label } from "@common/components"; -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useFieldArray, type UseFormReturn } from "react-hook-form"; import MngRegFormDetail from "../mngReg/mngRegFormDetail/mngRegFormDetail"; import { + //confirmToast, formatCommaNumber, handleCommaNumberChange, safeDate, @@ -38,6 +39,9 @@ import type { DemandCompType } from "@common/business_components/ui/sdmInsertFor import RuseMngTableForm from "@/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm"; import type { SelectDataType } from "@common/business_components"; import { BuseWaterQulity } from "./buseWaterQulity/buseWaterQulity"; +import toast from "react-hot-toast"; +import { useTranslation } from "react-i18next"; +//import { useTranslation } from "react-i18next"; export function PbnstBuseForm({ indexMng = 0, @@ -54,6 +58,8 @@ export function PbnstBuseForm({ setIndexBiz: (index: number) => void; readonly?: boolean; }) { + const { t } = useTranslation("base"); + const { code, pbnst, @@ -157,22 +163,25 @@ export function PbnstBuseForm({ } }, [fcBizs, indexBiz, setIndexBiz]); // 2. Define a submit handler. - function addRuseFcltObj() { + const addRuseFcltObj = useCallback(async () => { + const formRuse = form.getValues(`items.${indexMng}`); const formBizs = form.getValues(`items.${indexMng}.fcBizs`); const pbnstBizCycle = formBizs.length; - // 🧩 새로운 fcBizs 기본 객체 생성 (필수값만 채우고 나머지는 default로) - const newItem = fcBizSchema.parse({ - cycl: pbnstBizCycle + 1, - pbnstRuseFcltId: formRuse.pbnstRuseFcltId, - fcOrgwts: undefined, - pplInstls: undefined, - fcDemands: undefined, - }); - appendBiz(newItem); - setIndexBiz(pbnstBizCycle); // 새로 추가된 차수로 포커스 이동 - } + const newItem = fcBizSchema.parse({ + cycl: pbnstBizCycle + 1, + pbnstRuseFcltId: formRuse.pbnstRuseFcltId, + fcOrgwts: [], + + pplInstls: [], + fcDemands: [], + }); + await appendBiz(newItem); + toast.success(t('insertRuseBiz',{cycle: pbnstBizCycle + 1})) + setIndexBiz(pbnstBizCycle); + }, [form, indexMng, indexBiz, appendBiz, setIndexBiz]); + const { fields: fcDemands, append: appendDemand } = useFieldArray({ control: form.control, name: `items.${indexMng}.fcBizs.${indexBiz}.fcDemands`, @@ -206,7 +215,7 @@ export function PbnstBuseForm({ } }, [ppiYn, indexMng, indexBiz]); - const plusHist = () => { + const plusHist = useCallback(() => { if ( form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizSn`) ) { @@ -227,9 +236,9 @@ export function PbnstBuseForm({ cpct: 0, }); } - }; + }, [indexMng, indexBiz, appendPpl, form]); - const plusArray = () => { + const plusArray = useCallback(() => { appendDemand({ dmdCoNm: "", daddr: "", @@ -248,7 +257,7 @@ export function PbnstBuseForm({ dmdInfoId: "", //telno: "", }); - }; + }, [indexMng, indexBiz, appendDemand, form]); const removeSelected = () => { const nowPPl = form.getValues( @@ -293,7 +302,7 @@ export function PbnstBuseForm({ }, [form.formState, indexMng, indexBiz]); useEffect(() => { - console.log("form.formState ", form.formState); + //console.log("form.formState ", form.formState); }, [form.formState]); const pbnstBiz = form.watch(`items.${indexMng}.fcBizs`); @@ -489,17 +498,16 @@ export function PbnstBuseForm({
- - +
@@ -533,7 +541,10 @@ export function PbnstBuseForm({ 수요처 신규등록
-
+
{fcDemands.map((field, index) => (
{ setSelectedIds([])// 셀렉트 초기화를 위한 작업 if (rainChkData && rainChkData.length > 0) { - const rainChg = rainChkData?.map((item: any) => { const bud = tableData([item.building], { code }); + const rainyDetails= item.rainyDetails.map((detail)=>{ + return( + { + ...detail, + // 일단 테이블에서 사용하기 위해 넘버 전환 + ph: detail.ph&& !isNaN(detail.ph)?Number(detail.ph):detail.ph + } + ) + }) return { ...item, ...bud[0], + rainyDetails:rainyDetails, rowspan: item.rainyDetails?.length, }; }); + console.log('rainChg ', rainChg) setMakeTableData(rainChkTableData(rainChg)); } else { setMakeTableData([]); @@ -116,7 +126,8 @@ export default function RainChkgdTable({ if (findRain != undefined) { return { ...rd, - ph: Number(findRain.ph), + // 조드 타입과 맞추기위해 스트링 + ph: String(findRain.ph), trbt: Number(findRain.trbt), grssClfg: Number(findRain.grssClfg), etc: findRain.etc, diff --git a/apps/wr/public/locales/ko/message.json b/apps/wr/public/locales/ko/message.json index fb7af9ed2..fa122d798 100644 --- a/apps/wr/public/locales/ko/message.json +++ b/apps/wr/public/locales/ko/message.json @@ -22,5 +22,6 @@ "saveRowErrMsg": "수정을 원하는 행을 선택하고 저장버튼을 눌러주세요.", "costCalcErrMsg": "공사비 계산 진행 후 저장을 눌러주세요", "maxYearErrMsg": "최대 {{year}}년까지 선택가능합니다.", - "checkQtyMsg": "요구수량(m³/일)을 확인해주세요 계산할 수 없습니다." + "checkQtyMsg": "요구수량(m³/일)을 확인해주세요 계산할 수 없습니다.", + "insertRuseBiz": "{{cycle}}차 사업이 추가되었습니다." } \ No newline at end of file From 1e650a72ba7ff726360b7c356378912bd49611b2 Mon Sep 17 00:00:00 2001 From: jyha00 Date: Mon, 4 Aug 2025 19:53:36 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=EC=A7=80=EB=8F=84=EC=A0=90=EA=B2=80=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20=EC=97=91=EC=85=80=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95,=20=EC=A0=90=EA=B2=80=EC=9D=BC=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=20=ED=8F=AC=EB=A7=A4=ED=84=B0=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruseFcltMng/prfmncReg/chkgdnReg/page.tsx | 24 +++++++++++++-- .../prfmncSttn/chkgdnSttn/page.tsx | 24 +++++++++++++-- .../prfmncReg/chkgdnReg/rainChkgdn/excel.tsx | 16 ++++------ apps/wr/components/lib/func/TableData.tsx | 30 +++++++++++-------- apps/wr/components/lib/func/commom.tsx | 11 +++++++ 5 files changed, 77 insertions(+), 28 deletions(-) diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index bf18d4d98..97d80a7a8 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -118,13 +118,33 @@ export default function Page() { const rainPageChange = (pageNo: number) => { if (pageNo > 0) { setRainPageNation(pageNo); - rainChkInit(pageNo, rainPageSize, searchYear, commonCd); + if (fcltNm) { + rainChkNmSearch( + pageNo, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rainChkInit(pageNo, rainPageSize, searchYear, commonCd); + } } }; const rswtPageChange = (pageNo: number) => { if (pageNo > 0) { setRswtPageNation(pageNo); - rswtChkgdnInit(pageNo, rswtPageSize, searchYear, commonCd); + if (fcltNm) { + rswtChkNmSearch( + pageNo, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rswtChkgdnInit(pageNo, rswtPageSize, searchYear, commonCd); + } } }; diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index ba1821f20..6b4eead42 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -83,14 +83,34 @@ export default function Page() { const rainPageChange = (pageNo: number) => { if (pageNo > 0) { setRainPageNation(pageNo); - rainChkSttnInit(pageNo, rainPageSize, searchYear, commonCd); + if (fcltNm) { + rainChkSttnNmSearch( + pageNo, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rainChkSttnInit(pageNo, rainPageSize, searchYear, commonCd); + } } }; const rswtPageChange = (pageNo: number) => { if (pageNo > 0) { setRswtPageNation(pageNo); - rswtChkSttnInit(pageNo, rswtPageSize, searchYear, commonCd); + if (fcltNm) { + rswtChkNmSttnSearch( + pageNo, + rainPageSize, + searchYear, + commonCd, + fcltNm + ); + } else { + rswtChkSttnInit(pageNo, rswtPageSize, searchYear, commonCd); + } } }; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index a484f87c2..8e18317a8 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -132,20 +132,20 @@ export const excelToRainChkData = (excelData: any, year: string) => { bdstNm: item["시설명"] ?? "", bdstRuseFcltSn: Number(item["NO"]), chckYmd: checkYmd, - spwtPositn: item["유량측정방법"] ?? "", rgtr: TEST_UUID, - oilqMeasMthd: item["운영관리형태"] ?? "", + operMngCd: item["운영관리형태"] ?? "", anlOperCst: parseRawValue(item["연간운영비(원/년)"]), - operMngCd: item["유량측정방법"] ?? "", + oilqMeasMthd: item["유량측정방법"] ?? "", guideDetails: makeGuidDetail, rainyDetails: [ { + ph: item["PH"], utztnUsgCd: item["이용용도"], trbt: parseRawValue(item["탁도"]), grssClfg: parseRawValue(item["총대장균군수"]), etc: item["기타"] || "", // 필드 누락 방지 - vltnDt: vltnDt || "-", - vltnMttr: item["위반사항"] || "-", + vltnDt: vltnDt || "", + vltnMttr: item["위반사항"] || "", levyAmt: parseRawValue(item["과태료부과금액(천원)"]), rgtr: TEST_UUID, }, @@ -177,12 +177,6 @@ console.log("rainChkgdData", rainChkgdData); defaultMessage + `유량측정방법: 위탁 혹은 자체 만 허용) /입력값:${rain.oilqMeasMthd}` ); } - if (rain.spwtPositn.length > 1 && !chkSpwtPositnType.includes(rain.spwtPositn)) { - issues.push( - defaultMessage + `측정위치: 유량계, 수위계, 펌프적산전력계, 기타 중 하나만 허용) /입력값:${rain.spwtPositn}` - ); - } - rain.rainyDetails?.forEach((key) => { if (key.ph?.length > 1 && isInvalidNumber(key.ph)) { diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index 629281f02..f114df1e4 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -8,11 +8,12 @@ import { TableCell, TableRow, } from "@common/components/ui"; +import moment from "moment"; import { formatCommaNumber, - handleCommaNumberChange, + formatYyyymmdd, + handleCommaNumberChange } from "./commom"; -import moment from "moment"; export const rainChkTableData = (chkData: rainChkZodType[]) => { // 1. chkgdnSn + utztnUsgCd 기준 누계 정보 만들기 @@ -149,13 +150,16 @@ export const chRowspanTable = ( ) : key === "order" ? ( ++order ) : // value - ["anlOperCst", "dtfcltCpct", "prcsCpct"].includes( + ["anlOperCst", "dtfcltCpct", "prcsCpct"].includes( head.id ) ? ( - formatCommaNumber(value) - ) : ( - <>{value} - )} + formatCommaNumber(value) + ) : key === "chckYmd" ? ( + <>{formatYyyymmdd(value)} + ) : + ( + <>{value} + )} ); } @@ -231,12 +235,12 @@ export const chRowspanTable = ( /> ) ) : [ - "totalSplyUswtrUtztnQnt", - "totalRuseFcltUtztnQnt", - "splyUswtrUtztnQnt", - "ruseFcltUtztnQnt", - "levyAmt", - ].includes(head.id) ? ( + "totalSplyUswtrUtztnQnt", + "totalRuseFcltUtztnQnt", + "splyUswtrUtztnQnt", + "ruseFcltUtztnQnt", + "levyAmt", + ].includes(head.id) ? ( { { duration: Infinity } ); // 수동 닫기 }; + +// yyyy-mm-dd 형태로 포맷 +export const formatYyyymmdd = (val: string | undefined) => { + if (!val) return ""; + if (/^\d{8}$/.test(val)) { + return moment(val, "YYYYMMDD").format("YYYY-MM-DD"); + } + const m = moment(val); + return m.isValid() ? m.format("YYYY-MM-DD") : val; +}; \ No newline at end of file From ba56426947e22aceff2dae4305f60f75542cc181 Mon Sep 17 00:00:00 2001 From: jyha00 Date: Tue, 5 Aug 2025 18:43:25 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84=EC=A7=80?= =?UTF-8?q?=EB=8F=84=EC=A0=90=EA=B2=80=20=EB=83=84=EC=83=88,=20ph=20-?= =?UTF-8?q?=EB=A1=9C=20=ED=91=9C=EA=B8=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx | 24 ++++++------------- .../chkgdnReg/rswrtChkgdn/headList.tsx | 4 ++-- .../chkgdnSttn/rswtChkgdnSttn/headList.tsx | 4 ++-- apps/wr/components/lib/func/TableData.tsx | 13 ++++++++++ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx index aa550dcd1..d9016410d 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx @@ -1,17 +1,16 @@ -import type { SelectDataType } from "@common/business_components/ui"; -import { - chkMngType, - chkSpwtPositnType, - useTypes, - type Buildingtype, -} from "../rainChkgdn/excel"; import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import type { rswtChkZodType } from "."; import { isInvalidDate, isInvalidNumber, parseRawValue, } from "@/components/lib/func/excelFunc"; +import type { SelectDataType } from "@common/business_components/ui"; +import type { rswtChkZodType } from "."; +import { + chkSpwtPositnType, + useTypes, + type Buildingtype +} from "../rainChkgdn/excel"; export const rswtMakeExcelSample = ( buildings: Buildingtype[], @@ -284,15 +283,6 @@ const rswtExcelDataCheck = ( defaultMessage + ` 처리용량(m³): 숫자 형식 아님 (${rswt.prcsCpct})` ); } - if ( - rswt.oilqMeasMthd.length > 1 && - !chkMngType.includes(rswt.oilqMeasMthd) - ) { - issues.push( - defaultMessage + - `유량측정방법: 위탁 혹은 자체 만 허용) /입력값:${rswt.oilqMeasMthd}` - ); - } if ( rswt.spwtPositn.length > 1 && !chkSpwtPositnType.includes(rswt.spwtPositn) diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx index 04914b236..8ec8c3f41 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx @@ -163,11 +163,11 @@ export const rswtChkHeadListExport: TableUpperProps[] = [ }, { id: "trbt", title: "탁도(NTU)", upName: "useQuilty", upSequnce: 3 ,type: "number"}, { id: "bod", title: "BOD(mg/L)", upName: "useQuilty", upSequnce: 4 ,type: "number"}, - { id: "smll", title: "냄새", upName: "useQuilty", upSequnce: 5 ,type: "number"}, + { id: "smll", title: "냄새", upName: "useQuilty", upSequnce: 5 ,type: "text"}, { id: "crmty", title: "색도(도)", upName: "useQuilty", upSequnce: 6 ,type: "number"}, { id: "tn", title: "총질소(T-N)(mg/L)", upName: "useQuilty", upSequnce: 7 ,type: "number"}, { id: "tph", title: "총인(T-P)(mg/L)", upName: "useQuilty", upSequnce: 8 ,type: "number"}, - { id: "ph", title: "수소이온농도(PH)", upName: "useQuilty", upSequnce: 9,type: "number" }, + { id: "ph", title: "수소이온농도(PH)", upName: "useQuilty", upSequnce: 9,type: "text" }, { id: "clIonQnt", title: "염화물(mg/L)", upName: "useQuilty", upSequnce: 10 ,type: "number"}, { diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx index e000c550a..0fc025272 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx @@ -47,7 +47,7 @@ export const rswtChkSttnHeadListExport: TableUpperProps[] = [ title: "냄새", upName: "useQuilty", upSequnce: 5, - type: "number", + type: "text", }, { id: "crmty", @@ -64,7 +64,7 @@ export const rswtChkSttnHeadListExport: TableUpperProps[] = [ upSequnce: 8, type: "number", }, - { id: "ph", title: "수소이온농도(PH)", upName: "useQuilty", upSequnce: 9, type: "number" }, + { id: "ph", title: "수소이온농도(PH)", upName: "useQuilty", upSequnce: 9, type: "text" }, { id: "clIonQnt", title: "염화물(mg/L)", diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index f114df1e4..bee5e093d 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -234,6 +234,8 @@ export const chRowspanTable = ( }} /> ) + ) : ["smll", "ph"].includes(head.id) && head.type === "text" ? ( + <>- ) : [ "totalSplyUswtrUtztnQnt", "totalRuseFcltUtztnQnt", @@ -344,6 +346,17 @@ export const InputTableBody = ( return ( {headList.map((head, headIndex) => { + //냄새, ph면 계산 못하게 - 로 수정 + if (["smll", "ph"].includes(head.id)) { + return ( + + - + + ); + } const isTextColumn = head.id === "구분" || head.id === "용수명"; const textAlignClass = isTextColumn ? "text-center" From 24a55142fb2edbfa6ee9ae5bc22722dee760ff5f Mon Sep 17 00:00:00 2001 From: leedj312 Date: Tue, 5 Aug 2025 20:28:32 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=EB=AC=BC=EC=9E=AC=EC=9D=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=A7=80=EB=8F=84=20=EC=A0=84=EB=B0=98=EC=A0=81=EC=9D=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=ED=8A=B8=EB=A6=AC=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EA=B9=8C=EC=A7=80=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C(=EA=B2=80=EC=83=89=EB=B0=94=20=ED=95=B4=EC=95=BC?= =?UTF-8?q?=ED=95=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layerPopup/hasuFacility.tsx | 150 +++++++++++ .../layerPopup/htdflFacility.tsx | 0 .../layerPopup/rainFacility.tsx | 0 .../layerPopup/reuseFacility.tsx | 0 .../layerPopup/reuseMngFacility.tsx | 0 .../layerPopup/rswtFacility.tsx | 0 apps/wr/app/(popUp-layout)/layout.tsx | 13 + .../(popUp-layout)/mapDetilePopUp/page.tsx | 84 ++++++ .../(popUp-layout)/mapDetilePopUp/qweqwe.tsx | 187 +++++++++++++ .../wr/app/(popUp-layout)/newWindowPortal.tsx | 148 +++++++++++ apps/wr/app/{map => (popUp-layout)}/util.ts | 0 apps/wr/app/(with-layout)/layout.tsx | 18 ++ .../components/layerPopup/hasuFacility.tsx | 0 .../components/layerPopup/htdflFacility.tsx | 83 ++++++ .../components/layerPopup/rainFacility.tsx | 105 ++++++++ .../components/layerPopup/reuseFacility.tsx | 146 ++++++++++ .../layerPopup/reuseMngFacility.tsx | 103 +++++++ .../components/layerPopup/rswtFacility.tsx | 107 ++++++++ .../map/components/newWindowPopup.tsx | 8 +- .../map/components/newWindowPortal.tsx | 4 +- .../{ => (with-layout)}/map/mainMap/page.tsx | 74 +++++- .../{ => (with-layout)}/map/popup/page.tsx | 0 .../{ => (with-layout)}/map/service/index.ts | 0 .../{ => (with-layout)}/map/service/map.ts | 0 .../matMng/coMat/coMatRvw/page.tsx | 0 .../matMng/coMat/ruseCaseMng/page.tsx | 0 .../matMng/coMat/ruseRvwHstry/page.tsx | 0 .../matMng/coMng/coSttn/page.tsx | 0 .../matMng/coMng/drgtSttn/page.tsx | 0 .../matMng/coMng/ldrmntCoSttn/page.tsx | 0 .../ruseFcltMng/fcltReg/htdflReg/page.tsx | 0 .../ruseFcltMng/fcltReg/pbnstReg/page.tsx | 2 +- .../ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx | 0 .../ruseFcltMng/fcltReg/rainReg/TableHead.tsx | 0 .../ruseFcltMng/fcltReg/rainReg/page.tsx | 0 .../ruseFcltMng/fcltReg/rswtReg/page.tsx | 0 .../ruseFcltMng/fcltSttn/htdflSttn/page.tsx | 0 .../ruseFcltMng/fcltSttn/pbnstSttn/page.tsx | 0 .../ruseFcltMng/fcltSttn/rainSttn/page.tsx | 0 .../ruseFcltMng/fcltSttn/rswtSttn/page.tsx | 0 .../prfmncReg/chkgdnReg/TableHead.tsx | 0 .../ruseFcltMng/prfmncReg/chkgdnReg/page.tsx | 0 .../prfmncReg/pbnstPrfmncReg/page.tsx | 0 .../prfmncSttn/chkgdnSttn/page.tsx | 0 .../prfmncSttn/pbnstPrfmncSttn/page.tsx | 0 .../stats/rainStat/page.tsx | 0 .../stats/rswtStat/page.tsx | 0 apps/wr/app/layout.tsx | 11 +- apps/wr/app/store/map/coSttnMap/index.tsx | 120 +++++++++ apps/wr/app/store/map/common/index.tsx | 58 ++++ apps/wr/app/store/map/htdflMap/index.tsx | 63 +++++ apps/wr/app/store/map/ldrmntCoMap/index.tsx | 102 +++++++ apps/wr/app/store/map/pbnstMap/index.tsx | 108 ++++++++ apps/wr/app/store/map/rainMap/index.tsx | 67 +++++ apps/wr/app/store/map/rswtMap/index.tsx | 64 +++++ apps/wr/app/store/map/ruseMap/index.tsx | 94 +++++++ .../ruseFcltMng/fcltReg/pbnstReg/index.tsx | 2 +- .../ruseFcltMng/fcltSttn/pbnstSttn/index.tsx | 2 +- apps/wr/app/store/store.tsx | 251 ++++++++++++++---- .../ui/map/LayerPopUp/CoSttnMap/CoSttnMap.tsx | 195 ++++++++++++++ .../LayerPopUp/HasuFacilty/HasuFacility.tsx | 109 ++++++++ .../LayerPopUp/HedfFacilty/HtdfFacilty.tsx | 77 ++++++ .../LayerPopUp/LdrmntCoMap/LdrmntCoMap.tsx | 189 +++++++++++++ .../LayerPopUp/RainFacility/RainFacility.tsx | 102 +++++++ .../LayerPopUp/RswtFacilty/RswtFacilty.tsx | 99 +++++++ .../LayerPopUp/RuseFacilty/RuseFacility.tsx | 140 ++++++++++ .../sttn/pbnstSttnModal/pbnstSttnModal.tsx | 2 +- .../guideDetailTable/guideDetailTable.tsx | 2 +- .../chkgdTable/rainChkgd/rainChkgdTable.tsx | 2 +- .../chkgdTable/rswtChkgd/rswtChkgdTable.tsx | 2 +- .../pbnstReg/ruseMngTable/ruseMngTable.tsx | 2 +- .../ruseMngTableForm/ruseMngTableForm.tsx | 2 +- 72 files changed, 3009 insertions(+), 88 deletions(-) create mode 100644 apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx rename apps/wr/app/{map/components => (popUp-layout)}/layerPopup/htdflFacility.tsx (100%) rename apps/wr/app/{map/components => (popUp-layout)}/layerPopup/rainFacility.tsx (100%) rename apps/wr/app/{map/components => (popUp-layout)}/layerPopup/reuseFacility.tsx (100%) rename apps/wr/app/{map/components => (popUp-layout)}/layerPopup/reuseMngFacility.tsx (100%) rename apps/wr/app/{map/components => (popUp-layout)}/layerPopup/rswtFacility.tsx (100%) create mode 100644 apps/wr/app/(popUp-layout)/layout.tsx create mode 100644 apps/wr/app/(popUp-layout)/mapDetilePopUp/page.tsx create mode 100644 apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx create mode 100644 apps/wr/app/(popUp-layout)/newWindowPortal.tsx rename apps/wr/app/{map => (popUp-layout)}/util.ts (100%) create mode 100644 apps/wr/app/(with-layout)/layout.tsx rename apps/wr/app/{ => (with-layout)}/map/components/layerPopup/hasuFacility.tsx (100%) create mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx create mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx create mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx create mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx create mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx rename apps/wr/app/{ => (with-layout)}/map/components/newWindowPopup.tsx (97%) rename apps/wr/app/{ => (with-layout)}/map/components/newWindowPortal.tsx (95%) rename apps/wr/app/{ => (with-layout)}/map/mainMap/page.tsx (74%) rename apps/wr/app/{ => (with-layout)}/map/popup/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/map/service/index.ts (100%) rename apps/wr/app/{ => (with-layout)}/map/service/map.ts (100%) rename apps/wr/app/{ => (with-layout)}/matMng/coMat/coMatRvw/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/matMng/coMat/ruseCaseMng/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/matMng/coMat/ruseRvwHstry/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/matMng/coMng/coSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/matMng/coMng/drgtSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/matMng/coMng/ldrmntCoSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltReg/htdflReg/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltReg/pbnstReg/page.tsx (99%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltReg/rainReg/TableHead.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltReg/rainReg/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltReg/rswtReg/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltSttn/htdflSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltSttn/rainSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/fcltSttn/rswtSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/stats/rainStat/page.tsx (100%) rename apps/wr/app/{ => (with-layout)}/stats/rswtStat/page.tsx (100%) create mode 100644 apps/wr/app/store/map/coSttnMap/index.tsx create mode 100644 apps/wr/app/store/map/common/index.tsx create mode 100644 apps/wr/app/store/map/htdflMap/index.tsx create mode 100644 apps/wr/app/store/map/ldrmntCoMap/index.tsx create mode 100644 apps/wr/app/store/map/pbnstMap/index.tsx create mode 100644 apps/wr/app/store/map/rainMap/index.tsx create mode 100644 apps/wr/app/store/map/rswtMap/index.tsx create mode 100644 apps/wr/app/store/map/ruseMap/index.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/CoSttnMap/CoSttnMap.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/HasuFacilty/HasuFacility.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/LdrmntCoMap/LdrmntCoMap.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx create mode 100644 apps/wr/components/ui/map/LayerPopUp/RuseFacilty/RuseFacility.tsx diff --git a/apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx new file mode 100644 index 000000000..5868b2ccc --- /dev/null +++ b/apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx @@ -0,0 +1,150 @@ +import { useWrStore } from "@/app/store"; +import { btnClass } from "@/app/store/common/code"; +import { pbnMapTableSize } from "@/app/store/map/pbnstMap"; +import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import { tableData } from "@/components/lib/func/commom"; +import { + ContentsDiv, + SearchBaseForm, + SearchInput, + Title, + UiTable, + type ReturnType, +} from "@common/business_components/ui"; +import { Label } from "@common/components/ui"; +import { useEffect, useRef, useState } from "react"; +interface Props { + seletectedLayerNm: string; + viewMode: "list" | "detail" | "nothing"; + onFeatureSelect: (feature: any) => void; + onClose: () => void; + isRuseReg: { data: any | undefined }; +} +const HasuFacility = ({ + seletectedLayerNm, + viewMode, + onClose, + onFeatureSelect, + isRuseReg, +}: Props) => { + const { code, pbnMap, pbnMapInit } = useWrStore((state) => state); + const { pbnMapHeadList, pbnMapRes, pbnMapCount } = pbnMap; + const [hasuTable, setHasuTable] = useState(); + const [isReset, setIsReset] = useState(false); + const [pbnRuseNm, setPbnRuseNm] = useState(""); + + const ref = useRef({} as ReturnType); + useEffect(() => { + if (code.sggCd.length && pbnMapRes.length > 0) { + setHasuTable(tableData(pbnMapRes, { code })); + } + }, [code, pbnMapRes]); + + + useEffect(() => { + if (seletectedLayerNm !== "하수처리시설" || viewMode != "list") return; + if (!pbnMap.isInit) { + + console.log('ref.current ', ref.current) + pbnMapInit(1, pbnMapTableSize, ref.current); + } + }, [pbnMap.isInit, pbnMapInit]); + + const hasuCellClick = (index: number | undefined) => { + if (index !== undefined && pbnMapRes !== undefined) { + onFeatureSelect(pbnMapRes[index]); + onClose(); + } + }; + return viewMode == "list" ? ( + +
+
+ + <SearchBaseForm + selectSidoData={code.cityCd} + selectSigunData={code.sggCd} + selectRegionData={code.rvbsnCd} + selectUnitWaterShedData={code.lgbsnCd} + selectMiddleRegionData={code.mdmbsnCd} + selectEnvPartData={code.lclgvrnmntCd} + buttonOrder={["query", "init", "excel"]} + rightClassName="ml-auto mr-6 flex items-center space-x-1" + leftClassName="flex gap-5 w-9/12 m-4" + leftSelectClassName="w-1/4" + rightChildren={<></>} + leftChildren={ + <div className="col-span-3 flex items-center"> + <Label className="w-full mt-2 ml-4 text-xl text-gray-600"> + {"하수처리시설명"} + </Label> + <SearchInput + className={"text-2xl w-full"} + label="" + textValue={pbnRuseNm || ""} + setText={(e) => { + setPbnRuseNm(e || ""); + }} + /> + </div> + } + queryClick={() => { + setIsReset(true); + }} + initClick={function (): void { + setPbnRuseNm(""); + }} + btnClass={btnClass} + ref={ref} + isAdmin={false} + excelClick={function (returnType: ReturnType): void { + console.log("pbnstSttnSearch ", returnType); + }} + /> + </div> + <div className="col-span-6"> + {/* 높이 조정 */} + <UiTable + tableData={hasuTable || []} + headlist={pbnMapHeadList} + pageSize={pbnMapTableSize} + total={pbnMapCount || 0} + headName={""} + cellClick={hasuCellClick} + onPageChange={(page) => { + pbnMapInit(page, pbnMapTableSize, ref.current); + setIsReset(false); + }} + resetPageNo={isReset} + /> + </div> + </div> + </ContentsDiv> + ) : ( + <div style={{ overflowX: "hidden" }}> + <div className="flex justify-between items-center mb-4"> + <Title title="하수처리시설 상세정보" /> + </div> + {/* 높이 조정 */} + <UiTable + tableData={isRuseReg?.data || []} + headlist={pbnMapHeadList.slice(0, 4)} + pageSize={1} + total={0} + headName={"위치정보"} + cellClick={() => {}} + onPageChange={() => {}} + /> + <UiTable + tableData={isRuseReg?.data || []} + headlist={pbnMapHeadList.slice(4)} + pageSize={1} + total={0} + headName={"기본정보"} + cellClick={() => {}} + onPageChange={() => {}} + /> + </div> + ); +}; +export default HasuFacility; diff --git a/apps/wr/app/map/components/layerPopup/htdflFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/htdflFacility.tsx similarity index 100% rename from apps/wr/app/map/components/layerPopup/htdflFacility.tsx rename to apps/wr/app/(popUp-layout)/layerPopup/htdflFacility.tsx diff --git a/apps/wr/app/map/components/layerPopup/rainFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/rainFacility.tsx similarity index 100% rename from apps/wr/app/map/components/layerPopup/rainFacility.tsx rename to apps/wr/app/(popUp-layout)/layerPopup/rainFacility.tsx diff --git a/apps/wr/app/map/components/layerPopup/reuseFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/reuseFacility.tsx similarity index 100% rename from apps/wr/app/map/components/layerPopup/reuseFacility.tsx rename to apps/wr/app/(popUp-layout)/layerPopup/reuseFacility.tsx diff --git a/apps/wr/app/map/components/layerPopup/reuseMngFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/reuseMngFacility.tsx similarity index 100% rename from apps/wr/app/map/components/layerPopup/reuseMngFacility.tsx rename to apps/wr/app/(popUp-layout)/layerPopup/reuseMngFacility.tsx diff --git a/apps/wr/app/map/components/layerPopup/rswtFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/rswtFacility.tsx similarity index 100% rename from apps/wr/app/map/components/layerPopup/rswtFacility.tsx rename to apps/wr/app/(popUp-layout)/layerPopup/rswtFacility.tsx diff --git a/apps/wr/app/(popUp-layout)/layout.tsx b/apps/wr/app/(popUp-layout)/layout.tsx new file mode 100644 index 000000000..d3804ac93 --- /dev/null +++ b/apps/wr/app/(popUp-layout)/layout.tsx @@ -0,0 +1,13 @@ +"use client"; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + <> + <div>{children}</div> + </> + ); +} diff --git a/apps/wr/app/(popUp-layout)/mapDetilePopUp/page.tsx b/apps/wr/app/(popUp-layout)/mapDetilePopUp/page.tsx new file mode 100644 index 000000000..68be4a266 --- /dev/null +++ b/apps/wr/app/(popUp-layout)/mapDetilePopUp/page.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { CoSttnMap } from "@/components/ui/map/LayerPopUp/CoSttnMap/CoSttnMap"; +import { HasuFacility } from "@/components/ui/map/LayerPopUp/HasuFacilty/HasuFacility"; +import { HtdflFacility } from "@/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty"; +import { LdrmntCoMap } from "@/components/ui/map/LayerPopUp/LdrmntCoMap/LdrmntCoMap"; +import { RainFacility } from "@/components/ui/map/LayerPopUp/RainFacility/RainFacility"; +import { RswtFacility } from "@/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty"; +import { RuseFacility } from "@/components/ui/map/LayerPopUp/RuseFacilty/RuseFacility"; +import { useSearchParams } from "next/navigation"; + +export default function MapDetailPopUp() { + const searchParams = useSearchParams(); + const bc = new BroadcastChannel("mapDetailPopUp"); + + const renderConditionalContent = () => { + const layerId = searchParams.get("layerNm"); + switch (layerId) { + case "하수재이용시설": + return ( + <RuseFacility + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + case "하수처리시설": + return ( + <HasuFacility + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + case "빗물이용시설": + return ( + <RainFacility + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + case "중수도시설": + return ( + <RswtFacility + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + case "온배수시설": + return ( + <HtdflFacility + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + case "수요처": + return ( + <CoSttnMap + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + case "잠재수요처": + return ( + <LdrmntCoMap + rtnFeature={(feature) => { + bc.postMessage({ type: "SELECT_FEATURE", feature }); + }} + /> + ); + default: + return null; // 안전하게 아무 것도 렌더링하지 않음 + } + }; + return ( + <> + <div>{renderConditionalContent()}</div> + </> + ); +} diff --git a/apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx b/apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx new file mode 100644 index 000000000..365c5ef5c --- /dev/null +++ b/apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx @@ -0,0 +1,187 @@ +// "use client" +// import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +// import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +// import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +// import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; +// import { useGisContext } from "@common/business_components/ui/map/Gis"; +// import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form'; +// import React, { useCallback, useEffect, useRef, useState } from 'react'; +// import ResueFacility from '../layerPopup/reuseFacility'; +// import HasuFacility from '../layerPopup/hasuFacility'; +// import RainFacility from '../layerPopup/rainFacility'; +// import RswtFacility from '../layerPopup/rswtFacility'; +// import HtdflFacility from '../layerPopup/htdflFacility'; +// import ReuseMngFacility from '../layerPopup/reuseMngFacility'; +// import { detainSttn, fetchHasuDetail, fetchpbnstDetail } from "../util"; + +// interface NewWindowPopupProps { +// featureData: any; +// seletectedLayerNm?: string +// onFeatureSelect: (data: any) => void; +// onClose: () => void; +// } + +// const NewWindowPopup: React.FC<NewWindowPopupProps> = ({ +// featureData, +// seletectedLayerNm, +// onFeatureSelect, +// onClose +// }) => { +// const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject<number[]>; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; +// const [tabData, setTabData] = useState<{ id: string; name: string; data: any }[]>([]); +// const [activeTab, setActiveTab] = useState<string>('0'); +// const [viewMode, setViewMode] = useState<'list' | 'detail' | 'nothing'>('list'); +// const [fcltPk, setFcltPk] = useState<string>(''); + + +// // onClose 함수를 useCallback으로 메모이제이션 +// const memoizedOnClose = useCallback(() => { +// onClose(); +// }, [onClose]); + +// // 빗물재이용시설 변수 +// const [rainDetailModal, setRainDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false }); +// const [rainList, setRainList] = useState<customRainBdst[]>([]); + +// // 중수도시설 변수 +// const [rswtrDetailModal, setRswtrDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }); +// const [rswtrList, setRswtrList] = useState<customRswtBdst[]>([]); + +// // 온배수시설 변수 +// const [htdflDetailModal, setHtdflDetailModal] = useState<{ isOpen: boolean, data: customHtdflBdst | undefined }>({ data: undefined, isOpen: false }); +// const [htdflList, setHtdflList] = useState<customHtdflBdst[]>([]); + +// // 하수처리시설 변수 +// const [hasuList, setHasuList] = useState<pubHasuType[]>([]); +// const [isRuseReg, setIsRuseReg] = useState<{ +// data: any | undefined; +// }>({ data: undefined }); + +// // 수요처관리 변수 +// const [isDmdModal, setIsDmdModal] = useState<{ +// isMoal: boolean; +// data: any | undefined; +// }>({ isMoal: false, data: undefined }); +// const [mngList, setMngList] = useState<DemandCompType[]>([]); + +// ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// +// const getSelectedLayers = () => { +// console.trace('호출확인', 1) +// let result = null; +// const layers = gisMap ? gisMap.getLayers().getArray().filter((l: any) => l.getVisible()) : []; // gisMap이 null인지 확인 후 레이어 가져오기 +// let featureLayer: { get: (key: string) => any } = { get: () => null }; +// layers.forEach((layer: any) => { +// const source = layer.getSource(); +// if (source && source.hasFeature && featureData +// && typeof featureData.getId === 'function' && source.hasFeature(featureData)) { +// featureLayer = layer; // 피처가 속한 레이어 찾기) +// } +// }); +// result = featureLayer.get('lyrNm'); +// return result; +// }; +// // 상세 목록 데이터 상태 처리 +// useEffect(() => { +// if (hasuList.length > 0) setIsRuseReg({ data: [hasuList[0]] }); +// }, [hasuList]) +// useEffect(() => { +// if (rainList.length > 0) setRainDetailModal({ isOpen: true, data: rainList[0] }); +// }, [rainList]) +// useEffect(() => { +// if (rswtrList.length > 0) setRswtrDetailModal({ isOpen: true, data: rswtrList[0] }); +// }, [rswtrList]) +// useEffect(() => { +// if (htdflList.length > 0) setHtdflDetailModal({ isOpen: true, data: htdflList[0] }); +// }, [htdflList]) +// useEffect(() => { +// if (mngList.length > 0) setIsDmdModal({ isMoal: true, data: [mngList[0]] }); +// }, [mngList]) + +// const lastCalledIdRef = useRef<string | null>(null); +// const [layerId, setLayerId] = useState<string | null>(); + +// useEffect(() => { +// const layers = getSelectedLayers(); +// setLayerId(layers); +// }, []); // 최초 렌더링 시 호출 + +// // 피쳐 데이터가 변경될 때마다 호출 +// useEffect(() => { +// if (!featureData || typeof featureData.getProperties !== "function" || featureData.getProperties() == '') return; +// const selectedProps = featureData.getProperties(); +// const currentId = featureData.getId?.() || selectedProps?.id || selectedProps?.fid; +// // 유효하지 않은 ID는 아예 무시 +// if (!currentId || typeof currentId !== 'string') return; +// // 이전과 동일하면 무시 +// if (!currentId || currentId === lastCalledIdRef.current) return; +// lastCalledIdRef.current = currentId // 새로운 피처일 때만 API 호출 +// const layerId = getSelectedLayers?.(); +// if (!layerId || typeof layerId !== 'string') return; +// const featureCd = +// layerId === '하수재이용시설' ? selectedProps?.swtrmt_fclt_cd : +// ['빗물이용시설', '중수도시설', '온배수시설', '수요처'].includes(layerId) ? selectedProps?.bdst_nm : +// layerId === '하수처리시설' ? selectedProps?.swtrmt_fclt_nm : +// null; +// if (!featureCd || featureCd === fcltPk) return; + +// if (layerId === '하수재이용시설') { +// fetchpbnstDetail(featureCd, setTabData); +// } else if (layerId === '하수처리시설') { +// fetchHasuDetail(featureCd, selectedProps?.swtrmt_fclt_cd).then((data) => { setHasuList(data) }) +// } else { +// detainSttn(featureCd, layerId).then((res) => { +// if (layerId === '빗물이용시설') setRainList(res); +// else if (layerId === '중수도시설') setRswtrList(res); +// else if (layerId === '온배수시설') { setHtdflList(res); setHtdflDetailModal({ isOpen: true, data: res[0] }); } +// else if (layerId === '수요처') setMngList(res); +// }); +// } +// setFcltPk(featureCd); +// setActiveTab(featureCd); +// setViewMode("detail"); +// }, [featureData]); +// ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// + +// // 체크된 레이어에 따른 조건부 컴포넌트 렌더링 함수 +// const renderConditionalContent = () => { +// const actTabData = tabData.find((tab) => tab.id === activeTab); +// if (layerId === null || layerId === undefined) { +// setLayerId(seletectedLayerNm || ''); +// } + +// switch (layerId) { +// case '하수재이용시설': +// return (<ResueFacility viewMode={viewMode} seletectedLayerNm={layerId} tabData={tabData} actTabData={actTabData} setFcltPk={setFcltPk} onFeatureSelect={onFeatureSelect} onClose={onClose} />) +// case '하수처리시설': +// return (<HasuFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} isRuseReg={isRuseReg} />) +// case '빗물이용시설': +// return (<RainFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} rainDetailModal={rainDetailModal} />) +// case '중수도시설': +// return (<RswtFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} rswtrDetailModal={rswtrDetailModal} />) +// case '온배수시설': +// return (<HtdflFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} htdflDetailModal={htdflDetailModal} />) +// case '수요처': +// return(<ReuseMngFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} isDmdModal={isDmdModal} />) +// default: +// break; +// } +// return null; // 조건에 맞는 콘텐츠가 없을 경우 +// }; +// return ( +// // viewMode == 'nothing' ? <></> : +// // <NewWindowPortal +// // onClose={memoizedOnClose} +// // title="시설 상세 정보" +// // scrollbars='yes' +// // viewMode={viewMode} +// // resizable='no'> +// // {/* 체크된 레이어에 따른 조건부 렌더링 */} +// // {renderConditionalContent()} +// // </NewWindowPortal> +// <div> +// {renderConditionalContent()} +// </div> +// ); +// }; + +// export default NewWindowPopup; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/newWindowPortal.tsx b/apps/wr/app/(popUp-layout)/newWindowPortal.tsx new file mode 100644 index 000000000..6fdabead6 --- /dev/null +++ b/apps/wr/app/(popUp-layout)/newWindowPortal.tsx @@ -0,0 +1,148 @@ +import React, { useState, useEffect, useRef, useCallback, createContext, useContext } from 'react'; +import { createPortal } from 'react-dom'; + +// 현재 문서의 스타일(CSS)을 새 창으로 복사하는 함수 +const copyStyles = (sourceDoc: Document, targetDoc: Document) => { + Array.from(sourceDoc.styleSheets).forEach(styleSheet => { + try { + if (styleSheet.cssRules) { // <style> 태그로 주입된 CSS + const newStyleEl = sourceDoc.createElement('style'); + Array.from(styleSheet.cssRules).forEach(cssRule => { + newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText)); + }); + targetDoc.head.appendChild(newStyleEl); + } else if (styleSheet.href) { // <link> 태그로 연결된 CSS 파일 + const newLinkEl = sourceDoc.createElement('link'); + newLinkEl.rel = 'stylesheet'; + newLinkEl.href = styleSheet.href; + targetDoc.head.appendChild(newLinkEl); + } + } catch (e) { + console.warn('스타일시트를 복사할 수 없습니다:', e); + } + }); +}; + +interface NewWindowPortalProps { + children: React.ReactNode; + onClose: () => void; + title?: string; + width?: number; + height?: number; + resizable?: string; + scrollbars?: string; + viewMode?: 'list' | 'detail' | 'nothing'; +} + +// Context to provide the new window's document +const NewWindowContext = createContext<Document | null>(null); + +// Custom hook to consume the new window's document +export const useNewWindowDocument = () => { + const context = useContext(NewWindowContext); + if (context === null) { + throw new Error('useNewWindowDocument must be used within a NewWindowContext.Provider'); + } + return context; +}; + +const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, title = "", resizable = "yes", scrollbars = "yes", viewMode }) => { + const [container, setContainer] = useState<HTMLElement | null>(null); + const [targetDocument, setTargetDocument] = useState<Document | null>(null); + const newWindowRef = useRef<Window | null>(null); + const onCloseRef = useRef(onClose); + + // onClose 함수를 ref로 저장하여 의존성 문제 해결 + useEffect(() => { + onCloseRef.current = onClose; + }, [onClose]); + + const handleUnload = useCallback(() => { + onCloseRef.current(); + }, []); + useEffect(() => { + if (newWindowRef.current) { + if (viewMode == 'detail') { + newWindowRef.current.resizeTo(1100, 700); + } else { + newWindowRef.current.resizeTo(screen.availWidth, screen.availHeight); + } + } + }, [viewMode]); + useEffect(() => { + // 이미 창이 열려있으면 새로 열지 않음 + if (newWindowRef.current && !newWindowRef.current.closed) return; + // 브라우저 화면 정보 + const screenLeft = window.screenLeft ?? window.screenX; + const screenTop = window.screenTop ?? window.screenY; + const screenWidth = window.innerWidth ?? document.documentElement.clientWidth; + const screenHeight = window.innerHeight ?? document.documentElement.clientHeight; + + // 중앙 위치 계산 + const left = screenLeft + (screenWidth - window.screen.width) / 2; + const top = screenTop + (screenHeight - window.screen.height) / 2; + + // 1. 새 창을 열고 참조를 저장합니다. + const popupOptions = `width=${window.screen.width},height=${window.screen.height},left=${left}, top=${top}, resizable=${resizable},scrollbars=${scrollbars}`; + newWindowRef.current = window.open('', title, popupOptions); + + if (newWindowRef.current) { + newWindowRef.current.document.title = title; + + // 2. React 컴포넌트를 마운트할 컨테이너 div를 생성하여 새 창의 body에 추가합니다. + const div = newWindowRef.current.document.createElement('div'); + newWindowRef.current.document.body.appendChild(div); + setContainer(div); + setTargetDocument(newWindowRef.current.document); + + // 3. 메인 창의 스타일을 새 창으로 복사합니다. (매우 중요) + copyStyles(document, newWindowRef.current.document); + + // 4. 사용자가 창을 닫을 때 부모에게 알리기 위한 이벤트 리스너를 설정합니다. + newWindowRef.current.addEventListener('unload', handleUnload); + + // 5. 컴포넌트가 사라질 때 창을 닫는 클린업 함수를 반환합니다. + return () => { + if (newWindowRef.current) { + newWindowRef.current.removeEventListener('unload', handleUnload); + if (!newWindowRef.current.closed) { + newWindowRef.current.close(); + } + } + }; + } else { + alert('팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.'); + onCloseRef.current(); + } + }, [handleUnload, onClose, title]); + + // `createPortal`을 사용해 children을 새 창의 container div에 렌더링합니다. + // children을 NewWindowContext.Provider로 감싸서 새 창의 document를 하위 컴포넌트에서 접근 가능하도록 함 + return container && targetDocument ? ( + createPortal( + <NewWindowContext.Provider value={targetDocument}> + {children} + </NewWindowContext.Provider>, + container + ) + ) : null; +}; + +export default NewWindowPortal; + +/* +Usage example inside popup children: + +import { useNewWindowDocument } from './newWindowPortal'; + +const PopupChildComponent = () => { + const newWindowDocument = useNewWindowDocument(); + + return ( + <SomeSelectComponent + menuPortalTarget={newWindowDocument.body} // For react-select or MUI Select to render dropdowns correctly in new window + {...otherProps} + /> + ); +}; +*/ \ No newline at end of file diff --git a/apps/wr/app/map/util.ts b/apps/wr/app/(popUp-layout)/util.ts similarity index 100% rename from apps/wr/app/map/util.ts rename to apps/wr/app/(popUp-layout)/util.ts diff --git a/apps/wr/app/(with-layout)/layout.tsx b/apps/wr/app/(with-layout)/layout.tsx new file mode 100644 index 000000000..9c813f8ec --- /dev/null +++ b/apps/wr/app/(with-layout)/layout.tsx @@ -0,0 +1,18 @@ +"use client"; +import Base from "../base"; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + + + return ( + + <Base> + {children} + </Base> + + ); +} diff --git a/apps/wr/app/map/components/layerPopup/hasuFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/hasuFacility.tsx similarity index 100% rename from apps/wr/app/map/components/layerPopup/hasuFacility.tsx rename to apps/wr/app/(with-layout)/map/components/layerPopup/hasuFacility.tsx diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx new file mode 100644 index 000000000..fe4bef25a --- /dev/null +++ b/apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx @@ -0,0 +1,83 @@ +import { useWrStore } from '@/app/store'; +import type { customHtdflBdst } from '@/app/store/ruseFcltMng/fcltReg/htdflReg'; +import { tableData } from '@/components/lib/func/commom'; +import SttnDetailModal from '@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal'; +import { Title, UiTable } from '@common/business_components/ui'; +import { HeadMakeColSpan } from '@common/business_components/ui/table/HeadMakeColSpan'; +import React, { useEffect, useState } from 'react' +interface Props { + seletectedLayerNm: string; + viewMode: 'list' | 'detail' | 'nothing'; + onFeatureSelect: (feature: any) => void; + onClose: () => void; + htdflDetailModal: { isOpen: boolean; data: customHtdflBdst | undefined }; +} +const HtdflFacility = ({ seletectedLayerNm, viewMode, onFeatureSelect, onClose, htdflDetailModal }: Props) => { + const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore((state) => state); + const { htdflSttnRes, htdflSttnResCount } = htdflSttn; + const [htdflTable, setHtdflTable] = useState<customHtdflBdst[]>(); + const [htdflPage, setHtdflPage] = useState(1) + // 온배수시설 cellClick 이벤트 (상세정보) + const htdflCellClick = (index: number | undefined) => { + if (index !== undefined && htdflTable !== undefined) { + onFeatureSelect(htdflTable[index]); + onClose(); + } + }; + useEffect(() => { + if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; + if (!htdflSttn.isInit) { + initHtdfl(false, 1, "20", "0", '', code.cityCd, code.sggCd); + } + }, [code.cityCd, code.sggCd, htdflSttn.isInit, initHtdfl]); + + useEffect(() => { + if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; + const data = tableData(htdflSttnRes, { code }); + const chData = data + .map((item: any) => ({ + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].htdflObj, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + })) + .filter((item: any) => item.htdflObj !== undefined); + setHtdflTable(chData); + }, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]); + + useEffect(() => { + if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; + htdflSttnSearch(true, htdflPage, "20", '', '', code.cityCd, code.sggCd); + }, [code.cityCd, code.sggCd, htdflPage, htdflSttnSearch]); + return ( + viewMode == 'detail' ? ( + <SttnDetailModal type={"HTB"} formObj={htdflDetailModal.data as customHtdflBdst} /> + ) : ( + <div style={{ overflowY: 'auto' }}> + <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 || []} + headlist={htdflSttn.htdflSttHeadList} + pageSize={20} + total={htdflSttnResCount || 0} + cellClick={(index: number | undefined) => { + htdflCellClick(index ?? undefined); + }} + onPageChange={setHtdflPage} + > + <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> + </UiTable> + </div> + ) + ) +} + +export default HtdflFacility \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx new file mode 100644 index 000000000..54b51e8a6 --- /dev/null +++ b/apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx @@ -0,0 +1,105 @@ +import { useWrStore } from "@/app/store"; +import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { tableData } from "@/components/lib/func/commom"; +import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; +import { Title, UiTable } from "@common/business_components/ui"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import { useEffect, useState } from "react"; +interface Props { + seletectedLayerNm: string; + viewMode: 'list' | 'detail' | 'nothing'; + onFeatureSelect: (feature: any) => void; + onClose: () => void; + rainDetailModal: { isOpen: boolean; data: customRainBdst | undefined }; +} +const RainFacility = ({seletectedLayerNm,viewMode,onFeatureSelect,onClose,rainDetailModal}:Props) => { + // 빗물재이용시설 변수 + const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore( + (state) => state + ); + const { rainSttnRes, rainSttnResCount } = rainSttn; + const [rainTable, setRainTable] = useState<customRainBdst[]>(); + const [rainPage, setRainPage] = useState(1) + + // 빗물재이용시설 cellClick 이벤트 (상세정보) + const rainCellClick = (index: number | undefined, headId: string) => { + if ( + index !== undefined && + rainTable !== undefined && + headId !== 'chBuildingYn') { + onFeatureSelect(rainTable[index]); + onClose(); + } + } + useEffect(() => { + if (seletectedLayerNm !== '빗물이용시설' || viewMode != 'list') return; + console.log('빗물이용시설 초기값 호출', viewMode) + if (!rainSttn.isInit) { + rainSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); + } + }, [code.cityCd, code.sggCd, rainSttn.isInit, rainSttnInit]); + + useEffect(() => { + const data = tableData(rainSttnRes, { code }); + const chData = data + .map((item: any) => { + return { + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].rainyObj, + dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.dtfcltCpct, + instlCst: item.reuseBuilding[0].instlCst === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCst, + instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCstSprtAmt, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.pntfColArea, + filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, + archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, + }; + }) + .filter((item: any) => item.rainyObj !== undefined); + setRainTable(chData); + }, [code, rainSttnRes, rainSttn.rainSttHeadList]); + + useEffect(() => { + if (seletectedLayerNm !== '빗물이용시설' || viewMode != 'list') return; + rainSttnSearch(false, rainPage, "20", '', '', code.cityCd, code.sggCd); + }, [code.cityCd, code.sggCd, rainPage, rainSttnSearch]); + return (viewMode == 'detail' ? + (<SttnDetailModal type={"RNB"} formObj={rainDetailModal.data as customRainBdst} />) + : ( + <> + <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 || []} + headlist={rainSttn.rainSttHeadList} + pageSize={20} + total={rainSttnResCount} + cellClick={(index: number | undefined, headId: string) => { + rainCellClick(index ?? undefined, headId); + }} + onPageChange={setRainPage} + > + <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> + </UiTable> + </> + )) +} +export default RainFacility; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx new file mode 100644 index 000000000..152d37999 --- /dev/null +++ b/apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx @@ -0,0 +1,146 @@ +import { useWrStore } from "@/app/store"; +import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; +import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; +import { Title, UITab, UiTable } from "@common/business_components/ui"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import { useState, useEffect, useCallback } from "react"; +interface Props { + seletectedLayerNm: string; + viewMode: 'list' | 'detail' | 'nothing'; + setFcltPk: (pk: string) => void; + onFeatureSelect: (feature: any) => void; + onClose: () => void; + actTabData: { id: string; name: string; data: any } | undefined; + tabData: { id: string; name: string; data: any }[]; +} +const ResueFacility = ({ viewMode, seletectedLayerNm, tabData, actTabData, setFcltPk, onFeatureSelect, onClose}: Props) => { + const [activeTab, setActiveTab] = useState<string>(''); // 현재 활성화된 탭 + // 하수재이용시설 변수 + const { + pbnstSttn, + pbnstSttnSearch, + pbnSttnInit, + getFlcts + } = useWrStore((state) => state); + const { fclts, pbnstSttnResCount } = pbnstSttn + const [bdstTable, setBdstTable] = useState<WaterReuseFacility[]>() + // 재이용시설 cellClick 이벤트 (상세정보) + const pbnstCellClick = (index: number | undefined) => { + if ( + index !== undefined && + pbnstSttn.pbnstSttnRes && + pbnstSttn.pbnstSttnRes[index] + ) { + setFcltPk(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltId); + onFeatureSelect(pbnstSttn.pbnstSttnRes[index]); + onClose() + } + }; + + // 재이용 현황 초기값 + useEffect(() => { + if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; + if (!pbnstSttn.isInit) { + getFlcts() + } + }, [seletectedLayerNm, pbnstSttn.isInit]); + useEffect(() => { + if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; + pbnSttnInit("1", "20", { + partValue: "A", + sidoValue: '0', + sigunValue: "0", + regionValue: "", + unitWaterShedValue: "", + middleRegionValue: "", + envPartValue: "", + sidoText: "", + sigunText: "" + }, String(new Date().getFullYear()), pbnstSttn.fclts); + }, [fclts, pbnSttnInit, pbnstSttn.fclts, seletectedLayerNm]) + useEffect(() => { + setBdstTable(pbnstSttn.pbnstSttnRes); + }, [seletectedLayerNm, pbnstSttn.pbnstSttnRes]); + + // 재이용시설 조회 + // 재이용시설 페이징처리 관련 함수 + const onPageChangeHandler = useCallback((page: number) => { + if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; + pbnstSttnSearch( + false, + String(page), + String(20), + { + partValue: "A", + sidoValue: "0", + sigunValue: "0", + regionValue: "", + unitWaterShedValue: "", + middleRegionValue: "", + envPartValue: "", + sidoText: "", + sigunText: "", + }, + "", + String(new Date().getFullYear()), fclts + ); + }, [fclts, pbnstSttnSearch]); + // FIXME: 윤선화차장님 요구사항으로 엑셀 다운로드 삭제. + // const excelClick = useCallback(() => { + // // if (codeData) pbnstSttnSearch(1, "10000", codeData); + // excelDownload( + // [[]], + // "하수재이용시설 현황", + // "sample_pbnstSttn.xlsx", + // "A1:U2" + // ); + // }, [pbnstSttnSearch]); + return ( + viewMode == 'detail' ? + // 재이용시설 상세 + <> + <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), + }))} + /> + </div> + <PbnstSttnModal + data={actTabData?.data[0] || ({} as customPbnst)} + titleVisible={false} + /> + </> : + <div style={{ overflowY: 'auto' }}> + <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 || []} + headlist={pbnstSttn.pbnstSttHeadList} + pageSize={20} + total={pbnstSttnResCount || 0} + cellClick={(index: number | undefined) => { + pbnstCellClick(index); + }} + onPageChange={onPageChangeHandler} + > + <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> + </UiTable> + </div> + ) +} +export default ResueFacility; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx new file mode 100644 index 000000000..9030493ff --- /dev/null +++ b/apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx @@ -0,0 +1,103 @@ +import { useWrStore } from '@/app/store'; +import { tableData, formatPhoneNumber } from '@/components/lib/func/commom'; +import { Title, UiTable } from '@common/business_components/ui'; +import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form'; +import moment from 'moment'; +import React, { useEffect, useState } from 'react' +interface Props { + seletectedLayerNm: string; + viewMode: 'list' | 'detail' | 'nothing'; + onFeatureSelect: (feature: any) => void; + onClose: () => void; + isDmdModal: { data: any | undefined }; +} +const ReuseMngFacility = ({seletectedLayerNm, viewMode, onFeatureSelect, onClose, isDmdModal}:Props) => { + const { code, + coSttn, + coSttnInit, + coSttnSearch, + } = useWrStore((state) => state); + const [mngTable, setMngTable] = useState<DemandCompType[]>(); + const [mngPage, setMngPage] = useState(1); + const { coSttnRes, coSttnResCount, coSttHeadList } = coSttn; + useEffect(() => { + if (seletectedLayerNm !== '수요처' || viewMode != 'list') return; + if (!coSttn.isInit) { + coSttnInit("1", "20", "0"); + } + }, [coSttn.isInit, coSttnInit]); + const coMngCellClick = (index: number | undefined) => { + if (index !== undefined && mngTable !== undefined) { + onFeatureSelect(mngTable[index]); + onClose(); + } + }; + useEffect(() => { + if (seletectedLayerNm !== '수요처' || viewMode!='list') return; + if (coSttnRes) { + if (coSttnRes?.length > 0 && code.cityCd.length > 0) { + const data = tableData(coSttnRes, { code }); + const chData = data.map((item: any) => ({ + ...item, + telno: formatPhoneNumber(item.telno || undefined), + regDt: moment(item.regDt).format("YYYY-MM-DD"), + dmdInfoId: `${item.dmdInfoId.slice(0, 3)}-${item.dmdInfoId.slice(3, 5)}-${item.dmdInfoId.slice(5, 10)}-${item.dmdInfoId.slice(10)}` + })); + // .filter((item: any) => item !== undefined); + setMngTable(chData); + } + } + }, [coSttnRes, code]); + useEffect(() => { + if (seletectedLayerNm !== '수요처' || viewMode!='list') return; + coSttnSearch(String(mngPage), "20", String(0)); + }, [coSttnSearch, mngPage]); + return ( + viewMode == 'detail' + ? ( + <div style={{ overflowX: 'hidden' }}> + <div className="flex justify-between items-center mb-4"> + <Title title="수요처 상세정보" /> + </div> + {/* 높이 조정 */} + <UiTable + tableData={isDmdModal?.data || []} + headlist={coSttHeadList.slice(0, 3)} + pageSize={1} + total={0} + headName={"위치정보"} + cellClick={() => { }} + onPageChange={() => { }} + /> + <UiTable + tableData={isDmdModal?.data || []} + headlist={coSttHeadList.slice(3)} + pageSize={1} + total={0} + headName={"기본정보"} + cellClick={() => { }} + onPageChange={() => { }} + /> + </div> + ) : (<div> + <div className="flex justify-between items-center"> + <Title title="수요처 현황" /> + </div> + <UiTable + headName={[]} + tableData={mngTable || []} + headlist={coSttHeadList} + pageSize={20} + total={coSttnResCount + 10 || 0} + cellClick={(index: number | undefined) => { + coMngCellClick(index); + // setUpdateData(coSttnRes[index as number]); + }} + onPageChange={(page) => { + setMngPage(page); + }} + ></UiTable></div>) + ) +} + +export default ReuseMngFacility \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx new file mode 100644 index 000000000..dc2537c95 --- /dev/null +++ b/apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx @@ -0,0 +1,107 @@ +import { useWrStore } from "@/app/store"; +import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; +import { tableData } from "@/components/lib/func/commom"; +import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; +import { Title, UiTable } from "@common/business_components/ui"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import { useEffect, useState } from "react"; +interface Props { + seletectedLayerNm: string; + viewMode: 'list' | 'detail' | 'nothing'; + onFeatureSelect: (feature: any) => void; + onClose: () => void; + rswtrDetailModal: { isOpen: boolean; data: customRswtBdst | undefined }; +} +const RswtFacility = ({ seletectedLayerNm, viewMode, onFeatureSelect, onClose, rswtrDetailModal }: Props) => { + const { code, rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore( + (state) => state + ); + const { rswtSttnRes, rswtSttnResCount } = rswtSttn; + const [rswtrTable, setRswtrTable] = useState<customRswtBdst[]>() + const [rswtrPage, setRswtrPage] = useState(1); + // 중수도시설 cellClick 이벤트 (상세정보) + const rswtCellClick = (index: number | undefined, headId: string) => { + if (headId !== 'chBuildingYn' && index !== undefined && rswtrTable !== undefined) { + // setRswtrDetailModal({ isOpen: true, data: rswtrTable[index] }); + // setViewMode('detail') + onFeatureSelect(rswtrTable[index]); + onClose(); + } + } + useEffect(() => { + if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; + if (!rswtSttn.isInit) { + rswtSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); + } + }, [code.cityCd, code.sggCd, rswtSttn.isInit, rswtSttnInit]); + + useEffect(() => { + if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; + const data = tableData(rswtSttnRes, { code }); + const chData = data + .map((item: customRswtBdst) => { + return { + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0]?.rswtrObj, + chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N', + instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst, + instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt, + archArea: item?.archArea.split('.')[0] !== '-1' ? item?.archArea.split('.')[0] : '확인불가' + } + }) + .filter( + (item: customRswtBdst) => + item.reuseBuilding[0]?.rswtrObj !== undefined + ); + setRswtrTable(chData); + }, [code, rswtSttnRes]); + // FIXME: 윤선화 차장님 요구사항으로 엑셀 다운로드 삭제. + // const rswtSttnExcelDownload = useCallback(() => { + // if (rswtSttn.excelList.length > 0) { + // if (rswtSttn.excelList.length === 0) return; + // excelDownload( + // rswtSttn.excelList, + // "중수도시설 현황", + // "sample_rswtSttn.xlsx", + // "A1:W3", + // ); + // } + // }, [rswtSttn.excelList]) + + useEffect(() => { + if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; + rswtSttnSearch(false, rswtrPage, "20", '', '', code.cityCd, code.sggCd); + }, [code.cityCd, code.sggCd, rswtSttnSearch, rswtrPage]); + return ( + viewMode == 'detail' ? + // 중수도시설 상세 + ( + <SttnDetailModal type={"RST"} formObj={rswtrDetailModal.data as customRswtBdst} /> + ) : ( + <div style={{ overflowY: 'auto' }}> + <div className="flex justify-between items-center"> + <Title title="중수도시설 현황" /> + {/* <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={rswtSttnExcelDownload}> + 엑셀다운로드 + </Button> + </div> */} + </div> + <UiTable + headName={[]} + tableData={rswtrTable || []} + headlist={rswtSttn.rswtSttHeadList} + pageSize={20} + total={rswtSttnResCount} + cellClick={(index: number | undefined, headId: string) => { + rswtCellClick(index, headId); + }} + onPageChange={setRswtrPage} + > + <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> + </UiTable> + </div> + )) +} +export default RswtFacility; \ No newline at end of file diff --git a/apps/wr/app/map/components/newWindowPopup.tsx b/apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx similarity index 97% rename from apps/wr/app/map/components/newWindowPopup.tsx rename to apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx index 21d31b984..11ca0f58f 100644 --- a/apps/wr/app/map/components/newWindowPopup.tsx +++ b/apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx @@ -1,5 +1,5 @@ "use client" -import NewWindowPortal from '@/app/map/components/newWindowPortal'; +import NewWindowPortal from '@/app/(with-layout)/map/components/newWindowPortal'; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; @@ -8,7 +8,7 @@ import { useGisContext } from "@common/business_components/ui/map/Gis"; import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import ResueFacility from './layerPopup/reuseFacility'; -import { detainSttn, fetchHasuDetail, fetchpbnstDetail } from '../util'; +import { detainSttn, fetchHasuDetail, fetchpbnstDetail } from '../../../(popUp-layout)/util'; import HasuFacility from './layerPopup/hasuFacility'; import RainFacility from './layerPopup/rainFacility'; import RswtFacility from './layerPopup/rswtFacility'; @@ -22,7 +22,7 @@ interface NewWindowPopupProps { onClose: () => void; } -const NewWindowPopup: React.FC<NewWindowPopupProps> = ({ +const NewWindowPopup22: React.FC<NewWindowPopupProps> = ({ featureData, seletectedLayerNm, onFeatureSelect, @@ -180,4 +180,4 @@ const NewWindowPopup: React.FC<NewWindowPopupProps> = ({ ); }; -export default NewWindowPopup; \ No newline at end of file +export default NewWindowPopup22; \ No newline at end of file diff --git a/apps/wr/app/map/components/newWindowPortal.tsx b/apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx similarity index 95% rename from apps/wr/app/map/components/newWindowPortal.tsx rename to apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx index 119e3a52b..6a9009c6b 100644 --- a/apps/wr/app/map/components/newWindowPortal.tsx +++ b/apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx @@ -34,7 +34,7 @@ interface NewWindowPortalProps { viewMode?: 'list' | 'detail' | 'nothing'; } -const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, title = "", resizable = "yes", scrollbars = "yes", viewMode }) => { +const NewWindowPortal22: React.FC<NewWindowPortalProps> = ({ children, onClose, title = "", resizable = "yes", scrollbars = "yes", viewMode }) => { const [container, setContainer] = useState<HTMLElement | null>(null); const newWindowRef = useRef<Window | null>(null); const onCloseRef = useRef(onClose); @@ -109,4 +109,4 @@ const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, ti return container ? createPortal(children, container) : null; }; -export default NewWindowPortal; \ No newline at end of file +export default NewWindowPortal22; \ No newline at end of file diff --git a/apps/wr/app/map/mainMap/page.tsx b/apps/wr/app/(with-layout)/map/mainMap/page.tsx similarity index 74% rename from apps/wr/app/map/mainMap/page.tsx rename to apps/wr/app/(with-layout)/map/mainMap/page.tsx index e6f75feb0..dedcca225 100644 --- a/apps/wr/app/map/mainMap/page.tsx +++ b/apps/wr/app/(with-layout)/map/mainMap/page.tsx @@ -3,10 +3,13 @@ import Gis from "@common/business_components/ui/map/Gis"; import { useEffect, useRef, useState, useCallback } from "react"; import { mapService } from "../service"; -import NewWindowPopup from "../components/newWindowPopup"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; +import { useWrStore } from "@/app/store"; const Map = () => { + + const { comMap } = useWrStore((state) => state); + const {isFeatured} = comMap const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 const gisMaps = useRef<any | null>(null); const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 @@ -14,6 +17,7 @@ const Map = () => { const [featureData, setFeatureData] = useState<any>(null); // 선택된 피쳐 데이터 const [checkedLayers, setCheckedLayers] = useState<string[]>([]); const [checkedLayersData, setCheckedLayersData] = useState<any[]>([]); + const popupRef = useRef<Window | null>(null); const fetchData = async () => { try { @@ -25,16 +29,35 @@ const Map = () => { }; // 팝업 닫기 핸들러를 useCallback으로 메모이제이션 - const handlePopupClose = useCallback(() => { - setIsOpen(false); - setFeatureData(null); - }, []); + // const handlePopupClose = useCallback(() => { + // setIsOpen(false); + // setFeatureData(null); + // }, []); // 컴포넌트 마운트 시 1회 실행 useEffect(() => { fetchData(); }, []); + useEffect(() => { + const bc = new BroadcastChannel("mapDetailPopUp"); + bc.onmessage = (event) => { + if (event.data.type === "SELECT_FEATURE") { + console.log('event.data.feature ', event.data.feature) + onFeatureSelect(event.data.feature); + closePopup() + } + }; + }, []); + useEffect(() =>{ + console.log('isFeatured ', isFeatured) + + if(isFeatured){ + console.log('isFeatured ', isFeatured) + onFeatureSelect(isFeatured) + } + },[isFeatured]) + // 체크된 레이어 정보를 받는 핸들러 const handleCheckedLayersChange = ( checkedIds: string[], @@ -44,6 +67,8 @@ const Map = () => { setCheckedLayersData(checkedNodesData); }; + + // SearchModal, GisContent 등에서 호출 const onFeatureSelect = (data: any) => { const map = gisMaps.current; @@ -129,18 +154,39 @@ const Map = () => { // /> // ); // }; + const renderDetailView = useCallback( - (props: any) => ( - <NewWindowPopup - key={featureData?.fid || featureData?.id || featureData?.ftrIdn} - onClose={handlePopupClose} - checkedLayers={checkedLayers} - checkedLayersData={checkedLayersData} - {...props} - /> - ), + (props: any) => { + console.log('props ', props.seletectedLayerNm) + const url = `/mapDetilePopUp?layerNm=${encodeURIComponent(props.seletectedLayerNm)}`; + const width = window.screen.availWidth; + const height = window.screen.availHeight; + const left = 0; + const top = 0; + const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`; + popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions); + // return( + // <NewWindowPopup + // key={featureData?.fid || featureData?.id || featureData?.ftrIdn} + // onClose={handlePopupClose} + // checkedLayers={checkedLayers} + // checkedLayersData={checkedLayersData} + // {...props} + // /> + // ) + } + , [checkedLayers, checkedLayersData] // 필요 시 의존성 넣기 + ); + const closePopup = () => { + if (popupRef.current && !popupRef.current.closed) { + popupRef.current.close(); + popupRef.current = null; + setIsOpen(false); + setFeatureData(null); + } + }; return ( <div className="bg-container"> <Gis diff --git a/apps/wr/app/map/popup/page.tsx b/apps/wr/app/(with-layout)/map/popup/page.tsx similarity index 100% rename from apps/wr/app/map/popup/page.tsx rename to apps/wr/app/(with-layout)/map/popup/page.tsx diff --git a/apps/wr/app/map/service/index.ts b/apps/wr/app/(with-layout)/map/service/index.ts similarity index 100% rename from apps/wr/app/map/service/index.ts rename to apps/wr/app/(with-layout)/map/service/index.ts diff --git a/apps/wr/app/map/service/map.ts b/apps/wr/app/(with-layout)/map/service/map.ts similarity index 100% rename from apps/wr/app/map/service/map.ts rename to apps/wr/app/(with-layout)/map/service/map.ts diff --git a/apps/wr/app/matMng/coMat/coMatRvw/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx similarity index 100% rename from apps/wr/app/matMng/coMat/coMatRvw/page.tsx rename to apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx diff --git a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx similarity index 100% rename from apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx rename to apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx diff --git a/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/ruseRvwHstry/page.tsx similarity index 100% rename from apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx rename to apps/wr/app/(with-layout)/matMng/coMat/ruseRvwHstry/page.tsx diff --git a/apps/wr/app/matMng/coMng/coSttn/page.tsx b/apps/wr/app/(with-layout)/matMng/coMng/coSttn/page.tsx similarity index 100% rename from apps/wr/app/matMng/coMng/coSttn/page.tsx rename to apps/wr/app/(with-layout)/matMng/coMng/coSttn/page.tsx diff --git a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx b/apps/wr/app/(with-layout)/matMng/coMng/drgtSttn/page.tsx similarity index 100% rename from apps/wr/app/matMng/coMng/drgtSttn/page.tsx rename to apps/wr/app/(with-layout)/matMng/coMng/drgtSttn/page.tsx diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx similarity index 100% rename from apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx rename to apps/wr/app/(with-layout)/matMng/coMng/ldrmntCoSttn/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx similarity index 99% rename from apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx index d08d6f06e..688fb836c 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -10,7 +10,7 @@ import { UiTable, } from "@common/business_components"; import { Button } from "@common/components"; -import { useWrStore } from "../../../store"; +import { useWrStore } from "../../../../store"; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@common/components"; import { useCallback, useEffect, useState } from "react"; import ListDiv from "@common/business_components/ui/list_div"; diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/TableHead.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/TableHead.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltReg/rainReg/TableHead.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/TableHead.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/htdflSttn/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/htdflSttn/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead.tsx diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx similarity index 100% rename from apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx rename to apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/(with-layout)/stats/rainStat/page.tsx similarity index 100% rename from apps/wr/app/stats/rainStat/page.tsx rename to apps/wr/app/(with-layout)/stats/rainStat/page.tsx diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/(with-layout)/stats/rswtStat/page.tsx similarity index 100% rename from apps/wr/app/stats/rswtStat/page.tsx rename to apps/wr/app/(with-layout)/stats/rswtStat/page.tsx diff --git a/apps/wr/app/layout.tsx b/apps/wr/app/layout.tsx index add988817..fe4c3aff0 100644 --- a/apps/wr/app/layout.tsx +++ b/apps/wr/app/layout.tsx @@ -1,10 +1,9 @@ "use client"; import "./globals.css"; -import { StoreProvider} from "./store"; -import koBase from "../public/locales/ko/message.json"; import i18next from "i18next"; import { I18nextProvider } from "react-i18next"; -import Base from "./base"; +import koBase from "../public/locales/ko/message.json"; +import { StoreProvider } from "./store"; export default function RootLayout({ children, @@ -25,11 +24,9 @@ export default function RootLayout({ <html lang="en"> <body> <I18nextProvider i18n={i18next}> - <StoreProvider> - <Base> + <StoreProvider> {children} - </Base> - </StoreProvider> + </StoreProvider> </I18nextProvider> </body> </html> diff --git a/apps/wr/app/store/map/coSttnMap/index.tsx b/apps/wr/app/store/map/coSttnMap/index.tsx new file mode 100644 index 000000000..d6bedd9c5 --- /dev/null +++ b/apps/wr/app/store/map/coSttnMap/index.tsx @@ -0,0 +1,120 @@ +import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; +import type { CommonTableProps } from "../../common/type/header"; +import { coSttHeadListExport, coSttNodeListExport } from "../../matDmd/coSttn/headList"; +import { fetchType, getFetchWithCount } from "@/components/lib/api"; + +const coSttnMapRes: DemandCompType[] = []; + +export const costtnMapSize =20 + +export type coSttnMapState = { + coSttnMap: { + coSttnMapRes: DemandCompType[]; + coSttMapHeadList: CommonTableProps[]; + coSttMapNodeList: CommonTableProps[]; + excelList: []; + isInit: boolean; + coSttnMapResCount: number; + }; +}; + +type coSttnMapActions = { + coSttnMapInit: (pageNo: number, pageCnt: number, con: string) => void; + coSttnMapSearch: (pageNo: number, pageCnt: number, con: string) => void; + coSttnMapTxtSearch: (pageNo: number, pageCnt: number, con: string, txt: string) => void; +}; + +export type coSttnMapType = coSttnMapState & coSttnMapActions; + +export const coSttnMapStateExport: coSttnMapState = { + coSttnMap: { + coSttMapHeadList: coSttHeadListExport, + coSttMapNodeList: coSttNodeListExport, + coSttnMapRes: coSttnMapRes, + excelList: [], + isInit: false, + coSttnMapResCount: 0, + }, +}; + + +export const coSttnMapActionsExport: (set: any) => coSttnMapActions = ( + set: any +) => { + return { + coSttnMapInit: async (pageNo: number, pageCnt: number, con: string) => { + try { + const coSttnMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/request/${pageNo}/${pageCnt}/${con}` + ); + set((state: coSttnMapState) => { + return { + ...state, + coSttnMap: { + ...state.coSttnMap, + coSttnMapRes: coSttnMapRes.data, + isInit: false, + coSttnMapResCount: coSttnMapRes.count, + }, + }; + }); + } catch (e) { + console.log(e) + } + }, + coSttnMapSearch: async (pageNo: number, pageCnt: number, con: string) => { + try { + const coSttnMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/request/${pageNo}/${pageCnt}/${con}` + ); + if (Number(pageCnt) >= 10000) { + set((state: coSttnMapState) => { + return { + ...state, + coSttnMap: { + ...state.coSttnMap, + excelList: coSttnMapRes.data, + //isInit: false, + }, + }; + }); + } else + set((state: coSttnMapState) => { + return { + ...state, + coSttnMap: { + ...state.coSttnMap, + coSttnMapRes: coSttnMapRes.data, + isInit: false, + coSttnMapResCount: coSttnMapRes.count, + }, + }; + }); + } catch (erTxt) { + console.log("error", erTxt); + } + }, + coSttnMapTxtSearch: async (pageNo: number, pageCnt: number, con: string, txt: string) => { + try { + const coSttnMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`) + set((state: coSttnMapState) => { + return { + ...state, + coSttnMap: { + ...state.coSttnMap, + coSttnMapRes: coSttnMapRes.data, + coSttnMapResCount: coSttnMapRes.count, + isInit: false, + } + } + }) + } catch (erTxt) { + console.log("error", erTxt); + } + }, + } +} \ No newline at end of file diff --git a/apps/wr/app/store/map/common/index.tsx b/apps/wr/app/store/map/common/index.tsx new file mode 100644 index 000000000..2de402fa5 --- /dev/null +++ b/apps/wr/app/store/map/common/index.tsx @@ -0,0 +1,58 @@ + +export type comMapState = { + comMap: { + isFeatured:any + isModal:boolean + }; + }; + + type comMapActions = { + selectFeature:(feature:any)=>void, + chModalOpen:(open:boolean) => void, + }; + + export type comMapType = comMapState & comMapActions; + + export const comMapStateExport: comMapState = { + comMap: { + isFeatured:{}, + isModal:false + }, + }; + + + export const commonMapActionsExport: (set: any) => comMapActions = ( + set: any + ) => { + return { + selectFeature:(feature:any) => { + try { + set((state: comMapState) => { + return { + ...state, + comMap: { + ...state.comMap, + isFeatured:feature + }, + }; + }); + } catch (e) { + console.log(e) + } + },chModalOpen:(open:boolean) =>{ + try { + set((state: comMapState) => { + return { + ...state, + comMap: { + ...state.comMap, + isModal:open + }, + }; + }); + } catch (e) { + console.log(e) + } + } + } + } \ No newline at end of file diff --git a/apps/wr/app/store/map/htdflMap/index.tsx b/apps/wr/app/store/map/htdflMap/index.tsx new file mode 100644 index 000000000..8b6f4513b --- /dev/null +++ b/apps/wr/app/store/map/htdflMap/index.tsx @@ -0,0 +1,63 @@ +import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import type { CommonTableProps } from "../../common/type/header"; +import type { customHtdflBdst } from "../../ruseFcltMng/fcltReg/htdflReg"; +import { htdflSttHeadListExport, htdflSttNodeListExport } from "../../ruseFcltMng/fcltSttn/htdflSttn/headList"; + +export const htdfMapSize = 15; +export type htdfMapState = { + htdfMap: { + htdfMapRes: customHtdflBdst[]; + htdfMapCount: number; + isInit: boolean; + htdfSttHeadList: CommonTableProps[]; + htdfSttNodeList: CommonTableProps[]; + }; +}; + +type htdfMapActions = { + htdfMapInit: (page: number, total: number, cityOrSgg: string) => void; +}; + +export type htdfMapType = htdfMapState & htdfMapActions; + +export const htdfMapStateExport: htdfMapState = { + htdfMap: { + isInit: false, + htdfMapRes: [], + htdfMapCount: 1, + htdfSttHeadList: htdflSttHeadListExport, + htdfSttNodeList: htdflSttNodeListExport, + }, +}; + +export const htdfMapActionsExport: (set: any) => htdfMapActions = ( + set: any +) => { + return { + htdfMapInit: async (page: number, total: number, cityOrSgg: string) => { + try { + const htdfMapRes = await getFetchWithCount( + fetchType.WR, + `/drain/facilityList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + ); + + set((state: htdfMapState) => { + return { + ...state, + htdfMap: { + ...state.htdfMap, + htdfMapRes: htdfMapRes.data, + htdfMapCount: htdfMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + }; +}; diff --git a/apps/wr/app/store/map/ldrmntCoMap/index.tsx b/apps/wr/app/store/map/ldrmntCoMap/index.tsx new file mode 100644 index 000000000..f7b610e77 --- /dev/null +++ b/apps/wr/app/store/map/ldrmntCoMap/index.tsx @@ -0,0 +1,102 @@ +import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import type { CommonTableProps } from "../../common/type/header"; +import type { customLdrmnt } from "../../matDmd/ldrmntCoSttn"; +import { + ldrmntHeadListExport, + ldrmntNodeListExport, +} from "../../matDmd/ldrmntCoSttn/headList"; + + +export const ldrmntMapSize = 20; +export type ldrmntMapState = { + ldrmntMap: { + ldrmntMapHeadList: CommonTableProps[]; + ldrmntMapNodeList: CommonTableProps[]; + isInit: boolean; + ldrmntMapRes: customLdrmnt[]; + ldrmntMapResCount: number; + }; +}; + +type ldrmntMapActions = { + ldrmntMapInit: (page: number, total: number, con: string) => void; + ldrmntMapSearch: ( + page: number, + total: number, + con: string, + coNm: string + ) => void; +}; + +export type ldrmntMapType = ldrmntMapState & ldrmntMapActions; + +export const ldrmntMapStateExport: ldrmntMapState = { + ldrmntMap: { + ldrmntMapHeadList: ldrmntHeadListExport, + ldrmntMapNodeList: ldrmntNodeListExport, + isInit: false, + ldrmntMapRes: [], + ldrmntMapResCount: 1, + }, +}; + +export const ldrmntMapActionsExport: (set: any) => ldrmntMapActions = ( + set: any +) => { + return { + ldrmntMapInit: async (page: number, total: number, con: string) => { + try { + const ldrmntMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/request/temp/${page}/${total}/${con}` + ); + + set((state: ldrmntMapState) => { + return { + ...state, + ldrmntMap: { + ...state.ldrmntMap, + ldrmntMapRes: ldrmntMapRes.data, + ldrmntMapResCount: ldrmntMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + ldrmntMapSearch: async ( + page: number, + total: number, + con: string, + coNm: string + ) => { + let searchUrl = ""; + + if (con !== "") { + if (coNm !== "") { + searchUrl = `/reuseFc/request/temp/${page}/${total}/${con}/${coNm}`; + } else { + searchUrl = `/reuseFc/request/temp/${page}/${total}/${con}`; + } + } + try { + const ldrmntMapRes = await getFetchWithCount(fetchType.WR, searchUrl); + set((state: ldrmntMapState) => { + return { + ...state, + ldrmntMap: { + ...state.ldrmntMap, + ldrmntMapRes: ldrmntMapRes.data, + ldrmntMapResCount: ldrmntMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + }; +}; diff --git a/apps/wr/app/store/map/pbnstMap/index.tsx b/apps/wr/app/store/map/pbnstMap/index.tsx new file mode 100644 index 000000000..e2789d744 --- /dev/null +++ b/apps/wr/app/store/map/pbnstMap/index.tsx @@ -0,0 +1,108 @@ +import { fetchType, postFectch } from "@/components/lib/api"; +import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; +import { checkWrRegList } from "../../ruseFcltMng/fcltReg/pbnstReg"; +import type { ReturnType } from "@common/business_components/ui"; +import { pubFacHeadListExport } from "../../ruseFcltMng/fcltReg/pbnstReg/headList"; +import type { TableUpperProps } from "../../common/type/header"; + + +export const pbnMapTableSize =20; + +const hasuListFetch = async (page: number, pageTotal:number, reurnValue: ReturnType, searchNm?:string) => { + + let url = `/prcsFclt/ruseInfo/${page}/${pageTotal}/`; + const checkWrRegListRes = await checkWrRegList(); + + if (reurnValue.partValue === "A") { + url += `${reurnValue.partValue}/${ + // reurnValue.sidoValue ? reurnValue.sidoValue : reurnValue.sigunValue + reurnValue.sigunValue !== '0' ? reurnValue.sigunValue : reurnValue.sidoValue + }/0/1/SW` + + + } else if (reurnValue.partValue === "R") { + url += `${reurnValue.partValue}/${reurnValue.regionValue + ? reurnValue.regionValue + : reurnValue.unitWaterShedValue + ? reurnValue.unitWaterShedValue + : reurnValue.middleRegionValue + }/0/1/SW` + } else if (reurnValue.partValue === 'G') { + url += `${reurnValue.envPartValue}/${reurnValue.sigunValue !== '0' ? reurnValue.sigunValue : reurnValue.sidoValue}/0/1/SW` + } else { + url += `A/0/0/1/SW` + } + if (searchNm && searchNm?.length > 0) { + url += "/" + searchNm + } + + + +const data = checkWrRegListRes.filter((item:string) => item !== "") + + const rainRes = await postFectch( + url, + data, + fetchType.COMMON + ); + + const hasuList = rainRes.data.map((item: any) => { + return { + ...item, + fctCpc: Number(item.fctCpc) || 0, + ruse: item.ruse === false ? "N" : "Y", + }; + }); + + return {data: hasuList, count:rainRes.count}; +}; + +export type pbnMapState = { + pbnMap: { + isInit:boolean, + pbnMapRes:pubHasuType[] + pbnMapCount:number; + pbnMapHeadList:TableUpperProps[]; + }; + }; + + type pbnMapActions = { + pbnMapInit: (page: number, pageTotal:number, reurnValue: ReturnType) => void; + }; + + export type pbnMapType = pbnMapState & pbnMapActions; + + export const pbnMapStateExport: pbnMapState = { + pbnMap: { + isInit: false, + pbnMapRes:[], + pbnMapCount:1, + pbnMapHeadList:pubFacHeadListExport + }, + }; + + + export const pbnMapActionsExport: (set: any) => pbnMapActions = ( + set: any + ) => { + return { + pbnMapInit: async (page: number, pageTotal:number, reurnValue: ReturnType) => { + try { + const pubMapRes = await hasuListFetch(page,pageTotal,reurnValue) + set((state: pbnMapState) => { + return { + ...state, + pbnMap: { + ...state.pbnMap, + pbnMapRes: pubMapRes.data, + pbnMapCount: pubMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e) + } + }, + } + } \ No newline at end of file diff --git a/apps/wr/app/store/map/rainMap/index.tsx b/apps/wr/app/store/map/rainMap/index.tsx new file mode 100644 index 000000000..93b6bf9a4 --- /dev/null +++ b/apps/wr/app/store/map/rainMap/index.tsx @@ -0,0 +1,67 @@ +import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import type { CommonTableProps } from "../../common/type/header"; +import { + rainSttHeadListExport, + rainSttNodeListExport, +} from "../../ruseFcltMng/fcltSttn/rainSttn/headList"; +import type { customRainBdst } from "../../ruseFcltMng/fcltReg/rainReg"; + + +export const rainMapSize = 15 +export type rainMapState = { + rainMap: { + rainMapRes: customRainBdst[]; + rainMapCount: number; + isInit: boolean; + rainSttHeadList: CommonTableProps[]; + rainSttNodeList: CommonTableProps[]; + }; +}; + +type rainMapActions = { + rainMapInit: (page: number, total: number, cityOrSgg:string) => void; +}; + +export type rainMapType = rainMapState & rainMapActions; + +export const rainMapStateExport: rainMapState = { + rainMap: { + isInit: false, + rainMapRes: [], + rainMapCount: 1, + rainSttHeadList: rainSttHeadListExport, + rainSttNodeList: rainSttNodeListExport, + }, +}; + +export const rainMapActionsExport: (set: any) => rainMapActions = ( + set: any +) => { + return { + rainMapInit: async (page: number, total: number, cityOrSgg:string) => { + try { + const rainMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/rainyInfoList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + ); + + set((state: rainMapState) => { + return { + ...state, + rainMap: { + ...state.rainMap, + rainMapRes: rainMapRes.data, + rainMapCount: rainMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + }; +}; diff --git a/apps/wr/app/store/map/rswtMap/index.tsx b/apps/wr/app/store/map/rswtMap/index.tsx new file mode 100644 index 000000000..b7b2f0651 --- /dev/null +++ b/apps/wr/app/store/map/rswtMap/index.tsx @@ -0,0 +1,64 @@ +import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import type { CommonTableProps } from "../../common/type/header"; +import type { customRswtBdst } from "../../ruseFcltMng/fcltReg/rswtReg"; +import { rswtSttHeadListExport, rswtSttNodeListExport } from "../../ruseFcltMng/fcltSttn/rswtSttn/headList"; + + +export const rswtMapSize = 15 +export type rswtMapState = { + rswtMap: { + rswtMapRes: customRswtBdst[]; + rswtMapCount: number; + isInit: boolean; + rswtSttHeadList: CommonTableProps[]; + rswtSttNodeList: CommonTableProps[]; + }; +}; + +type rswtMapActions = { + rswtMapInit: (page: number, total: number, cityOrSgg:string) => void; +}; + +export type rswtMapType = rswtMapState & rswtMapActions; + +export const rswtMapStateExport: rswtMapState = { + rswtMap: { + isInit: false, + rswtMapRes: [], + rswtMapCount: 1, + rswtSttHeadList: rswtSttHeadListExport, + rswtSttNodeList: rswtSttNodeListExport, + }, +}; + +export const rswtMapActionsExport: (set: any) => rswtMapActions = ( + set: any +) => { + return { + rswtMapInit: async (page: number, total: number, cityOrSgg:string) => { + try { + const rswtMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/waterreuseFc` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + ); + + set((state: rswtMapState) => { + return { + ...state, + rswtMap: { + ...state.rswtMap, + rswtMapRes: rswtMapRes.data, + rswtMapCount: rswtMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + }; +}; diff --git a/apps/wr/app/store/map/ruseMap/index.tsx b/apps/wr/app/store/map/ruseMap/index.tsx new file mode 100644 index 000000000..f5145cbf3 --- /dev/null +++ b/apps/wr/app/store/map/ruseMap/index.tsx @@ -0,0 +1,94 @@ +import { fetchType, getFetch } from "@/components/lib/api"; +import type { CommonTableProps } from "../../common/type/header"; +import type { WaterReuseFacility } from "../../ruseFcltMng/fcltSttn/pbnstSttn/type"; +import { + pbnstSttNodeListExport, + pbnSttHeadListExport, +} from "../../ruseFcltMng/fcltSttn/pbnstSttn/headList"; +import type { ReturnType } from "@common/business_components/ui"; +import { hasuListFetch } from "../../ruseFcltMng/fcltSttn/pbnstSttn"; + +export const ruseMapSize = 15; +export type ruseMapState = { + ruseMap: { + ruseMapRes: WaterReuseFacility[]; + ruseMapCount: number; + isInit: boolean; + fclts: string[]; + ruseMapHeadList: CommonTableProps[]; + ruseMapNodeList: CommonTableProps[]; + }; +}; + +type ruseMapActions = { + getMapFlcts: () => void; + ruseMapInit: ( + page: number, + total: number, + reurnValue: ReturnType, + year: string, + fclts: string[] + ) => void; +}; + +export type ruseMapType = ruseMapState & ruseMapActions; + +export const ruseMapStateExport: ruseMapState = { + ruseMap: { + isInit: false, + ruseMapRes: [], + fclts: [], + ruseMapCount: 1, + ruseMapHeadList: pbnSttHeadListExport, + ruseMapNodeList: pbnstSttNodeListExport, + }, +}; + +export const ruseMapActionsExport: (set: any) => ruseMapActions = ( + set: any +) => { + return { + getMapFlcts: async () => { + const fclts = await getFetch(fetchType.WR, "/reuseFc/pubFc"); + + return set((state: ruseMapState) => ({ + ruseMap: { + ...state.ruseMap, + fclts: fclts, + }, + })); + }, + ruseMapInit: async ( + page: number, + total: number, + reurnValue: ReturnType, + year: string, + fclts: string[] + ) => { + try { + const ruseMapRes = await hasuListFetch( + String(page), + String(total), + reurnValue, + undefined, + year, + fclts + ); + + set((state: ruseMapState) => { + return { + ...state, + ruseMap: { + ...state.ruseMap, + ruseMapRes: ruseMapRes.data, + ruseMapCount: ruseMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + }; +}; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index d138a8dfe..3712b4dd1 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -97,7 +97,7 @@ export const pubFacStateExport: pubFacState = { }, }; -const checkWrRegList = async () => { +export const checkWrRegList = async () => { const wrRegList = await getFetch("wr", `/reuseFc/pubFc`); return wrRegList; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx index 7f905dd49..f14101626 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx @@ -87,7 +87,7 @@ export const pbnstSttnStateExport: pbnstSttnState = { }, }; -const hasuListFetch = async ( +export const hasuListFetch = async ( page: string, total: string, reurnValue: ReturnType, diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index 284f300c5..349dd8865 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -11,19 +11,54 @@ import { type comCodeState, type comCodeType, } from "./common/code"; -import { comFcltSearchAction, comFcltStateExport, type comFcltState, type comFcltType } from "./common/searchCode"; +import { + comFcltSearchAction, + comFcltStateExport, + type comFcltState, + type comFcltType, +} from "./common/searchCode"; import { matDmdActionsExport, matDmdStateExport, type matDmdState, type matDmdType, } from "./matDmd"; -import { coRvwActionsExport, coRvwStateExport, type coRvwState, type coRvwType } from "./matDmd/coMatRvw"; -import { coSttnActionsExport, coSttnStateExport, type coSttnState, type coSttnType } from "./matDmd/coSttn"; // 옮겨야함 -import { drgtActionsExport, drgtStateExport, type drgtState, type drgtType } from "./matDmd/drgtSttn"; -import { ldrmntActionsExport, ldrmntStateExport, type ldrmntState, type ldrmntType } from "./matDmd/ldrmntCoSttn"; -import { ruseCaseActionsExport, ruseCaseStateExport, type ruseCaseState, type ruseCaseType } from "./matDmd/ruseCaseMng"; -import { ruseHstryActionsExport, ruseHstryStateExport, type ruseHstryState, type ruseHstryType } from "./matDmd/ruseRvwHstry"; +import { + coRvwActionsExport, + coRvwStateExport, + type coRvwState, + type coRvwType, +} from "./matDmd/coMatRvw"; +import { + coSttnActionsExport, + coSttnStateExport, + type coSttnState, + type coSttnType, +} from "./matDmd/coSttn"; // 옮겨야함 +import { + drgtActionsExport, + drgtStateExport, + type drgtState, + type drgtType, +} from "./matDmd/drgtSttn"; +import { + ldrmntActionsExport, + ldrmntStateExport, + type ldrmntState, + type ldrmntType, +} from "./matDmd/ldrmntCoSttn"; +import { + ruseCaseActionsExport, + ruseCaseStateExport, + type ruseCaseState, + type ruseCaseType, +} from "./matDmd/ruseCaseMng"; +import { + ruseHstryActionsExport, + ruseHstryStateExport, + type ruseHstryState, + type ruseHstryType, +} from "./matDmd/ruseRvwHstry"; import { rainChkgdnActionsExport, rainChkgdnStateExport, @@ -36,15 +71,30 @@ import { type rswtChkgdnState, type rswtChkgdnType, } from "./prfmncReg/chkgdnReg/rswrtChkgdn"; -import { pbnstPrfmncActionsExport, pbnstPrfmncStateExport, type pbnstPrfmncState, type pbnstPrfmncType } from "./prfmncReg/pbnstPrfmncReg"; +import { + pbnstPrfmncActionsExport, + pbnstPrfmncStateExport, + type pbnstPrfmncState, + type pbnstPrfmncType, +} from "./prfmncReg/pbnstPrfmncReg"; import { rainChkSttnActionsExport, rainChkSttnStateExport, type rainChkSttnState, type rainChkSttnType, } from "./prfmncSttn/chkgdnSttn/rainChkgdnSttn"; -import { rswtChkStateExport, rswtChkSttnActionsExport, type rswtChkSttnState, type rswtChkSttnType } from "./prfmncSttn/chkgdnSttn/rswtChkgdnSttn"; -import { pbnstPrfmncSttnActionsExport, pbnstPrfmncSttnExport, type pbnstPrfmncSttnState, type pbnstPrfmncSttnType } from "./prfmncSttn/pbnstPrfmncSttn"; +import { + rswtChkStateExport, + rswtChkSttnActionsExport, + type rswtChkSttnState, + type rswtChkSttnType, +} from "./prfmncSttn/chkgdnSttn/rswtChkgdnSttn"; +import { + pbnstPrfmncSttnActionsExport, + pbnstPrfmncSttnExport, + type pbnstPrfmncSttnState, + type pbnstPrfmncSttnType, +} from "./prfmncSttn/pbnstPrfmncSttn"; import { bdstActionsExport, bdstStateExport, @@ -81,7 +131,12 @@ import { type htdflSttnState, type htdflSttnType, } from "./ruseFcltMng/fcltSttn/htdflSttn"; -import { pbnstSttnActionsExport, pbnstSttnStateExport, type pbnstSttnState, type pbnstSttnType } from "./ruseFcltMng/fcltSttn/pbnstSttn"; +import { + pbnstSttnActionsExport, + pbnstSttnStateExport, + type pbnstSttnState, + type pbnstSttnType, +} from "./ruseFcltMng/fcltSttn/pbnstSttn"; import { rainSttnActionsExport, rainSttnStateExport, @@ -94,11 +149,74 @@ import { type rswtSttnState, type rswtSttnType, } from "./ruseFcltMng/fcltSttn/rswtSttn"; -import { rainStatActionsExport, rainStatExport, type rainStatState, type rainStatType } from "./stats/rainStat"; -import { rswtStatActionsExport, rswtStatExport, type rswtStatState, type rswtStatType } from "./stats/rswtStat"; +import { + rainStatActionsExport, + rainStatExport, + type rainStatState, + type rainStatType, +} from "./stats/rainStat"; +import { + rswtStatActionsExport, + rswtStatExport, + type rswtStatState, + type rswtStatType, +} from "./stats/rswtStat"; //import { isLogin } from "./common/login"; import { LoginApi } from "@/src/entities/auth"; -import { authActionsExport, authStateExport, type authState, type authType } from "./common/auth"; +import { + authActionsExport, + authStateExport, + type authState, + type authType, +} from "./common/auth"; +import { + pbnMapActionsExport, + pbnMapStateExport, + type pbnMapState, + type pbnMapType, +} from "./map/pbnstMap"; +import { + comMapStateExport, + commonMapActionsExport, + type comMapState, + type comMapType, +} from "./map/common"; +import { + rainMapActionsExport, + rainMapStateExport, + type rainMapState, + type rainMapType, +} from "./map/rainMap"; +import { + rswtMapActionsExport, + rswtMapStateExport, + type rswtMapState, + type rswtMapType, +} from "./map/rswtMap"; +import { + htdfMapActionsExport, + htdfMapStateExport, + type htdfMapState, + type htdfMapType, +} from "./map/htdflMap"; +import { + ruseMapActionsExport, + ruseMapStateExport, + type ruseMapState, + type ruseMapType, +} from "./map/ruseMap"; +import { + coSttnMapActionsExport, + coSttnMapStateExport, + type coSttnMapState, + type coSttnMapType, +} from "./map/coSttnMap"; +import { + ldrmntMapActionsExport, + ldrmntMapStateExport, + type ldrmntMapState, + type ldrmntMapType, +} from "./map/ldrmntCoMap"; export type WrStore = comCodeType & pubFacType & @@ -112,23 +230,29 @@ export type WrStore = comCodeType & rainSttnType & rswtSttnType & htdflSttnType & - rainChkSttnType& - rswtChkSttnType& - pbnstSttnType& - coSttnType& // 옮겨야함 - ldrmntType& // 옮겨야함 - pbnstPrfmncType& - coRvwType& - ruseHstryType& - pbnstPrfmncSttnType& - drgtType& - ruseCaseType& - rainStatType& - rswtStatType& + rainChkSttnType & + rswtChkSttnType & + pbnstSttnType & + coSttnType & // 옮겨야함 + ldrmntType & // 옮겨야함 + pbnstPrfmncType & + coRvwType & + ruseHstryType & + pbnstPrfmncSttnType & + drgtType & + ruseCaseType & + rainStatType & + rswtStatType & comFcltType & - authType - - ; + pbnMapType & + comMapType & + rainMapType & + rswtMapType & + htdfMapType & + ruseMapType & + coSttnMapType & + ldrmntMapType & + authType; export const StoreZus = ( initState: comCodeState & @@ -143,22 +267,29 @@ export const StoreZus = ( rainSttnState & rswtSttnState & htdflSttnState & - rainChkSttnState& - comFcltState& + rainChkSttnState & + comFcltState & rswtChkSttnState & - pbnstSttnState& - coSttnState& // 옮겨야함 - ldrmntState& // 옮겨야함 - pbnstPrfmncState& - coRvwState& - ruseHstryState& - pbnstPrfmncSttnState& - drgtState& - ruseCaseState& - rainStatState& - rswtStatState& - authState - = { + pbnstSttnState & + coSttnState & // 옮겨야함 + ldrmntState & // 옮겨야함 + pbnstPrfmncState & + coRvwState & + ruseHstryState & + pbnstPrfmncSttnState & + drgtState & + ruseCaseState & + rainStatState & + rswtStatState & + pbnMapState & + comMapState & + rainMapState & + rswtMapState & + htdfMapState & + ruseMapState & + coSttnMapState & + ldrmntMapState & + authState = { ...comCodeStateExport, ...pubFacStateExport, ...rainFacStateExport, @@ -174,8 +305,8 @@ export const StoreZus = ( ...rainChkSttnStateExport, ...rswtChkStateExport, ...pbnstSttnStateExport, - ...coSttnStateExport, // 옮겨야함 - ...ldrmntStateExport, // 옮겨야함 + ...coSttnStateExport, + ...ldrmntStateExport, ...pbnstPrfmncStateExport, ...coRvwStateExport, ...ruseHstryStateExport, @@ -185,7 +316,15 @@ export const StoreZus = ( ...rainStatExport, ...rswtStatExport, ...comFcltStateExport, - ...authStateExport + ...pbnMapStateExport, + ...comMapStateExport, + ...authStateExport, + ...rainMapStateExport, + ...rswtMapStateExport, + ...htdfMapStateExport, + ...ruseMapStateExport, + ...coSttnMapStateExport, + ...ldrmntMapStateExport, } ) => { return createStore<WrStore>()((set) => { @@ -195,7 +334,7 @@ export const StoreZus = ( getMiddleRegionCd(set); getUnitWaterShedCd(set); getEnvPartCd(set); - LoginApi.login({userId: "CLEANWATER", password: "gktneh12!@"}) + LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" }); return { ...initState, ...comFcltSearchAction(set), @@ -214,8 +353,8 @@ export const StoreZus = ( ...rainChkSttnActionsExport(set), ...rswtChkSttnActionsExport(set), ...pbnstSttnActionsExport(set), - ...coSttnActionsExport(set), // 옮겨야함 - ...ldrmntActionsExport(set), // 옮겨야함 + ...coSttnActionsExport(set), // 옮겨야함 + ...ldrmntActionsExport(set), // 옮겨야함 ...pbnstPrfmncActionsExport(set), ...coRvwActionsExport(set), ...ruseHstryActionsExport(set), @@ -224,7 +363,15 @@ export const StoreZus = ( ...ruseCaseActionsExport(set), ...rainStatActionsExport(set), ...rswtStatActionsExport(set), - ...authActionsExport(set) + ...authActionsExport(set), + ...commonMapActionsExport(set), + ...pbnMapActionsExport(set), + ...rainMapActionsExport(set), + ...rswtMapActionsExport(set), + ...htdfMapActionsExport(set), + ...ruseMapActionsExport(set), + ...coSttnMapActionsExport(set), + ...ldrmntMapActionsExport(set), }; }); }; diff --git a/apps/wr/components/ui/map/LayerPopUp/CoSttnMap/CoSttnMap.tsx b/apps/wr/components/ui/map/LayerPopUp/CoSttnMap/CoSttnMap.tsx new file mode 100644 index 000000000..13e928506 --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/CoSttnMap/CoSttnMap.tsx @@ -0,0 +1,195 @@ +import { useWrStore } from "@/app/store"; +import { costtnMapSize } from "@/app/store/map/coSttnMap"; +import { + formatPhoneNumber, + getCity, + tableData, +} from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { + ContentsDiv, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, + Title, + UiTable, + type SelectDataType, +} from "@common/business_components/ui"; +import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; +import { Button } from "@common/components/ui"; +import moment from "moment"; +import { useCallback, useEffect, useState } from "react"; + +export function CoSttnMap({ + rtnFeature, +}: { + rtnFeature: (feature: any) => void; +}) { + const { + code, + coSttnMap, + coSttnMapInit, + coSttnMapSearch, + coSttnMapTxtSearch, + } = useWrStore((state) => state); + const [coSttnMapTable, setCoSttnMapTable] = useState<DemandCompType[]>(); + const [isReset, setIsReset] = useState(false); + const { coSttMapHeadList, coSttnMapRes, coSttnMapResCount } = coSttnMap; + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + + const [seartchTxt, setSearchTxt] = useState<string>(); + + const getSelCity = useCallback( + (val: string | number) => { + const cityValue = String(val); + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + setObjSearch({ city: cityValue, sgg: "0" }); + }, + [code.sggCd] + ); + + const getSgg = useCallback((val: string | number) => { + setObjSearch((prev) => ({ ...prev, sgg: String(val) })); + }, []); + + useEffect(() => { + // code.cityCd 데이터가 로드되었고, 아직 시/도 선택이 안된 초기 상태일 때 실행 + if (code.cityCd && code.cityCd.length > 0 && !objSearch.city) { + const firstCityVal = code.cityCd[0]?.val; + if (firstCityVal) { + // 첫 번째 시/도 값으로 상태를 초기화합니다. + getSelCity(firstCityVal); + } + } + }, [code.cityCd, objSearch.city, getSelCity]); + + useEffect(() => { + if (!coSttnMap.isInit) { + coSttnMapInit(1, costtnMapSize, "0"); + } + }, [coSttnMap.isInit, coSttnMapInit]); + + const coSttnMapCellClick = (index: number | undefined) => { + if (index !== undefined && coSttnMapTable !== undefined) { + rtnFeature(coSttnMapTable[index]); + } + }; + useEffect(() => { + if (coSttnMapRes) { + if (coSttnMapRes?.length > 0 && code.cityCd.length > 0) { + const data = tableData(coSttnMapRes, { code }); + const chData = data.map((item: any) => ({ + ...item, + telno: formatPhoneNumber(item.telno || undefined), + regDt: moment(item.regDt).format("YYYY-MM-DD"), + dmdInfoId: `${item.dmdInfoId.slice(0, 3)}-${item.dmdInfoId.slice(3, 5)}-${item.dmdInfoId.slice(5, 10)}-${item.dmdInfoId.slice(10)}`, + })); + // .filter((item: any) => item !== undefined); + setCoSttnMapTable(chData); + } + } + }, [coSttnMapRes, code]); + return ( + <> + <ContentsDiv> + <div className="grid grid-cols-4 gap-4 "> + <div className="col-span-4"> + <Title title={"수요처 관리"} /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd || []} + onSelectValue={(val) => { + getSelCity(val); + }} + value={objSearch.city} + /> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + onSelectValue={getSgg} + value={objSearch.sgg} + /> + <SearchInput + className={"!text-3xl ml-4"} + label="회사명" + textValue={seartchTxt ?? ""} + setText={(e) => { + setSearchTxt(e); + }} + /> + </div> + </SearchFormLeft> + <SearchFormRight className="w-3/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2"> + <Button + className="mt-2" + size={"sm"} + onClick={() => { + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + if (con) { + if (seartchTxt && seartchTxt?.length > 0) { + coSttnMapTxtSearch( + 1, + costtnMapSize, + String(con), + seartchTxt ?? "" + ); + } else { + coSttnMapSearch(1, costtnMapSize, String(con)); + } + setIsReset(true) + } + }} + > + 조회 + </Button> + </div> + </SearchFormRight> + </SearchDiv> + </div> + </div> + <div className="grid grid-cols-2 gap-4 "> + <div className="col-span-2"> + <UiTable + headName={[]} + tableData={coSttnMapTable || []} + headlist={coSttMapHeadList} + pageSize={20} + total={coSttnMapResCount|| 0} + cellClick={(index: number | undefined) => { + coSttnMapCellClick(index); + // setUpdateData(coSttnRes[index as number]); + }} + onPageChange={(page) => { + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + coSttnMapSearch(page, costtnMapSize, String(con)); + setIsReset(false); + }} + resetPageNo={isReset} + ></UiTable> + </div> + </div> + </ContentsDiv> + </> + ); +} diff --git a/apps/wr/components/ui/map/LayerPopUp/HasuFacilty/HasuFacility.tsx b/apps/wr/components/ui/map/LayerPopUp/HasuFacilty/HasuFacility.tsx new file mode 100644 index 000000000..4f9d052de --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/HasuFacilty/HasuFacility.tsx @@ -0,0 +1,109 @@ +import { useWrStore } from "@/app/store"; +import { btnClass } from "@/app/store/common/code"; +import { pbnMapTableSize } from "@/app/store/map/pbnstMap"; +import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import { tableData } from "@/components/lib/func/commom"; +import { + ContentsDiv, + SearchBaseForm, + SearchInput, + Title, + UiTable, + type ReturnType, +} from "@common/business_components/ui"; +import { Label } from "@common/components/ui"; +import { useEffect, useRef, useState } from "react"; + +export function HasuFacility({rtnFeature}:{rtnFeature:(feature:any)=>void } ) { + const { code, pbnMap, pbnMapInit } = useWrStore((state) => state); + const [hasuTable, setHasuTable] = useState<pubHasuType[]>(); + const [isReset, setIsReset] = useState(false); + const [pbnRuseNm, setPbnRuseNm] = useState<string>(""); + const ref = useRef<ReturnType>({} as ReturnType); + const { pbnMapHeadList, pbnMapRes, pbnMapCount } = pbnMap; + + useEffect(() => { + if (!pbnMap.isInit) { + pbnMapInit(1, pbnMapTableSize, ref.current); + } + }, [pbnMap.isInit, pbnMapInit]); + + useEffect(() => { + if (code.sggCd.length && pbnMapRes.length > 0) { + setHasuTable(tableData(pbnMapRes, { code })); + } + }, [code, pbnMapRes]); + + const hasuCellClick = (index: number | undefined) => { + if (index !== undefined && pbnMapRes !== undefined) { + rtnFeature(pbnMapRes[index]) + } + }; + return ( + <> + <ContentsDiv> + <div className="grid grid-cols-2 gap-4 "> + <div className="col-span-2"> + <Title title="하수처리시설 현황" /> + <SearchBaseForm + selectSidoData={code.cityCd} + selectSigunData={code.sggCd} + selectRegionData={code.rvbsnCd} + selectUnitWaterShedData={code.lgbsnCd} + selectMiddleRegionData={code.mdmbsnCd} + selectEnvPartData={code.lclgvrnmntCd} + buttonOrder={["query", "init", "excel"]} + rightClassName="ml-auto mr-6 flex items-center space-x-1" + leftClassName="flex gap-5 w-9/12 m-4" + leftSelectClassName="w-1/4" + rightChildren={<></>} + leftChildren={ + <div className="col-span-3 flex items-center"> + <Label className="w-full mt-2 ml-4 text-xl text-gray-600"> + {"하수처리시설명"} + </Label> + <SearchInput + className={"text-2xl w-full"} + label="" + textValue={pbnRuseNm || ""} + setText={(e) => { + setPbnRuseNm(e || ""); + }} + /> + </div> + } + queryClick={() => { + setIsReset(true); + }} + initClick={function (): void { + setPbnRuseNm(""); + }} + btnClass={btnClass} + ref={ref} + isAdmin={false} + excelClick={function (returnType: ReturnType): void { + console.log("pbnstSttnSearch ", returnType); + }} + /> + </div> + <div className="col-span-6"> + {/* 높이 조정 */} + <UiTable + tableData={hasuTable || []} + headlist={pbnMapHeadList} + pageSize={pbnMapTableSize} + total={pbnMapCount || 0} + headName={""} + cellClick={hasuCellClick} + onPageChange={(page) => { + pbnMapInit(page, pbnMapTableSize, ref.current); + setIsReset(false); + }} + resetPageNo={isReset} + /> + </div> + </div> + </ContentsDiv> + </> + ); +} diff --git a/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx b/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx new file mode 100644 index 000000000..bca9128e1 --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx @@ -0,0 +1,77 @@ +import { useWrStore } from "@/app/store"; +import { rainMapSize } from "@/app/store/map/rainMap"; +import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import { tableData } from "@/components/lib/func/commom"; +import { Title, UiTable } from "@common/business_components/ui"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import { useEffect, useState } from "react"; + +export function HtdflFacility({ + rtnFeature, + }: { + rtnFeature: (feature: any) => void; + }) { + const { code, htdfMap, htdfMapInit } = useWrStore((state) => state); + const { htdfMapCount, htdfMapRes, htdfSttHeadList, htdfSttNodeList } = + htdfMap; + const [htdflTable, setHtdflTable] = useState<customHtdflBdst[]>(); + const [isReset, setIsReset] = useState(false); + + const htdflCellClick = (index: number | undefined) => { + if (index !== undefined && htdflTable !== undefined) { + rtnFeature(htdflTable[index]); + + } + }; + + useEffect(() => { + if (!htdfMap.isInit) { + htdfMapInit(1, rainMapSize, "0"); + } + }, [htdfMap.isInit, htdfMapInit]); + + useEffect(() => { + const data = tableData(htdfMapRes, { code }); + const chData = data + .map((item: any) => ({ + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].htdflObj, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + })) + .filter((item: any) => item.htdflObj !== undefined); + setHtdflTable(chData); + }, [code, htdfMapRes]); + + return ( + <> + <div style={{ overflowY: "auto" }}> + <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 || []} + headlist={htdfSttHeadList} + pageSize={rainMapSize} + total={htdfMapCount} + cellClick={(index: number | undefined) => { + htdflCellClick(index ?? undefined); + }} + onPageChange={(page) => { + htdfMapInit(page, rainMapSize, "0"); + setIsReset(false); + }} + resetPageNo={isReset} + > + <HeadMakeColSpan upHeadList={htdfSttNodeList} /> + </UiTable> + </div> + </> + ); +} diff --git a/apps/wr/components/ui/map/LayerPopUp/LdrmntCoMap/LdrmntCoMap.tsx b/apps/wr/components/ui/map/LayerPopUp/LdrmntCoMap/LdrmntCoMap.tsx new file mode 100644 index 000000000..56e42368f --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/LdrmntCoMap/LdrmntCoMap.tsx @@ -0,0 +1,189 @@ +import { useWrStore } from "@/app/store"; +import { ldrmntMapSize } from "@/app/store/map/ldrmntCoMap"; +import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; +import { getCity, tableData } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { + ContentsDiv, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, + Title, + UiTable, + type SelectDataType, +} from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; +import { Button } from "@common/components/ui"; +import { useEffect, useState } from "react"; + +export function LdrmntCoMap({ + rtnFeature, +}: { + rtnFeature: (feature: any) => void; +}) { + const { code, ldrmntMap, ldrmntMapInit, ldrmntMapSearch } = useWrStore( + (state) => state + ); + + const { ldrmntMapRes, ldrmntMapResCount, ldrmntMapHeadList } = ldrmntMap; + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + const [bdstTable, setBdstTable] = useState<customLdrmnt[]>(); + const [searchTxt, setSearchTxt] = useState<string>(); + const [resetPage, isResetPage] = useState(false); + + const computeCityNm = () => { + let cityTxt = ""; + let sggTxt = ""; + + if (objSearch.city) { + cityTxt = code.cityCd.find((c) => c.val === objSearch.city)?.text || ""; + } + if (objSearch.sgg) { + sggTxt = code.sggCd.find((s) => s.val === objSearch.sgg)?.text || ""; + } + + if (cityTxt === "" || cityTxt === "전체") cityTxt = "0"; + + return sggTxt && sggTxt !== "0" ? `${cityTxt} ${sggTxt}` : cityTxt; + }; + + const cellClick = (index: number | undefined) => { + if (index !== undefined) { + rtnFeature(ldrmntMapRes[index]); + } + }; + + const getSelCity = (val: string | number) => { + const cityValue = String(val); + + if (cityValue === "0") { + setSelectSgg([]); + setObjSearch({ city: cityValue, sgg: "" }); + } else { + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + const firstSggVal = + data.find((item) => item.val === "0")?.val || (data[0]?.val ?? ""); + setObjSearch({ city: cityValue, sgg: firstSggVal }); + } + }; + + const getSgg = (val: string | number) => { + setObjSearch({ ...objSearch, sgg: String(val) }); + }; + + useEffect(() => { + if (!ldrmntMap.isInit) { + ldrmntMapInit(1, ldrmntMapSize, "0"); + } + }, [ldrmntMap.isInit, ldrmntMapInit]); + + useEffect(() => { + const transData = Array.isArray(ldrmntMapRes) + ? ldrmntMapRes + : [ldrmntMapRes]; + const data = tableData(transData, { code }); + const tbData = Array.isArray(data) + ? data.map((item: customLdrmnt) => ({ + ...item, + ctpvCd: item.fctryAddr?.split(" ")[0] || "", + sggCd: item.fctryAddr?.split(" ")[1] || "", + })) + : []; + + setBdstTable(tbData); + }, [ldrmntMapRes, code]); + + return ( + <> + <ContentsDiv> + <div className="grid grid-cols-4 gap-4 "> + <div className="col-span-4"> + <Title title={"잠재수요처 관리"} /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd} + onSelectValue={getSelCity} + /> + <SelectBox + className="col-span-2 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + value={objSearch.sgg} // value props 추가 + onSelectValue={getSgg} + /> + <SearchInput + className={"text-2xl ml-4"} + label="회사명" + textValue={searchTxt || ""} + setText={(e) => { + setSearchTxt(e); + }} + /> + </div> + </SearchFormLeft> + <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2 items-center"> + <Button + size={"sm"} + onClick={() => { + ldrmntMapSearch( + 1, + ldrmntMapSize, + computeCityNm(), + searchTxt || "" + ); + isResetPage(true); + }} + > + 조회 + </Button> + </div> + </SearchFormRight> + </SearchDiv> + </div> + </div> + <div className="grid grid-cols-6 gap-4 "> + <div className="col-span-6"> + <div className="overflow-x-auto"> + <ListDiv className="min-w-max"> + <UiTable + headName={undefined} + tableData={bdstTable || []} + headlist={ldrmntMapHeadList} + pageSize={20} + total={ldrmntMapResCount || 0} + cellClick={(index: number | undefined) => { + cellClick(index ?? undefined); + }} + onPageChange={(page) => { + ldrmntMapSearch( + page, + ldrmntMapSize, + computeCityNm(), + searchTxt || "" + ); + isResetPage(false); + }} + resetPageNo={resetPage} + /> + </ListDiv> + </div> + </div> + </div> + </ContentsDiv> + </> + ); +} diff --git a/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx b/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx new file mode 100644 index 000000000..348cf6b9e --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx @@ -0,0 +1,102 @@ +import { useWrStore } from "@/app/store"; +import { rainMapSize } from "@/app/store/map/rainMap"; +import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { tableData } from "@/components/lib/func/commom"; +import { ContentsDiv, Title, UiTable } from "@common/business_components/ui"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import { useEffect, useState } from "react"; + +export function RainFacility({ + rtnFeature, +}: { + rtnFeature: (feature: any) => void; +}) { + const { code, rainMap, rainMapInit } = useWrStore((state) => state); + const { rainMapRes, rainMapCount, rainSttHeadList, rainSttNodeList } = + rainMap; + const [rainTable, setRainTable] = useState<customRainBdst[]>(); + const [isReset, setIsReset] = useState(false); + + useEffect(() => { + if (!rainMap.isInit) { + rainMapInit(1, rainMapSize, "0"); + } + }, [rainMapInit, rainMap.isInit]); + + const rainCellClick = (index: number | undefined, headId: string) => { + if ( + index !== undefined && + rainTable !== undefined && + headId !== "chBuildingYn" + ) { + rtnFeature(rainTable[index]); + } + }; + + useEffect(() => { + + const data = tableData(rainMapRes, { code }); + const chData = data + .map((item: any) => { + return { + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].rainyObj, + dtfcltCpct: + item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.dtfcltCpct, + instlCst: + item.reuseBuilding[0].instlCst === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCst, + instlCstSprtAmt: + item.reuseBuilding[0].instlCstSprtAmt === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCstSprtAmt, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + pntfColArea: + item.reuseBuilding[0].rainyObj.pntfColArea === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.pntfColArea, + filtrTrtmfctCpct: + item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, + archArea: + Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, + }; + }) + .filter((item: any) => item.rainyObj !== undefined); + setRainTable(chData); + }, [code, rainMapRes]); + + return ( + <> + <ContentsDiv> + <div className="grid grid-cols-2 gap-4 "> + <div className="col-span-2"> + <Title title="빗물이용시설 현황" /> + <UiTable + headName={[]} + tableData={rainTable || []} + headlist={rainSttHeadList} + pageSize={20} + total={rainMapCount} + cellClick={(index: number | undefined, headId: string) => { + rainCellClick(index ?? undefined, headId); + }} + onPageChange={(page) => { + rainMapInit(page, rainMapSize, "0"); + setIsReset(false); + }} + resetPageNo={isReset} + > + <HeadMakeColSpan upHeadList={rainSttNodeList} /> + </UiTable> + </div> + </div> + </ContentsDiv> + </> + ); +} diff --git a/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx b/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx new file mode 100644 index 000000000..64d558b44 --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx @@ -0,0 +1,99 @@ +import { useWrStore } from "@/app/store"; +import { rainMapSize } from "@/app/store/map/rainMap"; +import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; +import { tableData } from "@/components/lib/func/commom"; +import { Title, UiTable } from "@common/business_components/ui"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import { useEffect, useState } from "react"; + +export function RswtFacility({ + rtnFeature, +}: { + rtnFeature: (feature: any) => void; +}) { + const { code, rswtMap, rswtMapInit } = useWrStore((state) => state); + const { rswtMapRes, rswtMapCount, rswtSttHeadList, rswtSttNodeList } = + rswtMap; + const [rswtrTable, setRswtrTable] = useState<customRswtBdst[]>(); + const [isReset, setIsReset] = useState(false); + + const rswtCellClick = (index: number | undefined, headId: string) => { + if ( + headId !== "chBuildingYn" && + index !== undefined && + rswtrTable !== undefined + ) { + rtnFeature(rswtrTable[index]); + } + }; + + useEffect(() => { + if (!rswtMap.isInit) { + rswtMapInit(1, rainMapSize, "0"); + } + }, [rswtMapInit, rswtMap.isInit]); + + useEffect(() => { + const data = tableData(rswtMapRes, { code }); + const chData = data + .map((item: customRswtBdst) => { + return { + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0]?.rswtrObj, + chBuildingYn: + item?.chgBuilding[0]?.bdstChgNm !== null && + item?.chgBuilding.length > 0 + ? "Y" + : "N", + instlCst: + item.reuseBuilding[0]?.instlCst === -1 + ? "확인불가" + : item.reuseBuilding[0]?.instlCst, + instlCstSprtAmt: + item.reuseBuilding[0]?.instlCstSprtAmt === -1 + ? "확인불가" + : item.reuseBuilding[0]?.instlCstSprtAmt, + archArea: + item?.archArea.split(".")[0] !== "-1" + ? item?.archArea.split(".")[0] + : "확인불가", + }; + }) + .filter( + (item: customRswtBdst) => item.reuseBuilding[0]?.rswtrObj !== undefined + ); + setRswtrTable(chData); + }, [code, rswtMapRes]); + return ( + <> + <div style={{ overflowY: "auto" }}> + <div className="flex justify-between items-center"> + <Title title="중수도시설 현황" /> + {/* <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={rswtSttnExcelDownload}> + 엑셀다운로드 + </Button> + </div> */} + </div> + <UiTable + headName={[]} + tableData={rswtrTable || []} + headlist={rswtSttHeadList} + pageSize={20} + total={rswtMapCount} + cellClick={(index: number | undefined, headId: string) => { + rswtCellClick(index, headId); + }} + onPageChange={(page) => { + rswtMapInit(page, rainMapSize, "0"); + setIsReset(false); + }} + resetPageNo={isReset} + > + <HeadMakeColSpan upHeadList={rswtSttNodeList} /> + </UiTable> + </div> + </> + ); +} diff --git a/apps/wr/components/ui/map/LayerPopUp/RuseFacilty/RuseFacility.tsx b/apps/wr/components/ui/map/LayerPopUp/RuseFacilty/RuseFacility.tsx new file mode 100644 index 000000000..4fd9c684f --- /dev/null +++ b/apps/wr/components/ui/map/LayerPopUp/RuseFacilty/RuseFacility.tsx @@ -0,0 +1,140 @@ +import { useWrStore } from "@/app/store"; +import { btnClass } from "@/app/store/common/code"; +import { ruseMapSize } from "@/app/store/map/ruseMap"; +import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; +import { yearOptions } from "@/components/lib/func/commom"; +import { + ContentsDiv, + SearchBaseForm, + SearchInput, + SelectBox, + Title, + UiTable, + type ReturnType, +} from "@common/business_components/ui"; +import { Label } from "@common/components/ui"; +import { useEffect, useRef, useState } from "react"; + +export function RuseFacility({ + rtnFeature, + }: { + rtnFeature: (feature: any) => void; + }) { + const { code, ruseMap, ruseMapInit, getMapFlcts } = useWrStore( + (state) => state + ); + + const { ruseMapCount, fclts, ruseMapRes,ruseMapHeadList } = ruseMap; + + const [ruseTable, setRuseTable] = useState<WaterReuseFacility[]>(); + const [isReset, setIsReset] = useState(false); + const ref = useRef<ReturnType>({} as ReturnType); + const [searchYear, setSearchYear] = useState<string>( + String(new Date().getFullYear()) + ); + const [pbnRuseNm, setPbnRuseNm] = useState<string>(""); + + const ruseCellClick = (index: number | undefined) => { + if ( + index !== undefined && + ruseTable !== undefined + ) { + rtnFeature(ruseTable[index]); + } + }; + useEffect(() => { + if (!ruseMap.isInit) { + getMapFlcts(); + } + }, [ruseMap.isInit]); + useEffect(() => { + ruseMapInit(1,ruseMapSize, ref.current, searchYear, fclts); + }, [fclts]); + + useEffect(() => { + if (ruseMapRes && ruseMapRes.length > 0) { + setRuseTable(ruseMapRes); + } else { + setRuseTable([]); + } + }, [ruseMapRes]); + + + return ( + <> + <ContentsDiv> + <div className="grid grid-cols-2 gap-4 "> + <div className="col-span-2"> + <Title title="하수재이용 시설 현황" /> + <SearchBaseForm + selectSidoData={code.cityCd} + selectSigunData={code.sggCd} + selectRegionData={code.rvbsnCd} + selectUnitWaterShedData={code.lgbsnCd} + selectMiddleRegionData={code.mdmbsnCd} + selectEnvPartData={code.lclgvrnmntCd} + buttonOrder={["query", "init", "excel"]} + rightClassName="ml-auto mr-6 flex items-center space-x-1" + leftClassName="flex gap-5 w-9/12 m-4" + leftSelectClassName="w-1/4" + rightChildren={<></>} + leftChildren={ + <div className="col-span-3 flex items-center"> + <SelectBox + className="w-48 h-full text-2xl" + label="연도" + selectClass={"w-full "} + selectArray={yearOptions} + value={searchYear} + onSelectValue={(val: string | number) => + setSearchYear(String(val)) + } + /> + <Label className="w-full mt-2 ml-4 text-xl text-gray-600"> + {"하수처리시설명"} + </Label> + <SearchInput + className={"text-2xl w-full"} + label="" + textValue={pbnRuseNm || ""} + setText={(e) => { + setPbnRuseNm(e || ""); + }} + /> + </div> + } + queryClick={() => { + setIsReset(true); + }} + initClick={function (): void { + setPbnRuseNm(""); + }} + btnClass={btnClass} + ref={ref} + isAdmin={false} + excelClick={function (returnType: ReturnType): void { + console.log("pbnstSttnSearch ", returnType); + }} + /> + </div> + <div className="col-span-6"> + {/* 높이 조정 */} + <UiTable + tableData={ruseTable || []} + headlist={ruseMapHeadList} + pageSize={ruseMapSize} + total={ruseMapCount || 0} + headName={""} + cellClick={ruseCellClick} + onPageChange={(page) => { + ruseMapInit(page,ruseMapSize , ref.current, searchYear, fclts); + setIsReset(false); + }} + resetPageNo={isReset} + /> + </div> + </div> + </ContentsDiv> + </> + ); +} diff --git a/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx b/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx index 1a16c1fef..4212032f0 100644 --- a/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx +++ b/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx @@ -1,4 +1,4 @@ -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; +import { headMakeprfmnc } from "@/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common/type/header"; import { diff --git a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx index 7522fdbfd..4ff4ab14e 100644 --- a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx @@ -1,5 +1,5 @@ "use client"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; +import { headMakeprfmnc } from "@/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index 6f3a46b34..6fc2c0632 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -1,5 +1,5 @@ "use client"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; +import { headMakeprfmnc } from "@/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common/type/header"; import { rainPageSize, type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index 2bb3a645f..aa74ad2c2 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -1,5 +1,5 @@ "use client"; -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; +import { headMakeprfmnc } from "@/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; diff --git a/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx b/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx index 07e7c1e8d..2e056a401 100644 --- a/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx +++ b/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx @@ -1,4 +1,4 @@ -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; +import { headMakeprfmnc } from "@/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; diff --git a/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx b/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx index b13160e8b..18c065ee2 100644 --- a/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx +++ b/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx @@ -1,4 +1,4 @@ -import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; +import { headMakeprfmnc } from "@/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; From bb6bba4497ba3e58bfcd3e356aae169d373d08b9 Mon Sep 17 00:00:00 2001 From: leedj312 <dlehd467@gmail.com> Date: Wed, 6 Aug 2025 09:36:13 +0900 Subject: [PATCH 5/7] =?UTF-8?q?=EB=AC=BC=EC=9E=AC=EC=9D=B4=EC=9A=A9=20?= =?UTF-8?q?=EB=A7=B5=20=EC=8B=9C=EC=84=A4=20=ED=98=84=ED=99=A9=20=ED=8C=9D?= =?UTF-8?q?=EC=97=85=20=EA=B2=80=EC=83=89=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/store/map/htdflMap/index.tsx | 26 +++ apps/wr/app/store/map/rainMap/index.tsx | 26 +++ apps/wr/app/store/map/rswtMap/index.tsx | 27 +++ .../LayerPopUp/HedfFacilty/HtdfFacilty.tsx | 176 ++++++++++++++---- .../LayerPopUp/RainFacility/RainFacility.tsx | 126 ++++++++++++- .../LayerPopUp/RswtFacilty/RswtFacilty.tsx | 157 +++++++++++++--- 6 files changed, 463 insertions(+), 75 deletions(-) diff --git a/apps/wr/app/store/map/htdflMap/index.tsx b/apps/wr/app/store/map/htdflMap/index.tsx index 8b6f4513b..97f936ef8 100644 --- a/apps/wr/app/store/map/htdflMap/index.tsx +++ b/apps/wr/app/store/map/htdflMap/index.tsx @@ -16,6 +16,7 @@ export type htdfMapState = { type htdfMapActions = { htdfMapInit: (page: number, total: number, cityOrSgg: string) => void; + htdfMapSearch: (page: number, total: number, cityOrSgg:string, searchTxt?:string) =>void }; export type htdfMapType = htdfMapState & htdfMapActions; @@ -59,5 +60,30 @@ export const htdfMapActionsExport: (set: any) => htdfMapActions = ( console.log(e); } }, + htdfMapSearch: async (page: number, total: number, cityOrSgg:string, searchTxt?:string) => { + try { + const htdfMapRes = await getFetchWithCount( + fetchType.WR, + `/drain/facilityList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + + (searchTxt ? `/${searchTxt}` : "") + ); + + set((state: htdfMapState) => { + return { + ...state, + htdfMap: { + ...state.htdfMap, + htdfMapRes: htdfMapRes.data, + htdfMapCount: htdfMapRes.count, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, }; }; diff --git a/apps/wr/app/store/map/rainMap/index.tsx b/apps/wr/app/store/map/rainMap/index.tsx index 93b6bf9a4..9ddca1f91 100644 --- a/apps/wr/app/store/map/rainMap/index.tsx +++ b/apps/wr/app/store/map/rainMap/index.tsx @@ -20,6 +20,7 @@ export type rainMapState = { type rainMapActions = { rainMapInit: (page: number, total: number, cityOrSgg:string) => void; + rainMapSearch: (page: number, total: number, cityOrSgg:string, searchTxt?:string) =>void }; export type rainMapType = rainMapState & rainMapActions; @@ -63,5 +64,30 @@ export const rainMapActionsExport: (set: any) => rainMapActions = ( console.log(e); } }, + rainMapSearch: async (page: number, total: number, cityOrSgg:string, searchTxt?:string) => { + try { + const rainMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/rainyInfoList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + + (searchTxt ? `/${searchTxt}` : "") + ); + + set((state: rainMapState) => { + return { + ...state, + rainMap: { + ...state.rainMap, + rainMapRes: rainMapRes.data, + rainMapCount: rainMapRes.count, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, }; }; diff --git a/apps/wr/app/store/map/rswtMap/index.tsx b/apps/wr/app/store/map/rswtMap/index.tsx index b7b2f0651..c55cdc983 100644 --- a/apps/wr/app/store/map/rswtMap/index.tsx +++ b/apps/wr/app/store/map/rswtMap/index.tsx @@ -17,6 +17,7 @@ export type rswtMapState = { type rswtMapActions = { rswtMapInit: (page: number, total: number, cityOrSgg:string) => void; + rswtMapSearch: (page: number, total: number, cityOrSgg:string, searchTxt?:string) => void }; export type rswtMapType = rswtMapState & rswtMapActions; @@ -60,5 +61,31 @@ export const rswtMapActionsExport: (set: any) => rswtMapActions = ( console.log(e); } }, + rswtMapSearch: async (page: number, total: number, cityOrSgg:string, searchTxt?:string) => { + try { + const rswtMapRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/waterreuseFc` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + + (searchTxt ? `/${searchTxt}` : "") + ); + + set((state: rswtMapState) => { + return { + ...state, + rswtMap: { + ...state.rswtMap, + rswtMapRes: rswtMapRes.data, + rswtMapCount: rswtMapRes.count, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + }; }; diff --git a/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx b/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx index bca9128e1..05589e38a 100644 --- a/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx +++ b/apps/wr/components/ui/map/LayerPopUp/HedfFacilty/HtdfFacilty.tsx @@ -1,26 +1,69 @@ import { useWrStore } from "@/app/store"; import { rainMapSize } from "@/app/store/map/rainMap"; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -import { tableData } from "@/components/lib/func/commom"; -import { Title, UiTable } from "@common/business_components/ui"; +import { getCity, tableData } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { + ContentsDiv, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, + Title, + UiTable, + type SelectDataType, +} from "@common/business_components/ui"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; +import { Button } from "@common/components/ui"; +import { useCallback, useEffect, useState } from "react"; export function HtdflFacility({ - rtnFeature, - }: { - rtnFeature: (feature: any) => void; - }) { - const { code, htdfMap, htdfMapInit } = useWrStore((state) => state); + rtnFeature, +}: { + rtnFeature: (feature: any) => void; +}) { + const { code, htdfMap, htdfMapInit,htdfMapSearch } = useWrStore((state) => state); const { htdfMapCount, htdfMapRes, htdfSttHeadList, htdfSttNodeList } = htdfMap; const [htdflTable, setHtdflTable] = useState<customHtdflBdst[]>(); const [isReset, setIsReset] = useState(false); + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + + const [seartchTxt, setSearchTxt] = useState<string>(); + + const getSelCity = useCallback( + (val: string | number) => { + const cityValue = String(val); + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + setObjSearch({ city: cityValue, sgg: "0" }); + }, + [code.sggCd] + ); + + const getSgg = useCallback((val: string | number) => { + setObjSearch((prev) => ({ ...prev, sgg: String(val) })); + }, []); + + useEffect(() => { + // code.cityCd 데이터가 로드되었고, 아직 시/도 선택이 안된 초기 상태일 때 실행 + if (code.cityCd && code.cityCd.length > 0 && !objSearch.city) { + const firstCityVal = code.cityCd[0]?.val; + if (firstCityVal) { + // 첫 번째 시/도 값으로 상태를 초기화합니다. + getSelCity(firstCityVal); + } + } + }, [code.cityCd, objSearch.city, getSelCity]); const htdflCellClick = (index: number | undefined) => { if (index !== undefined && htdflTable !== undefined) { - rtnFeature(htdflTable[index]); - + rtnFeature(htdflTable[index]); } }; @@ -45,33 +88,94 @@ export function HtdflFacility({ return ( <> - <div style={{ overflowY: "auto" }}> - <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> */} + <ContentsDiv> + <div className="grid grid-cols-4 gap-4 "> + <div className="col-span-4"> + <Title title="온배수시설 현황" /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd || []} + onSelectValue={(val) => { + getSelCity(val); + }} + value={objSearch.city} + /> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + onSelectValue={getSgg} + value={objSearch.sgg} + /> + <SearchInput + className={"!text-3xl ml-4"} + label="회사명" + textValue={seartchTxt ?? ""} + setText={(e) => { + setSearchTxt(e); + }} + /> + </div> + </SearchFormLeft> + <SearchFormRight className="w-3/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2"> + <Button + className="mt-2" + size={"sm"} + onClick={() => { + setIsReset(true); + }} + > + 조회 + </Button> + </div> + </SearchFormRight> + </SearchDiv> + </div> </div> - <UiTable - headName={[]} - tableData={htdflTable || []} - headlist={htdfSttHeadList} - pageSize={rainMapSize} - total={htdfMapCount} - cellClick={(index: number | undefined) => { - htdflCellClick(index ?? undefined); - }} - onPageChange={(page) => { - htdfMapInit(page, rainMapSize, "0"); - setIsReset(false); - }} - resetPageNo={isReset} - > - <HeadMakeColSpan upHeadList={htdfSttNodeList} /> - </UiTable> - </div> + <div className="grid grid-cols-2 gap-4 "> + <div className="col-span-2"> + <UiTable + headName={[]} + tableData={htdflTable || []} + headlist={htdfSttHeadList} + pageSize={rainMapSize} + total={htdfMapCount} + cellClick={(index: number | undefined) => { + htdflCellClick(index ?? undefined); + }} + onPageChange={(page) => { + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + if (con) { + if (seartchTxt && seartchTxt?.length > 0) { + htdfMapSearch( + page, + rainMapSize, + String(con), + seartchTxt ?? "" + ); + } else { + htdfMapSearch(page, rainMapSize, String(con)); + } + setIsReset(false); + } + }} + resetPageNo={isReset} + > + <HeadMakeColSpan upHeadList={htdfSttNodeList} /> + </UiTable> + </div> + </div> + </ContentsDiv> </> ); } diff --git a/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx b/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx index 348cf6b9e..e1a917e8f 100644 --- a/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx +++ b/apps/wr/components/ui/map/LayerPopUp/RainFacility/RainFacility.tsx @@ -1,24 +1,71 @@ import { useWrStore } from "@/app/store"; import { rainMapSize } from "@/app/store/map/rainMap"; import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { tableData } from "@/components/lib/func/commom"; -import { ContentsDiv, Title, UiTable } from "@common/business_components/ui"; +import { getCity, tableData } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { + ContentsDiv, + SearchDiv, + SearchFormLeft, + SearchFormRight, + SearchInput, + SelectBox, + Title, + UiTable, + type SelectDataType, +} from "@common/business_components/ui"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; +import { Button } from "@common/components/ui"; +import { useCallback, useEffect, useState } from "react"; export function RainFacility({ rtnFeature, }: { rtnFeature: (feature: any) => void; }) { - const { code, rainMap, rainMapInit } = useWrStore((state) => state); + const { code, rainMap, rainMapInit, rainMapSearch } = useWrStore( + (state) => state + ); const { rainMapRes, rainMapCount, rainSttHeadList, rainSttNodeList } = rainMap; const [rainTable, setRainTable] = useState<customRainBdst[]>(); const [isReset, setIsReset] = useState(false); + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + + const [seartchTxt, setSearchTxt] = useState<string>(); + + const getSelCity = useCallback( + (val: string | number) => { + const cityValue = String(val); + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + setObjSearch({ city: cityValue, sgg: "0" }); + }, + [code.sggCd] + ); + + const getSgg = useCallback((val: string | number) => { + setObjSearch((prev) => ({ ...prev, sgg: String(val) })); + }, []); + + useEffect(() => { + // code.cityCd 데이터가 로드되었고, 아직 시/도 선택이 안된 초기 상태일 때 실행 + if (code.cityCd && code.cityCd.length > 0 && !objSearch.city) { + const firstCityVal = code.cityCd[0]?.val; + if (firstCityVal) { + // 첫 번째 시/도 값으로 상태를 초기화합니다. + getSelCity(firstCityVal); + } + } + }, [code.cityCd, objSearch.city, getSelCity]); useEffect(() => { if (!rainMap.isInit) { + console.log(" init "); rainMapInit(1, rainMapSize, "0"); } }, [rainMapInit, rainMap.isInit]); @@ -34,7 +81,6 @@ export function RainFacility({ }; useEffect(() => { - const data = tableData(rainMapRes, { code }); const chData = data .map((item: any) => { @@ -74,9 +120,58 @@ export function RainFacility({ return ( <> <ContentsDiv> + <div className="grid grid-cols-4 gap-4 "> + <div className="col-span-4"> + <Title title="빗물이용시설 현황" /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd || []} + onSelectValue={(val) => { + getSelCity(val); + }} + value={objSearch.city} + /> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + onSelectValue={getSgg} + value={objSearch.sgg} + /> + <SearchInput + className={"!text-3xl ml-4"} + label="회사명" + textValue={seartchTxt ?? ""} + setText={(e) => { + setSearchTxt(e); + }} + /> + </div> + </SearchFormLeft> + <SearchFormRight className="w-3/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2"> + <Button + className="mt-2" + size={"sm"} + onClick={() => { + setIsReset(true); + }} + > + 조회 + </Button> + </div> + </SearchFormRight> + </SearchDiv> + </div> + </div> <div className="grid grid-cols-2 gap-4 "> <div className="col-span-2"> - <Title title="빗물이용시설 현황" /> <UiTable headName={[]} tableData={rainTable || []} @@ -87,8 +182,23 @@ export function RainFacility({ rainCellClick(index ?? undefined, headId); }} onPageChange={(page) => { - rainMapInit(page, rainMapSize, "0"); - setIsReset(false); + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + if (con) { + if (seartchTxt && seartchTxt?.length > 0) { + rainMapSearch( + page, + rainMapSize, + String(con), + seartchTxt ?? "" + ); + } else { + rainMapSearch(page, rainMapSize, String(con)); + } + setIsReset(false); + } }} resetPageNo={isReset} > diff --git a/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx b/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx index 64d558b44..18a2b2c1d 100644 --- a/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx +++ b/apps/wr/components/ui/map/LayerPopUp/RswtFacilty/RswtFacilty.tsx @@ -1,22 +1,57 @@ import { useWrStore } from "@/app/store"; import { rainMapSize } from "@/app/store/map/rainMap"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import { tableData } from "@/components/lib/func/commom"; -import { Title, UiTable } from "@common/business_components/ui"; +import { getCity, tableData } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import { ContentsDiv, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, SelectBox, Title, UiTable, type SelectDataType } from "@common/business_components/ui"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; +import { Button } from "@common/components/ui"; +import { useCallback, useEffect, useState } from "react"; export function RswtFacility({ rtnFeature, }: { rtnFeature: (feature: any) => void; }) { - const { code, rswtMap, rswtMapInit } = useWrStore((state) => state); + const { code, rswtMap, rswtMapInit,rswtMapSearch } = useWrStore((state) => state); const { rswtMapRes, rswtMapCount, rswtSttHeadList, rswtSttNodeList } = - rswtMap; + rswtMap; const [rswtrTable, setRswtrTable] = useState<customRswtBdst[]>(); const [isReset, setIsReset] = useState(false); + + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + + const [seartchTxt, setSearchTxt] = useState<string>(); + + const getSelCity = useCallback( + (val: string | number) => { + const cityValue = String(val); + const data = getCity(cityValue, code.sggCd); + setSelectSgg(data); + setObjSearch({ city: cityValue, sgg: "0" }); + }, + [code.sggCd] + ); + + const getSgg = useCallback((val: string | number) => { + setObjSearch((prev) => ({ ...prev, sgg: String(val) })); + }, []); + + useEffect(() => { + // code.cityCd 데이터가 로드되었고, 아직 시/도 선택이 안된 초기 상태일 때 실행 + if (code.cityCd && code.cityCd.length > 0 && !objSearch.city) { + const firstCityVal = code.cityCd[0]?.val; + if (firstCityVal) { + // 첫 번째 시/도 값으로 상태를 초기화합니다. + getSelCity(firstCityVal); + } + } + }, [code.cityCd, objSearch.city, getSelCity]); const rswtCellClick = (index: number | undefined, headId: string) => { if ( headId !== "chBuildingYn" && @@ -67,33 +102,93 @@ export function RswtFacility({ }, [code, rswtMapRes]); return ( <> - <div style={{ overflowY: "auto" }}> - <div className="flex justify-between items-center"> - <Title title="중수도시설 현황" /> - {/* <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={rswtSttnExcelDownload}> - 엑셀다운로드 - </Button> - </div> */} + <ContentsDiv> + <div className="grid grid-cols-4 gap-4 "> + <div className="col-span-4"> + <Title title="중수도이용시설 현황" /> + <SearchDiv> + <SearchFormLeft> + <div className="col-span-10 flex flex-row"> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl" + label="시도" + selectClass={""} + selectArray={code.cityCd || []} + onSelectValue={(val) => { + getSelCity(val); + }} + value={objSearch.city} + /> + <SelectBox + className="col-span-3 w-1/6 h-full text-2xl ml-4" + label="시군구" + selectClass={""} + selectArray={selectSgg || []} + onSelectValue={getSgg} + value={objSearch.sgg} + /> + <SearchInput + className={"!text-3xl ml-4"} + label="회사명" + textValue={seartchTxt ?? ""} + setText={(e) => { + setSearchTxt(e); + }} + /> + </div> + </SearchFormLeft> + <SearchFormRight className="w-3/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <div className="flex flex-row space-x-2"> + <Button + className="mt-2" + size={"sm"} + onClick={() => { + setIsReset(true); + }} + > + 조회 + </Button> + </div> + </SearchFormRight> + </SearchDiv> + </div> </div> - <UiTable - headName={[]} - tableData={rswtrTable || []} - headlist={rswtSttHeadList} - pageSize={20} - total={rswtMapCount} - cellClick={(index: number | undefined, headId: string) => { - rswtCellClick(index, headId); - }} - onPageChange={(page) => { - rswtMapInit(page, rainMapSize, "0"); - setIsReset(false); - }} - resetPageNo={isReset} - > - <HeadMakeColSpan upHeadList={rswtSttNodeList} /> - </UiTable> - </div> + <div className="grid grid-cols-2 gap-4 "> + <div className="col-span-2"> + <UiTable + headName={[]} + tableData={rswtrTable || []} + headlist={rswtSttHeadList} + pageSize={20} + total={rswtMapCount} + cellClick={(index: number | undefined, headId: string) => { + rswtCellClick(index, headId); + }} + onPageChange={(page) => { + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + if (con) { + if (seartchTxt && seartchTxt?.length > 0) { + rswtMapSearch( + page, + rainMapSize, + String(con), + seartchTxt ?? "" + ); + } else { + rswtMapSearch(page, rainMapSize, String(con)); + } + setIsReset(false); + }}} + resetPageNo={isReset} + > + <HeadMakeColSpan upHeadList={rswtSttNodeList} /> + </UiTable> + </div> + </div> + </ContentsDiv> </> ); } From 7ea388b30a2785d54891d0088dcdca2fdce7720c Mon Sep 17 00:00:00 2001 From: leedj312 <dlehd467@gmail.com> Date: Wed, 6 Aug 2025 17:57:22 +0900 Subject: [PATCH 6/7] =?UTF-8?q?=EC=A7=80=EB=8F=84=20=ED=98=84=EC=9E=AC=20?= =?UTF-8?q?=EB=A7=8C=EB=93=A4=EC=96=B4=EC=A7=84=EA=B2=83=EA=B9=8C=EC=A7=80?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EC=99=84=EB=A3=8C=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=EB=A1=9C=20=EB=A7=8C=EB=93=A4=EA=B2=83=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=ED=95=B4=EC=84=9C=20=ED=95=B4=EC=95=BC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(popUp-layout)/mapFeaturePopup/page.tsx | 121 ++++++++++++ .../wr/app/(with-layout)/map/mainMap/page.tsx | 152 ++++++++++----- apps/wr/app/store/map/htdflMap/index.tsx | 76 +++++--- apps/wr/app/store/map/pbnstMap/index.tsx | 178 ++++++++++-------- apps/wr/app/store/map/rainMap/index.tsx | 23 ++- apps/wr/app/store/map/rswtMap/index.tsx | 59 ++++-- apps/wr/app/store/map/ruseMap/index.tsx | 17 ++ "apps/wr/components/lib/func/\bmapUtil.ts" | 19 ++ 8 files changed, 474 insertions(+), 171 deletions(-) create mode 100644 apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx create mode 100644 "apps/wr/components/lib/func/\bmapUtil.ts" diff --git a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx new file mode 100644 index 000000000..9e7c1296e --- /dev/null +++ b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx @@ -0,0 +1,121 @@ +"use client"; +import { useWrStore } from "@/app/store"; +import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; +import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; +import { Title, UiTable } from "@common/business_components/ui"; +import { useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; + +export default function MapFeaturePopup() { + const [isFeatureCd, setIsFeatureCd] = useState<any>(null); + const { + pbnMap, + ruseMapDetail, + rainMapDetile, + rswtMapDetile, + htdfMapDetile, + pbnMapDetaile, + } = useWrStore((state) => state); + const { pbnMapHeadList } = pbnMap; + const [isDetail, setIsDetail] = useState<any>(null); + const [layerNm, setLayerNm] = useState<string>(); + const searchParams = useSearchParams(); + + useEffect(() => { + const layerName = searchParams.get("layerNm"); + const featureCd = searchParams.get("featureCd"); + setLayerNm(String(layerName)); + setIsFeatureCd(featureCd); + + const handleUnload = () => { + // 부모에게 닫힘 알림 + window.opener?.postMessage( + { type: "POPUP_CLOSED", target: "detail" }, + "*" + ); + }; + + window.addEventListener("beforeunload", handleUnload); + + return () => { + window.removeEventListener("beforeunload", handleUnload); + }; + }, []); + + useEffect(() => { + if (isFeatureCd && layerNm) { + let detail = {}; + if (layerNm === "하수재이용시설") { + detail = ruseMapDetail(isFeatureCd); + setIsDetail(detail); + } else if (layerNm === "하수처리시설") { + pbnMapDetaile(isFeatureCd, isFeatureCd).then((res) => { + setIsDetail(res); + }); + } else if (layerNm === "빗물이용시설") { + rainMapDetile(isFeatureCd).then((res) => { + setIsDetail(res); + }); + } else if (layerNm === "중수도시설") { + rswtMapDetile(isFeatureCd).then((res) => { + setIsDetail(res); + }); + } else if (layerNm === "온배수시설") { + htdfMapDetile(isFeatureCd).then((res) => { + setIsDetail(res); + }); + } + } + }, [isFeatureCd, layerNm]); + + if (!isDetail) return null; // 데이터 없으면 아무것도 안 그림 + return ( + <> + {isDetail ? ( + <div className="fixed inset-0 w-screen h-screen m-0 p-0 overflow-auto bg-white"> + {layerNm === "하수재이용시설" ? ( + <PbnstSttnModal data={isDetail} /> + ) : layerNm === "하수처리시설" ? ( + <div style={{ overflowX: "hidden" }}> + <div className="flex justify-between items-center mb-4"> + <Title title="하수처리시설 상세정보" /> + </div> + {/* 높이 조정 */} + <UiTable + tableData={isDetail || []} + headlist={pbnMapHeadList.slice(0, 4)} + pageSize={1} + total={0} + headName={"위치정보"} + cellClick={() => {}} + onPageChange={() => {}} + /> + <UiTable + tableData={isDetail || []} + headlist={pbnMapHeadList.slice(4)} + pageSize={1} + total={0} + headName={"기본정보"} + cellClick={() => {}} + onPageChange={() => {}} + /> + </div> + ) : ( + <SttnDetailModal + type={ + layerNm === "빗물이용시설" + ? "RNB" + : layerNm === "중수도시설" + ? "RST" + : "HTB" + } + formObj={isDetail} + /> + )} + </div> + ) : ( + <></> + )} + </> + ); +} diff --git a/apps/wr/app/(with-layout)/map/mainMap/page.tsx b/apps/wr/app/(with-layout)/map/mainMap/page.tsx index dedcca225..3b6eaa512 100644 --- a/apps/wr/app/(with-layout)/map/mainMap/page.tsx +++ b/apps/wr/app/(with-layout)/map/mainMap/page.tsx @@ -5,11 +5,11 @@ import { useEffect, useRef, useState, useCallback } from "react"; import { mapService } from "../service"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; import { useWrStore } from "@/app/store"; +import { getFeatureCd } from "@/components/lib/func/\bmapUtil"; const Map = () => { - - const { comMap } = useWrStore((state) => state); - const {isFeatured} = comMap + const { comMap } = useWrStore((state) => state); + const { isFeatured } = comMap; const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 const gisMaps = useRef<any | null>(null); const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 @@ -18,6 +18,7 @@ const Map = () => { const [checkedLayers, setCheckedLayers] = useState<string[]>([]); const [checkedLayersData, setCheckedLayersData] = useState<any[]>([]); const popupRef = useRef<Window | null>(null); + const popupDetailRef = useRef<Window | null>(null); const fetchData = async () => { try { @@ -43,20 +44,41 @@ const Map = () => { const bc = new BroadcastChannel("mapDetailPopUp"); bc.onmessage = (event) => { if (event.data.type === "SELECT_FEATURE") { - console.log('event.data.feature ', event.data.feature) onFeatureSelect(event.data.feature); - closePopup() + closePopup(); } }; }, []); - useEffect(() =>{ - console.log('isFeatured ', isFeatured) - if(isFeatured){ - console.log('isFeatured ', isFeatured) - onFeatureSelect(isFeatured) + useEffect(() => { + const messageHandler = (event: MessageEvent) => { + if (event.data.type === "POPUP_CLOSED") { + if (event.data.target === "detail") { + console.log("디테일 팝업 닫힘 감지됨"); + setFeatureData(null); + setIsOpen(false); + setIsSearchModalOpen(true); + popupDetailRef.current = null; + } else { + console.log("기타 팝업 닫힘 감지됨"); + popupRef.current = null; + } + } + }; + window.addEventListener("message", messageHandler); + return () => { + window.removeEventListener("message", messageHandler); + }; + }, []); + + useEffect(() => { + console.log("isFeatured ", isFeatured); + + if (isFeatured) { + console.log("isFeatured ", isFeatured); + onFeatureSelect(isFeatured); } - },[isFeatured]) + }, [isFeatured]); // 체크된 레이어 정보를 받는 핸들러 const handleCheckedLayersChange = ( @@ -67,8 +89,6 @@ const Map = () => { setCheckedLayersData(checkedNodesData); }; - - // SearchModal, GisContent 등에서 호출 const onFeatureSelect = (data: any) => { const map = gisMaps.current; @@ -92,16 +112,20 @@ const Map = () => { if (layerName === "하수재이용시설") { // 재이용시설 featureId = `${layerName}.${data.searchPk}`; - } else if ( //빗물이용시설, 중수도시설 + } else if ( + //빗물이용시설, 중수도시설 layerName === "빗물이용시설" || layerName == "중수도시설" ) { featureId = `${layerName}.${data.bdstInfoSn}`; - } else if (layerName === "하수처리시설") { //하수처리시설 + } else if (layerName === "하수처리시설") { + //하수처리시설 featureId = `${layerName}.${data.bscFctCd}`; - } else if (layerName === "온배수시설") { //온배수시설 + } else if (layerName === "온배수시설") { + //온배수시설 featureId = `${layerName}.${data.bdstRuseFcltSn}`; - } else if (layerName == "수요처") { //수요처 + } else if (layerName == "수요처") { + //수요처 featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`; } else { console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName); @@ -144,49 +168,79 @@ const Map = () => { setIsSearchModalOpen(false); }; - // MapSearchBar 래퍼 컴포넌트 - // const CustomMapSearchBar = (props: any) => { - // return ( - // <MapSearchBar - // {...props} - // searchType="공급처 후보지 조회" - // showApplyButton={false} - // /> - // ); - // }; + + const getSelectedLayers = (isFeature: any) => { + const map = gisMaps.current; + if (!map) { + console.warn("지도가 초기화되지 않았습니다."); + return; + } + let result = null; + const layers = map + ? map + .getLayers() + .getArray() + .filter((l: any) => l.getVisible()) + : []; // gisMap이 null인지 확인 후 레이어 가져오기 + let featureLayer: { get: (key: string) => any } = { get: () => null }; + layers.forEach((layer: any) => { + const source = layer.getSource(); + if ( + source && + source.hasFeature && + isFeature && + typeof isFeature.getId === "function" && + source.hasFeature(isFeature) + ) { + featureLayer = layer; // 피처가 속한 레이어 찾기) + } + }); + result = featureLayer.get("lyrNm"); + return result; + }; const renderDetailView = useCallback( (props: any) => { - console.log('props ', props.seletectedLayerNm) - const url = `/mapDetilePopUp?layerNm=${encodeURIComponent(props.seletectedLayerNm)}`; - const width = window.screen.availWidth; - const height = window.screen.availHeight; - const left = 0; - const top = 0; - const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`; - popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions); - // return( - // <NewWindowPopup - // key={featureData?.fid || featureData?.id || featureData?.ftrIdn} - // onClose={handlePopupClose} - // checkedLayers={checkedLayers} - // checkedLayersData={checkedLayersData} - // {...props} - // /> - // ) - } - , - [checkedLayers, checkedLayersData] // 필요 시 의존성 넣기 - + const isFeature = props.featureData.getProperties(); + if ( + Object.keys(isFeature).length === 0 && + isFeature.constructor === Object + ) { + const url = `/mapDetilePopUp?layerNm=${encodeURIComponent(props.seletectedLayerNm)}`; + const width = window.screen.availWidth; + const height = window.screen.availHeight; + const left = 0; + const top = 0; + const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`; + popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions); + } else { + const layerNm = getSelectedLayers(featureData); + const safeProps = featureData.getProperties(); + const featureCd = getFeatureCd(safeProps, String(layerNm)); + const url = `/mapFeaturePopup?layerNm=${encodeURIComponent(String(layerNm))}&featureCd=${encodeURIComponent(featureCd)} `; + const width = Math.floor(window.innerWidth * 0.4); // 화면 폭의 40% + const height = Math.floor(window.innerHeight - 450); // 150px 여백 확보; // calc(100% - 70px) + const left = (window.screen.availWidth - width) / 2; + const top = (window.screen.availHeight - height) / 2; + const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`; + popupDetailRef.current = window.open( + url, + "지도 시설 상세정보 팝업", + popupOptions + ); + } + }, + [checkedLayers, checkedLayersData, featureData] // 필요 시 의존성 넣기 ); const closePopup = () => { if (popupRef.current && !popupRef.current.closed) { popupRef.current.close(); popupRef.current = null; setIsOpen(false); - setFeatureData(null); + setFeatureData(null); } }; + return ( <div className="bg-container"> <Gis diff --git a/apps/wr/app/store/map/htdflMap/index.tsx b/apps/wr/app/store/map/htdflMap/index.tsx index 97f936ef8..03289a06d 100644 --- a/apps/wr/app/store/map/htdflMap/index.tsx +++ b/apps/wr/app/store/map/htdflMap/index.tsx @@ -1,4 +1,4 @@ -import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; import type { customHtdflBdst } from "../../ruseFcltMng/fcltReg/htdflReg"; import { htdflSttHeadListExport, htdflSttNodeListExport } from "../../ruseFcltMng/fcltSttn/htdflSttn/headList"; @@ -17,6 +17,8 @@ export type htdfMapState = { type htdfMapActions = { htdfMapInit: (page: number, total: number, cityOrSgg: string) => void; htdfMapSearch: (page: number, total: number, cityOrSgg:string, searchTxt?:string) =>void + htdfMapDetile:(featureCd:string) => Promise<customHtdflBdst | undefined>; + }; export type htdfMapType = htdfMapState & htdfMapActions; @@ -60,30 +62,52 @@ export const htdfMapActionsExport: (set: any) => htdfMapActions = ( console.log(e); } }, - htdfMapSearch: async (page: number, total: number, cityOrSgg:string, searchTxt?:string) => { - try { - const htdfMapRes = await getFetchWithCount( - fetchType.WR, - `/drain/facilityList` + - (page ? `/${page}` : "/1") + - (total ? `/${total}` : "/20") + - (cityOrSgg ? `/${cityOrSgg}` : "/0") + - (searchTxt ? `/${searchTxt}` : "") - ); - - set((state: htdfMapState) => { - return { - ...state, - htdfMap: { - ...state.htdfMap, - htdfMapRes: htdfMapRes.data, - htdfMapCount: htdfMapRes.count, - }, - }; - }); - } catch (e) { - console.log(e); - } - }, + htdfMapSearch: async ( + page: number, + total: number, + cityOrSgg: string, + searchTxt?: string + ) => { + try { + const htdfMapRes = await getFetchWithCount( + fetchType.WR, + `/drain/facilityList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + + (searchTxt ? `/${searchTxt}` : "") + ); + + set((state: htdfMapState) => { + return { + ...state, + htdfMap: { + ...state.htdfMap, + htdfMapRes: htdfMapRes.data, + htdfMapCount: htdfMapRes.count, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + htdfMapDetile: async (featureCd: string) => { + try { + const htdfDetail = await getFetch( + fetchType.WR, + `/drain/facilityList/1/3/0/${featureCd}` + ); + + if (htdfDetail && htdfDetail.length > 0) { + return htdfDetail[0]; + } else { + return null; + } + } catch (error) { + console.log(error); + throw error; // 호출부에서 catch 가능하도록 + } + }, }; }; diff --git a/apps/wr/app/store/map/pbnstMap/index.tsx b/apps/wr/app/store/map/pbnstMap/index.tsx index e2789d744..c093431ff 100644 --- a/apps/wr/app/store/map/pbnstMap/index.tsx +++ b/apps/wr/app/store/map/pbnstMap/index.tsx @@ -1,50 +1,48 @@ -import { fetchType, postFectch } from "@/components/lib/api"; +import { fetchType, postFectch } from "@/components/lib/api"; import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; import { checkWrRegList } from "../../ruseFcltMng/fcltReg/pbnstReg"; import type { ReturnType } from "@common/business_components/ui"; import { pubFacHeadListExport } from "../../ruseFcltMng/fcltReg/pbnstReg/headList"; import type { TableUpperProps } from "../../common/type/header"; +export const pbnMapTableSize = 20; -export const pbnMapTableSize =20; +const hasuListFetch = async ( + page: number, + pageTotal: number, + reurnValue: ReturnType, + searchNm?: string +) => { + let url = `/prcsFclt/ruseInfo/${page}/${pageTotal}/`; + const checkWrRegListRes = await checkWrRegList(); -const hasuListFetch = async (page: number, pageTotal:number, reurnValue: ReturnType, searchNm?:string) => { - - let url = `/prcsFclt/ruseInfo/${page}/${pageTotal}/`; - const checkWrRegListRes = await checkWrRegList(); - - if (reurnValue.partValue === "A") { - url += `${reurnValue.partValue}/${ - // reurnValue.sidoValue ? reurnValue.sidoValue : reurnValue.sigunValue - reurnValue.sigunValue !== '0' ? reurnValue.sigunValue : reurnValue.sidoValue - }/0/1/SW` - - - } else if (reurnValue.partValue === "R") { - url += `${reurnValue.partValue}/${reurnValue.regionValue + if (reurnValue.partValue === "A") { + url += `${reurnValue.partValue}/${ + // reurnValue.sidoValue ? reurnValue.sidoValue : reurnValue.sigunValue + reurnValue.sigunValue !== "0" + ? reurnValue.sigunValue + : reurnValue.sidoValue + }/0/1/SW`; + } else if (reurnValue.partValue === "R") { + url += `${reurnValue.partValue}/${ + reurnValue.regionValue ? reurnValue.regionValue : reurnValue.unitWaterShedValue ? reurnValue.unitWaterShedValue : reurnValue.middleRegionValue - }/0/1/SW` - } else if (reurnValue.partValue === 'G') { - url += `${reurnValue.envPartValue}/${reurnValue.sigunValue !== '0' ? reurnValue.sigunValue : reurnValue.sidoValue}/0/1/SW` - } else { - url += `A/0/0/1/SW` - } - if (searchNm && searchNm?.length > 0) { - url += "/" + searchNm - } - + }/0/1/SW`; + } else if (reurnValue.partValue === "G") { + url += `${reurnValue.envPartValue}/${reurnValue.sigunValue !== "0" ? reurnValue.sigunValue : reurnValue.sidoValue}/0/1/SW`; + } else { + url += `A/0/0/1/SW`; + } + if (searchNm && searchNm?.length > 0) { + url += "/" + searchNm; + } + const data = checkWrRegListRes.filter((item: string) => item !== ""); -const data = checkWrRegListRes.filter((item:string) => item !== "") - - const rainRes = await postFectch( - url, - data, - fetchType.COMMON - ); + const rainRes = await postFectch(url, data, fetchType.COMMON); const hasuList = rainRes.data.map((item: any) => { return { @@ -54,55 +52,77 @@ const data = checkWrRegListRes.filter((item:string) => item !== "") }; }); - return {data: hasuList, count:rainRes.count}; + return { data: hasuList, count: rainRes.count }; }; export type pbnMapState = { - pbnMap: { - isInit:boolean, - pbnMapRes:pubHasuType[] - pbnMapCount:number; - pbnMapHeadList:TableUpperProps[]; - }; + pbnMap: { + isInit: boolean; + pbnMapRes: pubHasuType[]; + pbnMapCount: number; + pbnMapHeadList: TableUpperProps[]; }; - - type pbnMapActions = { - pbnMapInit: (page: number, pageTotal:number, reurnValue: ReturnType) => void; - }; - - export type pbnMapType = pbnMapState & pbnMapActions; - - export const pbnMapStateExport: pbnMapState = { - pbnMap: { - isInit: false, - pbnMapRes:[], - pbnMapCount:1, - pbnMapHeadList:pubFacHeadListExport +}; + +type pbnMapActions = { + pbnMapInit: (page: number, pageTotal: number, reurnValue: ReturnType) => void; + pbnMapDetaile: (featureCd: string, data: string) => Promise<pubHasuType | undefined>; +}; + +export type pbnMapType = pbnMapState & pbnMapActions; + +export const pbnMapStateExport: pbnMapState = { + pbnMap: { + isInit: false, + pbnMapRes: [], + pbnMapCount: 1, + pbnMapHeadList: pubFacHeadListExport, + }, +}; + +export const pbnMapActionsExport: (set: any) => pbnMapActions = (set: any) => { + return { + pbnMapInit: async ( + page: number, + pageTotal: number, + reurnValue: ReturnType + ) => { + try { + const pubMapRes = await hasuListFetch(page, pageTotal, reurnValue); + set((state: pbnMapState) => { + return { + ...state, + pbnMap: { + ...state.pbnMap, + pbnMapRes: pubMapRes.data, + pbnMapCount: pubMapRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e); + } + }, + pbnMapDetaile: async (featureCd: string, data: string) => { + try { + const hasuRes = await postFectch( + `/prcsFclt/ruseInfo/1/20/A/0/0/1/SW/${featureCd}`, + [data], + fetchType.COMMON + ); + const filteredData = hasuRes.data.map((item: any) => { + return { + ...item, + fctCpc: Number(item.fctCpc) || 0, + ruse: item.ruse === false ? "N" : "Y", + }; + }); + return filteredData; + } catch (error) { + console.log(error); + throw error; // 호출부에서 catch 가능하도록 + } }, }; - - - export const pbnMapActionsExport: (set: any) => pbnMapActions = ( - set: any - ) => { - return { - pbnMapInit: async (page: number, pageTotal:number, reurnValue: ReturnType) => { - try { - const pubMapRes = await hasuListFetch(page,pageTotal,reurnValue) - set((state: pbnMapState) => { - return { - ...state, - pbnMap: { - ...state.pbnMap, - pbnMapRes: pubMapRes.data, - pbnMapCount: pubMapRes.count, - isInit: false, - }, - }; - }); - } catch (e) { - console.log(e) - } - }, - } - } \ No newline at end of file +}; diff --git a/apps/wr/app/store/map/rainMap/index.tsx b/apps/wr/app/store/map/rainMap/index.tsx index 9ddca1f91..a8d8ecb04 100644 --- a/apps/wr/app/store/map/rainMap/index.tsx +++ b/apps/wr/app/store/map/rainMap/index.tsx @@ -1,4 +1,4 @@ -import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; import { rainSttHeadListExport, @@ -21,6 +21,7 @@ export type rainMapState = { type rainMapActions = { rainMapInit: (page: number, total: number, cityOrSgg:string) => void; rainMapSearch: (page: number, total: number, cityOrSgg:string, searchTxt?:string) =>void + rainMapDetile:(featureCd:string) => Promise<customRainBdst | undefined>; }; export type rainMapType = rainMapState & rainMapActions; @@ -89,5 +90,23 @@ export const rainMapActionsExport: (set: any) => rainMapActions = ( console.log(e); } }, - }; + rainMapDetile: async (featureCd: string) => { + try { + console.log('featureCd ', featureCd) + + const rainDetail = await getFetch(fetchType.WR, + `/reuseFc/rainyInfoList/1/3/0/${featureCd}` ) + + if(rainDetail&&rainDetail.length>0){ + + return rainDetail[0]; + }else{ + return null; + } + } catch (error) { + console.log(error); + throw error; // 호출부에서 catch 가능하도록 + } + } +} }; diff --git a/apps/wr/app/store/map/rswtMap/index.tsx b/apps/wr/app/store/map/rswtMap/index.tsx index c55cdc983..e788bedc1 100644 --- a/apps/wr/app/store/map/rswtMap/index.tsx +++ b/apps/wr/app/store/map/rswtMap/index.tsx @@ -1,10 +1,12 @@ -import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; import type { customRswtBdst } from "../../ruseFcltMng/fcltReg/rswtReg"; -import { rswtSttHeadListExport, rswtSttNodeListExport } from "../../ruseFcltMng/fcltSttn/rswtSttn/headList"; +import { + rswtSttHeadListExport, + rswtSttNodeListExport, +} from "../../ruseFcltMng/fcltSttn/rswtSttn/headList"; - -export const rswtMapSize = 15 +export const rswtMapSize = 15; export type rswtMapState = { rswtMap: { rswtMapRes: customRswtBdst[]; @@ -16,8 +18,14 @@ export type rswtMapState = { }; type rswtMapActions = { - rswtMapInit: (page: number, total: number, cityOrSgg:string) => void; - rswtMapSearch: (page: number, total: number, cityOrSgg:string, searchTxt?:string) => void + rswtMapInit: (page: number, total: number, cityOrSgg: string) => void; + rswtMapSearch: ( + page: number, + total: number, + cityOrSgg: string, + searchTxt?: string + ) => void; + rswtMapDetile: (featureCd: string) => Promise<customRswtBdst | undefined>; }; export type rswtMapType = rswtMapState & rswtMapActions; @@ -36,15 +44,15 @@ export const rswtMapActionsExport: (set: any) => rswtMapActions = ( set: any ) => { return { - rswtMapInit: async (page: number, total: number, cityOrSgg:string) => { + rswtMapInit: async (page: number, total: number, cityOrSgg: string) => { try { const rswtMapRes = await getFetchWithCount( - fetchType.WR, - `/reuseFc/waterreuseFc` + - (page ? `/${page}` : "/1") + - (total ? `/${total}` : "/20") + - (cityOrSgg ? `/${cityOrSgg}` : "/0") - ); + fetchType.WR, + `/reuseFc/waterreuseFc` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (cityOrSgg ? `/${cityOrSgg}` : "/0") + ); set((state: rswtMapState) => { return { @@ -61,7 +69,12 @@ export const rswtMapActionsExport: (set: any) => rswtMapActions = ( console.log(e); } }, - rswtMapSearch: async (page: number, total: number, cityOrSgg:string, searchTxt?:string) => { + rswtMapSearch: async ( + page: number, + total: number, + cityOrSgg: string, + searchTxt?: string + ) => { try { const rswtMapRes = await getFetchWithCount( fetchType.WR, @@ -69,7 +82,7 @@ export const rswtMapActionsExport: (set: any) => rswtMapActions = ( (page ? `/${page}` : "/1") + (total ? `/${total}` : "/20") + (cityOrSgg ? `/${cityOrSgg}` : "/0") + - (searchTxt ? `/${searchTxt}` : "") + (searchTxt ? `/${searchTxt}` : "") ); set((state: rswtMapState) => { @@ -86,6 +99,22 @@ export const rswtMapActionsExport: (set: any) => rswtMapActions = ( console.log(e); } }, + rswtMapDetile: async (featureCd: string) => { + try { + const rswtDetail = await getFetch( + fetchType.WR, + `/reuseFc/waterreuseFc/1/3/0/${featureCd}` + ); + if (rswtDetail && rswtDetail.length > 0) { + return rswtDetail[0]; + } else { + return null; + } + } catch (error) { + console.log(error); + throw error; // 호출부에서 catch 가능하도록 + } + }, }; }; diff --git a/apps/wr/app/store/map/ruseMap/index.tsx b/apps/wr/app/store/map/ruseMap/index.tsx index f5145cbf3..d42fc6202 100644 --- a/apps/wr/app/store/map/ruseMap/index.tsx +++ b/apps/wr/app/store/map/ruseMap/index.tsx @@ -7,6 +7,7 @@ import { } from "../../ruseFcltMng/fcltSttn/pbnstSttn/headList"; import type { ReturnType } from "@common/business_components/ui"; import { hasuListFetch } from "../../ruseFcltMng/fcltSttn/pbnstSttn"; +import type { customPbnst } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; export const ruseMapSize = 15; export type ruseMapState = { @@ -29,6 +30,7 @@ type ruseMapActions = { year: string, fclts: string[] ) => void; + ruseMapDetail: (ruseFcltId: string) => Promise<customPbnst | undefined>; }; export type ruseMapType = ruseMapState & ruseMapActions; @@ -90,5 +92,20 @@ export const ruseMapActionsExport: (set: any) => ruseMapActions = ( console.log(e); } }, + ruseMapDetail: async (ruseFcltId: string) => { + try { + let ruseDetail = await getFetch("wr", `/reuseFc/pubFc/${ruseFcltId}`); + if (ruseDetail.length >= 0) { + ruseDetail = ruseDetail.find( + (item: customPbnst) => item.pbnstRuseFcltId === ruseFcltId + ); + } + // 🔑 스토어 업데이트 대신 리턴 + return ruseDetail; + } catch (errorHasu) { + console.log(errorHasu); + throw errorHasu; // 호출부에서 catch 가능하도록 + } + }, }; }; diff --git "a/apps/wr/components/lib/func/\bmapUtil.ts" "b/apps/wr/components/lib/func/\bmapUtil.ts" new file mode 100644 index 000000000..41a8c09b4 --- /dev/null +++ "b/apps/wr/components/lib/func/\bmapUtil.ts" @@ -0,0 +1,19 @@ + + + + export const getFeatureCd = (featurePropertise:any, layerNm:string) => { + console.log('layerNm ', layerNm ) + + const featureCd = + layerNm === "하수재이용시설" + ? featurePropertise?.swtrmt_fclt_cd + : ["빗물이용시설", "중수도시설", "온배수시설", "수요처"].includes( + layerNm + ) + ? featurePropertise?.bdst_nm + : layerNm === "하수처리시설" + ? featurePropertise?.swtrmt_fclt_nm + : null; + + return featureCd; + }; \ No newline at end of file From 551c41e9643fb2aaedfb3d21135493871ed24629 Mon Sep 17 00:00:00 2001 From: leedj312 <dlehd467@gmail.com> Date: Wed, 6 Aug 2025 19:30:13 +0900 Subject: [PATCH 7/7] =?UTF-8?q?=EC=A7=80=EB=8F=84=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=ED=95=98=EC=A7=80=EB=A7=8C=20=ED=8C=9D?= =?UTF-8?q?=EC=97=85=20=ED=81=AC=EA=B8=B0=20=EC=A1=B0=EC=A0=95=ED=95=B4?= =?UTF-8?q?=EC=95=BC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layerPopup/hasuFacility.tsx | 150 ---------- .../layerPopup/htdflFacility.tsx | 83 ------ .../layerPopup/rainFacility.tsx | 105 ------- .../layerPopup/reuseFacility.tsx | 146 ---------- .../layerPopup/rswtFacility.tsx | 107 ------- .../(popUp-layout)/mapDetilePopUp/qweqwe.tsx | 187 ------------ .../(popUp-layout)/mapFeaturePopup/page.tsx | 15 + .../wr/app/(popUp-layout)/newWindowPortal.tsx | 148 ---------- .../components/layerPopup/hasuFacility.tsx | 89 ------ .../components/layerPopup/htdflFacility.tsx | 83 ------ .../components/layerPopup/rainFacility.tsx | 105 ------- .../components/layerPopup/reuseFacility.tsx | 146 ---------- .../layerPopup/reuseMngFacility.tsx | 103 ------- .../components/layerPopup/rswtFacility.tsx | 107 ------- .../map/components/newWindowPopup.tsx | 183 ------------ .../map/components/newWindowPortal.tsx | 112 -------- apps/wr/app/(with-layout)/map/popup/page.tsx | 270 +++++++++--------- apps/wr/app/store/map/ldrmntCoMap/index.tsx | 20 +- "apps/wr/components/lib/func/\bmapUtil.ts" | 4 +- .../PbnFacility}/reuseMngFacility.tsx | 0 .../sttn/sttnDetailModal/coDatailModal.tsx | 23 +- 21 files changed, 188 insertions(+), 1998 deletions(-) delete mode 100644 apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx delete mode 100644 apps/wr/app/(popUp-layout)/layerPopup/htdflFacility.tsx delete mode 100644 apps/wr/app/(popUp-layout)/layerPopup/rainFacility.tsx delete mode 100644 apps/wr/app/(popUp-layout)/layerPopup/reuseFacility.tsx delete mode 100644 apps/wr/app/(popUp-layout)/layerPopup/rswtFacility.tsx delete mode 100644 apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx delete mode 100644 apps/wr/app/(popUp-layout)/newWindowPortal.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/hasuFacility.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx delete mode 100644 apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx rename apps/wr/{app/(popUp-layout)/layerPopup => components/ui/map/LayerPopUp/PbnFacility}/reuseMngFacility.tsx (100%) diff --git a/apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx deleted file mode 100644 index 5868b2ccc..000000000 --- a/apps/wr/app/(popUp-layout)/layerPopup/hasuFacility.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { useWrStore } from "@/app/store"; -import { btnClass } from "@/app/store/common/code"; -import { pbnMapTableSize } from "@/app/store/map/pbnstMap"; -import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import { tableData } from "@/components/lib/func/commom"; -import { - ContentsDiv, - SearchBaseForm, - SearchInput, - Title, - UiTable, - type ReturnType, -} from "@common/business_components/ui"; -import { Label } from "@common/components/ui"; -import { useEffect, useRef, useState } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: "list" | "detail" | "nothing"; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - isRuseReg: { data: any | undefined }; -} -const HasuFacility = ({ - seletectedLayerNm, - viewMode, - onClose, - onFeatureSelect, - isRuseReg, -}: Props) => { - const { code, pbnMap, pbnMapInit } = useWrStore((state) => state); - const { pbnMapHeadList, pbnMapRes, pbnMapCount } = pbnMap; - const [hasuTable, setHasuTable] = useState<pubHasuType[]>(); - const [isReset, setIsReset] = useState(false); - const [pbnRuseNm, setPbnRuseNm] = useState<string>(""); - - const ref = useRef<ReturnType>({} as ReturnType); - useEffect(() => { - if (code.sggCd.length && pbnMapRes.length > 0) { - setHasuTable(tableData(pbnMapRes, { code })); - } - }, [code, pbnMapRes]); - - - useEffect(() => { - if (seletectedLayerNm !== "하수처리시설" || viewMode != "list") return; - if (!pbnMap.isInit) { - - console.log('ref.current ', ref.current) - pbnMapInit(1, pbnMapTableSize, ref.current); - } - }, [pbnMap.isInit, pbnMapInit]); - - const hasuCellClick = (index: number | undefined) => { - if (index !== undefined && pbnMapRes !== undefined) { - onFeatureSelect(pbnMapRes[index]); - onClose(); - } - }; - return viewMode == "list" ? ( - <ContentsDiv> - <div className="grid grid-cols-2 gap-4 "> - <div className="col-span-2"> - <Title title="하수처리시설 현황" /> - <SearchBaseForm - selectSidoData={code.cityCd} - selectSigunData={code.sggCd} - selectRegionData={code.rvbsnCd} - selectUnitWaterShedData={code.lgbsnCd} - selectMiddleRegionData={code.mdmbsnCd} - selectEnvPartData={code.lclgvrnmntCd} - buttonOrder={["query", "init", "excel"]} - rightClassName="ml-auto mr-6 flex items-center space-x-1" - leftClassName="flex gap-5 w-9/12 m-4" - leftSelectClassName="w-1/4" - rightChildren={<></>} - leftChildren={ - <div className="col-span-3 flex items-center"> - <Label className="w-full mt-2 ml-4 text-xl text-gray-600"> - {"하수처리시설명"} - </Label> - <SearchInput - className={"text-2xl w-full"} - label="" - textValue={pbnRuseNm || ""} - setText={(e) => { - setPbnRuseNm(e || ""); - }} - /> - </div> - } - queryClick={() => { - setIsReset(true); - }} - initClick={function (): void { - setPbnRuseNm(""); - }} - btnClass={btnClass} - ref={ref} - isAdmin={false} - excelClick={function (returnType: ReturnType): void { - console.log("pbnstSttnSearch ", returnType); - }} - /> - </div> - <div className="col-span-6"> - {/* 높이 조정 */} - <UiTable - tableData={hasuTable || []} - headlist={pbnMapHeadList} - pageSize={pbnMapTableSize} - total={pbnMapCount || 0} - headName={""} - cellClick={hasuCellClick} - onPageChange={(page) => { - pbnMapInit(page, pbnMapTableSize, ref.current); - setIsReset(false); - }} - resetPageNo={isReset} - /> - </div> - </div> - </ContentsDiv> - ) : ( - <div style={{ overflowX: "hidden" }}> - <div className="flex justify-between items-center mb-4"> - <Title title="하수처리시설 상세정보" /> - </div> - {/* 높이 조정 */} - <UiTable - tableData={isRuseReg?.data || []} - headlist={pbnMapHeadList.slice(0, 4)} - pageSize={1} - total={0} - headName={"위치정보"} - cellClick={() => {}} - onPageChange={() => {}} - /> - <UiTable - tableData={isRuseReg?.data || []} - headlist={pbnMapHeadList.slice(4)} - pageSize={1} - total={0} - headName={"기본정보"} - cellClick={() => {}} - onPageChange={() => {}} - /> - </div> - ); -}; -export default HasuFacility; diff --git a/apps/wr/app/(popUp-layout)/layerPopup/htdflFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/htdflFacility.tsx deleted file mode 100644 index fe4bef25a..000000000 --- a/apps/wr/app/(popUp-layout)/layerPopup/htdflFacility.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { useWrStore } from '@/app/store'; -import type { customHtdflBdst } from '@/app/store/ruseFcltMng/fcltReg/htdflReg'; -import { tableData } from '@/components/lib/func/commom'; -import SttnDetailModal from '@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal'; -import { Title, UiTable } from '@common/business_components/ui'; -import { HeadMakeColSpan } from '@common/business_components/ui/table/HeadMakeColSpan'; -import React, { useEffect, useState } from 'react' -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - htdflDetailModal: { isOpen: boolean; data: customHtdflBdst | undefined }; -} -const HtdflFacility = ({ seletectedLayerNm, viewMode, onFeatureSelect, onClose, htdflDetailModal }: Props) => { - const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore((state) => state); - const { htdflSttnRes, htdflSttnResCount } = htdflSttn; - const [htdflTable, setHtdflTable] = useState<customHtdflBdst[]>(); - const [htdflPage, setHtdflPage] = useState(1) - // 온배수시설 cellClick 이벤트 (상세정보) - const htdflCellClick = (index: number | undefined) => { - if (index !== undefined && htdflTable !== undefined) { - onFeatureSelect(htdflTable[index]); - onClose(); - } - }; - useEffect(() => { - if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; - if (!htdflSttn.isInit) { - initHtdfl(false, 1, "20", "0", '', code.cityCd, code.sggCd); - } - }, [code.cityCd, code.sggCd, htdflSttn.isInit, initHtdfl]); - - useEffect(() => { - if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; - const data = tableData(htdflSttnRes, { code }); - const chData = data - .map((item: any) => ({ - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0].htdflObj, - chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - })) - .filter((item: any) => item.htdflObj !== undefined); - setHtdflTable(chData); - }, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]); - - useEffect(() => { - if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; - htdflSttnSearch(true, htdflPage, "20", '', '', code.cityCd, code.sggCd); - }, [code.cityCd, code.sggCd, htdflPage, htdflSttnSearch]); - return ( - viewMode == 'detail' ? ( - <SttnDetailModal type={"HTB"} formObj={htdflDetailModal.data as customHtdflBdst} /> - ) : ( - <div style={{ overflowY: 'auto' }}> - <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 || []} - headlist={htdflSttn.htdflSttHeadList} - pageSize={20} - total={htdflSttnResCount || 0} - cellClick={(index: number | undefined) => { - htdflCellClick(index ?? undefined); - }} - onPageChange={setHtdflPage} - > - <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> - </UiTable> - </div> - ) - ) -} - -export default HtdflFacility \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/layerPopup/rainFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/rainFacility.tsx deleted file mode 100644 index 54b51e8a6..000000000 --- a/apps/wr/app/(popUp-layout)/layerPopup/rainFacility.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { tableData } from "@/components/lib/func/commom"; -import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; -import { Title, UiTable } from "@common/business_components/ui"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - rainDetailModal: { isOpen: boolean; data: customRainBdst | undefined }; -} -const RainFacility = ({seletectedLayerNm,viewMode,onFeatureSelect,onClose,rainDetailModal}:Props) => { - // 빗물재이용시설 변수 - const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore( - (state) => state - ); - const { rainSttnRes, rainSttnResCount } = rainSttn; - const [rainTable, setRainTable] = useState<customRainBdst[]>(); - const [rainPage, setRainPage] = useState(1) - - // 빗물재이용시설 cellClick 이벤트 (상세정보) - const rainCellClick = (index: number | undefined, headId: string) => { - if ( - index !== undefined && - rainTable !== undefined && - headId !== 'chBuildingYn') { - onFeatureSelect(rainTable[index]); - onClose(); - } - } - useEffect(() => { - if (seletectedLayerNm !== '빗물이용시설' || viewMode != 'list') return; - console.log('빗물이용시설 초기값 호출', viewMode) - if (!rainSttn.isInit) { - rainSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); - } - }, [code.cityCd, code.sggCd, rainSttn.isInit, rainSttnInit]); - - useEffect(() => { - const data = tableData(rainSttnRes, { code }); - const chData = data - .map((item: any) => { - return { - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0].rainyObj, - dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.dtfcltCpct, - instlCst: item.reuseBuilding[0].instlCst === -1 - ? "확인불가" - : item.reuseBuilding[0].instlCst, - instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1 - ? "확인불가" - : item.reuseBuilding[0].instlCstSprtAmt, - chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.pntfColArea, - filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, - archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, - }; - }) - .filter((item: any) => item.rainyObj !== undefined); - setRainTable(chData); - }, [code, rainSttnRes, rainSttn.rainSttHeadList]); - - useEffect(() => { - if (seletectedLayerNm !== '빗물이용시설' || viewMode != 'list') return; - rainSttnSearch(false, rainPage, "20", '', '', code.cityCd, code.sggCd); - }, [code.cityCd, code.sggCd, rainPage, rainSttnSearch]); - return (viewMode == 'detail' ? - (<SttnDetailModal type={"RNB"} formObj={rainDetailModal.data as customRainBdst} />) - : ( - <> - <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 || []} - headlist={rainSttn.rainSttHeadList} - pageSize={20} - total={rainSttnResCount} - cellClick={(index: number | undefined, headId: string) => { - rainCellClick(index ?? undefined, headId); - }} - onPageChange={setRainPage} - > - <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> - </UiTable> - </> - )) -} -export default RainFacility; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/layerPopup/reuseFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/reuseFacility.tsx deleted file mode 100644 index 152d37999..000000000 --- a/apps/wr/app/(popUp-layout)/layerPopup/reuseFacility.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; -import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; -import { Title, UITab, UiTable } from "@common/business_components/ui"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useState, useEffect, useCallback } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - setFcltPk: (pk: string) => void; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - actTabData: { id: string; name: string; data: any } | undefined; - tabData: { id: string; name: string; data: any }[]; -} -const ResueFacility = ({ viewMode, seletectedLayerNm, tabData, actTabData, setFcltPk, onFeatureSelect, onClose}: Props) => { - const [activeTab, setActiveTab] = useState<string>(''); // 현재 활성화된 탭 - // 하수재이용시설 변수 - const { - pbnstSttn, - pbnstSttnSearch, - pbnSttnInit, - getFlcts - } = useWrStore((state) => state); - const { fclts, pbnstSttnResCount } = pbnstSttn - const [bdstTable, setBdstTable] = useState<WaterReuseFacility[]>() - // 재이용시설 cellClick 이벤트 (상세정보) - const pbnstCellClick = (index: number | undefined) => { - if ( - index !== undefined && - pbnstSttn.pbnstSttnRes && - pbnstSttn.pbnstSttnRes[index] - ) { - setFcltPk(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltId); - onFeatureSelect(pbnstSttn.pbnstSttnRes[index]); - onClose() - } - }; - - // 재이용 현황 초기값 - useEffect(() => { - if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; - if (!pbnstSttn.isInit) { - getFlcts() - } - }, [seletectedLayerNm, pbnstSttn.isInit]); - useEffect(() => { - if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; - pbnSttnInit("1", "20", { - partValue: "A", - sidoValue: '0', - sigunValue: "0", - regionValue: "", - unitWaterShedValue: "", - middleRegionValue: "", - envPartValue: "", - sidoText: "", - sigunText: "" - }, String(new Date().getFullYear()), pbnstSttn.fclts); - }, [fclts, pbnSttnInit, pbnstSttn.fclts, seletectedLayerNm]) - useEffect(() => { - setBdstTable(pbnstSttn.pbnstSttnRes); - }, [seletectedLayerNm, pbnstSttn.pbnstSttnRes]); - - // 재이용시설 조회 - // 재이용시설 페이징처리 관련 함수 - const onPageChangeHandler = useCallback((page: number) => { - if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; - pbnstSttnSearch( - false, - String(page), - String(20), - { - partValue: "A", - sidoValue: "0", - sigunValue: "0", - regionValue: "", - unitWaterShedValue: "", - middleRegionValue: "", - envPartValue: "", - sidoText: "", - sigunText: "", - }, - "", - String(new Date().getFullYear()), fclts - ); - }, [fclts, pbnstSttnSearch]); - // FIXME: 윤선화차장님 요구사항으로 엑셀 다운로드 삭제. - // const excelClick = useCallback(() => { - // // if (codeData) pbnstSttnSearch(1, "10000", codeData); - // excelDownload( - // [[]], - // "하수재이용시설 현황", - // "sample_pbnstSttn.xlsx", - // "A1:U2" - // ); - // }, [pbnstSttnSearch]); - return ( - viewMode == 'detail' ? - // 재이용시설 상세 - <> - <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), - }))} - /> - </div> - <PbnstSttnModal - data={actTabData?.data[0] || ({} as customPbnst)} - titleVisible={false} - /> - </> : - <div style={{ overflowY: 'auto' }}> - <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 || []} - headlist={pbnstSttn.pbnstSttHeadList} - pageSize={20} - total={pbnstSttnResCount || 0} - cellClick={(index: number | undefined) => { - pbnstCellClick(index); - }} - onPageChange={onPageChangeHandler} - > - <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> - </UiTable> - </div> - ) -} -export default ResueFacility; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/layerPopup/rswtFacility.tsx b/apps/wr/app/(popUp-layout)/layerPopup/rswtFacility.tsx deleted file mode 100644 index dc2537c95..000000000 --- a/apps/wr/app/(popUp-layout)/layerPopup/rswtFacility.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import { tableData } from "@/components/lib/func/commom"; -import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; -import { Title, UiTable } from "@common/business_components/ui"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - rswtrDetailModal: { isOpen: boolean; data: customRswtBdst | undefined }; -} -const RswtFacility = ({ seletectedLayerNm, viewMode, onFeatureSelect, onClose, rswtrDetailModal }: Props) => { - const { code, rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore( - (state) => state - ); - const { rswtSttnRes, rswtSttnResCount } = rswtSttn; - const [rswtrTable, setRswtrTable] = useState<customRswtBdst[]>() - const [rswtrPage, setRswtrPage] = useState(1); - // 중수도시설 cellClick 이벤트 (상세정보) - const rswtCellClick = (index: number | undefined, headId: string) => { - if (headId !== 'chBuildingYn' && index !== undefined && rswtrTable !== undefined) { - // setRswtrDetailModal({ isOpen: true, data: rswtrTable[index] }); - // setViewMode('detail') - onFeatureSelect(rswtrTable[index]); - onClose(); - } - } - useEffect(() => { - if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; - if (!rswtSttn.isInit) { - rswtSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); - } - }, [code.cityCd, code.sggCd, rswtSttn.isInit, rswtSttnInit]); - - useEffect(() => { - if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; - const data = tableData(rswtSttnRes, { code }); - const chData = data - .map((item: customRswtBdst) => { - return { - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0]?.rswtrObj, - chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N', - instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst, - instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt, - archArea: item?.archArea.split('.')[0] !== '-1' ? item?.archArea.split('.')[0] : '확인불가' - } - }) - .filter( - (item: customRswtBdst) => - item.reuseBuilding[0]?.rswtrObj !== undefined - ); - setRswtrTable(chData); - }, [code, rswtSttnRes]); - // FIXME: 윤선화 차장님 요구사항으로 엑셀 다운로드 삭제. - // const rswtSttnExcelDownload = useCallback(() => { - // if (rswtSttn.excelList.length > 0) { - // if (rswtSttn.excelList.length === 0) return; - // excelDownload( - // rswtSttn.excelList, - // "중수도시설 현황", - // "sample_rswtSttn.xlsx", - // "A1:W3", - // ); - // } - // }, [rswtSttn.excelList]) - - useEffect(() => { - if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; - rswtSttnSearch(false, rswtrPage, "20", '', '', code.cityCd, code.sggCd); - }, [code.cityCd, code.sggCd, rswtSttnSearch, rswtrPage]); - return ( - viewMode == 'detail' ? - // 중수도시설 상세 - ( - <SttnDetailModal type={"RST"} formObj={rswtrDetailModal.data as customRswtBdst} /> - ) : ( - <div style={{ overflowY: 'auto' }}> - <div className="flex justify-between items-center"> - <Title title="중수도시설 현황" /> - {/* <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={rswtSttnExcelDownload}> - 엑셀다운로드 - </Button> - </div> */} - </div> - <UiTable - headName={[]} - tableData={rswtrTable || []} - headlist={rswtSttn.rswtSttHeadList} - pageSize={20} - total={rswtSttnResCount} - cellClick={(index: number | undefined, headId: string) => { - rswtCellClick(index, headId); - }} - onPageChange={setRswtrPage} - > - <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> - </UiTable> - </div> - )) -} -export default RswtFacility; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx b/apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx deleted file mode 100644 index 365c5ef5c..000000000 --- a/apps/wr/app/(popUp-layout)/mapDetilePopUp/qweqwe.tsx +++ /dev/null @@ -1,187 +0,0 @@ -// "use client" -// import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -// import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -// import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -// import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -// import { useGisContext } from "@common/business_components/ui/map/Gis"; -// import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form'; -// import React, { useCallback, useEffect, useRef, useState } from 'react'; -// import ResueFacility from '../layerPopup/reuseFacility'; -// import HasuFacility from '../layerPopup/hasuFacility'; -// import RainFacility from '../layerPopup/rainFacility'; -// import RswtFacility from '../layerPopup/rswtFacility'; -// import HtdflFacility from '../layerPopup/htdflFacility'; -// import ReuseMngFacility from '../layerPopup/reuseMngFacility'; -// import { detainSttn, fetchHasuDetail, fetchpbnstDetail } from "../util"; - -// interface NewWindowPopupProps { -// featureData: any; -// seletectedLayerNm?: string -// onFeatureSelect: (data: any) => void; -// onClose: () => void; -// } - -// const NewWindowPopup: React.FC<NewWindowPopupProps> = ({ -// featureData, -// seletectedLayerNm, -// onFeatureSelect, -// onClose -// }) => { -// const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject<number[]>; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; -// const [tabData, setTabData] = useState<{ id: string; name: string; data: any }[]>([]); -// const [activeTab, setActiveTab] = useState<string>('0'); -// const [viewMode, setViewMode] = useState<'list' | 'detail' | 'nothing'>('list'); -// const [fcltPk, setFcltPk] = useState<string>(''); - - -// // onClose 함수를 useCallback으로 메모이제이션 -// const memoizedOnClose = useCallback(() => { -// onClose(); -// }, [onClose]); - -// // 빗물재이용시설 변수 -// const [rainDetailModal, setRainDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false }); -// const [rainList, setRainList] = useState<customRainBdst[]>([]); - -// // 중수도시설 변수 -// const [rswtrDetailModal, setRswtrDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }); -// const [rswtrList, setRswtrList] = useState<customRswtBdst[]>([]); - -// // 온배수시설 변수 -// const [htdflDetailModal, setHtdflDetailModal] = useState<{ isOpen: boolean, data: customHtdflBdst | undefined }>({ data: undefined, isOpen: false }); -// const [htdflList, setHtdflList] = useState<customHtdflBdst[]>([]); - -// // 하수처리시설 변수 -// const [hasuList, setHasuList] = useState<pubHasuType[]>([]); -// const [isRuseReg, setIsRuseReg] = useState<{ -// data: any | undefined; -// }>({ data: undefined }); - -// // 수요처관리 변수 -// const [isDmdModal, setIsDmdModal] = useState<{ -// isMoal: boolean; -// data: any | undefined; -// }>({ isMoal: false, data: undefined }); -// const [mngList, setMngList] = useState<DemandCompType[]>([]); - -// ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// -// const getSelectedLayers = () => { -// console.trace('호출확인', 1) -// let result = null; -// const layers = gisMap ? gisMap.getLayers().getArray().filter((l: any) => l.getVisible()) : []; // gisMap이 null인지 확인 후 레이어 가져오기 -// let featureLayer: { get: (key: string) => any } = { get: () => null }; -// layers.forEach((layer: any) => { -// const source = layer.getSource(); -// if (source && source.hasFeature && featureData -// && typeof featureData.getId === 'function' && source.hasFeature(featureData)) { -// featureLayer = layer; // 피처가 속한 레이어 찾기) -// } -// }); -// result = featureLayer.get('lyrNm'); -// return result; -// }; -// // 상세 목록 데이터 상태 처리 -// useEffect(() => { -// if (hasuList.length > 0) setIsRuseReg({ data: [hasuList[0]] }); -// }, [hasuList]) -// useEffect(() => { -// if (rainList.length > 0) setRainDetailModal({ isOpen: true, data: rainList[0] }); -// }, [rainList]) -// useEffect(() => { -// if (rswtrList.length > 0) setRswtrDetailModal({ isOpen: true, data: rswtrList[0] }); -// }, [rswtrList]) -// useEffect(() => { -// if (htdflList.length > 0) setHtdflDetailModal({ isOpen: true, data: htdflList[0] }); -// }, [htdflList]) -// useEffect(() => { -// if (mngList.length > 0) setIsDmdModal({ isMoal: true, data: [mngList[0]] }); -// }, [mngList]) - -// const lastCalledIdRef = useRef<string | null>(null); -// const [layerId, setLayerId] = useState<string | null>(); - -// useEffect(() => { -// const layers = getSelectedLayers(); -// setLayerId(layers); -// }, []); // 최초 렌더링 시 호출 - -// // 피쳐 데이터가 변경될 때마다 호출 -// useEffect(() => { -// if (!featureData || typeof featureData.getProperties !== "function" || featureData.getProperties() == '') return; -// const selectedProps = featureData.getProperties(); -// const currentId = featureData.getId?.() || selectedProps?.id || selectedProps?.fid; -// // 유효하지 않은 ID는 아예 무시 -// if (!currentId || typeof currentId !== 'string') return; -// // 이전과 동일하면 무시 -// if (!currentId || currentId === lastCalledIdRef.current) return; -// lastCalledIdRef.current = currentId // 새로운 피처일 때만 API 호출 -// const layerId = getSelectedLayers?.(); -// if (!layerId || typeof layerId !== 'string') return; -// const featureCd = -// layerId === '하수재이용시설' ? selectedProps?.swtrmt_fclt_cd : -// ['빗물이용시설', '중수도시설', '온배수시설', '수요처'].includes(layerId) ? selectedProps?.bdst_nm : -// layerId === '하수처리시설' ? selectedProps?.swtrmt_fclt_nm : -// null; -// if (!featureCd || featureCd === fcltPk) return; - -// if (layerId === '하수재이용시설') { -// fetchpbnstDetail(featureCd, setTabData); -// } else if (layerId === '하수처리시설') { -// fetchHasuDetail(featureCd, selectedProps?.swtrmt_fclt_cd).then((data) => { setHasuList(data) }) -// } else { -// detainSttn(featureCd, layerId).then((res) => { -// if (layerId === '빗물이용시설') setRainList(res); -// else if (layerId === '중수도시설') setRswtrList(res); -// else if (layerId === '온배수시설') { setHtdflList(res); setHtdflDetailModal({ isOpen: true, data: res[0] }); } -// else if (layerId === '수요처') setMngList(res); -// }); -// } -// setFcltPk(featureCd); -// setActiveTab(featureCd); -// setViewMode("detail"); -// }, [featureData]); -// ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// - -// // 체크된 레이어에 따른 조건부 컴포넌트 렌더링 함수 -// const renderConditionalContent = () => { -// const actTabData = tabData.find((tab) => tab.id === activeTab); -// if (layerId === null || layerId === undefined) { -// setLayerId(seletectedLayerNm || ''); -// } - -// switch (layerId) { -// case '하수재이용시설': -// return (<ResueFacility viewMode={viewMode} seletectedLayerNm={layerId} tabData={tabData} actTabData={actTabData} setFcltPk={setFcltPk} onFeatureSelect={onFeatureSelect} onClose={onClose} />) -// case '하수처리시설': -// return (<HasuFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} isRuseReg={isRuseReg} />) -// case '빗물이용시설': -// return (<RainFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} rainDetailModal={rainDetailModal} />) -// case '중수도시설': -// return (<RswtFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} rswtrDetailModal={rswtrDetailModal} />) -// case '온배수시설': -// return (<HtdflFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} htdflDetailModal={htdflDetailModal} />) -// case '수요처': -// return(<ReuseMngFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} isDmdModal={isDmdModal} />) -// default: -// break; -// } -// return null; // 조건에 맞는 콘텐츠가 없을 경우 -// }; -// return ( -// // viewMode == 'nothing' ? <></> : -// // <NewWindowPortal -// // onClose={memoizedOnClose} -// // title="시설 상세 정보" -// // scrollbars='yes' -// // viewMode={viewMode} -// // resizable='no'> -// // {/* 체크된 레이어에 따른 조건부 렌더링 */} -// // {renderConditionalContent()} -// // </NewWindowPortal> -// <div> -// {renderConditionalContent()} -// </div> -// ); -// }; - -// export default NewWindowPopup; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx index 9e7c1296e..1246525d9 100644 --- a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx +++ b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useWrStore } from "@/app/store"; import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; +import CoDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/coDatailModal"; import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import { Title, UiTable } from "@common/business_components/ui"; import { useSearchParams } from "next/navigation"; @@ -15,6 +16,7 @@ export default function MapFeaturePopup() { rswtMapDetile, htdfMapDetile, pbnMapDetaile, + ldrmntMapDetile, } = useWrStore((state) => state); const { pbnMapHeadList } = pbnMap; const [isDetail, setIsDetail] = useState<any>(null); @@ -64,6 +66,10 @@ export default function MapFeaturePopup() { htdfMapDetile(isFeatureCd).then((res) => { setIsDetail(res); }); + } else if (layerNm === "잠재수요처") { + ldrmntMapDetile(isFeatureCd).then((res) => { + setIsDetail(res); + }); } } }, [isFeatureCd, layerNm]); @@ -100,6 +106,15 @@ export default function MapFeaturePopup() { onPageChange={() => {}} /> </div> + ) : layerNm === "잠재수요처" ? ( + <CoDetailModal + formObj={isDetail} + readonly={false} + onFormSubmit={async (value) => { + console.log(value) + }} + isMap={true} + /> ) : ( <SttnDetailModal type={ diff --git a/apps/wr/app/(popUp-layout)/newWindowPortal.tsx b/apps/wr/app/(popUp-layout)/newWindowPortal.tsx deleted file mode 100644 index 6fdabead6..000000000 --- a/apps/wr/app/(popUp-layout)/newWindowPortal.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import React, { useState, useEffect, useRef, useCallback, createContext, useContext } from 'react'; -import { createPortal } from 'react-dom'; - -// 현재 문서의 스타일(CSS)을 새 창으로 복사하는 함수 -const copyStyles = (sourceDoc: Document, targetDoc: Document) => { - Array.from(sourceDoc.styleSheets).forEach(styleSheet => { - try { - if (styleSheet.cssRules) { // <style> 태그로 주입된 CSS - const newStyleEl = sourceDoc.createElement('style'); - Array.from(styleSheet.cssRules).forEach(cssRule => { - newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText)); - }); - targetDoc.head.appendChild(newStyleEl); - } else if (styleSheet.href) { // <link> 태그로 연결된 CSS 파일 - const newLinkEl = sourceDoc.createElement('link'); - newLinkEl.rel = 'stylesheet'; - newLinkEl.href = styleSheet.href; - targetDoc.head.appendChild(newLinkEl); - } - } catch (e) { - console.warn('스타일시트를 복사할 수 없습니다:', e); - } - }); -}; - -interface NewWindowPortalProps { - children: React.ReactNode; - onClose: () => void; - title?: string; - width?: number; - height?: number; - resizable?: string; - scrollbars?: string; - viewMode?: 'list' | 'detail' | 'nothing'; -} - -// Context to provide the new window's document -const NewWindowContext = createContext<Document | null>(null); - -// Custom hook to consume the new window's document -export const useNewWindowDocument = () => { - const context = useContext(NewWindowContext); - if (context === null) { - throw new Error('useNewWindowDocument must be used within a NewWindowContext.Provider'); - } - return context; -}; - -const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, title = "", resizable = "yes", scrollbars = "yes", viewMode }) => { - const [container, setContainer] = useState<HTMLElement | null>(null); - const [targetDocument, setTargetDocument] = useState<Document | null>(null); - const newWindowRef = useRef<Window | null>(null); - const onCloseRef = useRef(onClose); - - // onClose 함수를 ref로 저장하여 의존성 문제 해결 - useEffect(() => { - onCloseRef.current = onClose; - }, [onClose]); - - const handleUnload = useCallback(() => { - onCloseRef.current(); - }, []); - useEffect(() => { - if (newWindowRef.current) { - if (viewMode == 'detail') { - newWindowRef.current.resizeTo(1100, 700); - } else { - newWindowRef.current.resizeTo(screen.availWidth, screen.availHeight); - } - } - }, [viewMode]); - useEffect(() => { - // 이미 창이 열려있으면 새로 열지 않음 - if (newWindowRef.current && !newWindowRef.current.closed) return; - // 브라우저 화면 정보 - const screenLeft = window.screenLeft ?? window.screenX; - const screenTop = window.screenTop ?? window.screenY; - const screenWidth = window.innerWidth ?? document.documentElement.clientWidth; - const screenHeight = window.innerHeight ?? document.documentElement.clientHeight; - - // 중앙 위치 계산 - const left = screenLeft + (screenWidth - window.screen.width) / 2; - const top = screenTop + (screenHeight - window.screen.height) / 2; - - // 1. 새 창을 열고 참조를 저장합니다. - const popupOptions = `width=${window.screen.width},height=${window.screen.height},left=${left}, top=${top}, resizable=${resizable},scrollbars=${scrollbars}`; - newWindowRef.current = window.open('', title, popupOptions); - - if (newWindowRef.current) { - newWindowRef.current.document.title = title; - - // 2. React 컴포넌트를 마운트할 컨테이너 div를 생성하여 새 창의 body에 추가합니다. - const div = newWindowRef.current.document.createElement('div'); - newWindowRef.current.document.body.appendChild(div); - setContainer(div); - setTargetDocument(newWindowRef.current.document); - - // 3. 메인 창의 스타일을 새 창으로 복사합니다. (매우 중요) - copyStyles(document, newWindowRef.current.document); - - // 4. 사용자가 창을 닫을 때 부모에게 알리기 위한 이벤트 리스너를 설정합니다. - newWindowRef.current.addEventListener('unload', handleUnload); - - // 5. 컴포넌트가 사라질 때 창을 닫는 클린업 함수를 반환합니다. - return () => { - if (newWindowRef.current) { - newWindowRef.current.removeEventListener('unload', handleUnload); - if (!newWindowRef.current.closed) { - newWindowRef.current.close(); - } - } - }; - } else { - alert('팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.'); - onCloseRef.current(); - } - }, [handleUnload, onClose, title]); - - // `createPortal`을 사용해 children을 새 창의 container div에 렌더링합니다. - // children을 NewWindowContext.Provider로 감싸서 새 창의 document를 하위 컴포넌트에서 접근 가능하도록 함 - return container && targetDocument ? ( - createPortal( - <NewWindowContext.Provider value={targetDocument}> - {children} - </NewWindowContext.Provider>, - container - ) - ) : null; -}; - -export default NewWindowPortal; - -/* -Usage example inside popup children: - -import { useNewWindowDocument } from './newWindowPortal'; - -const PopupChildComponent = () => { - const newWindowDocument = useNewWindowDocument(); - - return ( - <SomeSelectComponent - menuPortalTarget={newWindowDocument.body} // For react-select or MUI Select to render dropdowns correctly in new window - {...otherProps} - /> - ); -}; -*/ \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/hasuFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/hasuFacility.tsx deleted file mode 100644 index 5a10ce3ed..000000000 --- a/apps/wr/app/(with-layout)/map/components/layerPopup/hasuFacility.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import { tableData } from "@/components/lib/func/commom"; -import { Title, UiTable } from "@common/business_components/ui"; -import { useEffect, useState } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - isRuseReg: { data: any | undefined }; -} -const HasuFacility = ({ seletectedLayerNm, viewMode, onClose, onFeatureSelect, isRuseReg }: Props) => { - const { - code, - pbnst, - pubHasuInit, - } = useWrStore((state) => state); - const { pubFacHeadList, pbnstHasuRes, pbnstHasuResCount } = pbnst; - const [hasuTable, setHasuTable] = useState<pubHasuType[]>(); - const [hasuPage, setHasuPage] = useState<number>(1); - useEffect(() => { - if (code.sggCd.length && pbnstHasuRes.length > 0) { - setHasuTable(tableData(pbnstHasuRes, { code })); - } - }, [code, pbnstHasuRes]); - useEffect(() => { - if (seletectedLayerNm !== '하수처리시설' || viewMode != 'list') return; - if (!pbnst.isInit) { - pubHasuInit("1", "0"); - } - }, [pbnst.isInit, pubHasuInit]); - useEffect(() => { - if (seletectedLayerNm !== '하수처리시설' || viewMode != 'list') return; - pubHasuInit(String(hasuPage), "0"); - }, [hasuPage, pubHasuInit]); - - const hasuCellClick = (index: number | undefined) => { - if (index !== undefined && pbnstHasuRes !== undefined) { - onFeatureSelect(pbnstHasuRes[index]); - onClose(); - } - }; - return (viewMode == 'list' ? ( - <div style={{ overflowY: 'auto' }}> - <div className="flex justify-between items-center mb-4"> - <Title title="하수처리시설 현황" /> - </div> - {/* 높이 조정 */} - <UiTable - tableData={hasuTable || []} - headlist={pubFacHeadList} - pageSize={11} - total={pbnstHasuResCount || 0} - headName={""} - cellClick={hasuCellClick} - onPageChange={setHasuPage} - /> - </div> - ) : - ( - <div style={{ overflowX: 'hidden' }}> - <div className="flex justify-between items-center mb-4"> - <Title title="하수처리시설 상세정보" /> - </div> - {/* 높이 조정 */} - <UiTable - tableData={isRuseReg?.data || []} - headlist={pubFacHeadList.slice(0, 4)} - pageSize={1} - total={0} - headName={"위치정보"} - cellClick={() => { }} - onPageChange={() => { }} - /> - <UiTable - tableData={isRuseReg?.data || []} - headlist={pubFacHeadList.slice(4)} - pageSize={1} - total={0} - headName={"기본정보"} - cellClick={() => { }} - onPageChange={() => { }} - /> - </div> - ) - ) -} -export default HasuFacility; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx deleted file mode 100644 index fe4bef25a..000000000 --- a/apps/wr/app/(with-layout)/map/components/layerPopup/htdflFacility.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { useWrStore } from '@/app/store'; -import type { customHtdflBdst } from '@/app/store/ruseFcltMng/fcltReg/htdflReg'; -import { tableData } from '@/components/lib/func/commom'; -import SttnDetailModal from '@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal'; -import { Title, UiTable } from '@common/business_components/ui'; -import { HeadMakeColSpan } from '@common/business_components/ui/table/HeadMakeColSpan'; -import React, { useEffect, useState } from 'react' -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - htdflDetailModal: { isOpen: boolean; data: customHtdflBdst | undefined }; -} -const HtdflFacility = ({ seletectedLayerNm, viewMode, onFeatureSelect, onClose, htdflDetailModal }: Props) => { - const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore((state) => state); - const { htdflSttnRes, htdflSttnResCount } = htdflSttn; - const [htdflTable, setHtdflTable] = useState<customHtdflBdst[]>(); - const [htdflPage, setHtdflPage] = useState(1) - // 온배수시설 cellClick 이벤트 (상세정보) - const htdflCellClick = (index: number | undefined) => { - if (index !== undefined && htdflTable !== undefined) { - onFeatureSelect(htdflTable[index]); - onClose(); - } - }; - useEffect(() => { - if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; - if (!htdflSttn.isInit) { - initHtdfl(false, 1, "20", "0", '', code.cityCd, code.sggCd); - } - }, [code.cityCd, code.sggCd, htdflSttn.isInit, initHtdfl]); - - useEffect(() => { - if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; - const data = tableData(htdflSttnRes, { code }); - const chData = data - .map((item: any) => ({ - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0].htdflObj, - chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - })) - .filter((item: any) => item.htdflObj !== undefined); - setHtdflTable(chData); - }, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]); - - useEffect(() => { - if (seletectedLayerNm !== '온배수시설' || viewMode != 'list') return; - htdflSttnSearch(true, htdflPage, "20", '', '', code.cityCd, code.sggCd); - }, [code.cityCd, code.sggCd, htdflPage, htdflSttnSearch]); - return ( - viewMode == 'detail' ? ( - <SttnDetailModal type={"HTB"} formObj={htdflDetailModal.data as customHtdflBdst} /> - ) : ( - <div style={{ overflowY: 'auto' }}> - <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 || []} - headlist={htdflSttn.htdflSttHeadList} - pageSize={20} - total={htdflSttnResCount || 0} - cellClick={(index: number | undefined) => { - htdflCellClick(index ?? undefined); - }} - onPageChange={setHtdflPage} - > - <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> - </UiTable> - </div> - ) - ) -} - -export default HtdflFacility \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx deleted file mode 100644 index 54b51e8a6..000000000 --- a/apps/wr/app/(with-layout)/map/components/layerPopup/rainFacility.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { tableData } from "@/components/lib/func/commom"; -import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; -import { Title, UiTable } from "@common/business_components/ui"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - rainDetailModal: { isOpen: boolean; data: customRainBdst | undefined }; -} -const RainFacility = ({seletectedLayerNm,viewMode,onFeatureSelect,onClose,rainDetailModal}:Props) => { - // 빗물재이용시설 변수 - const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore( - (state) => state - ); - const { rainSttnRes, rainSttnResCount } = rainSttn; - const [rainTable, setRainTable] = useState<customRainBdst[]>(); - const [rainPage, setRainPage] = useState(1) - - // 빗물재이용시설 cellClick 이벤트 (상세정보) - const rainCellClick = (index: number | undefined, headId: string) => { - if ( - index !== undefined && - rainTable !== undefined && - headId !== 'chBuildingYn') { - onFeatureSelect(rainTable[index]); - onClose(); - } - } - useEffect(() => { - if (seletectedLayerNm !== '빗물이용시설' || viewMode != 'list') return; - console.log('빗물이용시설 초기값 호출', viewMode) - if (!rainSttn.isInit) { - rainSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); - } - }, [code.cityCd, code.sggCd, rainSttn.isInit, rainSttnInit]); - - useEffect(() => { - const data = tableData(rainSttnRes, { code }); - const chData = data - .map((item: any) => { - return { - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0].rainyObj, - dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.dtfcltCpct, - instlCst: item.reuseBuilding[0].instlCst === -1 - ? "확인불가" - : item.reuseBuilding[0].instlCst, - instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1 - ? "확인불가" - : item.reuseBuilding[0].instlCstSprtAmt, - chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.pntfColArea, - filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, - archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, - }; - }) - .filter((item: any) => item.rainyObj !== undefined); - setRainTable(chData); - }, [code, rainSttnRes, rainSttn.rainSttHeadList]); - - useEffect(() => { - if (seletectedLayerNm !== '빗물이용시설' || viewMode != 'list') return; - rainSttnSearch(false, rainPage, "20", '', '', code.cityCd, code.sggCd); - }, [code.cityCd, code.sggCd, rainPage, rainSttnSearch]); - return (viewMode == 'detail' ? - (<SttnDetailModal type={"RNB"} formObj={rainDetailModal.data as customRainBdst} />) - : ( - <> - <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 || []} - headlist={rainSttn.rainSttHeadList} - pageSize={20} - total={rainSttnResCount} - cellClick={(index: number | undefined, headId: string) => { - rainCellClick(index ?? undefined, headId); - }} - onPageChange={setRainPage} - > - <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> - </UiTable> - </> - )) -} -export default RainFacility; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx deleted file mode 100644 index 152d37999..000000000 --- a/apps/wr/app/(with-layout)/map/components/layerPopup/reuseFacility.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; -import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; -import { Title, UITab, UiTable } from "@common/business_components/ui"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useState, useEffect, useCallback } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - setFcltPk: (pk: string) => void; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - actTabData: { id: string; name: string; data: any } | undefined; - tabData: { id: string; name: string; data: any }[]; -} -const ResueFacility = ({ viewMode, seletectedLayerNm, tabData, actTabData, setFcltPk, onFeatureSelect, onClose}: Props) => { - const [activeTab, setActiveTab] = useState<string>(''); // 현재 활성화된 탭 - // 하수재이용시설 변수 - const { - pbnstSttn, - pbnstSttnSearch, - pbnSttnInit, - getFlcts - } = useWrStore((state) => state); - const { fclts, pbnstSttnResCount } = pbnstSttn - const [bdstTable, setBdstTable] = useState<WaterReuseFacility[]>() - // 재이용시설 cellClick 이벤트 (상세정보) - const pbnstCellClick = (index: number | undefined) => { - if ( - index !== undefined && - pbnstSttn.pbnstSttnRes && - pbnstSttn.pbnstSttnRes[index] - ) { - setFcltPk(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltId); - onFeatureSelect(pbnstSttn.pbnstSttnRes[index]); - onClose() - } - }; - - // 재이용 현황 초기값 - useEffect(() => { - if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; - if (!pbnstSttn.isInit) { - getFlcts() - } - }, [seletectedLayerNm, pbnstSttn.isInit]); - useEffect(() => { - if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; - pbnSttnInit("1", "20", { - partValue: "A", - sidoValue: '0', - sigunValue: "0", - regionValue: "", - unitWaterShedValue: "", - middleRegionValue: "", - envPartValue: "", - sidoText: "", - sigunText: "" - }, String(new Date().getFullYear()), pbnstSttn.fclts); - }, [fclts, pbnSttnInit, pbnstSttn.fclts, seletectedLayerNm]) - useEffect(() => { - setBdstTable(pbnstSttn.pbnstSttnRes); - }, [seletectedLayerNm, pbnstSttn.pbnstSttnRes]); - - // 재이용시설 조회 - // 재이용시설 페이징처리 관련 함수 - const onPageChangeHandler = useCallback((page: number) => { - if (seletectedLayerNm !== '하수재이용시설' || viewMode !='list') return; - pbnstSttnSearch( - false, - String(page), - String(20), - { - partValue: "A", - sidoValue: "0", - sigunValue: "0", - regionValue: "", - unitWaterShedValue: "", - middleRegionValue: "", - envPartValue: "", - sidoText: "", - sigunText: "", - }, - "", - String(new Date().getFullYear()), fclts - ); - }, [fclts, pbnstSttnSearch]); - // FIXME: 윤선화차장님 요구사항으로 엑셀 다운로드 삭제. - // const excelClick = useCallback(() => { - // // if (codeData) pbnstSttnSearch(1, "10000", codeData); - // excelDownload( - // [[]], - // "하수재이용시설 현황", - // "sample_pbnstSttn.xlsx", - // "A1:U2" - // ); - // }, [pbnstSttnSearch]); - return ( - viewMode == 'detail' ? - // 재이용시설 상세 - <> - <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), - }))} - /> - </div> - <PbnstSttnModal - data={actTabData?.data[0] || ({} as customPbnst)} - titleVisible={false} - /> - </> : - <div style={{ overflowY: 'auto' }}> - <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 || []} - headlist={pbnstSttn.pbnstSttHeadList} - pageSize={20} - total={pbnstSttnResCount || 0} - cellClick={(index: number | undefined) => { - pbnstCellClick(index); - }} - onPageChange={onPageChangeHandler} - > - <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> - </UiTable> - </div> - ) -} -export default ResueFacility; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx deleted file mode 100644 index 9030493ff..000000000 --- a/apps/wr/app/(with-layout)/map/components/layerPopup/reuseMngFacility.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { useWrStore } from '@/app/store'; -import { tableData, formatPhoneNumber } from '@/components/lib/func/commom'; -import { Title, UiTable } from '@common/business_components/ui'; -import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form'; -import moment from 'moment'; -import React, { useEffect, useState } from 'react' -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - isDmdModal: { data: any | undefined }; -} -const ReuseMngFacility = ({seletectedLayerNm, viewMode, onFeatureSelect, onClose, isDmdModal}:Props) => { - const { code, - coSttn, - coSttnInit, - coSttnSearch, - } = useWrStore((state) => state); - const [mngTable, setMngTable] = useState<DemandCompType[]>(); - const [mngPage, setMngPage] = useState(1); - const { coSttnRes, coSttnResCount, coSttHeadList } = coSttn; - useEffect(() => { - if (seletectedLayerNm !== '수요처' || viewMode != 'list') return; - if (!coSttn.isInit) { - coSttnInit("1", "20", "0"); - } - }, [coSttn.isInit, coSttnInit]); - const coMngCellClick = (index: number | undefined) => { - if (index !== undefined && mngTable !== undefined) { - onFeatureSelect(mngTable[index]); - onClose(); - } - }; - useEffect(() => { - if (seletectedLayerNm !== '수요처' || viewMode!='list') return; - if (coSttnRes) { - if (coSttnRes?.length > 0 && code.cityCd.length > 0) { - const data = tableData(coSttnRes, { code }); - const chData = data.map((item: any) => ({ - ...item, - telno: formatPhoneNumber(item.telno || undefined), - regDt: moment(item.regDt).format("YYYY-MM-DD"), - dmdInfoId: `${item.dmdInfoId.slice(0, 3)}-${item.dmdInfoId.slice(3, 5)}-${item.dmdInfoId.slice(5, 10)}-${item.dmdInfoId.slice(10)}` - })); - // .filter((item: any) => item !== undefined); - setMngTable(chData); - } - } - }, [coSttnRes, code]); - useEffect(() => { - if (seletectedLayerNm !== '수요처' || viewMode!='list') return; - coSttnSearch(String(mngPage), "20", String(0)); - }, [coSttnSearch, mngPage]); - return ( - viewMode == 'detail' - ? ( - <div style={{ overflowX: 'hidden' }}> - <div className="flex justify-between items-center mb-4"> - <Title title="수요처 상세정보" /> - </div> - {/* 높이 조정 */} - <UiTable - tableData={isDmdModal?.data || []} - headlist={coSttHeadList.slice(0, 3)} - pageSize={1} - total={0} - headName={"위치정보"} - cellClick={() => { }} - onPageChange={() => { }} - /> - <UiTable - tableData={isDmdModal?.data || []} - headlist={coSttHeadList.slice(3)} - pageSize={1} - total={0} - headName={"기본정보"} - cellClick={() => { }} - onPageChange={() => { }} - /> - </div> - ) : (<div> - <div className="flex justify-between items-center"> - <Title title="수요처 현황" /> - </div> - <UiTable - headName={[]} - tableData={mngTable || []} - headlist={coSttHeadList} - pageSize={20} - total={coSttnResCount + 10 || 0} - cellClick={(index: number | undefined) => { - coMngCellClick(index); - // setUpdateData(coSttnRes[index as number]); - }} - onPageChange={(page) => { - setMngPage(page); - }} - ></UiTable></div>) - ) -} - -export default ReuseMngFacility \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx b/apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx deleted file mode 100644 index dc2537c95..000000000 --- a/apps/wr/app/(with-layout)/map/components/layerPopup/rswtFacility.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useWrStore } from "@/app/store"; -import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import { tableData } from "@/components/lib/func/commom"; -import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; -import { Title, UiTable } from "@common/business_components/ui"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { useEffect, useState } from "react"; -interface Props { - seletectedLayerNm: string; - viewMode: 'list' | 'detail' | 'nothing'; - onFeatureSelect: (feature: any) => void; - onClose: () => void; - rswtrDetailModal: { isOpen: boolean; data: customRswtBdst | undefined }; -} -const RswtFacility = ({ seletectedLayerNm, viewMode, onFeatureSelect, onClose, rswtrDetailModal }: Props) => { - const { code, rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore( - (state) => state - ); - const { rswtSttnRes, rswtSttnResCount } = rswtSttn; - const [rswtrTable, setRswtrTable] = useState<customRswtBdst[]>() - const [rswtrPage, setRswtrPage] = useState(1); - // 중수도시설 cellClick 이벤트 (상세정보) - const rswtCellClick = (index: number | undefined, headId: string) => { - if (headId !== 'chBuildingYn' && index !== undefined && rswtrTable !== undefined) { - // setRswtrDetailModal({ isOpen: true, data: rswtrTable[index] }); - // setViewMode('detail') - onFeatureSelect(rswtrTable[index]); - onClose(); - } - } - useEffect(() => { - if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; - if (!rswtSttn.isInit) { - rswtSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); - } - }, [code.cityCd, code.sggCd, rswtSttn.isInit, rswtSttnInit]); - - useEffect(() => { - if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; - const data = tableData(rswtSttnRes, { code }); - const chData = data - .map((item: customRswtBdst) => { - return { - ...item, - ...item.reuseBuilding[0], - ...item.reuseBuilding[0]?.rswtrObj, - chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N', - instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst, - instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt, - archArea: item?.archArea.split('.')[0] !== '-1' ? item?.archArea.split('.')[0] : '확인불가' - } - }) - .filter( - (item: customRswtBdst) => - item.reuseBuilding[0]?.rswtrObj !== undefined - ); - setRswtrTable(chData); - }, [code, rswtSttnRes]); - // FIXME: 윤선화 차장님 요구사항으로 엑셀 다운로드 삭제. - // const rswtSttnExcelDownload = useCallback(() => { - // if (rswtSttn.excelList.length > 0) { - // if (rswtSttn.excelList.length === 0) return; - // excelDownload( - // rswtSttn.excelList, - // "중수도시설 현황", - // "sample_rswtSttn.xlsx", - // "A1:W3", - // ); - // } - // }, [rswtSttn.excelList]) - - useEffect(() => { - if (seletectedLayerNm !== '중수도시설' || viewMode != 'list') return; - rswtSttnSearch(false, rswtrPage, "20", '', '', code.cityCd, code.sggCd); - }, [code.cityCd, code.sggCd, rswtSttnSearch, rswtrPage]); - return ( - viewMode == 'detail' ? - // 중수도시설 상세 - ( - <SttnDetailModal type={"RST"} formObj={rswtrDetailModal.data as customRswtBdst} /> - ) : ( - <div style={{ overflowY: 'auto' }}> - <div className="flex justify-between items-center"> - <Title title="중수도시설 현황" /> - {/* <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={rswtSttnExcelDownload}> - 엑셀다운로드 - </Button> - </div> */} - </div> - <UiTable - headName={[]} - tableData={rswtrTable || []} - headlist={rswtSttn.rswtSttHeadList} - pageSize={20} - total={rswtSttnResCount} - cellClick={(index: number | undefined, headId: string) => { - rswtCellClick(index, headId); - }} - onPageChange={setRswtrPage} - > - <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> - </UiTable> - </div> - )) -} -export default RswtFacility; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx b/apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx deleted file mode 100644 index 11ca0f58f..000000000 --- a/apps/wr/app/(with-layout)/map/components/newWindowPopup.tsx +++ /dev/null @@ -1,183 +0,0 @@ -"use client" -import NewWindowPortal from '@/app/(with-layout)/map/components/newWindowPortal'; -import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import { useGisContext } from "@common/business_components/ui/map/Gis"; -import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; -import ResueFacility from './layerPopup/reuseFacility'; -import { detainSttn, fetchHasuDetail, fetchpbnstDetail } from '../../../(popUp-layout)/util'; -import HasuFacility from './layerPopup/hasuFacility'; -import RainFacility from './layerPopup/rainFacility'; -import RswtFacility from './layerPopup/rswtFacility'; -import HtdflFacility from './layerPopup/htdflFacility'; -import ReuseMngFacility from './layerPopup/reuseMngFacility'; - -interface NewWindowPopupProps { - featureData: any; - seletectedLayerNm?: string - onFeatureSelect: (data: any) => void; - onClose: () => void; -} - -const NewWindowPopup22: React.FC<NewWindowPopupProps> = ({ - featureData, - seletectedLayerNm, - onFeatureSelect, - onClose -}) => { - const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject<number[]>; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; - const [tabData, setTabData] = useState<{ id: string; name: string; data: any }[]>([]); - const [activeTab, setActiveTab] = useState<string>('0'); - const [viewMode, setViewMode] = useState<'list' | 'detail' | 'nothing'>('list'); - const [fcltPk, setFcltPk] = useState<string>(''); - - - // onClose 함수를 useCallback으로 메모이제이션 - const memoizedOnClose = useCallback(() => { - onClose(); - }, [onClose]); - - // 빗물재이용시설 변수 - const [rainDetailModal, setRainDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false }); - const [rainList, setRainList] = useState<customRainBdst[]>([]); - - // 중수도시설 변수 - const [rswtrDetailModal, setRswtrDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }); - const [rswtrList, setRswtrList] = useState<customRswtBdst[]>([]); - - // 온배수시설 변수 - const [htdflDetailModal, setHtdflDetailModal] = useState<{ isOpen: boolean, data: customHtdflBdst | undefined }>({ data: undefined, isOpen: false }); - const [htdflList, setHtdflList] = useState<customHtdflBdst[]>([]); - - // 하수처리시설 변수 - const [hasuList, setHasuList] = useState<pubHasuType[]>([]); - const [isRuseReg, setIsRuseReg] = useState<{ - data: any | undefined; - }>({ data: undefined }); - - // 수요처관리 변수 - const [isDmdModal, setIsDmdModal] = useState<{ - isMoal: boolean; - data: any | undefined; - }>({ isMoal: false, data: undefined }); - const [mngList, setMngList] = useState<DemandCompType[]>([]); - - ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// - const getSelectedLayers = () => { - console.trace('호출확인', 1) - let result = null; - const layers = gisMap ? gisMap.getLayers().getArray().filter((l: any) => l.getVisible()) : []; // gisMap이 null인지 확인 후 레이어 가져오기 - let featureLayer: { get: (key: string) => any } = { get: () => null }; - layers.forEach((layer: any) => { - const source = layer.getSource(); - if (source && source.hasFeature && featureData - && typeof featureData.getId === 'function' && source.hasFeature(featureData)) { - featureLayer = layer; // 피처가 속한 레이어 찾기) - } - }); - result = featureLayer.get('lyrNm'); - return result; - }; - // 상세 목록 데이터 상태 처리 - useEffect(() => { - if (hasuList.length > 0) setIsRuseReg({ data: [hasuList[0]] }); - }, [hasuList]) - useEffect(() => { - if (rainList.length > 0) setRainDetailModal({ isOpen: true, data: rainList[0] }); - }, [rainList]) - useEffect(() => { - if (rswtrList.length > 0) setRswtrDetailModal({ isOpen: true, data: rswtrList[0] }); - }, [rswtrList]) - useEffect(() => { - if (htdflList.length > 0) setHtdflDetailModal({ isOpen: true, data: htdflList[0] }); - }, [htdflList]) - useEffect(() => { - if (mngList.length > 0) setIsDmdModal({ isMoal: true, data: [mngList[0]] }); - }, [mngList]) - - const lastCalledIdRef = useRef<string | null>(null); - const [layerId, setLayerId] = useState<string | null>(); - - useEffect(() => { - const layers = getSelectedLayers(); - setLayerId(layers); - }, []); // 최초 렌더링 시 호출 - - // 피쳐 데이터가 변경될 때마다 호출 - useEffect(() => { - if (!featureData || typeof featureData.getProperties !== "function" || featureData.getProperties() == '') return; - const selectedProps = featureData.getProperties(); - const currentId = featureData.getId?.() || selectedProps?.id || selectedProps?.fid; - // 유효하지 않은 ID는 아예 무시 - if (!currentId || typeof currentId !== 'string') return; - // 이전과 동일하면 무시 - if (!currentId || currentId === lastCalledIdRef.current) return; - lastCalledIdRef.current = currentId // 새로운 피처일 때만 API 호출 - const layerId = getSelectedLayers?.(); - if (!layerId || typeof layerId !== 'string') return; - const featureCd = - layerId === '하수재이용시설' ? selectedProps?.swtrmt_fclt_cd : - ['빗물이용시설', '중수도시설', '온배수시설', '수요처'].includes(layerId) ? selectedProps?.bdst_nm : - layerId === '하수처리시설' ? selectedProps?.swtrmt_fclt_nm : - null; - if (!featureCd || featureCd === fcltPk) return; - if (layerId === '하수재이용시설') { - fetchpbnstDetail(featureCd, setTabData); - } else if (layerId === '하수처리시설') { - fetchHasuDetail(featureCd, selectedProps?.swtrmt_fclt_cd).then((data) => { setHasuList(data) }) - } else { - detainSttn(featureCd, layerId).then((res) => { - if (layerId === '빗물이용시설') setRainList(res); - else if (layerId === '중수도시설') setRswtrList(res); - else if (layerId === '온배수시설') { setHtdflList(res); setHtdflDetailModal({ isOpen: true, data: res[0] }); } - else if (layerId === '수요처') setMngList(res); - }); - } - setFcltPk(featureCd); - setActiveTab(featureCd); - setViewMode("detail"); - }, [featureData]); - ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// - - // 체크된 레이어에 따른 조건부 컴포넌트 렌더링 함수 - const renderConditionalContent = () => { - const actTabData = tabData.find((tab) => tab.id === activeTab); - if (layerId === null || layerId === undefined) { - setLayerId(seletectedLayerNm || ''); - } - switch (layerId) { - case '하수재이용시설': - return (<ResueFacility viewMode={viewMode} seletectedLayerNm={layerId} tabData={tabData} actTabData={actTabData} setFcltPk={setFcltPk} onFeatureSelect={onFeatureSelect} onClose={onClose} />) - case '하수처리시설': - return (<HasuFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} isRuseReg={isRuseReg} />) - case '빗물이용시설': - return (<RainFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} rainDetailModal={rainDetailModal} />) - case '중수도시설': - return (<RswtFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} rswtrDetailModal={rswtrDetailModal} />) - case '온배수시설': - return (<HtdflFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} htdflDetailModal={htdflDetailModal} />) - case '수요처': - return(<ReuseMngFacility seletectedLayerNm={layerId} viewMode={viewMode} onFeatureSelect={onFeatureSelect} onClose={onClose} isDmdModal={isDmdModal} />) - default: - break; - } - return null; // 조건에 맞는 콘텐츠가 없을 경우 - }; - return ( - viewMode == 'nothing' ? <></> : - <NewWindowPortal - onClose={memoizedOnClose} - title="시설 상세 정보" - scrollbars='yes' - viewMode={viewMode} - resizable='no'> - {/* 체크된 레이어에 따른 조건부 렌더링 */} - {renderConditionalContent()} - </NewWindowPortal> - ); -}; - -export default NewWindowPopup22; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx b/apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx deleted file mode 100644 index 6a9009c6b..000000000 --- a/apps/wr/app/(with-layout)/map/components/newWindowPortal.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import React, { useState, useEffect, useRef, useCallback } from 'react'; -import { createPortal } from 'react-dom'; - -// 현재 문서의 스타일(CSS)을 새 창으로 복사하는 함수 -const copyStyles = (sourceDoc: Document, targetDoc: Document) => { - Array.from(sourceDoc.styleSheets).forEach(styleSheet => { - try { - if (styleSheet.cssRules) { // <style> 태그로 주입된 CSS - const newStyleEl = sourceDoc.createElement('style'); - Array.from(styleSheet.cssRules).forEach(cssRule => { - newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText)); - }); - targetDoc.head.appendChild(newStyleEl); - } else if (styleSheet.href) { // <link> 태그로 연결된 CSS 파일 - const newLinkEl = sourceDoc.createElement('link'); - newLinkEl.rel = 'stylesheet'; - newLinkEl.href = styleSheet.href; - targetDoc.head.appendChild(newLinkEl); - } - } catch (e) { - console.warn('스타일시트를 복사할 수 없습니다:', e); - } - }); -}; - -interface NewWindowPortalProps { - children: React.ReactNode; - onClose: () => void; - title?: string; - width?: number; - height?: number; - resizable?: string; - scrollbars?: string; - viewMode?: 'list' | 'detail' | 'nothing'; -} - -const NewWindowPortal22: React.FC<NewWindowPortalProps> = ({ children, onClose, title = "", resizable = "yes", scrollbars = "yes", viewMode }) => { - const [container, setContainer] = useState<HTMLElement | null>(null); - const newWindowRef = useRef<Window | null>(null); - const onCloseRef = useRef(onClose); - - // onClose 함수를 ref로 저장하여 의존성 문제 해결 - useEffect(() => { - onCloseRef.current = onClose; - }, [onClose]); - - const handleUnload = useCallback(() => { - onCloseRef.current(); - }, []); - useEffect(() => { - if (newWindowRef.current) { - if (viewMode == 'detail') { - newWindowRef.current.resizeTo(1100, 700); - } else { - newWindowRef.current.resizeTo(screen.availWidth, screen.availHeight); - } - } - }, [viewMode]); - useEffect(() => { - // 이미 창이 열려있으면 새로 열지 않음 - if (newWindowRef.current && !newWindowRef.current.closed) return; - // 브라우저 화면 정보 - const screenLeft = window.screenLeft ?? window.screenX; - const screenTop = window.screenTop ?? window.screenY; - const screenWidth = window.innerWidth ?? document.documentElement.clientWidth; - const screenHeight = window.innerHeight ?? document.documentElement.clientHeight; - - // 중앙 위치 계산 - const left = screenLeft + (screenWidth - window.screen.width) / 2; - const top = screenTop + (screenHeight - window.screen.height) / 2; - - // 1. 새 창을 열고 참조를 저장합니다. - const popupOptions = `width=${window.screen.width},height=${window.screen.height},left=${left}, top=${top}, resizable=${resizable},scrollbars=${scrollbars}`; - newWindowRef.current = window.open('', title, popupOptions); - - if (newWindowRef.current) { - newWindowRef.current.document.title = title; - - // 2. React 컴포넌트를 마운트할 컨테이너 div를 생성하여 새 창의 body에 추가합니다. - const div = newWindowRef.current.document.createElement('div'); - newWindowRef.current.document.body.appendChild(div); - setContainer(div); - - // 3. 메인 창의 스타일을 새 창으로 복사합니다. (매우 중요) - copyStyles(document, newWindowRef.current.document); - // 4. 사용자가 창을 닫을 때 부모에게 알리기 위한 이벤트 리스너를 설정합니다. - // const handleUnload = () => { - // onClose(); - // }; - newWindowRef.current.addEventListener('unload', handleUnload); - - // 5. 컴포넌트가 사라질 때 창을 닫는 클린업 함수를 반환합니다. - return () => { - if (newWindowRef.current) { - newWindowRef.current.removeEventListener('unload', handleUnload); - if (!newWindowRef.current.closed) { - newWindowRef.current.close(); - } - } - }; - } else { - alert('팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.'); - onCloseRef.current(); - // onClose(); - } - }, [handleUnload, onClose, title]); - - // `createPortal`을 사용해 children을 새 창의 container div에 렌더링합니다. - return container ? createPortal(children, container) : null; -}; - -export default NewWindowPortal22; \ No newline at end of file diff --git a/apps/wr/app/(with-layout)/map/popup/page.tsx b/apps/wr/app/(with-layout)/map/popup/page.tsx index 6c1cc47d0..ca7a07b43 100644 --- a/apps/wr/app/(with-layout)/map/popup/page.tsx +++ b/apps/wr/app/(with-layout)/map/popup/page.tsx @@ -1,149 +1,153 @@ -"use client"; +// "use client"; -import Gis from "@common/business_components/ui/map/Gis"; -import { useEffect, useRef, useState, useCallback } from "react"; -import { mapService } from "../service"; -import NewWindowPopup from "../components/newWindowPopup"; -import GisApp from "@common/business_components/ui/map/lib/gis.core"; +// import Gis from "@common/business_components/ui/map/Gis"; +// import { useEffect, useRef, useState, useCallback } from "react"; +// import { mapService } from "../service"; +// import NewWindowPopup from "../components/newWindowPopup"; +// import GisApp from "@common/business_components/ui/map/lib/gis.core"; -const Map = () => { - const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 - const gisMaps = useRef<any | null>(null); - const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 - const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태 - const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터 - const [checkedLayers, setCheckedLayers] = useState<string[]>([]); - const [checkedLayersData, setCheckedLayersData] = useState<any[]>([]); +// const Map = () => { +// const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 +// const gisMaps = useRef<any | null>(null); +// const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 +// const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태 +// const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터 +// const [checkedLayers, setCheckedLayers] = useState<string[]>([]); +// const [checkedLayersData, setCheckedLayersData] = useState<any[]>([]); - const fetchData = async () => { - try { - const response = await mapService.getLyrStngs(); - setTreeData(response); // API 응답 저장 - } catch (error) { - console.error("데이터 불러오기 실패:", error); - } - }; +// const fetchData = async () => { +// try { +// const response = await mapService.getLyrStngs(); +// setTreeData(response); // API 응답 저장 +// } catch (error) { +// console.error("데이터 불러오기 실패:", error); +// } +// }; - // 팝업 닫기 핸들러를 useCallback으로 메모이제이션 - const handlePopupClose = useCallback(() => { - setIsOpen(false); - setFeatureData(null); - }, []); +// // 팝업 닫기 핸들러를 useCallback으로 메모이제이션 +// const handlePopupClose = useCallback(() => { +// setIsOpen(false); +// setFeatureData(null); +// }, []); - // 컴포넌트 마운트 시 1회 실행 - useEffect(() => { - fetchData(); - }, []); +// // 컴포넌트 마운트 시 1회 실행 +// useEffect(() => { +// fetchData(); +// }, []); - // 체크된 레이어 정보를 받는 핸들러 - const handleCheckedLayersChange = (checkedIds: string[], checkedNodesData: any[]) => { - setCheckedLayers(checkedIds); - setCheckedLayersData(checkedNodesData); - }; +// // 체크된 레이어 정보를 받는 핸들러 +// const handleCheckedLayersChange = (checkedIds: string[], checkedNodesData: any[]) => { +// setCheckedLayers(checkedIds); +// setCheckedLayersData(checkedNodesData); +// }; - // SearchModal, GisContent 등에서 호출 - const onFeatureSelect = (data: any) => { - const map = gisMaps.current; - if (!map) { - console.warn("지도가 초기화되지 않았습니다."); - return; - } +// // SearchModal, GisContent 등에서 호출 +// const onFeatureSelect = (data: any) => { +// const map = gisMaps.current; +// if (!map) { +// console.warn("지도가 초기화되지 않았습니다."); +// return; +// } - // 항상 같은 select 객체 사용 - const select = GisApp.Module.select as any; - if (!select) return; +// // 항상 같은 select 객체 사용 +// const select = GisApp.Module.select as any; +// if (!select) return; - // 1. 기존 선택 초기화 - select.resetSelectedFeature(); +// // 1. 기존 선택 초기화 +// select.resetSelectedFeature(); - // 2. data가 OpenLayers Feature 인스턴스인지 확인 - let foundFeature: any = null; - if ( - data && - typeof data.getGeometry === "function" && - typeof data.setStyle === "function" - ) { - // 이미 Feature 인스턴스라면 그대로 사용 - foundFeature = data; - } else { - // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용 - const featureId = data.fid || data.ftrIdn || data.id; - map - .getLayers() - .getArray() - .forEach((layer: any) => { - const source = layer.getSource?.(); - if (source?.getFeatureById) { - const feature = source.getFeatureById(String(featureId).trim()); - if (feature) foundFeature = feature; - } - }); - } +// // 2. data가 OpenLayers Feature 인스턴스인지 확인 +// let foundFeature: any = null; +// if ( +// data && +// typeof data.getGeometry === "function" && +// typeof data.setStyle === "function" +// ) { +// // 이미 Feature 인스턴스라면 그대로 사용 +// foundFeature = data; +// } else { +// // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용 +// const featureId = data.fid || data.ftrIdn || data.id; +// map +// .getLayers() +// .getArray() +// .forEach((layer: any) => { +// const source = layer.getSource?.(); +// if (source?.getFeatureById) { +// const feature = source.getFeatureById(String(featureId).trim()); +// if (feature) foundFeature = feature; +// } +// }); +// } - // 3. 피처 선택 - if (foundFeature) { - const geometry = foundFeature.getGeometry(); - if (geometry) { - const extent = geometry.getExtent(); +// // 3. 피처 선택 +// if (foundFeature) { +// const geometry = foundFeature.getGeometry(); +// if (geometry) { +// const extent = geometry.getExtent(); - map.getView().fit(extent, { - duration: 300, - padding: [50, 50, 50, 50], - maxZoom: 16, - constrainResolution: true, - nearest: true, - }); - } - select.selectFeature(foundFeature, true); - } else { - console.warn("OpenLayers Feature를 찾을 수 없습니다:", data); - } +// map.getView().fit(extent, { +// duration: 300, +// padding: [50, 50, 50, 50], +// maxZoom: 16, +// constrainResolution: true, +// nearest: true, +// }); +// } +// select.selectFeature(foundFeature, true); +// } else { +// console.warn("OpenLayers Feature를 찾을 수 없습니다:", data); +// } - setFeatureData(data); - setIsOpen(true); - setIsSearchModalOpen(false); - }; +// setFeatureData(data); +// setIsOpen(true); +// setIsSearchModalOpen(false); +// }; - // MapSearchBar 래퍼 컴포넌트 - // const CustomMapSearchBar = (props: any) => { - // return ( - // <MapSearchBar - // {...props} - // searchType="공급처 후보지 조회" - // showApplyButton={false} - // /> - // ); - // }; +// // MapSearchBar 래퍼 컴포넌트 +// // const CustomMapSearchBar = (props: any) => { +// // return ( +// // <MapSearchBar +// // {...props} +// // searchType="공급처 후보지 조회" +// // showApplyButton={false} +// // /> +// // ); +// // }; - return ( - <div className="bg-container"> - <Gis - treeData={treeData} - isSearch={false} - gisMaps={gisMaps} - isMiniMap={false} - searchView={undefined} - detailView={(props: any) =>( - <NewWindowPopup - onClose={handlePopupClose} // 메모이제이션된 함수 사용 - checkedLayers={checkedLayers} - checkedLayersData={checkedLayersData} - {...props} - /> - )} - onFeatureSelect={onFeatureSelect} - setIsOpen={setIsOpen} - setFeatureData={setFeatureData} - featureData={featureData} - setIsSearchModalOpen={setIsSearchModalOpen} - isOpen={isOpen} - isSearchModalOpen={isSearchModalOpen} - onCheckedLayersChange={handleCheckedLayersChange} - imgVisble={true} - searchBar={undefined} - /> - </div> - ); -}; +// return ( +// <div className="bg-container"> +// <Gis +// treeData={treeData} +// isSearch={false} +// gisMaps={gisMaps} +// isMiniMap={false} +// searchView={undefined} +// detailView={(props: any) => +// // <NewWindowPopup +// // onClose={handlePopupClose} // 메모이제이션된 함수 사용 +// // checkedLayers={checkedLayers} +// // checkedLayersData={checkedLayersData} +// // {...props} +// // /> +// { -export default Map; +// console.log('p' ,props) +// } +// } +// onFeatureSelect={onFeatureSelect} +// setIsOpen={setIsOpen} +// setFeatureData={setFeatureData} +// featureData={featureData} +// setIsSearchModalOpen={setIsSearchModalOpen} +// isOpen={isOpen} +// isSearchModalOpen={isSearchModalOpen} +// onCheckedLayersChange={handleCheckedLayersChange} +// imgVisble={true} +// searchBar={undefined} +// /> +// </div> +// ); +// }; + +// export default Map; diff --git a/apps/wr/app/store/map/ldrmntCoMap/index.tsx b/apps/wr/app/store/map/ldrmntCoMap/index.tsx index f7b610e77..651fe21f2 100644 --- a/apps/wr/app/store/map/ldrmntCoMap/index.tsx +++ b/apps/wr/app/store/map/ldrmntCoMap/index.tsx @@ -1,4 +1,4 @@ -import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; import type { customLdrmnt } from "../../matDmd/ldrmntCoSttn"; import { @@ -26,6 +26,7 @@ type ldrmntMapActions = { con: string, coNm: string ) => void; + ldrmntMapDetile:(featureCd:string) => Promise<customLdrmnt | undefined>; }; export type ldrmntMapType = ldrmntMapState & ldrmntMapActions; @@ -97,6 +98,21 @@ export const ldrmntMapActionsExport: (set: any) => ldrmntMapActions = ( } catch (e) { console.log(e); } - }, + },ldrmntMapDetile: async (featureCd: string) => { + try { + + const ldrmtDetail = await getFetch(fetchType.WR, + `/reuseFc/request/temp/1/4/0/${featureCd}` ) + if(ldrmtDetail&&ldrmtDetail.length>0){ + + return ldrmtDetail[0]; + }else{ + return null; + } + } catch (error) { + console.log(error); + throw error; // 호출부에서 catch 가능하도록 + } + } }; }; diff --git "a/apps/wr/components/lib/func/\bmapUtil.ts" "b/apps/wr/components/lib/func/\bmapUtil.ts" index 41a8c09b4..f3925c413 100644 --- "a/apps/wr/components/lib/func/\bmapUtil.ts" +++ "b/apps/wr/components/lib/func/\bmapUtil.ts" @@ -3,11 +3,12 @@ export const getFeatureCd = (featurePropertise:any, layerNm:string) => { console.log('layerNm ', layerNm ) + console.log('featurePropertise ', featurePropertise ) const featureCd = layerNm === "하수재이용시설" ? featurePropertise?.swtrmt_fclt_cd - : ["빗물이용시설", "중수도시설", "온배수시설", "수요처"].includes( + : ["빗물이용시설", "중수도시설", "온배수시설", "수요처" ,'잠재수요처'].includes( layerNm ) ? featurePropertise?.bdst_nm @@ -15,5 +16,6 @@ ? featurePropertise?.swtrmt_fclt_nm : null; + console.log('featureCd ', featureCd) return featureCd; }; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/layerPopup/reuseMngFacility.tsx b/apps/wr/components/ui/map/LayerPopUp/PbnFacility/reuseMngFacility.tsx similarity index 100% rename from apps/wr/app/(popUp-layout)/layerPopup/reuseMngFacility.tsx rename to apps/wr/components/ui/map/LayerPopUp/PbnFacility/reuseMngFacility.tsx diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx index aef145cc1..80cdb5c4e 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx @@ -14,11 +14,13 @@ import type { z } from "zod"; export default function CoDetailModal({ formObj, onFormSubmit, - readonly + readonly, + isMap =false, }: { formObj: any; onFormSubmit: (values: customLdrmnt) => void; readonly?: boolean; + isMap?:boolean }) { const defaultValues: z.infer<typeof ldrmntZod> = ldrmntZod.parse({}); const form = useForm<z.infer<typeof ldrmntZod>>({ @@ -54,13 +56,18 @@ export default function CoDetailModal({ <h1 className="text-2xl font-medium text-label col-span-10"> 잠재수요처 상세정보 </h1> - <Button type="submit" - className="col-start-12 col-span-1" - size={"sm"} - disabled={readonly} - > - 저장 - </Button> + {!isMap ? ( + <Button + type="submit" + className="col-start-12 col-span-1" + size={"sm"} + disabled={readonly} + > + 저장 + </Button> + ) : ( + <></> + )} </div> <ScrollArea className="h-[79vh] mx-8"> <FormField