ERP-node/frontend/lib/report/conditionalUtils.ts

80 lines
2.4 KiB
TypeScript

/**
* 조건부 표시 규칙 평가 유틸
*
* [사용처]
* - CanvasComponent.tsx : 캔버스 내 컴포넌트 조건부 표시
* - ReportPreviewModal.tsx : 미리보기 시 조건부 표시
* - ReportListPreviewModal.tsx : 목록 미리보기 시 조건부 표시
*/
import type { ConditionalRule } from "@/types/report";
export type { ConditionalRule };
type QueryResultGetter = (
queryId: string
) => { fields: string[]; rows: Record<string, unknown>[] } | null;
/**
* 단일 조건 규칙을 평가한다.
* 쿼리 결과의 첫 번째 행에서 필드 값을 가져와 연산자로 비교한다.
*/
export function evaluateSingleRule(
rule: ConditionalRule,
getQueryResult: QueryResultGetter
): boolean {
const queryResult = getQueryResult(rule.queryId);
if (!queryResult?.rows?.length) return false;
const rawValue = queryResult.rows[0][rule.field];
const fieldStr =
rawValue !== null && rawValue !== undefined ? String(rawValue) : "";
const fieldNum = parseFloat(fieldStr);
const compareNum = parseFloat(rule.value);
switch (rule.operator) {
case "eq":
return fieldStr === rule.value;
case "ne":
return fieldStr !== rule.value;
case "gt":
return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum > compareNum;
case "lt":
return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum < compareNum;
case "gte":
return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum >= compareNum;
case "lte":
return !isNaN(fieldNum) && !isNaN(compareNum) && fieldNum <= compareNum;
case "contains":
return fieldStr.includes(rule.value);
case "notEmpty":
return fieldStr !== "";
case "empty":
return fieldStr === "";
default:
return false;
}
}
/**
* 다중 조건 규칙을 AND로 평가한다.
* 모든 규칙이 충족되면 action에 따라 표시/숨김을 결정한다.
*/
export function evaluateConditionalRules(
rules: ConditionalRule[] | undefined | null,
getQueryResult: QueryResultGetter
): boolean {
if (!rules || rules.length === 0) return true;
const validRules = rules.filter(
(r) => r.queryId && r.field && r.operator
);
if (validRules.length === 0) return true;
const action = validRules[0].action || "show";
const allMet = validRules.every((r) =>
evaluateSingleRule(r, getQueryResult)
);
return action === "show" ? allMet : !allMet;
}