Merge branch 'iipbs/sn/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/sn/dev
This commit is contained in:
@@ -648,4 +648,42 @@ export const untrtSwgRainCol5 = [
|
||||
{ id: 'mesureBod', title: 'BOD(mg/L)' },
|
||||
{ id: 'mesureToc', title: 'TOC(mg/L)' },
|
||||
{ id: 'mesureLoad', title: '오염부하량(kg)' }
|
||||
];
|
||||
|
||||
// 🎯 날짜 필드들 (yyyymmdd -> yyyy년 mm월 dd일)
|
||||
export const dateFields = [
|
||||
'instl_ymd', 'last_drdgn_ymd', 'cmcn_ymd', 'oprtng_strt_ymd', 'clsg_ymd',
|
||||
'mesure_begin_dt', 'mesure_end_dt', 'qltwtr_begin_dt', 'qltwtr_end_dt',
|
||||
'rain_begin_dt', 'rain_end_dt', 'mesureDt',
|
||||
// 🎯 camelCase 버전 추가
|
||||
'instlYmd', 'lastDrdgnYmd', 'cmcnYmd', 'oprtngStrtYmd', 'clsgYmd',
|
||||
'mesureBeginDt', 'mesureEndDt', 'qltwtrBeginDt', 'qltwtrEndDt',
|
||||
'rainBeginDt', 'rainEndDt'
|
||||
];
|
||||
|
||||
// 🎯 연월 필드들 (yyyymm -> yyyy년 m월)
|
||||
export const yearMonthFields = ['aplcnYm',];
|
||||
|
||||
// 🎯 날짜시간 필드들 (yyyy-mm-dd hh:mm:ss -> yyyy년 m월 d일 hh:mm)
|
||||
export const dateTimeFields = ['regDt',];
|
||||
|
||||
// 🎯 숫자 필드들 (천 단위 구분자)
|
||||
export const numberFields = [
|
||||
'pdmt', 'prlg', 'avg_grdn', 'drtw_mltv_area', 'excln_mltv_area', 'tmpt_dpth', 'scend_dpth', 'trfln_cnt', 'vrtc_len', 'wdth_len',
|
||||
'fclt_cpct', 'plln_area', 'prcs_zone_area_sum', 'swtrmt_ppltn_cnt', 'stty_crtr_bod', 'stty_crtr_toc', 'stty_crtr_ss', 'stty_crtr_tn', 'stty_crtr_tph', 'stty_crtr_clbcl_cnt',
|
||||
'swage_mh_diam', 'wdth_len', 'vrtc_len', 'altd_vl', 'dpthlVl',
|
||||
'plln_area', 'daily_prcs_cpct', 'max_impnd_cpct', 'altd_vl', 'wtlv_vl', 'excln_wpmp_ablt',
|
||||
'worflw_wall_hgt',
|
||||
'swr_ppl_eqp_ar', 'swr_trt_popl', 'weir_hg', 'weir_lt',
|
||||
'precdng_dry', 'rain_fall', 'cntnc_time', 'rain_in',
|
||||
'mesure_intrvl', 'qltwtr_co', 'mesureQy', 'mesureBod', 'mesureToc', 'mesureLoad',
|
||||
// 🎯 camelCase 버전 추가
|
||||
'avgGrdn', 'drtwMltvArea', 'exclnMltvArea', 'tmptDpth', 'scendDpth', 'trflnCnt', 'vrtcLen', 'wdthLen',
|
||||
'fcltCpct', 'pllnArea', 'prcsZoneAreaSum', 'swtrmtPpltnCnt', 'sttyCltrBod', 'sttyCltrToc', 'sttyCltrSs', 'sttyCltrTn', 'sttyCltrTph', 'sttyCltrClbclCnt',
|
||||
'swageMhDiam', 'altdVl', 'dpthlVl',
|
||||
'dailyPrcsCpct', 'maxImpndCpct', 'wtlvVl', 'exclnWpmpAblt',
|
||||
'worflwWallHgt',
|
||||
'swrPplEqpAr', 'swrTrtPopl', 'weirHg', 'weirLt',
|
||||
'precdngDry', 'rainFall', 'cntncTime', 'rainIn',
|
||||
'mesureIntrvl', 'qltwtrCo', 'rnysnFvlc', 'clarFvlc'
|
||||
];
|
||||
@@ -13,7 +13,7 @@ const drtwInputColumn = [
|
||||
]
|
||||
|
||||
// 하수펌프장
|
||||
const sewagePump = ({ featureData, isDrtwSewagePump, onSaveClick }: { featureData: any, isDrtwSewagePump: boolean, onSaveClick?: () => void }) => {
|
||||
const sewagePump = ({ featureData, isDrtwSewagePump, onSaveClick }: { featureData: any, isDrtwSewagePump?: boolean, onSaveClick?: () => void }) => {
|
||||
const [formData, setFormData] = useState<any>({});
|
||||
|
||||
// featureData가 변경될 때 formData 초기화
|
||||
|
||||
@@ -10,7 +10,8 @@ import { SwtrmtFcltCol, SwtrmtPrcsZoneCol, untrtSwgRainCol1, untrtSwgRainCol2, M
|
||||
import InfilChart from './components/popupComponent/chart/infilChart';
|
||||
import RdiiChart from './components/popupComponent/chart/rdiiChart';
|
||||
import { useInfilChartModalStore, useRdiiChartModalStore } from "./components/popupComponent/chartModalStore";
|
||||
import { set } from "react-hook-form";
|
||||
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
||||
|
||||
|
||||
// TODO:
|
||||
const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => {
|
||||
@@ -151,25 +152,21 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
|
||||
// 하수맨홀인 경우 용도코드를 텍스트로 변환
|
||||
if (selectedLayerName === '하수맨홀' && data) {
|
||||
const processedData = { ...data };
|
||||
|
||||
// mqlt_cd 값 변환 (재질코드)
|
||||
if (processedData.mqlt_cd) {
|
||||
if (data.mqlt_cd) {
|
||||
const materialCodeItem = MS_SWAGE_MHL_CODES.find(
|
||||
code => code.val === processedData.mqlt_cd.trim()
|
||||
code => code.val === data.mqlt_cd.trim()
|
||||
);
|
||||
if (materialCodeItem) {
|
||||
processedData.mqlt_cd = `${materialCodeItem.text}`;
|
||||
}
|
||||
if (materialCodeItem) data.mqlt_cd = `${materialCodeItem.text}`;
|
||||
}
|
||||
|
||||
setfetchData(processedData);
|
||||
setTableData(processedData);
|
||||
} else {
|
||||
setfetchData(data);
|
||||
setTableData(data);
|
||||
}
|
||||
|
||||
// 🎯 기본 데이터 포맷팅
|
||||
let formattedData = formatDisplayData(data);
|
||||
|
||||
setfetchData(formattedData);
|
||||
setTableData(formattedData);
|
||||
|
||||
switch (selectedLayerName) {
|
||||
case '하수처리시설':
|
||||
setHeadlist(SwtrmtFcltCol);
|
||||
@@ -185,8 +182,11 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
setButtonChk(false)
|
||||
setIsMainSsc(true)
|
||||
|
||||
setfetchData([processedData])
|
||||
setTableData(processedData);
|
||||
// 🎯 processedData도 포맷팅하여 설정
|
||||
const processedFormattedData = formatDisplayData(processedData);
|
||||
|
||||
setfetchData([processedFormattedData])
|
||||
setTableData(processedFormattedData);
|
||||
setIsLoading(false); // 기본 렌더링 완료
|
||||
|
||||
// 수량/수질측정 정보 데이터 호출
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
import { deleteData, getData } from '@/components/lib/api'
|
||||
import { UiTable, downloadExcelWithKoreanHeaders } from '@common/business_components/ui'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useState } from 'react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { z } from 'zod'
|
||||
import BaseLayout from '../BaseLayout'
|
||||
import { handleDelete } from '@/components/lib/utils'
|
||||
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
||||
|
||||
|
||||
const formSchema = z.object({
|
||||
@@ -83,6 +84,11 @@ const Result = () => {
|
||||
const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined);
|
||||
const [resetSelection, setResetSelection] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
// setCurPage(1);
|
||||
handleSearchButtonClick();
|
||||
}, [])
|
||||
|
||||
|
||||
const handleSearchButtonClick = async (customFormValues?: Partial<ResultFormValues>) => {
|
||||
setIsLoadingResult(true);
|
||||
@@ -92,12 +98,12 @@ const Result = () => {
|
||||
let inftwtAnlsSearchDto;
|
||||
|
||||
// swageTmplntCd 처리 로직 추가
|
||||
const processedSwageTmplntCd = formValues.swageTmplntCd && formValues.swageTmplntCd !== '0'
|
||||
const processedSwageTmplntCd = formValues.swageTmplntCd && formValues.swageTmplntCd !== '0'
|
||||
? (() => {
|
||||
const valString = String(formValues.swageTmplntCd);
|
||||
const parts = valString.split('.');
|
||||
return parts.length > 1 ? parts[1] : valString;
|
||||
})()
|
||||
const valString = String(formValues.swageTmplntCd);
|
||||
const parts = valString.split('.');
|
||||
return parts.length > 1 ? parts[1] : valString;
|
||||
})()
|
||||
: null;
|
||||
|
||||
if (customFormValues) {
|
||||
@@ -136,12 +142,20 @@ const Result = () => {
|
||||
console.log("API: ", `v1/rdiiAnls${queryString ? `?${queryString}` : ''}`);
|
||||
try {
|
||||
const data = await getData(`v1/rdiiAnls${queryString ? `?${queryString}` : ''}`);
|
||||
// 일련번호를 추가한 데이터로 변환
|
||||
const dataWithRowNumber = (data.content || []).map((item: any, index: number) => ({
|
||||
...item,
|
||||
rowNumber: index + 1, // 1부터 시작하는 일련번호 추가
|
||||
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn // scsYn이 null이면 'N'으로 변경
|
||||
}));
|
||||
|
||||
// 🎯 각 아이템을 개별적으로 포맷팅하면서 일련번호 추가
|
||||
const dataWithRowNumber = (data.content || []).map((item: any, index: number) => {
|
||||
// 🎯 먼저 각 아이템을 포맷팅
|
||||
const formattedItem = formatDisplayData(item);
|
||||
|
||||
// 추가 처리 및 일련번호 추가
|
||||
return {
|
||||
...formattedItem,
|
||||
rowNumber: index + 1, // 1부터 시작하는 일련번호 추가
|
||||
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn // scsYn이 null이면 'N'으로 변경
|
||||
};
|
||||
});
|
||||
|
||||
// setTableData(data.content || []);
|
||||
// setTotalData(tableData.length);
|
||||
setTableData(dataWithRowNumber);
|
||||
@@ -286,9 +300,9 @@ const Result = () => {
|
||||
selectedSwageProcessingZone={form.watch("swtrmtZoneCd")}
|
||||
onSwageProcessingZoneChange={(val) => form.setValue("swtrmtZoneCd", String(val))}
|
||||
aplcnYmFrom={form.watch("aplcnYmFrom")}
|
||||
setAplcnYmFrom={(val: string) => {form.setValue("aplcnYmFrom", val)}}
|
||||
setAplcnYmFrom={(val: string) => { form.setValue("aplcnYmFrom", val) }}
|
||||
aplcnYmTo={form.watch("aplcnYmTo")}
|
||||
setAplcnYmTo={(val: string) => {form.setValue("aplcnYmTo", val)}}
|
||||
setAplcnYmTo={(val: string) => { form.setValue("aplcnYmTo", val) }}
|
||||
isLoading={isLoadingResult}
|
||||
// Excel 다운로드 핸들러 추가
|
||||
onExcelDownload={handleExcelDownload}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
import { deleteData, getData } from '@/components/lib/api'
|
||||
import { UiTable, downloadExcel, downloadExcelWithKoreanHeaders } from '@common/business_components/ui'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useState } from 'react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { z } from 'zod'
|
||||
import BaseLayout from '../BaseLayout'
|
||||
import { handleDelete } from '@/components/lib/utils'
|
||||
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
||||
|
||||
|
||||
const formSchema = z.object({
|
||||
@@ -81,6 +82,10 @@ const Result = () => {
|
||||
const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined);
|
||||
const [resetSelection, setResetSelection] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
// setCurPage(1);
|
||||
handleSearchButtonClick();
|
||||
}, [])
|
||||
|
||||
const handleSearchButtonClick = async (customFormValues?: Partial<ResultFormValues>) => {
|
||||
setIsLoadingResult(true);
|
||||
@@ -90,12 +95,12 @@ const Result = () => {
|
||||
let inftwtAnlsSearchDto;
|
||||
|
||||
// swageTmplntCd 처리 로직 추가
|
||||
const processedSwageTmplntCd = formValues.swageTmplntCd && formValues.swageTmplntCd !== '0'
|
||||
const processedSwageTmplntCd = formValues.swageTmplntCd && formValues.swageTmplntCd !== '0'
|
||||
? (() => {
|
||||
const valString = String(formValues.swageTmplntCd);
|
||||
const parts = valString.split('.');
|
||||
return parts.length > 1 ? parts[1] : valString;
|
||||
})()
|
||||
const valString = String(formValues.swageTmplntCd);
|
||||
const parts = valString.split('.');
|
||||
return parts.length > 1 ? parts[1] : valString;
|
||||
})()
|
||||
: null;
|
||||
|
||||
if (customFormValues) {
|
||||
@@ -136,12 +141,19 @@ const Result = () => {
|
||||
console.log("API: ", `v1/inftwtAnls${queryString ? `?${queryString}` : ''}`);
|
||||
try {
|
||||
const data = await getData(`v1/inftwtAnls${queryString ? `?${queryString}` : ''}`);
|
||||
// 일련번호를 추가한 데이터로 변환
|
||||
const dataWithRowNumber = (data.content || []).map((item: any, index: number) => ({
|
||||
...item,
|
||||
rowNumber: index + 1, // 1부터 시작하는 일련번호 추가
|
||||
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn // scsYn이 null이면 'N'으로 변경
|
||||
}));
|
||||
|
||||
// 🎯 각 아이템을 개별적으로 포맷팅하면서 일련번호 추가
|
||||
const dataWithRowNumber = (data.content || []).map((item: any, index: number) => {
|
||||
// 🎯 먼저 각 아이템을 포맷팅
|
||||
const formattedItem = formatDisplayData(item);
|
||||
|
||||
// 추가 처리 및 일련번호 추가
|
||||
return {
|
||||
...formattedItem,
|
||||
rowNumber: index + 1, // 1부터 시작하는 일련번호 추가
|
||||
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn // scsYn이 null이면 'N'으로 변경
|
||||
};
|
||||
});
|
||||
// setTableData(data.content || []);
|
||||
// setTotalData(tableData.length);
|
||||
setTableData(dataWithRowNumber);
|
||||
@@ -248,7 +260,7 @@ const Result = () => {
|
||||
enoCd: selectedRowData.enoCd || null,
|
||||
ctpvCd: selectedRowData.ctpvCd || null,
|
||||
sggCd: selectedRowData.sggCd || null,
|
||||
swageTmplntCd: selectedRowData.swageTmplntCd || null,
|
||||
swageTmplntCd: selectedRowData.swageTmplntCd || null,
|
||||
// swtrmtZoneCd: selectedRowData.swtrmtZoneCd || null,
|
||||
};
|
||||
await handleSearchButtonClick(customFormValues);
|
||||
@@ -270,6 +282,8 @@ const Result = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<BaseLayout
|
||||
selectBox={{ title: '분석 대상지역 선택', searchChk: true, onSearchClick: handleSearchButtonClick }}
|
||||
@@ -289,9 +303,9 @@ const Result = () => {
|
||||
selectedSwageProcessingZone={form.watch("swtrmtZoneCd")}
|
||||
onSwageProcessingZoneChange={(val) => form.setValue("swtrmtZoneCd", String(val))}
|
||||
aplcnYmFrom={form.watch("aplcnYmFrom")}
|
||||
setAplcnYmFrom={(val: string) => {form.setValue("aplcnYmFrom", val)}}
|
||||
setAplcnYmFrom={(val: string) => { form.setValue("aplcnYmFrom", val) }}
|
||||
aplcnYmTo={form.watch("aplcnYmTo")}
|
||||
setAplcnYmTo={(val: string) => {form.setValue("aplcnYmTo", val)}}
|
||||
setAplcnYmTo={(val: string) => { form.setValue("aplcnYmTo", val) }}
|
||||
isLoading={isLoadingResult} // 로딩 상태 전달
|
||||
// Excel 다운로드 핸들러 추가
|
||||
onExcelDownload={handleExcelDownload}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
import { deleteData, postData } from '@/components/lib/api'
|
||||
import { searchCmmnCd, searchData } from '@/components/lib/common/apiHelpers'
|
||||
import { formatDate, handleDownload, yearOptions } from '@/components/lib/utils'
|
||||
import { searchData } from '@/components/lib/common/apiHelpers'
|
||||
import { formatDate, handleDownload } from '@/components/lib/utils'
|
||||
import LoadingOverlay from '@/components/ui/LoadingBar'
|
||||
import { SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, UiTable } from '@common/business_components/ui'
|
||||
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'
|
||||
@@ -15,8 +15,6 @@ const Page = () => {
|
||||
// 조회조건
|
||||
const [fromDate, setFromDate] = useState(() => { const date = new Date(); date.setDate(date.getDate() - 7); return date })
|
||||
const [toDate, setToDate] = useState(new Date())
|
||||
const [manageYear, setManageYear] = useState(yearOptions[0]?.val || '');
|
||||
const [mngQu, setMngQu] = useState(yearOptions[0]?.val || '');
|
||||
const [usr, setUsr] = useState('')
|
||||
const [pjNm, setpjNm] = useState('')
|
||||
// 파일업로드 관련 상태
|
||||
@@ -27,6 +25,7 @@ const Page = () => {
|
||||
const [curPage, setCurPage] = useState(1) //현재 페이지
|
||||
const [totalData, setTotalData] = useState(0) //총 데이터 수
|
||||
const [isLoading, setIsLoading] = useState(true) //로딩 상태
|
||||
const [isModalOpen, setIsModalOpen] = useState(false) // 모달 상태
|
||||
|
||||
// 조회
|
||||
const fetchData = async () => {
|
||||
@@ -87,6 +86,7 @@ const Page = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 현황 등록
|
||||
const registFile = async (fileName: string, year: string, quater: string, cd: string, id: string) => {
|
||||
const data = await postData('v1/sbmrgPrevnt', {
|
||||
@@ -97,8 +97,19 @@ const Page = () => {
|
||||
atflId: id,
|
||||
sbmrgPrevntBizNm: fileName
|
||||
})
|
||||
if (data) { alert('파일이 등록되었습니다.'); fetchData() }
|
||||
if (data) {
|
||||
alert('파일이 등록되었습니다.');
|
||||
setIsModalOpen(false);
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
|
||||
// 등록 버튼 클릭 핸들러
|
||||
const handleRegisterClick = () => {
|
||||
setIsModalOpen(true);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<LoadingOverlay isLoading={isLoading ?? false} />
|
||||
@@ -142,7 +153,10 @@ const Page = () => {
|
||||
</div>
|
||||
</SearchFormLeft>
|
||||
<SearchFormRight>
|
||||
<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 fetchData()} >조회</Button>
|
||||
<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 fetchData()} >조회</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">
|
||||
@@ -171,9 +185,22 @@ const Page = () => {
|
||||
onPageChange={async (page: number) => { setCurPage(page); await fetchData() }}
|
||||
/>
|
||||
</ListDiv>
|
||||
<ListDiv className="mt-4">
|
||||
<OperFileUploadForm title='도시침수 예방사업 사업추진현황 등록' onSubmit={async (file, year, quater, cd, id) => { await registFile(file, year, quater, cd, id) }} />
|
||||
</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)
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { deleteData, postData } from '@/components/lib/api'
|
||||
import { searchData } from '@/components/lib/common/apiHelpers'
|
||||
import { formatDate, handleDownload, yearOptions } from '@/components/lib/utils'
|
||||
import LoadingOverlay from '@/components/ui/LoadingBar'
|
||||
import { SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, UiTable } from '@common/business_components/ui'
|
||||
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'
|
||||
@@ -14,8 +14,6 @@ import OperFileUploadForm from '../../../components/ui/operFileUploadForm'
|
||||
const Page = () => {
|
||||
const [fromDate, setFromDate] = useState<Date>(() => { const date = new Date(); date.setDate(date.getDate() - 7); return date });
|
||||
const [toDate, setToDate] = useState<Date>(new Date());
|
||||
const [manageYear, setManageYear] = useState(yearOptions[0]?.val || '');
|
||||
const [mngQu, setMngQu] = useState(yearOptions[0]?.val || '');
|
||||
const [usr, setUsr] = useState('')
|
||||
const [pjNm, setpjNm] = useState('')
|
||||
const [fileNm, setFileNm] = useState('')
|
||||
@@ -25,6 +23,7 @@ const Page = () => {
|
||||
const [curPage, setCurPage] = useState(1)
|
||||
const [totalData, setTotalData] = useState(0) //총 데이터 수
|
||||
const [isLoading, setIsLoading] = useState(true) //로딩 상태
|
||||
const [isModalOpen, setIsModalOpen] = useState(false) // 모달 상태
|
||||
|
||||
// 데이터 조회
|
||||
const fetchData = async () => {
|
||||
@@ -98,7 +97,16 @@ const Page = () => {
|
||||
atflId: id,
|
||||
dcrpPplMtncBizNm: fileNm
|
||||
})
|
||||
if (data) { alert('파일이 등록되었습니다.'); fetchData() }
|
||||
if (data) {
|
||||
alert('파일이 등록되었습니다.');
|
||||
setIsModalOpen(false);
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
|
||||
// 등록 버튼 클릭 핸들러
|
||||
const handleRegisterClick = () => {
|
||||
setIsModalOpen(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +151,10 @@ const Page = () => {
|
||||
</div>
|
||||
</SearchFormLeft>
|
||||
<SearchFormRight>
|
||||
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 mr-2" size="sm" onClick={async () => { await fetchData() }}>조회</Button>
|
||||
<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 fetchData()} >조회</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">
|
||||
@@ -173,9 +184,22 @@ const Page = () => {
|
||||
onPageChange={async (page: number) => { setCurPage(page); await fetchData() }}
|
||||
/>
|
||||
</ListDiv>
|
||||
<ListDiv className="mt-4">
|
||||
<OperFileUploadForm title='노후 하수관로 정비사업 주진현황 등록' onSubmit={async (file, year, quater, cd, id) => { await registFile(file, year, quater, cd, id) }} />
|
||||
</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)
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,4 +54,57 @@ export const convertToTextValArray = (yyyymms: string[]): { text: string; val: s
|
||||
val: dateStr
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// 🎯 날짜 유효성 검사 함수 (8자리 또는 6자리 지원)
|
||||
export const isValidDateString = (dateStr: string): boolean => {
|
||||
// 숫자만 추출
|
||||
const cleanStr = dateStr.replace(/\D/g, '');
|
||||
|
||||
// 8자리 (yyyymmdd) 또는 6자리 (yyyymm) 확인
|
||||
if (cleanStr.length === 8) {
|
||||
// 연도, 월, 일 추출
|
||||
const year = parseInt(cleanStr.substring(0, 4));
|
||||
const month = parseInt(cleanStr.substring(4, 6));
|
||||
const day = parseInt(cleanStr.substring(6, 8));
|
||||
|
||||
// 기본 범위 검사
|
||||
if (year < 1900 || year > 2200) return false;
|
||||
if (month < 1 || month > 12) return false;
|
||||
if (day < 1 || day > 31) return false;
|
||||
|
||||
// Date 객체로 실제 유효한 날짜인지 검사
|
||||
const date = new Date(year, month - 1, day);
|
||||
return date.getFullYear() === year &&
|
||||
date.getMonth() === month - 1 &&
|
||||
date.getDate() === day;
|
||||
}
|
||||
else if (cleanStr.length === 6) {
|
||||
// 연도, 월 추출
|
||||
const year = parseInt(cleanStr.substring(0, 4));
|
||||
const month = parseInt(cleanStr.substring(4, 6));
|
||||
|
||||
// 기본 범위 검사
|
||||
if (year < 1900 || year > 2200) return false;
|
||||
if (month < 1 || month > 12) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// 🎯 날짜 포맷팅 함수
|
||||
export const formatDateString = (dateStr: string): string => {
|
||||
const cleanStr = dateStr.replace(/\D/g, ''); // 숫자만 추출
|
||||
|
||||
if (!isValidDateString(cleanStr)) {
|
||||
return dateStr; // 유효하지 않은 날짜면 원본 반환
|
||||
}
|
||||
|
||||
const year = cleanStr.substring(0, 4);
|
||||
const month = parseInt(cleanStr.substring(4, 6)); // parseInt로 앞의 0 제거
|
||||
const day = parseInt(cleanStr.substring(6, 8)); // parseInt로 앞의 0 제거
|
||||
|
||||
return `${year}년 ${month}월 ${day}일`;
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
import { dateFields, numberFields, yearMonthFields, dateTimeFields } from "../../../(map-layout)/map/components/common/table";
|
||||
import { isValidDateString, formatDateString } from "./date";
|
||||
|
||||
// 🎯 데이터 객체 전체를 포맷팅하는 함수
|
||||
export const formatDisplayData = (data: { [key: string]: any }): { [key: string]: string } => {
|
||||
if (!data) return {};
|
||||
|
||||
const formattedData: { [key: string]: string } = {};
|
||||
|
||||
Object.keys(data).forEach(fieldId => {
|
||||
const value = data[fieldId];
|
||||
|
||||
if (value === null || value === undefined || value === "") {
|
||||
formattedData[fieldId] = "-";
|
||||
return;
|
||||
}
|
||||
|
||||
// 🎯 연월 포맷팅 (yyyymm -> yyyy년 m월)
|
||||
if (yearMonthFields.includes(fieldId)) {
|
||||
const dateStr = String(value).trim();
|
||||
if (/^\d{6}$/.test(dateStr)) {
|
||||
const year = dateStr.substring(0, 4);
|
||||
const month = parseInt(dateStr.substring(4, 6));
|
||||
formattedData[fieldId] = `${year}년 ${month}월`;
|
||||
} else {
|
||||
formattedData[fieldId] = String(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 🎯 날짜시간 포맷팅 (yyyy-mm-dd hh:mm:ss -> yyyy년 m월 d일 hh:mm)
|
||||
if (dateTimeFields.includes(fieldId)) {
|
||||
const dateTimeStr = String(value).trim();
|
||||
// yyyy-mm-dd hh:mm:ss 형식 확인
|
||||
const dateTimeRegex = /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/;
|
||||
const match = dateTimeStr.match(dateTimeRegex);
|
||||
|
||||
if (match && match.length >= 6) {
|
||||
const year = match[1];
|
||||
const month = match[2];
|
||||
const day = match[3];
|
||||
const hour = match[4];
|
||||
const minute = match[5];
|
||||
const second = match[6];
|
||||
|
||||
// 🎯 undefined 체크 후 parseInt 적용
|
||||
if (year && month && day && hour && minute) {
|
||||
const formattedMonth = parseInt(month);
|
||||
const formattedDay = parseInt(day);
|
||||
formattedData[fieldId] = `${year}년 ${formattedMonth}월 ${formattedDay}일 ${hour}시 ${minute}분 ${second}초`;
|
||||
} else {
|
||||
formattedData[fieldId] = String(value);
|
||||
}
|
||||
} else {
|
||||
formattedData[fieldId] = String(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 🎯 기존 날짜 포맷팅 (yyyymmdd -> yyyy년 m월 d일)
|
||||
if (dateFields.includes(fieldId)) {
|
||||
const dateStr = String(value).trim();
|
||||
|
||||
// 숫자 타입이거나 숫자로만 구성된 문자열인지 확인
|
||||
if (/^\d+$/.test(dateStr)) {
|
||||
formattedData[fieldId] = formatDateString(dateStr);
|
||||
} else {
|
||||
formattedData[fieldId] = String(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 🎯 숫자 필드는 천 단위 구분자 추가
|
||||
if (numberFields.includes(fieldId)) {
|
||||
const numValue = Number(value);
|
||||
if (!isNaN(numValue) && isFinite(numValue)) {
|
||||
formattedData[fieldId] = numValue.toLocaleString('ko-KR');
|
||||
} else {
|
||||
formattedData[fieldId] = String(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 나머지는 문자열로 처리
|
||||
formattedData[fieldId] = String(value);
|
||||
});
|
||||
|
||||
return formattedData;
|
||||
};
|
||||
|
||||
// 🎯 단일 값만 포맷팅하는 함수 (기존 호환성을 위해 유지)
|
||||
export const formatDisplayValue = (value: any, fieldId: string): string => {
|
||||
const tempData = { [fieldId]: value };
|
||||
const formatted = formatDisplayData(tempData);
|
||||
return formatted[fieldId] || String(value);
|
||||
};
|
||||
@@ -4,3 +4,4 @@ export * from './date'
|
||||
export * from './excelToJson'
|
||||
export * from './fileDeleteUtil'
|
||||
export * from './fileDownload'
|
||||
export * from './formatDisplayValue'
|
||||
|
||||
Reference in New Issue
Block a user