feat:表格列排序

This commit is contained in:
hzm
2026-02-28 23:08:42 +08:00
parent 9e743e29f4
commit e0260f01ec
4 changed files with 396 additions and 9 deletions

View File

@@ -23,7 +23,25 @@ import {
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import ConfirmModal from './ConfirmModal';
import { DragIcon, ExitIcon, ResetIcon, SettingsIcon, StarIcon, TrashIcon } from './Icons';
import PcTableSettingModal from './PcTableSettingModal';
import { DragIcon, ExitIcon, SettingsIcon, StarIcon, TrashIcon } from './Icons';
const NON_FROZEN_COLUMN_IDS = [
'navOrEstimate',
'yesterdayChangePercent',
'estimateChangePercent',
'holdingAmount',
'todayProfit',
'holdingProfit',
];
const COLUMN_HEADERS = {
navOrEstimate: '净值/估值',
yesterdayChangePercent: '昨日涨跌幅',
estimateChangePercent: '估值涨跌幅',
holdingAmount: '持仓金额',
todayProfit: '当日收益',
holdingProfit: '持有收益',
};
const SortableRowContext = createContext({
setActivatorNodeRef: null,
@@ -168,6 +186,69 @@ export default function PcFundTable({
} catch { }
};
const getStoredColumnOrder = () => {
if (typeof window === 'undefined') return null;
try {
const raw = window.localStorage.getItem('customSettings');
if (!raw) return null;
const parsed = JSON.parse(raw);
const order = parsed?.pcTableColumnOrder;
if (!Array.isArray(order) || order.length === 0) return null;
const valid = order.filter((id) => NON_FROZEN_COLUMN_IDS.includes(id));
const missing = NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id));
return [...valid, ...missing];
} catch {
return null;
}
};
const persistColumnOrder = (nextOrder) => {
if (typeof window === 'undefined') return;
try {
const raw = window.localStorage.getItem('customSettings');
const parsed = raw ? JSON.parse(raw) : {};
const nextSettings =
parsed && typeof parsed === 'object'
? { ...parsed, pcTableColumnOrder: nextOrder }
: { pcTableColumnOrder: nextOrder };
window.localStorage.setItem('customSettings', JSON.stringify(nextSettings));
} catch { }
};
const getStoredColumnVisibility = () => {
if (typeof window === 'undefined') return null;
try {
const raw = window.localStorage.getItem('customSettings');
if (!raw) return null;
const parsed = JSON.parse(raw);
const visibility = parsed?.pcTableColumnVisibility;
if (!visibility || typeof visibility !== 'object') return null;
const normalized = {};
NON_FROZEN_COLUMN_IDS.forEach((id) => {
const value = visibility[id];
if (typeof value === 'boolean') {
normalized[id] = value;
}
});
return Object.keys(normalized).length ? normalized : null;
} catch {
return null;
}
};
const persistColumnVisibility = (nextVisibility) => {
if (typeof window === 'undefined') return;
try {
const raw = window.localStorage.getItem('customSettings');
const parsed = raw ? JSON.parse(raw) : {};
const nextSettings =
parsed && typeof parsed === 'object'
? { ...parsed, pcTableColumnVisibility: nextVisibility }
: { pcTableColumnVisibility: nextVisibility };
window.localStorage.setItem('customSettings', JSON.stringify(nextSettings));
} catch { }
};
const [columnSizing, setColumnSizing] = useState(() => {
const stored = getStoredColumnSizing();
if (stored.actions) {
@@ -176,12 +257,45 @@ export default function PcFundTable({
}
return stored;
});
const [columnOrder, setColumnOrder] = useState(() => getStoredColumnOrder() ?? [...NON_FROZEN_COLUMN_IDS]);
const [columnVisibility, setColumnVisibility] = useState(() => {
const stored = getStoredColumnVisibility();
if (stored) return stored;
const allVisible = {};
NON_FROZEN_COLUMN_IDS.forEach((id) => {
allVisible[id] = true;
});
return allVisible;
});
const [settingModalOpen, setSettingModalOpen] = useState(false);
const [resetConfirmOpen, setResetConfirmOpen] = useState(false);
const handleResetSizing = () => {
setColumnSizing({});
persistColumnSizing({});
setResetConfirmOpen(false);
};
const handleResetColumnOrder = () => {
const defaultOrder = [...NON_FROZEN_COLUMN_IDS];
setColumnOrder(defaultOrder);
persistColumnOrder(defaultOrder);
};
const handleResetColumnVisibility = () => {
const allVisible = {};
NON_FROZEN_COLUMN_IDS.forEach((id) => {
allVisible[id] = true;
});
setColumnVisibility(allVisible);
persistColumnVisibility(allVisible);
};
const handleToggleColumnVisibility = (columnId, visible) => {
setColumnVisibility((prev = {}) => {
const next = { ...prev, [columnId]: visible };
persistColumnVisibility(next);
return next;
});
};
const onRemoveFundRef = useRef(onRemoveFund);
const onToggleFavoriteRef = useRef(onToggleFavorite);
const onRemoveFromGroupRef = useRef(onRemoveFromGroup);
@@ -463,12 +577,12 @@ export default function PcFundTable({
className="icon-button"
onClick={(e) => {
e.stopPropagation?.();
setResetConfirmOpen(true);
setSettingModalOpen(true);
}}
title="重置列宽"
title="个性化设置"
style={{ border: 'none', width: '24px', height: '24px', backgroundColor: 'transparent', color: 'var(--text)' }}
>
<ResetIcon width="14" height="14" />
<SettingsIcon width="14" height="14" />
</button>
</div>
),
@@ -531,6 +645,22 @@ export default function PcFundTable({
},
state: {
columnSizing,
columnOrder,
columnVisibility,
},
onColumnOrderChange: (updater) => {
setColumnOrder((prev) => {
const next = typeof updater === 'function' ? updater(prev) : prev;
persistColumnOrder(next);
return next;
});
},
onColumnVisibilityChange: (updater) => {
setColumnVisibility((prev = {}) => {
const next = typeof updater === 'function' ? updater(prev) : (updater || {});
persistColumnVisibility(next);
return next;
});
},
initialState: {
columnPinning: {
@@ -752,6 +882,20 @@ export default function PcFundTable({
confirmText="重置"
/>
)}
<PcTableSettingModal
open={settingModalOpen}
onClose={() => setSettingModalOpen(false)}
columns={columnOrder.map((id) => ({ id, header: COLUMN_HEADERS[id] ?? id }))}
onColumnReorder={(newOrder) => {
setColumnOrder(newOrder);
persistColumnOrder(newOrder);
}}
columnVisibility={columnVisibility}
onToggleColumnVisibility={handleToggleColumnVisibility}
onResetColumnOrder={handleResetColumnOrder}
onResetColumnVisibility={handleResetColumnVisibility}
onResetSizing={() => setResetConfirmOpen(true)}
/>
</div>
);
}