From 09673d144e2c264dab8d167c3114567bd6037777 Mon Sep 17 00:00:00 2001 From: JIeunhuh Date: Wed, 7 May 2025 16:57:34 +0900 Subject: [PATCH 01/10] =?UTF-8?q?api=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/map/featureClickEventPopup.tsx | 28 ++++------ apps/sn/app/map/table.ts | 65 +++++++++++----------- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/apps/sn/app/map/featureClickEventPopup.tsx b/apps/sn/app/map/featureClickEventPopup.tsx index 6dd573732..54de59668 100644 --- a/apps/sn/app/map/featureClickEventPopup.tsx +++ b/apps/sn/app/map/featureClickEventPopup.tsx @@ -19,6 +19,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; const featureId = featureData.getId(); // 피처의 속성 가져오기 const [layerNm, setLayerNm] = useState(""); // 레이어 이름 상태 + const [tableData, setTableData] = useState(null); // 피처 데이터 상태 // 피쳐데이터의 현재 레이어 이름 가져오는 함수 const getSelectedLayers = () => { const layers = gisMap.getLayers().getArray(); // gisMap에서 모든 레이어 가져오기 @@ -62,21 +63,16 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, updateData(inspectionData, setInspectionData); } }; - async function transformFeatureDataToArray(featureId: any, keys: string[]) { - const data = await getData(`v1/map/features/${featureId}`); - // 필요한 키만 추출하여 새로운 객체 생성 - console.log("data", data); - const transformedData = keys.reduce((acc, key) => { - acc[key] = data[key] !== undefined ? data[key] : "N/A"; // 값이 없으면 "N/A"로 처리 - return acc; - }, {} as Record); - - // 배열로 감싸서 반환 - return [transformedData]; - } - const keys = SwtrmtFcltCol.map((column) => column.id); - const transformedFeatureData = transformFeatureDataToArray(featureId, keys); - useEffect(() => { setLayerNm(getSelectedLayers()) }, [featureId]); + useEffect(() => { + // const fetchData = async () => { + // if (featureId) { + setLayerNm(getSelectedLayers()); + // } + // const data = await getData(`v1/map/features/${featureId}`); + // setTableData(data); + // }; + // fetchData(); + }, [featureId]); const renderSection = (title: string, data: { year: string; type: string }[], sectionKey: string) => (
{/* 섹션 제목 */} @@ -127,7 +123,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
- Date: Wed, 7 May 2025 18:23:40 +0900 Subject: [PATCH 02/10] =?UTF-8?q?=EC=84=A0=ED=83=9D=EB=90=9C=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=EC=97=90=20=EB=A7=9E=EC=B6=B0=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=EB=B3=80=EA=B2=BD=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/map/featureClickEventPopup.tsx | 33 +++++++++++++++------- apps/sn/app/map/table.ts | 15 +++++++++- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/apps/sn/app/map/featureClickEventPopup.tsx b/apps/sn/app/map/featureClickEventPopup.tsx index 54de59668..435e5710d 100644 --- a/apps/sn/app/map/featureClickEventPopup.tsx +++ b/apps/sn/app/map/featureClickEventPopup.tsx @@ -2,7 +2,7 @@ import { VerticalTable } from "@/components/verticalTable"; import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui"; import { use, useEffect, useState } from "react"; -import { SwtrmtFcltCol } from "./table"; +import { SwtrmtFcltCol, SwtrmtPrcsZoneCol } from "./table"; import { useGisContext } from "@common/business_components/ui/map/Gis"; import { getData } from "@/components/lib/api"; const inputColumn = [ @@ -20,6 +20,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, const featureId = featureData.getId(); // 피처의 속성 가져오기 const [layerNm, setLayerNm] = useState(""); // 레이어 이름 상태 const [tableData, setTableData] = useState(null); // 피처 데이터 상태 + const [headlist, setHeadlist] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태 // 피쳐데이터의 현재 레이어 이름 가져오는 함수 const getSelectedLayers = () => { const layers = gisMap.getLayers().getArray(); // gisMap에서 모든 레이어 가져오기 @@ -64,14 +65,26 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, } }; useEffect(() => { - // const fetchData = async () => { - // if (featureId) { - setLayerNm(getSelectedLayers()); - // } - // const data = await getData(`v1/map/features/${featureId}`); - // setTableData(data); - // }; - // fetchData(); + const fetchData = async () => { + if (featureId) { + const selectedLayerName = getSelectedLayers(); // 레이어 이름 가져오기 + setLayerNm(selectedLayerName); // 상태 업데이트 + + const data = await getData(`v1/map/features/${featureId}`); + switch (selectedLayerName) { + case '하수처리시설': + setHeadlist(SwtrmtFcltCol); + break; + case '하수처리구역': + setHeadlist(SwtrmtPrcsZoneCol) + break; + default: + break; + } + setTableData(data); + }; + } + fetchData(); }, [featureId]); const renderSection = (title: string, data: { year: string; type: string }[], sectionKey: string) => (
@@ -123,7 +136,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
- Date: Fri, 9 May 2025 13:11:01 +0900 Subject: [PATCH 03/10] =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EB=B3=84=EB=A1=9C=20=EA=B0=9C=EB=B3=84=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EB=8F=99=EC=A0=81=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/{ => ui}/verticalTable.tsx | 0 apps/sn/app/map/components/InputSection.tsx | 50 ++++++++ apps/sn/app/map/components/SwtrmtFclt.tsx | 60 ++++++++++ apps/sn/app/map/components/index.ts | 18 +++ apps/sn/app/map/featureClickEventPopup.tsx | 113 ++++-------------- 5 files changed, 151 insertions(+), 90 deletions(-) rename apps/sn/app/components/{ => ui}/verticalTable.tsx (100%) create mode 100644 apps/sn/app/map/components/InputSection.tsx create mode 100644 apps/sn/app/map/components/SwtrmtFclt.tsx create mode 100644 apps/sn/app/map/components/index.ts diff --git a/apps/sn/app/components/verticalTable.tsx b/apps/sn/app/components/ui/verticalTable.tsx similarity index 100% rename from apps/sn/app/components/verticalTable.tsx rename to apps/sn/app/components/ui/verticalTable.tsx diff --git a/apps/sn/app/map/components/InputSection.tsx b/apps/sn/app/map/components/InputSection.tsx new file mode 100644 index 000000000..6c411e2cf --- /dev/null +++ b/apps/sn/app/map/components/InputSection.tsx @@ -0,0 +1,50 @@ +import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@common/components/ui"; +import React from "react"; + +interface InputSectionProps { + title: string; + data: { year: string; type: string }[]; + sectionKey: string; + onInputChange: (section: string, index: number, field: string, value: string) => void; +} + +const InputSection: React.FC = ({ title, data, sectionKey, onInputChange }) => { + return ( +
+ {/* 섹션 제목 */} +
+

