Files
frontend/apps/sn/app/(with-base-layout)/ii/result/page.tsx
T

269 lines
10 KiB
TypeScript

'use client'
import { deleteData, getData } 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'
import { handleDelete } from '@/components/lib/utils'
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: 'inftwtAnlsSn', title: '분석번호' },
{ id: 'swageTmplntNm', title: '하수처리장' },
// { id: 'swtrmtZoneNm', title: '처리구역' },
{ id: 'aplcnYm', title: '적용연월' },
{ id: 'drtwSwtcRt', title: '오수 전환율' },
{ id: 'anlsInfo', title: '침입수 분석정보' },
{ id: 'regDt', title: '분석일자' },
{ id: 'rgtrNm', 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 [resetSelection, setResetSelection] = useState<boolean>(false);
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: '10000000',
sort: 'inftwtAnlsSn,desc'
});
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/inftwtAnls${queryString ? `?${queryString}` : ''}`);
try {
const data = await getData(`v1/inftwtAnls${queryString ? `?${queryString}` : ''}`);
setTableData(data.content || []);
setTotalData(tableData.length);
console.log("response:", data);
console.log("response data:", data.content || []);
setIsLoadingResult(false);
} catch (error) {
setIsLoadingResult(false);
console.error("Error fetching analysis result data:", error);
alert("분석결과 조회 중 오류가 발생했습니다.");
setTableData([]);
setTotalData(0);
}
};
// 테이블 셀 클릭 핸들러 추가
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 () => {
setIsLoadingResult(true);
console.log("Selected row data for download:", selectedRowData);
if (!selectedRowData || selectedRowData.inftwtAnlsSn === undefined) {
setIsLoadingResult(false);
alert('다운로드할 데이터를 선택해주세요.');
return;
}
try {
const data = await getData(`v1/inftwtAnlsRslt/ppl/${selectedRowData.inftwtAnlsSn}`);
// 선택된 행 데이터를 Excel 다운로드 형식으로 변환
const excelData = data.content; // 배열로 감싸서 전달
// 파일명 생성 (분석번호 기반)
const fileName = `침입수분석결과_${selectedRowData.inftwtAnlsSn}_${selectedRowData.aplcnYm}`;
downloadExcel({
data: excelData as JSON[],
fileName: fileName,
sheetNameArray: ["침입수 분석결과"],
headerRange: "A1:D1" // 테이블 컬럼 수에 맞춰 조정
});
setIsLoadingResult(false);
} catch (error) {
setIsLoadingResult(false);
console.error("Excel 다운로드 중 오류 발생:", error);
alert("Excel 다운로드 중 오류가 발생했습니다. 다시 시도해주세요.");
}
};
// 파일 삭제 핸들러 추가
const handleFileDelete = async () => {
setIsLoadingResult(true);
console.log("Selected row data for deletion:", selectedRowData);
if (!selectedRowData || selectedRowData.inftwtAnlsSn === undefined) {
setIsLoadingResult(false);
alert('삭제할 파일을 선택해주세요.');
return;
}
// 삭제 확인 대화상자
const confirmDelete = window.confirm('선택된 분석 결과를 삭제하시겠습니까?');
if (!confirmDelete) {
return;
}
try {
// // 삭제 API 호출
console.log("Deleting analysis result with inftwtAnlsSn:", selectedRowData.inftwtAnlsSn);
const response1 = await deleteData(`v1/inftwtAnlsRslt/${selectedRowData.inftwtAnlsSn}`);
const response2 = await deleteData(`v1/inftwtAnls/${selectedRowData.inftwtAnlsSn}`);
// 첨부파일(inp파일) 삭제 API 호출
handleDelete(selectedRowData.atflCd, {
handleDeleteStart: () => console.log("파일 삭제 시작"),
handleDeleteSuccess: (response) => console.log("파일 삭제 성공:", response),
handleDeleteError: (error) => console.error("파일 삭제 실패:", error),
});
console.log("File delete response1:", response1);
console.log("File delete response2:", response2);
// 테이블 선택 상태 초기화 트리거
setResetSelection(true);
// 삭제 후 테이블 새로고침을 위해 재검색
const customFormValues: Partial<ResultFormValues> = {
aplcnYm: selectedRowData.aplcnYm || null,
enoCd: selectedRowData.enoCd || null,
ctpvCd: selectedRowData.ctpvCd || null,
sggCd: selectedRowData.sggCd || null,
swtrmtZoneCd: selectedRowData.swtrmtZoneCd || null,
};
await handleSearchButtonClick(customFormValues);
// 선택된 행 초기화
setSelectedRowData(null);
setSelectedRowIndex(undefined);
setIsLoadingResult(false);
alert('삭제가 완료되었습니다.');
setTimeout(() => {
setResetSelection(false);
}, 100);
} catch (error) {
setIsLoadingResult(false);
console.error("분석결과 파일 삭제 중 오류 발생:", error);
alert("분석결과 파일 삭제 중 오류가 발생했습니다. 다시 시도해주세요.");
}
};
return (
<BaseLayout
selectBox={{ title: '분석 대상지역 선택', searchChk: true, onSearchClick: handleSearchButtonClick }}
titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력' }}
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))
}
}}
isLoading={isLoadingResult} // 로딩 상태 전달
// 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">○ 침입수 산정결과 현황</div>
<div className="flex-grow overflow-auto">
<UiTable
headName=''
headlist={tableColumn}
tableData={tableData}
total={totalData}
pageSize={10}
children={undefined}
cellClick={handleCellClick}
onPageChange={(e) => { }}
resetSelection={resetSelection}
/>
</div>
</div>
]}
</BaseLayout>
)
}
export default Result