From f1601a7f99ebf56cd1758e64fe4287119e51752b Mon Sep 17 00:00:00 2001 From: yschoi Date: Thu, 22 May 2025 09:44:37 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8F=84=EC=8B=9C=EC=B9=A8=EC=88=98=20?= =?UTF-8?q?=EC=98=88=EB=B0=A9=EC=82=AC=EC=97=85=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/attachment/attachment-interface.tsx | 74 +++++++++++++ .../lib/api/attachment/attachment-service.tsx | 42 ++++++++ .../components/lib/utils/fileUploadUtil.tsx | 9 +- apps/sn/app/components/ui/fileUploadForm.tsx | 100 ++++++++++++------ apps/sn/app/oper/floodPre/page.tsx | 2 +- apps/sn/app/styles/components.css | 4 + apps/sn/middleware.ts | 54 ++++++++++ apps/sn/next.config.ts | 26 ++--- .../src/ui/main_content_div/index.tsx | 2 +- .../src/ui/map/lib/gis.core.js | 6 +- 10 files changed, 265 insertions(+), 54 deletions(-) create mode 100644 apps/sn/app/components/lib/api/attachment/attachment-interface.tsx create mode 100644 apps/sn/app/components/lib/api/attachment/attachment-service.tsx create mode 100644 apps/sn/middleware.ts diff --git a/apps/sn/app/components/lib/api/attachment/attachment-interface.tsx b/apps/sn/app/components/lib/api/attachment/attachment-interface.tsx new file mode 100644 index 000000000..351e76fcb --- /dev/null +++ b/apps/sn/app/components/lib/api/attachment/attachment-interface.tsx @@ -0,0 +1,74 @@ +import type { AxiosResponse } from "axios"; + +interface SortConfig { + empty: boolean; + sorted: boolean; + unsorted: boolean; +} + +interface PageableConfig { + sort: SortConfig; + offset: number; + pageNumber: number; + pageSize: number; + paged: boolean; + unpaged: boolean; +} + +export interface PageableList { + content: T[]; + pageable: PageableConfig; + sort: SortConfig; + totalPages: number; + totalElements: number; + number: number; + numberOfElements: number; + size: number; + first: boolean; + last: boolean; + empty: boolean; +} + +export interface PageableParams { + page?: number; + size?: number; + sort?: string[]; +} + +export interface AttachmentParams extends PageableParams { + keywordType?: string; + keyword?: string; + atflCd?: string; + atflSn?: number; + atflId?: string; + orgnlFileNm?: string; + atflFlieSz?: number; + atflType?: string; + dwnldNocs?: number; + delYn?: string; + lnkgDmnId?: string; + lnkgDmnNm?: string; +} + +export interface Attachment { + atflCd: string; + atflSn: number; + atflId: string; + physFileNm: string; + orgnlFileNm: string; + atflFlieSz: number; + atflType: string; + dwnldNocs: number; + delYn: string; + lnkgDmnId: string; + lnkgDmnNm: string; + regDt: string; +} + +export type AttachmentList = PageableList; + +export interface AttachmentService { + getAttachmentsList: (params: AttachmentParams) => Promise; + getAttachmentsInfo: (atflCd: string) => Promise; + deleteAttachmentByAtflCd: (atflCd: string) => Promise; +} diff --git a/apps/sn/app/components/lib/api/attachment/attachment-service.tsx b/apps/sn/app/components/lib/api/attachment/attachment-service.tsx new file mode 100644 index 000000000..36390c0fb --- /dev/null +++ b/apps/sn/app/components/lib/api/attachment/attachment-service.tsx @@ -0,0 +1,42 @@ +import type { AxiosResponse } from "axios"; +import type { + Attachment, + AttachmentList, + AttachmentParams, + AttachmentService, +} from "../attachment/attachment-interface"; +import { getData, deleteData } from "../index"; + +export const ENDPOINT = { + ATTACH_SERVICE: { + TUS_UPLOAD: "/attach-service/api/v1/tus/upload", + EDITOR_UPLOAD: "/attach-service/api/v1/upload/editor", + IMAGES: "/attach-service/api/v1/images", + MOVIE_THUMBNAIL: "/attach-service/api/v1/movie/thumbnail", + ATTACHMENTS: "/attach-service/api/v1/atfl/attachments", + DOWNLOAD: "/attach-service/api/v1/atflcd/download", + STREAM_VIDEO: "/attach-service/api/v1/stream/video", + }, +}; + +export class AttachmentApiService implements AttachmentService { + public async getAttachmentsList( + params: AttachmentParams, + ): Promise { + const response = await getData(`${ENDPOINT.ATTACH_SERVICE.ATTACHMENTS}`); + return response.data; + } + + public async getAttachmentsInfo(atflCd: string): Promise { + const response = await getData( + `${ENDPOINT.ATTACH_SERVICE.ATTACHMENTS}/${atflCd}`, + ); + return response.data; + } + + public async deleteAttachmentByAtflCd(atflCd: string): Promise { + await deleteData(`${ENDPOINT.ATTACH_SERVICE.ATTACHMENTS}/atflCd/${atflCd}`); + } +} + +export const AttachmentApi = new AttachmentApiService(); diff --git a/apps/sn/app/components/lib/utils/fileUploadUtil.tsx b/apps/sn/app/components/lib/utils/fileUploadUtil.tsx index 4685dd336..c2d380b54 100644 --- a/apps/sn/app/components/lib/utils/fileUploadUtil.tsx +++ b/apps/sn/app/components/lib/utils/fileUploadUtil.tsx @@ -1,10 +1,9 @@ import { Upload, type HttpResponse } from "tus-js-client"; import { getCookie, setCookie } from "@utils"; +import { ENDPOINT } from "../api/attachment/attachment-service"; -const AUTH_USER_ID = process.env.AUTH_USER_ID || ''; -const CLAIM_NAME = process.env.CLAIM_NAME || ''; -const BASE_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || ''; -const END_URL = `${BASE_URL}/attach-service/api/v1/tus/upload`; +const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; +const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; type UploadOptions = { handleUploadStart?: (upload: Upload) => void; @@ -24,7 +23,7 @@ export const handleUpload = (files: FileList, options?: UploadOptions) => { }; const upload = new Upload(file, { - endpoint: END_URL, + endpoint: ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD, chunkSize: 10 * 1024 * 1024, headers: { [CLAIM_NAME]: getCookie(CLAIM_NAME) ?? "", diff --git a/apps/sn/app/components/ui/fileUploadForm.tsx b/apps/sn/app/components/ui/fileUploadForm.tsx index 3c57bb812..d05b73eaf 100644 --- a/apps/sn/app/components/ui/fileUploadForm.tsx +++ b/apps/sn/app/components/ui/fileUploadForm.tsx @@ -1,13 +1,26 @@ "use client" import { FileUpload, SelectBox } from '@common/business_components/ui'; - import { Button, Input } from '@common/components/ui'; import React, { useState } from 'react' +import type { HttpResponse, Upload } from "tus-js-client"; +import { FileUploader } from "@common/components"; +import { handleUpload } from "@utils"; const FileUploadForm = ({ title }: { title: string }) => { const [files, setFiles] = useState(null); const [selectedYear, setSelectedYear] = useState(''); const [selectedQuarter, setSelectedQuarter] = useState(''); + const [upload, setUpload] = useState(null); + + const handleUploadResponse = (file: File) => async (res: HttpResponse) => { + const fileInfo = res.getHeader("X-File-Info"); + if (!fileInfo) return; + + const { atflCd, atflId } = JSON.parse(fileInfo) ?? {}; + const orgnlFileNm = file.name; + + console.log(atflCd, atflId, orgnlFileNm); + }; // 현재 년도부터 10년 전까지의 년도 옵션 생성 const yearOptions = Array.from({ length: 10 }, (_, i) => { @@ -23,38 +36,63 @@ const FileUploadForm = ({ title }: { title: string }) => {
- setSelectedYear(String(value))} - /> setSelectedQuarter(String(value))} - /> -
-
-
- -
- + customPreview={<>} + /> +
+ +
diff --git a/apps/sn/app/oper/floodPre/page.tsx b/apps/sn/app/oper/floodPre/page.tsx index 62ecd15b8..99b17d1bd 100644 --- a/apps/sn/app/oper/floodPre/page.tsx +++ b/apps/sn/app/oper/floodPre/page.tsx @@ -15,7 +15,7 @@ const Page = () => { const handleDownload = async () => { try { - const response = await fetch('/sn/attach-service/api/v1/download/6066b08c-2a55-438c-b8ff-2aed9739a0c6', { + const response = await fetch('/attach-service/api/v1/download/0dda8ecd-63dd-4e90-bbe1-08d6fcd08c9a', { method: 'GET', }); diff --git a/apps/sn/app/styles/components.css b/apps/sn/app/styles/components.css index b67efb8f0..4dc30bafd 100644 --- a/apps/sn/app/styles/components.css +++ b/apps/sn/app/styles/components.css @@ -22,4 +22,8 @@ @apply border-b-[#3f4042]; } } + + input[type="file"] { + @apply w-[200px] h-[40px] px-3 py-2 border border-[#d1d5db] rounded-md bg-white text-sm cursor-pointer; + } } diff --git a/apps/sn/middleware.ts b/apps/sn/middleware.ts new file mode 100644 index 000000000..be1d093ae --- /dev/null +++ b/apps/sn/middleware.ts @@ -0,0 +1,54 @@ +import { NextRequest, NextResponse } from "next/server"; + +const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; +const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; +const serverApiUrl = + process.env.NEXT_PUBLIC_SERVER_API_URL || "http://localhost:3002"; +const geoServerUrl = process.env.NEXT_PUBLIC_GEOSERVER_URL || ""; + +export function middleware(req: NextRequest) { + console.log("Middleware 진입:", req.nextUrl.pathname); + const pathname = req.nextUrl.pathname; + const searchParams = req.nextUrl.searchParams; + + if (pathname.startsWith("/server")) { + const queryParams = searchParams.toString(); + const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${ + queryParams ? `?${queryParams}` : "" + }`; + console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`); + return NextResponse.rewrite(new URL(newUrl)); + } + + if (pathname.startsWith("/geoserver")) { + const queryParams = searchParams.toString(); + const newUrl = `${geoServerUrl}${pathname.replace("/geoserver", "")}${ + queryParams ? `?${queryParams}` : "" + }`; + console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); + return NextResponse.rewrite(new URL(newUrl)); + } + + if (pathname.startsWith("/attach-service")) { + const requestHeaders = new Headers(req.headers); + const token = req.cookies.get(CLAIM_NAME)?.value; + const userId = req.cookies.get(AUTH_USER_ID)?.value; + const newUrl = `${serverApiUrl}${pathname}`; + + if (token) requestHeaders.set(CLAIM_NAME, token); + if (userId) requestHeaders.set(AUTH_USER_ID, userId); + + console.log( + `[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`, + ); + return NextResponse.rewrite(new URL(newUrl), { + headers: requestHeaders, + }); + } + + return NextResponse.next(); +} + +export const config = { + matcher: ["/server/:path*","/geoserver/:path*", "/attach-service/:path*"], +}; diff --git a/apps/sn/next.config.ts b/apps/sn/next.config.ts index 12162c0a0..f149ae9b8 100644 --- a/apps/sn/next.config.ts +++ b/apps/sn/next.config.ts @@ -6,7 +6,7 @@ const cnServerUrl = process.env.NEXT_PUBLIC_SERVER_API_URL?.replace(/\/$/, '') ? const nextConfig: NextConfig = { - basePath: "/sn", + // basePath: "/sn", typescript: { ignoreBuildErrors: true, // 이 줄 추가 }, @@ -44,18 +44,18 @@ const nextConfig: NextConfig = { return config; }, - async rewrites() { - return [ - { - source: '/geoserver/:hasudo*', - destination: `${geoServerUrl}/:hasudo*`, - }, - { - source: '/attach-service/:path*', - destination: `${cnServerUrl}/attach-service/:path*`, - }, - ]; - }, + // async rewrites() { + // return [ + // { + // source: '/geoserver/:hasudo*', + // destination: `${geoServerUrl}/:hasudo*`, + // }, + // { + // source: '/attach-service/:path*', + // destination: `${cnServerUrl}/attach-service/:path*`, + // }, + // ]; + // }, }; export default nextConfig; diff --git a/packages/common/business_components/src/ui/main_content_div/index.tsx b/packages/common/business_components/src/ui/main_content_div/index.tsx index 1432f472e..ea95cd2ab 100644 --- a/packages/common/business_components/src/ui/main_content_div/index.tsx +++ b/packages/common/business_components/src/ui/main_content_div/index.tsx @@ -2,7 +2,7 @@ export default function MainDiv(props: {children: React.ReactNode}) { return ( -
+
{props.children}
) diff --git a/packages/common/business_components/src/ui/map/lib/gis.core.js b/packages/common/business_components/src/ui/map/lib/gis.core.js index faebb90d3..4085e2907 100644 --- a/packages/common/business_components/src/ui/map/lib/gis.core.js +++ b/packages/common/business_components/src/ui/map/lib/gis.core.js @@ -28,8 +28,8 @@ GisApp.layerInfos = []; //기본정보 //GisApp.GEOSERVER_URL = 'http://rsone.iptime.org:10010/geoserver/hasudo/ows'; //GisApp.GEOSERVER_WMS_URL = 'http://rsone.iptime.org:10010/geoserver/hasudo/wms'; -GisApp.GEOSERVER_URL = '/sn/geoserver/hasudo/ows'; -GisApp.GEOSERVER_WMS_URL = '/sn/geoserver/hasudo/wms'; +GisApp.GEOSERVER_URL = '/geoserver/hasudo/ows'; +GisApp.GEOSERVER_WMS_URL = '/geoserver/hasudo/wms'; //맵 정보 GisApp.EMAP_URL = '/emap/'; @@ -47,7 +47,7 @@ GisApp.BASE_MAP_TYPES = []; GisApp.FROM_PROJ = 'EPSG:4326'; GisApp.TO_PROJ = 'EPSG:3857'; GisApp.TO_DATA_PROJ = 'EPSG:4326'; -GisApp.CONTEXT_LAYER_PATH = '/sn/images/map/layericon/'; +GisApp.CONTEXT_LAYER_PATH = '/images/map/layericon/'; GisApp.layerCode = {}; GisApp.hlLayerId = 'LightFeatureList'; GisApp.hLayerId = 'highLightFeature';