Files
frontend/apps/sn/app/(with-base-layout)/oper/floodPre/page.tsx
T
swcho 92692c0c46 feat:
- 도시침수예방사업, 노후 하수관로 정비사업 등록자 등록 및 조회 기능 구현
- 컬럼명 수정된 거에 맞게 변수명 수정 (하수펌프장, 하수맨홀)
2025-08-08 17:32:06 +09:00

258 lines
9.2 KiB
TypeScript

'use client'
import { deleteData, postData, useCookieAuth } from '@/components/lib/api'
import { searchData } from '@/components/lib/common/apiHelpers'
import { formatDate, handleDownload } from '@/components/lib/utils'
import LoadingOverlay from '@/components/ui/LoadingBar'
import { SearchDiv, SearchFormLeft, SearchFormRight, UiTable, UiModal } from '@common/business_components/ui'
import ListDiv from '@common/business_components/ui/list_div'
import { Button, DatePicker, Input, Label } from '@common/components/ui'
import { useEffect, useState } from 'react'
import { tableHeadlist } from '..'
import OperFileUploadForm from '../../../components/ui/operFileUploadForm'
import { tokenManager } from '@/entities/auth/lib/token-manager';
import { AUTH_USER_ID } from "@/shared/config";
import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "@common/components/config";
import { getUserInfo } from "@common/components/api";
const Page = () => {
const AUTH = useCookieAuth();
// 조회조건
const [fromDate, setFromDate] = useState(() => { const date = new Date(); date.setDate(date.getDate() - 7); return date })
const [toDate, setToDate] = useState(new Date())
const [usr, setUsr] = useState('')
const [pjNm, setpjNm] = useState('')
// 파일업로드 관련 상태
const [fileNm, setFileNm] = useState('') //파일명
const [atflId, setAtflId] = useState('') //파일 ID
const [sbmrgPrevntBizSn, setSbmrgPrevntBizSn] = useState('') //파일 일련번호
const [tableData, setTableData] = useState<any>([{}]) //테이블 데이터
const [curPage, setCurPage] = useState(1) //현재 페이지
const [totalData, setTotalData] = useState(0) //총 데이터 수
const [isLoading, setIsLoading] = useState(true) //로딩 상태
const [isModalOpen, setIsModalOpen] = useState(false) // 모달 상태
const [resetSelection, setResetSelection] = useState<boolean>(false); // 선택 초기화 상태
const [isResetPage, setIsResetPage] = useState<boolean>(false);
const { data: userInfo } = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.USERS],
queryFn: () => getUserInfo(),
enabled: true,
});
useEffect(() => {
setCurPage(1)
fetchData()
}, [])
// 페이지 변경 시마다 데이터 fetch
useEffect(() => {
setIsResetPage(false);
fetchData();
}, [curPage]);
// 조회 버튼 클릭 시 1페이지로 이동 및 데이터 초기화
const handleSearch: () => Promise<void> = async () => {
setCurPage(1); // 페이지를 1로 초기화
setIsResetPage(true); // 페이지를 초기화
await fetchData();
};
// 조회
const fetchData = async () => {
setIsLoading(true)
setResetSelection(true);
// searchCmmnCd('SITEKNDCD')
try {
const { data, total } = await searchData('v1/sbmrgPrevnt', {
fromRegDt: formatDate(fromDate),
toRegDt: formatDate(toDate),
sbmrgPrevntBizNm: pjNm,
auth: AUTH,
page: curPage - 1,
size: '10'
})
// 일련번호를 추가한 데이터로 변환 (전체 데이터 기준으로 일련번호 계산)
const dataWithRowNumber = (data || []).map((item: any, index: number) => ({
...item,
rowNumber: (curPage - 1) * 10 + index + 1, // 페이지 기준 일련번호 계산
}));
setTableData(dataWithRowNumber)
setTotalData(total)
}
catch (error) { console.error('Error fetching data:', error) }
finally {
setFileNm('');
setAtflId('');
setSbmrgPrevntBizSn('');
setIsLoading(false);
setResetSelection(false);
}
}
// 파일 다운로드
const isChckFile = () => {
if (fileNm === '' || fileNm === undefined) {
alert('파일을 선택해주세요')
return false
}
handleDownload(`/attach-service/api/v1/download/${atflId}`, fileNm)
}
// 선택 파일 삭제
const isDeleteFile = async () => {
if (sbmrgPrevntBizSn === '' || sbmrgPrevntBizSn === undefined) {
alert('삭제할 파일을 선택해주세요')
return false
}
const data = await deleteData(`/attach-service/api/v1/atfl/attachments/${atflId}`)
if (data) {
const delData = await deleteData(`v1/sbmrgPrevnt/${sbmrgPrevntBizSn}`)
if (delData.status === 200) {
alert('삭제되었습니다.')
fetchData()
}
}
else {
alert('삭제에 실패했습니다.')
}
}
// 현황 등록
const registFile = async (fileName: string, year: string, quater: string, cd: string, id: string) => {
const json = {
atflNm: fileName,
mngYr: year,
mngQu: quater,
atflCd: cd,
atflId: id,
sbmrgPrevntBizNm: fileName,
rgtr: tokenManager.getToken(AUTH_USER_ID) || null
}
console.log('request DTO', json);
const data = await postData('v1/sbmrgPrevnt', json)
if (data) {
alert('파일이 등록되었습니다.');
setIsModalOpen(false);
handleSearch();
}
}
// 등록 버튼 클릭 핸들러
const handleRegisterClick = () => {
setIsModalOpen(true);
}
return (
<>
<LoadingOverlay isLoading={isLoading ?? false} />
<SearchDiv>
<SearchFormLeft>
<div className='flex items-center gap-5'>
<div className='flex items-center gap-2'>
<Label className="w-20 text-xl text-gray-600">등록기간</Label>
<DatePicker mode={'single'}
selected={fromDate}
onSelect={(date: Date | undefined) => { if (date) setFromDate(date) }}
modifiers={{
disabled: { after: new Date() }
}}
/>
<span>~</span>
<DatePicker mode={'single'}
selected={toDate}
onSelect={(date: Date | undefined) => { if (date) setToDate(date) }}
modifiers={{
disabled: { after: new Date() }
}}
/>
</div>
<div className='flex items-center'>
<Label className="w-20 text-xl text-gray-600">등록자</Label>
<Input
className='w-[100px]'
value={usr}
onChange={(e) => setUsr(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleSearch();
}
}}
/>
</div>
<div className='flex items-center'>
<Label className="w-20 text-xl text-gray-600">파일명</Label>
<Input
className='w-[100px]'
value={pjNm}
onChange={(e) => setpjNm(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleSearch();
}
}}
/>
</div>
</div>
</SearchFormLeft>
<SearchFormRight>
<div className='flex items-center gap-5'>
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" size="sm" onClick={async () => await handleSearch()} >조회</Button>
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" size="sm" onClick={handleRegisterClick} >등록</Button>
</div>
</SearchFormRight>
</SearchDiv>
<ListDiv className="mt-4">
<div className="card-header flex items-center justify-between">
<h3 className="text-2xl font-medium">사업정보 등록현황</h3>
<div>
<Button className="px-4 py-2 !mr-[1.2rem] bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" size="sm" onClick={isChckFile} >파일 다운로드</Button>
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" onClick={isDeleteFile} >삭제</Button>
</div>
</div>
<UiTable
headName=''
tableData={tableData}
headlist={tableHeadlist}
pageSize={10}
total={totalData}
cellClick={(index) => {
if (index != null) {
const fileName = tableData[index]?.sbmrgPrevntBizNm ?? "";
const id = tableData[index]?.atflId ?? '';
setFileNm(fileName);
setAtflId(id);
setSbmrgPrevntBizSn(tableData[index]?.sbmrgPrevntBizSn);
}
}}
onPageChange={setCurPage}
resetSelection={resetSelection}
resetPageNo={isResetPage}
/>
</ListDiv>
{/* 파일 업로드 모달 */}
<UiModal
open={isModalOpen}
onOpenChange={setIsModalOpen}
bodyClass="w-auto max-w-[90vw] min-w-[600px] h-auto"
noHeaderYn="N"
noFooterYn="Y"
body={
<OperFileUploadForm
title='도시침수 예방사업 추진현황 등록'
onSubmit={async (file, year, quater, cd, id) => {
await registFile(file, year, quater, cd, id)
}}
/>
}
/>
</>
)
}
export default Page