feat: 침입수 분석, RDII 분석, 결과 페이지 연월로 수정

This commit is contained in:
swcho
2025-07-03 18:05:46 +09:00
parent 620faff7cd
commit 79ea2e56d5
5 changed files with 174 additions and 108 deletions
@@ -2,7 +2,7 @@
import { getData } from '@/components/lib/api'
import ContentLayout from '@/components/ui/contentLayout'
import { GovSidoSigunguSearchForm } from '@/components/ui/govSidoSigunguSearchForm'
import { DatePicker, Form, SearchFormRight, SelectBox } from '@common/business_components/ui'
import { DatePicker, DateMonthPicker, Form, SearchFormRight, SelectBox } from '@common/business_components/ui'
import ListDiv from '@common/business_components/ui/list_div'
import { SelectBox2 } from '@common/business_components/ui/select/index-2'
import { Button, Label } from '@common/components/ui'
@@ -51,8 +51,10 @@ type BaseLayout = {
onSwageTreatmentPlantChange?: (value: string | number) => void;
selectedSwageProcessingZone?: string | number;
onSwageProcessingZoneChange?: (value: string | number) => void;
aplcnYm?: Date
setAplcnYm?: (aplcnYm: Date | undefined) => void;
aplcnYmFrom?: string
setAplcnYmFrom?: (aplcnYmFrom: string) => void;
aplcnYmTo?: string
setAplcnYmTo?: (aplcnYmTo: string) => void;
isLoading?: boolean;
// Excel 다운로드 관련 props 추가
onExcelDownload?: () => void;
@@ -89,8 +91,10 @@ const BaseLayout = ({
onSwageTreatmentPlantChange,
selectedSwageProcessingZone,
onSwageProcessingZoneChange,
aplcnYm,
setAplcnYm,
aplcnYmFrom,
setAplcnYmFrom,
aplcnYmTo,
setAplcnYmTo,
isLoading,
// Excel 다운로드 관련 props 추가
onExcelDownload,
@@ -216,13 +220,37 @@ const BaseLayout = ({
{showDatePicker && ( // showDatePicker 값에 따라 DatePicker 렌더링
<>
<Label className="ml-4 w-20 text-xl text-gray-600 whitespace-nowrap">분석기간</Label>
<DatePicker
mode={"single"}
<DateMonthPicker
field={{
value: aplcnYm ?? new Date(),
onChange: setAplcnYm ?? ((date: Date | undefined) => console.log("DatePicker onChange:", date))
value: aplcnYmFrom || (() => { // aplcnYm이 없으면 현재 연월을 기본값으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(), // yyyyMM 형식
onChange: (value: string) => {
setAplcnYmFrom?.(value); // string 값을 직접 전달
}
}}
selectClass="ml-5 date-picker-trigger" />
selectClass="ml-5 w-[100px]"
startYear={1900} // 시작 연도 설정
/>
<span className="font-semibold text-xl mx-2">~</span>
<DateMonthPicker
field={{
value: aplcnYmTo || (() => { // aplcnYm이 없으면 현재 연월을 기본값으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(), // yyyyMM 형식
onChange: (value: string) => {
setAplcnYmTo?.(value); // string 값을 직접 전달
}
}}
selectClass="ml-5 w-[100px]"
startYear={1900} // 시작 연도 설정
/>
</>
)}
<GovSidoSigunguSearchForm
@@ -2,7 +2,7 @@
import { postData } from '@/components/lib/api'
import FileUploadForm from '@/components/ui/fileUploadForm'
import FormSection from '@/components/ui/formSection'
import { DatePicker, filePicked } from '@common/business_components/ui'
import { DateMonthPicker, filePicked } from '@common/business_components/ui'
import ListDiv from '@common/business_components/ui/list_div'
import { Input } from '@common/components/ui'
import { zodResolver } from '@hookform/resolvers/zod'
@@ -59,7 +59,13 @@ const IrSetting = () => {
initialFileInfo // 3: 유량자료 등록
]);
const [selectedDate, setSelectedDate] = useState(new Date());
// selectedDate를 yyyyMM 문자열 형식으로 변경
const [selectedDate, setSelectedDate] = useState(() => {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
});
const [input1, setInput1] = useState('');
const [input2, setInput2] = useState('');
const [select1, setSelect1] = useState('0'); // 환경청코드
@@ -87,7 +93,11 @@ const IrSetting = () => {
initialFileInfo,
initialFileInfo
]);
setSelectedDate(new Date()); // 날짜 선택 초기화
// selectedDate를 현재 연월로 초기화
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
setSelectedDate(`${year}${month}`);
setInput1(''); // 입력 필드 초기화
setInput2(''); // 입력 필드 초기화
setSelect1('0'); // 선택 필드 초기화
@@ -138,22 +148,6 @@ const IrSetting = () => {
const handleAnalysisClick = async () => {
setIsLoadingResult(true); // 로딩 상태 시작
// 오수전환율 값 0 ~ 1 사이인지 검증
if (input1 === '' || input1 === null || input1 === undefined) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율을 입력해주세요.');
return;
}
const numericInput1 = parseFloat(input1);
if (isNaN(numericInput1) || numericInput1 < 0 || numericInput1 > 1) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
return;
}
console.log(uploadedFilesData);
const file1 = uploadedFilesData[0]; // 오수관망도
const file2 = uploadedFilesData[1]; // 수용가-맨홀 매칭결과
@@ -173,6 +167,22 @@ const IrSetting = () => {
return;
}
// 오수전환율 값 0 ~ 1 사이인지 검증
if (input1 === '' || input1 === null || input1 === undefined) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율을 입력해주세요.');
return;
}
const numericInput1 = parseFloat(input1);
if (isNaN(numericInput1) || numericInput1 < 0 || numericInput1 > 1) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
return;
}
type MatchingResult = { anlsSn: number; mhlMngNo: string; rcptrNo: string; };
type TimePattern = { hrId: number; rt?: number | null | undefined; };
type FlowRate = { pplMngNo: string; mtrngDt: string; oilq?: number | null | undefined; };
@@ -236,7 +246,7 @@ const IrSetting = () => {
swtrmtZoneCd: (select5 && select5 !== '0' && select5 !== 0)
? select5.toString().split('.').pop() || null // '.'으로 split해서 마지막 부분만 사용
: null, // 하수처리구역코드 (선택값)
aplcnYm: new Date(selectedDate).toISOString().substring(0, 7).replace("-", ""), // 적용연월
aplcnYm: selectedDate, // 적용연월
drtwSwtcRt: parseFloat(input1) || null, // 오수전환율 (숫자로 변환)
anlsInfo: input2, // 분석정보
atflCd: file1?.atflCd, // 첨부파일CD (오수관망도)
@@ -318,18 +328,15 @@ const IrSetting = () => {
form={form}
titleNm='▷ 상수사용량 적용월'>
{/* 연월 선택 라이브러리로 수정 필요 */}
<DatePicker
mode={"single"}
<DateMonthPicker
field={{
value: selectedDate, // 현재 페이지의 selectedDate 상태 사용
onChange: (date: Date | undefined) => {
if (date) {
setSelectedDate(date);
form.setValue('inputdate', date, { shouldValidate: true });
}
value: selectedDate, // yyyyMM 형식
onChange: (value: string) => {
setSelectedDate(value);
}
}}
selectClass="ml-5 date-picker-trigger" // date-picker.css의 스타일 적용
selectClass="ml-5 w-[150px]"
startYear={1900} // 시작 연도 설정
/>
</FormSection>
<FormSection
+32 -43
View File
@@ -4,7 +4,7 @@ import { postData } from '@/components/lib/api'
import FileUploadForm from "@/components/ui/fileUploadForm"
import FormSection from "@/components/ui/formSection"
import BaseLayout from "../BaseLayout"
import { DatePicker, filePicked } from "@common/business_components/ui"
import { DateMonthPicker, filePicked } from "@common/business_components/ui"
import { Input } from "@common/components/ui"
import { zodResolver } from "@hookform/resolvers/zod"
import { Label } from '@radix-ui/react-label'
@@ -42,7 +42,7 @@ const formSchema = z.object({
rate: z.string(), // 오수전환율
// rain: z.instanceof(File).optional(), // 강우자료
analysisInfo: z.string().optional(), // 분석 정보
date: z.date(),
date: z.string(), // Date 객체에서 string(yyyyMM 형식)으로 변경
// date: z.coerce.date(),
})
// zod 스키마 타입 추론
@@ -72,7 +72,12 @@ const defaultFormValues: FormSchemaType = {
rate: "0.8", // 문자열로 기본값 설정
// rainFile: undefined,
analysisInfo: "test 분석정보",
date: new Date(),
date: (() => { // 현재 연월을 yyyyMM 형식으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(),
};
// 각 파일 업로드 폼의 데이터를 저장할 인터페이스 정의
@@ -108,7 +113,6 @@ export default function RTKForm() {
const [select4, setSelect4] = useState<string | number>('0'); // 하수처리장 (swageTmplntCd)
const [select5, setSelect5] = useState<string | number>('0'); // 하수처리구역 (swtrmtZoneCd)
// form 인스턴스 생성
const form = useForm<FormSchemaType>({
resolver: zodResolver(formSchema),
@@ -163,23 +167,6 @@ export default function RTKForm() {
// 침입수 분석 실행 버튼 클릭 핸들러
const handleAnalysisClick = async () => {
setIsLoadingResult(true); // 로딩 상태 시작
// 오수전환율 값 0 ~ 1 사이인지 검증
const rateValue = form.getValues().rate;
if (rateValue === '' || rateValue === null || rateValue === undefined) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율을 입력해주세요.');
return;
}
const numericInput1 = parseFloat(rateValue);
if (isNaN(numericInput1) || numericInput1 < 0 || numericInput1 > 1) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
return;
}
const formData = form.getValues();
console.log(uploadedFilesData);
@@ -198,6 +185,23 @@ export default function RTKForm() {
return;
}
// 오수전환율 값 0 ~ 1 사이인지 검증
const rateValue = form.getValues().rate;
if (rateValue === '' || rateValue === null || rateValue === undefined) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율을 입력해주세요.');
return;
}
const numericInput1 = parseFloat(rateValue);
if (isNaN(numericInput1) || numericInput1 < 0 || numericInput1 > 1) {
setIsLoadingResult(false);
console.error('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
alert('오수전환율은 0에서 1 사이의 값으로 입력해야 합니다.');
return;
}
const filePickers = [
{ file: file2, parser: excelToMatchingResultData },
{ file: file3, parser: excelToRainData },
@@ -241,7 +245,7 @@ export default function RTKForm() {
// 새로운 JSON 데이터 생성
const combinedAnalysisData = {
enoCd: (select1 && select1 !== '0') ? select1.toString() : null, // 환경청코드 (선택값)
aplcnYm: new Date(formData.date).toISOString().substring(0, 7).replace("-", ""), // 적용연월 (YYYYMM 형식)
aplcnYm: formData.date, // 적용연월 (YYYYMM 형식)
ctpvCd: (select2 && select2 !== '0') ? select2.toString() : null, // 시도코드 (선택값)
sggCd: (select3.val && select3.val !== '0') ? select3.val.toString() : null, // 시군구코드 (선택값)
swageTmplntCd: (select4 && select4 !== '0' && select4 !== 0)
@@ -448,30 +452,15 @@ export default function RTKForm() {
/>
</FormSection>
<FormSection name='date' form={form} titleNm='○ 상수사용량 적용월'>
{/* 연월 선택 라이브러리로 수정 필요 */}
{/* <DatePicker
selected={form.watch("date")}
onSelect={(date: Date | undefined) => {
if (date) {
form.setValue("date", date, { shouldValidate: true });
}
}}
mode={"single"}
className="ml-5"
/> */}
<DatePicker
mode={"single"} // mode는 DayPickerSingleProps에서 오므로 그대로 사용 가능
<DateMonthPicker
field={{
value: form.watch("date"), // react-hook-form의 "date" 필드 값 사용
onChange: (date: Date | undefined) => {
if (date) {
form.setValue("date", date, { shouldValidate: true });
}
value: form.watch("date"), // form의 date 값을 직접 사용
onChange: (value: string) => {
form.setValue("date", value, { shouldValidate: true }); // form의 date 필드에 직접 설정
}
}}
// className을 직접 사용하거나, DatePicker 내부에서 selectClass를 처리하도록 수정 필요
// 여기서는 DatePicker의 selectClass prop을 사용하고, date-picker.css의 스타일을 적용
selectClass="ml-5 date-picker-trigger"
selectClass="ml-5 w-[200px]"
startYear={1900} // 시작 연도 설정
/>
</FormSection>
<FormSection name='rate' form={form} titleNm='○ 분석 정보'>
@@ -18,7 +18,18 @@ const formSchema = z.object({
}).default({ val: '0', text: '전체' }),
swageTmplntCd: z.string().default('0'), // 하수처리장
swtrmtZoneCd: z.string().default('0'), // 하수처리구역
aplcnYm: z.date().default(new Date()), // 분석일자 (DatePicker와 연동)
aplcnYmFrom: z.string().default(() => { // Date에서 string(yyyyMM 형식)으로 변경
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
}), // 분석기간 시작연월
aplcnYmTo: z.string().default(() => { // Date에서 string(yyyyMM 형식)으로 변경
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
}), // 분석기간 종료연월
})
type ResultFormValues = z.infer<typeof formSchema>
@@ -49,7 +60,18 @@ const Result = () => {
sggCd: { val: '0', text: '전체' },
swageTmplntCd: '0',
swtrmtZoneCd: '0',
aplcnYm: new Date(),
aplcnYmFrom: (() => { // 현재 연월을 yyyyMM 형식으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(),
aplcnYmTo: (() => { // 현재 연월을 yyyyMM 형식으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(),
}
})
@@ -71,7 +93,8 @@ const Result = () => {
if (customFormValues) {
inftwtAnlsSearchDto = {
"aplcnYm": formValues.aplcnYm,
"aplcnYmFrom": formValues.aplcnYmFrom,
"aplcnYmTo": formValues.aplcnYmTo,
"enoCd": formValues.enoCd,
"ctpvCd": formValues.ctpvCd,
"sggCd": formValues.sggCd,
@@ -79,7 +102,8 @@ const Result = () => {
};
} else {
inftwtAnlsSearchDto = {
"aplcnYm": formValues.aplcnYm ? formValues.aplcnYm.toISOString().substring(0, 7).replace("-", "") : null,
"aplcnYmFrom": formValues.aplcnYmFrom && formValues.aplcnYmFrom !== '' ? formValues.aplcnYmFrom : null,
"aplcnYmTo": formValues.aplcnYmTo && formValues.aplcnYmTo !== '' ? formValues.aplcnYmTo : null,
"enoCd": formValues.enoCd === '0' ? null : formValues.enoCd,
"ctpvCd": formValues.ctpvCd === '0' ? null : formValues.ctpvCd,
"sggCd": formValues.sggCd?.val === '0' ? null : formValues.sggCd?.val,
@@ -208,7 +232,8 @@ const Result = () => {
// 삭제 후 테이블 새로고침을 위해 재검색
const customFormValues: Partial<ResultFormValues> = {
aplcnYm: selectedRowData.aplcnYm || null,
aplcnYmFrom: selectedRowData.aplcnYmFrom || null,
aplcnYmTo: selectedRowData.aplcnYmTo || null,
enoCd: selectedRowData.enoCd || null,
ctpvCd: selectedRowData.ctpvCd || null,
sggCd: selectedRowData.sggCd || null,
@@ -251,14 +276,10 @@ const Result = () => {
onSwageTreatmentPlantChange={(val) => form.setValue("swageTmplntCd", String(val))}
selectedSwageProcessingZone={form.watch("swtrmtZoneCd")}
onSwageProcessingZoneChange={(val) => form.setValue("swtrmtZoneCd", String(val))}
aplcnYm={form.watch("aplcnYm")}
setAplcnYm={(val) => {
if (val instanceof Date) {
form.setValue("aplcnYm", val)
} else if (val) {
form.setValue("aplcnYm", new Date(val))
}
}}
aplcnYmFrom={form.watch("aplcnYmFrom")}
setAplcnYmFrom={(val: string) => {form.setValue("aplcnYmFrom", val)}}
aplcnYmTo={form.watch("aplcnYmTo")}
setAplcnYmTo={(val: string) => {form.setValue("aplcnYmTo", val)}}
isLoading={isLoadingResult}
// Excel 다운로드 핸들러 추가
onExcelDownload={handleExcelDownload}
@@ -18,7 +18,18 @@ const formSchema = z.object({
}).default({ val: '0', text: '전체' }),
swageTmplntCd: z.string().default('0'), // 하수처리장
swtrmtZoneCd: z.string().default('0'), // 하수처리구역
aplcnYm: z.date().default(new Date()), // 분석일자 (DatePicker와 연동)
aplcnYmFrom: z.string().default(() => { // Date에서 string(yyyyMM 형식)으로 변경
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
}), // 분석기간 시작연월
aplcnYmTo: z.string().default(() => { // Date에서 string(yyyyMM 형식)으로 변경
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
}), // 분석기간 종료연월
})
type ResultFormValues = z.infer<typeof formSchema>
@@ -47,7 +58,18 @@ const Result = () => {
sggCd: { val: '0', text: '전체' },
swageTmplntCd: '0',
swtrmtZoneCd: '0',
aplcnYm: new Date(),
aplcnYmFrom: (() => { // 현재 연월을 yyyyMM 형식으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(),
aplcnYmTo: (() => { // 현재 연월을 yyyyMM 형식으로 설정
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return `${year}${month}`;
})(),
}
})
@@ -69,7 +91,8 @@ const Result = () => {
if (customFormValues) {
inftwtAnlsSearchDto = {
"aplcnYm": formValues.aplcnYm,
"aplcnYmFrom": formValues.aplcnYmFrom,
"aplcnYmTo": formValues.aplcnYmTo,
"enoCd": formValues.enoCd,
"ctpvCd": formValues.ctpvCd,
"sggCd": formValues.sggCd,
@@ -77,7 +100,8 @@ const Result = () => {
};
} else {
inftwtAnlsSearchDto = {
"aplcnYm": formValues.aplcnYm ? formValues.aplcnYm.toISOString().substring(0, 7).replace("-", "") : null,
"aplcnYmFrom": formValues.aplcnYmFrom && formValues.aplcnYmFrom !== '' ? formValues.aplcnYmFrom : null,
"aplcnYmTo": formValues.aplcnYmTo && formValues.aplcnYmTo !== '' ? formValues.aplcnYmTo : null,
"enoCd": formValues.enoCd === '0' ? null : formValues.enoCd,
"ctpvCd": formValues.ctpvCd === '0' ? null : formValues.ctpvCd,
"sggCd": formValues.sggCd?.val === '0' ? null : formValues.sggCd?.val,
@@ -208,7 +232,8 @@ const Result = () => {
// 삭제 후 테이블 새로고침을 위해 재검색
const customFormValues: Partial<ResultFormValues> = {
aplcnYm: selectedRowData.aplcnYm || null,
aplcnYmFrom: selectedRowData.aplcnYmFrom || null,
aplcnYmTo: selectedRowData.aplcnYmTo || null,
enoCd: selectedRowData.enoCd || null,
ctpvCd: selectedRowData.ctpvCd || null,
sggCd: selectedRowData.sggCd || null,
@@ -251,14 +276,10 @@ const Result = () => {
onSwageTreatmentPlantChange={(val) => form.setValue("swageTmplntCd", String(val))}
selectedSwageProcessingZone={form.watch("swtrmtZoneCd")}
onSwageProcessingZoneChange={(val) => form.setValue("swtrmtZoneCd", String(val))}
aplcnYm={form.watch("aplcnYm")}
setAplcnYm={(val) => {
if (val instanceof Date) {
form.setValue("aplcnYm", val)
} else if (val) {
form.setValue("aplcnYm", new Date(val))
}
}}
aplcnYmFrom={form.watch("aplcnYmFrom")}
setAplcnYmFrom={(val: string) => {form.setValue("aplcnYmFrom", val)}}
aplcnYmTo={form.watch("aplcnYmTo")}
setAplcnYmTo={(val: string) => {form.setValue("aplcnYmTo", val)}}
isLoading={isLoadingResult} // 로딩 상태 전달
// Excel 다운로드 핸들러 추가
onExcelDownload={handleExcelDownload}