Files
frontend/apps/st/src/components/util/grid/computedFieldCallbacks.ts
T

214 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { DataFieldValueCallback, ComputedFieldConfig } from "@/components/type/DataGrid.type";
/** 값 → 숫자 변환 (null/undefined/빈문자열 → 0) */
function toNum(v: unknown): number {
if (v == null || v === "") return 0;
if (typeof v === "number") return isNaN(v) ? 0 : v;
const n = parseFloat(String(v).replace(/,/g, ""));
return isNaN(n) ? 0 : n;
}
/** 소수점 첫째 자리 이후 버림 (반올림 없음) */
function truncateToFirstDecimal(value: number): number {
if (!Number.isFinite(value)) return 0;
return Math.floor(value * 10) / 10;
}
/** 합계용 valueCallback 생성 */
export function createSumValueCallback(fieldNames: string[]): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
let sum = 0;
for (const f of fieldNames) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) sum += toNum(values[idx]);
}
return sum;
};
}
/** 평균용 valueCallback 생성 */
export function createAvgValueCallback(fieldNames: string[]): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
let sum = 0;
let count = 0;
for (const f of fieldNames) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) {
const val = toNum(values[idx]);
sum += val;
count += 1;
}
}
return count > 0 ? sum / count : 0;
};
}
/** 차이값: fields[0] − fields[1] (예: 매설연장 − 철거연장) */
export function createDifferenceValueCallback(fields: string[]): DataFieldValueCallback {
const a = fields[0] ?? "";
const b = fields[1] ?? "";
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
if (!a || !b) return 0;
const ia = fieldNamesArr.indexOf(a);
const ib = fieldNamesArr.indexOf(b);
const va = ia >= 0 ? toNum(values[ia]) : 0;
const vb = ib >= 0 ? toNum(values[ib]) : 0;
return va - vb;
};
}
/** (여러 필드 합) - (여러 필드 합) */
export function createDifferenceOfSumsValueCallback(
minuendFields: string[],
subtrahendFields: string[],
): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
const sumOf = (fields: string[]) => {
let sum = 0;
for (const f of fields) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) sum += toNum(values[idx]);
}
return sum;
};
return sumOf(minuendFields) - sumOf(subtrahendFields);
};
}
/** 최대값용 valueCallback 생성 */
export function createMaxValueCallback(fieldNames: string[]): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
let max = Number.NEGATIVE_INFINITY;
for (const f of fieldNames) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) {
const val = toNum(values[idx]);
max = Math.max(max, val);
}
}
return max === Number.NEGATIVE_INFINITY ? 0 : max;
};
}
/** 단일 필드값 vs 여러 필드 합계 중 최대값 */
export function createMaxOfFieldAndSumValueCallback(
baseField: string,
sumFields: string[],
): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
const baseIdx = fieldNamesArr.indexOf(baseField);
const baseVal = baseIdx >= 0 ? toNum(values[baseIdx]) : 0;
let sumVal = 0;
for (const f of sumFields) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) sumVal += toNum(values[idx]);
}
return Math.max(baseVal, sumVal);
};
}
/** 여러 그룹의 max(baseField, sum(sumFields)) 값을 모두 합산 */
export function createSumOfMaxOfFieldAndSumGroupsValueCallback(
groups: Array<{ baseField: string; sumFields: string[] }>,
): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
let total = 0;
for (const group of groups) {
const baseIdx = fieldNamesArr.indexOf(group.baseField);
const baseVal = baseIdx >= 0 ? toNum(values[baseIdx]) : 0;
let sumVal = 0;
for (const f of group.sumFields) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) sumVal += toNum(values[idx]);
}
total += Math.max(baseVal, sumVal);
}
return total;
};
}
// 공공하수처리구역인구보급률(%), 고도처리인구보급률(%) valueCallback
export function createCoverageRateValueCallback(
numeratorFields: string[],
denominatorFields: string[]
): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
const getSum = (fields: string[]) => {
let sum = 0;
for (const f of fields) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) sum += toNum(values[idx]);
}
return sum;
};
const total2 = getSum(numeratorFields);
const total1 = getSum(denominatorFields);
return total1 === 0 ? 0 : (total2 / total1) * 100;
};
}
// 하수도 설치율(%) valueCallback — 항목·중간·결과 모두 소수 첫째 자리 이후 버림(반올림 없음)
export function createSwrgInstlrtRateValueCallback(
numeratorFields: string[],
denominatorFields: string[],
thirdFields: string[],
): DataFieldValueCallback {
return (_prod, _dataRow, _fieldName, fieldNamesArr, values) => {
const getSum = (fields: string[]) => {
let sum = 0;
for (const f of fields) {
const idx = fieldNamesArr.indexOf(f);
if (idx >= 0) {
sum += truncateToFirstDecimal(toNum(values[idx]));
}
}
return truncateToFirstDecimal(sum);
};
const sum1 = getSum(numeratorFields);
const sum2 = getSum(denominatorFields);
const piplSupprt = truncateToFirstDecimal(
toNum(values[fieldNamesArr.indexOf(thirdFields[0] || "piplSupprt")]),
);
const ratioPercent =
sum1 === 0 ? 0 : truncateToFirstDecimal((sum2 / sum1) * 100);
const result = truncateToFirstDecimal((ratioPercent * piplSupprt) / 100);
return result;
};
}
/** 연산 타입에 맞는 valueCallback 반환 */
export function getComputedValueCallback(config: ComputedFieldConfig): DataFieldValueCallback {
switch (config.type) {
case 'sum':
return createSumValueCallback(config.fields);
case 'avg':
return createAvgValueCallback(config.fields);
case 'max':
return createMaxValueCallback(config.fields);
case 'difference':
return createDifferenceValueCallback(config.fields);
case 'differenceOfSums':
return createDifferenceOfSumsValueCallback(
config.minuendFields,
config.subtrahendFields,
);
case 'maxOfFieldAndSum':
return createMaxOfFieldAndSumValueCallback(
config.baseField,
config.sumFields,
);
case 'sumOfMaxOfFieldAndSumGroups':
return createSumOfMaxOfFieldAndSumGroupsValueCallback(
config.groups,
);
case 'pblswrgPopltnSuprtRate':
case 'adtrtPopltnSuprtRate':
return createCoverageRateValueCallback(config.numeratorFields, config.denominatorFields);
case 'swrgInstlrtRate':
return createSwrgInstlrtRateValueCallback(config.numeratorFields, config.denominatorFields, config.thirdFields);
}
}