feat: 测试关联板块

This commit is contained in:
hzm
2026-03-17 19:49:33 +08:00
parent b489677d3e
commit fb0dc25341
3 changed files with 171 additions and 5 deletions

View File

@@ -28,8 +28,10 @@ import FitText from './FitText';
import MobileFundCardDrawer from './MobileFundCardDrawer';
import MobileSettingModal from './MobileSettingModal';
import { DragIcon, ExitIcon, SettingsIcon, SortIcon, StarIcon } from './Icons';
import { fetchRelatedSectors } from '@/app/api/fund';
const MOBILE_NON_FROZEN_COLUMN_IDS = [
'relatedSector',
'yesterdayChangePercent',
'estimateChangePercent',
'totalChangePercent',
@@ -39,6 +41,7 @@ const MOBILE_NON_FROZEN_COLUMN_IDS = [
'estimateNav',
];
const MOBILE_COLUMN_HEADERS = {
relatedSector: '关联板块',
latestNav: '最新净值',
estimateNav: '估算净值',
yesterdayChangePercent: '昨日涨幅',
@@ -233,6 +236,8 @@ export default function MobileFundTable({
const defaultVisibility = (() => {
const o = {};
MOBILE_NON_FROZEN_COLUMN_IDS.forEach((id) => { o[id] = true; });
// 新增列:默认隐藏(用户可在表格设置中开启)
o.relatedSector = false;
return o;
})();
@@ -245,7 +250,11 @@ export default function MobileFundTable({
})();
const mobileColumnVisibility = (() => {
const vis = currentGroupMobile?.mobileTableColumnVisibility ?? null;
if (vis && typeof vis === 'object' && Object.keys(vis).length > 0) return vis;
if (vis && typeof vis === 'object' && Object.keys(vis).length > 0) {
const next = { ...vis };
if (next.relatedSector === undefined) next.relatedSector = false;
return next;
}
return defaultVisibility;
})();
@@ -422,6 +431,7 @@ export default function MobileFundTable({
const LAST_COLUMN_EXTRA = 12;
const FALLBACK_WIDTHS = {
fundName: 140,
relatedSector: 120,
latestNav: 64,
estimateNav: 64,
yesterdayChangePercent: 72,
@@ -431,6 +441,49 @@ export default function MobileFundTable({
holdingProfit: 80,
};
const relatedSectorEnabled = mobileColumnVisibility?.relatedSector !== false;
const relatedSectorCacheRef = useRef(new Map());
const [relatedSectorByCode, setRelatedSectorByCode] = useState({});
const fetchRelatedSector = async (code) => fetchRelatedSectors(code);
const runWithConcurrency = async (items, limit, worker) => {
const queue = [...items];
const runners = Array.from({ length: Math.max(1, limit) }, async () => {
while (queue.length) {
const item = queue.shift();
if (item == null) continue;
// eslint-disable-next-line no-await-in-loop
await worker(item);
}
});
await Promise.all(runners);
};
useEffect(() => {
if (!relatedSectorEnabled) return;
if (!Array.isArray(data) || data.length === 0) return;
const codes = Array.from(new Set(data.map((d) => d?.code).filter(Boolean)));
const missing = codes.filter((code) => !relatedSectorCacheRef.current.has(code));
if (missing.length === 0) return;
let cancelled = false;
(async () => {
await runWithConcurrency(missing, 4, async (code) => {
const value = await fetchRelatedSector(code);
relatedSectorCacheRef.current.set(code, value);
if (cancelled) return;
setRelatedSectorByCode((prev) => {
if (prev[code] === value) return prev;
return { ...prev, [code]: value };
});
});
})();
return () => { cancelled = true; };
}, [relatedSectorEnabled, data]);
const columnWidthMap = useMemo(() => {
const visibleNonNameIds = mobileColumnOrder.filter((id) => mobileColumnVisibility[id] !== false);
const nonNameCount = visibleNonNameIds.length;
@@ -456,6 +509,7 @@ export default function MobileFundTable({
MOBILE_NON_FROZEN_COLUMN_IDS.forEach((id) => {
allVisible[id] = true;
});
allVisible.relatedSector = false;
setMobileColumnVisibility(allVisible);
};
const handleToggleMobileColumnVisibility = (columnId, visible) => {
@@ -654,6 +708,17 @@ export default function MobileFundTable({
),
meta: { align: 'left', cellClassName: 'name-cell', width: columnWidthMap.fundName },
},
{
id: 'relatedSector',
header: '关联板块',
cell: (info) => {
const original = info.row.original || {};
const code = original.code;
const value = (code && (relatedSectorByCode?.[code] ?? relatedSectorCacheRef.current.get(code))) || '';
return value || '—';
},
meta: { align: 'left', cellClassName: 'related-sector-cell', width: columnWidthMap.relatedSector ?? 120 },
},
{
accessorKey: 'latestNav',
header: '最新净值',
@@ -834,7 +899,7 @@ export default function MobileFundTable({
meta: { align: 'right', cellClassName: 'holding-cell', width: columnWidthMap.holdingProfit },
},
],
[currentTab, favorites, refreshing, columnWidthMap, showFullFundName, getFundCardProps, isNameSortMode, sortBy]
[currentTab, favorites, refreshing, columnWidthMap, showFullFundName, getFundCardProps, isNameSortMode, sortBy, relatedSectorByCode]
);
const table = useReactTable({