'use client'; import { useState, useEffect } from 'react'; import { flexRender, getCoreRowModel, useReactTable, } from '@tanstack/react-table'; import { fetchFundHistory } from '../api/fund'; import { cachedRequest } from '../lib/cacheRequest'; import FundHistoryNetValueModal from './FundHistoryNetValueModal'; /** * 历史净值表格行:日期、净值、日涨幅(按日期降序,涨红跌绿) */ function buildRows(history) { if (!Array.isArray(history) || history.length === 0) return []; const reversed = [...history].reverse(); return reversed.map((item, i) => { const prev = reversed[i + 1]; let dailyChange = null; if (prev && Number.isFinite(item.value) && Number.isFinite(prev.value) && prev.value !== 0) { dailyChange = ((item.value - prev.value) / prev.value) * 100; } return { date: item.date, netValue: item.value, dailyChange, }; }); } const columns = [ { accessorKey: 'date', header: '日期', cell: (info) => info.getValue(), meta: { align: 'left' }, }, { accessorKey: 'netValue', header: '净值', cell: (info) => { const v = info.getValue(); return v != null && Number.isFinite(v) ? Number(v).toFixed(4) : '—'; }, meta: { align: 'center' }, }, { accessorKey: 'dailyChange', header: '日涨幅', cell: (info) => { const v = info.getValue(); if (v == null || !Number.isFinite(v)) return '—'; const sign = v > 0 ? '+' : ''; const cls = v > 0 ? 'up' : v < 0 ? 'down' : ''; return {sign}{v.toFixed(2)}%; }, meta: { align: 'right' }, }, ]; export default function FundHistoryNetValue({ code, range = '1m', theme }) { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [modalOpen, setModalOpen] = useState(false); useEffect(() => { if (!code) { setData([]); setLoading(false); return; } let active = true; setLoading(true); setError(null); const cacheKey = `fund_history_${code}_${range}`; cachedRequest(() => fetchFundHistory(code, range), cacheKey, { cacheTime: 10 * 60 * 1000 }) .then((res) => { if (active) { setData(buildRows(res || [])); setLoading(false); } }) .catch((err) => { if (active) { setError(err); setData([]); setLoading(false); } }); return () => { active = false; }; }, [code, range]); const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), }); const visibleRows = table.getRowModel().rows.slice(0, 5); if (!code) return null; if (loading) { return (
加载历史净值...
); } if (error || data.length === 0) { return (
{error ? '加载失败' : '暂无历史净值'}
); } return (
{table.getHeaderGroups().map((hg) => ( {hg.headers.map((h) => ( ))} ))} {visibleRows.map((row) => ( {row.getVisibleCells().map((cell) => ( ))} ))}
{flexRender(h.column.columnDef.header, h.getContext())}
{flexRender(cell.column.columnDef.cell, cell.getContext())}
{modalOpen && ( )}
); }