feat(dc/tool-c): Add pivot column ordering and NA handling features

Major features:
1. Pivot transformation enhancements:
   - Add option to keep unselected columns with 3 aggregation methods
   - Maintain original column order after pivot (aligned with source file)
   - Preserve pivot value order (first appearance order)

2. NA handling across 4 core functions:
   - Recode: Support keep/map/drop for NA values
   - Filter: Already supports is_null/not_null operators
   - Binning: Support keep/label/assign for NA values (fix nan display)
   - Conditional: Add is_null/not_null operators

3. UI improvements:
   - Enable column header tooltips with custom header component
   - Add closeable alert for 50-row preview
   - Fix page scrollbar issues

Modified files:
Python: pivot.py, recode.py, binning.py, conditional.py, main.py
Backend: SessionController, QuickActionController, QuickActionService
Frontend: PivotDialog, RecodeDialog, BinningDialog, ConditionalDialog, DataGrid, index

Status: Ready for testing
This commit is contained in:
2025-12-09 14:40:14 +08:00
parent 75ceeb0653
commit f4f1d09837
19 changed files with 2314 additions and 123 deletions

View File

@@ -36,6 +36,7 @@ interface ToolCState {
// UI状态
isLoading: boolean;
isSidebarOpen: boolean;
isAlertClosed: boolean; // ✨ 新增:提示条关闭状态
// ✨ 功能按钮对话框状态
filterDialogVisible: boolean;
@@ -69,6 +70,7 @@ const ToolC = () => {
messages: [],
isLoading: false,
isSidebarOpen: true,
isAlertClosed: false, // ✨ 初始状态:未关闭
filterDialogVisible: false,
recodeDialogVisible: false,
binningDialogVisible: false,
@@ -228,7 +230,7 @@ const ToolC = () => {
// ==================== 渲染 ====================
return (
<div className="h-screen w-screen flex flex-col bg-gradient-to-br from-slate-50 to-slate-100 overflow-hidden">
<div className="h-screen w-screen flex flex-col bg-gradient-to-br from-slate-50 to-slate-100">
{/* 顶部栏 */}
<Header
fileName={state.fileName || '未上传文件'}
@@ -237,10 +239,10 @@ const ToolC = () => {
onToggleSidebar={() => updateState({ isSidebarOpen: !state.isSidebarOpen })}
/>
{/* 主工作区 */}
<div className="flex-1 flex overflow-hidden">
{/* 左侧:表格区域 */}
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
{/* 主工作区 - 移除overflow-hidden让子元素自己处理滚动 */}
<div className="flex-1 flex min-h-0">
{/* 左侧:表格区域 - 独立滚动 */}
<div className="flex-1 flex flex-col min-w-0">
<Toolbar
sessionId={state.sessionId}
onFilterClick={() => updateState({ filterDialogVisible: true })}
@@ -251,23 +253,34 @@ const ToolC = () => {
onComputeClick={() => updateState({ computeDialogVisible: true })}
onPivotClick={() => updateState({ pivotDialogVisible: true })}
/>
<div className="flex-1 p-4 overflow-hidden flex flex-col">
{/* ✨ 优化提示只显示前50行 */}
{state.data.length > 0 && (
<div className="mb-2 px-3 py-2 bg-blue-50 border border-blue-200 rounded-lg flex items-center gap-2 text-sm">
<span className="text-blue-600"></span>
<span className="text-blue-700">
<strong></strong> <strong>50</strong> <strong></strong>
</span>
<div className="flex-1 p-4 flex flex-col min-h-0">
{/* ✨ 优化提示只显示前50行(可关闭) */}
{state.data.length > 0 && !state.isAlertClosed && (
<div className="mb-2 px-3 py-2 bg-blue-50 border border-blue-200 rounded-lg flex items-center justify-between gap-2 text-sm">
<div className="flex items-center gap-2">
<span className="text-blue-600"></span>
<span className="text-blue-700">
<strong></strong> <strong>50</strong> <strong></strong>
</span>
</div>
<button
onClick={() => updateState({ isAlertClosed: true })}
className="text-blue-400 hover:text-blue-600 transition-colors p-1 rounded hover:bg-blue-100"
title="关闭提示"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
</svg>
</button>
</div>
)}
<div className="flex-1 overflow-hidden">
<div className="flex-1 min-h-0">
<DataGrid data={state.data} columns={state.columns} />
</div>
</div>
</div>
{/* 右侧AI 数据清洗助手 */}
{/* 右侧AI 数据清洗助手 - 独立滚动 */}
{state.isSidebarOpen && (
<Sidebar
isOpen={state.isSidebarOpen}