[feat]:[FL-132][P 曲线表格改为折线图展示]

1. 在 web/package.json 中添加 recharts 的必需依赖:react-redux 和 reselect
2. 在 lightning-distribution/page.tsx 中导入 recharts 组件
3. 将"峰值超越概率(P 曲线)"卡片改为折线图 + 可收起表格的展示方式:
   - 折线图为主视图,展示电流阈值(kA)与超越概率的关系
   - Y 轴在 50% 处添加水平参考线标注中值
   - 支持 tooltip 悬浮查看精确数值(阈值、概率、次数)
   - 表格放在 details 元素中,默认收起,用户可展开查看精确数值
4. 图表使用项目已有的 recharts 库,与 lightning-currents 页面保持一致

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
chengkai3
2026-06-15 19:10:20 +08:00
parent d23ac4f74c
commit 13a51bc7f5
2 changed files with 99 additions and 16 deletions
+2
View File
@@ -21,7 +21,9 @@
"next": "16.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-redux": "^9.3.0",
"recharts": "^3.8.1",
"reselect": "^5.2.0",
"tailwind-merge": "^3.5.0"
},
"devDependencies": {
@@ -18,6 +18,16 @@ import {
} from "antd";
import type { ColumnsType } from "antd/es/table";
import { useCallback, useMemo, useRef, useState, type CSSProperties } from "react";
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ReferenceLine,
ResponsiveContainer,
} from "recharts";
import { useAuth } from "@/components/auth-provider";
import { AdminPageLoading } from "@/components/admin-page-loading";
@@ -690,22 +700,93 @@ export default function AdminLightningDistributionPage() {
{distributionPCurve.length === 0 ? (
<Empty description="暂无统计数据" />
) : (
<Table
rowKey={(row) => `${row.threshold_ka}`}
pagination={false}
dataSource={distributionPCurve}
columns={[
{ title: "阈值(kA)", dataIndex: "threshold_ka", width: 140, render: (value: number) => formatNumber(value, 2) },
{
title: "超越概率",
dataIndex: "exceedance_probability",
width: 140,
render: (value: number) => `${(value * 100).toFixed(2)}%`,
},
{ title: "超越次数", dataIndex: "exceedance_count", width: 140 },
]}
size="small"
/>
<Space direction="vertical" size={16} className="w-full">
<div className="w-full" style={{ height: 400 }}>
<ResponsiveContainer width="100%" height="100%">
<LineChart
data={distributionPCurve}
margin={{ top: 10, right: 30, left: 10, bottom: 30 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="threshold_ka"
type="number"
domain={['dataMin', 'dataMax']}
label={{ value: '电流阈值 (kA)', position: 'insideBottom', offset: -10 }}
tickFormatter={(value) => `${value}`}
/>
<YAxis
domain={[0, 1]}
label={{ value: '超越概率', angle: -90, position: 'insideLeft' }}
tickFormatter={(value) => `${(value * 100).toFixed(0)}%`}
/>
<Tooltip
content={({ active, payload }) => {
if (active && payload && payload.length) {
const data = payload[0].payload;
return (
<div className="rounded-md border bg-white p-2 shadow-md">
<p className="text-sm">
<strong>:</strong> {formatNumber(data.threshold_ka, 2)} kA
</p>
<p className="text-sm">
<strong>:</strong> {(data.exceedance_probability * 100).toFixed(2)}%
</p>
<p className="text-sm">
<strong>:</strong> {data.exceedance_count}
</p>
</div>
);
}
return null;
}}
/>
<ReferenceLine
y={0.5}
stroke="#666"
strokeDasharray="5 5"
label={{
value: '50% (中值)',
position: 'right',
fill: '#666',
}}
/>
<Line
type="monotone"
dataKey="exceedance_probability"
stroke="#1890ff"
strokeWidth={2}
dot={{ r: 4 }}
activeDot={{ r: 6 }}
/>
</LineChart>
</ResponsiveContainer>
</div>
<details className="w-full">
<summary className="cursor-pointer select-none text-sm font-medium text-gray-700">
</summary>
<div className="mt-3">
<Table
rowKey={(row) => `${row.threshold_ka}`}
pagination={false}
dataSource={distributionPCurve}
columns={[
{ title: "阈值(kA)", dataIndex: "threshold_ka", width: 140, render: (value: number) => formatNumber(value, 2) },
{
title: "超越概率",
dataIndex: "exceedance_probability",
width: 140,
render: (value: number) => `${(value * 100).toFixed(2)}%`,
},
{ title: "超越次数", dataIndex: "exceedance_count", width: 140 },
]}
size="small"
/>
</div>
</details>
</Space>
)}
</Card>
</Space>