From 31ce13397e9a185759a230a7f0412cd1780f4b61 Mon Sep 17 00:00:00 2001 From: kiminchan Date: Wed, 6 May 2026 14:42:21 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B4=80=EB=A1=9C=EB=B6=84=EC=84=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/agedPipe/AgedPipePopupPage.tsx | 10 +- .../analysisMenu/AnalysisPopupMenu.tsx | 52 ++ .../PipeAnalysisDetailPopupPage.tsx | 338 ++++++++++ .../pipeAnalysis/PipeAnalysisPopupPage.tsx | 526 +++++++++++++++ .../pipeAnalysis/pipeAnalysisUtils.ts | 628 ++++++++++++++++++ apps/sn/app/(map-layout)/map/page.tsx | 49 +- .../windowPopup/model/popupDefinitions.ts | 42 ++ apps/sn/src/features/windowPopup/registry.tsx | 58 ++ .../ui/FeaturePlaceholderPopupContent.tsx | 25 + .../ui/PipeAnalysisDetailPopupContent.tsx | 10 + .../ui/PipeAnalysisPopupContent.tsx | 10 + .../src/ui/excel/excelStyle.tsx | 14 +- .../src/ui/excel/index.tsx | 6 +- .../business_components/src/ui/map/Gis.js | 2 +- .../src/ui/table/index.tsx | 2 +- 15 files changed, 1759 insertions(+), 13 deletions(-) create mode 100644 apps/sn/app/(map-layout)/map/components/analysisMenu/AnalysisPopupMenu.tsx create mode 100644 apps/sn/app/(map-layout)/map/components/pipeAnalysis/PipeAnalysisDetailPopupPage.tsx create mode 100644 apps/sn/app/(map-layout)/map/components/pipeAnalysis/PipeAnalysisPopupPage.tsx create mode 100644 apps/sn/app/(map-layout)/map/components/pipeAnalysis/pipeAnalysisUtils.ts create mode 100644 apps/sn/src/features/windowPopup/ui/FeaturePlaceholderPopupContent.tsx create mode 100644 apps/sn/src/features/windowPopup/ui/PipeAnalysisDetailPopupContent.tsx create mode 100644 apps/sn/src/features/windowPopup/ui/PipeAnalysisPopupContent.tsx diff --git a/apps/sn/app/(map-layout)/map/components/agedPipe/AgedPipePopupPage.tsx b/apps/sn/app/(map-layout)/map/components/agedPipe/AgedPipePopupPage.tsx index efea0197c..3626054c7 100644 --- a/apps/sn/app/(map-layout)/map/components/agedPipe/AgedPipePopupPage.tsx +++ b/apps/sn/app/(map-layout)/map/components/agedPipe/AgedPipePopupPage.tsx @@ -203,8 +203,8 @@ export default function AgedPipePopupPage() {
-
-
) : null} + ; export type WindowPopupKey = keyof typeof windowPopupDefinitions; diff --git a/apps/sn/src/features/windowPopup/registry.tsx b/apps/sn/src/features/windowPopup/registry.tsx index 7343e26b7..c76d9064f 100644 --- a/apps/sn/src/features/windowPopup/registry.tsx +++ b/apps/sn/src/features/windowPopup/registry.tsx @@ -11,6 +11,36 @@ import ReportFilesPopupContent from "./ui/ReportFilesPopupContent"; import ReportTabPopupContent from "./ui/ReportTabPopupContent"; import SearchModalPopupContent from "./ui/SearchModalPopupContent"; import SscDetailPopupContent from "./ui/SscDetailPopupContent"; +import type { WindowPopupContentProps } from "./model/types"; +import FeaturePlaceholderPopupContent from "./ui/FeaturePlaceholderPopupContent"; +import PipeAnalysisPopupContent from "./ui/PipeAnalysisPopupContent"; +import PipeAnalysisDetailPopupContent from "./ui/PipeAnalysisDetailPopupContent"; + +const FloodPredictionMapPopupContent = (_props: WindowPopupContentProps) => ( + +); + +const FloodHistoryPopupContent = (_props: WindowPopupContentProps) => ( + +); + +const GisEditPopupContent = (_props: WindowPopupContentProps) => ( + +); + +const GisManagementPopupContent = (_props: WindowPopupContentProps) => ( + +); + +const FlowRiskPopupContent = (_props: WindowPopupContentProps) => ( + +); export const windowPopupRegistry = { oldPpUpload: { @@ -57,4 +87,32 @@ export const windowPopupRegistry = { ...windowPopupDefinitions.agedPipePopup, component: AgedPipePopupContent, }, + pipeAnalysisPopup: { + ...windowPopupDefinitions.pipeAnalysisPopup, + component: PipeAnalysisPopupContent, + }, + pipeAnalysisDetailPopup: { + ...windowPopupDefinitions.pipeAnalysisDetailPopup, + component: PipeAnalysisDetailPopupContent, + }, + floodPredictionMapPopup: { + ...windowPopupDefinitions.floodPredictionMapPopup, + component: FloodPredictionMapPopupContent, + }, + floodHistoryPopup: { + ...windowPopupDefinitions.floodHistoryPopup, + component: FloodHistoryPopupContent, + }, + gisEditPopup: { + ...windowPopupDefinitions.gisEditPopup, + component: GisEditPopupContent, + }, + gisManagementPopup: { + ...windowPopupDefinitions.gisManagementPopup, + component: GisManagementPopupContent, + }, + flowRiskPopup: { + ...windowPopupDefinitions.flowRiskPopup, + component: FlowRiskPopupContent, + }, } as const satisfies Record; diff --git a/apps/sn/src/features/windowPopup/ui/FeaturePlaceholderPopupContent.tsx b/apps/sn/src/features/windowPopup/ui/FeaturePlaceholderPopupContent.tsx new file mode 100644 index 000000000..e05b3b6b5 --- /dev/null +++ b/apps/sn/src/features/windowPopup/ui/FeaturePlaceholderPopupContent.tsx @@ -0,0 +1,25 @@ +type Props = { + title: string; +}; + +export default function FeaturePlaceholderPopupContent({ title }: Props) { + return ( +
+
+

{title}

+
+ +
+
+

{title}

+

+ 현재는 팝업 창 구조만 우선 연결했습니다. +

+

+ 상세 기능은 추후 단계에서 구현될 예정입니다. +

+
+
+
+ ); +} diff --git a/apps/sn/src/features/windowPopup/ui/PipeAnalysisDetailPopupContent.tsx b/apps/sn/src/features/windowPopup/ui/PipeAnalysisDetailPopupContent.tsx new file mode 100644 index 000000000..c7d6f1f2a --- /dev/null +++ b/apps/sn/src/features/windowPopup/ui/PipeAnalysisDetailPopupContent.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import PipeAnalysisDetailPopupPage from "@/app/(map-layout)/map/components/pipeAnalysis/PipeAnalysisDetailPopupPage"; + +export default function PipeAnalysisDetailPopupContent() { + return ( + + + + ); +} diff --git a/apps/sn/src/features/windowPopup/ui/PipeAnalysisPopupContent.tsx b/apps/sn/src/features/windowPopup/ui/PipeAnalysisPopupContent.tsx new file mode 100644 index 000000000..215b559a9 --- /dev/null +++ b/apps/sn/src/features/windowPopup/ui/PipeAnalysisPopupContent.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react"; +import PipeAnalysisPopupPage from "@/app/(map-layout)/map/components/pipeAnalysis/PipeAnalysisPopupPage"; + +export default function PipeAnalysisPopupContent() { + return ( + + + + ); +} diff --git a/packages/common/business_components/src/ui/excel/excelStyle.tsx b/packages/common/business_components/src/ui/excel/excelStyle.tsx index 221e1387c..1a654775c 100644 --- a/packages/common/business_components/src/ui/excel/excelStyle.tsx +++ b/packages/common/business_components/src/ui/excel/excelStyle.tsx @@ -70,7 +70,8 @@ export const excelStyleWithKoreanHeaders = async ( range: string = "A1:V3", fileNm: string, headerMapping: { [key: string]: string }, - sampleData: any + sampleData: any, + mergeRanges?: string[] ) => { const workbook = await XlsxPopulate.Workbook.fromData(data); const sheet = workbook.activeSheet(); @@ -83,7 +84,7 @@ export const excelStyleWithKoreanHeaders = async ( const englishHeaders = Object.keys(sampleData); englishHeaders.forEach((englishHeader, index) => { const koreanHeader = headerMapping[englishHeader] || englishHeader; - const cellAddress = String.fromCharCode(65 + index) + '1'; // A1, B1, C1, ... + const cellAddress = `${getExcelColumnLetter(index + 1)}1`; sheet.cell(cellAddress).value(koreanHeader); }); @@ -98,13 +99,20 @@ export const excelStyleWithKoreanHeaders = async ( const numRows = sheet.usedRange()?.endCell()?.rowNumber() || 1; if (numRows > 1) { - const dataRange = sheet.range(`A1:${String.fromCharCode(65 + numCols - 1)}${numRows}`); + const lastColLetter = getExcelColumnLetter(numCols); + const dataRange = sheet.range(`A1:${lastColLetter}${numRows}`); dataRange?.style((styleQ) => { styleQ.verticalAlignment("center"); styleQ.borderEach({ style: "thin", color: { rgb: "CCCCCC" } }); }); } + if (mergeRanges && mergeRanges.length > 0) { + mergeRanges.forEach((mergeRange) => { + sheet.range(mergeRange).merged(true); + }); + } + // 4. 파일 다운로드 await makeExcelFile(workbook, fileNm); }; diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index 54e4fe6a8..ef753f976 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -407,6 +407,7 @@ type ExcelDownloadWithHeaderProps = { sheetNameArray: string[]; headerRange?: string; headerMapping: { [key: string]: string }; + mergeRanges?: string[]; } export const downloadExcelWithKoreanHeaders = async ({ @@ -414,7 +415,8 @@ export const downloadExcelWithKoreanHeaders = async ({ fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange = 'A1:V3', - headerMapping + headerMapping, + mergeRanges, }: ExcelDownloadWithHeaderProps) => { const dataArray = Array.isArray(data) ? data : [data]; @@ -432,5 +434,5 @@ export const downloadExcelWithKoreanHeaders = async ({ const buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }); // 3. 헤더만 한글로 교체하는 커스텀 스타일 함수 호출 - await excelStyleWithKoreanHeaders(buffer, headerRange, fileName, headerMapping, dataArray[0]); + await excelStyleWithKoreanHeaders(buffer, headerRange, fileName, headerMapping, dataArray[0], mergeRanges); }; diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js index d7bbf3fa5..d8076269f 100644 --- a/packages/common/business_components/src/ui/map/Gis.js +++ b/packages/common/business_components/src/ui/map/Gis.js @@ -343,7 +343,7 @@ function Gis({ {isSearch && ( -
+