wr: 표준공사비 모의산정
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
"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";
|
||||
|
||||
export default function ConstCostSimulationPage() {
|
||||
const form = useForm<DmdCoReqType>({
|
||||
defaultValues: {
|
||||
dmndQty: 0,
|
||||
demandCst: { cstrnCst: 0, usgPrcsProcs: "", prcsFcltCpctCstrnCst: 0, fcltSbsdCstrnCst: 0 },
|
||||
totalConstCost: 0
|
||||
} as any
|
||||
});
|
||||
|
||||
return <ConCostForm form={form} type="simulation" readonly={false} />;
|
||||
}
|
||||
@@ -74,9 +74,7 @@ export default function CoMatRvw() {
|
||||
const [toDate, setToDate] = useState<string>(
|
||||
String(new Date().getFullYear())
|
||||
);
|
||||
const [selectData, setSelectData] = useState<DmdCoReqType>(
|
||||
{} as DmdCoReqType
|
||||
);
|
||||
const [selectData, setSelectData] = useState<DmdCoReqType | null>(null); // selectData를 null로 초기화
|
||||
const [selectionVersion, setSelectionVersion] = useState(0);
|
||||
const bottomRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
@@ -122,7 +120,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 +129,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 ??
|
||||
@@ -205,6 +202,20 @@ export default function CoMatRvw() {
|
||||
setSelectionVersion((v) => v + 1); // 강제로 바뀌었다고 알리기
|
||||
}
|
||||
}, [selectData, form]);
|
||||
|
||||
/**
|
||||
* 하수 표준공사비 시뮬레이션(모의산정)
|
||||
*/
|
||||
const constCostSimulation = () => {
|
||||
const url = `/constCostSimulation`;
|
||||
const width = window.screen.availWidth;
|
||||
const height = 600;
|
||||
const left = 0;
|
||||
const top = 0;
|
||||
const popupOptions = `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;
|
||||
window.open(url, "candidatePopup", popupOptions);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContentsDiv>
|
||||
@@ -290,6 +301,9 @@ export default function CoMatRvw() {
|
||||
>
|
||||
조회
|
||||
</Button>
|
||||
<Button className={btnClass} onClick={()=>constCostSimulation()} >
|
||||
표준공사비 모의산정
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</SearchFormRight>
|
||||
@@ -773,5 +787,3 @@ export default function CoMatRvw() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,22 @@ export default function ConCostForm({
|
||||
selectionVersion,
|
||||
readonly = false,
|
||||
}: {
|
||||
form: UseFormReturn<DmdCoReqType>;
|
||||
form?: UseFormReturn<DmdCoReqType>;
|
||||
type: string;
|
||||
selectionVersion: number;
|
||||
readonly: boolean;
|
||||
selectionVersion?: number;
|
||||
readonly?: boolean;
|
||||
}) {
|
||||
// 시뮬레이션 모드를 위한 로컬 폼 생성
|
||||
const localForm = useForm<DmdCoReqType>({
|
||||
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 +117,33 @@ 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");
|
||||
const totalConstCost = activeForm.watch("totalConstCost");
|
||||
const cstrnCst = activeForm.watch("demandCst.cstrnCst") || 0;
|
||||
const splyList = activeForm.watch("splyCndtList");
|
||||
const useUsgCdWatch = activeForm.watch("useUsgCd");
|
||||
const useUsgCdLabel =
|
||||
code.sewageOutFclttUse?.find((item) => item.val === useUsgCdWatch)?.text ??
|
||||
String(useUsgCdWatch ?? "");
|
||||
|
||||
// 용도 변경 시 처리공정 자동 매핑 (시뮬레이션 대응)
|
||||
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 (!dmndQtyWatch) {
|
||||
@@ -194,12 +216,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 시 실행
|
||||
@@ -235,11 +257,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 +314,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 +332,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)}`;
|
||||
@@ -324,7 +347,7 @@ export default function ConCostForm({
|
||||
return (
|
||||
<>
|
||||
|
||||
<Form {...form}>
|
||||
<Form {...activeForm}>
|
||||
{/* <h3 className="mt-4 ml-2 text-2xl font-medium text-label">
|
||||
표준공사비 산정
|
||||
</h3> */}
|
||||
@@ -334,36 +357,35 @@ export default function ConCostForm({
|
||||
<Button className="mx-3" size={"sm"} onClick={calculateConstCost}>
|
||||
계산
|
||||
</Button>
|
||||
<Button
|
||||
className="mr-3"
|
||||
size={"sm"}
|
||||
onClick={form.handleSubmit(onSubmit)}
|
||||
disabled={readonly}
|
||||
>
|
||||
저장
|
||||
</Button>
|
||||
<Label>검토완료</Label>
|
||||
<Checkbox
|
||||
className="ml-3 mr-6"
|
||||
checked={checkFinish}
|
||||
onCheckedChange={
|
||||
(checked) => {
|
||||
if (readonly) return;
|
||||
setCheckFinish(checked === true);
|
||||
}
|
||||
|
||||
// 'indeterminate' 상태를 무시하고 순수 boolean 값으로만 상태를 업데이트합니다.
|
||||
}
|
||||
></Checkbox>
|
||||
<Label>관로 표준공사비 산정 프로그램</Label>
|
||||
<Button
|
||||
color="green"
|
||||
size={"sm"}
|
||||
onClick={zipDowonLoad}
|
||||
className="bg-none ml-6"
|
||||
>
|
||||
다운로드
|
||||
</Button>
|
||||
{!isSim && (
|
||||
<>
|
||||
<Button
|
||||
className="mr-3"
|
||||
size={"sm"}
|
||||
onClick={activeForm.handleSubmit(onSubmit)}
|
||||
disabled={readonly}
|
||||
>
|
||||
저장
|
||||
</Button>
|
||||
<Label>검토완료</Label>
|
||||
<Checkbox
|
||||
className="ml-3 mr-6"
|
||||
checked={checkFinish}
|
||||
onCheckedChange={(checked) => {
|
||||
if (readonly) return;
|
||||
setCheckFinish(checked === true);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!isSim && (
|
||||
<>
|
||||
<Label>관로 표준공사비 산정 프로그램</Label>
|
||||
<Button color="green" size={"sm"} onClick={zipDowonLoad} className="bg-none ml-6">
|
||||
다운로드
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-span-12 ml-4 mr-4">
|
||||
<h1 className={formH1Class}>기본사항</h1>
|
||||
@@ -371,25 +393,33 @@ export default function ConCostForm({
|
||||
<div className="grid grid-cols-12 gap-4 ml-4 mr-4">
|
||||
<div className="col-span-3 mt-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="useUsgCd"
|
||||
render={({ field }) => (
|
||||
<FormUi label="용도">
|
||||
<Input
|
||||
placeholder=""
|
||||
type="text"
|
||||
onChange={field.onChange}
|
||||
value={useUsgCdLabel}
|
||||
readOnly
|
||||
className={readOnlyInputClass}
|
||||
/>
|
||||
{isSim ? (
|
||||
<SelectBox
|
||||
label=""
|
||||
selectArray={code.sewageOutFclttUse || []}
|
||||
onSelectValue={field.onChange}
|
||||
value={field.value}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
placeholder=""
|
||||
type="text"
|
||||
value={useUsgCdLabel}
|
||||
readOnly
|
||||
className={readOnlyInputClass}
|
||||
/>
|
||||
)}
|
||||
</FormUi>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-3 mt-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="dmndQty"
|
||||
render={({ field }) => (
|
||||
<FormUi label="요구수량(m³/일)">
|
||||
@@ -401,8 +431,8 @@ export default function ConCostForm({
|
||||
field.onChange(Number(e.target.value));
|
||||
}}
|
||||
value={field.value ?? 0}
|
||||
readOnly={true}
|
||||
className={readOnlyInputClass}
|
||||
readOnly={!isSim}
|
||||
className={!isSim ? readOnlyInputClass : ""}
|
||||
/>
|
||||
</FormUi>
|
||||
)}
|
||||
@@ -439,7 +469,7 @@ export default function ConCostForm({
|
||||
bodyClassName={"w-[25vw] max-w-none"}
|
||||
></PopoverUi>
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="demandCst.usgPrcsProcs"
|
||||
render={({ field }) => (
|
||||
<FormUi label="">
|
||||
@@ -457,7 +487,7 @@ export default function ConCostForm({
|
||||
</div>
|
||||
<div className="col-span-3 mt-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="dmndQty"
|
||||
render={({ field }) => (
|
||||
<FormUi label="처리시설용량(m³/일)">
|
||||
@@ -502,7 +532,7 @@ export default function ConCostForm({
|
||||
></PopoverUi>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="demandCst.prcsFcltCpctCstrnCst"
|
||||
render={({ field }) => (
|
||||
<FormUi label="">
|
||||
@@ -540,7 +570,7 @@ export default function ConCostForm({
|
||||
></PopoverUi>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="demandCst.fcltSbsdCstrnCst"
|
||||
render={({ field }) => (
|
||||
<FormUi label="">
|
||||
@@ -585,7 +615,7 @@ export default function ConCostForm({
|
||||
bodyClassName={"w-[22vw]"}
|
||||
></PopoverUi>
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="totalConstCost"
|
||||
render={({ field }) => (
|
||||
<FormUi label="">
|
||||
@@ -604,35 +634,28 @@ export default function ConCostForm({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-3 mt-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>공급처 선정</Label>
|
||||
<Button
|
||||
size={"sm"}
|
||||
onClick={(e) => {
|
||||
searchCandidate(e);
|
||||
|
||||
//splyList => 해당객체가 대민에서 선택한 후보처 리스트
|
||||
//setLastSub => 해당 스테이트가 선택한 마지막 후보처를 넣어야하는 스테이트
|
||||
}}
|
||||
className="bg-none"
|
||||
>
|
||||
후보지 조회
|
||||
</Button>
|
||||
{form && (
|
||||
<div className="col-span-3 mt-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>공급처 선정</Label>
|
||||
<Button size={"sm"} onClick={searchCandidate} className="bg-none">
|
||||
후보지 조회
|
||||
</Button>
|
||||
</div>
|
||||
<FormUi label="">
|
||||
<Input
|
||||
placeholder=""
|
||||
type="text"
|
||||
value={lastSub?.ruseUtztnFcltNm || ""}
|
||||
readOnly
|
||||
className={readOnlyInputClass}
|
||||
/>
|
||||
</FormUi>
|
||||
</div>
|
||||
<FormUi label="">
|
||||
<Input
|
||||
placeholder=""
|
||||
type="text"
|
||||
value={lastSub?.ruseUtztnFcltNm || ""}
|
||||
readOnly
|
||||
className={readOnlyInputClass}
|
||||
/>
|
||||
</FormUi>
|
||||
</div>
|
||||
)}
|
||||
<div className="col-span-3 mt-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
control={activeForm.control}
|
||||
name="demandCst.cstrnCst"
|
||||
render={({ field }) => (
|
||||
<FormUi label="공급관로 표준공사비(백만원)">
|
||||
@@ -641,7 +664,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));
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user