diff --git a/apps/cm/src/pages/dashboard/api/fo-service.ts b/apps/cm/src/pages/dashboard/api/fo-service.ts index d85ae2d6d..9e9b3e02c 100644 --- a/apps/cm/src/pages/dashboard/api/fo-service.ts +++ b/apps/cm/src/pages/dashboard/api/fo-service.ts @@ -6,6 +6,7 @@ import { ENDPOINT } from "@/shared/config"; import type { OperWqltContent, OperFcltContent, ReuseStatusContent, OperationService } from "../model/fo-interface"; import type { mapOperFcltItem, mapOperFcltType } from "../model/fo-interface"; +import type { ReuseMapContent, mapReuseMapType } from "../model/fo-interface"; // 기준년도 조회 export type YearState = { @@ -52,34 +53,35 @@ export type OperFcltStateActions = { setOperFcltStatus: (operFcltStatus: OperFcltContent[] | null) => void; }; export type OperFcltStore = OperFcltState & OperFcltStateActions; -const initialOperFclt: OperFcltContent[]= [ - { - "cnt": 710, - "fctCpc": 2911609.0, - "rvbsn": "금강", - "gubun": "R" - }, - { - "cnt": 1032, - "fctCpc": 7506047.0, - "rvbsn": "낙동강", - "gubun": "R" - }, - { - "cnt": 1261, - "fctCpc": 2061610.0, - "rvbsn": "영산강", - "gubun": "R" - }, - { - "cnt": 983, - "fctCpc": 1.3229809E7, - "rvbsn": "한강", - "gubun": "R" - } - ]; +// const initialOperFclt: OperFcltContent[]= [ +// { +// "cnt": 710, +// "fctCpc": 2911609.0, +// "rvbsn": "금강", +// "gubun": "R" +// }, +// { +// "cnt": 1032, +// "fctCpc": 7506047.0, +// "rvbsn": "낙동강", +// "gubun": "R" +// }, +// { +// "cnt": 1261, +// "fctCpc": 2061610.0, +// "rvbsn": "영산강", +// "gubun": "R" +// }, +// { +// "cnt": 983, +// "fctCpc": 1.3229809E7, +// "rvbsn": "한강", +// "gubun": "R" +// } +// ]; export const defaultInitOperFcltState: OperFcltState = { - operFcltStatus: initialOperFclt, + // operFcltStatus: initialOperFclt, + operFcltStatus: null, }; export const createOperFcltStore = (initState: OperFcltState = defaultInitOperFcltState) => createStore()((set) => ({ @@ -106,6 +108,24 @@ export const useMapOperFcltStore = create((set) => ({ setMapOperFclt: (newMapOperFclt) => set({ mapOperFclt: newMapOperFclt }), })); +export const initailMapReuseMapData: mapReuseMapType = { + colTitle: {reuseAmnt: "하수재이용량",cnt : "시설수" }, //헤더 영역 + data: [ + {name: "금강", reuseAmnt: 17099, cnt: 3181}, + {name: "한강", reuseAmnt: 17099, cnt: 3181}, + {name: "낙동강", reuseAmnt: 14745, cnt: 3100}, + {name: "영산강", reuseAmnt: 5073, cnt: 1662}, + ] +}; +type mapReuseMapState = { + mapData: ReuseMapContent[]; + setMapData: (mapData: ReuseMapContent[]) => void; +}; +export const useMapReuseMapStore = create((set) => ({ + mapData: initailMapReuseMapData.data, + setMapData: (newMapOperFclt) => set({ mapData: newMapOperFclt }), +})); + /** * OperFcltContent[]를 지도 팝업 데이터 형태인 mapOperFcltItem[]으로 변환합니다. * @param data API 응답 데이터 @@ -196,6 +216,45 @@ export const createReuseStore = (initState: ReuseState = defaultInitReuseState) })); export const reuseStore = createReuseStore(); +/** + * 두 객체 또는 배열의 깊은 비교를 수행합니다. + * @param obj1 비교할 첫 번째 객체 + * @param obj2 비교할 두 번째 객체 + * @returns 두 객체의 내용이 같으면 true, 그렇지 않으면 false + */ +// function deepEqual(obj1: any, obj2: any): boolean { +// if (obj1 === obj2) { +// return true; +// } + +// if (obj1 == null || typeof obj1 !== 'object' || obj2 == null || typeof obj2 !== 'object') { +// return false; +// } + +// const keys1 = Object.keys(obj1); +// const keys2 = Object.keys(obj2); + +// if (keys1.length !== keys2.length) { +// return false; +// } + +// for (const key of keys1) { +// if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) { +// return false; +// } +// } + +// // 배열인 경우 순서와 내용이 모두 동일한지 확인 +// if (Array.isArray(obj1) && Array.isArray(obj2)) { +// if (obj1.length !== obj2.length) return false; +// for (let i = 0; i < obj1.length; i++) { +// if (!deepEqual(obj1[i], obj2[i])) return false; +// } +// } + +// return true; +// } + export class OperationApiService implements OperationService { @@ -248,7 +307,7 @@ export class OperationApiService implements OperationService { return list; } - // 수계별 시설운영 개소수 및 가동률 + // 수계별 유입ㆍ방류수질 분석 public async getDashOperWqlt(year: string): Promise { const response = await client.get<{ @@ -293,7 +352,25 @@ export class OperationApiService implements OperationService { return list; } - + // 수계별 하수재이용량, 시설수 + public async getReuseMap(year: string): Promise { + + const response = await client.get<{ + status: number; + data: ReuseMapContent[]; + count: number; + }>(ENDPOINT.OPERATION_SERVICE.REUSE_MAP, { + params: { + year, + }, + }); + + const list = (response.data.data ?? []).map((item) => ({ + ...item, + })); + + return list; + } } export const OperationApi = new OperationApiService(); diff --git a/apps/cm/src/pages/dashboard/api/sn-service.ts b/apps/cm/src/pages/dashboard/api/sn-service.ts index 789b46a9f..a612da51b 100644 --- a/apps/cm/src/pages/dashboard/api/sn-service.ts +++ b/apps/cm/src/pages/dashboard/api/sn-service.ts @@ -3,7 +3,7 @@ import { client } from "@/shared/api"; import { create } from "zustand"; import { ENDPOINT } from "@/shared/config"; import type { PplLengthContent, SewerageService } from "../model/sn-interface"; -import type { OldPplChartData } from "../model/sn-interface"; +import type { OldPplChartData,mapPplOldType,mapPplOldItem } from "../model/sn-interface"; export type SnState = { snStatus: PplLengthContent[] | null; @@ -65,6 +65,56 @@ export const useOldPplStore = create((set) => ({ setChartData: (chartData) => set(() => ({ chartData })), })); +export const initailMapOldPplData: mapPplOldType = { + colTitle: {totalLen: "총길이",pplLen2025: "20~25년",pplLen2530: "25~30년",pplLen30 : "30년 이상" }, //헤더 영역 + data: [ + {name: "금강", totalLen: 4545, pplLen2025: 1140, pplLen2530: 1391, pplLen30 : 2014}, + {name: "한강", totalLen: 17099, pplLen2025: 3181, pplLen2530: 3615, pplLen30 : 10303}, + {name: "낙동강", totalLen: 14745, pplLen2025: 3100, pplLen2530: 1814, pplLen30 : 9831}, + {name: "영산강", totalLen: 5073, pplLen2025: 1662, pplLen2530: 1411, pplLen30 : 2000}, + ] +}; +type mapPplOldState = { + mapData: mapPplOldItem[]; + setMapData: (mapData: mapPplOldItem[]) => void; +}; +export const useMapOldPplStore = create((set) => ({ + mapData: initailMapOldPplData.data, + setMapData: (newMapData) => set({ mapData: newMapData }), +})); + +/** + * OldPplChartData를 지도 팝업 데이터 형태인 mapPplOldItem[]으로 변환합니다. + * @param chartData 차트 데이터 + * @returns 유역별 노후관로 현황 데이터 + */ +export function transformChartDataToMapData(chartData: OldPplChartData): mapPplOldItem[] { + const mapData: mapPplOldItem[] = []; + const { labels, datasets } = chartData; + + const pplLen2025Data = datasets.find(d => d.label === '20-25년')?.data || []; + const pplLen2530Data = datasets.find(d => d.label === '25-30년')?.data || []; + const pplLen30Data = datasets.find(d => d.label === '30년이상')?.data || []; + + labels.forEach((label, index) => { + const pplLen2025 = pplLen2025Data[index] || 0; + const pplLen2530 = pplLen2530Data[index] || 0; + const pplLen30 = pplLen30Data[index] || 0; + const totalLen = pplLen2025 + pplLen2530 + pplLen30; + + mapData.push({ + name: label, + totalLen, + pplLen2025, + pplLen2530, + pplLen30, + }); + }); + + return mapData; +} + + export class SewerageApiService implements SewerageService { // 기간별 관로 총길이 public async getPplLength(instlYmdFrom: string, instlYmdTo: string): Promise { diff --git a/apps/cm/src/pages/dashboard/lib/korea-basin-map.tsx b/apps/cm/src/pages/dashboard/lib/korea-basin-map.tsx index 83b8c17c9..3d2f4b2dc 100644 --- a/apps/cm/src/pages/dashboard/lib/korea-basin-map.tsx +++ b/apps/cm/src/pages/dashboard/lib/korea-basin-map.tsx @@ -2,15 +2,18 @@ /** * 유역 지도 */ -import React, { useEffect, useRef } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { useStore } from "zustand"; import styles from "./korea-basin-map.module.css"; // 추가 import { basinStore } from "../api/fo-service"; import { basinKeyMap,MANUAL_LABEL_POS } from "../model/map-data"; import { BASIN_DATA, BASIN_IDS } from "../model/map-data"; -import type { mapOperFcltType } from "../model/fo-interface"; -import { useMapOperFcltStore } from "../api/fo-service"; -// import {Button} from "@common/components"; +import { svcInfo } from "../model/map-data"; +import type { mapOperFcltType, mapReuseMapType} from "../model/fo-interface"; +import type { mapPplOldType } from "../model/sn-interface"; +import { useMapOperFcltStore, OperationApi, useMapReuseMapStore } from "../api/fo-service"; +import { useMapOldPplStore } from "../api/sn-service"; +import {Button} from "@common/components"; const SVG_URL = "/images/region_map.svg"; // public 폴더에 region_map.svg 위치 필요 @@ -27,23 +30,137 @@ const mapOperFcltData: mapOperFcltType = { {name: "영산강", cnt: 1261, rt: 100,}, ] }; +const mapPplOldData: mapPplOldType = { + colTitle: {totalLen: "총길이",pplLen2025: "20~25년",pplLen2530: "25~30년",pplLen30 : "30년 이상" }, //헤더 영역 + data: [ + {name: "금강", totalLen: 4545, pplLen2025: 1140, pplLen2530: 1391, pplLen30 : 2014}, + {name: "한강", totalLen: 17099, pplLen2025: 3181, pplLen2530: 3615, pplLen30 : 10303}, + {name: "낙동강", totalLen: 14745, pplLen2025: 3100, pplLen2530: 1814, pplLen30 : 9831}, + {name: "영산강", totalLen: 5073, pplLen2025: 1662, pplLen2530: 1411, pplLen30 : 2000}, + ] +}; +const mapReuseMapData: mapReuseMapType = { + colTitle: {reuseAmnt: "하수재이용량",cnt : "시설수" }, //헤더 영역 + data: [ + {name: "금강", reuseAmnt: 17099, cnt: 3181}, + {name: "한강", reuseAmnt: 17099, cnt: 3181}, + {name: "낙동강", reuseAmnt: 14745, cnt: 3100}, + {name: "영산강", reuseAmnt: 5073, cnt: 1662}, + ] +}; export function KoreaBasinMap() { const stageRef = useRef(null); const svgLayerRef = useRef(null); const labelsLayerRef = useRef(null); const popupRef = useRef(null); - const popupTitleRef = useRef(null); - const popupHeader1Ref = useRef(null); - const popupHeader2Ref = useRef(null); - const popupData1Ref = useRef(null); - const popupData2Ref = useRef(null); - // const [services, setServices] = useState(svcInfo); + const [services, setServices] = useState(svcInfo); + const [popupContent, setPopupContent] = useState<{ title: string; items: { header: string; data: string }[] }>({ + title: '', + items: [], + }); const { selectedBasin, setSelectedBasin } = useStore(basinStore); - // const { operFcltStatus, setSelectedBasin } = useStore(operFcltStore); const selectedBasinKey = basinKeyMap[selectedBasin]; const {mapOperFclt} = useMapOperFcltStore(); + const {mapData: mapPplOld} = useMapOldPplStore(); + const {setMapData: setMapReuseMapData} = useMapReuseMapStore(); mapOperFcltData.data = mapOperFclt; + mapPplOldData.data = mapPplOld; + // mapReuseMapData.data = mapReuseMap; + + useEffect(() => { + const fetchData = async () => { + try { + const standardYear = await OperationApi.getStandardYear(); + const mapReuseMapRslt = await OperationApi.getReuseMap(standardYear); + setMapReuseMapData(mapReuseMapRslt); + mapReuseMapData.data = mapReuseMapRslt; + } catch (e) { + console.error("하수재이용량 map 데이터 조회 실패", e); + } + }; + fetchData(); + }, []); + // 유역정보 + const showFor = useCallback((g: SVGGElement) => { + const activeService = services.find(s => s.active); + if (!activeService) return; + + const key = (g as SVGGElement & { dataset: { key: string; label: string } }).dataset.key; + const basinName = BASIN_DATA[key as keyof typeof BASIN_DATA]?.name || (g as SVGGElement & { dataset: { label: string } }).dataset.label; + + const newPopupContent: { title: string; items: { header: string; data: string }[] } = { title: '', items: [] }; + + if (activeService.svcId === 'fo') { // 운영실태 + const item = mapOperFcltData.data.find(d => d.name === basinName); + newPopupContent.title = `2024년도 ${basinName}유역 시설운영 현황`; + newPopupContent.items.push({ + header: mapOperFcltData.colTitle.cnt, + data: item ? `${fmt(item.cnt)}개소` : '-', + }); + newPopupContent.items.push({ + header: mapOperFcltData.colTitle.rt, + data: item ? `${item.rt}%` : '-', + }); + } else if (activeService.svcId === 'sn') { // 하수관로 + const item = mapPplOldData.data.find(d => d.name === basinName); + newPopupContent.title = `2024년도 ${basinName}유역 노후하수관로 현황`; + const colTitles = mapPplOldData.colTitle; + newPopupContent.items.push({ + header: colTitles.totalLen, + data: item ? `${fmt(item.totalLen)}km` : '-', + }); + newPopupContent.items.push({ + header: colTitles.pplLen2025, + data: item ? `${fmt(item.pplLen2025)}km` : '-', + }); + newPopupContent.items.push({ + header: colTitles.pplLen2530, + data: item ? `${fmt(item.pplLen2530)}km` : '-', + }); + newPopupContent.items.push({ + header: colTitles.pplLen30, + data: item ? `${fmt(item.pplLen30)}km` : '-', + }); + } else if (activeService.svcId === 'wr') { // 물재이용 + const item = mapReuseMapData.data.find(d => d.name === basinName); + newPopupContent.title = `2024년도 ${basinName}유역 물재이용 현황`; + newPopupContent.items.push({ + header: mapReuseMapData.colTitle.reuseAmnt, + data: item ? `${fmt(item.reuseAmnt)}m³` : '-', + }); + newPopupContent.items.push({ + header: mapReuseMapData.colTitle.cnt, + data: item ? `${fmt(item.cnt)}개소` : '-', + }); + } + + setPopupContent(newPopupContent); + + if (!stageRef.current) return; + const sRect = stageRef.current.getBoundingClientRect(), + r = g.getBoundingClientRect(); + const cx = (r.left + r.right) / 2 - sRect.left; + const ty = r.top - sRect.top; + if (popupRef.current) { + popupRef.current.style.left = cx + "px"; + popupRef.current.style.top = ty + 6 + "px"; + popupRef.current.style.opacity = "1"; + popupRef.current.style.visibility = "visible"; + if (styles.show) { + popupRef.current.classList.add(styles.show); + } + } + + if (popupRef.current) { + const pRect = popupRef.current.getBoundingClientRect(); + const x = Math.max( + 12 + pRect.width / 2, + Math.min(cx, sRect.width - 12 - pRect.width / 2), + ); + popupRef.current.style.left = x + "px"; + } + }, [services, mapOperFclt]); // selectedBasinKey prop이 변경될 때 지도를 업데이트하는 useEffect useEffect(() => { @@ -64,6 +181,21 @@ export function KoreaBasinMap() { let gs: SVGGElement[] = []; let labels: HTMLDivElement[] = []; + const clear = () => { + gs.forEach((el) => el.classList.remove("active")); + if (popupRef.current) { + if (styles.show) { + popupRef.current.classList.remove(styles.show); + } + popupRef.current.style.opacity = "0"; + } + labels.forEach((l) => l.classList.remove("active")); + }; + + // const positionLabels = () => { + // // This function's content is moved inside the fetch callback + // }; + // console.log("Loading SVG from:", SVG_URL); fetch(SVG_URL) .then((r) => { @@ -147,70 +279,6 @@ export function KoreaBasinMap() { // // }); // }); - // 2) 함수들 먼저 정의 - const clear = () => { - gs.forEach((el) => el.classList.remove("active")); - if (popupRef.current) { - if (styles.show) { - popupRef.current.classList.remove(styles.show); - } - popupRef.current.style.opacity = "0"; - } - labels.forEach((l) => l.classList.remove("active")); - }; - - // 유역정보 - function showFor(g: SVGGElement) { - // console.log("showFor called for:", g); - const key = (g as SVGGElement & { dataset: { key: string; label: string } }).dataset.key; - const basinName = BASIN_DATA[key as keyof typeof BASIN_DATA]?.name || (g as SVGGElement & { dataset: { label: string } }).dataset.label; - const fcltItem = mapOperFcltData.data.find(d => d.name === basinName); - - if (popupTitleRef.current) { - popupTitleRef.current.textContent = `2024년도 ${basinName}유역 시설운영 현황`; - } - if (popupHeader1Ref.current) { - popupHeader1Ref.current.textContent = mapOperFcltData.colTitle.cnt; - } - if (popupHeader2Ref.current) { - popupHeader2Ref.current.textContent = mapOperFcltData.colTitle.rt; - } - if (popupData1Ref.current) { - popupData1Ref.current.textContent = fcltItem ? `${fmt(fcltItem.cnt)}개소` : "-"; - } - if (popupData2Ref.current) { - popupData2Ref.current.textContent = fcltItem ? `${fcltItem.rt}%` : "-"; - } - - if (!stageRef.current) return; - const sRect = stageRef.current.getBoundingClientRect(), - r = g.getBoundingClientRect(); - const cx = (r.left + r.right) / 2 - sRect.left; - const ty = r.top - sRect.top; - - // console.log("Popup position:", { cx, ty }); - - if (popupRef.current) { - popupRef.current.style.left = cx + "px"; - popupRef.current.style.top = ty + 6 + "px"; - popupRef.current.style.opacity = "1"; - popupRef.current.style.visibility = "visible"; - if (styles.show) { - popupRef.current.classList.add(styles.show); - } - // console.log("Added show class to popup:", popupRef.current.classList.toString()); - } - - if (popupRef.current) { - const pRect = popupRef.current.getBoundingClientRect(); - const x = Math.max( - 12 + pRect.width / 2, - Math.min(cx, sRect.width - 12 - pRect.width / 2), - ); - popupRef.current.style.left = x + "px"; - } - } - function showForWithLabel(g: SVGGElement) { // console.log("showForWithLabel called for:", g); showFor(g); @@ -233,7 +301,7 @@ export function KoreaBasinMap() { } // 3) 라벨 위치 - function positionLabels() { + const positionLabels = () => { if (!stageRef.current || !svg) return; const sRect = stageRef.current.getBoundingClientRect(); const inset = @@ -282,7 +350,7 @@ export function KoreaBasinMap() { } labels[i]!.style.left = `${px}px`; labels[i]!.style.top = `${py + 18}px`; - }); + }); } // 4) 상호작용 (함수들은 이미 위에서 정의됨) @@ -330,34 +398,36 @@ export function KoreaBasinMap() { return () => { window.removeEventListener("resize", () => {}); }; - }, []); + }, [selectedBasinKey, showFor]); // 의존성 배열에 mapOperFclt 추가 불필요 - // const handleSvcInfoClick = (clickedSvcId: string) => { - // setServices(prevServices => - // prevServices.map(svc => ({ - // ...svc, - // active: svc.svcId === clickedSvcId, - // })) - // ); - // }; + const handleSvcInfoClick = (clickedSvcId: string) => { + setServices(prevServices => + prevServices.map(svc => ({ + ...svc, + active: svc.svcId === clickedSvcId, + })) + ); + }; // 스타일은 필요에 따라 tailwind, css 등으로 커스터마이즈하세요. return (

