From 2ec793fd597c9bc06544ac11160ea2da55db0e3f Mon Sep 17 00:00:00 2001 From: dongsilove Date: Mon, 29 Dec 2025 11:00:38 +0900 Subject: [PATCH 01/92] =?UTF-8?q?fo:=20UiTable=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/planSewage/page.tsx | 66 +++++++++---------- .../src/ui/table/index.tsx | 20 +++--- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 1f8bd1e94..62ae9483a 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -20,13 +20,13 @@ const commentArray = [ ] export default function PlanSewage() { - const {Common - ,PlanSewage - ,PlanSewageSearch - ,initializeCommonData - ,searchPlanSewageList - } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }}; - + const { Common + , PlanSewage + , PlanSewageSearch + , initializeCommonData + , searchPlanSewageList + } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] } }; + const { isInit, selectUpdownData, @@ -42,7 +42,7 @@ export default function PlanSewage() { } = Common; const { - labelArray, + labelArray, } = PlanSewageSearch; const { @@ -69,9 +69,9 @@ export default function PlanSewage() { // 그리드 관련 const searchInputRef = useRef(null); - + // 모달 상태 추가 - + // 초기화 변수 const [resetPage, setResetPage] = useState(false); // 표 너비 @@ -109,17 +109,17 @@ export default function PlanSewage() { input.value = ""; } } - ref.current.sidoValue='11'; + ref.current.sidoValue = '11'; searchPlanSewage(ref.current, 1, 10); } useEffect(() => { - if(!excelTrigger) return; + if (!excelTrigger) return; if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '계획하수량 산정지표 현황', + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '계획하수량 산정지표 현황', sheetNameArray: ['계획하수량 산정지표 현황'], headerRange: 'A1:M1' }); @@ -130,31 +130,31 @@ export default function PlanSewage() { * 콜백함수 */ // 조회 - const searchPlanSewage = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchPlanSewage = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => { let nameCd, partStr switch (partValue) { case 'R': if (regionValue !== '0') { - if(unitWaterShedValue==='0') nameCd = regionValue; - else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + if (unitWaterShedValue === '0') nameCd = regionValue; + else if (middleRegionValue === '0') nameCd = unitWaterShedValue; else nameCd = middleRegionValue; } partStr = partValue break; default: - if(sidoValue !== '0') nameCd = ref.current.sidoValue!="0"?ref.current.sidoValue:sidoValue; - if(sigunValue !== '0') nameCd = sigunValue; - partStr = envPartValue !== '0' ? envPartValue:partValue; + 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 === 'G'){ - partValue = partValue==='G'?'A':partValue; + if (partStr === 'G') { + partValue = partValue === 'G' ? 'A' : partValue; searchPlanSewageList(pageNo, pageCnt, searchYear, partValue); } - else{ + else { searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); - } + } }, [operationValue, fcltyName, searchPlanSewageList, searchYear, fcltCpct]); /** @@ -162,7 +162,7 @@ export default function PlanSewage() { */ useEffect(() => { if (!isInit) { - if(!initTrigger){ + if (!initTrigger) { initializeCommonData(); searchPlanSewage(ref.current, 1, 10); setInitTrigger(true); @@ -170,9 +170,9 @@ export default function PlanSewage() { } }, [isInit, initializeCommonData, searchPlanSewageList, selectSearchYear, initTrigger, searchPlanSewage]); - const chkVal = useCallback((returntype:ReturnType) => { + const chkVal = useCallback((returntype: ReturnType) => { // setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") - setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G' ? upHeadList3 : upHeadList1); setResetPage(true); }, [upHeadList1, upHeadList2, upHeadList3]); @@ -190,11 +190,11 @@ export default function PlanSewage() { const mainList = planSewageList || []; const total = planSewageCount || 0; - + return ( - <SearchBaseForm + <SearchBaseForm leftChildren={<> <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> <SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> @@ -212,12 +212,12 @@ export default function PlanSewage() { queryClick={chkVal} excelClick={excelDownload} initClick={resetVal} - ref={ref} isAdmin={false} initSidoValue={"11"}/> + ref={ref} isAdmin={false} initSidoValue={"11"} /> <ListDiv> <LoadingOverlay isLoading={isLoading} /> <div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden"> - <div className="w-[120%] min-[1200px]:w-[100%]"> - <UiTable cellClick={ undefined } headName={"계획하수량 산정지표 현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> + <div className="w-[120%] min-[1200px]:w-[100%]"> + <UiTable cellClick={undefined} headName={"계획하수량 산정지표 현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> </div> <UnderComment divHeight={"5"} commentArray={commentArray} /> </div> diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index dc763d00b..f62831959 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -43,6 +43,7 @@ type UiHeadProps = { row?: number; widthPercent?: number; rowSpan?: number; + colSpan?: number; }; export function UiTable({ @@ -136,13 +137,13 @@ export function UiTable({ <></> )} <div className={`card !p-0r !m-[1.2rem] ${className}`}> - <Table variant="secondary" className={widthFixed?"table-fixed":""}> - {widthFixed? - <colgroup> - {leafCols.map(col => ( - <col key={col.id} style={{ width: col.widthPercent ? `${col.widthPercent}%` : undefined }} /> - ))} - </colgroup>:""} + <Table variant="secondary" className={widthFixed ? "table-fixed" : ""}> + {widthFixed ? + <colgroup> + {leafCols.map(col => ( + <col key={col.id} style={{ width: col.widthPercent ? `${col.widthPercent}%` : undefined }} /> + ))} + </colgroup> : ""} <TableHeader ref={headerRef} className="font-bold"> {children ? children : <HeadMakeColSpan upHeadList={headlist} />} </TableHeader> @@ -261,7 +262,10 @@ export function UiTable({ <TableRow> <TableCell colSpan={ - headlist.filter((item) => item.visible != false).length + headlist.filter((item) => item.visible != false).length - + headlist.filter( + (item) => item.visible != false && item.colSpan, + ).length } className="h-24 text-center text-gray-500" > From 39d0f586af0ebe1bf319e42a869aeca19e10bec3 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 29 Dec 2025 17:22:06 +0900 Subject: [PATCH 02/92] =?UTF-8?q?fo:=20dashboard=20=EC=88=98=EC=A7=88=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 2073 +++++++++++++------------ 1 file changed, 1037 insertions(+), 1036 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index b5f678a22..d1fbdcfe1 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -22,93 +22,93 @@ export type TableUpperProps = { title: string; upName?: string; upSequnce?: number; - align? : string; - row? : number; + align?: string; + row?: number; rowSpan?: number; colSpan?: number; - widthPercent? : number; + widthPercent?: number; } // ===TAB1 // main fclty export type mainFcltyProps = { - fcltyNm : string, - facilityCapacity : string, - publicMethod : string, - location : string + fcltyNm: string, + facilityCapacity: string, + publicMethod: string, + location: string } // 시설계획 export type planFcltyListProps = { - item : string, - provisionalApproval : string | number | '', - now : string | number | '', - stepOne : string | number | '', - stepTwo : string | number | '', - stepThree : string | number | '', - stepFour : string | number | '', + item: string, + provisionalApproval: string | number | '', + now: string | number | '', + stepOne: string | number | '', + stepTwo: string | number | '', + stepThree: string | number | '', + stepFour: string | number | '', } // 운영실태 export type OperationalStatusListProps = { - flowRate : string, - waterQlty : string, - yearAvg : number | '', - yearMax : number | '', - yearMin : number | '', - summerAll : number | string | '', - summerThree : number | string | '', - summerRain : number | string | '', - winterAll : number | string | '', - winterSunnyAvg : number | string | '', - winterSunnyMax : number | string | '', - winterSunnyMin : number | string | '', - groundWaterAvg : number | string | '', - groundWaterSummer : number | string | '', - groundWaterWinter : number | string | '', - rdi : number | string | '', - rdiRain : number | string | '', + flowRate: string, + waterQlty: string, + yearAvg: number | '', + yearMax: number | '', + yearMin: number | '', + summerAll: number | string | '', + summerThree: number | string | '', + summerRain: number | string | '', + winterAll: number | string | '', + winterSunnyAvg: number | string | '', + winterSunnyMax: number | string | '', + winterSunnyMin: number | string | '', + groundWaterAvg: number | string | '', + groundWaterSummer: number | string | '', + groundWaterWinter: number | string | '', + rdi: number | string | '', + rdiRain: number | string | '', } export interface operationalStatusListProps { - flowRate : string, - waterQlty : string, - yearAvg : number | '', - yearMax : number | '', - yearMin : number | '', - summerAll : number | '', - summerThree : number | '', - summerRain : number | '', - winterAll : number | '', - winterSunnyAvg : number | '', - winterSunnyMax : number | '', - winterSunnyMin : number | '', - groundWaterAvg : number | string | '', - groundWaterSummer : number | string | '', - groundWaterWinter : number | string | '', - rdi : number | '', + flowRate: string, + waterQlty: string, + yearAvg: number | '', + yearMax: number | '', + yearMin: number | '', + summerAll: number | '', + summerThree: number | '', + summerRain: number | '', + winterAll: number | '', + winterSunnyAvg: number | '', + winterSunnyMax: number | '', + winterSunnyMin: number | '', + groundWaterAvg: number | string | '', + groundWaterSummer: number | string | '', + groundWaterWinter: number | string | '', + rdi: number | '', } // 차트 export type lineBarChartDataProps = { - label : string, - lineVal : number - barVal : number - barVal0 : number - barVal1 : number - lineVal0 : number - lineVal1 : number + label: string, + lineVal: number + barVal: number + barVal0: number + barVal1: number + lineVal0: number + lineVal1: number } export type lineChartDataProps = { - label : string, - val : number, + label: string, + val: number, } export interface RainManageListProps { - rainItem : string, - rainRate : string, - rainDay : number, + rainItem: string, + rainRate: string, + rainDay: number, bscFctCd?: string, bscFctNm?: string, msrDt?: string @@ -126,10 +126,10 @@ export interface RainManageListProps { efflWqltSs: number | '', efflWqltTn: number | '', efflWqltTp: number | '', - rgnNm?:string|'', - rvbsn?:string|'', - lgbsn?:string|'', - mdmbsn?:string|'', + rgnNm?: string | '', + rvbsn?: string | '', + lgbsn?: string | '', + mdmbsn?: string | '', inflAmnt: number | '', lclgvrnmntNm?: string, infoRnDay?: number | '', @@ -149,7 +149,7 @@ export interface RainManageListProps { dsInflWqltTp: number | '', extnsSeqno?: number | '', rainEffectDay?: number | '', - toBeInfoRnDay? : number | '', + toBeInfoRnDay?: number | '', } export interface RainManageExcelType { @@ -157,7 +157,7 @@ export interface RainManageExcelType { 강우조건비율: number | '', 일수: number | '', 유입유량: string | number | '', - 시설용량대비: string |number | '', + 시설용량대비: string | number | '', 설계유입수질BOD: string | number | '', 설계유입수질TOC: string | number | '', 설계유입수질SS: string | number | '', @@ -169,533 +169,533 @@ export interface RainManageExcelType { 유입수질TN: string | number | '', 유입수질TP: string | number | '', 방류수질BOD: string | number | '', - 방류수질TOC: string |number | '', + 방류수질TOC: string | number | '', 방류수질SS: string | number | '', 방류수질TN: string | number | '', 방류수질TP: string | number | '', } export interface DrainageEquipmentListProps { - part1 : string | '', - part2 : string | '', - nowSum : number | '', - nowJoin : number | '', - nowSep : number | '', - stepOneSum : number | '', - stepOneJoin : number | '', - stepOneSep : number | '', - stepTwoSum : number | '', - stepTwoJoin : number | '', - stepTwoSep : number | '', - stepThreeSum : number | '', - stepThreeJoin : number | '', - stepThreeSep : number | '', - stepFourSum : number | '', - stepFourJoin : number | '', - stepFourSep : number | '', - etc : string | '', + part1: string | '', + part2: string | '', + nowSum: number | '', + nowJoin: number | '', + nowSep: number | '', + stepOneSum: number | '', + stepOneJoin: number | '', + stepOneSep: number | '', + stepTwoSum: number | '', + stepTwoJoin: number | '', + stepTwoSep: number | '', + stepThreeSum: number | '', + stepThreeJoin: number | '', + stepThreeSep: number | '', + stepFourSum: number | '', + stepFourJoin: number | '', + stepFourSep: number | '', + etc: string | '', } export interface DrainageEquipmentExcelType { - partOne : string | '', - partTwo : string | '', - nowSum : number | '', - nowJoin : number | '', - nowSep : number | '', - stepOneSum : number | '', - stepOneJoin : number | '', - stepOneSep : number | '', - stepTwoSum : number | '', - stepTwoJoin : number | '', - stepTwoSep : number | '', - stepThreeSum : number | '', - stepThreeJoin : number | '', - stepThreeSep : number | '', - stepFourSum : number | '', - stepFourJoin : number | '', - stepFourSep : number | '', + partOne: string | '', + partTwo: string | '', + nowSum: number | '', + nowJoin: number | '', + nowSep: number | '', + stepOneSum: number | '', + stepOneJoin: number | '', + stepOneSep: number | '', + stepTwoSum: number | '', + stepTwoJoin: number | '', + stepTwoSep: number | '', + stepThreeSum: number | '', + stepThreeJoin: number | '', + stepThreeSep: number | '', + stepFourSum: number | '', + stepFourJoin: number | '', + stepFourSep: number | '', } /** * Store - data */ // Main -const DashBoardTopLabelArray:string[] = ['구분', '시도', '시군구', '년도', '시설명']; +const DashBoardTopLabelArray: string[] = ['구분', '시도', '시군구', '년도', '시설명']; // === Tab1 // grid header -const upHeadListFclty:TableUpperProps[] = [ - { id : "fcltyNm", title : "시설명"}, - { id : "facilityCapacity", title : "시설용량(m³/일)"}, - { id : "publicMethod", title : "공법"}, - { id : "location", title : "지역구"}, +const upHeadListFclty: TableUpperProps[] = [ + { id: "fcltyNm", title: "시설명" }, + { id: "facilityCapacity", title: "시설용량(m³/일)" }, + { id: "publicMethod", title: "공법" }, + { id: "location", title: "지역구" }, ] -const fcltyList : mainFcltyProps[] = [ +const fcltyList: mainFcltyProps[] = [ ] function getPlanYearList(): string[] { - const currentYear = new Date().getFullYear(); // 올해 - const startYear = currentYear - 4; // 5년 전 - const endYear = currentYear + 1; // 내년 + const currentYear = new Date().getFullYear(); // 올해 + const startYear = currentYear - 4; // 5년 전 + const endYear = currentYear + 1; // 내년 - const years: string[] = []; + const years: string[] = []; - for (let y = startYear; y <= endYear; y++) { - years.push(String(y)); // 혹은 y.toString() - } + for (let y = startYear; y <= endYear; y++) { + years.push(String(y)); // 혹은 y.toString() + } - return years; + return years; } -let planYearList : string[] = getPlanYearList(); +let planYearList: string[] = getPlanYearList(); -const upHeadListPlanFclty : TableUpperProps[] = [ - { id: "item", title: "", upName:"upChangeRe", upSequnce:1 }, - { id: "provisionalApproval", title: "기승인\n4단계", upName:"upChangeRe", upSequnce:2 }, - { id: "now", title: "현재", upName:"upChangeRe", upSequnce:3 }, - { id: "stepOne", title: "1단계", upName:"upChangeRe", upSequnce:4 }, - { id: "stepTwo", title: "2단계", upName:"upChangeRe", upSequnce:5 }, - { id: "stepThree", title: "3단계", upName:"upChangeRe", upSequnce:6 }, - { id: "stepFour", title: "4단계", upName:"upChangeRe", upSequnce:7 }, +const upHeadListPlanFclty: TableUpperProps[] = [ + { id: "item", title: "", upName: "upChangeRe", upSequnce: 1 }, + { id: "provisionalApproval", title: "기승인\n4단계", upName: "upChangeRe", upSequnce: 2 }, + { id: "now", title: "현재", upName: "upChangeRe", upSequnce: 3 }, + { id: "stepOne", title: "1단계", upName: "upChangeRe", upSequnce: 4 }, + { id: "stepTwo", title: "2단계", upName: "upChangeRe", upSequnce: 5 }, + { id: "stepThree", title: "3단계", upName: "upChangeRe", upSequnce: 6 }, + { id: "stepFour", title: "4단계", upName: "upChangeRe", upSequnce: 7 }, ] // 시설계획 좌측 상단 -const planFcltyList:planFcltyListProps[] = [ +const planFcltyList: planFcltyListProps[] = [ { - item : "1.증설계획\n(㎥/일)", + item: "1.증설계획\n(㎥/일)", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "2.처리인구(인)", + item: "2.처리인구(인)", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "3.처리구역\n(km²)", + item: "3.처리구역\n(km²)", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "4.분류식화율\n(%)", + item: "4.분류식화율\n(%)", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "5.물사용량", + item: "5.물사용량", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "년도\n(최근 3개년)", + item: "년도\n(최근 3개년)", provisionalApproval: "물사용량\n(㎥/일)", now: "", stepOne: "", stepTwo: "비고", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "2021", + item: "2021", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "2022", + item: "2022", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, { - item : "2023", + item: "2023", provisionalApproval: "", now: "", stepOne: "", stepTwo: "", stepThree: "", - stepFour : "", + stepFour: "", }, ] -const upHeadListOperationStatus : TableUpperProps[] = [ - { id: "flowRate", title: "유량 및 수질", upName:"upChangeRe1", upSequnce:1 }, - { id: "waterQlty", title: "유량 및 수질", upName:"upChangeRe1", upSequnce:2 }, - { id: "yearAvg", title: "평균", upName:"upChangeRe2", upSequnce:1 }, - { id: "yearMax", title: "최대", upName:"upChangeRe2", upSequnce:2 }, - { id: "yearMin", title: "최소", upName:"upChangeRe2", upSequnce:3 }, - { id: "summerAll", title: "전기간", upName:"upChangeRe3", upSequnce:1 }, - { id: "summerThree", title: "강우시\n(3mm이상)", upName:"upChangeRe3", upSequnce:2 }, - { id: "summerRain", title: "청천시", upName:"upChangeRe3", upSequnce:3 }, - { id: "winterAll", title: "전기간", upName:"upChangeRe4", upSequnce:1 }, - { id: "winterSunnyAvg", title: "청천시\n평균", upName:"upChangeRe4", upSequnce:2 }, - { id: "winterSunnyMax", title: "청천시\n최대", upName:"upChangeRe4", upSequnce:3 }, - { id: "winterSunnyMin", title: "청천시\n최소", upName:"upChangeRe4", upSequnce:4 }, - { id: "groundWaterAvg", title: "연평균", upName:"upChangeRe5", upSequnce:1 }, - { id: "groundWaterSummer", title: "하절기\n평균", upName:"upChangeRe5", upSequnce:2 }, - { id: "groundWaterWinter", title: "동절기\n평균", upName:"upChangeRe5", upSequnce:3 }, +const upHeadListOperationStatus: TableUpperProps[] = [ + { id: "flowRate", title: "유량 및 수질", upName: "upChangeRe1", upSequnce: 1 }, + { id: "waterQlty", title: "유량 및 수질", upName: "upChangeRe1", upSequnce: 2 }, + { id: "yearAvg", title: "평균", upName: "upChangeRe2", upSequnce: 1 }, + { id: "yearMax", title: "최대", upName: "upChangeRe2", upSequnce: 2 }, + { id: "yearMin", title: "최소", upName: "upChangeRe2", upSequnce: 3 }, + { id: "summerAll", title: "전기간", upName: "upChangeRe3", upSequnce: 1 }, + { id: "summerThree", title: "강우시\n(3mm이상)", upName: "upChangeRe3", upSequnce: 2 }, + { id: "summerRain", title: "청천시", upName: "upChangeRe3", upSequnce: 3 }, + { id: "winterAll", title: "전기간", upName: "upChangeRe4", upSequnce: 1 }, + { id: "winterSunnyAvg", title: "청천시\n평균", upName: "upChangeRe4", upSequnce: 2 }, + { id: "winterSunnyMax", title: "청천시\n최대", upName: "upChangeRe4", upSequnce: 3 }, + { id: "winterSunnyMin", title: "청천시\n최소", upName: "upChangeRe4", upSequnce: 4 }, + { id: "groundWaterAvg", title: "연평균", upName: "upChangeRe5", upSequnce: 1 }, + { id: "groundWaterSummer", title: "하절기\n평균", upName: "upChangeRe5", upSequnce: 2 }, + { id: "groundWaterWinter", title: "동절기\n평균", upName: "upChangeRe5", upSequnce: 3 }, { id: "rdi", title: "RDII 추정" }, { id: "rdiRain", title: "RDII 추정시\n일강수량(mm)" }, ] -const upHeadListRainManage : TableUpperProps[] = [ - { id: "rainItem", title: "강우량", row:0, rowSpan:2, widthPercent: 8 }, - { id: "rainRate", title: "강우조건\n비율(%)", row:0, rowSpan:2, align: "right", widthPercent: 5 }, - { id: "rainDay", title: "일수", row:0, rowSpan:2, align: "right", widthPercent: 5 }, - { id: "A", title: "유입(㎥/일)", row:0, colSpan:2 }, - { id: "inflAmnt", title: "유입유량", row:1, align: "right", widthPercent: 6 }, - { id: "fctCpc", title: "시설용량대비", row:1, align: "right", widthPercent: 6 }, - { id: "B", title: "설계유입수질(㎎/L)", row:0, colSpan:5 }, - { id: "dsInflWqltBod", title: "BOD", row:1, align: "right" }, - { id: "dsInflWqltCod", title: "TOC\n(COD)", row:1, align: "right" }, - { id: "dsInflWqltSs", title: "SS", row:1, align: "right" }, - { id: "dsInflWqltTn", title: "T-N", row:1, align: "right" }, - { id: "dsInflWqltTp", title: "T-P", row:1, align: "right" }, - { id: "C", title: "유입수질(㎎/L)", row:0, colSpan:5 }, - { id: "inflAssctBfrWqltBod", title: "BOD", row:1, align: "right" }, - { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)", row:1, align: "right" }, - { id: "inflAssctBfrWqltSs", title: "SS", row:1, align: "right" }, - { id: "inflAssctBfrWqltTn", title: "T-N", row:1, align: "right" }, - { id: "inflAssctBfrWqltTp", title: "T-P", row:1, align: "right" }, - { id: "D", title: "방류수질(㎎/L)", row:0, colSpan:5 }, - { id: "efflWqltBod", title: "BOD", row:1, align: "right" }, - { id: "efflWqltToc", title: "TOC\n(COD)", row:1, align: "right" }, - { id: "efflWqltSs", title: "SS", row:1, align: "right" }, - { id: "efflWqltTn", title: "T-N", row:1, align: "right" }, - { id: "efflWqltTp", title: "T-P", row:1, align: "right" }, +const upHeadListRainManage: TableUpperProps[] = [ + { id: "rainItem", title: "강우량", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "rainRate", title: "강우조건\n비율(%)", row: 0, rowSpan: 2, align: "right", widthPercent: 5 }, + { id: "rainDay", title: "일수", row: 0, rowSpan: 2, align: "right", widthPercent: 5 }, + { id: "A", title: "유입(㎥/일)", row: 0, colSpan: 2 }, + { id: "inflAmnt", title: "유입유량", row: 1, align: "right", widthPercent: 6 }, + { id: "fctCpc", title: "시설용량대비", row: 1, align: "right", widthPercent: 6 }, + { id: "B", title: "설계유입수질(㎎/L)", row: 0, colSpan: 5 }, + { id: "dsInflWqltBod", title: "BOD", row: 1, align: "right" }, + { id: "dsInflWqltCod", title: "TOC\n(COD)", row: 1, align: "right" }, + { id: "dsInflWqltSs", title: "SS", row: 1, align: "right" }, + { id: "dsInflWqltTn", title: "T-N", row: 1, align: "right" }, + { id: "dsInflWqltTp", title: "T-P", row: 1, align: "right" }, + { id: "C", title: "유입수질(㎎/L)", row: 0, colSpan: 5 }, + { id: "inflAssctBfrWqltBod", title: "BOD", row: 1, align: "right" }, + { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)", row: 1, align: "right" }, + { id: "inflAssctBfrWqltSs", title: "SS", row: 1, align: "right" }, + { id: "inflAssctBfrWqltTn", title: "T-N", row: 1, align: "right" }, + { id: "inflAssctBfrWqltTp", title: "T-P", row: 1, align: "right" }, + { id: "D", title: "방류수질(㎎/L)", row: 0, colSpan: 5 }, + { id: "efflWqltBod", title: "BOD", row: 1, align: "right" }, + { id: "efflWqltToc", title: "TOC\n(COD)", row: 1, align: "right" }, + { id: "efflWqltSs", title: "SS", row: 1, align: "right" }, + { id: "efflWqltTn", title: "T-N", row: 1, align: "right" }, + { id: "efflWqltTp", title: "T-P", row: 1, align: "right" }, ] -const upHeadListDrainageEquipment : TableUpperProps[] = [ - { id: "part1", title: "구분", row:0, upName:"upChangeRe1", upSequnce:1 }, - { id: "part2", title: "구분", row:0, upName:"upChangeRe1", upSequnce:2 }, - { id: "nowSum", title: "계", row:2, upName:"upChangeRe2", upSequnce:1 }, - { id: "nowJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe2", upSequnce:2 }, - { id: "nowSep", title: "분리식\n가구수", row:2, upName:"upChangeRe2", upSequnce:3 }, - { id: "stepOneSum", title: "계", row:2, upName:"upChangeRe3", upSequnce:1 }, - { id: "stepOneJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe3", upSequnce:2 }, - { id: "stepOneSep", title: "분리식\n가구수", row:2, upName:"upChangeRe3", upSequnce:3 }, - { id: "stepTwoSum", title: "계", row:2, upName:"upChangeRe4", upSequnce:1 }, - { id: "stepTwoJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe4", upSequnce:2 }, - { id: "stepTwoSep", title: "분리식\n가구수", row:2, upName:"upChangeRe4", upSequnce:3 }, - { id: "stepThreeSum", title: "계", row:2, upName:"upChangeRe5", upSequnce:1 }, - { id: "stepThreeJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe5", upSequnce:2 }, - { id: "stepThreeSep", title: "분리식\n가구수", row:2, upName:"upChangeRe5", upSequnce:3 }, - { id: "stepFourSum", title: "계", row:2, upName:"upChangeRe6", upSequnce:1 }, - { id: "stepFourJoin", title: "합류식\n가구수", row:2, upName:"upChangeRe6", upSequnce:2 }, - { id: "stepFourSep", title: "분리식\n가구수", row:2, upName:"upChangeRe6", upSequnce:3 }, - { id: "etc", title: "비고", row:0, upName:"upChangeRe7", upSequnce:1 }, +const upHeadListDrainageEquipment: TableUpperProps[] = [ + { id: "part1", title: "구분", row: 0, upName: "upChangeRe1", upSequnce: 1 }, + { id: "part2", title: "구분", row: 0, upName: "upChangeRe1", upSequnce: 2 }, + { id: "nowSum", title: "계", row: 2, upName: "upChangeRe2", upSequnce: 1 }, + { id: "nowJoin", title: "합류식\n가구수", row: 2, upName: "upChangeRe2", upSequnce: 2 }, + { id: "nowSep", title: "분리식\n가구수", row: 2, upName: "upChangeRe2", upSequnce: 3 }, + { id: "stepOneSum", title: "계", row: 2, upName: "upChangeRe3", upSequnce: 1 }, + { id: "stepOneJoin", title: "합류식\n가구수", row: 2, upName: "upChangeRe3", upSequnce: 2 }, + { id: "stepOneSep", title: "분리식\n가구수", row: 2, upName: "upChangeRe3", upSequnce: 3 }, + { id: "stepTwoSum", title: "계", row: 2, upName: "upChangeRe4", upSequnce: 1 }, + { id: "stepTwoJoin", title: "합류식\n가구수", row: 2, upName: "upChangeRe4", upSequnce: 2 }, + { id: "stepTwoSep", title: "분리식\n가구수", row: 2, upName: "upChangeRe4", upSequnce: 3 }, + { id: "stepThreeSum", title: "계", row: 2, upName: "upChangeRe5", upSequnce: 1 }, + { id: "stepThreeJoin", title: "합류식\n가구수", row: 2, upName: "upChangeRe5", upSequnce: 2 }, + { id: "stepThreeSep", title: "분리식\n가구수", row: 2, upName: "upChangeRe5", upSequnce: 3 }, + { id: "stepFourSum", title: "계", row: 2, upName: "upChangeRe6", upSequnce: 1 }, + { id: "stepFourJoin", title: "합류식\n가구수", row: 2, upName: "upChangeRe6", upSequnce: 2 }, + { id: "stepFourSep", title: "분리식\n가구수", row: 2, upName: "upChangeRe6", upSequnce: 3 }, + { id: "etc", title: "비고", row: 0, upName: "upChangeRe7", upSequnce: 1 }, ] -const operationalStatusListOrg : OperationalStatusListProps[] = [ +const operationalStatusListOrg: OperationalStatusListProps[] = [ { - flowRate : '유량\n(㎥/일)', - waterQlty : '유입', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '유량\n(㎥/일)', + waterQlty: '유입', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '유량\n(㎥/일)', - waterQlty : '순수하수', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '유량\n(㎥/일)', + waterQlty: '순수하수', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '유량\n(㎥/일)', - waterQlty : '연계처리수', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '유량\n(㎥/일)', + waterQlty: '연계처리수', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '유량\n(㎥/일)', - waterQlty : '총인설비\n반류수', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '유량\n(㎥/일)', + waterQlty: '총인설비\n반류수', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '유량\n(㎥/일)', - waterQlty : '방류', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '유량\n(㎥/일)', + waterQlty: '방류', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '수질\n(mg/L)', - waterQlty : '유입\n(BOD)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '수질\n(mg/L)', + waterQlty: '유입\n(BOD)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '수질\n(mg/L)', - waterQlty : '방류\n(BOD)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '수질\n(mg/L)', + waterQlty: '방류\n(BOD)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '수질\n(mg/L)', - waterQlty : '유입\n(T-N)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '수질\n(mg/L)', + waterQlty: '유입\n(T-N)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '수질\n(mg/L)', - waterQlty : '방류\n(T-N)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '수질\n(mg/L)', + waterQlty: '방류\n(T-N)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '수질\n(mg/L)', - waterQlty : '유입\n(T-P)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '수질\n(mg/L)', + waterQlty: '유입\n(T-P)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '수질\n(mg/L)', - waterQlty : '방류\n(T-P)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '수질\n(mg/L)', + waterQlty: '방류\n(T-P)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '총인\n시설\n수질\n(mg/L)', - waterQlty : '총인설비\n유입(T-P)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '총인\n시설\n수질\n(mg/L)', + waterQlty: '총인설비\n유입(T-P)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, { - flowRate : '총인\n시설\n수질\n(mg/L)', - waterQlty : '총인설비\n방류(T-P)', - yearAvg : '', - yearMax : '', - yearMin : '', - summerAll : '', - summerThree : '', - summerRain : '', - winterAll : '', - winterSunnyAvg : '', - winterSunnyMax : '', - winterSunnyMin : '', - groundWaterAvg : '', - groundWaterSummer : '', - groundWaterWinter : '', - rdi : '', - rdiRain : '', + flowRate: '총인\n시설\n수질\n(mg/L)', + waterQlty: '총인설비\n방류(T-P)', + yearAvg: '', + yearMax: '', + yearMin: '', + summerAll: '', + summerThree: '', + summerRain: '', + winterAll: '', + winterSunnyAvg: '', + winterSunnyMax: '', + winterSunnyMin: '', + groundWaterAvg: '', + groundWaterSummer: '', + groundWaterWinter: '', + rdi: '', + rdiRain: '', }, ] -const chart_inflowRain : lineBarChartDataProps[] = []; -const chart_bodRain : lineBarChartDataProps[] = []; -const chart_inflTp : lineChartDataProps[] = []; -const chart_chongInTp : lineChartDataProps[] = []; -const chart_efflTp : lineChartDataProps[] = []; -const chart_inflTn : lineChartDataProps[] = []; -const chart_efflTn : lineChartDataProps[] = []; -const chart_inflBod : lineChartDataProps[] = []; -const chart_efflBod : lineChartDataProps[] = []; -const waterQltyStandartd : any = []; +const chart_inflowRain: lineBarChartDataProps[] = []; +const chart_bodRain: lineBarChartDataProps[] = []; +const chart_inflTp: lineChartDataProps[] = []; +const chart_chongInTp: lineChartDataProps[] = []; +const chart_efflTp: lineChartDataProps[] = []; +const chart_inflTn: lineChartDataProps[] = []; +const chart_efflTn: lineChartDataProps[] = []; +const chart_inflBod: lineChartDataProps[] = []; +const chart_efflBod: lineChartDataProps[] = []; +const waterQltyStandartd: any = []; -const rainManageList : RainManageListProps[] = []; +const rainManageList: RainManageListProps[] = []; -const drainageEquipmentList : DrainageEquipmentListProps[] = [ +const drainageEquipmentList: DrainageEquipmentListProps[] = [ { - part1 : '청천시청', - part2 : '청천시청', - nowSum : 101, - nowJoin : 102, - nowSep : 103, - stepOneSum : 104, - stepOneJoin : 105, - stepOneSep : 106, - stepTwoSum : 107, - stepTwoJoin : 108, - stepTwoSep : 109, - stepThreeSum : 110, - stepThreeJoin : 111, - stepThreeSep : 112, - stepFourSum : 113, - stepFourJoin : 114, - stepFourSep : 115, - etc : '1050', + part1: '청천시청', + part2: '청천시청', + nowSum: 101, + nowJoin: 102, + nowSep: 103, + stepOneSum: 104, + stepOneJoin: 105, + stepOneSep: 106, + stepTwoSum: 107, + stepTwoJoin: 108, + stepTwoSep: 109, + stepThreeSum: 110, + stepThreeJoin: 111, + stepThreeSep: 112, + stepFourSum: 113, + stepFourJoin: 114, + stepFourSep: 115, + etc: '1050', } ]; @@ -703,50 +703,50 @@ const drainageEquipmentList : DrainageEquipmentListProps[] = [ * Store - api (데이터 호출) ====================================*/ /* 시설정보 및 운영현황 - 계획 */ -const fetchFacilityPlan = async (targetYear : string | undefined, fcltyCd : string | undefined, set : (fn: (state: DashBoardType) => DashBoardType) => void) => { - try { - const res = await fetchPlanInfo(undefined, undefined, undefined, fcltyCd); - return res; - } catch (error) { - console.error('시설계획정보를 가져오는데 실패했습니다:', error); - set((state) => ({ - ...state, - PlanFclty : { - ...state.PlanFclty, - isLoadingPlanFclty : false, - isLoadingOperationStatus : false - } - })); - return {data: [], count: 0}; - } +const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string | undefined, set: (fn: (state: DashBoardType) => DashBoardType) => void) => { + try { + const res = await fetchPlanInfo(undefined, undefined, undefined, fcltyCd); + return res; + } catch (error) { + console.error('시설계획정보를 가져오는데 실패했습니다:', error); + set((state) => ({ + ...state, + PlanFclty: { + ...state.PlanFclty, + isLoadingPlanFclty: false, + isLoadingOperationStatus: false + } + })); + return { data: [], count: 0 }; + } }; /* 시설정보 및 운영현황 - 운영실태 */ -const fetchOperationStatus = async (searchYear: string|undefined, fcltyCd: string|undefined) => { - try{ - const url = '/dashBoard/mngInfo/' + (searchYear?searchYear:'2023') + '/' + (fcltyCd?fcltyCd:''); +const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined) => { + try { + const url = '/dashBoard/mngInfo/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : ''); const res = await getFetch('fo', url); return { data: res.data, count: res.count } - } catch (error) { + } catch (error) { console.error('운영실태 데이터를 가져오는데 실패했습니다:', error); return { data: [], count: 0 }; } } // 주요그래프 데이터 -const fetchMainGraph = async (searchYear: string|undefined, fcltyCd: string|undefined) => { - try { - const url = '/fclt/qlty/hist/' + (searchYear?searchYear:'2023') + '/' + (fcltyCd?fcltyCd:'11680PB001R'); +const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | undefined) => { + try { + const url = '/fclt/qlty/hist/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : '11680PB001R'); const res = await getFetch('fo', url); return { data: res.data, count: res.count } - } catch (error) { + } catch (error) { console.error('주요그래프 데이터를 가져오는데 실패했습니다:', error); return { data: [], count: 0 }; } } // 수질 데이터 청천시, 강우시 재계산 -const calcWaterQltyData = async (data: any[], searchYear : string|undefined, fcltyCd : string|undefined) => { +const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fcltyCd: string | undefined) => { const nullToZero = (value: any) => { return value === null || value === undefined || value === '' ? 0 : Number(value); @@ -754,180 +754,210 @@ const calcWaterQltyData = async (data: any[], searchYear : string|undefined, fcl const orgData = data; const res = await fetchMainGraph(searchYear, fcltyCd); - if(res.data.wqltObjs.length> 0) { + if (res.data.wqltObjs.length > 0) { const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; const qltyData = res.data.wqltObjs; - const qltyChungchunData = CalcRainEffect(clone(qltyData), 'SUNNY'); + // const qltyChungchunData = CalcRainEffect(clone(qltyData), 'SUNNY'); + + // 강우시 변수 + let rainSummerDay9 = 0, noNullRainSummerDay9 = 0; + let rainInflBodAvg9 = 0, rainInflTnAvg9 = 0, rainInflTpAvg9 = 0; + let rainEfflBodAvg9 = 0, rainEfflTnAvg9 = 0, rainEfflTpAvg9 = 0, rainTpInflAvg9 = 0; const qltyRainData = CalcRainEffect(clone(qltyData), 'RAIN'); + const rainEffectDayArray: string[] = []; + // 강우시 + qltyRainData.forEach((item: any) => { + const month = item.msrDt.substring(4, 6); // 월 추출 + if (month === '06' || month === '07' || month === '08') { + rainSummerDay9 += 1; + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullRainSummerDay9 += 1; + } + + rainInflBodAvg9 += nullToZero(item.inflAssctBfrWqltBod); + rainInflTnAvg9 += nullToZero(item.inflAssctBfrWqltTn); + rainInflTpAvg9 += nullToZero(item.inflAssctBfrWqltTp); + rainEfflBodAvg9 += nullToZero(item.efflWqltBod); + rainEfflTnAvg9 += nullToZero(item.efflWqltTn); + rainEfflTpAvg9 += nullToZero(item.efflWqltTp); + rainTpInflAvg9 += nullToZero(item.tpInflWqltTp); + } + }); + console.log("99999999999999999"); + console.log(rainSummerDay9, noNullRainSummerDay9, rainInflBodAvg9, rainInflTnAvg9, rainInflTpAvg9, rainEfflBodAvg9, rainEfflTnAvg9, rainEfflTpAvg9, rainTpInflAvg9); // (0) 전체변수 - let summerDay = 0; - let noNullSummerDay = 0; - let totalInflBodAvgSummer = 0; - let totalInflTnAvgSummer = 0; - let totalInflTpAvgSummer = 0; - let totalEfflBodAvgSummer = 0; - let totalEfflTnAvgSummer = 0; - let totalEfflTpAvgSummer = 0; - let totalTpInflAvgSummer = 0; + let summerDay = 0, noNullSummerDay = 0; + let totalInflBodAvgSummer = 0, totalInflTnAvgSummer = 0, totalInflTpAvgSummer = 0; + let totalEfflBodAvgSummer = 0, totalEfflTnAvgSummer = 0, totalEfflTpAvgSummer = 0, totalTpInflAvgSummer = 0; - let winterDay = 0; - let noNullWinterDay = 0; - let totalInflBodAvgWinter = 0; - let totalInflTnAvgWinter = 0; - let totalInflTpAvgWinter = 0; - let totalEfflBodAvgWinter = 0; - let totalEfflTnAvgWinter = 0; - let totalEfflTpAvgWinter = 0; - let totalTpInflAvgWinter = 0; + let winterDay = 0, noNullWinterDay = 0; + let totalInflBodAvgWinter = 0, totalInflTnAvgWinter = 0, totalInflTpAvgWinter = 0; + let totalEfflBodAvgWinter = 0, totalEfflTnAvgWinter = 0, totalEfflTpAvgWinter = 0, totalTpInflAvgWinter = 0; + // (1) 청천시 변수 + // (1-1) 날짜 count + let chungchunSummerDay = 0, noNullChungchunSummerDay = 0; + let chungchunWinterDay = 0, noNullChungchunWinterDay = 0; + + // (1-2) 하절기 + let chungchunInflBodAvgSummer = 0, chungchunInflTnAvgSummer = 0, chungchunInflTpAvgSummer = 0; + let chungchunEfflBodAvgSummer = 0, chungchunEfflTnAvgSummer = 0, chungchunEfflTpAvgSummer = 0; + let chungchunTpInflAvgSummer = 0; // 하절기 청천시 총인설비 유입TP + + // (1-3) 동절기 (최대, 최소, 평균 다 필요) + let chungchunInflBodAvg = 0, chungchunInflTnAvg = 0, chungchunInflTpAvg = 0, chungchunTpInflAvg = 0; + let chungchunInflBodMax = 0, chungchunInflTnMax = 0, chungchunInflTpMax = 0, chungchunTpInflMax = 0; + let chungchunInflBodMin = 99999999; + let chungchunInflTnMin = 99999999; + let chungchunInflTpMin = 99999999; + let chungchunTpInflMin = 99999999; + + let chungchunEfflBodAvg = 0, chungchunEfflTnAvg = 0, chungchunEfflTpAvg = 0; + let chungchunEfflBodMax = 0, chungchunEfflTnMax = 0, chungchunEfflTpMax = 0; + let chungchunEfflBodMin = 99999999; + let chungchunEfflTnMin = 99999999; + let chungchunEfflTpMin = 99999999; + + // 강우시 변수 + let rainSummerDay = 0, noNullRainSummerDay = 0; + let rainInflBodAvg = 0, rainInflTnAvg = 0, rainInflTpAvg = 0; + let rainEfflBodAvg = 0, rainEfflTnAvg = 0, rainEfflTpAvg = 0, rainTpInflAvg = 0; + + let rainEffectDay = 0; // 전체 대상 qltyData.forEach((item: any) => { + if (item.infoRnDay == null) item.infoRnDay = 0; const month = item.msrDt.substring(4, 6); // 월 추출 - if(month === '01' || month === '02'){ + + if (item.infoRnDay >= 3) { + rainEffectDay = 2; + } else { + rainEffectDay--; + } + + if (rainEffectDay >= 0) { + rainEffectDayArray.push(item.msrDt); + // 강우영향일 + if (month === '06' || month === '07' || month === '08') { + rainSummerDay += 1; + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullRainSummerDay += 1; + } + + rainInflBodAvg += nullToZero(item.inflAssctBfrWqltBod); + rainInflTnAvg += nullToZero(item.inflAssctBfrWqltTn); + rainInflTpAvg += nullToZero(item.inflAssctBfrWqltTp); + rainEfflBodAvg += nullToZero(item.efflWqltBod); + rainEfflTnAvg += nullToZero(item.efflWqltTn); + rainEfflTpAvg += nullToZero(item.efflWqltTp); + rainTpInflAvg += nullToZero(item.tpInflWqltTp); + } + } else if (rainEffectDay < 0) { //청천시 + + if (month === '01' || month === '02') { + chungchunWinterDay += 1; + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullChungchunWinterDay += 1; + } + + const inflbod = nullToZero(item.inflAssctBfrWqltBod); + const infltn = nullToZero(item.inflAssctBfrWqltTn); + const infltp = nullToZero(item.inflAssctBfrWqltTp); + const effbod = nullToZero(item.efflWqltBod); + const efftn = nullToZero(item.efflWqltTn); + const efftp = nullToZero(item.efflWqltTp); + const tpInfl = nullToZero(item.tpInflWqltTp); + + chungchunInflBodAvg += inflbod; + chungchunInflTnAvg += infltn; + chungchunInflTpAvg += infltp; + chungchunEfflBodAvg += effbod; + chungchunEfflTnAvg += efftn; + chungchunEfflTpAvg += efftp; + chungchunTpInflAvg += tpInfl; + + if (chungchunInflBodMax < inflbod) chungchunInflBodMax = inflbod; + if (chungchunInflTnMax < infltn) chungchunInflTnMax = infltn; + if (chungchunInflTpMax < infltp) chungchunInflTpMax = infltp; + if (chungchunEfflBodMax < effbod) chungchunEfflBodMax = effbod; + if (chungchunEfflTnMax < efftn) chungchunEfflTnMax = efftn; + if (chungchunEfflTpMax < efftp) chungchunEfflTpMax = efftp; + if (chungchunTpInflMax < tpInfl) chungchunTpInflMax = tpInfl; + + if (chungchunInflBodMin > inflbod) chungchunInflBodMin = inflbod; + if (chungchunInflTnMin > infltn) chungchunInflTnMin = infltn; + if (chungchunInflTpMin > infltp) chungchunInflTpMin = infltp; + if (chungchunEfflBodMin > effbod) chungchunEfflBodMin = effbod; + if (chungchunEfflTnMin > efftn) chungchunEfflTnMin = efftn; + if (chungchunEfflTpMin > efftp) chungchunEfflTpMin = efftp; + if (chungchunTpInflMin > tpInfl) chungchunTpInflMin = tpInfl; + } else if (month === '06' || month === '07' || month === '08') { + chungchunSummerDay += 1; + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullChungchunSummerDay += 1; + } + + chungchunInflBodAvgSummer += nullToZero(item.inflAssctBfrWqltBod); + chungchunInflTnAvgSummer += nullToZero(item.inflAssctBfrWqltTn); + chungchunInflTpAvgSummer += nullToZero(item.inflAssctBfrWqltTp); + chungchunEfflBodAvgSummer += nullToZero(item.efflWqltBod); + chungchunEfflTnAvgSummer += nullToZero(item.efflWqltTn); + chungchunEfflTpAvgSummer += nullToZero(item.efflWqltTp); + chungchunTpInflAvgSummer += nullToZero(item.tpInflWqltTp); + } + } + + + if (month === '01' || month === '02') { winterDay += 1; - if(item.tpInflWqltTp != null && item.tpInflWqltTp != 0){ - noNullWinterDay+=1; + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullWinterDay += 1; } totalInflBodAvgWinter += nullToZero(item.inflAssctBfrWqltBod); - totalInflTnAvgWinter += nullToZero(item.inflAssctBfrWqltTn); - totalInflTpAvgWinter += nullToZero(item.inflAssctBfrWqltTp); + totalInflTnAvgWinter += nullToZero(item.inflAssctBfrWqltTn); + totalInflTpAvgWinter += nullToZero(item.inflAssctBfrWqltTp); totalEfflBodAvgWinter += nullToZero(item.efflWqltBod); - totalEfflTnAvgWinter += nullToZero(item.efflWqltTn); - totalEfflTpAvgWinter += nullToZero(item.efflWqltTp); - totalTpInflAvgWinter += nullToZero(item.tpInflWqltTp); - }else if(month === '06' || month === '07' || month === '08'){ + totalEfflTnAvgWinter += nullToZero(item.efflWqltTn); + totalEfflTpAvgWinter += nullToZero(item.efflWqltTp); + totalTpInflAvgWinter += nullToZero(item.tpInflWqltTp); + } else if (month === '06' || month === '07' || month === '08') { summerDay += 1; - if(item.tpInflWqltTp != null && item.tpInflWqltTp != 0){ - noNullSummerDay+=1; + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullSummerDay += 1; } totalInflBodAvgSummer += nullToZero(item.inflAssctBfrWqltBod); - totalInflTnAvgSummer += nullToZero(item.inflAssctBfrWqltTn); - totalInflTpAvgSummer += nullToZero(item.inflAssctBfrWqltTp); + totalInflTnAvgSummer += nullToZero(item.inflAssctBfrWqltTn); + totalInflTpAvgSummer += nullToZero(item.inflAssctBfrWqltTp); totalEfflBodAvgSummer += nullToZero(item.efflWqltBod); - totalEfflTnAvgSummer += nullToZero(item.efflWqltTn); - totalEfflTpAvgSummer += nullToZero(item.efflWqltTp); - totalTpInflAvgSummer += nullToZero(item.tpInflWqltTp); + totalEfflTnAvgSummer += nullToZero(item.efflWqltTn); + totalEfflTpAvgSummer += nullToZero(item.efflWqltTp); + totalTpInflAvgSummer += nullToZero(item.tpInflWqltTp); } }); - orgData[5].winterAll = qltyDataSetting(totalInflBodAvgWinter, winterDay, 1); // 동절기 유입BOD - orgData[6].winterAll = qltyDataSetting(totalEfflBodAvgWinter, winterDay, 1); // 동절기 방류BOD - orgData[7].winterAll = qltyDataSetting(totalInflTnAvgWinter, winterDay, 3); // 동절기 유입TN - orgData[8].winterAll = qltyDataSetting(totalEfflTnAvgWinter, winterDay, 3); // 동절기 방류TN - orgData[9].winterAll = qltyDataSetting(totalInflTpAvgWinter, winterDay, 3); // 동절기 유입TP + orgData[5].winterAll = qltyDataSetting(totalInflBodAvgWinter, winterDay, 1); // 동절기 유입BOD + orgData[6].winterAll = qltyDataSetting(totalEfflBodAvgWinter, winterDay, 1); // 동절기 방류BOD + orgData[7].winterAll = qltyDataSetting(totalInflTnAvgWinter, winterDay, 3); // 동절기 유입TN + orgData[8].winterAll = qltyDataSetting(totalEfflTnAvgWinter, winterDay, 3); // 동절기 방류TN + orgData[9].winterAll = qltyDataSetting(totalInflTpAvgWinter, winterDay, 3); // 동절기 유입TP orgData[10].winterAll = qltyDataSetting(totalEfflTpAvgWinter, winterDay, 3); // 동절기 방류TP //총인설비 orgData[11].winterAll = qltyDataSetting(totalTpInflAvgWinter, noNullWinterDay, 3); orgData[12].winterAll = qltyDataSetting(totalEfflTpAvgWinter, winterDay, 3); - orgData[5].summerAll = qltyDataSetting(totalInflBodAvgSummer, summerDay, 1); // 하절기 유입BOD - orgData[6].summerAll = qltyDataSetting(totalEfflBodAvgSummer, summerDay, 1); // 하절기 방류BOD - orgData[7].summerAll = qltyDataSetting(totalInflTnAvgSummer, summerDay, 3); // 하절기 유입TN - orgData[8].summerAll = qltyDataSetting(totalEfflTnAvgSummer, summerDay, 3); // 하절기 방류TN - orgData[9].summerAll = qltyDataSetting(totalInflTpAvgSummer, summerDay, 3); // 하절기 유입TP + orgData[5].summerAll = qltyDataSetting(totalInflBodAvgSummer, summerDay, 1); // 하절기 유입BOD + orgData[6].summerAll = qltyDataSetting(totalEfflBodAvgSummer, summerDay, 1); // 하절기 방류BOD + orgData[7].summerAll = qltyDataSetting(totalInflTnAvgSummer, summerDay, 3); // 하절기 유입TN + orgData[8].summerAll = qltyDataSetting(totalEfflTnAvgSummer, summerDay, 3); // 하절기 방류TN + orgData[9].summerAll = qltyDataSetting(totalInflTpAvgSummer, summerDay, 3); // 하절기 유입TP orgData[10].summerAll = qltyDataSetting(totalEfflTpAvgSummer, summerDay, 3); // 하절기 방류TP //총인설비 orgData[11].summerAll = qltyDataSetting(totalTpInflAvgSummer, noNullSummerDay, 3); orgData[12].summerAll = qltyDataSetting(totalEfflTpAvgSummer, summerDay, 3); - // (1) 청천시 변수 - // (1-1) 날짜 count - let chungchunSummerDay = 0; - let chungchunWinterDay = 0; - let noNullChungchunSummerDay = 0; - let noNullChungchunWinterDay = 0; - - // (1-2) 하절기 - let chungchunInflBodAvgSummer = 0; // 하절기 청천시 유입BOD - let chungchunInflTnAvgSummer = 0; // 하절기 청천시 유입TN - let chungchunInflTpAvgSummer = 0; // 하절기 청천시 유입TP - let chungchunEfflBodAvgSummer = 0; // 하절기 청천시 방류BOD - let chungchunEfflTnAvgSummer = 0; // 하절기 청천시 방류TN - let chungchunEfflTpAvgSummer = 0; // 하절기 청천시 방류TP - let chungchunTpInflAvgSummer = 0; // 하절기 청천시 총인설비 유입TP - - // (1-3) 동절기 (최대, 최소, 평균 다 필요) - let chungchunInflBodAvg = 0; - let chungchunInflTnAvg = 0; - let chungchunInflTpAvg = 0; - let chungchunTpInflAvg = 0; - let chungchunInflBodMax = 0; - let chungchunInflTnMax = 0; - let chungchunInflTpMax = 0; - let chungchunTpInflMax = 0; - let chungchunInflBodMin = 99999999; - let chungchunInflTnMin = 99999999; - let chungchunInflTpMin = 99999999; - let chungchunTpInflMin = 99999999; - - let chungchunEfflBodAvg = 0; - let chungchunEfflTnAvg = 0; - let chungchunEfflTpAvg = 0; - let chungchunEfflBodMax = 0; - let chungchunEfflTnMax = 0; - let chungchunEfflTpMax = 0; - let chungchunEfflBodMin = 99999999; - let chungchunEfflTnMin = 99999999; - let chungchunEfflTpMin = 99999999; - - // 청천시 - qltyChungchunData.forEach((item: any) => { - const month = item.msrDt.substring(4, 6); // 월 추출 - if(month === '01' || month === '02'){ - chungchunWinterDay += 1; - if(item.tpInflWqltTp != null && item.tpInflWqltTp != 0){ - noNullChungchunWinterDay+=1; - } - - const inflbod = nullToZero(item.inflAssctBfrWqltBod); - const infltn = nullToZero(item.inflAssctBfrWqltTn); - const infltp = nullToZero(item.inflAssctBfrWqltTp); - const effbod = nullToZero(item.efflWqltBod); - const efftn = nullToZero(item.efflWqltTn); - const efftp = nullToZero(item.efflWqltTp); - const tpInfl = nullToZero(item.tpInflWqltTp); - - chungchunInflBodAvg += inflbod; - chungchunInflTnAvg += infltn; - chungchunInflTpAvg += infltp; - chungchunEfflBodAvg += effbod; - chungchunEfflTnAvg += efftn; - chungchunEfflTpAvg += efftp; - chungchunTpInflAvg += tpInfl; - - if(chungchunInflBodMax < inflbod) chungchunInflBodMax = inflbod; - if(chungchunInflTnMax < infltn) chungchunInflTnMax = infltn; - if(chungchunInflTpMax < infltp) chungchunInflTpMax = infltp; - if(chungchunEfflBodMax < effbod) chungchunEfflBodMax = effbod; - if(chungchunEfflTnMax < efftn) chungchunEfflTnMax = efftn; - if(chungchunEfflTpMax < efftp) chungchunEfflTpMax = efftp; - if(chungchunTpInflMax < tpInfl) chungchunTpInflMax = tpInfl; - - if(chungchunInflBodMin > inflbod) chungchunInflBodMin = inflbod; - if(chungchunInflTnMin > infltn) chungchunInflTnMin = infltn; - if(chungchunInflTpMin > infltp) chungchunInflTpMin = infltp; - if(chungchunEfflBodMin > effbod) chungchunEfflBodMin = effbod; - if(chungchunEfflTnMin > efftn) chungchunEfflTnMin = efftn; - if(chungchunEfflTpMin > efftp) chungchunEfflTpMin = efftp; - if(chungchunTpInflMin > tpInfl) chungchunTpInflMin = tpInfl; - }else if(month === '06' || month === '07' || month === '08'){ - chungchunSummerDay += 1; - if(item.tpInflWqltTp != null && item.tpInflWqltTp != 0){ - noNullChungchunSummerDay+=1; - } - - chungchunInflBodAvgSummer += nullToZero(item.inflAssctBfrWqltBod); - chungchunInflTnAvgSummer += nullToZero(item.inflAssctBfrWqltTn); - chungchunInflTpAvgSummer += nullToZero(item.inflAssctBfrWqltTp); - chungchunEfflBodAvgSummer += nullToZero(item.efflWqltBod); - chungchunEfflTnAvgSummer += nullToZero(item.efflWqltTn); - chungchunEfflTpAvgSummer += nullToZero(item.efflWqltTp); - chungchunTpInflAvgSummer += nullToZero(item.tpInflWqltTp); - } - }); // 청천시 수질 데이터 수정 // 하절기 @@ -972,37 +1002,6 @@ const calcWaterQltyData = async (data: any[], searchYear : string|undefined, fcl orgData[11].winterSunnyMin = chungchunTpInflMin === 99999999 ? '0.000' : roundUp(chungchunTpInflMin, 3).toFixed(3); orgData[12].winterSunnyMin = chungchunInflTpMin === 99999999 ? '0.000' : roundUp(chungchunInflTpMin, 3).toFixed(3); - // 강우시 변수 - let rainSummerDay = 0; - let noNullRainSummerDay = 0; - - let rainInflBodAvg = 0; - let rainInflTnAvg = 0; - let rainInflTpAvg = 0; - let rainEfflBodAvg = 0; - let rainEfflTnAvg = 0; - let rainEfflTpAvg = 0; - let rainTpInflAvg = 0; - - // 강우시 - qltyRainData.forEach((item: any) => { - const month = item.msrDt.substring(4, 6); // 월 추출 - if(month === '06' || month === '07' || month === '08'){ - rainSummerDay += 1; - if(item.tpInflWqltTp != null && item.tpInflWqltTp != 0){ - noNullRainSummerDay+=1; - } - - rainInflBodAvg += nullToZero(item.inflAssctBfrWqltBod); - rainInflTnAvg += nullToZero(item.inflAssctBfrWqltTn); - rainInflTpAvg += nullToZero(item.inflAssctBfrWqltTp); - rainEfflBodAvg += nullToZero(item.efflWqltBod); - rainEfflTnAvg += nullToZero(item.efflWqltTn); - rainEfflTpAvg += nullToZero(item.efflWqltTp); - rainTpInflAvg += nullToZero(item.tpInflWqltTp); - } - }); - // 강우시 수질 데이터 수정 orgData[5].summerThree = qltyDataSetting(rainInflBodAvg, rainSummerDay, 1); orgData[6].summerThree = qltyDataSetting(rainEfflBodAvg, rainSummerDay, 1); @@ -1014,6 +1013,8 @@ const calcWaterQltyData = async (data: any[], searchYear : string|undefined, fcl // 총인설비 orgData[11].summerThree = qltyDataSetting(rainTpInflAvg, noNullRainSummerDay, 3); orgData[12].summerThree = qltyDataSetting(rainInflTpAvg, rainSummerDay, 3); + console.log(rainEffectDayArray); + console.log("000000000", rainSummerDay, noNullRainSummerDay, rainInflBodAvg, rainInflTnAvg, rainInflTpAvg, rainEfflBodAvg, rainEfflTnAvg, rainEfflTpAvg, rainTpInflAvg); return orgData; } else { @@ -1039,190 +1040,190 @@ export type DashBoardActions = { export type DashBoardType = { DashboardMain: { isInit: boolean; - topLabelArray:string[]; + topLabelArray: string[]; }, - FcltyMain : { - isInit : boolean; - upHeadListFclty : TableUpperProps[]; - fcltyList : mainFcltyProps[]; + FcltyMain: { + isInit: boolean; + upHeadListFclty: TableUpperProps[]; + fcltyList: mainFcltyProps[]; }, - PlanFclty : { - isInit : boolean; - planYearList : string[]; - upHeadListPlanFclty : TableUpperProps[]; - planFcltyList : planFcltyListProps[]; - waterUsage1 : number | '', - waterUsage2 : number | '', - waterUsage3 : number | '', - isLoadingPlanFclty : boolean; + PlanFclty: { + isInit: boolean; + planYearList: string[]; + upHeadListPlanFclty: TableUpperProps[]; + planFcltyList: planFcltyListProps[]; + waterUsage1: number | '', + waterUsage2: number | '', + waterUsage3: number | '', + isLoadingPlanFclty: boolean; }, - OperationStatus : { - isInit : boolean; - upHeadListOperationStatus : TableUpperProps[]; - operationalStatusList : any; - isLoadingOperationStatus : boolean; + OperationStatus: { + isInit: boolean; + upHeadListOperationStatus: TableUpperProps[]; + operationalStatusList: any; + isLoadingOperationStatus: boolean; } - MainGraph : { - isInit : boolean; - chart_inflowRain : lineBarChartDataProps[]; - chart_bodRain : lineBarChartDataProps[]; - chart_inflTp : lineChartDataProps[]; - chart_chongInTp : lineChartDataProps[]; - chart_efflTp : lineChartDataProps[]; - chart_inflTn : lineChartDataProps[]; - chart_efflTn : lineChartDataProps[]; - chart_inflBod : lineChartDataProps[]; - chart_efflBod : lineChartDataProps[]; - waterQltyStandartd : any; - isLoadingMainGraph : boolean; + MainGraph: { + isInit: boolean; + chart_inflowRain: lineBarChartDataProps[]; + chart_bodRain: lineBarChartDataProps[]; + chart_inflTp: lineChartDataProps[]; + chart_chongInTp: lineChartDataProps[]; + chart_efflTp: lineChartDataProps[]; + chart_inflTn: lineChartDataProps[]; + chart_efflTn: lineChartDataProps[]; + chart_inflBod: lineChartDataProps[]; + chart_efflBod: lineChartDataProps[]; + waterQltyStandartd: any; + isLoadingMainGraph: boolean; }, - RainManage : { - isInit : boolean; - upHeadListRainManage : TableUpperProps[]; - rainManageList : RainManageListProps[]; - excelList : RainManageExcelType[]; - isLoadingRainManage : boolean; + RainManage: { + isInit: boolean; + upHeadListRainManage: TableUpperProps[]; + rainManageList: RainManageListProps[]; + excelList: RainManageExcelType[]; + isLoadingRainManage: boolean; }, - - DrainageEquipment : { - isInit : boolean; - upHeadListDrainageEquipment : TableUpperProps[]; - drainageEquipmentList : DrainageEquipmentListProps[]; - drainageEquipmentExcelList : DrainageEquipmentExcelType[]; + + DrainageEquipment: { + isInit: boolean; + upHeadListDrainageEquipment: TableUpperProps[]; + drainageEquipmentList: DrainageEquipmentListProps[]; + drainageEquipmentExcelList: DrainageEquipmentExcelType[]; } } export type DashBoardStore = DashBoardType & DashBoardActions; -export const dashBoardInitState:DashBoardType = { +export const dashBoardInitState: DashBoardType = { DashboardMain: { isInit: false, topLabelArray: DashBoardTopLabelArray, }, - - FcltyMain : { - isInit : false, - upHeadListFclty : upHeadListFclty, - fcltyList : fcltyList, + + FcltyMain: { + isInit: false, + upHeadListFclty: upHeadListFclty, + fcltyList: fcltyList, }, - PlanFclty : { - isInit : true, - planYearList : planYearList, - upHeadListPlanFclty : upHeadListPlanFclty, - planFcltyList : planFcltyList, - waterUsage1 : 0, - waterUsage2 : 0, - waterUsage3 : 0, - isLoadingPlanFclty : false, + PlanFclty: { + isInit: true, + planYearList: planYearList, + upHeadListPlanFclty: upHeadListPlanFclty, + planFcltyList: planFcltyList, + waterUsage1: 0, + waterUsage2: 0, + waterUsage3: 0, + isLoadingPlanFclty: false, }, - OperationStatus : { - isInit : false, - upHeadListOperationStatus : upHeadListOperationStatus, - operationalStatusList : operationalStatusListOrg, - isLoadingOperationStatus : false, + OperationStatus: { + isInit: false, + upHeadListOperationStatus: upHeadListOperationStatus, + operationalStatusList: operationalStatusListOrg, + isLoadingOperationStatus: false, }, - MainGraph : { - isInit : false, - chart_inflowRain : chart_inflowRain, - chart_bodRain : chart_bodRain, - chart_inflTp : chart_inflTp, - chart_chongInTp : chart_chongInTp, - chart_efflTp : chart_efflTp, - chart_inflTn : chart_inflTn, - chart_efflTn : chart_efflTn, - chart_inflBod : chart_inflBod, - chart_efflBod : chart_efflBod, - waterQltyStandartd : waterQltyStandartd, - isLoadingMainGraph : false, + MainGraph: { + isInit: false, + chart_inflowRain: chart_inflowRain, + chart_bodRain: chart_bodRain, + chart_inflTp: chart_inflTp, + chart_chongInTp: chart_chongInTp, + chart_efflTp: chart_efflTp, + chart_inflTn: chart_inflTn, + chart_efflTn: chart_efflTn, + chart_inflBod: chart_inflBod, + chart_efflBod: chart_efflBod, + waterQltyStandartd: waterQltyStandartd, + isLoadingMainGraph: false, }, - RainManage : { - isInit : false, - upHeadListRainManage : upHeadListRainManage, - rainManageList : rainManageList, - excelList : [], - isLoadingRainManage : false, + RainManage: { + isInit: false, + upHeadListRainManage: upHeadListRainManage, + rainManageList: rainManageList, + excelList: [], + isLoadingRainManage: false, }, - DrainageEquipment : { - isInit : false, - upHeadListDrainageEquipment : upHeadListDrainageEquipment, - drainageEquipmentList : drainageEquipmentList, - drainageEquipmentExcelList : [] + DrainageEquipment: { + isInit: false, + upHeadListDrainageEquipment: upHeadListDrainageEquipment, + drainageEquipmentList: drainageEquipmentList, + drainageEquipmentExcelList: [] } } /** * 데이터 폼 포맷설정 */ -export const dataFormSettingPlan=(item : planFcltyListProps, decmials : number) => { - DataForm({ type: 'float'+decmials, column: 'provisionalApproval', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float'+decmials, column: 'now', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float'+decmials, column: 'stepOne', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float'+decmials, column: 'stepTwo', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float'+decmials, column: 'stepThree', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float'+decmials, column: 'stepFour', item: item as unknown as Record<string, unknown>}); +export const dataFormSettingPlan = (item: planFcltyListProps, decmials: number) => { + DataForm({ type: 'float' + decmials, column: 'provisionalApproval', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float' + decmials, column: 'now', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float' + decmials, column: 'stepOne', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float' + decmials, column: 'stepTwo', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float' + decmials, column: 'stepThree', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float' + decmials, column: 'stepFour', item: item as unknown as Record<string, unknown> }); } -export const dataFormSetting=(item : OperationalStatusListProps)=> { +export const dataFormSetting = (item: OperationalStatusListProps) => { DataForm({ type: 'float0', column: 'yearAvg', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'yearMax', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'yearMin', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'summerAll', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'summerThree', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'summerRain', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'winterAll', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'winterSunnyAvg', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'winterSunnyMax', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'winterSunnyMin', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'groundWaterAvg', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'groundWaterSummer', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'groundWaterWinter', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'rainRate', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'rdi', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float0', column: 'yearMax', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'yearMin', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'summerAll', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'summerThree', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'summerRain', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'winterAll', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'winterSunnyAvg', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'winterSunnyMax', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'winterSunnyMin', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'groundWaterAvg', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'groundWaterSummer', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'groundWaterWinter', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'rainRate', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'rdi', item: item as unknown as Record<string, unknown> }); }; -export const dataFormSettingWqlty=(item : OperationalStatusListProps)=> { +export const dataFormSettingWqlty = (item: OperationalStatusListProps) => { DataForm({ type: 'float1', column: 'yearAvg', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float1', column: 'yearMax', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'yearMin', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'summerAll', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'summerThree', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'summerRain', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'winterAll', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'winterSunnyAvg', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'winterSunnyMax', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'winterSunnyMin', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'groundWaterAvg', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'groundWaterSummer', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'groundWaterWinter', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'rainRate', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float1', column: 'rdi', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'yearMax', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'yearMin', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'summerAll', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'summerThree', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'summerRain', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'winterAll', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'winterSunnyAvg', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'winterSunnyMax', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'winterSunnyMin', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'groundWaterAvg', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'groundWaterSummer', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'groundWaterWinter', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'rainRate', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float1', column: 'rdi', item: item as unknown as Record<string, unknown> }); }; -const changeValue=(operationalStatus, data, keyTxt = 'INFL_AMNT')=>{ - operationalStatus.yearAvg = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.yearData?Number(Math.round(data.yearData['AVG_'+keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.yearData['AVG_'+keyTxt] : ''; - operationalStatus.yearMax = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.yearData?Number(Math.round(data.yearData['MAX_'+keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.yearData['MAX_'+keyTxt] : ''; - operationalStatus.yearMin = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.yearData?Number(Math.round(data.yearData['MIN_'+keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.yearData['MIN_'+keyTxt] : ''; +const changeValue = (operationalStatus, data, keyTxt = 'INFL_AMNT') => { + operationalStatus.yearAvg = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['AVG_' + keyTxt] : ''; + operationalStatus.yearMax = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['MAX_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['MAX_' + keyTxt] : ''; + operationalStatus.yearMin = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['MIN_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['MIN_' + keyTxt] : ''; // 여름 - operationalStatus.summerAll = data.summer ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.summer?Number(Math.round(data.summer['AVG_'+keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.summer['AVG_'+keyTxt] : ''; - operationalStatus.summerThree = data.summerRainy ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.summerRainy?Number(Math.round(data.summerRainy["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.summerRainy["AVG_" + keyTxt] : ''; - operationalStatus.summerRain = data.summerSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.summerSunny?Number(Math.round(data.summerSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.summerSunny["AVG_" + keyTxt] : ''; + operationalStatus.summerAll = data.summer ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summer ? Number(Math.round(data.summer['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summer['AVG_' + keyTxt] : ''; + operationalStatus.summerThree = data.summerRainy ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summerRainy ? Number(Math.round(data.summerRainy["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summerRainy["AVG_" + keyTxt] : ''; + operationalStatus.summerRain = data.summerSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summerSunny ? Number(Math.round(data.summerSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summerSunny["AVG_" + keyTxt] : ''; // 겨울 - operationalStatus.winterAll = data.winter ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.winter?Number(Math.round(data.winter["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.winter["AVG_" + keyTxt] : ''; - operationalStatus.winterSunnyMin = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.winterSunny?Number(Math.round(data.winterSunny["MIN_" + keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.winterSunny["MIN_" + keyTxt] : ''; - operationalStatus.winterSunnyAvg = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.winterSunny?Number(Math.round(data.winterSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.winterSunny["AVG_" + keyTxt] : ''; - operationalStatus.winterSunnyMax = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN"))? data.winterSunny?Number(Math.round(data.winterSunny["MAX_" + keyTxt] * 1000) / 1000).toFixed(3).toString():'': data.winterSunny["MAX_" + keyTxt] : ''; + operationalStatus.winterAll = data.winter ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winter ? Number(Math.round(data.winter["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winter["AVG_" + keyTxt] : ''; + operationalStatus.winterSunnyMin = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["MIN_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["MIN_" + keyTxt] : ''; + operationalStatus.winterSunnyAvg = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["AVG_" + keyTxt] : ''; + operationalStatus.winterSunnyMax = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["MAX_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["MAX_" + keyTxt] : ''; // 지하수 - + // 오염물질 // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) const summerLowFlow = data.summerBod && data.summerBod.INFL_AMNT && data.summerBod.INFL_AMNT != 'null' ? Number(data.summerBod.INFL_AMNT) : 0; @@ -1233,20 +1234,20 @@ const changeValue=(operationalStatus, data, keyTxt = 'INFL_AMNT')=>{ operationalStatus.rdiRain = summerLowRain; } -const calcValue = (operationalStatus, data, keyTxt='INFL_ASSCT_BFR_WQLT_TP') => { +const calcValue = (operationalStatus, data, keyTxt = 'INFL_ASSCT_BFR_WQLT_TP') => { // 연간 - operationalStatus.yearAvg = data.yearData && data.yearData['AVG_'+keyTxt] ? Number(Math.round(data.yearData['AVG_'+keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.yearMax = data.yearData && data.yearData['MAX_'+keyTxt] ? Number(Math.round(data.yearData['MAX_'+keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.yearMin = data.yearData && data.yearData['MIN_'+keyTxt] ? Number(Math.round(data.yearData['MIN_'+keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.yearAvg = data.yearData && data.yearData['AVG_' + keyTxt] ? Number(Math.round(data.yearData['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.yearMax = data.yearData && data.yearData['MAX_' + keyTxt] ? Number(Math.round(data.yearData['MAX_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.yearMin = data.yearData && data.yearData['MIN_' + keyTxt] ? Number(Math.round(data.yearData['MIN_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; // 여름 - operationalStatus.summerAll = data.summer && data.summer['AVG_'+keyTxt] ? Number(Math.round(data.summer['AVG_'+keyTxt] * 0.8 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.summerThree = data.summerRainy && data.summerRainy['AVG_'+keyTxt] ? Number(Math.round(data.summerRainy['AVG_'+keyTxt] * 0.82 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.summerRain = data.summerSunny && data.summerSunny['AVG_'+keyTxt] ? Number(Math.round(data.summerSunny['AVG_'+keyTxt] * 0.74 * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.summerAll = data.summer && data.summer['AVG_' + keyTxt] ? Number(Math.round(data.summer['AVG_' + keyTxt] * 0.8 * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.summerThree = data.summerRainy && data.summerRainy['AVG_' + keyTxt] ? Number(Math.round(data.summerRainy['AVG_' + keyTxt] * 0.82 * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.summerRain = data.summerSunny && data.summerSunny['AVG_' + keyTxt] ? Number(Math.round(data.summerSunny['AVG_' + keyTxt] * 0.74 * 1000) / 1000).toFixed(3).toString() : ''; // 겨울 - operationalStatus.winterAll = data.winter && data.winter['AVG_'+keyTxt] ? Number(Math.round(data.winter['AVG_'+keyTxt] * 1.16*1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.winterSunnyMin = data.winterSunny && data.winterSunny['MIN_'+keyTxt] ? Number(Math.round(data.winterSunny['MIN_'+keyTxt] * 1.2 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.winterSunnyAvg = data.winterSunny && data.winterSunny['AVG_'+keyTxt] ? Number(Math.round(data.winterSunny['AVG_'+keyTxt] * 1.25 *1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.winterSunnyMax = data.winterSunny && data.winterSunny['MAX_'+keyTxt] ? Number(Math.round(data.winterSunny['MAX_'+keyTxt] * 1.3 *1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.winterAll = data.winter && data.winter['AVG_' + keyTxt] ? Number(Math.round(data.winter['AVG_' + keyTxt] * 1.16 * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.winterSunnyMin = data.winterSunny && data.winterSunny['MIN_' + keyTxt] ? Number(Math.round(data.winterSunny['MIN_' + keyTxt] * 1.2 * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.winterSunnyAvg = data.winterSunny && data.winterSunny['AVG_' + keyTxt] ? Number(Math.round(data.winterSunny['AVG_' + keyTxt] * 1.25 * 1000) / 1000).toFixed(3).toString() : ''; + operationalStatus.winterSunnyMax = data.winterSunny && data.winterSunny['MAX_' + keyTxt] ? Number(Math.round(data.winterSunny['MAX_' + keyTxt] * 1.3 * 1000) / 1000).toFixed(3).toString() : ''; } type RtnFlowType = { @@ -1263,32 +1264,32 @@ type RtnFlowResponse = { const searchWaterUsage = async (searchYear: string, fcltyCd: string) => { const waterUsage = [0, 0, 0]; - + for (let i = 0; i < 3; i++) { try { - const res = await getFetch('fo', '/fclt/flow/' + fcltyCd + '/' + (Number(searchYear)-i)) as RtnFlowResponse; + const res = await getFetch('fo', '/fclt/flow/' + fcltyCd + '/' + (Number(searchYear) - i)) as RtnFlowResponse; let totWaterUsage = 0; - + if (res && res.data && Array.isArray(res.data)) { res.data.forEach((item: RtnFlowType) => { totWaterUsage += Number(item.inflAmnt); }); - + if (res.count > 0) { const avg = totWaterUsage / res.count; waterUsage[i] = parseFloat((avg * 0.65).toFixed(2)); } } } catch (error) { - console.error(`Error fetching water usage for year ${Number(searchYear)-i}:`, error); + console.error(`Error fetching water usage for year ${Number(searchYear) - i}:`, error); waterUsage[i] = 0; } } - + return waterUsage; } -export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) => void)=>DashBoardActions=(set: (fn: (state: DashBoardType) => DashBoardType) => void) => { +export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardType) => void) => DashBoardActions = (set: (fn: (state: DashBoardType) => DashBoardType) => void) => { return { initializeDashBoardData: async () => { set((state: DashBoardType) => ({ @@ -1301,7 +1302,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) }, /** 시설정보 및 운영현황 - 계획정보 */ - searchPlanInfo : async (targetYear: string, fcltyCd: string) => { + searchPlanInfo: async (targetYear: string, fcltyCd: string) => { set((state: DashBoardType) => ({ ...state, PlanFclty: { @@ -1311,70 +1312,70 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) })); let waterUsage = [0, 0, 0]; waterUsage = await searchWaterUsage(targetYear, fcltyCd); - + set((state: DashBoardType) => ({ ...state, - PlanFclty : { + PlanFclty: { ...state.PlanFclty, - waterUsage1 : waterUsage[0] || 0, - waterUsage2 : waterUsage[1] || 0, - waterUsage3 : waterUsage[2] || 0, + waterUsage1: waterUsage[0] || 0, + waterUsage2: waterUsage[1] || 0, + waterUsage3: waterUsage[2] || 0, }, })); const res = await fetchFacilityPlan(targetYear, fcltyCd, set); - - let minDiff=9999999; + + let minDiff = 9999999; let minIndex; - res.forEach((el:any, idx) => { - if(minDiff>Math.abs(Number(targetYear) - Number(el.planYr))){ - minDiff=Math.abs(Number(targetYear) - Number(el.planYr)); - minIndex=idx; + res.forEach((el: any, idx) => { + if (minDiff > Math.abs(Number(targetYear) - Number(el.planYr))) { + minDiff = Math.abs(Number(targetYear) - Number(el.planYr)); + minIndex = idx; } }); const rtnPlanData = res[minIndex]; planFcltyList.map((el, index) => { - planYearList = []; - planYearList.push(rtnPlanData?rtnPlanData.planYrDt4.toString():""); - planYearList.push(rtnPlanData?rtnPlanData.planYr.toString():""); - planYearList.push(rtnPlanData?rtnPlanData.planYrDc1.toString():""); - planYearList.push(rtnPlanData?rtnPlanData.planYrDc2.toString():""); - planYearList.push(rtnPlanData?rtnPlanData.planYrDc3.toString():""); - planYearList.push(rtnPlanData?rtnPlanData.planYrDc4.toString():""); + planYearList = []; + planYearList.push(rtnPlanData ? rtnPlanData.planYrDt4.toString() : ""); + planYearList.push(rtnPlanData ? rtnPlanData.planYr.toString() : ""); + planYearList.push(rtnPlanData ? rtnPlanData.planYrDc1.toString() : ""); + planYearList.push(rtnPlanData ? rtnPlanData.planYrDc2.toString() : ""); + planYearList.push(rtnPlanData ? rtnPlanData.planYrDc3.toString() : ""); + planYearList.push(rtnPlanData ? rtnPlanData.planYrDc4.toString() : ""); - if(index === 0){ // 증설계획(㎥/일) - el.provisionalApproval = rtnPlanData?rtnPlanData.planSwageQntSumDt4:''; // 기승인4단계 - el.now = rtnPlanData?rtnPlanData.planSwageQntSum:''; // 현재 - el.stepOne = rtnPlanData?rtnPlanData.planSwageQntSumDc1:''; // 1단계 - el.stepTwo = rtnPlanData?rtnPlanData.planSwageQntSumDc2:''; // 2단계 - el.stepThree = rtnPlanData?rtnPlanData.planSwageQntSumDc3:''; // 3단계 - el.stepFour = rtnPlanData?rtnPlanData.planSwageQntSumDc4:''; // 4단계 + if (index === 0) { // 증설계획(㎥/일) + el.provisionalApproval = rtnPlanData ? rtnPlanData.planSwageQntSumDt4 : ''; // 기승인4단계 + el.now = rtnPlanData ? rtnPlanData.planSwageQntSum : ''; // 현재 + el.stepOne = rtnPlanData ? rtnPlanData.planSwageQntSumDc1 : ''; // 1단계 + el.stepTwo = rtnPlanData ? rtnPlanData.planSwageQntSumDc2 : ''; // 2단계 + el.stepThree = rtnPlanData ? rtnPlanData.planSwageQntSumDc3 : ''; // 3단계 + el.stepFour = rtnPlanData ? rtnPlanData.planSwageQntSumDc4 : ''; // 4단계 } - if(index === 1){ // 처리인구(인) - el.provisionalApproval = rtnPlanData?rtnPlanData.swtrmtPpltnCntDt4:''; - el.now = rtnPlanData?rtnPlanData.swtrmtPpltnCnt:''; - el.stepOne = rtnPlanData?rtnPlanData.swtrmtPpltnCntDc1:''; - el.stepTwo = rtnPlanData?rtnPlanData.swtrmtPpltnCntDc2:''; - el.stepThree = rtnPlanData?rtnPlanData.swtrmtPpltnCntDc3:''; - el.stepFour = rtnPlanData?rtnPlanData.swtrmtPpltnCntDc4:''; + if (index === 1) { // 처리인구(인) + el.provisionalApproval = rtnPlanData ? rtnPlanData.swtrmtPpltnCntDt4 : ''; + el.now = rtnPlanData ? rtnPlanData.swtrmtPpltnCnt : ''; + el.stepOne = rtnPlanData ? rtnPlanData.swtrmtPpltnCntDc1 : ''; + el.stepTwo = rtnPlanData ? rtnPlanData.swtrmtPpltnCntDc2 : ''; + el.stepThree = rtnPlanData ? rtnPlanData.swtrmtPpltnCntDc3 : ''; + el.stepFour = rtnPlanData ? rtnPlanData.swtrmtPpltnCntDc4 : ''; } - if(index === 2){ // 처리구역(km²) - el.provisionalApproval = rtnPlanData?rtnPlanData.swtrmtZoneAreaDt4:''; - el.now = rtnPlanData?rtnPlanData.swtrmtZoneArea:''; - el.stepOne = rtnPlanData?rtnPlanData.swtrmtZoneAreaDc1:''; - el.stepTwo = rtnPlanData?rtnPlanData.swtrmtZoneAreaDc2:''; - el.stepThree = rtnPlanData?rtnPlanData.swtrmtZoneAreaDc3:''; - el.stepFour = rtnPlanData?rtnPlanData.swtrmtZoneAreaDc4:''; + if (index === 2) { // 처리구역(km²) + el.provisionalApproval = rtnPlanData ? rtnPlanData.swtrmtZoneAreaDt4 : ''; + el.now = rtnPlanData ? rtnPlanData.swtrmtZoneArea : ''; + el.stepOne = rtnPlanData ? rtnPlanData.swtrmtZoneAreaDc1 : ''; + el.stepTwo = rtnPlanData ? rtnPlanData.swtrmtZoneAreaDc2 : ''; + el.stepThree = rtnPlanData ? rtnPlanData.swtrmtZoneAreaDc3 : ''; + el.stepFour = rtnPlanData ? rtnPlanData.swtrmtZoneAreaDc4 : ''; } - if(index === 4){ // 물사용량 - el.provisionalApproval = rtnPlanData?rtnPlanData.ugwtUseSum:''; + if (index === 4) { // 물사용량 + el.provisionalApproval = rtnPlanData ? rtnPlanData.ugwtUseSum : ''; } - - if(index === 2){ // 처리구역(km²) - dataFormSettingPlan(el, 1); - }else if(index == 4){ // 물사용량 - }else{ + + if (index === 2) { // 처리구역(km²) + dataFormSettingPlan(el, 1); + } else if (index == 4) { // 물사용량 + } else { dataFormSettingPlan(el, 0); } @@ -1412,7 +1413,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) let winterSunnyMin = 1; // 동절기 청천 최소 let winterSunnyAvg = 1; // 동절기 청천 평균 let winterSunnyMax = 1; // 동절기 청천 최대 - + // 최대, 최소 총 유입량 (1년 하루 합계의 최대, 최소) // 하절기 청천시, 강우시 재계산 리턴값 @@ -1433,29 +1434,29 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) let winterChungchunEfflAvg = 1; // 동절기 청천 방류량 평균 let winterChungchunEfflMax = 1; // 동절기 청천 방류량 최대 let winterChungchunEfflMin = 1; // 동절기 청천 방류량 최소 - + const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; - let rdiPercent = 0; + let rdiPercent = 0; let operationalStatusList = clone(operationalStatusListOrg); - if(data && operationalStatusList){ + if (data && operationalStatusList) { // 유량 - 유입 if (operationalStatusList?.[0]) { // 연간 - const yearAvg = data.yearData===null ? '' : ( - (data.yearData.AVG_INFL_AMNT?data.yearData.AVG_INFL_AMNT:0) + // 실제유입량(반류수제거)(m³/일) 평균 - (data.yearData.AVG_SUM_FLOW?data.yearData.AVG_SUM_FLOW:0) + // api 주석처리되어 있음. - (data.yearData.AVG_RETURN_AMNT?data.yearData.AVG_RETURN_AMNT:0) // 반류수유량(m³/일) 평균 + const yearAvg = data.yearData === null ? '' : ( + (data.yearData.AVG_INFL_AMNT ? data.yearData.AVG_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 평균 + (data.yearData.AVG_SUM_FLOW ? data.yearData.AVG_SUM_FLOW : 0) + // api 주석처리되어 있음. + (data.yearData.AVG_RETURN_AMNT ? data.yearData.AVG_RETURN_AMNT : 0) // 반류수유량(m³/일) 평균 ); - const yearMax = data.yearData===null ? '' : ( - (data.yearData.MAX_INFL_AMNT?data.yearData.MAX_INFL_AMNT:0) + // 실제유입량(반류수제거)(m³/일) 최대 - (data.yearData.MAX_SUM_FLOW?data.yearData.MAX_SUM_FLOW:0) + // api 주석처리되어 있음. - (data.yearData.MAX_RETURN_AMNT?data.yearData.MAX_RETURN_AMNT:0) // 반류수유량(m³/일) 최대 + const yearMax = data.yearData === null ? '' : ( + (data.yearData.MAX_INFL_AMNT ? data.yearData.MAX_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 최대 + (data.yearData.MAX_SUM_FLOW ? data.yearData.MAX_SUM_FLOW : 0) + // api 주석처리되어 있음. + (data.yearData.MAX_RETURN_AMNT ? data.yearData.MAX_RETURN_AMNT : 0) // 반류수유량(m³/일) 최대 ); - const yearMin = data.yearData===null ? '' : ( - (data.yearData.MIN_INFL_AMNT?data.yearData.MIN_INFL_AMNT:0) + // 실제유입량(반류수제거)(m³/일) 최소 - (data.yearData.MIN_SUM_FLOW?data.yearData.MIN_SUM_FLOW:0) + // api 주석처리되어 있음. - (data.yearData.MIN_RETURN_AMNT?data.yearData.MIN_RETURN_AMNT:0) // 반류수유량(m³/일) 최소 + const yearMin = data.yearData === null ? '' : ( + (data.yearData.MIN_INFL_AMNT ? data.yearData.MIN_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 최소 + (data.yearData.MIN_SUM_FLOW ? data.yearData.MIN_SUM_FLOW : 0) + // api 주석처리되어 있음. + (data.yearData.MIN_RETURN_AMNT ? data.yearData.MIN_RETURN_AMNT : 0) // 반류수유량(m³/일) 최소 ); operationalStatusList[0].yearAvg = yearAvg; @@ -1468,7 +1469,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) ); operationalStatusList[0].summerThree = data.summerRainy === null ? '' : ( // 하절기 강우시 (data.summerRainy.AVG_INFL_AMNT ? data.summerRainy.AVG_INFL_AMNT : 0) + - (data.summerRainy.AVG_SUM_FLOW ? data.summerRainy.AVG_SUM_FLOW : 0) + (data.summerRainy.AVG_SUM_FLOW ? data.summerRainy.AVG_SUM_FLOW : 0) ); operationalStatusList[0].summerRain = data.summerSunny === null ? '' : ( // 하절기 청천시 (data.summerSunny.AVG_INFL_AMNT ? data.summerSunny.AVG_INFL_AMNT : 0) + @@ -1476,23 +1477,23 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) ); // 겨울 operationalStatusList[0].winterAll = data.winter === null ? '' : ( // 동절기 전기간 - (data.winter.AVG_INFL_AMNT ? data.winter.AVG_INFL_AMNT : 0) + - (data.winter.AVG_SUM_FLOW ? data.winter.AVG_SUM_FLOW : 0) + + (data.winter.AVG_INFL_AMNT ? data.winter.AVG_INFL_AMNT : 0) + + (data.winter.AVG_SUM_FLOW ? data.winter.AVG_SUM_FLOW : 0) + (data.winter.AVG_TP_INFL_WQLT_TP ? data.winter.AVG_TP_INFL_WQLT_TP : 0) ); operationalStatusList[0].winterSunnyMin = data.winterSunny === null ? '' : (// 동절기 청천 최소 - (data.winterSunny.MIN_INFL_AMNT ? data.winterSunny.MIN_INFL_AMNT : 0) + - (data.winterSunny.MIN_SUM_FLOW ? data.winterSunny.MIN_SUM_FLOW : 0) + + (data.winterSunny.MIN_INFL_AMNT ? data.winterSunny.MIN_INFL_AMNT : 0) + + (data.winterSunny.MIN_SUM_FLOW ? data.winterSunny.MIN_SUM_FLOW : 0) + (data.winterSunny.MIN_TP_INFL_WQLT_TP ? data.winterSunny.MIN_TP_INFL_WQLT_TP : 0) ); operationalStatusList[0].winterSunnyAvg = data.winterSunny === null ? '' : (// 동절기 청천 평균 - (data.winterSunny.AVG_INFL_AMNT ? data.winterSunny.AVG_INFL_AMNT : 0) + - (data.winterSunny.AVG_SUM_FLOW ? data.winterSunny.AVG_SUM_FLOW : 0) + + (data.winterSunny.AVG_INFL_AMNT ? data.winterSunny.AVG_INFL_AMNT : 0) + + (data.winterSunny.AVG_SUM_FLOW ? data.winterSunny.AVG_SUM_FLOW : 0) + (data.winterSunny.AVG_TP_INFL_WQLT_TP ? data.winterSunny.AVG_TP_INFL_WQLT_TP : 0) ); operationalStatusList[0].winterSunnyMax = data.winterSunny === null ? '' : (// 동절기 청천 최대 - (data.winterSunny.MAX_INFL_AMNT ? data.winterSunny.MAX_INFL_AMNT : 0) + - (data.winterSunny.MAX_SUM_FLOW ? data.winterSunny.MAX_SUM_FLOW : 0) + + (data.winterSunny.MAX_INFL_AMNT ? data.winterSunny.MAX_INFL_AMNT : 0) + + (data.winterSunny.MAX_SUM_FLOW ? data.winterSunny.MAX_SUM_FLOW : 0) + (data.winterSunny.MAX_TP_INFL_WQLT_TP ? data.winterSunny.MAX_TP_INFL_WQLT_TP : 0) ); // 연계처리수 @@ -1515,39 +1516,39 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) let summerRainDayFlow = 0; let summerRainDayReturnFlow = 0; let summerRainDayEfflFlow = 0; - + let winterSumFlow = 0; let winterChungchunSumFlow = 0; let minWinterChungchunSumFlow = 9999999; let maxWinterChungchunSumFlow = 0; - + // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - yearDay = res2.data?res2.data.length:1; + yearDay = res2.data ? res2.data.length : 1; res2.data.forEach((item: any) => { yearSumFlow += item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - if(maxYearSumFlow < (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0)) { + if (maxYearSumFlow < (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0)) { maxYearSumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; } - if(minYearSumFlow > (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0)) { + if (minYearSumFlow > (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0)) { minYearSumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; } // 1년 최대 총 하수유입량 let totYearFlow = 0; totYearFlow = (item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0) + (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0) + (item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0); - if(totFlowMax < totYearFlow) { + if (totFlowMax < totYearFlow) { totFlowMax = totYearFlow; } - if(totFlowMin > totYearFlow || totFlowMin === 0) { + if (totFlowMin > totYearFlow || totFlowMin === 0) { totFlowMin = totYearFlow; } - if(item.msrDt.substring(4,6) === '06' || item.msrDt.substring(4,6) === '07' || item.msrDt.substring(4,6) === '08') { + if (item.msrDt.substring(4, 6) === '06' || item.msrDt.substring(4, 6) === '07' || item.msrDt.substring(4, 6) === '08') { summerDay += 1; summerSumFlow += item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - } else if(item.msrDt.substring(4,6) === '01' || item.msrDt.substring(4,6) === '02') { + } else if (item.msrDt.substring(4, 6) === '01' || item.msrDt.substring(4, 6) === '02') { winterDay += 1; winterSumFlow += item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; } @@ -1555,44 +1556,44 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); - + // 지하수유입량 - 청천시 기준 let chungcunSumFlow = 0; let sumSummerChungcunFlow = 0; let sumWinterChungcunFlow = 0; - + // 하절기 청천시 총인설비 반류수 let summerChungchunDayReturnAmnt = 0; // 하절기 청천시 방류수 let summerChungchunDayEfflAmnt = 0; // 동절기 총 유입량 최대, 최소 - let winterChungchunTotalInflAmntMax = 0 ; - let winterChungchunTotalInflAmntMin = 9999999 ; + let winterChungchunTotalInflAmntMax = 0; + let winterChungchunTotalInflAmntMin = 9999999; // 동절기 청천시 하수유입량 최대, 최소 - let winterChungchunDayFlowMax = 0 ; - let winterChungchunDayFlowMin = 9999999 ; + let winterChungchunDayFlowMax = 0; + let winterChungchunDayFlowMin = 9999999; // 동절기 청천시 총인반류수 최대, 최소, 평균 - let winterChungchunDayReturnMax = 0 ; - let winterChungchunDayReturnMin = 9999999 ; - let winterChungchunDayReturnAvg = 0 ; + let winterChungchunDayReturnMax = 0; + let winterChungchunDayReturnMin = 9999999; + let winterChungchunDayReturnAvg = 0; // 동절기 청천시 방류량 최대, 최소, 평균 - let winterChungchunDayEfflMax = 0 ; - let winterChungchunDayEfflMin = 9999999 ; + let winterChungchunDayEfflMax = 0; + let winterChungchunDayEfflMin = 9999999; let winterChungchunDayEfflAvg = 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'){ + if (flowItem.msrDt.substring(4, 6) === '06' || flowItem.msrDt.substring(4, 6) === '07' || flowItem.msrDt.substring(4, 6) === '08') { summerChungchunDay += 1; summerChungchunSumFlow += flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; sumSummerChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; summerChungchunDayReturnAmnt += flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; summerChungchunDayEfflAmnt += flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; - }else if(flowItem.msrDt.substring(4,6) ==='01' || flowItem.msrDt.substring(4,6) ==='02'){ + } else if (flowItem.msrDt.substring(4, 6) === '01' || flowItem.msrDt.substring(4, 6) === '02') { winterChungchuDay += 1; winterChungchunSumFlow += flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; @@ -1601,38 +1602,38 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) let totWinterTotalInflAmnt = 0; totWinterTotalInflAmnt = (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0) + (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0) + (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0); - if(winterChungchunTotalInflAmntMax < totWinterTotalInflAmnt) { + if (winterChungchunTotalInflAmntMax < totWinterTotalInflAmnt) { winterChungchunTotalInflAmntMax = totWinterTotalInflAmnt; } - if(winterChungchunTotalInflAmntMin > totWinterTotalInflAmnt || winterChungchunTotalInflAmntMin === 0) { + if (winterChungchunTotalInflAmntMin > totWinterTotalInflAmnt || winterChungchunTotalInflAmntMin === 0) { winterChungchunTotalInflAmntMin = totWinterTotalInflAmnt; } - if(winterChungchunDayFlowMin > (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0)) { + if (winterChungchunDayFlowMin > (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0)) { winterChungchunDayFlowMin = flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; } - if(winterChungchunDayFlowMax < (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0)) { + if (winterChungchunDayFlowMax < (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0)) { winterChungchunDayFlowMax = flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; } - if(minWinterChungchunSumFlow > (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0) ) { + if (minWinterChungchunSumFlow > (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0)) { minWinterChungchunSumFlow = flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; } - if(maxWinterChungchunSumFlow < (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0)) { + if (maxWinterChungchunSumFlow < (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0)) { maxWinterChungchunSumFlow = flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; } - if(winterChungchunDayReturnMin > (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0)) { + if (winterChungchunDayReturnMin > (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0)) { winterChungchunDayReturnMin = flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; } - if(winterChungchunDayReturnMax < (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0)) { + if (winterChungchunDayReturnMax < (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0)) { winterChungchunDayReturnMax = flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; } - if(winterChungchunDayEfflMin > (flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0)) { + if (winterChungchunDayEfflMin > (flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0)) { winterChungchunDayEfflMin = flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; } - if(winterChungchunDayEfflMax < (flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0)) { + if (winterChungchunDayEfflMax < (flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0)) { winterChungchunDayEfflMax = flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; } } @@ -1640,7 +1641,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) // 하절기 강우시 계산 calRainData.forEach((flowItem: any) => { - if(flowItem.msrDt.substring(4,6) === '06' || flowItem.msrDt.substring(4,6) === '07' || flowItem.msrDt.substring(4,6) === '08') { + if (flowItem.msrDt.substring(4, 6) === '06' || flowItem.msrDt.substring(4, 6) === '07' || flowItem.msrDt.substring(4, 6) === '08') { summerRainDay += 1; summerRainDaySumFlow += flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; summerRainDayFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; @@ -1650,36 +1651,36 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) }); // 연계처리수 - yearAvgSumFlow = Number((yearSumFlow&&Number(yearSumFlow)!=0)?(yearSumFlow / yearDay):''); + yearAvgSumFlow = Number((yearSumFlow && Number(yearSumFlow) != 0) ? (yearSumFlow / yearDay) : ''); yearMaxSumFlow = maxYearSumFlow; yearMinSumFlow = minYearSumFlow; - summerAll = summerSumFlow&&Number(summerSumFlow)!=0?Number(summerSumFlow / summerDay):0 - summerThree= summerRainDaySumFlow&&Number(summerRainDaySumFlow)!=0?Number(summerRainDaySumFlow / summerRainDay):0; - summerRain = summerChungchunSumFlow&&Number(summerChungchunSumFlow)!=0?Number(summerChungchunSumFlow / summerChungchunDay):0; - winterAll = winterSumFlow&&Number(winterSumFlow)!=0?Number(winterSumFlow / winterDay):0; + summerAll = summerSumFlow && Number(summerSumFlow) != 0 ? Number(summerSumFlow / summerDay) : 0 + summerThree = summerRainDaySumFlow && Number(summerRainDaySumFlow) != 0 ? Number(summerRainDaySumFlow / summerRainDay) : 0; + summerRain = summerChungchunSumFlow && Number(summerChungchunSumFlow) != 0 ? Number(summerChungchunSumFlow / summerChungchunDay) : 0; + winterAll = winterSumFlow && Number(winterSumFlow) != 0 ? Number(winterSumFlow / winterDay) : 0; winterSunnyMin = minWinterChungchunSumFlow; - winterSunnyAvg = winterChungchunSumFlow&&Number(winterChungchunSumFlow)!=0?(winterChungchunSumFlow / winterChungchuDay):0; + winterSunnyAvg = winterChungchunSumFlow && Number(winterChungchunSumFlow) != 0 ? (winterChungchunSumFlow / winterChungchuDay) : 0; winterSunnyMax = maxWinterChungchunSumFlow; // 하절기 강우시 계산 // 하수유입량 (강우시) - summerRainInflAmnt = summerRainDayFlow&&Number(summerRainDayFlow)!=0?Number(summerRainDayFlow / summerRainDay):0; + summerRainInflAmnt = summerRainDayFlow && Number(summerRainDayFlow) != 0 ? Number(summerRainDayFlow / summerRainDay) : 0; // 총인설비방류수 (강우시) - summerRainReturnAmnt = summerRainDayReturnFlow&&Number(summerRainDayReturnFlow)!=0?Number(summerRainDayReturnFlow / summerRainDay):0; + summerRainReturnAmnt = summerRainDayReturnFlow && Number(summerRainDayReturnFlow) != 0 ? Number(summerRainDayReturnFlow / summerRainDay) : 0; // 방루량 (강우시) - summerRainEfflAmnt = summerRainDayEfflFlow&&summerRainDayEfflFlow!=0?summerRainDayEfflFlow / summerRainDay:0; + summerRainEfflAmnt = summerRainDayEfflFlow && summerRainDayEfflFlow != 0 ? summerRainDayEfflFlow / summerRainDay : 0; // 동절기 청천시 계산 // 하수유입량 (청천시) 평균 - winterChungchunFlowAvg = sumWinterChungcunFlow&&Number(sumWinterChungcunFlow)!=0?(sumWinterChungcunFlow / winterChungchuDay):0; + winterChungchunFlowAvg = sumWinterChungcunFlow && Number(sumWinterChungcunFlow) != 0 ? (sumWinterChungcunFlow / winterChungchuDay) : 0; // 총인반류수 (청천시) 평균 - winterChungchunReturnAvg = winterChungchunDayReturnAvg&&Number(winterChungchunDayReturnAvg)!=0?(winterChungchunDayReturnAvg / winterChungchuDay):0; + winterChungchunReturnAvg = winterChungchunDayReturnAvg && Number(winterChungchunDayReturnAvg) != 0 ? (winterChungchunDayReturnAvg / winterChungchuDay) : 0; // 방류량 (청천시) 평균 - winterChungchunEfflAvg = winterChungchunDayEfflAvg&&Number(winterChungchunDayEfflAvg)!=0?(winterChungchunDayEfflAvg / winterChungchuDay):0; + winterChungchunEfflAvg = winterChungchunDayEfflAvg && Number(winterChungchunDayEfflAvg) != 0 ? (winterChungchunDayEfflAvg / winterChungchuDay) : 0; // 하수유입량 (청천시) 최대 winterChungchunFlowMax = winterChungchunDayFlowMax; // 총인반류수 (청천시) 최대 - winterChungchunReturnMax = winterChungchunDayReturnMax; + winterChungchunReturnMax = winterChungchunDayReturnMax; // 방류량 (청천시) 최대 winterChungchunEfflMax = winterChungchunDayEfflMax; // 하수유입량 (청천시) 최소 @@ -1704,15 +1705,15 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) const usage = chungcunSumFlow / calData.length; const summerUsage = sumSummerChungcunFlow / summerChungchunDay; const winterUsage = sumWinterChungcunFlow / winterChungchuDay; - + // 임시 계산변수값들 메인에 대입 summerChungchunFlow = summerUsage; summerChungchunReturnAmnt = summerChungchunDayReturnAmnt / summerChungchunDay; summerChungchunEfflAmnt = summerChungchunDayEfflAmnt / summerChungchunDay; - operationalStatusList[0].groundWaterAvg = Math.round((usage-(usage*0.65*OSU_PERCENT)) * 100) / 100; - operationalStatusList[0].groundWaterSummer = Math.round((summerUsage-(summerUsage*0.65*OSU_PERCENT)) * 100) / 100; - operationalStatusList[0].groundWaterWinter = Math.round((winterUsage-(winterUsage*0.65*OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterAvg = Math.round((usage - (usage * 0.65 * OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (summerUsage * 0.65 * OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (winterUsage * 0.65 * OSU_PERCENT)) * 100) / 100; //operationalStatusList[0].groundWaterAvg = calData.length === 0 ? '' : Number(calData[0].inflAmnt) - (Number(calData[0].inflAmnt)*0.65*0.8); //operationalStatusList[0].groundWaterSummer = calData.length === 0 ? '' : Number(calData[0].inflAmnt) - (Number(calData[0].inflAmnt)*0.65*0.8); @@ -1734,12 +1735,12 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) const summerMonth = ['06', '07', '08']; const winterMonth = ['01', '02']; - wqltDataTot.filter(item=>summerMonth.includes(item.msrDt.toString().replaceAll('-','').substring(4,6))).forEach(item2 => { - if(Number(item2.infoRnDay)>=3){ + wqltDataTot.filter(item => summerMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { + if (Number(item2.infoRnDay) >= 3) { const inflBod = Number(item2.inflAssctBfrWqltBod); const infl = Number(item2.inflAmnt); const rain = Number(item2.infoRnDay); - if(inflBod < minSummerBod){ + if (inflBod < minSummerBod) { minSummerBodInfl = infl; minSummerBod = inflBod; rdiRain = rain; @@ -1747,24 +1748,24 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) } }); - wqltDataSunny.filter(item=>winterMonth.includes(item.msrDt.toString().replaceAll('-','').substring(4,6))).forEach(item2 => { + wqltDataSunny.filter(item => winterMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { winterBodSunny += Number(item2.inflAssctBfrWqltBod); winterCnt += 1; }); - const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',','')); - const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',','')); - const roundWinterBodSunny = Number(roundNumber(winterBodSunny, 1).toString().replaceAll(',','')); + const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',', '')); + const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',', '')); + const roundWinterBodSunny = Number(roundNumber(winterBodSunny, 1).toString().replaceAll(',', '')); - const winterBodAvg = Number(roundNumber((roundWinterBodSunny / winterCnt), 1).toString().replaceAll(',','')); + 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); + rdiPercent = (rdiValue / minSummerBodInfl) * 100; - operationalStatusList[0].rdi = rdiValue; + operationalStatusList[0].rdi = rdiValue; operationalStatusList[0].rdiRain = rdiRain; /* const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; @@ -1774,35 +1775,35 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) operationalStatusList[0].rdiRain = summerLowRain; */ } - if(operationalStatusList[0] && operationalStatusList[7]){ - operationalStatusList[7].groundWaterAvg = operationalStatusList[0].groundWaterAvg === null ? '' : data.yearData && data.yearData.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterAvg.toString().replaceAll(',', '')) / (data.yearData && data.yearData.AVG_INFL_AMNT ? Number(data.yearData.AVG_INFL_AMNT.toString().replaceAll(',','')) : 0) * 100) * 10) / 10+'%'; - operationalStatusList[7].groundWaterSummer = operationalStatusList[0].groundWaterSummer === null ? '' : data.summer && data.summer.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterSummer.toString().replaceAll(',','')) / (data.summer && data.summer.AVG_INFL_AMNT ? Number(data.summer.AVG_INFL_AMNT.toString().replaceAll(',','')) : 0) * 100) * 10) / 10+'%'; - operationalStatusList[7].groundWaterWinter = operationalStatusList[0].groundWaterWinter === null ? '' : data.winter && data.winter.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterWinter.toString().replaceAll(',','')) / (data.winter && data.winter.AVG_INFL_AMNT ? Number(data.winter.AVG_INFL_AMNT.toString().replaceAll(',','')) : 0) * 100) * 10) / 10+'%'; - operationalStatusList[7].rdi = roundNumber(rdiPercent, 1)+'%'; + if (operationalStatusList[0] && operationalStatusList[7]) { + operationalStatusList[7].groundWaterAvg = operationalStatusList[0].groundWaterAvg === null ? '' : data.yearData && data.yearData.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterAvg.toString().replaceAll(',', '')) / (data.yearData && data.yearData.AVG_INFL_AMNT ? Number(data.yearData.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + operationalStatusList[7].groundWaterSummer = operationalStatusList[0].groundWaterSummer === null ? '' : data.summer && data.summer.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterSummer.toString().replaceAll(',', '')) / (data.summer && data.summer.AVG_INFL_AMNT ? Number(data.summer.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + operationalStatusList[7].groundWaterWinter = operationalStatusList[0].groundWaterWinter === null ? '' : data.winter && data.winter.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterWinter.toString().replaceAll(',', '')) / (data.winter && data.winter.AVG_INFL_AMNT ? Number(data.winter.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + operationalStatusList[7].rdi = roundNumber(rdiPercent, 1) + '%'; /* operationalStatusList[7].groundWaterAvg = operationalStatusList[0].groundWaterAvg === null ? '' : Number(Number(operationalStatusList[0].groundWaterAvg) / Number(data.yearData.AVG_INFL_AMNT)) * 100; operationalStatusList[7].groundWaterSummer = operationalStatusList[0].groundWaterSummer === null ? '' : Number(Number(operationalStatusList[0].groundWaterSummer) / Number(data.summer.AVG_INFL_AMNT)) * 100; operationalStatusList[7].groundWaterWinter = operationalStatusList[0].groundWaterWinter === null ? '' : Number(Number(operationalStatusList[0].groundWaterWinter) / Number(data.winter.AVG_INFL_AMNT)) * 100;*/ } - for(let i=1; i<operationalStatusList.length; i++){ + for (let i = 1; i < operationalStatusList.length; i++) { const txtArray = ['1', 'INFL_AMNT', 'SUM_FLOW', 'RETURN_AMNT', 'EFFL_AMNT', 'INFL_ASSCT_BFR_WQLT_BOD', 'EFFL_WQLT_BOD', 'INFL_ASSCT_BFR_WQLT_TN', 'EFFL_WQLT_TN', 'INFL_ASSCT_BFR_WQLT_TP', 'EFFL_WQLT_TP', 'TP_INFL_WQLT_TP', 'EFFL_WQLT_TP']; - if(operationalStatusList[i]){ - if(i < 7){ + if (operationalStatusList[i]) { + if (i < 7) { changeValue(operationalStatusList[i], data, txtArray[i]); - if(i < 5){ + if (i < 5) { dataFormSetting(operationalStatusList[i]!); - }else{ + } else { dataFormSettingWqlty(operationalStatusList[i]!); } - }else{ + } else { calcValue(operationalStatusList[i], data, txtArray[i]); } } } // 순수하수량 - if(operationalStatusList[1]){ + if (operationalStatusList[1]) { operationalStatusList[1].summerThree = summerRainInflAmnt; operationalStatusList[1].summerRain = summerChungchunFlow; operationalStatusList[1].winterSunnyAvg = winterChungchunFlowAvg; @@ -1812,7 +1813,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) } // 연계처리수 - if(operationalStatusList[2]){ + if (operationalStatusList[2]) { operationalStatusList[2].yearAvg = yearAvgSumFlow; operationalStatusList[2].yearMax = yearMaxSumFlow; operationalStatusList[2].yearMin = yearMinSumFlow; @@ -1827,7 +1828,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) } // 총인설비방류수 - if(operationalStatusList[3]){ + if (operationalStatusList[3]) { operationalStatusList[3].summerThree = summerRainReturnAmnt; operationalStatusList[3].summerRain = summerChungchunReturnAmnt; operationalStatusList[3].winterSunnyAvg = winterChungchunReturnAvg; @@ -1837,7 +1838,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) } // 방류수 - if(operationalStatusList[4]){ + if (operationalStatusList[4]) { operationalStatusList[4].summerThree = summerRainEfflAmnt; operationalStatusList[4].summerRain = summerChungchunEfflAmnt; operationalStatusList[4].winterSunnyAvg = winterChungchunEfflAvg; @@ -1882,15 +1883,15 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) } } - const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd); + const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd); // 수질 데이터 청천시, 강우시 재계산 // 총인설비가 없을 경우 제외 - console.log('총인시설 여부 : ', data.yearData?.TP_FCT_YN); + console.log('총인시설 여부 : ', data.yearData?.TP_FCT_YN); console.log('rtnData : ', rtnData); - if(data.yearData?.TP_FCT_YN !== 'Y') { + if (data.yearData?.TP_FCT_YN !== 'Y') { operationalStatusList = rtnData.slice(0, 11); - }else{ + } else { operationalStatusList = rtnData; } set((state: DashBoardType) => ({ @@ -1899,11 +1900,11 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) ...state.OperationStatus, operationalStatusList: operationalStatusList, operationalStatusCount: res.count, - isLoadingOperationStatus : false, + isLoadingOperationStatus: false, }, })) }, - + searchMainGraph: async (searchYear: string, fcltyCd: string) => { set((state: DashBoardType) => ({ ...state, @@ -1920,14 +1921,14 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) calData.forEach((flowItem: any) => { chungcunSumFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; }); - const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / calData.length:0; - + const usage = chungcunSumFlow && chungcunSumFlow > 0 ? chungcunSumFlow / calData.length : 0; + //bscFctCd === '11200PB001R') 중랑 - 테스트할 때 코드넣고 해야 보기편해요~ /* if(bscFctCd === '11200PB001R') { console.log('calData.length : ', calData.length); console.log('usage : ', usage, 'summerUsage : ', summerUsage, 'winterUsage : ', winterUsage); } */ - const underWaterInputYear = Math.round((usage-(usage*0.65*OSU_PERCENT)) * 1) / 1; + const underWaterInputYear = Math.round((usage - (usage * 0.65 * OSU_PERCENT)) * 1) / 1; // 법적방류수질 데이터 const sortedWaterQltyInfo = [...res2].sort((a, b) => { @@ -1935,17 +1936,17 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) const numA = Number(a.extnsSeqno); const numB = Number(b.extnsSeqno); if (!isNaN(numA) && !isNaN(numB)) { - return numA - numB; + return numA - numB; } // 숫자 변환이 실패하면 문자열로 비교 return String(a.extnsSeqno).localeCompare(String(b.extnsSeqno)); }); - const waterQltyStandartd : any = sortedWaterQltyInfo && sortedWaterQltyInfo.length > 0 + const waterQltyStandartd: any = sortedWaterQltyInfo && sortedWaterQltyInfo.length > 0 ? sortedWaterQltyInfo[sortedWaterQltyInfo.length - 1] : []; - if(res == null || res.data == null || res.data.length === 0) { + if (res == null || res.data == null || res.data.length === 0) { set((state: DashBoardType) => ({ ...state, MainGraph: { @@ -1959,61 +1960,61 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) chart_efflTn: [], chart_inflBod: [], chart_efflBod: [], - waterQltyStandartd : [], - isLoadingMainGraph : false, + waterQltyStandartd: [], + isLoadingMainGraph: false, } })); return; } - + const chart_inflowRain = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), barVal0: item.infoRnDay ?? 0, lineVal0: underWaterInputYear, lineVal1: item.inflAmnt ?? 0, })); - + const chart_bodRain = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), barVal0: item.infoRnDay ?? 0, lineVal0: item.inflAssctBfrWqltBod ?? 0, })); const chart_inflTp = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : item.inflAssctBfrWqltTp ?? 0 + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: item.inflAssctBfrWqltTp ?? 0 })); - + const chart_chongInTp = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : Number(item.tpInflWqltTp) == 0 ? null : item.tpInflWqltTp + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: Number(item.tpInflWqltTp) == 0 ? null : item.tpInflWqltTp })); - + const chart_efflTp = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : item.efflWqltTp ?? 0 + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: item.efflWqltTp ?? 0 })); const chart_inflTn = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : item.inflAssctBfrWqltTn ?? 0 + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: item.inflAssctBfrWqltTn ?? 0 })); const chart_efflTn = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : item.efflWqltTn ?? 0 + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: item.efflWqltTn ?? 0 })); const chart_inflBod = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : item.inflAssctBfrWqltBod ?? 0 + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: item.inflAssctBfrWqltBod ?? 0 })); - + const chart_efflBod = res.data.wqltObjs.map((item: FacilityWaterQltyProps) => ({ - label: item.msrDt.substring(0, 4)+"-"+item.msrDt.substring(4, 6)+"-"+item.msrDt.substring(6, 8), - val : item.efflWqltBod ?? 0 + label: item.msrDt.substring(0, 4) + "-" + item.msrDt.substring(4, 6) + "-" + item.msrDt.substring(6, 8), + val: item.efflWqltBod ?? 0 })); - + set((state: DashBoardType) => ({ ...state, MainGraph: { @@ -2021,19 +2022,19 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) chart_inflowRain: chart_inflowRain, chart_bodRain: chart_bodRain, chart_inflTp: chart_inflTp, - chart_chongInTp : chart_chongInTp, + chart_chongInTp: chart_chongInTp, chart_efflTp: chart_efflTp, chart_inflTn: chart_inflTn, chart_efflTn: chart_efflTn, chart_inflBod: chart_inflBod, chart_efflBod: chart_efflBod, - waterQltyStandartd : waterQltyStandartd, - isLoadingMainGraph : false, + waterQltyStandartd: waterQltyStandartd, + isLoadingMainGraph: false, }, })) }, - searchRainManage: async (searchYear: string, fcltyCd: string, isExcel : boolean) => { + searchRainManage: async (searchYear: string, fcltyCd: string, isExcel: boolean) => { set((state: DashBoardType) => ({ ...state, RainManage: { @@ -2042,13 +2043,13 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) }, })); const res = await fetchMainGraph(searchYear, fcltyCd); - if(res == null || res.data.wqltObjs == null || res.data.wqltObjs.length === 0) { + if (res == null || res.data.wqltObjs == null || res.data.wqltObjs.length === 0) { set((state: DashBoardType) => ({ ...state, RainManage: { ...state.RainManage, rainManageList: [], - isLoadingRainManage : false, + isLoadingRainManage: false, } })); return; @@ -2092,7 +2093,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) const rainEffectList = CalcRainEffect(res.data.wqltObjs, 'RAIN_DAY'); // Process the data and create rain management list - const totItemCnt = rainEffectList?rainEffectList.length : 1; + const totItemCnt = rainEffectList ? rainEffectList.length : 1; let totInflAssctBfrWqltBod = 0; let totInflAssctBfrWqltToc = 0; let totInflAssctBfrWqltSs = 0; @@ -2116,9 +2117,9 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) totEfflWqltTn += item.efflWqltTn ? Number(item.efflWqltTn.toString().trim()) : 0; totEfflWqltTp += item.efflWqltTp ? Number(item.efflWqltTp.toString().trim()) : 0; - const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; + const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; - if(toBeRain >= 3 && toBeRain < 10){ + if (toBeRain >= 3 && toBeRain < 10) { rainDate[1] = Number(rainDate[1] || 0) + 1; inflAmtCnt[1] = Number(inflAmtCnt[1] || 0) + 1; inflAmnt[1] = Number(inflAmnt[1] || 0) + Number(item.inflAmnt || 0); @@ -2134,7 +2135,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) inflAssctBfrWqltTpCnt[1] = Number(inflAssctBfrWqltTpCnt[1] || 0) + 1; inflAssctBfrWqltTp[1] = Number(inflAssctBfrWqltTp[1] || 0) + Number(item.inflAssctBfrWqltTp || 0); efflWqltBodCnt[1] = Number(efflWqltBodCnt[1] || 0) + 1; - efflWqltBod[1] = Number(efflWqltBod[1] || 0) + Number(item.efflWqltBod || 0); + efflWqltBod[1] = Number(efflWqltBod[1] || 0) + Number(item.efflWqltBod || 0); efflWqltTocCnt[1] = Number(efflWqltTocCnt[1] || 0) + 1; efflWqltToc[1] = Number(efflWqltToc[1] || 0) + Number(item.efflWqltToc || 0); efflWqltSsCnt[1] = Number(efflWqltSsCnt[1] || 0) + 1; @@ -2143,7 +2144,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTn[1] = Number(efflWqltTn[1] || 0) + Number(item.efflWqltTn || 0); efflWqltTpCnt[1] = Number(efflWqltTpCnt[1] || 0) + 1; efflWqltTp[1] = Number(efflWqltTp[1] || 0) + Number(item.efflWqltTp || 0); - }else if(toBeRain >= 10 && toBeRain < 20){ + } else if (toBeRain >= 10 && toBeRain < 20) { rainDate[2] = Number(rainDate[2] || 0) + 1; inflAmtCnt[2] = Number(inflAmtCnt[2] || 0) + 1; inflAmnt[2] = Number(inflAmnt[2] || 0) + Number(item.inflAmnt || 0); @@ -2168,7 +2169,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTn[2] = Number(efflWqltTn[2] || 0) + Number(item.efflWqltTn || 0); efflWqltTpCnt[2] = Number(efflWqltTpCnt[2] || 0) + 1; efflWqltTp[2] = Number(efflWqltTp[2] || 0) + Number(item.efflWqltTp || 0); - }else if(toBeRain >= 20 && toBeRain < 30){ + } else if (toBeRain >= 20 && toBeRain < 30) { rainDate[3] = Number(rainDate[3] || 0) + 1; inflAmtCnt[3] = Number(inflAmtCnt[3] || 0) + 1; inflAmnt[3] = Number(inflAmnt[3] || 0) + Number(item.inflAmnt || 0); @@ -2193,11 +2194,11 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTn[3] = Number(efflWqltTn[3] || 0) + Number(item.efflWqltTn || 0); efflWqltTpCnt[3] = Number(efflWqltTpCnt[3] || 0) + 1; efflWqltTp[3] = Number(efflWqltTp[3] || 0) + Number(item.efflWqltTp || 0); - }else if(toBeRain >= 30 && toBeRain < 40){ + } else if (toBeRain >= 30 && toBeRain < 40) { rainDate[4] = Number(rainDate[4] || 0) + 1; inflAmtCnt[4] = Number(inflAmtCnt[4] || 0) + 1; inflAmnt[4] = Number(inflAmnt[4] || 0) + Number(item.inflAmnt || 0); - fcltyCpct[4] = item.inflAmnt&&Number(item.inflAmnt) !== 0 ? Number(Math.round(Number(item.inflAmnt) / Number(item.fctCpc) * 10) / 10) : 0; + fcltyCpct[4] = item.inflAmnt && Number(item.inflAmnt) !== 0 ? Number(Math.round(Number(item.inflAmnt) / Number(item.fctCpc) * 10) / 10) : 0; inflAssctBfrWqltBodCnt[4] = Number(inflAssctBfrWqltBodCnt[4] || 0) + 1; inflAssctBfrWqltBod[4] = Number(inflAssctBfrWqltBod[4] || 0) + Number(item.inflAssctBfrWqltBod || 0); inflAssctBfrWqltTocCnt[4] = Number(inflAssctBfrWqltTocCnt[4] || 0) + 1; @@ -2218,7 +2219,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTn[4] = Number(efflWqltTn[4] || 0) + Number(item.efflWqltTn || 0); efflWqltTpCnt[4] = Number(efflWqltTpCnt[4] || 0) + 1; efflWqltTp[4] = Number(efflWqltTp[4] || 0) + Number(item.efflWqltTp || 0); - }else if(toBeRain >= 40 && toBeRain < 50){ + } else if (toBeRain >= 40 && toBeRain < 50) { rainDate[5] = Number(rainDate[5] || 0) + 1; inflAmtCnt[5] = Number(inflAmtCnt[5] || 0) + 1; inflAmnt[5] = Number(inflAmnt[5] || 0) + Number(item.inflAmnt || 0); @@ -2243,7 +2244,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTn[5] = Number(efflWqltTn[5] || 0) + Number(item.efflWqltTn || 0); efflWqltTpCnt[5] = Number(efflWqltTpCnt[5] || 0) + 1; efflWqltTp[5] = Number(efflWqltTp[5] || 0) + Number(item.efflWqltTp || 0); - }else if(toBeRain >= 50 && toBeRain < 60){ + } else if (toBeRain >= 50 && toBeRain < 60) { rainDate[6] = Number(rainDate[6] || 0) + 1; inflAmtCnt[6] = Number(inflAmtCnt[6] || 0) + 1; inflAmnt[6] = Number(inflAmnt[6] || 0) + Number(item.inflAmnt || 0); @@ -2268,7 +2269,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTn[6] = Number(efflWqltTn[6] || 0) + Number(item.efflWqltTn || 0); efflWqltTpCnt[6] = Number(efflWqltTpCnt[6] || 0) + 1; efflWqltTp[6] = Number(efflWqltTp[6] || 0) + Number(item.efflWqltTp || 0); - }else if(toBeRain >= 60){ + } else if (toBeRain >= 60) { rainDate[7] = Number(rainDate[7] || 0) + 1; inflAmtCnt[7] = Number(inflAmtCnt[7] || 0) + 1; inflAmnt[7] = Number(inflAmnt[7] || 0) + Number(item.inflAmnt || 0); @@ -2295,18 +2296,18 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltTp[7] = Number(efflWqltTp[7] || 0) + Number(item.efflWqltTp || 0); } }); - + // Process the data and create rain management list - if(res.data&&res.data.dsWqltObjs&&res.data.dsWqltObjs.length > 0){ + if (res.data && res.data.dsWqltObjs && res.data.dsWqltObjs.length > 0) { // 설계 유입수질 데이터 가져오기 - 0값이 있으면 이전 차수에서 가져오기 const getDesignWaterQualityData = (stepIndex: number, maxPreviousSteps: number = 3) => { for (let i = 0; i <= maxPreviousSteps && stepIndex - i >= 0; i++) { const currentStep = res.data.dsWqltObjs[stepIndex - i]; - if (currentStep && - currentStep.dsInflWqltBod > 0 && - currentStep.dsInflWqltCod > 0 && - currentStep.dsInflWqltSs > 0 && - currentStep.dsInflWqltTn > 0 && + if (currentStep && + currentStep.dsInflWqltBod > 0 && + currentStep.dsInflWqltCod > 0 && + currentStep.dsInflWqltSs > 0 && + currentStep.dsInflWqltTn > 0 && currentStep.dsInflWqltTp > 0) { return { dsInflWqltBod: currentStep.dsInflWqltBod, @@ -2329,23 +2330,23 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) const lastStepIndex = res.data.dsWqltObjs.length - 1; const designData = getDesignWaterQualityData(lastStepIndex); - + dsInflWqltBod[0] = designData.dsInflWqltBod; dsInflWqltCod[0] = designData.dsInflWqltCod; dsInflWqltSs[0] = designData.dsInflWqltSs; dsInflWqltTn[0] = designData.dsInflWqltTn; dsInflWqltTp[0] = designData.dsInflWqltTp; } - - rainDate[0] = (Number(rainDate[1]) || 0) + (Number(rainDate[2]) || 0) + (Number(rainDate[3]) || 0) + - (Number(rainDate[4]) || 0) + (Number(rainDate[5]) || 0) + (Number(rainDate[6]) || 0) + + + rainDate[0] = (Number(rainDate[1]) || 0) + (Number(rainDate[2]) || 0) + (Number(rainDate[3]) || 0) + + (Number(rainDate[4]) || 0) + (Number(rainDate[5]) || 0) + (Number(rainDate[6]) || 0) + (Number(rainDate[7]) || 0); - + // 강수비율 - for(let idx=0; idx<rainDate.length; idx++){ - if(Number(rainDate[idx]) > 0){ + for (let idx = 0; idx < rainDate.length; idx++) { + if (Number(rainDate[idx]) > 0) { rainRate[0] = '100'; - rainRate[idx] = (Math.round(Number(rainDate[idx])/Number(rainDate[0])*100*100)/100).toString(); + rainRate[idx] = (Math.round(Number(rainDate[idx]) / Number(rainDate[0]) * 100 * 100) / 100).toString(); } } @@ -2356,13 +2357,13 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) // 데이터 있는 항목만 계산 let dataIsCount = 0; - for(let idx=0; idx<inflAmnt.length; idx++){ - if(Number(inflAmnt[idx]) > 0){ + for (let idx = 0; idx < inflAmnt.length; idx++) { + if (Number(inflAmnt[idx]) > 0) { dataIsCount++; } } - for(let idx=0; idx<inflAmnt.length; idx++){ + for (let idx = 0; idx < inflAmnt.length; idx++) { inflAmnt[idx] = calculateAverage(Number(inflAmnt[idx]), Number(inflAmtCnt[idx])); inflAssctBfrWqltBod[idx] = calculateAverage(Number(inflAssctBfrWqltBod[idx]), Number(inflAssctBfrWqltBodCnt[idx])); inflAssctBfrWqltToc[idx] = calculateAverage(Number(inflAssctBfrWqltToc[idx]), Number(inflAssctBfrWqltTocCnt[idx])); @@ -2393,7 +2394,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) efflWqltSs[0] = Number((Math.round((totEfflWqltSs / totItemCnt) * 10) / 10).toFixed(1)); efflWqltTn[0] = Number((Math.round((totEfflWqltTn / totItemCnt) * 1000) / 1000).toFixed(3)); efflWqltTp[0] = Number((Math.round((totEfflWqltTp / totItemCnt) * 1000) / 1000).toFixed(3)); - + // 최종 리스트 const filteredData = itemList.map((item, index) => ({ rainItem: item, @@ -2411,15 +2412,15 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) inflAssctBfrWqltSs: inflAssctBfrWqltSs[index] ? (Math.round(inflAssctBfrWqltSs[index] * 10) / 10).toFixed(1) : '', inflAssctBfrWqltTn: inflAssctBfrWqltTn[index] ? (Math.round(inflAssctBfrWqltTn[index] * 1000) / 1000).toFixed(3) : '', inflAssctBfrWqltTp: inflAssctBfrWqltTp[index] ? (Math.round(inflAssctBfrWqltTp[index] * 1000) / 1000).toFixed(3) : '', - efflWqltBod: efflWqltBod[index] ? (Math.round(efflWqltBod[index] * 10) / 10).toFixed(1): '', + efflWqltBod: efflWqltBod[index] ? (Math.round(efflWqltBod[index] * 10) / 10).toFixed(1) : '', efflWqltToc: efflWqltToc[index] ? (Math.round(efflWqltToc[index] * 10) / 10).toFixed(1) : '', efflWqltSs: efflWqltSs[index] ? (Math.round(efflWqltSs[index] * 10) / 10).toFixed(1) : '', efflWqltTn: efflWqltTn[index] ? (Math.round(efflWqltTn[index] * 1000) / 1000).toFixed(3) : '', efflWqltTp: efflWqltTp[index] ? (Math.round(efflWqltTp[index] * 1000) / 1000).toFixed(3) : '' })); - - const excelList : RainManageExcelType[] = []; - if(isExcel){ + + const excelList: RainManageExcelType[] = []; + if (isExcel) { filteredData.forEach((item) => { excelList.push({ 강우량: item.rainItem, @@ -2430,7 +2431,7 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) 설계유입수질BOD: item.dsInflWqltBod ? (Math.round(Number(item.dsInflWqltBod) * 10) / 10).toFixed(1) : '', 설계유입수질TOC: item.dsInflWqltCod ? (Math.round(Number(item.dsInflWqltCod) * 10) / 10).toFixed(1) : '', 설계유입수질SS: item.dsInflWqltSs ? (Math.round(Number(item.dsInflWqltSs) * 10) / 10).toFixed(1) : '', - 설계유입수질TN: item.dsInflWqltTn ?(Math.round(Number(item.dsInflWqltTn) * 1000) / 1000).toFixed(3) : '', + 설계유입수질TN: item.dsInflWqltTn ? (Math.round(Number(item.dsInflWqltTn) * 1000) / 1000).toFixed(3) : '', 설계유입수질TP: item.dsInflWqltTp ? (Math.round(Number(item.dsInflWqltTp) * 1000) / 1000).toFixed(3) : '', 유입수질BOD: item.inflAssctBfrWqltBod ? (Math.round(Number(item.inflAssctBfrWqltBod) * 10) / 10).toFixed(1) : '', 유입수질TOC: item.inflAssctBfrWqltToc ? (Math.round(Number(item.inflAssctBfrWqltToc) * 10) / 10).toFixed(1) : '', @@ -2445,18 +2446,18 @@ export const dashBoardReducer:(set:(fn: (state: DashBoardType) => DashBoardType) }); }); } - + set((state: DashBoardType) => ({ ...state, RainManage: isExcel ? { ...state.RainManage, rainManageList: filteredData as any[], excelList: excelList, - isLoadingRainManage : false, + isLoadingRainManage: false, } : { ...state.RainManage, rainManageList: filteredData as any[], - isLoadingRainManage : false, + isLoadingRainManage: false, } })); }, From 6d0c8c9fba8265e4947d22c8796c1b6b1b24411c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A7=80=EC=B2=A0?= <jcchoi@onasys.co.kr> Date: Mon, 29 Dec 2025 18:16:37 +0900 Subject: [PATCH 03/92] =?UTF-8?q?=ED=99=98=EA=B2=BD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cm/next.config.ts | 20 ++++++++++++++------ apps/cs/next.config.ts | 14 ++++++++++++++ packages/common/components/src/api/menu.ts | 2 +- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/apps/cm/next.config.ts b/apps/cm/next.config.ts index 679528324..b388b76d9 100644 --- a/apps/cm/next.config.ts +++ b/apps/cm/next.config.ts @@ -3,10 +3,22 @@ import type { NextConfig } from "next"; const subDomain = process.env.NEXT_PUBLIC_SUB_DOMAIN || "http://localhost:13000"; -const backendUrl = process.env.NEXT_PUBLIC_SERVER_API_URL || "http://192.168.0.102:8000"; - const nextConfig: NextConfig = { output: "standalone", + experimental: { + proxyTimeout: 600000, + }, + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, + logging: { + fetches: { + fullUrl: true, + }, + }, async rewrites() { return { beforeFiles: [ @@ -27,10 +39,6 @@ const nextConfig: NextConfig = { source: "/cms/:path*", destination: `${subDomain}/cms/:path*`, }, - { - source: "/user-service/:path*", - destination: `${backendUrl}/user-service/:path*`, - }, ], fallback: [], }; diff --git a/apps/cs/next.config.ts b/apps/cs/next.config.ts index d75960377..61d7f72cc 100644 --- a/apps/cs/next.config.ts +++ b/apps/cs/next.config.ts @@ -5,6 +5,20 @@ const subDomain = const nextConfig: NextConfig = { output: "standalone", + experimental: { + proxyTimeout: 600000, + }, + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, + logging: { + fetches: { + fullUrl: true, + }, + }, async headers() { return [ { diff --git a/packages/common/components/src/api/menu.ts b/packages/common/components/src/api/menu.ts index ce6465b84..b4d84c95e 100644 --- a/packages/common/components/src/api/menu.ts +++ b/packages/common/components/src/api/menu.ts @@ -49,7 +49,7 @@ export const getAnonymouseMenuList = async ( siteId: string, ): Promise<MenuItem[]> => { const response = await fetch( - `${BASE_URL}/${ENDPOINT.CMS_SERVICE.MENU_ANONYMOUS}/user/${siteId}`, + `${BASE_URL}${ENDPOINT.CMS_SERVICE.MENU_ANONYMOUS}/user/${siteId}`, { method: "GET", headers: { From dafb3b0f9fff27b4d45ca628a6957aab9479616b Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Tue, 30 Dec 2025 07:23:59 +0900 Subject: [PATCH 04/92] =?UTF-8?q?fo:=20=EC=88=98=EC=A0=95=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 257 +++++++++++--------------- 1 file changed, 103 insertions(+), 154 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index d1fbdcfe1..ac041391e 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1403,37 +1403,21 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp const res = await fetchOperationStatus(searchYear, fcltyCd); // /dashBoard/mngInfo/ const data = res.data; - let yearMaxSumFlow = 1; // 연간운영실태 최대 - let yearMinSumFlow = 1; // 연간운영실태 최소 - let yearAvgSumFlow = 1; // 연간운영실태 평균 + let yearMaxSumFlow = 1, yearMinSumFlow = 1, yearAvgSumFlow = 1; // 연간 최대, 최소, 평균 let summerAll = 1; // 하절기 전기간 let summerThree = 1; // 하절기 let summerRain = 1; // 하절기 let winterAll = 1; // 동절기 전기간 - let winterSunnyMin = 1; // 동절기 청천 최소 - let winterSunnyAvg = 1; // 동절기 청천 평균 - let winterSunnyMax = 1; // 동절기 청천 최대 + let winterSunnyMin = 1, winterSunnyAvg = 1, winterSunnyMax = 1; // 동절기 청천 최소, 평균, 최대 // 최대, 최소 총 유입량 (1년 하루 합계의 최대, 최소) - // 하절기 청천시, 강우시 재계산 리턴값 - let summerChungchunFlow = 1; // 하절기 청천 - let summerChungchunReturnAmnt = 1; // 하절기 청천 - let summerChungchunEfflAmnt = 1; // 하절기 청천 - let summerRainInflAmnt = 1; // 하절기 강우시 - let summerRainReturnAmnt = 1; // 하절기 강우시 - let summerRainEfflAmnt = 1; // 하절기 강우시 - + let summerChungchunFlow = 1, summerChungchunReturnAmnt = 1, summerChungchunEfflAmnt = 1; // 하절기 청천 + let summerRainInflAmnt = 1, summerRainReturnAmnt = 1, summerRainEfflAmnt = 1; // 하절기 강우시 // 동절기 청천시 최대, 최소, 평균 리턴값 - let winterChungchunFlowAvg = 1; // 동절기 청천 하수유입량 평균 - let winterChungchunFlowMax = 1; // 동절기 청천 하수유입량 최대 - let winterChungchunFlowMin = 1; // 동절기 청천 하수유입량 최소 - let winterChungchunReturnAvg = 1; // 동절기 청천 총인반류수 평균 - let winterChungchunReturnMax = 1; // 동절기 청천 총인반류수 최대 - let winterChungchunReturnMin = 1; // 동절기 청천 총인반류수 최소 - let winterChungchunEfflAvg = 1; // 동절기 청천 방류량 평균 - let winterChungchunEfflMax = 1; // 동절기 청천 방류량 최대 - let winterChungchunEfflMin = 1; // 동절기 청천 방류량 최소 + let winterChungchunFlowAvg = 1, winterChungchunFlowMax = 1, winterChungchunFlowMin = 1; // 동절기 청천 하수유입량 평균, 최대, 최소 + let winterChungchunReturnAvg = 1, winterChungchunReturnMax = 1, winterChungchunReturnMin = 1; // 동절기 청천 총인반류수 평균, 최대, 최소 + let winterChungchunEfflAvg = 1, winterChungchunEfflMax = 1, winterChungchunEfflMin = 1; // 동절기 청천 방류량 평균, 최대, 최소 const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; @@ -1458,12 +1442,11 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp (data.yearData.MIN_SUM_FLOW ? data.yearData.MIN_SUM_FLOW : 0) + // api 주석처리되어 있음. (data.yearData.MIN_RETURN_AMNT ? data.yearData.MIN_RETURN_AMNT : 0) // 반류수유량(m³/일) 최소 ); - - operationalStatusList[0].yearAvg = yearAvg; - operationalStatusList[0].yearMax = yearMax; - operationalStatusList[0].yearMin = yearMin; - // 여름 - operationalStatusList[0].summerAll = data.summer === null ? '' : ( + operationalStatusList[0].yearAvg = yearAvg; // 연간유입평균 + operationalStatusList[0].yearMax = yearMax; // 연간유입최대 + operationalStatusList[0].yearMin = yearMin; // 연간유입최소 + // 하절기 + operationalStatusList[0].summerAll = data.summer === null ? '' : ( // 하절기전기간 (data.summer.AVG_INFL_AMNT ? data.summer.AVG_INFL_AMNT : 0) + (data.summer.AVG_SUM_FLOW ? data.summer.AVG_SUM_FLOW : 0) ); @@ -1475,7 +1458,7 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp (data.summerSunny.AVG_INFL_AMNT ? data.summerSunny.AVG_INFL_AMNT : 0) + (data.summerSunny.AVG_SUM_FLOW ? data.summerSunny.AVG_SUM_FLOW : 0) ); - // 겨울 + // 동절기 operationalStatusList[0].winterAll = data.winter === null ? '' : ( // 동절기 전기간 (data.winter.AVG_INFL_AMNT ? data.winter.AVG_INFL_AMNT : 0) + (data.winter.AVG_SUM_FLOW ? data.winter.AVG_SUM_FLOW : 0) + @@ -1496,63 +1479,21 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp (data.winterSunny.MAX_SUM_FLOW ? data.winterSunny.MAX_SUM_FLOW : 0) + (data.winterSunny.MAX_TP_INFL_WQLT_TP ? data.winterSunny.MAX_TP_INFL_WQLT_TP : 0) ); + // 연계처리수 - let yearDay = 0; - let summerDay = 0; - let winterDay = 0; - let summerRainDay = 0; - let summerChungchunDay = 0; - let winterChungchuDay = 0; - - let totFlowMax = 0; - let totFlowMin = 9999999; - - let yearSumFlow = 0; - let maxYearSumFlow = 0; - let minYearSumFlow = 9999999; - let summerSumFlow = 0; - let summerChungchunSumFlow = 0; - let summerRainDaySumFlow = 0; - let summerRainDayFlow = 0; - let summerRainDayReturnFlow = 0; - let summerRainDayEfflFlow = 0; - - let winterSumFlow = 0; - let winterChungchunSumFlow = 0; - let minWinterChungchunSumFlow = 9999999; - let maxWinterChungchunSumFlow = 0; + let yearDay = 0, summerDay = 0, winterDay = 0; // 연간 일수, 하절기 일수, 동절기 일수 + let summerRainDay = 0, summerChungchunDay = 0, winterChungchuDay = 0; // 하절기 강우 일수, 하절기 청천 일수, 동절기 청천 일수 + let totFlowMax = 0, totFlowMin = 9999999; + let yearSumFlow = 0, maxYearSumFlow = 0, minYearSumFlow = 9999999; + let summerSumFlow = 0, summerChungchunSumFlow = 0, summerRainDaySumFlow = 0; // 하절기 유입량 합, 하절기 청천 유입량 합, 하절기 강우 유입량 합 + let summerRainDayFlow = 0, summerRainDayReturnFlow = 0, summerRainDayEfflFlow = 0; // 하절기 강우 유입량, 하절기 강우 반류량, 하절기 강우 방류량 + let winterSumFlow = 0; // 동절기 유입량 합 + let winterChungchunSumFlow = 0; // 동절기 청천 유입량 합 + let maxWinterChungchunSumFlow = 0, minWinterChungchunSumFlow = 9999999; // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - yearDay = res2.data ? res2.data.length : 1; - res2.data.forEach((item: any) => { - yearSumFlow += item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - if (maxYearSumFlow < (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0)) { - maxYearSumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - } - if (minYearSumFlow > (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0)) { - minYearSumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - } - - // 1년 최대 총 하수유입량 - let totYearFlow = 0; - totYearFlow = (item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0) + (item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0) + (item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0); - if (totFlowMax < totYearFlow) { - totFlowMax = totYearFlow; - } - if (totFlowMin > totYearFlow || totFlowMin === 0) { - totFlowMin = totYearFlow; - } - - if (item.msrDt.substring(4, 6) === '06' || item.msrDt.substring(4, 6) === '07' || item.msrDt.substring(4, 6) === '08') { - summerDay += 1; - summerSumFlow += item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - } else if (item.msrDt.substring(4, 6) === '01' || item.msrDt.substring(4, 6) === '02') { - winterDay += 1; - winterSumFlow += item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; - } - }); const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); @@ -1561,94 +1502,102 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp let chungcunSumFlow = 0; let sumSummerChungcunFlow = 0; let sumWinterChungcunFlow = 0; + let summerChungchunDayReturnAmnt = 0; // 하절기 청천시 총인설비 반류수 + let summerChungchunDayEfflAmnt = 0; // 하절기 청천시 총인설비 방류수 - // 하절기 청천시 총인설비 반류수 - let summerChungchunDayReturnAmnt = 0; - // 하절기 청천시 방류수 - let summerChungchunDayEfflAmnt = 0; - - // 동절기 총 유입량 최대, 최소 - let winterChungchunTotalInflAmntMax = 0; - let winterChungchunTotalInflAmntMin = 9999999; - // 동절기 청천시 하수유입량 최대, 최소 - let winterChungchunDayFlowMax = 0; - let winterChungchunDayFlowMin = 9999999; - // 동절기 청천시 총인반류수 최대, 최소, 평균 - let winterChungchunDayReturnMax = 0; - let winterChungchunDayReturnMin = 9999999; + let winterChungchunTotalInflAmntMax = 0, winterChungchunTotalInflAmntMin = 9999999; // 동절기 총 유입량 최대, 최소 + let winterChungchunDayFlowMax = 0, winterChungchunDayFlowMin = 9999999; // 동절기 청천시 하수유입량 최대, 최소 + let winterChungchunDayReturnMax = 0, winterChungchunDayReturnMin = 9999999; // 동절기 청천시 총인반류수 최대, 최소, 평균 let winterChungchunDayReturnAvg = 0; // 동절기 청천시 방류량 최대, 최소, 평균 - let winterChungchunDayEfflMax = 0; - let winterChungchunDayEfflMin = 9999999; - let winterChungchunDayEfflAvg = 0; + let winterChungchunDayEfflMax = 0, winterChungchunDayEfflMin = 9999999, winterChungchunDayEfflAvg = 0; - // 하절기, 동절기 청천시 계산 - calData.forEach((flowItem: any) => { - chungcunSumFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; + let rainEffectDay = 0; + yearDay = res2.data ? res2.data.length : 1; + res2.data.forEach((item: any) => { - if (flowItem.msrDt.substring(4, 6) === '06' || flowItem.msrDt.substring(4, 6) === '07' || flowItem.msrDt.substring(4, 6) === '08') { - summerChungchunDay += 1; - summerChungchunSumFlow += flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; - sumSummerChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; - summerChungchunDayReturnAmnt += flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; - summerChungchunDayEfflAmnt += flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; + const month = item.msrDt.substring(4, 6); // 월 추출 + const sumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; + const inflAmnt = item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0; + const returnAmnt = item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0; + const efflAmnt = item.efflAmnt && item.efflAmnt !== 'x' ? Number(item.efflAmnt.toString().trim()) : 0; - } else if (flowItem.msrDt.substring(4, 6) === '01' || flowItem.msrDt.substring(4, 6) === '02') { - winterChungchuDay += 1; - winterChungchunSumFlow += flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; - sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; - winterChungchunDayReturnAvg += flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; - winterChungchunDayEfflAvg += flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; + if (item.infoRnDay == null) item.infoRnDay = 0; + if (item.infoRnDay >= 3) { + rainEffectDay = 2; + // 강우시 + } else { + rainEffectDay--; + } - let totWinterTotalInflAmnt = 0; - totWinterTotalInflAmnt = (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0) + (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0) + (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0); - if (winterChungchunTotalInflAmntMax < totWinterTotalInflAmnt) { - winterChungchunTotalInflAmntMax = totWinterTotalInflAmnt; - } - if (winterChungchunTotalInflAmntMin > totWinterTotalInflAmnt || winterChungchunTotalInflAmntMin === 0) { - winterChungchunTotalInflAmntMin = totWinterTotalInflAmnt; + if (rainEffectDay >= 0) { + // 강우영향일 + if (month === '06' || month === '07' || month === '08') { // 하절기 + summerRainDay += 1; + summerRainDaySumFlow += sumFlow; + summerRainDayFlow += inflAmnt; + summerRainDayReturnFlow += returnAmnt; + summerRainDayEfflFlow += efflAmnt; } + } else if (rainEffectDay < 0) { + // 청천시 + chungcunSumFlow += inflAmnt; - if (winterChungchunDayFlowMin > (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0)) { - winterChungchunDayFlowMin = flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; - } - if (winterChungchunDayFlowMax < (flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0)) { - winterChungchunDayFlowMax = flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; - } + if (month === '06' || month === '07' || month === '08') { // 하절기 + summerChungchunDay += 1; + summerChungchunSumFlow += sumFlow; + sumSummerChungcunFlow += inflAmnt; + summerChungchunDayReturnAmnt += returnAmnt; + summerChungchunDayEfflAmnt += efflAmnt; - if (minWinterChungchunSumFlow > (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0)) { - minWinterChungchunSumFlow = flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; - } - if (maxWinterChungchunSumFlow < (flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0)) { - maxWinterChungchunSumFlow = flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; - } + } else if (month === '01' || month === '02') { // 동절기 + winterChungchuDay += 1; + winterChungchunSumFlow += sumFlow; + sumWinterChungcunFlow += inflAmnt; + winterChungchunDayReturnAvg += returnAmnt; + winterChungchunDayEfflAvg += efflAmnt; - if (winterChungchunDayReturnMin > (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0)) { - winterChungchunDayReturnMin = flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; - } - if (winterChungchunDayReturnMax < (flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0)) { - winterChungchunDayReturnMax = flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; - } + let totWinterTotalInflAmnt = 0; + totWinterTotalInflAmnt = inflAmnt + sumFlow + returnAmnt; + if (winterChungchunTotalInflAmntMax < totWinterTotalInflAmnt) winterChungchunTotalInflAmntMax = totWinterTotalInflAmnt; + if (winterChungchunTotalInflAmntMin > totWinterTotalInflAmnt || winterChungchunTotalInflAmntMin === 0) winterChungchunTotalInflAmntMin = totWinterTotalInflAmnt; - if (winterChungchunDayEfflMin > (flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0)) { - winterChungchunDayEfflMin = flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; - } - if (winterChungchunDayEfflMax < (flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0)) { - winterChungchunDayEfflMax = flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; + if (winterChungchunDayFlowMin > inflAmnt) winterChungchunDayFlowMin = inflAmnt; + if (winterChungchunDayFlowMax < inflAmnt) winterChungchunDayFlowMax = inflAmnt; + + if (minWinterChungchunSumFlow > sumFlow) minWinterChungchunSumFlow = sumFlow; + if (maxWinterChungchunSumFlow < sumFlow) maxWinterChungchunSumFlow = sumFlow; + + if (winterChungchunDayReturnMin > returnAmnt) winterChungchunDayReturnMin = returnAmnt; + if (winterChungchunDayReturnMax < returnAmnt) winterChungchunDayReturnMax = returnAmnt; + + if (winterChungchunDayEfflMin > efflAmnt) winterChungchunDayEfflMin = efflAmnt; + if (winterChungchunDayEfflMax < efflAmnt) winterChungchunDayEfflMax = efflAmnt; } } + + + yearSumFlow += sumFlow; + if (maxYearSumFlow < sumFlow) maxYearSumFlow = sumFlow; + if (minYearSumFlow > sumFlow) minYearSumFlow = sumFlow; + + // 1년 최대 총 하수유입량 + let totYearFlow = 0; + totYearFlow = inflAmnt + sumFlow + returnAmnt; + if (totFlowMax < totYearFlow) totFlowMax = totYearFlow; + if (totFlowMin > totYearFlow || totFlowMin === 0) { + totFlowMin = totYearFlow; + } + + if (month === '06' || month === '07' || month === '08') { + summerDay += 1; + summerSumFlow += sumFlow; + } else if (month === '01' || month === '02') { + winterDay += 1; + winterSumFlow += sumFlow; + } }); - // 하절기 강우시 계산 - calRainData.forEach((flowItem: any) => { - if (flowItem.msrDt.substring(4, 6) === '06' || flowItem.msrDt.substring(4, 6) === '07' || flowItem.msrDt.substring(4, 6) === '08') { - summerRainDay += 1; - summerRainDaySumFlow += flowItem.sumFlow && flowItem.sumFlow !== 'x' ? Number(flowItem.sumFlow.toString().trim()) : 0; - summerRainDayFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0; - summerRainDayReturnFlow += flowItem.returnAmnt && flowItem.returnAmnt !== 'x' ? Number(flowItem.returnAmnt.toString().trim()) : 0; - summerRainDayEfflFlow += flowItem.efflAmnt && flowItem.efflAmnt !== 'x' ? Number(flowItem.efflAmnt.toString().trim()) : 0; - } - }); // 연계처리수 yearAvgSumFlow = Number((yearSumFlow && Number(yearSumFlow) != 0) ? (yearSumFlow / yearDay) : ''); From 4cb1c47d61087be83cf00a9d59f591f00bd97e16 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 30 Dec 2025 09:51:32 +0900 Subject: [PATCH 05/92] =?UTF-8?q?fo:=20dashboard=20=EC=86=8D=EB=8F=84?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/src/entities/auth/lib/auth-wrapper.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx index 0c2d04830..c1b2ecd99 100644 --- a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect } from "react"; -import { useRouter, usePathname } from "next/navigation"; +import { useRouter} from "next/navigation"; import { client } from "@/src/shared/api"; import type { IUserInfo } from "@/src/shared/store"; import { useUserStore, getCookie } from "@/src/shared/lib"; @@ -12,7 +12,7 @@ const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://loca const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const router = useRouter(); - const pathname = usePathname(); + // const pathname = usePathname(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { @@ -53,7 +53,7 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { } } })(); - }, [pathname]); + }, []); return <>{children}</>; }; From ae96324783088d4d445a01ccf78d918e900382b8 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 30 Dec 2025 10:08:36 +0900 Subject: [PATCH 06/92] =?UTF-8?q?fo:=20undefined=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 12 +++++------- apps/fo/src/entities/auth/lib/auth-wrapper.tsx | 6 +++--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index ac041391e..60267e388 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1495,9 +1495,10 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp const bscFctCd = fcltyCd; const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); - const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); + //const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); + //const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); + let cntSunnyDay = 0; // 청천일 수 // 지하수유입량 - 청천시 기준 let chungcunSumFlow = 0; let sumSummerChungcunFlow = 0; @@ -1540,6 +1541,7 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp summerRainDayEfflFlow += efflAmnt; } } else if (rainEffectDay < 0) { + cntSunnyDay += 1; // 청천일수 // 청천시 chungcunSumFlow += inflAmnt; @@ -1651,7 +1653,7 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp operationalStatusList[0].winterSunnyAvg = roundUp(Number(operationalStatusList[0].winterSunnyAvg), 0) + roundUp(winterSunnyAvg, 0); // 지하수유입량 - const usage = chungcunSumFlow / calData.length; + const usage = chungcunSumFlow / cntSunnyDay; //calData.length; const summerUsage = sumSummerChungcunFlow / summerChungchunDay; const winterUsage = sumWinterChungcunFlow / winterChungchuDay; @@ -1664,10 +1666,6 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (summerUsage * 0.65 * OSU_PERCENT)) * 100) / 100; operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (winterUsage * 0.65 * OSU_PERCENT)) * 100) / 100; - //operationalStatusList[0].groundWaterAvg = calData.length === 0 ? '' : Number(calData[0].inflAmnt) - (Number(calData[0].inflAmnt)*0.65*0.8); - //operationalStatusList[0].groundWaterSummer = calData.length === 0 ? '' : Number(calData[0].inflAmnt) - (Number(calData[0].inflAmnt)*0.65*0.8); - //operationalStatusList[0].groundWaterWinter = calData.length === 0 ? '' : Number(calData[0].inflAmnt) - (Number(calData[0].inflAmnt)*0.65*0.8); - // 오염물질 // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) const resp = await fetchMainGraph(searchYear, fcltyCd); diff --git a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx index c1b2ecd99..0c2d04830 100644 --- a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/fo/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 "@/src/shared/api"; import type { IUserInfo } from "@/src/shared/store"; import { useUserStore, getCookie } from "@/src/shared/lib"; @@ -12,7 +12,7 @@ const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://loca const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const router = useRouter(); - // const pathname = usePathname(); + const pathname = usePathname(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { @@ -53,7 +53,7 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { } } })(); - }, []); + }, [pathname]); return <>{children}</>; }; From a6b03ddc4edb4b3ea0a3f86c34b44a06df8cf05f Mon Sep 17 00:00:00 2001 From: jcchoi <jcchoi@onasys.co.kr> Date: Tue, 30 Dec 2025 11:21:21 +0900 Subject: [PATCH 07/92] Delete apps/cm/.env.development MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 환경설정 삭제 --- apps/cm/.env.development | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 apps/cm/.env.development diff --git a/apps/cm/.env.development b/apps/cm/.env.development deleted file mode 100644 index 9f786831b..000000000 --- a/apps/cm/.env.development +++ /dev/null @@ -1,7 +0,0 @@ -# apps/cs/src/shared/config/env.ts 참고 -NEXT_PUBLIC_PORT=3000 -NEXT_PUBLIC_PROXY_HOST=http://localhost:3000 -NEXT_PUBLIC_SITE_ID=CS -NEXT_PUBLIC_SUB_DOMAIN=http://localhost:3000 -NEXT_PUBLIC_SERVER_API_URL=http://192.168.0.102:8000 -NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2 \ No newline at end of file From a161cb23463e1c1959a421e61467476ef77cc929 Mon Sep 17 00:00:00 2001 From: jcchoi <jcchoi@onasys.co.kr> Date: Tue, 30 Dec 2025 11:21:34 +0900 Subject: [PATCH 08/92] Delete apps/cm/.env.local MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 환경설정 삭제 --- apps/cm/.env.local | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 apps/cm/.env.local diff --git a/apps/cm/.env.local b/apps/cm/.env.local deleted file mode 100644 index d0187a5e8..000000000 --- a/apps/cm/.env.local +++ /dev/null @@ -1,14 +0,0 @@ -# apps/cs/src/shared/config/env.ts 참고 -NEXT_PUBLIC_PORT=3000 -NEXT_PUBLIC_PROXY_HOST=http://localhost:3000 -NEXT_PUBLIC_SITE_ID=CM -NEXT_PUBLIC_SUB_DOMAIN=http://localhost:13000 -# NEXT_PUBLIC_SERVER_API_URL=http://localhost:8000 -NEXT_PUBLIC_SERVER_API_URL=http://dev.onasys.co.kr:8000 -NEXT_PUBLIC_LINK_BACKEND_API_HOST=http://rsone.iptime.org:10014 -NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2 - -NEXT_PUBLIC_SERVER_API_URL2=http://con.mind-one.co.kr:11083 -NEXT_PUBLIC_SERVER_API_URL3=https://apigateway.apps.rsonesoft.com -NEXT_PUBLIC_SN=https://devlion.hasuon.co.kr -NEXT_PUBLIC_WR=https://devtiger.hasuon.co.kr From a5d2a261ab8e6ce70cf5bf54bbb7d6ee5f65aa3b Mon Sep 17 00:00:00 2001 From: jcchoi <jcchoi@onasys.co.kr> Date: Tue, 30 Dec 2025 11:21:42 +0900 Subject: [PATCH 09/92] Delete apps/cm/.env.production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 환경설정 삭제 --- apps/cm/.env.production | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 apps/cm/.env.production diff --git a/apps/cm/.env.production b/apps/cm/.env.production deleted file mode 100644 index 750b4022e..000000000 --- a/apps/cm/.env.production +++ /dev/null @@ -1,11 +0,0 @@ -# apps/cs/src/shared/config/env.ts 참고 -NEXT_PUBLIC_PORT=3000 -NEXT_PUBLIC_PROXY_HOST=http://localhost:3000 -NEXT_PUBLIC_SITE_ID=CS -NEXT_PUBLIC_SUB_DOMAIN=http://localhost:13000 -NEXT_PUBLIC_SERVER_API_URL=http://192.168.0.102:8000 -NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2 - -NEXT_PUBLIC_SERVER_API_URL2=http://apigateway.iipbs-was.svc.cluster.local:8000 -NEXT_PUBLIC_SN=https://lion.hasuon.co.kr -NEXT_PUBLIC_WR=https://tiger.hasuon.co.kr \ No newline at end of file From b09e5c68f901d1922bf62086a3b50b587cf87667 Mon Sep 17 00:00:00 2001 From: jcchoi <jcchoi@onasys.co.kr> Date: Tue, 30 Dec 2025 11:21:50 +0900 Subject: [PATCH 10/92] Delete apps/cm/.env.zip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 환경설정 삭제 --- apps/cm/.env.zip | Bin 208838 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/cm/.env.zip diff --git a/apps/cm/.env.zip b/apps/cm/.env.zip deleted file mode 100644 index 610032d09678d470c0b5856f93210393b5e9c4a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208838 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%0Ab^&@;>U9Y~|dqbPE%UX`9@9a|J1Erqt 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 From 68669b2574e06cc60adb2df59e4ab5d95ce7b9b6 Mon Sep 17 00:00:00 2001 From: jcchoi <jcchoi@onasys.co.kr> Date: Tue, 30 Dec 2025 11:23:10 +0900 Subject: [PATCH 11/92] Update apps/cm/.env.example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 샘플 수정 --- apps/cm/.env.example | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/cm/.env.example b/apps/cm/.env.example index 9f786831b..5d9747b57 100644 --- a/apps/cm/.env.example +++ b/apps/cm/.env.example @@ -1,7 +1,14 @@ # apps/cs/src/shared/config/env.ts 참고 -NEXT_PUBLIC_PORT=3000 -NEXT_PUBLIC_PROXY_HOST=http://localhost:3000 -NEXT_PUBLIC_SITE_ID=CS -NEXT_PUBLIC_SUB_DOMAIN=http://localhost:3000 -NEXT_PUBLIC_SERVER_API_URL=http://192.168.0.102:8000 -NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2 \ No newline at end of file +NEXT_PUBLIC_PORT=3001 +NEXT_PUBLIC_PROXY_HOST=http://localhost:3001 +NEXT_PUBLIC_SITE_ID=CM +NEXT_PUBLIC_SUB_DOMAIN=http://localhost:13000 +# NEXT_PUBLIC_SERVER_API_URL=http://localhost:8000 +NEXT_PUBLIC_SERVER_API_URL=http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_LINK_BACKEND_API_HOST=http://rsone.iptime.org:10014 +NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2 + +NEXT_PUBLIC_SERVER_API_URL2=http://con.mind-one.co.kr:11083 +NEXT_PUBLIC_SERVER_API_URL3=https://apigateway.apps.rsonesoft.com +NEXT_PUBLIC_SN=https://devlion.hasuon.co.kr +NEXT_PUBLIC_WR=https://devtiger.hasuon.co.kr From a2cd08cbd965b6f56b7eaa64c7e3882ff8cc56d6 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 30 Dec 2025 17:04:23 +0900 Subject: [PATCH 12/92] =?UTF-8?q?feature=20=EC=A0=81=EC=9A=A9=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/.env.local | 2 ++ apps/fo/.env.mindone | 2 +- apps/fo/next.config.ts | 18 ++++++++----- .../fo/src/entities/auth/lib/auth-wrapper.tsx | 6 ++--- apps/sn/next.config.ts | 26 ++++++++++++++++--- apps/wr/.env.local | 1 + apps/wr/.env.mindone | 1 + apps/wr/next.config.ts | 18 ++++++++----- 8 files changed, 52 insertions(+), 22 deletions(-) diff --git a/apps/fo/.env.local b/apps/fo/.env.local index bf6d56f58..693b6e7ef 100644 --- a/apps/fo/.env.local +++ b/apps/fo/.env.local @@ -5,6 +5,7 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id NEXT_PUBLIC_ACCESS_TOKEN = access-token NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_PROXY_HOST = http://localhost:3000 +NEXT_PUBLIC_SUB_DOMAIN = http://localhost:13000 #NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/ @@ -17,6 +18,7 @@ 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 REACT_EDITOR=atom \ No newline at end of file diff --git a/apps/fo/.env.mindone b/apps/fo/.env.mindone index 2003db503..f014168c2 100644 --- a/apps/fo/.env.mindone +++ b/apps/fo/.env.mindone @@ -5,7 +5,7 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id NEXT_PUBLIC_ACCESS_TOKEN = access-token NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300 -NEXT_PUBLIC_SUB_DOMAIN = http://con.mind-one.co.kr:11300 +NEXT_PUBLIC_SUB_DOMAIN = http://con.mind-one.co.kr:13000 NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login #NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082 NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service diff --git a/apps/fo/next.config.ts b/apps/fo/next.config.ts index 709fd3cf6..6a892461e 100644 --- a/apps/fo/next.config.ts +++ b/apps/fo/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; -const subDomain = - process.env.NEXT_PUBLIC_PROXY_HOST || "http://localhost:3000"; +const domain = process.env.NEXT_PUBLIC_PROXY_HOST || "http://localhost:3000"; +const subDomain = process.env.NEXT_PUBLIC_SUB_DOMAIN || "http://localhost:13000"; const nextConfig: NextConfig = { output: "standalone", @@ -18,7 +18,7 @@ const nextConfig: NextConfig = { { type: "header", key: "referer", - value: "(.*)/pst(.*)", + value: "(.*)/cms(.*)", }, ], }, @@ -26,19 +26,23 @@ const nextConfig: NextConfig = { afterFiles: [ { source: "/sewerage-service/:path*", - destination: `${subDomain}/sewerage-service/:path*`, + destination: `${domain}/sewerage-service/:path*`, }, { source: "/reuse-service/:path*", - destination: `${subDomain}/reuse-service/:path*`, + destination: `${domain}/reuse-service/:path*`, }, { source: "/operation-service/:path*", - destination: `${subDomain}/operation-service/:path*`, + destination: `${domain}/operation-service/:path*`, }, { source: "/ngii-server/:path*", - destination: `${subDomain}/ngii-server/:path*`, + destination: `${domain}/ngii-server/:path*`, + }, + { + source: "/cms/:path*", + destination: `${subDomain}/cms/:path*`, }, ], fallback: [], diff --git a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx index 0c2d04830..864b54ce0 100644 --- a/apps/fo/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/fo/src/entities/auth/lib/auth-wrapper.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect } from "react"; -import { useRouter, usePathname } from "next/navigation"; +import { useRouter } from "next/navigation"; import { client } from "@/src/shared/api"; import type { IUserInfo } from "@/src/shared/store"; import { useUserStore, getCookie } from "@/src/shared/lib"; @@ -12,7 +12,7 @@ const LOGIN_PAGE_URL = process.env.NEXT_PUBLIC_CM_LOGIN_PAGE_URL || "http://loca const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const router = useRouter(); - const pathname = usePathname(); + // const pathname = usePathname(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { @@ -53,7 +53,7 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { } } })(); - }, [pathname]); + }, []); return <>{children}</>; }; diff --git a/apps/sn/next.config.ts b/apps/sn/next.config.ts index 66724c419..ac726f759 100644 --- a/apps/sn/next.config.ts +++ b/apps/sn/next.config.ts @@ -6,16 +6,34 @@ const subDomain = const nextConfig: NextConfig = { output: "standalone", experimental: { - proxyTimeout: 600000, // 10분 (밀리초 단위) - }, - typescript: { - ignoreBuildErrors: true, // 이 줄 추가 + proxyTimeout: 600000, }, eslint: { ignoreDuringBuilds: true, }, + typescript: { + ignoreBuildErrors: true, + }, + logging: { + fetches: { + fullUrl: true, + }, + }, async rewrites() { return { + beforeFiles: [ + { + source: "/_next/static/:path*", + destination: `${subDomain}/_next/static/:path*`, + has: [ + { + type: "header", + key: "referer", + value: "(.*)/cms(.*)", + }, + ], + }, + ], afterFiles: [ { source: "/cms/:path*", diff --git a/apps/wr/.env.local b/apps/wr/.env.local index f418f679e..db59d33c4 100644 --- a/apps/wr/.env.local +++ b/apps/wr/.env.local @@ -5,6 +5,7 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id NEXT_PUBLIC_ACCESS_TOKEN = access-token NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_PROXY_HOST = http://localhost:3001 +NEXT_PUBLIC_SUB_DOMAIN = http://localhost:13000 NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service/api/v1 NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000 diff --git a/apps/wr/.env.mindone b/apps/wr/.env.mindone index 4a928a910..8749fe39f 100644 --- a/apps/wr/.env.mindone +++ b/apps/wr/.env.mindone @@ -5,6 +5,7 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id NEXT_PUBLIC_ACCESS_TOKEN = access-token NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11301 +NEXT_PUBLIC_SUB_DOMAIN = http://con.mind-one.co.kr:13000 NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service/api/v1 NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000 diff --git a/apps/wr/next.config.ts b/apps/wr/next.config.ts index 709fd3cf6..6a892461e 100644 --- a/apps/wr/next.config.ts +++ b/apps/wr/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; -const subDomain = - process.env.NEXT_PUBLIC_PROXY_HOST || "http://localhost:3000"; +const domain = process.env.NEXT_PUBLIC_PROXY_HOST || "http://localhost:3000"; +const subDomain = process.env.NEXT_PUBLIC_SUB_DOMAIN || "http://localhost:13000"; const nextConfig: NextConfig = { output: "standalone", @@ -18,7 +18,7 @@ const nextConfig: NextConfig = { { type: "header", key: "referer", - value: "(.*)/pst(.*)", + value: "(.*)/cms(.*)", }, ], }, @@ -26,19 +26,23 @@ const nextConfig: NextConfig = { afterFiles: [ { source: "/sewerage-service/:path*", - destination: `${subDomain}/sewerage-service/:path*`, + destination: `${domain}/sewerage-service/:path*`, }, { source: "/reuse-service/:path*", - destination: `${subDomain}/reuse-service/:path*`, + destination: `${domain}/reuse-service/:path*`, }, { source: "/operation-service/:path*", - destination: `${subDomain}/operation-service/:path*`, + destination: `${domain}/operation-service/:path*`, }, { source: "/ngii-server/:path*", - destination: `${subDomain}/ngii-server/:path*`, + destination: `${domain}/ngii-server/:path*`, + }, + { + source: "/cms/:path*", + destination: `${subDomain}/cms/:path*`, }, ], fallback: [], From 67d8ff55233b5583a740ef6841ac45b73b98e1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A7=80=EC=B2=A0?= <jcchoi@onasys.co.kr> Date: Wed, 31 Dec 2025 10:20:49 +0900 Subject: [PATCH 13/92] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cm/.env.zip | Bin 208838 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/cm/.env.zip diff --git a/apps/cm/.env.zip b/apps/cm/.env.zip deleted file mode 100644 index 610032d09678d470c0b5856f93210393b5e9c4a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208838 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%0Ab^&@;>U9Y~|dqbPE%UX`9@9a|J1Erqt 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 From 2364de061648eea22f74bcbfb987a0ba7bcb31a4 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Wed, 31 Dec 2025 18:06:16 +0900 Subject: [PATCH 14/92] =?UTF-8?q?NEXT=5FPUBLIC=5FNGII=5FURL=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/.env.production | 2 +- apps/fo/.env.production | 2 +- apps/sn/.env.production | 2 +- apps/wr/.env.production | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/dm/.env.production b/apps/dm/.env.production index 5aeaa9c45..2a08a80e0 100644 --- a/apps/dm/.env.production +++ b/apps/dm/.env.production @@ -15,7 +15,7 @@ NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1 NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service -NEXT_PUBLIC_NGII_URL = http://172.29.143.87 +NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x} diff --git a/apps/fo/.env.production b/apps/fo/.env.production index 45e179066..64f0398e0 100644 --- a/apps/fo/.env.production +++ b/apps/fo/.env.production @@ -16,5 +16,5 @@ NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1 NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service -NEXT_PUBLIC_NGII_URL = http://172.29.143.87 +NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x} diff --git a/apps/sn/.env.production b/apps/sn/.env.production index b166d7390..c68db7859 100644 --- a/apps/sn/.env.production +++ b/apps/sn/.env.production @@ -11,7 +11,7 @@ NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000 NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl -NEXT_PUBLIC_NGII_URL = http://172.29.143.87 +NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x} NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000 NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000 diff --git a/apps/wr/.env.production b/apps/wr/.env.production index 27c562dee..934f1e6a5 100644 --- a/apps/wr/.env.production +++ b/apps/wr/.env.production @@ -15,7 +15,7 @@ NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1 NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service -NEXT_PUBLIC_NGII_URL = http://172.29.143.87 +NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x} NEXT_PUBLIC_HASUDOINFO = https://www.hasudoinfo.or.kr NEXT_PUBLIC_HASUDOINFO_IN = http://10.101.163.102:8889 From 7af6f3a324695a9ef26894d38fd2173243817b4a Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 1 Jan 2026 22:13:04 +0900 Subject: [PATCH 15/92] =?UTF-8?q?UiTable=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/dashboard/page.tsx | 96 +++------------ apps/fo/app/store/common/index.tsx | 110 ++++++++++-------- apps/fo/app/store/dashboard/index.tsx | 9 +- .../src/ui/table/index.tsx | 4 +- 4 files changed, 82 insertions(+), 137 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index 8d431cf75..b94fc21c1 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -40,6 +40,14 @@ export const generateYearDates = (searchYear: string) => { return dates; } +type FacilityType = { + bscFctCd: string; + bscFctNm: string; + fcltyCpc: number | ''; + trtFrfNm: string | ''; + efflWqltStndrdNm: string | ''; +} + export default function DashBoard() { // 입력값 상태 관리 const { Common, initializeCommonData, searchMainGraph, searchRainManage, searchOperationStatus, OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state); @@ -48,26 +56,10 @@ export default function DashBoard() { const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]); const [sidoValue, setSidoValue] = useState<string>('0'); const [sigunValue, setSigunValue] = useState<string>('0'); - const { - isInit, - selectSearchYear, - btnClass, - selectSidoData, - selectSigunData, - } = Common; - - const { - planFcltyList - } = PlanFclty; - - const { - operationalStatusList - } = OperationStatus; - - const { - excelList - } = RainManage; - + const { isInit, selectSearchYear, btnClass, selectSidoData, selectSigunData, } = Common; + const { planFcltyList } = PlanFclty; + const { operationalStatusList } = OperationStatus; + const { excelList } = RainManage; const { chart_inflowRain, chart_bodRain, @@ -79,10 +71,10 @@ export default function DashBoard() { } = MainGraph; /******************선택된 데이터******************/ - // 연도 - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || '0'); + + const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || '0'); // 연도 // 시설명 - const [fcltyList, setFcltyList] = useState<{ bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | '' }>({ + const [fcltyList, setFcltyList] = useState<FacilityType>({ bscFctCd: '11000SW001R', bscFctNm: '난지', fcltyCpc: 860000, @@ -90,7 +82,7 @@ export default function DashBoard() { efflWqltStndrdNm: '500톤 이상(Ⅲ지역)' }); - const [searchFcltyList, setSearchFcltyList] = useState<{ bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | '' }>({ + const [searchFcltyList, setSearchFcltyList] = useState<FacilityType>({ bscFctCd: '', bscFctNm: '', fcltyCpc: '', @@ -111,7 +103,7 @@ export default function DashBoard() { } }, [isInit, initializeCommonData]); - const handleFacilityChange = (facility: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | '' }) => { + const handleFacilityChange = (facility: FacilityType) => { setFcltyList(facility); }; @@ -255,60 +247,6 @@ export default function DashBoard() { headerRange: 'A1:J1', sheetName: '주요그래프' } - /* { - data: [['날짜', '강수량'],...chart_inflowRain.map((item) => [item.label, roundNumber(item.barVal0, 1)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '강수량' - }, - { - data: [['날짜', '유입하수량'],...chart_inflowRain.map((item) => [item.label, roundNumber(item.lineVal1, 0)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '유입하수량' - }, - { - data: [['날짜', '시설용량'],...chart_inflowRain.map((item) => [item.label, roundNumber(item.lineVal0, 0)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '시설용량' - }, - { - data: [['날짜', '유입BOD'],...chart_bodRain.map((item) => [item.label, roundNumber(item.lineVal0, 1)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '유입BOD' - }, - { - data: [['날짜', '유입T-P'],...chart_inflTp.map((item) => [item.label, roundNumber(item.val, 3)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '유입T-P' - }, - { - data: [['날짜', '총인유입T-P'],...chart_chongInTp.map((item) => [item.label, roundNumber(item.val, 3)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '총인유입T-P' - }, - { - data: [['날짜', '방류T-P'],...chart_efflTp.map((item) => [item.label, roundNumber(item.val, 3)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '방류T-P' - }, - { - data: [['날짜', '유입T-N'],...chart_inflTn.map((item) => [item.label, roundNumber(item.val, 3)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '유입T-N' - }, - { - data: [['날짜', '방류T-N'],...chart_efflTn.map((item) => [item.label, roundNumber(item.val, 3)])], - headerNum: 1, - headerRange: 'A1:B1', - sheetName: '방류T-N' - } */ ]; downloadMultipleExcel('주요그래프', sheetParameter); diff --git a/apps/fo/app/store/common/index.tsx b/apps/fo/app/store/common/index.tsx index e4aebc982..a381eb50d 100644 --- a/apps/fo/app/store/common/index.tsx +++ b/apps/fo/app/store/common/index.tsx @@ -129,14 +129,14 @@ const selectEnvPartSigunData: SelectDataType[] = [ // ]; // 상향 하향 데이터 -const selectUpdownData:SelectDataType[] = [ +const selectUpdownData: SelectDataType[] = [ { text: "전체", val: '0' }, { text: "500미만", val: '400' }, { text: "500이상", val: '500' }, ]; // 운영 상태 데이터 -const selectOperationData:SelectDataType[] = [ +const selectOperationData: SelectDataType[] = [ { text: "전체", val: '0' }, { text: "가동중", val: '1' }, { text: "재가동", val: '2' }, @@ -145,7 +145,7 @@ const selectOperationData:SelectDataType[] = [ ]; // 시설 구분 데이터 -const selectFacilityPartData:SelectDataType[] = [ +const selectFacilityPartData: SelectDataType[] = [ { text: "전체", val: '0' }, { text: "공공하수처리시설", val: 'SW' }, { text: "오수처리장", val: 'SS' }, @@ -158,12 +158,18 @@ const selectFacilityPartData:SelectDataType[] = [ // 년도 데이터 const getYearData = () => { - const year = new Date().getFullYear(); - const year1 = year - 1; - const year2 = year - 2; - const year3 = year - 3; - const year4 = year - 4; - const year5 = year - 5; + const today = new Date(); + const year = today.getFullYear(); + const month = today.getMonth() + 1; + + // 상반기(6월까지)는 2년 전, 하반기는 1년 전부터 시작 + const startYear = month <= 6 ? (year - 2) : (year - 1); + + const year1 = startYear; + const year2 = startYear - 1; + const year3 = startYear - 2; + const year4 = startYear - 3; + const year5 = startYear - 4; return [ { text: year1 + "년", val: year1.toString() }, { text: year2 + "년", val: year2.toString() }, @@ -173,10 +179,10 @@ const getYearData = () => { ] } -const selectSearchYear:SelectDataType[] = getYearData(); +const selectSearchYear: SelectDataType[] = getYearData(); // 유량 기간 구분 -const selectFlowTerm : SelectDataType[] = [ +const selectFlowTerm: SelectDataType[] = [ { text: "연간", val: '0' }, { text: "하절기", val: '01' }, { text: "동절기", val: '02' }, @@ -185,15 +191,15 @@ const selectFlowTerm : SelectDataType[] = [ ]; // 유량 기간 구분 -const selectFlowPanel : SelectDataType[] = [ - { text: "전체", val: '0'}, - { text: "3~10mm미만", val: '2'}, - { text: "10~20mm미만", val: '3'}, - { text: "20~30mm미만", val: '4'}, - { text: "30~40mm미만", val: '5'}, - { text: "40~50mm미만", val: '6'}, - { text: "50~60mm미만", val: '7'}, - { text: "60mm이상", val: '8'}, +const selectFlowPanel: SelectDataType[] = [ + { text: "전체", val: '0' }, + { text: "3~10mm미만", val: '2' }, + { text: "10~20mm미만", val: '3' }, + { text: "20~30mm미만", val: '4' }, + { text: "30~40mm미만", val: '5' }, + { text: "40~50mm미만", val: '6' }, + { text: "50~60mm미만", val: '7' }, + { text: "60mm이상", val: '8' }, ]; // 중권역 데이터 @@ -220,9 +226,9 @@ export const roundUp = (value: number, precision: number = 1): number => { * @param day : 일수 * @param digit : 소수점 자리수 */ -export const qltyDataSetting = (value: number, day : number, digit: number) => { - const toZero = digit === 1 ? '0.0' : digit === 2 ? '0.00' : '0.000'; - return value > 0 ? roundUp((value/day), digit).toFixed(digit) : toZero; +export const qltyDataSetting = (value: number, day: number, digit: number) => { + const toZero = digit === 1 ? '0.0' : digit === 2 ? '0.00' : '0.000'; + return value > 0 ? roundUp((value / day), digit).toFixed(digit) : toZero; }; export const COD_YEAR = 2021; @@ -234,13 +240,13 @@ export const COD_YEAR = 2021; // 처리시설 계획정보 호출 (알에스원) export const planInfoUrl = '/dc-service/api/v1/nowDmgMtncGnsvy'; -export const fetchPlanInfo = async (targetYear : string | undefined, ctpvNm : string | undefined, sggNm : string | undefined, fcltyCd : string | undefined) => { +export const fetchPlanInfo = async (targetYear: string | undefined, ctpvNm: string | undefined, sggNm: string | undefined, fcltyCd: string | undefined) => { try { const baseUrl = planInfoUrl; const queryParams = new URLSearchParams(); if (ctpvNm && ctpvNm !== '전체') queryParams.append('ctpvNm', ctpvNm); if (sggNm && sggNm !== '전체') queryParams.append('sggNm', sggNm); - if (targetYear) queryParams.append('targetYear',targetYear); + if (targetYear) queryParams.append('targetYear', targetYear); if (fcltyCd) queryParams.append('swtrmtFcltCd', fcltyCd); const queryString = queryParams.toString(); const url = queryString ? `${baseUrl}?${queryString}` : baseUrl; @@ -258,16 +264,16 @@ const fetchSidoData = async (): Promise<SelectDataType[]> => { const res = await getFetch('fo', '/addr/city'); const data = res.data; selectSidoData = [ - { text: "전체", val: '0'}, + { text: "전체", val: '0' }, ...data.map((item: sidoDataType) => ({ - text: item.sido || '', - val: String(item.adstDstrCd) || '' + text: item.sido || '', + val: String(item.adstDstrCd) || '' })) ]; return selectSidoData; } catch (error) { - console.error('시도 데이터를 가져오는데 실패했습니다:', error); - return selectSidoData; + console.error('시도 데이터를 가져오는데 실패했습니다:', error); + return selectSidoData; } }; @@ -279,10 +285,10 @@ const fetchSigunData = async (): Promise<SelectDataType[]> => { selectSigunData = [ { text: "전체", val: '0' }, ...data - .map((item: sigunDataType) => ({ + .map((item: sigunDataType) => ({ text: item.gugun || '', val: String(item.adstDstrCd) || '' - })) + })) ]; return selectSigunData; } catch (error) { @@ -297,7 +303,7 @@ const fetchRegionData = async (): Promise<SelectDataType[]> => { const res = await getFetch('fo', '/addr/sarea'); const data = res.data; return [ - { text: "전체", val: '0'}, + { text: "전체", val: '0' }, ...data.map((item: regionDataType) => ({ text: item.rvbsn || '', val: String(item.rvbsnCd) || '' @@ -317,10 +323,10 @@ const fetchMiddleRegionData = async (): Promise<SelectDataType[]> => { return [ { text: "전체", val: '0' }, ...data - .map((item: middleRegionDataType) => ({ - text: item.mdmbsn || '', - val: String(item.rvbsnCd) || '' - })) + .map((item: middleRegionDataType) => ({ + text: item.mdmbsn || '', + val: String(item.rvbsnCd) || '' + })) ]; } catch (error) { console.error('중권역 데이터를 가져오는데 실패했습니다:', error); @@ -336,10 +342,10 @@ const fetchUnitWaterShedData = async (): Promise<SelectDataType[]> => { return [ { text: "전체", val: '0' }, ...data - .map((item: unitWaterShedDataType) => ({ - text: item.lgbsn || '', - val: String(item.rvbsnCd) || '' - })) + .map((item: unitWaterShedDataType) => ({ + text: item.lgbsn || '', + val: String(item.rvbsnCd) || '' + })) ]; } catch (error) { console.error('단위유역 데이터를 가져오는데 실패했습니다:', error); @@ -355,11 +361,11 @@ const fetchEnvPartData = async (): Promise<envPartSelectDataType[]> => { selectEnvPartData = [ { text: "전체", val: '0', adstDliStrCd: '' }, ...data - .map((item: envPartDataType) => ({ - text: item.lclgvrnmntNm || '', - val: String(item.lclgvrnmntCd) || '', - adstDliStrCd: item.adstDliStrCd || '' - })) + .map((item: envPartDataType) => ({ + text: item.lclgvrnmntNm || '', + val: String(item.lclgvrnmntCd) || '', + adstDliStrCd: item.adstDliStrCd || '' + })) ]; return selectEnvPartData; } catch (error) { @@ -372,7 +378,7 @@ const fetchEnvPartData = async (): Promise<envPartSelectDataType[]> => { * Store - expaort ====================================*/ export type CommonAction = { - getMenuAuth : (menuCd : number) => Promise<void>; + getMenuAuth: (menuCd: number) => Promise<void>; initializeCommonData: () => Promise<void>; } @@ -394,7 +400,7 @@ export type CommonType = { selectFlowPanel: SelectDataType[]; selectEnvPartData: envPartSelectDataType[]; btnClass: string; - COD_YEAR : number; + COD_YEAR: number; }; auth: { @@ -424,7 +430,7 @@ export const commonState: CommonType = { selectFlowPanel: selectFlowPanel, selectEnvPartData: selectEnvPartData, btnClass: "p-4 m-2 !mr-10 text-white rounded-sm text-lg font-medium", - COD_YEAR : COD_YEAR, + COD_YEAR: COD_YEAR, }, auth: { @@ -436,10 +442,12 @@ export const commonState: CommonType = { }, }; -export const CommonReducer:(set:(fn: (state: CommonType) => CommonType) => void)=>CommonAction=(set: (fn: (state: CommonType) => CommonType) => void) => { +export const CommonReducer = ( + set: (fn: (state: CommonType) => CommonType) => void +): CommonAction => { return { // 메뉴 권한 확인 - getMenuAuth : async (menuCd : number) =>{ + getMenuAuth: async (menuCd: number) => { const response = await getFetch( "local", `/cms-service/api/v1/menu-authrts/pageinfo/${menuCd}` diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 60267e388..d3f3e3e05 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1289,7 +1289,9 @@ const searchWaterUsage = async (searchYear: string, fcltyCd: string) => { return waterUsage; } -export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardType) => void) => DashBoardActions = (set: (fn: (state: DashBoardType) => DashBoardType) => void) => { +export const dashBoardReducer = ( + set: (fn: (state: DashBoardType) => DashBoardType) => void +): DashBoardActions => { return { initializeDashBoardData: async () => { set((state: DashBoardType) => ({ @@ -1311,7 +1313,7 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp }, })); let waterUsage = [0, 0, 0]; - waterUsage = await searchWaterUsage(targetYear, fcltyCd); + waterUsage = await searchWaterUsage(targetYear, fcltyCd); // /fclt/flow/{fcltyCd}/{year} set((state: DashBoardType) => ({ ...state, @@ -1323,8 +1325,7 @@ export const dashBoardReducer: (set: (fn: (state: DashBoardType) => DashBoardTyp }, })); - const res = await fetchFacilityPlan(targetYear, fcltyCd, set); - + const res = await fetchFacilityPlan(targetYear, fcltyCd, set); // /dc-service/api/v1/nowDmgMtncGnsvy let minDiff = 9999999; let minIndex; res.forEach((el: any, idx) => { diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index f62831959..a0b421db8 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -263,9 +263,7 @@ export function UiTable({ <TableCell colSpan={ headlist.filter((item) => item.visible != false).length - - headlist.filter( - (item) => item.visible != false && item.colSpan, - ).length + headlist.filter((item) => item.visible != false && item.colSpan).length } className="h-24 text-center text-gray-500" > From 745a7d06ea2410cce314d073736ec6a4fbdfdf85 Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 13:55:02 +0900 Subject: [PATCH 16/92] =?UTF-8?q?fix:=20=EA=B0=9C=EB=B0=9C=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/page.tsx | 30 +++++++++---------- .../sn/src/entities/auth/lib/auth-wrapper.tsx | 13 +++++++- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/apps/sn/app/page.tsx b/apps/sn/app/page.tsx index 1babfe451..83b40887e 100644 --- a/apps/sn/app/page.tsx +++ b/apps/sn/app/page.tsx @@ -26,20 +26,20 @@ export default function Home() { const checkToken = getCookie(AUTH_USER_ID); useEffect(() => { - 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"); - } else router.push("/map"); + // 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"); + // } else router.push("/map"); }, []); } diff --git a/apps/sn/src/entities/auth/lib/auth-wrapper.tsx b/apps/sn/src/entities/auth/lib/auth-wrapper.tsx index 289a97087..5127b1e18 100644 --- a/apps/sn/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/sn/src/entities/auth/lib/auth-wrapper.tsx @@ -44,10 +44,21 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { setUserInfo(null); const hostname = window.location.hostname; + const checkToken = getCookie(AUTH_USER_ID); // 개발 환경에서는 localhost 도메인 사용 if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") - router.push("/"); // 개발시 홈으로 돌아가기 + 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"); // 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용 // router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용 From e0e1bb5b1ac7ed60ff36c30b24c18aae9845fb0d Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 15:18:06 +0900 Subject: [PATCH 17/92] =?UTF-8?q?fix:=20=EA=B0=9C=EB=B0=9C=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/page.tsx | 29 ++++++++++--------- .../sn/src/entities/auth/lib/auth-wrapper.tsx | 13 +-------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/apps/sn/app/page.tsx b/apps/sn/app/page.tsx index 83b40887e..fa9a15b7f 100644 --- a/apps/sn/app/page.tsx +++ b/apps/sn/app/page.tsx @@ -26,20 +26,21 @@ export default function Home() { const checkToken = getCookie(AUTH_USER_ID); useEffect(() => { - // const hostname = window.location.hostname; + const hostname = window.location.hostname; + console.log("개발 메인 hostname", 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"); - // } else router.push("/map"); + 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"); + } else router.push("/map"); }, []); } diff --git a/apps/sn/src/entities/auth/lib/auth-wrapper.tsx b/apps/sn/src/entities/auth/lib/auth-wrapper.tsx index 5127b1e18..1c27e6fe3 100644 --- a/apps/sn/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/sn/src/entities/auth/lib/auth-wrapper.tsx @@ -44,21 +44,10 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { setUserInfo(null); const hostname = window.location.hostname; - const checkToken = getCookie(AUTH_USER_ID); // 개발 환경에서는 localhost 도메인 사용 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"); + window.location.href = "/"; // 운영 환경에서는 서브도메인을 포함한 최상위 도메인 사용 // router.push는 같은 Next.js 앱 내에서만 작동하므로 다른 앱으로 이동할 때는 window.location.href 사용 From d4b32ffad0f0b5aed4aba138ff43026441b9a1eb Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 15:39:28 +0900 Subject: [PATCH 18/92] =?UTF-8?q?fix:=20=EC=84=9C=EB=B8=8C=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=ED=8F=AC=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/.env.mindone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sn/.env.mindone b/apps/sn/.env.mindone index d03f5cae5..cea5518db 100644 --- a/apps/sn/.env.mindone +++ b/apps/sn/.env.mindone @@ -5,7 +5,7 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id NEXT_PUBLIC_ACCESS_TOKEN = access-token NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11302 -NEXT_PUBLIC_SUB_DOMAIN = http://con.mind-one.co.kr:11300 +NEXT_PUBLIC_SUB_DOMAIN = http://con.mind-one.co.kr:13000 NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver From 8cc5a0a737dd2e2c4d0bef7dbedc724021fd5b39 Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 15:58:35 +0900 Subject: [PATCH 19/92] =?UTF-8?q?fix:=20base=5Furl=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/src/shared/config/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sn/src/shared/config/api.ts b/apps/sn/src/shared/config/api.ts index fe2e39682..16d1b5452 100644 --- a/apps/sn/src/shared/config/api.ts +++ b/apps/sn/src/shared/config/api.ts @@ -3,7 +3,7 @@ import { PROXY_HOST } from "./env"; // 브라우저에서는 동일 오리진으로 상대경로 호출 → CORS/localhost 고정 문제 방지 // (Next middleware가 /server/* 요청을 백엔드로 rewrite) // 서버 환경(SSR 등)에서는 절대 URL이 필요할 수 있어 기존 PROXY_HOST 기반 유지 -export const BASE_URL = typeof window === "undefined" ? `${PROXY_HOST}/server` : "/server"; +export const BASE_URL = `${PROXY_HOST}/server`; export const ENDPOINT = { ATTACH_SERVICE: { From ea738d687ba62a99d3de3e271df17921320b1011 Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 16:11:00 +0900 Subject: [PATCH 20/92] =?UTF-8?q?fix:=20router.push=20->=20window.location?= =?UTF-8?q?.href=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/page.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/sn/app/page.tsx b/apps/sn/app/page.tsx index fa9a15b7f..03c16e80b 100644 --- a/apps/sn/app/page.tsx +++ b/apps/sn/app/page.tsx @@ -19,10 +19,10 @@ import { LoginApi } from "@/entities/auth"; import { useEffect } from "react"; import { getCookie } from "@/shared/lib"; import { AUTH_USER_ID } from "@/shared/config"; -import { useRouter } from "next/navigation"; +// import { useRouter } from "next/navigation"; export default function Home() { - const router = useRouter(); + // const router = useRouter(); const checkToken = getCookie(AUTH_USER_ID); useEffect(() => { @@ -40,7 +40,7 @@ export default function Home() { } } doLogin(); - } else router.push("/map"); - } else router.push("/map"); + } else window.location.href = "/map"; + } else window.location.href = "/map"; }, []); } From 8f531a245f6e99acab2fd8cd4dbc93f47e4123f8 Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 17:41:52 +0900 Subject: [PATCH 21/92] =?UTF-8?q?fix:=20=EA=B0=9C=EB=B0=9C=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20env=20=ED=8C=8C=EC=9D=BC=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/page.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/sn/app/page.tsx b/apps/sn/app/page.tsx index 03c16e80b..087cb3ce0 100644 --- a/apps/sn/app/page.tsx +++ b/apps/sn/app/page.tsx @@ -26,6 +26,11 @@ export default function Home() { const checkToken = getCookie(AUTH_USER_ID); useEffect(() => { + console.log("ENV CHECK:", { + PROXY_HOST: process.env.NEXT_PUBLIC_PROXY_HOST, + PORT: process.env.NEXT_PUBLIC_PORT, + }); + const hostname = window.location.hostname; console.log("개발 메인 hostname", hostname); From f96ae66385b9e87feabfe1c3a1e1f5d5c22445d5 Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Fri, 2 Jan 2026 17:49:36 +0900 Subject: [PATCH 22/92] =?UTF-8?q?fix:=20=EA=B0=9C=EB=B0=9C=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A1=A4=EB=B0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/page.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/sn/app/page.tsx b/apps/sn/app/page.tsx index 087cb3ce0..2a1db71d8 100644 --- a/apps/sn/app/page.tsx +++ b/apps/sn/app/page.tsx @@ -19,20 +19,13 @@ import { LoginApi } from "@/entities/auth"; import { useEffect } from "react"; import { getCookie } from "@/shared/lib"; import { AUTH_USER_ID } from "@/shared/config"; -// import { useRouter } from "next/navigation"; export default function Home() { - // const router = useRouter(); const checkToken = getCookie(AUTH_USER_ID); useEffect(() => { - console.log("ENV CHECK:", { - PROXY_HOST: process.env.NEXT_PUBLIC_PROXY_HOST, - PORT: process.env.NEXT_PUBLIC_PORT, - }); const hostname = window.location.hostname; - console.log("개발 메인 hostname", hostname); if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "con.mind-one.co.kr") { if (!checkToken) { From 63543a016e3b99019ebcbda56a0f3750d05a1e6e Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 2 Jan 2026 18:04:19 +0900 Subject: [PATCH 23/92] =?UTF-8?q?fo:=20dashboard=20=EB=AC=BC=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=9F=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 77 +++++++-------------------- 1 file changed, 19 insertions(+), 58 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index d3f3e3e05..426954d53 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -760,32 +760,8 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc // const qltyChungchunData = CalcRainEffect(clone(qltyData), 'SUNNY'); // 강우시 변수 - let rainSummerDay9 = 0, noNullRainSummerDay9 = 0; - let rainInflBodAvg9 = 0, rainInflTnAvg9 = 0, rainInflTpAvg9 = 0; - let rainEfflBodAvg9 = 0, rainEfflTnAvg9 = 0, rainEfflTpAvg9 = 0, rainTpInflAvg9 = 0; - const qltyRainData = CalcRainEffect(clone(qltyData), 'RAIN'); const rainEffectDayArray: string[] = []; - // 강우시 - qltyRainData.forEach((item: any) => { - const month = item.msrDt.substring(4, 6); // 월 추출 - if (month === '06' || month === '07' || month === '08') { - rainSummerDay9 += 1; - if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { - noNullRainSummerDay9 += 1; - } - - rainInflBodAvg9 += nullToZero(item.inflAssctBfrWqltBod); - rainInflTnAvg9 += nullToZero(item.inflAssctBfrWqltTn); - rainInflTpAvg9 += nullToZero(item.inflAssctBfrWqltTp); - rainEfflBodAvg9 += nullToZero(item.efflWqltBod); - rainEfflTnAvg9 += nullToZero(item.efflWqltTn); - rainEfflTpAvg9 += nullToZero(item.efflWqltTp); - rainTpInflAvg9 += nullToZero(item.tpInflWqltTp); - } - }); - console.log("99999999999999999"); - console.log(rainSummerDay9, noNullRainSummerDay9, rainInflBodAvg9, rainInflTnAvg9, rainInflTpAvg9, rainEfflBodAvg9, rainEfflTnAvg9, rainEfflTpAvg9, rainTpInflAvg9); - + // (0) 전체변수 let summerDay = 0, noNullSummerDay = 0; let totalInflBodAvgSummer = 0, totalInflTnAvgSummer = 0, totalInflTpAvgSummer = 0; @@ -1013,8 +989,8 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc // 총인설비 orgData[11].summerThree = qltyDataSetting(rainTpInflAvg, noNullRainSummerDay, 3); orgData[12].summerThree = qltyDataSetting(rainInflTpAvg, rainSummerDay, 3); - console.log(rainEffectDayArray); - console.log("000000000", rainSummerDay, noNullRainSummerDay, rainInflBodAvg, rainInflTnAvg, rainInflTpAvg, rainEfflBodAvg, rainEfflTnAvg, rainEfflTpAvg, rainTpInflAvg); + // console.log(rainEffectDayArray); + // console.log("000000000", rainSummerDay, noNullRainSummerDay, rainInflBodAvg, rainInflTnAvg, rainInflTpAvg, rainEfflBodAvg, rainEfflTnAvg, rainEfflTpAvg, rainTpInflAvg); return orgData; } else { @@ -1250,40 +1226,25 @@ const calcValue = (operationalStatus, data, keyTxt = 'INFL_ASSCT_BFR_WQLT_TP') = operationalStatus.winterSunnyMax = data.winterSunny && data.winterSunny['MAX_' + keyTxt] ? Number(Math.round(data.winterSunny['MAX_' + keyTxt] * 1.3 * 1000) / 1000).toFixed(3).toString() : ''; } -type RtnFlowType = { - inflAmnt: string | number; - infoRnDay: string | number; - bscFctCd: string; - msrDt: string; +type wtrUsgYearsType = { + YEAR: string; + WTR_USG: number; } - -type RtnFlowResponse = { - data: RtnFlowType[]; +type wtrUsgYearsResponse = { + data: wtrUsgYearsType[]; count: number; } const searchWaterUsage = async (searchYear: string, fcltyCd: string) => { - const waterUsage = [0, 0, 0]; + const waterUsage = [0, 0, 0]; // searchYear, searchYear-1, searchYear-2 - for (let i = 0; i < 3; i++) { - try { - const res = await getFetch('fo', '/fclt/flow/' + fcltyCd + '/' + (Number(searchYear) - i)) as RtnFlowResponse; - let totWaterUsage = 0; - - if (res && res.data && Array.isArray(res.data)) { - res.data.forEach((item: RtnFlowType) => { - totWaterUsage += Number(item.inflAmnt); - }); - - if (res.count > 0) { - const avg = totWaterUsage / res.count; - waterUsage[i] = parseFloat((avg * 0.65).toFixed(2)); - } - } - } catch (error) { - console.error(`Error fetching water usage for year ${Number(searchYear) - i}:`, error); - waterUsage[i] = 0; - } + const res = await getFetch('fo', '/dashBoard/wtrUsgYears/' + searchYear + '/' + fcltyCd) as wtrUsgYearsResponse; + let i = 0; + if (res && res.data && Array.isArray(res.data)) { + res.data.forEach((item: wtrUsgYearsType) => { + waterUsage[i] = item.WTR_USG; + i++; + }); } return waterUsage; @@ -1314,7 +1275,7 @@ export const dashBoardReducer = ( })); let waterUsage = [0, 0, 0]; waterUsage = await searchWaterUsage(targetYear, fcltyCd); // /fclt/flow/{fcltyCd}/{year} - +console.log(waterUsage); set((state: DashBoardType) => ({ ...state, PlanFclty: { @@ -1834,9 +1795,9 @@ export const dashBoardReducer = ( const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd); // 수질 데이터 청천시, 강우시 재계산 // 총인설비가 없을 경우 제외 - console.log('총인시설 여부 : ', data.yearData?.TP_FCT_YN); + // console.log('총인시설 여부 : ', data.yearData?.TP_FCT_YN); - console.log('rtnData : ', rtnData); + // console.log('rtnData : ', rtnData); if (data.yearData?.TP_FCT_YN !== 'Y') { operationalStatusList = rtnData.slice(0, 11); } else { From 43af9042c80bb4a232a522478989c1d424aa6a87 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 2 Jan 2026 18:21:12 +0900 Subject: [PATCH 24/92] fix fo --- apps/fo/app/store/dashboard/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 426954d53..b2778e3d8 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -755,7 +755,7 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc const orgData = data; const res = await fetchMainGraph(searchYear, fcltyCd); if (res.data.wqltObjs.length > 0) { - const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; + // const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; const qltyData = res.data.wqltObjs; // const qltyChungchunData = CalcRainEffect(clone(qltyData), 'SUNNY'); From bd8d850a78c321eabf51b549474dd238dec7dfcd Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Fri, 2 Jan 2026 23:17:59 +0900 Subject: [PATCH 25/92] =?UTF-8?q?dm:=20=EC=97=B0=EB=85=B9=EC=83=89=20?= =?UTF-8?q?=EC=8A=A4=ED=82=A8=20=EB=B0=8F=20=EB=A9=94=EB=89=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/app/layout.tsx | 3 +++ packages/common/components/src/ui/header/index.tsx | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/dm/app/layout.tsx b/apps/dm/app/layout.tsx index 462537e09..7224c9dc2 100644 --- a/apps/dm/app/layout.tsx +++ b/apps/dm/app/layout.tsx @@ -1,5 +1,8 @@ "use client"; import "./globals.css"; +import { setCookie } from "../src/shared/lib"; + +setCookie("site-id-key", process.env.NEXT_PUBLIC_SITE_ID || "DM"); export default function RootLayout({ children, diff --git a/packages/common/components/src/ui/header/index.tsx b/packages/common/components/src/ui/header/index.tsx index 97ed4c151..ddd5e0c21 100644 --- a/packages/common/components/src/ui/header/index.tsx +++ b/packages/common/components/src/ui/header/index.tsx @@ -153,10 +153,10 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) { <SidebarTrigger className="size-12 !bg-transparent p-2 hover:!bg-accent [&>svg]:!size-full [&>svg]:text-foreground" /> <h1 className="flex flex-col items-center gap-2"> {mounted ? ( - <img + <img ref={logoRef} - src={getLogoImage()} - className="h-[3rem]" + src={getLogoImage()} + className="h-[3rem]" alt="logo" onLoad={() => { if (logoRef.current) { @@ -167,7 +167,7 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) { ) : ( <Skeleton className="h-[3rem] w-[15rem]" /> )} - <span + <span className="text-[1.2rem] font-semibold text-foreground" style={{ letterSpacing: logoWidth > 0 ? `${(logoWidth - 120) / (siteInfo?.siteNm?.length || 1)}px` : '0.05em' From 94b640d5664490c9de2543d099911f978d0e0015 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sat, 3 Jan 2026 14:50:26 +0900 Subject: [PATCH 26/92] =?UTF-8?q?dm:=20experimental=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/.env.local | 11 +++++------ apps/dm/next.config.ts | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/dm/.env.local b/apps/dm/.env.local index 44e7072c3..e73fe4485 100644 --- a/apps/dm/.env.local +++ b/apps/dm/.env.local @@ -4,17 +4,16 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id NEXT_PUBLIC_ACCESS_TOKEN = access-token NEXT_PUBLIC_REFRESH_TOKEN = refresh-token NEXT_PUBLIC_PORT = 3005 -#NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035 NEXT_PUBLIC_PROXY_HOST = http://localhost:3005 -NEXT_PUBLIC_DM_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1 -NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 -NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service/api/v1 -# NEXT_PUBLIC_FO_SERVER_API_URL = http://192.168.1.222:8883/operation-service/api/v1 NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000 +NEXT_PUBLIC_DM_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1 +# NEXT_PUBLIC_FO_SERVER_API_URL = http://192.168.1.222:8883/operation-service/api/v1 +NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service/api/v1 +NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1 NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload -NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1 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_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API diff --git a/apps/dm/next.config.ts b/apps/dm/next.config.ts index bc21e16a4..5e1533ec9 100644 --- a/apps/dm/next.config.ts +++ b/apps/dm/next.config.ts @@ -5,6 +5,9 @@ const subDomain = const nextConfig: NextConfig = { output: "standalone", + experimental: { + proxyTimeout: 600000, + }, async rewrites() { return { beforeFiles: [ From 897ce3eb242848d46db1f3e8622c0c47223f08cc Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sat, 3 Jan 2026 15:52:41 +0900 Subject: [PATCH 27/92] =?UTF-8?q?wr:=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/(map-layout)/map/mainMap/page.tsx | 228 +++++++++--------- apps/wr/components/lib/func/mapUtil.ts | 88 +++---- 2 files changed, 157 insertions(+), 159 deletions(-) diff --git a/apps/wr/app/(map-layout)/map/mainMap/page.tsx b/apps/wr/app/(map-layout)/map/mainMap/page.tsx index 362d45cb8..927703ad9 100644 --- a/apps/wr/app/(map-layout)/map/mainMap/page.tsx +++ b/apps/wr/app/(map-layout)/map/mainMap/page.tsx @@ -21,7 +21,7 @@ import WrOverLay from "@/components/ui/map/wrOverLay/wrOverLay"; const Map = () => { - const {code, comMap ,rainMapDetile ,rswtMapDetile,getRuseMaplListReturn,pbnMapDetaile,ldrmntMapDetile,htdfMapDetile,coSttnMapDetail} = useWrStore((state) => state); + const { code, comMap, rainMapDetile, rswtMapDetile, getRuseMaplListReturn, pbnMapDetaile, ldrmntMapDetile, htdfMapDetile, coSttnMapDetail } = useWrStore((state) => state); const { isFeatured } = comMap; const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 const gisMaps = useRef<any | null>(null); @@ -93,7 +93,6 @@ const Map = () => { return; } - // 항상 같은 select 객체 사용 const select = GisApp.Module.select as any; if (!select) return; @@ -109,7 +108,6 @@ const Map = () => { const layerName = getWrLayerNm(data); const featurePk = getWrFeaturePk(layerName ?? ""); - // 재이용시설 if (featurePk) { const lastPk = @@ -254,139 +252,139 @@ const Map = () => { const OVERLAY_MIN_ZOOM = 16; -const OVERLAY_COORD_PRECISION = 5; -const OVERLAY_MAX_PER_VIEW = 800; + const OVERLAY_COORD_PRECISION = 5; + const OVERLAY_MAX_PER_VIEW = 800; -const overlayManagersRef = useRef<any[]>([]); -const overlayActiveRef = useRef(false); -const moveEndDebounceRef = useRef<number | null>(null); + const overlayManagersRef = useRef<any[]>([]); + const overlayActiveRef = useRef(false); + const moveEndDebounceRef = useRef<number | null>(null); -// 반환: Promise<HTMLDivElement | null> -const overlayFormatter = async (feature: any, props: any) => { - const p = props || {}; - const featureId = - feature.getId?.() ?? p?.id ?? p?.fid ?? p?.ftrIdn ?? ''; - if (!featureId) return null; + // 반환: Promise<HTMLDivElement | null> + const overlayFormatter = async (feature: any, props: any) => { + const p = props || {}; + const featureId = + feature.getId?.() ?? p?.id ?? p?.fid ?? p?.ftrIdn ?? ''; + if (!featureId) return null; - const tableId = String(featureId).split('.')[0]??''; - const fcltCd = getFeatureCd(props, tableId); + const tableId = String(featureId).split('.')[0] ?? ''; + const fcltCd = getFeatureCd(props, tableId); - if (!fcltCd) return null; + if (!fcltCd) return null; - let data: any = null; - let title = ''; + let data: any = null; + let title = ''; - if (tableId === 'tb_il_swage_prcs_fclt') { data = await pbnMapDetaile(fcltCd); title = '하수처리시설'; } - else if (tableId === 'tb_wr_bdst_ruse_fclt') { data = await getRuseMaplListReturn(fcltCd); title = '하수재이용시설'; } - else if (tableId === 'tb_wr_rnwtr_utztn_fclt'){ data = await rainMapDetile(fcltCd); title = '빗물이용시설'; } - else if (tableId === 'tb_wr_rswtr_fclt') { data = await rswtMapDetile(fcltCd); title = '중수도시설'; } - else if (tableId === 'tb_wr_htdfl_fclt') { data = await htdfMapDetile(fcltCd); title = '온배수시설'; } - else if (tableId === 'tb_wr_ruse_fclt_dmd_co'){ data = await coSttnMapDetail(fcltCd); title = '수요처'; } - else if (tableId === 'tb_wr_tmpr_dmd_co') { data = await ldrmntMapDetile(fcltCd); title = '잠재수요처'; } + if (tableId === 'tb_il_swage_prcs_fclt') { data = await pbnMapDetaile(fcltCd); title = '하수처리시설'; } + else if (tableId === 'tb_wr_bdst_ruse_fclt') { data = await getRuseMaplListReturn(fcltCd); title = '하수재이용시설'; } + else if (tableId === 'tb_wr_rnwtr_utztn_fclt') { data = await rainMapDetile(fcltCd); title = '빗물이용시설'; } + else if (tableId === 'tb_wr_rswtr_fclt') { data = await rswtMapDetile(fcltCd); title = '중수도시설'; } + else if (tableId === 'tb_wr_htdfl_fclt') { data = await htdfMapDetile(fcltCd); title = '온배수시설'; } + else if (tableId === 'tb_wr_ruse_fclt_dmd_co') { data = await coSttnMapDetail(fcltCd); title = '수요처'; } + else if (tableId === 'tb_wr_tmpr_dmd_co') { data = await ldrmntMapDetile(fcltCd); title = '잠재수요처'; } - const empty = - data == null || - (Array.isArray(data) && data.length === 0) || - (typeof data === 'object' && !Array.isArray(data) && Object.keys(data).length === 0); + const empty = + data == null || + (Array.isArray(data) && data.length === 0) || + (typeof data === 'object' && !Array.isArray(data) && Object.keys(data).length === 0); - if (empty) return null; + if (empty) return null; - const div = document.createElement('div'); - const root = createRoot(div); - (div as any).__dispose = () => { try { root.unmount(); } catch {} }; - root.render(<WrOverLay title={title} data={data} code={code} />); - return div; // ← 데이터 있을 때만 HTMLElement 반환 -}; -const destroyAllManagers = () => { - overlayManagersRef.current.forEach(m => { try { m.destroy(); } catch {} }); - overlayManagersRef.current = []; - overlayActiveRef.current = false; -}; + const div = document.createElement('div'); + const root = createRoot(div); + (div as any).__dispose = () => { try { root.unmount(); } catch { } }; + root.render(<WrOverLay title={title} data={data} code={code} />); + return div; // ← 데이터 있을 때만 HTMLElement 반환 + }; + const destroyAllManagers = () => { + overlayManagersRef.current.forEach(m => { try { m.destroy(); } catch { } }); + overlayManagersRef.current = []; + overlayActiveRef.current = false; + }; -const mountOverlayManagers = () => { - const map = gisMaps.current; - if (!map) return; + const mountOverlayManagers = () => { + const map = gisMaps.current; + if (!map) return; - // 이전 것 정리 - destroyAllManagers(); + // 이전 것 정리 + destroyAllManagers(); - // 체크된 벡터 레이어만 골라 매니저 생성 - const checkedSet = new Set(checkedLayers.map(String)); - const layers: any[] = map.getLayers().getArray(); - const targets = layers.filter((layer: any) => { - const src = layer.getSource?.(); - const isVector = src && typeof src.getFeatures === "function"; - const id = String(layer.get?.("lyrSn") ?? layer.get?.("id") ?? ""); - return isVector && layer.getVisible?.() && checkedSet.has(id); - }); - - targets.forEach((layer: any) => { - const mgr = createOverlayManager(map, layer, overlayFormatter, { - coordPrecision: OVERLAY_COORD_PRECISION, - maxOverlaysPerViewport: OVERLAY_MAX_PER_VIEW, + // 체크된 벡터 레이어만 골라 매니저 생성 + const checkedSet = new Set(checkedLayers.map(String)); + const layers: any[] = map.getLayers().getArray(); + const targets = layers.filter((layer: any) => { + const src = layer.getSource?.(); + const isVector = src && typeof src.getFeatures === "function"; + const id = String(layer.get?.("lyrSn") ?? layer.get?.("id") ?? ""); + return isVector && layer.getVisible?.() && checkedSet.has(id); }); - mgr.mount(); // 리스너 1회 등록 - mgr.enable(); // 표시 + 1회 sync - overlayManagersRef.current.push(mgr); - }); - overlayActiveRef.current = overlayManagersRef.current.length > 0; -}; + targets.forEach((layer: any) => { + const mgr = createOverlayManager(map, layer, overlayFormatter, { + coordPrecision: OVERLAY_COORD_PRECISION, + maxOverlaysPerViewport: OVERLAY_MAX_PER_VIEW, + }); + mgr.mount(); // 리스너 1회 등록 + mgr.enable(); // 표시 + 1회 sync + overlayManagersRef.current.push(mgr); + }); -useEffect(() => { - const map = gisMaps.current; - if (!map) return; - - const z = map.getView()?.getZoom?.() ?? 0; - if (z < OVERLAY_MIN_ZOOM) { - // 저줌에선 그냥 안 보이게만 - overlayManagersRef.current.forEach(m => { try { m.disable({ clear:true, delayed:true }); } catch {} }); - return; - } - mountOverlayManagers(); - - return () => { destroyAllManagers(); }; -}, [checkedLayers]); - - -useEffect(() => { - const map = gisMaps.current; - if (!map) return; - - const onMoveStart = () => { - // 숨기기만 (리스너/DOM 대량 제거 X) - overlayManagersRef.current.forEach(m => { try { m.disable({ clear:false }); } catch {} }); - if (moveEndDebounceRef.current) { clearTimeout(moveEndDebounceRef.current); moveEndDebounceRef.current = null; } + overlayActiveRef.current = overlayManagersRef.current.length > 0; }; - const onMoveEnd = () => { + useEffect(() => { + const map = gisMaps.current; + if (!map) return; + const z = map.getView()?.getZoom?.() ?? 0; - const active = overlayActiveRef.current; + if (z < OVERLAY_MIN_ZOOM) { + // 저줌에선 그냥 안 보이게만 + overlayManagersRef.current.forEach(m => { try { m.disable({ clear: true, delayed: true }); } catch { } }); + return; + } + mountOverlayManagers(); - if (moveEndDebounceRef.current) clearTimeout(moveEndDebounceRef.current); - moveEndDebounceRef.current = window.setTimeout(() => { - if (z < OVERLAY_MIN_ZOOM) { - if (active) overlayManagersRef.current.forEach(m => { try { m.disable({ clear:true, delayed:true }); } catch {} }); - return; - } - if (!active) { - mountOverlayManagers(); - } else { - // 다시 보이고 1회만 동기화 - overlayManagersRef.current.forEach(m => { try { m.enable(); m.syncOverlays(); } catch {} }); - } - }, 180) as unknown as number; - }; + return () => { destroyAllManagers(); }; + }, [checkedLayers]); - map.on("movestart", onMoveStart); - map.on("moveend", onMoveEnd); - return () => { - map.un("movestart", onMoveStart); - map.un("moveend", onMoveEnd); - if (moveEndDebounceRef.current) { clearTimeout(moveEndDebounceRef.current); moveEndDebounceRef.current = null; } - }; -}, [checkedLayers]); + + useEffect(() => { + const map = gisMaps.current; + if (!map) return; + + const onMoveStart = () => { + // 숨기기만 (리스너/DOM 대량 제거 X) + overlayManagersRef.current.forEach(m => { try { m.disable({ clear: false }); } catch { } }); + if (moveEndDebounceRef.current) { clearTimeout(moveEndDebounceRef.current); moveEndDebounceRef.current = null; } + }; + + const onMoveEnd = () => { + const z = map.getView()?.getZoom?.() ?? 0; + const active = overlayActiveRef.current; + + if (moveEndDebounceRef.current) clearTimeout(moveEndDebounceRef.current); + moveEndDebounceRef.current = window.setTimeout(() => { + if (z < OVERLAY_MIN_ZOOM) { + if (active) overlayManagersRef.current.forEach(m => { try { m.disable({ clear: true, delayed: true }); } catch { } }); + return; + } + if (!active) { + mountOverlayManagers(); + } else { + // 다시 보이고 1회만 동기화 + overlayManagersRef.current.forEach(m => { try { m.enable(); m.syncOverlays(); } catch { } }); + } + }, 180) as unknown as number; + }; + + map.on("movestart", onMoveStart); + map.on("moveend", onMoveEnd); + return () => { + map.un("movestart", onMoveStart); + map.un("moveend", onMoveEnd); + if (moveEndDebounceRef.current) { clearTimeout(moveEndDebounceRef.current); moveEndDebounceRef.current = null; } + }; + }, [checkedLayers]); return ( <div className="bg-container"> <Gis diff --git a/apps/wr/components/lib/func/mapUtil.ts b/apps/wr/components/lib/func/mapUtil.ts index a39bf17d7..c49dea69f 100644 --- a/apps/wr/components/lib/func/mapUtil.ts +++ b/apps/wr/components/lib/func/mapUtil.ts @@ -1,22 +1,22 @@ import { formatCommaNumber, formatPhoneNumber } from "./commom"; const wrLayerList = [ - { text: "tb_il_swage_prcs_fclt", val: "bscFctCd" }, - { text: "tb_wr_bdst_ruse_fclt", val: "pbnstRuseFcltId" }, - { text: "tb_wr_rnwtr_utztn_fclt", val: "rainyObj" }, - { text: "tb_wr_rswtr_fclt", val: "rswtrObj" }, - { text: "tb_wr_htdfl_fclt", val: "htdflObj" }, - { text: "tb_wr_ruse_fclt_dmd_co", val: "dmdInfoId" }, - { text: "tb_wr_tmpr_dmd_co", val: "fctryMngSn" }, + { text: "tb_il_swage_prcs_fclt", val: "bscFctCd" }, //하수처리시설 + { text: "tb_wr_bdst_ruse_fclt", val: "pbnstRuseFcltId" }, //하수재이용시설 + { text: "tb_wr_rnwtr_utztn_fclt", val: "rainyObj" }, //빗물이용시설 + { text: "tb_wr_rswtr_fclt", val: "rswtrObj" }, //중수도시설 + { text: "tb_wr_htdfl_fclt", val: "htdflObj" }, //온배수시설 + { text: "tb_wr_ruse_fclt_dmd_co", val: "dmdInfoId" }, //수요처 + { text: "tb_wr_tmpr_dmd_co", val: "fctryMngSn" }, //잠재수요처 ]; const wrFeaturePK = [ - { text: "bscFctCd", val: "tb_il_swage_prcs_fclt" }, - { text: "searchPk", val: "tb_wr_bdst_ruse_fclt" }, - { text: "bdstInfoSn", val: "tb_wr_rnwtr_utztn_fclt" }, - { text: "bdstInfoSn", val: "tb_wr_rswtr_fclt" }, - { text: "bdstInfoSn", val: "tb_wr_htdfl_fclt" }, - { text: "dmdInfoId", val: "tb_wr_ruse_fclt_dmd_co" }, - { text: "fctryMngSn", val: "tb_wr_tmpr_dmd_co" }, + { text: "bscFctCd", val: "tb_il_swage_prcs_fclt" }, //하수처리시설 + { text: "searchPk", val: "tb_wr_bdst_ruse_fclt" }, //하수재이용시설 + { text: "bdstInfoSn", val: "tb_wr_rnwtr_utztn_fclt" }, //빗물이용시설 + { text: "bdstInfoSn", val: "tb_wr_rswtr_fclt" }, //중수도시설 + { text: "bdstInfoSn", val: "tb_wr_htdfl_fclt" }, //온배수시설 + { text: "dmdInfoId", val: "tb_wr_ruse_fclt_dmd_co" }, //수요처 + { text: "fctryMngSn", val: "tb_wr_tmpr_dmd_co" }, //잠재수요처 ]; // { text: "하수처리시설", val: "tb_il_swage_prcs_fclt" }, @@ -29,18 +29,18 @@ const wrFeaturePK = [ export const getFeatureCd = (featurePropertise: any, layerNm: string) => { const featureCd = - layerNm === "tb_wr_bdst_ruse_fclt" + layerNm === "tb_wr_bdst_ruse_fclt" //하수재이용시설 ? featurePropertise?.swtrmt_fclt_cd : [ - "tb_wr_rswtr_fclt", - "tb_wr_htdfl_fclt", - "tb_wr_rnwtr_utztn_fclt", - "tb_wr_tmpr_dmd_co", - ].includes(layerNm) + "tb_wr_rswtr_fclt", // 중수도시설 + "tb_wr_htdfl_fclt", // 온배수시설 + "tb_wr_rnwtr_utztn_fclt", // 빗물이용시설 + "tb_wr_tmpr_dmd_co", // 잠재수요처 + ].includes(layerNm) ? featurePropertise?.bdst_nm - : layerNm === "tb_il_swage_prcs_fclt" + : layerNm === "tb_il_swage_prcs_fclt" //하수처리시설 ? featurePropertise?.swtrmt_fclt_cd - : layerNm === "tb_wr_ruse_fclt_dmd_co" + : layerNm === "tb_wr_ruse_fclt_dmd_co" //수요처 ? featurePropertise?.bdst_info_sn : null; @@ -71,9 +71,9 @@ export const getSelectedLayers = (isFeature: any, gisMaps: any) => { let result = null; const layers = map ? map - .getLayers() - .getArray() - .filter((l: any) => l.getVisible()) + .getLayers() + .getArray() + .filter((l: any) => l.getVisible()) : []; // gisMap이 null인지 확인 후 레이어 가져오기 let featureLayer: { get: (key: string) => any } = { get: () => null }; @@ -119,12 +119,12 @@ export const getClickFeatureId = (data: any) => { } else if (layerName == "수요처") { //수요처 featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`; - }else if (layerName == "잠재수요처") { + } else if (layerName == "잠재수요처") { //잠재수요처 featureId = data.id_ - } else { - + } else { + featureId = data.id_ } @@ -160,7 +160,7 @@ export function featurePopUpOpen( ); } -export const getOverLayObj = (fclType: string, data: any,code?:any) => { +export const getOverLayObj = (fclType: string, data: any, code?: any) => { let newObj = {}; let title = ""; @@ -169,11 +169,11 @@ export const getOverLayObj = (fclType: string, data: any,code?:any) => { if (fclType === "하수재이용시설") { newObj = { - "시설용량(톤/일)": formatCommaNumber(data?.fcltCpct) ??'확인불가', - "재이용률(%)": (data?.fcltCpct / data?.bscFctCpc)||0, + "시설용량(톤/일)": formatCommaNumber(data?.fcltCpct) ?? '확인불가', + "재이용률(%)": (data?.fcltCpct / data?.bscFctCpc) || 0, "장내용수(m³/년)": formatCommaNumber(data?.inUsage) ?? '확인불가', - "장외용수(m3/년)":formatCommaNumber(data?.outUsage) ?? '확인불가', - // 수요처: data?.reuseBuilding[0]?.rainyObj.pntfColArea ?? '확인불가', + "장외용수(m3/년)": formatCommaNumber(data?.outUsage) ?? '확인불가', + // 수요처: data?.reuseBuilding[0]?.rainyObj.pntfColArea ?? '확인불가', }; title = data?.bdstNm ?? '확인불가'; } else if (fclType === "하수처리시설") { @@ -184,9 +184,9 @@ export const getOverLayObj = (fclType: string, data: any,code?:any) => { "재이용시설 등록여부": data?.ruse ?? '확인불가', }; title = data?.bscFctNm ?? '확인불가'; - } else if (fclType === "빗물이용시설" ) { + } else if (fclType === "빗물이용시설") { newObj = { - 건물용도: code?.bdstUsgCd.find((item) => item.val=== String(data?.reuseBuilding[0].bdstUsgCd) )?.text ?? '확인불가', + 건물용도: code?.bdstUsgCd.find((item) => item.val === String(data?.reuseBuilding[0].bdstUsgCd))?.text ?? '확인불가', 설치완료일: data?.reuseBuilding[0]?.instlCmptnDt ?? '확인불가', 처리시설유무: data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctYn ?? '확인불가', "처리시설용량(m³/일)": formatCommaNumber(data?.reuseBuilding[0]?.rainyObj.filtrTrtmfctCpct) ?? '확인불가', @@ -195,25 +195,25 @@ export const getOverLayObj = (fclType: string, data: any,code?:any) => { title = data?.bdstNm ?? '확인불가'; } else if (fclType === "중수도시설") { newObj = { - 건물용도: code?.bdstUsgCd.find((item) => item.val===String(data?.reuseBuilding[0].bdstUsgCd) )?.text ?? '확인불가', + 건물용도: code?.bdstUsgCd.find((item) => item.val === String(data?.reuseBuilding[0].bdstUsgCd))?.text ?? '확인불가', 설치완료일: data?.reuseBuilding[0]?.instlCmptnDt ?? '확인불가', - "주요 처리공정": data?.reuseBuilding[0]?.rswtrObj.filtrTrtmfctProcs ?? '확인불가', - 원수종류: code?.orgwtKndCd.find((item) => item.val === data?.reuseBuilding[0]?.rswtrObj.orgwtKndCd)?.text ?? '확인불가', + "주요 처리공정": data?.reuseBuilding[0]?.rswtrObj.filtrTrtmfctProcs ?? '확인불가', + 원수종류: code?.orgwtKndCd.find((item) => item.val === data?.reuseBuilding[0]?.rswtrObj.orgwtKndCd)?.text ?? '확인불가', //이용용도: isCode.filtrTrtmfctUsgCd data?.reuseBuilding[0]?.rswtrObj.altUswtrKndCd ?? '확인불가', }; title = data?.bdstNm ?? '확인불가'; } else if (fclType === "온배수시설") { newObj = { - '발전유형': data?.reuseBuilding[0]?.htdflObj.etgtType??'', - '설비용량': data?.reuseBuilding[0]?.htdflObj.fclCpct??'', - '담수화 여부': data?.reuseBuilding[0]?.htdflObj.plwtYn??'', + '발전유형': data?.reuseBuilding[0]?.htdflObj.etgtType ?? '', + '설비용량': data?.reuseBuilding[0]?.htdflObj.fclCpct ?? '', + '담수화 여부': data?.reuseBuilding[0]?.htdflObj.plwtYn ?? '', }; title = data?.bdstNm ?? '확인불가'; } else if (fclType === "수요처") { newObj = { - '사업자등록번호': data?.dmdInfoId??'', - '주소': data?.daddr??'', - '전화번호': formatPhoneNumber(data?.telno)??'', + '사업자등록번호': data?.dmdInfoId ?? '', + '주소': data?.daddr ?? '', + '전화번호': formatPhoneNumber(data?.telno) ?? '', }; title = data?.dmdCoNm ?? '확인불가'; From ac3acbb0f43264329fe6c0d1fc7f00cd636025c2 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sun, 4 Jan 2026 20:45:08 +0900 Subject: [PATCH 28/92] =?UTF-8?q?fo:=20dashboard=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 160 ++++++++++++++++++-------- apps/fo/app/store/store.tsx | 41 +++---- 2 files changed, 136 insertions(+), 65 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index b2778e3d8..081da3839 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -699,6 +699,7 @@ const drainageEquipmentList: DrainageEquipmentListProps[] = [ } ]; +type ApiRes = { data: any; count: any; } /**==================================== * Store - api (데이터 호출) ====================================*/ @@ -722,7 +723,7 @@ const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string }; /* 시설정보 및 운영현황 - 운영실태 */ -const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined) => { +const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined): Promise<ApiRes> => { try { const url = '/dashBoard/mngInfo/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : ''); const res = await getFetch('fo', url); @@ -746,14 +747,15 @@ const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | } // 수질 데이터 청천시, 강우시 재계산 -const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fcltyCd: string | undefined) => { +const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fcltyCd: string | undefined, mainGraphData: any) => { const nullToZero = (value: any) => { return value === null || value === undefined || value === '' ? 0 : Number(value); }; const orgData = data; - const res = await fetchMainGraph(searchYear, fcltyCd); + // const res = await fetchMainGraph(searchYear, fcltyCd); // /fclt/qlty/hist/{year}/{fcltyCd} + const res = mainGraphData; if (res.data.wqltObjs.length > 0) { // const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; const qltyData = res.data.wqltObjs; @@ -761,7 +763,7 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc // 강우시 변수 const rainEffectDayArray: string[] = []; - + // (0) 전체변수 let summerDay = 0, noNullSummerDay = 0; let totalInflBodAvgSummer = 0, totalInflTnAvgSummer = 0, totalInflTpAvgSummer = 0; @@ -1064,6 +1066,9 @@ export type DashBoardType = { rainManageList: RainManageListProps[]; excelList: RainManageExcelType[]; isLoadingRainManage: boolean; + mainGraphData: any; + mainGraphYear: string; + mainGraphFcltyCd: string; }, DrainageEquipment: { @@ -1127,6 +1132,9 @@ export const dashBoardInitState: DashBoardType = { rainManageList: rainManageList, excelList: [], isLoadingRainManage: false, + mainGraphData: null, + mainGraphYear: '', + mainGraphFcltyCd: '', }, DrainageEquipment: { @@ -1251,7 +1259,8 @@ const searchWaterUsage = async (searchYear: string, fcltyCd: string) => { } export const dashBoardReducer = ( - set: (fn: (state: DashBoardType) => DashBoardType) => void + set: (fn: (state: DashBoardType) => DashBoardType) => void, + get: () => DashBoardType ): DashBoardActions => { return { initializeDashBoardData: async () => { @@ -1275,7 +1284,7 @@ export const dashBoardReducer = ( })); let waterUsage = [0, 0, 0]; waterUsage = await searchWaterUsage(targetYear, fcltyCd); // /fclt/flow/{fcltyCd}/{year} -console.log(waterUsage); + set((state: DashBoardType) => ({ ...state, PlanFclty: { @@ -1355,6 +1364,26 @@ console.log(waterUsage); /** 시설정보 및 운영현황 - 운영실태 */ searchOperationStatus: async (isExcel: boolean, searchYear: string, fcltyCd: string) => { + const state = get(); + let mainGraphData: ApiRes = { data: [], count: 0 }; + + // 이미 조회된 데이터가 있는지 확인 (연도와 시설코드가 같을 때만) + if (state.RainManage.mainGraphYear === searchYear && state.RainManage.mainGraphFcltyCd === fcltyCd && state.RainManage.mainGraphData) { + mainGraphData = state.RainManage.mainGraphData; + } else { + mainGraphData = await fetchMainGraph(searchYear, fcltyCd); + // 조회된 데이터 저장 + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + mainGraphData: mainGraphData, + mainGraphYear: searchYear, + mainGraphFcltyCd: fcltyCd, + } + })); + } + set((state: DashBoardType) => ({ ...state, OperationStatus: { @@ -1630,52 +1659,55 @@ console.log(waterUsage); // 오염물질 // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) - const resp = await fetchMainGraph(searchYear, fcltyCd); - const wqltData = resp.data.wqltObjs; - const wqltDataTot = CalcRainEffect(clone(wqltData)); - const wqltDataSunny = CalcRainEffect(clone(wqltData), 'SUNNY'); + // const resp = await fetchMainGraph(searchYear, fcltyCd); + const resp = mainGraphData; + if (resp && resp.data && resp.data.wqltObjs) { + const wqltData = resp.data.wqltObjs; + const wqltDataTot = CalcRainEffect(clone(wqltData)); + const wqltDataSunny = CalcRainEffect(clone(wqltData), 'SUNNY'); - let minSummerBod = 99999999; - let minSummerBodInfl = 99999999; - let winterCnt = 0; - let winterBodSunny = 0; - let rdiRain = 0; + let minSummerBod = 99999999; + let minSummerBodInfl = 99999999; + let winterCnt = 0; + let winterBodSunny = 0; + let rdiRain = 0; - const summerMonth = ['06', '07', '08']; - const winterMonth = ['01', '02']; + const summerMonth = ['06', '07', '08']; + const winterMonth = ['01', '02']; - wqltDataTot.filter(item => summerMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { - if (Number(item2.infoRnDay) >= 3) { - const inflBod = Number(item2.inflAssctBfrWqltBod); - const infl = Number(item2.inflAmnt); - const rain = Number(item2.infoRnDay); - if (inflBod < minSummerBod) { - minSummerBodInfl = infl; - minSummerBod = inflBod; - rdiRain = rain; + wqltDataTot.filter(item => summerMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { + if (Number(item2.infoRnDay) >= 3) { + const inflBod = Number(item2.inflAssctBfrWqltBod); + const infl = Number(item2.inflAmnt); + const rain = Number(item2.infoRnDay); + if (inflBod < minSummerBod) { + minSummerBodInfl = infl; + minSummerBod = inflBod; + rdiRain = rain; + } } - } - }); + }); - wqltDataSunny.filter(item => winterMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { - winterBodSunny += Number(item2.inflAssctBfrWqltBod); - winterCnt += 1; - }); + wqltDataSunny.filter(item => winterMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { + winterBodSunny += Number(item2.inflAssctBfrWqltBod); + winterCnt += 1; + }); - const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',', '')); - const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',', '')); - const roundWinterBodSunny = Number(roundNumber(winterBodSunny, 1).toString().replaceAll(',', '')); + const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',', '')); + const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',', '')); + const roundWinterBodSunny = Number(roundNumber(winterBodSunny, 1).toString().replaceAll(',', '')); - const winterBodAvg = Number(roundNumber((roundWinterBodSunny / winterCnt), 1).toString().replaceAll(',', '')); - // 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) - const winMinusSum = winterBodAvg - roundMinSummerBod; + 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); - rdiPercent = (rdiValue / minSummerBodInfl) * 100; + rdiPercent = (rdiValue / minSummerBodInfl) * 100; - operationalStatusList[0].rdi = rdiValue; - operationalStatusList[0].rdiRain = rdiRain; + operationalStatusList[0].rdi = rdiValue; + operationalStatusList[0].rdiRain = rdiRain; + } /* const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; @@ -1792,7 +1824,7 @@ console.log(waterUsage); } } - const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd); // 수질 데이터 청천시, 강우시 재계산 + const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd, mainGraphData); // 수질 데이터 청천시, 강우시 재계산 // 총인설비가 없을 경우 제외 // console.log('총인시설 여부 : ', data.yearData?.TP_FCT_YN); @@ -1815,6 +1847,26 @@ console.log(waterUsage); }, searchMainGraph: async (searchYear: string, fcltyCd: string) => { + const state = get(); + let res: any = null; + + // 이미 조회된 데이터가 있는지 확인 + if (state.RainManage.mainGraphYear === searchYear && state.RainManage.mainGraphFcltyCd === fcltyCd && state.RainManage.mainGraphData) { + res = state.RainManage.mainGraphData; + } else { + res = await fetchMainGraph(searchYear, fcltyCd); + // 데이터 저장 + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + mainGraphData: res, + mainGraphYear: searchYear, + mainGraphFcltyCd: fcltyCd, + } + })); + } + set((state: DashBoardType) => ({ ...state, MainGraph: { @@ -1822,7 +1874,7 @@ console.log(waterUsage); isLoadingMainGraph: true, }, })); - const res = await fetchMainGraph(searchYear, fcltyCd); + // const res = await fetchMainGraph(searchYear, fcltyCd); const res2 = await fetchFacilityWaterQltyInfo(fcltyCd); let chungcunSumFlow = 0; @@ -1944,6 +1996,24 @@ console.log(waterUsage); }, searchRainManage: async (searchYear: string, fcltyCd: string, isExcel: boolean) => { + const state = get(); + let res: any = null; + + if (state.RainManage.mainGraphYear === searchYear && state.RainManage.mainGraphFcltyCd === fcltyCd && state.RainManage.mainGraphData) { + res = state.RainManage.mainGraphData; + } else { + res = await fetchMainGraph(searchYear, fcltyCd); + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + mainGraphData: res, + mainGraphYear: searchYear, + mainGraphFcltyCd: fcltyCd, + } + })); + } + set((state: DashBoardType) => ({ ...state, RainManage: { @@ -1951,7 +2021,7 @@ console.log(waterUsage); isLoadingRainManage: true, }, })); - const res = await fetchMainGraph(searchYear, fcltyCd); + // const res = await fetchMainGraph(searchYear, fcltyCd); if (res == null || res.data.wqltObjs == null || res.data.wqltObjs.length === 0) { set((state: DashBoardType) => ({ ...state, diff --git a/apps/fo/app/store/store.tsx b/apps/fo/app/store/store.tsx index f7f2222c6..c7064a40e 100644 --- a/apps/fo/app/store/store.tsx +++ b/apps/fo/app/store/store.tsx @@ -42,8 +42,9 @@ import { export type FoStore = CommonStore & tableType & DashBoardStore & ProcessFacilityStore & ProcessAreaStore & FlowRateSearchStore & FacilityPrecipitationStore & FacilityWaterQltyStore & PlanSewageStore & SewageOccurStore & UnderWaterStore & RdiStore; export type FoState = CommonType & tableState & ProcessFacilityType & ProcessAreaType & FacilityPrecipitationType & FlowRateSearchType & DashBoardType & FacilityWaterQltyType & PlanSewageType & SewageOccurType & UnderWaterType & RdiType; -export const StoreZus = - (initState: FoState = { ...commonState, +export const StoreZus = + (initState: FoState = { + ...commonState, ...tableStateExport , ...processFacilityInitState , ...processAreaInitState @@ -57,22 +58,22 @@ export const StoreZus = , ...rdiInitState } ) => { - return createStore<FoStore>()((set) => { - return { - ...initState, - ...CommonReducer(set), - ...tableActionsExport(set), - ...dashBoardReducer(set), - ...processFacilityReducer(set), - ...processAreaReducer(set), - ...facilityPrecipitationReducer(set), - ...flowRateSearchReducer(set), - ...facilityWaterQltyReducer(set), - ...planSewageReducer(set), - ...sewageOccurReducer(set), - ...underWaterReducer(set), - ...rdiReducer(set), - } - }) -} + return createStore<FoStore>()((set, get) => { + return { + ...initState, + ...CommonReducer(set), + ...tableActionsExport(set), + ...dashBoardReducer(set, get), + ...processFacilityReducer(set), + ...processAreaReducer(set), + ...facilityPrecipitationReducer(set), + ...flowRateSearchReducer(set), + ...facilityWaterQltyReducer(set), + ...planSewageReducer(set), + ...sewageOccurReducer(set), + ...underWaterReducer(set), + ...rdiReducer(set), + } + }) + } //store 등록하는 부분 \ No newline at end of file From 955c969fc58527c2ec983fabf9c60d2b99beb7b3 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 5 Jan 2026 06:50:18 +0900 Subject: [PATCH 29/92] =?UTF-8?q?fo:=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 081da3839..38df4f7b7 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -53,21 +53,21 @@ export type planFcltyListProps = { export type OperationalStatusListProps = { flowRate: string, waterQlty: string, - yearAvg: number | '', - yearMax: number | '', - yearMin: number | '', - summerAll: number | string | '', - summerThree: number | string | '', - summerRain: number | string | '', - winterAll: number | string | '', - winterSunnyAvg: number | string | '', - winterSunnyMax: number | string | '', - winterSunnyMin: number | string | '', - groundWaterAvg: number | string | '', - groundWaterSummer: number | string | '', - groundWaterWinter: number | string | '', - rdi: number | string | '', - rdiRain: number | string | '', + yearAvg: number | '', // 평균 + yearMax: number | '', // 최대 + yearMin: number | '', // 최소 + summerAll: number | string | '', // 하절기 전체 + summerThree: number | string | '', // 하절기 3mm이상 + summerRain: number | string | '', // 하절기 강우 + winterAll: number | string | '', // 동절기 전체 + winterSunnyAvg: number | string | '', // 동절기 청천시 평균 + winterSunnyMax: number | string | '', // 동절기 청천시 최대 + winterSunnyMin: number | string | '', // 동절기 청천시 최소 + groundWaterAvg: number | string | '', // 지하수 유입량 연평균 + groundWaterSummer: number | string | '',// 지하수 유입량 하절기 평균 + groundWaterWinter: number | string | '',// 지하수 유입량 동절기 평균 + rdi: number | string | '', // RDII 추정 + rdiRain: number | string | '', // RDII 추정시 일강수량(mm) } export interface operationalStatusListProps { @@ -345,7 +345,7 @@ const planFcltyList: planFcltyListProps[] = [ }, ] -const upHeadListOperationStatus: TableUpperProps[] = [ +const upHeadListOperationStatus: TableUpperProps[] = [ // 시설정보 및 운영현황 { id: "flowRate", title: "유량 및 수질", upName: "upChangeRe1", upSequnce: 1 }, { id: "waterQlty", title: "유량 및 수질", upName: "upChangeRe1", upSequnce: 2 }, { id: "yearAvg", title: "평균", upName: "upChangeRe2", upSequnce: 1 }, @@ -365,7 +365,7 @@ const upHeadListOperationStatus: TableUpperProps[] = [ { id: "rdiRain", title: "RDII 추정시\n일강수량(mm)" }, ] -const upHeadListRainManage: TableUpperProps[] = [ +const upHeadListRainManage: TableUpperProps[] = [ // 강우일 운영현황 { id: "rainItem", title: "강우량", row: 0, rowSpan: 2, widthPercent: 8 }, { id: "rainRate", title: "강우조건\n비율(%)", row: 0, rowSpan: 2, align: "right", widthPercent: 5 }, { id: "rainDay", title: "일수", row: 0, rowSpan: 2, align: "right", widthPercent: 5 }, From 69c068e82342b745c96244fa8d6009bc1165a310 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 5 Jan 2026 15:55:45 +0900 Subject: [PATCH 30/92] =?UTF-8?q?fo:=20dashboard=20=EC=A3=BC=EC=84=9D2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 32 +++++++++++++-------------- apps/fo/app/store/flowRate/index.tsx | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 38df4f7b7..b017e2b6f 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1420,17 +1420,17 @@ export const dashBoardReducer = ( // 연간 const yearAvg = data.yearData === null ? '' : ( (data.yearData.AVG_INFL_AMNT ? data.yearData.AVG_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 평균 - (data.yearData.AVG_SUM_FLOW ? data.yearData.AVG_SUM_FLOW : 0) + // api 주석처리되어 있음. + (data.yearData.AVG_SUM_FLOW ? data.yearData.AVG_SUM_FLOW : 0) + // 연계처리량 api 주석처리되어 있음. (data.yearData.AVG_RETURN_AMNT ? data.yearData.AVG_RETURN_AMNT : 0) // 반류수유량(m³/일) 평균 ); const yearMax = data.yearData === null ? '' : ( (data.yearData.MAX_INFL_AMNT ? data.yearData.MAX_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 최대 - (data.yearData.MAX_SUM_FLOW ? data.yearData.MAX_SUM_FLOW : 0) + // api 주석처리되어 있음. + (data.yearData.MAX_SUM_FLOW ? data.yearData.MAX_SUM_FLOW : 0) + // 연계처리량 api 주석처리되어 있음. (data.yearData.MAX_RETURN_AMNT ? data.yearData.MAX_RETURN_AMNT : 0) // 반류수유량(m³/일) 최대 ); const yearMin = data.yearData === null ? '' : ( (data.yearData.MIN_INFL_AMNT ? data.yearData.MIN_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 최소 - (data.yearData.MIN_SUM_FLOW ? data.yearData.MIN_SUM_FLOW : 0) + // api 주석처리되어 있음. + (data.yearData.MIN_SUM_FLOW ? data.yearData.MIN_SUM_FLOW : 0) + // 연계처리량 api 주석처리되어 있음. (data.yearData.MIN_RETURN_AMNT ? data.yearData.MIN_RETURN_AMNT : 0) // 반류수유량(m³/일) 최소 ); operationalStatusList[0].yearAvg = yearAvg; // 연간유입평균 @@ -1484,7 +1484,7 @@ export const dashBoardReducer = ( // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; - const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ + const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 //const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); //const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); @@ -1506,7 +1506,7 @@ export const dashBoardReducer = ( let rainEffectDay = 0; yearDay = res2.data ? res2.data.length : 1; - res2.data.forEach((item: any) => { + res2.data.forEach((item: any) => { //fetchFlowRateModalList const month = item.msrDt.substring(4, 6); // 월 추출 const sumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; @@ -1545,7 +1545,7 @@ export const dashBoardReducer = ( } else if (month === '01' || month === '02') { // 동절기 winterChungchuDay += 1; - winterChungchunSumFlow += sumFlow; + winterChungchunSumFlow += sumFlow; // 연계처리수 sumWinterChungcunFlow += inflAmnt; winterChungchunDayReturnAvg += returnAmnt; winterChungchunDayEfflAvg += efflAmnt; @@ -1632,16 +1632,16 @@ export const dashBoardReducer = ( // 방류량 (청천시) 최소 winterChungchunEfflMin = winterChungchunDayEfflMin - operationalStatusList[0].yearAvg = roundUp(Number(operationalStatusList[0].yearAvg), 0) + roundUp(yearAvgSumFlow, 0); - operationalStatusList[0].yearMax = roundUp(totFlowMax, 0); // + roundUp(yearMaxSumFlow, 0); - operationalStatusList[0].yearMin = roundUp(totFlowMin, 0); - operationalStatusList[0].summerAll = roundUp(Number(operationalStatusList[0].summerAll), 0) + roundUp(summerAll, 0); - operationalStatusList[0].summerThree = roundUp(Number(operationalStatusList[0].summerThree), 0) + roundUp(summerThree, 0); - operationalStatusList[0].summerRain = roundUp(Number(operationalStatusList[0].summerRain), 0) + roundUp(summerRain, 0); - operationalStatusList[0].winterAll = roundUp(Number(operationalStatusList[0].winterAll), 0) + roundUp(winterAll, 0); - operationalStatusList[0].winterSunnyMin = roundUp(winterChungchunTotalInflAmntMin, 0); - operationalStatusList[0].winterSunnyMax = roundUp(winterChungchunTotalInflAmntMax, 0); - operationalStatusList[0].winterSunnyAvg = roundUp(Number(operationalStatusList[0].winterSunnyAvg), 0) + roundUp(winterSunnyAvg, 0); + operationalStatusList[0].yearAvg = roundUp(Number(operationalStatusList[0].yearAvg), 0) + roundUp(yearAvgSumFlow, 0); // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) + operationalStatusList[0].yearMax = roundUp(totFlowMax, 0); // 연간 유입 최대 + operationalStatusList[0].yearMin = roundUp(totFlowMin, 0); // 연간 유입 최소 + operationalStatusList[0].summerAll = roundUp(Number(operationalStatusList[0].summerAll), 0) + roundUp(summerAll, 0); // 하절기 유입 전기간 + operationalStatusList[0].summerThree = roundUp(Number(operationalStatusList[0].summerThree), 0) + roundUp(summerThree, 0); // 하절기 유입 강우시(강우영향일) + operationalStatusList[0].summerRain = roundUp(Number(operationalStatusList[0].summerRain), 0) + roundUp(summerRain, 0); // 하절기 유입 청천시 + operationalStatusList[0].winterAll = roundUp(Number(operationalStatusList[0].winterAll), 0) + roundUp(winterAll, 0); // 동절기 유입 전기간 + operationalStatusList[0].winterSunnyMin = roundUp(winterChungchunTotalInflAmntMin, 0); // 동절기 유입 최소 + operationalStatusList[0].winterSunnyMax = roundUp(winterChungchunTotalInflAmntMax, 0); // 동절기 유입 최대 + operationalStatusList[0].winterSunnyAvg = roundUp(Number(operationalStatusList[0].winterSunnyAvg), 0) + roundUp(winterSunnyAvg, 0); // 동절기 유입 평균 // 지하수유입량 const usage = chungcunSumFlow / cntSunnyDay; //calData.length; diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 66d639fb8..94d4b9326 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -283,7 +283,7 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow const excelDownList: ExcelType[] = []; const rtnData = data.map((item: flowRateListProps) => { item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0) + item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); // 하수유입량 + 연계처리량 + 반류수유량(m³/일) dataFormSetting(item); return item; }); From 2a66772bfa28544635ff07ccc99d0dc73ea08ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A7=80=EC=B2=A0?= <jcchoi@onasys.co.kr> Date: Tue, 6 Jan 2026 09:46:27 +0900 Subject: [PATCH 31/92] =?UTF-8?q?=EC=BF=A0=ED=82=A4=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/app/api/proxy/[...url]/route.ts | 9 +++- .../common/components/src/ui/header/index.tsx | 43 ++++++++++++++++--- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/apps/cs/app/api/proxy/[...url]/route.ts b/apps/cs/app/api/proxy/[...url]/route.ts index 7442c702f..abd3ae007 100644 --- a/apps/cs/app/api/proxy/[...url]/route.ts +++ b/apps/cs/app/api/proxy/[...url]/route.ts @@ -60,13 +60,18 @@ async function handler( [AUTH_USER_ID]: userId, }); + const forwardedHost = request.headers.get("x-forwarded-host"); + const host = request.headers.get("host"); + const actualHost = forwardedHost || host || new URL(request.url).hostname.toString(); + // 운영 환경에서 domain 설정 + const domain = actualHost.includes("hasuon.or.kr") ? ".hasuon.or.kr" : actualHost; if (refreshToken) { cookieStore.set(REFRESH_TOKEN, refreshToken, { httpOnly: true, - sameSite: "lax", -// domain: domain, + sameSite: "strict", + domain: domain, path: "/", }); } diff --git a/packages/common/components/src/ui/header/index.tsx b/packages/common/components/src/ui/header/index.tsx index 97ed4c151..15b431b6a 100644 --- a/packages/common/components/src/ui/header/index.tsx +++ b/packages/common/components/src/ui/header/index.tsx @@ -72,22 +72,51 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) { }); if (!response.ok) throw new Error("Failed to logout"); - // 쿠키 삭제 + const actualHost = window.location.hostname; + + // 서브도메인 쿠키 삭제를 위한 루트 도메인 추출 + const getRootDomain = (hostname: string): string => { + // localhost나 IP 주소인 경우 + if (hostname === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) { + return hostname; + } + + // hasuon.or.kr 도메인인 경우 + if (hostname.includes("hasuon.or.kr")) { + return ".hasuon.or.kr"; + } + + // 일반적인 도메인의 경우 루트 도메인 추출 (예: sub.example.com → .example.com) + const parts = hostname.split("."); + if (parts.length >= 2) { + // 마지막 두 부분을 사용 (예: example.com) + return `.${parts.slice(-2).join(".")}`; + } + + return hostname; + }; + + const domain = getRootDomain(actualHost); + const cookieOptions = domain.startsWith(".") || domain === "localhost" + ? { domain } + : {}; + + // 쿠키 삭제 (서브도메인 포함) if (appConfig.AUTH_USER_ID) { - removeCookie(appConfig.AUTH_USER_ID); + removeCookie(appConfig.AUTH_USER_ID, cookieOptions); } if (appConfig.REFRESH_TOKEN) { - removeCookie(appConfig.REFRESH_TOKEN); + removeCookie(appConfig.REFRESH_TOKEN, cookieOptions); } if (appConfig.ACCESS_TOKEN) { - removeCookie(appConfig.ACCESS_TOKEN); + removeCookie(appConfig.ACCESS_TOKEN, cookieOptions); } if (appConfig.CLAIM_NAME) { - removeCookie(appConfig.CLAIM_NAME); + removeCookie(appConfig.CLAIM_NAME, cookieOptions); } - removeCookie("site-id-key"); - removeCookie("site-theme-key"); + removeCookie("site-id-key", cookieOptions); + removeCookie("site-theme-key", cookieOptions); window.location.href = "/auth/login"; } catch (error) { From a0ad12af492fc6d40bf7adca03a59932c45e23b4 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 6 Jan 2026 16:08:36 +0900 Subject: [PATCH 32/92] fo: api /dashboard/mngInfo --- apps/fo/app/store/dashboard/index.tsx | 787 ++++++++++++-------------- 1 file changed, 360 insertions(+), 427 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index b017e2b6f..09097d6e4 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -723,16 +723,16 @@ const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string }; /* 시설정보 및 운영현황 - 운영실태 */ -const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined): Promise<ApiRes> => { - try { - const url = '/dashBoard/mngInfo/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : ''); - const res = await getFetch('fo', url); - return { data: res.data, count: res.count } - } catch (error) { - console.error('운영실태 데이터를 가져오는데 실패했습니다:', error); - return { data: [], count: 0 }; - } -} +// const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined): Promise<ApiRes> => { +// try { +// const url = '/dashBoard/mngInfo/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : ''); +// const res = await getFetch('fo', url); +// return { data: res.data, count: res.count } +// } catch (error) { +// console.error('운영실태 데이터를 가져오는데 실패했습니다:', error); +// return { data: [], count: 0 }; +// } +// } // 주요그래프 데이터 const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | undefined) => { @@ -749,6 +749,15 @@ const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | // 수질 데이터 청천시, 강우시 재계산 const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fcltyCd: string | undefined, mainGraphData: any) => { + const operList = { + inflBod: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입BOD + inflTN: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입TN + inflTP: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입TP + efflBod: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류BOD + efflTN: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류TN + efflTP: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류TP + tpInflTp: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, //총인 유입수질 TP(mg/L) + }; const nullToZero = (value: any) => { return value === null || value === undefined || value === '' ? 0 : Number(value); }; @@ -775,6 +784,7 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc // (1) 청천시 변수 // (1-1) 날짜 count + let chungchunSummerDay = 0, noNullChungchunSummerDay = 0; let chungchunWinterDay = 0, noNullChungchunWinterDay = 0; @@ -804,6 +814,8 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc let rainEffectDay = 0; // 전체 대상 + const totalDay = qltyData.length; + let noNullYearDay = 0; qltyData.forEach((item: any) => { if (item.infoRnDay == null) item.infoRnDay = 0; const month = item.msrDt.substring(4, 6); // 월 추출 @@ -898,7 +910,7 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc totalEfflBodAvgWinter += nullToZero(item.efflWqltBod); totalEfflTnAvgWinter += nullToZero(item.efflWqltTn); totalEfflTpAvgWinter += nullToZero(item.efflWqltTp); - totalTpInflAvgWinter += nullToZero(item.tpInflWqltTp); + totalTpInflAvgWinter += nullToZero(item.tpInflWqltTp); //총인 유입수질 TP(mg/L) } else if (month === '06' || month === '07' || month === '08') { summerDay += 1; if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { @@ -912,74 +924,81 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc totalEfflTpAvgSummer += nullToZero(item.efflWqltTp); totalTpInflAvgSummer += nullToZero(item.tpInflWqltTp); } + + if (item.tpInflWqltTp != null && item.tpInflWqltTp != 0) { + noNullYearDay += 1; + } + operList.inflBod.yearTot += nullToZero(item.inflAssctBfrWqltBod); + operList.inflTN.yearTot += nullToZero(item.inflAssctBfrWqltTn); + operList.inflTP.yearTot += nullToZero(item.inflAssctBfrWqltTp); + operList.efflBod.yearTot += nullToZero(item.efflWqltBod); + operList.efflTN.yearTot += nullToZero(item.efflWqltTn); + operList.efflTP.yearTot += nullToZero(item.efflWqltTp); + operList.tpInflTp.yearTot += nullToZero(item.tpInflWqltTp); + // 최대 최소 + operList.inflBod.yearMax = Math.max(operList.inflBod.yearMax, nullToZero(item.inflAssctBfrWqltBod)); + operList.inflBod.yearMin = Math.min(operList.inflBod.yearMin, nullToZero(item.inflAssctBfrWqltBod)); + operList.inflTN.yearMax = Math.max(operList.inflTN.yearMax, nullToZero(item.inflAssctBfrWqltTn)); + operList.inflTN.yearMin = Math.min(operList.inflTN.yearMin, nullToZero(item.inflAssctBfrWqltTn)); + operList.inflTP.yearMax = Math.max(operList.inflTP.yearMax, nullToZero(item.inflAssctBfrWqltTp)); + operList.inflTP.yearMin = Math.min(operList.inflTP.yearMin, nullToZero(item.inflAssctBfrWqltTp)); + operList.efflBod.yearMax = Math.max(operList.efflBod.yearMax, nullToZero(item.efflWqltBod)); + operList.efflBod.yearMin = Math.min(operList.efflBod.yearMin, nullToZero(item.efflWqltBod)); + operList.efflTN.yearMax = Math.max(operList.efflTN.yearMax, nullToZero(item.efflWqltTn)); + operList.efflTN.yearMin = Math.min(operList.efflTN.yearMin, nullToZero(item.efflWqltTn)); + operList.efflTP.yearMax = Math.max(operList.efflTP.yearMax, nullToZero(item.efflWqltTp)); + operList.efflTP.yearMin = Math.min(operList.efflTP.yearMin, nullToZero(item.efflWqltTp)); + operList.tpInflTp.yearMax = Math.max(operList.tpInflTp.yearMax, nullToZero(item.tpInflWqltTp)); + operList.tpInflTp.yearMin = Math.min(operList.tpInflTp.yearMin, nullToZero(item.tpInflWqltTp)); + }); - orgData[5].winterAll = qltyDataSetting(totalInflBodAvgWinter, winterDay, 1); // 동절기 유입BOD - orgData[6].winterAll = qltyDataSetting(totalEfflBodAvgWinter, winterDay, 1); // 동절기 방류BOD - orgData[7].winterAll = qltyDataSetting(totalInflTnAvgWinter, winterDay, 3); // 동절기 유입TN - orgData[8].winterAll = qltyDataSetting(totalEfflTnAvgWinter, winterDay, 3); // 동절기 방류TN - orgData[9].winterAll = qltyDataSetting(totalInflTpAvgWinter, winterDay, 3); // 동절기 유입TP - orgData[10].winterAll = qltyDataSetting(totalEfflTpAvgWinter, winterDay, 3); // 동절기 방류TP + operList.inflBod.yearAvg = operList.inflBod.yearTot / totalDay; + operList.inflTN.yearAvg = operList.inflTN.yearTot / totalDay; + operList.inflTP.yearAvg = operList.inflTP.yearTot / totalDay; + operList.efflBod.yearAvg = operList.efflBod.yearTot / totalDay; + operList.efflTN.yearAvg = operList.efflTN.yearTot / totalDay; + operList.efflTP.yearAvg = operList.efflTP.yearTot / totalDay; + operList.tpInflTp.yearAvg = operList.tpInflTp.yearTot / totalDay; + orgData[5].yearAvg = qltyDataSetting(operList.inflBod.yearTot, totalDay, 1); // 연간 유입BOD + orgData[6].yearAvg = qltyDataSetting(operList.efflBod.yearTot,totalDay, 1); // 연간 방류BOD + orgData[7].yearAvg = qltyDataSetting(operList.inflTN.yearTot,totalDay, 3); // 연간 유입TN + orgData[8].yearAvg = qltyDataSetting(operList.efflTN.yearTot,totalDay, 3); // 연간 방류TN + orgData[9].yearAvg = qltyDataSetting(operList.inflTP.yearTot,totalDay, 3); // 연간 유입TP + orgData[10].yearAvg = qltyDataSetting(operList.efflTP.yearTot,totalDay, 3); // 연간 방류TP //총인설비 - orgData[11].winterAll = qltyDataSetting(totalTpInflAvgWinter, noNullWinterDay, 3); - orgData[12].winterAll = qltyDataSetting(totalEfflTpAvgWinter, winterDay, 3); + orgData[11].yearAvg = qltyDataSetting(operList.tpInflTp.yearTot, noNullYearDay, 3); // 연간 총인 유입수질 TP + orgData[12].yearAvg = qltyDataSetting(operList.efflTP.yearTot, totalDay, 3); // 연간 총인 유입수질 TP - orgData[5].summerAll = qltyDataSetting(totalInflBodAvgSummer, summerDay, 1); // 하절기 유입BOD - orgData[6].summerAll = qltyDataSetting(totalEfflBodAvgSummer, summerDay, 1); // 하절기 방류BOD - orgData[7].summerAll = qltyDataSetting(totalInflTnAvgSummer, summerDay, 3); // 하절기 유입TN - orgData[8].summerAll = qltyDataSetting(totalEfflTnAvgSummer, summerDay, 3); // 하절기 방류TN - orgData[9].summerAll = qltyDataSetting(totalInflTpAvgSummer, summerDay, 3); // 하절기 유입TP - orgData[10].summerAll = qltyDataSetting(totalEfflTpAvgSummer, summerDay, 3); // 하절기 방류TP + orgData[5].yearMax = roundUp(operList.inflBod.yearMax, 1); // 연간 유입BOD + orgData[6].yearMax = roundUp(operList.efflBod.yearMax, 1); // 연간 방류BOD + orgData[7].yearMax = roundUp(operList.inflTN.yearMax, 3).toFixed(3); // 연간 유입TN + orgData[8].yearMax = roundUp(operList.efflTN.yearMax, 3).toFixed(3); // 연간 방류TN + orgData[9].yearMax = roundUp(operList.inflTP.yearMax, 3).toFixed(3); // 연간 유입TP + orgData[10].yearMax = roundUp(operList.efflTP.yearMax, 3).toFixed(3); // 연간 방류TP + orgData[11].yearMax = roundUp(operList.tpInflTp.yearMax, 3).toFixed(3); // 연간 총인 유입수질 TP + orgData[12].yearMax = roundUp(operList.efflTP.yearMax, 3).toFixed(3); // 연간 총인 유입수질 TP + orgData[5].yearMin = roundUp(operList.inflBod.yearMin, 1); // 연간 유입BOD + orgData[6].yearMin = roundUp(operList.efflBod.yearMin, 1); // 연간 방류BOD + orgData[7].yearMin = roundUp(operList.inflTN.yearMin, 3).toFixed(3); // 연간 유입TN + orgData[8].yearMin = roundUp(operList.efflTN.yearMin, 3).toFixed(3); // 연간 방류TN + orgData[9].yearMin = roundUp(operList.inflTP.yearMin, 3).toFixed(3); // 연간 유입TP + orgData[10].yearMin = roundUp(operList.efflTP.yearMin, 3).toFixed(3); // 연간 방류TP + orgData[11].yearMin = roundUp(operList.tpInflTp.yearMin, 3).toFixed(3); // 연간 총인 유입수질 TP + orgData[12].yearMin = roundUp(operList.efflTP.yearMin, 3).toFixed(3); // 연간 총인 유입수질 TP + + orgData[5].summerAll = qltyDataSetting(totalInflBodAvgSummer, summerDay, 1); // 하절기 전기간 유입BOD + orgData[6].summerAll = qltyDataSetting(totalEfflBodAvgSummer, summerDay, 1); // 하절기 전기간 방류BOD + orgData[7].summerAll = qltyDataSetting(totalInflTnAvgSummer, summerDay, 3); // 하절기 전기간 유입TN + orgData[8].summerAll = qltyDataSetting(totalEfflTnAvgSummer, summerDay, 3); // 하절기 전기간 방류TN + orgData[9].summerAll = qltyDataSetting(totalInflTpAvgSummer, summerDay, 3); // 하절기 전기간 유입TP + orgData[10].summerAll = qltyDataSetting(totalEfflTpAvgSummer, summerDay, 3); // 하절기 전기간 방류TP //총인설비 orgData[11].summerAll = qltyDataSetting(totalTpInflAvgSummer, noNullSummerDay, 3); orgData[12].summerAll = qltyDataSetting(totalEfflTpAvgSummer, summerDay, 3); - - // 청천시 수질 데이터 수정 - // 하절기 - orgData[5].summerRain = qltyDataSetting(chungchunInflBodAvgSummer, chungchunSummerDay, 1); - orgData[6].summerRain = qltyDataSetting(chungchunEfflBodAvgSummer, chungchunSummerDay, 1); - orgData[7].summerRain = qltyDataSetting(chungchunInflTnAvgSummer, chungchunSummerDay, 3); - orgData[8].summerRain = qltyDataSetting(chungchunEfflTnAvgSummer, chungchunSummerDay, 3); - orgData[9].summerRain = qltyDataSetting(chungchunInflTpAvgSummer, chungchunSummerDay, 3); - orgData[10].summerRain = qltyDataSetting(chungchunEfflTpAvgSummer, chungchunSummerDay, 3); - - // 총인설비 - orgData[11].summerRain = qltyDataSetting(chungchunTpInflAvgSummer, noNullChungchunSummerDay, 3); - orgData[12].summerRain = qltyDataSetting(chungchunEfflTpAvgSummer, chungchunSummerDay, 3); - - // 동절기 - orgData[5].winterSunnyAvg = qltyDataSetting(chungchunInflBodAvg, chungchunWinterDay, 1); - orgData[6].winterSunnyAvg = qltyDataSetting(chungchunEfflBodAvg, chungchunWinterDay, 1); - orgData[7].winterSunnyAvg = qltyDataSetting(chungchunInflTnAvg, chungchunWinterDay, 3); - orgData[8].winterSunnyAvg = qltyDataSetting(chungchunEfflTnAvg, chungchunWinterDay, 3); - orgData[9].winterSunnyAvg = qltyDataSetting(chungchunInflTpAvg, chungchunWinterDay, 3); - orgData[10].winterSunnyAvg = qltyDataSetting(chungchunEfflTpAvg, chungchunWinterDay, 3); - - // 총인설비 - orgData[11].winterSunnyAvg = qltyDataSetting(chungchunTpInflAvg, noNullChungchunWinterDay, 3); - orgData[12].winterSunnyAvg = qltyDataSetting(chungchunInflTpAvg, chungchunWinterDay, 3); - - orgData[5].winterSunnyMax = roundUp(chungchunInflBodMax, 1).toFixed(1); - orgData[6].winterSunnyMax = roundUp(chungchunEfflBodMax, 1).toFixed(1); - orgData[7].winterSunnyMax = roundUp(chungchunInflTnMax, 3).toFixed(3); - orgData[8].winterSunnyMax = roundUp(chungchunEfflTnMax, 3).toFixed(3); - orgData[9].winterSunnyMax = roundUp(chungchunInflTpMax, 3).toFixed(3); - orgData[10].winterSunnyMax = roundUp(chungchunEfflTpMax, 3).toFixed(3); - orgData[11].winterSunnyMax = roundUp(chungchunTpInflMax, 3).toFixed(3); - orgData[12].winterSunnyMax = roundUp(chungchunInflTpMax, 3).toFixed(3); - - orgData[5].winterSunnyMin = chungchunInflBodMin === 99999999 ? '0.0' : roundUp(chungchunInflBodMin, 1).toFixed(1); - orgData[6].winterSunnyMin = chungchunEfflBodMin === 99999999 ? '0.0' : roundUp(chungchunEfflBodMin, 1).toFixed(1); - orgData[7].winterSunnyMin = chungchunInflTnMin === 99999999 ? '0.000' : roundUp(chungchunInflTnMin, 3).toFixed(3); - orgData[8].winterSunnyMin = chungchunEfflTnMin === 99999999 ? '0.000' : roundUp(chungchunEfflTnMin, 3).toFixed(3); - orgData[9].winterSunnyMin = chungchunInflTpMin === 99999999 ? '0.000' : roundUp(chungchunInflTpMin, 3).toFixed(3); - orgData[10].winterSunnyMin = chungchunEfflTpMin === 99999999 ? '0.000' : roundUp(chungchunEfflTpMin, 3).toFixed(3); - orgData[11].winterSunnyMin = chungchunTpInflMin === 99999999 ? '0.000' : roundUp(chungchunTpInflMin, 3).toFixed(3); - orgData[12].winterSunnyMin = chungchunInflTpMin === 99999999 ? '0.000' : roundUp(chungchunInflTpMin, 3).toFixed(3); - // 강우시 수질 데이터 수정 orgData[5].summerThree = qltyDataSetting(rainInflBodAvg, rainSummerDay, 1); orgData[6].summerThree = qltyDataSetting(rainEfflBodAvg, rainSummerDay, 1); @@ -987,12 +1006,61 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc orgData[8].summerThree = qltyDataSetting(rainEfflTnAvg, rainSummerDay, 3); orgData[9].summerThree = qltyDataSetting(rainInflTpAvg, rainSummerDay, 3); orgData[10].summerThree = qltyDataSetting(rainEfflTpAvg, rainSummerDay, 3); - // 총인설비 orgData[11].summerThree = qltyDataSetting(rainTpInflAvg, noNullRainSummerDay, 3); - orgData[12].summerThree = qltyDataSetting(rainInflTpAvg, rainSummerDay, 3); - // console.log(rainEffectDayArray); - // console.log("000000000", rainSummerDay, noNullRainSummerDay, rainInflBodAvg, rainInflTnAvg, rainInflTpAvg, rainEfflBodAvg, rainEfflTnAvg, rainEfflTpAvg, rainTpInflAvg); + orgData[12].summerThree = qltyDataSetting(rainEfflTpAvg, rainSummerDay, 3); + + // 하절기 청천시 수질 데이터 + orgData[5].summerRain = qltyDataSetting(chungchunInflBodAvgSummer, chungchunSummerDay, 1); + orgData[6].summerRain = qltyDataSetting(chungchunEfflBodAvgSummer, chungchunSummerDay, 1); + orgData[7].summerRain = qltyDataSetting(chungchunInflTnAvgSummer, chungchunSummerDay, 3); + orgData[8].summerRain = qltyDataSetting(chungchunEfflTnAvgSummer, chungchunSummerDay, 3); + orgData[9].summerRain = qltyDataSetting(chungchunInflTpAvgSummer, chungchunSummerDay, 3); + orgData[10].summerRain = qltyDataSetting(chungchunEfflTpAvgSummer, chungchunSummerDay, 3); + // 총인설비 + orgData[11].summerRain = qltyDataSetting(chungchunTpInflAvgSummer, noNullChungchunSummerDay, 3); + orgData[12].summerRain = qltyDataSetting(chungchunEfflTpAvgSummer, chungchunSummerDay, 3); + + orgData[5].winterAll = qltyDataSetting(totalInflBodAvgWinter, winterDay, 1); // 동절기 전기간 유입BOD + orgData[6].winterAll = qltyDataSetting(totalEfflBodAvgWinter, winterDay, 1); // 동절기 전기간 방류BOD + orgData[7].winterAll = qltyDataSetting(totalInflTnAvgWinter, winterDay, 3); // 동절기 전기간 유입TN + orgData[8].winterAll = qltyDataSetting(totalEfflTnAvgWinter, winterDay, 3); // 동절기 전기간 방류TN + orgData[9].winterAll = qltyDataSetting(totalInflTpAvgWinter, winterDay, 3); // 동절기 전기간 유입TP + orgData[10].winterAll = qltyDataSetting(totalEfflTpAvgWinter, winterDay, 3); // 동절기 전기간 방류TP + //총인설비 + orgData[11].winterAll = qltyDataSetting(totalTpInflAvgWinter, noNullWinterDay, 3); + orgData[12].winterAll = qltyDataSetting(totalEfflTpAvgWinter, winterDay, 3); + + // 동절기 청천시 수질 데이터 + orgData[5].winterSunnyAvg = qltyDataSetting(chungchunInflBodAvg, chungchunWinterDay, 1); + orgData[6].winterSunnyAvg = qltyDataSetting(chungchunEfflBodAvg, chungchunWinterDay, 1); + orgData[7].winterSunnyAvg = qltyDataSetting(chungchunInflTnAvg, chungchunWinterDay, 3); + orgData[8].winterSunnyAvg = qltyDataSetting(chungchunEfflTnAvg, chungchunWinterDay, 3); + orgData[9].winterSunnyAvg = qltyDataSetting(chungchunInflTpAvg, chungchunWinterDay, 3); + orgData[10].winterSunnyAvg = qltyDataSetting(chungchunEfflTpAvg, chungchunWinterDay, 3); + // 총인설비 + orgData[11].winterSunnyAvg = qltyDataSetting(chungchunTpInflAvg, noNullChungchunWinterDay, 3); + orgData[12].winterSunnyAvg = qltyDataSetting(chungchunEfflTpAvg, chungchunWinterDay, 3); + + orgData[5].winterSunnyMax = roundUp(chungchunInflBodMax, 1).toFixed(1); + orgData[6].winterSunnyMax = roundUp(chungchunEfflBodMax, 1).toFixed(1); + orgData[7].winterSunnyMax = roundUp(chungchunInflTnMax, 3).toFixed(3); + orgData[8].winterSunnyMax = roundUp(chungchunEfflTnMax, 3).toFixed(3); + orgData[9].winterSunnyMax = roundUp(chungchunInflTpMax, 3).toFixed(3); + orgData[10].winterSunnyMax = roundUp(chungchunEfflTpMax, 3).toFixed(3); + orgData[11].winterSunnyMax = roundUp(chungchunTpInflMax, 3).toFixed(3); + orgData[12].winterSunnyMax = roundUp(chungchunEfflTpMax, 3).toFixed(3); + + orgData[5].winterSunnyMin = chungchunInflBodMin === 99999999 ? '0.0' : roundUp(chungchunInflBodMin, 1).toFixed(1); + orgData[6].winterSunnyMin = chungchunEfflBodMin === 99999999 ? '0.0' : roundUp(chungchunEfflBodMin, 1).toFixed(1); + orgData[7].winterSunnyMin = chungchunInflTnMin === 99999999 ? '0.000' : roundUp(chungchunInflTnMin, 3).toFixed(3); + orgData[8].winterSunnyMin = chungchunEfflTnMin === 99999999 ? '0.000' : roundUp(chungchunEfflTnMin, 3).toFixed(3); + orgData[9].winterSunnyMin = chungchunInflTpMin === 99999999 ? '0.000' : roundUp(chungchunInflTpMin, 3).toFixed(3); + orgData[10].winterSunnyMin = chungchunEfflTpMin === 99999999 ? '0.000' : roundUp(chungchunEfflTpMin, 3).toFixed(3); + orgData[11].winterSunnyMin = chungchunTpInflMin === 99999999 ? '0.000' : roundUp(chungchunTpInflMin, 3).toFixed(3); + orgData[12].winterSunnyMin = chungchunEfflTpMin === 99999999 ? '0.000' : roundUp(chungchunEfflTpMin, 3).toFixed(3); + + return orgData; } else { @@ -1193,46 +1261,47 @@ export const dataFormSettingWqlty = (item: OperationalStatusListProps) => { DataForm({ type: 'float1', column: 'rdi', item: item as unknown as Record<string, unknown> }); }; -const changeValue = (operationalStatus, data, keyTxt = 'INFL_AMNT') => { - operationalStatus.yearAvg = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['AVG_' + keyTxt] : ''; - operationalStatus.yearMax = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['MAX_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['MAX_' + keyTxt] : ''; - operationalStatus.yearMin = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['MIN_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['MIN_' + keyTxt] : ''; - // 여름 - operationalStatus.summerAll = data.summer ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summer ? Number(Math.round(data.summer['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summer['AVG_' + keyTxt] : ''; - operationalStatus.summerThree = data.summerRainy ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summerRainy ? Number(Math.round(data.summerRainy["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summerRainy["AVG_" + keyTxt] : ''; - operationalStatus.summerRain = data.summerSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summerSunny ? Number(Math.round(data.summerSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summerSunny["AVG_" + keyTxt] : ''; - // 겨울 - operationalStatus.winterAll = data.winter ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winter ? Number(Math.round(data.winter["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winter["AVG_" + keyTxt] : ''; - operationalStatus.winterSunnyMin = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["MIN_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["MIN_" + keyTxt] : ''; - operationalStatus.winterSunnyAvg = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["AVG_" + keyTxt] : ''; - operationalStatus.winterSunnyMax = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["MAX_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["MAX_" + keyTxt] : ''; - // 지하수 +// const changeValue = (operationalStatus, data, keyTxt = 'INFL_AMNT') => { +// //console.log('data.yearData', data.yearData); +// operationalStatus.yearAvg = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['AVG_' + keyTxt] : ''; +// operationalStatus.yearMax = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['MAX_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['MAX_' + keyTxt] : ''; +// operationalStatus.yearMin = data.yearData ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.yearData ? Number(Math.round(data.yearData['MIN_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.yearData['MIN_' + keyTxt] : ''; +// // 여름 +// operationalStatus.summerAll = data.summer ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summer ? Number(Math.round(data.summer['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summer['AVG_' + keyTxt] : ''; +// operationalStatus.summerThree = data.summerRainy ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summerRainy ? Number(Math.round(data.summerRainy["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summerRainy["AVG_" + keyTxt] : ''; +// operationalStatus.summerRain = data.summerSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.summerSunny ? Number(Math.round(data.summerSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.summerSunny["AVG_" + keyTxt] : ''; +// // 겨울 +// operationalStatus.winterAll = data.winter ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winter ? Number(Math.round(data.winter["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winter["AVG_" + keyTxt] : ''; +// operationalStatus.winterSunnyMin = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["MIN_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["MIN_" + keyTxt] : ''; +// operationalStatus.winterSunnyAvg = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["AVG_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["AVG_" + keyTxt] : ''; +// operationalStatus.winterSunnyMax = data.winterSunny ? (keyTxt.includes('_TP') || keyTxt.includes("_TN")) ? data.winterSunny ? Number(Math.round(data.winterSunny["MAX_" + keyTxt] * 1000) / 1000).toFixed(3).toString() : '' : data.winterSunny["MAX_" + keyTxt] : ''; +// // 지하수 - // 오염물질 - // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) - const summerLowFlow = data.summerBod && data.summerBod.INFL_AMNT && data.summerBod.INFL_AMNT != 'null' ? Number(data.summerBod.INFL_AMNT) : 0; - const winterAvgBod = data.winterSunny && data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD && data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD != 'null' ? Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD) : 0; - const summerLowBod = data.summerBod && data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD && data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD != 'null' ? Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD) : 0; - const summerLowRain = data.summerBod && data.summerBod.INFO_RN_DAY && data.summerBod.INFO_RN_DAY != 'null' ? Number(data.summerBod.INFO_RN_DAY) : 0; - operationalStatus.rdi = winterAvgBod === 0 ? 0 : roundUp(summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod), 1); - operationalStatus.rdiRain = summerLowRain; -} +// // 오염물질 +// // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) +// const summerLowFlow = data.summerBod && data.summerBod.INFL_AMNT && data.summerBod.INFL_AMNT != 'null' ? Number(data.summerBod.INFL_AMNT) : 0; +// const winterAvgBod = data.winterSunny && data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD && data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD != 'null' ? Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD) : 0; +// const summerLowBod = data.summerBod && data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD && data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD != 'null' ? Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD) : 0; +// const summerLowRain = data.summerBod && data.summerBod.INFO_RN_DAY && data.summerBod.INFO_RN_DAY != 'null' ? Number(data.summerBod.INFO_RN_DAY) : 0; +// operationalStatus.rdi = winterAvgBod === 0 ? 0 : roundUp(summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod), 1); +// operationalStatus.rdiRain = summerLowRain; +// } -const calcValue = (operationalStatus, data, keyTxt = 'INFL_ASSCT_BFR_WQLT_TP') => { - // 연간 - operationalStatus.yearAvg = data.yearData && data.yearData['AVG_' + keyTxt] ? Number(Math.round(data.yearData['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.yearMax = data.yearData && data.yearData['MAX_' + keyTxt] ? Number(Math.round(data.yearData['MAX_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.yearMin = data.yearData && data.yearData['MIN_' + keyTxt] ? Number(Math.round(data.yearData['MIN_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; - // 여름 - operationalStatus.summerAll = data.summer && data.summer['AVG_' + keyTxt] ? Number(Math.round(data.summer['AVG_' + keyTxt] * 0.8 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.summerThree = data.summerRainy && data.summerRainy['AVG_' + keyTxt] ? Number(Math.round(data.summerRainy['AVG_' + keyTxt] * 0.82 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.summerRain = data.summerSunny && data.summerSunny['AVG_' + keyTxt] ? Number(Math.round(data.summerSunny['AVG_' + keyTxt] * 0.74 * 1000) / 1000).toFixed(3).toString() : ''; - // 겨울 - operationalStatus.winterAll = data.winter && data.winter['AVG_' + keyTxt] ? Number(Math.round(data.winter['AVG_' + keyTxt] * 1.16 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.winterSunnyMin = data.winterSunny && data.winterSunny['MIN_' + keyTxt] ? Number(Math.round(data.winterSunny['MIN_' + keyTxt] * 1.2 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.winterSunnyAvg = data.winterSunny && data.winterSunny['AVG_' + keyTxt] ? Number(Math.round(data.winterSunny['AVG_' + keyTxt] * 1.25 * 1000) / 1000).toFixed(3).toString() : ''; - operationalStatus.winterSunnyMax = data.winterSunny && data.winterSunny['MAX_' + keyTxt] ? Number(Math.round(data.winterSunny['MAX_' + keyTxt] * 1.3 * 1000) / 1000).toFixed(3).toString() : ''; -} +// const calcValue = (operationalStatus, data, keyTxt = 'INFL_ASSCT_BFR_WQLT_TP') => { +// // 연간 +// operationalStatus.yearAvg = data.yearData && data.yearData['AVG_' + keyTxt] ? Number(Math.round(data.yearData['AVG_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.yearMax = data.yearData && data.yearData['MAX_' + keyTxt] ? Number(Math.round(data.yearData['MAX_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.yearMin = data.yearData && data.yearData['MIN_' + keyTxt] ? Number(Math.round(data.yearData['MIN_' + keyTxt] * 1000) / 1000).toFixed(3).toString() : ''; +// // 여름 +// operationalStatus.summerAll = data.summer && data.summer['AVG_' + keyTxt] ? Number(Math.round(data.summer['AVG_' + keyTxt] * 0.8 * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.summerThree = data.summerRainy && data.summerRainy['AVG_' + keyTxt] ? Number(Math.round(data.summerRainy['AVG_' + keyTxt] * 0.82 * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.summerRain = data.summerSunny && data.summerSunny['AVG_' + keyTxt] ? Number(Math.round(data.summerSunny['AVG_' + keyTxt] * 0.74 * 1000) / 1000).toFixed(3).toString() : ''; +// // 겨울 +// operationalStatus.winterAll = data.winter && data.winter['AVG_' + keyTxt] ? Number(Math.round(data.winter['AVG_' + keyTxt] * 1.16 * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.winterSunnyMin = data.winterSunny && data.winterSunny['MIN_' + keyTxt] ? Number(Math.round(data.winterSunny['MIN_' + keyTxt] * 1.2 * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.winterSunnyAvg = data.winterSunny && data.winterSunny['AVG_' + keyTxt] ? Number(Math.round(data.winterSunny['AVG_' + keyTxt] * 1.25 * 1000) / 1000).toFixed(3).toString() : ''; +// operationalStatus.winterSunnyMax = data.winterSunny && data.winterSunny['MAX_' + keyTxt] ? Number(Math.round(data.winterSunny['MAX_' + keyTxt] * 1.3 * 1000) / 1000).toFixed(3).toString() : ''; +// } type wtrUsgYearsType = { YEAR: string; @@ -1391,97 +1460,43 @@ export const dashBoardReducer = ( isLoadingOperationStatus: true, }, })); - const res = await fetchOperationStatus(searchYear, fcltyCd); // /dashBoard/mngInfo/ - const data = res.data; - - let yearMaxSumFlow = 1, yearMinSumFlow = 1, yearAvgSumFlow = 1; // 연간 최대, 최소, 평균 - let summerAll = 1; // 하절기 전기간 - let summerThree = 1; // 하절기 - let summerRain = 1; // 하절기 - let winterAll = 1; // 동절기 전기간 - let winterSunnyMin = 1, winterSunnyAvg = 1, winterSunnyMax = 1; // 동절기 청천 최소, 평균, 최대 - - // 최대, 최소 총 유입량 (1년 하루 합계의 최대, 최소) - // 하절기 청천시, 강우시 재계산 리턴값 - let summerChungchunFlow = 1, summerChungchunReturnAmnt = 1, summerChungchunEfflAmnt = 1; // 하절기 청천 - let summerRainInflAmnt = 1, summerRainReturnAmnt = 1, summerRainEfflAmnt = 1; // 하절기 강우시 - // 동절기 청천시 최대, 최소, 평균 리턴값 - let winterChungchunFlowAvg = 1, winterChungchunFlowMax = 1, winterChungchunFlowMin = 1; // 동절기 청천 하수유입량 평균, 최대, 최소 - let winterChungchunReturnAvg = 1, winterChungchunReturnMax = 1, winterChungchunReturnMin = 1; // 동절기 청천 총인반류수 평균, 최대, 최소 - let winterChungchunEfflAvg = 1, winterChungchunEfflMax = 1, winterChungchunEfflMin = 1; // 동절기 청천 방류량 평균, 최대, 최소 + // const res = await fetchOperationStatus(searchYear, fcltyCd); // /dashBoard/mngInfo/ + // const data = res.data; + const operList = { + inFlow : {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 + , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + inflAmt: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999, yearSunny: 0 + , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 + , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + sumFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 + , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + returnFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 + , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + efflFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 + , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + }; const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; let rdiPercent = 0; let operationalStatusList = clone(operationalStatusListOrg); - if (data && operationalStatusList) { + if (operationalStatusList) { // 유량 - 유입 if (operationalStatusList?.[0]) { - // 연간 - const yearAvg = data.yearData === null ? '' : ( - (data.yearData.AVG_INFL_AMNT ? data.yearData.AVG_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 평균 - (data.yearData.AVG_SUM_FLOW ? data.yearData.AVG_SUM_FLOW : 0) + // 연계처리량 api 주석처리되어 있음. - (data.yearData.AVG_RETURN_AMNT ? data.yearData.AVG_RETURN_AMNT : 0) // 반류수유량(m³/일) 평균 - ); - const yearMax = data.yearData === null ? '' : ( - (data.yearData.MAX_INFL_AMNT ? data.yearData.MAX_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 최대 - (data.yearData.MAX_SUM_FLOW ? data.yearData.MAX_SUM_FLOW : 0) + // 연계처리량 api 주석처리되어 있음. - (data.yearData.MAX_RETURN_AMNT ? data.yearData.MAX_RETURN_AMNT : 0) // 반류수유량(m³/일) 최대 - ); - const yearMin = data.yearData === null ? '' : ( - (data.yearData.MIN_INFL_AMNT ? data.yearData.MIN_INFL_AMNT : 0) + // 실제유입량(반류수제거)(m³/일) 최소 - (data.yearData.MIN_SUM_FLOW ? data.yearData.MIN_SUM_FLOW : 0) + // 연계처리량 api 주석처리되어 있음. - (data.yearData.MIN_RETURN_AMNT ? data.yearData.MIN_RETURN_AMNT : 0) // 반류수유량(m³/일) 최소 - ); - operationalStatusList[0].yearAvg = yearAvg; // 연간유입평균 - operationalStatusList[0].yearMax = yearMax; // 연간유입최대 - operationalStatusList[0].yearMin = yearMin; // 연간유입최소 - // 하절기 - operationalStatusList[0].summerAll = data.summer === null ? '' : ( // 하절기전기간 - (data.summer.AVG_INFL_AMNT ? data.summer.AVG_INFL_AMNT : 0) + - (data.summer.AVG_SUM_FLOW ? data.summer.AVG_SUM_FLOW : 0) - ); - operationalStatusList[0].summerThree = data.summerRainy === null ? '' : ( // 하절기 강우시 - (data.summerRainy.AVG_INFL_AMNT ? data.summerRainy.AVG_INFL_AMNT : 0) + - (data.summerRainy.AVG_SUM_FLOW ? data.summerRainy.AVG_SUM_FLOW : 0) - ); - operationalStatusList[0].summerRain = data.summerSunny === null ? '' : ( // 하절기 청천시 - (data.summerSunny.AVG_INFL_AMNT ? data.summerSunny.AVG_INFL_AMNT : 0) + - (data.summerSunny.AVG_SUM_FLOW ? data.summerSunny.AVG_SUM_FLOW : 0) - ); - // 동절기 - operationalStatusList[0].winterAll = data.winter === null ? '' : ( // 동절기 전기간 - (data.winter.AVG_INFL_AMNT ? data.winter.AVG_INFL_AMNT : 0) + - (data.winter.AVG_SUM_FLOW ? data.winter.AVG_SUM_FLOW : 0) + - (data.winter.AVG_TP_INFL_WQLT_TP ? data.winter.AVG_TP_INFL_WQLT_TP : 0) - ); - operationalStatusList[0].winterSunnyMin = data.winterSunny === null ? '' : (// 동절기 청천 최소 - (data.winterSunny.MIN_INFL_AMNT ? data.winterSunny.MIN_INFL_AMNT : 0) + - (data.winterSunny.MIN_SUM_FLOW ? data.winterSunny.MIN_SUM_FLOW : 0) + - (data.winterSunny.MIN_TP_INFL_WQLT_TP ? data.winterSunny.MIN_TP_INFL_WQLT_TP : 0) - ); - operationalStatusList[0].winterSunnyAvg = data.winterSunny === null ? '' : (// 동절기 청천 평균 - (data.winterSunny.AVG_INFL_AMNT ? data.winterSunny.AVG_INFL_AMNT : 0) + - (data.winterSunny.AVG_SUM_FLOW ? data.winterSunny.AVG_SUM_FLOW : 0) + - (data.winterSunny.AVG_TP_INFL_WQLT_TP ? data.winterSunny.AVG_TP_INFL_WQLT_TP : 0) - ); - operationalStatusList[0].winterSunnyMax = data.winterSunny === null ? '' : (// 동절기 청천 최대 - (data.winterSunny.MAX_INFL_AMNT ? data.winterSunny.MAX_INFL_AMNT : 0) + - (data.winterSunny.MAX_SUM_FLOW ? data.winterSunny.MAX_SUM_FLOW : 0) + - (data.winterSunny.MAX_TP_INFL_WQLT_TP ? data.winterSunny.MAX_TP_INFL_WQLT_TP : 0) - ); - + // 연계처리수 let yearDay = 0, summerDay = 0, winterDay = 0; // 연간 일수, 하절기 일수, 동절기 일수 let summerRainDay = 0, summerChungchunDay = 0, winterChungchuDay = 0; // 하절기 강우 일수, 하절기 청천 일수, 동절기 청천 일수 - let totFlowMax = 0, totFlowMin = 9999999; - let yearSumFlow = 0, maxYearSumFlow = 0, minYearSumFlow = 9999999; - let summerSumFlow = 0, summerChungchunSumFlow = 0, summerRainDaySumFlow = 0; // 하절기 유입량 합, 하절기 청천 유입량 합, 하절기 강우 유입량 합 - let summerRainDayFlow = 0, summerRainDayReturnFlow = 0, summerRainDayEfflFlow = 0; // 하절기 강우 유입량, 하절기 강우 반류량, 하절기 강우 방류량 - let winterSumFlow = 0; // 동절기 유입량 합 - let winterChungchunSumFlow = 0; // 동절기 청천 유입량 합 - let maxWinterChungchunSumFlow = 0, minWinterChungchunSumFlow = 9999999; - + // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 @@ -1490,30 +1505,18 @@ export const dashBoardReducer = ( //const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); let cntSunnyDay = 0; // 청천일 수 - // 지하수유입량 - 청천시 기준 - let chungcunSumFlow = 0; - let sumSummerChungcunFlow = 0; - let sumWinterChungcunFlow = 0; - let summerChungchunDayReturnAmnt = 0; // 하절기 청천시 총인설비 반류수 - let summerChungchunDayEfflAmnt = 0; // 하절기 청천시 총인설비 방류수 - - let winterChungchunTotalInflAmntMax = 0, winterChungchunTotalInflAmntMin = 9999999; // 동절기 총 유입량 최대, 최소 - let winterChungchunDayFlowMax = 0, winterChungchunDayFlowMin = 9999999; // 동절기 청천시 하수유입량 최대, 최소 - let winterChungchunDayReturnMax = 0, winterChungchunDayReturnMin = 9999999; // 동절기 청천시 총인반류수 최대, 최소, 평균 - let winterChungchunDayReturnAvg = 0; - // 동절기 청천시 방류량 최대, 최소, 평균 - let winterChungchunDayEfflMax = 0, winterChungchunDayEfflMin = 9999999, winterChungchunDayEfflAvg = 0; - + // let chungcunSumFlow = 0; // 연간 청천 순수하수 + let rainEffectDay = 0; yearDay = res2.data ? res2.data.length : 1; - res2.data.forEach((item: any) => { //fetchFlowRateModalList + res2.data.forEach((item: any) => { // --일별 유량 start const month = item.msrDt.substring(4, 6); // 월 추출 const sumFlow = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; const inflAmnt = item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0; const returnAmnt = item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0; const efflAmnt = item.efflAmnt && item.efflAmnt !== 'x' ? Number(item.efflAmnt.toString().trim()) : 0; - + if (item.infoRnDay == null) item.infoRnDay = 0; if (item.infoRnDay >= 3) { rainEffectDay = 2; @@ -1524,135 +1527,141 @@ export const dashBoardReducer = ( if (rainEffectDay >= 0) { // 강우영향일 - if (month === '06' || month === '07' || month === '08') { // 하절기 + if (month === '06' || month === '07' || month === '08') { // 하절기 강우영향일 summerRainDay += 1; - summerRainDaySumFlow += sumFlow; - summerRainDayFlow += inflAmnt; - summerRainDayReturnFlow += returnAmnt; - summerRainDayEfflFlow += efflAmnt; + operList.inFlow.summerRainy += inflAmnt + sumFlow + returnAmnt; + operList.inflAmt.summerRainy += inflAmnt; + operList.sumFlow.summerRainy += sumFlow; + operList.returnFlow.summerRainy += returnAmnt; + operList.efflFlow.summerRainy += efflAmnt; } } else if (rainEffectDay < 0) { cntSunnyDay += 1; // 청천일수 // 청천시 - chungcunSumFlow += inflAmnt; + // chungcunSumFlow += inflAmnt; // 연간 청천 순수하수 + operList.inflAmt.yearSunny += inflAmnt; // 연간 청천 순수하수 - if (month === '06' || month === '07' || month === '08') { // 하절기 + if (month === '06' || month === '07' || month === '08') { // 하절기 청천 summerChungchunDay += 1; - summerChungchunSumFlow += sumFlow; - sumSummerChungcunFlow += inflAmnt; - summerChungchunDayReturnAmnt += returnAmnt; - summerChungchunDayEfflAmnt += efflAmnt; - - } else if (month === '01' || month === '02') { // 동절기 + operList.inFlow.summerSunny += inflAmnt + sumFlow + returnAmnt; + operList.inflAmt.summerSunny += inflAmnt; + operList.sumFlow.summerSunny += sumFlow; + operList.returnFlow.summerSunny += returnAmnt; + operList.efflFlow.summerSunny += efflAmnt; + } else if (month === '01' || month === '02') { // 동절기 청천 winterChungchuDay += 1; - winterChungchunSumFlow += sumFlow; // 연계처리수 - sumWinterChungcunFlow += inflAmnt; - winterChungchunDayReturnAvg += returnAmnt; - winterChungchunDayEfflAvg += efflAmnt; + const inflowOne = inflAmnt + sumFlow + returnAmnt; + operList.inFlow.winterSunny += inflAmnt + sumFlow + returnAmnt; + operList.inflAmt.winterSunny += inflAmnt; + operList.sumFlow.winterSunny += sumFlow; + operList.returnFlow.winterSunny += returnAmnt; + operList.efflFlow.winterSunny += efflAmnt; - let totWinterTotalInflAmnt = 0; - totWinterTotalInflAmnt = inflAmnt + sumFlow + returnAmnt; - if (winterChungchunTotalInflAmntMax < totWinterTotalInflAmnt) winterChungchunTotalInflAmntMax = totWinterTotalInflAmnt; - if (winterChungchunTotalInflAmntMin > totWinterTotalInflAmnt || winterChungchunTotalInflAmntMin === 0) winterChungchunTotalInflAmntMin = totWinterTotalInflAmnt; + if (operList.inFlow.winterSunnyMax < inflowOne) operList.inFlow.winterSunnyMax = inflowOne; + if (operList.inflAmt.winterSunnyMax < inflAmnt) operList.inflAmt.winterSunnyMax = inflAmnt; + if (operList.sumFlow.winterSunnyMax < sumFlow) operList.sumFlow.winterSunnyMax = sumFlow; + if (operList.returnFlow.winterSunnyMax < returnAmnt) operList.returnFlow.winterSunnyMax = returnAmnt; + if (operList.efflFlow.winterSunnyMax < efflAmnt) operList.efflFlow.winterSunnyMax = efflAmnt; - if (winterChungchunDayFlowMin > inflAmnt) winterChungchunDayFlowMin = inflAmnt; - if (winterChungchunDayFlowMax < inflAmnt) winterChungchunDayFlowMax = inflAmnt; - - if (minWinterChungchunSumFlow > sumFlow) minWinterChungchunSumFlow = sumFlow; - if (maxWinterChungchunSumFlow < sumFlow) maxWinterChungchunSumFlow = sumFlow; - - if (winterChungchunDayReturnMin > returnAmnt) winterChungchunDayReturnMin = returnAmnt; - if (winterChungchunDayReturnMax < returnAmnt) winterChungchunDayReturnMax = returnAmnt; - - if (winterChungchunDayEfflMin > efflAmnt) winterChungchunDayEfflMin = efflAmnt; - if (winterChungchunDayEfflMax < efflAmnt) winterChungchunDayEfflMax = efflAmnt; + if (operList.inFlow.winterSunnyMin > inflowOne) operList.inFlow.winterSunnyMin = inflowOne; + if (operList.inflAmt.winterSunnyMin > inflAmnt) operList.inflAmt.winterSunnyMin = inflAmnt; + if (operList.sumFlow.winterSunnyMin > sumFlow) operList.sumFlow.winterSunnyMin = sumFlow; + if (operList.returnFlow.winterSunnyMin > returnAmnt) operList.returnFlow.winterSunnyMin = returnAmnt; + if (operList.efflFlow.winterSunnyMin > efflAmnt) operList.efflFlow.winterSunnyMin = efflAmnt; } } + const inflowOne = inflAmnt + sumFlow + returnAmnt; + operList.inFlow.yearTot += inflAmnt + sumFlow + returnAmnt; + operList.inflAmt.yearTot += inflAmnt; + operList.sumFlow.yearTot += sumFlow; + operList.returnFlow.yearTot += returnAmnt; + operList.efflFlow.yearTot += efflAmnt; - yearSumFlow += sumFlow; - if (maxYearSumFlow < sumFlow) maxYearSumFlow = sumFlow; - if (minYearSumFlow > sumFlow) minYearSumFlow = sumFlow; + if (operList.inFlow.yearMax < inflowOne) operList.inFlow.yearMax = inflowOne; + if (operList.inflAmt.yearMax < inflAmnt) operList.inflAmt.yearMax = inflAmnt; + if (operList.sumFlow.yearMax < sumFlow) operList.sumFlow.yearMax = sumFlow; + if (operList.returnFlow.yearMax < returnAmnt) operList.returnFlow.yearMax = returnAmnt; + if (operList.efflFlow.yearMax < efflAmnt) operList.efflFlow.yearMax = efflAmnt; - // 1년 최대 총 하수유입량 - let totYearFlow = 0; - totYearFlow = inflAmnt + sumFlow + returnAmnt; - if (totFlowMax < totYearFlow) totFlowMax = totYearFlow; - if (totFlowMin > totYearFlow || totFlowMin === 0) { - totFlowMin = totYearFlow; - } + if (operList.inFlow.yearMin > inflowOne) operList.inFlow.yearMin = inflowOne; + if (operList.inflAmt.yearMin > inflAmnt) operList.inflAmt.yearMin = inflAmnt; + if (operList.sumFlow.yearMin > sumFlow) operList.sumFlow.yearMin = sumFlow; + if (operList.returnFlow.yearMin > returnAmnt) operList.returnFlow.yearMin = returnAmnt; + if (operList.efflFlow.yearMin > efflAmnt) operList.efflFlow.yearMin = efflAmnt; if (month === '06' || month === '07' || month === '08') { summerDay += 1; - summerSumFlow += sumFlow; + operList.inFlow.summerTot += inflAmnt + sumFlow + returnAmnt; + operList.inflAmt.summerTot += inflAmnt; + operList.sumFlow.summerTot += sumFlow; + operList.returnFlow.summerTot += returnAmnt; + operList.efflFlow.summerTot += efflAmnt; } else if (month === '01' || month === '02') { winterDay += 1; - winterSumFlow += sumFlow; + operList.inFlow.winterTot += inflAmnt + sumFlow + returnAmnt; + operList.inflAmt.winterTot += inflAmnt; + operList.sumFlow.winterTot += sumFlow; + operList.returnFlow.winterTot += returnAmnt; + operList.efflFlow.winterTot += efflAmnt; } - }); + }); // --일별 유량 end + // 연간 평균 + operList.inFlow.yearAvg = (yearDay > 0)? operList.inFlow.yearTot / yearDay : 0; + operList.inflAmt.yearAvg = (yearDay > 0)? operList.inflAmt.yearTot / yearDay : 0; + operList.sumFlow.yearAvg = (yearDay > 0)? operList.sumFlow.yearTot / yearDay : 0; + operList.returnFlow.yearAvg = (yearDay > 0)? operList.returnFlow.yearTot / yearDay : 0; + operList.efflFlow.yearAvg = (yearDay > 0)? operList.efflFlow.yearTot / yearDay : 0; + // 하절기 전기간 평균 + operList.inFlow.summerAvg = (summerDay > 0)? operList.inFlow.summerTot / summerDay : 0; + operList.inflAmt.summerAvg = (summerDay > 0)? operList.inflAmt.summerTot / summerDay : 0; + operList.sumFlow.summerAvg = (summerDay > 0)? operList.sumFlow.summerTot / summerDay : 0; + operList.returnFlow.summerAvg = (summerDay > 0)? operList.returnFlow.summerTot / summerDay : 0; + operList.efflFlow.summerAvg = (summerDay > 0)? operList.efflFlow.summerTot / summerDay : 0; + // 하절기 강우시 평균 + operList.inFlow.summerRainy = (summerRainDay > 0)? operList.inFlow.summerRainy / summerRainDay : 0; + operList.inflAmt.summerRainy = (summerRainDay > 0)? operList.inflAmt.summerRainy / summerRainDay : 0; + operList.sumFlow.summerRainy = (summerRainDay > 0)? operList.sumFlow.summerRainy / summerRainDay : 0; + operList.returnFlow.summerRainy = (summerRainDay > 0)? operList.returnFlow.summerRainy / summerRainDay : 0; + operList.efflFlow.summerRainy = (summerRainDay > 0)? operList.efflFlow.summerRainy / summerRainDay : 0; + // 하절기 청천시 평균 + operList.inFlow.summerSunny = (summerChungchunDay > 0)? operList.inFlow.summerSunny / summerChungchunDay : 0; + operList.inflAmt.summerSunny = (summerChungchunDay > 0)? operList.inflAmt.summerSunny / summerChungchunDay : 0; + operList.sumFlow.summerSunny = (summerChungchunDay > 0)? operList.sumFlow.summerSunny / summerChungchunDay : 0; + operList.returnFlow.summerSunny = (summerChungchunDay > 0)? operList.returnFlow.summerSunny / summerChungchunDay : 0; + operList.efflFlow.summerSunny = (summerChungchunDay > 0)? operList.efflFlow.summerSunny / summerChungchunDay : 0; + // 동절기 전기간 평균 + operList.inFlow.winterAvg = (winterDay > 0)? operList.inFlow.winterTot / winterDay : 0; + operList.inflAmt.winterAvg = (winterDay > 0)? operList.inflAmt.winterTot / winterDay : 0; + operList.sumFlow.winterAvg = (winterDay > 0)? operList.sumFlow.winterTot / winterDay : 0; + operList.returnFlow.winterAvg = (winterDay > 0)? operList.returnFlow.winterTot / winterDay : 0; + operList.efflFlow.winterAvg = (winterDay > 0)? operList.efflFlow.winterTot / winterDay : 0; + // 동절기 청천시 평균 + operList.inFlow.winterSunny = (winterChungchuDay > 0)? operList.inFlow.winterSunny / winterChungchuDay : 0; + operList.inflAmt.winterSunny = (winterChungchuDay > 0)? operList.inflAmt.winterSunny / winterChungchuDay : 0; + operList.sumFlow.winterSunny = (winterChungchuDay > 0)? operList.sumFlow.winterSunny / winterChungchuDay : 0; + operList.returnFlow.winterSunny = (winterChungchuDay > 0)? operList.returnFlow.winterSunny / winterChungchuDay : 0; + operList.efflFlow.winterSunny = (winterChungchuDay > 0)? operList.efflFlow.winterSunny / winterChungchuDay : 0; - // 연계처리수 - yearAvgSumFlow = Number((yearSumFlow && Number(yearSumFlow) != 0) ? (yearSumFlow / yearDay) : ''); - yearMaxSumFlow = maxYearSumFlow; - yearMinSumFlow = minYearSumFlow; - summerAll = summerSumFlow && Number(summerSumFlow) != 0 ? Number(summerSumFlow / summerDay) : 0 - summerThree = summerRainDaySumFlow && Number(summerRainDaySumFlow) != 0 ? Number(summerRainDaySumFlow / summerRainDay) : 0; - summerRain = summerChungchunSumFlow && Number(summerChungchunSumFlow) != 0 ? Number(summerChungchunSumFlow / summerChungchunDay) : 0; - winterAll = winterSumFlow && Number(winterSumFlow) != 0 ? Number(winterSumFlow / winterDay) : 0; - winterSunnyMin = minWinterChungchunSumFlow; - winterSunnyAvg = winterChungchunSumFlow && Number(winterChungchunSumFlow) != 0 ? (winterChungchunSumFlow / winterChungchuDay) : 0; - winterSunnyMax = maxWinterChungchunSumFlow; - - // 하절기 강우시 계산 - // 하수유입량 (강우시) - summerRainInflAmnt = summerRainDayFlow && Number(summerRainDayFlow) != 0 ? Number(summerRainDayFlow / summerRainDay) : 0; - // 총인설비방류수 (강우시) - summerRainReturnAmnt = summerRainDayReturnFlow && Number(summerRainDayReturnFlow) != 0 ? Number(summerRainDayReturnFlow / summerRainDay) : 0; - // 방루량 (강우시) - summerRainEfflAmnt = summerRainDayEfflFlow && summerRainDayEfflFlow != 0 ? summerRainDayEfflFlow / summerRainDay : 0; - - // 동절기 청천시 계산 - // 하수유입량 (청천시) 평균 - winterChungchunFlowAvg = sumWinterChungcunFlow && Number(sumWinterChungcunFlow) != 0 ? (sumWinterChungcunFlow / winterChungchuDay) : 0; - // 총인반류수 (청천시) 평균 - winterChungchunReturnAvg = winterChungchunDayReturnAvg && Number(winterChungchunDayReturnAvg) != 0 ? (winterChungchunDayReturnAvg / winterChungchuDay) : 0; - // 방류량 (청천시) 평균 - winterChungchunEfflAvg = winterChungchunDayEfflAvg && Number(winterChungchunDayEfflAvg) != 0 ? (winterChungchunDayEfflAvg / winterChungchuDay) : 0; - // 하수유입량 (청천시) 최대 - winterChungchunFlowMax = winterChungchunDayFlowMax; - // 총인반류수 (청천시) 최대 - winterChungchunReturnMax = winterChungchunDayReturnMax; - // 방류량 (청천시) 최대 - winterChungchunEfflMax = winterChungchunDayEfflMax; - // 하수유입량 (청천시) 최소 - winterChungchunFlowMin = winterChungchunDayFlowMin; - // 총인반류수 (청천시) 최소 - winterChungchunReturnMin = winterChungchunDayReturnMin; - // 방류량 (청천시) 최소 - winterChungchunEfflMin = winterChungchunDayEfflMin - - operationalStatusList[0].yearAvg = roundUp(Number(operationalStatusList[0].yearAvg), 0) + roundUp(yearAvgSumFlow, 0); // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) - operationalStatusList[0].yearMax = roundUp(totFlowMax, 0); // 연간 유입 최대 - operationalStatusList[0].yearMin = roundUp(totFlowMin, 0); // 연간 유입 최소 - operationalStatusList[0].summerAll = roundUp(Number(operationalStatusList[0].summerAll), 0) + roundUp(summerAll, 0); // 하절기 유입 전기간 - operationalStatusList[0].summerThree = roundUp(Number(operationalStatusList[0].summerThree), 0) + roundUp(summerThree, 0); // 하절기 유입 강우시(강우영향일) - operationalStatusList[0].summerRain = roundUp(Number(operationalStatusList[0].summerRain), 0) + roundUp(summerRain, 0); // 하절기 유입 청천시 - operationalStatusList[0].winterAll = roundUp(Number(operationalStatusList[0].winterAll), 0) + roundUp(winterAll, 0); // 동절기 유입 전기간 - operationalStatusList[0].winterSunnyMin = roundUp(winterChungchunTotalInflAmntMin, 0); // 동절기 유입 최소 - operationalStatusList[0].winterSunnyMax = roundUp(winterChungchunTotalInflAmntMax, 0); // 동절기 유입 최대 - operationalStatusList[0].winterSunnyAvg = roundUp(Number(operationalStatusList[0].winterSunnyAvg), 0) + roundUp(winterSunnyAvg, 0); // 동절기 유입 평균 + // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) + operationalStatusList[0].yearAvg = roundUp(operList.inFlow.yearAvg, 0); // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) + operationalStatusList[0].yearMax = roundUp(operList.inFlow.yearMax, 0); // 연간 유입 최대 + operationalStatusList[0].yearMin = roundUp(operList.inFlow.yearMin, 0); // 연간 유입 최소 + operationalStatusList[0].summerAll = roundUp(operList.inFlow.summerAvg, 0); // 하절기 유입 전기간 + operationalStatusList[0].summerThree = roundUp(operList.inFlow.summerRainy, 0); // 하절기 유입 강우시(강우영향일) + operationalStatusList[0].summerRain = roundUp(operList.inFlow.summerSunny, 0); // 하절기 유입 청천시 + operationalStatusList[0].winterAll = roundUp(operList.inFlow.winterAvg, 0); // 동절기 유입 전기간 + operationalStatusList[0].winterSunnyMin = roundUp(operList.inFlow.winterSunnyMin, 0); // 동절기 유입 최소 + operationalStatusList[0].winterSunnyMax = roundUp(operList.inFlow.winterSunnyMax, 0); // 동절기 유입 최대 + operationalStatusList[0].winterSunnyAvg = roundUp(operList.inFlow.winterAvg, 0); // 동절기 유입 평균 // 지하수유입량 - const usage = chungcunSumFlow / cntSunnyDay; //calData.length; - const summerUsage = sumSummerChungcunFlow / summerChungchunDay; - const winterUsage = sumWinterChungcunFlow / winterChungchuDay; + const usage = operList.inflAmt.yearSunny / cntSunnyDay; // 연간 청천 순수하수 평균 + const summerUsage = operList.inflAmt.summerSunny; // 하절기 청천 순수하수 평균 + const winterUsage = operList.inflAmt.winterSunny; // 동절기 청천 순수하수 평균 // 임시 계산변수값들 메인에 대입 - summerChungchunFlow = summerUsage; - summerChungchunReturnAmnt = summerChungchunDayReturnAmnt / summerChungchunDay; - summerChungchunEfflAmnt = summerChungchunDayEfflAmnt / summerChungchunDay; - operationalStatusList[0].groundWaterAvg = Math.round((usage - (usage * 0.65 * OSU_PERCENT)) * 100) / 100; operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (summerUsage * 0.65 * OSU_PERCENT)) * 100) / 100; operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (winterUsage * 0.65 * OSU_PERCENT)) * 100) / 100; @@ -1676,20 +1685,20 @@ export const dashBoardReducer = ( const winterMonth = ['01', '02']; wqltDataTot.filter(item => summerMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { - if (Number(item2.infoRnDay) >= 3) { - const inflBod = Number(item2.inflAssctBfrWqltBod); - const infl = Number(item2.inflAmnt); - const rain = Number(item2.infoRnDay); + if (Number(item2.infoRnDay) >= 3) { // 3mm 이상 강우일 + const inflBod = Number(item2.inflAssctBfrWqltBod); //유입연계전수질_BOD(mg/L) + const infl = Number(item2.inflAmnt); //실제유입량(반류수제거)(m³/일) + const rain = Number(item2.infoRnDay); //강우량 if (inflBod < minSummerBod) { minSummerBodInfl = infl; minSummerBod = inflBod; - rdiRain = rain; + rdiRain = rain; // 하절기 최소 bod일때의 일강수량 } } }); wqltDataSunny.filter(item => winterMonth.includes(item.msrDt.toString().replaceAll('-', '').substring(4, 6))).forEach(item2 => { - winterBodSunny += Number(item2.inflAssctBfrWqltBod); + winterBodSunny += Number(item2.inflAssctBfrWqltBod); // 동절기 청천시 유입BOD(mg/L) winterCnt += 1; }); @@ -1705,132 +1714,56 @@ export const dashBoardReducer = ( rdiPercent = (rdiValue / minSummerBodInfl) * 100; - operationalStatusList[0].rdi = rdiValue; - operationalStatusList[0].rdiRain = rdiRain; + operationalStatusList[0].rdi = rdiValue; // RDII 추정 + operationalStatusList[0].rdiRain = rdiRain; // RDII 추정시 일강수량(mm) } - /* const summerLowFlow = data.summerBod&&data.summerBod.INFL_AMNT&&data.summerBod.INFL_AMNT!='null'?Number(data.summerBod.INFL_AMNT):0; - const winterAvgBod = data.winterSunny&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD&&data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.winterSunny.AVG_INFL_ASSCT_BFR_WQLT_BOD):0; - const summerLowBod = data.summerBod&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD&&data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD!='null'?Number(data.summerBod.MIN_INFL_ASSCT_BFR_WQLT_BOD):0; - const summerLowRain = data.summerBod&&data.summerBod.INFO_RN_DAY&&data.summerBod.INFO_RN_DAY!='null'?Number(data.summerBod.INFO_RN_DAY):0; - operationalStatusList[0].rdi = winterAvgBod===0?0:roundUp(summerLowFlow * ((winterAvgBod - summerLowBod) / winterAvgBod), 2); - operationalStatusList[0].rdiRain = summerLowRain; */ } if (operationalStatusList[0] && operationalStatusList[7]) { - operationalStatusList[7].groundWaterAvg = operationalStatusList[0].groundWaterAvg === null ? '' : data.yearData && data.yearData.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterAvg.toString().replaceAll(',', '')) / (data.yearData && data.yearData.AVG_INFL_AMNT ? Number(data.yearData.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; - operationalStatusList[7].groundWaterSummer = operationalStatusList[0].groundWaterSummer === null ? '' : data.summer && data.summer.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterSummer.toString().replaceAll(',', '')) / (data.summer && data.summer.AVG_INFL_AMNT ? Number(data.summer.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; - operationalStatusList[7].groundWaterWinter = operationalStatusList[0].groundWaterWinter === null ? '' : data.winter && data.winter.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterWinter.toString().replaceAll(',', '')) / (data.winter && data.winter.AVG_INFL_AMNT ? Number(data.winter.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + // operationalStatusList[7].groundWaterAvg = operationalStatusList[0].groundWaterAvg === null ? '' : operList.inFlow.yearTot && data.yearData.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterAvg.toString().replaceAll(',', '')) / (data.yearData && data.yearData.AVG_INFL_AMNT ? Number(data.yearData.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + // operationalStatusList[7].groundWaterSummer = operationalStatusList[0].groundWaterSummer === null ? '' : data.summer && data.summer.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterSummer.toString().replaceAll(',', '')) / (data.summer && data.summer.AVG_INFL_AMNT ? Number(data.summer.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + // operationalStatusList[7].groundWaterWinter = operationalStatusList[0].groundWaterWinter === null ? '' : data.winter && data.winter.AVG_INFL_AMNT === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterWinter.toString().replaceAll(',', '')) / (data.winter && data.winter.AVG_INFL_AMNT ? Number(data.winter.AVG_INFL_AMNT.toString().replaceAll(',', '')) : 0) * 100) * 10) / 10 + '%'; + operationalStatusList[7].groundWaterAvg = operList.inflAmt.yearAvg === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterAvg.toString().replaceAll(',', '')) / operList.inflAmt.yearAvg * 100) * 10) / 10 + '%'; + operationalStatusList[7].groundWaterSummer = operList.inflAmt.summerAvg === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterSummer.toString().replaceAll(',', '')) / operList.inflAmt.summerAvg * 100) * 10) / 10 + '%'; + operationalStatusList[7].groundWaterWinter = operList.inflAmt.winterAvg === 0 ? '' : Math.round((Number(operationalStatusList[0].groundWaterWinter.toString().replaceAll(',', '')) / operList.inflAmt.winterAvg * 100) * 10) / 10 + '%'; operationalStatusList[7].rdi = roundNumber(rdiPercent, 1) + '%'; - /* operationalStatusList[7].groundWaterAvg = operationalStatusList[0].groundWaterAvg === null ? '' : Number(Number(operationalStatusList[0].groundWaterAvg) / Number(data.yearData.AVG_INFL_AMNT)) * 100; - operationalStatusList[7].groundWaterSummer = operationalStatusList[0].groundWaterSummer === null ? '' : Number(Number(operationalStatusList[0].groundWaterSummer) / Number(data.summer.AVG_INFL_AMNT)) * 100; - operationalStatusList[7].groundWaterWinter = operationalStatusList[0].groundWaterWinter === null ? '' : Number(Number(operationalStatusList[0].groundWaterWinter) / Number(data.winter.AVG_INFL_AMNT)) * 100;*/ } - for (let i = 1; i < operationalStatusList.length; i++) { - const txtArray = ['1', 'INFL_AMNT', 'SUM_FLOW', 'RETURN_AMNT', 'EFFL_AMNT', 'INFL_ASSCT_BFR_WQLT_BOD', 'EFFL_WQLT_BOD', 'INFL_ASSCT_BFR_WQLT_TN', 'EFFL_WQLT_TN', 'INFL_ASSCT_BFR_WQLT_TP', 'EFFL_WQLT_TP', 'TP_INFL_WQLT_TP', 'EFFL_WQLT_TP']; - if (operationalStatusList[i]) { - if (i < 7) { - changeValue(operationalStatusList[i], data, txtArray[i]); - if (i < 5) { - dataFormSetting(operationalStatusList[i]!); - } else { - dataFormSettingWqlty(operationalStatusList[i]!); - } - - } else { - calcValue(operationalStatusList[i], data, txtArray[i]); - } + // 순수하수량(1), 연계처리수(2), 총인설비방류수(3), 방류수(4) 데이터 매핑 + const flowMappings = [ + { index: 0, source: operList.inFlow }, + { index: 1, source: operList.inflAmt }, + { index: 2, source: operList.sumFlow }, + { index: 3, source: operList.returnFlow }, + { index: 4, source: operList.efflFlow }, + ]; + flowMappings.forEach(({ index, source }) => { + const item = operationalStatusList[index]; + if (item) { + item.yearAvg = source.yearAvg; + item.yearMax = source.yearMax; + item.yearMin = source.yearMin; + item.summerAll = source.summerAvg; + item.summerThree = source.summerRainy; + item.summerRain = source.summerSunny; + item.winterSunnyAvg = source.winterSunny; + item.winterSunnyMax = source.winterSunnyMax; + item.winterSunnyMin = source.winterSunnyMin; + item.winterAll = source.winterAvg; + dataFormSetting(item); } - } + }); - // 순수하수량 - if (operationalStatusList[1]) { - operationalStatusList[1].summerThree = summerRainInflAmnt; - operationalStatusList[1].summerRain = summerChungchunFlow; - operationalStatusList[1].winterSunnyAvg = winterChungchunFlowAvg; - operationalStatusList[1].winterSunnyMax = winterChungchunFlowMax; - operationalStatusList[1].winterSunnyMin = winterChungchunFlowMin; - dataFormSetting(operationalStatusList[1]); - } - - // 연계처리수 - if (operationalStatusList[2]) { - operationalStatusList[2].yearAvg = yearAvgSumFlow; - operationalStatusList[2].yearMax = yearMaxSumFlow; - operationalStatusList[2].yearMin = yearMinSumFlow; - operationalStatusList[2].summerAll = summerAll; - operationalStatusList[2].summerThree = summerThree; - operationalStatusList[2].summerRain = summerRain; - operationalStatusList[2].winterAll = winterAll; - operationalStatusList[2].winterSunnyMin = winterSunnyMin; - operationalStatusList[2].winterSunnyAvg = winterSunnyAvg; - operationalStatusList[2].winterSunnyMax = winterSunnyMax; - dataFormSetting(operationalStatusList[2]); - } - - // 총인설비방류수 - if (operationalStatusList[3]) { - operationalStatusList[3].summerThree = summerRainReturnAmnt; - operationalStatusList[3].summerRain = summerChungchunReturnAmnt; - operationalStatusList[3].winterSunnyAvg = winterChungchunReturnAvg; - operationalStatusList[3].winterSunnyMax = winterChungchunReturnMax; - operationalStatusList[3].winterSunnyMin = winterChungchunReturnMin; - dataFormSetting(operationalStatusList[3]); - } - - // 방류수 - if (operationalStatusList[4]) { - operationalStatusList[4].summerThree = summerRainEfflAmnt; - operationalStatusList[4].summerRain = summerChungchunEfflAmnt; - operationalStatusList[4].winterSunnyAvg = winterChungchunEfflAvg; - operationalStatusList[4].winterSunnyMax = winterChungchunEfflMax; - operationalStatusList[4].winterSunnyMin = winterChungchunEfflMin; - dataFormSetting(operationalStatusList[4]); - } - - if (operationalStatusList[0]) { - // 안전하게 숫자 변환하는 함수 - const toNum = (val) => { - if (val === null || val === undefined || val === '' || val === '0') return 0; - return Number(val.toString().replaceAll(',', '')) || 0; - }; - - operationalStatusList[0].summerAll = - toNum(operationalStatusList[1]?.summerAll) + - toNum(operationalStatusList[2]?.summerAll) + - toNum(operationalStatusList[3]?.summerAll); - - operationalStatusList[0].summerThree = - toNum(operationalStatusList[1]?.summerThree) + - toNum(operationalStatusList[2]?.summerThree) + - toNum(operationalStatusList[3]?.summerThree); - - operationalStatusList[0].summerRain = - toNum(operationalStatusList[1]?.summerRain) + - toNum(operationalStatusList[2]?.summerRain) + - toNum(operationalStatusList[3]?.summerRain); - - operationalStatusList[0].winterAll = - toNum(operationalStatusList[1]?.winterAll) + - toNum(operationalStatusList[2]?.winterAll) + - toNum(operationalStatusList[3]?.winterAll); - - operationalStatusList[0].winterSunnyAvg = - toNum(operationalStatusList[1]?.winterSunnyAvg) + - toNum(operationalStatusList[2]?.winterSunnyAvg) + - toNum(operationalStatusList[3]?.winterSunnyAvg); - - dataFormSetting(operationalStatusList[0]); - } } const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd, mainGraphData); // 수질 데이터 청천시, 강우시 재계산 // 총인설비가 없을 경우 제외 - // console.log('총인시설 여부 : ', data.yearData?.TP_FCT_YN); + console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.tpFctYn); + const tpFctYn = mainGraphData.data.wqltObjs?.tpFctYn; // console.log('rtnData : ', rtnData); - if (data.yearData?.TP_FCT_YN !== 'Y') { + if (tpFctYn !== 'Y') { operationalStatusList = rtnData.slice(0, 11); } else { operationalStatusList = rtnData; @@ -1840,7 +1773,7 @@ export const dashBoardReducer = ( OperationStatus: { ...state.OperationStatus, operationalStatusList: operationalStatusList, - operationalStatusCount: res.count, + operationalStatusCount: 0, isLoadingOperationStatus: false, }, })) From b57858c5efce9734de32ca8edac9465e349c1f41 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Wed, 7 Jan 2026 11:15:43 +0900 Subject: [PATCH 33/92] =?UTF-8?q?fo:=20=EC=B4=9D=EC=9D=B8=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=EC=97=AC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 133 ++++++++++++++------------ 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 09097d6e4..0e7dc8597 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -749,14 +749,14 @@ const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | // 수질 데이터 청천시, 강우시 재계산 const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fcltyCd: string | undefined, mainGraphData: any) => { - const operList = { - inflBod: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입BOD - inflTN: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입TN - inflTP: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 유입TP - efflBod: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류BOD - efflTN: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류TN - efflTP: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, // 방류TP - tpInflTp: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999}, //총인 유입수질 TP(mg/L) + const operList = { + inflBod: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 유입BOD + inflTN: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 유입TN + inflTP: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 유입TP + efflBod: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 방류BOD + efflTN: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 방류TN + efflTP: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, // 방류TP + tpInflTp: { yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 }, //총인 유입수질 TP(mg/L) }; const nullToZero = (value: any) => { return value === null || value === undefined || value === '' ? 0 : Number(value); @@ -962,11 +962,11 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc operList.tpInflTp.yearAvg = operList.tpInflTp.yearTot / totalDay; orgData[5].yearAvg = qltyDataSetting(operList.inflBod.yearTot, totalDay, 1); // 연간 유입BOD - orgData[6].yearAvg = qltyDataSetting(operList.efflBod.yearTot,totalDay, 1); // 연간 방류BOD - orgData[7].yearAvg = qltyDataSetting(operList.inflTN.yearTot,totalDay, 3); // 연간 유입TN - orgData[8].yearAvg = qltyDataSetting(operList.efflTN.yearTot,totalDay, 3); // 연간 방류TN - orgData[9].yearAvg = qltyDataSetting(operList.inflTP.yearTot,totalDay, 3); // 연간 유입TP - orgData[10].yearAvg = qltyDataSetting(operList.efflTP.yearTot,totalDay, 3); // 연간 방류TP + orgData[6].yearAvg = qltyDataSetting(operList.efflBod.yearTot, totalDay, 1); // 연간 방류BOD + orgData[7].yearAvg = qltyDataSetting(operList.inflTN.yearTot, totalDay, 3); // 연간 유입TN + orgData[8].yearAvg = qltyDataSetting(operList.efflTN.yearTot, totalDay, 3); // 연간 방류TN + orgData[9].yearAvg = qltyDataSetting(operList.inflTP.yearTot, totalDay, 3); // 연간 유입TP + orgData[10].yearAvg = qltyDataSetting(operList.efflTP.yearTot, totalDay, 3); // 연간 방류TP //총인설비 orgData[11].yearAvg = qltyDataSetting(operList.tpInflTp.yearTot, noNullYearDay, 3); // 연간 총인 유입수질 TP orgData[12].yearAvg = qltyDataSetting(operList.efflTP.yearTot, totalDay, 3); // 연간 총인 유입수질 TP @@ -1060,7 +1060,7 @@ const calcWaterQltyData = async (data: any[], searchYear: string | undefined, fc orgData[11].winterSunnyMin = chungchunTpInflMin === 99999999 ? '0.000' : roundUp(chungchunTpInflMin, 3).toFixed(3); orgData[12].winterSunnyMin = chungchunEfflTpMin === 99999999 ? '0.000' : roundUp(chungchunEfflTpMin, 3).toFixed(3); - + return orgData; } else { @@ -1463,27 +1463,37 @@ export const dashBoardReducer = ( // const res = await fetchOperationStatus(searchYear, fcltyCd); // /dashBoard/mngInfo/ // const data = res.data; - const operList = { - inFlow : {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + const operList = { + inFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - inflAmt: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999, yearSunny: 0 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + inflAmt: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999, yearSunny: 0 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - sumFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + sumFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - returnFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + returnFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, - efflFlow: {yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, + efflFlow: { + yearTot: 0, yearAvg: 0, yearMax: 0, yearMin: 9999999 , summerTot: 0, summerAvg: 0, summerRainy: 0, summerSunny: 0 , winterTot: 0, winterAvg: 0, winterSunny: 0, winterSunnyMax: 0, winterSunnyMin: 9999999 - , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0}, + , groundTot: 0, groundSummer: 0, groundWinter: 0, rdii: 0, rdiiRainAmt: 0 + }, }; const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? []; @@ -1492,11 +1502,11 @@ export const dashBoardReducer = ( if (operationalStatusList) { // 유량 - 유입 if (operationalStatusList?.[0]) { - + // 연계처리수 let yearDay = 0, summerDay = 0, winterDay = 0; // 연간 일수, 하절기 일수, 동절기 일수 let summerRainDay = 0, summerChungchunDay = 0, winterChungchuDay = 0; // 하절기 강우 일수, 하절기 청천 일수, 동절기 청천 일수 - + // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 @@ -1506,7 +1516,7 @@ export const dashBoardReducer = ( let cntSunnyDay = 0; // 청천일 수 // let chungcunSumFlow = 0; // 연간 청천 순수하수 - + let rainEffectDay = 0; yearDay = res2.data ? res2.data.length : 1; res2.data.forEach((item: any) => { // --일별 유량 start @@ -1516,7 +1526,7 @@ export const dashBoardReducer = ( const inflAmnt = item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0; const returnAmnt = item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0; const efflAmnt = item.efflAmnt && item.efflAmnt !== 'x' ? Number(item.efflAmnt.toString().trim()) : 0; - + if (item.infoRnDay == null) item.infoRnDay = 0; if (item.infoRnDay >= 3) { rainEffectDay = 2; @@ -1608,41 +1618,41 @@ export const dashBoardReducer = ( }); // --일별 유량 end // 연간 평균 - operList.inFlow.yearAvg = (yearDay > 0)? operList.inFlow.yearTot / yearDay : 0; - operList.inflAmt.yearAvg = (yearDay > 0)? operList.inflAmt.yearTot / yearDay : 0; - operList.sumFlow.yearAvg = (yearDay > 0)? operList.sumFlow.yearTot / yearDay : 0; - operList.returnFlow.yearAvg = (yearDay > 0)? operList.returnFlow.yearTot / yearDay : 0; - operList.efflFlow.yearAvg = (yearDay > 0)? operList.efflFlow.yearTot / yearDay : 0; + operList.inFlow.yearAvg = (yearDay > 0) ? operList.inFlow.yearTot / yearDay : 0; + operList.inflAmt.yearAvg = (yearDay > 0) ? operList.inflAmt.yearTot / yearDay : 0; + operList.sumFlow.yearAvg = (yearDay > 0) ? operList.sumFlow.yearTot / yearDay : 0; + operList.returnFlow.yearAvg = (yearDay > 0) ? operList.returnFlow.yearTot / yearDay : 0; + operList.efflFlow.yearAvg = (yearDay > 0) ? operList.efflFlow.yearTot / yearDay : 0; // 하절기 전기간 평균 - operList.inFlow.summerAvg = (summerDay > 0)? operList.inFlow.summerTot / summerDay : 0; - operList.inflAmt.summerAvg = (summerDay > 0)? operList.inflAmt.summerTot / summerDay : 0; - operList.sumFlow.summerAvg = (summerDay > 0)? operList.sumFlow.summerTot / summerDay : 0; - operList.returnFlow.summerAvg = (summerDay > 0)? operList.returnFlow.summerTot / summerDay : 0; - operList.efflFlow.summerAvg = (summerDay > 0)? operList.efflFlow.summerTot / summerDay : 0; + operList.inFlow.summerAvg = (summerDay > 0) ? operList.inFlow.summerTot / summerDay : 0; + operList.inflAmt.summerAvg = (summerDay > 0) ? operList.inflAmt.summerTot / summerDay : 0; + operList.sumFlow.summerAvg = (summerDay > 0) ? operList.sumFlow.summerTot / summerDay : 0; + operList.returnFlow.summerAvg = (summerDay > 0) ? operList.returnFlow.summerTot / summerDay : 0; + operList.efflFlow.summerAvg = (summerDay > 0) ? operList.efflFlow.summerTot / summerDay : 0; // 하절기 강우시 평균 - operList.inFlow.summerRainy = (summerRainDay > 0)? operList.inFlow.summerRainy / summerRainDay : 0; - operList.inflAmt.summerRainy = (summerRainDay > 0)? operList.inflAmt.summerRainy / summerRainDay : 0; - operList.sumFlow.summerRainy = (summerRainDay > 0)? operList.sumFlow.summerRainy / summerRainDay : 0; - operList.returnFlow.summerRainy = (summerRainDay > 0)? operList.returnFlow.summerRainy / summerRainDay : 0; - operList.efflFlow.summerRainy = (summerRainDay > 0)? operList.efflFlow.summerRainy / summerRainDay : 0; + operList.inFlow.summerRainy = (summerRainDay > 0) ? operList.inFlow.summerRainy / summerRainDay : 0; + operList.inflAmt.summerRainy = (summerRainDay > 0) ? operList.inflAmt.summerRainy / summerRainDay : 0; + operList.sumFlow.summerRainy = (summerRainDay > 0) ? operList.sumFlow.summerRainy / summerRainDay : 0; + operList.returnFlow.summerRainy = (summerRainDay > 0) ? operList.returnFlow.summerRainy / summerRainDay : 0; + operList.efflFlow.summerRainy = (summerRainDay > 0) ? operList.efflFlow.summerRainy / summerRainDay : 0; // 하절기 청천시 평균 - operList.inFlow.summerSunny = (summerChungchunDay > 0)? operList.inFlow.summerSunny / summerChungchunDay : 0; - operList.inflAmt.summerSunny = (summerChungchunDay > 0)? operList.inflAmt.summerSunny / summerChungchunDay : 0; - operList.sumFlow.summerSunny = (summerChungchunDay > 0)? operList.sumFlow.summerSunny / summerChungchunDay : 0; - operList.returnFlow.summerSunny = (summerChungchunDay > 0)? operList.returnFlow.summerSunny / summerChungchunDay : 0; - operList.efflFlow.summerSunny = (summerChungchunDay > 0)? operList.efflFlow.summerSunny / summerChungchunDay : 0; + operList.inFlow.summerSunny = (summerChungchunDay > 0) ? operList.inFlow.summerSunny / summerChungchunDay : 0; + operList.inflAmt.summerSunny = (summerChungchunDay > 0) ? operList.inflAmt.summerSunny / summerChungchunDay : 0; + operList.sumFlow.summerSunny = (summerChungchunDay > 0) ? operList.sumFlow.summerSunny / summerChungchunDay : 0; + operList.returnFlow.summerSunny = (summerChungchunDay > 0) ? operList.returnFlow.summerSunny / summerChungchunDay : 0; + operList.efflFlow.summerSunny = (summerChungchunDay > 0) ? operList.efflFlow.summerSunny / summerChungchunDay : 0; // 동절기 전기간 평균 - operList.inFlow.winterAvg = (winterDay > 0)? operList.inFlow.winterTot / winterDay : 0; - operList.inflAmt.winterAvg = (winterDay > 0)? operList.inflAmt.winterTot / winterDay : 0; - operList.sumFlow.winterAvg = (winterDay > 0)? operList.sumFlow.winterTot / winterDay : 0; - operList.returnFlow.winterAvg = (winterDay > 0)? operList.returnFlow.winterTot / winterDay : 0; - operList.efflFlow.winterAvg = (winterDay > 0)? operList.efflFlow.winterTot / winterDay : 0; + operList.inFlow.winterAvg = (winterDay > 0) ? operList.inFlow.winterTot / winterDay : 0; + operList.inflAmt.winterAvg = (winterDay > 0) ? operList.inflAmt.winterTot / winterDay : 0; + operList.sumFlow.winterAvg = (winterDay > 0) ? operList.sumFlow.winterTot / winterDay : 0; + operList.returnFlow.winterAvg = (winterDay > 0) ? operList.returnFlow.winterTot / winterDay : 0; + operList.efflFlow.winterAvg = (winterDay > 0) ? operList.efflFlow.winterTot / winterDay : 0; // 동절기 청천시 평균 - operList.inFlow.winterSunny = (winterChungchuDay > 0)? operList.inFlow.winterSunny / winterChungchuDay : 0; - operList.inflAmt.winterSunny = (winterChungchuDay > 0)? operList.inflAmt.winterSunny / winterChungchuDay : 0; - operList.sumFlow.winterSunny = (winterChungchuDay > 0)? operList.sumFlow.winterSunny / winterChungchuDay : 0; - operList.returnFlow.winterSunny = (winterChungchuDay > 0)? operList.returnFlow.winterSunny / winterChungchuDay : 0; - operList.efflFlow.winterSunny = (winterChungchuDay > 0)? operList.efflFlow.winterSunny / winterChungchuDay : 0; + operList.inFlow.winterSunny = (winterChungchuDay > 0) ? operList.inFlow.winterSunny / winterChungchuDay : 0; + operList.inflAmt.winterSunny = (winterChungchuDay > 0) ? operList.inflAmt.winterSunny / winterChungchuDay : 0; + operList.sumFlow.winterSunny = (winterChungchuDay > 0) ? operList.sumFlow.winterSunny / winterChungchuDay : 0; + operList.returnFlow.winterSunny = (winterChungchuDay > 0) ? operList.returnFlow.winterSunny / winterChungchuDay : 0; + operList.efflFlow.winterSunny = (winterChungchuDay > 0) ? operList.efflFlow.winterSunny / winterChungchuDay : 0; // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) operationalStatusList[0].yearAvg = roundUp(operList.inFlow.yearAvg, 0); // 연간 유입 평균 = 하수유입량(순수하수유입량) + 연계처리량 + 반류수유량(m³/일) @@ -1759,8 +1769,9 @@ export const dashBoardReducer = ( const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd, mainGraphData); // 수질 데이터 청천시, 강우시 재계산 // 총인설비가 없을 경우 제외 - console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.tpFctYn); - const tpFctYn = mainGraphData.data.wqltObjs?.tpFctYn; + console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.[0].tpFctYn); + + const tpFctYn = mainGraphData.data.wqltObjs?.[0].tpFctYn; // console.log('rtnData : ', rtnData); if (tpFctYn !== 'Y') { From 9b1342b2030041541fa4317364201edf80bb8ffc Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Wed, 7 Jan 2026 21:46:16 +0900 Subject: [PATCH 34/92] =?UTF-8?q?fo:=20=EC=B2=98=EB=A6=AC=EA=B5=AC?= =?UTF-8?q?=EC=97=AD=EC=A0=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/processArea/page.tsx | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 91bdb6ab0..adad3ea67 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -6,6 +6,7 @@ "use client" import { useFoStore } from "@/app/store"; +import { useShallow } from 'zustand/react/shallow'; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useEffect, useRef, useState } from "react"; @@ -13,19 +14,22 @@ import ProcessFacilityInfoModal from "./modal/page"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; export default function ProcessArea() { - const {Common, + const { + Common, ProcessArea, ProcessAreaSearch, initializeCommonData, searchProcessAreaList - } = useFoStore((state) => state) || { - Common: { isInit: false, selectSidoData: [], selectSigunData: [], selectRegionData: [], selectUnitWaterShedData: [], selectMiddleRegionData: [], selectEnvPartData: [], selectSearchYear: [{ val: "0" }], btnClass: "" }, - ProcessArea: { processAreaList: [], processAreaCount: 0, excelList: [], upHeadList1: [] }, - ProcessAreaSearch: { processFacilityLabelArray: [] }, - initializeCommonData: () => {}, - searchProcessAreaList: () => {} - }; - + } = useFoStore( + useShallow((state) => ({ // 다른 무관한 상태가 변경되어도 이 컴포넌트는 불필요하게 다시 렌더링 되지 않음. + Common: state.Common, + ProcessArea: state.ProcessArea, + ProcessAreaSearch: state.ProcessAreaSearch, + initializeCommonData: state.initializeCommonData, + searchProcessAreaList: state.searchProcessAreaList, + })) + ); + const { isInit, selectSidoData, @@ -37,7 +41,7 @@ export default function ProcessArea() { selectSearchYear, btnClass, } = Common; - + const { processFacilityLabelArray, } = ProcessAreaSearch; @@ -54,11 +58,11 @@ export default function ProcessArea() { // 그리드 관련 const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); - // 모달 상태 추가 + // 모달 상태 추가 const [selectedRow, setSelectedRow] = useState<number | null>(null); const [fcltyNm, setFcltyNm] = useState<string>(""); const [fcltyCd, setFcltyCd] = useState<string>(""); - + const [resetPage, setResetPage] = useState<boolean>(false); const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); @@ -74,7 +78,7 @@ export default function ProcessArea() { sigunText: '', }); - const searchProcessArea = useCallback(({ sidoText, sigunText}: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchProcessArea = useCallback(({ sidoText, sigunText }: ReturnType, pageNo: number, pageCnt: number = 20) => { searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue); }, [searchProcessAreaList, searchYearValue]); @@ -118,11 +122,11 @@ export default function ProcessArea() { useEffect(() => { if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '처리구역정보', - sheetNameArray: ['처리구역정보'], - headerRange: 'A1:W1' + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '처리구역정보', + sheetNameArray: ['처리구역정보'], + headerRange: 'A1:W1' }); } }, [excelList]); @@ -143,7 +147,7 @@ export default function ProcessArea() { <ContentsDiv> <SearchBaseForm leftChildren={<> - <SelectBox className="col-span-3" label={processFacilityLabelArray[6] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined}/> + <SelectBox className="col-span-3" label={processFacilityLabelArray[6] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYearValue(val.toString())} value={searchYearValue} selectClass={undefined} /> </>} rightChildren={undefined} selectSidoData={selectSidoData} @@ -169,8 +173,8 @@ export default function ProcessArea() { </ListDiv> </ContentsDiv> {selectedRow !== null && ( - <UiModal - body={<ProcessFacilityInfoModal fcltyName={fcltyNm} facilityCd={fcltyCd}></ProcessFacilityInfoModal>} + <UiModal + body={<ProcessFacilityInfoModal fcltyName={fcltyNm} facilityCd={fcltyCd}></ProcessFacilityInfoModal>} bodyClass="sm:max-w-[90vw] w-[1200px] h-[900px]" open={selectedRow !== null} onOpenChange={(open: boolean) => !open && closeModal()} From 5b76d02e0b9bee53ce65eb5453934087a445d064 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Thu, 8 Jan 2026 13:57:29 +0900 Subject: [PATCH 35/92] =?UTF-8?q?fo:=20=EA=B0=95=EC=88=98=ED=98=84?= =?UTF-8?q?=ED=99=A9=20excel=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/components/common/DataForm.tsx | 9 +++++-- .../facilityPrecipitation/modal/page.tsx | 27 +++++++++++-------- .../src/ui/excel/index.tsx | 10 +++++++ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/fo/app/components/common/DataForm.tsx b/apps/fo/app/components/common/DataForm.tsx index 48b428e32..d9e78c268 100644 --- a/apps/fo/app/components/common/DataForm.tsx +++ b/apps/fo/app/components/common/DataForm.tsx @@ -7,9 +7,14 @@ export const roundNumber = (value : any, decimals: number) => { if (typeof value === 'number') { return addCommas((Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)).toFixed(decimals)); - } else if (typeof value === 'string' && !isNaN(Number(value))) { - return addCommas(Number(value).toFixed(decimals)); + } else if (typeof value === 'string') { + // 콤마가 포함된 문자열 처리 ('1,083.0' 같은 경우) + const cleanedValue = value.replace(/,/g, ''); + if (!isNaN(Number(cleanedValue))) { + return addCommas(Number(cleanedValue).toFixed(decimals)); + } } + return value; // 변환 불가능한 경우 원래 값 반환 } export const addCommas = (value: string | number): any => { diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx index 1bd8a6c89..061d1738d 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx @@ -9,7 +9,7 @@ import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { roundNumber } from "@/app/components/common/DataForm"; import { useFoStore } from "@/app/store"; import type { PrecipitationPropsDetailProps } from "@/app/store/facilityPrecipitation"; -import { DatePickerRange, downloadExcel, UiTable } from "@common/business_components/ui"; +import { DatePickerRange, downloadExcelHeaders, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui"; import { useEffect, useRef, useState } from "react"; @@ -45,7 +45,7 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { const standYear = parseInt(props.searchYear); return [{ start: new Date(standYear, 0, 1), - end: new Date(standYear, 11, 31) + end: new Date(standYear, 11, 31) //월의 index는 0부터 시작 }]; }; @@ -112,7 +112,6 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { const getTableData = () => { const totals = calculateTotals(); totals.infoRnDay = roundNumber(totals.infoRnDay, 1); - return [ { bscFctCd: "", @@ -157,19 +156,25 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { const excelDownload = () => { const totData = getTableData(); - const excelDownList: any[] = []; + + // 헤더 순서를 명시적으로 정의 + const headers = ["날짜", "강수량(mm/일)", "강우일(일)", "강우영향일(일)"] as const; + + const excelDownList: Record<string, string | number>[] = []; if(totData.length > 0){ totData.forEach((item) => { - excelDownList.push({ - "날짜": item.rainDt, - "강수량(mm/일)": roundNumber(item.infoRnDay, 1), - "강우일(일)": roundNumber(item.rainDay, 0), - "강우영향일(일)": roundNumber(item.rainEffectDay, 0), - }); + // 순서를 보장하기 위해 헤더 순서대로 객체 생성 + const row: Record<string, string | number> = {}; + row[headers[0]] = item.rainDt; + row[headers[1]] = roundNumber(item.infoRnDay, 1); + row[headers[2]] = roundNumber(item.rainDay, 0); + row[headers[3]] = roundNumber(item.rainEffectDay, 0); + excelDownList.push(row); }); } + if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황', sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1' }); + downloadExcelHeaders({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황', sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1' }); } else if (totData.length == 0) { alert('다운받을 데이터가 없습니다.'); } diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index aedb32256..0b2659b69 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -6,6 +6,7 @@ type ExcelDownloadProps = { fileName: string; sheetNameArray: string[]; headerRange?: string; + headers?: string[]|undefined; decimalArray0? : number[]; decimalArray1? : number[]; decimalArray2? : number[]; @@ -19,6 +20,15 @@ export const downloadExcel = ({ data, fileName = new Date().getTime().toString() excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); }; +export const downloadExcelHeaders = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', headers}: ExcelDownloadProps) => { + const dataArray = Array.isArray(data) ? data : [data]; + // headers가 제공되면 열 순서를 강제함 + const worksheet = XLSX.utils.json_to_sheet(dataArray, headers ? { header: headers } : undefined); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); + excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); +}; + export const downloadExcelFormat = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', decimalArray0=[], decimalArray1=[], decimalArray2=[], decimalArray3=[]}: ExcelDownloadProps) => { const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]); const workbook = XLSX.utils.book_new(); From 295247845c2a5c2572796fd35930e03dd9edd032 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Thu, 8 Jan 2026 17:58:38 +0900 Subject: [PATCH 36/92] =?UTF-8?q?fo:=20=EC=A7=80=ED=95=98=EC=88=98?= =?UTF-8?q?=EC=9C=A0=EC=9E=85=EB=9F=89=20=EC=B5=9C=EB=8C=80,=20=EC=B5=9C?= =?UTF-8?q?=EC=86=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/components/common/DataForm.tsx | 22 +++ .../pages/(with-layout)/processArea/page.tsx | 2 +- .../(with-layout)/processFacility/page.tsx | 2 +- .../pages/(with-layout)/sewageOccur/page.tsx | 2 +- .../(with-layout)/underWaterInput/page.tsx | 2 +- apps/fo/app/store/dashboard/index.tsx | 34 +++-- apps/fo/app/store/sewageOccur/index.tsx | 133 ++++-------------- apps/fo/app/store/underWaterInput/index.tsx | 49 ++----- 8 files changed, 86 insertions(+), 160 deletions(-) diff --git a/apps/fo/app/components/common/DataForm.tsx b/apps/fo/app/components/common/DataForm.tsx index d9e78c268..b58322458 100644 --- a/apps/fo/app/components/common/DataForm.tsx +++ b/apps/fo/app/components/common/DataForm.tsx @@ -4,6 +4,28 @@ item: Record<string, unknown>; } +/** + * yyyymm 형태의 문자열을 받아 해당 월의 일수를 반환 + * @param {string} yyyymm - 예: "202502", "202412" + * @returns {number} 해당 월의 일수 (예: 28, 29, 30, 31) + */ +export const getDaysInMonth = (yyyymm: string) => { + if (typeof yyyymm !== 'string' || yyyymm.length !== 6) { + throw new Error("입력은 'yyyymm' 형식의 문자열이어야 합니다. 예: '202502'"); + } + + const year = parseInt(yyyymm.slice(0, 4), 10); // "2025" -> 2025 + const month = parseInt(yyyymm.slice(4, 6), 10); // "02" -> 2 + + if (isNaN(year) || isNaN(month) || month < 1 || month > 12) { + throw new Error("유효한 년/월이 아닙니다."); + } + + // Date(year, month, 0) -> 전달의 마지막 날 + // month에 '다음달'을 넣고, 일(day)에 0을 주면 해당 월의 마지막 날짜가 됨 + return new Date(year, month, 0).getDate(); +} + export const roundNumber = (value : any, decimals: number) => { if (typeof value === 'number') { return addCommas((Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)).toFixed(decimals)); diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index adad3ea67..009d72c9f 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -175,7 +175,7 @@ export default function ProcessArea() { {selectedRow !== null && ( <UiModal body={<ProcessFacilityInfoModal fcltyName={fcltyNm} facilityCd={fcltyCd}></ProcessFacilityInfoModal>} - bodyClass="sm:max-w-[90vw] w-[1200px] h-[900px]" + bodyClass="sm:max-w-[90vw] w-[1200px] h-[100dvh] max-h-[900px] overflow-y-auto" open={selectedRow !== null} onOpenChange={(open: boolean) => !open && closeModal()} /> diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 856ab4631..9c3c612b5 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -292,7 +292,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( <UiModal body={<ProcessFacilityInfoModal fcltyName={modalFcltyNm} facilityCd={modalFcltyCd} sido={modalSido} gugun={modalGugun} daddr={modalAddr} fctCpc={modalFctCpc} trtFrfNm={modalTrtFrfNm} rnDt={modalRnDt} cmplDt={modalCmplDt} trstOprEtpNm={modalTrstOprEtpNm} bscFctClsNm={modalBscFctClsNm} mnstr={modalMnstr} efflWtrrgn={modalEfflWtrrgn} lgbsn={modalLgbsn} efflWqltStndrdNm={modalEfflWqltStndrdNm} rgnNm={modalRgnNm} rvbsn={modalRvbsn}></ProcessFacilityInfoModal>} - bodyClass="sm:max-w-[70vw] sm:max-h-[95vh]" + bodyClass="sm:max-w-[70vw] h-[100dvh] max-h-[800px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} /> diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index 001e816ae..31862e362 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -250,7 +250,7 @@ export default function PlanSewage() { facilityCd={fcltyCd} searchYear={searchYear} />} - bodyClass="sm:max-w-[90vw] w-[1000px] h-[770px]" + bodyClass="sm:max-w-[90vw] w-[1000px] h-[100dvh] max-h-[770px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} noHeaderYn="Y" diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 47e9ec912..a2ad7bfd6 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -251,7 +251,7 @@ export default function UnderWaterInput() { {selectedRow !== null && ( <UiModal body={<UnderWaterInputModal fcltyCd={fcltyCd} fcltyName={fcltyNm} searchYear={searchYear}></UnderWaterInputModal>} - bodyClass="sm:max-w-[90vw] w-[1000px] h-[770px]" + bodyClass="sm:max-w-[90vw] w-[1000px] h-[100dvh] max-h-[770px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} noHeaderYn="Y" diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 0e7dc8597..94c0ab78e 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -2,9 +2,10 @@ * Store - 타입 */ -import { getFetch } from "@/app/components/api"; +import { getFetch, postFetch } from "@/app/components/api"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import DataForm, { roundNumber } from "@/app/components/common/DataForm"; +import { getDaysInMonth } from "@/app/components/common/DataForm"; import { fetchPlanInfo, OSU_PERCENT, qltyDataSetting, roundUp } from "../common"; import { type FacilityWaterQltyProps } from "../facilityWaterQlty"; import { fetchFlowRateModalList } from "../flowRate"; @@ -216,6 +217,11 @@ export interface DrainageEquipmentExcelType { stepFourSep: number | '', } +type WtrUsgYmProps = { + bscFctCd : string, // 처리구역시설코드 + levyYm : string, // 부과년월 + wtrUsg : number, // 월별 물사용량(m³/월) +} /** * Store - data */ @@ -722,17 +728,16 @@ const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string } }; -/* 시설정보 및 운영현황 - 운영실태 */ -// const fetchOperationStatus = async (searchYear: string | undefined, fcltyCd: string | undefined): Promise<ApiRes> => { -// try { -// const url = '/dashBoard/mngInfo/' + (searchYear ? searchYear : '2023') + '/' + (fcltyCd ? fcltyCd : ''); -// const res = await getFetch('fo', url); -// return { data: res.data, count: res.count } -// } catch (error) { -// console.error('운영실태 데이터를 가져오는데 실패했습니다:', error); -// return { data: [], count: 0 }; -// } -// } +// 시설들 월별 물사용량 정보 조회 +const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { + try { + const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/'+searchYear, fcltCdList); + return res; + } catch (error) { + console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); + return null; + } +}; // 주요그래프 데이터 const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | undefined) => { @@ -1460,8 +1465,9 @@ export const dashBoardReducer = ( isLoadingOperationStatus: true, }, })); - // const res = await fetchOperationStatus(searchYear, fcltyCd); // /dashBoard/mngInfo/ - // const data = res.data; + + const fcltCdList = [fcltyCd]; + const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 const operList = { inFlow: { diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx index e9857af71..becb5016b 100644 --- a/apps/fo/app/store/sewageOccur/index.tsx +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -29,7 +29,7 @@ export type SewageOccurProps = { mdmbsn: string, msrDt: string, } -export type modalTableType = { msrDt: string, waterUsage: number, swageChangePercent: number, estimationSewage: number }; +export type modalTableType = { msrDt: string, waterUsage: number, swageChangePercent: number, estimationSewage: number, } export type SewageOccurDetailProps = { cnt: number, sum: number, @@ -39,6 +39,8 @@ export type SewageOccurDetailProps = { sumWtrUsg: number, // 물사용량 합 avgWtrUsg: number, // 일평균 물사용량 monWtrUsg: number, // 월 물사용량 + maxEstSewerage: number, // 최대 오수발생량 추정 + minEstSewerage: number, // 최소 오수발생량 추정 } export type WtrUsgYmProps = { bscFctCd: string, // 처리구역시설코드 @@ -332,6 +334,7 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = // wtrUsgRes.data.forEach(fclt => { // wtrUsgMap[fclt.bscFctCd] = fclt.wtrUsg; // }); + let maxEstimationSewage = 0, minEstimationSewage = 999999999; for (const item of sewageOccurPropsList) { const detailList = soccurDetailRes?.data[item.bscFctCd]; @@ -368,17 +371,15 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = // console.log("totWaterUsage:", totWaterUsage); const count = detailList ? detailList.length : 0; const avg = count == 0 ? 0 : totWaterUsage / count; // 일평균 유입량 - item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); // 물사용량 = 일평균 유입량 * 65% + item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); // 물사용량 = 일평균 유입량 * 65% : 실제 수용가의 물사용량 없는 경우 if (wtrUsgYearTotal > 0 && wtrUsgYearDays > 0) { - item.waterUsage = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량 + item.waterUsage = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량: 실제 수용가의 물사용량 } item.sewageInputYear = parseFloat(avg.toFixed(2)); // 연간 하수유입량(m³/일) item.sewageInputChungchun = parseFloat((chungcunSumFlow === 0 ? 0 : (chungcunSumFlow / sumChungcunDay)).toFixed(2)); // 청천시 하수유입량 item.estimationSewage = parseFloat((item.waterUsage * OSU_PERCENT).toFixed(2)); // 오수발생량 추정(m³/일) - if (item.bscFctCd === '11200PB001R') { - console.log('chungcunSumFlow:', chungcunSumFlow); - console.log('sumChungcunDay:', sumChungcunDay); - } + if (item.estimationSewage > maxEstimationSewage) maxEstimationSewage = item.estimationSewage; + if (item.estimationSewage < minEstimationSewage) minEstimationSewage = item.estimationSewage; // 반올림 처리 ["fctCpc", "waterUsage", "swageChangePercent", "estimationSewage", "sewageInputYear", "sewageInputChungchun"].forEach( (key) => (item[key] = roundNumber(item[key], 0)) @@ -427,93 +428,11 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = })); } - /* fetchSewageOccurList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm).then(async (res) => { - const excelDownList: ExcelType[] = []; - const data = res.data; - // Promise.all을 사용하여 모든 비동기 작업이 완료될 때까지 기다림 - const calData = await Promise.all(data.map(async (item: SewageOccurProps) => { - item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; - item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; - item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.swageChangePercent = 90; - - const bscFctCd = item.bscFctCd; - const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse; - - let sumChungcunDay = 0; - let chungcunSumFlow = 0; - let totWaterUsage = 0; - - // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) - const rainEffectData = CalcRainEffect(res2.data); - - rainEffectData.forEach((item: FlowDataItem) => { - - if(Number(item.rainEffectDay) === 0){ - chungcunSumFlow += Number(item.inflAmnt); - sumChungcunDay += 1; - } - - totWaterUsage += Number(item.inflAmnt); - }); - const avg = totWaterUsage /res2.count; - item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); - item.sewageInputYear = parseFloat(avg.toFixed(2)); - item.sewageInputChungchun = parseFloat((chungcunSumFlow===0?0:(chungcunSumFlow / sumChungcunDay)).toFixed(2)); - item.estimationSewage = parseFloat((item.waterUsage * (item.swageChangePercent/100)).toFixed(2)); - return item; - })); - - calData.forEach((item: SewageOccurProps) => { - DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'waterUsage', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'swageChangePercent', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'estimationSewage', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'sewageInputYear', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'sewageInputChungchun', item: item as unknown as Record<string, unknown> }); - }); - - if(pageSize>5000){ - calData.forEach((item: SewageOccurProps) => { - excelDownList.push({ - 시설코드: item.bscFctCd, - 권역: item.rvbsn, - 단위유역: item.lgbsn, - 중권역: item.mdmbsn, - 환경청: item.rgnNm, - 시설명: item.bscFctNm, - 시도: item.sidoNm, - 시군구: item.sggNm, - 주소: item.daddr, - "시설용량(m³/일)": item.fctCpc, - "물사용량(m³/일)": item.waterUsage, - "오수전환율(%)": item.swageChangePercent, - "오수발생량추정(m³/일)": item.estimationSewage, - "연간하수유입량(m³/일)": item.sewageInputYear, - "청천시하수유입량(m³/일)": item.sewageInputChungchun, - }); - }); - } - // 조회 데이터 설정 - set((state: any) => ({ - ...state, - SewageOccur: pageSize<5000?{ - ...state.SewageOccur, - sewageOccurList: calData, - sewageOccurCount: res.count, - isLoading : false, - }:{ - ...state.SewageOccur, - excelList: excelDownList, - isLoading : false, - }, - })) - }); */ }, searchSewageOccurDetailList: async (bscFctCd: string, searchYear: string, startYm?: string, endYm?: string) => { const fcltCdList = [bscFctCd]; - const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); + const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear); const monthData: SewageOccurDetailProps[] = []; let tot = 0, cnt = 0; @@ -554,15 +473,15 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = } else { monthData[monthIdx] = { cnt: 1, sum: Number(item.inflAmnt), yr: item.msrDt.substring(0, 4) - , usage: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0, monWtrUsg: 0 + , usage: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0, monWtrUsg: 0, maxEstSewerage: 0, minEstSewerage: 999999999 }; } } - tot += Number(item.inflAmnt) + tot += Number(item.inflAmnt); // 연간 유입량 cnt++ }); - // 물사용량 + // 수용가 실제 물사용량 let totWtrUsg = 0; let cntWtrUsg = 0; if (wtrUsgRes && wtrUsgRes.data && wtrUsgRes.data[bscFctCd]) { @@ -582,25 +501,23 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = const tableData: modalTableType[] = [] - let maxWaterUsage = 0; - let minWaterUsage = 9999999999; + let maxWaterUsage = 0, minWaterUsage = 9999999999; + let maxEstSewage = 0, minEstSewage = 9999999999; let avgWaterUsage = 0; monthData.forEach((item, index) => { - item.avgWtrUsg = item.sum / item.cnt * 0.65; // 일평균 물사용량 = 일평균유입수 * 0.65 - if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; + item.avgWtrUsg = item.sum / item.cnt * 0.65; // 일평균 물사용량 = 일평균유입수 * 0.65 : 수용가 실제 물사용량이 없으면 + if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; //수용가 실제 물사용량이 있는 경우 + const estSewage = Math.round(item.avgWtrUsg * OSU_PERCENT * 1) / 1; // 오수발생량 추정 tableData.push({ msrDt: item.yr + '-' + (index + 1 >= 10 ? String(index + 1) : '0' + (index + 1)), waterUsage: Math.round(item.avgWtrUsg * 1) / 1, - swageChangePercent: OSU_PERCENT * 100,//(Math.round((item.usage/item.usage*OSU_PERCENT) * 100) / 100) * 100, - estimationSewage: Math.round(item.avgWtrUsg * OSU_PERCENT * 1) / 1 + swageChangePercent: OSU_PERCENT * 100, //오수전환율 (Math.round((item.usage/item.usage*OSU_PERCENT) * 100) / 100) * 100, + estimationSewage: estSewage, }) - if (item.avgWtrUsg > maxWaterUsage) { - maxWaterUsage = item.avgWtrUsg; - } - - if (item.avgWtrUsg < minWaterUsage) { - minWaterUsage = item.avgWtrUsg; - } + if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; // 물사용량 최대 + if (item.avgWtrUsg < minWaterUsage) minWaterUsage = item.avgWtrUsg; // 물사용량 최소 + if (maxEstSewage < estSewage) maxEstSewage = estSewage; // 오수발생량 최대 + if (minEstSewage > estSewage) minEstSewage = estSewage; // 오수발생량 최소 }); avgWaterUsage = tot / cnt * 0.65 @@ -617,13 +534,13 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = msrDt: '최대', waterUsage: roundNumber(Math.round(maxWaterUsage * 100) / 100, 0), swageChangePercent: OSU_PERCENT * 100, - estimationSewage: roundNumber(Math.round(maxWaterUsage * OSU_PERCENT * 1) / 1, 0), + estimationSewage: roundNumber(maxEstSewage / 1, 0), }, { msrDt: '최소', waterUsage: roundNumber(Math.round(minWaterUsage * 100) / 100, 0), swageChangePercent: OSU_PERCENT * 100, - estimationSewage: roundNumber(Math.round(minWaterUsage * OSU_PERCENT * 1) / 1, 0), + estimationSewage: roundNumber(minEstSewage / 1, 0), }, ...tableData ] diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index c6a2167d8..93745baf9 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -5,6 +5,7 @@ import type { ExcelType, UnderWaterInputModalProps, UnderWaterProps, WtrUsgYmPro // import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { OSU_PERCENT } from "../common"; import { fetchFacilityListInit } from "../processFacility"; +import { getDaysInMonth } from "@/app/components/common/DataForm"; export type { TableUpperProps }; // SewageOccurDetailProps 타입을 여기에 정의 @@ -241,7 +242,7 @@ export const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList ====================================*/ export type UnderWaterActions = { 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 + underWaterModal:(bscFctCd:string, searchYear:string, startYm:string, endYm:string)=>void } export type UnderWaterType = { @@ -310,27 +311,6 @@ const dataFormSetting=(item : UnderWaterProps)=> { // } // return results; // } -/** - * yyyymm 형태의 문자열을 받아 해당 월의 일수를 반환 - * @param {string} yyyymm - 예: "202502", "202412" - * @returns {number} 해당 월의 일수 (예: 28, 29, 30, 31) - */ -function getDaysInMonth(yyyymm) { - if (typeof yyyymm !== 'string' || yyyymm.length !== 6) { - throw new Error("입력은 'yyyymm' 형식의 문자열이어야 합니다. 예: '202502'"); - } - - const year = parseInt(yyyymm.slice(0, 4), 10); // "2025" -> 2025 - const month = parseInt(yyyymm.slice(4, 6), 10); // "02" -> 2 - - if (isNaN(year) || isNaN(month) || month < 1 || month > 12) { - throw new Error("유효한 년/월이 아닙니다."); - } - - // Date(year, month, 0) -> 전달의 마지막 날 - // month에 '다음달'을 넣고, 일(day)에 0을 주면 해당 월의 마지막 날짜가 됨 - return new Date(year, month, 0).getDate(); -} export type UnderWaterStore = UnderWaterType & UnderWaterActions; @@ -547,7 +527,7 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy } }, - unserWaterModal:async (bscFctCd, searchYear, startYm, endYm)=>{ + underWaterModal:async (bscFctCd, searchYear, startYm, endYm)=>{ const fcltCdList = [bscFctCd]; const wtrUsgRes : any = await fetchWtrUsgYmList(searchYear, fcltCdList); const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear); @@ -639,27 +619,28 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy const tableData:UnderWaterInputModalProps[] = [] - let maxWaterUsage = 0; - let minWaterUsage = 9999999999; - let avgWaterUsage = 0; - let maxSunnyInflAmnt = 0; - let minSunnyInflAmnt = 9999999999; - let avgSunnyInflAmnt = 0; + let maxWaterUsage = 0, minWaterUsage = 9999999999, avgWaterUsage = 0; // 물사용량 + let maxSunnyInflAmnt = 0, minSunnyInflAmnt = 9999999999, avgSunnyInflAmnt = 0; // 청천 유입량 + let maxUnderWaterInput = 0, minUnderWaterInput = 9999999999; // 지하수 유입량 monthData.forEach((item, index) => { item.usage = item.sum/item.cnt; // 일평균 유입량 - item.avgWtrUsg = item.sum/item.cnt * 0.65; // 일평균 물사용량 - if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; // 일평균 물사용량 + item.avgWtrUsg = item.sum/item.cnt * 0.65; // 일평균 물사용량 : 수용가 물사용량이 없는 경우 + // 일평균 물사용량 : 수용가 물사용량이 있는 경우 + if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; item.sunnyAvgInflAmnt = item.sunnyInflAmnt / item.sunnyCnt; // 청천 일평균 유입량 + const underWtrInput = Math.round((item.sunnyAvgInflAmnt-(item.avgWtrUsg*OSU_PERCENT)) * 1) / 1; // 지하수 유입량 평균 tableData.push({ msrDt: item.yr+'-'+(index+1>=10?String(index+1):'0'+(index+1)), realSewageInput:Math.round(item.sunnyAvgInflAmnt*1) /1, // 청천 실제 하수유입량 sewageOccur:Math.round(item.avgWtrUsg*OSU_PERCENT * 1) / 1,// 오수발생량 - underWaterInput:Math.round((item.sunnyAvgInflAmnt-(item.avgWtrUsg*OSU_PERCENT)) * 1) / 1, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + underWaterInput: underWtrInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) }) if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; if (item.sunnyAvgInflAmnt > maxSunnyInflAmnt) maxSunnyInflAmnt = item.sunnyAvgInflAmnt; if (item.avgWtrUsg < minWaterUsage) minWaterUsage = item.avgWtrUsg; if (item.sunnyAvgInflAmnt < minSunnyInflAmnt) minSunnyInflAmnt = item.sunnyAvgInflAmnt; + if (underWtrInput > maxUnderWaterInput) maxUnderWaterInput = underWtrInput; + if (underWtrInput < minUnderWaterInput) minUnderWaterInput = underWtrInput; }); if(monthData.length == 0){ @@ -683,13 +664,13 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy msrDt: '최대', realSewageInput: Math.round(maxSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 sewageOccur: Math.round(maxWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: Math.round((maxSunnyInflAmnt-(maxWaterUsage*OSU_PERCENT)) * 1) / 1, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + underWaterInput: maxUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) }, { msrDt: '최소', realSewageInput: Math.round(minSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 sewageOccur: Math.round(minWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: Math.round((minSunnyInflAmnt-(minWaterUsage*OSU_PERCENT)) * 1) / 1, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + underWaterInput: minUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) }, ...tableData ] From 6a5c7c301f82d562c6d8cc9d4e0ebe981475156c Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 8 Jan 2026 22:24:32 +0900 Subject: [PATCH 37/92] =?UTF-8?q?fo:=20dashboard=20=EC=A7=80=ED=95=98?= =?UTF-8?q?=EC=88=98=EC=9C=A0=EC=9E=85=EB=9F=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 25 +- apps/fo/app/store/sewageOccur/index.tsx | 4 +- apps/fo/app/store/underWaterInput/index.tsx | 552 ++++++++++---------- 3 files changed, 294 insertions(+), 287 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 94c0ab78e..fcddcc77b 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -218,9 +218,9 @@ export interface DrainageEquipmentExcelType { } type WtrUsgYmProps = { - bscFctCd : string, // 처리구역시설코드 - levyYm : string, // 부과년월 - wtrUsg : number, // 월별 물사용량(m³/월) + bscFctCd: string, // 처리구역시설코드 + levyYm: string, // 부과년월 + wtrUsg: number, // 월별 물사용량(m³/월) } /** * Store - data @@ -729,9 +729,9 @@ const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string }; // 시설들 월별 물사용량 정보 조회 -const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { +const fetchWtrUsgYmList = async (searchYear: string | undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { try { - const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/'+searchYear, fcltCdList); + const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/' + searchYear, fcltCdList); return res; } catch (error) { console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); @@ -1672,15 +1672,18 @@ export const dashBoardReducer = ( operationalStatusList[0].winterSunnyMax = roundUp(operList.inFlow.winterSunnyMax, 0); // 동절기 유입 최대 operationalStatusList[0].winterSunnyAvg = roundUp(operList.inFlow.winterAvg, 0); // 동절기 유입 평균 - // 지하수유입량 + // 청천시 유입(순수하수) 평균 const usage = operList.inflAmt.yearSunny / cntSunnyDay; // 연간 청천 순수하수 평균 const summerUsage = operList.inflAmt.summerSunny; // 하절기 청천 순수하수 평균 const winterUsage = operList.inflAmt.winterSunny; // 동절기 청천 순수하수 평균 - - // 임시 계산변수값들 메인에 대입 - operationalStatusList[0].groundWaterAvg = Math.round((usage - (usage * 0.65 * OSU_PERCENT)) * 100) / 100; - operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (summerUsage * 0.65 * OSU_PERCENT)) * 100) / 100; - operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (winterUsage * 0.65 * OSU_PERCENT)) * 100) / 100; + // 물사용량 = 유입평균 * 0.65 + const wtrUsg = operList.inflAmt.yearAvg * 0.65; // 연간 물사용량 평균 + const wtrUsgSummer = operList.inflAmt.summerAvg * 0.65; // 하절기 물사용량 평균 + const wtrUsgWinter = operList.inflAmt.winterAvg * 0.65; // 동절기 물사용량 평균 + // 지하수유입량 + operationalStatusList[0].groundWaterAvg = Math.round((usage - (wtrUsg * OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterSummer = Math.round((summerUsage - (wtrUsgSummer * OSU_PERCENT)) * 100) / 100; + operationalStatusList[0].groundWaterWinter = Math.round((winterUsage - (wtrUsgWinter * OSU_PERCENT)) * 100) / 100; // 오염물질 // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx index becb5016b..1f4e8ce7e 100644 --- a/apps/fo/app/store/sewageOccur/index.tsx +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -370,8 +370,8 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = // console.log("totWaterUsage:", totWaterUsage); const count = detailList ? detailList.length : 0; - const avg = count == 0 ? 0 : totWaterUsage / count; // 일평균 유입량 - item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); // 물사용량 = 일평균 유입량 * 65% : 실제 수용가의 물사용량 없는 경우 + const avg = count == 0 ? 0 : totWaterUsage / count; // 연간 하수유입량(m³/일) + item.waterUsage = parseFloat((avg * 0.65).toFixed(2)); // 물사용량 = 연간 하수유입량(m³/일) * 65% : 실제 수용가의 물사용량 없는 경우 if (wtrUsgYearTotal > 0 && wtrUsgYearDays > 0) { item.waterUsage = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량: 실제 수용가의 물사용량 } diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index 93745baf9..0a0ce9537 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -10,16 +10,16 @@ export type { TableUpperProps }; // SewageOccurDetailProps 타입을 여기에 정의 export type SewageOccurDetailProps = { - cnt : number, - sum : number, - yr:string, - usage:number, // 일평균 유입량 - sunnyCnt : number, - sunnyInflAmnt : number, - sunnyAvgInflAmnt : number, // 청천시 일평균 유입량 - cntWtrUsg : number, // 물사용량 일자수 - sumWtrUsg : number, // 물사용량 합 - avgWtrUsg:number, // 일평균 물사용량 + cnt: number, + sum: number, + yr: string, + usage: number, // 일평균 유입량 + sunnyCnt: number, + sunnyInflAmnt: number, + sunnyAvgInflAmnt: number, // 청천시 일평균 유입량 + cntWtrUsg: number, // 물사용량 일자수 + sumWtrUsg: number, // 물사용량 합 + avgWtrUsg: number, // 일평균 물사용량 } /**==================================== * Store - 타입 @@ -36,145 +36,145 @@ export type SewageOccurDetailProps = { /** * (1) 메인페이지 - */ + */ // 검색단 -const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; +const LabelArray: string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; // 리스트 헤더 -const upHeadList1:TableUpperProps[] = [ - { id: "A", title: "행정구역", row:0, colSpan:2 }, - { id: "sidoNm", title: "시도", row:1, widthPercent: 8 }, - { id: "sggNm", title: "시군구", row:1, widthPercent: 8 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "daddr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 }, - { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 }, - { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, - { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 8 }, +const upHeadList1: TableUpperProps[] = [ + { id: "A", title: "행정구역", row: 0, colSpan: 2 }, + { id: "sidoNm", title: "시도", row: 1, widthPercent: 8 }, + { id: "sggNm", title: "시군구", row: 1, widthPercent: 8 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "C", title: "지하수 유입량 추정", align: "right", row: 0, colSpan: 3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "properYn", title: "적정여부", row: 0, rowSpan: 2, widthPercent: 8 }, ]; -const upHeadList2:TableUpperProps[] = [ - { id: "A", title: "유역", row:0, colSpan:3 }, - { id: "rvbsn", title: "권역", row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "daddr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 }, - { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 }, - { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, - { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 8 }, - { id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 8 }, +const upHeadList2: TableUpperProps[] = [ + { id: "A", title: "유역", row: 0, colSpan: 3 }, + { id: "rvbsn", title: "권역", row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", row: 1, widthPercent: 5 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "C", title: "지하수 유입량 추정", align: "right", row: 0, colSpan: 3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align: "right", row: 1, widthPercent: 8 }, + { id: "properYn", title: "적정여부", row: 0, rowSpan: 2, widthPercent: 8 }, ]; -const upHeadList3:TableUpperProps[] = [ - { id: "A", title: "유역", row:0, colSpan:3 }, - { id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1, widthPercent: 5 }, - { id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 8 }, - { id: "B", title: "행정구역", row:0, colSpan:2 }, - { id: "sidoNm", title: "시도", row:1, widthPercent: 6 }, - { id: "sggNm", title: "시군구", row:1, widthPercent: 6 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "daddr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 }, - { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 }, - { id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 }, - { id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 6}, - { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 6 }, - { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 6 }, - { id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 6 }, +const upHeadList3: TableUpperProps[] = [ + { id: "A", title: "유역", row: 0, colSpan: 3 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row: 1, widthPercent: 5 }, + { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "B", title: "행정구역", row: 0, colSpan: 2 }, + { id: "sidoNm", title: "시도", row: 1, widthPercent: 6 }, + { id: "sggNm", title: "시군구", row: 1, widthPercent: 6 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 6 }, + { id: "inflAmnt", title: "연평균유입하수량(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "C", title: "지하수 유입량 추정", align: "right", row: 0, colSpan: 3 }, + { id: "underWaterInputYear", title: "연간\n(m³/일)", align: "right", row: 1, widthPercent: 6 }, + { id: "underWaterInputSummer", title: "하절기\n(m³/일)", align: "right", row: 1, widthPercent: 6 }, + { id: "underWaterInputWinter", title: "동절기\n(m³/일)", align: "right", row: 1, widthPercent: 6 }, + { id: "properYn", title: "적정여부", row: 0, rowSpan: 2, widthPercent: 6 }, ]; // 모달 -const upHeadListUnderWaterDetail:TableUpperProps[] = [ +const upHeadListUnderWaterDetail: TableUpperProps[] = [ { id: "msrDt", title: "날짜" }, - { id: "realSewageInput", title: "청천시 실제 하수유입량\n(m³/일)", align:"right" }, - { id: "sewageOccur", title: "오수발생량\n(m³/일)", align:"right" }, - { id: "underWaterInput", title: "지하수 유입량\n(m³/일)", align:"right" }, + { id: "realSewageInput", title: "청천시 실제 하수유입량\n(m³/일)", align: "right" }, + { id: "sewageOccur", title: "오수발생량\n(m³/일)", align: "right" }, + { id: "underWaterInput", title: "지하수 유입량\n(m³/일)", align: "right" }, ]; -const underWaterList:UnderWaterProps[] = [ +const underWaterList: UnderWaterProps[] = [ ] -const underWaterDetailList:UnderWaterInputModalProps[] = [ +const underWaterDetailList: UnderWaterInputModalProps[] = [ { - msrDt : "2024-01", - realSewageInput : 178007, - sewageOccur : 10.5, - underWaterInput : 80.6, + msrDt: "2024-01", + realSewageInput: 178007, + sewageOccur: 10.5, + underWaterInput: 80.6, }, { - msrDt : "2024-02", - realSewageInput : 123007, - sewageOccur : 10.7, - underWaterInput : 80.6, + msrDt: "2024-02", + realSewageInput: 123007, + sewageOccur: 10.7, + underWaterInput: 80.6, }, { - msrDt : "2024-03", - realSewageInput : 213007, - sewageOccur : 10.1, - underWaterInput : 80.6, + msrDt: "2024-03", + realSewageInput: 213007, + sewageOccur: 10.1, + underWaterInput: 80.6, }, { - msrDt : "2024-04", - realSewageInput : 83007, - sewageOccur : 9.57, - underWaterInput : 80.6, + msrDt: "2024-04", + realSewageInput: 83007, + sewageOccur: 9.57, + underWaterInput: 80.6, }, { - msrDt : "2024-05", - realSewageInput : 15007, - sewageOccur : 3.57, - underWaterInput : 80.6, + msrDt: "2024-05", + realSewageInput: 15007, + sewageOccur: 3.57, + underWaterInput: 80.6, }, { - msrDt : "2024-06", - realSewageInput : 123007, - sewageOccur : '', - underWaterInput : 80.6, + msrDt: "2024-06", + realSewageInput: 123007, + sewageOccur: '', + underWaterInput: 80.6, }, { - msrDt : "2024-07", - realSewageInput : 101007, - sewageOccur : 1, - underWaterInput : 80.6, + msrDt: "2024-07", + realSewageInput: 101007, + sewageOccur: 1, + underWaterInput: 80.6, }, { - msrDt : "2024-08", - realSewageInput : 103807, - sewageOccur : 10.57, - underWaterInput : '', + msrDt: "2024-08", + realSewageInput: 103807, + sewageOccur: 10.57, + underWaterInput: '', }, { - msrDt : "2024-09", - realSewageInput : 9007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-09", + realSewageInput: 9007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, { - msrDt : "2024-10", - realSewageInput : 163007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-10", + realSewageInput: 163007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, { - msrDt : "2024-11", - realSewageInput : 123007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-11", + realSewageInput: 123007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, { - msrDt : "2024-12", - realSewageInput : 1007, - sewageOccur : 10.57, - underWaterInput : 80.6, + msrDt: "2024-12", + realSewageInput: 1007, + sewageOccur: 10.57, + underWaterInput: 80.6, }, ] /**==================================== @@ -186,8 +186,8 @@ export interface FlowDataItem { inflAmnt: number | string; infoRnDay: number; msrDt: string; - rainEffectDay? : number; - sumFlow? : number | string | ''; + rainEffectDay?: number; + sumFlow?: number | string | ''; } export interface ApiResponse { @@ -217,9 +217,9 @@ const fetchUnderWaterList = async (pageNo: number, pageSize: number, searchYear: // } // 시설들 유량 정보 조회 -export const fetchDetailListFlow = async (searchYear: string|undefined, fcltCdList: string[]): Promise<UnderWaterProps | null> => { +export const fetchDetailListFlow = async (searchYear: string | undefined, fcltCdList: string[]): Promise<UnderWaterProps | null> => { try { - const res = await postFetch('fo', '/fclt/flow/'+searchYear, fcltCdList); + const res = await postFetch('fo', '/fclt/flow/' + searchYear, fcltCdList); return res; } catch (error) { console.error('시설정보 오수발생량 상세 데이터를 가져오는데 실패했습니다:', error); @@ -227,9 +227,9 @@ export const fetchDetailListFlow = async (searchYear: string|undefined, fcltCdLi } }; // 시설들 월별 물사용량 정보 조회 -export const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { +export const fetchWtrUsgYmList = async (searchYear: string | undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { try { - const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/'+searchYear, fcltCdList); + const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/' + searchYear, fcltCdList); return res; } catch (error) { console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); @@ -242,16 +242,16 @@ export const fetchWtrUsgYmList = async (searchYear: string|undefined, fcltCdList ====================================*/ export type UnderWaterActions = { searchUnderWaterList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; - underWaterModal:(bscFctCd:string, searchYear:string, startYm:string, endYm:string)=>void + underWaterModal: (bscFctCd: string, searchYear: string, startYm: string, endYm: string) => void } export type UnderWaterType = { UnderWaterSearch: { isInit: boolean; - labelArray:string[]; + labelArray: string[]; }, - UnderWater : { + UnderWater: { isInit: boolean; upHeadList1: TableUpperProps[]; upHeadList2: TableUpperProps[]; @@ -262,7 +262,7 @@ export type UnderWaterType = { isLoading: boolean; }, - UnderWaterDetail : { + UnderWaterDetail: { isInit: boolean; upHeadListUnderWaterDetail: TableUpperProps[]; gridListUnderWaterDetail: UnderWaterInputModalProps[]; @@ -275,30 +275,30 @@ export const underWaterInitState: UnderWaterType = { labelArray: LabelArray, }, - UnderWater : { - isInit : false, - upHeadList1 : upHeadList1, - upHeadList2 : upHeadList2, - upHeadList3 : upHeadList3, - underWaterList : underWaterList, - underWaterCount : 4, - excelList : [], - isLoading : true, + UnderWater: { + isInit: false, + upHeadList1: upHeadList1, + upHeadList2: upHeadList2, + upHeadList3: upHeadList3, + underWaterList: underWaterList, + underWaterCount: 4, + excelList: [], + isLoading: true, }, - UnderWaterDetail : { + UnderWaterDetail: { isInit: false, upHeadListUnderWaterDetail: upHeadListUnderWaterDetail, gridListUnderWaterDetail: underWaterDetailList, } } -const dataFormSetting=(item : UnderWaterProps)=> { +const dataFormSetting = (item: UnderWaterProps) => { DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'underWaterInputYear', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'underWaterInputSummer', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'underWaterInputWinter', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float0', column: 'underWaterInputYear', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'underWaterInputSummer', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'underWaterInputWinter', item: item as unknown as Record<string, unknown> }); } // 병렬 처리 제한용 헬퍼 @@ -314,23 +314,23 @@ const dataFormSetting=(item : UnderWaterProps)=> { export type UnderWaterStore = UnderWaterType & UnderWaterActions; -export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterType) => void)=>UnderWaterActions=(set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { +export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => UnderWaterActions = (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { return { 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 < 5000){ + + if (pageSize < 5000) { set((state: UnderWaterType) => ({ ...state, UnderWater: { ...state.UnderWater, - underWaterList : facilityInitData.data, - underWaterCount : facilityInitData.count, - isInit : true, + underWaterList: facilityInitData.data, + underWaterCount: facilityInitData.count, + isInit: true, isLoading: true, }, })); - }else{ + } else { set((state: UnderWaterType) => ({ ...state, UnderWater: { @@ -339,43 +339,43 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy }, })); } - + const fcltylist = facilityInitData.data; - const fcltCdList : string[] = []; // 시설코드목록 - const underWaterPropsList : UnderWaterProps[] = []; // 오수발생량시설목록 + const fcltCdList: string[] = []; // 시설코드목록 + const underWaterPropsList: UnderWaterProps[] = []; // 오수발생량시설목록 fcltylist.forEach(item => { fcltCdList.push(item.bscFctCd); underWaterPropsList.push({ - bscFctCd : item.bscFctCd, - sidoNm : item.sido, - sggNm : item.gugun, - lclgvrnmntNm : '', - bscFctNm : item.bscFctNm, - daddr : item.daddr, - fctCpc : parseFloat(item.fctCpc.toString().replace(/,/g, '')), - inflAmnt : 0, - waterUsage : 0, - underWaterInputYear : 0, - underWaterInputSummer : 0, - underWaterInputWinter : 0, - properYn : '', - infoRnDay : 0, - rgnNm : item.rgnNm, - rvbsn : item.rvbsn, - lgbsn : item.lgbsn, - mdmbsn : item.mdmbsn, - msrDt : '', + bscFctCd: item.bscFctCd, + sidoNm: item.sido, + sggNm: item.gugun, + lclgvrnmntNm: '', + bscFctNm: item.bscFctNm, + daddr: item.daddr, + fctCpc: parseFloat(item.fctCpc.toString().replace(/,/g, '')), + inflAmnt: 0, + waterUsage: 0, + underWaterInputYear: 0, + underWaterInputSummer: 0, + underWaterInputWinter: 0, + properYn: '', + infoRnDay: 0, + rgnNm: item.rgnNm, + rvbsn: item.rvbsn, + lgbsn: item.lgbsn, + mdmbsn: item.mdmbsn, + msrDt: '', }); }); - - const soccurDetailRes : any = await fetchDetailListFlow(searchYear, fcltCdList); - const wtrUsgYmRes : any = await fetchWtrUsgYmList(searchYear, fcltCdList); - + + const soccurDetailRes: any = await fetchDetailListFlow(searchYear, fcltCdList); + const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); + for (const item of underWaterPropsList) { - + const detailList = soccurDetailRes?.data[item.bscFctCd]; const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd]; - + let chungcunSumFlow = 0; // 청천유입량 let sumChungcunDay = 0; // 청천일수 let sumSummerChungcunDay = 0; // 하절기 청천일수 @@ -387,39 +387,39 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy let totWinterUsage = 0; // 동절기 하수유입량 let totSummerDays = 0; // 하절기 일수 let totWinterDays = 0; // 동절기 일수 - + const summerMonth = ['06', '07', '08']; const winterMonth = ['01', '02']; - + let rainEffectDay = 0; detailList?.forEach(item2 => { if (item2.infoRnDay == null || item2.infoRnDay.trim() == 'x') item2.infoRnDay = 0; - if(Number(item2.infoRnDay) >= 3) { + if (Number(item2.infoRnDay) >= 3) { rainEffectDay = 2; - }else{ + } else { rainEffectDay--; } - if(rainEffectDay<0){ //청천시 + if (rainEffectDay < 0) { //청천시 chungcunSumFlow += Number(item2.inflAmnt); sumChungcunDay += 1; - if(item2.msrDt.substring(4,6) ==='06' || item2.msrDt.substring(4,6) ==='07' || item2.msrDt.substring(4,6) ==='08'){ + if (item2.msrDt.substring(4, 6) === '06' || item2.msrDt.substring(4, 6) === '07' || item2.msrDt.substring(4, 6) === '08') { // 하절기 6,7,8월 sumSummerChungcunDay += 1; sumSummerChungcunFlow += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; - }else if(item2.msrDt.substring(4,6) ==='01' || item2.msrDt.substring(4,6) ==='02'){ + } else if (item2.msrDt.substring(4, 6) === '01' || item2.msrDt.substring(4, 6) === '02') { // 동절기 1,2월 sumWinterChungcunDay += 1; sumWinterChungcunFlow += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; } } totWaterUsage += Number(item2.inflAmnt); - if(item2.msrDt.substring(4,6) ==='06' || item2.msrDt.substring(4,6) ==='07' || item2.msrDt.substring(4,6) ==='08'){ + if (item2.msrDt.substring(4, 6) === '06' || item2.msrDt.substring(4, 6) === '07' || item2.msrDt.substring(4, 6) === '08') { // 하절기 6,7,8월 totSummerDays += 1; totSummerUsage += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; - }else if(item2.msrDt.substring(4,6) ==='01' || item2.msrDt.substring(4,6) ==='02'){ + } else if (item2.msrDt.substring(4, 6) === '01' || item2.msrDt.substring(4, 6) === '02') { // 동절기 1,2월 totWinterDays += 1; totWinterUsage += Number(item2.inflAmnt); //item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; @@ -427,8 +427,8 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy }); const count = detailList ? detailList.length : 0; - const avg = count == 0 ? 0 : totWaterUsage / count; // 일평균 유입량 - + const avg = count == 0 ? 0 : totWaterUsage / count; // 연간 일평균 유입량 + let wtrUsgYearTotal = 0; // 연간 물사용량 let summerWtrUsgTot = 0; // 하절기 물사용량 let winterWtrUsgTot = 0; // 동절기 물사용량 @@ -439,52 +439,52 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy const days = getDaysInMonth(item3.levyYm); wtrUsgYearTotal += Number(item3.wtrUsg); wtrUsgYearDays += days; - if(summerMonth.includes(item3.levyYm.slice(-2))){ + if (summerMonth.includes(item3.levyYm.slice(-2))) { summerWtrUsgTot += Number(item3.wtrUsg); summerWtrUsgDays += days; - }else if(winterMonth.includes(item3.levyYm.slice(-2))){ + } else if (winterMonth.includes(item3.levyYm.slice(-2))) { winterWtrUsgTot += Number(item3.wtrUsg); winterWtrUsgDays += days; } }); - + if (wtrUsgYearTotal > 0) { // 물사용량이 있는 경우 - const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / sumChungcunDay:0; // 청천시 일평균 유입량 - const summerUsage = sumSummerChungcunFlow?sumSummerChungcunFlow / sumSummerChungcunDay:0; // 하절기 청천시 일평균 유입량 - const winterUsage = sumWinterChungcunFlow?sumWinterChungcunFlow / sumWinterChungcunDay:0; // 동절기 청천시 일평균 유입량 - const wtrUsg = wtrUsgYearDays>0? wtrUsgYearTotal / wtrUsgYearDays: 0; // 일평균 물사용량 - const summerWtrUsg = summerWtrUsgTot?summerWtrUsgTot / summerWtrUsgDays:0; // 하절기 일평균 물사용량 - const winterWtrUsg = winterWtrUsgTot?winterWtrUsgTot / winterWtrUsgDays:0; // 동절기 일평균 물사용량 - + const usage = chungcunSumFlow && chungcunSumFlow > 0 ? chungcunSumFlow / sumChungcunDay : 0; // 청천시 일평균 유입량 + const summerUsage = sumSummerChungcunFlow ? sumSummerChungcunFlow / sumSummerChungcunDay : 0; // 하절기 청천시 일평균 유입량 + const winterUsage = sumWinterChungcunFlow ? sumWinterChungcunFlow / sumWinterChungcunDay : 0; // 동절기 청천시 일평균 유입량 + const wtrUsg = wtrUsgYearDays > 0 ? wtrUsgYearTotal / wtrUsgYearDays : 0; // 일평균 물사용량 + const summerWtrUsg = summerWtrUsgTot ? summerWtrUsgTot / summerWtrUsgDays : 0; // 하절기 일평균 물사용량 + const winterWtrUsg = winterWtrUsgTot ? winterWtrUsgTot / winterWtrUsgDays : 0; // 동절기 일평균 물사용량 + item.inflAmnt = roundNumber(avg, 0); - item.underWaterInputYear = Math.round((usage-(wtrUsg*OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.underWaterInputSummer = Math.round((summerUsage-(summerWtrUsg*OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) - item.underWaterInputWinter = Math.round((winterUsage-(winterWtrUsg*OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) - item.properYn = Math.round( (Number(usage-(wtrUsg*OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1 ) / 1 > 20?'초과유입':'적정'; // 적정여부 + item.underWaterInputYear = Math.round((usage - (wtrUsg * OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.underWaterInputSummer = Math.round((summerUsage - (summerWtrUsg * OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) + item.underWaterInputWinter = Math.round((winterUsage - (winterWtrUsg * OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) + item.properYn = Math.round((Number(usage - (wtrUsg * OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1) / 1 > 20 ? '초과유입' : '적정'; // 적정여부 } else { // 물사용량이 없는 경우, 일평균 유입량으로 물사용량 추정(물사용량 = 유입량*0.65) - const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / sumChungcunDay:0; // 청천시 일평균 유입량 - const summerUsage = sumSummerChungcunFlow?sumSummerChungcunFlow / sumSummerChungcunDay:0; // 하절기 청천시 일평균 유입량 - const winterUsage = sumWinterChungcunFlow?sumWinterChungcunFlow / sumWinterChungcunDay:0; // 동절기 청천시 일평균 유입량 + const usage = chungcunSumFlow && chungcunSumFlow > 0 ? chungcunSumFlow / sumChungcunDay : 0; // 청천시 일평균 유입량 + const summerUsage = sumSummerChungcunFlow ? sumSummerChungcunFlow / sumSummerChungcunDay : 0; // 하절기 청천시 일평균 유입량 + const winterUsage = sumWinterChungcunFlow ? sumWinterChungcunFlow / sumWinterChungcunDay : 0; // 동절기 청천시 일평균 유입량 const wtrUsg = avg * 0.65; // 일평균 물사용량 - const summerWtrUsg = totSummerDays>0? (totSummerUsage / totSummerDays)*0.65:0; // 하절기 일평균 물사용량 - const winterWtrUsg = totWinterDays>0? (totWinterUsage / totWinterDays)*0.65:0; // 동절기 일평균 물사용량 - + const summerWtrUsg = totSummerDays > 0 ? (totSummerUsage / totSummerDays) * 0.65 : 0; // 하절기 일평균 물사용량 + const winterWtrUsg = totWinterDays > 0 ? (totWinterUsage / totWinterDays) * 0.65 : 0; // 동절기 일평균 물사용량 + item.inflAmnt = roundNumber(avg, 0); //item.underWaterInputYear = Math.round((usage-(usage*0.65*OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) - item.underWaterInputYear = Math.round((usage-(wtrUsg*OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.underWaterInputSummer = Math.round((summerUsage-(summerWtrUsg*OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.underWaterInputWinter = Math.round((winterUsage-(winterWtrUsg*OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) - item.properYn = Math.round( (Number(usage-(wtrUsg*OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1 ) / 1 > 20?'초과유입':'적정'; // 적정여부 - // 반올림 처리 - // ["fctCpc", "inflAmnt", "underWaterInputYear", "underWaterInputSummer", "underWaterInputWinter"].forEach( - // (key) => (item[key] = roundNumber(item[key], 0)) - // ); + item.underWaterInputYear = Math.round((usage - (wtrUsg * OSU_PERCENT)) * 1) / 1; // 연간지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.underWaterInputSummer = Math.round((summerUsage - (summerWtrUsg * OSU_PERCENT)) * 1) / 1; // 하절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.underWaterInputWinter = Math.round((winterUsage - (winterWtrUsg * OSU_PERCENT)) * 1) / 1; // 동절기지하수유입량(m³/일) = 청천시 실제유입량 - (물사용량 × 오수전환율) + item.properYn = Math.round((Number(usage - (wtrUsg * OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1) / 1 > 20 ? '초과유입' : '적정'; // 적정여부 + // 반올림 처리 + // ["fctCpc", "inflAmnt", "underWaterInputYear", "underWaterInputSummer", "underWaterInputWinter"].forEach( + // (key) => (item[key] = roundNumber(item[key], 0)) + // ); } } - if(pageSize>= 5000){ + if (pageSize >= 5000) { const excelDownList: ExcelType[] = []; - underWaterPropsList.forEach((item : any) => { + underWaterPropsList.forEach((item: any) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); excelDownList.push({ @@ -510,10 +510,10 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy UnderWater: { ...state.UnderWater, excelList: excelDownList, - isLoading : false, + isLoading: false, }, })); - }else{ + } else { set((state: UnderWaterType) => ({ ...state, UnderWater: { @@ -521,21 +521,21 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy underWaterList: underWaterPropsList, underWaterCount: facilityInitData.count, excelList: [], - isLoading : false, + isLoading: false, }, })); } }, - - underWaterModal:async (bscFctCd, searchYear, startYm, endYm)=>{ + + underWaterModal: async (bscFctCd, searchYear, startYm, endYm) => { const fcltCdList = [bscFctCd]; - const wtrUsgRes : any = await fetchWtrUsgYmList(searchYear, fcltCdList); + const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear); const monthData: SewageOccurDetailProps[] = []; let tot = 0, cnt = 0; let sunnyTot = 0, sunnyCnt = 0; - - if(startYm) { + + if (startYm) { res.data = res.data.filter((item: FlowDataItem) => { const month = item.msrDt?.substring(0, 6); return month >= startYm; @@ -547,7 +547,7 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy }); } } - if(endYm) { + if (endYm) { res.data = res.data.filter((item: FlowDataItem) => { const month = item.msrDt?.substring(0, 6); return month <= endYm; @@ -562,36 +562,40 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy let rainEffectDay = 0; res.data?.forEach(item2 => { if (item2.infoRnDay == null || item2.infoRnDay.trim() == 'x') item2.infoRnDay = 0; - if(Number(item2.infoRnDay) >= 3) { + if (Number(item2.infoRnDay) >= 3) { rainEffectDay = 2; - }else{ + } else { rainEffectDay--; } - + const month = item2.msrDt?.substring(4, 6); const monthIdx = month ? Number(month) - 1 : -1; - if (monthIdx >= 0 && (monthIdx>=Number(startYm.substring(4,6))-1 && monthIdx <= Number(endYm.substring(4, 6))-1)) { + if (monthIdx >= 0 && (monthIdx >= Number(startYm.substring(4, 6)) - 1 && monthIdx <= Number(endYm.substring(4, 6)) - 1)) { if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sum += Number(item2.inflAmnt); // 유입량 합 monthData[monthIdx].cnt++; } else { - monthData[monthIdx] = {cnt:1, sum:Number(item2.inflAmnt), yr:item2.msrDt.substring(0,4) - , usage:0, sunnyCnt:0, sunnyInflAmnt:0, sunnyAvgInflAmnt: 0, cntWtrUsg:0, sumWtrUsg:0, avgWtrUsg:0}; + monthData[monthIdx] = { + cnt: 1, sum: Number(item2.inflAmnt), yr: item2.msrDt.substring(0, 4) + , usage: 0, sunnyCnt: 0, sunnyInflAmnt: 0, sunnyAvgInflAmnt: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0 + }; } - } - if(month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)){ + } + if (month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)) { cnt++; tot += item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; } - if(rainEffectDay<0) { // 청천시 + if (rainEffectDay < 0) { // 청천시 if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sunnyInflAmnt += Number(item2.inflAmnt); // 청천 유입량 합 monthData[monthIdx].sunnyCnt++; - }else { - monthData[monthIdx] = {cnt:1, sum:Number(item2.inflAmnt), yr:item2.msrDt.substring(0,4) - , usage:0, sunnyCnt:0, sunnyInflAmnt:0, sunnyAvgInflAmnt: 0, cntWtrUsg:0, sumWtrUsg:0, avgWtrUsg:0}; + } else { + monthData[monthIdx] = { + cnt: 1, sum: Number(item2.inflAmnt), yr: item2.msrDt.substring(0, 4) + , usage: 0, sunnyCnt: 0, sunnyInflAmnt: 0, sunnyAvgInflAmnt: 0, cntWtrUsg: 0, sumWtrUsg: 0, avgWtrUsg: 0 + }; } - if (month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)){ + if (month >= startYm.substring(4, 6) && month <= endYm.substring(4, 6)) { sunnyCnt++; sunnyTot += item2.inflAmnt && item2.inflAmnt !== 'x' ? Number(item2.inflAmnt.toString().trim()) : 0; } @@ -610,32 +614,32 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy if (typeof monthData[monthIdx] === 'object') { monthData[monthIdx].sumWtrUsg += Number(item.wtrUsg); monthData[monthIdx].cntWtrUsg += days; - } + } } totWtrUsg += Number(item.wtrUsg); cntWtrUsg += days; }); } - - const tableData:UnderWaterInputModalProps[] = [] - - let maxWaterUsage = 0, minWaterUsage = 9999999999, avgWaterUsage = 0; // 물사용량 + + const tableData: UnderWaterInputModalProps[] = [] + + let maxWaterUsage = 0, minWaterUsage = 9999999999, avgWaterUsage = 0; // 물사용량 let maxSunnyInflAmnt = 0, minSunnyInflAmnt = 9999999999, avgSunnyInflAmnt = 0; // 청천 유입량 let maxUnderWaterInput = 0, minUnderWaterInput = 9999999999; // 지하수 유입량 monthData.forEach((item, index) => { - item.usage = item.sum/item.cnt; // 일평균 유입량 - item.avgWtrUsg = item.sum/item.cnt * 0.65; // 일평균 물사용량 : 수용가 물사용량이 없는 경우 + item.usage = item.sum / item.cnt; // 일평균 유입량 + item.avgWtrUsg = item.sum / item.cnt * 0.65; // 일평균 물사용량 : 수용가 물사용량이 없는 경우 // 일평균 물사용량 : 수용가 물사용량이 있는 경우 - if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; + if (item.sumWtrUsg > 0 && item.cntWtrUsg > 0) item.avgWtrUsg = item.sumWtrUsg / item.cntWtrUsg; item.sunnyAvgInflAmnt = item.sunnyInflAmnt / item.sunnyCnt; // 청천 일평균 유입량 - const underWtrInput = Math.round((item.sunnyAvgInflAmnt-(item.avgWtrUsg*OSU_PERCENT)) * 1) / 1; // 지하수 유입량 평균 + const underWtrInput = Math.round((item.sunnyAvgInflAmnt - (item.avgWtrUsg * OSU_PERCENT)) * 1) / 1; // 지하수 유입량 평균 tableData.push({ - msrDt: item.yr+'-'+(index+1>=10?String(index+1):'0'+(index+1)), - realSewageInput:Math.round(item.sunnyAvgInflAmnt*1) /1, // 청천 실제 하수유입량 - sewageOccur:Math.round(item.avgWtrUsg*OSU_PERCENT * 1) / 1,// 오수발생량 + msrDt: item.yr + '-' + (index + 1 >= 10 ? String(index + 1) : '0' + (index + 1)), + realSewageInput: Math.round(item.sunnyAvgInflAmnt * 1) / 1, // 청천 실제 하수유입량 + sewageOccur: Math.round(item.avgWtrUsg * OSU_PERCENT * 1) / 1,// 오수발생량 underWaterInput: underWtrInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) }) - if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; + if (item.avgWtrUsg > maxWaterUsage) maxWaterUsage = item.avgWtrUsg; if (item.sunnyAvgInflAmnt > maxSunnyInflAmnt) maxSunnyInflAmnt = item.sunnyAvgInflAmnt; if (item.avgWtrUsg < minWaterUsage) minWaterUsage = item.avgWtrUsg; if (item.sunnyAvgInflAmnt < minSunnyInflAmnt) minSunnyInflAmnt = item.sunnyAvgInflAmnt; @@ -643,43 +647,43 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy if (underWtrInput < minUnderWaterInput) minUnderWaterInput = underWtrInput; }); - if(monthData.length == 0){ - maxWaterUsage = 0; minWaterUsage = 0; avgWaterUsage = 0; + if (monthData.length == 0) { + maxWaterUsage = 0; minWaterUsage = 0; avgWaterUsage = 0; maxSunnyInflAmnt = 0; minSunnyInflAmnt = 0; avgSunnyInflAmnt = 0; } - - avgWaterUsage = cnt>0? tot/cnt * 0.65:0; // 일평균 물사용량 - if (totWtrUsg > 0 && cntWtrUsg > 0) avgWaterUsage = totWtrUsg / cntWtrUsg; // 일평균 물사용량 - avgSunnyInflAmnt = (sunnyCnt>0)?sunnyTot/sunnyCnt:0; // 청천 일평균 유입량 - const newData= [ - { - msrDt: '평균', - realSewageInput:Math.round(avgSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 - sewageOccur:Math.round(avgWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: Math.round((avgSunnyInflAmnt-(avgWaterUsage*OSU_PERCENT)) * 1) / 1 // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) - //underWaterInput:Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.8)) * 100) / 100, - }, - { - msrDt: '최대', - realSewageInput: Math.round(maxSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 - sewageOccur: Math.round(maxWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: maxUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) - }, - { - msrDt: '최소', - realSewageInput: Math.round(minSunnyInflAmnt*1) /1, // 청천시 실제 하수유입량 - sewageOccur: Math.round(minWaterUsage*OSU_PERCENT * 1) / 1, // 오수발생량 - underWaterInput: minUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) - }, - ...tableData + avgWaterUsage = cnt > 0 ? tot / cnt * 0.65 : 0; // 일평균 물사용량 + if (totWtrUsg > 0 && cntWtrUsg > 0) avgWaterUsage = totWtrUsg / cntWtrUsg; // 일평균 물사용량 + avgSunnyInflAmnt = (sunnyCnt > 0) ? sunnyTot / sunnyCnt : 0; // 청천 일평균 유입량 + + const newData = [ + { + msrDt: '평균', + realSewageInput: Math.round(avgSunnyInflAmnt * 1) / 1, // 청천시 실제 하수유입량 + sewageOccur: Math.round(avgWaterUsage * OSU_PERCENT * 1) / 1, // 오수발생량 + underWaterInput: Math.round((avgSunnyInflAmnt - (avgWaterUsage * OSU_PERCENT)) * 1) / 1 // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + //underWaterInput:Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.8)) * 100) / 100, + }, + { + msrDt: '최대', + realSewageInput: Math.round(maxSunnyInflAmnt * 1) / 1, // 청천시 실제 하수유입량 + sewageOccur: Math.round(maxWaterUsage * OSU_PERCENT * 1) / 1, // 오수발생량 + underWaterInput: maxUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + }, + { + msrDt: '최소', + realSewageInput: Math.round(minSunnyInflAmnt * 1) / 1, // 청천시 실제 하수유입량 + sewageOccur: Math.round(minWaterUsage * OSU_PERCENT * 1) / 1, // 오수발생량 + underWaterInput: minUnderWaterInput, // 지하수 유입량 : 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율) + }, + ...tableData ] set((state: UnderWaterType) => ({ ...state, UnderWaterDetail: { ...state.UnderWaterDetail, - gridListUnderWaterDetail:newData + gridListUnderWaterDetail: newData } })) } From e5a750e8b9efdd32f2250eab06474f62316dbeb9 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 13:06:41 +0900 Subject: [PATCH 38/92] =?UTF-8?q?fo:=20eslint=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index fcddcc77b..f797fb428 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -5,7 +5,7 @@ import { getFetch, postFetch } from "@/app/components/api"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import DataForm, { roundNumber } from "@/app/components/common/DataForm"; -import { getDaysInMonth } from "@/app/components/common/DataForm"; +// import { getDaysInMonth } from "@/app/components/common/DataForm"; import { fetchPlanInfo, OSU_PERCENT, qltyDataSetting, roundUp } from "../common"; import { type FacilityWaterQltyProps } from "../facilityWaterQlty"; import { fetchFlowRateModalList } from "../flowRate"; @@ -1467,7 +1467,7 @@ export const dashBoardReducer = ( })); const fcltCdList = [fcltyCd]; - const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 + //const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 const operList = { inFlow: { From b960a0336158c738fce5c56046c7d39d8f419124 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 13:19:34 +0900 Subject: [PATCH 39/92] =?UTF-8?q?fo:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=B3=80=EC=88=98=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/dashboard/index.tsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index f797fb428..5129cbe2f 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -729,15 +729,15 @@ const fetchFacilityPlan = async (targetYear: string | undefined, fcltyCd: string }; // 시설들 월별 물사용량 정보 조회 -const fetchWtrUsgYmList = async (searchYear: string | undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { - try { - const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/' + searchYear, fcltCdList); - return res; - } catch (error) { - console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); - return null; - } -}; +// const fetchWtrUsgYmList = async (searchYear: string | undefined, fcltCdList: string[]): Promise<WtrUsgYmProps | null> => { +// try { +// const res = await postFetch('fo', '/fclt/flow/wtrUsgYm/' + searchYear, fcltCdList); +// return res; +// } catch (error) { +// console.error('시설들 월별 물사용량 데이터를 가져오는데 실패했습니다:', error); +// return null; +// } +// }; // 주요그래프 데이터 const fetchMainGraph = async (searchYear: string | undefined, fcltyCd: string | undefined) => { @@ -1466,7 +1466,7 @@ export const dashBoardReducer = ( }, })); - const fcltCdList = [fcltyCd]; + // const fcltCdList = [fcltyCd]; //const wtrUsgRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); // 수용가의 실제 물사용량 const operList = { From 39de22045b149e44a9359210bf9aafecae46983a Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 13:21:38 +0900 Subject: [PATCH 40/92] fo: build --- apps/fo/app/store/dashboard/index.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 5129cbe2f..44dabe9d3 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -2,7 +2,7 @@ * Store - 타입 */ -import { getFetch, postFetch } from "@/app/components/api"; +import { getFetch } from "@/app/components/api"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import DataForm, { roundNumber } from "@/app/components/common/DataForm"; // import { getDaysInMonth } from "@/app/components/common/DataForm"; @@ -217,11 +217,11 @@ export interface DrainageEquipmentExcelType { stepFourSep: number | '', } -type WtrUsgYmProps = { - bscFctCd: string, // 처리구역시설코드 - levyYm: string, // 부과년월 - wtrUsg: number, // 월별 물사용량(m³/월) -} +// type WtrUsgYmProps = { +// bscFctCd: string, // 처리구역시설코드 +// levyYm: string, // 부과년월 +// wtrUsg: number, // 월별 물사용량(m³/월) +// } /** * Store - data */ From f279f498655ce52e105d7dcfb30640cdd7c4b486 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 13:38:39 +0900 Subject: [PATCH 41/92] =?UTF-8?q?fo:=20build=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/underWaterInput/modal/page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx index 2e0f5f27e..02b1891ad 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/modal/page.tsx @@ -29,7 +29,7 @@ const tabList1 = [ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYear=new Date().getFullYear().toString()} : ModalProps) { // 그리드 관련 - const {Common, UnderWaterDetail, unserWaterModal} = useFoStore((state) => state); + const {Common, UnderWaterDetail, underWaterModal} = useFoStore((state) => state); const { btnClass } = Common; const [startYmDate, setStartYmDate] = useState<string>(searchYear+'01'); const [endYmDate, setEndYmDate] = useState<string>(searchYear+'12'); @@ -74,8 +74,8 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea }, [searchYear, tabTerm]); useEffect(()=>{ - unserWaterModal(fcltyCd, searchYear, searchYear+'01', searchYear+'12'); - }, [fcltyCd, searchYear, unserWaterModal]); + underWaterModal(fcltyCd, searchYear, searchYear+'01', searchYear+'12'); + }, [fcltyCd, searchYear, underWaterModal]); useEffect(() => { if(endYmDate < startYmDate) { @@ -93,8 +93,8 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea }, [startYmDate, endYmDate, gridListUnderWaterDetail, prevStartYmDate, prevEndYmDate]); useEffect(() => { - unserWaterModal(fcltyCd, searchYear, prevStartYmDate, prevEndYmDate); - } , [fcltyCd, searchYear, unserWaterModal, prevStartYmDate, prevEndYmDate]); + underWaterModal(fcltyCd, searchYear, prevStartYmDate, prevEndYmDate); + } , [fcltyCd, searchYear, underWaterModal, prevStartYmDate, prevEndYmDate]); const excelDownload = () => { const excelDownList: any[] = []; From a6514cab644a081cc0f0aca1eb8c3c49bc91253f Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 16:26:10 +0900 Subject: [PATCH 42/92] =?UTF-8?q?fo:=20dashboard=20=EA=B0=95=EC=9A=B0?= =?UTF-8?q?=EC=9D=BC=20=EC=9A=B4=EC=98=81=ED=98=84=ED=99=A9=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/common/CalcRainEffect.tsx | 103 ++++++++++++------ .../common/FacilityTermModalHeader.tsx | 7 +- .../app/pages/(with-layout)/flowRate/page.tsx | 2 +- apps/fo/app/store/dashboard/index.tsx | 9 +- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index beca33f78..0388c5951 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -10,41 +10,65 @@ */ export default function CalcRainEffect(data : any, weather='ALL') { - /* console.log("%c Calculate RainEffect !" , "background:blue;color:white"); - console.log("%c Data Length :"+data.length+" Weather : "+weather , "background:yellow;color:blue");*/ - // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) - for(let idx = 0; idx < data.length; idx++) { - const item = data[idx]; - if(item){ - if(item.infoRnDay && Number(item.infoRnDay) >= 3) { // 강우량이 3 이상인 경우 - item.rainEffectDay = 1; - } else { - item.rainEffectDay = 0; - } - - if(item.infoRnDay == 'x'){ - item.infoRnDay = '0.0'; - item.toBeInfoRnDay = '0.0'; - }else{ - item.infoRnDay = Number(item.infoRnDay).toFixed(1); - item.toBeInfoRnDay = Number(item.infoRnDay).toFixed(1); - } + let rtnDataAll : any = []; + let rtnDataSunny : any = []; + let rtnDataRain : any = []; + let rtnData : any = []; + let rainEffectStd = 0; + data.forEach(item => { + if (item.infoRnDay == null || item.infoRnDay == 'x' || item.infoRnDay == '') item.infoRnDay = 0; + if(Number(item.infoRnDay) >= 3) { // 강우일 + rainEffectStd = 2; + item.toBeInfoRnDay = item.infoRnDay; + } else { + rainEffectStd--; } - } - // 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정 - for(let idx = 0; idx < data.length; idx++) { - if(data[idx]) { - // 하루 전이 강우영향일(3 이상)인 경우 - if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay) >= 3) { - data[idx]!.rainEffectDay = 1; - } - // 이틀 전이 강우영향일(3 이상)인 경우 - if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay) >= 3) { - data[idx]!.rainEffectDay = 1; - } + if (rainEffectStd < 0) { // 청천일 + item.rainEffectDay = 0; + rtnDataSunny.push(item); + } else if (rainEffectStd >= 0) { // 강우일 + 강우영향일 + item.rainEffectDay = 1; + rtnDataRain.push(item); } - } + + rtnDataAll.push(item); + }); + + + // // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) + // for(let idx = 0; idx < data.length; idx++) { + // const item = data[idx]; + // if(item){ + // if(item.infoRnDay && Number(item.infoRnDay) >= 3) { // 강우량이 3 이상인 경우 + // item.rainEffectDay = 1; + // } else { + // item.rainEffectDay = 0; + // } + + // if(item.infoRnDay == 'x'){ + // item.infoRnDay = '0.0'; + // item.toBeInfoRnDay = '0.0'; + // }else{ + // item.infoRnDay = Number(item.infoRnDay).toFixed(1); + // item.toBeInfoRnDay = Number(item.infoRnDay).toFixed(1); + // } + // } + // } + + // // 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정 + // for(let idx = 0; idx < data.length; idx++) { + // if(data[idx]) { + // // 하루 전이 강우영향일(3 이상)인 경우 + // if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay) >= 3) { + // data[idx]!.rainEffectDay = 1; + // } + // // 이틀 전이 강우영향일(3 이상)인 경우 + // if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay) >= 3) { + // data[idx]!.rainEffectDay = 1; + // } + // } + // } for(let idx = 0; idx < data.length; idx++) { if(data[idx] && data[idx]?.rainEffectDay === 1) { @@ -63,13 +87,20 @@ export default function CalcRainEffect(data : any, weather='ALL') { } } - let rtnData : any = []; + // if (weather === 'ALL') { + // rtnData = data; + // } else if (weather === 'SUNNY') { + // rtnData = data.filter((item: any) => item.rainEffectDay === 0); + // } else { + // rtnData = data.filter((item: any) => item.rainEffectDay === 1); + // } + if (weather === 'ALL') { - rtnData = data; + rtnData = rtnDataAll; } else if (weather === 'SUNNY') { - rtnData = data.filter((item: any) => item.rainEffectDay === 0); + rtnData = rtnDataSunny; } else { - rtnData = data.filter((item: any) => item.rainEffectDay === 1); + rtnData = rtnDataRain; } return rtnData; } \ No newline at end of file diff --git a/apps/fo/app/components/common/FacilityTermModalHeader.tsx b/apps/fo/app/components/common/FacilityTermModalHeader.tsx index 52cee2ea3..84d6353b6 100644 --- a/apps/fo/app/components/common/FacilityTermModalHeader.tsx +++ b/apps/fo/app/components/common/FacilityTermModalHeader.tsx @@ -41,6 +41,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ const isDateInRanges = (date: Date) => { const standYear = parseInt(searchYear); + const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); const dateRanges:{start:Date, end:Date}[] = []; if (tabName.includes("_summer")) { @@ -51,7 +52,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ } else if (tabName.includes("_winter")) { dateRanges.push({ start: new Date(standYear, 0, 1), - end: new Date(standYear, 1, 28) + end: new Date(standYear, 1, isLeapYear ? 29 : 28) }); } else { dateRanges.push({ @@ -70,6 +71,8 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ useEffect(() => { let startDate = new Date(Number(searchYear), 0, 1); let endDate = new Date(Number(searchYear), 11, 31); + const standYear = Number(searchYear); + const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); if(tabName.includes("_summer")) { startDate = new Date(Number(searchYear), 5, 1); @@ -78,7 +81,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ setEndDate(endDate); } else if (tabName.includes("_winter")) { startDate = new Date(Number(searchYear), 0, 1); - endDate = new Date(Number(searchYear), 1, 28); + endDate = new Date(Number(searchYear), 1, isLeapYear ? 29 : 28); setStartDate(startDate); setEndDate(endDate); } else { diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index 77d96fff6..a1a5e22d1 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -216,7 +216,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( <UiModal body={<FlowRateModal fcltyName={fcltyNm} facilityCd={fcltyCd} searchYear={searchYearValue}></FlowRateModal>} - bodyClass="sm:max-w-[90vw] w-[1250px] h-[780px]" + bodyClass="sm:max-w-[90vw] w-[1250px] h-[100dvh] max-h-[780px]" open={selectedRow !== null} onOpenChange={(open: boolean) => !open && closeModal()} /> diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 44dabe9d3..8216dcd26 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1992,7 +1992,7 @@ export const dashBoardReducer = ( const rainRate = ['0', '0', '0', '0', '0', '0', '0', '0']; const rainDate = [0, 0, 0, 0, 0, 0, 0, 0]; const inflAmtCnt = [0, 0, 0, 0, 0, 0, 0, 0]; - const inflAmnt = [0, 0, 0, 0, 0, 0, 0, 0]; + const inflAmnt: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const fcltyCpct = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltBod: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltCod: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; @@ -2036,6 +2036,7 @@ export const dashBoardReducer = ( let totEfflWqltSs = 0; let totEfflWqltTn = 0; let totEfflWqltTp = 0; + let totInflAmnt = 0; rainEffectList.forEach((item: RainManageListProps) => { totInflAssctBfrWqltBod += item.inflAssctBfrWqltBod ? Number(item.inflAssctBfrWqltBod.toString().trim()) : 0; @@ -2048,6 +2049,7 @@ export const dashBoardReducer = ( totEfflWqltSs += item.efflWqltSs ? Number(item.efflWqltSs.toString().trim()) : 0; totEfflWqltTn += item.efflWqltTn ? Number(item.efflWqltTn.toString().trim()) : 0; totEfflWqltTp += item.efflWqltTp ? Number(item.efflWqltTp.toString().trim()) : 0; + totInflAmnt += item.inflAmnt ? Number(item.inflAmnt.toString().trim()) : 0; const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; @@ -2295,7 +2297,7 @@ export const dashBoardReducer = ( } } - for (let idx = 0; idx < inflAmnt.length; idx++) { + for (let idx = 1; idx < inflAmnt.length; idx++) { inflAmnt[idx] = calculateAverage(Number(inflAmnt[idx]), Number(inflAmtCnt[idx])); inflAssctBfrWqltBod[idx] = calculateAverage(Number(inflAssctBfrWqltBod[idx]), Number(inflAssctBfrWqltBodCnt[idx])); inflAssctBfrWqltToc[idx] = calculateAverage(Number(inflAssctBfrWqltToc[idx]), Number(inflAssctBfrWqltTocCnt[idx])); @@ -2314,7 +2316,8 @@ export const dashBoardReducer = ( return Number((arr.slice(1).reduce((sum, val) => sum + Number(val), 0))); }; - inflAmnt[0] = calculateAverage(calculateTotal(inflAmnt), dataIsCount); + // console.log(totInflAmnt); + inflAmnt[0] = calculateAverage(totInflAmnt, totItemCnt); fcltyCpct[0] = calculateTotal(fcltyCpct); inflAssctBfrWqltBod[0] = Number((Math.round((totInflAssctBfrWqltBod / totItemCnt) * 10) / 10).toFixed(1)); inflAssctBfrWqltToc[0] = Number((Math.round((totInflAssctBfrWqltToc / totItemCnt) * 10) / 10).toFixed(1)); From 58c8f118d3897c27f911d63e6052a29c37d4801e Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 16:34:52 +0900 Subject: [PATCH 43/92] =?UTF-8?q?fo:=20dashboard=20=EA=B0=95=EC=9A=B0?= =?UTF-8?q?=EC=9D=BC=EC=9A=B4=EC=98=81=ED=98=84=ED=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/components/common/CalcRainEffect.tsx | 6 +++--- apps/fo/app/store/dashboard/index.tsx | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index 0388c5951..a85f35443 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -10,9 +10,9 @@ */ export default function CalcRainEffect(data : any, weather='ALL') { - let rtnDataAll : any = []; - let rtnDataSunny : any = []; - let rtnDataRain : any = []; + const rtnDataAll : any = []; + const rtnDataSunny : any = []; + const rtnDataRain : any = []; let rtnData : any = []; let rainEffectStd = 0; data.forEach(item => { diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 8216dcd26..572912a53 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -2289,13 +2289,13 @@ export const dashBoardReducer = ( return count > 0 ? Number((value / count)) : 0; }; - // 데이터 있는 항목만 계산 - let dataIsCount = 0; - for (let idx = 0; idx < inflAmnt.length; idx++) { - if (Number(inflAmnt[idx]) > 0) { - dataIsCount++; - } - } + // // 데이터 있는 항목만 계산 + // let dataIsCount = 0; + // for (let idx = 0; idx < inflAmnt.length; idx++) { + // if (Number(inflAmnt[idx]) > 0) { + // dataIsCount++; + // } + // } for (let idx = 1; idx < inflAmnt.length; idx++) { inflAmnt[idx] = calculateAverage(Number(inflAmnt[idx]), Number(inflAmtCnt[idx])); From 54c958e8fa832e1935ccb1c63908689196a0926d Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 9 Jan 2026 18:10:19 +0900 Subject: [PATCH 44/92] =?UTF-8?q?fo:=20excel=20=EC=BB=AC=EB=9F=BC=20?= =?UTF-8?q?=EC=88=9C=EC=84=9C=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/modal/page.tsx | 3 ++- .../(with-layout)/sewageOccur/modal/page.tsx | 23 +++++++++++-------- .../src/ui/excel/index.tsx | 4 ++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx index 061d1738d..811f1c0ff 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/modal/page.tsx @@ -174,7 +174,8 @@ export default function PrecipitationModal(props: PrecipitationModalProps) { } if (excelDownList && excelDownList.length > 0) { - downloadExcelHeaders({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황', sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1' }); + downloadExcelHeaders({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황' + , sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1', headers }); } else if (totData.length == 0) { alert('다운받을 데이터가 없습니다.'); } diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx index bc7fec4e8..223dc055a 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/modal/page.tsx @@ -8,7 +8,7 @@ import { roundNumber } from "@/app/components/common/DataForm"; import { useFoStore } from "@/app/store"; import type { modalTableType } from "@/app/store/sewageOccur"; -import { DateMonthPicker, downloadExcel, UiTable } from "@common/business_components/ui"; +import { DateMonthPicker, downloadExcelHeaders, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui"; import { useEffect, useState } from "react"; @@ -69,20 +69,25 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd } }, [endYearMonth, startYearMonth]); - const excelDownload = () => { + const excelDownload = () => { + // 헤더 순서를 명시적으로 정의 + const headers = ["날짜", "물사용량(m³/일)", "오수전환율(%)", "오수발생량 추정(m³/일)"] as const; + const excelDownList: any[] = []; if(detailList.length > 0){ detailList.forEach((item) => { - excelDownList.push({ - "날짜": item.msrDt, - "물사용량(m³/일)": roundNumber(item.waterUsage, 0), - "오수전환율(%)": roundNumber(item.swageChangePercent, 0), - "오수발생량 추정(m³/일)": roundNumber(item.estimationSewage, 0), - }); + // 순서를 보장하기 위해 헤더 순서대로 객체 생성 + const row: Record<string, string | number> = {}; + row[headers[0]] = item.msrDt; + row[headers[1]] = roundNumber(item.waterUsage, 0); + row[headers[2]] = roundNumber(item.swageChangePercent, 0); + row[headers[3]] = roundNumber(item.estimationSewage, 0); + excelDownList.push(row); }); } if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 오수발생량 추정', sheetNameArray: [props.fcltyName + ' 오수발생량 추정'], headerRange: 'A1:D1' }); + downloadExcelHeaders({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 오수발생량 추정' + , sheetNameArray: [props.fcltyName + ' 오수발생량 추정'], headerRange: 'A1:D1', headers }); } else if (detailList.length == 0) { alert('다운받을 데이터가 없습니다.'); } diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index 0b2659b69..048a0cc42 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -6,7 +6,7 @@ type ExcelDownloadProps = { fileName: string; sheetNameArray: string[]; headerRange?: string; - headers?: string[]|undefined; + headers?: readonly string[]|undefined; decimalArray0? : number[]; decimalArray1? : number[]; decimalArray2? : number[]; @@ -23,7 +23,7 @@ export const downloadExcel = ({ data, fileName = new Date().getTime().toString() export const downloadExcelHeaders = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', headers}: ExcelDownloadProps) => { const dataArray = Array.isArray(data) ? data : [data]; // headers가 제공되면 열 순서를 강제함 - const worksheet = XLSX.utils.json_to_sheet(dataArray, headers ? { header: headers } : undefined); + const worksheet = XLSX.utils.json_to_sheet(dataArray, headers ? { header: [...headers] } : undefined); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); From ac8c58d2a9d6626ca5c0d4529c3aba34533c9f7b Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sat, 10 Jan 2026 15:33:36 +0900 Subject: [PATCH 45/92] =?UTF-8?q?fo:=20dashboard=20=EA=B0=95=EC=9A=B0?= =?UTF-8?q?=EC=9D=BC=EC=9A=B4=EC=98=81=ED=98=84=ED=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/common/CalcRainEffect.tsx | 71 +++-- .../pages/(with-layout)/dashboard/page.tsx | 9 +- .../dashboard/rainManage/page.tsx | 30 +- .../(with-layout)/flowRate/modal/page.tsx | 127 ++++---- apps/fo/app/store/dashboard/index.tsx | 130 +++++--- apps/fo/app/store/flowRate/index.tsx | 281 +++++++++--------- 6 files changed, 354 insertions(+), 294 deletions(-) diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index a85f35443..3ea198016 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -9,15 +9,16 @@ * @author jsyang */ -export default function CalcRainEffect(data : any, weather='ALL') { - const rtnDataAll : any = []; - const rtnDataSunny : any = []; - const rtnDataRain : any = []; - let rtnData : any = []; - let rainEffectStd = 0; - data.forEach(item => { +export default function CalcRainEffect(data: any, weather = 'ALL') { + const rtnDataAll: any = []; + const rtnDataSunny: any = []; + const rtnDataRain: any = []; + let rtnData: any = []; + let rainEffectStd = 0; + for (let idx = 0; idx < data.length; idx++) { + const item = data[idx]; if (item.infoRnDay == null || item.infoRnDay == 'x' || item.infoRnDay == '') item.infoRnDay = 0; - if(Number(item.infoRnDay) >= 3) { // 강우일 + if (Number(item.infoRnDay) >= 3) { // 강우일 rainEffectStd = 2; item.toBeInfoRnDay = item.infoRnDay; } else { @@ -29,14 +30,26 @@ export default function CalcRainEffect(data : any, weather='ALL') { rtnDataSunny.push(item); } else if (rainEffectStd >= 0) { // 강우일 + 강우영향일 item.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; + } + } rtnDataRain.push(item); } - - rtnDataAll.push(item); - }); - - // // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) + rtnDataAll.push(item); + } + + + // // 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일) // for(let idx = 0; idx < data.length; idx++) { // const item = data[idx]; // if(item){ @@ -70,22 +83,22 @@ 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; - } - } - } - } + // 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; + // } + // } + // } + // } // if (weather === 'ALL') { // rtnData = data; diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index b94fc21c1..6ab18b825 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -6,7 +6,10 @@ "use client" import { useFoStore } from "@/app/store"; -import { ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv, SelectBox, UITab, type SelectDataType } from "@common/business_components"; +import { + ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv + , SelectBox, UITab, type SelectDataType +} from "@common/business_components"; import { Button, TabsContent } from "@common/components/ui"; import { useEffect, useState } from "react"; import DashBoardFclty from "../dashboardMain/page"; @@ -50,9 +53,9 @@ type FacilityType = { export default function DashBoard() { // 입력값 상태 관리 - const { Common, initializeCommonData, searchMainGraph, searchRainManage, searchOperationStatus, OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state); + const { Common, initializeCommonData, searchMainGraph, searchRainManage, searchOperationStatus + , OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state); const [activeTab, setActiveTab] = useState<string>('facilityInfo'); - const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]); const [sidoValue, setSidoValue] = useState<string>('0'); const [sigunValue, setSigunValue] = useState<string>('0'); diff --git a/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx index e084bf04d..55e6275c8 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/rainManage/page.tsx @@ -15,27 +15,13 @@ export type facilityInfoProps = { fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[]; }; -export default function RainManageTab({searchYear = '', fcltyList = []}: facilityInfoProps) { - - const { - Common, - searchRainManage, - RainManage - } = useFoStore((state) => state); +export default function RainManageTab({ searchYear = '', fcltyList = [] }: facilityInfoProps) { + const { Common, searchRainManage, RainManage } = useFoStore((state) => state); const [hasSearched, setHasSearched] = useState(false); - // 이전 시설코드 저장 - const [prevFacilityCode, setPrevFacilityCode] = useState<string>(''); - - const { - isInit, - } = Common; - - const { - upHeadListRainManage, - rainManageList, - } = RainManage; - + const [prevFacilityCode, setPrevFacilityCode] = useState<string>(''); // 이전 시설코드 저장 + const { isInit, } = Common; + const { upHeadListRainManage, rainManageList, } = RainManage; const tableData = fcltyList; useEffect(() => { @@ -50,17 +36,17 @@ export default function RainManageTab({searchYear = '', fcltyList = []}: facilit useEffect(() => { setHasSearched(false); }, [searchYear]); - + return ( <div> - <UiTable + <UiTable headName="" tableData={rainManageList} headlist={upHeadListRainManage} pageSize={0} total={0} cellClick={undefined} - onPageChange={() => {}} + onPageChange={() => { }} widthFixed={true} > </UiTable> 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 42512f802..822b52979 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -34,11 +34,8 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const [copyYearList, setCopyYearList] = useState<FlowRateModalInterface[]>([]); const [isLoading, setIsLoading] = useState(true); const prevExcelListRef = useRef<modalExcelType[] | null>(null); - const { - modalFlowRateListYear, - upHeadListFlowRateModalYear, - } = FlowRateModal; - + const { modalFlowRateListYear, upHeadListFlowRateModalYear, } = FlowRateModal; + const ref = useRef<ReturnType<FlowRateModalInterface>>({ startDate: new Date(), endDate: new Date(), @@ -52,11 +49,11 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const filteredData = setFilterAfterData(returnType.filteredList as FlowRateModalInterface[]); setCopyYearList(filteredData); }, []); - + // 필터링 된 후 최대, 최소, 평균 값 계산 const setFilterAfterData = (filteredData: FlowRateModalInterface[]) => { if (!filteredData || filteredData.length === 0) return []; - + // 쉼표가 포함된 문자열을 숫자로 변환하는 함수 const parseNumber = (value: string | number | null | undefined): number => { if (value === null || value === undefined || value === '') return 0; @@ -89,7 +86,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st let avginfoRnDay = 0; let avgNoProcessInflAmnt = 0; let noProcessInflAmntCnt = 0; - + filteredData.forEach((item: FlowRateModalInterface) => { const totInflAmnt = parseNumber(item.totInflAmnt); const inflAmnt = parseNumber(item.inflAmnt); @@ -119,24 +116,24 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st avgefflAmnt += efflAmnt; avginfoRnDay += infoRnDay; - if(item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined){ - const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',','')); + if (item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined) { + const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',', '')); avgNoProcessInflAmnt += noProcessInflAmnt; maxNoProcessInflAmnt = Math.max(maxNoProcessInflAmnt, noProcessInflAmnt); minNoProcessInflAmnt = Math.min(minNoProcessInflAmnt, noProcessInflAmnt); - noProcessInflAmntCnt +=1; + noProcessInflAmntCnt += 1; } }); const newFilteredData = [ { msrDt: '평균', - totInflAmnt: avgtotInflAmnt && avgtotInflAmnt!=0 ? roundUp((avgtotInflAmnt / filteredData.length), 0) : 0, - inflAmnt: avginflAmnt && avginflAmnt!=0 ? roundUp((avginflAmnt / filteredData.length), 0) : 0, - sumFlow: avgsumFlow && avgsumFlow!=0 ? roundUp((avgsumFlow / filteredData.length), 0) : 0, - returnAmnt: avgreturnAmnt && avgreturnAmnt!=0 ? roundUp((avgreturnAmnt / filteredData.length), 0) : 0, - efflAmnt: avgefflAmnt && avgefflAmnt!=0 ? roundUp((avgefflAmnt / filteredData.length), 0) : 0, - noProcessInflAmnt : roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0), + totInflAmnt: avgtotInflAmnt && avgtotInflAmnt != 0 ? roundUp((avgtotInflAmnt / filteredData.length), 0) : 0, + inflAmnt: avginflAmnt && avginflAmnt != 0 ? roundUp((avginflAmnt / filteredData.length), 0) : 0, + sumFlow: avgsumFlow && avgsumFlow != 0 ? roundUp((avgsumFlow / filteredData.length), 0) : 0, + returnAmnt: avgreturnAmnt && avgreturnAmnt != 0 ? roundUp((avgreturnAmnt / filteredData.length), 0) : 0, + efflAmnt: avgefflAmnt && avgefflAmnt != 0 ? roundUp((avgefflAmnt / filteredData.length), 0) : 0, + noProcessInflAmnt: roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0), infoRnDay: avginfoRnDay > 0 ? roundUp((avginfoRnDay / filteredData.length), 1) : '0.0', rainEffectDay: 0, }, @@ -147,7 +144,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st sumFlow: roundUp(maxsumFlow, 0), returnAmnt: roundUp(maxreturnAmnt, 0), efflAmnt: roundUp(maxefflAmnt, 0), - noProcessInflAmnt : roundNumber(maxNoProcessInflAmnt, 0), + noProcessInflAmnt: roundNumber(maxNoProcessInflAmnt, 0), infoRnDay: maxinfoRnDay > 0 ? roundUp(maxinfoRnDay, 1) : '0.0', rainEffectDay: 0, }, @@ -158,7 +155,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st sumFlow: roundUp(minsumFlow, 0), returnAmnt: roundUp(minreturnAmnt, 0), efflAmnt: roundUp(minefflAmnt, 0), - noProcessInflAmnt : roundNumber(minNoProcessInflAmnt, 0), + noProcessInflAmnt: roundNumber(minNoProcessInflAmnt, 0), infoRnDay: mininfoRnDay > 0 ? roundUp(mininfoRnDay, 1) : '0.0', rainEffectDay: 0, }, @@ -185,7 +182,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const excelDownload = () => { const excelDownList: modalExcelType[] = []; - if(copyYearList.length > 0){ + if (copyYearList.length > 0) { copyYearList.forEach((item) => { excelDownList.push({ "날짜": item.msrDt, @@ -200,7 +197,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st }); } if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:H1' }); + 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('다운받을 데이터가 없습니다.'); } @@ -210,7 +207,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st return ( <> <UITab tabList={tabList} defaultValue="tab_term_year"> - <Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownload}> + <Button className={btnClass} style={{ float: 'right' }} color="green" onClick={excelDownload}> {"엑셀다운로드"} </Button> <TabsContent value="tab_term_year"> @@ -224,16 +221,16 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> - <UiTable - headName="유량현황" - tableData={copyYearList} - headlist={upHeadListFlowRateModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[370px]" - boldArray={[0,1,2]} + <UiTable + headName="유량현황" + tableData={copyYearList} + headlist={upHeadListFlowRateModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => { }} + className="h-[370px]" + boldArray={[0, 1, 2]} /> </div> <div className="mt-20"> @@ -251,16 +248,16 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> - <UiTable - headName="유량현황" - tableData={copyYearList} - headlist={upHeadListFlowRateModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[370px]" - boldArray={[0,1,2]} + <UiTable + headName="유량현황" + tableData={copyYearList} + headlist={upHeadListFlowRateModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => { }} + className="h-[370px]" + boldArray={[0, 1, 2]} /> </div> <div className="mt-20"> @@ -278,23 +275,23 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> - <UiTable - headName="유량현황" - tableData={copyYearList} - headlist={upHeadListFlowRateModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[370px]" - boldArray={[0,1,2]} + <UiTable + headName="유량현황" + tableData={copyYearList} + headlist={upHeadListFlowRateModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => { }} + className="h-[370px]" + boldArray={[0, 1, 2]} /> </div> <div className="mt-20"> <UnderComment commentArray={[commentArray]} /> </div> </TabsContent> - <TabsContent value="tab_term_chuncheon"> + <TabsContent value="tab_term_chuncheon"> <FacilityTermModalHeader<FlowRateModalInterface> searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -305,16 +302,16 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> - <UiTable - headName="유량현황" - tableData={copyYearList} - headlist={upHeadListFlowRateModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[370px]" - boldArray={[0,1,2]} + <UiTable + headName="유량현황" + tableData={copyYearList} + headlist={upHeadListFlowRateModalYear} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={() => { }} + className="h-[370px]" + boldArray={[0, 1, 2]} /> </div> <div className="mt-20"> @@ -332,10 +329,10 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> - <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}/> + <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} /> </div> <div className="mt-20"> - <UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)","강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} /> + <UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)", "강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} /> </div> </TabsContent> </UITab> diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 572912a53..8f3b4dd8a 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1142,6 +1142,9 @@ export type DashBoardType = { mainGraphData: any; mainGraphYear: string; mainGraphFcltyCd: string; + flowRateData: any; + flowRateYear: string; + flowRateFcltyCd: string; }, DrainageEquipment: { @@ -1208,6 +1211,9 @@ export const dashBoardInitState: DashBoardType = { mainGraphData: null, mainGraphYear: '', mainGraphFcltyCd: '', + flowRateData: null, + flowRateYear: '', + flowRateFcltyCd: '', }, DrainageEquipment: { @@ -1515,7 +1521,24 @@ export const dashBoardReducer = ( // 연계처리수,지하수유입량 const bscFctCd = fcltyCd; - const res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 + let res2: any = { data: [] }; + + // 이미 조회된 데이터가 있는지 확인 (연도와 시설코드가 같을 때만) + if (state.RainManage.flowRateYear === searchYear && state.RainManage.flowRateFcltyCd === fcltyCd && state.RainManage.flowRateData) { + res2 = state.RainManage.flowRateData; + } else { + res2 = await fetchFlowRateModalList(bscFctCd, searchYear); // /fclt/flow/ - 일별 유량 조회 + // 조회된 데이터 저장 + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + flowRateData: res2, + flowRateYear: searchYear, + flowRateFcltyCd: fcltyCd, + } + })); + } //const calData = CalcRainEffect(clone(res2.data), 'SUNNY'); //const calRainData = CalcRainEffect(clone(res2.data), 'RAIN'); @@ -1967,6 +1990,24 @@ export const dashBoardReducer = ( })); } + let res2: any = { data: [] }; + // 이미 조회된 데이터가 있는지 확인 (연도와 시설코드가 같을 때만) + if (state.RainManage.flowRateYear === searchYear && state.RainManage.flowRateFcltyCd === fcltyCd && state.RainManage.flowRateData) { + res2 = state.RainManage.flowRateData; + } else { + res2 = await fetchFlowRateModalList(fcltyCd, searchYear); // /fclt/flow/ - 일별 유량 조회 + // 조회된 데이터 저장 + set((state: DashBoardType) => ({ + ...state, + RainManage: { + ...state.RainManage, + flowRateData: res2, + flowRateYear: searchYear, + flowRateFcltyCd: fcltyCd, + } + })); + } + set((state: DashBoardType) => ({ ...state, RainManage: { @@ -1990,10 +2031,9 @@ export const dashBoardReducer = ( const itemList = ['계', '3~10mm 미만', '10~20mm 미만', '20~30mm 미만', '30~40mm 미만', '40~50mm 미만', '50~60mm 미만', '60mm 이상']; const rainRate = ['0', '0', '0', '0', '0', '0', '0', '0']; - const rainDate = [0, 0, 0, 0, 0, 0, 0, 0]; - const inflAmtCnt = [0, 0, 0, 0, 0, 0, 0, 0]; + const rainDate: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const inflAmnt: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; - const fcltyCpct = [0, 0, 0, 0, 0, 0, 0, 0]; + const fcltyCpct: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltBod: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltCod: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; const dsInflWqltSs: number[] = [0, 0, 0, 0, 0, 0, 0, 0]; @@ -2054,9 +2094,8 @@ export const dashBoardReducer = ( const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; if (toBeRain >= 3 && toBeRain < 10) { - rainDate[1] = Number(rainDate[1] || 0) + 1; - inflAmtCnt[1] = Number(inflAmtCnt[1] || 0) + 1; - inflAmnt[1] = Number(inflAmnt[1] || 0) + Number(item.inflAmnt || 0); + rainDate[1] = (rainDate[1] || 0) + 1; + inflAmnt[1] = (inflAmnt[1] || 0) + Number(item.inflAmnt || 0); fcltyCpct[1] = 0; inflAssctBfrWqltBodCnt[1] = Number(inflAssctBfrWqltBodCnt[1] || 0) + 1; inflAssctBfrWqltBod[1] = Number(inflAssctBfrWqltBod[1] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2079,9 +2118,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[1] = Number(efflWqltTpCnt[1] || 0) + 1; efflWqltTp[1] = Number(efflWqltTp[1] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 10 && toBeRain < 20) { - rainDate[2] = Number(rainDate[2] || 0) + 1; - inflAmtCnt[2] = Number(inflAmtCnt[2] || 0) + 1; - inflAmnt[2] = Number(inflAmnt[2] || 0) + Number(item.inflAmnt || 0); + rainDate[2] = (rainDate[2] || 0) + 1; + inflAmnt[2] = (inflAmnt[2] || 0) + Number(item.inflAmnt || 0); fcltyCpct[2] = 0; inflAssctBfrWqltBodCnt[2] = Number(inflAssctBfrWqltBodCnt[2] || 0) + 1; inflAssctBfrWqltBod[2] = Number(inflAssctBfrWqltBod[2] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2104,9 +2142,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[2] = Number(efflWqltTpCnt[2] || 0) + 1; efflWqltTp[2] = Number(efflWqltTp[2] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 20 && toBeRain < 30) { - rainDate[3] = Number(rainDate[3] || 0) + 1; - inflAmtCnt[3] = Number(inflAmtCnt[3] || 0) + 1; - inflAmnt[3] = Number(inflAmnt[3] || 0) + Number(item.inflAmnt || 0); + rainDate[3] = (rainDate[3] || 0) + 1; + inflAmnt[3] = (inflAmnt[3] || 0) + Number(item.inflAmnt || 0); fcltyCpct[3] = 0; inflAssctBfrWqltBodCnt[3] = Number(inflAssctBfrWqltBodCnt[3] || 0) + 1; inflAssctBfrWqltBod[3] = Number(inflAssctBfrWqltBod[3] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2129,9 +2166,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[3] = Number(efflWqltTpCnt[3] || 0) + 1; efflWqltTp[3] = Number(efflWqltTp[3] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 30 && toBeRain < 40) { - rainDate[4] = Number(rainDate[4] || 0) + 1; - inflAmtCnt[4] = Number(inflAmtCnt[4] || 0) + 1; - inflAmnt[4] = Number(inflAmnt[4] || 0) + Number(item.inflAmnt || 0); + rainDate[4] = (rainDate[4] || 0) + 1; + inflAmnt[4] = (inflAmnt[4] || 0) + Number(item.inflAmnt || 0); fcltyCpct[4] = item.inflAmnt && Number(item.inflAmnt) !== 0 ? Number(Math.round(Number(item.inflAmnt) / Number(item.fctCpc) * 10) / 10) : 0; inflAssctBfrWqltBodCnt[4] = Number(inflAssctBfrWqltBodCnt[4] || 0) + 1; inflAssctBfrWqltBod[4] = Number(inflAssctBfrWqltBod[4] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2154,9 +2190,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[4] = Number(efflWqltTpCnt[4] || 0) + 1; efflWqltTp[4] = Number(efflWqltTp[4] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 40 && toBeRain < 50) { - rainDate[5] = Number(rainDate[5] || 0) + 1; - inflAmtCnt[5] = Number(inflAmtCnt[5] || 0) + 1; - inflAmnt[5] = Number(inflAmnt[5] || 0) + Number(item.inflAmnt || 0); + rainDate[5] = (rainDate[5] || 0) + 1; + inflAmnt[5] = (inflAmnt[5] || 0) + Number(item.inflAmnt || 0); fcltyCpct[5] = 0; inflAssctBfrWqltBodCnt[5] = Number(inflAssctBfrWqltBodCnt[5] || 0) + 1; inflAssctBfrWqltBod[5] = Number(inflAssctBfrWqltBod[5] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2179,9 +2214,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[5] = Number(efflWqltTpCnt[5] || 0) + 1; efflWqltTp[5] = Number(efflWqltTp[5] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 50 && toBeRain < 60) { - rainDate[6] = Number(rainDate[6] || 0) + 1; - inflAmtCnt[6] = Number(inflAmtCnt[6] || 0) + 1; - inflAmnt[6] = Number(inflAmnt[6] || 0) + Number(item.inflAmnt || 0); + rainDate[6] = (rainDate[6] || 0) + 1; + inflAmnt[6] = (inflAmnt[6] || 0) + Number(item.inflAmnt || 0); fcltyCpct[6] = 0; inflAssctBfrWqltBodCnt[6] = Number(inflAssctBfrWqltBodCnt[6] || 0) + 1; inflAssctBfrWqltBod[6] = Number(inflAssctBfrWqltBod[6] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2204,9 +2238,8 @@ export const dashBoardReducer = ( efflWqltTpCnt[6] = Number(efflWqltTpCnt[6] || 0) + 1; efflWqltTp[6] = Number(efflWqltTp[6] || 0) + Number(item.efflWqltTp || 0); } else if (toBeRain >= 60) { - rainDate[7] = Number(rainDate[7] || 0) + 1; - inflAmtCnt[7] = Number(inflAmtCnt[7] || 0) + 1; - inflAmnt[7] = Number(inflAmnt[7] || 0) + Number(item.inflAmnt || 0); + rainDate[7] = (rainDate[7] || 0) + 1; + inflAmnt[7] = (inflAmnt[7] || 0) + Number(item.inflAmnt || 0); fcltyCpct[7] = 0; inflAssctBfrWqltBodCnt[7] = Number(inflAssctBfrWqltBodCnt[7] || 0) + 1; inflAssctBfrWqltBod[7] = Number(inflAssctBfrWqltBod[7] || 0) + Number(item.inflAssctBfrWqltBod || 0); @@ -2231,6 +2264,40 @@ export const dashBoardReducer = ( } }); + // 유량 = 순수하수 + 연계처리수 + 총인설비반류수 + const rainEffFlowList: any[] = CalcRainEffect(res2.data, 'RAIN_DAY'); + totInflAmnt = 0; inflAmnt.fill(0); rainDate.fill(0); + rainEffFlowList.forEach((item: any) => { // --일별 유량 start + const toBeRain = item.toBeInfoRnDay ? Number(item.toBeInfoRnDay) : 0; + const inflAmntOne = item.inflAmnt && item.inflAmnt !== 'x' ? Number(item.inflAmnt.toString().trim()) : 0; + const sumFlowOne = item.sumFlow && item.sumFlow !== 'x' ? Number(item.sumFlow.toString().trim()) : 0; + const returnAmntOne = item.returnAmnt && item.returnAmnt !== 'x' ? Number(item.returnAmnt.toString().trim()) : 0; + const inflowOne = inflAmntOne + sumFlowOne + returnAmntOne; + totInflAmnt = totInflAmnt + inflowOne; // 유량합계 + if (toBeRain >= 3 && toBeRain < 10) { + inflAmnt[1] = (inflAmnt[1] || 0) + inflowOne; + rainDate[1] = (rainDate[1] || 0) + 1; + } else if (toBeRain >= 10 && toBeRain < 20) { + inflAmnt[2] = (inflAmnt[2] || 0) + inflowOne; + rainDate[2] = (rainDate[2] || 0) + 1; + } else if (toBeRain >= 20 && toBeRain < 30) { + inflAmnt[3] = (inflAmnt[3] || 0) + inflowOne; + rainDate[3] = (rainDate[3] || 0) + 1; + } else if (toBeRain >= 30 && toBeRain < 40) { + inflAmnt[4] = (inflAmnt[4] || 0) + inflowOne; + rainDate[4] = (rainDate[4] || 0) + 1; + } else if (toBeRain >= 40 && toBeRain < 50) { + inflAmnt[5] = (inflAmnt[5] || 0) + inflowOne; + rainDate[5] = (rainDate[5] || 0) + 1; + } else if (toBeRain >= 50 && toBeRain < 60) { + inflAmnt[6] = (inflAmnt[6] || 0) + inflowOne; + rainDate[6] = (rainDate[6] || 0) + 1; + } else if (toBeRain >= 60) { + inflAmnt[7] = (inflAmnt[7] || 0) + inflowOne; + rainDate[7] = (rainDate[7] || 0) + 1; + } + }); // --일별 유량 end + // Process the data and create rain management list if (res.data && res.data.dsWqltObjs && res.data.dsWqltObjs.length > 0) { // 설계 유입수질 데이터 가져오기 - 0값이 있으면 이전 차수에서 가져오기 @@ -2289,16 +2356,8 @@ export const dashBoardReducer = ( return count > 0 ? Number((value / count)) : 0; }; - // // 데이터 있는 항목만 계산 - // let dataIsCount = 0; - // for (let idx = 0; idx < inflAmnt.length; idx++) { - // if (Number(inflAmnt[idx]) > 0) { - // dataIsCount++; - // } - // } - for (let idx = 1; idx < inflAmnt.length; idx++) { - inflAmnt[idx] = calculateAverage(Number(inflAmnt[idx]), Number(inflAmtCnt[idx])); + inflAmnt[idx] = rainDate[idx] ? Math.round((inflAmnt[idx] || 0) / (rainDate[idx] || 0)) : 0; inflAssctBfrWqltBod[idx] = calculateAverage(Number(inflAssctBfrWqltBod[idx]), Number(inflAssctBfrWqltBodCnt[idx])); inflAssctBfrWqltToc[idx] = calculateAverage(Number(inflAssctBfrWqltToc[idx]), Number(inflAssctBfrWqltTocCnt[idx])); inflAssctBfrWqltSs[idx] = calculateAverage(Number(inflAssctBfrWqltSs[idx]), Number(inflAssctBfrWqltSsCnt[idx])); @@ -2316,8 +2375,9 @@ export const dashBoardReducer = ( return Number((arr.slice(1).reduce((sum, val) => sum + Number(val), 0))); }; + // console.log(totInflAmnt); - inflAmnt[0] = calculateAverage(totInflAmnt, totItemCnt); + inflAmnt[0] = Math.round((totInflAmnt / totItemCnt)); // calculateAverage(totInflAmnt, totItemCnt); fcltyCpct[0] = calculateTotal(fcltyCpct); inflAssctBfrWqltBod[0] = Number((Math.round((totInflAssctBfrWqltBod / totItemCnt) * 10) / 10).toFixed(1)); inflAssctBfrWqltToc[0] = Number((Math.round((totInflAssctBfrWqltToc / totItemCnt) * 10) / 10).toFixed(1)); diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 94d4b9326..432bc5ba5 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -1,6 +1,6 @@ import { getFetch } from "@/app/components/api"; import type { TableUpperProps } from "../dashboard"; -import DataForm, { roundNumber } from "@/app/components/common/DataForm"; +import DataForm from "@/app/components/common/DataForm"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty"; import CommaToNumber from "@/app/components/common/CommaToNumber"; @@ -12,34 +12,34 @@ import CommaToNumber from "@/app/components/common/CommaToNumber"; /** * (1) 메인페이지 */ -const FlowRateSearchLabelArray:string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; +const FlowRateSearchLabelArray: string[] = ['구분', '시도', '시군구', '용량별', '시설명', '조회기간', '시설상태', '권역', '단위유역', '중권역', '환경청별']; export type flowRateListProps = { - bscFctCd : string, - sido : string, - gugun : string, - bscFctNm : string, - daddr : string, - fctCpc : number, - lclgvrnmntNm : string, - totInflAmnt : number | '', - inflAmnt : number | '', - sumFlow : number | '', - returnAmnt : number | '', - efflAmnt : number | '', - rgnNm : string, - rvbsn : string, - lgbsn : string, - mdmbsn : string, - infoRnDay : number | '', + bscFctCd: string, + sido: string, + gugun: string, + bscFctNm: string, + daddr: string, + fctCpc: number, + lclgvrnmntNm: string, + totInflAmnt: number | '', + inflAmnt: number | '', + sumFlow: number | '', + returnAmnt: number | '', + efflAmnt: number | '', + rgnNm: string, + rvbsn: string, + lgbsn: string, + mdmbsn: string, + infoRnDay: number | '', } export interface ExcelType { 시설코드: string, - 권역:string|'', - 단위유역:string|'', - 중권역:string|'', - 환경청:string|'', + 권역: string | '', + 단위유역: string | '', + 중권역: string | '', + 환경청: string | '', 시도: string, 시군구: string, 시설이름: string, @@ -66,105 +66,105 @@ export type modalExcelType = { * (2) 모달 */ export interface FlowRateModalInterface { - msrDt : string, - totInflAmnt : number | '', - inflAmnt : number | '', - sumFlow : number | '', - returnAmnt : number | '', - efflAmnt : number | '', - infoRnDay : number | string | '', - rainEffectDay : number | string | '' , - noProcessInflAmnt : number | string | '' + msrDt: string, + totInflAmnt: number | '', + inflAmnt: number | '', + sumFlow: number | '', + returnAmnt: number | '', + efflAmnt: number | '', + infoRnDay: number | string | '', + rainEffectDay: number | string | '', + noProcessInflAmnt: number | string | '' } export type FlowRateModalProps = { - msrDt : string, - totInflAmnt : number, - inflAmnt : number, - sumFlow : number, - returnAmnt : number, - efflAmnt : number, - infoRnDay : number | string | '', - rainEffectDay : number | string | '', - noProcessInflAmnt : number | string | '' + msrDt: string, + totInflAmnt: number, + inflAmnt: number, + sumFlow: number, + returnAmnt: number, + efflAmnt: number, + infoRnDay: number | string | '', + rainEffectDay: number | string | '', + noProcessInflAmnt: number | string | '' } /**==================================== * Store - data ====================================*/ - /** - * (1) 메인페이지 - */ +/** +* (1) 메인페이지 +*/ // 리스트 (행정별) -const upHeadList1:TableUpperProps[] = [ +const upHeadList1: TableUpperProps[] = [ { id: "A", title: "행정명", row: 0, colSpan: 2, widthPercent: 16 }, - { id: "sido", title: "시도", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "gugun", title: "시군구", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10}, + { id: "sido", title: "시도", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "gugun", title: "시군구", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 }, { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, - { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 } + { id: "fctCpc", title: "시설용량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 } ]; // 리스트 (권역별) -const upHeadList2:TableUpperProps[] = [ +const upHeadList2: TableUpperProps[] = [ { id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 24 }, - { id: "rvbsn", title: "권역", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "lgbsn", title: "단위유역", upName:"upChangeRe", row:1, widthPercent: 8 }, - { id: "mdmbsn", title: "중권역", upName:"upChangeRe", row:1, widthPercent: 8 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe", row: 1, widthPercent: 8 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe", row: 1, widthPercent: 8 }, { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 }, { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, - { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 10 }, - { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 } + { id: "fctCpc", title: "시설용량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 } ]; // 리스트 (환경청별별) -const upHeadList3:TableUpperProps[] = [ +const upHeadList3: TableUpperProps[] = [ { id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 15 }, - { id: "rvbsn", title: "권역", upName:"upChangeRe1", row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", upName:"upChangeRe1", row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", upName:"upChangeRe1", row:1, widthPercent: 5 }, - { id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 7 }, - { id: "B", title: "행정명", row: 0 ,colSpan: 2, widthPercent: 10 }, - { id: "sido", title: "시도", upName:"upChangeRe2", row:1, widthPercent: 5 }, - { id: "gugun", title: "시군구", upName:"upChangeRe2", row:1, widthPercent: 5 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe1", row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", row: 1, widthPercent: 5 }, + { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "B", title: "행정명", row: 0, colSpan: 2, widthPercent: 10 }, + { id: "sido", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "gugun", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 7 }, { id: "daddr", title: "주소", row: 0, rowSpan: 2 }, - { id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }, - { id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 } + { id: "fctCpc", title: "시설용량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "totInflAmnt", title: "총 유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "inflAmnt", title: "하수유입량\n(m³/일)", align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "sumFlow", title: '연계처리량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 }, + { id: "efflAmnt", title: '방류량\n(m³/일)', align: "right", row: 0, rowSpan: 2, widthPercent: 7 } ]; -const flowRateList:flowRateListProps[] = [ +const flowRateList: flowRateListProps[] = [ ] /** * (2) 모달 */ -const upHeadListFlowRateModal:TableUpperProps[] = [ - { id: "msrDt", title: "날짜"}, - { id: "totInflAmnt", title: "총 유입량(m³/일)", align:"right"}, - { id: "inflAmnt", title: "하수유입량(m³/일)", align:"right"}, - { 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: "infoRnDay", title: "강우량(mm/일)", align:"right"} +const upHeadListFlowRateModal: TableUpperProps[] = [ + { id: "msrDt", title: "날짜" }, + { id: "totInflAmnt", title: "총 유입량(m³/일)", align: "right" }, + { id: "inflAmnt", title: "하수유입량(m³/일)", align: "right" }, + { 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: "infoRnDay", title: "강우량(mm/일)", align: "right" } ] -const modalFlowRateListYear:FlowRateModalProps[] = [ +const modalFlowRateListYear: FlowRateModalProps[] = [ ] /**==================================== @@ -172,12 +172,13 @@ const modalFlowRateListYear:FlowRateModalProps[] = [ ====================================*/ const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { try { - const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; const res = await getFetch('fo', url); return { data: res.data, count: res.count } } catch (error) { console.error('시설정보 유량현황 데이터를 가져오는데 실패했습니다:', error); + console.log(error); return { data: [], count: 0 }; } } @@ -186,12 +187,12 @@ export const fetchFlowRateModalList = async (bscFctCd: string, searchYear: strin try { const url = '/fclt/flow/' + bscFctCd + '/' + searchYear; const res = await getFetch('fo', url); - + // msrDt 오름차순으로 정렬 const sortedData = res.data.sort((a: FlowRateModalInterface, b: FlowRateModalInterface) => { return new Date(a.msrDt).getTime() - new Date(b.msrDt).getTime(); }); - + return { data: sortedData } } catch (error) { console.error('시설정보 유량현황 모달 데이터를 가져오는데 실패했습니다:', error); @@ -206,69 +207,69 @@ export const fetchFlowRateModalList = async (bscFctCd: string, searchYear: strin export type FlowRateSearchActions = { searchFlowRateList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void; - - searchFlowRateModalList : (bscFctCd: string, searchYear: string) => void; + + searchFlowRateModalList: (bscFctCd: string, searchYear: string) => void; } export type FlowRateSearchType = { FlowRateSearch: { isInit: boolean; - flowRateSearchLabelArray:string[]; + flowRateSearchLabelArray: string[]; }, - FlowRateList : { - isInit : boolean; + FlowRateList: { + isInit: boolean; upHeadList1: TableUpperProps[]; upHeadList2: TableUpperProps[]; upHeadList3: TableUpperProps[]; - flowRateList:flowRateListProps[]; + flowRateList: flowRateListProps[]; flowRateCount: number; excelList: ExcelType[]; isLoading: boolean; }, - FlowRateModal : { - isInit : boolean; - modalFlowRateListYear : FlowRateModalProps[]; - upHeadListFlowRateModalYear : TableUpperProps[]; + FlowRateModal: { + isInit: boolean; + modalFlowRateListYear: FlowRateModalProps[]; + upHeadListFlowRateModalYear: TableUpperProps[]; } } export type FlowRateSearchStore = FlowRateSearchType & FlowRateSearchActions; -const dataFormSetting=(item : flowRateListProps | FlowRateModalProps)=> { +const dataFormSetting = (item: flowRateListProps | FlowRateModalProps) => { DataForm({ type: 'date', column: 'msrDt', item: item as unknown as Record<string, unknown> }); - DataForm({ type: 'float0', column: 'totInflAmnt', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'sumFlow', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'efflWqltBod', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'returnAmnt', item: item as unknown as Record<string, unknown>}); - DataForm({ type: 'float0', column: 'efflAmnt', item: item as unknown as Record<string, unknown>}); + DataForm({ type: 'float0', column: 'totInflAmnt', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'sumFlow', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'efflWqltBod', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'returnAmnt', item: item as unknown as Record<string, unknown> }); + DataForm({ type: 'float0', column: 'efflAmnt', item: item as unknown as Record<string, unknown> }); } -export const flowRateSearchInitState:FlowRateSearchType = { +export const flowRateSearchInitState: FlowRateSearchType = { FlowRateSearch: { isInit: false, flowRateSearchLabelArray: FlowRateSearchLabelArray, }, - FlowRateList : { - isInit : false, - upHeadList1 : upHeadList1, - upHeadList2 : upHeadList2, - upHeadList3 : upHeadList3, - flowRateList : flowRateList, - flowRateCount : 0, + FlowRateList: { + isInit: false, + upHeadList1: upHeadList1, + upHeadList2: upHeadList2, + upHeadList3: upHeadList3, + flowRateList: flowRateList, + flowRateCount: 0, excelList: [], isLoading: true, }, - FlowRateModal : { - isInit : false, - upHeadListFlowRateModalYear : upHeadListFlowRateModal, - modalFlowRateListYear : modalFlowRateListYear, + FlowRateModal: { + isInit: false, + upHeadListFlowRateModalYear: upHeadListFlowRateModal, + modalFlowRateListYear: modalFlowRateListYear, } } -export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => FlowRateSearchType) => void)=>FlowRateSearchActions=(set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => { +export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => FlowRateSearchActions = (set: (fn: (state: FlowRateSearchType) => FlowRateSearchType) => void) => { return { searchFlowRateList: async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { set((state: FlowRateSearchType) => ({ @@ -288,7 +289,7 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow return item; }); - if(pageSize>5000){ + if (pageSize > 5000) { rtnData.forEach((item: flowRateListProps) => { excelDownList.push({ 시설코드: item.bscFctCd, @@ -312,15 +313,15 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow set((state: FlowRateSearchType) => ({ ...state, - FlowRateList: pageSize<5000?{ + FlowRateList: pageSize < 5000 ? { ...state.FlowRateList, flowRateList: rtnData, flowRateCount: res.count, - isLoading : false, - }:{ + isLoading: false, + } : { ...state.FlowRateList, excelList: excelDownList, - isLoading : false, + isLoading: false, }, })) }, @@ -336,37 +337,37 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow /강우시 일별유입BOD) */ //let rainInflAmnt = 0; - let sunnyInflAmnt = 0; - let sunnyBod = 0; + let sunnyInflAmnt = 0; // 청천시 일별유입유량 + let sunnyBod = 0; // 청천시 일별유입BOD //let rainDay = 0; let sunnyDay = 0; inflData.forEach(item => { - if(item.rainEffectDay == 1){ + if (item.rainEffectDay == 1) { //rainDay += 1; //rainInflAmnt += Number(item.inflAmnt); } else { - const msrDt = item.msrDt.replaceAll('-',''); + const msrDt = item.msrDt.replaceAll('-', ''); sunnyDay += 1; sunnyInflAmnt += Number(item.inflAmnt); - sunnyBod += Number(wqltData.filter((wqitem)=>wqitem.msrDt === msrDt)[0].inflAssctBfrWqltBod); + sunnyBod += Number(wqltData.filter((wqitem) => wqitem.msrDt === msrDt)[0].inflAssctBfrWqltBod); } }); //const yearRainAmnt = rainInflAmnt===0?0:rainInflAmnt / rainDay; - const yearSunnyAmnt = sunnyInflAmnt===0?0:sunnyInflAmnt / sunnyDay; - const yearSunnyBod = sunnyBod===0?0:sunnyBod / sunnyDay; - + const yearSunnyAmnt = sunnyInflAmnt === 0 ? 0 : sunnyInflAmnt / sunnyDay; // 청천시 연평균유입유량 + const yearSunnyBod = sunnyBod === 0 ? 0 : sunnyBod / sunnyDay; // 청천시 연평균유입BOD + const rtnData = inflData.map((item: FlowRateModalProps) => { - const dayBod = Number(wqltData.filter(wqitem=>wqitem.msrDt === item.msrDt.replaceAll('-',''))[0].inflAssctBfrWqltBod); - const noProcessInflAmnt = roundNumber(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod, 0) - + const dayBod = Number(wqltData.filter(wqitem => wqitem.msrDt === item.msrDt.replaceAll('-', ''))[0].inflAssctBfrWqltBod); + const noProcessInflAmnt = Math.round(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod) + item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); - item.noProcessInflAmnt = noProcessInflAmnt && Number(noProcessInflAmnt.replaceAll(',','')) > 0 ? noProcessInflAmnt : ''; + item.noProcessInflAmnt = noProcessInflAmnt && noProcessInflAmnt > 0 ? noProcessInflAmnt : ''; dataFormSetting(item); return item; }); - + set((state: FlowRateSearchType) => ({ ...state, FlowRateModal: { From 94fa8eb7211e4c726944fdd3f11f649eaba0e27c Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sat, 10 Jan 2026 20:43:46 +0900 Subject: [PATCH 46/92] =?UTF-8?q?fo:=20=EC=9C=A0=EB=9F=89=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=20=EA=B0=95=EC=9A=B0=EC=8B=9C=20=ED=8F=89=EA=B7=A0?= =?UTF-8?q?=20=EB=8B=A8=EC=88=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/components/common/DataForm.tsx | 42 +++++----- .../common/FacilityTermModalHeader.tsx | 82 +++++++++---------- .../(with-layout)/flowRate/modal/page.tsx | 24 ++++-- apps/fo/app/store/flowRate/index.tsx | 54 ++++++------ 4 files changed, 107 insertions(+), 95 deletions(-) diff --git a/apps/fo/app/components/common/DataForm.tsx b/apps/fo/app/components/common/DataForm.tsx index b58322458..2c99129b2 100644 --- a/apps/fo/app/components/common/DataForm.tsx +++ b/apps/fo/app/components/common/DataForm.tsx @@ -26,7 +26,7 @@ export const getDaysInMonth = (yyyymm: string) => { return new Date(year, month, 0).getDate(); } -export const roundNumber = (value : any, decimals: number) => { +export const roundNumber = (value: any, decimals: number) => { if (typeof value === 'number') { return addCommas((Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)).toFixed(decimals)); } else if (typeof value === 'string') { @@ -45,48 +45,48 @@ export const addCommas = (value: string | number): any => { index === 0 ? part : part.replace(/(\d{3})/g, '$1,') ).join('.'); } else if (typeof value === 'string') { - return value.includes('.')?value.split('.').map((part, index) => + return value.includes('.') ? value.split('.').map((part, index) => index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part - ).join('.'):String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + ).join('.') : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } } export default function DataForm({ type, column, item }: DataFormProps) { - if(item) { + if (item) { const value = item[column]; - switch(type){ + switch (type) { case 'date': - if(value && typeof value === 'string' && value.length >= 8) + if (value && typeof value === 'string' && value.length >= 8 && !value.includes('-')) item[column] = value.substring(0, 4) + "-" + value.substring(4, 6) + "-" + value.substring(6, 8); - break; + break; case 'number': - if(value && value != '') { + if (value && value != '') { item[column] = value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } - break; + break; case 'float0': - if(value) { - item[column] = item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1) / 1).split('.').map((part, index) => - index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part - ).join('.') - : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); + if (value) { + item[column] = item[column] = String(value).includes('.') ? String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1) / 1).split('.').map((part, index) => + index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part + ).join('.') + : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ","); } - break; + break; case 'float1': - if(value) { + if (value) { item[column] = roundNumber(value, 1); } - break; + break; case 'float2': - if(value) { + if (value) { item[column] = roundNumber(value, 2); } - break; + break; case 'float3': - if(value) { + if (value) { item[column] = roundNumber(value, 3); } - break; + break; } } } \ No newline at end of file diff --git a/apps/fo/app/components/common/FacilityTermModalHeader.tsx b/apps/fo/app/components/common/FacilityTermModalHeader.tsx index 84d6353b6..4389e2f5a 100644 --- a/apps/fo/app/components/common/FacilityTermModalHeader.tsx +++ b/apps/fo/app/components/common/FacilityTermModalHeader.tsx @@ -4,14 +4,14 @@ import ListDiv from '@common/business_components/ui/list_div'; import { Table, TableCell, TableHead, TableRow } from '@common/components/ui'; import { useCallback, useEffect, useRef, useState } from 'react'; -type FacilityTermModalHeaderProps<T extends { msrDt: string }> = { - fcltyCd : string; +type FacilityTermModalHeaderProps<T extends { msrDt: string }> = { // T는 반드시 msrDt: string 필드를 가져야 한다 + fcltyCd: string; fcltyName: string; tabName: string; searchYear: string; searchList: T[]; ref: React.RefObject<ReturnType<T>>; - queryClick:(returnType:ReturnType<T>) => void; + queryClick: (returnType: ReturnType<T>) => void; } export type ReturnType<T> = { @@ -21,28 +21,28 @@ export type ReturnType<T> = { filteredList: T[]; } -export default function FacilityTermModalHeader<T extends { msrDt: string }>({ +export default function FacilityTermModalHeader<T extends { msrDt: string }>({ searchList, - fcltyName, - tabName, + fcltyName, + tabName, searchYear, queryClick, ref }: FacilityTermModalHeaderProps<T & { msrDt: string }>) { - const {Common} = useFoStore((state) => state); + const { Common } = useFoStore((state) => state); const { selectFlowPanel } = Common; const [startDate, setStartDate] = useState<Date>(new Date(Number(searchYear), 0, 1)); const [endDate, setEndDate] = useState<Date>(new Date(Number(searchYear), 11, 31)); const startPickerRef = useRef<HTMLDivElement>(null); const endPickerRef = useRef<HTMLDivElement>(null); - const [flowPanel, setFlowPanel] = useState<string>(selectFlowPanel[0]?.val ?? '00'); + const [flowPanel, setFlowPanel] = useState<string>(selectFlowPanel[0]?.val ?? '0'); // 초기값 "전체" const [copySearchList, setCopySearchList] = useState<T[]>(searchList); const [standSearchList, setStandSearchList] = useState<T[]>(searchList); const isDateInRanges = (date: Date) => { const standYear = parseInt(searchYear); const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); - const dateRanges:{start:Date, end:Date}[] = []; + const dateRanges: { start: Date, end: Date }[] = []; if (tabName.includes("_summer")) { dateRanges.push({ @@ -74,66 +74,66 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ const standYear = Number(searchYear); const isLeapYear = (standYear % 4 === 0 && standYear % 100 !== 0) || (standYear % 400 === 0); - if(tabName.includes("_summer")) { - startDate = new Date(Number(searchYear), 5, 1); - endDate = new Date(Number(searchYear), 7, 31); + if (tabName.includes("_summer")) { // 하절기 + startDate = new Date(Number(searchYear), 5, 1); // 6월 ~ + endDate = new Date(Number(searchYear), 7, 31); // 8월 setStartDate(startDate); setEndDate(endDate); - } else if (tabName.includes("_winter")) { - startDate = new Date(Number(searchYear), 0, 1); - endDate = new Date(Number(searchYear), 1, isLeapYear ? 29 : 28); + } else if (tabName.includes("_winter")) { // 동절기 + startDate = new Date(Number(searchYear), 0, 1); // 1월 ~ + endDate = new Date(Number(searchYear), 1, isLeapYear ? 29 : 28); // 2월 setStartDate(startDate); setEndDate(endDate); - } else { + } else { // 연간 startDate = new Date(Number(searchYear), 0, 1); endDate = new Date(Number(searchYear), 11, 31); setStartDate(startDate); setEndDate(endDate); } - + let filteredData: T[] = []; - if(tabName.includes("_rain")) { + if (tabName.includes("_rain")) { // 강우시 filteredData = searchList.filter((item) => { const itemDate = new Date((item as T & { msrDt: string }).msrDt); const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay; - - if(flowPanel === '2'){ + + if (flowPanel === '2') { //3~10mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 3 && infoRnDay < 10; - } else if(flowPanel === '3'){ + } else if (flowPanel === '3') { //10~20mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 10 && infoRnDay < 20; - } else if(flowPanel === '4'){ + } else if (flowPanel === '4') { //20~30mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 20 && infoRnDay < 30; - } else if(flowPanel === '5'){ + } else if (flowPanel === '5') { //30~40mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 30 && infoRnDay < 40; - } else if(flowPanel === '6'){ + } else if (flowPanel === '6') { //40~50mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 40 && infoRnDay < 50; - } else if(flowPanel === '7'){ + } else if (flowPanel === '7') { //50~60mm미만 const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 50 && infoRnDay < 60; - } else if(flowPanel === '8'){ + } else if (flowPanel === '8') { const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay; return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 60; } else { - return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (rainEffectDay ===1); + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (rainEffectDay === 1); } }); - } else if(tabName.includes("_chuncheon")) { + } else if (tabName.includes("_chuncheon")) { // 청천시 filteredData = searchList.filter((item) => { const itemDate = new Date((item as T & { msrDt: string }).msrDt); const itemDateOnly = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay; - return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && rainEffectDay==0; + return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && rainEffectDay == 0; }); } else { filteredData = searchList.filter((item) => { @@ -149,7 +149,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ }, [searchList, searchYear, tabName, flowPanel]); const handleStartDateSelect = (day: Date | undefined) => { - if(day && day > endDate) { + if (day && day > endDate) { alert('종료일은 시작일 이전일 수 없습니다.'); return; } @@ -172,7 +172,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ }; const handleEndDateSelect = (day: Date | undefined) => { - if(day && day < startDate) { + if (day && day < startDate) { alert('종료일은 시작일 이후일 수 없습니다.'); return; } @@ -193,7 +193,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ }); setCopySearchList(filteredData); }; - + const fncSetFilteredList = useCallback(() => { queryClick({ startDate: startDate, @@ -206,9 +206,9 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ useEffect(() => { fncSetFilteredList(); }, [fncSetFilteredList]); - + useEffect(() => { - if(ref && ref.current) { + if (ref && ref.current) { const customRef = ref.current; customRef.startDate = startDate; customRef.endDate = endDate; @@ -225,18 +225,18 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ <TableRow className="!h-[20px]"> <TableHead className="w-[120px]">{'시설명'}</TableHead> {tabName === "tab_term_rain" ? <TableCell className="w-[300px]">{fcltyName}</TableCell> : - <TableCell className="w-[380px]">{fcltyName}</TableCell>} + <TableCell className="w-[380px]">{fcltyName}</TableCell>} {tabName === "tab_term_rain" && ( <> <TableHead className="w-[120px]">{'강수구분'}</TableHead> <TableCell className="w-[250px]"> <div className="justify-center"> - <SelectBox - selectArray={selectFlowPanel} + <SelectBox + selectArray={selectFlowPanel} value={flowPanel} onSelectValue={(val) => setFlowPanel(val.toString())} - className="mx-3 w-[150px]" - label="" + className="mx-3 w-[150px]" + label="" selectClass="w-full p-1 border rounded bg-white" /> </div> @@ -247,7 +247,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ <TableCell className=""> <div className="flex"> <div ref={startPickerRef} className="flex justify-center"> - <DatePickerRange + <DatePickerRange mode="single" selected={startDate} onSelect={(date) => handleStartDateSelect(date as Date)} @@ -261,7 +261,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ <DatePickerRange mode="single" selected={endDate} - onSelect={(date) => handleEndDateSelect(date as Date)} + onSelect={(date) => handleEndDateSelect(date as Date)} className="w-full p-1 border rounded bg-white" disabled={(date) => !isDateInRanges(date)} defaultMonth={endDate} 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 822b52979..4e0fffeb5 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -8,6 +8,7 @@ import FacilityTermModalHeader from "@/app/components/common/FacilityTermModalHeader"; import { useFoStore } from "@/app/store"; import type { FlowRateModalInterface, modalExcelType } from "@/app/store/flowRate"; +import { dataFormSetting } from "@/app/store/flowRate"; import { downloadExcel, UITab, UiTable } from "@common/business_components/ui"; import { Button, TabsContent } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; @@ -76,7 +77,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st let minreturnAmnt = parseNumber(filteredData[0]?.returnAmnt); let minefflAmnt = parseNumber(filteredData[0]?.efflAmnt); let mininfoRnDay = parseNumber(filteredData[0]?.infoRnDay && filteredData[0]?.infoRnDay.toString().trim() !== 'x' ? filteredData[0]?.infoRnDay.toString().trim() : 0); - let minNoProcessInflAmnt = 99999999; + let minNoProcessInflAmnt = 99999999; // 미처리하수 추정량 let avgtotInflAmnt = 0; let avginflAmnt = 0; @@ -125,6 +126,12 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st } }); + const formattedData = filteredData.map((item: FlowRateModalInterface) => { + const newItem = { ...item }; + dataFormSetting(newItem); + return newItem; + }); + const newFilteredData = [ { msrDt: '평균', @@ -159,7 +166,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st infoRnDay: mininfoRnDay > 0 ? roundUp(mininfoRnDay, 1) : '0.0', rainEffectDay: 0, }, - ...filteredData + ...formattedData ]; return newFilteredData; } @@ -210,7 +217,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st <Button className={btnClass} style={{ float: 'right' }} color="green" onClick={excelDownload}> {"엑셀다운로드"} </Button> - <TabsContent value="tab_term_year"> + <TabsContent value="tab_term_year"> {/* 연간 */} <FacilityTermModalHeader<FlowRateModalInterface> searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -237,7 +244,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st <UnderComment commentArray={[commentArray]} /> </div> </TabsContent> - <TabsContent value="tab_term_summer"> + <TabsContent value="tab_term_summer"> {/* 하절기 */} <FacilityTermModalHeader<FlowRateModalInterface> searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -264,7 +271,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st <UnderComment commentArray={[commentArray]} /> </div> </TabsContent> - <TabsContent value="tab_term_winter"> + <TabsContent value="tab_term_winter"> {/* 동절기 */} <FacilityTermModalHeader<FlowRateModalInterface> searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -291,7 +298,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st <UnderComment commentArray={[commentArray]} /> </div> </TabsContent> - <TabsContent value="tab_term_chuncheon"> + <TabsContent value="tab_term_chuncheon"> {/* 청천시 */} <FacilityTermModalHeader<FlowRateModalInterface> searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -318,7 +325,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st <UnderComment commentArray={[commentArray]} /> </div> </TabsContent> - <TabsContent value="tab_term_rain"> + <TabsContent value="tab_term_rain"> {/* 강우시 */} <FacilityTermModalHeader<FlowRateModalInterface> searchList={modalFlowRateListYear} fcltyCd={props.facilityCd} @@ -329,7 +336,8 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st queryClick={filterData} /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> - <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} /> + <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} + cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} /> </div> <div className="mt-20"> <UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)", "강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} /> diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 432bc5ba5..7bec0be97 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -237,7 +237,7 @@ export type FlowRateSearchType = { export type FlowRateSearchStore = FlowRateSearchType & FlowRateSearchActions; -const dataFormSetting = (item: flowRateListProps | FlowRateModalProps) => { +export const dataFormSetting = (item: flowRateListProps | FlowRateModalProps | FlowRateModalInterface) => { DataForm({ type: 'date', column: 'msrDt', item: item as unknown as Record<string, unknown> }); DataForm({ type: 'float0', column: 'totInflAmnt', item: item as unknown as Record<string, unknown> }); DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record<string, unknown> }); @@ -330,44 +330,48 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl const inflData = CalcRainEffect(res.data); const res2 = await fetchFacilityWaterQltyListHist(searchYear, bscFctCd); - const wqltData = CalcRainEffect(res2?.data.wqltObjs); - + const wqltData = res2?.data.wqltObjs; + //const wqltData = CalcRainEffect(res2?.data.wqltObjs); /** - * [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]​ - /강우시 일별유입BOD) + * [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)] / 강우시 일별유입BOD */ - //let rainInflAmnt = 0; let sunnyInflAmnt = 0; // 청천시 일별유입유량 - let sunnyBod = 0; // 청천시 일별유입BOD - //let rainDay = 0; + let sunnyBod = 0; // 청천시 일별유입BOD let sunnyDay = 0; - - inflData.forEach(item => { - if (item.rainEffectDay == 1) { - //rainDay += 1; - //rainInflAmnt += Number(item.inflAmnt); + let rainEffectDay = 0; + wqltData?.forEach(item => { + if (item.infoRnDay == null) item.infoRnDay = 0; + if (Number(item.infoRnDay) >= 3) { + rainEffectDay = 2; } else { - const msrDt = item.msrDt.replaceAll('-', ''); + rainEffectDay--; + } + if (rainEffectDay < 0) { //청천시 sunnyDay += 1; sunnyInflAmnt += Number(item.inflAmnt); - sunnyBod += Number(wqltData.filter((wqitem) => wqitem.msrDt === msrDt)[0].inflAssctBfrWqltBod); + sunnyBod += Number(item.inflAssctBfrWqltBod); } }); - //const yearRainAmnt = rainInflAmnt===0?0:rainInflAmnt / rainDay; - const yearSunnyAmnt = sunnyInflAmnt === 0 ? 0 : sunnyInflAmnt / sunnyDay; // 청천시 연평균유입유량 - const yearSunnyBod = sunnyBod === 0 ? 0 : sunnyBod / sunnyDay; // 청천시 연평균유입BOD - + const yearSunnyAmnt = sunnyDay > 0 ? sunnyInflAmnt / sunnyDay : 0; // 청천시 연평균유입유량 + const yearSunnyBod = sunnyDay > 0 ? sunnyBod / sunnyDay : 0; // 청천시 연평균유입BOD + console.log(inflData); const rtnData = inflData.map((item: FlowRateModalProps) => { - const dayBod = Number(wqltData.filter(wqitem => wqitem.msrDt === item.msrDt.replaceAll('-', ''))[0].inflAssctBfrWqltBod); + const targetWqItem = wqltData?.find(wqitem => wqitem.msrDt === item.msrDt.replaceAll('-', '')); + const dayBod = targetWqItem ? Number(targetWqItem.inflAssctBfrWqltBod) : 0; const noProcessInflAmnt = Math.round(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod) + const totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); - item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0); - item.noProcessInflAmnt = noProcessInflAmnt && noProcessInflAmnt > 0 ? noProcessInflAmnt : ''; - dataFormSetting(item); - return item; + return { + ...item, + totInflAmnt, + noProcessInflAmnt: noProcessInflAmnt && noProcessInflAmnt > 0 ? noProcessInflAmnt : '', + msrDt: (item.msrDt.length === 8 && !item.msrDt.includes('-')) ? + `${item.msrDt.slice(0, 4)}-${item.msrDt.slice(4, 6)}-${item.msrDt.slice(6, 8)}` + : item.msrDt, + }; }); - + console.log(rtnData); set((state: FlowRateSearchType) => ({ ...state, FlowRateModal: { From 36294fef80a0109abecaf4e67356fe413ec7d212 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 12 Jan 2026 10:28:36 +0900 Subject: [PATCH 47/92] =?UTF-8?q?fo:=20=EC=B2=98=EB=A6=AC=EA=B5=AC?= =?UTF-8?q?=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/processArea/page.tsx | 3 +- apps/fo/app/store/processArea/index.tsx | 522 +++++++++--------- 2 files changed, 264 insertions(+), 261 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 009d72c9f..ba1e27767 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -167,7 +167,8 @@ export default function ProcessArea() { <LoadingOverlay isLoading={isLoading} /> <div className="h-full w-full overflow-x-scroll min-[1900px]:overflow-x-hidden"> <div className="w-[160%] min-[1900px]:w-[100%]"> - <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"처리구역정보"} tableData={mainList} headlist={upHeadList1} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> + <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"처리구역정보"} tableData={mainList} + headlist={upHeadList1} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> </div> </div> </ListDiv> diff --git a/apps/fo/app/store/processArea/index.tsx b/apps/fo/app/store/processArea/index.tsx index 959b83794..31da21bfc 100644 --- a/apps/fo/app/store/processArea/index.tsx +++ b/apps/fo/app/store/processArea/index.tsx @@ -12,52 +12,52 @@ export type { TableUpperProps }; */ // 처리구역 리스트 export type ProcessAreaProps = { - swtrmtFcltCd : string, + swtrmtFcltCd: string, ctpvNm?: string, sggNm?: string, - swtrmtFcltNm : string, - location : string, - fctCpc : number | '', - fcltCpctSum : number | '', - ruse : boolean, - planYrDt4 : string, - planYr : string, - planYrDc1 : string, - planYrDc2 : string, - planYrDc3 : string, - planYrDc4 : string, + swtrmtFcltNm: string, + location: string, + fctCpc: number | '', + fcltCpctSum: number | '', + ruse: boolean, + planYrDt4: string, + planYr: string, + planYrDc1: string, + planYrDc2: string, + planYrDc3: string, + planYrDc4: string, /** * 증설계획 */ // 기승인(당초4단계), 현재, 변경1~4 - planSwageQntSumDt4 : number | '', - planSwageQntSum : number | '', - planSwageQntSumDc1 : number | '', - planSwageQntSumDc2 : number | '', - planSwageQntSumDc3 : number | '', - planSwageQntSumDc4 : number | '', + planSwageQntSumDt4: number | '', + planSwageQntSum: number | '', + planSwageQntSumDc1: number | '', + planSwageQntSumDc2: number | '', + planSwageQntSumDc3: number | '', + planSwageQntSumDc4: number | '', /** * 처리인구 */ // 기승인(당초4단계), 변경1~4 - swtrmtPpltnCntDt4 : number | '', - swtrmtPpltnCnt : number | '', - swtrmtPpltnCntDc1 : number | '', - swtrmtPpltnCntDc2 : number | '', - swtrmtPpltnCntDc3 : number | '', - swtrmtPpltnCntDc4 : number | '', + swtrmtPpltnCntDt4: number | '', + swtrmtPpltnCnt: number | '', + swtrmtPpltnCntDc1: number | '', + swtrmtPpltnCntDc2: number | '', + swtrmtPpltnCntDc3: number | '', + swtrmtPpltnCntDc4: number | '', /** * 처리구역면적 */ // 기승인(당초4단계), 변경1~4 - swtrmtZoneAreaDt4 : number | '', - swtrmtZoneArea : number | '', - swtrmtZoneAreaDc1 : number | '', - swtrmtZoneAreaDc2 : number | '', - swtrmtZoneAreaDc3 : number | '', - swtrmtZoneAreaDc4 : number | '', + swtrmtZoneAreaDt4: number | '', + swtrmtZoneArea: number | '', + swtrmtZoneAreaDc1: number | '', + swtrmtZoneAreaDc2: number | '', + swtrmtZoneAreaDc3: number | '', + swtrmtZoneAreaDc4: number | '', // 처리구역 - trtDstr : string | '', + trtDstr: string | '', } export interface ExcelType { @@ -89,32 +89,32 @@ export interface ExcelType { // (2) 처리구역 팝업 // 시설증설 계획 export type FcltyImproveInfoProps = { - planSwageQntSumDt4 : number | '', - planSwageQntSum : number | '', - planSwageQntSumDc1 : number | '', - planSwageQntSumDc2 : number | '', - planSwageQntSumDc3 : number | '', - planSwageQntSumDc4 : number | '', + planSwageQntSumDt4: number | '', + planSwageQntSum: number | '', + planSwageQntSumDc1: number | '', + planSwageQntSumDc2: number | '', + planSwageQntSumDc3: number | '', + planSwageQntSumDc4: number | '', } // 처리인구 계획 export type ProcessPopulationProps = { - swtrmtPpltnCntDt4 : number | '', - swtrmtPpltnCnt : number | '', - swtrmtPpltnCntDc1 : number | '', - swtrmtPpltnCntDc2 : number | '', - swtrmtPpltnCntDc3 : number | '', - swtrmtPpltnCntDc4 : number | '', + swtrmtPpltnCntDt4: number | '', + swtrmtPpltnCnt: number | '', + swtrmtPpltnCntDc1: number | '', + swtrmtPpltnCntDc2: number | '', + swtrmtPpltnCntDc3: number | '', + swtrmtPpltnCntDc4: number | '', } // 처리구역 계획 export type ProcessAreaPlanProps = { - swtrmtZoneAreaDt4 : number | '', - swtrmtZoneArea : number | '', - swtrmtZoneAreaDc1 : number | '', - swtrmtZoneAreaDc2 : number | '', - swtrmtZoneAreaDc3 : number | '', - swtrmtZoneAreaDc4 : number | '', - trtDstr : string, + swtrmtZoneAreaDt4: number | '', + swtrmtZoneArea: number | '', + swtrmtZoneAreaDc1: number | '', + swtrmtZoneAreaDc2: number | '', + swtrmtZoneAreaDc3: number | '', + swtrmtZoneAreaDc4: number | '', + trtDstr: string, } /**==================================== @@ -123,93 +123,93 @@ export type ProcessAreaPlanProps = { /** * (1) 메인페이지 - */ + */ // 검색단 -const ProcessFacilityLabelArray:string[] = ['구분', '시도', '시군구','용량별', '시설명', '시설상태', '연도별', '권역', '단위유역', '중권역', '환경청별']; +const ProcessFacilityLabelArray: string[] = ['구분', '시도', '시군구', '용량별', '시설명', '시설상태', '연도별', '권역', '단위유역', '중권역', '환경청별']; // 리스트 헤더(행정별) -const upHeadList1:TableUpperProps[] = [ - { id: "A", title: "행정구역", colSpan:2, rowSpan:2, row:0 }, - { 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: 6 }, - { id: "location", title: "주소", rowSpan:3, row:0, widthPercent: 12 }, - { id: "fctCpc", title: "시설용량(m³/일)", align:"right", rowSpan:3, row:0, widthPercent: 5 }, - { id: "B", title: "시설계획", colSpan:19, row: 0 }, - { id: "C", title: "증설계획(m³/일)", colSpan:6, row: 1 }, - { id: "planSwageQntSumDt4", title: "기승인\n4단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "planSwageQntSum", title: "현재", row:2, align:"right", widthPercent: 3.5 }, - { id: "planSwageQntSumDc1", title: "1단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "planSwageQntSumDc2", title: "2단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "planSwageQntSumDc3", title: "3단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "planSwageQntSumDc4", title: "4단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "D", title: "처리인구(인)", colSpan:6, row:1 }, - { id: "swtrmtPpltnCntDt4", title: "기승인\n4단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtPpltnCnt", title: "현재", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtPpltnCntDc1", title: "1단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtPpltnCntDc2", title: "2단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtPpltnCntDc3", title: "3단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtPpltnCntDc4", title: "4단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "E", title: "처리구역(km²)", colSpan:7, row:1 }, - { id: "swtrmtZoneAreaDt4", title: "기승인\n4단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtZoneArea", title: "현재", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtZoneAreaDc1", title: "1단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtZoneAreaDc2", title: "2단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtZoneAreaDc3", title: "3단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "swtrmtZoneAreaDc4", title: "4단계", row:2, align:"right", widthPercent: 3.5 }, - { id: "trtDstr", title: "처리구역", row:2} +const upHeadList1: TableUpperProps[] = [ + { id: "A", title: "행정구역", colSpan: 2, rowSpan: 2, row: 0 }, + { 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: 6 }, + { id: "location", title: "주소", rowSpan: 3, row: 0, widthPercent: 12 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 3, row: 0, widthPercent: 5 }, + { id: "B", title: "시설계획", colSpan: 18, row: 0 }, + { id: "C", title: "증설계획(m³/일)", colSpan: 6, row: 1 }, + { id: "planSwageQntSumDt4", title: "기승인\n4단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "planSwageQntSum", title: "현재", row: 2, align: "right", widthPercent: 3.5 }, + { id: "planSwageQntSumDc1", title: "1단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "planSwageQntSumDc2", title: "2단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "planSwageQntSumDc3", title: "3단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "planSwageQntSumDc4", title: "4단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "D", title: "처리인구(인)", colSpan: 6, row: 1 }, + { id: "swtrmtPpltnCntDt4", title: "기승인\n4단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtPpltnCnt", title: "현재", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtPpltnCntDc1", title: "1단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtPpltnCntDc2", title: "2단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtPpltnCntDc3", title: "3단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtPpltnCntDc4", title: "4단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "E", title: "처리구역(km²)", colSpan: 6, row: 1 }, + { id: "swtrmtZoneAreaDt4", title: "기승인\n4단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtZoneArea", title: "현재", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtZoneAreaDc1", title: "1단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtZoneAreaDc2", title: "2단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtZoneAreaDc3", title: "3단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "swtrmtZoneAreaDc4", title: "4단계", row: 2, align: "right", widthPercent: 3.5 }, + { id: "trtDstr", title: "처리구역", row: 0, rowSpan: 3 } // row - header에서 몇번째 행인지 ]; -const processAreaList:ProcessAreaProps[] = [ +const processAreaList: ProcessAreaProps[] = [ ] /** * 처리구역정보 상세팝업 - */ + */ // 시설증설 계획 (헤더) -const upHeadListFcltyImproveInfo:TableUpperProps[] = [ - { id: "planSwageQntSumDt4", title: "기승인\n4단계(m³/일)", rowSpan:2, row:0, align:"right"}, - { id: "A", title: "증설계획(m³/일)", colSpan:5, row:0}, - { id: "planSwageQntSum", title: "현재", row:1, align:"right"}, - { id: "planSwageQntSumDc1", title: "1단계", row:1, align:"right"}, - { id: "planSwageQntSumDc2", title: "2단계", row:1, align:"right"}, - { id: "planSwageQntSumDc3", title: "3단계", row:1, align:"right"}, - { id: "planSwageQntSumDc4", title: "4단계", row:1, align:"right"}, +const upHeadListFcltyImproveInfo: TableUpperProps[] = [ + { id: "planSwageQntSumDt4", title: "기승인\n4단계(m³/일)", rowSpan: 2, row: 0, align: "right" }, + { id: "A", title: "증설계획(m³/일)", colSpan: 5, row: 0 }, + { id: "planSwageQntSum", title: "현재", row: 1, align: "right" }, + { id: "planSwageQntSumDc1", title: "1단계", row: 1, align: "right" }, + { id: "planSwageQntSumDc2", title: "2단계", row: 1, align: "right" }, + { id: "planSwageQntSumDc3", title: "3단계", row: 1, align: "right" }, + { id: "planSwageQntSumDc4", title: "4단계", row: 1, align: "right" }, ]; // 시설증설 계획 (리스트) -const gridListFcltyImproveInfo:FcltyImproveInfoProps[] = [ +const gridListFcltyImproveInfo: FcltyImproveInfoProps[] = [ ]; // 처리인구 계획 (헤더) -const upHeadListProcessPopulation:TableUpperProps[] = [ - { id: "swtrmtPpltnCntDt4", title: "기승인\n4단계(인)", rowSpan:2, row:0, align:"right"}, - { id: "A", title: "처리인구(인)", colSpan:5, row:0}, - { id: "swtrmtPpltnCnt", title: "현재", row:1, align:"right"}, - { id: "swtrmtPpltnCntDc1", title: "1단계", row:1, align:"right"}, - { id: "swtrmtPpltnCntDc2", title: "2단계", row:1, align:"right"}, - { id: "swtrmtPpltnCntDc3", title: "3단계", row:1, align:"right"}, - { id: "swtrmtPpltnCntDc4", title: "4단계", row:1, align:"right"}, +const upHeadListProcessPopulation: TableUpperProps[] = [ + { id: "swtrmtPpltnCntDt4", title: "기승인\n4단계(인)", rowSpan: 2, row: 0, align: "right" }, + { id: "A", title: "처리인구(인)", colSpan: 5, row: 0 }, + { id: "swtrmtPpltnCnt", title: "현재", row: 1, align: "right" }, + { id: "swtrmtPpltnCntDc1", title: "1단계", row: 1, align: "right" }, + { id: "swtrmtPpltnCntDc2", title: "2단계", row: 1, align: "right" }, + { id: "swtrmtPpltnCntDc3", title: "3단계", row: 1, align: "right" }, + { id: "swtrmtPpltnCntDc4", title: "4단계", row: 1, align: "right" }, ]; // 처리인구 계획 (리스트) -const gridListProcessPopulation:ProcessPopulationProps[] = [ +const gridListProcessPopulation: ProcessPopulationProps[] = [ ]; // 처리구역 계획 (헤더) -const upHeadListProcessAreaPlan:TableUpperProps[] = [ - { id: "swtrmtZoneAreaDt4", title: "기승인\n4단계(km²)", rowSpan:2, row:0, align:"right"}, - { id: "A", title: "처리면적(km²)", colSpan:6, row:0, align:"right"}, - { id: "swtrmtZoneArea", title: "현재", row:1, align:"right"}, - { id: "swtrmtZoneAreaDc1", title: "1단계", row:1, align:"right"}, - { id: "swtrmtZoneAreaDc2", title: "2단계", row:1, align:"right"}, - { id: "swtrmtZoneAreaDc3", title: "3단계", row:1, align:"right"}, - { id: "swtrmtZoneAreaDc4", title: "4단계", row:1, align:"right"}, - { id: "trtDstr", title: "처리구역", row:1} +const upHeadListProcessAreaPlan: TableUpperProps[] = [ + { id: "swtrmtZoneAreaDt4", title: "기승인\n4단계(km²)", rowSpan: 2, row: 0, align: "right" }, + { id: "A", title: "처리면적(km²)", colSpan: 5, row: 0, align: "right" }, + { id: "swtrmtZoneArea", title: "현재", row: 1, align: "right" }, + { id: "swtrmtZoneAreaDc1", title: "1단계", row: 1, align: "right" }, + { id: "swtrmtZoneAreaDc2", title: "2단계", row: 1, align: "right" }, + { id: "swtrmtZoneAreaDc3", title: "3단계", row: 1, align: "right" }, + { id: "swtrmtZoneAreaDc4", title: "4단계", row: 1, align: "right" }, + // { id: "trtDstr", title: "처리구역", row: 1 } ]; // 시설증설 계획 (리스트) -const gridListProcessAreaPlan:ProcessAreaPlanProps[] = [ +const gridListProcessAreaPlan: ProcessAreaPlanProps[] = [ ]; /**==================================== @@ -227,113 +227,115 @@ const gridListProcessAreaPlan:ProcessAreaPlanProps[] = [ } }; */ -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 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:any[], count:number}> => { - try { - const res = await fetchPlanInfo(targetYear, ctpvNm, sggNm, undefined); - if(res && res.length > 0){ - const enrichedData = await Promise.all( - res.map(async (item: ProcessAreaProps) => { - upHeadList1.forEach((head:TableUpperProps) => { - /* if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { - head.title = '현재\n(' + item.planYr + '년)'; - } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { - head.title = '1단계\n(' + item.planYrDc1 + '년)'; - } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { - head.title = '2단계\n(' + item.planYrDc2 + '년)'; - } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { - head.title = '3단계\n(' + item.planYrDc3 + '년)'; - } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { - head.title = '4단계\n(' + item.planYrDc4 + '년)'; - } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { - head.title = '기승인\n4단계(' + item.planYrDt4 + '년)'; - } */ - if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { - head.title = '현재'; - } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { - head.title = '1단계'; - } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { - head.title = '2단계'; - } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { - head.title = '3단계'; - } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { - head.title = '4단계'; - } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { - head.title = '기승인\n4단계'; - } - }); - return item; +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) { + const enrichedData = await Promise.all( + res.map(async (item: ProcessAreaProps) => { + upHeadList1.forEach((head: TableUpperProps) => { + /* if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = '현재\n(' + item.planYr + '년)'; + } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = '1단계\n(' + item.planYrDc1 + '년)'; + } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = '2단계\n(' + item.planYrDc2 + '년)'; + } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = '3단계\n(' + item.planYrDc3 + '년)'; + } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = '4단계\n(' + item.planYrDc4 + '년)'; + } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = '기승인\n4단계(' + item.planYrDt4 + '년)'; + } */ + if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = '현재'; + } else if (head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = '1단계'; + } else if (head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = '2단계'; + } else if (head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = '3단계'; + } else if (head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = '4단계'; + } else if (head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = '기승인\n4단계'; + } + }); + 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 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}; - } - } catch (error) { - console.error('시설계획정보를 가져오는데 실패했습니다:', error); - set((state) => ({ - ...state, - ProcessArea : { - ...state.ProcessArea, - isLoading : false + 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 : ''; + item.trtDstr = filterdData ? filterdData.trtDstr : ''; + }); + return { data: paginatedData, count: enrichedData.length }; + } else { + return { data: [], count: 0 }; } - })); - return {data: [], count: 0}; - } + } catch (error) { + console.error('시설계획정보를 가져오는데 실패했습니다:', error); + set((state) => ({ + ...state, + ProcessArea: { + ...state.ProcessArea, + isLoading: false + } + })); + return { data: [], count: 0 }; + } }; /**==================================== * Store - expaort =====================================*/ export type ProcessAreaActions = { - searchProcessAreaList : (pageNo: number, pageSize: number, ctpvNm?:string, sggNm?:string, targetYear?:string) => void; - initModalData : (swtrmtFcltCd:string) => void; + searchProcessAreaList: (pageNo: number, pageSize: number, ctpvNm?: string, sggNm?: string, targetYear?: string) => void; + initModalData: (swtrmtFcltCd: string) => void; } export type ProcessAreaType = { ProcessAreaSearch: { isInit: boolean; - processFacilityLabelArray:string[]; + processFacilityLabelArray: string[]; }, - ProcessArea : { + ProcessArea: { isInit: boolean; upHeadList1: TableUpperProps[]; processAreaList: ProcessAreaProps[]; processAreaCount: number; excelList: ExcelType[]; isLoading: boolean; - }, + }, - ProcessAreaDetail : { + ProcessAreaDetail: { isInit: boolean; upHeadListFcltyImproveInfo: TableUpperProps[]; gridListFcltyImproveInfo: FcltyImproveInfoProps[]; // Changed from facilityAreaProps to ProcessAreaProps @@ -350,23 +352,23 @@ export const processAreaInitState: ProcessAreaType = { processFacilityLabelArray: ProcessFacilityLabelArray, }, - ProcessArea : { - isInit : false, - upHeadList1 : upHeadList1, - processAreaList : processAreaList, - processAreaCount : 0, - excelList : [], - isLoading : true, + ProcessArea: { + isInit: false, + upHeadList1: upHeadList1, + processAreaList: processAreaList, + processAreaCount: 0, + excelList: [], + isLoading: true, }, - ProcessAreaDetail : { - isInit : false, - upHeadListFcltyImproveInfo : upHeadListFcltyImproveInfo, - gridListFcltyImproveInfo : gridListFcltyImproveInfo, - upHeadListProcessPopulation : upHeadListProcessPopulation, - gridListProcessPopulation : gridListProcessPopulation, - upHeadListProcessAreaPlan : upHeadListProcessAreaPlan, - gridListProcessAreaPlan : gridListProcessAreaPlan, + ProcessAreaDetail: { + isInit: false, + upHeadListFcltyImproveInfo: upHeadListFcltyImproveInfo, + gridListFcltyImproveInfo: gridListFcltyImproveInfo, + upHeadListProcessPopulation: upHeadListProcessPopulation, + gridListProcessPopulation: gridListProcessPopulation, + upHeadListProcessAreaPlan: upHeadListProcessAreaPlan, + gridListProcessAreaPlan: gridListProcessAreaPlan, }, } @@ -375,14 +377,14 @@ type SetStateFunction = (state: ProcessAreaType | ((state: ProcessAreaType) => P export type ProcessAreaStore = ProcessAreaType & ProcessAreaActions; -export const processAreaReducer:(set:SetStateFunction)=>ProcessAreaActions=(set: SetStateFunction) => { +export const processAreaReducer: (set: SetStateFunction) => ProcessAreaActions = (set: SetStateFunction) => { return { /** * 시설정보 리스트 데이터 호출 * @param pageNo : 페이지 번호 * @param pageSize : 페이지 크기 */ - searchProcessAreaList: async ( pageNo:number, pageSize:number, ctpvNm?:string, sggNm?:string, targetYear?:string) => { + searchProcessAreaList: async (pageNo: number, pageSize: number, ctpvNm?: string, sggNm?: string, targetYear?: string) => { set((state: ProcessAreaType) => ({ ...state, ProcessArea: { @@ -391,12 +393,12 @@ export const processAreaReducer:(set:SetStateFunction)=>ProcessAreaActions=(set: }, })); const res = await fetchProcessAreaList(pageNo, pageSize, ctpvNm, sggNm, targetYear, set); - res.data.forEach((item:ProcessAreaProps) => { + res.data.forEach((item: ProcessAreaProps) => { item.fctCpc = item.fcltCpctSum; - DataForm({ type: 'float1', column: 'fctCpc', item:item as unknown as Record<string, unknown>}); + DataForm({ type: 'float1', column: 'fctCpc', item: item as unknown as Record<string, unknown> }); }) const excelDownList: ExcelType[] = []; - if(pageSize>5000){ + if (pageSize > 5000) { res.data.forEach(item => { item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : ''; excelDownList.push({ @@ -425,78 +427,78 @@ export const processAreaReducer:(set:SetStateFunction)=>ProcessAreaActions=(set: 처리구역: item.trtDstr }); }); - }else{ + } else { res.data.forEach(item => { item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : ''; }) } - set((state:ProcessAreaType) => ({ + set((state: ProcessAreaType) => ({ ...state, - ProcessArea: pageSize<5000?{ + ProcessArea: pageSize < 5000 ? { ...state.ProcessArea, processAreaList: res.data, processAreaCount: res.count, - isLoading : false, - }:{ + isLoading: false, + } : { ...state.ProcessArea, excelList: excelDownList, - isLoading : false, + isLoading: false, }, })) }, - initModalData: async (swtrmtFcltCd:string) => { + initModalData: async (swtrmtFcltCd: string) => { set((state: ProcessAreaType) => { const rtnData = state.ProcessArea.processAreaList.find((item: ProcessAreaProps) => item.swtrmtFcltCd === swtrmtFcltCd); if (rtnData) { - upHeadListFcltyImproveInfo.forEach((head:TableUpperProps) => { - if(head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { - head.title = rtnData.planYr? '현재\n(' + rtnData.planYr + '년)':head.title = '현재'; - } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { - head.title = rtnData.planYrDc1? '1단계\n(' + rtnData.planYrDc1 + '년)':head.title = '1단계'; - } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { - head.title = rtnData.planYrDc2? '2단계\n(' + rtnData.planYrDc2 + '년)':head.title = '2단계'; - } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { - head.title = rtnData.planYrDc3? '3단계\n(' + rtnData.planYrDc3 + '년)':head.title = '3단계'; - } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { - head.title = rtnData.planYrDc4? '4단계\n(' + rtnData.planYrDc4 + '년)':head.title = '4단계'; - } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { - head.title = rtnData.planYrDt4? '기승인\n4단계(' + rtnData.planYrDt4 + '년)':head.title = '기승인\n4단계'; + upHeadListFcltyImproveInfo.forEach((head: TableUpperProps) => { + if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = rtnData.planYr ? '현재\n(' + rtnData.planYr + '년)' : head.title = '현재'; + } else if (head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = rtnData.planYrDc1 ? '1단계\n(' + rtnData.planYrDc1 + '년)' : head.title = '1단계'; + } else if (head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = rtnData.planYrDc2 ? '2단계\n(' + rtnData.planYrDc2 + '년)' : head.title = '2단계'; + } else if (head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = rtnData.planYrDc3 ? '3단계\n(' + rtnData.planYrDc3 + '년)' : head.title = '3단계'; + } else if (head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = rtnData.planYrDc4 ? '4단계\n(' + rtnData.planYrDc4 + '년)' : head.title = '4단계'; + } else if (head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = rtnData.planYrDt4 ? '기승인\n4단계(' + rtnData.planYrDt4 + '년)' : head.title = '기승인\n4단계'; } }); - upHeadListProcessAreaPlan.forEach((head:TableUpperProps) => { - if(head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { - head.title = rtnData.planYr? '현재\n(' + rtnData.planYr + '년)':head.title = '현재'; - } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { - head.title = rtnData.planYrDc1?'1단계\n(' + rtnData.planYrDc1 + '년)':head.title = '1단계'; - } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { - head.title = rtnData.planYrDc2?'2단계\n(' + rtnData.planYrDc2 + '년)':head.title = '2단계'; - } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { - head.title = rtnData.planYrDc3? '3단계\n(' + rtnData.planYrDc3 + '년)':head.title = '3단계'; - } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { - head.title = rtnData.planYrDc4?'4단계\n(' + rtnData.planYrDc4 + '년)':head.title = '4단계'; - } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { - head.title = rtnData.planYrDt4?'기승인\n4단계(' + rtnData.planYrDt4 + '년)':head.title = '기승인\n4단계'; + upHeadListProcessAreaPlan.forEach((head: TableUpperProps) => { + if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = rtnData.planYr ? '현재\n(' + rtnData.planYr + '년)' : head.title = '현재'; + } else if (head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = rtnData.planYrDc1 ? '1단계\n(' + rtnData.planYrDc1 + '년)' : head.title = '1단계'; + } else if (head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = rtnData.planYrDc2 ? '2단계\n(' + rtnData.planYrDc2 + '년)' : head.title = '2단계'; + } else if (head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = rtnData.planYrDc3 ? '3단계\n(' + rtnData.planYrDc3 + '년)' : head.title = '3단계'; + } else if (head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = rtnData.planYrDc4 ? '4단계\n(' + rtnData.planYrDc4 + '년)' : head.title = '4단계'; + } else if (head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = rtnData.planYrDt4 ? '기승인\n4단계(' + rtnData.planYrDt4 + '년)' : head.title = '기승인\n4단계'; } }); - upHeadListProcessPopulation.forEach((head:TableUpperProps) => { - if(head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { - head.title = rtnData.planYr?'현재\n(' + rtnData.planYr + '년)':head.title = '현재'; - } else if(head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { - head.title = rtnData.planYrDc1?'1단계\n(' + rtnData.planYrDc1 + '년)':head.title = '1단계'; - } else if(head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { - head.title = rtnData.planYrDc2?'2단계\n(' + rtnData.planYrDc2 + '년)':head.title = '2단계'; - } else if(head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { - head.title = rtnData.planYrDc3?'3단계\n(' + rtnData.planYrDc3 + '년)':head.title = '3단계'; - } else if(head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { - head.title = rtnData.planYrDc4?'4단계\n(' + rtnData.planYrDc4 + '년)':head.title = '4단계'; - } else if(head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { - head.title = rtnData.planYrDt4?'기승인\n4단계(' + rtnData.planYrDt4 + '년)':head.title = '기승인\n4단계'; + upHeadListProcessPopulation.forEach((head: TableUpperProps) => { + if (head.id === 'planSwageQntSum' || head.id === 'swtrmtPpltnCnt' || head.id === 'swtrmtZoneArea') { + head.title = rtnData.planYr ? '현재\n(' + rtnData.planYr + '년)' : head.title = '현재'; + } else if (head.id === 'planSwageQntSumDc1' || head.id === 'swtrmtPpltnCntDc1' || head.id === 'swtrmtZoneAreaDc1') { + head.title = rtnData.planYrDc1 ? '1단계\n(' + rtnData.planYrDc1 + '년)' : head.title = '1단계'; + } else if (head.id === 'planSwageQntSumDc2' || head.id === 'swtrmtPpltnCntDc2' || head.id === 'swtrmtZoneAreaDc2') { + head.title = rtnData.planYrDc2 ? '2단계\n(' + rtnData.planYrDc2 + '년)' : head.title = '2단계'; + } else if (head.id === 'planSwageQntSumDc3' || head.id === 'swtrmtPpltnCntDc3' || head.id === 'swtrmtZoneAreaDc3') { + head.title = rtnData.planYrDc3 ? '3단계\n(' + rtnData.planYrDc3 + '년)' : head.title = '3단계'; + } else if (head.id === 'planSwageQntSumDc4' || head.id === 'swtrmtPpltnCntDc4' || head.id === 'swtrmtZoneAreaDc4') { + head.title = rtnData.planYrDc4 ? '4단계\n(' + rtnData.planYrDc4 + '년)' : head.title = '4단계'; + } else if (head.id === 'planSwageQntSumDt4' || head.id === 'swtrmtPpltnCntDt4' || head.id === 'swtrmtZoneAreaDt4') { + head.title = rtnData.planYrDt4 ? '기승인\n4단계(' + rtnData.planYrDt4 + '년)' : head.title = '기승인\n4단계'; } }); - + // 시설증설 계획 데이터 생성 const fcltyImproveInfo: FcltyImproveInfoProps = { planSwageQntSumDt4: rtnData.planSwageQntSumDt4, From fe216499ec097caf6335a850b84bc09412e61c7d Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 12 Jan 2026 13:43:26 +0900 Subject: [PATCH 48/92] =?UTF-8?q?fo:=20=EC=A3=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityWaterQlty/modal/page.tsx | 393 ++++++++---------- .../(with-layout)/facilityWaterQlty/page.tsx | 46 +- apps/fo/app/store/facilityWaterQlty/index.tsx | 317 +++++++------- 3 files changed, 346 insertions(+), 410 deletions(-) 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 c10fd50cf..76c65ca3b 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx @@ -25,10 +25,10 @@ const commentArrayRain = [ "강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날" ]; -type ModalProps ={ +type ModalProps = { fcltyName: string; - facilityCd : string; - searchYear : string; + facilityCd: string; + searchYear: string; } const tabList1 = [ @@ -50,15 +50,15 @@ const tabList3 = [ { value: 'tab_term_winter_chongin', label: '동절기' } ]; -export default function WaterQualityModal({fcltyName='', facilityCd='', searchYear=new Date().getFullYear().toString()} : ModalProps) { +export default function WaterQualityModal({ fcltyName = '', facilityCd = '', searchYear = new Date().getFullYear().toString() }: ModalProps) { const [tabName, setTabName] = useState<string>('tab_num1'); // 그리드 관련 - const {FacilityWaterQltyModal, + const { FacilityWaterQltyModal, searchFacilityWaterQltyListHist, Common } = useFoStore((state) => state); - const {btnClass, COD_YEAR} = Common; + const { btnClass, COD_YEAR } = Common; const { upHeadListModalYear, upHeadListModalYearCod, @@ -71,7 +71,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe const prevExcelListRef = useRef<modalExcelType[] | null>(null); const prevChoinginExcelListRef = useRef<modalChoinginExcelType[] | null>(null); - + // 필터링 된 후 최대, 최소, 평균 값 계산 const setFilterAfterData = (filteredData: FacilityWaterQltyProps[]) => { // 쉼표가 포함된 문자열을 숫자로 변환하는 함수 @@ -100,7 +100,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe let maxNoProcessInflAmnt = 0; let maxInfoRnDay = 0; - + // 초기값 설정 let minEfflWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltBod) : 0; let minEfflWqltTn = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltTn) : 0; @@ -108,14 +108,14 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe let minefflWqltToc = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltToc) : 0; let minefflWqltCod = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltCod) : 0; let minEfflWqltSs = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltSs) : 0; - + let mininflAssctBfrWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltBod) : 0; let mininflAssctBfrWqltTn = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltTn) : 0; let minInflAssctBfrWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltTp) : 0; let mininflAssctBfrWqltToc = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltToc) : 0; let mininflAssctBfrWqltCod = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltCod) : 0; let mininflAssctBfrWqltSs = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltSs) : 0; - + let minTpInflWqltBod = 99999999; let minTpInflWqltTp = 99999999; let minNoProcessInflAmnt = 99999999; @@ -143,27 +143,27 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe let noProcessInflAmntCnt = 0; let avgInfoRnDay = 0; - + filteredData.forEach((item: FacilityWaterQltyProps) => { const efflWqltBod = parseNumber(item.efflWqltBod); const efflWqltTn = parseNumber(item.efflWqltTn); const efflWqltTp = parseNumber(item.efflWqltTp); const efflWqltToc = parseNumber(item.efflWqltToc); - const efflWqltCod = parseNumber(item.efflWqltCod?item.efflWqltCod.replaceAll("(","").replaceAll(")",""):0); + const efflWqltCod = parseNumber(item.efflWqltCod ? item.efflWqltCod.replaceAll("(", "").replaceAll(")", "") : 0); const efflWqltSs = parseNumber(item.efflWqltSs); const inflAssctBfrWqltBod = parseNumber(item.inflAssctBfrWqltBod); const inflAssctBfrWqltTn = parseNumber(item.inflAssctBfrWqltTn); const inflAssctBfrWqltTp = parseNumber(item.inflAssctBfrWqltTp); const inflAssctBfrWqltToc = parseNumber(item.inflAssctBfrWqltToc); - const inflAssctBfrWqltCod = parseNumber(item.inflAssctBfrWqltCod?item.inflAssctBfrWqltCod.replaceAll("(","").replaceAll(")",""):0); + const inflAssctBfrWqltCod = parseNumber(item.inflAssctBfrWqltCod ? item.inflAssctBfrWqltCod.replaceAll("(", "").replaceAll(")", "") : 0); const inflAssctBfrWqltSs = parseNumber(item.inflAssctBfrWqltSs); const tpInflWqltBod = parseNumber(item.tpInflWqltBod); const tpInflWqltTp = parseNumber(item.tpInflWqltTp); - if(item.tpInflWqltBod != null && item.tpInflWqltBod.trim() != '' && item.tpInflWqltBod != undefined ){ + if (item.tpInflWqltBod != null && item.tpInflWqltBod.trim() != '' && item.tpInflWqltBod != undefined) { tpInflWqltBodCnt += 1; } - if(item.tpInflWqltTp != null && item.tpInflWqltTp.trim() != '' && item.tpInflWqltTp != undefined ){ + if (item.tpInflWqltTp != null && item.tpInflWqltTp.trim() != '' && item.tpInflWqltTp != undefined) { tpInflWqltTpCnt += 1; } @@ -175,7 +175,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe maxefflWqltToc = Math.max(maxefflWqltToc, efflWqltToc); maxefflWqltCod = Math.max(maxefflWqltCod, efflWqltCod); maxEfflWqltSs = Math.max(maxEfflWqltSs, efflWqltSs); - + maxinflAssctBfrWqltBod = Math.max(maxinflAssctBfrWqltBod, inflAssctBfrWqltBod); maxinflAssctBfrWqltTn = Math.max(maxinflAssctBfrWqltTn, inflAssctBfrWqltTn); maxInflAssctBfrWqltTp = Math.max(maxInflAssctBfrWqltTp, inflAssctBfrWqltTp); @@ -202,11 +202,11 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe mininflAssctBfrWqltCod = Math.min(mininflAssctBfrWqltToc, inflAssctBfrWqltCod); mininflAssctBfrWqltSs = Math.min(mininflAssctBfrWqltSs, inflAssctBfrWqltSs); - if(item.tpInflWqltBod != null && item.tpInflWqltBod.trim() != '' && item.tpInflWqltBod != undefined ){ + if (item.tpInflWqltBod != null && item.tpInflWqltBod.trim() != '' && item.tpInflWqltBod != undefined) { minTpInflWqltBod = Math.min(minTpInflWqltBod, tpInflWqltBod); avgTpInflWqltBod += tpInflWqltBod; } - if(item.tpInflWqltTp != null && item.tpInflWqltTp.trim() != '' && item.tpInflWqltTp != undefined ){ + if (item.tpInflWqltTp != null && item.tpInflWqltTp.trim() != '' && item.tpInflWqltTp != undefined) { minTpInflWqltTp = Math.min(minTpInflWqltTp, tpInflWqltTp); avgTpInflWqltTp += tpInflWqltTp; } @@ -227,12 +227,12 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe avginflAssctBfrWqltCod += inflAssctBfrWqltCod; avginflAssctBfrWqltSs += inflAssctBfrWqltSs; - if(item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined){ - const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',','')); + if (item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined) { + const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',', '')); avgNoProcessInflAmnt += noProcessInflAmnt; maxNoProcessInflAmnt = Math.max(maxNoProcessInflAmnt, noProcessInflAmnt); minNoProcessInflAmnt = Math.min(minNoProcessInflAmnt, noProcessInflAmnt); - noProcessInflAmntCnt +=1; + noProcessInflAmntCnt += 1; } avgInfoRnDay += infoRnDay; @@ -241,18 +241,18 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe const newFilteredData = [ { msrDt: '평균', - efflWqltBod: filteredData.length==0 || avgEfflWqltBod===0?'0.0':roundNumber((avgEfflWqltBod / filteredData.length), 1), - efflWqltToc: filteredData.length==0 || avgefflWqltToc===0?'0.0':roundNumber((avgefflWqltToc / filteredData.length), 1), - efflWqltCod: filteredData.length==0 || avgefflWqltCod===0?"(0.0)":"("+roundNumber((avgefflWqltCod / filteredData.length), 1)+")", - efflWqltSs: filteredData.length==0 || avgEfflWqltSs===0?'0.0':roundNumber((avgEfflWqltSs / filteredData.length), 1), - efflWqltTn: filteredData.length==0 || avgEfflWqltTn ===0?'0.000':roundNumber((avgEfflWqltTn / filteredData.length), 3), - efflWqltTp: filteredData.length==0 || avgEfflWqltTp ===0?'0.000':roundNumber((avgEfflWqltTp / filteredData.length), 3), - inflAssctBfrWqltBod: filteredData.length==0 || avginflAssctBfrWqltBod===0?'0.0':roundNumber((avginflAssctBfrWqltBod / filteredData.length), 1), - inflAssctBfrWqltTn: filteredData.length==0 || avginflAssctBfrWqltTn===0?'0.000':roundNumber((avginflAssctBfrWqltTn / filteredData.length), 3), - inflAssctBfrWqltTp: filteredData.length==0 || avgInflAssctBfrWqltTp===0?'0.000':roundNumber((avgInflAssctBfrWqltTp / filteredData.length), 3), - inflAssctBfrWqltToc: filteredData.length==0 || avginflAssctBfrWqltToc===0?'0.0':roundNumber((avginflAssctBfrWqltToc / filteredData.length), 1), - inflAssctBfrWqltCod: filteredData.length==0 || avginflAssctBfrWqltCod===0?'(0.0)':"("+roundNumber((avginflAssctBfrWqltCod / filteredData.length), 1)+")", - inflAssctBfrWqltSs: filteredData.length==0 || avginflAssctBfrWqltSs===0?'0.0':roundNumber((avginflAssctBfrWqltSs / filteredData.length), 1), + efflWqltBod: filteredData.length == 0 || avgEfflWqltBod === 0 ? '0.0' : roundNumber((avgEfflWqltBod / filteredData.length), 1), + efflWqltToc: filteredData.length == 0 || avgefflWqltToc === 0 ? '0.0' : roundNumber((avgefflWqltToc / filteredData.length), 1), + efflWqltCod: filteredData.length == 0 || avgefflWqltCod === 0 ? "(0.0)" : "(" + roundNumber((avgefflWqltCod / filteredData.length), 1) + ")", + efflWqltSs: filteredData.length == 0 || avgEfflWqltSs === 0 ? '0.0' : roundNumber((avgEfflWqltSs / filteredData.length), 1), + efflWqltTn: filteredData.length == 0 || avgEfflWqltTn === 0 ? '0.000' : roundNumber((avgEfflWqltTn / filteredData.length), 3), + efflWqltTp: filteredData.length == 0 || avgEfflWqltTp === 0 ? '0.000' : roundNumber((avgEfflWqltTp / filteredData.length), 3), + inflAssctBfrWqltBod: filteredData.length == 0 || avginflAssctBfrWqltBod === 0 ? '0.0' : roundNumber((avginflAssctBfrWqltBod / filteredData.length), 1), + inflAssctBfrWqltTn: filteredData.length == 0 || avginflAssctBfrWqltTn === 0 ? '0.000' : roundNumber((avginflAssctBfrWqltTn / filteredData.length), 3), + inflAssctBfrWqltTp: filteredData.length == 0 || avgInflAssctBfrWqltTp === 0 ? '0.000' : roundNumber((avgInflAssctBfrWqltTp / filteredData.length), 3), + inflAssctBfrWqltToc: filteredData.length == 0 || avginflAssctBfrWqltToc === 0 ? '0.0' : roundNumber((avginflAssctBfrWqltToc / filteredData.length), 1), + inflAssctBfrWqltCod: filteredData.length == 0 || avginflAssctBfrWqltCod === 0 ? '(0.0)' : "(" + roundNumber((avginflAssctBfrWqltCod / filteredData.length), 1) + ")", + inflAssctBfrWqltSs: filteredData.length == 0 || avginflAssctBfrWqltSs === 0 ? '0.0' : roundNumber((avginflAssctBfrWqltSs / filteredData.length), 1), bscFctCd: "", bscFctNm: "", lclgvrnmntNm: "", @@ -260,25 +260,25 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe sggNm: "", addr: "", fctCpc: 0, - noProcessInflAmnt : roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0), - infoRnDay: filteredData.length==0 || avgInfoRnDay===0?'0.0':roundNumber(avgInfoRnDay / filteredData.length, 1), - tpInflWqltBod: filteredData.length==0 || avgTpInflWqltBod ===0 ?'0.0':roundNumber(avgTpInflWqltBod / tpInflWqltBodCnt, 1), - tpInflWqltTp: filteredData.length==0 || avgTpInflWqltTp === 0?'0.000':roundNumber(avgTpInflWqltTp / tpInflWqltTpCnt, 3) + noProcessInflAmnt: roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0), + infoRnDay: filteredData.length == 0 || avgInfoRnDay === 0 ? '0.0' : roundNumber(avgInfoRnDay / filteredData.length, 1), + tpInflWqltBod: filteredData.length == 0 || avgTpInflWqltBod === 0 ? '0.0' : roundNumber(avgTpInflWqltBod / tpInflWqltBodCnt, 1), + tpInflWqltTp: filteredData.length == 0 || avgTpInflWqltTp === 0 ? '0.000' : roundNumber(avgTpInflWqltTp / tpInflWqltTpCnt, 3) }, { - msrDt : '최대', - efflWqltBod : Math.round(maxEfflWqltBod * 10) / 10?roundNumber(maxEfflWqltBod, 1):'0.0', - efflWqltToc : Math.round(maxefflWqltToc * 10) / 10?roundNumber(maxefflWqltToc, 1):'0.0', - efflWqltCod : Math.round(maxefflWqltCod * 10) / 10?"("+roundNumber(maxefflWqltCod, 1)+")":'(0.0)', - efflWqltSs : Math.round(maxEfflWqltSs * 10) / 10?roundNumber(maxEfflWqltSs, 1):'0.0', - efflWqltTn : Math.round(maxEfflWqltTn * 1000) / 1000?roundNumber(maxEfflWqltTn, 3):'0.000', - efflWqltTp : Math.round(maxEfflWqltTp * 1000) / 1000?roundNumber(maxEfflWqltTp, 3):'0.000', - inflAssctBfrWqltBod : Math.round(maxinflAssctBfrWqltBod * 10) / 10?roundNumber(maxinflAssctBfrWqltBod, 1):'0.0', - inflAssctBfrWqltTn : Math.round(maxinflAssctBfrWqltTn * 1000) / 1000?roundNumber(maxinflAssctBfrWqltTn, 3):'0.000', - inflAssctBfrWqltTp : Math.round(maxInflAssctBfrWqltTp * 1000) / 1000?roundNumber(maxInflAssctBfrWqltTp, 3):'0.000', - inflAssctBfrWqltToc : Math.round(maxinflAssctBfrWqltToc * 10) / 10?roundNumber(maxinflAssctBfrWqltToc, 1):'0.0', - inflAssctBfrWqltCod : Math.round(maxinflAssctBfrWqltCod * 10) / 10?"("+roundNumber(maxinflAssctBfrWqltCod, 1)+")":'(0.0)', - inflAssctBfrWqltSs : Math.round(maxinflAssctBfrWqltSs * 10) / 10?roundNumber(maxinflAssctBfrWqltSs, 1):'0.0', + msrDt: '최대', + efflWqltBod: Math.round(maxEfflWqltBod * 10) / 10 ? roundNumber(maxEfflWqltBod, 1) : '0.0', + efflWqltToc: Math.round(maxefflWqltToc * 10) / 10 ? roundNumber(maxefflWqltToc, 1) : '0.0', + efflWqltCod: Math.round(maxefflWqltCod * 10) / 10 ? "(" + roundNumber(maxefflWqltCod, 1) + ")" : '(0.0)', + efflWqltSs: Math.round(maxEfflWqltSs * 10) / 10 ? roundNumber(maxEfflWqltSs, 1) : '0.0', + efflWqltTn: Math.round(maxEfflWqltTn * 1000) / 1000 ? roundNumber(maxEfflWqltTn, 3) : '0.000', + efflWqltTp: Math.round(maxEfflWqltTp * 1000) / 1000 ? roundNumber(maxEfflWqltTp, 3) : '0.000', + inflAssctBfrWqltBod: Math.round(maxinflAssctBfrWqltBod * 10) / 10 ? roundNumber(maxinflAssctBfrWqltBod, 1) : '0.0', + inflAssctBfrWqltTn: Math.round(maxinflAssctBfrWqltTn * 1000) / 1000 ? roundNumber(maxinflAssctBfrWqltTn, 3) : '0.000', + inflAssctBfrWqltTp: Math.round(maxInflAssctBfrWqltTp * 1000) / 1000 ? roundNumber(maxInflAssctBfrWqltTp, 3) : '0.000', + inflAssctBfrWqltToc: Math.round(maxinflAssctBfrWqltToc * 10) / 10 ? roundNumber(maxinflAssctBfrWqltToc, 1) : '0.0', + inflAssctBfrWqltCod: Math.round(maxinflAssctBfrWqltCod * 10) / 10 ? "(" + roundNumber(maxinflAssctBfrWqltCod, 1) + ")" : '(0.0)', + inflAssctBfrWqltSs: Math.round(maxinflAssctBfrWqltSs * 10) / 10 ? roundNumber(maxinflAssctBfrWqltSs, 1) : '0.0', bscFctCd: "", bscFctNm: "", lclgvrnmntNm: "", @@ -286,25 +286,25 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe sggNm: "", addr: "", fctCpc: 0, - noProcessInflAmnt : roundNumber(maxNoProcessInflAmnt, 0), - infoRnDay: Math.round(maxInfoRnDay * 10) / 10?roundNumber(maxInfoRnDay, 1):'0.0', - tpInflWqltBod: Math.round(maxTpInflWqltBod * 10) / 10?roundNumber(maxTpInflWqltBod, 1):'0.0', - tpInflWqltTp: Math.round(maxTpInflWqltTp * 1000) / 1000?roundNumber(maxTpInflWqltTp, 3):'0.000' + noProcessInflAmnt: roundNumber(maxNoProcessInflAmnt, 0), + infoRnDay: Math.round(maxInfoRnDay * 10) / 10 ? roundNumber(maxInfoRnDay, 1) : '0.0', + tpInflWqltBod: Math.round(maxTpInflWqltBod * 10) / 10 ? roundNumber(maxTpInflWqltBod, 1) : '0.0', + tpInflWqltTp: Math.round(maxTpInflWqltTp * 1000) / 1000 ? roundNumber(maxTpInflWqltTp, 3) : '0.000' }, { - msrDt : '최소', - efflWqltBod : Math.round(minEfflWqltBod * 10) / 10?roundNumber(minEfflWqltBod, 1) : '0.0', - efflWqltToc : Math.round(minefflWqltToc * 10) / 10?roundNumber(minefflWqltToc, 1) : '0.0', - efflWqltCod : Math.round(minefflWqltCod * 10) / 10?"("+roundNumber(minefflWqltCod, 1)+")" : '(0.0)', - efflWqltSs : Math.round(minEfflWqltSs * 10) / 10?roundNumber(minEfflWqltSs, 1) : '0.0', - efflWqltTn : Math.round(minEfflWqltTn * 1000) / 1000?roundNumber(minEfflWqltTn, 3) : '0.000', - efflWqltTp : Math.round(minEfflWqltTp * 1000) / 1000?roundNumber(minEfflWqltTp, 3) : '0.000', - inflAssctBfrWqltBod : Math.round(mininflAssctBfrWqltBod * 10) / 10?roundNumber(mininflAssctBfrWqltBod, 1) : '0.0', - inflAssctBfrWqltTn : Math.round(mininflAssctBfrWqltTn * 1000) / 1000?roundNumber(mininflAssctBfrWqltTn, 3) : '0.000', - inflAssctBfrWqltTp : Math.round(minInflAssctBfrWqltTp * 1000) / 1000?roundNumber(minInflAssctBfrWqltTp, 3) : '0.000', - inflAssctBfrWqltToc : Math.round(mininflAssctBfrWqltToc * 10) / 10?roundNumber(mininflAssctBfrWqltToc, 1) : '0.0', - inflAssctBfrWqltCod : Math.round(mininflAssctBfrWqltCod * 10) / 10?"("+roundNumber(mininflAssctBfrWqltCod, 1)+")" : '(0.0)', - inflAssctBfrWqltSs : Math.round(mininflAssctBfrWqltSs * 10) / 10?roundNumber(mininflAssctBfrWqltSs, 1) : '0.0', + msrDt: '최소', + efflWqltBod: Math.round(minEfflWqltBod * 10) / 10 ? roundNumber(minEfflWqltBod, 1) : '0.0', + efflWqltToc: Math.round(minefflWqltToc * 10) / 10 ? roundNumber(minefflWqltToc, 1) : '0.0', + efflWqltCod: Math.round(minefflWqltCod * 10) / 10 ? "(" + roundNumber(minefflWqltCod, 1) + ")" : '(0.0)', + efflWqltSs: Math.round(minEfflWqltSs * 10) / 10 ? roundNumber(minEfflWqltSs, 1) : '0.0', + efflWqltTn: Math.round(minEfflWqltTn * 1000) / 1000 ? roundNumber(minEfflWqltTn, 3) : '0.000', + efflWqltTp: Math.round(minEfflWqltTp * 1000) / 1000 ? roundNumber(minEfflWqltTp, 3) : '0.000', + inflAssctBfrWqltBod: Math.round(mininflAssctBfrWqltBod * 10) / 10 ? roundNumber(mininflAssctBfrWqltBod, 1) : '0.0', + inflAssctBfrWqltTn: Math.round(mininflAssctBfrWqltTn * 1000) / 1000 ? roundNumber(mininflAssctBfrWqltTn, 3) : '0.000', + inflAssctBfrWqltTp: Math.round(minInflAssctBfrWqltTp * 1000) / 1000 ? roundNumber(minInflAssctBfrWqltTp, 3) : '0.000', + inflAssctBfrWqltToc: Math.round(mininflAssctBfrWqltToc * 10) / 10 ? roundNumber(mininflAssctBfrWqltToc, 1) : '0.0', + inflAssctBfrWqltCod: Math.round(mininflAssctBfrWqltCod * 10) / 10 ? "(" + roundNumber(mininflAssctBfrWqltCod, 1) + ")" : '(0.0)', + inflAssctBfrWqltSs: Math.round(mininflAssctBfrWqltSs * 10) / 10 ? roundNumber(mininflAssctBfrWqltSs, 1) : '0.0', bscFctCd: "", bscFctNm: "", lclgvrnmntNm: "", @@ -312,10 +312,10 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe sggNm: "", addr: "", fctCpc: 0, - noProcessInflAmnt : roundNumber(minNoProcessInflAmnt, 0), - infoRnDay: Math.round(minInfoRnDay * 10) / 10?'0.0':roundNumber(minInfoRnDay, 1), - tpInflWqltBod: Math.round(minTpInflWqltBod * 10) / 10 && minTpInflWqltBod != 99999999?roundNumber(minTpInflWqltBod, 1):'0.0', - tpInflWqltTp: Math.round(minTpInflWqltTp * 1000) / 1000 && minTpInflWqltTp != 99999999?roundNumber(minTpInflWqltTp, 3):'0.000' + noProcessInflAmnt: roundNumber(minNoProcessInflAmnt, 0), + infoRnDay: Math.round(minInfoRnDay * 10) / 10 ? '0.0' : roundNumber(minInfoRnDay, 1), + tpInflWqltBod: Math.round(minTpInflWqltBod * 10) / 10 && minTpInflWqltBod != 99999999 ? roundNumber(minTpInflWqltBod, 1) : '0.0', + tpInflWqltTp: Math.round(minTpInflWqltTp * 1000) / 1000 && minTpInflWqltTp != 99999999 ? roundNumber(minTpInflWqltTp, 3) : '0.000' }, ...filteredData ]; @@ -326,7 +326,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe // 날짜 필터링 관련 상태 const [copyYearList, setCopyYearList] = useState<FacilityWaterQltyProps[]>([]); const [chongInWaterQltyYearList, setChongInWaterQltyYearList] = useState<FacilityWaterQltyProps[]>([]); - + useEffect(() => { searchFacilityWaterQltyListHist(searchYear, facilityCd); }, [searchYear, facilityCd, searchFacilityWaterQltyListHist]); @@ -354,10 +354,10 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe }, []); const excelDownload = () => { - - if(tabName === 'tab_num1'){ + + if (tabName === 'tab_num1') { //처리시설 수질현황 const excelDownList: modalExcelType[] = []; - if(copyYearList.length > 0){ + if (copyYearList.length > 0) { copyYearList.forEach((item) => { excelDownList.push({ 날짜: item.msrDt, @@ -371,26 +371,27 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe "유출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"), + "강우량(mm/일)": CommaToNumber(item.infoRnDay ? item.infoRnDay.toString() : "0.0"), }); }); } if (excelDownList && excelDownList.length > 0) { downloadExcelFormat( - { data: JSON.parse(JSON.stringify(excelDownList)) - , fileName: searchYear+'년 '+fcltyName + ' 수질현황' + { + 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] + , 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{ + } else { // 총인설비 수질현황 const excelDownList: modalChoinginExcelType[] = []; - if(chongInWaterQltyYearList.length > 0){ + if (chongInWaterQltyYearList.length > 0) { chongInWaterQltyYearList.forEach((item) => { excelDownList.push({ 날짜: item.msrDt, @@ -403,12 +404,13 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe } if (excelDownList && excelDownList.length > 0) { downloadExcelFormat( - { data: JSON.parse(JSON.stringify(excelDownList)) - , fileName: searchYear+'년 '+fcltyName + ' 총인설비수질현황' + { + data: JSON.parse(JSON.stringify(excelDownList)) + , fileName: searchYear + '년 ' + fcltyName + ' 총인설비수질현황' , sheetNameArray: [fcltyName + ' 총인설비수질현황'] , headerRange: 'A1:E1' - , decimalArray1: [1,3] - , decimalArray3: [2,4] + , decimalArray1: [1, 3] + , decimalArray3: [2, 4] }); } else if (prevChoinginExcelListRef.current && prevChoinginExcelListRef.current.length > 0) { alert('다운받을 데이터가 없습니다.'); @@ -424,7 +426,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe return ( <> <UITab tabList={tabList1} defaultValue="tab_num1" onValueChange={(value) => setTabName(value)}> - <Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownload}> + <Button className={btnClass} style={{ float: 'right' }} color="green" onClick={excelDownload}> {"엑셀다운로드"} </Button> {/* 처리시설 수질현황 */} @@ -433,24 +435,16 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe <TabsContent value="tab_term_year"> <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName={"tab_term_year"} - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_year" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[350px]"> - <UiTable - headName={undefined} - tableData={copyYearList} - headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[310px]" - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={Number(searchYear) < COD_YEAR ? upHeadListModalYearCod : upHeadListModalYear} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[310px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> </UiTable> @@ -460,132 +454,97 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe {/*<h3 className="text-2xl font-medium text-label text-right">({msrmtDate?msrmtDate.substring(0,4)+'-'+msrmtDate.substring(4,6)+'-'+msrmtDate.substring(6,8):yesterDayStr})</h3> */} </div> <div className="overflow-y-auto h-[250px]"> - <UiTable - headName={undefined} - tableData={tmsList} - headlist={upHeadListModalTms} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={tmsList} + headlist={upHeadListModalTms} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalTms} layoutNum={4} /> </UiTable> - {msrmtDate != yesterDayStr?.replaceAll('-','') ? ( - <UnderComment commentArray={["전날 데이터 결측으로 인해 가장 최근 데이터 표출함"]} divHeight="0"/> + {msrmtDate != yesterDayStr?.replaceAll('-', '') ? ( + <UnderComment commentArray={["전날 데이터 결측으로 인해 가장 최근 데이터 표출함"]} divHeight="0" /> ) : null} </div> </TabsContent> - <TabsContent value="tab_term_summer"> + <TabsContent value="tab_term_summer">{/* 하절기 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_summer" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_summer" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[500px]"> - <UiTable + <UiTable headName={undefined} tableData={copyYearList} - headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => { } } - className="h-[500px]" - boldArray={[0,1,2]} + headlist={Number(searchYear) < COD_YEAR ? upHeadListModalYearCod : upHeadListModalYear} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> </UiTable> </div> </TabsContent> - <TabsContent value="tab_term_winter"> + <TabsContent value="tab_term_winter">{/* 동절기 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_winter" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_winter" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[500px]"> - <UiTable - headName={undefined} - tableData={copyYearList} - headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[500px]" - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={Number(searchYear) < COD_YEAR ? upHeadListModalYearCod : upHeadListModalYear} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> </UiTable> </div> </TabsContent> - <TabsContent value="tab_term_chuncheon"> + <TabsContent value="tab_term_chuncheon">{/* 청천 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_chuncheon" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_chuncheon" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[500px]"> - <UiTable - headName={undefined} - tableData={copyYearList} - headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[500px]" - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={Number(searchYear) < COD_YEAR ? upHeadListModalYearCod : upHeadListModalYear} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> </UiTable> </div> - <UnderComment commentArray={commentArrayChungchun} divHeight="10"/> + <UnderComment commentArray={commentArrayChungchun} divHeight="10" /> </TabsContent> - <TabsContent value="tab_term_rain"> + <TabsContent value="tab_term_rain">{/* 강우시 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_rain" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_rain" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[500px]"> - <UiTable - headName={undefined} - tableData={copyYearList} - headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[500px]" - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={Number(searchYear) < COD_YEAR ? upHeadListModalYearCod : upHeadListModalYear} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> </UiTable> </div> - <UnderComment commentArray={commentArrayRain} divHeight="10"/> + <UnderComment commentArray={commentArrayRain} divHeight="10" /> </TabsContent> </UITab> </TabsContent> @@ -596,24 +555,16 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe <TabsContent value="tab_term_year_chongin"> <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={chongInWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_year" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_year" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[550px]"> - <UiTable - headName={undefined} - tableData={copyYearList} - headlist={upHeadListModalChongIn} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[500px]" - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalChongIn} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalChongIn} layoutNum={5} /> </UiTable> @@ -623,24 +574,16 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe <TabsContent value="tab_term_summer_chongin"> <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={chongInWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_summer" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_summer" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[550px]"> - <UiTable - headName={undefined} - tableData={copyYearList} - headlist={upHeadListModalChongIn} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[500px]" - boldArray={[0,1,2]} + <UiTable + headName={undefined} + tableData={copyYearList} + headlist={upHeadListModalChongIn} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalChongIn} layoutNum={5} /> </UiTable> @@ -650,24 +593,16 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe <TabsContent value="tab_term_winter_chongin"> <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={chongInWaterQltyYearList} - fcltyCd={facilityCd} - fcltyName={fcltyName} - tabName="tab_term_winter" - searchYear={searchYear} - ref={ref} - queryClick={filterData} + fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_winter" + searchYear={searchYear} ref={ref} queryClick={filterData} /> <div className="overflow-y-auto h-[550px]"> - <UiTable - headName={undefined} - tableData={copyYearList} + <UiTable + headName={undefined} + tableData={copyYearList} headlist={upHeadListModalChongIn} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={() => {}} - className="h-[500px]" - boldArray={[0,1,2]} + pageSize={0} total={0} cellClick={undefined} + onPageChange={() => { }} className="h-[500px]" boldArray={[0, 1, 2]} > <HeadMakeColSpan upHeadList={upHeadListModalChongIn} layoutNum={5} /> </UiTable> diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 885ee2728..86a434d6b 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -23,7 +23,7 @@ export default function ProcessFacilitySearch() { } = useFoStore((state) => state) || { FacilityWaterQltyList: { facilityWaterQltyList: [], facilityWaterQltyCount: 0 } }; const { - isInit, + isInit, selectUpdownData, selectOperationData, selectSidoData, @@ -66,26 +66,26 @@ export default function ProcessFacilitySearch() { const [fcltyCd, setFcltyCd] = useState<string>(""); const [modalYear, setModalYear] = useState<string>(""); - const searchFcltyQltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchFcltyQltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => { let nameCd, partStr; switch (partValue) { case 'R': if (regionValue !== '0') { - if(unitWaterShedValue==='0') nameCd = regionValue; - else if (middleRegionValue==='0') nameCd = unitWaterShedValue; + if (unitWaterShedValue === '0') nameCd = regionValue; + else if (middleRegionValue === '0') nameCd = unitWaterShedValue; else nameCd = middleRegionValue; } partStr = partValue break; default: - if(sidoValue !== '0') nameCd = ref.current.sidoValue!="0"?ref.current.sidoValue:sidoValue; - if(sigunValue !== '0') nameCd = sigunValue; - partStr = envPartValue !== '0' ? envPartValue:partValue; - break; + 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 ==='G'){ + if (partStr === 'G') { searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue); - }else{ + } else { searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); } }, [operationValue, fcltyName, searchFacilityWaterQltyList, searchYearValue, fcltCpct]); @@ -138,34 +138,34 @@ export default function ProcessFacilitySearch() { useEffect(() => { if (!isInit) { - if(!initTrigger){ + if (!initTrigger) { initializeCommonData(); searchFcltyQltyList(ref.current, 1, 10); - setInitTrigger(true); + setInitTrigger(true); } } }, [isInit, initializeCommonData, searchFacilityWaterQltyList, searchFcltyQltyList, initTrigger]); useEffect(() => { - if(!excelTrigger) return; + if (!excelTrigger) return; if (excelList && excelList.length > 0) { downloadExcelFormat( { - data: excelList as unknown as JSON[], - fileName: '시설별 수질현황', - sheetNameArray: ['시설별 수질현황'], + data: excelList as unknown as JSON[], + fileName: '시설별 수질현황', + sheetNameArray: ['시설별 수질현황'], headerRange: 'A1:T1', - decimalArray1:[10,11,12,15,16,17], - decimalArray3:[13,14,18,19] + decimalArray1: [10, 11, 12, 15, 16, 17], + decimalArray3: [13, 14, 18, 19] } ); } }, [excelList, excelTrigger]); - const chkVal = useCallback((returntype:ReturnType) => { + const chkVal = useCallback((returntype: ReturnType) => { // setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") - setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1); + setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G' ? upHeadList3 : upHeadList1); setResetPage(true); }, [upHeadList1, upHeadList2, upHeadList3]); @@ -173,7 +173,7 @@ export default function ProcessFacilitySearch() { setExcelTrigger(true); searchFcltyQltyList(ref.current, 1, 10000); }, [searchFcltyQltyList]); - + const handlePageChange = useCallback((page: number) => { setResetPage(false); searchFcltyQltyList(ref.current, page, 10); @@ -202,7 +202,7 @@ export default function ProcessFacilitySearch() { queryClick={chkVal} excelClick={excelDownload} initClick={resetVal} - ref={ref} isAdmin={false} initSidoValue={"11"}/> + ref={ref} isAdmin={false} initSidoValue={"11"} /> <ListDiv> <LoadingOverlay isLoading={isLoading} /> <div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden"> @@ -215,7 +215,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( <UiModal body={<WaterQualityModal fcltyName={fcltyNm} facilityCd={fcltyCd} searchYear={modalYear}></WaterQualityModal>} - bodyClass="sm:max-w-[90vw] w-[1300px] h-[920px]" + bodyClass="sm:max-w-[90vw] w-[1300px] h-[100dvh] max-h-[930px] overflow-y-auto" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} noHeaderYn="Y" diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index 0eafcfcd0..5d2e886f4 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -37,8 +37,8 @@ export interface FacilityWaterQltyProps { inflAssctAftWqltBod: string | '', inflAssctBfrWqltToc: string | '', inflAssctAftWqltToc: string | '', - inflAssctBfrWqltCod : string | '', - inflAssctAftWqltCod : string | '', + inflAssctBfrWqltCod: string | '', + inflAssctAftWqltCod: string | '', inflAssctBfrWqltSs: string | '', inflAssctAftWqltSs: string | '', inflAssctBfrWqltTn: string | '', @@ -47,14 +47,14 @@ export interface FacilityWaterQltyProps { inflAssctAftWqltTp: string | '', efflWqltBod: string | '', efflWqltToc: string | '', - efflWqltCod : string | '', + efflWqltCod: string | '', efflWqltSs: string | '', efflWqltTn: string | '', efflWqltTp: string | '', - rgnNm:string|'', - rvbsn:string|'', - lgbsn:string|'', - mdmbsn:string|'', + rgnNm: string | '', + rvbsn: string | '', + lgbsn: string | '', + mdmbsn: string | '', inflAmnt: number | '', lclgvrnmntNm: string, infoRnDay: number | string | '', @@ -68,14 +68,14 @@ export interface FacilityWaterQltyProps { tpInflWqltTp: string | '', tpInflWqltEclgyTox: string | '', tpInflWqltClfgrpcnt: string | '', - noProcessInflAmnt : string | number | '', + noProcessInflAmnt: string | number | '', } export interface ExcelType { 시설코드: string, - 권역:string|'', - 단위유역:string|'', - 중권역:string|'', - 환경청:string|'', + 권역: string | '', + 단위유역: string | '', + 중권역: string | '', + 환경청: string | '', 시도: string, 시군구: string, 시설이름: string, @@ -146,74 +146,74 @@ const mainLabelArray: string[] = ['구분', '시도', '시군구', '용량별', // 시설수질리스트 헤더(행정별) const upHeadList1: TableUpperProps[] = [ - { id: "C", title: "행정명", colSpan: 2, row:0, widthPercent:10 }, - { id: "sidoNm", title: "시도", row: 1, widthPercent:5}, - { id: "sggNm", title: "시군구", row: 1, widthPercent:5 }, + { id: "C", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 }, + { id: "sidoNm", title: "시도", row: 1, widthPercent: 5 }, + { id: "sggNm", title: "시군구", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", rowSpan: 2, row: 0, widthPercent: 10 }, { id: "addr", title: "주소", rowSpan: 2, row: 0 }, - { id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0, widthPercent:10 }, - { id: "A", title: "유입", colSpan: 5, row: 0, widthPercent:25 }, - { id: "B", title: "방류", colSpan: 5, row: 0, widthPercent:25 }, - { id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1, widthPercent:5 }, - { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent:5 }, - { id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent:5 }, - { id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 4, align: "right", row: 1, widthPercent:5 }, - { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent:5 }, - { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1, widthPercent:5 }, - { id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent:5 }, - { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent:5 }, - { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 4, align: "right", row: 1, widthPercent:5 }, - { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent:5 }, + { id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0, widthPercent: 10 }, + { id: "A", title: "유입", colSpan: 5, row: 0, widthPercent: 25 }, + { id: "B", title: "방류", colSpan: 5, row: 0, widthPercent: 25 }, + { id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 4, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 4, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, ]; // 시설수질리스트 헤더(권역별) const upHeadList2: TableUpperProps[] = [ - { id: "C", title: "유역", colSpan: 3, row: 0, widthPercent:15 }, - { id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row:1, widthPercent:5 }, - { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row:1, widthPercent:5 }, - { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row:1, widthPercent:5 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent:10 }, - { id: "addr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2, widthPercent:8 }, - { id: "A", title: "유입", colSpan: 5, row: 0, widthPercent:25 }, - { id: "B", title: "방류", colSpan: 5, row: 0, widthPercent:25 }, - { id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1, widthPercent:5 }, - { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent:5 }, - { id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent:5 }, - { id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent:5 }, - { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent:5 }, - { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1, widthPercent:5 }, - { id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent:5 }, - { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent:5 }, - { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent:5 }, - { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent:5 }, + { id: "C", title: "유역", colSpan: 3, row: 0, widthPercent: 15 }, + { id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row: 1, widthPercent: 5 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 }, + { id: "addr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "A", title: "유입", colSpan: 5, row: 0, widthPercent: 25 }, + { id: "B", title: "방류", colSpan: 5, row: 0, widthPercent: 25 }, + { id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent: 5 }, + { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent: 5 }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent: 5 }, ]; // 시설수질리스트 헤더(환경청별) const upHeadList3: TableUpperProps[] = [ { id: "C", title: "유역", colSpan: 3, row: 0, widthPercent: 15 }, - { id: "rvbsn", title: "권역", row:1, widthPercent: 5 }, - { id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 }, - { id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 }, - { id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 7 }, + { id: "rvbsn", title: "권역", row: 1, widthPercent: 5 }, + { id: "lgbsn", title: "단위유역", row: 1, widthPercent: 5 }, + { id: "mdmbsn", title: "중권역", row: 1, widthPercent: 5 }, + { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 7 }, { id: "D", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 }, - { id: "sidoNm", title: "시도", upName: "upChangeRe2", row:1, widthPercent: 5 }, - { id: "sggNm", title: "시군구", upName: "upChangeRe2", row:1, widthPercent: 5 }, - { id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 }, - { id: "addr", title: "주소", row:0, rowSpan:2 }, - { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2, widthPercent: 5 }, + { id: "sidoNm", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "sggNm", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, + { id: "addr", title: "주소", row: 0, rowSpan: 2 }, + { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row: 0, rowSpan: 2, widthPercent: 5 }, { id: "A", title: "유입", colSpan: 5, row: 0, widthPercent: 20 }, { id: "B", title: "방류", colSpan: 5, row: 0, widthPercent: 20 }, - { id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1, widthPercent: 4 }, - { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent: 4 }, - { id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent: 4 }, - { id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent: 4 }, - { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent: 4 }, - { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1, widthPercent: 4 }, - { id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent: 4 }, - { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent: 4 }, - { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent: 4 }, - { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent: 4 }, + { id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1, widthPercent: 4 }, + { id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent: 4 }, + { id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent: 4 }, + { id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent: 4 }, + { id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent: 4 }, + { id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1, widthPercent: 4 }, + { id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent: 4 }, + { id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent: 4 }, + { id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent: 4 }, + { id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent: 4 }, ]; /** @@ -282,9 +282,9 @@ const upHeadListModalChongIn: TableUpperProps[] = [ ====================================*/ // 메인페이지 // 시설정보 수질 리스트 데이터 호출 -const fetchFacilityWaterQltyList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string|undefined, nameCd?: string|undefined, fcltCpct?: string|undefined, operationValue?: string|undefined, fcltyNm?: string | undefined): Promise<{ data: FacilityWaterQltyProps[], count: number }> => { +const fetchFacilityWaterQltyList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string | undefined, nameCd?: string | undefined, fcltCpct?: string | undefined, operationValue?: string | undefined, fcltyNm?: string | undefined): Promise<{ data: FacilityWaterQltyProps[], count: number }> => { try { - const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; + const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; const res = await getFetch('fo', url); return { data: res.data, count: res.count } @@ -295,7 +295,7 @@ const fetchFacilityWaterQltyList = async (pageNo: number, pageSize: number, sear } // 시설정보 수질 리스트 데이터 호출(모달-수질TMS) -const fetchFacilityWaterQltyTmsList = async (facilityCd: string|undefined) => { +const fetchFacilityWaterQltyTmsList = async (facilityCd: string | undefined) => { try { const res = await getFetch('wr', '/il/getTms/' + facilityCd); return { data: res.data, count: res.count }; @@ -306,7 +306,7 @@ const fetchFacilityWaterQltyTmsList = async (facilityCd: string|undefined) => { }; // 시설정보 수질 리스트 데이터 호출(모달-이력) -export const fetchFacilityWaterQltyListHist = async (searchYear: string|undefined, facilityCd: string|undefined): Promise<WaterQualityHistoryResponse | null> => { +export const fetchFacilityWaterQltyListHist = async (searchYear: string | undefined, facilityCd: string | undefined): Promise<WaterQualityHistoryResponse | null> => { try {// const res = await getFetch('fo', '/fclt/qlty/hist/' + searchYear + '/' + facilityCd); return res; @@ -316,9 +316,9 @@ export const fetchFacilityWaterQltyListHist = async (searchYear: string|undefine } }; // 시설정보 RDII 상세 [{BOD - inflAssctBfrWqltBod, 유입유량 inflAmnt, 강우량 infoRnDay, 측정일 msrDt}] -export const fetchFacilityRdiiDetailList = async (searchYear: string|undefined, swtrmtFcltCdList: string[]): Promise<FacilityRdiiDetailProps | null> => { +export const fetchFacilityRdiiDetailList = async (searchYear: string | undefined, swtrmtFcltCdList: string[]): Promise<FacilityRdiiDetailProps | null> => { try { - const res = await postFetch('fo', '/rdii/detail/'+searchYear, swtrmtFcltCdList); + const res = await postFetch('fo', '/rdii/detail/' + searchYear, swtrmtFcltCdList); return res; } catch (error) { console.error('시설정보 RDII 상세 데이터를 가져오는데 실패했습니다:', error); @@ -345,7 +345,7 @@ export type FacilityWaterQltyType = { FacilityWaterQltyModal: { // 처리시설 수질현황 upHeadListModalYear: TableUpperProps[]; - upHeadListModalYearCod : TableUpperProps[]; + upHeadListModalYearCod: TableUpperProps[]; facilityWaterQltyYearList: FacilityWaterQltyProps[]; upHeadListModalTms: TableUpperProps[]; facilityWaterQltyTmsList: FacilityWaterQltyTmsProps[]; @@ -431,8 +431,9 @@ const dataFormSetting = (item: FacilityWaterQltyProps) => { } export type FacilityWaterQltyStore = FacilityWaterQltyType & FacilityWaterQltyActions; - -export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType) => FacilityWaterQltyType) => void): FacilityWaterQltyActions => { +// 타입 정의를 분리하여 가독성 향상 +type SetFunc = (fn: (state: FacilityWaterQltyType) => FacilityWaterQltyType) => void; +export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions => { return { // 메인페이지 /** @@ -457,53 +458,53 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); const rtnData = res.data.map(item => { dataFormSetting(item) - if(item.inflAssctBfrWqltTn) { - item.inflAssctBfrWqltTn = Number(Math.round(Number(item.inflAssctBfrWqltTn) * 1000)/1000).toFixed(3); + if (item.inflAssctBfrWqltTn) { + item.inflAssctBfrWqltTn = Number(Math.round(Number(item.inflAssctBfrWqltTn) * 1000) / 1000).toFixed(3); } - if(item.efflWqltTn){ - item.efflWqltTn = Number(Math.round(Number(item.efflWqltTn) * 1000)/1000).toFixed(3); + if (item.efflWqltTn) { + item.efflWqltTn = Number(Math.round(Number(item.efflWqltTn) * 1000) / 1000).toFixed(3); } - if(item.inflAssctBfrWqltTp){ - item.inflAssctBfrWqltTp = Number(Math.round(Number(item.inflAssctBfrWqltTp) * 1000)/1000).toFixed(3); + if (item.inflAssctBfrWqltTp) { + item.inflAssctBfrWqltTp = Number(Math.round(Number(item.inflAssctBfrWqltTp) * 1000) / 1000).toFixed(3); } - if(item.efflWqltTp){ - item.efflWqltTp = Number(Math.round(Number(item.efflWqltTp) * 1000)/1000).toFixed(3); + if (item.efflWqltTp) { + item.efflWqltTp = Number(Math.round(Number(item.efflWqltTp) * 1000) / 1000).toFixed(3); } - if(item.inflAssctBfrWqltToc){ - item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltToc) { + item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10) / 10).toFixed(1); } - if(item.efflWqltToc){ - item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10)/10).toFixed(1); + if (item.efflWqltToc) { + item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10) / 10).toFixed(1); } - if(item.inflAssctBfrWqltBod){ - item.inflAssctBfrWqltBod = Number(Math.round(Number(item.inflAssctBfrWqltBod) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltBod) { + item.inflAssctBfrWqltBod = Number(Math.round(Number(item.inflAssctBfrWqltBod) * 10) / 10).toFixed(1); } - if(item.efflWqltBod){ - item.efflWqltBod = Number(Math.round(Number(item.efflWqltBod) * 10)/10).toFixed(1); + if (item.efflWqltBod) { + item.efflWqltBod = Number(Math.round(Number(item.efflWqltBod) * 10) / 10).toFixed(1); } - if(item.inflAssctBfrWqltSs){ - item.inflAssctBfrWqltSs = Number(Math.round(Number(item.inflAssctBfrWqltSs) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltSs) { + item.inflAssctBfrWqltSs = Number(Math.round(Number(item.inflAssctBfrWqltSs) * 10) / 10).toFixed(1); } - if(item.efflWqltSs){ - item.efflWqltSs = Number(Math.round(Number(item.efflWqltSs) * 10)/10).toFixed(1); + if (item.efflWqltSs) { + item.efflWqltSs = Number(Math.round(Number(item.efflWqltSs) * 10) / 10).toFixed(1); } - if(item.inflAssctBfrWqltToc){ - item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltToc) { + item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10) / 10).toFixed(1); } - if(item.efflWqltToc){ - item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10)/10).toFixed(1); + if (item.efflWqltToc) { + item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10) / 10).toFixed(1); } return item; }); const excelDownList: ExcelType[] = []; - if(pageSize>5000){ + if (pageSize > 5000) { res.data.forEach(item => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; - item.inflAssctBfrWqltToc = Number(searchYear)<COD_YEAR? "("+item.inflAssctBfrWqltToc+")" : item.inflAssctBfrWqltToc; - item.efflWqltToc = Number(searchYear)<COD_YEAR? "("+item.efflWqltToc+")" : item.efflWqltToc; + item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc; + item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc; excelDownList.push({ 시설코드: item.bscFctCd, 권역: item.rvbsn, @@ -527,27 +528,27 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType "유출TP(mg/L)": CommaToNumber(item.efflWqltTp), }); }); - }else{ + } else { res.data.forEach((item: FacilityWaterQltyProps) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; - item.inflAssctBfrWqltToc = Number(searchYear)<COD_YEAR? "("+item.inflAssctBfrWqltToc+")" : item.inflAssctBfrWqltToc; - item.efflWqltToc = Number(searchYear)<COD_YEAR? "("+item.efflWqltToc+")" : item.efflWqltToc; + item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc; + item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc; }); } set((state: FacilityWaterQltyType) => ({ ...state, - FacilityWaterQltyMain: pageSize<5000?{ + FacilityWaterQltyMain: pageSize < 5000 ? { ...state.FacilityWaterQltyMain, facilityWaterQltyList: rtnData, facilityWaterQltyCount: res.count, - isLoading : false, - }:{ + isLoading: false, + } : { ...state.FacilityWaterQltyMain, excelList: excelDownList, - isLoading : false, + isLoading: false, }, })) }, @@ -555,10 +556,10 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType searchFacilityWaterQltyListHist: async (searchYear: string, facilityCd: string) => { const res = await fetchFacilityWaterQltyListHist(searchYear, facilityCd); const res1 = await fetchFacilityWaterQltyTmsList(facilityCd); - + let rtnMsrmtDate = ''; const rtnTmsList: FacilityWaterQltyTmsProps[] = []; - if(res1.data){ + if (res1.data) { rtnTmsList.push({ part: '평균', toc: res1.data.tocAvgVl, @@ -584,7 +585,7 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType }); rtnMsrmtDate = res1.data.msrmtDate; - }else{ + } else { rtnTmsList.push({ part: '평균', toc: 0, @@ -606,20 +607,20 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType toc: 0, ss: 0, tn: 0, - tp: 0, + tp: 0, }); rtnMsrmtDate = ''; } - - if(Array.isArray(res) || !res || !('data' in res) || !res.data || !res.data.wqltObjs || res.data.wqltObjs.length === 0) { + + if (Array.isArray(res) || !res || !('data' in res) || !res.data || !res.data.wqltObjs || res.data.wqltObjs.length === 0) { set((state: FacilityWaterQltyType) => ({ ...state, FacilityWaterQltyModal: { ...state.FacilityWaterQltyModal, facilityWaterQltyYearList: [], - tmsList : rtnTmsList, - msrmtDate : rtnMsrmtDate + tmsList: rtnTmsList, + msrmtDate: rtnMsrmtDate } })) return; @@ -627,7 +628,7 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType // facilityPrecipitation의 rainEffectDay 계산 로직을 적용 const data = CalcRainEffect(res.data.wqltObjs); - + /** * [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]​ /강우시 일별유입BOD) @@ -639,7 +640,7 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType let sunnyDay = 0; data.forEach(item => { - if(item.rainEffectDay == 1){ + if (item.rainEffectDay == 1) { //rainDay += 1; //rainInflAmnt += Number(item.inflAmnt); } else { @@ -650,69 +651,69 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType }); //const yearRainAmnt = rainInflAmnt===0?0:rainInflAmnt / rainDay; - const yearSunnyAmnt = sunnyInflAmnt===0?0:sunnyInflAmnt / sunnyDay; - const yearSunnyBod = sunnyBod===0?0:sunnyBod / sunnyDay; + const yearSunnyAmnt = sunnyInflAmnt === 0 ? 0 : sunnyInflAmnt / sunnyDay; + const yearSunnyBod = sunnyBod === 0 ? 0 : sunnyBod / sunnyDay; // const rtnData = data.map((item: FacilityWaterQltyProps) => { dataFormSetting(item) - if(item.inflAssctBfrWqltTn) { - item.inflAssctBfrWqltTn = Number(Math.round(Number(item.inflAssctBfrWqltTn) * 1000)/1000).toFixed(3); + if (item.inflAssctBfrWqltTn) { + item.inflAssctBfrWqltTn = Number(Math.round(Number(item.inflAssctBfrWqltTn) * 1000) / 1000).toFixed(3); } - if(item.efflWqltTn){ - item.efflWqltTn = Number(Math.round(Number(item.efflWqltTn) * 1000)/1000).toFixed(3); + if (item.efflWqltTn) { + item.efflWqltTn = Number(Math.round(Number(item.efflWqltTn) * 1000) / 1000).toFixed(3); } - if(item.inflAssctBfrWqltTp){ - item.inflAssctBfrWqltTp = Number(Math.round(Number(item.inflAssctBfrWqltTp) * 1000)/1000).toFixed(3); + if (item.inflAssctBfrWqltTp) { + item.inflAssctBfrWqltTp = Number(Math.round(Number(item.inflAssctBfrWqltTp) * 1000) / 1000).toFixed(3); } - if(item.efflWqltTp){ - item.efflWqltTp = Number(Math.round(Number(item.efflWqltTp) * 1000)/1000).toFixed(3); + if (item.efflWqltTp) { + item.efflWqltTp = Number(Math.round(Number(item.efflWqltTp) * 1000) / 1000).toFixed(3); } - if(item.inflAssctBfrWqltToc){ - item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltToc) { + item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10) / 10).toFixed(1); } - if(item.efflWqltToc){ - item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10)/10).toFixed(1); + if (item.efflWqltToc) { + item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10) / 10).toFixed(1); } - if(item.inflAssctBfrWqltCod){ - item.inflAssctBfrWqltCod = "("+Number(Math.round(Number(item.inflAssctBfrWqltCod) * 10)/10).toFixed(1)+")"; + if (item.inflAssctBfrWqltCod) { + item.inflAssctBfrWqltCod = "(" + Number(Math.round(Number(item.inflAssctBfrWqltCod) * 10) / 10).toFixed(1) + ")"; } - if(item.efflWqltCod){ - item.efflWqltCod = "("+Number(Math.round(Number(item.efflWqltCod) * 10)/10).toFixed(1)+")"; + if (item.efflWqltCod) { + item.efflWqltCod = "(" + Number(Math.round(Number(item.efflWqltCod) * 10) / 10).toFixed(1) + ")"; } - if(item.inflAssctBfrWqltBod){ - item.inflAssctBfrWqltBod = Number(Math.round(Number(item.inflAssctBfrWqltBod) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltBod) { + item.inflAssctBfrWqltBod = Number(Math.round(Number(item.inflAssctBfrWqltBod) * 10) / 10).toFixed(1); } - if(item.efflWqltBod){ - item.efflWqltBod = Number(Math.round(Number(item.efflWqltBod) * 10)/10).toFixed(1); + if (item.efflWqltBod) { + item.efflWqltBod = Number(Math.round(Number(item.efflWqltBod) * 10) / 10).toFixed(1); } - if(item.inflAssctBfrWqltSs){ - item.inflAssctBfrWqltSs = Number(Math.round(Number(item.inflAssctBfrWqltSs) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltSs) { + item.inflAssctBfrWqltSs = Number(Math.round(Number(item.inflAssctBfrWqltSs) * 10) / 10).toFixed(1); } - if(item.efflWqltSs){ - item.efflWqltSs = Number(Math.round(Number(item.efflWqltSs) * 10)/10).toFixed(1); + if (item.efflWqltSs) { + item.efflWqltSs = Number(Math.round(Number(item.efflWqltSs) * 10) / 10).toFixed(1); } - if(item.inflAssctBfrWqltToc){ - item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10)/10).toFixed(1); + if (item.inflAssctBfrWqltToc) { + item.inflAssctBfrWqltToc = Number(Math.round(Number(item.inflAssctBfrWqltToc) * 10) / 10).toFixed(1); } - if(item.efflWqltToc){ - item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10)/10).toFixed(1); + if (item.efflWqltToc) { + item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10) / 10).toFixed(1); } - if(item.tpInflWqltBod){ - item.tpInflWqltBod = item.tpInflWqltBod?Number(Math.round(Number(item.tpInflWqltBod) * 10)/10).toFixed(1):Number(item.tpInflWqltBod)===0?'0.0':''; - }else{ + if (item.tpInflWqltBod) { + item.tpInflWqltBod = item.tpInflWqltBod ? Number(Math.round(Number(item.tpInflWqltBod) * 10) / 10).toFixed(1) : Number(item.tpInflWqltBod) === 0 ? '0.0' : ''; + } else { item.tpInflWqltBod = ''; } - if(item.tpInflWqltTp){ - item.tpInflWqltTp = item.tpInflWqltTp?Number(Math.round(Number(item.tpInflWqltTp) * 1000)/1000).toFixed(3): Number(item.tpInflWqltTp)===0?'0.000':''; - }else{ + if (item.tpInflWqltTp) { + item.tpInflWqltTp = item.tpInflWqltTp ? Number(Math.round(Number(item.tpInflWqltTp) * 1000) / 1000).toFixed(3) : Number(item.tpInflWqltTp) === 0 ? '0.000' : ''; + } else { item.tpInflWqltTp = ''; } const dayBod = Number(item.inflAssctBfrWqltBod); const noProcessInflAmnt = roundNumber(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod, 0) - item.noProcessInflAmnt = noProcessInflAmnt && Number(noProcessInflAmnt.replaceAll(',','')) > 0 ? noProcessInflAmnt : ''; + item.noProcessInflAmnt = noProcessInflAmnt && Number(noProcessInflAmnt.replaceAll(',', '')) > 0 ? noProcessInflAmnt : ''; return item; }) @@ -721,8 +722,8 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType FacilityWaterQltyModal: { ...state.FacilityWaterQltyModal, facilityWaterQltyYearList: rtnData, - tmsList : rtnTmsList, - msrmtDate : rtnMsrmtDate + tmsList: rtnTmsList, + msrmtDate: rtnMsrmtDate } })) }, From 8f26c1482e5abcdc425ab63bd2bd32abc8cf5ab5 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 12 Jan 2026 22:40:58 +0900 Subject: [PATCH 49/92] =?UTF-8?q?fo:=20=EC=B4=9D=EC=9D=B8=EC=84=A4?= =?UTF-8?q?=EB=B9=84=20=EC=88=98=EC=A7=88=ED=98=84=ED=99=A9=20=EA=B8=B0?= =?UTF-8?q?=EA=B0=84=EB=B3=84=20exceldownload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/FacilityTermModalHeader.tsx | 2 +- .../facilityWaterQlty/modal/page.tsx | 55 +++++++++---------- apps/fo/app/store/facilityWaterQlty/index.tsx | 43 ++++----------- 3 files changed, 37 insertions(+), 63 deletions(-) diff --git a/apps/fo/app/components/common/FacilityTermModalHeader.tsx b/apps/fo/app/components/common/FacilityTermModalHeader.tsx index 4389e2f5a..a46b3652d 100644 --- a/apps/fo/app/components/common/FacilityTermModalHeader.tsx +++ b/apps/fo/app/components/common/FacilityTermModalHeader.tsx @@ -35,7 +35,7 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({ const [endDate, setEndDate] = useState<Date>(new Date(Number(searchYear), 11, 31)); const startPickerRef = useRef<HTMLDivElement>(null); const endPickerRef = useRef<HTMLDivElement>(null); - const [flowPanel, setFlowPanel] = useState<string>(selectFlowPanel[0]?.val ?? '0'); // 초기값 "전체" + const [flowPanel, setFlowPanel] = useState<string>(selectFlowPanel[0]?.val ?? '0'); // 강수구분 : 초기값 "전체" const [copySearchList, setCopySearchList] = useState<T[]>(searchList); const [standSearchList, setStandSearchList] = useState<T[]>(searchList); 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 76c65ca3b..7de556932 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx @@ -52,12 +52,10 @@ const tabList3 = [ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', searchYear = new Date().getFullYear().toString() }: ModalProps) { const [tabName, setTabName] = useState<string>('tab_num1'); - - // 그리드 관련 - const { FacilityWaterQltyModal, - searchFacilityWaterQltyListHist, - Common - } = useFoStore((state) => state); + // 날짜 필터링 관련 상태 + const [copyYearList, setCopyYearList] = useState<FacilityWaterQltyProps[]>([]); + const [chongInWaterQltyYearList, setChongInWaterQltyYearList] = useState<FacilityWaterQltyProps[]>([]); + const { FacilityWaterQltyModal, searchFacilityWaterQltyListHist, Common } = useFoStore((state) => state); const { btnClass, COD_YEAR } = Common; const { upHeadListModalYear, @@ -72,6 +70,16 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea const prevExcelListRef = useRef<modalExcelType[] | null>(null); const prevChoinginExcelListRef = useRef<modalChoinginExcelType[] | null>(null); + useEffect(() => { + searchFacilityWaterQltyListHist(searchYear, facilityCd); + }, [searchYear, facilityCd, searchFacilityWaterQltyListHist]); + + useEffect(() => { + const filteredYearData = setFilterAfterData(facilityWaterQltyYearList); + setCopyYearList(filteredYearData as FacilityWaterQltyProps[]); + setChongInWaterQltyYearList(filteredYearData as FacilityWaterQltyProps[]); + }, [facilityWaterQltyYearList]); + // 필터링 된 후 최대, 최소, 평균 값 계산 const setFilterAfterData = (filteredData: FacilityWaterQltyProps[]) => { // 쉼표가 포함된 문자열을 숫자로 변환하는 함수 @@ -313,7 +321,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea addr: "", fctCpc: 0, noProcessInflAmnt: roundNumber(minNoProcessInflAmnt, 0), - infoRnDay: Math.round(minInfoRnDay * 10) / 10 ? '0.0' : roundNumber(minInfoRnDay, 1), + infoRnDay: Math.round(minInfoRnDay * 10) / 10 ? roundNumber(minInfoRnDay, 1) : '0.0', tpInflWqltBod: Math.round(minTpInflWqltBod * 10) / 10 && minTpInflWqltBod != 99999999 ? roundNumber(minTpInflWqltBod, 1) : '0.0', tpInflWqltTp: Math.round(minTpInflWqltTp * 1000) / 1000 && minTpInflWqltTp != 99999999 ? roundNumber(minTpInflWqltTp, 3) : '0.000' }, @@ -323,20 +331,6 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea return newFilteredData; } - // 날짜 필터링 관련 상태 - const [copyYearList, setCopyYearList] = useState<FacilityWaterQltyProps[]>([]); - const [chongInWaterQltyYearList, setChongInWaterQltyYearList] = useState<FacilityWaterQltyProps[]>([]); - - useEffect(() => { - searchFacilityWaterQltyListHist(searchYear, facilityCd); - }, [searchYear, facilityCd, searchFacilityWaterQltyListHist]); - - useEffect(() => { - const filteredYearData = setFilterAfterData(facilityWaterQltyYearList); - setCopyYearList(filteredYearData as FacilityWaterQltyProps[]); - setChongInWaterQltyYearList(filteredYearData as FacilityWaterQltyProps[]); - }, [facilityWaterQltyYearList]); - const yesterDay = new Date(); yesterDay.setDate(yesterDay.getDate() - 1); const yesterDayStr = yesterDay.toISOString().split('T')[0]; @@ -350,7 +344,8 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea const filterData = useCallback((returnType: ReturnType<FacilityWaterQltyProps>) => { const filteredData = setFilterAfterData(returnType.filteredList); - setCopyYearList(filteredData as FacilityWaterQltyProps[]); + setCopyYearList(filteredData as FacilityWaterQltyProps[]); // 처리시설 수질현황 + setChongInWaterQltyYearList(filteredData as FacilityWaterQltyProps[]); // 총인설비 수질현황 }, []); const excelDownload = () => { @@ -393,6 +388,8 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea const excelDownList: modalChoinginExcelType[] = []; if (chongInWaterQltyYearList.length > 0) { chongInWaterQltyYearList.forEach((item) => { + // if (copyYearList.length > 0) { + // copyYearList.forEach((item) => { excelDownList.push({ 날짜: item.msrDt, "유입BOD(mg/L)": CommaToNumber(item.tpInflWqltBod), @@ -432,7 +429,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea {/* 처리시설 수질현황 */} <TabsContent value="tab_num1"> <UITab tabList={tabList2} defaultValue="tab_term_year"> - <TabsContent value="tab_term_year"> + <TabsContent value="tab_term_year">{/* 연간 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_year" @@ -449,9 +446,9 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea <HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} /> </UiTable> </div> - <div className="card-header"> + <div className="card-header border-t mt-1"> <h3 className="text-2xl font-medium text-label">수질 TMS</h3> - {/*<h3 className="text-2xl font-medium text-label text-right">({msrmtDate?msrmtDate.substring(0,4)+'-'+msrmtDate.substring(4,6)+'-'+msrmtDate.substring(6,8):yesterDayStr})</h3> */} + <h3 className="text-2xl font-medium text-label text-right">({msrmtDate ? msrmtDate.substring(0, 4) + '-' + msrmtDate.substring(4, 6) + '-' + msrmtDate.substring(6, 8) : yesterDayStr})</h3> </div> <div className="overflow-y-auto h-[250px]"> <UiTable @@ -507,7 +504,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea </div> </TabsContent> - <TabsContent value="tab_term_chuncheon">{/* 청천 */} + <TabsContent value="tab_term_chuncheon">{/* 청천시 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={facilityWaterQltyYearList} fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_chuncheon" @@ -552,7 +549,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea {/* 총인설비 수질현황 */} <TabsContent value="tab_num2" > <UITab tabList={tabList3} defaultValue="tab_term_year_chongin"> - <TabsContent value="tab_term_year_chongin"> + <TabsContent value="tab_term_year_chongin">{/* 연간 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={chongInWaterQltyYearList} fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_year" @@ -571,7 +568,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea </div> </TabsContent> - <TabsContent value="tab_term_summer_chongin"> + <TabsContent value="tab_term_summer_chongin">{/* 하절기 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={chongInWaterQltyYearList} fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_summer" @@ -590,7 +587,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea </div> </TabsContent> - <TabsContent value="tab_term_winter_chongin"> + <TabsContent value="tab_term_winter_chongin">{/* 동절기 */} <FacilityTermModalHeader<FacilityWaterQltyProps> searchList={chongInWaterQltyYearList} fcltyCd={facilityCd} fcltyName={fcltyName} tabName="tab_term_winter" diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index 5d2e886f4..db60c5b2d 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -2,7 +2,7 @@ import DataForm, { roundNumber } from "@/app/components/common/DataForm"; import type { TableUpperProps } from "../dashboard"; import CalcRainEffect from "@/app/components/common/CalcRainEffect"; -import { COD_YEAR } from "../common"; +import { COD_YEAR } from "../common"; // 2021년 import CommaToNumber from "@/app/components/common/CommaToNumber"; export type { TableUpperProps }; @@ -431,7 +431,7 @@ const dataFormSetting = (item: FacilityWaterQltyProps) => { } export type FacilityWaterQltyStore = FacilityWaterQltyType & FacilityWaterQltyActions; -// 타입 정의를 분리하여 가독성 향상 + type SetFunc = (fn: (state: FacilityWaterQltyType) => FacilityWaterQltyType) => void; export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions => { return { @@ -447,7 +447,9 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions * @param operationValue : 운영상태코드 * @param fcltyNm : 시설명 */ - searchFacilityWaterQltyList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + searchFacilityWaterQltyList: async (pageNo: number, pageSize: number, searchYear: string, part?: string + , nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + set((state: FacilityWaterQltyType) => ({ ...state, FacilityWaterQltyMain: { @@ -567,7 +569,6 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions tn: res1.data.tnAvgVl, tp: res1.data.tpAvgVl, }); - rtnTmsList.push({ part: '최대', toc: res1.data.tocMaxVl, @@ -575,7 +576,6 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions tn: res1.data.tnMaxVl, tp: res1.data.tpMaxVl, }); - rtnTmsList.push({ part: '최소', toc: res1.data.tocMinVl, @@ -586,30 +586,9 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions rtnMsrmtDate = res1.data.msrmtDate; } else { - rtnTmsList.push({ - part: '평균', - toc: 0, - ss: 0, - tn: 0, - tp: 0, - }); - - rtnTmsList.push({ - part: '최대', - toc: 0, - ss: 0, - tn: 0, - tp: 0, - }); - - rtnTmsList.push({ - part: '최소', - toc: 0, - ss: 0, - tn: 0, - tp: 0, - }); - + rtnTmsList.push({ part: '평균', toc: 0, ss: 0, tn: 0, tp: 0, }); + rtnTmsList.push({ part: '최대', toc: 0, ss: 0, tn: 0, tp: 0, }); + rtnTmsList.push({ part: '최소', toc: 0, ss: 0, tn: 0, tp: 0, }); rtnMsrmtDate = ''; } @@ -633,10 +612,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions * [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]​ /강우시 일별유입BOD) */ - //let rainInflAmnt = 0; let sunnyInflAmnt = 0; let sunnyBod = 0; - //let rainDay = 0; let sunnyDay = 0; data.forEach(item => { @@ -700,12 +677,12 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10) / 10).toFixed(1); } - if (item.tpInflWqltBod) { + if (item.tpInflWqltBod) { // 총인 유입수질 BOD(mg/L) item.tpInflWqltBod = item.tpInflWqltBod ? Number(Math.round(Number(item.tpInflWqltBod) * 10) / 10).toFixed(1) : Number(item.tpInflWqltBod) === 0 ? '0.0' : ''; } else { item.tpInflWqltBod = ''; } - if (item.tpInflWqltTp) { + if (item.tpInflWqltTp) { // 총인 유입수질 TP(mg/L) item.tpInflWqltTp = item.tpInflWqltTp ? Number(Math.round(Number(item.tpInflWqltTp) * 1000) / 1000).toFixed(3) : Number(item.tpInflWqltTp) === 0 ? '0.000' : ''; } else { item.tpInflWqltTp = ''; From c57f05cc3ec8600f711cbbc3cd36b9853c5175de Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Tue, 13 Jan 2026 22:53:35 +0900 Subject: [PATCH 50/92] =?UTF-8?q?sn:=20showModal=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/searchModal/searchModal.tsx | 158 +++++++++--------- .../(without-layout)/stats/hasuStat/page.tsx | 14 +- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index 34cdb674b..0906ce0ca 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -125,91 +125,91 @@ const SearchModal: React.FC = () => { {/* 📋 결과 리스트 */} {/* 기본정보 탭 */} {activeTab === 'basic' && ( - <div className="h-[79vh] w-full overflow-x-hidden overflow-y-auto rounded-lg border mt-4"> - <div className="flex-1 px-2 pb-2"> - <LoadingOverlay isLoading={isLoading} /> - <UiTable - headName={(() => { - const label = BASIC_TYPES.find((type) => type.val === basicType)?.text - return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건</>); - })() - } - tableData={tableData} - headlist={dynamicHeadlist} - pageSize={10} - total={tableCount} - cellClick={handleBasicCellClick} - onPageChange={setCurPage} - resetPageNo={isResetPage} - resetSelection={isResetSelection} - curPage={curPage} - headButton={ - <div className='flex'> - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button> - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button> - </div> - } - /> - </div> + <div className="h-[79dvh] w-full rounded-lg border mt-4"> + {/* <div className="flex-1 px-2 pb-2"> */} + <LoadingOverlay isLoading={isLoading} /> + <UiTable + headName={(() => { + const label = BASIC_TYPES.find((type) => type.val === basicType)?.text + return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건</>); + })() + } + tableData={tableData} + headlist={dynamicHeadlist} + pageSize={10} + total={tableCount} + cellClick={handleBasicCellClick} + onPageChange={setCurPage} + resetPageNo={isResetPage} + resetSelection={isResetSelection} + curPage={curPage} + headButton={ + <div className='flex'> + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button> + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button> + </div> + } + /> + {/* </div> */} </div> )} {/* 유지관리 정보 탭 */} {activeTab === 'operation' && ( <> - <div className="h-[39vh] w-full overflow-hidden rounded-lg border mt-4"> - <div className="flex-1 px-2 pb-2"> - <LoadingOverlay isLoading={isLoading} /> - <UiTable - headName={ - (() => { - const label = WORK_TYPES.find((type) => type.val === workType)?.text - return (<>{label} 사업 현황 ({tableCount.toLocaleString('ko-KR')})건</>); - })() - } - tableData={tableData} - headlist={dynamicHeadlist} - pageSize={OPERATION_TABLE_SIZE} - total={tableCount} - cellClick={handleOperationCellClick} - onPageChange={setCurPage} - resetPageNo={isResetPage} - resetSelection={isResetSelection} - curPage={curPage} - headButton={ - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-sm font-medium green" size="sm" onClick={operationExcelDownload}>파일 다운로드</Button> - } - /> - </div> + <div className="h-[39dvh] w-full overflow-x-hidden overflow-y-auto rounded-lg border mt-4"> + {/* <div className="flex-1 px-2 pb-2"> */} + <LoadingOverlay isLoading={isLoading} /> + <UiTable + headName={ + (() => { + const label = WORK_TYPES.find((type) => type.val === workType)?.text + return (<>{label} 사업 현황 ({tableCount.toLocaleString('ko-KR')})건</>); + })() + } + tableData={tableData} + headlist={dynamicHeadlist} + pageSize={OPERATION_TABLE_SIZE} + total={tableCount} + cellClick={handleOperationCellClick} + onPageChange={setCurPage} + resetPageNo={isResetPage} + resetSelection={isResetSelection} + curPage={curPage} + headButton={ + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-sm font-medium green" size="sm" onClick={operationExcelDownload}>파일 다운로드</Button> + } + /> + {/* </div> */} </div> - <div className="h-[39vh] w-full overflow-hidden rounded-lg border"> + <div className="h-[39dvh] w-full overflow-x-hidden overflow-y-auto rounded-lg border"> {/* 테이블2 영역 */} - <div className="flex-1 px-2 pb-2"> - <LoadingOverlay isLoading={isDetailLoading} /> - <UiTable - headName={ - (() => { - const label = WORK_TYPES.find((type) => type.val === workType)?.text - return (<>{label} 결과표 ({detailTableCount.toLocaleString('ko-KR')})건</>); - })() - } - tableData={detailTableData} - headlist={dynamicHeadlist2} - pageSize={OPERATION_TABLE_SIZE} - total={detailTableCount} - cellClick={handleOperationResultCellClick} - onPageChange={setDetailCurPage} - resetPageNo={isResetDetailPage} - resetSelection={isResetDetailSelection} - curPage={detailCurPage} - headButton={ - <div className='flex'> - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button> - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={operationResultExcelDownload}>파일 다운로드</Button> - </div> - } - /> - </div> + {/* <div className="flex-1 px-2 pb-2"> */} + <LoadingOverlay isLoading={isDetailLoading} /> + <UiTable + headName={ + (() => { + const label = WORK_TYPES.find((type) => type.val === workType)?.text + return (<>{label} 결과표 ({detailTableCount.toLocaleString('ko-KR')})건</>); + })() + } + tableData={detailTableData} + headlist={dynamicHeadlist2} + pageSize={OPERATION_TABLE_SIZE} + total={detailTableCount} + cellClick={handleOperationResultCellClick} + onPageChange={setDetailCurPage} + resetPageNo={isResetDetailPage} + resetSelection={isResetDetailSelection} + curPage={detailCurPage} + headButton={ + <div className='flex'> + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button> + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={operationResultExcelDownload}>파일 다운로드</Button> + </div> + } + /> + {/* </div> */} </div> </> )} @@ -224,8 +224,8 @@ const SearchModal: React.FC = () => { bodyClass={` h-[100dvh] w-[90dvw] - max-w-[1200px] - max-h-[100dvh] + max-w-[1220px] + max-h-[970px] overflow-y-hidden z-[101] `} diff --git a/apps/wr/app/(without-layout)/stats/hasuStat/page.tsx b/apps/wr/app/(without-layout)/stats/hasuStat/page.tsx index 34ce031e1..d6e9ff601 100644 --- a/apps/wr/app/(without-layout)/stats/hasuStat/page.tsx +++ b/apps/wr/app/(without-layout)/stats/hasuStat/page.tsx @@ -20,20 +20,20 @@ export default function HasuStatPage() { const data = await res.json(); const ip: string = data?.ip || ""; if (didCancel) return; - //alert("Client IP:" + ip); + console.log("Client IP:" + ip); const is10 = /^10\./.test(ip); const is172 = /^172\./.test(ip); - setStatus(is10||is172 ? "redirect-internal" : "redirect-root"); + setStatus(is10 || is172 ? "redirect-internal" : "redirect-root"); // Use location.replace so user can't go back to this page - if (is10||is172) { + if (is10 || is172) { // redirect to internal IP // alert(process.env.NEXT_PUBLIC_HASUDOINFO_IN +'/cms/lay1/WS10000014/program.do'); - window.open(process.env.NEXT_PUBLIC_HASUDOINFO_IN +'/cms/lay1/WS10000014/program.do', '_blank'); + window.open(process.env.NEXT_PUBLIC_HASUDOINFO_IN + '/cms/lay1/WS10000014/program.do', '_blank'); } else { // alert(process.env.NEXT_PUBLIC_HASUDOINFO +'/cms/lay1/WS10000014/program.do'); - window.open(process.env.NEXT_PUBLIC_HASUDOINFO +'/cms/lay1/WS10000014/program.do', '_blank'); + window.open(process.env.NEXT_PUBLIC_HASUDOINFO + '/cms/lay1/WS10000014/program.do', '_blank'); } window.history.back(); } catch { @@ -53,13 +53,13 @@ export default function HasuStatPage() { }, []); return ( - <div style={{padding:20,fontFamily:'Noto Sans KR, sans-serif'}}> + <div style={{ padding: 20, fontFamily: 'Noto Sans KR, sans-serif' }}> {status === "checking" && <div>접속 IP 확인 중...</div>} {status === "redirect-internal" && <div>내부망으로 이동합니다...</div>} {status === "redirect-root" && <div>외부에서 접속하여 루트로 이동합니다...</div>} {status === "error-fallback" && ( <div> - 문제가 발생하여 루트로 이동합니다. 이동하지 않으면 <Link href="/">여기</Link>를 클릭하세요. + 문제가 발생하여 루트로 이동합니다. 이동하지 않으면 <Link href="/">여기</Link>를 클릭하세요. </div> )} </div> From 7588ee4e6adfae2eb6821ef65b8e4e16fc995685 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Wed, 14 Jan 2026 17:05:26 +0900 Subject: [PATCH 51/92] =?UTF-8?q?dm:=20=EC=9C=A0=EC=82=AC=EC=82=AC?= =?UTF-8?q?=EB=A1=80=20=ED=8C=9D=EC=97=85=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/sdmMng/sdmInfoInsert/modalSimilar/page.tsx | 6 +++--- apps/dm/components/ui/sdmInfoInsertForm/component.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/modalSimilar/page.tsx b/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/modalSimilar/page.tsx index 22418c7b7..35836d07c 100644 --- a/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/modalSimilar/page.tsx +++ b/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/modalSimilar/page.tsx @@ -87,9 +87,9 @@ export default function ModalSimilarPage({ sply = 0, usageCd = '', money = 0 }: }, [getSimilarCaseList, money, searchUseType, sply, usageCd]); return ( - <div className="align-top w-[1360px] overflow-x-auto"> + <div className="align-top w-[1360px] h-full"> <Title title="유사사례 조회" /> - <div className="overflow-x-auto h-[450px] w-full mt-8" tabIndex={0} aria-label="유사사례 테이블 영역"> + <div className="overflow-x-auto h-[480px] w-full mt-8" tabIndex={0} aria-label="유사사례 테이블 영역"> <div className="w-[150%]"> <div className="card-header justify-self-start"> <h3 className="text-2xl font-medium text-label">유사사례</h3> @@ -148,7 +148,7 @@ export default function ModalSimilarPage({ sply = 0, usageCd = '', money = 0 }: </div> </div> </div> - <div className="overflow-x-auto h-[270px] w-full mt-8"> + <div className="overflow-x-auto h-[270px] w-full mt-8 overflow-y-hidden"> <div className="w-[130%]"> <UiTable headName={"사업비 상세정보"} diff --git a/apps/dm/components/ui/sdmInfoInsertForm/component.tsx b/apps/dm/components/ui/sdmInfoInsertForm/component.tsx index 17e4bfdc8..62b214f04 100644 --- a/apps/dm/components/ui/sdmInfoInsertForm/component.tsx +++ b/apps/dm/components/ui/sdmInfoInsertForm/component.tsx @@ -950,7 +950,7 @@ export function SdmInfoRegForm({ body={ <ModalSimilarPage sply={sply} usageCd={usageCd} money={money} /> } - bodyClass="sm:max-w-[100vw] w-[1400px] h-[900px]" + bodyClass="sm:max-w-[100vw] w-[1400px] h-[100dvh] max-h-[900px] overflow-y-auto overflow-x-hidden" open={isSimilarCase} onOpenChange={(open) => !open && setIsSimilarCase(false)} noHeaderYn="Y" From 21b043cbae0da414c37746dcae5e941928691897 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Wed, 14 Jan 2026 17:51:48 +0900 Subject: [PATCH 52/92] =?UTF-8?q?dm:=20=EC=9C=A0=EC=82=AC=EC=82=AC?= =?UTF-8?q?=EB=A1=80=20=EC=82=AC=EC=97=85=EB=AA=85=20***=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/app/store/sdmMng/index.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/dm/app/store/sdmMng/index.tsx b/apps/dm/app/store/sdmMng/index.tsx index b5b258839..ef7fb4cea 100644 --- a/apps/dm/app/store/sdmMng/index.tsx +++ b/apps/dm/app/store/sdmMng/index.tsx @@ -167,7 +167,7 @@ export type DemandMatchings = { // 유사사례 export type SimilarCaseType = { - ruseBizNm : string | ''; + ruseBizNm : string | ''; // 사업명 bizBgngDate : string | ''; bizEndDate : string | ''; splyFcltKnd : string | ''; @@ -751,11 +751,23 @@ export const SdmReducer = (set: any): SdmActions => { // 유사사례 조회 getSimilarCaseList: async (part: string, value: number|string) => { const res = await fetchGetSimilarCaseList(part, value); - if(res && res.length !== 0) { + const similarCaseList = res.map((el: SimilarCaseType) => { + const maskedBizNm = el.ruseBizNm + ? el.ruseBizNm.replace(/^(\s*)^\S+/, "***") // 첫 단어(공백 전까지) 치환 + : el.ruseBizNm; + + return { + ...el, + ruseBizNm: maskedBizNm, + }; + }); + console.log(similarCaseList); + + if(similarCaseList && similarCaseList.length !== 0) { set((state: SdmType) => ({ Sdm: { ...state.Sdm, - similarCaseList: res, + similarCaseList: similarCaseList, } })) return; From 4e27466f0099f314c64d1661498aca863c5eefe6 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Thu, 15 Jan 2026 15:51:08 +0900 Subject: [PATCH 53/92] =?UTF-8?q?dm:=20GATEWAY=5FURL=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/.env.local | 2 +- apps/dm/.env.mindone | 1 + apps/dm/.env.production | 1 + apps/dm/app/store/wrStatus/index.tsx | 2 +- apps/dm/components/ui/api/index.ts | 25 +++++++++++++++++++------ apps/dm/middleware.ts | 23 ++++++++--------------- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/apps/dm/.env.local b/apps/dm/.env.local index e73fe4485..88b6f8067 100644 --- a/apps/dm/.env.local +++ b/apps/dm/.env.local @@ -16,7 +16,7 @@ NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload 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_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API +NEXT_PUBLIC_GATEWAY_URL=http://con.mind-one.co.kr:11083 # 개발 서버 API #NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성 #NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정 NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login diff --git a/apps/dm/.env.mindone b/apps/dm/.env.mindone index 1ca3ecfb6..da6f80177 100644 --- a/apps/dm/.env.mindone +++ b/apps/dm/.env.mindone @@ -14,6 +14,7 @@ NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/ap 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_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API +NEXT_PUBLIC_GATEWAY_URL=http://con.mind-one.co.kr:11083 # 개발 서버 API # NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성 #NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정 NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login diff --git a/apps/dm/.env.production b/apps/dm/.env.production index 2a08a80e0..5a401c89a 100644 --- a/apps/dm/.env.production +++ b/apps/dm/.env.production @@ -15,6 +15,7 @@ NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1 NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service +NEXT_PUBLIC_GATEWAY_URL = http://apigateway.iipbs-was.svc.cluster.local:8000 NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x} diff --git a/apps/dm/app/store/wrStatus/index.tsx b/apps/dm/app/store/wrStatus/index.tsx index bd43db731..b3c08e9e2 100644 --- a/apps/dm/app/store/wrStatus/index.tsx +++ b/apps/dm/app/store/wrStatus/index.tsx @@ -92,7 +92,7 @@ export const DmStatusReducer = (set: any): DmStatusActions => { const sewageCnt = item.sewageCnt; const rainwaterCnt = item.rainwaterCnt; const reclaimedCnt = item.reclaimedCnt; - console.log("regionText ", regionText); + if (!regionText) console.log("item.region ", item.region); if (regionText && regionText.text) { return { region: regionText ? regionText.text : item.region, diff --git a/apps/dm/components/ui/api/index.ts b/apps/dm/components/ui/api/index.ts index 7ba66c4ed..abb0c2c73 100644 --- a/apps/dm/components/ui/api/index.ts +++ b/apps/dm/components/ui/api/index.ts @@ -1,23 +1,33 @@ //8880 import { AUTH_USER_ID, CLAIM_NAME } from "@/src/shared/config"; -import { DEV_URL_FO, DEV_URL_WR } from "../config"; import { getCookie } from "@common/components/lib/cookie"; + const tokenId = getCookie(AUTH_USER_ID); const Authorization = getCookie(CLAIM_NAME); export const fetchType = { COMMON: "common", WR: "wr", - FO:'fo' + FO: "fo", + SN: "sn" }; +const API_VERSION = "/api/v1" +const servers = { + common: "", + local: "", + fo: "/operation-service" + API_VERSION, + wr: "/reuse-service" + API_VERSION, + sn: "/sewerage-service" + API_VERSION, +} + interface RequestParams { [key: string]: unknown; } export const getFetch = async (type: string, url: string) => { - const baseUrl = type === fetchType.FO ? DEV_URL_FO : DEV_URL_WR; + const baseUrl = servers[type]; const response = await fetch(baseUrl + url, { method: "GET", headers: { @@ -35,7 +45,8 @@ export const getFetch = async (type: string, url: string) => { }; export const postFetch = async (url: string, params: RequestParams) => { - const response = await fetch(DEV_URL_WR + url, { + const baseUrl = servers[fetchType.WR]; + const response = await fetch(baseUrl + url, { method: "POST", headers: { "Content-Type": "application/json", @@ -52,7 +63,8 @@ export const postFetch = async (url: string, params: RequestParams) => { }; export const putFetch = async (url: string, params: RequestParams) => { - const response = await fetch(DEV_URL_WR + url, { + const baseUrl = servers[fetchType.WR]; + const response = await fetch(baseUrl + url, { method: "PUT", headers: { "Content-Type": "application/json", @@ -69,7 +81,8 @@ export const putFetch = async (url: string, params: RequestParams) => { }; export const deleteFetch = async (url: string, params: RequestParams) => { - const response = await fetch(DEV_URL_WR + url, { + const baseUrl = servers[fetchType.WR]; + const response = await fetch(baseUrl + url, { method: "DELETE", headers: { "Content-Type": "application/json", diff --git a/apps/dm/middleware.ts b/apps/dm/middleware.ts index 0b2b21fbb..44d4cb390 100644 --- a/apps/dm/middleware.ts +++ b/apps/dm/middleware.ts @@ -1,13 +1,13 @@ import { NextRequest, NextResponse } from "next/server"; import { CLAIM_NAME, AUTH_USER_ID } from "./src/shared/config"; -import { SERVER_API_FO_URL, SERVER_API_WR_URL } from "./src/shared/config/env"; +// import { SERVER_API_FO_URL, SERVER_API_WR_URL } from "./src/shared/config/env"; // const CLAIM_NAME = "Authorization"; // const AUTH_USER_ID = "token-id"; const serverApiUrl = process.env.NEXT_PUBLIC_CS_SERVER_API_URL; const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || ""; const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || ""; -const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || ""; +const GATEWAY_URL = process.env.NEXT_PUBLIC_GATEWAY_URL || ""; const BUSINESS_JUSO_API_URL = process.env.NEXT_PUBLIC_FINDADRESS_URL || ""; const AdressKey = process.env.NEXT_PRIVATE_WR_ADDRESS_KEY || ""; @@ -112,7 +112,7 @@ export function middleware(req: NextRequest) { const url = req.nextUrl.clone(); url.searchParams.set("TYPENAME", typename.replace("hasudo:", "")); queryParams = url.searchParams.toString(); - newUrl = `${SEWERAGE_API_URL}/api/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`; + newUrl = `${GATEWAY_URL}/api/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`; } console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); @@ -121,24 +121,17 @@ export function middleware(req: NextRequest) { if (pathname.startsWith("/reuse-service")) { const queryParams = searchParams.toString(); - const newUrl = `${SERVER_API_WR_URL}${pathname.replace("/reuse-service", "")}${queryParams ? `?${queryParams}` : "" - }`; + const newUrl = `${GATEWAY_URL}${pathname}${queryParams ? `?${queryParams}` : ""}`; console.log(`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`); return NextResponse.rewrite(new URL(newUrl)); - } - - if (pathname.startsWith("/operation-service")) { + } else if (pathname.startsWith("/operation-service")) { const queryParams = searchParams.toString(); - const newUrl = `${SERVER_API_FO_URL}${pathname.replace("/operation-service", "")}${queryParams ? `?${queryParams}` : "" - }`; + const newUrl = `${GATEWAY_URL}${pathname}${queryParams ? `?${queryParams}` : ""}`; console.log(`[Middleware] Rewriting from '/operation-service' path to: ${newUrl}`); return NextResponse.rewrite(new URL(newUrl)); - } - - if (pathname.startsWith("/sewerage-service")) { + } else if (pathname.startsWith("/sewerage-service")) { const queryParams = searchParams.toString(); - const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service", "")}${queryParams ? `?${queryParams}` : "" - }`; + const newUrl = `${GATEWAY_URL}${pathname}${queryParams ? `?${queryParams}` : ""}`; console.log(`[Middleware] Rewriting from '/sewerage-service' path to: ${newUrl}`); return NextResponse.rewrite(new URL(newUrl)); } From 3716e8c7b2e4b48d4bdc500f304e7ac3a139611d Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 15 Jan 2026 21:14:49 +0900 Subject: [PATCH 54/92] =?UTF-8?q?dm:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/sdmMng/sdmInfoInsert/page.tsx | 18 +- .../pages/sdmMng/sdmLogout/page.tsx | 22 + apps/dm/app/store/sdmMng/index.tsx | 617 +++++++++--------- 3 files changed, 348 insertions(+), 309 deletions(-) create mode 100644 apps/dm/app/(base-layout)/pages/sdmMng/sdmLogout/page.tsx diff --git a/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/page.tsx b/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/page.tsx index b6a395974..df418b20f 100644 --- a/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/page.tsx +++ b/apps/dm/app/(base-layout)/pages/sdmMng/sdmInfoInsert/page.tsx @@ -1,5 +1,11 @@ "use client"; +/** + * 수요정보등록 화면 + * + * 🔗 사용 API + * - 수요정보등록: POST /reuseFc/request/demandInfo + */ import { useDmStore } from "@/app/store"; import { sdmInfoFormSchema, type DemandCompBizType, type SdmInfoFormData } from "@/app/store/sdmMng"; import { SdmInfoRegForm } from "@/components/ui/sdmInfoInsertForm/component"; @@ -60,7 +66,7 @@ function SdmInfoInsertContent() { ...prev, sdmNm: searchParams.get("dmdCoNm") || "", })); - if(searchParams.get("dmdInfoId")){ + if (searchParams.get("dmdInfoId")) { // const data = { // dmdCoNm: searchParams.get("dmdCoNm") || '', // ctpvCd: searchParams.get("ctpvCd") || '', @@ -69,8 +75,8 @@ function SdmInfoInsertContent() { // daddr: searchParams.get("daddr") || '', // telno: searchParams.get("telno") || '', // } - - // sessionStorage.setItem("user", JSON.stringify(data || {})); + + // sessionStorage.setItem("user", JSON.stringify(data || {})); } //sessionStorage.setItem("user", JSON.parse(user||'') || ""); setIsLogin(user || searchParams.get("dmdInfoId") ? true : false); @@ -121,7 +127,7 @@ function SdmInfoInsertContent() { const userData = JSON.parse(user); if (userData.dmdCoNm) { setFacilityName(userData.dmdCoNm); - form.setValue("sdmNm", userData.dmdCoNm); + form.setValue("sdmNm", userData.dmdCoNm); // 수요처명(회사명) } } catch (error) { console.error("Error parsing user data:", error); @@ -203,10 +209,10 @@ function SdmInfoInsertContent() { tph: Number(data.tph) || null, trbt: Number(data.trbt) || null, ph: data.ph || "", - blgcOxygDmndQnt: Number(data.bod) ||null, + blgcOxygDmndQnt: Number(data.bod) || null, clIonQnt: Number(data.clIonQnt) || null, smll: data.smll || "", - cdtnv: Number(data.cdtnv) ||null, + cdtnv: Number(data.cdtnv) || null, crmty: Number(data.crmty) || null, rmrk: data.rmrk || "", bzmnNo: "", diff --git a/apps/dm/app/(base-layout)/pages/sdmMng/sdmLogout/page.tsx b/apps/dm/app/(base-layout)/pages/sdmMng/sdmLogout/page.tsx new file mode 100644 index 000000000..2c682bdbf --- /dev/null +++ b/apps/dm/app/(base-layout)/pages/sdmMng/sdmLogout/page.tsx @@ -0,0 +1,22 @@ +"use client"; +/** + * 수요처 로그아웃 화면 + * + * 🔗 사용 API + * + */ +import { useDmStore } from "@/app/store"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; + +export default function SdmLogout() { + const router = useRouter(); + const { actionLogout } = useDmStore((state) => state); + + useEffect(() => { + actionLogout(); + router.push("/pages/sdmMng/sdmInfoInsert"); + }, [actionLogout, router]); + + return null; +} diff --git a/apps/dm/app/store/sdmMng/index.tsx b/apps/dm/app/store/sdmMng/index.tsx index ef7fb4cea..2e52ac13d 100644 --- a/apps/dm/app/store/sdmMng/index.tsx +++ b/apps/dm/app/store/sdmMng/index.tsx @@ -50,8 +50,8 @@ export const sdmInfoFormSchema = z.object({ // 모든 수질 관련 필드 // 총대장균군수는 null 값을 불검출로 표시하기때문에 해당 검사에서 제외함. const allFields: (keyof typeof data)[] = [ - "tn", "combResdch", "tph", - "trbt", "ph", "bod", "clIonQnt", + "tn", "combResdch", "tph", + "trbt", "ph", "bod", "clIonQnt", "smll", "cdtnv", "crmty", ]; @@ -104,38 +104,38 @@ export type SdmInfoFormData = z.infer<typeof sdmInfoFormSchema>; // 수요처 정보 export type DemandCompBizType = { - index : number | ''; - dmdInfoId : string | ''; - dmdInfoFk : string | ''; - bzmnNo : string | ''; - dmdCoNm : string | ''; - daddr : string | ''; - telno : string | ''; - rgtr : string | ''; - useUsgCd : string | ''; - ctpvCd : string | ''; - sggCd : string | ''; - dmdAplyPswd : string | ''; - wntUntprc : number | ''; - dmndTmng : Date | ''; - dmndQty : number | ''; - grssClfg : number | null //총대장균군수 - tn : number | null //총질소 - combResdch : number | null //결합잔류염소 - tph : number | null //총인 - trbt : number | null //탁도 - ph : string | ''; //수소이온농 - blgcOxygDmndQnt : number | null //생물학적산소요구량 - clIonQnt : number | null //염화물 - smll : string | ''; //냄새 - cdtnv : number | null; //전기전도도 - crmty : number | null //색도 - rmrk : string | ''; - reqDt : string | ''; - dmdInfoSn : number | ''; - status : string | ''; - splyCndtList:SupplyCandidate[]|[], - ruseUtztnFcltNm?:string|'' + index: number | ''; + dmdInfoId: string | ''; + dmdInfoFk: string | ''; + bzmnNo: string | ''; + dmdCoNm: string | ''; + daddr: string | ''; + telno: string | ''; + rgtr: string | ''; + useUsgCd: string | ''; + ctpvCd: string | ''; + sggCd: string | ''; + dmdAplyPswd: string | ''; + wntUntprc: number | ''; + dmndTmng: Date | ''; + dmndQty: number | ''; + grssClfg: number | null //총대장균군수 + tn: number | null //총질소 + combResdch: number | null //결합잔류염소 + tph: number | null //총인 + trbt: number | null //탁도 + ph: string | ''; //수소이온농 + blgcOxygDmndQnt: number | null //생물학적산소요구량 + clIonQnt: number | null //염화물 + smll: string | ''; //냄새 + cdtnv: number | null; //전기전도도 + crmty: number | null //색도 + rmrk: string | ''; + reqDt: string | ''; + dmdInfoSn: number | ''; + status: string | ''; + splyCndtList: SupplyCandidate[] | [], + ruseUtztnFcltNm?: string | '' } @@ -147,107 +147,107 @@ export type SupplyCandidate = { export type DemandMatchings = { - splyFcltFk : string | ''; - splyFcltFlg : string | ''; - pbnstRuseFcltBizFk : number | ''; - splyBgngDay : string | ''; - splyEndDay : string | ''; - splyCpct : number | ''; - splyFmYn : string | ''; - useUsgCd : string | ''; - dmdInfoSn : number | ''; - splyCndtList : string | ''; - mtchnCmptnYmd : string | ''; - rvwCmptnYmd : string | ''; - regDt : string | ''; - rgtr : string | ''; - mdfcnDt : string | ''; - mdfr : string | ''; + splyFcltFk: string | ''; + splyFcltFlg: string | ''; + pbnstRuseFcltBizFk: number | ''; + splyBgngDay: string | ''; + splyEndDay: string | ''; + splyCpct: number | ''; + splyFmYn: string | ''; + useUsgCd: string | ''; + dmdInfoSn: number | ''; + splyCndtList: string | ''; + mtchnCmptnYmd: string | ''; + rvwCmptnYmd: string | ''; + regDt: string | ''; + rgtr: string | ''; + mdfcnDt: string | ''; + mdfr: string | ''; } // 유사사례 export type SimilarCaseType = { - ruseBizNm : string | ''; // 사업명 - bizBgngDate : string | ''; - bizEndDate : string | ''; - splyFcltKnd : string | ''; - splyFcltNm : string | ''; - splyFcltCpct : string | ''; - dmdFcltNm : string | ''; - dmdFcltAddr : string | ''; - ruseFcltCpct : string | ''; - ruseFcltPplLen : string | ''; - ruseFcltUsg : string | ''; - ruseFcltSplyCpct : string | ''; - ruseFcltPrcsMsrc : string | ''; - grnteWqUsg : string | ''; - grnteWqGrssClfg : string | ''; - grnteWqCombResdch : string | ''; - grnteWqTrbt : string | ''; - grnteWqBod : string | ''; - grnteWqSmll : string | ''; - grnteWqCrmty : string | ''; - grnteWqTn : string | ''; - grnteWqTp : string | ''; - grnteWqPh : string | ''; - grnteWqClIonQnt : string | ''; - grnteWqCndctStat : string | ''; - grnteWqRmrk : string | ''; - reqBizReuseFcltCst : string | ''; - reqBizPplCst : string | ''; - reqBizArchCst : string | ''; - reqBizMchnCst : string | ''; - reqBizMtrngCst : string | ''; - reqBizGisCst : string | ''; - reqBizCctvCst : string | ''; - reqBizCmcnCst : string | ''; - reqBizWstCst : string | ''; - reqBizDesignCst : string | ''; - reqBizSpvsCst : string | ''; - reqBizSbsdCst : string | ''; - reqBizEtc : string | ''; - reqBizGrssCst : string | ''; - prcmPlanNlep : string | ''; - prcmPlanLcep : string | ''; - prcmPlanBrdnCst : string | ''; - prcmPlanEcqrRt : string | ''; - prcmPlanGrssCst : string | ''; - clclnNlep : string | ''; - clclnLcep : string | ''; - clclnBrdnCst : string | ''; - clclnEcqrRt : string | ''; - clclnGrssCst : string | ''; + ruseBizNm: string | ''; // 사업명 + bizBgngDate: string | ''; + bizEndDate: string | ''; + splyFcltKnd: string | ''; + splyFcltNm: string | ''; + splyFcltCpct: string | ''; + dmdFcltNm: string | ''; + dmdFcltAddr: string | ''; + ruseFcltCpct: string | ''; + ruseFcltPplLen: string | ''; + ruseFcltUsg: string | ''; + ruseFcltSplyCpct: string | ''; + ruseFcltPrcsMsrc: string | ''; + grnteWqUsg: string | ''; + grnteWqGrssClfg: string | ''; + grnteWqCombResdch: string | ''; + grnteWqTrbt: string | ''; + grnteWqBod: string | ''; + grnteWqSmll: string | ''; + grnteWqCrmty: string | ''; + grnteWqTn: string | ''; + grnteWqTp: string | ''; + grnteWqPh: string | ''; + grnteWqClIonQnt: string | ''; + grnteWqCndctStat: string | ''; + grnteWqRmrk: string | ''; + reqBizReuseFcltCst: string | ''; + reqBizPplCst: string | ''; + reqBizArchCst: string | ''; + reqBizMchnCst: string | ''; + reqBizMtrngCst: string | ''; + reqBizGisCst: string | ''; + reqBizCctvCst: string | ''; + reqBizCmcnCst: string | ''; + reqBizWstCst: string | ''; + reqBizDesignCst: string | ''; + reqBizSpvsCst: string | ''; + reqBizSbsdCst: string | ''; + reqBizEtc: string | ''; + reqBizGrssCst: string | ''; + prcmPlanNlep: string | ''; + prcmPlanLcep: string | ''; + prcmPlanBrdnCst: string | ''; + prcmPlanEcqrRt: string | ''; + prcmPlanGrssCst: string | ''; + clclnNlep: string | ''; + clclnLcep: string | ''; + clclnBrdnCst: string | ''; + clclnEcqrRt: string | ''; + clclnGrssCst: string | ''; } // 사업비 상세정보 export type MoneyDetailType = { - reqBizGrssCst : string | ''; - reqBizReuseFcltCst : string | ''; - reqBizPplCst : string | ''; - reqBizArchCst : string | ''; - reqBizMchnCst : string | ''; - reqBizMtrngCst : string | ''; - reqBizGisCst : string | ''; - reqBizCctvCst : string | ''; - reqBizCmcnCst : string | ''; - reqBizWstCst : string | ''; - reqBizDesignCst : string | ''; - reqBizSpvsCst : string | ''; - reqBizSbsdCst : string | ''; - reqBizEtc : string | ''; - + reqBizGrssCst: string | ''; + reqBizReuseFcltCst: string | ''; + reqBizPplCst: string | ''; + reqBizArchCst: string | ''; + reqBizMchnCst: string | ''; + reqBizMtrngCst: string | ''; + reqBizGisCst: string | ''; + reqBizCctvCst: string | ''; + reqBizCmcnCst: string | ''; + reqBizWstCst: string | ''; + reqBizDesignCst: string | ''; + reqBizSpvsCst: string | ''; + reqBizSbsdCst: string | ''; + reqBizEtc: string | ''; + /** 재원조달계획(백만원원) */ - prcmPlanGrssCst : string | ''; - prcmPlanNlep : string | ''; - prcmPlanLcep : string | ''; - prcmPlanBrdnCst : string | ''; - prcmPlanEcqrRt : string | ''; + prcmPlanGrssCst: string | ''; + prcmPlanNlep: string | ''; + prcmPlanLcep: string | ''; + prcmPlanBrdnCst: string | ''; + prcmPlanEcqrRt: string | ''; /** 사업비 정산(백만원) */ - clclnGrssCst : string | ''; - clclnNlep : string | ''; - clclnLcep : string | ''; - clclnBrdnCst : string | ''; - clclnEcqrRt : string | ''; + clclnGrssCst: string | ''; + clclnNlep: string | ''; + clclnLcep: string | ''; + clclnBrdnCst: string | ''; + clclnEcqrRt: string | ''; } // 규칙 타입 선언 export type DisableRulesType = Record<string, string[]>; @@ -255,144 +255,144 @@ export type DisableRulesType = Record<string, string[]>; * Store - 데이터 ====================================*/ // 수요처 정보 -const demandCompList : DemandCompType[] = [ +const demandCompList: DemandCompType[] = [ ] const disableRules: DisableRulesType = { - "청소": ["tn", 'tph',"clIonQnt" ,'cdtnv'], - "화장실용수": ["tn", 'tph',"clIonQnt" ,'cdtnv'], - "세척": ["combResdch", "crmty",'tph','tn',"clIonQnt",'cdtnv'], - "살수": ["combResdch", "crmty",'tph','tn',"clIonQnt",'cdtnv'], - "조경": ["combResdch", "crmty",'tph','cdtnv'], - "농업_간접용수": ["combResdch", "crmty",'tn','tph','clIonQnt'], - "농업_직접용수": ["combResdch", "crmty",'tn','tph','clIonQnt'], - "하천": ["combResdch", "trbt", "crmty" ,'clIonQnt','cdtnv'], - '공업':[] - }; + "청소": ["tn", 'tph', "clIonQnt", 'cdtnv'], + "화장실용수": ["tn", 'tph', "clIonQnt", 'cdtnv'], + "세척": ["combResdch", "crmty", 'tph', 'tn', "clIonQnt", 'cdtnv'], + "살수": ["combResdch", "crmty", 'tph', 'tn', "clIonQnt", 'cdtnv'], + "조경": ["combResdch", "crmty", 'tph', 'cdtnv'], + "농업_간접용수": ["combResdch", "crmty", 'tn', 'tph', 'clIonQnt'], + "농업_직접용수": ["combResdch", "crmty", 'tn', 'tph', 'clIonQnt'], + "하천": ["combResdch", "trbt", "crmty", 'clIonQnt', 'cdtnv'], + '공업': [] +}; - const defaultRules: Record<string, object> = { - "청소": { - grssClfg: null, - combResdch:0.2, - trbt: 2, - bod: 5, - crmty: 20, - ph: "5.8~8.5", - smll:'불쾌하지않을것', - tn:null, - tph: null, - clIonQnt: null, - cdtnv: null, +const defaultRules: Record<string, object> = { + "청소": { + grssClfg: null, + combResdch: 0.2, + trbt: 2, + bod: 5, + crmty: 20, + ph: "5.8~8.5", + smll: '불쾌하지않을것', + tn: null, + tph: null, + clIonQnt: null, + cdtnv: null, - }, - "화장실용수": { - grssClfg: null, - combResdch:0.2, - trbt: 2, - bod: 5, - crmty: 20, - smll:'불쾌하지않을것', - ph: "5.8~8.5", - tn:null, - tph: null, - clIonQnt: null, - cdtnv: null, - }, - "세척": { - grssClfg: null, - trbt: 2, - bod: 5, - ph: "5.8~8.5", - combResdch:null, - smll:'불쾌하지않을것', - crmty:null, - tn:null, - tph: null, - clIonQnt: null, - cdtnv: null, - }, - "살수": { - grssClfg: null, - trbt: 2, - bod: 5, - ph: "5.8~8.5", - smll:'불쾌하지않을것', - combResdch:null, - crmty:null, - tn:null, - tph: null, - clIonQnt: null, - cdtnv: null, - }, - "조경": { - grssClfg: null, - trbt: 2, - bod: 5, - ph: "5.8~8.5", - smll:'불쾌하지않을것', - clIonQnt:250, - combResdch:null, - crmty:null, - tn:null, - tph: null, - cdtnv: null, - }, - "농업_간접용수": { - grssClfg: null, - trbt: 5, - bod: 8, - ph: "5.8~8.5", - cdtnv:2000, - combResdch:null, - crmty:null, - tn:null, - tph: null, - clIonQnt: null, - }, - "농업_직접용수": { - grssClfg: null, - trbt: 2, - bod: 8, - smll:'불쾌하지않을것', - ph: "5.8~8.5", - cdtnv:700, - combResdch:null, - crmty:null, - tn:null, - tph: null, - clIonQnt: null, - }, - "하천": { - grssClfg: 1000, - bod: 5, - tn: 10, - tph: 0.5, - smll:'불쾌하지않을것', - ph: "5.8~8.5", - combResdch:null, - trbt:null, - crmty:null, - clIonQnt: null, - cdtnv:null - }, - '공업':{ - grssClfg: null, - bod: null, - tn: null, - tph: null, - ph: "~", - combResdch:null, - smll:'불쾌하지않을것', - trbt:null, - crmty:null, - clIonQnt: null, - cdtnv:null - } - }; + }, + "화장실용수": { + grssClfg: null, + combResdch: 0.2, + trbt: 2, + bod: 5, + crmty: 20, + smll: '불쾌하지않을것', + ph: "5.8~8.5", + tn: null, + tph: null, + clIonQnt: null, + cdtnv: null, + }, + "세척": { + grssClfg: null, + trbt: 2, + bod: 5, + ph: "5.8~8.5", + combResdch: null, + smll: '불쾌하지않을것', + crmty: null, + tn: null, + tph: null, + clIonQnt: null, + cdtnv: null, + }, + "살수": { + grssClfg: null, + trbt: 2, + bod: 5, + ph: "5.8~8.5", + smll: '불쾌하지않을것', + combResdch: null, + crmty: null, + tn: null, + tph: null, + clIonQnt: null, + cdtnv: null, + }, + "조경": { + grssClfg: null, + trbt: 2, + bod: 5, + ph: "5.8~8.5", + smll: '불쾌하지않을것', + clIonQnt: 250, + combResdch: null, + crmty: null, + tn: null, + tph: null, + cdtnv: null, + }, + "농업_간접용수": { + grssClfg: null, + trbt: 5, + bod: 8, + ph: "5.8~8.5", + cdtnv: 2000, + combResdch: null, + crmty: null, + tn: null, + tph: null, + clIonQnt: null, + }, + "농업_직접용수": { + grssClfg: null, + trbt: 2, + bod: 8, + smll: '불쾌하지않을것', + ph: "5.8~8.5", + cdtnv: 700, + combResdch: null, + crmty: null, + tn: null, + tph: null, + clIonQnt: null, + }, + "하천": { + grssClfg: 1000, + bod: 5, + tn: 10, + tph: 0.5, + smll: '불쾌하지않을것', + ph: "5.8~8.5", + combResdch: null, + trbt: null, + crmty: null, + clIonQnt: null, + cdtnv: null + }, + '공업': { + grssClfg: null, + bod: null, + tn: null, + tph: null, + ph: "~", + combResdch: null, + smll: '불쾌하지않을것', + trbt: null, + crmty: null, + clIonQnt: null, + cdtnv: null + } +}; // 사용용도 -const useTypesData : SelectDataType[] = [ +const useTypesData: SelectDataType[] = [ { text: '청소', val: "청소" }, { text: "화장실용수", val: "화장실용수" }, { text: "세척", val: "세척" }, @@ -440,8 +440,8 @@ export const similarCaseModalHeader: TableUpperProps[] = [ ] // 유사사례 데이터 -const similarCaseList : SimilarCaseType[] = [ - +const similarCaseList: SimilarCaseType[] = [ + ] // 사업비 상세정보 모달 헤더 @@ -477,12 +477,12 @@ export const moneyDetailModalHeader: TableUpperProps[] = [ ] // 사업비 상세정보 -const moneyDetailList : MoneyDetailType[] = [ +const moneyDetailList: MoneyDetailType[] = [ ] // 수요정보 신청현황 헤더 export const upHeadSdmInfoStatus: TableUpperProps[] = [ - { id: "index", title: "No."}, + { id: "index", title: "No." }, { id: "ctpvCd", title: "시도", row: 0, rowSpan: 2 }, { id: "sggCd", title: "시군구", row: 0, rowSpan: 2 }, { id: "dmdCoNm", title: "회사명", row: 0, rowSpan: 2 }, @@ -501,7 +501,7 @@ export const upHeadSdmInfoStatus: TableUpperProps[] = [ const postSdmData = async (data: DemandCompType) => { try { await postFetch("/reuseFc/request", data); - sessionStorage.setItem("user", JSON.stringify(data) ); + sessionStorage.setItem("user", JSON.stringify(data)); toast.success("수요처 등록에 성공하였습니다."); return true; } catch (error) { @@ -526,16 +526,16 @@ const postSdmLoginData = async (data: DemandCompType) => { try { const res = await postFetch("/reuseFc/request/login", data); const jsonData = await res.json(); - + const status = jsonData.status; const loginData = jsonData.data; let loginSuccess = false; - if(status === 200 && loginData != null) { + if (status === 200 && loginData != null) { alert("수요처 로그인에 성공하였습니다."); sessionStorage.setItem("user", JSON.stringify(loginData)); loginSuccess = true; - } else if(status === 401) { - alert("패스워드가 틀렸습니다."); + } else if (status === 401) { + alert("패스워드가 일치하지 않습니다."); loginSuccess = false; } else { alert("등록된 수요처가 없습니다."); @@ -553,35 +553,35 @@ const getDemandCompList = async (searchText: string, pageCnt: number) => { try { const url = '/reuseFc/request/' + (searchText ? searchText : '') + '/' + pageCnt; const res = await getFetch(fetchType.WR, url); - return { - data: res?.data || [], - count: res?.count || 0 + return { + data: res?.data || [], + count: res?.count || 0 } } catch (error) { - console.error(error+' 수요처 정보를 불러오지 못했습니다.'); + console.error(error + ' 수요처 정보를 불러오지 못했습니다.'); return { data: [], count: 0 }; } } -const getSdmInfoStatusList = async (dmdInfoId : string) => { +const getSdmInfoStatusList = async (dmdInfoId: string) => { try { const url = '/reuseFc/request/' + dmdInfoId; const res = await getFetch(fetchType.WR, url); return res?.data || []; } catch (error) { - console.error(error+' 수요정보 신청현황을 불러오지 못했습니다.'); + console.error(error + ' 수요정보 신청현황을 불러오지 못했습니다.'); return []; } } // 유사사례 조회 -const fetchGetSimilarCaseList = async (part: string, value: number|string) => { +const fetchGetSimilarCaseList = async (part: string, value: number | string) => { try { const url = '/reuseFc/pubFcRuseCase/dm/' + part + '/' + (value ? value : 0); const res = await getFetch(fetchType.WR, url); return res?.data || []; } catch (error) { - console.error(error+' 유사사례 조회에 실패하였습니다.'); + console.error(error + ' 유사사례 조회에 실패하였습니다.'); return []; } } @@ -590,23 +590,24 @@ const fetchGetSimilarCaseList = async (part: string, value: number|string) => { * Store - expaort ====================================*/ export type SdmActions = { - initializeSdmData: () => void; - insertSdmData: (data: DemandCompType) => Promise<void>; - insertSdmInfoData: (data: DemandCompBizType) => Promise<void>; - getDemandCompList: (searchText: string, pageCnt: number) => Promise<void>; - actionLogin: (data: DemandCompType) => Promise<void>; - getSdmInfoStatusList: (dmdInfoId: string) => Promise<void>; - getSimilarCaseList: (part: string, value: number|string) => Promise<void>; + initializeSdmData: () => void; + insertSdmData: (data: DemandCompType) => Promise<void>; + insertSdmInfoData: (data: DemandCompBizType) => Promise<void>; + getDemandCompList: (searchText: string, pageCnt: number) => Promise<void>; + actionLogin: (data: DemandCompType) => Promise<void>; + getSdmInfoStatusList: (dmdInfoId: string) => Promise<void>; + getSimilarCaseList: (part: string, value: number | string) => Promise<void>; + actionLogout: () => Promise<void>; } -export type SdmType ={ - Sdm :{ +export type SdmType = { + Sdm: { isInit: boolean; useTypesData: SelectDataType[]; demandCompList: DemandCompType[]; upHeadSimilarCaseList: TableUpperProps[]; similarCaseList: SimilarCaseType[]; - upHeadMoneyDetailList : TableUpperProps[]; + upHeadMoneyDetailList: TableUpperProps[]; moneyDetailList: MoneyDetailType[]; // 수요정보 신청현황 @@ -615,28 +616,28 @@ export type SdmType ={ defaultRules: Record<string, object> disableRules: DisableRulesType; // 로그인관련 - successNextPage : boolean; + successNextPage: boolean; successLogin: boolean; } } export const SdmState: SdmType = { - Sdm:{ - isInit:false, + Sdm: { + isInit: false, useTypesData: useTypesData, demandCompList: demandCompList, upHeadSimilarCaseList: similarCaseModalHeader, similarCaseList: similarCaseList, - upHeadMoneyDetailList : moneyDetailModalHeader, + upHeadMoneyDetailList: moneyDetailModalHeader, moneyDetailList: moneyDetailList, // 수요정보 신청현황 sdmInfoStatusList: [], - defaultRules:defaultRules, - disableRules:disableRules, + defaultRules: defaultRules, + disableRules: disableRules, upHeadSdmInfoStatus: upHeadSdmInfoStatus, // 로그인관련 - successNextPage : false, + successNextPage: false, successLogin: false, } } @@ -648,13 +649,13 @@ export const SdmReducer = (set: any): SdmActions => { insertSdmData: async (data: DemandCompType) => { const preRes = await getSdmInfoStatusList(data.dmdInfoId); - if(preRes?.dmdInfoId) { + if (preRes?.dmdInfoId) { toast.error('이미 등록된 수요처입니다.'); return; } const res = await postSdmData(data); - if(res) { + if (res) { set((state: SdmType) => ({ Sdm: { ...state.Sdm, @@ -671,7 +672,7 @@ export const SdmReducer = (set: any): SdmActions => { // 수요처 정보 getDemandCompList: async (searchText: string, pageCnt: number) => { const res = await getDemandCompList(searchText, pageCnt); - if(res.data.length === 0) { + if (res.data.length === 0) { set((state: SdmType) => ({ Sdm: { ...state.Sdm, @@ -693,7 +694,7 @@ export const SdmReducer = (set: any): SdmActions => { getSdmInfoStatusList: async (dmdInfoId: string) => { const res = await getSdmInfoStatusList(dmdInfoId); - if(res.length === 0) { + if (res.length === 0) { set((state: SdmType) => ({ Sdm: { ...state.Sdm, @@ -704,13 +705,13 @@ export const SdmReducer = (set: any): SdmActions => { } //const sdmInfoStatusList : DemandCompBizType[] = []; - const sdmInfoStatusList : DemandCompBizType[]= res.demandInfo.map((el: DemandCompBizType, index: number) => { + const sdmInfoStatusList: DemandCompBizType[] = res.demandInfo.map((el: DemandCompBizType, index: number) => { const matchingInfo = res.demandMatchings.find((matching: DemandMatchings) => matching.dmdInfoSn === el.dmdInfoSn); const status = matchingInfo?.splyFcltFlg?.trim() === 'Sub' ? '검토' : matchingInfo?.splyFcltFlg?.trim() === 'matched' ? '매칭완료' : '신청'; const ruseUtztnFcltNm = matchingInfo?.ruseUtztnFcltNm ? matchingInfo.ruseUtztnFcltNm : ''; - return( { + return ({ ...el, index: ++index, bzmnNo: res.bzmnNo, @@ -723,8 +724,8 @@ export const SdmReducer = (set: any): SdmActions => { sggCd: res.sggCd, useUsgCd: el.useUsgCd, dmndTmng: el.dmndTmng, - dmdInfoSn : el.dmdInfoSn, - status : status, + dmdInfoSn: el.dmdInfoSn, + status: status, splyCndtList: el.splyCndtList, ruseUtztnFcltNm: ruseUtztnFcltNm || '' }) @@ -749,7 +750,7 @@ export const SdmReducer = (set: any): SdmActions => { }, // 유사사례 조회 - getSimilarCaseList: async (part: string, value: number|string) => { + getSimilarCaseList: async (part: string, value: number | string) => { const res = await fetchGetSimilarCaseList(part, value); const similarCaseList = res.map((el: SimilarCaseType) => { const maskedBizNm = el.ruseBizNm @@ -762,24 +763,34 @@ export const SdmReducer = (set: any): SdmActions => { }; }); console.log(similarCaseList); - - if(similarCaseList && similarCaseList.length !== 0) { + + if (similarCaseList && similarCaseList.length !== 0) { set((state: SdmType) => ({ - Sdm: { + Sdm: { ...state.Sdm, similarCaseList: similarCaseList, } })) return; - }else{ + } else { set((state: SdmType) => ({ - Sdm: { + Sdm: { ...state.Sdm, similarCaseList: [], } })) return; } + }, + + actionLogout: async () => { + sessionStorage.removeItem("user"); + set((state: SdmType) => ({ + Sdm: { + ...state.Sdm, + successLogin: false, + } + })) } } } From 943d858c5aa36b5d51c71277ead4ce3f128279da Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 16 Jan 2026 17:37:49 +0900 Subject: [PATCH 55/92] =?UTF-8?q?cm:=20=EC=9A=B0=ED=8E=B8=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EB=96=BC=EC=96=B4=EB=82=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business_components/src/lib/utils.ts | 2 +- .../business_components/src/ui/index.ts | 3 +- .../src/ui/sdmInsertForm/form.tsx | 185 +-------------- .../ui/search_address/SearchAddressModal.tsx | 221 ++++++++++++++++++ .../src/ui/search_address/findAddress.ts | 118 ++++++++++ .../src/ui/search_address/index.ts | 3 + .../src/ui/search_address/zipService.ts | 66 ++++++ 7 files changed, 419 insertions(+), 179 deletions(-) create mode 100644 packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx create mode 100644 packages/common/business_components/src/ui/search_address/findAddress.ts create mode 100644 packages/common/business_components/src/ui/search_address/index.ts create mode 100644 packages/common/business_components/src/ui/search_address/zipService.ts diff --git a/packages/common/business_components/src/lib/utils.ts b/packages/common/business_components/src/lib/utils.ts index a5ef19350..1a87df14d 100644 --- a/packages/common/business_components/src/lib/utils.ts +++ b/packages/common/business_components/src/lib/utils.ts @@ -2,5 +2,5 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)); //clsx 결과 (단순 합치기):twMerge 결과 (Tailwind 충돌 제거) } diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index db1132b58..ae419bd83 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -15,6 +15,7 @@ export * from "./search_form_right"; export * from "./search_input"; export * from "./search_input_select"; // export * from "./search_input_address"; +export * from "./search_address"; export * from "./select"; export * from "./tab"; export * from "./table"; @@ -24,4 +25,4 @@ export * from "./sdmInsertForm"; export * from "./popover_ui"; export * from "./date_month_picker"; export * from "./date_picker_range" -export * from "./map/GisOverlay"; \ No newline at end of file +export * from "./map/GisOverlay"; diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx index 6f0cbff2b..b2499ab43 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -1,4 +1,4 @@ -import { Button, Input, Label } from "@common/components"; +import { Button, Input } from "@common/components"; import { AsYouType } from "libphonenumber-js"; import React, { useCallback, useEffect, useState } from "react"; import type { ControllerRenderProps, UseFormReturn } from "react-hook-form"; @@ -6,10 +6,7 @@ import { FormField } from "../form"; import { FormUi } from "../form_ui"; import { SelectBox } from "../select"; import { SdmSearchForm } from "./sdmNameBox"; -import { UiModal, UiTable } from '../../ui'; -import type { Zip, ZipSearchParams } from "../search_input_address/zipService"; -import { findAddress } from "../search_input_address/findAddress"; -import { cn } from "@common/components"; +import { SearchAddressModal } from "../search_address/SearchAddressModal"; // 수요처 정보 export type DemandCompType = { @@ -91,7 +88,6 @@ export function SdmRegForm({ readOnly, openNetwork, }: SdmRegFormProps) { - const PAGE_SIZE = 10; const [sidoValue, setSidoValue] = useState<string>(""); const [sigunValue, setSigunValue] = useState<string>(""); const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([ @@ -104,30 +100,6 @@ export function SdmRegForm({ const [zipId, setZipId] = useState<number | undefined>(undefined); const [address, setAddress] = useState<string | undefined>(""); const [detailedAddress, setDetailedAddress] = useState<string>(""); - const [curPage, setCurPage] = useState<number>(1); - // 우편번호 검색 관련 상태 - const [zipSearchResults, setZipSearchResults] = useState<Zip[]>([]); - const [zipTotalElements, setZipTotalElements] = useState<number>(-1); - const [searchQuery, setSearchQuery] = useState<ZipSearchParams>({ - roadNm: "", - bldgNoMno: null, - bldgNoSno: null, - page: curPage, - size: PAGE_SIZE - }); - const [isResetPage, setIsResetPage] = useState<boolean>(false); - const [isResetSelection, setIsResetSelection] = useState<boolean>(false); - const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined); - const [selectedZip, setSelectedZip] = useState<Zip>(); - const [isSelectedZip, setIsSelectedZip] = useState<boolean>(false); - - const handleCellClick = (index: any, headId: any) => { - console.log('index', index); - console.log('headId', headId); - setSelectedZip(zipSearchResults[index]); - setIsSelectedZip(true); - console.log('selectedZip', zipSearchResults[index]); - }; const formatPhoneNumber = (value: string) => { const input = value; @@ -293,17 +265,6 @@ export function SdmRegForm({ [orgBznmNo, setIsDuplicate], ); - // 우편번호 선택 함수 - const handleSelectAddress = () => { - setZipId(selectedZip?.zipId); - setAddress(selectedZip?.zipAddr || ""); - setDetailedAddress(""); - setIsZipModalOpen(false); - setSelectedZip(undefined); - setIsSelectedZip(false); - setSelectedRowIndex(undefined); - }; - useEffect(() => { if (updateList?.dmdInfoId) { form.reset(updateList); @@ -325,16 +286,6 @@ export function SdmRegForm({ console.log("form.formState.errors ", form.formState.errors); }, [form.formState.errors]); - useEffect(() => { - console.log("curPage ", curPage); - searchQuery.page = curPage - 1; - const fetchAddress = async () => { - const result = await findAddress(searchQuery); - setZipSearchResults(result?.content); - }; - fetchAddress(); - }, [curPage]); - // 폼 제출 전에 주소 합치기 useEffect(() => { // address와 detailedAddress를 합쳐서 daddr에 설정 @@ -344,105 +295,6 @@ export function SdmRegForm({ } }, [address, detailedAddress, form]); - const renderBody = () => ( - <> - <form - onSubmit={async (e) => { - e.preventDefault(); - e.stopPropagation(); - const result = await findAddress(searchQuery); - setZipSearchResults(result?.content); - setZipTotalElements(result?.totalElements); - }} - className="mb-4 space-y-2" - > - {/* 검색 조건 부분 */} - <div className="card card-border !m-0 flex flex-col gap-4 p-4"> - <div className="grid grid-cols-3 gap-4"> - <div className="flex flex-col"> - <Label className="mb-1 font-bold text-base">도로명</Label> - <Input - value={searchQuery.roadNm || ""} - onChange={(e) => - setSearchQuery({ - ...searchQuery, - roadNm: e.target.value, - }) - } - placeholder="예: 테헤란로" - className="!text-[1.3rem]" - /> - </div> - - <div className="flex flex-col"> - <Label className="mb-1 text-base">건물본번</Label> - <Input - type="number" - value={searchQuery.bldgNoMno ?? ""} - onChange={(e) => { - const value = e.target.value - ? parseInt(e.target.value) - : null; - setSearchQuery({ - ...searchQuery, - bldgNoMno: value, - }); - }} - placeholder="예: 123" - className="!text-[1.3rem]" - /> - </div> - - <div className="flex flex-col"> - <Label className="mb-1 text-base">건물부번</Label> - <Input - type="number" - value={searchQuery.bldgNoSno ?? ""} - onChange={(e) => { - const value = e.target.value - ? parseInt(e.target.value) - : null; - setSearchQuery({ - ...searchQuery, - bldgNoSno: value, - }); - }} - placeholder="예: 45" - className="!text-[1.3rem]" - /> - </div> - </div> - - <div className="flex justify-end"> - <Button className="rounded-md" type="submit">검색</Button> - </div> - </div> - </form> - - {/* 검색 결과 부분 */} - {zipTotalElements > 0 && ( - <UiTable - headName='' - tableData={zipSearchResults} - headlist={[{ id: 'zoneNo', title: '우편번호' }, { id: 'zipAddr', title: '주소' }]} - pageSize={PAGE_SIZE} - total={zipTotalElements} - cellClick={handleCellClick} - onPageChange={setCurPage} - resetPageNo={isResetPage} - resetSelection={isResetSelection} - index={selectedRowIndex} - /> - )} - {zipTotalElements === 0 && ( - <div className={cn("flex h-96 flex-col items-center justify-center gap-4")}> - <i className="diveicon di-info-circle text-3xl" /> - 조회된 데이터가 없습니다. - </div> - )} - </> - ); - const formFields: Array<{ name: keyof FormSchema; @@ -725,35 +577,14 @@ export function SdmRegForm({ /> ); })} - <UiModal - headerTitle="주소 검색" - headerTitleClass="text-2xl font-bold text-gray-900" + <SearchAddressModal open={isZipModalOpen} onOpenChange={setIsZipModalOpen} - bodyClass={` - ${zipTotalElements > -1 ? 'h-[80vh]' : 'h-[30vh]'} - w-[30vw] - min-w-[500px] - max-w-[90vw] - max-h-[85vh] - overflow-y-auto - !fixed - !top-[50%] - !left-[50%] - !-translate-x-1/2 - !-translate-y-1/2 - z-[101] - flex - flex-col - `} - body={renderBody()} - footerContent={ - <div className="w-full flex justify-center items-center gap-4"> - <Button className="rounded-md" size="lg" onClick={handleSelectAddress} disabled={!isSelectedZip}>선택</Button> - <Button className="rounded-md" size="lg" onClick={() => setIsZipModalOpen(false)}>취소</Button> - </div> - } - useDirectRender={true} + onSelect={(zip) => { + setZipId(zip.zipId); + setAddress(zip.zipAddr || ""); + setDetailedAddress(""); + }} /> </> ); diff --git a/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx b/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx new file mode 100644 index 000000000..55529f89a --- /dev/null +++ b/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx @@ -0,0 +1,221 @@ +import { Button, Input, Label, cn } from "@common/components"; +import React, { useState, useEffect } from "react"; +import { UiModal } from "../dialog_ui"; +import { UiTable } from "../table"; +import type { Zip, ZipSearchParams } from "./zipService"; +import { findAddress } from "./findAddress"; + +interface SearchAddressModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + onSelect: (zip: Zip) => void; +} + +export function SearchAddressModal({ open, onOpenChange, onSelect }: SearchAddressModalProps) { + const PAGE_SIZE = 10; + const [curPage, setCurPage] = useState<number>(1); + const [zipSearchResults, setZipSearchResults] = useState<Zip[]>([]); + const [zipTotalElements, setZipTotalElements] = useState<number>(-1); + const [searchQuery, setSearchQuery] = useState<ZipSearchParams>({ + roadNm: "", + bldgNoMno: null, + bldgNoSno: null, + page: 1, + size: PAGE_SIZE + }); + const [isResetPage, setIsResetPage] = useState<boolean>(false); + const [isResetSelection, setIsResetSelection] = useState<boolean>(false); + const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined); + const [selectedZip, setSelectedZip] = useState<Zip>(); + const [isSelectedZip, setIsSelectedZip] = useState<boolean>(false); + + // Initialize/Reset state when modal opens + useEffect(() => { + if (open) { + setCurPage(1); + setZipSearchResults([]); + setZipTotalElements(-1); + setSearchQuery({ + roadNm: "", + bldgNoMno: null, + bldgNoSno: null, + page: 0, + size: PAGE_SIZE + }); + setSelectedZip(undefined); + setIsSelectedZip(false); + setSelectedRowIndex(undefined); + setIsResetPage(true); + setTimeout(() => setIsResetPage(false), 100); + } + }, [open]); + + // Pagination Effect + useEffect(() => { + if (!open || zipTotalElements === -1) return; + + // Correctly update query for pagination without mutation + const nextPage = curPage - 1; + if (searchQuery.page !== nextPage) { + const newQuery = { ...searchQuery, page: nextPage }; + setSearchQuery(newQuery); + + const fetchAddress = async () => { + const result = await findAddress(newQuery); + setZipSearchResults(result?.content || []); + }; + fetchAddress(); + } + }, [curPage, open, zipTotalElements]); + + const handleCellClick = (index: any) => { + setSelectedZip(zipSearchResults[index]); + setIsSelectedZip(true); + setSelectedRowIndex(index); + }; + + const handleSearch = async (e: React.FormEvent) => { + e.preventDefault(); + e.stopPropagation(); + + const query = { ...searchQuery, page: 0 }; + setSearchQuery(query); + setCurPage(1); + setIsResetPage(true); + + const result = await findAddress(query); + setZipSearchResults(result?.content || []); + setZipTotalElements(result?.totalElements || 0); + + setTimeout(() => setIsResetPage(false), 100); + }; + + const handleConfirm = () => { + if (selectedZip) { + onSelect(selectedZip); + onOpenChange(false); + } + }; + + return ( + <UiModal + headerTitle="주소 검색" + headerTitleClass="text-2xl font-bold text-gray-900" + open={open} + onOpenChange={onOpenChange} + bodyClass={` + ${zipTotalElements > -1 ? 'h-[80vh]' : 'h-[30vh]'} + w-[30vw] + min-w-[500px] + max-w-[90vw] + min-h-[235px] + overflow-y-auto + !fixed + !top-[50%] + !left-[50%] + !-translate-x-1/2 + !-translate-y-1/2 + z-[101] + flex + flex-col + `} + body={ + <> + <form + onSubmit={handleSearch} + className="mb-4 space-y-2" + > + <div className="card card-border !m-0 flex flex-col gap-4 p-4"> + <div className="grid grid-cols-3 gap-4"> + <div className="flex flex-col"> + <Label className="mb-1 font-bold text-base">도로명</Label> + <Input + value={searchQuery.roadNm || ""} + onChange={(e) => + setSearchQuery({ + ...searchQuery, + roadNm: e.target.value, + }) + } + placeholder="예: 테헤란로" + className="!text-[1.3rem]" + /> + </div> + + <div className="flex flex-col"> + <Label className="mb-1 text-base">건물본번</Label> + <Input + type="number" + value={searchQuery.bldgNoMno ?? ""} + onChange={(e) => { + const value = e.target.value + ? parseInt(e.target.value) + : null; + setSearchQuery({ + ...searchQuery, + bldgNoMno: value, + }); + }} + placeholder="예: 123" + className="!text-[1.3rem]" + /> + </div> + + <div className="flex flex-col"> + <Label className="mb-1 text-base">건물부번</Label> + <Input + type="number" + value={searchQuery.bldgNoSno ?? ""} + onChange={(e) => { + const value = e.target.value + ? parseInt(e.target.value) + : null; + setSearchQuery({ + ...searchQuery, + bldgNoSno: value, + }); + }} + placeholder="예: 45" + className="!text-[1.3rem]" + /> + </div> + </div> + + <div className="flex justify-end"> + <Button className="rounded-md" type="submit">검색</Button> + </div> + </div> + </form> + + {zipTotalElements > 0 && ( + <UiTable + headName='' + tableData={zipSearchResults} + headlist={[{ id: 'zoneNo', title: '우편번호' }, { id: 'zipAddr', title: '주소' }]} + pageSize={PAGE_SIZE} + total={zipTotalElements} + cellClick={handleCellClick} + onPageChange={setCurPage} + resetPageNo={isResetPage} + resetSelection={isResetSelection} + index={selectedRowIndex} + /> + )} + {zipTotalElements === 0 && ( + <div className={cn("flex h-96 flex-col items-center justify-center gap-4")}> + <i className="diveicon di-info-circle text-3xl" /> + 조회된 데이터가 없습니다. + </div> + )} + </> + } + footerContent={ + <div className="w-full flex justify-center items-center gap-4"> + <Button className="rounded-md" size="lg" onClick={handleConfirm} disabled={!isSelectedZip}>선택</Button> + <Button className="rounded-md" size="lg" onClick={() => onOpenChange(false)}>취소</Button> + </div> + } + useDirectRender={true} + /> + ); +} diff --git a/packages/common/business_components/src/ui/search_address/findAddress.ts b/packages/common/business_components/src/ui/search_address/findAddress.ts new file mode 100644 index 000000000..5e5ba4360 --- /dev/null +++ b/packages/common/business_components/src/ui/search_address/findAddress.ts @@ -0,0 +1,118 @@ + +// const Key = 'U01TX0FVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA' +// const addresssKey = 'devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM='; //인증키 만료일은 2025-11-23 + +import type { Zip, ZipSearchParams } from "./zipService"; + +/** + * 주소 API 응답 타입 + * https://business.juso.go.kr/addrlink/main.do 해당 사이트 참조 + */ +export type AddressApiResponse = { + results: { + common: { + errorMessage: string; + countPerPage: string; + totalCount: string; + errorCode: string; + currentPage: string; + }; + juso: addressType[]; + }; +} + +export type addressType = { + detBdNmList: string; + engAddr: string; + rn: string; + emdNm: string; + zipNo: string; + roadAddrPart2: string; + emdNo: string; + sggNm: string; + jibunAddr: string; + siNm: string; + roadAddrPart1: string; + bdNm: string; + admCd: string; + udrtYn: string; + lnbrMnnm: string; + roadAddr: string; + lnbrSlno: string; + buldMnnm: string; + bdKdcd: string; + liNm: string; + rnMgtSn: string; + mtYn: string; + bdMgtSn: string; + buldSlno: string; +} + +/** + * 주소에 따른 검색 + * @param search : 검색어 + * @returns addressType[] 주소 배열 + */ +export const findAddress = async (searchQuery: ZipSearchParams): Promise<any> => { + if (!searchQuery) return []; + + // 쿼리 파라미터 생성 + const params = new URLSearchParams(); + if (searchQuery.roadNm) params.append('roadNm', searchQuery.roadNm); + if (searchQuery.bldgNoMno != null) params.append('bldgNoMno', searchQuery.bldgNoMno.toString()); + if (searchQuery.bldgNoSno != null) params.append('bldgNoSno', searchQuery.bldgNoSno.toString()); + if (searchQuery.page != null) params.append('page', searchQuery.page.toString()); + if (searchQuery.size != null) params.append('size', searchQuery.size.toString()); + + const url = `/cms-service/api/v1/zips?${params.toString()}`; + try { + const response = await fetch(url); + if (!response.ok) throw new Error('Network response was not ok'); + + const data = await response.json(); + if (data) return data + else return []; + } catch (error) { + console.error('Error fetching address data:', error); + return []; + } + +} + + + +export const searchFilter = (search: string) => { + + + if (search.length > 0) { + //특수문자 제거 + const expText = /[%=><]/; + if (expText.test(search) == true) { + alert("특수문자를 입력 할수 없습니다."); + search = search.split(expText).join(""); + return false; + } + + //특정문자열(sql예약어의 앞뒤공백포함) 제거 + const sqlArray = [ + //sql 예약어 + "OR", "SELECT", "INSERT", "DELETE", "UPDATE", "CREATE", "DROP", "EXEC", + "UNION", "FETCH", "DECLARE", "TRUNCATE" + ] + + let regex; + for (let i = 0; i < sqlArray.length; i++) { + regex = new RegExp(sqlArray[i] as string, "gi"); + + if (regex.test(search)) { + alert("\"" + sqlArray[i] + "\"와(과) 같은 특정문자로 검색할 수 없습니다."); + search = search.replace(regex, ""); + return false; + } + } + } + return true; + + + +} diff --git a/packages/common/business_components/src/ui/search_address/index.ts b/packages/common/business_components/src/ui/search_address/index.ts new file mode 100644 index 000000000..b790bb492 --- /dev/null +++ b/packages/common/business_components/src/ui/search_address/index.ts @@ -0,0 +1,3 @@ +export * from "./SearchAddressModal"; +export * from "./findAddress"; +export * from "./zipService"; diff --git a/packages/common/business_components/src/ui/search_address/zipService.ts b/packages/common/business_components/src/ui/search_address/zipService.ts new file mode 100644 index 000000000..03e4a8ccc --- /dev/null +++ b/packages/common/business_components/src/ui/search_address/zipService.ts @@ -0,0 +1,66 @@ +interface SortConfig { + empty: boolean; + sorted: boolean; + unsorted: boolean; +} + +interface PageableConfig { + sort: SortConfig; + offset: number; + pageNumber: number; + pageSize: number; + paged: boolean; + unpaged: boolean; +} + +export interface PageableList<T> { + content: T[]; + pageable: PageableConfig; + sort: SortConfig; + totalPages: number; + totalElements: number; + number: number; + numberOfElements: number; + size: number; + first: boolean; + last: boolean; + empty: boolean; +} + +export interface PageableParams { + page?: number; + size?: number; + sort?: string; +} + + +export interface ZipSearchParams extends PageableParams { + zoneNo?: string; // 구역번호 + ctpvNm?: string; // 시도명 + sggNm?: string; // 시군구명 + emdNm?: string; // 읍면동명 + roadNm?: string; // 도로명 + stdgNm?: string; // 법정동명 + dongNm?: string; // 행정동명 + bldgNoMno?: number | null; // 빌딩본번 + bldgNoSno?: number | null; // 빌딩딩부번 + lotnoMno?: number | null; // 지번본번 + lotnoSno?: number | null; // 지번부번 +} + +export interface Zip { + zipId: number; + zoneNo: string; + ctpvNm: string; + sggNm: string; + emdNm: string; + roadNm: string; + bldgNoMno: number; + bldgNoSno: number; + lotnoMno: number; + lotnoSno: number; + lotno: string; + zipAddr: string; +} + +export type ZipList = PageableList<Zip>; From 44580f515668811272493e3ac030a485a286e7e7 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sun, 18 Jan 2026 21:21:19 +0900 Subject: [PATCH 56/92] =?UTF-8?q?fo:=EC=88=98=EC=A7=88=ED=98=84=ED=99=A9?= =?UTF-8?q?=20=EC=B4=9D=EC=9D=B8=EC=84=A4=EB=B9=84tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityWaterQlty/modal/page.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) 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 7de556932..470a44e4c 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx @@ -77,7 +77,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea useEffect(() => { const filteredYearData = setFilterAfterData(facilityWaterQltyYearList); setCopyYearList(filteredYearData as FacilityWaterQltyProps[]); - setChongInWaterQltyYearList(filteredYearData as FacilityWaterQltyProps[]); + setChongInWaterQltyYearList(facilityWaterQltyYearList); }, [facilityWaterQltyYearList]); // 필터링 된 후 최대, 최소, 평균 값 계산 @@ -344,8 +344,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea const filterData = useCallback((returnType: ReturnType<FacilityWaterQltyProps>) => { const filteredData = setFilterAfterData(returnType.filteredList); - setCopyYearList(filteredData as FacilityWaterQltyProps[]); // 처리시설 수질현황 - setChongInWaterQltyYearList(filteredData as FacilityWaterQltyProps[]); // 총인설비 수질현황 + setCopyYearList(filteredData as FacilityWaterQltyProps[]); // 처리시설/총인설비 수질현황 }, []); const excelDownload = () => { @@ -386,10 +385,10 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea prevExcelListRef.current = excelDownList; } else { // 총인설비 수질현황 const excelDownList: modalChoinginExcelType[] = []; - if (chongInWaterQltyYearList.length > 0) { - chongInWaterQltyYearList.forEach((item) => { - // if (copyYearList.length > 0) { - // copyYearList.forEach((item) => { + // if (chongInWaterQltyYearList.length > 0) { + // chongInWaterQltyYearList.forEach((item) => { + if (copyYearList.length > 0) { + copyYearList.forEach((item) => { excelDownList.push({ 날짜: item.msrDt, "유입BOD(mg/L)": CommaToNumber(item.tpInflWqltBod), @@ -610,4 +609,4 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea </UITab> </> ); -} \ No newline at end of file +} From e464d298ad4b89a47fe53636968de360150a1059 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 19 Jan 2026 13:24:29 +0900 Subject: [PATCH 57/92] =?UTF-8?q?wr:=2036=20=EA=B3=84=ED=86=B5=EB=8F=84=20?= =?UTF-8?q?=ED=8F=89=EB=A9=B4=EB=8F=84=20=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 3 +- .../matMng/coMat/ruseCaseMng/page.tsx | 156 ++++++++++-------- .../ruseFcltMng/fcltReg/pbnstReg/page.tsx | 4 + .../app/store/matDmd/ruseCaseMng/headList.tsx | 4 +- .../fcltReg/pbnstReg/mngReg/mngRegForm.tsx | 7 +- .../src/ui/file-upload/lib/file_upload.tsx | 1 + .../ui/search_address/SearchAddressModal.tsx | 2 +- .../src/ui/table/index.tsx | 7 +- 8 files changed, 108 insertions(+), 76 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 47142e0a1..98120523a 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -215,7 +215,8 @@ export default function Rdi() { <LoadingOverlay isLoading={isLoading} /> <div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden"> <div className="w-[120%] min-[1200px]:w-[100%]"> - <UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> + <UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList} + pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> </div> <UnderComment divHeight={"0"} commentArray={commentArray} /> </div> diff --git a/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx index afea9d894..6001d8827 100644 --- a/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx +++ b/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx @@ -24,6 +24,7 @@ import { Button, Label } from "@common/components/ui"; import { useEffect, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; import { useTranslation } from "react-i18next"; +import * as XLSX from "xlsx"; export default function RuseCaseMng() { const { code, ruseCaseMng, selectRuseCaseMng, ruseCaseMngInit } = useWrStore( @@ -76,7 +77,9 @@ export default function RuseCaseMng() { }; useEffect(() => { - if (excelList !== undefined && excelList.length === 0) { + if (!excelList) return; + + if (excelList.length === 0) { toast.error(t("excelDownErrMsg")); return; } @@ -86,74 +89,93 @@ export default function RuseCaseMng() { } // 받은 파일 바인너리 처리 const blobRet = await response.arrayBuffer(); - if (excelList) { - const excelData1 = excelList.map((item) => { - return [ - item.ruseBizNm, - item.bizBgngDate, - item.bizEndDate, - item.splyFcltKnd, - item.splyFcltNm, - item.splyFcltCpct, - item.dmdFcltNm, - item.dmdFcltAddr, - item.ruseFcltCpct, - item.ruseFcltPplLen, - item.ruseFcltUsg, - item.ruseFcltSplyCpct, - item.ruseFcltPrcsMsrc, - item.grnteWqUsg, - item.grnteWqGrssClfg, - item.grnteWqCombResdch, - item.grnteWqTrbt, - item.grnteWqBod, - item.grnteWqSmll, - item.grnteWqCrmty, - item.grnteWqTn, - item.grnteWqTp, - item.grnteWqPh, - item.grnteWqClIonQnt, - item.grnteWqCndctStat, - item.grnteWqRmrk, - item.reqBizGrssCst, - item.reqBizReuseFcltCst, - item.reqBizPplCst, - item.reqBizArchCst, - item.reqBizMchnCst, - item.reqBizMtrngCst, - item.reqBizGisCst, - item.reqBizCctvCst, - item.reqBizCmcnCst, - item.reqBizWstCst, - item.reqBizDesignCst, - item.reqBizSpvsCst, - item.reqBizSbsdCst, - item.reqBizEtc, - item.prcmPlanGrssCst, - item.prcmPlanNlep, - item.prcmPlanLcep, - item.prcmPlanBrdnCst, - item.prcmPlanEcqrRt, - item.clclnGrssCst, - item.clclnNlep, - item.clclnLcep, - item.clclnBrdnCst, - item.clclnEcqrRt, - ]; - }); - const sheetParameter: SheetParameter[] = [ - { - data: excelData1, - headerNum: 2, - headerRange: "A1:AX1", - sheetName: "물재이용사례", - startCol: "A", - }, + const replaceHeaderText = (text: string) => + text + .replaceAll("사업시작일", "사업시작년") + .replaceAll("사업종료일", "사업종료년"); + + const wb = XLSX.read(blobRet, { type: "array" }); + wb.SheetNames.forEach((sheetName) => { + const sheet = wb.Sheets[sheetName]; + if (!sheet) return; + + Object.keys(sheet).forEach((addr) => { + if (addr.startsWith("!")) return; + const cell = sheet[addr] as XLSX.CellObject | undefined; + if (!cell || typeof cell.v !== "string") return; + const next = replaceHeaderText(cell.v); + if (next !== cell.v) cell.v = next; + }); + }); + const updatedBlob = XLSX.write(wb, { bookType: "xlsx", type: "array" }); + + const excelData1 = excelList.map((item) => { + return [ + item.ruseBizNm, + item.bizBgngDate, + item.bizEndDate, + item.splyFcltKnd, + item.splyFcltNm, + item.splyFcltCpct, + item.dmdFcltNm, + item.dmdFcltAddr, + item.ruseFcltCpct, + item.ruseFcltPplLen, + item.ruseFcltUsg, + item.ruseFcltSplyCpct, + item.ruseFcltPrcsMsrc, + item.grnteWqUsg, + item.grnteWqGrssClfg, + item.grnteWqCombResdch, + item.grnteWqTrbt, + item.grnteWqBod, + item.grnteWqSmll, + item.grnteWqCrmty, + item.grnteWqTn, + item.grnteWqTp, + item.grnteWqPh, + item.grnteWqClIonQnt, + item.grnteWqCndctStat, + item.grnteWqRmrk, + item.reqBizGrssCst, + item.reqBizReuseFcltCst, + item.reqBizPplCst, + item.reqBizArchCst, + item.reqBizMchnCst, + item.reqBizMtrngCst, + item.reqBizGisCst, + item.reqBizCctvCst, + item.reqBizCmcnCst, + item.reqBizWstCst, + item.reqBizDesignCst, + item.reqBizSpvsCst, + item.reqBizSbsdCst, + item.reqBizEtc, + item.prcmPlanGrssCst, + item.prcmPlanNlep, + item.prcmPlanLcep, + item.prcmPlanBrdnCst, + item.prcmPlanEcqrRt, + item.clclnGrssCst, + item.clclnNlep, + item.clclnLcep, + item.clclnBrdnCst, + item.clclnEcqrRt, ]; - // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 - await filePickedBlobArray(blobRet, "물재이용사례현황", sheetParameter); - } + }); + + const sheetParameter: SheetParameter[] = [ + { + data: excelData1, + headerNum: 2, + headerRange: "A1:AX1", + sheetName: "물재이용사례", + startCol: "A", + }, + ]; + // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 + await filePickedBlobArray(updatedBlob, "물재이용사례현황", sheetParameter); }); }, [excelList]); diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx index d5d0e9b33..e460aa31e 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -45,6 +45,10 @@ import { useTranslation } from "react-i18next"; * indexMng: 시설정보 * indexBiz: 차수별 정보 * 로 하수재이용 시설에 등록된 시설 및 차수별 정보를 관리한다. + * 🔗 사용 API + * 하수재이용시설을 등록 /reuseFc/pubFc + * 첨부파일 삭제 /attach-service/api/v1/atfl/attachments/atflCd// + * 첨부파일 다운로드 /attach-service/api/v1/atflcd/download/ * */ export default function PublicReuseFaciltyInsert() { diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx index 8ed65ee7d..c201f5d28 100644 --- a/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx +++ b/apps/wr/app/store/matDmd/ruseCaseMng/headList.tsx @@ -11,14 +11,14 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [ }, { id: "bizBgngDate", - title: "사업시작일", + title: "사업시작년", visible: true, row: 0, rowSpan: 2, }, { id: "bizEndDate", - title: "사업종료일", + title: "사업종료년", visible: true, row: 0, rowSpan: 2, diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx index 6fd110297..d4e7fe940 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx @@ -35,10 +35,11 @@ export type FilesType = { file: File; }; +const diagramFileTypes = ".pdf,.jpg,.jpeg,.png,.bmp"; /** * 재이용시설 등록 - 하수재이용 시설등록 - * 재이용시설 등록 - 하수재이용 시설현황 + * 재이용시설 등록 - 하수재이용 시설현황 * - layout.tsx에 의해 공통 레이아웃이 적용됨 * - with-layout 적용 * - 하수처리시설에 하수재이용 시설 시설 정보를 등록한다. @@ -459,7 +460,7 @@ export function PbnstMngForm({ setFiles={(files: File[] | null) => { if (files) fileHandler(files, "relation"); }} - fileTypes=".pdf" + fileTypes={diagramFileTypes} onFileClick={(index) => { fileDownLoad( relationfiles?.find( @@ -497,7 +498,7 @@ export function PbnstMngForm({ setFiles={(files: File[] | null) => { if (files) fileHandler(files, "plan"); }} - fileTypes=".pdf" + fileTypes={diagramFileTypes} onFileClick={(index) => { fileDownLoad( planFiles?.find( diff --git a/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx b/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx index 42662ab1d..030ddda95 100644 --- a/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx +++ b/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx @@ -93,6 +93,7 @@ export const FileUploader = forwardRef< ".jpeg": "image/jpeg", ".png": "image/png", ".gif": "image/gif", + ".bmp": "image/bmp", ".doc": "application/msword", ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".xls": "application/vnd.ms-excel", diff --git a/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx b/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx index 55529f89a..699d3cc50 100644 --- a/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx +++ b/packages/common/business_components/src/ui/search_address/SearchAddressModal.tsx @@ -24,7 +24,7 @@ export function SearchAddressModal({ open, onOpenChange, onSelect }: SearchAddre size: PAGE_SIZE }); const [isResetPage, setIsResetPage] = useState<boolean>(false); - const [isResetSelection, setIsResetSelection] = useState<boolean>(false); + const [isResetSelection] = useState<boolean>(false); const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined); const [selectedZip, setSelectedZip] = useState<Zip>(); const [isSelectedZip, setIsSelectedZip] = useState<boolean>(false); diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index a0b421db8..1a0fc57c0 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -119,7 +119,6 @@ export function UiTable({ }; const leafCols = getLeafCols(headlist); - return ( <> {headName ? ( @@ -263,7 +262,11 @@ export function UiTable({ <TableCell colSpan={ headlist.filter((item) => item.visible != false).length - - headlist.filter((item) => item.visible != false && item.colSpan).length + headlist.filter( + (item) => + item.visible != false && + (item.colSpan || ["A", "B", "C"].includes(item.id)), + ).length } className="h-24 text-center text-gray-500" > From 122e10f85175af6239a6ca05c395325c01e9c8f6 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 19 Jan 2026 16:38:26 +0900 Subject: [PATCH 58/92] =?UTF-8?q?wr:=20=EC=9E=AC=EC=9B=90=ED=98=91?= =?UTF-8?q?=EC=9D=98=20=EB=AC=B8=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matMng/coMat/ruseCaseMng/page.tsx | 4 +++ .../ruseFcltMng/fcltReg/pbnstReg/page.tsx | 34 +++++++++---------- .../ruseFcltMng/fcltSttn/htdflSttn/page.tsx | 11 +++--- .../ruseFcltMng/fcltSttn/pbnstSttn/page.tsx | 19 ++++++----- .../ruseFcltMng/fcltSttn/rainSttn/page.tsx | 3 ++ .../ruseFcltMng/fcltSttn/rswtSttn/page.tsx | 3 ++ apps/wr/app/store/common/auth/index.tsx | 3 +- .../ruseFcltMng/fcltReg/pbnstReg/index.tsx | 4 +-- 8 files changed, 47 insertions(+), 34 deletions(-) diff --git a/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx index 6001d8827..a64c57364 100644 --- a/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx +++ b/apps/wr/app/(with-layout)/matMng/coMat/ruseCaseMng/page.tsx @@ -321,8 +321,12 @@ export default function RuseCaseMng() { }} resetPageNo={resetPage} /> + <span className="text-2xl font-bold text-gray-500"> + ☞ 본 사례의 사업비는 재원협의 단계의 정보이므로, 최종확정된 비용이 아닙니다. + </span> </div> </ListDiv> + </div> </div> </ContentsDiv> diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx index e460aa31e..f6d83e29c 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -1,3 +1,19 @@ +/** + * 재이용시설 등록 - 하수재이용 시설등록 + * + * - layout.tsx에 의해 공통 레이아웃이 적용됨 + * - with-layout 적용 + * - 하수처리시설에 하수재이용 시설을 등록 한다. + * - form으로 시설정보 및 차수별 정보의 컴포넌트 데이터를 관리한다 + * indexMng: 시설정보 + * indexBiz: 차수별 정보 + * 로 하수재이용 시설에 등록된 시설 및 차수별 정보를 관리한다. + * 🔗 사용 API + * 하수재이용시설을 등록 /reuseFc/pubFc + * 첨부파일 삭제 /attach-service/api/v1/atfl/attachments/atflCd// + * 첨부파일 다운로드 /attach-service/api/v1/atflcd/download/ + * */ + "use client"; import { ContentsDiv, @@ -35,22 +51,6 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { createDefaultPbnstItem } from "./utilsZod"; import { useTranslation } from "react-i18next"; -/** - * 재이용시설 등록 - 하수재이용 시설등록 - * - * - layout.tsx에 의해 공통 레이아웃이 적용됨 - * - with-layout 적용 - * - 하수처리시설에 하수재이용 시설을 등록 한다. - * - form으로 시설정보 및 차수별 정보의 컴포넌트 데이터를 관리한다 - * indexMng: 시설정보 - * indexBiz: 차수별 정보 - * 로 하수재이용 시설에 등록된 시설 및 차수별 정보를 관리한다. - * 🔗 사용 API - * 하수재이용시설을 등록 /reuseFc/pubFc - * 첨부파일 삭제 /attach-service/api/v1/atfl/attachments/atflCd// - * 첨부파일 다운로드 /attach-service/api/v1/atflcd/download/ - * */ - export default function PublicReuseFaciltyInsert() { const { auth, @@ -108,7 +108,7 @@ export default function PublicReuseFaciltyInsert() { useEffect(() => { if (useInitRef.current == true && laeSeCd !== undefined) { - pubHasuInit("1", laeSeCd); + pubHasuInit("1", laeSeCd); //page: string, sggOrCity: string } }, [useInitRef.current, laeSeCd]); diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/htdflSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/htdflSttn/page.tsx index beaa71569..ea4b49924 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/htdflSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/htdflSttn/page.tsx @@ -1,5 +1,7 @@ +/** + * 온배수시설 현황 + */ "use client"; - import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import type { @@ -34,11 +36,9 @@ import toast, { Toaster } from "react-hot-toast"; import { useTranslation } from "react-i18next"; export default function HtdflSttn() { - const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore( - (state) => state - ); + const { auth, code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore((state) => state); + const { laeSeCd } = auth; // 지자체구분코드 const { htdflSttnRes, htdflSttnResCount } = htdflSttn; - const isDownloadTriggered = useRef(false); const { t } = useTranslation('base'); const [pageNation, setPageNation] = useState(1); @@ -57,6 +57,7 @@ export default function HtdflSttn() { // }>({ isOpen: false, chBuilding: [] }); const [fcltNm, setFcltNm] = useState<string>(""); + console.log("laeSeCd : ", laeSeCd); useEffect(() => { htdflSttnSearch(false, pageNation, htdflSttnSize, String(getConValue()), fcltNm, code.cityCd, code.sggCd); isResetPage(false) diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx index ca0b04f31..2a2340253 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx @@ -1,3 +1,12 @@ +/** + * 하수재이용 시설 현황 + * 재이용시설 현황 - 하수재이용시설 현황 + * - layout.tsx에 의해 공통 레이아웃이 적용됨 + * - with-layout 적용 + * 하수처리시설. 하수재이용시설 , 하수재이용시설 실적에 대한 정보를 확인한다. + * 모달 : 테이블의 헤더를 원하는대로 조절해서 볼수 있다. + * 클릭시 해당 재이용ㅇ + * */ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; @@ -24,15 +33,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; import { useTranslation } from "react-i18next"; -/** - * 하수재이용 시설 현황 - * 재이용시설 현황 - 하수재이용시설 현황 - * - layout.tsx에 의해 공통 레이아웃이 적용됨 - * - with-layout 적용 - * 하수처리시설. 하수재이용시설 , 하수재이용시설 실적에 대한 정보를 확인한다. - * 모달 : 테이블의 헤더를 원하는대로 조절해서 볼수 있다. - * 클릭시 해당 재이용ㅇ - * */ + export default function PbnstSttn() { const { code, diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx index f5ec6e8c8..46f1fa0c4 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx @@ -1,3 +1,6 @@ +/** + * 빗물재이용시설 현황 + */ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index 7cb81d209..268ef8a35 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -1,3 +1,6 @@ +/** + * 중수도시설 현황 + */ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; diff --git a/apps/wr/app/store/common/auth/index.tsx b/apps/wr/app/store/common/auth/index.tsx index 7b647d5e7..209b1fb8a 100644 --- a/apps/wr/app/store/common/auth/index.tsx +++ b/apps/wr/app/store/common/auth/index.tsx @@ -10,7 +10,7 @@ export type authState = { regAuthrtYn: string; mdfcnAuthrtYn: string; delAuthrtYn: string; - laeSeCd: string; + laeSeCd: string; // 지자체구분코드 myUUID?: string; }; }; @@ -72,6 +72,7 @@ export const authActionsExport: (set: any, get: any) => authActions = ( return; } const infoMe = await getUserInfo(); + console.log(infoMe); const isLaeSeCd = infoMe.laeSeCd.slice(0, 2) === "G3" ? infoMe.laeSeCd.slice(2) : "0"; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index b1e0daf82..d595a0624 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -118,7 +118,7 @@ const hasuListFetch = async ( if (searchTxt) { url = url + `/${searchTxt}`; } - const rainRes = await postFectch(url, data, fetchType.COMMON); + const rainRes = await postFectch(url, data, fetchType.COMMON); // fo const hasuList = rainRes.data.map((item: any) => { return { @@ -176,7 +176,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { // 하수처리시설을 조회한다(운영실태) pubHasuInit: async (page: string, sggOrCity: string) => { try { - const pbnstHasuRes = await hasuListFetch(page, sggOrCity); + const pbnstHasuRes = await hasuListFetch(page, sggOrCity); // /prcsFclt/ruseInfo return set((state: pubFacState) => ({ ...state, pbnst: { From 3eb8861d0619231f307f0d29af3f6b88445d70ce Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 19 Jan 2026 18:11:56 +0900 Subject: [PATCH 59/92] =?UTF-8?q?dm:=20=EB=AC=BC=EC=9E=AC=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=98=84=ED=99=A9=20=EC=8B=9C=EB=8F=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dm/app/store/wrStatus/index.tsx | 14 ++++----- apps/dm/app/store/wrStatus/type.ts | 10 ++++--- .../facilityPrecipitation/page.tsx | 30 +++++++++++-------- .../app/store/facilityPrecipitation/index.tsx | 4 ++- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/apps/dm/app/store/wrStatus/index.tsx b/apps/dm/app/store/wrStatus/index.tsx index b3c08e9e2..d3cc61cc4 100644 --- a/apps/dm/app/store/wrStatus/index.tsx +++ b/apps/dm/app/store/wrStatus/index.tsx @@ -85,22 +85,20 @@ export const DmStatusReducer = (set: any): DmStatusActions => { const boardData: DmStatusBoardType[] = data.data.map( (item: DmStatusDataType) => { - const regionText = cityCd.find((city) => item.region === city.val); + const regionText = item.sidoNm; //cityCd.find((city) => item.region === city.val); const sewage = item.sewage; const rainwater = item.rainwater; const reclaimed = item.reclaimed; const sewageCnt = item.sewageCnt; const rainwaterCnt = item.rainwaterCnt; const reclaimedCnt = item.reclaimedCnt; - if (!regionText) console.log("item.region ", item.region); - if (regionText && regionText.text) { + return { - region: regionText ? regionText.text : item.region, - sewage: sewageCnt + "(" + sewage + ")", - rainwater: rainwaterCnt + "(" + rainwater + ")", - reclaimed: reclaimedCnt + "(" + reclaimed + ")", + region: regionText ? regionText : item.region, + sewage: sewageCnt + "(" + sewage.toLocaleString() + ")", + rainwater: rainwaterCnt + "(" + rainwater.toLocaleString() + ")", + reclaimed: reclaimedCnt + "(" + reclaimed.toLocaleString() + ")", }; - } } ).filter((item): item is DmStatusBoardType => item !== undefined); diff --git a/apps/dm/app/store/wrStatus/type.ts b/apps/dm/app/store/wrStatus/type.ts index 513a5fb01..2cf1b36f0 100644 --- a/apps/dm/app/store/wrStatus/type.ts +++ b/apps/dm/app/store/wrStatus/type.ts @@ -1,14 +1,16 @@ export type DmStatusDataType = { - region: string; + sidoNm: string; // 시도명 + region: string; // 시도코드 sewage: string; rainwater: string; reclaimed: string; - sewageCnt:string - rainwaterCnt:string - reclaimedCnt:string + sewageCnt:string; + rainwaterCnt:string; + reclaimedCnt:string; }; export type DmStatusBoardType = { + sidoNm: string; // 시도명 region: string; sewage: string; rainwater: string; diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 0e46505e0..18a769871 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -209,10 +209,13 @@ export default function FacilityPrecipitation() { <ContentsDiv> <SearchBaseForm leftChildren={<> - <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} + onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} /> <SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} /> - <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> - <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectSearchYear} + onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} /> + <SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectOperationData} + onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} /> </>} rightChildren={undefined} selectSidoData={selectSidoData} @@ -226,16 +229,19 @@ export default function FacilityPrecipitation() { excelClick={excelDownload} initClick={resetVal} ref={ref} isAdmin={false}/> - <ListDiv> - <LoadingOverlay isLoading={isLoading} /> - <div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden"> - <div className="w-[120%] min-[1200px]:w-[100%]"> - <UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 강수현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} /> + <ListDiv> + <LoadingOverlay isLoading={isLoading} /> + <div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden"> + <div className="w-[120%] min-[1200px]:w-[100%]"> + <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 divHeight={"3"} commentArray={["강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의"]} /> </div> - <UnderComment divHeight={"3"} commentArray={["강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의"]} /> - </div> - </ListDiv> - </ContentsDiv> + </ListDiv> + </ContentsDiv> {selectedRow !== null && ( <UiModal body={<PrecipitationModal searchYear={searchYear} fcltyName={fcltyNm} facilityCd={fcltyCd} detailList={gridListPrecipitationDetail}></PrecipitationModal>} diff --git a/apps/fo/app/store/facilityPrecipitation/index.tsx b/apps/fo/app/store/facilityPrecipitation/index.tsx index 6272ef55b..b18471eca 100644 --- a/apps/fo/app/store/facilityPrecipitation/index.tsx +++ b/apps/fo/app/store/facilityPrecipitation/index.tsx @@ -153,7 +153,9 @@ export const fetchFacilityRainDetailList = async (searchYear: string|undefined, } }; -const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { +const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number, searchYear: string, part?: string + , nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + const tailStr = '/'+pageNo + '/' + pageSize + '/' + searchYear + (part?'/' + part:'' ) + (nameCd?'/' + nameCd:'' ) + (fcltCpct?'/' + fcltCpct:'' ) + (operationValue?'/' + operationValue:'' ) + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') ; const url = '/fclt/rain' + tailStr; const res = await getFetch('fo', url); From 599e8a95c783d4956d1343062394618ec55f6c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A7=80=EC=B2=A0?= <jcchoi@onasys.co.kr> Date: Tue, 20 Jan 2026 15:00:08 +0900 Subject: [PATCH 60/92] =?UTF-8?q?logout=20=EC=88=98=EC=A0=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cm/app/api/auth/logout/route.ts | 25 ++++- .../cm/src/entities/auth/lib/token-manager.ts | 4 +- .../common/components/src/ui/header/index.tsx | 96 ++++++++++++++++++- 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/apps/cm/app/api/auth/logout/route.ts b/apps/cm/app/api/auth/logout/route.ts index ba8e23374..8740d9d5b 100644 --- a/apps/cm/app/api/auth/logout/route.ts +++ b/apps/cm/app/api/auth/logout/route.ts @@ -9,10 +9,31 @@ import { export async function POST() { const cookieStore = await cookies(); + + // 백엔드에 로그아웃 알림 (토큰 블랙리스트 처리) + const refreshToken = cookieStore.get(REFRESH_TOKEN)?.value; + + if (refreshToken) { + try { + // ⭐ Spring Boot 백엔드에 로그아웃 요청 + await fetch(`${process.env.NEXT_PUBLIC_SERVER_API_URL}/api/auth/logout`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Cookie": `${REFRESH_TOKEN}=${refreshToken}`, + }, + // credentials: "include", // fetch에서는 직접 쿠키 전달 + }); + } catch (error) { + console.error("Backend logout failed:", error); + } + } + + // Next.js 쿠키 삭제 cookieStore.delete(ACCESS_TOKEN); cookieStore.delete(REFRESH_TOKEN); cookieStore.delete(AUTH_USER_ID); cookieStore.delete(CLAIM_NAME); - return NextResponse.json({ message: "Logged out" }, { status: 200 }); -} + return NextResponse.json({ message: "Logged out" }, { status: 200 }); +} \ No newline at end of file diff --git a/apps/cm/src/entities/auth/lib/token-manager.ts b/apps/cm/src/entities/auth/lib/token-manager.ts index 21ed00218..8fcf21984 100644 --- a/apps/cm/src/entities/auth/lib/token-manager.ts +++ b/apps/cm/src/entities/auth/lib/token-manager.ts @@ -1,4 +1,4 @@ -import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config"; +import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME, REFRESH_TOKEN } from "@/shared/config"; import { getCookie, setCookie, removeCookie } from "@/shared/lib"; export class TokenManager { @@ -76,6 +76,8 @@ export class TokenManager { this.removeToken(CLAIM_NAME); this.removeToken(AUTH_USER_ID); + this.removeToken(REFRESH_TOKEN); + this.removeToken(ACCESS_TOKEN); } } diff --git a/packages/common/components/src/ui/header/index.tsx b/packages/common/components/src/ui/header/index.tsx index 15b431b6a..d1675d6f1 100644 --- a/packages/common/components/src/ui/header/index.tsx +++ b/packages/common/components/src/ui/header/index.tsx @@ -64,7 +64,99 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) { queryFn: () => getSiteList(), enabled: isLoggedIn && !viewOnly, }); - + const logout = async () => { + try { + // 1. 백엔드 API 로그아웃 호출 + const response = await fetch("/api/auth/logout", { + method: "POST", + credentials: "include", // ⭐ 쿠키 포함 중요! + }); + + if (!response.ok) { + console.error("Logout API failed"); + // API 실패해도 계속 진행 + } + } catch (error) { + console.error("Logout error:", error); + // 에러가 나도 계속 진행 + } finally { + // 2. 클라이언트 쿠키 삭제 (백업) + clearClientCookies(); + + // 3. 로컬/세션 스토리지 정리 + if (typeof window !== "undefined") { + localStorage.clear(); + sessionStorage.clear(); + } + + // 4. 로그인 페이지로 리다이렉트 + window.location.href = "/auth/login"; + } + }; + + // 쿠키 삭제 헬퍼 함수 + const clearClientCookies = () => { + const actualHost = window.location.hostname; + + // 루트 도메인 추출 + const getRootDomain = (hostname: string): string => { + if (hostname === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) { + return hostname; + } + + if (hostname.includes("hasuon.or.kr")) { + return ".hasuon.or.kr"; + } + + const parts = hostname.split("."); + if (parts.length >= 2) { + return `.${parts.slice(-2).join(".")}`; + } + + return hostname; + }; + + const domain = getRootDomain(actualHost); + + // 삭제할 쿠키 목록 + const cookiesToDelete = [ + appConfig.AUTH_USER_ID, + appConfig.REFRESH_TOKEN, + appConfig.ACCESS_TOKEN, + appConfig.CLAIM_NAME, + "site-id-key", + "site-theme-key", + ].filter(Boolean); // undefined 제거 + + // 여러 방법으로 쿠키 삭제 시도 + cookiesToDelete.forEach((cookieName) => { + if (!cookieName) return; + + // 방법 1: removeCookie 함수 사용 + if (domain === "localhost") { + removeCookie(cookieName, {}); + } else { + removeCookie(cookieName, { domain }); + } + + // 방법 2: 직접 document.cookie 설정 (도메인 포함) + if (domain !== "localhost") { + document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}`; + } + + // 방법 3: 도메인 없이 삭제 (현재 도메인만) + document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; + + // 방법 4: Secure 속성 포함 삭제 + if (window.location.protocol === "https:") { + if (domain !== "localhost") { + document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}; secure`; + } + document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; secure`; + } + }); + }; + /* const logout = async () => { try { const response = await fetch("/api/auth/logout", { @@ -123,7 +215,7 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) { console.error(error); } }; - +*/ const openPopup = useCallback(async (popup: Popup) => { try { const cookieName = `cs-popup-hide-for-day-${popup.popupSn}`; From 2469a8406859cc59f3363fade7072c3bac1e9561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A7=80=EC=B2=A0?= <jcchoi@onasys.co.kr> Date: Wed, 21 Jan 2026 17:52:22 +0900 Subject: [PATCH 61/92] =?UTF-8?q?=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EB=A7=81=ED=81=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cm/app/api/auth/logout/route.ts | 24 +------------------ .../cm/src/pages/dashboard/ui/mypost-list.tsx | 14 +++++++---- .../cm/src/pages/dashboard/ui/notice-list.tsx | 10 ++++---- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/apps/cm/app/api/auth/logout/route.ts b/apps/cm/app/api/auth/logout/route.ts index 8740d9d5b..fdcc9df7c 100644 --- a/apps/cm/app/api/auth/logout/route.ts +++ b/apps/cm/app/api/auth/logout/route.ts @@ -9,31 +9,9 @@ import { export async function POST() { const cookieStore = await cookies(); - - // 백엔드에 로그아웃 알림 (토큰 블랙리스트 처리) - const refreshToken = cookieStore.get(REFRESH_TOKEN)?.value; - - if (refreshToken) { - try { - // ⭐ Spring Boot 백엔드에 로그아웃 요청 - await fetch(`${process.env.NEXT_PUBLIC_SERVER_API_URL}/api/auth/logout`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Cookie": `${REFRESH_TOKEN}=${refreshToken}`, - }, - // credentials: "include", // fetch에서는 직접 쿠키 전달 - }); - } catch (error) { - console.error("Backend logout failed:", error); - } - } - - // Next.js 쿠키 삭제 cookieStore.delete(ACCESS_TOKEN); cookieStore.delete(REFRESH_TOKEN); cookieStore.delete(AUTH_USER_ID); cookieStore.delete(CLAIM_NAME); - return NextResponse.json({ message: "Logged out" }, { status: 200 }); -} \ No newline at end of file +} diff --git a/apps/cm/src/pages/dashboard/ui/mypost-list.tsx b/apps/cm/src/pages/dashboard/ui/mypost-list.tsx index ec5f97d48..2c15b7d7d 100644 --- a/apps/cm/src/pages/dashboard/ui/mypost-list.tsx +++ b/apps/cm/src/pages/dashboard/ui/mypost-list.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; import { getCoreRowModel } from "@tanstack/react-table"; -import { PostApi, type MyPost } from "@/entities/post"; +import { PostApi, type MyPost, type NoticePost } from "@/entities/post"; import { ENDPOINT } from "@/shared/config"; import { useDataTable } from "@/shared/lib"; import { @@ -23,15 +23,21 @@ const MyPostList: React.FC = () => { }), }); + const handleMyPostRowClick = (row: MyPost) => { + router.push(`/cms/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}`); + }; + const { tableComponent: myPostTableComponent } = useDataTable({ query: myPostQuery, tableOptions: { - columns: myPostTableColumns, - getCoreRowModel: getCoreRowModel(), + columns: myPostTableColumns, + getCoreRowModel: getCoreRowModel(), }, dataTableOptions: { - variant: "line", + variant: "line", + onRowClick: handleMyPostRowClick }, + }); return ( diff --git a/apps/cm/src/pages/dashboard/ui/notice-list.tsx b/apps/cm/src/pages/dashboard/ui/notice-list.tsx index 86e21a4a3..502973225 100644 --- a/apps/cm/src/pages/dashboard/ui/notice-list.tsx +++ b/apps/cm/src/pages/dashboard/ui/notice-list.tsx @@ -26,7 +26,7 @@ const NoticeList: React.FC = () => { }); const handleNoticePostRowClick = (row: NoticePost) => { - router.push(`/bbs/bbsnotice/${row.bbsId}/${row.pstNo}`); + router.push(`/cms/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}`); }; const handleMoreClick = () => { @@ -40,12 +40,12 @@ const NoticeList: React.FC = () => { const { tableComponent: noticePostTableComponent } = useDataTable({ query: noticePostQuery, tableOptions: { - columns: noticePostTableColumns, - getCoreRowModel: getCoreRowModel(), + columns: noticePostTableColumns, + getCoreRowModel: getCoreRowModel(), }, dataTableOptions: { - variant: "line", - onRowClick: handleNoticePostRowClick, + variant: "line", + onRowClick: handleNoticePostRowClick, }, }); From bd5c2f07d389d99a734fd789f3d04f63dd282af5 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Wed, 21 Jan 2026 22:15:02 +0900 Subject: [PATCH 62/92] =?UTF-8?q?fo:=20=EC=98=A4=EC=88=98=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=EB=9F=89=20=EC=88=98=EC=A0=95=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/sewageOccur/index.tsx | 44 +++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx index 1f4e8ce7e..a0ff0a3f3 100644 --- a/apps/fo/app/store/sewageOccur/index.tsx +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -4,6 +4,7 @@ import { roundNumber } from "@/app/components/common/DataForm"; import { OSU_PERCENT } from "../common"; import type { TableUpperProps } from "../dashboard"; import { fetchFacilityListInit } from "../processFacility"; +import { fetchFacilityRainDetailList } from "../facilityPrecipitation"; export type { TableUpperProps }; /** @@ -330,15 +331,46 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = const soccurDetailRes: any = await fetchSweageOccurListFlow(searchYear, fcltCdList); const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); - // const wtrUsgMap : Record<string, number> = {}; - // wtrUsgRes.data.forEach(fclt => { - // wtrUsgMap[fclt.bscFctCd] = fclt.wtrUsg; - // }); + + //--------- + const rainDetailList: Record<string, any[]> = {}; + const wtrDetailList: Record<string, any[]> = {}; + const results: any[] = []; + const wtrResults: any[] = []; + for (let idx = 0; idx < fcltCdList.length; idx += 100) { + const slicedItems = fcltCdList.slice(idx, idx + 100); + const result = await fetchSweageOccurListFlow(searchYear, slicedItems); + const wtrResult = await fetchWtrUsgYmList(searchYear, slicedItems); + results.push(result); + wtrResults.push(wtrResult); + } + //console.log(results); + // 결과를 합치기 + for (const res of results) { + if (res.status === 200 && res.data) { + for (const [key, value] of Object.entries(res.data)) { + const keyStr = String(key); + rainDetailList[keyStr] = [...(rainDetailList[keyStr] || []), ...(value as any[])]; + } + } + } + for (const res of wtrResults) { + if (res.status === 200 && res.data) { + for (const [key, value] of Object.entries(res.data)) { + const keyStr = String(key); + wtrDetailList[keyStr] = [...(wtrDetailList[keyStr] || []), ...(value as any[])]; + } + } + } + //------- + let maxEstimationSewage = 0, minEstimationSewage = 999999999; for (const item of sewageOccurPropsList) { - const detailList = soccurDetailRes?.data[item.bscFctCd]; - const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd]; + //const detailList = soccurDetailRes?.data[item.bscFctCd]; + // const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd]; + const detailList = rainDetailList[item.bscFctCd]; + const wtrUsgYmList = wtrDetailList[item.bscFctCd]; item.swageChangePercent = 90; let sumChungcunDay = 0; // 청천일수 From 974d15962ca6921cf3478f80be88920b239fa091 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Thu, 22 Jan 2026 11:26:43 +0900 Subject: [PATCH 63/92] =?UTF-8?q?fo:=20exceldownload=204=EB=B3=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/flowRate/index.tsx | 34 ++++++++++++--- apps/fo/app/store/rdi/index.tsx | 32 ++++++++++---- apps/fo/app/store/sewageOccur/index.tsx | 14 ++++--- apps/fo/app/store/underWaterInput/index.tsx | 46 ++++++++++++++++++--- 4 files changed, 104 insertions(+), 22 deletions(-) diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 7bec0be97..02b55bd30 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -175,11 +175,11 @@ const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: s const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; const res = await getFetch('fo', url); - return { data: res.data, count: res.count } + return { data: res.data, count: res.count, status: res.status} } catch (error) { console.error('시설정보 유량현황 데이터를 가져오는데 실패했습니다:', error); console.log(error); - return { data: [], count: 0 }; + return { data: [], count: 0, status: 300 }; } } @@ -279,8 +279,32 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl isLoading: true, }, })); - const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); - const data = res.data; + + // const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + + //--------- + const flowRateList: any[] = []; + const results: any[] = []; + for (let idx = 0; idx < pageSize; idx += 100) { + const tmpPageNo = Math.floor(idx / 100) + 1; + const tmpPageSize = Math.min(100, pageSize - idx); + const result = await fetchFlowRateList( tmpPageNo, tmpPageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + results.push(result); + + } + console.log(results); + // 결과를 합치기 + + for (const res of results) { + if (res?.status === 200 && Array.isArray(res?.data)) { + flowRateList.push(...res.data); + } + } + const recordCount = results[0]?.count || 0; + //------- + + // const data = res.data; + const data = flowRateList; const excelDownList: ExcelType[] = []; const rtnData = data.map((item: flowRateListProps) => { item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); @@ -316,7 +340,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl FlowRateList: pageSize < 5000 ? { ...state.FlowRateList, flowRateList: rtnData, - flowRateCount: res.count, + flowRateCount: recordCount, isLoading: false, } : { ...state.FlowRateList, diff --git a/apps/fo/app/store/rdi/index.tsx b/apps/fo/app/store/rdi/index.tsx index 67c6efa1e..ff6a23053 100644 --- a/apps/fo/app/store/rdi/index.tsx +++ b/apps/fo/app/store/rdi/index.tsx @@ -322,15 +322,33 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio fcltCdList.push(item.bscFctCd); }); - const rdiiDetailListRes : any = await fetchFacilityRdiiDetailList(searchYear, fcltCdList); - console.log(rdiiDetailListRes); + // const rdiiDetailListRes : any = await fetchFacilityRdiiDetailList(searchYear, fcltCdList); + + //--------- + const rainDetailList: Record<string, any[]> = {}; + const results: any[] = []; + for (let idx = 0; idx < fcltCdList.length; idx += 100) { + const slicedItems = fcltCdList.slice(idx, idx + 100); + const result = await fetchFacilityRdiiDetailList(searchYear, slicedItems); + results.push(result); + } + //console.log(results); + // 결과를 합치기 + for (const res of results) { + if (res.status === 200 && res.data) { + for (const [key, value] of Object.entries(res.data)) { + const keyStr = String(key); + if (!rainDetailList[keyStr]) rainDetailList[keyStr] = []; + rainDetailList[keyStr].push(...(value as any[])); + } + } + } + //------- + // console.log(rdiiDetailListRes); for (const item of rtnData) { - //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); + // const rdiiDetailList = rdiiDetailListRes?.data[item.bscFctCd]; + const rdiiDetailList = rainDetailList[item.bscFctCd]; let rtnWinterInflBod = 0; let rtnSummerBodInfl = 0; diff --git a/apps/fo/app/store/sewageOccur/index.tsx b/apps/fo/app/store/sewageOccur/index.tsx index a0ff0a3f3..fd219c0f1 100644 --- a/apps/fo/app/store/sewageOccur/index.tsx +++ b/apps/fo/app/store/sewageOccur/index.tsx @@ -4,7 +4,7 @@ import { roundNumber } from "@/app/components/common/DataForm"; import { OSU_PERCENT } from "../common"; import type { TableUpperProps } from "../dashboard"; import { fetchFacilityListInit } from "../processFacility"; -import { fetchFacilityRainDetailList } from "../facilityPrecipitation"; +// import { fetchFacilityRainDetailList } from "../facilityPrecipitation"; export type { TableUpperProps }; /** @@ -329,8 +329,8 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = }); }); - const soccurDetailRes: any = await fetchSweageOccurListFlow(searchYear, fcltCdList); - const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); + // const soccurDetailRes: any = await fetchSweageOccurListFlow(searchYear, fcltCdList); + // const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); //--------- const rainDetailList: Record<string, any[]> = {}; @@ -350,7 +350,9 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = if (res.status === 200 && res.data) { for (const [key, value] of Object.entries(res.data)) { const keyStr = String(key); - rainDetailList[keyStr] = [...(rainDetailList[keyStr] || []), ...(value as any[])]; + //rainDetailList[keyStr] = [...(rainDetailList[keyStr] || []), ...(value as any[])]; + if (!rainDetailList[keyStr]) rainDetailList[keyStr] = []; + rainDetailList[keyStr].push(...(value as any[])); } } } @@ -358,7 +360,9 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) = if (res.status === 200 && res.data) { for (const [key, value] of Object.entries(res.data)) { const keyStr = String(key); - wtrDetailList[keyStr] = [...(wtrDetailList[keyStr] || []), ...(value as any[])]; + // wtrDetailList[keyStr] = [...(wtrDetailList[keyStr] || []), ...(value as any[])]; + if (!wtrDetailList[keyStr]) wtrDetailList[keyStr] = []; + wtrDetailList[keyStr].push(...(value as any[])); } } } diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index 0a0ce9537..d4d4c39e2 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -368,13 +368,49 @@ export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWater }); }); - const soccurDetailRes: any = await fetchDetailListFlow(searchYear, fcltCdList); - const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); - + // const soccurDetailRes: any = await fetchDetailListFlow(searchYear, fcltCdList); + // const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList); + //--------- + const rainDetailList: Record<string, any[]> = {}; + const wtrDetailList: Record<string, any[]> = {}; + const results: any[] = []; + const wtrResults: any[] = []; + for (let idx = 0; idx < fcltCdList.length; idx += 100) { + const slicedItems = fcltCdList.slice(idx, idx + 100); + const result = await fetchDetailListFlow(searchYear, slicedItems); + const wtrResult = await fetchWtrUsgYmList(searchYear, slicedItems); + results.push(result); + wtrResults.push(wtrResult); + } + //console.log(results); + // 결과를 합치기 + for (const res of results) { + if (res.status === 200 && res.data) { + for (const [key, value] of Object.entries(res.data)) { + const keyStr = String(key); + //rainDetailList[keyStr] = [...(rainDetailList[keyStr] || []), ...(value as any[])]; + if (!rainDetailList[keyStr]) rainDetailList[keyStr] = []; + rainDetailList[keyStr].push(...(value as any[])); + } + } + } + for (const res of wtrResults) { + if (res.status === 200 && res.data) { + for (const [key, value] of Object.entries(res.data)) { + const keyStr = String(key); + // wtrDetailList[keyStr] = [...(wtrDetailList[keyStr] || []), ...(value as any[])]; + if (!wtrDetailList[keyStr]) wtrDetailList[keyStr] = []; + wtrDetailList[keyStr].push(...(value as any[])); + } + } + } + //------- for (const item of underWaterPropsList) { - const detailList = soccurDetailRes?.data[item.bscFctCd]; - const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd]; + // const detailList = soccurDetailRes?.data[item.bscFctCd]; + // const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd]; + const detailList = rainDetailList[item.bscFctCd]; + const wtrUsgYmList = wtrDetailList[item.bscFctCd]; let chungcunSumFlow = 0; // 청천유입량 let sumChungcunDay = 0; // 청천일수 From da1107566c9150679c1c44da2ce8c9e577cf340e Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 22 Jan 2026 21:47:50 +0900 Subject: [PATCH 64/92] =?UTF-8?q?fo:=20=EC=88=98=EC=A7=88=ED=98=84?= =?UTF-8?q?=ED=99=A9,=20=EA=B3=84=ED=9A=8D=ED=95=98=EC=88=98=EB=9F=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/facilityWaterQlty/index.tsx | 41 +++++++++++++--- apps/fo/app/store/flowRate/index.tsx | 4 +- apps/fo/app/store/planSewage/index.tsx | 49 ++++++++++++++++--- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index db60c5b2d..4a08b429a 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -282,15 +282,19 @@ const upHeadListModalChongIn: TableUpperProps[] = [ ====================================*/ // 메인페이지 // 시설정보 수질 리스트 데이터 호출 -const fetchFacilityWaterQltyList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string | undefined, nameCd?: string | undefined, fcltCpct?: string | undefined, operationValue?: string | undefined, fcltyNm?: string | undefined): Promise<{ data: FacilityWaterQltyProps[], count: number }> => { +const fetchFacilityWaterQltyList = async ( + pageNo: number, pageSize: number, searchYear: string, partCd?: string | undefined + , nameCd?: string | undefined, fcltCpct?: string | undefined + , operationValue?: string | undefined, fcltyNm?: string | undefined +): Promise<{ data: FacilityWaterQltyProps[], count: number, status: number }> => { try { const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr; const res = await getFetch('fo', url); - return { data: res.data, count: res.count } + return { data: res.data, count: res.count, status: res.status }; } catch (error) { console.error('시설정보 수질현황 데이터를 가져오는데 실패했습니다:', error); - return { data: [], count: 0 }; + return { data: [], count: 0, status: 300 }; } } @@ -457,8 +461,27 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions isLoading: true, }, })); - const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); - const rtnData = res.data.map(item => { + + // const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + //--------- + const waterQltyList: any[] = []; + let recordCount = 0; + for (let idx = 0; idx < pageSize; idx += 100) { + const tmpPageNo = Math.floor(idx / 100) + 1; + const tmpPageSize = Math.min(100, pageSize - idx); + const result = await fetchFacilityWaterQltyList(tmpPageNo, tmpPageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + if (result?.status === 200 && Array.isArray(result?.data)) { + waterQltyList.push(...result.data); + } + recordCount = result?.count || 0; + if (result?.count < tmpPageNo * tmpPageSize) { + break; // 더 이상 데이터가 없으면 중지 + } + } + //------- + + // const rtnData = res.data.map(item => { + const rtnData = waterQltyList.map(item => { dataFormSetting(item) if (item.inflAssctBfrWqltTn) { item.inflAssctBfrWqltTn = Number(Math.round(Number(item.inflAssctBfrWqltTn) * 1000) / 1000).toFixed(3); @@ -500,7 +523,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions }); const excelDownList: ExcelType[] = []; if (pageSize > 5000) { - res.data.forEach(item => { + // res.data.forEach(item => { + waterQltyList.forEach(item => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; @@ -531,7 +555,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions }); }); } else { - res.data.forEach((item: FacilityWaterQltyProps) => { + // res.data.forEach((item: FacilityWaterQltyProps) => { + waterQltyList.forEach((item: FacilityWaterQltyProps) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; @@ -545,7 +570,7 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions FacilityWaterQltyMain: pageSize < 5000 ? { ...state.FacilityWaterQltyMain, facilityWaterQltyList: rtnData, - facilityWaterQltyCount: res.count, + facilityWaterQltyCount: recordCount, isLoading: false, } : { ...state.FacilityWaterQltyMain, diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 02b55bd30..232755c1d 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -290,7 +290,9 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl const tmpPageSize = Math.min(100, pageSize - idx); const result = await fetchFlowRateList( tmpPageNo, tmpPageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); results.push(result); - + if (result?.count < tmpPageNo * tmpPageSize) { + break; // 더 이상 데이터가 없으면 중지 + } } console.log(results); // 결과를 합치기 diff --git a/apps/fo/app/store/planSewage/index.tsx b/apps/fo/app/store/planSewage/index.tsx index 2fd9b531c..b11130a16 100644 --- a/apps/fo/app/store/planSewage/index.tsx +++ b/apps/fo/app/store/planSewage/index.tsx @@ -4,6 +4,7 @@ import { getFetch, postFetch } from "@/app/components/api"; import { type ApiResponse } from "../underWaterInput"; // import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { roundUp } from "../common"; +import { fetchSweageOccurListFlow, fetchWtrUsgYmList } from "../sewageOccur"; export type { TableUpperProps }; /** * 처리시설 연간 운영현황 > 계획하수량 산정지표 현황 @@ -101,14 +102,15 @@ const planSewageList: PlanSewageProps[] = [ * @param oprtngSttsCd : 운영 상태 코드 * @param facilityName : 시설명 */ -const fetchPlanSewageList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { +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; const res = await getFetch('fo', url); return { data: res.data, count: res.count } } -// 분류식화율 구하기 위한 api 호출 +// 분류식화율 구하기 위한 api 호출 : 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) × 100 const fetchPlanZoneList = async (searchYear: string, fcltCdList: string[]) => { try { const res = await postFetch('fo', '/prcsFclt/info/planZone/' + searchYear, fcltCdList); @@ -251,19 +253,50 @@ export const planSewageReducer: (set: (fn: (state: PlanSewageType) => PlanSewage const excelDownList: ExcelType[] = []; // const data = res.data - const planZoneRes: any = await fetchPlanZoneList(searchYear, fcltCdList); - const planZoneList = planZoneRes?.data; + // 분류식화율 구하기 위한 api 호출 : 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) × 100 + // const planZoneRes: any = await fetchPlanZoneList(searchYear, fcltCdList); + // const detailRes: any = await fetchFlow(searchYear, fcltCdList); + //--------- + const planZoneList: any[] = []; + const flowDetailList: Record<string, any[]> = {}; + // const results: any[] = []; + const flowDetailResults: any[] = []; + for (let idx = 0; idx < fcltCdList.length; idx += 100) { + const slicedItems = fcltCdList.slice(idx, idx + 100); + const result = await fetchPlanZoneList(searchYear, slicedItems); // 분류식화율 구하기 위한 api 호출 : 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) × 100 + const flowResult = await fetchFlow(searchYear, slicedItems); + if (result?.status === 200 && Array.isArray(result?.data)) { + planZoneList.push(...result.data); + } + flowDetailResults.push(flowResult); + } + //console.log(results); + // 결과를 합치기 + for (const res of flowDetailResults) { + if (res.status === 200 && res.data) { + for (const [key, value] of Object.entries(res.data)) { + const keyStr = String(key); + if (!flowDetailList[keyStr]) flowDetailList[keyStr] = []; + flowDetailList[keyStr].push(...(value as any[])); + } + } + } + //------- + + + // const planZoneList = planZoneRes?.data; planZoneList?.forEach(item => { const planSewageItem = planSewageList.find(item2 => item2.bscFctCd == item.bscFctCd); if (planSewageItem) { - planSewageItem.sprtProcZoneAr = item.sprtProcZoneAr; - planSewageItem.procZoneSm = item.procZoneSm; + planSewageItem.sprtProcZoneAr = item.sprtProcZoneAr; // 처리구역면적_분류식 + planSewageItem.procZoneSm = item.procZoneSm; //처리구역면적합계 } }); - const detailRes: any = await fetchFlow(searchYear, fcltCdList); + //const detailRes: any = await fetchFlow(searchYear, fcltCdList); for (const item of planSewageList) { - const detailList = detailRes?.data[item.bscFctCd]; + // const detailList = detailRes?.data[item.bscFctCd]; + const detailList = flowDetailList[item.bscFctCd]; let avgInflAmnt = 0; let sumInflAmntSunny = 0; From 30b98de0a1c456c8a0a602627958e5dd1f003954 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 22 Jan 2026 21:57:42 +0900 Subject: [PATCH 65/92] =?UTF-8?q?fo:=20planSewage=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/planSewage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/fo/app/store/planSewage/index.tsx b/apps/fo/app/store/planSewage/index.tsx index b11130a16..1f81dec01 100644 --- a/apps/fo/app/store/planSewage/index.tsx +++ b/apps/fo/app/store/planSewage/index.tsx @@ -4,7 +4,7 @@ import { getFetch, postFetch } from "@/app/components/api"; import { type ApiResponse } from "../underWaterInput"; // import CalcRainEffect from "@/app/components/common/CalcRainEffect"; import { roundUp } from "../common"; -import { fetchSweageOccurListFlow, fetchWtrUsgYmList } from "../sewageOccur"; +// import { fetchSweageOccurListFlow, fetchWtrUsgYmList } from "../sewageOccur"; export type { TableUpperProps }; /** * 처리시설 연간 운영현황 > 계획하수량 산정지표 현황 From cf61a8956b4164afaa1e6cdf409f7f82083cd372 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 26 Jan 2026 12:57:00 +0900 Subject: [PATCH 66/92] =?UTF-8?q?fo:=20exceldown=EC=8B=9C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/.env.local | 2 +- apps/fo/.env.production | 5 ++--- .../app/pages/(with-layout)/sewageOccur/page.tsx | 16 ++++++++++++++++ .../pages/(with-layout)/underWaterInput/page.tsx | 16 ++++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/fo/.env.local b/apps/fo/.env.local index 693b6e7ef..1b80d302e 100644 --- a/apps/fo/.env.local +++ b/apps/fo/.env.local @@ -8,7 +8,7 @@ NEXT_PUBLIC_PROXY_HOST = http://localhost:3000 NEXT_PUBLIC_SUB_DOMAIN = http://localhost:13000 #NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service -NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/ +NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000 NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver diff --git a/apps/fo/.env.production b/apps/fo/.env.production index 64f0398e0..d6940b0e9 100644 --- a/apps/fo/.env.production +++ b/apps/fo/.env.production @@ -8,13 +8,12 @@ NEXT_PUBLIC_REFRESH_TOKEN = refresh-token #NEXT_PUBLIC_PROXY_HOST = https://devlarva.hasuon.or.kr #NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service -NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1 +NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000 NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl -NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1 -NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service +NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x} diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index 31862e362..e9297d0f5 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -196,6 +196,22 @@ export default function PlanSewage() { // 엑셀다운로드 const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } searchFacilityPrecipitation(ref.current, 1, 5000); setIsInitExcelDownload(true); }, [searchFacilityPrecipitation]); diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index a2ad7bfd6..969ae2a05 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -200,6 +200,22 @@ export default function UnderWaterInput() { // 엑셀다운로드 const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } searchFacilityPrecipitation(ref.current, 1, 5000); setIsMount(true); }, [searchFacilityPrecipitation]); From a61fda8b58931c2869dc892bab2d6555de43149f Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 26 Jan 2026 16:13:33 +0900 Subject: [PATCH 67/92] =?UTF-8?q?fo:=20exceldown=EC=8B=9C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EB=82=98=EB=A8=B8=EC=A7=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/page.tsx | 16 ++++++++++++++++ .../(with-layout)/facilityWaterQlty/page.tsx | 17 +++++++++++++++++ .../app/pages/(with-layout)/flowRate/page.tsx | 17 +++++++++++++++++ .../app/pages/(with-layout)/planSewage/page.tsx | 17 +++++++++++++++++ .../pages/(with-layout)/processArea/page.tsx | 17 +++++++++++++++++ .../(with-layout)/processFacility/page.tsx | 17 +++++++++++++++++ apps/fo/app/pages/(with-layout)/rdi/page.tsx | 17 +++++++++++++++++ 7 files changed, 118 insertions(+) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 18a769871..eecab5768 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -191,6 +191,22 @@ export default function FacilityPrecipitation() { // 엑셀다운로드 const excelDownload = useCallback((searchReturn: ReturnType) => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } searchFacilityPrecipitation(searchReturn, 1, 10000); }, [searchFacilityPrecipitation]); diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 86a434d6b..539cc6f31 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -170,6 +170,23 @@ export default function ProcessFacilitySearch() { }, [upHeadList1, upHeadList2, upHeadList3]); const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } + setExcelTrigger(true); searchFcltyQltyList(ref.current, 1, 10000); }, [searchFcltyQltyList]); diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index a1a5e22d1..696e8f0b2 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -176,6 +176,23 @@ export default function ProcessFacilitySearch() { }, [upHeadList1, upHeadList2, upHeadList3]); const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } + searchFlowRate(ref.current, 1, 10000); setExcelTrigger(true); }, [searchFlowRate]); diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 62ae9483a..0f73f1035 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -178,6 +178,23 @@ export default function PlanSewage() { // 엑셀다운로드 const excelDownload = useCallback((searchReturn: ReturnType) => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } + searchPlanSewage(searchReturn, 1, 10000); setExcelTrigger(true); }, [searchPlanSewage]); diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index ba1e27767..deca4366c 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -132,6 +132,23 @@ export default function ProcessArea() { }, [excelList]); const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } + searchProcessArea(ref.current, 1, 10000); }, [searchProcessArea]); diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 9c3c612b5..b239970e0 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -236,6 +236,23 @@ export default function ProcessFacilitySearch() { } const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } + searchFcltyList(ref.current, 1, 10000); }, [searchFcltyList]); diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 98120523a..ef1691d69 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -175,6 +175,23 @@ export default function Rdi() { // 엑셀다운로드 const excelDownload = useCallback(() => { + if (ref.current.partValue === 'A') { // 행정별 + if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'R') { // 유역별 + if (!ref.current.regionValue || ref.current.regionValue === '0') { + alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + return; + } + } else if (ref.current.partValue === 'G') { // 환경청별 + if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + return; + } + } + searchRdi(ref.current, 1, 5000); setIsInitExcelDownload(true); }, [searchRdi]); From 4356ec8a34855828ece8359188557f5d6658b203 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Wed, 28 Jan 2026 18:05:48 +0900 Subject: [PATCH 68/92] =?UTF-8?q?fo:=20=EB=85=84=EB=8F=84=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EB=B0=8F=20exceldown=EC=8B=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20=EC=B2=98=EB=A6=AC=203=EB=B3=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/dashboard/page.tsx | 8 +++-- .../facilityPrecipitation/page.tsx | 17 +++++---- .../(with-layout)/facilityWaterQlty/page.tsx | 11 ++++-- .../app/pages/(with-layout)/flowRate/page.tsx | 35 +++++++++++-------- .../pages/(with-layout)/planSewage/page.tsx | 13 ++++--- .../pages/(with-layout)/processArea/page.tsx | 17 +++++---- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 11 ++++-- .../pages/(with-layout)/sewageOccur/page.tsx | 25 ++++++++----- .../(with-layout)/underWaterInput/page.tsx | 27 ++++++++------ apps/fo/app/store/common/index.tsx | 30 ++++++++-------- .../src/ui/select/index.tsx | 22 +++++++----- 11 files changed, 136 insertions(+), 80 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index 6ab18b825..833f706ed 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -60,6 +60,10 @@ export default function DashBoard() { const [sidoValue, setSidoValue] = useState<string>('0'); const [sigunValue, setSigunValue] = useState<string>('0'); const { isInit, selectSearchYear, btnClass, selectSidoData, selectSigunData, } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; const { planFcltyList } = PlanFclty; const { operationalStatusList } = OperationStatus; const { excelList } = RainManage; @@ -75,7 +79,7 @@ export default function DashBoard() { /******************선택된 데이터******************/ - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || '0'); // 연도 + const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 연도 // 시설명 const [fcltyList, setFcltyList] = useState<FacilityType>({ bscFctCd: '11000SW001R', @@ -283,7 +287,7 @@ export default function DashBoard() { trtFrfNm: '표준활성슬러지법, MLE, A2O', efflWqltStndrdNm: '500톤 이상(Ⅲ지역)' }); - setSearchYear(selectSearchYear[0]?.val || '0'); + setSearchYear(defaultSearchYear); searchFcltyList.bscFctNm = '난지'; setSidoValue('0'); diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index eecab5768..0f29a28c4 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -37,6 +37,11 @@ export default function FacilityPrecipitation() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { labelArray, } = FacilityPrecipitationSearch; @@ -90,7 +95,7 @@ export default function FacilityPrecipitation() { // 시설상태 const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); /** * 페이지 함수 @@ -102,7 +107,7 @@ export default function FacilityPrecipitation() { // 상태값 설정 setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); - setSearchYear(selectSearchYear[0]?.val || "0"); + setSearchYear(defaultSearchYear); // SearchInputSelect 초기화 setFcltyName(""); if (searchInputRef.current) { @@ -111,7 +116,7 @@ export default function FacilityPrecipitation() { input.value = ""; } } - searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0"); + searchFacilityPrecipitationList(1, 10, defaultSearchYear); } // 모달 닫기 @@ -134,9 +139,9 @@ export default function FacilityPrecipitation() { useEffect(() => { if (!isInit) { initializeCommonData(); - searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0"); + searchFacilityPrecipitationList(1, 10, defaultSearchYear); } - }, [isInit, initializeCommonData, searchFacilityPrecipitationList, selectSearchYear]); + }, [isInit, initializeCommonData, searchFacilityPrecipitationList, defaultSearchYear]); useEffect(() => { if (excelList && excelList.length > 0) { @@ -270,4 +275,4 @@ export default function FacilityPrecipitation() { )} </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 539cc6f31..0f8427458 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -36,6 +36,11 @@ export default function ProcessFacilitySearch() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { mainLabelArray, upHeadList1, @@ -57,7 +62,7 @@ export default function ProcessFacilitySearch() { const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); const [fcltyName, setFcltyName] = useState<string>(""); const [operationValue, setOperationValue] = useState<string>("0"); - const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear); const [fcltCpct, setFcltCpct] = useState<string>("0"); // 모달 상태 추가 @@ -96,7 +101,7 @@ export default function ProcessFacilitySearch() { // 상태값 설정 setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); - setSearchYearValue(selectSearchYear[0]?.val || "0"); + setSearchYearValue(defaultSearchYear); // SearchInputSelect 초기화 setFcltyName(""); if (searchInputRef.current) { @@ -241,4 +246,4 @@ export default function ProcessFacilitySearch() { )} </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index 696e8f0b2..c80d46699 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -7,7 +7,7 @@ "use client" import { useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; -import type { ExcelType } from "@/app/store/flowRate"; +// import type { ExcelType } from "@/app/store/flowRate"; import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; @@ -38,6 +38,11 @@ export default function ProcessFacilitySearch() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { flowRateSearchLabelArray } = FlowRateSearch; @@ -57,17 +62,17 @@ export default function ProcessFacilitySearch() { const [fcltCpct, setFcltCpct] = useState<string>("0"); const [fcltyName, setFcltyName] = useState<string>(""); const [operationValue, setOperationValue] = useState<string>("0"); - const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear); // const [widthSize, setWidthSize] = useState<string>("w-[120%]"); const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1); const [resetPage, setResetPage] = useState<boolean>(false); - const prevExcelListRef = useRef<ExcelType[] | null>(null); + // const prevExcelListRef = useRef<ExcelType[] | null>(null); // 모달 상태 추가 const [selectedRow, setSelectedRow] = useState<number | null>(null); const [fcltyNm, setFcltyNm] = useState<string>(""); const [fcltyCd, setFcltyCd] = useState<string>(""); - const [excelTrigger, setExcelTrigger] = useState<boolean>(false); + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); const [initTrigger, setInitTrigger] = useState<boolean>(false); const searchFlowRate = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { @@ -99,7 +104,7 @@ export default function ProcessFacilitySearch() { // setWidthSize("w-[120%]"); setUpheadList(upHeadList1) // 상태값 설정 - setSearchYearValue(selectSearchYear[0]?.val || "0"); + setSearchYearValue(defaultSearchYear); setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); // SearchInputSelect 초기화 @@ -147,15 +152,17 @@ export default function ProcessFacilitySearch() { }, [isInit, initializeCommonData, searchFlowRateList, selectSearchYear, searchFlowRate, initTrigger]); useEffect(() => { - if(!excelTrigger) return; + if(!isExcelDownClick) 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, excelTrigger]); + const timer = setTimeout(() => { + 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 { + alert('조회된 결과가 없습니다.'); + } + }, 1000); // 약간의 지연을 두고 다운로드 실행 + return () => clearTimeout(timer); + }, [excelList, isExcelDownClick]); const ref = useRef<ReturnType>({ partValue: '', @@ -194,7 +201,7 @@ export default function ProcessFacilitySearch() { } searchFlowRate(ref.current, 1, 10000); - setExcelTrigger(true); + setIsExcelDownClick(true); }, [searchFlowRate]); const total = flowRateCount; diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 0f73f1035..41b541ce9 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -41,6 +41,11 @@ export default function PlanSewage() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { labelArray, } = PlanSewageSearch; @@ -85,7 +90,7 @@ export default function PlanSewage() { // 시설상태 const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); const [initTrigger, setInitTrigger] = useState<boolean>(false); @@ -100,7 +105,7 @@ export default function PlanSewage() { // 상태값 설정 setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); - setSearchYear(selectSearchYear[0]?.val || "0"); + setSearchYear(defaultSearchYear); // SearchInputSelect 초기화 setFcltyName(""); if (searchInputRef.current) { @@ -168,7 +173,7 @@ export default function PlanSewage() { setInitTrigger(true); } } - }, [isInit, initializeCommonData, searchPlanSewageList, selectSearchYear, initTrigger, searchPlanSewage]); + }, [isInit, initializeCommonData, initTrigger, searchPlanSewage]); const chkVal = useCallback((returntype: ReturnType) => { // setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") @@ -241,4 +246,4 @@ export default function PlanSewage() { </ListDiv> </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index deca4366c..e3b6fc3da 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -42,6 +42,11 @@ export default function ProcessArea() { btnClass, } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { processFacilityLabelArray, } = ProcessAreaSearch; @@ -64,7 +69,7 @@ export default function ProcessArea() { const [fcltyCd, setFcltyCd] = useState<string>(""); const [resetPage, setResetPage] = useState<boolean>(false); - const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear); const ref = useRef<ReturnType>({ partValue: '', @@ -95,8 +100,8 @@ export default function ProcessArea() { input.value = ""; } } - setSearchYearValue(selectSearchYear[0]?.val || "0"); - searchProcessAreaList(1, 10, '', '', selectSearchYear[0]?.val || "0"); + setSearchYearValue(defaultSearchYear); + searchProcessAreaList(1, 10, '', '', defaultSearchYear); } // 셀 클릭 시 모달 표시 @@ -116,9 +121,9 @@ export default function ProcessArea() { useEffect(() => { if (!isInit) { initializeCommonData(); - searchProcessAreaList(1, 10, '', '', selectSearchYear[0]?.val || "0"); + searchProcessAreaList(1, 10, '', '', defaultSearchYear); } - }, [isInit, initializeCommonData, searchProcessAreaList]); + }, [isInit, initializeCommonData, searchProcessAreaList, defaultSearchYear]); useEffect(() => { if (excelList && excelList.length > 0) { @@ -200,4 +205,4 @@ export default function ProcessArea() { )} </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index ef1691d69..d166e01a3 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -41,6 +41,11 @@ export default function Rdi() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { labelArray, } = RdiSearch; @@ -83,7 +88,7 @@ export default function Rdi() { // 시설상태 const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀 다운로드 트리거 const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false); @@ -99,7 +104,7 @@ export default function Rdi() { // 상태값 설정 setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); - setSearchYear(selectSearchYear[0]?.val || "0"); + setSearchYear(defaultSearchYear); // SearchInputSelect 초기화 setFcltyName(""); if (searchInputRef.current) { @@ -241,4 +246,4 @@ export default function Rdi() { </ContentsDiv> </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index e9297d0f5..a7ff0df71 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -44,6 +44,11 @@ export default function PlanSewage() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { labelArray, } = SewageOccurSearch; @@ -93,9 +98,9 @@ export default function PlanSewage() { // 시설상태 const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 - const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false); + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); /** * 페이지 함수 @@ -107,7 +112,7 @@ export default function PlanSewage() { // 상태값 설정 setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); - setSearchYear(selectSearchYear[0]?.val || "0"); + setSearchYear(defaultSearchYear); // SearchInputSelect 초기화 setFcltyName(""); if (searchInputRef.current) { @@ -116,7 +121,7 @@ export default function PlanSewage() { input.value = ""; } } - searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0"); + searchSewageOccurList(1, 10, defaultSearchYear); } // 모달 닫기 @@ -139,12 +144,12 @@ export default function PlanSewage() { useEffect(() => { if (!isInit) { initializeCommonData(); - searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0"); + searchSewageOccurList(1, 10, defaultSearchYear); } - }, [isInit, initializeCommonData, searchSewageOccurList, selectSearchYear]); + }, [isInit, initializeCommonData, searchSewageOccurList, defaultSearchYear]); useEffect(() => { - if(!isInitExcelDownload) return ; + if(!isExcelDownClick) return ; const timer = setTimeout(() => { if (excelList && excelList.length > 0) { @@ -154,11 +159,13 @@ export default function PlanSewage() { sheetNameArray: ['오수발생량 추정'], headerRange: 'A1:O1' }); + } else { + alert("조회된 결과가 없습니다."); } }, 500); // 약간의 지연을 두고 다운로드 실행 return () => clearTimeout(timer); - }, [excelList, isInit, isInitExcelDownload]); + }, [excelList, isInit, isExcelDownClick]); /** * 콜백함수 @@ -213,7 +220,7 @@ export default function PlanSewage() { } } searchFacilityPrecipitation(ref.current, 1, 5000); - setIsInitExcelDownload(true); + setIsExcelDownClick(true); }, [searchFacilityPrecipitation]); // 페이지 변경 diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 969ae2a05..849689312 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -50,6 +50,11 @@ export default function UnderWaterInput() { btnClass } = Common; + const defaultSearchYear = + selectSearchYear.find((item) => item.selected)?.val || + selectSearchYear[0]?.val || + "0"; + const { labelArray, } = UnderWaterSearch; @@ -98,9 +103,9 @@ export default function UnderWaterInput() { // 시설상태 const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 - const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0"); + const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 - const [isMount, setIsMount] = useState<boolean>(false); + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); /** * 페이지 함수 @@ -112,7 +117,7 @@ export default function UnderWaterInput() { // 상태값 설정 setFcltCpct(selectUpdownData[0]?.val || "0"); setOperationValue(selectOperationData[0]?.val || "0"); - setSearchYear(selectSearchYear[0]?.val || "0"); + setSearchYear(defaultSearchYear); // SearchInputSelect 초기화 setFcltyName(""); if (searchInputRef.current) { @@ -121,7 +126,7 @@ export default function UnderWaterInput() { input.value = ""; } } - searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0"); + searchUnderWaterList(1, 10, defaultSearchYear); } // 모달 닫기 @@ -144,12 +149,12 @@ export default function UnderWaterInput() { useEffect(() => { if (!isInit) { initializeCommonData(); - searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0"); + searchUnderWaterList(1, 10, defaultSearchYear); } - }, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear]); + }, [isInit, initializeCommonData, searchUnderWaterList, defaultSearchYear]); useEffect(() => { - if(!isMount) return ; + if(!isExcelDownClick) return ; const timer = setTimeout(() => { if (excelList && excelList.length > 0) { @@ -159,10 +164,12 @@ export default function UnderWaterInput() { sheetNameArray: ['지하수유입량 추정'], headerRange: 'A1:O1' }); + } else { + alert("조회된 결과가 없습니다."); } }, 1000); // 약간의 지연을 두고 다운로드 실행 return () => clearTimeout(timer); - }, [excelList, isMount]); + }, [excelList, isExcelDownClick]); /** * 콜백함수 @@ -217,7 +224,7 @@ export default function UnderWaterInput() { } } searchFacilityPrecipitation(ref.current, 1, 5000); - setIsMount(true); + setIsExcelDownClick(true); }, [searchFacilityPrecipitation]); // 페이지 변경 @@ -276,4 +283,4 @@ export default function UnderWaterInput() { )} </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/store/common/index.tsx b/apps/fo/app/store/common/index.tsx index a381eb50d..d24305aa9 100644 --- a/apps/fo/app/store/common/index.tsx +++ b/apps/fo/app/store/common/index.tsx @@ -12,6 +12,8 @@ import { getFetch, getFetchAreaList } from "@/app/components/api"; export type SelectDataType = { text: string; val: string; + selected?: boolean; + hidden?: boolean; } // grid header export type TableUpperProps = { @@ -160,23 +162,21 @@ const selectFacilityPartData: SelectDataType[] = [ const getYearData = () => { const today = new Date(); const year = today.getFullYear(); - const month = today.getMonth() + 1; + // const month = today.getMonth() + 1; // 상반기(6월까지)는 2년 전, 하반기는 1년 전부터 시작 - const startYear = month <= 6 ? (year - 2) : (year - 1); + // const startYear = month <= 6 ? (year - 2) : (year - 1); + const startYear = year - 1; - const year1 = startYear; - const year2 = startYear - 1; - const year3 = startYear - 2; - const year4 = startYear - 3; - const year5 = startYear - 4; - return [ - { text: year1 + "년", val: year1.toString() }, - { text: year2 + "년", val: year2.toString() }, - { text: year3 + "년", val: year3.toString() }, - { text: year4 + "년", val: year4.toString() }, - { text: year5 + "년", val: year5.toString() }, - ] + // 최근 10개년도 제공 (기본값: 첫 번째 항목 선택) + return Array.from({ length: 10 }, (_, index) => { + const targetYear = startYear - index; + return { + text: `${targetYear}년`, + val: targetYear.toString(), + selected: index === 0, + }; + }); } const selectSearchYear: SelectDataType[] = getYearData(); @@ -486,4 +486,4 @@ export const CommonReducer = ( } } -export type CommonStore = CommonType & CommonAction; \ No newline at end of file +export type CommonStore = CommonType & CommonAction; diff --git a/packages/common/business_components/src/ui/select/index.tsx b/packages/common/business_components/src/ui/select/index.tsx index f9dac92d6..32510eb18 100644 --- a/packages/common/business_components/src/ui/select/index.tsx +++ b/packages/common/business_components/src/ui/select/index.tsx @@ -1,7 +1,8 @@ // selectBox import { Label } from "@common/components"; -import React, { useEffect, useState } from "react"; +// import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { Select, SelectContent, @@ -15,6 +16,7 @@ interface SelectBox1 { text: string; val: string | number; hidden?: boolean; + selected?: boolean; } const SelectBox = React.forwardRef< @@ -51,18 +53,22 @@ const SelectBox = React.forwardRef< const [isOpen, setIsOpen] = useState(false); // hidden이 true인 항목만 드롭다운에서 제외 const visibleItems = selectArray.filter((item) => !item.hidden); + const selectedItem = visibleItems.find((item) => item.selected); + + const resolvedValue = + value === undefined && selectedItem ? selectedItem.val : value; // 현재 값이 hidden 항목이거나 빈 값인 경우 undefined로 설정하여 placeholder가 표시되도록 함 const currentValue = - value !== undefined && + resolvedValue !== undefined && hiddenItem && - (String(value) === String(hiddenItem.val) || - value === "" || - value === "0" || - value === 0) + (String(resolvedValue) === String(hiddenItem.val) || + resolvedValue === "" || + resolvedValue === "0" || + resolvedValue === 0) ? undefined - : value !== undefined - ? String(value) + : resolvedValue !== undefined + ? String(resolvedValue) : undefined; return ( From 5faced2928a4741d8584bdda4ea6c4019e2eb75f Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Thu, 29 Jan 2026 09:12:00 +0900 Subject: [PATCH 69/92] =?UTF-8?q?fo:=20default=20=EB=85=84=EB=8F=84=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/common/index.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/fo/app/store/common/index.tsx b/apps/fo/app/store/common/index.tsx index d24305aa9..f71550f1a 100644 --- a/apps/fo/app/store/common/index.tsx +++ b/apps/fo/app/store/common/index.tsx @@ -162,11 +162,11 @@ const selectFacilityPartData: SelectDataType[] = [ const getYearData = () => { const today = new Date(); const year = today.getFullYear(); - // const month = today.getMonth() + 1; - + const month = today.getMonth() + 1; + // 상반기(6월까지)는 2년 전, 하반기는 1년 전부터 시작 - // const startYear = month <= 6 ? (year - 2) : (year - 1); - const startYear = year - 1; + const defaultIdx = month <= 6 ? 2 : 1; + const startYear = year; // 최근 10개년도 제공 (기본값: 첫 번째 항목 선택) return Array.from({ length: 10 }, (_, index) => { @@ -174,7 +174,7 @@ const getYearData = () => { return { text: `${targetYear}년`, val: targetYear.toString(), - selected: index === 0, + selected: index === defaultIdx, }; }); } From a2504f4c85c1ed4073073d781204e2e812bb39ee Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Thu, 29 Jan 2026 18:07:08 +0900 Subject: [PATCH 70/92] =?UTF-8?q?fo:exceldown=EC=8B=9C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=ED=95=B4=EC=A0=9C=204=EA=B0=9C=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/page.tsx | 32 +++++++------- .../pages/(with-layout)/processArea/page.tsx | 32 +++++++------- .../(with-layout)/processFacility/page.tsx | 32 +++++++------- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 43 ++++++++++--------- .../src/shared/providers/prompt-provider.tsx | 1 + 5 files changed, 72 insertions(+), 68 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 0f29a28c4..14d16810d 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -196,22 +196,22 @@ export default function FacilityPrecipitation() { // 엑셀다운로드 const excelDownload = useCallback((searchReturn: ReturnType) => { - if (ref.current.partValue === 'A') { // 행정별 - if (!ref.current.sidoValue || ref.current.sidoValue === '0') { - alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'R') { // 유역별 - if (!ref.current.regionValue || ref.current.regionValue === '0') { - alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'G') { // 환경청별 - if (!ref.current.envPartValue || ref.current.envPartValue === '0') { - alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); - return; - } - } + // if (ref.current.partValue === 'A') { // 행정별 + // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'R') { // 유역별 + // if (!ref.current.regionValue || ref.current.regionValue === '0') { + // alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'G') { // 환경청별 + // if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + // alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } searchFacilityPrecipitation(searchReturn, 1, 10000); }, [searchFacilityPrecipitation]); diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index e3b6fc3da..371a1262d 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -137,22 +137,22 @@ export default function ProcessArea() { }, [excelList]); const excelDownload = useCallback(() => { - if (ref.current.partValue === 'A') { // 행정별 - if (!ref.current.sidoValue || ref.current.sidoValue === '0') { - alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'R') { // 유역별 - if (!ref.current.regionValue || ref.current.regionValue === '0') { - alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'G') { // 환경청별 - if (!ref.current.envPartValue || ref.current.envPartValue === '0') { - alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); - return; - } - } + // if (ref.current.partValue === 'A') { // 행정별 + // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'R') { // 유역별 + // if (!ref.current.regionValue || ref.current.regionValue === '0') { + // alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'G') { // 환경청별 + // if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + // alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } searchProcessArea(ref.current, 1, 10000); }, [searchProcessArea]); diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index b239970e0..9a6535db1 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -236,22 +236,22 @@ export default function ProcessFacilitySearch() { } const excelDownload = useCallback(() => { - if (ref.current.partValue === 'A') { // 행정별 - if (!ref.current.sidoValue || ref.current.sidoValue === '0') { - alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'R') { // 유역별 - if (!ref.current.regionValue || ref.current.regionValue === '0') { - alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'G') { // 환경청별 - if (!ref.current.envPartValue || ref.current.envPartValue === '0') { - alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); - return; - } - } + // if (ref.current.partValue === 'A') { // 행정별 + // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'R') { // 유역별 + // if (!ref.current.regionValue || ref.current.regionValue === '0') { + // alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'G') { // 환경청별 + // if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + // alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } searchFcltyList(ref.current, 1, 10000); }, [searchFcltyList]); diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index d166e01a3..63df65e13 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -90,7 +90,8 @@ export default function Rdi() { // 조회기간 const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀 다운로드 트리거 - const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false); + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const [initTrigger, setInitTrigger] = useState<boolean>(false); /** @@ -118,7 +119,7 @@ export default function Rdi() { } useEffect(() => { - if(!isInitExcelDownload) return ; + if(!isExcelDownClick) return ; if (excelList && excelList.length > 0) { downloadExcel({ data: excelList as unknown as JSON[], @@ -126,8 +127,10 @@ export default function Rdi() { sheetNameArray: ['RDII추정'], headerRange: 'A1:R1' }); + } else { + alert("조회된 결과가 없습니다."); } - }, [excelList, isInitExcelDownload]); + }, [excelList, isExcelDownClick]); /** * 콜백함수 @@ -180,25 +183,25 @@ export default function Rdi() { // 엑셀다운로드 const excelDownload = useCallback(() => { - if (ref.current.partValue === 'A') { // 행정별 - if (!ref.current.sidoValue || ref.current.sidoValue === '0') { - alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'R') { // 유역별 - if (!ref.current.regionValue || ref.current.regionValue === '0') { - alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); - return; - } - } else if (ref.current.partValue === 'G') { // 환경청별 - if (!ref.current.envPartValue || ref.current.envPartValue === '0') { - alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); - return; - } - } + // if (ref.current.partValue === 'A') { // 행정별 + // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { + // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'R') { // 유역별 + // if (!ref.current.regionValue || ref.current.regionValue === '0') { + // alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } else if (ref.current.partValue === 'G') { // 환경청별 + // if (!ref.current.envPartValue || ref.current.envPartValue === '0') { + // alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.'); + // return; + // } + // } searchRdi(ref.current, 1, 5000); - setIsInitExcelDownload(true); + setIsExcelDownClick(true); }, [searchRdi]); // 페이지 변경 diff --git a/apps/fo/src/shared/providers/prompt-provider.tsx b/apps/fo/src/shared/providers/prompt-provider.tsx index 10338c338..7724d0326 100644 --- a/apps/fo/src/shared/providers/prompt-provider.tsx +++ b/apps/fo/src/shared/providers/prompt-provider.tsx @@ -1,3 +1,4 @@ +"use client"; import { createContext, useState } from "react"; interface PromptContext { From 527b0c65672927d495c61d3e170f01800287fdcd Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 29 Jan 2026 20:56:43 +0900 Subject: [PATCH 71/92] =?UTF-8?q?fo:=20exceldownload=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EA=B0=80=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/page.tsx | 28 ++++++++----- .../(with-layout)/facilityWaterQlty/page.tsx | 40 +++++++++++-------- .../app/pages/(with-layout)/flowRate/page.tsx | 1 + .../pages/(with-layout)/planSewage/page.tsx | 32 +++++++++------ .../pages/(with-layout)/processArea/page.tsx | 29 +++++++++----- .../(with-layout)/processFacility/page.tsx | 18 +++++++-- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 26 +++++++----- .../pages/(with-layout)/sewageOccur/page.tsx | 1 + .../(with-layout)/underWaterInput/page.tsx | 1 + 9 files changed, 116 insertions(+), 60 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 14d16810d..4df912186 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -96,7 +96,8 @@ export default function FacilityPrecipitation() { const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); - + // 엑셀다운로드 트리거 + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); /** * 페이지 함수 */ @@ -144,14 +145,22 @@ export default function FacilityPrecipitation() { }, [isInit, initializeCommonData, searchFacilityPrecipitationList, defaultSearchYear]); useEffect(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '시설별 강수현황', - sheetNameArray: ['시설별 강수현황'], - headerRange: 'A1:N1' - }); - } + if (!isExcelDownClick) return; + + const timer = setTimeout(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '시설별 강수현황', + sheetNameArray: ['시설별 강수현황'], + headerRange: 'A1:N1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + }, 500); + return () => clearTimeout(timer); }, [excelList]); useEffect(() => { @@ -213,6 +222,7 @@ export default function FacilityPrecipitation() { // } // } searchFacilityPrecipitation(searchReturn, 1, 10000); + setIsExcelDownClick(true); }, [searchFacilityPrecipitation]); // 페이지 변경 diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 0f8427458..1df3be0cd 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -54,7 +54,8 @@ export default function ProcessFacilitySearch() { const mainList: FacilityWaterQltyProps[] = facilityWaterQltyList || []; const [initTrigger, setInitTrigger] = useState<boolean>(false); - const [excelTrigger, setExcelTrigger] = useState<boolean>(false); + // 엑셀다운로드 트리거 + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); // 그리드 관련 const [resetPage, setResetPage] = useState<boolean>(false); const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); @@ -152,21 +153,28 @@ export default function ProcessFacilitySearch() { }, [isInit, initializeCommonData, searchFacilityWaterQltyList, searchFcltyQltyList, initTrigger]); useEffect(() => { - if (!excelTrigger) return; + if (!isExcelDownClick) return; - if (excelList && excelList.length > 0) { - downloadExcelFormat( - { - data: excelList as unknown as JSON[], - fileName: '시설별 수질현황', - sheetNameArray: ['시설별 수질현황'], - headerRange: 'A1:T1', - decimalArray1: [10, 11, 12, 15, 16, 17], - decimalArray3: [13, 14, 18, 19] - } - ); - } - }, [excelList, excelTrigger]); + const timer = setTimeout(() => { + if (excelList && excelList.length > 0) { + downloadExcelFormat( + { + data: excelList as unknown as JSON[], + fileName: '시설별 수질현황', + sheetNameArray: ['시설별 수질현황'], + headerRange: 'A1:T1', + decimalArray1: [10, 11, 12, 15, 16, 17], + decimalArray3: [13, 14, 18, 19] + } + ); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + }, 500); + + return () => clearTimeout(timer); + }, [excelList, isExcelDownClick]); const chkVal = useCallback((returntype: ReturnType) => { // setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") @@ -192,7 +200,7 @@ export default function ProcessFacilitySearch() { } } - setExcelTrigger(true); + setIsExcelDownClick(true); searchFcltyQltyList(ref.current, 1, 10000); }, [searchFcltyQltyList]); diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index c80d46699..66b8c990d 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -160,6 +160,7 @@ export default function ProcessFacilitySearch() { } else { alert('조회된 결과가 없습니다.'); } + setIsExcelDownClick(false); }, 1000); // 약간의 지연을 두고 다운로드 실행 return () => clearTimeout(timer); }, [excelList, isExcelDownClick]); diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 41b541ce9..fca74757c 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -93,8 +93,9 @@ export default function PlanSewage() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); const [initTrigger, setInitTrigger] = useState<boolean>(false); + // 엑셀다운로드 트리거 + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const [excelTrigger, setExcelTrigger] = useState<boolean>(false); /** * 페이지 함수 */ @@ -119,17 +120,24 @@ export default function PlanSewage() { } useEffect(() => { - if (!excelTrigger) return; + if (!isExcelDownClick) return; - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '계획하수량 산정지표 현황', - sheetNameArray: ['계획하수량 산정지표 현황'], - headerRange: 'A1:M1' - }); - } - }, [excelList, excelTrigger]); + const timer = setTimeout(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '계획하수량 산정지표 현황', + sheetNameArray: ['계획하수량 산정지표 현황'], + headerRange: 'A1:M1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + }, 500); + + return () => clearTimeout(timer); + }, [excelList, isExcelDownClick]); /** * 콜백함수 @@ -201,7 +209,7 @@ export default function PlanSewage() { } searchPlanSewage(searchReturn, 1, 10000); - setExcelTrigger(true); + setIsExcelDownClick(true); }, [searchPlanSewage]); // 페이지 변경 diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 371a1262d..00ce67077 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -70,6 +70,8 @@ export default function ProcessArea() { const [resetPage, setResetPage] = useState<boolean>(false); const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear); + + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); const ref = useRef<ReturnType>({ partValue: '', @@ -126,15 +128,23 @@ export default function ProcessArea() { }, [isInit, initializeCommonData, searchProcessAreaList, defaultSearchYear]); useEffect(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '처리구역정보', - sheetNameArray: ['처리구역정보'], - headerRange: 'A1:W1' - }); - } - }, [excelList]); + if(!isExcelDownClick) return; + + const timer = setTimeout(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '처리구역정보', + sheetNameArray: ['처리구역정보'], + headerRange: 'A1:W1' + }); + } else { + alert('조회된 결과가 없습니다.'); + } + setIsExcelDownClick(false); + }, 500); // 약간의 지연을 두고 다운로드 실행 + return () => clearTimeout(timer); + }, [excelList, isExcelDownClick]); const excelDownload = useCallback(() => { // if (ref.current.partValue === 'A') { // 행정별 @@ -155,6 +165,7 @@ export default function ProcessArea() { // } searchProcessArea(ref.current, 1, 10000); + setIsExcelDownClick(true); }, [searchProcessArea]); const handlePageChange = useCallback((pageNo: number) => { diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 9a6535db1..fdc70433e 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -89,6 +89,7 @@ export default function ProcessFacilitySearch() { const [partValue, setPartValue] = useState<string>("A"); // const [widthSize, setWidthSize] = useState<string>("w-[120%]"); const [upHeadList, setUpheadList] = useState(upHeadList1); + const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); /** * 모달 상태 변수 @@ -150,10 +151,18 @@ export default function ProcessFacilitySearch() { }, [partValue, upHeadList1, upHeadList2, upHeadList3]); useEffect(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); - } - }, [excelList]); + if(!isExcelDownClick) return; + + const timer = setTimeout(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); + } else { + alert('조회된 결과가 없습니다.'); + } + setIsExcelDownClick(false); + }, 500); // 약간의 지연을 두고 다운로드 실행 + return () => clearTimeout(timer); + }, [excelList, isExcelDownClick]); const searchFcltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => { let nameCd, partStr @@ -254,6 +263,7 @@ export default function ProcessFacilitySearch() { // } searchFcltyList(ref.current, 1, 10000); + setIsExcelDownClick(true); }, [searchFcltyList]); // 모달 닫기 diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 63df65e13..03d4017bc 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -120,16 +120,22 @@ export default function Rdi() { useEffect(() => { if(!isExcelDownClick) return ; - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: 'RDII추정', - sheetNameArray: ['RDII추정'], - headerRange: 'A1:R1' - }); - } else { - alert("조회된 결과가 없습니다."); - } + + const timer = setTimeout(() => { + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: 'RDII추정', + sheetNameArray: ['RDII추정'], + headerRange: 'A1:R1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + }, 500); // 약간의 지연을 두고 다운로드 실행 + + return () => clearTimeout(timer); }, [excelList, isExcelDownClick]); /** diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index a7ff0df71..4d3578314 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -162,6 +162,7 @@ export default function PlanSewage() { } else { alert("조회된 결과가 없습니다."); } + setIsExcelDownClick(false); }, 500); // 약간의 지연을 두고 다운로드 실행 return () => clearTimeout(timer); diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 849689312..d03053520 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -167,6 +167,7 @@ export default function UnderWaterInput() { } else { alert("조회된 결과가 없습니다."); } + setIsExcelDownClick(false); }, 1000); // 약간의 지연을 두고 다운로드 실행 return () => clearTimeout(timer); }, [excelList, isExcelDownClick]); From 1aaa8fcd6b10b7411ae5365d91e0c3e6435b605a Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Thu, 29 Jan 2026 21:25:40 +0900 Subject: [PATCH 72/92] =?UTF-8?q?fo:=20pagination=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/store/facilityWaterQlty/index.tsx | 26 ++++++++----- apps/fo/app/store/flowRate/index.tsx | 37 +++++++++++-------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index 4a08b429a..1a3508597 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -466,16 +466,22 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions //--------- const waterQltyList: any[] = []; let recordCount = 0; - for (let idx = 0; idx < pageSize; idx += 100) { - const tmpPageNo = Math.floor(idx / 100) + 1; - const tmpPageSize = Math.min(100, pageSize - idx); - const result = await fetchFacilityWaterQltyList(tmpPageNo, tmpPageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); - if (result?.status === 200 && Array.isArray(result?.data)) { - waterQltyList.push(...result.data); - } - recordCount = result?.count || 0; - if (result?.count < tmpPageNo * tmpPageSize) { - break; // 더 이상 데이터가 없으면 중지 + if (pageSize < 5000) { + const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + waterQltyList.push(...res.data); + recordCount = res.count; + } else { + for (let idx = 0; idx < pageSize; idx += 100) { + const tmpPageNo = Math.floor(idx / 100) + 1; + const tmpPageSize = Math.min(100, pageSize - idx); + const result = await fetchFacilityWaterQltyList(tmpPageNo, tmpPageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm); + if (result?.status === 200 && Array.isArray(result?.data)) { + waterQltyList.push(...result.data); + } + recordCount = result?.count || 0; + if (result?.count < tmpPageNo * tmpPageSize) { + break; // 더 이상 데이터가 없으면 중지 + } } } //------- diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 232755c1d..9bca32518 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -285,23 +285,30 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl //--------- const flowRateList: any[] = []; const results: any[] = []; - for (let idx = 0; idx < pageSize; idx += 100) { - const tmpPageNo = Math.floor(idx / 100) + 1; - const tmpPageSize = Math.min(100, pageSize - idx); - const result = await fetchFlowRateList( tmpPageNo, tmpPageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); - results.push(result); - if (result?.count < tmpPageNo * tmpPageSize) { - break; // 더 이상 데이터가 없으면 중지 - } - } - console.log(results); - // 결과를 합치기 - - for (const res of results) { - if (res?.status === 200 && Array.isArray(res?.data)) { - flowRateList.push(...res.data); + if (pageSize < 5000) { + const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + flowRateList.push(...res.data); + results.push(res); + } else { + for (let idx = 0; idx < pageSize; idx += 100) { + const tmpPageNo = Math.floor(idx / 100) + 1; + const tmpPageSize = Math.min(100, pageSize - idx); + const result = await fetchFlowRateList( tmpPageNo, tmpPageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm); + results.push(result); + if (result?.count < tmpPageNo * tmpPageSize) { + break; // 더 이상 데이터가 없으면 중지 + } + } + // console.log(results); + // 결과를 합치기 + + for (const res of results) { + if (res?.status === 200 && Array.isArray(res?.data)) { + flowRateList.push(...res.data); + } } } + //--------- const recordCount = results[0]?.count || 0; //------- From 39fb1d974abbdb57fffbfd92695b0ff00b98184d Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 30 Jan 2026 10:39:41 +0900 Subject: [PATCH 73/92] =?UTF-8?q?fo:=20excel=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/page.tsx | 39 +++++++++------ .../(with-layout)/facilityWaterQlty/page.tsx | 48 +++++++++++-------- .../app/pages/(with-layout)/flowRate/page.tsx | 29 +++++++---- .../pages/(with-layout)/planSewage/page.tsx | 40 +++++++++------- .../pages/(with-layout)/processArea/page.tsx | 39 +++++++++------ .../(with-layout)/processFacility/page.tsx | 33 ++++++++----- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 38 +++++++++------ .../pages/(with-layout)/sewageOccur/page.tsx | 41 +++++++++------- .../(with-layout)/underWaterInput/page.tsx | 42 +++++++++------- apps/fo/app/store/processFacility/index.tsx | 4 +- 10 files changed, 217 insertions(+), 136 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 4df912186..42dbb1be1 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -98,6 +98,7 @@ export default function FacilityPrecipitation() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 */ @@ -147,21 +148,28 @@ export default function FacilityPrecipitation() { useEffect(() => { if (!isExcelDownClick) return; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '시설별 강수현황', - sheetNameArray: ['시설별 강수현황'], - headerRange: 'A1:N1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - }, 500); - return () => clearTimeout(timer); - }, [excelList]); + if (isLoading) { + excelWaitRef.current = true; + return; + } + + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '시설별 강수현황', + sheetNameArray: ['시설별 강수현황'], + headerRange: 'A1:N1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); useEffect(() => { if (facilityPrecipitation.length > 0) { @@ -221,6 +229,7 @@ export default function FacilityPrecipitation() { // return; // } // } + excelWaitRef.current = false; searchFacilityPrecipitation(searchReturn, 1, 10000); setIsExcelDownClick(true); }, [searchFacilityPrecipitation]); diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 1df3be0cd..316ea78a1 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -56,6 +56,7 @@ export default function ProcessFacilitySearch() { const [initTrigger, setInitTrigger] = useState<boolean>(false); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); // 그리드 관련 const [resetPage, setResetPage] = useState<boolean>(false); const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); @@ -155,26 +156,32 @@ export default function ProcessFacilitySearch() { useEffect(() => { if (!isExcelDownClick) return; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcelFormat( - { - data: excelList as unknown as JSON[], - fileName: '시설별 수질현황', - sheetNameArray: ['시설별 수질현황'], - headerRange: 'A1:T1', - decimalArray1: [10, 11, 12, 15, 16, 17], - decimalArray3: [13, 14, 18, 19] - } - ); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - }, 500); + if (isLoading) { + excelWaitRef.current = true; + return; + } - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcelFormat( + { + data: excelList as unknown as JSON[], + fileName: '시설별 수질현황', + sheetNameArray: ['시설별 수질현황'], + headerRange: 'A1:T1', + decimalArray1: [10, 11, 12, 15, 16, 17], + decimalArray3: [13, 14, 18, 19] + } + ); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); const chkVal = useCallback((returntype: ReturnType) => { // setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") @@ -200,8 +207,9 @@ export default function ProcessFacilitySearch() { } } - setIsExcelDownClick(true); + excelWaitRef.current = false; searchFcltyQltyList(ref.current, 1, 10000); + setIsExcelDownClick(true); }, [searchFcltyQltyList]); const handlePageChange = useCallback((page: number) => { diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index 66b8c990d..527c8d45e 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -73,6 +73,7 @@ export default function ProcessFacilitySearch() { const [fcltyNm, setFcltyNm] = useState<string>(""); const [fcltyCd, setFcltyCd] = useState<string>(""); const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); const [initTrigger, setInitTrigger] = useState<boolean>(false); const searchFlowRate = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { @@ -154,16 +155,23 @@ export default function ProcessFacilitySearch() { useEffect(() => { if(!isExcelDownClick) return; - const timer = setTimeout(() => { - 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 { - alert('조회된 결과가 없습니다.'); - } - setIsExcelDownClick(false); - }, 1000); // 약간의 지연을 두고 다운로드 실행 - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (isLoading) { + excelWaitRef.current = true; + return; + } + + if (!excelWaitRef.current) { + 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 { + alert('조회된 결과가 없습니다.'); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); const ref = useRef<ReturnType>({ partValue: '', @@ -201,6 +209,7 @@ export default function ProcessFacilitySearch() { } } + excelWaitRef.current = false; searchFlowRate(ref.current, 1, 10000); setIsExcelDownClick(true); }, [searchFlowRate]); diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index fca74757c..3ad19c1bb 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -95,6 +95,7 @@ export default function PlanSewage() { const [initTrigger, setInitTrigger] = useState<boolean>(false); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 @@ -122,22 +123,28 @@ export default function PlanSewage() { useEffect(() => { if (!isExcelDownClick) return; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '계획하수량 산정지표 현황', - sheetNameArray: ['계획하수량 산정지표 현황'], - headerRange: 'A1:M1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - }, 500); - - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (isLoading) { + excelWaitRef.current = true; + return; + } + + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '계획하수량 산정지표 현황', + sheetNameArray: ['계획하수량 산정지표 현황'], + headerRange: 'A1:M1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); /** * 콜백함수 @@ -208,6 +215,7 @@ export default function PlanSewage() { } } + excelWaitRef.current = false; searchPlanSewage(searchReturn, 1, 10000); setIsExcelDownClick(true); }, [searchPlanSewage]); diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 00ce67077..d4fb0e973 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -72,6 +72,7 @@ export default function ProcessArea() { const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear); const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); const ref = useRef<ReturnType>({ partValue: '', @@ -130,21 +131,28 @@ export default function ProcessArea() { useEffect(() => { if(!isExcelDownClick) return; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '처리구역정보', - sheetNameArray: ['처리구역정보'], - headerRange: 'A1:W1' - }); - } else { - alert('조회된 결과가 없습니다.'); - } - setIsExcelDownClick(false); - }, 500); // 약간의 지연을 두고 다운로드 실행 - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (isLoading) { + excelWaitRef.current = true; + return; + } + + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '처리구역정보', + sheetNameArray: ['처리구역정보'], + headerRange: 'A1:W1' + }); + } else { + alert('조회된 결과가 없습니다.'); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); const excelDownload = useCallback(() => { // if (ref.current.partValue === 'A') { // 행정별 @@ -164,6 +172,7 @@ export default function ProcessArea() { // } // } + excelWaitRef.current = false; searchProcessArea(ref.current, 1, 10000); setIsExcelDownClick(true); }, [searchProcessArea]); diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index fdc70433e..995f2e8e9 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -90,6 +90,7 @@ export default function ProcessFacilitySearch() { // const [widthSize, setWidthSize] = useState<string>("w-[120%]"); const [upHeadList, setUpheadList] = useState(upHeadList1); const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); /** * 모달 상태 변수 @@ -151,18 +152,25 @@ export default function ProcessFacilitySearch() { }, [partValue, upHeadList1, upHeadList2, upHeadList3]); useEffect(() => { - if(!isExcelDownClick) return; + if (!isExcelDownClick) return; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); - } else { - alert('조회된 결과가 없습니다.'); - } - setIsExcelDownClick(false); - }, 500); // 약간의 지연을 두고 다운로드 실행 - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (isLoading) { + excelWaitRef.current = true; + return; + } + + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); + } else { + alert('조회된 결과가 없습니다.'); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); const searchFcltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => { let nameCd, partStr @@ -262,6 +270,7 @@ export default function ProcessFacilitySearch() { // } // } + excelWaitRef.current = false; searchFcltyList(ref.current, 1, 10000); setIsExcelDownClick(true); }, [searchFcltyList]); @@ -326,4 +335,4 @@ export default function ProcessFacilitySearch() { )} </MainDiv> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 03d4017bc..8f601c299 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -91,6 +91,7 @@ export default function Rdi() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀 다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); const [initTrigger, setInitTrigger] = useState<boolean>(false); @@ -121,22 +122,28 @@ export default function Rdi() { useEffect(() => { if(!isExcelDownClick) return ; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: 'RDII추정', - sheetNameArray: ['RDII추정'], - headerRange: 'A1:R1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - }, 500); // 약간의 지연을 두고 다운로드 실행 + if (isLoading) { + excelWaitRef.current = true; + return; + } - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: 'RDII추정', + sheetNameArray: ['RDII추정'], + headerRange: 'A1:R1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); /** * 콜백함수 @@ -206,6 +213,7 @@ export default function Rdi() { // } // } + excelWaitRef.current = false; searchRdi(ref.current, 1, 5000); setIsExcelDownClick(true); }, [searchRdi]); diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index 4d3578314..a9e990e82 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -101,6 +101,7 @@ export default function PlanSewage() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 @@ -151,22 +152,28 @@ export default function PlanSewage() { useEffect(() => { if(!isExcelDownClick) return ; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '오수발생량 추정', - sheetNameArray: ['오수발생량 추정'], - headerRange: 'A1:O1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - }, 500); // 약간의 지연을 두고 다운로드 실행 + if (isLoading) { + excelWaitRef.current = true; + return; + } - return () => clearTimeout(timer); - }, [excelList, isInit, isExcelDownClick]); + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '오수발생량 추정', + sheetNameArray: ['오수발생량 추정'], + headerRange: 'A1:O1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); /** * 콜백함수 @@ -190,7 +197,8 @@ export default function PlanSewage() { break; } if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { - searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue + , fcltyName.trim() !== ""? fcltyName : undefined); } else { searchSewageOccurList(pageNo, pageCnt, searchYear); } @@ -220,6 +228,7 @@ export default function PlanSewage() { return; } } + excelWaitRef.current = false; searchFacilityPrecipitation(ref.current, 1, 5000); setIsExcelDownClick(true); }, [searchFacilityPrecipitation]); diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index d03053520..1b90b4584 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -106,6 +106,7 @@ export default function UnderWaterInput() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); + const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 @@ -156,21 +157,28 @@ export default function UnderWaterInput() { useEffect(() => { if(!isExcelDownClick) return ; - const timer = setTimeout(() => { - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '지하수유입량 추정', - sheetNameArray: ['지하수유입량 추정'], - headerRange: 'A1:O1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - }, 1000); // 약간의 지연을 두고 다운로드 실행 - return () => clearTimeout(timer); - }, [excelList, isExcelDownClick]); + if (isLoading) { + excelWaitRef.current = true; + return; + } + + if (!excelWaitRef.current) { + return; + } + + if (excelList && excelList.length > 0) { + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '지하수유입량 추정', + sheetNameArray: ['지하수유입량 추정'], + headerRange: 'A1:O1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + setIsExcelDownClick(false); + excelWaitRef.current = false; + }, [excelList, isExcelDownClick, isLoading]); /** * 콜백함수 @@ -194,7 +202,8 @@ export default function UnderWaterInput() { break; } 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); + searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue + , fcltyName.trim() !== ""? fcltyName : undefined); } else { searchUnderWaterList(pageNo, pageCnt, searchYear); } @@ -224,6 +233,7 @@ export default function UnderWaterInput() { return; } } + excelWaitRef.current = false; searchFacilityPrecipitation(ref.current, 1, 5000); setIsExcelDownClick(true); }, [searchFacilityPrecipitation]); diff --git a/apps/fo/app/store/processFacility/index.tsx b/apps/fo/app/store/processFacility/index.tsx index 8fa38e5bc..240ad2d4d 100644 --- a/apps/fo/app/store/processFacility/index.tsx +++ b/apps/fo/app/store/processFacility/index.tsx @@ -418,7 +418,9 @@ const gridListFcltyWaterQltyInfo: fcltyWaterQltyInfoProps[] = [ */ export const fetchFacilityListInit = 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 : '') : ''; + const tailStr = partValue ? '/' + (partValue === 'G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + + (facilityPartValue && facilityPartValue !== ''? '/' + facilityPartValue : '') + + (facilityName && facilityName !== ''? '/' + facilityName : '') : ''; const url = '/prcsFclt/info/' + pageNo + '/' + pageSize + tailStr; const res = await getFetch('fo', url); res.data.forEach((item: Record<string, unknown>) => { From 164fc1388e73a26a670c183f9ef097b16d79c5f6 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 30 Jan 2026 16:22:51 +0900 Subject: [PATCH 74/92] =?UTF-8?q?fo:=20=EA=B0=95=EC=9A=B0=EC=8B=9C=20?= =?UTF-8?q?=EA=B0=95=EC=9A=B0=EC=9D=BC=EC=9D=98=20=EA=B0=95=EC=9A=B0?= =?UTF-8?q?=EB=9F=89=EC=97=90=20=EC=9D=8C=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/common/CalcRainEffect.tsx | 12 +-- .../(with-layout)/flowRate/modal/page.tsx | 32 +++++-- apps/fo/app/store/facilityWaterQlty/index.tsx | 28 +++--- apps/fo/app/store/underWaterInput/index.tsx | 10 +- .../src/ui/table/index.tsx | 92 ++++++++++--------- 5 files changed, 104 insertions(+), 70 deletions(-) diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index 3ea198016..898bea0ba 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -30,18 +30,18 @@ export default function CalcRainEffect(data: any, weather = 'ALL') { rtnDataSunny.push(item); } else if (rainEffectStd >= 0) { // 강우일 + 강우영향일 item.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; } } + 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; + } + } rtnDataRain.push(item); } 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 4e0fffeb5..c92fb4325 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -34,6 +34,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const { btnClass } = Common; const [copyYearList, setCopyYearList] = useState<FlowRateModalInterface[]>([]); const [isLoading, setIsLoading] = useState(true); + const [activeTab, setActiveTab] = useState<string>("tab_term_year"); const prevExcelListRef = useRef<modalExcelType[] | null>(null); const { modalFlowRateListYear, upHeadListFlowRateModalYear, } = FlowRateModal; @@ -183,10 +184,6 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st fetchData(); }, [props.facilityCd, props.searchYear, searchFlowRateModalList]); - if (isLoading) { - return <div>로딩 중...</div>; - } - const excelDownload = () => { const excelDownList: modalExcelType[] = []; if (copyYearList.length > 0) { @@ -206,14 +203,32 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st if (excelDownList && excelDownList.length > 0) { 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('다운받을 데이터가 없습니다.'); + alert('조회된 결과가 없습니다.'); } prevExcelListRef.current = excelDownList; } + const rainCellClassName = useCallback( + (row: FlowRateModalInterface, headId: string, rowIndex: number) => { + if (activeTab !== "tab_term_rain") return ""; + if (headId !== "infoRnDay") return ""; + if (rowIndex < 3) return ""; + + const raw = row.infoRnDay; + const value = typeof raw === "string" ? Number(raw.replace(/,/g, "").trim()) : Number(raw); + if (!Number.isFinite(value)) return ""; + return value > 3 ? "bg-red-50 font-semibold" : ""; + }, + [activeTab], + ); + + if (isLoading) { + return <div>로딩 중...</div>; + } + return ( <> - <UITab tabList={tabList} defaultValue="tab_term_year"> + <UITab tabList={tabList} defaultValue="tab_term_year" onValueChange={setActiveTab}> <Button className={btnClass} style={{ float: 'right' }} color="green" onClick={excelDownload}> {"엑셀다운로드"} </Button> @@ -337,7 +352,8 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st /> <div className="h-[370px] overflow-y-auto overflow-x-hidden"> <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} - cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} /> + cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} + cellClassName={rainCellClassName} /> </div> <div className="mt-20"> <UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)", "강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} /> @@ -346,4 +362,4 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st </UITab> </> ); -} \ No newline at end of file +} diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index 1a3508597..676c0624c 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -28,9 +28,11 @@ export interface FacilityRdiiDetailProps { export interface FacilityWaterQltyProps { bscFctCd: string, bscFctNm: string, - msrDt: string - sidoNm: string, - sggNm: string, + msrDt: string, + sido: string, + gugun: string, + // sidoNm: string, + // sggNm: string, addr: string, fctCpc: number, inflAssctBfrWqltBod: string | '', @@ -147,8 +149,8 @@ const mainLabelArray: string[] = ['구분', '시도', '시군구', '용량별', // 시설수질리스트 헤더(행정별) const upHeadList1: TableUpperProps[] = [ { id: "C", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 }, - { id: "sidoNm", title: "시도", row: 1, widthPercent: 5 }, - { id: "sggNm", title: "시군구", row: 1, widthPercent: 5 }, + { id: "sido", title: "시도", row: 1, widthPercent: 5 }, + { id: "gugun", title: "시군구", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", rowSpan: 2, row: 0, widthPercent: 10 }, { id: "addr", title: "주소", rowSpan: 2, row: 0 }, { id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0, widthPercent: 10 }, @@ -197,8 +199,8 @@ const upHeadList3: TableUpperProps[] = [ { id: "mdmbsn", title: "중권역", row: 1, widthPercent: 5 }, { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 7 }, { id: "D", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 }, - { id: "sidoNm", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, - { id: "sggNm", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "sido", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "gugun", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, { id: "addr", title: "주소", row: 0, rowSpan: 2 }, { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row: 0, rowSpan: 2, widthPercent: 5 }, @@ -533,8 +535,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions waterQltyList.forEach(item => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; - item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + // item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + // item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc; item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc; excelDownList.push({ @@ -543,8 +545,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions 단위유역: item.lgbsn, 중권역: item.mdmbsn, 환경청: item.rgnNm, - 시도: item.sidoNm, - 시군구: item.sggNm, + 시도: item.sido, + 시군구: item.gugun, 시설이름: item.bscFctNm, 주소: item.addr, "시설용량(m³/일)": CommaToNumber(item.fctCpc), @@ -565,8 +567,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions waterQltyList.forEach((item: FacilityWaterQltyProps) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; - item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + // item.sidoNm = item.; + // item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc; item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc; }); diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index d4d4c39e2..806b12e2b 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -317,6 +317,14 @@ export type UnderWaterStore = UnderWaterType & UnderWaterActions; export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => UnderWaterActions = (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { return { searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + set((state: UnderWaterType) => ({ + ...state, + UnderWater: { + ...state.UnderWater, + isLoading: true, + }, + })); + const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm); if (pageSize < 5000) { @@ -724,4 +732,4 @@ export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWater })) } } -} \ No newline at end of file +} diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index 1a0fc57c0..94c86d2d8 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -16,14 +16,15 @@ export type ChkClass = { chk: boolean; readonly: boolean; }; -type UiTableProps = { +type UiTableProps<T extends object> = { headName: React.ReactNode | undefined; - tableData: { [key: string]: any }[]; + tableData: T[]; headlist: UiHeadProps[]; pageSize: number; total: number; cellClick: ((index: number | undefined, headId: string) => void) | undefined; onPageChange: (page: number) => void; + cellClassName?: (row: T, headId: string, rowIndex: number) => string; className?: string; resetPageNo?: boolean; children?: React.ReactNode | undefined; @@ -46,7 +47,7 @@ type UiHeadProps = { colSpan?: number; }; -export function UiTable({ +export function UiTable<T extends object = Record<string, unknown>>({ tableData, headlist, pageSize, @@ -55,6 +56,7 @@ export function UiTable({ children, cellClick, onPageChange, + cellClassName, className = "", resetPageNo = false, boldArray = [], @@ -63,7 +65,7 @@ export function UiTable({ curPage = 1, headButton = undefined, widthFixed = false -}: UiTableProps) { +}: UiTableProps<T>) { const [cur, setCur] = useState<number>(curPage); const [idx, setIdx] = useState<number>(index); const [headerHeight, setHeaderHeight] = useState<number>(0); @@ -148,7 +150,7 @@ export function UiTable({ </TableHeader> <TableBody className="text-center"> {tableData.length > 0 ? ( - tableData?.map((el: Record<string, unknown>, index) => ( + tableData?.map((el: T, index) => ( <TableRow key={`row-${index}`}> {headlist .filter((item) => item.visible != false) @@ -163,29 +165,32 @@ export function UiTable({ : cellClick ? "cursor-pointer" : "" - } sticky top-20 z-40 bg-secondary !font-bold whitespace-pre-line`} + } ${cellClassName ? cellClassName(el, head.id, index) : ""} sticky top-20 z-40 bg-secondary !font-bold whitespace-pre-line`} style={{ top: `${headerHeight + index * 32 - 4}px` }} onClick={() => handleCellClick(index, head.id)} key={`cell-${head.id}-${index}`} > - {typeof el[head.id] !== "number" - ? String(el[head.id] ?? "") - : String(el[head.id]).includes(".") - ? String(el[head.id]) - .split(".") - .map((part, index) => - index === 0 - ? part.replace( - /\B(?=(\d{3})+(?!\d))/g, - ",", - ) - : part, - ) - .join(".") - : String(el[head.id] ?? "").replace( - /\B(?=(\d{3})+(?!\d))/g, - ",", - )} + {(() => { + const cellValue = (el as Record<string, unknown>)[head.id]; + return typeof cellValue !== "number" + ? String(cellValue ?? "") + : String(cellValue).includes(".") + ? String(cellValue) + .split(".") + .map((part, index) => + index === 0 + ? part.replace( + /\B(?=(\d{3})+(?!\d))/g, + ",", + ) + : part, + ) + .join(".") + : String(cellValue ?? "").replace( + /\B(?=(\d{3})+(?!\d))/g, + ",", + ); + })()} </TableCell> ) : ( <TableCell @@ -194,47 +199,49 @@ export function UiTable({ : cellClick ? "cursor-pointer" : "" - } mt-[${boldArray.length * 40}px] whitespace-pre-line`} + } ${cellClassName ? cellClassName(el, head.id, index) : ""} mt-[${boldArray.length * 40}px] whitespace-pre-line`} onClick={() => handleCellClick(index, head.id)} key={`cell-${head.id}-${index}`} > { //체크박스 유형애서 readOnly가 필요한 경우를 위해서 ChkClass 를 사용해서 readOnly 처리함. - typeof el[head.id] === "object" && - el[head.id] !== null && - "chk" in (el[head.id] as object) && - "readonly" in (el[head.id] as object) ? ( + (() => { + const cellValue = (el as Record<string, unknown>)[head.id]; + return typeof cellValue === "object" && + cellValue !== null && + "chk" in (cellValue as object) && + "readonly" in (cellValue as object) ? ( <Checkbox checked={ - (el[head.id] as ChkClass)?.chk === true + (cellValue as ChkClass)?.chk === true } onCheckedChange={(checked) => { { - console.log(el[head.id]); + console.log(cellValue); } if ( - (el[head.id] as ChkClass).readonly == true + (cellValue as ChkClass).readonly == true ) return; - (el[head.id] as ChkClass).chk = + (cellValue as ChkClass).chk = Boolean(checked); }} > <Check className="h-6 w-6 text-primary" /> </Checkbox> - ) : typeof el[head.id] === "boolean" ? ( + ) : typeof cellValue === "boolean" ? ( <Checkbox - checked={el[head.id] === true} + checked={cellValue === true} onCheckedChange={(checked) => { - el[head.id] = checked; + (el as Record<string, unknown>)[head.id] = checked; }} > <Check className="h-6 w-6 text-primary" /> </Checkbox> - ) : typeof el[head.id] !== "number" ? ( - String(el[head.id] ?? "") - ) : String(el[head.id]).includes(".") ? ( - String(el[head.id]) + ) : typeof cellValue !== "number" ? ( + String(cellValue ?? "") + ) : String(cellValue).includes(".") ? ( + String(cellValue) .split(".") .map((part, index) => index === 0 @@ -246,11 +253,12 @@ export function UiTable({ ) .join(".") ) : ( - String(el[head.id] ?? "").replace( + String(cellValue ?? "").replace( /\B(?=(\d{3})+(?!\d))/g, ",", ) - ) + ); + })() } </TableCell> )), From c6cfedb28b36dba4646f2a2b565282a51e285f5d Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Fri, 30 Jan 2026 18:14:30 +0900 Subject: [PATCH 75/92] =?UTF-8?q?fo:=20=EC=9C=A0=EB=9F=89=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=ED=8C=9D=EC=97=85=20=EA=B0=95=EC=9A=B0=EC=8B=9C=20?= =?UTF-8?q?=EA=B0=95=EC=9A=B0=EC=9D=BC=20=EC=9D=8C=EC=98=81=ED=91=9C?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityWaterQlty/modal/page.tsx | 4 +++- .../(with-layout)/flowRate/modal/page.tsx | 23 +++++++++++++++---- apps/fo/app/store/flowRate/index.tsx | 4 ++-- .../src/ui/table/index.tsx | 4 +++- 4 files changed, 26 insertions(+), 9 deletions(-) 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 470a44e4c..c1a6afdf8 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx @@ -447,7 +447,9 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea </div> <div className="card-header border-t mt-1"> <h3 className="text-2xl font-medium text-label">수질 TMS</h3> - <h3 className="text-2xl font-medium text-label text-right">({msrmtDate ? msrmtDate.substring(0, 4) + '-' + msrmtDate.substring(4, 6) + '-' + msrmtDate.substring(6, 8) : yesterDayStr})</h3> + <h3 className="text-2xl font-medium text-label text-right"> + ({msrmtDate ? msrmtDate.substring(0, 4) + '-' + msrmtDate.substring(4, 6) + '-' + msrmtDate.substring(6, 8) : yesterDayStr}) + </h3> </div> <div className="overflow-y-auto h-[250px]"> <UiTable 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 c92fb4325..b214e0a48 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -208,16 +208,29 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st prevExcelListRef.current = excelDownList; } - const rainCellClassName = useCallback( - (row: FlowRateModalInterface, headId: string, rowIndex: number) => { + // const rainCellClassName = useCallback( + // (row: FlowRateModalInterface, headId: string, rowIndex: number) => { + // if (activeTab !== "tab_term_rain") return ""; + // if (headId !== "infoRnDay") return ""; + // if (rowIndex < 3) return ""; + + // const raw = row.infoRnDay; + // const value = typeof raw === "string" ? Number(raw.replace(/,/g, "").trim()) : Number(raw); + // if (!Number.isFinite(value)) return ""; + // return value > 3 ? "bg-red-50 font-semibold" : ""; + // }, + // [activeTab], + // ); + + const rainRowClassName = useCallback( + (row: FlowRateModalInterface, rowIndex: number) => { if (activeTab !== "tab_term_rain") return ""; - if (headId !== "infoRnDay") return ""; if (rowIndex < 3) return ""; const raw = row.infoRnDay; const value = typeof raw === "string" ? Number(raw.replace(/,/g, "").trim()) : Number(raw); if (!Number.isFinite(value)) return ""; - return value > 3 ? "bg-red-50 font-semibold" : ""; + return value > 3 ? "bg-slate-50" : ""; }, [activeTab], ); @@ -353,7 +366,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st <div className="h-[370px] overflow-y-auto overflow-x-hidden"> <UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} - cellClassName={rainCellClassName} /> + rowClassName={rainRowClassName} /> </div> <div className="mt-20"> <UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)", "강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} /> diff --git a/apps/fo/app/store/flowRate/index.tsx b/apps/fo/app/store/flowRate/index.tsx index 9bca32518..b097fc234 100644 --- a/apps/fo/app/store/flowRate/index.tsx +++ b/apps/fo/app/store/flowRate/index.tsx @@ -388,7 +388,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl const yearSunnyAmnt = sunnyDay > 0 ? sunnyInflAmnt / sunnyDay : 0; // 청천시 연평균유입유량 const yearSunnyBod = sunnyDay > 0 ? sunnyBod / sunnyDay : 0; // 청천시 연평균유입BOD - console.log(inflData); + //console.log(inflData); const rtnData = inflData.map((item: FlowRateModalProps) => { const targetWqItem = wqltData?.find(wqitem => wqitem.msrDt === item.msrDt.replaceAll('-', '')); const dayBod = targetWqItem ? Number(targetWqItem.inflAssctBfrWqltBod) : 0; @@ -404,7 +404,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl : item.msrDt, }; }); - console.log(rtnData); + //console.log(rtnData); set((state: FlowRateSearchType) => ({ ...state, FlowRateModal: { diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index 94c86d2d8..d2fd81de6 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -25,6 +25,7 @@ type UiTableProps<T extends object> = { cellClick: ((index: number | undefined, headId: string) => void) | undefined; onPageChange: (page: number) => void; cellClassName?: (row: T, headId: string, rowIndex: number) => string; + rowClassName?: (row: T, rowIndex: number) => string; className?: string; resetPageNo?: boolean; children?: React.ReactNode | undefined; @@ -57,6 +58,7 @@ export function UiTable<T extends object = Record<string, unknown>>({ cellClick, onPageChange, cellClassName, + rowClassName, className = "", resetPageNo = false, boldArray = [], @@ -151,7 +153,7 @@ export function UiTable<T extends object = Record<string, unknown>>({ <TableBody className="text-center"> {tableData.length > 0 ? ( tableData?.map((el: T, index) => ( - <TableRow key={`row-${index}`}> + <TableRow key={`row-${index}`} className={rowClassName ? rowClassName(el, index) : ""}> {headlist .filter((item) => item.visible != false) .map( From 85615a826e42da53570f4d755041d80ac5755acb Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Sat, 31 Jan 2026 16:05:21 +0900 Subject: [PATCH 76/92] =?UTF-8?q?fo:=20exceldown=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/page.tsx | 67 ++++++++-------- .../(with-layout)/facilityWaterQlty/page.tsx | 76 +++++++++---------- .../app/pages/(with-layout)/flowRate/page.tsx | 58 ++++++-------- .../pages/(with-layout)/planSewage/page.tsx | 68 ++++++++--------- .../pages/(with-layout)/processArea/page.tsx | 65 +++++++--------- .../(with-layout)/processFacility/page.tsx | 55 ++++++-------- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 68 ++++++++--------- .../pages/(with-layout)/sewageOccur/page.tsx | 70 ++++++++--------- .../(with-layout)/underWaterInput/page.tsx | 67 ++++++++-------- .../src/ui/search_base_form/index.tsx | 6 +- 10 files changed, 267 insertions(+), 333 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 42dbb1be1..7fd141694 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -5,11 +5,11 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import PrecipitationModal from "./modal/page"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; import UnderComment from "@/app/components/common/UnderComment"; @@ -22,6 +22,11 @@ export default function FacilityPrecipitation() { ,initializeCommonData ,searchFacilityPrecipitationList } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }}; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -50,7 +55,6 @@ export default function FacilityPrecipitation() { upHeadList1, upHeadList2, upHeadList3, - excelList, facilityPrecipitation, facilityPrecipitationCount, isLoading, @@ -98,7 +102,6 @@ export default function FacilityPrecipitation() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 */ @@ -145,32 +148,6 @@ export default function FacilityPrecipitation() { } }, [isInit, initializeCommonData, searchFacilityPrecipitationList, defaultSearchYear]); - useEffect(() => { - if (!isExcelDownClick) return; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '시설별 강수현황', - sheetNameArray: ['시설별 강수현황'], - headerRange: 'A1:N1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - useEffect(() => { if (facilityPrecipitation.length > 0) { @@ -181,7 +158,7 @@ export default function FacilityPrecipitation() { * 콜백함수 */ // 조회 - const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchFacilityPrecipitation = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { let nameCd, partStr switch (partValue) { case 'R': @@ -199,9 +176,9 @@ export default function FacilityPrecipitation() { break; } if (partStr.length > 1 || operationValue!== '0' || fcltCpct !== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { - searchFacilityPrecipitationList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + await searchFacilityPrecipitationList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); } else { - searchFacilityPrecipitationList(pageNo, pageCnt, searchYear); + await searchFacilityPrecipitationList(pageNo, pageCnt, searchYear); } }, [operationValue, fcltyName, searchFacilityPrecipitationList, searchYear, fcltCpct]); @@ -212,7 +189,8 @@ export default function FacilityPrecipitation() { }, [upHeadList1, upHeadList2, upHeadList3]); // 엑셀다운로드 - const excelDownload = useCallback((searchReturn: ReturnType) => { + const excelDownload = useCallback(async (searchReturn: ReturnType) => { + if (isExcelDownClick) return; // if (ref.current.partValue === 'A') { // 행정별 // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -229,10 +207,24 @@ export default function FacilityPrecipitation() { // return; // } // } - excelWaitRef.current = false; - searchFacilityPrecipitation(searchReturn, 1, 10000); setIsExcelDownClick(true); - }, [searchFacilityPrecipitation]); + try { + await searchFacilityPrecipitation(searchReturn, 1, 10000); + const latestExcelList = store.getState().FacilityPrecipitation.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ + data: latestExcelList as unknown as JSON[], + fileName: '시설별 강수현황', + sheetNameArray: ['시설별 강수현황'], + headerRange: 'A1:N1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchFacilityPrecipitation, store]); // 페이지 변경 const handlePageChange = useCallback((page: number) => { @@ -267,6 +259,7 @@ export default function FacilityPrecipitation() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false}/> <ListDiv> diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 316ea78a1..265c9788f 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -6,13 +6,13 @@ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; import type { FacilityWaterQltyProps } from "@/app/store/facilityWaterQlty"; import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import WaterQualityModal from "./modal/page"; export default function ProcessFacilitySearch() { @@ -21,6 +21,11 @@ export default function ProcessFacilitySearch() { , initializeCommonData , searchFacilityWaterQltyList } = useFoStore((state) => state) || { FacilityWaterQltyList: { facilityWaterQltyList: [], facilityWaterQltyCount: 0 } }; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -48,7 +53,6 @@ export default function ProcessFacilitySearch() { upHeadList3, facilityWaterQltyList, facilityWaterQltyCount, - excelList, isLoading, } = FacilityWaterQltyMain; @@ -56,7 +60,6 @@ export default function ProcessFacilitySearch() { const [initTrigger, setInitTrigger] = useState<boolean>(false); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); // 그리드 관련 const [resetPage, setResetPage] = useState<boolean>(false); const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); @@ -73,7 +76,7 @@ export default function ProcessFacilitySearch() { const [fcltyCd, setFcltyCd] = useState<string>(""); const [modalYear, setModalYear] = useState<string>(""); - const searchFcltyQltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => { + const searchFcltyQltyList = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => { let nameCd, partStr; switch (partValue) { case 'R': @@ -91,9 +94,9 @@ export default function ProcessFacilitySearch() { break; } if (partStr === 'G') { - searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue); + await searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue); } else { - searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + await searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); } }, [operationValue, fcltyName, searchFacilityWaterQltyList, searchYearValue, fcltCpct]); @@ -153,43 +156,14 @@ export default function ProcessFacilitySearch() { } }, [isInit, initializeCommonData, searchFacilityWaterQltyList, searchFcltyQltyList, initTrigger]); - useEffect(() => { - if (!isExcelDownClick) return; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcelFormat( - { - data: excelList as unknown as JSON[], - fileName: '시설별 수질현황', - sheetNameArray: ['시설별 수질현황'], - headerRange: 'A1:T1', - decimalArray1: [10, 11, 12, 15, 16, 17], - decimalArray3: [13, 14, 18, 19] - } - ); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - const chkVal = useCallback((returntype: ReturnType) => { // setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]") setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G' ? upHeadList3 : upHeadList1); setResetPage(true); }, [upHeadList1, upHeadList2, upHeadList3]); - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; if (ref.current.partValue === 'A') { // 행정별 if (!ref.current.sidoValue || ref.current.sidoValue === '0') { alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -206,11 +180,28 @@ export default function ProcessFacilitySearch() { return; } } - - excelWaitRef.current = false; - searchFcltyQltyList(ref.current, 1, 10000); setIsExcelDownClick(true); - }, [searchFcltyQltyList]); + try { + await searchFcltyQltyList(ref.current, 1, 10000); + const latestExcelList = store.getState().FacilityWaterQltyMain.excelList || []; + if (latestExcelList.length > 0) { + downloadExcelFormat( + { + data: latestExcelList as unknown as JSON[], + fileName: '시설별 수질현황', + sheetNameArray: ['시설별 수질현황'], + headerRange: 'A1:T1', + decimalArray1: [10, 11, 12, 15, 16, 17], + decimalArray3: [13, 14, 18, 19] + } + ); + } else { + alert("조회된 결과가 없습니다."); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchFcltyQltyList, store]); const handlePageChange = useCallback((page: number) => { setResetPage(false); @@ -239,6 +230,7 @@ export default function ProcessFacilitySearch() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false} initSidoValue={"11"} /> <ListDiv> diff --git a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx index 527c8d45e..d83386dee 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/page.tsx @@ -5,13 +5,13 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; // import type { ExcelType } from "@/app/store/flowRate"; import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import FlowRateModal from "./modal/page"; export default function ProcessFacilitySearch() { @@ -21,6 +21,11 @@ export default function ProcessFacilitySearch() { ,initializeCommonData ,searchFlowRateList } = useFoStore((state) => state); + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null); @@ -54,7 +59,6 @@ export default function ProcessFacilitySearch() { upHeadList3, flowRateList, flowRateCount, - excelList, isLoading, } = FlowRateList; @@ -73,10 +77,9 @@ export default function ProcessFacilitySearch() { const [fcltyNm, setFcltyNm] = useState<string>(""); const [fcltyCd, setFcltyCd] = useState<string>(""); const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); const [initTrigger, setInitTrigger] = useState<boolean>(false); - const searchFlowRate = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchFlowRate = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { let nameCd, partStr; switch (partValue) { @@ -95,9 +98,9 @@ export default function ProcessFacilitySearch() { break; } if(partStr==='G'){ - searchFlowRateList(pageNo, pageCnt, searchYearValue); + await searchFlowRateList(pageNo, pageCnt, searchYearValue); }else{ - searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + await searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); } }, [searchFlowRateList, searchYearValue, fcltCpct, operationValue, fcltyName]); @@ -152,27 +155,6 @@ export default function ProcessFacilitySearch() { } }, [isInit, initializeCommonData, searchFlowRateList, selectSearchYear, searchFlowRate, initTrigger]); - useEffect(() => { - if(!isExcelDownClick) return; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - 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 { - alert('조회된 결과가 없습니다.'); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - const ref = useRef<ReturnType>({ partValue: '', sidoValue: '11', @@ -191,7 +173,8 @@ export default function ProcessFacilitySearch() { setResetPage(true); }, [upHeadList1, upHeadList2, upHeadList3]); - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; if (ref.current.partValue === 'A') { // 행정별 if (!ref.current.sidoValue || ref.current.sidoValue === '0') { alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -208,11 +191,19 @@ export default function ProcessFacilitySearch() { return; } } - - excelWaitRef.current = false; - searchFlowRate(ref.current, 1, 10000); setIsExcelDownClick(true); - }, [searchFlowRate]); + try { + await searchFlowRate(ref.current, 1, 10000); + const latestExcelList = store.getState().FlowRateList.excelList || []; + if (latestExcelList.length > 0) { + downloadExcelFormat({ data: JSON.parse(JSON.stringify(latestExcelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1', decimalArray0: [9,10,11,12,13,14] }); + } else { + alert('조회된 결과가 없습니다.'); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchFlowRate, store]); const total = flowRateCount; return ( @@ -237,6 +228,7 @@ export default function ProcessFacilitySearch() { queryClick={chkVal} excelClick={excelDownload} initClick={resetVal} + excelDisabled={isExcelDownClick} ref={ref} isAdmin={false} initSidoValue={'11'}/> <ListDiv> <LoadingOverlay isLoading={isLoading} /> diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 3ad19c1bb..8b41524d1 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -5,11 +5,11 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; import { downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; import UnderComment from "@/app/components/common/UnderComment"; @@ -26,6 +26,11 @@ export default function PlanSewage() { , initializeCommonData , searchPlanSewageList } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] } }; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -56,7 +61,6 @@ export default function PlanSewage() { upHeadList3, planSewageList, planSewageCount, - excelList, isLoading, } = PlanSewage; @@ -95,7 +99,6 @@ export default function PlanSewage() { const [initTrigger, setInitTrigger] = useState<boolean>(false); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 @@ -120,37 +123,11 @@ export default function PlanSewage() { searchPlanSewage(ref.current, 1, 10); } - useEffect(() => { - if (!isExcelDownClick) return; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '계획하수량 산정지표 현황', - sheetNameArray: ['계획하수량 산정지표 현황'], - headerRange: 'A1:M1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - /** * 콜백함수 */ // 조회 - const searchPlanSewage = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => { + const searchPlanSewage = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => { let nameCd, partStr switch (partValue) { case 'R': @@ -170,10 +147,10 @@ export default function PlanSewage() { if (partStr === 'G') { partValue = partValue === 'G' ? 'A' : partValue; - searchPlanSewageList(pageNo, pageCnt, searchYear, partValue); + await searchPlanSewageList(pageNo, pageCnt, searchYear, partValue); } else { - searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + await searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); } }, [operationValue, fcltyName, searchPlanSewageList, searchYear, fcltCpct]); @@ -197,7 +174,8 @@ export default function PlanSewage() { }, [upHeadList1, upHeadList2, upHeadList3]); // 엑셀다운로드 - const excelDownload = useCallback((searchReturn: ReturnType) => { + const excelDownload = useCallback(async (searchReturn: ReturnType) => { + if (isExcelDownClick) return; if (ref.current.partValue === 'A') { // 행정별 if (!ref.current.sidoValue || ref.current.sidoValue === '0') { alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -214,11 +192,24 @@ export default function PlanSewage() { return; } } - - excelWaitRef.current = false; - searchPlanSewage(searchReturn, 1, 10000); setIsExcelDownClick(true); - }, [searchPlanSewage]); + try { + await searchPlanSewage(searchReturn, 1, 10000); + const latestExcelList = store.getState().PlanSewage.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ + data: latestExcelList as unknown as JSON[], + fileName: '계획하수량 산정지표 현황', + sheetNameArray: ['계획하수량 산정지표 현황'], + headerRange: 'A1:M1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchPlanSewage, store]); // 페이지 변경 const handlePageChange = useCallback((page: number) => { @@ -249,6 +240,7 @@ export default function PlanSewage() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false} initSidoValue={"11"} /> <ListDiv> diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index d4fb0e973..84d8ee8b1 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -5,11 +5,11 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import { useShallow } from 'zustand/react/shallow'; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import ProcessFacilityInfoModal from "./modal/page"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; @@ -29,6 +29,11 @@ export default function ProcessArea() { searchProcessAreaList: state.searchProcessAreaList, })) ); + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -55,7 +60,6 @@ export default function ProcessArea() { upHeadList1, processAreaList, processAreaCount, - excelList, isLoading, } = ProcessArea; @@ -72,7 +76,6 @@ export default function ProcessArea() { const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear); const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); const ref = useRef<ReturnType>({ partValue: '', @@ -86,8 +89,8 @@ export default function ProcessArea() { sigunText: '', }); - const searchProcessArea = useCallback(({ sidoText, sigunText }: ReturnType, pageNo: number, pageCnt: number = 20) => { - searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue); + const searchProcessArea = useCallback(async ({ sidoText, sigunText }: ReturnType, pageNo: number, pageCnt: number = 20) => { + await searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue); }, [searchProcessAreaList, searchYearValue]); // 조회 @@ -128,33 +131,8 @@ export default function ProcessArea() { } }, [isInit, initializeCommonData, searchProcessAreaList, defaultSearchYear]); - useEffect(() => { - if(!isExcelDownClick) return; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '처리구역정보', - sheetNameArray: ['처리구역정보'], - headerRange: 'A1:W1' - }); - } else { - alert('조회된 결과가 없습니다.'); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; // if (ref.current.partValue === 'A') { // 행정별 // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -172,10 +150,24 @@ export default function ProcessArea() { // } // } - excelWaitRef.current = false; - searchProcessArea(ref.current, 1, 10000); setIsExcelDownClick(true); - }, [searchProcessArea]); + try { + await searchProcessArea(ref.current, 1, 10000); + const latestExcelList = store.getState().ProcessArea.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ + data: latestExcelList as unknown as JSON[], + fileName: '처리구역정보', + sheetNameArray: ['처리구역정보'], + headerRange: 'A1:W1' + }); + } else { + alert('조회된 결과가 없습니다.'); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchProcessArea, store]); const handlePageChange = useCallback((pageNo: number) => { setResetPage(false); @@ -201,6 +193,7 @@ export default function ProcessArea() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={true} diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 995f2e8e9..e73213bb1 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -6,11 +6,11 @@ "use client" import UnderComment from "@/app/components/common/UnderComment"; -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import ProcessFacilityInfoModal from "./modal/page"; export default function ProcessFacilitySearch() { @@ -25,6 +25,11 @@ export default function ProcessFacilitySearch() { //시설데이터 수질정보 조회 ,searchProcessFacilityWaterQlty } = useFoStore((state) => state) || { ProcessFacilityList: { processFacilityList: [], processFacilityCount: 0 }}; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -69,7 +74,6 @@ export default function ProcessFacilitySearch() { upHeadList1, upHeadList2, upHeadList3, - excelList, isLoading, } = ProcessFacilityList; @@ -90,7 +94,6 @@ export default function ProcessFacilitySearch() { // const [widthSize, setWidthSize] = useState<string>("w-[120%]"); const [upHeadList, setUpheadList] = useState(upHeadList1); const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); /** * 모달 상태 변수 @@ -151,28 +154,7 @@ export default function ProcessFacilitySearch() { } }, [partValue, upHeadList1, upHeadList2, upHeadList3]); - useEffect(() => { - if (!isExcelDownClick) return; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); - } else { - alert('조회된 결과가 없습니다.'); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - - const searchFcltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => { + const searchFcltyList = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => { let nameCd, partStr switch (partValue) { case 'R': @@ -189,7 +171,7 @@ export default function ProcessFacilitySearch() { partStr = envPartValue !== '0' ? envPartValue:partValue; break; } - searchProcessFacility(pageNo, pageCnt, partStr, nameCd || '0', fcltCpct, operationValue, facilityPartValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); + await searchProcessFacility(pageNo, pageCnt, partStr, nameCd || '0', fcltCpct, operationValue, facilityPartValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); if(isSearch) { setIsSearch(false); } @@ -252,7 +234,8 @@ export default function ProcessFacilitySearch() { } } - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; // if (ref.current.partValue === 'A') { // 행정별 // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -270,10 +253,19 @@ export default function ProcessFacilitySearch() { // } // } - excelWaitRef.current = false; - searchFcltyList(ref.current, 1, 10000); setIsExcelDownClick(true); - }, [searchFcltyList]); + try { + await searchFcltyList(ref.current, 1, 10000); + const latestExcelList = store.getState().ProcessFacilityList.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ data: latestExcelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); + } else { + alert('조회된 결과가 없습니다.'); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchFcltyList, store]); // 모달 닫기 const closeModal = () => { @@ -302,6 +294,7 @@ export default function ProcessFacilitySearch() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false} /> <ListDiv> diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 8f601c299..459cd44ca 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -5,11 +5,11 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; import UnderComment from "@/app/components/common/UnderComment"; @@ -26,6 +26,11 @@ export default function Rdi() { ,RdiSearch ,searchRdiList } = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }}; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -56,7 +61,6 @@ export default function Rdi() { upHeadList3, rdiList, rdiCount, - excelList, isLoading, } = Rdi; @@ -91,7 +95,6 @@ export default function Rdi() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀 다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); const [initTrigger, setInitTrigger] = useState<boolean>(false); @@ -119,37 +122,11 @@ export default function Rdi() { searchRdi(ref.current, 1, 10); } - useEffect(() => { - if(!isExcelDownClick) return ; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: 'RDII추정', - sheetNameArray: ['RDII추정'], - headerRange: 'A1:R1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - /** * 콜백함수 */ // 조회 - const searchRdi = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchRdi = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { let nameCd, partStr switch (partValue) { case 'R': @@ -168,10 +145,9 @@ export default function Rdi() { } if(partStr === 'G'){ - searchRdiList(pageNo, pageCnt, searchYear); + await searchRdiList(pageNo, pageCnt, searchYear); }else{ - searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); - + await searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined); } }, [operationValue, fcltyName, searchRdiList, searchYear, fcltCpct]); @@ -195,7 +171,8 @@ export default function Rdi() { }, [upHeadList1, upHeadList2, upHeadList3]); // 엑셀다운로드 - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; // if (ref.current.partValue === 'A') { // 행정별 // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { // alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -213,10 +190,24 @@ export default function Rdi() { // } // } - excelWaitRef.current = false; - searchRdi(ref.current, 1, 5000); setIsExcelDownClick(true); - }, [searchRdi]); + try { + await searchRdi(ref.current, 1, 5000); + const latestExcelList = store.getState().Rdi.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ + data: latestExcelList as unknown as JSON[], + fileName: 'RDII추정', + sheetNameArray: ['RDII추정'], + headerRange: 'A1:R1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchRdi, store]); // 페이지 변경 const handlePageChange = useCallback((page: number) => { @@ -248,6 +239,7 @@ export default function Rdi() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false} initSidoValue={"11"}/> <ListDiv> diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index a9e990e82..4dc3125d1 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -6,13 +6,13 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import { type TableUpperProps } from "@/app/store/common"; import type { SewageOccurProps } from "@/app/store/sewageOccur"; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, useEffect, useRef, useState } from "react"; import SewageOccurModal from "./modal/page"; export default function PlanSewage() { @@ -29,6 +29,11 @@ export default function PlanSewage() { searchSewageOccurList: () => {}, calculateModalDataForAllFacilities: async () => [] }; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -59,7 +64,6 @@ export default function PlanSewage() { upHeadList3, sewageOccurList, sewageOccurCount, - excelList, isLoading, } = SewageOccur; @@ -99,10 +103,8 @@ export default function PlanSewage() { const [operationValue, setOperationValue] = useState<string>("0"); // 조회기간 const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); - // 엑셀다운로드 트리거 + // 엑셀 조회 중 상태 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); - /** * 페이지 함수 */ @@ -149,37 +151,11 @@ export default function PlanSewage() { } }, [isInit, initializeCommonData, searchSewageOccurList, defaultSearchYear]); - useEffect(() => { - if(!isExcelDownClick) return ; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '오수발생량 추정', - sheetNameArray: ['오수발생량 추정'], - headerRange: 'A1:O1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - /** * 콜백함수 */ // 조회 - const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchFacilityPrecipitation = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { let nameCd, partStr switch (partValue) { case 'R': @@ -197,10 +173,10 @@ export default function PlanSewage() { break; } if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { - searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue + await searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue , fcltyName.trim() !== ""? fcltyName : undefined); } else { - searchSewageOccurList(pageNo, pageCnt, searchYear); + await searchSewageOccurList(pageNo, pageCnt, searchYear); } }, [fcltCpct, operationValue, fcltyName, searchSewageOccurList, searchYear]); @@ -211,7 +187,8 @@ export default function PlanSewage() { }, [upHeadList1, upHeadList2, upHeadList3]); // 엑셀다운로드 - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; if (ref.current.partValue === 'A') { // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -228,10 +205,24 @@ export default function PlanSewage() { return; } } - excelWaitRef.current = false; - searchFacilityPrecipitation(ref.current, 1, 5000); setIsExcelDownClick(true); - }, [searchFacilityPrecipitation]); + try { + await searchFacilityPrecipitation(ref.current, 1, 5000); + const latestExcelList = store.getState().SewageOccur.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ + data: latestExcelList as unknown as JSON[], + fileName: '오수발생량 추정', + sheetNameArray: ['오수발생량 추정'], + headerRange: 'A1:O1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchFacilityPrecipitation]); // 페이지 변경 const handlePageChange = useCallback((page: number) => { @@ -263,6 +254,7 @@ export default function PlanSewage() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false} diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 1b90b4584..4404403e3 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -7,11 +7,11 @@ */ "use client" -import { useFoStore } from "@/app/store"; +import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useContext, 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"; @@ -35,6 +35,11 @@ export default function UnderWaterInput() { initializeCommonData: () => {}, searchUnderWaterList: () => {} }; + const store = useContext(StoreContext); + + if (!store) { + throw new Error("StoreContext is not available. Ensure StoreProvider is mounted."); + } const { isInit, @@ -65,7 +70,6 @@ export default function UnderWaterInput() { upHeadList3, underWaterList, underWaterCount, - excelList, isLoading, } = UnderWater; @@ -106,7 +110,6 @@ export default function UnderWaterInput() { const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 엑셀다운로드 트리거 const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false); - const excelWaitRef = useRef<boolean>(false); /** * 페이지 함수 @@ -154,37 +157,11 @@ export default function UnderWaterInput() { } }, [isInit, initializeCommonData, searchUnderWaterList, defaultSearchYear]); - useEffect(() => { - if(!isExcelDownClick) return ; - - if (isLoading) { - excelWaitRef.current = true; - return; - } - - if (!excelWaitRef.current) { - return; - } - - if (excelList && excelList.length > 0) { - downloadExcel({ - data: excelList as unknown as JSON[], - fileName: '지하수유입량 추정', - sheetNameArray: ['지하수유입량 추정'], - headerRange: 'A1:O1' - }); - } else { - alert("조회된 결과가 없습니다."); - } - setIsExcelDownClick(false); - excelWaitRef.current = false; - }, [excelList, isExcelDownClick, isLoading]); - /** * 콜백함수 */ // 조회 - const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { + const searchFacilityPrecipitation = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => { let nameCd, partStr switch (partValue) { case 'R': @@ -202,10 +179,10 @@ export default function UnderWaterInput() { break; } if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) { - searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue + await searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue , fcltyName.trim() !== ""? fcltyName : undefined); } else { - searchUnderWaterList(pageNo, pageCnt, searchYear); + await searchUnderWaterList(pageNo, pageCnt, searchYear); } }, [fcltCpct, operationValue, fcltyName, searchUnderWaterList, searchYear]); @@ -216,7 +193,8 @@ export default function UnderWaterInput() { }, [upHeadList1, upHeadList2, upHeadList3]); // 엑셀다운로드 - const excelDownload = useCallback(() => { + const excelDownload = useCallback(async () => { + if (isExcelDownClick) return; if (ref.current.partValue === 'A') { // if (!ref.current.sidoValue || ref.current.sidoValue === '0') { alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.'); @@ -233,10 +211,24 @@ export default function UnderWaterInput() { return; } } - excelWaitRef.current = false; - searchFacilityPrecipitation(ref.current, 1, 5000); setIsExcelDownClick(true); - }, [searchFacilityPrecipitation]); + try { + await searchFacilityPrecipitation(ref.current, 1, 5000); + const latestExcelList = store.getState().UnderWater.excelList || []; + if (latestExcelList.length > 0) { + downloadExcel({ + data: latestExcelList as unknown as JSON[], + fileName: '지하수유입량 추정', + sheetNameArray: ['지하수유입량 추정'], + headerRange: 'A1:O1' + }); + } else { + alert("조회된 결과가 없습니다."); + } + } finally { + setIsExcelDownClick(false); + } + }, [isExcelDownClick, searchFacilityPrecipitation, store]); // 페이지 변경 const handlePageChange = useCallback((page: number) => { @@ -268,6 +260,7 @@ export default function UnderWaterInput() { btnClass={btnClass} queryClick={chkVal} excelClick={excelDownload} + excelDisabled={isExcelDownClick} initClick={resetVal} ref={ref} isAdmin={false} 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 82798db0b..9cef315c3 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 @@ -26,6 +26,7 @@ type SearchBaseType = { leftSelectClassName?: string; buttonOrder?: ("query" | "init" | "excel")[]; initSidoValue?: string | ''; + excelDisabled?: boolean; } export type ReturnType = { partValue: string; @@ -60,6 +61,7 @@ function SearchBaseForm ({ leftSelectClassName, buttonOrder, initSidoValue='', + excelDisabled=false, }: SearchBaseType) { const [partValue, setPartValue] = useState<string>("A"); const [sidoValue, setSidoValue] = useState<string>(initSidoValue?initSidoValue:"0"); @@ -87,7 +89,7 @@ function SearchBaseForm ({ ); case "excel": return ( - <Button className={btnClass} color="green" onClick={excelDownload} key="excel"> + <Button className={btnClass} color="green" onClick={excelDownload} key="excel" disabled={excelDisabled}> {excelName ? excelName : "엑셀다운로드"} </Button> ); @@ -191,4 +193,4 @@ function SearchBaseForm ({ } export { SearchBaseForm }; - \ No newline at end of file + From ddb36933589a2dc18b4c7b89515103f8d402cbfd Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 2 Feb 2026 18:14:45 +0900 Subject: [PATCH 77/92] =?UTF-8?q?fo:=20=EB=AA=A8=EB=9E=98=EC=8B=9C?= =?UTF-8?q?=EA=B3=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/dashboard/facilityInfo/page.tsx | 2 +- apps/fo/app/store/dashboard/index.tsx | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/dashboard/facilityInfo/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/facilityInfo/page.tsx index dd689f2fa..e65fe3cc8 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/facilityInfo/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/facilityInfo/page.tsx @@ -271,7 +271,7 @@ export default function ProcessFacilitySearch({searchYear = '', fcltyList = []}: (head.id === 'flowRate' && index === 0)?<TableCell rowSpan={5} className="text-center" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: (head.id === 'flowRate' && index === 5)?<TableCell rowSpan={6} className="text-center" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: (head.id === 'flowRate' && index === 11)?<TableCell rowSpan={2} className="text-center" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: - (head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 0)?<TableCell rowSpan={7} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: + (head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 0)?<TableCell rowSpan={7} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{Number.isNaN(el[head.id]) ? "" : el[head.id]}</TableCell>: (head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 7)?<TableCell rowSpan={6} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: (head.id === 'rdi'&&index === 0)?<TableCell rowSpan={7} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: (head.id === 'rdi'&&index === 7)?<TableCell rowSpan={6} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>: diff --git a/apps/fo/app/store/dashboard/index.tsx b/apps/fo/app/store/dashboard/index.tsx index 8f3b4dd8a..398f82c0e 100644 --- a/apps/fo/app/store/dashboard/index.tsx +++ b/apps/fo/app/store/dashboard/index.tsx @@ -1712,7 +1712,7 @@ export const dashBoardReducer = ( // RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD)) // const resp = await fetchMainGraph(searchYear, fcltyCd); const resp = mainGraphData; - if (resp && resp.data && resp.data.wqltObjs) { + if (resp && resp.data && resp.data.wqltObjs && resp.data.wqltObjs.length > 0) { const wqltData = resp.data.wqltObjs; const wqltDataTot = CalcRainEffect(clone(wqltData)); const wqltDataSunny = CalcRainEffect(clone(wqltData), 'SUNNY'); @@ -1800,10 +1800,11 @@ export const dashBoardReducer = ( const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd, mainGraphData); // 수질 데이터 청천시, 강우시 재계산 + let tpFctYn = 'N'; + if (mainGraphData.data.wqltObjs && mainGraphData.data.wqltObjs.length > 0) + tpFctYn = mainGraphData.data.wqltObjs?.[0].tpFctYn; // 총인설비가 없을 경우 제외 - console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.[0].tpFctYn); - - const tpFctYn = mainGraphData.data.wqltObjs?.[0].tpFctYn; + console.log('총인시설 여부 : ', tpFctYn); // console.log('rtnData : ', rtnData); if (tpFctYn !== 'Y') { From 8a160dc97ce09dee7fd8f54d1c623f631abda80d Mon Sep 17 00:00:00 2001 From: bicochan <chanii8@naver.com> Date: Tue, 3 Feb 2026 10:47:23 +0900 Subject: [PATCH 78/92] =?UTF-8?q?[cs]=20feat:=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=ED=8C=90=20=ED=86=B5=EA=B3=84=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=94=EC=9D=B8=EB=94=A9=20?= =?UTF-8?q?=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + apps/cs/docs/표준단어정의서.md | 831 ++++++++++++++++++ .../api/board-statistics-service.ts | 45 +- .../model/board-statistics-interface.ts | 44 +- .../board-statistics/model/chart-data.ts | 23 +- .../ui/board-statistics-page.tsx | 21 +- apps/cs/src/shared/config/api.ts | 1 + 7 files changed, 887 insertions(+), 79 deletions(-) create mode 100644 apps/cs/docs/표준단어정의서.md diff --git a/.gitignore b/.gitignore index 878447ead..ab07be55d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ apps/fo/.next/**/* pnpm-lock.yaml settings.json .npmrc +.cursor \ No newline at end of file diff --git a/apps/cs/docs/표준단어정의서.md b/apps/cs/docs/표준단어정의서.md new file mode 100644 index 000000000..6950eb84b --- /dev/null +++ b/apps/cs/docs/표준단어정의서.md @@ -0,0 +1,831 @@ +# 표준단어정의서 + +AI 이해용으로 정리된 표준단어명, 영문약어명, 영문명 목록입니다. + +| 표준단어명 | 표준단어 영문약어명 | 표준단어 영문명 | +|-----------|-------------------|----------------| +| BOD | BOD | Biochemical Oxygen Demand | +| C/N비 | CNR | Carbon-Nitrogen Ratio | +| COD | COD | Chemical Oxygen Demand | +| F/M비 | FMR | Food-Microorganism Ratio | +| GISD | GISDATA | Geographic Information System Data | +| HTML | HTML | Hypertext Markup Language | +| ID | ID | Id | +| IP | IP | Internet Protocol | +| KEY | KEY | Key | +| ND | ND | Not Detected | +| NON | NON | Non | +| NTU | NTU | Nephelometry Turbidity Unit | +| OPT | OPT | Opt | +| PAC | PAC | Polyaluminium Chloride | +| PH | PH | Hydrogen Exponent | +| PKI | PKI | Public Key Infrastructure | +| POOL | POOL | Pool | +| SS | SS | Suspended Solids (Ss) | +| TCE | TCE | Trichloroethane | +| TM | TM | Transverse Mercator | +| T-N | TN | Total Nitrogen | +| TOC | TOC | Total Organic Carbon | +| T-P | TP | Total Phosphorus | +| URL | URL | Uniform Resource Locator | +| 가구 | HSHD | Household | +| 가능 | PSBL | Possible | +| 가동 | OPR | Operation | +| 가산 | ADTN | Addition | +| 가성소다 | NAOH | Caustic Soda(Nach) | +| 가축분뇨 | ANMA | Animal Manure | +| 값 | VAL | Value | +| 강도 | IN | Intensity | +| 강우 | RAIN | Rain | +| 개방 | OPN | Opening | +| 개별 | INDIV | Individual | +| 개보수비 | RPAFEE | Repair Fee | +| 개설 | ESTBL | Establishment | +| 개시 | STRT | Start | +| 개정 | RVSN | Revision | +| 개조 | REMDEL | Remodeling | +| 개체 | INDVD | Individual | +| 개체군 | POPU | Population | +| 개폐 | RORGN | Reorganization | +| 갱신 | UPDT | Update | +| 건물 | BLDG | Building | +| 건설 | CONC | Construction | +| 건수 | NOCS | The Number Of Cases | +| 건조 | DRY | Dry | +| 검사 | INSP | Inspection | +| 검사서 | EXRPT | Examination Report | +| 검정 | RCGN | Recognition | +| 검증 | VRFC | Verification | +| 검출 | DETECT | Detection | +| 검토 | RVW | Review | +| 격자 | LATTC | Lattice | +| 결과 | RSLT | Result | +| 결의 | DCIS | Decision | +| 결정 | DCSN | Decision | +| 경계 | BNDRY | Boundary | +| 경과 | PROC | Process | +| 경도 | LOT | Longitude | +| 경보 | ALARM | Alarm | +| 경사판 | ICNTPT | Inclination plate | +| 계 | SUM | Summation | +| 계량기 | MRNR | Measuring Instrument | +| 계량기분리 | METRSPRT | Meter Separation | +| 계면 | SGLV | Sludge Level | +| 계산식 | FMUL | Formula | +| 계약 | CTRT | Contract | +| 계약기간 | CNTRPD | Contract Period | +| 계절 | SEASON | Season | +| 계획 | PLAN | Plan | +| 고도처리 | AWTR | Advanced Water Treatment | +| 고시 | ANCMNT | Announcement | +| 고액분리 | SLSPRT | Solid-Liquid Separation | +| 고형물체류시간 | SRT | Solid Retention Time | +| 공간데이터 | SPCEDATA | Space Data | +| 공공 | PUBLIC | Public | +| 공급 | SPLY | Supply | +| 공기 | AIR | Air | +| 공기여과 | ARFT | Air Filter | +| 공문 | ODOC | Official Documnet | +| 공법 | MSRC | Method Of Construction | +| 공사 | CSTRN | Construction | +| 공사비 | CONSTEXPN | Construction Expenses | +| 공업지역 | MNFTR_ARA | Manufacturing Area | +| 공용면적 | CMAR | Common Area | +| 공통 | CMMN | Commonness | +| 관 | PP | Pipe | +| 관계 | REL | Relation | +| 관련 | RLTN | Relation | +| 관로 | PPLINE | Pipe Line | +| 관리 | MNG | Management | +| 관리기관 | MGC | Management Agency | +| 관리자 | MNGR | Manager | +| 관찰 | WTCH | Watch | +| 관측 | OBSR | Observation | +| 관측소 | OBSRVT | Observatory | +| 교반기 | AGITOR | Agirator | +| 교정 | CRRC | Correction | +| 구간 | SCTN | Section | +| 구동 | DRIVE | Drive | +| 구분 | SE | Section | +| 구성 | CMPSG | Composing | +| 구역 | ZONE | Zone | +| 구조 | STRCT | Structure | +| 권역 | DSTR | District | +| 권한 | AUTH | Authority | +| 규격 | STNDRD | Standard | +| 규모 | SCAL | Scale | +| 규제 | REGL | Regulation | +| 균등 | EQLTY | Equality | +| 금액 | AMT | Amount | +| 급수 | WSP | Water Supply | +| 기간 | WHL | While | +| 기관 | INST | Institution | +| 기록 | RECD | Recording | +| 기록부 | REGI | Register | +| 기밀 | SCRET | Secret | +| 기법 | TECQU | Techniques | +| 기본 | BSIC | Basics | +| 기본정보 | BASINF | Bassinfo | +| 기본키 | PK | Primary Key | +| 기상 | WETHER | Weather | +| 기안 | DRFTG | Drafting | +| 기재 | WRIT | Write | +| 기점 | CDPNT | Cardinal Point | +| 기존 | LGCY | Legacy | +| 기준 | CRTR | Criteria | +| 기타 | ETC | Etc | +| 기한 | TERM | Term | +| 기후 | CLMT | Climate | +| 긴급 | EMRG | Emergency | +| 날개벽 | WW | Wing Wall | +| 날씨 | WETHR | Weather | +| 날짜 | DATE | DATE | +| 남조류 | BLAL | Blue-Green Algae | +| 납 | PB | Plumbum | +| 내려받기 | DWLD | Download | +| 내부반송 | ITNRCC | Internal Recycl | +| 내용 | CN | Content | +| 내용연수 | SVLF | Service Life | +| 냄새 | SMELL | Smell | +| 년 | YY | Year | +| 년간 | FAYR | For A Year | +| 노즐 | NZL | Nozzle | +| 노출 | EXPSR | Exposure | +| 농도 | DNSTY | Density | +| 농축 | TKN | Thickened | +| 누적 | ACML | Accumulate | +| 누출 | LKG | Leakage | +| 눈 | SNW | Snow | +| 단가 | UNPRC | Unit Price | +| 단기 | SRTPD | Short Period | +| 단순 | SIMPL | Simplicity | +| 단위 | UNIT | Unit | +| 대구역 | LZONE | Large Zone | +| 대분류 | LCLAS | Large Classification | +| 대장 | REGSTR | Register | +| 대장균 | COLI | Coliform, Fecal Coliform | +| 대장균군 | COLIB | Coliform Bacteria | +| 대지면적 | SIAR | Site Area | +| 대체 | RPLC | Replace | +| 덮개 | COVR | Cover | +| 데이타 | DAT | Data | +| 도구 | UNT | Unit | +| 도래 | ADVNT | Advent | +| 도로 | ROAD | Road | +| 도로명 | RN | Road Name | +| 도시 | CTY | City | +| 도엽 | MAPDMC | Map Demarcation | +| 도표 | CHART | Chart | +| 독성 | TOXCTY | Toxicity | +| 동의 | AGRE | Agreement | +| 동절기 | WSESN | The Winter Season | +| 등급 | GRD | Grade | +| 등기 | RG | Registered | +| 등록 | REG | Registration | +| 디바이스 | DVICE | Device | +| 디코딩 | DCD | Decoding | +| 레이어 | LYR | Layer | +| 로그인 | LGN | Login | +| 로우 | ROW | Row | +| 마감 | DDLN | Deadline | +| 마이크로필터 | MCRFT | Micro Filter | +| 막 | MBRN | Membrane | +| 만족도 | STFDG | Satisfaction Degree | +| 맑음 | CLAR | Clear | +| 매각 | SAL | Sale | +| 맨홀 | MH | Manhole | +| 맵 | MAP | Map | +| 메인 | MAIN | Main | +| 메일 | EMAIL | Email | +| 메탄올 | MTN | Methanol(CH3OH) | +| 명 | NM | Name | +| 모니터링 | MTRG | Monitoring | +| 모델 | MODL | Model | +| 모델링 | MODLNG | Modeling | +| 모래 | SAND | Sand | +| 목 | MOK | Mok | +| 무산소 | ANX | Anoxic | +| 무산소조 | ANX_TANK | Anoxic Tank | +| 무인센서 | MNLSENSR | Manless Sensor | +| 문서 | DCMT | Document | +| 물 | WTR | Water | +| 미급수 | NONWTRSPL | Non Water Supply | +| 미생물 | BLGC | Biological | +| 미세먼지 | PM | Particulate Matter | +| 미세목 | MCRB | Micro Bar | +| 민간위탁 | ETSVN | Entrustment To Civilian | +| 민감 | SST | Sensitive | +| 민원 | CVLCPT | Civil Complaint | +| 바이러스 | VIRS | Virus | +| 반기 | HT | Half Term | +| 반류수 | SIDSWT | Side Stream Water | +| 반송 | SNDBK | Send Back | +| 반송수 | RCCWT | Recycled Water | +| 반송슬러지 | RTNSLG | Return Sludge | +| 반영 | RFLT | Reflection | +| 반응조 | RETNK | Reactant Tank | +| 반출 | EXPRT | Export | +| 반토 | ALUM | Alumina | +| 반환 | GVBK | Giving Back | +| 받이 | INL | Inlet | +| 발생 | OCRN | Occurrence | +| 발전 | PWGNRT | Power Generation | +| 발주기관 | ORNT | Order Institution | +| 방류 | DCWTR | Discharge Water Stock Etc | +| 방류구 | DSCHG | Discharge | +| 방류수 | EFLEC | Effluence | +| 방문 | VST | Visit | +| 방문자 | VSTR | Visitor | +| 방법 | MTHD | Method | +| 방사 | RLSE | Release | +| 배관 | PLINE | Pipeline | +| 배분 | DSTRB | Distirbution | +| 배설물 | EXCRTN | Excretion | +| 배수 | DRNG | Drainage | +| 배수구역 | DRANGZN | Drainage Zone | +| 배출 | EXHST | Exhaust | +| 배출가스 | EMGA | Emission Gases | +| 배출구 | VENT | Vent | +| 배출시설 | DHGP | Discharge Equipment | +| 배출시험 | EXHTST | Exhaust Test | +| 배출자 | DCHGR | Discharge Person | +| 밸브 | VALVE | Valve | +| 번호 | NO | Number | +| 법 | LAW | Law | +| 법적 | LGL | Legal | +| 법정 | STTY | Statutory | +| 법정동 | STDG | Statutory Dong(Administrative District) | +| 법정리 | STLI | Statutory Li(Administrative District) | +| 변경 | CHG | Change | +| 변동 | FLCTN | Fluctuation | +| 변속기 | TRMIS | Transmission | +| 보고 | RPT | Report | +| 보고서 | RPOT | Report | +| 보관 | STORG | Storage | +| 보수 | MEND | Mend | +| 보유 | HOLD | Hold | +| 보정 | RVSION | Revision | +| 보조 | ASSISC | Assistance | +| 보조금 | SBSIDY | Subsidy | +| 복개 | COVE | Cover | +| 복토 | CWTH | Covering With Soil | +| 본류 | MI_RV | Main River | +| 본번 | MNO | Main Number | +| 부검 | ATPSY | Autopsy | +| 부과 | LEVY | Levy | +| 부과금 | LVYAMT | Levy Amount | +| 부기 | BUKIP | Bookkeeping | +| 부담금 | ALOTM | Allotment | +| 부번 | SNO | Sub Number | +| 부산물 | BYPRD | By-Product | +| 부서 | DEPT | Department | +| 부숙화 | DECPZ | Decomposed ~Ize | +| 부적합 | IMPPRTY | Impropriety | +| 부착 | ASN | Adhesion | +| 부품 | CMPNT | Components | +| 부하량 | LOADQTY | Load Quantity | +| 분과 | DIVSN | Division | +| 분뇨 | ENSO | Excreta, Night Soil | +| 분류 | CL | Classification | +| 분류군 | TAXON | Taxon | +| 분리막 | SPRTMBR | Separation Membrane | +| 분배 | DTRBT | Distribution | +| 분배조 | DTRBT_TANK | Distribution Tank | +| 분야 | RLM | Realm | +| 분원성 | FECL | Fecal | +| 분원성대장균군 | FCOLI | Fecal Coliform | +| 분원성연쇄상구균 | FCSTRCCI | Fecal Streptococci | +| 분할 | PRTIN | Partition | +| 비밀번호 | PSWD | Password | +| 비상 | EMGNY | Emergency | +| 비정상 | ABNRM | Abnormality | +| 사양 | SPECS | Specification | +| 사업비 | WCT | Working Cost | +| 사업장 | BPLC | Business Place | +| 사여과지 | SAND_ FILTR | Sand Filter | +| 사용 | USE | Use | +| 사용가능 | USABLE | Usable | +| 사용권 | RIOUS | Right Of Using | +| 사용량 | USG | USAGE | +| 사용자 | USER | User | +| 사위 | FDG | Four Directions Girth | +| 사유 | RESN | Reason | +| 사이클 | CYCLE | Cycle | +| 사이트 | SITE | Site | +| 사진 | PHOT | Photograph | +| 사항 | MATTR | Matter | +| 사후 | AFTFAT | After Fact | +| 삭제 | DEL | Deletion | +| 산기관 | DFS | Diffuser | +| 산업 | INDUST | Industrial | +| 산화환원전위 | ORP | Oxidation Reduction Potential | +| 살모넬라 | SLMN | Salmonella | +| 삼원촉매장치 | TWCTLC | Three Way Catalytic Converter | +| 상세 | DTL | Details | +| 상세주소 | DADDR | Detailed Address | +| 상수 | WT | Water | +| 상업지역 | CMCL_ARA | Commercial Area | +| 상태 | STUS | Status | +| 상품 | GDS | Goods | +| 상향류 | UFW | Upflow | +| 상호 | CONM | Company Name | +| 색도 | CRMTY | Chromaticity | +| 생략 | OMS | Omission | +| 생물 | LVB | Living Being | +| 생물반응조 | BIRAT | Bioreactor | +| 생물서식처 | ORGNHBT | Organism Habitat | +| 생물종 | BISP | Biological Species | +| 생성 | CRT | Creation | +| 생슬러지 | RSLG | Raw Sludge | +| 생태 | ECLGY | Ecology | +| 생태독성 | ECTOX | ecotoxicity | +| 서류 | PAPE | Papers | +| 서명 | SIGN | Signing | +| 서버 | SRVR | Server | +| 서비스 | SRVC | Service | +| 설계 | DESGN | Design | +| 설계용량 | DESGN_CPCT | Design Capacity | +| 설립 | FNDN | Foundation | +| 설정 | STNG | Setting | +| 설치 | INSTL | Installation | +| 성격 | CHTR | Character | +| 성공 | SCS | Success | +| 성능 | PRFMNC | Performance | +| 성능검사 | EFTST | Efficiency Test | +| 성적서 | SCRRP | Score Report | +| 세균 | BCLS | Bacillus | +| 세목 | FB | Fine bar | +| 세부 | DETAIL | Detail | +| 세정 | WS | Washing | +| 세정제 | CNML | Cleaning Material | +| 소 | SML | Small | +| 소독 | DSNF | Disinfection | +| 소독제 | DSINF | Disinfectant | +| 소분류 | SCLAS | Small Classification | +| 소수점 | DCPT | Decimal Point | +| 소요 | REQ | Required | +| 소유 | OWN | Own | +| 소유역 | SBASIN | Sub Basin | +| 소재지 | PLAC | Place Of Location | +| 소포 | ATFM | Antifoaming | +| 소포수 | FBW | Foam Breaking Water | +| 소포제 | ANAG | Antifoaming Agent | +| 송부 | SENDNG | Sending | +| 송신 | SNDM | Send Message | +| 송풍기 | BLW | Blower | +| 수 | CNT | Count | +| 수거 | TKAWY | Take Away | +| 수계 | WWBH | Watershed, Water Basin, Hydrosphere | +| 수동 | HOPR | Hand Operation | +| 수리학적 체류시간 | HRT | Hydraulic Retention Time | +| 수문 | Gate | Gate | +| 수산화나트륨 | SOHY | Sodium Hydroxide | +| 수소이온 | HION | Hydrogen Ion | +| 수신 | RCPTN | Reception | +| 수용가 | RCPTR | Receptor | +| 수위 | WAL | Water Level | +| 수정 | MDFCN | Modification | +| 수정자 | MDFR | Modifier | +| 수제 | SPRDIKE | Superdike | +| 수조 | Tank | Tank | +| 수질 | QTWT | Quality Of Water | +| 수질개선 | WTRQLIMP | Water Quality Improvement | +| 수질기준 | WQST | Water Quality Standards | +| 수질배출정보 | WTDI | Water Discharge Information | +| 수집 | CLCT | Collection | +| 순환 | CCL | Cycling | +| 쉬겔라 | SHIGLA | Shigella | +| 스컴 | SCM | Scum | +| 스크린 | SCR | Screen | +| 슬러지 | SLG | Sludge | +| 슬러지 밀도지수 | SDI | sludge density index | +| 슬러지 용량 지표 | SVI | Sludge Volume Index | +| 습지 | WTLN | Wetland | +| 승인 | APRV | Approval | +| 승인권 | APPRVRGT | Right Of Approval | +| 시각 | TIME | Time | +| 시간 | HR | Hour | +| 시군구 | SGG | Si/Gun/Gu | +| 시나리오 | SCEN | Scenario | +| 시도 | CTPV | Cities And Provinces | +| 시료 | SMPL | Sample | +| 시설 | FCLT | Facility | +| 시설면적 | FCAR | Facility Area | +| 시설물 | FCLTS | Facilities | +| 시스템 | SYS | System | +| 시안 | CYN | Cyaan | +| 시운전 | TSTRN | Test Run | +| 시작 | BGNG | Beginning | +| 시점 | PTM | Point Time | +| 시행 | ENFC | Enforcement | +| 시험 | TEST | Test | +| 신고 | DCLR | Declaration | +| 신고자 | DCL | Declarer | +| 신규 | NEW | New | +| 신기술 | NTCH | New Technology | +| 신뢰 | CNFDNC | Confidence | +| 신뢰성 | CRDIBLTY | Credibility | +| 실시 | OPRT | Operation | +| 실적 | ACRS | Actual Result | +| 실행 | EXCN | Execution | +| 심사 | SRNG | Screening | +| 심의 | DLBR | Deliberation | +| 아황산환원혐기성포자형성균 | SFSRA | Spore Forming Sulfite Reducing Anaerobes | +| 안정화 | STBLZT | Stabilization | +| 암롤박스(컨테이너) | ARTCT | Arm roll type container | +| 암모니아성질소 | NHN | Ammonia Nitrogen | +| 압력 | PRESSR | Pressure | +| 압송 | PUMPNG | Pumping | +| 압축 | CMPRS | Compress | +| 액비 | LQFERTLZ | Liquid Fertilizer | +| 액상 | LIQD | Liquid | +| 약 | GENTLE | Gentle | +| 약품 | CMC | Chemical | +| 약품비 | MEDFEE | Medicine Fee | +| 약품사용 | USMD | Use Medicines | +| 업로드 | UPLD | Upload | +| 업무 | DTY | Duty | +| 없음 | NOT | Nothing | +| 에너지 | ENR | Energy | +| 에틸벤젠 | ETBNZN | Ethylbenzene | +| 여과 | FILTR | Filteration | +| 여과수 | FTWT | Filtered Water | +| 여과재 | FTMTRL | Filter Material | +| 여과형 | FILTRFOM | Filter Form | +| 여부 | YN | Yes or No | +| 여시니아균 | YERSNA | Yersinia | +| 역률 | PWRER_FCT | Power Factor | +| 역세척 | BWS | Back Wash | +| 연결 | CONN | Connection | +| 연계 | LINK | Link | +| 연도 | YR | Year | +| 연락 | CNTC | Contact | +| 연령 | AGE | Age | +| 연료화 | FUELZ | Fuelize | +| 연월 | YM | Year and Month | +| 염소 | CLRN | Chlorine | +| 염소소독 | CHDI | Chlorine Disinfection | +| 염소이온 | CLION | Chlorine Ion | +| 염화제이철 | IRCLD | Iron(III) Chloride | +| 예보 | FRCST | Forecast | +| 예비 | PRPT | Preparation | +| 예산 | BGT | Budget | +| 예상 | EXPCT | Expectation | +| 예약 | RSVT | Reservation | +| 예외 | EXCPT | Exception | +| 예정 | PRNG | Prearrangement | +| 예찰 | PRDICT | Prediction | +| 오류 | ERR | Error | +| 오수받이 | HUS_INL | House Inlet | +| 오염물질 | CNTMN | Contaminant | +| 오염원 | POLUSRC | Pollution Source | +| 오존 | OZN | Ozone | +| 오프로드 | OFFRD | Off Road | +| 옥살산 | OXACID | Oxalic Acid | +| 와류 | VORTEX | Vortex | +| 와류형 | VORTXFOM | Vortex From | +| 완결 | COMPLT | Completion | +| 완료 | CMPTN | Completion | +| 완전 | PRFECT | Perfection | +| 요건 | REQSIT | Requisite | +| 요막액 | ALLNTFLD | Allantoic Fluid | +| 요청 | DMND | Demand | +| 용량 | CPCT | Capacity | +| 용역 | SERVC | Service | +| 용존산소 | DO | Dissolved Oxygen | +| 용해 | DSLV | Dissolving | +| 우량 | EXLT | Excellent | +| 우수 | ST | Storm | +| 우수받이 | STRT_INL | Street Inlet | +| 우수토구 | STM_OVFL_MUT | Storm Overflow Mouth | +| 우회 | BP | BY PASS | +| 운반 | CNVY | Conveyance | +| 운영 | OPER | Operation | +| 운영비 | OPEXP | Operation Expense | +| 운행 | OPRAT | Operation | +| 원격 | RMRT | Rmrt | +| 원격감시체계 | TMS | Tele Monitoring System | +| 원료 | MTRAL | Material | +| 원수 | ORGWT | Origin'S Water | +| 원인자 | ORGPR | The Origin Person | +| 월 | MM | Month | +| 위도 | LAT | Latitude | +| 위반 | CNTR | Contravene | +| 위촉 | ENTRST | Entrusting | +| 위치 | LOC | Location | +| 위탁 | CNSG | Consign | +| 위탁자 | CONSGNR | Consignor | +| 유기인 | ORGP | Organic Phosphorus | +| 유량 | FLUX | Flux | +| 유량조정조 | EQLZT__TANK | Equalization Tank | +| 유입 | INFlOW | Inflow | +| 유입수 | INFWTR | Influent Water | +| 유주 | SWARMG | Swarming | +| 유지 | MNTNC | Maintenance | +| 유지용수공급 | MWRS | Maintenance Water Requirement Supply | +| 유체 | FLUID | Fluid | +| 유출 | EFFLUX | Efflux | +| 유충 | LAVL | Larval | +| 유형 | TY | Type | +| 유효 | VLD | Validity | +| 음용 | DKPS | For Drinking Purpose | +| 읍면동 | EMD | Eup/Myun/Dong | +| 응답 | RSPNS | Response | +| 응집제 | COAG | Cohesive Agents | +| 이관 | TRNSF | Transfer | +| 이동 | MVMN | Movement | +| 이력 | HST | History | +| 이메일 | EML | Email | +| 이상 | ABOVE | Above | +| 이송 | TRSF | Transfer | +| 이의 | OBJC | Objection | +| 이차 | SCDR | Secondary | +| 이차침전지 | SCDR_SDMT_TANK | Secondary Sedimaentation | +| 이행 | MIG | Migratation | +| 인건비 | PEXP | Personnel Expenses{Expenditure] | +| 인계 | HNDVR | Handover | +| 인계서 | HDOVDC | Handover Document | +| 인구 | POPL | Population | +| 인산 | PHACID | Phosphoric Acid | +| 인산염인 | POP | phosphate | +| 인양기 | LFT | Lifter | +| 인원수 | NOPE | The Number of Persons | +| 인증 | CERT | Certification | +| 인처리 | PPRCS | Phosphorus Process | +| 인허가 | APVL | Approval | +| 일 | DY | Day | +| 일련번호 | SN | Serial Number | +| 일반 | GNRL | General | +| 일별 | DALY | Daily | +| 일시 | DT | Date and Time | +| 일자 | YMD | YEAR Month Day | +| 일지 | DIARY | Diary | +| 일차 | PRM | Primary | +| 일차침전지 | PST_SDMT_TANK | Primary Sedimentation Tank | +| 일평균 | DYRG | Day Average | +| 임시 | TMPR | Temporary | +| 임의 | RNDM | Random | +| 입고 | WRHS | Warehousing | +| 입력 | INPT | Input | +| 잉여 | SPS | Surplus | +| 잉여슬러지 | EC_SLG | Excess Sludge | +| 자 | MAN | Man | +| 자갈 | GRAVEL | Gravel | +| 자료 | DATA | Data | +| 자리 | DIGIT | Digit | +| 자립화 | SLFRLI | Self Reliance | +| 자연형 | NATRLFOM | Natural Form | +| 자외선 | URLI | Ultraviolet Rays, Light | +| 자재 | MTRIL | Material | +| 자체 | ITSL | Itself | +| 작성 | WRT | Writing | +| 작업 | JOB | Job | +| 잠금 | LOCK | Lock | +| 장기 | LNGTR | Long Term | +| 장소 | PLCE | Place | +| 장착 | MNTNG | Mounting | +| 재 | RE | Re | +| 재이용 | REUSE | Reuse | +| 재이용수 | | Reuse Water | +| 재활용 | RUSE | Reuse | +| 저감 | REDUC | Reduction | +| 저류조 | DTT_TANK | Detention Tank | +| 저온 | LOWTMP | Low Temperature | +| 저장 | STRG | Storage | +| 저장소 | STORGE | Storage | +| 적발 | DSCL | Disclose | +| 적산 | ADD | Addition | +| 적용 | APLCN | Application | +| 적합 | STBLT | Suitability | +| 전기 | ELCTY | Electricity | +| 전기료 | ELFEE | Electricity Fee | +| 전력 | PWRER | Power | +| 전문 | SPCY | Specially | +| 전산 | CMPUTT | Computation | +| 전송 | TRSM | Transmission | +| 전압 | VLTGE | Voltage | +| 전용 | EXUSE | Exclusive Use | +| 전원 | SELCT | Source Of Electricity | +| 전처리 | PRETR | Pretreatment | +| 점검 | CHCK | Check | +| 접속 | CNTN | Connection | +| 정밀 | PRCIS | Precision | +| 정보 | INFO | Information | +| 정산 | CLCLN | Calculation | +| 정상 | NRMLT | Normality | +| 정수장 | WPPW | Water Purification Plant, Waterworks | +| 정제 | REFINE | Refining | +| 정지 | STP | Stop | +| 제거 | RMV | Removal | +| 제수변 | SL_VALVE | Sluice Valve | +| 제작 | MNFCT | Manufacture | +| 제조사 | MKR | Maker | +| 제출 | SBMSN | Submission | +| 제한 | LIMT | Limitation | +| 조류 | ALG | Algae | +| 조목 | CSB | Coarse Bar | +| 조사 | EXMN | Examination | +| 조성 | MAKE | Make | +| 조정 | EQLT | Equalization | +| 조치 | ACTN | Action | +| 조회 | INQ | Inquiry | +| 존재 | EXST | Existence | +| 종결 | TRMN | Termination | +| 종균제 | MICBA | Microbial Agent | +| 종료 | END | End | +| 종류 | KND | Kind | +| 종목 | IEM | Item | +| 종별 | ASORT | Assortment | +| 종사자 | ENFSN | Enfilade Person | +| 종점 | TMNL | Terminal | +| 좌표 | COOR | Coordinate | +| 주간 | WIK | Week | +| 주변 | CFR | Circumference | +| 주소 | ADDR | Address | +| 주입 | IJTN | Injection | +| 주파수 | FQNC | Frequency | +| 준공 | CMCN | Completion Of Construction | +| 중권역 | MDSTRC | Medium District | +| 중복 | DPCN | Duplication | +| 중분류 | MLSFC | Middle Classification | +| 중온 | MESPH | Mesophilic | +| 중첩 | RETRTN | Reiteration | +| 중화설비 | NUTEQP | Neutralization Equipment | +| 중화제 | CNTAG | Counteragent | +| 증가 | INCRS | Increase | +| 지도점검표사본 | CITBMR | Copy of Instruction Checklist | +| 지방자치단체 | LGOV | Local Governments | +| 지번 | LOTNO | Lot Number | +| 지상 | GRND | Ground | +| 지역 | ARA | Area | +| 지질 | NTRFS | Nature Of Soil | +| 지질도 | GEOMAP | Geological Map | +| 지하 | UDGD | Underground | +| 지하수 | GROU | Groundwater | +| 지형 | TPGRPH | Topography | +| 진공 | VCM | Vacuum | +| 진단 | DGNSS | Diagnosis | +| 진동 | VIBRAT | Vibration | +| 진행 | PRGRE | Progress | +| 질산 | NIACID | Nitric Acid. | +| 질산성질소 | NO3N | Nitrate Nitrogen | +| 집계 | TOT | Total | +| 집계구 | SUMDST | Summation District | +| 집행 | IMPL | Implementation | +| 찌꺼기 | LEES | Lees | +| 차아염소산 | NAOCL | Hypochlorous Acid | +| 차집 | ITCT | Intercepting | +| 착공 | BGNCST | Begin Construction | +| 채수 | SAMWT | Sampling Of Water | +| 채수기 | WTRSMPLR | Water Sampler | +| 채수병 | WTRBOTL | Water Bottle | +| 처리 | PRCS | Process | +| 처리비 | PSSFEE | Process Fee | +| 처리수 | TRT_WT | Treated Water | +| 처리수조 | TRT_WT_TANK | Treated Water Tank | +| 처리시설 | TRTMTFCLT | Treatment Facility | +| 처리자 | PRCR | Processor | +| 처분 | DSPS | Disposition | +| 철염 | FESLT | Ferric Salt | +| 첨부 | ATCH | Attachment | +| 첨부파일 | ATFI | Attachment File | +| 초과 | EXCS | Excess | +| 초기화 | INITL | Initialization | +| 촉매 | CTLY | Catalyst | +| 총계 | TSM | Summation | +| 총대장균군 | TCOLFGRP | Total Coliform Group | +| 총량 | TQT | Total Quantity | +| 총면적 | GFA | Gross Floor Area | +| 총사업비 | TPCO | Total Project Cost | +| 총인구 | TPOPLTN | Total Population | +| 총인처리시설 | TPFCT | Total Phosphorus facility | +| 최근 | RCNT | Recent | +| 최대값 | MAXV | Maximum Value | +| 최소값 | MINV | Minimum Value | +| 최적 | BMTB | Being The Most Suitable | +| 최종 | LAST | Last | +| 최초 | FRST | First | +| 추출 | EXTR | Extraction | +| 추출정보 | EXTRINFO | Extraction Information | +| 축 | AXS | Axis | +| 출력 | OTPT | Output | +| 출발 | LVE | Leave | +| 충전기 | CHRGR | Charger | +| 취득 | ACQS | Acquisition | +| 취소 | RTRCN | Retraction | +| 측정 | MSUR | Measurement | +| 측정기 | MSRR | Measurement Instrument | +| 측정소 | MSRSTN | Measurement Station | +| 침사지 | GTCB | Grit Chamber | +| 침전 | SDMT | Sediment | +| 침전지 | SDMT_TANK | sedimentation tank | +| 컨베이어 | CVY | Conveyor | +| 컬럼 | COL | Column | +| 코드 | CD | Code | +| 크기 | SZ | Size | +| 크실렌 | XYLEN | Xylene | +| 탄화 | CARB | Carbonization | +| 탈거 | CRYOFF | Carry Off | +| 탈리액 | SPNT | Supernatant | +| 탈수 | DWTR | Dewatering | +| 탈수기 | DEHYM | Dehydration Machine | +| 탈질 | DNTFCT | Denitrificatio | +| 탈취 | DODRZ | Deodorization | +| 탈취기 | DEODRZ | Deodorizer | +| 탈취제 | DEODR | Deodorant | +| 탈황제 | DSLFA | Desulfurizing Agent | +| 터널형 | YUNLTP | Tunnel Type | +| 테이블 | TBL | Table | +| 토구 | OTFL | Outfall | +| 토지 | LAD | Land | +| 토지면적 | LDAR | Land Area | +| 통계 | STATS | Statistics | +| 통보 | NTFCTN | Notification | +| 통신 | COMM | Communication | +| 통지 | AVTSMT | Avertissement | +| 통합 | UNTY | Unity | +| 특성 | CHRT | Character | +| 특수 | SPECL | Special | +| 특정유해물질 | SHCH | Specified Hazardous Chemicals | +| 파일 | FILE | File | +| 판정 | JGMT | Judgement | +| 펌프 | PUMP | Pump | +| 펌프장 | PUMP_STT | Pump Station | +| 페놀 | PHNL | Phenol | +| 평가 | EVL | Evaluation | +| 폐기 | DSCD | Discard | +| 폐기물 | WSTE | Waste | +| 폐쇄 | CLSG | Closing | +| 폐수 | WAWA | Waste Water | +| 폐수처리 | WSWT | Wastewater Treatment | +| 폐열 | WASTHET | Waste Heat | +| 포기 | ARTN | Aeration | +| 포트 | PORT | Port | +| 폭기조 | ARTN_TANK | Aeration Tank | +| 폴리머 | PLYMR | Polymer | +| 폴리철 | FRRCSU | Ferric Sulfate | +| 표고 | AL | Altitude | +| 표기 | MARK | Mark | +| 표시 | INDCT | Indication | +| 표준 | STD | Standard | +| 표출 | EPRSS | Expression | +| 플래그 | FLAG | Flag | +| 필드 | FILD | Field | +| 필수 | ESNTL | Essential | +| 필증 | CERFIN | Certificate Of Finishing | +| 필터 | FLTER | Filter | +| 하수 | SWGE | Sewage | +| 하수도 | DRNGSYS | Drainage System | +| 하수미처리 | SEWGUNTTM | Un Sewage Treatment | +| 하수처리 | SEWGTRTM | Sewage Treatment | +| 하수처리수 | STWTR | Sewage Treatment Water | +| 하위 | LOWR | Lower | +| 하향류 | DWFW | Downflow | +| 할인 | DSCNT | Discount | +| 함수율 | MISTR_CTNT | Moisture content | +| 합계 | SMM | Summation | +| 해당 | RLVT | Relevant | +| 해석 | INTRPRTT | Interpretation | +| 해양투기 | OCDU | Ocean Dumping | +| 행망 | ADMNW | Administration Network | +| 행정 | ADMN | Administration | +| 행정구역 | ADMI | Administrative District | +| 행정동 | DONG | Dong (Administrative District) | +| 허가 | PRMSN | Permission | +| 허용 | PERM | Permission | +| 현상 | PHNMN | Phenomenon | +| 혐기 | AARB | Anaerobic | +| 혐기조 | AARB_TANK | Anaerobic tank | +| 협잡물 | CCMT | Concomitant | +| 형태 | SHAP | Shape | +| 호기 | ARB | Aerobic | +| 호기조 | ARB_TANK | Aerobic Tank | +| 호소수 | LMSHWT | Lake And Marsh Water | +| 호수 | LKE | Lake | +| 호안 | RVTMNT | Revetment | +| 호이스트 | HIST | Hoist | +| 혼합 | CMPN | Compound | +| 혼합액현탁고형물 | MLSS | Mixed liquor suspended solids | +| 혼화지 | MXG_TNAK | Mixing tank | +| 홈페이지 | HMPG | Homepage | +| 홍수 | FLOOD | Flood | +| 확인 | IDNTY | Identify | +| 확인서 | CNFRMN | Confirmation | +| 확인자 | IDFR | Identifier | +| 확장자 | EXTN | Extension | +| 확정 | CFMTN | Confirmation | +| 환경 | ENVR | Environment | +| 환경기초시설 | ENINF | Environmental Infrastructure | +| 환원 | RSTORE | Restoration | +| 활성탄 | AC | Activated Carbon | +| 활성화 | PRMT | Promote/Facilitate | +| 활용 | PRUS | Practical Use | +| 황산 | ECCBT | Encyclopaedia Britannica (H2So4) | +| 회사 | CO | Company | +| 회수 | RTRVL | Retrieval | +| 회신 | RPLY | Reply | +| 효율 | EFC | Efficiency | +| 효율성 | EFFCTV | Effectiveness | +| 휴대 | MBL | Mobile | +| 흡수정 | EXTTW | Extraction Well | +| 흡착 | ADST | Adsorption | diff --git a/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts b/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts index 03291223c..9380132e8 100644 --- a/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts +++ b/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts @@ -1,53 +1,22 @@ -// import { client } from "@/shared/api"; -// import { ENDPOINT } from "@/shared/config"; +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; import { type BoardStatisticsParams, type BoardStatistics, type BoardStatisticsService, } from "../model/board-statistics-interface"; -// 임시 모의 데이터 -const mockBoardStatisticsData: BoardStatistics = { - totalPosts: 2456, - totalComments: 156, - averageRating: 4.2, - totalViews: 45678, - dayList: [ - { date: "1월", posts: 10, comments: 5, views: 800 }, - { date: "2월", posts: 15, comments: 8, views: 1200 }, - { date: "3월", posts: 12, comments: 10, views: 1000 }, - { date: "4월", posts: 18, comments: 15, views: 1500 }, - { date: "5월", posts: 22, comments: 20, views: 1800 }, - { date: "6월", posts: 20, comments: 18, views: 1600 }, - { date: "7월", posts: 25, comments: 22, views: 2000 }, - ], - boardList: [ - { boardType: "notice", boardName: "공지사항", count: 45 }, - { boardType: "faq", boardName: "FAQ", count: 120 }, - { boardType: "qna", boardName: "Q&A", count: 180 }, - { boardType: "free", boardName: "자유게시판", count: 95 }, - ], - statusList: [ - { status: "completed", statusName: "답변완료", count: 75 }, - { status: "waiting", statusName: "답변대기", count: 25 }, - ], -}; - class BoardStatisticsApiService implements BoardStatisticsService { async getBoardStatistics( params: BoardStatisticsParams, ): Promise<BoardStatistics> { - console.log("params: ", params); try { // 실제 API 연동 시 아래 코드 사용 - // const response = await client.get<BoardStatistics>( - // `${ENDPOINT.CMS_SERVICE.BOARD_STATISTICS}`, - // { params }, - // ); - // return response.data; - - // 임시 모의 데이터 반환 - return Promise.resolve(mockBoardStatisticsData); + const response = await client.get<BoardStatistics>( + `${ENDPOINT.BOARD_SERVICE.STATISTICS}`, + { params }, + ); + return response.data; } catch (error) { console.error("게시판 통계 데이터 조회 실패:", error); throw error; diff --git a/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts b/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts index 1f113475f..3d7a97c87 100644 --- a/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts +++ b/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts @@ -12,32 +12,36 @@ export interface BoardStatisticsParams extends PageableParams { } export interface BoardStatistics { - totalPosts: number; - totalComments: number; - averageRating: number; - totalViews: number; - dayList: DayStatistics[]; - boardList: BoardTypeStatistics[]; - statusList: StatusStatistics[]; + bbsTotalDto: BbsTotalDto; // 게시판 전체 통계 + pstAnsList: PstAnswerStatistics[]; // 게시물 답변 상태별 통계 목록 + bbsDailyList: BbsDailyStatistics[]; // 게시판 일별 통계 목록 + bbsPstCntList: BbsPostCountStatistics[]; // 게시판별 게시물 건수 통계 목록 } -interface DayStatistics { - date: string; - posts: number; - comments: number; - views: number; +interface BbsTotalDto { + pstInqCnt: number; // 게시물 조회 건수 + pstEvlAvg: number; // 게시물 평가 평균 + pstTotCnt: number; // 게시물 총 건수 + pstAnsWaitCnt: number; // 게시물 답변 대기 건수 } -interface BoardTypeStatistics { - boardType: string; - boardName: string; - count: number; +interface PstAnswerStatistics { + answerNm: string; // 답변 명 + answerYn: string; // 답변 여부 (Y/N) + ansCnt: number; // 답변 건수 } -interface StatusStatistics { - status: string; - statusName: string; - count: number; +interface BbsDailyStatistics { + dayYmd: string; // 일자 (YYYY-MM-DD) + pstInqCnt: number; // 게시물 조회 건수 + pstCmntCnt: number; // 게시물 댓글 건수 + pstNewCnt: number; // 게시물 신규 건수 +} + +interface BbsPostCountStatistics { + bbsId: number; // 게시판 ID + bbsNm: string; // 게시판 명 + pstCnt: number; // 게시물 건수 } export interface BoardStatisticsService { diff --git a/apps/cs/src/pages/board-statistics/model/chart-data.ts b/apps/cs/src/pages/board-statistics/model/chart-data.ts index 2a9b6671f..487d70976 100644 --- a/apps/cs/src/pages/board-statistics/model/chart-data.ts +++ b/apps/cs/src/pages/board-statistics/model/chart-data.ts @@ -11,20 +11,20 @@ export const chartData = { } => { return { data: { - labels: data.dayList.map((item) => item.date), + labels: data.bbsDailyList.map((item) => item.dayYmd), datasets: [ { type: "line", label: "신규게시물", - data: data.dayList.map((item) => item.posts), + data: data.bbsDailyList.map((item) => item.pstNewCnt), borderColor: getCssVariableValue("--chart-1"), backgroundColor: "rgba(59, 130, 246, 0.1)", tension: 0.4, }, { type: "line", - label: "답변대기", - data: data.dayList.map((item) => item.comments), + label: "댓글수", + data: data.bbsDailyList.map((item) => item.pstCmntCnt), borderColor: getCssVariableValue("--chart-2"), backgroundColor: "rgba(236, 72, 153, 0.1)", tension: 0.4, @@ -32,11 +32,10 @@ export const chartData = { { type: "line", label: "조회수", - data: data.dayList.map((item) => item.views), + data: data.bbsDailyList.map((item) => item.pstInqCnt), borderColor: getCssVariableValue("--chart-3"), backgroundColor: "rgba(168, 85, 247, 0.1)", tension: 0.4, - hidden: true, }, ], }, @@ -67,13 +66,13 @@ export const chartData = { } => { return { data: { - labels: data.boardList.map((item) => item.boardName), + labels: data.bbsPstCntList.map((item) => item.bbsNm), datasets: [ { type: "bar", label: "게시판별 분포", - data: data.boardList.map((item) => item.count), - backgroundColor: data.boardList.map((_, index) => + data: data.bbsPstCntList.map((item) => item.pstCnt), + backgroundColor: data.bbsPstCntList.map((_, index) => getCssVariableValue(`--chart-${(index % 5) + 1}`), ), }, @@ -106,12 +105,12 @@ export const chartData = { } => { return { data: { - labels: data.statusList.map((item) => item.statusName), + labels: data.pstAnsList.map((item) => item.answerNm), datasets: [ { type: "doughnut", - data: data.statusList.map((item) => item.count), - backgroundColor: data.statusList.map((_, index) => + data: data.pstAnsList.map((item) => item.ansCnt), + backgroundColor: data.pstAnsList.map((_, index) => getCssVariableValue(`--chart-${(index % 5) + 1}`), ), }, diff --git a/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx b/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx index 13dcbe812..716c390ab 100644 --- a/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx +++ b/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx @@ -26,7 +26,7 @@ import { SelectValue, } from "@common/components"; import { SiteSelect } from "@/entities/site"; -// import { ENDPOINT } from "@/shared/config"; +import { ENDPOINT } from "@/shared/config"; import { NoData } from "@/shared/ui/no-data"; import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker"; import { BoardStatisticsApi } from "../api/board-statistics-service"; @@ -66,7 +66,7 @@ function BoardStatisticsPage() { }); const { data: boardStatisticsData } = useQuery({ - queryKey: ["board-statistics", searchParams], + queryKey: [ENDPOINT.BOARD_SERVICE.STATISTICS, searchParams], queryFn: () => BoardStatisticsApi.getBoardStatistics({ ...searchParams, @@ -176,7 +176,8 @@ function BoardStatisticsPage() { <h3 className="text-lg font-medium text-gray-500">총 게시물</h3> <div className="flex items-center justify-between"> <div className="mt-2 text-4xl font-bold"> - {boardStatisticsData?.totalPosts.toLocaleString() || 0} + {boardStatisticsData?.bbsTotalDto?.pstTotCnt?.toLocaleString() || + 0} </div> <div className="h-16 w-24"> <Line @@ -210,7 +211,8 @@ function BoardStatisticsPage() { <h3 className="text-lg font-medium text-gray-500">답변대기</h3> <div className="flex items-center justify-between"> <div className="mt-2 text-4xl font-bold"> - {boardStatisticsData?.totalComments.toLocaleString() || 0} + {boardStatisticsData?.bbsTotalDto?.pstAnsWaitCnt?.toLocaleString() || + 0} </div> <div className="h-16 w-24"> <Line @@ -244,7 +246,7 @@ function BoardStatisticsPage() { <h3 className="text-lg font-medium text-gray-500">평균평점</h3> <div className="flex items-center justify-between"> <div className="mt-2 text-4xl font-bold"> - {boardStatisticsData?.averageRating.toFixed(1) || 0} + {boardStatisticsData?.bbsTotalDto?.pstEvlAvg?.toFixed(1) || 0} </div> <div className="h-16 w-24"> <Line @@ -278,7 +280,8 @@ function BoardStatisticsPage() { <h3 className="text-lg font-medium text-gray-500">총 조회수</h3> <div className="flex items-center justify-between"> <div className="mt-2 text-4xl font-bold"> - {boardStatisticsData?.totalViews.toLocaleString() || 0} + {boardStatisticsData?.bbsTotalDto?.pstInqCnt?.toLocaleString() || + 0} </div> <div className="h-16 w-24"> <Line @@ -315,7 +318,7 @@ function BoardStatisticsPage() { <h3 className="text-2xl font-medium">일별 게시물 현황</h3> </div> <div className="h-96 p-4"> - {boardStatisticsData?.dayList?.length ? ( + {boardStatisticsData?.bbsDailyList?.length ? ( <Line {...chartData.day(boardStatisticsData)} /> ) : ( <NoData /> @@ -329,7 +332,7 @@ function BoardStatisticsPage() { <h3 className="text-2xl font-medium">답변상태</h3> </div> <div className="h-96 p-4"> - {boardStatisticsData?.statusList?.length ? ( + {boardStatisticsData?.pstAnsList?.length ? ( <Doughnut {...chartData.status(boardStatisticsData)} /> ) : ( <NoData /> @@ -342,7 +345,7 @@ function BoardStatisticsPage() { <h3 className="text-2xl font-medium">게시판별 분포</h3> </div> <div className="h-96 p-4"> - {boardStatisticsData?.boardList?.length ? ( + {boardStatisticsData?.bbsPstCntList?.length ? ( <Bar {...chartData.board(boardStatisticsData)} /> ) : ( <NoData /> diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index ce6f61381..4f7f5ef9f 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -63,6 +63,7 @@ export const ENDPOINT = { POSTS: "/board-service/api/v1/posts", POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts", POST_EVALUATION: "/board-service/api/v1/pstEvl", + STATISTICS: "/board-service/api/v1/stat/bbs", }, }; From 912e335b279724a0511c7e625f1a9e7c799f445a Mon Sep 17 00:00:00 2001 From: bicochan <chanii8@naver.com> Date: Tue, 3 Feb 2026 17:48:15 +0900 Subject: [PATCH 79/92] =?UTF-8?q?[cs]=20feat:=20=EB=8C=80=EC=8B=9C?= =?UTF-8?q?=EB=B3=B4=EB=93=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=8B=A4?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EC=95=8C=EB=A6=BC=20=ED=8C=A8=EB=84=90=20?= =?UTF-8?q?=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/dashboard/api/dashboard-service.ts | 16 +++++++- .../dashboard/model/dashboard-interface.ts | 13 +++++++ .../src/pages/dashboard/ui/dashboard-page.tsx | 39 ++++++++++--------- apps/cs/src/shared/config/api.ts | 1 + .../src/ui/header/notice-popover.tsx | 15 +++---- 5 files changed, 58 insertions(+), 26 deletions(-) diff --git a/apps/cs/src/pages/dashboard/api/dashboard-service.ts b/apps/cs/src/pages/dashboard/api/dashboard-service.ts index 94bf807a1..784f1df82 100644 --- a/apps/cs/src/pages/dashboard/api/dashboard-service.ts +++ b/apps/cs/src/pages/dashboard/api/dashboard-service.ts @@ -1,6 +1,11 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; -import type { Dashboard, DashboardService } from "../model/dashboard-interface"; +import type { + Dashboard, + DashboardService, + NoticeUser, +} from "../model/dashboard-interface"; +import type { PageableList } from "@/shared/model"; export class DashboardApiService implements DashboardService { public async getDashboard(): Promise<Dashboard> { @@ -9,6 +14,15 @@ export class DashboardApiService implements DashboardService { ); return response.data; } + + public async getNoticeUserList( + recvUnqId: string, + ): Promise<PageableList<NoticeUser>> { + const response = await client.get<PageableList<NoticeUser>>( + `${ENDPOINT.CMS_SERVICE.NOTICE_USER}/${recvUnqId}/list`, + ); + return response.data; + } } export const DashboardApi = new DashboardApiService(); diff --git a/apps/cs/src/pages/dashboard/model/dashboard-interface.ts b/apps/cs/src/pages/dashboard/model/dashboard-interface.ts index 9e038eef7..77a4649cc 100644 --- a/apps/cs/src/pages/dashboard/model/dashboard-interface.ts +++ b/apps/cs/src/pages/dashboard/model/dashboard-interface.ts @@ -1,3 +1,5 @@ +import type { PageableList } from "@/shared/model"; + export interface SiteStatisticsContent { siteId: string; siteNm: string; @@ -27,6 +29,17 @@ export interface Dashboard { menuAccessList: MenuStatisticsContent[]; } +export interface NoticeUser { + notiId: number; + recvUnqId: string; + senderUnqId: string; + notiType: string; + notiTtl: string; + notReadYn: string; + regDt: string; +} + export interface DashboardService { getDashboard(): Promise<Dashboard>; + getNoticeUserList(recvUnqId: string): Promise<PageableList<NoticeUser>>; } diff --git a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx index 65fd0030a..32ea14966 100644 --- a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx +++ b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx @@ -1,5 +1,6 @@ "use client"; +import dayjs from "dayjs"; import { useRouter } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; import { getCoreRowModel } from "@tanstack/react-table"; @@ -17,8 +18,8 @@ import { } from "chart.js"; import { Bar, Line } from "react-chartjs-2"; import { PostApi, type RecentPost } from "@/entities/post"; -import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { AUTH_USER_ID, ENDPOINT } from "@/shared/config"; +import { getCookie, useDataTable } from "@/shared/lib"; import { DashboardApi } from "../api/dashboard-service"; import { chartData } from "../model/chart-data"; import { @@ -39,12 +40,21 @@ ChartJS.register( ); function DashboardPage() { + const userId = getCookie(AUTH_USER_ID) ?? ""; + const router = useRouter(); + const { data } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.DASHBOARD], queryFn: () => DashboardApi.getDashboard(), }); + const { data: noticeUserList } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER], + queryFn: () => DashboardApi.getNoticeUserList(userId), + enabled: !!userId, + }); + const noticePostQuery = useQuery({ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS], queryFn: () => @@ -323,22 +333,15 @@ function DashboardPage() { </div> <div className="p-4"> <div className="space-y-4 text-foreground"> - <div className="flex items-center justify-between border-b border-border pb-4"> - <span className="font-medium">신규 사용자 가입</span> - <span>{(1).toLocaleString()}분 전</span> - </div> - <div className="flex items-center justify-between border-b border-border pb-4"> - <span className="font-medium">메뉴 수정 요청</span> - <span>{(5).toLocaleString()}분 전</span> - </div> - <div className="flex items-center justify-between border-b border-border pb-4"> - <span className="font-medium">게시물 신고</span> - <span>{(10).toLocaleString()}분 전</span> - </div> - <div className="flex items-center justify-between"> - <span className="font-medium">컨텐츠 승인 요청</span> - <span>{(15).toLocaleString()}분 전</span> - </div> + {noticeUserList?.content?.map((item) => ( + <div + key={item.notiId} + className="flex items-center justify-between border-b border-border pb-4" + > + <span className="font-medium">{item.notiTtl}</span> + <span>{dayjs(item.regDt).fromNow()}</span> + </div> + ))} </div> </div> </div> diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index 4f7f5ef9f..db8eda72c 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -56,6 +56,7 @@ export const ENDPOINT = { APILOG: "/cms-service/api/v1/api-logs", SITE_AUTHORITY: "/cms-service/api/v1/site-authrt", CONNECTION_LOG: "/cms-service/api/v1/cntnlog", + NOTICE_USER: "/cms-service/api/v1/noti/user", }, BOARD_SERVICE: { BBS: "/board-service/api/v1/bbs", diff --git a/packages/common/components/src/ui/header/notice-popover.tsx b/packages/common/components/src/ui/header/notice-popover.tsx index 6ee35371b..251756a94 100644 --- a/packages/common/components/src/ui/header/notice-popover.tsx +++ b/packages/common/components/src/ui/header/notice-popover.tsx @@ -34,6 +34,7 @@ export function NoticePopover() { queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER], queryFn: () => getNoticeUserList(userId!), enabled: !!userId, + select: (data) => data.content.filter((item) => item.notReadYn === "N"), }); const { data: unreadNoticeCount } = useQuery({ @@ -53,11 +54,11 @@ export function NoticePopover() { }; const handleSelectAll = () => { - if (noticeUserList?.content) { - if (selectedNoticeIds.length === noticeUserList.content.length) { + if (noticeUserList) { + if (selectedNoticeIds.length === noticeUserList.length) { setSelectedNoticeIds([]); } else { - const allIds = noticeUserList.content.map((item) => item.notiId); + const allIds = noticeUserList.map((item) => item.notiId); setSelectedNoticeIds(allIds); } } @@ -79,9 +80,9 @@ export function NoticePopover() { } }; - const isAllSelected = noticeUserList?.content - ? selectedNoticeIds.length === noticeUserList.content.length && - noticeUserList.content.length > 0 + const isAllSelected = noticeUserList + ? selectedNoticeIds.length === noticeUserList.length && + noticeUserList.length > 0 : false; useEffect(() => { @@ -107,7 +108,7 @@ export function NoticePopover() { </Label> </div> <ul> - {noticeUserList?.content?.map((item) => ( + {noticeUserList?.map((item) => ( <li key={item.notiId} className={cn( From 7227b98961b2e50e49f13a416ab91e389ea567bf Mon Sep 17 00:00:00 2001 From: bicochan <chanii8@naver.com> Date: Wed, 4 Feb 2026 09:34:50 +0900 Subject: [PATCH 80/92] =?UTF-8?q?[cs]=20feat:=20=EB=8C=80=EC=8B=9C?= =?UTF-8?q?=EB=B3=B4=EB=93=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20=ED=8C=A8=EB=84=90=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/dashboard/api/dashboard-service.ts | 12 +++ .../dashboard/model/dashboard-interface.ts | 25 ++++++ .../src/pages/dashboard/ui/dashboard-page.tsx | 83 ++++++++++++++----- 3 files changed, 100 insertions(+), 20 deletions(-) diff --git a/apps/cs/src/pages/dashboard/api/dashboard-service.ts b/apps/cs/src/pages/dashboard/api/dashboard-service.ts index 784f1df82..998215864 100644 --- a/apps/cs/src/pages/dashboard/api/dashboard-service.ts +++ b/apps/cs/src/pages/dashboard/api/dashboard-service.ts @@ -4,6 +4,8 @@ import type { Dashboard, DashboardService, NoticeUser, + Schedule, + ScheduleQueryParams, } from "../model/dashboard-interface"; import type { PageableList } from "@/shared/model"; @@ -23,6 +25,16 @@ export class DashboardApiService implements DashboardService { ); return response.data; } + + public async getScheduleList( + params?: ScheduleQueryParams, + ): Promise<Schedule[]> { + const response = await client.get<Schedule[]>( + ENDPOINT.CMS_SERVICE.SCHEDULES, + { params }, + ); + return response.data; + } } export const DashboardApi = new DashboardApiService(); diff --git a/apps/cs/src/pages/dashboard/model/dashboard-interface.ts b/apps/cs/src/pages/dashboard/model/dashboard-interface.ts index 77a4649cc..e2a01173d 100644 --- a/apps/cs/src/pages/dashboard/model/dashboard-interface.ts +++ b/apps/cs/src/pages/dashboard/model/dashboard-interface.ts @@ -39,7 +39,32 @@ export interface NoticeUser { regDt: string; } +export interface Schedule { + schdlBgngDt: string; + schdlEndDt: string; + actualDate: string; + schdlSn: number; + siteId: string; + schdlTtl: string; + schdlSeCd: string; + schdlCn: string; + reptYn: string; + commSchdlYn: string; + atflCd: string | null; +} + +export interface ScheduleQueryParams { + siteId?: string; + schdlTtl?: string; + schdlSeCd?: string; + schdlBgngYmd?: string; + schdlEndYmd?: string; + reptYn?: string; + commSchdlYn?: string; +} + export interface DashboardService { getDashboard(): Promise<Dashboard>; getNoticeUserList(recvUnqId: string): Promise<PageableList<NoticeUser>>; + getScheduleList(params?: ScheduleQueryParams): Promise<Schedule[]>; } diff --git a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx index 32ea14966..d787a6ab7 100644 --- a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx +++ b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx @@ -18,7 +18,7 @@ import { } from "chart.js"; import { Bar, Line } from "react-chartjs-2"; import { PostApi, type RecentPost } from "@/entities/post"; -import { AUTH_USER_ID, ENDPOINT } from "@/shared/config"; +import { AUTH_USER_ID, ENDPOINT, SITE_ID } from "@/shared/config"; import { getCookie, useDataTable } from "@/shared/lib"; import { DashboardApi } from "../api/dashboard-service"; import { chartData } from "../model/chart-data"; @@ -53,6 +53,29 @@ function DashboardPage() { queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER], queryFn: () => DashboardApi.getNoticeUserList(userId), enabled: !!userId, + select: (data) => { + // 오늘 ~ 한 달 전 사이의 일정 + const today = dayjs().endOf("day"); + const monthAgo = dayjs().subtract(1, "month").startOf("day"); + return data.content?.filter((item) => { + const regDt = dayjs(item.regDt); + return ( + (regDt.isSame(monthAgo) || regDt.isAfter(monthAgo)) && + (regDt.isSame(today) || regDt.isBefore(today)) + ); + }); + }, + }); + + const { data: scheduleList } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.SCHEDULES], + queryFn: () => + DashboardApi.getScheduleList({ + siteId: SITE_ID, + schdlBgngYmd: dayjs().format("YYYY-MM-DD"), + schdlEndYmd: dayjs().add(1, "month").format("YYYY-MM-DD"), + commSchdlYn: "Y", + }), }); const noticePostQuery = useQuery({ @@ -333,7 +356,7 @@ function DashboardPage() { </div> <div className="p-4"> <div className="space-y-4 text-foreground"> - {noticeUserList?.content?.map((item) => ( + {noticeUserList?.map((item) => ( <div key={item.notiId} className="flex items-center justify-between border-b border-border pb-4" @@ -352,24 +375,44 @@ function DashboardPage() { </div> <div className="p-4"> <div className="space-y-4 text-foreground"> - <div className="flex items-center justify-between border-b border-border pb-4"> - <span className="font-medium"> - {(3).toLocaleString()}월 정기 시스템 점검 - </span> - <span>내일</span> - </div> - <div className="flex items-center justify-between border-b border-border pb-4"> - <span className="font-medium">서버 업데이트 예정</span> - <span>{(3).toLocaleString()}일 후</span> - </div> - <div className="flex items-center justify-between border-b border-border pb-4"> - <span className="font-medium">백업 스케줄</span> - <span>{(5).toLocaleString()}일 후</span> - </div> - <div className="flex items-center justify-between"> - <span className="font-medium">정기 보안 점검</span> - <span>{(7).toLocaleString()}일 후</span> - </div> + {scheduleList && scheduleList.length > 0 ? ( + scheduleList.map((schedule, index) => { + const today = dayjs(); + const scheduleDate = dayjs(schedule.actualDate); + const daysUntil = scheduleDate.diff(today, "day"); + + let timeText = ""; + if (daysUntil === 0) { + timeText = "오늘"; + } else if (daysUntil === 1) { + timeText = "내일"; + } else if (daysUntil > 1) { + timeText = `${daysUntil}일 후`; + } else { + timeText = scheduleDate.format("YYYY-MM-DD"); + } + + return ( + <div + key={schedule.schdlSn} + className={`flex items-center justify-between ${ + index < scheduleList.length - 1 + ? "border-b border-border pb-4" + : "" + }`} + > + <span className="font-medium"> + {schedule.schdlTtl} + </span> + <span>{timeText}</span> + </div> + ); + }) + ) : ( + <div className="text-center text-muted-foreground"> + 예정된 일정이 없습니다. + </div> + )} </div> </div> </div> From 206cd10844df87abcf31f1623a36f1d4f6d21525 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Wed, 4 Feb 2026 13:50:45 +0900 Subject: [PATCH 81/92] =?UTF-8?q?sn:=20=ED=95=98=EC=88=98=EA=B4=80?= =?UTF-8?q?=EB=A7=9D=EB=8F=84=20=ED=8C=9D=EC=97=85-=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=ED=95=AD=EB=AA=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/components/common/table.ts | 88 +++++++++++++++++-- .../map/searchModal/searchModal.tsx | 48 +++++----- .../map/searchModal/useBasicTab.ts | 28 ++++-- .../src/ui/map/lib/gis.core.js | 2 +- 4 files changed, 129 insertions(+), 37 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/components/common/table.ts b/apps/sn/app/(map-layout)/map/components/common/table.ts index 081e13d1f..2aa3d0ac5 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -27,7 +27,8 @@ export const MsSwagePplCol = [ // { id: 'ftre_smbol_cd', title: '지형지물부호코드' }, // { id: 'lyrTypeNm', title: '레이어타입명' }, ] -export const MsSwagePplCol2 = [ +// 하수관로 searchModal 기본정보tab +export const MsSwagePplCol2 = [ { id: 'rowNumber', title: '일련\n번호' }, { id: 'fcltMngNo', title: '시설\n관리번호' }, { id: 'instMngNo', title: '기관\n관리번호' }, @@ -44,13 +45,13 @@ export const MsSwagePplCol2 = [ { id: 'tmptMhlMngNo', title: '시점맨홀\n관리번호' }, { id: 'scendDpth', title: '종점깊이\n(m)' }, { id: 'scendMhlMngNo', title: '종점맨홀\n관리번호' }, - // { id: 'vrtcLen', title: '세로길이\n(m)' }, - // { id: 'wdthLen', title: '가로길이\n(m)' }, - // { id: 'fcltyShpCd', title: '시설물형태코드' }, + { id: 'vrtcLen', title: '세로길이\n(m)' }, + { id: 'wdthLen', title: '가로길이\n(m)' }, + { id: 'fcltyShpCd', title: '시설물형태코드' }, // { id: 'fid', title: 'FID' }, // { id: 'ftreSmbolCd', title: '지형지물부호코드' }, // { id: 'mngInstCd', title: '관리기관코드' }, - // { id: 'mqltCd', title: '재질코드' }, + { id: 'mqltCd', title: '재질코드' }, // { id: 'pbadmsEmdCd', title: '행정읍면동코드' }, // { id: 'usgCd', title: '용도코드' }, // { id: 'lyrTypeNm', title: '레이어타입명' }, @@ -69,6 +70,10 @@ export const MsSwagePplExcelCol = { 'tmptMhlMngNo': '시점맨홀 관리번호', 'scendDpth': '종점 깊이(m)', 'scendMhlMngNo': '종점맨홀 관리번호', + 'vrtcLen': '세로길이(m)', + 'wdthLen': '가로길이(m)', + 'fcltyShpCd': '시설물형태코드', + 'mqltCd': '재질코드', }; // 하수관로 용도 코드표 export const MS_SWAGE_PPL_USE_CODES = [ @@ -275,7 +280,80 @@ export const MS_SWAGE_PPL_CODES = [ { val: "MOP977", text: "전주용입상관" }, { val: "MOP978", text: "MD관" }, ]; +// 하수관로 'fcltyShpCd' '시설물형태코드' +export const MS_SWAGE_PPL_SHAPE = [ + { val: "FOR000 ", text: "미분류" }, + { val: "FOR001 ", text: "원형" }, + { val: "FOR002 ", text: "원추형" }, + { val: "FOR003 ", text: "원통형" }, + { val: "FOR004 ", text: "구형" }, + { val: "FOR005 ", text: "타원형" }, + { val: "FOR006 ", text: "난원" }, + { val: "FOR007 ", text: "반원형" }, + { val: "FOR010 ", text: "피라미드형" }, + { val: "FOR011 ", text: "사면체형" }, + { val: "FOR012 ", text: "기둥,축" }, + { val: "FOR013 ", text: "돛대,활대처럼 둥글고 긴 원재" }, + { val: "FOR014 ", text: "아치형" }, + { val: "FOR015 ", text: "다중아치형" }, + { val: "FOR016 ", text: "돔형" }, + { val: "FOR017 ", text: "고형체형" }, + + { val: "FOR020 ", text: "사각형" }, + { val: "FOR021 ", text: "평방형" }, + { val: "FOR022 ", text: "다이아몬드형" }, + { val: "FOR023 ", text: "사다리꼴" }, + { val: "FOR024 ", text: "각형" }, + { val: "FOR025 ", text: "마제형관" }, + { val: "FOR026 ", text: "태형" }, + + { val: "FOR030 ", text: "A형" }, + { val: "FOR031 ", text: "H형" }, + { val: "FOR032 ", text: "I형" }, + { val: "FOR033 ", text: "Y형" }, + { val: "FOR034 ", text: "T형" }, + + { val: "FOR050 ", text: "불규칙한 형태" }, + + { val: "FOR900 ", text: "계란형" }, + { val: "FOR901 ", text: "구(사각)형" }, + { val: "FOR902 ", text: "높이조절철개형" }, + { val: "FOR903 ", text: "박스형(RCB)" }, + { val: "FOR904 ", text: "반월개거" }, + { val: "FOR905 ", text: "반월개거(측구)" }, + { val: "FOR906 ", text: "벽돌조" }, + { val: "FOR907 ", text: "사각철판" }, + { val: "FOR908 ", text: "석축개거" }, + { val: "FOR909 ", text: "석축개거(측구)" }, + { val: "FOR910 ", text: "승수로" }, + { val: "FOR911 ", text: "옹벽개거" }, + { val: "FOR912 ", text: "옹벽개거(측구)" }, + { val: "FOR913 ", text: "이단" }, + { val: "FOR914 ", text: "이중침전형" }, + { val: "FOR915 ", text: "자연개거" }, + { val: "FOR916 ", text: "자연개거(측구)" }, + { val: "FOR917 ", text: "조립식" }, + { val: "FOR918 ", text: "지상관" }, + { val: "FOR919 ", text: "지상단구" }, + { val: "FOR920 ", text: "지상쌍구" }, + { val: "FOR921 ", text: "지하단구" }, + { val: "FOR922 ", text: "지하쌍구" }, + { val: "FOR923 ", text: "직사각형" }, + { val: "FOR924 ", text: "타설식" }, + { val: "FOR925 ", text: "토류형" }, + { val: "FOR926 ", text: "흄관원형" }, + { val: "FOR927 ", text: "L형측구" }, + { val: "FOR928 ", text: "LO형측구" }, + { val: "FOR929 ", text: "LU형측구" }, + { val: "FOR930 ", text: "PVC이중벽관" }, + { val: "FOR931 ", text: "RCB 맨홀" }, + { val: "FOR932 ", text: "U형" }, + { val: "FOR933 ", text: "U형측구(미복개)" }, + { val: "FOR934 ", text: "U형측구(복개)" }, + + { val: "FOR999 ", text: "기타" } +]; // 하수처리시설 export const SwtrmtFcltCol = [ { id: 'swtrmt_fclt_nm', title: '하수처리시설명' }, diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index 0906ce0ca..d179652f3 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -125,32 +125,30 @@ const SearchModal: React.FC = () => { {/* 📋 결과 리스트 */} {/* 기본정보 탭 */} {activeTab === 'basic' && ( - <div className="h-[79dvh] w-full rounded-lg border mt-4"> - {/* <div className="flex-1 px-2 pb-2"> */} + <div className="h-[79dvh] w-full rounded-lg border mt-4 overflow-x-scroll"> <LoadingOverlay isLoading={isLoading} /> - <UiTable - headName={(() => { - const label = BASIC_TYPES.find((type) => type.val === basicType)?.text - return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건</>); - })() - } - tableData={tableData} - headlist={dynamicHeadlist} - pageSize={10} - total={tableCount} - cellClick={handleBasicCellClick} - onPageChange={setCurPage} - resetPageNo={isResetPage} - resetSelection={isResetSelection} - curPage={curPage} - headButton={ - <div className='flex'> - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button> - <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button> - </div> - } - /> - {/* </div> */} + <UiTable className='w-[120%]' + headName={(() => { + const label = BASIC_TYPES.find((type) => type.val === basicType)?.text + return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건</>); + })() + } + tableData={tableData} + headlist={dynamicHeadlist} + pageSize={10} + total={tableCount} + cellClick={handleBasicCellClick} + onPageChange={setCurPage} + resetPageNo={isResetPage} + resetSelection={isResetSelection} + curPage={curPage} + headButton={ + <div className='flex'> + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button> + <Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button> + </div> + } + /> </div> )} {/* 유지관리 정보 탭 */} diff --git a/apps/sn/app/(map-layout)/map/searchModal/useBasicTab.ts b/apps/sn/app/(map-layout)/map/searchModal/useBasicTab.ts index 80d3deb50..9184286ed 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/useBasicTab.ts +++ b/apps/sn/app/(map-layout)/map/searchModal/useBasicTab.ts @@ -14,7 +14,7 @@ */ import { downloadExcelWithKoreanHeaders } from '@common/business_components/ui'; import { - MS_SWAGE_PPL_USE_CODES, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES, + MS_SWAGE_PPL_USE_CODES, MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_SHAPE, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES, MsSwagePplExcelCol, SwtrmtFcltExcelCol, SwtrmtPrcsZoneExcelCol, MsSwageMhlExcelCol, ExclnSewagePumpExcelCol, stofcbrExcelCol } from '../components/common/table'; import { getData } from "@/components/lib/api"; @@ -46,6 +46,7 @@ export default function useBasicTab() { } = useSearchModalStore(); const { ctpv, sgg } = useStore(); + const fetchBasicFilteredData = async () => { let cqlFilters: string[] = []; const queryParams = new URLSearchParams({ @@ -79,8 +80,15 @@ export default function useBasicTab() { if (!sggCd && code) sggCd = code.slice(0, 5); } - const matchedMhlCode = MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim()); - const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(code => code.val === item?.usgCd); + const matchedMqltCode = basicType === 'tb_ms_swage_ppl' + ? MS_SWAGE_PPL_CODES.find(code => code.val === item?.mqltCd?.trim()) // 하수관로 재질 + : basicType === 'tb_ms_swage_mhl' + ? MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim()) // 맨홀 재질 + : undefined; + const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(code => code.val === item?.usgCd); // 맨홀 용도 + const matchedPplShpCode = MS_SWAGE_PPL_SHAPE.find(code => code.val === item?.fcltyShpCd); // 하수관로 시설물형태코드 + + const ctpvNm = ctpv.find(code => code.val.trim() === ctpvCd)?.text || item?.ctpvNm; const sggNm = sgg.find(code => code.val.trim() === sggCd)?.text || item?.sggNm; const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim()); @@ -90,15 +98,17 @@ export default function useBasicTab() { ...formattedItem, rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가 scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item?.scsYn, // scsYn이 null이면 'N'으로 변경 - mqltCd: matchedMhlCode ? matchedMhlCode.text : item?.mqltCd, + mqltCd: matchedMqltCode ? matchedMqltCode.text : item?.mqltCd, usgCd: matchedMhlUsgCode ? matchedMhlUsgCode.text : (usgCdObj ? usgCdObj.text : item?.usgCd), ctpvNm: ctpvNm ?? '-', sggNm: sggNm ?? '-', swtrmt_zone_nm: item.swtrmtZoneNm || item.swtrmt_zone_nm || '-', + fcltyShpCd: matchedPplShpCode? matchedPplShpCode.text : item?.fcltyShpCd, }; }); setTableData(dataWithRowNumber); + // console.log(tableData); setTableCount(res.count || []); }; @@ -150,7 +160,7 @@ export default function useBasicTab() { // 하수관로 cqlFilters = swagePplCqlFilters() headerMapping = MsSwagePplExcelCol; - headerRange = "A1:M1"; + headerRange = "A1:Q1"; break; } case 'tb_il_swage_prcs_fclt': { @@ -196,6 +206,8 @@ export default function useBasicTab() { const mhlUsgCdMap = new Map(MS_SWAGE_MHL_USE_CODES.map(code => [code.val?.trim(), code.text])); const pplUsgCdMap = new Map(MS_SWAGE_PPL_USE_CODES.map(code => [code.val?.trim(), code.text])); + const pplMqltCdMap = new Map(MS_SWAGE_PPL_CODES.map(code => [code.val?.trim(), code.text])); + const pplShpCdMap = new Map(MS_SWAGE_PPL_SHAPE.map(code => [code.val?.trim(), code.text])); // 관로 시설물형태코드 const ctpvMap = new Map(ctpv.map(code => [code.val?.trim(), code.text])); const sggMap = new Map(sgg.map(code => [code.val?.trim(), code.text])); @@ -232,6 +244,10 @@ export default function useBasicTab() { tmptMhlMngNo: formattedItem.tmptMhlMngNo ?? item.tmptMhlMngNo ?? '-', scendDpth: formattedItem.scendDpth ?? item.scendDpth ?? '-', scendMhlMngNo: formattedItem.scendMhlMngNo ?? item.scendMhlMngNo ?? '-', + vrtcLen: formattedItem.vrtcLen ?? item.vrtcLen ?? '-', + wdthLen: formattedItem.wdthLen ?? item.wdthLen ?? '-', + fcltyShpCd: pplShpCdMap.get(item?.fcltyShpCd?.trim()) || item.fcltyShpCd || formattedItem.fcltyShpCd || '-', + mqltCd: pplMqltCdMap.get(item?.mqltCd?.trim()) || item.mqltCd || formattedItem.mqltCd || '-', }; } case 'tb_il_swage_prcs_fclt': { @@ -329,4 +345,4 @@ export default function useBasicTab() { return { fetchBasicFilteredData, handleBasicCellClick, basicExcelDownload }; -}; \ No newline at end of file +}; diff --git a/packages/common/business_components/src/ui/map/lib/gis.core.js b/packages/common/business_components/src/ui/map/lib/gis.core.js index e8e05f037..2e97e8af5 100644 --- a/packages/common/business_components/src/ui/map/lib/gis.core.js +++ b/packages/common/business_components/src/ui/map/lib/gis.core.js @@ -172,7 +172,7 @@ GisApp.core.prototype = { wmtsSource.setTileUrlFunction((tileCoord) => { const [z, x, y] = tileCoord; const matrix = matrixIds[z]; - console.log(GisApp.NGII_WMTS_URL.replace("{z}", matrix).replace("{x}", x).replace("{y}", y)); + // console.log(GisApp.NGII_WMTS_URL.replace("{z}", matrix).replace("{x}", x).replace("{y}", y)); return GisApp.NGII_WMTS_URL .replace("{z}", matrix) .replace("{x}", x) From 8565331e68dccf652cc5f9f0953141966f3af6fa Mon Sep 17 00:00:00 2001 From: bicochan <chanii8@naver.com> Date: Fri, 6 Feb 2026 11:26:40 +0900 Subject: [PATCH 82/92] =?UTF-8?q?[cs]=20feat:=20=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EC=96=BC=EB=A1=9C=EA=B7=B8=20=EB=8B=AB=ED=9E=90=20=EB=95=8C=20?= =?UTF-8?q?=ED=8F=BC=20=EB=B0=8F=20=EC=BF=BC=EB=A6=AC=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=B4=88=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/admin/ui/add-admin-dialog.tsx | 19 +++++++++- apps/cs/src/pages/code/ui/lwpocode-dialog.tsx | 6 ++- apps/cs/src/pages/code/ui/upcode-dialog.tsx | 6 ++- .../pages/groups/ui/menu-authority-dialog.tsx | 38 ++++++++++--------- .../module/ui/management-authority-dialog.tsx | 6 ++- .../src/pages/role/ui/mapping-role-dialog.tsx | 6 ++- 6 files changed, 58 insertions(+), 23 deletions(-) diff --git a/apps/cs/src/pages/admin/ui/add-admin-dialog.tsx b/apps/cs/src/pages/admin/ui/add-admin-dialog.tsx index 859af4058..c49d75530 100644 --- a/apps/cs/src/pages/admin/ui/add-admin-dialog.tsx +++ b/apps/cs/src/pages/admin/ui/add-admin-dialog.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { keepPreviousData, useQuery, @@ -75,7 +75,7 @@ function AddAdminDialog() { }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.USERS, pagination, "normal-user"], + queryKey: [ENDPOINT.USER_SERVICE.USERS, "findPageUser", pagination], queryFn: () => UserApi.findPageUser({ ...userSearchQuery, @@ -181,6 +181,21 @@ function AddAdminDialog() { query.refetch(); }; + useEffect(() => { + if (!open) { + setRowSelection({}); + setSelectedGroupId(""); + setUserSearchQuery({ + keywordType: "userName", + keyword: "", + }); + setPagination({ pageIndex: 0, pageSize: 10 }); + queryClient.removeQueries({ + queryKey: [ENDPOINT.USER_SERVICE.USERS, "findPageUser"], + }); + } + }, [open]); + return ( <Dialog open={open} onOpenChange={setOpen}> <DialogTrigger asChild> diff --git a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx index d21f5b60a..3179303dd 100644 --- a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx +++ b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx @@ -1,4 +1,4 @@ -import { memo } from "react"; +import { memo, useEffect } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery, useQueryClient } from "@tanstack/react-query"; @@ -140,6 +140,10 @@ const LwpoCodeManagementDialog = memo( } }; + useEffect(() => { + if (!open) form.reset(); + }, [open]); + return ( <Dialog open={open} onOpenChange={onOpenChange} {...props}> <DialogTrigger asChild>{children}</DialogTrigger> diff --git a/apps/cs/src/pages/code/ui/upcode-dialog.tsx b/apps/cs/src/pages/code/ui/upcode-dialog.tsx index fafb7429f..6774bd17e 100644 --- a/apps/cs/src/pages/code/ui/upcode-dialog.tsx +++ b/apps/cs/src/pages/code/ui/upcode-dialog.tsx @@ -1,4 +1,4 @@ -import { memo } from "react"; +import { memo, useEffect } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; @@ -96,6 +96,10 @@ const UpCodeManagementDialog = memo( if (await confirm(confirmMessage)) callback(data); }; + useEffect(() => { + if (!open) form.reset(); + }, [open]); + return ( <Dialog open={open} onOpenChange={onOpenChange} {...props}> <DialogTrigger asChild>{children}</DialogTrigger> diff --git a/apps/cs/src/pages/groups/ui/menu-authority-dialog.tsx b/apps/cs/src/pages/groups/ui/menu-authority-dialog.tsx index 38c6597fc..cde3cf641 100644 --- a/apps/cs/src/pages/groups/ui/menu-authority-dialog.tsx +++ b/apps/cs/src/pages/groups/ui/menu-authority-dialog.tsx @@ -1,4 +1,4 @@ -import { useState, useRef } from "react"; +import { useState, useRef, useEffect } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; @@ -48,25 +48,14 @@ function MenuAuthorityDialog({ groupId }: MenuAuthorityDialogProps) { keywordType: "", siteId: "", }); - - const handleReset = () => { - if (inputRef.current) inputRef.current.value = ""; - setKeywordType(""); - setSiteId(""); - setSearchParams({ - keyword: "", - keywordType: "", - siteId: "", - }); - }; - const query = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.MENU_AUTHRTS, groupId, searchParams], - queryFn: () => MenuAuthorityApi.getGroupMenuAuthorityList({ - groupId, - ...searchParams - }), + queryFn: () => + MenuAuthorityApi.getGroupMenuAuthorityList({ + groupId, + ...searchParams, + }), enabled: open && !!groupId, }); @@ -117,6 +106,21 @@ function MenuAuthorityDialog({ groupId }: MenuAuthorityDialogProps) { }); }; + const handleReset = () => { + if (inputRef.current) inputRef.current.value = ""; + setSiteId(""); + setKeywordType(""); + setSearchParams({ + keyword: "", + keywordType: "", + siteId: "", + }); + }; + + useEffect(() => { + if (!open) handleReset(); + }, [open]); + return ( <Dialog open={open} onOpenChange={setOpen}> <DialogTrigger asChild> diff --git a/apps/cs/src/pages/module/ui/management-authority-dialog.tsx b/apps/cs/src/pages/module/ui/management-authority-dialog.tsx index 0459ba804..b3e6f3fe5 100644 --- a/apps/cs/src/pages/module/ui/management-authority-dialog.tsx +++ b/apps/cs/src/pages/module/ui/management-authority-dialog.tsx @@ -1,4 +1,4 @@ -import { useState, memo } from "react"; +import { useState, memo, useEffect } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; @@ -90,6 +90,10 @@ const ManagementAuthorityDialog = memo( } }; + useEffect(() => { + if (!open) form.reset(); + }, [open]); + return ( <Dialog open={open} onOpenChange={setOpen}> <DialogTrigger asChild> diff --git a/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx b/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx index 5377f6a7b..e327fb88e 100644 --- a/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx +++ b/apps/cs/src/pages/role/ui/mapping-role-dialog.tsx @@ -1,4 +1,4 @@ -import { useState, useRef } from "react"; +import { useState, useRef, useEffect } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { getCoreRowModel, type ColumnDef } from "@tanstack/react-table"; import { @@ -113,6 +113,10 @@ function MappingRoleDialog({ }, }); + useEffect(() => { + if (!open) handleReset(); + }, [open]); + return ( <Dialog open={open} onOpenChange={onOpenChange} {...props}> <DialogTrigger asChild> From 21dd8f47a1ee5b8a075fae47cb5f082186089483 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Mon, 9 Feb 2026 18:18:11 +0900 Subject: [PATCH 83/92] =?UTF-8?q?wr:=20=EC=A7=80=EB=8F=84=EC=A0=90?= =?UTF-8?q?=EA=B2=80=EA=B2=B0=EA=B3=BC=20=EB=93=B1=EB=A1=9D=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EC=9A=B4=EC=98=81=EA=B4=80=EB=A6=AC=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EB=AA=85=EC=9C=BC=EB=A1=9C=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruseFcltMng/prfmncReg/chkgdnReg/page.tsx | 4 ++-- .../ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index aea5c4b39..0fe594630 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -94,7 +94,7 @@ export default function Page() { const cellClick = () => { if (searchYear) - if (selFcltDiv === "RNB") { + if (selFcltDiv === "RNB") { // 빗물 if (fcltNm) { rainChkNmSearch( rainPageNation, @@ -107,7 +107,7 @@ export default function Page() { } else { rainChkInit(rainPageNation, rainPageSize, searchYear, laeSeCd); } - } else { + } else { // 중수도 if (fcltNm) { rswtChkNmSearch( rainPageNation, diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index e931cf706..3a59edb49 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -13,6 +13,7 @@ import { chRowspanTable, rswtChkTableData, } from "@/components/lib/func/TableData"; +import { codeToText } from "@/components/lib/func/commom"; import UiPageNations from "@common/business_components/ui/table/uiPageNations"; import { Table, TableBody, TableHeader } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; @@ -99,9 +100,16 @@ export default function RswtChkgdTable({ const tableTotalData = rswtChkTableData(rswtChkData); const makeRswtChkData = tableTotalData.map((item: any) => { const bud = tableData([item.building], { code }); + // 운영관리형태 코드 → 한글 텍스트로 치환 (빗물 화면과 동일한 표시) + const operMngCdText = + codeToText(item.operMngCd?.trim(), "rainRswtMng") ?? + codeToText(item.reuseBuilding?.operMngCd?.trim(), "rainRswtMng") ?? + item.operMngCd; + return { ...item, ...bud[0], + operMngCd: operMngCdText, rowspan: item.rswtrDetails?.length, }; }); From 8d481aab099d61ad157f2550c6e18bc299a1fc99 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 9 Feb 2026 21:40:02 +0900 Subject: [PATCH 84/92] =?UTF-8?q?fo:=20=EC=B2=98=EB=A6=AC=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=20=EC=8B=9C=EC=84=A4=EC=A0=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../processFacility/modal/page.tsx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx index 7e3f7c52f..512b0be19 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx @@ -5,6 +5,7 @@ */ "use client" +import { useCallback, useRef } from "react"; import { useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/dashboard"; import { downloadExcelFormat, filePickedBlobArray, UITab, UiTable } from "@common/business_components/ui"; @@ -121,6 +122,21 @@ export default function ProcessFacilityInfoModal(props: ModalType) { const upHeadListPlanInfoChange = headMakeList(upHeadListPlanInfo, 2); const upHeadListFcltyHistInfoChange = headMakeList(upHeadListFcltyHistInfo, 3); const upHeadListFcltyWaterQltyInfoChange = headMakeList(upHeadListFcltyWaterQltyInfo, 4); + const historyTopScrollRef = useRef<HTMLDivElement>(null); + const historyBottomScrollRef = useRef<HTMLDivElement>(null); + const syncLockRef = useRef(false); + + const syncScroll = useCallback((source: HTMLDivElement | null, target: HTMLDivElement | null) => { + if (!source || !target || syncLockRef.current) return; + syncLockRef.current = true; + const nextTop = source.scrollTop; + if (target.scrollTop !== nextTop) { + target.scrollTop = nextTop; + } + requestAnimationFrame(() => { + syncLockRef.current = false; + }); + }, []); const excelDownloadPlan = () => { const excelDownList: any[] = []; @@ -218,7 +234,7 @@ export default function ProcessFacilityInfoModal(props: ModalType) { <h3 className="text-2xl font-medium text-label">시설 기본정보</h3> </div> <div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r"> - <Table> + <Table variant="secondary"> <thead> <TableRow className=""> <TableHead className="w-1/6">{'시설명'}</TableHead> @@ -262,7 +278,11 @@ export default function ProcessFacilityInfoModal(props: ModalType) { <TabsContent value="history_info"> <ListDiv> - <div className="h-[250px] w-full overflow-y-auto overflow-x-hidden"> + <div + className="h-[250px] w-full overflow-y-auto overflow-x-hidden" + ref={historyTopScrollRef} + onScroll={() => syncScroll(historyTopScrollRef.current, historyBottomScrollRef.current)} + > <Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownloadPlan}> {"엑셀다운로드"} </Button> @@ -274,7 +294,11 @@ export default function ProcessFacilityInfoModal(props: ModalType) { </div> </ListDiv> <ListDiv> - <div className="h-[250px] w-full overflow-y-auto overflow-x-hidden"> + <div + className="h-[250px] w-full overflow-y-auto overflow-x-hidden" + ref={historyBottomScrollRef} + onScroll={() => syncScroll(historyBottomScrollRef.current, historyTopScrollRef.current)} + > <Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownloadQlty}> {"엑셀다운로드"} </Button> @@ -292,4 +316,4 @@ export default function ProcessFacilityInfoModal(props: ModalType) { </div> </> ); -} \ No newline at end of file +} From 3787f824df88b6b879e18c7d36a1830c1d7a2eea Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 9 Feb 2026 22:38:10 +0900 Subject: [PATCH 85/92] =?UTF-8?q?fo:=20exceldown=EC=8B=9C=20,=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../facilityPrecipitation/page.tsx | 7 ++-- .../(with-layout)/facilityWaterQlty/page.tsx | 3 +- .../pages/(with-layout)/planSewage/page.tsx | 32 ++++++++++++++--- .../pages/(with-layout)/processArea/page.tsx | 11 ++++-- .../(with-layout)/processFacility/page.tsx | 10 ++++-- apps/fo/app/pages/(with-layout)/rdi/page.tsx | 36 ++++++++++++++++--- .../pages/(with-layout)/sewageOccur/page.tsx | 34 +++++++++++++++--- .../(with-layout)/underWaterInput/page.tsx | 33 ++++++++++++++--- 8 files changed, 140 insertions(+), 26 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx index 7fd141694..9570320d4 100644 --- a/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityPrecipitation/page.tsx @@ -7,7 +7,7 @@ "use client" import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; -import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; import PrecipitationModal from "./modal/page"; @@ -212,11 +212,12 @@ export default function FacilityPrecipitation() { await searchFacilityPrecipitation(searchReturn, 1, 10000); const latestExcelList = store.getState().FacilityPrecipitation.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ + downloadExcelFormat({ data: latestExcelList as unknown as JSON[], fileName: '시설별 강수현황', sheetNameArray: ['시설별 강수현황'], - headerRange: 'A1:N1' + headerRange: 'A1:N1', + decimalArray0: [9, 11, 12, 13], }); } else { alert("조회된 결과가 없습니다."); diff --git a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx index 265c9788f..a90929225 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/page.tsx @@ -191,8 +191,7 @@ export default function ProcessFacilitySearch() { fileName: '시설별 수질현황', sheetNameArray: ['시설별 수질현황'], headerRange: 'A1:T1', - decimalArray1: [10, 11, 12, 15, 16, 17], - decimalArray3: [13, 14, 18, 19] + decimalArray0: [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] } ); } else { diff --git a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx index 8b41524d1..bdfd9c4b4 100644 --- a/apps/fo/app/pages/(with-layout)/planSewage/page.tsx +++ b/apps/fo/app/pages/(with-layout)/planSewage/page.tsx @@ -7,7 +7,7 @@ "use client" import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; -import { downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; +import { downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; @@ -197,11 +197,35 @@ export default function PlanSewage() { await searchPlanSewage(searchReturn, 1, 10000); const latestExcelList = store.getState().PlanSewage.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ - data: latestExcelList as unknown as JSON[], + const toNumber = (value: unknown) => { + if (value === null || value === undefined || value === '') return ''; + const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, "")); + return Number.isFinite(parsed) ? parsed : ''; + }; + + const numericKeys = [ + "시설용량(m³/일)", + "여유용량(m³/일)", + "변동부하율(%)", + "분류식화율(%)", + ]; + + const excelData = latestExcelList.map((row) => { + const nextRow = { ...row } as Record<string, unknown>; + numericKeys.forEach((key) => { + if (key in nextRow) { + nextRow[key] = toNumber(nextRow[key]); + } + }); + return nextRow; + }); + + downloadExcelFormat({ + data: excelData as unknown as JSON[], fileName: '계획하수량 산정지표 현황', sheetNameArray: ['계획하수량 산정지표 현황'], - headerRange: 'A1:M1' + headerRange: 'A1:M1', + decimalArray0: [9, 10, 11, 12] }); } else { alert("조회된 결과가 없습니다."); diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 84d8ee8b1..60dfff2cc 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -7,7 +7,7 @@ "use client" import { StoreContext, useFoStore } from "@/app/store"; import { useShallow } from 'zustand/react/shallow'; -import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; import ProcessFacilityInfoModal from "./modal/page"; @@ -155,11 +155,16 @@ export default function ProcessArea() { await searchProcessArea(ref.current, 1, 10000); const latestExcelList = store.getState().ProcessArea.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ + downloadExcelFormat({ data: latestExcelList as unknown as JSON[], fileName: '처리구역정보', sheetNameArray: ['처리구역정보'], - headerRange: 'A1:W1' + headerRange: 'A1:W1', + decimalArray0: [ + 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, + 17, 18, 19, 20, 21 + ] }); } else { alert('조회된 결과가 없습니다.'); diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index e73213bb1..76546b4d7 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -7,7 +7,7 @@ "use client" import UnderComment from "@/app/components/common/UnderComment"; import { StoreContext, useFoStore } from "@/app/store"; -import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; @@ -258,7 +258,13 @@ export default function ProcessFacilitySearch() { await searchFcltyList(ref.current, 1, 10000); const latestExcelList = store.getState().ProcessFacilityList.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ data: latestExcelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' }); + downloadExcelFormat({ + data: latestExcelList as unknown as JSON[], + fileName: '처리시설 시설정보', + sheetNameArray: ['처리시설 시설정보'], + headerRange: 'A1:P1', + decimalArray0: [9, 10, 11], + }); } else { alert('조회된 결과가 없습니다.'); } diff --git a/apps/fo/app/pages/(with-layout)/rdi/page.tsx b/apps/fo/app/pages/(with-layout)/rdi/page.tsx index 459cd44ca..ff4b8d205 100644 --- a/apps/fo/app/pages/(with-layout)/rdi/page.tsx +++ b/apps/fo/app/pages/(with-layout)/rdi/page.tsx @@ -7,7 +7,7 @@ "use client" import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; -import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; +import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; @@ -195,11 +195,39 @@ export default function Rdi() { await searchRdi(ref.current, 1, 5000); const latestExcelList = store.getState().Rdi.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ - data: latestExcelList as unknown as JSON[], + const toNumber = (value: unknown) => { + if (value === null || value === undefined || value === '') return ''; + const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, "")); + return Number.isFinite(parsed) ? parsed : ''; + }; + + const numericKeys = [ + "시설용량(m³/일)", + "청천시유입하수량(m³/일)", + "하절기강우일최저유입BOD(mg/L)", + "하절기최저유입BOD유입유량(m³/일)", + "동절기청천시유입BOD(mg/L)", + "RDII추정", + "RDII추정시일강수량(mm)", + "강우시총추정유입량(m³/일)", + ]; + + const excelData = latestExcelList.map((row) => { + const nextRow = { ...row } as Record<string, unknown>; + numericKeys.forEach((key) => { + if (key in nextRow) { + nextRow[key] = toNumber(nextRow[key]); + } + }); + return nextRow; + }); + + downloadExcelFormat({ + data: excelData as unknown as JSON[], fileName: 'RDII추정', sheetNameArray: ['RDII추정'], - headerRange: 'A1:R1' + headerRange: 'A1:R1', + decimalArray0: [9, 10, 11, 12, 13, 14, 15, 16], }); } else { alert("조회된 결과가 없습니다."); diff --git a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx index 4dc3125d1..95aa8961a 100644 --- a/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx +++ b/apps/fo/app/pages/(with-layout)/sewageOccur/page.tsx @@ -9,7 +9,7 @@ import { StoreContext, useFoStore } from "@/app/store"; import { type TableUpperProps } from "@/app/store/common"; import type { SewageOccurProps } from "@/app/store/sewageOccur"; -import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import LoadingOverlay from "@common/business_components/ui/loadingBar"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; @@ -210,11 +210,37 @@ export default function PlanSewage() { await searchFacilityPrecipitation(ref.current, 1, 5000); const latestExcelList = store.getState().SewageOccur.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ - data: latestExcelList as unknown as JSON[], + const toNumber = (value: unknown) => { + if (value === null || value === undefined || value === '') return ''; + const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, "")); + return Number.isFinite(parsed) ? parsed : ''; + }; + + const numericKeys = [ + "시설용량(m³/일)", + "물사용량(m³/일)", + "오수전환율(%)", + "오수발생량추정(m³/일)", + "연간하수유입량(m³/일)", + "청천시하수유입량(m³/일)", + ]; + + const excelData = latestExcelList.map((row) => { + const nextRow = { ...row } as Record<string, unknown>; + numericKeys.forEach((key) => { + if (key in nextRow) { + nextRow[key] = toNumber(nextRow[key]); + } + }); + return nextRow; + }); + + downloadExcelFormat({ + data: excelData as unknown as JSON[], fileName: '오수발생량 추정', sheetNameArray: ['오수발생량 추정'], - headerRange: 'A1:O1' + headerRange: 'A1:O1', + decimalArray0: [9, 10, 11, 12, 13, 14] }); } else { alert("조회된 결과가 없습니다."); diff --git a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx index 4404403e3..36fbff308 100644 --- a/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx +++ b/apps/fo/app/pages/(with-layout)/underWaterInput/page.tsx @@ -9,7 +9,7 @@ "use client" import { StoreContext, useFoStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common"; -import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; +import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; import UnderWaterInputModal from "./modal/page"; @@ -216,11 +216,36 @@ export default function UnderWaterInput() { await searchFacilityPrecipitation(ref.current, 1, 5000); const latestExcelList = store.getState().UnderWater.excelList || []; if (latestExcelList.length > 0) { - downloadExcel({ - data: latestExcelList as unknown as JSON[], + const toNumber = (value: unknown) => { + if (value === null || value === undefined || value === '') return ''; + const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, "")); + return Number.isFinite(parsed) ? parsed : ''; + }; + + const numericKeys = [ + "시설용량(m³/일)", + "평균유입하수량(m³/일)", + "연간지하수유입량(m³/일)", + "하절기지하수유입량(m³/일)", + "동절기지하수유입량(m³/일)", + ]; + + const excelData = latestExcelList.map((row) => { + const nextRow = { ...row } as Record<string, unknown>; + numericKeys.forEach((key) => { + if (key in nextRow) { + nextRow[key] = toNumber(nextRow[key]); + } + }); + return nextRow; + }); + + downloadExcelFormat({ + data: excelData as unknown as JSON[], fileName: '지하수유입량 추정', sheetNameArray: ['지하수유입량 추정'], - headerRange: 'A1:O1' + headerRange: 'A1:O1', + decimalArray0: [9, 10, 11, 12, 13] }); } else { alert("조회된 결과가 없습니다."); From aacf652dac15d4be3fb559d49c1afea9aa40cc22 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Mon, 9 Feb 2026 23:14:23 +0900 Subject: [PATCH 86/92] =?UTF-8?q?fo:=20=EC=B2=98=EB=A6=AC=EC=8B=9C?= =?UTF-8?q?=EC=84=A4=20=ED=8C=9D=EC=97=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/pages/(with-layout)/processFacility/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 76546b4d7..75bd371e0 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -327,7 +327,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( <UiModal body={<ProcessFacilityInfoModal fcltyName={modalFcltyNm} facilityCd={modalFcltyCd} sido={modalSido} gugun={modalGugun} daddr={modalAddr} fctCpc={modalFctCpc} trtFrfNm={modalTrtFrfNm} rnDt={modalRnDt} cmplDt={modalCmplDt} trstOprEtpNm={modalTrstOprEtpNm} bscFctClsNm={modalBscFctClsNm} mnstr={modalMnstr} efflWtrrgn={modalEfflWtrrgn} lgbsn={modalLgbsn} efflWqltStndrdNm={modalEfflWqltStndrdNm} rgnNm={modalRgnNm} rvbsn={modalRvbsn}></ProcessFacilityInfoModal>} - bodyClass="sm:max-w-[70vw] h-[100dvh] max-h-[800px]" + bodyClass="sm:max-w-[100vw] w-[1100px] h-[100dvh] max-h-[800px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} /> From c5816985918a0571966a9d831e15d800c7e533ee Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 10 Feb 2026 10:13:32 +0900 Subject: [PATCH 87/92] =?UTF-8?q?fo:=20=EA=B3=B5=EB=B2=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(with-layout)/processFacility/modal/page.tsx | 10 +++++++++- .../pages/(with-layout)/processFacility/page.tsx | 2 +- apps/fo/app/store/processFacility/index.tsx | 15 ++++++++++++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx index 512b0be19..20c885797 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx @@ -153,11 +153,19 @@ export default function ProcessFacilityInfoModal(props: ModalType) { "시운전완료일": item.trlrnCmplDt, "가동개시일": item.rnDt, "시설용량(m³/일)": item.fctCpc&&item.fctCpc.toString().trim()!=''?Number(item.fctCpc.toString().replaceAll(',','')):'', + "공법구분": item.trtSrsHanNm, + "공법계열": item.trtMocHanNm, + "방법": item.trtFrfHanNm, }); }); } if (excelDownList && excelDownList.length > 0) { - downloadExcelFormat({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.fcltyName + ' 시설이력관리', sheetNameArray: [props.fcltyName + ' 시설이력관리'], headerRange: 'A1:I1' }); + downloadExcelFormat({ + data: JSON.parse(JSON.stringify(excelDownList)), + fileName: props.fcltyName + ' 시설이력관리', + sheetNameArray: [props.fcltyName + ' 시설이력관리'], + decimalArray0: [8], + headerRange: 'A1:L1' }); } else if (gridListFcltyHistInfo.length == 0) { alert('다운받을 데이터가 없습니다.'); } diff --git a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx index 75bd371e0..def1ca0e8 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/page.tsx @@ -327,7 +327,7 @@ export default function ProcessFacilitySearch() { {selectedRow !== null && ( <UiModal body={<ProcessFacilityInfoModal fcltyName={modalFcltyNm} facilityCd={modalFcltyCd} sido={modalSido} gugun={modalGugun} daddr={modalAddr} fctCpc={modalFctCpc} trtFrfNm={modalTrtFrfNm} rnDt={modalRnDt} cmplDt={modalCmplDt} trstOprEtpNm={modalTrstOprEtpNm} bscFctClsNm={modalBscFctClsNm} mnstr={modalMnstr} efflWtrrgn={modalEfflWtrrgn} lgbsn={modalLgbsn} efflWqltStndrdNm={modalEfflWqltStndrdNm} rgnNm={modalRgnNm} rvbsn={modalRvbsn}></ProcessFacilityInfoModal>} - bodyClass="sm:max-w-[100vw] w-[1100px] h-[100dvh] max-h-[800px]" + bodyClass="sm:max-w-[100vw] w-[1300px] h-[100dvh] max-h-[800px]" open={selectedRow !== null} onOpenChange={(open) => !open && closeModal()} /> diff --git a/apps/fo/app/store/processFacility/index.tsx b/apps/fo/app/store/processFacility/index.tsx index 240ad2d4d..006185e6d 100644 --- a/apps/fo/app/store/processFacility/index.tsx +++ b/apps/fo/app/store/processFacility/index.tsx @@ -113,7 +113,10 @@ export type fcltyHistInfoProps = { sitArea: number, trtDstrArea: number, swrTrtPopl: number, - fctCpc: number | '' + fctCpc: number | '', + trtSrsHanNm?: string, // 공법구분 + trtMocHanNm?: string, // 공법계열 + trtFrfHanNm?: string, // 방법 } // 시설 수질정보 @@ -328,6 +331,9 @@ const upHeadListFcltyHistInfo: TableUpperProps[] = [ { id: "trlrnCmplDt", title: "시운전완료일" }, { id: "rnDt", title: "가동개시일" }, { id: "fctCpc", title: "시설용량(m³/일)", align: 'right' }, + { id: "trtSrsHanNm", title: "공법구분" }, + { id: "trtMocHanNm", title: "공법계열" }, + { id: "trtFrfHanNm", title: "방법" }, ]; // 시설 이력관리 (리스트) @@ -344,7 +350,10 @@ const gridListFcltyHistInfo: fcltyHistInfoProps[] = [ sitArea: 0, trtDstrArea: 0, swrTrtPopl: 0, - fctCpc: 860000 + fctCpc: 860000, + trtFrfHanNm: "", + trtMocHanNm: "", + trtSrsHanNm: "", } ]; @@ -902,4 +911,4 @@ export const processFacilityReducer: (set: SetStateFunction) => ProcessFacilityA } } } -} \ No newline at end of file +} From a7d7ffb7673c9fd9bfcc241337cc502dcd8f7e12 Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 10 Feb 2026 13:49:48 +0900 Subject: [PATCH 88/92] =?UTF-8?q?wr:=20chRowspanTable=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/components/lib/func/TableData.tsx | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index 1a66802f5..0c613bed0 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -190,12 +190,10 @@ export const chRowspanTable = ( value={formatCommaNumber(value) || ""} disabled={!selectedIds.includes(row.chkgdnSn)} maxLength={numSize} - onInput={(e: React.ChangeEvent<HTMLInputElement>) => { - if ( - head.type === "number" && - e.target.value.length > numSize - ) { - e.target.value = e.target.value.slice(0, numSize); + onInput={(e: React.FormEvent<HTMLInputElement>) => { + const el = e.currentTarget; + if (head.type === "number" && el.value.length > numSize) { + el.value = el.value.slice(0, numSize); } }} /> @@ -225,12 +223,10 @@ export const chRowspanTable = ( value={value || ""} disabled={!selectedIds.includes(row.chkgdnSn)} maxLength={numSize} - onInput={(e: React.ChangeEvent<HTMLInputElement>) => { - if ( - head.type === "number" && - e.target.value.length > numSize - ) { - e.target.value = e.target.value.slice(0, numSize); + onInput={(e: React.FormEvent<HTMLInputElement>) => { + const el = e.currentTarget; + if (head.type === "number" && el.value.length > numSize) { + el.value = el.value.slice(0, numSize); } }} /> From c8912357b2821af700186fd93a211839aeccb07f Mon Sep 17 00:00:00 2001 From: ljpark <mind-one005@mind-one.co.kr> Date: Tue, 10 Feb 2026 18:02:47 +0900 Subject: [PATCH 89/92] =?UTF-8?q?fo:=20exceldowntl=20,=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=ED=91=9C=EB=A1=9C=EB=B3=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/dashboard/page.tsx | 22 ++- .../src/ui/excel/index.tsx | 137 +++++++++++++++--- 2 files changed, 135 insertions(+), 24 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index 833f706ed..8728cfe1d 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -7,7 +7,7 @@ "use client" import { useFoStore } from "@/app/store"; import { - ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv + ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv, downloadExcelFormat , SelectBox, UITab, type SelectDataType } from "@common/business_components"; import { Button, TabsContent } from "@common/components/ui"; @@ -142,13 +142,11 @@ export default function DashBoard() { } } - const excelDownload = () => { + const excelDownload = async () => { if (!fcltyList.bscFctCd) return; switch (activeTab) { case 'facilityInfo': // 시설정보 및 운영현황 - searchOperationStatus(false, searchYear, fcltyList.bscFctCd).then(() => { setTimeout(() => { makeExcelData(); }, 200); }); - const makeExcelData = async () => { fetch(`/mainDashBoard.xlsx`, {}).then(async (response) => { if (!response.ok) { @@ -198,20 +196,26 @@ export default function DashBoard() { headerNum: 3, headerRange: 'A1:G2', sheetName: '운영실태', - startCol: 'A' + startCol: 'A', + decimalRange0: 'B9:B11', }, { data: excelData2, headerNum: 4, headerRange: 'A1:Q3', sheetName: '운영실태', - startCol: 'C' + startCol: 'C', + decimalRange0: 'C4:O8', + decimalRange1: 'C9:L10,M11:O11', + decimalRange3: 'C11:L16', } ]; // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 await filePickedBlobArray(blobRet, '시설정보및운영현황', sheetParameter); }); }; + await searchOperationStatus(false, searchYear, fcltyList.bscFctCd); + await makeExcelData(); break; case 'mainGraph': // 주요그래프 @@ -262,7 +266,11 @@ export default function DashBoard() { case 'rainManage': // 강우일 운영현황 searchRainManage(searchYear, fcltyList.bscFctCd, true); if (excelList && excelList.length > 0) { - downloadExcel({ data: excelList as unknown as JSON[], fileName: '강우일 운영현황', sheetNameArray: ['강우일 운영현황'], headerRange: 'A1:T1' }); + downloadExcel({ + data: excelList as unknown as JSON[], + fileName: '강우일 운영현황', + sheetNameArray: ['강우일 운영현황'], + headerRange: 'A1:T1' }); } break; // Add other cases for different tabs as needed diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index 048a0cc42..662705837 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -11,6 +11,10 @@ type ExcelDownloadProps = { decimalArray1? : number[]; decimalArray2? : number[]; decimalArray3? : number[]; + decimalRange0?: string; + decimalRange1?: string; + decimalRange2?: string; + decimalRange3?: string; } export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3'}: ExcelDownloadProps) => { @@ -29,7 +33,20 @@ export const downloadExcelHeaders = ({ data, fileName = new Date().getTime().toS excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); }; -export const downloadExcelFormat = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', decimalArray0=[], decimalArray1=[], decimalArray2=[], decimalArray3=[]}: ExcelDownloadProps) => { +export const downloadExcelFormat = ({ + data, + fileName = new Date().getTime().toString() + '.xlsx', + sheetNameArray = ["Sheet1"], + headerRange = 'A1:V3', + decimalArray0 = [], + decimalArray1 = [], + decimalArray2 = [], + decimalArray3 = [], + decimalRange0, + decimalRange1, + decimalRange2, + decimalRange3, +}: ExcelDownloadProps) => { const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]); @@ -61,10 +78,35 @@ export const downloadExcelFormat = ({ data, fileName = new Date().getTime().toSt } } }; + const applyRangeFormat = (rangeStr: string | undefined, decimal: number) => { + if (!rangeStr) return; + const rangeInfo = XLSX.utils.decode_range(rangeStr); + for (let row = rangeInfo.s.r; row <= rangeInfo.e.r; row++) { + for (let col = rangeInfo.s.c; col <= rangeInfo.e.c; col++) { + const cellAddr = XLSX.utils.encode_cell({ r: row, c: col }); + const cell = worksheet[cellAddr]; + if (cell && typeof cell.v === "number") { + if (decimal === 1) { + cell.z = "#,##0.0"; + } else if (decimal === 2) { + cell.z = "#,##0.00"; + } else if (decimal === 3) { + cell.z = "#,##0.000"; + } else { + cell.z = "#,##0"; + } + } + } + } + }; chaneValue(decimalArray0, 0); chaneValue(decimalArray1, 1); chaneValue(decimalArray2, 2); chaneValue(decimalArray3, 3); + applyRangeFormat(decimalRange0, 0); + applyRangeFormat(decimalRange1, 1); + applyRangeFormat(decimalRange2, 2); + applyRangeFormat(decimalRange3, 3); excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName); }; @@ -74,6 +116,10 @@ export type SheetParameter = { headerRange: string; sheetName: string; startCol?: string; + decimalRange0?: string; + decimalRange1?: string; + decimalRange2?: string; + decimalRange3?: string; }; export const downloadMultipleExcel = (fileName = new Date().getTime().toString() + '.xlsx', sheetArray: SheetParameter[]): Promise<JSON | undefined> => { @@ -201,23 +247,80 @@ export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, header }); } -export const filePickedBlobArray = (oFile: ArrayBuffer, fileNm: string, sheetArray: SheetParameter[]): Promise<JSON | undefined> => { - return new Promise<JSON | undefined>(async () => { - const wb = XLSX.read(oFile, { type: 'binary' }); - wb.SheetNames.forEach(function (sheetName, index) { - if (sheetArray[index]) { - const sheet = wb.Sheets[sheetName]; - if (sheet) { - const startCol = sheetArray[index].startCol ? sheetArray[index].startCol : 'A'; - XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, { origin: startCol + sheetArray[index].headerNum }); - } else { - console.error(`Sheet "${sheetName}" is undefined.`); - } +// export const filePickedBlobArray = (oFile: ArrayBuffer, fileNm: string, sheetArray: SheetParameter[]): Promise<JSON | undefined> => { +// return new Promise<JSON | undefined>(async () => { +// const wb = XLSX.read(oFile, { type: 'binary' }); +// wb.SheetNames.forEach(function (sheetName, index) { +// if (sheetArray[index]) { +// const sheet = wb.Sheets[sheetName]; +// if (sheet) { +// const startCol = sheetArray[index].startCol ? sheetArray[index].startCol : 'A'; +// XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, { origin: startCol + sheetArray[index].headerNum }); +// } else { +// console.error(`Sheet "${sheetName}" is undefined.`); +// } +// } +// }); +// await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm) +// }); +// } +export const filePickedBlobArray = async ( + oFile: ArrayBuffer, + fileNm: string, + sheetArray: SheetParameter[] +): Promise<JSON | undefined> => { + const wb = XLSX.read(oFile, { type: "binary" }); + + wb.SheetNames.forEach((sheetName, index) => { + if (sheetArray[index]) { + const sheet = wb.Sheets[sheetName]; + if (sheet) { + const startCol = sheetArray[index].startCol ?? "A"; + XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, { + origin: startCol + sheetArray[index].headerNum, + }); + const applyRangeFormat = (rangeStr: string | undefined, decimal: number) => { + if (!rangeStr) return; + const parts = rangeStr.split(",").map((part) => part.trim()).filter(Boolean); + for (const part of parts) { + const rangeInfo = XLSX.utils.decode_range(part); + for (let row = rangeInfo.s.r; row <= rangeInfo.e.r; row++) { + for (let col = rangeInfo.s.c; col <= rangeInfo.e.c; col++) { + const cellAddr = XLSX.utils.encode_cell({ r: row, c: col }); + const cell = sheet[cellAddr]; + if (cell && typeof cell.v === "number") { + if (decimal === 1) { + cell.z = "#,##0.0"; + } else if (decimal === 2) { + cell.z = "#,##0.00"; + } else if (decimal === 3) { + cell.z = "#,##0.000"; + } else { + cell.z = "#,##0"; + } + } + } + } + } + }; + applyRangeFormat(sheetArray[index].decimalRange0, 0); + applyRangeFormat(sheetArray[index].decimalRange1, 1); + applyRangeFormat(sheetArray[index].decimalRange2, 2); + applyRangeFormat(sheetArray[index].decimalRange3, 3); + } else { + console.error(`Sheet "${sheetName}" is undefined.`); } - }); - await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm) + } }); -} + + await excelArrayStyle( + XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), + sheetArray, + fileNm + ); + + return undefined; +}; type ExcelDownloadWithHeaderProps = { data: JSON | JSON[]; @@ -251,4 +354,4 @@ export const downloadExcelWithKoreanHeaders = async ({ // 3. 헤더만 한글로 교체하는 커스텀 스타일 함수 호출 await excelStyleWithKoreanHeaders(buffer, headerRange, fileName, headerMapping, dataArray[0]); -}; \ No newline at end of file +}; From 7650ec30e877e3ce5b0cb74b3138b9ceb4dc0f71 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Tue, 10 Feb 2026 20:30:41 +0900 Subject: [PATCH 90/92] =?UTF-8?q?fo:=20dashboard=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/pages/(with-layout)/dashboard/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index 8728cfe1d..fec75a0b7 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -7,7 +7,7 @@ "use client" import { useFoStore } from "@/app/store"; import { - ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv, downloadExcelFormat + ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv , SelectBox, UITab, type SelectDataType } from "@common/business_components"; import { Button, TabsContent } from "@common/components/ui"; From e264159323dfdf429795043796d2821768da254e Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Tue, 10 Feb 2026 22:41:56 +0900 Subject: [PATCH 91/92] =?UTF-8?q?fo:=20=EC=88=98=EC=A7=88=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=ED=8C=9D=EC=97=85=20exceldown=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/(with-layout)/dashboard/page.tsx | 15 ++++++++----- .../facilityWaterQlty/modal/page.tsx | 2 +- .../(with-layout)/flowRate/modal/page.tsx | 11 ++++++++-- .../processFacility/modal/page.tsx | 2 +- .../src/ui/excel/index.tsx | 22 +++++++++++++++++++ 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx index fec75a0b7..24d71e719 100644 --- a/apps/fo/app/pages/(with-layout)/dashboard/page.tsx +++ b/apps/fo/app/pages/(with-layout)/dashboard/page.tsx @@ -7,7 +7,7 @@ "use client" import { useFoStore } from "@/app/store"; import { - ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv + ContentsDiv, downloadExcelFormat, downloadMultipleExcel, filePickedBlobArrayFormat, MainDiv , SelectBox, UITab, type SelectDataType } from "@common/business_components"; import { Button, TabsContent } from "@common/components/ui"; @@ -197,7 +197,8 @@ export default function DashBoard() { headerRange: 'A1:G2', sheetName: '운영실태', startCol: 'A', - decimalRange0: 'B9:B11', + decimalRange0: 'B3:G2,B9:B11', + decimalRange1: 'B5:G5', }, { data: excelData2, @@ -211,7 +212,7 @@ export default function DashBoard() { } ]; // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 - await filePickedBlobArray(blobRet, '시설정보및운영현황', sheetParameter); + await filePickedBlobArrayFormat(blobRet, '시설정보및운영현황', sheetParameter); }); }; await searchOperationStatus(false, searchYear, fcltyList.bscFctCd); @@ -266,11 +267,15 @@ export default function DashBoard() { case 'rainManage': // 강우일 운영현황 searchRainManage(searchYear, fcltyList.bscFctCd, true); if (excelList && excelList.length > 0) { - downloadExcel({ + downloadExcelFormat({ data: excelList as unknown as JSON[], fileName: '강우일 운영현황', sheetNameArray: ['강우일 운영현황'], - headerRange: 'A1:T1' }); + headerRange: 'A1:T1', + decimalArray0: [2,3], + decimalArray1: [1,4,5,6,7,10,11,12,15,16,17], + decimalArray3: [8,9,13,14,18,19], + }); } break; // Add other cases for different tabs as needed 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 c1a6afdf8..9c6d5360a 100644 --- a/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/facilityWaterQlty/modal/page.tsx @@ -394,7 +394,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea "유입BOD(mg/L)": CommaToNumber(item.tpInflWqltBod), "유입TP(mg/L)": CommaToNumber(item.tpInflWqltTp), "유출BOD(mg/L)": CommaToNumber(item.efflWqltBod), - "유출TP(mg/L)": CommaToNumber(item.efflWqltTn), + "유출TP(mg/L)": CommaToNumber(item.efflWqltTp), }); }); } 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 b214e0a48..0cffa775e 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -9,7 +9,7 @@ import FacilityTermModalHeader from "@/app/components/common/FacilityTermModalHe import { useFoStore } from "@/app/store"; import type { FlowRateModalInterface, modalExcelType } from "@/app/store/flowRate"; import { dataFormSetting } from "@/app/store/flowRate"; -import { downloadExcel, UITab, UiTable } from "@common/business_components/ui"; +import { downloadExcelFormat, UITab, UiTable } from "@common/business_components/ui"; import { Button, TabsContent } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import type { ReturnType } from "../../../../components/common/FacilityTermModalHeader"; @@ -201,7 +201,14 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st }); } if (excelDownList && excelDownList.length > 0) { - downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear + '년 ' + props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:H1' }); + downloadExcelFormat({ + data: JSON.parse(JSON.stringify(excelDownList)), + fileName: props.searchYear + '년 ' + props.fcltyName + ' 유량현황', + sheetNameArray: [props.fcltyName + ' 유량현황'], + headerRange: 'A1:H1', + decimalArray0: [1, 2, 3, 4, 5, 6], + decimalArray1: [0], + }); } else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) { alert('조회된 결과가 없습니다.'); } diff --git a/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx b/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx index 20c885797..3118e008f 100644 --- a/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processFacility/modal/page.tsx @@ -206,7 +206,7 @@ export default function ProcessFacilityInfoModal(props: ModalType) { const sheetParameter = [ { data: excelData, - headerNum: 2, + headerNum: 3, headerRange: 'A1:S2', sheetName: '시설 수질정보', startCol: 'A' diff --git a/packages/common/business_components/src/ui/excel/index.tsx b/packages/common/business_components/src/ui/excel/index.tsx index 662705837..80acd9696 100644 --- a/packages/common/business_components/src/ui/excel/index.tsx +++ b/packages/common/business_components/src/ui/excel/index.tsx @@ -268,6 +268,27 @@ export const filePickedBlobArray = async ( oFile: ArrayBuffer, fileNm: string, sheetArray: SheetParameter[] +): Promise<JSON | undefined> => { + const wb = XLSX.read(oFile, { type: 'binary' }); + wb.SheetNames.forEach(function (sheetName, index) { + if (sheetArray[index]) { + const sheet = wb.Sheets[sheetName]; + if (sheet) { + const startCol = sheetArray[index].startCol ? sheetArray[index].startCol : 'A'; + XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, { origin: startCol + sheetArray[index].headerNum }); + } else { + console.error(`Sheet "${sheetName}" is undefined.`); + } + } + }); + await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm); + return undefined; +}; + +export const filePickedBlobArrayFormat = async ( + oFile: ArrayBuffer, + fileNm: string, + sheetArray: SheetParameter[] ): Promise<JSON | undefined> => { const wb = XLSX.read(oFile, { type: "binary" }); @@ -276,6 +297,7 @@ export const filePickedBlobArray = async ( const sheet = wb.Sheets[sheetName]; if (sheet) { const startCol = sheetArray[index].startCol ?? "A"; + XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, { origin: startCol + sheetArray[index].headerNum, }); From 8d5546abd58254ea516da2ba64dfe46665166500 Mon Sep 17 00:00:00 2001 From: dongsilove <ljparkmindone@gmail.com> Date: Tue, 10 Feb 2026 22:55:58 +0900 Subject: [PATCH 92/92] =?UTF-8?q?fo:=20=EC=B2=98=EB=A6=AC=EA=B5=AC?= =?UTF-8?q?=EC=97=AD=20exceldown=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/fo/app/pages/(with-layout)/processArea/page.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/fo/app/pages/(with-layout)/processArea/page.tsx b/apps/fo/app/pages/(with-layout)/processArea/page.tsx index 60dfff2cc..bca5a7b91 100644 --- a/apps/fo/app/pages/(with-layout)/processArea/page.tsx +++ b/apps/fo/app/pages/(with-layout)/processArea/page.tsx @@ -160,11 +160,8 @@ export default function ProcessArea() { fileName: '처리구역정보', sheetNameArray: ['처리구역정보'], headerRange: 'A1:W1', - decimalArray0: [ - 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, - 17, 18, 19, 20, 21 - ] + decimalArray0: [3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15], + decimalArray2: [16, 17, 18, 19, 20, 21], }); } else { alert('조회된 결과가 없습니다.');