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/common/features/.gitignore b/apps/common/features/.gitignore
index b660a552e..e8d8437ee 100644
--- a/apps/common/features/.gitignore
+++ b/apps/common/features/.gitignore
@@ -37,5 +37,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts
-.env*
-__ENV__.js
\ No newline at end of file
+.env*
\ No newline at end of file
diff --git a/apps/common/features/cli.js b/apps/common/features/cli.js
deleted file mode 100644
index 9f165f497..000000000
--- a/apps/common/features/cli.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { findUp } from "find-up";
-import { config } from "dotenv";
-import fs from "fs";
-import yargs from "yargs";
-import { hideBin } from "yargs/helpers";
-
-async function parseDotenv(nodeEnv) {
- const envFilePath = await findUp(`.env.${nodeEnv}`);
-
- const parsedEnv = config({ path: envFilePath }).parsed || {};
-
- return parsedEnv;
-}
-
-function writeEnv(parsedEnv) {
- const scriptFilePath = `${fs.realpathSync(process.cwd())}/public/__ENV__.js`;
-
- fs.writeFileSync(
- scriptFilePath,
- `window.__ENV__ = ${JSON.stringify(parsedEnv)}`,
- );
-}
-
-yargs(hideBin(process.argv))
- .command(
- "next-env",
- "Create Next.js runtime environment js",
- function builder(y) {
- return y.option("env", {
- alias: "e",
- type: "string",
- description: "Environment name(ex: development, production)",
- });
- },
- async function handler(args) {
- const nodeEnv = args.e || args.env || "development";
-
- const parsedEnv = await parseDotenv(nodeEnv); // dotenv 파싱
- writeEnv(parsedEnv); // 환경 변수 스크립트 파일 생성
-
- return parsedEnv;
- },
- )
- .parse();
diff --git a/apps/common/features/package.json b/apps/common/features/package.json
index bfa43377e..304e88bae 100644
--- a/apps/common/features/package.json
+++ b/apps/common/features/package.json
@@ -1,12 +1,11 @@
{
"name": "features",
"version": "0.1.0",
- "type": "module",
"private": true,
"scripts": {
- "dev": "node cli.js next-env -e ${NODE_ENV:-development} && next dev -p 13000",
+ "dev": "next dev -p 13000",
"build": "next build",
- "start": "node cli.js next-env -e ${NODE_ENV:-production} && next start -p 13000",
+ "start": "next start -p 13000",
"lint": "next lint"
},
"dependencies": {
@@ -28,8 +27,6 @@
"axios": "^1.8.1",
"chart.js": "^4.4.8",
"dayjs": "^1.11.13",
- "dotenv": "^17.2.1",
- "find-up": "^7.0.0",
"js-cookie": "^3.0.5",
"next": "15.3.0",
"next-themes": "^0.4.6",
@@ -48,7 +45,6 @@
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.13.1",
"@types/webpack": "^5.28.5",
- "@types/yargs": "^17.0.33",
"eslint": "^9",
"eslint-config-next": "15.1.7",
"postcss": "^8",
diff --git a/apps/common/features/src/app/index.tsx b/apps/common/features/src/app/index.tsx
index eb6e75d00..692b55ef0 100644
--- a/apps/common/features/src/app/index.tsx
+++ b/apps/common/features/src/app/index.tsx
@@ -4,16 +4,12 @@ import "@fontsource-variable/noto-sans-kr";
import { AppProvider } from "./providers";
import { cookies } from "next/headers";
-import Script from "next/script";
const App = async ({ children }: Readonly<{ children: React.ReactNode }>) => {
const theme = (await cookies()).get("site-theme-key");
return (
-
-
-
{children}
diff --git a/apps/common/features/src/shared/config/api.ts b/apps/common/features/src/shared/config/api.ts
index df4c0da7d..67b8948d7 100644
--- a/apps/common/features/src/shared/config/api.ts
+++ b/apps/common/features/src/shared/config/api.ts
@@ -1,10 +1,6 @@
-"use client";
+import { PROXY_HOST } from "./env";
-import { getCookie, getEnv } from "../lib";
-
-const SITE_ID = getCookie("site-id-key") ?? "";
-const PROXY_HOST_KEY = `NEXT_PUBLIC_PROXY_HOST_${SITE_ID}`;
-export const BASE_URL = `${getEnv(PROXY_HOST_KEY)}/server`;
+export const BASE_URL = `${PROXY_HOST}/server`;
export const ENDPOINT = {
ATTACH_SERVICE: {
diff --git a/apps/common/features/src/shared/lib/env.ts b/apps/common/features/src/shared/lib/env.ts
deleted file mode 100644
index 4ad7ad5a2..000000000
--- a/apps/common/features/src/shared/lib/env.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-declare global {
- interface Window {
- __ENV__?: Record;
- }
-}
-
-export function getEnvConfig(): Record {
- if (typeof window === "undefined") return {};
- return window.__ENV__ ?? {};
-}
-
-export function getEnv(key: string): string | undefined {
- return getEnvConfig()[key];
-}
diff --git a/apps/common/features/src/shared/lib/index.ts b/apps/common/features/src/shared/lib/index.ts
index 82bb6c8b7..42ec7d509 100644
--- a/apps/common/features/src/shared/lib/index.ts
+++ b/apps/common/features/src/shared/lib/index.ts
@@ -3,4 +3,3 @@ export { useAlertStore } from "./use-alert-store";
export { useMenuStore } from "./use-menu-store";
export { useUserStore } from "./use-user-store";
export { usePrompt } from "./use-prompt";
-export { getEnv } from "./env";
diff --git a/apps/common/features/tsconfig.json b/apps/common/features/tsconfig.json
index f0333a1b7..f12491cae 100644
--- a/apps/common/features/tsconfig.json
+++ b/apps/common/features/tsconfig.json
@@ -27,7 +27,6 @@
"@/*": ["./*"],
"@common/assets": ["../../../../packages/common/assets/dist/"],
"@common/components": ["../../../../packages/common/components/dist/"],
- "@common/config": ["../../../../packages/common/config/dist/"],
"@common/network": ["../../../../packages/common/network/"]
}
},
diff --git a/apps/cs/src/pages/link/ui/link-form.tsx b/apps/cs/src/pages/link/ui/link-form.tsx
index 41f125335..d46696d88 100644
--- a/apps/cs/src/pages/link/ui/link-form.tsx
+++ b/apps/cs/src/pages/link/ui/link-form.tsx
@@ -195,7 +195,13 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink,
- * 연계 URL
+
+ {['link0001', 'link0002'].includes(form.watch('link_clsf_cd') as string) ? '* 연계 데이터베이스 URL' :
+ (form.watch('link_clsf_cd') === 'link0007' ? '* 연계 파일 경로'
+ : '* 연계 URL'
+ )
+ }
+
- * 연계 KEY
+
+ {['link0001', 'link0002'].includes(form.watch('link_clsf_cd') as string) ? '* 연계 데이터베이스 DRIVER' :
+ (form.watch('link_clsf_cd') === 'link0007' ? '* 연계 파일 확장자'
+ : '* 연계 KEY'
+ )
+ }
+
) {
+
+ useEffect(() => {
+ // 렌더 중이 아니라 클라이언트에서만 실행 + 에러 캐치
+ void LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" })
+ .catch((e) => {
+ console.error("Auto login failed:", e);
+ });
+ }, []);
return (
- {children}
+ {children}
diff --git a/apps/fo/app/pages/(map-layout)/map/page.tsx b/apps/fo/app/pages/(map-layout)/map/page.tsx
index 7c1d78164..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";
@@ -73,6 +73,18 @@ const Map = () => {
fetchData();
}, []);
+ function formatWithCommas(value: any) {
+ if (value === null || value === undefined) return value;
+ const num = Number(value);
+ return isNaN(num) ? value : num.toLocaleString();
+ }
+
+ function formatDateString(dateStr: string) {
+ dateStr = dateStr.trim();
+ if (typeof dateStr !== "string" || dateStr.length !== 8) return dateStr;
+ return `${dateStr.slice(0, 4)}-${dateStr.slice(4, 6)}-${dateStr.slice(6)}`;
+ }
+
// ===== 오버레이 콘텐츠 빌더 =====
const buildOverlayContent = (layerType: string, feature: FeatureData) => {
const props: Record = {};
@@ -80,15 +92,13 @@ const Map = () => {
const mayGet = (k: string) => (feature.get ? feature.get(k) : undefined);
const safe = (v: any) => (v === undefined || v === null ? "-" : String(v));
- console.log(feature);
-
// 레이어 유형별 대표 필드 추출(없으면 "-")
if (layerType === "tb_il_swage_prcs_fclt") {
// 하수처리시설
props["하수처리시설명"] = mayGet("swtrmt_fclt_nm");
- props["시설용량(m³/d)"] = mayGet("fclt_cpct");
+ props["시설용량(m³/d)"] = formatWithCommas(mayGet("fclt_cpct"));
props["주소"] = mayGet("rdnm_addr");
- props["가동개시일"] = mayGet("oprtng_strt_ymd");
+ props["가동개시일"] = formatDateString(mayGet("oprtng_strt_ymd"));
props["공법"] = mayGet("rprs_msrc_cn");
} else if (layerType === "tb_ms_swage_prcs_zone") {
// 처리구역(존)
@@ -118,14 +128,14 @@ const Map = () => {
${title}
${Object.entries(props)
- .map(
- ([k, v]) => `
+ .map(
+ ([k, v]) => `
| ${k} |
${safe(v)} |
`
- )
- .join("")}
+ )
+ .join("")}
`;
return el;
@@ -268,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 (
@@ -289,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/rdi/index.tsx b/apps/fo/app/store/rdi/index.tsx
index b1eccc2b7..fd9ca52b6 100644
--- a/apps/fo/app/store/rdi/index.tsx
+++ b/apps/fo/app/store/rdi/index.tsx
@@ -219,7 +219,6 @@ type SetStateFunction = (state: RdiType | ((state: RdiType) => RdiType)) => void
export type RdiStore = RdiType & RdiActions;
export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunction) => {
- console.log("tableActionsExport");
return {
searchRdiList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
set((state: RdiType) => ({
diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx
index 5feb91f94..7eec53913 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.sidoNm, // sido ?? 타입에러 나서 수정함
+ 시군구: item.sggNm, //sgg ??
+ 주소: 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/apps/fo/app/store/store.tsx b/apps/fo/app/store/store.tsx
index 589bc4d78..f7f2222c6 100644
--- a/apps/fo/app/store/store.tsx
+++ b/apps/fo/app/store/store.tsx
@@ -1,4 +1,3 @@
-import { LoginApi } from '@/src/entities/auth/api/login-service';
import { createStore } from 'zustand/vanilla';
import { CommonReducer, commonState, type CommonStore, type CommonType } from './common';
import { dashBoardInitState, dashBoardReducer, type DashBoardStore, type DashBoardType } from './dashboard';
@@ -59,7 +58,6 @@ export const StoreZus =
}
) => {
return createStore()((set) => {
- LoginApi.login({userId: "CLEANWATER", password: "gktneh12!@"})
return {
...initState,
...CommonReducer(set),
diff --git a/apps/fo/src/entities/auth/api/login-service.ts b/apps/fo/src/entities/auth/api/login-service.ts
index 3f2d958c6..760858b99 100644
--- a/apps/fo/src/entities/auth/api/login-service.ts
+++ b/apps/fo/src/entities/auth/api/login-service.ts
@@ -28,9 +28,6 @@ export class LoginApiService implements LoginService {
const accessToken = response.headers.get(ACCESS_TOKEN);
const tokenId = response.headers.get(AUTH_USER_ID);
- console.log('accessToken ', accessToken)
- console.log('tokenId ', tokenId)
-
if (!accessToken || !tokenId) {
throw new Error("Missing required authentication tokens");
}
diff --git a/apps/sn/.env.development b/apps/sn/.env.development
index f08d2b517..0fffc4f89 100644
--- a/apps/sn/.env.development
+++ b/apps/sn/.env.development
@@ -3,7 +3,8 @@ 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_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
+# NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_CLAIM_NAME = Authorization
diff --git a/apps/sn/.env.local b/apps/sn/.env.local
index 232412579..35701bd81 100644
--- a/apps/sn/.env.local
+++ b/apps/sn/.env.local
@@ -3,7 +3,8 @@ 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_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
+# NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_CLAIM_NAME = Authorization
diff --git a/apps/sn/.env.production b/apps/sn/.env.production
index 946499394..3fb05262e 100644
--- a/apps/sn/.env.production
+++ b/apps/sn/.env.production
@@ -7,7 +7,8 @@ NEXT_PUBLIC_PORT = 3000
NEXT_PUBLIC_PROXY_HOST = https://sn.hasuon.or.kr
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
NEXT_PUBLIC_ADDR_URL = http://con.mind-one.co.kr:11082
-NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
+# NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_NGII_URL = http://10.98.25.94:18080/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC
diff --git a/apps/wr/.env.development b/apps/wr/.env.development
index da82fd281..ceaf190df 100644
--- a/apps/wr/.env.development
+++ b/apps/wr/.env.development
@@ -18,7 +18,8 @@ NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
-NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
+# NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/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/wr/.env.local b/apps/wr/.env.local
index 24fd548a8..4d8937ea6 100644
--- a/apps/wr/.env.local
+++ b/apps/wr/.env.local
@@ -10,7 +10,8 @@ NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
-NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
+# NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
diff --git a/apps/wr/.env.production b/apps/wr/.env.production
index e29f3cec6..4a0754665 100644
--- a/apps/wr/.env.production
+++ b/apps/wr/.env.production
@@ -5,7 +5,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/operation-service/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
-NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
+NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
+# NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
diff --git a/apps/wr/app/(map-layout)/map/mainMap/page.tsx b/apps/wr/app/(map-layout)/map/mainMap/page.tsx
index 7451ae4b5..0006631d3 100644
--- a/apps/wr/app/(map-layout)/map/mainMap/page.tsx
+++ b/apps/wr/app/(map-layout)/map/mainMap/page.tsx
@@ -6,7 +6,14 @@ import { mapService } from "../../service";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
import { SearchBar } from "@common/business_components/ui/map/searchBar/searchBar";
import { useWrStore } from "@/app/store";
-import { getFeatureCd } from "@/components/lib/func/mapUtil";
+import {
+ featurePopUpOpen,
+ getClickFeatureId,
+ getFeatureCd,
+ getSelectedLayers,
+ getWrFeaturePk,
+ getWrLayerNm,
+} from "@/components/lib/func/mapUtil";
import toast, { Toaster } from "react-hot-toast";
const Map = () => {
@@ -24,7 +31,7 @@ const Map = () => {
const fetchData = async () => {
try {
- const response = await mapService.getLyrStngs('WR_NETWORK');
+ const response = await mapService.getLyrStngs("WR_NETWORK");
setTreeData(response); // API 응답 저장
} catch (error) {
console.error("데이터 불러오기 실패:", error);
@@ -42,27 +49,15 @@ const Map = () => {
fetchData();
}, []);
- useEffect(() => {
- const bc = new BroadcastChannel("mapDetailPopUp");
- bc.onmessage = (event) => {
- if (event.data.type === "SELECT_FEATURE") {
- onFeatureSelect(event.data.feature);
- closePopup();
- }
- };
- }, []);
-
useEffect(() => {
const messageHandler = (event: MessageEvent) => {
if (event.data.type === "POPUP_CLOSED") {
if (event.data.target === "detail") {
- console.log("디테일 팝업 닫힘 감지됨");
setFeatureData(null);
setIsOpen(false);
setIsSearchModalOpen(true);
popupDetailRef.current = null;
} else {
- console.log("기타 팝업 닫힘 감지됨");
popupRef.current = null;
}
}
@@ -73,15 +68,6 @@ const Map = () => {
};
}, []);
- useEffect(() => {
- console.log("isFeatured ", isFeatured);
-
- if (isFeatured) {
- console.log("isFeatured ", isFeatured);
- onFeatureSelect(isFeatured);
- }
- }, [isFeatured]);
-
// 체크된 레이어 정보를 받는 핸들러
const handleCheckedLayersChange = (
checkedIds: string[],
@@ -93,10 +79,11 @@ const Map = () => {
// SearchModal, GisContent 등에서 호출
const onFeatureFocus = (data: any) => {
- console.log(data);
+ console.log('data',data)
};
- const onFeatureSelect = (data: any) => {
+ const onFeatureSelect = (data: any ,popUpClick?:boolean) => {
+
const map = gisMaps.current;
if (!map) {
console.warn("지도가 초기화되지 않았습니다.");
@@ -113,29 +100,21 @@ const Map = () => {
// 2. data가 OpenLayers Feature 인스턴스인지 확인
let foundFeature: any = null;
let featureId = data.fid;
- const layerName = data.layerNm;
- console.log("선택된 레이어 이름:", data, layerName);
- if (layerName === "하수재이용시설") {
+
+ if(popUpClick){
+ const layerName = getWrLayerNm(data);
+ const featurePk = getWrFeaturePk(layerName ?? "");
// 재이용시설
- featureId = `${layerName}.${data.searchPk}`;
- } else if (
- //빗물이용시설, 중수도시설
- layerName === "빗물이용시설" ||
- layerName == "중수도시설"
- ) {
- featureId = `${layerName}.${data.bdstInfoSn}`;
- } else if (layerName === "하수처리시설") {
- //하수처리시설
- featureId = `${layerName}.${data.bscFctCd}`;
- } else if (layerName === "온배수시설") {
- //온배수시설
- featureId = `${layerName}.${data.bdstRuseFcltSn}`;
- } else if (layerName == "수요처") {
- //수요처
- featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
- } else {
- console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName);
- featureId = `${layerName}.${data.fid || data.id || data.ftrIdn}`;
+ if (featurePk) {
+
+ const lastPk = layerName==='tb_wr_ruse_fclt_dmd_co'? data[featurePk].replaceAll("-", "") : data[featurePk]
+ featureId = `${layerName}.${lastPk}`;
+ } else {
+ console.warn("해당 피처는 선택된 레이어에서 찾을수 없습니다.");
+ }
+ }else{
+ featureId=getClickFeatureId(data)
+
}
map
.getLayers()
@@ -164,7 +143,11 @@ const Map = () => {
}
select.selectFeature(foundFeature, true);
} else {
- console.warn("OpenLayers Feature를 찾을 수 없습니다:", data);
+ console.warn("OpenLayers Feature를 찾을 수 없습니다:");
+ console.log("foundFeature :", foundFeature );
+ console.warn("featureId : ", featureId);
+ console.warn("data : ", data);
+ console.warn(": 끝");
}
const currentId = data?.fid || data?.id || data?.ftrIdn;
const lastId = featureData?.fid || featureData?.id || featureData?.ftrIdn;
@@ -172,37 +155,35 @@ const Map = () => {
setFeatureData(data);
setIsOpen(true);
setIsSearchModalOpen(false);
+
+ if (popUpClick && foundFeature&&!(
+ Object.keys(foundFeature?.getProperties()).length === 0 &&
+ foundFeature.constructor === Object
+ )){
+ const layerName = getWrLayerNm(data);
+ const isColumn = getFeatureCd(foundFeature.getProperties(), String(layerName));
+ if(layerName&&isColumn)
+ featurePopUpOpen(layerName,isColumn,popupDetailRef)
+ }
};
- const getSelectedLayers = (isFeature: any) => {
- const map = gisMaps.current;
- if (!map) {
- console.warn("지도가 초기화되지 않았습니다.");
- return;
+ useEffect(() => {
+ if (isFeatured) {
+ onFeatureSelect(isFeatured);
}
- let result = null;
- const layers = map
- ? map
- .getLayers()
- .getArray()
- .filter((l: any) => l.getVisible())
- : []; // gisMap이 null인지 확인 후 레이어 가져오기
- let featureLayer: { get: (key: string) => any } = { get: () => null };
- layers.forEach((layer: any) => {
- const source = layer.getSource();
- if (
- source &&
- source.hasFeature &&
- isFeature &&
- typeof isFeature.getId === "function" &&
- source.hasFeature(isFeature)
- ) {
- featureLayer = layer; // 피처가 속한 레이어 찾기)
+ }, [isFeatured]);
+
+ useEffect(() => {
+ const bc = new BroadcastChannel("mapDetailPopUp");
+ bc.onmessage = (event) => {
+ if (event.data.type === "SELECT_FEATURE") {
+ onFeatureSelect(event.data.feature,true);
+ closePopup();
}
- });
- result = featureLayer.get("lyrNm");
- return result;
- };
+ };
+ }, []);
+
+
const renderDetailView = useCallback(
(props: any) => {
@@ -213,45 +194,21 @@ const Map = () => {
}
const isFeature = props?.featureData;
-
- console.log('isFeature 1', isFeature)
- if( typeof isFeature.getProperties === "function" ){
-
+ if (typeof isFeature.getProperties === "function") {
if (
- Object.keys(isFeature?.getProperties()).length === 0 &&
- isFeature.constructor === Object
+ !(
+ Object.keys(isFeature?.getProperties()).length === 0 &&
+ isFeature.constructor === Object
+ )
) {
- const url = `/mapDetailPopUp?layerNm=${encodeURIComponent(props.seletectedLayerNm)}`;
- const width = window.screen.availWidth;
- const height = window.screen.availHeight;
- const left = 0;
- const top = 0;
- const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=no`;
- popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions);
- } else {
- const layerNm = getSelectedLayers(isFeature);
- const safeProps = isFeature.getProperties();
- const featureCd = getFeatureCd(safeProps, String(layerNm));
- const url = `/mapFeaturePopup?layerNm=${encodeURIComponent(String(layerNm))}&featureCd=${encodeURIComponent(featureCd)} `;
- const width =
- String(layerNm) === "하수재이용시설"
- ? Math.floor(window.innerWidth * 0.8)
- : Math.floor(window.innerWidth * 0.4); // 화면 폭의 40%
- const height =
- String(layerNm) === "하수재이용시설"
- ? Math.floor(window.innerHeight - 150)
- : Math.floor(window.innerHeight - 450); // 150px 여백 확보; // calc(100% - 70px)
- const left = (window.screen.availWidth - width) / 2;
- const top = (window.screen.availHeight - height) / 2;
- const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;
- popupDetailRef.current = window.open(
- url,
- "지도 시설 상세정보 팝업",
- popupOptions
- );
+ const layerNm = getSelectedLayers(isFeature,gisMaps);
+ const safeProps = isFeature.getProperties();
+ const featureCd = getFeatureCd(safeProps, String(layerNm));
+ if(layerNm)
+ featurePopUpOpen(layerNm,featureCd,popupDetailRef)
}
- }else{
- console.log(' data확인 필요')
+ } else {
+ console.log(" data확인 필요");
}
},
[checkedLayers, checkedLayersData, featureData] // 필요 시 의존성 넣기
@@ -265,9 +222,10 @@ const Map = () => {
}
};
- const onOpenPopup = (data:any) => {
- if(data){
-
+ const onOpenPopup = (data: any) => {
+ if (data) {
+ setIsOpen(true);
+ setFeatureData(null);
const url = `/mapDetailPopUp?layerNm=${encodeURIComponent(data)}`;
const width = window.screen.availWidth;
const height = window.screen.availHeight;
@@ -275,12 +233,10 @@ const Map = () => {
const top = 0;
const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=no`;
popupRef.current = window.open(url, "지도 레이어 팝업", popupOptions);
- }else{
- toast.error('시설 및 수요처가 선택되지 않았습니다.')
+ } else {
+ toast.error("시설 및 수요처가 선택되지 않았습니다.");
}
-
-
- }
+ };
return (
@@ -316,12 +272,12 @@ const Map = () => {
/>
}
waterDepth={undefined}
- onOpenPopup={(data:any) =>{
- onOpenPopup(data)
+ onOpenPopup={(data: any) => {
+ onOpenPopup(data);
}}
/>
-
+
);
};
diff --git a/apps/wr/app/(map-layout)/map/popup/page.tsx b/apps/wr/app/(map-layout)/map/popup/page.tsx
deleted file mode 100644
index ca7a07b43..000000000
--- a/apps/wr/app/(map-layout)/map/popup/page.tsx
+++ /dev/null
@@ -1,153 +0,0 @@
-// "use client";
-
-// import Gis from "@common/business_components/ui/map/Gis";
-// import { useEffect, useRef, useState, useCallback } from "react";
-// import { mapService } from "../service";
-// import NewWindowPopup from "../components/newWindowPopup";
-// import GisApp from "@common/business_components/ui/map/lib/gis.core";
-
-// const Map = () => {
-// const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
-// const gisMaps = useRef(null);
-// const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
-// const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태
-// const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
-// const [checkedLayers, setCheckedLayers] = useState([]);
-// const [checkedLayersData, setCheckedLayersData] = useState([]);
-
-// const fetchData = async () => {
-// try {
-// const response = await mapService.getLyrStngs();
-// setTreeData(response); // API 응답 저장
-// } catch (error) {
-// console.error("데이터 불러오기 실패:", error);
-// }
-// };
-
-// // 팝업 닫기 핸들러를 useCallback으로 메모이제이션
-// const handlePopupClose = useCallback(() => {
-// setIsOpen(false);
-// setFeatureData(null);
-// }, []);
-
-// // 컴포넌트 마운트 시 1회 실행
-// useEffect(() => {
-// fetchData();
-// }, []);
-
-// // 체크된 레이어 정보를 받는 핸들러
-// const handleCheckedLayersChange = (checkedIds: string[], checkedNodesData: any[]) => {
-// setCheckedLayers(checkedIds);
-// setCheckedLayersData(checkedNodesData);
-// };
-
-// // SearchModal, GisContent 등에서 호출
-// const onFeatureSelect = (data: any) => {
-// const map = gisMaps.current;
-// if (!map) {
-// 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;
-// if (
-// data &&
-// typeof data.getGeometry === "function" &&
-// typeof data.setStyle === "function"
-// ) {
-// // 이미 Feature 인스턴스라면 그대로 사용
-// foundFeature = data;
-// } else {
-// // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용
-// const featureId = data.fid || data.ftrIdn || data.id;
-// map
-// .getLayers()
-// .getArray()
-// .forEach((layer: any) => {
-// const source = layer.getSource?.();
-// if (source?.getFeatureById) {
-// const feature = source.getFeatureById(String(featureId).trim());
-// if (feature) foundFeature = feature;
-// }
-// });
-// }
-
-// // 3. 피처 선택
-// if (foundFeature) {
-// const geometry = foundFeature.getGeometry();
-// if (geometry) {
-// const extent = geometry.getExtent();
-
-// map.getView().fit(extent, {
-// duration: 300,
-// padding: [50, 50, 50, 50],
-// maxZoom: 16,
-// constrainResolution: true,
-// nearest: true,
-// });
-// }
-// select.selectFeature(foundFeature, true);
-// } else {
-// console.warn("OpenLayers Feature를 찾을 수 없습니다:", data);
-// }
-
-// setFeatureData(data);
-// setIsOpen(true);
-// setIsSearchModalOpen(false);
-// };
-
-// // MapSearchBar 래퍼 컴포넌트
-// // const CustomMapSearchBar = (props: any) => {
-// // return (
-// //
-// // );
-// // };
-
-// return (
-//
-//
-// //
-// {
-
-// console.log('p' ,props)
-// }
-// }
-// onFeatureSelect={onFeatureSelect}
-// setIsOpen={setIsOpen}
-// setFeatureData={setFeatureData}
-// featureData={featureData}
-// setIsSearchModalOpen={setIsSearchModalOpen}
-// isOpen={isOpen}
-// isSearchModalOpen={isSearchModalOpen}
-// onCheckedLayersChange={handleCheckedLayersChange}
-// imgVisble={true}
-// searchBar={undefined}
-// />
-//
-// );
-// };
-
-// export default Map;
diff --git a/apps/wr/app/(popUp-layout)/mapDetailPopUp/page.tsx b/apps/wr/app/(popUp-layout)/mapDetailPopUp/page.tsx
index d8e93c567..8da833282 100644
--- a/apps/wr/app/(popUp-layout)/mapDetailPopUp/page.tsx
+++ b/apps/wr/app/(popUp-layout)/mapDetailPopUp/page.tsx
@@ -44,6 +44,7 @@ export default function MapDetailPopUp() {
return (
{
+
bc.postMessage({ type: "SELECT_FEATURE", feature });
}}
/>
diff --git a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx
index debea36c9..a660e5e6b 100644
--- a/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx
+++ b/apps/wr/app/(popUp-layout)/mapFeaturePopup/page.tsx
@@ -1,5 +1,6 @@
"use client";
import { useWrStore } from "@/app/store";
+import CoSttnDetailPopup from "@/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup";
import { RuseDetailPopup } from "@/components/ui/map/detailPopup/ruseDetailPopup";
import CoDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/coDatailModal";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
@@ -16,6 +17,7 @@ export default function MapFeaturePopup() {
htdfMapDetile,
pbnMapDetaile,
ldrmntMapDetile,
+ coSttnMapDetail
} = useWrStore((state) => state);
const { pbnMapHeadList } = pbnMap;
const [isDetail, setIsDetail] = useState(null);
@@ -45,25 +47,30 @@ export default function MapFeaturePopup() {
useEffect(() => {
if (isFeatureCd && layerNm) {
- if (layerNm === "하수재이용시설") {
- setIsDetail(isFeatureCd);
- } else if (layerNm === "하수처리시설") {
+ if (layerNm === "tb_wr_bdst_ruse_fclt") {
+ setIsDetail(isFeatureCd);
+ } else if (layerNm === "tb_il_swage_prcs_fclt") {
pbnMapDetaile(isFeatureCd, isFeatureCd).then((res) => {
setIsDetail(res);
});
- } else if (layerNm === "빗물이용시설") {
+ } else if (layerNm === "tb_wr_rnwtr_utztn_fclt") {
rainMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
- } else if (layerNm === "중수도시설") {
+ } else if (layerNm === "tb_wr_rswtr_fclt") {
rswtMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
- } else if (layerNm === "온배수시설") {
+ } else if (layerNm === "tb_wr_htdfl_fclt") {
htdfMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
- } else if (layerNm === "잠재수요처") {
+ }else if(layerNm ==='tb_wr_ruse_fclt_dmd_co'){
+ coSttnMapDetail(isFeatureCd).then((res) => {
+ console.log('tb_wr_ruse_fclt_dmd_co ', res)
+ setIsDetail(res);
+ });
+ } else if (layerNm === "tb_wr_tmpr_dmd_co") {
ldrmntMapDetile(isFeatureCd).then((res) => {
setIsDetail(res);
});
@@ -76,9 +83,9 @@ export default function MapFeaturePopup() {
<>
{isDetail ? (
- {layerNm === "하수재이용시설" ? (
+ {layerNm === "tb_wr_bdst_ruse_fclt" ? (
- ) : layerNm === "하수처리시설" ? (
+ ) : layerNm === "tb_il_swage_prcs_fclt" ? (
@@ -103,21 +110,26 @@ export default function MapFeaturePopup() {
onPageChange={() => {}}
/>
- ) : layerNm === "잠재수요처" ? (
+ ) : layerNm === "tb_wr_tmpr_dmd_co" ? (
{
- console.log(value)
+ console.log(value);
}}
isMap={true}
/>
- ) : (
+ ) :layerNm === "tb_wr_ruse_fclt_dmd_co" ? (
+
+ )
+ : (
diff --git a/apps/wr/app/layout.tsx b/apps/wr/app/layout.tsx
index fe4c3aff0..17945be51 100644
--- a/apps/wr/app/layout.tsx
+++ b/apps/wr/app/layout.tsx
@@ -4,6 +4,8 @@ import i18next from "i18next";
import { I18nextProvider } from "react-i18next";
import koBase from "../public/locales/ko/message.json";
import { StoreProvider } from "./store";
+import { LoginApi } from "@/src/entities/auth";
+import { useEffect } from "react";
export default function RootLayout({
children,
@@ -20,13 +22,21 @@ export default function RootLayout({
},
});
+ useEffect(() => {
+ // 렌더 중이 아니라 클라이언트에서만 실행 + 에러 캐치
+ void LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" })
+ .catch((e) => {
+ console.error("Auto login failed:", e);
+ });
+ }, []);
+
return (
-
- {children}
-
+
+ {children}
+
diff --git a/apps/wr/app/map/searchBar/SearchInputText.tsx b/apps/wr/app/map/searchBar/SearchInputText.tsx
deleted file mode 100644
index 97ba51fb7..000000000
--- a/apps/wr/app/map/searchBar/SearchInputText.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-// SearchInputText.tsx
-"use client";
-import { Input } from "@common/components/ui";
-import { useEffect, useRef, useState } from "react";
-
-interface SearchInputTextProps {
- initValue?: string;
- setValue: (val: string) => void;
- setRtnData: (val: { fnm: string; fid: string }) => void;
- searchList: { fnm: string; fid: string }[];
- onEnter?: () => void;
- className?: string;
-}
-
-export default function SearchInputText({
- initValue,
- setValue,
- setRtnData,
- searchList,
- onEnter,
- className,
-}: SearchInputTextProps) {
- const [showResults, setShowResults] = useState(false);
- const [text, setText] = useState(initValue ?? "");
- const [highlightIndex, setHighlightIndex] = useState(-1);
- const wrapperRef = useRef(null);
-
- useEffect(() => {
- setText(initValue ?? "");
- }, [initValue]);
-
- useEffect(() => {
- if (searchList.length > 0) {
- setShowResults(true);
- } else {
- setShowResults(false);
- }
- setHighlightIndex(-1);
- }, [searchList]);
-
- useEffect(() => {
- function handleClickOutside(event: MouseEvent) {
- if (
- wrapperRef.current &&
- !(wrapperRef.current as any).contains(event.target)
- ) {
- setShowResults(false);
- }
- }
- document.addEventListener("mousedown", handleClickOutside);
- return () => {
- document.removeEventListener("mousedown", handleClickOutside);
- };
- }, [wrapperRef]);
-
- const handleChange = (e: React.ChangeEvent) => {
- setText(e.target.value);
- setValue(e.target.value);
- setHighlightIndex(-1);
- };
-
- const handleSelect = (item: { fnm: string; fid: string }) => {
- setText(item.fnm);
- setValue(item.fnm);
- setRtnData(item);
- setShowResults(false);
- };
-
- const handleKeyDown = (e: React.KeyboardEvent) => {
- if (e.key === "Enter") {
- if (highlightIndex >= 0 && highlightIndex < searchList.length) {
- const selected = searchList[highlightIndex];
- if (selected) handleSelect(selected);
- } else if (onEnter) {
- onEnter();
- }
- } else if (e.key === "ArrowDown") {
- e.preventDefault();
- setHighlightIndex((prev) =>
- prev < searchList.length - 1 ? prev + 1 : prev
- );
- } else if (e.key === "ArrowUp") {
- e.preventDefault();
- setHighlightIndex((prev) => (prev > 0 ? prev - 1 : -1));
- }
- };
-
- return (
-
-
- {showResults && (
-
- {searchList.length > 0 ? (
- searchList.map((item, index) => (
-
handleSelect(item)}
- >
- {item.fnm}
-
- ))
- ) : (
-
- 검색 결과가 없습니다.
-
- )}
-
- )}
-
- );
-}
diff --git a/apps/wr/app/map/searchBar/comboSearchBar.tsx b/apps/wr/app/map/searchBar/comboSearchBar.tsx
deleted file mode 100644
index 15736d710..000000000
--- a/apps/wr/app/map/searchBar/comboSearchBar.tsx
+++ /dev/null
@@ -1,298 +0,0 @@
-"use client";
-import { SelectBox, type SelectDataType } from "@common/business_components/ui";
-import { Button } from "@common/components/ui";
-import { useCallback, useEffect, useState } from "react";
-
-const geoserverUrl =
- "/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&outputFormat=application/json";
-
-const FACILITY_TYPE_URL_MAP: Record = {
- tb_il_swage_prcs_fclt: geoserverUrl, //하수처리시설
- tb_wr_bdst_ruse_fclt:
- "/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000", //재이용시설 post
- tb_wr_rnwtr_utztn_fclt: "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}", //빗물이용시설 get
- tb_wr_rswtr_fclt: "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}", //중수도시설 get
- tb_wr_htdfl_fclt: "/reuse-service/drain/facilityList/1/1000/{sggCd}", //온배수시설 get
- tb_wr_ruse_fclt_dmd_co: "/reuse-service/reuseFc/request/1/1000/{sggCd}", //수요처 get
- tb_wr_tmpr_dmd_co:
- "/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}", //잠재수요처 get
-};
-
-interface SearchBarProps {
- onFeatureSelect: (feature: any) => void;
- gisMaps: React.RefObject;
- facilityTypes: { text: string; val: string }[];
-}
-
-export function SearchBar({
- onFeatureSelect,
- gisMaps,
- facilityTypes,
-}: SearchBarProps) {
- const [sidoValue, setSidoValue] = useState("0");
- const [sigunValue, setSigunValue] = useState("0");
- const [sidoData, setSidoData] = useState([
- { text: "선택", val: "0" },
- ]);
- const [sigunData, setSigunData] = useState([
- { text: "선택", val: "0" },
- ]);
- const [filteredSigunData, setFilteredSigunData] = useState([
- { text: "선택", val: "0" },
- ]);
-
- const [facilityData, setFacilityData] = useState([
- { text: "선택", val: "0" },
- ]);
- const [facilityValue, setFacilityValue] = useState("0");
-
- const [facilityType, setFacilityType] = useState(
- facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0"
- );
-
- //시도, 시군구 조회
- const fetchSido = async () => {
- const url = `/cms-service/api/v1/code/cache/ADSTDSTRCD/Y`;
- const res = await fetch(url);
- const json = await res.json();
- const sidoList = json
- .filter(
- (item: any) =>
- typeof item.lwpoCd === "string" && item.lwpoCd.length === 2
- )
- .map((feature: any) => ({
- val: feature.lwpoCd,
- text: feature.lwpoCdNm,
- }));
- setSidoData([{ text: "선택", val: "0" }, ...sidoList]);
-
- const sigunList = json
- .filter(
- (item: any) =>
- typeof item.lwpoCd === "string" && item.lwpoCd.length !== 2
- )
- .map((feature: any) => ({
- val: feature.lwpoCd,
- text: feature.lwpoCdNm,
- }));
- setSigunData(sigunList);
- };
-
- //시설명 콤보박스 조회
- const fetchFacilitiesBySggNm = async (
- sggCd: string,
- sggNm: string,
- sidoNm: string,
- currentFacilityType?: string
- ) => {
- const type = currentFacilityType ?? facilityType;
- if (!type || type === "0") return;
-
- const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
- if (!baseUrlTemplate) return;
-
- const year = new Date().getFullYear().toString();
- let url = baseUrlTemplate
- .replace("{year}", year)
- .replace("{sggCd}", sggCd)
- .replace("{sidoNm}", encodeURIComponent(sidoNm))
- .replace("{sggNm}", encodeURIComponent(sggNm));
-
- let list: SelectDataType[] = [];
-
- if (
- type === "tb_il_swage_prcs_fclt" //하수처리시설
- ) {
- const cqlFilter = `ctpv_nm='${encodeURIComponent(sidoNm)}' AND sgg_nm='${encodeURIComponent(sggNm)}'`;
- url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`;
- const res = await fetch(url);
- const json = await res.json();
- list = json.features.map((f: any) => ({
- text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
- val: f.id,
- }));
- } else if (
- type === "tb_wr_bdst_ruse_fclt" // 재이용시설
- ) {
- //재용에서 참조하는 하수처리시설 목록
- const paramsRes = await fetch("/reuse-service/reuseFc/pubFc");
- const paramsJson = await paramsRes.json();
- const params = paramsJson.data;
-
- const res = await fetch(url, {
- method: "POST",
- headers: {
- accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify(params),
- });
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.ruseUtztnFcltNm ?? "(이름없음)",
- val: item.pbnstRuseFcltId,
- }));
- } 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 방식
- const res = await fetch(url);
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.dmdCoNm ?? "(이름없음)",
- val: item.fctryMngSn,
- }));
- } else {
- // GET 방식
- const res = await fetch(url);
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.bdstNm ?? "(이름없음)",
- val: item.bdstInfoSn,
- }));
- }
-
- setFacilityData([{ text: "선택", val: "0" }, ...list]);
- setFacilityValue("0");
- };
-
- //시도, 시군구 초기 데이터 조회
- useEffect(() => {
- fetchSido();
- }, []);
-
- //시군구 데이터 초기화
- const initializeSigunData = useCallback(
- (sidoCd: string) => {
- if (sidoCd === "0") {
- setFilteredSigunData([{ text: "선택", val: "0" }]);
- setSigunValue("0");
- return;
- }
- const prefix = sidoCd.substring(0, 2);
- const filtered = sigunData.filter((item) => item.val.startsWith(prefix));
- setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]);
- setSigunValue("0");
- },
- [sigunData]
- );
-
- //콤보박스 선택시 연관 콤보박스 처리
- const onSelectValue = useCallback(
- (val: string, type: string) => {
- if (type === "ctpvCd") {
- setSidoValue(val);
- initializeSigunData(val);
- setFacilityData([{ text: "선택", val: "0" }]);
- setFacilityValue("0");
- } else if (type === "sggCd") {
- setSigunValue(val);
- const sidoNm =
- sidoData.find((item) => item.val === sidoValue)?.text || "";
- const sggNm = sigunData.find((item) => item.val === val)?.text || "";
- const sggCd = sigunData.find((item) => item.val === val)?.val || "";
- if (sggNm && sidoNm)
- fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, facilityType);
- } else if (type === "facilityType") {
- setFacilityType(val);
- setFacilityValue("0");
- setFacilityData([{ text: "선택", val: "0" }]);
- const sidoNm =
- sidoData.find((item) => item.val === sidoValue)?.text || "";
- const sggNm =
- sigunData.find((item) => item.val === sigunValue)?.text || "";
- const sggCd =
- sigunData.find((item) => item.val === sigunValue)?.val || "";
- if (sggNm && sidoNm) fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, val);
- } else if (type === "fcltCd") {
- setFacilityValue(val);
- }
- },
- [initializeSigunData, sigunData, sigunValue, sidoData, sidoValue]
- );
-
- //조회 버튼 클릭
- const handleSearch = () => {
- if (!gisMaps.current || facilityValue === "0") return;
- const layers = gisMaps.current.getLayers().getArray();
- for (const layer of layers) {
- const source = layer.getSource?.();
- const feature = source?.getFeatureById?.(facilityValue);
- if (feature) {
- onFeatureSelect(feature);
- return;
- }
- }
- alert("해당 처리시설을 지도에서 찾을 수 없습니다.");
- };
-
- return (
-
-
-
-
- {facilityTypes.length > 1 && (
-
- onSelectValue(val.toString(), "facilityType")
- }
- value={facilityType}
- />
- )}
- onSelectValue(val.toString(), "ctpvCd")}
- value={sidoValue}
- />
- onSelectValue(val.toString(), "sggCd")}
- value={sigunValue}
- />
- onSelectValue(val.toString(), "fcltCd")}
- value={facilityValue}
- />
-
-
-
-
-
-
-
- );
-}
diff --git a/apps/wr/app/map/searchBar/procSearchBar.tsx b/apps/wr/app/map/searchBar/procSearchBar.tsx
deleted file mode 100644
index 15736d710..000000000
--- a/apps/wr/app/map/searchBar/procSearchBar.tsx
+++ /dev/null
@@ -1,298 +0,0 @@
-"use client";
-import { SelectBox, type SelectDataType } from "@common/business_components/ui";
-import { Button } from "@common/components/ui";
-import { useCallback, useEffect, useState } from "react";
-
-const geoserverUrl =
- "/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&outputFormat=application/json";
-
-const FACILITY_TYPE_URL_MAP: Record = {
- tb_il_swage_prcs_fclt: geoserverUrl, //하수처리시설
- tb_wr_bdst_ruse_fclt:
- "/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000", //재이용시설 post
- tb_wr_rnwtr_utztn_fclt: "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}", //빗물이용시설 get
- tb_wr_rswtr_fclt: "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}", //중수도시설 get
- tb_wr_htdfl_fclt: "/reuse-service/drain/facilityList/1/1000/{sggCd}", //온배수시설 get
- tb_wr_ruse_fclt_dmd_co: "/reuse-service/reuseFc/request/1/1000/{sggCd}", //수요처 get
- tb_wr_tmpr_dmd_co:
- "/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}", //잠재수요처 get
-};
-
-interface SearchBarProps {
- onFeatureSelect: (feature: any) => void;
- gisMaps: React.RefObject;
- facilityTypes: { text: string; val: string }[];
-}
-
-export function SearchBar({
- onFeatureSelect,
- gisMaps,
- facilityTypes,
-}: SearchBarProps) {
- const [sidoValue, setSidoValue] = useState("0");
- const [sigunValue, setSigunValue] = useState("0");
- const [sidoData, setSidoData] = useState([
- { text: "선택", val: "0" },
- ]);
- const [sigunData, setSigunData] = useState([
- { text: "선택", val: "0" },
- ]);
- const [filteredSigunData, setFilteredSigunData] = useState([
- { text: "선택", val: "0" },
- ]);
-
- const [facilityData, setFacilityData] = useState([
- { text: "선택", val: "0" },
- ]);
- const [facilityValue, setFacilityValue] = useState("0");
-
- const [facilityType, setFacilityType] = useState(
- facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0"
- );
-
- //시도, 시군구 조회
- const fetchSido = async () => {
- const url = `/cms-service/api/v1/code/cache/ADSTDSTRCD/Y`;
- const res = await fetch(url);
- const json = await res.json();
- const sidoList = json
- .filter(
- (item: any) =>
- typeof item.lwpoCd === "string" && item.lwpoCd.length === 2
- )
- .map((feature: any) => ({
- val: feature.lwpoCd,
- text: feature.lwpoCdNm,
- }));
- setSidoData([{ text: "선택", val: "0" }, ...sidoList]);
-
- const sigunList = json
- .filter(
- (item: any) =>
- typeof item.lwpoCd === "string" && item.lwpoCd.length !== 2
- )
- .map((feature: any) => ({
- val: feature.lwpoCd,
- text: feature.lwpoCdNm,
- }));
- setSigunData(sigunList);
- };
-
- //시설명 콤보박스 조회
- const fetchFacilitiesBySggNm = async (
- sggCd: string,
- sggNm: string,
- sidoNm: string,
- currentFacilityType?: string
- ) => {
- const type = currentFacilityType ?? facilityType;
- if (!type || type === "0") return;
-
- const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
- if (!baseUrlTemplate) return;
-
- const year = new Date().getFullYear().toString();
- let url = baseUrlTemplate
- .replace("{year}", year)
- .replace("{sggCd}", sggCd)
- .replace("{sidoNm}", encodeURIComponent(sidoNm))
- .replace("{sggNm}", encodeURIComponent(sggNm));
-
- let list: SelectDataType[] = [];
-
- if (
- type === "tb_il_swage_prcs_fclt" //하수처리시설
- ) {
- const cqlFilter = `ctpv_nm='${encodeURIComponent(sidoNm)}' AND sgg_nm='${encodeURIComponent(sggNm)}'`;
- url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`;
- const res = await fetch(url);
- const json = await res.json();
- list = json.features.map((f: any) => ({
- text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
- val: f.id,
- }));
- } else if (
- type === "tb_wr_bdst_ruse_fclt" // 재이용시설
- ) {
- //재용에서 참조하는 하수처리시설 목록
- const paramsRes = await fetch("/reuse-service/reuseFc/pubFc");
- const paramsJson = await paramsRes.json();
- const params = paramsJson.data;
-
- const res = await fetch(url, {
- method: "POST",
- headers: {
- accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify(params),
- });
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.ruseUtztnFcltNm ?? "(이름없음)",
- val: item.pbnstRuseFcltId,
- }));
- } 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 방식
- const res = await fetch(url);
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.dmdCoNm ?? "(이름없음)",
- val: item.fctryMngSn,
- }));
- } else {
- // GET 방식
- const res = await fetch(url);
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.bdstNm ?? "(이름없음)",
- val: item.bdstInfoSn,
- }));
- }
-
- setFacilityData([{ text: "선택", val: "0" }, ...list]);
- setFacilityValue("0");
- };
-
- //시도, 시군구 초기 데이터 조회
- useEffect(() => {
- fetchSido();
- }, []);
-
- //시군구 데이터 초기화
- const initializeSigunData = useCallback(
- (sidoCd: string) => {
- if (sidoCd === "0") {
- setFilteredSigunData([{ text: "선택", val: "0" }]);
- setSigunValue("0");
- return;
- }
- const prefix = sidoCd.substring(0, 2);
- const filtered = sigunData.filter((item) => item.val.startsWith(prefix));
- setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]);
- setSigunValue("0");
- },
- [sigunData]
- );
-
- //콤보박스 선택시 연관 콤보박스 처리
- const onSelectValue = useCallback(
- (val: string, type: string) => {
- if (type === "ctpvCd") {
- setSidoValue(val);
- initializeSigunData(val);
- setFacilityData([{ text: "선택", val: "0" }]);
- setFacilityValue("0");
- } else if (type === "sggCd") {
- setSigunValue(val);
- const sidoNm =
- sidoData.find((item) => item.val === sidoValue)?.text || "";
- const sggNm = sigunData.find((item) => item.val === val)?.text || "";
- const sggCd = sigunData.find((item) => item.val === val)?.val || "";
- if (sggNm && sidoNm)
- fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, facilityType);
- } else if (type === "facilityType") {
- setFacilityType(val);
- setFacilityValue("0");
- setFacilityData([{ text: "선택", val: "0" }]);
- const sidoNm =
- sidoData.find((item) => item.val === sidoValue)?.text || "";
- const sggNm =
- sigunData.find((item) => item.val === sigunValue)?.text || "";
- const sggCd =
- sigunData.find((item) => item.val === sigunValue)?.val || "";
- if (sggNm && sidoNm) fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, val);
- } else if (type === "fcltCd") {
- setFacilityValue(val);
- }
- },
- [initializeSigunData, sigunData, sigunValue, sidoData, sidoValue]
- );
-
- //조회 버튼 클릭
- const handleSearch = () => {
- if (!gisMaps.current || facilityValue === "0") return;
- const layers = gisMaps.current.getLayers().getArray();
- for (const layer of layers) {
- const source = layer.getSource?.();
- const feature = source?.getFeatureById?.(facilityValue);
- if (feature) {
- onFeatureSelect(feature);
- return;
- }
- }
- alert("해당 처리시설을 지도에서 찾을 수 없습니다.");
- };
-
- return (
-
-
-
-
- {facilityTypes.length > 1 && (
-
- onSelectValue(val.toString(), "facilityType")
- }
- value={facilityType}
- />
- )}
- onSelectValue(val.toString(), "ctpvCd")}
- value={sidoValue}
- />
- onSelectValue(val.toString(), "sggCd")}
- value={sigunValue}
- />
- onSelectValue(val.toString(), "fcltCd")}
- value={facilityValue}
- />
-
-
-
-
-
-
-
- );
-}
diff --git a/apps/wr/app/map/searchBar/searchBar.tsx b/apps/wr/app/map/searchBar/searchBar.tsx
deleted file mode 100644
index ab3dacb0e..000000000
--- a/apps/wr/app/map/searchBar/searchBar.tsx
+++ /dev/null
@@ -1,351 +0,0 @@
-"use client";
-import { SelectBox, type SelectDataType } from "@common/business_components/ui";
-import { Button } from "@common/components/ui";
-import { useCallback, useEffect, useState } from "react";
-import SearchInputText from "./SearchInputText";
-
-const FACILITY_TYPE_URL_MAP: Record = {
- tb_il_swage_prcs_fclt:
- "/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_il_swage_prcs_fclt&outputFormat=application/json&propertyName=swtrmt_fclt_cd,swtrmt_fclt_nm&cql_filter=",
- tb_wr_bdst_ruse_fclt:
- "/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000/",
- tb_wr_rnwtr_utztn_fclt:
- "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}/{fcltyNm}",
- tb_wr_rswtr_fclt:
- "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}/{fcltyNm}",
- tb_wr_htdfl_fclt:
- "/reuse-service/drain/facilityList/1/1000/{sggCd}/{fcltyNm}",
- tb_wr_ruse_fclt_dmd_co:
- "/reuse-service/reuseFc/request/1/1000/{sggCd}/{fcltyNm}",
- tb_wr_tmpr_dmd_co:
- "/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}/{fcltyNm}",
-};
-
-interface SearchBarProps {
- gisMaps: React.RefObject;
- facilityTypes: { text: string; val: string }[];
- onFeatureFocus: any;
-}
-
-export function SearchBar({
- gisMaps,
- facilityTypes,
- onFeatureFocus,
-}: SearchBarProps) {
- console.log('gisMaps ', gisMaps)
- console.log('onFeatureFocus ', onFeatureFocus)
-
- const [sidoValue, setSidoValue] = useState("0");
- const [sigunValue, setSigunValue] = useState("0");
- const [facilityType, setFacilityType] = useState(
- facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0"
- );
- const [fcltyNm, setFcltyNm] = useState("");
- const [searchList, setSearchList] = useState<{ fnm: string; fid: string }[]>(
- []
- );
-
- const [sidoData, setSidoData] = useState([
- { text: "시도", val: "0" },
- ]);
- const [sigunData, setSigunData] = useState([
- { text: "시군구", val: "0" },
- ]);
- const [filteredSigunData, setFilteredSigunData] = useState([
- { text: "시군구", val: "0" },
- ]);
-
- const fetchSido = async () => {
- const res = await fetch("/cms-service/api/v1/code/cache/ADSTDSTRCD/Y");
- const json = await res.json();
- const sidoList = json
- .filter((item: any) => item.lwpoCd?.length === 2)
- .map((item: any) => ({ val: item.lwpoCd, text: item.lwpoCdNm }));
- const sigunList = json
- .filter((item: any) => item.lwpoCd?.length > 2)
- .map((item: any) => ({ val: item.lwpoCd, text: item.lwpoCdNm }));
- setSidoData([{ text: "시도", val: "0" }, ...sidoList]);
- setSigunData(sigunList);
- };
-
- const initializeSigunData = useCallback(
- (sidoCd: string) => {
- if (sidoCd === "0") {
- setFilteredSigunData([{ text: "시도", val: "0" }]);
- setSigunValue("0");
- return;
- }
- const prefix = sidoCd.substring(0, 2);
- const filtered = sigunData.filter((item) => item.val.startsWith(prefix));
- setFilteredSigunData([{ text: "시군구", val: "0" }, ...filtered]);
- setSigunValue("0");
- },
- [sigunData]
- );
-
- useEffect(() => {
- fetchSido();
- }, []);
-
- const onSelectValue = useCallback(
- (val: string, type: string) => {
- if (type === "ctpvCd") {
- setSidoValue(val);
- initializeSigunData(val);
- setSearchList([]);
- setFcltyNm("");
- } else if (type === "sggCd") {
- setSigunValue(val);
- setSearchList([]);
- setFcltyNm("");
- } else if (type === "facilityType") {
- setFacilityType(val);
- setSearchList([]);
- setFcltyNm("");
- }
- },
- [initializeSigunData]
- );
-
- const handleSearch = async () => {
- if (!fcltyNm) return alert("시설명을 입력하세요.");
-
- const sidoNm = sidoData.find((item) => item.val === sidoValue)?.text || "";
- const sggNm = sigunData.find((item) => item.val === sigunValue)?.text || "";
-
- const type = facilityType;
- const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
- if (!baseUrlTemplate) return;
-
- let url = baseUrlTemplate;
- const year = new Date().getFullYear().toString();
- url = url
- .replace("{year}", year)
- .replace("{sggCd}", sigunValue)
- .replace("{sidoNm}", encodeURIComponent(sidoNm))
- .replace("{sggNm}", encodeURIComponent(sggNm))
- .replace("{fcltyNm}", encodeURIComponent(fcltyNm));
-
- let list: SelectDataType[] = [];
-
- if (type === "tb_il_swage_prcs_fclt") {
- const cqlFilter = `ctpv_nm='${sidoNm}' and sgg_nm='${sggNm}' and swtrmt_fclt_nm like '%${fcltyNm}%'`;
- url += encodeURIComponent(cqlFilter);
- const res = await fetch(url);
- const json = await res.json();
- list = json.features.map((f: any) => ({
- text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
- val: f.id,
- }));
- } 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;
- const procResult = procData
- .filter((code: string) => code.slice(0, 5) === sigunValue)
- .map((code: string) => {
- return code;
- });
-
- //처리시설명으로 처리시설코드 조회
- let procUrl2 =
- "/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}";
- procUrl2 = procUrl2
- .replace("{sggCd}", sigunValue)
- .replace("{fcltyNm}", encodeURIComponent(fcltyNm));
- const procRes2 = await fetch(procUrl2, {
- method: "POST",
- headers: {
- accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify(procResult),
- });
- const procJson2 = await procRes2.json();
- const procResult2 = (procJson2.data || []).map((item: any) => item.fid);
-
- //최종 처리시설코드로 재이용시설조회
- const res = await fetch(url, {
- method: "POST",
- headers: {
- accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify(procResult2),
- });
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.ruseUtztnFcltNm ?? "(이름없음)",
- val: item.pbnstRuseFcltId,
- }));
- } 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 방식
- const res = await fetch(url);
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.dmdCoNm ?? "(이름없음)",
- val: item.fctryMngSn,
- }));
- } else {
- // GET 방식
- const res = await fetch(url);
- const json = await res.json();
- list = (json.data || []).map((item: any) => ({
- text: item.bdstNm ?? "(이름없음)",
- val: item.bdstInfoSn,
- }));
- }
-
- if (list.length === 0) {
- alert("검색 결과가 없습니다.");
- setSearchList([]);
- setFcltyNm("");
- return;
- }
-
- const newList = list.map((item: any) => {
- const code = item.val;
- const name = item.text;
- return { fnm: name, fid: code };
- });
- setSearchList(newList);
- };
-
- const moveFocus = (feature: any) => {
- console.log('feature ' ,feature)
-
- // console.log('searchbar:moveFocus')
- // const map = gisMaps.current;
- // if (!map) {
- // 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;
- // let featureId = data.fid;
- // const layerName = data.layerNm;
- // map
- // .getLayers()
- // .getArray()
- // .forEach((layer: any) => {
- // const source = layer.getSource?.();
- // if (source?.getFeatureById) {
- // const feature = source.getFeatureById(String(featureId).trim());
- // if (feature) foundFeature = feature;
- // }
- // });
-
- // // 3. 피처 선택
- // if (foundFeature) {
- // const geometry = foundFeature.getGeometry();
- // if (geometry) {
- // const extent = geometry.getExtent();
-
- // map.getView().fit(extent, {
- // duration: 300,
- // padding: [50, 50, 50, 50],
- // maxZoom: 16,
- // constrainResolution: true,
- // nearest: true,
- // });
- // }
- // // select.selectFeature(foundFeature, true);
- // } else {
- // console.warn("OpenLayers Feature를 찾을 수 없습니다:", data);
- // }
- };
-
- return (
-
-
-
-
- {facilityTypes.length > 1 && (
-
- onSelectValue(val.toString(), "facilityType")
- }
- value={facilityType}
- />
- )}
- onSelectValue(val.toString(), "ctpvCd")}
- value={sidoValue}
- />
- onSelectValue(val.toString(), "sggCd")}
- value={sigunValue}
- />
- {
- setFcltyNm(val);
- }}
- setRtnData={(selected: { fnm: string; fid: string }) => {
- // 선택된 항목이 있을 경우 onFeatureSelect 실행
- const type = facilityType;
- moveFocus({
- layerNm: type,
- ...selected,
- });
- }}
- searchList={searchList}
- onEnter={handleSearch}
- className="mr-5 w-[150px]"
- />
-
-
-
-
-
-
-
- );
-}
diff --git a/apps/wr/app/store/map/coSttnMap/index.tsx b/apps/wr/app/store/map/coSttnMap/index.tsx
index d6bedd9c5..9d1b90cfe 100644
--- a/apps/wr/app/store/map/coSttnMap/index.tsx
+++ b/apps/wr/app/store/map/coSttnMap/index.tsx
@@ -1,11 +1,14 @@
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
import type { CommonTableProps } from "../../common/type/header";
-import { coSttHeadListExport, coSttNodeListExport } from "../../matDmd/coSttn/headList";
-import { fetchType, getFetchWithCount } from "@/components/lib/api";
+import {
+ coSttHeadListExport,
+ coSttNodeListExport,
+} from "../../matDmd/coSttn/headList";
+import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api";
const coSttnMapRes: DemandCompType[] = [];
-export const costtnMapSize =20
+export const costtnMapSize = 20;
export type coSttnMapState = {
coSttnMap: {
@@ -21,7 +24,13 @@ export type coSttnMapState = {
type coSttnMapActions = {
coSttnMapInit: (pageNo: number, pageCnt: number, con: string) => void;
coSttnMapSearch: (pageNo: number, pageCnt: number, con: string) => void;
- coSttnMapTxtSearch: (pageNo: number, pageCnt: number, con: string, txt: string) => void;
+ coSttnMapTxtSearch: (
+ pageNo: number,
+ pageCnt: number,
+ con: string,
+ txt: string
+ ) => void;
+ coSttnMapDetail: (dmdInfoId: string) => Promise;
};
export type coSttnMapType = coSttnMapState & coSttnMapActions;
@@ -37,7 +46,6 @@ export const coSttnMapStateExport: coSttnMapState = {
},
};
-
export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
set: any
) => {
@@ -60,7 +68,7 @@ export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
};
});
} catch (e) {
- console.log(e)
+ console.log(e);
}
},
coSttnMapSearch: async (pageNo: number, pageCnt: number, con: string) => {
@@ -96,11 +104,17 @@ export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
console.log("error", erTxt);
}
},
- coSttnMapTxtSearch: async (pageNo: number, pageCnt: number, con: string, txt: string) => {
+ coSttnMapTxtSearch: async (
+ pageNo: number,
+ pageCnt: number,
+ con: string,
+ txt: string
+ ) => {
try {
const coSttnMapRes = await getFetchWithCount(
fetchType.WR,
- `/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`)
+ `/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`
+ );
set((state: coSttnMapState) => {
return {
...state,
@@ -109,12 +123,23 @@ export const coSttnMapActionsExport: (set: any) => coSttnMapActions = (
coSttnMapRes: coSttnMapRes.data,
coSttnMapResCount: coSttnMapRes.count,
isInit: false,
- }
- }
- })
+ },
+ };
+ });
} catch (erTxt) {
console.log("error", erTxt);
}
},
- }
-}
\ No newline at end of file
+ coSttnMapDetail: async (dmdInfoId: string) => {
+ try {
+ const coSttnMapDetail = await getFetch(
+ fetchType.WR,
+ `/reuseFc/request/${dmdInfoId}`
+ );
+ return coSttnMapDetail;
+ } catch (erTxt) {
+ console.log("error", erTxt);
+ }
+ },
+ };
+};
diff --git a/apps/wr/app/store/matDmd/coMatRvw/type.tsx b/apps/wr/app/store/matDmd/coMatRvw/type.tsx
index 58d539538..ec0f0e09c 100644
--- a/apps/wr/app/store/matDmd/coMatRvw/type.tsx
+++ b/apps/wr/app/store/matDmd/coMatRvw/type.tsx
@@ -79,11 +79,11 @@ export const DmdCoReqSchema = z.object({
grssClfg: z.number().nullish(),
combResdch: z.number().nullish(),
trbt: z.number().nullish(),
- smll: z.number().nullish(),
+ smll: z.string().nullish(),
crmty: z.number().nullish(),
tn: z.number().nullish(),
tph: z.number().nullish(),
- ph: z.number().nullish(),
+ ph: z.string().nullish(),
clIonQnt: z.number().nullish(),
cdtnv: z.number().nullish(),
rmrk: z.string().nullish(),
diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx
index c7dcf1ca8..e19ec2216 100644
--- a/apps/wr/app/store/store.tsx
+++ b/apps/wr/app/store/store.tsx
@@ -161,7 +161,6 @@ import {
type rswtStatState,
type rswtStatType,
} from "./stats/rswtStat";
-import { LoginApi } from "@/src/entities/auth";
import {
authActionsExport,
authStateExport,
@@ -342,7 +341,6 @@ export const StoreZus = (
getMiddleRegionCd(set);
getUnitWaterShedCd(set);
getEnvPartCd(set);
- LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" });
return {
...initState,
...comFcltSearchAction(set),
diff --git a/apps/wr/components/lib/func/mapUtil.ts b/apps/wr/components/lib/func/mapUtil.ts
index f3925c413..78aa71427 100644
--- a/apps/wr/components/lib/func/mapUtil.ts
+++ b/apps/wr/components/lib/func/mapUtil.ts
@@ -1,21 +1,142 @@
+const wrLayerList = [
+ { text: "tb_il_swage_prcs_fclt", val: "bscFctCd" },
+ { text: "tb_wr_bdst_ruse_fclt", val: "pbnstRuseFcltId" },
+ { text: "tb_wr_rnwtr_utztn_fclt", val: "rainyObj" },
+ { text: "tb_wr_rswtr_fclt", val: "rswtrObj" },
+ { text: "tb_wr_htdfl_fclt", val: "htdflObj" },
+ { text: "tb_wr_ruse_fclt_dmd_co", val: "dmdInfoId" },
+ { text: "tb_wr_tmpr_dmd_co", val: "fctryMngSn" },
+];
+const wrFeaturePK = [
+ { text: "bscFctCd", val: "tb_il_swage_prcs_fclt" },
+ { text: "pbnstRuseFcltId", val: "tb_wr_bdst_ruse_fclt" },
+ { text: "bdstInfoSn", val: "tb_wr_rnwtr_utztn_fclt" },
+ { text: "bdstInfoSn", val: "tb_wr_rswtr_fclt" },
+ { text: "bdstInfoSn", val: "tb_wr_htdfl_fclt" },
+ { text: "dmdInfoId", val: "tb_wr_ruse_fclt_dmd_co" },
+ { text: "fctryMngSn", val: "tb_wr_tmpr_dmd_co" },
+];
+// { text: "하수처리시설", val: "tb_il_swage_prcs_fclt" },
+// { text: "하수재이용시설", val: "tb_wr_bdst_ruse_fclt" },
+// { text: "빗물이용시설", val: "tb_wr_rnwtr_utztn_fclt" },
+// { text: "중수도시설", val: "tb_wr_rswtr_fclt" },
+// { text: "온배수시설", val: "tb_wr_htdfl_fclt" },
+// { text: "수요처", val: "tb_wr_ruse_fclt_dmd_co" },
+// { text: "잠재수요처", val: "tb_wr_tmpr_dmd_co" },
-
- export const getFeatureCd = (featurePropertise:any, layerNm:string) => {
- console.log('layerNm ', layerNm )
- console.log('featurePropertise ', featurePropertise )
-
- const featureCd =
- layerNm === "하수재이용시설"
+export const getFeatureCd = (featurePropertise: any, layerNm: string) => {
+ const featureCd =
+ layerNm === "tb_wr_bdst_ruse_fclt"
? featurePropertise?.swtrmt_fclt_cd
- : ["빗물이용시설", "중수도시설", "온배수시설", "수요처" ,'잠재수요처'].includes(
- layerNm
- )
+ : [
+ "tb_wr_ruse_fclt_dmd_co",
+ "tb_wr_rswtr_fclt",
+ "tb_wr_htdfl_fclt",
+ "tb_wr_rnwtr_utztn_fclt",
+ "tb_wr_tmpr_dmd_co",
+ ].includes(layerNm)
? featurePropertise?.bdst_nm
- : layerNm === "하수처리시설"
+ : layerNm === "tb_il_swage_prcs_fclt"
? featurePropertise?.swtrmt_fclt_nm
: null;
- console.log('featureCd ', featureCd)
- return featureCd;
- };
\ No newline at end of file
+ return featureCd;
+};
+
+export const getWrLayerNm = (featurePropertise: any) => {
+ const result = wrLayerList
+ .filter(item => item.val in featurePropertise) // 키 존재 여부 체크
+ .map(item => item.text);
+
+
+ return result[0];
+};
+
+
+export const getWrFeaturePk = (layerName :string) => {
+ const result = wrFeaturePK
+ .filter(item => item.val === layerName) // 키 존재 여부 체크
+ .map(item => item.text);
+ return result[0];
+};
+
+export const getSelectedLayers = (isFeature: any, gisMaps:any) => {
+ const map = gisMaps.current;
+ if (!map) {
+ console.warn("지도가 초기화되지 않았습니다.");
+ return;
+ }
+ let result = null;
+ const layers = map
+ ? map
+ .getLayers()
+ .getArray()
+ .filter((l: any) => l.getVisible())
+ : []; // gisMap이 null인지 확인 후 레이어 가져오기
+ let featureLayer: { get: (key: string) => any } = { get: () => null };
+
+ layers.forEach((layer: any) => {
+ const source = layer.getSource();
+ if (
+ source &&
+ source.hasFeature &&
+ isFeature &&
+ typeof isFeature.getId === "function" &&
+ source.hasFeature(isFeature)
+ ) {
+ featureLayer = layer; // 피처가 속한 레이어 찾기)
+ }
+ });
+
+ result = featureLayer.get("lyrTyNm");
+
+ return result;
+};
+
+export const getClickFeatureId = (data: any) => {
+ let featureId =''
+ const layerName = data.layerNm;
+ if (layerName === "하수재이용시설") {
+ // 재이용시설
+ featureId = `${layerName}.${data.searchPk}`;
+ } else if (
+ //빗물이용시설, 중수도시설
+ layerName === "빗물이용시설" ||
+ layerName == "중수도시설"
+ ) {
+ featureId = `${layerName}.${data.bdstInfoSn}`;
+ } else if (layerName === "하수처리시설") {
+ //하수처리시설
+ featureId = `${layerName}.${data.bscFctCd}`;
+ } else if (layerName === "온배수시설") {
+ //온배수시설
+ featureId = `${layerName}.${data.bdstRuseFcltSn}`;
+ } else if (layerName == "수요처") {
+ //수요처
+ featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
+ } else {
+ featureId = `${layerName}.${data.fid || data.id || data.ftrIdn}`;
+ }
+ return featureId;
+};
+
+export function featurePopUpOpen(layerNm:string,featureCd:string,popupDetailRef){
+ const url = `/mapFeaturePopup?layerNm=${encodeURIComponent(String(layerNm))}&featureCd=${encodeURIComponent(featureCd)} `;
+ const width =
+ String(layerNm) === "tb_wr_bdst_ruse_fclt"
+ ? Math.floor(window.innerWidth * 0.8)
+ : Math.floor(window.innerWidth * 0.4); // 화면 폭의 40%
+ const height =
+ String(layerNm) === "tb_wr_bdst_ruse_fclt"
+ ? Math.floor(window.innerHeight - 150)
+ : Math.floor(window.innerHeight - 450); // 150px 여백 확보; // calc(100% - 70px)
+ const left = (window.screen.availWidth - width) / 2;
+ const top = (window.screen.availHeight - height) / 2;
+ const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;
+ popupDetailRef.current = window.open(
+ url,
+ "지도 시설 상세정보 팝업",
+ popupOptions
+ );
+}
\ No newline at end of file
diff --git a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx
index 515121e4e..7f87fe1fd 100644
--- a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx
+++ b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx
@@ -67,6 +67,7 @@ export default function ConCostForm({
useEffect(() => {
// 다른 행을 선택하면(selectionVersion 변경) 체크박스 상태를 초기화합니다.
setCheckFinish(false);
+ setLastSub(null)
}, [selectionVersion]);
//공급처 팝업 값 셋팅
@@ -173,12 +174,13 @@ export default function ConCostForm({
return;
}
- const splycd = form.getValues("splyCndtList");
- const pk =
- splycd && splycd[0]?.ruseUtztnFcltCd
- ? splycd[0]?.ruseUtztnFcltCd
- : "11000SW001R1";
+ // const pk =
+ // splycd && splycd[0]?.ruseUtztnFcltCd
+ // ? splycd[0]?.ruseUtztnFcltCd
+ // : "11000SW001R1";
+ const pk =lastSub?.ruseUtztnFcltCd??null
+
if (type === "mat") {
if (value.demandCst) {
const data: DedMatUpdateType = {
@@ -190,31 +192,37 @@ export default function ConCostForm({
flg: checkFinish ? "Checked" : "Sub",
rgtr: TEST_UUID,
};
- if (checkFinish) {
- toast((t) => (
-
- 검토완료 변경시 공사비는 변경할수 없습니다.
-
- 진행하시겠습니까?
-
-
-
-
-
- ));
- } else {
- coMatRvwUpdate(pk, form.getValues("dmdInfoId"), data);
+ if(pk !==null){
+
+ if (checkFinish) {
+ toast((t) => (
+
+ 검토완료 변경시 공사비는 변경할수 없습니다.
+
+ 진행하시겠습니까?
+
+
+
+
+
+ ));
+ } else {
+ coMatRvwUpdate(pk, form.getValues("dmdInfoId"), data);
+ }
+ }else{
+ toast.error('후보지를 먼저 선택해주세요')
}
}
} else if (type === "hist") {
diff --git a/apps/wr/components/ui/map/detailPopup/coSttnDetailPopup.tsx b/apps/wr/components/ui/map/detailPopup/coSttnDetailPopup.tsx
deleted file mode 100644
index dbd30a89d..000000000
--- a/apps/wr/components/ui/map/detailPopup/coSttnDetailPopup.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-export default function coSttnDetailPopup(){
-
-
- return(
- <>
-
-
- >
- )
-}
\ No newline at end of file
diff --git a/apps/wr/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup.tsx b/apps/wr/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup.tsx
new file mode 100644
index 000000000..26c586561
--- /dev/null
+++ b/apps/wr/components/ui/map/detailPopup/coSttnDetailPopup/coSttnDetailPopup.tsx
@@ -0,0 +1,30 @@
+import { useWrStore } from "@/app/store";
+import SdmInsertForm from "@common/business_components/ui/sdmInsertForm";
+import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
+
+export default function CoSttnDetailPopup({isDetail} :{isDetail:DemandCompType}){
+ const {
+ code
+ } = useWrStore((state) => state);
+
+
+ return(
+
+ {
+ console.log(searchText, pageCnt);
+ }}
+ rtnInputData={async (data) => {
+ console.log(data)
+ }}
+ bodyClassNm={"w-full mx-auto bg-white rounded-lg shadow-md p-6"}
+ updateList={isDetail}
+ readOnly={true}
+ >
+
+
+ )
+}
\ No newline at end of file
diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts
index c5c7f8c01..7758ec5ec 100644
--- a/apps/wr/middleware.ts
+++ b/apps/wr/middleware.ts
@@ -16,15 +16,6 @@ export function middleware(req: NextRequest) {
console.log(`[Middleware] Request URL: ${req.url}`);
const searchParams = req.nextUrl.searchParams;
- // if (pathname.startsWith("/server")) {
- // const queryParams = searchParams.toString();
- // const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${
- // queryParams ? `?${queryParams}` : ""
- // }`;
- // console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`);
- // return NextResponse.rewrite(new URL(newUrl));
- // }
-
if (pathname.startsWith("/server")) {
const decodedParams = Array.from(searchParams.entries())
.map(([key, value]) => `${key}=${decodeURIComponent(value)}`)
@@ -37,7 +28,6 @@ export function middleware(req: NextRequest) {
}
if (pathname === "/") {
- console.log(" maim 화면이동 ");
return NextResponse.redirect(new URL("/map/mainMap", req.url));
}
@@ -46,7 +36,6 @@ export function middleware(req: NextRequest) {
const Authorization = req.cookies.get(CLAIM_NAME)?.value;
const newUrl = `${serverApiUrl}${pathname}`;
- console.log("Authorization cms-service ", Authorization);
if (Authorization) requestHeaders.set(CLAIM_NAME, Authorization);
//if (userId) requestHeaders.set(AUTH_USER_ID, userId);
@@ -90,7 +79,6 @@ export function middleware(req: NextRequest) {
if (pathname.startsWith("/geoserver")) {
let queryParams = searchParams.toString();
const typename = searchParams.get("TYPENAME");
- console.log("typename ", typename);
const startYmd = searchParams.get("START_YMD") ?? null;
const endYmd = searchParams.get("END_YMD") ?? null;
@@ -129,7 +117,7 @@ export function middleware(req: NextRequest) {
newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
}
- console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
+ //console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
return NextResponse.rewrite(new URL(newUrl));
}
diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js
index 1f6bc148c..71f9fccf3 100644
--- a/packages/common/business_components/src/ui/map/Gis.js
+++ b/packages/common/business_components/src/ui/map/Gis.js
@@ -164,19 +164,9 @@ function Gis({
[mapInstanceRef],
);
- //피처로 포커스 이동
- const handleFeatureFocus = useCallback(
- (layerName, data) => {
- console.log("handleFeatureFocus");
- // onFeatureFocus?.(data);
- },
- [mapInstanceRef],
- );
-
// 지도 생성 및 초기화
useEffect(() => {
if (!mapRef.current) return;
- //if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단
// EPSG:5179 등록
proj4.defs([
@@ -316,9 +306,9 @@ function Gis({
const handleCheckedLayersChange = useCallback(
(checkedIds, checkedNodesData) => {
setTimeout(() => {
- setCheckedLayers(checkedIds);
- setCheckedLayersData(checkedNodesData);
- onCheckedLayersChange?.(checkedIds, checkedNodesData);
+ setCheckedLayers(checkedIds);
+ setCheckedLayersData(checkedNodesData);
+ onCheckedLayersChange?.(checkedIds, checkedNodesData);
}, 1000);
},
[onCheckedLayersChange],
diff --git a/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx b/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx
index 33388ce62..21239bd7b 100644
--- a/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx
+++ b/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx
@@ -249,6 +249,7 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => {
nearest: true,
});
} else {
+ alert("위치정보를 찾을 수 없습니다.")
console.warn("geometry를 찾을 수 없습니다:", data);
}
} else {
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 e750ab1a7..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");
@@ -69,7 +71,7 @@ export const SearchBar = ({
const initializeSigunData = useCallback(
(sidoCd: string) => {
if (sidoCd === "0") {
- setFilteredSigunData([{ text: "시도", val: "0" }]);
+ setFilteredSigunData([{ text: "시군구", val: "0" }]);
setSigunValue("0");
return;
}
@@ -110,7 +112,6 @@ export const SearchBar = ({
const sidoNm = sidoData.find((item) => item.val === sidoValue)?.text || "";
const sggNm = sigunData.find((item) => item.val === sigunValue)?.text || "";
-
const type = facilityType;
const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
if (!baseUrlTemplate) return;
@@ -135,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;
@@ -148,7 +147,6 @@ export const SearchBar = ({
return code;
});
- //처리시설명으로 처리시설코드 조회
let procUrl2 =
"/operation-service/prcsFclt/ruseInfo/1/1000/A/{sggCd}/0/1/SW/{fcltyNm}";
procUrl2 = procUrl2
@@ -163,9 +161,10 @@ export const SearchBar = ({
body: JSON.stringify(procResult),
});
const procJson2 = await procRes2.json();
- const procResult2 = (procJson2.data || []).map((item: any) => item.fid);
+ const procResult2 = (procJson2.data || []).map(
+ (item: any) => item.bscFctCd
+ );
- //최종 처리시설코드로 재이용시설조회
const res = await fetch(url, {
method: "POST",
headers: {
@@ -179,19 +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) => ({
@@ -199,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) => ({
@@ -223,21 +219,33 @@ export const SearchBar = ({
setSearchList(newList);
};
- //해당 시설물로 이동
+ //해당 시설물로 이동
const handleFeatureFocus = (data: any) => {
+ let featureId = data.fid;
+ const layerNm = data.layerNm;
+
+ if (!isNaN(Number(featureId))) {
+ featureId = String(featureId);
+ }
+
+ if (layerNm === "tb_wr_bdst_ruse_fclt") {
+ featureId = featureId.slice(0, 11);
+ }
+
+ if (!featureId.includes(".")) {
+ featureId = layerNm + "." + featureId;
+ }
+
const map = gisMaps.current;
if (!map) {
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;
- let featureId = data.fid;
+
map
.getLayers()
.getArray()
@@ -248,7 +256,7 @@ export const SearchBar = ({
if (feature) foundFeature = feature;
}
});
- // 3. 피처 선택
+
if (foundFeature) {
const geometry = foundFeature.getGeometry();
if (geometry) {
@@ -261,13 +269,35 @@ export const SearchBar = ({
nearest: true,
});
} else {
+ alert("위치정보를 찾을 수 없습니다.");
console.warn("geometry를 찾을 수 없습니다:", data);
}
} else {
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 (
@@ -285,7 +315,7 @@ export const SearchBar = ({
{ text: "시설 구분", val: "0" },
...facilityTypes,
]}
- onSelectValue={(val:any) =>
+ onSelectValue={(val: any) =>
onSelectValue(val.toString(), "facilityType")
}
value={facilityType}
@@ -297,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,
@@ -336,6 +369,16 @@ export const SearchBar = ({
>
조회
+ {onInit && (
+
+ )}
diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx
index 09dd10525..20a2050bc 100644
--- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx
+++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx
@@ -66,11 +66,12 @@ interface SdmRegFormProps {
rtnValue: (searchText: string, pageCnt: number) => void;
setIsDuplicate: (value: boolean) => void;
updateList?:DemandCompType
+ readOnly?:boolean
}
type FieldComponent = (field: ControllerRenderProps) => JSX.Element;
-export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigunData, dataList, rtnValue, setIsDuplicate ,updateList}: SdmRegFormProps) {
+export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigunData, dataList, rtnValue, setIsDuplicate ,updateList,readOnly}: SdmRegFormProps) {
const [sidoValue, setSidoValue] = useState('');
const [sigunValue, setSigunValue] = useState('');
const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]);
@@ -304,6 +305,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
dataList={dataList}
rtnValue={setRtnValue}
rtnText={setRtnText}
+ readOnly={readOnly}
{...field}
/>
)
@@ -352,6 +354,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
placeholder="주소를 입력하세요"
type="text"
className="!text-xl text-gray-600"
+ readOnly={readOnly}
{...field}
/>
)
@@ -370,6 +373,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
type="text"
className="!text-xl text-gray-600"
value={formattedValue}
+ readOnly={readOnly}
onChange={(e) => {
const value = e.target.value.replace(/\D/g, ''); // 숫자만 저장
field.onChange(value);
@@ -386,6 +390,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
placeholder="패스워드를 입력하세요"
type="password"
className="!text-xl text-gray-600"
+ readOnly={readOnly}
{...field}
/>
)
@@ -398,6 +403,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
placeholder="패스워드를 입력하세요"
type="password"
className="!text-xl text-gray-600"
+ readOnly={readOnly}
{...field}
/>
)
diff --git a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx
index 4091139b9..d88b72e4b 100644
--- a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx
+++ b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx
@@ -17,6 +17,7 @@ type thisProps = {
rtnInputData: (data: DemandCompType) => void;
bodyClassNm?: string;
updateList?:DemandCompType
+ readOnly?:boolean
}
const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean ,updateList?:DemandCompType) => z.object({
@@ -87,35 +88,7 @@ const defaultValues: FormSchema = {
* @returns
*/
-/**
- * 페이지에서 작업
- const {Common, initializeCommonData, getDemandCompList, insertSdmData, Sdm} = useDmStore((state) => state);
- const { selectSidoData, selectSigunData } = Common;
- const { demandCompList } = Sdm;
-
- // 공통데이터 (시도, 시군구 데이터 호출)
- useEffect(() => {
- initializeCommonData();
- }, [initializeCommonData]);
-
- // 컴포넌트에서 텍스트 검색 호출
- const callback = useCallback((searchText: string, pageCnt: number) => {
- searchText = searchText.trim();
- if(searchText.length > 0) {
- getDemandCompList(searchText, pageCnt);
- }
- }, [getDemandCompList]);
-
- // 컴포넌트에서 수요처 등록 호출
- const handleInsertSdmData = useCallback((data: DemandCompType) => {
- insertSdmData(data);
-
- }, [insertSdmData]);
- */
-
-export default function SdmInsertForm({selectSidoData, selectSigunData, dataList, rtnValue, rtnInputData,bodyClassNm, updateList}: thisProps) {
- /* const { insertSdmData } = useDmStore((state) => state);
- const router = useRouter(); */
+export default function SdmInsertForm({selectSidoData, selectSigunData, dataList, rtnValue, rtnInputData,bodyClassNm, updateList,readOnly}: thisProps) {
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
const [isDuplicate, setIsDuplicate] = useState(false);
@@ -191,14 +164,19 @@ export default function SdmInsertForm({selectSidoData, selectSigunData, dataList
rtnValue={setRtnValue}
setIsDuplicate={setIsDuplicate}
updateList={updateList}
+ readOnly={readOnly}
/>
-
+ {readOnly==true?<>
+ >:
+
+ }
+
diff --git a/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx
index 59800b31e..94edc3836 100644
--- a/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx
+++ b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx
@@ -8,6 +8,7 @@ export type thisProps = {
rtnValue: (searchText: string, pageCnt: number) => void;
rtnData: (item: DemandCompType) => void;
rtnText: (text: string) => void;
+ readOnly?:boolean
};
/**
@@ -25,6 +26,7 @@ export const SdmSearchForm = ({
dataList = [],
rtnData = () => {},
rtnText = () => {},
+ readOnly
}: thisProps) => {
const [isOpen, setIsOpen] = useState(false);
const [textValue, setTextValue] = useState(initValue || "");
@@ -84,6 +86,7 @@ export const SdmSearchForm = ({
/* onFocus={() => setIsOpen(true)} */
className="h-[3.2rem] w-full rounded-md border border-gray-300 pl-3 !text-xl text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder={`${label}을(를) 입력하세요`}
+ readOnly={readOnly}
/>
{isOpen && (
diff --git a/packages/common/components/src/ui/footer/index.tsx b/packages/common/components/src/ui/footer/index.tsx
index 8bb6e0c90..34b2e46e9 100644
--- a/packages/common/components/src/ui/footer/index.tsx
+++ b/packages/common/components/src/ui/footer/index.tsx
@@ -1,8 +1,9 @@
-import { useQuery } from "@tanstack/react-query";
+import { useRef } from "react";
import Autoplay from "embla-carousel-autoplay";
-import { getConfig } from "@common/config";
+import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "../../config";
import { getSiteInfo } from "../../api";
+import { getCookie } from "../../lib";
import {
Carousel,
CarouselContent,
@@ -10,10 +11,8 @@ import {
CarouselNext,
CarouselPrevious,
} from "../carousel";
-import { useRef } from "react";
-const appConfig = getConfig();
-const siteId = appConfig.SITE_ID ?? "";
+const siteId = getCookie("site-id-key") ?? "";
export function Footer() {
const { data: siteInfo } = useQuery({
diff --git a/packages/common/components/src/ui/header/index.tsx b/packages/common/components/src/ui/header/index.tsx
index eaf8cc8e5..22e0a0d56 100644
--- a/packages/common/components/src/ui/header/index.tsx
+++ b/packages/common/components/src/ui/header/index.tsx
@@ -21,8 +21,8 @@ import { SearchForm } from "./search-form";
import { NoticePopover } from "./notice-popover";
const appConfig = getConfig();
-const siteId = appConfig.SITE_ID ?? "";
const userId = getCookie(appConfig.AUTH_USER_ID ?? "");
+const siteId = getCookie("site-id-key") ?? "";
const isLoggedIn = !!userId;
export function Header({ viewOnly }: { viewOnly?: boolean }) {
diff --git a/packages/common/components/src/ui/lnb/index.tsx b/packages/common/components/src/ui/lnb/index.tsx
index b7ce9c6fa..07733dbed 100644
--- a/packages/common/components/src/ui/lnb/index.tsx
+++ b/packages/common/components/src/ui/lnb/index.tsx
@@ -40,8 +40,8 @@ import {
} from "../../api";
const appConfig = getConfig();
-const appSiteId = appConfig.SITE_ID ?? "";
const userId = getCookie(appConfig.AUTH_USER_ID ?? "");
+const appSiteId = getCookie("site-id-key") ?? "";
const isLoggedIn = !!userId;
export function LNB({
@@ -201,7 +201,7 @@ export function LNB({
/>
{item.menuKornNm}
-
+
);
@@ -282,9 +282,11 @@ export function LNB({
>
- {menuList?.map((item) => )}
+ {menuList?.map((item) => (
+
+ ))}
-
+
{/* 도움말 아이콘 */}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7b5b2f5df..4b31cf51b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -247,12 +247,6 @@ importers:
dayjs:
specifier: ^1.11.13
version: 1.11.13
- dotenv:
- specifier: ^17.2.1
- version: 17.2.1
- find-up:
- specifier: ^7.0.0
- version: 7.0.0
js-cookie:
specifier: ^3.0.5
version: 3.0.5
@@ -280,6 +274,9 @@ importers:
tus-js-client:
specifier: ^4.3.1
version: 4.3.1
+ yargs:
+ specifier: ^18.0.0
+ version: 18.0.0
zod:
specifier: ^3.24.2
version: 3.25.76
@@ -299,9 +296,6 @@ importers:
'@types/webpack':
specifier: ^5.28.5
version: 5.28.5
- '@types/yargs':
- specifier: ^17.0.33
- version: 17.0.33
eslint:
specifier: ^9
version: 9.33.0
@@ -5001,14 +4995,28 @@ packages:
- webpack-cli
dev: true
- /@types/yargs-parser@21.0.3:
- resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
- dev: true
-
- /@types/yargs@17.0.33:
- resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+ /@typescript-eslint/eslint-plugin@8.25.0(@typescript-eslint/parser@8.39.0)(eslint@9.33.0)(typescript@5.6.3):
+ resolution: {integrity: sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.8.0'
dependencies:
- '@types/yargs-parser': 21.0.3
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 8.39.0(eslint@9.33.0)(typescript@5.6.3)
+ '@typescript-eslint/scope-manager': 8.25.0
+ '@typescript-eslint/type-utils': 8.25.0(eslint@9.33.0)(typescript@5.6.3)
+ '@typescript-eslint/utils': 8.25.0(eslint@9.33.0)(typescript@5.6.3)
+ '@typescript-eslint/visitor-keys': 8.25.0
+ eslint: 9.33.0
+ graphemer: 1.4.0
+ ignore: 5.3.2
+ natural-compare: 1.4.0
+ ts-api-utils: 2.1.0(typescript@5.6.3)
+ typescript: 5.6.3
+ transitivePeerDependencies:
+ - supports-color
dev: true
/@typescript-eslint/eslint-plugin@8.39.0(@typescript-eslint/parser@8.39.0)(eslint@9.33.0)(typescript@5.6.3):
@@ -5081,6 +5089,14 @@ packages:
- supports-color
dev: true
+ /@typescript-eslint/scope-manager@8.25.0:
+ resolution: {integrity: sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dependencies:
+ '@typescript-eslint/types': 8.25.0
+ '@typescript-eslint/visitor-keys': 8.25.0
+ dev: true
+
/@typescript-eslint/scope-manager@8.39.0:
resolution: {integrity: sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5107,6 +5123,23 @@ packages:
typescript: 5.9.2
dev: true
+ /@typescript-eslint/type-utils@8.25.0(eslint@9.33.0)(typescript@5.6.3):
+ resolution: {integrity: sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.8.0'
+ dependencies:
+ '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.6.3)
+ '@typescript-eslint/utils': 8.25.0(eslint@9.33.0)(typescript@5.6.3)
+ debug: 4.4.1
+ eslint: 9.33.0
+ ts-api-utils: 2.1.0(typescript@5.6.3)
+ typescript: 5.6.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/@typescript-eslint/type-utils@8.39.0(eslint@9.33.0)(typescript@5.6.3):
resolution: {integrity: sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5125,11 +5158,35 @@ packages:
- supports-color
dev: true
+ /@typescript-eslint/types@8.25.0:
+ resolution: {integrity: sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dev: true
+
/@typescript-eslint/types@8.39.0:
resolution: {integrity: sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
dev: true
+ /@typescript-eslint/typescript-estree@8.25.0(typescript@5.6.3):
+ resolution: {integrity: sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <5.8.0'
+ dependencies:
+ '@typescript-eslint/types': 8.25.0
+ '@typescript-eslint/visitor-keys': 8.25.0
+ debug: 4.4.1
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.7.2
+ ts-api-utils: 2.1.0(typescript@5.6.3)
+ typescript: 5.6.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/@typescript-eslint/typescript-estree@8.39.0(typescript@5.6.3):
resolution: {integrity: sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5172,6 +5229,23 @@ packages:
- supports-color
dev: true
+ /@typescript-eslint/utils@8.25.0(eslint@9.33.0)(typescript@5.6.3):
+ resolution: {integrity: sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
+ typescript: '>=4.8.4 <5.8.0'
+ dependencies:
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0)
+ '@typescript-eslint/scope-manager': 8.25.0
+ '@typescript-eslint/types': 8.25.0
+ '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.6.3)
+ eslint: 9.33.0
+ typescript: 5.6.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/@typescript-eslint/utils@8.39.0(eslint@9.33.0)(typescript@5.6.3):
resolution: {integrity: sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -5189,6 +5263,14 @@ packages:
- supports-color
dev: true
+ /@typescript-eslint/visitor-keys@8.25.0:
+ resolution: {integrity: sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dependencies:
+ '@typescript-eslint/types': 8.25.0
+ eslint-visitor-keys: 4.2.1
+ dev: true
+
/@typescript-eslint/visitor-keys@8.39.0:
resolution: {integrity: sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -6077,6 +6159,15 @@ packages:
wrap-ansi: 7.0.0
dev: true
+ /cliui@9.0.1:
+ resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==}
+ engines: {node: '>=20'}
+ dependencies:
+ string-width: 7.2.0
+ strip-ansi: 7.1.0
+ wrap-ansi: 9.0.0
+ dev: false
+
/clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
@@ -6560,11 +6651,6 @@ packages:
csstype: 3.1.3
dev: false
- /dotenv@17.2.1:
- resolution: {integrity: sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==}
- engines: {node: '>=12'}
- dev: false
-
/dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -6618,6 +6704,10 @@ packages:
resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==}
dev: false
+ /emoji-regex@10.4.0:
+ resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
+ dev: false
+
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -6916,7 +7006,7 @@ packages:
dependencies:
'@next/eslint-plugin-next': 15.1.7
'@rushstack/eslint-patch': 1.12.0
- '@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0)(eslint@9.33.0)(typescript@5.6.3)
+ '@typescript-eslint/eslint-plugin': 8.25.0(@typescript-eslint/parser@8.39.0)(eslint@9.33.0)(typescript@5.6.3)
'@typescript-eslint/parser': 8.39.0(eslint@9.33.0)(typescript@5.6.3)
eslint: 9.33.0
eslint-import-resolver-node: 0.3.9
@@ -7347,15 +7437,6 @@ packages:
path-exists: 4.0.0
dev: true
- /find-up@7.0.0:
- resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
- engines: {node: '>=18'}
- dependencies:
- locate-path: 7.2.0
- path-exists: 5.0.0
- unicorn-magic: 0.1.0
- dev: false
-
/flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@@ -7490,6 +7571,11 @@ packages:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
+ /get-east-asian-width@1.3.0:
+ resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
+ engines: {node: '>=18'}
+ dev: false
+
/get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@@ -8310,13 +8396,6 @@ packages:
p-locate: 5.0.0
dev: true
- /locate-path@7.2.0:
- resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dependencies:
- p-locate: 6.0.0
- dev: false
-
/lodash-es@4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: true
@@ -8842,13 +8921,6 @@ packages:
yocto-queue: 0.1.0
dev: true
- /p-limit@4.0.0:
- resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dependencies:
- yocto-queue: 1.2.1
- dev: false
-
/p-locate@4.1.0:
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
engines: {node: '>=8'}
@@ -8863,13 +8935,6 @@ packages:
p-limit: 3.1.0
dev: true
- /p-locate@6.0.0:
- resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dependencies:
- p-limit: 4.0.0
- dev: false
-
/p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
@@ -8911,11 +8976,6 @@ packages:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
- /path-exists@5.0.0:
- resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dev: false
-
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
@@ -10176,6 +10236,15 @@ packages:
emoji-regex: 9.2.2
strip-ansi: 7.1.0
+ /string-width@7.2.0:
+ resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ emoji-regex: 10.4.0
+ get-east-asian-width: 1.3.0
+ strip-ansi: 7.1.0
+ dev: false
+
/string.prototype.includes@2.0.1:
resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==}
engines: {node: '>= 0.4'}
@@ -10760,11 +10829,6 @@ packages:
/undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
- /unicorn-magic@0.1.0:
- resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
- engines: {node: '>=18'}
- dev: false
-
/unicorn-magic@0.3.0:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
@@ -11198,6 +11262,15 @@ packages:
string-width: 5.1.2
strip-ansi: 7.1.0
+ /wrap-ansi@9.0.0:
+ resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
+ engines: {node: '>=18'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 7.2.0
+ strip-ansi: 7.1.0
+ dev: false
+
/ws@8.18.3:
resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
engines: {node: '>=10.0.0'}
@@ -11245,7 +11318,6 @@ packages:
/y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
- dev: true
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
@@ -11274,6 +11346,11 @@ packages:
engines: {node: '>=12'}
dev: true
+ /yargs-parser@22.0.0:
+ resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=23}
+ dev: false
+
/yargs@15.4.1:
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
engines: {node: '>=8'}
@@ -11304,16 +11381,23 @@ packages:
yargs-parser: 21.1.1
dev: true
+ /yargs@18.0.0:
+ resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=23}
+ dependencies:
+ cliui: 9.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ string-width: 7.2.0
+ y18n: 5.0.8
+ yargs-parser: 22.0.0
+ dev: false
+
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
- /yocto-queue@1.2.1:
- resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==}
- engines: {node: '>=12.20'}
- dev: false
-
/zod-validation-error@3.5.3(zod@3.25.76):
resolution: {integrity: sha512-OT5Y8lbUadqVZCsnyFaTQ4/O2mys4tj7PqhdbBCp7McPwvIEKfPtdA6QfPeFQK2/Rz5LgwmAXRJTugBNBi0btw==}
engines: {node: '>=18.0.0'}