유역별 정보

- {/* - {services.map((svc) => ( - - ))} - */} + +
+ {services.map((svc) => ( + + ))} +
+
diff --git a/apps/cm/src/pages/dashboard/model/fo-interface.ts b/apps/cm/src/pages/dashboard/model/fo-interface.ts index 9ec3a312c..0d8a918c1 100644 --- a/apps/cm/src/pages/dashboard/model/fo-interface.ts +++ b/apps/cm/src/pages/dashboard/model/fo-interface.ts @@ -34,6 +34,11 @@ export interface OperWqltContent { avgEfflTn: number; // 기간 평균 유출수 TN } +export interface ReuseMapContent { + name: string; // 유역명 + reuseAmnt: number; // 하수재이용량 + cnt: number; // 시설수 +} export interface ReuseStatusContent { yr: string; @@ -63,10 +68,10 @@ export type mapOperFcltType = { data: mapOperFcltItem[]; }; - -// function buildCntRt( operFcltStatus: OperFcltContent[]) : mapBasinData => { -// const colTitle = {cnt:"개소수",rt:"가동률"}; -// const result: mapBasinData = {}; - - -// } \ No newline at end of file +export type mapReuseMapType = { + colTitle: { + reuseAmnt: string; // 하수재이용량 + cnt: string; // 시설수 + }; + data: ReuseMapContent[]; +}; \ No newline at end of file diff --git a/apps/cm/src/pages/dashboard/model/sn-interface.ts b/apps/cm/src/pages/dashboard/model/sn-interface.ts index 650564637..865b96688 100644 --- a/apps/cm/src/pages/dashboard/model/sn-interface.ts +++ b/apps/cm/src/pages/dashboard/model/sn-interface.ts @@ -30,6 +30,25 @@ type SnOldPplLength = { [key: string]: SnOldPplItem; }; +export type mapPplOldItem = { + name: string; + totalLen: number; + pplLen2025: number; + pplLen2530: number; + pplLen30: number; +}; + +export type mapPplOldType = { + colTitle: { + totalLen: string; // 총길이 + pplLen2025: string; // 20~25년 + pplLen2530: string; // 25~30년 + pplLen30 : string; // 30년 이상 + }; + data: mapPplOldItem[]; +}; + + export function buildSnOldPplLength( chartData: { labels: string[]; diff --git a/apps/cm/src/pages/dashboard/ui/reuse-chart.tsx b/apps/cm/src/pages/dashboard/ui/reuse-chart.tsx index de650cfa7..edcc19b97 100644 --- a/apps/cm/src/pages/dashboard/ui/reuse-chart.tsx +++ b/apps/cm/src/pages/dashboard/ui/reuse-chart.tsx @@ -155,7 +155,7 @@ const ReuseChart: React.FC = () => { const startSlider = () => { intervalRef.current = setInterval(() => { setActiveIndex(prevIndex => (prevIndex + 1) % chartItems.length); - }, 30000); + }, 7000); }; const stopSlider = () => { diff --git a/apps/cm/src/pages/dashboard/ui/sn-old-ppl.tsx b/apps/cm/src/pages/dashboard/ui/sn-old-ppl.tsx index 757d9a4d2..dfe4ff260 100644 --- a/apps/cm/src/pages/dashboard/ui/sn-old-ppl.tsx +++ b/apps/cm/src/pages/dashboard/ui/sn-old-ppl.tsx @@ -15,8 +15,8 @@ import { } from "chart.js"; import { Bar } from "react-chartjs-2"; import { Button } from "@common/components"; -import type { PplLengthContent, ChartDataSet } from "../model/sn-interface"; -import { SewerageApi, useOldPplStore } from "../api/sn-service"; +import type { PplLengthContent, ChartDataSet, OldPplChartData } from "../model/sn-interface"; +import { SewerageApi, useOldPplStore,useMapOldPplStore, transformChartDataToMapData } from "../api/sn-service"; // ChartJS 컴포넌트 등록 @@ -27,6 +27,7 @@ export default function SnOldPpl() { const [oldPpl2530Data, setOldPpl2530Data] = useState([]); const [oldPpl30Data, setOldPpl30Data] = useState([]); const {chartData, setChartData} = useOldPplStore(); + const {setMapData} = useMapOldPplStore(); useEffect(() => { const currentYear = new Date().getFullYear(); @@ -72,11 +73,15 @@ export default function SnOldPpl() { newDatasets.push(createDataset('30년이상', oldPpl30Data, '#F87171')); } - setChartData({ + const newChartData: OldPplChartData = { labels: allZones, datasets: newDatasets, - }); + }; + setChartData(newChartData); + + // 차트 데이터를 기반으로 지도 팝업 데이터 생성 및 상태 업데이트 + setMapData(transformChartDataToMapData(newChartData)); }, [oldPpl2025Data, oldPpl2530Data, oldPpl30Data]); // 각 지역별 총 길이 계산 @@ -86,7 +91,8 @@ export default function SnOldPpl() { return sum + (typeof value === 'number' ? value : 0); }, 0); }); - + + // 차트 옵션 설정 const options: ChartOptions<"bar"> = { responsive: true, diff --git a/apps/cm/src/shared/config/api.ts b/apps/cm/src/shared/config/api.ts index 241188bee..983d1f64d 100644 --- a/apps/cm/src/shared/config/api.ts +++ b/apps/cm/src/shared/config/api.ts @@ -80,6 +80,7 @@ export const ENDPOINT = { OPER_CNTRT: "/operation-service/api/v1/dashBoard/main/oper/cntrt", OPER_WQLT: "/operation-service/api/v1/dashBoard/main/oper/wqlt", REUSE_STATUS: "/operation-service/api/v1/dashBoard/main/reuse/status", + REUSE_MAP: "/operation-service/api/v1/dashBoard/main/reuse/map", }, IC_SERVICE: { GROUPING_STATISTICS: "/ic-service/api/v1/support-status-summary",