diff --git a/apps/cs/src/pages/link/ui/link-form.tsx b/apps/cs/src/pages/link/ui/link-form.tsx index 9447c0bb2..51d8c9f18 100644 --- a/apps/cs/src/pages/link/ui/link-form.tsx +++ b/apps/cs/src/pages/link/ui/link-form.tsx @@ -244,7 +244,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, - 연계서버 IP + + {'link0007' === form.watch('link_clsf_cd') as string ? '연계 파일명 구분자' : '연계서버 IP'} + diff --git a/apps/dm/app/(base-layout)/pages/wrStatus/page.tsx b/apps/dm/app/(base-layout)/pages/wrStatus/page.tsx index ce38a1226..e6b6da4d6 100644 --- a/apps/dm/app/(base-layout)/pages/wrStatus/page.tsx +++ b/apps/dm/app/(base-layout)/pages/wrStatus/page.tsx @@ -367,7 +367,7 @@ export default function WrStatusPage() { item.label!= '')} chartTitle={chartOption.chartTitle} chartClassName={chartOption.chartClassName} graphSize={chartOption.graphSize} diff --git a/apps/dm/app/(popup-layout)/map/popup/page.tsx b/apps/dm/app/(popup-layout)/map/popup/page.tsx index 6efb4ebef..ea1e4b174 100644 --- a/apps/dm/app/(popup-layout)/map/popup/page.tsx +++ b/apps/dm/app/(popup-layout)/map/popup/page.tsx @@ -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) => { diff --git a/apps/dm/app/(popup-layout)/map/service/map.ts b/apps/dm/app/(popup-layout)/map/service/map.ts index 7701288bb..00e3ab561 100644 --- a/apps/dm/app/(popup-layout)/map/service/map.ts +++ b/apps/dm/app/(popup-layout)/map/service/map.ts @@ -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', diff --git a/apps/dm/components/ui/sdmInfoInsertForm/component.tsx b/apps/dm/components/ui/sdmInfoInsertForm/component.tsx index 5cfa526b8..2ba965a6e 100644 --- a/apps/dm/components/ui/sdmInfoInsertForm/component.tsx +++ b/apps/dm/components/ui/sdmInfoInsertForm/component.tsx @@ -896,7 +896,7 @@ export function SdmInfoRegForm({
{ field.onChange(e.target.value); diff --git a/apps/fo/.env.local b/apps/fo/.env.local index 17c6c38cd..e9db65062 100644 --- a/apps/fo/.env.local +++ b/apps/fo/.env.local @@ -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 diff --git a/apps/fo/app/api/auth/logout/route.ts b/apps/fo/app/api/auth/logout/route.ts index 8832d35a3..f96bb544d 100644 --- a/apps/fo/app/api/auth/logout/route.ts +++ b/apps/fo/app/api/auth/logout/route.ts @@ -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 }); } diff --git a/apps/fo/app/auth/login/route.ts b/apps/fo/app/auth/login/route.ts new file mode 100644 index 000000000..d954cbaa1 --- /dev/null +++ b/apps/fo/app/auth/login/route.ts @@ -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)); // 공단 환경 + } +} \ No newline at end of file diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index 9a99564e7..beca33f78 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -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; } diff --git a/apps/fo/app/page.tsx b/apps/fo/app/page.tsx index 473a7815c..cf94377eb 100644 --- a/apps/fo/app/page.tsx +++ b/apps/fo/app/page.tsx @@ -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); } diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index 77e4168ec..bf15f2493 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -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': diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx index e76778d89..c10fd50cf 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx @@ -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('tab_num1'); + // 그리드 관련 const {FacilityWaterQltyModal, searchFacilityWaterQltyListHist, @@ -68,6 +70,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe } = FacilityWaterQltyModal; const prevExcelListRef = useRef(null); + const prevChoinginExcelListRef = useRef(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 ( <> - + setTabName(value)}> @@ -555,7 +591,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe {/* 총인설비 수질현황 */} - + diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index a107dfd2a..cb4861971 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -48,7 +48,8 @@ export default function ProcessFacilitySearch() { } = FacilityWaterQltyMain; const mainList: FacilityWaterQltyProps[] = facilityWaterQltyList || []; - + const [initTrigger, setInitTrigger] = useState(false); + const [excelTrigger, setExcelTrigger] = useState(false); // 그리드 관련 const [resetPage, setResetPage] = useState(false); const searchInputRef = useRef(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({ 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"}/>
- index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total<10?facilityWaterQltyList.length:total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> + index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
diff --git a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx index 30b97c945..42512f802 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -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]} />
+
+ +
@@ -257,6 +263,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st boldArray={[0,1,2]} /> +
+ +
@@ -281,6 +290,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st boldArray={[0,1,2]} /> +
+ +
@@ -305,6 +317,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st boldArray={[0,1,2]} /> +
+ +
@@ -319,7 +334,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
{}} className="h-[370px]" boldArray={[0,1,2]}/>
- +
+ +
diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index 5b53f51a2..a7e0933eb 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -67,9 +67,12 @@ export default function ProcessFacilitySearch() { const [selectedRow, setSelectedRow] = useState(null); const [fcltyNm, setFcltyNm] = useState(""); const [fcltyCd, setFcltyCd] = useState(""); - + const [excelTrigger, setExcelTrigger] = useState(false); + const [initTrigger, setInitTrigger] = useState(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({ 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 ( @@ -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"> diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 1f1768af5..fa993715e 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -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"> diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index fc571c665..94be9bd0b 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -71,7 +71,7 @@ export default function ProcessArea() { middleRegionValue: '', envPartValue: '', sidoText: '', - sigunText: '' + sigunText: '', }); const searchProcessArea = useCallback(({ sidoText, sigunText}: ReturnType, pageNo: number, pageCnt:number=20) => { diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 69fb49b14..f581c0def 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -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"> diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index 87bc8e7a8..e7bae003f 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -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) => { diff --git a/apps/fo/app/pages/(with-layout)/test/page.tsx b/apps/fo/app/pages/(with-layout)/test/page.tsx new file mode 100644 index 000000000..86689df10 --- /dev/null +++ b/apps/fo/app/pages/(with-layout)/test/page.tsx @@ -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> + ); +} \ No newline at end of file diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 52184d591..8ac105698 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -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 && ( diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index d0ddc6090..0eafcfcd0 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -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 diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 05a41e556..66d639fb8 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -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) { diff --git a/apps/fo/app/store/planSewage/index.tsx b/apps/fo/app/store/planSewage/index.tsx index 80a4d66e7..44ab12440 100644 --- a/apps/fo/app/store/planSewage/index.tsx +++ b/apps/fo/app/store/planSewage/index.tsx @@ -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 } } diff --git a/apps/fo/app/store/processArea/index.tsx b/apps/fo/app/store/processArea/index.tsx index 37b4d52f0..8a8b3075e 100644 --- a/apps/fo/app/store/processArea/index.tsx +++ b/apps/fo/app/store/processArea/index.tsx @@ -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[] = []; diff --git a/apps/fo/app/store/processFacility/index.tsx b/apps/fo/app/store/processFacility/index.tsx index 5cdab43b6..f4184865d 100644 --- a/apps/fo/app/store/processFacility/index.tsx +++ b/apps/fo/app/store/processFacility/index.tsx @@ -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 : '') : ''; diff --git a/apps/fo/app/store/rdi/index.tsx b/apps/fo/app/store/rdi/index.tsx index c22859043..6fd287432 100644 --- a/apps/fo/app/store/rdi/index.tsx +++ b/apps/fo/app/store/rdi/index.tsx @@ -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, diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx index 2f22cad81..7e58f83fe 100644 --- a/apps/fo/app/store/sewageOccur/index.tsx +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -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({ diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index a3238b306..0624886e9 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -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) diff --git a/apps/fo/middleware.ts b/apps/fo/middleware.ts index 4f491145f..f9891ff7d 100644 --- a/apps/fo/middleware.ts +++ b/apps/fo/middleware.ts @@ -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 }); } diff --git a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx index 0d69c260d..d3ae23177 100644 --- a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx @@ -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 로그인 페이지로 리다이렉트 } } })(); diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx index d55e1c9c2..e334d7d30 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/Ssc.tsx @@ -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) => { diff --git a/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx b/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx index b788b9cf6..39617eb21 100644 --- a/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx +++ b/apps/sn/app/(map-layout)/map/components/popupComponent/chart/rdiiChart.tsx @@ -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); diff --git a/apps/sn/app/(map-layout)/map/page.tsx b/apps/sn/app/(map-layout)/map/page.tsx index 651738642..90ec5a120 100644 --- a/apps/sn/app/(map-layout)/map/page.tsx +++ b/apps/sn/app/(map-layout)/map/page.tsx @@ -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'); } }; diff --git a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx index 13025e2ec..692551cbb 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx @@ -1,8 +1,8 @@ /** - * ➡️ 경로 : 하수관망도 메인 페이지 (오른쪽 돋보기 모양 클릭) - 검색 모달 창 내 운영정보 탭 + * ➡️ 경로 : 하수관망도 메인 페이지 (오른쪽 돋보기 모양 클릭) - 검색 모달 창 내 유지관리 정보 탭 * * 📄 Operation Tab - * Next.js App Router (app/) 기반 검색 모달 운영정보 탭 컴포넌트 + * Next.js App Router (app/) 기반 검색 모달 유지관리 정보 탭 컴포넌트 * * - 업무구분 선택 (보수 및 갱신, 점검 및 진단, 청소 및 준설) * - 사업명 입력 및 수행기간 범위 선택 diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index d2537663e..8da8911e5 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -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"> diff --git a/apps/sn/app/(map-layout)/map/searchModal/useOperationTab.ts b/apps/sn/app/(map-layout)/map/searchModal/useOperationTab.ts index a4df8ae92..669dd4cb5 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/useOperationTab.ts +++ b/apps/sn/app/(map-layout)/map/searchModal/useOperationTab.ts @@ -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조회 후 다시 시도해주세요."); diff --git a/apps/sn/app/(map-layout)/map/searchModal/useSearchModal.ts b/apps/sn/app/(map-layout)/map/searchModal/useSearchModal.ts index 770a8700d..1d317e3d4 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/useSearchModal.ts +++ b/apps/sn/app/(map-layout)/map/searchModal/useSearchModal.ts @@ -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 호출 함수 diff --git a/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx b/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx index 52685aaf8..c791a3f12 100644 --- a/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx @@ -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({ diff --git a/apps/sn/app/(with-base-layout)/ii/result/page.tsx b/apps/sn/app/(with-base-layout)/ii/result/page.tsx index 59ccf0b08..832809dcc 100644 --- a/apps/sn/app/(with-base-layout)/ii/result/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/result/page.tsx @@ -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({ diff --git a/apps/sn/app/(with-base-layout)/layout.tsx b/apps/sn/app/(with-base-layout)/layout.tsx index 228db9a79..346521d17 100644 --- a/apps/sn/app/(with-base-layout)/layout.tsx +++ b/apps/sn/app/(with-base-layout)/layout.tsx @@ -1,5 +1,5 @@ /** - * ➡️ 경로 : I/I분석, 운영정보 모든 페이지 + * ➡️ 경로 : I/I분석, 유지관리 정보 모든 페이지 * * 📄 With Base Layout * Next.js App Router (app/) 기반 분석 페이지 기본 레이아웃 컴포넌트 diff --git a/apps/sn/app/(with-base-layout)/oper/floodPre/page.tsx b/apps/sn/app/(with-base-layout)/oper/floodPre/page.tsx index 1a5999db6..ada56d443 100644 --- a/apps/sn/app/(with-base-layout)/oper/floodPre/page.tsx +++ b/apps/sn/app/(with-base-layout)/oper/floodPre/page.tsx @@ -1,5 +1,5 @@ /** - * ➡️ 경로 : 운영정보 - 도시침수예방사업 + * ➡️ 경로 : 유지관리 정보 - 도시침수예방사업 * * 📄 FloodPre Page * 침수예방 사업 정보 등록 및 조회 페이지 컴포넌트 diff --git a/apps/sn/app/(with-base-layout)/oper/oldPp/page.tsx b/apps/sn/app/(with-base-layout)/oper/oldPp/page.tsx index eee336a3b..6f26f70ec 100644 --- a/apps/sn/app/(with-base-layout)/oper/oldPp/page.tsx +++ b/apps/sn/app/(with-base-layout)/oper/oldPp/page.tsx @@ -1,5 +1,5 @@ /** - * ➡️ 경로 : 운영정보 - 노후 하수관로 정비사업 + * ➡️ 경로 : 유지관리 정보 - 노후 하수관로 정비사업 * * 📄 OldPp Page * 노후 하수관로 정비사업 추진현황 페이지 컴포넌트 diff --git a/apps/sn/app/api/auth/logout/route.ts b/apps/sn/app/api/auth/logout/route.ts index fdcc9df7c..37e758731 100644 --- a/apps/sn/app/api/auth/logout/route.ts +++ b/apps/sn/app/api/auth/logout/route.ts @@ -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 }); } diff --git a/apps/sn/app/auth/login/route.ts b/apps/sn/app/auth/login/route.ts new file mode 100644 index 000000000..d954cbaa1 --- /dev/null +++ b/apps/sn/app/auth/login/route.ts @@ -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)); // 공단 환경 + } +} \ No newline at end of file diff --git a/apps/sn/app/components/lib/api/index.ts b/apps/sn/app/components/lib/api/index.ts index 6b668294d..d567eec05 100644 --- a/apps/sn/app/components/lib/api/index.ts +++ b/apps/sn/app/components/lib/api/index.ts @@ -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> => { diff --git a/apps/sn/app/page.tsx b/apps/sn/app/page.tsx index d3e22baee..1babfe451 100644 --- a/apps/sn/app/page.tsx +++ b/apps/sn/app/page.tsx @@ -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"); }, []); } diff --git a/apps/sn/app/store/useSearchModalStore.ts b/apps/sn/app/store/useSearchModalStore.ts index 4d8702a08..1a74844bf 100644 --- a/apps/sn/app/store/useSearchModalStore.ts +++ b/apps/sn/app/store/useSearchModalStore.ts @@ -3,7 +3,7 @@ * 검색 모달 Zustand 스토어 * * - 검색 모달 열기/닫기 및 탭 전환 상태 관리 - * - 기본정보 및 운영정보 탭 데이터 필터링 및 조회 + * - 기본정보 및 유지관리 정보 탭 데이터 필터링 및 조회 * - 테이블 데이터 및 페이지네이션 상태 관리 * - 지역(시도/시군구) 및 날짜 범위 필터링 기능 * - 로딩 상태 및 리셋 플래그 관리 diff --git a/apps/sn/src/entities/auth/lib/auth-wrapper.tsx b/apps/sn/src/entities/auth/lib/auth-wrapper.tsx index e1b7f67d5..289a97087 100644 --- a/apps/sn/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/sn/src/entities/auth/lib/auth-wrapper.tsx @@ -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}</>; }; diff --git a/apps/wr/.env.local b/apps/wr/.env.local index fbce226c3..a35173615 100644 --- a/apps/wr/.env.local +++ b/apps/wr/.env.local @@ -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= diff --git a/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx index 472b8222f..d4e16b676 100644 --- a/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx +++ b/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx @@ -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"> diff --git a/apps/wr/app/(with-layout)/matMng/coMng/coSttn/page.tsx b/apps/wr/app/(with-layout)/matMng/coMng/coSttn/page.tsx index c8ffb904e..957130910 100644 --- a/apps/wr/app/(with-layout)/matMng/coMng/coSttn/page.tsx +++ b/apps/wr/app/(with-layout)/matMng/coMng/coSttn/page.tsx @@ -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, diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx index 24529c1b3..53c3e4403 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx @@ -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> diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/TableHead.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/TableHead.tsx index 9dd67dc44..608194f8a 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/TableHead.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/TableHead.tsx @@ -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 )} diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx index f3567210d..0b74c9a0b 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -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> diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx index 27fe7456f..4dcf82d70 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx @@ -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> diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx index bedb71815..75a2e6860 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx @@ -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) { diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index 6b4eead42..fe1bd06de 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -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> diff --git a/apps/wr/app/api/auth/logout/route.ts b/apps/wr/app/api/auth/logout/route.ts index 8832d35a3..f96bb544d 100644 --- a/apps/wr/app/api/auth/logout/route.ts +++ b/apps/wr/app/api/auth/logout/route.ts @@ -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 }); } diff --git a/apps/wr/app/auth/login/route.ts b/apps/wr/app/auth/login/route.ts new file mode 100644 index 000000000..d954cbaa1 --- /dev/null +++ b/apps/wr/app/auth/login/route.ts @@ -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)); // 공단 환경 + } +} \ No newline at end of file diff --git a/apps/wr/app/page.tsx b/apps/wr/app/page.tsx index 37fbe8b00..fb131e794 100644 --- a/apps/wr/app/page.tsx +++ b/apps/wr/app/page.tsx @@ -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"); }, []); } diff --git a/apps/wr/app/store/common/auth/index.tsx b/apps/wr/app/store/common/auth/index.tsx index 7eceacb39..7b647d5e7 100644 --- a/apps/wr/app/store/common/auth/index.tsx +++ b/apps/wr/app/store/common/auth/index.tsx @@ -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; + } + + }, }; }; diff --git a/apps/wr/app/store/common/type/header.tsx b/apps/wr/app/store/common/type/header.tsx index 29780ba03..75bf29433 100644 --- a/apps/wr/app/store/common/type/header.tsx +++ b/apps/wr/app/store/common/type/header.tsx @@ -24,5 +24,6 @@ export type TableUpperProps = { mergeCell?:boolean // 셀을 합칠경우 maxLength?:number readonly?:boolean + commonCode?:string // 공통코드 사용할경우 }; diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index 21636860a..2a4150a30 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -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}` diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index 1a0af3fad..9c36c4b57 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -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, diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx index e9ebdab8d..cf2eca339 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx @@ -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: { diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx index 6c2564655..13429fbc7 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx @@ -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, diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx index 837b669ec..efcfb03e6 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/bdstReg/index.tsx @@ -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) => ({ diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx index 28888d042..0dc6e3f75 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx @@ -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 }, + })); + }); + }, + }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 565909a57..e95c4c48d 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -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 }, + })); + }); + }, }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx index 57c5538f7..96b225c8a 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx @@ -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(), }); - - - diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx index 7fa3595fc..f38636507 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx @@ -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 }, + })); + }); + }, }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx index 9ed008ac5..ab77aaf6a 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx @@ -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, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx index 46a2f0e61..2bfd24664 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx @@ -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 ?? ""), //설치완료일시 diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx index ec772610d..5c9dbd638 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx @@ -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, diff --git a/apps/wr/app/store/stats/rainStat/headList.tsx b/apps/wr/app/store/stats/rainStat/headList.tsx index 664e060c4..7601919d5 100644 --- a/apps/wr/app/store/stats/rainStat/headList.tsx +++ b/apps/wr/app/store/stats/rainStat/headList.tsx @@ -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, }, { diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index 80787ae43..d08db404d 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -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") { diff --git a/apps/wr/app/store/stats/rswtStat/headList.tsx b/apps/wr/app/store/stats/rswtStat/headList.tsx index c0860fea7..47aeca57b 100644 --- a/apps/wr/app/store/stats/rswtStat/headList.tsx +++ b/apps/wr/app/store/stats/rswtStat/headList.tsx @@ -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, }, { diff --git a/apps/wr/app/store/stats/rswtStat/index.tsx b/apps/wr/app/store/stats/rswtStat/index.tsx index bd9a9c8e0..fa183f1a2 100644 --- a/apps/wr/app/store/stats/rswtStat/index.tsx +++ b/apps/wr/app/store/stats/rswtStat/index.tsx @@ -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; } } diff --git a/apps/wr/components/lib/api/index.ts b/apps/wr/components/lib/api/index.ts index 162ae9de3..6ff75f5a6 100644 --- a/apps/wr/components/lib/api/index.ts +++ b/apps/wr/components/lib/api/index.ts @@ -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(); }; diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx index 4e7773e0b..df5aaca77 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx @@ -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> </> ) } \ No newline at end of file diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx index 66c4da68f..11ce1b6f4 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx @@ -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, { diff --git a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx index 192a65397..72ec5e7e7 100644 --- a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx @@ -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> diff --git a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx index 72affedc9..f2a9d2f6d 100644 --- a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx @@ -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> diff --git a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx index 522c9b4fe..95b4915be 100644 --- a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx @@ -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> diff --git a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx index 24a983dce..4b84491a2 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx @@ -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")); } diff --git a/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx index fb2754050..9d349a6dd 100644 --- a/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx @@ -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]); diff --git a/apps/wr/public/locales/ko/message.json b/apps/wr/public/locales/ko/message.json index fa122d798..ee1bead78 100644 --- a/apps/wr/public/locales/ko/message.json +++ b/apps/wr/public/locales/ko/message.json @@ -23,5 +23,6 @@ "costCalcErrMsg": "공사비 계산 진행 후 저장을 눌러주세요", "maxYearErrMsg": "최대 {{year}}년까지 선택가능합니다.", "checkQtyMsg": "요구수량(m³/일)을 확인해주세요 계산할 수 없습니다.", - "insertRuseBiz": "{{cycle}}차 사업이 추가되었습니다." + "insertRuseBiz": "{{cycle}}차 사업이 추가되었습니다.", + "noUserInfoMsg": "사용자 정보가 없습니다. 다시 로그인해주세요." } \ No newline at end of file diff --git a/apps/wr/src/entities/auth/lib/auth-wrapper.tsx b/apps/wr/src/entities/auth/lib/auth-wrapper.tsx index 1a4461c3f..dcc6e81cd 100644 --- a/apps/wr/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/wr/src/entities/auth/lib/auth-wrapper.tsx @@ -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}</>; }; diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx index 21e1a27bb..6d4bf8acf 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -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 ?? ""} /> ), }, diff --git a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx index 6dbefef4f..1b9aed0a0 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx @@ -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> } diff --git a/packages/common/business_components/src/ui/search_base_form/index.tsx b/packages/common/business_components/src/ui/search_base_form/index.tsx index f99963f14..82798db0b 100644 --- a/packages/common/business_components/src/ui/search_base_form/index.tsx +++ b/packages/common/business_components/src/ui/search_base_form/index.tsx @@ -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> diff --git a/packages/common/business_components/src/ui/search_form_left/index.tsx b/packages/common/business_components/src/ui/search_form_left/index.tsx index a989995ed..04537ec5e 100644 --- a/packages/common/business_components/src/ui/search_form_left/index.tsx +++ b/packages/common/business_components/src/ui/search_form_left/index.tsx @@ -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}