ERP-node/frontend/lib/registry/layouts/card-layout/CardLayoutRenderer.tsx

183 lines
5.1 KiB
TypeScript

"use client";
import { AutoRegisteringLayoutRenderer } from "../AutoRegisteringLayoutRenderer";
import { CardLayoutDefinition } from "./index";
import { CardLayoutLayout } from "./CardLayoutLayout";
import React, { useState, useEffect } from "react";
import { tableTypeApi } from "@/lib/api/screen";
/**
* 카드 레이아웃 렌더러 컴포넌트
*/
const CardLayoutRendererComponent: React.FC<any> = (props) => {
const { layout, children, onUpdateLayout, onSelectComponent, isDesignMode } = props;
const [tableData, setTableData] = useState<any[]>([]);
const [tableColumns, setTableColumns] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
// 테이블 데이터 로딩
useEffect(() => {
const loadTableData = async () => {
// 디자인 모드에서는 테이블 데이터를 로드하지 않음
if (isDesignMode) {
return;
}
// 카드 설정에서 테이블명 확인 (여러 소스에서 시도)
const tableName =
layout?.tableName ||
layout?.screenTableName ||
props?.tableName ||
props?.selectedScreen?.tableName ||
"company_mng"; // 임시 하드코딩 (테스트용)
if (!tableName) {
console.log("📋 카드 레이아웃: 테이블명이 설정되지 않음", {
layoutTableName: layout?.tableName,
screenTableName: layout?.screenTableName,
propsTableName: props?.tableName,
selectedScreenTableName: props?.selectedScreen?.tableName,
});
return;
}
try {
setLoading(true);
console.log(`📋 카드 레이아웃: ${tableName} 테이블 데이터 로딩 시작`);
// 테이블 데이터와 컬럼 정보를 병렬로 로드
const [dataResponse, columnsResponse] = await Promise.all([
tableTypeApi.getTableData(tableName, {
page: 1,
size: 50, // 카드 레이아웃용으로 적당한 개수
}),
tableTypeApi.getColumns(tableName),
]);
console.log(`📋 카드 레이아웃: ${tableName} 데이터 로딩 완료`, {
total: dataResponse.total,
dataLength: dataResponse.data.length,
columnsLength: columnsResponse.length,
sampleData: dataResponse.data.slice(0, 2),
sampleColumns: columnsResponse.slice(0, 3),
});
setTableData(dataResponse.data);
setTableColumns(columnsResponse);
} catch (error) {
console.error(`❌ 카드 레이아웃: ${tableName} 데이터 로딩 실패`, error);
setTableData([]);
} finally {
setLoading(false);
}
};
loadTableData();
}, [layout?.tableName, isDesignMode]);
return (
<CardLayoutLayout
layout={layout}
children={children}
onUpdateLayout={onUpdateLayout}
onSelectComponent={onSelectComponent}
isDesignMode={isDesignMode}
tableData={tableData}
tableColumns={tableColumns}
/>
);
};
/**
* 카드 레이아웃 렌더러
* AutoRegisteringLayoutRenderer를 상속받아 자동 등록 기능 제공
*/
export class CardLayoutRenderer extends AutoRegisteringLayoutRenderer {
/**
* 레이아웃 정의 (자동 등록용)
*/
static layoutDefinition = CardLayoutDefinition;
/**
* 카드 레이아웃 렌더링
*/
render(): React.ReactElement {
return <CardLayoutRendererComponent {...this.props} />;
}
/**
* 카드 컨테이너 스타일 계산
*/
getCardContainerStyle(): React.CSSProperties {
const cardConfig = this.props.layout.layoutConfig?.cardLayout || {
columns: 3,
gap: 16,
};
return {
display: "grid",
gridTemplateColumns: `repeat(${cardConfig.columns}, 1fr)`,
gridTemplateRows: "repeat(2, 300px)",
gap: `${cardConfig.gap}px`,
padding: "16px",
width: "100%",
height: "100%",
};
}
/**
* 개별 카드 스타일 계산
*/
getCardStyle(zoneId: string): React.CSSProperties {
const baseStyle: React.CSSProperties = {
backgroundColor: "white",
border: "1px solid #e5e7eb",
borderRadius: "8px",
padding: "16px",
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1)",
transition: "all 0.2s ease-in-out",
overflow: "hidden",
display: "flex",
flexDirection: "column",
position: "relative",
minHeight: "200px",
};
// 디자인 모드에서 추가 스타일
if (this.props.isDesignMode) {
return {
...baseStyle,
cursor: "pointer",
borderColor: "#d1d5db",
};
}
return baseStyle;
}
/**
* 카드 호버 효과 계산
*/
getCardHoverStyle(): React.CSSProperties {
return {
borderColor: "#3b82f6",
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
transform: "translateY(-1px)",
};
}
/**
* 그리드 위치 계산
*/
getGridPosition(index: number): { row: number; column: number } {
const columns = this.props.layout.layoutConfig?.cardLayout?.columns || 3;
return {
row: Math.floor(index / columns),
column: index % columns,
};
}
}
// 자동 등록 실행
CardLayoutRenderer.registerSelf();