fix: 피벗 ConfigPanel — 컬럼별 area dropdown 폐기, 메타 옵션 8종으로 교체
T4 (3e6bce70d) 의 ④ 피벗 설정이 빌더에서 row/column/data/filter 를 컬럼별
dropdown 으로 미리 정해버려 피벗의 본질 (사용자 자유 분석) 을 흐림. 본체
(FieldPanel / FieldChooser) 가 영역 배치 담당하도록 일관성 정리 (Excel 피벗
패턴).
삭제 — "사번 [row▼] / 사용자ID [row▼] ..." 컬럼별 area dropdown 매핑 67줄
신규 ④ 피벗 설정 — 메타 토글 8종 (CPRow + CPSwitch)
- 차트 표시 (pivotChart.enabled)
- 필드 선택기 (pivotFieldChooser.enabled)
- 행 총계 (pivotTotals.showRowGrandTotals)
- 열 총계 (pivotTotals.showColumnGrandTotals)
- 셀 병합 (pivotStyle.mergeCells)
- 행 교대 색 (pivotStyle.alternateRowColors)
- 엑셀 내보내기 (pivotExportConfig.excel)
- PDF 내보내기 (pivotExportConfig.pdf)
빌더 = "피벗에 어떤 도구/표시를 켤지" 만 결정.
본체 = row/column/data/filter 영역 배치 + drag-and-drop + drilldown + filter
+ chart 등 분석 인터랙션 담당 (이미 T3b 통째 흡수됨).
다른 viewMode (grouped: groupBy / card: cardColumnMapping) 는 본체 분석 UI
가 없으므로 ConfigPanel 이 핵심 — pivot 만 메타 패턴으로 가는 게 맞다
(Codex GO 판정).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -281,73 +281,122 @@ export const InvTableConfigPanel: React.FC<InvTableConfigPanelProps> = ({
|
||||
)}
|
||||
|
||||
{displayMode === "pivot" && (
|
||||
<CPSection title="④ 피벗 설정" desc="row · column · data 영역에 컬럼 배치">
|
||||
{columns.length === 0 ? (
|
||||
<Hint tone="warn">컬럼을 먼저 자동 로드 또는 추가하세요.</Hint>
|
||||
) : (
|
||||
<>
|
||||
<Hint>
|
||||
각 컬럼의 영역을 지정하면 피벗 필드가 생성됩니다. data 영역만 집계 함수가 필요합니다.
|
||||
</Hint>
|
||||
{columns.map((col, idx) => {
|
||||
const fields = current.pivotFields ?? [];
|
||||
const fieldIdx = fields.findIndex((f) => f.field === col.key);
|
||||
const field = fieldIdx >= 0 ? fields[fieldIdx] : undefined;
|
||||
const area = field?.area ?? "none";
|
||||
const summaryType = field?.summaryType ?? "sum";
|
||||
const updateField = (next: Partial<NonNullable<TableConfig["pivotFields"]>[number]> | "remove") => {
|
||||
const list = [...fields];
|
||||
if (next === "remove") {
|
||||
if (fieldIdx >= 0) list.splice(fieldIdx, 1);
|
||||
} else if (fieldIdx >= 0) {
|
||||
list[fieldIdx] = { ...list[fieldIdx], ...next };
|
||||
} else {
|
||||
list.push({
|
||||
field: col.key,
|
||||
caption: col.label || col.key,
|
||||
area: "row",
|
||||
...next,
|
||||
});
|
||||
}
|
||||
patch({ pivotFields: list });
|
||||
};
|
||||
return (
|
||||
<CPRow key={col.key} label={col.label || col.key}>
|
||||
<div style={{ display: "flex", gap: 6, alignItems: "center" }}>
|
||||
<CPSelect
|
||||
value={area}
|
||||
onChange={(v) => {
|
||||
if (v === "none") updateField("remove");
|
||||
else updateField({ area: v as any });
|
||||
}}
|
||||
searchable={false}
|
||||
>
|
||||
<option value="none">없음</option>
|
||||
<option value="row">row</option>
|
||||
<option value="column">column</option>
|
||||
<option value="data">data</option>
|
||||
<option value="filter">filter</option>
|
||||
</CPSelect>
|
||||
{area === "data" && (
|
||||
<CPSelect
|
||||
value={summaryType}
|
||||
onChange={(v) => updateField({ summaryType: v as any })}
|
||||
searchable={false}
|
||||
>
|
||||
<option value="sum">합계</option>
|
||||
<option value="count">개수</option>
|
||||
<option value="avg">평균</option>
|
||||
<option value="min">최소</option>
|
||||
<option value="max">최대</option>
|
||||
<option value="countDistinct">고유 개수</option>
|
||||
</CPSelect>
|
||||
)}
|
||||
</div>
|
||||
</CPRow>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
<CPSection title="④ 피벗 설정" desc="본체 분석 UI에서 사용할 표시 옵션">
|
||||
{/* 피벗 필드 배치는 PivotView 본체의 FieldPanel/FieldChooser가 담당한다. ConfigPanel은 메타 옵션만 관리한다. */}
|
||||
<CPRow label="차트 표시">
|
||||
<CPSwitch
|
||||
value={current.pivotChart?.enabled ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotChart: {
|
||||
type: current.pivotChart?.type ?? "bar",
|
||||
position: current.pivotChart?.position ?? "bottom",
|
||||
...current.pivotChart,
|
||||
enabled: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="필드 선택기">
|
||||
<CPSwitch
|
||||
value={current.pivotFieldChooser?.enabled ?? true}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotFieldChooser: {
|
||||
...current.pivotFieldChooser,
|
||||
enabled: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="행 총계">
|
||||
<CPSwitch
|
||||
value={current.pivotTotals?.showRowGrandTotals ?? true}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotTotals: {
|
||||
...current.pivotTotals,
|
||||
showRowGrandTotals: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="열 총계">
|
||||
<CPSwitch
|
||||
value={current.pivotTotals?.showColumnGrandTotals ?? true}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotTotals: {
|
||||
...current.pivotTotals,
|
||||
showColumnGrandTotals: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="셀 병합">
|
||||
<CPSwitch
|
||||
value={current.pivotStyle?.mergeCells ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotStyle: {
|
||||
theme: current.pivotStyle?.theme ?? "default",
|
||||
headerStyle: current.pivotStyle?.headerStyle ?? "default",
|
||||
cellPadding: current.pivotStyle?.cellPadding ?? "normal",
|
||||
borderStyle: current.pivotStyle?.borderStyle ?? "light",
|
||||
...current.pivotStyle,
|
||||
mergeCells: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="행 교대 색">
|
||||
<CPSwitch
|
||||
value={current.pivotStyle?.alternateRowColors ?? true}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotStyle: {
|
||||
theme: current.pivotStyle?.theme ?? "default",
|
||||
headerStyle: current.pivotStyle?.headerStyle ?? "default",
|
||||
cellPadding: current.pivotStyle?.cellPadding ?? "normal",
|
||||
borderStyle: current.pivotStyle?.borderStyle ?? "light",
|
||||
...current.pivotStyle,
|
||||
alternateRowColors: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="엑셀 내보내기">
|
||||
<CPSwitch
|
||||
value={current.pivotExportConfig?.excel ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotExportConfig: {
|
||||
...current.pivotExportConfig,
|
||||
excel: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="PDF 내보내기">
|
||||
<CPSwitch
|
||||
value={current.pivotExportConfig?.pdf ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotExportConfig: {
|
||||
...current.pivotExportConfig,
|
||||
pdf: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
</CPSection>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user