"use client"; import React, { useState, useEffect, useMemo } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Plus, Trash2, GripVertical, Database, Table2, ChevronsUpDown, Check } from "lucide-react"; import { cn } from "@/lib/utils"; import { AggregationWidgetConfig, AggregationItem, AggregationType } from "./types"; import { tableManagementApi } from "@/lib/api/tableManagement"; import { tableTypeApi } from "@/lib/api/screen"; interface AggregationWidgetConfigPanelProps { config: AggregationWidgetConfig; onChange: (config: Partial) => void; screenTableName?: string; } /** * 집계 위젯 설정 패널 */ export function AggregationWidgetConfigPanel({ config, onChange, screenTableName, }: AggregationWidgetConfigPanelProps) { const [columns, setColumns] = useState>([]); const [loadingColumns, setLoadingColumns] = useState(false); const [availableTables, setAvailableTables] = useState>([]); const [loadingTables, setLoadingTables] = useState(false); const [tableComboboxOpen, setTableComboboxOpen] = useState(false); // 실제 사용할 테이블 이름 계산 const targetTableName = useMemo(() => { if (config.useCustomTable && config.customTableName) { return config.customTableName; } return config.tableName || screenTableName; }, [config.useCustomTable, config.customTableName, config.tableName, screenTableName]); // 화면 테이블명 자동 설정 (초기 한 번만) useEffect(() => { if (screenTableName && !config.tableName && !config.customTableName) { onChange({ tableName: screenTableName }); } }, [screenTableName, config.tableName, config.customTableName, onChange]); // 전체 테이블 목록 로드 useEffect(() => { const fetchTables = async () => { setLoadingTables(true); try { const response = await tableTypeApi.getTables(); setAvailableTables( response.map((table: any) => ({ tableName: table.tableName, displayName: table.displayName || table.tableName, })) ); } catch (error) { console.error("테이블 목록 가져오기 실패:", error); } finally { setLoadingTables(false); } }; fetchTables(); }, []); // 테이블 컬럼 로드 useEffect(() => { const loadColumns = async () => { if (!targetTableName) { setColumns([]); return; } setLoadingColumns(true); try { const result = await tableManagementApi.getColumnList(targetTableName); if (result.success && result.data?.columns) { setColumns( result.data.columns.map((col: any) => ({ columnName: col.columnName || col.column_name, label: col.displayName || col.columnLabel || col.column_label || col.label || col.columnName || col.column_name, dataType: col.dataType || col.data_type, inputType: col.inputType || col.input_type, webType: col.webType || col.web_type, })) ); } else { setColumns([]); } } catch (error) { console.error("컬럼 로드 실패:", error); setColumns([]); } finally { setLoadingColumns(false); } }; loadColumns(); }, [targetTableName]); // 집계 항목 추가 const addItem = () => { const newItem: AggregationItem = { id: `agg-${Date.now()}`, columnName: "", columnLabel: "", type: "sum", format: "number", decimalPlaces: 0, }; onChange({ items: [...(config.items || []), newItem], }); }; // 집계 항목 삭제 const removeItem = (id: string) => { onChange({ items: (config.items || []).filter((item) => item.id !== id), }); }; // 집계 항목 업데이트 const updateItem = (id: string, updates: Partial) => { onChange({ items: (config.items || []).map((item) => item.id === id ? { ...item, ...updates } : item ), }); }; // 숫자형 컬럼만 필터링 (count 제외) - 입력 타입(inputType/webType)으로만 확인 const numericColumns = columns.filter((col) => { const inputType = (col.inputType || col.webType || "")?.toLowerCase(); return ( inputType === "number" || inputType === "decimal" || inputType === "integer" || inputType === "float" || inputType === "currency" || inputType === "percent" ); }); return (
집계 위젯 설정
{/* 테이블 설정 (컴포넌트 개발 가이드 준수) */}

데이터 소스 테이블

집계할 데이터의 테이블을 선택합니다


{/* 현재 선택된 테이블 표시 (카드 형태) */}
{config.customTableName || config.tableName || screenTableName || "테이블 미선택"}
{config.useCustomTable ? "커스텀 테이블" : "화면 기본 테이블"}
{/* 테이블 선택 Combobox */} 테이블을 찾을 수 없습니다 {/* 그룹 1: 화면 기본 테이블 */} {screenTableName && ( { onChange({ useCustomTable: false, customTableName: undefined, tableName: screenTableName, items: [], // 테이블 변경 시 집계 항목 초기화 }); setTableComboboxOpen(false); }} className="text-xs cursor-pointer" > {screenTableName} )} {/* 그룹 2: 전체 테이블 */} {availableTables .filter((table) => table.tableName !== screenTableName) .map((table) => ( { onChange({ useCustomTable: true, customTableName: table.tableName, tableName: table.tableName, items: [], // 테이블 변경 시 집계 항목 초기화 }); setTableComboboxOpen(false); }} className="text-xs cursor-pointer" > {table.displayName || table.tableName} ))}
{/* 레이아웃 설정 */}

레이아웃


onChange({ gap: e.target.value })} placeholder="16px" className="h-8 text-xs" />
onChange({ showLabels: checked as boolean })} />
onChange({ showIcons: checked as boolean })} />
{/* 집계 항목 설정 */}

집계 항목


{(config.items || []).length === 0 ? (
집계 항목을 추가해주세요
) : (
{(config.items || []).map((item, index) => (
항목 {index + 1}
{/* 컬럼 선택 */}
{/* 집계 타입 */}
{/* 표시 라벨 */}
updateItem(item.id, { columnLabel: e.target.value })} placeholder="표시될 라벨" className="h-7 text-xs" />
{/* 표시 형식 */}
{/* 접두사 */}
updateItem(item.id, { prefix: e.target.value })} placeholder="예: ₩" className="h-7 text-xs" />
{/* 접미사 */}
updateItem(item.id, { suffix: e.target.value })} placeholder="예: 원, 개" className="h-7 text-xs" />
))}
)}
{/* 스타일 설정 */}

스타일


onChange({ backgroundColor: e.target.value })} className="h-8" />
onChange({ borderRadius: e.target.value })} placeholder="6px" className="h-8 text-xs" />
onChange({ labelColor: e.target.value })} className="h-8" />
onChange({ valueColor: e.target.value })} className="h-8" />
); }