feat: merge history into dashboard, remove history nav entry

This commit is contained in:
root 2026-02-27 08:25:11 +00:00
parent eebbfd456c
commit 1a7a77e183
3 changed files with 74 additions and 94 deletions

View File

@ -1,91 +1,5 @@
"use client";
import { useEffect, useState } from "react";
import { HistoryPoint } from "@/lib/api";
import {
LineChart, Line, XAxis, YAxis, Tooltip, Legend,
ResponsiveContainer, ReferenceLine
} from "recharts";
import { redirect } from "next/navigation";
export default function HistoryPage() {
const [btc, setBtc] = useState<HistoryPoint[]>([]);
const [eth, setEth] = useState<HistoryPoint[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/history")
.then((r) => r.json())
.then((d) => { setBtc(d.BTC ?? []); setEth(d.ETH ?? []); setLoading(false); })
.catch(() => setLoading(false));
}, []);
const btcMap = new Map(btc.map((p) => [p.timestamp.slice(0, 13), p.fundingRate * 100]));
const ethMap = new Map(eth.map((p) => [p.timestamp.slice(0, 13), p.fundingRate * 100]));
const allTimes = Array.from(new Set([...btcMap.keys(), ...ethMap.keys()])).sort();
const chartData = allTimes.slice(-42).map((t) => ({
time: t.slice(5).replace("T", " "),
BTC: btcMap.get(t) ?? null,
ETH: ethMap.get(t) ?? null,
}));
const tableData = allTimes.slice().reverse().slice(0, 50).map((t) => ({
time: t.replace("T", " "),
btc: btcMap.get(t),
eth: ethMap.get(t),
}));
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold text-slate-900"></h1>
<p className="text-slate-500 text-sm mt-1">7 BTC / ETH </p>
</div>
{loading ? (
<div className="text-slate-500">...</div>
) : (
<>
<div className="rounded-xl border border-slate-200 bg-white p-6">
<h2 className="text-slate-800 font-semibold mb-4">7</h2>
<ResponsiveContainer width="100%" height={260}>
<LineChart data={chartData} margin={{ top: 4, right: 8, bottom: 4, left: 8 }}>
<XAxis dataKey="time" tick={{ fill: "#64748b", fontSize: 10 }} tickLine={false} interval="preserveStartEnd" />
<YAxis tick={{ fill: "#64748b", fontSize: 10 }} tickLine={false} axisLine={false} tickFormatter={(v) => `${v.toFixed(3)}%`} width={60} />
<Tooltip formatter={(v) => [`${Number(v).toFixed(4)}%`]} contentStyle={{ background: "#1e293b", border: "1px solid #475569", borderRadius: 8 }} />
<Legend wrapperStyle={{ fontSize: 12, color: "#94a3b8" }} />
<ReferenceLine y={0} stroke="#475569" strokeDasharray="4 2" />
<Line type="monotone" dataKey="BTC" stroke="#06b6d4" strokeWidth={1.5} dot={false} connectNulls />
<Line type="monotone" dataKey="ETH" stroke="#8b5cf6" strokeWidth={1.5} dot={false} connectNulls />
</LineChart>
</ResponsiveContainer>
</div>
<div className="rounded-xl border border-slate-200 bg-white overflow-hidden">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-slate-200 bg-slate-800">
<th className="text-left px-4 py-3 text-slate-500 font-medium"></th>
<th className="text-right px-4 py-3 text-blue-600 font-medium">BTC </th>
<th className="text-right px-4 py-3 text-violet-400 font-medium">ETH </th>
</tr>
</thead>
<tbody>
{tableData.map((row, i) => (
<tr key={i} className="border-b border-slate-200/50 hover:bg-slate-50">
<td className="px-4 py-2 text-slate-500 font-mono text-xs">{row.time}</td>
<td className={`px-4 py-2 text-right font-mono text-xs ${row.btc == null ? "text-slate-500" : row.btc >= 0 ? "text-emerald-400" : "text-red-400"}`}>
{row.btc != null ? `${row.btc.toFixed(4)}%` : "--"}
</td>
<td className={`px-4 py-2 text-right font-mono text-xs ${row.eth == null ? "text-slate-500" : row.eth >= 0 ? "text-emerald-400" : "text-red-400"}`}>
{row.eth != null ? `${row.eth.toFixed(4)}%` : "--"}
</td>
</tr>
))}
</tbody>
</table>
</div>
</>
)}
</div>
);
redirect("/");
}

View File

