|
|
|
|
@ -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>
|
|
|
|
|
|