实时数据页面

main
wangyunfei888 1 month ago
parent e7efc6e4fd
commit 96533b63f1

@ -1,9 +1,9 @@
import React, { useMemo, useState } from 'react';
import { Select, Tree, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { Select, Tree } from 'antd';
import ReactECharts from 'echarts-for-react';
import * as echarts from 'echarts';
import { ReactComponent as Icon1 } from '@/assets/business_basic/icon1.svg';
import { ReactComponent as Icon2 } from '@/assets/business_basic/icon2.svg';
import StandardTable from '@/components/StandardTable';
import styles from './HistoryTrend.less';
const buildingOptions = [
@ -17,6 +17,12 @@ const factoryOptions = [
{ label: '南京油库', value: 'nanjing' },
];
const rangeOptions = [
{ label: '近24小时', value: '24h' },
{ label: '近7天', value: '7d' },
{ label: '近30天', value: '30d' },
];
const rawTreeData = [
{
title: '上海油库',
@ -116,133 +122,152 @@ const formatTreeNodes = data =>
children: item.children ? formatTreeNodes(item.children) : undefined,
}));
const tableColumns = [
{
title: '层级',
dataIndex: 'level',
key: 'level',
width: 110,
align: 'center',
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
width: 120,
align: 'center',
},
{
title: '代码',
dataIndex: 'code',
key: 'code',
align: 'center',
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '最后更新',
dataIndex: 'updatedAt',
key: 'updatedAt',
align: 'center',
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
width: 140,
align: 'center',
render: () => (
<>
<a style={{ marginRight: 12, color: '#006665' }}>查看详情</a>
<a style={{ color: '#2D9E9D' }}>编辑</a>
</>
),
},
];
const timeAxis = ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00'];
const tableDataSource = [
{
id: 1,
level: '工厂',
name: '华东油库',
code: 'CN-EAST-OIL',
type: '原油存储',
status: '已激活',
updatedAt: '2025-10-25 22:30:16',
},
{
id: 2,
level: '罐区',
name: '汽油罐区',
code: 'GASOLINE-AREA',
type: '成品油',
status: '已激活',
updatedAt: '2025-10-25 10:28:14',
},
{
id: 3,
level: '罐区',
name: '柴油罐区',
code: 'DIESEL-AREA',
type: '成品油',
status: '已激活',
updatedAt: '2025-10-23 20:58:24',
},
{
id: 4,
level: '罐组',
name: '92汽油调合罐组',
code: 'G92-GROUP',
type: '调合罐组',
status: '维护中',
updatedAt: '2025-10-23 04:59:13',
},
{
id: 5,
level: '储罐',
name: 'T-101',
code: 'TANK-101',
type: '浮顶罐',
status: '维护中',
updatedAt: '2025-10-22 03:03:13',
},
{
id: 6,
level: '设备',
name: 'LT-101',
code: 'LEVEL-101',
type: '液位计',
status: '已激活',
updatedAt: '2025-10-22 03:03:13',
},
];
const liquidLevelSeries = [79, 18, 76, 45, 36, 69, 43, 74, 48, 53, 55, 21];
const temperatureSeries = [32.2, 31.1, 32.0, 30.6, 30.9, 32.1, 30.7, 32.8, 30.8, 31.7, 31.1, 30.6];
const pressureSeries = [0.116, 0.114, 0.113, 0.112, 0.114, 0.113, 0.116, 0.115, 0.111, 0.114, 0.115, 0.114];
const HistoryTrend = () => {
const [buildingType, setBuildingType] = useState('plant');
const [factory, setFactory] = useState('all');
const [selectedKeys, setSelectedKeys] = useState(['t101']);
const [checkedKeys, setCheckedKeys] = useState(['t101']);
const [levelRange, setLevelRange] = useState('24h');
const [tempRange, setTempRange] = useState('24h');
const treeData = useMemo(() => formatTreeNodes(rawTreeData), []);
const tableData = useMemo(
const levelTrendOption = useMemo(() => {
const areaGradient = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(45, 158, 157, 0.35)' },
{ offset: 1, color: 'rgba(45, 158, 157, 0.02)' },
]);
return {
color: ['#2d9e9d'],
tooltip: {
trigger: 'axis',
backgroundColor: '#0f3030',
borderColor: 'rgba(45, 158, 157, 0.4)',
textStyle: { color: '#dff4f2' },
axisPointer: {
lineStyle: {
color: '#2d9e9d',
},
},
},
legend: {
data: ['液位 (%)'],
right: 20,
top: 10,
icon: 'circle',
textStyle: { color: '#4e5856' },
},
grid: { left: 40, right: 20, top: 50, bottom: 30 },
xAxis: {
type: 'category',
data: timeAxis,
boundaryGap: false,
axisTick: { show: false },
axisLine: { lineStyle: { color: '#d6e5df' } },
axisLabel: { color: '#76807d' },
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: { formatter: '{value}%', color: '#76807d' },
splitLine: { lineStyle: { color: '#e6f1ec' } },
},
series: [
{
name: '液位 (%)',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 8,
lineStyle: { width: 3 },
itemStyle: { color: '#2d9e9d' },
areaStyle: { color: areaGradient },
data: liquidLevelSeries,
},
],
};
}, []);
const temperaturePressureOption = useMemo(
() => ({
list: tableDataSource,
pagination: {
currentPage: 1,
pageSize: 10,
total: tableDataSource.length,
color: ['#2a7b8d', '#c2b453'],
tooltip: {
trigger: 'axis',
backgroundColor: '#0f3030',
borderColor: 'rgba(42, 123, 141, 0.4)',
textStyle: { color: '#dff4f2' },
axisPointer: { type: 'cross', link: [{ xAxisIndex: 'all' }] },
},
legend: {
data: ['温度 (℃)', '压力 (MPa)'],
right: 20,
top: 10,
icon: 'circle',
textStyle: { color: '#4e5856' },
},
grid: { left: 50, right: 50, top: 50, bottom: 30 },
xAxis: [
{
type: 'category',
data: timeAxis,
boundaryGap: false,
axisTick: { show: false },
axisLine: { lineStyle: { color: '#d6e5df' } },
axisLabel: { color: '#76807d' },
},
],
yAxis: [
{
type: 'value',
name: '温度 (℃)',
min: 28,
max: 33,
axisLabel: { formatter: '{value}', color: '#76807d' },
nameTextStyle: { color: '#76807d' },
splitLine: { lineStyle: { color: '#e6f1ec' } },
},
{
type: 'value',
name: '压力 (MPa)',
min: 0.11,
max: 0.12,
position: 'right',
axisLabel: { formatter: '{value}', color: '#76807d' },
nameTextStyle: { color: '#76807d' },
splitLine: { show: false },
},
],
series: [
{
name: '温度 (℃)',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 7,
lineStyle: { width: 3, color: '#2a7b8d' },
itemStyle: { color: '#2a7b8d' },
data: temperatureSeries,
},
{
name: '压力 (MPa)',
type: 'line',
smooth: true,
symbol: 'diamond',
symbolSize: 7,
lineStyle: { width: 3, color: '#c2b453' },
itemStyle: { color: '#c2b453' },
yAxisIndex: 1,
data: pressureSeries,
},
],
}),
[],
);
@ -298,28 +323,49 @@ const HistoryTrend = () => {
</section>
<section className={styles.rightPanel}>
<div className={styles.blockHeader}>
<span className={styles.titleIcon} />
<span className={styles.blockTitle}>层级结构</span>
<div className={styles.headerAction}>
<Button
className={styles.addLevelButton}
icon={<PlusOutlined />}
<div className={styles.trendCard}>
<div className={styles.trendHeader}>
<div className={styles.headerTitle}>
<span className={styles.titleIcon} />
<span className={styles.blockTitle}>液位历史趋势</span>
</div>
<Select
value={levelRange}
onChange={setLevelRange}
options={rangeOptions}
className={styles.rangeSelect}
dropdownMatchSelectWidth={false}
size="small"
>
添加层级
</Button>
/>
</div>
<div className={styles.chartWrapper}>
<ReactECharts option={levelTrendOption} style={{ height: '260px' }} notMerge lazyUpdate />
</div>
</div>
<div className={styles.tableWrapper}>
<StandardTable
columns={tableColumns}
data={tableData}
rowKey="id"
isshowAlert={false}
pagination={{ pageSize: 10 }}
size="small"
/>
<div className={styles.trendCard}>
<div className={styles.trendHeader}>
<div className={styles.headerTitle}>
<span className={styles.titleIcon} />
<span className={styles.blockTitle}>温度与压力趋势</span>
</div>
<Select
value={tempRange}
onChange={setTempRange}
options={rangeOptions}
className={styles.rangeSelect}
dropdownMatchSelectWidth={false}
size="small"
/>
</div>
<div className={styles.chartWrapper}>
<ReactECharts
option={temperaturePressureOption}
style={{ height: '260px' }}
notMerge
lazyUpdate
/>
</div>
</div>
</section>
</div>

@ -23,6 +23,7 @@
box-shadow: 0 4px 20px rgba(21, 32, 66, 0.04);
display: flex;
flex-direction: column;
gap: 16px;
}
.blockHeader {
@ -44,15 +45,6 @@
font-weight: 500;
color: #333333;
}
.headerAction {
margin-left: auto;
:global(&.ant-btn-sm) {
height: 28px !important;
line-height: 28px;
}
}
}
.filters {
@ -149,23 +141,56 @@
}
}
.tableWrapper {
flex: 1;
.trendCard {
background: #fff;
border-radius: 10px;
border: 1px solid #e0eeea;
padding: 12px 12px 16px;
box-shadow: 0 6px 16px rgba(12, 49, 41, 0.06);
display: flex;
flex-direction: column;
gap: 12px;
}
:global {
.ant-table-thead>tr>th {
text-align: center;
background: #f0f7f7;
font-weight: 450;
color: #333333;
}
.trendHeader {
display: flex;
align-items: center;
justify-content: space-between;
}
.ant-table-tbody>tr>td {
text-align: center;
font-weight: 400;
color: #4e5856;
}
.headerTitle {
display: flex;
align-items: center;
gap: 8px;
}
.rangeSelect {
width: 120px;
:global(.ant-select-selector) {
border: 1px solid rgba(45, 158, 157, 1);
border-radius: 4px;
height: 28px;
}
:global(.ant-select-focused .ant-select-selector) {
border-color: rgba(45, 158, 157, 1) !important;
box-shadow: 0 0 0 2px rgba(45, 158, 157, 0.2) !important;
}
:global(.ant-select:hover .ant-select-selector) {
border-color: rgba(45, 158, 157, 1) !important;
}
}
.chartWrapper {
width: 100%;
height: 280px;
background: linear-gradient(180deg, #f8fbfa 0%, #ffffff 100%);
border-radius: 8px;
border: 1px solid #e6f1ec;
padding: 6px;
box-sizing: border-box;
}
}

@ -301,8 +301,13 @@ const RealtimeData = () => {
</section>
<section className={styles.rightPanel}>
<div className={styles.mainTitle}>实时监测点数据</div>
<div className={styles.blockHeader}>
<span className={styles.titleIcon} />
<span className={styles.blockTitle}>实时数据</span>
</div>
{/* 从这里开始下面的内容 */}
{/* 从这里开始下面的内容 */}
<div className={styles.tableWrapper}>
<StandardTable
columns={tableColumns}

@ -286,9 +286,10 @@
}
.alertTitle {
font-weight: 600;
font-weight: 450;
color: #333333;
margin-bottom: 4px;
font-size: 15px;
}
.alertDesc {

Loading…
Cancel
Save