Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# turbo
|
||||
.turbo/
|
||||
.vscode/**/*
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
@@ -38,4 +38,3 @@ yarn-error.log*
|
||||
next-env.d.ts
|
||||
|
||||
.env*
|
||||
__ENV__.js
|
||||
@@ -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();
|
||||
@@ -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",
|
||||
|
||||
@@ -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 (
|
||||
<html lang="ko" data-theme={theme?.value}>
|
||||
<head>
|
||||
<Script src="/__ENV__.js" strategy="beforeInteractive" />
|
||||
</head>
|
||||
<body>
|
||||
<AppProvider>{children}</AppProvider>
|
||||
</body>
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
__ENV__?: Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
export function getEnvConfig(): Record<string, string> {
|
||||
if (typeof window === "undefined") return {};
|
||||
return window.__ENV__ ?? {};
|
||||
}
|
||||
|
||||
export function getEnv(key: string): string | undefined {
|
||||
return getEnvConfig()[key];
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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/"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -195,7 +195,13 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink,
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>* 연계 URL</TableHead>
|
||||
<TableHead>
|
||||
{['link0001', 'link0002'].includes(form.watch('link_clsf_cd') as string) ? '* 연계 데이터베이스 URL' :
|
||||
(form.watch('link_clsf_cd') === 'link0007' ? '* 연계 파일 경로'
|
||||
: '* 연계 URL'
|
||||
)
|
||||
}
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -242,7 +248,13 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink,
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>* 연계 KEY</TableHead>
|
||||
<TableHead>
|
||||
{['link0001', 'link0002'].includes(form.watch('link_clsf_cd') as string) ? '* 연계 데이터베이스 DRIVER' :
|
||||
(form.watch('link_clsf_cd') === 'link0007' ? '* 연계 파일 확장자'
|
||||
: '* 연계 KEY'
|
||||
)
|
||||
}
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
@@ -5,7 +5,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
NEXT_PUBLIC_CLAIM_NAME = Authorization
|
||||
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
NEXT_PUBLIC_CLAIM_NAME = Authorization
|
||||
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||
|
||||
@@ -18,7 +18,8 @@ NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
NEXT_PUBLIC_CLAIM_NAME = Authorization
|
||||
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
"use client"
|
||||
import "./globals.css";
|
||||
import { StoreProvider } from "./store";
|
||||
import { LoginApi } from "@/src/entities/auth";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
|
||||
useEffect(() => {
|
||||
// 렌더 중이 아니라 클라이언트에서만 실행 + 에러 캐치
|
||||
void LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" })
|
||||
.catch((e) => {
|
||||
console.error("Auto login failed:", e);
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
|
||||
@@ -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<string, any> = {};
|
||||
@@ -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") {
|
||||
// 처리구역(존)
|
||||
@@ -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 (
|
||||
<div className="bg-container">
|
||||
@@ -289,7 +311,7 @@ const Map = () => {
|
||||
onCheckedLayersChange={undefined}
|
||||
imgVisble={false}
|
||||
searchBar={
|
||||
<ProcSearchBar gisMaps={gisMaps} facilityTypes={facilityTypes} />
|
||||
<SearchBar gisMaps={gisMaps} facilityTypes={facilityTypes} onFeatureFocus={undefined} onInit={onInit} />
|
||||
}
|
||||
waterDepth={undefined}
|
||||
/>
|
||||
|
||||
@@ -6,7 +6,6 @@ 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);
|
||||
@@ -14,9 +13,14 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd
|
||||
// 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<modalTableType[]>([]);
|
||||
|
||||
// 가능한 시작년월 설정
|
||||
const [enableEndMonth, setEnableEndMonth] = useState<string[]>(['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월']}
|
||||
/>~
|
||||
<DateMonthPicker
|
||||
field={{
|
||||
@@ -81,6 +108,7 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd
|
||||
selectClass="ml-5 w-[100px]"
|
||||
startYear={1900}
|
||||
yearReadOnly={true}
|
||||
enableMonth={enableEndMonth}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -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<FoStore>()((set) => {
|
||||
LoginApi.login({userId: "CLEANWATER", password: "gktneh12!@"})
|
||||
return {
|
||||
...initState,
|
||||
...CommonReducer(set),
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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("-", "")}`;
|
||||
if (featurePk) {
|
||||
|
||||
const lastPk = layerName==='tb_wr_ruse_fclt_dmd_co'? data[featurePk].replaceAll("-", "") : data[featurePk]
|
||||
featureId = `${layerName}.${lastPk}`;
|
||||
} else {
|
||||
console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName);
|
||||
featureId = `${layerName}.${data.fid || data.id || data.ftrIdn}`;
|
||||
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
|
||||
)
|
||||
) {
|
||||
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 layerNm = getSelectedLayers(isFeature,gisMaps);
|
||||
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
|
||||
);
|
||||
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 (
|
||||
<div className="bg-container">
|
||||
@@ -316,8 +272,8 @@ const Map = () => {
|
||||
/>
|
||||
}
|
||||
waterDepth={undefined}
|
||||
onOpenPopup={(data:any) =>{
|
||||
onOpenPopup(data)
|
||||
onOpenPopup={(data: any) => {
|
||||
onOpenPopup(data);
|
||||
}}
|
||||
/>
|
||||
<Toaster position="top-center" />
|
||||
|
||||
@@ -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<any | null>(null);
|
||||
// const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
|
||||
// const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태
|
||||
// const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
|
||||
// const [checkedLayers, setCheckedLayers] = useState<string[]>([]);
|
||||
// const [checkedLayersData, setCheckedLayersData] = useState<any[]>([]);
|
||||
|
||||
// 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 (
|
||||
// // <MapSearchBar
|
||||
// // {...props}
|
||||
// // searchType="공급처 후보지 조회"
|
||||
// // showApplyButton={false}
|
||||
// // />
|
||||
// // );
|
||||
// // };
|
||||
|
||||
// return (
|
||||
// <div className="bg-container">
|
||||
// <Gis
|
||||
// treeData={treeData}
|
||||
// isSearch={false}
|
||||
// gisMaps={gisMaps}
|
||||
// isMiniMap={false}
|
||||
// searchView={undefined}
|
||||
// detailView={(props: any) =>
|
||||
// // <NewWindowPopup
|
||||
// // onClose={handlePopupClose} // 메모이제이션된 함수 사용
|
||||
// // checkedLayers={checkedLayers}
|
||||
// // checkedLayersData={checkedLayersData}
|
||||
// // {...props}
|
||||
// // />
|
||||
// {
|
||||
|
||||
// console.log('p' ,props)
|
||||
// }
|
||||
// }
|
||||
// onFeatureSelect={onFeatureSelect}
|
||||
// setIsOpen={setIsOpen}
|
||||
// setFeatureData={setFeatureData}
|
||||
// featureData={featureData}
|
||||
// setIsSearchModalOpen={setIsSearchModalOpen}
|
||||
// isOpen={isOpen}
|
||||
// isSearchModalOpen={isSearchModalOpen}
|
||||
// onCheckedLayersChange={handleCheckedLayersChange}
|
||||
// imgVisble={true}
|
||||
// searchBar={undefined}
|
||||
// />
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default Map;
|
||||
@@ -44,6 +44,7 @@ export default function MapDetailPopUp() {
|
||||
return (
|
||||
<RswtFacility
|
||||
rtnFeature={(feature) => {
|
||||
|
||||
bc.postMessage({ type: "SELECT_FEATURE", feature });
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -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<any>(null);
|
||||
@@ -45,25 +47,30 @@ export default function MapFeaturePopup() {
|
||||
|
||||
useEffect(() => {
|
||||
if (isFeatureCd && layerNm) {
|
||||
if (layerNm === "하수재이용시설") {
|
||||
if (layerNm === "tb_wr_bdst_ruse_fclt") {
|
||||
setIsDetail(isFeatureCd);
|
||||
} else if (layerNm === "하수처리시설") {
|
||||
} 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 ? (
|
||||
<div className="fixed inset-0 w-screen h-screen m-0 p-0 bg-white">
|
||||
{layerNm === "하수재이용시설" ? (
|
||||
{layerNm === "tb_wr_bdst_ruse_fclt" ? (
|
||||
<RuseDetailPopup bscFctCd={isDetail} />
|
||||
) : layerNm === "하수처리시설" ? (
|
||||
) : layerNm === "tb_il_swage_prcs_fclt" ? (
|
||||
<div style={{ overflowX: "hidden" }}>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<Title title="하수처리시설 상세정보" />
|
||||
@@ -103,21 +110,26 @@ export default function MapFeaturePopup() {
|
||||
onPageChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
) : layerNm === "잠재수요처" ? (
|
||||
) : layerNm === "tb_wr_tmpr_dmd_co" ? (
|
||||
<CoDetailModal
|
||||
formObj={isDetail}
|
||||
readonly={false}
|
||||
onFormSubmit={async (value) => {
|
||||
console.log(value)
|
||||
console.log(value);
|
||||
}}
|
||||
isMap={true}
|
||||
/>
|
||||
) : (
|
||||
) :layerNm === "tb_wr_ruse_fclt_dmd_co" ? (
|
||||
<CoSttnDetailPopup
|
||||
isDetail={isDetail}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<SttnDetailModal
|
||||
type={
|
||||
layerNm === "빗물이용시설"
|
||||
layerNm === "tb_wr_rnwtr_utztn_fclt"
|
||||
? "RNB"
|
||||
: layerNm === "중수도시설"
|
||||
: layerNm === "tb_wr_rswtr_fclt"
|
||||
? "RST"
|
||||
: "HTB"
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ export default function CoMatRvw() {
|
||||
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||
placeholder=""
|
||||
value={
|
||||
field.value != -1
|
||||
field.value != -1 ||field.value != undefined
|
||||
? `${field.value}`
|
||||
: "불검출"
|
||||
}
|
||||
|
||||
@@ -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,6 +22,14 @@ export default function RootLayout({
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// 렌더 중이 아니라 클라이언트에서만 실행 + 에러 캐치
|
||||
void LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" })
|
||||
.catch((e) => {
|
||||
console.error("Auto login failed:", e);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
|
||||
@@ -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<HTMLInputElement>) => {
|
||||
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<HTMLInputElement>) => {
|
||||
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 (
|
||||
<div className="relative" ref={wrapperRef}>
|
||||
<Input
|
||||
value={text}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="시설명을 입력하세요"
|
||||
className={
|
||||
className + " rounded-lg border px-2 py-1 text-sm h-[29.5px]"
|
||||
}
|
||||
/>
|
||||
{showResults && (
|
||||
<div className="absolute z-10 mt-1 max-h-200 w-full overflow-auto rounded border bg-white shadow">
|
||||
{searchList.length > 0 ? (
|
||||
searchList.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`cursor-pointer px-3 py-1 hover:bg-gray-100 ${
|
||||
highlightIndex === index ? "bg-blue-100" : ""
|
||||
}`}
|
||||
onClick={() => handleSelect(item)}
|
||||
>
|
||||
{item.fnm}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="px-3 py-2 text-sm text-gray-500">
|
||||
검색 결과가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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<string, string> = {
|
||||
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<any>;
|
||||
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<SelectDataType[]>([
|
||||
{ text: "선택", val: "0" },
|
||||
]);
|
||||
const [sigunData, setSigunData] = useState<SelectDataType[]>([
|
||||
{ text: "선택", val: "0" },
|
||||
]);
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||
{ text: "선택", val: "0" },
|
||||
]);
|
||||
|
||||
const [facilityData, setFacilityData] = useState<SelectDataType[]>([
|
||||
{ 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 (
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="col-span-4">
|
||||
<div className="card card-border flex">
|
||||
<div className="col-span-10 flex flex-row">
|
||||
{facilityTypes.length > 1 && (
|
||||
<SelectBox
|
||||
labelClass="w-[120px]"
|
||||
className="mr-10 w-[190px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시설물유형"
|
||||
selectArray={[{ text: "선택", val: "0" }, ...facilityTypes]}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "facilityType")
|
||||
}
|
||||
value={facilityType}
|
||||
/>
|
||||
)}
|
||||
<SelectBox
|
||||
labelClass="w-[40px]"
|
||||
className="mr-10 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시도"
|
||||
selectArray={sidoData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
||||
value={sidoValue}
|
||||
/>
|
||||
<SelectBox
|
||||
labelClass="w-[65px]"
|
||||
className="mr-10 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시군구"
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
||||
value={sigunValue}
|
||||
/>
|
||||
<SelectBox
|
||||
labelClass="w-[60px]"
|
||||
className="mr-3 w-[180px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시설명"
|
||||
selectArray={facilityData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "fcltCd")}
|
||||
value={facilityValue}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row space-x-2">
|
||||
<Button
|
||||
color="primary"
|
||||
className="mx-2 mt-1 ml-5"
|
||||
size={"sm"}
|
||||
onClick={handleSearch}
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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<string, string> = {
|
||||
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<any>;
|
||||
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<SelectDataType[]>([
|
||||
{ text: "선택", val: "0" },
|
||||
]);
|
||||
const [sigunData, setSigunData] = useState<SelectDataType[]>([
|
||||
{ text: "선택", val: "0" },
|
||||
]);
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||
{ text: "선택", val: "0" },
|
||||
]);
|
||||
|
||||
const [facilityData, setFacilityData] = useState<SelectDataType[]>([
|
||||
{ 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 (
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="col-span-4">
|
||||
<div className="card card-border flex">
|
||||
<div className="col-span-10 flex flex-row">
|
||||
{facilityTypes.length > 1 && (
|
||||
<SelectBox
|
||||
labelClass="w-[120px]"
|
||||
className="mr-10 w-[190px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시설물유형"
|
||||
selectArray={[{ text: "선택", val: "0" }, ...facilityTypes]}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "facilityType")
|
||||
}
|
||||
value={facilityType}
|
||||
/>
|
||||
)}
|
||||
<SelectBox
|
||||
labelClass="w-[40px]"
|
||||
className="mr-10 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시도"
|
||||
selectArray={sidoData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
||||
value={sidoValue}
|
||||
/>
|
||||
<SelectBox
|
||||
labelClass="w-[65px]"
|
||||
className="mr-10 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시군구"
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
||||
value={sigunValue}
|
||||
/>
|
||||
<SelectBox
|
||||
labelClass="w-[60px]"
|
||||
className="mr-3 w-[180px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="시설명"
|
||||
selectArray={facilityData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "fcltCd")}
|
||||
value={facilityValue}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row space-x-2">
|
||||
<Button
|
||||
color="primary"
|
||||
className="mx-2 mt-1 ml-5"
|
||||
size={"sm"}
|
||||
onClick={handleSearch}
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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<string, string> = {
|
||||
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<any>;
|
||||
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<SelectDataType[]>([
|
||||
{ text: "시도", val: "0" },
|
||||
]);
|
||||
const [sigunData, setSigunData] = useState<SelectDataType[]>([
|
||||
{ text: "시군구", val: "0" },
|
||||
]);
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||
{ 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 (
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="col-span-4">
|
||||
<div className="card card-border flex">
|
||||
<div className="col-span-10 flex flex-row">
|
||||
{facilityTypes.length > 1 && (
|
||||
<SelectBox
|
||||
labelClass="w-[120px]"
|
||||
className="mr-5 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=""
|
||||
selectArray={[
|
||||
{ text: "시설 구분", val: "0" },
|
||||
...facilityTypes,
|
||||
]}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "facilityType")
|
||||
}
|
||||
value={facilityType}
|
||||
/>
|
||||
)}
|
||||
<SelectBox
|
||||
labelClass="w-[40px]"
|
||||
className="mr-5 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=""
|
||||
selectArray={sidoData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
||||
value={sidoValue}
|
||||
/>
|
||||
<SelectBox
|
||||
labelClass="w-[65px]"
|
||||
className="mr-5 w-[150px]"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=""
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
||||
value={sigunValue}
|
||||
/>
|
||||
<SearchInputText
|
||||
initValue={fcltyNm}
|
||||
setValue={(val: string = "") => {
|
||||
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]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row space-x-2">
|
||||
<Button
|
||||
color="primary"
|
||||
className="mx-2 mt-1"
|
||||
size="sm"
|
||||
onClick={handleSearch}
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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<DemandCompType | undefined>;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
coSttnMapDetail: async (dmdInfoId: string) => {
|
||||
try {
|
||||
const coSttnMapDetail = await getFetch(
|
||||
fetchType.WR,
|
||||
`/reuseFc/request/${dmdInfoId}`
|
||||
);
|
||||
return coSttnMapDetail;
|
||||
} catch (erTxt) {
|
||||
console.log("error", erTxt);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 )
|
||||
|
||||
export const getFeatureCd = (featurePropertise: any, layerNm: string) => {
|
||||
const featureCd =
|
||||
layerNm === "하수재이용시설"
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
@@ -67,6 +67,7 @@ export default function ConCostForm({
|
||||
useEffect(() => {
|
||||
// 다른 행을 선택하면(selectionVersion 변경) 체크박스 상태를 초기화합니다.
|
||||
setCheckFinish(false);
|
||||
setLastSub(null)
|
||||
}, [selectionVersion]);
|
||||
|
||||
//공급처 팝업 값 셋팅
|
||||
@@ -173,11 +174,12 @@ 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) {
|
||||
@@ -190,6 +192,9 @@ export default function ConCostForm({
|
||||
flg: checkFinish ? "Checked" : "Sub",
|
||||
rgtr: TEST_UUID,
|
||||
};
|
||||
|
||||
if(pk !==null){
|
||||
|
||||
if (checkFinish) {
|
||||
toast((t) => (
|
||||
<span className="flex flex-col items-center text-2xl">
|
||||
@@ -216,6 +221,9 @@ export default function ConCostForm({
|
||||
} else {
|
||||
coMatRvwUpdate(pk, form.getValues("dmdInfoId"), data);
|
||||
}
|
||||
}else{
|
||||
toast.error('후보지를 먼저 선택해주세요')
|
||||
}
|
||||
}
|
||||
} else if (type === "hist") {
|
||||
delete value.totalConstCost;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
export default function coSttnDetailPopup(){
|
||||
|
||||
|
||||
return(
|
||||
<>
|
||||
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -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(
|
||||
<div>
|
||||
<SdmInsertForm
|
||||
selectSidoData={code.cityCd}
|
||||
selectSigunData={code.sggCd}
|
||||
dataList={[]}
|
||||
rtnValue={(searchText: string, pageCnt: number) => {
|
||||
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}
|
||||
></SdmInsertForm>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+1
-13
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -249,6 +249,7 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => {
|
||||
nearest: true,
|
||||
});
|
||||
} else {
|
||||
alert("위치정보를 찾을 수 없습니다.")
|
||||
console.warn("geometry를 찾을 수 없습니다:", data);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -26,12 +26,14 @@ interface SearchBarProps {
|
||||
gisMaps: React.RefObject<any>;
|
||||
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) => ({
|
||||
@@ -225,19 +221,31 @@ export const SearchBar = ({
|
||||
|
||||
//해당 시설물로 이동
|
||||
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);
|
||||
}
|
||||
|
||||
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}
|
||||
/>
|
||||
<SelectBox
|
||||
@@ -306,7 +338,9 @@ export const SearchBar = ({
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=""
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val:any) => onSelectValue(val.toString(), "sggCd")}
|
||||
onSelectValue={(val: any) =>
|
||||
onSelectValue(val.toString(), "sggCd")
|
||||
}
|
||||
value={sigunValue}
|
||||
/>
|
||||
<SearchInputText
|
||||
@@ -315,7 +349,6 @@ export const SearchBar = ({
|
||||
setFcltyNm(val);
|
||||
}}
|
||||
setRtnData={(selected: { fnm: string; fid: string }) => {
|
||||
// 선택된 항목이 있을 경우 onFeatureSelect 실행
|
||||
const type = facilityType;
|
||||
handleFeatureFocus({
|
||||
layerNm: type,
|
||||
@@ -336,6 +369,16 @@ export const SearchBar = ({
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
{onInit && (
|
||||
<Button
|
||||
color="primary"
|
||||
className="mx-2 mt-1"
|
||||
size="sm"
|
||||
onClick={handleInit}
|
||||
>
|
||||
초기화
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,11 +66,12 @@ interface SdmRegFormProps {
|
||||
rtnValue: (searchText: string, pageCnt: number) => void;
|
||||
setIsDuplicate: (value: boolean) => void;
|
||||
updateList?:DemandCompType
|
||||
readOnly?:boolean
|
||||
}
|
||||
|
||||
type FieldComponent = (field: ControllerRenderProps<FormSchema, keyof FormSchema>) => 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<string>('');
|
||||
const [sigunValue, setSigunValue] = useState<string>('');
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ 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}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
<div className="flex justify-center pt-4">
|
||||
{readOnly==true?<>
|
||||
</>:
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-32 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
|
||||
>
|
||||
수요처등록
|
||||
</Button>
|
||||
}
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
|
||||
@@ -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 && (
|
||||
<div className="absolute top-full left-0 z-50 mb-2 max-h-72 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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({
|
||||
@@ -282,7 +282,9 @@ export function LNB({
|
||||
>
|
||||
<SidebarContent className="bg-background">
|
||||
<SidebarMenu className="gap-0">
|
||||
{menuList?.map((item) => <MenuItem key={item.menuCd} item={item} />)}
|
||||
{menuList?.map((item) => (
|
||||
<MenuItem key={item.menuCd} item={item} />
|
||||
))}
|
||||
</SidebarMenu>
|
||||
|
||||
{/* 도움말 아이콘 */}
|
||||
@@ -292,7 +294,7 @@ export function LNB({
|
||||
<button
|
||||
className={cn(
|
||||
"flex h-12 w-full items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
||||
"focus:outline-none"
|
||||
"focus:outline-none",
|
||||
)}
|
||||
title="도움말"
|
||||
>
|
||||
|
||||
Generated
+152
-68
@@ -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'}
|
||||
|
||||
Reference in New Issue
Block a user