From 9ac72c111b6b05ee21ddce1b09455c305397aca2 Mon Sep 17 00:00:00 2001 From: ljpark Date: Thu, 7 May 2026 15:39:28 +0900 Subject: [PATCH] =?UTF-8?q?dm:=20=EC=88=98=EC=9A=94=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EC=9C=A0=EC=82=AC=EC=82=AC=EB=A1=80=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reuse/apply/modal/SimilarCaseModal.tsx | 8 +- .../app/(with-layout)/apply/dmdinfo/page.tsx | 98 ++++++++++--------- .../app/(with-layout)/apply/status/page.tsx | 41 +++++++- apps/dm/app/store/sdmMng/index.tsx | 2 + 4 files changed, 96 insertions(+), 53 deletions(-) diff --git a/apps/dm/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx b/apps/dm/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx index 774ab81b8..6f68ab515 100644 --- a/apps/dm/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx +++ b/apps/dm/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx @@ -1,10 +1,12 @@ -// apps/dm/app/(landing)/reuse/apply/modal/SimilarCaseModal.tsx (유사사례 모달) +/** + * 유사사례 Modal + */ "use client"; import { useEffect, useMemo, useState, useId } from "react"; import { createPortal } from "react-dom"; -type Criterion = "" | "supplyAmt" | "treatment" | "usePurpose"; +type Criterion = "" | "supplyAmt" | "treatment" | "usePurpose"; // 유사기준 export type SimilarCaseRow = { caseId: string; @@ -90,7 +92,7 @@ export default function SimilarCaseModal({ // 모달 열릴 때 초기화 useEffect(() => { if (!open) return; - setCriterion("supplyAmt"); + setCriterion("supplyAmt"); // 요구수량(㎥/d) onSearch("supplyAmt"); setSelectedCaseId(""); }, [open]); diff --git a/apps/dm/app/(with-layout)/apply/dmdinfo/page.tsx b/apps/dm/app/(with-layout)/apply/dmdinfo/page.tsx index 18f829856..cef0461d2 100644 --- a/apps/dm/app/(with-layout)/apply/dmdinfo/page.tsx +++ b/apps/dm/app/(with-layout)/apply/dmdinfo/page.tsx @@ -36,9 +36,9 @@ export default function DemandRegisterPage() { // 기본정보 const [reqDate, setReqDate] = useState(today); - const [reqQty, setReqQty] = useState(""); - const [usePurpose, setUsePurpose] = useState(""); - const [hopePrice, setHopePrice] = useState(""); + const [reqQty, setReqQty] = useState(""); // 요구수량(㎥/d) + const [usePurpose, setUsePurpose] = useState(""); // 사용용도 + const [hopePrice, setHopePrice] = useState(""); // 희망단가 // 요구수질 const [coliform, setColiform] = useState(""); // 총대장균군수 @@ -62,9 +62,9 @@ export default function DemandRegisterPage() { const [cand3, setCand3] = useState(""); //const [candidateList, setCandidateList] = useState([]); - const useTypesData = useDmStore((state) => state.Sdm.useTypesData); - const getUseTypesData = useDmStore((state) => state.getUseTypesData); - const [openSimilar, setOpenSimilar] = useState(false); + const useTypesData = useDmStore((state) => state.Sdm.useTypesData); // 사용용도 + const getUseTypesData = useDmStore((state) => state.getUseTypesData); // 사용용도 함수 + const [openSimilar, setOpenSimilar] = useState(false); // 유사사례 modal open // 후보지 팝업 메시지 핸들러 const candsRef = useRef<{ name: string; code: string }[]>([]); @@ -114,15 +114,16 @@ export default function DemandRegisterPage() { const getSimilarCaseList = useDmStore((state) => state.getSimilarCaseList); const [farmText, setFarmText] = useState("이하"); - const insertSdmInfoData = useDmStore( - (state) => state.insertSdmInfoData - ); + const insertSdmInfoData = useDmStore( (state) => state.insertSdmInfoData ); // 수요정보등록 useEffect(() => { - getUseTypesData(); + getUseTypesData(); // 사용용도 조회 }, [getUseTypesData]); + // 후보지 선택 팝업이 window.postMessage로 넘긴 선택 결과를 받아 + // 현재 화면의 후보지 입력칸(cand1~3)에 반영한다. useEffect(() => { + // message 이벤트의 payload를 읽어 후보지 목록 상태를 갱신하는 핸들러 const handler = (event: MessageEvent) => { if (!event.data) return; @@ -199,25 +200,26 @@ export default function DemandRegisterPage() { return true; } + // 유사사례 const rows: SimilarCaseRow[] = similarCaseList.map((el, idx) => ({ caseId: String(idx), - projectName: el.ruseBizNm, - period: `${el.bizBgngDate} ~ ${el.bizEndDate}`, + projectName: el.ruseBizNm, // 사업명 + period: `${el.bizBgngDate} ~ ${el.bizEndDate}`, // 사업기간 - supplyFacilityType: el.splyFcltKnd, - supplyName: el.splyFcltNm, - supplyCapacity: Number(el.splyFcltCpct), + supplyFacilityType: el.splyFcltKnd, // 시설종류 + supplyName: el.splyFcltNm, // 공급처명 + supplyCapacity: Number(el.splyFcltCpct), // 공급처 시설용량 - demandName: el.dmdFcltNm, - demandAddress: el.dmdFcltAddr, + demandName: el.dmdFcltNm, // 수요처명 + demandAddress: el.dmdFcltAddr, // 수요처 주소 - facilityCapacity: Number(el.ruseFcltCpct), - pipeKm: Number(el.ruseFcltPplLen), - purpose: el.ruseFcltUsg, + facilityCapacity: Number(el.ruseFcltCpct), // 재이용시설 시설용량 + pipeKm: Number(el.ruseFcltPplLen), // 재이용시설 관로길이 + purpose: el.ruseFcltUsg, // 재이용시설 용도 - supplyAmt: Number(el.ruseFcltSplyCpct), - treatment: el.ruseFcltPrcsMsrc, - usePurpose: el.ruseFcltUsg, + supplyAmt: Number(el.ruseFcltSplyCpct), // 재이용시설 공급(용)량 + treatment: el.ruseFcltPrcsMsrc, // 재이용시설 처리공법 + usePurpose: el.ruseFcltUsg, // 재이용시설 용도 })); const detailsByCaseId: Record = {}; @@ -311,6 +313,7 @@ export default function DemandRegisterPage() { } } + // 후보지 조회 팝업 Open const searchCandidate = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); @@ -327,28 +330,27 @@ export default function DemandRegisterPage() { window.open(url, "candidatePopup", popupOptions); }; + // 유사기준 const getCriterionCode = (criterion: string) => { switch (criterion) { - case "supplyAmt": - return "S"; - case "money": - return "M"; - case "usePurpose": - return "U"; - default: - return ""; + case "supplyAmt": return "S"; // 공급량 + case "money": return "M"; // 단가? + case "usePurpose": return "U"; // 이용용도 + default: return ""; } }; + // 유사사례 Modal Open const searchSimilarCase = async (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); setOpenSimilar(true); }; + // 수요정보 입력란 초기화 const initQualityForm = () => { setColiform(""); - setNoDetect(false); + setNoDetect(false); // 총대장균군수 불검출 setTn(""); setResidualCl(""); setTp(""); @@ -363,6 +365,7 @@ export default function DemandRegisterPage() { setFarmText("이하"); } + // 사용용도별 초기화 const fncSetOptionValue = (e: React.ChangeEvent) => { const value = e.target.value; initQualityForm(); @@ -640,19 +643,20 @@ export default function DemandRegisterPage() { {/* 후보지 선택 */}
- 공급처 후보지 선택 -
- (필수아님) + + 공급처 후보지 선택 + (필수아님) +
-
+
- + - -
+
+
@@ -703,7 +705,7 @@ export default function DemandRegisterPage() { rows={rows} // 실제 데이터 detailsByCaseId={detailsByCaseId} onSearch={async (criterion) => { - const code = getCriterionCode(criterion); + const code = getCriterionCode(criterion); // 'S' 공급량, 'U' 사용용도 if (!code) return; // 값은 상황에 맞게 (예시: usePurpose) console.log(code+' req: '+reqQty+' purpose :'+usePurpose); diff --git a/apps/dm/app/(with-layout)/apply/status/page.tsx b/apps/dm/app/(with-layout)/apply/status/page.tsx index 44d6f1bbb..d5dbf68c5 100644 --- a/apps/dm/app/(with-layout)/apply/status/page.tsx +++ b/apps/dm/app/(with-layout)/apply/status/page.tsx @@ -6,12 +6,15 @@ import { useDmStore } from "@/app/store"; import type { DemandCompBizType } from "@/app/store/sdmMng"; import SubPageHeader from "@/components/SubPageHeader"; +import UiPageNations from "@common/business_components/ui/table/uiPageNations"; import { useEffect, useMemo, useRef, useState } from "react"; type TopField = { label: string; key: string, value: string; required?: boolean }; type PairField = { label: string; key: string, value: string }; type SessionUser = { dmdInfoId?: string }; +const PAGE_SIZE = 10; + const formatDate = (value: string | Date | "" | undefined) => { if (!value) return "-"; const date = new Date(value); @@ -135,6 +138,7 @@ export default function DemandStatusPage() { const [isLoginStorageInfo, setIsLoginStorageInfo] = useState(false); const [selectedDmdInfoSn, setSelectedDmdInfoSn] = useState(null); const [transformedSdmInfoStatusList, setTransformedSdmInfoStatusList] = useState([]); + const [currentPage, setCurrentPage] = useState(1); // 수정 유무 const [ isEditMode, setIsEditMode ] = useState(false); @@ -213,6 +217,18 @@ export default function DemandStatusPage() { ); }, [transformedSdmInfoStatusList, selectedDmdInfoSn]); + const pagedSdmInfoStatusList = useMemo(() => { + const startIndex = (currentPage - 1) * PAGE_SIZE; + return transformedSdmInfoStatusList.slice(startIndex, startIndex + PAGE_SIZE); + }, [currentPage, transformedSdmInfoStatusList]); + + useEffect(() => { + const totalPages = Math.max(1, Math.ceil(transformedSdmInfoStatusList.length / PAGE_SIZE)); + if (currentPage > totalPages) { + setCurrentPage(totalPages); + } + }, [currentPage, transformedSdmInfoStatusList.length]); + const topFields: TopField[] = useMemo(() => { if (!selectedSdmInfoStatus) return []; @@ -392,7 +408,7 @@ export default function DemandStatusPage() { ) : ( - transformedSdmInfoStatusList.map((sdmInfoStatus, index) => { + pagedSdmInfoStatusList.map((sdmInfoStatus, index) => { const active = sdmInfoStatus.dmdInfoSn === selectedSdmInfoStatus?.dmdInfoSn; return ( - {sdmInfoStatus.index || index + 1} + + {sdmInfoStatus.index || (currentPage - 1) * PAGE_SIZE + index + 1} + {formatValue(sdmInfoStatus.ctpvCd)} {formatValue(sdmInfoStatus.sggCd)} {formatValue(sdmInfoStatus.dmdCoNm)} @@ -432,6 +450,25 @@ export default function DemandStatusPage() { + {transformedSdmInfoStatusList.length > 0 ? ( +
+ +
+ ) : null}
diff --git a/apps/dm/app/store/sdmMng/index.tsx b/apps/dm/app/store/sdmMng/index.tsx index 19a5a10cd..dfe9d7850 100644 --- a/apps/dm/app/store/sdmMng/index.tsx +++ b/apps/dm/app/store/sdmMng/index.tsx @@ -537,6 +537,8 @@ const getSdmInfoStatusList = async (dmdInfoId: string) => { // 유사사례 조회 const fetchGetSimilarCaseList = async (part: string, value: number | string) => { try { + // part : 'S' 요구수량 , 'U' 사용용도 + // default : part 'S' , value 10000 즉, part와 value값이 없으면 backend에서 default값으로 조회함. const url = '/reuseFc/pubFcRuseCase/dm/' + part + '/' + (value ? value : 0); const res = await getFetch(fetchType.WR, url); return res?.data || [];