diff --git a/apps/dm/.env.local b/apps/dm/.env.local index 4dce58c9d..47ff660f3 100644 --- a/apps/dm/.env.local +++ b/apps/dm/.env.local @@ -18,8 +18,7 @@ NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y} NEXT_PUBLIC_GATEWAY_URL=http://con.mind-one.co.kr:11083 # 개발 서버 API -#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성 -#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정 +# NEXT_PUBLIC_GATEWAY_URL=http://localhost:8883 # 개발 서버 API # 박이정 NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do diff --git a/apps/dm/app/(landing)/reuse/_components/BusinessSubNav.tsx b/apps/dm/app/(landing)/reuse/_components/BusinessSubNav.tsx new file mode 100644 index 000000000..6b4246412 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/_components/BusinessSubNav.tsx @@ -0,0 +1,242 @@ +"use client"; + +import Link from "next/link"; +import { useEffect, useMemo, useState } from "react"; +import { ChevronDown, ChevronUp } from "lucide-react"; + +export type AnchorSection = { + id: string; + label: string; +}; + +export type BusinessSubNavMenu = { + key: string; + label: string; + href?: string; + current?: boolean; + defaultOpen?: boolean; + sections?: AnchorSection[]; +}; + +type BusinessSubNavProps = { + menus?: BusinessSubNavMenu[]; + offsetTop?: number; + className?: string; +}; + +export default function BusinessSubNav({ + menus = [], + offsetTop = 120, + className = "", +}: BusinessSubNavProps) { + const [activeId, setActiveId] = useState(""); + const [openMenus, setOpenMenus] = useState>({}); + + const allSections = useMemo( + () => menus.flatMap((menu) => menu.sections ?? []), + [menus] + ); + + useEffect(() => { + const initialOpenState: Record = {}; + + menus.forEach((menu) => { + initialOpenState[menu.key] = menu.defaultOpen ?? menu.current ?? false; + }); + + setOpenMenus(initialOpenState); + }, [menus]); + + useEffect(() => { + if (!allSections.length) return; + + const observer = new IntersectionObserver( + (entries) => { + const visible = entries + .filter((entry) => entry.isIntersecting) + .sort((a, b) => b.intersectionRatio - a.intersectionRatio); + + if (visible[0]) { + setActiveId(visible[0].target.id); + } + }, + { + rootMargin: `-${offsetTop}px 0px -55% 0px`, + threshold: [0.2, 0.35, 0.5, 0.7], + } + ); + + const targets = allSections + .map((section) => document.getElementById(section.id)) + .filter(Boolean) as HTMLElement[]; + + targets.forEach((el) => observer.observe(el)); + + const hash = window.location.hash.replace("#", ""); + const initialActive = + allSections.find((section) => section.id === hash)?.id ?? + allSections[0]?.id ?? + ""; + + setActiveId(initialActive); + + return () => observer.disconnect(); + }, [allSections, offsetTop]); + + useEffect(() => { + if (!activeId) return; + + const parentMenu = menus.find((menu) => + (menu.sections ?? []).some((section) => section.id === activeId) + ); + + if (!parentMenu) return; + + setOpenMenus(() => { + const nextOpenState: Record = {}; + + menus.forEach((menu) => { + nextOpenState[menu.key] = menu.key === parentMenu.key; + }); + + return nextOpenState; + }); + }, [activeId, menus]); + + const handleMove = (id: string) => { + setActiveId(id); + + const target = document.getElementById(id); + if (!target) return; + + window.history.replaceState(null, "", `#${id}`); + + const top = target.getBoundingClientRect().top + window.scrollY - offsetTop; + + window.scrollTo({ + top, + behavior: "smooth", + }); + }; + + const toggleMenu = (key: string) => { + setOpenMenus((prev) => ({ + ...prev, + [key]: !prev[key], + })); + }; + + if (!menus.length) return null; + + return ( + + ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/business/_components/GlobalCaseSection.tsx b/apps/dm/app/(landing)/reuse/business/_components/GlobalCaseSection.tsx new file mode 100644 index 000000000..5d981d7de --- /dev/null +++ b/apps/dm/app/(landing)/reuse/business/_components/GlobalCaseSection.tsx @@ -0,0 +1,116 @@ +"use client"; + +import CaseImageSlider from "@/components/CaseImageSlider"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +// 구분선 +function Hr({ className = "" }: { className?: string }) { + return
; +} + +export default function GlobalCaseSection() { + const title = "해외 재이용 사례"; + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+
+
+ 사례 개요 + + +
+ +
+ +
+ 대만 + + +
+ +
+ +
+ 호주 + + +
+ +
+ +
+ 싱가포르 + + +
+ +
+ +
+ EU + + +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx b/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx new file mode 100644 index 000000000..374e3ddd4 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx @@ -0,0 +1,191 @@ +"use client"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function BlockTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +// 구분선 +function Hr({ className = "" }: { className?: string }) { + return
; +} + +type SupplyRow = { + facility: string; + usage: string; + amount: string; +}; + +function SupplyTable({ rows }: { rows: SupplyRow[] }) { + return ( +
+ + + + + + + + + + {rows.map((row, index) => ( + + + + + + ))} + +
+ 시설명 + + 이용용도 + + 공급량(㎥) +
+ {row.facility} + + {row.usage} + + {row.amount} +
+
+ ); +} + +function InfoList({ + projectName, + purpose, + totalCost, + treatment, +}: { + projectName: string; + purpose: string; + totalCost: string; + treatment: string; +}) { + return ( +
+
+ 사업명 +
    +
  • {projectName}
  • +
+
+ +
+ 사업목적 +
    +
  • {purpose}
  • +
+
+ +
+ 사업 주요 내용 +
    +
  • 총사업비 : {totalCost}
  • +
  • 처리공법 : {treatment}
  • +
+
+ +
+ 사업량 +
+
+ ); +} + +export default function GreywaterExampleSection() { + const title = "중수 재이용 사례"; + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+ +
+
+ 경기도 안산시 + + + + +
+ +
+ +
+ 경기도 용인시 + + + + +
+ +
+ +
+ 경기도 평택시 + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx b/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx new file mode 100644 index 000000000..d73fdf1a2 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx @@ -0,0 +1,72 @@ +"use client"; + +import CaseImageSlider from "@/components/CaseImageSlider"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +// 구분선 +function Hr({ className = "" }: { className?: string }) { + return
; +} + +export default function RainExampleSection() { + const title = "빗물 재이용 사례"; + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+ +
+ 경기도 수원시 + + +
+ +
+ +
+ 제주특별자치도 + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/business/_components/SewageExampleSection.tsx b/apps/dm/app/(landing)/reuse/business/_components/SewageExampleSection.tsx new file mode 100644 index 000000000..72ac9741a --- /dev/null +++ b/apps/dm/app/(landing)/reuse/business/_components/SewageExampleSection.tsx @@ -0,0 +1,256 @@ +"use client"; + +import CaseImageSlider from "@/components/CaseImageSlider"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +// 구분선 +function Hr({ className = "" }: { className?: string }) { + return
; +} + +export default function SewageExampleSection() { + const title = "하수처리수 재이용 사례"; + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+ +
+
+ 충청남도 보령시 + + + +
+ 사업명 +

+ 충남 보령 하수재이용 +
: 보령·신보령화력발전소에 하루 1만톤의 탈황용수 공급을 위해 + 보령하수처리시설의 하수처리수 재이용 사업 추진 +

+
+ +
+ +
+ 사업 방식 +

+ 2017년 한국환경공단과 사업대행 위 · 수탁 협약 체결 +

+
+ +
+ 사업 주요 내용 +

+ 처리공정 : 전처리 UF + 후처리 RO +
+ 시설용량 : 1만m³/일 +
+ 관로 : 8.7km +
+ 사업비 : 315억원 +
+ 위치: 충청남도 보령시 대청방조제로 322 일원 +

+
+ +
+ +
+ 특이사항 +

+ 국내 유일 하수재이용 공업용수 공급 재정사업으로 2016년 충남 서부권 + 가뭄 시 지역사회 기여 차원에서 기관간 MOU를 바탕으로 추진 +

+
+
+ +
+ +
+ 청주시 + + + +
+ 사업명 +

청주시 하수 재이용 시설

+
+ +
+ +
+ 사업 주요 내용 +

+ 청주시 하수처리수 재이용 민간투자사업(BTO) +
+ 공급량 : 35,000㎥/일 +
+ 공급관로 : 8.3㎞ +
+ 사업비 : 622억원 +
+ 수요처 : SK하이닉스 등 일반산업단지 +
+ 지역 : 충청북도 청주시 흥덕구 가락리 135-9번지 일원 +
+ 적용기술 : 분리막 UF, RO +

+
+
+ +
+ +
+ 구리시 도로자동청소시스템 + + + +
+ 사업명 +

+ 구리시 도로자동청소시스템 설치사업 +

+
+ +
+ +
+ 사업목적 +

+ 공공하수처리시설 발생 재이용수 일부를 도로자동청소시스템에 활용하여 + 미세먼지 저감 및 폭염 취약성 완화 +

+
+
+ +
+ +
+ 수원시 황구지천 + + + +
+ 사업명 +

+ 수원시 황구지천 하수처리수 재이용사업 +

+
+
+ +
+ +
+ 파주시 + + + +
+ 사업명 +

+ 경기도 파주시 하수재이용 +
+ 운정·금촌하수처리시설의 하수처리수를 막공법으로 재처리하여 파주 LCD + 산업단지에 공업용수 공급 +

+
+
+ +
+ +
+ 여수시 + + + +
+ 사업명 +

+ 여수시 하수처리수 재이용 민간 투자사업(BTO) +

+
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/business/layout.tsx b/apps/dm/app/(landing)/reuse/business/layout.tsx index c8017b0db..31ff075b2 100644 --- a/apps/dm/app/(landing)/reuse/business/layout.tsx +++ b/apps/dm/app/(landing)/reuse/business/layout.tsx @@ -1,6 +1,7 @@ "use client"; -import { ReactNode, useEffect, useMemo, useState } from "react"; +import type { ReactNode } from "react"; +import { useEffect, useMemo, useState } from "react"; import { usePathname } from "next/navigation"; import Lnb from "../_components/Lnb"; import BusinessSubNav from "../_components/BusinessSubNav"; @@ -67,4 +68,4 @@ export default function BusinessLayout({ children }: { children: ReactNode }) {
); -} \ No newline at end of file +} diff --git a/apps/dm/app/(landing)/reuse/business/page.tsx b/apps/dm/app/(landing)/reuse/business/page.tsx new file mode 100644 index 000000000..9386012b1 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/business/page.tsx @@ -0,0 +1,85 @@ +import SubPageHeader from "@/components/SubPageHeader"; +import BusinessSubNav, { type BusinessSubNavMenu } from "@/components/BusinessSubNav"; + +import RainExampleSection from "./_components/RainExampleSection"; +import GreywaterExampleSection from "./_components/GreywaterExampleSection"; +import SewageExampleSection from "./_components/SewageExampleSection"; +import GlobalCaseSection from "./_components/GlobalCaseSection"; + +const menus: BusinessSubNavMenu[] = [ + { + key: "example-rain", + label: "빗물 재이용 사례", + sections: [ + { id: "example-rain-suwon", label: "경기도 수원시" }, + { id: "example-rain-jeju", label: "제주특별자치도" }, + ], + }, + { + key: "example-greywater", + label: "중수 재이용 사례", + defaultOpen: false, + sections: [ + { id: "example-greywater-ansan", label: "경기도 안산시" }, + { id: "example-greywater-yongin", label: "경기도 용인시" }, + { id: "example-greywater-pyeongtaek", label: "경기도 평택시" }, + ], + }, + { + key: "example-sewage", + label: "하수처리수 재이용 사례", + defaultOpen: false, + sections: [ + { id: "example-sewage-bolyeong", label: "충청남도 보령시" }, + { id: "example-sewage-cheongju", label: "청주시" }, + { id: "example-sewage-guri", label: "구리시 도로자동청소시스템" }, + { id: "example-sewage-hwanggu", label: "수원시 황구지천" }, + { id: "example-sewage-paju", label: "파주시" }, + { id: "example-sewage-yeosu", label: "여수시" }, + ], + }, + { + key: "example-global", + label: "해외 재이용 사례", + defaultOpen: false, + sections: [ + { id: "example-global-overview", label: "사례 개요" }, + { id: "example-global-taiwan", label: "대만" }, + { id: "example-global-australia", label: "호주" }, + { id: "example-global-singapore", label: "싱가포르" }, + { id: "example-global-eu", label: "EU" }, + ], + }, +]; + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +export default function ExamplePage() { + return ( +
+ {/* 상단 헤더 */} + + + {/* 우측 앵커 네비 */} + + +
+ +
+ +
+ +
+ +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/cases/_components/GreywaterStatusSection.tsx b/apps/dm/app/(landing)/reuse/cases/_components/GreywaterStatusSection.tsx new file mode 100644 index 000000000..1f5f93b44 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/cases/_components/GreywaterStatusSection.tsx @@ -0,0 +1,461 @@ +"use client"; + +import React from "react"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +function SourceText() { + return ( +

+ 자료: 환경부(2024), 「2023 하수도 통계」 +

+ ); +} + +const tableStyles = { + container: "w-[1000px] mx-auto overflow-hidden", + table: "w-full table-fixed border-collapse text-center text-[16px]", + th: "border border-[#858F98] py-3 font-bold text-neutral-800", + td: "border border-[#858F98] py-3 text-neutral-700 font-medium break-keep", + headerBg: "bg-[#E3E7EA]", +}; + +export default function GreywaterStatusSection() { + const title = "중수도(현황)"; + + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+ +
+ {/* 1) 전체 중수도 설치 및 이용 현황 */} +
+ 전체 중수도 설치 및 이용 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + {[ + { + group: "전체", + rows: [ + ["시설수 (개소)", "576", "633", "682", "740", "819", "842"], + ["건축연면적 (만m²)", "1,494.2", "1,514.4", "1,524.9", "989.1", "1,104.3", "1,015.4"], + ["처리용량 (만m³/일)", "39.6", "40.0", "51.1", "47.1", "48.9", "50.7"], + ["사용량 (만m³/년)", "2,223.4", "1,165.2", "6,713.0", "4,681.7", "3,918.2", "898.4"], + ], + }, + { + group: "법적 대상", + rows: [ + ["시설수 (개소)", "146", "154", "156", "170", "166", "169"], + ["건축연면적 (만m²)", "674.9", "682.4", "736.1", "421.1", "434.9", "465.5"], + ["처리용량 (만m³/일)", "20.0", "20.1", "31.2", "22.8", "21.2", "24.7"], + ["사용량 (만m³/년)", "1,819.4", "712.8", "6,479.9", "4,416.8", "3,663.1", "616.1"], + ], + }, + { + group: "법적 비대상", + rows: [ + ["시설수 (개소)", "430", "479", "526", "570", "653", "673"], + ["건축연면적 (만m²)", "819.3", "832.0", "788.8", "568.0", "669.4", "549.9"], + ["처리용량 (만m³/일)", "19.6", "19.5", "19.9", "24.3", "27.7", "26.0"], + ["사용량 (만m³/년)", "404.0", "452.4", "233.1", "264.9", "255.1", "282.3"], + ], + }, + ].map((section, sIdx) => ( + + {section.rows.map((row, rIdx) => ( + + {rIdx === 0 && ( + + )} + {row.map((val, i) => { + const isFirstCol = i === 0; + const isHighlightedCol = [1, 3, 5].includes(i); + + return ( + + ))} + + ))} + +
+ 구분 + + 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {section.group} + + ); + })} +
+
+ + +
+
+ +
+ + {/* 2) 공장 및 발전시설 내 중수도 설치 현황 */} +
+ 공장 및 발전시설 내 중수도 설치 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + {[ + { + group: "전체", + rows: [ + ["시설수 (개소)", "125", "127", "139", "146", "151", "176"], + ["처리용량 (만m³/일)", "141.3", "141.0", "146.7", "189.0", "190.3", "166.5"], + ["사용량 (만m³/년)", "33,712", "29,300", "33,110", "22,284", "21,593", "21,349"], + ], + }, + { + group: "법적 대상", + rows: [ + ["시설수 (개소)", "59", "63", "78", "78", "82", "86"], + ["처리용량 (만m³/일)", "108.6", "109.7", "118.1", "159.5", "142.6", "119.4"], + ["사용량 (만m³/년)", "24,847", "24,021", "28,055", "17,959", "12,241", "12,296"], + ], + }, + { + group: "법적 비대상", + rows: [ + ["시설수 (개소)", "66", "64", "61", "68", "69", "90"], + ["처리용량 (만m³/일)", "32.7", "31.4", "28.7", "29.5", "47.7", "47.1"], + ["사용량 (만m³/년)", "8,864.9", "5,278.8", "5,054.7", "4,324.6", "9,353.3", "9,052.4"], + ], + }, + ].map((section, sIdx) => ( + + {section.rows.map((row, rIdx) => ( + + {rIdx === 0 && ( + + )} + {row.map((val, i) => { + const isFirstCol = i === 0; + const isHighlightedCol = [1, 3, 5].includes(i); + + return ( + + ))} + + ))} + +
+ 구분 + + 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {section.group} + + ); + })} +
+
+ + +
+
+ +
+ + {/* 3) 중수도 건축물별 이용량 현황 */} +
+ 중수도 건축물별 이용량 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + {[ + ["공동주택", "804.0", "245.8", "255.1", "282.3", "255.1", "282.3"], + ["판매시설", "1,447.5", "477.1", "802.1", "713.0", "972.3", "742.4"], + ["숙박시설", "458.5", "0.4", "177.0", "102.0", "123.3", "140.9"], + ["업무시설", "20.7", "0.3", "14.3", "44.9", "31.5", "37.4"], + ["의료시설", "97.7", "7.2", "63.7", "55.7", "85.1", "70.4"], + ["교육연구시설", "536.6", "1.5", "1,558.4", "772.2", "315.1", "66.7"], + ["운수·물류시설", "759.2", "34.2", "459.8", "259.8", "252.8", "410.4"], + ["기타", "453.1", "443.3", "3,126.8", "2,451.5", "1,880.8", "199.7"], + ["합계", "35,936.3", "30,466.6", "37,487.2", "25,480.6", "24,345.8", "22,247.6"], + ].map((row, idx) => ( + + {row.map((val, i) => ( + + ))} + + ))} + +
+ 구분 + + 이용량 (천m³/년) +
+ 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {val} +
+
+ + +
+
+ +
+ + {/* 4) 중수도 용도별 이용량 현황 */} +
+ 중수도 용도별 이용량 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + {[ + ["공업용수", "33,082", "28,719", "32,312", "21,707", "20,991", "20,470"], + ["세척·살수용수", "860.2", "146.5", "133.8", "100.7", "95.1", "149.9"], + ["조경용수", "403.7", "99.3", "3,297.0", "2,611.1", "1,827.0", "1,116.7"], + ["청소용수", "623.9", "764.2", "1,430.6", "879.7", "1,146.2", "286.0"], + ["수세식화장실용수", "530.0", "646.6", "183.5", "161.2", "216.6", "147.6"], + ["냉·난방용수", "150.1", "56.2", "57.5", "6.4", "0.9", "0.5"], + ["친수용수", "120.8", "18.5", "29.3", "8.2", "4.1", "2.8"], + ["기타", "165.6", "16.1", "43.2", "5.7", "64.0", "73.9"], + ].map((row, idx) => ( + + {row.map((val, i) => ( + + ))} + + ))} + +
+ 구분 + + 이용량 (천m³/년) +
+ 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {val} +
+
+ + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/cases/_components/RainStatusSection.tsx b/apps/dm/app/(landing)/reuse/cases/_components/RainStatusSection.tsx new file mode 100644 index 000000000..ec150d55b --- /dev/null +++ b/apps/dm/app/(landing)/reuse/cases/_components/RainStatusSection.tsx @@ -0,0 +1,381 @@ +"use client"; + +import React from "react"; + +// 공통 섹션 타이틀 컴포넌트 +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +// 구분선 +function Hr({ className = "" }: { className?: string }) { + return
; +} + +// 출처 텍스트 +function SourceText() { + return ( +

+ 자료: 환경부(2024), 「2023 하수도 통계」 +

+ ); +} + +const tableStyles = { + container: "w-[1000px] mx-auto overflow-hidden", + table: "w-full table-fixed border-collapse text-center text-[16px]", + th: "border border-[#858F98] py-3 font-bold text-neutral-800", + td: "border border-[#858F98] py-3 text-neutral-700 font-medium break-keep", + headerBg: "bg-[#E3E7EA]", +}; + +export default function RainStatusSection() { + const title = "빗물이용시설(현황)"; + + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+ +
+ {/* 1) 빗물이용시설의 건축물별 빗물이용량 현황 */} +
+ 빗물이용시설의 건축물별 빗물이용량 현황 + +
+
+ + + + + + + + + + + + + + + + + {[ + ["골프장", "6,771.8", "6,417.4", "8,371.6", "10,215.4", "11,360", "10,191.6"], + ["공공시설", "364", "325.2", "201.9", "244.6", "209.9", "299.6"], + ["공동주택", "291", "840.5", "804.2", "2,393.0", "2,386", "2,428.4"], + ["대규모점포", "169.9", "214.4", "58.4", "427.2", "371", "293.3"], + ["체육시설", "52.6", "44.7", "48.6", "75.3", "71.8", "77.6"], + ["학교", "33", "25.5", "22", "155.8", "165.4", "32.6"], + ["기타", "311.6", "901.2", "344.5", "537.8", "564", "621.2"], + ].map((row, idx) => ( + + {row.map((val, i) => ( + + ))} + + ))} + +
+ 구분 + + 빗물이용량 (천m³/년) +
+ 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {val} +
+
+ + +
+
+ +
+ + {/* 2) 빗물이용시설의 용도별 분포 (2023년 기준) */} +
+ 빗물이용시설의 용도별 분포 (2023년 기준) + +
+
+ + + + + + + + + + + + + + + + + + + + + {[ + ["청소·환경정화용수", "195", "32.7", "108.8", "24.9", "5.8", "2.6", "4.4", "2.9", "-", "68.1"], + ["세척·살수용수", "12", "1.4", "37", "35", "-", "-", "1.9", "-", "-", "0.2"], + ["조경용수", "3,165", "7,440.8", "13,554.1", "168.1", "2,421.9", "290.7", "66.2", "29", "10,044", "534.3"], + ["냉·난방수", "8", "1.6", "0.1", "-", "-", "-", "-", "0.1", "-", "-"], + ["공업용수", "6", "14.9", "53.2", "52.8", "-", "-", "-", "-", "-", "0.4"], + ["농업용수", "6.0", "0.5", "0.6", "-", "-", "-", "-", "-", "-", "0.6"], + ["기타", "48", "306.1", "155.6", "2.8", "-", "-", "0.6", "0.5", "147.5", "4.2"], + ["미기재", "103", "22.9", "34.8", "16.0", "0.6", "-", "4.6", "0.2", "-", "13.5"], + ["합계", "3,543", "7,820.8", "13,944.7", "299.6", "2,428.4", "293.3", "77.6", "32.6", "10,191.6", "621.2"], + ].map((row, idx) => ( + + {row.map((val, i) => { + const isHighlightedCol = [1, 2].includes(i); + + return ( + + ); + })} + + ))} + +
+ 용도 + + 개소수 +
+ (개소) +
+ 저류용량 +
+ (천m³) +
+ 빗물이용량 (천m³/년) +
+ 총사용량 + + 공공시설 + + 공동주택 + + 대규모점포 + + 체육시설 + + 학교 + + 골프장 + + 기타 +
+ {val} +
+
+ + +
+
+ +
+ + {/* 3) 빗물이용시설의 용도별 빗물이용량 현황 */} +
+ 빗물이용시설의 용도별 빗물이용량 현황 + +
+
+ + + + + + + + + + + + + + + + + {[ + ["청소·화장실용수", "126.5", "134.1", "96.5", "153.9", "140.5", "108.8"], + ["세척·살수용수", "14.8", "14.6", "9.5", "49.8", "49.7", "37.0"], + ["조경용수", "7,629.8", "8,496.2", "9,415.4", "13,360.4", "14,466.3", "13,554.1"], + ["친수용수", "1.0", "0.1", "0.1", "0.1", "0.1", "0.1"], + ["공업용수", "152.0", "77.0", "77.0", "75.4", "0.4", "53.2"], + ["농업용수", "4.4", "4.3", "4.3", "4.3", "0.6", "0.6"], + ["기타", "37.7", "42.6", "230.7", "394.3", "463.2", "155.6"], + ].map((row, idx) => ( + + {row.map((val, i) => ( + + ))} + + ))} + +
+ 용도 + + 빗물이용량 (천m³/년) +
+ 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {val} +
+
+ + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/cases/_components/SewageStatusSection.tsx b/apps/dm/app/(landing)/reuse/cases/_components/SewageStatusSection.tsx new file mode 100644 index 000000000..0a2b34d5d --- /dev/null +++ b/apps/dm/app/(landing)/reuse/cases/_components/SewageStatusSection.tsx @@ -0,0 +1,705 @@ +"use client"; + +import React from "react"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +function SourceText() { + return ( +

+ 자료: 환경부(2024), 「2023 하수도 통계」 +

+ ); +} + +const tableStyles = { + container: "w-[1000px] mx-auto overflow-hidden", + table: "w-full table-fixed border-collapse text-center text-[16px]", + th: "border border-[#858F98] py-3 font-bold text-neutral-800", + td: "border border-[#858F98] py-3 text-neutral-700 font-medium break-keep", + headerBg: "bg-[#E3E7EA]", +}; + +export default function SewageStatusSection() { + const title = "하수처리수 재이용시설(현황)"; + + return ( +
+ {/* 상단 타이틀 */} +
+

+ {title} + +

+
+ +
+ {/* 1) 연도별 하수처리수 재이용 현황 */} +
+ 연도별 하수처리수 재이용 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + {[ + { + group: "전체", + rows: [ + [ + "개소수 (개소)", + "671", + "681", + "698", + "704", + "714", + "717", + ], + [ + "하수처리량 (백만m³/년)", + "7,163.7", + "7,140.4", + "7,375.6", + "7,335.8", + "7,378.9", + "7,537.2", + ], + [ + "재이용량 (백만m³/년)", + "1,112.7", + "1,148.7", + "1,148.7", + "1,127.0", + "1,136.8", + "1,137.5", + ], + [ + "재이용률 (%)", + "17.4", + "16.5", + "15.5", + "14.1", + "14.3", + "14.4", + ], + ], + }, + { + group: "법적 대상", + rows: [ + [ + "개소수 (개소)", + "68", + "82", + "94", + "97", + "101", + "118", + ], + [ + "하수처리량 (백만m³/년)", + "761.2", + "839.0", + "935.3", + "1,158.7", + "1,220.6", + "1,473.6", + ], + [ + "재이용량 (백만m³/년)", + "162.2", + "190.6", + "218.5", + "244.6", + "247.2", + "324.9", + ], + [ + "재이용률 (%)", + "24.7", + "25.4", + "27.8", + "25.7", + "24.2", + "24.1", + ], + ], + }, + { + group: "법적 미대상", + rows: [ + [ + "개소수 (개소)", + "603", + "599", + "604", + "607", + "613", + "599", + ], + [ + "하수처리량 (백만m³/년)", + "6,402.5", + "6,301.4", + "6,440.3", + "6,177.1", + "6,158.3", + "6,063.5", + ], + [ + "재이용량 (백만m³/년)", + "950.6", + "958.1", + "926.2", + "882.4", + "889.5", + "812.7", + ], + [ + "재이용률 (%)", + "16.5", + "15.3", + "13.6", + "12.2", + "12.6", + "12.5", + ], + ], + }, + ].map((section, sIdx) => ( + + {section.rows.map((row, rIdx) => ( + + {rIdx === 0 && ( + + )} + {row.map((val, i) => { + const isFirstCol = i === 0; + const isHighlightedCol = [1, 3, 5].includes(i); + + return ( + + ))} + + ))} + +
+ 구분 + + 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {section.group} + + ); + })} +
+
+ + +
+
+ +
+ + {/* 2) 용도별 하수처리수 재이용 현황 */} +
+ 용도별 하수처리수 재이용 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + {[ + { label: "총 재이용량", type: "total", values: ["1,112.7", "1,148.7", "1,144.7", "1,127.0", "1,136.8", "1,137.5"] }, + { label: "장내 재이용", type: "category", values: ["520.6", "519.8", "513.9", "520.3", "502.2", "490.0"] }, + { label: "세척수", type: "red-item", values: ["177.9", "174.4", "169.4", "180.9", "196.8", "191.2"] }, + { label: "냉각수", type: "red-item", values: ["45.5", "46.8", "50.4", "40.6", "38.3", "41.7"] }, + { label: "청소수", type: "red-item", values: ["17.6", "21.2", "21.2", "21.7", "20.8", "20.5"] }, + { label: "조경용수", type: "red-item", values: ["0.1", "0.1", "-", "-", "-", "-"] }, + { label: "회생용수", type: "red-item", values: ["15.8", "16.7", "17.8", "15.7", "14.4", "14.0"] }, + { label: "장내급수도", type: "red-item", values: ["2.4", "-", "-", "-", "-", "-"] }, + { label: "장내기타용수", type: "red-item", values: ["261.3", "260.6", "255.0", "261.1", "231.8", "222.6"] }, + { label: "장외 재이용", type: "category", values: ["592.1", "628.9", "630.8", "606.7", "634.6", "647.5"] }, + { label: "청소·화장실용수", type: "blue-item", values: ["0.6", "0.4", "0.4", "0.4", "0.4", "0.4"] }, + { label: "세척·살수용수", type: "blue-item", values: ["5.6", "9.9", "2.9", "2.1", "3.0", "3.6"] }, + { label: "조경용수", type: "blue-item", values: ["10.3", "16.4", "5.9", "4.5", "8.9", "9.5"] }, + { label: "친수용수", type: "blue-item", values: ["7.8", "3.1", "3.1", "3.0", "10.9", "10.5"] }, + { label: "하천유지용수", type: "blue-item", values: ["480.5", "482.5", "496.2", "442.7", "471.7", "484.0"] }, + { label: "농업용수", type: "blue-item", values: ["12.2", "11.9", "13.4", "10.7", "10.6", "11.4"] }, + { label: "지하수 충전", type: "blue-item", values: ["0.0", "0.0", "0.0", "13.4", "0.0", "0.0"] }, + { label: "공업용수", type: "blue-item", values: ["75.2", "104.6", "108.9", "129.9", "129.0", "128.1"] }, + ].map((row, idx) => { + const isSubItem = row.type === "red-item" || row.type === "blue-item"; + const isLastInGroup = idx === 8 || idx === 17; + + return ( + + + + {row.values.map((val, i) => ( + + ))} + + ); + })} + +
+ 구분 + + 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {isSubItem ? ( + <> +
+
+ + {row.label} + + + ) : ( + + {row.label} + + )} +
+ {val} +
+
+ + +
+
+ +
+ + {/* 3) 하수처리시설 설치 및 이용 현황 */} +
+ 하수처리시설 설치 및 이용 현황 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + {[ + { + group: "전체", + rows: [ + [ + "시설수 (개소)", + "671", + "681", + "698", + "704", + "714", + "717", + ], + [ + "시설용량 (만m³/일)", + "25,846", + "26,067", + "26,244", + "26,492", + "26,586", + "26,766", + ], + [ + "처리용량 (만m³/일)", + "1,112.7", + "1,148.7", + "1,144.7", + "1,127.0", + "1,136.8", + "1,137.5", + ], + ], + }, + { + group: "법적 대상", + rows: [ + [ + "시설수 (개소)", + "68", + "82", + "94", + "97", + "101", + "118", + ], + [ + "시설용량 (만m³/일)", + "3,088.9", + "3,359.2", + "3,612.6", + "4,412.2", + "4,692.3", + "5,503.8", + ], + [ + "처리용량 (만m³/일)", + "162.2", + "190.6", + "218.5", + "244.6", + "247.2", + "324.9", + ], + ], + }, + { + group: "법적 미대상", + rows: [ + [ + "시설수 (개소)", + "603", + "599", + "604", + "607", + "613", + "599", + ], + [ + "시설용량 (만m³/일)", + "22,757", + "22,708", + "22,631", + "22,080", + "21,894", + "21,262", + ], + [ + "처리용량 (만m³/일)", + "950.6", + "958.1", + "926.2", + "882.4", + "889.5", + "812.7", + ], + ], + }, + ].map((section, sIdx) => ( + + {section.rows.map((row, rIdx) => ( + + {rIdx === 0 && ( + + )} + {row.map((val, i) => { + const isFirstCol = i === 0; + const isHighlightedCol = [1, 3, 5].includes(i); + + return ( + + ))} + + ))} + +
+ 구분 + + 2018 + + 2019 + + 2020 + + 2021 + + 2022 + + 2023 +
+ {section.group} + + ); + })} +
+
+ + +
+
+ +
+ + {/* 4) 시도별 하수처리수 재이용 현황 */} +
+ 시도별 하수처리수 재이용 현황 + +
+
+
+ (단위: 백만m³/일) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {[ + ["합계", "7,537.2", "1,137.5", "490.0", "647.5", "484.0", "128.1", "11.4", "24.0", "15.1%", ""], + ["서울특별시", "1,567.0", "114.9", "59.3", "55.6", "55.1", "-", "-", "0.5", "7.3%", ""], + ["부산광역시", "491.5", "146.2", "120.7", "25.5", "25.3", "-", "-", "0.2", "29.7%", ""], + ["대구광역시", "432.7", "102.4", "38.2", "64.2", "64.1", "-", "-", "0.1", "23.7%", ""], + ["인천광역시", "302.3", "57.7", "11.6", "46.1", "29.2", "12.1", "0.5", "4.3", "19.1%", ""], + ["광주광역시", "211.1", "28.7", "6.5", "22.3", "22.2", "-", "-", "0.1", "13.6%", ""], + ["대전광역시", "244.6", "11.9", "11.9", "0.68", "0.0", "-", "-", "0.1", "4.9%", ""], + ["울산광역시", "235.1", "36.1", "6.1", "29.9", "29.7", "0.2", "-", "-", "15.3%", ""], + ["세종특별자치시", "38.5", "2.5", "2.0", "0.5", "0.4", "-", "0.2", "-", "6.6%", ""], + ["경기도", "1,926.8", "313.3", "122.2", "191.0", "153.0", "33.3", "0.4", "4.3", "16.3%", ""], + ["강원도", "230.4", "19.6", "15.4", "4.2", "2.1", "-", "-", "2.1", "8.5%", ""], + ["충청북도", "190.9", "15.6", "6.3", "9.2", "7.4", "0.6", "-", "1.2", "8.2%", ""], + ["충청남도", "241.5", "41.4", "9.8", "31.5", "17.7", "8.6", "4.5", "0.8", "17.1%", ""], + ["전라북도", "292.4", "42.7", "7.5", "35.1", "33.5", "0.2", "1.0", "0.5", "14.6%", ""], + ["전라남도", "254.0", "23.6", "12.3", "11.3", "8.7", "0.0", "1.0", "1.6", "9.3%", ""], + ["경상북도", "378.4", "129.1", "33.7", "95.3", "20.8", "72.5", "0.8", "1.3", "34.1%", ""], + ["경상남도", "411.3", "50.1", "25.0", "25.0", "14.7", "0.5", "3.0", "6.9", "12.2%", ""], + ["제주특별자치도", "88.6", "1.7", "1.5", "0.12", "-", "-", "0.1", "-", "1.9%", ""], + ].map((row, idx) => ( + + {row.map((val, i) => ( + + ))} + + ))} + +
+ 시도 + + 연간 +
+ 하수 +
+ 처리량 +
+ 재이용현황 + + 재이용률 +
+ (%) +
+ 비고 +
+ 계 + + 장내 + + 장외 +
+ 소계 + + 하천유지용수 + + 공업용수 + + 농업용수 + + 기타용수 +
+ {val} +
+
+ + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/cases/page.tsx b/apps/dm/app/(landing)/reuse/cases/page.tsx new file mode 100644 index 000000000..1043827dd --- /dev/null +++ b/apps/dm/app/(landing)/reuse/cases/page.tsx @@ -0,0 +1,96 @@ +// DM 물 재이용 현황 페이지 +import BusinessSubNav, { type BusinessSubNavMenu } from "@/components/BusinessSubNav"; +import SubPageHeader from "@/components/SubPageHeader"; +import RainStatusSection from "./_components/RainStatusSection"; +import GreywaterStatusSection from "./_components/GreywaterStatusSection"; +import SewageStatusSection from "./_components/SewageStatusSection"; + +const menus: BusinessSubNavMenu[] = [ + { + key: "status-rain", + label: "빗물이용시설(현황)", + sections: [ + { + id: "status-rain-building", + label: "빗물이용시설의 건축물별 빗물이용량 현황", + }, + { + id: "status-rain-purpose-distribution", + label: "빗물이용시설의 용도별 분포 (2023년 기준)", + }, + { + id: "status-rain-purpose-usage", + label: "빗물이용시설의 용도별 빗물이용량 현황", + }, + ], + }, + { + key: "status-greywater", + label: "중수도(현황)", + defaultOpen: false, + sections: [ + { + id: "status-greywater-overall", + label: "전체 중수도 설치 및 이용 현황", + }, + { + id: "status-greywater-factory", + label: "공장 및 발전시설 내 중수도 설치 현황", + }, + { + id: "status-greywater-building", + label: "중수도 건축물별 이용량 현황", + }, + { + id: "status-greywater-usage", + label: "중수도 용도별 이용량 현황", + }, + ], + }, + { + key: "status-sewage", + label: "하수처리수 재이용시설(현황)", + defaultOpen: false, + sections: [ + { + id: "status-treated-year", + label: "연도별 하수처리수 재이용 현황", + }, + { + id: "status-treated-usage", + label: "용도별 하수처리수 재이용 현황", + }, + { + id: "status-treated-facility", + label: "하수처리시설 설치 및 이용 현황", + }, + { + id: "status-treated-region", + label: "시도별 하수처리수 재이용 현황", + }, + ], + }, +]; + +export default function StatusPage() { + return ( +
+ {/* 상단 헤더 */} + + {/* 우측 앵커 네비 */} + + +
+ + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/intro/_components/LawIntroSection.tsx b/apps/dm/app/(landing)/reuse/intro/_components/LawIntroSection.tsx new file mode 100644 index 000000000..de39aa798 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/intro/_components/LawIntroSection.tsx @@ -0,0 +1,123 @@ +"use client"; + +import React from "react"; +import Image, { type StaticImageData } from "next/image"; + +import lawPlan from "@/public/images/landing/intro/law_timeline.png"; +import planPerformance from "@/public/images/landing/intro/performance_left.png"; +import domesticChange from "@/public/images/landing/intro/domestic_textbox.png"; +import policyHistory from "@/public/images/landing/intro/policy_timeline.png"; +import lawRelation from "@/public/images/landing/intro/rel_note.png"; +import domesticLinkage from "@/public/images/landing/intro/linkage.png"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +function ImgCard({ src, alt }: { src: StaticImageData; alt: string }) { + return ( +
+ {alt} +
+ ); +} + +function SectionShell({ + id, + title, + children, + className = "", +}: { + id: string; + title: string; + children: React.ReactNode; + className?: string; +}) { + return ( +
+ {title} +
{children}
+
+ ); +} + +export default function LawIntroSection() { + const title = "물 재이용 법"; + + return ( +
+
+

+ {title} + +

+
+ +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/intro/_components/RainIntroSection.tsx b/apps/dm/app/(landing)/reuse/intro/_components/RainIntroSection.tsx new file mode 100644 index 000000000..4de564a54 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/intro/_components/RainIntroSection.tsx @@ -0,0 +1,99 @@ +"use client"; + +import React from "react"; +import Image, { type StaticImageData } from "next/image"; + +import rainSummary from "@/public/images/landing/intro/rainreuse_intro.png"; +import rainDuty from "@/public/images/landing/intro/rainreuse_mandatory.png"; +import rainDesign from "@/public/images/landing/intro/rainwater_design.png"; +import rainStandard from "@/public/images/landing/intro/rainwater_standards.png"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +function ImgCard({ src, alt }: { src: StaticImageData; alt: string }) { + return ( +
+ {alt} +
+ ); +} + +function SectionShell({ + id, + title, + children, + className = "", +}: { + id: string; + title: string; + children: React.ReactNode; + className?: string; +}) { + return ( +
+ {title} +
{children}
+
+ ); +} + +export default function RainIntroSection() { + const title = "빗물 이용시설"; + + return ( +
+
+

+ {title} + +

+
+ +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/intro/_components/ReuseWaterIntroSection.tsx b/apps/dm/app/(landing)/reuse/intro/_components/ReuseWaterIntroSection.tsx new file mode 100644 index 000000000..03b01e398 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/intro/_components/ReuseWaterIntroSection.tsx @@ -0,0 +1,96 @@ +"use client"; + +import React from "react"; +import Image, { type StaticImageData } from "next/image"; + +import greywaterIntro from "@/public/images/landing/intro/greywater_intro.png"; +import greywaterMandatory from "@/public/images/landing/intro/greywater_mandatory.png"; +import greywaterStandard from "@/public/images/landing/intro/greywater_standard.png"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +function ImgCard({ src, alt }: { src: StaticImageData; alt: string }) { + return ( +
+ {alt} +
+ ); +} + +function SectionShell({ + id, + title, + children, + className = "", +}: { + id: string; + title: string; + children: React.ReactNode; + className?: string; +}) { + return ( +
+ {title} +
{children}
+
+ ); +} + +export default function ReuseWaterIntroSection() { + const title = "중수도"; + + return ( +
+
+

+ {title} + +

+
+ +
+ + + + +
+ + + + + +
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/intro/_components/TreatedIntroSection.tsx b/apps/dm/app/(landing)/reuse/intro/_components/TreatedIntroSection.tsx new file mode 100644 index 000000000..ff3ece0fc --- /dev/null +++ b/apps/dm/app/(landing)/reuse/intro/_components/TreatedIntroSection.tsx @@ -0,0 +1,89 @@ +"use client"; + +import React from "react"; +import Image, { type StaticImageData } from "next/image"; + +import treatedwaterIntro from "@/public/images/landing/intro/treatedwater_intro.png"; +import treatedwaterMandatory from "@/public/images/landing/intro/treatedwater_mandatory.png"; + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +
+ +

{children}

+
+ ); +} + +function Hr({ className = "" }: { className?: string }) { + return
; +} + +function ImgCard({ src, alt }: { src: StaticImageData; alt: string }) { + return ( +
+ {alt} +
+ ); +} + +function SectionShell({ + id, + title, + children, + className = "", +}: { + id: string; + title: string; + children: React.ReactNode; + className?: string; +}) { + return ( +
+ {title} +
{children}
+
+ ); +} + +export default function TreatedIntroSection() { + const title = "하수처리수"; + + return ( +
+
+

+ {title} + +

+
+ +
+ + + + +
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(landing)/reuse/intro/page.tsx b/apps/dm/app/(landing)/reuse/intro/page.tsx new file mode 100644 index 000000000..5ee955604 --- /dev/null +++ b/apps/dm/app/(landing)/reuse/intro/page.tsx @@ -0,0 +1,86 @@ +// DM 물 재이용 소개 페이지 +import BusinessSubNav, { type BusinessSubNavMenu } from "@/components/BusinessSubNav"; +import SubPageHeader from "@/components/SubPageHeader"; +import LawIntroSection from "./_components/LawIntroSection"; +import RainIntroSection from "./_components/RainIntroSection"; +import ReuseWaterIntroSection from "./_components/ReuseWaterIntroSection"; +import TreatedIntroSection from "./_components/TreatedIntroSection"; + +const menus: BusinessSubNavMenu[] = [ + { + key: "intro-law", + label: "물 재이용 법", + sections: [ + { id: "law-plan", label: "법률 제·개정 및 기본계획 수립" }, + { id: "plan-performance", label: "제2차 계획 대비 실적 현황" }, + { id: "domestic-change", label: "우리나라의 수자원 현황 및 물이용 여건" }, + { id: "policy-history", label: "물 재이용 정책 변화 추이" }, + { id: "law-relation", label: "타법령과의 관계 검토" }, + { id: "domestic-linkage", label: "주요 국가계획의 정책방향과 연계한 물 재이용 정책 필요" }, + ], + }, + { + key: "intro-rain", + label: "빗물 이용시설", + defaultOpen: false, + sections: [ + { id: "rain-intro", label: "빗물 재이용 소개" }, + { + id: "rain-mandatory", + label: "빗물이용시설 설치 관리 법적 의무 대상", + }, + { id: "rain-design", label: "빗물이용시설 설계 방안" }, + { + id: "rain-standards", + label: "빗물이용시설 시설기준 및 관리기준", + }, + ], + }, + { + key: "intro-greywater", + label: "중수도", + defaultOpen: false, + sections: [ + { id: "greywater-intro", label: "중수 재이용 소개" }, + { id: "greywater-mandatory", label: "중수도 설치 의무 대상" }, + { id: "greywater-standard", label: "중수도 시설기준 및 관리기준" }, + ], + }, + { + key: "intro-treated", + label: "하수처리수", + defaultOpen: false, + sections: [ + { id: "treatedwater-intro", label: "하수처리수 소개" }, + { + id: "treatedwater-mandatory", + label: "하수처리수 재이용시설 의무 대상", + }, + ], + }, +]; + +export default function IntroPage() { + return ( +
+ {/* 상단 헤더 */} + + {/* 우측 앵커 네비 */} + + + {/* 본문 */} +
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/dm/app/(with-layout)/status/_components/RainStatusSection.tsx b/apps/dm/app/(with-layout)/status/_components/RainStatusSection.tsx index ec150d55b..81b9a73c3 100644 --- a/apps/dm/app/(with-layout)/status/_components/RainStatusSection.tsx +++ b/apps/dm/app/(with-layout)/status/_components/RainStatusSection.tsx @@ -1,6 +1,16 @@ "use client"; -import React from "react"; +import { useEffect, useMemo } from "react"; +// import SubPageHeader from "@/components/SubPageHeader"; +import { useDmStore } from "@/app/store"; +import { formatUsage } from "@/app/common/transValueFormat"; +import type { + DmStatusBildTpYearsType, + DmStatusUsgBildTpType, + DmStatusUsgYearsType, + TableHeaderType, +} from "@/app/store/dm-status/type"; + // 공통 섹션 타이틀 컴포넌트 function SectionTitle({ children }: { children: React.ReactNode }) { @@ -17,15 +27,6 @@ function Hr({ className = "" }: { className?: string }) { return
; } -// 출처 텍스트 -function SourceText() { - return ( -

- 자료: 환경부(2024), 「2023 하수도 통계」 -

- ); -} - const tableStyles = { container: "w-[1000px] mx-auto overflow-hidden", table: "w-full table-fixed border-collapse text-center text-[16px]", @@ -34,7 +35,112 @@ const tableStyles = { headerBg: "bg-[#E3E7EA]", }; +const headerColors6 = [ + "bg-[#01ACE5]", + "bg-[#17AFC7]", + "bg-[#2CB2A9]", + "bg-[#42B58B]", + "bg-[#57B86D]", + "bg-[#81C784]", +]; +const headerColors8 = [ + "bg-[#01ACE5]", + "bg-[#10AED0]", + "bg-[#20B0BA]", + "bg-[#2FB2A5]", + "bg-[#3FB58F]", + "bg-[#4EB77A]", + "bg-[#5EB964]", + "bg-[#6DBB4F]", +]; export default function RainStatusSection() { + const getRainyByBildTpYears = useDmStore((state) => state.getRainyByBildTpYears); + const getRainyByUsgBildTp = useDmStore((state) => state.getRainyByUsgBildTp); + const getRainyByUsgYears = useDmStore((state) => state.getRainyByUsgYears); + const rainyYears = useDmStore((state) => state.rainy.rainyYears); + const selectYear = rainyYears.slice(-1)[0]; + const rainyByBildTpYearsHeader = useDmStore((state) => state.rainy.rainyByBildTpYearsHeader); + const rainyByBildTpYears = useDmStore((state) => state.rainy.rainyByBildTpYears); + const rainyByUsgBildTpHeader = useDmStore((state) => state.rainy.rainyByUsgBildTpHeader); + const rainyByUsgBildTp = useDmStore((state) => state.rainy.rainyByUsgBildTp); + const rainyByUsgYearsHeader = useDmStore((state) => state.rainy.rainyByUsgYearsHeader); + const rainyByUsgYears = useDmStore((state) => state.rainy.rainyByUsgYears); + const partBildTpHeader = useMemo( + () => rainyByUsgBildTpHeader.slice(3).map((header) => header.title), + [rainyByUsgBildTpHeader] + ); + + + // 출처 텍스트 + function SourceText() { + return ( +

+ 자료: 환경부(2024), 「{selectYear} 하수도 통계」 +

+ ); + } + + useEffect(() => { + void getRainyByBildTpYears(); + void getRainyByUsgBildTp(); + void getRainyByUsgYears(); + }, [getRainyByBildTpYears, getRainyByUsgBildTp, getRainyByUsgYears]); + + const renderPartHeaders = (headers: string[], headerColors: string[]) => { + return headers.map((header, index) => ( + + {header} + + )); + }; + + const renderBuildingUsageCells = ( + row: DmStatusBildTpYearsType | DmStatusUsgYearsType | DmStatusUsgYearsType, + headers: TableHeaderType[] + ) => { + const rowData = row as Record; + const firstHeaderId = headers[0]?.id; + const rowKey = firstHeaderId ? String(rowData[firstHeaderId] ?? "") : ""; + + return headers.map((header, index) => { + const value = rowData[header.id]; + + return ( + + {index === 0 ? value : formatUsage(value as string | number, 1000, 1)} + + ); + }); + }; + + const renderRainyByUsgBildTpCells = (row: DmStatusUsgBildTpType) => { + return rainyByUsgBildTpHeader.map((header, index) => { + const value = row[header.id as keyof DmStatusUsgBildTpType]; + const displayValue = + index === 0 + ? value + : header.id === "CNT" + ? Number(value).toLocaleString("ko-KR") + : formatUsage(value as string | number, 1000, 1); + + return ( + + {displayValue == 0.0 ? "-" : displayValue} + + ); + }); + }; + const title = "빗물이용시설(현황)"; return ( @@ -57,80 +163,21 @@ export default function RainStatusSection() { - - - - - - - - + {renderPartHeaders(rainyYears, headerColors6)} - {[ - ["골프장", "6,771.8", "6,417.4", "8,371.6", "10,215.4", "11,360", "10,191.6"], - ["공공시설", "364", "325.2", "201.9", "244.6", "209.9", "299.6"], - ["공동주택", "291", "840.5", "804.2", "2,393.0", "2,386", "2,428.4"], - ["대규모점포", "169.9", "214.4", "58.4", "427.2", "371", "293.3"], - ["체육시설", "52.6", "44.7", "48.6", "75.3", "71.8", "77.6"], - ["학교", "33", "25.5", "22", "155.8", "165.4", "32.6"], - ["기타", "311.6", "901.2", "344.5", "537.8", "564", "621.2"], - ].map((row, idx) => ( + {rainyByBildTpYears.map((row, idx) => ( - {row.map((val, i) => ( - - ))} + {renderBuildingUsageCells(row, rainyByBildTpYearsHeader)} ))} @@ -155,119 +202,19 @@ export default function RainStatusSection() {
+ 구분 + 빗물이용량 (천m³/년)
- 2018 - - 2019 - - 2020 - - 2021 - - 2022 - - 2023 -
- {val} -
- - - - + + + + - - - - - - - - + {renderPartHeaders(partBildTpHeader, headerColors8)} - {[ - ["청소·환경정화용수", "195", "32.7", "108.8", "24.9", "5.8", "2.6", "4.4", "2.9", "-", "68.1"], - ["세척·살수용수", "12", "1.4", "37", "35", "-", "-", "1.9", "-", "-", "0.2"], - ["조경용수", "3,165", "7,440.8", "13,554.1", "168.1", "2,421.9", "290.7", "66.2", "29", "10,044", "534.3"], - ["냉·난방수", "8", "1.6", "0.1", "-", "-", "-", "-", "0.1", "-", "-"], - ["공업용수", "6", "14.9", "53.2", "52.8", "-", "-", "-", "-", "-", "0.4"], - ["농업용수", "6.0", "0.5", "0.6", "-", "-", "-", "-", "-", "-", "0.6"], - ["기타", "48", "306.1", "155.6", "2.8", "-", "-", "0.6", "0.5", "147.5", "4.2"], - ["미기재", "103", "22.9", "34.8", "16.0", "0.6", "-", "4.6", "0.2", "-", "13.5"], - ["합계", "3,543", "7,820.8", "13,944.7", "299.6", "2,428.4", "293.3", "77.6", "32.6", "10,191.6", "621.2"], - ].map((row, idx) => ( - - {row.map((val, i) => { - const isHighlightedCol = [1, 2].includes(i); - - return ( - - ); - })} + {rainyByUsgBildTp.map((row, idx) => ( + + {renderRainyByUsgBildTpCells(row)} ))} @@ -292,80 +239,17 @@ export default function RainStatusSection() {
- 용도 - - 개소수 -
- (개소) -
- 저류용량 -
- (천m³) -
- 빗물이용량 (천m³/년) - 용도개소수
(개소)
저류용량
(천m³)
빗물이용량 (천m³/년)
- 총사용량 - - 공공시설 - - 공동주택 - - 대규모점포 - - 체육시설 - - 학교 - - 골프장 - - 기타 -
- {val} -
- - + + - - - - - - + {renderPartHeaders(rainyYears, headerColors6)} - {[ - ["청소·화장실용수", "126.5", "134.1", "96.5", "153.9", "140.5", "108.8"], - ["세척·살수용수", "14.8", "14.6", "9.5", "49.8", "49.7", "37.0"], - ["조경용수", "7,629.8", "8,496.2", "9,415.4", "13,360.4", "14,466.3", "13,554.1"], - ["친수용수", "1.0", "0.1", "0.1", "0.1", "0.1", "0.1"], - ["공업용수", "152.0", "77.0", "77.0", "75.4", "0.4", "53.2"], - ["농업용수", "4.4", "4.3", "4.3", "4.3", "0.6", "0.6"], - ["기타", "37.7", "42.6", "230.7", "394.3", "463.2", "155.6"], - ].map((row, idx) => ( + {rainyByUsgYears.map((row, idx) => ( - {row.map((val, i) => ( - - ))} + {renderBuildingUsageCells(row, rainyByUsgYearsHeader)} ))} diff --git a/apps/dm/app/(with-layout)/status/rain/page.tsx b/apps/dm/app/(with-layout)/status/rain/page.tsx index b690f3dee..88f041edf 100644 --- a/apps/dm/app/(with-layout)/status/rain/page.tsx +++ b/apps/dm/app/(with-layout)/status/rain/page.tsx @@ -1,6 +1,15 @@ "use client"; +import { useEffect, useMemo } from "react"; import SubPageHeader from "@/components/SubPageHeader"; +import { useDmStore } from "@/app/store"; +import { formatUsage } from "@/app/common/transValueFormat"; +import type { + DmStatusBildTpYearsType, + DmStatusUsgBildTpType, + DmStatusUsgYearsType, + TableHeaderType, +} from "@/app/store/dm-status/type"; // 공통 섹션 타이틀 컴포넌트 function SectionTitle({ children }: { children: React.ReactNode }) { @@ -17,14 +26,7 @@ function Hr({ className = "" }: { className?: string }) { return
; } -// 출처 텍스트 -function SourceText() { - return ( -

- 자료: 환경부(2024), 「2023 하수도 통계」 -

- ); -} + const tableStyles = { container: "w-[1000px] mx-auto overflow-hidden", @@ -34,7 +36,114 @@ const tableStyles = { headerBg: "bg-[#E3E7EA]", }; +const headerColors6 = [ + "bg-[#01ACE5]", + "bg-[#17AFC7]", + "bg-[#2CB2A9]", + "bg-[#42B58B]", + "bg-[#57B86D]", + "bg-[#81C784]", +]; +const headerColors8 = [ + "bg-[#01ACE5]", + "bg-[#10AED0]", + "bg-[#20B0BA]", + "bg-[#2FB2A5]", + "bg-[#3FB58F]", + "bg-[#4EB77A]", + "bg-[#5EB964]", + "bg-[#6DBB4F]", +]; + + export default function RainwaterStatusPage() { + const getRainyByBildTpYears = useDmStore((state) => state.getRainyByBildTpYears); + const getRainyByUsgBildTp = useDmStore((state) => state.getRainyByUsgBildTp); + const getRainyByUsgYears = useDmStore((state) => state.getRainyByUsgYears); + const rainyYears = useDmStore((state) => state.rainy.rainyYears); + const selectYear = rainyYears.slice(-1)[0]; + const rainyByBildTpYearsHeader = useDmStore((state) => state.rainy.rainyByBildTpYearsHeader); + const rainyByBildTpYears = useDmStore((state) => state.rainy.rainyByBildTpYears); + const rainyByUsgBildTpHeader = useDmStore((state) => state.rainy.rainyByUsgBildTpHeader); + const rainyByUsgBildTp = useDmStore((state) => state.rainy.rainyByUsgBildTp); + const rainyByUsgYearsHeader = useDmStore((state) => state.rainy.rainyByUsgYearsHeader); + const rainyByUsgYears = useDmStore((state) => state.rainy.rainyByUsgYears); + const partBildTpHeader = useMemo( + () => rainyByUsgBildTpHeader.slice(3).map((header) => header.title), + [rainyByUsgBildTpHeader] + ); + + + // 출처 텍스트 + function SourceText() { + return ( +

+ 자료: 환경부(2024), 「{selectYear} 하수도 통계」 +

+ ); + } + + useEffect(() => { + void getRainyByBildTpYears(); + void getRainyByUsgBildTp(); + void getRainyByUsgYears(); + }, [getRainyByBildTpYears, getRainyByUsgBildTp, getRainyByUsgYears]); + + const renderPartHeaders = (headers: string[], headerColors: string[]) => { + return headers.map((header, index) => ( +
+ )); + }; + + const renderBuildingUsageCells = ( + row: DmStatusBildTpYearsType | DmStatusUsgYearsType | DmStatusUsgYearsType, + headers: TableHeaderType[] + ) => { + const rowData = row as Record; + const firstHeaderId = headers[0]?.id; + const rowKey = firstHeaderId ? String(rowData[firstHeaderId] ?? "") : ""; + + return headers.map((header, index) => { + const value = rowData[header.id]; + + return ( + + ); + }); + }; + + const renderRainyByUsgBildTpCells = (row: DmStatusUsgBildTpType) => { + return rainyByUsgBildTpHeader.map((header, index) => { + const value = row[header.id as keyof DmStatusUsgBildTpType]; + const displayValue = + index === 0 + ? value + : header.id === "CNT" + ? Number(value).toLocaleString("ko-KR") + : formatUsage(value as string | number, 1000, 1); + + return ( + + ); + }); + }; + return (
구분 -
- - - - - - + {renderPartHeaders(rainyYears, headerColors6)} - {[ - ["골프장", "6,771.8", "6,417.4", "8,371.6", "10,215.4", "11,360", "10,191.6"], - ["공공시설", "364", "325.2", "201.9", "244.6", "209.9", "299.6"], - ["공동주택", "291", "840.5", "804.2", "2,393.0", "2,386", "2,428.4"], - ["대규모점포", "169.9", "214.4", "58.4", "427.2", "371", "293.3"], - ["체육시설", "52.6", "44.7", "48.6", "75.3", "71.8", "77.6"], - ["학교", "33", "25.5", "22", "155.8", "165.4", "32.6"], - ["기타", "311.6", "901.2", "344.5", "537.8", "564", "621.2"], - ].map((row, idx) => ( + {rainyByBildTpYears.map((row, idx) => ( - {row.map((val, i) => ( - - ))} + {renderBuildingUsageCells(row, rainyByBildTpYearsHeader)} ))} @@ -108,7 +197,7 @@ export default function RainwaterStatusPage() { {/* 2) 빗물이용시설의 용도별 분포 (2023년 기준) */}
- 빗물이용시설의 용도별 분포 (2023년 기준) + 빗물이용시설의 용도별 분포 ({selectYear}년 기준)
- 용도 - - 빗물이용량 (천m³/년) - 용도빗물이용량 (천m³/년)
- 2018 - - 2019 - - 2020 - - 2021 - - 2022 - - 2023 -
- {val} -
+ {header} + + {index === 0 ? value : formatUsage(value as string | number, 1000, 1)} + + {displayValue == 0.0 ? "-" : displayValue} + + 빗물이용량 (천m³/년)
201820192020202120222023
- {val} -
@@ -120,40 +209,13 @@ export default function RainwaterStatusPage() { - - - - - - - - + {renderPartHeaders(partBildTpHeader, headerColors8)} - {[ - ["청소·환경정화용수", "195", "32.7", "108.8", "24.9", "5.8", "2.6", "4.4", "2.9", "-", "68.1"], - ["세척·살수용수", "12", "1.4", "37", "35", "-", "-", "1.9", "-", "-", "0.2"], - ["조경용수", "3,165", "7,440.8", "13,554.1", "168.1", "2,421.9", "290.7", "66.2", "29", "10,044", "534.3"], - ["냉·난방수", "8", "1.6", "0.1", "-", "-", "-", "-", "0.1", "-", "-"], - ["공업용수", "6", "14.9", "53.2", "52.8", "-", "-", "-", "-", "-", "0.4"], - ["농업용수", "6.0", "0.5", "0.6", "-", "-", "-", "-", "-", "-", "0.6"], - ["기타", "48", "306.1", "155.6", "2.8", "-", "-", "0.6", "0.5", "147.5", "4.2"], - ["미기재", "103", "22.9", "34.8", "16.0", "0.6", "-", "4.6", "0.2", "-", "13.5"], - ["합계", "3,543", "7,820.8", "13,944.7", "299.6", "2,428.4", "293.3", "77.6", "32.6", "10,191.6", "621.2"], - ].map((row, idx) => ( - - {row.map((val, i) => { - const isHighlightedCol = [1, 2].includes(i); - return ( - - ); - })} + {rainyByUsgBildTp.map((row, idx) => ( + + {renderRainyByUsgBildTpCells(row)} ))} @@ -177,33 +239,13 @@ export default function RainwaterStatusPage() { - - - - - - + {renderPartHeaders(rainyYears, headerColors6)} - {[ - ["청소·화장실용수", "126.5", "134.1", "96.5", "153.9", "140.5", "108.8"], - ["세척·살수용수", "14.8", "14.6", "9.5", "49.8", "49.7", "37.0"], - ["조경용수", "7,629.8", "8,496.2", "9,415.4", "13,360.4", "14,466.3", "13,554.1"], - ["친수용수", "1.0", "0.1", "0.1", "0.1", "0.1", "0.1"], - ["공업용수", "152.0", "77.0", "77.0", "75.4", "0.4", "53.2"], - ["농업용수", "4.4", "4.3", "4.3", "4.3", "0.6", "0.6"], - ["기타", "37.7", "42.6", "230.7", "394.3", "463.2", "155.6"], - ].map((row, idx) => ( + {rainyByUsgYears.map((row, idx) => ( - {row.map((val, i) => ( - - ))} + {renderBuildingUsageCells(row, rainyByUsgYearsHeader)} ))} @@ -215,4 +257,4 @@ export default function RainwaterStatusPage() { ); -} \ No newline at end of file +} diff --git a/apps/dm/app/common/transValueFormat.tsx b/apps/dm/app/common/transValueFormat.tsx index 4d76d84e0..a9120d695 100644 --- a/apps/dm/app/common/transValueFormat.tsx +++ b/apps/dm/app/common/transValueFormat.tsx @@ -23,4 +23,26 @@ export default function TransValueFormat({value='', format=''}: CommonProps) { : String(value ?? '').replace(/\B(?=(\d{3})+(?!\d))/g, ",")} : <>{value} ) -} \ No newline at end of file +} + +export const formatUsage = ( + value: string | number, + unitSize: number = 1, + decimalPlaces: number = 0 + ) => { + const numeric = + typeof value === "number" ? value : Number(String(value).replaceAll(",", "")); + + if (Number.isNaN(numeric)) { + return String(value); + } + + const scaledValue = numeric / unitSize; + const roundedValue = + Math.round(scaledValue * 10 ** decimalPlaces) / 10 ** decimalPlaces; + + return roundedValue.toLocaleString("ko-KR", { + minimumFractionDigits: decimalPlaces, + maximumFractionDigits: decimalPlaces, + }); + }; \ No newline at end of file diff --git a/apps/dm/app/store/dm-status/index.tsx b/apps/dm/app/store/dm-status/index.tsx new file mode 100644 index 000000000..d7ced4d41 --- /dev/null +++ b/apps/dm/app/store/dm-status/index.tsx @@ -0,0 +1,243 @@ +import { fetchType, getFetch } from "@/components/ui/api"; +import type { + TableHeaderType, DmStatusBildTpYearsType, DmStatusUsgBildTpType, DmStatusUsgYearsType, + DmStatusLawYearsType, DmStatusSidoYearsType, +} from "./type"; +import { rainyByBildTpYearsHeader, rainyByUsgBildTpHeader, rainyByUsgYearsHeader } from "./type"; +import { rswtrByLawYearsHeader, rswtrByBildTpYearsHeader, rswtrByUsgYearsHeader } from "./type"; +import { pbnstByLawYearsHeader, pbnstByUsgYearsHeader, pbnstByCpcYearsHeader, pbnstBySidoYearsHeader } from "./type"; + + +export type DmStatusActions = { + getRainyByBildTpYears: () => Promise; // 1.대민 빗물재이용현황 건축물유형별 최근 6년간 + getRainyByUsgBildTp: () => Promise; // 2.대민 빗물재이용현황 이용용도별 건축물별 + getRainyByUsgYears: () => Promise; // 3.대민 빗물재이용현황 이용용도별 최근 6년간 + getRswtrByLawYears: (bildTpCond: string) => Promise; // 4.대민 중수도재이용현황 법적대상별 최근 6년간 + getRswtrByBildTpYears: () => Promise; // 5.대민 중수도재이용현황 건축물별 최근 6년간 + getRswtrByUsgYears: () => Promise; // 6.대민 중수도재이용현황 이용용도별 최근 6년간 + getPbnstByLawYears: () => Promise; // 7.대민 하수재이용현황 법적대상별 최근 6년간 + getPbnstByUsgYears: () => Promise; // 8.대민 하수재이용현황 이용용도별 최근 6년간 + getPbnstByCpcYears: () => Promise; // 9.대민 하수재이용현황 용량 최근 6년간 + getPbnstBySidoYears: () => Promise; // 10.대민 하수재이용현황 시도별 +}; + +export type DmStatusType = { + rainy: { + rainyYears: string[]; + rainyByBildTpYearsHeader: TableHeaderType[]; + rainyByUsgBildTpHeader: TableHeaderType[]; + rainyByUsgYearsHeader: TableHeaderType[]; + rainyByBildTpYears: DmStatusBildTpYearsType[]; + rainyByUsgBildTp: DmStatusUsgBildTpType[]; + rainyByUsgYears: DmStatusUsgYearsType[]; + }, + rswtr: { + rswtrYears: string[]; + rswtrByLawYearsHeader: TableHeaderType[]; + rswtrByBildTpYearsHeader: TableHeaderType[]; + rswtrByUsgYearsHeader: TableHeaderType[]; + rswtrByLawYears: DmStatusLawYearsType[]; + rswtrByBildTpYears: DmStatusBildTpYearsType[]; + rswtrByUsgYears: DmStatusUsgYearsType[]; + }, + pbnst: { + pbnstYears: string[]; + pbnstByLawYearsHeader: TableHeaderType[]; + pbnstByUsgYearsHeader: TableHeaderType[]; + pbnstByCpcYearsHeader: TableHeaderType[]; + pbnstBySidoYearsHeader: TableHeaderType[]; + pbnstByLawYears: DmStatusBildTpYearsType[]; + pbnstByUsgYears: DmStatusBildTpYearsType[]; + pbnstByCpcYears: DmStatusBildTpYearsType[]; + pbnstBySidoYears: DmStatusBildTpYearsType[]; + } +}; + +export const dmStatusState: DmStatusType = { + rainy: { + rainyYears: ["2019", "2020", "2021", "2022", "2023", "2024"], + rainyByBildTpYearsHeader: rainyByBildTpYearsHeader, + rainyByUsgBildTpHeader: rainyByUsgBildTpHeader, + rainyByUsgYearsHeader: rainyByUsgYearsHeader, + rainyByBildTpYears: [], + rainyByUsgBildTp: [], + rainyByUsgYears: [], + }, + rswtr: { + rswtrYears: ["2019", "2020", "2021", "2022", "2023", "2024"], + rswtrByLawYearsHeader: rswtrByLawYearsHeader, + rswtrByBildTpYearsHeader: rswtrByBildTpYearsHeader, + rswtrByUsgYearsHeader: rswtrByUsgYearsHeader, + rswtrByLawYears: [], + rswtrByBildTpYears: [], + rswtrByUsgYears: [], + }, + pbnst: { + pbnstYears: ["2019", "2020", "2021", "2022", "2023", "2024"], + pbnstByLawYearsHeader: pbnstByLawYearsHeader, + pbnstByUsgYearsHeader: pbnstByUsgYearsHeader, + pbnstByCpcYearsHeader: pbnstByCpcYearsHeader, + pbnstBySidoYearsHeader: pbnstBySidoYearsHeader, + pbnstByLawYears: [], + pbnstByUsgYears: [], + pbnstByCpcYears: [], + pbnstBySidoYears: [], + } +}; + +export type DmStatusStore = DmStatusType & DmStatusActions; + +export const DmStatusReducer = (set: any): DmStatusActions => { + return { + // 1. 대민 빗물재이용현황 건축물유형별 최근 6년간 + getRainyByBildTpYears: async () => { + const res = await getFetch(fetchType.WR, "/dmStatus/rainyByBildTpYears"); + const rainyByBildTpYears = Array.isArray(res?.data) ? res.data : []; + const rainyYears = (rainyByBildTpYears[0]?.YEAR ?? "") + .split(",") + .map((year) => year.trim()) + .filter(Boolean); + + set((state: DmStatusType) => ({ + ...state, + rainy: { + ...state.rainy, + rainyByBildTpYears, + rainyYears, + } + })); + + }, + // 2.대민 빗물재이용현황 이용용도별 건축물별 + getRainyByUsgBildTp: async () => { + const res = await getFetch(fetchType.WR, "/dmStatus/rainyByUsgBildTp"); + const rainyByUsgBildTp = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + rainy: { + ...state.rainy, + rainyByUsgBildTp, + } + })); + + }, + // 3.대민 빗물재이용현황 이용용도별 최근 6년간 + getRainyByUsgYears: async () => { + const res = await getFetch(fetchType.WR, "/dmStatus/rainyByUsgYears"); + const rainyByUsgYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + rainy: { + ...state.rainy, + rainyByUsgYears, + } + })); + + }, + // 4.대민 중수도재이용현황 법적대상별 최근 6년간 + getRswtrByLawYears: async (bildTpCond: string) => { + const res = await getFetch(fetchType.WR,`/dmStatus/rswtrByLawYears/${bildTpCond}`); + const rswtrByLawYears = Array.isArray(res?.data) ? res.data : []; + const maxYear = Number(rswtrByLawYears[0]?.MAXYR); + const rswtrYears = Number.isFinite(maxYear) + ? Array.from({ length: 6 }, (_, index) => String(maxYear - 5 + index)) + : dmStatusState.rswtr.rswtrYears; + + set((state: DmStatusType) => ({ + ...state, + rswtr: { + ...state.rswtr, + rswtrYears, + rswtrByLawYears, + } + })); + + }, + // 5.대민 중수도재이용현황 건축물별 최근 6년간 + getRswtrByBildTpYears: async () => { + const res = await getFetch(fetchType.WR,"/dmStatus/rswtrByBildTpYears"); + const rswtrByBildTpYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + rswtr: { + ...state.rswtr, + rswtrByBildTpYears, + } + })); + + }, + // 6.대민 중수도재이용현황 이용용도별 최근 6년간 + getRswtrByUsgYears: async () => { + const res = await getFetch(fetchType.WR,"/dmStatus/rswtrByUsgYears"); + const rswtrByUsgYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + rswtr: { + ...state.rswtr, + rswtrByUsgYears, + } + })); + + }, + // 7.대민 하수재이용현황 법적대상별 최근 6년간 + getPbnstByLawYears: async () => { + const res = await getFetch(fetchType.WR,"/dmStatus/pbnstByLawYears"); + const pbnstByLawYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + pbnst: { + ...state.pbnst, + pbnstByLawYears, + } + })); + + }, + // 8.대민 하수재이용현황 이용용도별 최근 6년간 + getPbnstByUsgYears: async () => { + const res = await getFetch(fetchType.WR,"/dmStatus/pbnstByUsgYears"); + const pbnstByUsgYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + pbnst: { + ...state.pbnst, + pbnstByUsgYears, + } + })); + + }, + // 9.대민 하수재이용현황 용량 최근 6년간 + getPbnstByCpcYears: async () => { + const res = await getFetch(fetchType.WR,"/dmStatus/pbnstByCpcYears"); + const pbnstByCpcYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + pbnst: { + ...state.pbnst, + pbnstByCpcYears, + } + })); + + }, + // 10.대민 하수재이용현황 시도별 + getPbnstBySidoYears: async () => { + const res = await getFetch(fetchType.WR,"/dmStatus/pbnstBySidoYears"); + const pbnstBySidoYears = Array.isArray(res?.data) ? res.data : []; + + set((state: DmStatusType) => ({ + ...state, + pbnst: { + ...state.pbnst, + pbnstBySidoYears, + } + })); + + }, + }; +}; diff --git a/apps/dm/app/store/dm-status/type.ts b/apps/dm/app/store/dm-status/type.ts new file mode 100644 index 000000000..986471d83 --- /dev/null +++ b/apps/dm/app/store/dm-status/type.ts @@ -0,0 +1,215 @@ +export type TableHeaderType = { + id: string; + title: string; + upName?: string; + upSequnce?: number; + align?: string; + row?: number; + rowSpan?: number; + colSpan?: number; + widthPercent?: number; +} + +export type DmStatusBildTpYearsType = { + BILD_TP: string; // 건물구분 + YEAR?: string; // 가로 연도 목록 + Y1: string | number; + Y2: string | number; + Y3: string | number; + Y4: string | number; + Y5: string | number; + Y6: string | number; +}; + +export type DmStatusUsgBildTpType = { + USG_NM: string; + CNT: string | number; + USEQTY: string | number; + SGBS_CPCTY: string | number; + PUB_FCT: string | number; + COMM_HOUSE: string | number; + MEGA_STORE: string | number; + GYM_FCT: string | number; + SCHOOL: string | number; + GOLF: string | number; + ETC: string | number; +}; + +export type DmStatusUsgYearsType = { + USG_NM: string; // 용도 + YEAR?: string; // 가로 연도 목록 + Y1: string | number; + Y2: string | number; + Y3: string | number; + Y4: string | number; + Y5: string | number; + Y6: string | number; + MAXYR?: string; // 최종 확정 연도 +}; + +export type DmStatusLawYearsType = { + COL1: string; // 전체, 법적 대상, 법적 미대상 + COL2: string; // 구분 + MAXYR?: string; // 최종 확정 연도 + Y1: string | number; + Y2: string | number; + Y3: string | number; + Y4: string | number; + Y5: string | number; + Y6: string | number; +}; + +export type DmStatusSidoYearsType = { + COL: string; // 컬럼 구분 + MAXYR?: string; // 최종 확정 연도 + Y1: string | number; + Y2: string | number; + Y3: string | number; + Y4: string | number; + Y5: string | number; + Y6: string | number; +}; + + + + +// 빗물이용시설의 건축물별 빗물이용량 현황 +export const rainyByBildTpYearsHeader: TableHeaderType[] = [ + { id: "BILD_TP", title: "구분", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; +export const rainyByBildTpYearsInit: DmStatusBildTpYearsType[] = [ + { BILD_TP: "골프장", Y1: "6,771.8", Y2: "6,417.4", Y3: "8,371.6", Y4: "10,215.4", Y5: "11,360", Y6: "10,191.6" }, + { BILD_TP: "공공시설", Y1: "364", Y2: "325.2", Y3: "201.9", Y4: "244.6", Y5: "209.9", Y6: "299.6" }, + { BILD_TP: "공동주택", Y1: "291", Y2: "840.5", Y3: "804.2", Y4: "2,393.0", Y5: "2,386", Y6: "2,428.4" }, + { BILD_TP: "대규모점포", Y1: "169.9", Y2: "214.4", Y3: "58.4", Y4: "427.2", Y5: "371", Y6: "293.3" }, + { BILD_TP: "체육시설", Y1: "52.6", Y2: "44.7", Y3: "48.6", Y4: "75.3", Y5: "71.8", Y6: "77.6" }, + { BILD_TP: "학교", Y1: "33", Y2: "25.5", Y3: "22", Y4: "155.8", Y5: "165.4", Y6: "32.6" }, + { BILD_TP: "기타", Y1: "311.6", Y2: "901.2", Y3: "344.5", Y4: "537.8", Y5: "564", Y6: "621.2" }, +]; +// 빗물이용시설의 용도별 분포 +export const rainyByUsgBildTpHeader: TableHeaderType[] = [ + { id: "USG_NM", title: "용도", row: 0, widthPercent: 15 }, + { id: "CNT", title: "개소수", row: 1, widthPercent: 5 }, + { id: "SGBS_CPCTY", title: "저류용량", row: 1, widthPercent: 5 }, + { id: "USEQTY", title: "총사용량", row: 1, widthPercent: 5 }, + { id: "PUB_FCT", title: "공공시설", row: 1, widthPercent: 5 }, + { id: "COMM_HOUSE", title: "공동주택", row: 0, widthPercent: 7 }, + { id: "MEGA_STORE", title: "대규모점포", row: 0, widthPercent: 10 }, + { id: "GYM_FCT", title: "체육시설", row: 1, widthPercent: 5 }, + { id: "SCHOOL", title: "학교", row: 1, widthPercent: 5 }, + { id: "GOLF", title: "골프장", row: 1, widthPercent: 5 }, + { id: "ETC", title: "기타", row: 1, widthPercent: 5 }, +]; +export const rainyByUsgBildTpInit: DmStatusUsgBildTpType[] = [ + { USG_NM: "청소·환경정화용수", CNT: "195", SGBS_CPCTY: "32.7", USEQTY: "108.8", PUB_FCT: "24.9", COMM_HOUSE: "5.8", MEGA_STORE: "2.6", GYM_FCT: "4.4", SCHOOL: "2.9", GOLF: "-", ETC: "68.1" }, + { USG_NM: "세척·살수용수", CNT: "12", SGBS_CPCTY: "1.4", USEQTY: "37", PUB_FCT: "35", COMM_HOUSE: "-", MEGA_STORE: "-", GYM_FCT: "1.9", SCHOOL: "-", GOLF: "-", ETC: "0.2" }, + { USG_NM: "조경용수", CNT: "3,165", SGBS_CPCTY: "7,440.8", USEQTY: "13,554.1", PUB_FCT: "168.1", COMM_HOUSE: "2,421.9", MEGA_STORE: "290.7", GYM_FCT: "66.2", SCHOOL: "29", GOLF: "10,044", ETC: "534.3" }, + { USG_NM: "냉·난방수", CNT: "8", SGBS_CPCTY: "1.6", USEQTY: "0.1", PUB_FCT: "-", COMM_HOUSE: "-", MEGA_STORE: "-", GYM_FCT: "-", SCHOOL: "0.1", GOLF: "-", ETC: "-" }, + { USG_NM: "공업용수", CNT: "6", SGBS_CPCTY: "14.9", USEQTY: "53.2", PUB_FCT: "52.8", COMM_HOUSE: "-", MEGA_STORE: "-", GYM_FCT: "-", SCHOOL: "-", GOLF: "-", ETC: "0.4" }, + { USG_NM: "농업용수", CNT: "6.0", SGBS_CPCTY: "0.5", USEQTY: "0.6", PUB_FCT: "-", COMM_HOUSE: "-", MEGA_STORE: "-", GYM_FCT: "-", SCHOOL: "-", GOLF: "-", ETC: "0.6" }, + { USG_NM: "기타", CNT: "48", SGBS_CPCTY: "306.1", USEQTY: "155.6", PUB_FCT: "2.8", COMM_HOUSE: "-", MEGA_STORE: "-", GYM_FCT: "0.6", SCHOOL: "0.5", GOLF: "147.5", ETC: "4.2" }, + { USG_NM: "미기재", CNT: "103", SGBS_CPCTY: "22.9", USEQTY: "34.8", PUB_FCT: "16.0", COMM_HOUSE: "0.6", MEGA_STORE: "-", GYM_FCT: "4.6", SCHOOL: "0.2", GOLF: "-", ETC: "13.5" }, + { USG_NM: "합계", CNT: "3,543", SGBS_CPCTY: "7,820.8", USEQTY: "13,944.7", PUB_FCT: "299.6", COMM_HOUSE: "2,428.4", MEGA_STORE: "293.3", GYM_FCT: "77.6", SCHOOL: "32.6", GOLF: "10,191.6", ETC: "621.2" }, +]; + +// 빗물이용시설의 용도별 빗물이용량 현황 +export const rainyByUsgYearsHeader: TableHeaderType[] = [ + { id: "USG_NM", title: "용도", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; +export const rainyByUsgYearsInit: DmStatusUsgYearsType[] = [ + { USG_NM: "청소·화장실용수", Y1: "126.5", Y2: "134.1", Y3: "96.5", Y4: "153.9", Y5: "140.5", Y6: "108.8" }, + { USG_NM: "세척·살수용수", Y1: "14.8", Y2: "14.6", Y3: "9.5", Y4: "49.8", Y5: "49.7", Y6: "37.0" }, + { USG_NM: "조경용수", Y1: "7,629.8", Y2: "8,496.2", Y3: "9,415.4", Y4: "13,360.4", Y5: "14,466.3", Y6: "13,554.1" }, + { USG_NM: "친수용수", Y1: "1.0", Y2: "0.1", Y3: "0.1", Y4: "0.1", Y5: "0.1", Y6: "0.1" }, + { USG_NM: "공업용수", Y1: "152.0", Y2: "77.0", Y3: "77.0", Y4: "75.4", Y5: "0.4", Y6: "53.2" }, + { USG_NM: "농업용수", Y1: "4.4", Y2: "4.3", Y3: "4.3", Y4: "4.3", Y5: "0.6", Y6: "0.6" }, + { USG_NM: "기타", Y1: "37.7", Y2: "42.6", Y3: "230.7", Y4: "394.3", Y5: "463.2", Y6: "155.6" }, +]; + +// 전체 중수도 설치 및 이용 현황 (공장 및 발전시설 제외) +export const rswtrByLawYearsHeader: TableHeaderType[] = [ + { id: "BILD_TP", title: "구분", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + +export const rswtrByBildTpYearsHeader: TableHeaderType[] = [ + { id: "BILD_TP", title: "구분", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + +export const rswtrByUsgYearsHeader: TableHeaderType[] = [ + { id: "USE_NM", title: "용도", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + +// 연도별 하수처리수 재이용 현황 +export const pbnstByLawYearsHeader: TableHeaderType[] = [ + { id: "BILD_TP", title: "구분", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + +// 용도별 하수처리수 재이용 현황 +export const pbnstByUsgYearsHeader: TableHeaderType[] = [ + { id: "BILD_TP", title: "구분", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + +// 하수처리시설 설치 및 이용 현황 +export const pbnstByCpcYearsHeader: TableHeaderType[] = [ + { id: "USE_NM", title: "용도", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + +// 시도별 하수처리수 재이용 현황 +export const pbnstBySidoYearsHeader: TableHeaderType[] = [ + { id: "USE_NM", title: "용도", row: 0, widthPercent: 15 }, + { id: "Y1", title: "2019", row: 1, widthPercent: 5 }, + { id: "Y2", title: "2020", row: 1, widthPercent: 5 }, + { id: "Y3", title: "2021", row: 1, widthPercent: 5 }, + { id: "Y4", title: "2022", row: 0, widthPercent: 7 }, + { id: "Y5", title: "2023", row: 0, widthPercent: 10 }, + { id: "Y6", title: "2024", row: 1, widthPercent: 5 }, +]; + diff --git a/apps/dm/app/store/store.tsx b/apps/dm/app/store/store.tsx index 25508bae2..c1d4fcdfd 100644 --- a/apps/dm/app/store/store.tsx +++ b/apps/dm/app/store/store.tsx @@ -18,8 +18,7 @@ import { dmStatusState, type DmStatusStore, type DmStatusType, -} from "./wrStatus"; - +} from "./dm-status"; export type DmStore = CommonStore & SdmStore & DmMapStore & DmStatusStore; export type DmState = CommonType & SdmType & DmMapType & DmStatusType;
빗물이용량 (천m³/년)
총사용량공공시설공동주택대규모점포체육시설학교골프장기타
- {val} -
빗물이용량 (천m³/년)
201820192020202120222023
- {val} -