Merge remote-tracking branch 'origin/iipbs/sn/dev' into iipbs/sn/ii
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
NEXT_PUBLIC_SITE_ID = SN
|
||||
NEXT_PUBLIC_PORT = 3002
|
||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3002
|
||||
NEXT_PUBLIC_ADDR_URL = http://con.mind-one.co.kr:11082
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
NEXT_PUBLIC_SITE_ID = SN
|
||||
NEXT_PUBLIC_PORT = 11302
|
||||
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11302
|
||||
NEXT_PUBLIC_ADDR_URL = http://con.mind-one.co.kr:11082
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver #TODO 운영에서 바꿔야 함
|
||||
NEXT_PUBLIC_RSONE_DC_URL = https://apigateway.rsonesoft.com #자료관 데이터
|
||||
NEXT_PUBLIC_CLAIM_NAME = Authorization
|
||||
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||
NEXT_PUBLIC_ACCESS_TOKEN = access-token
|
||||
|
||||
@@ -10,6 +10,9 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
||||
import { SidoSigunguSelectBox } from '@/components/ui/SidoSigunguSelectBox';
|
||||
import { MsSwagePplCol2, SwtrmtFcltCol2, SwtrmtPrcsZoneCol2, MsSwageMhlCol2, ExclnSewagePumpCol2, stofcbrCol2 } from './components/common/table';
|
||||
import LoadingOverlay from '@/components/ui/LoadingBar';
|
||||
//import { useDcTree, flattenFolders, useSggCd, useCityCd } from './components/searchModalReportApi';
|
||||
import { getDcTree,useDcTree,flattenFolders, useSggCd, useCityCd } from './components/searchModalReportApi';
|
||||
import { useCityCdStore, type SelectDataType } from './commonStore';
|
||||
|
||||
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}`;
|
||||
|
||||
@@ -51,22 +54,15 @@ const operationTableHeadlist = [
|
||||
// 하수도정비 기본계획 보고서
|
||||
const reportTableHeadlist = [
|
||||
{ id: "no", title: "NO" },
|
||||
{ id: "approvalYear", title: "승인년도" },
|
||||
{ id: "sido", title: "시도" },
|
||||
{ id: "sigungu", title: "시군구" },
|
||||
{ id: "treatmentPlant", title: "하수처리장" },
|
||||
{ id: "treatmentZone", title: "하수처리구역" },
|
||||
{ id: "reportCount", title: "보고서(00건)" },
|
||||
{ id: "planMapCount", title: "하수도대장 평면도(00건)" },
|
||||
{ id: "approvalYear", title: "승인년도" },
|
||||
{ id: "plantZoneGugun", title: "구분" },
|
||||
{ id: "reportGubun", title: "보고서구분" },
|
||||
{ id: "fileName", title: "파일명" },
|
||||
{ id: "regDate", title: "등록일자" },
|
||||
];
|
||||
|
||||
const 처리구역List = [
|
||||
{ val: "0", text: "선택" },
|
||||
{ val: "a", text: "A" },
|
||||
{ val: "b", text: "B" },
|
||||
];
|
||||
|
||||
// 날짜 조합 함수
|
||||
const getDateString = (
|
||||
year: string,
|
||||
@@ -99,9 +95,10 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
const [tableCount, setTableCount] = useState<number>(0);
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [basicType, setBasicType] = useState(BASIC_TYPES[0]?.val ?? "");
|
||||
const [시도, set시도] = useState(0);
|
||||
const [시군구, set시군구] = useState(0);
|
||||
const [처리구역, set처리구역] = useState("");
|
||||
const [ctpvCd, setCtpvCd] = useState('0');
|
||||
const [sigungu, setSigungu] = useState('0');
|
||||
//const [swageProcessingZone, set처리구역] = useState("");
|
||||
const [gubun, setGubun] = useState(""); // 하수정비기본계획 report
|
||||
// 날짜 상태 선언
|
||||
const [시작1, set시작1] = useState("");
|
||||
const [시작2, set시작2] = useState("");
|
||||
@@ -124,12 +121,17 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
const [가동개시_종료_일, set가동개시_종료_일] = useState('');
|
||||
const [fromDate, setFromDate] = useState(() => { const date = new Date(); date.setDate(date.getDate() - 7); return date })
|
||||
const [toDate, setToDate] = useState(new Date())
|
||||
const [filteredSiguns, setFilteredSiguns] = useState<SelectDataType[]>([{ val: '0', text: '전체', sido: '0' }]);
|
||||
|
||||
// 로딩바
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
// 상세 정보 조회를 위한 상태 추가
|
||||
const [popupFeature, setPopupFeature] = useState<any>(null);
|
||||
|
||||
const sidos = useCityCd();
|
||||
const siguns = useSggCd();
|
||||
const reportOriginData = useDcTree("");
|
||||
|
||||
// 오늘 날짜 구하기
|
||||
const today = new Date();
|
||||
const todayYear = today.getFullYear().toString();
|
||||
@@ -162,6 +164,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
else if (basicType === 'tb_ms_swage_pmstn') dynamicHeadlist = ExclnSewagePumpCol2; // 하수펌프장
|
||||
else if (basicType === 'tb_ms_stofcbr') dynamicHeadlist = stofcbrCol2; // 우수토실
|
||||
|
||||
|
||||
// 조회 버튼 클릭 시 1페이지로 이동하도록 수정
|
||||
const handleSearch = () => {
|
||||
setCurPage(1); // 페이지를 1로 초기화
|
||||
@@ -177,7 +180,16 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
// 구분(basicType)이 바뀔 때마다 queryParams, filterParams 초기화
|
||||
const handleCtpvCdChange = (val: string|number) => {
|
||||
const sidoOption = sidos.find((n) => n.val === val);
|
||||
setCtpvCd(String(val));
|
||||
if (val !== '0' && sidoOption) {
|
||||
const filterSiguns = siguns.filter(item => item.sido === sidoOption.text);
|
||||
filterSiguns.unshift({ val: '0', text: '전체', sido: '0' });
|
||||
setFilteredSiguns(filterSiguns);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// filterParams 초기화
|
||||
// setFilterParams({});
|
||||
@@ -193,9 +205,8 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
set가동개시_종료_월("");
|
||||
set가동개시_시작_일("");
|
||||
set가동개시_종료_일("");
|
||||
set시도(0);
|
||||
set시군구(0);
|
||||
set처리구역("");
|
||||
setCtpvCd('0');
|
||||
setSigungu('0');
|
||||
setYearFilter({
|
||||
시작: "",
|
||||
종료: "",
|
||||
@@ -205,7 +216,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
setTableCount(0);
|
||||
setTableData([]);
|
||||
// queryParams는 fetchFilteredData 내에서 매번 새로 생성되므로 별도 상태 초기화는 필요 없음
|
||||
}, [activeTab, basicType]);
|
||||
}, [activeTab, basicType, open]);
|
||||
|
||||
// 페이지 변경 시마다 데이터 fetch
|
||||
useEffect(() => {
|
||||
@@ -216,6 +227,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
}
|
||||
}, [curPage]);
|
||||
|
||||
|
||||
// 검색 API 호출 함수
|
||||
const fetchFilteredData = async () => {
|
||||
setIsLoading(true); // 로딩 시작
|
||||
@@ -243,14 +255,46 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
|
||||
if (cqlFilters.length > 0) queryParams.append('cqlFiter', cqlFilters.join(' and '));
|
||||
|
||||
console.log('API URL:', `${API_URL}/v1/fclts?${queryParams.toString()}`);
|
||||
const res = await axios.get(`${API_URL}/v1/fclts?${queryParams.toString()}`);
|
||||
console.log('필터링된 API 결과(개수):', res.data.count);
|
||||
console.log('필터링된 API 결과(데이터):', res.data.data);
|
||||
if (activeTab === 'report') {
|
||||
//const reportOriginData = await getDcTree('경기도');
|
||||
const reportData = flattenFolders(reportOriginData);
|
||||
let filterReportData = reportData;
|
||||
if (ctpvCd !== "0") {
|
||||
const sidoOption = sidos.find((n) => n.val === ctpvCd);
|
||||
filterReportData = filterReportData.filter(item => item.sido === sidoOption?.text);
|
||||
}
|
||||
if (sigungu !== "0") {
|
||||
const sigunguOption = filteredSiguns.find((n) => n.val === sigungu);
|
||||
filterReportData = filterReportData.filter(item => item.sigungu === sigunguOption?.text);
|
||||
}
|
||||
if (yearFilter.시작 != "" && yearFilter.종료 == "")
|
||||
filterReportData = filterReportData.filter(item => (item.approvalYear)? item.approvalYear >= yearFilter.시작+"년" : null);
|
||||
if (yearFilter.시작 == "" && yearFilter.종료 != "")
|
||||
filterReportData = filterReportData.filter(item => (item.approvalYear)? item.approvalYear <= yearFilter.종료+"년" : null);
|
||||
if (yearFilter.시작 != "" && yearFilter.종료 != "") {
|
||||
filterReportData = filterReportData.filter(item => {
|
||||
return (item.approvalYear)? item.approvalYear >= yearFilter.시작+"년" && item.approvalYear <= yearFilter.종료+"년": null;
|
||||
});
|
||||
}
|
||||
if (gubun !== "") {
|
||||
filterReportData = filterReportData.filter(item => (item.plantZoneGugun)? String(item.plantZoneGugun).includes(String(gubun)) : null);
|
||||
}
|
||||
console.log('report count:', filterReportData.length);
|
||||
setTableCount(filterReportData.length || 0);
|
||||
filterReportData = filterReportData.slice((curPage-1)*10, curPage*10); // paging
|
||||
filterReportData = filterReportData?.map((item, index)=>({...item, no:(curPage-1)*10+index+1}));
|
||||
setTableData(filterReportData || []);
|
||||
|
||||
} else {
|
||||
console.log('API URL:', `${API_URL}/v1/fclts?${queryParams.toString()}`);
|
||||
const res = await axios.get(`${API_URL}/v1/fclts?${queryParams.toString()}`);
|
||||
console.log('필터링된 API 결과(개수):', res.data.count);
|
||||
console.log('필터링된 API 결과(데이터):', res.data.data);
|
||||
setTableData(res.data.data || []);
|
||||
setTableCount(res.data.count || []);
|
||||
console.log('tableCount 상태 업데이트 후:', res.data.count); // tableCount 로그 추가
|
||||
}
|
||||
|
||||
setTableData(res.data.data || []);
|
||||
setTableCount(res.data.count || []);
|
||||
console.log('tableCount 상태 업데이트 후:', res.data.count); // tableCount 로그 추가
|
||||
setShowTable(true);
|
||||
} catch (err) {
|
||||
console.error('API ERROR:', err);
|
||||
@@ -326,8 +370,8 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
// 하수처리구역용 CQL 필터 생성
|
||||
const zoneCqlFilters = () => {
|
||||
const cqlFilters: string[] = [];
|
||||
if (시도) cqlFilters.push(`ctpv_cd='${시도}'`);
|
||||
if (시군구) cqlFilters.push(`sgg_cd='${시군구}'`);
|
||||
if (ctpvCd) cqlFilters.push(`ctpv_cd='${ctpvCd}'`);
|
||||
if (sigungu) cqlFilters.push(`sgg_cd='${sigungu}'`);
|
||||
if (변수1) cqlFilters.push(`swtrmt_zone_nm ILIKE '%${변수1}%'`);
|
||||
if (변수2) cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${변수2}%'`);
|
||||
return cqlFilters;
|
||||
@@ -447,25 +491,9 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
const reportCqlFilters = () => {
|
||||
const cqlFilters: string[] = [];
|
||||
// 설치년도 범위
|
||||
if (시도) cqlFilters.push(`ctpv_cd='${시도}'`);
|
||||
if (시군구) cqlFilters.push(`sgg_cd='${시군구}'`);
|
||||
if (처리구역) cqlFilters.push(`처리구역='${처리구역}'`);
|
||||
if (변수1) cqlFilters.push(`처리구역코드='${변수1}'`);
|
||||
const startDate = getDateString(
|
||||
yearFilter.시작,
|
||||
가동개시_시작_월,
|
||||
가동개시_시작_일,
|
||||
"19000101",
|
||||
);
|
||||
const endDate = getDateString(
|
||||
yearFilter.종료,
|
||||
가동개시_종료_월,
|
||||
가동개시_종료_일,
|
||||
`${todayYear}${todayMonth}${todayDate}`,
|
||||
);
|
||||
cqlFilters.push(
|
||||
`설치시작년도 >= '${startDate}' and 설치시작년도 <= '${endDate}'`,
|
||||
);
|
||||
if (ctpvCd) cqlFilters.push(`ctpv_cd='${ctpvCd}'`);
|
||||
if (sigungu) cqlFilters.push(`sgg_cd='${sigungu}'`);
|
||||
|
||||
return cqlFilters;
|
||||
};
|
||||
|
||||
@@ -694,13 +722,13 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
<div className="mb-3">
|
||||
<div className="mb-2 flex items-center">
|
||||
<SidoSigunguSelectBox
|
||||
sido={시도}
|
||||
sigungu={시군구}
|
||||
sido={ctpvCd}
|
||||
sigungu={sigungu}
|
||||
onSidoChange={(sidoId) => {
|
||||
set시도(sidoId);
|
||||
set시군구(0);
|
||||
setCtpvCd(sidoId);
|
||||
setSigungu(0);
|
||||
}}
|
||||
onSigunguChange={set시군구}
|
||||
onSigunguChange={setSigungu}
|
||||
/>
|
||||
<Label className="mr-2 w-auto text-xl text-gray-600">
|
||||
하수처리구역명
|
||||
@@ -1008,34 +1036,34 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
<div className="relative flex flex-col border rounded-lg p-6 mb-4 w-full h-[23vh]">
|
||||
{/* 시도, 시군구, 하수처리구역 한 줄 */}
|
||||
<div className="mb-6 flex items-center">
|
||||
<SidoSigunguSelectBox
|
||||
sido={시도}
|
||||
sigungu={시군구}
|
||||
onSidoChange={(sidoId) => {
|
||||
set시도(sidoId);
|
||||
set시군구(0);
|
||||
}}
|
||||
onSigunguChange={set시군구}
|
||||
/>
|
||||
<SelectBox2
|
||||
className="w-[150px] mr-8"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시도"
|
||||
selectArray={sidos}
|
||||
value={ctpvCd}
|
||||
onSelectValue={handleCtpvCdChange}
|
||||
/>
|
||||
<SelectBox2
|
||||
className="w-48"
|
||||
selectClass="w-48 rounded-lg bg-white truncate"
|
||||
label="시군구"
|
||||
selectArray={filteredSiguns}
|
||||
value={sigungu}
|
||||
onSelectValue={val => setSigungu(String(val))}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<SelectBox2
|
||||
className="w-auto mr-2"
|
||||
selectClass="rounded-lg bg-white text-xl"
|
||||
label="하수처리구역"
|
||||
selectArray={처리구역List.map(opt => ({ val: opt.val, text: opt.text }))}
|
||||
onSelectValue={val => set처리구역(String(val))}
|
||||
value={처리구역}
|
||||
/>
|
||||
<label className="inline-block w-auto whitespace-nowrap text-xl text-gray-600 mr-2">구분</label>
|
||||
<Input
|
||||
className='!text-xl w-[100px] placeholder:text-center mr-8'
|
||||
placeholder="입력"
|
||||
value={변수1}
|
||||
value={gubun}
|
||||
onChange={(e) => {
|
||||
// 숫자만 입력 허용
|
||||
const val = e.target.value.replace(/[^0-9]/g, '');
|
||||
set변수1(val);
|
||||
const val = e.target.value;
|
||||
setGubun(val);
|
||||
}}
|
||||
/>
|
||||
<YearRangeSelectBox
|
||||
@@ -1046,6 +1074,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
endLabel=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 조회 버튼 중앙 정렬 */}
|
||||
<div className="absolute bottom-4 right-4 mr-2">
|
||||
<Button className="text-base py-2" onClick={handleSearch}>조회</Button>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
export type SelectDataType = {
|
||||
text: string;
|
||||
val: string;
|
||||
sido?: string; // 시도 코드 (선택 사항)
|
||||
}
|
||||
|
||||
interface CityCdStore {
|
||||
cityCd: string;
|
||||
setCityCd: (cityCd: string) => void;
|
||||
sidos: SelectDataType[];
|
||||
setSidos: (sidos: SelectDataType[]) => void;
|
||||
siguns : SelectDataType[];
|
||||
setSiguns: (siguns: SelectDataType[]) => void;
|
||||
}
|
||||
|
||||
export const useCityCdStore = create<CityCdStore>((set) => ({
|
||||
cityCd: '',
|
||||
setCityCd: (cityCd: string) => set({ cityCd }),
|
||||
sidos: [],
|
||||
setSidos: (sidos: SelectDataType[]) => set({ sidos }),
|
||||
siguns: [],
|
||||
setSiguns: (siguns: SelectDataType[]) => set({ siguns }),
|
||||
}));
|
||||
@@ -65,12 +65,6 @@ export type TOilqData = {
|
||||
oilq: number; // 유량
|
||||
}
|
||||
|
||||
export const getDcTree = async () => {
|
||||
const queryString = '';
|
||||
const result = await getDcData(`/api/v1/dc/tree${queryString ? `?${queryString}` : ''}`);
|
||||
return result;
|
||||
};
|
||||
|
||||
const getOptionsAplcnYm = (yyyymms: string[]): { text: string; val: string, hidden?: boolean }[] => {
|
||||
const yyyymms1 = yyyymms.map(dateStr => {
|
||||
const year = dateStr.slice(0, 4);
|
||||
|
||||
@@ -78,7 +78,6 @@ const InfilChart = ({ pplMngNo }: ModalOpenProp) => {
|
||||
|
||||
// API 호출
|
||||
try {
|
||||
const dcData = fn.getDcTree();
|
||||
const data = await fn.selectInftwtAnls(selectedValue);
|
||||
setInftwtAnlss(data ?? []);
|
||||
setInftwtAnlsInfos(fn.getOptionsInftwtAnlsInfo(data));
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import {useState, useEffect} from 'react';
|
||||
import { getDcData } from '@/components/lib/api';
|
||||
import { json } from 'stream/consumers';
|
||||
|
||||
const ADDR_URL = process.env.NEXT_PUBLIC_ADDR_URL;
|
||||
|
||||
type Folder = {
|
||||
clsfSystmSn: string;
|
||||
upClsfSystmSn: string;
|
||||
clsfSystmNm: string;
|
||||
children: Folder[];
|
||||
};
|
||||
|
||||
type FlattenedFolder = {
|
||||
[key: string]: string|number;
|
||||
};
|
||||
|
||||
type SelectDataType = {
|
||||
text: string;
|
||||
val: string;
|
||||
sido?: string; // 시도 코드 (선택 사항)
|
||||
}
|
||||
|
||||
// 시군구 데이터
|
||||
export const getSggCd = async (): Promise<SelectDataType[]> => {
|
||||
try {
|
||||
const response = await fetch(`${ADDR_URL}/api/v1/addr/sgg`, { method: "GET", headers: { accept: "application/json" } });
|
||||
if (!response.ok) throw new Error(`시군구 데이터 오류: ${response.status}`);
|
||||
const res = await response.json();
|
||||
const sgg = res.data;
|
||||
const sggCd = sgg.map((item: any) => ({
|
||||
val: item.adstDstrCd,
|
||||
sido: item.sido,
|
||||
text: item.gugun,
|
||||
}));
|
||||
sggCd.unshift({ val: '0', text: '전체' }); // "전체" 옵션 추가
|
||||
return sggCd;
|
||||
} catch (error) {
|
||||
console.error('시군구 데이터를 가져오는데 실패했습니다:', error);
|
||||
return [{ val: '0', text: '전체', sido: '0' }];
|
||||
}
|
||||
};
|
||||
|
||||
// 시도 데이터
|
||||
export const getCityCd = async (): Promise<SelectDataType[]> => {
|
||||
try {
|
||||
const response = await fetch(`${ADDR_URL}/api/v1/addr/city`, { method: "GET", headers: { accept: "application/json" } });
|
||||
if (!response.ok) throw new Error(`시도 데이터 오류: ${response.status}`);
|
||||
const res = await response.json();
|
||||
const city = res.data;
|
||||
const cityCd = city.map((item: any) => ({
|
||||
val: item.adstDstrCd,
|
||||
text: item.sido,
|
||||
}));
|
||||
cityCd.unshift({ val: '0', text: '전체' });
|
||||
return cityCd;
|
||||
} catch (error) {
|
||||
console.error('시도 데이터를 가져오는데 실패했습니다:', error);
|
||||
return [{ val: '0', text: '전체', sido: '0' }];
|
||||
}
|
||||
};
|
||||
|
||||
export const useSggCd = () => {
|
||||
const [data, setData] = useState<SelectDataType[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetch = async () => {
|
||||
const result = await getSggCd();
|
||||
if (result) {
|
||||
setData(result);
|
||||
}
|
||||
};
|
||||
fetch();
|
||||
}, []);
|
||||
|
||||
return data;
|
||||
};
|
||||
export const useCityCd = () => {
|
||||
const [data, setData] = useState<SelectDataType[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetch = async () => {
|
||||
const result = await getCityCd();
|
||||
if (result) {
|
||||
setData(result);
|
||||
}
|
||||
};
|
||||
fetch();
|
||||
}, []);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const isYear = (value: string): boolean => {
|
||||
return /^[0-9]{4}년$/.test(value);
|
||||
};
|
||||
|
||||
export function flattenFolders(data: Folder[]): FlattenedFolder[] {
|
||||
const result: FlattenedFolder[] = [];
|
||||
const exceptNodeNm = ["부분","통합","전체"];
|
||||
const addNodeNm = ["보고서","요약보고서","부록","기타"]; // level5
|
||||
const columnNms: { [key: number]: string } = { 0: "root", 1:"sido", 2:"sigungu", 3:"approvalYear"
|
||||
,4:"plantZoneGugun", 5:"reportGubun", 7:"fileName", 8:"regDate" };
|
||||
|
||||
function traverse(
|
||||
node: Folder,
|
||||
path: { [key: string]: string| number },
|
||||
level: number
|
||||
) {
|
||||
if (level === 2 && isYear(node.clsfSystmNm)) {
|
||||
level++;
|
||||
}
|
||||
if (level === 4 && addNodeNm.includes(node.clsfSystmNm)) {
|
||||
level++; // 레벨을 증가시켜 하위값에 추가되도록 함.
|
||||
}
|
||||
|
||||
const newPath = {
|
||||
...path,
|
||||
[`${columnNms[level]}`]: node.clsfSystmNm,
|
||||
};
|
||||
|
||||
if (node.children.length === 0) {
|
||||
newPath.no = result.length + 1;
|
||||
newPath.clsfSystmSn = node.clsfSystmSn; // 파일 조회를 위한 고유번호
|
||||
result.push(newPath);
|
||||
} else {
|
||||
if (level === 4) {
|
||||
if (exceptNodeNm.includes(node.clsfSystmNm)) {
|
||||
level--; // 제외할 노드 이름인 경우, 현재의 레벨에 하위값이 써지도록 함.
|
||||
}
|
||||
}
|
||||
node.children.forEach((child) => {
|
||||
traverse(child, newPath, level + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
data.forEach((root) => traverse(root, {}, 0));
|
||||
console.log(result.slice(0, 10));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
export const getDcTree = async (clsfSystmNm:string) => {
|
||||
const cityName = encodeURIComponent(clsfSystmNm);
|
||||
const queryString = 'clsfSystmNm='+cityName;
|
||||
console.log("getDcTree queryString:", queryString);
|
||||
//const result = await getDcData(`/api/v1/dc/clsf${queryString ? `?${queryString}` : ''}`);
|
||||
const result = await getDcData("/api/v1/dc/clsf?clsfSystmNm=" + clsfSystmNm);
|
||||
return result;
|
||||
};
|
||||
export const useDcTree = (clsfSystmNm:string) => {
|
||||
const [data, setData] = useState<SelectDataType[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetch = async () => {
|
||||
const result = await getDcTree(clsfSystmNm);
|
||||
if (result) {
|
||||
setData(result);
|
||||
}
|
||||
};
|
||||
fetch();
|
||||
}, [clsfSystmNm]);
|
||||
|
||||
return data;
|
||||
};
|
||||
export const getDcFile = async (clsfSystmSn:string) => {
|
||||
const queryString = 'clsfSystmNm='+clsfSystmSn;
|
||||
console.log("getDcTree queryString:", queryString);
|
||||
const result = await getDcData(`/api/v1/dc/file${queryString ? `?${queryString}` : ''}`);
|
||||
return result;
|
||||
};
|
||||
export const addDcFileName = async(data: any) => {
|
||||
const updated = await Promise.all(
|
||||
data.map(async (item) => {
|
||||
const fileName = await getDcFile(item.systmSn);
|
||||
return { ...item, fileName };
|
||||
})
|
||||
);
|
||||
return updated;
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import { VerticalTable } from '../../../components/ui/verticalTable';
|
||||
import React, { useState } from 'react'
|
||||
import InputSection from '../InputSection';
|
||||
import { handleInputChange } from '../common';
|
||||
import { Button } from '@common/components/ui';
|
||||
import InfilChart from './chart/infilChart';
|
||||
// 하수관로
|
||||
// TODO: RDII 버튼인가 그거 팝업 두개 구현 필요
|
||||
const inputColumn = [
|
||||
{ id: "title", title: "설치주제", type: "select", options: ["BTL", "재정사업"] },
|
||||
{ id: "swtrmt_zone_cd", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
|
||||
{ id: "basu", title: "배수구역", type: "input" },
|
||||
{ id: "mltv_dtdv_nm", title: "배수분구", type: "input" },
|
||||
{ id: "wltjs", title: "지선/간선", type: "select", options: ["지선", "간선"] },
|
||||
{ id: "flow", title: "흐름방식", type: "select", options: ["자연유하", "압송"] },
|
||||
{ id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] },
|
||||
];
|
||||
const SwtrmtFclt = ({ featureData }: { featureData: any }) => {
|
||||
console.log("featureData", featureData);
|
||||
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
||||
const [btnTxt, setBtnTxt] = useState<string>("");
|
||||
const openModal = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.currentTarget.textContent && setBtnTxt(e.currentTarget.textContent)
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
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 dataMap = {
|
||||
repair: { data: repairData, setData: setRepairData },
|
||||
cleaning: { data: cleaningData, setData: setCleaningData },
|
||||
inspection: { data: inspectionData, setData: setInspectionData },
|
||||
};
|
||||
const keysToExtract = [
|
||||
"swtrmt_zone_cd",
|
||||
"mltv_dtdv_nm",
|
||||
"fid",
|
||||
"lyrTypeNm",
|
||||
"reg_dt",
|
||||
"mdfcn_dt",
|
||||
"rgtr",
|
||||
"mdfr",
|
||||
];
|
||||
// const filteredData = Object.entries(featureData)
|
||||
// .filter(([key]) => keysToExtract.includes(key)) // 필요한 키만 필터링
|
||||
// .map(([key, value]) => ({ key, value: value ?? "N/A" })); // 테이블 데이터 형식으로 변환
|
||||
|
||||
return (
|
||||
<div>
|
||||
<VerticalTable headName='자체 입력정보' tableData={[]} headlist={inputColumn} pageSize={20} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}}></VerticalTable>
|
||||
<InputSection title="보수 및 갱신" data={repairData} sectionKey="repair" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<InputSection title="청소 및 준설" data={cleaningData} sectionKey="cleaning" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<InputSection title="점검 및 진단" data={inspectionData} sectionKey="inspection" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<div className="absolute bottom-0 left-0 w-full flex justify-start space-x-2 p-4">
|
||||
<Button
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||
onClick={openModal}
|
||||
>
|
||||
Infil
|
||||
</Button>
|
||||
<Button
|
||||
className="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
|
||||
onClick={openModal}
|
||||
>
|
||||
RDII
|
||||
</Button>
|
||||
</div>
|
||||
<InfilChart btnTxt={btnTxt} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} closeModal={closeModal} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SwtrmtFclt
|
||||
@@ -1,49 +0,0 @@
|
||||
import Modal from '../../../components/ui/modal';
|
||||
import { VerticalTable } from '../../../components/ui/verticalTable';
|
||||
import { UiTable } from '@common/business_components/ui';
|
||||
import { Button, TableCell } from '@common/components/ui';
|
||||
import React, { useState } from 'react'
|
||||
|
||||
// 하수처리시설
|
||||
const headList = [
|
||||
{ id: "title", title: "하수도정비 기본계획보고서" },
|
||||
{ id: "cad", title: "하수도대장 평면도" },]
|
||||
const modalHeadList = [
|
||||
{ id: "no", title: "번호" },
|
||||
{ id: "year", title: "승인연도" },
|
||||
{ id: "cad", title: '평면도'},
|
||||
{ id: "fileNm", title: "파일명" },
|
||||
{ id: "date", title: "입력시간" },
|
||||
]
|
||||
|
||||
const SwtrmtFclt = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [modalTitle, setModalTitle] = useState<string>('');
|
||||
const openModal = (title:string) => {
|
||||
setIsModalOpen(true);
|
||||
setModalTitle(title)
|
||||
};
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<VerticalTable children={{
|
||||
title: <Button onClick={() => openModal('하수도정비 기본계획보고서')}>보고서</Button>,
|
||||
cad: <Button onClick={() => openModal('하수도대장 평면도')}>평면도</Button>,
|
||||
}} headName='디지털 자료관 연계정보' tableData={[]} headlist={headList} pageSize={20} total={0} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}}></VerticalTable>
|
||||
<Modal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} closeModal={closeModal}>
|
||||
<div className='grid grid-col-2'>
|
||||
<UiTable headName={modalTitle} tableData={[]} headlist={modalHeadList} pageSize={20} total={0} cellClick={undefined} children={undefined} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}
|
||||
}></UiTable>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SwtrmtFclt
|
||||
@@ -1,140 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { type ChartConfig, MainChart, CHART_FORM } from "@common/business_components";
|
||||
import Modal from '../../../../components/ui/modal';
|
||||
import { Button } from '@common/components/ui';
|
||||
type ModalOpenProp = {
|
||||
isModalOpen: boolean,
|
||||
setIsModalOpen: (open: boolean) => void,
|
||||
closeModal: () => void,
|
||||
btnTxt?: string,
|
||||
}
|
||||
const InfilChart = ({ btnTxt, isModalOpen, setIsModalOpen, closeModal }: ModalOpenProp) => {
|
||||
const [popupOpen, setPopupOpen] = React.useState(false);
|
||||
const buttonRef = React.useRef<HTMLButtonElement>(null); // 버튼 참조
|
||||
const [popupPosition, setPopupPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 }); // 팝업 위치
|
||||
const openPopup = () => {
|
||||
if (buttonRef.current) {
|
||||
const rect = buttonRef.current.getBoundingClientRect(); // 버튼 위치 계산
|
||||
setPopupPosition({
|
||||
top: rect.bottom + window.scrollY, // 버튼 아래쪽
|
||||
left: rect.left + window.scrollX, // 버튼 왼쪽
|
||||
});
|
||||
}
|
||||
setPopupOpen(true); // 팝업 열기
|
||||
};
|
||||
console.log("btnTxt", btnTxt);
|
||||
const closePopup = () => {setPopupOpen(false);}; // 팝업 닫기
|
||||
const chartForm = CHART_FORM.LINE;
|
||||
const chartData = {
|
||||
chartData1: [
|
||||
{ label: "1", val: 20 },
|
||||
{ label: "3", val: 40 },
|
||||
{ label: "5", val: 60 },
|
||||
],
|
||||
chartData2: [
|
||||
{ label: "1", val: 15 },
|
||||
{ label: "3", val: 35 },
|
||||
{ label: "5", val: 55 },
|
||||
],
|
||||
}
|
||||
const chartConfig = Object.values(chartData).flat().reduce((config, element) => {
|
||||
config[element.label] = {
|
||||
label: element.label,
|
||||
color: "hsl(var(--chart-1))",
|
||||
};
|
||||
return config;
|
||||
}, {} as Record<string, { label: string; color: string }>) satisfies ChartConfig;
|
||||
const getCurrentDate = () => {
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = String(today.getMonth() + 1).padStart(2, "0"); // 월은 0부터 시작하므로 +1
|
||||
return `${year}-${month}`;
|
||||
};
|
||||
return (
|
||||
<Modal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} closeModal={closeModal}>
|
||||
{/* 분석 입력현황 조회 */}
|
||||
<div className='grid grid-cols-4 gap-4'>
|
||||
<div className="grid grid-rows-4 gap-4 mb-4">
|
||||
<Button className="bg-white text-white w-[130px] font-bold px-4 mt-2 py-2" onClick={openPopup}>
|
||||
분석 입력현황 조회
|
||||
</Button>
|
||||
|
||||
{/* 침입수량 분석결과 */}
|
||||
<div className="bg-white text-red-600 font-bold px-4 py-2 ">
|
||||
침입수량 분석결과
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="text-black text-xl font-bold">120</span>
|
||||
<span className="ml-2 text-black">m³/d</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 차트 */}
|
||||
<div className="w-[500px] h-[300px] bg-white p-4">
|
||||
<MainChart chartConfig={chartConfig} chartForm={chartForm} chartData={chartData} chartTitle={'관로유량'} />
|
||||
</div>
|
||||
</div>
|
||||
{popupOpen && (
|
||||
<div
|
||||
className="absolute bg-gray-100 border border-gray-300 w-[320px] shadow-lg p-4 rounded"
|
||||
style={{
|
||||
top: popupPosition.top,
|
||||
left: popupPosition.left,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<div className="text-lg font-bold mb-2">분석 입력현황</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>상수사용량 정보:</div>
|
||||
<div>
|
||||
<input type='month' defaultValue={getCurrentDate()} className="border border-gray-300 rounded px-2 py-1"/>
|
||||
</div>
|
||||
<div>오수 전환율:</div>
|
||||
<div>
|
||||
<select className="border border-gray-300 rounded px-2 py-1">
|
||||
<option>0.85</option>
|
||||
<option>0.90</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>수용가-맨홀 매칭:</div>
|
||||
<div>
|
||||
<select className="border border-gray-300 rounded px-2 py-1">
|
||||
<option>매칭(양평).shp</option>
|
||||
<option>매칭(서울).shp</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>관망도 자료:</div>
|
||||
<div>
|
||||
<select className="border border-gray-300 rounded px-2 py-1">
|
||||
<option>양평.inp</option>
|
||||
<option>서울.inp</option>
|
||||
</select>
|
||||
</div>
|
||||
{btnTxt === 'RDII' ? <><div>강우 자료:</div>
|
||||
<div>
|
||||
<select className="border border-gray-300 rounded px-2 py-1">
|
||||
<option>R20240815.xlsx</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>RTX 계수 출처:</div>
|
||||
<div>
|
||||
<select className="border border-gray-300 rounded px-2 py-1">
|
||||
<option>2015년 하수도정비기본계획</option>
|
||||
</select>
|
||||
</div>
|
||||
</> : null}
|
||||
</div>
|
||||
<div className="flex justify-end mt-4 space-x-2">
|
||||
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={closePopup}>
|
||||
저장
|
||||
</button>
|
||||
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={closePopup}>
|
||||
종료
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default InfilChart
|
||||
@@ -1,18 +0,0 @@
|
||||
import { VerticalTable } from '../../../components/ui/verticalTable';
|
||||
import React from 'react'
|
||||
const inputColumn = [
|
||||
{ id: "swtrmt_zone_cd", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
|
||||
{ id: "mltv_dtdv_nm", title: "배수분구", type: "input" },
|
||||
{ id: "freq", title: "설계빈도", type: "input" },
|
||||
]
|
||||
// 오수펌프
|
||||
const sewagePump = ({ featureData }: { featureData: any }) => {
|
||||
return (
|
||||
<div><VerticalTable headName='자체 입력정보' tableData={[]} headlist={inputColumn} pageSize={0} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default sewagePump
|
||||
@@ -1,21 +0,0 @@
|
||||
// 하수맨홀
|
||||
import { VerticalTable } from '../../../components/ui/verticalTable';
|
||||
import React from 'react'
|
||||
const inputColumn = [
|
||||
{ id: "guyeok", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
|
||||
{ id: "basu", title: "배수구역", type: "input" },
|
||||
{ id: "bungu", title: "배수분구", type: "input" },
|
||||
{ id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] },
|
||||
{id:'spec', title:'규격', type:'input'},
|
||||
];
|
||||
const Smh = () => {
|
||||
return (
|
||||
<div>
|
||||
<VerticalTable headName='자체 입력정보' tableData={[]} headlist={inputColumn} pageSize={20} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}}></VerticalTable>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Smh;
|
||||
@@ -1,19 +0,0 @@
|
||||
import { VerticalTable } from '../../../components/ui/verticalTable';
|
||||
import React from 'react'
|
||||
const inputColumn = [
|
||||
{ id: "swtrmt_zone_cd", title: "처리구역", type: "input" },
|
||||
{ id: "mltv_dtdv_nm", title: "배수분구", type: "input" },
|
||||
]
|
||||
// 빗물펌프
|
||||
const StormWaterPump = ({ featureData }: { featureData: Record<string, any> }) => {
|
||||
const validKey = inputColumn.map((item) => item.id);
|
||||
const filteredData = featureData && Object.entries(featureData).filter(([key]) => validKey.includes(key)).reduce((obj: Record<string, any>, [key, value]) => {obj[key] = value; return obj;}, {});
|
||||
return (
|
||||
<div><VerticalTable headName='자체 입력정보' tableData={[filteredData]} headlist={inputColumn} pageSize={0} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StormWaterPump
|
||||
Reference in New Issue
Block a user