수요처매칭 계산식 진행중
This commit is contained in:
@@ -94,7 +94,6 @@ export default function RuseRvwHstry() {
|
||||
} else {
|
||||
|
||||
|
||||
console.log("시도코드", sggCd);
|
||||
ruseRvwInqua(pageNation, 13, String(startYear), String(endYear), sggCd);
|
||||
}
|
||||
};
|
||||
@@ -193,7 +192,6 @@ export default function RuseRvwHstry() {
|
||||
}
|
||||
}, [rvwHistRes]);
|
||||
|
||||
useEffect(() => {}, [form.formState]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("변경여부 ", form.formState.isDirty);
|
||||
|
||||
@@ -187,13 +187,13 @@ export const rateFeeHeadListExport: CommonTableProps[] = [
|
||||
];
|
||||
|
||||
export const usageProcData = [
|
||||
{ usage: "청소", process: "총인처리시설 + 염소소독" },
|
||||
{ usage: "화장실용수", process: "총인처리시설 + 염소소독" },
|
||||
{ usage: "세척", process: "총인처리시설 + UV소독" },
|
||||
{ usage: "살수", process: "총인처리시설 + UV소독" },
|
||||
{ usage: "조경", process: "총인처리시설 + UV소독" },
|
||||
{ usage: "농업", process: "총인처리시설 + UV소독" },
|
||||
{ usage: "하천", process: "총인처리시설 + UV소독" },
|
||||
{ usage: "지하수", process: "전처리시설 + RO" },
|
||||
{ usage: "공업", process: "전처리시설 + RO" },
|
||||
{ usage: "청소", process: "총인처리시설+염소소독" },
|
||||
{ usage: "화장실용수", process: "총인처리시설+염소소독" },
|
||||
{ usage: "세척", process: "총인처리시설+UV소독" },
|
||||
{ usage: "살수", process: "총인처리시설+UV소독" },
|
||||
{ usage: "조경", process: "총인처리시설+UV소독" },
|
||||
{ usage: "농업", process: "총인처리시설+UV소독" },
|
||||
{ usage: "하천", process: "총인처리시설+UV소독" },
|
||||
{ usage: "지하수", process: "전처리시설+RO" },
|
||||
{ usage: "공업", process: "전처리시설+RO" },
|
||||
];
|
||||
|
||||
@@ -93,6 +93,8 @@ import { z } from "zod";
|
||||
demandMatching: DemandMatchingSchema.nullish(),
|
||||
demandCst: DemandCstSchema,
|
||||
ruseUtztnFcltNm:z.string().nullish(),
|
||||
totalConstCost:z.number().nullish(),
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
export const findBounds = (
|
||||
data: any[],
|
||||
fctCd: string,
|
||||
qty: number
|
||||
): { lower?: any; upper?: any } => {
|
||||
const filtered = data.filter((item) => item.fctCd === fctCd);
|
||||
|
||||
const lowers = filtered.filter((item) => Number(item.fctCpc) <= qty);
|
||||
const uppers = filtered.filter((item) => Number(item.fctCpc) > qty);
|
||||
|
||||
const lower =
|
||||
lowers.length > 0
|
||||
? lowers.reduce((acc, curr) =>
|
||||
Number(curr.fctCpc) > Number(acc.fctCpc) ? curr : acc
|
||||
)
|
||||
: undefined;
|
||||
const upper =
|
||||
uppers.length > 0
|
||||
? uppers.reduce((acc, curr) =>
|
||||
Number(curr.fctCpc) < Number(acc.fctCpc) ? curr : acc
|
||||
)
|
||||
: undefined;
|
||||
|
||||
return { lower, upper };
|
||||
};
|
||||
|
||||
// (기울기) a = (y2 - y1) / (x2 - x1)
|
||||
// (절편) b = y1 - a * x1
|
||||
// ↓
|
||||
// 결과값 y = a * x + b
|
||||
|
||||
export const getInterpolation = (
|
||||
Upper: { stdCost: number; fctCpc: number },
|
||||
Lower: { stdCost: number; fctCpc: number },
|
||||
qtyYear: number
|
||||
): number => {
|
||||
const slope =
|
||||
(Number(Upper?.stdCost) - Number(Lower?.stdCost)) /
|
||||
(Number(Upper?.fctCpc) - Number(Lower?.fctCpc));
|
||||
const intercept = Number(Lower?.stdCost) - slope * Number(Lower?.fctCpc);
|
||||
return slope * qtyYear + intercept;
|
||||
};
|
||||
|
||||
export const transformAndInterpolate = (
|
||||
rawData: any,
|
||||
dmndQtyYear: number
|
||||
): any => {
|
||||
const result: any = {};
|
||||
|
||||
for (const key in rawData) {
|
||||
const item = rawData[key];
|
||||
|
||||
const range = {
|
||||
Lower: {
|
||||
fctCpc: item.lower?.stdCost,
|
||||
stdCost: item.lower?.rt,
|
||||
},
|
||||
Upper: {
|
||||
fctCpc: item.upper?.stdCost,
|
||||
stdCost: item.upper?.rt,
|
||||
},
|
||||
};
|
||||
console.log("range ", range);
|
||||
result[key] = getInterpolation(range.Upper, range.Lower, dmndQtyYear);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const getConstFctCode = (fctCd: string) => {
|
||||
const fctMap: { [key: string]: string } = {
|
||||
총인처리시설: "001",
|
||||
염소소독: "002",
|
||||
UV소독: "003",
|
||||
전처리시설: "004",
|
||||
RO: "005",
|
||||
};
|
||||
|
||||
return fctMap[fctCd];
|
||||
};
|
||||
@@ -153,3 +153,6 @@ export const getdmdMatFlag = (flag: string|undefined) => {
|
||||
}
|
||||
return flagMat;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,12 @@ import type {
|
||||
} from "@/app/store/matDmd/coMatRvw/type";
|
||||
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||
import { formH1Class } from "@/components/lib/class/comClass";
|
||||
import {
|
||||
findBounds,
|
||||
getConstFctCode,
|
||||
getInterpolation,
|
||||
transformAndInterpolate,
|
||||
} from "@/components/lib/func/calculateConstCost ";
|
||||
import { ConstCostFeeTable } from "@/components/ui/modal/coMat/constCostFeeTable";
|
||||
import { RateFeeTableModal } from "@/components/ui/modal/coMat/rateFeeModal";
|
||||
import {
|
||||
@@ -17,7 +23,8 @@ import {
|
||||
} from "@common/business_components/ui";
|
||||
import PopoverUi from "@common/business_components/ui/popover_ui";
|
||||
import { Button, Input, Label } from "@common/components/ui";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { read } from "fs";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { type UseFormReturn } from "react-hook-form";
|
||||
|
||||
export default function ConCostForm({
|
||||
@@ -27,7 +34,14 @@ export default function ConCostForm({
|
||||
form: UseFormReturn<DmdCoReqType>;
|
||||
type: string;
|
||||
}) {
|
||||
const { coMatRvwUpdate, ruseRvwCalUpdate,getRateFee ,getConstCostFee} = useWrStore((state) => state);
|
||||
const {
|
||||
constCostRes,
|
||||
rateFeeRes,
|
||||
coMatRvwUpdate,
|
||||
ruseRvwCalUpdate,
|
||||
getRateFee,
|
||||
getConstCostFee,
|
||||
} = useWrStore((state) => state);
|
||||
|
||||
const ref = useRef<boolean>(false);
|
||||
|
||||
@@ -38,9 +52,8 @@ export default function ConCostForm({
|
||||
getRateFee(String(currentYear));
|
||||
ref.current = true;
|
||||
}
|
||||
}, [ref, getConstCostFee ,getRateFee ]);
|
||||
}, [ref, getConstCostFee, getRateFee]);
|
||||
|
||||
|
||||
const [isTrfMo, setIsTrfMo] = useState<{
|
||||
isModal: boolean;
|
||||
}>({ isModal: false });
|
||||
@@ -59,6 +72,82 @@ 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 calculateConstCost = useCallback(() => {
|
||||
const usgPrcsProcs = usgPrcsProcsWatch;
|
||||
const dmndQtyYear = dmndQtyWatch * 365;
|
||||
if (usgPrcsProcs && usgPrcsProcs?.length > 0) {
|
||||
const firstProc =
|
||||
getConstFctCode(usgPrcsProcs?.split("+")[0] || "") || "";
|
||||
const secondProc =
|
||||
getConstFctCode(usgPrcsProcs?.split("+")[1] || "") || "";
|
||||
|
||||
const { lower: firstLower, upper: firstUpper } = findBounds(
|
||||
constCostRes,
|
||||
firstProc || "",
|
||||
Number(dmndQtyYear)
|
||||
);
|
||||
const { lower: secondLower, upper: secondUpper } = findBounds(
|
||||
constCostRes,
|
||||
secondProc || "",
|
||||
Number(dmndQtyYear)
|
||||
);
|
||||
|
||||
const firstConstFee = getInterpolation(
|
||||
firstUpper,
|
||||
firstLower,
|
||||
dmndQtyYear
|
||||
);
|
||||
const secondConstFee = getInterpolation(
|
||||
secondUpper,
|
||||
secondLower,
|
||||
dmndQtyYear
|
||||
);
|
||||
const result = Math.round(firstConstFee + secondConstFee) / 100;
|
||||
|
||||
const groupCodes = ["BD", "CE", "SE", "WD"];
|
||||
const groupedBounds: { [key: string]: { lower?: any; upper?: any } } = {};
|
||||
for (const code of groupCodes) {
|
||||
const groupItems = rateFeeRes.filter((item) => item.incExpCd === code);
|
||||
const lowers = groupItems.filter(
|
||||
(item) => Number(item.stdCost) <= result
|
||||
);
|
||||
const uppers = groupItems.filter(
|
||||
(item) => Number(item.stdCost) > result
|
||||
);
|
||||
|
||||
const lower =
|
||||
lowers.length > 0
|
||||
? lowers.reduce((acc, curr) =>
|
||||
Number(curr.stdCost) > Number(acc.stdCost) ? curr : acc
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const upper =
|
||||
uppers.length > 0
|
||||
? uppers.reduce((acc, curr) =>
|
||||
Number(curr.stdCost) < Number(acc.stdCost) ? curr : acc
|
||||
)
|
||||
: undefined;
|
||||
|
||||
groupedBounds[code] = { lower, upper };
|
||||
}
|
||||
|
||||
const resultRate = transformAndInterpolate(groupedBounds, result);
|
||||
const fcltSbsdEpsTrf =result * (resultRate.BD + resultRate.CE + resultRate.SE + resultRate.WD);
|
||||
|
||||
const realResult =
|
||||
result +fcltSbsdEpsTrf;
|
||||
|
||||
form.setValue("demandCst.prcsFcltCpctCstrnCst", result);
|
||||
form.setValue( "demandCst.fcltSbsdEpsTrf",fcltSbsdEpsTrf);
|
||||
form.setValue("totalConstCost", realResult);
|
||||
}
|
||||
}, [constCostRes, rateFeeRes, usgPrcsProcsWatch, dmndQtyWatch]);
|
||||
|
||||
const onSubmit = (value: DmdCoReqType) => {
|
||||
if (type === "mat") {
|
||||
@@ -77,7 +166,7 @@ export default function ConCostForm({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log(" form ", form.formState.errors);
|
||||
// console.log(" form ", form.formState.errors);
|
||||
}, [form.formState]);
|
||||
|
||||
return (
|
||||
@@ -90,7 +179,7 @@ export default function ConCostForm({
|
||||
<div className="flex items-center mx-3 mb-3">
|
||||
<h1 className="">처리시설 표준공사비 산정</h1>
|
||||
|
||||
<Button size={"sm"} onClick={(e) => {}}>
|
||||
<Button size={"sm"} onClick={calculateConstCost}>
|
||||
계산
|
||||
</Button>
|
||||
<Button size={"sm"} onClick={form.handleSubmit(onSubmit)}>
|
||||
@@ -111,7 +200,7 @@ export default function ConCostForm({
|
||||
placeholder=""
|
||||
type="text"
|
||||
onChange={(e) => {
|
||||
field.onChange((e.target.value));
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={field.value ?? ""}
|
||||
/>
|
||||
@@ -194,9 +283,10 @@ export default function ConCostForm({
|
||||
type="number"
|
||||
step="0.001"
|
||||
onChange={(e) => {
|
||||
field.onChange(Number(e.target.value));
|
||||
//field.onChange(Number(e.target.value) * 365 );
|
||||
}}
|
||||
value={Number(field.value) * 365 || 0}
|
||||
readOnly
|
||||
/>
|
||||
</FormUi>
|
||||
)}
|
||||
@@ -286,16 +376,22 @@ export default function ConCostForm({
|
||||
}
|
||||
bodyClassName={"w-[22vw]"}
|
||||
></PopoverUi>
|
||||
<Input
|
||||
placeholder=""
|
||||
className="mt-2"
|
||||
type="number"
|
||||
step="0.01"
|
||||
onChange={(e) => {}}
|
||||
value={
|
||||
form.getValues("demandCst.prcsFcltCpctCstrnCst") +
|
||||
form.getValues("demandCst.fcltSbsdEpsTrf") || 0
|
||||
}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="totalConstCost"
|
||||
render={({ field }) => (
|
||||
<FormUi label="">
|
||||
<Input
|
||||
placeholder=""
|
||||
className="mt-2"
|
||||
type="number"
|
||||
step="0.01"
|
||||
onChange={(e) => {}}
|
||||
value={field.value ?? 0}
|
||||
readOnly
|
||||
/>
|
||||
</FormUi>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-3 mt-4">
|
||||
@@ -323,75 +419,80 @@ export default function ConCostForm({
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-4 mt-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="demandCst.cstrnCst"
|
||||
render={({ field }) => (
|
||||
<FormUi label="공급관로 표준공사비(백만원)">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="demandCst.cstrnCst"
|
||||
render={({ field }) => (
|
||||
<FormUi label="공급관로 표준공사비(백만원)">
|
||||
<Input
|
||||
placeholder=""
|
||||
type="number"
|
||||
step="0.01"
|
||||
onChange={(e) => {
|
||||
field.onChange(Number(e.target.value));
|
||||
}}
|
||||
value={field.value ?? 0}
|
||||
/>
|
||||
</FormUi>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-4 mt-4 mb-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name=""
|
||||
render={({ field }) => (
|
||||
<Label className="text-xl">
|
||||
처리시설 + 공급관로 총사업비(백만원)
|
||||
<FormUi label="">
|
||||
<Input
|
||||
placeholder=""
|
||||
type="text"
|
||||
type="number"
|
||||
step="0.001"
|
||||
onChange={(e) => {
|
||||
field.onChange(Number(e.target.value));
|
||||
}}
|
||||
value={field.value ?? 0}
|
||||
readOnly={true}
|
||||
value={(totalConstCost ?? 0) + (cstrnCst ?? 0)}
|
||||
/>
|
||||
</FormUi>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-4 mt-4 mb-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name=""
|
||||
render={({ field }) => (
|
||||
<Label className="text-xl">
|
||||
처리시설 + 공급관로 총사업비(백만원)
|
||||
<FormUi label="">
|
||||
<Input
|
||||
placeholder=""
|
||||
type="number"
|
||||
step="0.001"
|
||||
onChange={(e) => {
|
||||
field.onChange(Number(e.target.value));
|
||||
}}
|
||||
readOnly={true}
|
||||
value={field.value ?? 0}
|
||||
/>
|
||||
</FormUi>
|
||||
</Label>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className=" col-span-4 mt-4 ">
|
||||
<Label>관로 표준공사비 산정 프로그램</Label>
|
||||
<Button
|
||||
color="green"
|
||||
size={"sm"}
|
||||
onClick={zipDowonLoad}
|
||||
className="bg-none ml-6"
|
||||
>
|
||||
다운로드
|
||||
</Button>
|
||||
</div>
|
||||
</Label>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className=" col-span-4 mt-4 ">
|
||||
<Label>관로 표준공사비 산정 프로그램</Label>
|
||||
<Button
|
||||
color="green"
|
||||
size={"sm"}
|
||||
onClick={zipDowonLoad}
|
||||
className="bg-none ml-6"
|
||||
>
|
||||
다운로드
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UiModal
|
||||
body={<RateFeeTableModal setReturnData={(e) =>{}}></RateFeeTableModal>}
|
||||
body={
|
||||
<ConstCostFeeTable setReturnData={(e) => {}}></ConstCostFeeTable>
|
||||
}
|
||||
bodyClass="w-[40vw] max-w-none h-[40vh]"
|
||||
open={isCmpttnMo.isModal}
|
||||
onOpenChange={(open) => {
|
||||
setIsCmpttnMo({ isModal: open });
|
||||
}}
|
||||
/>
|
||||
<UiModal
|
||||
body={
|
||||
<RateFeeTableModal setReturnData={(e) => {}}></RateFeeTableModal>
|
||||
}
|
||||
bodyClass="w-[40vw] h-[40vh] "
|
||||
open={isTrfMo.isModal}
|
||||
onOpenChange={(open) => {
|
||||
setIsTrfMo({ isModal: open });
|
||||
}}
|
||||
/>
|
||||
<UiModal
|
||||
body={<ConstCostFeeTable setReturnData={(e) =>{}}></ConstCostFeeTable>}
|
||||
bodyClass="w-[40vw] max-w-none h-[40vh]"
|
||||
open={isCmpttnMo.isModal}
|
||||
onOpenChange={(open) => {
|
||||
setIsCmpttnMo({ isModal: open });
|
||||
}}
|
||||
/>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -23,12 +23,12 @@ export function ConstCostFeeTable({
|
||||
const [constCostData, setConstCostData] = useState<ContCostMap[]>([]);
|
||||
|
||||
|
||||
function getFctDescription(fctCd: string) {
|
||||
const getFctDescription = (fctCd: string) => {
|
||||
const fctMap: { [key: string]: string } = {
|
||||
"001": "총인",
|
||||
"002": "염소.소독",
|
||||
"003": "uv소독",
|
||||
"004": "생물학적탈질",
|
||||
"001": "총인처리시설",
|
||||
"002": "염소소독",
|
||||
"003": "UV소독",
|
||||
"004": "전처리시설",
|
||||
"005": "RO",
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user