实时数据页面

main
wangyunfei888 1 month ago
parent e7efc6e4fd
commit 96533b63f1

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

@ -23,6 +23,7 @@
box-shadow: 0 4px 20px rgba(21, 32, 66, 0.04); box-shadow: 0 4px 20px rgba(21, 32, 66, 0.04);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px;
} }
.blockHeader { .blockHeader {
@ -44,15 +45,6 @@
font-weight: 500; font-weight: 500;
color: #333333; color: #333333;
} }
.headerAction {
margin-left: auto;
:global(&.ant-btn-sm) {
height: 28px !important;
line-height: 28px;
}
}
} }
.filters { .filters {
@ -149,23 +141,56 @@
} }
} }
.tableWrapper { .trendCard {
flex: 1; 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 { .trendHeader {
.ant-table-thead>tr>th { display: flex;
text-align: center; align-items: center;
background: #f0f7f7; justify-content: space-between;
font-weight: 450;
color: #333333;
} }
.ant-table-tbody>tr>td { .headerTitle {
text-align: center; display: flex;
font-weight: 400; align-items: center;
color: #4e5856; 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>
<section className={styles.rightPanel}> <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}> <div className={styles.tableWrapper}>
<StandardTable <StandardTable
columns={tableColumns} columns={tableColumns}

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

Loading…
Cancel
Save