Merge commit 'fb8812303baa27bf0f38fb3b60da43a8ab716e25' into iipbs/wr/gisPopup

This commit is contained in:
JIeunhuh
2025-07-07 10:46:21 +09:00
110 changed files with 4655 additions and 2915 deletions
+1 -1
View File
@@ -18,5 +18,5 @@ apps/wr/.next/**/*
apps/fo/.next/**/*
# env
.env*
#.env*
.qodo
+12
View File
@@ -0,0 +1,12 @@
NEXT_PUBLIC_SITE_ID = WR
NEXT_PUBLIC_PORT = 11301
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11301
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
NEXT_PUBLIC_TEMP_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver #TODO 운영에서 바꿔야 함
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
+14
View File
@@ -0,0 +1,14 @@
NEXT_PUBLIC_SITE_ID = WR
NEXT_PUBLIC_PORT = 3001
NEXT_PUBLIC_PROXY_HOST = http://localhost:3001
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
NEXT_PUBLIC_TEMP_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver #TODO 운영에서 바꿔야 함
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정
+1 -1
View File
@@ -31,7 +31,7 @@ yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
#.env*
# vercel
.vercel
+1 -1
View File
@@ -124,7 +124,7 @@ const Map = () => {
treeData={treeData}
isSearch={false}
gisMaps={gisMaps}
isMiniMap={true}
isMiniMap={false}
searchView={undefined}
// searchView={(props: any) => (
// <MapSearchBar
+10 -1
View File
@@ -2,11 +2,12 @@ import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { excelDownload } from "@/components/lib/func/commom";
import { Title, UiTable, UITab } from '@common/business_components';
import { Title, UiTable, UITab, ContentsDiv } from '@common/business_components';
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import { Button } from "@common/components/ui";
import React, { useCallback, useState, useEffect } from 'react';
import NewWindowPortal from '@/app/map/newWindowPortal';
import PbnstPrfmncSttnPopup from "@/app/map/pbnstPrfmncSttnPopup";
import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal";
import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type";
import type { chgBuilding, customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
@@ -27,6 +28,13 @@ interface NewWindowPopupProps {
onClose: () => void;
}
// 탭
const TABS = [
{ val: "0", text: "재이용시설1" },
{ val: "1", text: "재이용시설2" },
{ val: "2", text: "재이용시설n" },
];
// 데이터의 속성(key)을 사용자에게 보여줄 한글 이름으로 변환하기 위한 맵
// 실제 데이터에 맞게 이 부분을 확장해야 합니다.
const propertyNameMap: { [key: string]: string } = {
@@ -202,6 +210,7 @@ const NewWindowPopup: React.FC<NewWindowPopupProps> = ({
}, [featureData]);
// 빗물재이용시설 cellClick 이벤트 (상세정보)
const rainCellClick = (index: number | undefined, headId: string) => {
if (
+2 -2
View File
@@ -2,8 +2,8 @@
/**
* 관망도 API
*/
// const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map`
const API_URL = "http://con.mind-one.co.kr:11083/sewerage-service/api/v1/map";
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map`
//const API_URL = "http://con.mind-one.co.kr:11083/sewerage-service/api/v1/map";
export type LyrStngProps = {
lyr_sn: string
+36 -19
View File
@@ -9,6 +9,7 @@ import {
} from "@/app/store/matDmd/coMatRvw/type";
import { formH1Class, formTableName } from "@/components/lib/class/comClass";
import {
formatPhoneNumber,
getCity,
getdmdMatFlag,
tableData,
@@ -33,7 +34,7 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Input, Label } from "@common/components/ui";
import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { useForm, useWatch } from "react-hook-form";
import toast, { Toaster } from "react-hot-toast";
import { z } from "zod";
import moment from "moment";
@@ -45,7 +46,7 @@ import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/b
export default function CoMatRvw() {
const { code, coRvw, coMatRvwInit, coMatRvwSearch, coMatRvwInqua } =
useWrStore((state) => state);
const { coMatRvwRes } = coRvw;
const { coMatRvwRes,coMatRvwCount } = coRvw;
//init, sub, match
const initRef = useRef<boolean>(false);
const { coRvwHeadList } = coRvw;
@@ -68,6 +69,7 @@ export default function CoMatRvw() {
const [selectData, setSelectData] = useState<DmdCoReqType>(
{} as DmdCoReqType
);
const [selectionVersion, setSelectionVersion] = useState(0);
const getSearch = (
startYear: number,
@@ -91,39 +93,45 @@ export default function CoMatRvw() {
const form = useForm<z.infer<typeof DmdCoReqSchema>>({
resolver: zodResolver(DmdCoReqSchema),
shouldUnregister: false,
// defaultValues: DmdCoReqSchema.parse({})
});
const TableCellClick = (index: number) => {
console.log(coMatRvwRes);
if (coMatRvwRes && coMatRvwRes[index]) {
setSelectData(coMatRvwRes[index]);
setSelectionVersion((v) => v + 1); // 행을 클릭할 때마다 버전을 1씩 증가
}
};
const useUsgCdWatch = useWatch({ control: form.control, name: "useUsgCd" });
useEffect(() => {
if (form?.getValues("useUsgCd")) {
if (useUsgCdWatch) {
form.setValue(
"demandCst.usgPrcsProcs",
usageProcData?.find(
(item) => item.usage === (form?.getValues("useUsgCd") as string)
(item) => item.usage === useUsgCdWatch
)?.process ?? ""
);
}
}, [form.watch("useUsgCd")]);
}, [useUsgCdWatch, form,selectionVersion]);
useEffect(() => {
if (coMatRvwRes.length > 0) {
if (coMatRvwRes&&coMatRvwRes.length > 0) {
const data = coMatRvwRes?.map((item, index) => {
let flag = "";
flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ??"");
flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ||undefined);
return {
...item,
ctpvCd: item.demandCo?.ctpvCd,
sggCd: item.demandCo?.sggCd,
dmdCoNm: item.demandCo?.dmdCoNm,
daddr: item.demandCo?.daddr,
telno: item.demandCo?.telno,
regDt: moment(item?.demandCo?.regDt).format("YYYY-MM-DD"),
telno: formatPhoneNumber(item?.demandCo?.telno||''),
dmndTmng: item?.dmndTmng,
splyFcltFlg: flag,
};
});
@@ -151,14 +159,23 @@ export default function CoMatRvw() {
useEffect(() => {
if (selectData) {
console.log(selectData);
form.reset(selectData);
try {
DmdCoReqSchema.parse(selectData);
} catch (e) {
if (e instanceof z.ZodError) {
console.log(e.flatten());
}
}
form.reset( selectData);
setSelectionVersion((v) => v + 1); // 강제로 바뀌었다고 알리기
}
}, [selectData, form]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"수요매칭검토"} />
<SearchDiv>
@@ -181,7 +198,7 @@ export default function CoMatRvw() {
<div className="col-span-7 w-full">
<div className="flex flex-row items-center">
<Label className="text-xl text-gray-600 mx-6">
하수 재이용년도
수요신청년도
</Label>
<SelectBox
className="h-full w-32 text-2xl"
@@ -259,7 +276,7 @@ export default function CoMatRvw() {
tableData={dmdMatData || []}
headlist={coRvwHeadList}
pageSize={20}
total={100000}
total={coMatRvwCount}
cellClick={(index: number | undefined, headId: string) => {
if (index !== undefined && index >= 0) {
TableCellClick(index);
@@ -269,7 +286,7 @@ export default function CoMatRvw() {
></UiTable>
</ListDiv>
<hr />
<ScrollArea className="h-[49vh]">
{/* <ScrollArea className="h-[49vh]"> */}
<ListDiv>
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
@@ -279,7 +296,7 @@ export default function CoMatRvw() {
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="demandCo.regDt"
name="dmndTmng"
render={({ field }) => (
<FormUi label="요구시기">
<Input
@@ -660,9 +677,9 @@ export default function CoMatRvw() {
</div>
</div>
</Form>
<ConCostForm form={form} type={"mat"} />
<ConCostForm form={form} type={"mat"} selectionVersion={selectionVersion} />
</ListDiv>
</ScrollArea>
{/* </ScrollArea> */}
</div>
</div>
</ContentsDiv>
+21 -9
View File
@@ -5,6 +5,7 @@ import { ruseUtzType } from "@/app/store/matDmd/ruseCaseMng/headList";
import { excelDownload, getCity } from "@/components/lib/func/commom";
import RuseCaseMngExcel from "@/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import {
ContentsDiv,
filePickedBlobArray,
@@ -20,11 +21,12 @@ import {
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useState } from "react";
import { useEffect, useState } from "react";
import { toast, Toaster } from "react-hot-toast";
export default function RuseCaseMng() {
const { code, ruseCaseMng, selectRuseCaseMng } = useWrStore((state) => state);
const { ruseCaseMngList } = ruseCaseMng;
const { ruseCaseMngList, status, count } = ruseCaseMng;
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>([]);
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
@@ -34,8 +36,10 @@ export default function RuseCaseMng() {
const [name, setName] = useState<string>("");
// 물재이용사례 조회
const searchRuseCaseMng = async () => {
const searchRuseCaseMng = async (pageNo: number, pageSize: number) => {
const res = await selectRuseCaseMng(
pageNo,
pageSize,
sidoCd ?? "",
sigunguCd ?? "",
selectUtz[0] ?? "",
@@ -68,7 +72,7 @@ export default function RuseCaseMng() {
// 다운로드
const download = () => {
searchRuseCaseMng();
searchRuseCaseMng(1, 10000);;
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
if (!response.ok) {
@@ -142,7 +146,7 @@ export default function RuseCaseMng() {
}
];
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter);
await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter);
});
}
@@ -157,6 +161,12 @@ export default function RuseCaseMng() {
);
}
useEffect(() => {
if(status === 200){
setIsExcelOpen({ isModal: false });
}
}, [status]);
return (
<>
<ContentsDiv>
@@ -202,7 +212,7 @@ export default function RuseCaseMng() {
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2">
<div className="space-y">
<div className="flex flex-row space-x-2">
<Button size={"sm"} onClick={() => { searchRuseCaseMng() }}>
<Button size={"sm"} onClick={() => { searchRuseCaseMng(1, 20) }}>
조회
</Button>
<Button size={"sm"} onClick={() => { setIsExcelOpen({ isModal: true }); }}>
@@ -230,16 +240,18 @@ export default function RuseCaseMng() {
children={undefined}
headlist={ruseCaseMng.ruseHeadList}
pageSize={20}
total={100000}
total={count}
cellClick={(index: number | undefined, headId: string) => {}}
onPageChange={() => {}}
onPageChange={(pageNo: number) => {
searchRuseCaseMng(pageNo, 10);
}}
/>
</div>
</ListDiv>
</div>
</div>
</ContentsDiv>
<Toaster position="top-center" />
{/* 엑셀 등록 모달 */}
<UiModal
open={isExcelOpen.isModal}
+59 -39
View File
@@ -7,6 +7,7 @@ import {
type RvwHistTableType,
} from "@/app/store/matDmd/coMatRvw/type";
import {
formatPhoneNumber,
getCity,
getdmdMatFlag,
yearOptions,
@@ -43,7 +44,7 @@ export default function RuseRvwHstry() {
ruseRvwInqua,
ruseRvwComplete,
} = useWrStore((state) => state);
const { rvwHistRes, ruseHistHeadList } = ruseHist;
const { rvwHistRes, ruseHistHeadList,rvwHistCount } = ruseHist;
const [pageNation, setPageNatiion] = useState<number>(1);
const [dmdCoNm, setDmdCoNm] = useState<string>("");
@@ -69,6 +70,36 @@ export default function RuseRvwHstry() {
setObjSearch({ city: cityValue, sgg: "0" });
};
useEffect(() =>{
getButtonSearch()
},[pageNation])
const getButtonSearch=()=>{
if (fromDate && toDate) {
const fromNum = Number(fromDate);
const toNum = Number(toDate);
if (fromNum > toNum) {
toast.error(
"시작년도가 종료년도 이후로 설정할 수 없습니다."
);
} else {
let con: string | number = "";
if (String(objSearch.city).length > 0) {
con = String(objSearch.city);
}
if (String(objSearch.sgg).length > 0 && objSearch.sgg !== "0") {
con = String(objSearch.sgg);
}
getSearch(
fromNum,
toNum,
con,
dmdCoNm,
ruseUtztnFcltNm
);
}
}
}
const getSgg = (val: string | number) => {
console.log(val);
setObjSearch({ ...objSearch, sgg: String(val) });
@@ -163,23 +194,29 @@ export default function RuseRvwHstry() {
const data = rvwHistRes?.map((item, index) => {
let flag = "";
flag = getdmdMatFlag(item.demandMatching?.splyFcltFlg ?? "");
const formatDate = (dateStr: string | null | undefined) => {
// null, undefined, 빈 문자열인 경우 '없음'을 반환합니다.
if (!dateStr) return "없음";
// "YYYYMMDD" 형식으로 날짜를 파싱합니다.
const d = moment(dateStr, "YYYYMMDD");
// 파싱된 날짜가 유효한 경우에만 포맷하고, 그렇지 않으면 '없음'을 반환합니다.
return d.isValid() ? d.format("YYYY-MM-DD") : "없음";
};
return {
...item,
ctpvCd: item.demandCo?.ctpvCd,
sggCd: item.demandCo?.sggCd,
dmdCoNm: item.demandCo?.dmdCoNm,
daddr: item.demandCo?.daddr,
telno: item.demandCo?.telno,
regDt: item?.demandCo?.regDt
? moment(item?.demandCo?.regDt).format("YYYY-MM-DD")
: "없음",
rvwCmptnYmd: item?.rvwCmptnYmd
? moment(item?.rvwCmptnYmd).format("YYYY-MM-DD")
: "없음",
mtchnCmptnYmd: item?.mtchnCmptnYmd
? moment(item?.mtchnCmptnYmd).format("YYYY-MM-DD")
telno: formatPhoneNumber(item.demandCo?.telno ||''),
dmndTmng: item?.dmndTmng
? moment(item?.dmndTmng).format("YYYY-MM-DD")
: "없음",
rvwCmptnYmd: formatDate(item.demandMatching?.rvwCmptnYmd),
mtchnCmptnYmd: formatDate(item.demandMatching?.mtchnCmptnYmd),
ruseUtztnFcltNm: item.ruseUtztnFcltNm,
dmndQty: item.dmndQty,
splyFcltFlg: flag,
@@ -272,30 +309,7 @@ export default function RuseRvwHstry() {
<Button
size={"sm"}
onClick={(e) => {
if (fromDate && toDate) {
const fromNum = Number(fromDate);
const toNum = Number(toDate);
if (fromNum > toNum) {
toast.error(
"시작년도가 종료년도 이후로 설정할 수 없습니다."
);
} else {
let con: string | number = "";
if (String(objSearch.city).length > 0) {
con = String(objSearch.city);
}
if (String(objSearch.sgg).length > 0 && objSearch.sgg !== "0") {
con = String(objSearch.sgg);
}
getSearch(
fromNum,
toNum,
con,
dmdCoNm,
ruseUtztnFcltNm
);
}
}
getButtonSearch()
}}
>
조회
@@ -318,17 +332,23 @@ export default function RuseRvwHstry() {
tableData={rvwHistData || []}
headlist={ruseHistHeadList}
pageSize={20}
total={100000}
total={rvwHistCount}
cellClick={(index: number | undefined, headId: string) => {
TableCellClick(index);
}}
onPageChange={setPageNatiion}
onPageChange={
(page)=>{
setPageNatiion(page)
}
}
></UiTable>
<hr />
{/* <hr />
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
</h3>
<ConCostForm form={form} type={"hist"} />
<ConCostForm form={form} type={"hist"} selectionVersion={0} /> */}
</ListDiv>
</div>
</div>
+47 -22
View File
@@ -5,6 +5,7 @@ import { btnClass } from "@/app/store/common/code";
import { fetchType, getFetch } from "@/components/lib/api";
import {
excelDownload,
formatPhoneNumber,
getCity,
tableData
} from "@/components/lib/func/commom";
@@ -26,6 +27,7 @@ import ListDiv from "@common/business_components/ui/list_div";
import SdmInsertForm from "@common/business_components/ui/sdmInsertForm";
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
import { Button } from "@common/components/ui";
import moment from "moment";
import { useCallback, useEffect, useState } from "react";
import toast, { Toaster } from "react-hot-toast";
@@ -59,17 +61,29 @@ export default function CoSttn() {
const [seartchTxt, setSearchTxt] = useState<string>();
const [upadateData, setUpdateData] = useState<DemandCompType>();
const getSelCity = (val: string | number) => {
const cityValue = String(val); // Ensure val is treated as a string
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
setObjSearch({ city: cityValue, sgg: "" });
};
const getSelCity = useCallback((val: string | number) => {
const cityValue = String(val);
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
// 시/도를 변경하면 시/군/구는 '전체'("0")로 초기화합니다.
setObjSearch({ city: cityValue, sgg: "0" });
}, [code.sggCd]);
const getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) });
};
const getSgg = useCallback((val: string | number) => {
setObjSearch((prev) => ({ ...prev, sgg: String(val) }));
}, []);
useEffect(() => {
// code.cityCd 데이터가 로드되었고, 아직 시/도 선택이 안된 초기 상태일 때 실행
if (code.cityCd && code.cityCd.length > 0 && !objSearch.city) {
const firstCityVal = code.cityCd[0]?.val;
if (firstCityVal) {
// 첫 번째 시/도 값으로 상태를 초기화합니다.
getSelCity(firstCityVal);
}
}
}, [code.cityCd, objSearch.city, getSelCity]);
useEffect(() => {
if (!coSttn.isInit) {
coSttnInit("1", "13", "0");
@@ -77,15 +91,21 @@ export default function CoSttn() {
}, [coSttn.isInit, coSttnInit]);
useEffect(() => {
if (coSttnRes?.length > 0 && code.cityCd.length > 0) {
const data = tableData(coSttnRes, { code });
const chData = data.map((item: any) => ({
...item,
}));
// .filter((item: any) => item !== undefined);
setBdstTable(chData);
} else if (coSttnRes.length == 0) {
setBdstTable([]);
if(coSttnRes){
if (coSttnRes?.length > 0 && code.cityCd.length > 0) {
const data = tableData(coSttnRes, { code });
const chData = data.map((item: any) => ({
...item,
telno:formatPhoneNumber(item.telno||undefined),
regDt: moment(item.regDt).format("YYYY-MM-DD")
}));
// .filter((item: any) => item !== undefined);
setBdstTable(chData);
} else if (coSttnRes?.length == 0) {
setBdstTable([]);
}
}
}, [coSttnRes, code]);
@@ -116,8 +136,11 @@ export default function CoSttn() {
const searchClick = () => {
const con = (objSearch.sgg && objSearch.sgg !== "0") ? objSearch.sgg : objSearch.city;
if (con) {
if (seartchTxt && seartchTxt?.length > 0) {
console.log(' seartchTxt ', seartchTxt)
coSttnTxtSearch("1", "13", String(con), seartchTxt ?? "");
} else {
coSttnSearch("1", "13", String(con));
@@ -139,13 +162,15 @@ export default function CoSttn() {
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
value={objSearch.city}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시군구"
selectClass={""}
selectArray={selectSgg?selectSgg : [{text:"전체",val:"0"}]}
selectArray={selectSgg || []}
onSelectValue={getSgg}
value={objSearch.sgg}
/>
<SearchInput
className={"!text-3xl"}
@@ -159,7 +184,7 @@ export default function CoSttn() {
</SearchFormLeft>
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="flex flex-row space-x-2">
<Button size={"sm"} onClick={searchClick}>
<Button className="mt-2" size={"sm"} onClick={searchClick}>
조회
</Button>
<Button
@@ -179,7 +204,7 @@ export default function CoSttn() {
onClick={() => {
/* 저장 로직 */
if (!upadateData) {
<ToastFormUi body={"수요처 변경을 원하는 행을 선택해주세요"} title={"수요처관리"}></ToastFormUi>;
toast.error("수요처 변경을 원하는 행을 선택해주세요")
}else{
setIsDmdModal({
...isDmdModal,
@@ -187,7 +212,7 @@ export default function CoSttn() {
}
}}
>
저장
수정
</Button>
<Button
size={"sm"}
+103 -55
View File
@@ -3,18 +3,17 @@ import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import type { customDrgt } from "@/app/store/matDmd/drgtSttn";
import { drgtHeadListExport } from "@/app/store/matDmd/drgtSttn/headList";
import { excelDownload, getCity } from "@/components/lib/func/commom";
import { getCity } from "@/components/lib/func/commom";
import DrgtDetailModal from "@/components/ui/modal/coMat/drgtDetailModal";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import { ContentsDiv, DateMonthPicker, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui";
import { MonthPicker } from "@common/business_components/ui/date_month_picker/mothPicker";
import { ContentsDiv, DateMonthPicker, downloadExcel, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, DatePicker, Label } from "@common/components/ui";
import { useCallback, useEffect, useState } from "react";
import { Button, Label, ScrollArea } from "@common/components/ui";
import { useEffect, useState } from "react";
import { toast, Toaster } from "react-hot-toast";
export default function DrgtSttn() {
const { code, drgt, drgtSearch, drgtModalSearch } = useWrStore((state) => state);
const { code, drgt, drgtSearch, drgtModalSearch, drgtInit } = useWrStore((state) => state);
const { drgtRes, drgtMoRes } = drgt;
const [fromDate, setFromDate] = useState<string>();
const [toDate, setToDate] = useState<string>();
@@ -22,6 +21,7 @@ export default function DrgtSttn() {
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [tableData, setTableData] = useState<customDrgt[]>();
const [selectedSgg, setSelectedSgg] = useState<string>('');
const [excelData, setExcelData] = useState<any[]>();
const [drgtModal, setDrgtModal] = useState<{
isOpen: boolean;
data: customDrgt | undefined;
@@ -35,45 +35,82 @@ export default function DrgtSttn() {
}
}
const excelClick = () => {
downloadExcel({
data: excelData ?? [],
fileName: "우리동네가뭄 현황",
sheetNameArray: ["Sheet1"],
headerRange: "A1:G1"
})
}
useEffect(() => {
if (!drgt.isInit) {
drgtInit();
}
}, [drgt.isInit, drgtInit]);
useEffect(() => {
let resData = Array.isArray(drgtRes) ? drgtRes : [drgtRes];
resData = resData.map((item) => {
if (item.sggNm === '세종시') {
return {
...item,
ctpvCd: '세종특별자치시',
sggNm: ''
}
}
return {
...item,
ctpvCd: code.cityCd.find(ct => (ct.text == item.sggNm || (code.sggCd.find(sgg => sgg.text == item.sggNm)?.val.substring(0, 2) == ct.val)))?.text,
sggNm: code.sggCd.find(sgg => sgg.text == item.sggNm)?.text
}
})
const data = Array.isArray(resData)
? resData.map((item: customDrgt) => {
return {
"시도": item.ctpvCd,
"시군구": item.sggNm,
"정상(횟수)": item.normal,
"관심(횟수)": item.attention,
"주의(횟수)": item.caution,
"관심+주의(횟수)": item.warning,
"가뭄순위": item.ranking,
}
}) : [];
setExcelData(data)
setTableData(resData)
}, [drgtRes])
useEffect(() => {
if (drgtMoRes && drgtMoRes.length > 0) {
setDrgtModal({ isOpen: true, data: drgtMoRes });
}
}, [drgtMoRes]);
const getCityVal = (val: string, sggCd: SelectDataType[]) => {
const data = sggCd
.filter((item) => String(item.val).substring(0, 2) === val)
.map((item) => ({
val: item.val,
text: item.text, // 한국어 텍스트
}));
return data;
};
const getSelCity = (val: string | number) => {
const cityValue = String(val);
const data = getCityVal(cityValue, code.sggCd);
setSelectSgg(data);
const sggVal = data.length > 0 ? data[0].val : '';
setSelectedSgg(sggVal); // 시군구 value 세팅
setObjSearch({ city: cityValue, sgg: sggVal });
if (cityValue === "0") {
setSelectSgg([]);
setSelectedSgg('');
setObjSearch({ city: cityValue, sgg: '' });
} else {
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? "");
setSelectedSgg(firstSggVal);
setObjSearch({ city: cityValue, sgg: firstSggVal });
}
};
const getSgg = (val: string | number) => {
setSelectedSgg(String(val));
setObjSearch({ ...objSearch, sgg: String(val) });
};
const excelClick = useCallback(() => {
excelDownload(
[[]],
"우리동네가뭄",
"sample_drgtSttn.xlsx",
"A1:H1"
);
}, []);
useEffect(() => {
if (fromDate === undefined && toDate === undefined) {
const today = new Date();
@@ -101,7 +138,7 @@ export default function DrgtSttn() {
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
className="col-span-2 w-1/6 h-full text-2xl ml-8"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
@@ -110,7 +147,7 @@ export default function DrgtSttn() {
/>
<div className="col-span-5 w-auto">
<div className="flex flex-row items-center">
<Label className="text-xl text-gray-600">조회기간</Label>
<Label className="text-xl text-gray-600 ml-8">조회기간</Label>
<div className="flex flex-row w-1/4">
<DateMonthPicker
field={{
@@ -125,8 +162,9 @@ export default function DrgtSttn() {
setFromDate(formatted);
}
}}
selectClass="ml-4 text-2xl"
/>
<span>~</span>
<span className="ml-2 text-center">~</span>
<DateMonthPicker
field={{
value: toDate,
@@ -140,6 +178,7 @@ export default function DrgtSttn() {
setToDate(formatted);
}
}}
selectClass="ml-4"
/>
</div>
</div>
@@ -148,35 +187,42 @@ export default function DrgtSttn() {
</SearchFormLeft>
<SearchFormRight
className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="flex flex-row space-x-2">
<div className="flex flex-row space-x-2 items-center">
<Button
size={"sm"}
onClick={(e) => {
let sidoText = '';
let sggText = '';
let sggText = [];
if (objSearch?.city.toString().length > 0) {
sidoText = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? '';
}
if (objSearch?.sgg.toString().length > 1) {
sggText = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? '';
} else {
sggText = code.sggCd.filter((item) => item.val.substring(0, 2) === objSearch?.city).map((item) => item.text);
}
if (sidoText === '전체') { sidoText = '' }
if (sidoText === '세종특별자치시') {
sidoText = '세종시';
sggText = sidoText;
}
drgtSearch(fromDate ?? "", toDate ?? "", sidoText, sggText)
const searchArr = [];
if (sidoText) searchArr.push(sidoText);
if (Array.isArray(sggText)) {
searchArr.push(...sggText);
} else if (sggText) {
searchArr.push(sggText);
}
drgtSearch(fromDate ?? "", toDate ?? "", searchArr)
}}
>
조회
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => { }}
>
상세보기
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
@@ -199,17 +245,19 @@ export default function DrgtSttn() {
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={drgtRes || []}
headlist={drgtHeadListExport}
pageSize={20}
total={10000}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={() => { }}
></UiTable>
<ScrollArea className="h-[66vh]">
<UiTable
headName={undefined}
tableData={tableData || []}
headlist={drgtHeadListExport}
pageSize={14}
total={0}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={() => { }}
></UiTable>
</ScrollArea>
</ListDiv>
</div>
</div>
@@ -219,7 +267,7 @@ export default function DrgtSttn() {
setDrgtModal({ ...drgtModal, isOpen: !drgtModal.isOpen });
}}
bodyClass={"w-[50vw] max-w-none h-[80vh]"}
body={<DrgtDetailModal data={drgtModal.data} /*formObj={drgtModal.data}*/ />}
body={<DrgtDetailModal data={drgtModal.data} />}
/>
<Toaster position="top-center" />
</ContentsDiv>
+46 -27
View File
@@ -44,7 +44,7 @@ export default function LdrmntCoSttn() {
const [searchTxt, setSearchTxt] = useState<string>();
const ref = useRef<ReturnType>({} as ReturnType);
const [excelData, setExcelData] = useState<any[]>();
const [isExcelDownload, setIsExcelDownload] = useState(false);
const excelClick = useCallback(() => {
excelDownload(
@@ -57,14 +57,22 @@ export default function LdrmntCoSttn() {
}, []);
const excelDownloadClick = () => {
downloadExcel({
data: excelData ?? [],
fileName: "잠재수요처 관리",
sheetNameArray: ["Sheet1"],
headerRange: "A1:F1"
})
ldrmntSearch(1, "10000", "0", "");
setIsExcelDownload(true);
}
useEffect(() => {
if (isExcelDownload && excelData && excelData.length > 0) {
downloadExcel({
data: excelData,
fileName: "잠재수요처 관리",
sheetNameArray: ["Sheet1"],
headerRange: "A1:F1"
});
setIsExcelDownload(false);
}
}, [excelData, isExcelDownload]);
const [isExcelOpen, setIsExcelOpen] = useState<{
isModal: boolean;
}>({ isModal: false });
@@ -73,14 +81,21 @@ export default function LdrmntCoSttn() {
if (index !== undefined) {
setDetailModal({ isOpen: true, data: ldrmntRes[index] });
}
}
const getSelCity = (val: string | number) => {
const cityValue = String(val); // Ensure val is treated as a string
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
setObjSearch({ city: cityValue, sgg: '' });
const cityValue = String(val);
if (cityValue === "0") {
setSelectSgg([]);
setObjSearch({ city: cityValue, sgg: "" });
} else {
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? "");
setObjSearch({ city: cityValue, sgg: firstSggVal });
}
};
const getSgg = (val: string | number) => {
@@ -125,10 +140,9 @@ export default function LdrmntCoSttn() {
setExcelData(data)
}, [excelList])
useEffect(() => {
let cityTxt = '';
let sggTxt = '';
let cityTxt = ''
let sggTxt = ''
if (objSearch?.city.toString().length > 0) {
cityTxt = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? '';
@@ -138,21 +152,23 @@ export default function LdrmntCoSttn() {
sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? '';
}
let cityNm = "";
if (cityTxt === '전체' || cityTxt === '') {
cityTxt = '0'
}
let cityNm = ""
if (sggTxt !== "0") {
cityNm = cityTxt + " " + sggTxt;
cityNm = cityTxt + " " + sggTxt
} else {
cityNm = cityTxt;
cityNm = cityTxt
}
if (cityNm) {
if (cityTxt === '') cityNm = "0";
ldrmntSearch(pageNation, cityNm, searchTxt || "");
ldrmntSearch(pageNation, '20', cityNm, searchTxt || "");
} else {
ldrmntSearch(pageNation, "", searchTxt || "");
ldrmntSearch(pageNation, '20', '0', searchTxt || "");
}
}, [pageNation, objSearch, code, searchTxt, ldrmntSearch])
}, [pageNation]);
return (
<>
@@ -175,6 +191,7 @@ export default function LdrmntCoSttn() {
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
value={objSearch.sgg} // value props 추가
onSelectValue={getSgg}
/>
<SearchInput
@@ -189,7 +206,7 @@ export default function LdrmntCoSttn() {
</SearchFormLeft>
<SearchFormRight
className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="flex flex-row space-x-2">
<div className="flex flex-row space-x-2 items-center">
<Button
size={"sm"}
onClick={(e) => {
@@ -205,6 +222,10 @@ export default function LdrmntCoSttn() {
sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? '';
}
if (cityTxt === '전체' || cityTxt === '') {
cityTxt = '0'
}
let cityNm = ""
if (sggTxt !== "0") {
@@ -212,10 +233,8 @@ export default function LdrmntCoSttn() {
} else {
cityNm = cityTxt
}
if (cityNm) {
if (cityTxt === '') cityNm = "0";
ldrmntSearch(pageNation, cityNm, searchTxt || "");
ldrmntSearch(pageNation, '20', cityNm, searchTxt || "");
}
}}
>
@@ -16,73 +16,80 @@ import { Button } from "@common/components";
import ListDiv from "@common/business_components/ui/list_div";
import { useEffect, useState } from "react";
import { tableData } from "@/components/lib/func/commom";
import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm";
import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm";
import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg";
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import { Toaster } from "react-hot-toast";
export default function Home() {
const { code, htdfl, initHtdfl,getHtdflBdstData } = useWrStore((state) => state);
const { code, htdfl, initHtdflReg, getHtdflBdstData ,htdflNmSearch} = useWrStore(
(state) => state
);
const [searchTxt, setSearchTxt] = useState("");
const [pageNation, setPageNation] = useState(1);
const [htdflForm, setHtdflForm] = useState<customHtdflBdst>();
const [bdstTable, setbdstTable] = useState<customHtdflBdst[]>();
const [issNewReg,setIsNewReg] = useState<boolean>( false);
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
const { htdflRes } = htdfl;
useEffect(() => {
if (!htdfl.isInit) {
initHtdfl('0');
initHtdflReg('41')
}
}, [htdfl.isInit, initHtdfl]);
}, [htdfl.isInit, initHtdflReg]);
useEffect(() => {
if (code.sggCd.length > 0) {
if (htdflRes&&htdflRes.length>0) {
const htdflData = tableData(htdflRes, { code }).map(
(item: customHtdflBdst) => {
return {
...item,
bdstChgYn: item?.chgBuilding && item.chgBuilding.length > 0 && item.chgBuilding[0]?.bdstChgNm !== null ? 'Y' : 'N',
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd
};
}
);
setbdstTable(htdflData);
console.log('htdflRes ', htdflRes)
const htdflData = tableData(htdflRes, { code }).map(
(item: customHtdflBdst) => {
let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가'
return {
...item,
archArea:archArea
};
}
);
setbdstTable(htdflData);
}else{
setbdstTable([]);
}
}, [code, htdflRes]);
const cellClick: (val: number|undefined ,headId: string) => void = (
val
,headId) => {
const cellClick: (val: number | undefined, headId: string) => void = (
val,
headId
) => {
if ((bdstTable ?? []).length > 0 && val !== undefined) {
{
setHtdflForm(htdflRes[val]);
}
}
if (headId === "bdstChgYn" && val !== undefined) {
if (
htdflRes[val]?.bdstInfoPk != null &&
htdflRes[val]?.chgBuilding?.length > 0
) {
bdstChgModal(htdflRes[val]?.chgBuilding as chgBuilding[]);
}
}
};
const bdstChgModal = (chgBuilding: chgBuilding[]) => {
setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
// if (headId === "bdstChgYn" && val !== undefined) {
// if (
// htdflRes[val]?.bdstInfoPk != null &&
// htdflRes[val]?.chgBuilding?.length > 0
// ) {
// bdstChgModal(htdflRes[val]?.chgBuilding as chgBuilding[]);
// }
// }
};
// const bdstChgModal = (chgBuilding: chgBuilding[]) => {
// setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
// };
useEffect(() => {
getHtdflBdstData(pageNation, "0");
getHtdflBdstData(pageNation, "41");
}, [pageNation]);
return (
@@ -103,14 +110,23 @@ export default function Home() {
/>
</SearchFormLeft>
<SearchFormRight>
<div className="flex flex-row space-x-2 items-center">
<Button size={"sm"} onClick={()=>{initHtdfl(searchTxt||"")}}>조회</Button>
<Button
<div className="flex flex-row space-x-2 items-center">
<Button
size={"sm"}
onClick={() => setIsNewReg(!issNewReg)}
>
신규등록
</Button>
onClick={() => {
if(searchTxt&&searchTxt.length>0){
htdflNmSearch(String(41),searchTxt)
}else{
initHtdflReg(String(41) );
}
}}
>
조회
</Button>
<Button size={"sm"} onClick={() => setIsNewReg(!issNewReg)}>
신규등록
</Button>
</div>
</SearchFormRight>
</SearchDiv>
@@ -126,41 +142,50 @@ export default function Home() {
pageSize={100}
total={10}
headName={"건축물 목록"}
cellClick={(val, headId) => { cellClick(val || undefined, headId); } }
cellClick={(val, headId) => {
cellClick(val || undefined, headId);
}}
onPageChange={setPageNation}
>
</UiTable>
></UiTable>
</ListDiv>
</div>
<div className="col-span-2 max-h-full">
<ListDiv>
<ScrollArea className="h-[60vh]">
<HtdflRegForm
htdflForm={htdflForm ?? ({} as customHtdflBdst)}
isModal={false}
/>
</ScrollArea>
<ListDiv>
<ScrollArea className="h-[60vh]">
<HtdflRegForm
htdflForm={htdflForm ?? ({} as customHtdflBdst)}
isModal={false}
/>
</ScrollArea>
</ListDiv>
</div>
</div>
<UiModal
body={<BdstReg moType="HTB"></BdstReg>}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
}}
/>
<UiModal
<UiModal
body={
<BdstReg
moType="HTB"
isModal={false}
setIsModal={setIsNewReg}
></BdstReg>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
}}
/>
<Toaster position="top-center" />
{/* <UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>}
body={
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}
}
/>
}}
/> */}
</ContentsDiv>
</>
);
@@ -35,6 +35,10 @@ import { useFieldArray, useForm, type FieldErrors } from "react-hook-form"; // F
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createDefaultPbnstItem } from "./utilsZod";
export default function PublicReuseFaciltyInsert() {
const {
code,
@@ -66,6 +70,8 @@ export default function PublicReuseFaciltyInsert() {
// defaultValues: { items: pbnstRegArrayZod.parse([]) },
mode: "onChange",
});
const { isDirty } = form.formState;
const {
fields: items,
append,
@@ -83,7 +89,11 @@ export default function PublicReuseFaciltyInsert() {
}, [pbnst.isInit, pubHasuInit]);
const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => {
const data = writeRgtrAndMdfr(valuse.items);
if (!isDirty) {
toast.error("변경사항이 없습니다."); // 변경사항이 없으면 메시지 표시
return;
} const data = writeRgtrAndMdfr(valuse.items);
let bizs = [] as fcBizType[];
data.forEach((fclt) => {
bizs = [...bizs, ...fclt.fcBizs];
@@ -100,66 +110,71 @@ export default function PublicReuseFaciltyInsert() {
fcOpers: fclt.fcOpers,
};
});
await pbnstRuseFcltUpdate(pbnst as customPbnst[]);
await pbnstRuseFcltUpdate(pbnst as customPbnst[])
await pbnstRuseBizUpdate(bizs);
};
// 폼 유효성 검사 실패 시 호출될 함수
const onInvalid = (
errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>
) => {
// 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다.
const onInvalid = (errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>) => {
console.log("errors:", errors);
const findAllErrors = (
errorObject: any,
path: (string | number)[] = []
): { message: string; path: (string | number)[] }[] => {
if (!errorObject) return [];
return Object.keys(errorObject).flatMap((key) => {
const value = errorObject[key];
const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key;
const newPath = [...path, currentKey];
if (value && typeof value === "object") {
if (typeof value.message === "string") {
return [{ message: value.message, path: newPath }]; // 에러 메시지와 경로 반환
if (value.message) {
return [{ message: value.message, path: newPath }];
}
return findAllErrors(value, newPath);
}
return [];
});
};
const errorList = findAllErrors(errors);
if (errorList.length > 0) {
errorList.forEach((errorInfo) => {
const { message, path } = errorInfo;
let prefix = "";
const itemsIndex = path.indexOf("items");
if (itemsIndex > -1 && path.length > itemsIndex + 1) {
const itemIdx = path[itemsIndex + 1] as number;
const facilityName = form.getValues(
`items.${itemIdx}.ruseUtztnFcltNm`
);
const facilityName = form.getValues(`items.${itemIdx}.ruseUtztnFcltNm`);
if (facilityName) {
prefix += `[${facilityName}] `;
}
const fcBizsIndex = path.indexOf("fcBizs");
if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) {
const bizIdx = path[fcBizsIndex + 1] as number;
const cycle = form.getValues(
`items.${itemIdx}.fcBizs.${bizIdx}.cycl`
);
const cycle = form.getValues(`items.${itemIdx}.fcBizs.${bizIdx}.cycl`);
if (cycle) {
prefix += `[${cycle}차수] `;
}
}
}
// 최종 오류 메시지 출력
toast.error(`${prefix}${message}`);
});
}
};
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
useEffect(() => {
if (code.sggCd.length && pbnstHasuRes.length > 0) {
@@ -184,7 +199,11 @@ export default function PublicReuseFaciltyInsert() {
useEffect(() => {
if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) {
form.reset({ items: pbnstRegArrayZod.parse(pbnst.pbnstRes) });
form.reset({ items: pbnst.pbnstRes });
} else {
form.reset({ items: [] });
}
@@ -204,21 +223,23 @@ export default function PublicReuseFaciltyInsert() {
if (pbnstRes && pbnstRes.length > 0) {
const lastPbnst = pbnstRes[pbnstRes.length - 1];
if (lastPbnst && selecTableRow) {
append(
pbnstRegZod.parse({
pbnstRuseFcltPk:
String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1),
ruseUtztnFcltNm: "",
fcBizs: [
fcBizSchema.parse({
pbnstRuseFcltFk:
String(lastPbnst.pbnstRuseFcltPk) +
String(pbnstRes.length + 1),
cycl: 1,
}),
] as fcBizType[],
})
);
// append(
// pbnstRegZod.parse({
// pbnstRuseFcltPk:
// String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1),
// ruseUtztnFcltNm: null,
// fcBizs: [
// fcBizSchema.parse({
// pbnstRuseFcltFk:
// String(lastPbnst.pbnstRuseFcltPk) +
// String(pbnstRes.length + 1),
// cycl: 1,
// }),
// ] as fcBizType[],
// })
// );
append(createDefaultPbnstItem(selecTableRow, pbnstRes.length));
setIsRuseReg({ isModal: true });
}
} else {
@@ -400,6 +421,8 @@ export default function PublicReuseFaciltyInsert() {
setIsRuseReg({ isModal: false });
}
}}
onInvalid ={onInvalid}
></PbnstRegModal>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
@@ -0,0 +1,38 @@
import type { fcBizType, pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
export function createDefaultPbnstItem(
selecTableRow: pubHasuType,
index: number
) {
const pk = String(selecTableRow.bscFctCd) + String(index + 1);
return {
pbnstRuseFcltPk: pk,
swtrmtFcltFk: "",
ruseUtztnFcltNm: "", // 필수 입력이므로 빈 문자열로
fcltCpct: 0,
ruseCpct: 0,
splyExtraCpct: 0,
regDt: null,
rgtr: "test",
mdfcnDt: null,
mdfr: "test",
fcFiles: [],
fcBizs: [
createDefaultBiz(pk, 1), // 첫 차수
],
fcOpers: [],
};
}
export function createDefaultBiz(
pbnstRuseFcltFk: string,
cycl: number
): fcBizType {
return {
pbnstRuseFcltFk,
cycl,
// 필요한 값 있으면 여기에 추가
} as fcBizType;
}
@@ -21,11 +21,14 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components";
import { useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
export default function Home() {
const { rain, code, initRain, rainSearch, getRainData } = useWrStore((state) => {
return state;
});
const { rain, code, initRain, rainSearch, getRainData } = useWrStore(
(state) => {
return state;
}
);
const { rainRes } = rain;
const [rainForm, setRainForm] = useState<customRainBdst>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
@@ -38,10 +41,9 @@ export default function Home() {
}>({ isOpen: false, chgBuilding: [] });
useEffect(() => {
setIsNewReg( false)
setIsNewReg(false);
if (!rain.isInit) {
initRain('41');
initRain("41");
}
}, [rain.isInit, initRain]);
@@ -49,8 +51,11 @@ export default function Home() {
if (code.sggCd.length > 0) {
const rainData = tableData(rainRes, { code }).map(
(item: customRainBdst) => {
let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가'
return {
...item,
archArea:archArea,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
};
}
@@ -130,35 +135,39 @@ export default function Home() {
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
{/* <ScrollArea className="h-[60vh]"> */}
<UiTable
tableData={bdstTable || []}
headlist={rain.upHeadList}
pageSize={20}
total={10000}
headName={"건축물 목록"}
cellClick={(val, headId) => {
cellClick(val, headId);
}}
onPageChange={setPageNation}
>
</UiTable>
<UiTable
tableData={bdstTable || []}
headlist={rain.upHeadList}
pageSize={20}
total={10000}
headName={"건축물 목록"}
cellClick={(val, headId) => {
cellClick(val, headId);
}}
onPageChange={setPageNation}
></UiTable>
{/* </ScrollArea> */}
</ListDiv>
</div>
<div className="col-span-2 max-h-full">
<ListDiv className="">
<ScrollArea className="h-[60vh]">
<RainRegForm
rainForm={rainForm ?? ({} as customRainBdst)}
isModal={false}
></RainRegForm>
<RainRegForm
rainForm={rainForm ?? ({} as customRainBdst)}
isModal={false}
></RainRegForm>
</ScrollArea>
</ListDiv>
</div>
</div>
<UiModal
body={<BdstReg moType="RNB"></BdstReg>}
body={
<BdstReg
moType="RNB"
isModal={issNewReg}
setIsModal={setIsNewReg}
></BdstReg>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
@@ -176,6 +185,8 @@ export default function Home() {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
<Toaster position="top-center" />
</ContentsDiv>
</>
);
@@ -20,6 +20,7 @@ import {
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components";
import { useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
export default function Home() {
const { code, rswt, initRswt, rswtBdstSearch, getRswtBdstData } = useWrStore(
@@ -45,8 +46,13 @@ export default function Home() {
if (code.sggCd.length > 0 && rswtRes?.length > 0) {
const rswtData = tableData(rswtRes, { code })?.map(
(item: customRswtBdst) => {
let archArea =
item?.archArea.split(".")[0] !== "-1"
? item?.archArea.split(".")[0]
: "확인불가";
return {
...item,
archArea: archArea,
bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N",
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd,
};
@@ -151,7 +157,13 @@ export default function Home() {
</div>
<UiModal
body={<BdstReg moType="RST" setIsModal={setIsNewReg}></BdstReg>}
body={
<BdstReg
moType="RST"
setIsModal={setIsNewReg}
isModal={issNewReg}
></BdstReg>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
@@ -162,12 +174,14 @@ export default function Home() {
bodyClass={""}
open={bdstChgProps.isOpen}
body={
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding} ></BdstChgModal>
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
<Toaster position="top-center" />
</ContentsDiv>
</>
);
@@ -8,6 +8,7 @@ import type {
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
excelDownload,
getCity,
getCityOrSgg,
tableData,
} from "@/components/lib/func/commom";
@@ -16,16 +17,23 @@ import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDeta
import {
ContentsDiv,
SearchBaseForm,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type ReturnType,
type SelectDataType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { Button, Label } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import { excelHtdflSttnParsing } from "@/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
export default function HtdflSttn() {
const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore(
@@ -38,6 +46,8 @@ export default function HtdflSttn() {
const [pageNation, setPageNation] = useState(1);
const [isChHead, setIsChHead] = useState(false);
const [bdstTable, setBdstTable] = useState<customRainBdst[]>();
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [detailModal, setDetailModal] = useState<{
isOpen: boolean;
data: customRainBdst | undefined;
@@ -46,17 +56,47 @@ export default function HtdflSttn() {
isOpen: boolean;
chBuilding: chgBuilding[];
}>({ isOpen: false, chBuilding: [] });
const codeData = getCityOrSgg(ref);
const [fcltNm, setFcltNm] = useState<string>("");
const excelClick = useCallback(() => {
if (codeData) htdflSttnSearch(1, "10000", codeData);
}, [htdflSttnSearch, codeData]);
// 최신 검색 조건 반영
const con = getConValue();
htdflSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd);
}, [htdflSttnSearch, objSearch, code.cityCd, code.sggCd]);
useEffect(() => {
if (codeData != null) htdflSttnSearch(pageNation, "20", codeData);
htdflSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
}, [pageNation]);
const getSelCity = (val: string | number) => {
const cityValue = String(val);
if (cityValue === "0") {
setSelectSgg([]);
setObjSearch({ city: cityValue, sgg: "" });
} else {
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? "");
setObjSearch({ city: cityValue, sgg: firstSggVal });
}
};
const getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) })
};
const getConValue = () => {
if (!objSearch.city || objSearch.city === "0") {
return "0";
}
if (objSearch.sgg && objSearch.sgg !== "0") {
return objSearch.sgg;
}
return objSearch.city;
};
const cellClick = (index: number | undefined, headId: string) => {
if (
headId !== "chBuildingYn" &&
@@ -67,42 +107,34 @@ export default function HtdflSttn() {
}
};
useEffect(() => {
const excelDown = async () => {
if (htdflSttn.excelList.length > 0) {
if (htdflSttn.excelList.length === 0) return;
const excelData = await tableData(htdflSttn.excelList, { code });
const htdflExcel = excelHtdflSttnParsing(excelData, code.cityCd, code.sggCd);
excelDownload(
htdflExcel as [[]],
"온배수시설 현황",
"sample_htdflSttn.xlsx",
"A1:S3"
);
}
};
excelDown();
if (htdflSttn.excelList.length > 0) {
if (htdflSttn.excelList.length === 0) return;
excelDownload(
htdflSttn.excelList,
"온배수시설 현황",
"sample_htdflSttn.xlsx",
"A1:S3"
);
}
}, [htdflSttn.excelList, code]);
useEffect(() => {
if (!htdflSttn.isInit) {
initHtdfl(codeData ?? "0");
initHtdfl(1, "20", "0", fcltNm, code.cityCd, code.sggCd);
}
}, [htdflSttn.isInit, initHtdfl]);
useEffect(() => {
if (htdflSttnRes.length > 0 && code.cityCd.length > 0) {
const data = tableData(htdflSttnRes, { code });
const chData = data
.map((item: any) => ({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].htdflObj,
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
}))
.filter((item: any) => item.htdflObj !== undefined);
setBdstTable(chData);
}
const data = tableData(htdflSttnRes, { code });
const chData = data
.map((item: any) => ({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].htdflObj,
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
}))
.filter((item: any) => item.htdflObj !== undefined);
setBdstTable(chData);
}, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]);
return (
@@ -111,43 +143,76 @@ export default function HtdflSttn() {
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"온배수 시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
} }
>
조회항목설정
</Button>}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
let con;
if (returnType.sigunValue != "0") {
con = returnType.sigunValue;
} else {
con = returnType.sidoValue;
}
htdflSttnSearch(pageNation, "20", con);
} }
excelClick={excelClick}
initClick={function (): void { } }
btnClass={btnClass}
ref={ref} isAdmin={false} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl ml-4"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
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">
{"시설명"}
</Label>
<SearchInput
className={"w-full h-full text-2xl"}
label={""}
textValue={fcltNm || ""}
setText={setFcltNm}
/>
</div>
</div>
</SearchFormLeft>
<SearchFormRight
className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="flex flex-row space-x-2 items-center">
<Button
size={"sm"}
onClick={() => {
const con = getConValue();
htdflSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd);
}}
>
조회
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
onClick={excelClick}
>
다운로드
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
headName={undefined}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} />
@@ -4,6 +4,7 @@ import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import {
excelDownload,
getCity,
getCityOrSgg,
tableData,
} from "@/components/lib/func/commom";
@@ -11,13 +12,19 @@ import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
import {
ContentsDiv,
SearchBaseForm,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type ReturnType,
type SelectDataType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { Button, Label } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import type {
chgBuilding,
@@ -26,6 +33,7 @@ import type {
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
export default function RainSttn() {
const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore(
@@ -37,13 +45,14 @@ export default function RainSttn() {
const [pageNation, setPageNation] = useState(1);
const [isChHead, setIsChHead] = useState(false);
const [bdstTable, setBdstTable] = useState<customRainBdst[]>();
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false })
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chBuilding: chgBuilding[];
}>({ isOpen: false, chBuilding: [] });
const codeData = getCityOrSgg(ref);
const [fcltNm, setFcltNm] = useState<string>("");
const cellClick = (index: number | undefined, headId: string) => {
@@ -56,30 +65,74 @@ export default function RainSttn() {
}
};
const getSelCity = (val: string | number) => {
const cityValue = String(val);
if (cityValue === "0") {
setSelectSgg([]);
setObjSearch({ city: cityValue, sgg: "" });
} else {
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? "");
setObjSearch({ city: cityValue, sgg: firstSggVal });
}
};
const getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) })
};
const getConValue = () => {
if (!objSearch.city || objSearch.city === "0") {
return "0";
}
if (objSearch.sgg && objSearch.sgg !== "0") {
return objSearch.sgg;
}
return objSearch.city;
};
useEffect(() => {
if (!rainSttn.isInit) {
rainSttnInit(codeData ?? "0");
rainSttnInit(1, "20", "0", fcltNm, code.cityCd, code.sggCd);
}
}, [rainSttn.isInit, rainSttnInit]);
useEffect(() => {
if (rainSttnRes.length > 0 && code.cityCd.length > 0) {
const data = tableData(rainSttnRes, { code });
const chData = data
.map((item: any) => ({
const data = tableData(rainSttnRes, { code });
const chData = data
.map((item: any) => {
return {
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].rainyObj,
dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1
? "확인불가"
: item.reuseBuilding[0].rainyObj.dtfcltCpct,
instlCst: item.reuseBuilding[0].instlCst === -1
? "확인불가"
: item.reuseBuilding[0].instlCst,
instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1
? "확인불가"
: item.reuseBuilding[0].instlCstSprtAmt,
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
}))
.filter((item: any) => item.rainyObj !== undefined);
setBdstTable(chData);
}
pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1
? "확인불가"
: item.reuseBuilding[0].rainyObj.pntfColArea,
filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1
? "확인불가"
: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct,
archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea,
};
})
.filter((item: any) => item.rainyObj !== undefined);
setBdstTable(chData);
}, [code, rainSttnRes, rainSttn.rainSttHeadList]);
useEffect(() => {
if (codeData != null) rainSttnSearch(pageNation, "20", codeData, code.cityCd, code.sggCd);
rainSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
}, [pageNation]);
useEffect(() => {
@@ -95,8 +148,10 @@ export default function RainSttn() {
}, [rainSttn.excelList]);
const excelClick = useCallback(() => {
if (codeData) rainSttnSearch(1, "10000", codeData, code.cityCd, code.sggCd);
}, [rainSttnSearch, codeData, code.cityCd, code.sggCd]);
// 최신 검색 조건 반영
const con = getConValue();
rainSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd);
}, [rainSttnSearch, objSearch, code.cityCd, code.sggCd]);
return (
<>
@@ -104,47 +159,75 @@ export default function RainSttn() {
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"빗물재이용 시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={
<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
let con;
if (returnType.sigunValue != "0") {
con = returnType.sigunValue;
} else {
con = returnType.sidoValue;
}
rainSttnSearch(1, "20", con, code.cityCd, code.sggCd);
}}
excelClick={excelClick}
initClick={function (): void { }}
btnClass={btnClass}
ref={ref}
isAdmin={false}
/>
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl ml-4"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
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">
{"시설명"}
</Label>
<SearchInput
className={"w-full h-full text-2xl"}
label={""}
textValue={fcltNm || ""}
setText={setFcltNm}
/>
</div>
</div>
</SearchFormLeft>
<SearchFormRight
className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="flex flex-row space-x-2 items-center">
<Button
size={"sm"}
onClick={() => {
const con = getConValue();
rainSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd);
}}
>
조회
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
onClick={excelClick}
>
다운로드
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
headName={undefined}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} />
@@ -5,23 +5,31 @@ import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
import {
excelDownload,
getCity,
getCityOrSgg,
tableData,
} from "@/components/lib/func/commom";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
import {
ContentsDiv,
SearchBaseForm,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type ReturnType,
type SelectDataType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import { Button } from "@common/components/ui";
import { Button, Label } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
export default function RswtSttn() {
@@ -34,13 +42,14 @@ export default function RswtSttn() {
const [isChHead, setIsChHead] = useState(false);
const ref = useRef<ReturnType>({} as ReturnType);
const [bdstTable, setBdstTable] = useState<customRswtBdst[]>();
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false })
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chBuilding: chgBuilding[];
}>({ isOpen: false, chBuilding: [] });
const codeCityOrSgg = getCityOrSgg(ref);
const [fcltNm, setFcltNm] = useState<string>("");
const cellClick = (index: number | undefined, headId: string) => {
@@ -50,37 +59,67 @@ export default function RswtSttn() {
if (
bdstTable[index] &&
bdstTable[index]?.chBuildingYn === 'Y'
) {
setBdstChgProps({ isOpen: true, chBuilding: bdstTable[index].chgBuilding });
}
}
}
const getSelCity = (val: string | number) => {
const cityValue = String(val);
if (cityValue === "0") {
setSelectSgg([]);
setObjSearch({ city: cityValue, sgg: "" });
} else {
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? "");
setObjSearch({ city: cityValue, sgg: firstSggVal });
}
};
const getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) })
};
const getConValue = () => {
if (!objSearch.city || objSearch.city === "0") {
return "0";
}
if (objSearch.sgg && objSearch.sgg !== "0") {
return objSearch.sgg;
}
return objSearch.city;
};
useEffect(() => {
if (!rswtSttn.isInit) {
rswtSttnInit("0");
rswtSttnInit(1, "20", "0", fcltNm, code.cityCd, code.sggCd);
}
}, [rswtSttn.isInit, rswtSttnInit]);
useEffect(() => {
if (rswtSttnRes?.length > 0 && code.cityCd.length > 0) {
const data = tableData(rswtSttnRes, { code });
const chData = data
.map((item: customRswtBdst) => ({
const data = tableData(rswtSttnRes, { code });
const chData = data
.map((item: customRswtBdst) => {
return {
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0]?.rswtrObj,
chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N'
}))
.filter(
(item: customRswtBdst) =>
item.reuseBuilding[0]?.rswtrObj !== undefined
);
chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N',
instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst,
instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt,
archArea : item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가'
}
})
.filter(
(item: customRswtBdst) =>
item.reuseBuilding[0]?.rswtrObj !== undefined
);
setBdstTable(chData);
}
setBdstTable(chData);
}, [code, rswtSttnRes]);
useEffect(() => {
@@ -95,16 +134,14 @@ export default function RswtSttn() {
}
}, [rswtSttn.excelList]);
const excelClick = useCallback(
(returnType: ReturnType) => {
if (codeCityOrSgg)
rswtSttnSearch(1, "10000", codeCityOrSgg, code.cityCd, code.sggCd);
},
[rswtSttnSearch, code.cityCd, code.sggCd, codeCityOrSgg]
);
const excelClick = useCallback(() => {
// 최신 검색 조건 반영
const con = getConValue();
rswtSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd);
}, [rswtSttnSearch, objSearch, code.cityCd, code.sggCd]);
useEffect(() => {
if (codeCityOrSgg != null) rswtSttnSearch(pageNation, "20", codeCityOrSgg, code.cityCd, code.sggCd);
rswtSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd);
}, [pageNation]);
return (
@@ -113,38 +150,75 @@ export default function RswtSttn() {
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"중수도시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
} }
>
조회항목설정
</Button>}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
if (codeCityOrSgg)
rswtSttnSearch(1, "20", codeCityOrSgg, code.cityCd, code.sggCd);
} }
excelClick={excelClick}
initClick={function (): void { } }
btnClass={btnClass}
ref={ref} isAdmin={false} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl ml-4"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
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">
{"시설명"}
</Label>
<SearchInput
className={"w-full h-full text-2xl"}
label={""}
textValue={fcltNm || ""}
setText={setFcltNm}
/>
</div>
</div>
</SearchFormLeft>
<SearchFormRight
className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="flex flex-row space-x-2 items-center">
<Button
size={"sm"}
onClick={() => {
const con = getConValue();
rswtSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd);
}}
>
조회
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
onClick={excelClick}
>
다운로드
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
headName={undefined}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} />
@@ -26,10 +26,10 @@ export const headMakeprfmnc = (
key={head.id}
rowSpan={1}
colSpan={
makeHeadNm.find((ch) => ch.headNm === head.upName)?.length
makeHeadNm?.find((ch) => ch.headNm === head.upName)?.length
}
>
{makeHeadNm.find((ch) => ch.headNm === head.upName)?.text}
{makeHeadNm?.find((ch) => ch.headNm === head.upName)?.text}
</TableHead>
) : null
)}
@@ -39,7 +39,7 @@ export const headMakeprfmnc = (
{upHeadList
.filter((data) => data.visible != false)
.map((head: TableUpperProps) =>
makeHeadNm.find((ch) => ch.headNm === head.upName) ? (
makeHeadNm?.find((ch) => ch.headNm === head.upName) ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
@@ -1,10 +1,14 @@
"use client";
import { useWrStore } from "@/app/store";
import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type {
rswtChkZodType,
rswtrChkDetailsZodType,
import {
commonCd,
rainPageSize,
type rainChkZodType,
} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import {
rswtPageSize,
type rswtrChkDetailsZodType,
} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import {
excelArrayDownload,
@@ -15,23 +19,27 @@ import ChkgdExcel from "@/components/ui/modal/chkgd/chkgdExcel/chkgdExcel";
import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal";
import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable";
import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable";
import { SearchInput } from "@common/business_components";
import {
ContentsDiv,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label } from "@common/components/ui";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@common/components/ui/tooltip";
import { useCallback, useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
import { shallow } from "zustand/shallow";
import toast, { Toaster } from "react-hot-toast";
//-----------------------
export default function Page() {
const {
code,
@@ -42,9 +50,10 @@ export default function Page() {
rainChkDelete,
rainChkExcelDownload,
rainChkHeadChange,
rainChkNmSearch,
isRainSttn,
rswtChkgdnInit,
rswtChkNmSearch,
rswtChkPolInit,
rswtChkDetilsUpdate,
rswtChkDelete,
@@ -61,39 +70,84 @@ export default function Page() {
rswtrChkDetailsZodType[]
>([]);
const [deleteIdx, setDeleteIdx] = useState<number[]>([]);
const [rainPageNation, setRainPageNation] = useState(1);
const [rswtPageNation, setRswtPageNation] = useState(1);
const [fcltNm, setFcltNm] = useState<string>("");
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
const [isModal, setIsModal] = useState({
open: false,
data: {},
});
const cellClick = () => {
if (searchYear)
if (selFcltDiv === "RNB") {
rainChkInit(searchYear, "0");
} else {
rswtChkgdnInit(searchYear, "0");
}
};
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const cellClick = () => {
if (searchYear)
if (selFcltDiv === "RNB") {
if (fcltNm) {
rainChkNmSearch(
rainPageNation,
rainPageSize,
searchYear,
commonCd,
fcltNm
);
} else {
rainChkInit(rainPageNation, rainPageSize, searchYear, commonCd);
}
} else {
if (fcltNm) {
rswtChkNmSearch(
rainPageNation,
rainPageSize,
searchYear,
commonCd,
fcltNm
);
} else {
rswtChkgdnInit(rswtPageNation, rswtPageSize, searchYear, commonCd);
}
}
};
const rainPageChange = (pageNo: number) => {
if (pageNo > 0) {
setRainPageNation(pageNo);
rainChkInit(pageNo, rainPageSize, searchYear, commonCd);
}
};
const rswtPageChange = (pageNo: number) => {
if (pageNo > 0) {
setRswtPageNation(pageNo);
rswtChkgdnInit(pageNo, rswtPageSize, searchYear, commonCd);
}
};
useEffect(() => {
if (!rainChkgdn.isInit) {
rainChkInit(new Date().getFullYear().toString(), "0");
rainChkInit(
1,
rainPageSize,
new Date().getFullYear().toString(),
commonCd
);
isRainSttn(false);
setIsModal({ data: {}, open: false });
setIsRegExcel(false);
}
}, [rainChkgdn.isInit, rainChkInit, rainPageSize]);
useEffect(() => {
if (!rswtChkgdn.isInit) {
rswtChkgdnInit(new Date().getFullYear().toString(), "0");
rswtChkgdnInit(
1,
rswtPageSize,
new Date().getFullYear().toString(),
commonCd
);
setIsModal({ data: {}, open: false });
setIsRegExcel(false);
}
}, [rainChkgdn.isInit, rainChkInit]);
}, [rswtChkgdn.isInit, rswtChkgdnInit, rswtPageSize]);
useEffect(() => {
if (rswtChkgdn.excelList[0] && rswtChkgdn.excelList[0]?.data.length > 1) {
@@ -156,9 +210,17 @@ export default function Page() {
};
const chkUpdateTable = (selFcltDiv: string) => {
if (selFcltDiv === "RNB") {
if (updateRainDetail && updateRainDetail.length > 0) {
rainChkDetilUpdate(updateRainDetail);
} else {
toast.error("수정을 원하는 행을 선택하고 저장버튼을 눌러주세요 ");
}
} else {
if (updateRswtDetail && updateRswtDetail.length > 0) {
rswtChkDetilsUpdate(updateRswtDetail);
} else {
toast.error("수정을 원하는 행을 선택하고 저장버튼을 눌러주세요 ");
}
}
};
@@ -179,9 +241,9 @@ export default function Page() {
selectClass={""}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
onSelectValue={(val: string | number) => {
setSearchYear(String(val));
}}
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
@@ -195,12 +257,22 @@ export default function Page() {
selectArray={rainChkgdn.fcltDiv}
onSelectValue={(val: string | number) => {
if (val === "RST") rswtChkPolInit();
setSelFcltDiv(String(val))
}
}
setSelFcltDiv(String(val));
}}
value={selFcltDiv ?? rainChkgdn.fcltDiv[0]?.val}
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
{"시설명"}
</Label>
<SearchInput
className={"w-full h-full text-2xl"}
label={""}
textValue={fcltNm || ""}
setText={setFcltNm}
/>
</div>
</SearchFormLeft>
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
<div className="space-y">
@@ -221,6 +293,10 @@ export default function Page() {
>
삭제
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size={"sm"}
onClick={() => {
@@ -229,6 +305,16 @@ export default function Page() {
>
저장
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" sideOffset={5}>
<h2 className="text-xl">
아래 테이블에 선택을 체크하면 입력셀이 활성화 됩니다.
</h2>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<Button
size={"sm"}
onClick={() => {
@@ -255,13 +341,18 @@ export default function Page() {
detailUp={setUpdateRainDetail}
handleClick={handleClick}
rainChkData={rainChkgdn.rainChk}
/>
pageNation={rainPageNation}
onPageChange={rainPageChange}
pageCount={rainChkgdn.rainChkCount} />
) : (
<RswtChkgdTable
detaiRswtlUpdate={setUpdateRSwtDetail}
deleteRswtData={setDeleteIdx}
handleRswtClick={handleClick}
rswtChkData={rswtChkgdn.rswtChkRes}
pageNation={rswtPageNation}
onPageChange={rswtPageChange}
pageCount={rswtChkgdn.rswtChkCount}
/>
)}
</ListDiv>
@@ -269,17 +360,28 @@ export default function Page() {
</div>
<UiModal
open={isModal.open}
onOpenChange={() => {
setIsModal({ open: !open, data: {} });
onOpenChange={(open: boolean) => {
setIsModal((prev) => ({ ...prev, open }));
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />}
body={
<ChkgdModal
type={selFcltDiv}
obj={isModal.data}
setIsModal={(open) => setIsModal((prev) => ({ ...prev, open }))}
/>
}
></UiModal>
<UiModal
open={isRegExcel}
onOpenChange={setIsRegExcel}
bodyClass={"w-[30vw] max-w-none"}
body={<ChkgdExcel type={selFcltDiv}></ChkgdExcel>}
body={
<ChkgdExcel
type={selFcltDiv}
setIsRegExcel={setIsRegExcel}
></ChkgdExcel>
}
/>
<Toaster position="top-center" />
</ContentsDiv>
@@ -25,7 +25,7 @@ import {
} from "@common/components/ui";
import { useState, useEffect, useCallback } from "react";
import { set } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import toast, { Toaster } from "react-hot-toast";
import { headMakeprfmnc } from "../chkgdnReg/TableHead";
import { InputTableBody } from "@/components/lib/func/TableData";
import {
@@ -37,6 +37,7 @@ import {
type PrfType,
} from "@/app/store/prfmncReg/pbnstPrfmncReg/type";
import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel";
import data from "@common/components/ui/icon-finder/data";
export default function prfmncPrfmncReg() {
const { code, prfmnc, prfmncHasuInit, prfmnRegData } = useWrStore(
@@ -51,11 +52,12 @@ export default function prfmncPrfmncReg() {
}>({ isModal: false, data: {} as FcPrfType });
const [inputData, setInputData] = useState<any[]>();
const [pbnstRuseFcltPk, setPbnstRuseFcltPk] = useState<string>();
const [pageNation , setPageNation] = useState<number>(1);
const [pageNation, setPageNation] = useState<number>(1);
const [cellNum, setCellNum] = useState<number>(1);
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const excelClick = useCallback(() => {
excelDownload(
[[]],
@@ -65,33 +67,43 @@ export default function prfmncPrfmncReg() {
);
}, [prfmnc.excelList]);
const onSave = useCallback(() => {
const onSave = useCallback(
async() => {
if (pbnstRuseFcltPk) {
prfmnRegData(
await prfmnRegData(pageNation,'41',
excelToPbnPrfData(
inputData as unknown as JSON[],
searchYear,
pbnstRuseFcltPk
) as unknown as PrfType
);
prfmncHasuInit(String(pageNation), "41");
// cellClick(cellNum)
}
}, [inputData, searchYear, pbnstRuseFcltPk,prfmncHasuInit,pageNation]);
}, [inputData, searchYear, pbnstRuseFcltPk, pageNation,cellNum]);
const cellClick = useCallback(
(index: number | undefined, headId: string) => {
(index: number | undefined) => {
if (index !== undefined) {
setIsExcelOPen({
isModal: false,
data: prfmncRes[index] || ({} as FcPrfType),
});
const inUsageData = structuredClone(initValInUsage);
const outUsageData = structuredClone(initValOutUsage);
const inSubtotal = structuredClone(subTotalObj);
const outSubtotal = structuredClone(subTotalObj);
const inUsageData = structuredClone(initValInUsage).map((row) => ({
...row,
구분: "장내용수",
}));
const outUsageData = structuredClone(initValOutUsage).map((row) => ({
...row,
구분: "장외용수",
}));
const inSubtotal = {
...structuredClone(subTotalObj),
구분: "장내용수",
};
const outSubtotal = {
...structuredClone(subTotalObj),
구분: "장외용수",
};
if (prfmncRes[index]?.prfList) {
prfmncRes[index].prfList?.forEach((prfItem) => {
const month = Number(prfItem?.ym?.slice(4)); // "MM"
@@ -127,7 +139,11 @@ export default function prfmncPrfmncReg() {
});
inUsageData.push(inSubtotal);
outUsageData.push(outSubtotal);
const usageTotalObj: { [key: string]: any } = structuredClone(totalObj);
const usageTotalObj: { [key: string]: any } = {
...structuredClone(totalObj),
구분: "총합계",
용수명: "",
};
for (const key in usageTotalObj) {
if (["usage", "gubun", "edit"].includes(key)) continue;
const val =
@@ -138,7 +154,6 @@ export default function prfmncPrfmncReg() {
}
const tableData = [...inUsageData, ...outUsageData, usageTotalObj];
setPbnstRuseFcltPk(prfmncRes[index].pbnstRuseFcltPk);
setInputData(tableData);
} else {
setInputData([]);
@@ -150,19 +165,24 @@ export default function prfmncPrfmncReg() {
useEffect(() => {
if (!prfmnc.isInit) {
prfmncHasuInit('1', "41");
prfmncHasuInit(1, "41");
}
}, [prfmnc.isInit, prfmncHasuInit]);
useEffect(() => {
setbdstTable(prfmncRes);
}, [prfmncRes]);
// cellNum이 0일 경우(첫 번째 행)도 유효한 인덱스이므로 undefined 여부만 체크합니다.
if (cellNum !== undefined) {
cellClick(cellNum);
}
}, [prfmncRes, cellNum, cellClick]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"하수재이용 시설 등록"} />
<Title title={"하수재이용 실적 등록"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-2 flex flex-row space-x-2">
@@ -211,7 +231,12 @@ export default function prfmncPrfmncReg() {
<Button
size={"sm"}
onClick={() => {
setIsExcelOPen({ ...isExcelOpen, isModal: true });
if (cellNum === undefined) {
toast.error("하수처리재이용시설을 선택해주세요.");
return;
} else {
setIsExcelOPen({ ...isExcelOpen, isModal: true });
}
}}
>
파일등록
@@ -231,13 +256,15 @@ export default function prfmncPrfmncReg() {
<ListDiv className="min-h-0">
<ScrollArea className="h-[60vh]">
<UiTable
key={'leftTable'}
tableData={bdstTable || []}
headlist={pbnstPrfmncHeadList}
pageSize={10}
total={10000}
headName={"하수재이용시설 목록"}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index, headId);
cellClick(index);
setCellNum(index ?? 0);
}}
onPageChange={setPageNation}
children={undefined}
@@ -257,7 +284,7 @@ export default function prfmncPrfmncReg() {
<TableHeader className="font-bold">
{headMakeprfmnc(monthHeadList, [])}
</TableHeader>
<TableBody>
<TableBody key={prfmnc.pageKey+'pageKey'}>
{InputTableBody(inputData ?? [], monthHeadList, setInputData)}
</TableBody>
</Table>
@@ -266,8 +293,23 @@ export default function prfmncPrfmncReg() {
</div>
</ContentsDiv>
<UiModal
bodyClass={""}
body={<PbnPrfExcelModal data={isExcelOpen.data}></PbnPrfExcelModal>}
bodyClass={"w-[30vw] max-w-none"}
body={
<PbnPrfExcelModal
data={isExcelOpen.data}
setIsExcelOPen={(open) => {
setIsExcelOPen({ ...isExcelOpen, isModal: open })
}}
setModalExcelData={ async(excelData ) =>{
await prfmnRegData(pageNation,'41',
excelData,
);
// 데이터 저장 후 UI 업데이트는 useEffect가 감지하여 처리하므로 여기서는 호출하지 않습니다.
}
}
></PbnPrfExcelModal>
}
open={isExcelOpen.isModal}
onOpenChange={() => {
setIsExcelOPen({ isModal: false, data: {} as FcPrfType });
@@ -1,6 +1,8 @@
"use client";
import { useWrStore } from "@/app/store";
import { commonCd, rainPageSize } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { rswtPageSize } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import {
excelDownload,
yearOptions
@@ -13,6 +15,7 @@ import {
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal
@@ -28,9 +31,9 @@ export default function Page() {
rainChkSttn,
rswtChkSttn,
rainChkSttnInit,
rainChkSttnSearch,
rswtChkSttnSearch,
rainChkSttnNmSearch,
rswtChkSttnInit,
rswtChkNmSttnSearch,
isRainSttn,
isRswtSttn,
rswtChkPolInit,
@@ -39,6 +42,9 @@ export default function Page() {
});
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
const [rainPageNation, setRainPageNation] = useState(1);
const [rswtPageNation, setRswtPageNation] = useState(1);
const [fcltNm, setFcltNm] = useState<string>("");
const [isModal, setIsModal] = useState({
open: false,
data: {},
@@ -47,29 +53,64 @@ export default function Page() {
const cellClick = () => {
if (searchYear) {
if (selFcltDiv === "RNB") {
rainChkSttnSearch(searchYear, "0");
if (fcltNm) {
rainChkSttnNmSearch(
rainPageNation,
rainPageSize,
searchYear,
commonCd,
fcltNm
);
} else {
rainChkSttnInit(rainPageNation, rainPageSize, searchYear, commonCd);
}
} else {
rswtChkSttnSearch(searchYear, "0");
if (fcltNm) {
rswtChkNmSttnSearch(
rswtPageNation,
rswtPageSize,
searchYear,
commonCd,
fcltNm
);
} else {
rswtChkSttnInit(rswtPageNation, rswtPageSize, searchYear, commonCd);
}
}
}
};
const rainPageChange = (pageNo: number) => {
if (pageNo > 0) {
setRainPageNation(pageNo);
rainChkSttnInit(pageNo, rainPageSize, searchYear, commonCd);
}
};
const rswtPageChange = (pageNo: number) => {
if (pageNo > 0) {
setRswtPageNation(pageNo);
rswtChkSttnInit(pageNo, rswtPageSize, searchYear, commonCd);
}
};
useEffect(() => {
if (!rainChkSttn.isInit) {
isRainSttn(true)
rainChkSttnInit(new Date().getFullYear().toString(), "0");
console.log("여기", rainPageSize)
rainChkSttnInit(1, rainPageSize, new Date().getFullYear().toString(), commonCd);
setIsModal({ data: {}, open: false });
}
}, [rainChkSttn.isInit, rainChkSttnInit]);
}, [rainChkSttn.isInit, rainChkSttnInit, rainPageSize]);
useEffect(() => {
if (!rswtChkSttn.isInit) {
setIsModal({ data: {}, open: false });
rswtChkSttnInit(new Date().getFullYear().toString(), "0");
rswtChkSttnInit(1, rswtPageSize, new Date().getFullYear().toString(), commonCd);
isRswtSttn(true)
}
}, [rswtChkSttn.isInit, rswtChkSttnInit])
}, [rswtChkSttn.isInit, rswtChkSttnInit, rswtPageSize])
const handleClick = useCallback(
@@ -133,6 +174,17 @@ export default function Page() {
value={selFcltDiv ?? rainChkSttn.fcltDiv[0]?.val}
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
{"시설명"}
</Label>
<SearchInput
className={"w-full text-2xl"}
label={""}
textValue={fcltNm || ""}
setText={setFcltNm}
/>
</div>
</SearchFormLeft>
<SearchFormRight>
<div className="space-y">
@@ -163,6 +215,9 @@ export default function Page() {
detailUp={() => { }}
handleClick={handleClick}
rainChkData={rainChkSttn.rainChkRes}
pageNation={rainPageNation}
onPageChange={rainPageChange}
pageCount={rainChkSttn.rainChkCount}
/>
) : (
<RswtChkgdTable
@@ -170,6 +225,9 @@ export default function Page() {
deleteRswtData={() => { }}
handleRswtClick={handleClick}
rswtChkData={rswtChkSttn.rswtChkRes}
pageNation={rswtPageNation}
onPageChange={rswtPageChange}
pageCount={rswtChkSttn.rswtChkCount}
/>
)}
</ListDiv>
@@ -181,7 +239,7 @@ export default function Page() {
setIsModal({ open: !open, data: {} });
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />}
body={<ChkgdModal type={selFcltDiv} obj={isModal.data} setIsModal={() => { }} />}
></UiModal>
<Toaster position="top-center" />
</ContentsDiv>
@@ -8,9 +8,11 @@ import { excelDownload, yearOptions } from "@/components/lib/func/commom";
import SearchInputText from "@/components/ui/searchInput/searchInput";
import { CHART_FORM, ContentsDiv, MainChart, ScrollArea, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ChartConfig, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label } from "@common/components/ui";
import { Button, Label, Table, TableBody, TableHeader } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import toast, { Toaster } from "react-hot-toast";
import { headMakeprfmnc } from "../../prfmncReg/chkgdnReg/TableHead";
import { InputTableBody } from "@/components/lib/func/TableData";
export default function PbnstPrfmncSttn() {
const {
@@ -34,9 +36,9 @@ export default function PbnstPrfmncSttn() {
const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>();
const [pbnRuseNm, setPbnRuseNm] = useState<string>("");
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [excelData, setExcelData] = useState<any[]>([]);
const excelClick = useCallback(() => {
excelDownload(
@@ -83,15 +85,20 @@ export default function PbnstPrfmncSttn() {
type lineChartDataProps = { label: string, val: number, color: string };
const prfTableData = (prfList: PrfType[], year: string) => {
const inUsageData = structuredClone(initValInUsage);
const outUsageData = structuredClone(initValOutUsage);
const inSubtotal = structuredClone(subTotalObj);
const outSubtotal = structuredClone(subTotalObj);
const inUsageData = structuredClone(initValInUsage).map(row => ({
...row,
구분: "장내용수",
}));
const outUsageData = structuredClone(initValOutUsage).map(row => ({
...row,
구분: "장외용수",
}));
const inSubtotal = { ...structuredClone(subTotalObj), 구분: "장내용수" };
const outSubtotal = { ...structuredClone(subTotalObj), 구분: "장외용수" };
const prfFilter = prfList?.filter((e) => e.ym.slice(0, 4) === year)
if (prfList && prfFilter.length > 0) {
prfList?.forEach((prfItem) => {
const month = Number(prfItem?.ym?.slice(4)); // "MM"
const monthKey = `${month}월`;
@@ -142,7 +149,7 @@ export default function PbnstPrfmncSttn() {
setPrfData([]);
}
}
const [chartId, setChartId] = useState<string>();
useEffect(() => {
// 누적 변수 초기화
@@ -198,8 +205,8 @@ export default function PbnstPrfmncSttn() {
prfTableData([], year)
rawData.forEach((item) => {
// 실적 테이블 데이터
if (chartId){
if(item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltFk === chartId){
if (chartId) {
if (item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltFk === chartId) {
prfTableData(item.prfList, year);
}
item.prfList.filter((e) => e.ym.slice(0, 4) === year && e.pbnstRuseFcltFk === chartId).forEach((element) => {
@@ -265,40 +272,40 @@ export default function PbnstPrfmncSttn() {
});
// 도넛차트 데이터
dnData.push({ label: "세척수", val: wshwtr, fill: "red" });
dnData.push({ label: "냉각수", val: coolUswtr, fill: "orange" });
dnData.push({ label: "청소수", val: cleanUswtr, fill: "yellow" });
dnData.push({ label: "식수대", val: drwtUswtr, fill: "green" });
dnData.push({ label: "희석용수", val: dltnUswtr, fill: "skyblue" });
dnData.push({ label: "중수도", val: ithlRswtr, fill: "blue" });
dnData.push({ label: "기타", val: ithlEtcUswtr, fill: "purple" });
dnData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "red" });
dnData.push({ label: "세척살수용수", val: resn, fill: "orange" });
dnData.push({ label: "조경용수", val: lndwtr, fill: "yellow" });
dnData.push({ label: "친수용수", val: hydUswtr, fill: "green" });
dnData.push({ label: "지하수충전", val: ugwtChr, fill: "skyblue" });
dnData.push({ label: "농업용수", val: farmUswtr, fill: "blue" });
dnData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "purple" });
dnData.push({ label: "공업용수", val: indstUswtr, fill: "black" });
dnData.push({ label: "세척수", val: wshwtr, fill: "#F7CFD8" });
dnData.push({ label: "냉각수", val: coolUswtr, fill: "#F4F8D3" });
dnData.push({ label: "청소수", val: cleanUswtr, fill: "#A6D6D6" });
dnData.push({ label: "식수대", val: drwtUswtr, fill: "#8E7DBE" });
dnData.push({ label: "희석용수", val: dltnUswtr, fill: "#FF8383" });
dnData.push({ label: "중수도", val: ithlRswtr, fill: "#FFF574" });
dnData.push({ label: "기타", val: ithlEtcUswtr, fill: "#A1D6CB" });
dnData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "#A19AD3" });
dnData.push({ label: "세척살수용수", val: resn, fill: "#B1F0F7" });
dnData.push({ label: "조경용수", val: lndwtr, fill: "#81BFDA" });
dnData.push({ label: "친수용수", val: hydUswtr, fill: "#F5F0CD" });
dnData.push({ label: "지하수충전", val: ugwtChr, fill: "#FADA7A" });
dnData.push({ label: "농업용수", val: farmUswtr, fill: "#A6AEBF" });
dnData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "#C5D3E8" });
dnData.push({ label: "공업용수", val: indstUswtr, fill: "#D0E8C5" });
// 장내용수 도넛
dnInData.push({ label: "세척수", val: wshwtr, fill: "yellow" });
dnInData.push({ label: "냉각수", val: coolUswtr, fill: "green" });
dnInData.push({ label: "청소수", val: cleanUswtr, fill: "yellow" });
dnInData.push({ label: "식수대", val: drwtUswtr, fill: "green" });
dnInData.push({ label: "희석용수", val: dltnUswtr, fill: "yellow" });
dnInData.push({ label: "중수도", val: ithlRswtr, fill: "green" });
dnInData.push({ label: "기타", val: ithlEtcUswtr, fill: "yellow" });
dnInData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "green" });
dnInData.push({ label: "세척살수용수", val: resn, fill: "yellow" });
dnInData.push({ label: "세척수", val: wshwtr, fill: "#F7CFD8" });
dnInData.push({ label: "냉각수", val: coolUswtr, fill: "#F4F8D3" });
dnInData.push({ label: "청소수", val: cleanUswtr, fill: "#A6D6D6" });
dnInData.push({ label: "식수대", val: drwtUswtr, fill: "#8E7DBE" });
dnInData.push({ label: "희석용수", val: dltnUswtr, fill: "#FF8383" });
dnInData.push({ label: "중수도", val: ithlRswtr, fill: "#FFF574" });
dnInData.push({ label: "기타", val: ithlEtcUswtr, fill: "#A1D6CB" });
dnInData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "#A19AD3" });
dnInData.push({ label: "세척살수용수", val: resn, fill: "#B1F0F7" });
// 장외용수 도넛
dnOutData.push({ label: "조경용수", val: lndwtr, fill: "yellow" });
dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "black" });
dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "yellow" });
dnOutData.push({ label: "농업용수", val: farmUswtr, fill: "black" });
dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "yellow" });
dnOutData.push({ label: "공업용수", val: indstUswtr, fill: "black" });
dnOutData.push({ label: "조경용수", val: lndwtr, fill: "#81BFDA" });
dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "#F5F0CD" });
dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "#FADA7A" });
dnOutData.push({ label: "농업용수", val: farmUswtr, fill: "#A6AEBF" });
dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "#C5D3E8" });
dnOutData.push({ label: "공업용수", val: indstUswtr, fill: "#D0E8C5" });
// 라인차트 데이터
setInLineData({
@@ -466,7 +473,7 @@ export default function PbnstPrfmncSttn() {
useEffect(() => {
setbdstTable(prfmncRes);
if(prfmncRes?.[0]?.pbnstRuseFcltPk) setChartId(prfmncRes[0].pbnstRuseFcltPk)
if (prfmncRes?.[0]?.pbnstRuseFcltPk) setChartId(prfmncRes[0].pbnstRuseFcltPk)
}, [prfmncRes]);
@@ -619,12 +626,12 @@ export default function PbnstPrfmncSttn() {
</div>
<h1 className="">하수재이용실적 현황</h1>
<ListDiv className="col-span-8 pr-6 ">
<ScrollArea className="h-[60vh]">
<div className="card-header">
{/* <ScrollArea className="h-[60vh]"> */}
{/* <div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m3) 등록결과"}
</h3>
</div>
</div> */}
<UiTable
headName={undefined}
@@ -637,7 +644,26 @@ export default function PbnstPrfmncSttn() {
throw new Error("Function not implemented.");
}}>
</UiTable>
</ScrollArea>
{/* <ListDiv className="col-span-8 pr-6 ">
<ScrollArea className="h-[60vh]">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m3) 등록결과"}
</h3>
</div>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(monthHeadList, [])}
</TableHeader>
<TableBody>
{InputTableBody(prfData ?? [], monthHeadList, setPrfData)}
</TableBody>
</Table>
</ScrollArea>
</ListDiv> */}
{/* </ScrollArea> */}
</ListDiv>
</ListDiv>
+2 -1
View File
@@ -210,8 +210,9 @@ export default function RainStat() {
...item,
ctpvCd: item.cityText
};
})
}).filter((item: RainStatProps) => item.cityText !== '없음')
: [];
setBdstTable(tbData);
}, [code, rainStatList]);
+1 -1
View File
@@ -46,7 +46,7 @@ export default function RswtStat() {
...item,
ctpvCd: item.cityText
};
})
}).filter((item: RswtStatProps) => item.cityText !== '없음')
: [];
setRswtTable(tbData);
}, [code, rswtStatList])
+204
View File
@@ -0,0 +1,204 @@
import type { SelectDataType } from "@common/business_components";
export const yn: SelectDataType[] = [
{ val: "Y", text: "Y" },
{ val: "N", text: "N" },
];
export const bdstFilterYn: SelectDataType[] = [
{ val: "Y", text: "Y" },
{ val: "N", text: "N" },
{ val: "D", text: "확인불가" },
{ val: "F", text: "미가동" },
];
// 최우수(그린1)/우수(그린2), 우량(그린3), 일반(그린4), 확인불가 체크
export const bdstGrntchClass: SelectDataType[] = [
{ val: "최우수(그린1)", text: "최우수(그린1)" },
{ val: "우수(그린2)", text: "우수(그린2)" },
{ val: "우량(그린3)", text: "우량(그린3)" },
{ val: "일반(그린4)", text: "일반(그린4)" },
{ val: "확인불가", text: "확인불가" },
];
export const bdstIncenYn: SelectDataType[] = [
{ val: "Y", text: "Y" },
{ val: "N", text: "N" },
{ val: "D", text: "확인불가" },
];
//처리장연계/자체+연계/자체처리
export const erctUswtrPrcsMeth: SelectDataType[] = [
{ val: "처리장연계", text: "처리장연계" },
{ val: "자체+연계", text: "자체+연계" },
{ val: "자체처리", text: "자체처리" },
];
export const rusePrcsMthdCd: SelectDataType[] = [
{ val: "물리학적처리", text: "물리학적처리" },
{ val: "생물학적처리", text: "생물학적처리" },
];
export const ruseSeCd: SelectDataType[] = [
{ val: "신규", text: "신규" },
{ val: "증설", text: "증설" },
{ val: "관로", text: "관로" },
{ val: "감량", text: "감량" },
{ val: "개량", text: "개량" },
];
export const ruseBizMthdCd: SelectDataType[] = [
{ val: "재정", text: "재정" },
{ val: "민간투자", text: "민간투자" },
{ val: "자체", text: "자체" },
];
//공통 건축물 용도
export const bdstUsgCd: SelectDataType[] = [
{ val: "-1", text: "확인불가" },
{ val: "1", text: "운동장" },
{ val: "2", text: "체육관" },
{ val: "3", text: "공공업무시설" },
{ val: "4", text: "공공기관의청사" },
{ val: "5", text: "아파트" },
{ val: "6", text: "연립주택" },
{ val: "7", text: "다세대주택" },
{ val: "8", text: "기숙사" },
{ val: "9", text: "초등학교" },
{ val: "10", text: "중학교" },
{ val: "11", text: "고등학교" },
{ val: "12", text: "전문대학" },
{ val: "13", text: "대학및대학교" },
{ val: "14", text: "골프장" },
{ val: "15", text: "대규모점포" },
{ val: "16", text: "기타" },
];
export const rswtBdstType: SelectDataType[] = [
{ text: "숙박업", val: "17" },
{ text: "목욕장업", val: "18" },
{ text: "공장", val: "19" },
{ text: "발전시설", val: "20" },
{ text: "관광단지개발사업", val: "21" },
{ text: "도시개발사업", val: "22" },
{ text: "산업단지개발사업", val: "23" },
{ text: "택지개발사업", val: "24" },
{ text: "대규모점포(대형마트)", val: "25" },
{ text: "대규모점포(전문점)", val: "26" },
{ text: "대규모점포(백화점)", val: "27" },
{ text: "대규모점포(쇼핑센터)", val: "28" },
{ text: "대규모점포(복합쇼핑몰)", val: "29" },
{ text: "물류시설", val: "30" },
{ text: "운수시설(여객자동차터미널)", val: "31" },
{ text: "운수시설(철도시설)", val: "32" },
{ text: "운수시설(공항시설)", val: "33" },
{ text: "운수시설(항만시설)", val: "34" },
{ text: "업무시설(공공업무시설)", val: "35" },
{ text: "업무시설(금융업소)", val: "36" },
{ text: "업무시설(사무소)", val: "37" },
{ text: "업무시설(결혼상담소 등 소개업소)", val: "38" },
{ text: "업무시설(출판사)", val: "39" },
{ text: "업무시설(신문사)", val: "40" },
{ text: "업무시설(오피스텔)", val: "41" },
{ text: "교정시설", val: "42" },
{ text: "방송국", val: "43" },
{ text: "전신전화국", val: "44" },
{ text: "기타", val: "45" },
];
export const orgwtKndCd = [
{ text: "오수(변기 오수 제외)", val: "1" },
{ text: "오수", val: "2" },
{ text: "폐수", val: "3" },
{ text: "오수 및 폐수", val: "4" },
{ text: "기타", val: "5" },
];
export const chBuCd = [
{ val: "증축", text: "증축" },
{ val: "개축", text: "개축" },
{ val: "재축", text: "재축" },
];
export const dmdUszCd = [
{ val: "조경용수", text: "조경용수" },
{ val: "청소화장실용수", text: "청소화장실용수" },
{ val: "농업용수", text: "농업용수" },
{ val: "공업용수", text: "공업용수" },
{ val: "친수용수", text: "친수용수" },
{ val: "기타", text: "기타" },
];
export const ruseMngMtd = [
{ val: "자체운영", text: "자체운영" },
{ val: "공기업", text: "공기업" },
{ val: "민간(대행)", text: "민간(대행)" },
];
export const pplQulity = [
{ val: "도복장강관", text: "도복장강관" },
{ val: "PE관", text: "PE관" },
{ val: "스테인레스관", text: "스테인레스관" },
{ val: "덕타일주철관", text: "덕타일주철관" },
{ val: "유리섬유복합관", text: "유리섬유복합관" },
{ val: "기타", text: "기타" },
];
export const pplLenght = [
{ val: "D100", text: "D100" },
{ val: "D200", text: "D200" },
{ val: "D250", text: "D250" },
{ val: "D300", text: "D300" },
{ val: "D350", text: "D350" },
{ val: "D400", text: "D400" },
{ val: "D450", text: "D450" },
{ val: "D500", text: "D500" },
{ val: "D700", text: "D700" },
{ val: "D900", text: "D900" },
{ val: "D1000​", text: "D1000​" },
];
export const rainFcltCd = [
{ val: "지붕", text: "지붕" },
{ val: "건물옥상", text: "건물옥상" },
{ val: "골프장 연못", text: "골프장 연못" },
{ val: "운동장 바닥", text: "운동장 바닥" },
{ val: "운동장 지붕", text: "운동장 지붕" },
{ val: "주차장", text: "주차장" },
{ val: "태양광패널", text: "태양광패널" },
{ val: "연못", text: "연못" },
{ val: "기타", text: "기타" },
{ val: "확인불가", text: "확인불가" },
];
//물리화학적처리(스크린, 응집, 침전)/생물학적처리(활성슬러지법 등)/소독(염소, UV 등)/기타
export const rswtPrscCdMthdCd = [
{
val: "물리화학적처리(스크린,응집,침전)",
text: "물리화학적처리(스크린,응집,침전)",
},
{
val: "생물학적처리(활성슬러지법 등)",
text: "생물학적처리(활성슬러지법 등)",
},
{ val: "소독(염소, UV 등)", text: "소독(염소, UV 등)" },
{ val: "기타", text: "기타" },
];
export const htdPowerMthdCd= [
{
val: "석탄화력발전",
text: "석탄화력발전",
},
];
//(공업용수/양식장/농업용수)
export const htdUtztnUsgCd= [
{
val: "공업용수",
text: "공업용수",
},
{
val: "양식장",
text: "양식장",
},
{
val: "농업용수",
text: "농업용수",
},
];
+50 -207
View File
@@ -1,214 +1,13 @@
import { getFetch } from "@/components/lib/api";
import type { EnvPartSelectDataType, SelectDataType } from "@common/business_components/ui";
import { bdstFilterYn, bdstGrntchClass, bdstIncenYn, bdstUsgCd, chBuCd, dmdUszCd, erctUswtrPrcsMeth, htdPowerMthdCd, htdUtztnUsgCd, orgwtKndCd, pplLenght, pplQulity, rainFcltCd, rswtPrscCdMthdCd, ruseBizMthdCd, ruseMngMtd, rusePrcsMthdCd, ruseSeCd, yn } from "./basicCode";
export const btnClass = "p-4 m-2 text-white rounded-sm text-lg font-medium "
const yn: SelectDataType[] = [
{ val: 'Y', text: 'Y' },
{ val: 'N', text: 'N' },
]
//처리장연계/자체+연계/자체처리
const erctUswtrPrcsMeth : SelectDataType[]= [
{ val: '처리장연계', text: '처리장연계' },
{ val: '자체+연계', text: '자체+연계' },
{ val: '자체처리', text: '자체처리' },
]
const rusePrcsMthdCd : SelectDataType[] = [
{ val: '물리학적처리', text: '물리학적처리' },
{ val: '생물학적처리', text: '생물학적처리' },
]
const ruseSeCd : SelectDataType[] = [
{ val: '신규', text: '신규' },
{ val: '증설', text: '증설' },
{ val: '관로', text: '관로' },
{ val: '감량', text: '감량' },
{ val: '개량', text: '개량' },
]
const ruseBizMthdCd: SelectDataType[] = [
{ val: '재정', text: '재정' },
{ val: '민간투자', text: '민간투자' },
{ val: '자체', text: '자체' },
]
//공통 건축물 용도
const bdstUsgCd: SelectDataType[] = [
{ val: '-1', text: "확인불가" },
{ val: '1', text: "운동장" },
{ val: '2', text: "체육관" },
{ val: '3', text: "공공업무시설" },
{ val: '4', text: "공공기관의청사" },
{ val: '5', text: "아파트" },
{ val: '6', text: "연립주택" },
{ val: '7', text: "다세대주택" },
{ val: '8', text: "기숙사" },
{ val: '9', text: "초등학교" },
{ val: '10', text: "중학교" },
{ val: '11', text: "고등학교" },
{ val: '12', text: "전문대학" },
{ val: '13', text: "대학및대학교" },
{ val: '14', text: "골프장" },
{ val: '15', text: "대규모점포" },
{ val: '16', text: "기타" },
];
//빗물 집수면 종류 용도
// const rainFcltCd = [
// { val: "1", text: "지붕" },
// { val: "2", text: "건물옥상" },
// { val: "3", text: "골프장 연못" },
// { val: "4", text: "운동장 바닥" },
// { val: "5", text: "운동장 지붕" },
// { val: "6", text: "주차장" },
// { val: "7", text: "태양광패널" },
// { val: "8", text: "연못" },
// { val: "9", text: "기타" },
// { val: "10", text: "확인불가" },
// ];
// 중수도 필수 원수종류
const rswtBdstType: SelectDataType[] = [
{ text: "숙박업", val: "17" },
{ text: "목욕장업", val: "18" },
{ text: "공장", val: "19" },
{ text: "발전시설", val: "20" },
{ text: "관광단지개발사업", val: "21" },
{ text: "도시개발사업", val: "22" },
{ text: "산업단지개발사업", val: "23" },
{ text: "택지개발사업", val: "24" },
{ text: "대규모점포(대형마트)", val: "25" },
{ text: "대규모점포(전문점)", val: "26" },
{ text: "대규모점포(백화점)", val: "27" },
{ text: "대규모점포(쇼핑센터)", val: "28" },
{ text: "대규모점포(복합쇼핑몰)", val: "29" },
{ text: "물류시설", val: "30" },
{ text: "운수시설(여객자동차터미널)", val: "31" },
{ text: "운수시설(철도시설)", val: "32" },
{ text: "운수시설(공항시설)", val: "33" },
{ text: "운수시설(항만시설)", val: "34" },
{ text: "업무시설(공공업무시설)", val: "35" },
{ text: "업무시설(금융업소)", val: "36" },
{ text: "업무시설(사무소)", val: "37" },
{ text: "업무시설(결혼상담소 등 소개업소)", val: "38" },
{ text: "업무시설(출판사)", val: "39" },
{ text: "업무시설(신문사)", val: "40" },
{ text: "업무시설(오피스텔)", val: "41" },
{ text: "교정시설", val: "42" },
{ text: "방송국", val: "43" },
{ text: "전신전화국", val: "44" },
{ text: "기타", val: "45" }
];
const orgwtKndCd = [
{ text: "오수(변기 오수 제외)", val: "1" },
{ text: "오수", val: "2" },
{ text: "폐수", val: "3" },
{ text: "오수 및 폐수", val: "4" },
{ text: "기타", val: "5" },
];
const chBuCd = [
{ val: "증축", text: "증축" },
{ val: "개축", text: "개축" },
{ val: "재축", text: "재축" },
]
const dmdUszCd = [
{ val: "조경용수", text: "조경용수" },
{ val: "청소화장실용수", text: "청소화장실용수" },
{ val: "농업용수", text: "농업용수" },
{ val: "공업용수", text: "공업용수" },
{ val: "친수용수", text: "친수용수" },
{ val: "기타", text: "기타" },
]
const ruseMngMtd = [
{ val: "자체운영", text: "자체운영" },
{ val: "공기업", text: "공기업" },
{ val: "민간(대행)", text: "민간(대행)" },
]
const pplQulity = [
{ val: "도복장강관", text: "도복장강관" },
{ val: "PE관", text: "PE관" },
{ val: "스테인레스관", text: "스테인레스관" },
{ val: "덕타일주철관", text: "덕타일주철관" },
{ val: "유리섬유복합관", text: "유리섬유복합관" },
{ val: "기타", text: "기타" },
]
const pplLenght = [
{ val: "D100", text: "D100" },
{ val: "D200", text: "D200" },
{ val: "D250", text: "D250" },
{ val: "D300", text: "D300" },
{ val: "D350", text: "D350" },
{ val: "D400", text: "D400" },
{ val: "D450", text: "D450" },
{ val: "D500", text: "D500" },
{ val: "D700", text: "D700" },
{ val: "D900", text: "D900" },
{ val: "D1000​", text: "D1000​" },
]
export const buildingType = {
RST:"RST",
RNB:"RNB",
HTB:"HTB"
}
const rainFcltCd = [
{ val: "지붕", text: "지붕" },
{ val: "건물옥상", text: "건물옥상" },
{ val: "골프장 연못", text: "골프장 연못" },
{ val: "운동장 바닥", text: "운동장 바닥" },
{ val: "운동장 지붕", text: "운동장 지붕" },
{ val: "주차장", text: "주차장" },
{ val: "태양광패널", text: "태양광패널" },
{ val: "연못", text: "연못" },
{ val: "기타", text: "기타" },
{ val: "확인불가", text: "확인불가" },
];
export type comCodeState = {
code: {
isInit: boolean;
chBuCd: SelectDataType[]
rainFcltCd: SelectDataType[];
bdstUsgCd: SelectDataType[];
cityCd: SelectDataType[];
sggCd: SelectDataType[];
rvbsnCd: SelectDataType[];
mdmbsnCd: SelectDataType[];
lgbsnCd: SelectDataType[];
lclgvrnmntCd: EnvPartSelectDataType[];
orgwtKndCd: SelectDataType[];
yn: SelectDataType[];
pplQulity: SelectDataType[];
pplLenght: SelectDataType[];
dmdUszCd:SelectDataType[]
buildingType: {
RST:string,
RNB:string,
HTB:string
}
ruseMngMtd:SelectDataType[]
ruseSeCd: SelectDataType[];
ruseBizMthdCd: SelectDataType[];
rusePrcsMthdCd: SelectDataType[];
erctUswtrPrcsMeth: SelectDataType[];
};
};
export type comCodeType = comCodeState & comCodeActions;
export const getSggCd = async (set: any) => {
const sgg = await getFetch("common", "/addr/sgg");
/* const sggCd = sgg.map((item: any) => ({
@@ -217,7 +16,7 @@ export const getSggCd = async (set: any) => {
})); */
const sggCd = [
{ text: "전체", val: '0' },
// { text: "전체", val: '0' },
...sgg
.map((item: any) => ({
text: item.gugun || '',
@@ -334,6 +133,47 @@ export const getEnvPartCd = async (set: any) => {
export type comCodeState = {
code: {
isInit: boolean;
chBuCd: SelectDataType[]
rainFcltCd: SelectDataType[];
bdstUsgCd: SelectDataType[];
cityCd: SelectDataType[];
sggCd: SelectDataType[];
rvbsnCd: SelectDataType[];
mdmbsnCd: SelectDataType[];
lgbsnCd: SelectDataType[];
lclgvrnmntCd: EnvPartSelectDataType[];
orgwtKndCd: SelectDataType[];
yn: SelectDataType[];
pplQulity: SelectDataType[];
pplLenght: SelectDataType[];
dmdUszCd:SelectDataType[]
buildingType: {
RST:string,
RNB:string,
HTB:string
}
ruseMngMtd:SelectDataType[]
ruseSeCd: SelectDataType[];
ruseBizMthdCd: SelectDataType[];
rusePrcsMthdCd: SelectDataType[];
erctUswtrPrcsMeth: SelectDataType[];
bdstFilterYn: SelectDataType[];
bdstIncenYn: SelectDataType[];
bdstGrntchClass:SelectDataType[];
rswtPrscCdMthdCd:SelectDataType[];
htdPowerMthdCd:SelectDataType[]
htdUtztnUsgCd:SelectDataType[]
};
};
export type comCodeType = comCodeState & comCodeActions;
export const comCodeStateExport: comCodeState = {
code: {
isInit: false,
@@ -356,7 +196,13 @@ export const comCodeStateExport: comCodeState = {
ruseSeCd:ruseSeCd,
ruseBizMthdCd: ruseBizMthdCd,
rusePrcsMthdCd:rusePrcsMthdCd,
erctUswtrPrcsMeth:erctUswtrPrcsMeth
erctUswtrPrcsMeth:erctUswtrPrcsMeth,
bdstFilterYn:bdstFilterYn,
bdstIncenYn:bdstIncenYn,
bdstGrntchClass:bdstGrntchClass,
rswtPrscCdMthdCd:rswtPrscCdMthdCd,
htdPowerMthdCd:htdPowerMthdCd,
htdUtztnUsgCd:htdUtztnUsgCd,
},
};
@@ -364,9 +210,6 @@ export type comCodeActions = {
codeInit: () => void;
};
export const codeActionExport: (set: any) => comCodeActions = (set: any) => {
return {
codeInit: async () => {
+12 -8
View File
@@ -70,6 +70,7 @@ export type comFcltState = {
export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
return {
getSwtrmtFcltNm: async (searchNm: string) => {
const fcltNm = await getFetch(
"common",
`/prcsFclt/info/1/11/${searchNm}`
@@ -94,10 +95,13 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
`/reuseFc/request/${searchNm}/${cnt}`
);
console.log(coList);
set((state: comFcltState) => {
return (state.demandCompList = [...coList]);
});
if(coList&&coList.length>0){
set((state: comFcltState) => {
return (state.demandCompList = [...coList]);
});
}
},
regDemandCompany: async (data: DemandCompType) => {
try {
@@ -112,9 +116,10 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
} else {
message = "fail";
}
set((state: comFcltState) => {
state.dmdIsSucees = message;
return state;
return state.dmdIsSucees = message;
});
} catch (err) {
console.log(err);
@@ -132,8 +137,7 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => {
}
set((state: comFcltState) => {
state.dmdIsSucees = message;
return state;
return state.dmdIsSucees = message;
});
} catch (err) {
console.log(err);
@@ -29,12 +29,12 @@ export const coRvwHeadListExport: CommonTableProps[]= [
visible: true,
},
{
id: "regDt", //바꾸기
id: "dmndTmng",
title: "신청일자",
visible: true,
},
{
id: "state", //바꾸기
id: "splyFcltFlg",
title: "진행상태",
visible: true,
},
+61 -39
View File
@@ -1,13 +1,18 @@
import { constCostHeadListExport, coRvwHeadListExport, coRvwNodeListExport, rateFeeHeadListExport } from "./headList";
import {
constCostHeadListExport,
coRvwHeadListExport,
coRvwNodeListExport,
rateFeeHeadListExport,
} from "./headList";
import type { CommonTableProps } from "../../common/type/header";
import type { DedMatUpdateType, DmdCoReqType } from "./type";
import { fetchType, getFetch, putFectch } from "@/components/lib/api";
import toast from "react-hot-toast/headless";
import { fetchType, getFetch, getFetchWithCount, putFectch } from "@/components/lib/api";
import toast from "react-hot-toast";
const coRvwHeadList = coRvwHeadListExport;
const coRvwNodeList = coRvwNodeListExport;
const rateFeeHeadList =rateFeeHeadListExport;
const constCostHeadList=constCostHeadListExport
const rateFeeHeadList = rateFeeHeadListExport;
const constCostHeadList = constCostHeadListExport;
export type coRvwState = {
coRvw: {
isInit: boolean;
@@ -16,6 +21,7 @@ export type coRvwState = {
coRvwNodeList: CommonTableProps[];
rateFeeHeadList: CommonTableProps[];
constCostHeadList: CommonTableProps[];
coMatRvwCount:number;
};
};
@@ -25,8 +31,9 @@ export const coRvwStateExport: coRvwState = {
coMatRvwRes: [],
coRvwHeadList: coRvwHeadList,
coRvwNodeList: coRvwNodeList,
rateFeeHeadList:rateFeeHeadList,
constCostHeadList:constCostHeadList
rateFeeHeadList: rateFeeHeadList,
constCostHeadList: constCostHeadList,
coMatRvwCount:1
},
};
@@ -37,7 +44,7 @@ type coRvwActions = {
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
endYear: string
) => void;
coMatRvwUpdate: (
splyCd: string,
@@ -50,7 +57,7 @@ type coRvwActions = {
startYear: string,
endYear: string,
sggCd: string,
dmdCoNm: string,
dmdCoNm: string
) => void;
coMatRvwInqua: (
pageNo: number,
@@ -65,10 +72,10 @@ const coMatInit = async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
endYear: string
) => {
const url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
const coMatRvwRes = await getFetch(fetchType.WR, url);
const url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
const coMatRvwRes = await getFetchWithCount(fetchType.WR, url);
return coMatRvwRes;
};
@@ -79,7 +86,7 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
endYear: string
) => {
const coMatRvwRes = await coMatInit(pageNo, pageCnt, startYear, endYear);
@@ -88,7 +95,8 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
coRvw: {
...state.coRvw,
init: false,
coMatRvwRes: coMatRvwRes,
coMatRvwRes: coMatRvwRes.data,
coMatRvwCount:coMatRvwRes.count
},
}));
},
@@ -98,25 +106,37 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
data: DedMatUpdateType
) => {
try {
const isUpdate = await putFectch(
const response = await putFectch(
`/reuseFc/request/cst/${splyCd}/${dmdCd}`,
data
);
if (response.status === 200) {
const coMatRvwRes = coMatInit(
1,
10,
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
init: false,
coMatRvwRes: coMatRvwRes,
},
}));
if(data.flg ==='Sub'){
toast.success("매칭 검토로 저장되었습니다.");
}else{
toast.success("매칭 검토완료로 저장되었습니다.");
}
const coMatRvwRes = await coMatInit(
1,
10,
new Date().getFullYear().toString(),
new Date().getFullYear().toString()
);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
coMatRvwRes: coMatRvwRes.data,
coMatRvwCount:coMatRvwRes.count,
init: false,
},
}));
} else {
toast.error("매칭 검토 저장에 실패했습니다.");
}
} catch (e) {
toast.error("매칭 검토 저장 오류입니다.");
}
@@ -127,9 +147,9 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
startYear: string,
endYear: string,
sggCd: string,
dmdCoNm: string,
dmdCoNm: string
) => {
let url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
let url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}`;
@@ -142,14 +162,15 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
url += `/0`;
}
console.log(' url ', url)
const coMatRvwRes = await getFetch(fetchType.WR, url);
console.log(" url ", url);
const coMatRvwRes = await getFetchWithCount(fetchType.WR, url);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
coMatRvwRes: coMatRvwRes,
coMatRvwRes: coMatRvwRes.data,
coMatRvwCount:coMatRvwRes.count,
},
}));
},
@@ -161,23 +182,24 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
sggCd: string
) => {
try {
let url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
let url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}/0`;
}else if(sggCd ==='0'){
} else if (sggCd === "0") {
url += `/0/0`;
}
const coMatRvwRes = await getFetch(fetchType.WR, url);
const coMatRvwRes = await getFetchWithCount(fetchType.WR, url);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
coMatRvwRes: coMatRvwRes,
coMatRvwRes: coMatRvwRes.data,
coMatRvwCount:coMatRvwRes.count,
},
}));
} catch (e) {
console.log(" error ", e);
}
}
},
};
};
+130 -155
View File
@@ -1,173 +1,148 @@
import { z } from "zod";
const DemandInfoSchema = z.object({
dmdInfoSn: z.number(),
dmdInfoFk: z.string(),
dmndTmng: z.coerce.date(),
dmndQty: z.number(),
wntUntprc: z.number(),
grssClfg: z.number(),
combResdch: z.number(),
trbt: z.number(),
blgcOxygDmndQnt: z.number(),
smll: z.number(),
crmty: z.number().nullish(),
tn: z.number(),
tph: z.number(),
ph: z.number(),
clIonQnt: z.number(),
cdtnv: z.number(),
rmrk: z.string(),
useUsgCd: z.string(),
mtchnCmptnYmd: z.string().nullish(),
rvwCmptnYmd: z.string().nullish()
});
const DemandMatchingSchema = z.object({
dmdInfoFk: z.string().nullish(),
splyFcltFk: z.string().nullish(),
splyFcltFlg: z.string().nullish(),
pbnstRuseFcltBizFk: z.number().nullish(),
splyBgngDay: z.coerce.date().nullish(),
splyEndDay: z.coerce.date().nullish(),
splyCpct: z.number().nullish(),
splyFmYn: z.string().nullish(),
useUsgCd: z.string().nullish(),
dmdInfoSn: z.number().nullish(),
splyCndtList:z.array(z.string().nullish() ).nullish()
});
const DemandCoSchema = z.object({
dmdInfoPk: z.string(),
dmdCoNm: z.string(),
ctpvCd: z.string(),
sggCd: z.string(),
daddr: z.string(),
splyBgngDay: z.coerce.date(),
splyEndDay: z.coerce.date(),
splyCpct: z.number(),
splyFmYn: z.string().nullish(),
telno: z.string(),
useUsgCd: z.string().nullish(),
regDt: z.coerce.date().nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.coerce.date().nullish(),
mdfr: z.string().nullish(),
dmdAplyPswd: z.string(),
demandInfo: z.array(DemandInfoSchema.nullish()).nullish(), // 안쓰는 거임
demandMatchings: z.array(DemandMatchingSchema.nullish()).nullish()// 안쓰는 거임
});
const DemandCstSchema = z.object({
dmdInfoSn: z.number(),
usgPrcsProcs: z.string().nullish(),
cstrnCst: z.number(),
fcltSbsdCstrnCst: z.number(),
prcsFcltCpctCstrnCst: z.number()
});
export const DmdCoReqSchema = z.object({
cityText:z.string().nullish(),
sggText:z.string().nullish(),
dmdInfoSn: z.number(),
dmdInfoFk: z.string(),
dmndTmng: z.coerce.date(),
dmndQty: z.number(),
wntUntprc: z.number().nullish(),
grssClfg: z.number().nullish(),
combResdch: z.number().nullish(),
trbt: z.number().nullish(),
blgcOxygDmndQnt: z.number(),
smll: z.number().nullish(),
crmty: z.number().nullish(),
tn: z.number().nullish(),
tph: z.number().nullish(),
ph: z.number().nullish(),
clIonQnt: z.number().nullish(),
cdtnv: z.number(),
rmrk: z.string().nullish(),
useUsgCd: z.string().nullish(),
mtchnCmptnYmd: z.string().nullish(),
rvwCmptnYmd: z.string().nullish(),
demandCo: DemandCoSchema.nullish(),
demandMatching: DemandMatchingSchema.nullish(),
demandCst: DemandCstSchema,
ruseUtztnFcltNm:z.string().nullish(),
totalConstCost:z.number().nullish(),
const DemandInfoSchema = z.object({
dmdInfoSn: z.number(),
dmdInfoFk: z.string().nullish(),
dmndTmng: z.coerce.date().nullish(),
dmndQty: z.number().nullish(),
wntUntprc: z.number().nullish(),
grssClfg: z.number().nullish(),
combResdch: z.number().nullish(),
trbt: z.number().nullish(),
blgcOxygDmndQnt: z.number(),
smll: z.number().nullish(),
crmty: z.number().nullish(),
tn: z.number().nullish(),
tph: z.number().nullish(),
ph: z.number(),
clIonQnt: z.number().nullish(),
cdtnv: z.number().nullish(),
rmrk: z.string().nullish(),
useUsgCd: z.string().nullish(),
});
});
const DemandMatchingSchema = z.object({
dmdInfoFk: z.string().nullish(),
splyFcltFk: z.string().nullish(),
splyFcltFlg: z.string().nullish(),
pbnstRuseFcltBizFk: z.number().nullish(),
splyBgngDay: z.coerce.date().nullish(),
splyEndDay: z.coerce.date().nullish(),
splyCpct: z.number().nullish(),
splyFmYn: z.string().nullish(),
useUsgCd: z.string().nullish(),
dmdInfoSn: z.number().nullish(),
splyCndtList: z.array(z.string().nullish()).nullish(),
mtchnCmptnYmd: z.string().nullish(),
rvwCmptnYmd: z.string().nullish(),
});
const DemandCoSchema = z.object({
dmdInfoPk: z.string().nullish(),
dmdCoNm: z.string().nullish(),
ctpvCd: z.string().nullish(),
sggCd: z.string().nullish(),
daddr: z.string().nullish(),
splyBgngDay: z.coerce.date().nullish(),
splyEndDay: z.coerce.date().nullish(),
splyCpct: z.number().nullish(),
splyFmYn: z.string().nullish(),
telno: z.string().nullish(),
useUsgCd: z.string().nullish(),
regDt: z.coerce.date().nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.coerce.date().nullish(),
mdfr: z.string().nullish(),
dmdAplyPswd: z.string().nullish(),
demandInfo: z.array(DemandInfoSchema.nullish()).nullish(), // 안쓰는 거임
demandMatchings: z.array(DemandMatchingSchema.nullish()).nullish(), // 안쓰는 거임
});
const DemandCstSchema = z.object({
dmdInfoSn: z.number().nullish(),
usgPrcsProcs: z.string().nullish(),
cstrnCst: z.number().default(0),
fcltSbsdCstrnCst: z.number().default(0),
prcsFcltCpctCstrnCst: z.number().default(0),
});
export const DmdCoReqSchema = z.object({
cityText: z.string().nullish(),
sggText: z.string().nullish(),
dmdInfoSn: z.number().default(0),
dmdInfoFk: z.string().default(''),
dmndTmng: z.coerce.date().nullish(),
dmndQty: z.number().nullish(), // null 또는 undefined 허용
blgcOxygDmndQnt: z.number().nullish(),
wntUntprc: z.number().nullish(),
grssClfg: z.number().nullish(),
combResdch: z.number().nullish(),
trbt: z.number().nullish(),
smll: z.number().nullish(),
crmty: z.number().nullish(),
tn: z.number().nullish(),
tph: z.number().nullish(),
ph: z.number().nullish(),
clIonQnt: z.number().nullish(),
cdtnv: z.number().nullish(),
rmrk: z.string().nullish(),
useUsgCd: z.string().nullish(),
mtchnCmptnYmd: z.string().nullish(),
rvwCmptnYmd: z.string().nullish(),
demandCo: DemandCoSchema.nullish(),
demandMatching: DemandMatchingSchema.nullish(),
demandCst: DemandCstSchema.nullish(),
ruseUtztnFcltNm: z.string().nullish(),
totalConstCost: z.number().nullish(),
});
export type DmdCoReqType = z.infer<typeof DmdCoReqSchema>;
export type DmdMatTableType = {
cityText:string,
sggText:string,
dmdCoNm:string,
daddr:string,
telno:string,
regDt:string,
splyFcltFlg:string
}
cityText: string;
sggText: string;
dmdCoNm: string;
daddr: string;
telno: string;
regDt: string;
splyFcltFlg: string;
};
export type DedMatUpdateType =
{
export type DedMatUpdateType = {
dmdInfoSn: number;
usgPrcsProcs: string;
cstrnCst: number;
fcltSbsdCstrnCst: number;
prcsFcltCpctCstrnCst: number;
rgtr: string;
}
flg?:string;
};
export type RvwHistTableType = {
cityText:string,
sggText:string,
dmdCoNm:string,
daddr:string,
telno:string,
regDt:string,
rvwCmptnYmd:string,
mtchnCmptnYmd:string,
ruseUtztnFcltNm:string,
dmndQty:string,
useUsgCd:string,
splyFcltFlg:string
completeYn:boolean
dmdInfoSn :string
cityText: string;
sggText: string;
dmdCoNm: string;
daddr: string;
telno: string;
regDt: string;
rvwCmptnYmd: string;
mtchnCmptnYmd: string;
ruseUtztnFcltNm: string;
dmndQty: string;
useUsgCd: string;
splyFcltFlg: string;
completeYn: boolean;
dmdInfoSn: string;
};
}
export type RvwHistTableType = {
cityText:string,
sggText:string,
dmdCoNm:string,
daddr:string,
telno:string,
regDt:string,
rvwCmptnYmd:string,
mtchnCmptnYmd:string,
ruseUtztnFcltNm:string,
dmndQty:string,
useUsgCd:string,
splyFcltFlg:string
completeYn:boolean
dmdInfoSn :string
}
export type conCostFeeType= {
yr: string,
fctCpc: string,
fctCd: string,
stdCost: string
}
export type conCostFeeType = {
yr: string;
fctCpc: string;
fctCd: string;
stdCost: string;
};
export type rateFeeType = {
yr: string,
incExpCd: string,
stdCost: number,
rt: number
}
yr: string;
incExpCd: string;
stdCost: number;
rt: number;
};
@@ -44,6 +44,11 @@ export const coSttHeadListExport: z.infer<typeof sttnHeadListType> = [
title: "전화번호",
visible: true,
},
{
id: "regDt",
title: "등록일자",
visible: true,
},
];
export const coSttNodeListExport: CommonTableProps[] = [
+1 -1
View File
@@ -2,7 +2,7 @@ import type { CommonTableProps } from "@/app/store/common/type/header";
import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api";
import { coSttHeadListExport, coSttNodeListExport } from "./headList";
import { excelCoSttnParsing } from "./excel";
import type { DemandCompType } from "@common/business_components/ui";
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
// 테이블 헤드 리스트
const coSttNodeList = coSttNodeListExport;
@@ -2,8 +2,8 @@ import { z } from "zod";
import type { CommonTableProps } from "../../common/type/header";
export const drgtZod = z.object({
ctpvCd: z.string().default(''),
sggNm: z.string().default(''),
ctpvCd: z.string().default('').nullish(),
sggNm: z.string().default('').nullish(),
normal: z.string().default(''),
attention: z.string().default(''),
caution: z.string().default(''),
+83 -59
View File
@@ -1,4 +1,4 @@
import { fetchType, getFetch } from "@/components/lib/api";
import { fetchType, getFetch, postFectch } from "@/components/lib/api";
import type { CommonTableProps } from "../../common/type/header";
import { drgtHeadListExport, drgtZod } from "./headList";
import type { z } from "zod";
@@ -14,11 +14,13 @@ export type drgtState = {
drgtHeadList: CommonTableProps[];
drgtRes: customDrgt[];
drgtMoRes: customDrgt[];
isInit: boolean;
}
}
type drgtActions = {
drgtSearch: (fromDate: string, toDate: string, sido: string, sgg: string) => void
drgtInit: () => void
drgtSearch: (fromDate: string, toDate: string, sido: string[]) => void
drgtModalSearch: (fromDate: string, toDate: string, sgg: string) => void
};
@@ -29,72 +31,97 @@ export const drgtStateExport: drgtState = {
drgtHeadList: drgtHeadList,
drgtRes: drgtRes,
drgtMoRes: drgtRes,
isInit: false,
}
}
const initFetch = async (fromDate: string, toDate: string, sido:string[]) => {
console.log("sido",sido)
const drgtData = await postFectch(
`/il/getDataCount/${fromDate}/${toDate}`,
sido,
fetchType.WR
);
//주의, 관심, 정상 추출
const statusData = Array.from(
new Set(drgtData.data.map((e) => e.lvngMfgUswtrDrgtInfo))
);
const statusMap = drgtData.data.reduce((acc: any, { sggNm, lvngMfgUswtrDrgtInfo: status, countDrgt }: { sggNm: string; lvngMfgUswtrDrgtInfo: string; countDrgt: number }) => {
if (!acc[sggNm]) {
acc[sggNm] = { sggNm, ...Object.fromEntries(statusData.map((e) => [e, 0])) };
}
acc[sggNm][status] = Number(countDrgt);
return acc;
}, {});
const data = Object.values(statusMap);
const formatStatus = data.map((item) => {
const attention = item['관심'] || 0;
const caution = item['주의'] || 0;
return {
sggNm: item.sggNm,
normal: String(item['정상'] || 0),
caution: String(caution),
attention: String(attention),
warning: String(attention + caution),
};
});
const ranking = Array.from(
new Set(formatStatus.map(e => Number(e.warning)))
).sort((a, b) => b - a);
const rankData = ranking.reduce((acc, val, idx) => {
acc[val] = idx + 1;
return acc;
}, {});
const drgtRes = formatStatus.map(item => ({
...item,
warning: String(item.warning),
ranking: rankData[Number(item.warning)],
}));
return drgtRes;
}
export const drgtActionsExport: (set: any) => drgtActions = (
set: any
) => {
return {
drgtSearch: async (fromDate: string, toDate: string, sido: string, sgg: string) => {
drgtInit: async () => {
try {
let searchUrl = "";
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const formatted = `${year}${month}`;
const fromDate = formatted;
const toDate = formatted;
if (sido === "" || sido === "전체") {
searchUrl = `/il/getDataCount/${fromDate}/${toDate}`;
} else {
searchUrl = `/il/getDataCount/${fromDate}/${toDate}/${sido}/${sgg}`;
}
console.log("searchUrl", searchUrl);
const drgtData = await getFetch(
fetchType.WR,
searchUrl
);
console.log("drgtRes", drgtData)
//주의, 관심, 정상 추출
const statusData = Array.from(
new Set(drgtData.map((e) => e.lvngMfgUswtrDrgtInfo))
);
const statusMap = drgtData.reduce((acc: any, { sggNm, lvngMfgUswtrDrgtInfo: status, countDrgt }: { sggNm: string; lvngMfgUswtrDrgtInfo: string; countDrgt: number }) => {
if (!acc[sggNm]) {
acc[sggNm] = { sggNm, ...Object.fromEntries(statusData.map((e) => [e, 0])) };
}
acc[sggNm][status] = Number(countDrgt);
return acc;
}, {});
const data = Object.values(statusMap);
const formatStatus = data.map((item) => {
const attention = item['관심'] || 0;
const caution = item['주의'] || 0;
//FIXME: 페이지 처음 로딩될때 데이터 보려고 6월로 박아놓음 이거 fromDate로 고치기
const drgtRes = await initFetch("202506", toDate, []);
set((state: drgtState) => {
return {
sggNm: item.sggNm,
normal: String(item['정상'] || 0),
caution: String(caution),
attention: String(attention),
warning: String(attention + caution),
};
...state,
drgt: {
...state.drgt,
drgtRes: drgtRes,
isInit: false,
},
}
});
} catch (e) {
console.log(e)
}
},
drgtSearch: async (fromDate: string, toDate: string, sido: string[]) => {
try {
const drgtRes = await initFetch(fromDate, toDate, sido);
const ranking = Array.from(
new Set(formatStatus.map(e => Number(e.warning)))
).sort((a, b) => b - a);
const rankData = ranking.reduce((acc, val, idx) => {
acc[val] = idx + 1;
return acc;
}, {});
const drgtRes = formatStatus.map(item => ({
...item,
warning: String(item.warning),
ranking: rankData[Number(item.warning)],
}));
set((state: drgtState) => {
return {
...state,
@@ -115,10 +142,7 @@ export const drgtActionsExport: (set: any) => drgtActions = (
`/il/getData/${fromDate}/${toDate}/${sgg}/${sgg}`
);
console.log("drgtMoData", drgtMoData)
const drgtMoRes = drgtMoData.map((item) => {
console.log("item", item)
const year = item.anlsYmd.slice(0, 4);
const month = item.anlsYmd.slice(4, 6);
const drgtState = item.lvngMfgUswtrDrgtInfo;
@@ -46,29 +46,17 @@ export const names: nameMap = {
}
export const excelPbnstSttnParsing = (data: any[]): string[][] => {
export const excelLdrmntParsing = (data: any[]): string[][] => {
const excelExportData: string[][] = [];
data.forEach((item) => {
excelExportData.push([
item.rvbsn,
String(item.lgbsn),
item.mdmbsn ?? "",
item.rgnNm ?? "",
String(item.sido ?? ""),
String(item.gugun ?? ""),
String(item.bscFctNm ?? ""),
String(item.efflWqltStndrdNm ?? ""),
String(item.fctCpc ?? ""),
String(item.tel ?? ""),
String(item.ruseUtztnFcltNm ?? ""),
String(item.fcltCpct ?? ""),
String(item.splyExtraCpct ?? ""),
String(item.ruseCpct ?? ""),
String(item.usageTotal ?? ""),
String(item.inUsage ?? ""),
String(item.outUsage ?? ""),
item.fctryAddr?.split(" ")[0] || "",
item.fctryAddr?.split(" ")[1] || "",
item.dmdCoNm,
item.fctryAddr,
item.fctryMngNo,
item.telno,
])
})
return excelExportData;
+40 -27
View File
@@ -2,10 +2,8 @@ import type { CommonTableProps } from "@/app/store/common/type/header";
import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import { z } from "zod";
import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList";
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList";
// 테이블 헤드 리스트
const ldrmntHeadList = ldrmntHeadListExport;
@@ -34,7 +32,7 @@ const excelDownList: ExcelType[] = [];
type ldrmntActions = {
ldrmntRegData: (data: any[]) => void,
ldrmntInit: (con: string) => void
ldrmntSearch: (page: number, sggCd: string, coNm: string) => void;
ldrmntSearch: (page: number, sggCd: string, total: string, coNm: string) => void;
ldrmntUpdate: (ldrmntRes: customLdrmnt) => void;
ldrmntDelete: () => void;
};
@@ -61,6 +59,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
fetchType.WR,
`/reuseFc/request/temp/1/20/${con}`
);
set((state: ldrmntState) => {
return {
...state,
@@ -68,6 +67,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
...state.ldrmnt,
ldrmntRes: ldrmntRes,
isInit: false,
excelList: excelDownList,
},
}
});
@@ -101,44 +101,57 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = (
}
},
ldrmntSearch: async (page: number, sggCd: string, coNm: string) => {
ldrmntSearch: async (page: number, total: string, sggCd: string, coNm: string) => {
let searchUrl = "";
if (sggCd !== "") {
if (coNm !== "") {
searchUrl = `/reuseFc/request/temp/${page}/20/${sggCd}/${coNm}`;
searchUrl = `/reuseFc/request/temp/${page}/${total}/${sggCd}/${coNm}`;
} else {
searchUrl = `/reuseFc/request/temp/${page}/20/${sggCd}`;
searchUrl = `/reuseFc/request/temp/${page}/${total}/${sggCd}`;
}
}
try {
const ldrmntRes = await getFetch(
fetchType.WR,
searchUrl
);
ldrmntRes.forEach((item: customLdrmnt) => {
excelDownList.push({
ctpvCd: item.ctpvCd,
sggCd: item.sggCd,
dmdCoNm: item.dmdCoNm,
fctryAddr: item.fctryAddr,
fctryMngNo: item.fctryMngNo,
telno: item.telno,
if (Number(total) > 5000) {
let excelDownList: ExcelType[] = [];
ldrmntRes.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,
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes,
excelList: excelDownList,
},
}
})
},
};
});
return excelDownList;
} else
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes,
isInit: false,
},
};
});
return ldrmntRes;
} catch (e) {
console.log(e)
}
+26 -19
View File
@@ -1,12 +1,13 @@
import { fetchType, getFetch, postFectch } from "@/components/lib/api";
import { fetchType, getFetch, getFetchWithCount, postFectch } from "@/components/lib/api";
import type { TableUpperProps } from "../../common/type/header";
import { ruseCaseHeadListExport } from "./headList";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import { toast } from "react-hot-toast";
export type ruseCaseState = {
ruseCaseMng: {
ruseHeadList:TableUpperProps[];
ruseCaseMngList:ruseCaseMngExcelProps[];
status: number;
count: number;
};
};
@@ -64,20 +65,19 @@ export interface ruseCaseMngExcelProps {
}
type ruseCaseActions = {
selectRuseCaseMng: (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise<void>;
selectRuseCaseMng: (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise<void>;
insertRuseCaseMng: (data: any) => Promise<void>;
};
export const fetchSearchRuseCaseMng = async (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
const tailUrl = ((sigunguCd !== '전체' && sigunguCd !=='') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd? `/${usageCd}` : '/0') + (name? `/${name}` : '');
const resp = await getFetch(fetchType.WR,`/reuseFc/pubFcRuseCase${tailUrl}`);
return resp;
export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
const tailUrl = '/'+pageNo+'/'+pageSize+ ((sigunguCd !== '전체' && sigunguCd !=='') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd? `/${usageCd}` : '/0') + (name? `/${name}` : '');
const resp = await getFetchWithCount(fetchType.WR,`/reuseFc/pubFcRuseCase${tailUrl}`);
return {data:resp.data, count:resp.count};
};
export const fetchInsertRuseCaseMng = async (data: any) => {
const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR);
return response.data;
return {data:response.data, status:response.status};
};
export type ruseCaseType = ruseCaseState & ruseCaseActions;
@@ -86,6 +86,8 @@ export const ruseCaseStateExport: ruseCaseState = {
ruseCaseMng: {
ruseHeadList:ruseCaseHeadListExport,
ruseCaseMngList:[],
status: 0,
count: 0,
},
};
@@ -93,13 +95,13 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
set: any
) => {
return {
selectRuseCaseMng: async (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
const res = await fetchSearchRuseCaseMng(sidoCd, sigunguCd, usageCd, name);
console.log('res : ', res);
selectRuseCaseMng: async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name);
set((state: ruseCaseState) => ({
ruseCaseMng: {
...state.ruseCaseMng,
ruseCaseMngList: res,
ruseCaseMngList: res.data,
count: res.count,
},
}));
},
@@ -107,11 +109,16 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
insertRuseCaseMng: async (data: any) => {
const response = await fetchInsertRuseCaseMng(data);
if(response.status === 200){
ToastFormUi({
body: "잠재수요처 등록이 완료되었습니다. ",
title: "잠재수요처 등록",
});
toast.success("물재이용사례 등록이 완료되었습니다. ");
}else{
toast.error("물재이용사례 등록에 실패하였습니다. ");
}
set((state: ruseCaseState) => ({
ruseCaseMng: {
...state.ruseCaseMng,
status: response.status,
},
}));
},
};
};
};
@@ -28,7 +28,7 @@ export const ruseHstryHeadListExport:TableUpperProps[]= [
visible: true,
},
{
id: "regDt", //바꾸기
id: "dmndTmng", //바꾸기
title: "신청일자",
visible: true,
},
+26 -13
View File
@@ -5,7 +5,7 @@ import type {
TableUpperProps,
} from "../../common/type/header";
import { ruseHstryHeadListExport } from "./headList";
import { fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api";
import { fetchType, getFetch, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api";
import type { DmdCoReqType } from "../coMatRvw/type";
import toast from "react-hot-toast";
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
@@ -16,6 +16,7 @@ export type ruseHstryState = {
ruseHist: {
isInit: boolean;
rvwHistRes: DmdCoReqType[];
rvwHistCount:number;
ruseHistHeadList: TableUpperProps[];
};
};
@@ -25,6 +26,7 @@ export const ruseHstryStateExport: ruseHstryState = {
isInit: false,
rvwHistRes: [],
ruseHistHeadList: ruseHistHeadList,
rvwHistCount:1,
},
};
@@ -79,14 +81,14 @@ const irvwHistInit = async (
startYear: string,
endYear: string,
) => {
let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
// console.log("sggCd ", sggCd);
// if (sggCd) {
// url += `/${sggCd}`;
// }
const rvwHistRes = await getFetch(fetchType.WR, url);
const rvwHistRes = await getFetchWithCount(fetchType.WR, url);
return rvwHistRes;
};
@@ -115,7 +117,8 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
ruseHist: {
...state.ruseHist,
init: false,
rvwHistRes: rvwHistRes,
rvwHistRes: rvwHistRes.data,
rvwHistCount:rvwHistRes.count
},
}));
},
@@ -140,8 +143,8 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
ruseHist: {
...state.ruseHist,
init: false,
rvwHistRes: rvwHistRes,
},
rvwHistRes: rvwHistRes.data,
rvwHistCount:rvwHistRes.count },
}));
}
} catch (e) {
@@ -158,7 +161,7 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
dmdCoNm: string,
ruseUtztnFcltNm: string
) => {
let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}`;
@@ -175,14 +178,14 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
} else {
url += `/0`;
}
const rvwHistRes = await getFetch(fetchType.WR, url);
const rvwHistRes = await getFetchWithCount(fetchType.WR, url);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
rvwHistRes: rvwHistRes,
},
rvwHistRes: rvwHistRes.data,
rvwHistCount:rvwHistRes.count },
}));
},
ruseRvwInqua: async (
@@ -193,16 +196,17 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
sggCd: string
) => {
try {
let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}/0`;
}
const rvwHistRes = await getFetch(fetchType.WR, url);
const rvwHistRes = await getFetchWithCount(fetchType.WR, url);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
rvwHistRes: rvwHistRes,
rvwHistRes: rvwHistRes.data,
rvwHistCount:rvwHistRes.count
},
}));
} catch (e) {
@@ -224,6 +228,15 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
rvwHistRes: rvwHistRes.data,
rvwHistCount:rvwHistRes.count
},
}));
}
} catch (e) {
console.log(" error ", e);
@@ -94,15 +94,15 @@ export const excelToRainChkData = (excelData: any, year: string) => {
}
const makeGuidDetail = Array.from({ length: 12 }, (_, i) => {
let month = `${i + 1}`;
const splyData = item[`보급_${month}월`];
const splyData = item[`대체_${month}월`];
const ruseData = item[`빗물_${month}월`];
if (month.length < 2) month = "0" + month;
return {
utztnUsgCd: item["이용용도"],
ym: year + month,
chckYmd: checkYmd,
splyUswtrUtztnQnt: Number(splyData ?? 0),
ruseFcltUtztnQnt: Number(ruseData ?? 0),
splyUswtrUtztnQnt: Number(splyData) || 0,
ruseFcltUtztnQnt: Number(ruseData) || 0,
flg: "RNB",
};
});
@@ -120,13 +120,13 @@ export const excelToRainChkData = (excelData: any, year: string) => {
rainyDetails: [
{
utztnUsgCd: item["이용용도"] ?? "",
ph: Number(item["PH"] ?? 0),
trbt: Number(item["탁도"] ?? 0),
grssClfg: Number(item["총대장균군수"] ?? 0),
etc: item["기타"] ?? "", // 필드 누락 방지
vltnDt: vltnDt ?? "",
vltnMttr: item["위반사항"] ?? "",
levyAmt: Number(item["과태료부과금액(천원)"] ?? 0),
ph: Number(item["PH"] || 0),
trbt: Number(item["탁도"] || 0),
grssClfg: Number(item["총대장균군수"] || 0),
etc: item["기타"] || "", // 필드 누락 방지
vltnDt: vltnDt || "-",
vltnMttr: item["위반사항"] || "-",
levyAmt: Number(item["과태료부과금액(천원)"] || 0),
rgtr: TEST_UUID,
},
],
@@ -114,10 +114,22 @@ export type splRuseWaterType = {
ruse12: number;
};
export const rainHeadNmExport: chHeadType[] = [
export const rainMainHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "이용수질(필요시)", length: 3 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
];
export const rainRuseHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "이용수질(필요시)", length: 3 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
{ headNm: "ruseWater", text: "연간대체수 이용량(m³)", length: 13 },
{ headNm: "detailQulity", text: "분기", length: 11 },
];
export const rainSplHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "이용수질(필요시)", length: 3 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
{ headNm: "ruseWater", text: "연간보급수 이용량(m³)", length: 13 },
{ headNm: "detailQulity", text: "분기", length: 11 },
{ headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 },
];
@@ -134,7 +146,7 @@ export const rainChkgdnHeadListExport: TableUpperProps[] = [
{ id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true },
{ id: "chckYmd", title: "점검일", mergeCell: true },
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간대체수이용량(m³)" },
{ id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" },
{
id: "ph",
@@ -1,27 +1,31 @@
import { buildingType } from "@/app/store/common/code";
import {
TEST_UUID,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { TableUpperProps } from "@/app/store/common/type/header";
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
deleteFectch,
fetchType,
getFetch,
getFetchWithCount,
postFectch,
putFectch,
} from "@/components/lib/api";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import type { SelectDataType } from "@common/business_components/ui";
import toast from "react-hot-toast";
import { z } from "zod";
import { buildingToExcelType } from "./excel";
import {
rainChkgdnHeadListExport,
rainChkZod,
rainHeadNmExport,
rainMainHeadNmExport,
rainRuseHeadNmExport,
rainSplHeadNmExport,
ruseHeadListExport,
splHeadListExport,
type chHeadType,
} from "./headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
export const rainPageSize = 5;
export const commonCd = "41";
export type rainChkZodType = z.infer<typeof rainChkZod>;
const fcltDiv = [
@@ -29,30 +33,41 @@ const fcltDiv = [
{ val: "RNB", text: "빗물이용시설" },
];
const rainHeadNm = rainHeadNmExport;
const rainRuseHeadNm = rainRuseHeadNmExport;
const rainSplHeadNm = rainSplHeadNmExport;
const rainChkgdnHeadList = rainChkgdnHeadListExport;
const ruseHeadList = ruseHeadListExport;
const splHeadList = splHeadListExport;
const rainMainHeadNm = rainMainHeadNmExport
const rainChk: rainChkZodType[] = [];
export type rainChkgdnState = {
rainChkgdn: {
rainChkgdnHeadList: TableUpperProps[];
rainSplHeadNm: chHeadType[]
rainRuseHeadNm: chHeadType[]
rainChk: rainChkZodType[];
rainHeadNm: chHeadType[];
ruseHeadList: TableUpperProps[];
splHeadList: TableUpperProps[];
isInit: boolean;
isModalClose: boolean;
fcltDiv: SelectDataType[];
rainMainHeadNm: chHeadType[]
excelList: [];
isSttn: boolean;
rainChkCount: number;
isLoading: boolean;
};
};
type rainChkgdnActions = {
rainChkInit: (sggCd: string, searchTxt: string) => void;
rainChkInit: (
pageNo: number,
cnt: number,
sggCd: string,
searchTxt: string
) => void;
rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise<void>;
rainChkGuidUpdate(rainChk: rainChkZodType): Promise<void>;
rainChkExcelDownload(
@@ -62,6 +77,13 @@ type rainChkgdnActions = {
rainChkExcelDataUPload(excelData: rainChkZodType[]): Promise<void>;
rainChkDelete(chkgdnPks: number[]): Promise<void>;
rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit: boolean) => void;
rainChkNmSearch: (
pageNo: number,
cnt: number,
year: string,
sggCd: string,
txt: string
) => void;
};
export type rainChkgdnType = rainChkgdnState & rainChkgdnActions;
@@ -69,7 +91,9 @@ export type rainChkgdnType = rainChkgdnState & rainChkgdnActions;
export const rainChkgdnStateExport: rainChkgdnState = {
rainChkgdn: {
rainChkgdnHeadList: rainChkgdnHeadList,
rainHeadNm: rainHeadNm,
rainRuseHeadNm: rainRuseHeadNm,
rainSplHeadNm: rainSplHeadNm,
rainMainHeadNm: rainMainHeadNm,
rainChk: rainChk,
splHeadList: splHeadList,
ruseHeadList: ruseHeadList,
@@ -78,6 +102,8 @@ export const rainChkgdnStateExport: rainChkgdnState = {
excelList: [],
fcltDiv: fcltDiv,
isSttn: false,
rainChkCount: 1,
isLoading: false,
},
};
@@ -98,12 +124,23 @@ const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => {
return chData;
};
const initFetch = async (txt: string | undefined, sgg: string | undefined) => {
const initFetch = async (
pageNo: number,
cnt: number,
year: string | undefined,
sgg: string | undefined
) => {
const currentYear = new Date().getFullYear().toString();
const rainRes = await getFetch(
const rainRes = await getFetchWithCount(
"wr",
`/reuseChk/rainy` + (txt ? `/${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0")
`/reuseChk/rainy` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/10") +
(year ? `/${year}` : `/${currentYear}`) +
(sgg ? `/${sgg}` : "/0")
);
return rainRes;
};
@@ -129,42 +166,89 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
}));
},
rainChkExcelDataUPload: async (excelData: rainChkZodType[]) => {
set((state: rainChkgdnType) => (
{ rainChkgdn: { ...state.rainChkgdn, isLoading: true } }));
try {
const res = await postFectch("/reuseChk/rainy", excelData);
console.log("res", res);
console.log("res.ok", res.ok)
if (res.ok) {
ToastFormUi({
body: "지도점검 등록이 완료되었습니다. ",
title: "지도점검 등록",
});
if (res.status === 200) {
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(
1,
rainPageSize,
currentYear,
commonCd
);
set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes.data,
rainChkCount: rainChkRes.count,
},
}));
toast.success("지도점검 등록이 완료되었습니다.");
} else {
toast.error("지도점검 등록이 실패되었습니다.");
}
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(currentYear, "0");
return set((state: rainChkgdnState) => ({
} catch (error) {
console.log(error);
toast.error("지도점검 등록이 실패되었습니다.");
} finally {
set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: false } }));
}
},
rainChkInit: async (
pageNo: number,
cnt: number,
year: string,
sggCd: string
) => {
// set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: true } }));
try {
const rainChkRes = await initFetch(pageNo, cnt, year, sggCd);
set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
rainChk: rainChkRes.data,
rainChkCount: rainChkRes.count,
isInit: false, // 무한 루프 방지를 위해 isInit을 true로 설정
},
}));
} catch (error) {
console.log(error);
ToastFormUi({
body: "지도점검 등록이 실패되었습니다.",
title: "지도점검 등록",
});
// 에러가 발생하더라도 무한 루프에 빠지지 않도록 isInit을 true로 설정합니다.
// set((state: rainChkgdnType) => ({
// rainChkgdn: { ...state.rainChkgdn, isInit: true },
// }));
} finally {
// set((state: rainChkgdnType) => ({ rainChkgdn: { ...state.rainChkgdn, isLoading: false } }));
}
},
rainChkInit: async (searchTxt: string, sggCd: string) => {
rainChkNmSearch: async (
pageNo: number,
cnt: number,
year: string,
sggCd: string,
txt: string
) => {
try {
const rainChkRes = await initFetch(searchTxt, sggCd);
const currentYear = new Date().getFullYear();
const rainChkRes = await getFetchWithCount(
"wr",
`/reuseChk/rainy` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/10") +
(year ? `/${year}` : `/${currentYear}`) +
(sggCd ? `/${sggCd}` : "/0") +
(txt ? `/${txt}` : "")
);
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
rainChk: rainChkRes.data,
rainChkCount: rainChkRes.count,
},
}));
} catch (error) {
@@ -175,48 +259,62 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
try {
const chData = await makeMdfrChk(rainChk, "rain", "rainDetil");
const res = await postFectch("/reuseChk/rainy", chData);
if (res.ok) {
ToastFormUi({
body: "지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
const res = await putFectch("/reuseChk/rainy/list", chData);
if (res) {
toast.success(
"지도점검 대체수 및 밋물이용량 수정이 완료되었습니다. "
);
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(
1,
rainPageSize,
currentYear,
"41"
);
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes.data,
rainChkCount: rainChkRes.count,
},
}));
} else {
toast.error("지도점검 대체수 및 밋물이용량 수정 오류입니다.");
}
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(currentYear, "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
console.log(error);
alert("수정에 실패하였습니다.");
toast.error("지도점검 대체수 및 밋물이용량 수정 오류입니다.");
}
},
rainChkGuidUpdate: async (rainChk: rainChkZodType) => {
try {
//const chData = await makeMdfrChk(rainChk, "guideDetails", "rainDetil");
const res = await putFectch("/reuseChk/rainy", rainChk);
if (res.ok) {
ToastFormUi({
body: "지도점검 수질 및 과태료 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
if (res.status === 200) {
toast.success("지도점검 수질 및 과태료 수정이 완료되었습니다. ");
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(
1,
rainPageSize,
currentYear,
"41"
);
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes.data,
rainChkCount: rainChkRes.count,
},
}));
} else {
toast.error("지도점검 수질 및 과태료 수정 오류입니다.");
}
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(currentYear, "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
console.log(error);
toast.error("지도점검 수질 및 과태료 수정 오류입니다.");
}
},
rainChkDelete: async (chkgdnPks: number[]) => {
@@ -224,22 +322,29 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
const res = await deleteFectch(`/reuseChk/rainy`, chkgdnPks);
if (res) {
ToastFormUi({
body: "삭제가 완료되었습니다. ",
title: "지도점검 삭제",
});
toast.success("삭제가 완료되었습니다. ");
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(
1,
rainPageSize,
currentYear,
"41"
);
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes.data,
rainChkCount: rainChkRes.count,
},
}));
} else {
toast.error("삭제시 오류가 발생하였습니다.. ");
}
const currentYear = new Date().getFullYear().toString();
const rainChkRes = await initFetch(currentYear, "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" });
toast.error("삭제시 오류가 발생하였습니다.. ");
}
},
rainChkHeadChange: async (rainChkgdn: rainChkgdnState, isEdit: boolean) => {
@@ -249,16 +354,13 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
const ruseHeadList = rainChkgdn.rainChkgdn.ruseHeadList;
rainChkgdnHeadList.forEach((head) => {
if (head.edit !== undefined)
head.edit = isEdit;
if (head.edit !== undefined) head.edit = isEdit;
});
splHeadList.forEach((head) => {
if (head.edit !== undefined)
head.edit = isEdit;
if (head.edit !== undefined) head.edit = isEdit;
});
ruseHeadList.forEach((head) => {
if (head.edit !== undefined)
head.edit = isEdit;
if (head.edit !== undefined) head.edit = isEdit;
});
return set((state: rainChkgdnState) => ({
@@ -267,7 +369,7 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
...state.rainChkgdn,
rainChkgdnHeadList: rainChkgdnHeadList,
splHeadList: splHeadList,
ruseHeadList: ruseHeadList
ruseHeadList: ruseHeadList,
},
}));
} catch (error) {
@@ -1,6 +1,6 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
import { z } from "zod";
import { guideDetail, type chHeadType } from "../rainChkgdn/headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
export type polutionType = {
chkgdnDtlFk: number;
@@ -109,6 +109,24 @@ export const rswtChkgdZod = z.object({
rswtrPollutions: z.array(rswtrPolutionsZode),
});
export const rswtRuseHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "이용수질(필요시)", length: 3 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
{ headNm: "ruseWater", text: "연간중수 이용량(m³)", length: 13 },
{ headNm: "detailQulity", text: "분기", length: 11 },
];
export const rswtSplHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "이용수질(필요시)", length: 3 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
{ headNm: "detailQulity", text: "분기", length: 11 },
{ headNm: "splWater", text: "연간대체수 이용량(m³)", length: 13 },
];
export const rswtHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "연간 평균 이용수질", length: 10 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
@@ -126,7 +144,7 @@ export const rswtChkHeadListExport: TableUpperProps[] = [
{ id: "spwtPositn", title: "채수지점" ,mergeCell: true},
{ id: "chckYmd", title: "점검일" ,mergeCell: true},
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)" ,type: "number"},
{ id: "splyUswtrUtztnQnt", title: "연간대체수이용량(m³)" ,type: "number"},
{ id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)",type: "number"},
{
@@ -1,18 +1,24 @@
import { buildingType } from "@/app/store/common/code";
import type { TableUpperProps } from "@/app/store/common/type/header";
import {
TEST_UUID,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type {
SelectDataType,
SheetParameter,
} from "@common/business_components";
import {
deleteFectch,
fetchType,
getFetch,
getFetchWithCount,
postFectch,
putFectch,
} from "@/components/lib/api";
import { buildingType } from "@/app/store/common/code";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import type {
SelectDataType,
SheetParameter,
} from "@common/business_components";
import toast from "react-hot-toast";
import { z } from "zod";
import { type chHeadType } from "../rainChkgdn/headList";
import { rswtMakeExcelSample } from "./excel";
import {
rswtChkgdZod,
@@ -20,15 +26,19 @@ import {
rswtDetailHeadListExport,
rswtHeadNmExport,
rswtrDetailsZod,
rswtRuseHeadNmExport,
rswtSplHeadNmExport,
} from "./headList";
import { z } from "zod";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import { type chHeadType } from "../rainChkgdn/headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
export const rswtPageSize = 5;
const rswtChkHeadList = rswtChkHeadListExport;
const rswtDetailHeadList = rswtDetailHeadListExport;
const rswtHeadNm = rswtHeadNmExport;
const rswtRuseHeadNm =rswtRuseHeadNmExport
const rswtSplHeadNm =rswtSplHeadNmExport
export type rswtChkZodType = z.infer<typeof rswtChkgdZod>;
export type rswtrChkDetailsZodType = z.infer<typeof rswtrDetailsZod>;
export type rswtChkgdnState = {
@@ -40,13 +50,29 @@ export type rswtChkgdnState = {
excelList: SheetParameter[];
rswtChkRes: rswtChkZodType[];
rswtChkPolGuide: rswtChkZodType[];
rswtSplHeadNm:chHeadType[]
rswtRuseHeadNm:chHeadType[]
isInit: boolean;
isSttn:boolean
isSttn: boolean;
isLoading:boolean;
rswtChkCount: number;
};
};
type rswtChkgdnActions = {
rswtChkgdnInit: (year: string, sggCd: string) => void;
rswtChkgdnInit: (
pageNo: number,
cnt: number,
year: string,
sggCd: string
) => void;
rswtChkNmSearch: (
pageNo: number,
cnt: number,
year: string,
sggCd: string,
txt: string
) => void;
rswtrChkExcelDownload(
sidoCode: SelectDataType[],
sggCode: SelectDataType[]
@@ -57,7 +83,7 @@ type rswtChkgdnActions = {
rswtChkPolAndGuide: (chkGdnPk: number) => void;
rswtChkPolInit: () => void;
rwstPolAndGuideUpdate: (rswtChk: rswtChkZodType[]) => void;
rswtChkHeadChange: (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => void;
rswtChkHeadChange: (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => void;
};
export type rswtChkgdnType = rswtChkgdnState & rswtChkgdnActions;
@@ -67,25 +93,41 @@ export const rswtChkgdnStateExport: rswtChkgdnState = {
rswtChkHeadList: rswtChkHeadList,
rswtDetailHeadList: rswtDetailHeadList,
rswtHeadNm: rswtHeadNm,
excelList: [{
data: [[]], headerNum: 0, headerRange: "A1:V3",
rswtRuseHeadNm:rswtRuseHeadNm,
rswtSplHeadNm:rswtSplHeadNm,
excelList: [
{
data: [[]],
headerNum: 0,
headerRange: "A1:V3",
sheetName: "",
startCol: '1'
}],
startCol: "1",
},
],
rswtChkRes: [],
rswtChkPolGuide: [],
isInit: false,
isSttn:false,
isSttn: false,
isLoading:false,
rswtChkCount: 1,
},
};
const initFetch = async (year: string | undefined, sgg: string | undefined) => {
const initFetch = async (
pageNo: number,
cnt: number,
year: string | undefined,
sgg: string | undefined
) => {
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await getFetch(
const rswtChkRes = await getFetchWithCount(
"wr",
`/reuseChk/reuseWater/` +
(year ? `${year}` : currentYear) +
(sgg ? `/${sgg}` : "/0")
`/reuseChk/reuseWater` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/20") +
(year ? `/${year}` : `/${currentYear}`) +
(sgg ? `/${sgg}` : "/0")
);
return rswtChkRes;
};
@@ -137,16 +179,63 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
},
}));
},
rswtChkgdnInit: async (year: string, sggCd: string) => {
rswtChkgdnInit: async (
pageNo: number,
cnt: number,
year: string,
sggCd: string
) => {
// set((state: rswtChkgdnType) => ({ rswtChkgdn: { ...state.rswtChkgdn, isLoading: true } }));
try {
const rswtChkRes = await initFetch(year, sggCd);
const rswtChkRes = await initFetch(pageNo, cnt, year, sggCd);
console.log("rswtChkRes", rswtChkRes)
set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
isInit: true, // 무한 루프를 방지하기 위해 isInit을 true로 설정
},
}));
} catch (error) {
// console.log(error);
// set((state: rswtChkgdnType) => ({
// rswtChkgdn: { ...state.rswtChkgdn, isInit: true },
// }));
} finally {
// set((state: rswtChkgdnType) => ({ rswtChkgdn: { ...state.rswtChkgdn, isLoading: false } }));
}
},
rswtChkNmSearch: async (
pageNo: number,
cnt: number,
year: string,
sggCd: string,
txt: string
) => {
try {
console.log("여기")
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await getFetchWithCount(
"wr",
`/reuseChk/reuseWater` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/20") +
(year ? `/${year}` : `/${currentYear}`) +
(sggCd ? `/${sggCd}` : "/0") +
(txt ? `/${txt}` : "")
);
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
isInit: false,
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
// isInit: false,
},
}));
} catch (error) {
@@ -155,6 +244,8 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
},
rswtChkExceDataUpload: async (excelData: rswtChkZodType[]) => {
try {
set((state: rswtChkgdnType) => (
{ rswtChkgdn: { ...state.rswtChkgdn, isLoading: true } }));
const res = await postFectch("/reuseChk/reuseWater", excelData);
if (res.ok) {
ToastFormUi({
@@ -163,65 +254,66 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
});
}
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await initFetch(currentYear, "0");
const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
},
}));
} catch (error) {
console.log(error);
}finally{
set((state: rswtChkgdnType) => (
{ rswtChkgdn: { ...state.rswtChkgdn, isLoading: false } }));
}
},
rswtChkDetilsUpdate: async (rswtChk: rswtrChkDetailsZodType[]) => {
try {
const chData = await makeMdfrChk(rswtChk);
const res = await putFectch("/reuseChk/reuseWater", chData);
if (res.ok) {
ToastFormUi({
body: "지도점검 과태료 수정 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
toast.success("지도점검 과태료 수정이 완료되었습니다. ",)
}
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await initFetch(currentYear, "0");
const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
},
}));
} catch (error) {
console.log(error);
alert("수정에 실패하였습니다.");
toast.error("지도점검 과태료 수정 오류입니다. ",)
}
},
rswtChkDelete: async (chkgdnPks: number[]) => {
try {
const res = await deleteFectch(`/reuseChk/reuseWater`, chkgdnPks);
if (res.ok) {
ToastFormUi({
body: "삭제가 완료되었습니다. ",
title: "지도점검 삭제",
});
if (res) {
toast.success("삭제가 완료되었습니다.")
}
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await initFetch(currentYear, "0");
const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
},
}));
} catch (error) {
ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" });
toast.error("삭제 오류입니다.")
}
},
rswtChkPolAndGuide: async (chkGdnPk: number) => {
@@ -238,7 +330,11 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
rswtChkPolGuide: rswtChkPolGuide,
},
}));
} catch (error) {}
} catch (error) {
}
},
rswtChkPolInit: () => {
try {
@@ -259,13 +355,10 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
chData[0]
);
if (res.ok) {
ToastFormUi({
body: "지도점검 연간 수질 및 보급수/중수도 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
toast.success("지도점검 연간 수질 및 대체수/중수도 수정이 완료되었습니다.")
}
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await initFetch(currentYear, "0");
const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
@@ -275,10 +368,9 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
}));
} catch (error) {
console.log(error);
ToastFormUi({
body: "지도점검 연간 수질 및 보급수/중수도 수정이 실패하였습니다.. ",
title: "지도점검 수정",
});
toast.error("지도점검 연간 수질 및 대체수/중수도 수정 오류입니다.")
}
},
rswtChkHeadChange: async (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => {
@@ -4,7 +4,7 @@ import type { TableUpperProps } from "../../common/type/header";
export const pbnPrfRegExcelZod = z.object({
ym: z.string().default(""),
bscFctNm: z.string().default(""),
pbnstRuseFcltFk:z.string(),
pbnstRuseFcltFk: z.string(),
pbnstRuseFcltNm: z.string().default(""),
file: z.instanceof(File).optional(),
});
@@ -18,20 +18,21 @@ export const pbnstPrfmncHeadListExport: TableUpperProps[] = [
];
export const monthHeadListExport: TableUpperProps[] = [
{ id: "구분", title: "구분", mergeCell: true },
{ id: "용수명", title: "용수명" },
{ id: "total", title: "계" },
{ id: "1월", title: "1월" ,edit: true },
{ id: "2월", title: "2월" ,edit: true },
{ id: "3월", title: "3월" ,edit: true },
{ id: "4월", title: "4월" ,edit: true },
{ id: "5월", title: "5월" ,edit: true },
{ id: "6월", title: "6월" ,edit: true },
{ id: "7월", title: "7월" ,edit: true },
{ id: "8월", title: "8월" ,edit: true },
{ id: "9월", title: "9월" ,edit: true },
{ id: "10월", title: "10월" ,edit: true },
{ id: "11월", title: "11월" ,edit: true },
{ id: "12월", title: "12월" ,edit: true },
{ id: "1월", title: "1월", edit: true },
{ id: "2월", title: "2월", edit: true },
{ id: "3월", title: "3월", edit: true },
{ id: "4월", title: "4월", edit: true },
{ id: "5월", title: "5월", edit: true },
{ id: "6월", title: "6월", edit: true },
{ id: "7월", title: "7월", edit: true },
{ id: "8월", title: "8월", edit: true },
{ id: "9월", title: "9월", edit: true },
{ id: "10월", title: "10월", edit: true },
{ id: "11월", title: "11월", edit: true },
{ id: "12월", title: "12월", edit: true },
];
@@ -16,6 +16,7 @@ export type pbnstPrfmncState = {
monthHeadList: TableUpperProps[];
prfmncRes: FcPrfType[];
excelList: Number[];
pageKey:number
};
};
@@ -26,21 +27,22 @@ export const pbnstPrfmncStateExport: pbnstPrfmncState = {
monthHeadList: monthHeadList,
prfmncRes: [],
excelList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
pageKey:1
},
};
export type pbnstPrfmncType = pbnstPrfmncState & pbnstPrfmncActions;
type pbnstPrfmncActions = {
prfmncHasuInit: (page: string, sggOrCity: string) => void;
prfmnRegData: (data: PrfType) => void;
prfmncHasuInit: (page: number, sggOrCity: string) => void;
prfmnRegData: (page:number,sggOrCity:string, data: PrfType) => void;
};
const checkWrRegList = async () => {
const wrRegList = await getFetch("wr", `/reuseFc/pubDetailList`);
return wrRegList;
};
const hasuListFetch = async (page: string, sggOrCity: string) => {
const hasuListFetch = async (page: number, sggOrCity: string) => {
const checkWrRegListRes = await checkWrRegList();
const rainRes = await postFectch(
`/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`,
@@ -74,7 +76,7 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = (
set: any
) => {
return {
prfmncHasuInit: async (page: string, sggOrCity: string) => {
prfmncHasuInit: async (page: number, sggOrCity: string) => {
try {
const prfmncRes = await hasuListFetch(page, sggOrCity);
return set((state: pbnstPrfmncState) => ({
@@ -89,7 +91,7 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = (
console.log(errorHasu);
}
},
prfmnRegData: async (data: PrfType) => {
prfmnRegData: async (page:number,sggOrCity:string,data: PrfType) => {
try {
const ressponse = await postFectch(
"/reuseFc/pubFcPrf",
@@ -100,6 +102,17 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = (
if (ressponse.status === 200) {
toast.success("하수재이용 시설 실적 등록이 완료되었습니다.");
const prfmncRes = await hasuListFetch(page, sggOrCity);
return set((state: pbnstPrfmncState) => ({
...state,
prfmnc: {
...state.prfmnc,
prfmncRes: prfmncRes,
isInit: false,
pageKey: state.prfmnc.pageKey + 1
},
}));
}
} catch (e) {
console.log(e);
@@ -11,7 +11,7 @@ export const rainChkgdnHeadSttnExport: TableUpperProps[] = [
{ id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true },
{ id: "chckYmd", title: "점검일", mergeCell: true },
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간대체수이용량(m³)" },
{ id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" },
{
id: "ph",
@@ -1,11 +1,10 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { type TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { getFetch } from "@/components/lib/api";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import { rainMainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import { getFetchWithCount } from "@/components/lib/api";
import type { SelectDataType } from "@common/business_components/ui";
import { rainChkgdnHeadSttnExport, ruseSttnHeadListExport, splSttnHeadListExport } from "./headList";
import { rainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import { buildingExcelRainSttn } from "./excel";
import { rainChkgdnHeadSttnExport, ruseSttnHeadListExport, splSttnHeadListExport } from "./headList";
const fcltDiv = [
{ val: "RST", text: "중수도시설" },
@@ -16,29 +15,28 @@ const fcltDiv = [
const rainChkgdnHeadList = rainChkgdnHeadSttnExport;
const ruseHeadList = ruseSttnHeadListExport;
const splHeadList = splSttnHeadListExport;
const rainHeadNm = rainHeadNmExport
const rainChk: rainChkZodType[] = [];
const rainHeadNm = rainMainHeadNmExport
export type rainChkSttnState = {
rainChkSttn: {
rainChkRes: rainChkZodType[];
fcltDiv: SelectDataType[];
rainChkgdnHeadList: TableUpperProps[];
rainHeadNm:chHeadType[];
rainHeadNm: chHeadType[];
ruseHeadList: TableUpperProps[];
splHeadList: TableUpperProps[];
sttnExcelList:[]
sttnExcelList: []
isInit: boolean;
isSttn:boolean;
isSttn: boolean;
rainChkCount: number;
};
};
type rainChkSttnActions = {
rainChkSttnInit: (searchTxt: string, sggCd: string) => void;
rainChkSttnSearch: (searchTxt: string, sggCd: string) => void;
isRainSttn:(isSttn:boolean) => void;
getRainSttnExcel:(excelList:rainChkZodType[]) => void;
rainChkSttnInit: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void;
isRainSttn: (isSttn: boolean) => void;
getRainSttnExcel: (excelList: rainChkZodType[]) => void;
rainChkSttnNmSearch: (pageNo: number, cnt: number, year: string, sggCd: string, txt: string) => void
};
export type rainChkSttnType = rainChkSttnState & rainChkSttnActions;
@@ -50,18 +48,23 @@ export const rainChkSttnStateExport: rainChkSttnState = {
rainChkgdnHeadList: rainChkgdnHeadList,
ruseHeadList: ruseHeadList,
splHeadList: splHeadList,
rainHeadNm:rainHeadNm,
rainHeadNm: rainHeadNm,
isInit: false,
sttnExcelList:[],
isSttn:false,
sttnExcelList: [],
isSttn: false,
rainChkCount: 1,
},
};
const initFetch = async (txt: string | undefined, sgg: string | undefined) => {
const initFetch = async (pageNo: number, cnt: number, txt: string | undefined, sgg: string | undefined) => {
const currentYear = new Date().getFullYear().toString();
const rainRes = await getFetch(
const rainRes = await getFetchWithCount(
"wr",
`/reuseChk/rainy/` + (txt ? `${txt}` : currentYear) + (sgg ? `/${sgg}` : "/0")
`/reuseChk/rainy` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/5") +
(txt ? `/${txt}` : `/${currentYear}`) +
(sgg ? `/${sgg}` : "/0")
);
return rainRes;
};
@@ -69,48 +72,66 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = (
set: any
) => {
return {
rainChkSttnInit: async (searchTxt: string, sggCd: string) => {
rainChkSttnInit: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => {
try {
const rainChkRes = await initFetch(searchTxt, sggCd);
const rainChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd);
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
rainChkRes:rainChkRes
rainChkRes: rainChkRes.data,
rainChkCount: rainChkRes.count,
isSttn: true
},
}));
} catch (error) {
console.log(error);
}
},
rainChkSttnSearch: async (searchTxt: string, sggCd: string) => {
rainChkSttnNmSearch: async (
pageNo: number,
cnt: number,
year: string,
sggCd: string,
txt: string
) => {
try {
const rainChkRes = await initFetch(searchTxt, sggCd);
const currentYear = new Date().getFullYear();
const rainChkRes = await getFetchWithCount(
"wr",
`/reuseChk/rainy` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/5") +
(year ? `/${year}` : `/${currentYear}`) +
(sggCd ? `/${sggCd}` : "/0") +
(txt ? `/${txt}` : "")
);
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
rainChkRes:rainChkRes
rainChkRes: rainChkRes.data,
rainChkCount: rainChkRes.count,
},
}));
} catch (error) {
console.log(error);
}
},isRainSttn :(isSttn:boolean) =>{
},
isRainSttn: (isSttn: boolean) => {
try {
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
isSttn:isSttn
isSttn: isSttn
},
}));
} catch (error) {
console.log(error);
}
},getRainSttnExcel: async (excelList:rainChkZodType[]) => {
}, getRainSttnExcel: async (excelList: rainChkZodType[]) => {
try {
const excelData = buildingExcelRainSttn(excelList)
@@ -119,7 +140,7 @@ export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = (
...state,
rainChkSttn: {
...state.rainChkSttn,
sttnExcelList:excelData
sttnExcelList: excelData
},
}));
} catch (error) {
@@ -1,10 +1,10 @@
import { rswtHeadNmExport } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList";
import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import { getFetch } from "@/components/lib/api";
import { rswtHeadNmExport } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList";
import { getFetch, getFetchWithCount } from "@/components/lib/api";
import { buildingExcelRswtSttn } from "./excel";
import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headList";
const rswtChkHeadList = rswtChkSttnHeadListExport;
const rswtDetailHeadList = rswtDetailSttnHeadListExport;
@@ -20,14 +20,15 @@ export type rswtChkSttnState = {
rswtChkRes: rswtChkZodType[];
isInit: boolean;
isSttn: boolean;
rswtChkCount: number;
};
};
type rswtChkSttnActions = {
rswtChkSttnInit: (searchTxt: string, sggCd: string) => void;
rswtChkSttnInit: (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => void;
isRswtSttn: (isSttn: boolean) => void;
getRswtSttnExcel: (excelList: rswtChkZodType[]) => void;
rswtChkSttnSearch: (searchTxt: string, sggCd: string) => void;
rswtChkNmSttnSearch: (pageNo: number, cnt: number, year: string, sggCd: string, txt: string) => void;
};
export type rswtChkSttnType = rswtChkSttnState & rswtChkSttnActions;
@@ -41,33 +42,36 @@ export const rswtChkStateExport: rswtChkSttnState = {
rswtChkRes: [],
isInit: false,
isSttn: false,
rswtChkCount: 1,
},
};
const initFetch = async (year: string | undefined, sgg: string | undefined) => {
const initFetch = async (pageNo: number, cnt: number, year: string | undefined, sgg: string | undefined) => {
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await getFetch(
const rswtChkRes = await getFetchWithCount(
"wr",
`/reuseChk/reuseWater/` +
(year ? `${year}` : currentYear) +
`/reuseChk/reuseWater` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/20") +
(year ? `/${year}` : `/${currentYear}`) +
(sgg ? `/${sgg}` : "/0")
);
return rswtChkRes;
};
export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = (
set: any
) => {
return {
rswtChkSttnInit: async (searchTxt: string, sggCd: string) => {
rswtChkSttnInit: async (pageNo: number, cnt: number, searchTxt: string, sggCd: string) => {
try {
const rswtChkRes = await initFetch(searchTxt, sggCd);
const rswtChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd);
return set((state: rswtChkSttnState) => ({
...state,
rswtChkSttn: {
...state.rswtChkSttn,
rswtChkRes: rswtChkRes,
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
isInit: false,
},
}));
@@ -104,15 +108,32 @@ export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = (
console.log(error);
}
},
rswtChkSttnSearch: async (searchTxt: string, sggCd: string) => {
rswtChkNmSttnSearch: async (
pageNo: number,
cnt: number,
year: string,
sggCd: string,
txt: string
) => {
try {
const rswtChkRes = await initFetch(searchTxt, sggCd);
const currentYear = new Date().getFullYear().toString();
const rswtChkRes = await getFetchWithCount(
"wr",
`/reuseChk/reuseWater` +
(pageNo ? `/${pageNo}` : "/1") +
(cnt ? `/${cnt}` : "/20") +
(year ? `/${year}` : `/${currentYear}`) +
(sggCd ? `/${sggCd}` : "/0") +
(txt ? `/${txt}` : "")
);
return set((state: rswtChkSttnState) => ({
...state,
rswtChkSttn: {
...state.rswtChkSttn,
rswtChkRes: rswtChkRes
rswtChkRes: rswtChkRes.data,
rswtChkCount: rswtChkRes.count,
isInit: false,
},
}));
} catch (error) {
@@ -79,8 +79,9 @@ const isRswtBdst = (data: any): data is customRswtBdst =>{
data.reuseBuilding=chData;
}
if(data?.chgBuilding.length>0){
const chRgtr = data.chgBuilding.map((item) =>({...item, rgtr:TEST_UUID, mdfr: item.mdfr ?? null }))
if('chgBuilding' in data && Array.isArray(data.chgBuilding) && data.chgBuilding.length > 0){
const chRgtr = data.chgBuilding.map((item) =>({...item, rgtr:TEST_UUID, mdfr: item.mdfr ?? null }))
data.chgBuilding =chRgtr;
}
return data;
@@ -127,7 +128,7 @@ const isRswtBdst = (data: any): data is customRswtBdst =>{
data.reuseBuilding=chData;
}
if(data?.chgBuilding.length>0){
if('chgBuilding' in data && Array.isArray(data.chgBuilding) && data.chgBuilding.length > 0){
const chMdfr = data.chgBuilding.map((item) =>({...item, mdfr:TEST_UUID, archChgArea: item.archChgArea ?? '' }))
data.chgBuilding =chMdfr;
}
@@ -0,0 +1,10 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
export const htdTableHeadList: TableUpperProps[] = [
{ id: "cityText", title: "시도" },
{ id: "sggText", title: "시군구" },
{ id: "bdstNm", title: "발전소명" },
{ id: "daddr", title: "위치" },
{ id: "frstArchPrmsnDt", title: "준공년도" },
{ id: "archArea", title: "건축면적" },
];
@@ -6,9 +6,12 @@ import { makeMdfr, makeRstr } from "../bdstReg";
import {
baseReuseBuildingSchema,
chgBuildingSchema,
htdflReuseBuildingSchema,
validationMessages,
} from "../rainReg/type"; // Import baseReuseBuildingSchema, chgBuildingSchema, validationMessages
import type { TableUpperProps } from "@/app/store/common/type/header";
import { htdTableHeadList } from "./headList";
import toast from "react-hot-toast";
const hdtflObjSchema = z.object({
htdflFcltPk: z.number().nullish(),
@@ -21,8 +24,8 @@ const hdtflObjSchema = z.object({
.positive({ message: validationMessages.required("시설 용량") }),
plwtYn: z.enum(["Y", "N"]).default("Y"),
orgwtWtritSpt: z
.number()
.positive({ message: validationMessages.required("원수 취수량") }),
.string()
.min(1, { message: validationMessages.required("원수 취수 지점") }),
orgwtOcrnProcs: z
.string()
.min(1, { message: validationMessages.required("원수 발생 공정") }),
@@ -53,7 +56,9 @@ const hdtflObjSchema = z.object({
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
emsnExitTp: z.number().default(0), // 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
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
});
@@ -71,22 +76,21 @@ export const hdtflZod = z.object({
.date()
.default(() => new Date())
.nullish(),
archArea: z.number().default(0),
archArea: z.string().default(''),
archChgArea: z.number().nullish().default(0),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
reuseBuilding: z
.array(
baseReuseBuildingSchema.extend({
htdflReuseBuildingSchema.extend({
htdflObj: hdtflObjSchema,
})
)
.default([]),
chgBuilding: z.array(chgBuildingSchema).default([]), // Use imported chgBuildingSchema
//온배수는 건축물은 등록 하는것이 다름
// chgBuilding: z.array(chgBuildingSchema).nullish(), // Use imported chgBuildingSchema
});
export type customHtdflBdst = z.infer<typeof hdtflZod>;
export type htdflFacState = {
htdfl: {
isInit: boolean;
@@ -95,7 +99,8 @@ export type htdflFacState = {
};
};
type htdflFacSActions = {
initHtdfl: (code: string) => void;
initHtdflReg: (code: string) => void;
htdflNmSearch: (code: string | number, fcltNm:string) => void;
htdflBdstUpdate: (data: customHtdflBdst, code: string | number) => void;
htdflBdstReg: (data: customHtdflBdst, code: string | number) => void;
getHtdflBdstData: (pageNation: number, code: string | number) => void;
@@ -104,18 +109,24 @@ type htdflFacSActions = {
const htdflRes: customHtdflBdst[] = [];
export type htdflFacType = htdflFacState & htdflFacSActions;
export const htdflFacStateExport: htdflFacState = {
htdfl: {
isInit: false,
upHeadList: upHeadList,
upHeadList: htdTableHeadList,
htdflRes: htdflRes,
},
};
const initFetch = async (code: string | number) => {
const rswtRes = await getFetch("wr", `/facilityList/1/20/${code}`);
const initFetch = async (code: string) => {
console.log(' initFetch code ', code)
let url = `/drain/facilityList/1/20`
url+=`/${code}`
const rswtRes = await getFetch("wr", url);
return rswtRes;
};
export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
@@ -128,8 +139,6 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
"wr",
`/drain/facilityList/${pageNation}/20/${code}`
);
console.log(pageNation);
// 여기서 상태 업데이트
return set((state: htdflFacState) => ({
...state,
htdfl: {
@@ -142,10 +151,9 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
console.log(e);
}
},
initHtdfl: async (code: string) => {
initHtdflReg: async (code: string) => {
try {
const htdflRes = await initFetch(code);
const htdflRes = await initFetch( String(code));
set((state: htdflFacState) => {
return {
...state,
@@ -162,13 +170,19 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
},
htdflBdstUpdate: async (data: customHtdflBdst, code: string | number) => {
try {
const chData = await makeMdfr(data);
const res = await putFectch("/drain/facility", data);
if (res.ok) {
alert(" 수정이 완료되었습니다.");
const res = await putFectch("/drain/facility", chData);
if (res.status) {
toast.success("온배수 건축물 수정이 완료되었습니다.");
}
const htdflRes = await initFetch(code);
const htdflRes = await getFetch(
"wr",
`/drain/facilityList/1/20/${code}`
);
set((state: htdflFacState) => ({
...state,
htdfl: {
@@ -178,42 +192,20 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
},
}));
} catch (errorUpdate) {
alert(
"업데이트 오류입니다. " +
(errorUpdate instanceof Error ? errorUpdate.message : "")
);
toast.error("온배수 건축물 수정 오류입니다..");
}
},
htdflBdstReg: async (data: customHtdflBdst, code: string | number) => {
try {
const chData = await makeRstr(data);
const res = await postFectch("/drain/facility", data);
if (res.ok) {
if (data.chgBuilding.length > 0) {
await res
.json()
.then((resData: any) => {
const chPK = resData?.data?.bdstInfoPk;
const makeCh = resData.data.chgBuilding.map(
(item: chgBuilding) => ({
...item,
bdstInfoFk: chPK,
})
);
const chch = postFectch("/reuseFc/chgBuilding", makeCh);
return chch;
})
.then((chch: any) => {
if (chch.ok) {
alert("등록이 완료되었습니다.");
}
});
} else {
alert("등록이 완료되었습니다.");
}
// data는 단일 객체이므로 .map을 사용할 수 없습니다.
// 등록 시에는 건축물 변경 이력이 없으므로 chgBuilding을 빈 배열로 설정하고,
// API가 배열을 기대하므로 단일 객체를 배열로 감싸줍니다.
const chData = makeRstr(data);
const res = await postFectch("/drain/facility", chData);
if (res.status ===200) {
toast.success("온배수 건축물 등록이 완료되었습니다.");
}
const htdflRes = await initFetch(code);
const htdflRes = await initFetch(String(code));
set((state: htdflFacState) => ({
...state,
htdfl: {
@@ -223,7 +215,25 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = (
},
}));
} catch (errorReg) {
alert("등록 오류입니다.");
toast.error("온배수 건축물 등록 오류입니다..");
}
},htdflNmSearch :async(code:string | number, fcltNm:string) =>{
try {
const htdflRes = await getFetch("wr", `/drain/facilityList/1/20/${code}/${fcltNm}`);
set((state: htdflFacState) => {
return {
...state,
htdfl: {
...state.htdfl,
htdflRes: htdflRes,
isInit: false,
},
};
});
} catch (error) {
console.log(error);
}
},
};
@@ -54,6 +54,7 @@ export type pubFacState = {
pbnsUpdateIndex: pbnstInsertIndex;
fcOrgwtsNmList:pubHasuType[];
dmdComList: any[];
apiMessage:string;
};
};
type pubFacActions = {
@@ -94,6 +95,7 @@ export const pubFacStateExport: pubFacState = {
pbnsUpdateIndex: {} as pbnstInsertIndex,
fcOrgwtsNmList:[],
dmdComList: [],
apiMessage:''
},
};
@@ -269,8 +271,13 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
ruseRes
);
if(response){
toast.success(` 하수재이용 시설 정보가 수정되었습니다.`);
}
} catch (error) {
console.error("Error pbnstRuseFcltUpdate:", error);
toast.error(` 하수재이용 시설 정보가 수정오류입니다.`);
}
} ,pbnstRuseBizUpdate : async(ruseRes:fcBizType[])=>{
try {
@@ -280,6 +287,10 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
`/reuseFc/pubFcBiz`,
ruseRes
);
if(response){
toast.success(` 하수재이용 시설 사업이 수정되었습니다.`);
}
const pbnstRes = await hasuListFetch("11", "11");
return set((state: pubFacState) => ({
@@ -292,6 +303,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
}));
} catch (error) {
console.error("Error pbnstRuseFcltUpdate:", error);
toast.error(` 하수재이용 시설 사업이 수정이 실패되엇습니다..`);
}
} ,
getBizCycle: async (pbnstObj: customPbnst) => {
@@ -163,7 +163,7 @@ export const fcBizSchema = z.object({
etc: z.string().default(""),
totalMoney: zNumNullish.default(0),
rprcsFcltCpct: zNumDefaultZero,
majorPrcsMsrcCd: z.string().default(""),
majorPrcsMsrcCd: z.string().nullish(),
addr: z.string().default(""),
rprcsMthdCd: z.string().default(""),
inoutYn: z.enum(["Y", "N"]).default("Y"),
@@ -236,8 +236,11 @@ export const fcBizSchema = z.object({
export const pbnstRegZod = z.object({
pbnstRuseFcltPk: z.string().default(""),
swtrmtFcltFk: z.string().default(""),
ruseUtztnFcltNm: z.string().default(""),
fcltCpct: zNumDefaultZero,
ruseUtztnFcltNm: z
.preprocess(
(v) => (v !== null && v !== undefined ? String(v).trim() : ""), // null/undefined → "", 공백 제거
z.string().min(1, "시설 이름을 입력하세요")),
fcltCpct: zNumDefaultZero,
ruseCpct: zNumDefaultZero,
splyExtraCpct: zNumDefaultZero,
regDt: zDateDefaultNow,
@@ -246,7 +249,12 @@ export const pbnstRegZod = z.object({
mdfr: z.string().default("test"),
fcFiles: z.array(fcFileSchema).default([]).nullish(),
fcBizs: z.array(fcBizSchema).default([]),
fcOpers: z.array(fcOperSchema).default([]).nullish(),
fcOpers: z
.array(fcOperSchema)
.refine((val) => val.length >= 1, {
message: "재이용시설의 운영정보를 최소 하나를 등록해주세요",
})
.default([]), // 기본값 설정
});
export const pbnstRegArrayZod = z.array(pbnstRegZod);
@@ -10,7 +10,7 @@ export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e'
const rainyObjSchema = z.object({
bdstReuseFcltFk: z.number().nullish(),
pntfColKnd: z.string().min(1, { message: validationMessages.requiredSelect("종류") }),
pntfColArea: z.number().positive({ message: validationMessages.required("면적(m³)") }),
pntfColArea: z.number().nullish() ,
dtfcltCpct: z.number().default(0),
filtrTrtmfctYn: z.string().default("Y"),
filtrTrtmfctCpct: z.number().nullish().default(0),
@@ -34,7 +34,7 @@ export const rainZod = z.object({
bdstNm: z.string().default(""),
frstArchPrmsnDt: z.date().default(() => new Date()),
archChgPrmsnDt: z.coerce.date().nullish().default(null),
archArea: z.number().default(0),
archArea: z.string().default(''),
archChgArea: z.number().default(0),
rgtr:z.string().nullish(),
mdfr:z.string().nullish(),
@@ -162,29 +162,28 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
const test =await makeRstr(data);
const res = await postFectch("/reuseFc/rainyInfo", test);
if(res.ok){
if(res.status===200){
if(data.chgBuilding.length > 0){
await res.json().then((resData: any) => {
const chPK = resData?.data?.bdstInfoPk
const makeCh= resData.data.chgBuilding.map((item: chgBuilding) =>
const chPK = res?.data?.bdstInfoPk
const makeCh= res.data.chgBuilding.map((item: chgBuilding) =>
( {
...item,
bdstInfoFk: chPK,
})
);
const chch= postFectch("/reuseFc/chgBuilding", makeCh);
return chch;
}).then((chch: any) => {
const chch= await postFectch("/reuseFc/chgBuilding", makeCh);
console.log('chch ', chch)
if(chch.status ===200) {
toast.success("등록이 완료되었습니다.");
toast.success("건축물 등록이 완료되었습니다.");
}else{
toast.error("건축물 증축/개축/중축 오류입니다.");
}
})
}else{
toast.success("등록이 완료되었습니다.");
toast.success("건축물 등록이 완료되었습니다.");
}
}else{
toast.error("건축물 등록이 완료되었습니다.");
}
const rainRes = await initFetch(code);
set((state: rainFacState) => ({
@@ -197,7 +196,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
}));
} catch (e) {
console.log("e", e);
alert("등록 오류입니다.");
toast.error("등록시 오류가 발생하였습니다.");
} finally {
}
},
@@ -205,9 +204,9 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
try {
const chData =await makeMdfr(data);
const res = await putFectch("/reuseFc/rainyInfo", chData);
console.log('rainUpdate', res);
if(res.ok){
alert(" 수정이 완료되었습니다.")
if(res.status === 200){
toast.success("수정이 완료되었습니다.");
}
const rainRes = await initFetch(code);
set((state: rainFacState) => ({
@@ -220,7 +219,7 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = (
}));
} catch (e) {
console.log("e", e);
alert("업데이트 오류입니다.");
toast.error("수정시 오류가 발생하였습니다.");
} finally {
}
}
@@ -17,7 +17,10 @@ export const baseReuseBuildingSchema = z.object({
instlCstSprtYn: z.string().default("Y"),
instlCstSprtAmt: z.number().nullish(),
grntchBdstCertYn: z.string().default("Y"),
grntchBdstCertYr: z.string().default("").refine(
grntchBdstCertYr: z
.string()
.max(4, { message: validationMessages.yearFormat })
.refine(
(year) => year.length === 0 || /^\d{4}$/.test(year),
{
message: validationMessages.yearFormat,
@@ -29,7 +32,12 @@ export const baseReuseBuildingSchema = z.object({
crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
bdstUsgCd: z.number().min(1, { message: validationMessages.requiredSelect("건축물용도") }).default(0),
bdstUsgCd: z
.number()
.default(0)
.refine((val) => val === -1 || val >= 1, {
message: validationMessages.requiredSelect("건축물용도"),
}),
lawTrgtYn: z.string().default("Y"),
rgtr: z.string().nullish(),
mdfr: z.string().nullish(),
@@ -43,3 +51,40 @@ export const chgBuildingSchema = z.object({
rgtr:z.string().nullish(),
mdfr:z.string().nullish(),
});
export const htdflReuseBuildingSchema = z.object({
bdstRuseFcltPk: z.number().nullish(),
bdstInfoFk: z.number().nullish(),
instlCmptnDt: z.coerce.date().default(() => new Date()),
instlCst: z.number().nullish(),
operMngCd: z.string().optional().nullish(),
anlOperCst: z.number().default(0),
instlCstSprtYn: z.string().default("Y"),
instlCstSprtAmt: z.number().nullish(),
grntchBdstCertYn: z.string().default("Y"),
grntchBdstCertYr: z
.string()
.max(4, { message: validationMessages.yearFormat })
.refine(
(year) => year.length === 0 || /^\d{4}$/.test(year),
{
message: validationMessages.yearFormat,
}
)
.nullish(),
grntchBdstCertNo: z.string().default(""),
grntchBdstCertGrd: z.string().default(""),
crgRdctYn: z.string().default("N").nullish(), /// 안쓰는 값
crgRdctBss: z.string().default("").nullish(), /// 안쓰는 값
crgRdctAmt: z.number().default(0), // 안쓰는 값
ruseFcltFlg: z.string().default(""),
bdstUsgCd: z.number().default(0).nullish(),
lawTrgtYn: z.string().default("Y").nullish(),
rgtr: z.string().nullish(),
mdfr: z.string().nullish(),
});
@@ -5,13 +5,14 @@ import type { TableUpperProps } from "@/app/store/common/type/header";
import { z } from "zod";
import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "../rainReg/type";
import { makeMdfr, makeRstr } from "../bdstReg";
import toast from "react-hot-toast";
const rswtrObjSchema = z.object({
bdstRuseFcltFk: z.number().nullish(),
wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }),
oblgTrgtWtrUsqty: z.number().nullish().default(0),
//wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }),
//oblgTrgtWtrUsqty: z.number().nullish().default(0),
orgwtKndCd: z.string({ required_error: validationMessages.requiredSelect("원수 종류") }).min(1, { message: validationMessages.requiredSelect("원수 종류") }),
filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }).positive({ message: validationMessages.required("처리시설 용량") }),
filtrTrtmfctCpct: z.number({ required_error: validationMessages.required("처리시설 용량") }),
filtrTrtmfctProcs: z.string({ required_error: validationMessages.required("주요처리공정") }).min(1, { message: validationMessages.required("주요처리공정") }),
filtrTrtmfctUsgCd: z.string().default("").nullish(),
rswtrUsqty: z.number().default(0),
@@ -36,7 +37,7 @@ export const rswtZod = z.object({
frstArchPrmsnDt: z.date().default(() => new Date()),
archChgPrmsnDt: z.coerce.date().nullish().default(null),
chBuildingYn: z.string().nullish(),
archArea: z.number().default(0),
archArea: z.string().default(''),
archChgArea: z.number().default(0),
rgtr: z.string().nullish().default(null),
mdfr: z.string().nullish().default(null),
@@ -152,8 +153,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
try {
const chData = await makeMdfr(data);
const res = await putFectch("/reuseFc/waterreuseFc", chData);
if (res.ok) {
alert("등록이 완료되었습니다.");
if (res.status ===200) {
toast.success("중수도 건축물 수정이 완료되었습니다.");
const rswtRes = await initFetch(code);
set((state: rswtFacState) => ({
...state,
@@ -165,10 +166,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
}));
}
} catch (errorUpdate) {
alert(
"업데이트 오류입니다. " +
(errorUpdate instanceof Error ? errorUpdate.message : "")
);
toast.error("중수도 건축물 수정 오류입니다. ");
} finally {
}
},
@@ -176,29 +175,28 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
try {
const chData = await makeRstr(data);
const res = await postFectch("/reuseFc/waterreuseFc", chData);
if (res.ok) {
if (data.chgBuilding.length > 0) {
await res
.json()
.then((resData: any) => {
const chPK = resData?.data?.bdstInfoPk;
const makeCh = resData.data.chgBuilding.map(
(item: chgBuilding) => ({
...item,
bdstInfoFk: chPK,
})
);
const chch = postFectch("/reuseFc/chgBuilding", makeCh);
return chch;
})
.then((chch: any) => {
if (chch.ok) {
alert("등록이 완료되었습니다.");
}
});
if (res.status===200) {
if(data.chgBuilding.length > 0){
const chPK = res?.data?.bdstInfoPk
const makeCh= res.data.chgBuilding.map((item: chgBuilding) =>
( {
...item,
bdstInfoFk: chPK,
})
);
const chch= await postFectch("/reuseFc/chgBuilding", makeCh);
if(chch.status ===200) {
toast.success("건축물 등록이 완료되었습니다.");
}else{
toast.error("건축물 증축/개축/중축 오류입니다.");
}
} else {
alert("등록이 완료되었습니다.");
toast.success("건축물 등록이 완료되었습니다.");
}
}else{
toast.error("건축물 등록이 완료되었습니다.");
}
const rainRes = await initFetch(code);
set((state: rswtFacState) => ({
@@ -211,7 +209,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = (
}));
} catch (e) {
console.log("e", e);
alert("등록 오류입니다.");
toast.error("등록시 오류가 발생하였습니다.");
} finally {
}
},
@@ -5,6 +5,7 @@ import type { z } from "zod";
import { controlHeadView } from "../rainSttn";
import type { customHtdflBdst } from "../../fcltReg/htdflReg";
import { fetchType, getFetch } from "@/components/lib/api";
import type { SelectDataType } from "@common/business_components/ui";
const htdflSttHeadList = htdflSttHeadListExport;
const htdflSttNodeList = htdflSttNodeListExport;
@@ -20,8 +21,12 @@ export type htdflSttnState = {
};
};
type htdflSttnActions = {
initHtdfl: (con: string) => void;
htdflSttnSearch: (page: number, total: string, con: string) => void;
initHtdfl: (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void;
htdflSttnSearch: (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void;
htdflChSttnHead: (
headList: z.infer<typeof sttnHeadListType>,
) => void;
@@ -38,10 +43,17 @@ export const htdflSttnStateExport: htdflSttnState = {
isInit: false,
},
};
const initFetch = async (code: string | number) => {
const initFetch = async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
const htdflRes = await getFetch(
"wr",
`/drain/facilityList/1/20/${code}`)
`/drain/facilityList` +
(page ? `/${page}` : "/1") +
(total ? `/${total}` : "/20") +
(con ? `/${con}` : "/0") +
(txt ? `/${txt}` : "")
);
return htdflRes;
};
@@ -50,9 +62,11 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = (
set: any
) => {
return {
initHtdfl: async (code: string | number) => {
initHtdfl: async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
try {
const htdflSttnRes = await initFetch(code);
const htdflSttnRes = await initFetch(page, total, con, txt, sidoCode, sggCode);
set((state: htdflSttnState) => {
return {
...state,
@@ -67,17 +81,22 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = (
console.log(error);
}
},
htdflSttnSearch: async (page: number, total: string, con: string) => {
htdflSttnSearch: async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
try {
console.log("page", page)
const htdflSttnRes = await getFetch(
fetchType.WR,
`/drain/facilityList/${page}/${total}/${con}`
`/drain/facilityList` +
(page ? `/${page}` : "/1") +
(total ? `/${total}` : "/20") +
(con ? `/${con}` : "/0") +
(txt ? `/${txt}` : "")
);
if (Number(total) > 9000) {
set((state: htdflSttnState) => {
return {
...state,
htdflSttn: {
@@ -31,8 +31,8 @@ export const rainSttHeadListExport: z.infer<typeof sttnHeadListType> = [
visible: true,
},
{
id: "bdstUsgCd",
title: "건축물용도코드",
id: "bdsgUsgText",
title: "건축물용도",
visible: true,
},
{
@@ -209,8 +209,8 @@ export const rainSttNodeListExport: CommonTableProps[] = [
colSpan: 1,
},
{
id: "bdstUsgCd",
title: "건축물용도코드",
id: "bdsgUsgText",
title: "건축물용도",
upName: "bdnstInfo",
visible: true,
row: 2,
@@ -1,4 +1,4 @@
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { fetchType, getFetch } from "@/components/lib/api";
import {
type customRainBdst,
@@ -16,34 +16,34 @@ import type { CommonTableProps } from "@/app/store/common/type/header";
import type { SelectDataType } from "@common/business_components/ui";
// 테이블 헤드 리스트
const rainSttHeadList = rainSttHeadListExport;
const rainSttHeadList = rainSttHeadListExport;
const rainSttNodeList = rainSttNodeListExport;
const rainSttnDetailNodeList = rainSttnDetailNodeListExport;
const rainSttnDetailHeadList = rainSttnDetailHeadListExport;
const rainSttnRes: customRainBdst[] = [];
const rainChkRes : rainChkZodType ={} as rainChkZodType
const rainChkRes: rainChkZodType = {} as rainChkZodType
const visibleHeadList = (falseHeads:CommonTableProps[], orgNodeList:CommonTableProps[])=>{
const visibleHeadList = (falseHeads: CommonTableProps[], orgNodeList: CommonTableProps[]) => {
const visibleHeads = orgNodeList.map((node) => {
const copyNode = {...node}
falseHeads.forEach((head)=>{
if(copyNode.id ===head.id)
copyNode.visible = head.visible
const copyNode = { ...node }
falseHeads.forEach((head) => {
if (copyNode.id === head.id)
copyNode.visible = head.visible
})
return copyNode;
})
return visibleHeads
}
const getColspanReductionMap = (falseHeads:CommonTableProps[], orgList:CommonTableProps[]):Record<string, number> => {
const reduceMap:Record<string, number> = {};
const getColspanReductionMap = (falseHeads: CommonTableProps[], orgList: CommonTableProps[]): Record<string, number> => {
const reduceMap: Record<string, number> = {};
falseHeads.forEach(head => {
const node = orgList.find(n => n.id === head.id);
if (node?.upName) {
reduceMap[node.upName] = (reduceMap[node.upName] || 0) + 1;
if (node.row&& node.row >= 3) {
if (node.row && node.row >= 3) {
const upperUpName = orgList.find(n => n.id === node.upName)?.upName;
if (upperUpName) {
reduceMap[upperUpName] = (reduceMap[upperUpName] || 0) + 1;
@@ -78,35 +78,37 @@ const applyColspanReduction = (
});
};
// 일단 헤더가 3개 이상인경우 visible 처리를 위해서 공통함수로 작업
export const controlHeadView = (headList:CommonTableProps[], orgNodeList:CommonTableProps[] ) =>{
export const controlHeadView = (headList: CommonTableProps[], orgNodeList: CommonTableProps[]) => {
const falseHeads = headList.filter((item) => item.visible == false);
const viewHeadList = visibleHeadList(falseHeads, orgNodeList)
const reduceMap= getColspanReductionMap( falseHeads,viewHeadList)
return applyColspanReduction(viewHeadList,reduceMap);
const reduceMap = getColspanReductionMap(falseHeads, viewHeadList)
return applyColspanReduction(viewHeadList, reduceMap);
}
export type rainSttnState = {
rainSttn: {
rainSttnRes: customRainBdst[];
rainSttHeadList: CommonTableProps[];
rainSttNodeList: CommonTableProps[];
rainSttnDetailHeadList:CommonTableProps[]
rainSttnDetailNodeList:CommonTableProps[]
rainChkRes:rainChkZodType
rainSttnDetailHeadList: CommonTableProps[]
rainSttnDetailNodeList: CommonTableProps[]
rainChkRes: rainChkZodType
excelList: [];
isInit: boolean;
};
};
type rainSttnActions = {
rainSttnInit:(con:string) => void
rainSttnSearch: (page: number, total: string, con: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => void;
rainSttnInit: (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void
rainSttnSearch: (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void;
rainChSttnHead: (
headList: z.infer<typeof sttnHeadListType>,
) => void;
rainSttnChkSearch:(rusePk:string) => void;
rainSttnChkSearch: (rusePk: string) => void;
};
export type rainSttnType = rainSttnState & rainSttnActions;
@@ -115,10 +117,10 @@ export const rainSttnStateExport: rainSttnState = {
rainSttn: {
rainSttHeadList: rainSttHeadList,
rainSttNodeList: rainSttNodeList,
rainSttnDetailHeadList:rainSttnDetailHeadList,
rainSttnDetailNodeList:rainSttnDetailNodeList,
rainSttnDetailHeadList: rainSttnDetailHeadList,
rainSttnDetailNodeList: rainSttnDetailNodeList,
rainSttnRes: rainSttnRes,
rainChkRes:rainChkRes,
rainChkRes: rainChkRes,
excelList: [],
isInit: false,
},
@@ -128,12 +130,18 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
set: any
) => {
return {
rainSttnInit: async( con:string)=>{
try{
rainSttnInit: async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
try {
const rainSttnRes = await getFetch(
const rainSttnRes = await getFetch(
fetchType.WR,
`/reuseFc/rainyInfoList/1/20/${con}`
`/reuseFc/rainyInfoList` +
(page ? `/${page}` : "/1") +
(total ? `/${total}` : "/20") +
(con ? `/${con}` : "/0") +
(txt ? `/${txt}` : "")
);
set((state: rainSttnState) => {
return {
@@ -145,17 +153,21 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
},
};
});
}catch(e){
} catch (e) {
console.log(e)
}
},
rainSttnSearch: async (page: number, total: string, con: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
rainSttnSearch: async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
try {
const rainSttnRes = await getFetch(
fetchType.WR,
`/reuseFc/rainyInfoList/${page}/${total}/${con}`
`/reuseFc/rainyInfoList` +
(page ? `/${page}` : "/1") +
(total ? `/${total}` : "/20") +
(con ? `/${con}` : "/0") +
(txt ? `/${txt}` : "")
);
if (Number(total) > 9000) {
const rainExcel = excelRainSttnParsing(rainSttnRes, sidoCode, sggCode);
@@ -186,7 +198,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
rainChSttnHead: async (
headList: z.infer<typeof sttnHeadListType>
) => {
const changeNodeList= controlHeadView(headList,rainSttNodeList)
const changeNodeList = controlHeadView(headList, rainSttNodeList)
return set((state: rainSttnState) => ({
rainSttn: {
@@ -196,21 +208,21 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = (
},
}));
},
rainSttnChkSearch: async(
rusePk:string
)=>{
rainSttnChkSearch: async (
rusePk: string
) => {
const rainChkRes = await getFetch(
fetchType.WR,
`/reuseChk/rainy/${rusePk}`
);
return set((state: rainSttnState) =>({
return set((state: rainSttnState) => ({
rainSttn: {
...state.rainSttn,
rainChkRes:rainChkRes
rainChkRes: rainChkRes
},
}) )
}))
}
};
@@ -28,9 +28,12 @@ export type rswtSttnState = {
};
type rswtSttnActions = {
rswtSttnInit: (con: string) => void;
rswtSttnSearch: (page: number, total: string, con: string, sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void;
rswtSttnInit: (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void;
rswtSttnSearch: (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => void;
rswtChSttnHead: (
headList: z.infer<typeof sttnHeadListType>,
) => void;
@@ -54,12 +57,18 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = (
set: any
) => {
return {
rswtSttnInit: async (con: string) => {
rswtSttnInit: async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
try {
const rswtSttnRes = await getFetch(
fetchType.WR,
`/reuseFc/waterreuseFc/1/20/${con}`
`/reuseFc/waterreuseFc` +
(page ? `/${page}` : "/1") +
(total ? `/${total}` : "/20") +
(con ? `/${con}` : "/0") +
(txt ? `/${txt}` : "")
);
set((state: rswtSttnState) => {
return {
@@ -75,13 +84,18 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = (
console.log(e)
}
},
rswtSttnSearch: async (page: number, total: string, con: string,
rswtSttnSearch: async (page: number, total: string, con: string, txt: string,
sidoCode: SelectDataType[],
sggCode: SelectDataType[]) => {
try {
console.log("헐", page)
const rswtSttnRes = await getFetch(
fetchType.WR,
`/reuseFc/waterreuseFc/${page}/${total}/${con}`
`/reuseFc/waterreuseFc` +
(page ? `/${page}` : "/1") +
(total ? `/${total}` : "/20") +
(con ? `/${con}` : "/0") +
(txt ? `/${txt}` : "")
);
if (Number(total) > 9000) {
const rswtExcel = excelRSwtSttnParsing(rswtSttnRes, sidoCode, sggCode);
+134 -68
View File
@@ -2,6 +2,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 { useEffect } from "react";
export const rainChkTableData = (chkData: rainChkZodType[]) => {
// 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기
@@ -54,27 +55,32 @@ export const rainChkTableData = (chkData: rainChkZodType[]) => {
export const rswtChkTableData = (chkData: rswtChkZodType[]) => {
// 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기
const makeRswtData: any[] = [];
chkData.forEach((root) => {
root.rswtrDetails.forEach((detail) => {
let flatRswtChk = {};
const findGuide = root.guideDetails.find(
(guide) => guide.utztnUsgCd === detail.utztnUsgCd
);
const findPoluttion = root.rswtrPollutions.find(
(polution) => polution.utztnUsgCd === detail.utztnUsgCd
);
const operMngCd = root?.reuseBuilding.operMngCd;
flatRswtChk = {
...root,
...detail,
...findGuide,
...findPoluttion,
...flatRswtChk,
operMngCd: operMngCd,
};
makeRswtData.push(flatRswtChk);
if(chkData&&chkData.length>0){
chkData?.forEach((root) => {
root.rswtrDetails.forEach((detail) => {
let flatRswtChk = {};
const findGuide = root.guideDetails.find(
(guide) => guide.utztnUsgCd === detail.utztnUsgCd
);
const findPoluttion = root.rswtrPollutions.find(
(polution) => polution.utztnUsgCd === detail.utztnUsgCd
);
const operMngCd = root?.reuseBuilding.operMngCd;
flatRswtChk = {
...root,
...detail,
...findGuide,
...findPoluttion,
...flatRswtChk,
operMngCd: operMngCd,
};
makeRswtData.push(flatRswtChk);
});
});
});
}
return makeRswtData;
};
@@ -93,6 +99,7 @@ export const chRowspanTable = (
let order = 0
// rowspan된 셀 렌더링 여부 추적용
const renderedMap = new Map<string, Set<number>>();
return (
<>
{makeTableData.map((row, rowIndex) => (
@@ -103,6 +110,7 @@ export const chRowspanTable = (
const key = head.id;
const isMerged = head.mergeCell;
const value = row[key];
// 병합 대상이면 중복 렌더링 여부 판단
if (isMerged) {
const renderedSet = renderedMap.get(key) ?? new Set<number>();
@@ -152,7 +160,7 @@ export const chRowspanTable = (
onChange={(e) => {
handleChange(rowIndex, head.id, e.target.value);
}}
value={value ?? ""}
value={value || ""}
disabled={!selectedIds.includes(row.chkgdnPk)}
/>
) : (
@@ -174,8 +182,6 @@ export const chRowspanTable = (
);
};
export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean) => {
return headList.forEach((head) => {
if (head.edit !== undefined)
@@ -187,63 +193,123 @@ export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean)
});
}
const handleChange = (
rowIndex: number,
field: any,
value: string | number,
setInputData: (data:any) => void
setInputData: (data: any) => void
) => {
if(Number(value) < 0 ||! Number(value)){
value = 0;
}else{
if (Number(value) < 0 || !Number(value)) {
value = 0;
} else {
value = Number(value);
}
setInputData((prevData:any) =>
prevData?.map((row:any, index: number) => {
if (index === rowIndex) {
return {
...row,
[field ]: value,
};
}
return row;
})
);
setInputData((prevData: any) =>
prevData?.map((row: any, index: number) => {
if (index === rowIndex) {
return {
...row,
[field]: value,
};
}
return row;
})
);
};
;
export const InputTableBody = (chgRes: any[] | [] ,headList:TableUpperProps[], setInputData: (data: any[]) => void) => {
return (
export const InputTableBody = (
chgRes: any[] | [],
headList: TableUpperProps[],
setInputData: (data: any[]) => void
) => {
// mergeCell 처리용
const getRowSpan = (data: any[], key: string, rowIndex: number) => {
if (rowIndex > 0 && data[rowIndex][key] === data[rowIndex - 1][key]) {
return 0; // 이전과 같으면 셀을 그리지 않음
}
let span = 1;
for (let i = rowIndex + 1; i < data.length; i++) {
if (data[i][key] === data[rowIndex][key]) span++;
else break;
}
return span;
};
return (
<>
{chgRes.map((data, dataIndex) => (
<TableRow key={dataIndex + "row"}>
{headList.map((head, headIndex) => (
<TableCell key={head.id + headIndex} className="w-36" >
{head.edit ===true && data.edit !==false?
<Input
className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`}
onChange={(e) =>
handleChange(dataIndex, head.id, e.target.value,setInputData)
}
value={data[head.id as keyof any] ?? ""}
/> : (
<div
className={`
${head.id !== "utztnUsgCd" ? "text-right" : "text-center"}
!text-xl w-full h-10
`}
{chgRes.map((data, dataIndex) => {
// 소계/총합계 행 판별
const isSubTotal = data["용수명"] === "소계";
const isTotal = data["구분"] === 0;
const bgClass = isTotal
? "bg-[#d5e1eb] font-bold"
: isSubTotal
? "bg-[#e6eef5] font-semibold"
: "";
return (
<TableRow key={dataIndex + "row"}>
{headList.map((head, headIndex) => {
// 총합계 행이면 "구분"에서 colSpan=2로 병합
if (
data["구분"] === 0 &&
head.id === "구분"
) {
return (
<TableCell
key={head.id + headIndex}
colSpan={2}
className="font-bold text-center bg-[#d5e1eb]"
>
{data[head.id as keyof any] ?? ""}
</div>
)
총합계
</TableCell>
);
}
// 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음
if (
data["구분"] === 0 &&
head.id === "용수명"
) {
return null;
}
// 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] ?? ""}
</TableCell>
);
}
</TableCell>
))}
</TableRow>
))}
// 기본 셀
return head.edit === true && data.edit !== false ? (
<TableCell key={head.id + headIndex} className={`w-36 ${bgClass}`}>
<Input
className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`}
onChange={(e) =>
handleChange(dataIndex, head.id, e.target.value, setInputData)
}
value={data[head.id as keyof any] ?? ""}
/>
</TableCell>
) : (
<TableCell key={head.id + headIndex} className={`w-36 ${bgClass}`}>
<div
className={`
${head.id !== "utztnUsgCd" ? "text-right" : "text-center"}
!text-xl w-full h-10
`}
>
{data[head.id as keyof any] ?? ""}
</div>
</TableCell>
);
})}
</TableRow>
);
})}
</>
);
}
};
+47 -14
View File
@@ -9,12 +9,22 @@ import {
import type { RefObject } from "react";
export const getCity = (val: string, sggCd: SelectDataType[]) => {
const data = sggCd
.filter((item) => String(item.val).substring(0, 2) === val)
let data:any
if(val !=='0'){
data = sggCd
.filter((item) => String(item.val).substring(0, 2) === val)
.map((item) => ({
val: item.val,
text: item.text, // 한국어 텍스트
}));
}else{
data = sggCd
.map((item) => ({
val: item.val,
text: item.text, // 한국어 텍스트
}));
}
data.unshift({ val: "0", text: "전체" });
return data;
};
@@ -103,7 +113,18 @@ export const handleCommaNumberChange = (
) => {
const raw = e.target.value.replace(/,/g, "");
if (!/^\d*$/.test(raw)) return;
onChange(raw === "" ? "" : Number(raw));
onChange(raw === "" ? "" : Number(raw));
};
// onchange 텍스트를 숫자로 and ,제거
export const handleMinusNumberChange = (
e: React.ChangeEvent<HTMLInputElement>,
onChange: (value: number | "") => void
) => {
const raw = e.target.value.replace(/,/g, "");
if (!/^\d*$/.test(raw)) return;
onChange(raw === "" ? -1 : Number(raw));
};
// 숫자입력시 , 삽입
@@ -144,18 +165,30 @@ export const yearOptions: { val: string; text: string }[] = Array.from(
})
);
export const getdmdMatFlag = (flag: string|undefined) => {
let flagMat = "";
export const getdmdMatFlag = (flag: string | undefined | null) => {
const cleanFlag = (flag ?? "").trim();
if(flag === undefined || flag === null) {
flagMat = "신청";
}else if(flag.trim() === "Sub") {
flagMat = "검토";
}else if(flag.trim() === "matched") {
flagMat = "매칭완료";
}else {
flagMat = "신청";
switch (cleanFlag) {
case "Sub":
return "검토";
case "Matched":
return "매칭완료";
case "Checked":
return '검토완료';
default:
return "신청";
}
return flagMat;
};
export const formatPhoneNumber=(tel:string) => {
const onlyNums = tel.replace(/[^0-9]/g, '');
if (onlyNums.length === 10) {
return onlyNums.replace(/(\d{2})(\d{4})(\d{4})/, '$1-$2-$3');
} else if (onlyNums.length === 11) {
return onlyNums.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
} else {
return tel; // 유효하지 않으면 빈 문자열
}
}
@@ -22,8 +22,7 @@ import {
UiTable,
} from "@common/business_components/ui";
import PopoverUi from "@common/business_components/ui/popover_ui";
import { Button, Input, Label } from "@common/components/ui";
import type { read } from "fs";
import { Button, Checkbox, Input, Label } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import { type UseFormReturn } from "react-hook-form";
import toast from "react-hot-toast";
@@ -31,9 +30,11 @@ import toast from "react-hot-toast";
export default function ConCostForm({
form,
type,
selectionVersion,
}: {
form: UseFormReturn<DmdCoReqType>;
type: string;
selectionVersion: number;
}) {
const {
constCostRes,
@@ -46,6 +47,8 @@ export default function ConCostForm({
const ref = useRef<boolean>(false);
const [checkFinish, setCheckFinish] = useState<boolean>(false);
useEffect(() => {
if (!ref.current) {
const currentYear = new Date().getFullYear();
@@ -55,6 +58,13 @@ export default function ConCostForm({
}
}, [ref, getConstCostFee, getRateFee]);
useEffect(() => {
// 다른 행을 선택하면(selectionVersion 변경) 체크박스 상태를 초기화합니다.
setCheckFinish(false);
}, [selectionVersion]);
const zipDowonLoad = () => {
fetch(`/2024_constarctFeeProgram.zip`, {}).then(async (response) => {
const blobRet = await response.blob();
@@ -70,26 +80,40 @@ export default function ConCostForm({
const dmndQtyWatch = form.watch("dmndQty");
const totalConstCost = form.watch("totalConstCost");
const cstrnCst = form.watch("demandCst.cstrnCst");
const useUsgCdWatch = form.watch("useUsgCd");
const calculateConstCost = useCallback(() => {
const usgPrcsProcs = usgPrcsProcsWatch;
if (!dmndQtyWatch) {
toast.error("요구수량(M3/d)을 확인해주세요 계산할수 없습니다. ");
return;
}
if (usgPrcsProcs === null || usgPrcsProcs === undefined) {
toast.error(
"용도에 따른 처리공정을 확인할수 없습니다. 용도를 확인해주세요. "
);
return;
}
const dmndQtyYear = dmndQtyWatch * 365;
if (usgPrcsProcs && usgPrcsProcs?.length > 0) {
const firstProc = getConstFctCode(usgPrcsProcs?.split("+")[0] || "") || "";
const secondProc = getConstFctCode(usgPrcsProcs?.split("+")[1] || "") || "";
const firstProc =
getConstFctCode(usgPrcsProcs?.split("+")[0] || "") || "";
const secondProc =
getConstFctCode(usgPrcsProcs?.split("+")[1] || "") || "";
const { lower: firstLower, upper: firstUpper } = findBounds(
constCostRes,
firstProc || "",
'fctCd',
'fctCpc',
"fctCd",
"fctCpc",
Number(dmndQtyYear)
);
const { lower: secondLower, upper: secondUpper } = findBounds(
constCostRes,
secondProc || "",
'fctCd',
'fctCpc',
"fctCd",
"fctCpc",
Number(dmndQtyYear)
);
@@ -108,48 +132,62 @@ export default function ConCostForm({
const groupCodes = ["BD", "CE", "SE", "WD"];
const groupedBounds: { [key: string]: { lower?: any; upper?: any } } = {};
for (const code of groupCodes) {
groupedBounds[code] = findBounds(rateFeeRes, code, 'incExpCd', 'stdCost',result);
groupedBounds[code] = findBounds(
rateFeeRes,
code,
"incExpCd",
"stdCost",
result
);
}
const resultRate = transformAndInterpolate(groupedBounds, result);
const fcltSbsdCstrnCst = (result* (resultRate.BD + resultRate.CE + resultRate.SE + resultRate.WD) / 100);
const fcltSbsdCstrnCst =
(result *
(resultRate.BD + resultRate.CE + resultRate.SE + resultRate.WD)) /
100;
const realResult = result + fcltSbsdCstrnCst;
form.setValue("demandCst.prcsFcltCpctCstrnCst", Math.round(result) );
form.setValue("demandCst.fcltSbsdCstrnCst", Math.round(fcltSbsdCstrnCst)) ;
form.setValue("totalConstCost", Math.round(realResult));
form.setValue("demandCst.prcsFcltCpctCstrnCst", Math.round(result));
form.setValue("demandCst.fcltSbsdCstrnCst", Math.round(fcltSbsdCstrnCst));
form.setValue("totalConstCost", Math.round(realResult));
}
}, [constCostRes, rateFeeRes, usgPrcsProcsWatch, dmndQtyWatch]);
const onSubmit = (value: DmdCoReqType) => {
if( !form.getValues('demandCst.prcsFcltCpctCstrnCst') ){
toast.error('공사비 계산 진행 후 저장을 눌러주새요')
return
if (value.demandCst && !value.demandCst.prcsFcltCpctCstrnCst) {
toast.error("공사비 계산 진행 후 저장을 눌러주새요");
return;
}
if (type === "mat") {
const data: DedMatUpdateType = {
dmdInfoSn: form.getValues("dmdInfoSn"),
usgPrcsProcs: form.getValues("demandCst.usgPrcsProcs"),
cstrnCst: form.getValues("demandCst.cstrnCst"),
fcltSbsdCstrnCst: form.getValues("demandCst.fcltSbsdCstrnCst"),
prcsFcltCpctCstrnCst: form.getValues("demandCst.prcsFcltCpctCstrnCst"),
rgtr: TEST_UUID,
};
coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoFk"), data);
if (value.demandCst) {
const data: DedMatUpdateType = {
dmdInfoSn: value.dmdInfoSn,
usgPrcsProcs: value.demandCst.usgPrcsProcs || "",
cstrnCst: value.demandCst.cstrnCst || 0,
fcltSbsdCstrnCst: value.demandCst.fcltSbsdCstrnCst || 0,
prcsFcltCpctCstrnCst: value.demandCst.prcsFcltCpctCstrnCst || 0,
flg: checkFinish?'Checked':'Sub',
rgtr: TEST_UUID,
};
coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoFk"), data);
}
} else if (type === "hist") {
delete value.totalConstCost
delete value.ruseUtztnFcltNm
delete value.totalConstCost;
delete value.ruseUtztnFcltNm;
ruseRvwCalUpdate(value);
}
};
useEffect(() => {
console.log(" form ", form.formState.errors);
console.log(" form ", form.formState.errors);
}, [form.formState]);
useEffect(() => {
form.register("dmdInfoSn");
form.register("dmdInfoFk");
form.register("ruseUtztnFcltNm");
}, []);
return (
<>
<hr className="mt-8" />
@@ -163,18 +201,30 @@ export default function ConCostForm({
<Button className="mx-3" size={"sm"} onClick={calculateConstCost}>
계산
</Button>
<Button className="mr-3" size={"sm"} onClick={form.handleSubmit(onSubmit)}>
<Button
className="mr-3"
size={"sm"}
onClick={form.handleSubmit(onSubmit)}
>
저장
</Button>
<Label>관로 표준공사비 산정 프로그램</Label>
<Button
color="green"
size={"sm"}
onClick={zipDowonLoad}
className="bg-none ml-6"
>
다운로드
</Button>
<Label>검토완료</Label>
<Checkbox
className="ml-3 mr-6"
checked={checkFinish}
onCheckedChange={(checked) =>
// 'indeterminate' 상태를 무시하고 순수 boolean 값으로만 상태를 업데이트합니다.
setCheckFinish(checked === true)}
></Checkbox>
<Label>관로 표준공사비 산정 프로그램</Label>
<Button
color="green"
size={"sm"}
onClick={zipDowonLoad}
className="bg-none ml-6"
>
다운로드
</Button>
</div>
<div className="col-span-12 w-full">
<h1 className={formH1Class}>기본사항</h1>
@@ -255,7 +305,7 @@ export default function ConCostForm({
placeholder=""
type="text"
onChange={field.onChange}
value={form.getValues("demandCst.usgPrcsProcs") ?? ""}
value={field.value ?? ""}
className="mt-2"
/>
</FormUi>
@@ -285,13 +335,15 @@ export default function ConCostForm({
<div className="col-span-12 w-full">
<h1 className={formH1Class}>공사비 입력사항</h1>
</div>
<div className="col-span-3 mt-4">
<div className="col-span-2 mt-4">
<div className="flex items-center justify-between">
<PopoverUi
childrenTriger={
<>
<Label className="underline">
처리시설용량에 따른 공사비(백만원) <i className="diveicon di-search" />
처리시설용량에 따른 공사비(백만원){" "}
<i className="diveicon di-search" />
</Label>
</>
}
@@ -324,7 +376,7 @@ export default function ConCostForm({
)}
/>
</div>
<div className="col-span-3 mt-4">
<div className="col-span-2 mt-4">
<div className="flex items-center justify-between">
<PopoverUi
childrenTriger={
@@ -363,12 +415,13 @@ export default function ConCostForm({
)}
/>
</div>
<div className="col-span-3 mt-4">
<div className="col-span-2 mt-4">
<PopoverUi
childrenTriger={
<>
<Label className="underline">
총사업비 (백만원) <i className="diveicon di-search" />
처리시설 총사업비(백만원){" "}
<i className="diveicon di-search" />
</Label>
</>
}
@@ -405,7 +458,7 @@ export default function ConCostForm({
)}
/>
</div>
<div className="col-span-3 mt-4">
{/* <div className="col-span-3 mt-4">
<div className="flex items-center justify-between">
<Label>공급처 선정</Label>
<Button size={"sm"} onClick={(e) => {}} className="bg-none">
@@ -428,8 +481,8 @@ export default function ConCostForm({
</FormUi>
)}
/>
</div>
<div className="col-span-4 mt-4">
</div> */}
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="demandCst.cstrnCst"
@@ -448,7 +501,7 @@ export default function ConCostForm({
)}
/>
</div>
<div className="col-span-4 mt-4 mb-3">
<div className="col-span-3 mt-4 mb-3">
<Label className="text-xl">
처리시설 + 공급관로 총사업비(백만원)
</Label>
@@ -16,11 +16,10 @@ import {
type SelectDataType,
} from "@common/business_components";
import { Button, Checkbox, Input } from "@common/components";
import { Check } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useEffect, useState } from "react";
import { useFieldArray } from "react-hook-form";
export default function BdstReg({ form }: { form: any }) {
export default function BdstReg({ form, type }: { form: any; type?: string }) {
const { code } = useWrStore((state) => {
return state;
});
@@ -37,23 +36,16 @@ export default function BdstReg({ form }: { form: any }) {
bdstUsgCd: "",
});
};
// 잠깐 주석처리
// const removeLastItem = () => {
// if (fields.length > 0) {
// remove(fields.length - 1);
// }
// };
const removeSelected = () => {
const idxsToRemove = fields
.map((item, idx) => selectedIds.includes(item.id) ? idx : -1)
.filter(index => index > -1)
.sort((prevIndex, nextIndex) => nextIndex - prevIndex);
const idxsToRemove = fields
.map((item, idx) => (selectedIds.includes(item.id) ? idx : -1))
.filter((index) => index > -1)
.sort((prevIndex, nextIndex) => nextIndex - prevIndex);
remove(idxsToRemove);
setSelectedIds([]);
};
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>();
const [objSearch, setObjSearch] = useState<objSearchType>({
sgg: "",
@@ -90,18 +82,14 @@ export default function BdstReg({ form }: { form: any }) {
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const toggleSelect = (id: string) => {
setSelectedIds(prev =>
prev.includes(id)
? prev.filter(x => x !== id)
: [...prev, id]
setSelectedIds((prev) =>
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
);
};
return (
<>
<h1 className={formH1Class}>
건축물 시설 정보
</h1>
<h1 className={formH1Class}> { type !== "HTB"?"건축물 기본 정보": '발전소 기본 정보'}</h1>
<div className="grid grid-cols-6 gap-2 mt-4">
<div className="col-span-3">
<FormField
@@ -152,10 +140,10 @@ export default function BdstReg({ form }: { form: any }) {
control={form.control}
name="bdstNm"
render={({ field }) => (
<FormUi label="건축물명">
<FormUi label={ type !== "HTB"?"건축물명": '발전소명'}>
<Input
className={selectClass}
placeholder="1,000,000"
placeholder= {type !== "HTB"?"건축물 명 입력하세요":'발전소명 입력하세요' }
type="text"
{...field}
/>
@@ -168,10 +156,10 @@ export default function BdstReg({ form }: { form: any }) {
control={form.control}
name="daddr"
render={({ field }) => (
<FormUi label="위치">
<FormUi label= { type !== "HTB"?"건축물 주소": '발전소 주소'} >
<Input
className={selectClass}
placeholder=""
placeholder="위치를 입력해주세요"
type="search"
{...field}
/>
@@ -179,162 +167,176 @@ export default function BdstReg({ form }: { form: any }) {
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.bdstUsgCd"
render={({ field }) => (
<FormUi label="건축물용도">
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.bdstUsgCd}
onSelectValue={(val) => {
field.onChange(Number(val));
}}
value={field.value??code.bdstUsgCd[0]?.val}
/>
</FormUi>
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="frstArchPrmsnDt"
render={({ field }) => (
<FormUi label="최초건축허가일">
<FormUi label= { type !== "HTB"?"최초건축허가일": '준공년도'} >
<DatePicker
mode={"single"}
field={{
value: field.value?? new Date(),
value: field.value ?? new Date(),
onChange: (date: Date | undefined) => field.onChange(date),
}}
selectClass={'w-full'}
selectClass={"w-full"}
></DatePicker>
</FormUi>
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="archArea"
render={({ field }) => (
<FormUi label="건축면적(m³)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
/>
</FormUi>
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.lawTrgtYn"
render={({ field }) => (
<FormUi label="법정의무대상여부">
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={(val) => {
field.onChange(val);
}}
value={field.value??code.yn[0]?.val }
/>
</FormUi>
)}
/>
</div>
</div>
<h1 className={formH1Class}>
중축, 개축, 재축
</h1>
<div className="flex justify-end gap-2 mt-4">
<Button type="button" className="" size={"sm"} onClick={plusHist}>
이력추가
</Button>
<Button
type="button"
className="!bg-red-500 text-white"
size={"sm"}
onClick={removeSelected}
>
삭제
</Button>
</div>
{fields.map((field, index) => (
<div key={field.id} className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center">
<div className="col-span-1 flex justify-center mr-4">
<Checkbox
checked={selectedIds.includes(field.id)}
onCheckedChange={() => toggleSelect(field.id)}
/>
</div>
<div className="">
<FormField
control={form.control}
name={`chgBuilding.${index}.bdstChgNm`}
render={({ field: f }) => (
<FormUi label="구분">
<SelectBox
selectClass={selectClass}
selectArray={code.chBuCd}
onSelectValue={val => f.onChange(val)}
value={f.value ?? code.chBuCd[0]?.val} className={""} label={""} />
</FormUi>
)}
/>
</div>
<div className="">
<FormField
control={form.control}
name={`chgBuilding.${index}.archChgPrmsnDt`}
render={({ field: f }) => (
<FormUi label="허가일">
<DatePicker
mode="single"
field={{
value: safeDate(f.value) || new Date(),
onChange: (date) => f.onChange(date),
}}
selectClass="w-full"
{type !== "HTB" ? (
<>
<div className="grid grid-cols-6 gap-2 mt-4 ">
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.bdstUsgCd"
render={({ field }) => (
<FormUi label="건축물용도">
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.bdstUsgCd}
onSelectValue={(val) => {
field.onChange(Number(val));
}}
value={field.value ?? code.bdstUsgCd[0]?.val}
/>
</FormUi>
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="archArea"
render={({ field }) => (
<FormUi label="건축면적(m³)">
<Input
className={selectClass}
placeholder="면적을 입력하세요"
type="text"
onChange={(e) => {
field.onChange(e.target.value)
}}
value={field.value}
/>
</FormUi>
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.lawTrgtYn"
render={({ field }) => (
<FormUi label="법정의무대상여부">
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={(val) => {
field.onChange(val);
}}
value={field.value ?? code.yn[0]?.val}
/>
</FormUi>
)}
/>
</div>
</div>
<h1 className={formH1Class}>중축, 개축, 재축</h1>
<div className="flex justify-end gap-2 mt-4">
<Button type="button" className="" size={"sm"} onClick={plusHist}>
이력추가
</Button>
<Button
type="button"
className="!bg-red-500 text-white"
size={"sm"}
onClick={removeSelected}
>
삭제
</Button>
</div>
{fields.map((field, index) => (
<div
key={field.id}
className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center"
>
<div className="col-span-1 flex justify-center mr-4">
<Checkbox
checked={selectedIds.includes(field.id)}
onCheckedChange={() => toggleSelect(field.id)}
/>
</FormUi>
)}
/>
</div>
<div className="">
<FormField
control={form.control}
name={`chgBuilding.${index}.archChgArea`}
render={({ field: f }) => (
<FormUi label="면적">
<Input
placeholder="-"
type="text"
onChange={e => handleCommaNumberChange(e, f.onChange)}
value={formatCommaNumber(f.value)}
className={selectClass}
</div>
<div className="">
<FormField
control={form.control}
name={`chgBuilding.${index}.bdstChgNm`}
render={({ field: f }) => (
<FormUi label="구분">
<SelectBox
selectClass={selectClass}
selectArray={code.chBuCd}
onSelectValue={(val) => f.onChange(val)}
value={f.value ?? code.chBuCd[0]?.val}
className={""}
label={""}
/>
</FormUi>
)}
/>
</FormUi>
)}
/>
</div>
</div>
))}
<div className="border-b border-gray-300 my-4"> </div>
</div>
<div className="">
<FormField
control={form.control}
name={`chgBuilding.${index}.archChgPrmsnDt`}
render={({ field: f }) => (
<FormUi label="허가일">
<DatePicker
mode="single"
field={{
value: safeDate(f.value) || new Date(),
onChange: (date) => f.onChange(date),
}}
selectClass="w-full"
/>
</FormUi>
)}
/>
</div>
<div className="">
<FormField
control={form.control}
name={`chgBuilding.${index}.archChgArea`}
render={({ field: f }) => (
<FormUi label="면적">
<Input
placeholder="-"
type="text"
onChange={(e) => f.onChange}
value={f.value}
className={selectClass}
/>
</FormUi>
)}
/>
</div>
</div>
))}
<div className="border-b border-gray-300 my-4"> </div>
</>
) : (
<></>
)}
</>
);
}
@@ -23,15 +23,18 @@ import {
handleCommaNumberChange,
} from "@/components/lib/func/commom";
import { formH1Class } from "@/components/lib/class/comClass";
import toast from "react-hot-toast";
export default function HtdflRegForm({
htdflForm,
isModal,
readonly = false
readonly = false,
setIsModal,
}: {
htdflForm: customHtdflBdst;
isModal: boolean;
readonly?: boolean;
setIsModal?: (modal: boolean) => void;
}) {
const { code, htdflBdstUpdate, htdflBdstReg } = useWrStore((state) => state);
@@ -41,16 +44,24 @@ export default function HtdflRegForm({
resolver: zodResolver(hdtflZod),
defaultValues: defaultValues,
});
const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]);
const onSubmit = (values: z.infer<typeof hdtflZod>) => {
if (isModal) {
htdflBdstReg(values, '41');
const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd";
if (data === "noCd") {
toast.error("시도/시군구 코드를 선택해야합니다.");
return;
}
htdflBdstReg(values,data);
if (setIsModal) setIsModal(false);
} else {
htdflBdstUpdate(values, '41');
htdflBdstUpdate(values, "41");
}
};
const cleanHtdflData = (raw: any): z.infer<typeof hdtflZod> => {
return {
...raw,
@@ -80,9 +91,31 @@ export default function HtdflRegForm({
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
// form.reset은 비동기로 동작할 수 있어, useEffect 하나로 관리하여 의도치 않은 초기화를 방지합니다.
useEffect(() => {
if (hdtflZod) form.reset(cleanHtdflData(htdflForm));
}, [htdflForm]);
// Case 1: 수정 또는 '복사하여 등록' 등 데이터가 주입되는 경우
if (htdflForm && Object.keys(htdflForm).length > 0) {
form.reset(cleanHtdflData(htdflForm));
}
// Case 2: 데이터가 없는 순수 신규 등록 모드인 경우
if(isModal) {
const firstYnValue = code.yn?.[0]?.val;
const firstHtdPowerMthdCd = code.htdPowerMthdCd?.[0]?.val;
const firstHtdUtztnUsgCd = code.htdUtztnUsgCd?.[0]?.val;
if (firstHtdPowerMthdCd) {
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 });
}
if (firstHtdUtztnUsgCd) {
form.setValue('reuseBuilding.0.htdflObj.utztnUsg', firstHtdUtztnUsgCd, { shouldDirty: true });
}
}
}, [htdflForm, code, form]);
return (
<div className="!mx-[1.6rem] !p-0r">
@@ -91,20 +124,30 @@ export default function HtdflRegForm({
{/* <div className="flex justify-between items-center mx-3"> */}
<div>
<div className="grid grid-cols-12 flex items-center card-header">
<h1 className="text-2xl font-medium text-label col-span-10">온배수 시설 정보</h1>
<h1 className="text-2xl font-medium text-label col-span-10">
온배수 시설 등록
</h1>
{!readonly && (
<Button type="submit" className="col-start-12 col-span-1" size={"sm"}>
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
)}
</div>
</div>
{isModal && htdflForm != undefined ? <BdstReg form={form} /> : <></>}
{isModal && htdflForm != undefined ? (
<BdstReg form={form} type="HTB" />
) : (
<></>
)}
{isModal ? (
<h1 className="text-xl col-span-10 mt-4">
온배수 시설 정보{" "}
</h1>
<div className=" my-4">
<h1 className={formH1Class}>온배수 시설 정보 </h1>
</div>
) : (
<></>
)}
@@ -115,15 +158,14 @@ export default function HtdflRegForm({
control={form.control}
name="reuseBuilding.0.htdflObj.etgtType"
render={({ field }) => (
<FormUi label="발전유형(코드정비후 수정)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
<FormUi label="발전유형">
<SelectBox
className={""}
label={""}
selectClass={selectClass}
selectArray={code.htdPowerMthdCd}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e)
}}
readOnly={readonly}
/>
</FormUi>
@@ -136,13 +178,14 @@ export default function HtdflRegForm({
control={form.control}
name="reuseBuilding.0.htdflObj.fclCpct" // 이름 이상함.
render={({ field }) => (
<FormUi label="설비용량">
<FormUi label="설비용량(KW)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -162,8 +205,8 @@ export default function HtdflRegForm({
label={""}
selectClass={selectClass}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
value={field.value ?? code.yn[0]?.val}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
</FormUi>
@@ -172,9 +215,7 @@ export default function HtdflRegForm({
</div>
</div>
<div className=" my-4">
<h1 className={formH1Class}>
온배수 시설 운영현황
</h1>
<h1 className={formH1Class}>온배수 시설 운영현황</h1>
</div>
<div className="grid grid-cols-10 gap-1 mt-4">
@@ -183,14 +224,14 @@ export default function HtdflRegForm({
control={form.control}
name="reuseBuilding.0.htdflObj.orgwtWtritSpt"
render={({ field }) => (
<FormUi label="원수취수 지점(코드정비후 수정)">
<FormUi label="원수취수 지점">
<Input
className={selectClass}
placeholder="1,000,000"
placeholder=""
type="text"
value={field.value ?? 0}
value={field.value ?? ''}
onChange={(e) => {
if (!readonly) field.onChange(Number(e.target.value));
if (!readonly) field.onChange((e.target.value));
}}
readOnly={readonly}
/>
@@ -206,11 +247,11 @@ export default function HtdflRegForm({
<FormUi label="원수발생 공정">
<Input
className={selectClass}
placeholder="1,000,000"
type=""
placeholder=""
type="text"
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange
if (!readonly) field.onChange(e.target.value);
}}
readOnly={readonly}
/>
@@ -223,13 +264,35 @@ export default function HtdflRegForm({
control={form.control}
name="reuseBuilding.0.htdflObj.wtritEntrcTp"
render={({ field }) => (
<FormUi label="취수구 온도">
<FormUi label="취수구 온도(℃)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
/>
</FormUi>
)}
/>
</div>
<div className="col-span-5">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.emsnExitTp"
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}
@@ -249,7 +312,8 @@ export default function HtdflRegForm({
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -263,14 +327,14 @@ export default function HtdflRegForm({
control={form.control}
name="reuseBuilding.0.htdflObj.prcsProcsYn"
render={({ field }) => (
<FormUi label="처리공정">
<FormUi label="처리공정 유무">
<SelectBox
className={""}
label={""}
selectClass={selectClass}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
value={field.value ?? code.yn[0]?.val}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
</FormUi>
@@ -288,7 +352,8 @@ export default function HtdflRegForm({
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -308,8 +373,8 @@ export default function HtdflRegForm({
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
value={field.value ?? code.yn[0]?.val}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
readOnly={readonly}
/>
</FormUi>
@@ -327,7 +392,8 @@ export default function HtdflRegForm({
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -342,14 +408,13 @@ export default function HtdflRegForm({
name="reuseBuilding.0.htdflObj.utztnUsg"
render={({ field }) => (
<FormUi label="이용용도">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.htdUtztnUsgCd}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? ""}
onChange={() => {
if (!readonly) field.onChange
}}
readOnly={readonly}
/>
</FormUi>
@@ -359,9 +424,7 @@ export default function HtdflRegForm({
</div>
<div className=" my-2">
<h1 className={formH1Class}>
요구수질
</h1>
<h1 className={formH1Class}>수질</h1>
</div>
<div className="grid grid-cols-12 gap-4">
@@ -376,7 +439,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -397,7 +461,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -420,7 +485,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -441,7 +507,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -464,7 +531,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -485,7 +553,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -508,7 +577,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -529,7 +599,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -552,7 +623,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -573,7 +645,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -596,7 +669,8 @@ export default function HtdflRegForm({
placeholder="10"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
if (!readonly)
handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
@@ -606,26 +680,6 @@ export default function HtdflRegForm({
/>
</div>
<div className="col-span-6">
<FormField
control={form.control}
name="reuseBuilding.0.htdflObj.emsnExitTp"
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}
/>
</FormUi>
)}
/>
</div>
</div>
</form>
</Form>
@@ -30,7 +30,11 @@ import { Button, DataTable, Input, Label } from "@common/components";
import { useEffect, useRef, useState } from "react";
import { useFieldArray, useForm, type UseFormReturn } from "react-hook-form";
import MngRegFormDetail from "../mngReg/mngRegFormDetail/mngRegFormDetail";
import { safeDate } from "@/components/lib/func/commom";
import {
formatCommaNumber,
handleCommaNumberChange,
safeDate,
} from "@/components/lib/func/commom";
import SearchInputText from "@/components/ui/searchInput/searchInput";
import SdmInsertForm from "@common/business_components/ui/sdmInsertForm";
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
@@ -82,54 +86,55 @@ export function PbnstBuseForm({
}>({ isMoal: false, data: {} as DemandCompType });
useEffect(() => {
const etc= isNaN(Number(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`)))
const etc = isNaN(
Number(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`))
);
let total =
(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.gvsbs`) ?? 0) +
(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.lcep`) ?? 0) +
(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cusrAlotm`) ?? 0)
if( !etc ) {
total+=Number(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`))
}
(form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cusrAlotm`) ?? 0);
if (!etc) {
total += Number(
form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`)
);
}
form.setValue(`items.${indexMng}.fcBizs.${indexBiz}.totalMoney`, total);
}, [
form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.gvsbs`),
form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.lcep`),
form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.cusrAlotm`),
form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`)
form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.etc`),
]);
const fcOrgwts = form.watch(`items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`);
const fcOrgwts = form.watch( `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`)
useEffect(() => {
console.log("fcOrgwts", fcOrgwts);
if (fcOrgwts && fcOrgwts?.length > 0) {
const swtrmtFcltFkList = fcOrgwts?.map((item) => item.swtrmtFcltFk);
useEffect(() =>{
console.log("swtrmtFcltFkList ", swtrmtFcltFkList);
console.log('fcOrgwts ', fcOrgwts)
if(fcOrgwts&&fcOrgwts?.length>0){
const swtrmtFcltFkList = fcOrgwts.map((item) => item.swtrmtFcltFk);
console.log('swtrmtFcltFkList ', swtrmtFcltFkList)
if(swtrmtFcltFkList.length > 0){
getFcOrgwts(swtrmtFcltFkList.filter((item): item is string => item != null), fcOrgwts?.length)
if (swtrmtFcltFkList.length > 0) {
getFcOrgwts(
swtrmtFcltFkList.filter((item): item is string => item != null),
fcOrgwts?.length
);
}
}
},[fcOrgwts])
useEffect(() =>{
}, [fcOrgwts]);
useEffect(() => {
if (fcOrgwtsNmList && fcOrgwtsNmList.length > 0) {
console.log('fcOrgwtsNmList ', fcOrgwtsNmList)
console.log('fcOrgwts ', fcOrgwts)
fcOrgwts?.forEach((item, index) => {
const orgwtNm = fcOrgwtsNmList.find(
(orgwt) => orgwt.bscFctCd === item.swtrmtFcltFk
)?.bscFctNm;
console.log('orgwtNm ', orgwtNm)
console.log("orgwtNm ", orgwtNm);
if (orgwtNm) {
form.setValue(
`items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts.${index}.ruseUtztnFcltNm`,
@@ -137,10 +142,8 @@ export function PbnstBuseForm({
);
}
});
}
},[fcOrgwtsNmList,fcOrgwts])
}
}, [fcOrgwtsNmList, fcOrgwts]);
// fcBizs 데이터가 변경될 때마다 차수 선택 목록을 업데이트합니다.
useEffect(() => {
@@ -189,6 +192,23 @@ export function PbnstBuseForm({
name: `items.${indexMng}.fcBizs.${indexBiz}.fcDemands`,
});
const demandsContainerRef = useRef<HTMLDivElement>(null);
const prevDemandsLengthRef = useRef(fcDemands.length);
// 수요처 추가 시 새로 추가된 항목으로 스크롤하는 효과
useEffect(() => {
// 수요처 항목이 추가되었는지 확인 (길이가 이전보다 길어졌는지)
if (fcDemands.length > prevDemandsLengthRef.current) {
// 컨테이너의 마지막 자식 요소(새로 추가된 수요처 폼)로 부드럽게 스크롤
demandsContainerRef.current?.lastElementChild?.scrollIntoView({
behavior: "smooth",
block: "end",
});
}
// 다음 렌더링을 위해 현재 길이를 ref에 저장
prevDemandsLengthRef.current = fcDemands.length;
}, [fcDemands.length]);
const { fields: fcOrgwtFiled } = useFieldArray({
control: form.control,
name: `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`,
@@ -294,7 +314,6 @@ export function PbnstBuseForm({
setSumCpct(sum);
}, [form.formState, indexMng, indexBiz]);
const pbnstBiz = form.watch(`items.${indexMng}.fcBizs`);
return (
<>
@@ -347,7 +366,7 @@ export function PbnstBuseForm({
<MngRegFormDetail
key={`buziMoney-${indexMng}-${indexBiz}`}
formList={businessMoneyInfo}
h1Title={"사업비"}
h1Title={"사업비(원)"}
form={form}
moClass="grid grid-cols-12 gap-4"
sonClass="col-span-4"
@@ -400,6 +419,7 @@ export function PbnstBuseForm({
</div>
<RuseMngTable
key={`fcOrgwts-${indexMng}-${indexBiz}`} // 이게 핵심!
tableData={
form.getValues(
`items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`
@@ -425,7 +445,7 @@ export function PbnstBuseForm({
<Label className="text-right">합계</Label>
<Input
type="text"
value={sumCpct}
value={ formatCommaNumber(sumCpct)}
readOnly={true}
className="w-32 border-gray-300 rounded pr-8 "
/>
@@ -484,7 +504,8 @@ export function PbnstBuseForm({
<MngRegFormDetail
formList={ruseWaterQulityList}
h1Title={"하수처리수 재이용시설 보증수질"}
h1Title={`하수처리수 재이용시설 보증수질 `}
subTitle="※재처리시설이 있는 경우만 작성"
form={form}
moClass="grid grid-cols-12 gap-4"
sonClass="col-span-4"
@@ -504,7 +525,7 @@ export function PbnstBuseForm({
size={commonButonSize}
className="mt-6 mr-3"
>
수요항목 추가
수요처 추가
</Button>
<Button
type="button"
@@ -517,17 +538,14 @@ export function PbnstBuseForm({
size={commonButonSize}
className="mt-6"
>
수요처 추가
수요처 신규등록
</Button>
</div>
{(
form.getValues(
`items.${indexMng}.fcBizs.${indexBiz}.fcDemands`
) || []
).map((field, index) => (
<div ref={demandsContainerRef}>
{fcDemands.map((field, index) => (
<div
key={`fcDemands-${indexMng}-${indexBiz}=${index}`} // 이게 핵심!
className="grid grid-cols-12 gap-4 mt-3"
key={field.id} // useFieldArray의 고유 id를 key로 사용
className="grid grid-cols-12 gap-4 mt-3 border-b border-gray-400 pb-3"
>
<div key={index + "keySon1"} className="col-span-4">
<FormField
@@ -658,14 +676,14 @@ export function PbnstBuseForm({
control={form.control}
name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyCpct`}
render={({ field: f }) => (
<FormUi label="(계약)공급량(m3/일)">
<FormUi label="(계약)공급량(m³/일)">
<Input
placeholder=""
type="number"
value={f.value ?? 0}
type="text"
onChange={(e) => {
f.onChange(Number(e.target.value));
handleCommaNumberChange(e, f.onChange);
}}
value={formatCommaNumber(f.value)}
/>
</FormUi>
)}
@@ -691,9 +709,9 @@ export function PbnstBuseForm({
)}
/>
</div>
<br></br>
</div>
))}
))}
</div>
</div>
</form>
</Form>
@@ -705,6 +723,9 @@ export function PbnstBuseForm({
bodyClass={"w-[70vw] max-w-none max-h-[90vh] overflow-y-auto"}
body={
<FcOrgwtsRegModal
initTableData={form.getValues(
`items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`
) ?? []}
closeModal={() => {
setIsFcOrgwts(false);
}}
@@ -14,6 +14,7 @@ import { Input } from "@common/components/ui";
export default function MngRegFormDetail({
formList,
h1Title,
subTitle,
form,
moClass,
sonClass,
@@ -22,6 +23,7 @@ export default function MngRegFormDetail({
}: {
formList: formDetailType[];
h1Title?: string;
subTitle?:string
form: any;
moClass?: string;
indexBiz?: number;
@@ -33,6 +35,8 @@ export default function MngRegFormDetail({
return (
<>
{h1Title ? <h1 className={formH1Class}>{h1Title}</h1> : <></>}
{subTitle ? <h3 className={'items-center'}>{subTitle}</h3> : <></>}
<div className={moClass}>
{formList?.map((formHead, index) => {
const fieldId =
@@ -97,7 +101,7 @@ export default function MngRegFormDetail({
: []
}
onSelectValue={field.onChange}
value={field.value.trim()}
value={field.value?.trim() ?? (Array.isArray(potentialOptions) && potentialOptions[0]?.val )}
readOnly={formHead.option === "readOnly"}
/>
);
@@ -4,29 +4,32 @@ import { useWrStore } from "@/app/store";
import {
rainZod,
selectClass,
type customRainBdst
type customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { formH1Class, formH2Class } from "@/components/lib/class/comClass";
import {
formatCommaNumber,
handleCommaNumberChange,
handleMinusNumberChange,
} from "@/components/lib/func/commom";
import { DatePicker, FormUi } from "@common/business_components";
import { Form, FormField, SelectBox } from "@common/business_components/ui";
import { Button, Input } from "@common/components/ui";
import { Button, Checkbox, Input, Label } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
import BdstReg from "../bdstReg/bdstReg";
import toast from "react-hot-toast";
export default function RainRegForm({
rainForm,
isModal,
readonly = false
readonly = false,
setIsModal,
}: {
rainForm: customRainBdst;
isModal: boolean;
setIsModal?: (modal: boolean) => void;
readonly?: boolean;
}) {
const { code, rainBdstReg, rainBdstUpdate, rain } = useWrStore(
@@ -38,6 +41,7 @@ export default function RainRegForm({
resolver: zodResolver(rainZod),
defaultValues: defaultValues,
});
const instlCst = form.watch(`reuseBuilding.0.instlCst`);
const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn] = form.watch([
"reuseBuilding.0.grntchBdstCertYn",
@@ -69,7 +73,7 @@ export default function RainRegForm({
? item?.grntchBdstCertYr
: "", // null → ""
instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y"
grntchBdstCertYn:item?.grntchBdstCertYn??"Y",
grntchBdstCertYn: item?.grntchBdstCertYn ?? "Y",
rainyObj: {
...item?.rainyObj,
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y",
@@ -79,7 +83,6 @@ export default function RainRegForm({
};
useEffect(() => {
if (grntchBdstCertYn === "N") {
form.setValue("reuseBuilding.0.grntchBdstCertYr", "");
form.setValue("reuseBuilding.0.grntchBdstCertNo", "");
@@ -90,15 +93,24 @@ export default function RainRegForm({
form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctCpct", 0);
form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctPrs", "");
}
if (grntchBdstCertYn === "D") {
form.setValue("reuseBuilding.0.grntchBdstCertYr", "0000");
form.setValue("reuseBuilding.0.grntchBdstCertNo", "확인불가");
form.setValue("reuseBuilding.0.grntchBdstCertGrd", "확인불가");
} else if (instlCstSprtYn === "D") {
form.setValue("reuseBuilding.0.instlCstSprtAmt", -1);
} else if (filtrTrtmfctYn === "D") {
form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctCpct", -1);
form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctPrs", "확인불가");
}
}, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn]);
const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]);
// form 값이 변경될 때마다 로그 출력
useEffect(() => {
const subscription = form.watch((value) => {
});
const subscription = form.watch((value) => {});
return () => subscription.unsubscribe();
}, [form]);
@@ -108,7 +120,15 @@ export default function RainRegForm({
const onSubmit = (values: z.infer<typeof rainZod>) => {
if (isModal) {
rainBdstReg(values, "41");
const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd";
if (data === "noCd") {
toast.error("시도/시군구 코드를 선택해야합니다.");
return;
}
rainBdstReg(values, data);
if (setIsModal) setIsModal(false);
} else {
rainBdstUpdate(values, "41");
}
@@ -125,10 +145,14 @@ export default function RainRegForm({
<div>
<div className="grid grid-cols-12 flex items-center card-header">
<h1 className="text-2xl font-medium text-label col-span-10">
{isModal ? "건축물 운영정보" : "빗물이용시설 정보"}
{isModal ? "건축물 정보" : "빗물이용시설 정보"}
</h1>
{!readonly && (
<Button type="submit" className="col-start-12 col-span-1" size={"sm"}>
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
)}
@@ -142,12 +166,9 @@ export default function RainRegForm({
) : (
<></>
)}
<h1 className={formH1Class}>
기본정보
</h1>
<div className="grid grid-cols-4 gap-2 mt-4">
<div className="col-span-2">
<h1 className={formH1Class}>기본정보</h1>
<div className="grid grid-cols-6 gap-2 mt-4">
<div className="col-span-3">
<FormField
control={form.control}
name="reuseBuilding.0.instlCmptnDt"
@@ -160,7 +181,8 @@ export default function RainRegForm({
field.value && !isNaN(new Date(field.value).getTime())
? new Date(field.value)
: new Date(),
onChange: (date: Date | undefined) => field.onChange(date),
onChange: (date: Date | undefined) =>
field.onChange(date),
}}
selectClass={"w-full"}
readOnly={readonly}
@@ -170,48 +192,93 @@ export default function RainRegForm({
/>
</div>
<div className="col-span-2">
<div className="col-span-3">
<FormField
control={form.control}
name="reuseBuilding.0.instlCst"
render={({ field }) => (
<FormUi label="설치비">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
/>
</FormUi>
)}
name={`reuseBuilding.0.instlCst`}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<FormUi label="설치비(원)">
<Input
placeholder="1,000,000"
type="text"
className={selectClass}
readOnly={readonly}
value={
isUnknown ? "확인불가" : formatCommaNumber(value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
/>
</FormUi>
);
}}
/>
</div>
</div>
<div className="">
<h1 className={formH1Class}>
빗물이용시설 정보
</h1>
<h1 className={formH1Class}>빗물이용시설 정보</h1>
</div>
<div>
<h2 className={formH2Class}>집수면</h2>
<h2 className={formH2Class}>집수면 및 저류조</h2>
</div>
<div className="grid grid-cols-10 gap-4 mt-4 ">
<div className="col-span-5">
<div className="grid grid-cols-12 gap-4 mt-4 ">
<div className="col-span-4">
<FormField
control={form.control}
name="reuseBuilding.0.rainyObj.dtfcltCpct"
render={({ field }) => {
const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1
return (
<FormUi label="저류조 용량(m³)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
value={
isUnknown
? "확인불가"
: formatCommaNumber(field.value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
readOnly={readonly}
/>
</FormUi>
);
}}
/>
</div>
<div className="col-span-4">
<FormField
control={form.control}
name="reuseBuilding.0.rainyObj.pntfColKnd"
render={({ field }) => (
<FormUi label="종류">
<FormUi label="집수면 종류">
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={rainFcltCd}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? rainFcltCd[0]?.val}
readOnly={readonly}
/>
@@ -219,24 +286,39 @@ export default function RainRegForm({
)}
/>
</div>
<div className="col-span-5">
<div className="col-span-4">
<FormField
control={form.control}
name="reuseBuilding.0.rainyObj.pntfColArea"
render={({ field }) => (
<FormUi label="면적(m³)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
/>
</FormUi>
)}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<div className="flex items-center gap-2">
<FormUi label="집수면 용량(m³)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
value={
isUnknown ? "확인불가" : formatCommaNumber(value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
readOnly={readonly}
/>
</FormUi>
</div>
);
}}
/>
</div>
</div>
@@ -255,8 +337,8 @@ export default function RainRegForm({
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
selectArray={code.bdstFilterYn}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.yn[0]?.val}
readOnly={readonly}
/>
@@ -268,47 +350,66 @@ export default function RainRegForm({
<FormField
control={form.control}
name="reuseBuilding.0.rainyObj.filtrTrtmfctCpct"
render={({ field }) => (
<FormUi label="용량(m³/일)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly }
disabled={filtrTrtmfctYn !== "Y"}
/>
</FormUi>
)}
render={({ field }) => {
const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1
return (
<FormUi label="용량(m³/일)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
value={
isUnknown
? "확인불가"
: formatCommaNumber(field.value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
readOnly={readonly}
disabled={filtrTrtmfctYn !== "Y"}
/>
</FormUi>
);
}}
/>
</div>
<div className="col-span-4">
<FormField
control={form.control}
name="reuseBuilding.0.rainyObj.filtrTrtmfctPrs"
render={({ field }) => (
<FormUi label="처리공정">
<Input
className={selectClass}
placeholder=""
type="text"
value={field.value ?? ""}
onChange={field.onChange}
readOnly={readonly }
disabled={filtrTrtmfctYn !== "Y"}
/>
</FormUi>
)}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === "-"; // 또는 Number(value) === -1
return (
<div className="flex items-center gap-2">
<FormUi label="처리공정">
<Input
className={" h-full !text-xl col-span-4"}
placeholder="처리공정 입력"
type="text"
value={field.value ?? ""}
onChange={field.onChange}
readOnly={readonly}
disabled={filtrTrtmfctYn !== "Y"}
/>
</FormUi>
</div>
);
}}
/>
</div>
</div>
<div className=" my-2">
<h1 className={formH1Class}>
인센티브 정보
</h1>
<h1 className={formH1Class}>인센티브 정보</h1>
</div>
<div>
<h2 className={formH2Class}>설치비 지원</h2>
@@ -324,8 +425,8 @@ export default function RainRegForm({
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
selectArray={code.bdstIncenYn}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.yn[0]?.val}
readOnly={readonly}
/>
@@ -337,24 +438,37 @@ export default function RainRegForm({
<FormField
control={form.control}
name="reuseBuilding.0.instlCstSprtAmt"
render={({ field }) => (
<FormUi label="지원금액(원)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={instlCstSprtYn !== "Y"}
/>
</FormUi>
)}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<FormUi label="지원금액(원)">
<Input
className={selectClass}
placeholder=""
type="text"
readOnly={readonly || isUnknown}
value={
isUnknown ? "확인불가" : formatCommaNumber(value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
disabled={instlCstSprtYn !== "Y"}
/>
</FormUi>
);
}}
/>
</div>
</div>
<div>
<h2 className={formH2Class}>녹색건축물 인증</h2>
</div>
@@ -369,8 +483,8 @@ export default function RainRegForm({
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
selectArray={code.bdstIncenYn}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.yn[0]?.val}
/>
</FormUi>
@@ -381,40 +495,72 @@ export default function RainRegForm({
<FormField
control={form.control}
name="reuseBuilding.0.grntchBdstCertYr"
render={({ field }) => (
<FormUi label="인증년도">
<Input
className={selectClass}
placeholder="2024"
type=""
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e);
}}
readOnly={grntchBdstCertYn !== "Y"}
/>
</FormUi>
)}
render={({ field }) => {
const isUnknown =
field.value === null || field.value === "0000"; // 또는 Number(value) === -1
return (
<FormUi label="인증년도">
<Input
className={selectClass}
placeholder="2024"
type=""
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
value={isUnknown ? "확인불가" : (field.value ?? "")}
onChange={(e) => {
if (readonly) return;
if (e.target.value === "확인불가") {
field.onChange("0000");
} else {
field.onChange(e.target.value);
}
}}
disabled={grntchBdstCertYn !== "Y"}
max={4}
/>
</FormUi>
);
}}
/>
</div>
<div className="col-span-3 ">
<FormField
control={form.control}
name="reuseBuilding.0.grntchBdstCertNo"
render={({ field }) => (
<FormUi label="인증번호">
<Input
className={selectClass}
placeholder="ab1234678"
type=""
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e);
}}
readOnly={grntchBdstCertYn !== "Y"}
/>
</FormUi>
)}
render={({ field }) => {
const isUnknown =
field.value === null || field.value === "0000"; // 또는 Number(value) === -1
return (
<FormUi label="인증번호">
<Input
className={selectClass}
placeholder="ab1234678"
type=""
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
value={isUnknown ? "확인불가" : (field.value ?? "")}
onChange={(e) => {
if (readonly) return;
if (e.target.value === "확인불가") {
field.onChange("");
} else {
field.onChange(e.target.value);
}
}}
disabled={grntchBdstCertYn !== "Y"}
/>
</FormUi>
);
}}
/>
</div>
<div className="col-span-3">
@@ -423,15 +569,14 @@ export default function RainRegForm({
name="reuseBuilding.0.grntchBdstCertGrd"
render={({ field }) => (
<FormUi label="인증등급">
<Input
className={selectClass}
placeholder="A"
type=""
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e);
}}
readOnly={grntchBdstCertYn !== "Y"}
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.bdstGrntchClass}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.bdstGrntchClass[0]?.val}
readOnly={readonly}
/>
</FormUi>
)}
@@ -10,6 +10,7 @@ import { formH1Class, formH2Class } from "@/components/lib/class/comClass";
import {
formatCommaNumber,
handleCommaNumberChange,
handleMinusNumberChange,
} from "@/components/lib/func/commom";
import {
DatePicker,
@@ -21,7 +22,7 @@ import {
import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { useForm, type UseFormReturn } from "react-hook-form";
import { z } from "zod";
import BdstReg from "../bdstReg/bdstReg";
@@ -29,7 +30,7 @@ export default function RswtrRegForm({
rswtForm,
isModal,
setIsModal,
readonly = false
readonly = false,
}: {
rswtForm: customRswtBdst;
isModal: boolean;
@@ -56,12 +57,16 @@ export default function RswtrRegForm({
const onSubmit = (values: z.infer<typeof rswtZod>) => {
if (isModal) {
rswtBdstReg(values, "41");
if(setIsModal) setIsModal(false)
if (setIsModal) setIsModal(false);
} else {
rswtBdstUpdate(values, "41");
}
};
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => {
const filtrTrtmfctCpct = form.watch('reuseBuilding.0.rswtrObj.filtrTrtmfctCpct')
const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => {
console.log('raw ', raw)
return {
...raw,
frstArchPrmsnDt: raw?.frstArchPrmsnDt
@@ -73,21 +78,28 @@ export default function RswtrRegForm({
reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({
...item,
instlCmptnDt: item?.instlCmptnDt
? new Date(item.instlCmptnDt)
: new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화
operMngCd: item?.operMngCd ?? "", // null → ""
instlCstSprtYn: item?.instlCstSprtYn ?? "Y", // null → "Y"
grntchBdstCertYn:item?.grntchBdstCertYn??"Y",
rswtrObj: {
? new Date(item.instlCmptnDt)
: new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화
operMngCd: item?.operMngCd ?? "", // null → ""
instlCstSprtYn: item?.instlCstSprtYn || code.yn[0]?.val, // null → "Y"
grntchBdstCertYn: item?.grntchBdstCertYn|| code.yn[0]?.val,
rswtrObj: {
...item?.rswtrObj,
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn ?? "Y",
filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn || code.yn[0]?.val,
filtrTrtmfctCpct: item?.rswtrObj?.filtrTrtmfctCpct ?? null,
filtrTrtmfctProcs: item?.rswtrObj?.filtrTrtmfctProcs || code.rswtPrscCdMthdCd[0]?.val,
orgwtKndCd: item?.rswtrObj?.orgwtKndCd || code.orgwtKndCd[0]?.val,
},
})),
};
};
// useEffect(() =>{
// console.log(' formform ', form.watch())
// },[form.formState])
useEffect(() =>{
console.log(' filtrTrtmfctCpct ', filtrTrtmfctCpct)
},[filtrTrtmfctCpct])
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
@@ -99,6 +111,16 @@ export default function RswtrRegForm({
} else if (instlCstSprtYn === "N") {
form.setValue("reuseBuilding.0.instlCstSprtAmt", 0);
}
if (grntchBdstCertYn === "D") {
form.setValue("reuseBuilding.0.grntchBdstCertYr", "0000");
form.setValue("reuseBuilding.0.grntchBdstCertNo", "확인불가");
form.setValue("reuseBuilding.0.grntchBdstCertGrd", "확인불가");
} else if (instlCstSprtYn === "D") {
form.setValue("reuseBuilding.0.instlCstSprtAmt", -1);
}
}, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs, form]);
useEffect(() => {
@@ -116,7 +138,11 @@ export default function RswtrRegForm({
건축물 운영정보
</h1>
{!readonly && (
<Button type="submit" className="col-start-12 col-span-1" size={"sm"}>
<Button
type="submit"
className="col-start-12 col-span-1"
size={"sm"}
>
저장
</Button>
)}
@@ -155,68 +181,37 @@ export default function RswtrRegForm({
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.instlCst"
render={({ field }) => (
<FormUi label="설치비">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
/>
</FormUi>
)}
/>
</div>
</div>
<div className="grid grid-cols-4 gap-2 mt-4">
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.rswtrObj.wtrUsqty"
render={({ field }) => (
<FormUi label="물사용량(m³)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
/>
</FormUi>
)}
/>
</div>
<div className="col-span-2">
<FormField
control={form.control}
name="reuseBuilding.0.rswtrObj.oblgTrgtWtrUsqty"
render={({ field }) => (
<FormUi label="의무대상 물사용량(m³)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={readonly}
/>
</FormUi>
)}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<FormUi label="설치비">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
value={
isUnknown ? "확인불가" : formatCommaNumber(value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
readOnly={readonly}
/>
</FormUi>
);
}}
/>
</div>
</div>
@@ -229,20 +224,36 @@ export default function RswtrRegForm({
<FormField
control={form.control}
name="reuseBuilding.0.rswtrObj.filtrTrtmfctCpct"
render={({ field }) => (
<FormUi label="처리시설 용량">
<Input
className={selectClass}
placeholder=""
type="number"
value={field.value ?? 0}
onChange={(e) => {
if (!readonly) field.onChange(Number(e.target.value));
}}
readOnly={readonly}
/>
</FormUi>
)}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<FormUi label="처리시설 용량">
<Input
className={selectClass}
placeholder=""
type="text"
value={
isUnknown ? "확인불가" : formatCommaNumber(value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
console.log('value')
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
readOnly={readonly}
/>
</FormUi>
);
}}
/>
</div>
<div className="col-span-4">
@@ -256,7 +267,7 @@ export default function RswtrRegForm({
label={""}
selectClass={selectClass}
selectArray={code.orgwtKndCd}
onSelectValue={readonly ? () => { } : field.onChange}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.orgwtKndCd[0]?.val}
readOnly={readonly}
/>
@@ -270,14 +281,13 @@ export default function RswtrRegForm({
name="reuseBuilding.0.rswtrObj.filtrTrtmfctProcs"
render={({ field }) => (
<FormUi label="주요처리공정">
<Input
className={selectClass}
placeholder=""
type=""
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange
}}
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.rswtPrscCdMthdCd}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.rswtPrscCdMthdCd[0]?.val}
readOnly={readonly}
/>
</FormUi>
@@ -303,9 +313,9 @@ export default function RswtrRegForm({
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
value={field.value ?? code.yn[0]?.val}
selectArray={code.bdstIncenYn}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.bdstIncenYn[0]?.val}
readOnly={readonly}
/>
</FormUi>
@@ -313,23 +323,37 @@ export default function RswtrRegForm({
/>
</div>
<div className="col-span-1">
<FormField
<FormField
control={form.control}
name="reuseBuilding.0.instlCstSprtAmt"
render={({ field }) => (
<FormUi label="지원금액(원)">
<Input
className={selectClass}
placeholder="1,000,000"
type="text"
onChange={(e) => {
if (!readonly) handleCommaNumberChange(e, field.onChange);
}}
value={formatCommaNumber(field.value)}
readOnly={instlCstSprtYn !== "Y"}
/>
</FormUi>
)}
render={({ field }) => {
const value = field.value;
const isUnknown = value === null || value === -1; // 또는 Number(value) === -1
return (
<FormUi label="지원금액(원)">
<Input
className={selectClass}
placeholder=""
type="text"
readOnly={readonly || isUnknown}
value={
isUnknown ? "확인불가" : formatCommaNumber(value)
}
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
onChange={(e) => {
if (readonly) return;
handleMinusNumberChange(e, field.onChange);
}}
disabled={instlCstSprtYn === "N"||instlCstSprtYn === "D"}
/>
</FormUi>
);
}}
/>
</div>
</div>
@@ -348,9 +372,9 @@ export default function RswtrRegForm({
className={""}
selectClass={selectClass}
label={""}
selectArray={code.yn}
onSelectValue={readonly ? () => { } : field.onChange}
value={field.value ?? code.yn[0]?.val}
selectArray={code.bdstIncenYn}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value || code.yn[0]?.val}
readOnly={readonly}
/>
</FormUi>
@@ -361,41 +385,75 @@ export default function RswtrRegForm({
<FormField
control={form.control}
name="reuseBuilding.0.grntchBdstCertYr"
render={({ field }) => (
render={({ field }) =>
{
const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1
return (
<FormUi label="인증년도">
<Input
className={selectClass}
placeholder="2024"
type="text"
{...field}
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e)
type=""
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
readOnly={grntchBdstCertYn !== "Y"}
value={
isUnknown?'확인불가':field.value ?? ""}
onChange={(e) => {
if (readonly) return
if (e.target.value === '확인불가') {
field.onChange('0000');
}else{
field.onChange(e.target.value);
}
}}
disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"}
max={4}
/>
</FormUi>
)}
)}}
/>
</div>
<div className="col-span-3">
<FormField
control={form.control}
name="reuseBuilding.0.grntchBdstCertNo"
render={({ field }) => (
render={({ field }) =>
{
const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1
return (
<FormUi label="인증번호">
<Input
className={selectClass}
placeholder="ab1234678"
type=""
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e)
onFocus={() => {
// 입력 시 자동으로 확인불가 해제
if (isUnknown && !readonly) {
field.onChange(""); // 초기화
}
}}
readOnly={grntchBdstCertYn !== "Y"}
value={
isUnknown?'확인불가':field.value ?? ""}
onChange={(e) => {
if (readonly) return
if (e.target.value === '확인불가') {
field.onChange('');
}else{
field.onChange(e.target.value);
}
}}
disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"}
/>
</FormUi>
)}
)}}
/>
</div>
<div className="col-span-3">
@@ -404,15 +462,14 @@ export default function RswtrRegForm({
name="reuseBuilding.0.grntchBdstCertGrd"
render={({ field }) => (
<FormUi label="인증등급">
<Input
className={selectClass}
placeholder="A"
type=""
value={field.value ?? ""}
onChange={(e) => {
if (!readonly) field.onChange(e)
}}
readOnly={grntchBdstCertYn !== "Y"}
<SelectBox
className={""}
selectClass={selectClass}
label={""}
selectArray={code.bdstGrntchClass}
onSelectValue={readonly ? () => {} : field.onChange}
value={field.value ?? code.bdstGrntchClass[0]?.val}
readOnly={readonly}
/>
</FormUi>
)}
@@ -1,41 +1,46 @@
import { useWrStore } from "@/app/store";
import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import { excelToRainChkData } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel";
import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import {
excelToRswtGuideData,
excelToRswtPolution,
} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import {
filePicked,
filePickedArray,
FileUpload,
Form,
FormField,
FormUi,
SelectBox,
Title,
} from "@common/business_components/ui";
import { Card } from "@common/business_components/ui/chart/lib/card";
import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import type { z } from "zod";
export default function ChkgdExcel({ type }: { type: string }) {
const {
rswtChkgdn,
rainChkExcelDataUPload,
rswtChkExceDataUpload,
} = useWrStore((state) => {
return state;
});
const [files, setFiles] = useState<File[] | null>(null);
export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setIsRegExcel:(open:boolean) =>void }) {
const { rswtChkgdn, rainChkExcelDataUPload, rswtChkExceDataUpload } =
useWrStore((state) => {
return state;
});
const [excelData, setExcelData] = useState<
rswtChkZodType[] | rainChkZodType[]
>();
const [file, setFile] = useState<File | null>(null);
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = e.target.files?.[0];
if (selectedFile) {
setFile(selectedFile);
}
};
const [excelRswtData, setExcelRswtData] = useState<rswtChkZodType[]>();
const currentYear = new Date().getFullYear();
@@ -49,7 +54,7 @@ export default function ChkgdExcel({ type }: { type: string }) {
);
const defaultValues: z.infer<typeof chkgdRegExcel> = chkgdRegExcel.parse({
chckYr: String(currentYear)
chckYr: String(currentYear),
});
const form = useForm<z.infer<typeof chkgdRegExcel>>({
@@ -58,14 +63,10 @@ export default function ChkgdExcel({ type }: { type: string }) {
});
useEffect(() => {
if (files) {
const file = files[0];
if (file) {
if (form.getValues("chckYr").length < 1) {
ToastFormUi({
body: "파일업로드 이전에 등록년도를 작성해주세요 ",
title: "지도점검 등록",
});
setFiles(null);
toast.error("파일업로드 이전에 등록년도를 작성해주세요 ");
setFile(null);
return;
}
if (file)
@@ -87,7 +88,6 @@ export default function ChkgdExcel({ type }: { type: string }) {
form.getValues("chckYr")
);
const keyGenerator = (item: rswtChkZodType) =>
`${item.bdstRuseFcltFk}|${item.chckYmd}|${item.utztnUsgCd}`;
const totalData: rswtChkZodType[] = guideData.map((guide) => {
@@ -98,12 +98,11 @@ export default function ChkgdExcel({ type }: { type: string }) {
guide.utztnUsgCd === polution.utztnUsgCd
);
if (fusion) {
return {
...guide,
rswtrPollutions: fusion?.rswtrPollutions,
rswtrDetails:fusion?.rswtrDetails
rswtrDetails: fusion?.rswtrDetails,
};
} else {
return {
@@ -118,19 +117,17 @@ export default function ChkgdExcel({ type }: { type: string }) {
(item) => !guideKey.has(keyGenerator(item))
);
const listTotalData: rswtChkZodType[] = [
...totalData,
...onlypolution,
];
const listTotalData:rswtChkZodType[] =[
...totalData,
...onlypolution
]
setExcelRswtData(listTotalData);
setExcelRswtData(listTotalData);
}
});
}
}
}, [files]);
}, [file]);
function findMatchingItems<T>(
arrayA: T[],
@@ -144,34 +141,31 @@ export default function ChkgdExcel({ type }: { type: string }) {
(!condition || condition(item)) && bKeySet.has(keySelector(item))
);
}
const onSubmit = (values: z.infer<typeof chkgdRegExcel>) => {
if (values.chckYr === "") {
ToastFormUi({ body: "등록년도를 작성해주세요", title: "지도점검 등록" });
toast.error("등록년도를 작성해주세요");
return;
}
if (type === "RNB") {
if (excelData === undefined || excelData?.length === 0) {
ToastFormUi({
body: "빈 파일 및 파일 오류 입니다.",
title: "지도점검 등록",
});
toast.error("빈 파일 및 파일 오류 입니다.");
return;
} else {
rainChkExcelDataUPload(excelData as rainChkZodType[]);
setIsRegExcel(false)
}
} else if (type === "RST") {
if (excelRswtData === undefined || excelRswtData?.length === 0) {
ToastFormUi({
body: "빈 파일 및 파일 오류 입니다.",
title: "중수지도점검 등록",
});
toast.error("빈 파일 및 파일 오류 입니다.");
return;
} else {
rswtChkExceDataUpload(excelRswtData as rswtChkZodType[]);
setIsRegExcel(false)
}
}
};
@@ -223,13 +217,13 @@ export default function ChkgdExcel({ type }: { type: string }) {
name="file"
render={({ field }) => (
<FormUi label="점검결과 파일">
<FileUpload
files={files || []}
setFiles={(files: File[] | null) => {
if (files) setFiles(files);
}}
fileTypes="xlsx"
></FileUpload>
<div className="space-y-4 p-4">
<Input
type="file"
onChange={handleFileChange}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
/>
</div>
</FormUi>
)}
/>
@@ -1,16 +1,14 @@
import { useWrStore } from "@/app/store";
import { ScrollArea, Title } from "@common/business_components/ui";
import { Button } from "@common/components/ui";
import { useEffect, useState } from "react";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable";
import type { TableUpperProps } from "@/app/store/common/type/header";
import type { splRuseWaterType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { rswtrPolutionsZode } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList";
import { GuideDetailsTable } from "@/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable";
import { ScrollArea, Title } from "@common/business_components/ui";
import { Button } from "@common/components/ui";
import React, { useEffect, useState } from "react";
import type { z } from "zod";
import React from "react";
import type { TableUpperProps } from "@/app/store/common/type/header";
export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
export default function ChkgdModal({ type, obj, setIsModal }: { type: string; obj: any, setIsModal: (open: boolean) => void }) {
const {
rainChkgdn,
rswtChkgdn,
@@ -39,7 +37,6 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
"4": [] as z.infer<typeof rswtrPolutionsZode>[],
});
const { rainChk, ruseHeadList, splHeadList } = rainChkgdn;
const [updateData, setUpdateData] = useState<splRuseWaterType[]>();
const initStats = (): z.infer<typeof rswtrPolutionsZode> => ({
@@ -97,7 +94,6 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
target = { utztnUsgCd: code, ruseTotal: 0, splTotal: 0 };
acc.push(target);
}
// 월별 값 누적
target[ruseMonthKey] = (target[ruseMonthKey] ?? 0) + ruseValue;
target[splMonthKey] = (target[splMonthKey] ?? 0) + splValue;
@@ -106,7 +102,17 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
target.splTotal += splValue;
return acc;
}, []);
setGuidData(result);
if (result) {
// '기타' 항목을 배열의 맨 뒤로 정렬합니다.
result.sort((a: splRuseWaterType, b: splRuseWaterType) => {
if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다.
if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다.
return 0; // 순서를 유지합니다.
});
}
setGuidData(result as splRuseWaterType[]);
if (obj.rswtrPollutions) {
const resultPolution: Record<string, any[]> = {
@@ -159,6 +165,14 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
if (!resultPolution[nodeKey]) {
resultPolution[nodeKey] = [];
}
// '기타' 항목을 배열의 맨 뒤로 정렬합니다.
resultPolution[nodeKey].sort((a: any, b: any) => {
if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다.
if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다.
return 0; // 순서를 유지합니다.
});
resultPolution[nodeKey].push(average);
});
@@ -200,12 +214,14 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
obj.guideDetails = realGuideDetail;
if (type === "RNB") {
rainChkGuidUpdate(obj);
setIsModal(false)
} else {
const polution = Object.values(upPolutionData)
.flat()
.filter((item) => item.utztnUsgCd !== "평균");
obj.rswtrPollutions = polution;
rwstPolAndGuideUpdate([obj]);
setIsModal(false)
}
};
@@ -231,7 +247,8 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
</div>
<div className="flex justify-between">
<h3 className="text-2xl font-bold text-gray-900 mt-2 ml-6">
{`(${obj.bdstNm})`}
{type === "RNB"
? `(${obj.bdstNm})` : `(${obj.building.bdstNm})`}
</h3>
{!rainChkSttn.isSttn ? (
<Button className="" onClick={allDataUpdate}>
@@ -245,12 +262,13 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
<ScrollArea className="h-[60vh]">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
{`연간보급수이용량`}
{`연간대체수이용량`}
</h3>
</div>
<GuideDetailsTable
chgRes={guidData || []}
headList={headList.ruseHeadList}
headList={headList.splHeadList}
upheadList={type === "RNB" ? rainChkgdn.rainSplHeadNm : rswtChkgdn.rswtSplHeadNm}
type={""}
setChGuidData={(data) => {
setChGuidData(data);
@@ -263,7 +281,8 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
</div>
<GuideDetailsTable
chgRes={guidData || []}
headList={headList.splHeadList}
headList={headList.ruseHeadList}
upheadList={type === "RNB" ? rainChkgdn.rainRuseHeadNm : rswtChkgdn.rswtRuseHeadNm}
type={""}
setChGuidData={(data) => {
setChGuidData(data);
@@ -285,6 +304,7 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) {
<GuideDetailsTable
chgRes={value}
headList={headList?.rswtDetailHeadList}
upheadList={rswtChkgdn.rswtSplHeadNm}
type={""}
setChGuidData={(data) => {
getPolutionData(data);
@@ -18,12 +18,13 @@ import { Button, Input } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import toast from "react-hot-toast";
import type { z } from "zod";
export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelData}: { data: FcPrfType ,setIsExcelOPen:(open:boolean )=>void,setModalExcelData:(excelData :PrfType)=>void }) {
const { prfmnRegData } = useWrStore((state) => state);
const [files, setFiles] = useState<File[] | null>(null);
const [file, setFile] = useState<File | null>(null);
const [excelData, setExcelData] = useState<PrfType[]>();
const form = useForm<z.infer<typeof pbnPrfRegExcelZod>>({
resolver: zodResolver(pbnPrfRegExcelZod),
@@ -31,10 +32,20 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
ym: String(new Date().getFullYear()),
},
});
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const selectedFile = e.target.files?.[0];
if (selectedFile) {
setFile(selectedFile);
}
};
const onSubmit = (values: z.infer<typeof pbnPrfRegExcelZod>) => {
if (excelData) {
prfmnRegData(excelData as unknown as PrfType);
// prfmnRegData(1,'41', excelData as unknown as PrfType);
setModalExcelData(excelData as unknown as PrfType)
setIsExcelOPen(false)
}
@@ -46,111 +57,120 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) {
form.setValue("pbnstRuseFcltNm", data.ruseUtztnFcltNm);
}, [data]);
useEffect(() => {
console.log("excelData", excelData);
}, [excelData]);
useEffect(() => {
if (files) {
const file = files[0];
if (file) {
const isFile = file
if (form.getValues("ym").length < 1) {
ToastFormUi({
body: "파일업로드 이전에 등록년도를 작성해주세요 ",
title: "지도점검 등록",
});
setFiles(null);
toast.error("파일업로드 이전에 등록년도를 작성해주세요 " );
setFile(null);
return;
}
if (file)
filePicked(file, 0).then((res) => {
if (isFile) {
filePicked(isFile, 0).then((res) => {
if (res !== undefined)
setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"),form.getValues('pbnstRuseFcltFk') ) as PrfType[])
setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"), form.getValues('pbnstRuseFcltFk')) as PrfType[])
});
}
}
}, [files]);
}, [file]);
return (
<>
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<div>
<div className="flex justify-between items-center">
<Title title={"하수재이용 실적등록"}></Title>
</div>
<div className="flex justify-between">
<h3 className="text-2xl font-bold text-gray-900 mt-1 ml-7">
{"점검정보 입력"}
</h3>
<Button className="" type="submit">
<Button className="mr-6 mt-10" type="submit">
저장
</Button>
</div>
<h3 className="text-2xl font-bold text-gray-900 my-3 ml-7">
{"점검정보 입력"}
</h3>
<div>
<div className="mx-7">
<FormField
control={form.control}
name="ym"
render={({ field }) => (
<FormUi label="등록년도">
<SelectBox
className="w-1/4 text-3xl"
className="w-1/2 pr-4 text-3xl"
selectClass={""}
label=""
selectArray={yearOptions}
value={field.value||new Date().getFullYear()}
value={field.value || new Date().getFullYear()}
onSelectValue={(val) => field.onChange(val)}
/>
</FormUi>
)}
/>
<div className="flex gap-4 mt-4">
<div className="flex-1">
<FormField
control={form.control}
name="bscFctNm"
render={({ field }) => (
<FormUi label="시설명">
<Input
className="text-3xl"
value={field.value || ''}
onChange={field.onChange}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="flex-1">
<FormField
control={form.control}
name="pbnstRuseFcltNm"
render={({ field }) => (
<FormUi label="재이용시설명">
<Input
className="flex-1 text-3xl"
value={field.value || ''}
onChange={field.onChange}
readOnly
/>
</FormUi>
)}
/>
</div>
</div>
<div className="mt-4">
<FormField
control={form.control}
name="file"
render={({ field }) => (
<FormUi label="점검결과 파일">
{/* <FileUpload
files={files || []}
setFiles={(files: File[] | null) => {
if (files) setFiles(files);
}}
fileTypes="xlsx"
maxFiles={1}
<FormField
control={form.control}
name="bscFctNm"
render={({ field }) => (
<FormUi label="시설명">
<Input
className="w-1/4 text-3xl"
value={field.value||''}
onChange={field.onChange}
readOnly
/>
</FormUi>
)}
/>
<FormField
control={form.control}
name="pbnstRuseFcltNm"
render={({ field }) => (
<FormUi label="재이용시설명">
<Input
className="w-1/4 text-3xl"
value={field.value||''}
onChange={field.onChange}
readOnly
/>
</FormUi>
)}
/>
<FormField
control={form.control}
name="file"
render={({ field }) => (
<FormUi label="점검결과 파일">
<FileUpload
files={files || []}
setFiles={(files: File[] | null) => {
if (files) setFiles(files);
}}
fileTypes="xlsx"
maxFiles={1}
></FileUpload>
</FormUi>
)}
/>
></FileUpload> */}
<div className="space-y-4 p-4">
<Input
type="file"
onChange={handleFileChange}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
/>
</div>
</FormUi>
)}
/>
</div>
</div>
</form>
</Form>
@@ -3,25 +3,38 @@
import { btnClass } from "@/app/store/common/code"
import type { customDrgt } from "@/app/store/matDmd/drgtSttn"
import { drgtDetailHeadListExport } from "@/app/store/matDmd/drgtSttn/headList"
import { excelDownload } from "@/components/lib/func/commom"
import { Title, UiTable } from "@common/business_components/ui"
import { downloadExcel, Title, UiTable } from "@common/business_components/ui"
import ListDiv from "@common/business_components/ui/list_div"
import { Button } from "@common/components/ui"
import { useCallback, useEffect } from "react"
import { Button, ScrollArea } from "@common/components/ui"
import { useEffect, useState } from "react"
export default function DrgtDetailModal({
data,
}: {
data: customDrgt;
}) {
const excelClick = useCallback(() => {
excelDownload(
[[]],
"우리동네가뭄",
"sample_drgtSttn.xlsx",
"A1:H1"
);
}, []);
const [excelData, setExcelData] = useState<any[]>();
const excelClick = () => {
downloadExcel({
data: excelData ?? [],
fileName: "우리동네가뭄 상세현황",
sheetNameArray: ["Sheet1"],
headerRange: "A1:C1"
})
}
useEffect(() => {
const resData = Array.isArray(data) ? data : [data];
const exData = Array.isArray(resData)
? resData.map((item: customDrgt) => {
return {
"년": item.year,
"월": item.month,
"가뭄상태": item.drgtState,
}
}) : [];
setExcelData(exData)
}, [data])
return (
<>
@@ -43,15 +56,17 @@ export default function DrgtDetailModal({
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={data}
headlist={drgtDetailHeadListExport}
pageSize={10}
total={10000}
cellClick={(index: number | undefined, headId: string) => { }}
onPageChange={() => { }}
></UiTable>
<ScrollArea className="h-[63vh]">
<UiTable
headName={undefined}
tableData={data}
headlist={drgtDetailHeadListExport}
pageSize={10}
total={10000}
cellClick={(index: number | undefined, headId: string) => { }}
onPageChange={() => { }}
></UiTable>
</ScrollArea>
</ListDiv>
</div>
</div>
@@ -4,9 +4,9 @@ import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn";
import { names } from "@/app/store/matDmd/ldrmntCoSttn/excel";
import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui";
import { Form, FormField } from "@common/business_components/ui/form";
import { Button } from "@common/components/ui";
import { Button, Progress } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import { useState } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import type { z } from "zod";
@@ -30,20 +30,20 @@ export default function CoRegExcel() {
try {
let array: { [key: string]: string | number }[] = []
let isError = false;
if (Array.isArray(res)){
if (Array.isArray(res)) {
res.some((item, index) => {
let object: { [key: string]: string | number } = {}
Object.keys(names).some((key) => {
if (item && names[key] !== undefined) {
if (key === "공장관리번호") {
item[key] = String(item[key])
} else {
object[names[key] as string] = item[key];
}
// if (key === "공장관리번호") {
// item[key] = String(item[key])
// } else {
object[names[key] as string] = item[key];
// }
}
return false;
})
if(isError === true)
if (isError === true)
return true;
array.push(object)
@@ -55,8 +55,8 @@ export default function CoRegExcel() {
return false;
})
}
if(isError === false)
ldrmntRegData(array);
if (isError === false)
ldrmntRegData(array);
} catch (e) {
console.log(e)
alert(e)
@@ -67,7 +67,6 @@ export default function CoRegExcel() {
};
}
return (
<>
<div>
@@ -87,7 +86,6 @@ export default function CoRegExcel() {
</div>
<div>
<FormField
control={form.control}
name="file"
@@ -29,10 +29,11 @@ export type objSearchType = {
interface BdstRegProps<T extends MoType> {
moType: T;
isModal:boolean;
setIsModal?: (open: boolean) => void;
}
export function BdstReg<T extends MoType>({ moType,setIsModal }: BdstRegProps<T>) {
export function BdstReg<T extends MoType>({ moType,setIsModal,isModal }: BdstRegProps<T>) {
const { rain, code, bdst,findBdst } = useWrStore((state) => {
return state;
});
@@ -45,13 +46,13 @@ export function BdstReg<T extends MoType>({ moType,setIsModal }: BdstRegProps<T>
const getSelCity = (val: string | number) => {
const cityValue = String(val); // Ensure val is treated as a string
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
getSgg(data[0]?.val || "");
// getSgg(data[0]?.val || "");
setObjSearch({ city: cityValue, sgg: '' });
};
const getSgg = (val: string | number) => {
console.log(val);
setObjSearch({...objSearch,sgg: String(val)})
};
@@ -85,10 +86,7 @@ export function BdstReg<T extends MoType>({ moType,setIsModal }: BdstRegProps<T>
if (data) {
setRainBdstForm(data);
}
}
}
useEffect(()=>{
@@ -122,7 +120,12 @@ export function BdstReg<T extends MoType>({ moType,setIsModal }: BdstRegProps<T>
</div>
<div className="border-t border-gray-300 my-4"></div>
<div className="h-auto">
<h1 className="text-2xl font-medium text-label pl-8">건축물 목록</h1>
<h1 className="text-2xl font-medium text-label pl-8">
건축물 목록
<span className="!text-2xl text-base text-blue-500">
(유의 사항: 신규등록하려는 건축물이 목록에 없을 경우 하단 건축물 정보에 추가하여 주시기 바랍니다.)
</span>
</h1>
<ScrollArea className="h-[30vh]">
<div>
<UiTable
@@ -142,10 +145,10 @@ export function BdstReg<T extends MoType>({ moType,setIsModal }: BdstRegProps<T>
<ScrollArea className="h-[40vh]">
<div>
{ moType === 'RNB'?
<RainRegForm rainForm={rainBdstForm as customRainBdst} isModal={true} />
<RainRegForm rainForm={rainBdstForm as customRainBdst} isModal={isModal} setIsModal={setIsModal} />
:moType==='RST'
? <RswtrRegForm rswtForm={rainBdstForm as customRswtBdst} isModal={true} setIsModal={(open) =>{setIsModal}}></RswtrRegForm>
:<HtdflRegForm htdflForm={rainBdstForm as unknown as customHtdflBdst} isModal={true}></HtdflRegForm>
? <RswtrRegForm rswtForm={rainBdstForm as customRswtBdst} isModal={isModal} setIsModal={(open) =>{setIsModal && setIsModal(open)}}></RswtrRegForm>
:<HtdflRegForm htdflForm={rainBdstForm as unknown as customHtdflBdst} isModal={true} setIsModal={(open) =>{setIsModal && setIsModal(open)}}></HtdflRegForm>
}
</div>
@@ -14,13 +14,16 @@ import { Button } from "@common/business_components/ui/table/lib/button";
import { Input } from "@common/components/ui";
import { ArrowLeft, ArrowRight } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import toast from "react-hot-toast";
export default function FcOrgwtsRegModal({
onRightSet,
closeModal,
initTableData,
}: {
onRightSet?: (rightData: fcOrgwtType[]) => void;
closeModal?: (val: boolean) => void;
initTableData?: any[];
}) {
const { code, pbnst, getSwtrmtFcltNm, searchFclts } = useWrStore(
(state) => state
@@ -31,6 +34,30 @@ export default function FcOrgwtsRegModal({
const leftRef = useRef<pubHasuType[] | null>([] as pubHasuType[]);
const [rightData, setRightData] = useState<pubHasuType[]>();
const [inputVal, setInputVal] = useState<string>("");
const saveData = () => {
if (rightData && rightData?.length > 0) {
if (onRightSet)
onRightSet(
(rightData as pubHasuType[])?.map((item) => {
return {
...item,
swtrmtFcltFk: item.bscFctCd, // 임시값, 실제 데이터에 맞게 수정
orgwtWtritQnt: Number(item.fctCpc), // 임시값, 실제 데이터에 맞게 수정
tmsYn: "N", // 임시값, 실제 데이터에 맞게 수정
dschgFmYn: "N", // 임시값, 실제 데이터에 맞게 수정
dtlPstnExpln: item.addr, // 임시값, 실제 데이터에 맞게 수정
choose: false, // 임시값, 실제 데이터에 맞게 수정
}
// 필요한 경우 다른 속성들도 추가
}) as unknown as fcOrgwtType[]
);
closeModal?.(false)
}
else {
toast.error("취수하수처리장 목록을 선택해주세요.")
}
}
useEffect(() => {
if (Array.isArray(searchFclts)) {
@@ -48,46 +75,62 @@ export default function FcOrgwtsRegModal({
}, [searchFclts]);
useEffect(() => {
if (code.sggCd.length > 0 && pbnstHasuRes.length > 0) {
setbdstTable(tableData(pbnstHasuRes, { code }));
console.log("bdstTable ", bdstTable);
const data = pbnstHasuRes.filter((item) => !initTableData?.find((initItem) => initItem.ruseUtztnFcltNm === item.bscFctNm))
leftRef.current?.filter((item) => !initTableData?.find((initItem) => initItem.ruseUtztnFcltNm === item.bscFctNm));
setbdstTable(tableData(data, { code }));
}
}, [code, pbnstHasuRes]);
}, [code, pbnstHasuRes, initTableData]);
useEffect(() => {
console.log("rightData ", rightData);
if (onRightSet)
onRightSet(
(rightData as pubHasuType[])?.map((item) => ({
swtrmtFcltFk: item.bscFctCd, // 임시값, 실제 데이터에 맞게 수정
orgwtWtritQnt: Number(item.fctCpc), // 임시값, 실제 데이터에 맞게 수정
tmsYn: "N", // 임시값, 실제 데이터에 맞게 수정
dschgFmYn: "N", // 임시값, 실제 데이터에 맞게 수정
dtlPstnExpln: item.addr, // 임시값, 실제 데이터에 맞게 수정
choose: false, // 임시값, 실제 데이터에 맞게 수정
// 필요한 경우 다른 속성들도 추가
})) as unknown as fcOrgwtType[]
);
}, [rightData]);
if (initTableData && Array.isArray(initTableData)) {
setRightData(initTableData.map(item => ({
...item,
choose: item.choose,
sido: item.dtlPstnExpln?.split(" ")[0] || "",
gugun: item.dtlPstnExpln?.split(" ")[1] || "",
bscFctNm: item.ruseUtztnFcltNm,
addr: item.dtlPstnExpln,
orgwtWtritQnt: String(item.orgwtWtritQnt),
fctCpc: String(item.orgwtWtritQnt),
swtrmtFcltFk: item.swtrmtFcltFk,
})));
rightRef.current = initTableData.map(item => ({ ...item }));
}
}, []);
return (
<div className="flex flex-col h-[80vh]">
<div className="shrink-0 p-4 border-b z-10 bg-white">
<div className="flex items-center">
<Title title="취수하수처리장 추가" />
{/* <Button size="sm" onClick={() => closeModal?.(false)}>저장</Button> */}
<div className="flex items-center gap-2 mt-8">
<Label className="text-xl text-gray-600">시설명</Label>
<Input
className="w-48 text-xl"
type="text"
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
/>
<Button size="sm" onClick={() => getSwtrmtFcltNm(inputVal)}>
조회
</Button>
<Label className="text-xl text-gray-600">시설명</Label>
<Input
className="w-48 text-xl"
type="text"
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
/>
<Button size="sm" onClick={() => {
if(inputVal){
getSwtrmtFcltNm(inputVal)
}else{
const filterData = pbnstHasuRes.filter((item) => ! rightData?.find(( right) => right.bscFctNm ===item.bscFctNm))
setbdstTable(tableData(filterData, { code }));
}
}
}>
조회
</Button>
<Button size="sm" onClick={saveData}>저장</Button>
</div>
</div>
</div>
@@ -107,10 +150,10 @@ export default function FcOrgwtsRegModal({
{/* 테이블 영역 */}
<div className="flex flex-row gap-4 flex-grow p-4 overflow-x-auto">
{/* 왼쪽 테이블 */}
{/* 왼쪽 테이블 */}
<div className="w-5/12 min-w-[400px]">
<Label className="text-2xl text-gray-600 mb-2 block text-right">
<div className="w-5/12 min-w-[400px]">
<Label className="text-2xl text-gray-600 mb-2 block text-right">
공공하수처리시설 목록
</Label>
<RuseMngTable
@@ -123,7 +166,7 @@ export default function FcOrgwtsRegModal({
{/* 중간 이동 버튼 */}
<div className="flex flex-col justify-center items-center gap-4 w-[200px] min-w-[120px]">
<ArrowRight
<ArrowRight
onClick={() => {
const checked = leftRef.current?.filter((item) => item.choose);
const unchecked = leftRef.current?.filter((item) => !item.choose);
@@ -159,7 +202,7 @@ export default function FcOrgwtsRegModal({
{/* 오른쪽 테이블 */}
<div className="w-5/12 min-w-[400px]">
<Label className="text-2xl text-gray-600 mb-2 block text-right">
<Label className="text-2xl text-gray-600 mb-2 block text-right">
취수하수처리장 목록
</Label>
<RuseMngTable
@@ -1,6 +1,7 @@
"use client";
import { useWrStore } from "@/app/store";
import {
pbnstRegZod,
type customPbnst,
type PbnstRegArrrayType,
type pubHasuType,
@@ -16,17 +17,25 @@ import {
} from "@common/components/ui";
import { useEffect, useState } from "react";
import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm";
import { useFieldArray, type UseFormReturn } from "react-hook-form";
import {
useFieldArray,
type FieldErrors,
type UseFormReturn,
} from "react-hook-form";
import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg";
import toast from "react-hot-toast";
import type { z } from "zod";
export function PbnstRegModal({
form,
setPbnstInsert
setPbnstInsert,
onInvalid
}: {
form: UseFormReturn<{ items: PbnstRegArrrayType }>;
setPbnstInsert: (data: customPbnst) => void
setPbnstInsert: (data: customPbnst) => void;
onInvalid:(errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>) => void
}) {
const { pbnstInsert } = useWrStore((state) => {
const { pbnstInsert } = useWrStore((state) => {
return state;
});
const [pbnstBdstForm, setPbnstBdstForm] = useState<customPbnst>(
@@ -35,15 +44,78 @@ export function PbnstRegModal({
const [currentTab, setCurrentTab] = useState<string>("mng");
const [indexMng, setIndexMng] = useState<number>(0);
const [indexBiz, setIndexBiz] = useState<number>(0);
const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => {
const item = valuse.items[indexMng];
const data = item ? writeRgtrAndMdfr([item]) : [];
if (data && data[0]) {
// pbnstInsert(data[0]);
setPbnstInsert(data[0])
}
};
const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => {
const item = valuse.items[indexMng];
const data = item ? writeRgtrAndMdfr([item]) : [];
if (data && data[0]) {
setPbnstInsert(data[0]);
}
};
// const onInvalid = (
// errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>
// ) => {
// // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다.
// const findAllErrors = (
// errorObject: any,
// path: (string | number)[] = []
// ): { message: string; path: (string | number)[] }[] => {
// if (!errorObject) return [];
// return Object.keys(errorObject).flatMap((key) => {
// const value = errorObject[key];
// const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key;
// const newPath = [...path, currentKey];
// if (value && typeof value === "object") {
// if (typeof value.message === "string") {
// return [{ message: value.message, path: newPath }]; // 에러 메시지와 경로 반환
// }
// return findAllErrors(value, newPath);
// }
// return [];
// });
// };
// const errorList = findAllErrors(errors);
// if (errorList.length > 0) {
// errorList.forEach((errorInfo) => {
// const { message, path } = errorInfo;
// let prefix = "";
// const itemsIndex = path.indexOf("items");
// if (itemsIndex > -1 && path.length > itemsIndex + 1) {
// const itemIdx = path[itemsIndex + 1] as number;
// const facilityName = form.getValues(
// `items.${itemIdx}.ruseUtztnFcltNm`
// );
// if (facilityName) {
// prefix += `[${facilityName}] `;
// }
// const fcBizsIndex = path.indexOf("fcBizs");
// if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) {
// const bizIdx = path[fcBizsIndex + 1] as number;
// const cycle = form.getValues(
// `items.${itemIdx}.fcBizs.${bizIdx}.cycl`
// );
// if (cycle) {
// prefix += `[${cycle}차수] `;
// }
// }
// }
// toast.error(`${prefix}${message}`);
// });
// }
// };
const handleTabChange = (value: string) => {
setCurrentTab(value);
@@ -76,7 +148,7 @@ export function PbnstRegModal({
차수별정보
</TabsTrigger>
<Button
onClick={form.handleSubmit(onSubmit)}
onClick={form.handleSubmit(onSubmit, onInvalid)}
size={"sm"}
className="!justify-end"
>
@@ -13,6 +13,7 @@ import {
type customPbnst,
type fcBizType,
} from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { formH1Class } from "@/components/lib/class/comClass";
import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm";
import { ScrollArea, Title, UiTable } from "@common/business_components/ui";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
@@ -31,7 +32,7 @@ import { z } from "zod";
export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titleVisible?: boolean }) {
const { code, pbnstSttn, prfmnc } = useWrStore((state) => state);
const [fcltTab, setFcltTab] = useState<string>("fclt");
const [ruseTab, setRuseTab] = useState<string>("inoutTotal");
const [ruseTab, setRuseTab] = useState<string>("totalPrf");
const [ruseBizData, setRuseBizData] = useState<{
data: any[];
head: TableUpperProps[];
@@ -229,7 +230,8 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
(item) => item.pbnstRuseFcltPk === data.pbnstRuseFcltPk
)?.prfList;
if (prfList) {console.log("prfList", prfList);
if (prfList) {
console.log("prfList", prfList);
getTablePrfData(prfList);
}
@@ -243,12 +245,12 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
form.reset({ items: [data] })
}
},[data, form])
}, [data, form])
useEffect(()=>{
useEffect(() => {
console.log("prfData", prfData);
},[prfData])
}, [prfData])
return (
<>
<div>
@@ -264,72 +266,79 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl
indexMng={indexMng}
setIndexMng={setIndexMng}
/>
<Tabs defaultValue="fclt" onValueChange={setFcltTab}>
<TabsList className="">
<TabsTrigger className="!text-xl" value="fclt">
하수처리수 재이용시설 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="sply">
재이용 원수 취수 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="ppi">
재이용 공급관로 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="guarantee">
재이용 보증수질 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="dmdCo">
재이용 수요처 현황
</TabsTrigger>
</TabsList>
<TabsContent className="max-h-full" value={fcltTab}>
<UiTable
headName={undefined}
tableData={ruseTableData || []}
headlist={ruseHeadList || []}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}
children={
fcltTab === "fclt" ? (
<HeadMakeColSpan upHeadList={pbnstSttn.ruseFcltNodeList} />
) : undefined
}
></UiTable>
</TabsContent>
</Tabs>
<Tabs onValueChange={setRuseTab}>
<TabsList className="">
<TabsTrigger className="!text-xl" value="totalPrf">
장내외합계
</TabsTrigger>
<TabsTrigger className="!text-xl" value="inPrf">
장내용수
</TabsTrigger>
<TabsTrigger className="!text-xl" value="outPrf">
장외용수
</TabsTrigger>
</TabsList>
<TabsContent className="max-h-full" value={ruseTab}>
{prfData && (
<div className="px-6">
<div className="">
<h1 className={formH1Class}>하수재이용시설 현황</h1>
</div>
<Tabs defaultValue="fclt" onValueChange={setFcltTab}>
<TabsList className="mt-4">
<TabsTrigger className="!text-xl" value="fclt">
하수처리수 재이용시설 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="sply">
재이용 원수 취수 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="ppi">
재이용 공급관로 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="guarantee">
재이용 보증수질 현황
</TabsTrigger>
<TabsTrigger className="!text-xl" value="dmdCo">
재이용 수요처 현황
</TabsTrigger>
</TabsList>
<TabsContent className="max-h-full" value={fcltTab}>
<UiTable
headName={undefined}
tableData={prfData[ruseTab as keyof typeof prfData] || []}
headlist={monthHeadList || []}
tableData={ruseTableData || []}
headlist={ruseHeadList || []}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}
children={
fcltTab === "fclt" ? (
<HeadMakeColSpan upHeadList={pbnstSttn.ruseFcltNodeList} />
) : undefined
}
></UiTable>
)}
</TabsContent>
</Tabs>
</TabsContent>
</Tabs>
<div className="">
<h1 className={formH1Class}>하수재이용실적</h1>
</div>
<Tabs defaultValue="totalPrf" onValueChange={setRuseTab}>
<TabsList className="mt-4">
<TabsTrigger className="!text-xl" value="totalPrf">
장내외합계
</TabsTrigger>
<TabsTrigger className="!text-xl" value="inPrf">
장내용수
</TabsTrigger>
<TabsTrigger className="!text-xl" value="outPrf">
장외용수
</TabsTrigger>
</TabsList>
<TabsContent className="max-h-full" value={ruseTab}>
{prfData && (
<UiTable
headName={undefined}
tableData={prfData[ruseTab as keyof typeof prfData] || []}
headlist={monthHeadList || []}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}
></UiTable>
)}
</TabsContent>
</Tabs>
</div>
</ScrollArea>
</div>
</>
@@ -62,9 +62,6 @@ export default function SearchInputText({
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
useEffect(() =>{
console.log('searchList ', searchList)
},[searchList])
return (
<div ref={wrapperRef}>
@@ -4,6 +4,7 @@ import { useWrStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common/type/header";
import type {
} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import { InputTableBody } from "@/components/lib/func/TableData";
import {
Input,
@@ -13,16 +14,18 @@ import {
TableHeader,
TableRow,
} from "@common/components/ui";
import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
export function GuideDetailsTable({
chgRes,
headList,
upheadList,
type,
setChGuidData,
}: {
chgRes: any[];
headList: TableUpperProps[];
headList: TableUpperProps[];
upheadList: chHeadType[];
type: string;
setChGuidData: (chgRes: any[]) => void;
}) {
@@ -35,21 +38,21 @@ export function GuideDetailsTable({
useEffect(() => {
setChGuidData(inputData??[] );
setChGuidData(inputData ?? []);
}, [inputData]);
return (
<>
<div className={`card !m-[1.2rem] !p-0r `}>
<Table variant="secondary">
<TableHeader className="font-bold">{headMakeprfmnc(headList, rainChkgdn?.rainHeadNm)}</TableHeader>
<TableBody >
{InputTableBody(inputData ?? [],headList, setInputData) }
</TableBody>
</Table>
</div>
<div className={`card !m-[1.2rem] !p-0r `}>
<Table variant="secondary">
<TableHeader className="font-bold">{headMakeprfmnc(headList, upheadList)}</TableHeader>
<TableBody >
{InputTableBody(inputData ?? [], headList, setInputData)}
</TableBody>
</Table>
</div>
</>
);
}
@@ -1,15 +1,16 @@
"use client";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
import { useWrStore } from "@/app/store";
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
import { rainPageSize, type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import { tableData } from "@/components/lib/func/commom";
import {
chRowspanTable,
headVisibleChange,
rainChkTableData
} from "@/components/lib/func/TableData";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UiPageNations from "@common/business_components/ui/table/uiPageNations";
import {
Table,
TableBody,
@@ -17,21 +18,27 @@ import {
} from "@common/components/ui";
import { useCallback, useEffect, useState } from "react";
export default function RainChkgdTable({
detailUp,
handleClick=() => {},
detailUp,
handleClick = () => { },
deleteData,
rainChkData,
pageNation,
onPageChange,
pageCount,
}: {
detailUp: (data: rainChkZodType[]) => void;
handleClick?: (data:any) => void;
deleteData:(selectedIds:number[])=>void
handleClick?: (data: any) => void;
deleteData: (selectedIds: number[]) => void
rainChkData?: rainChkZodType[];
pageNation: number;
onPageChange: (page: number) => void;
pageCount: number;
}) {
const { code, rainChkgdn ,rainChkSttn,getRainSttnExcel } = useWrStore((state) => state);
const { code, rainChkgdn, rainChkSttn, getRainSttnExcel } = useWrStore((state) => state);
const [makeTableData, setMakeTableData] = useState<any[]>([]);
const [selectedIds, setSelectedIds] = useState<number[]>([]);
const [upRaintDetail, setUpRaintDetail] = useState<rainChkZodType[]>([]);
const [headList, setHeadList] = useState< {headList:TableUpperProps[],upHeadList:chHeadType[]}>({headList:[], upHeadList:[]});
const [headList, setHeadList] = useState<{ headList: TableUpperProps[], upHeadList: chHeadType[] }>({ headList: [], upHeadList: [] });
const toggleSelection = (pk: number, checked: boolean) => {
@@ -46,30 +53,31 @@ export default function RainChkgdTable({
) => {
setMakeTableData((prev) =>
prev.map((row, idx) => {
return idx === rowIndex ? { ...row, [field]: value } : row
prev.map((row, idx) => {
return idx === rowIndex ? { ...row, [field]: value } : row
}
)
);
};
const handleCellClick= useCallback((index: number, headId: string) => {
const handleCellClick = useCallback((index: number, headId: string) => {
if (
headId === "totalSplyUswtrUtztnQnt" ||
headId === "totalRuseFcltUtztnQnt"
) {
handleClick(makeTableData[index])
}
},[makeTableData, handleClick]);
}, [makeTableData, handleClick]);
useEffect(() => {
setSelectedIds([])// 셀렉트 초기화를 위한 작업
if(rainChkData){
const rainChg = rainChkData.map((item: any) => {
if (rainChkData && rainChkData.length > 0) {
const rainChg = rainChkData?.map((item: any) => {
const bud = tableData([item.building], { code });
return {
...item,
@@ -77,16 +85,19 @@ export default function RainChkgdTable({
rowspan: item.rainyDetails?.length,
};
});
setMakeTableData(rainChkTableData(rainChg));
} else {
setMakeTableData([]);
}
}, [rainChkData, code]);
useEffect(() => {
//데이터를 평탄화 한것중에 체크박스 선택한 테이블만 선택
//현황 페이지에서 필요한 엑셀 데이터를 바뀔때마다 넣기 위해서
getRainSttnExcel(makeTableData);
const selectedData = makeTableData.filter((item) =>selectedIds.includes(item.chkgdnPk));
const selectedData = makeTableData.filter((item) => selectedIds.includes(item.chkgdnPk));
if (selectedData.length > 0) {
const updateTableData = rainChkgdn.rainChk
@@ -101,7 +112,6 @@ export default function RainChkgdTable({
);
if (findRain != undefined) {
console.log(findRain)
return {
...rd,
ph: Number(findRain.ph),
@@ -127,63 +137,70 @@ export default function RainChkgdTable({
}
})
.filter(Boolean);
setUpRaintDetail(updateTableData as rainChkZodType[]);
}
}, [makeTableData,selectedIds]);
}, [makeTableData, selectedIds]);
useEffect(() => {
detailUp(upRaintDetail);
}, [upRaintDetail]);
useEffect(() =>{
if(selectedIds.length >0){
useEffect(() => {
if (selectedIds.length > 0) {
// 삭제를 위한 데이터 삽입
deleteData(selectedIds )
deleteData(selectedIds)
}
},[selectedIds])
}, [selectedIds])
///현황일 경우 input 비활성화 한다.
useEffect(() => {
if(rainChkSttn.isSttn){
useEffect(() => {
if (rainChkSttn.isSttn) {
setHeadList({
headList: rainChkSttn.rainChkgdnHeadList,
upHeadList: rainChkSttn.rainHeadNm
})
}else{
} else {
setHeadList({
headList: rainChkgdn.rainChkgdnHeadList,
upHeadList: rainChkgdn.rainHeadNm
upHeadList: rainChkgdn.rainMainHeadNm
})
}
}, [rainChkSttn.isSttn, rainChkgdn.rainChkgdnHeadList , rainChkSttn.rainChkgdnHeadList]);
}, [rainChkSttn.isSttn, rainChkgdn.rainChkgdnHeadList, rainChkSttn.rainChkgdnHeadList]);
return (
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(
headList?.headList,
headList?.upHeadList
)}
</TableHeader>
<>
<LoadingOverlay isLoading={rainChkgdn.isLoading}></LoadingOverlay>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(
headList?.headList,
headList?.upHeadList
)}
</TableHeader>
<TableBody>
{chRowspanTable(
makeTableData,
headList.headList,
handleChange,
toggleSelection,
selectedIds,
handleCellClick
)}
</TableBody>
</Table>
<TableBody>
{chRowspanTable(
makeTableData,
headList.headList,
handleChange,
toggleSelection,
selectedIds,
handleCellClick
)}
</TableBody>
</Table>
<UiPageNations
total={pageCount}
cur={pageNation}
pageSize={rainPageSize}
onPageChange={onPageChange}
/>
</>
);
}
@@ -1,35 +1,44 @@
"use client";
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
import { useWrStore } from "@/app/store";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type {
rswtChkZodType,
rswtrChkDetailsZodType,
} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import type { TableUpperProps } from "@/app/store/common/type/header";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import {
rswtPageSize,
type rswtChkZodType,
type rswtrChkDetailsZodType,
} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import { tableData } from "@/components/lib/func/commom";
import {
chRowspanTable,
rswtChkTableData,
} from "@/components/lib/func/TableData";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UiPageNations from "@common/business_components/ui/table/uiPageNations";
import { Table, TableBody, TableHeader } from "@common/components/ui";
import { useCallback, useEffect, useState } from "react";
export default function RswtChkgdTable({
detaiRswtlUpdate,
handleRswtClick = () => {},
handleRswtClick = () => { },
deleteRswtData,
rswtChkData,
pageNation,
onPageChange,
pageCount,
}: {
detaiRswtlUpdate: (data: rswtrChkDetailsZodType[]) => void;
handleRswtClick?: (data: any) => void;
deleteRswtData: (selectedIds: number[]) => void;
rswtChkData: rswtChkZodType[];
pageNation: number;
onPageChange: (page: number) => void;
pageCount: number;
}) {
const { code, rswtChkgdn,rswtChkSttn , rswtChkgdnInit, rswtChkPolAndGuide,getRswtSttnExcel } = useWrStore(
const { code, rswtChkgdn, rswtChkSttn, rswtChkgdnInit, rswtChkPolAndGuide, getRswtSttnExcel } = useWrStore(
(state) => state
);
const [headList, setHeadList] = useState< {headList:TableUpperProps[],upHeadList:chHeadType[]}>({headList:[], upHeadList:[]});
const [headList, setHeadList] = useState<{ headList: TableUpperProps[], upHeadList: chHeadType[] }>({ headList: [], upHeadList: [] });
const [makeTableData, setMakeTableData] = useState<any[]>([]);
const [selectedIds, setSelectedIds] = useState<number[]>([]);
@@ -67,7 +76,6 @@ export default function RswtChkgdTable({
}, [rswtChkgdn.rswtChkPolGuide]);
useEffect(() => {
console.log("makeTableData ", makeTableData)
getRswtSttnExcel(makeTableData)
const selectedData = makeTableData
.map((item) => {
@@ -111,25 +119,24 @@ export default function RswtChkgdTable({
}, [selectedIds]);
///현황일 경우 input 비활성화 한다.
useEffect(() => {
if(rswtChkSttn.isSttn){
useEffect(() => {
if (rswtChkSttn.isSttn) {
setHeadList({
headList: rswtChkSttn.rswtChkSttnHeadList,
upHeadList: rswtChkSttn.rswtSttnHeadNm
})
}else{
} else {
setHeadList({
headList: rswtChkgdn.rswtChkHeadList,
upHeadList: rswtChkgdn.rswtHeadNm
})
}
}, [rswtChkSttn.isSttn, rswtChkgdn.rswtChkHeadList , rswtChkSttn.rswtChkSttnHeadList]);
}, [rswtChkSttn.isSttn, rswtChkgdn.rswtChkHeadList, rswtChkSttn.rswtChkSttnHeadList]);
return (
<>
<LoadingOverlay isLoading={rswtChkgdn.isLoading}></LoadingOverlay>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(headList?.headList, headList?.upHeadList)}
@@ -146,6 +153,12 @@ export default function RswtChkgdTable({
)}
</TableBody>
</Table>
<UiPageNations
total={pageCount}
cur={pageNation}
pageSize={rswtPageSize}
onPageChange={onPageChange}
/>
</>
);
}
@@ -3,6 +3,10 @@ import type { TableUpperProps } from "@/app/store/common/type/header";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { customPbnst as OriginalCustomPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
formatCommaNumber,
handleCommaNumberChange,
} from "@/components/lib/func/commom";
import {
DatePicker,
@@ -32,12 +36,24 @@ type RuseMngTableProps = {
indexMng?: number;
indexBiz?: number;
form?: any;
formNm?:string
formNm?: string;
};
const RuseMngTableForm = React.forwardRef<any, RuseMngTableProps>(
({ tableData, headList, upHeadList, code, onTableSet, indexMng, form,formNm,indexBiz }, ref) => {
(
{
tableData,
headList,
upHeadList,
code,
onTableSet,
indexMng,
form,
formNm,
indexBiz,
},
ref
) => {
return (
<>
<Table key={`table-${indexMng}-${indexBiz}`} variant="secondary">
@@ -73,26 +89,31 @@ const RuseMngTableForm = React.forwardRef<any, RuseMngTableProps>(
typeof indexMng === "number" &&
indexMng >= 0 &&
typeof indexBiz === "number" &&
indexBiz >= 0?
`items.${indexMng}.fcBizs.${indexBiz}.${formNm}.${i}.${head.id}`:
typeof indexMng === "number" && indexMng >= 0?
`items.${indexMng}.${formNm}.${i}.${head.id}`:
`items.${indexMng}.${formNm}.${i}.${head.id}`}
indexBiz >= 0
? `items.${indexMng}.fcBizs.${indexBiz}.${formNm}.${i}.${head.id}`
: typeof indexMng === "number" && indexMng >= 0
? `items.${indexMng}.${formNm}.${i}.${head.id}`
: `items.${indexMng}.${formNm}.${i}.${head.id}`
}
render={({ field }) => (
<FormUi label="">
{head.edit === true ? (
<Input
className={`${head.type === "number" ? "text-right" : "text-center"} !text-xl`}
type={head.type}
type="text"
onChange={(txt) => {
field.onChange(txt.target.value);
if (head.type === "number") {
handleCommaNumberChange(txt, field.onChange);
} else {
field.onChange(txt.target.value);
}
}}
value={
head.type === "number"
? (Number(field.value) ?? 0)
? formatCommaNumber(field.value)
: field.value || ""
}
readOnly ={head.readonly ? true : false}
readOnly={head.readonly ? true : false}
/>
) : head.type === "select" ? (
<SelectBox
@@ -102,43 +123,41 @@ const RuseMngTableForm = React.forwardRef<any, RuseMngTableProps>(
(item) => item.name === head.selectData
)?.val ?? []
}
value={
field.value || ""
}
value={field.value || ""}
className={""}
selectClass={selectClass}
onSelectValue={(val) => {
if(head.readonly === true){
return
}else{
if (head.readonly === true) {
return;
} else {
field.onChange(val);
}
}}
readOnly ={head.readonly ? true : false}
readOnly={head.readonly ? true : false}
// Disabled prop removed as SelectBox does not support it
></SelectBox>
) : head.type === "date" ? (
<DatePicker
mode="single"
field={{
value:typeof field.value === "string" ? new Date(field.value) : field.value,
value:
typeof field.value === "string"
? new Date(field.value)
: field.value,
onChange: (date: Date | undefined) => {
console.log("date", date);
field.onChange(date); // readonly 상태가 아닐 때만 값 변경
field.onChange(date); // readonly 상태가 아닐 때만 값 변경
},
}}
selectClass={"w-full"}
readOnly ={head.readonly ? true : false}
readOnly={head.readonly ? true : false}
/>
) : head.type === "checkbox" ? (
<Checkbox
className=""
checked={ field.value || false}
checked={field.value || false}
onCheckedChange={(checked) => {
field.onChange(checked);
field.onChange(checked);
}}
></Checkbox>
) : (
+10 -1
View File
@@ -6,6 +6,7 @@ const CLAIM_NAME = "Authorization";
const AUTH_USER_ID = "token-id";
const serverApiUrl = CS_URL;
const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
export function middleware(req: NextRequest) {
const pathname = req.nextUrl.pathname;
@@ -55,9 +56,17 @@ export function middleware(req: NextRequest) {
return NextResponse.rewrite(new URL(newUrl));
}
if (pathname.startsWith("/sewerage-service")) {
const queryParams = searchParams.toString();
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));
}
return NextResponse.next();
}
export const config = {
matcher: ["/server/:path*", "/attach-service/:path*", "/geoserver/:path*"],
matcher: ["/server/:path*", "/attach-service/:path*", "/geoserver/:path*", "/sewerage-service/:path*"],
};
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -44,6 +44,7 @@
"recharts": "^2.15.1",
"sonner": "^2.0.1",
"tailwind-merge": "^3.0.1",
"tailwindcss-animate": "^1.0.7",
"xlsx": "^0.18.5",
"xlsx-populate": "^1.21.0",
"zod": "^3.24.2"
@@ -88,12 +88,12 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle='
return (
<>
{chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
<div className="!mt-3 text-[2.5rem] font-bold text-center">
<div className="!mt-3 text-[2.5rem] font-bold">
{chartTitle}
</div>): null}
<div className="flex justify-center h-full w-full">
<ChartContainer config={chartConfig ?? {}} className={chartClassName + " !w-[88%]"}>
<BarChart accessibilityLayer data={chartData} margin={{ top: 5, right: 20, left: 30, bottom: 5 }}>
<div className="flex justify-center">
<ChartContainer config={chartConfig ?? {}} className={chartClassName + " !w-[90%]"}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="label"
@@ -110,13 +110,8 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle='
axisLine={true}
fontSize={12}
fontWeight={500}
tickFormatter={(value) => {
// 소수점이 있는 경우 소수점을 유지하고 천단위 콤마 추가
return value.toString().includes('.')
? value.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 2 })
: value.toLocaleString();
}}
label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: -24, orientation: "left" } : undefined}
domain={[0, Math.ceil(barMaxValue * 1)]}
label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: 20 } : undefined}
/>
<ChartTooltip cursor={false} content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />}/>
{chartData && chartData.length > 0 && (
@@ -7,7 +7,6 @@ import {
} from "./lib/chart";
import type { CSSProperties } from "react";
/*
const customStyles = {
legendContainer: {
display: "flex",
@@ -18,22 +17,6 @@ const customStyles = {
marginTop: "10px",
} as CSSProperties,
};
*/
const customStyles = {
legendContainer: {
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center",
gap: "12px",
fontSize: "13px",
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px",
} as CSSProperties,
};
type BarChartProps = {
chartConfig: ChartConfig | undefined;
@@ -77,7 +60,7 @@ const CustomTooltip = ({
};
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
/*const CustomLegend = (props: any) => {
const CustomLegend = (props: any) => {
const { payload } = props;
return (
<div style={customStyles.legendContainer}>
@@ -89,38 +72,6 @@ const CustomTooltip = ({
))}
</div>
);
};*/
const CustomLegend = (props: any) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: any, index: number) => (
<div
key={`legend-${index}`}
className="flex items-center"
style={{
minWidth: "90px",
margin: "2px 0",
}}
>
<div
style={{
width: "14px",
height: "14px",
backgroundColor: entry.color,
borderRadius: "3px",
marginRight: "8px",
minWidth: "14px",
minHeight: "14px",
}}
></div>
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span>
</div>
))}
</div>
);
};
export default function DoubleBarChart({chartConfig=undefined, chartData=[], chartTitle='차트', chartClassName='w-full h-full', graphSize=40, yFieldText='', showLegend=false} : BarChartProps) {
@@ -132,7 +83,7 @@ export default function DoubleBarChart({chartConfig=undefined, chartData=[], cha
.map(key => item[key])
).flat());
};
console.log(chartData);
const barMaxValue = getMaxValue(chartData, 'barVal');
return (
<>
@@ -48,7 +48,6 @@ type LegendProps = {
};
/** 차트 기본 스타일 */
/*
const customStyles = {
legendContainer: {
display: "flex",
@@ -59,23 +58,6 @@ const customStyles = {
marginTop: "10px",
} as CSSProperties,
};
*/
/** 차트 기본 스타일 (라인차트와 동일하게) */
const customStyles = {
legendContainer: {
display: "flex",
flexWrap: "wrap", // 여러 줄로 자동 줄바꿈
justifyContent: "center",
alignItems: "center",
gap: "12px", // 아이템 간 간격
fontSize: "13px",
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px", // 범례 영역 높이 통일
} as CSSProperties,
};
// 커스텀 툴팁
const CustomTooltip = ({ active, payload, label }: {
@@ -100,7 +82,6 @@ const CustomTooltip = ({ active, payload, label }: {
};
// 커스텀 범례
/*
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
@@ -116,52 +97,12 @@ const CustomLegend = (props: LegendProps) => {
</div>
);
};
*/
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: LegendEntry, index: number) => (
<div
key={`legend-${index}`}
className="flex items-center"
style={{
minWidth: "90px",
margin: "2px 0",
}}
>
<div
style={{
width: "14px",
height: "14px",
backgroundColor: entry.fill,
borderRadius: "3px",
marginRight: "8px",
minWidth: "14px",
minHeight: "14px",
}}
></div>
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>
{entry.payload?.label || entry.value}
</span>
</div>
))}
</div>
);
};
export default function DoughnutChart(props: {
chartConfig: any;
chartData: ChartDataItem[] | undefined;
chartTitle: string
}) {
const legendData = props.chartData?.map(item => ({
value: item.label,
fill: props.chartConfig?.[item.label]?.fill || 'blue',
})) ?? [];
return (
<Card className="flex flex-col">
<CardContent className="flex-1 pb-0">
@@ -189,9 +130,9 @@ export default function DoughnutChart(props: {
nameKey="label"
innerRadius={60}
/>
<CustomLegend />
</PieChart>
</ChartContainer>
<CustomLegend payload={legendData} />
</div>
</CardContent>
</Card>
@@ -127,7 +127,7 @@ export default function LineBarchart({
className="text-[12px] font-bold"
tickCount={6}
orientation="left"
tickFormatter={(value) => value.toLocaleString()}
domain={[0, Math.ceil(lineMaxValue * 1)]}
label={{ value: yFieldText, angle: -90, position: 'insideLeft' }}
/>}
{/* 오른쪽 Y축: barVal */}
@@ -136,7 +136,7 @@ export default function LineBarchart({
className="text-[12px] font-bold"
tickCount={6}
orientation="right"
tickFormatter={(value) => value.toLocaleString()}
domain={[0, Math.ceil(barMaxValue * 1)]}
label={{ value: yFieldText2, angle: -90, position: 'insideRight' }}
reversed={true}
/>}
@@ -18,7 +18,6 @@ type LineChartProps = {
}
/** 차트 기본 스타일 */
/*
const customStyles = {
legendContainer: {
display: "flex",
@@ -29,23 +28,6 @@ const customStyles = {
marginTop: "10px",
} as CSSProperties,
};
*/
/** 차트 기본 스타일 */
const customStyles = {
legendContainer: {
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center",
gap: "12px",
fontSize: "13px",
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px",
} as CSSProperties,
};
type LegendEntry = {
value: string;
@@ -78,7 +60,7 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?:
};
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
/*const CustomLegend = (props: LegendProps) => {
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
@@ -92,40 +74,6 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?:
))}
</div>
);
};*/
// 커스텀 범례 (도넛차트와 동일하게)
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: LegendEntry, index: number) => (
<div
key={`legend-${index}`}
className="flex items-center"
style={{
minWidth: "90px",
margin: "2px 0",
}}
>
<div
style={{
width: "14px",
height: "14px",
backgroundColor: entry.color,
borderRadius: "3px",
marginRight: "8px",
minWidth: "14px",
minHeight: "14px",
}}
></div>
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span>
</div>
))}
</div>
);
};
type DataType = {label: string; val: string};
@@ -193,7 +141,7 @@ export default function Linechart({
>
<CartesianGrid vertical={false} />
<XAxis dataKey="label" fontSize="8px" fontWeight="bold" />
<YAxis yAxisId="left" className="text-[12px] font-bold" tickFormatter={(value) => value.toLocaleString()} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} />
<YAxis yAxisId="left" className="text-[12px] font-bold" domain={[0, Math.ceil(lineMaxValue * 1.1)]} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} />
<Tooltip content={<CustomTooltip />} />
{showLegend && <Legend content={CustomLegend as ContentType}/>}
{Object.keys(chartData).map((key) => {
@@ -17,7 +17,6 @@ type MonthPickerProps = {
field: { value: string; onChange: (date: string) => void }; // yyyyMM 문자열
selectClass?: string;
readOnly?: boolean;
startYear?: number; // 시작 연도 props 추가
};
// yyyyMM → Date 객체
@@ -38,7 +37,6 @@ export const DateMonthPicker = ({
field,
selectClass,
readOnly = false,
startYear,
}: MonthPickerProps) => {
const [open, setOpen] = useState(false);
@@ -77,7 +75,6 @@ export const DateMonthPicker = ({
<MonthPicker
currentMonth={parsedDate}
onMonthChange={handleSelect}
startYear={startYear}
/>
</PopoverContent>
</Popover>
@@ -28,41 +28,35 @@ export type MonthPickerProps = {
newMonth: Date | undefined,
shouldClosePopover?: boolean
) => void;
startYear?: number;
};
export function MonthPicker({ currentMonth, onMonthChange, startYear }: MonthPickerProps) {
export function MonthPicker({ currentMonth, onMonthChange }: MonthPickerProps) {
const today = startOfToday();
const currentYear = today.getFullYear();
const currentYear = today.getFullYear();
const yearFromProp = format(currentMonth, "yyyy");
const selectedYear = parseInt(yearFromProp);
const selectedYear = parseInt(yearFromProp);
// 현재 월의 시작 날짜
const fullYearStart = parse(yearFromProp, "yyyy", new Date());
const yearEnd =
selectedYear === currentYear ? today : endOfYear(fullYearStart);
// startYear가 없으면 기존과 동일하게 (현재년도 - 20년부터 현재년도까지)
// startYear가 있으면 해당 년도부터 현재년도까지, 내림차순으로 정렬
const yearRange = startYear
? Array.from({ length: currentYear - startYear + 1 }, (_, i) => currentYear - i)
: Array.from({ length: 21 }, (_, i) => currentYear - 20 + i);
const yearRange = Array.from({ length: 21 }, (_, i) => currentYear - 20 + i);
const months = eachMonthOfInterval({ start: fullYearStart, end: yearEnd });
const getMonthButtonClass = (month: Date) =>
cn(
"inline-flex h-9 w-16 items-center justify-center rounded-md p-0 text-sm font-normal ring-offset-white transition-colors hover:bg-slate-100 hover:text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-selected:opacity-100 dark:ring-offset-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50 dark:focus-visible:ring-slate-800",
isEqual(month, currentMonth) &&
"bg-slate-900 text-slate-50 hover:bg-slate-900 hover:text-slate-50 focus:bg-slate-900 focus:text-slate-50 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50 dark:hover:text-slate-900 dark:focus:bg-slate-50 dark:focus:text-slate-900",
"bg-slate-900 text-slate-50 hover:bg-slate-900 hover:text-slate-50 focus:bg-slate-900 focus:text-slate-50 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50 dark:hover:text-slate-900 dark:focus:bg-slate-50 dark:focus:text-slate-900",
!isEqual(month, currentMonth) &&
isEqual(month, getStartOfCurrentMonth()) &&
"bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50"
isEqual(month, getStartOfCurrentMonth()) &&
"bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-slate-50"
);
return (
@@ -83,7 +77,7 @@ export function MonthPicker({ currentMonth, onMonthChange, startYear }: MonthPic
onMonthChange(newDate, false);
}}
>
<SelectTrigger className="w-[140px] h-9 text-base">
<SelectTrigger className="w-[120px] h-7">
<SelectValue placeholder="년도" />
</SelectTrigger>
<SelectContent>
@@ -118,7 +112,7 @@ export function MonthPicker({ currentMonth, onMonthChange, startYear }: MonthPic
onClick={() => onMonthChange(month, true)}
>
<time dateTime={format(month, "yyyy-MM-dd")}>
{format(month, 'MMM', { locale: ko })}
{format(month, 'MMM', { locale: ko })}
</time>
</button>
</div>

Some files were not shown because too many files have changed in this diff Show More