102 lines
2.6 KiB
TypeScript
102 lines
2.6 KiB
TypeScript
export const findBounds = (
|
|
data: any[],
|
|
fctCd: string,
|
|
dataCode: string,
|
|
qtyCode:string,
|
|
qty: number
|
|
): { lower: any; upper: any } => {
|
|
|
|
|
|
const filtered = data.filter((item) => item[dataCode] === fctCd);
|
|
|
|
const lowers = filtered.filter((item) => Number(item[qtyCode]) <= qty);
|
|
const uppers = filtered.filter((item) => Number(item[qtyCode]) > qty);
|
|
|
|
const lower =
|
|
lowers.length > 0
|
|
? lowers.reduce((acc, curr) =>
|
|
Number(curr[qtyCode]) > Number(acc[qtyCode]) ? curr : acc
|
|
)
|
|
: undefined;
|
|
|
|
const upper =
|
|
uppers.length > 0
|
|
? uppers.reduce((acc, curr) =>
|
|
Number(curr[qtyCode]) < Number(acc[qtyCode]) ? curr : acc
|
|
)
|
|
: undefined;
|
|
|
|
// ✅ 바운더리 하나만 있을 경우 대체 처리
|
|
if (!lower && upper) return { lower: upper, upper };
|
|
if (!upper && lower) return { lower, upper: lower };
|
|
|
|
// ✅ 정상 보간 구간
|
|
if (lower && upper) return { lower, upper };
|
|
|
|
// ❌ 둘 다 없을 경우 (fctCd 필터 결과가 없음)
|
|
throw new Error(`No matching bounds found for fctCd: ${fctCd}, qty: ${qty}`);
|
|
};
|
|
|
|
|
|
// (기울기) 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 x1 = Number(Lower.fctCpc); // 최소 처리 용량
|
|
const y1 = Number(Lower.stdCost); // 최소 공사비/요율
|
|
const x2 = Number(Upper.fctCpc); // 최대 처리 용량
|
|
const y2 = Number(Upper.stdCost); // 최대 공사비/요율
|
|
|
|
if (qtyYear <= x1) return y1; // 최소 이하면 y1 반환
|
|
if (qtyYear >= x2) return y2; // 최대 이상이면 y2 반환
|
|
|
|
const slope = (y2 - y1) / (x2 - x1); // 기울기 a
|
|
const intercept = y1 - slope * x1; // 절편 b
|
|
|
|
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,
|
|
},
|
|
};
|
|
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];
|
|
};
|