Merge branch 'iipbs/sn/dev'
This commit is contained in:
@@ -235,6 +235,7 @@ const Map = () => {
|
||||
<>
|
||||
<div className="bg-container">
|
||||
<Gis
|
||||
showZoomLevel={true}
|
||||
height='h-screen'
|
||||
treeData={treeData}
|
||||
isSearch={false}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -295,6 +295,7 @@ const Map = () => {
|
||||
return (
|
||||
<div className="bg-container">
|
||||
<Gis
|
||||
showZoomLevel={true}
|
||||
treeData={treeData}
|
||||
isSearch={false}
|
||||
gisMaps={gisMaps}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,268 +1,279 @@
|
||||
'use client'
|
||||
import { CHART_FORM, type ChartConfig, MainChart, UiModal } from "@common/business_components";
|
||||
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import moment from 'moment';
|
||||
|
||||
import {
|
||||
CHART_FORM,
|
||||
type ChartConfig,
|
||||
MainChart,
|
||||
UiModal,
|
||||
} from '@common/business_components';
|
||||
import { SelectBox } from '@common/business_components/ui';
|
||||
import { Button, Input, Label } from '@common/components';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import moment from "moment";
|
||||
|
||||
import type { TInftwtAnls } from './aplcnYms';
|
||||
import * as fn from './aplcnYms';
|
||||
import { useInfilChartModalStore } from '../chartModalStore'; // 모달 상태 관리 스토어
|
||||
import { useInfilChartModalStore } from '../chartModalStore';
|
||||
|
||||
type ModalOpenProp = {
|
||||
pplMngNo?: string, // 관로관리번호
|
||||
}
|
||||
type DataType = { label: string; val: number };
|
||||
pplMngNo?: string; // 관로관리번호
|
||||
};
|
||||
|
||||
const InfilChart = ({ pplMngNo }: ModalOpenProp) => {
|
||||
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useInfilChartModalStore(); // 모달 상태 관리 스토어
|
||||
const [popupOpen, setPopupOpen] = React.useState(false); // 조회조건팝업
|
||||
const buttonRef = React.useRef<HTMLButtonElement>(null); // 버튼 참조
|
||||
const [popupPosition, setPopupPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 }); // 팝업 위치
|
||||
const [selectedAplcnYm, setSelectedAplcnYm] = useState("");
|
||||
type DataType = {
|
||||
label: string;
|
||||
val: number;
|
||||
};
|
||||
|
||||
const INITIAL_ANALYSIS_OPTIONS = [{ val: 0, text: '선택' }];
|
||||
|
||||
const InfilChart = ({ pplMngNo = '' }: ModalOpenProp) => {
|
||||
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useInfilChartModalStore();
|
||||
|
||||
const [selectedAplcnYm, setSelectedAplcnYm] = useState('');
|
||||
const [inftwtAnlss, setInftwtAnlss] = useState<TInftwtAnls[]>([]);
|
||||
const [inftwtAnlsInfos, setInftwtAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>([{ val: 0, text: '선택' }]); // 침입수분석정보 options
|
||||
const [inftwtAnls, setInftwtAnls] = useState<TInftwtAnls | null>(null); // 침입수분석정보
|
||||
const [selectedInftwtAnls, setSelectedInftwtAnls] = useState<number>(0); // 침입수분석 정보 선택시 사용
|
||||
const [inftwtAnlsInfos, setInftwtAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>(
|
||||
INITIAL_ANALYSIS_OPTIONS,
|
||||
);
|
||||
const [inftwtAnls, setInftwtAnls] = useState<TInftwtAnls | null>(null);
|
||||
const [selectedInftwtAnls, setSelectedInftwtAnls] = useState<number>(0);
|
||||
const [chartData, setChartData] = useState<{ chartData1: DataType[]; chartData2: DataType[] }>({
|
||||
chartData1: [], chartData2: [],
|
||||
chartData1: [],
|
||||
chartData2: [],
|
||||
});
|
||||
const [inftwtQty, setInftwtQty] = useState<string>("0"); // 침입수량
|
||||
const aplcnYms = fn.useAplcnYms('inftwtAnlsRslt'); // 상수사용월 데이터 가져오기
|
||||
const [inftwtQty, setInftwtQty] = useState<string>('0');
|
||||
|
||||
pplMngNo = "L" + pplMngNo; // inp파일에 하수관로와 맨홀의 번호가 같으면 분석 오류가 발행하여
|
||||
const openPopup = () => {
|
||||
if (buttonRef.current) {
|
||||
const rect = buttonRef.current.getBoundingClientRect(); // 버튼 위치 계산
|
||||
setPopupPosition({
|
||||
top: rect.bottom + window.scrollY, // 버튼 아래쪽
|
||||
left: rect.left + window.scrollX, // 버튼 왼쪽
|
||||
});
|
||||
}
|
||||
setPopupOpen(true); // 팝업 열기
|
||||
};
|
||||
const aplcnYms = fn.useAplcnYms('inftwtAnlsRslt');
|
||||
const normalizedPplMngNo = pplMngNo ? `L${pplMngNo}` : '';
|
||||
|
||||
const chartForm = CHART_FORM.LINE;
|
||||
const chartConfig = {
|
||||
chartData1: { label: '순오수량', color: "red", },
|
||||
chartData2: { label: '실측하수량', color: "orange", }
|
||||
chartData1: { label: '순오수량', color: 'red' },
|
||||
chartData2: { label: '실측하수량', color: 'orange' },
|
||||
} as ChartConfig;
|
||||
|
||||
const hasChartData = useMemo(() => {
|
||||
return chartData.chartData1.length > 0 || chartData.chartData2.length > 0;
|
||||
}, [chartData]);
|
||||
|
||||
const resetState = () => {
|
||||
setSelectedAplcnYm('');
|
||||
setInftwtAnlss([]);
|
||||
setInftwtAnlsInfos(INITIAL_ANALYSIS_OPTIONS);
|
||||
setInftwtAnls(null);
|
||||
setSelectedInftwtAnls(0);
|
||||
setChartData({ chartData1: [], chartData2: [] });
|
||||
setInftwtQty('0');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isModalOpen === false) {
|
||||
setPopupOpen(true); // 모달이 닫힐 때 조회조건팝업은 열어두기
|
||||
setSelectedAplcnYm(""); // 상수사용월 초기화
|
||||
setInftwtAnlss([]); // 침입수분석 초기화
|
||||
setInftwtAnlsInfos([{ val: 0, text: '선택' }]); // 침입수분석정보 초기화
|
||||
setInftwtAnls(null); // 침입수분석정보 초기화
|
||||
setSelectedInftwtAnls(0); // 침입수분석 일련번호 초기화
|
||||
setChartData({ chartData1: [], chartData2: [], }); // 차트 데이터 초기화
|
||||
setInftwtQty("0"); // 침입수량 초기화
|
||||
if (!isModalOpen) {
|
||||
resetState(); // 모달이 닫힐 때 리셋
|
||||
}
|
||||
}, [isModalOpen]);
|
||||
|
||||
// 상수사용월 변경 핸들러
|
||||
const handleAplcnYmChange = async (val: string | number) => {
|
||||
const selectedValue = String(val);
|
||||
|
||||
setSelectedAplcnYm(selectedValue);
|
||||
|
||||
// 즉시 관련 상태 초기화
|
||||
setInftwtAnlss([]);
|
||||
setInftwtAnls(null);
|
||||
setSelectedInftwtAnls(0);
|
||||
setInftwtQty('0');
|
||||
setChartData({ chartData1: [], chartData2: [] });
|
||||
|
||||
// 빈 값이면 초기화만 하고 종료
|
||||
if (!selectedValue || selectedValue === "0" || selectedValue === "") {
|
||||
setInftwtAnlsInfos([{ val: 0, text: '선택' }]);
|
||||
if (!selectedValue || selectedValue === '0') {
|
||||
setInftwtAnlsInfos(INITIAL_ANALYSIS_OPTIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
// API 호출
|
||||
try {
|
||||
const data = await fn.selectInftwtAnls(selectedValue);
|
||||
setInftwtAnlss(data ?? []);
|
||||
setInftwtAnlsInfos(fn.getOptionsInftwtAnlsInfo(data));
|
||||
const list = data ?? [];
|
||||
setInftwtAnlss(list);
|
||||
setInftwtAnlsInfos(fn.getOptionsInftwtAnlsInfo(list));
|
||||
} catch (error) {
|
||||
console.error("selectInftwtAnls 에러:", error);
|
||||
console.error('selectInftwtAnls 에러:', error);
|
||||
setInftwtAnlss([]);
|
||||
setInftwtAnlsInfos([{ val: 0, text: '선택' }]);
|
||||
setInftwtAnlsInfos(INITIAL_ANALYSIS_OPTIONS);
|
||||
}
|
||||
setSelectedInftwtAnls(0);
|
||||
};
|
||||
|
||||
// 분석정보 변경 핸들러
|
||||
const handleInftwtAnlsSnChange = (val: string | number) => {
|
||||
const selectedValue = Number(val);
|
||||
setSelectedInftwtAnls(selectedValue);
|
||||
|
||||
// 선택된 침입수분석 정보에 대한 처리 로직
|
||||
setSelectedInftwtAnls(selectedValue);
|
||||
setChartData({ chartData1: [], chartData2: [] });
|
||||
setInftwtQty('0');
|
||||
|
||||
if (selectedValue === 0) {
|
||||
setInftwtAnls(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedAnls = inftwtAnlss.find(anls => anls.inftwtAnlsSn === selectedValue);
|
||||
if (selectedAnls) {
|
||||
setInftwtAnls(selectedAnls);
|
||||
const selectedAnls = inftwtAnlss.find((anls) => anls.inftwtAnlsSn === selectedValue) ?? null;
|
||||
setInftwtAnls(selectedAnls);
|
||||
};
|
||||
|
||||
const infilRsltChart = async () => {
|
||||
if (!selectedAplcnYm || selectedInftwtAnls === 0 || !normalizedPplMngNo) {
|
||||
setChartData({ chartData1: [], chartData2: [] });
|
||||
setInftwtQty('0');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const [inftwtAnlsRslt, oilq, qty] = await Promise.all([
|
||||
fn.selectInftwtAnlsRslt(selectedInftwtAnls, normalizedPplMngNo),
|
||||
fn.selectOilq(selectedInftwtAnls, normalizedPplMngNo).catch((err) => {
|
||||
console.error('selectOilq 에러:', err);
|
||||
return [];
|
||||
}),
|
||||
fn.selectPplInftwtQty(selectedInftwtAnls, normalizedPplMngNo).catch((err) => {
|
||||
console.error('selectPplInftwtQty 에러:', err);
|
||||
return 0;
|
||||
}),
|
||||
]);
|
||||
|
||||
setChartData({
|
||||
chartData1: fn.getChartDataInftwtAnlsRslt(inftwtAnlsRslt ?? []),
|
||||
chartData2: fn.getChartDataOilq(oilq ?? []),
|
||||
});
|
||||
|
||||
const normalizedQty = Number(qty ?? 0);
|
||||
setInftwtQty(normalizedQty.toLocaleString('ko-KR'));
|
||||
} catch (error) {
|
||||
console.error('infilRsltChart 에러:', error);
|
||||
setChartData({ chartData1: [], chartData2: [] });
|
||||
setInftwtQty('0');
|
||||
}
|
||||
};
|
||||
|
||||
const closePopup = () => { // 팝업 닫기
|
||||
setPopupOpen(false);
|
||||
}
|
||||
const infilRsltChart = () => { // 그래프 & 팝업 닫기
|
||||
const renderInfoInput = (label: string, value?: string | number | null) => (
|
||||
<div className="grid grid-cols-[minmax(0,32%)_minmax(0,68%)] items-center gap-3">
|
||||
<Label className="w-auto text-[14px] font-semibold text-[#5c6470] whitespace-nowrap">{label}</Label>
|
||||
<Input
|
||||
className="h-[42px] rounded-[5px] border border-[#d7dde5] bg-white px-3 text-xl md:text-xl text-[#2b3440]"
|
||||
placeholder=""
|
||||
value={value ?? ''}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
fn.selectInftwtAnlsRslt(selectedInftwtAnls, pplMngNo).then((data) => {// 침입수분석 결과 조회
|
||||
const rsltData = fn.getChartDataInftwtAnlsRslt(data ?? []);
|
||||
setChartData(prev => ({
|
||||
...prev,
|
||||
chartData1: rsltData // 침입수분석결과
|
||||
}));
|
||||
});
|
||||
fn.selectOilq(selectedInftwtAnls, pplMngNo).then((data) => {// 유량 조회
|
||||
const rsltData = fn.getChartDataOilq(data ?? []);
|
||||
setChartData(prev => ({
|
||||
...prev,
|
||||
chartData2: rsltData // 유량
|
||||
}));
|
||||
}).catch((err) => {
|
||||
console.error("selectOilq 에러:", err);
|
||||
setChartData(prev => ({
|
||||
...prev,
|
||||
chartData2: [] // 유량 데이터 초기화
|
||||
}));
|
||||
});
|
||||
fn.selectPplInftwtQty(selectedInftwtAnls, pplMngNo).then((data) => {// 침입수량 조회
|
||||
if (data > 0) {
|
||||
setInftwtQty(data.toLocaleString('ko-KR'));
|
||||
}
|
||||
});
|
||||
setPopupOpen(false);
|
||||
};
|
||||
const handleReset = () => {
|
||||
resetState();
|
||||
}
|
||||
|
||||
const renderBody = () => (
|
||||
<>
|
||||
<div className="text-black text-3xl font-bold mb-5">침입수분석결과</div>
|
||||
|
||||
<div className='grid grid-cols-[1fr_3fr] gap-4'>
|
||||
<div className="h-[90%] grid grid-rows-4 gap-4 mb-4">
|
||||
<Button className="bg-white text-white w-[130px] font-bold px-4 mt-2 py-2" onClick={openPopup}>
|
||||
분석 입력현황 조회
|
||||
</Button>
|
||||
{/* 상수사용량 적용연월 */}
|
||||
<div className="bg-white px-4 py-2 ">
|
||||
<span className="text-2xl text-red-600 font-bold">● 상수사용량 적용연월</span>
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="ml-5 text-black text-xl font-bold">
|
||||
{(selectedAplcnYm) ? moment(selectedAplcnYm, "YYYYMM").format("YYYY-MM") : ""}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* 침입수량 분석결과 */}
|
||||
<div className="bg-white px-4 py-2 ">
|
||||
<span className="text-2xl text-red-600 font-bold">● 침입수량 산정결과</span>
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="ml-5 text-black text-xl">침입수량 : </span>
|
||||
<span className="w-[45px] inline-block text-right text-black text-xl font-bold">{inftwtQty}</span>
|
||||
<span className="ml-2 text-black text-xl">m³/d</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 차트 */}
|
||||
<div className="h-[90%] bg-white text-3xl">
|
||||
<MainChart chartConfig={chartConfig} chartForm={chartForm} chartData={chartData} chartTitle={'침입수량 그래프'}
|
||||
yFieldText2="" yFieldText="유량(m³/h)"/>
|
||||
</div>
|
||||
<div className="text-black">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div className="text-[18px] font-semibold text-[#111827]" />
|
||||
</div>
|
||||
{popupOpen && (
|
||||
<div
|
||||
className="absolute bg-gray-100 border border-gray-300 w-[440px] shadow-lg p-6 rounded text-2xl"
|
||||
style={{
|
||||
top: popupPosition.top,
|
||||
left: popupPosition.left,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<div className="font-bold mb-6 text-3xl">침입수분석 입력현황</div>
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">상수사용월:</Label>
|
||||
<SelectBox
|
||||
className="w-[220px] mr-8 z-[51] mb-2"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=''
|
||||
selectArray={aplcnYms}
|
||||
value={selectedAplcnYm}
|
||||
onSelectValue={handleAplcnYmChange}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">분석정보:</Label>
|
||||
<SelectBox
|
||||
className="w-[220px] mr-8 z-[51] mb-2"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=''
|
||||
selectArray={inftwtAnlsInfos}
|
||||
value={selectedInftwtAnls}
|
||||
onSelectValue={handleInftwtAnlsSnChange}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">오수전환율:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={inftwtAnls?.drtwSwtcRt ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">시간패턴 파일명:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={inftwtAnls?.atflHrPttnNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">수용가-맨홀 매칭:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={inftwtAnls?.atflMpngNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">관망도 파일명:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={inftwtAnls?.atflInpNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">유량 파일명:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={inftwtAnls?.atflOilqNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
|
||||
<div className="grid min-h-[68vh] grid-cols-[minmax(0,38%)_minmax(0,62%)] gap-5">
|
||||
<section className="relative rounded-[12px] border border-[#b1b1b1] bg-white p-5">
|
||||
<h3 className="mb-6 text-[20px] font-extrabold tracking-[-0.02em] text-black">
|
||||
침입수 분석 선택 조건
|
||||
</h3>
|
||||
|
||||
<div className="rounded-[6px] border border-[#d9dde3] bg-[#eff1f4] px-4 py-6">
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-[minmax(0,32%)_minmax(0,68%)] items-center gap-3">
|
||||
<Label className="w-auto text-[14px] font-semibold text-[#5c6470] whitespace-nowrap">
|
||||
상수사용월:
|
||||
</Label>
|
||||
<SelectBox
|
||||
className="w-full"
|
||||
selectClass="h-[42px] rounded-[5px] border border-[#d7dde5] bg-white text-xl"
|
||||
label=""
|
||||
selectArray={aplcnYms}
|
||||
value={selectedAplcnYm}
|
||||
onSelectValue={handleAplcnYmChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-[minmax(0,32%)_minmax(0,68%)] items-center gap-3">
|
||||
<Label className="w-auto text-[14px] font-semibold text-[#5c6470] whitespace-nowrap">
|
||||
분석정보:
|
||||
</Label>
|
||||
<SelectBox
|
||||
className="w-full"
|
||||
selectClass="h-[42px] rounded-[5px] border border-[#d7dde5] bg-white text-xl"
|
||||
label=""
|
||||
selectArray={inftwtAnlsInfos}
|
||||
value={selectedInftwtAnls}
|
||||
onSelectValue={handleInftwtAnlsSnChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{renderInfoInput('오수전환율:', inftwtAnls?.drtwSwtcRt ?? '')}
|
||||
{renderInfoInput('시간패턴 파일명:', inftwtAnls?.atflHrPttnNm ?? '')}
|
||||
{renderInfoInput('수용가-맨홀 매칭:', inftwtAnls?.atflMpngNm ?? '')}
|
||||
{renderInfoInput('관망도 파일명:', inftwtAnls?.atflInpNm ?? '')}
|
||||
{renderInfoInput('유량 파일명:', inftwtAnls?.atflOilqNm ?? '')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end mt-4 space-x-2">
|
||||
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={closePopup}>
|
||||
닫기
|
||||
</button>
|
||||
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={infilRsltChart}>
|
||||
선택조건 적용
|
||||
</button>
|
||||
|
||||
<div className="absolute inset-x-0 bottom-0 mb-[40px] flex justify-center">
|
||||
<Button size="lg" onClick={infilRsltChart} >
|
||||
조회
|
||||
</Button>
|
||||
<Button size="lg" color="gray" onClick={handleReset} >
|
||||
초기화
|
||||
</Button>
|
||||
</div>
|
||||
</div>)}
|
||||
{/* </Modal > */}
|
||||
</>
|
||||
)
|
||||
</section>
|
||||
|
||||
<section className="relative rounded-[12px] border border-[#b1b1b1] bg-white p-5">
|
||||
<h3 className="mb-6 text-[20px] font-extrabold tracking-[-0.02em] text-black">침입수 분석 결과</h3>
|
||||
|
||||
<div className="mb-6 grid grid-cols-2 gap-5">
|
||||
<div className="flex min-h-[98px] items-center justify-between rounded-[14px] border border-[#4f88c6] bg-white px-6 py-4">
|
||||
<div className="flex items-center gap-2 text-[16px] font-extrabold text-[#ef4444]">
|
||||
{/* <span className="text-[14px] leading-none">●</span> */}
|
||||
<span>상수사용량 적용연월</span>
|
||||
</div>
|
||||
<div className="text-[20px] font-extrabold text-[#222]">
|
||||
{selectedAplcnYm ? moment(selectedAplcnYm, 'YYYYMM').format('YYYY-MM') : '-'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-[98px] items-center justify-between rounded-[14px] border border-[#4f88c6] bg-white px-6 py-4">
|
||||
<div className="flex items-center gap-2 text-[16px] font-extrabold text-[#ef4444]">
|
||||
{/* <span className="text-[14px] leading-none">●</span> */}
|
||||
<span>침입수량 산정결과</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-[1fr_auto] items-center gap-7 text-[#222]">
|
||||
<span className="text-[16px] text-[#666]">침입수량</span>
|
||||
<div className='w-[66px] flex items-end justify-start gap-2'>
|
||||
<span className="text-[20px] font-extrabold">{inftwtQty}</span>
|
||||
<span className="pb-[2px] text-[16px]">m³/d</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-[10px] bg-white px-2 pb-2 pt-3">
|
||||
{hasChartData ? (
|
||||
<MainChart
|
||||
chartConfig={chartConfig}
|
||||
chartForm={chartForm}
|
||||
chartData={chartData}
|
||||
chartTitle={'침입수량 그래프'}
|
||||
yFieldText="유량(m³/h)"
|
||||
yFieldText2=""
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-[464px] items-center justify-center text-[18px] text-[#2c2f33]">
|
||||
데이터가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<UiModal
|
||||
@@ -270,17 +281,17 @@ const InfilChart = ({ pplMngNo }: ModalOpenProp) => {
|
||||
onOpenChange={setIsModalOpen}
|
||||
headerTitle=""
|
||||
bodyClass={`
|
||||
min-h-[50vh]
|
||||
w-[55vw]
|
||||
max-w-none
|
||||
max-h-none
|
||||
overflow-visible
|
||||
z-[50]
|
||||
`}
|
||||
w-[78vw]
|
||||
max-w-none
|
||||
min-w-[1000px]
|
||||
min-h-[72vh]
|
||||
overflow-visible
|
||||
z-[50]
|
||||
`}
|
||||
body={renderBody()}
|
||||
noFooterYn='Y'
|
||||
noFooterYn="Y"
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(InfilChart);
|
||||
export default React.memo(InfilChart);
|
||||
|
||||
@@ -1,282 +1,339 @@
|
||||
'use client'
|
||||
import { CHART_FORM, type ChartConfig, MainChart, UiModal } from "@common/business_components";
|
||||
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import moment from 'moment';
|
||||
|
||||
import {
|
||||
CHART_FORM,
|
||||
type ChartConfig,
|
||||
MainChart,
|
||||
UiModal,
|
||||
} from '@common/business_components';
|
||||
import { SelectBox } from '@common/business_components/ui';
|
||||
import { Button, Input, Label } from '@common/components';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import moment from "moment";
|
||||
|
||||
import type { TRdiiAnls } from './aplcnYms';
|
||||
import * as fn from './aplcnYms';
|
||||
import { useRdiiChartModalStore } from '../chartModalStore'; // 모달 상태 관리 스토어
|
||||
import { useRdiiChartModalStore } from '../chartModalStore';
|
||||
|
||||
type ModalOpenProp = {
|
||||
pplMngNo: string, // 관로관리번호
|
||||
}
|
||||
// 차트
|
||||
type lineBarChartData = {
|
||||
label : string;
|
||||
lineVal0 : number;
|
||||
barVal0 : number;
|
||||
}
|
||||
pplMngNo?: string; // 관로관리번호
|
||||
};
|
||||
|
||||
type LineBarChartData = {
|
||||
label: string;
|
||||
lineVal0: number;
|
||||
barVal0: number;
|
||||
};
|
||||
|
||||
const RdiiChart = ({ pplMngNo }: ModalOpenProp) => {
|
||||
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useRdiiChartModalStore(); // 모달 상태 관리 스토어
|
||||
const [popupOpen, setPopupOpen] = React.useState(false); // 조회조건팝업
|
||||
const buttonRef = React.useRef<HTMLButtonElement>(null); // 버튼 참조
|
||||
const [popupPosition, setPopupPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 }); // 팝업 위치
|
||||
const [aplcnYm, setAplcnYm] = useState("");
|
||||
const INITIAL_ANALYSIS_OPTIONS = [{ val: 0, text: '선택' }];
|
||||
|
||||
const RdiiChart = ({ pplMngNo = '' }: ModalOpenProp) => {
|
||||
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useRdiiChartModalStore();
|
||||
|
||||
const [aplcnYm, setAplcnYm] = useState('');
|
||||
const [rdiiAnlss, setRdiiAnlss] = useState<TRdiiAnls[]>([]);
|
||||
const [rdiiAnlsInfos, setRdiiAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>([{ val: 0, text: '선택' }]); // 강우유입수분석정보 options
|
||||
const [rdiiAnlsInfos, setRdiiAnlsInfos] = useState<{ text: string; val: number; hidden?: boolean }[]>(
|
||||
INITIAL_ANALYSIS_OPTIONS,
|
||||
);
|
||||
const [rdiiAnls, setRdiiAnls] = useState<TRdiiAnls | null>(null); // 강우유입수분석정보
|
||||
const [rainInfwtAnlsSn, setRainInfwtAnlsSn] = useState<number>(0); // 강우유입수분석 정보 선택시 사용
|
||||
const [chartData, setChartData] = useState<lineBarChartData[]>([]);
|
||||
const [rdiiQty, setRdiiQty] = useState<string>("0"); // 강우유입수량
|
||||
const [rainTotal, setRainTotal] = useState<string>("0"); // 적용강우량
|
||||
const [totalVolume, setTotalVolume] = useState<string>("0"); // 총체적 m³/mm
|
||||
const [rainInfwtAnlsSn, setRainInfwtAnlsSn] = useState<number>(0);// 강우유입수분석 정보 선택시 사용
|
||||
const [chartData, setChartData] = useState<LineBarChartData[]>([]);
|
||||
const [rdiiQty, setRdiiQty] = useState<string>('0'); // 강우유입수량
|
||||
const [rainTotal, setRainTotal] = useState<string>('0'); // 적용강우량
|
||||
const [totalVolume, setTotalVolume] = useState<string>('0');// 총체적 m³/mm
|
||||
|
||||
const aplcnYms = fn.useAplcnYms('rdiiAnlsRslt'); // 상수사용월 데이터 가져오기
|
||||
pplMngNo = "L"+pplMngNo; // "L13101003";
|
||||
|
||||
const openPopup = () => {
|
||||
if (buttonRef.current) {
|
||||
const rect = buttonRef.current.getBoundingClientRect(); // 버튼 위치 계산
|
||||
setPopupPosition({
|
||||
top: rect.bottom + window.scrollY, // 버튼 아래쪽
|
||||
left: rect.left + window.scrollX, // 버튼 왼쪽
|
||||
});
|
||||
}
|
||||
setPopupOpen(true); // 팝업 열기
|
||||
};
|
||||
const normalizedPplMngNo = pplMngNo ? `L${pplMngNo}` : '';
|
||||
|
||||
const chartForm = CHART_FORM.LINEBAR2;
|
||||
const chartConfig = {
|
||||
barVal0: {
|
||||
barVal0: {
|
||||
label: '강수량',
|
||||
color: "#33AAFF",
|
||||
color: '#33AAFF',
|
||||
},
|
||||
lineVal0: {
|
||||
label: 'RDII',
|
||||
color: "#FF0000",
|
||||
color: '#FF0000',
|
||||
},
|
||||
} as ChartConfig;
|
||||
|
||||
const hasChartData = useMemo(() => chartData.length > 0, [chartData]);
|
||||
|
||||
const resetState = () => {
|
||||
setAplcnYm(''); // 상수사용월 초기화
|
||||
setRdiiAnlss([]); // 강우유입수분석 초기화
|
||||
setRdiiAnlsInfos(INITIAL_ANALYSIS_OPTIONS); // 강우유입수분석정보 초기화
|
||||
setRdiiAnls(null); // 강우유입수분석정보 초기화
|
||||
setRainInfwtAnlsSn(0); // 강우유입수분석 일련번호 초기화
|
||||
setChartData([]);
|
||||
setRdiiQty('0'); // 강우유입수량 초기화
|
||||
setRainTotal('0');// 적용강우량 초기화
|
||||
setTotalVolume('0');// 총체적 m³/mm 초기화
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isModalOpen === false) {
|
||||
setPopupOpen(true); // 모달이 닫힐 때 팝업은
|
||||
setAplcnYm(""); // 상수사용월 초기화
|
||||
setRdiiAnlss([]); // 강우유입수분석 초기화
|
||||
setRdiiAnlsInfos([{ val: 0, text: '선택' }]); // 강우유입수분석정보 초기화
|
||||
setRdiiAnls(null); // 강우유입수분석정보 초기화
|
||||
setRainInfwtAnlsSn(0); // 강우유입수분석 일련번호 초기화
|
||||
setChartData([]); // 차트 데이터 초기화
|
||||
setRdiiQty("0"); // 강우유입수량 초기화
|
||||
setRainTotal("0"); // 적용강우량 초기화
|
||||
setTotalVolume("0"); // 총체적 m³/mm 초기화
|
||||
if (!isModalOpen) {
|
||||
resetState();
|
||||
}
|
||||
}, [isModalOpen]);
|
||||
|
||||
// 상수사용월 변경시 분석 정보 리스트 가져오기
|
||||
useEffect(() => {
|
||||
// aplcnYm이 비어있거나 "0"이면 API 호출하지 않음
|
||||
if (!aplcnYm || aplcnYm === "0" || aplcnYm === "") {
|
||||
setRainInfwtAnlsSn(0); // 초기화
|
||||
setRdiiAnlsInfos([]);
|
||||
const handleAplcnYmChange = async (val: string | number) => {
|
||||
const selectedValue = String(val);
|
||||
|
||||
setAplcnYm(selectedValue);
|
||||
setRdiiAnlss([]);
|
||||
setRdiiAnls(null);
|
||||
setRainInfwtAnlsSn(0);
|
||||
setChartData([]);
|
||||
setRdiiQty('0');
|
||||
setRainTotal('0');
|
||||
setTotalVolume('0');
|
||||
|
||||
if (!selectedValue || selectedValue === '0') {
|
||||
setRdiiAnlsInfos(INITIAL_ANALYSIS_OPTIONS);
|
||||
return;
|
||||
}
|
||||
fn.selectRdiiAnls(aplcnYm)
|
||||
.then((data) => {
|
||||
setRdiiAnlss(data ?? []); // 선택한 월의 분석성공한 RDII분석데이터[]
|
||||
setRdiiAnlsInfos(fn.getOptionsRdiiAnlsInfo(data));
|
||||
setRdiiAnls(null); // 오수전환율 이후 초기화
|
||||
setRainInfwtAnlsSn(0); // 초기화
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("selectrdiiAnls 에러:", error);
|
||||
setRdiiAnlss([]);
|
||||
setRdiiAnlsInfos([]);
|
||||
});
|
||||
}, [aplcnYm]);
|
||||
|
||||
// 값 표시
|
||||
useEffect(() => {
|
||||
// 선택된 강우유입수분석 정보에 대한 처리 로직
|
||||
if (rainInfwtAnlsSn === 0) return;
|
||||
const selectedAnls = rdiiAnlss.find(anls => anls.rainInfwtAnlsSn === rainInfwtAnlsSn);
|
||||
if (selectedAnls) {
|
||||
setRdiiAnls(selectedAnls);
|
||||
try {
|
||||
const data = await fn.selectRdiiAnls(selectedValue); // 상수사용월 변경시 분석 정보 리스트 가져오기
|
||||
const list = data ?? [];
|
||||
setRdiiAnlss(list);
|
||||
setRdiiAnlsInfos(fn.getOptionsRdiiAnlsInfo(list));
|
||||
} catch (error) {
|
||||
console.error('selectRdiiAnls 에러:', error);
|
||||
setRdiiAnlss([]);
|
||||
setRdiiAnlsInfos(INITIAL_ANALYSIS_OPTIONS);
|
||||
}
|
||||
}, [rainInfwtAnlsSn, rdiiAnlss]);
|
||||
|
||||
const closePopup = () => { // 팝업 닫기
|
||||
setPopupOpen(false);
|
||||
}
|
||||
const rdiiRsltChart = () => { // 그래프 & 팝업 닫기
|
||||
fetchFilteredData();
|
||||
fn.selectPplRdiiQty(rainInfwtAnlsSn, pplMngNo).then((data) => {// 강우유입수량 조회
|
||||
setRdiiQty(Math.round(data?.rdiih*24).toLocaleString('ko-KR')); // cmd: m³/d 단위로 변환
|
||||
if (data?.raintotal && data?.rainTotal !== 0) {
|
||||
setRainTotal(data?.raintotal.toLocaleString('ko-KR')); // 총강우량mm
|
||||
setTotalVolume(Math.round(data?.rdiih * data?.sustaintime / data?.raintotal).toLocaleString('ko-KR')); // 총체적 m³/mm
|
||||
}
|
||||
});
|
||||
setPopupOpen(false);
|
||||
};
|
||||
|
||||
const fetchFilteredData: () => Promise<void> = async () => {
|
||||
const rsltData = await fn.selectRdiiAnlsRslt(rainInfwtAnlsSn, pplMngNo);
|
||||
const rsltDataformatted = fn.getChartDataRdiiAnlsRslt(rsltData ?? []); // format 변경
|
||||
const rainData = await fn.selectRainData(rainInfwtAnlsSn);
|
||||
const rainDataformatted = fn.getChartDataRainData(rainData ?? []); // format 변경
|
||||
const rainMap = new Map(rainDataformatted.map(item => [item.label, item.barVal0]));
|
||||
const handleRdiiAnlsSnChange = (val: string | number) => {
|
||||
const selectedValue = Number(val);
|
||||
|
||||
setRainInfwtAnlsSn(selectedValue);
|
||||
setChartData([]);
|
||||
setRdiiQty('0');
|
||||
setRainTotal('0');
|
||||
setTotalVolume('0');
|
||||
|
||||
if (selectedValue === 0) {
|
||||
setRdiiAnls(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedAnls = rdiiAnlss.find((anls) => anls.rainInfwtAnlsSn === selectedValue) ?? null;
|
||||
setRdiiAnls(selectedAnls);
|
||||
};
|
||||
|
||||
const fetchFilteredData = async () => {
|
||||
if (!rainInfwtAnlsSn || !normalizedPplMngNo) {
|
||||
setChartData([]);
|
||||
setRdiiQty('0');
|
||||
setRainTotal('0');
|
||||
setTotalVolume('0');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const [rsltData, rainData, qtyData] = await Promise.all([
|
||||
fn.selectRdiiAnlsRslt(rainInfwtAnlsSn, normalizedPplMngNo),
|
||||
fn.selectRainData(rainInfwtAnlsSn),
|
||||
fn.selectPplRdiiQty(rainInfwtAnlsSn, normalizedPplMngNo),
|
||||
]);
|
||||
|
||||
const rsltDataFormatted = fn.getChartDataRdiiAnlsRslt(rsltData ?? []);
|
||||
const rainDataFormatted = fn.getChartDataRainData(rainData ?? []);
|
||||
const rainMap = new Map(rainDataFormatted.map((item) => [item.label, item.barVal0]));
|
||||
|
||||
rsltDataFormatted.forEach((item) => {
|
||||
const matchedVal = rainMap.get(item.label);
|
||||
if (matchedVal !== undefined) {
|
||||
item.barVal0 = matchedVal;
|
||||
}
|
||||
});
|
||||
|
||||
setChartData(rsltDataFormatted);// 차트 데이터 설정
|
||||
|
||||
const avgRdii = Number(qtyData?.rdiih ?? 0);
|
||||
const appliedRainfall = Number(qtyData?.raintotal ?? 0);
|
||||
const rdiiPerRainfall =
|
||||
qtyData?.raintotal && qtyData?.raintotal !== 0
|
||||
? Math.round(avgRdii * Number(qtyData?.sustaintime ?? 0) / qtyData.raintotal)
|
||||
: 0;
|
||||
|
||||
setRdiiQty(Math.round(avgRdii * 24).toLocaleString('ko-KR'));
|
||||
setRainTotal(appliedRainfall.toLocaleString('ko-KR'));
|
||||
setTotalVolume(rdiiPerRainfall.toLocaleString('ko-KR'));
|
||||
} catch (error) {
|
||||
console.error('rdiiRsltChart 에러:', error);
|
||||
setChartData([]);
|
||||
setRdiiQty('0');
|
||||
setRainTotal('0');
|
||||
setTotalVolume('0');
|
||||
}
|
||||
};
|
||||
|
||||
const renderInfoInput = (label: string, value?: string | number | null) => (
|
||||
<div className="grid grid-cols-[minmax(0,32%)_minmax(0,68%)] items-center gap-3">
|
||||
<Label className="w-auto whitespace-nowrap text-[14px] font-semibold text-[#5c6470]">
|
||||
{label}
|
||||
</Label>
|
||||
<Input
|
||||
className="h-[42px] rounded-[5px] border border-[#d7dde5] bg-white px-3 text-xl text-[#2b3440]"
|
||||
placeholder=""
|
||||
value={value ?? ''}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
rsltDataformatted.forEach(item => {
|
||||
const matchedVal = rainMap.get(item.label);
|
||||
if (matchedVal !== undefined) {
|
||||
item.barVal0 = matchedVal;
|
||||
}
|
||||
});
|
||||
setChartData(rsltDataformatted); // 차트 데이터 설정
|
||||
}
|
||||
const renderBody = () => (
|
||||
<>
|
||||
<div className="text-black text-3xl font-bold mb-5">RDII분석결과</div>
|
||||
|
||||
<div className='grid grid-cols-[1fr_3fr] gap-4'>
|
||||
<div className="grid grid-rows-4 gap-4 mb-4">
|
||||
<Button className="bg-white text-white w-[130px] font-bold px-4 mt-2 py-2" onClick={openPopup}>
|
||||
분석 입력현황 조회
|
||||
</Button>
|
||||
{/* 상수사용량 적용연월 */}
|
||||
<div className="bg-white px-4 py-2 ">
|
||||
<span className="text-2xl text-red-600 font-bold">● 상수사용량 적용연월</span>
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="ml-5 text-black text-xl font-bold">
|
||||
{(aplcnYm)? moment(aplcnYm, "YYYYMM").format("YYYY-MM"):""}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 강우유입수량 분석결과 */}
|
||||
<div className="bg-white px-4 py-2 ">
|
||||
<span className="text-2xl text-red-600 font-bold">● 강우유입수량 분석결과</span>
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="w-[95px] inline-block text-right text-black text-xl">평균RDII : </span>
|
||||
<span className="w-[45px] inline-block text-right text-black text-xl font-bold"> {rdiiQty}</span>
|
||||
<span className="ml-2 text-black"> m³/d</span>
|
||||
</div>
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="w-[95px] inline-block text-right text-black text-xl">적용강우량 : </span>
|
||||
<span className="w-[45px] inline-block text-right text-black text-xl font-bold"> {rainTotal}</span>
|
||||
<span className="ml-2 text-black"> mm</span>
|
||||
</div>
|
||||
<div className="flex items-center mt-2">
|
||||
<span className="w-[95px] inline-block text-right text-black text-xl">강우량대비RDII : </span>
|
||||
<span className="w-[45px] inline-block text-right text-black text-xl font-bold"> {totalVolume}</span>
|
||||
<span className="ml-2 text-black"> m³/mm</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 차트 */}
|
||||
<div className="h-[90%] bg-white text-2xl">
|
||||
<MainChart chartConfig={chartConfig} chartForm={chartForm} chartData={chartData} chartTitle={'RDII 그래프'}
|
||||
yFieldText2="강수량(mm)" yFieldText="유량(m³/h)" />
|
||||
</div>
|
||||
<div className="text-black">
|
||||
<div className="mb-4 flex items-start justify-between">
|
||||
<div className="text-[18px] font-semibold text-[#111827]" />
|
||||
</div>
|
||||
{popupOpen && (
|
||||
<div
|
||||
className="absolute bg-gray-100 border border-gray-300 w-[440px] shadow-lg p-6 rounded text-2xl"
|
||||
style={{
|
||||
top: popupPosition.top,
|
||||
left: popupPosition.left,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<div className="font-bold mb-6 text-3xl">강우유입수분석 입력현황</div>
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">상수사용월:</Label>
|
||||
<SelectBox
|
||||
className="w-[220px] mr-8 z-[51] mb-2"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=''
|
||||
selectArray={aplcnYms}
|
||||
value={aplcnYm}
|
||||
onSelectValue={(val) => {
|
||||
setAplcnYm(String(val));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">분석정보:</Label>
|
||||
<SelectBox
|
||||
className="w-[220px] mr-8 z-[51] mb-2"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label=''
|
||||
selectArray={rdiiAnlsInfos}
|
||||
value={rainInfwtAnlsSn}
|
||||
onSelectValue={(val) => {
|
||||
setRainInfwtAnlsSn(Number(val));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">오수전환율:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={rdiiAnls?.drtwSwtcRt ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">수용가-맨홀 매칭:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={rdiiAnls?.atflMpngNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">관망도 파일명:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={rdiiAnls?.atflInpNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">강우 파일명:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={rdiiAnls?.atflRainNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex items-center justify-between'>
|
||||
<Label className="mr-2 w-auto text-2xl text-gray-600 whitespace-nowrap">RTK계수 출처:</Label>
|
||||
<Input
|
||||
className="mr-8 w-[220px] !text-xl placeholder:text-center mb-2"
|
||||
placeholder=""
|
||||
value={rdiiAnls?.srcNm ?? ""}
|
||||
readOnly={true}
|
||||
/>
|
||||
|
||||
<div className="grid min-h-[68vh] grid-cols-[minmax(0,36%)_minmax(0,64%)] gap-5">
|
||||
<section className="relative rounded-[12px] border border-[#b1b1b1] bg-white p-5">
|
||||
<h3 className="mb-6 text-[20px] font-extrabold tracking-[-0.02em] text-black">
|
||||
강우유입수분석 선택 조건
|
||||
</h3>
|
||||
|
||||
<div className="rounded-[6px] border border-[#d9dde3] bg-[#eff1f4] px-4 py-6">
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-[minmax(0,32%)_minmax(0,68%)] items-center gap-3">
|
||||
<Label className="w-auto whitespace-nowrap text-[14px] font-semibold text-[#5c6470]">
|
||||
상수사용월:
|
||||
</Label>
|
||||
<SelectBox
|
||||
className="w-full"
|
||||
selectClass="h-[42px] rounded-[5px] border border-[#d7dde5] bg-white text-xl"
|
||||
label=""
|
||||
selectArray={aplcnYms}
|
||||
value={aplcnYm}
|
||||
onSelectValue={handleAplcnYmChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-[minmax(0,32%)_minmax(0,68%)] items-center gap-3">
|
||||
<Label className="w-auto whitespace-nowrap text-[14px] font-semibold text-[#5c6470]">
|
||||
분석정보:
|
||||
</Label>
|
||||
<SelectBox
|
||||
className="w-full"
|
||||
selectClass="h-[42px] rounded-[5px] border border-[#d7dde5] bg-white text-xl"
|
||||
label=""
|
||||
selectArray={rdiiAnlsInfos}
|
||||
value={rainInfwtAnlsSn}
|
||||
onSelectValue={handleRdiiAnlsSnChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{renderInfoInput('오수전환율:', rdiiAnls?.drtwSwtcRt ?? '')}
|
||||
{renderInfoInput('수용가-맨홀 매칭:', rdiiAnls?.atflMpngNm ?? '')}
|
||||
{renderInfoInput('관망도 파일명:', rdiiAnls?.atflInpNm ?? '')}
|
||||
{renderInfoInput('강우 파일명:', rdiiAnls?.atflRainNm ?? '')}
|
||||
{renderInfoInput('RTK계수 출처:', rdiiAnls?.srcNm ?? '')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end mt-4 space-x-2">
|
||||
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={closePopup}>
|
||||
닫기
|
||||
</button>
|
||||
<button className="px-4 py-2 bg-gray-600 text-white rounded" onClick={rdiiRsltChart}>
|
||||
선택조건 적용
|
||||
</button>
|
||||
|
||||
<div className="absolute inset-x-0 bottom-0 mb-[40px] flex justify-center">
|
||||
<Button size="lg" onClick={fetchFilteredData}>
|
||||
조회
|
||||
</Button>
|
||||
|
||||
<Button size="lg" color="gray" onClick={resetState}>
|
||||
초기화
|
||||
</Button>
|
||||
</div>
|
||||
</div>)}
|
||||
{/* </Modal > */}
|
||||
</>
|
||||
)
|
||||
</section>
|
||||
|
||||
<section className="relative rounded-[12px] border border-[#b1b1b1] bg-white p-5">
|
||||
<h3 className="mb-6 text-[20px] font-extrabold tracking-[-0.02em] text-black">
|
||||
강우유입수분석 결과
|
||||
</h3>
|
||||
|
||||
<div className="mb-6 flex gap-5">
|
||||
{/* 좌측 카드 */}
|
||||
<div className="flex min-h-[98px] min-w-0 basis-2/5 grow shrink-[1.4] items-center justify-between rounded-[16px] border border-[#5fa3ea] bg-white px-6 py-4">
|
||||
<div className="text-[16px] font-bold text-[#ef4444]">
|
||||
상수사용량 적용연월
|
||||
</div>
|
||||
<div className="text-[24px] font-extrabold leading-none text-[#111]">
|
||||
{aplcnYm ? moment(aplcnYm, 'YYYYMM').format('YYYY-MM') : '-'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측 카드 */}
|
||||
<div className="flex min-h-[98px] min-w-0 basis-3/5 grow shrink items-center gap-5 rounded-[16px] border border-[#5fa3ea] bg-white px-6 py-4">
|
||||
{/* 좌측: 제목 (세로 가운데 정렬) */}
|
||||
<div className="flex min-w-0 basis-[32%] items-center">
|
||||
<div className="text-[16px] font-bold text-[#ef4444] break-keep">
|
||||
강우유입수량 분석결과
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 지표 영역 */}
|
||||
<div className="flex min-w-0 basis-[68%] flex-col gap-[2px]">
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<div className="min-w-0 basis-[48%] text-right text-[15px] text-[#555]">
|
||||
평균RDII
|
||||
</div>
|
||||
<div className="min-w-0 basis-[32%] text-right text-[18px] font-extrabold text-[#111] tabular-nums">
|
||||
{rdiiQty}
|
||||
</div>
|
||||
<div className="min-w-0 basis-[20%] text-left text-[14px] text-[#111]">
|
||||
m³/d
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<div className="min-w-0 basis-[48%] text-right text-[15px] text-[#555]">
|
||||
적용 강우량
|
||||
</div>
|
||||
<div className="min-w-0 basis-[32%] text-right text-[18px] font-extrabold text-[#111] tabular-nums">
|
||||
{rainTotal}
|
||||
</div>
|
||||
<div className="min-w-0 basis-[20%] text-left text-[14px] text-[#111]">
|
||||
mm
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<div className="min-w-0 basis-[48%] text-right text-[15px] text-[#555]">
|
||||
강우량 대비 RDII
|
||||
</div>
|
||||
<div className="min-w-0 basis-[32%] text-right text-[18px] font-extrabold text-[#111] tabular-nums">
|
||||
{totalVolume}
|
||||
</div>
|
||||
<div className="min-w-0 basis-[20%] text-left text-[14px] text-[#111]">
|
||||
m³/mm
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-[10px] bg-white px-2 pb-2 pt-3">
|
||||
{hasChartData ? (
|
||||
<MainChart
|
||||
chartConfig={chartConfig}
|
||||
chartForm={chartForm}
|
||||
chartData={chartData}
|
||||
chartTitle={'RDII 그래프'}
|
||||
yFieldText2="강수량(mm)"
|
||||
yFieldText="유량(m³/h)"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-[464px] items-center justify-center text-[18px] text-[#2c2f33]">
|
||||
데이터가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<UiModal
|
||||
@@ -284,17 +341,17 @@ const RdiiChart = ({ pplMngNo }: ModalOpenProp) => {
|
||||
onOpenChange={setIsModalOpen}
|
||||
headerTitle=""
|
||||
bodyClass={`
|
||||
min-h-[50vh]
|
||||
w-[55vw]
|
||||
max-w-none
|
||||
max-h-none
|
||||
overflow-visible
|
||||
z-[50]
|
||||
`}
|
||||
w-[78vw]
|
||||
max-w-none
|
||||
min-w-[1100px]
|
||||
min-h-[72vh]
|
||||
overflow-visible
|
||||
z-[50]
|
||||
`}
|
||||
body={renderBody()}
|
||||
noFooterYn = 'Y'
|
||||
noFooterYn="Y"
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(RdiiChart);
|
||||
export default React.memo(RdiiChart);
|
||||
|
||||
@@ -171,6 +171,7 @@ const Map = () => {
|
||||
setIsPlaying={setIsPlaying as any}
|
||||
targetLayerTypes={WATER_DEPTH_LAYER_TYPES as any}
|
||||
checkInterval={2500}
|
||||
showZoomLevel={true}
|
||||
|
||||
defaultZoom={7.5}
|
||||
defaultLonLat={[127.75, 36]}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -388,6 +388,7 @@ const Map = () => {
|
||||
return (
|
||||
<div className="bg-container">
|
||||
<Gis
|
||||
showZoomLevel={true}
|
||||
treeData={treeData}
|
||||
isSearch={false}
|
||||
gisMaps={gisMaps}
|
||||
|
||||
@@ -58,6 +58,7 @@ export default function MapDrgtPopUp() {
|
||||
return (
|
||||
<div className="bg-container">
|
||||
<Gis
|
||||
showZoomLevel={true}
|
||||
treeData={treeData}
|
||||
isSearch={false}
|
||||
gisMaps={gisMaps}
|
||||
|
||||
@@ -277,6 +277,7 @@ const Map = () => {
|
||||
<>
|
||||
<div className="bg-container">
|
||||
<Gis
|
||||
showZoomLevel={true}
|
||||
height='h-screen'
|
||||
treeData={treeData}
|
||||
isSearch={false}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* 📄 CoMatRvw 수요매칭 검토
|
||||
* Next.js App Router (app/) 기반 페이지 컴포넌트 예시
|
||||
*
|
||||
* - 대민에서 신청하는 수요처의 수요등록 정보를 운영담당자가 수요 매칭 검토를 진행한다.
|
||||
* - 전체적으로 form을 만들어서 form안에 데이터를 넣고 api를 호출하여 저장한다.
|
||||
*/
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { btnClass } from "@/app/store/common/code";
|
||||
import { usageProcData } from "@/app/store/matDmd/coMatRvw/headList";
|
||||
@@ -33,26 +39,21 @@ import {
|
||||
} from "@common/business_components/ui";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import { Button, Input, Label } from "@common/components/ui";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import moment from "moment";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useForm, useWatch } from "react-hook-form";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { z } from "zod";
|
||||
|
||||
|
||||
/**
|
||||
* 📄 CoMatRvw 수요매칭 검토
|
||||
* Next.js App Router (app/) 기반 페이지 컴포넌트 예시
|
||||
*
|
||||
* - 대민에서 신청하는 수요처의 수요등록 정보를 운영담당자가 수요 매칭 검토를 진행한다.
|
||||
* - 전체적으로 form을 만들어서 form안에 데이터를 넣고 api를 호출하여 저장한다.
|
||||
*/
|
||||
export default function CoMatRvw() {
|
||||
const { auth, code, coRvw, coMatRvwInit, coMatRvwSearch, coMatRvwInqua } =
|
||||
useWrStore((state) => state);
|
||||
const { coMatRvwRes, coMatRvwCount } = coRvw;
|
||||
const { regAuthrtYn } = auth;
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
//init, sub, match
|
||||
const initRef = useRef<boolean>(false);
|
||||
@@ -253,7 +254,7 @@ export default function CoMatRvw() {
|
||||
const fromNum = Number(fromDate);
|
||||
const toNum = Number(toDate);
|
||||
if (fromNum > toNum) {
|
||||
toast.error(
|
||||
alert(
|
||||
"시작년도가 종료년도 이후로 설정할 수 없습니다."
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -21,8 +21,9 @@ import {
|
||||
} from "@common/business_components/ui";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import { Button, Label } from "@common/components/ui";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { useEffect, useState } from "react";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
@@ -44,6 +45,7 @@ export default function RuseCaseMng() {
|
||||
const [name, setName] = useState<string>("");
|
||||
const [resetPage, isResetPage] = useState(false);
|
||||
const { t } = useTranslation("base");
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
// 엑셀 등록 모달
|
||||
const [isExcelOpen, setIsExcelOpen] = useState<boolean>(false);
|
||||
@@ -84,7 +86,7 @@ export default function RuseCaseMng() {
|
||||
if (!excelList) return;
|
||||
|
||||
if (excelList.length === 0) {
|
||||
toast.error(t("excelDownErrMsg"));
|
||||
alert(t("excelDownErrMsg"));
|
||||
return;
|
||||
}
|
||||
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
|
||||
|
||||
@@ -24,9 +24,10 @@ import {
|
||||
} from "@common/business_components/ui";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import { Button, Label } from "@common/components/ui";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import moment from "moment";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
export default function RuseRvwHstry() {
|
||||
const {
|
||||
@@ -40,6 +41,7 @@ export default function RuseRvwHstry() {
|
||||
} = useWrStore((state) => state);
|
||||
const { rvwHistRes, ruseHistHeadList, rvwHistCount } = ruseHist;
|
||||
const { regAuthrtYn } = auth;
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
const [pageNation, setPageNatiion] = useState<number>(1);
|
||||
|
||||
@@ -79,7 +81,7 @@ export default function RuseRvwHstry() {
|
||||
const fromNum = Number(fromDate);
|
||||
const toNum = Number(toDate);
|
||||
if (fromNum > toNum) {
|
||||
toast.error("시작년도가 종료년도 이후로 설정할 수 없습니다.");
|
||||
alert("시작년도가 종료년도 이후로 설정할 수 없습니다.");
|
||||
} else {
|
||||
let con: string | number = "";
|
||||
if (String(objSearch.city).length > 0) {
|
||||
@@ -133,7 +135,7 @@ export default function RuseRvwHstry() {
|
||||
selectedData[index]?.splyFcltFlg === "매칭완료" &&
|
||||
headId === "completeYn"
|
||||
) {
|
||||
toast.error(t("canNotChangeMatStateMsg"));
|
||||
alert(t("canNotChangeMatStateMsg"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -177,7 +179,7 @@ export default function RuseRvwHstry() {
|
||||
// </span>
|
||||
// ));
|
||||
} else {
|
||||
toast.error( t('isNotMatchFinishMsg'));
|
||||
alert(t('isNotMatchFinishMsg'));
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { btnClass } from "@/app/store/common/code";
|
||||
import { excelCoSttnParsing } from "@/app/store/matDmd/coSttn/excel";
|
||||
import { fetchType, getFetch } from "@/components/lib/api";
|
||||
import {
|
||||
confirmToast,
|
||||
//confirmToast,
|
||||
excelDownload,
|
||||
formatPhoneNumber,
|
||||
getCity,
|
||||
@@ -29,8 +29,10 @@ import type { DemandCompType } from "@common/business_components/ui/sdmInsertFor
|
||||
import { Button } from "@common/components/ui";
|
||||
import moment from "moment";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
// import toast, { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
export default function CoSttn() {
|
||||
const {
|
||||
@@ -48,7 +50,8 @@ export default function CoSttn() {
|
||||
getMyUUID
|
||||
} = useWrStore((state) => state);
|
||||
const { regAuthrtYn, mdfcnAuthrtYn } = auth;
|
||||
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const { confirm } = useConfirm();
|
||||
const [bdstTable, setBdstTable] = useState<DemandCompType[]>();
|
||||
const [pageNation, setPageNation] = useState(1);
|
||||
const { coSttnRes, coSttnResCount } = coSttn;
|
||||
@@ -98,7 +101,7 @@ export default function CoSttn() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!coSttn.isInit) {
|
||||
coSttnInit("1", "13", "0");
|
||||
coSttnInit("1", "13", "0"); // 수요처 목록 조회
|
||||
}
|
||||
}, [coSttn.isInit, coSttnInit]);
|
||||
|
||||
@@ -167,16 +170,21 @@ export default function CoSttn() {
|
||||
}
|
||||
};
|
||||
const { t } = useTranslation('base');
|
||||
const initPassword = () => {
|
||||
const initPassword = async () => {
|
||||
if (updateData) {
|
||||
const dmdInfoId = updateData.dmdInfoId;
|
||||
const dmdInfoSliceId = `${dmdInfoId.slice(0, 3)}-${dmdInfoId.slice(3, 5)}-${dmdInfoId.slice(5, 10)}-${dmdInfoId.slice(10)}`
|
||||
const handleConfirm = () => {
|
||||
coSttnPwInit(dmdInfoId);
|
||||
const handleConfirm = async () => {
|
||||
const message = await coSttnPwInit(dmdInfoId);
|
||||
alert(message);
|
||||
};
|
||||
confirmToast( t('isInitPw', { dmdInfoId: dmdInfoSliceId }), handleConfirm, 'text-2xl');
|
||||
//confirmToast( t('isInitPw', { dmdInfoId: dmdInfoSliceId }), handleConfirm, 'text-2xl');
|
||||
if (await confirm(t('isInitPw', { dmdInfoId: dmdInfoSliceId }))) {
|
||||
await handleConfirm();
|
||||
}
|
||||
} else {
|
||||
toast.error("비밀번호 초기화를 원하는 행을 선택해주세요.")
|
||||
alert("비밀번호 초기화를 원하는 행을 선택해주세요.");
|
||||
// toast.error("비밀번호 초기화를 원하는 행을 선택해주세요.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +246,7 @@ export default function CoSttn() {
|
||||
onClick={() => {
|
||||
/* 저장 로직 */
|
||||
if (!updateData) {
|
||||
toast.error("수요처 변경을 원하는 행을 선택해주세요");
|
||||
alert("수요처 변경을 원하는 행을 선택해주세요");
|
||||
} else {
|
||||
setIsDmdModal({
|
||||
...isDmdModal,
|
||||
@@ -274,8 +282,8 @@ export default function CoSttn() {
|
||||
headName={[]}
|
||||
tableData={bdstTable || []}
|
||||
headlist={coSttn.coSttHeadList}
|
||||
pageSize={20}
|
||||
total={coSttnResCount + 10 || 0}
|
||||
pageSize={13}
|
||||
total={coSttnResCount || 0}
|
||||
cellClick={ async(index: number | undefined) => {
|
||||
const uuid = await getMyUUID();
|
||||
const updateData = coSttnRes[index as number];
|
||||
@@ -319,7 +327,8 @@ export default function CoSttn() {
|
||||
? objSearch.sgg
|
||||
: objSearch.city;
|
||||
if (updateData?.dmdInfoId) {
|
||||
await updateDemandCompany(data as DemandCompType);
|
||||
const message = await updateDemandCompany(data as DemandCompType);
|
||||
alert(message);
|
||||
coSttnInit("1", "13", String(con));
|
||||
setIsDmdModal({
|
||||
isMoal: false,
|
||||
@@ -332,12 +341,11 @@ export default function CoSttn() {
|
||||
`/reuseFc/request/${data.dmdInfoId}`
|
||||
);
|
||||
if (dmd) {
|
||||
toast.error(
|
||||
`사업자번호 ${dmd.dmdInfoId}는 이미 등록되었습니다. 다시등록해주세요`
|
||||
);
|
||||
alert(`사업자번호 ${dmd.dmdInfoId}는 이미 등록되었습니다. 다시등록해주세요`);
|
||||
return;
|
||||
}
|
||||
await regDemandCompany(data as DemandCompType);
|
||||
const message = await regDemandCompany(data as DemandCompType);
|
||||
alert(message);
|
||||
coSttnInit("1", "13", String(con));
|
||||
setIsDmdModal({
|
||||
isMoal: false,
|
||||
@@ -352,7 +360,7 @@ export default function CoSttn() {
|
||||
}
|
||||
></UiModal>
|
||||
</ContentsDiv>
|
||||
<Toaster position="top-center" />
|
||||
{/* <Toaster position="top-center" /> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/b
|
||||
import { ContentsDiv, DateMonthPicker, downloadExcel, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import { Button, Label, ScrollArea } from "@common/components/ui";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { toast, Toaster } from "react-hot-toast";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
|
||||
export default function DrgtSttn() {
|
||||
const { code, drgt, drgtSearch, drgtModalSearch, drgtInit } = useWrStore((state) => state);
|
||||
const { drgtRes, drgtMoRes } = drgt;
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const [fromDate, setFromDate] = useState<string>('202506');
|
||||
const [toDate, setToDate] = useState<string>('202506');
|
||||
const [selectSgg, setSelectSgg] = useState<SelectDataType[]>([{ val: '0', text: '전체' }]);
|
||||
@@ -32,7 +34,7 @@ export default function DrgtSttn() {
|
||||
if (fromDate && toDate && drgtRes[index]) {
|
||||
drgtModalSearch(fromDate, toDate, drgtRes[index].sggNm ?? '');
|
||||
} else {
|
||||
toast.error("조회기간을 선택해주세요.");
|
||||
alert("조회기간을 선택해주세요.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,9 @@ import {
|
||||
} from "@common/business_components/ui";
|
||||
import ListDiv from "@common/business_components/ui/list_div";
|
||||
import { Button } from "@common/components/ui";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function LdrmntCoSttn() {
|
||||
@@ -46,6 +47,7 @@ export default function LdrmntCoSttn() {
|
||||
const [resetPage, isResetPage] = useState(false);
|
||||
const [isDownloadClicked, setIsDownloadClicked] = useState(false);
|
||||
const { t } = useTranslation('base');
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const { regAuthrtYn, mdfcnAuthrtYn } = auth;
|
||||
|
||||
const excelClick = useCallback(() => {
|
||||
@@ -113,7 +115,7 @@ export default function LdrmntCoSttn() {
|
||||
headerRange: "A1:F1"
|
||||
});
|
||||
} else {
|
||||
toast.error(t('excelDownErrMsg'));
|
||||
alert(t('excelDownErrMsg'));
|
||||
}
|
||||
setIsDownloadClicked(false);
|
||||
}, [excelData, isDownloadClicked]);
|
||||
@@ -270,7 +272,8 @@ export default function LdrmntCoSttn() {
|
||||
readonly={mdfcnAuthrtYn === 'N'}
|
||||
onFormSubmit={async (value) => {
|
||||
const handleConfirm = async () => {
|
||||
await ldrmntUpdate(value);
|
||||
const message = await ldrmntUpdate(value);
|
||||
alert(message);
|
||||
setDetailModal({ ...detailModal, isOpen: false });
|
||||
ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || "");
|
||||
};
|
||||
|
||||
@@ -44,13 +44,14 @@ import {
|
||||
import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm";
|
||||
import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm";
|
||||
import { PbnstRegModal } from "@/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal";
|
||||
import toast, { Toaster } from "react-hot-toast"; // toast 이미 import 되어 있음
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg";
|
||||
import { useFieldArray, useForm, type FieldErrors } from "react-hook-form"; // FieldErrors 타입 추가
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { createDefaultPbnstItem } from "./utilsZod";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
export default function PublicReuseFaciltyInsert() {
|
||||
const {
|
||||
auth,
|
||||
@@ -66,6 +67,7 @@ export default function PublicReuseFaciltyInsert() {
|
||||
} = useWrStore((state) => state);
|
||||
|
||||
const { t } = useTranslation("base");
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const { pubFacHeadList, pbnstHasuResCount, pbnstHasuRes, pbnstRes } = pbnst;
|
||||
const { regAuthrtYn, mdfcnAuthrtYn, laeSeCd } = auth;
|
||||
const [, setCurrentTab] = useState<string>("mng");
|
||||
@@ -140,7 +142,7 @@ export default function PublicReuseFaciltyInsert() {
|
||||
const isFcltSuccess = resFclt.status === "fulfilled";
|
||||
const isBizSuccess = resBiz.status === "fulfilled";
|
||||
if (isFcltSuccess && isBizSuccess) {
|
||||
toast.success("하수 재이용 시설 및 사업이 수정되었습니다. ");
|
||||
alert("하수 재이용 시설 및 사업이 수정되었습니다.");
|
||||
// 메시지 표시, 페이지 이동 등
|
||||
} else {
|
||||
let message = "";
|
||||
@@ -151,7 +153,7 @@ export default function PublicReuseFaciltyInsert() {
|
||||
if (!isBizSuccess) {
|
||||
message += "하수재이용 시설 사업 ";
|
||||
}
|
||||
toast.error(message + "오류 입니다 ");
|
||||
alert(message + "오류 입니다 ");
|
||||
pubHasuInit("1", laeSeCd);
|
||||
}
|
||||
});
|
||||
@@ -215,7 +217,7 @@ export default function PublicReuseFaciltyInsert() {
|
||||
}
|
||||
}
|
||||
// 최종 오류 메시지 출력
|
||||
toast.error(`${prefix}${message}`);
|
||||
alert(`${prefix}${message}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -321,8 +323,8 @@ export default function PublicReuseFaciltyInsert() {
|
||||
onClick={() => {
|
||||
// pbnstMngData([] as customPbnst[]);
|
||||
if (!selectRow) {
|
||||
toast.error(
|
||||
"하수리시시설을 테이블을 선택하고 등록버튼을 눌러주세요"
|
||||
alert(
|
||||
"재시용시설을 등록할 하수리시시설을 테이블에서 선택하고 등록버튼을 눌러주세요"
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
@@ -416,7 +418,7 @@ export default function PublicReuseFaciltyInsert() {
|
||||
onClick={() => {
|
||||
// pbnstMngData([] as customPbnst[]);
|
||||
if (!selectRow) {
|
||||
toast.error(
|
||||
alert(
|
||||
"하수리시시설을 테이블을 선택하고 등록버튼을 눌러주세요"
|
||||
);
|
||||
return;
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
|
||||
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
|
||||
import type { conCostFeeType, rateFeeType } from "./type";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
|
||||
export const comFcltStateExport: comFcltState = {
|
||||
@@ -59,8 +58,8 @@ export type comFcltState = {
|
||||
type comFcltActions = {
|
||||
getSwtrmtFcltNm: (searchNm: string) => void;
|
||||
getDemandCompList: (searchNm: string, cnt: number) => void;
|
||||
regDemandCompany: (data: DemandCompType) => void;
|
||||
updateDemandCompany: (data: DemandCompType) => void;
|
||||
regDemandCompany: (data: DemandCompType) => Promise<string>;
|
||||
updateDemandCompany: (data: DemandCompType) => Promise<string>;
|
||||
getConstCostFee: (year: string) => void;
|
||||
getRateFee: (year: string) => void;
|
||||
};
|
||||
@@ -109,7 +108,6 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
|
||||
fetchType.WR
|
||||
);
|
||||
if (response.status === 200) {
|
||||
toast.success('수요처가 등록되었습니다. ')
|
||||
set((state: comFcltState) => {
|
||||
|
||||
return {
|
||||
@@ -117,11 +115,12 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
|
||||
dmdIsSucees: "success"
|
||||
}
|
||||
});
|
||||
return "수요처가 등록되었습니다.";
|
||||
}
|
||||
return "수요처 등록에 실패하였습니다.";
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
toast.error('수요처가 등록 오류입니다.. ')
|
||||
|
||||
return "수요처 등록 중 오류가 발생했습니다.";
|
||||
}
|
||||
},
|
||||
updateDemandCompany: async (data: DemandCompType) => {
|
||||
@@ -131,7 +130,6 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
|
||||
let message = "";
|
||||
if (response.status === 200) {
|
||||
message = "success";
|
||||
toast.success('수요처 정보가 변경되었습니다. ' )
|
||||
} else {
|
||||
message = "fail";
|
||||
}
|
||||
@@ -142,10 +140,13 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
|
||||
dmdIsSucees: message
|
||||
}
|
||||
});
|
||||
if (response.status === 200) {
|
||||
return "수요처 정보가 변경되었습니다.";
|
||||
}
|
||||
return "수요처 정보 변경에 실패하였습니다.";
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
toast.success('수요처 정보가 오류입니다. ' )
|
||||
|
||||
return "수요처 정보 변경 중 오류가 발생했습니다.";
|
||||
}
|
||||
},
|
||||
getRateFee: async (year: string) => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { fetchType, getFetchWithCount, putFectch } from "@/components/lib/api";
|
||||
import toast from "react-hot-toast";
|
||||
import type { CommonTableProps } from "../../common/type/header";
|
||||
import {
|
||||
constCostHeadListExport,
|
||||
@@ -50,7 +49,7 @@ type coRvwActions = {
|
||||
splyCd: string,
|
||||
dmdCd: string,
|
||||
data: DedMatUpdateType
|
||||
) => void;
|
||||
) => Promise<string>;
|
||||
coMatRvwSearch: (
|
||||
pageNo: number,
|
||||
pageCnt: number,
|
||||
@@ -104,20 +103,17 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
|
||||
splyCd: string,
|
||||
dmdCd: string,
|
||||
data: DedMatUpdateType
|
||||
) => {
|
||||
): Promise<string> => {
|
||||
try {
|
||||
const response = await putFectch(
|
||||
`/reuseFc/request/cst/${splyCd}/${dmdCd}`,
|
||||
data
|
||||
);
|
||||
if (response.status === 200) {
|
||||
|
||||
if(data.flg ==='Sub'){
|
||||
|
||||
toast.success("매칭 검토로 저장되었습니다.");
|
||||
}else{
|
||||
toast.success("매칭 검토완료로 저장되었습니다.");
|
||||
}
|
||||
const successMessage =
|
||||
data.flg === "Sub"
|
||||
? "매칭 검토로 저장되었습니다."
|
||||
: "매칭 검토완료로 저장되었습니다.";
|
||||
|
||||
const coMatRvwRes = await coMatInit(
|
||||
1,
|
||||
@@ -125,21 +121,22 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
|
||||
new Date().getFullYear().toString(),
|
||||
new Date().getFullYear().toString()
|
||||
);
|
||||
return set((state: coRvwState) => ({
|
||||
set((state: coRvwState) => ({
|
||||
...state,
|
||||
coRvw: {
|
||||
...state.coRvw,
|
||||
coMatRvwRes: coMatRvwRes.data,
|
||||
coMatRvwCount:coMatRvwRes.count,
|
||||
coMatRvwCount: coMatRvwRes.count,
|
||||
init: false,
|
||||
},
|
||||
}));
|
||||
return successMessage;
|
||||
} else {
|
||||
toast.error("매칭 검토 저장에 실패했습니다.");
|
||||
return "매칭 검토 저장에 실패했습니다.";
|
||||
}
|
||||
} catch (e) {
|
||||
toast.error("매칭 검토 저장 오류입니다.");
|
||||
console.error("coMatRvwUpdate error", e);
|
||||
return "매칭 검토 저장 오류입니다.";
|
||||
}
|
||||
},
|
||||
coMatRvwSearch: async (
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { CommonTableProps } from "@/app/store/common/type/header";
|
||||
import { fetchType, getFetchWithCount, putFectch } from "@/components/lib/api";
|
||||
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
|
||||
import { coSttHeadListExport, coSttNodeListExport } from "./headList";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
// 테이블 헤드 리스트
|
||||
const coSttNodeList = coSttNodeListExport;
|
||||
@@ -25,7 +24,7 @@ type coSttnActions = {
|
||||
coSttnInit: (pageNo: string, pageCnt: string, con: string) => void;
|
||||
coSttnSearch: (pageNo: string, pageCnt: string, con: string) => void;
|
||||
coSttnTxtSearch: (pageNo: string, pageCnt: string, con: string, txt: string) => void;
|
||||
coSttnPwInit: (dmdInfoId: string) => void;
|
||||
coSttnPwInit: (dmdInfoId: string) => Promise<string>;
|
||||
};
|
||||
|
||||
export type coSttnType = coSttnState & coSttnActions;
|
||||
@@ -46,6 +45,7 @@ export const coSttnActionsExport: (set: any) => coSttnActions = (
|
||||
set: any
|
||||
) => {
|
||||
return {
|
||||
// 수요처 목록 조회
|
||||
coSttnInit: async (pageNo: string, pageCnt: string, con: string) => {
|
||||
try {
|
||||
|
||||
@@ -126,10 +126,14 @@ export const coSttnActionsExport: (set: any) => coSttnActions = (
|
||||
try {
|
||||
const response = await putFectch(`/reuseFc/request/chgPassword/${dmdInfoId}`,[])
|
||||
if (response.status === 200) {
|
||||
toast.success('비밀번호가 초기화 되었습니다.')
|
||||
return "비밀번호가 초기화되었습니다.";
|
||||
} else {
|
||||
toast.error('비밀번호 초기화에 실패하였습니다')
|
||||
return "비밀번호 초기화에 실패하였습니다.";
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return "비밀번호 초기화에 실패하였습니다.";
|
||||
} finally {
|
||||
set((state: coSttnState) => {
|
||||
return {
|
||||
...state,
|
||||
@@ -139,11 +143,7 @@ export const coSttnActionsExport: (set: any) => coSttnActions = (
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
toast.error('비밀번호 초기화에 실패하였습니다.')
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export const ldrmntHeadListExport: CommonTableProps[] = [
|
||||
},
|
||||
{
|
||||
id: "fctryAddr",
|
||||
title: "공장주소",
|
||||
title: "회사주소",
|
||||
visible: true,
|
||||
row: 1,
|
||||
rowSpan: 1,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { CommonTableProps } from "@/app/store/common/type/header";
|
||||
import { deleteFectch, fetchType, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod";
|
||||
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
|
||||
import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList";
|
||||
@@ -35,7 +34,7 @@ type ldrmntActions = {
|
||||
ldrmntRegData: (data: any[]) => void,
|
||||
ldrmntInit: (isExcel: boolean, con: string) => void
|
||||
ldrmntSearch: (isExcel: boolean, page: number, sggCd: string, total: string, coNm: string) => void;
|
||||
ldrmntUpdate: (ldrmntRes: customLdrmnt) => void;
|
||||
ldrmntUpdate: (ldrmntRes: customLdrmnt) => Promise<string>;
|
||||
ldrmntDelete: () => void;
|
||||
loadingOpen: (isOpen: boolean) => void
|
||||
};
|
||||
@@ -192,12 +191,14 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
|
||||
);
|
||||
|
||||
if (res.ok) {
|
||||
toast.success("잠재수요처 상세정보가 수정되었습니다.",)
|
||||
return "잠재수요처 상세정보가 수정되었습니다.";
|
||||
}
|
||||
return "잠재수요처 상세정보 수정에 실패하였습니다.";
|
||||
} catch (error) {
|
||||
console.error("Error ldrmntUpdate:", error);
|
||||
toast.error("잠재수요처 상세정보 수정에 실패하였습니다.")
|
||||
return "잠재수요처 상세정보 수정에 실패하였습니다.";
|
||||
}
|
||||
return "잠재수요처 상세정보가 없습니다.";
|
||||
},
|
||||
ldrmntDelete: async () => {
|
||||
try {
|
||||
@@ -228,4 +229,4 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { fetchType, getFetchWithCount, postFectch } from "@/components/lib/api";
|
||||
import { toast } from "react-hot-toast";
|
||||
import type { TableUpperProps } from "../../common/type/header";
|
||||
import { ruseCaseHeadListExport } from "./headList";
|
||||
import type { ruseCaseMngExcelProps } from "./excel";
|
||||
@@ -24,7 +23,7 @@ type ruseCaseActions = {
|
||||
usageCd: string,
|
||||
name: string
|
||||
) => Promise<void>;
|
||||
insertRuseCaseMng: (data: any) => Promise<void>;
|
||||
insertRuseCaseMng: (data: any) => Promise<string>;
|
||||
};
|
||||
|
||||
const fetchSearchRuseCaseMng = async (
|
||||
@@ -131,11 +130,10 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
||||
}
|
||||
},
|
||||
|
||||
insertRuseCaseMng: async (data: any) => {
|
||||
insertRuseCaseMng: async (data: any): Promise<string> => {
|
||||
try {
|
||||
const response = await fetchInsertRuseCaseMng(data);
|
||||
if (response.status === 200) {
|
||||
toast.success("물재이용사례 등록이 완료되었습니다. ");
|
||||
const res = await getFetchWithCount(
|
||||
fetchType.WR,
|
||||
`/reuseFc/pubFcRuseCase/1/10/0/0`
|
||||
@@ -147,11 +145,13 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
||||
count: res.count,
|
||||
},
|
||||
}));
|
||||
return "물재이용사례 등록이 완료되었습니다.";
|
||||
} else {
|
||||
return "물재이용사례 등록에 실패했습니다.";
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
toast.error("물재이용사례 등록에 실패하였습니다. ");
|
||||
return "물재이용사례 등록에 실패했습니다.";
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
getInterpolation,
|
||||
transformAndInterpolate,
|
||||
} from "@/components/lib/func/calculateConstCost ";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { ConstCostFeeTable } from "@/components/ui/modal/coMat/constCostFeeTable";
|
||||
import { RateFeeTableModal } from "@/components/ui/modal/coMat/rateFeeModal";
|
||||
import {
|
||||
@@ -53,6 +54,7 @@ export default function ConCostForm({
|
||||
getRateFee,
|
||||
getConstCostFee,
|
||||
} = useWrStore((state) => state);
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
const ref = useRef<boolean>(false);
|
||||
|
||||
@@ -108,11 +110,11 @@ export default function ConCostForm({
|
||||
const calculateConstCost = useCallback(() => {
|
||||
const usgPrcsProcs = usgPrcsProcsWatch;
|
||||
if (!dmndQtyWatch) {
|
||||
toast.error("요구수량(m³/일)을 확인해주세요 계산할수 없습니다. ");
|
||||
alert("요구수량(m³/일)을 확인해주세요 계산할수 없습니다. ");
|
||||
return;
|
||||
}
|
||||
if (usgPrcsProcs === null || usgPrcsProcs === undefined) {
|
||||
toast.error(
|
||||
alert(
|
||||
"용도에 따른 처리공정을 확인할수 없습니다. 용도를 확인해주세요. "
|
||||
);
|
||||
return;
|
||||
@@ -175,9 +177,9 @@ export default function ConCostForm({
|
||||
form.setValue("totalConstCost", Math.round(realResult));
|
||||
}
|
||||
}, [constCostRes, rateFeeRes, usgPrcsProcsWatch, dmndQtyWatch]);
|
||||
const onSubmit = (value: DmdCoReqType) => {
|
||||
const onSubmit = async (value: DmdCoReqType) => {
|
||||
if (value.demandCst && !value.demandCst.prcsFcltCpctCstrnCst) {
|
||||
toast.error("공사비 계산 진행 후 저장을 눌러주새요");
|
||||
alert("공사비 계산 진행 후 저장을 눌러주새요");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -211,10 +213,15 @@ export default function ConCostForm({
|
||||
<div className="flex gap-2 mt-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
toast.dismiss(t.id);
|
||||
|
||||
coMatRvwUpdate(pk, form.getValues("dmdInfoId"), data);
|
||||
|
||||
const message = await coMatRvwUpdate(
|
||||
pk,
|
||||
form.getValues("dmdInfoId"),
|
||||
data
|
||||
);
|
||||
alert(message);
|
||||
}}
|
||||
>
|
||||
확인
|
||||
@@ -226,10 +233,15 @@ export default function ConCostForm({
|
||||
</span>
|
||||
));
|
||||
} else {
|
||||
coMatRvwUpdate(pk, form.getValues("dmdInfoId"), data);
|
||||
const message = await coMatRvwUpdate(
|
||||
pk,
|
||||
form.getValues("dmdInfoId"),
|
||||
data
|
||||
);
|
||||
alert(message);
|
||||
}
|
||||
}else{
|
||||
toast.error('후보지를 먼저 선택해주세요')
|
||||
alert('후보지를 먼저 선택해주세요')
|
||||
}
|
||||
}
|
||||
} else if (type === "hist") {
|
||||
|
||||
@@ -39,8 +39,9 @@ import type { DemandCompType } from "@common/business_components/ui/sdmInsertFor
|
||||
import RuseMngTableForm from "@/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm";
|
||||
import type { SelectDataType } from "@common/business_components";
|
||||
import { BuseWaterQulity } from "./buseWaterQulity/buseWaterQulity";
|
||||
import toast from "react-hot-toast";
|
||||
// import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
//import { useTranslation } from "react-i18next";
|
||||
|
||||
|
||||
@@ -74,6 +75,7 @@ export function PbnstBuseForm({
|
||||
readonly?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation("base");
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
const {
|
||||
code,
|
||||
@@ -193,7 +195,7 @@ export function PbnstBuseForm({
|
||||
fcDemands: [],
|
||||
});
|
||||
await appendBiz(newItem);
|
||||
toast.success(t('insertRuseBiz',{cycle: pbnstBizCycle + 1}))
|
||||
alert(t('insertRuseBiz',{cycle: pbnstBizCycle + 1}))
|
||||
setIndexBiz(pbnstBizCycle);
|
||||
}, [form, indexMng, indexBiz, appendBiz, setIndexBiz]);
|
||||
|
||||
@@ -779,8 +781,9 @@ export function PbnstBuseForm({
|
||||
rtnValue={(searchText: string, pageCnt: number) => {
|
||||
getDemandCompList(searchText, pageCnt);
|
||||
}}
|
||||
rtnInputData={(data) => {
|
||||
regDemandCompany(data as DemandCompType);
|
||||
rtnInputData={async (data) => {
|
||||
const message = await regDemandCompany(data as DemandCompType);
|
||||
alert(message);
|
||||
setIsDmdModal({
|
||||
isMoal: false,
|
||||
data: data as DemandCompType,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useWrStore } from "@/app/store";
|
||||
import { coRegExcel } from "@/app/store/matDmd/coSttn/headList";
|
||||
import { mapAndValidateRow, type ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/excel";
|
||||
import { showConfirmToast } from "@/components/lib/func/commom";
|
||||
import { useAlertStore } from "@/src/shared/lib";
|
||||
import { filePicked, Title } from "@common/business_components/ui";
|
||||
import { Form } from "@common/business_components/ui/form";
|
||||
import { Button, Input } from "@common/components/ui";
|
||||
@@ -12,6 +13,7 @@ import type { z } from "zod";
|
||||
|
||||
export default function RuseCaseMngExcel({setIsExcelOpen}:{setIsExcelOpen: (isOpen:boolean)=>void}) {
|
||||
const { insertRuseCaseMng } = useWrStore((state) => state);
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const form = useForm<z.infer<typeof coRegExcel>>({
|
||||
resolver: zodResolver(coRegExcel),
|
||||
});
|
||||
@@ -20,7 +22,7 @@ export default function RuseCaseMngExcel({setIsExcelOpen}:{setIsExcelOpen: (isOp
|
||||
|
||||
const onSubmit = () => {
|
||||
if (file) {
|
||||
filePicked(file, 0).then((res: unknown) => {
|
||||
filePicked(file, 0).then(async (res: unknown) => {
|
||||
try {
|
||||
const newArray: ruseCaseMngExcelProps[] = []
|
||||
const isError:string[][] = []
|
||||
@@ -144,7 +146,8 @@ export default function RuseCaseMngExcel({setIsExcelOpen}:{setIsExcelOpen: (isOp
|
||||
alert("업로드할 데이터가 없습니다.");
|
||||
return;
|
||||
}else if(newArray.length > 0){
|
||||
insertRuseCaseMng(newArray);
|
||||
const message = await insertRuseCaseMng(newArray);
|
||||
alert(message);
|
||||
setIsExcelOpen(false);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -188,4 +191,4 @@ export default function RuseCaseMngExcel({setIsExcelOpen}:{setIsExcelOpen: (isOp
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -21,10 +21,12 @@ function AlertDialog() {
|
||||
{message}
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<DialogClose asChild>
|
||||
<Button>확인</Button>
|
||||
</DialogClose>
|
||||
<DialogFooter>
|
||||
<div className="flex w-full justify-center">
|
||||
<DialogClose asChild>
|
||||
<Button>확인</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
@@ -28,17 +28,19 @@ function ConfirmDialog({
|
||||
{message}
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<DialogClose asChild>
|
||||
<Button onClick={onConfirm} {...confirmButtonProps}>
|
||||
{confirmButtonProps?.label ?? "확인"}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button onClick={onCancel} color="white" {...cancelButtonProps}>
|
||||
{cancelButtonProps?.label ?? "취소"}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogFooter>
|
||||
<div className="flex w-full justify-center gap-2">
|
||||
<DialogClose asChild>
|
||||
<Button onClick={onConfirm} {...confirmButtonProps}>
|
||||
{confirmButtonProps?.label ?? "확인"}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button onClick={onCancel} color="white" {...cancelButtonProps}>
|
||||
{cancelButtonProps?.label ?? "취소"}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
@@ -28,13 +28,9 @@
|
||||
"@/*": ["./*"],
|
||||
"@common/components/*": ["../../packages/common/components/src/*"],
|
||||
"@common/components": ["../../packages/common/components/src/index"],
|
||||
"@common/business_components/*": [
|
||||
"../../packages/common/business_components/src/*"
|
||||
],
|
||||
"@common/business_components": [
|
||||
"../../packages/common/business_components/src/index"
|
||||
],
|
||||
"@common/network": ["../../packages/common/network"]
|
||||
"@common/business_components/*": ["../../packages/common/business_components/src/*"],
|
||||
"@common/business_components": ["../../packages/common/business_components/src/index"],
|
||||
"@common/network": ["../../packages/common/network"],
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
|
||||
@@ -19,6 +19,7 @@ import GisMapToggle from "./GisMapToggle";
|
||||
import GisSelect from "./GisSelect";
|
||||
import GisToolBar from "./GisToolBar";
|
||||
import GisTree from "./GisTree";
|
||||
import GisZoomLevel from "./GisZoomLevel";
|
||||
import "./lib/css/gis.common.css";
|
||||
import GisApp from "./lib/gis.core";
|
||||
import LoadingOverlay from "@common/business_components/ui/loadingBar";
|
||||
@@ -58,6 +59,7 @@ function Gis({
|
||||
droughtDates = { startYmd: '', endYmd: '' },
|
||||
defaultZoom = 15,
|
||||
defaultLonLat = [127.4875, 37.4916],
|
||||
showZoomLevel = false,
|
||||
}) {
|
||||
const mapRef = useRef();
|
||||
const [mapObject, setMapObject] = useState({});
|
||||
@@ -325,6 +327,7 @@ function Gis({
|
||||
</div>
|
||||
)}
|
||||
<GisToolBar />
|
||||
{showZoomLevel && <GisZoomLevel />}
|
||||
<GisMapToggle />
|
||||
<GisSelect onFeatureSelect={handleFeatureSelect} />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useGisContext } from './Gis';
|
||||
|
||||
export default React.memo(function GisZoomLevel() {
|
||||
const { gisMap } = useGisContext();
|
||||
const trackRef = useRef(null);
|
||||
const [zoomInfo, setZoomInfo] = useState({
|
||||
zoom: 0,
|
||||
minZoom: 0,
|
||||
maxZoom: 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!gisMap) return undefined;
|
||||
|
||||
const view = gisMap.getView();
|
||||
if (!view) return undefined;
|
||||
|
||||
const updateZoomInfo = () => {
|
||||
setZoomInfo({
|
||||
zoom: view.getZoom() ?? 0,
|
||||
minZoom: view.getMinZoom?.() ?? 0,
|
||||
maxZoom: view.getMaxZoom?.() ?? 20,
|
||||
});
|
||||
};
|
||||
|
||||
updateZoomInfo();
|
||||
view.on('change:resolution', updateZoomInfo);
|
||||
|
||||
return () => {
|
||||
view.un('change:resolution', updateZoomInfo);
|
||||
};
|
||||
}, [gisMap]);
|
||||
|
||||
if (!gisMap) return <></>;
|
||||
|
||||
const { zoom, minZoom, maxZoom } = zoomInfo;
|
||||
const range = Math.max(maxZoom - minZoom, 1);
|
||||
const normalized = Math.min(Math.max((zoom - minZoom) / range, 0), 1);
|
||||
const fillHeight = `${normalized * 100}%`;
|
||||
const thumbBottom = `calc(${fillHeight} - 1px)`;
|
||||
|
||||
const updateZoomFromClientY = clientY => {
|
||||
if (!gisMap || !trackRef.current) return;
|
||||
|
||||
const view = gisMap.getView();
|
||||
const rect = trackRef.current.getBoundingClientRect();
|
||||
const offsetY = rect.bottom - clientY;
|
||||
const nextNormalized = Math.min(Math.max(offsetY / rect.height, 0), 1);
|
||||
const nextZoom = minZoom + nextNormalized * range;
|
||||
view.setZoom(nextZoom);
|
||||
};
|
||||
|
||||
const zoomIn = () => {
|
||||
const view = gisMap.getView();
|
||||
if (view.getMaxZoom() > view.getZoom()) {
|
||||
view.animate({
|
||||
zoom: view.getZoom() + 1,
|
||||
duration: 250,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const zoomOut = () => {
|
||||
const view = gisMap.getView();
|
||||
if (view.getMinZoom() < view.getZoom()) {
|
||||
view.animate({
|
||||
zoom: view.getZoom() - 1,
|
||||
duration: 250,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleTrackPointerDown = event => {
|
||||
event.preventDefault();
|
||||
updateZoomFromClientY(event.clientY);
|
||||
|
||||
const handlePointerMove = moveEvent => {
|
||||
updateZoomFromClientY(moveEvent.clientY);
|
||||
};
|
||||
|
||||
const handlePointerUp = () => {
|
||||
window.removeEventListener('pointermove', handlePointerMove);
|
||||
window.removeEventListener('pointerup', handlePointerUp);
|
||||
};
|
||||
|
||||
window.addEventListener('pointermove', handlePointerMove);
|
||||
window.addEventListener('pointerup', handlePointerUp);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="zoom-level-control" title={`현재 줌 레벨 ${zoom.toFixed(1)}`}>
|
||||
<div className="zoom-level-panel">
|
||||
<button type="button" className="zoom-level-btn" onClick={zoomIn} aria-label="확대">
|
||||
+
|
||||
</button>
|
||||
<div className="zoom-level-gauge">
|
||||
<div
|
||||
ref={trackRef}
|
||||
className="zoom-level-track"
|
||||
onPointerDown={handleTrackPointerDown}
|
||||
>
|
||||
<div className="zoom-level-fill" style={{ height: fillHeight }} />
|
||||
<div className="zoom-level-thumb" style={{ bottom: thumbBottom }} />
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" className="zoom-level-btn" onClick={zoomOut} aria-label="축소">
|
||||
-
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -173,6 +173,100 @@
|
||||
text-indent: -9999px;
|
||||
}
|
||||
|
||||
.zoom-level-control {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 60px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.zoom-level-panel {
|
||||
overflow: hidden;
|
||||
width: 40px;
|
||||
background: #fff;
|
||||
border: 1px solid #9aa7b8;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0px 0px 5px #999;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.zoom-level-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
font-size: 26px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.zoom-level-panel .zoom-level-btn:last-child {
|
||||
border-top: 1px solid #eeeeee;
|
||||
border-bottom: 0 none;
|
||||
}
|
||||
|
||||
.zoom-level-btn:hover {
|
||||
background: #67aee3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.zoom-level-gauge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 128px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.zoom-level-track {
|
||||
position: relative;
|
||||
width: 12px;
|
||||
height: 96px;
|
||||
border-radius: 6px;
|
||||
cursor: ns-resize;
|
||||
touch-action: none;
|
||||
background:
|
||||
linear-gradient(to top, #b8b8b8, #b8b8b8) center / 4px 100% no-repeat,
|
||||
repeating-linear-gradient(
|
||||
to top,
|
||||
transparent 0,
|
||||
transparent 8px,
|
||||
#d9d9d9 8px,
|
||||
#d9d9d9 9px
|
||||
),
|
||||
linear-gradient(to top, #f5f5f5, #fafafa);
|
||||
}
|
||||
|
||||
.zoom-level-fill {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: #3b82f6;
|
||||
border-radius: 999px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.zoom-level-thumb {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: 22px;
|
||||
height: 5px;
|
||||
border: 0.5px solid #111;
|
||||
border-radius: 2px;
|
||||
background: #fff;
|
||||
transform: translateX(-50%);
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.ol-scale-line {
|
||||
background: rgba(0, 60, 136, 0.3);
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -118,7 +118,7 @@ GisOlLayer.prototype = {
|
||||
let toProj = GisApp.TO_PROJ;
|
||||
let lyrTyNm = options.lyrTyNm;
|
||||
let typename = this.storageNm + lyrTyNm;
|
||||
let filter = options?.flterSql && options.flterSql && options.flterSql.trim() !== '';
|
||||
const filter = (options?.flterSql ?? '').trim();
|
||||
|
||||
let params = {};
|
||||
params['TYPENAME'] = typename;
|
||||
|
||||
Reference in New Issue
Block a user