diff --git a/.gitignore b/.gitignore
index 6b685ea40..945daeeba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# turbo
.turbo/
+.vscode/**/*
# dependencies
node_modules/
diff --git a/apps/fo/.env.development b/apps/fo/.env.development
index d362ecf94..de81dde66 100644
--- a/apps/fo/.env.development
+++ b/apps/fo/.env.development
@@ -5,7 +5,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
-NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
diff --git a/apps/fo/.env.local b/apps/fo/.env.local
index 4313985b8..2e937af0c 100644
--- a/apps/fo/.env.local
+++ b/apps/fo/.env.local
@@ -5,7 +5,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
-NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
diff --git a/apps/fo/.env.production b/apps/fo/.env.production
index aa2cb2c90..797328765 100644
--- a/apps/fo/.env.production
+++ b/apps/fo/.env.production
@@ -18,7 +18,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
-NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
diff --git a/apps/fo/app/pages/(map-layout)/map/page.tsx b/apps/fo/app/pages/(map-layout)/map/page.tsx
index ad3f70295..984a8afa7 100644
--- a/apps/fo/app/pages/(map-layout)/map/page.tsx
+++ b/apps/fo/app/pages/(map-layout)/map/page.tsx
@@ -3,7 +3,7 @@
import Gis from "@common/business_components/ui/map/Gis";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { useEffect, useRef, useState } from "react";
-import { ProcSearchBar } from "@common/business_components/ui/map/searchBar";
+import { SearchBar } from "@common/business_components/ui/map/searchBar";
// OpenLayers overlay/extent 유틸
import Overlay from "ol/Overlay";
@@ -278,7 +278,19 @@ const Map = () => {
setIsSearchModalOpen(false);
};
- // (선택) 다른 위치 클릭 시 오버레이 닫고 싶다면 Gis 쪽에서 지도 클릭 이벤트 받아 여기서 제거하는 훅을 연결하면 됨.
+ const onInit = () => {
+
+ const map = gisMaps.current;
+ if (!map) {
+ console.warn("지도가 초기화되지 않았습니다.");
+ return;
+ }
+
+ if (overlayRef.current) {
+ map.removeOverlay?.(overlayRef.current);
+ overlayRef.current = null;
+ }
+ }
return (
@@ -299,7 +311,7 @@ const Map = () => {
onCheckedLayersChange={undefined}
imgVisble={false}
searchBar={
-
+
}
waterDepth={undefined}
/>
diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx
index 06ca11cc1..4081b4547 100644
--- a/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx
+++ b/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx
@@ -6,17 +6,21 @@ import ListDiv from "@common/business_components/ui/list_div";
import { Table, TableCell, TableHead, TableRow } from "@common/components/ui";
import { useEffect, useState } from "react";
-
export default function SewageOccurModal(props: { fcltyName: string; facilityCd : string; searchYear : string}) {
// 그리드 관련
const {SewageOccurDetail, searchSewageOccurDetailList} = useFoStore((state) => state);
// searchYear 유효성 검사 및 기본값 설정
const validSearchYear = props.searchYear && /^\d{4}$/.test(props.searchYear) ? props.searchYear : new Date().getFullYear().toString();
+
const [startYearMonth, setStartYearMonth] = useState(validSearchYear+'01');
const [endYearMonth, setEndYearMonth] = useState(validSearchYear+'12');
const [detailList, setDetailList] = useState
([]);
+
+ // 가능한 시작년월 설정
+ const [enableEndMonth, setEnableEndMonth] = useState(['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']);
+
const {
upHeadListSewageOccurDetail,
gridListSewageOccurDetail
@@ -33,7 +37,29 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd
useEffect(() => {
searchSewageOccurDetailList(props.facilityCd, validSearchYear, startYearMonth, endYearMonth);
- }, [startYearMonth, endYearMonth]);
+ }, [startYearMonth, endYearMonth, searchSewageOccurDetailList, props.facilityCd, validSearchYear]);
+
+ useEffect(() => {
+ const standdardMonthList = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']
+ setEnableEndMonth(standdardMonthList);
+ // 시작년월이 바뀌면 선택가능한 년월 데이터가 변경돼야 한다.
+ if(startYearMonth){
+ const startMm = startYearMonth.substring(4, 6);
+
+ if(endYearMonth < startYearMonth) {
+ setEndYearMonth(startYearMonth);
+ }
+
+ standdardMonthList.forEach((month) => {
+ setEnableEndMonth((prev) => {
+ if (parseInt(month.replaceAll('월', '')) < parseInt(startMm)) {
+ return prev.filter((m) => m !== month);
+ }
+ return prev;
+ });
+ });
+ }
+ }, [endYearMonth, startYearMonth]);
return (
<>
@@ -63,6 +89,7 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd
selectClass="ml-5 w-[100px]"
startYear={1900}
yearReadOnly={true}
+ enableMonth={['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']}
/>~
diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx
index 5feb91f94..f97520d17 100644
--- a/apps/fo/app/store/sewageOccur/index.tsx
+++ b/apps/fo/app/store/sewageOccur/index.tsx
@@ -222,6 +222,7 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
},
}));
const res = await fetchSewageOccurList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
+ const excelDownList: ExcelType[] = [];
const data = res.data;
// Promise.all을 사용하여 모든 비동기 작업이 완료될 때까지 기다림
const calData = await Promise.all(data.map(async (item: SewageOccurProps) => {
@@ -301,6 +302,28 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
item.estimationSewage = parseFloat((item.waterUsage * (item.swageChangePercent/100)).toFixed(2));
return item;
}));
+
+ if(pageSize>5000){
+ calData.forEach((item: SewageOccurProps) => {
+ excelDownList.push({
+ 시설코드: item.bscFctCd,
+ 권역: item.rvbsn,
+ 단위유역: item.lgbsn,
+ 중권역: item.mdmbsn,
+ 환경청: item.rgnNm,
+ 시설명: item.bscFctNm,
+ 시도: item.sido,
+ 시군구: item.sigungo,
+ 주소: item.daddr,
+ 시설용량: item.fctCpc,
+ 물사용량: item.waterUsage,
+ 오수전환율: item.swageChangePercent,
+ 오수발생량추정: item.estimationSewage,
+ 연간하수유입량 : item.sewageInputYear,
+ 청천시하수유입량 : item.sewageInputChungchun,
+ });
+ });
+ }
// 조회 데이터 설정
set((state: any) => ({
...state,
@@ -311,7 +334,7 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
isLoading : false,
}:{
...state.SewageOccur,
- excelList: [],
+ excelList: excelDownList,
isLoading : false,
},
}))
diff --git a/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx b/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx
index eee60ca41..623758ec3 100644
--- a/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx
+++ b/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx
@@ -26,12 +26,14 @@ interface SearchBarProps {
gisMaps: React.RefObject;
facilityTypes: { text: string; val: string }[];
onFeatureFocus: any;
+ onInit?: any;
}
export const SearchBar = ({
gisMaps,
facilityTypes,
onFeatureFocus,
+ onInit = () => { },
}: SearchBarProps) => {
const [sidoValue, setSidoValue] = useState("0");
const [sigunValue, setSigunValue] = useState("0");
@@ -134,10 +136,8 @@ export const SearchBar = ({
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
val: f.id,
}));
- } else if (
- type === "tb_wr_bdst_ruse_fclt" // 재이용시설
- ) {
- //재이용에서 참조하는 하수처리시설 목록
+ } else if (type === "tb_wr_bdst_ruse_fclt") {
+ // 재이용시설
const procRes = await fetch("/reuse-service/reuseFc/pubFc");
const procJson = await procRes.json();
const procData = procJson.data;
@@ -147,8 +147,8 @@ export const SearchBar = ({
return code;
});
- //처리시설명으로 처리시설코드 조회
- let procUrl2 = "/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}";
+ let procUrl2 =
+ "/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}";
procUrl2 = procUrl2
.replace("{sggCd}", sigunValue)
.replace("{fcltyNm}", encodeURIComponent(fcltyNm));
@@ -161,9 +161,10 @@ export const SearchBar = ({
body: JSON.stringify(procResult),
});
const procJson2 = await procRes2.json();
- const procResult2 = (procJson2.data || []).map((item: any) => item.bscFctCd);
+ const procResult2 = (procJson2.data || []).map(
+ (item: any) => item.bscFctCd
+ );
- //최종 처리시설코드로 재이용시설조회
const res = await fetch(url, {
method: "POST",
headers: {
@@ -177,20 +178,16 @@ export const SearchBar = ({
text: item.ruseUtztnFcltNm ?? "(이름없음)",
val: item.pbnstRuseFcltId,
}));
-
- } else if (
- type === "tb_wr_ruse_fclt_dmd_co" //수요처
- ) {
+ } else if (type === "tb_wr_ruse_fclt_dmd_co") {
+ // 수요처
const res = await fetch(url);
const json = await res.json();
list = (json.data || []).map((item: any) => ({
text: item.dmdCoNm ?? "(이름없음)",
val: item.dmdInfoId,
}));
- } else if (
- type === "tb_wr_tmpr_dmd_co" //잠재수요처
- ) {
- // GET 방식
+ } else if (type === "tb_wr_tmpr_dmd_co") {
+ // 잠재수요처 (GET)
const res = await fetch(url);
const json = await res.json();
list = (json.data || []).map((item: any) => ({
@@ -198,7 +195,7 @@ export const SearchBar = ({
val: item.fctryMngSn,
}));
} else {
- // GET 방식
+ // 기타 (GET)
const res = await fetch(url);
const json = await res.json();
list = (json.data || []).map((item: any) => ({
@@ -222,14 +219,12 @@ export const SearchBar = ({
setSearchList(newList);
};
- //해당 시설물로 이동
+ //해당 시설물로 이동
const handleFeatureFocus = (data: any) => {
-
let featureId = data.fid;
const layerNm = data.layerNm;
if (!isNaN(Number(featureId))) {
- // 숫자면 문자열로 변환
featureId = String(featureId);
}
@@ -246,12 +241,9 @@ export const SearchBar = ({
console.warn("지도가 초기화되지 않았습니다.");
return;
}
- // 항상 같은 select 객체 사용
const select = GisApp.Module.select as any;
if (!select) return;
- // 1. 기존 선택 초기화
- //select.resetSelectedFeature();
- // 2. data가 OpenLayers Feature 인스턴스인지 확인
+
let foundFeature: any = null;
map
@@ -264,7 +256,7 @@ export const SearchBar = ({
if (feature) foundFeature = feature;
}
});
- // 3. 피처 선택
+
if (foundFeature) {
const geometry = foundFeature.getGeometry();
if (geometry) {
@@ -284,7 +276,28 @@ export const SearchBar = ({
console.warn("Feature를 찾을 수 없습니다:", data);
}
- onFeatureFocus(foundFeature);
+ if (onFeatureFocus) {
+ onFeatureFocus(foundFeature);
+ }
+ };
+
+ // 초기화(검색 조건 리셋)
+ const handleInit = () => {
+ // 시설 구분 기본값: 단일 항목이면 그 값, 아니면 "0"
+ const defaultFacilityType =
+ facilityTypes?.length === 1 && facilityTypes[0]
+ ? facilityTypes[0].val
+ : "0";
+
+ // 시도/시군구/시설구분/시설명/검색목록 초기화
+ setSidoValue("0");
+ initializeSigunData("0"); // 시군구 목록도 "시군구/0"로 리셋되고, sigunValue도 "0"으로 맞춤
+ setFacilityType(defaultFacilityType);
+ setFcltyNm("");
+ setSearchList([]);
+
+ // 필요 시 외부 초기화 콜백 실행
+ onInit?.();
};
return (
@@ -314,7 +327,9 @@ export const SearchBar = ({
selectClass="rounded-lg bg-white"
label=""
selectArray={sidoData}
- onSelectValue={(val: any) => onSelectValue(val.toString(), "ctpvCd")}
+ onSelectValue={(val: any) =>
+ onSelectValue(val.toString(), "ctpvCd")
+ }
value={sidoValue}
/>
onSelectValue(val.toString(), "sggCd")}
+ onSelectValue={(val: any) =>
+ onSelectValue(val.toString(), "sggCd")
+ }
value={sigunValue}
/>
{
- // 선택된 항목이 있을 경우 onFeatureSelect 실행
const type = facilityType;
handleFeatureFocus({
layerNm: type,
@@ -353,6 +369,16 @@ export const SearchBar = ({
>
조회
+ {onInit && (
+
+ )}