From 5d5b97d39f5eba6e453c3ba98f36cee9e6e14f2b Mon Sep 17 00:00:00 2001 From: YangJinSoo94 Date: Wed, 2 Jul 2025 17:26:10 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=EB=AC=BC=EC=9E=AC=EC=9D=B4=EC=9A=A9?= =?UTF-8?q?=EC=82=AC=EB=A1=80=EA=B4=80=EB=A6=AC,=20=ED=86=B5=EA=B3=84=20?= =?UTF-8?q?=EA=B2=B0=ED=95=A8=EC=A1=B0=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx | 16 ++++++++++---- apps/wr/app/stats/rainStat/page.tsx | 3 ++- apps/wr/app/stats/rswtStat/page.tsx | 2 +- .../wr/app/store/matDmd/ruseCaseMng/index.tsx | 22 +++++++++++-------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx index 436b77736..517dab0c0 100644 --- a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx +++ b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx @@ -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 } = ruseCaseMng; const [selectSgg, setSelectSgg] = useState([]); const [objSearch, setObjSearch] = useState({ sgg: "", city: "" }); @@ -142,7 +144,7 @@ export default function RuseCaseMng() { } ]; // 버퍼에 있는 엑셀데이터 전달 후 json으로 변환 - await filePickedBlobArray(blobRet, '시설정보및운영현황황', sheetParameter); + await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter); }); } @@ -157,6 +159,12 @@ export default function RuseCaseMng() { ); } + useEffect(() => { + if(status === 200){ + setIsExcelOpen({ isModal: false }); + } + }, [status]); + return ( <> @@ -239,7 +247,7 @@ export default function RuseCaseMng() { - + {/* 엑셀 등록 모달 */} item.cityText !== '없음') : []; + setBdstTable(tbData); }, [code, rainStatList]); diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index c0741433c..997e95ca5 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -46,7 +46,7 @@ export default function RswtStat() { ...item, ctpvCd: item.cityText }; - }) + }).filter((item: RswtStatProps) => item.cityText !== '없음') : []; setRswtTable(tbData); }, [code, rswtStatList]) diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx index 915740f79..76468d249 100644 --- a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx +++ b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx @@ -1,12 +1,12 @@ import { fetchType, getFetch, 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; }; }; @@ -69,7 +69,6 @@ type ruseCaseActions = { }; 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; @@ -77,7 +76,7 @@ export const fetchSearchRuseCaseMng = async (sidoCd: string, sigunguCd: string, 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 +85,7 @@ export const ruseCaseStateExport: ruseCaseState = { ruseCaseMng: { ruseHeadList:ruseCaseHeadListExport, ruseCaseMngList:[], + status: 0, }, }; @@ -95,7 +95,6 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = ( return { selectRuseCaseMng: async (sidoCd: string, sigunguCd: string, usageCd : string, name: string) => { const res = await fetchSearchRuseCaseMng(sidoCd, sigunguCd, usageCd, name); - console.log('res : ', res); set((state: ruseCaseState) => ({ ruseCaseMng: { ...state.ruseCaseMng, @@ -107,11 +106,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, + }, + })); }, }; }; From 1f2316d8b4bc5ba23fbff224833aef0b19ed82c3 Mon Sep 17 00:00:00 2001 From: jyha00 Date: Thu, 3 Jul 2025 10:50:02 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=EC=A4=91=EC=88=98=EB=8F=84/=EC=98=A8?= =?UTF-8?q?=EB=B0=B0=EC=88=98=EC=8B=9C=EC=84=A4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=EC=A1=B0=EA=B1=B4=20=EB=B3=80=EA=B2=BD,=20-1?= =?UTF-8?q?=EA=B0=92=20=ED=99=95=EC=9D=B8=EB=B6=88=EA=B0=80=EB=A1=9C=20?= =?UTF-8?q?=ED=91=9C=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruseFcltMng/fcltSttn/htdflSttn/page.tsx | 176 ++++++++++++------ .../ruseFcltMng/fcltSttn/rainSttn/page.tsx | 62 +----- .../ruseFcltMng/fcltSttn/rswtSttn/page.tsx | 155 ++++++++++----- .../ruseFcltMng/fcltSttn/htdflSttn/index.tsx | 16 +- 4 files changed, 242 insertions(+), 167 deletions(-) diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx index e43d5b04f..03b549270 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx @@ -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,22 @@ import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDeta import { ContentsDiv, SearchBaseForm, + SearchDiv, + SearchFormLeft, + SearchFormRight, + 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 { 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 +45,8 @@ export default function HtdflSttn() { const [pageNation, setPageNation] = useState(1); const [isChHead, setIsChHead] = useState(false); const [bdstTable, setBdstTable] = useState(); + const [selectSgg, setSelectSgg] = useState() + const [objSearch, setObjSearch] = useState({ sgg: "", city: "" }); const [detailModal, setDetailModal] = useState<{ isOpen: boolean; data: customRainBdst | undefined; @@ -50,13 +59,44 @@ export default function HtdflSttn() { const codeData = getCityOrSgg(ref); const excelClick = useCallback(() => { - if (codeData) htdflSttnSearch(1, "10000", codeData); - }, [htdflSttnSearch, codeData]); + // 최신 검색 조건 반영 + const con = getConValue(); + htdflSttnSearch(1, "10000", String(con), code.cityCd, code.sggCd); + }, [htdflSttnSearch, objSearch, code.cityCd, code.sggCd]); useEffect(() => { - if (codeData != null) htdflSttnSearch(pageNation, "20", codeData); + if (codeData != null) htdflSttnSearch(pageNation, "20", codeData, 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,20 +107,15 @@ 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(() => { @@ -90,19 +125,16 @@ export default function HtdflSttn() { }, [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,65 @@ export default function HtdflSttn() {
- <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> + </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(1, "20", String(con), 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} /> diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx index 7e068bcd0..804e9d808 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx @@ -82,7 +82,6 @@ export default function RainSttn() { }; const getSgg = (val: string | number) => { - console.log("val", val) setObjSearch({ ...objSearch, sgg: String(val) }) }; @@ -96,8 +95,6 @@ export default function RainSttn() { return objSearch.city; }; - - useEffect(() => { if (!rainSttn.isInit) { rainSttnInit(codeData ?? "0"); @@ -108,8 +105,6 @@ export default function RainSttn() { const data = tableData(rainSttnRes, { code }); const chData = data .map((item: any) => { - console.log("item", item); - console.log("왜안돼", item.reuseBuilding[0].rainyObj.dtfcltCpct) return { ...item, ...item.reuseBuilding[0], @@ -124,10 +119,16 @@ export default function RainSttn() { ? "확인불가" : item.reuseBuilding[0].instlCstSprtAmt, chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + 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); - console.log("chData", chData) setBdstTable(chData); }, [code, rainSttnRes, rainSttn.rainSttHeadList]); @@ -147,9 +148,6 @@ 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 excelClick = useCallback(() => { // 최신 검색 조건 반영 const con = getConValue(); @@ -162,8 +160,6 @@ export default function RainSttn() { <div className="grid grid-cols-4 gap-4 "> <div className="col-span-4"> <Title title={"빗물재이용 시설 현황"} /> - - <SearchDiv> <SearchFormLeft> <div className="col-span-10 flex flex-row"> @@ -215,50 +211,6 @@ export default function RainSttn() { </div> </SearchFormRight> </SearchDiv> - - - - - - - - - - - {/* <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} - /> */} </div> </div> <div className="grid grid-cols-6 gap-4 "> diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index f9b3c6187..05ee774f1 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -5,19 +5,26 @@ 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, + 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"; @@ -34,6 +41,8 @@ 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; @@ -58,6 +67,35 @@ export default function RswtSttn() { } } + 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"); @@ -65,22 +103,25 @@ export default function RswtSttn() { }, [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) => { + console.log("item", item) + 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, + } + }) + .filter( + (item: customRswtBdst) => + item.reuseBuilding[0]?.rswtrObj !== undefined + ); - setBdstTable(chData); - } + setBdstTable(chData); }, [code, rswtSttnRes]); useEffect(() => { @@ -95,13 +136,11 @@ 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), code.cityCd, code.sggCd); + }, [rswtSttnSearch, objSearch, code.cityCd, code.sggCd]); useEffect(() => { if (codeCityOrSgg != null) rswtSttnSearch(pageNation, "20", codeCityOrSgg, code.cityCd, code.sggCd); @@ -113,38 +152,64 @@ 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> + </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(1, "20", String(con), 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} /> diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx index dccc8719c..ba81066be 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx @@ -5,6 +5,8 @@ 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"; +import { excelHtdflSttnParsing } from "./excel"; const htdflSttHeadList = htdflSttHeadListExport; const htdflSttNodeList = htdflSttNodeListExport; @@ -21,7 +23,8 @@ export type htdflSttnState = { }; type htdflSttnActions = { initHtdfl: (con: string) => void; - htdflSttnSearch: (page: number, total: string, con: string) => void; + htdflSttnSearch: (page: number, total: string, con: string, sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; htdflChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; @@ -67,22 +70,23 @@ 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, + sidoCode: SelectDataType[], + sggCode: SelectDataType[] + ) => { try { const htdflSttnRes = await getFetch( fetchType.WR, `/drain/facilityList/${page}/${total}/${con}` ); if (Number(total) > 9000) { - - + const htdflExcel = excelHtdflSttnParsing(htdflSttnRes, sidoCode, sggCode); set((state: htdflSttnState) => { - return { ...state, htdflSttn: { ...state.htdflSttn, - excelList: htdflSttnRes, + excelList: htdflExcel, }, }; }); From 45a0ff043dc090b840edf734ca2f51b5a6e4d121 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 3 Jul 2025 16:32:23 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=EC=9E=AC=EC=9D=B4=EC=9A=A9=EC=8B=A4?= =?UTF-8?q?=EC=A0=81=ED=98=84=ED=99=A9=20=EC=9E=A5=EB=82=B4=EC=99=B8?= =?UTF-8?q?=EC=9A=A9=EC=88=98=20=EC=B4=9D=EC=8B=A4=EC=A0=81=20=EC=B0=A8?= =?UTF-8?q?=ED=8A=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prfmncSttn/pbnstPrfmncSttn/page.tsx | 121 +++++++++--------- .../prfmncSttn/pbnstPrfmncSttn/index.tsx | 34 ++--- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx index f689eb745..3e860d744 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx @@ -68,8 +68,6 @@ export default function PbnstPrfmncSttn() { chartData5: lineChartDataProps[]; chartData6: lineChartDataProps[]; chartData7: lineChartDataProps[]; - chartData8: lineChartDataProps[]; - chartData9: lineChartDataProps[]; }>(); const [outLineData, setOutLineData] = useState<{ chartData1: lineChartDataProps[]; @@ -78,6 +76,8 @@ export default function PbnstPrfmncSttn() { chartData4: lineChartDataProps[]; chartData5: lineChartDataProps[]; chartData6: lineChartDataProps[]; + chartData7: lineChartDataProps[]; + chartData8: lineChartDataProps[]; }>(); type dnChartForm = { label: string, val: number, fill?: string }; @@ -228,16 +228,18 @@ export default function PbnstPrfmncSttn() { indstUswtr += element.indstUswtr; // 월별 합계 - inUsageSum = element.wshwtr + inUsageSum = + element.wshwtr + element.coolUswtr + element.cleanUswtr + element.drwtUswtr + element.dltnUswtr + element.ithlRswtr + element.ithlEtcUswtr - + element.cleanToilUswtr - + element.resn; - outUsageSum = element.lndwtr + outUsageSum = + element.cleanToilUswtr + + element.resn + + element.lndwtr + element.hydUswtr + element.ugwtChr + element.farmUswtr @@ -258,9 +260,10 @@ export default function PbnstPrfmncSttn() { dltnUswtrData.push({ label: `${month}월`, val: element.dltnUswtr, color: "purple" }); ithlRswtrData.push({ label: `${month}월`, val: element.ithlRswtr, color: "green" }); ithlEtcUswtrData.push({ label: `${month}월`, val: element.ithlEtcUswtr, color: "blue" }); + + cleanToilUswtrData.push({ label: `${month}월`, val: element.cleanToilUswtr, color: "magenta" }); resnData.push({ label: `${month}월`, val: element.resn, color: "skyblue" }); - lndwtrData.push({ label: `${month}월`, val: element.lndwtr, color: "red" }); hydUswtrData.push({ label: `${month}월`, val: element.hydUswtr, color: "orange" }); ugwtChrData.push({ label: `${month}월`, val: element.ugwtChr, color: "yellow" }); @@ -271,22 +274,18 @@ export default function PbnstPrfmncSttn() { } }); + let dnTotalIn = 0; + let dnTotalOut = 0; + inUsageArr.forEach((item) => { + dnTotalIn += item + }) + outUsageArr.forEach((item) => { + dnTotalOut += item + }) + // 도넛차트 데이터 - 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" }); + dnData.push({ label: "장내용수", val: dnTotalIn, fill: "#8DD8FF" }); + dnData.push({ label: "장외용수", val: dnTotalOut, fill: "#FFF085" }); // 장내용수 도넛 dnInData.push({ label: "세척수", val: wshwtr, fill: "#F7CFD8" }); @@ -296,10 +295,10 @@ export default function PbnstPrfmncSttn() { 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: cleanToilUswtr, fill: "#A19AD3" }); + dnOutData.push({ label: "세척살수용수", val: resn, fill: "#B1F0F7" }); dnOutData.push({ label: "조경용수", val: lndwtr, fill: "#81BFDA" }); dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "#F5F0CD" }); dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "#FADA7A" }); @@ -315,17 +314,17 @@ export default function PbnstPrfmncSttn() { chartData4: drwtUswtrData, chartData5: dltnUswtrData, chartData6: ithlRswtrData, - chartData7: ithlEtcUswtrData, - chartData8: cleanToilUswtrData, - chartData9: resnData + chartData7: ithlEtcUswtrData }); setOutLineData({ - chartData1: lndwtrData, - chartData2: hydUswtrData, - chartData3: ugwtChrData, - chartData4: farmUswtrData, - chartData5: rvrKeepUswtrData, - chartData6: indstUswtrData, + chartData1: cleanToilUswtrData, + chartData2: resnData, + chartData3: lndwtrData, + chartData4: hydUswtrData, + chartData5: ugwtChrData, + chartData6: farmUswtrData, + chartData7: rvrKeepUswtrData, + chartData8: indstUswtrData, }); setBarData(barData); setChartData(dnData); @@ -408,15 +407,7 @@ export default function PbnstPrfmncSttn() { chartData7: { label: '기타', color: "blue", - }, - chartData8: { - label: '청소화장실용수', - color: "magenta", - }, - chartData9: { - label: '세척살수용수', - color: "skyblue", - }, + } } satisfies ChartConfig; setLnInChartConfig(newChartConfig); } @@ -427,26 +418,34 @@ export default function PbnstPrfmncSttn() { if (outLineData?.chartData1) { const newChartConfig = { chartData1: { - label: '조경용수', + label: '청소화장실용수', color: "red", }, chartData2: { + label: '세척살수용수', + color: "pink", + }, + chartData3: { + label: '조경용수', + color: "gray", + }, + chartData4: { label: '친수용수', color: "orange", }, - chartData3: { + chartData5: { label: '지하수충전', color: "yellow", }, - chartData4: { + chartData6: { label: '농업용수', color: "green", }, - chartData5: { + chartData7: { label: '하천등유지용수', color: "blue", }, - chartData6: { + chartData8: { label: '공업용수', color: "purple", }, @@ -615,7 +614,7 @@ export default function PbnstPrfmncSttn() { <h1 className="">장내·외 월별 하수재이용실적 현황</h1> <div className="flex"> <div className="w-1/3"> - <MainChart chartConfig={barChartConfig} chartData={barData} chartTitle={"월별 장내·외 용수 총 실적"} chartForm={CHART_FORM.DOUBLEBAR} /> + <MainChart chartConfig={barChartConfig} chartData={barData} chartTitle={"월별 장내·외 용수 총 실적"} chartForm={CHART_FORM.DOUBLEBAR} showLegend={true} /> </div> <div className="w-1/3"> <MainChart chartConfig={lnInChartConfig} chartData={inLineData} chartTitle={"월별 장내 용수 실적"} chartForm={CHART_FORM.LINE} /> @@ -627,25 +626,25 @@ export default function PbnstPrfmncSttn() { <h1 className="">하수재이용실적 현황</h1> <ListDiv className="col-span-8 pr-6 "> {/* <ScrollArea className="h-[60vh]"> */} - {/* <div className="card-header"> + {/* <div className="card-header"> <h3 className="text-2xl font-medium text-label"> {"하수처리수재이용 실적(m3) 등록결과"} </h3> </div> */} - <UiTable - headName={undefined} - tableData={prfData || []} - headlist={monthHeadList} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - }}> - </UiTable> + <UiTable + headName={undefined} + tableData={prfData || []} + headlist={monthHeadList} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }}> + </UiTable> - {/* <ListDiv className="col-span-8 pr-6 "> + {/* <ListDiv className="col-span-8 pr-6 "> <ScrollArea className="h-[60vh]"> <div className="card-header"> <h3 className="text-2xl font-medium text-label"> diff --git a/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx b/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx index b513085ae..db8b6a717 100644 --- a/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx @@ -148,7 +148,7 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions let usageSum = 0; let year = ""; const yearsData = [] - + res.data.forEach((item) => { if (item.prfList.length === 0) { const year = ""; // 연도 정보가 없으면 빈 문자열, 필요시 item에서 추출 @@ -161,26 +161,26 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions item.prfList.forEach((acc) => { year = acc.ym?.substring(0, 4) ?? ""; inUsageSum = - (acc.wshwtr ?? 0) + - (acc.coolUswtr ?? 0) + - (acc.cleanUswtr ?? 0) + - (acc.drwtUswtr ?? 0) + - (acc.dltnUswtr ?? 0) + - (acc.ithlRswtr ?? 0) + - (acc.ithlEtcUswtr ?? 0) + - (acc.cleanToilUswtr ?? 0) + - (acc.resn ?? 0); + (acc.wshwtr ?? 0) + //조경용수 + (acc.coolUswtr ?? 0) + //냉각수 + (acc.cleanUswtr ?? 0) + //청소수 + (acc.drwtUswtr ?? 0) + //식수대 + (acc.dltnUswtr ?? 0) + //희석용수 + (acc.ithlRswtr ?? 0) + //중수도 + (acc.ithlEtcUswtr ?? 0) //기타 outUsageSum = - (acc.lndwtr ?? 0) + - (acc.hydUswtr ?? 0) + - (acc.ugwtChr ?? 0) + - (acc.farmUswtr ?? 0) + - (acc.rvrKeepUswtr ?? 0) + - (acc.indstUswtr ?? 0); + (acc.cleanToilUswtr ?? 0) + //청소화장실용수 + (acc.resn ?? 0)+ //세척살수용도 + (acc.lndwtr ?? 0) + //조경용수 + (acc.hydUswtr ?? 0) + //친수용수 + (acc.ugwtChr ?? 0) + //지하수충전 + (acc.farmUswtr ?? 0) + //농업용수 + (acc.rvrKeepUswtr ?? 0) + //하천등유지용수 + (acc.indstUswtr ?? 0); //공업용수 const yearData = yearsData.find( (yearItem) => yearItem.year === year && - yearItem.pbnstRuseFcltPk == acc.pbnstRuseFcltPk + yearItem.pbnstRuseFcltPk == acc.pbnstRuseFcltFk ); if (yearData) { From da1795a519302df3f99ecf8273c15b72e5adf673 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 3 Jul 2025 16:35:24 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=EC=B0=A8=ED=8A=B8=EB=B3=84=20=EB=B2=94?= =?UTF-8?q?=EB=A1=80=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/chart/DoubleBar.tsx | 53 +++++++++++++++- .../src/ui/chart/DoughnutChart.tsx | 61 ++++++++++++++++++- .../src/ui/chart/LineChart.tsx | 54 +++++++++++++++- 3 files changed, 164 insertions(+), 4 deletions(-) diff --git a/packages/common/business_components/src/ui/chart/DoubleBar.tsx b/packages/common/business_components/src/ui/chart/DoubleBar.tsx index 9627485aa..b201b3bf9 100644 --- a/packages/common/business_components/src/ui/chart/DoubleBar.tsx +++ b/packages/common/business_components/src/ui/chart/DoubleBar.tsx @@ -7,6 +7,7 @@ import { } from "./lib/chart"; import type { CSSProperties } from "react"; +/* const customStyles = { legendContainer: { display: "flex", @@ -17,6 +18,22 @@ 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; @@ -60,7 +77,7 @@ const CustomTooltip = ({ }; // 커스텀 범례 (글씨 크기 키우기 + 스타일 추가) -const CustomLegend = (props: any) => { +/*const CustomLegend = (props: any) => { const { payload } = props; return ( <div style={customStyles.legendContainer}> @@ -72,6 +89,38 @@ const CustomLegend = (props: any) => { ))} </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) { @@ -83,7 +132,7 @@ export default function DoubleBarChart({chartConfig=undefined, chartData=[], cha .map(key => item[key]) ).flat()); }; - console.log(chartData); + const barMaxValue = getMaxValue(chartData, 'barVal'); return ( <> diff --git a/packages/common/business_components/src/ui/chart/DoughnutChart.tsx b/packages/common/business_components/src/ui/chart/DoughnutChart.tsx index 39dee3d9e..99395267a 100644 --- a/packages/common/business_components/src/ui/chart/DoughnutChart.tsx +++ b/packages/common/business_components/src/ui/chart/DoughnutChart.tsx @@ -48,6 +48,7 @@ type LegendProps = { }; /** 차트 기본 스타일 */ +/* const customStyles = { legendContainer: { display: "flex", @@ -58,6 +59,23 @@ 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 }: { @@ -82,6 +100,7 @@ const CustomTooltip = ({ active, payload, label }: { }; // 커스텀 범례 +/* const CustomLegend = (props: LegendProps) => { const { payload } = props; if (!payload) return null; @@ -97,12 +116,52 @@ 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"> @@ -130,9 +189,9 @@ export default function DoughnutChart(props: { nameKey="label" innerRadius={60} /> - <CustomLegend /> </PieChart> </ChartContainer> + <CustomLegend payload={legendData} /> </div> </CardContent> </Card> diff --git a/packages/common/business_components/src/ui/chart/LineChart.tsx b/packages/common/business_components/src/ui/chart/LineChart.tsx index 4014702b6..28b4ceabf 100644 --- a/packages/common/business_components/src/ui/chart/LineChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineChart.tsx @@ -18,6 +18,7 @@ type LineChartProps = { } /** 차트 기본 스타일 */ +/* const customStyles = { legendContainer: { display: "flex", @@ -28,6 +29,23 @@ 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; @@ -60,7 +78,7 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: }; // 커스텀 범례 (글씨 크기 키우기 + 스타일 추가) -const CustomLegend = (props: LegendProps) => { +/*const CustomLegend = (props: LegendProps) => { const { payload } = props; if (!payload) return null; @@ -74,6 +92,40 @@ 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.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}; From 32271a86a02b7a45db9bbb41178311d59f7d8291 Mon Sep 17 00:00:00 2001 From: swcho <swcho@mind-one.co.kr> Date: Thu, 3 Jul 2025 16:58:14 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20DateMonthPicker=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=20startYear=20props=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20width,=20height=20=EB=86=92=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/date_month_picker/index.tsx | 3 ++ .../src/ui/date_month_picker/mothPicker.tsx | 28 +++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/common/business_components/src/ui/date_month_picker/index.tsx b/packages/common/business_components/src/ui/date_month_picker/index.tsx index d318b561f..1b97d9ce1 100644 --- a/packages/common/business_components/src/ui/date_month_picker/index.tsx +++ b/packages/common/business_components/src/ui/date_month_picker/index.tsx @@ -17,6 +17,7 @@ type MonthPickerProps = { field: { value: string; onChange: (date: string) => void }; // yyyyMM 문자열 selectClass?: string; readOnly?: boolean; + startYear?: number; // 시작 연도 props 추가 }; // yyyyMM → Date 객체 @@ -37,6 +38,7 @@ export const DateMonthPicker = ({ field, selectClass, readOnly = false, + startYear, }: MonthPickerProps) => { const [open, setOpen] = useState(false); @@ -75,6 +77,7 @@ export const DateMonthPicker = ({ <MonthPicker currentMonth={parsedDate} onMonthChange={handleSelect} + startYear={startYear} /> </PopoverContent> </Popover> diff --git a/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx b/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx index acf17fba4..2b64ab439 100644 --- a/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx +++ b/packages/common/business_components/src/ui/date_month_picker/mothPicker.tsx @@ -28,35 +28,41 @@ export type MonthPickerProps = { newMonth: Date | undefined, shouldClosePopover?: boolean ) => void; + startYear?: number; }; -export function MonthPicker({ currentMonth, onMonthChange }: MonthPickerProps) { +export function MonthPicker({ currentMonth, onMonthChange, startYear }: 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); - - - const yearRange = Array.from({ length: 21 }, (_, i) => currentYear - 20 + i); + + + // startYear가 없으면 기존과 동일하게 (현재년도 - 20년부터 현재년도까지) + // startYear가 있으면 해당 년도부터 현재년도까지, 내림차순으로 정렬 + const yearRange = startYear + ? Array.from({ length: currentYear - startYear + 1 }, (_, i) => currentYear - i) + : 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 ( @@ -77,7 +83,7 @@ const selectedYear = parseInt(yearFromProp); onMonthChange(newDate, false); }} > - <SelectTrigger className="w-[120px] h-7"> + <SelectTrigger className="w-[140px] h-9 text-base"> <SelectValue placeholder="년도" /> </SelectTrigger> <SelectContent> @@ -112,7 +118,7 @@ const selectedYear = parseInt(yearFromProp); onClick={() => onMonthChange(month, true)} > <time dateTime={format(month, "yyyy-MM-dd")}> - {format(month, 'MMM', { locale: ko })} + {format(month, 'MMM', { locale: ko })} </time> </button> </div> From d936c71f7ee27e486f54d2518f93ba8cc496dc88 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 3 Jul 2025 17:04:19 +0900 Subject: [PATCH 06/11] =?UTF-8?q?y=EC=B6=95=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=ED=95=98=EB=8B=A8=EC=97=90=20=EC=9C=84=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/common/business_components/src/ui/chart/BarChart.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx index 0802a72e4..62dd2333f 100644 --- a/packages/common/business_components/src/ui/chart/BarChart.tsx +++ b/packages/common/business_components/src/ui/chart/BarChart.tsx @@ -110,8 +110,7 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle=' axisLine={true} fontSize={12} fontWeight={500} - domain={[0, Math.ceil(barMaxValue * 1)]} - label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: 20 } : undefined} + label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideBottom', angle: 0, offset: -24 } : undefined} /> <ChartTooltip cursor={false} content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />}/> {chartData && chartData.length > 0 && ( From ed96df4b22edbf501eded10894134275b9593f59 Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 3 Jul 2025 17:24:15 +0900 Subject: [PATCH 07/11] =?UTF-8?q?barChart=20=EA=B8=80=EC=94=A8=20=EA=B0=80?= =?UTF-8?q?=EC=9A=B4=EB=8D=B0=20=EC=A0=95=EB=A0=AC,=20yFieldText=20?= =?UTF-8?q?=EC=A0=9C=EB=8C=80=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business_components/src/ui/chart/BarChart.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx index 62dd2333f..a7282830d 100644 --- a/packages/common/business_components/src/ui/chart/BarChart.tsx +++ b/packages/common/business_components/src/ui/chart/BarChart.tsx @@ -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"> + <div className="!mt-3 text-[2.5rem] font-bold text-center"> {chartTitle} </div>): null} - <div className="flex justify-center"> - <ChartContainer config={chartConfig ?? {}} className={chartClassName + " !w-[90%]"}> - <BarChart accessibilityLayer data={chartData}> + <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 }}> <CartesianGrid vertical={false} /> <XAxis dataKey="label" @@ -110,7 +110,7 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle=' axisLine={true} fontSize={12} fontWeight={500} - label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideBottom', angle: 0, offset: -24 } : undefined} + label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: -24, orientation: "left" } : undefined} /> <ChartTooltip cursor={false} content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />}/> {chartData && chartData.length > 0 && ( From 03179ede64699cd3ccdfe56efb44ea48bcfe6cbf Mon Sep 17 00:00:00 2001 From: JIeunhuh <entks301@naver.com> Date: Thu, 3 Jul 2025 18:02:11 +0900 Subject: [PATCH 08/11] =?UTF-8?q?gistree=20=EB=A0=88=EC=9D=B4=EC=96=B4=20?= =?UTF-8?q?=EC=98=86=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/common/business_components/src/ui/map/GisTree.js | 3 ++- .../business_components/src/ui/table/uiPageNations.tsx | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/common/business_components/src/ui/map/GisTree.js b/packages/common/business_components/src/ui/map/GisTree.js index 6a2e8face..9dbf2c42a 100644 --- a/packages/common/business_components/src/ui/map/GisTree.js +++ b/packages/common/business_components/src/ui/map/GisTree.js @@ -170,7 +170,7 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes image.src = canvas.toDataURL('image/png'); return image; }; - + if (!treeData || treeData.length === 0) return null; return ( @@ -203,6 +203,7 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes <input type="checkbox" checked={checked.includes(node.id)} onChange={() => handleCheck(node.id)} className="cursor-pointer" /> {node.icon && <span>{node.icon}</span>} <span className="text-[1.3rem] font-medium text-label">{node.text}</span> + {depth > 0 && <span><img className="cursor-pointer w-5 h-5" src='/images/map/layericon/Layer_Select_BTN.png' onClick={()=>{}} alt={node.text}></img></span>} </div> )} sort={(a, b) => { diff --git a/packages/common/business_components/src/ui/table/uiPageNations.tsx b/packages/common/business_components/src/ui/table/uiPageNations.tsx index 891fc4c81..a4ee3b4fc 100644 --- a/packages/common/business_components/src/ui/table/uiPageNations.tsx +++ b/packages/common/business_components/src/ui/table/uiPageNations.tsx @@ -40,7 +40,8 @@ export default function UiPageNations(commonPageNationsProps: CommonPageNationsP <PaginationItem> <PaginationPrevious href="#" - onClick={() => { + onClick={(e) => { + e.preventDefault(); if (startPage > 1) handlePageChange(startPage - 1); }} /> @@ -53,7 +54,7 @@ export default function UiPageNations(commonPageNationsProps: CommonPageNationsP <PaginationLink href="#" isActive={pageNum === pageProps.cur} - onClick={() => handlePageChange(pageNum)} + onClick={(e) => {e.preventDefault(); handlePageChange(pageNum)}} > {pageNum} </PaginationLink> @@ -65,7 +66,8 @@ export default function UiPageNations(commonPageNationsProps: CommonPageNationsP <PaginationItem> <PaginationNext href="#" - onClick={() => { + onClick={(e) => { + e.preventDefault(); if (endPage < totalPages) handlePageChange(endPage + 1); }} /> From c9138b72cacb72e09db39d32f072f6a7e5adfe3b Mon Sep 17 00:00:00 2001 From: YangJinSoo94 <jschrome782@gmail.com> Date: Thu, 3 Jul 2025 18:56:25 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=EC=B0=A8=ED=8A=B8=20=EC=A0=9C=EB=AA=A9?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/business_components/src/ui/chart/BarChart.tsx | 6 ++++++ .../business_components/src/ui/chart/LineBarChart.tsx | 4 ++-- .../common/business_components/src/ui/chart/LineChart.tsx | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx index a7282830d..994feb3b3 100644 --- a/packages/common/business_components/src/ui/chart/BarChart.tsx +++ b/packages/common/business_components/src/ui/chart/BarChart.tsx @@ -110,6 +110,12 @@ 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} /> <ChartTooltip cursor={false} content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />}/> diff --git a/packages/common/business_components/src/ui/chart/LineBarChart.tsx b/packages/common/business_components/src/ui/chart/LineBarChart.tsx index 8c7202104..11984cc14 100644 --- a/packages/common/business_components/src/ui/chart/LineBarChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineBarChart.tsx @@ -127,7 +127,7 @@ export default function LineBarchart({ className="text-[12px] font-bold" tickCount={6} orientation="left" - domain={[0, Math.ceil(lineMaxValue * 1)]} + tickFormatter={(value) => value.toLocaleString()} 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" - domain={[0, Math.ceil(barMaxValue * 1)]} + tickFormatter={(value) => value.toLocaleString()} label={{ value: yFieldText2, angle: -90, position: 'insideRight' }} reversed={true} />} diff --git a/packages/common/business_components/src/ui/chart/LineChart.tsx b/packages/common/business_components/src/ui/chart/LineChart.tsx index 28b4ceabf..6c1b6e7bd 100644 --- a/packages/common/business_components/src/ui/chart/LineChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineChart.tsx @@ -193,7 +193,7 @@ export default function Linechart({ > <CartesianGrid vertical={false} /> <XAxis dataKey="label" fontSize="8px" fontWeight="bold" /> - <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' }} /> + <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' }} /> <Tooltip content={<CustomTooltip />} /> {showLegend && <Legend content={CustomLegend as ContentType}/>} {Object.keys(chartData).map((key) => { From b20948fcfe67039f4e02fa04e3945ad08dd93431 Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 3 Jul 2025 19:46:11 +0900 Subject: [PATCH 10/11] =?UTF-8?q?=EC=9E=A0=EC=9E=AC=EC=88=98=EC=9A=94?= =?UTF-8?q?=EC=B2=98=20=EC=97=91=EC=85=80=20=EB=93=B1=EB=A1=9D=20=EC=8B=9C?= =?UTF-8?q?=20=EB=A1=9C=EB=94=A9=EB=B0=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wr/app/matMng/coMng/ldrmntCoSttn/page.tsx | 7 +- .../app/store/matDmd/ldrmntCoSttn/index.tsx | 64 +++++++++++++------ .../coReg/coRegExcel/coRegExcelModal.tsx | 39 +++++------ 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index eb43b29bf..e33bcc265 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -28,8 +28,10 @@ import { type SelectDataType } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; +import LoadingOverlay from "@common/business_components/ui/loadingBar"; import { Button } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; +import { Toaster } from "react-hot-toast"; export default function LdrmntCoSttn() { const { code, ldrmnt, ldrmntInit, ldrmntSearch, } = useWrStore( @@ -273,7 +275,7 @@ export default function LdrmntCoSttn() { <div className="overflow-x-auto"> <ListDiv className="min-w-max"> <UiTable - headName={[]} + headName={undefined} tableData={bdstTable || []} headlist={ldrmntHeadListExport} pageSize={20} @@ -299,8 +301,9 @@ export default function LdrmntCoSttn() { setIsExcelOpen({ isModal: !isExcelOpen.isModal }) }} bodyClass={"w-[40vw] max-w-none"} - body={<CoRegExcel />} + body={<CoRegExcel isModal={(isOpen) => setIsExcelOpen({ isModal: isOpen })} />} /> + <Toaster position="top-center"></Toaster> </div> diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index 6a5f18247..289ced6e1 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -20,6 +20,7 @@ export type ldrmntState = { excelList: ExcelType[]; isInit: boolean; ldrmntRes: customLdrmnt[]; + isLoading: boolean; }; }; @@ -35,6 +36,7 @@ type ldrmntActions = { ldrmntSearch: (page: number, sggCd: string, total: string, coNm: string) => void; ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; ldrmntDelete: () => void; + loadingOpen: (isOpen: boolean) => void }; export type ldrmntType = ldrmntState & ldrmntActions; @@ -46,6 +48,7 @@ export const ldrmntStateExport: ldrmntState = { excelList: [], isInit: false, ldrmntRes: ldrmntRes, + isLoading: false, }, }; @@ -75,31 +78,30 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( console.log(e) } }, + loadingOpen: (isOpen) => { + return set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + isLoading: isOpen, + }, + }; + }); + }, ldrmntRegData: async (data) => { - try { - const response = await postFectch( - "/reuseFc/request/temp", - data, - fetchType.WR - ); + await deleteFectch( + `/reuseFc/request/temp`, + ); - console.log('response ', response) + const response = await postFectch( + "/reuseFc/request/temp", + data, + fetchType.WR + ); - if (response.status === 200) { - ToastFormUi({ - body: "잠재수요처 등록이 완료되었습니다. ", - title: "잠재수요처 등록", - }); + console.log('response ', response) - } - } catch (e) { - console.log(e) - ToastFormUi({ - body: "잠재수요처 등록이 실패하였습니다. ", - title: "잠재수요처 등록", - }); - - } }, ldrmntSearch: async (page: number, total: string, sggCd: string, coNm: string) => { let searchUrl = ""; @@ -111,6 +113,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( searchUrl = `/reuseFc/request/temp/${page}/${total}/${sggCd}`; } } + try { const ldrmntRes = await getFetch( fetchType.WR, @@ -178,11 +181,30 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( }, ldrmntDelete: async () => { try { + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + isLoading: true, + }, + }; + }); const response = await deleteFectch( `/reuseFc/request/temp`, ); } catch (error) { + console.log("error", error) + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + isLoading: false, + }, + }; + }); console.error("Error ldrmntDelete:", error); } }, diff --git a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx index 89f15a3cc..6f6afe186 100644 --- a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx +++ b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx @@ -4,32 +4,36 @@ 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 LoadingOverlay from "@common/business_components/ui/loadingBar"; import { Button, Progress } 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 CoRegExcel() { - - +export default function CoRegExcel({ isModal }: { isModal: (open: boolean) => void }) { + const { ldrmnt,loadingOpen } = useWrStore((state) => state); + const { isLoading } = ldrmnt; const form = useForm<z.infer<typeof coRegExcel>>({ resolver: zodResolver(coRegExcel), }); const { ldrmntRegData, ldrmntDelete } = useWrStore((state) => state); const [excelData, setExcelData] = useState<customLdrmnt[]>(); - const [file, setFiles] = useState<File | undefined>(); + useEffect(() => { + console.log("ldrmnt", ldrmnt) + }, [ldrmnt]) + const onSubmit = (values: z.infer<typeof coRegExcel>) => { - ldrmntDelete(); + loadingOpen(true); if (file) { - filePicked(file, 0).then((res) => { - //TODO:loading + filePicked(file, 0).then(async (res) => { + try { let array: { [key: string]: string | number }[] = [] - let isError = false; if (Array.isArray(res)) { res.some((item, index) => { let object: { [key: string]: string | number } = {} @@ -43,26 +47,24 @@ export default function CoRegExcel() { } return false; }) - if (isError === true) - return true; + array.push(object) - if (index != 0 && index % 5000 == 0) { - ldrmntRegData(array); - array = [] - array.length = 0; - } return false; }) } - if (isError === false) - ldrmntRegData(array); + await ldrmntRegData(array); + isModal(false); + loadingOpen(false); + toast.success(`잠재수요처 등록이 완료되었습니다.`); } catch (e) { console.log(e) + loadingOpen(false); alert(e) return true; } - + }).catch((e)=>{ + console.log("file", e); }); }; } @@ -70,6 +72,7 @@ export default function CoRegExcel() { return ( <> <div> + <LoadingOverlay isLoading={isLoading}></LoadingOverlay> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> <div> From 01ebab4a94be128d2919b44ef5d2bfe5b721759e Mon Sep 17 00:00:00 2001 From: jyha00 <jyha@mind-one.co.kr> Date: Thu, 3 Jul 2025 20:21:01 +0900 Subject: [PATCH 11/11] =?UTF-8?q?=EB=A1=9C=EB=94=A9=EB=B0=94=20import=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/common/business_components/src/ui/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index fd1e6fe9e..06c641259 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -21,4 +21,5 @@ export * from "./table_div"; export * from "./title"; export * from "./sdmInsertForm"; export * from "./popover_ui"; -export * from "./date_month_picker"; \ No newline at end of file +export * from "./date_month_picker"; +export * from "./loadingBar"; \ No newline at end of file