ERP-node/frontend/lib/registry/components/simple-repeater-table/useCalculation.ts

68 lines
2.0 KiB
TypeScript

import { useCallback } from "react";
import { CalculationRule } from "./types";
/**
* 계산 필드 자동 업데이트 훅
*/
export function useCalculation(calculationRules: CalculationRule[] = []) {
/**
* 단일 행의 계산 필드 업데이트
*/
const calculateRow = useCallback(
(row: any): any => {
if (calculationRules.length === 0) return row;
const updatedRow = { ...row };
for (const rule of calculationRules) {
try {
// formula에서 필드명 자동 추출 (영문자, 숫자, 언더스코어로 구성된 단어)
let formula = rule.formula;
const fieldMatches = formula.match(/[a-zA-Z_][a-zA-Z0-9_]*/g) || [];
// 추출된 필드명들을 사용 (dependencies가 없으면 자동 추출 사용)
const dependencies = rule.dependencies && rule.dependencies.length > 0
? rule.dependencies
: fieldMatches;
// 필드명을 실제 값으로 대체
for (const dep of dependencies) {
// 결과 필드는 제외
if (dep === rule.result) continue;
const value = parseFloat(row[dep]) || 0;
// 정확한 필드명만 대체 (단어 경계 사용)
formula = formula.replace(new RegExp(`\\b${dep}\\b`, "g"), value.toString());
}
// 계산 실행 (Function 사용)
const result = new Function(`return ${formula}`)();
updatedRow[rule.result] = result;
} catch (error) {
console.error(`계산 오류 (${rule.formula}):`, error);
updatedRow[rule.result] = 0;
}
}
return updatedRow;
},
[calculationRules]
);
/**
* 전체 데이터의 계산 필드 업데이트
*/
const calculateAll = useCallback(
(data: any[]): any[] => {
return data.map((row) => calculateRow(row));
},
[calculateRow]
);
return {
calculateRow,
calculateAll,
};
}