diff --git a/.gitignore b/.gitignore index 7175c78d4..ee2cfd052 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,7 @@ # dependencies node_modules/ - -# build -.next/ -dist/ +.idea/ # build .next @@ -22,9 +19,14 @@ apps/fo/.next/**/* #.env* .qodo +# next-agents-md +.next-docs/ + pnpm-lock.yaml settings.json .npmrc .cursor +.agent - +apps/**/tsconfig.tsbuildinfo +logs/ diff --git a/.husky/pre-push b/.husky/pre-push index 0ddfdb46e..2adeaead9 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -3,4 +3,8 @@ BRANCH=$(git rev-parse --abbrev-ref HEAD) if [ "$BRANCH" != "main" ]; then exit 0 fi +echo "Branch: $BRANCH" +echo "Changed packages (dry-run):" +pnpm turbo run build --filter="...[origin/$BRANCH]" --dry-run +echo "Starting build..." pnpm turbo run build --filter="...[origin/$BRANCH]" diff --git a/apps/_template/.env.example b/apps/_template/.env.example index b2d706024..f9794a6f8 100644 --- a/apps/_template/.env.example +++ b/apps/_template/.env.example @@ -3,3 +3,6 @@ NEXT_PUBLIC_PORT= NEXT_PUBLIC_PROXY_HOST= NEXT_PUBLIC_SITE_ID= NEXT_PUBLIC_SERVER_API_URL= + +# 401 시 브라우저 리다이렉트 대상 +NEXT_PUBLIC_AUTH_LOGIN_REDIRECT_URL=/auth/login diff --git a/apps/_template/package.json b/apps/_template/package.json index fb27f8af7..17b53990f 100644 --- a/apps/_template/package.json +++ b/apps/_template/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/cm/package.json b/apps/cm/package.json index 9d4e1da8f..bde698393 100644 --- a/apps/cm/package.json +++ b/apps/cm/package.json @@ -52,7 +52,7 @@ "@types/node": "^22.13.1", "@types/webpack": "^5.28.5", "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/cm/src/entities/auth/lib/auth-wrapper.tsx b/apps/cm/src/entities/auth/lib/auth-wrapper.tsx index 1aa4f8e61..5366696f7 100644 --- a/apps/cm/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/cm/src/entities/auth/lib/auth-wrapper.tsx @@ -5,16 +5,15 @@ import { useRouter } from "next/navigation"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; +import { isAtLoginRedirectUrl } from "@common/network"; import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const router = useRouter(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { - // 로그인 페이지에서는 인증 체크를 건너뜀 - if (window.location.pathname === '/auth/login') { + if (isAtLoginRedirectUrl("/auth/login")) { return; } @@ -35,13 +34,8 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - - try { - await LoginApi.silentRefresh(); - await authCheck(); - } catch (refreshError) { - console.error("Token refresh failed:", refreshError); - setUserInfo(null); + setUserInfo(null); + if (!isAtLoginRedirectUrl("/auth/login")) { router.push("/auth/login"); } } diff --git a/apps/cm/src/pages/auth/login/ui/login-page.tsx b/apps/cm/src/pages/auth/login/ui/login-page.tsx index fed7be4ad..297d28a8f 100644 --- a/apps/cm/src/pages/auth/login/ui/login-page.tsx +++ b/apps/cm/src/pages/auth/login/ui/login-page.tsx @@ -145,11 +145,11 @@ function LoginPage() {

- 유역하수도 통합플랫폼 + 유역하수도통합플랫폼
- 통합관리시스템 + 하수도 포탈

-

유역하수도 통합플랫폼에 오신 것을 환영합니다.

+

유역하수도통합플랫폼 하수도 포탈에 오신 것을 환영합니다.

