cm:유역변경
This commit is contained in:
+2
-2
@@ -7,5 +7,5 @@ NEXT_PUBLIC_SERVER_API_URL=http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_LINK_BACKEND_API_HOST=http://rsone.iptime.org:10014
|
||||
NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2
|
||||
|
||||
# NEXT_PUBLIC_SERVER_API_URL2=http://con.mind-one.co.kr:11083/
|
||||
NEXT_PUBLIC_SERVER_API_URL2=http://192.168.1.222:8883/
|
||||
NEXT_PUBLIC_SERVER_API_URL2=http://con.mind-one.co.kr:11083/
|
||||
# NEXT_PUBLIC_SERVER_API_URL2=http://192.168.1.222:8883/
|
||||
@@ -5,6 +5,43 @@ import { ENDPOINT } from "@/shared/config";
|
||||
import type { OperWqltContent, OperFcltContent, ReuseStatusContent, OperationService
|
||||
} from "../model/fo-interface";
|
||||
|
||||
// 기준년도 조회
|
||||
export type YearState = {
|
||||
year: string | null;
|
||||
};
|
||||
export type YearStateActions = {
|
||||
setYear: (year: string | null) => void;
|
||||
};
|
||||
export type YearStore = YearState & YearStateActions;
|
||||
|
||||
export const defaultYearInitState: YearState = {
|
||||
year: null,
|
||||
};
|
||||
export const createYearStore = (initState: YearState = defaultYearInitState) =>
|
||||
createStore<YearStore>()((set) => ({
|
||||
...initState,
|
||||
setYear: (year) => set(() => ({ year })),
|
||||
}));
|
||||
export const yearStore = createYearStore();
|
||||
|
||||
// 유역
|
||||
export type BasinState = {
|
||||
selectedBasin: string;
|
||||
};
|
||||
export type BasinStateActions = {
|
||||
setSelectedBasin: (selectedBasin: string ) => void;
|
||||
};
|
||||
export type BasinStore = BasinState & BasinStateActions;
|
||||
export const defaultBasinInitState: BasinState = {
|
||||
selectedBasin: "한강",
|
||||
};
|
||||
export const createBasinStore = (initState: BasinState = defaultBasinInitState) =>
|
||||
createStore<BasinStore>()((set) => ({
|
||||
...initState,
|
||||
setSelectedBasin: (selectedBasin) => set(() => ({ selectedBasin })),
|
||||
}));
|
||||
export const basinStore = createBasinStore();
|
||||
|
||||
//수계별 시설운영 개소수 및 가동률
|
||||
export type OperFcltState = {
|
||||
operFcltStatus: OperFcltContent[] | null;
|
||||
@@ -50,6 +87,7 @@ const initialWqltData: OperWqltContent[] = [
|
||||
export const defaultInitOperWqltState: OperWqltState = {
|
||||
operWqltStatus: initialWqltData,
|
||||
};
|
||||
export const operFcltStore = createOperFcltStore();
|
||||
|
||||
// 물재이용 현황
|
||||
export type ReuseState = {
|
||||
@@ -73,29 +111,8 @@ export const createReuseStore = (initState: ReuseState = defaultInitReuseState)
|
||||
...initState,
|
||||
setReuseStatus: (reuseStatus) => set(() => ({ reuseStatus })),
|
||||
}));
|
||||
|
||||
// 기준년도 조회
|
||||
export type YearState = {
|
||||
year: string | null;
|
||||
};
|
||||
export type YearStateActions = {
|
||||
setYear: (year: string | null) => void;
|
||||
};
|
||||
export type YearStore = YearState & YearStateActions;
|
||||
|
||||
export const defaultYearInitState: YearState = {
|
||||
year: null,
|
||||
};
|
||||
export const createYearStore = (initState: YearState = defaultYearInitState) =>
|
||||
createStore<YearStore>()((set) => ({
|
||||
...initState,
|
||||
setYear: (year) => set(() => ({ year })),
|
||||
}));
|
||||
|
||||
// 전역으로 공유할 store 인스턴스
|
||||
export const operFcltStore = createOperFcltStore();
|
||||
export const reuseStore = createReuseStore();
|
||||
export const yearStore = createYearStore();
|
||||
|
||||
|
||||
export class OperationApiService implements OperationService {
|
||||
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { useStore } from "zustand";
|
||||
import styles from "./korea-basin-map.module.css"; // 추가
|
||||
import { basinStore } from "../api/fo-service";
|
||||
|
||||
const SVG_URL = "/images/region_map.svg"; // public 폴더에 region_map.svg 위치 필요
|
||||
|
||||
// 2. 유역 키를 매핑하는 로직 (예: "한강" -> "han")
|
||||
export const basinKeyMap: { [key: string]: string } = {
|
||||
"한강": "han",
|
||||
"금강": "geum",
|
||||
"낙동강": "nakdong",
|
||||
"영산강": "yeongsan",
|
||||
};
|
||||
// --- 라벨 좌표(수동 고정값) : inset 적용 영역 기준 퍼센트 또는 px 사용 ---
|
||||
// - 퍼센트: { x:0~1, y:0~1 } (권장: 반응형에 유리)
|
||||
// - 픽셀: { px:number, py:number } (inset 좌상단 원점 기준)
|
||||
const MANUAL_LABEL_POS = {
|
||||
han: { x: 0.52, y: 0.14 },
|
||||
geum: { x: 0.28, y: 0.47 },
|
||||
@@ -56,6 +68,7 @@ function fmt(n: number) {
|
||||
return new Intl.NumberFormat("ko-KR").format(n);
|
||||
}
|
||||
|
||||
|
||||
export function KoreaBasinMap() {
|
||||
const stageRef = useRef<HTMLDivElement>(null);
|
||||
const svgLayerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -65,12 +78,28 @@ export function KoreaBasinMap() {
|
||||
const rowsRef = useRef<HTMLTableSectionElement>(null);
|
||||
const colTitleRef = useRef<HTMLTableCellElement>(null);
|
||||
|
||||
const { selectedBasin } = useStore(basinStore);
|
||||
const selectedBasinKey = basinKeyMap[selectedBasin];
|
||||
// selectedBasinKey prop이 변경될 때 지도를 업데이트하는 useEffect
|
||||
useEffect(() => {
|
||||
if (selectedBasinKey) {
|
||||
const svg = svgLayerRef.current?.querySelector("svg");
|
||||
if (!svg) return;
|
||||
|
||||
// 모든 유역의 활성화 상태를 초기화합니다.
|
||||
svg.querySelectorAll('.basin.active').forEach(el => el.classList.remove('active'));
|
||||
|
||||
const targetGroup = svg.querySelector(`.basin[data-key="${selectedBasinKey}"]`) as SVGGElement | null;
|
||||
targetGroup?.classList.add('active');
|
||||
}
|
||||
}, [selectedBasinKey]);
|
||||
|
||||
useEffect(() => {
|
||||
let svg: SVGSVGElement | null = null;
|
||||
let gs: SVGGElement[] = [];
|
||||
let labels: HTMLDivElement[] = [];
|
||||
|
||||
console.log("Loading SVG from:", SVG_URL);
|
||||
// console.log("Loading SVG from:", SVG_URL);
|
||||
fetch(SVG_URL)
|
||||
.then((r) => {
|
||||
console.log("SVG fetch response:", r.status, r.statusText);
|
||||
@@ -173,6 +202,7 @@ export function KoreaBasinMap() {
|
||||
labels.forEach((l) => l.classList.remove("active"));
|
||||
};
|
||||
|
||||
// 유역정보
|
||||
function showFor(g: SVGGElement) {
|
||||
console.log("showFor called for:", g);
|
||||
const key = (g as SVGGElement & { dataset: { key: string; label: string } }).dataset.key;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useStore } from "zustand";
|
||||
import { tokenManager } from "@/entities/auth/lib/token-manager";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { KoreaBasinMap } from "../lib/korea-basin-map";
|
||||
import { KoreaBasinMap, basinKeyMap } from "../lib/korea-basin-map";
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
@@ -48,8 +49,7 @@ interface UserInfo {
|
||||
function DashboardPage() {
|
||||
const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
|
||||
const [error, setError] = useState("");
|
||||
const router = useRouter();
|
||||
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
const fetchUserInfo = async () => {
|
||||
console.log("fetchUserInfo called");
|
||||
|
||||
@@ -8,13 +8,17 @@ import BasinSelect from "./basIn-select";
|
||||
import { Doughnut } from "react-chartjs-2";
|
||||
import type { Chart as ChartJS } from "chart.js";
|
||||
// import type { OperFcltContent } from "../model/fo-interface";
|
||||
import { OperationApi, operFcltStore } from "../api/fo-service";
|
||||
import { OperationApi, operFcltStore, basinStore } from "../api/fo-service";
|
||||
|
||||
const FoFcltCntRt: React.FC = () => {
|
||||
const [year, setYear] = useState<string | null>(null);
|
||||
const [selectedBasin, setSelectedBasin] = useState<string>("한강");
|
||||
const { selectedBasin, setSelectedBasin } = useStore(basinStore);
|
||||
const operFcltStatus = useStore(operFcltStore, (state) => state.operFcltStatus);
|
||||
|
||||
const onBasinChange = (value: string) => {
|
||||
setSelectedBasin(value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
@@ -55,7 +59,7 @@ const FoFcltCntRt: React.FC = () => {
|
||||
<div className="card card-border">
|
||||
<div className="card-header text-foreground">
|
||||
<h3 className="text-2xl font-medium">수계별 시설운영 개소수 및 가동률</h3>
|
||||
<BasinSelect selectedBasin={selectedBasin} onValueChange={setSelectedBasin} />
|
||||
<BasinSelect selectedBasin={selectedBasin} onValueChange={onBasinChange} />
|
||||
</div>
|
||||
<div className="h-60 p-4">
|
||||
<div className="flex gap-2 h-full">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* 수계별 유입ㆍ방류수질 분석
|
||||
*/
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { useStore } from "zustand";
|
||||
import { Line } from 'react-chartjs-2';
|
||||
import BasinSelect from "./basIn-select";
|
||||
import {
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
Title, Tooltip, Legend, type ChartOptions,
|
||||
} from 'chart.js';
|
||||
import type { OperWqltContent } from "../model/fo-interface";
|
||||
import { OperationApi } from "../api/fo-service";
|
||||
import { OperationApi, basinStore } from "../api/fo-service";
|
||||
import { defaultInitOperWqltState } from "../api/fo-service";
|
||||
|
||||
// Chart.js 등록
|
||||
@@ -20,11 +21,15 @@ ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, T
|
||||
type WaterQualityType = 'BOD' | 'TOC' | 'SS' | 'TP' | 'TN';
|
||||
|
||||
const FoWqltInflEffl: React.FC = () => {
|
||||
const [selectedBasin, setSelectedBasin] = useState<string>("한강");
|
||||
const { selectedBasin, setSelectedBasin } = useStore(basinStore);
|
||||
const [selectedTab, setSelectedTab] = useState<WaterQualityType>('BOD');
|
||||
const [wqltData, setWqltData] = useState<OperWqltContent[]>([]);
|
||||
const tabs: WaterQualityType[] = ['BOD', 'TOC', 'SS', 'TP', 'TN'];
|
||||
|
||||
const onBasinChange = (value: string) => {
|
||||
setSelectedBasin(value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setWqltData(defaultInitOperWqltState.operWqltStatus);
|
||||
const fetchData = async () => {
|
||||
@@ -192,7 +197,7 @@ const FoWqltInflEffl: React.FC = () => {
|
||||
<div className="card card-border">
|
||||
<div className="card-header text-foreground">
|
||||
<h3 className="text-2xl font-medium">수계별 유입ㆍ방류수질 분석</h3>
|
||||
<BasinSelect selectedBasin={selectedBasin} onValueChange={setSelectedBasin} />
|
||||
<BasinSelect selectedBasin={selectedBasin} onValueChange={onBasinChange} />
|
||||
</div>
|
||||
<div className="h-60">
|
||||
<div style={{ padding: '4px', height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||
|
||||
Reference in New Issue
Block a user