This commit is contained in:
2025-11-12 14:05:51 +09:00
95 changed files with 1457 additions and 731 deletions
+3 -1
View File
@@ -244,7 +244,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink,
</TableCell>
</TableRow>
<TableRow>
<TableHead>연계서버 IP</TableHead>
<TableHead>
{'link0007' === form.watch('link_clsf_cd') as string ? '연계 파일명 구분자' : '연계서버 IP'}
</TableHead>
<TableCell>
<FormField
control={form.control}
+1 -1
View File
@@ -13,7 +13,7 @@ NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:80
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
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_WR_API_URL= http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service
NEXT_PUBLIC_NGII_URL = http://172.29.143.87
NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x}
@@ -58,7 +58,7 @@ export default function MyForm() {
dataList={demandCompList}
rtnValue={callback}
rtnInputData={handleInsertSdmData}
openNetwork={true}
openNetwork={false}
/>
<Toaster position="top-center" />
</div>
@@ -367,7 +367,7 @@ export default function WrStatusPage() {
<MainChart
chartForm={chartOption.chartForm}
chartConfig={chartOption.chartConfig}
chartData={chartOption.chartData}
chartData={chartOption.chartData?.filter(item=>item.label!= '')}
chartTitle={chartOption.chartTitle}
chartClassName={chartOption.chartClassName}
graphSize={chartOption.graphSize}
@@ -99,7 +99,7 @@ const Map = () => {
if (feature) {
foundFeature = feature;
return;
}
}
}
}
});
@@ -132,6 +132,8 @@ const Map = () => {
},
{ width: 30 }
);
} else {
alert("수요처의 좌표정보를 찾을수 없으므로, 상단 조회조건의 시설명을 입력하여 위치를 조회하시기 바랍니다.");
}
const formatNumber = (val: any) => {
@@ -43,7 +43,7 @@ export const mapService = {
return response.json();
},
getPbnstRuseFclts: async (ruseFcltPk:any) => {
const response = await fetch(`${DEV_URL_WR}/api/v1/reuseFc/pubFc/${ruseFcltPk}`, {
const response = await fetch(`${DEV_URL_WR}/reuseFc/pubFc/${ruseFcltPk}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
@@ -896,7 +896,7 @@ export function SdmInfoRegForm({
<div className="relative flex-1 min-w-0">
<Input
type="text"
className="w-full pr-16 border py-2 text-right rounded-md"
className="w-full pr-16 border py-2 rounded-md"
placeholder=""
onChange={(e) => {
field.onChange(e.target.value);
+1
View File
@@ -15,6 +15,7 @@ NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com/dc-service
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
#NEXT_PUBLIC_SERVER_API_URL = http://localhost:8883/operation-service
+13 -4
View File
@@ -9,9 +9,18 @@ import {
export async function POST() {
const cookieStore = await cookies();
cookieStore.delete(ACCESS_TOKEN);
cookieStore.delete(REFRESH_TOKEN);
cookieStore.delete(AUTH_USER_ID);
cookieStore.delete(CLAIM_NAME);
const cookieOptions = {
httpOnly: true,
sameSite: "lax" as const,
path: "/",
maxAge: 0, // 즉시 만료
};
cookieStore.set(ACCESS_TOKEN, "", cookieOptions);
cookieStore.set(REFRESH_TOKEN, "", cookieOptions);
cookieStore.set(AUTH_USER_ID, "", cookieOptions);
cookieStore.set(CLAIM_NAME, "", cookieOptions);
return NextResponse.json({ message: "Logged out" }, { status: 200 });
}
+12
View File
@@ -0,0 +1,12 @@
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const hostname = request.nextUrl.hostname;
const redirectUrl = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "https://queen.hasuon.or.kr";
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") {
return NextResponse.redirect(new URL("/", request.url)); // 로컬 및 개발 환경
} else {
return NextResponse.redirect(new URL(redirectUrl)); // 공단 환경
}
}
@@ -16,7 +16,7 @@ export default function CalcRainEffect(data : any, weather='ALL') {
for(let idx = 0; idx < data.length; idx++) {
const item = data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay) >= 3) {
if(item.infoRnDay && Number(item.infoRnDay) >= 3) { // 강우량이 3 이상인 경우
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
@@ -49,11 +49,13 @@ export default function CalcRainEffect(data : any, weather='ALL') {
for(let idx = 0; idx < data.length; idx++) {
if(data[idx] && data[idx]?.rainEffectDay === 1) {
if(idx > 1){
// 전날 비가 왔고 오늘 강우량 3미만인 경우 전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전날 강우량으로 설정
if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.toBeInfoRnDay = data[idx-1]!.infoRnDay;
}
}
if(idx > 2){
// 전전날 비가 왔고 오늘 강우량 3미만인 경우 전전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전전날 강우량으로 설정
if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.toBeInfoRnDay = data[idx-2]!.infoRnDay;
}
+1 -1
View File
@@ -15,7 +15,7 @@ export default function Home() {
async function doLogin() {
try {
await LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" });
window.location.href = "/pages/dashboard";
location.href = "/pages/dashboard";
} catch (err) {
console.error("로그인 실패", err);
}
@@ -145,71 +145,74 @@ export default function DashBoard() {
const excelDownload = () => {
if (!fcltyList.bscFctCd) return;
switch (activeTab) {
case 'facilityInfo':
searchOperationStatus(false, searchYear, fcltyList.bscFctCd);
searchOperationStatus(false, searchYear, fcltyList.bscFctCd).then(() => {setTimeout(() => {makeExcelData();}, 200);});
fetch(`/mainDashBoard.xlsx`, {}).then(async (response) => {
if (!response.ok) {
throw Error(response.statusText);
}
// 받은 파일 바인너리 처리
const blobRet = await response.arrayBuffer();
const excelData1 = planFcltyList.map((item) => {
return [
item.item,
Number(item.provisionalApproval.toString().replaceAll(',',''))?Number(item.provisionalApproval.toString().replaceAll(',','')):item.provisionalApproval,
item.now,
item.stepOne,
item.stepTwo,
item.stepThree,
item.stepFour,
];
});
// operationalStatusList를 2차원 배열로 변환
const excelData2 = operationalStatusList.map((item, index) => {
const baseData = [
Number(item.yearAvg?.replaceAll(',','')),
Number(item.yearMax?.replaceAll(',','')),
Number(item.yearMin?.replaceAll(',','')),
Number(item.summerAll?.replaceAll(',','')),
Number(item.summerThree?.replaceAll(',','')),
Number(item.summerRain?.replaceAll(',','')),
Number(item.winterAll?.replaceAll(',','')),
Number(item.winterSunnyAvg?.replaceAll(',','')),
Number(item.winterSunnyMax?.replaceAll(',','')),
Number(item.winterSunnyMin?.replaceAll(',','')),
Number(item.groundWaterAvg?.replaceAll(',','').replaceAll('%','')),
Number(item.groundWaterSummer?.replaceAll(',','').replaceAll('%','')),
Number(item.groundWaterWinter?.replaceAll(',','').replaceAll('%',''))
];
// index가 0일 때만 rdi와 rdiRain 추가
console.log(item.rdiRain);
return index === 0 ? [...baseData, item.rdi&&item.rdi.toString().trim()!=''?Number(item.rdi.toString().replaceAll(',','')):'', item.rdiRain&&item.rdiRain.toString().trim()!=''?Number(item.rdiRain.toString().replaceAll(',','')):''] : baseData;
});
const sheetParameter = [
{
data: excelData1,
headerNum: 3,
headerRange: 'A1:G2',
sheetName: '운영실태',
startCol: 'A'
},
{
data: excelData2,
headerNum: 4,
headerRange: 'A1:Q3',
sheetName: '운영실태',
startCol: 'C'
const makeExcelData = async () => {
fetch(`/mainDashBoard.xlsx`, {}).then(async (response) => {
if (!response.ok) {
throw Error(response.statusText);
}
];
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter);
});
// 받은 파일 바인너리 처리
const blobRet = await response.arrayBuffer();
const excelData1 = planFcltyList.map((item) => {
return [
item.item,
item.provisionalApproval?Number(item.provisionalApproval.toString().replaceAll(',',''))?Number(item.provisionalApproval.toString().replaceAll(',','')):item.provisionalApproval:'',
item.now,
item.stepOne,
item.stepTwo,
item.stepThree,
item.stepFour,
];
});
// operationalStatusList를 2차원 배열로 변환
const excelData2 = operationalStatusList.map((item, index) => {
console.log(item.yearAvg+' '+item.yearMax+' '+item.yearMin);
const baseData = [
Number(item.yearAvg?.toString().replaceAll(',','')),
Number(item.yearMax?.toString().replaceAll(',','')),
Number(item.yearMin?.toString().replaceAll(',','')),
Number(item.summerAll?.toString().replaceAll(',','')),
Number(item.summerThree?.toString().replaceAll(',','')),
Number(item.summerRain?.toString().replaceAll(',','')),
Number(item.winterAll?.toString().replaceAll(',','')),
Number(item.winterSunnyAvg?.toString().replaceAll(',','')),
Number(item.winterSunnyMax?.toString().replaceAll(',','')),
Number(item.winterSunnyMin?.toString().replaceAll(',','')),
Number(item.groundWaterAvg?.toString().replaceAll(',','').replaceAll('%','')),
Number(item.groundWaterSummer?.toString().replaceAll(',','').replaceAll('%','')),
Number(item.groundWaterWinter?.toString().replaceAll(',','').replaceAll('%',''))
];
// index가 0일 때만 rdi와 rdiRain 추가
return index === 0 ? [...baseData, item.rdi&&item.rdi.toString().trim()!=''?Number(item.rdi.toString().replaceAll(',','')):'', item.rdiRain&&item.rdiRain.toString().trim()!=''?Number(item.rdiRain.toString().replaceAll(',','')):''] : baseData;
});
const sheetParameter = [
{
data: excelData1,
headerNum: 3,
headerRange: 'A1:G2',
sheetName: '운영실태',
startCol: 'A'
},
{
data: excelData2,
headerNum: 4,
headerRange: 'A1:Q3',
sheetName: '운영실태',
startCol: 'C'
}
];
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter);
});
};
break;
case 'mainGraph':
@@ -9,7 +9,7 @@ import CommaToNumber from "@/app/components/common/CommaToNumber";
import { roundNumber } from "@/app/components/common/DataForm";
import UnderComment from "@/app/components/common/UnderComment";
import { useFoStore } from "@/app/store";
import type { FacilityWaterQltyProps, modalExcelType } from "@/app/store/facilityWaterQlty";
import type { FacilityWaterQltyProps, modalChoinginExcelType, modalExcelType } from "@/app/store/facilityWaterQlty";
import { downloadExcelFormat, UITab, UiTable } from "@common/business_components/ui";
import { Button, TabsContent } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
@@ -51,6 +51,8 @@ const tabList3 = [
];
export default function WaterQualityModal({fcltyName='', facilityCd='', searchYear=new Date().getFullYear().toString()} : ModalProps) {
const [tabName, setTabName] = useState<string>('tab_num1');
// 그리드 관련
const {FacilityWaterQltyModal,
searchFacilityWaterQltyListHist,
@@ -68,6 +70,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
} = FacilityWaterQltyModal;
const prevExcelListRef = useRef<modalExcelType[] | null>(null);
const prevChoinginExcelListRef = useRef<modalChoinginExcelType[] | null>(null);
// 필터링 된 후 최대, 최소, 평균 값 계산
const setFilterAfterData = (filteredData: FacilityWaterQltyProps[]) => {
@@ -351,43 +354,76 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
}, []);
const excelDownload = () => {
const excelDownList: modalExcelType[] = [];
if(copyYearList.length > 0){
copyYearList.forEach((item) => {
excelDownList.push({
날짜: item.msrDt,
"유입BOD(mg/L)": CommaToNumber(item.inflAssctBfrWqltBod),
"유입TOC(COD)(mg/L)": CommaToNumber(item.inflAssctBfrWqltToc),
"유입SS(mg/L)": CommaToNumber(item.inflAssctBfrWqltSs),
"유입TN(mg/L)": CommaToNumber(item.inflAssctBfrWqltTn),
"유입TP(mg/L)": CommaToNumber(item.inflAssctBfrWqltTp),
"유출BOD(mg/L)": CommaToNumber(item.efflWqltBod),
"유출TOC(COD)(mg/L)": CommaToNumber(item.efflWqltToc),
"유출SS(mg/L)": CommaToNumber(item.efflWqltSs),
"유출TN(mg/L)": CommaToNumber(item.efflWqltTn),
"유출TP(mg/L)": CommaToNumber(item.efflWqltTp),
"강우량(mm/일)": CommaToNumber(item.infoRnDay?item.infoRnDay.toString():"0.0"),
if(tabName === 'tab_num1'){
const excelDownList: modalExcelType[] = [];
if(copyYearList.length > 0){
copyYearList.forEach((item) => {
excelDownList.push({
날짜: item.msrDt,
"유입BOD(mg/L)": CommaToNumber(item.inflAssctBfrWqltBod),
"유입TOC(COD)(mg/L)": CommaToNumber(item.inflAssctBfrWqltToc),
"유입SS(mg/L)": CommaToNumber(item.inflAssctBfrWqltSs),
"유입TN(mg/L)": CommaToNumber(item.inflAssctBfrWqltTn),
"유입TP(mg/L)": CommaToNumber(item.inflAssctBfrWqltTp),
"유출BOD(mg/L)": CommaToNumber(item.efflWqltBod),
"유출TOC(COD)(mg/L)": CommaToNumber(item.efflWqltToc),
"유출SS(mg/L)": CommaToNumber(item.efflWqltSs),
"유출TN(mg/L)": CommaToNumber(item.efflWqltTn),
"유출TP(mg/L)": CommaToNumber(item.efflWqltTp),
"강우량(mm/일)": CommaToNumber(item.infoRnDay?item.infoRnDay.toString():"0.0"),
});
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcelFormat(
{ data: JSON.parse(JSON.stringify(excelDownList))
, fileName: searchYear+'년 '+fcltyName + ' 수질현황'
, sheetNameArray: [fcltyName + ' 수질현황']
, headerRange: 'A1:L1'
, decimalArray1: [1,2,3,6,7,8,11]
, decimalArray3: [4,5,9,10]
}
if (excelDownList && excelDownList.length > 0) {
downloadExcelFormat(
{ data: JSON.parse(JSON.stringify(excelDownList))
, fileName: searchYear+'년 '+fcltyName + ' 수질현황'
, sheetNameArray: [fcltyName + ' 수질현황']
, headerRange: 'A1:L1'
, decimalArray1: [1,2,3,6,7,8,11]
, decimalArray3: [4,5,9,10]
});
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
prevExcelListRef.current = excelDownList;
}else{
const excelDownList: modalChoinginExcelType[] = [];
if(chongInWaterQltyYearList.length > 0){
chongInWaterQltyYearList.forEach((item) => {
excelDownList.push({
날짜: item.msrDt,
"유입BOD(mg/L)": CommaToNumber(item.tpInflWqltBod),
"유입TP(mg/L)": CommaToNumber(item.tpInflWqltTp),
"유출BOD(mg/L)": CommaToNumber(item.efflWqltBod),
"유출TP(mg/L)": CommaToNumber(item.efflWqltTn),
});
});
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
if (excelDownList && excelDownList.length > 0) {
downloadExcelFormat(
{ data: JSON.parse(JSON.stringify(excelDownList))
, fileName: searchYear+'년 '+fcltyName + ' 총인설비수질현황'
, sheetNameArray: [fcltyName + ' 총인설비수질현황']
, headerRange: 'A1:E1'
, decimalArray1: [1,3]
, decimalArray3: [2,4]
});
} else if (prevChoinginExcelListRef.current && prevChoinginExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
prevChoinginExcelListRef.current = excelDownList;
}
prevExcelListRef.current = excelDownList;
}
useEffect(() => {
setTabName("tab_num1");
}, []);
return (
<>
<UITab tabList={tabList1} defaultValue="tab_num1">
<UITab tabList={tabList1} defaultValue="tab_num1" onValueChange={(value) => setTabName(value)}>
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownload}>
{"엑셀다운로드"}
</Button>
@@ -555,7 +591,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
</TabsContent>
{/* 총인설비 수질현황 */}
<TabsContent value="tab_num2">
<TabsContent value="tab_num2" >
<UITab tabList={tabList3} defaultValue="tab_term_year_chongin">
<TabsContent value="tab_term_year_chongin">
<FacilityTermModalHeader<FacilityWaterQltyProps>
@@ -48,7 +48,8 @@ export default function ProcessFacilitySearch() {
} = FacilityWaterQltyMain;
const mainList: FacilityWaterQltyProps[] = facilityWaterQltyList || [];
const [initTrigger, setInitTrigger] = useState<boolean>(false);
const [excelTrigger, setExcelTrigger] = useState<boolean>(false);
// 그리드 관련
const [resetPage, setResetPage] = useState<boolean>(false);
const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null);
@@ -77,16 +78,15 @@ export default function ProcessFacilitySearch() {
partStr = partValue
break;
default:
if(sidoValue !== '0') nameCd = sidoValue;
if(sidoValue !== '0') nameCd = ref.current.sidoValue!="0"?ref.current.sidoValue:sidoValue;
if(sigunValue !== '0') nameCd = sigunValue;
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
if(partStr ==='G'){
searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue);
}else{
searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchFacilityWaterQltyList, searchYearValue, fcltCpct]);
@@ -105,7 +105,8 @@ export default function ProcessFacilitySearch() {
input.value = "";
}
}
searchFacilityWaterQltyList(1, 10, selectSearchYear[0]?.val || "0");
ref.current.sidoValue = "11";
searchFcltyQltyList(ref.current, 1, 10);
}
// 셀 클릭 시 모달 표시
@@ -125,7 +126,7 @@ export default function ProcessFacilitySearch() {
}
const ref = useRef<ReturnType>({
partValue: '',
sidoValue: '',
sidoValue: '11',
sigunValue: '',
regionValue: '',
unitWaterShedValue: '',
@@ -137,12 +138,17 @@ export default function ProcessFacilitySearch() {
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchFacilityWaterQltyList(1, 10, selectSearchYear[0]?.val || "0");
if(!initTrigger){
initializeCommonData();
searchFcltyQltyList(ref.current, 1, 10);
setInitTrigger(true);
}
}
}, [isInit, initializeCommonData, searchFacilityWaterQltyList, selectSearchYear]);
}, [isInit, initializeCommonData, searchFacilityWaterQltyList, searchFcltyQltyList, initTrigger]);
useEffect(() => {
if(!excelTrigger) return;
if (excelList && excelList.length > 0) {
downloadExcelFormat(
{
@@ -154,15 +160,8 @@ export default function ProcessFacilitySearch() {
decimalArray3:[13,14,18,19]
}
);
/* downloadExcel({
data: excelList as unknown as JSON[],
fileName: '시설별 수질현황',
sheetNameArray: ['시설별 수질현황'],
headerRange: 'A1:T1'
}); */
}
}, [excelList]);
}, [excelList, excelTrigger]);
const chkVal = useCallback((returntype:ReturnType) => {
setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]")
@@ -171,6 +170,7 @@ export default function ProcessFacilitySearch() {
}, [upHeadList1, upHeadList2, upHeadList3]);
const excelDownload = useCallback(() => {
setExcelTrigger(true);
searchFcltyQltyList(ref.current, 1, 10000);
}, [searchFcltyQltyList]);
@@ -202,12 +202,12 @@ export default function ProcessFacilitySearch() {
queryClick={chkVal}
excelClick={excelDownload}
initClick={resetVal}
ref={ref} isAdmin={false} />
ref={ref} isAdmin={false} initSidoValue={"11"}/>
<ListDiv>
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total<10?facilityWaterQltyList.length:total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
</div>
</ListDiv>
@@ -25,6 +25,8 @@ const tabList = [
{ value: 'tab_term_rain', label: '강우시' }
];
const commentArray = "[미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)]";
export default function FlowRateModal(props: { fcltyName: string; facilityCd: string; searchYear: string }) {
// 그리드 관련
const { Common, FlowRateModal, searchFlowRateModalList } = useFoStore((state) => state);
@@ -192,12 +194,13 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
"연계처리량(m³/일)": CommaToNumber(item.sumFlow),
"총인반류수량(m³/일)": CommaToNumber(item.returnAmnt),
"방류량(m³/일)": CommaToNumber(item.efflAmnt),
/* "강우량(mm/일)": item.infoRnDay, */
"미처리하수 추정량(m³/일)": CommaToNumber(item.noProcessInflAmnt),
"강우량(mm/일)": CommaToNumber(item.infoRnDay),
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:G1' });
downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:H1' });
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
@@ -233,6 +236,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
boldArray={[0,1,2]}
/>
</div>
<div className="mt-20">
<UnderComment commentArray={[commentArray]} />
</div>
</TabsContent>
<TabsContent value="tab_term_summer">
<FacilityTermModalHeader<FlowRateModalInterface>
@@ -257,6 +263,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
boldArray={[0,1,2]}
/>
</div>
<div className="mt-20">
<UnderComment commentArray={[commentArray]} />
</div>
</TabsContent>
<TabsContent value="tab_term_winter">
<FacilityTermModalHeader<FlowRateModalInterface>
@@ -281,6 +290,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
boldArray={[0,1,2]}
/>
</div>
<div className="mt-20">
<UnderComment commentArray={[commentArray]} />
</div>
</TabsContent>
<TabsContent value="tab_term_chuncheon">
<FacilityTermModalHeader<FlowRateModalInterface>
@@ -305,6 +317,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
boldArray={[0,1,2]}
/>
</div>
<div className="mt-20">
<UnderComment commentArray={[commentArray]} />
</div>
</TabsContent>
<TabsContent value="tab_term_rain">
<FacilityTermModalHeader<FlowRateModalInterface>
@@ -319,7 +334,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
<div className="h-[370px] overflow-y-auto overflow-x-hidden">
<UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}/>
</div>
<UnderComment commentArray={["강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} />
<div className="mt-20">
<UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)","강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} />
</div>
</TabsContent>
</UITab>
</>
@@ -67,9 +67,12 @@ export default function ProcessFacilitySearch() {
const [selectedRow, setSelectedRow] = useState<number | null>(null);
const [fcltyNm, setFcltyNm] = useState<string>("");
const [fcltyCd, setFcltyCd] = useState<string>("");
const [excelTrigger, setExcelTrigger] = useState<boolean>(false);
const [initTrigger, setInitTrigger] = useState<boolean>(false);
const searchFlowRate = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
let nameCd, partStr
let nameCd, partStr;
switch (partValue) {
case 'R':
if (regionValue !== '0') {
@@ -77,20 +80,20 @@ export default function ProcessFacilitySearch() {
else if (middleRegionValue==='0') nameCd = unitWaterShedValue;
else nameCd = middleRegionValue;
}
partStr = partValue
partStr = partValue;
break;
default:
if(sidoValue !== '0') nameCd = sidoValue;
if(sidoValue !== '0') nameCd = ref.current.sidoValue!="0"?ref.current.sidoValue:sidoValue;
if(sigunValue !== '0') nameCd = sigunValue;
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
if(partStr==='G'){
searchFlowRateList(pageNo, pageCnt, searchYearValue);
}else{
searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchFlowRateList, searchYearValue, fcltCpct]);
}, [searchFlowRateList, searchYearValue, fcltCpct, operationValue, fcltyName]);
const resetVal = () => {
setWidthSize("w-[120%]");
@@ -107,7 +110,8 @@ export default function ProcessFacilitySearch() {
input.value = "";
}
}
searchFlowRateList(1, 10, selectSearchYear[0]?.val || "0");
ref.current.sidoValue = '11';
searchFlowRate(ref.current,1, 10);
}
// 셀 클릭 시 모달 표시
@@ -133,23 +137,29 @@ export default function ProcessFacilitySearch() {
// 시도 데이터 초기화
useEffect(() => {
if(!isInit) {
initializeCommonData();
searchFlowRateList(1, 10, selectSearchYear[0]?.val || "0");
if(!initTrigger){
initializeCommonData();
searchFlowRate(ref.current, 1, 10);
setInitTrigger(true);
}
//searchFlowRateList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchFlowRateList, selectSearchYear]);
}, [isInit, initializeCommonData, searchFlowRateList, selectSearchYear, searchFlowRate, initTrigger]);
useEffect(() => {
if(!excelTrigger) return;
if (excelList && excelList.length > 0) {
downloadExcelFormat({ data: JSON.parse(JSON.stringify(excelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1', decimalArray0: [9,10,11,12,13,14] });
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
prevExcelListRef.current = excelList;
}, [excelList]);
}, [excelList, excelTrigger]);
const ref = useRef<ReturnType>({
partValue: '',
sidoValue: '',
sidoValue: '11',
sigunValue: '',
regionValue: '',
unitWaterShedValue: '',
@@ -167,10 +177,10 @@ export default function ProcessFacilitySearch() {
const excelDownload = useCallback(() => {
searchFlowRate(ref.current, 1, 10000);
setExcelTrigger(true);
}, [searchFlowRate]);
const total = flowRateCount;
return (
<MainDiv>
<Title title="시설별 유량현황" />
@@ -193,7 +203,7 @@ export default function ProcessFacilitySearch() {
queryClick={chkVal}
excelClick={excelDownload}
initClick={resetVal}
ref={ref} isAdmin={false}/>
ref={ref} isAdmin={false} initSidoValue={'11'}/>
<ListDiv>
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
@@ -57,7 +57,7 @@ export default function PlanSewage() {
const ref = useRef<ReturnType>({
partValue: '',
sidoValue: '',
sidoValue: '11',
sigunValue: '',
regionValue: '',
unitWaterShedValue: '',
@@ -86,7 +86,10 @@ export default function PlanSewage() {
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
const [initTrigger, setInitTrigger] = useState<boolean>(false);
const [excelTrigger, setExcelTrigger] = useState<boolean>(false);
/**
* 페이지 함수
*/
@@ -106,20 +109,13 @@ export default function PlanSewage() {
input.value = "";
}
}
searchPlanSewageList(1, 10, selectSearchYear[0]?.val || "0", ref.current.partValue);
ref.current.sidoValue='11';
searchPlanSewage(ref.current, 1, 10);
}
/**
* useEffect
*/
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchPlanSewageList(1, 10, selectSearchYear[0]?.val || "0", ref.current.partValue);
}
}, [isInit, initializeCommonData, searchPlanSewageList, selectSearchYear]);
if(!excelTrigger) return;
useEffect(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
@@ -128,7 +124,7 @@ export default function PlanSewage() {
headerRange: 'A1:M1'
});
}
}, [excelList]);
}, [excelList, excelTrigger]);
/**
* 콜백함수
@@ -146,20 +142,34 @@ export default function PlanSewage() {
partStr = partValue
break;
default:
if(sidoValue !== '0') nameCd = sidoValue;
if(sidoValue !== '0') nameCd = ref.current.sidoValue!="0"?ref.current.sidoValue:sidoValue;
if(sigunValue !== '0') nameCd = sigunValue;
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
// G로 넘기면 데이터가 안떠서 환경청 전체로 넘기면 전체를 추출하기위해서...
if(partStr === 'G'){
partValue = partValue==='G'?'A':partValue;
searchPlanSewageList(pageNo, pageCnt, searchYear, partValue);
}
else{
searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchPlanSewageList, searchYear, fcltCpct]);
/**
* useEffect
*/
useEffect(() => {
if (!isInit) {
if(!initTrigger){
initializeCommonData();
searchPlanSewage(ref.current, 1, 10);
setInitTrigger(true);
}
}
}, [isInit, initializeCommonData, searchPlanSewageList, selectSearchYear, initTrigger, searchPlanSewage]);
const chkVal = useCallback((returntype:ReturnType) => {
setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]")
setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1);
@@ -169,6 +179,7 @@ export default function PlanSewage() {
// 엑셀다운로드
const excelDownload = useCallback((searchReturn: ReturnType) => {
searchPlanSewage(searchReturn, 1, 10000);
setExcelTrigger(true);
}, [searchPlanSewage]);
// 페이지 변경
@@ -201,7 +212,7 @@ export default function PlanSewage() {
queryClick={chkVal}
excelClick={excelDownload}
initClick={resetVal}
ref={ref} isAdmin={false}/>
ref={ref} isAdmin={false} initSidoValue={"11"}/>
<ListDiv>
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
@@ -71,7 +71,7 @@ export default function ProcessArea() {
middleRegionValue: '',
envPartValue: '',
sidoText: '',
sigunText: ''
sigunText: '',
});
const searchProcessArea = useCallback(({ sidoText, sigunText}: ReturnType, pageNo: number, pageCnt:number=20) => {
+30 -22
View File
@@ -14,6 +14,7 @@ import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
const commentArray = [
"적정판단근거 = 하절기(6~8)월 강우일 중 BOD수질이 최저인 일자의 RDII추정량을 기준으로 판단",
"강우시 총 추정유입량 = 청천시 유입하수량 + RDII 추정값",
"주) 처리장 유입부에서 측정된 유량 및 수질조사 자료를 기준으로 산정된 결과임"
]
@@ -83,11 +84,10 @@ export default function Rdi() {
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
// 엑셀 다운로드 트리거
const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false);
useEffect(() => {
console.log(isLoading);
}, [isLoading]);
const [initTrigger, setInitTrigger] = useState<boolean>(false);
/**
* 페이지 함수
*/
@@ -108,29 +108,21 @@ export default function Rdi() {
input.value = "";
}
}
searchRdiList(1, 10, selectSearchYear[0]?.val || "0");
ref.current.sidoValue = "11";
searchRdi(ref.current, 1, 10);
}
/**
* useEffect
*/
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchRdiList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchRdiList, selectSearchYear]);
useEffect(() => {
if(!isInitExcelDownload) return ;
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: 'RDII추정',
sheetNameArray: ['RDII추정'],
headerRange: 'A1:O1'
headerRange: 'A1:R1'
});
}
}, [excelList]);
}, [excelList, isInitExcelDownload]);
/**
* 콜백함수
@@ -153,13 +145,28 @@ export default function Rdi() {
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
if(partStr === 'G'){
searchRdiList(pageNo, pageCnt, searchYear);
}else{
searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchRdiList, searchYear, fcltCpct]);
/**
* useEffect
*/
useEffect(() => {
if (!isInit) {
if(!initTrigger){
initializeCommonData();
searchRdi(ref.current, 1, 10);
setInitTrigger(true);
}
}
}, [isInit, initializeCommonData, searchRdiList, selectSearchYear, searchRdi, initTrigger]);
const chkVal = useCallback((returntype:ReturnType) => {
setWidthSize(returntype.partValue=='A' ?"w-[130%]":"w-[150%]")
setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1);
@@ -168,7 +175,8 @@ export default function Rdi() {
// 엑셀다운로드
const excelDownload = useCallback(() => {
searchRdi(ref.current, 1, 10000);
searchRdi(ref.current, 1, 5000);
setIsInitExcelDownload(true);
}, [searchRdi]);
// 페이지 변경
@@ -202,7 +210,7 @@ export default function Rdi() {
queryClick={chkVal}
excelClick={excelDownload}
initClick={resetVal}
ref={ref} isAdmin={false} />
ref={ref} isAdmin={false} initSidoValue={"11"}/>
<ListDiv>
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
@@ -21,7 +21,6 @@ export default function PlanSewage() {
,SewageOccurSearch
,initializeCommonData
,searchSewageOccurList
,resetExcelList
} = useFoStore((state) => state) || {
Common: { isInit: false, selectUpdownData: [], selectOperationData: [], selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" },
SewageOccur: { sewageOccurList: [], sewageOccurCount: 0, excelList: [], upHeadList1: [], upHeadList2: [], upHeadList3: [] },
@@ -95,6 +94,8 @@ export default function PlanSewage() {
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
// 엑셀다운로드 트리거
const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false);
/**
* 페이지 함수
@@ -136,14 +137,15 @@ export default function PlanSewage() {
* useEffect
*/
useEffect(() => {
resetExcelList();
if (!isInit) {
initializeCommonData();
searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchSewageOccurList]);
}, [isInit, initializeCommonData, searchSewageOccurList, selectSearchYear]);
useEffect(() => {
if(!isInitExcelDownload) return ;
const timer = setTimeout(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
@@ -156,7 +158,7 @@ export default function PlanSewage() {
}, 500); // 약간의 지연을 두고 다운로드 실행
return () => clearTimeout(timer);
}, [excelList, isInit]);
}, [excelList, isInit, isInitExcelDownload]);
/**
* 콜백함수
@@ -194,12 +196,9 @@ export default function PlanSewage() {
// 엑셀다운로드
const excelDownload = useCallback(() => {
searchFacilityPrecipitation(ref.current, 1, sewageOccurCount);
setTimeout(() => {
resetExcelList()
}, 1000); // 약간의 지연을 두고 초기화 (다운로드 완료 후)
}, [searchFacilityPrecipitation, sewageOccurCount]);
searchFacilityPrecipitation(ref.current, 1, 5000);
setIsInitExcelDownload(true);
}, [searchFacilityPrecipitation]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -0,0 +1,22 @@
"use client";
import React from "react";
export default function TestPage() {
const handleFindUser = () => {
fetch('/operation-service/api/v1/fclt/flow/1/10/2024', {
method: "GET",
}).then((data) => {
console.log(data);
});
};
return (
<div className="text-4xl">
<span>여기를 click</span>
<button onClick={handleFindUser} className="bg-blue-500 hover:bg-blue-700 text-white">
버튼
</button>
</div>
);
}
@@ -15,6 +15,12 @@ import { useCallback, useEffect, useRef, useState } from "react";
import UnderWaterInputModal from "./modal/page";
import type { UnderWaterProps } from "@/app/store/underWaterInput/types";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
const commentArray = [
"적정여부(=연간 지하수유입량/연평균 유입하수량*100)가 20%이하면 “적정”으로 표출, 그 이상은 “초과유입”으로 표출",
"지하수 유입량 = 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율)"
]
export default function UnderWaterInput() {
const {Common
@@ -22,7 +28,6 @@ export default function UnderWaterInput() {
,UnderWaterSearch
,initializeCommonData
,searchUnderWaterList
,resetExcelList
} = useFoStore((state) => state) || {
Common: { isInit: false, selectUpdownData: [], selectOperationData: [], selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" },
UnderWater: { underWaterList: [], underWaterCount: 0, excelList: [], upHeadList1: [], upHeadList2: [], upHeadList3: [] },
@@ -94,6 +99,8 @@ export default function UnderWaterInput() {
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
// 엑셀다운로드 트리거
const [isMount, setIsMount] = useState<boolean>(false);
/**
* 페이지 함수
@@ -135,26 +142,27 @@ export default function UnderWaterInput() {
* useEffect
*/
useEffect(() => {
resetExcelList();
if (!isInit) {
initializeCommonData();
searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear, resetExcelList]);
}, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear]);
useEffect(() => {
if(!isMount) return ;
const timer = setTimeout(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: '지하수유입량 추정',
sheetNameArray: ['지하수유입량 추정'],
headerRange: 'A1:V1'
headerRange: 'A1:O1'
});
}
}, 500); // 약간의 지연을 두고 다운로드 실행
}, 1000); // 약간의 지연을 두고 다운로드 실행
return () => clearTimeout(timer);
}, [excelList]);
}, [excelList, isMount]);
/**
* 콜백함수
@@ -179,7 +187,7 @@ export default function UnderWaterInput() {
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
} else {
searchUnderWaterList(pageNo, pageCnt, searchYear);
}
}, [fcltCpct, operationValue, fcltyName, searchUnderWaterList, searchYear]);
@@ -192,12 +200,9 @@ export default function UnderWaterInput() {
// 엑셀다운로드
const excelDownload = useCallback(() => {
searchFacilityPrecipitation(ref.current, 1, underWaterCount);
setTimeout(() => {
resetExcelList();
}, 1000); // 약간의 지연을 두고 다운로드 실행
}, [resetExcelList, searchFacilityPrecipitation, underWaterCount]);
searchFacilityPrecipitation(ref.current, 1, 5000);
setIsMount(true);
}, [searchFacilityPrecipitation]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -239,9 +244,8 @@ export default function UnderWaterInput() {
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"지하수유입량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true}/>
</div>
<UnderComment commentArray={commentArray} />
</div>
<span className="text-2xl text-gray-500">※적정여부 = 연간 지하수유입량/연평균 유입하수량*100 </span><br></br>
<span className="text-2xl text-gray-500">※지하수 유입량 = 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율)</span>
</ListDiv>
</ContentsDiv>
{selectedRow !== null && (
+28 -1
View File
@@ -1,4 +1,4 @@
import { getFetch } from "@/app/components/api";
import { getFetch, postFetch } from "@/app/components/api";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
@@ -15,6 +15,15 @@ export type { TableUpperProps };
/**
* (1) 메인페이지
*/
// RDII 상세 타입
export interface FacilityRdiiDetailProps {
msrDt: string, // 측정일
inflAssctBfrWqltBod: string | '', // 유입연계전수질_BOD(mg/L)
inflAmnt: number | '', // 실제유입량(반류수제거)(m³/일)
infoRnDay: number | string | '', // 강수량 (mm/일)
}
// 시설수질리스트 타입
export interface FacilityWaterQltyProps {
bscFctCd: string,
@@ -118,6 +127,14 @@ export type modalExcelType = {
"강우량(mm/일)": number | '';
}
export type modalChoinginExcelType = {
날짜: string;
"유입BOD(mg/L)": number | '';
"유입TP(mg/L)": number | '';
"유출BOD(mg/L)": number | '';
"유출TP(mg/L)": number | '';
}
/**====================================
* Store - data
====================================*/
@@ -298,6 +315,16 @@ export const fetchFacilityWaterQltyListHist = async (searchYear: string|undefine
return null;
}
};
// 시설정보 RDII 상세 [{BOD - inflAssctBfrWqltBod, 유입유량 inflAmnt, 강우량 infoRnDay, 측정일 msrDt}]
export const fetchFacilityRdiiDetailList = async (searchYear: string|undefined, swtrmtFcltCdList: string[]): Promise<FacilityRdiiDetailProps | null> => {
try {
const res = await postFetch('fo', '/rdii/detail/'+searchYear, swtrmtFcltCdList);
return res;
} catch (error) {
console.error('시설정보 RDII 상세 데이터를 가져오는데 실패했습니다:', error);
return null;
}
};
/**====================================
* Store - export
+3 -3
View File
@@ -59,7 +59,8 @@ export type modalExcelType = {
"연계처리량(m³/일)": number | '',
"총인반류수량(m³/일)": number | '',
"방류량(m³/일)": number | '',
/* "강우량(mm/일)": number | string | '', */
"미처리하수 추정량(m³/일)": number | '',
"강우량(mm/일)": number | string | '',
}
/**
* (2) 모달
@@ -159,7 +160,7 @@ const upHeadListFlowRateModal:TableUpperProps[] = [
{ id: "sumFlow", title: "연계처리량(m³/일)", align:"right"},
{ id: "returnAmnt", title: "총인 반류수량(m³/일)", align:"right"},
{ id: "efflAmnt", title: "방류량(m³/일)", align:"right"},
{ id: "noProcessInflAmnt", title: "미처리하수량(m³/일)", align:"right"},
{ id: "noProcessInflAmnt", title: "미처리하수 추정량(m³/일)", align:"right"},
{ id: "infoRnDay", title: "강우량(mm/일)", align:"right"}
]
@@ -173,7 +174,6 @@ const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: s
try {
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
console.log(url);
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
} catch (error) {
-1
View File
@@ -96,7 +96,6 @@ const planSewageList:PlanSewageProps[] = [
const fetchPlanSewageList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
const tailStr = partCd ? '/'+ partCd + '/' + (nameCd || '0') + '/' + (fcltCpct || '0') + '/' + (operationValue || '0') +'/0'+ (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/prcsFclt/info/plan/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
console.log(url);
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
}
+34 -16
View File
@@ -13,11 +13,12 @@ export type { TableUpperProps };
// 처리구역 리스트
export type ProcessAreaProps = {
swtrmtFcltCd : string,
sido : string,
gugun : string,
ctpvNm?: string,
sggNm?: string,
swtrmtFcltNm : string,
location : string,
fctCpc : number | '',
fcltCpctSum : number | '',
ruse : boolean,
planYrDt4 : string,
planYr : string,
@@ -129,8 +130,8 @@ const ProcessFacilityLabelArray:string[] = ['구분', '시도', '시군구','용
// 리스트 헤더(행정별)
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", colSpan:2, rowSpan:2, row:0 },
{ id: "sido", title: "시도", upName:"upChangeRe", row:2, widthPercent:4 },
{ id: "sigungo", title: "시군구", upName:"upChangeRe", row:2, widthPercent:4 },
{ id: "ctpvNm", title: "시도", upName:"upChangeRe", row:2, widthPercent:4 },
{ id: "sggNm", title: "시군구", upName:"upChangeRe", row:2, widthPercent:4 },
{ id: "swtrmtFcltNm", title: "시설명", rowSpan:3, row:0, widthPercent: 8 },
{ id: "location", title: "주소", rowSpan:3, row:0 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", rowSpan:3, row:0, widthPercent: 5 },
@@ -215,7 +216,7 @@ const gridListProcessAreaPlan:ProcessAreaPlanProps[] = [
* Store - API
=====================================*/
// 시설 상세 정보 조회 API
const fetchFacilityDetailInfo = async (swtrmtFcltCd: string) => {
/* const fetchFacilityDetailInfo = async (swtrmtFcltCd: string) => {
try {
const tailUrl = '/1/5/A/0/0/0/SW';
const res = await postFetch('fo', '/prcsFclt/ruseInfo'+tailUrl, [swtrmtFcltCd]);
@@ -224,10 +225,20 @@ const fetchFacilityDetailInfo = async (swtrmtFcltCd: string) => {
console.error('시설정보 데이터를 가져오는데 실패했습니다:', error);
return {data: [], count: 0};
}
}; */
const fetchFacilityDetailInfo = async (pageNo:number, pageSize:number, swtrmtFcltCd: string[]) : Promise<{data:any[], count:number}> => {
try {
const res = await postFetch('fo', '/prcsFclt/ruseInfo/'+pageNo+'/'+pageSize, swtrmtFcltCd);
return {data: res.data, count:res.count};
} catch (error) {
console.error('시설정보 데이터를 가져오는데 실패했습니다:', error);
return {data:[], count:0};
}
};
// 시설정보 리스트 데이터 호출(구분 선택 후 시설명 있을 경우)
const fetchProcessAreaList = async (pageNo : number, pageSize : number, ctpvNm : string | undefined, sggNm : string | undefined, targetYear : string | undefined, set : (fn: (state: ProcessAreaType) => ProcessAreaType) => void): Promise<{data:ProcessAreaProps[], count:number}> => {
const fetchProcessAreaList = async (pageNo : number, pageSize : number, ctpvNm : string | undefined, sggNm : string | undefined, targetYear : string | undefined, set : (fn: (state: ProcessAreaType) => ProcessAreaType) => void): Promise<{data:any[], count:number}> => {
try {
const res = await fetchPlanInfo(targetYear, ctpvNm, sggNm, undefined);
if(res && res.length > 0){
@@ -261,21 +272,27 @@ const fetchProcessAreaList = async (pageNo : number, pageSize : number, ctpvNm :
head.title = '기승인\n4단계';
}
});
const res = await fetchFacilityDetailInfo(item.swtrmtFcltCd);
const detailInfo = res.data.filter((item:ProcessAreaProps) => item.ruse === true);
return {
...item,
sido: detailInfo.length > 0 ? detailInfo[0].sido||'' : '',
sigungo: detailInfo.length > 0 ? detailInfo[0].gugun||'' : '',
location: detailInfo.length > 0 ? detailInfo[0].addr||'' : '',
fctCpc: detailInfo.length > 0 ? detailInfo[0].fctCpc||'' : 0,
trtDstr: detailInfo.length > 0 ? detailInfo[0].trtDstr||'' : '',
};
return item;
})
);
const startIndex = (pageNo - 1) * pageSize;
const endIndex = startIndex + pageSize;
const paginatedData = enrichedData.slice(startIndex, endIndex);
const fcltyCdList : string[]= [];
paginatedData.forEach(item => {
fcltyCdList.push(item.swtrmtFcltCd);
})
const detailFcltylist = await fetchFacilityDetailInfo(1, pageSize, fcltyCdList);
paginatedData.forEach(item => {
const filterdData = detailFcltylist.data.filter(fItem=>fItem.bscFctCd === item.swtrmtFcltCd)[0] || null;
item.fcltCpctSum = filterdData ? filterdData.fctCpc : '';
item.location = filterdData ? filterdData.addr : '';
item.ctpvNm = filterdData ? filterdData.sido : '';
item.sggNm = filterdData ? filterdData.gugun : '';
});
return {data: paginatedData, count: enrichedData.length};
}else{
return {data: [], count: 0};
@@ -375,6 +392,7 @@ export const processAreaReducer:(set:SetStateFunction)=>ProcessAreaActions=(set:
}));
const res = await fetchProcessAreaList(pageNo, pageSize, ctpvNm, sggNm, targetYear, set);
res.data.forEach((item:ProcessAreaProps) => {
item.fctCpc = item.fcltCpctSum;
DataForm({ type: 'float1', column: 'fctCpc', item:item as unknown as Record<string, unknown>});
})
const excelDownList: ExcelType[] = [];
@@ -431,7 +431,6 @@ export const fetchFacilityListInit = async (pageNo:number, pageSize:number, part
}
};
const fetchFacilityList = async (pageNo:number, pageSize:number, partValue?:string, nameCd?:string, fcltCpct?:string, oprtngSttsCd?:string, facilityPartValue?:string, facilityName?:string ): Promise<{data:facilityListProps[], count:number}> => {
try {
const tailStr = partValue ? '/'+ (partValue==='G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + '/' + facilityPartValue + (facilityName && facilityName !== '' ? '/' + facilityName : '') : '';
+127 -84
View File
@@ -1,9 +1,10 @@
import { getFetch } from "@/app/components/api";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
//import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty";
import type { FlowResponse } from "../sewageOccur";
//import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty";
import { fetchFacilityRdiiDetailList } from "../facilityWaterQlty";
//import type { FlowResponse } from "../sewageOccur";
export type { TableUpperProps };
/**====================================
* Store - 타입
@@ -21,16 +22,16 @@ export type RdiProps = {
lclgvrnmntNm : string,
daddr : string,
fctCpc : number,
summerMinBodValue : number,
summerMinBodValue : number | '',
inflAmnt : number | string | '',
winterAvgBodLowRainfall : number,
rdiiValue : number,
infoRnDay : number,
winterAvgBodLowRainfall : number | '',
rdiiValue : number | '',
infoRnDay : number | '',
rgnNm : string,
rvbsn : string,
lgbsn : string,
mdmbsn : string,
rainEffectDay : number, // 강우영향일
rainEffectDay : number | '', // 강우영향일
chungchunFlow : string | number | '',
rainCalInflAmnt : string | number | '',
properYn : string,
@@ -174,6 +175,18 @@ const fetchRdiList = async (pageNo: number, pageSize: number, searchYear: string
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/rdii/list/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
const res = await getFetch('fo', url);
res.data.forEach((item: RdiProps) => {
item.fctCpc = item.fctCpc && item.fctCpc > 0 ? Number(item.fctCpc.toString().trim()) : 0;
item.summerMinBodValue = '';
item.inflAmnt = '';
item.winterAvgBodLowRainfall = '';
item.rdiiValue = '';
item.infoRnDay = '';
item.properYn = '';
item.sido = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
item.sigungo = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
});
return { data: res.data, count: res.count }
}catch(error){
console.log(error);
@@ -185,6 +198,7 @@ const fetchRdiList = async (pageNo: number, pageSize: number, searchYear: string
* Store - expaort
====================================*/
export type RdiActions = {
resetExcelList: () => void;
searchRdiList: (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void;
}
@@ -231,10 +245,31 @@ const dataFormSetting=(item : RdiProps)=> {
// Add type definitions for state setter function
type SetStateFunction = (state: RdiType | ((state: RdiType) => RdiType)) => void;
// 병렬 처리 제한용 헬퍼
// async function processInBatches(items, batchSize, callback) {
// const results:any = [];
// for (let i = 0; i < items.length; i += batchSize) {
// const batch = items.slice(i, i + batchSize);
// const batchResults = await Promise.all(batch.map(callback));
// results.push(...batchResults);
// }
// return results;
// }
export type RdiStore = RdiType & RdiActions;
export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunction) => {
return {
resetExcelList: () => {
set((state: RdiType) => ({
...state,
Rdi: {
...state.Rdi,
excelList: [],
},
}));
},
searchRdiList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
set((state: RdiType) => ({
...state,
@@ -245,44 +280,53 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
}));
const res = await fetchRdiList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm);
const data = res.data;
const reData = await Promise.all(data.map(async (item: RdiProps) => {
const bscFctCd = item.bscFctCd;
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse;
const calData = CalcRainEffect(res2.data, 'SUNNY');
let avgChungcunSumFlow = 0;
let chungcunSumFlow = 0;
calData.forEach((flowItem: any) => {
chungcunSumFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
/* if(flowItem.msrDt.substring(4,6) ==='06' || flowItem.msrDt.substring(4,6) ==='07' || flowItem.msrDt.substring(4,6) ==='08'){
sumSummerChungcunDay += 1;
sumSummerChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
}else if(flowItem.msrDt.substring(4,6) ==='01' || flowItem.msrDt.substring(4,6) ==='02'){
sumWinterChungcunDay += 1;
sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
} */
});
avgChungcunSumFlow = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / calData.length : 0;
item.chungchunFlow = avgChungcunSumFlow;
item.rainCalInflAmnt = Number(avgChungcunSumFlow) + Number(item.rdiiValue);
return item;
}));
if(pageSize>=5000){
set((state: RdiType) => ({
...state,
Rdi: {
...state.Rdi,
excelList: [],
isLoading: true,
},
}));
}
else{
set((state: RdiType) => ({
...state,
Rdi: {
...state.Rdi,
rdiList: res.data,
excelList: [],
rdiCount: res.count,
isLoading: true,
},
}));
}
const excelDownList: ExcelType[] = [];
const rtnData = reData.map((item: RdiProps) => {
const rtnData = res.data.map((item: RdiProps) => {
return {
...item,
sido: item.lclgvrnmntNm.split(' ')[0]?.toString() || '',
sigungo: item.lclgvrnmntNm.split(' ')[1]?.toString() || '',
inflAmnt: item.inflAmnt?Number(item.inflAmnt).toFixed(1): ''
inflAmnt: item.inflAmnt?Number(item.inflAmnt).toFixed(1): '' // 유입유량 (강우량)
}
})
// 청천히 동절기 유입bod를 새로 구하기 위해서 재 호출
const fcltCdList : string[]= [];
rtnData.forEach(item => {
fcltCdList.push(item.bscFctCd);
});
const rdiiDetailListRes : any = await fetchFacilityRdiiDetailList(searchYear, fcltCdList);
console.log(rdiiDetailListRes);
for (const item of rtnData) {
const fcltyCd = item.bscFctCd;
const res: any = await fetchFacilityWaterQltyListHist(searchYear, fcltyCd);
//const fcltyCd = item.bscFctCd;
//const res: any = await fetchFacilityWaterQltyListHist(searchYear, fcltyCd);
//const rdiiDetailList = res.data.wqltObjs;
const rdiiDetailList = rdiiDetailListRes?.data[item.bscFctCd];
//console.log(rdiiDetailListRes);
let rtnWinterInflBod = 0;
let rtnSummerBodInfl = 0;
@@ -291,81 +335,80 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
let rtnRdiRain = 0;
let chungchunFlow = 0;
if (res?.data) {
const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? [];
const rtnWqltData = res.data.wqltObjs;
const wqltDataTot = CalcRainEffect(clone(rtnWqltData));
const wqltDataSunny = CalcRainEffect(clone(rtnWqltData), 'SUNNY');
if (rdiiDetailList) {
let chungchunInfl = 0;
let chungchunInfl = 0; // 청천시 유입
let chungchunCnt = 0;
let minSummerBod = 99999999;
let minSummerBodInfl = 99999999;
let winterCnt = 0;
let winterBodSunny = 0;
let rdiRain = 0;
let rdiRain = 0;
const summerMonth = ['06', '07', '08'];
const winterMonth = ['01', '02'];
wqltDataTot.forEach(item2 => {
if(item2.rainEffectDay == 0){
chungchunCnt ++;
chungchunInfl += Number(item2.inflAmnt);
}
if(summerMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
if(Number(item2.infoRnDay)>=3){
//const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? [];
let rainEffectDay = 0;
rdiiDetailList.forEach(item2 => {
if (item2.infoRnDay == null) item2.infoRnDay = 0;
if(item2.infoRnDay >= 3) {
rainEffectDay = 2;
//강우시
if(summerMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
//하절기
const inflBod = Number(item2.inflAssctBfrWqltBod);
const infl = Number(item2.inflAmnt);
const rain = Number(item2.infoRnDay);
if(inflBod < minSummerBod){
minSummerBodInfl = infl;
minSummerBod = inflBod;
rdiRain = rain;
minSummerBodInfl = infl; // 강우일 하절기 최저 유입 BOD 일때의 유입유량
minSummerBod = inflBod; // 강우일 하절기 최저 유입 BOD
rdiRain = rain; // 강우일 하절기 최저 유입 BOD 일때의 강우량
}
}
}else{
rainEffectDay--;
}
if(rainEffectDay<0){
//청천시
chungchunInfl += item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0;
chungchunCnt ++;
if(winterMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
winterBodSunny += Number(item2.inflAssctBfrWqltBod); // 동절기 청천시 유입BOD 합계
winterCnt += 1;
}
}
});
wqltDataSunny.filter(item=>winterMonth.includes(item.msrDt.toString().replaceAll('-','').substring(4,6))).forEach(item2 => {
winterBodSunny += Number(item2.inflAssctBfrWqltBod);
winterCnt += 1;
});
minSummerBod = minSummerBod === 99999999 ? 0 : minSummerBod;
minSummerBodInfl = minSummerBodInfl === 99999999 ? 0 : minSummerBodInfl;
minSummerBod = minSummerBod === 99999999 ? 0 : minSummerBod; // 강우일 최저 유입 BOD
minSummerBodInfl = minSummerBodInfl === 99999999 ? 0 : minSummerBodInfl; // 강우일 최저 유입 BOD일때 유입유량
const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',',''));
const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',',''));
const roundWinterBodSunny = Number(roundNumber(winterBodSunny, 1).toString().replaceAll(',',''));
console.log('bsccd : ', item.bscFctCd);
console.log('roundMinSummerBodInfl : ',roundMinSummerBodInfl);
console.log('roundMinSummerBod : ',roundMinSummerBod);
console.log('roundWinterBodSunny : ',roundWinterBodSunny);
const winterBodAvg = Number(roundNumber((roundWinterBodSunny / winterCnt), 1).toString().replaceAll(',',''));
// 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD))
const winMinusSum = winterBodAvg - roundMinSummerBod;
const rdiValue = winMinusSum===0 ? 0 : roundMinSummerBodInfl * (winMinusSum / winterBodAvg );
const rdiValue = winMinusSum===0 ? 0 : roundMinSummerBodInfl * (winMinusSum / winterBodAvg ); // RDII 추정
rtnWinterInflBod = winterBodAvg;
rtnSummerBodInfl = minSummerBodInfl;
rtnSummerBod = minSummerBod;
rtnRdiValue = rdiValue;
rtnRdiRain = rdiRain;
chungchunFlow = chungchunInfl == 0? 0 : chungchunInfl / chungchunCnt;
rtnWinterInflBod = winterBodAvg; // 동절기 청천시 유입BOD
rtnSummerBodInfl = minSummerBodInfl; // 하절기(6~8월) 중 최저 유입 BOD일때 유입유량
rtnSummerBod = minSummerBod; // 하절기(6~8월) 중 최저 유입 BOD
rtnRdiValue = rdiValue; // RDII 추정
rtnRdiRain = rdiRain; // RDII 추정시 일강수량
chungchunFlow = chungchunInfl == 0? 0 : chungchunInfl / chungchunCnt; // 청천시 유입하수량
}
item.summerMinBodValue = roundNumber(rtnSummerBod,1);
item.inflAmnt = roundNumber(rtnSummerBodInfl.toString(), 0);
item.winterAvgBodLowRainfall = roundNumber(rtnWinterInflBod, 1);
item.rdiiValue = roundNumber(rtnRdiValue, 0);
item.infoRnDay = roundNumber(rtnRdiRain, 0);
item.chungchunFlow = roundNumber(chungchunFlow, 0);
item.rainCalInflAmnt = roundNumber(Number(item.chungchunFlow.toString().replaceAll(',','')) + Number(item.rdiiValue.toString().replaceAll(',','')), 0);
item.summerMinBodValue = roundNumber(rtnSummerBod,1); // 하절기강우일최저유입BOD(mg/L)
item.inflAmnt = roundNumber(rtnSummerBodInfl.toString(), 0); // 하절기최저유입BOD유입유량(m³/일)
item.winterAvgBodLowRainfall = rtnWinterInflBod?roundNumber(rtnWinterInflBod, 1):0; // 동절기청천시유입BOD(mg/L)
item.rdiiValue = rtnRdiValue?roundNumber(rtnRdiValue, 0):0; // RDII추정
item.infoRnDay = roundNumber(rtnRdiRain, 0); // RDII추정시일강수량(mm)
item.chungchunFlow = roundNumber(chungchunFlow, 0); //청천시유입하수량(m³/일)
item.rainCalInflAmnt = roundNumber(Number(item.chungchunFlow.toString().replaceAll(',',''))
+ Number(item.rdiiValue.toString().replaceAll(',','')), 0) || 0; // 강우시총추정유입량(m³/일)
item.properYn = Number(item.rainCalInflAmnt.toString().replaceAll(',','')) > Number(item.fctCpc.toString().replaceAll(',','')) ? '초과유입' : '적정';
}
@@ -374,7 +417,7 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
dataFormSetting(item);
})
if(pageSize>5000){
if(pageSize>=5000){
rtnData.forEach((item: RdiProps) => {
excelDownList.push({
시설코드: item.bscFctCd,
+7 -16
View File
@@ -148,7 +148,6 @@ const fetchSweageOccurListFlow = async(fcltyCd : string, searchYear : string) =>
* Store - expaort
====================================*/
export type SewageOccurActions = {
resetExcelList: () => void;
searchSewageOccurList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void;
searchSewageOccurDetailList: (bscFctCd: string, searchYear: string, startYearMonth?: string, endYearMonth?: string) => void;
}
@@ -230,24 +229,14 @@ export type FlowResponse = {
export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
return {
resetExcelList: () => {
set((state: SewageOccurType) => ({
...state,
SewageOccur: {
...state.SewageOccur,
excelList: [],
},
}));
},
searchSewageOccurList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm);
if(pageSize < facilityInitData.count){
if(pageSize < 5000){
set((state: SewageOccurType) => ({
...state,
SewageOccur: {
...state.SewageOccur,
sewageOccurList : facilityInitData.data,
sewageOccurList : [],
sewageOccurCount : facilityInitData.count,
excelList : [],
isLoading: true
@@ -265,11 +254,13 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
}
const fcltylist = facilityInitData.data;
const fcltyCount = facilityInitData.count;
const calData = await processInBatches(fcltylist, 20, async (item: SewageOccurProps, index: number) => {
const bscFctCd = item.bscFctCd;
const res = await fetchSweageOccurListFlow(bscFctCd, searchYear);
const res = await fetchSweageOccurListFlow(bscFctCd, searchYear).catch(() => {
console.log('Error fetching flow data for facility code:', bscFctCd);
return { data: [], count: 0 };
});
item.sidoNm = item.sidoNm || '';
item.sggNm = item.sggNm || '';
@@ -306,7 +297,7 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
return {...item, index:index};
});
if(pageSize >= fcltyCount){
if(pageSize >= 5000){
const excelDownList: ExcelType[] = [];
calData.forEach((item: SewageOccurProps) => {
excelDownList.push({
+6 -15
View File
@@ -213,7 +213,6 @@ const fetchUnderWaterListFlow = async(fcltyCd : string, searchYear : string) =>
* Store - expaort
====================================*/
export type UnderWaterActions = {
resetExcelList: () => void;
searchUnderWaterList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void;
unserWaterModal:(bscFctCd:string, searchYear:string, startYm:string, endYm:string)=>void
}
@@ -289,20 +288,10 @@ export type UnderWaterStore = UnderWaterType & UnderWaterActions;
export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterType) => void)=>UnderWaterActions=(set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => {
return {
resetExcelList: () => {
set((state: UnderWaterType) => ({
...state,
UnderWater: {
...state.UnderWater,
excelList : [],
},
}));
},
searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm);
if(pageSize < facilityInitData.count){
if(pageSize < 5000){
set((state: UnderWaterType) => ({
...state,
UnderWater: {
@@ -324,11 +313,13 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
}
const fcltylist = facilityInitData.data;
const fcltyCount = facilityInitData.count;
const calData = await processInBatches(fcltylist, 20, async (item: any, index: number) => {
const bscFctCd = item.bscFctCd;
const res = await fetchUnderWaterListFlow(bscFctCd, searchYear);
const res = await fetchUnderWaterListFlow(bscFctCd, searchYear).catch((error) => {
console.log('Error fetching flow data for facility code:', bscFctCd, error);
return { data: [], count: 0 }; // 에러 발생 시 빈 데이터 반환
});
item.sidoNm = item.sido || '';
item.sggNm = item.gugun || '';
@@ -377,7 +368,7 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
return {...item, index:index};
});
if(pageSize>= fcltyCount){
if(pageSize>= 5000){
const excelDownList: ExcelType[] = [];
calData.forEach((item : any) => {
dataFormSetting(item)
+9 -9
View File
@@ -36,15 +36,15 @@ function rewriteWith(url: string, req: NextRequest, withAuth = false): NextRespo
const headers = withAuth ? buildAuthHeaders(req) : new Headers(req.headers);
if (url.indexOf("/operation-service") !== -1) {
// x-forwarded- 로 시작하는 헤더의 첫 번째 값만 남김
for (const [key, value] of headers.entries()) {
if (key.startsWith('x-forwarded-') && value.includes(',')) {
const first = (value?.split(',')[0] || '').trim();
headers.set(key, first);
}
}
}
// if (url.indexOf("/operation-service") !== -1) {
// // x-forwarded- 로 시작하는 헤더의 첫 번째 값만 남김
// for (const [key, value] of headers.entries()) {
// if (key.startsWith('x-forwarded-') && value.includes(',')) {
// const first = (value?.split(',')[0] || '').trim();
// headers.set(key, first);
// }
// }
// }
return NextResponse.rewrite(new URL(url), { headers });
}
@@ -2,16 +2,18 @@
import { useEffect } from "react";
import { useRouter } from "next/navigation";
//import { usePathname } from "next/navigation";
import { client } from "@/src/shared/api";
import type { IUserInfo } from "@/src/shared/store";
import { useUserStore, getCookie } from "@/src/shared/lib";
import { ENDPOINT, AUTH_USER_ID } from "@/src/shared/config";
import { LoginApi } from "../api/login-service";
// const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3001/auth/login"; // 개발 환경 URL
const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3001/auth/login"; // 개발 환경 URL
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
const router = useRouter();
//const pathname = usePathname();
const { userInfo, setUserInfo } = useUserStore((state) => state);
async function authCheck() {
@@ -40,15 +42,15 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
console.error("Token refresh failed:", refreshError);
setUserInfo(null);
// const hostname = window.location.hostname;
const hostname = location.hostname;
// 개발 환경에서는 localhost 도메인 사용
// if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
router.push("/"); // 개발시 홈으로 돌아가기
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
// if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
if (hostname.includes("hasuon.or.kr")) location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
}
}
})();
@@ -65,7 +65,37 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
size: '3',
});
const result = await getData(`v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`);
let result;
const res = await fetch(`/sewerage-service/api/v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`, {
method: "GET",
});
if (res.ok) {
// 응답이 비어있는지 확인
const contentLength = res.headers.get('content-length');
if (contentLength === '0') result = null;
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
const text = await res.text();
if (!text || text.trim() === '') result = null;
// JSON 파싱 시도
result = JSON.parse(text);
}
// helper: "YYYY-MM-DD HH:MM:SS" -> "MM-DD HH:MM"
const formatNoYearNoSec = (val: any) => {
if (!val && val !== 0) return "-";
const s = String(val);
// 정규식으로 안전하게 매칭 후 변환
const m = s.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})(?::\d{2})?$/);
if (m) {
const [, , mm, dd, hh, min] = m;
return `${mm}-${dd} ${hh}:${min}`;
}
// 포맷이 예상과 다르면, 길이에 따라 잘라보기
if (s.length >= 16) return s.substring(5, 16); // "YYYY-" 제거하고 초 전까지
return s;
};
const processedDataArray: any[] = result.content.map((data: any) => {
// 🎯 formatDisplayData로 기본 포맷팅 적용
@@ -75,6 +105,10 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
return {
...formattedItem,
flwmtrCombined: `${data.flwmtrMesureTpEtc || '-'} / ${data.flwmtrKnd || '-'}`,
mesureBeginDt: data.mesureBeginDt ? formatNoYearNoSec(data.mesureBeginDt) : '-',
mesureEndDt: data.mesureEndDt ? formatNoYearNoSec(data.mesureEndDt) : '-',
qltwtrBeginDt: data.qltwtrBeginDt ? formatNoYearNoSec(data.qltwtrBeginDt) : '-',
qltwtrEndDt: data.qltwtrEndDt ? formatNoYearNoSec(data.qltwtrEndDt) : '-',
};
});
setRainMeasureData(processedDataArray);
@@ -99,7 +133,22 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
size: '3',
});
const result = await getData(`v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs?${queryParams.toString()}`);
let result;
const res = await fetch(`/sewerage-service/api/v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs?${queryParams.toString()}`, {
method: "GET",
});
if (res.ok) {
// 응답이 비어있는지 확인
const contentLength = res.headers.get('content-length');
if (contentLength === '0') result = null;
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
const text = await res.text();
if (!text || text.trim() === '') result = null;
// JSON 파싱 시도
result = JSON.parse(text);
}
// 각 아이템 전처리
const processedDataArray = result.content.map((data: any) => {
@@ -113,10 +113,10 @@ const RdiiChart = ({ pplMngNo }: ModalOpenProp) => {
const rdiiRsltChart = () => { // 그래프 & 팝업 닫기
fetchFilteredData();
fn.selectPplRdiiQty(rainInfwtAnlsSn, pplMngNo).then((data) => {// 강우유입수량 조회
setRdiiQty(Math.round(data.rdiih*24).toLocaleString('ko-KR')); // cmd: m³/d 단위로 변환
if (data.raintotal && data.rainTotal !== 0) {
setRainTotal(data.raintotal.toLocaleString('ko-KR')); // 총강우량mm
setTotalVolume(Math.round(data.rdiih * data.sustaintime / data.raintotal).toLocaleString('ko-KR')); // 총체적 m³/mm
setRdiiQty(Math.round(data?.rdiih*24).toLocaleString('ko-KR')); // cmd: m³/d 단위로 변환
if (data?.raintotal && data?.rainTotal !== 0) {
setRainTotal(data?.raintotal.toLocaleString('ko-KR')); // 총강우량mm
setTotalVolume(Math.round(data?.rdiih * data?.sustaintime / data?.raintotal).toLocaleString('ko-KR')); // 총체적 m³/mm
}
});
setPopupOpen(false);
+19 -2
View File
@@ -43,10 +43,27 @@ const Map = () => {
const fetchData = async () => {
try {
const data = await getData("v1/map/lyrStngs/SN_NETWORK");
let data;
const res = await fetch("/sewerage-service/api/v1/map/lyrStngs/SN_NETWORK", {
method: "GET",
});
if (res.ok) {
// 응답이 비어있는지 확인
const contentLength = res.headers.get('content-length');
if (contentLength === '0') data = null;
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
const text = await res.text();
if (!text || text.trim() === '') data = null;
// JSON 파싱 시도
data = JSON.parse(text);
}
setTreeData(data);
} catch (error) {
console.error("데이터 불러오기 실패:", error);
console.error('JSON parsing error:', error);
// JSON 파싱에 실패한 경우, 원본 텍스트 또는 null 반환
throw new Error('Invalid JSON response from server');
}
};
@@ -1,8 +1,8 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (오른쪽 돋보기 모양 클릭) - 검색 모달 창 내 운영정보 탭
* ➡️ 경로 : 하수관망도 메인 페이지 (오른쪽 돋보기 모양 클릭) - 검색 모달 창 내 유지관리 정보 탭
*
* 📄 Operation Tab
* Next.js App Router (app/) 기반 검색 모달 운영정보 탭 컴포넌트
* Next.js App Router (app/) 기반 검색 모달 유지관리 정보 탭 컴포넌트
*
* - 업무구분 선택 (보수 및 갱신, 점검 및 진단, 청소 및 준설)
* - 사업명 입력 및 수행기간 범위 선택
@@ -4,9 +4,9 @@
* 📄 Search Modal
* Next.js App Router (app/) 기반 검색 모달 컴포넌트
*
* - 탭 기반 검색 인터페이스 (기본정보, 운영정보, 보고서)
* - 탭 기반 검색 인터페이스 (기본정보, 유지관리 정보, 보고서)
* - 테이블 데이터 표시 및 페이지네이션 기능
* - 시설물 조회 결과 및 운영 사업 현황 표시
* - 시설물 조회 결과 및 유지관리 사업 현황 표시
* - 엑셀 다운로드 및 지도에서 보기 기능
* - Zustand를 통한 검색 모달 상태 관리
* - 로딩 오버레이 및 선택 초기화 지원
@@ -72,7 +72,7 @@ const SearchModal: React.FC = () => {
return [];
}
if (activeTab === 'operation') return OPERATION_TABLE_HEADLIST; // 운영정보
if (activeTab === 'operation') return OPERATION_TABLE_HEADLIST; // 유지관리 정보
return [];
}, [activeTab, basicType, workType]);
@@ -118,7 +118,7 @@ const SearchModal: React.FC = () => {
onValueChange={(value: string) => setActiveTab(value)}
/>
{activeTab === 'basic' && (<BasicTab />)} {/* 기본정보 탭 */}
{activeTab === 'operation' && (<OperationTab />)} {/* 운영정보 탭 */}
{activeTab === 'operation' && (<OperationTab />)} {/* 유지관리 정보 탭 */}
{activeTab === 'report' && (<ReportTab open={isSearchModalOpen} />)} {/* 하수도정비기본계획보고서 탭 */}
@@ -153,7 +153,7 @@ const SearchModal: React.FC = () => {
</div>
</div>
)}
{/* 운영정보 탭 */}
{/* 유지관리 정보 탭 */}
{activeTab === 'operation' && (
<>
<div className="h-[39vh] w-full overflow-hidden rounded-lg border">
@@ -1,6 +1,6 @@
/**
* 📄 useOperationTab Hook
* 검색 모달 운영정보 탭 훅
* 검색 모달 유지관리 정보 탭 훅
*
* - 필터링된 사업 현황 데이터 조회 및 포맷팅
* - 사업 현황 테이블 셀 클릭 시 상세 결과표 조회
@@ -11,8 +11,8 @@
* - 데이터 매핑 및 코드 변환 (사업 유형, 용도, 재질 등)
*
* 🔗 사용 API
* - 운영정보 목록 조회: GET /api/v1/bizInfo (sewerage-service)
* - 운영정보(사업정보) 관련 시설 목록 조회: GET /api/v1/bizInfo/fclts (sewerage-service)
* - 유지관리 정보 목록 조회: GET /api/v1/bizInfo (sewerage-service)
* - 유지관리 정보(사업정보) 관련 시설 목록 조회: GET /api/v1/bizInfo/fclts (sewerage-service)
*/
import { downloadExcelWithKoreanHeaders } from '@common/business_components/ui';
import { MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_USE_CODES } from '../components/common/table';
@@ -48,12 +48,12 @@ export default function useOperationTab() {
} = useSearchModalStore();
const { BIZ_TY_CD } = useStore();
const WORK_TYPES = [ // 운영정보 '구분' 선택 목록
const WORK_TYPES = [ // 유지관리 정보 '구분' 선택 목록
{ val: "['200', '201', '204']", text: "보수 및 갱신" },
{ val: "['100']", text: "점검 및 진단" },
{ val: "['203']", text: "청소 및 준설" },
];
const OPERATION_TABLE_HEADLIST = [ // 운영정보 - 사업 현황
const OPERATION_TABLE_HEADLIST = [ // 유지관리 정보 - 사업 현황
{ id: 'rowNumber', title: '일련번호' },
{ id: "bizInfoNm", title: "사업명" },
{ id: "flfmtBgngYmd", title: "수행시작일자" },
@@ -62,7 +62,7 @@ export default function useOperationTab() {
{ id: "bizTypeCd", title: "사업유형" },
{ id: "bizAmt", title: "사업금액" },
];
const MAINTENANACE_TABLE_HEADLIST = [ // 운영정보 - 보수 및 갱신 결과표
const MAINTENANACE_TABLE_HEADLIST = [ // 유지관리 정보 - 보수 및 갱신 결과표
{ id: 'rowNumber', title: '일련번호' },
{ id: "fcltMngNo", title: "관리번호" },
{ id: "swtrmt_zone_nm", title: "처리구역" },
@@ -75,7 +75,7 @@ export default function useOperationTab() {
{ id: "instlYmd", title: "설치일자" },
// { id: "instlYmd", title: "사업구분" },
];
const CLEANING_TABLE_HEADLIST = [ // 운영정보 - 청소 및 준설 결과표
const CLEANING_TABLE_HEADLIST = [ // 유지관리 정보 - 청소 및 준설 결과표
{ id: 'rowNumber', title: '일련번호' },
{ id: "fcltMngNo", title: "관리번호" },
{ id: "swtrmt_zone_nm", title: "처리구역" },
@@ -87,7 +87,7 @@ export default function useOperationTab() {
{ id: "prlgVl", title: "연장(m)" },
{ id: "instlYmd", title: "설치일자" },
];
const INSPECTION_TABLE_HEADLIST = [ // 운영정보 - 점검 및 진단 결과표
const INSPECTION_TABLE_HEADLIST = [ // 유지관리 정보 - 점검 및 진단 결과표
{ id: 'rowNumber', title: '일련번호' },
{ id: "fcltMngNo", title: "관리번호" },
{ id: "swtrmt_zone_nm", title: "처리구역" },
@@ -150,7 +150,7 @@ export default function useOperationTab() {
setDetailTableCount(0);
};
// 운영정보 테이블 cellClick 핸들러
// 유지관리 정보 테이블 cellClick 핸들러
const handleOperationCellClick = async (index?: number | undefined, headId?: String) => {
setIsResetDetailPage(true); // 페이지를 1로 초기화
setIsResetDetailSelection(true); // 선택 초기화
@@ -188,7 +188,7 @@ export default function useOperationTab() {
setDetailTableData(mappedData);
setDetailTableCount(res.count || 0);
} catch (error) {
console.error('운영정보 cellClick 에러:', error);
console.error('유지관리 정보 cellClick 에러:', error);
} finally {
setIsDetailLoading(false);
setIsResetDetailPage(false);
@@ -197,7 +197,7 @@ export default function useOperationTab() {
}
};
// 운영정보 디테일 테이블 cellClick 핸들러
// 유지관리 정보 디테일 테이블 cellClick 핸들러
const handleOperationResultCellClick = async (index?: number | undefined, headId?: String) => {
if (typeof index === "number") {
setIsLoading(true);
@@ -212,7 +212,7 @@ export default function useOperationTab() {
}
};
// 운영정보 디테일 테이블 페이지네이션 핸들러
// 유지관리 정보 디테일 테이블 페이지네이션 핸들러
const handleOperationPageNation = async (index?: number | undefined) => {
if (typeof index === "number") {
setIsDetailLoading(true);
@@ -241,14 +241,14 @@ export default function useOperationTab() {
setDetailTableData(mappedData);
setDetailTableCount(res.count || 0);
} catch (error) {
console.error('운영정보 페이지네이션 에러:', error);
console.error('유지관리 정보 페이지네이션 에러:', error);
} finally {
setIsDetailLoading(false);
}
}
};
// 운영정보 Excel 다운로드 핸들러 추가
// 유지관리 정보 Excel 다운로드 핸들러 추가
const operationExcelDownload = async () => {
if (tableData.length === 0) {
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
@@ -342,7 +342,7 @@ export default function useOperationTab() {
}
};
// 운영정보 결과표 Excel 다운로드 핸들러 추가
// 유지관리 정보 결과표 Excel 다운로드 핸들러 추가
const operationResultExcelDownload = async () => {
if (detailTableData.length === 0) {
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
@@ -2,7 +2,7 @@
* 📄 useSearchModal Hook
* 검색 모달 훅
*
* - 탭 기반 검색 인터페이스 관리 (기본정보, 운영정보, 보고서)
* - 탭 기반 검색 인터페이스 관리 (기본정보, 유지관리 정보, 보고서)
* - 필터링된 데이터 조회 및 포맷팅
* - 조회 버튼을 통한 데이터 검색 트리거
* - 여러 시설 보기 기능
@@ -10,7 +10,7 @@
* - 데이터 매핑 및 코드 변환 (사업 유형 등)
*
* 🔗 사용 API
* - 운영정보 목록 조회: GET /api/v1/bizInfo (sewerage-service)
* - 유지관리 정보 목록 조회: GET /api/v1/bizInfo (sewerage-service)
*/
import { getData } from "@/components/lib/api";
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
@@ -43,9 +43,9 @@ export default function useSearchModal() {
const { BIZ_TY_CD } = useStore();
const TABS = [
{ val: "basic", text: "기본정보" },
{ val: "operation", text: "운영정보" },
{ val: "report", text: "하수도정비기본계획보고서" },
{ val: "basic", text: "기본 정보" },
{ val: "operation", text: "유지관리 정보" },
{ val: "report", text: "하수도 정비 기본계획 보고서" },
];
// 검색 API 호출 함수
@@ -18,7 +18,7 @@
* - RDII분석 삭제: DELETE /api/v1/rdiiAnls/{rainInfwtAnlsSn} (sewerage-service)
*/
'use client'
import { deleteData, getData, useCookieAuth } from '@/components/lib/api'
import { deleteData, getData } from '@/components/lib/api'
import { UiTable, downloadExcelWithKoreanHeaders } from '@common/business_components/ui'
import { zodResolver } from '@hookform/resolvers/zod'
import { useState, useEffect } from 'react'
@@ -66,7 +66,7 @@ const tableColumn = [
]
const Result = () => {
const AUTH = useCookieAuth();
//const AUTH = useCookieAuth();
const form = useForm<ResultFormValues>({
resolver: zodResolver(formSchema),
@@ -133,7 +133,7 @@ const Result = () => {
ctpvCd: ctpvCd !== '0' ? ctpvCd.trim() : null,
sggCd: sggCd !== '0' ? sggCd : null,
swtrmtFcltNm: formValues.swtrmtFcltNm?.trim() ? formValues.swtrmtFcltNm : null,
auth: AUTH,
//auth: AUTH,
};
const queryParams = new URLSearchParams({
@@ -18,7 +18,7 @@
* - 침입수분석 삭제: DELETE /api/v1/inftwtAnls/{inftwtAnlsSn} (sewerage-service)
*/
'use client'
import { deleteData, getData, useCookieAuth } from '@/components/lib/api'
import { deleteData, getData } from '@/components/lib/api'
import { UiTable, downloadExcelWithKoreanHeaders } from '@common/business_components/ui'
import { zodResolver } from '@hookform/resolvers/zod'
import { useState, useEffect } from 'react'
@@ -63,7 +63,7 @@ const tableColumn = [
]
const Result = () => {
const AUTH = useCookieAuth();
//const AUTH = useCookieAuth();
const form = useForm<ResultFormValues>({
resolver: zodResolver(formSchema),
@@ -127,7 +127,7 @@ const Result = () => {
"ctpvCd": ctpvCd === '0' ? null : ctpvCd.trim(),
"sggCd": sggCd === '0' ? null : sggCd,
"swtrmtFcltNm": formValues.swtrmtFcltNm?.trim() ? formValues.swtrmtFcltNm : null,
"auth": AUTH,
//"auth": AUTH,
};
const queryParams = new URLSearchParams({
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* ➡️ 경로 : I/I분석, 운영정보 모든 페이지
* ➡️ 경로 : I/I분석, 유지관리 정보 모든 페이지
*
* 📄 With Base Layout
* Next.js App Router (app/) 기반 분석 페이지 기본 레이아웃 컴포넌트
@@ -1,5 +1,5 @@
/**
* ➡️ 경로 : 운영정보 - 도시침수예방사업
* ➡️ 경로 : 유지관리 정보 - 도시침수예방사업
*
* 📄 FloodPre Page
* 침수예방 사업 정보 등록 및 조회 페이지 컴포넌트
@@ -1,5 +1,5 @@
/**
* ➡️ 경로 : 운영정보 - 노후 하수관로 정비사업
* ➡️ 경로 : 유지관리 정보 - 노후 하수관로 정비사업
*
* 📄 OldPp Page
* 노후 하수관로 정비사업 추진현황 페이지 컴포넌트
+24 -6
View File
@@ -1,5 +1,5 @@
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import { NextRequest, NextResponse } from "next/server";
import {
ACCESS_TOKEN,
AUTH_USER_ID,
@@ -7,11 +7,29 @@ import {
REFRESH_TOKEN,
} from "@/shared/config";
export async function POST() {
export async function POST(request: NextRequest) {
const cookieStore = await cookies();
cookieStore.delete(ACCESS_TOKEN);
cookieStore.delete(REFRESH_TOKEN);
cookieStore.delete(AUTH_USER_ID);
cookieStore.delete(CLAIM_NAME);
// 쿠버네티스 환경: x-forwarded-host 또는 host 헤더에서 실제 도메인 가져오기
const forwardedHost = request.headers.get("x-forwarded-host");
const host = request.headers.get("host");
const actualHost = forwardedHost || host || request.nextUrl.hostname;
// 운영 환경에서 domain 설정
const domain = actualHost.includes("hasuon.or.kr") ? ".hasuon.or.kr" : undefined;
const cookieOptions = {
httpOnly: true,
sameSite: "lax" as const,
path: "/",
maxAge: 0, // 즉시 만료
...(domain && { domain }),
};
cookieStore.set(ACCESS_TOKEN, "", cookieOptions);
cookieStore.set(REFRESH_TOKEN, "", cookieOptions);
cookieStore.set(AUTH_USER_ID, "", cookieOptions);
cookieStore.set(CLAIM_NAME, "", cookieOptions);
return NextResponse.json({ message: "Logged out" }, { status: 200 });
}
+12
View File
@@ -0,0 +1,12 @@
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const hostname = request.nextUrl.hostname;
const redirectUrl = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "https://queen.hasuon.or.kr";
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") {
return NextResponse.redirect(new URL("/", request.url)); // 로컬 및 개발 환경
} else {
return NextResponse.redirect(new URL(redirectUrl)); // 공단 환경
}
}
+7 -4
View File
@@ -34,7 +34,7 @@ export const getData = async (url: string): Promise<any> => {
// JSON 파싱 시도
const data = JSON.parse(text);
return data;
return data.data;
} catch (error) {
console.error('JSON parsing error:', error);
// JSON 파싱에 실패한 경우, 원본 텍스트 또는 null 반환
@@ -55,7 +55,8 @@ export const postData = async (url: string, data: object): Promise<any> => {
const res = await fetch(`${BASE_URL}/${url}`, options);
if (res.ok) {
const resData = await res.json();
return resData;
console.log('postData response:', resData);
return resData.data;
}
};
@@ -63,7 +64,8 @@ export const postMutiPart = async (url: string, data: FormData): Promise<any> =>
const res = await axios.post(`${BASE_URL}/${url}`, data, {
timeout: 600000, // 10분
});
return res.data;
console.log('postMultiPart response:', res);
return res.data.data;
};
export const putData = async (url: string, data: object): Promise<any> => {
@@ -76,7 +78,8 @@ export const putData = async (url: string, data: object): Promise<any> => {
};
const res = await fetch(`${BASE_URL}/${url}`, options);
const resData = await res.json();
return resData;
console.log('putData response:', resData);
return resData.data;
};
export const deleteData = async (url: string, data?: object): Promise<any> => {
+14 -14
View File
@@ -23,23 +23,23 @@ import { useRouter } from "next/navigation";
export default function Home() {
const router = useRouter();
const userId = "CLEANWATER";
const password = "gktneh12!@";
const checkToken = getCookie(AUTH_USER_ID);
useEffect(() => {
if (!checkToken) {
async function doLogin() {
try {
await LoginApi.login({ userId, password });
window.location.href = "/map";
} catch (err) {
console.error("로그인 실패", err);
const hostname = window.location.hostname;
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") {
if (!checkToken) {
async function doLogin() {
try {
await LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" });
window.location.href = "/map";
} catch (err) {
console.error("로그인 실패", err);
}
}
}
doLogin();
} else {
router.push("/map");
}
doLogin();
} else router.push("/map");
} else router.push("/map");
}, []);
}
+1 -1
View File
@@ -3,7 +3,7 @@
* 검색 모달 Zustand 스토어
*
* - 검색 모달 열기/닫기 및 탭 전환 상태 관리
* - 기본정보 및 운영정보 탭 데이터 필터링 및 조회
* - 기본정보 및 유지관리 정보 탭 데이터 필터링 및 조회
* - 테이블 데이터 및 페이지네이션 상태 관리
* - 지역(시도/시군구) 및 날짜 범위 필터링 기능
* - 로딩 상태 및 리셋 플래그 관리
@@ -1,7 +1,7 @@
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useRouter, usePathname } from "next/navigation";
import { client } from "@/shared/api";
import type { IUserInfo } from "@/shared/store";
import { useUserStore } from "@/shared/lib";
@@ -10,10 +10,11 @@ import { getCookie } from "@/shared/lib";
import { LoginApi } from "../api/login-service";
// const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://dev.onasys.co.kr:3000/auth/login"; // 로그인 페이지 URL
const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://dev.onasys.co.kr:3000/auth/login"; // 로그인 페이지 URL
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
const router = useRouter();
const pathname = usePathname();
const { userInfo, setUserInfo } = useUserStore((state) => state);
async function authCheck() {
@@ -42,19 +43,19 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
console.error("Token refresh failed:", refreshError);
setUserInfo(null);
// const hostname = window.location.hostname;
const hostname = window.location.hostname;
// 개발 환경에서는 localhost 도메인 사용
// if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
router.push("/"); // 개발시 홈으로 돌아가기
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
// if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
}
}
})();
}, []);
}, [pathname]);
return <>{children}</>;
};
+2
View File
@@ -14,8 +14,10 @@ NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
#NEXT_PUBLIC_WR_SERVER_API_URL = http://192.168.1.222:8883/reuse-service/api/v1
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
# NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
NEXT_PUBLIC_NGII_PARAM = 04trYP9_xwLAfALjwZ-B8g&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={x}&tilerow={y}
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
NEXT_PUBLIC_FINDADRESS_URL = https://business.juso.go.kr/addrlink/addrLinkApi.do
NEXT_PRIVATE_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
@@ -77,7 +77,7 @@ export default function CoMatRvw() {
{} as DmdCoReqType
);
const [selectionVersion, setSelectionVersion] = useState(0);
const bottomRef = useRef<HTMLDivElement | null>(null);
//수요 매칭 검색
@@ -111,6 +111,7 @@ export default function CoMatRvw() {
if (coMatRvwRes && coMatRvwRes[index]) {
setSelectData(coMatRvwRes[index]);
setSelectionVersion((v) => v + 1); // 행을 클릭할 때마다 버전을 1씩 증가
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}
};
const useUsgCdWatch = useWatch({ control: form.control, name: "useUsgCd" });
@@ -294,12 +295,16 @@ export default function CoMatRvw() {
setPageNatiion(val);
}}
></UiTable>
<div ref={bottomRef} />
</ListDiv>
<hr />
<br /><hr />
<br />
{/* <ScrollArea className="h-[49vh]"> */}
<ListDiv>
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
<div className="card-header flex items-center justify-between">
<h3 className="text-2xl font-medium text-label">수요신청 상세현황</h3>
</div>
<h3 className="mt-4 ml-2 text-2xl font-medium text-label" >
</h3>
<Form {...form}>
<div className="grid grid-cols-12 gap-4 ml-4 mr-4">
@@ -46,6 +46,7 @@ export default function CoSttn() {
coSttnTxtSearch,
demandCompList,
coSttnPwInit,
getMyUUID
} = useWrStore((state) => state);
const { regAuthrtYn, mdfcnAuthrtYn } = auth;
@@ -278,7 +279,12 @@ export default function CoSttn() {
headlist={coSttn.coSttHeadList}
pageSize={20}
total={coSttnResCount + 10 || 0}
cellClick={(index: number | undefined) => {
cellClick={ async(index: number | undefined) => {
const uuid = await getMyUUID();
const updateData = coSttnRes[index as number];
if (updateData && typeof uuid === "string") {
updateData.mdfr = uuid;
}
setUpdateData(coSttnRes[index as number]);
}}
onPageChange={(page) => {
@@ -322,6 +328,7 @@ export default function CoSttn() {
isMoal: false,
data: data as DemandCompType,
});
setIsResetSelection(true);
} else {
const dmd = await getFetch(
fetchType.WR,
@@ -36,10 +36,11 @@ export default function Home() {
const [htdflForm, setHtdflForm] = useState<customHtdflBdst>();
const [bdstTable, setbdstTable] = useState<customHtdflBdst[]>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [resetPageNo, setResetPageNo] = useState<boolean>(false);
const { htdflRes, htdflResCount } = htdfl;
const { regAuthrtYn, mdfcnAuthrtYn, laeSeCd } = auth;
const { htdflRes, htdflResCount, htdfTableIndex } = htdfl;
const useInitRef = useRef(false);
const { regAuthrtYn, mdfcnAuthrtYn, laeSeCd } = auth;
useEffect(() => {
getLaeSeCdCheck();
@@ -65,6 +66,8 @@ export default function Home() {
return {
...item,
archArea: archArea,
cityText: item.ctpvCd === 0 ? "세종특별자치시" : (item as any).cityText,
sggText: (item as any).sggText === "없음" ? "-" : (item as any).sggText,
};
}
);
@@ -74,17 +77,27 @@ export default function Home() {
}
}, [code, htdflRes]);
const cellClick: (val: number, headId: string) => void = (val) => {
if (!htdflRes || !Array.isArray(htdflRes)) return;
const idx = Number(val);
console.log('htdflRes[idx]', htdflRes[idx]);
setHtdflForm(htdflRes[idx]);
};
const cellClick: (val: number) => void = (val) => {
if (!htdflRes || !Array.isArray(htdflRes)) return;
const idx = Number(val);
setHtdflForm(htdflRes[idx]);
setResetPageNo(false);
};
useEffect(() => {
getHtdflBdstData(pageNation, "0");
getHtdflBdstData(pageNation, laeSeCd);
setResetPageNo(false);
}, [pageNation]);
useEffect(() => {
if (typeof htdfTableIndex === "number" && htdfTableIndex >= 0) {
console.log('htdfTableIndex ', htdfTableIndex)
cellClick(htdfTableIndex);
setResetPageNo(true);
}
}, [htdfTableIndex]);
return (
<>
<ContentsDiv>
@@ -138,12 +151,14 @@ const cellClick: (val: number, headId: string) => void = (val) => {
pageSize={20}
total={htdflResCount}
headName={"시설물 목록"}
cellClick={(val, headId) => {
cellClick={(val) => {
if (val !== null && val !== undefined) {
cellClick(val, headId);
cellClick(val);
}
}}
onPageChange={setPageNation}
index={htdfTableIndex}
resetPageNo={resetPageNo}
></UiTable>
</ListDiv>
</div>
@@ -12,7 +12,7 @@ export const makeFcltRegHead = (upHeadList: TableUpperProps[]) => {
</TableHead>
) : head.upName === "upChangeRe" && head.upSequnce === 1 ? (
<TableHead key={head.id} rowSpan={1} colSpan={3}>
{"중축 개축 재축 "}
{"증축 개축 재축 "}
</TableHead>
) : null
)}
@@ -48,14 +48,14 @@ export default function Home() {
const { regAuthrtYn, mdfcnAuthrtYn, laeSeCd } = auth;
const { rainRes, rainResCount } = rain;
const { rainRes, rainResCount ,rainTableIndex} = rain;
const useInitRef = useRef(false);
const [rainForm, setRainForm] = useState<customRainBdst>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [pageNation, setPageNation] = useState(1);
const [bdstTable, setbdstTable] = useState<customRainBdst[]>();
const [searchTxt, setSearchTxt] = useState<string>();
const [resetPageNo, setResetPageNo] = useState<boolean>(false);
useEffect(() => {
getLaeSeCdCheck();
useInitRef.current = true;
@@ -78,10 +78,12 @@ export default function Home() {
archArea: formatArchArea(item?.archArea, 1),
bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N",
frstArchPrmsnDt: item?.frstArchPrmsnDt || "확인불가",
cityText: item.ctpvCd === 0 ? "세종특별자치시" : (item as any).cityText,
sggText: (item as any).sggText === "없음" ? "-" : (item as any).sggText,
};
}
);
console.log("rainData", rainData);
setbdstTable(rainData);
} else {
setbdstTable([]);
@@ -91,13 +93,23 @@ export default function Home() {
const cellClick: (val: number | undefined) => void = (val) => {
if (val !== undefined) {
setRainForm(rainRes[val]);
setResetPageNo(false);
}
};
useEffect(() => {
getRainData(pageNation, laeSeCd);
setResetPageNo(false);
}, [pageNation]);
useEffect(() => {
if (typeof rainTableIndex === 'number' && rainTableIndex >= 0) {
cellClick(rainTableIndex);
setResetPageNo(true);
}
}, [rainTableIndex]);
return (
<>
<ContentsDiv>
@@ -157,6 +169,8 @@ export default function Home() {
cellClick(val);
}}
onPageChange={setPageNation}
index={rainTableIndex}
resetPageNo={resetPageNo}
></UiTable>
{/* </ScrollArea> */}
</ListDiv>
@@ -49,7 +49,9 @@ export default function Home() {
const [pageNation, setPageNation] = useState(1);
const [selectVal, setSelect] = useState<number>();
const [bdstTable, setbdstTable] = useState<customRswtBdst[]>();
const { rswtRes, rswtResCount } = rswt;
const [resetPageNo, setResetPageNo] = useState<boolean>(false);
const { rswtRes, rswtResCount ,rswtTableIndex} = rswt;
const useInitRef = useRef(false);
useEffect(() => {
@@ -78,6 +80,8 @@ export default function Home() {
archArea: archArea,
bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N",
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd,
cityText: item.ctpvCd === 0 ? "세종특별자치시" : (item as any).cityText,
sggText: (item as any).sggText === "없음" ? "-" : (item as any).sggText,
};
}
);
@@ -96,20 +100,29 @@ export default function Home() {
}
}, [rswtRes, selectVal]);
const cellClick: (val: number | undefined, headId: string) => void = (
const cellClick: (val: number | undefined) => void = (
val
) => {
if ((bdstTable ?? []).length > 0 && val !== undefined) {
{
setSelect(val);
setResetPageNo(false);
}
}
};
useEffect(() => {
getRswtBdstData(pageNation,laeSeCd);
setResetPageNo(false);
}, [pageNation]);
useEffect(() => {
if (typeof rswtTableIndex === 'number' && rswtTableIndex >= 0) {
cellClick(rswtTableIndex);
setResetPageNo(true);
}
}, [rswtTableIndex]);
return (
<>
<ContentsDiv>
@@ -163,7 +176,8 @@ export default function Home() {
headName={"건축물 목록"}
cellClick={cellClick}
onPageChange={setPageNation}
index={0}
index={rswtTableIndex}
resetPageNo={resetPageNo}
></UiTable>
</ListDiv>
</div>
@@ -209,8 +209,9 @@ export default function PrfmncPrfmncReg() {
useEffect(() => {
const year = new Date().getFullYear();
if(laeSeCd === undefined || laeSeCd ==='') return;
prfmncHasuInit(1, laeSeCd, String(year), prfPbnFclts);
}, [prfPbnFclts]);
}, [prfPbnFclts,laeSeCd]);
useEffect(() => {
if (prfmncRes && prfmncRes.length > 0) {
@@ -1,12 +1,9 @@
"use client";
import { useWrStore } from "@/app/store";
import { commonCd, rainPageSize } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { rainPageSize } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { rswtPageSize } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import {
excelDownload,
yearOptions
} from "@/components/lib/func/commom";
import { excelDownload, yearOptions } from "@/components/lib/func/commom";
import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal";
import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable";
import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable";
@@ -18,7 +15,7 @@ import {
SearchInput,
SelectBox,
Title,
UiModal
UiModal,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label } from "@common/components/ui";
@@ -28,6 +25,7 @@ import { useTranslation } from "react-i18next";
export default function Page() {
const {
auth,
rainChkSttn,
rswtChkSttn,
rainChkSttnInit,
@@ -41,6 +39,7 @@ export default function Page() {
return state;
});
const { laeSeCd } = auth;
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
const [rainPageNation, setRainPageNation] = useState(1);
const [rswtPageNation, setRswtPageNation] = useState(1);
@@ -49,7 +48,9 @@ export default function Page() {
open: false,
data: {},
});
const [searchYear, setSearchYear] = useState<string>(String(new Date().getFullYear()));
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const cellClick = () => {
if (searchYear) {
if (selFcltDiv === "RNB") {
@@ -58,11 +59,11 @@ export default function Page() {
rainPageNation,
rainPageSize,
searchYear,
commonCd,
laeSeCd,
fcltNm
);
} else {
rainChkSttnInit(rainPageNation, rainPageSize, searchYear, commonCd);
rainChkSttnInit(rainPageNation, rainPageSize, searchYear, laeSeCd);
}
} else {
if (fcltNm) {
@@ -70,11 +71,11 @@ export default function Page() {
rswtPageNation,
rswtPageSize,
searchYear,
commonCd,
laeSeCd,
fcltNm
);
} else {
rswtChkSttnInit(rswtPageNation, rswtPageSize, searchYear, commonCd);
rswtChkSttnInit(rswtPageNation, rswtPageSize, searchYear, laeSeCd);
}
}
}
@@ -84,15 +85,9 @@ export default function Page() {
if (pageNo > 0) {
setRainPageNation(pageNo);
if (fcltNm) {
rainChkSttnNmSearch(
pageNo,
rainPageSize,
searchYear,
commonCd,
fcltNm
);
rainChkSttnNmSearch(pageNo, rainPageSize, searchYear, laeSeCd, fcltNm);
} else {
rainChkSttnInit(pageNo, rainPageSize, searchYear, commonCd);
rainChkSttnInit(pageNo, rainPageSize, searchYear, laeSeCd);
}
}
};
@@ -101,38 +96,38 @@ export default function Page() {
if (pageNo > 0) {
setRswtPageNation(pageNo);
if (fcltNm) {
rswtChkNmSttnSearch(
pageNo,
rainPageSize,
searchYear,
commonCd,
fcltNm
);
rswtChkNmSttnSearch(pageNo, rainPageSize, searchYear, laeSeCd, fcltNm);
} else {
rswtChkSttnInit(pageNo, rswtPageSize, searchYear, commonCd);
rswtChkSttnInit(pageNo, rswtPageSize, searchYear, laeSeCd);
}
}
};
useEffect(() => {
if (!rainChkSttn.isInit) {
isRainSttn(true)
rainChkSttnInit(1, rainPageSize, new Date().getFullYear().toString(), commonCd);
isRainSttn(true);
rainChkSttnInit(
1,
rainPageSize,
new Date().getFullYear().toString(),
laeSeCd
);
setIsModal({ data: {}, open: false });
}
}, [rainChkSttn.isInit, rainChkSttnInit, rainPageSize]);
useEffect(() => {
if (!rswtChkSttn.isInit) {
setIsModal({ data: {}, open: false });
rswtChkSttnInit(1, rswtPageSize, new Date().getFullYear().toString(), commonCd);
isRswtSttn(true)
rswtChkSttnInit(
1,
rswtPageSize,
new Date().getFullYear().toString(),
laeSeCd
);
isRswtSttn(true);
}
}, [rswtChkSttn.isInit, rswtChkSttnInit, rswtPageSize])
}, [rswtChkSttn.isInit, rswtChkSttnInit, rswtPageSize]);
const handleClick = useCallback(
(data: any) => {
@@ -140,11 +135,14 @@ export default function Page() {
},
[isModal]
);
const { t } = useTranslation('base');
const { t } = useTranslation("base");
const excelDown = () => {
if (rainChkSttn.sttnExcelList && selFcltDiv === "RNB") {
if (!rainChkSttn.sttnExcelList || rainChkSttn.sttnExcelList.length === 0) {
toast.error(t('excelDownErrMsg'));
if (
!rainChkSttn.sttnExcelList ||
rainChkSttn.sttnExcelList.length === 0
) {
toast.error(t("excelDownErrMsg"));
return;
}
excelDownload(
@@ -155,8 +153,11 @@ export default function Page() {
3
);
} else if (rswtChkSttn.sttnExcelList && selFcltDiv === "RST") {
if (!rswtChkSttn.sttnExcelList || rswtChkSttn.sttnExcelList.length === 0) {
toast.error(t('excelDownErrMsg'));
if (
!rswtChkSttn.sttnExcelList ||
rswtChkSttn.sttnExcelList.length === 0
) {
toast.error(t("excelDownErrMsg"));
return;
}
excelDownload(
@@ -167,7 +168,7 @@ export default function Page() {
3
);
}
}
};
return (
<ContentsDiv>
@@ -177,7 +178,9 @@ export default function Page() {
<SearchDiv>
<SearchFormLeft>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-48 mt-2 text-xl text-gray-600">{'지도점검년도'}</Label>
<Label className="w-48 mt-2 text-xl text-gray-600">
{"지도점검년도"}
</Label>
<SelectBox
className="w-full h-full text-2xl"
label=""
@@ -190,7 +193,9 @@ export default function Page() {
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">{'시설구분'}</Label>
<Label className="w-28 mt-2 text-xl text-gray-600">
{"시설구분"}
</Label>
<SelectBox
className={"w-full h-full text-2xl"}
label={""}
@@ -198,9 +203,8 @@ export default function Page() {
selectArray={rainChkSttn.fcltDiv}
onSelectValue={(val: string | number) => {
if (val === "RST") rswtChkPolInit();
setSelFcltDiv(String(val))
}
}
setSelFcltDiv(String(val));
}}
value={selFcltDiv ?? rainChkSttn.fcltDiv[0]?.val}
/>
</div>
@@ -227,7 +231,13 @@ export default function Page() {
>
조회
</Button>
<Button color="green" size={"sm"} onClick={() => { excelDown() }}>
<Button
color="green"
size={"sm"}
onClick={() => {
excelDown();
}}
>
다운로드
</Button>
</div>
@@ -241,8 +251,8 @@ export default function Page() {
<ListDiv>
{selFcltDiv === "RNB" ? (
<RainChkgdTable
deleteData={() => { }}
detailUp={() => { }}
deleteData={() => {}}
detailUp={() => {}}
handleClick={handleClick}
rainChkData={rainChkSttn.rainChkRes}
pageNation={rainPageNation}
@@ -252,8 +262,8 @@ export default function Page() {
/>
) : (
<RswtChkgdTable
detaiRswtlUpdate={() => { }}
deleteRswtData={() => { }}
detaiRswtlUpdate={() => {}}
deleteRswtData={() => {}}
handleRswtClick={handleClick}
rswtChkData={rswtChkSttn.rswtChkRes}
pageNation={rswtPageNation}
@@ -271,7 +281,14 @@ export default function Page() {
setIsModal({ open: !open, data: {} });
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal readonly={true} type={selFcltDiv} obj={isModal.data} setIsModal={() => { }} />}
body={
<ChkgdModal
readonly={true}
type={selFcltDiv}
obj={isModal.data}
setIsModal={() => {}}
/>
}
></UiModal>
<Toaster position="top-center" />
</ContentsDiv>
+13 -4
View File
@@ -9,9 +9,18 @@ import {
export async function POST() {
const cookieStore = await cookies();
cookieStore.delete(ACCESS_TOKEN);
cookieStore.delete(REFRESH_TOKEN);
cookieStore.delete(AUTH_USER_ID);
cookieStore.delete(CLAIM_NAME);
const cookieOptions = {
httpOnly: true,
sameSite: "lax" as const,
path: "/",
maxAge: 0, // 즉시 만료
};
cookieStore.set(ACCESS_TOKEN, "", cookieOptions);
cookieStore.set(REFRESH_TOKEN, "", cookieOptions);
cookieStore.set(AUTH_USER_ID, "", cookieOptions);
cookieStore.set(CLAIM_NAME, "", cookieOptions);
return NextResponse.json({ message: "Logged out" }, { status: 200 });
}
+12
View File
@@ -0,0 +1,12 @@
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const hostname = request.nextUrl.hostname;
const redirectUrl = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "https://queen.hasuon.or.kr";
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") {
return NextResponse.redirect(new URL("/", request.url)); // 로컬 및 개발 환경
} else {
return NextResponse.redirect(new URL(redirectUrl)); // 공단 환경
}
}
+14 -14
View File
@@ -9,23 +9,23 @@ import { useRouter } from "next/navigation";
export default function Home() {
const router = useRouter();
const userId = "CLEANWATER";
const password = "gktneh12!@";
const checkToken = getCookie(AUTH_USER_ID);
useEffect(() => {
if (!checkToken) {
async function doLogin() {
try {
await LoginApi.login({ userId, password });
window.location.href = "/map/mainMap";
} catch (err) {
console.error("로그인 실패", err);
const hostname = window.location.hostname;
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") {
if (!checkToken) {
async function doLogin() {
try {
await LoginApi.login({ userId: "CLEANWATER", password: "gktneh12!@" });
window.location.href = "/map/mainMap";
} catch (err) {
console.error("로그인 실패", err);
}
}
}
doLogin();
} else {
router.push("/map/mainMap");
}
doLogin();
} else router.push("/map/mainMap");
} else router.push("/map/mainMap");
}, []);
}
+28 -1
View File
@@ -1,5 +1,6 @@
import { fetchType, getFetchWithCount } from "@/components/lib/api";
import { getUserInfo } from "@common/components/api";
import { getCookie } from "@common/components/lib";
import toast from "react-hot-toast";
export type authState = {
@@ -10,6 +11,7 @@ export type authState = {
mdfcnAuthrtYn: string;
delAuthrtYn: string;
laeSeCd: string;
myUUID?: string;
};
};
@@ -23,14 +25,15 @@ export const authStateExport: authState = {
mdfcnAuthrtYn: "Y",
delAuthrtYn: "Y",
laeSeCd: "",
myUUID:''
},
};
export type authActions = {
getMenuAuthrts: (menuCd: number) => void;
getLaeSeCdCheck: () => Promise<void>;
getMyUUID: () => Promise<string |undefined>;
};
export const authActionsExport: (set: any, get: any) => authActions = (
set: any,
get: any
@@ -83,5 +86,29 @@ export const authActionsExport: (set: any, get: any) => authActions = (
console.error("laeSeCd check error", e);
}
},
getMyUUID: async () => {
try{
const cached = get().auth.myUUID;
if (cached && cached !== "") {
return cached;
}
const tokenId = getCookie("token-id");
set((state: authState) => ({
...state,
auth: {
...state.auth,
myUUID: tokenId,
},
}));
return tokenId;
}catch(e){
console.error("getMyUUID error", e);
return undefined;
}
},
};
};
+1
View File
@@ -24,5 +24,6 @@ export type TableUpperProps = {
mergeCell?:boolean // 셀을 합칠경우
maxLength?:number
readonly?:boolean
commonCode?:string // 공통코드 사용할경우
};
@@ -208,7 +208,8 @@ export const excelToRainChkData = (excelData: any, year: string) => {
`과태료부과금액(천원): 숫자 형식 아님 /입력값:${key.levyAmt}`
);
}
if (key.vltnDt?.length > 2 && isInvalidDate(key.vltnDt)) {
if (key.vltnDt?.length >= 1 && isInvalidDate(key.vltnDt)) {
issues.push(
defaultMessage +
`과태료 부과일(위반일): 날짜 형식 아님 /입력값:${key.vltnDt}`
@@ -25,7 +25,6 @@ import {
} from "./headList";
export const rainPageSize = 5;
export const commonCd = "41";
export type rainChkZodType = z.infer<typeof rainChkZod>;
const fcltDiv = [
@@ -75,7 +74,7 @@ type rainChkgdnActions = {
sggCode: SelectDataType[],
sggCd:string
): Promise<void>;
rainChkExcelDataUPload(excelData: rainChkZodType[] ,year :string) : Promise<void>;
rainChkExcelDataUPload(excelData: rainChkZodType[] ,year :string,laeSeCd:string) : Promise<void>;
rainChkDelete(chkgdnSns: number[] ,year :string): Promise<void>;
rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit: boolean) => void;
rainChkNmSearch: (
@@ -168,7 +167,7 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
},
}));
},
rainChkExcelDataUPload: async (excelData: rainChkZodType[] ,year:string) => {
rainChkExcelDataUPload: async (excelData: rainChkZodType[] ,year:string,laeSeCd:string) => {
set((state: rainChkgdnType) => (
{ rainChkgdn: { ...state.rainChkgdn, isLoading: true } }));
try {
@@ -178,7 +177,7 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
1,
rainPageSize,
year,
commonCd
laeSeCd
);
set((state: rainChkgdnState) => ({
...state,
@@ -78,7 +78,7 @@ type rswtChkgdnActions = {
sggCode: SelectDataType[],
sggCd: string,
): Promise<void>;
rswtChkExceDataUpload: (excelData: rswtChkZodType[]) => void;
rswtChkExceDataUpload: (excelData: rswtChkZodType[],laeSeCd:string) => void;
rswtChkDelete: (chkgdnSns: number[] ,year:string) => void;
rswtChkDetilsUpdate: (rswtChkDetails: rswtrChkDetailsZodType[] ,year:string) => void;
rswtChkPolAndGuide: (chkgdnSn: number) => void;
@@ -244,7 +244,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
console.log(error);
}
},
rswtChkExceDataUpload: async (excelData: rswtChkZodType[]) => {
rswtChkExceDataUpload: async (excelData: rswtChkZodType[],laeSeCd:string) => {
try {
set((state: rswtChkgdnType) => (
{ rswtChkgdn: { ...state.rswtChkgdn, isLoading: true } }));
@@ -256,7 +256,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
});
}
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0");
const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, laeSeCd);
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
@@ -1,3 +1,13 @@
/**
* 재이용실적등록 > 하수재이용실적등록
*
* 🔗 사용 API
* - 하수재이용시설 실적 조회: POST /api/v1/reuseFc/pubDetailList/{year}/{sggOrCity}/{page}/{pageSize} (reuse-service)
* - 하수재이용시설 실적 등록: POST /api/v1/reuseFc/pubFcPrf (reuse-service)
* - 공공재이용시설 목록 조회: POST /api/v1/prcsFclt/ruseInfo/{page}/{pageSize}/{type}/{sggOrCity}/{etc1}/{etc2}/{etc3} (server-service)
* - 공공재이용시설 목록 조회(이름검색): POST /api/v1/prcsFclt/ruseInfo/{page}/{pageSize}/{type}/{sggOrCity}/{searchTxt} (server-service)
* - 공공재이용시설 조회: GET /api/v1/reuseFc/pubFc (reuse-service)
**/
import { fetchType, getFetch, postFectch } from "@/components/lib/api";
import { pbnstPrfmncHeadListExport, monthHeadListExport } from "./headList";
import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
@@ -75,8 +85,8 @@ const hasuListFetch = async (
: fclt.slice(0, 5) === sggOrCity;
});
}
let url = `/prcsFclt/ruseInfo/1/${filteredFclt.length + 1}/A/${sggOrCity}/0/1/SW`;
//let url = `/prcsFclt/ruseInfo/1/${filteredFclt.length + 1}/A/${sggOrCity}/0/1/SW`;
let url = `/prcsFclt/ruseInfo/1/${filteredFclt.length + 1}`;
if (searchTxt && searchTxt?.length > 0) {
url += `/${searchTxt}`;
}
@@ -121,7 +131,6 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = (
getPrfFmcRes: async () => {
try {
const pbnPrfRes = await getFetch(fetchType.WR, "/reuseFc/pubFc");
console.log("pbnPrfRes ", pbnPrfRes);
set((state: pbnstPrfmncState) => ({
...state,
prfmnc: {
@@ -140,7 +149,6 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = (
prfPbnFclts: string[]
) => {
try {
console.log("prfPbnFclts ", prfPbnFclts);
const prfmncRes = await hasuListFetch(
page,
sggOrCity,
@@ -1,5 +1,5 @@
import { getFetch } from "@/components/lib/api";
import { TEST_UUID, type customRainBdst } from "../rainReg";
import type { customRainBdst } from "../rainReg";
import type { customHtdflBdst } from "../htdflReg";
import type { customRswtBdst } from "../rswtReg";
import type { TableUpperProps } from "@/app/store/common/type/header";
@@ -35,18 +35,19 @@ const isRswtBdst = (data: any): data is customRswtBdst => {
};
export const makeRstr = (
data: customRainBdst | customHtdflBdst | customRswtBdst
data: customRainBdst | customHtdflBdst | customRswtBdst,
myUUID: string
) => {
data.rgtr = TEST_UUID;
data.rgtr = myUUID;
let chData;
if (isRainBdst(data)) {
chData = data.reuseBuilding.map((item) => ({
...item,
rgtr: TEST_UUID,
rgtr: myUUID,
rainyObj: {
...item.rainyObj,
rgtr: TEST_UUID,
rgtr: myUUID,
},
}));
@@ -54,10 +55,10 @@ export const makeRstr = (
} else if (isHtdflBdst(data)) {
chData = data.reuseBuilding.map((item) => ({
...item,
rgtr: TEST_UUID,
rgtr: myUUID,
htdflObj: {
...item.htdflObj,
rgtr: TEST_UUID,
rgtr: myUUID,
},
}));
@@ -65,10 +66,10 @@ export const makeRstr = (
} else if (isRswtBdst(data)) {
chData = data.reuseBuilding.map((item) => ({
...item,
rgtr: TEST_UUID,
rgtr: myUUID,
rswtrObj: {
...item.rswtrObj,
rgtr: TEST_UUID,
rgtr: myUUID,
},
}));
data.reuseBuilding = chData;
@@ -81,7 +82,7 @@ export const makeRstr = (
) {
const chRgtr = data.chgBuilding.map((item) => ({
...item,
rgtr: TEST_UUID,
rgtr: myUUID,
mdfr: item.mdfr ?? null,
}));
data.chgBuilding = chRgtr;
@@ -90,23 +91,24 @@ export const makeRstr = (
};
export const makeMdfr = (
data: customRainBdst | customHtdflBdst | customRswtBdst
data: customRainBdst | customHtdflBdst | customRswtBdst,
myUUID: string
) => {
data.mdfr = TEST_UUID;
data.mdfr = myUUID;
let chData;
if (isRainBdst(data)) {
chData = data.reuseBuilding.map((item) => ({
...item,
mdfr: TEST_UUID,
mdfr: myUUID,
rainyObj: {
...item.rainyObj,
mdfr: TEST_UUID,
mdfr: myUUID,
},
}));
if (data?.chgBuilding.length > 0) {
const chRgtr = data.chgBuilding.map((item) => ({
...item,
rgtr: TEST_UUID,
rgtr: myUUID,
mdfr: item.mdfr ?? null,
}));
data.chgBuilding = chRgtr;
@@ -116,20 +118,20 @@ export const makeMdfr = (
} else if (isHtdflBdst(data)) {
chData = data.reuseBuilding.map((item) => ({
...item,
mdfr: TEST_UUID,
mdfr: myUUID,
htdflObj: {
...item.htdflObj,
mdfr: TEST_UUID,
mdfr: myUUID,
},
}));
data.reuseBuilding = chData;
} else if (isRswtBdst(data)) {
chData = data.reuseBuilding.map((item) => ({
...item,
mdfr: TEST_UUID,
mdfr: myUUID,
rswtrObj: {
...item.rswtrObj,
mdfr: TEST_UUID,
mdfr: myUUID,
},
}));
data.reuseBuilding = chData;
@@ -142,7 +144,7 @@ export const makeMdfr = (
) {
const chMdfr = data.chgBuilding.map((item) => ({
...item,
mdfr: TEST_UUID,
mdfr: myUUID,
archChgArea: item.archChgArea ?? "",
}));
data.chgBuilding = chMdfr;
@@ -168,8 +170,9 @@ type bdstActions = {
setUserCitySggCd: (
laeSeCd: string,
cityCd: SelectDataType[],
sggCd: SelectDataType[]) => void;
setUserSggCd: ( userCityCd: string,sggCd: SelectDataType[]) => void;
sggCd: SelectDataType[]
) => void;
setUserSggCd: (userCityCd: string, sggCd: SelectDataType[]) => void;
};
const findBdstInfo = async (sggCd: string, searchTxt: string, flg: string) => {
@@ -218,16 +221,15 @@ export const bdstActionsExport: (set: any) => bdstActions = (set: any) => {
sggCd: SelectDataType[]
) => {
let city = [...cityCd];
let sgg = [...sggCd]
console.log('sgg ', sgg)
let sgg = [...sggCd];
console.log("sgg ", sgg);
if (laeSeCd === "0" && cityCd.length > 0) {
city = city;
sgg = [{ val: "0", text: "전체" }]
sgg = [{ val: "0", text: "전체" }];
} else if (laeSeCd.length === 2 && cityCd.length > 0) {
city = cityCd.filter((item) => item.val === laeSeCd);
sgg = sggCd.filter((item) => item.val.slice(0, 2) === laeSeCd);
sggCd.unshift({ val: "0", text: "전체" });
} else if (
laeSeCd.length === 5 &&
cityCd.length > 0 &&
@@ -235,13 +237,9 @@ export const bdstActionsExport: (set: any) => bdstActions = (set: any) => {
) {
city = cityCd.filter((item) => item.val === laeSeCd.slice(0, 2));
sgg = sggCd.filter((item) => item.val === laeSeCd);
}
return set((state: bdstState) => ({
...state,
bdst: {
...state.bdst,
@@ -249,9 +247,8 @@ export const bdstActionsExport: (set: any) => bdstActions = (set: any) => {
userSggCd: sgg,
},
}));
},setUserSggCd( userCityCd: string,sggCd: SelectDataType[]){
},
setUserSggCd(userCityCd: string, sggCd: SelectDataType[]) {
const sgg = sggCd.filter((item) => item.val.slice(0, 2) === userCityCd);
return set((state: bdstState) => ({
@@ -1,4 +1,4 @@
import { getFetchWithCount, postFectch, putFectch } from "@/components/lib/api";
import { getFetchWithCount, postFectch, putFectch, deleteFectch } from "@/components/lib/api";
import type { TableUpperProps } from "@/app/store/common/type/header";
import toast from "react-hot-toast";
@@ -94,14 +94,17 @@ export type htdflFacState = {
upHeadList: TableUpperProps[];
htdflRes: customHtdflBdst[];
htdflResCount:number
htdfTableIndex?: number;
};
};
type htdflFacSActions = {
initHtdflReg: (code: string) => void;
htdflNmSearch: (code: string | number, fcltNm:string) => void;
htdflBdstUpdate: (data: customHtdflBdst, code: string | number) => void;
htdflBdstReg: (data: customHtdflBdst, code: string | number) => void;
htdflBdstUpdate: (data: customHtdflBdst, code: string | number,myUUID:string) => void;
htdflBdstReg: (data: customHtdflBdst, code: string | number,myUUID:string) => void;
htdflBdstDelete: (data: customHtdflBdst, code: string | number) => void;
getHtdflBdstData: (pageNation: number, code: string | number) => void;
resetHtdflTableIndex:(index:number)=>void;
};
const htdflRes: customHtdflBdst[] = [];
@@ -113,6 +116,7 @@ export const htdflFacStateExport: htdflFacState = {
upHeadList: htdTableHeadList,
htdflRes: htdflRes,
htdflResCount:1,
htdfTableIndex: undefined,
},
};
@@ -167,9 +171,9 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
console.log(error);
}
},
htdflBdstUpdate: async (data: customHtdflBdst, code: string | number) => {
htdflBdstUpdate: async (data: customHtdflBdst, code: string | number,myUUID:string) => {
try {
const chData = await makeMdfr(data);
const chData = await makeMdfr(data,myUUID);
const res = await putFectch("/drain/facility", chData);
if (res.status) {
toast.success("온배수 시설물 수정이 완료되었습니다.");
@@ -192,12 +196,12 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
console.log(errorUpdate);
}
},
htdflBdstReg: async (data: customHtdflBdst, code: string | number) => {
htdflBdstReg: async (data: customHtdflBdst, code: string | number,myUUID:string) => {
try {
// data는 단일 객체이므로 .map을 사용할 수 없습니다.
// 등록 시에는 건축물 변경 이력이 없으므로 chgBuilding을 빈 배열로 설정하고,
// API가 배열을 기대하므로 단일 객체를 배열로 감싸줍니다.
const chData = makeRstr(data);
const chData = makeRstr(data,myUUID);
const res = await postFectch("/drain/facility", chData);
if (res.status ===200) {
toast.success("온배수 시설 등록이 완료되었습니다.");
@@ -217,7 +221,30 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
console.log(errorReg);
}
},htdflNmSearch :async(code:string | number, fcltNm:string) =>{
},
// 온배수시설을 삭제한다.
htdflBdstDelete: async (data: customHtdflBdst, code: string | number) => {
try {
await deleteFectch(`/drain/facility/${data.reuseBuilding?.[0]?.bdstRuseFcltSn}`);
toast.success(`${data.bdstNm} 시설이 삭제되었습니다.`);
const htdflRes = await initFetch(String(code));
set((state: htdflFacState) => ({
...state,
htdfl: {
...state.htdfl,
htdflRes: htdflRes.data,
htdflResCount: htdflRes.count,
},
}));
} catch (e) {
console.log("e", e);
const errorMessage = e instanceof Error ? e.message : "삭제 중 오류가 발생했습니다.";
toast.error(errorMessage);
} finally {
}
},
htdflNmSearch :async(code:string | number, fcltNm:string) =>{
try {
const htdflRes = await getFetchWithCount("wr", `/drain/facilityList/1/11/${code}/${fcltNm}`);
set((state: htdflFacState) => {
@@ -235,5 +262,20 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
console.log(error);
}
},
resetHtdflTableIndex: (index: number) => {
// 1) 동일값도 '변경'으로 느끼게 잠깐 -1
set((state: htdflFacState) => ({
...state,
htdfl: { ...state.htdfl, htdfTableIndex: -1 },
}));
// 2) 다음 마이크로태스크에서 진짜 값 복구
Promise.resolve().then(() => {
set((state: htdflFacState) => ({
...state,
htdfl: { ...state.htdfl, htdfTableIndex: index },
}));
});
},
};
};
@@ -1,5 +1,6 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
import {
deleteFectch,
fetchType,
getFetchWithCount,
postFectch,
@@ -88,14 +89,17 @@ export type rainFacState = {
upHeadList: TableUpperProps[];
rainRes: customRainBdst[];
rainResCount: number;
rainTableIndex?: number;
};
};
type rainFacSActions = {
initRain: (code: string | number) => void;
getRainData: (pageNation: number, code: string | number) => void;
rainSearch: (txt: string, pageNation: number, code: string) => void;
rainBdstReg: (data: customRainBdst, code: string | number) => void;
rainBdstUpdate: (data: customRainBdst, code: string | number) => void;
rainBdstReg: (data: customRainBdst, code: string | number,myUUID:string) => void;
rainBdstUpdate: (data: customRainBdst, code: string | number,myUUID:string) => void;
rainBdstDelete: (data: customRainBdst, code: string | number) => void;
resetRainTableIndex:(index:number)=>void;
};
export type rainFacType = rainFacState & rainFacSActions;
@@ -105,6 +109,7 @@ export const rainFacStateExport: rainFacState = {
rainRes: rainRes,
rainResCount: 1,
upHeadList: upHeadList,
rainTableIndex: undefined,
},
};
@@ -167,7 +172,6 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
`/reuseFc/rainyInfoList/${pageNation}/${rainRegSize}/${code}` +
(txt ? `/${txt}` : "")
);
console.log("rainRes", rainRes);
set((state: rainFacState) => {
return {
rain: {
@@ -182,9 +186,9 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
}
},
// 빗물 이용시설을 등록한다.
rainBdstReg: async (data: customRainBdst, code: string | number) => {
rainBdstReg: async (data: customRainBdst, code: string | number,myUUID:string) => {
try {
const test = await makeRstr(data);
const test = await makeRstr(data,myUUID);
const res = await postFectch("/reuseFc/rainyInfo", test);
if (res.status === 200) {
if (data.chgBuilding.length > 0) {
@@ -198,7 +202,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
if (chch.status === 200) {
toast.success("건축물 등록이 완료되었습니다.");
} else {
toast.error("건축물 증축/개축/중축 오류입니다.");
toast.error("건축물 증축/개축/재축 오류입니다.");
}
} else {
toast.success("건축물 등록이 완료되었습니다.");
@@ -222,14 +226,13 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
}
},
// 빗물이용시설 시설에 대한 사항을 업데이트한다
rainBdstUpdate: async (data: customRainBdst, code: string | number) => {
rainBdstUpdate: async (data: customRainBdst, code: string | number,myUUID:string) => {
try {
const chData = await makeMdfr(data);
const chData = await makeMdfr(data,myUUID);
const res = await putFectch("/reuseFc/rainyInfo", chData);
if (res.status === 200) {
if (data.chgBuilding.length > 0) {
const chPK = data?.bdstInfoSn;
console.log("chPK", chPK);
const makeCh = data.chgBuilding.map((item: chgBuilding) => ({
...item,
bdstInfoSn: chPK,
@@ -239,9 +242,11 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
if (chch.status === 200) {
toast.success("건축물 수정이 완료되었습니다.");
} else {
toast.error("건축물 증축/개축/중축 오류입니다.");
toast.error("건축물 증축/개축/재축 오류입니다.");
}
} else {
await deleteFectch("/reuseFc/DeleteChgBuilding" , data.bdstInfoSn);
toast.success("건축물 수정이 완료되었습니다.");
}
} else {
@@ -263,5 +268,41 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
} finally {
}
},
// 빗물 이용시설을 삭제한다.
rainBdstDelete: async (data: customRainBdst, code: string | number) => {
try {
await deleteFectch(`/reuseFc/rainyInfo/${data.reuseBuilding?.[0]?.bdstRuseFcltSn}`);
toast.success(`${data.bdstNm} 시설이 삭제되었습니다.`);
const rainRes = await initFetch(code);
set((state: rainFacState) => ({
...state,
rain: {
...state.rain,
rainRes: rainRes.data,
rainResCount: rainRes.count,
},
}));
} catch (e) {
console.log("e", e);
const errorMessage = e instanceof Error ? e.message : "삭제 중 오류가 발생했습니다.";
toast.error(errorMessage);
} finally {
}
},
resetRainTableIndex: (index: number) => {
// 1) 동일값도 '변경'으로 느끼게 잠깐 -1
set((state: rainFacState) => ({
...state,
rain: { ...state.rain, rainTableIndex: -1 },
}));
// 2) 다음 마이크로태스크에서 진짜 값 복구
Promise.resolve().then(() => {
set((state: rainFacState) => ({
...state,
rain: { ...state.rain, rainTableIndex: index },
}));
});
},
};
};
@@ -1,28 +1,30 @@
import { z } from "zod";
export const validationMessages = {
required: (field: string) => `${field}을(를) 입력해주세요.`,
requiredSelect: (field: string) => `${field}을(를) 선택해주세요.`,
yearFormat: '4자리 연도만 입력하세요',
};
required: (field: string) => `${field}을(를) 입력해주세요.`,
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(999_999_999_999, { message: "최대 1,000,000,000,000까지 입력 가능합니다." })
.nullish(),
.number()
.max(999_999_999_999, {
message: "최대 1,000,000,000,000까지 입력 가능합니다.",
})
.nullish(),
operMngCd: z.string().optional().default(""),
anlOperCst: z.number().default(0),
instlCstSprtYn: z.string().default("Y"),
instlCstSprtAmt: z.number().nullish(),
grntchBdstCertYn: z.string().default("Y"),
grntchBdstCertYr: z.string().refine(
(val) => val === "" || /^\d{4}$/.test(val),
{ message: "연도는 빈값 또는 4자리 숫자여야 합니다." }
),
grntchBdstCertYr: z
.string()
.refine((val) => val === "" || /^\d{4}$/.test(val), {
message: "연도는 빈값 또는 4자리 숫자여야 합니다.",
}),
grntchBdstCertNo: z.string().default(""),
grntchBdstCertGrd: z.string().default(""),
crgRdctYn: z.string().default("N").nullish(), /// 안쓰는 값
@@ -30,11 +32,11 @@ export const baseReuseBuildingSchema = z.object({
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
bdstUsgCd: z
.string()
.default('000')
.refine((val) => val.trim().length > 0, {
message: validationMessages.requiredSelect("건축물용도"),
}),
.string()
.default("000")
.refine((val) => val.trim().length > 0, {
message: validationMessages.requiredSelect("건축물용도"),
}),
lawTrgtYn: z.string().default("Y"),
rgtr: z.string().nullish(),
mdfr: z.string().nullish(),
@@ -42,15 +44,17 @@ export const baseReuseBuildingSchema = z.object({
export const chgBuildingSchema = z.object({
bdstInfoSn: z.number().nullish(),
archChgPrmsnDt: z.coerce.date({required_error: validationMessages.required("허가일")}),
archChgPrmsnDt: z.coerce.date({
required_error: validationMessages.required("허가일"),
}),
archChgArea: z.string().default("-"),
bdstChgNm: z.string().min(1, { message: validationMessages.requiredSelect("구분") }),
rgtr:z.string().nullish(),
mdfr:z.string().nullish(),
bdstChgNm: z
.string()
.min(1, { message: validationMessages.requiredSelect("구분") }),
rgtr: z.string().nullish(),
mdfr: z.string().nullish(),
});
export const htdflReuseBuildingSchema = z.object({
bdstRuseFcltSn: z.number().nullish(),
bdstInfoSn: z.number().nullish(),
@@ -62,26 +66,25 @@ export const htdflReuseBuildingSchema = z.object({
instlCstSprtAmt: z.number().nullish(),
grntchBdstCertYn: z.string().default("Y"),
grntchBdstCertYr: z
.string()
.max(4, { message: validationMessages.yearFormat })
.refine(
(year) => year.length === 0 || /^\d{4}$/.test(year),
{
.string()
.max(4, { message: validationMessages.yearFormat })
.refine((year) => year.length === 0 || /^\d{4}$/.test(year), {
message: validationMessages.yearFormat,
}
)
.nullish(),
})
.nullish(),
grntchBdstCertNo: z.string().default(""),
grntchBdstCertGrd: z.string().default(""),
crgRdctYn: z.string().default("N").nullish(), /// 안쓰는 값
crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
bdstUsgCd: z.number().default(0).nullish(),
bdstUsgCd: z
.string()
.default("000")
.refine((val) => val.trim().length > 0, {
message: validationMessages.requiredSelect("건축물용도"),
}),
lawTrgtYn: z.string().default("Y").nullish(),
rgtr: z.string().nullish(),
mdfr: z.string().nullish(),
});
@@ -1,4 +1,4 @@
import { getFetchWithCount, postFectch, putFectch } from "@/components/lib/api";
import { deleteFectch, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api";
import { upHeadList, type chgBuilding } from "../rainReg";
import type { TableUpperProps } from "@/app/store/common/type/header";
@@ -62,18 +62,21 @@ export type rswtFacState = {
upHeadList: TableUpperProps[];
rswtRes: customRswtBdst[];
rswtResCount: number;
rswtTableIndex?: number;
};
};
type rswtFacSActions = {
initRswt: (code: string | number) => void;
rswtBdstUpdate: (data: customRswtBdst, code: string | number) => void;
rswtBdstUpdate: (data: customRswtBdst, code: string | number,myUUID:string) => void;
getRswtBdstData: (pageNation: number, code: string | number) => void;
rswtBdstSearch: (
txt: string,
pageNation: number,
code: string | number
) => void;
rswtBdstReg: (data: customRswtBdst, code: string | number) => void;
rswtBdstReg: (data: customRswtBdst, code: string | number,myUUID:string) => void;
rswtBdstDelete: (data: customRswtBdst, code: string | number) => void;
resetRswtTableIndex:(index:number)=>void;
};
export type rswtFacType = rswtFacState & rswtFacSActions;
@@ -158,9 +161,9 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
}
},
// 중수도 시설에 대한 사항을 업데이트한다
rswtBdstUpdate: async (data: customRswtBdst, code: string | number) => {
rswtBdstUpdate: async (data: customRswtBdst, code: string | number,myUUID:string) => {
try {
const chData = await makeMdfr(data);
const chData = await makeMdfr(data,myUUID);
const res = await putFectch("/reuseFc/waterreuseFc", chData);
if (res.status === 200) {
if (data.chgBuilding.length > 0) {
@@ -176,9 +179,10 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
if (chch.status === 200) {
toast.success("중수도 건축물 수정이 완료되었습니다.");
} else {
toast.error("중수도 건축물 증축/개축/중축 오류입니다.");
toast.error("중수도 건축물 증축/개축/재축 오류입니다.");
}
} else {
await deleteFectch("/reuseFc/DeleteChgBuilding" , data.bdstInfoSn);
toast.success("중수도 건축물 수정이 완료되었습니다.");
}
} else {
@@ -201,9 +205,9 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
}
},
// 중수도 시설을 등록한다.
rswtBdstReg: async (data: customRswtBdst, code: string | number) => {
rswtBdstReg: async (data: customRswtBdst, code: string | number,myUUID:string) => {
try {
const chData = await makeRstr(data);
const chData = await makeRstr(data,myUUID);
const res = await postFectch("/reuseFc/waterreuseFc", chData);
if (res.status === 200) {
if (data.chgBuilding.length > 0) {
@@ -219,13 +223,12 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
if (chch.status === 200) {
console.log('chch.status', chch.status)
toast.success("건축물(중수도) 및 증축/개축/중축 등록이 완료되었습니다.");
toast.success("건축물(중수도) 및 증축/개축/재축 등록이 완료되었습니다.");
} else {
toast.error("건축물(중수도 증축/개축/중축 오류입니다.");
toast.error("건축물(중수도) 증축/개축/재축 오류입니다.");
}
} else {
toast.success("건축물(중수도 등록이 완료되었습니다.");
toast.success("건축물(중수도) 등록이 완료되었습니다.");
}
} else {
toast.error("건축물(중수도) 등록이 완료하였습니다.");
@@ -233,7 +236,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
const rswtRes = await initFetch(code);
set((state: rswtFacState) => ({
...state,
rain: {
rswt: {
...state.rswt,
rswtRes: rswtRes.data,
rswtResCount: rswtRes.count,
@@ -245,5 +248,41 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
} finally {
}
},
// 중수도시설을 삭제한다.
rswtBdstDelete: async (data: customRswtBdst, code: string | number) => {
try {
await deleteFectch(`/reuseFc/waterreuseFc/${data.reuseBuilding?.[0]?.bdstRuseFcltSn}`);
toast.success(`${data.bdstNm} 시설이 삭제되었습니다.`);
const rswtRes = await initFetch(code);
set((state: rswtFacState) => ({
...state,
rswt: {
...state.rswt,
rswtRes: rswtRes.data,
rswtResCount: rswtRes.count,
},
}));
} catch (e) {
console.log("e", e);
const errorMessage = e instanceof Error ? e.message : "삭제 중 오류가 발생했습니다.";
toast.error(errorMessage);
} finally {
}
},
resetRswtTableIndex: (index: number) => {
// 1) 동일값도 '변경'으로 느끼게 잠깐 -1
set((state: rswtFacState) => ({
...state,
rswt: { ...state.rswt, rswtTableIndex: -1 },
}));
// 2) 다음 마이크로태스크에서 진짜 값 복구
Promise.resolve().then(() => {
set((state: rswtFacState) => ({
...state,
rswt: { ...state.rswt, rswtTableIndex: index },
}));
});
},
};
};
@@ -47,7 +47,7 @@ export const rainSttHeadListExport: z.infer<typeof sttnHeadListType> = [
},
{
id: "chBuildingYn",
title: "중축・개축・재축여부",
title: "증축・개축・재축여부",
visible: true,
},
{
@@ -237,7 +237,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "chBuildingYn",
title: "중축・개축・재축여부",
title: "증축・개축・재축여부",
upName: "bdnstInfo",
visible: true,
row: 2,
@@ -18,7 +18,7 @@ export const excelRSwtSttnParsing = (
String(item.frstArchPrmsnDt ?? ""),
String(item.archArea.split('.')[0] === '-1' ? '확인불가' : item.archArea.split('.')[0]),
// String(item.reuseBuilding?.[0]?.rswtrObj.wtrUsqty ?? "0"), //물사용량
String(item.chgBuilding.length > 0 ? "Y" : "N"), //중축・개축・재축여부
String(item.chgBuilding.length > 0 ? "Y" : "N"), //증축・개축・재축여부
String(item.reuseBuilding?.[0]?.lawTrgtYn ?? ""), //법적의무대상여부
// String(item.reuseBuilding?.[0]?.rswtrObj.oblgTrgtWtrUsqty ?? ""), //의무대상물사용량
String(item.reuseBuilding?.[0]?.instlCmptnDt ?? ""), //설치완료일시
@@ -45,7 +45,7 @@ export const rswtSttHeadListExport: z.infer<typeof sttnHeadListType> = [
// },
{
id: "chBuildingYn",
title: "중축・개축・재축여부",
title: "증축・개축・재축여부",
visible: true,
},
@@ -239,7 +239,7 @@ export const rswtSttNodeListExport: CommonTableProps[] = [
// },
{
id: "chBuildingYn",
title: "중축・개축・재축여부",
title: "증축・개축・재축여부",
upName: "bdnstInfo",
visible: true,
row: 2,
@@ -40,36 +40,43 @@ export const rainStatHeadListExport: TableUpperProps[] = [
{
id: "lndwtr",
title: "조경용수",
commonCode : "01",
row:1,
},
{
id: "cleanToilUswtr",
title: "청소화장실용수",
commonCode : "02",
row:1,
},
{
id:"resn",
title:"세척살수용수",
commonCode : "03",
row:1,
},
{
id: "farmUswtr",
title: "농업용수",
commonCode : "04",
row:1,
},
{
id: "indstUswtr",
title: "공업용수",
commonCode : "05",
row:1,
},
{
id: "hydUswtr",
title: "친수용수",
commonCode : "06",
row:1,
},
{
id: "ithlEtcUswtr",
title: "기타",
commonCode : "07",
row:1,
},
{
+10 -5
View File
@@ -89,12 +89,11 @@ export const rainStatActionsExport = (
searchRainStatList: async (year: string, city: SelectDataType[]) => {
const res = await fetchRainStatList(year);
const cityArr: any[] = [];
console.log('res ', res)
res.filter((resFilter: RainStatProps) =>
city.some((cityCd) =>
resFilter.ctpvCd?.trim() === cityCd.val.trim()
// 도시코드가 0인 데이터 필터링
resFilter.ctpvCd?.trim() === cityCd.val.trim() && resFilter.ctpvCd.trim() != "0"
)
)
.forEach((item: RainStatProps) => {
@@ -116,14 +115,20 @@ export const rainStatActionsExport = (
obj.dtfcltCpct = item.dtfcltCpct;
obj.wtrUsqty = item.wtrUsqty;
obj.anlOperCst = item.anlOperCst;
obj.lndwtr = 0; //조경용수
obj.cleanToilUswtr = 0; //청소화장실용수
obj.resn = 0; //세척살수용수
obj.farmUswtr = 0; //농업용수
obj.indstUswtr = 0; //공업용수
obj.hydUswtr = 0; //친수용수
obj.ithlEtcUswtr = 0; //기타
cityArr.push(obj);
}
if (item.guideStats && item.guideStats.length > 0) {
item.guideStats.forEach((guide: GuideStatProps) => {
rainStatHeadListExport.forEach((headItem: TableUpperProps) => {
if (headItem.title == guide.utztnUsgCd) {
if (headItem.commonCode == guide.utztnUsgCd) {
if (!obj[headItem.id] || typeof obj[headItem.id] !== "number")
obj[headItem.id] = 0;
if (typeof obj[headItem.id] === "number") {
@@ -64,31 +64,37 @@ export const rswtStatHeadListExport :TableUpperProps[]=[
{
id: "lndwtr",
title: "조경용수",
commonCode: "01",
row:1,
},
{
id: "cleanToilUswtr",
title: "청소화장실용수",
commonCode : "02",
row:1,
},
{
id: "farmUswtr",
title: "농업용수",
commonCode : "04",
row:1,
},
{
id: "indstUswtr",
title: "공업용수",
commonCode : "05",
row:1,
},
{
id: "hydUswtr",
title: "친수용수",
commonCode : "06",
row:1,
},
{
id: "ithlEtcUswtr",
title: "기타",
commonCode : "07",
row:1,
},
{
+1 -2
View File
@@ -118,10 +118,9 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = (
item.guideStats.forEach((guide: GuideStatProps) => {
rswtStatHeadListExport.forEach((headItem: TableUpperProps) => {
if (headItem.title == guide.utztnUsgCd) {
if (headItem.commonCode == guide.utztnUsgCd) {
if (!obj[headItem.id] || typeof obj[headItem.id] !== "number") obj[headItem.id] = 0;
if (typeof obj[headItem.id] === "number") {
obj[headItem.id] += guide.ruseFcltUtztnQnt;
}
}
+12 -1
View File
@@ -167,7 +167,18 @@ export const deleteFectch = async (
body: params ? JSON.stringify(params) : undefined,
});
if (!response.ok) {
throw new Error(`오류 발생: ${response.status}`);
// 에러 응답 본문 파싱
const errorText = await response.text();
let errorMessage = `오류 발생: ${response.status}`;
try {
const errorJson = JSON.parse(errorText);
errorMessage = errorJson.message || errorMessage;
} catch {
errorMessage = errorText || errorMessage;
}
throw new Error(errorMessage);
}
return await response.text();
};
@@ -7,7 +7,7 @@ import { formH1Class } from "@/components/lib/class/comClass";
import { safeDate } from "@/components/lib/func/commom";
import { DatePicker, FormField, FormUi, SelectBox } from "@common/business_components";
import { Button, Checkbox, Input } from "@common/components";
import { useState } from "react";
import { useRef, useState } from "react";
import { useFieldArray } from "react-hook-form";
export default function BdstAdd({ form, readonly }: { form: any; readonly?: boolean; }) {
@@ -21,12 +21,21 @@ export default function BdstAdd({ form, readonly }: { form: any; readonly?: bool
control: form?.control, // Provide a fallback to avoid errors
});
const bottomRef = useRef<HTMLDivElement>(null);
const plusHist = () => {
append({
bdstChgNm: code.chBuCd[0]?.val,
archChgPrmsnDt: new Date(),
archChgArea: "",
});
// 새 항목이 렌더링된 후 스크롤 이동
setTimeout(() => {
if (bottomRef.current) {
bottomRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}, 100);
};
const [selectedIds, setSelectedIds] = useState<string[]>([]);
@@ -48,7 +57,7 @@ export default function BdstAdd({ form, readonly }: { form: any; readonly?: bool
return (
<>
<h1 className={formH1Class}>중축, 개축, 재축</h1>
<h1 className={formH1Class}>증축, 개축, 재축</h1>
{!readonly && (
<div className="flex justify-end gap-2 mt-4">
@@ -142,7 +151,7 @@ export default function BdstAdd({ form, readonly }: { form: any; readonly?: bool
</div>
</div>
))}
<div className="border-b border-gray-300 my-4"> </div>
<div ref={bottomRef} className="border-b border-gray-300 my-4"> </div>
</>
)
}
@@ -67,8 +67,8 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
}, [form.form]);
useEffect(() => {
const bdstInfoSn = form.getValues("bdstInfoSn");
if (bdstInfoSn && bdstInfoSn > 0) form.setValue("daddr", bdstInfoSn);
//const bdstInfoSn = form.getValues("bdstInfoSn");
// if (bdstInfoSn && bdstInfoSn > 0) form.setValue("daddr", bdstInfoSn);
}, [form.getValues("bdstInfoSn")]);
const userCtpvCd = form.watch("ctpvCd");
@@ -77,7 +77,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
useEffect(() => {
const city = String(userCtpvCd);
if (city && city === "0") {
if (city && (city === "0" || city === "50")) {
setUserSggCd([{ text: "전체", val: "0" }]);
form.setValue("sggCd", 0, {
@@ -42,7 +42,8 @@ export default function HtdflRegForm({
setIsModal?: (modal: boolean) => void;
isMap?: boolean;
}) {
const { code, htdflBdstUpdate, htdflBdstReg } = useWrStore((state) => state);
const { auth, code, htdflBdstUpdate, htdflBdstReg, htdflBdstDelete, resetHtdflTableIndex, getMyUUID } =
useWrStore((state) => state);
const [frontPHdata, setFrontPHdata] = useState("");
const [backPHdata, setBackPHdata] = useState("");
@@ -52,12 +53,21 @@ export default function HtdflRegForm({
resolver: zodResolver(hdtflZod),
defaultValues: defaultValues,
});
const { laeSeCd } = auth;
const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]);
const bdstNm = form.watch("bdstNm");
const isPowerPlant = bdstNm?.includes("발전소");
const { t } = useTranslation("base");
const onSubmit = (values: z.infer<typeof hdtflZod>) => {
const onSubmit = async (values: z.infer<typeof hdtflZod>) => {
const myUUID = await getMyUUID();
if (!myUUID) {
toast.error(t('noUserInfoMsg'));
return;
}
if (isModal) {
const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd";
if (data === "noCd") {
@@ -65,18 +75,25 @@ export default function HtdflRegForm({
return;
}
const handleConfirm = async () => {
htdflBdstReg(values, data);
htdflBdstReg(values, data,myUUID);
if (setIsModal) setIsModal(false);
};
confirmToast(t("isInsertMsg"), handleConfirm);
} else {
const handleConfirm = async () => {
htdflBdstUpdate(values, "0");
await htdflBdstUpdate(values, laeSeCd,myUUID);
console.log(' htdflBdstUpdate ')
resetHtdflTableIndex(0);
};
confirmToast(t("isUpdateMsg"), handleConfirm);
}
};
const onDelete = async () => {
const code = htdflForm.ctpvCd ? htdflForm.ctpvCd : htdflForm.sggCd ? htdflForm.sggCd : "noCd";
confirmToast(`정말 ${htdflForm.bdstNm} 시설을 삭제하시겠습니까?`, () => htdflBdstDelete(htdflForm, code));
}
const cleanHtdflData = (raw: any): z.infer<typeof hdtflZod> => {
const buildings =
raw?.reuseBuilding && raw.reuseBuilding.length > 0
@@ -194,7 +211,7 @@ export default function HtdflRegForm({
const firstYnValue = code.yn?.[0]?.val;
const firstHtdPowerMthdCd = code.htdPowerMthdCd?.[0]?.val;
const firstHtdUtztnUsgCd = code.htdUtztnUsgCd?.[0]?.val;
console.log('htdflForm ', htdflForm)
if (firstHtdPowerMthdCd) {
form.setValue(
"reuseBuilding.0.htdflObj.etgtType",
@@ -251,13 +268,23 @@ export default function HtdflRegForm({
온배수 시설 등록
</h1>
{!readonly && (
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
<div className="flex justify-end gap-2 mt-4">
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
<Button
type="button"
className="!bg-red-500 text-white"
size={"sm"}
onClick={onDelete}
>
삭제
</Button>
</div>
)}
</div>
</div>
@@ -38,10 +38,11 @@ export default function RainRegForm({
readonly?: boolean;
isMap?: boolean;
}) {
const { code, rainBdstReg, rainBdstUpdate } = useWrStore(
const { auth,code, rainBdstReg, rainBdstUpdate, rainBdstDelete, resetRainTableIndex, getMyUUID} = useWrStore(
(state) => state
);
const { rainFcltCd } = code;
const {laeSeCd } = auth;
const form = useForm<z.infer<typeof rainZod>>({
resolver: zodResolver(rainZod),
// defaultValues: defaultValues,
@@ -57,7 +58,7 @@ export default function RainRegForm({
// const [divStyle, setDivStyle] = useState("h-[53vh]");
useEffect(() => {
if(isMap=== true){
}
}, [isMap]);
@@ -128,27 +129,41 @@ export default function RainRegForm({
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
const onSubmit = (values: z.infer<typeof rainZod>) => {
const onSubmit = async(values: z.infer<typeof rainZod>) => {
const myUUID = await getMyUUID();
if (!myUUID) {
toast.error(t('noUserInfoMsg'));
return;
}
if (isModal) {
const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd";
if (data === "noCd") {
toast.error("시도/시군구 코드를 선택해야합니다.");
return;
}
const handleConfirm = async () => {
rainBdstReg(values, data);
rainBdstReg(values, data,myUUID);
if (setIsModal) setIsModal(false);
};
confirmToast(t('isInsertMsg'), handleConfirm);
} else {
const handleConfirm = async () => {
rainBdstUpdate(values, "41");
await rainBdstUpdate(values, laeSeCd,myUUID);
resetRainTableIndex(0)
};
confirmToast(t('isUpdateMsg'), handleConfirm);
}
};
const onDelete = async () => {
const code = rainForm.ctpvCd ? rainForm.ctpvCd : rainForm.sggCd ? rainForm.sggCd : "noCd";
confirmToast(`정말 ${rainForm.bdstNm} 시설을 삭제하시겠습니까?`, () => rainBdstDelete(rainForm, code));
}
useEffect(() => {
if (rainZod) form.reset(cleanRainData(rainForm));
}, [rainForm]);
@@ -166,13 +181,23 @@ export default function RainRegForm({
{isModal ? "건축물 정보" : "빗물이용시설 정보"}
</h1>
{!readonly && (
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
<div className="flex justify-end gap-2 mt-4">
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
<Button
type="button"
className="!bg-red-500 text-white"
size={"sm"}
onClick={onDelete}
>
삭제
</Button>
</div>
)}
</div>
</div>
@@ -28,6 +28,7 @@ import BdstAdd from "../bdstReg/bdstAdd";
import BdstReg from "../bdstReg/bdstReg";
import { useTranslation } from "react-i18next";
import { numSize, txtSize } from "@/app/store/common/code/basicCode";
import toast from "react-hot-toast";
export default function RswtrRegForm({
rswtForm,
@@ -42,13 +43,15 @@ export default function RswtrRegForm({
readonly?: boolean;
isMap?: boolean;
}) {
const { code, rswtBdstUpdate, rswtBdstReg } = useWrStore((state) => state);
const { auth,code, rswtBdstUpdate, rswtBdstReg, rswtBdstDelete, resetRswtTableIndex,getMyUUID} = useWrStore((state) => state);
// const [divStyle, setDivStyle] = useState("h-[53vh]");
const {laeSeCd } = auth;
useEffect(() => {
if (isMap) {
}
}, [isMap]);
// const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({});
const { t } = useTranslation("base");
const form = useForm<z.infer<typeof rswtZod>>({
resolver: zodResolver(rswtZod),
@@ -60,23 +63,43 @@ export default function RswtrRegForm({
"reuseBuilding.0.instlCstSprtYn",
"reuseBuilding.0.rswtrObj.filtrTrtmfctProcs",
]);
const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]);
const { t } = useTranslation("base");
const onSubmit = (values: z.infer<typeof rswtZod>) => {
const onSubmit =async (values: z.infer<typeof rswtZod>) => {
const myUUID = await getMyUUID();
if (!myUUID) {
toast.error(t('noUserInfoMsg'));
return;
}
if (isModal) {
const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd";
if (data === "noCd") {
toast.error("시도/시군구 코드를 선택해야합니다.");
return;
}
const handleConfirm = async () => {
rswtBdstReg(values, "41");
rswtBdstReg(values, data,myUUID);
if (setIsModal) setIsModal(false);
};
confirmToast(t("isInsertMsg"), handleConfirm);
} else {
const handleConfirm = async () => {
rswtBdstUpdate(values, "41");
rswtBdstUpdate(values, laeSeCd,myUUID);
resetRswtTableIndex(0)
};
confirmToast(t("isUpdateMsg"), handleConfirm);
}
};
const onDelete = async () => {
const code = rswtForm.ctpvCd ? rswtForm.ctpvCd : rswtForm.sggCd ? rswtForm.sggCd : "noCd";
confirmToast(`정말 ${rswtForm.bdstNm} 시설을 삭제하시겠습니까?`, () => rswtBdstDelete(rswtForm, code));
}
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => {
const buildings =
raw?.reuseBuilding && raw.reuseBuilding.length > 0
@@ -114,6 +137,8 @@ export default function RswtrRegForm({
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
useEffect(() => {
if (grntchBdstCertYn === "N") {
form.setValue("reuseBuilding.0.grntchBdstCertYr", "");
@@ -151,13 +176,23 @@ export default function RswtrRegForm({
건축물 정보
</h1>
{!readonly && (
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
<div className="flex justify-end gap-2 mt-4">
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
<Button
type="button"
className="!bg-red-500 text-white"
size={"sm"}
onClick={onDelete}
>
삭제
</Button>
</div>
)}
</div>
</div>
@@ -36,6 +36,7 @@ export default function ChkgdExcel({
setYearChange: (year: string) => void;
}) {
const {
auth,
rswtChkgdn,
rainChkgdn,
rainChkExcelDataUPload,
@@ -51,6 +52,7 @@ export default function ChkgdExcel({
const [file, setFile] = useState<File | null>(null);
const { laeSeCd } = auth;
const clearFile = () => {
if (fileInputRef.current) {
fileInputRef.current.value = ""; // ✅ 파일 선택 비우기
@@ -202,7 +204,8 @@ export default function ChkgdExcel({
} else {
rainChkExcelDataUPload(
excelData as rainChkZodType[],
form.getValues("chckYr")
form.getValues("chckYr"),
laeSeCd
);
setIsRegExcel(false);
setYearChange(form.getValues("chckYr"));
@@ -213,7 +216,7 @@ export default function ChkgdExcel({
return;
} else {
rswtChkExceDataUpload(excelRswtData as rswtChkZodType[]);
rswtChkExceDataUpload(excelRswtData as rswtChkZodType[], laeSeCd);
setIsRegExcel(false);
setYearChange(form.getValues("chckYr"));
}
@@ -122,10 +122,15 @@ export function BdstReg<T extends MoType>({
setUserSggCd([{ text: "전체", val: "0" }]);
setObjSearch({ ...objSearch, sgg: "0" });
} else if (city.length === 2) {
const sgg = code.sggCd.filter((item) => item.val.slice(0, 2) === city);
//sgg.unshift({ text: "전체", val: "0" });
setUserSggCd(sgg);
setObjSearch({ ...objSearch, sgg: Number(sgg[0]?.val) });
if (city === "50") {
setUserSggCd([{ text: "전체", val: "0" }] as SelectDataType[]);
setObjSearch({ ...objSearch, sgg: "0" });
} else {
const sgg = code.sggCd.filter((item) => item.val.slice(0, 2) === city);
//sgg.unshift({ text: "전체", val: "0" });
setUserSggCd(sgg);
setObjSearch({ ...objSearch, sgg: Number(sgg[0]?.val) });
}
}
}, [objSearch.city]);
+2 -1
View File
@@ -23,5 +23,6 @@
"costCalcErrMsg": "공사비 계산 진행 후 저장을 눌러주세요",
"maxYearErrMsg": "최대 {{year}}년까지 선택가능합니다.",
"checkQtyMsg": "요구수량(m³/일)을 확인해주세요 계산할 수 없습니다.",
"insertRuseBiz": "{{cycle}}차 사업이 추가되었습니다."
"insertRuseBiz": "{{cycle}}차 사업이 추가되었습니다.",
"noUserInfoMsg": "사용자 정보가 없습니다. 다시 로그인해주세요."
}
@@ -1,7 +1,7 @@
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useRouter, usePathname } from "next/navigation";
import { client } from "../../../shared/api";
import type { IUserInfo } from "../../../shared/store";
import { useUserStore } from "../../../shared/lib";
@@ -10,10 +10,11 @@ import { getCookie } from "../../../shared/lib";
import { LoginApi } from "../api/login-service";
// const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3000/auth/login"; // 로그인 페이지 URL
const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://localhost:3000/auth/login"; // 로그인 페이지 URL
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
const router = useRouter();
const pathname = usePathname();
const { userInfo, setUserInfo } = useUserStore((state) => state);
async function authCheck() {
@@ -42,19 +43,19 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
console.error("Token refresh failed:", refreshError);
setUserInfo(null);
// const hostname = window.location.hostname;
const hostname = window.location.hostname;
// 개발 환경에서는 localhost 도메인 사용
// if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr")
router.push("/"); // 개발시 홈으로 돌아가기
// 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용
// router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용
// if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
if (hostname.includes("hasuon.or.kr")) window.location.href = LOGIN_PAGE_URL; // 세션 만료 시 CM 로그인 페이지로 리다이렉트
}
}
})();
}, []);
}, [pathname]);
return <>{children}</>;
};
@@ -18,6 +18,7 @@ export type DemandCompType = {
daddr: string | "";
telno: string | "";
rgtr: string | "";
mdfr?:string ;
useUsgCd: string | "";
ctpvCd: string | "";
sggCd: string | "";
@@ -54,6 +55,7 @@ interface FormSchema {
telno: string;
bznmTotNo?: string;
rgtr?: string | "";
mdfr?: string | null;
dmdAplyPswd?: string;
dmdAplyPswdConfirm?: string;
}
@@ -261,8 +263,6 @@ export function SdmRegForm({
);
useEffect(() => {
form.setValue("rgtr", "2d4b151d-1828-41e0-91d9-4cd28ea1cc7e");
if (updateList?.dmdInfoId) {
form.reset(updateList);
if (updateList?.dmdInfoId.slice(10, 14) !== "0000") {
@@ -375,7 +375,7 @@ export function SdmRegForm({
type="text"
className="!text-xl text-gray-600"
onChange={(e) => bznNoChange(e, "dmdInfoId", field)}
value={formatBusinessNumber(field.value || "")}
value={formatBusinessNumber(field.value ?? "")}
readOnly={!!updateList?.dmdInfoId}
/>
),
@@ -396,7 +396,7 @@ export function SdmRegForm({
disabled={isBznmTotNoDisabled}
onChange={(e) => bznNoChange(e, "bznmTotNo", field)}
// {...field}
value={field.value}
value={field.value ?? ""}
readOnly={!!updateList?.dmdInfoId}
/>
</FormUi>
@@ -421,6 +421,7 @@ export function SdmRegForm({
className="!text-xl text-gray-600"
readOnly={readOnly}
{...field}
value={field.value ?? ""}
/>
),
},
@@ -456,6 +457,7 @@ export function SdmRegForm({
className="!text-xl text-gray-600"
readOnly={readOnly}
{...field}
value={field.value ?? ""}
/>
),
},
@@ -469,6 +471,7 @@ export function SdmRegForm({
className="!text-xl text-gray-600"
readOnly={readOnly}
{...field}
value={field.value ?? ""}
/>
),
},
@@ -7,6 +7,7 @@ import { FormProvider, useForm, type SubmitHandler } from "react-hook-form";
import { toast, Toaster } from "sonner";
import * as z from "zod";
import type { SelectDataType } from "../search_input_select";
import { getCookie } from "@common/components/lib";
type thisProps = {
@@ -45,6 +46,7 @@ const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean ,up
.max(11, "전화번호는 11자 이내로 입력해주세요")
.regex(/^[0-9]+$/, "전화번호는 숫자만 입력 가능합니다"),
rgtr: z.string().optional(),
mdfr: z.string().nullish(),
dmdAplyPswd : updateList?.dmdInfoId // 업데이트일경우
? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음
: z.string().optional()
@@ -75,6 +77,7 @@ const defaultValues: FormSchema = {
daddr: '',
telno: '',
rgtr: '',
mdfr: '',
dmdAplyPswd: '',
dmdAplyPswdConfirm: '',
};
@@ -120,20 +123,25 @@ export default function SdmInsertForm({selectSidoData, selectSigunData, dataList
try {
// form 에러 체크
const formErrors = form.formState.errors;
if (Object.keys(formErrors).length > 0) {
const myUUID = getCookie('token-id') ||'c475824c-0e82-4a06-a282-2b55a20df265';
if (Object.keys(formErrors).length > 0 ) {
const errorMessage = Object.values(formErrors)[0]?.message || '입력값을 확인해주세요.';
toast.error(errorMessage);
return;
}
const dmdInfoId = data.dmdInfoId + (data.bznmTotNo || '0000');
const formData = {
...data,
dmdInfoId,
bzmnNo: data.dmdInfoId,
rgtr: myUUID ,
};
console.log(' formData ', formData)
/* await insertSdmData(formData); */
rtnInputData(formData as unknown as DemandCompType);
@@ -175,7 +183,7 @@ export default function SdmInsertForm({selectSidoData, selectSigunData, dataList
type="submit"
className="w-32 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
>
수요처등록
{updateList ?'수정' :'등록'}
</Button>
}
@@ -25,6 +25,7 @@ type SearchBaseType = {
leftClassName?: string;
leftSelectClassName?: string;
buttonOrder?: ("query" | "init" | "excel")[];
initSidoValue?: string | '';
}
export type ReturnType = {
partValue: string;
@@ -57,10 +58,11 @@ function SearchBaseForm ({
rightClassName,
leftClassName,
leftSelectClassName,
buttonOrder
buttonOrder,
initSidoValue='',
}: SearchBaseType) {
const [partValue, setPartValue] = useState<string>("A");
const [sidoValue, setSidoValue] = useState<string>("0");
const [sidoValue, setSidoValue] = useState<string>(initSidoValue?initSidoValue:"0");
const [sigunValue, setSigunValue] = useState<string>("0");
const [sidoText, setSidoText] = useState<string>("");
const [sigunText, setSigunText] = useState<string>("");
@@ -94,7 +96,7 @@ function SearchBaseForm ({
}
};
const queryVal = () => {
console.log("조회버튼 클릭");
console.log("조회버튼 클릭",);
queryClick({
partValue: partValue,
sidoValue: sidoValue,
@@ -108,11 +110,18 @@ function SearchBaseForm ({
});
}
const initVal = useCallback(() => {
if(initSidoValue){
setSidoValue(initSidoValue);
}
setResetTrigger(true);
initClick();
}, [setResetTrigger, initClick]);
}, [initSidoValue, setResetTrigger, initClick]);
useEffect(() => {
if (resetTrigger) {
if(initSidoValue!=""){
setSidoValue(initSidoValue);
}
setResetTrigger(false);
}
}, [resetTrigger]);
@@ -167,6 +176,7 @@ function SearchBaseForm ({
isAdmin={isAdmin}
leftClassName={leftClassName}
leftSelectClassName={leftSelectClassName}
initSidoValue={initSidoValue}
>
{leftChildren}
</SearchFormLeft>
@@ -46,6 +46,7 @@ type SearchFormLeftProps = {
isAdmin?: boolean;
leftClassName?: string;
leftSelectClassName?: string;
initSidoValue?: string;
}
export type EnvPartSelectDataType = SelectDataType & {
@@ -58,11 +59,11 @@ const selectPartData:SelectDataType[] = [
{ text: "환경청별", val: 'G' },
];
function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSidoText, setRtnSigunValue, setRtnSigunText, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false, isAdmin = false, leftClassName, leftSelectClassName }: SearchFormLeftProps) {
function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSidoText, setRtnSigunValue, setRtnSigunText, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false, isAdmin = false, leftClassName, leftSelectClassName, initSidoValue }: SearchFormLeftProps) {
/******************선택된 데이터******************/
const [partValue, setPartValue] = useState<string>('A');
//행정별 시도 시군구
const [sidoValue, setSidoValue] = useState<string>('0');
const [sidoValue, setSidoValue] = useState<string>(initSidoValue?initSidoValue : '0');
const [sigunValue, setSigunValue] = useState<string>('0');
const [sidoText, setSidoText] = useState<string>('');
const [sigunText, setSigunText] = useState<string>('');
@@ -85,6 +86,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
const [filteredEnvPartSidoData, setFilteredEnvPartSidoData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd:'' }]);
const [filteredEnvPartSigunData, setFilteredEnvPartSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]);
const [initTrigger, setInitTrigger] = useState<boolean>(false);
// 시군구 세팅
const initializeSigunData = (sidoCd: string) => {
if (sidoCd === '0') {
@@ -99,7 +101,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
setFilteredSigunData(newFilteredData);
}
}
// 단위유역 세팅
const initializeUnitWaterShedData = (regionCd: string) => {
if(regionCd === '0') {
@@ -159,6 +161,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
}
const onSelectValue = (val: string, type: string) => {
setInitTrigger(true);
let selectedSido;
let selectedSigun;
let selectedEnvPartSido;
@@ -272,7 +275,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
// 리셋 함수
const resetAllValues = () => {
setPartValue('A');
setSidoValue('0');
setSidoValue(initSidoValue?initSidoValue:'0');
setSigunValue('0');
setRegionValue('0');
setUnitWaterShedValue('0');
@@ -287,7 +290,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
setFilteredEnvPartSigunData([{ text: "전체", val: '0' }]);
if (setRtnPartValue) setRtnPartValue('A');
if (setRtnSidoValue) setRtnSidoValue('0');
if (setRtnSidoValue) setRtnSidoValue(initSidoValue?initSidoValue:'0');
if (setRtnSigunValue) setRtnSigunValue('0');
if (setRtnRegionValue) setRtnRegionValue('0');
if (setRtnUnitWaterShedValue) setRtnUnitWaterShedValue('0');
@@ -304,6 +307,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
// 리셋 후 트리거를 false로 설정
if (setRtnPartValue) {
setRtnPartValue('A');
setInitTrigger(false);
}
}
}, [resetTrigger]);
@@ -327,7 +331,12 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
) : (
<>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시도'} selectArray={selectSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'sido')} value={sidoValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시군구'} selectArray={filteredSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'sigun')} value={sigunValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시군구'} selectArray={initSidoValue&&!initTrigger?[
{ text: '전체', val: '0' },
...selectSigunData.filter(
(item) => String(item.val).slice(0, 2) === String(initSidoValue)
),
]:filteredSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'sigun')} value={sigunValue} selectClass={undefined}/>
</>
)}
{children}