logo diff --git a/apps/common/features/next.config.ts b/apps/common/features/next.config.ts index 34965cf32..8a50ea611 100644 --- a/apps/common/features/next.config.ts +++ b/apps/common/features/next.config.ts @@ -1,6 +1,21 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { + output: "standalone", + experimental: { + proxyTimeout: 600000, + }, + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, + logging: { + fetches: { + fullUrl: true, + }, + }, async rewrites() { return { afterFiles: [ diff --git a/apps/common/features/package.json b/apps/common/features/package.json index 14a96b6f8..7118ae49d 100644 --- a/apps/common/features/package.json +++ b/apps/common/features/package.json @@ -46,7 +46,7 @@ "@types/node": "^22.13.1", "@types/webpack": "^5.28.5", "eslint": "^9", - "eslint-config-next": "15.1.7", + "eslint-config-next": "15.3.8", "postcss": "^8", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx b/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx index e518f938a..d514569e0 100644 --- a/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx @@ -4,13 +4,17 @@ import { useEffect } from "react"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; +import { getAuthLoginRedirectUrl, isAtLoginRedirectUrl } from "@common/network"; import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { + if (isAtLoginRedirectUrl(getAuthLoginRedirectUrl())) { + return; + } + const userId = getCookie(AUTH_USER_ID); if (!userId) { throw new Error("Missing required authentication tokens"); @@ -28,8 +32,6 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - await LoginApi.silentRefresh(); - await authCheck(); } })(); }, []); diff --git a/apps/cs/.gitignore b/apps/cs/.gitignore index b63718b61..f80a96304 100644 --- a/apps/cs/.gitignore +++ b/apps/cs/.gitignore @@ -38,4 +38,5 @@ yarn-error.log* next-env.d.ts .env* -!.env.example \ No newline at end of file +!.env.example +/start_cs.log diff --git a/apps/cs/package.json b/apps/cs/package.json index 03ec06fcf..27f43fcc1 100644 --- a/apps/cs/package.json +++ b/apps/cs/package.json @@ -52,7 +52,7 @@ "@types/node": "^22.13.1", "@types/webpack": "^5.28.5", "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/cs/src/entities/auth/lib/auth-wrapper.tsx b/apps/cs/src/entities/auth/lib/auth-wrapper.tsx index c0be4c2dd..57ae75c34 100644 --- a/apps/cs/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/cs/src/entities/auth/lib/auth-wrapper.tsx @@ -1,18 +1,24 @@ "use client"; import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; -import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; +import { isAtLoginRedirectUrl } from "@common/network"; +import { + ENDPOINT, + AUTH_USER_ID, + AUTH_LOGIN_REDIRECT_URL, +} from "@/shared/config"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { - const router = useRouter(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { + if (isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + return; + } + const userId = getCookie(AUTH_USER_ID); if (!userId) { throw new Error("Missing required authentication tokens"); @@ -30,14 +36,9 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - - try { - await LoginApi.silentRefresh(); - await authCheck(); - } catch (refreshError) { - console.error("Token refresh failed:", refreshError); - setUserInfo(null); - router.push("/auth/login"); + setUserInfo(null); + if (!isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + window.location.assign(AUTH_LOGIN_REDIRECT_URL); } } })(); diff --git a/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx b/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx index 7ae7990a1..d94d79c9a 100644 --- a/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx +++ b/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx @@ -39,10 +39,10 @@ function LoginlogPage() { const [presetDateRange, setPresetDateRange] = useState(""); const [dateRange, setDateRange] = useState(defaultDateRange); const [userId, setUserId] = useState(""); - const [errOcrnYn, setErrOcrnYn] = useState("N"); + const [errOcrnYn, setErrOcrnYn] = useState("ALL"); const [searchParams, setSearchParams] = useState({ userId: "", - errOcrnYn: "N", + errOcrnYn: "", searchDateFrom: dayjs().subtract(7, "day").format("YYYY-MM-DD"), searchDateTo: dayjs().format("YYYY-MM-DD"), sort: "lgnDt,desc", @@ -87,7 +87,7 @@ function LoginlogPage() { setSearchParams({ ...searchParams, userId, - errOcrnYn, + errOcrnYn: errOcrnYn === "ALL" ? "" : errOcrnYn, searchDateFrom: dateRange.from ? dayjs(dateRange.from).format("YYYY-MM-DD") : "", @@ -102,12 +102,12 @@ function LoginlogPage() { const handleReset = () => { setUserId(""); - setErrOcrnYn("N"); + setErrOcrnYn("ALL"); setDateRange(defaultDateRange); setSearchParams({ ...searchParams, userId: "", - errOcrnYn: "N", + errOcrnYn: "", searchDateFrom: dayjs().subtract(7, "day").format("YYYY-MM-DD"), searchDateTo: dayjs().format("YYYY-MM-DD"), }); @@ -180,6 +180,7 @@ function LoginlogPage() { + 전체 정상 오류 diff --git a/apps/cs/src/shared/config/env.ts b/apps/cs/src/shared/config/env.ts index c6373724f..95d1a4477 100644 --- a/apps/cs/src/shared/config/env.ts +++ b/apps/cs/src/shared/config/env.ts @@ -2,6 +2,8 @@ export const PORT = process.env.NEXT_PUBLIC_PORT || "3000"; export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`; export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL; +export const AUTH_LOGIN_REDIRECT_URL = + process.env.NEXT_PUBLIC_AUTH_LOGIN_REDIRECT_URL || "/auth/login"; export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "CS"; export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; export const ACCESS_TOKEN = diff --git a/apps/dc/package.json b/apps/dc/package.json index 747cdf91e..5835b9ab6 100644 --- a/apps/dc/package.json +++ b/apps/dc/package.json @@ -41,7 +41,7 @@ "@types/node": "^22.17.0", "@types/webpack": "^5.28.5", "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/dc/src/entities/auth/lib/auth-wrapper.tsx b/apps/dc/src/entities/auth/lib/auth-wrapper.tsx index 1f196ed52..57ae75c34 100644 --- a/apps/dc/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/dc/src/entities/auth/lib/auth-wrapper.tsx @@ -1,20 +1,24 @@ "use client"; import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; -import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; - -const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; +import { isAtLoginRedirectUrl } from "@common/network"; +import { + ENDPOINT, + AUTH_USER_ID, + AUTH_LOGIN_REDIRECT_URL, +} from "@/shared/config"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { - const router = useRouter(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { + if (isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + return; + } + const userId = getCookie(AUTH_USER_ID); if (!userId) { throw new Error("Missing required authentication tokens"); @@ -32,14 +36,9 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - - try { - await LoginApi.silentRefresh(); - await authCheck(); - } catch (refreshError) { - console.error("Token refresh failed:", refreshError); - setUserInfo(null); - router.push("/auth/login"); + setUserInfo(null); + if (!isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + window.location.assign(AUTH_LOGIN_REDIRECT_URL); } } })(); diff --git a/apps/dc/src/shared/config/env.ts b/apps/dc/src/shared/config/env.ts index 89d2c039c..9edea0e2d 100644 --- a/apps/dc/src/shared/config/env.ts +++ b/apps/dc/src/shared/config/env.ts @@ -3,10 +3,14 @@ export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`; export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL; -export const NEXT_PUBLIC_DC_SERVICE_API_URL = process.env.NEXT_PUBLIC_DC_SERVICE_API_URL || `http://localhost:${PORT}`; +export const NEXT_PUBLIC_DC_SERVICE_API_URL = + process.env.NEXT_PUBLIC_DC_SERVICE_API_URL || `http://localhost:${PORT}`; +export const AUTH_LOGIN_REDIRECT_URL = + process.env.NEXT_PUBLIC_AUTH_LOGIN_REDIRECT_URL || "/auth/login"; // Flask API URL -export const FLASK_API_URL = process.env.NEXT_PUBLIC_FLASK_API_URL || "http://localhost:5000"; +export const FLASK_API_URL = + process.env.NEXT_PUBLIC_FLASK_API_URL || "http://localhost:5000"; //export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "DC"; export const SITE_ID = "DC"; diff --git a/apps/dm/package.json b/apps/dm/package.json index 71d504f50..844e0b1aa 100644 --- a/apps/dm/package.json +++ b/apps/dm/package.json @@ -29,7 +29,7 @@ "@eslint/eslintrc": "^3", "@types/webpack": "^5.28.5", "eslint": "^9", - "eslint-config-next": "15.1.7", + "eslint-config-next": "15.3.8", "postcss": "^8", "tailwindcss": "^3.4.1", "typescript": "^5" diff --git a/apps/dm_new/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx b/apps/dm_new/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx index 5ea0d03cd..774ab81b8 100644 --- a/apps/dm_new/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx +++ b/apps/dm_new/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx @@ -82,7 +82,7 @@ export default function SimilarCaseModal({ const titleId = useId(); const [mounted, setMounted] = useState(false); - const [criterion, setCriterion] = useState(""); + const [criterion, setCriterion] = useState("supplyAmt"); const [selectedCaseId, setSelectedCaseId] = useState(""); useEffect(() => setMounted(true), []); @@ -90,7 +90,8 @@ export default function SimilarCaseModal({ // 모달 열릴 때 초기화 useEffect(() => { if (!open) return; - setCriterion(""); + setCriterion("supplyAmt"); + onSearch("supplyAmt"); setSelectedCaseId(""); }, [open]); @@ -201,7 +202,6 @@ export default function SimilarCaseModal({ }} className="h-10 w-[180px] rounded-md border border-neutral-300 bg-white px-3 text-sm outline-none focus:border-neutral-500" > - diff --git a/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx b/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx index b69b0fdd9..3282f54a5 100644 --- a/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx +++ b/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx @@ -3,6 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import SubPageHeader from "../../_components/SubPageHeader"; +//import { useDmStore } from "@/app/store"; type WaterDetail = { toc: string; @@ -114,12 +115,17 @@ type PairField = { label: string; value: string }; export default function DemandStatusPage() { const rows = useMemo(() => MOCK, []); - // ✅ rows가 빈 경우도 대비 (런타임 오류 방지) + // rows가 빈 경우도 대비 (런타임 오류 방지) const [selectedId, setSelectedId] = useState(rows[0]?.id ?? null); - // ✅ 상세영역 스크롤 이동용 + // 상세영역 스크롤 이동용 const detailRef = useRef(null); + // update + /* const updateSdmInfoData = useDmStore( + (state) => state.updateSdmInfoData + ); */ + // ✅ selected 계산 안정화 const selected = useMemo(() => { if (!rows.length) return null; diff --git a/apps/dm_new/app/(popup-layout)/map/popup/page.tsx b/apps/dm_new/app/(popup-layout)/map/popup/page.tsx index e410ad2a7..bdce68a87 100644 --- a/apps/dm_new/app/(popup-layout)/map/popup/page.tsx +++ b/apps/dm_new/app/(popup-layout)/map/popup/page.tsx @@ -1,6 +1,7 @@ "use client"; import Gis from "@common/business_components/ui/map/Gis"; +import "@/app/commonOrigin.css"; import { useEffect, useRef, useState } from "react"; import { mapService } from "../service"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; @@ -29,10 +30,15 @@ const Map = () => { ruseUtztnFcltCd: fclt.pbnstRuseFcltId, })); + if (!window.opener || typeof window.opener.postMessage !== "function") { + alert("부모 창을 찾을 수 없습니다. 팝업이 'noopener'로 열렸거나, 보안 정책으로 차단되었을 수 있어요."); + return; + } + window.opener.postMessage( { type: "SET_SUBS_INFO", - payload: subsInfoList, // 또는 필요한 데이터 + payload: subsInfoList, // 배열로 전송 (최대 3개) }, "*" ); @@ -52,9 +58,23 @@ const Map = () => { //하수처리시설코드로 재이용시설 목록 조회 const reuseData = async (ruseFcltPk: any) => { + if (!ruseFcltPk) { + console.warn("[reuseData] ruseFcltPk가 없습니다."); + return; + } try { + console.log("[reuseData] API 호출 - ruseFcltPk:", ruseFcltPk); const response = await mapService.getPbnstRuseFclts(ruseFcltPk); - const data = response.data || []; + console.log("[reuseData] API 응답 전체:", response); + // 응답이 배열이면 바로 사용, 객체면 .data 추출 + const data = Array.isArray(response) + ? response + : Array.isArray(response?.data) + ? response.data + : response?.data + ? [response.data] + : []; + console.log("[reuseData] 파싱된 data:", data); setSelectedFclts((prev) => { const newItems = data.filter( (item: any) => @@ -62,7 +82,7 @@ const Map = () => { Object.keys(item).length > 0 && !prev.some((f) => f.pbnstRuseFcltId === item.pbnstRuseFcltId) ); - console.log(newItems); + console.log("[reuseData] 추가될 newItems:", newItems); return [...prev, ...newItems]; }); } catch (error) { @@ -75,11 +95,45 @@ const Map = () => { fetchData(); }, []); + // 부모창에 초기 선택값 요청 (팝업 열릴 때 기존 선택 목록 받아오기) + useEffect(() => { + const origin = window.location.origin; + if (window.opener) { + window.opener.postMessage({ type: "REQUEST_INIT_SUBS_INFO" }, origin); + } + }, []); + + // 부모창에서 초기 선택값 수신 + useEffect(() => { + const origin = window.location.origin; + + const handler = (event: MessageEvent) => { + if (event.origin !== origin) return; + + const data = event.data; + if (!data || typeof data !== "object") return; + + if (data.type === "INIT_SUBS_INFO") { + const list = Array.isArray(data.payload) ? data.payload : []; + setSelectedFclts( + list.map((x) => ({ + ruseUtztnFcltNm: x.ruseUtztnFcltNm ?? "", + pbnstRuseFcltId: x.ruseUtztnFcltCd ?? "", + })) + ); + } + }; + + window.addEventListener("message", handler); + return () => window.removeEventListener("message", handler); + }, []); + // 레이어 생성 후 초기화 처리 const onCheckedLayersChange = () => { //수요처 ID const urlParams = new URLSearchParams(window.location.search); const dmdInfoId = urlParams.get("dmdInfoId"); + console.log("[하이라이트] dmdInfoId:", dmdInfoId); //수요처 위치로 화면 이동 const maps = gisMaps.current; @@ -88,22 +142,42 @@ const Map = () => { const featureId = `${layerNm}.${dmdInfoId}`; let foundFeature: any = null; + // 현재 로드된 레이어 목록 출력 + const allLayerNames = maps + .getLayers() + .getArray() + .map((l: any) => l.get("lyrTyNm") || l.get("name") || "(unnamed)"); + console.log("[하이라이트] 전체 레이어 목록:", allLayerNames); + console.log("[하이라이트] 탐색 대상 레이어:", layerNm); + console.log("[하이라이트] 탐색 대상 featureId:", featureId); + maps .getLayers() .getArray() .forEach((layer: any) => { if (layer.get("lyrTyNm") == layerNm) { + console.log("[하이라이트] 레이어 발견:", layerNm); const source = layer.getSource?.(); if (source?.getFeatureById) { const feature = source.getFeatureById(String(featureId).trim()); + console.log("[하이라이트] feature 탐색결과:", feature); if (feature) { foundFeature = feature; return; - } + } + // feature 못 찾을 때 소스 내 전체 feature ID 출력 + if (source?.getFeatures) { + const allIds = source.getFeatures().map((f: any) => f.getId()); + console.log("[하이라이트] 소스 내 전체 feature ID:", allIds); + } } } }); + if (!foundFeature) { + console.warn("[하이라이트] feature를 찾지 못했습니다. 위 레이어 목록/ID를 확인하세요."); + } + if (foundFeature) { const geometry = foundFeature.getGeometry(); @@ -133,7 +207,7 @@ const Map = () => { { width: 30 } ); } else { - alert("수요처의 좌표정보를 찾을수 없으므로, 상단 조회조건의 시설명을 입력하여 위치를 조회하시기 바랍니다."); + console.warn("수요처의 좌표정보를 찾을 수 없습니다. dmdInfoId:", dmdInfoId); } const formatNumber = (val: any) => { @@ -185,6 +259,7 @@ const Map = () => { // 검색해서 재이용시설 선택하면 해당 시설로 화면 이동 처리 useEffect(() => { + console.warn(selectDataPk); if (!selectDataPk || Object.keys(selectDataPk).length === 0) return; const maps = gisMaps.current; let foundFeature: any = null; @@ -226,8 +301,12 @@ const Map = () => { // 재이용시설 클릭 시 선택 시설목록에 추가 const onFeatureSelect = (data: any) => { + // feature의 모든 속성 출력 (어떤 키가 있는지 확인) + const properties = data.getProperties?.() ?? {}; + console.log("[onFeatureSelect] feature 속성 전체:", properties); // 처리시설코드 const swtrmtFcltCd = data.get("swtrmt_fclt_cd"); + console.log("[onFeatureSelect] swtrmt_fclt_cd:", swtrmtFcltCd); reuseData(swtrmtFcltCd); }; diff --git a/apps/dm_new/app/(popup-layout)/map/popup/selectedFcltList.tsx b/apps/dm_new/app/(popup-layout)/map/popup/selectedFcltList.tsx index bdf4d7e2c..5c742684f 100644 --- a/apps/dm_new/app/(popup-layout)/map/popup/selectedFcltList.tsx +++ b/apps/dm_new/app/(popup-layout)/map/popup/selectedFcltList.tsx @@ -22,36 +22,32 @@ export default function SelectedFcltList({ const TableContent = ( <> - + - 시설명 - - 하수처리량 -
- (㎥/일) + 시설명 + + 처리량(㎥/일) - - 재이용량 -
- (㎥/일) + + 재이용량(㎥/일) - 삭제 + 삭제 {data.map((item) => ( - - {item.ruseUtztnFcltNm} - + + {item.ruseUtztnFcltNm} + {Number(item.splyExtraCpct || 0).toLocaleString()} - + {Number(item.ruseCpct || 0).toLocaleString()} - + - {/* 수질기준참고 모달 */} - setOpenRef(false)} - imageSrc="/images/landing/water_quality_ref_1.png" - /> -
-
+ + + + - {/* 요구수질 테이블 */} -
- {/* 1행 */} - - - -
- } - rightLabel="총질소(T-N)(mg/L)" - rightControl={ - - } - /> - - - {/* 2행 */} - } - rightLabel="총인(T-P)(mg/L)" - rightControl={ - - } - /> - - - {/* 3행 */} - - } - rightLabel="수소이온농도(pH)" - rightControl={ -
- setPh((p) => ({ ...p, min: v }))} - className="w-32" - /> - ~ - setPh((p) => ({ ...p, max: v }))} - className="w-32" - /> -
- } - /> - - - {/* 4행 */} - - 생물화학적산소요구량 -
- (BOD)(mg/L) - - } - leftRequired - leftControl={} - rightLabel="염화물(mgCL/L)" - rightControl={} - /> - - - {/* 5행 */} - setOdor(e.target.value)} - className="h-11 w-full max-w-[200px] rounded-md border border-neutral-300 bg-white px-3 text-sm outline-none focus:border-neutral-500" - > - - - - - } - rightLabel="전기전도도(µs/cm)" - rightControl={} - /> - - - {/* 6행 */} - } - rightLabel="비고" - rightControl={ -