feat: 테이블 검색 필터 위젯 구현 완료

- TableOptionsContext 기반 테이블 자동 감지 시스템 구현
- 독립 위젯으로 드래그앤드롭 배치 가능
- 3가지 기능: 컬럼 가시성, 필터 설정, 그룹 설정
- FlowWidget, TableList, SplitPanel 등 모든 테이블 컴포넌트 지원
- 유틸리티 카테고리에 등록 (1920×80px)
- 위젯 크기 제어 가이드 룰 파일에 추가
This commit is contained in:
kjs
2025-11-12 10:48:24 +09:00
parent fef2f4a132
commit c6941bc41f
21 changed files with 4284 additions and 757 deletions
@@ -1,6 +1,6 @@
"use client";
import React, { useState, useEffect, useCallback } from "react";
import React, { useState, useEffect, useCallback, useRef } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
@@ -52,6 +52,8 @@ import { FileUpload } from "@/components/screen/widgets/FileUpload";
import { AdvancedSearchFilters } from "./filters/AdvancedSearchFilters";
import { SaveModal } from "./SaveModal";
import { useScreenPreview } from "@/contexts/ScreenPreviewContext";
import { useTableOptions } from "@/contexts/TableOptionsContext";
import { TableFilter, ColumnVisibility } from "@/types/table-options";
// 파일 데이터 타입 정의 (AttachedFileInfo와 호환)
interface FileInfo {
@@ -102,6 +104,8 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
}) => {
const { isPreviewMode } = useScreenPreview(); // 프리뷰 모드 확인
const { user } = useAuth(); // 사용자 정보 가져오기
const { registerTable, unregisterTable } = useTableOptions(); // Context 훅
const [data, setData] = useState<Record<string, any>[]>([]);
const [loading, setLoading] = useState(false);
const [searchValues, setSearchValues] = useState<Record<string, any>>({});
@@ -113,6 +117,11 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
const hasInitializedWidthsRef = useRef(false);
const columnRefs = useRef<Record<string, HTMLTableCellElement | null>>({});
const isResizingRef = useRef(false);
// TableOptions 상태
const [filters, setFilters] = useState<TableFilter[]>([]);
const [grouping, setGrouping] = useState<string[]>([]);
const [columnVisibility, setColumnVisibility] = useState<ColumnVisibility[]>([]);
// SaveModal 상태 (등록/수정 통합)
const [showSaveModal, setShowSaveModal] = useState(false);
@@ -147,6 +156,33 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
// 카테고리 값 매핑 캐시 (컬럼명 -> {코드 -> {라벨, 색상}})
const [categoryMappings, setCategoryMappings] = useState<Record<string, Record<string, { label: string; color?: string }>>>({});
// 테이블 등록 (Context에 등록)
const tableId = `datatable-${component.id}`;
useEffect(() => {
if (!component.tableName || !component.columns) return;
registerTable({
tableId,
label: component.title || "데이터 테이블",
tableName: component.tableName,
columns: component.columns.map((col) => ({
columnName: col.field,
columnLabel: col.label,
inputType: col.inputType || "text",
visible: col.visible !== false,
width: col.width || 150,
sortable: col.sortable,
filterable: col.filterable !== false,
})),
onFilterChange: setFilters,
onGroupChange: setGrouping,
onColumnVisibilityChange: setColumnVisibility,
});
return () => unregisterTable(tableId);
}, [component.id, component.tableName, component.columns, component.title]);
// 공통코드 옵션 가져오기
const loadCodeOptions = useCallback(
async (categoryCode: string) => {