"use client"; /** * PivotGrid 렌더러 * 화면 관리 시스템에서 PivotGrid를 렌더링하는 컴포넌트 */ import React, { useState, useEffect, useMemo } from "react"; import { ComponentRegistry } from "../../ComponentRegistry"; import { PivotGridComponent } from "./PivotGridComponent"; import { PivotGridConfigPanel } from "./PivotGridConfigPanel"; import { PivotGridComponentConfig, PivotFieldConfig, PivotCellData, } from "./types"; import { apiClient } from "@/lib/api/client"; // ==================== 타입 ==================== interface PivotGridRendererProps { // 위젯 ID id?: string; // 컴포넌트 설정 config?: PivotGridComponentConfig; // 외부 데이터 (formData 등에서 주입) data?: Record[]; // 화면 관리 컨텍스트 formData?: Record; // 이벤트 핸들러 onCellClick?: (cellData: PivotCellData) => void; onDataLoad?: (data: Record[]) => void; // 제어관리 연동 buttonControlOptions?: { buttonId?: string; actionType?: string; }; // 자동 필터 (멀티테넌시) autoFilter?: { companyCode?: string; }; } // ==================== 메인 컴포넌트 ==================== export const PivotGridRenderer: React.FC = ({ id, config, data: externalData, formData, onCellClick, onDataLoad, buttonControlOptions, autoFilter, }) => { const [data, setData] = useState[]>([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); // 데이터 로드 useEffect(() => { const loadData = async () => { // 외부 데이터가 있으면 사용 if (externalData && externalData.length > 0) { setData(externalData); onDataLoad?.(externalData); return; } // 데이터 소스 설정 확인 if (!config?.dataSource?.tableName) { setData([]); return; } setLoading(true); setError(null); try { // 테이블 데이터 조회 const params: any = { tableName: config.dataSource.tableName, }; // 멀티테넌시 필터 적용 if (autoFilter?.companyCode) { params.companyCode = autoFilter.companyCode; } // 필터 조건 적용 if (config.dataSource.filterConditions) { const filters: Record = {}; config.dataSource.filterConditions.forEach((cond) => { if (cond.valueFromField && formData) { filters[cond.field] = formData[cond.valueFromField]; } else if (cond.value !== undefined) { filters[cond.field] = cond.value; } }); params.filters = JSON.stringify(filters); } const response = await apiClient.get( `/api/table-management/data/${config.dataSource.tableName}`, { params } ); if (response.data.success) { const loadedData = response.data.data || []; setData(loadedData); onDataLoad?.(loadedData); } else { throw new Error(response.data.message || "데이터 로드 실패"); } } catch (err: any) { console.error("PivotGrid 데이터 로드 실패:", err); setError(err.message || "데이터를 불러오는데 실패했습니다"); setData([]); } finally { setLoading(false); } }; loadData(); }, [ config?.dataSource?.tableName, config?.dataSource?.filterConditions, externalData, formData, autoFilter?.companyCode, onDataLoad, ]); // 필드 설정에서 formData 값 적용 const processedFields = useMemo(() => { if (!config?.fields) return []; return config.fields.map((field) => { // 필터 값에 formData 적용 if (field.filterValues && formData) { return { ...field, filterValues: field.filterValues.map((v) => { if (typeof v === "string" && v.startsWith("{{") && v.endsWith("}}")) { const key = v.slice(2, -2).trim(); return formData[key] ?? v; } return v; }), }; } return field; }); }, [config?.fields, formData]); // 로딩 상태 if (loading) { return (
데이터 로딩 중...
); } // 에러 상태 if (error) { return (

데이터 로드 실패

{error}

); } return ( ); }; // ==================== 컴포넌트 등록 ==================== ComponentRegistry.register({ type: "pivot-grid", label: "피벗 그리드", category: "data", icon: "BarChart3", description: "다차원 데이터 분석을 위한 피벗 테이블 컴포넌트", defaultConfig: { dataSource: { type: "table", tableName: "", }, fields: [], totals: { showRowGrandTotals: true, showColumnGrandTotals: true, showRowTotals: true, showColumnTotals: true, }, style: { theme: "default", headerStyle: "default", cellPadding: "normal", borderStyle: "light", alternateRowColors: true, highlightTotals: true, }, allowExpandAll: true, exportConfig: { excel: true, }, height: "400px", }, Renderer: PivotGridRenderer, ConfigPanel: PivotGridConfigPanel, }); export default PivotGridRenderer;