feat: RDII 분석결과 화면 구현

This commit is contained in:
swcho
2025-06-09 15:33:46 +09:00
parent e4bf427fca
commit f9f913560c
3 changed files with 249 additions and 33 deletions
+245
View File
@@ -0,0 +1,245 @@
'use client'
import { getData, deleteData } from '@/components/lib/api'
import { UiTable, downloadExcel } from '@common/business_components/ui'
import { zodResolver } from '@hookform/resolvers/zod'
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import BaseLayout from '../BaseLayout'
const formSchema = z.object({
enoCd: z.string().default('0'), // 환경청코드
ctpvCd: z.string().default('0'), // 시도코드
sggCd: z.object({ // 시군구
val: z.string().default('0'),
text: z.string().default('전체'),
}).default({ val: '0', text: '전체' }),
swageTmplntCd: z.string().default('0'), // 하수처리장
swtrmtZoneCd: z.string().default('0'), // 하수처리구역
aplcnYm: z.date().default(new Date()), // 분석일자 (DatePicker와 연동)
})
type ResultFormValues = z.infer<typeof formSchema>
const tableColumn = [
{ id: 'no', title: '번호' },
{ id: 'analysis no', title: '분석번호' },
{ id: 'hasu', title: '하수처리장' },
{ id: 'guyeok', title: '처리구역' },
{ id: 'sangsu', title: '상수 사용량' },
{ id: 'rate', title: '오수 전환율' },
{ id: 'rtx', title: 'RTX 계수 출처' },
{ id: 'rdii', title: 'RDII 기여면적' },
{ id: 'rdii analysis info', title: 'RDII 분석정보' },
{ id: 'date', title: '분석일자' },
{ id: 'usr', title: '분석자' }
]
const Result = () => {
const form = useForm<ResultFormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
enoCd: '0',
ctpvCd: '0',
sggCd: { val: '0', text: '전체' },
swageTmplntCd: '0',
swtrmtZoneCd: '0',
aplcnYm: new Date(),
}
})
const [tableData, setTableData] = useState<any[]>([]); // API 조회 결과 저장 상태
const [totalData, setTotalData] = useState(0) //총 데이터 수
const [isLoadingResult, setIsLoadingResult] = useState<boolean>(false); // 로딩 상태
const [selectedRowData, setSelectedRowData] = useState<any>(null);
const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined);
const handleSearchButtonClick = async (customFormValues?: Partial<ResultFormValues>) => {
setIsLoadingResult(true);
const formValues = customFormValues || form.getValues(); // react-hook-form에서 현재 값 가져오기
console.log("formValues", formValues);
let inftwtAnlsSearchDto;
if (customFormValues) {
inftwtAnlsSearchDto = {
"aplcnYm": formValues.aplcnYm,
"enoCd": formValues.enoCd,
"ctpvCd": formValues.ctpvCd,
"sggCd": formValues.sggCd,
"swtrmtZoneCd": formValues.swtrmtZoneCd,
};
} else {
inftwtAnlsSearchDto = {
"aplcnYm": formValues.aplcnYm ? formValues.aplcnYm.toISOString().substring(0, 7).replace("-", "") : null,
"enoCd": formValues.enoCd === '0' ? null : formValues.enoCd,
"ctpvCd": formValues.ctpvCd === '0' ? null : formValues.ctpvCd,
"sggCd": formValues.sggCd?.val === '0' ? null : formValues.sggCd?.val,
"swtrmtZoneCd": formValues.swtrmtZoneCd === '0' ? null : formValues.swtrmtZoneCd,
};
}
console.log("Search DTO:", inftwtAnlsSearchDto);
const queryParams = new URLSearchParams({
page: '0',
size: '10',
sort: 'inftwtAnlsSn'
});
Object.entries(inftwtAnlsSearchDto).forEach(([key, value]) => {
if (value !== undefined && value !== null && String(value).trim() !== '') { // undefined, null, 빈 문자열이 아닌 경우에만 추가
queryParams.append(key, String(value));
}
});
const queryString = queryParams.toString();
console.log("API: ", `v1/rdiiAnls${queryString ? `?${queryString}` : ''}`);
try {
const data = await getData(`v1/rdiiAnls${queryString ? `?${queryString}` : ''}`);
setTableData(data.content || []);
setTotalData(tableData.length);
console.log("response:", data);
console.log("response data:", data.content || []);
} catch (error) {
console.error("Error fetching analysis result data:", error);
alert("분석결과 조회 중 오류가 발생했습니다.");
setTableData([]);
setTotalData(0);
} finally {
setIsLoadingResult(false);
}
};
// 테이블 셀 클릭 핸들러 추가
const handleCellClick = (index: number | undefined, headId: string) => {
if (index !== undefined && tableData[index]) {
setSelectedRowData(tableData[index]);
setSelectedRowIndex(index);
console.log("Selected row data:", tableData[index]);
}
};
// Excel 다운로드 핸들러 추가
const handleExcelDownload = async () => {
console.log("Selected row data for download:", selectedRowData);
if (!selectedRowData || selectedRowData.inftwtAnlsSn === undefined) {
alert('다운로드할 데이터를 선택해주세요.');
return;
}
try {
const data = await getData(`v1/rdiiAnlsRslt/ppl/${selectedRowData.inftwtAnlsSn}`);
// 선택된 행 데이터를 Excel 다운로드 형식으로 변환
const excelData = data.content; // 배열로 감싸서 전달
// 파일명 생성 (분석번호 기반)
const fileName = `RDII분석결과_${selectedRowData.inftwtAnlsSn}_${selectedRowData.aplcnYm}`;
downloadExcel({
data: excelData as JSON[],
fileName: fileName,
sheetNameArray: ["RDII 분석결과"],
headerRange: "A1:D1" // 테이블 컬럼 수에 맞춰 조정
});
} catch (error) {
console.error("Excel 다운로드 중 오류 발생:", error);
alert("Excel 다운로드 중 오류가 발생했습니다. 다시 시도해주세요.");
}
};
// 파일 삭제 핸들러 추가
const handleFileDelete = async () => {
console.log("Selected row data for deletion:", selectedRowData);
if (!selectedRowData || selectedRowData.inftwtAnlsSn === undefined) {
alert('삭제할 파일을 선택해주세요.');
return;
}
// 삭제 확인 대화상자
const confirmDelete = window.confirm('선택된 분석 결과를 삭제하시겠습니까?');
if (!confirmDelete) {
return;
}
try {
// 삭제 API 호출
const response1 = await deleteData(`v1/rdiiAnlsRslt/${selectedRowData.inftwtAnlsSn}`);
const response2 = await deleteData(`v1/rdiiAnls/${selectedRowData.inftwtAnlsSn}`);
console.log("File delete response1:", response1);
console.log("File delete response2:", response2);
// 삭제 후 테이블 새로고침을 위해 재검색
const customFormValues: Partial<ResultFormValues> = {
aplcnYm: selectedRowData.aplcnYm || '0',
enoCd: selectedRowData.enoCd || '0',
ctpvCd: selectedRowData.ctpvCd || '0',
sggCd: selectedRowData.sggCd || '0',
swtrmtZoneCd: selectedRowData.swtrmtZoneCd || '0',
};
await handleSearchButtonClick(customFormValues);
// 선택된 행 초기화
setSelectedRowData(null);
setSelectedRowIndex(undefined);
alert('삭제가 완료되었습니다.');
} catch (error) {
console.error("분석결과 파일 삭제 중 오류 발생:", error);
alert("분석결과 파일 삭제 중 오류가 발생했습니다. 다시 시도해주세요.");
}
};
return (
<BaseLayout
selectBox={{ title: '분석 대상지역 선택', searchChk: true, onSearchClick: handleSearchButtonClick }}
titleName={{ mainTitle: '분석결과', firstCardTitle: 'RDII 산정결과 현황' }}
form={form} // form 인스턴스 전달
onSubmitEvent={() => { }} // BaseLayout의 form 태그에 연결될 onSubmit
graphBtn={true}
showDatePicker={true}
enoCd={form.watch("enoCd")}
setEnoCd={(val) => form.setValue("enoCd", val)}
ctpvCd={form.watch("ctpvCd")}
setCtpvCd={(val) => form.setValue("ctpvCd", val)}
sigungu={form.watch("sggCd")}
setSigungu={(val) => form.setValue("sggCd", val)}
selectedSwageTreatmentPlant={form.watch("swageTmplntCd")}
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))
}
}}
// Excel 다운로드 핸들러 추가
onExcelDownload={handleExcelDownload}
onDeleteFile={handleFileDelete}
selectedRowData={selectedRowData}
>
{[<div key='table1' className="h-[55vh] flex flex-col p-4 border rounded-lg bg-white shadow-md">
<div className="mb-[1.2rem] text-xl font-medium">○ RDII 분석결과 현황</div>
<div className="flex-grow overflow-auto">
<UiTable
headName=''
headlist={tableColumn}
tableData={tableData}
total={totalData}
pageSize={10}
children={undefined}
cellClick={handleCellClick}
onPageChange={(e) => { }}
/>
</div>
</div>
]}
</BaseLayout>
)
}
export default Result
+2 -32
View File
@@ -7,10 +7,6 @@ import { useForm } from 'react-hook-form'
import { z } from 'zod'
import BaseLayout from '../BaseLayout'
interface ApiSelectOption {
text: string;
val: string;
}
const formSchema = z.object({
enoCd: z.string().default('0'), // 환경청코드
@@ -37,19 +33,6 @@ const tableColumn = [
{ id: 'regDt', title: '분석일자' },
{ id: 'rgtrNm', title: '분석자' }
]
const tableColumn2 = [
{ id: 'no', title: '번호' },
{ id: 'analysis no', title: '분석번호' },
{ id: 'hasu', title: '하수처리장' },
{ id: 'guyeok', title: '처리구역' },
{ id: 'sangsu', title: '상수 사용량' },
{ id: 'rate', title: '오수 전환율' },
{ id: 'rtx', title: 'RTX 계수 출처' },
{ id: 'rdii', title: 'RDII 기여면적' },
{ id: 'rdii analysis info', title: 'RDII 분석정보' },
{ id: 'date', title: '분석일자' },
{ id: 'usr', title: '분석자' }
]
const Result = () => {
const form = useForm<ResultFormValues>({
@@ -151,7 +134,6 @@ const Result = () => {
const excelData = data.content; // 배열로 감싸서 전달
// 파일명 생성 (분석번호 기반)
const formValues = form.getValues();
const fileName = `침입수분석결과_${selectedRowData.inftwtAnlsSn}_${selectedRowData.aplcnYm}`;
downloadExcel({
@@ -210,7 +192,7 @@ const Result = () => {
return (
<BaseLayout
selectBox={{ title: '분석 대상지역 선택', searchChk: true, onSearchClick: handleSearchButtonClick }}
titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력', secondCardTitle: 'RDII 산정결과 현황' }}
titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력' }}
form={form} // form 인스턴스 전달
onSubmitEvent={() => { }} // BaseLayout의 form 태그에 연결될 onSubmit
graphBtn={true}
@@ -252,19 +234,7 @@ const Result = () => {
onPageChange={(e) => { }}
/>
</div>
</div>,
// <div key='table2'>
// <UiTable
// headName=''
// headlist={tableColumn2}
// tableData={rdiiResultData}
// total={rdiiResultData.length}
// pageSize={10}
// children={undefined}
// cellClick={(e) => { }}
// onPageChange={(e) => { }}
// />
// </div>
</div>
]}
</BaseLayout>
)
+2 -1
View File
@@ -20,7 +20,8 @@ export default function Home() {
<div className="flex flex-row gap-4 p-4">
<Link href={"/ii/irsetting"}><Button>침입수 분석</Button></Link>
<Link href={"/ii/rdii"}><Button>RDII 분석</Button></Link>
<Link href={"/ii/result"}><Button>분석결과</Button></Link>
<Link href={"/ii/result"}><Button>침입수 분석 결과</Button></Link>
<Link href={"/ii/rdii_result"}><Button>RDII 분석 결과</Button></Link>
</div>
</div>
</div>