Compare commits

...
Author SHA1 Message Date
leedj312 3b6e8ceedb 빗물 통계 수정 2025-07-22 20:55:00 +09:00
leedj312 b4e3d922b1 Merge commit 'a028b6ae8bba8e074e82900d05925d4e5a9c6951' into iipbs/wr/dev 2025-07-22 15:38:12 +09:00
leedj312 a028b6ae8b ui 테이블 체크박스 사용시 클래스 타입을 사용 체크 2025-07-22 15:37:54 +09:00
leedj312 ad0803f405 Merge commit '03675aaa6062402fbb3772e97cd966c0f7abd890' into iipbs/wr/dev 2025-07-22 14:38:24 +09:00
jyha00 03675aaa60 재이용통계 엑셀 다운로드시 시도명 없음 수정 2025-07-22 14:36:09 +09:00
leedj312 c0c19c0425 매칭완료 오류사항 수정 2025-07-22 14:32:25 +09:00
leedj312 214d283366 Merge commit '7d95ddf6a521f108b3b49d71760ba6e92a56d2dc' into iipbs/wr/login-test 2025-07-22 13:56:46 +09:00
truthwing 7d95ddf6a5 ChkClass 타입의 정보로 동작되는 체크박스 추가. 2025-07-22 13:55:31 +09:00
jyha00 a19c5c269a 지도점검 테이블 재수정 2025-07-22 13:37:35 +09:00
jyha00 6102e0af6b 지도점검 테이블 수정 2025-07-22 13:10:22 +09:00
jyha00 225bae08d3 readOnly 수정 2025-07-22 13:09:20 +09:00
leedj312 d8b5abb12f 미들웨어 반영 기본값 반영 2025-07-22 10:36:56 +09:00
leedj312 d9a3da96bb 베이스 변경사항 2025-07-22 09:24:19 +09:00
leedj312 87d1f33c05 Merge commit 'd68c6c151c5135ccb1f326fd36cd4b02200106f7' into iipbs/wr/login-test 2025-07-22 09:23:56 +09:00
leedj312 d68c6c151c Merge commit 'ddf3a5cfa0aedbb2bb73e073ff97fa68ca2c5d9a' into iipbs/wr/dev 2025-07-21 20:00:43 +09:00
leedj312 dfb910f270 Merge commit '5976b35c902b1fb1da1fdc637e620a0d0d3e9ede' into iipbs/wr/dev 2025-07-21 19:58:48 +09:00
leedj312 ddf3a5cfa0 캘린더 함수 오류 2025-07-21 19:56:57 +09:00
jyha00 5976b35c90 결함 오류 수정 2025-07-21 19:56:41 +09:00
truthwing 6b204fce15 djlee product 2025-07-21 19:51:52 +09:00
leedj312 f731d0f9f0 변경사항 2025-07-21 19:04:13 +09:00
leedj312 e231d0c4be 수정 사항 발견 2025-07-21 18:05:13 +09:00
leedj312 e4328a2ed4 Merge commit '069e489d031203200fc4d73e470767503a3dc227' into iipbs/wr/dev 2025-07-21 18:01:43 +09:00
leedj312 069e489d03 온배수 현황 수질 작업중 2025-07-21 17:59:55 +09:00
leedj312 990dffc11c 물재이용 / 이동시 메인으로 이동 2025-07-21 17:59:38 +09:00
jyha00 b4140d6457 결함 수정 2025-07-21 17:50:47 +09:00
jyha00 91af5fd27c Merge branch 'iipbs/common/main' into iipbs/wr/pfmncSttn 2025-07-21 16:15:56 +09:00
jyha00 0bb16f9795 도넛차트 범례 높이 조정 2025-07-21 15:28:42 +09:00
jyha00 be7efb2ad0 결함 오류 수정 2025-07-21 15:27:18 +09:00
jyha00 fbd9575df7 잠재수요처 페이지 오류 수정 2025-07-21 11:07:51 +09:00
51 changed files with 1446 additions and 947 deletions
+24
View File
@@ -0,0 +1,24 @@
"use client"
import { BaseLayout } from "@common/components/ui"
import { useWrStore } from "./store"
import { MainDiv } from "@common/business_components/ui"
import type { MenuItem } from "./store/common/type/menu"
import { useRouter } from "next/navigation"
export default function Base({
children,
}: Readonly<{
children: React.ReactNode
}>) {
const { getMenuAuthrts } = useWrStore((state) => state)
const router = useRouter()
const changeMenu = (path: MenuItem) => {
getMenuAuthrts(path.menuCd)
router.push(path.urlPath)
}
return (
<BaseLayout handleMenuClick={changeMenu}>
<MainDiv>{children}</MainDiv>
</BaseLayout>
)
}
+11 -21
View File
@@ -1,12 +1,10 @@
'use client'
import { BaseLayout } from "@common/components";
"use client";
import "./globals.css";
import { StoreProvider } from "./store";
import { MainDiv } from "@common/business_components";
import koBase from '../public/locales/ko/message.json';
import { StoreProvider} from "./store";
import koBase from "../public/locales/ko/message.json";
import i18next from "i18next";
import { I18nextProvider } from "react-i18next";
import { useRouter } from "next/navigation";
import Base from "./base";
export default function RootLayout({
children,
@@ -14,34 +12,26 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
i18next.init({
lng: 'ko',
fallbackLng: 'ko',
lng: "ko",
fallbackLng: "ko",
resources: {
ko: {
base: koBase,
},
}
},
});
const router = useRouter();
return (
<html lang="en">
<body>
<I18nextProvider i18n={i18next}>
<StoreProvider>
<BaseLayout
handleMenuClick={(e) =>{
router.push(e.urlPath)
}}
>
<MainDiv>
{children}
</MainDiv>
</BaseLayout>
<Base>
{children}
</Base>
</StoreProvider>
</I18nextProvider>
</body>
</html >
</html>
);
}
+1 -1
View File
@@ -316,7 +316,7 @@ export default function CoMatRvw() {
control={form.control}
name="dmndQty"
render={({ field }) => (
<FormUi label="요구수량(M3/d)">
<FormUi label="요구수량(m³/일)">
<Input
placeholder=""
type="number"
+56 -55
View File
@@ -1,12 +1,9 @@
"use client";
import { useWrStore } from "@/app/store";
import { type RvwHistTableType } from "@/app/store/matDmd/coMatRvw/type";
import {
DmdCoReqSchema,
type DmdCoReqType,
type RvwHistTableType,
} from "@/app/store/matDmd/coMatRvw/type";
import {
confirmToast,
formatPhoneNumber,
getCity,
getdmdMatFlag,
@@ -27,11 +24,10 @@ import {
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import moment from "moment";
import { useCallback, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast, { Toaster } from "react-hot-toast";
import { useTranslation } from "react-i18next";
export default function RuseRvwHstry() {
const {
code,
@@ -51,6 +47,7 @@ export default function RuseRvwHstry() {
sgg: "",
city: "",
});
const { t } = useTranslation('base');
const [fromDate, setFromDate] = useState<string>(
String(new Date().getFullYear())
@@ -116,53 +113,65 @@ export default function RuseRvwHstry() {
}
};
const form = useForm<DmdCoReqType>({
resolver: zodResolver(DmdCoReqSchema),
mode: "onChange",
});
const TableCellClick = useCallback(
(index: number | undefined) => {
if (
index !== undefined &&
index >= 0 &&
rvwHistRes &&
rvwHistRes[index]
) {
form.reset(rvwHistRes[index]);
(index: number | undefined, headId: string) => {
if (index !== undefined && index >= 0) {
const selectedData = rvwHistData;
if (selectedData && selectedData.length > 0) {
if (
selectedData[index]?.splyFcltFlg === "검토완료" &&
headId === "completeYn"
) {
setRvwHistData([...selectedData]);
} else if (
selectedData[index]?.splyFcltFlg === "매칭완료" &&
headId === "completeYn"
) {
toast.error(t("canNotChangeMatStateMsg"));
return;
}
}
}
},
[rvwHistRes, form]
[rvwHistData]
);
const confrirmToast = () => {
const completeData = rvwHistData
?.map((item) => {
form.clearErrors();
if (item?.completeYn) {
if (item?.completeYn.chk && item.splyFcltFlg === "검토완료") {
return Number(item.dmdInfoSn);
}
})
.filter((item) => item !== undefined);
if (form.formState.isDirty) {
toast((t) => (
<span className="flex flex-col items-center">
표준공사비 정보가 변경되었습니다. 검토 완료 진행시 입력한 정보는
초기화 됩니다.
<br />
진행하시겠습니까?
<button
onClick={() => {
toast.dismiss(t.id);
ruseRvwComplete(completeData as number[]);
}}
>
확인
</button>
<button onClick={() => toast.dismiss(t.id)}>취소</button>
</span>
));
if (completeData && completeData?.length > 0) {
confirmToast(t('isMatchFinishMsg'), () => ruseRvwComplete(completeData as number[]));
// const handleConfirm = async () => {
// ruseRvwComplete(completeData as number[]);
// };
// toast((t) => (
// <span className="flex flex-col items-center">
// 매칭완료를 진행하시겠습니까?
// <br />
// <div className="mt-2 flex flex-row space-x-2">
// <Button
// size={"sm"}
// onClick={() => {
// toast.dismiss(t.id);
// ruseRvwComplete(completeData as number[]);
// }}
// >
// 확인
// </Button>
// <Button size={"sm"} onClick={() => toast.dismiss(t.id)}>
// 취소
// </Button>
// </div>
// </span>
// ));
} else {
ruseRvwComplete(completeData as number[]);
toast.error( t('isNotMatchFinishMsg'));
}
};
useEffect(() => {
@@ -203,11 +212,10 @@ export default function RuseRvwHstry() {
rvwCmptnYmd: formatDate(item.demandMatching?.rvwCmptnYmd),
mtchnCmptnYmd: formatDate(item.demandMatching?.mtchnCmptnYmd),
ruseUtztnFcltNm: item.ruseUtztnFcltNm,
dmndQty: item.dmndQty,
splyFcltFlg: flag,
completeYn: false,
completeYn: {chk:flag=="매칭완료", readonly:flag=="매칭완료"},
} as unknown as RvwHistTableType;
});
@@ -215,9 +223,6 @@ export default function RuseRvwHstry() {
}
}, [rvwHistRes]);
useEffect(() => {
console.log("변경여부 ", form.formState.isDirty);
}, [form.formState]);
return (
<ContentsDiv>
@@ -301,7 +306,7 @@ export default function RuseRvwHstry() {
조회
</Button>
<Button size={"sm"} onClick={confrirmToast}>
검토완료
저장
</Button>
</div>
</div>
@@ -319,18 +324,14 @@ export default function RuseRvwHstry() {
headlist={ruseHistHeadList}
pageSize={20}
total={rvwHistCount}
cellClick={(index: number | undefined) => {
TableCellClick(index);
cellClick={(index: number | undefined, headId: string) => {
console.log("테이블 클릭", index);
TableCellClick(index, headId);
}}
onPageChange={(page) => {
setPageNatiion(page);
}}
></UiTable>
{/* <hr />
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
</h3>
<ConCostForm form={form} type={"hist"} selectionVersion={0} /> */}
</ListDiv>
</div>
</div>
+3 -1
View File
@@ -101,7 +101,9 @@ export default function CoSttn() {
...item,
telno: formatPhoneNumber(item.telno || undefined),
regDt: moment(item.regDt).format("YYYY-MM-DD"),
}));
dmdInfoId: `${item.dmdInfoId.slice(0, 3)}-${item.dmdInfoId.slice(3, 5)}-${item.dmdInfoId.slice(5,10)}-${item.dmdInfoId.slice(10)}`
}));
console.log("chData:", chData)
// .filter((item: any) => item !== undefined);
setBdstTable(chData);
} else if (coSttnRes?.length == 0) {
+26 -28
View File
@@ -43,8 +43,9 @@ export default function LdrmntCoSttn() {
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [bdstTable, setBdstTable] = useState<customLdrmnt[]>();
const [searchTxt, setSearchTxt] = useState<string>();
const [excelData, setExcelData] = useState<any[]>();
const [excelData, setExcelData] = useState<any[] | undefined>()
const [resetPage, isResetPage] = useState(false);
const [isDownloadClicked, setIsDownloadClicked] = useState(false);
const { t } = useTranslation('base');
const excelClick = useCallback(() => {
@@ -79,10 +80,31 @@ export default function LdrmntCoSttn() {
const excelDownloadClick = useCallback(() => {
const cityNm = computeCityNm();
setExcelData(undefined);
setIsDownloadClicked(true);
ldrmntSearch(true, 1, String(ldrmntResCount), cityNm, searchTxt || "");
}, [objSearch, searchTxt, code, ldrmntSearch, computeCityNm, ldrmntResCount]);
useEffect(() => {
const transData = Array.isArray(excelList) ? excelList : [excelList];
const exData = tableData(transData, { code });
const data = Array.isArray(exData)
? exData.map((item: customLdrmnt) => {
return {
"시도": item.fctryAddr?.split(" ")[0] || "",
"시군구": item.fctryAddr?.split(" ")[1] || "",
"회사명": item.dmdCoNm,
"공장주소": item.fctryAddr,
"공장관리번호": item.fctryMngNo,
"전화번호": item.telno
}
}) : [];
setExcelData(data)
}, [excelList])
useEffect(() => {
if (!isDownloadClicked) return;
if (excelData === undefined) return;
if (excelData && excelData.length > 0) {
downloadExcel({
data: excelData,
@@ -93,7 +115,8 @@ export default function LdrmntCoSttn() {
} else {
toast.error(t('excelDownErrMsg'));
}
}, [excelData]);
setIsDownloadClicked(false);
}, [excelData, isDownloadClicked]);
const [isExcelOpen, setIsExcelOpen] = useState<{
isModal: boolean;
@@ -125,7 +148,7 @@ export default function LdrmntCoSttn() {
useEffect(() => {
if (!ldrmnt.isInit) {
ldrmntInit("0");
ldrmntInit(false, "0");
}
}, [ldrmnt.isInit, ldrmntInit]);
@@ -144,23 +167,6 @@ export default function LdrmntCoSttn() {
setBdstTable(tbData);
}, [ldrmntRes, code]);
useEffect(() => {
const transData = Array.isArray(excelList) ? excelList : [excelList];
const exData = tableData(transData, { code });
const data = Array.isArray(exData)
? exData.map((item: customLdrmnt) => {
return {
"시도": item.fctryAddr?.split(" ")[0] || "",
"시군구": item.fctryAddr?.split(" ")[1] || "",
"회사명": item.dmdCoNm,
"공장주소": item.fctryAddr,
"공장관리번호": item.fctryMngNo,
"전화번호": item.telno
}
}) : [];
setExcelData(data)
}, [excelList])
useEffect(() => {
ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || "");
isResetPage(false)
@@ -264,10 +270,6 @@ export default function LdrmntCoSttn() {
}}
bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"}
body={<CoDetailModal formObj={detailModal.data} onFormSubmit={async (value) => {
// confirmToast(t('isUpdateMsg'), await ldrmntUpdate(value))
// // await ldrmntUpdate(value)
// setDetailModal({ ...detailModal, isOpen: false })
// ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || "");
const handleConfirm = async () => {
await ldrmntUpdate(value);
setDetailModal({ ...detailModal, isOpen: false });
@@ -286,12 +288,8 @@ export default function LdrmntCoSttn() {
body={<CoRegExcel isModal={(isOpen) => setIsExcelOpen({ isModal: isOpen })} />}
/>
<Toaster position="top-center"></Toaster>
</div>
</ContentsDiv>
</>
)
}
@@ -364,6 +364,7 @@ export default function PublicReuseFaciltyInsert() {
setIndexMng(index);
}}
indexMng={indexMng}
readonly={false}
/>
</TabsContent>
<TabsContent className="max-h-full" value="buse">
@@ -3,7 +3,7 @@ import { useWrStore } from "@/app/store";
import {
type customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { tableData } from "@/components/lib/func/commom";
import { formatCommaNumber, tableData } from "@/components/lib/func/commom";
import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm";
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import {
@@ -52,7 +52,7 @@ export default function Home() {
: "확인불가";
return {
...item,
archArea: archArea,
archArea: formatCommaNumber(archArea),
};
}
@@ -166,8 +166,8 @@ export default function HtdflSttn() {
value={objSearch.sgg} // value props 추가
onSelectValue={getSgg}
/>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
<div className="col-span-2 flex flex-row space-x-2 ml-3 mt-2">
<Label className="w-28 mt-2 text-xl">
{"시설명"}
</Label>
<SearchInput
@@ -124,8 +124,13 @@ export default function RainSttn() {
item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1
? "확인불가"
: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct,
archArea:
Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea,
// archArea:
// Math.floor(item.archArea) === -1 ? "확인불가" : Math.trunc(item.archArea) ? item.archArea,
archArea: isNaN(Number(item.archArea))
? item.archArea
: Math.floor(Number(item.archArea)) === -1
? '확인불가'
: Math.trunc(Number(item.archArea))
};
})
.filter((item: any) => item.rainyObj !== undefined);
@@ -206,12 +211,12 @@ export default function RainSttn() {
value={objSearch.sgg} // value props 추가
onSelectValue={getSgg}
/>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
<div className="col-span-2 flex flex-row space-x-2 ml-3 mt-2">
<Label className="w-28 mt-2 text-xl">
{"시설명"}
</Label>
<SearchInput
className={"w-full h-full text-2xl"}
className={"w-full text-2xl"}
label={""}
textValue={fcltNm || ""}
setText={setFcltNm}
@@ -164,8 +164,8 @@ export default function RswtSttn() {
getSgg
}
/>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
<div className="col-span-2 flex flex-row space-x-2 ml-3 mt-2">
<Label className="w-28 mt-2 text-xl">
{"시설명"}
</Label>
<SearchInput
+96 -84
View File
@@ -16,50 +16,44 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
export default function RainStat() {
const { code, rainStat, searchRainStatList } = useWrStore((state) => state);
const { rainStatList, excelList, rainDetailList } = rainStat;
const { rainStatList, rainDetailList } = rainStat;
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [exData, setExData] = useState<Array<Record<string, string | number>>>();
//const [exData, setExData] = useState<Array<Record<string, string | number>>>();
const [bdstTable, setBdstTable] = useState<RainStatProps[]>();
const { t } = useTranslation('base');
useEffect(() => {
searchRainStatList(searchYear);
}, [code.cityCd, code.sggCd, searchRainStatList])
searchRainStatList(searchYear ,code.cityCd);
}, [code.cityCd, searchRainStatList])
const excelDetailDownLoad=() =>{
const excelDetailDownLoad = () => {
const sidoList = new Set<string>();
const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map
const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map
// 먼저 시도별 상세 데이터를 그룹화
rainDetailList.forEach((item: RainStatProps[]) => {
// 복사된 배열을 사용
const transformedRainDetailList = rainDetailList.map((originItem: RainStatProps[]) => {
const item = [...originItem]; // 원본 복사
const sidoVal = item.at(0)?.toString().trim();
const sigunVal = item.at(1)?.toString().trim();
let sidoText = '';
let sigunText = '';
const sido = code.cityCd.find((city) => city.val === sidoVal);
const sigun = code.sggCd.find((sgg) => sgg.val === sigunVal);
sidoText = sido?.text || '';
sigunText = sigun?.text || '';
// 시도, 시군구 코드를 텍스트로 변환하여 데이터에 할당
if (item.length > 0) {
item[0] = sidoText as unknown as RainStatProps;
}
if (item.length > 1) {
item[1] = sigunText as unknown as RainStatProps;
}
if (item.length > 2) {
item[2] = sidoText+' '+sigunText as unknown as RainStatProps;
}
const sidoText = sido?.text || '';
const sigunText = sigun?.text || '';
if (item.length > 0) item[0] = sidoText as unknown as RainStatProps;
if (item.length > 1) item[1] = sigunText as unknown as RainStatProps;
if (item.length > 2) item[2] = `${sidoText} ${sigunText}` as unknown as RainStatProps;
// 시도별 상세 데이터 수집
if (sidoText) {
@@ -72,53 +66,40 @@ export default function RainStat() {
// 시도별 합계 데이터 수집
if (sidoText && !sidoList.has(sidoText)) {
sidoList.add(sidoText);
// 시도별 초기 데이터 구조 생성 (예: [시도명, 0, 0, 0, ...])
const initialData: (string | number)[] = [sidoText];
// 데이터의 나머지 컬럼들을 0으로 초기화 (실제 컬럼 수에 맞게 조정 필요)
for (let i = 1; i < item.length; i++) {
initialData.push(0);
}
sidoDataMap.set(sidoText, initialData);
}
return item;
});
// 시도별 합계 계산
rainDetailList.forEach((item: RainStatProps[]) => {
// 이후 합계 계산에서도 transformedRainDetailList 사용
transformedRainDetailList.forEach((item: RainStatProps[]) => {
const sidoText = item[0]?.toString();
if (sidoText && sidoDataMap.has(sidoText)) {
const sidoData = sidoDataMap.get(sidoText)!;
// 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작)
for (let i = 1; i < item.length && i < sidoData.length; i++) {
if(i == 2){
if (i == 2) {
sidoData[i] = '합계';
} else if(i == 3){
// 해당 시도의 데이터 개수를 계산
const sidoDataCount = rainDetailList.filter((data: unknown[]) =>
} else if (i == 3) {
const sidoDataCount = transformedRainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 0 && String(data[0]) === sidoText
).length;
sidoData[i] = sidoDataCount;
} else if( i == 4){
} else if (i == 4) {
sidoData[i] = '';
} else if(i == 6){
// 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우)
const bumCnt = rainDetailList.filter((data: unknown[]) =>
} else if (i == 6) {
const bumCnt = transformedRainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText
).filter((data: unknown[]) => String(data[6]) === '대상').length;
sidoData[i] = bumCnt;
} else if(i==8){
const value = Number(item[8]) || 0;
} else if ([8, 11, 12, 14].includes(i)) {
const value = Number(item[i]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==11){
const value = Number(item[11]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==12){
const value = Number(item[12]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==14){
const value = Number(item[14]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
}
else {
} else {
sidoData[i] = '';
}
}
@@ -127,12 +108,12 @@ export default function RainStat() {
// 시도별로 합계와 상세 데이터를 순서대로 배치
const summaryExcelData: (string | number)[][] = [];
// 시도별로 순회하면서 합계와 상세 데이터를 추가
Array.from(sidoList).forEach((sidoText) => {
const sidoSummary = sidoDataMap.get(sidoText);
const sidoDetails = sidoDetailMap.get(sidoText) || [];
if (sidoSummary) {
// 시도 합계 데이터 추가
summaryExcelData.push(sidoSummary);
@@ -144,62 +125,91 @@ export default function RainStat() {
});
const sidoSummaryList = Array.from(sidoDataMap.values());
const sidoTotalSummary = [['전체', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '', 0]];
const sidoTotalSummary = [['전국', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '']];
sidoSummaryList.forEach((item: (string | number)[]) => {
item.forEach((value: string | number, index: number) => {
if(typeof value === 'number') {
if (typeof value === 'number') {
if (sidoTotalSummary[0] && index < sidoTotalSummary[0].length) {
sidoTotalSummary[0][index] = Number(sidoTotalSummary[0][index]) + Number(value);
}
}
});
});
// sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성
const excelData = [...sidoTotalSummary, ...sidoSummaryList, ...summaryExcelData];
console.log(' excelData ', excelData)
excelDownload(
excelData as unknown as [][],
"빗물이용시설 통계",
"sample_rainStats.xlsx",
"A1:V3",
"A1:O3",
4
);
}
const excelClick = () => {
if(bdstTable){
const tbData = bdstTable .map((item: RainStatProps) => {
return {
"시도": item.cityText,
"개소": item.tmp,
"설치비(백만원)": item.instlCst,
"저류조용량(m³/년)": item.dtfcltCpct,
"연간사용량(m³/년)": item.wtrUsqty,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"세척살수용수": item.resn,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
})
downloadExcel({
data: (exData as unknown as JSON[]) ?? [],
data: (tbData as unknown as JSON[]) ?? [],
fileName: "재이용통계",
sheetNameArray: ["Sheet1"],
headerRange: "A1:M1"
})
}else{
toast.error(t('excelDownErrMsg'));
}
}
useEffect(() => {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const excelData = tableData(transExcel, { code });
const tbData = Array.isArray(excelData)
? excelData.map((item: RainStatProps) => {
return {
"시도": item.cityText,
"개소": item.tmp,
"설치비(백만원)": item.instlCst,
"저류조용량(m³/년)": item.dtfcltCpct,
"연간사용량(m³/년)": item.wtrUsqty,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"세척살수용수": item.resn,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
})
: [];
setExData(tbData);
}, [code, excelList])
// useEffect(() => {
// if(excelList && excelList.length>0){
// console.log('excelList ', excelList)
// const transExcel = Array.isArray(excelList) ? excelList : [excelList];
// const excelData = tableData(transExcel, { code });
// const tbData = Array.isArray(excelData)
// ? excelData
// .filter((item: RainStatProps) => item.cityText !== '없음')
// .map((item: RainStatProps) => {
// return {
// "시도": item.cityText,
// "개소": item.tmp,
// "설치비(백만원)": item.instlCst,
// "저류조용량(m³/년)": item.dtfcltCpct,
// "연간사용량(m³/년)": item.wtrUsqty,
// "조경용수": item.lndwtr,
// "청소화장실용수": item.cleanToilUswtr,
// "세척살수용수": item.resn,
// "농업용수": item.farmUswtr,
// "공업용수": item.indstUswtr,
// "친수용수": item.hydUswtr,
// "기타": item.ithlEtcUswtr,
// "연간운영비(백만원/년)": item.anlOperCst,
// };
// })
// : [];
// setExData(tbData);
// }
// }, [code, excelList])
useEffect(() => {
const transData = Array.isArray(rainStatList) ? rainStatList : [rainStatList];
@@ -208,11 +218,13 @@ export default function RainStat() {
? data.map((item: RainStatProps) => {
return {
...item,
ctpvCd: item.cityText
ctpvCd: item.cityText==='전체'?'전국': item.cityText,
cityText: item.cityText==='전체'?'전국': item.cityText,
};
}).filter((item: RainStatProps) => item.cityText !== '없음')
: [];
setBdstTable(tbData);
}, [code, rainStatList]);
@@ -237,7 +249,7 @@ export default function RainStat() {
/>
</div>
<div className="flex flex-row space-x-2 items-center">
<Button className="" size={"sm"} onClick={()=>{searchRainStatList(searchYear);}}>
<Button className="" size={"sm"} onClick={() => { searchRainStatList(searchYear ,code.cityCd); }}>
조회
</Button>
<Button className="" size={"sm"} onClick={() => excelClick()}>
@@ -264,7 +276,7 @@ export default function RainStat() {
total={0}
headName={""}
cellClick={undefined}
onPageChange={() => {}}
onPageChange={() => { }}
></UiTable>
</ScrollArea>
</ListDiv>
+43 -41
View File
@@ -55,29 +55,31 @@ export default function RswtStat() {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const exData = tableData(transExcel, { code });
const tbData = Array.isArray(exData) ?
exData.map((item: RswtStatProps) => {
return {
"시도": item.cityText,
"개소": item.ctpvCnt,
// "건축연면적(m³)": item.archArea,
"처리용량(m³)": item.filtrTrtmfctCpct,
"물사용량(m³/년)": item.wtrUsqty,
"중수도+대체수이용량(m³/년)": item.rswtAltSum,
"중수도이용량(m³/년)": item.rswtrUsqty,
"대체수이용량(m³/년)": item.altUswtrUtztnQnt,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
}) : [];
exData
.filter((item: RswtStatProps) => item.cityText !== '없음')
.map((item: RswtStatProps) => {
return {
"시도": item.cityText,
"개소": item.ctpvCnt,
// "건축연면적(m³)": item.archArea,
"처리용량(m³)": item.filtrTrtmfctCpct,
"물사용량(m³/년)": item.wtrUsqty,
"중수도+대체수이용량(m³/년)": item.rswtAltSum,
"중수도이용량(m³/년)": item.rswtrUsqty,
"대체수이용량(m³/년)": item.altUswtrUtztnQnt,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
}) : [];
setExceData(tbData);
}, [code, excelList])
const excelDetailDownLoad=() =>{
const excelDetailDownLoad = () => {
const sidoList = new Set<string>();
const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map
const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map
@@ -94,7 +96,7 @@ export default function RswtStat() {
sidoText = sido?.text || '';
sigunText = sigun?.text || '';
// 시도, 시군구 코드를 텍스트로 변환하여 데이터에 할당
if (item.length > 0) {
item[0] = sidoText as unknown as RswtStatProps;
@@ -103,7 +105,7 @@ export default function RswtStat() {
item[1] = sigunText as unknown as RswtStatProps;
}
if (item.length > 2) {
item[2] = sidoText+' '+sigunText as unknown as RswtStatProps;
item[2] = sidoText + ' ' + sigunText as unknown as RswtStatProps;
}
// 시도별 상세 데이터 수집
@@ -113,7 +115,7 @@ export default function RswtStat() {
}
sidoDetailMap.get(sidoText)!.push(item as unknown as (string | number)[]);
}
// 시도별 합계 데이터 수집
if (sidoText && !sidoList.has(sidoText)) {
sidoList.add(sidoText);
@@ -134,41 +136,41 @@ export default function RswtStat() {
const sidoData = sidoDataMap.get(sidoText)!;
// 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작)
for (let i = 1; i < item.length && i < sidoData.length; i++) {
if(i == 2){
if (i == 2) {
sidoData[i] = '합계';
} else if(i == 3){
} else if (i == 3) {
// 해당 시도의 데이터 개수를 계산
const sidoDataCount = rswtDetailList.filter((data: unknown[]) =>
const sidoDataCount = rswtDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 0 && String(data[0]) === sidoText
).length;
sidoData[i] = sidoDataCount;
} else if( i == 4){
} else if (i == 4) {
sidoData[i] = '';
} else if(i == 6){
} else if (i == 6) {
// 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우)
const bumCnt = rswtDetailList.filter((data: unknown[]) =>
const bumCnt = rswtDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText
).filter((data: unknown[]) => String(data[6]) === '대상').length;
sidoData[i] = bumCnt;
} else if(i==9){
} else if (i == 9) {
const value = Number(item[9]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==10){
} else if (i == 10) {
const value = Number(item[10]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==11){
} else if (i == 11) {
const value = Number(item[11]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==12){
} else if (i == 12) {
const value = Number(item[12]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
}else if(i==13){
} else if (i == 13) {
const value = Number(item[13]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==14){
} else if (i == 14) {
const value = Number(item[14]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==16){
} else if (i == 16) {
const value = Number(item[16]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else {
@@ -177,15 +179,15 @@ export default function RswtStat() {
}
}
});
// 시도별로 합계와 상세 데이터를 순서대로 배치
const summaryExcelData: (string | number)[][] = [];
// 시도별로 순회하면서 합계와 상세 데이터를 추가
Array.from(sidoList).forEach((sidoText) => {
const sidoSummary = sidoDataMap.get(sidoText);
const sidoDetails = sidoDetailMap.get(sidoText) || [];
if (sidoSummary) {
// 시도 합계 데이터 추가
summaryExcelData.push(sidoSummary);
@@ -200,7 +202,7 @@ export default function RswtStat() {
const sidoTotalSummary = [['전체', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '', 0]];
sidoSummaryList.forEach((item: (string | number)[]) => {
item.forEach((value: string | number, index: number) => {
if(typeof value === 'number') {
if (typeof value === 'number') {
if (sidoTotalSummary[0] && index < sidoTotalSummary[0].length) {
sidoTotalSummary[0][index] = Number(sidoTotalSummary[0][index]) + Number(value);
}
@@ -209,7 +211,7 @@ export default function RswtStat() {
});
// sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성
const excelData = [...sidoTotalSummary,...sidoSummaryList, ...summaryExcelData];
const excelData = [...sidoTotalSummary, ...sidoSummaryList, ...summaryExcelData];
excelDownload(
excelData as unknown as [][],
+75
View File
@@ -0,0 +1,75 @@
import { getFetch, getFetchWithCount } from "@/components/lib/api";
import toast from "react-hot-toast";
export const getMenuAuthrts = async (menuCd: number) => {
const response = await getFetch(
"LOCAL",
`/cms-service/api/v1/menu-authrts/pageinfo/${menuCd}`
);
authStateExport.auth = {
mngAuthrtYn: response[0].mngAuthrtYn,
inqAuthrtYn: response[0].mngAuthrtYn,
regAuthrtYn: response[0].mngAuthrtYn,
mdfcnAuthrtYn: response[0].mngAuthrtYn,
delAuthrtYn: response[0].mngAuthrtYn,
};
};
export type authState = {
auth: {
mngAuthrtYn: string;
inqAuthrtYn: string;
regAuthrtYn: string;
mdfcnAuthrtYn: string;
delAuthrtYn: string;
};
};
export type authType = authState & authActions;
export const authStateExport: authState = {
auth: {
mngAuthrtYn: "Y",
inqAuthrtYn: "Y",
regAuthrtYn: "Y",
mdfcnAuthrtYn: "Y",
delAuthrtYn: "Y",
},
};
export type authActions = {
getMenuAuthrts: (menuCd: number) => void;
};
export const authActionsExport: (set: any) => authActions = (set: any) => {
return {
getMenuAuthrts: async (menuCd: number) => {
try{
const response = await getFetchWithCount( 'LOCAL',
`/cms-service/api/v1/menu-authrts/pageinfo/${menuCd}`
);
set((state: authState) => {
return {
...state,
auth: {
mngAuthrtYn: response[0].mngAuthrtYn,
inqAuthrtYn: response[0].mngAuthrtYn,
regAuthrtYn: response[0].mngAuthrtYn,
mdfcnAuthrtYn: response[0].mngAuthrtYn,
delAuthrtYn: response[0].mngAuthrtYn,
},
};
});
}catch(e){
toast.error('권한 정보를 가져오는 중 오류가 발생했습니다. 관리자에게 문의하세요.');
console.error('Error fetching menu authorities:', e);
}
},
};
};
@@ -0,0 +1,19 @@
export interface MenuItem {
menuCd: number;
menuKornNm: string;
menuEngNm: string;
parentId: number | null;
sortSeq: number;
iconNm?: string;
children: MenuItem[] | null;
levelNo: number;
urlPath: string;
menuLnkgTypeCd: string;
menuLnkgSn: number;
menuPath: string;
qrcd: string;
useYn: string;
otptYn: string;
newWndwYn: string;
requiredUrlPath: boolean;
}
@@ -20,7 +20,7 @@ export const coRvwHeadListExport: CommonTableProps[]= [
},
{
id: "daddr",
title: "공장주소",
title: "주소",
visible: true,
},
{
+2 -1
View File
@@ -1,3 +1,4 @@
import type { ChkClass } from "@common/business_components/ui";
import { z } from "zod";
const DemandInfoSchema = z.object({
@@ -130,7 +131,7 @@ export type RvwHistTableType = {
dmndQty: string;
useUsgCd: string;
splyFcltFlg: string;
completeYn: boolean;
completeYn: ChkClass;
dmdInfoSn: string;
};
+52 -33
View File
@@ -29,11 +29,11 @@ type ExcelType = {
[key: string]: string | number | undefined;
};
const excelDownList: ExcelType[] = [];
// const excelDownList: ExcelType[] = [];
type ldrmntActions = {
ldrmntRegData: (data: any[]) => void,
ldrmntInit: (con: string) => void
ldrmntInit: (isExcel: boolean, con: string) => void
ldrmntSearch: (isExcel: boolean, page: number, sggCd: string, total: string, coNm: string) => void;
ldrmntUpdate: (ldrmntRes: customLdrmnt) => void;
ldrmntDelete: () => void;
@@ -58,25 +58,47 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
set: any
) => {
return {
ldrmntInit: async (con: string) => {
ldrmntInit: async (isExcel: boolean,con: string) => {
try {
const ldrmntRes = await getFetchWithCount(
fetchType.WR,
`/reuseFc/request/temp/1/20/${con}`
);
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes.data,
ldrmntResCount: ldrmntRes.count,
isInit: false,
excelList: excelDownList,
},
}
});
if (isExcel) {
const excelDownList: ExcelType[] = [];
ldrmntRes.data.forEach((item: customLdrmnt) => {
excelDownList.push({
ctpvCd: item.ctpvCd,
sggCd: item.sggCd,
dmdCoNm: item.dmdCoNm,
fctryAddr: item.fctryAddr,
fctryMngNo: item.fctryMngNo,
telno: item.telno,
})
})
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
excelList: excelDownList,
ldrmntResCount: ldrmntRes.count,
},
};
});
} else {
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes.data,
ldrmntResCount: ldrmntRes.count,
isInit: false,
},
}
});
}
} catch (e) {
console.log(e)
}
@@ -96,6 +118,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
await deleteFectch(
`/reuseFc/request/temp`,
);
console.log("deleteFectch", deleteFectch)
const response = await postFectch(
"/reuseFc/request/temp",
@@ -121,7 +144,6 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
fetchType.WR,
searchUrl
);
console.log("알이에스", ldrmntRes)
if (isExcel) {
const excelDownList: ExcelType[] = [];
ldrmntRes.data.forEach((item: customLdrmnt) => {
@@ -144,7 +166,6 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
},
};
});
return excelDownList;
} else
set((state: ldrmntState) => {
return {
@@ -157,27 +178,26 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
},
};
});
return ldrmntRes;
} catch (e) {
console.log(e)
}
},
ldrmntUpdate: async (ldrmntRes: customLdrmnt) => {
if(ldrmntRes)
try {
ldrmntRes.rgtr = TEST_UUID;
const res = await putFectch(
`/reuseFc/request/temp`,
ldrmntRes
);
if (ldrmntRes)
try {
ldrmntRes.rgtr = TEST_UUID;
const res = await putFectch(
`/reuseFc/request/temp`,
ldrmntRes
);
if (res.ok) {
toast.success("잠재수요처 상세정보가 수정되었습니다.",)
if (res.ok) {
toast.success("잠재수요처 상세정보가 수정되었습니다.",)
}
} catch (error) {
console.error("Error ldrmntUpdate:", error);
toast.error("잠재수요처 상세정보 수정에 실패하였습니다.")
}
} catch (error) {
console.error("Error ldrmntUpdate:", error);
toast.error("잠재수요처 상세정보 수정에 실패하였습니다.")
}
},
ldrmntDelete: async () => {
try {
@@ -193,7 +213,6 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
await deleteFectch(
`/reuseFc/request/temp`,
);
} catch (error) {
console.log("error", error)
set((state: ldrmntState) => {
@@ -6,6 +6,7 @@ export const ruseHstryHeadListExport:TableUpperProps[]= [
id: "cityText",
title: "시도",
visible: true,
},
{
id: "sggText",
@@ -19,7 +20,7 @@ export const ruseHstryHeadListExport:TableUpperProps[]= [
},
{
id: "daddr",
title: "공장주소",
title: "주소",
visible: true,
},
{
@@ -49,7 +50,7 @@ export const ruseHstryHeadListExport:TableUpperProps[]= [
},
{
id: "dmndQty", //바꾸기
title: "요구수량(M3/d)",
title: "요구수량(m³/일)",
visible: true,
},
{
@@ -130,7 +130,7 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
toast.success("매칭 계산 저장이 완료입니다.");
const rvwHistRes = await irvwHistInit(
1,
10,
13,
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
@@ -217,10 +217,10 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
fetchType.WR
);
if (complet.status === 200) {
toast.success("완료 처리가 완료되었습니다.");
toast.success("매칭완료가 완료되었습니다.");
const rvwHistRes = await irvwHistInit(
1,
10,
13,
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
@@ -236,7 +236,7 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
}
} catch (e) {
console.log(" error ", e);
toast.error("완료 처리 중 오류가 발생했습니다.");
toast.error("매칭 완료 처리 중 오류가 발생했습니다.");
}
},
};
@@ -195,7 +195,7 @@ export const rainChkgdnHeadListExport: TableUpperProps[] = [
title: "부과금액(천원)",
upName: "feeHist",
upSequnce: 3,
type: "number",
type: "text",
edit: true,
},
];
@@ -42,17 +42,17 @@ const hdtflObjSchema = z.object({
utztnUsg: z
.string()
.min(1, { message: validationMessages.required("이용 용도") }),
grssClfg: z.number().default(0), // Measurements, 0 is fine as default
combResdch: z.number().default(0), // Measurements, 0 is fine as default
trbt: z.number().default(0), // Measurements, 0 is fine as default
bod: z.number().default(0), // Measurements, 0 is fine as default
smll: z.number().default(0), // Measurements, 0 is fine as default
crmty: z.number().default(0), // Measurements, 0 is fine as default
tn: z.number().default(0), // Measurements, 0 is fine as default
tph: z.number().default(0), // Measurements, 0 is fine as default
ph: z.number().default(0), // Measurements, 0 is fine as default
clIonQnt: z.number().default(0), // Measurements, 0 is fine as default
cdtnv: z.number().default(0), // Measurements, 0 is fine as default
grssClfg: z.number().default(0).nullish(), // Measurements, 0 is fine as default
combResdch: z.number().default(0).nullish(), // Measurements, 0 is fine as default
trbt: z.number().default(0).nullish(), // Measurements, 0 is fine as default
bod: z.number().default(0).nullish(), // Measurements, 0 is fine as default
smll:z.string().default('').nullish(), // Measurements, 0 is fine as default
crmty: z.number().default(0).nullish(), // Measurements, 0 is fine as default
tn: z.number().default(0).nullish(), // Measurements, 0 is fine as default
tph:z.number().default(0).nullish(),// Measurements, 0 is fine as default
ph: z.string().default('').nullish(), // Measurements, 0 is fine as default
clIonQnt: z.number().default(0).nullish(), // Measurements, 0 is fine as default
cdtnv: z.number().default(0).nullish(), // Measurements, 0 is fine as default
emsnExitTp: z.number()
.max(100, { message: "온도는 100이상이 될 수 없습니다." })
.default(0), // Changed max to 100 based on message, // Measurements, 0 is fine as default
@@ -53,7 +53,7 @@ export const pbnstDemandHeadListExport: TableUpperProps[] = [
export const pbnstOrgwtHeadListRxport: TableUpperProps[] = [
{ id: "ruseUtztnFcltNm", title: "하수처리장명" },
{ id: "orgwtWtritQnt", title: "원수취수량", type: "number" },
{ id: "orgwtWtritQnt", title: "원수취수량(m³/일)", type: "number" },
{ id: "tmsYn", title: "하수처리량TMS 전후" },
{ id: "dschgFmYn", title: "하수처리장 방류 유량계 전·후​" },
{ id: "dtlPstnExpln", title: "상세위치", edit: true },
@@ -141,7 +141,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [
},
{
id: "fctCpc",
title: "시설용량(톤/일)",
title: "시설용량(m³/일)",
visible: true,
row: 1,
rowSpan: 2,
@@ -157,7 +157,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [
},
{
id: "rusSup",
title: "재이용수공급가능량",
title: "재이용수공급가능량(m³/일)",
visible: true,
row: 1,
rowSpan: 1,
@@ -226,7 +226,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [
},
{
id: "fcltCpct",
title: "시설용량(m³/일)",
title: "시설용량",
upName: "rusSup",
visible: true,
row: 2,
@@ -235,7 +235,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [
},
{
id: "splyExtraCpct",
title: "하수처리량(m³/일)",
title: "하수처리량",
upName: "rusSup",
visible: true,
row: 2,
@@ -244,7 +244,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [
},
{
id: "ruseCpct",
title: "재이용량(m³/일)",
title: "재이용량",
upName: "rusSup",
visible: true,
row: 2,
@@ -337,7 +337,7 @@ export const ruseFcltNodeListExport: TableUpperProps[] = [
},
{
id: "mainSplyPumpCpct",
title: "메인공급펌프용량",
title: "메인공급펌프용량(m³/일)",
visible: true,
row: 1,
rowSpan: 3,
@@ -345,7 +345,7 @@ export const ruseFcltNodeListExport: TableUpperProps[] = [
},
{
id: "buziFee",
title: "사업비(백만원)",
title: "사업비(원)",
visible: true,
row: 2,
rowSpan: 1,
@@ -418,7 +418,7 @@ export const ruseFcltNodeListExport: TableUpperProps[] = [
},
{
id: "cusrAlotm",
title: "민간투자비",
title: "민간투자비",
visible: true,
row: 3,
rowSpan: 1,
@@ -438,7 +438,7 @@ export const ruseFcltNodeListExport: TableUpperProps[] = [
export const ruseSplyHeadListExport: TableUpperProps[] = [
{ id: "cycl", title: "차수", visible: true },
{ id: "orgwtWtritQnt", title: "원수취수량", visible: true },
{ id: "orgwtWtritQnt", title: "원수취수량(m³/일)", visible: true },
{ id: "tmsYn", title: "하수처리량TMS 전후", visible: true },
{ id: "dschgFmYn", title: "하수처리장 방류 유량계 전·후​", visible: true },
{ id: "dtlPstnExpln", title: "상세위치 설명", visible: true },
@@ -447,8 +447,8 @@ export const ruseSplyHeadListExport: TableUpperProps[] = [
export const rusePplHeadListExport: TableUpperProps[] = [
{ id: "cycl", title: "차수", visible: true },
{ id: "ppMqlt", title: "관재질", type: "select", visible: true },
{ id: "pdmt", title: "관경", type: "select", visible: true },
{ id: "cpct", title: "연장", edit: true, visible: true },
{ id: "pdmt", title: "관경(mm)", type: "select", visible: true },
{ id: "cpct", title: "연장(m)", edit: true, visible: true },
];
export const ruseGuranteeHeadListExport: TableUpperProps[] = [
@@ -458,10 +458,10 @@ export const ruseGuranteeHeadListExport: TableUpperProps[] = [
{ id: "combResdch", title: "결합잔류염소(mh/L)", visible: true },
{ id: "trbt", title: "탁도(NTU)", visible: true },
{ id: "smll", title: "냄새", visible: true },
{ id: "crmty", title: "색도", visible: true },
{ id: "crmty", title: "색도(도)", visible: true },
{ id: "tn", title: "총질소(mg/L)", visible: true },
{ id: "tph", title: "총인(mg/L)", visible: true },
{ id: "ph", title: "수소이온농도", visible: true },
{ id: "ph", title: "수소이온농도(PH)", visible: true },
{ id: "clIonQnt", title: "염화물(mg/L)", visible: true },
{ id: "cdtnv", title: "전기전도도(μs/cm)​", visible: true },
];
@@ -228,7 +228,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "archArea",
title: "건축면적",
title: "건축면적(m³)",
upName: "bdnstInfo",
visible: true,
row: 2,
@@ -265,7 +265,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
{
id: "instlCst",
title: "설치비용",
title: "설치비용(원)",
upName: "rainFcltInfo",
visible: true,
row: 2,
@@ -285,7 +285,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
{
id: "pntfColKnd",
title: "집수지점종류",
title: "종류",
upName: "pntfCol",
visible: true,
row: 3,
@@ -294,7 +294,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "pntfColArea",
title: "집수지점면적",
title: "면적(m²)",
upName: "pntfCol",
visible: true,
row: 3,
@@ -304,7 +304,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
{
id: "dtfcltCpct",
title: "저류조용량",
title: "저류조용량(m³)",
upName: "rainFcltInfo",
visible: true,
row: 2,
@@ -322,7 +322,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "filtrTrtmfctCpct",
title: "여과처리시설용량",
title: "여과처리시설용량(m³)",
upName: "filtrTrtmfct",
visible: true,
row: 3,
@@ -359,7 +359,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "instlCstSprtAmt",
title: "설치지원비용",
title: "설치지원비용(원)",
upName: "instlCstSprt",
visible: true,
row: 3,
@@ -379,7 +379,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
{
id: "grntchBdstCertYn",
title: "녹색건축물인증여부",
title: "인증여부",
upName: "grntchBdstCert",
visible: true,
row: 3,
@@ -388,7 +388,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "grntchBdstCertYr",
title: "녹색건축물인증년도",
title: "인증년도",
upName: "grntchBdstCert",
visible: true,
row: 3,
@@ -397,7 +397,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "grntchBdstCertNo",
title: "녹색건축물인증번호",
title: "인증번호",
upName: "grntchBdstCert",
visible: true,
row: 3,
@@ -406,7 +406,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [
},
{
id: "grntchBdstCertGrd",
title: "녹색건축물인증등급",
title: "인증등급",
upName: "grntchBdstCert",
visible: true,
row: 3,
+195 -133
View File
@@ -2,158 +2,215 @@ import { fetchType, getFetch } from "@/components/lib/api";
import type { TableUpperProps } from "../../common/type/header";
import { excelRainStat } from "./excel";
import { rainStatHeadListExport } from "./headList";
import type { SelectDataType } from "@common/business_components/ui";
export type RainStatProps = {
cityText: string
ctpvCd: string //시도
sggCd: string //시군구
areaNm: string //행정구역명
bdstNm: string //시설명
bdstUsgCd: string //건축물용도코드
daddr: string //주소
lawTrgtYn: string //법적의무대상여부
instlCmptnDt: string //설치완료일자
instlCst: number //설치비용
pntfColKnd: string //접수면종류
filtrTrtmfctYn: string //여과등처리시설유무
archArea: number //건축연면적
dtfcltCpct: number //처리용량(저류조용량)
wtrUsqty: number //연간사용량
utztnUsgCd: string //이용용도코드
anlOperCst: number //연간운영비
annRnwtQty: number //물사용량
jungsudo: number //중수도​이용량
dachae: number //대체수​이용량
lndwtr: number //조경용수
cleanToilUswtr: number //청소화장실용수
resn: number //세척살수용수
farmUswtr: number //농업용수
indstUswtr: number //공업용수
hydUswtr: number //친수용수
ithlEtcUswtr: number //기타
tmp: number //개소
guideStats: GuideStatProps[]
}
cityText: string;
ctpvCd: string; //시도
sggCd: string; //시군구
areaNm: string; //행정구역명
bdstNm: string; //시설명
bdstUsgCd: string; //건축물용도코드
daddr: string; //주소
lawTrgtYn: string; //법적의무대상여부
instlCmptnDt: string; //설치완료일자
instlCst: number; //설치비용
pntfColKnd: string; //접수면종류
filtrTrtmfctYn: string; //여과등처리시설유무
archArea: number; //건축연면적
dtfcltCpct: number; //처리용량(저류조용량)
wtrUsqty: number; //연간사용량
utztnUsgCd: string; //이용용도코드
anlOperCst: number; //연간운영비
annRnwtQty: number; //물사용량
jungsudo: number; //중수도​이용량
dachae: number; //대체수​이용량
lndwtr: number; //조경용수
cleanToilUswtr: number; //청소화장실용수
resn: number; //세척살수용수
farmUswtr: number; //농업용수
indstUswtr: number; //공업용수
hydUswtr: number; //친수용수
ithlEtcUswtr: number; //기타
tmp: number; //개소
guideStats: GuideStatProps[];
};
export type GuideStatProps = {
utztnUsgCd: string
splyUswtrUtztnQnt : number,
ruseFcltUtztnQnt: number
}
utztnUsgCd: string;
splyUswtrUtztnQnt: number;
ruseFcltUtztnQnt: number;
};
type ExcelType = {
[key: string]: string | number | undefined;
[key: string]: string | number | undefined;
};
const excelDownList: ExcelType[] = [];
const fetchRainStatList = async (year: string) => {
const res = await getFetch(fetchType.WR, `/reuseChk/rainy/stat/${year}`)
return res;
}
const res = await getFetch(fetchType.WR, `/reuseChk/rainy/stat/${year}`);
return res;
};
type rainStatActions = {
searchRainStatList: (year: string) => void
}
searchRainStatList: (year: string, city: SelectDataType[]) => void;
};
export type rainStatState = {
rainStat: {
rainStatHeadList: TableUpperProps[],
rainStatList: RainStatProps[],
excelList: ExcelType[]
rainDetailList : [][]
}
}
rainStat: {
rainStatHeadList: TableUpperProps[];
rainStatList: RainStatProps[];
excelList: ExcelType[];
rainDetailList: [][];
};
};
export type rainStatType = rainStatState & rainStatActions;
export const rainStatExport: rainStatState = {
rainStat: {
rainStatHeadList: rainStatHeadListExport,
rainStatList: [],
excelList: [],
rainDetailList : []
}
}
rainStat: {
rainStatHeadList: rainStatHeadListExport,
rainStatList: [],
excelList: [],
rainDetailList: [],
},
};
export const rainStatActionsExport = (
set: (fn: (state: rainStatState) => rainStatState) => void
set: (fn: (state: rainStatState) => rainStatState) => void
) => {
return {
searchRainStatList: async (year: string) => {
const res = await fetchRainStatList(year);
const cityArr: any[] = [];
res.forEach((item: RainStatProps) => {
return {
searchRainStatList: async (year: string, city: SelectDataType[]) => {
const res = await fetchRainStatList(year);
const cityArr: any[] = [];
let obj = cityArr.find((e) => {
return e.ctpvCd == item.ctpvCd
})
res.filter((resFilter: RainStatProps) =>
city.some((cityCd) =>
resFilter.ctpvCd?.trim() === cityCd.val.trim()
)
)
.forEach((item: RainStatProps) => {
let obj = cityArr.find((e) => {
return e.ctpvCd == item.ctpvCd;
});
if (obj) {
obj.instlCst += item.instlCst
obj.dtfcltCpct += item.dtfcltCpct
obj.wtrUsqty += item.wtrUsqty
obj.anlOperCst += item.anlOperCst
obj.tmp += 1
} else {
obj = {};
obj.ctpvCd = item.ctpvCd
obj.instlCst = item.instlCst
obj.tmp = 1
obj.dtfcltCpct = item.dtfcltCpct
obj.wtrUsqty = item.wtrUsqty
obj.anlOperCst = item.anlOperCst
if (obj) {
obj.instlCst += item.instlCst;
obj.dtfcltCpct += item.dtfcltCpct;
obj.wtrUsqty += item.wtrUsqty;
obj.anlOperCst += item.anlOperCst;
obj.tmp += 1;
} else {
obj = {};
obj.ctpvCd = item.ctpvCd;
obj.instlCst = item.instlCst;
obj.tmp = 1;
obj.dtfcltCpct = item.dtfcltCpct;
obj.wtrUsqty = item.wtrUsqty;
obj.anlOperCst = item.anlOperCst;
cityArr.push(obj)
cityArr.push(obj);
}
if (item.guideStats && item.guideStats.length > 0) {
item.guideStats.forEach((guide: GuideStatProps) => {
rainStatHeadListExport.forEach((headItem: TableUpperProps) => {
if (headItem.title == guide.utztnUsgCd) {
if (!obj[headItem.id] || typeof obj[headItem.id] !== "number")
obj[headItem.id] = 0;
if (typeof obj[headItem.id] === "number") {
obj[headItem.id] += guide.ruseFcltUtztnQnt;
}
}
});
});
}
});
if (item.guideStats && item.guideStats.length > 0) {
item.guideStats.forEach((guide: GuideStatProps) => {
rainStatHeadListExport.forEach((headItem: TableUpperProps) => {
const totalObj = {
ctpvCd: "0",
tmp: 0,
instlCst: 0, //설치비
dtfcltCpct: 0, //저류조용량
bdstUsgCd: 0, //연간사용량
lndwtr: 0, //조경용수
cleanToilUswtr: 0, //청소화장실용수
resn: 0, //세척살수용수
farmUswtr: 0, //농업용수
indstUswtr: 0, //공업용수
hydUswtr: 0, //친수용수
ithlEtcUswtr: 0, //기타
anlOperCst: 0, //연간운영비
} as any;
if (headItem.title == guide.utztnUsgCd) {
if (!obj[headItem.id] || typeof obj[headItem.id] !== "number") obj[headItem.id] = 0;
if (typeof obj[headItem.id] === "number") {
cityArr.forEach((item) => {
// if(item.ctpvCd === '0') return; // Skip total object if exists
totalObj.tmp += !isNaN(Number(item.tmp)) ? Number(item.tmp) : 0;
totalObj.instlCst += !isNaN(Number(item.instlCst))
? Number(item.instlCst)
: 0;
totalObj.dtfcltCpct += !isNaN(Number(item.dtfcltCpct))
? Number(item.dtfcltCpct)
: 0;
totalObj.bdstUsgCd += !isNaN(Number(item.bdstUsgCd))
? Number(item.bdstUsgCd)
: 0;
totalObj.lndwtr += !isNaN(Number(item.lndwtr))
? Number(item.lndwtr)
: 0;
totalObj.cleanToilUswtr += !isNaN(Number(item.cleanToilUswtr))
? Number(item.cleanToilUswtr)
: 0;
totalObj.resn += !isNaN(Number(item.resn)) ? Number(item.resn) : 0;
totalObj.farmUswtr += !isNaN(Number(item.farmUswtr))
? Number(item.farmUswtr)
: 0;
totalObj.indstUswtr += !isNaN(Number(item.indstUswtr))
? Number(item.indstUswtr)
: 0;
totalObj.hydUswtr += !isNaN(Number(item.hydUswtr))
? Number(item.hydUswtr)
: 0;
totalObj.ithlEtcUswtr += !isNaN(Number(item.ithlEtcUswtr))
? Number(item.ithlEtcUswtr)
: 0;
totalObj.anlOperCst += !isNaN(Number(item.anlOperCst))
? Number(item.anlOperCst)
: 0;
obj[headItem.id] += guide.ruseFcltUtztnQnt;
}
}
});
})
}
})
excelDownList.push({
ctpvCd: item.ctpvCd,
tmp: item.tmp,
instlCst: item.instlCst, //설치비
dtfcltCpct: item.dtfcltCpct, //저류조용량
bdstUsgCd: item.bdstUsgCd, //연간사용량
lndwtr: item.lndwtr, //조경용수
cleanToilUswtr: item.cleanToilUswtr, //청소화장실용수
resn: item.resn, //세척살수용수
farmUswtr: item.farmUswtr, //농업용수
indstUswtr: item.indstUswtr, //공업용수
hydUswtr: item.hydUswtr, //친수용수
ithlEtcUswtr: item.ithlEtcUswtr, //기타
anlOperCst: item.anlOperCst, //연간운영비
});
});
cityArr.forEach(item => {
excelDownList.push({
ctpvCd: item.ctpvCd,
tmp: item.tmp,
instlCst: item.instlCst, //설치비
dtfcltCpct: item.dtfcltCpct, //저류조용량
bdstUsgCd: item.bdstUsgCd, //연간사용량
lndwtr: item.lndwtr, //조경용수
cleanToilUswtr: item.cleanToilUswtr, //청소화장실용수
resn: item.resn, //세척살수용수
farmUswtr: item.farmUswtr, //농업용수
indstUswtr: item.indstUswtr, //공업용수
hydUswtr: item.hydUswtr, //친수용수
ithlEtcUswtr: item.ithlEtcUswtr, //기타
anlOperCst: item.anlOperCst, //연간운영비
})
})
//상세
const rainDetailList : RainStatProps[] = [];
res.forEach((item:RainStatProps) => {
const utztnUsgArray = new Array<string>();
item.guideStats.forEach((guideStat) => {
utztnUsgArray.push(guideStat.utztnUsgCd);
})
rainDetailList.push({
...item,
utztnUsgCd : utztnUsgArray.join(', '),
})
})
const excelDetailData = excelRainStat(rainDetailList);
/* const rainStatHeadList = data.map((item:RainStatProps) => ({
//상세
const rainDetailList: RainStatProps[] = [];
res.forEach((item: RainStatProps) => {
const utztnUsgArray = new Array<string>();
item.guideStats.forEach((guideStat) => {
utztnUsgArray.push(guideStat.utztnUsgCd);
});
rainDetailList.push({
...item,
utztnUsgCd: utztnUsgArray.join(", "),
});
});
const excelDetailData = excelRainStat(rainDetailList);
/* const rainStatHeadList = data.map((item:RainStatProps) => ({
...item,
ctpvCd:item.ctpvCd,
sggCd:item.sggCd,
@@ -172,14 +229,19 @@ export const rainStatActionsExport = (
way7:item.way7,
yearMoney:item.yearMoney,
})) */
set((state: rainStatState) => ({
rainStat: {
...state.rainStat,
rainDetailList: excelDetailData as [][],
rainStatList: cityArr,
excelList: excelDownList
}
}));
}
}
}
console.log(" cityArr ", cityArr);
console.log(" excelDownList ", excelDownList);
cityArr.unshift(totalObj);
set((state: rainStatState) => ({
rainStat: {
...state.rainStat,
rainDetailList: excelDetailData as [][],
rainStatList: cityArr,
excelList: excelDownList,
},
}));
},
};
};
+10 -4
View File
@@ -98,6 +98,7 @@ import { rainStatActionsExport, rainStatExport, type rainStatState, type rainSta
import { rswtStatActionsExport, rswtStatExport, type rswtStatState, type rswtStatType } from "./stats/rswtStat";
//import { isLogin } from "./common/login";
import { LoginApi } from "@/src/entities/auth";
import { authActionsExport, authStateExport, type authState, type authType } from "./common/auth";
export type WrStore = comCodeType &
pubFacType &
@@ -124,7 +125,9 @@ export type WrStore = comCodeType &
ruseCaseType&
rainStatType&
rswtStatType&
comFcltType
comFcltType &
authType
;
export const StoreZus = (
@@ -153,7 +156,8 @@ export const StoreZus = (
drgtState&
ruseCaseState&
rainStatState&
rswtStatState
rswtStatState&
authState
= {
...comCodeStateExport,
...pubFacStateExport,
@@ -180,7 +184,8 @@ export const StoreZus = (
...ruseCaseStateExport,
...rainStatExport,
...rswtStatExport,
...comFcltStateExport
...comFcltStateExport,
...authStateExport
}
) => {
return createStore<WrStore>()((set) => {
@@ -218,7 +223,8 @@ export const StoreZus = (
...drgtActionsExport(set),
...ruseCaseActionsExport(set),
...rainStatActionsExport(set),
...rswtStatActionsExport(set)
...rswtStatActionsExport(set),
...authActionsExport(set)
};
});
};
+61 -31
View File
@@ -3,6 +3,7 @@ import type { TableUpperProps } from "@/app/store/common/type/header";
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui";
import { formatCommaNumber, handleCommaNumberChange } from "./commom";
export const rainChkTableData = (chkData: rainChkZodType[]) => {
// 1. chkgdnSn + utztnUsgCd 기준 누계 정보 만들기
@@ -141,7 +142,12 @@ export const chRowspanTable = (
) : key === "order" ? (
++order
) : (
value
// value
(["anlOperCst", "dtfcltCpct", "prcsCpct"].includes(head.id)) ? (
formatCommaNumber(value)
) : (
<>{value}</>
)
)}
</TableCell>
);
@@ -155,26 +161,44 @@ export const chRowspanTable = (
onClick={() => handleCellClick(rowIndex, head.id)}
>
{head.edit === true ? (
<Input
className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`}
type={head.type}
onChange={(e) => {
handleChange(rowIndex, head.id, e.target.value);
}}
value={value || ""}
disabled={!selectedIds.includes(row.chkgdnSn)}
maxLength={numSize}
//input type number일때 slice 처리
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
if (head.type === 'number' && e.target.value.length > numSize) {
e.target.value = e.target.value.slice(0, numSize);
}
}}
/>
(["levyAmt", "anlOperCst", "dtfcltCpct", "prcsCpct"].includes(head.id)) ? (
<Input
className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`}
type={head.type}
onChange={(e) => {
handleCommaNumberChange(e, val =>
handleChange(rowIndex, head.id, val))
}}
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);
}
}}
/>
) : (
<Input
className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`}
type={head.type}
onChange={(e) => {
handleChange(rowIndex, head.id, e.target.value);
}}
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);
}
}}
/>
)
) : (
(head.id === "totalSplyUswtrUtztnQnt" || head.id === "totalRuseFcltUtztnQnt" || head.id === "splyUswtrUtztnQnt" || head.id === "ruseFcltUtztnQnt") ? (
<span className="underline text-blue-600 cursor-pointer">
{value}
(["totalSplyUswtrUtztnQnt", "totalRuseFcltUtztnQnt", "splyUswtrUtztnQnt", "ruseFcltUtztnQnt", "levyAmt"].includes(head.id)) ? (
<span className={["totalSplyUswtrUtztnQnt", "totalRuseFcltUtztnQnt", "splyUswtrUtztnQnt", "ruseFcltUtztnQnt"].includes(head.id) ? "underline text-blue-600 cursor-pointer" : ""}>
{formatCommaNumber(value)}
</span>
) : (
<>{value}</>
@@ -182,7 +206,6 @@ export const chRowspanTable = (
)}
</TableCell>
);
})}
</TableRow>
))) : (
@@ -210,20 +233,18 @@ export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean)
const handleChange = (
rowIndex: number,
field: any,
value: string | number,
value: string,
setInputData: (data: any) => void
) => {
if (Number(value) < 0 || !Number(value)) {
value = 0;
} else {
value = Number(value);
value = "0";
}
setInputData((prevData: any) =>
prevData?.map((row: any, index: number) => {
if (index === rowIndex) {
return {
...row,
[field]: value,
[field]: Number(value.replace(/,/g, "")),
};
}
return row;
@@ -271,7 +292,7 @@ export const InputTableBody = (
// 총합계 행이면 "구분"에서 colSpan=2로 병합
if (
data["구분"] === 0 &&
(data["구분"] === 0 || data["용수명"] === 0) &&
head.id === "구분"
) {
return (
@@ -286,18 +307,27 @@ export const InputTableBody = (
}
// 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음
if (
data["구분"] === 0 &&
(data["구분"] === 0 || data["용수명"] === 0) &&
head.id === "용수명"
) {
return null;
}
// 총합계 행의 나머지 셀에도 색상 적용
if (data["구분"] === 0 || data["용수명"] === 0) {
return (
<TableCell key={head.id + headIndex} className="bg-[#d5e1eb] font-bold text-right">
{Number(data[head.id]) ? formatCommaNumber(data[head.id as keyof any]) : data[head.id as keyof any] ?? ""}
</TableCell>
);
}
// mergeCell 처리
if (head.mergeCell) {
const rowSpan = getRowSpan(chgRes, head.id, dataIndex);
if (rowSpan === 0) return null;
return (
<TableCell key={head.id + headIndex} rowSpan={rowSpan} className={`w-36 align-middle text-center whitespace-nowrap ${bgClass}`}>
{data[head.id as keyof any] ?? ""}
{Number(data[head.id]) ? formatCommaNumber(data[head.id as keyof any]) : data[head.id as keyof any] ?? ""}
</TableCell>
);
}
@@ -311,7 +341,7 @@ export const InputTableBody = (
onChange={(e) =>
handleChange(dataIndex, head.id, e.target.value, setInputData)
}
value={data[head.id as keyof any] ?? ""}
value={formatCommaNumber(data[head.id as keyof any]) ?? ""}
maxLength={numSize}
/>
</TableCell>
@@ -324,7 +354,7 @@ export const InputTableBody = (
// `}
className={`${textAlignClass} !text-xl w-full h-10`}
>
{data[head.id as keyof any] ?? ""}
{Number(data[head.id]) ? formatCommaNumber(data[head.id as keyof any]) : data[head.id as keyof any] ?? ""}
</div>
</TableCell>
);
+11
View File
@@ -116,6 +116,17 @@ export const handleCommaNumberChange = (
onChange(raw === "" ? "" : Number(raw));
};
export const handleOnlyNumberChange = (
e: React.ChangeEvent<HTMLInputElement>,
onChange: (value: number | "") => void
) => {
// 콤마 제거 후 숫자와 소수점만 남기기
const cleaned = e.target.value.replace(/,/g, "").replace(/[^0-9.]/g, "");
// 숫자 및 소수점 외 입력 차단
if (!/^\d*\.?\d*$/.test(cleaned)) return;
onChange(cleaned === "" ? "" : Number(cleaned));
};
// onchange 텍스트를 숫자로 and ,제거
export const handleMinusNumberChange = (
e: React.ChangeEvent<HTMLInputElement>,
@@ -85,7 +85,7 @@ export default function ConCostForm({
const calculateConstCost = useCallback(() => {
const usgPrcsProcs = usgPrcsProcsWatch;
if (!dmndQtyWatch) {
toast.error("요구수량(M3/d)을 확인해주세요 계산할수 없습니다. ");
toast.error("요구수량(m³/일)을 확인해주세요 계산할수 없습니다. ");
return;
}
if (usgPrcsProcs === null || usgPrcsProcs === undefined) {
@@ -278,7 +278,7 @@ export default function ConCostForm({
control={form.control}
name="dmndQty"
render={({ field }) => (
<FormUi label="요구수량(M3/d)">
<FormUi label="요구수량(m³/일)">
<Input
placeholder=""
type="number"
@@ -315,7 +315,7 @@ export default function ConCostForm({
]}
pageSize={0}
total={0}
cellClick={() => {}}
cellClick={undefined}
onPageChange={() => {}}
/>
</>
@@ -344,7 +344,7 @@ export default function ConCostForm({
control={form.control}
name="dmndQty"
render={({ field }) => (
<FormUi label="처리시설 용량(요구수량 * 365일)">
<FormUi label="처리시설용량(m³/일)">
<Input
placeholder=""
type="number"
@@ -2,15 +2,14 @@ import { useWrStore } from "@/app/store";
import { numSize, txtSize } from "@/app/store/common/code/basicCode";
import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { formH1Class } from "@/components/lib/class/comClass";
import { handleCommaNumberChange } from "@/components/lib/func/commom";
import {
DatePicker,
FormField,
FormUi,
DatePicker,
SelectBox,
type SelectDataType,
} from "@common/business_components";
import { Input } from "@common/components";
import { Input } from "@common/components";
import { useEffect, useState } from "react";
export default function BdstReg({ form, type }: { form: any; type?: string }) {
@@ -18,39 +17,39 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
return state;
});
const {userSiSggCd } =code
const { userSiSggCd } = code
const [useCityCd, setUserCityCd] = useState<SelectDataType[]>([])
const [useSggCd, setUserSggCd] = useState<SelectDataType[]>([])
// const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>();
// const [objSearch, setObjSearch] = useState<objSearchType>({
// sgg: "",
// city: "",
// });
useEffect(() =>{
if(userSiSggCd.length===2 && code.cityCd.length>0){
useEffect(() => {
if (userSiSggCd.length === 2 && code.cityCd.length > 0) {
const city = code.cityCd.filter((item) => item.val === userSiSggCd)
const sgg = code.sggCd.filter((item) => item.val.slice(0,2) === userSiSggCd )
sgg.unshift({text:'전체' , val:'0'})
const sgg = code.sggCd.filter((item) => item.val.slice(0, 2) === userSiSggCd)
sgg.unshift({ text: '전체', val: '0' })
setUserCityCd(city) // Fix: Ensure city is of type SelectDataType[]
setUserSggCd(sgg)
if (city[0]?.val) {
// 여기 중요
queueMicrotask(() => {
form.setValue("ctpvCd", Number(city[0]?.val), { shouldDirty: true, shouldTouch: true, shouldValidate: true });
});
// 여기 중요
queueMicrotask(() => {
form.setValue("ctpvCd", Number(city[0]?.val), { shouldDirty: true, shouldTouch: true, shouldValidate: true });
});
}
}else if(userSiSggCd.length===5 && code.cityCd.length>0 && code.sggCd.length>0) {
const city = code.cityCd.filter((item) => item.val === userSiSggCd.slice(0,2))
} else if (userSiSggCd.length === 5 && code.cityCd.length > 0 && code.sggCd.length > 0) {
const city = code.cityCd.filter((item) => item.val === userSiSggCd.slice(0, 2))
const sgg = code.sggCd.filter((item) => item.val === userSiSggCd)
setUserSggCd(sgg)
setUserCityCd(city)
form.setValue('ctpvCd',Number(city[0]?.val) )
form.setValue('sggCd',Number(sgg[0]?.val) )
form.setValue('ctpvCd', Number(city[0]?.val))
form.setValue('sggCd', Number(sgg[0]?.val))
}
},[form, userSiSggCd, code.cityCd, code.sggCd])
}, [form, userSiSggCd, code.cityCd, code.sggCd])
@@ -70,15 +69,13 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
useEffect(() =>{
console.log('form.formState ', form.watch())
},[form.formState])
useEffect(() => {
console.log('form.formState ', form.watch("archArea"))
}, [form.formState])
return (
<>
<h1 className={formH1Class}> { type !== "HTB"?"건축물 기본 정보": '시설 기본 정보'}</h1>
<h1 className={formH1Class}> {type !== "HTB" ? "건축물 기본 정보" : '시설 기본 정보'}</h1>
<div className="grid grid-cols-6 gap-2 mt-4">
<div className="col-span-3">
<FormField
@@ -127,16 +124,16 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
control={form.control}
name="bdstNm"
render={({ field }) => (
<FormUi label={ type !== "HTB"?"건축물명": '시설명'}>
<FormUi label={type !== "HTB" ? "건축물명" : '시설명'}>
<Input
className={selectClass}
placeholder= {type !== "HTB"?"건축물 명 입력하세요":'시설명 입력하세요' }
placeholder={type !== "HTB" ? "건축물 명 입력하세요" : '시설명 입력하세요'}
type="text"
onChange={(e) => {
field.onChange(e.target.value)
}}
value={field.value||''}
maxLength={txtSize}
onChange={(e) => {
field.onChange(e.target.value)
}}
value={field.value || ''}
maxLength={txtSize}
/>
</FormUi>
)}
@@ -147,16 +144,16 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
control={form.control}
name="daddr"
render={({ field }) => (
<FormUi label= { type !== "HTB"?"건축물 주소": '시설 주소'} >
<FormUi label={type !== "HTB" ? "건축물 주소" : '시설 주소'} >
<Input
className={selectClass}
placeholder="위치를 입력해주세요"
type="search"
onChange={(e) => {
field.onChange(e.target.value)
}}
value={field.value||''}
maxLength={50}
}}
value={field.value || ''}
maxLength={50}
/>
</FormUi>
)}
@@ -168,7 +165,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
control={form.control}
name="frstArchPrmsnDt"
render={({ field }) => (
<FormUi label= { type !== "HTB"?"최초건축허가일": '준공년도'} >
<FormUi label={type !== "HTB" ? "최초건축허가일" : '준공년도'} >
<DatePicker
mode={"single"}
field={{
@@ -221,9 +218,9 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
placeholder="면적을 입력하세요"
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
field.onChange(e.target.value)
}}
value={field.value||''}
value={field.value || ''}
maxLength={numSize}
/>
</FormUi>
@@ -251,7 +248,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) {
/>
</div>
</div>
</>
</>
) : (
<></>
)}
@@ -12,6 +12,7 @@ import {
confirmToast,
formatCommaNumber,
handleCommaNumberChange,
handleOnlyNumberChange,
} from "@/components/lib/func/commom";
import {
Form,
@@ -19,9 +20,9 @@ import {
FormUi,
SelectBox,
} from "@common/business_components/ui";
import { Button, Input, ScrollArea } from "@common/components/ui";
import { Button, Input, Label, ScrollArea } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
@@ -40,6 +41,8 @@ export default function HtdflRegForm({
setIsModal?: (modal: boolean) => void;
}) {
const { code, htdflBdstUpdate, htdflBdstReg } = useWrStore((state) => state);
const [frontPHdata, setFrontPHdata] = useState("");
const [backPHdata, setBackPHdata] = useState("");
const defaultValues: z.infer<typeof hdtflZod> = hdtflZod.parse({});
@@ -51,7 +54,7 @@ export default function HtdflRegForm({
const bdstNm = form.watch("bdstNm");
const isPowerPlant = bdstNm?.includes("발전소");
const { t } = useTranslation('base');
const { t } = useTranslation("base");
const onSubmit = (values: z.infer<typeof hdtflZod>) => {
if (isModal) {
const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd";
@@ -63,13 +66,12 @@ export default function HtdflRegForm({
htdflBdstReg(values, data);
if (setIsModal) setIsModal(false);
};
confirmToast(t('isInsertMsg'), handleConfirm);
confirmToast(t("isInsertMsg"), handleConfirm);
} else {
const handleConfirm = async () => {
htdflBdstUpdate(values, "0");
};
confirmToast(t('isUpdateMsg'), handleConfirm);
confirmToast(t("isUpdateMsg"), handleConfirm);
}
};
@@ -97,12 +99,51 @@ export default function HtdflRegForm({
})),
};
};
const isSetFrontPh = useCallback(
(frontPHdata: string) => {
setFrontPHdata(frontPHdata);
if (!frontPHdata) {
form.setValue(`reuseBuilding.0.htdflObj.ph`, "");
return;
}
const PHdata = form.getValues(`reuseBuilding.0.htdflObj.ph`);
let backPH;
if (PHdata && String(PHdata).includes("~")) {
backPH = PHdata.split("~")[1];
} else {
backPH = String(Number(frontPHdata) + 1);
}
const MatchData = `${frontPHdata}~${backPH}`;
form.setValue(`reuseBuilding.0.htdflObj.ph`, MatchData);
},
[form]
);
const isSetBackPh = useCallback(
(backPHdata: string) => {
setBackPHdata(backPHdata);
if (!backPHdata) {
form.setValue(`reuseBuilding.0.htdflObj.ph`, "");
return;
}
const PHdata = form.getValues(`reuseBuilding.0.htdflObj.ph`);
let frontPH;
if (PHdata && String(PHdata).includes("~")) {
frontPH = PHdata.split("~")[0];
} else {
frontPH = String(Math.max(Number(backPHdata) - 1, 0));
}
const MatchData = `${frontPH}~${backPHdata}`;
form.setValue(`reuseBuilding.0.htdflObj.ph`, MatchData);
},
[form]
);
const [divStyle, setDivStyle] = useState("h-[53vh]");
useEffect(() => {
if (isModal === true) {
setDivStyle("h-[53vh] max-h-[37vh]")
setDivStyle("h-[53vh] max-h-[37vh]");
} else if (readonly === true) {
setDivStyle("h-[62vh]")
setDivStyle("h-[62vh]");
} else {
setDivStyle("h-[57vh]")
}
@@ -116,7 +157,25 @@ export default function HtdflRegForm({
useEffect(() => {
// Case 1: 수정 또는 '복사하여 등록' 등 데이터가 주입되는 경우
if (htdflForm && Object.keys(htdflForm).length > 0) {
const htdflPH = htdflForm.reuseBuilding[0]?.htdflObj.ph
if(htdflPH && String(htdflPH).includes("~")){
const [frontPH, backPH] = htdflPH.split("~");
if (frontPH) {
setFrontPHdata(frontPH);
}
if (backPH) {
setBackPHdata(backPH);
}
} else {
setFrontPHdata("");
setBackPHdata("");
}
form.reset(cleanHtdflData(htdflForm));
}else{
form.reset();
}
// Case 2: 데이터가 없는 순수 신규 등록 모드인 경우
if (isModal) {
@@ -125,15 +184,33 @@ export default function HtdflRegForm({
const firstHtdUtztnUsgCd = code.htdUtztnUsgCd?.[0]?.val;
if (firstHtdPowerMthdCd) {
form.setValue('reuseBuilding.0.htdflObj.etgtType', firstHtdPowerMthdCd, { shouldDirty: true });
form.setValue(
"reuseBuilding.0.htdflObj.etgtType",
firstHtdPowerMthdCd,
{ shouldDirty: true }
);
}
if (firstYnValue) {
form.setValue('reuseBuilding.0.htdflObj.plwtYn', firstYnValue as "Y" | "N", { shouldDirty: true });
form.setValue('reuseBuilding.0.htdflObj.prcsProcsYn', firstYnValue as "Y" | "N", { shouldDirty: true });
form.setValue('reuseBuilding.0.htdflObj.fmYn', firstYnValue as "Y" | "N", { shouldDirty: true });
form.setValue(
"reuseBuilding.0.htdflObj.plwtYn",
firstYnValue as "Y" | "N",
{ shouldDirty: true }
);
form.setValue(
"reuseBuilding.0.htdflObj.prcsProcsYn",
firstYnValue as "Y" | "N",
{ shouldDirty: true }
);
form.setValue(
"reuseBuilding.0.htdflObj.fmYn",
firstYnValue as "Y" | "N",
{ shouldDirty: true }
);
}
if (firstHtdUtztnUsgCd) {
form.setValue('reuseBuilding.0.htdflObj.utztnUsg', firstHtdUtztnUsgCd, { shouldDirty: true });
form.setValue("reuseBuilding.0.htdflObj.utztnUsg", firstHtdUtztnUsgCd, {
shouldDirty: true,
});
}
}
}, [htdflForm, code, form]);
@@ -142,12 +219,37 @@ export default function HtdflRegForm({
if (!isPowerPlant) {
form.setValue(
"reuseBuilding.0.htdflObj.etgtType",
"해당없음", // 빈 문자열로 초기화
{ shouldDirty: true } // dirty 상태로 남길지 여부는 취사선택
"해당없음", // 빈 문자열로 초기화
{ shouldDirty: true } // dirty 상태로 남길지 여부는 취사선택
);
}
}, [isPowerPlant, form]);
// useEffect(() => {
// const watchPH = form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.ph`);
// const checkPkAndCycle =
// form.getValues(`items.${indexMng}.pbnstRuseFcltId`) +
// String(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cycl`));
// console.log("checkPkAndCycle ", checkPkAndCycle);
// if (chekcPk !== checkPkAndCycle) {
// if (watchPH && watchPH !== undefined) {
// const [frontPH, backPH] = watchPH.split("~");
// if (frontPH) {
// setFrontPHdata(frontPH);
// }
// if (backPH) {
// setBackPHdata(backPH);
// }
// } else {
// setFrontPHdata("0");
// setBackPHdata("0");
// }
// setCheakPk(checkPkAndCycle);
// }
// }, [form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.ph`), chekcPk]);
return (
<div className="!mx-[1.6rem] !p-0r">
<Form {...form}>
@@ -155,7 +257,7 @@ export default function HtdflRegForm({
{/* <div className="flex justify-between items-center mx-3"> */}
<div>
<h1 className="text-2xl font-bold text-gray-900 mt-3 ml-1">
{readonly && `(${htdflForm?.bdstNm})`}
{readonly && `(시설명 : ${htdflForm?.bdstNm})`}
</h1>
<div className="grid grid-cols-12 flex items-center card-header">
<h1 className="text-2xl font-medium text-label col-span-10">
@@ -198,9 +300,13 @@ export default function HtdflRegForm({
label={""}
selectClass={selectClass}
selectArray={code.htdPowerMthdCd}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
// value={field.value ?? ""}
value={field.value || (code?.htdPowerMthdCd[0] &&code?.htdPowerMthdCd[0].val)}
value={
field.value ||
(code?.htdPowerMthdCd[0] &&
code?.htdPowerMthdCd[0].val)
}
readOnly={readonly || !isPowerPlant}
/>
</FormUi>
@@ -241,7 +347,7 @@ export default function HtdflRegForm({
label={""}
selectClass={selectClass}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
@@ -254,8 +360,9 @@ export default function HtdflRegForm({
<h1 className={formH1Class}>온배수 시설 운영현황</h1>
</div>
<div className="grid grid-cols-10 gap-1 mt-4">
<div className="col-span-5">
{/* <div className="grid grid-cols-10 gap-1 mt-4"> */}
<div className="grid grid-cols-12 gap-4">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.orgwtWtritSpt"
@@ -265,9 +372,9 @@ export default function HtdflRegForm({
className={selectClass}
placeholder=""
type="text"
value={field.value ?? ''}
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange((e.target.value));
if (!readonly) field.onChange(e.target.value);
}}
readOnly={readonly}
maxLength={txtSize}
@@ -276,7 +383,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.orgwtOcrnProcs"
@@ -297,7 +404,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.wtritEntrcTp"
@@ -319,7 +426,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.emsnExitTp"
@@ -341,12 +448,12 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.amtgnr"
render={({ field }) => (
<FormUi label="발생량(m³/년)">
<FormUi label="발생량(m³/일)">
<Input
className={selectClass}
placeholder="1,000,000"
@@ -363,7 +470,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.prcsProcsYn"
@@ -374,7 +481,7 @@ export default function HtdflRegForm({
label={""}
selectClass={selectClass}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
@@ -382,7 +489,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.prcsFcltCpct"
@@ -404,7 +511,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.fmYn"
@@ -415,7 +522,7 @@ export default function HtdflRegForm({
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
@@ -423,12 +530,12 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.utztnCpct"
render={({ field }) => (
<FormUi label="이용량(m³/년)">
<FormUi label="이용량(m³/일)">
<Input
className={selectClass}
placeholder="1,000,000"
@@ -445,7 +552,7 @@ export default function HtdflRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.utztnUsg"
@@ -456,7 +563,7 @@ export default function HtdflRegForm({
selectClass={selectClass}
label={""}
selectArray={code.htdUtztnUsgCd}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
@@ -477,18 +584,25 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.grssClfg"
render={({ field }) => (
<FormUi label="총대장균군(개/mg)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이하
</span>
</div>
</div>
</FormUi>
)}
/>
@@ -500,18 +614,25 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.tn"
render={({ field }) => (
<FormUi label="총질소(T-N)(mg/L)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder=""
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={6}
/>{" "}
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이하
</span>
</div>
</div>
</FormUi>
)}
/>
@@ -548,18 +669,25 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.tph"
render={({ field }) => (
<FormUi label="총인(T-P)(mg/L)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이하
</span>
</div>
</div>
</FormUi>
)}
/>
@@ -573,41 +701,57 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.trbt"
render={({ field }) => (
<FormUi label="탁도(NTU)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
handleOnlyNumberChange(e, field.onChange);
}}
value={
field.value !== undefined && field.value !== 0
? `${field.value}`
: ""
}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이상
</span>
</div>
</div>
</FormUi>
)}
/>
</div>
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.ph"
name="reuseBuilding.0.htdflObj.crmty"
render={({ field }) => (
<FormUi label="수소이온농도(PH)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<FormUi label="색도(도)">
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이상
</span>
</div>
</div>
</FormUi>
)}
/>
@@ -621,18 +765,25 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.bod"
render={({ field }) => (
<FormUi label="생물학적 산소요구량(mg/L)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이하
</span>
</div>
</div>
</FormUi>
)}
/>
@@ -644,18 +795,25 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.clIonQnt"
render={({ field }) => (
<FormUi label="염화물(mg/L)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={7}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이하
</span>
</div>
</div>
</FormUi>
)}
/>
@@ -669,69 +827,83 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.smll"
render={({ field }) => (
<FormUi label="냄새">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
<SelectBox
className={"!text-2xl"}
label={""}
selectClass={undefined}
selectArray={[
{ val: "불쾌하지않을것", text: "불쾌하지않을것" },
{ val: "없음", text: "없음" },
]}
readOnly={readonly}
maxLength={numSize}
/>
onSelectValue={(val) => {
field.onChange(val);
}}
value={field.value || undefined}
></SelectBox>
</FormUi>
)}
/>
</div>
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.cdtnv"
render={({ field }) => (
<FormUi label="전기전도도(μs/cm)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<div className="flex items-center gap-2">
<div className="relative flex-1 min-w-0">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
이하
</span>
</div>
</div>
</FormUi>
)}
/>
</div>
</div>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.crmty"
render={({ field }) => (
<FormUi label="색도(도)">
<Input
className={selectClass}
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
maxLength={numSize}
/>
</FormUi>
)}
/>
<Label className="text-xl">수소이온농도(PH)</Label>
<div className="flex flex-row items-center gap-2">
<Input
className="!text-xl w-1/2"
placeholder=""
type="text"
onChange={(e) =>
//setFrontPHdata(e.target.value)
isSetFrontPh(e.target.value)
}
value={frontPHdata ?? ""}
readOnly={readonly}
maxLength={3}
/>
<span className="text-xl">~</span>
<Input
className="!text-xl w-1/2"
placeholder=""
type="text"
onChange={(e) => {
isSetBackPh(e.target.value);
}}
value={backPHdata ?? ""}
readOnly={readonly}
maxLength={3}
/>
</div>
</div>
</div>
</ScrollArea>
@@ -494,7 +494,7 @@ export function PbnstBuseForm({
sonClass="col-span-4"
indexMng={indexMng}
indexBiz={indexBiz}
formType={""}
readonly={false}
/>
</div>
@@ -13,7 +13,7 @@ export function BuseWaterQulity({
sonClass,
indexMng,
indexBiz,
formType,
readonly,
}: {
form: UseFormReturn<{ items: PbnstRegArrrayType }>;
h1Title: string;
@@ -22,7 +22,7 @@ export function BuseWaterQulity({
sonClass: string;
indexMng: number;
indexBiz: number;
formType?: string;
readonly?: boolean;
}) {
const [frontPHdata, setFrontPHdata] = useState("0");
const [backPHdata, setBackPHdata] = useState("0");
@@ -131,7 +131,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -168,7 +168,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
{/* TODO: 총대장균군수 확인 필요*/}
@@ -203,7 +203,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -237,7 +237,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -267,7 +267,7 @@ export function BuseWaterQulity({
field.onChange(String(e.target.value));
}}
value={field.value ?? ""}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly === "sttn" ? true : false}
maxLength={txtSize}
/> */}
<SelectBox
@@ -278,7 +278,7 @@ export function BuseWaterQulity({
{ val: "불쾌하지않을것", text: "불쾌하지않을것" },
{ val: "없음", text: "없음" },
]}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
onSelectValue={(val) => {
field.onChange(val);
}}
@@ -310,7 +310,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -344,7 +344,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -379,7 +379,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={6}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -413,7 +413,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={7}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -448,7 +448,7 @@ export function BuseWaterQulity({
? `${field.value}`
: ""
}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={7}
/>
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
@@ -472,7 +472,7 @@ export function BuseWaterQulity({
isSetFrontPh(e.target.value)
}
value={frontPHdata ?? ""}
readOnly={formType === "sttn"}
readOnly={readonly}
maxLength={3}
/>
<span className="text-xl">~</span>
@@ -484,7 +484,7 @@ export function BuseWaterQulity({
isSetBackPh(e.target.value);
}}
value={backPHdata ?? ""}
readOnly={formType === "sttn"}
readOnly={readonly}
maxLength={3}
/>
</div>
@@ -41,11 +41,13 @@ export function PbnstMngForm({
formType,
indexMng,
setIndexMng,
readonly
}: {
form: UseFormReturn<{ items: PbnstRegArrrayType }>;
formType: string;
indexMng: number;
setIndexMng: (index: number) => void;
readonly:boolean
}) {
const { code, pbnst, fileDelete, fileDownLoad } = useWrStore(
(state) => state
@@ -286,14 +288,14 @@ export function PbnstMngForm({
render={({ field }) => (
<FormUi label="">
<Input
className="!text-2xl"
className="!text-2xl ml-4 mt-1"
placeholder=""
type="text"
onChange={(e) => {
field.onChange(String(e.target.value));
}}
value={field.value ?? ""}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
maxLength={txtSize}
/>
</FormUi>
@@ -374,7 +376,7 @@ export function PbnstMngForm({
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
/>
</FormUi>
)}
@@ -398,7 +400,7 @@ export function PbnstMngForm({
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
/>
</FormUi>
)}
@@ -421,7 +423,7 @@ export function PbnstMngForm({
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={formType === "sttn" ? true : false}
readOnly={readonly}
/>
</FormUi>
)}
@@ -159,7 +159,7 @@ export default function RainRegForm({
<form onSubmit={form.handleSubmit(onSubmit)}>
<div>
<h1 className="text-2xl font-bold text-gray-900 mt-3 ml-1">
{readonly && `(${rainForm?.bdstNm})`}
{readonly && `(시설명 : ${rainForm?.bdstNm})`}
</h1>
<div className="grid grid-cols-12 flex items-center card-header">
<h1 className="text-2xl font-medium text-label col-span-10">
@@ -315,8 +315,8 @@ export default function RainRegForm({
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<div className="flex items-center gap-2">
<FormUi label="집수면 용량(m³)">
// <div className="flex items-center gap-2">
<FormUi label="집수면 면적(m²)">
<Input
className={selectClass}
placeholder="1,000,000"
@@ -338,7 +338,7 @@ export default function RainRegForm({
maxLength={numSize}
/>
</FormUi>
</div>
// </div>
);
}}
/>
@@ -413,7 +413,7 @@ export default function RainRegForm({
// const isUnknown = value === null || value === "-"; // 또는 Number(value) === -1
return (
<div className="flex items-center gap-2">
// <div className="flex items-center gap-2">
<FormUi label="처리공정">
<Input
className={" h-full !text-xl col-span-4"}
@@ -426,7 +426,7 @@ export default function RainRegForm({
maxLength={txtSize}
/>
</FormUi>
</div>
// </div>
);
}}
/>
@@ -5,21 +5,17 @@ import type {
conCostFeeType,
ContCostMap,
} from "@/app/store/common/searchCode/type";
import { yearOptions } from "@/components/lib/func/commom";
import { SelectBox, UiTable } from "@common/business_components/ui";
import { UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Label, } from "@common/components/ui";
import { useEffect, useState } from "react";
import { useEffect, useState } from "react";
export function ConstCostFeeTable() {
const { coRvw, constCostRes } = useWrStore((state) => state);
const [year, setYear] = useState<string>(String(new Date().getFullYear()));
const [constCostData, setConstCostData] = useState<ContCostMap[]>([]);
const getFctDescription = (fctCd: string) => {
const getFctDescription = (fctCd: string) => {
const fctMap: { [key: string]: string } = {
"001": "총인처리시설",
"002": "염소소독",
@@ -73,26 +69,19 @@ export function ConstCostFeeTable() {
공사비 산정표 보기
</h3>
<hr />
<div className="flex items-center">
<Label className="text-xl text-gray-600">기준년도</Label>
<SelectBox
className="h-full text-2xl"
label=""
selectClass={"ml-4"}
selectArray={yearOptions}
value={year}
onSelectValue={(val: string | number) => setYear(String(val))}
/>
<div className="col-span-5 flex items-center">
<Label className="ml-2 mr-1 text-xl text-gray-600">기준년도</Label>
<span>{new Date().getFullYear() || ""}</span>
</div>
<UiTable
headName={""}
tableData={constCostData || []}
headlist={coRvw.constCostHeadList}
pageSize={0}
total={0}
cellClick={() => {}}
onPageChange={() => {}}
/>
<UiTable
headName={""}
tableData={constCostData || []}
headlist={coRvw.constCostHeadList}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={() => { }}
/>
</ListDiv>
</>
);
@@ -80,7 +80,7 @@ export function RateFeeTableModal() {
<hr className="col-span-6 border-gray-300" />
<div className="col-span-5 flex items-center">
<Label className=" text-xl text-gray-600">기준년도</Label>
<Label className="mr-1 text-xl text-gray-600">기준년도</Label>
<span>{new Date().getFullYear() || ""}</span>
</div>
<div className="col-span-6 pr-6">
@@ -89,7 +89,7 @@ export default function CoRegExcel({
<h3 className="text-2xl font-bold text-gray-900 mt-1 ml-7">
{"잠재수요처 파일"}
</h3>
<Button className="" type="submit" size={"sm"} onClick={onSubmit}>
<Button className="" type="submit" size={"sm"}>
저장
</Button>
</div>
@@ -99,6 +99,7 @@ export function PbnstRegModal({
formType={"reg"}
indexMng={indexMng}
setIndexMng={setIndexMng}
readonly={false}
/>
</TabsContent>
<TabsContent className="max-h-full" value="buse">
@@ -35,7 +35,7 @@ import { useForm } from "react-hook-form";
import { z } from "zod";
export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titleVisible?: boolean }) {
const { pbnstSttn, prfmnc , pbnstPrfmncSttn} = useWrStore((state) => state);
const { pbnstSttn, prfmnc, pbnstPrfmncSttn } = useWrStore((state) => state);
const [fcltTab, setFcltTab] = useState<string>("fclt");
const [ruseTab, setRuseTab] = useState<string>("totalPrf");
const [ruseHeadList, setRuseHeadList] = useState<TableUpperProps[]>([]);
@@ -67,10 +67,10 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
cusrAlotm: item.cusrAlotm ?? "-",
etc: item.etc ?? "-",
totalMoney:
Number(item.addr) +
Number(item.gvsbs) +
Number(item.lcep) +
Number(item.cusrAlotm),
Number(item.cusrAlotm) +
(isNaN(Number(item.etc)) ? 0 : Number(item.etc)),
instlAprvSncnDt: item.instlAprvSncnDt?.toISOString ?? "-",
bizCmcnDay: item.bizCmcnDay?.toISOString ?? "-",
rprcsFcltCpct: item.rprcsFcltCpct ?? "-",
@@ -167,8 +167,8 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
const getTablePrfData = (prfList: PrfType[]) => {
const inUsageData = structuredClone(initValInUsage);
const outUsageData = structuredClone(initValOutUsage);
const inSubtotal = structuredClone(subTotalObj);
const outSubtotal = structuredClone(subTotalObj);
const inSubtotal = { ...structuredClone(subTotalObj), 구분: "장내용수" };
const outSubtotal = { ...structuredClone(subTotalObj), 구분: "장외용수" };
if (prfList) {
prfList?.forEach((prfItem) => {
@@ -216,7 +216,9 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
(usageTotalObj as any)[key] = val;
}
const tableData = [...inUsageData, ...outUsageData, usageTotalObj];
console.log("inusageData", inUsageData)
console.log("outUsageData", outUsageData)
console.log("tableData", tableData)
setPrfData({
inPrf: inUsageData,
outPrf: outUsageData,
@@ -264,6 +266,7 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
formType={"sttn"}
indexMng={indexMng}
setIndexMng={setIndexMng}
readonly={true}
/>
<div className="px-6">
<div className="">
@@ -300,8 +303,8 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
}}
>
{fcltTab === "fclt" ? (
<HeadMakeColSpan upHeadList={pbnstSttn.ruseFcltNodeList} />
) : undefined}
<HeadMakeColSpan upHeadList={pbnstSttn.ruseFcltNodeList} />
) : undefined}
</UiTable>
</TabsContent>
</Tabs>
@@ -323,22 +326,22 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
<TabsContent className="max-h-full" value={ruseTab}>
{prfData && (
<ListDiv className="col-span-8 pr-6 ">
<ScrollArea className="h-[60vh]">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m³) 등록결과"}
</h3>
</div>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(pbnstPrfmncSttn.monthSttnHeadList, [])}
</TableHeader>
<TableBody key={prfmnc.pageKey + 'pageKey'}>
{InputTableBody(prfData[ruseTab as keyof typeof prfData] || [], pbnstPrfmncSttn.monthSttnHeadList, setPrfData as any)}
</TableBody>
</Table>
</ScrollArea>
</ListDiv>
<ScrollArea className="h-[60vh]">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m³) 등록결과"}
</h3>
</div>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(pbnstPrfmncSttn.monthSttnHeadList, [])}
</TableHeader>
<TableBody key={prfmnc.pageKey + 'pageKey'}>
{InputTableBody(prfData[ruseTab as keyof typeof prfData] || [], pbnstPrfmncSttn.monthSttnHeadList, setPrfData as any)}
</TableBody>
</Table>
</ScrollArea>
</ListDiv>
)}
</TabsContent>
</Tabs>
@@ -421,11 +421,11 @@ export default function CoDetailModal({
<Input
className={selectClass}
placeholder=""
type="number"
type="text"
onChange={(e) => {
field.onChange(e.target.value);
handleCommaNumberChange(e, field.onChange);
}}
value={field.value ?? 0}
value={formatCommaNumber(field.value) ?? 0}
min={0}
readOnly={true}
/>
+57 -35
View File
@@ -4,7 +4,7 @@ import { CLAIM_NAME, AUTH_USER_ID } from "./src/shared/config";
// const CLAIM_NAME = "Authorization";
// const AUTH_USER_ID = "token-id";
const serverApiUrl = CS_URL;
const serverApiUrl = CS_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 || "";
@@ -25,28 +25,43 @@ export function middleware(req: NextRequest) {
if (pathname.startsWith("/server")) {
const decodedParams = Array.from(searchParams.entries())
.map(([key, value]) => `${key}=${decodeURIComponent(value)}`)
.join("&");
.map(([key, value]) => `${key}=${decodeURIComponent(value)}`)
.join("&");
console.log(' sesesesesesevereveraserwereqwrewbrtkehjwrtg server')
const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${
decodedParams ? `?${decodedParams}` : ""
}`;
return NextResponse.rewrite(new URL(newUrl));
}
if (pathname === "/") {
console.log(" maim 화면이동 ");
return NextResponse.redirect(new URL("/map/mainMap", req.url));
}
if (pathname.startsWith("/cms-service")) {
const requestHeaders = new Headers(req.headers);
const Authorization = req.cookies.get(CLAIM_NAME)?.value;
const newUrl = `${serverApiUrl}${pathname}`;
console.log("Authorization cms-service ", Authorization);
if (Authorization) requestHeaders.set(CLAIM_NAME, Authorization);
//if (userId) requestHeaders.set(AUTH_USER_ID, userId);
console.log(
`[Middleware] Rewriting from '/cms-service' path to: ${newUrl}`
);
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/attach-service")) {
const requestHeaders = new Headers(req.headers);
// const token =
// "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhMGVjN2EwNy03NTJhLTRmN2YtODlhNi04NTRlNjNkMmUzYTAiLCJhdXRob3JpdGllcyI6IlJPTEVfQURNSU4sUk9MRV9BTk9OWU1PVVMiLCJtbmdyWW4iOiJZIiwiZXhwIjoxNzUyMTM1OTk3fQ.itGY6M6mC2iwKvEpXw2KS6354T_B_OFz4hD26ResIgwJhpwiDJCMuSXD-rZ3AarmAIKd0udpCuJR7UlvFMN2ww";
// const userId = "a0ec7a07-752a-4f7f-89a6-854e63d2e3a0";
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl}${pathname}`;
//wr:dev: pathname /attach-service/api/v1/tus/upload/5e60b70a-956e-40c3-be5a-cdd3100bf8ad
//http://dev.onasys.co.kr:8000/attach-service/api/v1/tus/upload/5e60b70a-956e-40c3-be5a-cdd3100bf8ad
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
@@ -66,7 +81,7 @@ export function middleware(req: NextRequest) {
`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`
);
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders
headers: requestHeaders,
});
}
@@ -78,33 +93,31 @@ export function middleware(req: NextRequest) {
let newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`;
if (
typename == "hasudo:tb_il_swage_prcs_fclt" //하수처리시설
|| typename == "hasudo:tb_ms_swage_prcs_zone" //하수처리구역
|| typename == "hasudo:tb_ms_sbmrg_dngr_map" //침수위험지도
|| typename == "hasudo:tb_ms_flood_dngr_map" //도시침수지도
typename == "hasudo:tb_il_swage_prcs_fclt" || //하수처리시설
typename == "hasudo:tb_ms_swage_prcs_zone" || //하수처리구역
typename == "hasudo:tb_ms_sbmrg_dngr_map" || //침수위험지도
typename == "hasudo:tb_ms_flood_dngr_map" //도시침수지도
) {
newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`;
}
else if (
typename == "hasudo:tb_ms_swage_ppl" //관로
|| typename == "hasudo:tb_ms_swage_mhl" //맨홀
|| typename == "hasudo:tb_ms_swage_pmstn" //펌프장
|| typename == "hasudo:tb_ms_stofcbr" //우수토실
} else if (
typename == "hasudo:tb_ms_swage_ppl" || //관로
typename == "hasudo:tb_ms_swage_mhl" || //맨홀
typename == "hasudo:tb_ms_swage_pmstn" || //펌프장
typename == "hasudo:tb_ms_stofcbr" //우수토실
) {
newUrl = `${LX_GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`;
}
else if (
typename == "hasudo:om_dt_untrt_swg_rain" //중점우수토실
|| typename == "hasudo:om_wqlt_station" //관측소
|| typename == "hasudo:tb_wr_bdst_ruse_fclt" //재이용시설
|| typename == "hasudo:tb_wr_rnwtr_utztn_fclt" //빗물이용시설
|| typename == "hasudo:tb_wr_rswtr_fclt" //중수도시설
|| typename == "hasudo:tb_wr_htdfl_fclt" //온배수시설
|| typename == "hasudo:tb_wr_ruse_fclt_dmd_co" //수요처
|| typename == "hasudo:tb_wr_tmpr_dmd_co" //잠재수요처
){
} else if (
typename == "hasudo:om_dt_untrt_swg_rain" || //중점우수토실
typename == "hasudo:om_wqlt_station" || //관측소
typename == "hasudo:tb_wr_bdst_ruse_fclt" || //재이용시설
typename == "hasudo:tb_wr_rnwtr_utztn_fclt" || //빗물이용시설
typename == "hasudo:tb_wr_rswtr_fclt" || //중수도시설
typename == "hasudo:tb_wr_htdfl_fclt" || //온배수시설
typename == "hasudo:tb_wr_ruse_fclt_dmd_co" || //수요처
typename == "hasudo:tb_wr_tmpr_dmd_co" //잠재수요처
) {
const url = req.nextUrl.clone();
url.searchParams.set('TYPENAME', typename.replace("hasudo:",""));
url.searchParams.set("TYPENAME", typename.replace("hasudo:", ""));
queryParams = url.searchParams.toString();
newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`;
}
@@ -115,8 +128,9 @@ export function middleware(req: NextRequest) {
if (pathname.startsWith("/sewerage-service")) {
const queryParams = searchParams.toString();
const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service/api", "")}${queryParams ? `?${queryParams}` : ""
}`;
const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service/api", "")}${
queryParams ? `?${queryParams}` : ""
}`;
console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`);
return NextResponse.rewrite(new URL(newUrl));
}
@@ -125,5 +139,13 @@ export function middleware(req: NextRequest) {
}
export const config = {
matcher: ["/server/:path*", "/user-service/:path*", "/attach-service/:path*", "/geoserver/:path*", "/sewerage-service/:path*"],
matcher: [
"/cms-service/:path*",
"/server/:path*",
"/user-service/:path*",
"/attach-service/:path*",
"/geoserver/:path*",
"/sewerage-service/:path*",
"/"
],
};
+7 -2
View File
@@ -12,14 +12,19 @@
"isUpdateMsg": "수정한 정보를 저장하시겠습니까?",
"isInsertMsg": "등록하시겠습니까?",
"isUpdatetMsg": "수정하시겠습니까?",
"matchFinishMsg" : "{{name}}이(가) 완료되었습니다.",
"excelDownErrMsg": "다운로드할 데이터가 없습니다.",
"isMatchFinishMsg":" 매칭완료를 진행하시겠습니까?",
"isNotMatchFinishMsg":"검토완료중 매칭완료 여부를 체크한 항목이 없습니다.",
"canNotChangeMatStateMsg":"매칭완료된 항목은 상태를 변경할 수 없습니다.",
"alreadyInsertedErrMsg": "사업자번호 {{num}}(은)는 이미 등록되었습니다. 다시 등록해주세요.",
"saveRowErrMsg": "수정을 원하는 행을 선택하고 저장버튼을 눌러주세요.",
"costCalcErrMsg":"공사비 계산 진행 후 저장을 눌러주세요",
"maxYearErrMsg": "최대 {{year}}년까지 선택가능합니다.",
"checkQtyMsg": "요구수량(M3/d)을 확인해주세요 계산할 수 없습니다."
"checkQtyMsg": "요구수량(m³/일)을 확인해주세요 계산할 수 없습니다."
}
@@ -29,23 +29,18 @@ export class LoginApiService implements LoginService {
const accessToken = response.headers.get(ACCESS_TOKEN);
const tokenId = response.headers.get(AUTH_USER_ID);
console.log('accessToken ', accessToken)
console.log('tokenId ', tokenId)
if (!accessToken || !tokenId) {
throw new Error("Missing required authentication tokens");
}
tokenManager.setToken(CLAIM_NAME, accessToken);
tokenManager.setToken(AUTH_USER_ID, tokenId);
tokenManager.setToken("site-id-key", SITE_ID);
tokenManager.setToken(CLAIM_NAME, accessToken)
tokenManager.setToken(AUTH_USER_ID, tokenId)
tokenManager.setToken("site-id-key", SITE_ID)
tokenManager.setupRefreshTimer(
() => this.silentRefresh(),
JWT_EXPIRATION_TIME,
);
} catch (error) {
console.log(' login err ' , error)
throw new Error(`Login failed: ${error}`);
}
}
@@ -67,7 +62,7 @@ export class LoginApiService implements LoginService {
if (!accessToken || !tokenId) {
throw new Error("Missing required authentication tokens");
}
tokenManager.setToken(CLAIM_NAME, accessToken);
tokenManager.setToken(AUTH_USER_ID, tokenId);
} catch (error) {
@@ -1,45 +0,0 @@
// "use client";
// import { useEffect } from "react";
// import { useRouter } from "next/navigation";
// import { LoginApi } from "../api/login-service";
// const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
// const router = useRouter();
// const { userInfo, setUserInfo } = useUserStore((state) => state);
// async function authCheck() {
// const userId = getCookie(AUTH_USER_ID);
// if (!userId) {
// throw new Error("Missing required authentication tokens");
// }
// const response = await client.get<IUserInfo>(
// `${ENDPOINT.USER_SERVICE.USERS}/info/me`,
// );
// if (!userInfo) setUserInfo(response.data);
// }
// useEffect(() => {
// (async () => {
// try {
// await authCheck();
// } catch (error) {
// console.error(error);
// try {
// await LoginApi.silentRefresh();
// await authCheck();
// } catch (refreshError) {
// console.error("Token refresh failed:", refreshError);
// setUserInfo(null);
// router.push("/auth/login");
// }
// }
// })();
// }, []);
// return <>{children}</>;
// };
// export { AuthWrapper };
+1 -1
View File
@@ -1,6 +1,6 @@
import { PROXY_HOST } from "./env";
export const BASE_URL = `${PROXY_HOST}/server`;
export const BASE_URL = `${PROXY_HOST}`;
export const ENDPOINT = {
ATTACH_SERVICE: {
@@ -50,7 +50,7 @@ const customStyles = {
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px", // 범례 영역 높이 통일
minHeight: "60px", // 범례 영역 높이 통일
} as CSSProperties,
};
const renderCustomizedLabel = ({
@@ -108,12 +108,11 @@ export function DatePicker({
// captionLayout="dropdown-buttons"
// fromYear={2000}
// toYear={new Date().getFullYear()}
toDate={new Date()} // 금일까지만 표시됨 (금일 이후는 안보임)
showOutsideDays={false} // 금월 까지만 표출되도록
mode="single"
selected={field?.value}
onSelect={handleSelect}
initialFocus
disabled={{ after: new Date() }} // 금일까지만 표시됨 (금일 이후는 안보임) 20250721 캘린더가 변경됨!!
locale={ko}
/>
</PopoverContent>
@@ -1,11 +1,21 @@
"use client"
"use client";
import { Checkbox, Table, TableBody, TableCell, TableHeader, TableRow } from "@common/components";
import {
Checkbox,
Table,
TableBody,
TableCell,
TableHeader,
TableRow,
} from "@common/components";
import { useEffect, useState, useRef } from "react";
import { HeadMakeColSpan } from "./HeadMakeColSpan";
import UiPageNations from "./uiPageNations";
import { Check } from "lucide-react";
export type ChkClass = {
chk: boolean;
readonly: boolean;
};
type UiTableProps = {
headName: React.ReactNode | undefined;
tableData: { [key: string]: any }[];
@@ -20,22 +30,35 @@ type UiTableProps = {
boldArray?: number[];
resetSelection?: boolean;
index?: number;
}
};
type UiHeadProps = {
id: string;
title: string;
align?: string;
visible?: boolean;
}
};
export function UiTable({ tableData, headlist, pageSize, total, headName, children, cellClick, onPageChange, className = '', resetPageNo = false, boldArray = [], resetSelection = false, index = -1 }: UiTableProps) {
export function UiTable({
tableData,
headlist,
pageSize,
total,
headName,
children,
cellClick,
onPageChange,
className = "",
resetPageNo = false,
boldArray = [],
resetSelection = false,
index = -1,
}: UiTableProps) {
const [cur, setCur] = useState<number>(1);
const [idx, setIdx] = useState<number>(index);
const [headerHeight, setHeaderHeight] = useState<number>(0);
const headerRef = useRef<HTMLTableSectionElement>(null);
useEffect(() => {
if (resetPageNo) {
setCur(1);
@@ -51,14 +74,14 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
useEffect(() => {
if (headerRef.current) {
setHeaderHeight(headerRef.current.offsetHeight-5);
setHeaderHeight(headerRef.current.offsetHeight - 5);
}
}, [tableData, headlist]);
const handlePageChange = (page: number) => {
setCur(page);
onPageChange(page);
}
};
const handleCellClick = (index: number, headId: string) => {
if (cellClick) {
@@ -67,81 +90,158 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
}
};
return (
<>
{headName ? <div className="card-header">
<h3 className="text-2xl font-medium text-label">{headName}</h3>
</div> : <></>}
<div className={`card !m-[1.2rem] !p-0r ${className}`}>
{headName ? (
<div className="card-header">
<h3 className="text-2xl font-medium text-label">{headName}</h3>
</div>
) : (
<></>
)}
<div className={`card !p-0r !m-[1.2rem] ${className}`}>
<Table variant="secondary">
<TableHeader ref={headerRef} className="font-bold">
{children ? children : <HeadMakeColSpan upHeadList={headlist} />}
</TableHeader>
<TableBody className='text-center'>
{tableData.length > 0 ? tableData?.map((el: Record<string, unknown>, index) => (
<TableRow key={`row-${index}`}>
{headlist
.filter((item) => item.visible != false)
.map((head) => (
head.id && head.id.length > 1 && (
boldArray.includes(index)
?
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''
} !font-bold sticky bg-secondary z-40`}
style={{ top: `${headerHeight + (index * 39)}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, ",")}
</TableCell>
:
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''
<TableBody className="text-center">
{tableData.length > 0 ? (
tableData?.map((el: Record<string, unknown>, index) => (
<TableRow key={`row-${index}`}>
{headlist
.filter((item) => item.visible != false)
.map(
(head) =>
head.id &&
head.id.length > 1 &&
(boldArray.includes(index) ? (
<TableCell
className={`${head.align === "right" ? "text-right" : head.align === "center" ? "text-center" : "text-center"} ${
cellClick && idx === index
? "cursor-pointer !font-[1000]"
: cellClick
? "cursor-pointer"
: ""
} sticky z-40 bg-secondary !font-bold`}
style={{ top: `${headerHeight + index * 39}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,
",",
)}
</TableCell>
) : (
<TableCell
className={`${head.align === "right" ? "text-right" : head.align === "center" ? "text-center" : "text-center"} ${
cellClick && idx === index
? "cursor-pointer !font-[1000]"
: cellClick
? "cursor-pointer"
: ""
} mt-[${boldArray.length * 40}px]`}
onClick={() => handleCellClick(index, head.id)}
key={`cell-${head.id}-${index}`}
>
{typeof el[head.id] === 'boolean'
? <Checkbox
checked={el[head.id] === true}
onCheckedChange={(checked) => {
el[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]).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, ",")}
</TableCell>
)
))}
</TableRow>
)) : (
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) ? (
<Checkbox
checked={
(el[head.id] as ChkClass)?.chk === true
}
onCheckedChange={(checked) => {
{
console.log(el[head.id]);
}
if (
(el[head.id] as ChkClass).readonly == true
)
return;
(el[head.id] as ChkClass).chk =
Boolean(checked);
}}
>
<Check className="h-6 w-6 text-primary" />
</Checkbox>
) : typeof el[head.id] === "boolean" ? (
<Checkbox
checked={el[head.id] === true}
onCheckedChange={(checked) => {
el[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])
.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,
",",
)
)
}
</TableCell>
)),
)}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={headlist.filter((item) => item.visible != false).length} className="h-24 text-center text-gray-500">
<TableCell
colSpan={
headlist.filter((item) => item.visible != false).length
}
className="h-24 text-center text-gray-500"
>
조회된 결과가 없습니다.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
{total <= 0 ? <></> : <UiPageNations total={total} cur={cur} pageSize={pageSize} onPageChange={handlePageChange} />}
{total <= 0 ? (
<></>
) : (
<UiPageNations
total={total}
cur={cur}
pageSize={pageSize}
onPageChange={handlePageChange}
/>
)}
</div>
</>
);
}
}