From efa28d8a4743276c4cf29b1ef28d656f1df0211a Mon Sep 17 00:00:00 2001 From: leeheejin Date: Wed, 29 Oct 2025 18:26:06 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BF=BC=EB=A6=AC=EB=AC=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EC=A2=80=20=EC=99=84=ED=99=94=EC=8B=9C=ED=82=A8=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/CustomMetricTestWidget.tsx | 134 ++++++------------ 1 file changed, 45 insertions(+), 89 deletions(-) diff --git a/frontend/components/dashboard/widgets/CustomMetricTestWidget.tsx b/frontend/components/dashboard/widgets/CustomMetricTestWidget.tsx index 68834ba8..74869ef0 100644 --- a/frontend/components/dashboard/widgets/CustomMetricTestWidget.tsx +++ b/frontend/components/dashboard/widgets/CustomMetricTestWidget.tsx @@ -221,10 +221,8 @@ export default function CustomMetricTestWidget({ element }: CustomMetricTestWidg const { sourceName, rows } = result.value; - // 집계된 데이터인지 확인 (행이 적고 숫자 컬럼이 있으면) - const hasAggregatedData = rows.length > 0 && rows.length <= 100; - - if (hasAggregatedData && rows.length > 0) { + // 🎯 간단한 쿼리도 잘 작동하도록 개선된 로직 + if (rows.length > 0) { const firstRow = rows[0]; const columns = Object.keys(firstRow); @@ -235,28 +233,44 @@ export default function CustomMetricTestWidget({ element }: CustomMetricTestWidg }); // 문자열 컬럼 찾기 - const stringColumns = columns.filter((col) => { - const value = firstRow[col]; - return typeof value === "string" || !numericColumns.includes(col); - }); + const stringColumns = columns.filter((col) => !numericColumns.includes(col)); - // console.log(`📊 [${sourceName}] 컬럼 분석:`, { - // 전체: columns, - // 숫자: numericColumns, - // 문자열: stringColumns, - // }); - - // 🆕 자동 집계 로직: 집계 컬럼 이름으로 판단 (count, 개수, sum, avg 등) - const isAggregated = numericColumns.some((col) => - /count|개수|sum|합계|avg|평균|min|최소|max|최대|total|전체/i.test(col), - ); - - if (isAggregated && numericColumns.length > 0) { - // 집계 컬럼이 있으면 이미 집계된 데이터로 판단 (GROUP BY 결과) - // console.log(`✅ [${sourceName}] 집계된 데이터로 판단 (집계 컬럼 발견: ${numericColumns.join(", ")})`); + // 🎯 케이스 0: 1행인데 숫자 컬럼이 여러 개 → 각 컬럼을 별도 카드로 + if (rows.length === 1 && numericColumns.length > 1) { + // 예: SELECT COUNT(*) AS 전체, SUM(...) AS 배송중, ... + numericColumns.forEach((col) => { + allMetrics.push({ + label: col, // 컬럼명이 라벨 + value: Number(firstRow[col]) || 0, + field: col, + aggregation: "custom", + color: colors[allMetrics.length % colors.length], + sourceName: sourceName, + rawData: [firstRow], + }); + }); + } + // 🎯 케이스 1: 컬럼이 2개 (라벨 + 값) → 가장 간단한 형태 + else if (columns.length === 2) { + const labelCol = columns[0]; + const valueCol = columns[1]; + rows.forEach((row) => { + allMetrics.push({ + label: String(row[labelCol] || ""), + value: Number(row[valueCol]) || 0, + field: valueCol, + aggregation: "custom", + color: colors[allMetrics.length % colors.length], + sourceName: sourceName, + rawData: [row], + }); + }); + } + // 🎯 케이스 2: 숫자 컬럼이 1개 이상 있음 → 집계된 데이터 + else if (numericColumns.length > 0) { rows.forEach((row, index) => { - // 라벨: 첫 번째 문자열 컬럼 + // 라벨: 첫 번째 문자열 컬럼 (없으면 첫 번째 컬럼) const labelField = stringColumns[0] || columns[0]; const label = String(row[labelField] || `항목 ${index + 1}`); @@ -264,8 +278,6 @@ export default function CustomMetricTestWidget({ element }: CustomMetricTestWidg const valueField = numericColumns[0]; const value = Number(row[valueField]) || 0; - // console.log(` [${sourceName}] 메트릭: ${label} = ${value}`); - allMetrics.push({ label: label, value: value, @@ -276,25 +288,18 @@ export default function CustomMetricTestWidget({ element }: CustomMetricTestWidg rawData: [row], }); }); - } else { - // 숫자 컬럼이 없으면 자동 집계 (마지막 컬럼 기준) - // console.log(`✅ [${sourceName}] 자동 집계 모드 (숫자 컬럼 없음)`); - - // 마지막 컬럼을 집계 기준으로 사용 + } + // 🎯 케이스 3: 숫자 컬럼이 없음 → 마지막 컬럼 기준으로 카운트 + else { const aggregateField = columns[columns.length - 1]; - // console.log(` [${sourceName}] 집계 기준 컬럼: ${aggregateField}`); - - // 해당 컬럼의 값별로 카운트 const countMap = new Map(); + rows.forEach((row) => { const value = String(row[aggregateField] || "기타"); countMap.set(value, (countMap.get(value) || 0) + 1); }); - // 카운트 결과를 메트릭으로 변환 countMap.forEach((count, label) => { - // console.log(` [${sourceName}] 자동 집계: ${label} = ${count}개`); - allMetrics.push({ label: label, value: count, @@ -318,59 +323,10 @@ export default function CustomMetricTestWidget({ element }: CustomMetricTestWidg }); } - // 🆕 숫자 컬럼이 없을 때의 기존 로직은 주석 처리 - /* if (false && result.status === "fulfilled") { - // 숫자 컬럼이 없으면 각 컬럼별 고유값 개수 표시 - // console.log(`📊 [${sourceName}] 문자열 데이터, 각 컬럼별 고유값 개수 표시`); - - // 데이터 소스에서 선택된 컬럼 가져오기 - const dataSourceConfig = (element?.dataSources || element?.chartConfig?.dataSources)?.find( - (ds) => ds.name === sourceName || ds.id === result.value?.sourceIndex.toString(), - ); - const selectedColumns = dataSourceConfig?.selectedColumns || []; - - // 선택된 컬럼이 있으면 해당 컬럼만, 없으면 전체 컬럼 표시 - const columnsToShow = selectedColumns.length > 0 ? selectedColumns : columns; - - // console.log(` [${sourceName}] 표시할 컬럼:`, columnsToShow); - - columnsToShow.forEach((col) => { - // 해당 컬럼이 실제로 존재하는지 확인 - if (!columns.includes(col)) { - console.warn(` [${sourceName}] 컬럼 "${col}"이 데이터에 없습니다.`); - return; - } - - // 해당 컬럼의 고유값 개수 계산 - const uniqueValues = new Set(rows.map((row) => row[col])); - const uniqueCount = uniqueValues.size; - - // console.log(` [${sourceName}] ${col}: ${uniqueCount}개 고유값`); - - allMetrics.push({ - label: `${sourceName} - ${col} (고유값)`, - value: uniqueCount, - field: col, - aggregation: "distinct", - color: colors[allMetrics.length % colors.length], - sourceName: sourceName, - rawData: rows, // 원본 데이터 저장 - }); - }); - - // 총 행 개수도 추가 - allMetrics.push({ - label: `${sourceName} - 총 개수`, - value: rows.length, - field: "count", - aggregation: "count", - color: colors[allMetrics.length % colors.length], - sourceName: sourceName, - rawData: rows, // 원본 데이터 저장 - }); - } */ - } else { - // 행이 많으면 각 컬럼별 고유값 개수 + 총 개수 표시 + } + // 🎯 행이 많을 때도 간단하게 처리 + else if (rows.length > 100) { + // 행이 많으면 총 개수만 표시 // console.log(`📊 [${sourceName}] 일반 데이터 (행 많음), 컬럼별 통계 표시`); const firstRow = rows[0]; -- 2.43.0