797 lines
32 KiB
TypeScript
797 lines
32 KiB
TypeScript
import React from 'react';
|
|
import axios from 'axios';
|
|
import { UiModal } from '@common/business_components/ui/dialog_ui';
|
|
import { Button } from '@common/components';
|
|
import { UiTable2 } from '@common/business_components/ui/table/index-2';
|
|
import { CommonTableColumn } from "./table";
|
|
|
|
|
|
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: 100 }, (_, i) => `${2025 - i}`);
|
|
|
|
// 하수처리구역 테이블 헤더 리스트
|
|
const swageZoneTableHeadlist = [
|
|
// { id: 'ctpvCd', title: '시도코드' },
|
|
{ id: 'ctpvNm', title: '시도명' },
|
|
// { id: 'sggCd', title: '시군구코드' },
|
|
{ id: 'sggNm', title: '시군구명' },
|
|
// { id: 'swtrmtZoneSn', title: '하수처리구역번호' },
|
|
{ id: 'swtrmtZoneNm', title: '하수처리구역명' },
|
|
{ id: 'swtrmtFcltCd', title: '하수처리시설번호' },
|
|
{ id: 'swtrmtFcltNm', title: '하수처리시설명' },
|
|
]
|
|
// 하수처리시설 테이블 헤더 리스트
|
|
const swageFcltTableHeadlist = [
|
|
{ id: 'swtrmtFcltCd', title: '하수처리시설코드' },
|
|
{ id: 'swtrmtFcltNm', title: '하수처리시설명' },
|
|
{ id: 'fcltCpct', title: '시설용량' },
|
|
{ id: 'rgnExpln', title: '지역설명' },
|
|
{ id: 'cmcnYmd', title: '준공일자' },
|
|
{ id: 'oprtngStrtYmd', title: '가동개시일자' },
|
|
{ id: 'clsgYmd', title: '폐쇄일자' },
|
|
{ id: 'laeNm', title: '지자체명' },
|
|
{ id: 'ctpvNm', title: '시도명' },
|
|
{ id: 'sggNm', title: '시군구명' },
|
|
{ id: 'sareaNm', title: '권역명' },
|
|
{ id: 'lrgeSareaNm', title: '대권역명' },
|
|
{ id: 'rvrNm', title: '하천명' },
|
|
{ id: 'addr', title: '주소' },
|
|
{ id: 'daddr', title: '상세주소' },
|
|
{ id: 'rdnmAddr', title: '도로명주소' },
|
|
{ id: 'dtlRdnmAddr', title: '상세도로명주소' },
|
|
{ id: 'dschgWtstNm', title: '방류수계명' },
|
|
{ id: 'pllnArea', title: '부지면적' },
|
|
{ id: 'mngRprtvBzentyNm', title: '관리대행업제명' },
|
|
{ id: 'swtrmtPpltnCnt', title: '하수처리인구수' },
|
|
{ id: 'prcsZoneAreaSum', title: '처리구역면적합계' },
|
|
{ id: 'geom', title: 'geometry' },
|
|
{ id: 'xcrd', title: 'X좌표' },
|
|
{ id: 'ycrd', title: 'Y좌표' },
|
|
{ id: 'rprsMsrcCn', title: '대표공법내용' },
|
|
{ id: 'sttyCrtrBod', title: '법정기준생물화학적산소요구량' },
|
|
{ id: 'sttyCrtrToc', title: '법정기준TOC' },
|
|
{ id: 'sttyCrtrSs', title: '법정기준SS' },
|
|
{ id: 'sttyCrtrTn', title: '법정기준총질소' },
|
|
{ id: 'sttyCrtrTph', title: '법정기준총인' },
|
|
{ id: 'sttyCrtrClbclCnt', title: '법정기준대장균수' },
|
|
{ id: 'bsnNm', title: '유역명' },
|
|
];
|
|
|
|
// '구분' 선택 목록
|
|
const BASIC_TYPES = [
|
|
{ key: 'SEWER_PIPE', label: '하수관로' },
|
|
{ key: 'tb_il_swage_prcs_fclt', label: '하수처리시설' },
|
|
{ key: 'tb_ms_swage_prcs_zone', 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 = [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 26, name: '부산광역시' },
|
|
{ id: 28, name: '인천광역시' },
|
|
{ id: 30, name: '대전광역시' },
|
|
{ id: 41, name: '경기도' },
|
|
{ id: 42, name: '강원도' },
|
|
{ id: 44, name: '충청남도' },
|
|
{ id: 45, name: '전라북도' },
|
|
{ id: 46, name: '전라남도' },
|
|
{ id: 47, name: '경상북도' },
|
|
{ id: 48, name: '경상남도' },
|
|
];
|
|
|
|
// 시도별 시군구 리스트 매핑
|
|
const sigunguMap: Record<number, { id: number; name: string }[]> = {
|
|
26: [
|
|
{ id: 0, name: '선택' },
|
|
// ...부산산광역시의 시군구 추가
|
|
],
|
|
28: [
|
|
{ id: 0, name: '선택' },
|
|
// ...인천광역시의 시군구 추가
|
|
],
|
|
30: [
|
|
{ id: 0, name: '선택' },
|
|
// ...대전광역시의 시군구 추가
|
|
],
|
|
41: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 41820, name: '가평군' },
|
|
{ id: 41550, name: '안성시' },
|
|
{ id: 41830, name: '양평군' },
|
|
{ id: 41670, name: '여주시' },
|
|
{ id: 41500, name: '이천시' },
|
|
{ id: 41430, name: '의왕시' },
|
|
{ id: 41150, name: '의정부시' },
|
|
{ id: 41480, name: '파주시' },
|
|
{ id: 41650, name: '포천시' },
|
|
// ...경기도의 시군구 추가
|
|
],
|
|
42: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 42170, name: '동해시' },
|
|
{ id: 42110, name: '춘천시' },
|
|
{ id: 42720, name: '홍천군' },
|
|
// ...강원도의 시군구 추가
|
|
],
|
|
44: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 44770, name: '서천군' },
|
|
// ...충청남도의 시군구 추가
|
|
],
|
|
45: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 45130, name: '군산시' },
|
|
{ id: 45190, name: '남원시' },
|
|
{ id: 45730, name: '무주군' },
|
|
{ id: 45800, name: '부안군' },
|
|
{ id: 45770, name: '순창군' },
|
|
{ id: 45140, name: '익산시' },
|
|
{ id: 45750, name: '임실군' },
|
|
{ id: 45710, name: '완주군' },
|
|
{ id: 45110, name: '전주시' },
|
|
// ...전라북도의 시군구 추가
|
|
],
|
|
46: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 46810, name: "강진군" },
|
|
{ id: 46770, name: "고흥군" },
|
|
{ id: 46720, name: "곡성군" },
|
|
{ id: 46730, name: "구례군" },
|
|
{ id: 46230, name: "광양시" },
|
|
{ id: 46170, name: "나주시" },
|
|
{ id: 46110, name: "목포시" },
|
|
{ id: 46840, name: "무안군" },
|
|
{ id: 46150, name: "순천시" },
|
|
{ id: 46910, name: "신안군" },
|
|
{ id: 46130, name: "여수시" },
|
|
{ id: 46890, name: "완도군" },
|
|
// ...전라남도의 시군구 추가
|
|
],
|
|
47: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 47130, name: "경주시" },
|
|
{ id: 47830, name: "고령군" },
|
|
{ id: 47190, name: "구미시" },
|
|
{ id: 47720, name: "군위군" },
|
|
{ id: 47150, name: "김천시" },
|
|
{ id: 47280, name: "문경시" },
|
|
{ id: 47920, name: "봉화군" },
|
|
{ id: 47250, name: "상주시" },
|
|
{ id: 47770, name: "영덕군" },
|
|
{ id: 47760, name: "영양군" },
|
|
{ id: 47210, name: "영주시" },
|
|
{ id: 47900, name: "예천군" },
|
|
{ id: 47930, name: "울진군" },
|
|
{ id: 47730, name: "의성군" },
|
|
{ id: 47750, name: "청송군" },
|
|
{ id: 47850, name: "칠곡군" },
|
|
{ id: 47110, name: "포항시" },
|
|
// ...경상북도의 시군구 추가
|
|
],
|
|
48: [
|
|
{ id: 0, name: '선택' },
|
|
{ id: 48310, name: "거제시" },
|
|
{ id: 48250, name: "김해시" },
|
|
{ id: 48270, name: "밀양시" },
|
|
{ id: 48220, name: "통영시" },
|
|
// ...경상남도의 시군구 추가
|
|
],
|
|
// ...나머지 시도별 시군구 추가
|
|
};
|
|
|
|
const 처리구역List = ['선택', 'A', 'B'];
|
|
const 설치년도List = ['선택', ...YEARS];
|
|
|
|
// swageZoneTableHeadlist, tableData 타입 예시 (실제 타입에 맞게 수정)
|
|
type TableHead = {
|
|
key: string;
|
|
label: string;
|
|
};
|
|
type TableRow = Record<string, any>;
|
|
|
|
interface SearchModalProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
}
|
|
|
|
// filterParams 타입 정의 추가
|
|
type FilterParams = {
|
|
swtrmt_zone_nm?: string;
|
|
ctpv_cd?: number;
|
|
sgg_cd?: number;
|
|
swtrmt_fclt_nm?: string;
|
|
// 추가 필터 속성들...
|
|
};
|
|
|
|
// 해당 년/월의 마지막 일 구하는 함수
|
|
function getLastDayOfMonth(year: string, month: string) {
|
|
if (!year || !month) return 31;
|
|
const y = parseInt(year, 10);
|
|
const m = parseInt(month, 10);
|
|
if (isNaN(y) || isNaN(m)) return 31;
|
|
return new Date(y, m, 0).getDate();
|
|
}
|
|
// 날짜 조합 함수
|
|
const getDateString = (year: string, month: string, day: string, defaultDate: string) => {
|
|
if (!year && !month && !day) return defaultDate;
|
|
const y = year || defaultDate.slice(0, 4);
|
|
const m = month || defaultDate.slice(4, 6);
|
|
const d = day || defaultDate.slice(6, 8);
|
|
return `${y}${m}${d}`;
|
|
};
|
|
|
|
const SearchModal: React.FC<SearchModalProps> = ({ open, onOpenChange }) => {
|
|
const [activeTab, setActiveTab] = React.useState('basic');
|
|
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(0);
|
|
const [시군구, set시군구] = React.useState(0);
|
|
const [처리구역, set처리구역] = React.useState('');
|
|
const [설치년도1, set설치년도1] = React.useState('');
|
|
const [설치년도2, set설치년도2] = React.useState('');
|
|
const [tableData, setTableData] = React.useState<any[]>([]);
|
|
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 [가동개시_종료_월, set가동개시_종료_월] = React.useState('');
|
|
const [가동개시_종료_일, set가동개시_종료_일] = React.useState('');
|
|
|
|
// 오늘 날짜 구하기
|
|
const today = new Date();
|
|
const todayYear = today.getFullYear().toString();
|
|
const todayMonth = (today.getMonth() + 1).toString().padStart(2, '0');
|
|
const todayDate = today.getDate().toString().padStart(2, '0');
|
|
|
|
// UiTable2에 넘길 headlist를 BASIC_TYPES 값에 따라 분기 처리
|
|
let dynamicHeadlist = swageZoneTableHeadlist;
|
|
if (basicType === 'tb_ms_swage_prcs_zone') {
|
|
dynamicHeadlist = swageZoneTableHeadlist; // 하수처리구역
|
|
} else if (basicType === 'tb_il_swage_prcs_fclt') {
|
|
dynamicHeadlist = swageFcltTableHeadlist; // 하수처리시설
|
|
}
|
|
|
|
|
|
|
|
|
|
// 선택된 시도에 따라 시군구 리스트 가져오기
|
|
const selectedSigunguList = sigunguMap[시도] || [{ id: 0, name: '선택' }];
|
|
|
|
// 조회 버튼 클릭 시 1페이지로 이동하도록 수정
|
|
const handleSearch = () => {
|
|
setCurPage(1); // 페이지를 1로 초기화
|
|
fetchFilteredData();
|
|
setShowTable(true);
|
|
};
|
|
|
|
// 선택된 필터 값을 저장할 상태 추가
|
|
const [filterParams, setFilterParams] = React.useState<FilterParams>({});
|
|
|
|
// 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<HTMLDivElement>(null);
|
|
const [dynamicHeight, setDynamicHeight] = React.useState<number | undefined>(undefined);
|
|
|
|
// 구분(basicType)이 바뀔 때마다 queryParams, filterParams 초기화
|
|
React.useEffect(() => {
|
|
// filterParams 초기화
|
|
setFilterParams({});
|
|
set시설용량최소('');
|
|
set시설용량최대('');
|
|
set가동개시_시작_년('');
|
|
set가동개시_시작_월('');
|
|
set가동개시_시작_일('');
|
|
set가동개시_종료_년('');
|
|
set가동개시_종료_월('');
|
|
set가동개시_종료_일('');
|
|
set하수처리구역명('');
|
|
set하수처리시설명('');
|
|
set시도(0);
|
|
set시군구(0);
|
|
set처리구역('');
|
|
set설치년도1('');
|
|
set설치년도2('');
|
|
// queryParams는 fetchFilteredData 내에서 매번 새로 생성되므로 별도 상태 초기화는 필요 없음
|
|
}, [basicType]);
|
|
|
|
// 필터 값이 변경될 때 쿼리 파라미터 업데이트
|
|
React.useEffect(() => {
|
|
const params: FilterParams = {};
|
|
|
|
if (하수처리구역명) {
|
|
params.swtrmt_zone_nm = 하수처리구역명;
|
|
}
|
|
|
|
// 시도 선택 시 (0이 아닌 경우)
|
|
if (시도 !== 0) {
|
|
const selectedSido = sidoList.find(item => item.id === 시도);
|
|
if (selectedSido) {
|
|
params.ctpv_cd = selectedSido.id;
|
|
}
|
|
}
|
|
|
|
// 시군구 선택 시 (0이 아닌 경우)
|
|
if (시군구 !== 0) {
|
|
const selectedSigungu = (sigunguMap[시도] || []).find((item: { id: number; name: string }) => item.id === 시군구);
|
|
if (selectedSigungu) {
|
|
params.sgg_cd = selectedSigungu.id;
|
|
}
|
|
}
|
|
|
|
// 하수처리시설명이 있으면 추가
|
|
if (하수처리시설명) {
|
|
params.swtrmt_fclt_nm = 하수처리시설명;
|
|
}
|
|
|
|
setFilterParams(params);
|
|
}, [하수처리구역명, 시도, 시군구, 하수처리시설명]);
|
|
|
|
|
|
React.useEffect(() => {
|
|
if (contentRef.current) {
|
|
setDynamicHeight(contentRef.current.scrollHeight + 60); // 여유 padding
|
|
}
|
|
}, [activeTab, showTable, curPage, tableData.length]);
|
|
|
|
|
|
// 검색 API 호출 함수
|
|
const fetchFilteredData = () => {
|
|
const queryParams = new URLSearchParams({
|
|
lyrTypeNm: basicType
|
|
});
|
|
|
|
const cqlFilters: string[] = [];
|
|
|
|
// 구분별 분기 처리
|
|
if (basicType === 'tb_ms_swage_prcs_zone') {
|
|
// 하수처리구역
|
|
// 시도
|
|
if (filterParams.ctpv_cd) {
|
|
cqlFilters.push(`ctpv_cd='${filterParams.ctpv_cd}'`);
|
|
}
|
|
// 시군구
|
|
if (filterParams.sgg_cd) {
|
|
cqlFilters.push(`sgg_cd='${filterParams.sgg_cd}'`);
|
|
}
|
|
// 하수처리구역명
|
|
if (filterParams.swtrmt_zone_nm) {
|
|
cqlFilters.push(`swtrmt_zone_nm ILIKE '%${filterParams.swtrmt_zone_nm}%'`);
|
|
}
|
|
// 하수처리시설명
|
|
if (filterParams.swtrmt_fclt_nm) {
|
|
cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${filterParams.swtrmt_fclt_nm}%'`);
|
|
}
|
|
} else if (basicType === 'tb_il_swage_prcs_fclt') {
|
|
// 하수처리시설
|
|
// 가동개시일자 범위 필터 추가
|
|
// 기본값: 19000101 ~ 오늘
|
|
const startDate = getDateString(가동개시_시작_년, 가동개시_시작_월, 가동개시_시작_일, '19000101');
|
|
const endDate = getDateString(가동개시_종료_년, 가동개시_종료_월, 가동개시_종료_일, `${todayYear}${todayMonth}${todayDate}`);
|
|
cqlFilters.push(`oprtng_strt_ymd >= '${startDate}' and oprtng_strt_ymd <= '${endDate}'`);
|
|
// 시설용량 범위(fclt_cpct) 필터 추가
|
|
if (시설용량최소 && 시설용량최대) cqlFilters.push(`fclt_cpct BETWEEN ${시설용량최소} AND ${시설용량최대}`);
|
|
else if (시설용량최소) cqlFilters.push(`fclt_cpct >= ${시설용량최소}`);
|
|
else if (시설용량최대) cqlFilters.push(`fclt_cpct <= ${시설용량최대}`);
|
|
// 하수처리시설명
|
|
if (filterParams.swtrmt_fclt_nm) {
|
|
cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${filterParams.swtrmt_fclt_nm}%'`);
|
|
}
|
|
} else {
|
|
// 기타 구분(예: 하수관로, 맨홀 등) - 필요시 추가
|
|
// 예시: 이름으로 검색
|
|
if (filterParams.swtrmt_fclt_nm) {
|
|
cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${filterParams.swtrmt_fclt_nm}%'`);
|
|
}
|
|
}
|
|
|
|
// 파라미터 이름 오타 주의! (Swagger와 동일하게)
|
|
if (cqlFilters.length > 0) {
|
|
queryParams.append('cqlFiter', cqlFilters.join(' and '));
|
|
}
|
|
|
|
console.log('API URL:', `${API_URL}/v1/map/features?${queryParams.toString()}`);
|
|
axios.get(`${API_URL}/v1/map/features?${queryParams.toString()}`)
|
|
.then(res => {
|
|
// 결과값을 표에 사용할 수 있도록 상태에 저장
|
|
console.log('필터링된 API 결과:', res.data.length);
|
|
console.log('필터링된 API 결과:', res.data);
|
|
setTableData(res.data || []); // res.data 구조에 따라 조정 필요
|
|
setShowTable(true);
|
|
})
|
|
.catch(err => {
|
|
console.error('API ERROR:', err);
|
|
setTableData([]); // 에러 시 빈 배열로 초기화
|
|
});
|
|
};
|
|
|
|
|
|
const renderBody = () => (
|
|
<>
|
|
{/* 탭 영역 */}
|
|
<div className="flex gap-2 mb-4">
|
|
{TABS.map(tab => (
|
|
<button
|
|
key={tab.key}
|
|
className={`px-4 py-2 rounded-t border border-b-0 text-base font-semibold
|
|
${activeTab === tab.key
|
|
? 'bg-[#bfcfe6] text-black'
|
|
: 'bg-[#e6e6e6] text-gray-700'
|
|
}`}
|
|
style={{
|
|
borderColor: '#888',
|
|
borderBottom: activeTab === tab.key ? '2px solid white' : undefined,
|
|
minWidth: 140,
|
|
fontSize: '1.1rem',
|
|
height: '2.4rem', // 글자 크기에서 약간의 여백만 있도록 높이 조정
|
|
}}
|
|
onClick={() => setActiveTab(tab.key)}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* 기본정보 탭 */}
|
|
{activeTab === 'basic' && (
|
|
<div className="border rounded p-6 mb-4">
|
|
{/* 구분 */}
|
|
<div className="flex justify-between items-center mb-3 gap-4">
|
|
<div className="flex items-center">
|
|
<label className="font-semibold text-xl mr-2">구분</label>
|
|
<select
|
|
className="border rounded text-xl px-2 py-1"
|
|
value={basicType}
|
|
onChange={e => setBasicType(e.target.value)}
|
|
>
|
|
{BASIC_TYPES.map(opt => (
|
|
<option key={opt.key} value={opt.key}>{opt.label}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
{/* 분기처리: 하수처리구역 */}
|
|
{basicType === 'tb_ms_swage_prcs_zone' && (
|
|
<div className="mb-3">
|
|
<div className="flex items-center mb-2">
|
|
<label className="font-semibold text-xl mr-2">시도</label>
|
|
<select className="border rounded text-xl px-2 py-1 mr-4" value={시도} onChange={e => set시도(parseInt(e.target.value))}>
|
|
{sidoList.map(opt => (
|
|
<option key={opt.id} value={opt.id}>{opt.name}</option>
|
|
))}
|
|
</select>
|
|
<label className="font-semibold text-xl mr-2">시군구</label>
|
|
<select className="border rounded text-xl px-2 py-1 mr-4" value={시군구} onChange={e => set시군구(parseInt(e.target.value))}>
|
|
{selectedSigunguList.map(opt => (
|
|
<option key={opt.id} value={opt.id}>{opt.name}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div className="flex items-center">
|
|
<label className="font-semibold text-xl mr-2">하수처리구역명</label>
|
|
<input className="border rounded text-xl px-2 py-1 mr-4" value={하수처리구역명} onChange={e => set하수처리구역명(e.target.value)} />
|
|
</div>
|
|
<div className="flex items-center">
|
|
<label className="font-semibold text-xl mr-2">하수처리시설명</label>
|
|
<input className="border rounded text-xl px-2 py-1 mr-4" value={하수처리시설명} onChange={e => set하수처리시설명(e.target.value)} />
|
|
</div>
|
|
</div>
|
|
)}
|
|
{/* 분기처리: 하수처리시설 */}
|
|
{basicType === 'tb_il_swage_prcs_fclt' && (
|
|
<div className="mb-3">
|
|
{/* 가동개시일자 */}
|
|
<div className="flex items-center mb-2">
|
|
<label className="font-semibold text-xl mr-2">가동개시일자</label>
|
|
{/* 시작일자 */}
|
|
<select
|
|
className="border rounded text-xl px-2 py-1 mr-1"
|
|
value={가동개시_시작_년}
|
|
onChange={e => set가동개시_시작_년(e.target.value)}
|
|
>
|
|
<option value="">년</option>
|
|
{Array.from({ length: today.getFullYear() - 1900 + 1 }, (_, i) => {
|
|
const y = (today.getFullYear() - i).toString();
|
|
return <option key={y} value={y}>{y}</option>;
|
|
})}
|
|
</select>
|
|
{/* <select
|
|
className="border rounded text-xl px-2 py-1 mr-1"
|
|
value={가동개시_시작_월}
|
|
onChange={e => set가동개시_시작_월(e.target.value)}
|
|
>
|
|
<option value="">월</option>
|
|
{[...Array(12)].map((_, i) => {
|
|
const m = (i + 1).toString().padStart(2, '0');
|
|
return <option key={m} value={m}>{m}</option>;
|
|
})}
|
|
</select>
|
|
<select
|
|
className="border rounded text-xl px-2 py-1 mr-4"
|
|
value={가동개시_시작_일}
|
|
onChange={e => set가동개시_시작_일(e.target.value)}
|
|
>
|
|
<option value="">일</option>
|
|
{[...Array(31)].map((_, i) => {
|
|
const d = (i + 1).toString().padStart(2, '0');
|
|
return <option key={d} value={d}>{d}</option>;
|
|
})}
|
|
</select> */}
|
|
<span className="mx-1">~</span>
|
|
{/* 종료일자 */}
|
|
<select
|
|
className="border rounded text-xl px-2 py-1 mr-1"
|
|
value={가동개시_종료_년}
|
|
onChange={e => set가동개시_종료_년(e.target.value)}
|
|
>
|
|
<option value="">년</option>
|
|
{Array.from({ length: today.getFullYear() - 1900 + 1 }, (_, i) => {
|
|
const y = (today.getFullYear() - i).toString();
|
|
// 시작년이 선택된 경우, 종료년은 시작년 이상만 표시
|
|
if (가동개시_시작_년 && parseInt(y) < parseInt(가동개시_시작_년)) return null;
|
|
return <option key={y} value={y}>{y}</option>;
|
|
})}
|
|
</select>
|
|
{/* <select
|
|
className="border rounded text-xl px-2 py-1 mr-1"
|
|
value={가동개시_종료_월}
|
|
onChange={e => set가동개시_종료_월(e.target.value)}
|
|
>
|
|
<option value="">월</option>
|
|
{[...Array(12)].map((_, i) => {
|
|
const m = (i + 1).toString().padStart(2, '0');
|
|
// 시작년/월이 선택된 경우, 종료년이 시작년과 같으면 시작월 이상만 표시
|
|
if (
|
|
가동개시_시작_년 &&
|
|
가동개시_종료_년 === 가동개시_시작_년 &&
|
|
가동개시_시작_월 &&
|
|
parseInt(m) < parseInt(가동개시_시작_월)
|
|
) return null;
|
|
return <option key={m} value={m}>{m}</option>;
|
|
})}
|
|
</select>
|
|
<select
|
|
className="border rounded text-xl px-2 py-1 mr-4"
|
|
value={가동개시_종료_일}
|
|
onChange={e => set가동개시_종료_일(e.target.value)}
|
|
>
|
|
<option value="">일</option>
|
|
{[...Array(31)].map((_, i) => {
|
|
const d = (i + 1).toString().padStart(2, '0');
|
|
// 시작년/월/일이 선택된 경우, 종료년/월이 시작년/월과 같으면 시작일 이상만 표시
|
|
if (
|
|
가동개시_시작_년 &&
|
|
가동개시_종료_년 === 가동개시_시작_년 &&
|
|
가동개시_시작_월 &&
|
|
가동개시_종료_월 === 가동개시_시작_월 &&
|
|
가동개시_시작_일 &&
|
|
parseInt(d) < parseInt(가동개시_시작_일)
|
|
) return null;
|
|
// 시작년/월이 선택된 경우, 종료년/월이 시작년/월과 같고 시작일이 선택되었으면 시작일 이상만 표시
|
|
if (
|
|
가동개시_시작_년 &&
|
|
가동개시_종료_년 === 가동개시_시작_년 &&
|
|
가동개시_시작_월 &&
|
|
가동개시_종료_월 === 가동개시_시작_월 &&
|
|
가동개시_시작_일 &&
|
|
parseInt(d) < parseInt(가동개시_시작_일)
|
|
) return null;
|
|
// 시작년/월만 선택된 경우, 종료년/월이 시작년/월과 같으면 모든 일 표시(위 조건에 포함)
|
|
// 시작년만 선택된 경우, 종료년이 시작년과 같으면 모든 월/일 표시(위 조건에 포함)
|
|
return <option key={d} value={d}>{d}</option>;
|
|
})}
|
|
</select> */}
|
|
</div>
|
|
{/* 시설용량 */}
|
|
<div className="flex items-center mb-2">
|
|
<label className="font-semibold text-xl mr-2">시설용량</label>
|
|
<input
|
|
type="text"
|
|
className="border rounded text-xl px-2 py-1 mr-2 w-40 placeholder:text-center"
|
|
placeholder="최소"
|
|
value={시설용량최소}
|
|
onChange={e => {
|
|
// 숫자만 입력 허용
|
|
const val = e.target.value.replace(/[^0-9]/g, '');
|
|
set시설용량최소(val);
|
|
}}
|
|
/>
|
|
<span className="text-xl mr-2">~</span>
|
|
<input
|
|
type="text"
|
|
className="border rounded text-xl px-2 py-1 mr-4 w-40 placeholder:text-center"
|
|
placeholder="최대"
|
|
value={시설용량최대}
|
|
onChange={e => {
|
|
// 숫자만 입력 허용
|
|
const val = e.target.value.replace(/[^0-9]/g, '');
|
|
set시설용량최대(val);
|
|
}}
|
|
/>
|
|
</div>
|
|
{/* 하수처리시설명 */}
|
|
<div className="flex items-center">
|
|
<label className="font-semibold text-xl mr-2">하수처리시설명</label>
|
|
<input className="border rounded text-xl px-2 py-1 mr-4" value={하수처리시설명} onChange={e => set하수처리시설명(e.target.value)} />
|
|
</div>
|
|
</div>
|
|
)}
|
|
{/* 조회 버튼 중앙 정렬 */}
|
|
<div className="flex justify-center">
|
|
<Button className="w-40 text-base py-2" onClick={handleSearch}>조회</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 운영정보 탭 */}
|
|
{activeTab === 'operation' && (
|
|
<div className="border rounded p-6 mb-4">
|
|
<div className="flex items-center gap-6 mb-6">
|
|
<label className="w-24 font-semibold text-base">업무구분</label>
|
|
<select
|
|
className="border rounded px-3 py-2 text-base"
|
|
value={workType}
|
|
onChange={e => setWorkType(e.target.value)}
|
|
style={{ minWidth: 140 }}
|
|
>
|
|
{WORK_TYPES.map(w => (
|
|
<option key={w.key} value={w.key}>{w.label}</option>
|
|
))}
|
|
</select>
|
|
|
|
<label className="w-16 text-center font-semibold text-base">년도</label>
|
|
<select
|
|
className="border rounded px-3 py-2 text-base"
|
|
value={startYear}
|
|
onChange={e => setStartYear(e.target.value)}
|
|
style={{ minWidth: 100 }}
|
|
>
|
|
<option value="">선택</option>
|
|
{YEARS.map(y => (
|
|
<option key={y} value={y}>{y}</option>
|
|
))}
|
|
</select>
|
|
<span className="mx-2 text-lg">~</span>
|
|
<select
|
|
className="border rounded px-3 py-2 text-base"
|
|
value={endYear}
|
|
onChange={e => setEndYear(e.target.value)}
|
|
style={{ minWidth: 100 }}
|
|
>
|
|
<option value="">선택</option>
|
|
{YEARS.map(y => (
|
|
<option key={y} value={y}>{y}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div className="flex justify-center">
|
|
<Button className="w-40 text-base py-2" onClick={() => setShowTable(true)}>
|
|
조회
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 하수도정비기본계획보고서서 탭 */}
|
|
{activeTab === 'report' && (
|
|
<div className="border rounded p-6 mb-4">
|
|
{/* 시도, 시군구, 하수처리구역 한 줄 */}
|
|
<div className="flex items-center mb-3">
|
|
<label className="font-semibold mr-2">시도</label>
|
|
<select className="border rounded px-2 py-1 mr-4" value={시도} onChange={e => set시도(e.target.value)}>
|
|
{sidoList.map(opt => (
|
|
<option key={opt.id} value={opt.name}>{opt.id}</option>
|
|
))}
|
|
</select>
|
|
<label className="font-semibold mr-2">시군구</label>
|
|
<select className="border rounded px-2 py-1 mr-4" value={시군구} onChange={e => set시군구(e.target.value)}>
|
|
{/* {sigunguMap.map(opt => (
|
|
<option key={opt} value={opt}>{opt}</option>
|
|
))} */}
|
|
</select>
|
|
<label className="font-semibold mr-2">하수처리구역</label>
|
|
<select className="border rounded px-2 py-1 mr-2" value={처리구역} onChange={e => set처리구역(e.target.value)}>
|
|
{처리구역List.map(opt => (
|
|
<option key={opt} value={opt}>{opt}</option>
|
|
))}
|
|
</select>
|
|
<input className="border rounded px-2 py-1 w-24" placeholder="0000" />
|
|
</div>
|
|
{/* 승인년도 한 줄 */}
|
|
<div className="flex items-center mb-4">
|
|
<label className="font-semibold mr-2">승인년도</label>
|
|
<select className="border rounded px-2 py-1 mr-2" value={설치년도1} onChange={e => set설치년도1(e.target.value)}>
|
|
{설치년도List.map(opt => (
|
|
<option key={opt} value={opt}>{opt}</option>
|
|
))}
|
|
</select>
|
|
<span className="mx-1">~</span>
|
|
<select className="border rounded px-2 py-1" value={설치년도2} onChange={e => set설치년도2(e.target.value)}>
|
|
{설치년도List.map(opt => (
|
|
<option key={opt} value={opt}>{opt}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
{/* 조회 버튼 중앙 정렬 */}
|
|
<div className="flex justify-center">
|
|
<Button className="w-40 text-base py-2">조회</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 📋 결과 리스트 */}
|
|
<div className="border-t pt-6 space-y-2" style={{ maxWidth: '100vw', maxHeight: '60vh', overflowX: 'auto'}}>
|
|
{/* 선택된 탭의 label */}
|
|
<div className="text-2xl font-bold mb-2">
|
|
{TABS.find(tab => tab.key === activeTab)?.label}
|
|
</div>
|
|
{/* "▶" + 선택된 탭 label + " 조회 결과" */}
|
|
<div className="text-lg font-semibold mb-6">
|
|
▶ {TABS.find(tab => tab.key === activeTab)?.label} 조회 결과
|
|
</div>
|
|
<UiTable2 headName='' tableData={tableData} headlist={dynamicHeadlist}
|
|
pageSize={tableData.length < 10 ? tableData.length : 10}
|
|
total={tableData.length} children={undefined}
|
|
cellClick={() => { }} onPageChange={setCurPage}
|
|
resetPageNo={false}
|
|
cur={curPage}
|
|
/>
|
|
</div>
|
|
</>
|
|
);
|
|
{/* </DialogContent>
|
|
</Dialog>
|
|
); */}
|
|
|
|
return (
|
|
<UiModal
|
|
open={open}
|
|
onOpenChange={onOpenChange}
|
|
bodyClass={`
|
|
${modalMaxWidth} ${modalMinWidth}
|
|
transition-all duration-300
|
|
w-full overflow-hidden
|
|
`}
|
|
body={renderBody()}
|
|
headerTitle="검색"
|
|
// 필요시 footerContent 등 추가
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default React.memo(SearchModal);
|