lhj #369
|
|
@ -384,20 +384,36 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
localStorage.setItem(stateStorageKey, JSON.stringify(stateToSave));
|
||||
}, [fields, pivotState, sortConfig, columnWidths, stateStorageKey]);
|
||||
|
||||
// 상태 복원 (localStorage)
|
||||
// 상태 복원 (localStorage) - 프로덕션 안전성 강화
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
const savedState = localStorage.getItem(stateStorageKey);
|
||||
if (savedState) {
|
||||
try {
|
||||
const parsed = JSON.parse(savedState);
|
||||
if (parsed.fields) setFields(parsed.fields);
|
||||
if (parsed.pivotState) setPivotState(parsed.pivotState);
|
||||
if (parsed.sortConfig) setSortConfig(parsed.sortConfig);
|
||||
if (parsed.columnWidths) setColumnWidths(parsed.columnWidths);
|
||||
} catch (e) {
|
||||
console.warn("피벗 상태 복원 실패:", e);
|
||||
|
||||
try {
|
||||
const savedState = localStorage.getItem(stateStorageKey);
|
||||
if (!savedState) return;
|
||||
|
||||
const parsed = JSON.parse(savedState);
|
||||
|
||||
// 필드 복원 시 유효성 검사 (중요!)
|
||||
if (parsed.fields && Array.isArray(parsed.fields) && parsed.fields.length > 0) {
|
||||
// 저장된 필드가 현재 데이터와 호환되는지 확인
|
||||
const validFields = parsed.fields.filter((f: PivotFieldConfig) =>
|
||||
f && typeof f.field === "string" && typeof f.area === "string"
|
||||
);
|
||||
|
||||
if (validFields.length > 0) {
|
||||
setFields(validFields);
|
||||
}
|
||||
}
|
||||
|
||||
// 나머지 상태 복원
|
||||
if (parsed.pivotState) setPivotState(parsed.pivotState);
|
||||
if (parsed.sortConfig) setSortConfig(parsed.sortConfig);
|
||||
if (parsed.columnWidths) setColumnWidths(parsed.columnWidths);
|
||||
} catch (e) {
|
||||
console.warn("피벗 상태 복원 실패, localStorage 초기화:", e);
|
||||
// 손상된 상태는 제거
|
||||
localStorage.removeItem(stateStorageKey);
|
||||
}
|
||||
}, [stateStorageKey]);
|
||||
|
||||
|
|
@ -512,15 +528,15 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
const visibleFields = fields.filter((f) => f.visible !== false);
|
||||
// FieldChooser에서 이미 필드를 완전히 제거하므로 visible 필터링 불필요
|
||||
// 행, 열, 데이터 영역에 필드가 하나도 없으면 null 반환 (필터는 제외)
|
||||
if (visibleFields.filter((f) => ["row", "column", "data"].includes(f.area)).length === 0) {
|
||||
if (fields.filter((f) => ["row", "column", "data"].includes(f.area)).length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = processPivotData(
|
||||
filteredData,
|
||||
visibleFields,
|
||||
fields,
|
||||
pivotState.expandedRowPaths,
|
||||
pivotState.expandedColumnPaths
|
||||
);
|
||||
|
|
@ -536,32 +552,18 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
});
|
||||
|
||||
return result;
|
||||
}, [
|
||||
filteredData,
|
||||
fields,
|
||||
JSON.stringify(pivotState.expandedRowPaths),
|
||||
JSON.stringify(pivotState.expandedColumnPaths)
|
||||
]);
|
||||
}, [filteredData, fields, pivotState.expandedRowPaths, pivotState.expandedColumnPaths]);
|
||||
|
||||
// 🆕 초기 로드 시 첫 레벨 자동 확장
|
||||
// 초기 로드 시 첫 레벨 자동 확장
|
||||
useEffect(() => {
|
||||
if (pivotResult && pivotResult.flatRows.length > 0 && !isInitialExpanded) {
|
||||
console.log("🔶 피벗 결과 생성됨:", {
|
||||
flatRowsCount: pivotResult.flatRows.length,
|
||||
expandedRowPaths: pivotState.expandedRowPaths.length,
|
||||
isInitialExpanded,
|
||||
});
|
||||
|
||||
// 첫 레벨 행들의 경로 수집 (level 0인 행들)
|
||||
const firstLevelRows = pivotResult.flatRows.filter(row => row.level === 0 && row.hasChildren);
|
||||
|
||||
console.log("🔶 첫 레벨 행 (level 0, hasChildren):", firstLevelRows.map(r => ({ path: r.path, caption: r.caption })));
|
||||
const firstLevelRows = pivotResult.flatRows.filter((row) => row.level === 0 && row.hasChildren);
|
||||
|
||||
// 첫 레벨 행이 있으면 자동 확장
|
||||
if (firstLevelRows.length > 0) {
|
||||
const firstLevelPaths = firstLevelRows.map(row => row.path);
|
||||
console.log("🔶 초기 자동 확장 실행 (한 번만):", firstLevelPaths);
|
||||
setPivotState(prev => ({
|
||||
const firstLevelPaths = firstLevelRows.map((row) => row.path);
|
||||
setPivotState((prev) => ({
|
||||
...prev,
|
||||
expandedRowPaths: firstLevelPaths,
|
||||
}));
|
||||
|
|
@ -725,19 +727,16 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
// 필드 변경
|
||||
const handleFieldsChange = useCallback(
|
||||
(newFields: PivotFieldConfig[]) => {
|
||||
// 🆕 visible: false 필드 제거 (FieldChooser에서 "사용 안함"으로 설정한 필드)
|
||||
const visibleFields = newFields.filter(f => f.visible !== false);
|
||||
|
||||
// FieldChooser에서 이미 필드를 완전히 제거하므로 추가 필터링 불필요
|
||||
console.log("🔷 [handleFieldsChange] 필드 변경:", {
|
||||
totalFields: newFields.length,
|
||||
visibleFields: visibleFields.length,
|
||||
removedFields: newFields.length - visibleFields.length,
|
||||
filterFields: visibleFields.filter(f => f.area === "filter").length,
|
||||
filterFieldNames: visibleFields.filter(f => f.area === "filter").map(f => f.field),
|
||||
filterFields: newFields.filter(f => f.area === "filter").length,
|
||||
filterFieldNames: newFields.filter(f => f.area === "filter").map(f => f.field),
|
||||
rowFields: newFields.filter(f => f.area === "row").length,
|
||||
columnFields: newFields.filter(f => f.area === "column").length,
|
||||
dataFields: newFields.filter(f => f.area === "data").length,
|
||||
});
|
||||
console.log("🔷 [handleFieldsChange] setFields 호출 전");
|
||||
setFields(visibleFields);
|
||||
console.log("🔷 [handleFieldsChange] setFields 호출 후");
|
||||
setFields(newFields);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
|
@ -945,6 +944,8 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
|
||||
// 인쇄 기능 (PDF 내보내기보다 먼저 정의해야 함)
|
||||
const handlePrint = useCallback(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const printContent = tableRef.current;
|
||||
if (!printContent) return;
|
||||
|
||||
|
|
@ -1047,8 +1048,10 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
|
||||
// 상태 초기화 (확장/축소, 정렬, 필터만 초기화, 필드 설정은 유지)
|
||||
const handleResetState = useCallback(() => {
|
||||
// 로컬 스토리지에서 상태 제거
|
||||
localStorage.removeItem(stateStorageKey);
|
||||
// 로컬 스토리지에서 상태 제거 (SSR 보호)
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.removeItem(stateStorageKey);
|
||||
}
|
||||
|
||||
// 확장/축소, 정렬, 필터 상태만 초기화
|
||||
setPivotState({
|
||||
|
|
@ -1061,9 +1064,6 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
setColumnWidths({});
|
||||
setSelectedCell(null);
|
||||
setSelectionRange(null);
|
||||
|
||||
// 🆕 필드 설정은 유지 (initialFields로 되돌리지 않음)
|
||||
console.log("🔷 피벗 상태가 초기화되었습니다 (필드 설정은 유지)");
|
||||
}, [stateStorageKey]);
|
||||
|
||||
// 필드 숨기기/표시 상태
|
||||
|
|
@ -1081,11 +1081,6 @@ export const PivotGridComponent: React.FC<PivotGridProps> = ({
|
|||
});
|
||||
}, []);
|
||||
|
||||
// 숨겨진 필드 제외한 활성 필드들
|
||||
const visibleFields = useMemo(() => {
|
||||
return fields.filter((f) => !hiddenFields.has(f.field));
|
||||
}, [fields, hiddenFields]);
|
||||
|
||||
// 숨겨진 필드 목록
|
||||
const hiddenFieldsList = useMemo(() => {
|
||||
return fields.filter((f) => hiddenFields.has(f.field));
|
||||
|
|
|
|||
Loading…
Reference in New Issue