Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend
This commit is contained in:
@@ -60,6 +60,8 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
||||
// 데이터 변환을 위한 별도의 useEffect
|
||||
useEffect(() => {
|
||||
if (sdmInfoStatusList.length > 0) {
|
||||
|
||||
|
||||
const newTransformedList = sdmInfoStatusList.map((item: DemandCompBizType) => ({
|
||||
...item,
|
||||
ctpvCd: selectSidoData.find(sido => sido.val === item.ctpvCd?.trim())?.text || '',
|
||||
|
||||
@@ -54,11 +54,25 @@ function SdmInfoInsertContent() {
|
||||
|
||||
useEffect(() => {
|
||||
const user = sessionStorage.getItem("user");
|
||||
|
||||
|
||||
setDefaultValues((prev) => ({
|
||||
...prev,
|
||||
sdmNm: searchParams.get("dmdCoNm") || "",
|
||||
}));
|
||||
sessionStorage.setItem("user", searchParams.get("dmdInfoId") || "");
|
||||
if(searchParams.get("dmdInfoId")){
|
||||
// const data = {
|
||||
// dmdCoNm: searchParams.get("dmdCoNm") || '',
|
||||
// ctpvCd: searchParams.get("ctpvCd") || '',
|
||||
// sggCd: searchParams.get("sggCd") || '',
|
||||
// dmdInfoId: searchParams.get("dmdInfoId") || '',
|
||||
// daddr: searchParams.get("daddr") || '',
|
||||
// telno: searchParams.get("telno") || '',
|
||||
// }
|
||||
|
||||
// sessionStorage.setItem("user", JSON.stringify(data || {}));
|
||||
}
|
||||
//sessionStorage.setItem("user", JSON.parse(user||'') || "");
|
||||
setIsLogin(user || searchParams.get("dmdInfoId") ? true : false);
|
||||
}, [searchParams]);
|
||||
|
||||
|
||||
@@ -691,6 +691,7 @@ export const SdmReducer = (set: any): SdmActions => {
|
||||
// 수요정보 신청현황
|
||||
getSdmInfoStatusList: async (dmdInfoId: string) => {
|
||||
const res = await getSdmInfoStatusList(dmdInfoId);
|
||||
|
||||
if(res.length === 0) {
|
||||
set((state: SdmType) => ({
|
||||
Sdm: {
|
||||
@@ -700,15 +701,15 @@ export const SdmReducer = (set: any): SdmActions => {
|
||||
}))
|
||||
return;
|
||||
}
|
||||
const sdmInfoStatusList : DemandCompBizType[] = [];
|
||||
//const sdmInfoStatusList : DemandCompBizType[] = [];
|
||||
|
||||
res.demandInfo.map((el: DemandCompBizType, index: number) => {
|
||||
const sdmInfoStatusList : DemandCompBizType[]= res.demandInfo.map((el: DemandCompBizType, index: number) => {
|
||||
const matchingInfo = res.demandMatchings.find((matching: DemandMatchings) => matching.dmdInfoSn === el.dmdInfoSn);
|
||||
const status = matchingInfo?.splyFcltFlg?.trim() === 'Sub' ? '검토' : matchingInfo?.splyFcltFlg?.trim() === 'matched' ? '매칭완료' : '신청';
|
||||
const ruseUtztnFcltNm = matchingInfo?.ruseUtztnFcltNm ? matchingInfo.ruseUtztnFcltNm : '';
|
||||
|
||||
|
||||
const tmpData = {
|
||||
return( {
|
||||
...el,
|
||||
index: ++index,
|
||||
bzmnNo: res.bzmnNo,
|
||||
@@ -725,9 +726,9 @@ export const SdmReducer = (set: any): SdmActions => {
|
||||
status : status,
|
||||
splyCndtList: el.splyCndtList,
|
||||
ruseUtztnFcltNm: ruseUtztnFcltNm || ''
|
||||
}
|
||||
sdmInfoStatusList.push(tmpData);
|
||||
})
|
||||
})
|
||||
|
||||
set((state: SdmType) => ({
|
||||
Sdm: {
|
||||
...state.Sdm,
|
||||
|
||||
@@ -10,4 +10,4 @@ NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
|
||||
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
|
||||
NEXT_PUBLIC_NGII_URL = http://10.98.25.94:18080/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/sewerage-service/api
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = https://apigateway.hasuon.or.kr/sewerage-service/api
|
||||
|
||||
@@ -149,18 +149,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
setIsResetDetailSelection(true); // 선택 초기화
|
||||
setDetailBizId(0);
|
||||
// queryParams는 fetchFilteredData 내에서 매번 새로 생성되므로 별도 상태 초기화는 필요 없음
|
||||
}, [activeTab, basicType, workType, open]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveTab(TABS[0]?.val ?? "basic");
|
||||
setBasicType(BASIC_TYPES[0]?.val ?? "");
|
||||
setWorkType(WORK_TYPES[0]?.val ?? "");
|
||||
setTableCount(0);
|
||||
setTableData([]);
|
||||
setDetailTableCount(0);
|
||||
setDetailTableData([]);
|
||||
setDetailBizId(0);
|
||||
}, [open]);
|
||||
}, [activeTab, basicType, workType]);
|
||||
|
||||
// 페이지 변경 시마다 데이터 fetch
|
||||
useEffect(() => {
|
||||
@@ -490,14 +479,16 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
};
|
||||
|
||||
// 기본정보 테이블 cellClick 핸들러
|
||||
const handleBasicCellClick = (index?: number | undefined, headId?: String) => {
|
||||
const handleBasicCellClick = async (index?: number | undefined, headId?: String) => {
|
||||
if (typeof index === "number") {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = tableData[index];
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fid = row.fid;
|
||||
const core = GisApp.Module.layer as any;
|
||||
core.showSearchResultsFromGeoJSON(layerNm, fid);
|
||||
await core.showSearchResultsFromGeoJSON(layerNm, fid);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false); // SearchModal 닫기
|
||||
}
|
||||
};
|
||||
@@ -521,8 +512,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
RequestDTO.workTypes = JSON.parse(workType.replace(/'/g, '"'));
|
||||
|
||||
const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`);
|
||||
console.log('운영정보 cellClick 데이터1:', res);
|
||||
console.log('운영정보 cellClick 데이터2:', res.data);
|
||||
console.log('운영정보 cellClick 데이터:', res.data);
|
||||
|
||||
const mappedData = (res.data || []).map((item: any, detailIndex: number) => {
|
||||
const formattedItem = formatDisplayData(item);
|
||||
@@ -587,8 +577,22 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleOperationResultCellClick = async (index?: number | undefined, headId?: String) => {
|
||||
if (typeof index === "number") {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = detailTableData[index];
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fid = row.fid;
|
||||
const core = GisApp.Module.layer as any;
|
||||
await core.showSearchResultsFromGeoJSON(layerNm, fid);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false); // SearchModal 닫기
|
||||
}
|
||||
};
|
||||
|
||||
// 기본정보 Excel 다운로드 핸들러
|
||||
const BasicExcelDownload = async () => {
|
||||
const basicExcelDownload = async () => {
|
||||
if (tableData.length === 0) {
|
||||
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||
return;
|
||||
@@ -804,7 +808,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
};
|
||||
|
||||
// 운영정보 Excel 다운로드 핸들러 추가
|
||||
const OperationExcelDownload = async () => {
|
||||
const operationExcelDownload = async () => {
|
||||
if (tableData.length === 0) {
|
||||
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||
return;
|
||||
@@ -898,7 +902,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
};
|
||||
|
||||
// 운영정보 Excel 다운로드 핸들러 추가
|
||||
const OperationResultExcelDownload = async () => {
|
||||
const operationResultExcelDownload = async () => {
|
||||
if (detailTableData.length === 0) {
|
||||
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||
return;
|
||||
@@ -1001,12 +1005,41 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const viewMultipleFeature = async () => {
|
||||
if (activeTab === 'basic') {
|
||||
if (!(tableData.length === 0)) {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = tableData[0];
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fids = tableData.map((item) => item.fid);
|
||||
const core = GisApp.Module.layer as any;
|
||||
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false);
|
||||
}
|
||||
} else if (activeTab === 'operation') {
|
||||
if (!(detailTableData.length === 0)) {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = detailTableData[0];
|
||||
console.log('row', row);
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fids = detailTableData.map((item) => item.fid);
|
||||
const core = GisApp.Module.layer as any;
|
||||
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const renderBody = () => (
|
||||
<>
|
||||
{/* 탭 영역 */}
|
||||
<UITab
|
||||
defaultValue={TABS[0]?.val}
|
||||
defaultValue={activeTab}
|
||||
tabList={TABS.map((tab) => ({
|
||||
value: tab.val,
|
||||
label: tab.text
|
||||
@@ -1084,7 +1117,10 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
headButton={
|
||||
<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={BasicExcelDownload}>파일 다운로드</Button>
|
||||
<div className='flex'>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -1112,7 +1148,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
headButton={
|
||||
<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={OperationExcelDownload}>파일 다운로드</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-sm font-medium green" size="sm" onClick={operationExcelDownload}>파일 다운로드</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -1133,12 +1169,15 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
headlist={dynamicHeadlist2}
|
||||
pageSize={OPERATION_TABLE_SIZE}
|
||||
total={detailTableCount}
|
||||
cellClick={undefined}
|
||||
cellClick={handleOperationResultCellClick}
|
||||
onPageChange={setDetailCurPage}
|
||||
resetPageNo={isResetDetailPage}
|
||||
resetSelection={isResetDetailSelection}
|
||||
headButton={
|
||||
<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={OperationResultExcelDownload}>파일 다운로드</Button>
|
||||
<div className='flex'>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={operationResultExcelDownload}>파일 다운로드</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -58,6 +58,8 @@ type BaseLayout = {
|
||||
onDeleteFile?: () => void;
|
||||
onAnalysis?: () => void;
|
||||
selectedRowData?: any;
|
||||
isIr?: boolean;
|
||||
isRdii?: boolean;
|
||||
}
|
||||
|
||||
const BaseLayout = ({
|
||||
@@ -87,6 +89,8 @@ const BaseLayout = ({
|
||||
onExcelDownload,
|
||||
onDeleteFile,
|
||||
onAnalysis,
|
||||
isIr = false,
|
||||
isRdii = false,
|
||||
}: BaseLayout) => {
|
||||
|
||||
// 컴포넌트 언마운트 시 confirmToast 정리
|
||||
@@ -207,6 +211,24 @@ const BaseLayout = ({
|
||||
{graphBtn && (
|
||||
<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>
|
||||
)}
|
||||
{/* 침입수 분석 */}
|
||||
{isIr && (
|
||||
<Button
|
||||
size="sm"
|
||||
className="mx-4 py-2 text-white rounded-sm text-lg font-medium green"
|
||||
>
|
||||
<a href="/samples/ir_setting_sample.zip" download="침입수 분석 업로드 파일 양식.zip">양식 받기</a>
|
||||
</Button>
|
||||
)}
|
||||
{/* RDII 분석 */}
|
||||
{isRdii && (
|
||||
<Button
|
||||
size="sm"
|
||||
className="mx-4 py-2 text-white rounded-sm text-lg font-medium green"
|
||||
>
|
||||
<a href="/samples/rdii_sample.zip" download="RDII 분석 업로드 파일 양식.zip">양식 받기</a>
|
||||
</Button>
|
||||
)}
|
||||
{/* 분석 버튼 */}
|
||||
{analysisBtn && (
|
||||
<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={handleConfirm}>{analysisBtn}</Button>
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
'use client'
|
||||
|
||||
// FileUpload.js
|
||||
import React, { useState } from 'react';
|
||||
import axios from 'axios';
|
||||
const SEWERAGE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
|
||||
|
||||
function FileUpload() {
|
||||
const [file, setFile] = useState(null);
|
||||
const [text, setText] = useState('');
|
||||
|
||||
const handleFileChange = (e) => {
|
||||
setFile(e.target.files[0]);
|
||||
};
|
||||
|
||||
const handleTextChange = (e) => {
|
||||
setText(e.target.value);
|
||||
};
|
||||
|
||||
function getCookie(name:string) {
|
||||
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||
if (match && match[2]) {
|
||||
return decodeURIComponent(match[2]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const handleFindUser = (e) => {
|
||||
const auth = getCookie("Authorization");
|
||||
if (auth) console.log("쿠키 auth : " + auth);
|
||||
fetch(SEWERAGE_URL+"/v1/inftwtAnls/users/65a00f65-8460-49af-98ec-042977e56f4b", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({authToken: auth})
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
const handleFindUserOna = (e) => {
|
||||
const auth = getCookie("Authorization");
|
||||
if (auth) console.log("쿠키 auth : " + auth);
|
||||
fetch("/server/user-service/api/v1/users/65a00f65-8460-49af-98ec-042977e56f4b").then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!file) {
|
||||
alert('파일을 선택하세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const jsonData = {
|
||||
aplcnYm: '202507',
|
||||
enoCd: 'ABC'
|
||||
};
|
||||
|
||||
// JSON → Blob 으로 변환 + MIME 지정
|
||||
const jsonBlob = new Blob([JSON.stringify(jsonData)], {
|
||||
type: 'application/json'
|
||||
});
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('data', jsonBlob);
|
||||
formData.append('inpFile', file);
|
||||
|
||||
try {
|
||||
const response = await axios.post('http://localhost:8883/sewerage-service/api/v1/rdiiAnls/savewithfile', formData);
|
||||
|
||||
alert('업로드 성공: ' + response.data.message);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert('업로드 실패');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="text-2xl">
|
||||
<div>
|
||||
<label>텍스트 입력:</label>
|
||||
<input type="text" value={text} onChange={handleTextChange} />
|
||||
</div>
|
||||
<div>
|
||||
<label>파일 선택:</label>
|
||||
<input type="file" onChange={handleFileChange} />
|
||||
</div>
|
||||
<button type="submit" className="px-4 py-2 bg-gray-500 text-white rounded">업로드</button>
|
||||
<button type="button" className="px-4 py-2 bg-gray-400 text-white rounded"
|
||||
onClick={handleFindUser}>사용자조회</button>
|
||||
<button type="button" className="px-4 py-2 bg-gray-200 text-white rounded"
|
||||
onClick={handleFindUserOna}>사용자조회ona</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default FileUpload;
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import { postData } from '@/components/lib/api'
|
||||
import { postMutiPart } from '@/components/lib/api'
|
||||
import FileUploadForm from '@/components/ui/fileUploadForm'
|
||||
import FormSection from '@/components/ui/formSection'
|
||||
import { DateMonthPicker, filePicked } from '@common/business_components/ui'
|
||||
@@ -52,6 +52,19 @@ const IrSetting = () => {
|
||||
const [sggCd, setSggCd] = useState<string>('0'); // 시군구 코드 상태
|
||||
const [sggName, setSggName] = useState<string>(''); // 시군구 이름 상태
|
||||
const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>(''); // 하수처리시설명 상태
|
||||
const [uploadedFilesData, setUploadedFilesData] = useState<UploadedFileInfo[]>([
|
||||
initialFileInfo, // 0: 오수관망도
|
||||
initialFileInfo, // 1: 수용가-맨홀 매칭결과
|
||||
initialFileInfo, // 2: 오수량 시간패턴
|
||||
initialFileInfo // 3: 유량자료 등록
|
||||
]);
|
||||
// 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 { data: userInfo } = useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
@@ -72,21 +85,6 @@ const IrSetting = () => {
|
||||
}
|
||||
})
|
||||
|
||||
const [uploadedFilesData, setUploadedFilesData] = useState<UploadedFileInfo[]>([
|
||||
initialFileInfo, // 0: 오수관망도
|
||||
initialFileInfo, // 1: 수용가-맨홀 매칭결과
|
||||
initialFileInfo, // 2: 오수량 시간패턴
|
||||
initialFileInfo // 3: 유량자료 등록
|
||||
]);
|
||||
|
||||
// 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 resetAllForms = () => {
|
||||
form.reset({ // react-hook-form 초기화
|
||||
@@ -121,7 +119,7 @@ const IrSetting = () => {
|
||||
index: number, // FileUploadForm의 fileIdx 값
|
||||
selectedFile: File | null,
|
||||
cd: string | null,
|
||||
id: string | null
|
||||
id: string | null,
|
||||
) => {
|
||||
setUploadedFilesData(prevData => {
|
||||
const newData = [...prevData];
|
||||
@@ -137,17 +135,16 @@ const IrSetting = () => {
|
||||
|
||||
|
||||
const registFile = async (analysisData: any) => {
|
||||
setIsLoadingResult(true); // 로딩 상태 시작
|
||||
setIsLoadingResult(true);
|
||||
console.log("Submitting combined analysis data to backend:", analysisData);
|
||||
// 추후 API 엔드포인트에 맞게 URL 수정 필요
|
||||
const data = await postData('v1/inftwtAnls', analysisData);
|
||||
const data = await postMutiPart('v1/inftwtAnls/savewithfile', analysisData);
|
||||
console.log("Response from backend:", data);
|
||||
if (data) {
|
||||
setIsLoadingResult(false); // 로딩 상태 시작
|
||||
setIsLoadingResult(false);
|
||||
alert("분석 데이터가 성공적으로 제출되었습니다.");
|
||||
resetAllForms(); // 성공 시 폼 초기화 함수 호출
|
||||
} else {
|
||||
setIsLoadingResult(false); // 로딩 상태 시작
|
||||
setIsLoadingResult(false);
|
||||
alert("분석 데이터 제출 중 오류가 발생했습니다.");
|
||||
}
|
||||
};
|
||||
@@ -306,10 +303,10 @@ const IrSetting = () => {
|
||||
: null;
|
||||
const rcptrInfoData = file5?.file
|
||||
? parsedResults.find(r => r && r.fileName === file5.file?.name)?.parsedData
|
||||
: null;
|
||||
: null;
|
||||
|
||||
// 새로운 JSON 데이터 생성
|
||||
const combinedAnalysisData = {
|
||||
const jsonData = {
|
||||
ctpvCd: ctpvCd !== '0' ? String(ctpvCd).trim() : null,
|
||||
sggCd: sggCd !== '0' ? String(sggCd) : null, // 시군구코드 (선택값)
|
||||
swtrmtFcltNm: swtrmtFcltNm ?? null,
|
||||
@@ -318,8 +315,8 @@ const IrSetting = () => {
|
||||
anlsInfo: input2, // 분석정보
|
||||
rgtr: tokenManager.getToken(AUTH_USER_ID) || null, // 등록자 (사용자 ID)
|
||||
rgtrNm: userInfo?.userName, // 등록자 (사용자 ID)
|
||||
atflCd: file1?.atflCd, // 첨부파일CD (오수관망도)
|
||||
atflId: file1?.atflId, // 첨부파일ID (오수관망도)
|
||||
//atflCd: file1?.atflCd, // 첨부파일CD (오수관망도)
|
||||
//atflId: file1?.atflId, // 첨부파일ID (오수관망도)
|
||||
atflInpNm: file1?.file?.name, // 오수관망도 파일명
|
||||
atflHrPttnNm: file3?.file?.name, // 오수량 시간패턴 파일명
|
||||
atflMpngNm: file2?.file?.name, // 수용가-맨홀 매칭결과 파일명
|
||||
@@ -330,9 +327,15 @@ const IrSetting = () => {
|
||||
tbSnRcptrInfo: rcptrInfoData, // 수용가 상수사용량 (없을 수 있음)
|
||||
};
|
||||
|
||||
console.log("통합 분석 데이터 (JSON):", combinedAnalysisData);
|
||||
console.log("통합 분석 데이터 (JSON):", jsonData);
|
||||
|
||||
const jsonBlob = new Blob([JSON.stringify(jsonData)], {
|
||||
type: 'application/json'
|
||||
});
|
||||
const combinedAnalysisData = new FormData();
|
||||
combinedAnalysisData.append('data', jsonBlob);
|
||||
if (file1?.file) combinedAnalysisData.append('inpFile', file1.file);
|
||||
|
||||
// 수정된 registFile 함수를 호출하여 combinedAnalysisData를 전송합니다.
|
||||
await registFile(combinedAnalysisData);
|
||||
setIsLoadingResult(false);
|
||||
} catch (error) {
|
||||
@@ -342,9 +345,8 @@ const IrSetting = () => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// const handleAnalysisClick = () => {
|
||||
// }
|
||||
//const rcptrInfoShow = true;
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<LoadingOverlay isLoading={isLoadingResult} />
|
||||
@@ -366,36 +368,10 @@ const IrSetting = () => {
|
||||
setSwtrmtFcltNm={setSwtrmtFcltNm}
|
||||
setIsLoading={setIsLoadingResult}
|
||||
onAnalysis={handleAnalysisClick}
|
||||
isIr={true}
|
||||
>
|
||||
{[<div key="irsetting-layout-key" className="grid gap-4">
|
||||
<FormSection name='suyeongaPlace' form={form} titleNm='▷ 오수관망도'>
|
||||
<FileUploadForm
|
||||
key={`file-upload-0-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(0, file, cd, id)}
|
||||
showButton={false}
|
||||
showPreview={true}
|
||||
accept={".inp"}
|
||||
fileIdx={0} />
|
||||
</FormSection>
|
||||
<FormSection name='suyeonga' form={form} titleNm='▷ 수용가-맨홀 매칭결과'>
|
||||
<FileUploadForm
|
||||
key={`file-upload-1-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(1, file, cd, id)}
|
||||
showButton={false}
|
||||
showPreview={true}
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={1} />
|
||||
</FormSection>
|
||||
<FormSection name='pattern' form={form} titleNm='▷ 오수량 시간패턴'>
|
||||
<FileUploadForm
|
||||
key={`file-upload-2-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(2, file, cd, id)}
|
||||
showButton={false}
|
||||
showPreview={true}
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={2} />
|
||||
</FormSection>
|
||||
<FormSection name='inputdate' form={form} titleNm='▷ 상수사용량 적용월'>
|
||||
<FormSection name='inputdate' form={form} titleNm='▷ 상수사용량 적용월' required={true}>
|
||||
{/* 연월 선택 라이브러리로 수정 필요 */}
|
||||
<DateMonthPicker
|
||||
field={{
|
||||
@@ -417,7 +393,42 @@ const IrSetting = () => {
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={4} />
|
||||
</FormSection>
|
||||
<FormSection name='rtkSource' form={form} titleNm='▷ 오수전환율'>
|
||||
<FormSection name='suyeongaPlace' form={form} titleNm='▷ 오수관망도' required={true}>
|
||||
<FileUploadForm
|
||||
key={`file-upload-0-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(0, file, cd, id)}
|
||||
showButton={false}
|
||||
showPreview={true}
|
||||
accept={".inp"}
|
||||
fileIdx={0} />
|
||||
</FormSection>
|
||||
<FormSection name='suyeonga' form={form} titleNm='▷ 수용가-맨홀 매칭결과' required={true}>
|
||||
<div className="flex items-center">
|
||||
<FileUploadForm
|
||||
key={`file-upload-1-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(1, file, cd, id)}
|
||||
showButton={false}
|
||||
showPreview={true}
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={1} />
|
||||
{/* <Button
|
||||
size={"sm"}
|
||||
className={`text-white rounded-sm text-lg font-medium green`}
|
||||
>
|
||||
<a href="/samples/manhole-consumer-matching-template.xlsx" download="수용가-맨홀 매칭결과 파일 양식.xlsx">양식 받기</a>
|
||||
</Button> */}
|
||||
</div>
|
||||
</FormSection>
|
||||
<FormSection name='pattern' form={form} titleNm='▷ 오수량 시간패턴' required={true}>
|
||||
<FileUploadForm
|
||||
key={`file-upload-2-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(2, file, cd, id)}
|
||||
showButton={false}
|
||||
showPreview={true}
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={2} />
|
||||
</FormSection>
|
||||
<FormSection name='rtkSource' form={form} titleNm='▷ 오수전환율' required={true}>
|
||||
<Input
|
||||
value={input1}
|
||||
onChange={(e) => {
|
||||
@@ -445,7 +456,7 @@ const IrSetting = () => {
|
||||
placeholder="예: 0.75"
|
||||
/>
|
||||
</FormSection>
|
||||
<FormSection name='analysis information' form={form} titleNm='▷ 분석 정보'>
|
||||
<FormSection name='analysis information' form={form} titleNm='▷ 분석 정보' required={true}>
|
||||
<Input
|
||||
value={input2}
|
||||
onChange={(e) => setInput2(e.target.value)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { postData } from '@/components/lib/api'
|
||||
import { postMutiPart } from '@/components/lib/api'
|
||||
import FileUploadForm from "@/components/ui/fileUploadForm"
|
||||
import FormSection from "@/components/ui/formSection"
|
||||
import BaseLayout from "../BaseLayout"
|
||||
@@ -157,13 +157,18 @@ export default function RTKForm() {
|
||||
};
|
||||
|
||||
const registFile = async (analysisData: any) => {
|
||||
console.log("Submitting combined analysis data to backend");
|
||||
// 추후 API 엔드포인트에 맞게 URL 수정 필요
|
||||
const data = await postData('v1/rdiiAnls', analysisData);
|
||||
setIsLoadingResult(true);
|
||||
console.log("Submitting combined analysis data to backend", analysisData);
|
||||
const data = await postMutiPart('v1/rdiiAnls/savewithfile', analysisData);
|
||||
console.log("Response from backend:", data);
|
||||
if (data) {
|
||||
setIsLoadingResult(false);
|
||||
alert("분석 데이터가 성공적으로 제출되었습니다.");
|
||||
resetAllForms(); // 성공 시 폼 초기화 함수 호출
|
||||
} else alert("분석 데이터 제출 중 오류가 발생했습니다.");
|
||||
} else {
|
||||
setIsLoadingResult(false);
|
||||
alert("분석 데이터 제출 중 오류가 발생했습니다.");
|
||||
}
|
||||
};
|
||||
|
||||
// 침입수 분석 실행 버튼 클릭 핸들러
|
||||
@@ -182,7 +187,7 @@ export default function RTKForm() {
|
||||
}
|
||||
|
||||
const formData = form.getValues();
|
||||
console.log(uploadedFilesData);
|
||||
console.log('uploadedFilesData', uploadedFilesData);
|
||||
const file1 = uploadedFilesData[0]; // 오수관망도
|
||||
const file2 = uploadedFilesData[1]; // 수용가-맨홀 매칭결과
|
||||
const file3 = uploadedFilesData[2]; // 강우자료
|
||||
@@ -253,9 +258,9 @@ export default function RTKForm() {
|
||||
if (!file || !file.file) return null; // fileInfo 객체 및 file 객체 null 체크
|
||||
|
||||
// filePicked 함수에 File 객체와 headerNum 전달
|
||||
const jsonData = await filePicked(file.file, 0);
|
||||
const ExcelToJsonData = await filePicked(file.file, 0);
|
||||
|
||||
if (jsonData === undefined) {
|
||||
if (ExcelToJsonData === undefined) {
|
||||
console.warn(`Warning: filePicked returned undefined for ${file.file.name}`);
|
||||
return {
|
||||
fileName: file.file.name,
|
||||
@@ -265,9 +270,9 @@ export default function RTKForm() {
|
||||
};
|
||||
}
|
||||
|
||||
// jsonData를 각 parser 함수로 처리
|
||||
// ExcelToJsonData를 각 parser 함수로 처리
|
||||
// parser 함수가 filePicked가 반환하는 JSON 형식을 직접 처리한다고 가정
|
||||
const parsedDataBySpecificFunction = parser(jsonData);
|
||||
const parsedDataBySpecificFunction = parser(ExcelToJsonData);
|
||||
|
||||
return {
|
||||
fileName: file.file.name,
|
||||
@@ -279,11 +284,28 @@ export default function RTKForm() {
|
||||
);
|
||||
|
||||
// 각 파싱 결과 접근
|
||||
const matchingResultData = parsedResults.find(r => r && r.fileName === file2.file?.name)?.parsedData;
|
||||
const rainData = parsedResults.find(r => r && r.fileName === file3.file?.name)?.parsedData;
|
||||
const matchingResultData = parsedResults.find(r => r && r.fileName === file2.file?.name)?.parsedData ?? [];
|
||||
const rainData = parsedResults.find(r => r && r.fileName === file3.file?.name)?.parsedData ?? [];
|
||||
|
||||
// 상수사용량 적용월과 강우자료의 날짜 일치 여부 검증
|
||||
let dateValidated = true;
|
||||
|
||||
if (rainData) {
|
||||
rainData
|
||||
.filter(data => data && 'mtrngDt' in data)
|
||||
.map(data => {
|
||||
if (formData.date !== data.mtrngDt.replace(/-/g, '').slice(0, 6)) dateValidated = false;
|
||||
});
|
||||
}
|
||||
if (!dateValidated) {
|
||||
setIsLoadingResult(false);
|
||||
alert("'상수사용량 적용월'과 강우자료의 '날짜'가 일치하지 않습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 새로운 JSON 데이터 생성
|
||||
const combinedAnalysisData = {
|
||||
const jsonData = {
|
||||
aplcnYm: formData.date, // 적용연월 (YYYYMM 형식)
|
||||
ctpvCd: ctpvCd !== '0' ? String(ctpvCd).trim() : null, // 시도코드 (선택값)
|
||||
sggCd: sggCd !== '0' ? String(sggCd) : null, // 시군구코드 (선택값)
|
||||
@@ -329,9 +351,15 @@ export default function RTKForm() {
|
||||
tbSnRainData: rainData, // 강우자료
|
||||
};
|
||||
|
||||
console.log("통합 분석 데이터 (JSON):", combinedAnalysisData);
|
||||
console.log("통합 분석 데이터 (JSON):", jsonData);
|
||||
|
||||
const jsonBlob = new Blob([JSON.stringify(jsonData)], {
|
||||
type: 'application/json'
|
||||
});
|
||||
const combinedAnalysisData = new FormData();
|
||||
combinedAnalysisData.append('data', jsonBlob);
|
||||
if (file1?.file) combinedAnalysisData.append('inpFile', file1.file);
|
||||
|
||||
// 수정된 registFile 함수를 호출하여 combinedAnalysisData를 전송합니다.
|
||||
await registFile(combinedAnalysisData);
|
||||
setIsLoadingResult(false);
|
||||
} catch (error) {
|
||||
@@ -389,18 +417,20 @@ export default function RTKForm() {
|
||||
setSwtrmtFcltNm={setSwtrmtFcltNm}
|
||||
setIsLoading={setIsLoadingResult}
|
||||
onAnalysis={handleAnalysisClick}
|
||||
isRdii={true}
|
||||
>
|
||||
{[<div className="space-y-[1.2rem] overflow-x-auto pt-4 pb-4 px-2" key="form-section">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormSection name="rtkSource" form={form} titleNm="○ RTK계수 출처">
|
||||
<FormSection name="rtkSource" form={form} titleNm="○ RTK계수 출처" required={true}>
|
||||
<Input {...form.register("rtkSource")} className="h-12 text-center text-xl w-[225px]" />
|
||||
</FormSection>
|
||||
<FormSection name="rdiiArea" form={form} titleNm="○ RDII 기여면적(ha)">
|
||||
<FormSection name="rdiiArea" form={form} titleNm="○ RDII 기여면적(ha)" required={true}>
|
||||
<Input {...form.register("rdiiArea")} className="h-12 text-center text-xl w-[225px]" />
|
||||
</FormSection></div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label className="mb-2 text-xl font-medium">○ 단위도 계수</Label>
|
||||
<span className="text-2xl text-red-500">*</span>
|
||||
<EditableFormTable
|
||||
form={form}
|
||||
name="unitFactors"
|
||||
@@ -411,6 +441,7 @@ export default function RTKForm() {
|
||||
</div>
|
||||
<div>
|
||||
<Label className="mb-[1.2rem] text-xl font-medium">○ 초기 차단 깊이</Label>
|
||||
<span className="text-2xl text-red-500">*</span>
|
||||
<EditableFormTable
|
||||
form={form}
|
||||
name="initialDepths"
|
||||
@@ -421,7 +452,7 @@ export default function RTKForm() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormSection name="suyeonga" form={form} titleNm="○ 오수관망도"><div className="w-[350px]">
|
||||
<FormSection name="suyeonga" form={form} titleNm="○ 오수관망도" required={true}><div className="w-[350px]">
|
||||
<FileUploadForm
|
||||
key={`file-upload-0-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(0, file, cd, id)}
|
||||
@@ -430,7 +461,7 @@ export default function RTKForm() {
|
||||
accept={".inp"}
|
||||
fileIdx={0} />
|
||||
</div></FormSection>
|
||||
<FormSection name="regopm" form={form} titleNm="○ 수용가-맨홀 매칭결과"><div className="w-[350px]">
|
||||
<FormSection name="regopm" form={form} titleNm="○ 수용가-맨홀 매칭결과" required={true}><div className="flex items-center">
|
||||
<FileUploadForm
|
||||
key={`file-upload-1-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(1, file, cd, id)}
|
||||
@@ -438,8 +469,14 @@ export default function RTKForm() {
|
||||
showPreview={true}
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={1} />
|
||||
{/* <Button
|
||||
size={"sm"}
|
||||
className={`text-white rounded-sm text-lg font-medium green`}
|
||||
>
|
||||
<a href="/samples/manhole-consumer-matching-template.xlsx" download="수용가-맨홀 매칭결과 파일 양식.xlsx">양식 받기</a>
|
||||
</Button> */}
|
||||
</div></FormSection>
|
||||
<FormSection name="rain" form={form} titleNm="○ 강우자료"><div className="w-[350px]">
|
||||
<FormSection name="rain" form={form} titleNm="○ 강우자료" required={true}><div className="w-[350px]">
|
||||
<FileUploadForm
|
||||
key={`file-upload-2-${formResetKey}`} // 폼 초기화를 위한 key
|
||||
onFileSelect={(file, cd, id) => handleFileSelection(2, file, cd, id)}
|
||||
@@ -448,7 +485,7 @@ export default function RTKForm() {
|
||||
accept={".xls, .xlsx, .xlsm, .xltx"}
|
||||
fileIdx={2} />
|
||||
</div></FormSection>
|
||||
<FormSection name='rate' form={form} titleNm='○ 오수전환율'>
|
||||
<FormSection name='rate' form={form} titleNm='○ 오수전환율' required={true}>
|
||||
<Input
|
||||
value={form.watch("rate")} // form의 rate 값을 가져옴
|
||||
onChange={(e) => {
|
||||
@@ -478,7 +515,7 @@ export default function RTKForm() {
|
||||
placeholder="0 ~ 1 사이의 값 입력"
|
||||
/>
|
||||
</FormSection>
|
||||
<FormSection name='date' form={form} titleNm='○ 상수사용량 적용월'>
|
||||
<FormSection name='date' form={form} titleNm='○ 상수사용량 적용월' required={true}>
|
||||
<DateMonthPicker
|
||||
field={{
|
||||
value: form.watch("date"), // form의 date 값을 직접 사용
|
||||
@@ -490,7 +527,7 @@ export default function RTKForm() {
|
||||
startYear={1900} // 시작 연도 설정
|
||||
/>
|
||||
</FormSection>
|
||||
<FormSection name='rate' form={form} titleNm='○ 분석 정보'>
|
||||
<FormSection name='rate' form={form} titleNm='○ 분석 정보' required={true}>
|
||||
<Input
|
||||
{...form.register("analysisInfo")}
|
||||
className="h-12 text-center text-xl w-[225px] ml-5"
|
||||
|
||||
@@ -14,6 +14,7 @@ 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";
|
||||
import TableModal from './tableModal';
|
||||
|
||||
|
||||
const Page = () => {
|
||||
@@ -32,7 +33,8 @@ const Page = () => {
|
||||
const [curPage, setCurPage] = useState(1) //현재 페이지
|
||||
const [totalData, setTotalData] = useState(0) //총 데이터 수
|
||||
const [isLoading, setIsLoading] = useState(true) //로딩 상태
|
||||
const [isModalOpen, setIsModalOpen] = useState(false) // 모달 상태
|
||||
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false) // 등록 모달 상태
|
||||
const [isTableModalOpen, setIsTableModalOpen] = useState(false) // 테이블 모달 상태
|
||||
const [resetSelection, setResetSelection] = useState<boolean>(false); // 선택 초기화 상태
|
||||
const [isResetPage, setIsResetPage] = useState<boolean>(false);
|
||||
|
||||
@@ -135,14 +137,14 @@ const Page = () => {
|
||||
const data = await postData('v1/sbmrgPrevnt', json)
|
||||
if (data) {
|
||||
alert('파일이 등록되었습니다.');
|
||||
setIsModalOpen(false);
|
||||
setIsUploadModalOpen(false);
|
||||
handleSearch();
|
||||
}
|
||||
}
|
||||
|
||||
// 등록 버튼 클릭 핸들러
|
||||
const handleRegisterClick = () => {
|
||||
setIsModalOpen(true);
|
||||
setIsUploadModalOpen(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +213,7 @@ const Page = () => {
|
||||
<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 !mr-[1.2rem] px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" 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>
|
||||
@@ -228,6 +230,7 @@ const Page = () => {
|
||||
setFileNm(fileName);
|
||||
setAtflId(id);
|
||||
setSbmrgPrevntBizSn(tableData[index]?.sbmrgPrevntBizSn);
|
||||
setIsTableModalOpen(true);
|
||||
}
|
||||
}}
|
||||
onPageChange={setCurPage}
|
||||
@@ -237,8 +240,8 @@ const Page = () => {
|
||||
</ListDiv>
|
||||
{/* 파일 업로드 모달 */}
|
||||
<UiModal
|
||||
open={isModalOpen}
|
||||
onOpenChange={setIsModalOpen}
|
||||
open={isUploadModalOpen}
|
||||
onOpenChange={setIsUploadModalOpen}
|
||||
bodyClass="w-auto max-w-[90vw] min-w-[600px] h-auto"
|
||||
noHeaderYn="N"
|
||||
noFooterYn="Y"
|
||||
@@ -251,6 +254,21 @@ const Page = () => {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{/* 엑셀 데이터 테이블 모달 */}
|
||||
<UiModal
|
||||
open={isTableModalOpen}
|
||||
onOpenChange={setIsTableModalOpen}
|
||||
bodyClass={`
|
||||
h-[100dvh]
|
||||
w-[90dvw]
|
||||
max-w-[100dvw]
|
||||
max-h-[100dvh]
|
||||
overflow-hidden
|
||||
z-[101]
|
||||
`}
|
||||
body={<TableModal fileNm={fileNm} atflId={atflId} />}
|
||||
useDirectRender={true}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
'use client'
|
||||
import { useState, useEffect } from 'react'
|
||||
import LoadingOverlay from '@/components/ui/LoadingBar'
|
||||
import { UITab, UiTable } from '@common/business_components/ui'
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
const TABS = [
|
||||
{ val: "management", text: "관리SHEET" },
|
||||
{ val: "Inspection results", text: "운영관리현황 점검결과" },
|
||||
];
|
||||
|
||||
interface TableModalProps {
|
||||
fileNm: string;
|
||||
atflId: string;
|
||||
}
|
||||
|
||||
const TableModal: React.FC<TableModalProps> = ({ fileNm, atflId }) => {
|
||||
|
||||
const [activeTab, setActiveTab] = useState(TABS[0]?.val ?? "management");
|
||||
const [managementTableHeader, setManagementTableHeader] = useState<{ id: string; title: string }[]>([]) //테이블 헤더
|
||||
const [managementTableData, setManagementTableData] = useState<any>([{}]) //테이블 데이터
|
||||
const [resultTableHeader, setResultTableHeader] = useState<{ id: string; title: string }[]>([]) //테이블 헤더
|
||||
const [resultTableData, setResultTableData] = useState<any>([{}]) //테이블 데이터
|
||||
const [isLoading, setIsLoading] = useState(false) //로딩 상태
|
||||
|
||||
useEffect(() => {
|
||||
isChckFile();
|
||||
}, []);
|
||||
|
||||
// 파일 다운로드
|
||||
const isChckFile = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
if (fileNm === '' || fileNm === undefined) {
|
||||
alert('파일을 선택해주세요')
|
||||
setIsLoading(false);
|
||||
return false
|
||||
}
|
||||
|
||||
const response = await fetch(`/attach-service/api/v1/download/${atflId}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('파일을 가져오는 중 오류가 발생했습니다.');
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
|
||||
const file = new File([blob], fileNm, {
|
||||
type: blob.type || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||
});
|
||||
|
||||
const targetSheets = ['관리SHEET', '운영관리현황 점검결과'];
|
||||
const jsonDataBySheet = await filePickedSelectedSheets(file, 0, targetSheets);
|
||||
|
||||
// 관리 SHEET
|
||||
const managementHeader = jsonDataBySheet['관리SHEET']?.[7] || [];
|
||||
// 1번째~47번째, 74번째~80번째 데이터만 필터링
|
||||
const filteredManagementHeader = Object.entries(managementHeader)
|
||||
.filter(([key, value]) => {
|
||||
const match = key.match(/^__EMPTY_(\d+)$/);
|
||||
if (match) {
|
||||
const index = parseInt(match[1] ?? '', 10);
|
||||
return (index > 0 && index < 47) || (index > 73);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.map(([key, value]) => ({
|
||||
id: key,
|
||||
title: String(value).replace(/\r\n/g, '\n')
|
||||
}));
|
||||
|
||||
setManagementTableHeader(filteredManagementHeader);
|
||||
console.log('managementTableHeader', filteredManagementHeader);
|
||||
|
||||
const managementData = Array.isArray(jsonDataBySheet['관리SHEET'])
|
||||
? jsonDataBySheet['관리SHEET'].slice(8)
|
||||
: [];
|
||||
// console.log('변환 후:', excelToManagementData(managementData));
|
||||
const filteredManagementData = filterEmptyRows(managementData);
|
||||
setManagementTableData(filteredManagementData);
|
||||
console.log('managementTableData', filteredManagementData);
|
||||
|
||||
// 운영관리현황 점검결과
|
||||
const resultHeader = jsonDataBySheet['운영관리현황 점검결과']?.[2] || [];
|
||||
const dynamicInspectionHeader = Object.entries(resultHeader)
|
||||
.map(([key, value]) => ({
|
||||
id: key,
|
||||
title: String(value).replace(/\r\n/g, '\n')
|
||||
}));
|
||||
dynamicInspectionHeader.splice(1, 0, {
|
||||
id: "__EMPTY_2",
|
||||
title: ''
|
||||
});
|
||||
setResultTableHeader(dynamicInspectionHeader);
|
||||
console.log('resultTableHeader', dynamicInspectionHeader);
|
||||
|
||||
const resultData = Array.isArray(jsonDataBySheet['운영관리현황 점검결과'])
|
||||
? jsonDataBySheet['운영관리현황 점검결과'].slice(3)
|
||||
: [];
|
||||
const filteredResultData = filterEmptyRows(resultData);
|
||||
setResultTableData(filteredResultData);
|
||||
console.log('resultTableData', filteredResultData);
|
||||
} catch (error) {
|
||||
console.error('파일 처리 중 오류 발생:', error);
|
||||
alert('파일 처리 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function filterEmptyRows(data: any[]) {
|
||||
return data
|
||||
.filter(row => {
|
||||
return Object.entries(row).some(([key, value]) => {
|
||||
const match = key.match(/^__EMPTY_(\d+)$/);
|
||||
if (!match || parseInt(match[1] ?? '', 10) < 2) return false;
|
||||
|
||||
return value !== undefined &&
|
||||
value !== null &&
|
||||
value !== '' &&
|
||||
value !== '-' &&
|
||||
String(value).trim() !== '';
|
||||
});
|
||||
})
|
||||
.map((row) => {
|
||||
const processedRow = { ...row };
|
||||
const keys = Object.keys(processedRow);
|
||||
|
||||
keys.forEach((key, keyIndex) => {
|
||||
// 마지막 속성(비고)이 아닌 경우에만 빈 값을 '-'으로 변경
|
||||
if (keyIndex !== keys.length - 1) {
|
||||
const value = processedRow[key];
|
||||
if (value === undefined ||
|
||||
value === null ||
|
||||
value === '' ||
|
||||
String(value).trim() === '') {
|
||||
processedRow[key] = '-';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return processedRow;
|
||||
});
|
||||
};
|
||||
|
||||
// 특정 시트만 선택적으로 JSON으로 변환하는 함수
|
||||
function filePickedSelectedSheets(file: File, headerNum: number = 0, sheetNames: string[]): Promise<Record<string, any[]>> {
|
||||
const reader = new FileReader();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
reader.onload = function (e) {
|
||||
const data = e.target?.result;
|
||||
if (!data) {
|
||||
console.error("Failed to read file: e.target.result is null");
|
||||
reject(new Error("Failed to read file"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Excel 파일 읽기
|
||||
const wb = XLSX.read(data, { type: 'binary', cellDates: true });
|
||||
const result: Record<string, any[]> = {};
|
||||
|
||||
// 지정된 시트 이름만 찾아서 처리
|
||||
sheetNames.forEach(targetSheetName => {
|
||||
// 대소문자 구분 없이 시트 이름 찾기
|
||||
const sheetName = wb.SheetNames.find(name =>
|
||||
name.toLowerCase() === targetSheetName.toLowerCase()
|
||||
);
|
||||
|
||||
if (sheetName) {
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
if (sheet) {
|
||||
console.log(`Found sheet: "${sheetName}"`);
|
||||
const jsonData = XLSX.utils.sheet_to_json(sheet, { range: headerNum, raw: false });
|
||||
result[targetSheetName] = jsonData;
|
||||
}
|
||||
} else {
|
||||
console.warn(`Sheet "${targetSheetName}" not found in workbook`);
|
||||
result[targetSheetName] = [];
|
||||
}
|
||||
});
|
||||
|
||||
resolve(result);
|
||||
};
|
||||
|
||||
reader.onerror = function () {
|
||||
console.error("Error reading file");
|
||||
reject(new Error("Error reading file"));
|
||||
};
|
||||
|
||||
// 파일 읽기 시작
|
||||
reader.readAsBinaryString(file);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 탭 영역 */}
|
||||
<UITab
|
||||
defaultValue={activeTab}
|
||||
tabList={TABS.map((tab) => ({
|
||||
value: tab.val,
|
||||
label: tab.text
|
||||
}))}
|
||||
onValueChange={(value: string) => setActiveTab(value)}
|
||||
/>
|
||||
{/* 관리SHEET 탭 */}
|
||||
{activeTab === 'management' && (
|
||||
<div className="h-[79vh] w-full overflow-auto rounded-lg border">
|
||||
<div className="flex-1 px-2 pb-2">
|
||||
<LoadingOverlay isLoading={isLoading} />
|
||||
<div className="min-w-[550%]">
|
||||
<UiTable
|
||||
headName={'관리SHEET'}
|
||||
tableData={managementTableData}
|
||||
headlist={managementTableHeader}
|
||||
pageSize={10}
|
||||
total={0}
|
||||
cellClick={undefined}
|
||||
onPageChange={() => { }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* 운영관리현황 점검결과 탭 */}
|
||||
{activeTab === 'Inspection results' && (
|
||||
<div className="h-[79vh] w-full overflow-auto rounded-lg border">
|
||||
<div className="flex-1 px-2 pb-2">
|
||||
<LoadingOverlay isLoading={isLoading} />
|
||||
<UiTable
|
||||
headName={'운영관리현황 점검결과'}
|
||||
tableData={resultTableData}
|
||||
headlist={resultTableHeader}
|
||||
pageSize={10}
|
||||
total={0}
|
||||
className={"overflow-x-auto overflow-y-auto"}
|
||||
cellClick={undefined}
|
||||
onPageChange={() => { }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
};
|
||||
|
||||
export default TableModal;
|
||||
@@ -205,7 +205,7 @@ const Page = () => {
|
||||
<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 !mr-[1.2rem] px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" 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>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import axios from 'axios';
|
||||
|
||||
const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || '';
|
||||
|
||||
export const getData = async (url: string, data?: object): Promise<any> => {
|
||||
export const getData = async (url: string): Promise<any> => {
|
||||
const res = await fetch(url.startsWith('/') ? `${url}` : `${BASE_URL}/${url}`, {
|
||||
method: "GET",
|
||||
});
|
||||
@@ -48,13 +49,8 @@ export const postData = async (url: string, data: object): Promise<any> => {
|
||||
};
|
||||
|
||||
export const postMutiPart = async (url: string, data: FormData): Promise<any> => {
|
||||
const options: RequestInit = {
|
||||
method: "POST",
|
||||
body: data,
|
||||
};
|
||||
const res = await fetch(`${BASE_URL}/${url}`, options);
|
||||
const resData = await res.json();
|
||||
return resData;
|
||||
const res = await axios.post(`${BASE_URL}/${url}`, data);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const putData = async (url: string, data: object): Promise<any> => {
|
||||
|
||||
@@ -41,23 +41,84 @@ const FileUploadForm = ({
|
||||
const [selectedYear, setSelectedYear] = useState<string>(yearOptions[0]?.val || '');
|
||||
const [selectedQuarter, setSelectedQuarter] = useState<string>(quater[0]?.val || '');
|
||||
|
||||
const internalHandleUploadResponse = (file: File) => async (res: HttpResponse) => {
|
||||
const fileInfo = res.getHeader("X-File-Info");
|
||||
if (!fileInfo) {
|
||||
if (onFileSelect) onFileSelect(file, null, null);
|
||||
function registFile() {
|
||||
console.log(files?.[0]?.name)
|
||||
if (!currentFile) {
|
||||
alert('파일을 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
const { atflCd: newAtflCd, atflId: newAtflId } = JSON.parse(fileInfo) ?? {};
|
||||
const orgnlFileNm = file.name;
|
||||
console.log(`FileUploadForm (idx: ${fileIdx ?? 'N/A'}) - orgnlFileNm:`, orgnlFileNm, 'New AtflCd:', newAtflCd, 'New AtflId:', newAtflId);
|
||||
setFileName(orgnlFileNm);
|
||||
setInternalAtflCd(newAtflCd);
|
||||
setInternalAtflId(newAtflId);
|
||||
|
||||
if (onFileSelect) {
|
||||
onFileSelect(file, newAtflCd, newAtflId);
|
||||
if (!selectedYear) {
|
||||
alert('등록년도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
};
|
||||
if (!selectedQuarter) {
|
||||
alert('분기를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileNm = currentFile.name;
|
||||
if (onSubmit && files && currentFile) {
|
||||
// Promise로 handleUpload 완료를 기다림
|
||||
handleUploadWithResponse(files, currentFile)
|
||||
.then(({ atflCd, atflId }) => {
|
||||
// 업로드 완료 후 onSubmit 실행
|
||||
onSubmit(fileNm, selectedYear, selectedQuarter, atflCd || '', atflId || '');
|
||||
|
||||
// UI 초기화
|
||||
setFiles(null);
|
||||
setFileName('');
|
||||
setUploaderKey(prev => prev + 1);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('파일 업로드 실패:', error);
|
||||
alert('파일 업로드 중 오류가 발생했습니다.');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// handleUpload를 Promise로 감싸는 헬퍼 함수
|
||||
function handleUploadWithResponse(files: FileList, file: File): Promise<{ atflCd: string | null, atflId: string | null }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const uploadResponseHandler = async (res: HttpResponse) => {
|
||||
try {
|
||||
const fileInfo = res.getHeader("X-File-Info");
|
||||
if (!fileInfo) {
|
||||
resolve({ atflCd: null, atflId: null });
|
||||
return;
|
||||
}
|
||||
|
||||
const { atflCd: newAtflCd, atflId: newAtflId } = JSON.parse(fileInfo) ?? {};
|
||||
console.log(`FileUploadForm (idx: ${fileIdx ?? 'N/A'}) - Upload completed:`, newAtflCd, newAtflId);
|
||||
|
||||
// 내부 상태도 업데이트 (다른 용도로 사용할 수 있음)
|
||||
setInternalAtflCd(newAtflCd);
|
||||
setInternalAtflId(newAtflId);
|
||||
setFileName(file.name);
|
||||
|
||||
if (onFileSelect) {
|
||||
onFileSelect(file, newAtflCd, newAtflId);
|
||||
}
|
||||
|
||||
// Promise 완료
|
||||
resolve({ atflCd: newAtflCd, atflId: newAtflId });
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const uploadErrorHandler = (error: Error) => {
|
||||
console.error('Upload failed:', error);
|
||||
reject(error);
|
||||
};
|
||||
|
||||
// 기존 handleUpload 유틸리티 사용 (수정하지 않음)
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
handleSuccess: setUpload,
|
||||
handleResponse: uploadResponseHandler,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
@@ -87,19 +148,12 @@ const FileUploadForm = ({
|
||||
if (!firstFile) return; // 타입스크립트 undefined 가능성 제거
|
||||
|
||||
setFiles(selectedFiles);
|
||||
setFileName(firstFile.name);
|
||||
setCurrentFile(firstFile);
|
||||
|
||||
if (onFileSelect) {
|
||||
onFileSelect(firstFile, internalAtflCd, internalAtflId);
|
||||
}
|
||||
|
||||
handleUpload(selectedFiles, {
|
||||
handleUploadStart: setUpload,
|
||||
handleSuccess: setUpload,
|
||||
// handleResponse는 tus-js-client의 Upload 인스턴스 콜백과 연동 필요
|
||||
// 여기서는 handleUpload 유틸리티가 응답을 직접 처리한다고 가정
|
||||
handleResponse: internalHandleUploadResponse(firstFile),
|
||||
});
|
||||
}}
|
||||
customPreview={
|
||||
showPreview ? (
|
||||
@@ -116,30 +170,7 @@ const FileUploadForm = ({
|
||||
<Button
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
console.log(files?.[0]?.name)
|
||||
if (!currentFile) {
|
||||
alert('파일을 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
if (!selectedYear) {
|
||||
alert('등록년도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
if (!selectedQuarter) {
|
||||
alert('분기를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
const fileNm = currentFile.name;
|
||||
if (onSubmit) {
|
||||
// 부모에게 전달할 때는 내부 상태인 internalAtflCd, internalAtflId 사용
|
||||
onSubmit(fileNm, selectedYear, selectedQuarter, internalAtflCd || '', internalAtflId || '');
|
||||
setFiles(null); // 파일 업로드 후 파일 목록 초기화
|
||||
setFileName(''); // 파일명 초기화
|
||||
// 파일 업로드 후 FileUploader 컴포넌트를 재마운트하기 위해 key 값 변경
|
||||
setUploaderKey(prev => prev + 1);
|
||||
}
|
||||
}}
|
||||
onClick={() => registFile()}
|
||||
>
|
||||
등록
|
||||
</Button>
|
||||
|
||||
@@ -6,12 +6,13 @@ interface FormSectionProps {
|
||||
titleNm: string
|
||||
form: any
|
||||
name: string
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
const FormSection = ({ children, titleNm, form, name }: FormSectionProps) => {
|
||||
const FormSection = ({ children, titleNm, form, name, required }: FormSectionProps) => {
|
||||
return (
|
||||
<div className="grid grid-cols-[200px_1fr] items-center">
|
||||
<div className="text-xl font-medium">{titleNm}</div>
|
||||
<div className="text-xl font-medium">{titleNm}{required && <span className="text-2xl text-red-500">*</span>}</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,7 +5,7 @@ import {
|
||||
type SelectDataType,
|
||||
} from "@common/business_components/ui";
|
||||
import { Button, Label } from "@common/components/ui";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
import SearchInputText from "../SearchInputText/SearchInputText";
|
||||
|
||||
export function SearchBar({
|
||||
@@ -15,7 +15,7 @@ export function SearchBar({
|
||||
setHasuPk: (hasuPk: any) => void;
|
||||
onApply: () => void;
|
||||
}) {
|
||||
const { map, code, codeInit, findRuseFclt } = useWrStore(
|
||||
const { map, code, findRuseFclt } = useWrStore(
|
||||
(state) => state
|
||||
);
|
||||
const [sidoValue, setSidoValue] = useState<string>("");
|
||||
@@ -24,10 +24,7 @@ export function SearchBar({
|
||||
{ text: "전체", val: "0" },
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
//codeInit();
|
||||
}, [codeInit]);
|
||||
|
||||
|
||||
const initializeSigunData = useCallback(
|
||||
(sidoCd: string) => {
|
||||
if (sidoCd === "0") {
|
||||
|
||||
@@ -585,7 +585,7 @@ export default function CoMatRvw() {
|
||||
control={form.control}
|
||||
name="ph"
|
||||
render={({ field }) => (
|
||||
<FormUi label="수소이온농도(PH)">
|
||||
<FormUi label="수소이온농도(ph)">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative flex-1 min-w-0">
|
||||
<Input
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { type customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||
import { formatCommaNumber, tableData } from "@/components/lib/func/commom";
|
||||
import { rainRegSize, type customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||
import { formatArchArea, tableData } from "@/components/lib/func/commom";
|
||||
import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm";
|
||||
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
|
||||
import {
|
||||
@@ -49,14 +49,11 @@ export default function Home() {
|
||||
if (rainRes && rainRes.length > 0) {
|
||||
const rainData = tableData(rainRes, { code }).map(
|
||||
(item: customRainBdst) => {
|
||||
const archArea =
|
||||
item?.archArea.split(".")[0] !== "-1"
|
||||
? item?.archArea.split(".")[0]
|
||||
: "확인불가";
|
||||
return {
|
||||
...item,
|
||||
archArea: formatCommaNumber(archArea),
|
||||
archArea: formatArchArea(item?.archArea,1),
|
||||
bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N",
|
||||
frstArchPrmsnDt:item?.frstArchPrmsnDt||'확인불가'
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -129,7 +126,7 @@ export default function Home() {
|
||||
<UiTable
|
||||
tableData={bdstTable || []}
|
||||
headlist={rain.upHeadList}
|
||||
pageSize={20}
|
||||
pageSize={rainRegSize}
|
||||
total={rainResCount}
|
||||
headName={"건축물 목록"}
|
||||
cellClick={(val) => {
|
||||
@@ -140,9 +137,9 @@ export default function Home() {
|
||||
{/* </ScrollArea> */}
|
||||
</ListDiv>
|
||||
</div>
|
||||
<div className="col-span-2 max-h-full">
|
||||
<ListDiv className="">
|
||||
<ScrollArea className="h-[65vh]">
|
||||
<div className="col-span-2 ">
|
||||
<ListDiv >
|
||||
<ScrollArea className="h-[75vh]">
|
||||
<RainRegForm
|
||||
rainForm={rainForm ?? ({} as customRainBdst)}
|
||||
isModal={false}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { useWrStore } from "@/app/store";
|
||||
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
|
||||
import { rswtRegSize, type customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
|
||||
import { tableData } from "@/components/lib/func/commom";
|
||||
import RswtrRegForm from "@/components/ui/form/fcltReg/rswtrReg/rswtrRegForm";
|
||||
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
|
||||
@@ -134,7 +134,7 @@ export default function Home() {
|
||||
<UiTable
|
||||
tableData={bdstTable || []}
|
||||
headlist={rswt.upHeadList}
|
||||
pageSize={20}
|
||||
pageSize={rswtRegSize}
|
||||
total={rswtResCount}
|
||||
headName={"건축물 목록"}
|
||||
cellClick={cellClick}
|
||||
@@ -145,7 +145,7 @@ export default function Home() {
|
||||
</div>
|
||||
<div className="col-span-2 max-h-full">
|
||||
<ListDiv className="">
|
||||
<ScrollArea className="h-[65vh]">
|
||||
<ScrollArea className="h-[75vh]">
|
||||
<RswtrRegForm
|
||||
rswtForm={rswtForm ?? ({} as customRswtBdst)}
|
||||
isModal={false}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { btnClass } from "@/app/store/common/code";
|
||||
import type {
|
||||
customRainBdst
|
||||
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||
import { htdflSttnSize } from "@/app/store/ruseFcltMng/fcltSttn/htdflSttn";
|
||||
import {
|
||||
excelDownload,
|
||||
getCity,
|
||||
@@ -57,7 +58,7 @@ export default function HtdflSttn() {
|
||||
const [fcltNm, setFcltNm] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
htdflSttnSearch(false, pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
htdflSttnSearch(false, pageNation, htdflSttnSize, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
isResetPage(false)
|
||||
}, [pageNation]);
|
||||
|
||||
@@ -102,7 +103,7 @@ export default function HtdflSttn() {
|
||||
|
||||
const excelClick = useCallback(() => {
|
||||
isDownloadTriggered.current = true;
|
||||
htdflSttnSearch(true, 1, String(htdflSttnResCount), String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
htdflSttnSearch(true, 1, htdflSttnResCount, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
}, [htdflSttnSearch, objSearch, code.cityCd, code.sggCd, fcltNm, htdflSttnResCount]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -124,7 +125,7 @@ export default function HtdflSttn() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!htdflSttn.isInit) {
|
||||
initHtdfl(false, 1, "20", "0", fcltNm, code.cityCd, code.sggCd);
|
||||
initHtdfl(false, 1, htdflSttnSize, "0", fcltNm, code.cityCd, code.sggCd);
|
||||
}
|
||||
}, [htdflSttn.isInit, initHtdfl]);
|
||||
|
||||
@@ -185,7 +186,7 @@ export default function HtdflSttn() {
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
htdflSttnSearch(false, 1, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
htdflSttnSearch(false, 1,htdflSttnSize, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
isResetPage(true)
|
||||
}}
|
||||
>
|
||||
@@ -219,7 +220,7 @@ export default function HtdflSttn() {
|
||||
headName={undefined}
|
||||
tableData={bdstTable || []}
|
||||
headlist={htdflSttn.htdflSttHeadList}
|
||||
pageSize={20}
|
||||
pageSize={htdflSttnSize}
|
||||
total={htdflSttnResCount || 0}
|
||||
cellClick={(index: number | undefined, headId: string) => {
|
||||
cellClick(index ?? undefined, headId);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { btnClass } from "@/app/store/common/code";
|
||||
import type {
|
||||
customRainBdst,
|
||||
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||
import { rainSttnSize } from "@/app/store/ruseFcltMng/fcltSttn/rainSttn";
|
||||
import {
|
||||
excelDownload,
|
||||
getCity,
|
||||
@@ -91,7 +92,7 @@ export default function RainSttn() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!rainSttn.isInit) {
|
||||
rainSttnInit(false, 1, "20", "0", fcltNm, code.cityCd, code.sggCd);
|
||||
rainSttnInit(false, 1, rainSttnSize, "0", fcltNm, code.cityCd, code.sggCd);
|
||||
}
|
||||
}, [rainSttn.isInit, rainSttnInit]);
|
||||
|
||||
@@ -115,8 +116,8 @@ export default function RainSttn() {
|
||||
item.reuseBuilding[0].instlCstSprtAmt === -1
|
||||
? "확인불가"
|
||||
: item.reuseBuilding[0].instlCstSprtAmt,
|
||||
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
|
||||
pntfColArea:
|
||||
chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N',
|
||||
pntfColArea:
|
||||
item.reuseBuilding[0].rainyObj.pntfColArea === -1
|
||||
? "확인불가"
|
||||
: item.reuseBuilding[0].rainyObj.pntfColArea,
|
||||
@@ -130,7 +131,8 @@ export default function RainSttn() {
|
||||
? item.archArea
|
||||
: Math.floor(Number(item.archArea)) === -1
|
||||
? '확인불가'
|
||||
: Math.trunc(Number(item.archArea))
|
||||
: Math.trunc(Number(item.archArea)),
|
||||
pntfColKnd: code.rainFcltCd.find((pnt) => pnt.val === item.reuseBuilding[0].rainyObj?.pntfColKnd)?.text ??''
|
||||
};
|
||||
})
|
||||
.filter((item: any) => item.rainyObj !== undefined);
|
||||
@@ -141,7 +143,7 @@ export default function RainSttn() {
|
||||
rainSttnSearch(
|
||||
false,
|
||||
pageNation,
|
||||
"20",
|
||||
rainSttnSize,
|
||||
String(getConValue()),
|
||||
fcltNm,
|
||||
code.cityCd,
|
||||
@@ -172,7 +174,7 @@ export default function RainSttn() {
|
||||
rainSttnSearch(
|
||||
true,
|
||||
1,
|
||||
String(rainSttnResCount),
|
||||
rainSttnResCount,
|
||||
String(getConValue()),
|
||||
fcltNm,
|
||||
code.cityCd,
|
||||
@@ -232,7 +234,7 @@ export default function RainSttn() {
|
||||
rainSttnSearch(
|
||||
false,
|
||||
1,
|
||||
"20",
|
||||
rainSttnSize,
|
||||
String(getConValue()),
|
||||
fcltNm,
|
||||
code.cityCd,
|
||||
@@ -271,7 +273,7 @@ export default function RainSttn() {
|
||||
headName={undefined}
|
||||
tableData={bdstTable || []}
|
||||
headlist={rainSttn.rainSttHeadList}
|
||||
pageSize={20}
|
||||
pageSize={rainSttnSize}
|
||||
total={rainSttnResCount || 0}
|
||||
cellClick={(index: number | undefined) => {
|
||||
cellClick(index ?? undefined);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { btnClass } from "@/app/store/common/code";
|
||||
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
|
||||
import { rswtSttnSize } from "@/app/store/ruseFcltMng/fcltSttn/rswtSttn";
|
||||
import {
|
||||
excelDownload,
|
||||
getCity,
|
||||
@@ -83,18 +84,20 @@ export default function RswtSttn() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!rswtSttn.isInit) {
|
||||
rswtSttnInit(false, 1, "20", "0", fcltNm, code.cityCd, code.sggCd);
|
||||
rswtSttnInit(false, 1, rswtSttnSize, "0", fcltNm, code.cityCd, code.sggCd);
|
||||
}
|
||||
}, [rswtSttn.isInit, rswtSttnInit]);
|
||||
|
||||
useEffect(() => {
|
||||
const data = tableData(rswtSttnRes, { code });
|
||||
const chData = data
|
||||
.map((item: customRswtBdst) => {
|
||||
.map((item: customRswtBdst) => {
|
||||
const isOrgwtKndCd = item.reuseBuilding[0]?.rswtrObj.orgwtKndCd
|
||||
return {
|
||||
...item,
|
||||
...item.reuseBuilding[0],
|
||||
...item.reuseBuilding[0]?.rswtrObj,
|
||||
orgwtKndCd: isOrgwtKndCd? code.orgwtKndCd.find((item) => item.val===isOrgwtKndCd)?.text : "확인불가",
|
||||
chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N',
|
||||
instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst,
|
||||
instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt,
|
||||
@@ -128,11 +131,11 @@ export default function RswtSttn() {
|
||||
|
||||
const excelClick = useCallback(() => {
|
||||
isDownloadTriggered.current = true;
|
||||
rswtSttnSearch(true, 1, String(rswtSttnResCount), String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
rswtSttnSearch(true, 1, rswtSttnResCount, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
}, [rswtSttnSearch, objSearch, code.cityCd, code.sggCd, fcltNm, rswtSttnResCount]);
|
||||
|
||||
useEffect(() => {
|
||||
rswtSttnSearch(false, pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
rswtSttnSearch(false, pageNation, rswtSttnSize, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
isResetPage(false)
|
||||
}, [pageNation]);
|
||||
|
||||
@@ -183,7 +186,7 @@ export default function RswtSttn() {
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={() => {
|
||||
rswtSttnSearch(false, 1, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
rswtSttnSearch(false, 1, rswtSttnSize, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
isResetPage(true)
|
||||
}}
|
||||
>
|
||||
@@ -217,7 +220,7 @@ export default function RswtSttn() {
|
||||
headName={undefined}
|
||||
tableData={bdstTable || []}
|
||||
headlist={rswtSttn.rswtSttHeadList}
|
||||
pageSize={20}
|
||||
pageSize={rswtSttnSize}
|
||||
total={rswtSttnResCount || 0}
|
||||
cellClick={(index: number | undefined) => { cellClick(index ?? undefined) }}
|
||||
onPageChange={setPageNation}
|
||||
|
||||
@@ -71,6 +71,35 @@ export const bdstUsgCd: SelectDataType[] = [
|
||||
{ val: "14", text: "골프장" },
|
||||
{ val: "15", text: "대규모점포" },
|
||||
{ val: "16", text: "기타" },
|
||||
{ text: "숙박업", val: "17" },
|
||||
{ text: "목욕장업", val: "18" },
|
||||
{ text: "공장", val: "19" },
|
||||
{ text: "발전시설", val: "20" },
|
||||
{ text: "관광단지개발사업", val: "21" },
|
||||
{ text: "도시개발사업", val: "22" },
|
||||
{ text: "산업단지개발사업", val: "23" },
|
||||
{ text: "택지개발사업", val: "24" },
|
||||
{ text: "대규모점포(대형마트)", val: "25" },
|
||||
{ text: "대규모점포(전문점)", val: "26" },
|
||||
{ text: "대규모점포(백화점)", val: "27" },
|
||||
{ text: "대규모점포(쇼핑센터)", val: "28" },
|
||||
{ text: "대규모점포(복합쇼핑몰)", val: "29" },
|
||||
{ text: "물류시설", val: "30" },
|
||||
{ text: "운수시설(여객자동차터미널)", val: "31" },
|
||||
{ text: "운수시설(철도시설)", val: "32" },
|
||||
{ text: "운수시설(공항시설)", val: "33" },
|
||||
{ text: "운수시설(항만시설)", val: "34" },
|
||||
{ text: "업무시설(공공업무시설)", val: "35" },
|
||||
{ text: "업무시설(금융업소)", val: "36" },
|
||||
{ text: "업무시설(사무소)", val: "37" },
|
||||
{ text: "업무시설(결혼상담소 등 소개업소)", val: "38" },
|
||||
{ text: "업무시설(출판사)", val: "39" },
|
||||
{ text: "업무시설(신문사)", val: "40" },
|
||||
{ text: "업무시설(오피스텔)", val: "41" },
|
||||
{ text: "교정시설", val: "42" },
|
||||
{ text: "방송국", val: "43" },
|
||||
{ text: "전신전화국", val: "44" },
|
||||
{ text: "기타", val: "45" },
|
||||
];
|
||||
|
||||
export const rswtBdstType: SelectDataType[] = [
|
||||
@@ -106,11 +135,11 @@ export const rswtBdstType: SelectDataType[] = [
|
||||
];
|
||||
|
||||
export const orgwtKndCd = [
|
||||
{ text: "오수(변기 오수 제외)", val: "1" },
|
||||
{ text: "오수", val: "2" },
|
||||
{ text: "폐수", val: "3" },
|
||||
{ text: "오수 및 폐수", val: "4" },
|
||||
{ text: "기타", val: "5" },
|
||||
{ text: "오수(변기 오수 제외)", val: "01" },
|
||||
{ text: "오수", val: "02" },
|
||||
{ text: "폐수", val: "03" },
|
||||
{ text: "오수 및 폐수", val: "04" },
|
||||
{ text: "기타", val: "05" },
|
||||
];
|
||||
|
||||
export const chBuCd = [
|
||||
@@ -157,18 +186,19 @@ export const pplLenght = [
|
||||
];
|
||||
|
||||
export const rainFcltCd = [
|
||||
{ val: "지붕", text: "지붕" },
|
||||
{ val: "건물옥상", text: "건물옥상" },
|
||||
{ val: "골프장 연못", text: "골프장 연못" },
|
||||
{ val: "운동장 바닥", text: "운동장 바닥" },
|
||||
{ val: "운동장 지붕", text: "운동장 지붕" },
|
||||
{ val: "주차장", text: "주차장" },
|
||||
{ val: "태양광패널", text: "태양광패널" },
|
||||
{ val: "연못", text: "연못" },
|
||||
{ val: "기타", text: "기타" },
|
||||
{ val: "확인불가", text: "확인불가" },
|
||||
{ val: "01", text: "지붕" },
|
||||
{ val: "02", text: "건물옥상" },
|
||||
{ val: "03", text: "골프장 연못" },
|
||||
{ val: "04", text: "운동장 바닥" },
|
||||
{ val: "05", text: "운동장 지붕" },
|
||||
{ val: "06", text: "주차장" },
|
||||
{ val: "07", text: "태양광패널" },
|
||||
{ val: "08", text: "연못" },
|
||||
{ val: "09", text: "기타" },
|
||||
{ val: "10", text: "확인불가" },
|
||||
];
|
||||
|
||||
|
||||
//물리화학적처리(스크린, 응집, 침전)/생물학적처리(활성슬러지법 등)/소독(염소, UV 등)/기타
|
||||
export const rswtPrscCdMthdCd = [
|
||||
{
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
import { getFetch } from "@/components/lib/api";
|
||||
import type { EnvPartSelectDataType, SelectDataType } from "@common/business_components/ui";
|
||||
import { bdstFilterYn, bdstGrntchClass, bdstIncenYn, bdstUsgCd, chBuCd, dmdUszCd, erctUswtrPrcsMeth, htdPowerMthdCd, htdUtztnUsgCd, orgwtKndCd, pplLenght, pplQulity, rainFcltCd, rswtPrscCdMthdCd, ruseBizMthdCd, ruseMngMtd, rusePrcsMthdCd, ruseSeCd, yn } from "./basicCode";
|
||||
export const btnClass = "p-4 m-2 text-white rounded-sm text-lg font-medium "
|
||||
|
||||
|
||||
const laeSecd = '41'
|
||||
|
||||
import type {
|
||||
EnvPartSelectDataType,
|
||||
SelectDataType,
|
||||
} from "@common/business_components/ui";
|
||||
import {
|
||||
bdstFilterYn,
|
||||
bdstGrntchClass,
|
||||
bdstIncenYn,
|
||||
bdstUsgCd,
|
||||
chBuCd,
|
||||
dmdUszCd,
|
||||
erctUswtrPrcsMeth,
|
||||
htdPowerMthdCd,
|
||||
htdUtztnUsgCd,
|
||||
orgwtKndCd,
|
||||
pplLenght,
|
||||
pplQulity,
|
||||
rainFcltCd,
|
||||
rswtPrscCdMthdCd,
|
||||
ruseBizMthdCd,
|
||||
ruseMngMtd,
|
||||
rusePrcsMthdCd,
|
||||
ruseSeCd,
|
||||
yn,
|
||||
} from "./basicCode";
|
||||
export const btnClass = "p-4 m-2 text-white rounded-sm text-lg font-medium ";
|
||||
|
||||
const laeSecd = "41";
|
||||
//물재이용 주소 코드: devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
|
||||
export const buildingType = {
|
||||
RST:"RST",
|
||||
RNB:"RNB",
|
||||
HTB:"HTB"
|
||||
}
|
||||
RST: "RST",
|
||||
RNB: "RNB",
|
||||
HTB: "HTB",
|
||||
};
|
||||
export const getSggCd = async (set: any) => {
|
||||
const sgg = await getFetch("common", "/addr/sgg");
|
||||
/* const sggCd = sgg.map((item: any) => ({
|
||||
@@ -19,15 +40,14 @@ export const getSggCd = async (set: any) => {
|
||||
text: item.gugun,
|
||||
})); */
|
||||
|
||||
const sggCd = [
|
||||
// { text: "전체", val: '0' },
|
||||
...sgg
|
||||
.map((item: any) => ({
|
||||
text: item.gugun || '',
|
||||
val: String(item.adstDstrCd) || ''
|
||||
}))
|
||||
const sggCd = [
|
||||
// { text: "전체", val: '0' },
|
||||
...sgg.map((item: any) => ({
|
||||
text: item.gugun || "",
|
||||
val: String(item.adstDstrCd) || "",
|
||||
})),
|
||||
];
|
||||
|
||||
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
@@ -41,7 +61,7 @@ export const getCityCd = async (set: any) => {
|
||||
val: item.adstDstrCd,
|
||||
text: item.sido,
|
||||
}));
|
||||
cityCd.unshift({ val: '0', text: '전체' })
|
||||
cityCd.unshift({ val: "0", text: "전체" });
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
@@ -58,7 +78,7 @@ export const getRegionCd = async (set: any) => {
|
||||
val: item.rvbsnCd,
|
||||
text: item.rvbsn,
|
||||
}));
|
||||
rvbsnCd.unshift({ val: '0', text: '전체' })
|
||||
rvbsnCd.unshift({ val: "0", text: "전체" });
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
@@ -66,7 +86,7 @@ export const getRegionCd = async (set: any) => {
|
||||
},
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('권역 데이터를 가져오는데 실패했습니다:', error);
|
||||
console.error("권역 데이터를 가져오는데 실패했습니다:", error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,7 +98,7 @@ export const getMiddleRegionCd = async (set: any) => {
|
||||
val: item.rvbsnCd,
|
||||
text: item.mdmbsn,
|
||||
}));
|
||||
mdmbsnCd.unshift({ val: '0', text: '전체' })
|
||||
mdmbsnCd.unshift({ val: "0", text: "전체" });
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
@@ -86,11 +106,10 @@ export const getMiddleRegionCd = async (set: any) => {
|
||||
},
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('중권역 데이터를 가져오는데 실패했습니다:', error);
|
||||
console.error("중권역 데이터를 가져오는데 실패했습니다:", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 단위유역 API 호출 함수 추가
|
||||
export const getUnitWaterShedCd = async (set: any) => {
|
||||
try {
|
||||
@@ -99,7 +118,7 @@ export const getUnitWaterShedCd = async (set: any) => {
|
||||
val: item.rvbsnCd,
|
||||
text: item.lgbsn,
|
||||
}));
|
||||
lgbsnCd.unshift({ val: '0', text: '전체' })
|
||||
lgbsnCd.unshift({ val: "0", text: "전체" });
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
@@ -107,23 +126,20 @@ export const getUnitWaterShedCd = async (set: any) => {
|
||||
},
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('대영역 데이터를 가져오는데 실패했습니다:', error);
|
||||
console.error("대영역 데이터를 가져오는데 실패했습니다:", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 환경청 데이터
|
||||
export const getEnvPartCd = async (set: any) => {
|
||||
try {
|
||||
const lclgvrnmnt = await getFetch('common', '/addr/govArea');
|
||||
const lclgvrnmnt = await getFetch("common", "/addr/govArea");
|
||||
const lclgvrnmntCd = lclgvrnmnt.map((item: any) => ({
|
||||
val: item.lclgvrnmntCd,
|
||||
text: item.lclgvrnmntNm,
|
||||
adstDliStrCd: item.adstDliStrCd || ''
|
||||
|
||||
adstDliStrCd: item.adstDliStrCd || "",
|
||||
}));
|
||||
lclgvrnmntCd.unshift({ val: '0', text: '전체', adstDliStrCd: '' })
|
||||
lclgvrnmntCd.unshift({ val: "0", text: "전체", adstDliStrCd: "" });
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
@@ -131,17 +147,14 @@ export const getEnvPartCd = async (set: any) => {
|
||||
},
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('환경청 데이터를 가져오는데 실패했습니다:', error);
|
||||
console.error("환경청 데이터를 가져오는데 실패했습니다:", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
export type comCodeState = {
|
||||
code: {
|
||||
isInit: boolean;
|
||||
chBuCd: SelectDataType[]
|
||||
chBuCd: SelectDataType[];
|
||||
rainFcltCd: SelectDataType[];
|
||||
bdstUsgCd: SelectDataType[];
|
||||
cityCd: SelectDataType[];
|
||||
@@ -154,32 +167,29 @@ export type comCodeState = {
|
||||
yn: SelectDataType[];
|
||||
pplQulity: SelectDataType[];
|
||||
pplLenght: SelectDataType[];
|
||||
dmdUszCd:SelectDataType[]
|
||||
dmdUszCd: SelectDataType[];
|
||||
buildingType: {
|
||||
RST:string,
|
||||
RNB:string,
|
||||
HTB:string
|
||||
}
|
||||
ruseMngMtd:SelectDataType[]
|
||||
RST: string;
|
||||
RNB: string;
|
||||
HTB: string;
|
||||
};
|
||||
ruseMngMtd: SelectDataType[];
|
||||
ruseSeCd: SelectDataType[];
|
||||
ruseBizMthdCd: SelectDataType[];
|
||||
rusePrcsMthdCd: SelectDataType[];
|
||||
erctUswtrPrcsMeth: SelectDataType[];
|
||||
bdstFilterYn: SelectDataType[];
|
||||
bdstIncenYn: SelectDataType[];
|
||||
bdstGrntchClass:SelectDataType[];
|
||||
rswtPrscCdMthdCd:SelectDataType[];
|
||||
htdPowerMthdCd:SelectDataType[]
|
||||
htdUtztnUsgCd:SelectDataType[]
|
||||
userSiSggCd : string;
|
||||
|
||||
bdstGrntchClass: SelectDataType[];
|
||||
rswtPrscCdMthdCd: SelectDataType[];
|
||||
htdPowerMthdCd: SelectDataType[];
|
||||
htdUtztnUsgCd: SelectDataType[];
|
||||
userSiSggCd: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type comCodeType = comCodeState & comCodeActions;
|
||||
|
||||
|
||||
|
||||
export const comCodeStateExport: comCodeState = {
|
||||
code: {
|
||||
isInit: false,
|
||||
@@ -193,62 +203,40 @@ export const comCodeStateExport: comCodeState = {
|
||||
mdmbsnCd: [],
|
||||
lgbsnCd: [],
|
||||
lclgvrnmntCd: [],
|
||||
pplQulity:pplQulity,
|
||||
pplLenght:pplLenght,
|
||||
pplQulity: pplQulity,
|
||||
pplLenght: pplLenght,
|
||||
yn: yn,
|
||||
dmdUszCd:dmdUszCd,
|
||||
buildingType:buildingType,
|
||||
ruseMngMtd:ruseMngMtd,
|
||||
ruseSeCd:ruseSeCd,
|
||||
dmdUszCd: dmdUszCd,
|
||||
buildingType: buildingType,
|
||||
ruseMngMtd: ruseMngMtd,
|
||||
ruseSeCd: ruseSeCd,
|
||||
ruseBizMthdCd: ruseBizMthdCd,
|
||||
rusePrcsMthdCd:rusePrcsMthdCd,
|
||||
erctUswtrPrcsMeth:erctUswtrPrcsMeth,
|
||||
bdstFilterYn:bdstFilterYn,
|
||||
bdstIncenYn:bdstIncenYn,
|
||||
bdstGrntchClass:bdstGrntchClass,
|
||||
rswtPrscCdMthdCd:rswtPrscCdMthdCd,
|
||||
htdPowerMthdCd:htdPowerMthdCd,
|
||||
htdUtztnUsgCd:htdUtztnUsgCd,
|
||||
userSiSggCd:laeSecd,
|
||||
rusePrcsMthdCd: rusePrcsMthdCd,
|
||||
erctUswtrPrcsMeth: erctUswtrPrcsMeth,
|
||||
bdstFilterYn: bdstFilterYn,
|
||||
bdstIncenYn: bdstIncenYn,
|
||||
bdstGrntchClass: bdstGrntchClass,
|
||||
rswtPrscCdMthdCd: rswtPrscCdMthdCd,
|
||||
htdPowerMthdCd: htdPowerMthdCd,
|
||||
htdUtztnUsgCd: htdUtztnUsgCd,
|
||||
userSiSggCd: laeSecd,
|
||||
},
|
||||
};
|
||||
|
||||
export type comCodeActions = {
|
||||
codeInit: () => void;
|
||||
returnCodeText: (val: string, codeName: string) => string;
|
||||
};
|
||||
|
||||
export const codeActionExport: (set: any) => comCodeActions = (set: any) => {
|
||||
return {
|
||||
codeInit: async () => {
|
||||
const sgg = await getFetch("common", "/addr/sgg");
|
||||
|
||||
const sggCd = sgg.map((item: any) => ({
|
||||
val: item.adstDstrCd,
|
||||
text: item.gugun,
|
||||
}));
|
||||
|
||||
const city = await getFetch("common", "/addr/city");
|
||||
const cityCd = city.map((item: any) => ({
|
||||
val: item.adstDstrCd,
|
||||
text: item.sido,
|
||||
}));
|
||||
|
||||
return set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
sggCd: sggCd,
|
||||
cityCd: cityCd,
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
divCityCd: async (cd: string) => {
|
||||
set((state: comCodeState) => ({
|
||||
code: {
|
||||
...state.code,
|
||||
sggCd: state.code.sggCd.filter((item) => { return item.val.toString().slice(0, 2) === cd }),
|
||||
},
|
||||
}));
|
||||
returnCodeText: (val: string, codeName: string) => {
|
||||
console.log('val', val, 'codeName', codeName);
|
||||
return set((state: comCodeState) => {
|
||||
const codeList = state.code[codeName] || [];
|
||||
const found = codeList.find((item) => item.val === val);
|
||||
return found ? found.text : val;
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -286,12 +286,12 @@ export const ldrmntNodeListExport: CommonTableProps[] = [
|
||||
title: "지목",
|
||||
visible: true,
|
||||
row: 1,
|
||||
rowSpan: 1,
|
||||
rowSpan: 1,
|
||||
colSpan: 1,
|
||||
},
|
||||
{
|
||||
id: "usgRgnArea",
|
||||
title: "용지면적",
|
||||
title: "용지면적(m²)",
|
||||
visible: true,
|
||||
row: 1,
|
||||
rowSpan: 1,
|
||||
|
||||
@@ -167,7 +167,7 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [
|
||||
},
|
||||
{
|
||||
id: "grnteWqPh",
|
||||
title: "수소이온농도(PH)",
|
||||
title: "수소이온농도(ph)",
|
||||
visible: true,
|
||||
row: 1,
|
||||
},
|
||||
|
||||
@@ -151,7 +151,7 @@ export const rainChkgdnHeadListExport: TableUpperProps[] = [
|
||||
{ id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" },
|
||||
{
|
||||
id: "ph",
|
||||
title: "수소이온농도(PH)",
|
||||
title: "수소이온농도(ph)",
|
||||
upName: "useQuilty",
|
||||
upSequnce: 1,
|
||||
type: "number",
|
||||
|
||||
@@ -167,7 +167,7 @@ export const rswtChkHeadListExport: TableUpperProps[] = [
|
||||
{ id: "crmty", title: "색도(도)", upName: "useQuilty", upSequnce: 6 ,type: "number"},
|
||||
{ id: "tn", title: "총질소(T-N)(mg/L)", upName: "useQuilty", upSequnce: 7 ,type: "number"},
|
||||
{ id: "tph", title: "총인(T-P)(mg/L)", upName: "useQuilty", upSequnce: 8 ,type: "number"},
|
||||
{ id: "ph", title: "수소이온농도(PH)", upName: "useQuilty", upSequnce: 9,type: "text" },
|
||||
{ id: "ph", title: "수소이온농도(ph)", upName: "useQuilty", upSequnce: 9,type: "text" },
|
||||
{ id: "clIonQnt", title: "염화물(mg/L)", upName: "useQuilty", upSequnce: 10 ,type: "number"},
|
||||
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ export const rainChkgdnHeadSttnExport: TableUpperProps[] = [
|
||||
{ id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" },
|
||||
{
|
||||
id: "ph",
|
||||
title: "수소이온농도(PH)",
|
||||
title: "수소이온농도(ph)",
|
||||
upName: "useQuilty",
|
||||
upSequnce: 1,
|
||||
type: "number",
|
||||
|
||||
@@ -64,7 +64,7 @@ export const rswtChkSttnHeadListExport: TableUpperProps[] = [
|
||||
upSequnce: 8,
|
||||
type: "number",
|
||||
},
|
||||
{ id: "ph", title: "수소이온농도(PH)", upName: "useQuilty", upSequnce: 9, type: "text" },
|
||||
{ id: "ph", title: "수소이온농도(ph)", upName: "useQuilty", upSequnce: 9, type: "text" },
|
||||
{
|
||||
id: "clIonQnt",
|
||||
title: "염화물(mg/L)",
|
||||
|
||||
@@ -6,7 +6,7 @@ import { makeMdfr, makeRstr } from "../bdstReg";
|
||||
import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "./type";
|
||||
|
||||
export const TEST_UUID = '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e'
|
||||
|
||||
export const rainRegSize =15
|
||||
const rainyObjSchema = z.object({
|
||||
bdstReuseFcltFk: z.number().nullish(),
|
||||
pntfColKnd: z.string().min(1, { message: validationMessages.requiredSelect("종류") }),
|
||||
@@ -99,7 +99,7 @@ export const rainFacStateExport: rainFacState = {
|
||||
|
||||
const initFetch = async (code: string | number) => {
|
||||
// const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/10/${code}`);
|
||||
const rainRes = await getFetchWithCount("wr", `/reuseFc/rainyInfoList/1/11/${code}`);
|
||||
const rainRes = await getFetchWithCount("wr", `/reuseFc/rainyInfoList/1/${rainRegSize}/${code}`);
|
||||
return rainRes;
|
||||
};
|
||||
export const rainFacActionsExport: (set: any) => rainFacSActions = (
|
||||
@@ -108,7 +108,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
|
||||
return {
|
||||
getRainData: async (pageNation: number, code: string | number) => {
|
||||
try {
|
||||
const rainRes = await getFetchWithCount("wr", `/reuseFc/rainyInfoList/${pageNation}/11/${code}`);
|
||||
const rainRes = await getFetchWithCount("wr", `/reuseFc/rainyInfoList/${pageNation}/${rainRegSize}/${code}`);
|
||||
|
||||
// 여기서 상태 업데이트
|
||||
return set((state: rainFacState) => ({
|
||||
@@ -149,7 +149,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
|
||||
try {
|
||||
|
||||
// const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/41` +(txt? `/${txt}`:''))
|
||||
const rainRes = await getFetchWithCount('wr', `/reuseFc/rainyInfoList/${pageNation}/11/41` + (txt ? `/${txt}` : ''))
|
||||
const rainRes = await getFetchWithCount('wr', `/reuseFc/rainyInfoList/${pageNation}/${rainRegSize}/41` + (txt ? `/${txt}` : ''))
|
||||
console.log("rainRes", rainRes)
|
||||
set((state: rainFacState) => {
|
||||
return {
|
||||
|
||||
@@ -6,14 +6,13 @@ export const validationMessages = {
|
||||
requiredSelect: (field: string) => `${field}을(를) 선택해주세요.`,
|
||||
yearFormat: '4자리 연도만 입력하세요',
|
||||
};
|
||||
|
||||
export const baseReuseBuildingSchema = z.object({
|
||||
bdstRuseFcltSn: z.number().nullish(),
|
||||
bdstInfoSn: z.number().nullish(),
|
||||
instlCmptnDt: z.coerce.date().default(() => new Date()),
|
||||
instlCst: z
|
||||
.number()
|
||||
.max(9_999_999, { message: "최대 9,999,999까지 입력 가능합니다." })
|
||||
.max(999_999_999_999, { message: "최대 1,000,000,000,000까지 입력 가능합니다." })
|
||||
.nullish(),
|
||||
operMngCd: z.string().optional().default(""),
|
||||
anlOperCst: z.number().default(0),
|
||||
|
||||
@@ -7,6 +7,8 @@ import { z } from "zod";
|
||||
import { makeMdfr, makeRstr } from "../bdstReg";
|
||||
import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "../rainReg/type";
|
||||
|
||||
|
||||
export const rswtRegSize =15;
|
||||
const rswtrObjSchema = z.object({
|
||||
bdstRuseFcltSn: z.number().nullish(),
|
||||
//wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }),
|
||||
@@ -84,7 +86,7 @@ export const rswtFacStateExport: rswtFacState = {
|
||||
};
|
||||
|
||||
const initFetch = async (code: string | number) => {
|
||||
const rswtRes = await getFetchWithCount("wr", `/reuseFc/waterreuseFc/1/11/${code}`);
|
||||
const rswtRes = await getFetchWithCount("wr", `/reuseFc/waterreuseFc/1/${rswtRegSize}/${code}`);
|
||||
return rswtRes;
|
||||
};
|
||||
export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
|
||||
@@ -99,7 +101,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
|
||||
try {
|
||||
const rswtRes = await getFetchWithCount(
|
||||
"wr",
|
||||
`/reuseFc/waterreuseFc/${pageNation}/11/${code}` +
|
||||
`/reuseFc/waterreuseFc/${pageNation}/${rswtRegSize}/${code}` +
|
||||
(txt ? `/${txt}` : "")
|
||||
);
|
||||
set((state: rswtFacState) => {
|
||||
@@ -121,7 +123,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
|
||||
try {
|
||||
const rswtRes = await getFetchWithCount(
|
||||
"wr",
|
||||
`/reuseFc/waterreuseFc/${pageNation}/11/${code}`
|
||||
`/reuseFc/waterreuseFc/${pageNation}/${rswtRegSize}/${code}`
|
||||
);
|
||||
console.log(pageNation);
|
||||
// 여기서 상태 업데이트
|
||||
|
||||
@@ -11,6 +11,8 @@ import { htdflSttHeadListExport, htdflSttNodeListExport } from "./headList";
|
||||
const htdflSttHeadList = htdflSttHeadListExport;
|
||||
const htdflSttNodeList = htdflSttNodeListExport;
|
||||
|
||||
|
||||
export const htdflSttnSize =10;
|
||||
export type htdflSttnState = {
|
||||
htdflSttn: {
|
||||
isInit: boolean;
|
||||
@@ -22,10 +24,10 @@ export type htdflSttnState = {
|
||||
};
|
||||
};
|
||||
type htdflSttnActions = {
|
||||
initHtdfl: (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
initHtdfl: (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => void;
|
||||
htdflSttnSearch: (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
htdflSttnSearch: (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => void;
|
||||
htdflChSttnHead: (
|
||||
@@ -45,7 +47,7 @@ export const htdflSttnStateExport: htdflSttnState = {
|
||||
htdflSttnResCount: 1,
|
||||
},
|
||||
};
|
||||
const initFetch = async (page: number, total: string, con: string, txt: string) => {
|
||||
const initFetch = async (page: number, total: number, con: string, txt: string) => {
|
||||
const htdflRes = await getFetchWithCount(
|
||||
"wr",
|
||||
`/drain/facilityList` +
|
||||
@@ -62,7 +64,7 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = (
|
||||
set: any
|
||||
) => {
|
||||
return {
|
||||
initHtdfl: async (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
initHtdfl: async (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => {
|
||||
try {
|
||||
@@ -95,7 +97,7 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = (
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
htdflSttnSearch: async (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
htdflSttnSearch: async (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => {
|
||||
try {
|
||||
|
||||
@@ -461,7 +461,7 @@ export const ruseGuranteeHeadListExport: TableUpperProps[] = [
|
||||
{ id: "crmty", title: "색도(도)", visible: true },
|
||||
{ id: "tn", title: "총질소(mg/L)", visible: true },
|
||||
{ id: "tph", title: "총인(mg/L)", visible: true },
|
||||
{ id: "ph", title: "수소이온농도(PH)", visible: true },
|
||||
{ id: "ph", title: "수소이온농도(ph)", visible: true },
|
||||
{ id: "clIonQnt", title: "염화물(mg/L)", visible: true },
|
||||
{ id: "cdtnv", title: "전기전도도(μs/cm)", visible: true },
|
||||
];
|
||||
|
||||
@@ -228,7 +228,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
|
||||
},
|
||||
{
|
||||
id: "archArea",
|
||||
title: "건축면적(m³)",
|
||||
title: "건축면적(m²)",
|
||||
upName: "bdnstInfo",
|
||||
visible: true,
|
||||
row: 2,
|
||||
|
||||
@@ -15,6 +15,8 @@ import type { z } from "zod";
|
||||
import type { CommonTableProps } from "@/app/store/common/type/header";
|
||||
import type { SelectDataType } from "@common/business_components/ui";
|
||||
|
||||
|
||||
export const rainSttnSize = 10;
|
||||
// 테이블 헤드 리스트
|
||||
const rainSttHeadList = rainSttHeadListExport;
|
||||
const rainSttNodeList = rainSttNodeListExport;
|
||||
@@ -100,10 +102,10 @@ export type rainSttnState = {
|
||||
};
|
||||
};
|
||||
type rainSttnActions = {
|
||||
rainSttnInit: (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rainSttnInit: (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => void
|
||||
rainSttnSearch: (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rainSttnSearch: (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => void;
|
||||
rainChSttnHead: (
|
||||
@@ -132,7 +134,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
|
||||
set: any
|
||||
) => {
|
||||
return {
|
||||
rainSttnInit: async (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rainSttnInit: async (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => {
|
||||
try {
|
||||
@@ -141,7 +143,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
|
||||
fetchType.WR,
|
||||
`/reuseFc/rainyInfoList` +
|
||||
(page ? `/${page}` : "/1") +
|
||||
(total ? `/${total}` : "/20") +
|
||||
(total ? `/${total}` : "/15") +
|
||||
(con ? `/${con}` : "/0") +
|
||||
(txt ? `/${txt}` : "")
|
||||
);
|
||||
@@ -172,7 +174,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
rainSttnSearch: async (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rainSttnSearch: async (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => {
|
||||
try {
|
||||
@@ -180,7 +182,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
|
||||
fetchType.WR,
|
||||
`/reuseFc/rainyInfoList` +
|
||||
(page ? `/${page}` : "/1") +
|
||||
(total ? `/${total}` : "/20") +
|
||||
(total ? `/${total}` : "/15") +
|
||||
(con ? `/${con}` : "/0") +
|
||||
(txt ? `/${txt}` : "")
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ const rswtSttHeadList = rswtSttHeadListExport;
|
||||
const rswtSttnRes: customRswtBdst[] = [];
|
||||
|
||||
|
||||
export const rswtSttnSize = 10;
|
||||
|
||||
export type rswtSttnState = {
|
||||
rswtSttn: {
|
||||
@@ -29,10 +30,10 @@ export type rswtSttnState = {
|
||||
};
|
||||
|
||||
type rswtSttnActions = {
|
||||
rswtSttnInit: (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rswtSttnInit: (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => void;
|
||||
rswtSttnSearch: (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rswtSttnSearch: (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => void;
|
||||
rswtChSttnHead: (
|
||||
@@ -59,7 +60,7 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = (
|
||||
set: any
|
||||
) => {
|
||||
return {
|
||||
rswtSttnInit: async (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rswtSttnInit: async (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => {
|
||||
try {
|
||||
@@ -67,7 +68,7 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = (
|
||||
fetchType.WR,
|
||||
`/reuseFc/waterreuseFc` +
|
||||
(page ? `/${page}` : "/1") +
|
||||
(total ? `/${total}` : "/20") +
|
||||
(total ? `/${total}` : "/10") +
|
||||
(con ? `/${con}` : "/0") +
|
||||
(txt ? `/${txt}` : "")
|
||||
);
|
||||
@@ -99,7 +100,7 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = (
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
rswtSttnSearch: async (isExcel: boolean, page: number, total: string, con: string, txt: string,
|
||||
rswtSttnSearch: async (isExcel: boolean, page: number, total: number, con: string, txt: string,
|
||||
sidoCode: SelectDataType[],
|
||||
sggCode: SelectDataType[]) => {
|
||||
try {
|
||||
@@ -107,7 +108,7 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = (
|
||||
fetchType.WR,
|
||||
`/reuseFc/waterreuseFc` +
|
||||
(page ? `/${page}` : "/1") +
|
||||
(total ? `/${total}` : "/20") +
|
||||
(total ? `/${total}` : "/10") +
|
||||
(con ? `/${con}` : "/0") +
|
||||
(txt ? `/${txt}` : "")
|
||||
);
|
||||
|
||||
@@ -272,4 +272,28 @@ export const formatYyyymmdd = (val: string | undefined) => {
|
||||
}
|
||||
const m = moment(val);
|
||||
return m.isValid() ? m.format("YYYY-MM-DD") : val;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 문자열 숫자(콤마 포함 가능)를 반올림 처리해 반환.
|
||||
* 숫자가 아닌 경우(예: "확인불가")는 원래 값을 그대로 반환.
|
||||
*
|
||||
* @param value 입력 문자열
|
||||
* @param digits 소수점 자릿수 (기본 0 = 정수 반올림)
|
||||
*/
|
||||
export const formatArchArea =(value: string, digits: number=0 ) => {
|
||||
|
||||
// "확인불가" 등 숫자 아님 → 그대로 반환
|
||||
const cleaned = value.replace(/,/g, "");
|
||||
const num = parseFloat(cleaned);
|
||||
|
||||
if (isNaN(num)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// 반올림 (digits 자릿수까지)
|
||||
const rounded = num.toFixed(digits);
|
||||
|
||||
// 다시 천 단위 콤마 찍어서 반환
|
||||
return Number(rounded).toLocaleString();
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
SelectBox,
|
||||
type SelectDataType,
|
||||
} from "@common/business_components";
|
||||
import SearchInputAddress from "@common/business_components/ui/search_input_address";
|
||||
import type { addressType } from "@common/business_components/ui/search_input_address/findAddress";
|
||||
import { Input } from "@common/components";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
@@ -16,49 +18,47 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
const { code } = useWrStore((state) => {
|
||||
return state;
|
||||
});
|
||||
const { userSiSggCd } = code;
|
||||
const [useCityCd, setUserCityCd] = useState<SelectDataType[]>([]);
|
||||
const [useSggCd, setUserSggCd] = useState<SelectDataType[]>([]);
|
||||
|
||||
const { userSiSggCd } = code
|
||||
const [useCityCd, setUserCityCd] = useState<SelectDataType[]>([])
|
||||
const [useSggCd, setUserSggCd] = useState<SelectDataType[]>([])
|
||||
|
||||
// const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>();
|
||||
// const [objSearch, setObjSearch] = useState<objSearchType>({
|
||||
// sgg: "",
|
||||
// city: "",
|
||||
// });
|
||||
|
||||
useEffect(() => {
|
||||
if (userSiSggCd.length === 2 && code.cityCd.length > 0) {
|
||||
const city = code.cityCd.filter((item) => item.val === userSiSggCd)
|
||||
const sgg = code.sggCd.filter((item) => item.val.slice(0, 2) === userSiSggCd)
|
||||
sgg.unshift({ text: '전체', val: '0' })
|
||||
setUserCityCd(city) // Fix: Ensure city is of type SelectDataType[]
|
||||
setUserSggCd(sgg)
|
||||
const city = code.cityCd.filter((item) => item.val === userSiSggCd);
|
||||
const sgg = code.sggCd.filter(
|
||||
(item) => item.val.slice(0, 2) === userSiSggCd
|
||||
);
|
||||
sgg.unshift({ text: "전체", val: "0" });
|
||||
setUserCityCd(city); // Fix: Ensure city is of type SelectDataType[]
|
||||
setUserSggCd(sgg);
|
||||
if (city[0]?.val) {
|
||||
// 여기 중요
|
||||
queueMicrotask(() => {
|
||||
form.setValue("ctpvCd", Number(city[0]?.val), { shouldDirty: true, shouldTouch: true, shouldValidate: true });
|
||||
form.setValue("ctpvCd", Number(city[0]?.val), {
|
||||
shouldDirty: true,
|
||||
shouldTouch: true,
|
||||
shouldValidate: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if (userSiSggCd.length === 5 && code.cityCd.length > 0 && code.sggCd.length > 0) {
|
||||
const city = code.cityCd.filter((item) => item.val === userSiSggCd.slice(0, 2))
|
||||
const sgg = code.sggCd.filter((item) => item.val === userSiSggCd)
|
||||
setUserSggCd(sgg)
|
||||
setUserCityCd(city)
|
||||
form.setValue('ctpvCd', Number(city[0]?.val))
|
||||
form.setValue('sggCd', Number(sgg[0]?.val))
|
||||
|
||||
} else if (
|
||||
userSiSggCd.length === 5 &&
|
||||
code.cityCd.length > 0 &&
|
||||
code.sggCd.length > 0
|
||||
) {
|
||||
const city = code.cityCd.filter(
|
||||
(item) => item.val === userSiSggCd.slice(0, 2)
|
||||
);
|
||||
const sgg = code.sggCd.filter((item) => item.val === userSiSggCd);
|
||||
setUserSggCd(sgg);
|
||||
setUserCityCd(city);
|
||||
form.setValue("ctpvCd", Number(city[0]?.val));
|
||||
form.setValue("sggCd", Number(sgg[0]?.val));
|
||||
}
|
||||
}, [form, userSiSggCd, code.cityCd, code.sggCd])
|
||||
}, [form, userSiSggCd, code.cityCd, code.sggCd]);
|
||||
|
||||
|
||||
|
||||
// useEffect(() => {
|
||||
// const city = form.getValues("ctpvCd");
|
||||
// const sgg = form.getValues("sggCd");
|
||||
// setObjSearch({ city: city, sgg: sgg });
|
||||
// }, [selectSgg]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = form.form?.watch((value: any) => {
|
||||
console.log("vale", value);
|
||||
@@ -67,15 +67,16 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
return () => subscription?.unsubscribe();
|
||||
}, [form.form]);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
console.log('form.formState ', form.watch("archArea"))
|
||||
}, [form.formState])
|
||||
console.log("form.formState ", form.watch("archArea"));
|
||||
}, [form.formState]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className={formH1Class}> {type !== "HTB" ? "건축물 기본 정보" : '시설 기본 정보'}</h1>
|
||||
<h1 className={formH1Class}>
|
||||
{" "}
|
||||
{type !== "HTB" ? "건축물 기본 정보" : "시설 기본 정보"}
|
||||
</h1>
|
||||
<div className="grid grid-cols-6 gap-2 mt-4">
|
||||
<div className="col-span-3">
|
||||
<FormField
|
||||
@@ -91,7 +92,11 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
onSelectValue={(val) => {
|
||||
field.onChange(Number(val));
|
||||
}}
|
||||
value={typeof field.value !== "undefined" ? field.value : useCityCd[0]?.val}
|
||||
value={
|
||||
typeof field.value !== "undefined"
|
||||
? field.value
|
||||
: useCityCd[0]?.val
|
||||
}
|
||||
/>
|
||||
</FormUi>
|
||||
)}
|
||||
@@ -124,15 +129,19 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
control={form.control}
|
||||
name="bdstNm"
|
||||
render={({ field }) => (
|
||||
<FormUi label={type !== "HTB" ? "건축물명" : '시설명'}>
|
||||
<FormUi label={type !== "HTB" ? "건축물명" : "시설명"}>
|
||||
<Input
|
||||
className={selectClass}
|
||||
placeholder={type !== "HTB" ? "건축물 명 입력하세요" : '시설명 입력하세요'}
|
||||
placeholder={
|
||||
type !== "HTB"
|
||||
? "건축물 명 입력하세요"
|
||||
: "시설명 입력하세요"
|
||||
}
|
||||
type="text"
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value)
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={field.value || ''}
|
||||
value={field.value || ""}
|
||||
maxLength={txtSize}
|
||||
/>
|
||||
</FormUi>
|
||||
@@ -144,8 +153,8 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
control={form.control}
|
||||
name="daddr"
|
||||
render={({ field }) => (
|
||||
<FormUi label={type !== "HTB" ? "건축물 주소" : '시설 주소'} >
|
||||
<Input
|
||||
<FormUi label={type !== "HTB" ? "건축물 주소" : "시설 주소"}>
|
||||
{/* <Input
|
||||
className={selectClass}
|
||||
placeholder="위치를 입력해주세요"
|
||||
type="search"
|
||||
@@ -154,7 +163,16 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
}}
|
||||
value={field.value || ''}
|
||||
maxLength={50}
|
||||
/>
|
||||
/> */}
|
||||
<div>
|
||||
<SearchInputAddress
|
||||
initValue={undefined}
|
||||
setRtnData={(rtnData: addressType) => {
|
||||
console.log("rtnData", rtnData);
|
||||
field.onChange(rtnData.roadAddrPart1);
|
||||
}}
|
||||
></SearchInputAddress>
|
||||
</div>
|
||||
</FormUi>
|
||||
)}
|
||||
/>
|
||||
@@ -165,7 +183,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
control={form.control}
|
||||
name="frstArchPrmsnDt"
|
||||
render={({ field }) => (
|
||||
<FormUi label={type !== "HTB" ? "최초건축허가일" : '준공년도'} >
|
||||
<FormUi label={type !== "HTB" ? "최초건축허가일" : "준공년도"}>
|
||||
<DatePicker
|
||||
mode={"single"}
|
||||
field={{
|
||||
@@ -174,7 +192,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
}}
|
||||
// modifiers={{
|
||||
// disabled: { after: new Date() }
|
||||
// }}
|
||||
// }}
|
||||
selectClass={"w-full"}
|
||||
></DatePicker>
|
||||
</FormUi>
|
||||
@@ -212,15 +230,15 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
|
||||
control={form.control}
|
||||
name="archArea"
|
||||
render={({ field }) => (
|
||||
<FormUi label="건축면적(m³)">
|
||||
<FormUi label="건축면적(m²)">
|
||||
<Input
|
||||
className={selectClass}
|
||||
placeholder="면적을 입력하세요"
|
||||
type="text"
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value)
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={field.value || ''}
|
||||
value={field.value || ""}
|
||||
maxLength={numSize}
|
||||
/>
|
||||
</FormUi>
|
||||
|
||||
@@ -881,7 +881,7 @@ export default function HtdflRegForm({
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-4">
|
||||
<div className="col-span-6">
|
||||
<Label className="text-xl">수소이온농도(PH)</Label>
|
||||
<Label className="text-xl">수소이온농도(ph)</Label>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Input
|
||||
className="!text-xl w-1/2"
|
||||
|
||||
@@ -445,7 +445,7 @@ export function PbnstBuseForm({
|
||||
onSelectValue={(val) => setPpiYn(String(val))}
|
||||
readOnly={readonly}
|
||||
/>
|
||||
<Label className="text-right">합계</Label>
|
||||
<Label className="text-right">합계(m)</Label>
|
||||
<Input
|
||||
type="text"
|
||||
value={formatCommaNumber(sumCpct)}
|
||||
|
||||
@@ -14,9 +14,9 @@ import {
|
||||
} from "@/components/lib/func/commom";
|
||||
import { DatePicker, FormUi } from "@common/business_components";
|
||||
import { Form, FormField, SelectBox } from "@common/business_components/ui";
|
||||
import { Button, Input, ScrollArea } from "@common/components/ui";
|
||||
import { Button, Input } from "@common/components/ui";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import BdstReg from "../bdstReg/bdstReg";
|
||||
@@ -54,18 +54,12 @@ export default function RainRegForm({
|
||||
"reuseBuilding.0.rainyObj.filtrTrtmfctYn",
|
||||
]);
|
||||
|
||||
const [divStyle, setDivStyle] = useState("h-[53vh]");
|
||||
// const [divStyle, setDivStyle] = useState("h-[53vh]");
|
||||
useEffect(() => {
|
||||
if(isMap=== true){
|
||||
setDivStyle("h-[100vh]")
|
||||
}else if (isModal === true) {
|
||||
setDivStyle("h-[53vh] max-h-[37vh]")
|
||||
} else if (readonly === true) {
|
||||
setDivStyle("h-[62vh]")
|
||||
} else {
|
||||
setDivStyle("h-[57vh]")
|
||||
|
||||
}
|
||||
}, [isModal, readonly ,isMap]);
|
||||
}, [isMap]);
|
||||
|
||||
const cleanRainData = (raw: any): z.infer<typeof rainZod> => {
|
||||
const buildings =
|
||||
@@ -94,6 +88,8 @@ export default function RainRegForm({
|
||||
grntchBdstCertYn: item?.grntchBdstCertYn ?? "Y",
|
||||
rainyObj: {
|
||||
...item?.rainyObj,
|
||||
pntfColKnd:item.rainyObj?.pntfColKnd??'확인불가',
|
||||
filtrTrtmfctPrs:item.rainyObj?.filtrTrtmfctPrs??'',
|
||||
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y",
|
||||
},
|
||||
})),
|
||||
@@ -139,7 +135,6 @@ export default function RainRegForm({
|
||||
toast.error("시도/시군구 코드를 선택해야합니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const handleConfirm = async () => {
|
||||
rainBdstReg(values, data);
|
||||
if (setIsModal) setIsModal(false);
|
||||
@@ -180,7 +175,7 @@ export default function RainRegForm({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<ScrollArea className={divStyle}>
|
||||
{/* <ScrollArea className={divStyle}> */}
|
||||
{isModal && rainForm != undefined ? <BdstReg form={form} /> : <></>}
|
||||
{isModal ? (
|
||||
<h1 className="pl-3 text-xl col-span-10 mt-4">
|
||||
@@ -614,7 +609,7 @@ export default function RainRegForm({
|
||||
</div>
|
||||
</div>
|
||||
<BdstAdd form={form} readonly={readonly}></BdstAdd>
|
||||
</ScrollArea>
|
||||
{/* </ScrollArea> */}
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
@@ -19,9 +19,9 @@ import {
|
||||
FormUi,
|
||||
SelectBox,
|
||||
} from "@common/business_components/ui";
|
||||
import { Button, Input, ScrollArea } from "@common/components/ui";
|
||||
import { Button, Input } from "@common/components/ui";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import BdstAdd from "../bdstReg/bdstAdd";
|
||||
@@ -46,18 +46,11 @@ export default function RswtrRegForm({
|
||||
const { code, rswtBdstUpdate, rswtBdstReg } = useWrStore(
|
||||
(state) => state
|
||||
);
|
||||
const [divStyle, setDivStyle] = useState("h-[53vh]");
|
||||
// const [divStyle, setDivStyle] = useState("h-[53vh]");
|
||||
useEffect(() => {
|
||||
if(isMap){
|
||||
setDivStyle("h-[100vh]")
|
||||
}else if (isModal === true) {
|
||||
setDivStyle("h-[53vh] max-h-[37vh]")
|
||||
} else if (readonly === true) {
|
||||
setDivStyle("h-[62vh]")
|
||||
} else {
|
||||
setDivStyle("h-[57vh]")
|
||||
}
|
||||
}, [isModal, readonly ,isMap]);
|
||||
}, [isMap]);
|
||||
// const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({});
|
||||
|
||||
const form = useForm<z.infer<typeof rswtZod>>({
|
||||
@@ -176,7 +169,7 @@ export default function RswtrRegForm({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<ScrollArea className={divStyle}>
|
||||
{/* <ScrollArea className={divStyle}> */}
|
||||
{isModal && rswtForm != undefined ? <BdstReg form={form} /> : <></>}
|
||||
{isModal ? (
|
||||
<h1 className="pl-3 text-xl col-span-10 mt-4 ">
|
||||
@@ -506,7 +499,7 @@ export default function RswtrRegForm({
|
||||
</div>
|
||||
</div>
|
||||
<BdstAdd form={form} readonly={readonly}></BdstAdd>
|
||||
</ScrollArea>
|
||||
{/* </ScrollArea> */}
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
@@ -196,7 +196,7 @@ export function BdstReg<T extends MoType>({
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<div className="border-t border-gray-300 my-4"></div>
|
||||
{/* <ScrollArea className="h-[40vh]"> */}
|
||||
<ScrollArea className="h-[40vh]">
|
||||
<div>
|
||||
{moType === "RNB" ? (
|
||||
<RainRegForm
|
||||
@@ -226,7 +226,7 @@ export function BdstReg<T extends MoType>({
|
||||
></HtdflRegForm>
|
||||
)}
|
||||
</div>
|
||||
{/* </ScrollArea> */}
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -571,7 +571,7 @@ export default function CoDetailModal({
|
||||
control={form.control}
|
||||
name="usgRgnArea"
|
||||
render={({ field }) => (
|
||||
<FormUi label="용지면적">
|
||||
<FormUi label="용지면적(m²)">
|
||||
<Input
|
||||
className={selectClass}
|
||||
placeholder=""
|
||||
|
||||
@@ -19,6 +19,14 @@ const customStyles = {
|
||||
} as CSSProperties,
|
||||
};
|
||||
|
||||
const fncNumberFormet = (value : string | number) => {
|
||||
return String(value).includes('.')?
|
||||
String(parseFloat(value.toString().replace(/,/g, ''))).split('.').map((part, index) =>
|
||||
index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
|
||||
).join('.')
|
||||
: String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
type BarChartProps = {
|
||||
chartConfig: ChartConfig | undefined;
|
||||
chartData: any[] | undefined;
|
||||
@@ -51,7 +59,7 @@ const CustomTooltip = ({
|
||||
<div key={index} style={{ marginTop: "10px", display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
{/* 색상 박스 추가 (범례 색상과 동일) */}
|
||||
<div style={{ width: "10px", height: "10px", backgroundColor: item.color, borderRadius: "50%" }}></div>
|
||||
<span className="text-[11px] font-bold">{` ${item.name} : ${item.value}`}</span>
|
||||
<span className="text-[11px] font-bold">{` ${item.name} : ${fncNumberFormet(item.value)}`}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
type ChartConfig
|
||||
} from "./lib/chart";
|
||||
import type { ContentType } from "recharts/types/component/DefaultLegendContent";
|
||||
import type { set } from "date-fns";
|
||||
|
||||
// 툴크 커스텀 css
|
||||
/** 차트 기본 스타일 */
|
||||
@@ -29,6 +30,7 @@ type LineBarChartProps = {
|
||||
yFieldText?: string | undefined;
|
||||
yFieldText2?: string | undefined;
|
||||
showLegend?: boolean;
|
||||
setXAxisYearTick?: boolean;
|
||||
}
|
||||
|
||||
type LegendEntry = {
|
||||
@@ -86,7 +88,8 @@ export default function LineBarchart({
|
||||
graphSize = 40,
|
||||
yFieldText,
|
||||
yFieldText2,
|
||||
showLegend = true
|
||||
showLegend = true,
|
||||
setXAxisYearTick = false
|
||||
}: LineBarChartProps) {
|
||||
if (!chartData || chartData.length === 0) {
|
||||
return <div>데이터가 없습니다.</div>;
|
||||
@@ -105,6 +108,24 @@ export default function LineBarchart({
|
||||
const lineMaxValue = getMaxValue(chartData, 'lineVal');
|
||||
const barMaxValue = getMaxValue(chartData, 'barVal');
|
||||
|
||||
const getTicks = (data : any []) => {
|
||||
const monthSet = new Set<string>();
|
||||
const rtnData : string[] = [];
|
||||
for(const item of data){
|
||||
const month = String(item.label).slice(0,7);
|
||||
if(!monthSet.has(month)){
|
||||
monthSet.add(month);
|
||||
rtnData.push(item.label);
|
||||
}
|
||||
}
|
||||
return rtnData;
|
||||
}
|
||||
|
||||
let monthTicks : string[] = [];
|
||||
if(setXAxisYearTick){
|
||||
monthTicks = getTicks(chartData);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={chartClassName}>
|
||||
{chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
|
||||
@@ -121,7 +142,10 @@ export default function LineBarchart({
|
||||
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="label" fontSize="8px" fontWeight="bold"/>
|
||||
{setXAxisYearTick?
|
||||
<XAxis dataKey="label" ticks={monthTicks} tickFormatter={(value) => value.slice(0,7)} fontSize="8px" fontWeight="bold"/> :
|
||||
<XAxis dataKey="label" fontSize="8px" fontWeight="bold"/>
|
||||
}
|
||||
{/* 왼쪽 Y축: lineVal */}
|
||||
{yFieldText && <YAxis
|
||||
yAxisId="left"
|
||||
|
||||
@@ -15,6 +15,7 @@ type LineChartProps = {
|
||||
graphSize?: number;
|
||||
yFieldText?: string;
|
||||
showLegend?: boolean;
|
||||
setXAxisYearTick?: boolean;
|
||||
}
|
||||
|
||||
/** 차트 기본 스타일 */
|
||||
@@ -141,7 +142,8 @@ export default function Linechart({
|
||||
chartClassName = 'w-full h-full',
|
||||
graphSize = 40,
|
||||
yFieldText,
|
||||
showLegend = true
|
||||
showLegend = true,
|
||||
setXAxisYearTick = false,
|
||||
}: LineChartProps) {
|
||||
if (!chartData || Object.keys(chartData).length === 0) {
|
||||
return <div>데이터가 없습니다.</div>;
|
||||
@@ -164,18 +166,24 @@ export default function Linechart({
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// 데이터의 최대값 계산
|
||||
const getMaxValue = (data: ChartDataType): number => {
|
||||
return Math.max(...Object.values(data).flatMap(dataset =>
|
||||
dataset.map(entry => {
|
||||
const val = parseFloat(entry.val);
|
||||
return isNaN(val) ? 0 : val;
|
||||
})
|
||||
));
|
||||
};
|
||||
|
||||
const lineMaxValue = getMaxValue(chartData);
|
||||
|
||||
const getTicks = (data : any []) => {
|
||||
const monthSet = new Set<string>();
|
||||
const rtnData : string[] = [];
|
||||
for(const item of data){
|
||||
const month = String(item.label).slice(0,7);
|
||||
if(!monthSet.has(month)){
|
||||
monthSet.add(month);
|
||||
rtnData.push(item.label);
|
||||
}
|
||||
}
|
||||
return rtnData;
|
||||
}
|
||||
|
||||
let monthTicks : string[] = [];
|
||||
if(setXAxisYearTick){
|
||||
monthTicks = getTicks(mergedData);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={chartClassName}>
|
||||
{chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
|
||||
@@ -192,8 +200,27 @@ export default function Linechart({
|
||||
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis dataKey="label" fontSize="8px" fontWeight="bold" />
|
||||
<YAxis yAxisId="left" className="text-[12px] font-bold" tickFormatter={(value) => value.toLocaleString()} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} />
|
||||
|
||||
{setXAxisYearTick ?
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
fontSize="8px"
|
||||
fontWeight="bold"
|
||||
ticks={monthTicks}
|
||||
tickFormatter={(value) => value.slice(0,7)}
|
||||
/> :
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
fontSize="8px"
|
||||
fontWeight="bold"
|
||||
/>
|
||||
}
|
||||
|
||||
<YAxis
|
||||
yAxisId="left"
|
||||
className="text-[12px] font-bold"
|
||||
orientation="left"
|
||||
label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} />
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
{showLegend && <Legend content={CustomLegend as ContentType}/>}
|
||||
{Object.keys(chartData).map((key) => {
|
||||
|
||||
@@ -56,6 +56,7 @@ type MainChartProps = {
|
||||
yFieldText? : string | undefined;
|
||||
yFieldText2? : string | undefined;
|
||||
showLegend? : boolean;
|
||||
setXAxisYearTick ?: boolean;
|
||||
}
|
||||
|
||||
function MainChart(props: MainChartProps) {
|
||||
@@ -65,7 +66,7 @@ function MainChart(props: MainChartProps) {
|
||||
);
|
||||
} else if( props.chartForm == CHART_FORM.LINE ){
|
||||
return (
|
||||
<LineChart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle} chartClassName={props.chartClassName} graphSize={props.graphSize} yFieldText={props.yFieldText} showLegend={props.showLegend}/>
|
||||
<LineChart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle} chartClassName={props.chartClassName} graphSize={props.graphSize} yFieldText={props.yFieldText} showLegend={props.showLegend} setXAxisYearTick={props.setXAxisYearTick}/>
|
||||
);
|
||||
} else if( props.chartForm == CHART_FORM.DN ){
|
||||
return (
|
||||
@@ -73,7 +74,7 @@ function MainChart(props: MainChartProps) {
|
||||
);
|
||||
} else if (props.chartForm == CHART_FORM.LINEBAR){
|
||||
return (
|
||||
<LineBarchart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle} chartClassName={props.chartClassName} graphSize={props.graphSize} yFieldText={props.yFieldText} yFieldText2={props.yFieldText2} showLegend={props.showLegend}/>
|
||||
<LineBarchart chartConfig={props.chartConfig} chartData={props.chartData} chartTitle={props.chartTitle} chartClassName={props.chartClassName} graphSize={props.graphSize} yFieldText={props.yFieldText} yFieldText2={props.yFieldText2} showLegend={props.showLegend} setXAxisYearTick={props.setXAxisYearTick}/>
|
||||
);
|
||||
} else if (props.chartForm == CHART_FORM.LINEBAR2){
|
||||
return (
|
||||
|
||||
@@ -14,6 +14,7 @@ export * from "./search_form_left";
|
||||
export * from "./search_form_right";
|
||||
export * from "./search_input";
|
||||
export * from "./search_input_select";
|
||||
export * from "./search_input_address";
|
||||
export * from "./select";
|
||||
export * from "./tab";
|
||||
export * from "./table";
|
||||
|
||||
@@ -688,6 +688,111 @@ GisOlLayer.prototype = {
|
||||
});
|
||||
|
||||
return source;
|
||||
},
|
||||
/**
|
||||
* 여러 개의 검색 결과를 GeoJSON으로 표시
|
||||
* @param {string} lyrTyNm 레이어 타입명
|
||||
* @param {Array|string} featureIds 피처 ID 배열 또는 단일 ID
|
||||
*/
|
||||
showMultipleSearchResultsFromGeoJSON: function (lyrTyNm, featureIds) {
|
||||
const layer = this.ensureSearchLayer();
|
||||
|
||||
const prev = layer.getSource();
|
||||
if (prev) prev.clear(true);
|
||||
|
||||
const layerCode = GisApp.layerCode;
|
||||
const matched = Object.values(layerCode).find(obj => obj.lyrTyNm === lyrTyNm);
|
||||
layer.set("gobjTy", matched.gobjTy);
|
||||
|
||||
const source = this.getMultiFeatureSourceFromGeoserver(lyrTyNm, featureIds);
|
||||
|
||||
const onLoadEnd = async () => {
|
||||
const feats = source.getFeatures();
|
||||
if (feats && feats.length > 0) {
|
||||
const select = GisApp.Module.select;
|
||||
await select.resetSelectedFeature();
|
||||
for (const feature of feats) select.selectMultiFeature(feature, true);
|
||||
const geometries = feats.map(f => f.getGeometry());
|
||||
if (geometries.length > 0) {
|
||||
const extent = this.combineExtents(geometries.map(g => g?.getExtent()));
|
||||
|
||||
let map = GisApp.Module.core.map;
|
||||
map.getView().fit(extent, {
|
||||
duration: 300,
|
||||
padding: [50, 50, 50, 50],
|
||||
maxZoom: 16
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn('[search-layer] GeoJSON에 피처가 없습니다.');
|
||||
}
|
||||
source.un('featuresloadend', onLoadEnd);
|
||||
source.un('featuresloaderror', onLoadError);
|
||||
};
|
||||
|
||||
const onLoadError = (e) => {
|
||||
console.error('[search-layer] GeoJSON 로드 실패:', e);
|
||||
source.un('featuresloadend', onLoadEnd);
|
||||
source.un('featuresloaderror', onLoadError);
|
||||
};
|
||||
|
||||
source.once('featuresloadend', onLoadEnd);
|
||||
source.once('featuresloaderror', onLoadError);
|
||||
|
||||
layer.setSource(source);
|
||||
|
||||
source.refresh();
|
||||
},
|
||||
/**
|
||||
* 피쳐 ID로 지오서버에서 검색해서 여러개 피처의 벡터소스를 리턴
|
||||
* @param {} lyrTyNm
|
||||
* @param {*} featureId
|
||||
* @returns
|
||||
*/
|
||||
getMultiFeatureSourceFromGeoserver: function (lyrTyNm, featureId) {
|
||||
|
||||
const typeName = this.storageNm + lyrTyNm;
|
||||
const srsName = GisApp.TO_PROJ;
|
||||
const baseUrl = GisApp.GEOSERVER_URL;
|
||||
|
||||
const ids = Array.isArray(featureId) ? featureId : [featureId];
|
||||
|
||||
const source = new VectorSource({
|
||||
format: new GeoJSON(),
|
||||
url: () => {
|
||||
const params = new URLSearchParams({
|
||||
SERVICE: 'WFS',
|
||||
VERSION: '1.1.0',
|
||||
REQUEST: 'GetFeature',
|
||||
TYPENAME: typeName,
|
||||
SRSNAME: srsName,
|
||||
OUTPUTFORMAT: 'application/json',
|
||||
FEATUREID: ids.join(','),
|
||||
});
|
||||
return `${baseUrl}?${params.toString()}`;
|
||||
},
|
||||
strategy: all,
|
||||
});
|
||||
|
||||
return source;
|
||||
},
|
||||
/**
|
||||
* 여러 extent 배열을 받아 결합된 extent를 반환
|
||||
* @param {Array<Array<number>>} extents [[minX,minY,maxX,maxY], ...]
|
||||
* @returns {Array<number>|null}
|
||||
*/
|
||||
combineExtents: function (extents) {
|
||||
if (!extents || extents.length === 0) return null;
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
for (const e of extents) {
|
||||
if (!e || e.length < 4) continue;
|
||||
minX = Math.min(minX, e[0]);
|
||||
minY = Math.min(minY, e[1]);
|
||||
maxX = Math.max(maxX, e[2]);
|
||||
maxY = Math.max(maxY, e[3]);
|
||||
}
|
||||
if (!isFinite(minX) || !isFinite(minY) || !isFinite(maxX) || !isFinite(maxY)) return null;
|
||||
return [minX, minY, maxX, maxY];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,47 +1,48 @@
|
||||
import { Input } from "@common/components";
|
||||
import { AsYouType } from "libphonenumber-js";
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import type { ControllerRenderProps, UseFormReturn } from "react-hook-form";
|
||||
import { FormField } from "../form";
|
||||
import { FormUi } from "../form_ui";
|
||||
import { SelectBox } from "../select";
|
||||
import { SdmSearchForm } from "./sdmNameBox";
|
||||
import SearchInputAddress from "../search_input_address";
|
||||
import type { addressType } from "../search_input_address/findAddress";
|
||||
|
||||
// 수요처 정보
|
||||
export type DemandCompType = {
|
||||
index : number | '';
|
||||
dmdInfoId : string | '';
|
||||
bzmnNo : string | '';
|
||||
dmdCoNm : string | '';
|
||||
daddr : string | '';
|
||||
telno : string | '';
|
||||
rgtr : string | '';
|
||||
useUsgCd : string | '';
|
||||
ctpvCd : string | '';
|
||||
sggCd : string | '';
|
||||
dmdAplyPswd : string | '';
|
||||
wntUntprc : number | '';
|
||||
dmndTmng : Date | '';
|
||||
dmndQty : number | '';
|
||||
grssClfg : number | '';
|
||||
tn : number | '';
|
||||
combResdch : number | '';
|
||||
tph : number | '';
|
||||
trbt : number | '';
|
||||
ph : number | '';
|
||||
blgcOxygDmndQnt : number | '';
|
||||
clIonQnt : number | '';
|
||||
smll : number | '';
|
||||
cdtnv : number | '';
|
||||
crmty : number | '';
|
||||
rmrk : string | '';
|
||||
reqDt : string | '';
|
||||
}
|
||||
|
||||
index: number | "";
|
||||
dmdInfoId: string | "";
|
||||
bzmnNo: string | "";
|
||||
dmdCoNm: string | "";
|
||||
daddr: string | "";
|
||||
telno: string | "";
|
||||
rgtr: string | "";
|
||||
useUsgCd: string | "";
|
||||
ctpvCd: string | "";
|
||||
sggCd: string | "";
|
||||
dmdAplyPswd: string | "";
|
||||
wntUntprc: number | "";
|
||||
dmndTmng: Date | "";
|
||||
dmndQty: number | "";
|
||||
grssClfg: number | "";
|
||||
tn: number | "";
|
||||
combResdch: number | "";
|
||||
tph: number | "";
|
||||
trbt: number | "";
|
||||
ph: number | "";
|
||||
blgcOxygDmndQnt: number | "";
|
||||
clIonQnt: number | "";
|
||||
smll: number | "";
|
||||
cdtnv: number | "";
|
||||
crmty: number | "";
|
||||
rmrk: string | "";
|
||||
reqDt: string | "";
|
||||
};
|
||||
|
||||
type SelectDataType = {
|
||||
text: string;
|
||||
val: string;
|
||||
text: string;
|
||||
val: string;
|
||||
};
|
||||
|
||||
interface FormSchema {
|
||||
@@ -52,7 +53,7 @@ interface FormSchema {
|
||||
daddr: string;
|
||||
telno: string;
|
||||
bznmTotNo?: string;
|
||||
rgtr?: string | '';
|
||||
rgtr?: string | "";
|
||||
dmdAplyPswd?: string;
|
||||
dmdAplyPswdConfirm?: string;
|
||||
}
|
||||
@@ -65,38 +66,50 @@ interface SdmRegFormProps {
|
||||
dataList: DemandCompType[];
|
||||
rtnValue: (searchText: string, pageCnt: number) => void;
|
||||
setIsDuplicate: (value: boolean) => void;
|
||||
updateList?:DemandCompType
|
||||
readOnly?:boolean
|
||||
updateList?: DemandCompType;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
type FieldComponent = (field: ControllerRenderProps<FormSchema, keyof FormSchema>) => JSX.Element;
|
||||
type FieldComponent = (
|
||||
field: ControllerRenderProps<FormSchema, keyof FormSchema>,
|
||||
) => JSX.Element;
|
||||
|
||||
export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigunData, dataList, rtnValue, setIsDuplicate ,updateList,readOnly}: SdmRegFormProps) {
|
||||
const [sidoValue, setSidoValue] = useState<string>('');
|
||||
const [sigunValue, setSigunValue] = useState<string>('');
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]);
|
||||
export function SdmRegForm({
|
||||
form,
|
||||
onCheckboxChange,
|
||||
selectSidoData,
|
||||
selectSigunData,
|
||||
dataList,
|
||||
rtnValue,
|
||||
setIsDuplicate,
|
||||
updateList,
|
||||
readOnly,
|
||||
}: SdmRegFormProps) {
|
||||
const [sidoValue, setSidoValue] = useState<string>("");
|
||||
const [sigunValue, setSigunValue] = useState<string>("");
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||
{ text: "전체", val: "0" },
|
||||
]);
|
||||
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true);
|
||||
const [orgBznmNo, setOrgBznmNo] = useState<string>('');
|
||||
const [updateCoNm, setUpdateNm] = useState<string >('')
|
||||
const [orgBznmNo, setOrgBznmNo] = useState<string>("");
|
||||
const [updateCoNm, setUpdateNm] = useState<string>("");
|
||||
|
||||
|
||||
|
||||
const formatPhoneNumber = (value:string) => {
|
||||
const formatPhoneNumber = (value: string) => {
|
||||
const input = value;
|
||||
const formatter = new AsYouType("KR");
|
||||
const formatted = formatter.input(input);
|
||||
|
||||
return formatted
|
||||
return formatted;
|
||||
};
|
||||
|
||||
// 사업자등록번호 포맷팅 함수 (3-2-5 형식)
|
||||
const formatBusinessNumber = (value: string) => {
|
||||
// 숫자만 추출
|
||||
const digitsOnly = value.replace(/\D/g, "");
|
||||
|
||||
|
||||
// 10자리까지만 처리
|
||||
const limitedDigits = digitsOnly.slice(0, 10);
|
||||
|
||||
|
||||
// 3-2-5 형식으로 포맷팅
|
||||
if (limitedDigits.length <= 3) {
|
||||
return limitedDigits;
|
||||
@@ -107,136 +120,166 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const initializeSigunData = useCallback((sidoCd: string) => {
|
||||
if (sidoCd === '0') {
|
||||
setSigunValue('0');
|
||||
setFilteredSigunData([{ text: "전체", val: '0' }]);
|
||||
} else {
|
||||
const newFilteredData = [
|
||||
{ text: "전체", val: '0' },
|
||||
...selectSigunData.filter((item: SelectDataType) => item.val.substring(0, 2) === sidoCd)
|
||||
];
|
||||
setSigunValue('0');
|
||||
setFilteredSigunData(newFilteredData);
|
||||
}
|
||||
}, [selectSigunData]);
|
||||
|
||||
const onSelectValue = useCallback((
|
||||
val: string,
|
||||
type: string,
|
||||
field: ControllerRenderProps<FormSchema, keyof FormSchema> | undefined
|
||||
) => {
|
||||
if(!updateList?.dmdInfoId)
|
||||
switch (type) {
|
||||
case "ctpvCd":
|
||||
initializeSigunData(val);
|
||||
setSidoValue(val);
|
||||
field?.onChange(val);
|
||||
form.setValue('dmdInfoId', '');
|
||||
form.setValue('bznmTotNo', '');
|
||||
break;
|
||||
case "sggCd":
|
||||
setSigunValue(val);
|
||||
field?.onChange(val);
|
||||
form.setValue('dmdInfoId', '');
|
||||
form.setValue('bznmTotNo', '');
|
||||
break;
|
||||
}
|
||||
}, [initializeSigunData, form,updateList]);
|
||||
|
||||
const handleCheckboxChange = useCallback((checked: boolean) => {
|
||||
setIsBznmTotNoDisabled(checked);
|
||||
onCheckboxChange?.(checked);
|
||||
}, [onCheckboxChange]);
|
||||
|
||||
const setRtnValue = useCallback((searchText: string, pageCnt: number) => {
|
||||
rtnValue(searchText, pageCnt);
|
||||
}, [rtnValue]);
|
||||
|
||||
const setRtnData = useCallback((item: DemandCompType) => {
|
||||
const rtnCompData = item;
|
||||
|
||||
form.setValue('dmdCoNm', rtnCompData?.dmdCoNm || '');
|
||||
form.setValue('dmdInfoId', rtnCompData?.dmdInfoId.substring(0,10) || '');
|
||||
form.setValue('bznmTotNo', rtnCompData?.dmdInfoId.substring(10,14)==='0000' ? '' : rtnCompData?.dmdInfoId.substring(10,14));
|
||||
|
||||
// 수요처 불러온 후 사업자번호를 바꿀경우를 대비함
|
||||
setOrgBznmNo(rtnCompData?.dmdInfoId);
|
||||
const sidoCd = rtnCompData?.ctpvCd.trim() || '';
|
||||
setSidoValue(sidoCd);
|
||||
form.setValue('ctpvCd', sidoCd);
|
||||
initializeSigunData(sidoCd);
|
||||
|
||||
setTimeout(() => {
|
||||
const sigunCd = rtnCompData?.sggCd.trim() || '';
|
||||
setSigunValue(sigunCd);
|
||||
form.setValue('sggCd', sigunCd);
|
||||
}, 100);
|
||||
|
||||
if(rtnCompData?.dmdInfoId.substring(10,14) === '0000') {
|
||||
handleCheckboxChange(true);
|
||||
} else {
|
||||
handleCheckboxChange(false);
|
||||
}
|
||||
|
||||
form.setValue('daddr', rtnCompData?.daddr || '');
|
||||
form.setValue('telno', rtnCompData?.telno || '');
|
||||
|
||||
// 선택을 했을 때 중복 상태를 true로 설정
|
||||
setIsDuplicate(true);
|
||||
}, [form, handleCheckboxChange, initializeSigunData, setIsDuplicate]);
|
||||
|
||||
const setRtnText = useCallback((text: string) => {
|
||||
form.setValue('dmdCoNm', text);
|
||||
}, [form]);
|
||||
|
||||
const bznNoChange = useCallback((e: React.ChangeEvent<HTMLInputElement>, noType: string, field?: ControllerRenderProps<FormSchema, keyof FormSchema>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
if(noType === 'dmdInfoId') {
|
||||
// 숫자만 추출하여 저장 (포맷팅 제거)
|
||||
const digitsOnly = value.replace(/\D/g, "");
|
||||
|
||||
if(orgBznmNo.substring(0,10) === digitsOnly) {
|
||||
setIsDuplicate(true);
|
||||
const initializeSigunData = useCallback(
|
||||
(sidoCd: string) => {
|
||||
if (sidoCd === "0") {
|
||||
setSigunValue("0");
|
||||
setFilteredSigunData([{ text: "전체", val: "0" }]);
|
||||
} else {
|
||||
setIsDuplicate(false);
|
||||
const newFilteredData = [
|
||||
{ text: "전체", val: "0" },
|
||||
...selectSigunData.filter(
|
||||
(item: SelectDataType) => item.val.substring(0, 2) === sidoCd,
|
||||
),
|
||||
];
|
||||
setSigunValue("0");
|
||||
setFilteredSigunData(newFilteredData);
|
||||
}
|
||||
field?.onChange(digitsOnly);
|
||||
} else {
|
||||
if(orgBznmNo.substring(10,14) === value) {
|
||||
setIsDuplicate(true);
|
||||
} else {
|
||||
setIsDuplicate(false);
|
||||
}
|
||||
field?.onChange(value);
|
||||
}
|
||||
}, [orgBznmNo, setIsDuplicate]);
|
||||
},
|
||||
[selectSigunData],
|
||||
);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
form.setValue('rgtr', '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e');
|
||||
|
||||
if(updateList?.dmdInfoId){
|
||||
form.reset(updateList)
|
||||
if(updateList?.dmdInfoId.slice(10,14) !== '0000') {
|
||||
handleCheckboxChange( false);
|
||||
form.setValue('bznmTotNo', updateList?.dmdInfoId.slice(10,14));
|
||||
} else {
|
||||
handleCheckboxChange( true);
|
||||
const onSelectValue = useCallback(
|
||||
(
|
||||
val: string,
|
||||
type: string,
|
||||
field: ControllerRenderProps<FormSchema, keyof FormSchema> | undefined,
|
||||
) => {
|
||||
if (!updateList?.dmdInfoId)
|
||||
switch (type) {
|
||||
case "ctpvCd":
|
||||
initializeSigunData(val);
|
||||
setSidoValue(val);
|
||||
field?.onChange(val);
|
||||
form.setValue("dmdInfoId", "");
|
||||
form.setValue("bznmTotNo", "");
|
||||
break;
|
||||
case "sggCd":
|
||||
setSigunValue(val);
|
||||
field?.onChange(val);
|
||||
form.setValue("dmdInfoId", "");
|
||||
form.setValue("bznmTotNo", "");
|
||||
break;
|
||||
}
|
||||
form.setValue('dmdInfoId', updateList?.dmdInfoId.slice(0,10));
|
||||
setUpdateNm(updateList?.dmdCoNm)
|
||||
// setSigunValue(updateList?.sggCd)
|
||||
}else{
|
||||
handleCheckboxChange( true);
|
||||
}
|
||||
}, [updateList,form]);
|
||||
},
|
||||
[initializeSigunData, form, updateList],
|
||||
);
|
||||
|
||||
const handleCheckboxChange = useCallback(
|
||||
(checked: boolean) => {
|
||||
setIsBznmTotNoDisabled(checked);
|
||||
onCheckboxChange?.(checked);
|
||||
},
|
||||
[onCheckboxChange],
|
||||
);
|
||||
|
||||
const setRtnValue = useCallback(
|
||||
(searchText: string, pageCnt: number) => {
|
||||
rtnValue(searchText, pageCnt);
|
||||
},
|
||||
[rtnValue],
|
||||
);
|
||||
|
||||
const setRtnData = useCallback(
|
||||
(item: DemandCompType) => {
|
||||
const rtnCompData = item;
|
||||
|
||||
form.setValue("dmdCoNm", rtnCompData?.dmdCoNm || "");
|
||||
form.setValue("dmdInfoId", rtnCompData?.dmdInfoId.substring(0, 10) || "");
|
||||
form.setValue(
|
||||
"bznmTotNo",
|
||||
rtnCompData?.dmdInfoId.substring(10, 14) === "0000"
|
||||
? ""
|
||||
: rtnCompData?.dmdInfoId.substring(10, 14),
|
||||
);
|
||||
|
||||
// 수요처 불러온 후 사업자번호를 바꿀경우를 대비함
|
||||
setOrgBznmNo(rtnCompData?.dmdInfoId);
|
||||
const sidoCd = rtnCompData?.ctpvCd.trim() || "";
|
||||
setSidoValue(sidoCd);
|
||||
form.setValue("ctpvCd", sidoCd);
|
||||
initializeSigunData(sidoCd);
|
||||
|
||||
setTimeout(() => {
|
||||
const sigunCd = rtnCompData?.sggCd.trim() || "";
|
||||
setSigunValue(sigunCd);
|
||||
form.setValue("sggCd", sigunCd);
|
||||
}, 100);
|
||||
|
||||
if (rtnCompData?.dmdInfoId.substring(10, 14) === "0000") {
|
||||
handleCheckboxChange(true);
|
||||
} else {
|
||||
handleCheckboxChange(false);
|
||||
}
|
||||
|
||||
form.setValue("daddr", rtnCompData?.daddr || "");
|
||||
form.setValue("telno", rtnCompData?.telno || "");
|
||||
|
||||
// 선택을 했을 때 중복 상태를 true로 설정
|
||||
setIsDuplicate(true);
|
||||
},
|
||||
[form, handleCheckboxChange, initializeSigunData, setIsDuplicate],
|
||||
);
|
||||
|
||||
const setRtnText = useCallback(
|
||||
(text: string) => {
|
||||
form.setValue("dmdCoNm", text);
|
||||
},
|
||||
[form],
|
||||
);
|
||||
|
||||
const bznNoChange = useCallback(
|
||||
(
|
||||
e: React.ChangeEvent<HTMLInputElement>,
|
||||
noType: string,
|
||||
field?: ControllerRenderProps<FormSchema, keyof FormSchema>,
|
||||
) => {
|
||||
const value = e.target.value;
|
||||
|
||||
if (noType === "dmdInfoId") {
|
||||
// 숫자만 추출하여 저장 (포맷팅 제거)
|
||||
const digitsOnly = value.replace(/\D/g, "");
|
||||
|
||||
if (orgBznmNo.substring(0, 10) === digitsOnly) {
|
||||
setIsDuplicate(true);
|
||||
} else {
|
||||
setIsDuplicate(false);
|
||||
}
|
||||
field?.onChange(digitsOnly);
|
||||
} else {
|
||||
if (orgBznmNo.substring(10, 14) === value) {
|
||||
setIsDuplicate(true);
|
||||
} else {
|
||||
setIsDuplicate(false);
|
||||
}
|
||||
field?.onChange(value);
|
||||
}
|
||||
},
|
||||
[orgBznmNo, setIsDuplicate],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
console.log( 'form.formState.errors ', form.formState.errors)
|
||||
},[form.formState.errors])
|
||||
form.setValue("rgtr", "2d4b151d-1828-41e0-91d9-4cd28ea1cc7e");
|
||||
|
||||
if (updateList?.dmdInfoId) {
|
||||
form.reset(updateList);
|
||||
if (updateList?.dmdInfoId.slice(10, 14) !== "0000") {
|
||||
handleCheckboxChange(false);
|
||||
form.setValue("bznmTotNo", updateList?.dmdInfoId.slice(10, 14));
|
||||
} else {
|
||||
handleCheckboxChange(true);
|
||||
}
|
||||
form.setValue("dmdInfoId", updateList?.dmdInfoId.slice(0, 10));
|
||||
setUpdateNm(updateList?.dmdCoNm);
|
||||
// setSigunValue(updateList?.sggCd)
|
||||
} else {
|
||||
handleCheckboxChange(true);
|
||||
}
|
||||
}, [updateList, form]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("form.formState.errors ", form.formState.errors);
|
||||
}, [form.formState.errors]);
|
||||
|
||||
const formFields: Array<{
|
||||
name: keyof FormSchema;
|
||||
@@ -246,53 +289,64 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
|
||||
{
|
||||
name: "ctpvCd",
|
||||
label: "시도",
|
||||
component: (field) => (
|
||||
component: (field) =>
|
||||
updateList?.dmdInfoId ? (
|
||||
<Input
|
||||
placeholder="시도"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) =>{field.onChange(e.target.value)} }
|
||||
value={ selectSidoData.find(item => item.val === field.value?.trim() )?.text??''}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={
|
||||
selectSidoData.find((item) => item.val === field.value?.trim())
|
||||
?.text ?? ""
|
||||
}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
) : (
|
||||
<SelectBox
|
||||
selectClass={undefined}
|
||||
label=""
|
||||
selectArray={selectSidoData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), 'ctpvCd', field??'')}
|
||||
className=""
|
||||
value={sidoValue}
|
||||
/>
|
||||
)
|
||||
)
|
||||
<SelectBox
|
||||
selectClass={undefined}
|
||||
label=""
|
||||
selectArray={selectSidoData}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "ctpvCd", field ?? "")
|
||||
}
|
||||
className=""
|
||||
value={sidoValue}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "sggCd",
|
||||
label: "시군구",
|
||||
component: (field) => (
|
||||
component: (field) =>
|
||||
updateList?.dmdInfoId ? (
|
||||
<Input
|
||||
placeholder="시도"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) =>{field.onChange(e.target.value)} }
|
||||
value={selectSigunData.find(item => item.val === field.value?.trim() )?.text??''}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={
|
||||
selectSigunData.find((item) => item.val === field.value?.trim())
|
||||
?.text ?? ""
|
||||
}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
) : (
|
||||
<SelectBox
|
||||
selectClass={"!text-xl text-gray-600"}
|
||||
label=""
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) => onSelectValue(val.toString(), 'sggCd', field)}
|
||||
className=""
|
||||
value={sigunValue}
|
||||
/>
|
||||
|
||||
)
|
||||
)
|
||||
<SelectBox
|
||||
selectClass={"!text-xl text-gray-600"}
|
||||
label=""
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "sggCd", field)
|
||||
}
|
||||
className=""
|
||||
value={sigunValue}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdCoNm",
|
||||
@@ -308,117 +362,138 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdInfoId",
|
||||
label: "사업자등록번호",
|
||||
component: (field) => (
|
||||
<Input
|
||||
<Input
|
||||
placeholder="사업자등록번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) => bznNoChange(e, 'dmdInfoId', field)}
|
||||
value={formatBusinessNumber(field.value || '')}
|
||||
onChange={(e) => bznNoChange(e, "dmdInfoId", field)}
|
||||
value={formatBusinessNumber(field.value || "")}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "bznmTotNo",
|
||||
label: "",
|
||||
component: (field) => (
|
||||
<FormUi
|
||||
<FormUi
|
||||
label="종사업자등록번호"
|
||||
onCheckboxChange={handleCheckboxChange}
|
||||
isDisabled={isBznmTotNoDisabled}
|
||||
>
|
||||
<Input
|
||||
placeholder="여러사업장이 있을 경우 입력해주세요"
|
||||
<Input
|
||||
placeholder="여러사업장이 있을 경우 입력해주세요"
|
||||
type="text"
|
||||
className="!mt-5 !text-xl text-gray-600"
|
||||
disabled={isBznmTotNoDisabled}
|
||||
onChange={(e) => bznNoChange(e, 'bznmTotNo', field)}
|
||||
// {...field}
|
||||
value={ field.value}
|
||||
onChange={(e) => bznNoChange(e, "bznmTotNo", field)}
|
||||
// {...field}
|
||||
value={field.value}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
</FormUi>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "daddr",
|
||||
label: "사업자주소",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="주소를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
// <Input
|
||||
// placeholder="주소를 입력하세요"
|
||||
// type="text"
|
||||
// className="!text-xl text-gray-600"
|
||||
// readOnly={readOnly}
|
||||
// {...field}
|
||||
// />
|
||||
<SearchInputAddress
|
||||
initValue={undefined}
|
||||
setRtnData={(rtnData: addressType)=> {
|
||||
field.onChange(rtnData.roadAddrPart1);
|
||||
console.log("rtnData ", rtnData);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "telno",
|
||||
label: "전화번호",
|
||||
component: (field) =>
|
||||
|
||||
{
|
||||
const formattedValue = formatPhoneNumber(field.value??''); // 초기 렌더링 시에도 포맷 적용
|
||||
component: (field) => {
|
||||
const formattedValue = formatPhoneNumber(field.value ?? ""); // 초기 렌더링 시에도 포맷 적용
|
||||
|
||||
return (
|
||||
<Input
|
||||
placeholder="전화번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={formattedValue}
|
||||
readOnly={readOnly}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value.replace(/\D/g, ''); // 숫자만 저장
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Input
|
||||
placeholder="전화번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={formattedValue}
|
||||
readOnly={readOnly}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value.replace(/\D/g, ""); // 숫자만 저장
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
name: "dmdAplyPswd",
|
||||
label: "패스워드",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
type="password"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdAplyPswdConfirm",
|
||||
label: "패스워드확인",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
type="password"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
/>
|
||||
)
|
||||
}
|
||||
]
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{formFields
|
||||
.filter(({ name }) => !(updateList?.dmdInfoId && (name === "dmdAplyPswd" || name === "dmdAplyPswdConfirm")))
|
||||
.filter(
|
||||
({ name }) =>
|
||||
!(
|
||||
updateList?.dmdInfoId &&
|
||||
(name === "dmdAplyPswd" || name === "dmdAplyPswdConfirm")
|
||||
),
|
||||
)
|
||||
.map(({ name, label, component }) => {
|
||||
const error = form.formState.errors[name];
|
||||
const inputId = `${name}-input`;
|
||||
const errorId = `${name}-error`;
|
||||
const isRequired = ["ctpvCd", "sggCd", "dmdCoNm", "dmdInfoId", "daddr", "telno", "dmdAplyPswd", "dmdAplyPswdConfirm"].includes(name);
|
||||
const isRequired = [
|
||||
"ctpvCd",
|
||||
"sggCd",
|
||||
"dmdCoNm",
|
||||
"dmdInfoId",
|
||||
"daddr",
|
||||
"telno",
|
||||
"dmdAplyPswd",
|
||||
"dmdAplyPswdConfirm",
|
||||
].includes(name);
|
||||
|
||||
return (
|
||||
<FormField
|
||||
@@ -427,20 +502,27 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<div className="mb-4">
|
||||
<label htmlFor={inputId} className="block text-gray-800 font-medium text-xl">
|
||||
<label
|
||||
htmlFor={inputId}
|
||||
className="block text-xl font-medium text-gray-800"
|
||||
>
|
||||
{label}
|
||||
{isRequired && <span className="text-red-500 ml-1">*</span>}
|
||||
{isRequired && <span className="ml-1 text-red-500">*</span>}
|
||||
</label>
|
||||
|
||||
{React.cloneElement(component(field), {
|
||||
id: inputId,
|
||||
"aria-required": isRequired,
|
||||
"aria-invalid": !!error,
|
||||
"aria-describedby": error ? errorId : undefined
|
||||
"aria-describedby": error ? errorId : undefined,
|
||||
})}
|
||||
|
||||
{error?.message && (
|
||||
<p id={errorId} role="alert" className="text-red-500 text-lg mt-1">
|
||||
<p
|
||||
id={errorId}
|
||||
role="alert"
|
||||
className="mt-1 text-lg text-red-500"
|
||||
>
|
||||
{error.message}
|
||||
</p>
|
||||
)}
|
||||
@@ -451,4 +533,4 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ export default function SdmInsertForm({selectSidoData, selectSigunData, dataList
|
||||
<>
|
||||
<div className="text-center mb-8">
|
||||
<h1 className="text-4xl font-bold text-gray-900 underline">
|
||||
수요처등록
|
||||
{readOnly==true? '수요처 정보':'수요처 등록'}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
const addresssKey = 'devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM='; //인증키 만료일은 2025-11-23
|
||||
|
||||
/**
|
||||
* 주소 API 응답 타입
|
||||
* https://business.juso.go.kr/addrlink/main.do 해당 사이트 참조
|
||||
*/
|
||||
export type AddressApiResponse ={
|
||||
results: {
|
||||
common: {
|
||||
errorMessage: string;
|
||||
countPerPage: string;
|
||||
totalCount: string;
|
||||
errorCode: string;
|
||||
currentPage: string;
|
||||
};
|
||||
juso: addressType[];
|
||||
};
|
||||
}
|
||||
|
||||
export type addressType ={
|
||||
detBdNmList: string;
|
||||
engAddr: string;
|
||||
rn: string;
|
||||
emdNm: string;
|
||||
zipNo: string;
|
||||
roadAddrPart2: string;
|
||||
emdNo: string;
|
||||
sggNm: string;
|
||||
jibunAddr: string;
|
||||
siNm: string;
|
||||
roadAddrPart1: string;
|
||||
bdNm: string;
|
||||
admCd: string;
|
||||
udrtYn: string;
|
||||
lnbrMnnm: string;
|
||||
roadAddr: string;
|
||||
lnbrSlno: string;
|
||||
buldMnnm: string;
|
||||
bdKdcd: string;
|
||||
liNm: string;
|
||||
rnMgtSn: string;
|
||||
mtYn: string;
|
||||
bdMgtSn: string;
|
||||
buldSlno: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 주소에 따른 검색
|
||||
* @param search : 검색어
|
||||
* @returns addressType[] 주소 배열
|
||||
*/
|
||||
export const findAddress = async (search: string) => {
|
||||
if (!search) {
|
||||
return [];
|
||||
}
|
||||
const params = new URLSearchParams({
|
||||
currentPage: "1", // 원하는 페이지
|
||||
countPerPage: "5", // 페이지당 결과 수
|
||||
keyword: search, // 검색어(주소)
|
||||
confmKey: addresssKey, // 인증키 인터넷용 패쇄망용은 따로 발급 필요 즉 middleware에서 치환해서 사용해야할듯
|
||||
resultType: "json", // 결과 형식 기본은 xml
|
||||
});
|
||||
const url = `https://business.juso.go.kr/addrlink/addrLinkApi.do?${params.toString()}`;
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.results && data.results.juso) {
|
||||
return data.results.juso as addressType[];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching address data:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { Input } from "@common/components/ui";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { findAddress, type addressType } from "./findAddress";
|
||||
|
||||
type thisProps = {
|
||||
initValue: string | undefined;
|
||||
setRtnData: (rtnData: addressType) => void;
|
||||
readonly?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param initValue : 초기값 ?
|
||||
* @returns setRtnData => 선택된 주소 데이터 반환
|
||||
*/
|
||||
export default function SearchInputAddress({
|
||||
initValue = undefined,
|
||||
setRtnData = () => {},
|
||||
readonly=false
|
||||
}: thisProps) {
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [textValue, setTextValue] = useState(initValue || "");
|
||||
const [searchList, setSearchList] = useState<addressType[]>([]);
|
||||
|
||||
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const handleInputChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
setTextValue(value);
|
||||
findAddress(value).then((data) => {
|
||||
setSearchList(data);
|
||||
})
|
||||
if (value) {
|
||||
setIsOpen(true);
|
||||
} else {
|
||||
setIsOpen(false);
|
||||
}
|
||||
},
|
||||
[setSearchList]
|
||||
);
|
||||
|
||||
const handleSuggestionClick = useCallback(
|
||||
(roadAddrPart1: string) => {
|
||||
setTextValue(roadAddrPart1);
|
||||
setIsOpen(false);
|
||||
setRtnData(searchList?.find((item) => item.roadAddrPart1 === roadAddrPart1) || ({} as addressType));
|
||||
},
|
||||
[searchList, setRtnData]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
wrapperRef.current &&
|
||||
!wrapperRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} className="relative">
|
||||
<Input
|
||||
type="text"
|
||||
value={textValue}
|
||||
onChange={handleInputChange}
|
||||
/* onFocus={() => setIsOpen(true)} */
|
||||
className="w-full h-[3.2rem] !text-xl pl-3 text-gray-600 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder={`주소를 입력하세요`}
|
||||
readOnly={readonly}
|
||||
/>
|
||||
{isOpen && (
|
||||
<div className="absolute left-0 right-0 mt-2 bg-white border border-gray-300 rounded-md shadow-lg max-h-72 overflow-auto z-50">
|
||||
<div className="max-h-72">
|
||||
{searchList && searchList.length > 0 ? (
|
||||
searchList.map((item: addressType, index: number) => (
|
||||
<div
|
||||
key={index}
|
||||
className="!text-xl w-full text-left px-5 py-3 hover:bg-gray-100 cursor-pointer overflow-auto"
|
||||
onClick={() => handleSuggestionClick(item.roadAddrPart1)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
handleSuggestionClick(item.roadAddrPart1);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.zipNo}
|
||||
<span className="float-right">{item.roadAddrPart1}</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="!text-xl w-full px-5 py-3 hover:bg-gray-100 cursor-pointer overflow-auto">
|
||||
검색 결과가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -137,7 +137,7 @@ export function UiTable({
|
||||
: cellClick
|
||||
? "cursor-pointer"
|
||||
: ""
|
||||
} sticky top-20 z-40 bg-secondary !font-bold`}
|
||||
} sticky top-20 z-40 bg-secondary !font-bold whitespace-pre-line`}
|
||||
style={{ top: `${headerHeight + index * 32 - 4}px` }}
|
||||
onClick={() => handleCellClick(index, head.id)}
|
||||
key={`cell-${head.id}-${index}`}
|
||||
@@ -168,7 +168,7 @@ export function UiTable({
|
||||
: cellClick
|
||||
? "cursor-pointer"
|
||||
: ""
|
||||
} mt-[${boldArray.length * 40}px]`}
|
||||
} mt-[${boldArray.length * 40}px] whitespace-pre-line`}
|
||||
onClick={() => handleCellClick(index, head.id)}
|
||||
key={`cell-${head.id}-${index}`}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user