lhj #184

Merged
hjlee merged 3 commits from lhj into main 2025-11-05 16:37:50 +09:00
7 changed files with 447 additions and 14 deletions
Showing only changes of commit b4cc844675 - Show all commits

View File

@ -44,6 +44,7 @@ export default function ScreenViewPage() {
const [tableSortBy, setTableSortBy] = useState<string | undefined>();
const [tableSortOrder, setTableSortOrder] = useState<"asc" | "desc">("asc");
const [tableColumnOrder, setTableColumnOrder] = useState<string[] | undefined>();
const [tableDisplayData, setTableDisplayData] = useState<any[]>([]); // 화면에 표시된 데이터 (컬럼 순서 포함)
// 플로우에서 선택된 데이터 (버튼 액션에 전달)
const [flowSelectedData, setFlowSelectedData] = useState<any[]>([]);
@ -433,13 +434,16 @@ export default function ScreenViewPage() {
sortBy={tableSortBy}
sortOrder={tableSortOrder}
columnOrder={tableColumnOrder}
onSelectedRowsChange={(_, selectedData, sortBy, sortOrder, columnOrder) => {
tableDisplayData={tableDisplayData}
onSelectedRowsChange={(_, selectedData, sortBy, sortOrder, columnOrder, tableDisplayData) => {
console.log("🔍 화면에서 선택된 행 데이터:", selectedData);
console.log("📊 정렬 정보:", { sortBy, sortOrder, columnOrder });
console.log("📊 화면 표시 데이터:", { count: tableDisplayData?.length, firstRow: tableDisplayData?.[0] });
setSelectedRowsData(selectedData);
setTableSortBy(sortBy);
setTableSortOrder(sortOrder || "asc");
setTableColumnOrder(columnOrder);
setTableDisplayData(tableDisplayData || []);
}}
flowSelectedData={flowSelectedData}
flowSelectedStepId={flowSelectedStepId}
@ -494,13 +498,16 @@ export default function ScreenViewPage() {
sortBy={tableSortBy}
sortOrder={tableSortOrder}
columnOrder={tableColumnOrder}
onSelectedRowsChange={(_, selectedData, sortBy, sortOrder, columnOrder) => {
tableDisplayData={tableDisplayData}
onSelectedRowsChange={(_, selectedData, sortBy, sortOrder, columnOrder, tableDisplayData) => {
console.log("🔍 화면에서 선택된 행 데이터 (자식):", selectedData);
console.log("📊 정렬 정보 (자식):", { sortBy, sortOrder, columnOrder });
console.log("📊 화면 표시 데이터 (자식):", { count: tableDisplayData?.length, firstRow: tableDisplayData?.[0] });
setSelectedRowsData(selectedData);
setTableSortBy(sortBy);
setTableSortOrder(sortOrder || "asc");
setTableColumnOrder(columnOrder);
setTableDisplayData(tableDisplayData || []);
}}
refreshKey={tableRefreshKey}
onRefresh={() => {
@ -631,6 +638,7 @@ export default function ScreenViewPage() {
userId={user?.userId}
userName={userName}
companyCode={companyCode}
tableDisplayData={tableDisplayData}
selectedRowsData={selectedRowsData}
sortBy={tableSortBy}
sortOrder={tableSortOrder}

View File

@ -66,6 +66,7 @@ interface RealtimePreviewProps {
// 테이블 정렬 정보 전달용
sortBy?: string;
sortOrder?: "asc" | "desc";
tableDisplayData?: any[]; // 🆕 화면 표시 데이터
[key: string]: any; // 추가 props 허용
}
@ -109,7 +110,14 @@ const renderArea = (component: ComponentData, children?: React.ReactNode) => {
};
// 동적 웹 타입 위젯 렌더링 컴포넌트
const WidgetRenderer: React.FC<{ component: ComponentData; isDesignMode?: boolean }> = ({ component, isDesignMode = false }) => {
const WidgetRenderer: React.FC<{
component: ComponentData;
isDesignMode?: boolean;
sortBy?: string;
sortOrder?: "asc" | "desc";
tableDisplayData?: any[];
[key: string]: any;
}> = ({ component, isDesignMode = false, sortBy, sortOrder, tableDisplayData, ...restProps }) => {
// 위젯 컴포넌트가 아닌 경우 빈 div 반환
if (!isWidgetComponent(component)) {
return <div className="text-xs text-gray-500"> </div>;
@ -158,6 +166,9 @@ const WidgetRenderer: React.FC<{ component: ComponentData; isDesignMode?: boolea
readonly: readonly,
isDesignMode,
isInteractive: !isDesignMode,
sortBy, // 🆕 정렬 정보
sortOrder, // 🆕 정렬 방향
tableDisplayData, // 🆕 화면 표시 데이터
}}
config={widget.webTypeConfig}
/>
@ -231,6 +242,7 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
onFlowSelectedDataChange,
sortBy,
sortOrder,
tableDisplayData, // 🆕 화면 표시 데이터
...restProps
}) => {
const { user } = useAuth();
@ -557,6 +569,7 @@ export const RealtimePreviewDynamic: React.FC<RealtimePreviewProps> = ({
isDesignMode={isDesignMode}
sortBy={sortBy}
sortOrder={sortOrder}
tableDisplayData={tableDisplayData}
{...restProps}
/>
</div>

View File

@ -29,10 +29,11 @@ export interface ComponentRenderer {
// 테이블 선택된 행 정보 (다중 선택 액션용)
selectedRows?: any[];
selectedRowsData?: any[];
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[]) => void;
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[], tableDisplayData?: any[]) => void;
// 테이블 정렬 정보 (엑셀 다운로드용)
sortBy?: string;
sortOrder?: "asc" | "desc";
tableDisplayData?: any[]; // 🆕 화면 표시 데이터
// 플로우 선택된 데이터 정보 (플로우 위젯 선택 액션용)
flowSelectedData?: any[];
flowSelectedStepId?: number | null;
@ -104,11 +105,12 @@ export interface DynamicComponentRendererProps {
// 테이블 선택된 행 정보 (다중 선택 액션용)
selectedRows?: any[];
selectedRowsData?: any[];
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[]) => void;
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[], tableDisplayData?: any[]) => void;
// 테이블 정렬 정보 (엑셀 다운로드용)
sortBy?: string;
sortOrder?: "asc" | "desc";
columnOrder?: string[];
tableDisplayData?: any[]; // 🆕 화면 표시 데이터
// 플로우 선택된 데이터 정보 (플로우 위젯 선택 액션용)
flowSelectedData?: any[];
flowSelectedStepId?: number | null;
@ -200,6 +202,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
onSelectedRowsChange,
sortBy, // 🆕 정렬 컬럼
sortOrder, // 🆕 정렬 방향
tableDisplayData, // 🆕 화면 표시 데이터
flowSelectedData,
flowSelectedStepId,
onFlowSelectedDataChange,
@ -290,6 +293,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
// 테이블 정렬 정보 전달
sortBy,
sortOrder,
tableDisplayData, // 🆕 화면 표시 데이터
// 플로우 선택된 데이터 정보 전달
flowSelectedData,
flowSelectedStepId,

View File

@ -47,6 +47,7 @@ export interface ButtonPrimaryComponentProps extends ComponentRendererProps {
sortBy?: string;
sortOrder?: "asc" | "desc";
columnOrder?: string[];
tableDisplayData?: any[]; // 화면에 표시된 데이터 (컬럼 순서 포함)
// 플로우 선택된 데이터 정보 (플로우 위젯 선택 액션용)
flowSelectedData?: any[];
@ -82,6 +83,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
sortBy, // 🆕 정렬 컬럼
sortOrder, // 🆕 정렬 방향
columnOrder, // 🆕 컬럼 순서
tableDisplayData, // 🆕 화면에 표시된 데이터
selectedRows,
selectedRowsData,
flowSelectedData,
@ -417,6 +419,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
sortBy, // 🆕 정렬 컬럼
sortOrder, // 🆕 정렬 방향
columnOrder, // 🆕 컬럼 순서
tableDisplayData, // 🆕 화면에 표시된 데이터
// 플로우 선택된 데이터 정보 추가
flowSelectedData,
flowSelectedStepId,

View File

@ -25,6 +25,7 @@ import {
import { Checkbox } from "@/components/ui/checkbox";
import { cn } from "@/lib/utils";
import { toast } from "sonner";
import { tableDisplayStore } from "@/stores/tableDisplayStore";
import {
Dialog,
DialogContent,
@ -139,7 +140,7 @@ export interface TableListComponentProps {
onClose?: () => void;
screenId?: string;
userId?: string; // 사용자 ID (컬럼 순서 저장용)
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[]) => void;
onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[], sortBy?: string, sortOrder?: "asc" | "desc", columnOrder?: string[], tableDisplayData?: any[]) => void;
onConfigChange?: (config: any) => void;
refreshKey?: number;
}
@ -266,6 +267,62 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
const [groupByColumns, setGroupByColumns] = useState<string[]>([]);
const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set());
// 🆕 초기 로드 시 localStorage에서 컬럼 순서 불러오기
useEffect(() => {
if (!tableConfig.selectedTable || !userId) return;
const userKey = userId || 'guest';
const storageKey = `table_column_order_${tableConfig.selectedTable}_${userKey}`;
const savedOrder = localStorage.getItem(storageKey);
if (savedOrder) {
try {
const parsedOrder = JSON.parse(savedOrder);
console.log("📂 localStorage에서 컬럼 순서 불러오기:", { storageKey, columnOrder: parsedOrder });
setColumnOrder(parsedOrder);
// 부모 컴포넌트에 초기 컬럼 순서 전달
if (onSelectedRowsChange && parsedOrder.length > 0) {
console.log("✅ 초기 컬럼 순서 전달:", parsedOrder);
// 초기 데이터도 함께 전달 (컬럼 순서대로 재정렬)
const initialData = data.map((row: any) => {
const reordered: any = {};
parsedOrder.forEach((colName: string) => {
if (colName in row) {
reordered[colName] = row[colName];
}
});
// 나머지 컬럼 추가
Object.keys(row).forEach((key) => {
if (!(key in reordered)) {
reordered[key] = row[key];
}
});
return reordered;
});
console.log("📊 초기 화면 표시 데이터 전달:", { count: initialData.length, firstRow: initialData[0] });
// 전역 저장소에 데이터 저장
if (tableConfig.selectedTable) {
tableDisplayStore.setTableData(
tableConfig.selectedTable,
initialData,
parsedOrder.filter(col => col !== '__checkbox__'),
sortColumn,
sortDirection
);
}
onSelectedRowsChange([], [], sortColumn, sortDirection, parsedOrder, initialData);
}
} catch (error) {
console.error("❌ 컬럼 순서 파싱 실패:", error);
}
}
}, [tableConfig.selectedTable, userId, data.length]); // data.length 추가 (데이터 로드 후 실행)
const { optimizedConvertCode } = useEntityJoinOptimization(columnMeta, {
enableBatchLoading: true,
preloadCommonCodes: true,
@ -499,20 +556,78 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
// 정렬 변경 시 선택 정보와 함께 정렬 정보도 전달
if (onSelectedRowsChange) {
const selectedRowsData = data.filter((row, index) => selectedRows.has(getRowKey(row, index)));
// 1단계: 데이터를 정렬
const sortedData = [...data].sort((a, b) => {
const aVal = a[newSortColumn];
const bVal = b[newSortColumn];
// null/undefined 처리
if (aVal == null && bVal == null) return 0;
if (aVal == null) return 1;
if (bVal == null) return -1;
// 숫자 비교
const aNum = Number(aVal);
const bNum = Number(bVal);
if (!isNaN(aNum) && !isNaN(bNum)) {
return newSortDirection === "desc" ? bNum - aNum : aNum - bNum;
}
// 문자열 비교
const aStr = String(aVal);
const bStr = String(bVal);
const comparison = aStr.localeCompare(bStr);
return newSortDirection === "desc" ? -comparison : comparison;
});
// 2단계: 정렬된 데이터를 컬럼 순서대로 재정렬
const reorderedData = sortedData.map((row: any) => {
const reordered: any = {};
visibleColumns.forEach((col) => {
if (col.columnName in row) {
reordered[col.columnName] = row[col.columnName];
}
});
// 나머지 컬럼 추가
Object.keys(row).forEach((key) => {
if (!(key in reordered)) {
reordered[key] = row[key];
}
});
return reordered;
});
console.log("✅ 정렬 정보 전달:", {
selectedRowsCount: selectedRows.size,
selectedRowsDataCount: selectedRowsData.length,
sortBy: newSortColumn,
sortOrder: newSortDirection,
columnOrder: columnOrder.length > 0 ? columnOrder : undefined
columnOrder: columnOrder.length > 0 ? columnOrder : undefined,
tableDisplayDataCount: reorderedData.length,
firstRowAfterSort: reorderedData[0]?.[newSortColumn],
lastRowAfterSort: reorderedData[reorderedData.length - 1]?.[newSortColumn]
});
onSelectedRowsChange(
Array.from(selectedRows),
selectedRowsData,
newSortColumn,
newSortDirection,
columnOrder.length > 0 ? columnOrder : undefined
columnOrder.length > 0 ? columnOrder : undefined,
reorderedData
);
// 전역 저장소에 정렬된 데이터 저장
if (tableConfig.selectedTable) {
const cleanColumnOrder = (columnOrder.length > 0 ? columnOrder : visibleColumns.map(c => c.columnName)).filter(col => col !== '__checkbox__');
tableDisplayStore.setTableData(
tableConfig.selectedTable,
reorderedData,
cleanColumnOrder,
newSortColumn,
newSortDirection
);
}
} else {
console.warn("⚠️ onSelectedRowsChange 콜백이 없습니다!");
}
@ -653,6 +768,55 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
setColumnOrder(newColumnOrder);
console.log("🔄 columnOrder 상태 업데이트:", newColumnOrder);
// 컬럼 순서 변경을 부모 컴포넌트에 전달 (엑셀 다운로드용)
if (onSelectedRowsChange) {
const selectedRowsData = data.filter((row, index) => selectedRows.has(getRowKey(row, index)));
// 화면에 표시된 데이터를 새로운 컬럼 순서대로 재정렬
const reorderedData = data.map((row: any) => {
const reordered: any = {};
newColumns.forEach((col) => {
if (col.columnName in row) {
reordered[col.columnName] = row[col.columnName];
}
});
// 나머지 컬럼 추가
Object.keys(row).forEach((key) => {
if (!(key in reordered)) {
reordered[key] = row[key];
}
});
return reordered;
});
console.log("✅ 컬럼 순서 변경 정보 전달:", {
columnOrder: newColumnOrder,
sortBy: sortColumn,
sortOrder: sortDirection,
reorderedDataCount: reorderedData.length
});
onSelectedRowsChange(
Array.from(selectedRows),
selectedRowsData,
sortColumn,
sortDirection,
newColumnOrder,
reorderedData
);
// 전역 저장소에 컬럼 순서 변경된 데이터 저장
if (tableConfig.selectedTable) {
const cleanColumnOrder = newColumnOrder.filter(col => col !== '__checkbox__');
tableDisplayStore.setTableData(
tableConfig.selectedTable,
reorderedData,
cleanColumnOrder,
sortColumn,
sortDirection
);
}
}
setDraggedColumnIndex(null);
setDragOverColumnIndex(null);
};
@ -714,6 +878,78 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
return cols.sort((a, b) => (a.order || 0) - (b.order || 0));
}, [tableConfig.columns, tableConfig.checkbox, columnOrder]);
// 🆕 visibleColumns가 변경될 때마다 현재 컬럼 순서를 부모에게 전달
const lastColumnOrderRef = useRef<string>("");
useEffect(() => {
console.log("🔍 [컬럼 순서 전달 useEffect] 실행됨:", {
hasCallback: !!onSelectedRowsChange,
visibleColumnsLength: visibleColumns.length,
visibleColumnsNames: visibleColumns.map(c => c.columnName),
});
if (!onSelectedRowsChange) {
console.warn("⚠️ onSelectedRowsChange 콜백이 없습니다!");
return;
}
if (visibleColumns.length === 0) {
console.warn("⚠️ visibleColumns가 비어있습니다!");
return;
}
const currentColumnOrder = visibleColumns
.map(col => col.columnName)
.filter(name => name !== "__checkbox__"); // 체크박스 컬럼 제외
console.log("🔍 [컬럼 순서] 체크박스 제외 후:", currentColumnOrder);
// 컬럼 순서가 실제로 변경되었을 때만 전달 (무한 루프 방지)
const columnOrderString = currentColumnOrder.join(",");
console.log("🔍 [컬럼 순서] 비교:", {
current: columnOrderString,
last: lastColumnOrderRef.current,
isDifferent: columnOrderString !== lastColumnOrderRef.current,
});
if (columnOrderString === lastColumnOrderRef.current) {
console.log("⏭️ 컬럼 순서 변경 없음, 전달 스킵");
return;
}
lastColumnOrderRef.current = columnOrderString;
console.log("📊 현재 화면 컬럼 순서 전달:", currentColumnOrder);
// 선택된 행 데이터 가져오기
const selectedRowsData = data.filter((row, index) => selectedRows.has(getRowKey(row, index)));
// 화면에 표시된 데이터를 컬럼 순서대로 재정렬
const reorderedData = data.map((row: any) => {
const reordered: any = {};
visibleColumns.forEach((col) => {
if (col.columnName in row) {
reordered[col.columnName] = row[col.columnName];
}
});
// 나머지 컬럼 추가
Object.keys(row).forEach((key) => {
if (!(key in reordered)) {
reordered[key] = row[key];
}
});
return reordered;
});
onSelectedRowsChange(
Array.from(selectedRows),
selectedRowsData,
sortColumn,
sortDirection,
currentColumnOrder,
reorderedData
);
}, [visibleColumns.length, visibleColumns.map(c => c.columnName).join(",")]); // 의존성 단순화
const getColumnWidth = (column: ColumnConfig) => {
if (column.columnName === "__checkbox__") return 50;
if (column.width) return column.width;

View File

@ -1689,6 +1689,17 @@ export class ButtonActionExecutor {
private static async handleExcelDownload(config: ButtonActionConfig, context: ButtonActionContext): Promise<boolean> {
try {
console.log("📥 엑셀 다운로드 시작:", { config, context });
console.log("🔍 context.columnOrder 확인:", {
hasColumnOrder: !!context.columnOrder,
columnOrderLength: context.columnOrder?.length,
columnOrder: context.columnOrder,
});
console.log("🔍 context.tableDisplayData 확인:", {
hasTableDisplayData: !!context.tableDisplayData,
tableDisplayDataLength: context.tableDisplayData?.length,
tableDisplayDataFirstRow: context.tableDisplayData?.[0],
tableDisplayDataColumns: context.tableDisplayData?.[0] ? Object.keys(context.tableDisplayData[0]) : [],
});
// 동적 import로 엑셀 유틸리티 로드
const { exportToExcel } = await import("@/lib/utils/excelExport");
@ -1736,8 +1747,38 @@ export class ButtonActionExecutor {
});
}
}
// 2순위: 테이블 전체 데이터 (API 호출)
// 2순위: 화면 표시 데이터 (컬럼 순서 포함, 정렬 적용됨)
else if (context.tableDisplayData && context.tableDisplayData.length > 0) {
dataToExport = context.tableDisplayData;
console.log("✅ 화면 표시 데이터 사용 (context):", {
count: dataToExport.length,
firstRow: dataToExport[0],
columns: Object.keys(dataToExport[0] || {}),
});
}
// 2.5순위: 전역 저장소에서 화면 표시 데이터 조회
else if (context.tableName) {
const { tableDisplayStore } = await import("@/stores/tableDisplayStore");
const storedData = tableDisplayStore.getTableData(context.tableName);
if (storedData && storedData.data.length > 0) {
dataToExport = storedData.data;
console.log("✅ 화면 표시 데이터 사용 (전역 저장소):", {
tableName: context.tableName,
count: dataToExport.length,
firstRow: dataToExport[0],
lastRow: dataToExport[dataToExport.length - 1],
columns: Object.keys(dataToExport[0] || {}),
columnOrder: storedData.columnOrder,
sortBy: storedData.sortBy,
sortOrder: storedData.sortOrder,
// 정렬 컬럼의 첫/마지막 값 확인
firstSortValue: storedData.sortBy ? dataToExport[0]?.[storedData.sortBy] : undefined,
lastSortValue: storedData.sortBy ? dataToExport[dataToExport.length - 1]?.[storedData.sortBy] : undefined,
});
}
// 3순위: 테이블 전체 데이터 (API 호출)
else {
console.log("🔄 테이블 전체 데이터 조회 중...", context.tableName);
console.log("📊 정렬 정보:", {
sortBy: context.sortBy,
@ -1773,6 +1814,7 @@ export class ButtonActionExecutor {
} catch (error) {
console.error("❌ 테이블 데이터 조회 실패:", error);
}
}
}
// 4순위: 폼 데이터
else if (context.formData && Object.keys(context.formData).length > 0) {
@ -1814,15 +1856,26 @@ export class ButtonActionExecutor {
const sheetName = config.excelSheetName || "Sheet1";
const includeHeaders = config.excelIncludeHeaders !== false;
// 🆕 컬럼 순서 재정렬 (사용자가 드래그앤드롭으로 변경한 순서 적용)
if (context.columnOrder && context.columnOrder.length > 0 && dataToExport.length > 0) {
console.log("🔄 컬럼 순서 재정렬:", context.columnOrder);
// 🆕 컬럼 순서 재정렬 (화면에 표시된 순서대로)
let columnOrder: string[] | undefined = context.columnOrder;
// columnOrder가 없으면 tableDisplayData에서 추출 시도
if (!columnOrder && context.tableDisplayData && context.tableDisplayData.length > 0) {
columnOrder = Object.keys(context.tableDisplayData[0]);
console.log("📊 tableDisplayData에서 컬럼 순서 추출:", columnOrder);
}
if (columnOrder && columnOrder.length > 0 && dataToExport.length > 0) {
console.log("🔄 컬럼 순서 재정렬 시작:", {
columnOrder,
originalColumns: Object.keys(dataToExport[0] || {}),
});
dataToExport = dataToExport.map((row: any) => {
const reorderedRow: any = {};
// 1. columnOrder에 있는 컬럼들을 순서대로 추가
context.columnOrder!.forEach((colName: string) => {
columnOrder!.forEach((colName: string) => {
if (colName in row) {
reorderedRow[colName] = row[colName];
}
@ -1839,9 +1892,15 @@ export class ButtonActionExecutor {
});
console.log("✅ 컬럼 순서 재정렬 완료:", {
originalColumns: Object.keys(dataToExport[0] || {}),
reorderedColumns: Object.keys(dataToExport[0] || {}),
});
} else {
console.log("⏭️ 컬럼 순서 재정렬 스킵:", {
hasColumnOrder: !!columnOrder,
columnOrderLength: columnOrder?.length,
hasTableDisplayData: !!context.tableDisplayData,
dataToExportLength: dataToExport.length,
});
}
console.log("📥 엑셀 다운로드 실행:", {

View File

@ -0,0 +1,110 @@
/**
*
*
*/
interface TableDisplayState {
data: any[];
columnOrder: string[];
sortBy: string | null;
sortOrder: "asc" | "desc";
tableName: string;
}
class TableDisplayStore {
private state: Map<string, TableDisplayState> = new Map();
private listeners: Set<() => void> = new Set();
/**
*
* @param tableName
* @param data
* @param columnOrder
* @param sortBy
* @param sortOrder
*/
setTableData(
tableName: string,
data: any[],
columnOrder: string[],
sortBy: string | null,
sortOrder: "asc" | "desc"
) {
this.state.set(tableName, {
data,
columnOrder,
sortBy,
sortOrder,
tableName,
});
console.log("📦 [TableDisplayStore] 데이터 저장:", {
tableName,
dataCount: data.length,
columnOrderLength: columnOrder.length,
sortBy,
sortOrder,
firstRow: data[0],
});
this.notifyListeners();
}
/**
*
* @param tableName
*/
getTableData(tableName: string): TableDisplayState | undefined {
const state = this.state.get(tableName);
console.log("📤 [TableDisplayStore] 데이터 조회:", {
tableName,
found: !!state,
dataCount: state?.data.length,
});
return state;
}
/**
*
*/
getAllTableData(): Map<string, TableDisplayState> {
return new Map(this.state);
}
/**
*
* @param tableName
*/
clearTableData(tableName: string) {
this.state.delete(tableName);
this.notifyListeners();
}
/**
*
*/
clearAll() {
this.state.clear();
this.notifyListeners();
}
/**
*
*/
subscribe(listener: () => void) {
this.listeners.add(listener);
return () => {
this.listeners.delete(listener);
};
}
private notifyListeners() {
this.listeners.forEach((listener) => listener());
}
}
// 싱글톤 인스턴스
export const tableDisplayStore = new TableDisplayStore();