{title}

+
+ {/* 테이블 */} +
+ + + + 년도 + 구분 + + + + {data.map((row, index) => ( + + + onInputChange(sectionKey, index, "year", e.target.value)} + className="w-full text-xl border-radius-0 px-3 py-2 text-base text-center leading-normal" + /> + + + {row.type} + + + ))} + +
+
+
+ ); +}; + +export default InputSection; \ No newline at end of file diff --git a/apps/sn/app/map/components/SwtrmtFclt.tsx b/apps/sn/app/map/components/SwtrmtFclt.tsx new file mode 100644 index 000000000..66adaa394 --- /dev/null +++ b/apps/sn/app/map/components/SwtrmtFclt.tsx @@ -0,0 +1,60 @@ +import { VerticalTable } from '@/components/ui/verticalTable'; +import React, { useState } from 'react' +import InputSection from './InputSection'; +// 하수처리시설 +// TODO: 컬럼에 보고서 엉 ? 이거 버튼누르면 팝업으로 상세화면 띄워주는 건지 확인 필요 +const inputColumn = [ + { id: "title", title: "설치주제", type: "select", options: ["BTL", "재정사업"] }, + { id: "guyeok", title: "처리구역", type: "select", options: ["구역1", "구역2"] }, + { id: "basu", title: "배수구역", type: "input" }, + { id: "bungu", title: "배수분구", type: "input" }, + { id: "wltjs", title: "지선/간선", type: "select", options: ["지선", "간선"] }, + { id: "flow", title: "흐름방식", type: "select", options: ["자연유하", "압송"] }, + { id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] }, +]; +const SwtrmtFclt = () => { + const [repairData, setRepairData] = useState([ + { year: "2025", type: "개대체" }, + { year: "2025", type: "보수" }, + ]); + const [cleaningData, setCleaningData] = useState([ + { year: "2025", type: "청소" }, + { year: "2025", type: "준설" }, + ]); + const [inspectionData, setInspectionData] = useState([ + { year: "2025", type: "관로기술진단" }, + { year: "2025", type: "관로기술진단" }, + ]); + + const handleInputChange = (section: string, index: number, field: string, value: string) => { + const updateData = ( + data: { year: string; type: string }[], + setData: React.Dispatch> + ) => { + const updated = [...data]; + if (updated[index]) { + updated[index][field as keyof typeof updated[number]] = value; + } + setData(updated); + }; + + if (section === "repair") { + updateData(repairData, setRepairData); + } else if (section === "cleaning") { + updateData(cleaningData, setCleaningData); + } else if (section === "inspection") { + updateData(inspectionData, setInspectionData); + } + }; + return ( +
+ + + handleInputChange(section, index, field, value)} /> + handleInputChange(section, index, field, value)} />
+ ) +} + +export default SwtrmtFclt \ No newline at end of file diff --git a/apps/sn/app/map/components/index.ts b/apps/sn/app/map/components/index.ts new file mode 100644 index 000000000..6ec872d24 --- /dev/null +++ b/apps/sn/app/map/components/index.ts @@ -0,0 +1,18 @@ +import SwtrmtFclt from "./SwtrmtFclt"; + +// 레이어 이름과 컴포넌트를 매핑 +const layerContentMap: { [key: string]: { component: React.FC; props?: any; } } = { + "하수처리시설": { + component: SwtrmtFclt, + }, + "하수처리구역": {component : SwtrmtFclt,} +}; + +// 동적 컴포넌트 반환 함수 +export const getLayerContentComponent = (layerNm: string): React.FC => { + const component = layerContentMap[layerNm]; + if (!component) { + throw new Error(`Component not found for layer name: ${layerNm}`); + } + return component.component; +}; \ No newline at end of file diff --git a/apps/sn/app/map/featureClickEventPopup.tsx b/apps/sn/app/map/featureClickEventPopup.tsx index 435e5710d..b477fcdf8 100644 --- a/apps/sn/app/map/featureClickEventPopup.tsx +++ b/apps/sn/app/map/featureClickEventPopup.tsx @@ -1,10 +1,12 @@ 'use client' -import { VerticalTable } from "@/components/verticalTable"; +import { VerticalTable } from "@/components/ui/verticalTable"; import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui"; import { use, useEffect, useState } from "react"; import { SwtrmtFcltCol, SwtrmtPrcsZoneCol } from "./table"; import { useGisContext } from "@common/business_components/ui/map/Gis"; import { getData } from "@/components/lib/api"; +import InputSection from "./components/InputSection"; +import { getLayerContentComponent } from "./components"; const inputColumn = [ { id: "title", title: "설치주제", type: "select", options: ["BTL", "재정사업"] }, { id: "guyeok", title: "처리구역", type: "select", options: ["구역1", "구역2"] }, @@ -17,7 +19,7 @@ const inputColumn = [ // TODO: const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => { const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; - const featureId = featureData.getId(); // 피처의 속성 가져오기 + const featureId = featureData.getId(); // 피처의 id 가져오기 const [layerNm, setLayerNm] = useState(""); // 레이어 이름 상태 const [tableData, setTableData] = useState(null); // 피처 데이터 상태 const [headlist, setHeadlist] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태 @@ -33,93 +35,29 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, }); return featureLayer.get('lyrNm'); // 레이어 이름 출력 }; - const [repairData, setRepairData] = useState([ - { year: "2025", type: "개대체" }, - { year: "2025", type: "보수" }, - ]); - - const [cleaningData, setCleaningData] = useState([ - { year: "2025", type: "청소" }, - { year: "2025", type: "준설" }, - ]); - - const [inspectionData, setInspectionData] = useState([ - { year: "2025", type: "관로기술진단" }, - { year: "2025", type: "관로기술진단" }, - ]); - const handleInputChange = (section: string, index: number, field: string, value: string) => { - const updateData = (data: { year: string; type: string }[], setData: React.Dispatch>) => { - const updated = [...data]; - if (updated[index]) { - updated[index][field as keyof typeof updated[number]] = value; - } - setData(updated); - }; - - if (section === "repair") { - updateData(repairData, setRepairData); - } else if (section === "cleaning") { - updateData(cleaningData, setCleaningData); - } else if (section === "inspection") { - updateData(inspectionData, setInspectionData); - } - }; - useEffect(() => { + useEffect(() => { const fetchData = async () => { if (featureId) { const selectedLayerName = getSelectedLayers(); // 레이어 이름 가져오기 setLayerNm(selectedLayerName); // 상태 업데이트 - - const data = await getData(`v1/map/features/${featureId}`); - switch (selectedLayerName) { - case '하수처리시설': - setHeadlist(SwtrmtFcltCol); - break; - case '하수처리구역': - setHeadlist(SwtrmtPrcsZoneCol) - break; - default: - break; - } - setTableData(data); - }; - } + + const data = await getData(`v1/map/features/${featureId}`); + switch (selectedLayerName) { + case '하수처리시설': + setHeadlist(SwtrmtFcltCol); + break; + case '하수처리구역': + setHeadlist(SwtrmtPrcsZoneCol) + break; + default: + break; + } + setTableData(data); + }; + } fetchData(); }, [featureId]); - const renderSection = (title: string, data: { year: string; type: string }[], sectionKey: string) => ( -
- {/* 섹션 제목 */} -
-

{title}

-
- {/* 테이블 */} -
- - - - 년도 - 구분 - - - - {data.map((row, index) => ( - - - handleInputChange(sectionKey, index, "year", e.target.value)} - className="w-full text-xl border-radius-0 px-3 py-2 text-base text-center leading-normal" - /> - - {row.type} - - ))} - -
-
-
- ); + const ContentComponent = layerNm ? getLayerContentComponent(layerNm) : null; return (