From dad78579cc83a16e5c192eb459ad4a5f1e6898d0 Mon Sep 17 00:00:00 2001 From: ljpark Date: Thu, 11 Dec 2025 14:20:38 +0900 Subject: [PATCH 1/3] =?UTF-8?q?cm:=20=EC=88=98=EA=B3=84=EB=B3=84=20?= =?UTF-8?q?=EC=9C=A0=EC=9E=85=E3=86=8D=EB=B0=A9=EB=A5=98=EC=88=98=EC=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cm/src/pages/dashboard/api/fo-service.ts | 75 +++++++---- .../src/pages/dashboard/model/fo-interface.ts | 47 +++++-- .../src/pages/dashboard/ui/fo-fclt-cnt-rt.tsx | 20 +-- .../pages/dashboard/ui/fo-wqlt-Infl-effl.tsx | 116 ++++++++++-------- apps/cm/src/shared/config/api.ts | 1 + 5 files changed, 168 insertions(+), 91 deletions(-) diff --git a/apps/cm/src/pages/dashboard/api/fo-service.ts b/apps/cm/src/pages/dashboard/api/fo-service.ts index 2e0f6e7ae..129a64cd6 100644 --- a/apps/cm/src/pages/dashboard/api/fo-service.ts +++ b/apps/cm/src/pages/dashboard/api/fo-service.ts @@ -2,8 +2,10 @@ import { client } from "@/shared/api"; import { createStore } from "zustand/vanilla"; import { ENDPOINT } from "@/shared/config"; -import type { OperFcltContent, ReuseStatusContent, OperationService } from "../model/fo-interface"; +import type { OperWqltContent, OperFcltContent, ReuseStatusContent, OperationService +} from "../model/fo-interface"; +//수계별 시설운영 개소수 및 가동률 export type OperFcltState = { operFcltStatus: OperFcltContent[] | null; }; @@ -11,23 +13,6 @@ export type OperFcltStateActions = { setOperFcltStatus: (operFcltStatus: OperFcltContent[] | null) => void; }; export type OperFcltStore = OperFcltState & OperFcltStateActions; - -export type ReuseState = { - reuseStatus: ReuseStatusContent[] | null; -}; -export type ReuseStateActions = { - setReuseStatus: (reuseStatus: ReuseStatusContent[] | null) => void; -}; -export type ReuseStore = ReuseState & ReuseStateActions; - -export type YearState = { - year: string | null; -}; -export type YearStateActions = { - setYear: (year: string | null) => void; -}; -export type YearStore = YearState & YearStateActions; - export const defaultInitOperFcltState: OperFcltState = { operFcltStatus: null, }; @@ -37,7 +22,26 @@ export const createOperFcltStore = (initState: OperFcltState = defaultInitOperFc setOperFcltStatus: (operFcltStatus) => set(() => ({ operFcltStatus })), })); +//수계별 유입ㆍ방류수질 분석 +export type OperWqltState = { + operWqltStatus: OperWqltContent[] | null; +}; +export type OperWqltStateActions = { + setOperWqltStatus: (operWqltStatus: OperWqltContent[] | null) => void; +}; +export type OperWqltStore = OperWqltState & OperWqltStateActions; +export const defaultInitOperWqltState: OperWqltState = { + operWqltStatus: null, +}; +// 물재이용 현황 +export type ReuseState = { + reuseStatus: ReuseStatusContent[] | null; +}; +export type ReuseStateActions = { + setReuseStatus: (reuseStatus: ReuseStatusContent[] | null) => void; +}; +export type ReuseStore = ReuseState & ReuseStateActions; const initialReuseStatusData: ReuseStatusContent[] = [ { yr: '2021', sewage: 7335803, reclaimed: 254805510.3, rainwater: 14049224.5 }, { yr: '2022', sewage: 7378907, reclaimed: 243457788.8, rainwater: 15128093.4 }, @@ -53,6 +57,15 @@ export const createReuseStore = (initState: ReuseState = defaultInitReuseState) setReuseStatus: (reuseStatus) => set(() => ({ reuseStatus })), })); +// 기준년도 조회 +export type YearState = { + year: string | null; +}; +export type YearStateActions = { + setYear: (year: string | null) => void; +}; +export type YearStore = YearState & YearStateActions; + export const defaultYearInitState: YearState = { year: null, }; @@ -64,13 +77,12 @@ export const createYearStore = (initState: YearState = defaultYearInitState) => // 전역으로 공유할 store 인스턴스 export const operFcltStore = createOperFcltStore(); -// 전역으로 공유할 store 인스턴스 export const reuseStore = createReuseStore(); -// 전역으로 공유할 store 인스턴스 export const yearStore = createYearStore(); export class OperationApiService implements OperationService { + // 기준년도 조회 public async getStandardYear(): Promise { const { year, setYear } = yearStore.getState(); if (year) { @@ -117,7 +129,27 @@ export class OperationApiService implements OperationService { return list; } - // 여러 컴포넌트에서 호출해도 서버 호출은 1번만 되도록 캐싱 + // 수계별 시설운영 개소수 및 가동률 + public async getDashOperWqlt(year: string): Promise { + + const response = await client.get<{ + status: number; + data: OperWqltContent[]; + count: number; + }>(ENDPOINT.OPERATION_SERVICE.OPER_WQLT, { + params: { + year, + }, + }); + + const list = (response.data.data ?? []).map((item) => ({ + ...item, + })); + + return list; + } + + // 물재이용 현황 public async getReuseStatus(): Promise { // API 호출 시에는 항상 최신 데이터를 가져오도록 캐싱 로직을 제거하거나 수정할 수 있습니다. // 여기서는 기존 캐싱 로직을 유지하되, 초기 데이터가 아닌 경우에만 API를 호출하도록 합니다. @@ -146,3 +178,4 @@ export class OperationApiService implements OperationService { } export const OperationApi = new OperationApiService(); + diff --git a/apps/cm/src/pages/dashboard/model/fo-interface.ts b/apps/cm/src/pages/dashboard/model/fo-interface.ts index 6d57ae6bd..7aa61ff8d 100644 --- a/apps/cm/src/pages/dashboard/model/fo-interface.ts +++ b/apps/cm/src/pages/dashboard/model/fo-interface.ts @@ -1,10 +1,3 @@ -export interface ReuseStatusContent { - yr: string; - sewage: number; - reclaimed: number; - rainwater: number; -} - export interface OperFcltContent { rvbsn: string; // 유역 cnt: number; // 개소수 @@ -12,6 +5,46 @@ export interface OperFcltContent { gubun: string; // 구분 } +export interface OperWqltContent { + rvbsn: string; // 유역명 + yr: string; // 연도 + + sumInflBod: number; // 유입수 BOD 합계 + sumInflToc: number; // 유입수 TOC 합계 + sumInflSs: number; // 유입수 SS 합계 + sumInflTp: number; // 유입수 TP 합계 + sumInflTn: number; // 유입수 TN 합계 + + sumEfflBod: number; // 유출수 BOD 합계 + sumEfflToc: number; // 유출수 TOC 합계 + sumEfflSs: number; // 유출수 SS 합계 + sumEfflTp: number; // 유출수 TP 합계 + sumEfflTn: number; // 유출수 TN 합계 + + avgInflBod: number; // 기간 평균 유입수 BOD + avgInflToc: number; // 기간 평균 유입수 TOC + avgInflSs: number; // 기간 평균 유입수 SS + avgInflTp: number; // 기간 평균 유입수 TP + avgInflTn: number; // 기간 평균 유입수 TN + + avgEfflBod: number; // 기간 평균 유출수 BOD + avgEfflToc: number; // 기간 평균 유출수 TOC + avgEfflSs: number; // 기간 평균 유출수 SS + avgEfflTp: number; // 기간 평균 유출수 TP + avgEfflTn: number; // 기간 평균 유출수 TN +} + + +export interface ReuseStatusContent { + yr: string; + sewage: number; + reclaimed: number; + rainwater: number; +} + export interface OperationService { + getStandardYear(): Promise ; + getDashOperCntRt(year: string): Promise; + getDashOperWqlt(year: string): Promise; getReuseStatus(): Promise; } \ No newline at end of file diff --git a/apps/cm/src/pages/dashboard/ui/fo-fclt-cnt-rt.tsx b/apps/cm/src/pages/dashboard/ui/fo-fclt-cnt-rt.tsx index f9534f1aa..7003cc130 100644 --- a/apps/cm/src/pages/dashboard/ui/fo-fclt-cnt-rt.tsx +++ b/apps/cm/src/pages/dashboard/ui/fo-fclt-cnt-rt.tsx @@ -6,6 +6,7 @@ import React, { useEffect, useState, useMemo } from 'react'; import { useStore } from "zustand"; import BasinSelect from "./basIn-select"; import { Doughnut } from "react-chartjs-2"; +import type { Chart as ChartJS } from "chart.js"; // import type { OperFcltContent } from "../model/fo-interface"; import { OperationApi, operFcltStore } from "../api/fo-service"; @@ -31,24 +32,23 @@ const FoFcltCntRt: React.FC = () => { if (!operFcltStatus) { return { facilityCount: 0, operatingRate: 0, chartData: [0, 100] }; } - console.log(operFcltStatus); const basinData = operFcltStatus.filter(d => d.rvbsn === selectedBasin); // 선택된 유역의 데이터만 filter const operatingData = basinData.find(d => d.gubun === 'R'); // 선택 유역의 R 데이터만 const nonOperatingData = basinData.find(d => d.gubun === 'A'); - + const facilityCount = operatingData?.cnt ?? 0; const operatingCapacity = operatingData?.fctCpc ?? 0; const nonOperatingCapacity = nonOperatingData?.fctCpc ?? 0; const totalCapacity = operatingCapacity + nonOperatingCapacity; - + const operatingRate = totalCapacity > 0 ? Math.round((operatingCapacity / totalCapacity) * 100) : 0; - const nonOperatingRate = totalCapacity > 0 ? Math.round((nonOperatingCapacity / totalCapacity) * 100) : 0; - - return { + const result = { facilityCount, operatingRate, - chartData: [operatingRate, nonOperatingRate], + chartData: [operatingCapacity, nonOperatingCapacity], }; + console.log(result); + return result; }, [operFcltStatus, selectedBasin]); return ( @@ -106,12 +106,14 @@ const FoFcltCntRt: React.FC = () => { } } }} + key={displayData.operatingRate} // Key를 변경하여 차트 강제 업데이트 plugins={[{ id: 'centerText', - afterDraw: (chart) => { + afterDraw: (chart: ChartJS) => { const ctx = chart.ctx; const centerX = chart.width / 2; const centerY = chart.height / 2; + const rate = displayData.operatingRate ?? 0; // 가동률 텍스트 ctx.save(); @@ -119,7 +121,7 @@ const FoFcltCntRt: React.FC = () => { ctx.fillStyle = '#00DFE5'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; - ctx.fillText(`${displayData.operatingRate}%`, centerX, centerY + 10); + ctx.fillText(`${rate}%`, centerX, centerY + 10); // 라벨 텍스트 ctx.font = '10px Arial'; diff --git a/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx b/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx index 7ea5c3c15..9a526b451 100644 --- a/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx +++ b/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx @@ -2,57 +2,66 @@ /** * 수계별 유입ㆍ방류수질 분석 */ -import React, { useState } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import { Line } from 'react-chartjs-2'; import BasinSelect from "./basIn-select"; import { Chart as ChartJS, - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend, - type ChartOptions, + CategoryScale, LinearScale, PointElement, LineElement, + Title, Tooltip, Legend, type ChartOptions, } from 'chart.js'; +import type { OperWqltContent } from "../model/fo-interface"; +import { OperationApi } from "../api/fo-service"; // Chart.js 등록 -ChartJS.register( - CategoryScale, - LinearScale, - PointElement, - LineElement, - Title, - Tooltip, - Legend -); +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend); type WaterQualityType = 'BOD' | 'TOC' | 'SS' | 'TP' | 'TN'; -interface ChartData { - labels: string[]; - inflowData: number[]; - inflowAverage: number[]; - effluentData: number[]; - effluentAverage: number[]; -} - const FoWqltInflEffl: React.FC = () => { + // const [year, setYear] = useState(null); const [selectedBasin, setSelectedBasin] = useState("한강"); - const [selectedTab, setSelectedTab] = useState('BOD'); - - // 데이터 (실제로는 API에서 가져올 데이터) - const bodData: ChartData = { - labels: ['2020', '2021', '2022', '2023', '2024'], - inflowData: [2255.6, 2282.2, 2304.3, 5156.6, 4620.4], - inflowAverage: [2255.6, 2282.2, 2304.3, 2304.3, 2304.3], - effluentData: [55, 47.5, 52, 79.7, 83.9], - effluentAverage: [55, 47.5, 52, 52, 52], - }; - + const [selectedTab, setSelectedTab] = useState('BOD'); + const [wqltData, setWqltData] = useState([]); const tabs: WaterQualityType[] = ['BOD', 'TOC', 'SS', 'TP', 'TN']; + useEffect(() => { + const fetchData = async () => { + try { + const standardYear = await OperationApi.getStandardYear(); + const data = await OperationApi.getDashOperWqlt(standardYear); + setWqltData(data); + console.log(wqltData); + } catch (e) { + console.error("시설 유입ㆍ방류수질 데이터 조회 실패", e); + } + }; + fetchData(); + }, []); + + const chartData = useMemo(() => { + const filteredData = wqltData + .filter(d => d.rvbsn === selectedBasin) // 해당 유역 + .sort((a, b) => Number(a.yr) - Number(b.yr)); + + const wqltKey = selectedTab.charAt(0).toUpperCase() + selectedTab.slice(1).toLowerCase(); + const inflowKey = `sumInfl${wqltKey}` as keyof OperWqltContent; + const effluentKey = `sumEffl${wqltKey}` as keyof OperWqltContent; + const inflowAvgKey = `avgInfl${wqltKey}` as keyof OperWqltContent; + const effluentAvgKey = `avgEffl${wqltKey}` as keyof OperWqltContent; + + + const labels = filteredData.map(d => d.yr ?? ''); + const inflowData = filteredData.map(d => d[inflowKey] as number); + const effluentData = filteredData.map(d => d[effluentKey] as number); + const inflowAvg = filteredData[0]?.[inflowAvgKey] as number ?? 0; + const effluentAvg = filteredData[0]?.[effluentAvgKey] as number ?? 0; + + return { labels, inflowData, effluentData, inflowAvg, effluentAvg }; + }, [wqltData, selectedBasin, selectedTab]); + + console.log(chartData); + // 차트 공통 옵션 // const getChartOptions = (yAxisLabel: string): ChartOptions<'line'> => ({ const getChartOptions = (): ChartOptions<'line'> => ({ @@ -124,11 +133,11 @@ const FoWqltInflEffl: React.FC = () => { // 유입 데이터 차트 설정 const inflowChartData = { - labels: bodData.labels, + labels: chartData.labels, datasets: [ { - label: '유입BOD (mg/L)', - data: bodData.inflowData, + label: `유입${selectedTab} (mg/L)`, + data: chartData.inflowData, borderColor: '#00D4FF', backgroundColor: '#00D4FF', borderWidth: 1, @@ -138,25 +147,25 @@ const FoWqltInflEffl: React.FC = () => { }, { label: '유입 평균 (mg/L)', - data: bodData.inflowAverage, + data: Array(chartData.labels.length).fill(chartData.inflowAvg), borderColor: '#FF1493', backgroundColor: '#FF1493', borderWidth: 1, borderDash: [10, 5], - pointRadius: 2, + pointRadius: 0, pointHoverRadius: 4, tension: 0, }, ], }; - // 발류 데이터 차트 설정 + // 방류 데이터 차트 설정 const effluentChartData = { - labels: bodData.labels, + labels: chartData.labels, datasets: [ { - label: '발류BOD (mg/L)', - data: bodData.effluentData, + label: `방류${selectedTab} (mg/L)`, + data: chartData.effluentData, borderColor: '#00FF88', backgroundColor: '#00FF88', borderWidth: 1, @@ -165,13 +174,13 @@ const FoWqltInflEffl: React.FC = () => { tension: 0.4, }, { - label: '발류 평균 (mg/L)', - data: bodData.effluentAverage, + label: '방류 평균 (mg/L)', + data: Array(chartData.labels.length).fill(chartData.effluentAvg), borderColor: '#FFB800', backgroundColor: '#FFB800', borderWidth: 1, borderDash: [10, 5], - pointRadius: 1, + pointRadius: 0, pointHoverRadius: 4, tension: 0, }, @@ -209,15 +218,14 @@ const FoWqltInflEffl: React.FC = () => { {/* 차트 영역 */} -
+
{/* 유입 차트 */} -
- {/* */} +
- {/* 발류 차트 */} -
+ {/* 방류 차트 */} +
diff --git a/apps/cm/src/shared/config/api.ts b/apps/cm/src/shared/config/api.ts index 3ac14a983..45096e25e 100644 --- a/apps/cm/src/shared/config/api.ts +++ b/apps/cm/src/shared/config/api.ts @@ -78,6 +78,7 @@ export const ENDPOINT = { OPERATION_SERVICE: { MAIN_YEAR: "/operation-service/api/v1/dashBoard/main/year", 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", }, IC_SERVICE: { From b91c02613542698f0ad83aba77fd288112bb19cf Mon Sep 17 00:00:00 2001 From: ljpark Date: Thu, 11 Dec 2025 17:03:44 +0900 Subject: [PATCH 2/3] =?UTF-8?q?cm:=20=EC=9C=A0=EC=9E=85=EB=B0=A9=EB=A5=98?= =?UTF-8?q?=EC=88=98=EC=A7=88=20=EC=B4=88=EA=B8=B0=EA=B0=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cm/src/pages/dashboard/api/fo-service.ts | 23 ++++++++++++++++--- .../pages/dashboard/ui/fo-wqlt-Infl-effl.tsx | 3 ++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/cm/src/pages/dashboard/api/fo-service.ts b/apps/cm/src/pages/dashboard/api/fo-service.ts index 129a64cd6..3dc64dc5f 100644 --- a/apps/cm/src/pages/dashboard/api/fo-service.ts +++ b/apps/cm/src/pages/dashboard/api/fo-service.ts @@ -24,14 +24,31 @@ export const createOperFcltStore = (initState: OperFcltState = defaultInitOperFc //수계별 유입ㆍ방류수질 분석 export type OperWqltState = { - operWqltStatus: OperWqltContent[] | null; + operWqltStatus: OperWqltContent[] | []; }; export type OperWqltStateActions = { - setOperWqltStatus: (operWqltStatus: OperWqltContent[] | null) => void; + setOperWqltStatus: (operWqltStatus: OperWqltContent[] | []) => void; }; export type OperWqltStore = OperWqltState & OperWqltStateActions; +const initialWqltData: OperWqltContent[] = [ + { rvbsn: '금강', yr: '2020', sumInflBod: 97975, sumInflToc: 59900, sumInflSs: 103564, sumInflTp: 2879, sumInflTn: 27062, sumEfflBod: 100143, sumEfflToc: 57805, sumEfflSs: 100942, sumEfflTp: 2901, sumEfflTn: 26796, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '금강', yr: '2021', sumInflBod: 97943, sumInflToc: 55043, sumInflSs: 102727, sumInflTp: 2866, sumInflTn: 26237, sumEfflBod: 100143, sumEfflToc: 57805, sumEfflSs: 100942, sumEfflTp: 2901, sumEfflTn: 26796, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '금강', yr: '2022', sumInflBod: 104513, sumInflToc: 58471, sumInflSs: 96534, sumInflTp: 2960, sumInflTn: 27089, sumEfflBod: 100143, sumEfflToc: 57805, sumEfflSs: 100942, sumEfflTp: 2901, sumEfflTn: 26796, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '낙동강', yr: '2020', sumInflBod: 127321, sumInflToc: 79241, sumInflSs: 120184, sumInflTp: 4004, sumInflTn: 35373, sumEfflBod: 128919, sumEfflToc: 69837, sumEfflSs: 123866, sumEfflTp: 4773, sumEfflTn: 36740, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '낙동강', yr: '2021', sumInflBod: 127792, sumInflToc: 61919, sumInflSs: 123625, sumInflTp: 4157, sumInflTn: 35270, sumEfflBod: 128919, sumEfflToc: 69837, sumEfflSs: 123866, sumEfflTp: 4773, sumEfflTn: 36740, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '낙동강', yr: '2022', sumInflBod: 131644, sumInflToc: 68350, sumInflSs: 127789, sumInflTp: 6159, sumInflTn: 39578, sumEfflBod: 128919, sumEfflToc: 69837, sumEfflSs: 123866, sumEfflTp: 4773, sumEfflTn: 36740, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '영산강', yr: '2020', sumInflBod: 141092, sumInflToc: 97019, sumInflSs: 140610, sumInflTp: 14032, sumInflTn: 45880, sumEfflBod: 132293, sumEfflToc: 83642, sumEfflSs: 140673, sumEfflTp: 8419, sumEfflTn: 46126, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '영산강', yr: '2021', sumInflBod: 131004, sumInflToc: 74582, sumInflSs: 141129, sumInflTp: 5682, sumInflTn: 45056, sumEfflBod: 132293, sumEfflToc: 83642, sumEfflSs: 140673, sumEfflTp: 8419, sumEfflTn: 46126, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '영산강', yr: '2022', sumInflBod: 124784, sumInflToc: 79326, sumInflSs: 140281, sumInflTp: 5543, sumInflTn: 47443, sumEfflBod: 132293, sumEfflToc: 83642, sumEfflSs: 140673, sumEfflTp: 8419, sumEfflTn: 46126, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '한강', yr: '2020', sumInflBod: 146258, sumInflToc: 92931, sumInflSs: 151875, sumInflTp: 4151, sumInflTn: 36537, sumEfflBod: 152099, sumEfflToc: 84360, sumEfflSs: 153111, sumEfflTp: 8443, sumEfflTn: 35571, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '한강', yr: '2021', sumInflBod: 150983, sumInflToc: 77755, sumInflSs: 153838, sumInflTp: 4098, sumInflTn: 34946, sumEfflBod: 152099, sumEfflToc: 84360, sumEfflSs: 153111, sumEfflTp: 8443, sumEfflTn: 35571, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '한강', yr: '2022', sumInflBod: 159057, sumInflToc: 82394, sumInflSs: 153619, sumInflTp: 17080, sumInflTn: 35231, sumEfflBod: 152099, sumEfflToc: 84360, sumEfflSs: 153111, sumEfflTp: 8443, sumEfflTn: 35571, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '', yr: '2020', sumInflBod: 55280, sumInflToc: 35027, sumInflSs: 55125, sumInflTp: 1695, sumInflTn: 15442, sumEfflBod: 65532, sumEfflToc: 36455, sumEfflSs: 65256, sumEfflTp: 2830, sumEfflTn: 18291, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '', yr: '2021', sumInflBod: 66809, sumInflToc: 33841, sumInflSs: 65743, sumInflTp: 2015, sumInflTn: 17674, sumEfflBod: 65532, sumEfflToc: 36455, sumEfflSs: 65256, sumEfflTp: 2830, sumEfflTn: 18291, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, + { rvbsn: '', yr: '2022', sumInflBod: 74505, sumInflToc: 40498, sumInflSs: 74899, sumInflTp: 4780, sumInflTn: 21756, sumEfflBod: 65532, sumEfflToc: 36455, sumEfflSs: 65256, sumEfflTp: 2830, sumEfflTn: 18291, avgInflBod: 0, avgInflToc: 0, avgInflSs: 0, avgInflTp: 0, avgInflTn: 0, avgEfflBod: 0, avgEfflToc: 0, avgEfflSs: 0, avgEfflTp: 0, avgEfflTn: 0 }, +]; export const defaultInitOperWqltState: OperWqltState = { - operWqltStatus: null, + operWqltStatus: initialWqltData, }; // 물재이용 현황 diff --git a/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx b/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx index 9a526b451..a2cc12168 100644 --- a/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx +++ b/apps/cm/src/pages/dashboard/ui/fo-wqlt-Infl-effl.tsx @@ -12,6 +12,7 @@ import { } from 'chart.js'; import type { OperWqltContent } from "../model/fo-interface"; import { OperationApi } from "../api/fo-service"; +import { defaultInitOperWqltState } from "../api/fo-service"; // Chart.js 등록 ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend); @@ -19,13 +20,13 @@ ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, T type WaterQualityType = 'BOD' | 'TOC' | 'SS' | 'TP' | 'TN'; const FoWqltInflEffl: React.FC = () => { - // const [year, setYear] = useState(null); const [selectedBasin, setSelectedBasin] = useState("한강"); const [selectedTab, setSelectedTab] = useState('BOD'); const [wqltData, setWqltData] = useState([]); const tabs: WaterQualityType[] = ['BOD', 'TOC', 'SS', 'TP', 'TN']; useEffect(() => { + setWqltData(defaultInitOperWqltState.operWqltStatus); const fetchData = async () => { try { const standardYear = await OperationApi.getStandardYear(); From 9306cb68144a726876e4282a199e806821ee6225 Mon Sep 17 00:00:00 2001 From: ljpark Date: Thu, 11 Dec 2025 21:20:09 +0900 Subject: [PATCH 3/3] =?UTF-8?q?cm:=20=EC=A7=80=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/dashboard/lib/korea-basin-map.tsx | 151 +++++++++--------- .../src/pages/dashboard/ui/dashboard-page.tsx | 11 +- 2 files changed, 82 insertions(+), 80 deletions(-) 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 637f88e9d..eacf1a2e1 100644 --- a/apps/cm/src/pages/dashboard/lib/korea-basin-map.tsx +++ b/apps/cm/src/pages/dashboard/lib/korea-basin-map.tsx @@ -348,78 +348,85 @@ export function KoreaBasinMap() { // 스타일은 필요에 따라 tailwind, css 등으로 커스터마이즈하세요. return ( -
-
-
-
-
-