Merge commit 'c9169772922b9ad3046b894b4375f3983779a1bd'

This commit is contained in:
leedj312
2025-09-09 10:10:30 +09:00
6 changed files with 309 additions and 272 deletions
+82 -253
View File
@@ -1,237 +1,43 @@
'use client'; 'use client';
import { regionData, regionIdMap } from '@/app/common/comFunction';
import { useDmStore } from '@/app/store';
import type { DmStatusDataType } from '@/app/store/wrStatus/type';
import { CHART_FORM, MainChart, type ChartConfig } from '@common/business_components'; import { CHART_FORM, MainChart, type ChartConfig } from '@common/business_components';
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react'; import React, { useEffect, useRef, useState, useCallback } from 'react';
interface RegionData {
name: string; interface WrStatusChartProps {
x: number; chartForm: string;
y: number; chartConfig: ChartConfig;
values: number[]; chartData: any;
chartTitle: string;
chartClassName?: string;
graphSize?: number;
yFieldText? : string | undefined;
yFieldText2? : string | undefined;
showLegend? : boolean;
setXAxisYearTick ?: boolean;
} }
interface TableData { export default function WrStatusPage() {
region: string;
sewage: string;
rainwater: string;
reclaimed: string;
thermal: string;
}
const { dmStatus, getDmStatusData} = useDmStore((state) => state);
const WrStatusPage: React.FC = () => { const { statusData,facilityTotals ,chartData} = dmStatus;
const [selectedRegion, setSelectedRegion] = useState<string | null>(null); const [selectedRegion, setSelectedRegion] = useState<string | null>(null);
const [hoveredRegion, setHoveredRegion] = useState<string | null>(null); const [hoveredRegion, setHoveredRegion] = useState<string | null>(null);
const [tooltipPosition, setTooltipPosition] = useState<{ x: number; y: number } | null>(null); const [tooltipPosition, setTooltipPosition] = useState<{ x: number; y: number } | null>(null);
const [chartOption, setChartOption] = useState<WrStatusChartProps>({} as WrStatusChartProps)
const svgContainerRef = useRef<HTMLDivElement>(null); const svgContainerRef = useRef<HTMLDivElement>(null);
const [chartData] = useState<any[]>([
{
label : '서울',
하수 : 4,
빗물 : 816,
중수도 : 371,
온배수 : 0
},
{
label : '부산',
하수 : 13,
빗물 : 68,
중수도 : 20,
온배수 : 1
},
{
label : '대구',
하수 : 9,
빗물 : 294,
중수도 : 14,
온배수 : 2
},
{
label : '인천',
하수 : 17,
빗물 : 165,
중수도 : 35,
온배수 : 15
},
{
label : '광주',
하수 : 3,
빗물 : 74,
중수도 : 15,
온배수 : 15
},
{
label : '대전',
하수 : 2,
빗물 : 52,
중수도 : 11,
온배수 : 20
},
{
label : '울산',
하수 : 8,
빗물 : 111,
중수도 : 19,
온배수 : 30
},
{
label : '세종',
하수 : 9,
빗물 : 65,
중수도 : 0,
온배수 : 0
},
{
label : '경기',
하수 : 176,
빗물 : 1009,
중수도 : 252,
온배수 : 40
},
{
label : '강원',
하수 : 69,
빗물 : 69,
중수도 : 22,
온배수 : 0
},
{
label : '충북',
하수 : 38,
빗물 : 17,
중수도 : 91,
온배수 : 0
},
{
label : '충남',
하수 : 67,
빗물 : 54,
중수도 : 188,
온배수 : 0
},
{
label : '전북',
하수 : 55,
빗물 : 33,
중수도 : 220,
온배수 : 0
},
{
label : '전남',
하수 : 83,
빗물 : 16,
중수도 : 75,
온배수 : 0
},
{
label : '경북',
하수 : 81,
빗물 : 37,
중수도 : 70,
온배수 : 0
},
{
label : '경남',
하수 : 75,
빗물 : 27,
중수도 : 140,
온배수 : 0
},
{
label : '제주',
하수 : 8,
빗물 : 47,
중수도 : 64,
온배수 : 0
}
]);
const chartConfig = chartData.reduce((config, element) => {
config[element.label] = {
label: element.label,
color : "hsl(var(--chart-1))"
};
return config;
}, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig;
const chartOption = {
chartForm : CHART_FORM.BAR,
chartConfig : chartConfig,
chartData : chartData,
chartTitle : '',
chartClassName : "h-[300px] w-full",
graphSize : 40,
yFieldText : '시설(개소)',
showLegend : true
}
const colorLegend = [ const colorLegend = [
{ label: '하수', color: '#FF6B6B', key: 'sewage' }, { label: '하수', color: '#FF6B6B', key: 'sewage' },
{ label: '빗물', color: '#4ECDC4', key: 'rainwater' }, { label: '빗물', color: '#4ECDC4', key: 'rainwater' },
{ label: '중수도', color: '#45B7D1', key: 'reclaimed' }, { label: '중수도', color: '#45B7D1', key: 'reclaimed' },
{ label: '온배수', color: '#FED16A', key: 'thermal' }, { label: '온배수', color: '#FED16A', key: 'thermal' },
]; ];
const facilityTotalsColor = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A'];
const regionIdMap: Record<string, string> = {
서울: '서울특별시',
부산: '부산광역시',
대구: '대구광역시',
인천: '인천광역시',
광주: '광주광역시',
대전: '대전광역시',
울산: '울산광역시',
세종: '세종특별자치시',
경기: '경기도',
강원: '강원특별자치도',
충북: '충청북도',
충남: '충청남도',
전북: '전라북도',
전남: '전라남도',
경북: '경상북도',
경남: '경상남도',
제주: '제주특별자치도'
};
const tableData: TableData[] = [
{ region: '전국', sewage: '717(1,137,538)', rainwater: '3544(13,945)', reclaimed: '1018(222,476)', thermal: '123(492)' },
{ region: '서울특별시', sewage: '4(114,908)', rainwater: '816(430)', reclaimed: '371(341)', thermal: '0' },
{ region: '부산광역시', sewage: '13(146,197)', rainwater: '68(335)', reclaimed: '20(512)', thermal: '1(18)' },
{ region: '대구광역시', sewage: '9(102,380)', rainwater: '294(133)', reclaimed: '14(44)', thermal: '2(12)' },
{ region: '인천광역시', sewage: '17(57,691)', rainwater: '165(642)', reclaimed: '35(7,859)', thermal: '15(32)' },
{ region: '광주광역시', sewage: '3(28,738)', rainwater: '74(23)', reclaimed: '15(450)', thermal: '15(6)' },
{ region: '대전광역시', sewage: '2(11,966)', rainwater: '52(2)', reclaimed: '11(492)', thermal: '20(100)' },
{ region: '울산광역시', sewage: '8(36,076)', rainwater: '111(39)', reclaimed: '19(28,904)', thermal: '30(130)' },
{ region: '세종특별자치시', sewage: '9(2,555)', rainwater: '65(16)', reclaimed: '0(0)', thermal: '0' },
{ region: '경기도', sewage: '176(313,298)', rainwater: '1009(4,735)', reclaimed: '252(77,096)', thermal: '40(143)' },
{ region: '강원특별자치도', sewage: '69(19,677)', rainwater: '69(4)', reclaimed: '22(447)', thermal: '0' },
{ region: '충청북도', sewage: '38(15,607)', rainwater: '17(91)', reclaimed: '91(2,211)', thermal: '0' },
{ region: '충청남도', sewage: '67(41,368)', rainwater: '54(77)', reclaimed: '188(50,434)', thermal: '0' },
{ region: '전라북도', sewage: '55(42,671)', rainwater: '33(199)', reclaimed: '220(9,453)', thermal: '0' },
{ region: '전라남도', sewage: '83(23,560)', rainwater: '16(885)', reclaimed: '75(15,412)', thermal: '0' },
{ region: '경상북도', sewage: '81(129,081)', rainwater: '37(341)', reclaimed: '70(27,818)', thermal: '0' },
{ region: '경상남도', sewage: '75(50,101)', rainwater: '27(244)', reclaimed: '140(343)', thermal: '0' },
{ region: '제주특별자치도', sewage: '8(1,666)', rainwater: '47(5,746)', reclaimed: '64(660)', thermal: '0' },
];
const regionData: RegionData[] = useMemo(() => [
{ name: '서울', x: 170, y: 140, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '인천', x: 120, y: 150, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경기', x: 210, y: 210, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '강원', x: 330, y: 120, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충북', x: 260, y: 280, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충남', x: 100, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '세종', x: 180, y: 305, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대전', x: 195, y: 360, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전북', x: 170, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전남', x: 160, y: 600, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '광주', x: 120, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경북', x: 400, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경남', x: 310, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대구', x: 350, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '울산', x: 450, y: 500, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '부산', x: 420, y: 550, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '제주', x: 60, y: 750, values: [0.3, 0.3, 0.2, 0.2] },
], []);
const handleMarkerClick = (regionId: string) => { const handleMarkerClick = (regionId: string) => {
if (selectedRegion === regionId) { if (selectedRegion === regionId) {
@@ -241,7 +47,6 @@ const WrStatusPage: React.FC = () => {
} }
}; };
const createDonutMarker = useCallback((svg: SVGSVGElement, x: number, y: number, name: string, values: number[]) => { const createDonutMarker = useCallback((svg: SVGSVGElement, x: number, y: number, name: string, values: number[]) => {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A']; const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A'];
const radius = 26; const radius = 26;
@@ -252,7 +57,6 @@ const WrStatusPage: React.FC = () => {
console.warn(`Invalid region name: ${name}`); console.warn(`Invalid region name: ${name}`);
return; return;
} }
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g'); const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
g.setAttribute('transform', `translate(${x}, ${y})`); g.setAttribute('transform', `translate(${x}, ${y})`);
g.setAttribute('id', `marker-${name}`); g.setAttribute('id', `marker-${name}`);
@@ -336,6 +140,13 @@ const WrStatusPage: React.FC = () => {
svg.appendChild(g); svg.appendChild(g);
}, [handleMarkerClick, regionIdMap]); }, [handleMarkerClick, regionIdMap]);
useEffect(() => {
getDmStatusData('2023');
},[])
useEffect(() => { useEffect(() => {
const loadSVG = async () => { const loadSVG = async () => {
try { try {
@@ -393,6 +204,31 @@ const WrStatusPage: React.FC = () => {
}); });
} }
}, [selectedRegion]); }, [selectedRegion]);
useEffect(() => {
if(chartData.length>0){
const chartConfig = chartData.reduce((config, element) => {
config[element.label] = {
label: element.label,
color : "hsl(var(--chart-1))"
};
return config;
}, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig;
const Option = {
chartForm : CHART_FORM.BAR,
chartConfig : chartConfig,
chartData : chartData,
chartTitle : '',
chartClassName : "h-[300px] w-full",
graphSize : 40,
yFieldText : '시설(개소)',
showLegend : true
}
setChartOption(Option)
}else{
setChartOption({} as WrStatusChartProps)
}
}, [chartData]);
return ( return (
<div className="flex h-screen bg-[#F2F2F2] text-gray-800"> <div className="flex h-screen bg-[#F2F2F2] text-gray-800">
@@ -401,7 +237,6 @@ const WrStatusPage: React.FC = () => {
{/* 상단 제목 */} {/* 상단 제목 */}
<div className="mb-6 flex justify-between items-center"> <div className="mb-6 flex justify-between items-center">
<h2 className="text-2xl font-bold">물재이용 현황</h2> <h2 className="text-2xl font-bold">물재이용 현황</h2>
<div className="text-sm text-gray-500">관리자 ▼</div>
</div> </div>
{/* 콘텐츠 본문 */} {/* 콘텐츠 본문 */}
@@ -439,11 +274,11 @@ const WrStatusPage: React.FC = () => {
<div className="font-semibold mb-1">{hoveredRegion}</div> <div className="font-semibold mb-1">{hoveredRegion}</div>
<div className="space-y-1"> <div className="space-y-1">
{colorLegend.map(({ label, color, key }) => ( {colorLegend.map(({ label, color, key }) => (
<div key={key} className="flex items-center space-x-2"> <div key={key+'' +color} className="flex items-center space-x-2">
<span className="text-[12px] inline-block w-3 h-3 rounded-sm" style={{ backgroundColor: color }}></span> <span className="text-[12px] inline-block w-3 h-3 rounded-sm" style={{ backgroundColor: color }}></span>
<span className="text-[12px]"> <span className="text-[12px]">
{label}:{' '} {label}:{' '}
{tableData.find(d => d.region === hoveredRegion)?.[key as keyof TableData] ?? '-'} {statusData?.find(d => d.region === hoveredRegion)?.[key as keyof DmStatusDataType] || '-'}
</span> </span>
</div> </div>
))} ))}
@@ -453,22 +288,12 @@ const WrStatusPage: React.FC = () => {
{/* 범례 */} {/* 범례 */}
<div className="absolute bottom-2 right-2 bg-white rounded-lg shadow-md p-4 text-sm space-y-2"> <div className="absolute bottom-2 right-2 bg-white rounded-lg shadow-md p-4 text-sm space-y-2">
<div className="flex items-center space-x-2"> {facilityTotals?.map((item, index) => (
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#FF6B6B'}}></span> <div key ={'fcltTotal' +index}className="flex items-center space-x-2">
<span className="text-[12px] text-gray-900">하수재이용시설 (총 717개소)</span> <span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor:facilityTotalsColor[index]}}></span>
</div> <span className="text-[12px] text-gray-900">{item}</span>
<div className="flex items-center space-x-2"> </div>
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#4ECDC4'}}></span> )) }
<span className="text-[12px] text-gray-900">빗물이용시설 (총 3,730개소)</span>
</div>
<div className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#45B7D1'}}></span>
<span className="text-[12px] text-gray-900">중수도시설 (총 1,074개소)</span>
</div>
<div className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#FED16A'}}></span>
<span className="text-[12px] text-gray-900">온배수시설 (총 201개소)</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -479,10 +304,10 @@ const WrStatusPage: React.FC = () => {
{/* 재이용시설현황 표 */} {/* 재이용시설현황 표 */}
<div className="bg-white rounded-xl shadow border border-[#DBE2E6] overflow-hidden"> <div className="bg-white rounded-xl shadow border border-[#DBE2E6] overflow-hidden">
{/* 타이틀 + 버튼 영역 */} {/* 타이틀 + 버튼 영역 */}
<div className="flex justify-between items-center border-b border-[#DBE2E6] px-4 py-3"> <div className="flex justify-between items-center border-b border-[#436d85] px-4 py-3">
<div> <div>
<h3 className="text-[12px] font-semibold">재이용시설현황(2023)</h3> <h3 className="text-[12px] font-semibold">재이용시설현황(2023)</h3>
<p className="text-[12px] text-[#999] font-medium">행정구역별 재이용시설현황(개소)</p> <p className="text-[12px] text-[#999] font-medium">행정구역별 재이용시설현황[개소(천m³/년)]</p>
</div> </div>
</div> </div>
<div className="p-4"> <div className="p-4">
@@ -493,14 +318,18 @@ const WrStatusPage: React.FC = () => {
<tr> <tr>
<th className="text-[12px] font-semibold px-4 py-2">번호</th> <th className="text-[12px] font-semibold px-4 py-2">번호</th>
<th className="text-[12px] font-semibold px-4 py-2">시도</th> <th className="text-[12px] font-semibold px-4 py-2">시도</th>
<th className="text-[12px] font-semibold px-4 py-2">하수(이용량,천𝓂³/년)</th> <th className="text-[12px] font-semibold px-4 py-2">하수재이용시설</th>
<th className="text-[12px] font-semibold px-4 py-2">빗물이용시설</th>
<th className="text-[12px] font-semibold px-4 py-2">중수도시설</th>
<th className="text-[12px] font-semibold px-4 py-2">온배수시설</th>
{/* <th className="text-[12px] font-semibold px-4 py-2">하수(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">빗물(이용량,천𝓂³/년)</th> <th className="text-[12px] font-semibold px-4 py-2">빗물(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">중수도(이용량,천𝓂³/년)</th> <th className="text-[12px] font-semibold px-4 py-2">중수도(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">온배수(이용량,천𝓂³/년)</th> <th className="text-[12px] font-semibold px-4 py-2">온배수(이용량,천𝓂³/년)</th> */}
</tr> </tr>
</thead> </thead>
<tbody className="divide-y"> <tbody className="divide-y">
{tableData.map((row, index) => ( {statusData?.map((row, index) => (
<tr key={index} className="hover:bg-gray-50"> <tr key={index} className="hover:bg-gray-50">
<td className="text-[12px] px-4 py-2 text-center"> <td className="text-[12px] px-4 py-2 text-center">
{index+1} {index+1}
@@ -526,16 +355,18 @@ const WrStatusPage: React.FC = () => {
</div> </div>
<div className="p-4 bg-[#f9fbfd]"> <div className="p-4 bg-[#f9fbfd]">
<div className="h-[305px] text-gray-500"> <div className="h-[305px] text-gray-500">
<MainChart {chartOption?
chartForm={chartOption.chartForm} <MainChart
chartConfig={chartOption.chartConfig} chartForm={chartOption.chartForm}
chartData={chartOption.chartData} chartConfig={chartOption.chartConfig}
chartTitle={chartOption.chartTitle} chartData={chartOption.chartData}
chartClassName={chartOption.chartClassName} chartTitle={chartOption.chartTitle}
graphSize={chartOption.graphSize} chartClassName={chartOption.chartClassName}
yFieldText={chartOption.yFieldText} graphSize={chartOption.graphSize}
showLegend={chartOption.showLegend} yFieldText={chartOption.yFieldText}
/> showLegend={chartOption.showLegend}
/>
:<></>}
</div> </div>
</div> </div>
</div> </div>
@@ -545,5 +376,3 @@ const WrStatusPage: React.FC = () => {
</div> </div>
); );
}; };
export default WrStatusPage;
+74
View File
@@ -0,0 +1,74 @@
import type { DmStatusChartType, DmStatusDataType, RegionData, } from "../store/wrStatus/type";
export const regionData:RegionData[] = [
{ name: '서울', x: 170, y: 140, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '인천', x: 120, y: 150, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경기', x: 210, y: 210, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '강원', x: 330, y: 120, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충북', x: 260, y: 280, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충남', x: 100, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '세종', x: 180, y: 305, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대전', x: 195, y: 360, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전북', x: 170, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전남', x: 160, y: 600, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '광주', x: 120, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경북', x: 400, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경남', x: 310, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대구', x: 350, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '울산', x: 450, y: 500, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '부산', x: 420, y: 550, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '제주', x: 60, y: 750, values: [0.3, 0.3, 0.2, 0.2] },
]
export const regionIdMap: Record<string, string> = {
서울: '서울특별시',
부산: '부산광역시',
대구: '대구광역시',
인천: '인천광역시',
광주: '광주광역시',
대전: '대전광역시',
울산: '울산광역시',
세종: '세종특별자치시',
경기: '경기도',
강원: '강원특별자치도',
충북: '충청북도',
충남: '충청남도',
전북: '전라북도',
전남: '전라남도',
경북: '경상북도',
경남: '경상남도',
제주: '제주특별자치도'
};
const makeRegion = (region: string) => {
if (region === '서울특별시') return '서울'
if (region === '부산광역시') return '부산'
if (region === '대구광역시') return '대구'
if (region === '인천광역시') return '인천'
if (region === '광주광역시') return '광주'
if (region === '대전광역시') return '대전'
if (region === '울산광역시') return '울산'
if (region === '세종특별자치시') return '세종'
if (region === '경기도') return '경기'
if (region === '강원특별자치도') return '강원'
if (region === '충청북도') return '충북'
if (region === '충청남도') return '충남'
if (region === '전라북도') return '전북'
if (region === '전라남도') return '전남'
if (region === '경상북도') return '경북'
if (region === '경상남도') return '경남'
if (region === '제주특별자치도') return '제주'
return region;
}
export const changeStatusMapData= (data: DmStatusDataType[]) : DmStatusChartType[]=> {
return data.map((item) => ({
label: makeRegion(item.region??''),
하수: item.sewage.split('(')[0]??'',
빗물: item.rainwater.split('(')[0]??'',
중수도: item.reclaimed.split('(')[0] ??'',
온배수: item.thermal.split('(')[0] ??'',
}));
}
+38 -19
View File
@@ -1,29 +1,48 @@
import { createStore } from 'zustand/vanilla'; import { createStore } from "zustand/vanilla";
import { CommonReducer, CommonState, type CommonStore, type CommonType } from './common'; import {
import { SdmReducer, SdmState, type SdmStore, type SdmType } from './sdmMng'; CommonReducer,
import { dmMapState, type DmMapType, type DmMapStore, DmMapReducer } from './map'; CommonState,
import { tokenManager } from '@/src/entities/auth/lib/token-manager'; type CommonStore,
type CommonType,
} from "./common";
import { SdmReducer, SdmState, type SdmStore, type SdmType } from "./sdmMng";
import {
dmMapState,
type DmMapType,
type DmMapStore,
DmMapReducer,
} from "./map";
import { tokenManager } from "@/src/entities/auth/lib/token-manager";
import {
DmStatusReducer,
dmStatusState,
type DmStatusStore,
type DmStatusType,
} from "./wrStatus";
export type DmStore = CommonStore & SdmStore &DmMapStore ; export type DmStore = CommonStore & SdmStore & DmMapStore & DmStatusStore;
export type DmState = CommonType & SdmType &DmMapType; export type DmState = CommonType & SdmType & DmMapType & DmStatusType;
export const StoreZus = (initState: DmState= { export const StoreZus = (
...CommonState, initState: DmState = {
...SdmState, ...CommonState,
...dmMapState, ...SdmState,
}) => { ...dmMapState,
...dmStatusState,
}
) => {
return createStore<DmStore>()((set) => { return createStore<DmStore>()((set) => {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
tokenManager.setToken("site-id-key", 'DM'); tokenManager.setToken("site-id-key", "DM");
tokenManager.setToken("site-theme-key", 'green'); tokenManager.setToken("site-theme-key", "green");
} }
return { return {
...initState, ...initState,
...CommonReducer(set), ...CommonReducer(set),
...SdmReducer(set), ...SdmReducer(set),
...DmMapReducer(set) ...DmMapReducer(set),
} ...DmStatusReducer(set),
}) };
} });
};
+63
View File
@@ -0,0 +1,63 @@
import { changeStatusMapData } from "@/app/common/comFunction";
import { fetchType, getFetch } from "@/components/ui/api";
import type {
DmStatusDataType,
DmStatusChartType,
} from "./type";
export type DmStatusActions = {
getDmStatusData(year: string): void;
};
export type DmStatusType = {
dmStatus: {
statusData: DmStatusDataType[];
facilityTotals: string[];
chartData: DmStatusChartType[];
};
};
export const dmStatusState: DmStatusType = {
dmStatus: {
statusData: [],
facilityTotals: [],
chartData: [],
},
};
export type DmStatusStore = DmStatusType & DmStatusActions;
export const DmStatusReducer = (set: any): DmStatusActions => {
return {
getDmStatusData: async (year: string) => {
const data = await getFetch(fetchType.WR, "/daemin/" + year);
let isData:DmStatusDataType[] =[]
if(data.data&&data.data.length>0){
isData=data.data
}else{
fetch(`data/wrStatusData.json`).then((res) => res.json()).then((json) => isData=json)//만약 백엔드에서 못가져올경우 방어책
}
const orgin: DmStatusDataType[] = isData;
const chartData = changeStatusMapData(orgin);
const facilityTotals = [
"하수재이용시설" + "(총" + orgin[0]?.sewage.split("(")[0] + "개소)",
"빗물재이용시설" + "(총" + orgin[0]?.rainwater.split("(")[0] + "개소)",
"중수도재이용시설" +
"(총" +
orgin[0]?.reclaimed.split("(")[0] +
"개소)",
"온배수재이용시설" + "(총" + orgin[0]?.thermal.split("(")[0] + "개소)",
];
set((state: DmStatusType) => ({
...state,
dmStatus: {
...state.dmStatus,
statusData: data.data,
chartData: chartData,
facilityTotals: facilityTotals,
},
}));
},
};
};
+32
View File
@@ -0,0 +1,32 @@
export type DmStatusDataType = {
region: string;
sewage: string;
rainwater: string;
reclaimed: string;
thermal: string;
};
export type DmStatusFcltType = {
sewageFclt: string;
rainwaterFclt: string;
reclaimedFclt: string;
thermalFclt: string;
};
export type DmStatusChartType = {
label: string,
하수: string,
빗물: string,
중수도: string,
온배수: string,
}
export type RegionData = {
name: string;
x: number;
y: number;
values: number[];
}
+20
View File
@@ -0,0 +1,20 @@
[
{ "region": "전국", "sewage": "717(1,137,538)", "rainwater": "3544(13,945)", "reclaimed": "1018(222,476)", "thermal": "123(492)" },
{ "region": "서울특별시", "sewage": "4(114,908)", "rainwater": "816(430)", "reclaimed": "371(341)", "thermal": "0" },
{ "region": "부산광역시", "sewage": "13(146,197)", "rainwater": "68(335)", "reclaimed": "20(512)", "thermal": "1(18)" },
{ "region": "대구광역시", "sewage": "9(102,380)", "rainwater": "294(133)", "reclaimed": "14(44)", "thermal": "2(12)" },
{ "region": "인천광역시", "sewage": "17(57,691)", "rainwater": "165(642)", "reclaimed": "35(7,859)", "thermal": "15(32)" },
{ "region": "광주광역시", "sewage": "3(28,738)", "rainwater": "74(23)", "reclaimed": "15(450)", "thermal": "15(6)" },
{ "region": "대전광역시", "sewage": "2(11,966)", "rainwater": "52(2)", "reclaimed": "11(492)", "thermal": "20(100)" },
{ "region": "울산광역시", "sewage": "8(36,076)", "rainwater": "111(39)", "reclaimed": "19(28,904)", "thermal": "30(130)" },
{ "region": "세종특별자치시", "sewage": "9(2,555)", "rainwater": "65(16)", "reclaimed": "0(0)", "thermal": "0" },
{ "region": "경기도", "sewage": "176(313,298)", "rainwater": "1009(4,735)", "reclaimed": "252(77,096)", "thermal": "40(143)" },
{ "region": "강원특별자치도", "sewage": "69(19,677)", "rainwater": "69(4)", "reclaimed": "22(447)", "thermal": "0" },
{ "region": "충청북도", "sewage": "38(15,607)", "rainwater": "17(91)", "reclaimed": "91(2,211)", "thermal": "0" },
{ "region": "충청남도", "sewage": "67(41,368)", "rainwater": "54(77)", "reclaimed": "188(50,434)", "thermal": "0" },
{ "region": "전라북도", "sewage": "55(42,671)", "rainwater": "33(199)", "reclaimed": "220(9,453)", "thermal": "0" },
{ "region": "전라남도", "sewage": "83(23,560)", "rainwater": "16(885)", "reclaimed": "75(15,412)", "thermal": "0" },
{ "region": "경상북도", "sewage": "81(129,081)", "rainwater": "37(341)", "reclaimed": "70(27,818)", "thermal": "0" },
{ "region": "경상남도", "sewage": "75(50,101)", "rainwater": "27(244)", "reclaimed": "140(343)", "thermal": "0" },
{ "region": "제주특별자치도", "sewage": "8(1,666)", "rainwater": "47(5,746)", "reclaimed": "64(660)", "thermal": "0" }
]