diff --git a/apps/dm/app/(landing)/reuse/_components/CaseTabsCarousel.tsx b/apps/dm/app/(landing)/reuse/_components/CaseTabsCarousel.tsx index ece8f0848..e70bc3e02 100644 --- a/apps/dm/app/(landing)/reuse/_components/CaseTabsCarousel.tsx +++ b/apps/dm/app/(landing)/reuse/_components/CaseTabsCarousel.tsx @@ -33,8 +33,8 @@ type CaseItem = { }; const TABS: { key: TabKey; label: string }[] = [ - { key: "rain", label: "빗물 재이용 사례" }, - { key: "reuse", label: "중수 재이용 사례" }, + { key: "rain", label: "빗물이용시설 사례" }, + { key: "reuse", label: "중수도 사례" }, { key: "sewage", label: "하수 재이용 사례" }, { key: "global", label: "해외 재이용 사례" }, ]; @@ -59,7 +59,7 @@ const MOCK: Record = { ], reuse: Array.from({ length: 6 }).map((_, i) => ({ id: `reuse-${i}`, - title: `중수 재이용 사례 ${i + 1}`, + title: `중수도 사례 ${i + 1}`, desc: "설명 문구가 들어갑니다. (최대 2~3줄) …", imageSrc: "/images/landing/sample_case.png", href: "#", diff --git a/apps/dm/app/(landing)/reuse/_constants/lnb.ts b/apps/dm/app/(landing)/reuse/_constants/lnb.ts index 671dabd65..f88de62bc 100644 --- a/apps/dm/app/(landing)/reuse/_constants/lnb.ts +++ b/apps/dm/app/(landing)/reuse/_constants/lnb.ts @@ -23,7 +23,7 @@ export const LNB_CASES = [ // 물 재이용 사례처럼 2depth가 있는 메뉴 export const LNB_BUSINESS: LnbItem[] = [ { - label: "빗물 재이용 사례", + label: "빗물이용시설 사례", children: [ { label: "경기도 수원시", href: "/reuse/business/rain/suwon" }, // { label: "충청남도 보령시", href: "/reuse/business/rain/bolyeong" }, @@ -31,7 +31,7 @@ export const LNB_BUSINESS: LnbItem[] = [ ], }, { - label: "중수 재이용 사례", + label: "중수도 사례", children: [{ label: "사례 목록", href: "/reuse/business/graywater" }], }, { diff --git a/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx b/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx index 374e3ddd4..35dfc1247 100644 --- a/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx +++ b/apps/dm/app/(landing)/reuse/business/_components/GreywaterExampleSection.tsx @@ -109,7 +109,7 @@ function InfoList({ } export default function GreywaterExampleSection() { - const title = "중수 재이용 사례"; + const title = "중수도 사례"; return (
{/* 상단 타이틀 */} diff --git a/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx b/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx index d73fdf1a2..0381b3ebc 100644 --- a/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx +++ b/apps/dm/app/(landing)/reuse/business/_components/RainExampleSection.tsx @@ -17,7 +17,7 @@ function Hr({ className = "" }: { className?: string }) { } export default function RainExampleSection() { - const title = "빗물 재이용 사례"; + const title = "빗물이용시설 사례"; return (
{/* 상단 타이틀 */} diff --git a/apps/dm/app/(landing)/reuse/business/page.tsx b/apps/dm/app/(landing)/reuse/business/page.tsx index 9386012b1..660680c0c 100644 --- a/apps/dm/app/(landing)/reuse/business/page.tsx +++ b/apps/dm/app/(landing)/reuse/business/page.tsx @@ -9,7 +9,7 @@ import GlobalCaseSection from "./_components/GlobalCaseSection"; const menus: BusinessSubNavMenu[] = [ { key: "example-rain", - label: "빗물 재이용 사례", + label: "빗물이용시설 사례", sections: [ { id: "example-rain-suwon", label: "경기도 수원시" }, { id: "example-rain-jeju", label: "제주특별자치도" }, @@ -17,7 +17,7 @@ const menus: BusinessSubNavMenu[] = [ }, { key: "example-greywater", - label: "중수 재이용 사례", + label: "중수도 사례", defaultOpen: false, sections: [ { id: "example-greywater-ansan", label: "경기도 안산시" }, diff --git a/apps/dm/app/(landing)/reuse/business/rain/suwon/page.tsx b/apps/dm/app/(landing)/reuse/business/rain/suwon/page.tsx index 3acba860b..d96772126 100644 --- a/apps/dm/app/(landing)/reuse/business/rain/suwon/page.tsx +++ b/apps/dm/app/(landing)/reuse/business/rain/suwon/page.tsx @@ -46,7 +46,7 @@ export default function GreywaterPage() { crumbs={[ { label: "Home", href: "/reuse" }, { label: "물 재이용 사례" }, - { label: "빗물 재이용 사례" }, + { label: "빗물이용시설 사례" }, { label: "수원시", href: "/reuse/business/rain/suwon" }, ]} hideFooterLine diff --git a/apps/dm/app/(with-layout)/example/_components/GlobalCaseSection.tsx b/apps/dm/app/(with-layout)/example/_components/GlobalCaseSection.tsx index 141658d3e..73492a21d 100644 --- a/apps/dm/app/(with-layout)/example/_components/GlobalCaseSection.tsx +++ b/apps/dm/app/(with-layout)/example/_components/GlobalCaseSection.tsx @@ -650,8 +650,7 @@ const globalCases: GlobalCase[] = [ depth: 1, }, - { text: "안핑을 포함한 16건 공사 완료시 628,100 CMD 공급 가능" }, - { text: "공급단가는 수질과 운영조건에 따라 다르게 책정" }, + ], }, { diff --git a/apps/dm/app/(with-layout)/example/_components/GreywaterExampleSection.tsx b/apps/dm/app/(with-layout)/example/_components/GreywaterExampleSection.tsx index b038216b6..1705a6c84 100644 --- a/apps/dm/app/(with-layout)/example/_components/GreywaterExampleSection.tsx +++ b/apps/dm/app/(with-layout)/example/_components/GreywaterExampleSection.tsx @@ -109,7 +109,7 @@ function InfoList({ } export default function GreywaterExampleSection() { - const title = "중수 재이용 사례"; + const title = "중수도 사례"; return (
{/* 상단 타이틀 */} diff --git a/apps/dm/app/(with-layout)/example/_components/RainExampleSection.tsx b/apps/dm/app/(with-layout)/example/_components/RainExampleSection.tsx index 7ced9d60e..5f975356a 100644 --- a/apps/dm/app/(with-layout)/example/_components/RainExampleSection.tsx +++ b/apps/dm/app/(with-layout)/example/_components/RainExampleSection.tsx @@ -123,7 +123,7 @@ function RainTable({ rows }: { rows: RainTableRow[] }) { } export default function RainExampleSection() { - const title = "빗물 재이용 사례"; + const title = "빗물이용시설 사례"; return (
diff --git a/apps/dm/app/(with-layout)/example/_components/SewageExampleSection.tsx b/apps/dm/app/(with-layout)/example/_components/SewageExampleSection.tsx index 7d9a5a3da..cd4c1d420 100644 --- a/apps/dm/app/(with-layout)/example/_components/SewageExampleSection.tsx +++ b/apps/dm/app/(with-layout)/example/_components/SewageExampleSection.tsx @@ -334,7 +334,7 @@ const sewageCases: SewageCase[] = [ ]; export default function SewageExampleSection() { - const title = "하수처리 재이용 사례"; + const title = "하수처리수 재이용 사례"; return (
diff --git a/apps/dm/app/(with-layout)/example/greywater/page.tsx b/apps/dm/app/(with-layout)/example/greywater/page.tsx index 154d98b06..ab76d58d7 100644 --- a/apps/dm/app/(with-layout)/example/greywater/page.tsx +++ b/apps/dm/app/(with-layout)/example/greywater/page.tsx @@ -115,11 +115,11 @@ export default function GreywaterPage() { return (
diff --git a/apps/dm/app/(with-layout)/intro/_components/RainIntroSection.tsx b/apps/dm/app/(with-layout)/intro/_components/RainIntroSection.tsx index 4de564a54..bbf1b141a 100644 --- a/apps/dm/app/(with-layout)/intro/_components/RainIntroSection.tsx +++ b/apps/dm/app/(with-layout)/intro/_components/RainIntroSection.tsx @@ -54,7 +54,7 @@ function SectionShell({ } export default function RainIntroSection() { - const title = "빗물 이용시설"; + const title = "빗물이용시설"; return (
diff --git a/apps/dm/app/(with-layout)/intro/_components/TreatedIntroSection.tsx b/apps/dm/app/(with-layout)/intro/_components/TreatedIntroSection.tsx index ff3ece0fc..19debe88f 100644 --- a/apps/dm/app/(with-layout)/intro/_components/TreatedIntroSection.tsx +++ b/apps/dm/app/(with-layout)/intro/_components/TreatedIntroSection.tsx @@ -52,7 +52,7 @@ function SectionShell({ } export default function TreatedIntroSection() { - const title = "하수처리수"; + const title = "하수처리수 재이용"; return (
diff --git a/apps/dm/app/(with-layout)/intro/page.tsx b/apps/dm/app/(with-layout)/intro/page.tsx index 02d050764..7b643e55d 100644 --- a/apps/dm/app/(with-layout)/intro/page.tsx +++ b/apps/dm/app/(with-layout)/intro/page.tsx @@ -9,7 +9,7 @@ import TreatedIntroSection from "./_components/TreatedIntroSection"; const menus: BusinessSubNavMenu[] = [ { key: "intro-law", - label: "물 재이용 법", + label: "물재이용법", sections: [ { id: "law-plan", label: "법률 제·개정 및 기본계획 수립" }, { id: "plan-performance", label: "제2차 계획 대비 실적 현황" }, @@ -21,7 +21,7 @@ const menus: BusinessSubNavMenu[] = [ }, { key: "intro-rain", - label: "빗물 이용시설", + label: "빗물이용시설", defaultOpen: false, sections: [ { id: "rain-intro", label: "빗물 재이용 소개" }, @@ -48,7 +48,7 @@ const menus: BusinessSubNavMenu[] = [ }, { key: "intro-treated", - label: "하수처리수", + label: "하수처리수 재이용", defaultOpen: false, sections: [ { id: "treatedwater-intro", label: "하수처리수 소개" }, diff --git a/apps/dm/components/CaseTabsCarousel.tsx b/apps/dm/components/CaseTabsCarousel.tsx index d0d399786..f9ad4f2a8 100644 --- a/apps/dm/components/CaseTabsCarousel.tsx +++ b/apps/dm/components/CaseTabsCarousel.tsx @@ -33,8 +33,8 @@ type CaseItem = { }; const TABS: { key: TabKey; label: string }[] = [ - { key: "rain", label: "빗물 재이용 사례" }, - { key: "greywater", label: "중수 재이용 사례" }, + { key: "rain", label: "빗물이용시설 사례" }, + { key: "greywater", label: "중수도 사례" }, { key: "sewage", label: "하수 재이용 사례" }, { key: "global", label: "해외 재이용 사례" }, ]; diff --git a/apps/dm/public/images/landing/intro/law_timeline.png b/apps/dm/public/images/landing/intro/law_timeline.png index 68cd72d17..56ff1c347 100644 Binary files a/apps/dm/public/images/landing/intro/law_timeline.png and b/apps/dm/public/images/landing/intro/law_timeline.png differ diff --git a/apps/dm/public/images/landing/intro/policy_timeline.png b/apps/dm/public/images/landing/intro/policy_timeline.png index 1cb90cef4..296bad776 100644 Binary files a/apps/dm/public/images/landing/intro/policy_timeline.png and b/apps/dm/public/images/landing/intro/policy_timeline.png differ diff --git a/apps/wr/.eslintrc.ts b/apps/wr/.eslintrc.ts new file mode 100644 index 000000000..9c0110d98 --- /dev/null +++ b/apps/wr/.eslintrc.ts @@ -0,0 +1,6 @@ +module.exports = { + parserOptions: { + tsconfigRootDir: __dirname, + project: "./tsconfig.eslint.json", + }, +}; \ No newline at end of file diff --git a/apps/wr/app/(popUp-layout)/constCostSimulation/page.tsx b/apps/wr/app/(popUp-layout)/constCostSimulation/page.tsx new file mode 100644 index 000000000..c76e3d597 --- /dev/null +++ b/apps/wr/app/(popUp-layout)/constCostSimulation/page.tsx @@ -0,0 +1,28 @@ +"use client"; + +/** + * 표준공사비 시뮬레이션 Popup + */ +import { useForm } from "react-hook-form"; +import ConCostForm from "@/components/ui/form/coMat/conCostForm/conCostForm"; +import type { DmdCoReqType } from "@/app/store/matDmd/coMatRvw/type"; +import ListDiv from "@common/business_components/ui/list_div"; + +export default function ConstCostSimulationPage() { + const form = useForm({ + defaultValues: { + dmndQty: 0, + demandCst: { cstrnCst: 0, usgPrcsProcs: "", prcsFcltCpctCstrnCst: 0, fcltSbsdCstrnCst: 0 }, + totalConstCost: 0 + } as any + }); + + return ( + +
+

표준공사비 산정

+
+ +
+ ) +} diff --git a/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx b/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx index 4304945bd..bf784b41a 100644 --- a/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx +++ b/apps/wr/app/(with-layout)/matMng/coMat/coMatRvw/page.tsx @@ -52,6 +52,7 @@ export default function CoMatRvw() { const { auth, code, coRvw, coMatRvwInit, coMatRvwSearch, coMatRvwInqua } = useWrStore((state) => state); const { coMatRvwRes, coMatRvwCount } = coRvw; + // const [mounted, setMounted] = useState(false); const { regAuthrtYn } = auth; const alert = useAlertStore((state) => state.setMessage); @@ -74,9 +75,7 @@ export default function CoMatRvw() { const [toDate, setToDate] = useState( String(new Date().getFullYear()) ); - const [selectData, setSelectData] = useState( - {} as DmdCoReqType - ); + const [selectData, setSelectData] = useState(null); // selectData를 null로 초기화 const [selectionVersion, setSelectionVersion] = useState(0); const bottomRef = useRef(null); @@ -122,7 +121,7 @@ export default function CoMatRvw() { if (coMatRvwRes && coMatRvwRes[index]) { setSelectData(coMatRvwRes[index]); setSelectionVersion((v) => v + 1); // 행을 클릭할 때마다 버전을 1씩 증가 - bottomRef.current?.scrollIntoView({ behavior: "smooth" }); // 화면 스크로 처리 + bottomRef.current?.scrollIntoView({ behavior: "smooth" }); // 화면 스크롤 처리 } }; const useUsgCdWatch = useWatch({ control: form.control, name: "useUsgCd" }); @@ -131,7 +130,6 @@ export default function CoMatRvw() { String(useUsgCdWatch ?? ""); useEffect(() => { if (useUsgCdWatch) { - console.log("useUsgCdWatch:" , useUsgCdWatch); const normalizedUseUsgCd = code.sewageOutFclttUse?.find((item) => item.val === useUsgCdWatch)?.val ?? code.sewageOutFclttUse?.find((item) => item.text === useUsgCdWatch)?.val ?? @@ -188,6 +186,7 @@ export default function CoMatRvw() { useEffect(() => { if (!initRef.current) { coMatRvwInit(1, 13, fromDate, toDate); + //setMounted(true); initRef.current = true; } }, [coMatRvwInit, initRef, fromDate, toDate]); @@ -205,6 +204,20 @@ export default function CoMatRvw() { setSelectionVersion((v) => v + 1); // 강제로 바뀌었다고 알리기 } }, [selectData, form]); + + /** + * 하수 표준공사비 시뮬레이션(모의산정) + */ + const constCostSimulation = () => { + const url = `/constCostSimulation`; + const width = Math.floor(window.screen.availWidth * 0.6); + const height = Math.floor(window.screen.availHeight * 0.6); + const left = Math.floor(window.screenX + (window.outerWidth - width) / 2); + const top = Math.floor(window.screenY + (window.outerHeight - height) / 2); + const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`; + window.open(url, "candidatePopup", popupOptions); + }; + return ( <> @@ -290,6 +303,9 @@ export default function CoMatRvw() { > 조회 +
@@ -318,10 +334,9 @@ export default function CoMatRvw() { getSearch(val, Number(fromDate), Number(toDate), con, dmdCoNm); }} > -
+
-

-
+
{/* */}
@@ -343,10 +358,11 @@ export default function CoMatRvw() { onChange={(e) => { field.onChange(String(e.target.value)); }} - value={ - moment(field.value).format("YYYY-MM-DD") ?? "" + value={ // 값이 있을 때만 moment 실행, 없으면 빈 문자열 + field.value ? moment(field.value).format("YYYY-MM-DD") : "" } readOnly + suppressHydrationWarning // 시간 차이로 인한 경고 무시 className={readOnlyInputClass} /> @@ -773,5 +789,3 @@ export default function CoMatRvw() { ); } - - diff --git a/apps/wr/app/store/common/searchCode/index.ts b/apps/wr/app/store/common/searchCode/index.ts index 31f5bd3fe..f1c46820d 100644 --- a/apps/wr/app/store/common/searchCode/index.ts +++ b/apps/wr/app/store/common/searchCode/index.ts @@ -53,17 +53,19 @@ export type comFcltState = { searchFclts: pubHasuType[]; demandCompList: DemandCompType[]; checkDemand: DemandCompType; - constCostRes:conCostFeeType[], // 표준사업비 + constCostRes:conCostFeeType[], // 표준사업비 (공사비 산정표) rateFeeRes:rateFeeType[], }; - type comFcltActions = { +type comFcltActions = { getSwtrmtFcltNm: (searchNm: string) => void; getDemandCompList: (searchNm: string, cnt: number) => void; regDemandCompany: (data: DemandCompType) => Promise; updateDemandCompany: (data: DemandCompType) => Promise; getConstCostFee: (year: string) => void; getRateFee: (year: string) => void; + getRateFeeRtn: (year: string) => Promise; + getConstCostFeeRtn: (year: string) => Promise; }; export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { @@ -168,7 +170,20 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { console.log(" error ", e); } }, - // 공사금액 조회 : ONSEMIRO_NEW.EM_STD_COST_REUSE 설치관리표준사업비 재이용시설 공사비 + // 요율정보 조회 : ONSEMIRO_NEW.EM_STD_COST_INC_EXP_RT 설치관리표준사업비 부대경비요율 + // 팝업에서 연도 변경하여 볼 수 있도록 데이터를 return한다. + getRateFeeRtn: async (year: string) => { + try { + const url = `/prcsFclt/CstRt/${year}`; + const rateFeeRes = await getFetch(fetchType.COMMON, url); + + return rateFeeRes; + } catch (e) { + console.log(" error ", e); + return []; + } + }, + // 공사금액 (공사비 산정표) 조회 : ONSEMIRO_NEW.EM_STD_COST_REUSE 설치관리표준사업비 재이용시설 공사비 getConstCostFee: async (year: string) => { try { const url = `/prcsFclt/CstRuse/${year}`; @@ -182,9 +197,21 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { }); } catch (e) { - console.log('getConstCostFee ', e) + console.log('getConstCostFee ', e); + } + }, + // 공사금액 (공사비 산정표) 조회 : ONSEMIRO_NEW.EM_STD_COST_REUSE 설치관리표준사업비 재이용시설 공사비 + getConstCostFeeRtn: async (year: string): Promise => { + try { + const url = `/prcsFclt/CstRuse/${year}`; + const constCost = await getFetch(fetchType.COMMON, url); + return constCost; + } catch (e) { + console.log('getConstCostFee ', e); + return []; + } } }; }; diff --git a/apps/wr/app/store/matDmd/coMatRvw/headList.tsx b/apps/wr/app/store/matDmd/coMatRvw/headList.tsx index c6ef94875..180e5dc5c 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/headList.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/headList.tsx @@ -24,17 +24,18 @@ export const coRvwNodeListExport: CommonTableProps[] = [ ]; export const constCostHeadListExport: CommonTableProps[] = [ - { id: "gubun", title: "구분", visible: true, }, - { id: "500", title: "500", visible: true, }, - { id: "1000", title: "1,000", visible: true, }, - { id: "2000", title: "2,000", visible: true, }, - { id: "3000", title: "3,000", visible: true, }, //바꾸기 - { id: "5000", title: "5,000", visible: true, }, //바꾸기 - { id: "10000", title: "10,000", visible: true, }, // - { id: "20000", title: "20,000", visible: true, }, // - { id: "30000", title: "30,000", visible: true, }, // - { id: "50000", title: "50,000", visible: true, }, // - { id: "100000", title: "100,000", visible: true, }, //바꾸기 + { id: "gubun", title: "구분", visible: true, row: 0, rowSpan: 2, colSpan: 1 }, + { id: "A", title: "처리시설용량(m³)", visible: true, row: 0, rowSpan: 1, colSpan: 10 }, + { id: "500", title: "500", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "1000", title: "1,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "2000", title: "2,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "3000", title: "3,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "5000", title: "5,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "10000", title: "10,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "20000", title: "20,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "30000", title: "30,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "50000", title: "50,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, + { id: "100000", title: "100,000", visible: true, row: 1, rowSpan: 1, colSpan: 1 }, ]; export const rateFeeHeadListExport: CommonTableProps[] = [ diff --git a/apps/wr/app/store/matDmd/coMatRvw/index.tsx b/apps/wr/app/store/matDmd/coMatRvw/index.tsx index 39d1eaa28..b347a1df8 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/index.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/index.tsx @@ -66,7 +66,7 @@ type coRvwActions = { sggCd: string ) => void; }; - +// 수요매칭검토현황 목록 const coMatInit = async ( pageNo: number, pageCnt: number, @@ -99,9 +99,10 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { }, })); }, + // 수요처 매칭 검토 저장 coMatRvwUpdate: async ( - splyCd: string, - dmdCd: string, + splyCd: string, // 공공기관재사용시설아이디 - 하수재이용시설id : pbnst_ruse_fclt_id + dmdCd: string, // 수요정보id dmd_info_id data: DedMatUpdateType ): Promise => { try { @@ -148,6 +149,7 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { sggCd: string, dmdCoNm: string ) => { + // 수요처 년도별 정보 검색 let url = `/reuseFc/request/infoList/Sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`; if (sggCd.length > 0) { diff --git a/apps/wr/app/store/matDmd/coMatRvw/type.tsx b/apps/wr/app/store/matDmd/coMatRvw/type.tsx index ec0f0e09c..d195953cd 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/type.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/type.tsx @@ -60,47 +60,47 @@ const DemandCoSchema = z.object({ }); 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), + 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), - dmdInfoId: 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.string().nullish(), - crmty: z.number().nullish(), - tn: z.number().nullish(), - tph: z.number().nullish(), - ph: z.string().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(), + cityText: z.string().nullish(), // 시도 + sggText: z.string().nullish(), // 시군구 + dmdInfoSn: z.number().default(0), // 수요정보 일련번호 + dmdInfoId: z.string().default(''), // 수요정보 ID + dmndTmng: z.coerce.date().nullish(), // 요구시기 + dmndQty: z.number().nullish(), // 요구수량(m³/일) + blgcOxygDmndQnt: z.number().nullish(), // 생물학적 산소요구량(BOD)(mg/L) + wntUntprc: z.number().nullish(), // 희망단가(원/m3) + grssClfg: z.number().nullish(), // 총대장균군수(개/mg) + combResdch: z.number().nullish(), // 결합잔류염소(mg/L) + trbt: z.number().nullish(), // 탁도(NTU) + smll: z.string().nullish(), // 냄새 + crmty: z.number().nullish(), // 색도(도) + tn: z.number().nullish(), // 총질소(T-N)(mg/L) + tph: z.number().nullish(), // 총인(T-P)(mg/L) + ph: z.string().nullish(), // 수소이온농도(pH) + clIonQnt: z.number().nullish(), // 염화물(mgCL/L) + cdtnv: z.number().nullish(), // 전기전도도(㎲/cm) + 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(), // 공급처명 splyCndtList: z.array( z.object({ - ruseUtztnFcltNm: z.string(), - ruseUtztnFcltCd: z.string(), + ruseUtztnFcltNm: z.string(), // 공급처명 + ruseUtztnFcltCd: z.string(), // 공급처 코드 }).nullish() - ).nullish(), - totalConstCost: z.number().nullish(), + ).nullish(), // 공급처 후보지 목록 + totalConstCost: z.number().nullish(), // 처리시설 총사업비(백만원) }); export type DmdCoReqType = z.infer; @@ -159,4 +159,4 @@ export type rateFeeType = { export type SupplyCandidate = { ruseUtztnFcltNm: string; ruseUtztnFcltCd: string; -}; \ No newline at end of file +}; diff --git a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx index 932382709..09ed01987 100644 --- a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx +++ b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx @@ -20,20 +20,21 @@ import { Form, FormField, FormUi, + SelectBox, UiTable, } from "@common/business_components/ui"; import { useConfirm } from "@frontend-opensource/use-react-hooks"; import PopoverUi from "@common/business_components/ui/popover_ui"; import { Button, Checkbox, Input, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; -import { type UseFormReturn } from "react-hook-form"; +import { useForm, type UseFormReturn } from "react-hook-form"; /** - * ConCostForm - * 호출: (with-layout)/matMng/coMat/coMatRvw 에서 호출 + * ConCostForm + * 호출: (with-layout)/matMng/coMat/coMatRvw * - * 공사비를 산정하고 - * - * */ + * @param form - 외부에서 전달된 폼 객체 (없을 경우 시뮬레이션용 로컬 폼 사용) + * @param type - "mat": 매칭, "hist": 이력, "simulation": 모의산정 + */ export default function ConCostForm({ form, @@ -41,11 +42,27 @@ export default function ConCostForm({ selectionVersion, readonly = false, }: { - form: UseFormReturn; + form?: UseFormReturn; type: string; - selectionVersion: number; - readonly: boolean; + selectionVersion?: number; + readonly?: boolean; }) { + const [mounted, setMounted] = useState(false); + useEffect(() => { + setMounted(true); + }, []); + + // 시뮬레이션 모드를 위한 로컬 폼 생성 + const localForm = useForm({ + defaultValues: { + dmndQty: 0, + demandCst: { cstrnCst: 0, usgPrcsProcs: "" } + } as any + }); + + const activeForm = form || localForm; + const isSim = type === "simulation"; + const readOnlyInputClass = "bg-slate-50 text-gray-700"; const { constCostRes, // 표준사업비 @@ -105,23 +122,54 @@ export default function ConCostForm({ link.click(); }); }; - const usgPrcsProcsWatch = form.watch("demandCst.usgPrcsProcs"); - const dmndQtyWatch = form.watch("dmndQty"); - const totalConstCost = form.watch("totalConstCost"); - const cstrnCst = form.watch("demandCst.cstrnCst"); - const splyList = form.watch("splyCndtList"); - const useUsgCdWatch = form.watch("useUsgCd"); + const usgPrcsProcsWatch = activeForm.watch("demandCst.usgPrcsProcs"); // 용도에 따른 처리공정 + const dmndQtyWatch = activeForm.watch("dmndQty"); // 요구수량(m³/일) + const totalConstCost = activeForm.watch("totalConstCost"); // 처리시설 총사업비(백만원) + const cstrnCst = activeForm.watch("demandCst.cstrnCst") || 0; // 공급관로 표준공사비(백만원) + const prcsFcltCpctCstrnCst = activeForm.watch("demandCst.prcsFcltCpctCstrnCst") || 0; // 처리시설용량에 따른 공사비(백만원) + const fcltSbsdCstrnCst = activeForm.watch("demandCst.fcltSbsdCstrnCst") || 0; // 시설부대경비 + const splyList = activeForm.watch("splyCndtList"); // 공급처 후보지 목록 + const useUsgCdWatch = activeForm.watch("useUsgCd"); // 사용 용도 코드 + const ruseUtztnFcltNmWatch = activeForm.watch("ruseUtztnFcltNm"); // 선정된 공급처 명 const useUsgCdLabel = - code.sewageOutFclttUse?.find((item) => item.val === useUsgCdWatch)?.text ?? + code.sewageOutFclttUse?.find((item) => item.val === useUsgCdWatch)?.text ?? // 사용 용도 명칭(라벨) String(useUsgCdWatch ?? ""); + useEffect(() => { + const calculatedTotalConstCost = Number(prcsFcltCpctCstrnCst) + Number(fcltSbsdCstrnCst); + + if ((totalConstCost ?? 0) !== calculatedTotalConstCost) { + activeForm.setValue("totalConstCost", calculatedTotalConstCost); + } + }, [ + activeForm, + prcsFcltCpctCstrnCst, + fcltSbsdCstrnCst, + totalConstCost, + selectionVersion, + ]); + + // 용도 변경 시 처리공정 자동 매핑 (시뮬레이션 대응) + useEffect(() => { + if (useUsgCdWatch) { + const matched = usageProcData.find((item) => item.useUsgCd === useUsgCdWatch); + if (matched && matched.process !== usgPrcsProcsWatch) { + activeForm.setValue("demandCst.usgPrcsProcs", matched.process); + } + } + }, [useUsgCdWatch, activeForm, usgPrcsProcsWatch]); + /** * 표준공산비 산정 : "계산"버튼 click시 */ const calculateConstCost = useCallback(() => { const usgPrcsProcs = usgPrcsProcsWatch; - if (selectionVersion == 0) { - alert("먼저 목록에서 수요신청 건을 선택하세요."); + if (!isSim && selectionVersion == 0) { + alert("목록에서 수요신청 건을 선택하세요."); + return; + } + if (!useUsgCdWatch) { + alert("용도 값이 없습니다."); return; } if (!dmndQtyWatch) { @@ -148,7 +196,7 @@ export default function ConCostForm({ const firstProc = getConstFctCode(usgPrcsProcs?.split("+")[0] || "") || ""; // 첫번째 공정 const secondProc = getConstFctCode(usgPrcsProcs?.split("+")[1] || "") || ""; // 두번째 공정 - // 첫번째 처리공정 코드에 해당하는 표준공사비 테이블이서 요구수량을 감싸는 하한/상한 구간을 찾는 부분이다. + // 첫번째 처리공정 코드에 해당하는 표준공사비 테이블에서 요구수량을 감싸는 하한/상한 구간을 찾는 부분이다. const { lower: firstLower, upper: firstUpper } = findBounds( constCostRes, // 표준공사비 firstProc || "", @@ -194,12 +242,12 @@ export default function ConCostForm({ 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)); + activeForm.setValue("demandCst.prcsFcltCpctCstrnCst", Math.round(result)); + activeForm.setValue("demandCst.fcltSbsdCstrnCst", Math.round(fcltSbsdCstrnCst)); + activeForm.setValue("totalConstCost", Math.round(realResult)); alert("표준공산비 산정이 완료되었습니다."); } - }, [constCostRes, rateFeeRes, usgPrcsProcsWatch, dmndQtyWatch]); + }, [constCostRes, rateFeeRes, usgPrcsProcsWatch, dmndQtyWatch, isSim, selectionVersion, activeForm]); /** * 저장 버튼 click 시 실행 @@ -212,22 +260,22 @@ export default function ConCostForm({ return; } - // const pk = - // splycd && splycd[0]?.ruseUtztnFcltCd - // ? splycd[0]?.ruseUtztnFcltCd - // : "11000SW001R1"; + // 1순위: 팝업에서 새로 선택한 코드 (lastSub) + // 2순위: 기존 DB에서 불러와 폼에 저장된 코드 (demandMatching.pbnstRuseFcltId) + const pk = + lastSub?.ruseUtztnFcltCd ?? + activeForm.getValues("demandMatching.pbnstRuseFcltId") ?? + null; - const pk =lastSub?.ruseUtztnFcltCd??null; // 후보지 - if (type === "mat") { 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", + 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", // "Sub": 검토중, "Checked": 검토완료(재이용검토이력 화면에 나타남) rgtr: TEST_UUID, }; @@ -235,11 +283,11 @@ export default function ConCostForm({ if (checkFinish) { if (await confirm("검토완료 변경시 공사비는 변경할수 없습니다.\n진행하시겠습니까?")) { - const message = await coMatRvwUpdate( pk, form.getValues("dmdInfoId"), data ); + const message = await coMatRvwUpdate( pk, activeForm.getValues("dmdInfoId"), data ); alert(message); } } else { - const message = await coMatRvwUpdate( pk, form.getValues("dmdInfoId"), data ); + const message = await coMatRvwUpdate( pk, activeForm.getValues("dmdInfoId"), data ); alert(message); } }else{ @@ -292,10 +340,11 @@ export default function ConCostForm({ useEffect(() => { - form.register("dmdInfoSn"); - form.register("dmdInfoId"); - form.register("ruseUtztnFcltNm"); - }, []); + if (!activeForm) return; + activeForm.register("dmdInfoSn"); + activeForm.register("dmdInfoId"); + activeForm.register("ruseUtztnFcltNm"); + }, [activeForm]); /** @@ -309,7 +358,7 @@ export default function ConCostForm({ alert("먼저 목록에서 수요신청 건을 선택하세요."); return; } - const dmdInfoId = form.getValues("dmdInfoId"); + const dmdInfoId = activeForm.getValues("dmdInfoId"); console.log(dmdInfoId) const url = `/splyPopup?dmdInfoId=${encodeURIComponent(dmdInfoId)}`; @@ -321,10 +370,12 @@ export default function ConCostForm({ window.open(url, "candidatePopup", popupOptions); }; + if (!mounted) return null; // 서버 사이드 렌더링 시에는 아무것도 그리지 않음 (선택 사항) + return ( <> -
+ {/*

표준공사비 산정

*/} @@ -334,62 +385,72 @@ export default function ConCostForm({ - - - { - if (readonly) return; - setCheckFinish(checked === true); - } - - // 'indeterminate' 상태를 무시하고 순수 boolean 값으로만 상태를 업데이트합니다. - } - > - - -
-
-

기본사항

+ {!isSim && ( + <> + + + { + if (readonly) return; + setCheckFinish(checked === true); + }} + /> + + )} + {!isSim && ( + <> + + + + )}
+
+
+

기본사항

+
( - + {isSim ? ( + + ) : ( + + )} )} />
( @@ -401,8 +462,8 @@ export default function ConCostForm({ field.onChange(Number(e.target.value)); }} value={field.value ?? 0} - readOnly={true} - className={readOnlyInputClass} + readOnly={!isSim} + className={!isSim ? readOnlyInputClass : ""} /> )} @@ -439,7 +500,7 @@ export default function ConCostForm({ bodyClassName={"w-[25vw] max-w-none"} > ( @@ -457,7 +518,7 @@ export default function ConCostForm({
( @@ -482,7 +543,7 @@ export default function ConCostForm({

공사비 입력사항

-
+
} - bodyClassName={"w-fit max-w-[40vw]"} + bodyClassName={"w-fit max-w-[400] overflow-x-auto"} >
( @@ -515,7 +576,7 @@ export default function ConCostForm({ }} value={field.value ?? 0} readOnly - className={readOnlyInputClass} + className={`mt-2 ${readOnlyInputClass}`} /> )} @@ -536,11 +597,11 @@ export default function ConCostForm({ } - bodyClassName={"w-[22vw]"} + bodyClassName={"w-fit max-w-[100] overflow-x-auto"} >
( @@ -553,7 +614,7 @@ export default function ConCostForm({ }} value={field.value ?? 0} readOnly - className={readOnlyInputClass} + className={`mt-2 ${readOnlyInputClass}`} /> )} @@ -585,7 +646,7 @@ export default function ConCostForm({ bodyClassName={"w-[22vw]"} > ( @@ -604,35 +665,30 @@ export default function ConCostForm({ )} />
-
-
- - + {!isSim && ( +
+
+ + +
+ + +
- - - -
-
+ )} +
( @@ -641,7 +697,7 @@ export default function ConCostForm({ type="number" step="0.01" onChange={(e) => { - if (readonly) return; + if (readonly && !isSim) return; field.onChange(Number(e.target.value)); }} @@ -652,17 +708,16 @@ export default function ConCostForm({ />
- - + + +
diff --git a/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx b/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx index 6be066931..d3f02e278 100644 --- a/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx +++ b/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx @@ -1,3 +1,6 @@ +/** + * 공사비 산정표 + */ "use client"; import { useWrStore } from "@/app/store"; @@ -5,29 +8,24 @@ import type { conCostFeeType, ContCostMap, } from "@/app/store/common/searchCode/type"; -import { UiTable } from "@common/business_components/ui"; +import { SelectBox, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Label, } from "@common/components/ui"; import { useEffect, useState } from "react"; + export function ConstCostFeeTable() { - const { coRvw, constCostRes } = useWrStore((state) => state); + const { coRvw, constCostRes, getConstCostFeeRtn } = useWrStore((state) => state); const [constCostData, setConstCostData] = useState([]); - const 기준년도 = constCostRes?.[0]?.yr ?? ""; + const [selectedYear, setSelectedYear] = useState(String(new Date().getFullYear())); + // 연도 선택을 위한 옵션 생성 (예: 현재 연도부터 10년 전까지) + const yearOptions = Array.from({ length: 10 }, (_, i) => { + const year = new Date().getFullYear() - i; + return { val: String(year), text: String(year) }; + }); - const getFctDescription = (fctCd: string) => { - const fctMap: { [key: string]: string } = { - "001": "총인처리시설", - "002": "염소소독", - "003": "UV소독", - "004": "전처리시설", - "005": "RO", - }; - - return fctMap[fctCd]; - } - useEffect(() => { + const fetchData = async (constCostRes: conCostFeeType[]) => { const tableData = constCostRes?.reduce( (acc: ContCostMap[], cur: conCostFeeType) => { const key = cur.fctCd; @@ -48,7 +46,7 @@ export function ConstCostFeeTable() { }; acc?.push(target); } - target[cur.fctCpc] = cur.stdCost; + target[cur.fctCpc] = Number(cur.stdCost); return acc; }, @@ -60,19 +58,66 @@ export function ConstCostFeeTable() { gubun: getFctDescription(item.gubun) || item.gubun, }; }); - setConstCostData(formattedTableData); + + return formattedTableData; + }; + + const getFctDescription = (fctCd: string) => { + const fctMap: { [key: string]: string } = { + "001": "총인처리시설", + "002": "염소소독", + "003": "UV소독", + "004": "전처리시설", + "005": "RO", + }; + + return fctMap[fctCd]; + } + + useEffect(() => { + const fetchConstCost = async () => { + const data = await fetchData(constCostRes); + setConstCostData(data); + }; + fetchConstCost(); }, [constCostRes]); + useEffect(() => { + const fetchConstCost = async () => { + if (selectedYear) { + const result = await getConstCostFeeRtn(selectedYear); + if (result && result.length > 0) { + const data = await fetchData(result); + setConstCostData(data); + } else { + alert(selectedYear+'년 데이터가 없습니다.'); + } + } + } + fetchConstCost(); + }, [selectedYear]); + return ( - <> - -

+ +
+

공사비 산정표 보기

-
-
- - {기준년도} +
+
+
+ + setSelectedYear(String(val)) + } + /> +
+ 단위: 백만원
{ }} /> - - +
+ 시설용량 구간내 공사비는 직선보간법에 의하여 산출 +
+
+ ); } diff --git a/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx b/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx index 9118f8127..5439d489c 100644 --- a/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx +++ b/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx @@ -2,15 +2,24 @@ import { useWrStore } from "@/app/store"; import type { rateFeeType } from "@/app/store/common/searchCode/type"; -import { UiTable } from "@common/business_components/ui"; +import { SelectBox, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Label } from "@common/components/ui"; import { useEffect, useState } from "react"; export function RateFeeTableModal() { - const { coRvw, rateFeeRes } = useWrStore((state) => state); - const [reateFeeTable, setRateFeeTable] = useState([]); - const 기준년도 = rateFeeRes?.[0]?.yr ?? ""; + const { coRvw, rateFeeRes, getRateFeeRtn } = useWrStore((state) => state); + const [rateFeeTable, setRateFeeTable] = useState([]); + const [selectedYear, setSelectedYear] = useState(String(new Date().getFullYear())); + + // 연도 선택을 위한 옵션 생성 (예: 현재 연도부터 10년 전까지) + const yearOptions = Array.from({ length: 10 }, (_, i) => { + const year = new Date().getFullYear() - i; + return { val: String(year), text: String(year) }; + }); + + // const 기준년도 = rateFeeRes?.[0]?.yr ?? selectedYear; // 실제 데이터의 기준년도 또는 선택된 연도 + // setSelectedYear(rateFeeRes?.[0]?.yr ?? selectedYear); const gubunLabelMap: Record = { 50: "5천만원까지", @@ -32,6 +41,11 @@ export function RateFeeTableModal() { 500000: "5000억원까지", }; + /** + * rateFeeRes 데이터를 가공하여 테이블에 표시하기 적합한 형태로 변환합니다. + * - 'SS' 코드를 제외하고, stdCost 기준으로 그룹화하여 BD, SE, CE 요율을 컬럼으로 피벗합니다. + * - gubunLabelMap을 사용하여 stdCost에 해당하는 한글 라벨을 추가합니다. + */ const fetchData = async (rateFeeRes: rateFeeType[]) => { const data = await rateFeeRes ?.filter((item: rateFeeType) => { @@ -65,40 +79,68 @@ export function RateFeeTableModal() { useEffect(() => { if (rateFeeRes?.length >= 0) { + setSelectedYear(rateFeeRes?.[0]?.yr ?? selectedYear); fetchData(rateFeeRes).then((data) => { setRateFeeTable(data); }); } }, [rateFeeRes]); - return ( - <> - -
-

- 요율표 보기 -

-
+ // 컴포넌트 마운트 시 또는 선택된 연도가 변경될 때 데이터 조회 + useEffect(() => { + const fetchRateFee = async () => { + if (selectedYear) { + const result = await getRateFeeRtn(selectedYear); + if (result && result.length > 0) { + const data = await fetchData(result); + setRateFeeTable(data); + } else { + alert(selectedYear+'년 데이터가 없습니다.'); + } + } + } + fetchRateFee(); + }, [selectedYear]); -
- - {기준년도} -
-
- {}} - pageSize={0} - total={0} - cellClick={undefined} - /> -
+ return ( + +
+

+ 시설부대경비 요율(%) +

+
+ +
+ + setSelectedYear(String(val)) + } + />
- - +
+ {}} + pageSize={0} + total={0} + cellClick={undefined} + /> +
+
+ 출처 : 하수도분야 보조금 편성 및 실무요령 +
+ 시설부대경비 및 감리비 요율적용시 공사비가 요율표의 중간에 있을 때는 직선보간법에 의하여 산출 +
+
+
); } diff --git a/packages/common/business_components/src/ui/popover_ui/index.tsx b/packages/common/business_components/src/ui/popover_ui/index.tsx index 39094bc24..bc7cb0b76 100644 --- a/packages/common/business_components/src/ui/popover_ui/index.tsx +++ b/packages/common/business_components/src/ui/popover_ui/index.tsx @@ -13,7 +13,7 @@ export default function PopoverUi({ <> {childrenTriger} - + e.preventDefault()}> {childrenBody}