diff --git a/packages/common/business_components/package.json b/packages/common/business_components/package.json index 1f02a708e..a338556dc 100644 --- a/packages/common/business_components/package.json +++ b/packages/common/business_components/package.json @@ -31,6 +31,7 @@ "@radix-ui/react-scroll-area": "^1.2.3", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-slot": "^1.1.2", + "axios": "1.8.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^3.6.0", diff --git a/packages/common/business_components/src/ui/map/GisTab.js b/packages/common/business_components/src/ui/map/GisTab.js index baf268879..b63b774bb 100644 --- a/packages/common/business_components/src/ui/map/GisTab.js +++ b/packages/common/business_components/src/ui/map/GisTab.js @@ -2,10 +2,13 @@ import React, { useState } from 'react'; import { Tabs, TabsList, TabsTrigger } from '@common/components/ui/tabs'; import GisTree from './GisTree'; import GisSearch from './GisSearch'; -import { ChevronLeft, ChevronRight } from 'lucide-react'; +import { ChevronLeft, ChevronRight, Search } from 'lucide-react'; +import SearchModal from './SearchModal'; + function GisTab({ visible, setVisible, isSearch }) { const [activeTab, setActiveTab] = useState('layers'); + const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); return ( <> @@ -17,21 +20,29 @@ function GisTab({ visible, setVisible, isSearch }) { 레이어 {isSearch && ( - 검색 + + // + // + // )} {/* GisTree는 항상 마운트되며, 탭 상태에 따라 보여주기만 함 */}
{/* GisSearch도 동일하게 처리 */} - {isSearch && ( + {/* {isSearch && (
- )} + )} */} + + + {/* 🔍 검색 모달 */} + {/* 접기 버튼 */} diff --git a/packages/common/business_components/src/ui/map/SearchModal.tsx b/packages/common/business_components/src/ui/map/SearchModal.tsx new file mode 100644 index 000000000..434ca99c8 --- /dev/null +++ b/packages/common/business_components/src/ui/map/SearchModal.tsx @@ -0,0 +1,377 @@ +import React from 'react'; +import axios from 'axios'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogClose, +} from '@common/components/ui/dialog'; +import { Button } from '@common/components'; +import { UiTable } from '../../ui'; + + +const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}`; + +const TABS = [ + { key: 'basic', label: '기본정보' }, + { key: 'operation', label: '운영정보' }, + { key: 'report', label: '하수도정비기본계획보고서' }, +]; + +const WORK_TYPES = [ + { key: 'maintenance', label: '보수 및 갱신' }, + { key: 'cleaning', label: '청소 및 준설' }, + { key: 'inspection', label: '점검 및 진단' }, +]; + +const YEARS = Array.from({ length: 150 }, (_, i) => `${2025 - i}`); + +const tableHeadlist = [ + { id: 'no', title: 'NO' }, + { id: 'fileNm', title: '파일명' }, + { id: 'manageYear', title: '년도' }, + { id: 'bungi', title: '분기' }, + { id: 'registDt', title: '등록 일자' }, + { id: 'registUsr', title: '등록자' } +] + +const tableData = [ + { 'no': '1', 'fileNm': '파일명', 'manageYear': '2023', 'registDt': '2025-04-16', 'registUsr': 'me', 'bungi': '1분기' }, + { 'no': '2', 'fileNm': '파일명', 'manageYear': '2024', 'registDt': '2025-04-16', 'registUsr': 'me2', 'bungi': '1분기' }, + { 'no': '3', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '4', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '5', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '6', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '7', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '8', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '9', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }, + { 'no': '10', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' } +] + +const BASIC_TYPES = [ + { key: 'SEWER_PIPE', label: '하수관로' }, + { key: 'TREATMENT_FACILITY', label: '하수처리시설' }, + { key: 'TREATMENT_AREA', label: '하수처리구역' }, + { key: 'MANHOLE', label: '하수맨홀' }, + { key: 'WASTEWATER_PUMP', label: '오수펌프' }, + { key: 'RAINWATER_PUMP', label: '빗물펌프' }, + { key: 'OUTFALL', label: '우수토실' }, + { key: 'RETENTION_FACILITY', label: '하수저류시설' }, + { key: 'PRIORITY_OUTFALL', label: '중점우수토실' }, +]; + +const sidoList = ['선택', '서울', '경기', '부산']; +const sigunguList = ['선택', '강남구', '서초구', '수원시']; +const 처리구역List = ['선택', 'A', 'B']; +const 하수관용도List = ['선택', '우수', '오수']; +const 관재질List = ['선택', 'PVC', 'PE']; +const 설치년도List = ['선택', ...YEARS]; +const 경과년도List = ['선택', '1', '2', '3']; + +// tableHeadlist, tableData 타입 예시 (실제 타입에 맞게 수정) +type TableHead = { + key: string; + label: string; +}; +type TableRow = Record; + +interface SearchModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +const SearchModal: React.FC = ({ open, onOpenChange }) => { + const [activeTab, setActiveTab] = React.useState('operation'); + const [workType, setWorkType] = React.useState(WORK_TYPES[0]?.key ?? ''); + const [startYear, setStartYear] = React.useState(''); + const [endYear, setEndYear] = React.useState(''); + const [showTable, setShowTable] = React.useState(false); + const [curPage, setCurPage] = React.useState(1); + const [basicType, setBasicType] = React.useState(BASIC_TYPES[0]?.key ?? ''); + const [관리번호, set관리번호] = React.useState(''); + const [시도, set시도] = React.useState(''); + const [시군구, set시군구] = React.useState(''); + const [처리구역, set처리구역] = React.useState(''); + const [하수관용도, set하수관용도] = React.useState(''); + const [관재질, set관재질] = React.useState(''); + const [설치년도1, set설치년도1] = React.useState(''); + const [설치년도2, set설치년도2] = React.useState(''); + const [경과년도, set경과년도] = React.useState(''); + const [연장1, set연장1] = React.useState(''); + const [연장2, set연장2] = React.useState(''); + + // cellClick 함수 타입 지정 + const handleCellClick = (row: TableRow, col: TableHead) => { + // 원하는 동작 구현 + console.log(row, col); + }; + + const modalMinWidth = 'min-w-[900px]'; + const modalMaxWidth = 'max-w-6xl'; + + // 모달 높이 동적 계산 + const contentRef = React.useRef(null); + const [dynamicHeight, setDynamicHeight] = React.useState(undefined); + + // API 호출 테스트 (axios 사용) + React.useEffect(() => { + // API_URL root 경로 확인 테스트 + console.log('API_URL:', API_URL); + + // lyrTypeNm과 cql_filter에 따른 API 호출 테스트 + axios.get(`${API_URL}/v1/map/features?lyrTypeNm=tb_ms_swage_prcs_zone&cql_filter=ctpv_nm='전라북도'`) + .then(res => { + console.log('API DATA:', res.data); // 실제 JSON 데이터 출력 + }) + .catch(err => { + console.error('API ERROR:', err); + }); + }, []); + + React.useEffect(() => { + if (contentRef.current) { + setDynamicHeight(contentRef.current.scrollHeight + 60); // 여유 padding + } + }, [activeTab, showTable, curPage, tableData.length]); + + return ( + + + + 검색 + + + {/* 탭 영역 */} +
+ {TABS.map(tab => ( + + ))} +
+ + {/* 기본정보 탭 */} + {activeTab === 'basic' && ( +
+ {/* 구분 */} +
+ + +
+ {/* 관리번호, 시도, 시군구 한 줄 */} +
+ + set관리번호(e.target.value)} /> + + + + +
+ {/* 처리구역, 하수관용도, 관재질 한 줄 */} +
+ + + + + + +
+ {/* 설치년도, 경과년도 한 줄 */} +
+ + + ~ + + + +
+ {/* 연장 한 줄 */} +
+ + set연장1(e.target.value)} /> + ~ + set연장2(e.target.value)} /> +
+ {/* 조회 버튼 중앙 정렬 */} +
+ +
+
+ )} + + {/* 운영정보 탭 */} + {activeTab === 'operation' && ( +
+
+ + + + + + ~ + +
+
+ +
+
+ )} + + {/* 하수도정비기본계획보고서서 탭 */} + {activeTab === 'report' && ( +
+ {/* 시도, 시군구, 하수처리구역 한 줄 */} +
+ + + + + + + +
+ {/* 승인년도 한 줄 */} +
+ + + ~ + +
+ {/* 조회 버튼 중앙 정렬 */} +
+ +
+
+ )} + + {/* 📋 결과 리스트 */} +
+ {/* 선택된 탭의 label */} +
+ {TABS.find(tab => tab.key === activeTab)?.label} +
+ {/* "▶" + 선택된 탭 label + " 조회 결과" */} +
+ ▶ {TABS.find(tab => tab.key === activeTab)?.label} 조회 결과 +
+ { }} onPageChange={function (page: number): void { + throw new Error('Function not implemented.') + }}> + +
+
+
+ ); +} + +export default React.memo(SearchModal); diff --git a/packages/common/business_components/src/ui/search_icon/index.tsx b/packages/common/business_components/src/ui/search_icon/index.tsx new file mode 100644 index 000000000..0ef0e17e3 --- /dev/null +++ b/packages/common/business_components/src/ui/search_icon/index.tsx @@ -0,0 +1,18 @@ +export default function SearchIcon() { + return ( + + + + ); + } \ No newline at end of file