feat:分组下个性化数据独立

This commit is contained in:
hzm
2026-03-01 21:03:42 +08:00
parent 8bcffffaa7
commit 92d22b0bef
4 changed files with 265 additions and 195 deletions

View File

@@ -141,78 +141,112 @@ export default function MobileFundTable({
setActiveId(null); setActiveId(null);
}; };
const getStoredMobileColumnOrder = () => { const groupKey = currentTab ?? 'all';
if (typeof window === 'undefined') return null;
const getCustomSettingsWithMigration = () => {
if (typeof window === 'undefined') return {};
try { try {
const raw = window.localStorage.getItem('customSettings'); const raw = window.localStorage.getItem('customSettings');
if (!raw) return null; const parsed = raw ? JSON.parse(raw) : {};
const parsed = JSON.parse(raw); if (!parsed || typeof parsed !== 'object') return {};
const order = parsed?.mobileTableColumnOrder; if (parsed.pcTableColumnOrder != null || parsed.pcTableColumnVisibility != null || parsed.pcTableColumns != null || parsed.mobileTableColumnOrder != null || parsed.mobileTableColumnVisibility != null) {
if (!Array.isArray(order) || order.length === 0) return null; const all = {
...(parsed.all && typeof parsed.all === 'object' ? parsed.all : {}),
pcTableColumnOrder: parsed.pcTableColumnOrder,
pcTableColumnVisibility: parsed.pcTableColumnVisibility,
pcTableColumns: parsed.pcTableColumns,
mobileTableColumnOrder: parsed.mobileTableColumnOrder,
mobileTableColumnVisibility: parsed.mobileTableColumnVisibility,
};
delete parsed.pcTableColumnOrder;
delete parsed.pcTableColumnVisibility;
delete parsed.pcTableColumns;
delete parsed.mobileTableColumnOrder;
delete parsed.mobileTableColumnVisibility;
parsed.all = all;
window.localStorage.setItem('customSettings', JSON.stringify(parsed));
}
return parsed;
} catch {
return {};
}
};
const getInitialMobileConfigByGroup = () => {
const parsed = getCustomSettingsWithMigration();
const byGroup = {};
Object.keys(parsed).forEach((k) => {
if (k === 'pcContainerWidth') return;
const group = parsed[k];
if (!group || typeof group !== 'object') return;
const order = Array.isArray(group.mobileTableColumnOrder) && group.mobileTableColumnOrder.length > 0
? group.mobileTableColumnOrder
: null;
const visibility = group.mobileTableColumnVisibility && typeof group.mobileTableColumnVisibility === 'object'
? group.mobileTableColumnVisibility
: null;
byGroup[k] = {
mobileTableColumnOrder: order ? (() => {
const valid = order.filter((id) => MOBILE_NON_FROZEN_COLUMN_IDS.includes(id)); const valid = order.filter((id) => MOBILE_NON_FROZEN_COLUMN_IDS.includes(id));
const missing = MOBILE_NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id)); const missing = MOBILE_NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id));
return [...valid, ...missing]; return [...valid, ...missing];
} catch { })() : null,
return null; mobileTableColumnVisibility: visibility,
}
}; };
const persistMobileColumnOrder = (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, mobileTableColumnOrder: nextOrder }
: { mobileTableColumnOrder: nextOrder };
window.localStorage.setItem('customSettings', JSON.stringify(nextSettings));
onCustomSettingsChange?.();
} catch {}
};
const getStoredMobileColumnVisibility = () => {
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?.mobileTableColumnVisibility;
if (!visibility || typeof visibility !== 'object') return null;
const normalized = {};
MOBILE_NON_FROZEN_COLUMN_IDS.forEach((id) => {
const value = visibility[id];
if (typeof value === 'boolean') normalized[id] = value;
}); });
return Object.keys(normalized).length ? normalized : null; return byGroup;
} catch {
return null;
}
}; };
const persistMobileColumnVisibility = (nextVisibility) => {
const [configByGroup, setConfigByGroup] = useState(getInitialMobileConfigByGroup);
const currentGroupMobile = configByGroup[groupKey];
const defaultOrder = [...MOBILE_NON_FROZEN_COLUMN_IDS];
const defaultVisibility = (() => {
const o = {};
MOBILE_NON_FROZEN_COLUMN_IDS.forEach((id) => { o[id] = true; });
return o;
})();
const mobileColumnOrder = (() => {
const order = currentGroupMobile?.mobileTableColumnOrder ?? defaultOrder;
if (!Array.isArray(order) || order.length === 0) return [...MOBILE_NON_FROZEN_COLUMN_IDS];
const valid = order.filter((id) => MOBILE_NON_FROZEN_COLUMN_IDS.includes(id));
const missing = MOBILE_NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id));
return [...valid, ...missing];
})();
const mobileColumnVisibility = (() => {
const vis = currentGroupMobile?.mobileTableColumnVisibility ?? null;
if (vis && typeof vis === 'object' && Object.keys(vis).length > 0) return vis;
return defaultVisibility;
})();
const persistMobileGroupConfig = (updates) => {
if (typeof window === 'undefined') return; if (typeof window === 'undefined') return;
try { try {
const raw = window.localStorage.getItem('customSettings'); const raw = window.localStorage.getItem('customSettings');
const parsed = raw ? JSON.parse(raw) : {}; const parsed = raw ? JSON.parse(raw) : {};
const nextSettings = const group = parsed[groupKey] && typeof parsed[groupKey] === 'object' ? { ...parsed[groupKey] } : {};
parsed && typeof parsed === 'object' if (updates.mobileTableColumnOrder !== undefined) group.mobileTableColumnOrder = updates.mobileTableColumnOrder;
? { ...parsed, mobileTableColumnVisibility: nextVisibility } if (updates.mobileTableColumnVisibility !== undefined) group.mobileTableColumnVisibility = updates.mobileTableColumnVisibility;
: { mobileTableColumnVisibility: nextVisibility }; parsed[groupKey] = group;
window.localStorage.setItem('customSettings', JSON.stringify(nextSettings)); window.localStorage.setItem('customSettings', JSON.stringify(parsed));
setConfigByGroup((prev) => ({ ...prev, [groupKey]: { ...prev[groupKey], ...updates } }));
onCustomSettingsChange?.(); onCustomSettingsChange?.();
} catch {} } catch {}
}; };
const [mobileColumnOrder, setMobileColumnOrder] = useState( const setMobileColumnOrder = (nextOrderOrUpdater) => {
() => getStoredMobileColumnOrder() ?? [...MOBILE_NON_FROZEN_COLUMN_IDS] const next = typeof nextOrderOrUpdater === 'function'
); ? nextOrderOrUpdater(mobileColumnOrder)
const [mobileColumnVisibility, setMobileColumnVisibility] = useState(() => { : nextOrderOrUpdater;
const stored = getStoredMobileColumnVisibility(); persistMobileGroupConfig({ mobileTableColumnOrder: next });
if (stored) return stored; };
const allVisible = {}; const setMobileColumnVisibility = (nextOrUpdater) => {
MOBILE_NON_FROZEN_COLUMN_IDS.forEach((id) => { const next = typeof nextOrUpdater === 'function'
allVisible[id] = true; ? nextOrUpdater(mobileColumnVisibility)
}); : nextOrUpdater;
return allVisible; persistMobileGroupConfig({ mobileTableColumnVisibility: next });
}); };
const [settingModalOpen, setSettingModalOpen] = useState(false); const [settingModalOpen, setSettingModalOpen] = useState(false);
const tableContainerRef = useRef(null); const tableContainerRef = useRef(null);
const [tableContainerWidth, setTableContainerWidth] = useState(0); const [tableContainerWidth, setTableContainerWidth] = useState(0);
@@ -258,9 +292,7 @@ export default function MobileFundTable({
}, [tableContainerWidth, mobileColumnOrder, mobileColumnVisibility]); }, [tableContainerWidth, mobileColumnOrder, mobileColumnVisibility]);
const handleResetMobileColumnOrder = () => { const handleResetMobileColumnOrder = () => {
const defaultOrder = [...MOBILE_NON_FROZEN_COLUMN_IDS]; setMobileColumnOrder([...MOBILE_NON_FROZEN_COLUMN_IDS]);
setMobileColumnOrder(defaultOrder);
persistMobileColumnOrder(defaultOrder);
}; };
const handleResetMobileColumnVisibility = () => { const handleResetMobileColumnVisibility = () => {
const allVisible = {}; const allVisible = {};
@@ -268,14 +300,9 @@ export default function MobileFundTable({
allVisible[id] = true; allVisible[id] = true;
}); });
setMobileColumnVisibility(allVisible); setMobileColumnVisibility(allVisible);
persistMobileColumnVisibility(allVisible);
}; };
const handleToggleMobileColumnVisibility = (columnId, visible) => { const handleToggleMobileColumnVisibility = (columnId, visible) => {
setMobileColumnVisibility((prev = {}) => { setMobileColumnVisibility((prev = {}) => ({ ...prev, [columnId]: visible }));
const next = { ...prev, [columnId]: visible };
persistMobileColumnVisibility(next);
return next;
});
}; };
// 移动端名称列:无拖拽把手,长按整行触发排序 // 移动端名称列:无拖拽把手,长按整行触发排序
@@ -298,6 +325,7 @@ export default function MobileFundTable({
onRemoveFromGroupRef.current?.(original); onRemoveFromGroupRef.current?.(original);
}} }}
title="从当前分组移除" title="从当前分组移除"
style={{ backgroundColor: 'transparent'}}
> >
<ExitIcon width="18" height="18" style={{ transform: 'rotate(180deg)' }} /> <ExitIcon width="18" height="18" style={{ transform: 'rotate(180deg)' }} />
</button> </button>
@@ -309,6 +337,7 @@ export default function MobileFundTable({
onToggleFavoriteRef.current?.(original); onToggleFavoriteRef.current?.(original);
}} }}
title={isFavorites ? '取消自选' : '添加自选'} title={isFavorites ? '取消自选' : '添加自选'}
style={{ backgroundColor: 'transparent'}}
> >
<StarIcon width="18" height="18" filled={isFavorites} /> <StarIcon width="18" height="18" filled={isFavorites} />
</button> </button>
@@ -538,7 +567,6 @@ export default function MobileFundTable({
const newNonFrozen = next.filter((id) => id !== 'fundName'); const newNonFrozen = next.filter((id) => id !== 'fundName');
if (newNonFrozen.length) { if (newNonFrozen.length) {
setMobileColumnOrder(newNonFrozen); setMobileColumnOrder(newNonFrozen);
persistMobileColumnOrder(newNonFrozen);
} }
}, },
onColumnVisibilityChange: (updater) => { onColumnVisibilityChange: (updater) => {
@@ -546,7 +574,6 @@ export default function MobileFundTable({
const rest = { ...next }; const rest = { ...next };
delete rest.fundName; delete rest.fundName;
setMobileColumnVisibility(rest); setMobileColumnVisibility(rest);
persistMobileColumnVisibility(rest);
}, },
initialState: { initialState: {
columnPinning: { columnPinning: {
@@ -738,7 +765,6 @@ export default function MobileFundTable({
columnVisibility={mobileColumnVisibility} columnVisibility={mobileColumnVisibility}
onColumnReorder={(newOrder) => { onColumnReorder={(newOrder) => {
setMobileColumnOrder(newOrder); setMobileColumnOrder(newOrder);
persistMobileColumnOrder(newOrder);
}} }}
onToggleColumnVisibility={handleToggleMobileColumnVisibility} onToggleColumnVisibility={handleToggleMobileColumnVisibility}
onResetColumnOrder={handleResetMobileColumnOrder} onResetColumnOrder={handleResetMobileColumnOrder}

View File

@@ -161,131 +161,160 @@ export default function PcFundTable({
} }
setActiveId(null); setActiveId(null);
}; };
const getStoredColumnSizing = () => { const groupKey = currentTab ?? 'all';
const getCustomSettingsWithMigration = () => {
if (typeof window === 'undefined') return {}; if (typeof window === 'undefined') return {};
try { try {
const raw = window.localStorage.getItem('customSettings'); const raw = window.localStorage.getItem('customSettings');
if (!raw) return {}; const parsed = raw ? JSON.parse(raw) : {};
const parsed = JSON.parse(raw); if (!parsed || typeof parsed !== 'object') return {};
const sizing = parsed?.pcTableColumns; if (parsed.pcTableColumnOrder != null || parsed.pcTableColumnVisibility != null || parsed.pcTableColumns != null || parsed.mobileTableColumnOrder != null || parsed.mobileTableColumnVisibility != null) {
if (!sizing || typeof sizing !== 'object') return {}; const all = {
return Object.fromEntries( ...(parsed.all && typeof parsed.all === 'object' ? parsed.all : {}),
Object.entries(sizing).filter(([, value]) => Number.isFinite(value)), pcTableColumnOrder: parsed.pcTableColumnOrder,
); pcTableColumnVisibility: parsed.pcTableColumnVisibility,
pcTableColumns: parsed.pcTableColumns,
mobileTableColumnOrder: parsed.mobileTableColumnOrder,
mobileTableColumnVisibility: parsed.mobileTableColumnVisibility,
};
delete parsed.pcTableColumnOrder;
delete parsed.pcTableColumnVisibility;
delete parsed.pcTableColumns;
delete parsed.mobileTableColumnOrder;
delete parsed.mobileTableColumnVisibility;
parsed.all = all;
window.localStorage.setItem('customSettings', JSON.stringify(parsed));
}
return parsed;
} catch { } catch {
return {}; return {};
} }
}; };
const persistColumnSizing = (nextSizing) => { const buildPcConfigFromGroup = (group) => {
if (typeof window === 'undefined') return; if (!group || typeof group !== 'object') return null;
try { const sizing = group.pcTableColumns;
const raw = window.localStorage.getItem('customSettings'); const sizingObj = sizing && typeof sizing === 'object'
const parsed = raw ? JSON.parse(raw) : {}; ? Object.fromEntries(Object.entries(sizing).filter(([, v]) => Number.isFinite(v)))
const nextSettings = : {};
parsed && typeof parsed === 'object' if (sizingObj.actions) {
? { ...parsed, pcTableColumns: nextSizing } const { actions, ...rest } = sizingObj;
: { pcTableColumns: nextSizing }; Object.assign(sizingObj, rest);
window.localStorage.setItem('customSettings', JSON.stringify(nextSettings)); delete sizingObj.actions;
onCustomSettingsChange?.(); }
} catch { } const order = Array.isArray(group.pcTableColumnOrder) && group.pcTableColumnOrder.length > 0
? group.pcTableColumnOrder
: null;
const visibility = group.pcTableColumnVisibility && typeof group.pcTableColumnVisibility === 'object'
? group.pcTableColumnVisibility
: null;
return { sizing: sizingObj, order, visibility };
}; };
const getStoredColumnOrder = () => { const getDefaultPcGroupConfig = () => ({
if (typeof window === 'undefined') return null; order: [...NON_FROZEN_COLUMN_IDS],
try { visibility: null,
const raw = window.localStorage.getItem('customSettings'); sizing: {},
if (!raw) return null; });
const parsed = JSON.parse(raw);
const order = parsed?.pcTableColumnOrder; const getInitialConfigByGroup = () => {
if (!Array.isArray(order) || order.length === 0) return null; const parsed = getCustomSettingsWithMigration();
const byGroup = {};
Object.keys(parsed).forEach((k) => {
if (k === 'pcContainerWidth') return;
const group = parsed[k];
const pc = buildPcConfigFromGroup(group);
if (pc) {
byGroup[k] = {
pcTableColumnOrder: pc.order ? (() => {
const valid = pc.order.filter((id) => NON_FROZEN_COLUMN_IDS.includes(id));
const missing = NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id));
return [...valid, ...missing];
})() : null,
pcTableColumnVisibility: pc.visibility,
pcTableColumns: Object.keys(pc.sizing).length ? pc.sizing : null,
};
}
});
return byGroup;
};
const [configByGroup, setConfigByGroup] = useState(getInitialConfigByGroup);
const currentGroupPc = configByGroup[groupKey];
const defaultPc = getDefaultPcGroupConfig();
const columnOrder = (() => {
const order = currentGroupPc?.pcTableColumnOrder ?? defaultPc.order;
if (!Array.isArray(order) || order.length === 0) return [...NON_FROZEN_COLUMN_IDS];
const valid = order.filter((id) => NON_FROZEN_COLUMN_IDS.includes(id)); const valid = order.filter((id) => NON_FROZEN_COLUMN_IDS.includes(id));
const missing = NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id)); const missing = NON_FROZEN_COLUMN_IDS.filter((id) => !valid.includes(id));
return [...valid, ...missing]; return [...valid, ...missing];
} catch { })();
return null; const columnVisibility = (() => {
} const vis = currentGroupPc?.pcTableColumnVisibility ?? null;
}; if (vis && typeof vis === 'object' && Object.keys(vis).length > 0) return vis;
const allVisible = {};
const persistColumnOrder = (nextOrder) => { NON_FROZEN_COLUMN_IDS.forEach((id) => { allVisible[id] = true; });
if (typeof window === 'undefined') return; return allVisible;
try { })();
const raw = window.localStorage.getItem('customSettings'); const columnSizing = (() => {
const parsed = raw ? JSON.parse(raw) : {}; const s = currentGroupPc?.pcTableColumns;
const nextSettings = if (s && typeof s === 'object') {
parsed && typeof parsed === 'object' const out = Object.fromEntries(Object.entries(s).filter(([, v]) => Number.isFinite(v)));
? { ...parsed, pcTableColumnOrder: nextOrder } if (out.actions) {
: { pcTableColumnOrder: nextOrder }; const { actions, ...rest } = out;
window.localStorage.setItem('customSettings', JSON.stringify(nextSettings));
onCustomSettingsChange?.();
} 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));
onCustomSettingsChange?.();
} catch { }
};
const [columnSizing, setColumnSizing] = useState(() => {
const stored = getStoredColumnSizing();
if (stored.actions) {
const { actions, ...rest } = stored;
return rest; return rest;
} }
return stored; return out;
}); }
const [columnOrder, setColumnOrder] = useState(() => getStoredColumnOrder() ?? [...NON_FROZEN_COLUMN_IDS]); return {};
const [columnVisibility, setColumnVisibility] = useState(() => { })();
const stored = getStoredColumnVisibility();
if (stored) return stored; const persistPcGroupConfig = (updates) => {
const allVisible = {}; if (typeof window === 'undefined') return;
NON_FROZEN_COLUMN_IDS.forEach((id) => { try {
allVisible[id] = true; const raw = window.localStorage.getItem('customSettings');
}); const parsed = raw ? JSON.parse(raw) : {};
return allVisible; const group = parsed[groupKey] && typeof parsed[groupKey] === 'object' ? { ...parsed[groupKey] } : {};
}); if (updates.pcTableColumnOrder !== undefined) group.pcTableColumnOrder = updates.pcTableColumnOrder;
if (updates.pcTableColumnVisibility !== undefined) group.pcTableColumnVisibility = updates.pcTableColumnVisibility;
if (updates.pcTableColumns !== undefined) group.pcTableColumns = updates.pcTableColumns;
parsed[groupKey] = group;
window.localStorage.setItem('customSettings', JSON.stringify(parsed));
setConfigByGroup((prev) => ({ ...prev, [groupKey]: { ...prev[groupKey], ...updates } }));
onCustomSettingsChange?.();
} catch { }
};
const setColumnOrder = (nextOrderOrUpdater) => {
const next = typeof nextOrderOrUpdater === 'function'
? nextOrderOrUpdater(columnOrder)
: nextOrderOrUpdater;
persistPcGroupConfig({ pcTableColumnOrder: next });
};
const setColumnVisibility = (nextOrUpdater) => {
const next = typeof nextOrUpdater === 'function'
? nextOrUpdater(columnVisibility)
: nextOrUpdater;
persistPcGroupConfig({ pcTableColumnVisibility: next });
};
const setColumnSizing = (nextOrUpdater) => {
const next = typeof nextOrUpdater === 'function'
? nextOrUpdater(columnSizing)
: nextOrUpdater;
const { actions, ...rest } = next || {};
persistPcGroupConfig({ pcTableColumns: rest || {} });
};
const [settingModalOpen, setSettingModalOpen] = useState(false); const [settingModalOpen, setSettingModalOpen] = useState(false);
const [resetConfirmOpen, setResetConfirmOpen] = useState(false); const [resetConfirmOpen, setResetConfirmOpen] = useState(false);
const handleResetSizing = () => { const handleResetSizing = () => {
setColumnSizing({}); setColumnSizing({});
persistColumnSizing({});
setResetConfirmOpen(false); setResetConfirmOpen(false);
}; };
const handleResetColumnOrder = () => { const handleResetColumnOrder = () => {
const defaultOrder = [...NON_FROZEN_COLUMN_IDS]; setColumnOrder([...NON_FROZEN_COLUMN_IDS]);
setColumnOrder(defaultOrder);
persistColumnOrder(defaultOrder);
}; };
const handleResetColumnVisibility = () => { const handleResetColumnVisibility = () => {
@@ -294,14 +323,9 @@ export default function PcFundTable({
allVisible[id] = true; allVisible[id] = true;
}); });
setColumnVisibility(allVisible); setColumnVisibility(allVisible);
persistColumnVisibility(allVisible);
}; };
const handleToggleColumnVisibility = (columnId, visible) => { const handleToggleColumnVisibility = (columnId, visible) => {
setColumnVisibility((prev = {}) => { setColumnVisibility((prev = {}) => ({ ...prev, [columnId]: visible }));
const next = { ...prev, [columnId]: visible };
persistColumnVisibility(next);
return next;
});
}; };
const onRemoveFundRef = useRef(onRemoveFund); const onRemoveFundRef = useRef(onRemoveFund);
const onToggleFavoriteRef = useRef(onToggleFavorite); const onToggleFavoriteRef = useRef(onToggleFavorite);
@@ -350,6 +374,7 @@ export default function PcFundTable({
onRemoveFromGroupRef.current?.(original); onRemoveFromGroupRef.current?.(original);
}} }}
title="从小分组移除" title="从小分组移除"
style={{ backgroundColor: 'transparent'}}
> >
<ExitIcon width="18" height="18" style={{ transform: 'rotate(180deg)' }} /> <ExitIcon width="18" height="18" style={{ transform: 'rotate(180deg)' }} />
</button> </button>
@@ -676,7 +701,6 @@ export default function PcFundTable({
setColumnSizing((prev) => { setColumnSizing((prev) => {
const next = typeof updater === 'function' ? updater(prev) : updater; const next = typeof updater === 'function' ? updater(prev) : updater;
const { actions, ...rest } = next || {}; const { actions, ...rest } = next || {};
persistColumnSizing(rest || {});
return rest || {}; return rest || {};
}); });
}, },
@@ -686,18 +710,10 @@ export default function PcFundTable({
columnVisibility, columnVisibility,
}, },
onColumnOrderChange: (updater) => { onColumnOrderChange: (updater) => {
setColumnOrder((prev) => { setColumnOrder(updater);
const next = typeof updater === 'function' ? updater(prev) : prev;
persistColumnOrder(next);
return next;
});
}, },
onColumnVisibilityChange: (updater) => { onColumnVisibilityChange: (updater) => {
setColumnVisibility((prev = {}) => { setColumnVisibility(updater);
const next = typeof updater === 'function' ? updater(prev) : (updater || {});
persistColumnVisibility(next);
return next;
});
}, },
initialState: { initialState: {
columnPinning: { columnPinning: {
@@ -927,7 +943,6 @@ export default function PcFundTable({
columns={columnOrder.map((id) => ({ id, header: COLUMN_HEADERS[id] ?? id }))} columns={columnOrder.map((id) => ({ id, header: COLUMN_HEADERS[id] ?? id }))}
onColumnReorder={(newOrder) => { onColumnReorder={(newOrder) => {
setColumnOrder(newOrder); setColumnOrder(newOrder);
persistColumnOrder(newOrder);
}} }}
columnVisibility={columnVisibility} columnVisibility={columnVisibility}
onToggleColumnVisibility={handleToggleColumnVisibility} onToggleColumnVisibility={handleToggleColumnVisibility}

View File

@@ -1900,7 +1900,7 @@ input[type="number"] {
.mobile-setting-drawer { .mobile-setting-drawer {
width: 100%; width: 100%;
max-height: 75vh; max-height: 90vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border-radius: 20px 20px 0 0; border-radius: 20px 20px 0 0;

View File

@@ -1751,15 +1751,44 @@ export default function HomePage() {
setGroups(next); setGroups(next);
storageHelper.setItem('groups', JSON.stringify(next)); storageHelper.setItem('groups', JSON.stringify(next));
if (currentTab === id) setCurrentTab('all'); if (currentTab === id) setCurrentTab('all');
try {
const raw = window.localStorage.getItem('customSettings');
const parsed = raw ? JSON.parse(raw) : {};
if (parsed && typeof parsed === 'object' && parsed[id] !== undefined) {
delete parsed[id];
window.localStorage.setItem('customSettings', JSON.stringify(parsed));
triggerCustomSettingsSync();
}
} catch { }
}; };
const handleUpdateGroups = (newGroups) => { const handleUpdateGroups = (newGroups) => {
const removedIds = groups.filter((g) => !newGroups.find((ng) => ng.id === g.id)).map((g) => g.id);
setGroups(newGroups); setGroups(newGroups);
storageHelper.setItem('groups', JSON.stringify(newGroups)); storageHelper.setItem('groups', JSON.stringify(newGroups));
// 如果当前选中的分组被删除了,切换回“全部” // 如果当前选中的分组被删除了,切换回“全部”
if (currentTab !== 'all' && currentTab !== 'fav' && !newGroups.find(g => g.id === currentTab)) { if (currentTab !== 'all' && currentTab !== 'fav' && !newGroups.find(g => g.id === currentTab)) {
setCurrentTab('all'); setCurrentTab('all');
} }
if (removedIds.length > 0) {
try {
const raw = window.localStorage.getItem('customSettings');
const parsed = raw ? JSON.parse(raw) : {};
if (parsed && typeof parsed === 'object') {
let changed = false;
removedIds.forEach((groupId) => {
if (parsed[groupId] !== undefined) {
delete parsed[groupId];
changed = true;
}
});
if (changed) {
window.localStorage.setItem('customSettings', JSON.stringify(parsed));
triggerCustomSettingsSync();
}
}
} catch { }
}
}; };
const handleAddFundsToGroup = (codes) => { const handleAddFundsToGroup = (codes) => {
@@ -3906,7 +3935,7 @@ export default function HomePage() {
style={{ style={{
width: '100%', width: '100%',
height: '48px', height: '48px',
border: '2px dashed rgba(255,255,255,0.1)', border: '2px dashed var(--border)',
background: 'transparent', background: 'transparent',
borderRadius: '12px', borderRadius: '12px',
color: 'var(--muted)', color: 'var(--muted)',
@@ -3926,7 +3955,7 @@ export default function HomePage() {
e.currentTarget.style.background = 'rgba(34, 211, 238, 0.05)'; e.currentTarget.style.background = 'rgba(34, 211, 238, 0.05)';
}} }}
onMouseLeave={(e) => { onMouseLeave={(e) => {
e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)'; e.currentTarget.style.borderColor = 'var(--border)';
e.currentTarget.style.color = 'var(--muted)'; e.currentTarget.style.color = 'var(--muted)';
e.currentTarget.style.background = 'transparent'; e.currentTarget.style.background = 'transparent';
}} }}