From ee3ddce41d23b627e54b6ed29c9d7c0af92677d4 Mon Sep 17 00:00:00 2001 From: kiminchan Date: Mon, 29 Jun 2026 14:51:46 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A7=80=EB=B0=98=EC=B9=A8=ED=95=98=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EA=B4=80=EB=A1=9C=20=EC=9A=A9=EB=8F=84=20?= =?UTF-8?q?OGC011=20=EB=A7=A4=ED=95=91=20=EB=B0=8F=20=ED=91=9C=20=EB=84=88?= =?UTF-8?q?=EB=B9=84=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sinkhole/SinkholeDetailPanel.tsx | 77 +++++++++++++++++-- .../001-fe-SFR-010-010-지반침하정보-통합구현기록.md | 10 +++ 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/components/sinkhole/SinkholeDetailPanel.tsx b/apps/sn/app/(map-layout)/map/components/sinkhole/SinkholeDetailPanel.tsx index 806939365..a660d0c7e 100644 --- a/apps/sn/app/(map-layout)/map/components/sinkhole/SinkholeDetailPanel.tsx +++ b/apps/sn/app/(map-layout)/map/components/sinkhole/SinkholeDetailPanel.tsx @@ -1,8 +1,9 @@ "use client"; -import { useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Button } from "@common/components"; import { VerticalTable } from "@/components/ui/verticalTable"; +import { getCmsData } from "@/components/lib/api"; import type { SinkholeDetail, SinkholeNearbyPipe } from "./sinkholeTypes"; type Props = { @@ -13,6 +14,14 @@ type Props = { onSelectPipe: (pipe: SinkholeNearbyPipe) => void; }; +type PipeUseCodeItem = { + lwpoCd: string; + lwpoCdNm: string; +}; + +let pipeUseCodeCache: PipeUseCodeItem[] | null = null; +let pipeUseCodePromise: Promise | null = null; + const display = (value: unknown) => { const normalized = String(value ?? "").trim(); return normalized ? normalized : "-"; @@ -33,6 +42,31 @@ const parseElapsedYears = (value: unknown) => { const displayElapsedYears = (value: unknown) => displayNumber(value, "년"); +const normalizePipeUseCodes = (data: any): PipeUseCodeItem[] => { + if (!Array.isArray(data)) return []; + return data.map((item: any) => ({ + lwpoCd: String(item?.lwpoCd ?? "").trim(), + lwpoCdNm: String(item?.lwpoCdNm ?? "").trim(), + })); +}; + +const loadPipeUseCodes = async () => { + if (pipeUseCodeCache) return pipeUseCodeCache; + if (!pipeUseCodePromise) { + pipeUseCodePromise = getCmsData(`/api/v1/code/cache/OGC011/Y`) + .catch(() => getCmsData(`/api/v1/code/cache/OGC011`)) + .then((data) => { + const codes = normalizePipeUseCodes(data); + pipeUseCodeCache = codes; + return codes; + }) + .finally(() => { + pipeUseCodePromise = null; + }); + } + return pipeUseCodePromise; +}; + export default function SinkholeDetailPanel({ detail, nearbyPipes, @@ -40,7 +74,32 @@ export default function SinkholeDetailPanel({ onClose, onSelectPipe, }: Props) { + const [pipeUseCodeMap, setPipeUseCodeMap] = useState>(new Map()); const canShowNearby = String(detail.coordStatus ?? "").trim() === "SUCCESS"; + + useEffect(() => { + let cancelled = false; + + loadPipeUseCodes() + .then((codes) => { + if (cancelled) return; + setPipeUseCodeMap(new Map(codes.map((item) => [item.lwpoCd, item.lwpoCdNm]))); + }) + .catch((error) => { + console.error("Failed to load OGC011 pipe use codes:", error); + }); + + return () => { + cancelled = true; + }; + }, []); + + const getPipeUseName = (pipe: SinkholeNearbyPipe) => { + const rawCode = String(pipe.pipeTypeCd ?? pipe.pipeTypeName ?? "").trim(); + if (!rawCode) return "-"; + return pipeUseCodeMap.get(rawCode) ?? rawCode; + }; + const nearbyPipeElapsedSummary = useMemo(() => { const elapsedYears = nearbyPipes .map((pipe) => parseElapsedYears(pipe.elapsedYears)) @@ -56,6 +115,7 @@ export default function SinkholeDetailPanel({ return { average, oldest }; }, [nearbyPipes]); + const summaryTableData = useMemo( () => [ { @@ -157,10 +217,11 @@ export default function SinkholeDetailPanel({
- - - - + + + + + @@ -170,6 +231,9 @@ export default function SinkholeDetailPanel({ + @@ -191,6 +255,9 @@ export default function SinkholeDetailPanel({ + diff --git a/apps/sn/docs/작업내용/SFR-010-010-지반침하정보/001-fe-SFR-010-010-지반침하정보-통합구현기록.md b/apps/sn/docs/작업내용/SFR-010-010-지반침하정보/001-fe-SFR-010-010-지반침하정보-통합구현기록.md index 4e9486c84..c2eb16288 100644 --- a/apps/sn/docs/작업내용/SFR-010-010-지반침하정보/001-fe-SFR-010-010-지반침하정보-통합구현기록.md +++ b/apps/sn/docs/작업내용/SFR-010-010-지반침하정보/001-fe-SFR-010-010-지반침하정보-통합구현기록.md @@ -370,3 +370,13 @@ - `map/page.tsx`는 기존 기능이 많아 무리하게 누적하면 회귀 위험이 크다. - 원천 데이터에 없는 컬럼을 화면은 요구하고 있어, API/FE 표시 정책이 늦게 확정되면 구현이 되돌아갈 수 있다. - 좌표 없는 사고건과 좌표 실패 사고건은 UI와 QA 시나리오가 달라 예외 흐름이 많다. + +### 4.44 2026-06-29 지반침하 상세 전용 OGC011 공통코드 매핑으로 범위 제한 + +- 지반침하 상세의 반경 내 관로 `용도`만 `OGC011` 공통코드로 한글화하도록 범위를 다시 좁혔다. +- 초기 보완에서는 `searchCmmnCd` 공통 헬퍼를 확장했지만, 다른 기능으로 영향 범위가 번질 수 있어 공통 헬퍼 변경은 되돌렸다. +- 대신 `SinkholeDetailPanel.tsx` 내부에서만 `getCmsData('/api/v1/code/cache/OGC011/Y')`를 우선 조회하고, 실패 시 `OGC011` 전체 조회로 fallback 하도록 로컬 캐시 로더를 추가했다. +- 이로써 현재 `sn`에서 공통코드 확장 영향은 지반침하 상세 패널 내부에만 한정되고, 기존 다른 화면의 공통코드/하드코딩 코드표 흐름은 건드리지 않는다. +- 표 컬럼 폭도 함께 조정해 `관로 ID`는 소폭 줄이고 `용도`는 한 줄로 보이도록 미세 보정했다. +- 변경 파일은 `FE_APP_ROOT/app/(map-layout)/map/components/sinkhole/SinkholeDetailPanel.tsx`, `FE_APP_ROOT/app/components/lib/common/apiHelpers.ts` 2개이며, 공통 헬퍼는 원래 계약으로 복구했다. +- BE API, DTO, DB 변경은 없다. \ No newline at end of file
관로 ID + 용도 + 경과년도 {display(pipe.pipeId)} + {getPipeUseName(pipe)} + {displayElapsedYears(pipe.elapsedYears)}