Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
# 공단 개발
|
||||
NEXT_PUBLIC_SITE_ID = DM
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
NEXT_PUBLIC_PROXY_HOST = https://devreuse.hasuon.or.kr
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.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_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
|
||||
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_REUSE_API_URL= http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
|
||||
|
||||
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
|
||||
NEXT_PRIVATE_WR_ADDRESS_KEY = U01TXOFVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA=
|
||||
+4
-3
@@ -13,9 +13,10 @@ NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
NEXT_PUBLIC_REUSE_API_URL=http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
|
||||
@@ -10,9 +10,10 @@ 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_REUSE_API_URL=http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
|
||||
# NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
|
||||
+10
-7
@@ -1,19 +1,22 @@
|
||||
# 공단 운영
|
||||
NEXT_PUBLIC_SITE_ID = DM
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
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_PROXY_HOST = https://devreuse.hasuon.or.kr
|
||||
#NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.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_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
|
||||
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_REUSE_API_URL= http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_WR_API_URL= http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87
|
||||
NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x}
|
||||
|
||||
|
||||
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
|
||||
|
||||
@@ -29,7 +29,7 @@ export type LyrStngProps = {
|
||||
export const mapService = {
|
||||
//레이어 설정 조회
|
||||
getLyrStngs: async () => {
|
||||
const response = await fetch(`${DEV_URL_SN}/app/v1/map/lyrStngs/DM_NETWORK`, {
|
||||
const response = await fetch(`${DEV_URL_SN}/api/v1/map/lyrStngs/DM_NETWORK`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
|
||||
+22
-1
@@ -11,6 +11,18 @@ const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
|
||||
const BUSINESS_JUSO_API_URL = process.env.NEXT_PUBLIC_FINDADRESS_URL || "";
|
||||
const AdressKey = process.env.NEXT_PRIVATE_WR_ADDRESS_KEY || "";
|
||||
|
||||
/** 공통: URLSearchParams의 값을 decodeURIComponent 적용하여 querystring 생성 */
|
||||
function toDecodedQueryString(params: URLSearchParams): string {
|
||||
const entries: string[][] = Array.from(params.entries()).map(([k, v]) => {
|
||||
try {
|
||||
return [k, decodeURIComponent(v)] as string[];
|
||||
} catch {
|
||||
return [k, v] as string[];
|
||||
}
|
||||
});
|
||||
return new URLSearchParams(entries).toString();
|
||||
}
|
||||
|
||||
export function middleware(req: NextRequest) {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
console.log(`[Middleware] Request URL: ${req.url}`);
|
||||
@@ -109,7 +121,7 @@ export function middleware(req: NextRequest) {
|
||||
const url = req.nextUrl.clone();
|
||||
url.searchParams.set("TYPENAME", typename.replace("hasudo:", ""));
|
||||
queryParams = url.searchParams.toString();
|
||||
newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
|
||||
newUrl = `${SEWERAGE_API_URL}/api/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
|
||||
}
|
||||
|
||||
console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
|
||||
@@ -142,6 +154,14 @@ export function middleware(req: NextRequest) {
|
||||
console.log(`[Middleware] Rewriting from '/sewerage-service' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/ngii-server")) {
|
||||
const decodedQuery = toDecodedQueryString(searchParams);
|
||||
const newUrl = `${process.env.NEXT_PUBLIC_NGII_URL}${pathname.replace("/ngii-server", "")}${decodedQuery ? `?${decodedQuery}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '${pathname}' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/bussiness-juso-service")) {
|
||||
console.log("AdressKey ", AdressKey);
|
||||
const params = new URLSearchParams({
|
||||
@@ -173,6 +193,7 @@ export const config = {
|
||||
"/reuse-service/:path*",
|
||||
"/sewerage-service/:path*",
|
||||
"/bussiness-juso-service/:path*",
|
||||
"/ngii-server/:path*",
|
||||
"/",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# 공단 개발
|
||||
NEXT_PUBLIC_SITE_ID = FO
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
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_PROXY_HOST = https://devlarva.hasuon.or.kr
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.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_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/openap/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
+5
-10
@@ -4,22 +4,17 @@ 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_DEV_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login
|
||||
NEXT_PUBLIC_VDI_DEV_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login
|
||||
NEXT_PUBLIC_VDI_DEV_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login
|
||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
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_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
|
||||
#NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&layer=korean_map&style=korean&tilematrixset=EPSG:5179&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&layer=korean_map&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
|
||||
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com/dc-service
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
|
||||
#NEXT_PUBLIC_SERVER_API_URL = http://localhost:8883/operation-service
|
||||
|
||||
|
||||
@@ -5,13 +5,14 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||
NEXT_PUBLIC_ACCESS_TOKEN = access-token
|
||||
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
|
||||
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
#NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
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_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&layer=korean_map&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com/dc-service
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
|
||||
@@ -5,6 +5,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_PROXY_HOST = https://devlarva.hasuon.or.kr
|
||||
#NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
@@ -12,6 +14,7 @@ NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
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_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service
|
||||
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/openap/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87
|
||||
NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import {
|
||||
ACCESS_TOKEN,
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
REFRESH_TOKEN,
|
||||
} from "@/src/shared/config";
|
||||
|
||||
export async function POST() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete(ACCESS_TOKEN);
|
||||
cookieStore.delete(REFRESH_TOKEN);
|
||||
cookieStore.delete(AUTH_USER_ID);
|
||||
cookieStore.delete(CLAIM_NAME);
|
||||
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 📄 Proxy Route
|
||||
* API 프록시 라우트
|
||||
*
|
||||
* - 서버 API로의 요청 프록시 처리
|
||||
* - 쿠키 기반 인증 토큰 및 리프레시 토큰 관리
|
||||
* - POST 및 PUT 요청 핸들링
|
||||
* - 사용자 인증 정보 검증 및 응답 처리
|
||||
* - 에러 핸들링 및 상태 코드 반환
|
||||
* - 사이트 ID 및 헤더 설정
|
||||
*/
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token";
|
||||
const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id";
|
||||
const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
|
||||
const REFRESH_TOKEN = process.env.NEXT_PUBLIC_REFRESH_TOKEN || "refresh-token";
|
||||
const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || "";
|
||||
const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "SN";
|
||||
|
||||
async function handler(
|
||||
request: Request,
|
||||
params: { url: string[] },
|
||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||
) {
|
||||
const cookieStore = await cookies();
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Site-Id": SITE_ID,
|
||||
};
|
||||
let body = {};
|
||||
const isRefreshHandler = params.url.includes("refresh");
|
||||
|
||||
// silent refresh
|
||||
if (isRefreshHandler) {
|
||||
const refreshToken = cookieStore.get(REFRESH_TOKEN);
|
||||
headers[CLAIM_NAME] = refreshToken?.value ?? "";
|
||||
|
||||
if (!headers[CLAIM_NAME]) {
|
||||
return NextResponse.json({ message: "Can't refresh" }, { status: 401 });
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!isRefreshHandler) {
|
||||
body = await request.json();
|
||||
}
|
||||
|
||||
const result = await fetch(`${SERVER_API_URL}/${params.url.join("/")}`, {
|
||||
method,
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
console.log("Invalid Credentials ");
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Credentials" },
|
||||
{ status: 401 },
|
||||
);
|
||||
}
|
||||
|
||||
const accessToken = result.headers.get(ACCESS_TOKEN);
|
||||
const refreshToken = result.headers.get(REFRESH_TOKEN);
|
||||
const userId = result.headers.get(AUTH_USER_ID);
|
||||
|
||||
if (accessToken && userId) {
|
||||
const response = NextResponse.json({
|
||||
[ACCESS_TOKEN]: accessToken,
|
||||
[AUTH_USER_ID]: userId,
|
||||
});
|
||||
|
||||
if (refreshToken) {
|
||||
cookieStore.set(REFRESH_TOKEN, refreshToken, {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Credentials" },
|
||||
{ status: 401 },
|
||||
);
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ message: "Server Error", error },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
) {
|
||||
const params = await props.params;
|
||||
return handler(request, params, "POST");
|
||||
}
|
||||
|
||||
export async function PUT(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
) {
|
||||
const params = await props.params;
|
||||
return handler(request, params, "PUT");
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
*/
|
||||
|
||||
export default function CalcRainEffect(data : any, weather='ALL') {
|
||||
console.log("%c Calculate RainEffect !" , "background:blue;color:white");
|
||||
console.log("%c Data Length :"+data.length+" Weather : "+weather , "background:yellow;color:blue");
|
||||
/* console.log("%c Calculate RainEffect !" , "background:blue;color:white");
|
||||
console.log("%c Data Length :"+data.length+" Weather : "+weather , "background:yellow;color:blue");*/
|
||||
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
|
||||
for(let idx = 0; idx < data.length; idx++) {
|
||||
const item = data[idx];
|
||||
|
||||
@@ -55,7 +55,7 @@ const Map = () => {
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map`;
|
||||
const API_URL = "/sewerage-service/api/v1/map";
|
||||
const reqUrl = `${API_URL}/lyrStngs/FO_NETWORK`;
|
||||
const response = await fetch(reqUrl, {
|
||||
method: "GET",
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
"use client"
|
||||
import { useFoStore } from "@/app/store";
|
||||
import type { TableUpperProps } from "@/app/store/common";
|
||||
import { type TableUpperProps } from "@/app/store/common";
|
||||
import type { SewageOccurProps } from "@/app/store/sewageOccur";
|
||||
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import LoadingOverlay from "@common/business_components/ui/loadingBar";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import SewageOccurModal from "./modal/page";
|
||||
import type { SewageOccurProps } from "@/app/store/sewageOccur";
|
||||
import LoadingOverlay from "@common/business_components/ui/loadingBar";
|
||||
|
||||
export default function PlanSewage() {
|
||||
const {Common
|
||||
@@ -21,6 +21,7 @@ export default function PlanSewage() {
|
||||
,SewageOccurSearch
|
||||
,initializeCommonData
|
||||
,searchSewageOccurList
|
||||
,resetExcelList
|
||||
} = useFoStore((state) => state) || {
|
||||
Common: { isInit: false, selectUpdownData: [], selectOperationData: [], selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" },
|
||||
SewageOccur: { sewageOccurList: [], sewageOccurCount: 0, excelList: [], upHeadList1: [], upHeadList2: [], upHeadList3: [] },
|
||||
@@ -135,6 +136,7 @@ export default function PlanSewage() {
|
||||
* useEffect
|
||||
*/
|
||||
useEffect(() => {
|
||||
resetExcelList();
|
||||
if (!isInit) {
|
||||
initializeCommonData();
|
||||
searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0");
|
||||
@@ -142,15 +144,19 @@ export default function PlanSewage() {
|
||||
}, [isInit, initializeCommonData, searchSewageOccurList]);
|
||||
|
||||
useEffect(() => {
|
||||
if (excelList && excelList.length > 0) {
|
||||
downloadExcel({
|
||||
data: excelList as unknown as JSON[],
|
||||
fileName: '오수발생량 추정',
|
||||
sheetNameArray: ['오수발생량 추정'],
|
||||
headerRange: 'A1:O1'
|
||||
});
|
||||
}
|
||||
}, [excelList]);
|
||||
const timer = setTimeout(() => {
|
||||
if (excelList && excelList.length > 0) {
|
||||
downloadExcel({
|
||||
data: excelList as unknown as JSON[],
|
||||
fileName: '오수발생량 추정',
|
||||
sheetNameArray: ['오수발생량 추정'],
|
||||
headerRange: 'A1:O1'
|
||||
});
|
||||
}
|
||||
}, 500); // 약간의 지연을 두고 다운로드 실행
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [excelList, isInit]);
|
||||
|
||||
/**
|
||||
* 콜백함수
|
||||
@@ -188,8 +194,12 @@ export default function PlanSewage() {
|
||||
|
||||
// 엑셀다운로드
|
||||
const excelDownload = useCallback(() => {
|
||||
searchFacilityPrecipitation(ref.current, 1, 10000);
|
||||
}, [searchFacilityPrecipitation]);
|
||||
searchFacilityPrecipitation(ref.current, 1, sewageOccurCount);
|
||||
|
||||
setTimeout(() => {
|
||||
resetExcelList()
|
||||
}, 1000); // 약간의 지연을 두고 초기화 (다운로드 완료 후)
|
||||
}, [searchFacilityPrecipitation, sewageOccurCount]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
@@ -250,4 +260,4 @@ export default function PlanSewage() {
|
||||
)}
|
||||
</MainDiv>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export default function UnderWaterInput() {
|
||||
,UnderWaterSearch
|
||||
,initializeCommonData
|
||||
,searchUnderWaterList
|
||||
,resetExcelList
|
||||
} = useFoStore((state) => state) || {
|
||||
Common: { isInit: false, selectUpdownData: [], selectOperationData: [], selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" },
|
||||
UnderWater: { underWaterList: [], underWaterCount: 0, excelList: [], upHeadList1: [], upHeadList2: [], upHeadList3: [] },
|
||||
@@ -134,21 +135,25 @@ export default function UnderWaterInput() {
|
||||
* useEffect
|
||||
*/
|
||||
useEffect(() => {
|
||||
resetExcelList();
|
||||
if (!isInit) {
|
||||
initializeCommonData();
|
||||
searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0");
|
||||
}
|
||||
}, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear]);
|
||||
}, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear, resetExcelList]);
|
||||
|
||||
useEffect(() => {
|
||||
if (excelList && excelList.length > 0) {
|
||||
downloadExcel({
|
||||
data: excelList as unknown as JSON[],
|
||||
fileName: '지하수유입량 추정',
|
||||
sheetNameArray: ['지하수유입량 추정'],
|
||||
headerRange: 'A1:V1'
|
||||
});
|
||||
}
|
||||
const timer = setTimeout(() => {
|
||||
if (excelList && excelList.length > 0) {
|
||||
downloadExcel({
|
||||
data: excelList as unknown as JSON[],
|
||||
fileName: '지하수유입량 추정',
|
||||
sheetNameArray: ['지하수유입량 추정'],
|
||||
headerRange: 'A1:V1'
|
||||
});
|
||||
}
|
||||
}, 500); // 약간의 지연을 두고 다운로드 실행
|
||||
return () => clearTimeout(timer);
|
||||
}, [excelList]);
|
||||
|
||||
/**
|
||||
@@ -187,8 +192,12 @@ export default function UnderWaterInput() {
|
||||
|
||||
// 엑셀다운로드
|
||||
const excelDownload = useCallback(() => {
|
||||
searchFacilityPrecipitation(ref.current, 1, 10000);
|
||||
}, [searchFacilityPrecipitation]);
|
||||
searchFacilityPrecipitation(ref.current, 1, underWaterCount);
|
||||
|
||||
setTimeout(() => {
|
||||
resetExcelList();
|
||||
}, 1000); // 약간의 지연을 두고 다운로드 실행
|
||||
}, [resetExcelList, searchFacilityPrecipitation, underWaterCount]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
|
||||
@@ -252,6 +252,7 @@ export const facilityPrecipitationReducer:(set:(fn: (state: FacilityPrecipitatio
|
||||
const excelDownList: ExcelType[] = [];
|
||||
|
||||
if(pageSize>5000){
|
||||
console.log('엑셀다운로드 데이터 생성 : ', data.length);
|
||||
data.forEach((item: FacilityPrecipitationProps) => {
|
||||
excelDownList.push({
|
||||
시설코드: item.bscFctCd,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getFetch } from "@/app/components/api";
|
||||
import DataForm from "@/app/components/common/DataForm";
|
||||
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
|
||||
import type { TableUpperProps } from "../dashboard";
|
||||
export type { TableUpperProps };
|
||||
|
||||
@@ -412,6 +412,26 @@ const gridListFcltyWaterQltyInfo:fcltyWaterQltyInfoProps[] = [
|
||||
====================================*/
|
||||
|
||||
// 시설정보 리스트 데이터 호출(구분 선택 후 시설명 있을 경우)
|
||||
export const fetchFacilityListInit = async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string ): Promise<{data:facilityListProps[], count:number}> => {
|
||||
try {
|
||||
const tailStr = partValue ? '/'+ (partValue==='G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + '/' + facilityPartValue + (facilityName && facilityName !== '' ? '/' + facilityName : '') : '';
|
||||
const url = '/prcsFclt/info/'+pageNo+'/'+pageSize+tailStr;
|
||||
const res = await getFetch('fo', url);
|
||||
res.data.forEach((item: Record<string, unknown>) => {
|
||||
item.daddr = item.addr ? item.addr : '';
|
||||
item.sidoNm = item.sido ? item.sido : '';
|
||||
item.sggNm = item.gugun ? item.gugun : '';
|
||||
item.fctCpc = roundNumber(item.fctCpc as number, 0);
|
||||
});
|
||||
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.error('시설정보 데이터를 가져오는데 실패했습니다:', error);
|
||||
return {data: [], count: 0};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const fetchFacilityList = async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string ): Promise<{data:facilityListProps[], count:number}> => {
|
||||
try {
|
||||
const tailStr = partValue ? '/'+ (partValue==='G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + '/' + facilityPartValue + (facilityName && facilityName !== '' ? '/' + facilityName : '') : '';
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import DataForm from "@/app/components/common/DataForm";
|
||||
import type { TableUpperProps } from "../dashboard";
|
||||
import { getFetch } from "@/app/components/api";
|
||||
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
|
||||
import { roundNumber } from "@/app/components/common/DataForm";
|
||||
import { OSU_PERCENT } from "../common";
|
||||
import type { TableUpperProps } from "../dashboard";
|
||||
import { fetchFacilityListInit } from "../processFacility";
|
||||
export type { TableUpperProps };
|
||||
/**====================================
|
||||
* Store - 타입
|
||||
@@ -124,24 +125,30 @@ const tempSewageOccurList:modalTableType[] = []
|
||||
* Store - API
|
||||
====================================*/
|
||||
|
||||
const fetchSewageOccurList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
/*const fetchSewageOccurList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
// 20250701임시시
|
||||
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
|
||||
const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
|
||||
const res = await getFetch('fo', url);
|
||||
return { data: res.data, count: res.count }
|
||||
|
||||
/*
|
||||
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
|
||||
const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
|
||||
const res = await getFetch('fo', url);
|
||||
return { data: res.data, count: res.count } */
|
||||
return { data: res.data, count: res.count }
|
||||
}*/
|
||||
|
||||
const fetchSweageOccurListFlow = async(fcltyCd : string, searchYear : string) => {
|
||||
const url = '/fclt/flow/' + fcltyCd + '/' + searchYear;
|
||||
const res = await getFetch('fo', url);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**====================================
|
||||
* Store - expaort
|
||||
====================================*/
|
||||
export type SewageOccurActions = {
|
||||
resetExcelList: () => void;
|
||||
searchSewageOccurList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void;
|
||||
searchSewageOccurDetailList: (bscFctCd: string, searchYear: string, startYearMonth?: string, endYearMonth?: string) => void;
|
||||
}
|
||||
@@ -194,6 +201,17 @@ export const sewageOccurInitState: SewageOccurType = {
|
||||
}
|
||||
}
|
||||
|
||||
// 병렬 처리 제한용 헬퍼
|
||||
async function processInBatches(items, batchSize, callback) {
|
||||
const results:any = [];
|
||||
for (let i = 0; i < items.length; i += batchSize) {
|
||||
const batch = items.slice(i, i + batchSize);
|
||||
const batchResults = await Promise.all(batch.map(callback));
|
||||
results.push(...batchResults);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
export type SewageOccurStore = SewageOccurType & SewageOccurActions;
|
||||
|
||||
// Add type definitions for API responses
|
||||
@@ -212,33 +230,58 @@ export type FlowResponse = {
|
||||
|
||||
export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
|
||||
return {
|
||||
searchSewageOccurList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
resetExcelList: () => {
|
||||
set((state: SewageOccurType) => ({
|
||||
...state,
|
||||
SewageOccur: {
|
||||
...state.SewageOccur,
|
||||
isLoading: true,
|
||||
},
|
||||
...state,
|
||||
SewageOccur: {
|
||||
...state.SewageOccur,
|
||||
excelList: [],
|
||||
},
|
||||
}));
|
||||
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) => {
|
||||
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
},
|
||||
|
||||
searchSewageOccurList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm);
|
||||
if(pageSize < facilityInitData.count){
|
||||
set((state: SewageOccurType) => ({
|
||||
...state,
|
||||
SewageOccur: {
|
||||
...state.SewageOccur,
|
||||
sewageOccurList : facilityInitData.data,
|
||||
sewageOccurCount : facilityInitData.count,
|
||||
excelList : [],
|
||||
isLoading: true
|
||||
},
|
||||
}));
|
||||
}else{
|
||||
set((state: SewageOccurType) => ({
|
||||
...state,
|
||||
SewageOccur: {
|
||||
...state.SewageOccur,
|
||||
excelList : [],
|
||||
isLoading: true
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
const fcltylist = facilityInitData.data;
|
||||
const fcltyCount = facilityInitData.count;
|
||||
|
||||
const calData = await processInBatches(fcltylist, 20, async (item: SewageOccurProps, index: number) => {
|
||||
const bscFctCd = item.bscFctCd;
|
||||
const res = await fetchSweageOccurListFlow(bscFctCd, searchYear);
|
||||
|
||||
item.sidoNm = item.sidoNm || '';
|
||||
item.sggNm = item.sggNm || '';
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
item.swageChangePercent = 90;
|
||||
|
||||
const bscFctCd = item.bscFctCd;
|
||||
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse;
|
||||
|
||||
let sumChungcunDay = 0;
|
||||
let chungcunSumFlow = 0;
|
||||
let totWaterUsage = 0;
|
||||
|
||||
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
|
||||
const rainEffectData = CalcRainEffect(res2.data);
|
||||
const rainEffectData = CalcRainEffect(res.data);
|
||||
|
||||
rainEffectData.forEach((item: FlowDataItem) => {
|
||||
|
||||
@@ -246,27 +289,25 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
|
||||
chungcunSumFlow += Number(item.inflAmnt);
|
||||
sumChungcunDay += 1;
|
||||
}
|
||||
|
||||
totWaterUsage += Number(item.inflAmnt);
|
||||
});
|
||||
const avg = totWaterUsage /res2.count;
|
||||
|
||||
const avg = res.count == 0 ? 0 : totWaterUsage /res.count;
|
||||
item.waterUsage = parseFloat((avg * 0.65).toFixed(2));
|
||||
item.sewageInputYear = parseFloat(avg.toFixed(2));
|
||||
item.sewageInputChungchun = parseFloat((chungcunSumFlow===0?0:(chungcunSumFlow / sumChungcunDay)).toFixed(2));
|
||||
item.estimationSewage = parseFloat((item.waterUsage * (item.swageChangePercent/100)).toFixed(2));
|
||||
return item;
|
||||
}));
|
||||
|
||||
calData.forEach((item: SewageOccurProps) => {
|
||||
DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'waterUsage', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'swageChangePercent', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'estimationSewage', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'sewageInputYear', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'sewageInputChungchun', item: item as unknown as Record<string, unknown> });
|
||||
// 반올림 처리
|
||||
["fctCpc", "waterUsage", "swageChangePercent", "estimationSewage", "sewageInputYear", "sewageInputChungchun"].forEach(
|
||||
(key) => (item[key] = roundNumber(item[key], 0))
|
||||
);
|
||||
|
||||
return {...item, index:index};
|
||||
});
|
||||
|
||||
if(pageSize>5000){
|
||||
if(pageSize >= fcltyCount){
|
||||
const excelDownList: ExcelType[] = [];
|
||||
calData.forEach((item: SewageOccurProps) => {
|
||||
excelDownList.push({
|
||||
시설코드: item.bscFctCd,
|
||||
@@ -286,21 +327,109 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
|
||||
"청천시하수유입량(m³/일)": item.sewageInputChungchun,
|
||||
});
|
||||
});
|
||||
set((state: SewageOccurType) => ({
|
||||
...state,
|
||||
SewageOccur: {
|
||||
...state.SewageOccur,
|
||||
excelList: excelDownList,
|
||||
isLoading : false,
|
||||
},
|
||||
}));
|
||||
}else{
|
||||
set((state: SewageOccurType) => ({
|
||||
...state,
|
||||
SewageOccur: {
|
||||
...state.SewageOccur,
|
||||
sewageOccurList : calData,
|
||||
sewageOccurCount : facilityInitData.count,
|
||||
isLoading: false,
|
||||
excelList: [],
|
||||
},
|
||||
}));
|
||||
}
|
||||
// 조회 데이터 설정
|
||||
set((state: any) => ({
|
||||
...state,
|
||||
SewageOccur: pageSize<5000?{
|
||||
...state.SewageOccur,
|
||||
sewageOccurList: calData,
|
||||
sewageOccurCount: res.count,
|
||||
isLoading : false,
|
||||
}:{
|
||||
...state.SewageOccur,
|
||||
excelList: excelDownList,
|
||||
isLoading : false,
|
||||
},
|
||||
}))
|
||||
|
||||
/* fetchSewageOccurList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm).then(async (res) => {
|
||||
const excelDownList: ExcelType[] = [];
|
||||
const data = res.data;
|
||||
// Promise.all을 사용하여 모든 비동기 작업이 완료될 때까지 기다림
|
||||
const calData = await Promise.all(data.map(async (item: SewageOccurProps) => {
|
||||
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
item.swageChangePercent = 90;
|
||||
|
||||
const bscFctCd = item.bscFctCd;
|
||||
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse;
|
||||
|
||||
let sumChungcunDay = 0;
|
||||
let chungcunSumFlow = 0;
|
||||
let totWaterUsage = 0;
|
||||
|
||||
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
|
||||
const rainEffectData = CalcRainEffect(res2.data);
|
||||
|
||||
rainEffectData.forEach((item: FlowDataItem) => {
|
||||
|
||||
if(Number(item.rainEffectDay) === 0){
|
||||
chungcunSumFlow += Number(item.inflAmnt);
|
||||
sumChungcunDay += 1;
|
||||
}
|
||||
|
||||
totWaterUsage += Number(item.inflAmnt);
|
||||
});
|
||||
const avg = totWaterUsage /res2.count;
|
||||
item.waterUsage = parseFloat((avg * 0.65).toFixed(2));
|
||||
item.sewageInputYear = parseFloat(avg.toFixed(2));
|
||||
item.sewageInputChungchun = parseFloat((chungcunSumFlow===0?0:(chungcunSumFlow / sumChungcunDay)).toFixed(2));
|
||||
item.estimationSewage = parseFloat((item.waterUsage * (item.swageChangePercent/100)).toFixed(2));
|
||||
return item;
|
||||
}));
|
||||
|
||||
calData.forEach((item: SewageOccurProps) => {
|
||||
DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'waterUsage', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'swageChangePercent', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'estimationSewage', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'sewageInputYear', item: item as unknown as Record<string, unknown> });
|
||||
DataForm({ type: 'float0', column: 'sewageInputChungchun', item: item as unknown as Record<string, unknown> });
|
||||
});
|
||||
|
||||
if(pageSize>5000){
|
||||
calData.forEach((item: SewageOccurProps) => {
|
||||
excelDownList.push({
|
||||
시설코드: item.bscFctCd,
|
||||
권역: item.rvbsn,
|
||||
단위유역: item.lgbsn,
|
||||
중권역: item.mdmbsn,
|
||||
환경청: item.rgnNm,
|
||||
시설명: item.bscFctNm,
|
||||
시도: item.sidoNm,
|
||||
시군구: item.sggNm,
|
||||
주소: item.daddr,
|
||||
"시설용량(m³/일)": item.fctCpc,
|
||||
"물사용량(m³/일)": item.waterUsage,
|
||||
"오수전환율(%)": item.swageChangePercent,
|
||||
"오수발생량추정(m³/일)": item.estimationSewage,
|
||||
"연간하수유입량(m³/일)": item.sewageInputYear,
|
||||
"청천시하수유입량(m³/일)": item.sewageInputChungchun,
|
||||
});
|
||||
});
|
||||
}
|
||||
// 조회 데이터 설정
|
||||
set((state: any) => ({
|
||||
...state,
|
||||
SewageOccur: pageSize<5000?{
|
||||
...state.SewageOccur,
|
||||
sewageOccurList: calData,
|
||||
sewageOccurCount: res.count,
|
||||
isLoading : false,
|
||||
}:{
|
||||
...state.SewageOccur,
|
||||
excelList: excelDownList,
|
||||
isLoading : false,
|
||||
},
|
||||
}))
|
||||
}); */
|
||||
},
|
||||
|
||||
searchSewageOccurDetailList: async (bscFctCd: string, searchYear: string, startYearMonth?: string, endYearMonth?: string) => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { getFetch } from "@/app/components/api";
|
||||
import DataForm from "@/app/components/common/DataForm";
|
||||
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
|
||||
import type { TableUpperProps } from "../dashboard";
|
||||
import type { ExcelType, UnderWaterInputModalProps, UnderWaterProps } from "./types";
|
||||
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
|
||||
import { OSU_PERCENT } from "../common";
|
||||
import { fetchFacilityListInit } from "../processFacility";
|
||||
export type { TableUpperProps };
|
||||
|
||||
// SewageOccurDetailProps 타입을 여기에 정의
|
||||
@@ -187,24 +188,32 @@ export interface ApiResponse {
|
||||
count: number;
|
||||
}
|
||||
|
||||
/*
|
||||
const fetchUnderWaterList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
|
||||
const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
|
||||
const res = await getFetch('fo', url);
|
||||
return { data: res.data, count: res.count }
|
||||
/*
|
||||
|
||||
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
|
||||
const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
|
||||
const res = await getFetch('fo', url);
|
||||
return { data: res.data, count: res.count } */
|
||||
return { data: res.data, count: res.count }
|
||||
|
||||
//return { data: underWaterList, count: 2 };
|
||||
}*/
|
||||
|
||||
const fetchUnderWaterListFlow = async(fcltyCd : string, searchYear : string) => {
|
||||
const url = '/fclt/flow/' + fcltyCd + '/' + searchYear;
|
||||
const res = await getFetch('fo', url);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**====================================
|
||||
* Store - expaort
|
||||
====================================*/
|
||||
export type UnderWaterActions = {
|
||||
resetExcelList: () => void;
|
||||
searchUnderWaterList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void;
|
||||
unserWaterModal:(bscFctCd:string, searchYear:string, startYm:string, endYm:string)=>void
|
||||
}
|
||||
@@ -220,7 +229,7 @@ export type UnderWaterType = {
|
||||
upHeadList1: TableUpperProps[];
|
||||
upHeadList2: TableUpperProps[];
|
||||
upHeadList3: TableUpperProps[];
|
||||
underWaterList: UnderWaterProps[]; // Changed from facilityAreaProps to ProcessAreaProps
|
||||
underWaterList: any[]; // Changed from facilityAreaProps to ProcessAreaProps
|
||||
underWaterCount: number;
|
||||
excelList: ExcelType[];
|
||||
isLoading: boolean;
|
||||
@@ -265,29 +274,65 @@ const dataFormSetting=(item : UnderWaterProps)=> {
|
||||
DataForm({ type: 'float0', column: 'underWaterInputWinter', item: item as unknown as Record<string, unknown>});
|
||||
}
|
||||
|
||||
// 병렬 처리 제한용 헬퍼
|
||||
async function processInBatches(items, batchSize, callback) {
|
||||
const results :any = [];
|
||||
for (let i = 0; i < items.length; i += batchSize) {
|
||||
const batch = items.slice(i, i + batchSize);
|
||||
const batchResults = await Promise.all(batch.map(callback));
|
||||
results.push(...batchResults);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
export type UnderWaterStore = UnderWaterType & UnderWaterActions;
|
||||
|
||||
export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterType) => void)=>UnderWaterActions=(set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => {
|
||||
return {
|
||||
searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
resetExcelList: () => {
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: {
|
||||
...state.UnderWater,
|
||||
isLoading: true,
|
||||
excelList : [],
|
||||
},
|
||||
}));
|
||||
|
||||
const res = await fetchUnderWaterList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
|
||||
const data = res.data;
|
||||
const calData = await Promise.all(data.map(async (item: UnderWaterProps) => {
|
||||
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
},
|
||||
|
||||
searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm);
|
||||
|
||||
if(pageSize < facilityInitData.count){
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: {
|
||||
...state.UnderWater,
|
||||
underWaterList : facilityInitData.data,
|
||||
underWaterCount : facilityInitData.count,
|
||||
isInit : true,
|
||||
isLoading: true,
|
||||
},
|
||||
}));
|
||||
}else{
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: {
|
||||
...state.UnderWater,
|
||||
isLoading: true,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
const fcltylist = facilityInitData.data;
|
||||
const fcltyCount = facilityInitData.count;
|
||||
|
||||
const calData = await processInBatches(fcltylist, 20, async (item: any, index: number) => {
|
||||
const bscFctCd = item.bscFctCd;
|
||||
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as ApiResponse;
|
||||
const calData = CalcRainEffect(res2.data, 'SUNNY');
|
||||
const res = await fetchUnderWaterListFlow(bscFctCd, searchYear);
|
||||
|
||||
item.sidoNm = item.sido || '';
|
||||
item.sggNm = item.gugun || '';
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
|
||||
let chungcunSumFlow = 0;
|
||||
|
||||
@@ -297,7 +342,8 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
|
||||
let sumWinterChungcunDay = 0;
|
||||
let sumWinterChungcunFlow = 0;
|
||||
|
||||
calData.forEach((flowItem: FlowDataItem) => {
|
||||
const rainEffectData = CalcRainEffect(res.data, 'SUNNY');
|
||||
rainEffectData.forEach((flowItem: FlowDataItem) => {
|
||||
chungcunSumFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
|
||||
|
||||
if(flowItem.msrDt.substring(4,6) ==='06' || flowItem.msrDt.substring(4,6) ==='07' || flowItem.msrDt.substring(4,6) ==='08'){
|
||||
@@ -308,25 +354,32 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
|
||||
sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
|
||||
}
|
||||
});
|
||||
const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / calData.length:0;
|
||||
|
||||
let totWaterInflow = 0
|
||||
|
||||
const rainEffectTot = CalcRainEffect(res.data);
|
||||
rainEffectTot.forEach((flowItem: FlowDataItem) => {
|
||||
totWaterInflow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
|
||||
});
|
||||
|
||||
|
||||
const avg = res.count === 0 ? 0 : totWaterInflow / res.count;
|
||||
|
||||
const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / rainEffectData.length:0;
|
||||
const summerUsage = sumSummerChungcunFlow?sumSummerChungcunFlow / sumSummerChungcunDay:0;
|
||||
const winterUsage = sumWinterChungcunFlow?sumWinterChungcunFlow / sumWinterChungcunDay:0;
|
||||
|
||||
//bscFctCd === '11200PB001R') 중랑 - 테스트할 때 코드넣고 해야 보기편해요~
|
||||
/* if(bscFctCd === '11200PB001R') {
|
||||
console.log('calData.length : ', calData.length);
|
||||
console.log('usage : ', usage, 'summerUsage : ', summerUsage, 'winterUsage : ', winterUsage);
|
||||
} */
|
||||
item.inflAmnt = roundNumber(avg, 0);
|
||||
item.underWaterInputYear = Math.round((usage-(usage*0.65*OSU_PERCENT)) * 1) / 1;
|
||||
item.underWaterInputSummer = Math.round((summerUsage-(summerUsage*0.65*OSU_PERCENT)) * 1) / 1;
|
||||
item.underWaterInputWinter = Math.round((winterUsage-(winterUsage*0.65*OSU_PERCENT)) * 1) / 1;
|
||||
item.properYn = Math.round( (Number(usage-(usage*0.65*OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1 ) / 1 > 20?'초과유입':'적정';
|
||||
return item;
|
||||
}));
|
||||
return {...item, index:index};
|
||||
});
|
||||
|
||||
const excelDownList: ExcelType[] = [];
|
||||
if(pageSize>5000){
|
||||
calData.forEach(item => {
|
||||
if(pageSize>= fcltyCount){
|
||||
const excelDownList: ExcelType[] = [];
|
||||
calData.forEach((item : any) => {
|
||||
dataFormSetting(item)
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
/* item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
@@ -349,27 +402,26 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
|
||||
적정여부: item.properYn,
|
||||
});
|
||||
});
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: {
|
||||
...state.UnderWater,
|
||||
excelList: excelDownList,
|
||||
isLoading : false,
|
||||
},
|
||||
}));
|
||||
}else{
|
||||
data.forEach((item: UnderWaterProps) => {
|
||||
dataFormSetting(item)
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
/* item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; */
|
||||
});
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: {
|
||||
...state.UnderWater,
|
||||
underWaterList: calData,
|
||||
underWaterCount: facilityInitData.count,
|
||||
excelList: [],
|
||||
isLoading : false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: pageSize<5000?{
|
||||
...state.UnderWater,
|
||||
underWaterList: calData,
|
||||
underWaterCount: res.count,
|
||||
isLoading : false,
|
||||
}:{
|
||||
...state.UnderWater,
|
||||
isLoading : false,
|
||||
excelList: excelDownList
|
||||
},
|
||||
}))
|
||||
},
|
||||
|
||||
unserWaterModal:async (bscFctCd, searchYear, startYm, endYm)=>{
|
||||
|
||||
+50
-15
@@ -9,6 +9,18 @@ const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
|
||||
const serverApiUrl = SERVER_API_CS_URL;
|
||||
const DC_URL = process.env.NEXT_PUBLIC_DC_URL || "";
|
||||
|
||||
/** 공통: URLSearchParams의 값을 decodeURIComponent 적용하여 querystring 생성 */
|
||||
function toDecodedQueryString(params: URLSearchParams): string {
|
||||
const entries: string[][] = Array.from(params.entries()).map(([k, v]) => {
|
||||
try {
|
||||
return [k, decodeURIComponent(v)] as string[];
|
||||
} catch {
|
||||
return [k, v] as string[];
|
||||
}
|
||||
});
|
||||
return new URLSearchParams(entries).toString();
|
||||
}
|
||||
|
||||
/** 공통: 요청 헤더에 쿠키 기반 인증 값 주입 */
|
||||
function buildAuthHeaders(req: NextRequest): Headers {
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
@@ -21,9 +33,20 @@ function buildAuthHeaders(req: NextRequest): Headers {
|
||||
|
||||
/** 공통: rewrite 응답 생성 (헤더 주입 여부 선택) */
|
||||
function rewriteWith(url: string, req: NextRequest, withAuth = false): NextResponse {
|
||||
return withAuth
|
||||
? NextResponse.rewrite(new URL(url), { headers: buildAuthHeaders(req) })
|
||||
: NextResponse.rewrite(new URL(url));
|
||||
|
||||
const headers = withAuth ? buildAuthHeaders(req) : new Headers(req.headers);
|
||||
|
||||
if (url.indexOf("/operation-service") !== -1) {
|
||||
// x-forwarded- 로 시작하는 헤더의 첫 번째 값만 남김
|
||||
for (const [key, value] of headers.entries()) {
|
||||
if (key.startsWith('x-forwarded-') && value.includes(',')) {
|
||||
const first = (value?.split(',')[0] || '').trim();
|
||||
headers.set(key, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.rewrite(new URL(url), { headers });
|
||||
}
|
||||
|
||||
export function middleware(req: NextRequest) {
|
||||
@@ -75,11 +98,12 @@ export function middleware(req: NextRequest) {
|
||||
const url = req.nextUrl.clone();
|
||||
url.searchParams.set('TYPENAME', typename.replace("hasudo:",""));
|
||||
queryParams = url.searchParams.toString();
|
||||
newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
|
||||
newUrl = `${SEWERAGE_API_URL}/api/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
|
||||
}
|
||||
|
||||
console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/sewerage-service")) {
|
||||
@@ -88,13 +112,15 @@ export function middleware(req: NextRequest) {
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/sewerage-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/attach-service") || pathname.startsWith("/cms-service")) {
|
||||
const newUrl = `${serverApiUrl}${pathname}`;
|
||||
console.log(`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/reuse-service")) {
|
||||
@@ -103,7 +129,8 @@ export function middleware(req: NextRequest) {
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/operation-service")) {
|
||||
@@ -112,7 +139,8 @@ export function middleware(req: NextRequest) {
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/operation-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/dc-service")) {
|
||||
@@ -121,19 +149,25 @@ export function middleware(req: NextRequest) {
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/dc-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/user-service")) {
|
||||
const newUrl = `${SERVER_API_CS_URL}${pathname}`;
|
||||
console.log(`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
// if (pathname === "/") {
|
||||
// return NextResponse.redirect(new URL("/pages/dashboard", req.url));
|
||||
// }
|
||||
// return NextResponse.next();
|
||||
if (pathname.startsWith("/ngii-server")) {
|
||||
const decodedQuery = toDecodedQueryString(searchParams);
|
||||
const newUrl = `${process.env.NEXT_PUBLIC_NGII_URL}${pathname.replace("/ngii-server", "")}${decodedQuery ? `?${decodedQuery}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '${pathname}' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
export const config = {
|
||||
@@ -148,5 +182,6 @@ export const config = {
|
||||
"/operation-service/:path*",
|
||||
"/reuse-service/:path*",
|
||||
"/dc-service/:path*",
|
||||
"/ngii-server/:path*",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -5,6 +5,9 @@ const subDomain =
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
experimental: {
|
||||
proxyTimeout: 600000, // 10분 (밀리초 단위)
|
||||
},
|
||||
async rewrites() {
|
||||
return {
|
||||
beforeFiles: [
|
||||
@@ -33,6 +36,10 @@ const nextConfig: NextConfig = {
|
||||
source: "/operation-service/:path*",
|
||||
destination: `${subDomain}/operation-service/:path*`,
|
||||
},
|
||||
{
|
||||
source: "/ngii-server/:path*",
|
||||
destination: `${subDomain}/ngii-server/:path*`,
|
||||
},
|
||||
],
|
||||
fallback: [],
|
||||
};
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { client } from "@/src/shared/api";
|
||||
import type { IUserInfo } from "@/src/shared/store";
|
||||
import { useUserStore, getCookie } from "@/src/shared/lib";
|
||||
import { ENDPOINT, AUTH_USER_ID } from "@/src/shared/config";
|
||||
import { LoginApi } from "../api/login-service";
|
||||
|
||||
const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3001/auth/login"; // 개발 환경 URL
|
||||
// const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3001/auth/login"; // 개발 환경 URL
|
||||
|
||||
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const { userInfo, setUserInfo } = useUserStore((state) => state);
|
||||
|
||||
async function authCheck() {
|
||||
@@ -41,19 +40,19 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
setUserInfo(null);
|
||||
|
||||
const hostname = window.location.hostname;
|
||||
// const hostname = window.location.hostname;
|
||||
|
||||
// 개발 환경에서는 localhost 도메인 사용
|
||||
//if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
|
||||
// if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
|
||||
router.push("/"); // 개발시 홈으로 돌아가기
|
||||
|
||||
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
|
||||
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
|
||||
//if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
|
||||
// if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [pathname]);
|
||||
}, []);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# 공단 개발
|
||||
NEXT_PUBLIC_SITE_ID = SN
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
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_PROXY_HOST = https://devlion.hasuon.or.kr
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
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_NGII_URL = http://172.29.143.87/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
+4
-4
@@ -5,15 +5,15 @@ NEXT_PUBLIC_ACCESS_TOKEN = access-token
|
||||
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
|
||||
NEXT_PUBLIC_PORT = 3002
|
||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3002
|
||||
# NEXT_PUBLIC_PROXY_HOST = http://sn.onasys.co.kr:3002
|
||||
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_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&layer=korean_map&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
#NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&layer=korean_map&style=korean&tilematrixset=EPSG:5179&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083
|
||||
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.222:8883
|
||||
# NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883
|
||||
|
||||
@@ -8,6 +8,7 @@ NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11302
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
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_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&layer=korean_map&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083
|
||||
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
|
||||
@@ -5,10 +5,14 @@ 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_PROXY_HOST = https://devlion.hasuon.or.kr
|
||||
#NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
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_NGII_URL = http://172.29.143.87/openap/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87
|
||||
NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service
|
||||
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ const ReportTab: React.FC<ReportTabProps> = ({ open, isSearch = true, ctpvNm, sg
|
||||
const { REPORT_TYPES, flattenFolders, addFileName } = useReportTab();
|
||||
|
||||
useEffect(() => {
|
||||
fetchDcTree(""); // 하수정비기본계획 report
|
||||
fetchDcTree("기본계획"); // 하수정비기본계획 report
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
* - 데이터 매핑 및 코드 변환 (시도/시군구, 보고서 유형 등)
|
||||
*
|
||||
* 🔗 사용 API
|
||||
* - 보고서 파일 조회: GET /api/v1/dc/file (dc-service)
|
||||
* - 파일 다운로드: GET /api/v1/dc/file/download (dc-service)
|
||||
* - 보고서 파일 조회: GET /api/v1/file (dc-service)
|
||||
* - 파일 다운로드: GET /api/v1/fileDownload (dc-service)
|
||||
*/
|
||||
import { getDcData } from '@/components/lib/api';
|
||||
import { fileDownload } from '@/utils';
|
||||
@@ -117,7 +117,7 @@ export default function useReportTab() {
|
||||
return [];
|
||||
}
|
||||
const queryString = 'clsfSystmSn=' + clsfSystmSn;
|
||||
const result = await getDcData(`/api/v1/dc/file${queryString ? `?${queryString}` : ''}`);
|
||||
const result = await getDcData(`/api/v1/file${queryString ? `?${queryString}` : ''}`);
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -146,7 +146,7 @@ export default function useReportTab() {
|
||||
return;
|
||||
}
|
||||
const queryString = 'filePath=' + encodeURIComponent(filePath);
|
||||
const responseBlob = await getDcData(`/api/v1/dc/file/download${queryString ? `?${queryString}` : ''}`, "blob");
|
||||
const responseBlob = await getDcData(`/api/v1/fileDownload${queryString ? `?${queryString}` : ''}`, "blob");
|
||||
fileDownload(responseBlob, fileName);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,13 +143,12 @@ const Page = () => {
|
||||
// 현황 등록
|
||||
const registFile = async (fileName: string, year: string, quater: string, cd: string, id: string) => {
|
||||
const json = {
|
||||
atflNm: fileName,
|
||||
mngYr: year,
|
||||
mngQu: quater,
|
||||
atflCd: cd,
|
||||
atflId: id,
|
||||
sbmrgPrevntBizNm: fileName,
|
||||
rgtr: tokenManager.getToken(AUTH_USER_ID) || null
|
||||
atflCd: cd,
|
||||
rgtr: tokenManager.getToken(AUTH_USER_ID) || null,
|
||||
sbmrgPrevntBizNm: fileName
|
||||
}
|
||||
const data = await postData('v1/sbmrgPrevnt', json)
|
||||
if (data) {
|
||||
|
||||
@@ -139,16 +139,15 @@ const Page = () => {
|
||||
|
||||
// 파일 등록
|
||||
const registFile = async (fileNm: string, year: string, quater: string, cd: string, id: string) => {
|
||||
const data = await postData('v1/dcrpPpl', {
|
||||
atflNm: fileNm,
|
||||
const json = {
|
||||
mngYr: year,
|
||||
mngQu: quater,
|
||||
atflCd: cd,
|
||||
atflId: id,
|
||||
dcrpPplMtncBizNm: fileNm,
|
||||
rgtr: tokenManager.getToken(AUTH_USER_ID) || null,
|
||||
rgtrNm: userInfo?.userName,
|
||||
})
|
||||
dcrpPplMtncBizNm: fileNm
|
||||
}
|
||||
const data = await postData('v1/dcrpPpl', json);
|
||||
if (data) {
|
||||
alert('파일이 등록되었습니다.');
|
||||
setIsModalOpen(false);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import {
|
||||
ACCESS_TOKEN,
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
REFRESH_TOKEN,
|
||||
} from "@/shared/config";
|
||||
|
||||
export async function POST() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete(ACCESS_TOKEN);
|
||||
cookieStore.delete(REFRESH_TOKEN);
|
||||
cookieStore.delete(AUTH_USER_ID);
|
||||
cookieStore.delete(CLAIM_NAME);
|
||||
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
||||
}
|
||||
@@ -60,7 +60,9 @@ export const postData = async (url: string, data: object): Promise<any> => {
|
||||
};
|
||||
|
||||
export const postMutiPart = async (url: string, data: FormData): Promise<any> => {
|
||||
const res = await axios.post(`${BASE_URL}/${url}`, data);
|
||||
const res = await axios.post(`${BASE_URL}/${url}`, data, {
|
||||
timeout: 600000, // 10분
|
||||
});
|
||||
return res.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -72,6 +72,11 @@ const FileUploadForm = ({
|
||||
handleUploadWithResponse(files, currentFile)
|
||||
.then(({ atflCd, atflId }) => {
|
||||
// 업로드 완료 후 onSubmit 실행
|
||||
console.log('fileNm', fileNm);
|
||||
console.log('selectedYear', selectedYear);
|
||||
console.log('selectedQuarter', selectedQuarter);
|
||||
console.log('atflCd', atflCd);
|
||||
console.log('atflId', atflId);
|
||||
onSubmit(fileNm, selectedYear, selectedQuarter, atflCd || '', atflId || '');
|
||||
|
||||
// UI 초기화
|
||||
@@ -120,6 +125,8 @@ const FileUploadForm = ({
|
||||
reject(error);
|
||||
};
|
||||
|
||||
console.log('Starting upload for files:', files);
|
||||
|
||||
// 기존 handleUpload 유틸리티 사용 (수정하지 않음)
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
@@ -160,6 +167,10 @@ const FileUploadForm = ({
|
||||
setFileName(firstFile.name);
|
||||
setCurrentFile(firstFile);
|
||||
|
||||
console.log('selectedFiles', selectedFiles);
|
||||
console.log('firstFile', firstFile);
|
||||
console.log('firstFile name', firstFile.name);
|
||||
|
||||
if (onFileSelect) {
|
||||
onFileSelect(firstFile, internalAtflCd, internalAtflId);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export const useReportTabStore = create<useReportTabStoreType>((set, get) => ({
|
||||
fetchDcTree: async (clsfSystmNm: string) => {
|
||||
const { dcTree } = get();
|
||||
try {
|
||||
const result = await getDcData("/api/v1/dc/clsf?clsfSystmNm=" + clsfSystmNm);
|
||||
const result = await getDcData("/api/v1/clsf?clsfSystmNm=" + clsfSystmNm);
|
||||
if (result && JSON.stringify(result) !== JSON.stringify(dcTree))
|
||||
set({ dcTree: result });
|
||||
} catch (error) {
|
||||
@@ -51,7 +51,7 @@ export const useReportTabStore = create<useReportTabStoreType>((set, get) => ({
|
||||
return [];
|
||||
}
|
||||
const queryString = 'clsfSystmSn=' + clsfSystmSn;
|
||||
const result = await getDcData(`/api/v1/dc/file${queryString ? `?${queryString}` : ''}`);
|
||||
const result = await getDcData(`/api/v1/file${queryString ? `?${queryString}` : ''}`);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
+20
-6
@@ -47,7 +47,8 @@ export function middleware(req: NextRequest) {
|
||||
const newUrl = `${SERVER_API_URL}${pathname.replace("/server", "")}${decodedQuery ? `?${decodedQuery}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/api/proxy")) {
|
||||
@@ -55,7 +56,8 @@ export function middleware(req: NextRequest) {
|
||||
const newUrl = `${SERVER_API_URL}${pathname}${decodedQuery ? `?${decodedQuery}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/geoserver")) {
|
||||
@@ -97,7 +99,8 @@ export function middleware(req: NextRequest) {
|
||||
}
|
||||
|
||||
console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/attach-service")
|
||||
@@ -106,7 +109,8 @@ export function middleware(req: NextRequest) {
|
||||
) {
|
||||
const newUrl = `${SERVER_API_URL}${pathname}`;
|
||||
console.log(`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/dc-service")) {
|
||||
@@ -116,14 +120,23 @@ export function middleware(req: NextRequest) {
|
||||
|
||||
const newUrl = `${DC_URL}${pathname}${decodedParams ? `?${decodedParams}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '/dc-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/sewerage-service")) {
|
||||
const decodedQuery = toDecodedQueryString(searchParams);
|
||||
const newUrl = `${SEWERAGE_API_URL}${pathname}${decodedQuery ? `?${decodedQuery}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '${pathname}' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/ngii-server")) {
|
||||
const decodedQuery = toDecodedQueryString(searchParams);
|
||||
const newUrl = `${process.env.NEXT_PUBLIC_NGII_URL}${pathname.replace("/ngii-server", "")}${decodedQuery ? `?${decodedQuery}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '${pathname}' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
return NextResponse.next();
|
||||
@@ -139,6 +152,7 @@ export const config = {
|
||||
"/cms-service/:path*",
|
||||
"/dc-service/:path*",
|
||||
"/sewerage-service/:path*",
|
||||
"/ngii-server/:path*",
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
@@ -2,6 +2,9 @@ import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
experimental: {
|
||||
proxyTimeout: 600000, // 10분 (밀리초 단위)
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true, // 이 줄 추가
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { client } from "@/shared/api";
|
||||
import type { IUserInfo } from "@/shared/store";
|
||||
import { useUserStore } from "@/shared/lib";
|
||||
@@ -10,11 +10,10 @@ import { getCookie } from "@/shared/lib";
|
||||
import { LoginApi } from "../api/login-service";
|
||||
|
||||
|
||||
const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://dev.onasys.co.kr:3000/auth/login"; // 로그인 페이지 URL
|
||||
// const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://dev.onasys.co.kr:3000/auth/login"; // 로그인 페이지 URL
|
||||
|
||||
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const { userInfo, setUserInfo } = useUserStore((state) => state);
|
||||
|
||||
async function authCheck() {
|
||||
@@ -43,19 +42,19 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
setUserInfo(null);
|
||||
|
||||
const hostname = window.location.hostname;
|
||||
// const hostname = window.location.hostname;
|
||||
|
||||
// 개발 환경에서는 localhost 도메인 사용
|
||||
//if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
|
||||
// if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
|
||||
router.push("/"); // 개발시 홈으로 돌아가기
|
||||
|
||||
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
|
||||
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
|
||||
//if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
|
||||
// if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [pathname]);
|
||||
}, []);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# 공단 개발
|
||||
NEXT_PUBLIC_SITE_ID = WR
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
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_PROXY_HOST = https://devtiger.hasuon.or.kr
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.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_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
|
||||
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
|
||||
NEXT_PRIVATE_WR_ADDRESS_KEY = U01TXOFVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA=
|
||||
+4
-2
@@ -12,8 +12,10 @@ NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
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_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&layer=korean_map&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
#NEXT_PUBLIC_WR_SERVER_API_URL = http://192.168.1.222:8883/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
|
||||
NEXT_PUBLIC_FINDADRESS_URL = https://business.juso.go.kr/addrlink/addrLinkApi.do
|
||||
NEXT_PRIVATE_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
|
||||
|
||||
@@ -12,8 +12,9 @@ NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
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_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g&layer=korean_map&TileMatrix={z}&TileCol={x}&TileRow={y}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
|
||||
|
||||
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
|
||||
NEXT_PRIVATE_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
|
||||
|
||||
@@ -5,6 +5,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_PROXY_HOST = https://devtiger.hasuon.or.kr
|
||||
#NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
|
||||
@@ -12,8 +14,9 @@ NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
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_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC&layer=korean_map&TileMatrix={z}&TileCol={y}&TileRow={x}
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service
|
||||
NEXT_PUBLIC_NGII_URL = http://172.29.143.87
|
||||
NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x}
|
||||
|
||||
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
|
||||
NEXT_PRIVATE_WR_ADDRESS_KEY = U01TXOFVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA=
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* 관망도 API
|
||||
*/
|
||||
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map`
|
||||
const API_URL = `/sewerage-service/api/v1/map`
|
||||
//const API_URL = "http://con.mind-one.co.kr:11083/sewerage-service/api/v1/map";
|
||||
|
||||
export type LyrStngProps = {
|
||||
|
||||
@@ -30,7 +30,7 @@ export type LyrStngProps = {
|
||||
export const mapService = {
|
||||
//레이어 설정 조회
|
||||
getLyrStngs: async () => {
|
||||
const response = await fetch(`${DEV_URL_SN}/v1/map/lyrStngs/DM_NETWORK`, {
|
||||
const response = await fetch(`${DEV_URL_SN}/api/v1/map/lyrStngs/DM_NETWORK`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
"use client";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
|
||||
|
||||
return (
|
||||
<>{children}</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function HasuStatPage() {
|
||||
const [status, setStatus] = useState<string>("checking");
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false;
|
||||
|
||||
async function checkAndRedirect() {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 3000);
|
||||
|
||||
const res = await fetch(`/api/client-ip`, { signal: controller.signal });
|
||||
clearTimeout(timeout);
|
||||
|
||||
if (!res.ok) throw new Error("no-ip");
|
||||
const data = await res.json();
|
||||
const ip: string = data?.ip || "";
|
||||
if (didCancel) return;
|
||||
alert("Client IP:" + ip);
|
||||
|
||||
const is10 = /^10\./.test(ip);
|
||||
const is172 = /^172\./.test(ip);
|
||||
setStatus(is10||is172 ? "redirect-internal" : "redirect-root");
|
||||
|
||||
// Use location.replace so user can't go back to this page
|
||||
if (is10||is172) {
|
||||
// redirect to internal IP
|
||||
window.open('http://10.101.163.102:8888/cms/lay1/WS10000014/program.do', '_blank');
|
||||
} else {
|
||||
window.open('https://www.hasudoinfo.or.kr/cms/lay1/WS10000014/program.do', '_blank');
|
||||
}
|
||||
window.history.back();
|
||||
} catch {
|
||||
// If anything fails, fall back to root
|
||||
if (!didCancel) {
|
||||
setStatus("error-fallback");
|
||||
window.location.replace("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAndRedirect();
|
||||
|
||||
return () => {
|
||||
didCancel = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{padding:20,fontFamily:'Noto Sans KR, sans-serif'}}>
|
||||
{status === "checking" && <div>접속 IP 확인 중...</div>}
|
||||
{status === "redirect-internal" && <div>내부망으로 이동합니다...</div>}
|
||||
{status === "redirect-root" && <div>외부에서 접속하여 루트로 이동합니다...</div>}
|
||||
{status === "error-fallback" && (
|
||||
<div>
|
||||
문제가 발생하여 루트로 이동합니다. 이동하지 않으면 <Link href="/">여기</Link>를 클릭하세요.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
import {
|
||||
ACCESS_TOKEN,
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
REFRESH_TOKEN,
|
||||
} from "@/src/shared/config";
|
||||
|
||||
export async function POST() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete(ACCESS_TOKEN);
|
||||
cookieStore.delete(REFRESH_TOKEN);
|
||||
cookieStore.delete(AUTH_USER_ID);
|
||||
cookieStore.delete(CLAIM_NAME);
|
||||
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const headers = request.headers;
|
||||
// 1. x-forwarded-for 또는 x-real-ip에서 IP 추출
|
||||
let ip = headers.get('x-forwarded-for') || headers.get('x-real-ip') || '';
|
||||
|
||||
// IP가 있으면 첫 번째 IP 주소만 추출
|
||||
if (ip) {
|
||||
if (ip.includes(',')) {
|
||||
ip = ip.split(',')[0]?.trim()||'';
|
||||
} else {
|
||||
ip = ip.trim();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. IPv6 주소 정규화
|
||||
if (ip.startsWith('::ffff:')) {
|
||||
ip = ip.replace('::ffff:', '');
|
||||
}
|
||||
|
||||
// 4. localhost IPv6를 IPv4로 변환
|
||||
if (ip === '::1') {
|
||||
ip = '127.0.0.1';
|
||||
}
|
||||
|
||||
return NextResponse.json({ ip });
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 📄 Proxy Route
|
||||
* API 프록시 라우트
|
||||
*
|
||||
* - 서버 API로의 요청 프록시 처리
|
||||
* - 쿠키 기반 인증 토큰 및 리프레시 토큰 관리
|
||||
* - POST 및 PUT 요청 핸들링
|
||||
* - 사용자 인증 정보 검증 및 응답 처리
|
||||
* - 에러 핸들링 및 상태 코드 반환
|
||||
* - 사이트 ID 및 헤더 설정
|
||||
*/
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token";
|
||||
const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id";
|
||||
const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
|
||||
const REFRESH_TOKEN = process.env.NEXT_PUBLIC_REFRESH_TOKEN || "refresh-token";
|
||||
const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || "";
|
||||
const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "SN";
|
||||
|
||||
async function handler(
|
||||
request: Request,
|
||||
params: { url: string[] },
|
||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||
) {
|
||||
const cookieStore = await cookies();
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Site-Id": SITE_ID,
|
||||
};
|
||||
let body = {};
|
||||
const isRefreshHandler = params.url.includes("refresh");
|
||||
|
||||
// silent refresh
|
||||
if (isRefreshHandler) {
|
||||
const refreshToken = cookieStore.get(REFRESH_TOKEN);
|
||||
headers[CLAIM_NAME] = refreshToken?.value ?? "";
|
||||
|
||||
if (!headers[CLAIM_NAME]) {
|
||||
return NextResponse.json({ message: "Can't refresh" }, { status: 401 });
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!isRefreshHandler) {
|
||||
body = await request.json();
|
||||
}
|
||||
|
||||
const result = await fetch(`${SERVER_API_URL}/${params.url.join("/")}`, {
|
||||
method,
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
console.log("Invalid Credentials ");
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Credentials" },
|
||||
{ status: 401 },
|
||||
);
|
||||
}
|
||||
|
||||
const accessToken = result.headers.get(ACCESS_TOKEN);
|
||||
const refreshToken = result.headers.get(REFRESH_TOKEN);
|
||||
const userId = result.headers.get(AUTH_USER_ID);
|
||||
|
||||
if (accessToken && userId) {
|
||||
const response = NextResponse.json({
|
||||
[ACCESS_TOKEN]: accessToken,
|
||||
[AUTH_USER_ID]: userId,
|
||||
});
|
||||
|
||||
if (refreshToken) {
|
||||
cookieStore.set(REFRESH_TOKEN, refreshToken, {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid Credentials" },
|
||||
{ status: 401 },
|
||||
);
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ message: "Server Error", error },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
) {
|
||||
const params = await props.params;
|
||||
return handler(request, params, "POST");
|
||||
}
|
||||
|
||||
export async function PUT(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
) {
|
||||
const params = await props.params;
|
||||
return handler(request, params, "PUT");
|
||||
}
|
||||
@@ -30,9 +30,9 @@ export const baseReuseBuildingSchema = z.object({
|
||||
crgRdctAmt: z.number().default(0), // 안쓰는 값
|
||||
ruseFcltFlg: z.string().default(""),
|
||||
bdstUsgCd: z
|
||||
.number()
|
||||
.default(0)
|
||||
.refine((val) => val === -1 || val >= 1, {
|
||||
.string()
|
||||
.default('000')
|
||||
.refine((val) => val.trim().length > 0, {
|
||||
message: validationMessages.requiredSelect("건축물용도"),
|
||||
}),
|
||||
lawTrgtYn: z.string().default("Y"),
|
||||
|
||||
@@ -21,7 +21,7 @@ export const LOCAL_URL_WR = PROXY_HOST + `/api/v1`;
|
||||
export const DEV_URL_WR = '/reuse-service';
|
||||
export const DEV_URL_FO = '/operation-service';
|
||||
//export const DEV_URL_FO = SERVER_API_FO_URL;
|
||||
export const DEV_URL_SN = '/sewerage-service/api';
|
||||
export const DEV_URL_SN = '/sewerage-service';
|
||||
export const LOCAL_URL = PROXY_HOST;
|
||||
export const CS_URL = SERVER_API_CS_URL;
|
||||
export const CS_TUS_UPLOAD = SERVER_API_CS_TUS_URL;
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function RainRegForm({
|
||||
operMngCd: item?.operMngCd ?? "", // null → ""
|
||||
grntchBdstCertYr:
|
||||
typeof item?.grntchBdstCertYr === "string"
|
||||
? item?.grntchBdstCertYr
|
||||
? item?.grntchBdstCertYr.trim()
|
||||
: "", // null → ""
|
||||
bdstUsgCd: item?.bdstUsgCd ?? Number("-1"), // null → "-1"
|
||||
instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y"
|
||||
|
||||
+35
-9
@@ -13,6 +13,18 @@ const OPERATION_API_URL = process.env.NEXT_PUBLIC_FO_SERVER_API_URL || "";
|
||||
const BUSINESS_JUSO_API_URL = process.env.NEXT_PUBLIC_FINDADRESS_URL || "";
|
||||
const AdressKey = process.env.NEXT_PRIVATE_WR_ADDRESS_KEY || "";
|
||||
|
||||
/** 공통: URLSearchParams의 값을 decodeURIComponent 적용하여 querystring 생성 */
|
||||
function toDecodedQueryString(params: URLSearchParams): string {
|
||||
const entries: string[][] = Array.from(params.entries()).map(([k, v]) => {
|
||||
try {
|
||||
return [k, decodeURIComponent(v)] as string[];
|
||||
} catch {
|
||||
return [k, v] as string[];
|
||||
}
|
||||
});
|
||||
return new URLSearchParams(entries).toString();
|
||||
}
|
||||
|
||||
/** 공통: 요청 헤더에 쿠키 기반 인증 값 주입 */
|
||||
function buildAuthHeaders(req: NextRequest): Headers {
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
@@ -50,19 +62,22 @@ export function middleware(req: NextRequest) {
|
||||
if (pathname.startsWith("/cms-service")) {
|
||||
const newUrl = `${serverApiUrl}${pathname}`;
|
||||
console.log(`[Middleware] Rewriting from '/cms-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/attach-service")) {
|
||||
const newUrl = `${serverApiUrl}${pathname}`;
|
||||
console.log(`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/user-service")) {
|
||||
const newUrl = `${serverApiUrl}${pathname}`;
|
||||
console.log(`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/geoserver")) {
|
||||
@@ -103,20 +118,22 @@ export function middleware(req: NextRequest) {
|
||||
if (startYmd) url.searchParams.set("startYmd", startYmd);
|
||||
if (endYmd) url.searchParams.set("endYmd", endYmd);
|
||||
queryParams = url.searchParams.toString();
|
||||
newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
|
||||
newUrl = `${SEWERAGE_API_URL}/api/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
|
||||
}
|
||||
|
||||
//console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/sewerage-service")) {
|
||||
const queryParams = searchParams.toString();
|
||||
const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service/api", "")}${
|
||||
const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service", "")}${
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/sewerage-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/reuse-service")) {
|
||||
@@ -125,7 +142,8 @@ export function middleware(req: NextRequest) {
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/operation-service")) {
|
||||
@@ -134,7 +152,8 @@ export function middleware(req: NextRequest) {
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/operation-service' path to: ${newUrl}`);
|
||||
return rewriteWith(newUrl, req, true);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +173,12 @@ export function middleware(req: NextRequest) {
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/ngii-server")) {
|
||||
const decodedQuery = toDecodedQueryString(searchParams);
|
||||
const newUrl = `${process.env.NEXT_PUBLIC_NGII_URL}${pathname.replace("/ngii-server", "")}${decodedQuery ? `?${decodedQuery}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '${pathname}' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
return NextResponse.next();
|
||||
}
|
||||
@@ -169,6 +194,7 @@ export const config = {
|
||||
"/reuse-service/:path*",
|
||||
"/operation-service/:path*",
|
||||
"/bussiness-juso-service/:path*",
|
||||
"/ngii-server/:path*",
|
||||
"/"
|
||||
],
|
||||
};
|
||||
|
||||
@@ -5,6 +5,9 @@ const subDomain =
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
experimental: {
|
||||
proxyTimeout: 600000, // 10분 (밀리초 단위)
|
||||
},
|
||||
async rewrites() {
|
||||
return {
|
||||
beforeFiles: [
|
||||
@@ -33,6 +36,10 @@ const nextConfig: NextConfig = {
|
||||
source: "/operation-service/:path*",
|
||||
destination: `${subDomain}/operation-service/:path*`,
|
||||
},
|
||||
{
|
||||
source: "/ngii-server/:path*",
|
||||
destination: `${subDomain}/ngii-server/:path*`,
|
||||
},
|
||||
],
|
||||
fallback: [],
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { client } from "../../../shared/api";
|
||||
import type { IUserInfo } from "../../../shared/store";
|
||||
import { useUserStore } from "../../../shared/lib";
|
||||
@@ -10,11 +10,10 @@ import { getCookie } from "../../../shared/lib";
|
||||
import { LoginApi } from "../api/login-service";
|
||||
|
||||
|
||||
const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3000/auth/login"; // 로그인 페이지 URL
|
||||
// const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3000/auth/login"; // 로그인 페이지 URL
|
||||
|
||||
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const { userInfo, setUserInfo } = useUserStore((state) => state);
|
||||
|
||||
async function authCheck() {
|
||||
@@ -43,19 +42,19 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
setUserInfo(null);
|
||||
|
||||
const hostname = window.location.hostname;
|
||||
// const hostname = window.location.hostname;
|
||||
|
||||
// 개발 환경에서는 localhost 도메인 사용
|
||||
//if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
|
||||
// if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
|
||||
router.push("/"); // 개발시 홈으로 돌아가기
|
||||
|
||||
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
|
||||
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
|
||||
//if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
|
||||
// if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [pathname]);
|
||||
}, []);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
@@ -41,7 +41,8 @@ GisApp.GOOGLE_HYBRID_URL = `https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}&k
|
||||
GisApp.GOOGLE_3D_URL = `https://tile.googleapis.com/v1/3dtiles/root.json?key=${GisApp.GOOGLE_API_KEY}`;
|
||||
|
||||
// NGII 정보(배경지도)
|
||||
GisApp.NGII_WMTS_URL = process.env.NEXT_PUBLIC_NGII_URL;
|
||||
//GisApp.NGII_WMTS_URL = process.env.NEXT_PUBLIC_NGII_URL;
|
||||
GisApp.NGII_WMTS_URL = `/ngii-server/openapi/Gettile.do?apikey=${process.env.NEXT_PUBLIC_NGII_PARAM}`;
|
||||
|
||||
GisApp.EMAP_URL = '/emap/';
|
||||
GisApp.EMAP_SATELLITE_URL = '/emap/satellite/';
|
||||
@@ -149,8 +150,6 @@ GisApp.core.prototype = {
|
||||
const resolutions = [1044.48, 522.24, 261.12, 130.56, 65.28, 32.64, 16.32, 8.16, 4.08, 2.04, 1.02, 0.51, 0.255];
|
||||
const matrixIds = ["L06", "L07", "L08", "L09", "L10", "L11", "L12", "L13", "L14", "L15", "L16", "L17", "L18"];
|
||||
|
||||
|
||||
const templateUrl = process.env.NEXT_PUBLIC_NGII_URL;
|
||||
const tileGrid = new WMTSTileGrid({
|
||||
origin: getTopLeft(projection.getExtent()),
|
||||
resolutions: resolutions,
|
||||
@@ -168,25 +167,13 @@ GisApp.core.prototype = {
|
||||
matrixSet: 'EPSG:5179',
|
||||
format: 'image/png',
|
||||
style: 'korean',
|
||||
/*
|
||||
tileUrlFunction: (tileCoord) => {
|
||||
const [z, x, y] = tileCoord;
|
||||
const matrix = matrixIds[z];
|
||||
const replacedUrl = templateUrl
|
||||
.replace("{z}", matrix)
|
||||
.replace("{x}", x)
|
||||
.replace("{y}", y); // 여기서는 교환 안 함 — env 템플릿이 담당
|
||||
console.log('++++++',replacedUrl)
|
||||
return replacedUrl;
|
||||
},
|
||||
*/
|
||||
});
|
||||
|
||||
wmtsSource.setTileUrlFunction((tileCoord) => {
|
||||
const [z, x, y] = tileCoord;
|
||||
const matrix = matrixIds[z];
|
||||
console.log(templateUrl.replace("{z}", matrix).replace("{x}", x).replace("{y}", y));
|
||||
return templateUrl
|
||||
console.log(GisApp.NGII_WMTS_URL.replace("{z}", matrix).replace("{x}", x).replace("{y}", y));
|
||||
return GisApp.NGII_WMTS_URL
|
||||
.replace("{z}", matrix)
|
||||
.replace("{x}", x)
|
||||
.replace("{y}", y);
|
||||
|
||||
Generated
+1414
-1416
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user