@ -1,10 +1,14 @@
"use client";
import { useEffect, useState, useCallback } from "react";
import { api, RatesResponse, StatsResponse, HistoryResponse } from "@/lib/api";
import { api, RatesResponse, StatsResponse, HistoryResponse, HistoryPoint } from "@/lib/api";
import RateCard from "@/components/RateCard";
import StatsCard from "@/components/StatsCard";
import FundingChart from "@/components/FundingChart";
import {
LineChart, Line, XAxis, YAxis, Tooltip, Legend,
ResponsiveContainer, ReferenceLine
} from "recharts";
export default function Dashboard() {
const [rates, setRates] = useState<RatesResponse | null>(null);
@ -29,9 +33,7 @@ export default function Dashboard() {
const [s, h] = await Promise.all([api.stats(), api.history()]);
setStats(s);
setHistory(h);
} catch {
// stats/history 失败不影响主界面
}
} catch {}
}, []);
useEffect(() => {
@ -42,6 +44,21 @@ export default function Dashboard() {
return () => { clearInterval(rateInterval); clearInterval(slowInterval); };
}, [fetchRates, fetchAll]);
// 历史费率表格数据
const btcMap = new Map((history?.BTC ?? []).map((p: HistoryPoint) => [p.timestamp.slice(0, 13), p.fundingRate * 100]));
const ethMap = new Map((history?.ETH ?? []).map((p: HistoryPoint) => [p.timestamp.slice(0, 13), p.fundingRate * 100]));
const allTimes = Array.from(new Set([...btcMap.keys(), ...ethMap.keys()])).sort();
const historyChartData = allTimes.slice(-42).map((t) => ({
time: t.slice(5).replace("T", " "),
BTC: btcMap.get(t) ?? null,
ETH: ethMap.get(t) ?? null,
}));
const tableData = allTimes.slice().reverse().slice(0, 50).map((t) => ({
time: t.replace("T", " "),
btc: btcMap.get(t),
eth: ethMap.get(t),
}));
return (
<div className="space-y-6">
{/* Header */}
@ -77,7 +94,7 @@ export default function Dashboard() {
</div>
)}
{/* History Chart */}
{/* 7天走势图FundingChart */}
{history && (
<div className="rounded-xl border border-slate-200 bg-white shadow-sm p-6">
<h2 className="text-slate-800 font-semibold mb-4">7</h2>
@ -85,6 +102,55 @@ export default function Dashboard() {
</div>
)}
{/* 历史费率折线图 */}
{allTimes.length > 0 && (
<div className="rounded-xl border border-slate-200 bg-white shadow-sm p-6">
<h2 className="text-slate-800 font-semibold mb-4">78</h2>
<ResponsiveContainer width="100%" height={220}>
<LineChart data={historyChartData} margin={{ top: 4, right: 8, bottom: 4, left: 8 }}>
<XAxis dataKey="time" tick={{ fill: "#94a3b8", fontSize: 10 }} tickLine={false} interval="preserveStartEnd" />
<YAxis tick={{ fill: "#94a3b8", fontSize: 10 }} tickLine={false} axisLine={false} tickFormatter={(v) => `${v.toFixed(3)}%`} width={60} />
<Tooltip formatter={(v) => [`${Number(v).toFixed(4)}%`]} contentStyle={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 8, fontSize: 12 }} />
<Legend wrapperStyle={{ fontSize: 12 }} />
<ReferenceLine y={0} stroke="#94a3b8" strokeDasharray="4 2" />
<Line type="monotone" dataKey="BTC" stroke="#2563eb" strokeWidth={1.5} dot={false} connectNulls />
<Line type="monotone" dataKey="ETH" stroke="#7c3aed" strokeWidth={1.5} dot={false} connectNulls />
</LineChart>
</ResponsiveContainer>
</div>
)}
{/* 历史费率明细表 */}
{tableData.length > 0 && (
<div className="rounded-xl border border-slate-200 bg-white shadow-sm overflow-hidden">
<div className="px-6 py-4 border-b border-slate-100">
<h2 className="text-slate-800 font-semibold">50</h2>
</div>
<table className="w-full text-sm">
<thead>
<tr className="border-b border-slate-200 bg-slate-50">
<th className="text-left px-4 py-3 text-slate-500 font-medium"></th>
<th className="text-right px-4 py-3 text-blue-600 font-medium">BTC </th>
<th className="text-right px-4 py-3 text-violet-600 font-medium">ETH </th>
</tr>
</thead>
<tbody>
{tableData.map((row, i) => (
<tr key={i} className="border-b border-slate-100 hover:bg-slate-50">
<td className="px-4 py-2 text-slate-500 font-mono text-xs">{row.time}</td>
<td className={`px-4 py-2 text-right font-mono text-xs ${row.btc == null ? "text-slate-400" : row.btc >= 0 ? "text-emerald-600" : "text-red-500"}`}>
{row.btc != null ? `${row.btc.toFixed(4)}%` : "--"}
</td>
<td className={`px-4 py-2 text-right font-mono text-xs ${row.eth == null ? "text-slate-400" : row.eth >= 0 ? "text-emerald-600" : "text-red-500"}`}>
{row.eth != null ? `${row.eth.toFixed(4)}%` : "--"}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
{/* Strategy note */}
<div className="rounded-lg border border-blue-100 bg-blue-50 px-5 py-3 text-sm text-slate-600">
<span className="text-blue-600 font-medium"></span>
@ -93,3 +159,4 @@ export default function Dashboard() {
</div>
);
}

View File

@ -6,7 +6,6 @@ const navLinks = [
{ href: "/", label: "仪表盘" },
{ href: "/kline", label: "K线" },
{ href: "/live", label: "实时" },
{ href: "/history", label: "历史" },
{ href: "/signals", label: "信号" },
{ href: "/about", label: "说明" },
];