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