Merge branch 'iipbs/sn/dev'

This commit is contained in:
2026-02-10 10:48:50 +09:00
12 changed files with 200 additions and 37 deletions
@@ -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("조회된 결과가 없습니다.");
@@ -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 {
@@ -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("조회된 결과가 없습니다.");
@@ -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('조회된 결과가 없습니다.');
@@ -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[] = [];
@@ -137,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('다운받을 데이터가 없습니다.');
}
@@ -218,7 +242,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 +286,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 +302,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 +324,4 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
</div>
</>
);
}
}
@@ -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('조회된 결과가 없습니다.');
}
@@ -321,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-[1300px] h-[100dvh] max-h-[800px]"
open={selectedRow !== null}
onOpenChange={(open) => !open && closeModal()}
/>
+32 -4
View File
@@ -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("조회된 결과가 없습니다.");
@@ -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("조회된 결과가 없습니다.");
@@ -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("조회된 결과가 없습니다.");
+12 -3
View File
@@ -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
}
}
}
}
}
@@ -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,
@@ -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,
};
});