Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wisdom-components
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ReactWeb5
wisdom-components
Commits
f23d3a78
Commit
f23d3a78
authored
Nov 26, 2024
by
陈龙
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 优化历史曲线时间选择器;优化数据加载
parent
a383e3fa
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
374 additions
and
620 deletions
+374
-620
EC_HistoryView.md
...es/extend-components/EC_HistoryView/src/EC_HistoryView.md
+16
-3
SingleChart.js
packages/extend-components/EC_HistoryView/src/SingleChart.js
+92
-87
index.js
packages/extend-components/EC_HistoryView/src/apis/index.js
+14
-1
GridDemo.js
...es/extend-components/EC_HistoryView/src/demos/GridDemo.js
+3
-8
index.js
packages/extend-components/EC_HistoryView/src/demos/index.js
+8
-3
index.js
packages/extend-components/EC_HistoryView/src/index.js
+241
-518
No files found.
packages/extend-components/EC_HistoryView/src/EC_HistoryView.md
View file @
f23d3a78
...
...
@@ -26,16 +26,16 @@ path: /
## 单图表-状态
<code
src=
"./demos/indexForStatus.js"
></code>
[
//
]:
#
(<code src="./demos/indexForStatus.js"></code>)
## 单图表-频率
<code
src=
"./demos/indexForFrequency.js"
></code>
[
//
]:
#
(<code src="./demos/indexForFrequency.js"></code>)
[
//
]:
#
'## 移动端'
[
//
]:
#
'<code src="./demos/mobile.js"></code>'
## 多图表
[
//
]:
#
(## 多图表)
[
//
]:
#
(<code src="./demos/GridDemo.js"></code>)
...
...
@@ -52,6 +52,19 @@ path: /
| deviceParams | 设备参数信息 | array | - | - |
| needMarkLine | 是否添加报警标识线 | boolean | true | |
## 字典配置
```
text
数据字典中,根据需要配置以下条目
组件_ec_historyview
- 曲线居中 true/false
- 数据滤波 true/false
- 日期模式 常规模式/简易模式
- 离散算法设备类型 水厂,二供泵房
曲线居中、数据滤波,默认是否勾选;
日期模式下,常规模式时间格式为 YYYY-MM-DD HH:mm,简易模式时间格式为YYYY-MM-DD;
离散算法设备类型,适用于数据起伏较大的设备类型,根据实际场景,配置设备类型即可
```
### deviceParams
```
javascript
...
...
packages/extend-components/EC_HistoryView/src/SingleChart.js
View file @
f23d3a78
...
...
@@ -34,90 +34,8 @@ const SingleChart = memo((props) => {
const
chartRef
=
useRef
();
const
timerRef
=
useRef
();
const
SpecialType
=
[
'状态值'
,
'开关值'
];
// 横向柱状条
const
option
=
useMemo
(()
=>
{
const
config
=
{
needUnit
:
true
,
curveCenter
,
showGridLine
,
deviceAlarmSchemes
,
showMarkLine
:
true
,
showPoint
:
true
,
chartType
,
showBoxOption
,
special
};
let
allValDesc
=
{};
let
_allSensorType
=
special
?.
allSensorType
?.
reduce
((
final
,
curr
)
=>
{
final
[
curr
.
id
]
=
curr
.
type
;
return
final
;
},
{});
let
_allPointAddress
=
special
?.
allPointAddress
?.
reduce
((
final
,
curr
)
=>
{
final
[
curr
.
name
]
=
_allSensorType
[
curr
.
sensorTypeID
];
allValDesc
[
curr
.
name
]
=
curr
.
valDesc
;
return
final
;
},
{});
if
(
dataSource
.
length
===
1
&&
SpecialType
.
includes
(
_allPointAddress
[
dataSource
[
0
].
sensorName
]))
{
config
.
sensorType
=
_allPointAddress
[
dataSource
[
0
].
sensorName
];
config
.
special
.
allValDesc
=
allValDesc
;
return
specialTypeChartOptionGenerator
({
dataSource
,
config
});
}
let
_option
=
optionGenerator
(
dataSource
,
null
,
contrast
,
contrastOption
,
smooth
,
config
,
lineDataType
,
predicateData
,
theme
);
if
(
emptyOrError
.
empty
||
emptyOrError
.
error
)
{
if
(
isArray
(
_option
.
yAxis
))
{
_option
.
yAxis
.
forEach
(
item
=>
{
item
.
max
=
100
;
item
.
min
=
0
;
})
}
else
{
_option
.
yAxis
.
max
=
100
;
_option
.
yAxis
.
min
=
0
;
}
}
// 加入bi模式
if
(
theme
===
'BI'
)
_option
=
patchBIOption
(
_option
,
BI
);
return
_option
;
},
[
dataSource
,
smooth
,
curveCenter
,
chartType
,
predicateData
]);
useEffect
(()
=>
{
if
(
exportCanvas
.
exportFlag
)
{
const
chart
=
chartRef
.
current
?.
getEchartsInstance
?.();
let
a
=
document
.
createElement
(
'a'
);
a
.
href
=
chart
.
getDataURL
(
'image/png'
);
a
.
download
=
'曲线图片.png'
a
.
click
();
a
.
remove
();
exportCanvas
.
setExportFlag
(
null
);
}
},
[
exportCanvas
.
exportFlag
]);
useEffect
(()
=>
{
chartRef
.
current
?.
resize
?.();
const
chart
=
chartRef
.
current
?.
getEchartsInstance
?.();
function
hander
(
params
)
{
const
{
selected
}
=
params
;
const
count
=
Object
.
values
(
selected
||
{}).
filter
((
item
)
=>
item
).
length
;
const
option
=
cloneDeep
(
chart
.
getOption
());
const
needMarkLine
=
count
===
1
;
option
.
series
.
forEach
((
item
,
index
)
=>
{
if
(
needMarkLine
&&
selected
[
item
.
name
])
{
item
.
markLine
=
alarmMarkLine
(
dataSource
[
index
],
index
,
[
dataSource
[
index
]],
deviceAlarmSchemes
,
);
// item.markPoint = minMaxMarkPoint(dataSource[index], index, [dataSource[index]]);
}
else
{
item
.
markLine
=
{};
item
.
markPoint
=
{};
}
});
chart
.
setOption
(
option
,
true
);
}
function
renderMarkPoint
(
e
)
{
if
(
timerRef
.
current
)
clearTimeout
(
timerRef
.
current
);
timerRef
.
current
=
setTimeout
(()
=>
{
const
minMaxMarkPoint
=
(
dataSource
)
=>
{
const
minMaxMarkPoint
=
(
dataSource
,
chart
)
=>
{
// 只有一个数据曲线时显示markline
if
(
dataSource
.
length
!==
1
)
return
{};
// 1. 找出最大、最小的值
...
...
@@ -270,11 +188,98 @@ const SingleChart = memo((props) => {
data
,
};
};
// minMaxMarkPoint(dataSource)
chart
.
setOption
({
series
:
{
markPoint
:
minMaxMarkPoint
(
dataSource
)}})
const
renderMarkPoint
=
()
=>
{
if
(
timerRef
.
current
)
clearTimeout
(
timerRef
.
current
);
const
chart
=
chartRef
.
current
?.
getEchartsInstance
?.();
timerRef
.
current
=
setTimeout
(()
=>
{
chart
.
setOption
({
series
:
{
markPoint
:
minMaxMarkPoint
(
dataSource
,
chart
)}})
},
200
)
}
};
const
option
=
useMemo
(()
=>
{
const
config
=
{
needUnit
:
true
,
curveCenter
,
showGridLine
,
deviceAlarmSchemes
,
showMarkLine
:
true
,
showPoint
:
true
,
chartType
,
showBoxOption
,
special
};
let
allValDesc
=
{};
let
_allSensorType
=
special
?.
allSensorType
?.
reduce
((
final
,
curr
)
=>
{
final
[
curr
.
id
]
=
curr
.
type
;
return
final
;
},
{});
let
_allPointAddress
=
special
?.
allPointAddress
?.
reduce
((
final
,
curr
)
=>
{
final
[
curr
.
name
]
=
_allSensorType
[
curr
.
sensorTypeID
];
allValDesc
[
curr
.
name
]
=
curr
.
valDesc
;
return
final
;
},
{});
if
(
dataSource
.
length
===
1
&&
SpecialType
.
includes
(
_allPointAddress
[
dataSource
[
0
].
sensorName
]))
{
config
.
sensorType
=
_allPointAddress
[
dataSource
[
0
].
sensorName
];
config
.
special
.
allValDesc
=
allValDesc
;
return
specialTypeChartOptionGenerator
({
dataSource
,
config
});
}
let
_option
=
optionGenerator
(
dataSource
,
null
,
contrast
,
contrastOption
,
smooth
,
config
,
lineDataType
,
predicateData
,
theme
);
// 将markPoint配置加入
const
chart
=
chartRef
.
current
?.
getEchartsInstance
?.();
if
(
_option
?.
series
?.[
0
]
&&
chart
)
{
_option
.
series
[
0
].
markPoint
=
minMaxMarkPoint
(
dataSource
,
chart
);
}
if
(
emptyOrError
.
empty
||
emptyOrError
.
error
)
{
if
(
isArray
(
_option
.
yAxis
))
{
_option
.
yAxis
.
forEach
(
item
=>
{
item
.
max
=
100
;
item
.
min
=
0
;
})
}
else
{
_option
.
yAxis
.
max
=
100
;
_option
.
yAxis
.
min
=
0
;
}
}
// 加入bi模式
if
(
theme
===
'BI'
)
_option
=
patchBIOption
(
_option
,
BI
);
return
_option
;
},
[
dataSource
,
smooth
,
curveCenter
,
chartType
,
predicateData
,
chartRef
]);
useEffect
(()
=>
{
if
(
exportCanvas
.
exportFlag
)
{
const
chart
=
chartRef
.
current
?.
getEchartsInstance
?.();
let
a
=
document
.
createElement
(
'a'
);
a
.
href
=
chart
.
getDataURL
(
'image/png'
);
a
.
download
=
'曲线图片.png'
a
.
click
();
a
.
remove
();
exportCanvas
.
setExportFlag
(
null
);
}
},
[
exportCanvas
.
exportFlag
]);
useEffect
(()
=>
{
chartRef
.
current
?.
resize
?.();
const
chart
=
chartRef
.
current
?.
getEchartsInstance
?.();
function
hander
(
params
)
{
const
{
selected
}
=
params
;
const
count
=
Object
.
values
(
selected
||
{}).
filter
((
item
)
=>
item
).
length
;
const
option
=
cloneDeep
(
chart
.
getOption
());
const
needMarkLine
=
count
===
1
;
option
.
series
.
forEach
((
item
,
index
)
=>
{
if
(
needMarkLine
&&
selected
[
item
.
name
])
{
item
.
markLine
=
alarmMarkLine
(
dataSource
[
index
],
index
,
[
dataSource
[
index
]],
deviceAlarmSchemes
,
);
// item.markPoint = minMaxMarkPoint(dataSource[index], index, [dataSource[index]]);
}
else
{
item
.
markLine
=
{};
item
.
markPoint
=
{};
}
});
chart
.
setOption
(
option
,
true
);
}
if
(
!
chart
)
return
;
renderMarkPoint
();
chart
.
on
(
'legendselectchanged'
,
hander
);
...
...
@@ -285,7 +290,7 @@ const SingleChart = memo((props) => {
chart
.
off
(
'legendselectchanged'
,
renderMarkPoint
);
chart
.
off
(
'datazoom'
,
renderMarkPoint
);
};
},
[
dataSource
,
deviceAlarmSchemes
]);
},
[
JSON
.
stringify
(
option
)
]);
// 网格开关,不更新整个图表
useEffect
(()
=>
{
...
...
packages/extend-components/EC_HistoryView/src/apis/index.js
View file @
f23d3a78
...
...
@@ -59,7 +59,20 @@ export function getDictionaryInfoAll(params) {
params
})
}
export
function
searchDataDictionaryList
(
params
)
{
return
request
({
url
:
`
${
baseUrl
}
/PandaOMS/OMS/DataManger/SearchDataDictionaryList`
,
method
:
REQUEST_METHOD_GET
,
params
})
}
export
function
getDataDictionaryList
(
params
)
{
return
request
({
url
:
`
${
baseUrl
}
/PandaOMS/OMS/DataManger/GetDataDictionaryList`
,
method
:
REQUEST_METHOD_GET
,
params
})
}
export
function
getSensorType
()
{
return
request
({
url
:
`
${
baseUrl
}
/PandaMonitor/Monitor/Sensor/GetSensorType`
,
...
...
packages/extend-components/EC_HistoryView/src/demos/GridDemo.js
View file @
f23d3a78
...
...
@@ -95,14 +95,9 @@ import HistoryView from '../index';
];*/
const
deviceParams
=
[
{
"deviceCode"
:
"EGJZ00000002"
,
"sensors"
:
"出水实际压力,1#水箱液位"
,
"deviceType"
:
"二供机组"
},
{
"deviceCode"
:
"EGBF00000004"
,
"sensors"
:
"今日用电量,今日供水量"
,
"deviceType"
:
"二供泵房"
"deviceCode"
:
"SZJCY00000001"
,
"sensors"
:
"温度,压力,浊度,二氧化氯"
,
"deviceType"
:
"水质监测仪"
}
]
const
Demo
=
()
=>
{
...
...
packages/extend-components/EC_HistoryView/src/demos/index.js
View file @
f23d3a78
...
...
@@ -2,10 +2,15 @@ import React from 'react';
import
HistoryView
from
'../index'
;
const
deviceParams
=
[
{
/*
{
"deviceCode": "EGBF00000022",
"sensors": "出水瞬时流量,今日用电量,余氯",
"deviceType": "二供泵房"
}*/
{
"deviceCode"
:
"SZJCY00000006"
,
"sensors"
:
"浊度"
,
"deviceType"
:
"水质监测仪"
}
]
const
Demo
=
()
=>
{
...
...
@@ -13,8 +18,8 @@ const Demo = () => {
<>
<
div
>
<
div
style
=
{{
height
:
700
}}
>
{
/*<HistoryView deviceParams={deviceParams} defaultModel="curve" />*/
}
<
HistoryView
theme
=
{
'BI'
}
deviceParams
=
{
deviceParams
}
defaultModel
=
"curve"
/>
<
HistoryView
deviceParams
=
{
deviceParams
}
defaultModel
=
"curve"
/>
{
/*<HistoryView theme={'BI'} deviceParams={deviceParams} defaultModel="curve"/>*/
}
<
/div
>
<
/div
>
<
/
>
...
...
packages/extend-components/EC_HistoryView/src/index.js
View file @
f23d3a78
...
...
@@ -7,26 +7,13 @@ import React, {useContext, useEffect, useMemo, useState, useCallback, useRef} fr
import
PropTypes
from
'prop-types'
;
import
classNames
from
'classnames'
;
import
{
Checkbox
,
ConfigProvider
,
DatePicker
,
Radio
,
Select
,
Spin
,
Tabs
,
Tooltip
,
Button
,
message
,
Progress
,
Checkbox
,
ConfigProvider
,
DatePicker
,
Radio
,
Select
,
Spin
,
Tabs
,
Tooltip
,
Button
,
message
,
Progress
,
Input
}
from
'antd'
;
import
{
CloseCircleFilled
,
PlusCircleOutlined
,
QuestionCircleFilled
,
DownloadOutlined
,
CloseCircleFilled
,
PlusCircleOutlined
,
QuestionCircleFilled
,
DownloadOutlined
,
SwapOutlined
,
}
from
'@ant-design/icons'
;
import
moment
from
'moment'
;
import
_
from
'lodash'
;
import
_
,
{
cloneDeep
}
from
'lodash'
;
import
TimeRangePicker
from
'@wisdom-components/timerangepicker'
;
import
PandaEmpty
from
'@wisdom-components/empty'
;
import
{
...
...
@@ -35,7 +22,10 @@ import {
getExportDeviceHistoryUrl
,
getDictionaryInfoAll
,
getPointAddress
,
getPointAddressEntry
,
getPredicateSensor
,
getPointAddressEntry
,
getPredicateSensor
,
searchDataDictionaryList
,
getDataDictionaryList
,
}
from
'./apis'
;
import
SingleChart
from
'./SingleChart'
;
import
GridChart
from
'./GridChart'
;
...
...
@@ -54,82 +44,45 @@ const endFormat = 'YYYY-MM-DD 23:59:59';
const
timeFormat
=
'YYYY-MM-DD HH:mm:ss'
;
const
dateFormat
=
'YYYYMMDD'
;
const
timeList
=
[
{
key
:
'twelveHours'
,
name
:
'近12小时'
,
},
{
key
:
'roundClock'
,
name
:
'近24小时'
,
},
{
key
:
'yesterday'
,
name
:
'昨日'
,
},
{
key
:
'oneWeek'
,
name
:
'近1周'
,
},
{
key
:
'oneMonth'
,
name
:
'近1月'
,
},
];
const
timeList
=
[{
key
:
'twelveHours'
,
name
:
'近12小时'
,
},
{
key
:
'roundClock'
,
name
:
'近24小时'
,
},
{
key
:
'yesterday'
,
name
:
'昨日'
,
},
{
key
:
'oneWeek'
,
name
:
'近1周'
,
},
{
key
:
'oneMonth'
,
name
:
'近1月'
,
},];
const
predicateMap
=
{
twelveHours
:
12
,
roundClock
:
24
,
oneWeek
:
24
,
oneMonth
:
24
twelveHours
:
12
,
roundClock
:
24
,
oneWeek
:
24
,
oneMonth
:
24
}
// 同期对比 日 快捷按钮
const
shortcutsForDay
=
[
{
label
:
'近3天'
,
value
:
'近3天'
,
},
{
label
:
'近7天'
,
value
:
'近7天'
,
},
/* {
const
shortcutsForDay
=
[{
label
:
'近3天'
,
value
:
'近3天'
,
},
{
label
:
'近7天'
,
value
:
'近7天'
,
},
/* {
label: '去年同期',
value: '去年同期',
}*/
];
}*/
];
// 同期对比 月 快捷按钮
const
shortcutsForMonth
=
[
{
label
:
'近3月'
,
value
:
'近3月'
,
},
{
label
:
'近6月'
,
value
:
'近6月'
,
},
/* {
const
shortcutsForMonth
=
[{
label
:
'近3月'
,
value
:
'近3月'
,
},
{
label
:
'近6月'
,
value
:
'近6月'
,
},
/* {
label: '去年同期',
value: '去年同期',
}*/
];
}*/
];
const
CheckboxData
=
[
{
key
:
'curveCenter'
,
label
:
'曲线居中'
,
checked
:
false
,
showInCurve
:
true
,
showInTable
:
false
,
},
{
key
:
'chartGrid'
,
label
:
'图表网格'
,
checked
:
true
,
showInCurve
:
true
,
showInTable
:
false
,
},
{
const
CheckboxData
=
[{
key
:
'curveCenter'
,
label
:
'曲线居中'
,
checked
:
false
,
showInCurve
:
true
,
showInTable
:
false
,
},
{
key
:
'chartGrid'
,
label
:
'图表网格'
,
checked
:
true
,
showInCurve
:
true
,
showInTable
:
false
,
},
{
key
:
'ignoreOutliers'
,
label
:
'去除异常值'
,
type
:
'updateIgnoreOutliers'
,
...
...
@@ -138,79 +91,31 @@ const CheckboxData = [
showInTable
:
true
,
tooltip
:
'采用递推平均滤波法(滑动平均滤波法)对采样数据中的异常离群值进行识别与去除。'
,
hasSub
:
true
,
},
{
key
:
'dataThin'
,
label
:
'数据抽稀'
,
type
:
'updateDataThin'
,
checked
:
true
,
showInCurve
:
false
,
showInTable
:
true
,
}
];
},
{
key
:
'dataThin'
,
label
:
'数据抽稀'
,
type
:
'updateDataThin'
,
checked
:
true
,
showInCurve
:
false
,
showInTable
:
true
,
}];
const
timeIntervalList
=
[
{
key
:
'1min'
,
zoom
:
'1'
,
unit
:
'min'
,
name
:
'1分钟'
,
},
{
key
:
'5'
,
zoom
:
'5'
,
unit
:
'min'
,
name
:
'5分钟'
,
},
{
key
:
'10'
,
zoom
:
'10'
,
unit
:
'min'
,
name
:
'10分钟'
,
},
{
key
:
'30'
,
zoom
:
'30'
,
unit
:
'min'
,
name
:
'30分钟'
,
},
{
key
:
'1'
,
zoom
:
'1'
,
unit
:
'h'
,
name
:
'1小时'
,
},
{
key
:
'2'
,
zoom
:
'2'
,
unit
:
'h'
,
name
:
'2小时'
,
},
{
key
:
'4'
,
zoom
:
'4'
,
unit
:
'h'
,
name
:
'4小时'
,
},
{
key
:
'6'
,
zoom
:
'6'
,
unit
:
'h'
,
name
:
'6小时'
,
},
{
key
:
'12'
,
zoom
:
'12'
,
unit
:
'h'
,
name
:
'12小时'
,
},
{
key
:
'24'
,
zoom
:
'24'
,
unit
:
'h'
,
name
:
'24小时'
,
},
];
const
timeIntervalList
=
[{
key
:
'1min'
,
zoom
:
'1'
,
unit
:
'min'
,
name
:
'1分钟'
,
},
{
key
:
'5'
,
zoom
:
'5'
,
unit
:
'min'
,
name
:
'5分钟'
,
},
{
key
:
'10'
,
zoom
:
'10'
,
unit
:
'min'
,
name
:
'10分钟'
,
},
{
key
:
'30'
,
zoom
:
'30'
,
unit
:
'min'
,
name
:
'30分钟'
,
},
{
key
:
'1'
,
zoom
:
'1'
,
unit
:
'h'
,
name
:
'1小时'
,
},
{
key
:
'2'
,
zoom
:
'2'
,
unit
:
'h'
,
name
:
'2小时'
,
},
{
key
:
'4'
,
zoom
:
'4'
,
unit
:
'h'
,
name
:
'4小时'
,
},
{
key
:
'6'
,
zoom
:
'6'
,
unit
:
'h'
,
name
:
'6小时'
,
},
{
key
:
'12'
,
zoom
:
'12'
,
unit
:
'h'
,
name
:
'12小时'
,
},
{
key
:
'24'
,
zoom
:
'24'
,
unit
:
'h'
,
name
:
'24小时'
,
},];
const
handleTimeForPredicate
=
(
key
,
start
,
end
)
=>
{
let
t
=
predicateMap
[
key
]
||
0
;
...
...
@@ -251,24 +156,16 @@ const updateTime = (key, predicate) => {
if
(
predicate
)
{
end
=
handleTimeForPredicate
(
key
,
end
)
}
return
[
{
dateFrom
:
start
,
dateTo
:
end
,
},
];
return
[{
dateFrom
:
start
,
dateTo
:
end
,
},];
};
const
DefaultDatePicker
=
(
value
)
=>
[
{
key
:
1
,
value
:
moment
(),
},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
value
),
},
];
const
DefaultDatePicker
=
(
value
)
=>
[{
key
:
1
,
value
:
moment
(),
},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
value
),
},];
const
handleBatchTime
=
(
arr
,
cOption
)
=>
{
let
newArr
=
[];
...
...
@@ -290,10 +187,7 @@ const handleFakeData = (dateRange, deviceParams) => {
let
_arr
=
cur
.
sensors
.
split
(
','
);
_arr
.
forEach
(
sensor
=>
{
final
.
push
({
dataModel
:
[
{
pt
:
dateFrom
,
pv
:
null
},
{
pt
:
dateTo
,
pv
:
null
}
],
dataModel
:
[{
pt
:
dateFrom
,
pv
:
null
},
{
pt
:
dateTo
,
pv
:
null
}],
dateFrom
,
dateTo
,
deviceCode
:
cur
.
deviceCode
,
...
...
@@ -313,8 +207,7 @@ const timeColumn = {
width
:
170
,
ellipsis
:
true
,
align
:
'center'
,
sorter
:
true
,
// sortOrder:['descend','ascend']
sorter
:
true
,
// sortOrder:['descend','ascend']
};
const
OriginMaxDays
=
31
;
// 原始曲线请求数据的最大天数
const
CharacteristicMaxDays
=
null
;
// 特征曲线或者其他曲线的最大天数
...
...
@@ -336,8 +229,7 @@ const HistoryView = (props) => {
}
=
props
;
if
(
theme
===
'Normal'
)
import
(
'./index.less'
);
if
(
theme
===
'BI'
)
import
(
'./indexForBI.less'
);
const
isBoxPlots
=
deviceParams
?.
length
===
1
&&
deviceParams
?.[
0
]?.
sensors
?.
split
(
','
).
length
===
1
;
const
isBoxPlots
=
deviceParams
?.
length
===
1
&&
deviceParams
?.[
0
]?.
sensors
?.
split
(
','
).
length
===
1
;
const
[
loading
,
setLoading
]
=
useState
(
null
);
const
[
activeTabKey
,
setActiveTabKey
]
=
useState
(
defaultModel
);
...
...
@@ -352,9 +244,7 @@ const HistoryView = (props) => {
const
[
contrastOption
,
setContrastOption
]
=
useState
(
'day'
);
// 对比时间类型: 日/月
const
[
datePickerArr
,
setDatePickerArr
]
=
useState
(
DefaultDatePicker
(
defaultDate
));
// 对比时间段配置值
const
[
checkboxData
,
setCheckboxData
]
=
useState
(()
=>
[...
CheckboxData
]);
// 曲线设置项
const
[
dataThinKey
,
setDataThinKey
]
=
useState
(
timeIntervalList
[
0
].
key
===
'1min'
?
timeIntervalList
[
1
].
key
:
timeIntervalList
[
0
].
key
,
);
// 曲线抽稀时间设置
const
[
dataThinKey
,
setDataThinKey
]
=
useState
(
timeIntervalList
[
0
].
key
===
'1min'
?
timeIntervalList
[
1
].
key
:
timeIntervalList
[
0
].
key
,);
// 曲线抽稀时间设置
const
[
algorithmValue
,
setAlgorithmValue
]
=
useState
(
1
);
const
[
columns
,
setColumns
]
=
useState
([]);
...
...
@@ -380,23 +270,18 @@ const HistoryView = (props) => {
const
[
predicateTime
,
setPredicateTime
]
=
useState
(
null
);
// 需要处理默认数据,确保图表能够一直显示坐标轴。用来存储当前的请求状态。
const
emptyOrError
=
useRef
({
empty
:
true
,
error
:
true
empty
:
true
,
error
:
true
})
// 这部分功能有问题,等待解决后上线 2024年3月13日
const
[
discreteDeviceType
,
setDiscreteDeviceType
]
=
useState
([
'水厂'
])
const
[
discreteDeviceType
,
setDiscreteDeviceType
]
=
useState
([
'水厂'
]);
const
[
timeFormatter
,
setTimeFormatter
]
=
useState
(
'常规模式'
);
// 常规模式 YYYY-MM-DD HH:mm 简易模式 YYYY-MM-DD
// 历史数据相关的特征描述
const
deviceConfig
=
useRef
({
oneDevice
:
deviceParams
.
length
===
1
,
//单设备
oneSensor
:
[
...
new
Set
(
deviceParams
.
reduce
((
final
,
cur
)
=>
{
oneSensor
:
[...
new
Set
(
deviceParams
.
reduce
((
final
,
cur
)
=>
{
let
_sensors
=
cur
.
sensors
.
split
(
','
);
return
final
.
concat
(
_sensors
);
},
[]),
),
].
length
===
1
,
// 单指标
},
[]),),].
length
===
1
,
// 单指标
});
// 表格虚拟列表
const
tableRef
=
useRef
();
...
...
@@ -424,16 +309,11 @@ const HistoryView = (props) => {
// 数据配置
const
dataConfig
=
useMemo
(()
=>
{
const
initial
=
{
ignoreOutliers
:
false
,
dataThin
:
false
,
zoom
:
''
,
// 数据抽稀时间
ignoreOutliers
:
false
,
dataThin
:
false
,
zoom
:
''
,
// 数据抽稀时间
unit
:
''
,
// 数据抽稀时间单位
};
// 曲线居中,过滤异常值,数据抽稀
const
config
=
checkboxData
.
reduce
(
(
pre
,
item
)
=>
(
item
.
key
!==
'curveCenter'
&&
(
pre
[
item
.
key
]
=
item
.
checked
),
pre
),
initial
,
);
const
config
=
checkboxData
.
reduce
((
pre
,
item
)
=>
(
item
.
key
!==
'curveCenter'
&&
(
pre
[
item
.
key
]
=
item
.
checked
),
pre
),
initial
,);
// 数据抽稀时间单位
const
dataThin
=
timeIntervalList
.
find
((
item
)
=>
item
.
key
===
dataThinKey
);
config
.
zoom
=
activeTabKey
===
'curve'
?
''
:
dataThin
?.
zoom
??
''
;
...
...
@@ -478,8 +358,7 @@ const HistoryView = (props) => {
// 同期对比模式: 选择(日/月)
const
onContrastChange
=
(
value
)
=>
{
if
(
value
===
'month'
)
{
if
(
lineDataType
===
'原始曲线'
)
message
.
info
(
'月模式数据量较大,不支持原始曲线模式,已切换为特征曲线'
);
if
(
lineDataType
===
'原始曲线'
)
message
.
info
(
'月模式数据量较大,不支持原始曲线模式,已切换为特征曲线'
);
setLineDataType
(
'特征曲线'
);
}
setShortcutsValue
(
''
);
...
...
@@ -505,13 +384,9 @@ const HistoryView = (props) => {
const
handleAddDatePicker
=
()
=>
{
// 操作时间就清除掉快捷键选用状态
setShortcutsValue
(
''
);
setDatePickerArr
([
...
datePickerArr
,
{
key
:
datePickerArr
[
datePickerArr
.
length
-
1
].
key
+
1
,
value
:
''
,
},
]);
setDatePickerArr
([...
datePickerArr
,
{
key
:
datePickerArr
[
datePickerArr
.
length
-
1
].
key
+
1
,
value
:
''
,
},]);
};
// 同期对比模式: 删除日期选择组件
...
...
@@ -552,46 +427,40 @@ const HistoryView = (props) => {
let
_arr
=
[];
switch
(
_val
)
{
case
'近3天'
:
_arr
=
[
{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'days'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'days'
)},
];
_arr
=
[{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'days'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'days'
)
},];
break
;
case
'近7天'
:
_arr
=
[
{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'days'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'days'
)},
{
key
:
4
,
value
:
moment
().
subtract
(
3
,
'days'
)},
{
key
:
5
,
value
:
moment
().
subtract
(
4
,
'days'
)},
{
key
:
6
,
value
:
moment
().
subtract
(
5
,
'days'
)},
{
key
:
7
,
value
:
moment
().
subtract
(
6
,
'days'
)},
];
_arr
=
[{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'days'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'days'
)
},
{
key
:
4
,
value
:
moment
().
subtract
(
3
,
'days'
)},
{
key
:
5
,
value
:
moment
().
subtract
(
4
,
'days'
)
},
{
key
:
6
,
value
:
moment
().
subtract
(
5
,
'days'
)},
{
key
:
7
,
value
:
moment
().
subtract
(
6
,
'days'
)},];
break
;
case
'近3月'
:
_arr
=
[
{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'months'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'months'
)},
];
_arr
=
[{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'months'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'months'
)
},];
break
;
case
'近6月'
:
_arr
=
[
{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'months'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'months'
)},
{
key
:
4
,
value
:
moment
().
subtract
(
3
,
'months'
)},
{
key
:
5
,
value
:
moment
().
subtract
(
4
,
'months'
)},
{
key
:
6
,
value
:
moment
().
subtract
(
5
,
'months'
)},
];
_arr
=
[{
key
:
1
,
value
:
moment
()},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
'months'
)},
{
key
:
3
,
value
:
moment
().
subtract
(
2
,
'months'
)
},
{
key
:
4
,
value
:
moment
().
subtract
(
3
,
'months'
)},
{
key
:
5
,
value
:
moment
().
subtract
(
4
,
'months'
)
},
{
key
:
6
,
value
:
moment
().
subtract
(
5
,
'months'
)},];
break
;
}
setShortcutsDatePickerArr
(
_arr
);
};
const
renderTimeOption
=
useMemo
(()
=>
{
return
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-date`
)}
>
return
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-date`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
时间选择
<
/div
>
<
Radio
.
Group
value
=
{
timeValue
}
onChange
=
{
onTimeSetChange
}
>
<
Radio
.
Button
value
=
"customer"
>
自定义
<
/Radio.Button
>
...
...
@@ -605,27 +474,23 @@ const HistoryView = (props) => {
value
=
{
customerChecked
}
dataSource
=
{
timeList
}
/
>
<
Input
.
Group
compact
>
<
RangePicker
getPopupContainer
=
{
trigger
=>
trigger
.
parentElement
}
format
=
{
'YYYY-MM-DD HH:mm'
}
format
=
{
timeFormatter
===
'简易模式'
?
'YYYY-MM-DD'
:
'YYYY-MM-DD HH:mm'
}
className
=
{
classNames
(
`
${
prefixCls
}
-custime-customer`
)}
onChange
=
{
onCustomerRangeChange
}
value
=
{
dates
||
customerTime
}
onCalendarChange
=
{(
val
)
=>
{
setDates
(
val
);
}}
ranges
=
{
dates
?.[
0
]
?
{
当前时间
:
()
=>
{
return
[
dates
?.[
0
]
||
moment
(
moment
().
format
(
'YYYY-MM-DD 00:00:00'
)),
moment
(
moment
()),
];
ranges
=
{{
...(
dates
?.[
0
]
?
{
[
`
${
timeFormatter
===
'简易模式'
?
'今天'
:
'当前时间'
}
`
]:
()
=>
{
return
[
dates
?.[
0
]
||
moment
(
moment
().
format
(
'YYYY-MM-DD 00:00:00'
)),
moment
(
moment
()),];
},
}
:
{}
}
}
:
{})
}}
onOpenChange
=
{(
open
)
=>
{
if
(
open
)
{
setDates
([
null
,
null
]);
...
...
@@ -644,13 +509,23 @@ const HistoryView = (props) => {
const
tooEarly
=
dates
[
1
]
&&
dates
[
1
].
diff
(
current
,
'days'
)
>
_days
;
return
!!
tooEarly
||
!!
tooLate
;
}}
showTime
=
{{
format
:
'YYYY-MM-DD HH:mm'
,
minuteStep
:
10
,
showTime
=
{
timeFormatter
===
'简易模式'
?
false
:
{
format
:
'YYYY-MM-DD HH:mm'
,
minuteStep
:
10
,
}}
/
>
<
/
>
)}
<
Button
style
=
{{
color
:
'#1980ff'
,
cursor
:
'pointer'
,
textDecoration
:
'underline'
,
}}
onClick
=
{()
=>
{
setTimeFormatter
(
timeFormatter
===
'常规模式'
?
'简易模式'
:
'常规模式'
)
}}
>
<
Tooltip
title
=
{
`切换至
${
timeFormatter
===
'常规模式'
?
'【简易模式】:该模式取全天数据'
:
'【常规模式】:该模式取值时段可精确到分'
}
`
}
>
<
SwapOutlined
/>
<
/Tooltip
>
<
/Button
>
<
/Input.Group
>
<
/>
)
}
{
timeValue
===
'contrast'
&&
(
// 同期对比
<>
<
Select
value
=
{
contrastOption
}
getPopupContainer
=
{
trigger
=>
trigger
.
parentElement
}
...
...
@@ -666,10 +541,7 @@ const HistoryView = (props) => {
{(
contrastOption
===
'day'
?
shortcutsForDay
:
shortcutsForMonth
).
map
((
item
)
=>
{
return
<
Radio
.
Button
value
=
{
item
.
value
}
>
{
item
.
label
}
<
/Radio.Button>
;
})}
<
/Radio.Group
>
)
:
(
''
)}
<
/Radio.Group>
)
:
(
''
)
}
{
datePickerArr
.
map
((
child
,
index
)
=>
(
<
div
key
=
{
child
.
key
}
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-list`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-wrap`
)}
>
...
...
@@ -681,35 +553,20 @@ const HistoryView = (props) => {
onChange
=
{(
date
,
dateString
)
=>
onContrastPickerChange
(
date
,
dateString
,
child
)}
style
=
{{
width
:
130
,
border
:
!
shortcutsValue
?
'1px solid #1890ff'
:
''
}}
/
>
{
datePickerArr
.
length
>
2
&&
(
<
div
{
datePickerArr
.
length
>
2
&&
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-delete`
)}
onClick
=
{()
=>
handleDeleteDatePicker
(
index
)}
>
<
CloseCircleFilled
/>
<
/div
>
)}
<
/div>
)
}
<
/div
>
{
index
<
datePickerArr
.
length
-
1
&&
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-connect`
)}
>
与
<
/div
>
)}
<
/div
>
))}
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-connect`
)}
>
与
<
/div>
)
}
<
/div>
))
}
{
datePickerArr
.
length
<
4
&&
<
PlusCircleOutlined
onClick
=
{
handleAddDatePicker
}
/>
}
<
/
>
)}
<
/div
>
);
},
[
timeValue
,
customerChecked
,
lineDataType
,
datePickerArr
,
deviceParams
,
dates
,
customerTime
,
chartDataSource
,
]);
<
/>
)
}
<
/div>
)
;
},
[
timeValue
,
customerChecked
,
lineDataType
,
datePickerArr
,
deviceParams
,
dates
,
customerTime
,
chartDataSource
,
timeFormatter
]);
// 曲线设置项选择/取消
const
onCheckboxChange
=
(
e
,
key
,
showJustLine
)
=>
{
...
...
@@ -758,19 +615,14 @@ const HistoryView = (props) => {
const
gridOptions
=
[
'curveCenter'
];
if
(
grid
&&
curveAccess
&&
gridOptions
.
indexOf
(
child
.
key
)
===
-
1
)
return
null
;
return
(
(
curveAccess
||
tableAccess
)
&&
(
<>
return
((
curveAccess
||
tableAccess
)
&&
(
<>
<
Checkbox
checked
=
{
child
.
checked
}
onChange
=
{(
e
)
=>
onCheckboxChange
(
e
,
child
.
key
)}
>
{
child
.
label
}
<
/Checkbox
>
{
child
.
tooltip
&&
(
<
Tooltip
title
=
{
child
.
tooltip
}
>
{
child
.
tooltip
&&
(
<
Tooltip
title
=
{
child
.
tooltip
}
>
<
QuestionCircleFilled
className
=
{
`
${
prefixCls
}
-question`
}
/
>
<
/Tooltip
>
)}
{
child
.
hasSub
&&
child
.
checked
&&
false
?
(
<
Select
<
/Tooltip>
)
}
{
child
.
hasSub
&&
child
.
checked
&&
false
?
(
<
Select
style
=
{{
width
:
80
,
marginLeft
:
10
}}
value
=
{
algorithmValue
}
onChange
=
{(
e
)
=>
setAlgorithmValue
(
e
)}
...
...
@@ -778,23 +630,16 @@ const HistoryView = (props) => {
<
Option
value
=
{
1
}
>
低
<
/Option
>
<
Option
value
=
{
5
}
>
中
<
/Option
>
<
Option
value
=
{
10
}
>
高
<
/Option
>
<
/Select
>
)
:
(
''
)}
<
/
>
)
);
<
/Select>
)
:
(
''
)
}
<
/>
))
;
};
const
renderCurveOption
=
(
isChart
,
isSingle
,
isStatus
)
=>
{
return
(
<
div
return
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-cover`
)}
style
=
{
isChart
&&
isSingle
?
{
width
:
'100%'
}
:
{}}
>
{
isChart
&&
!
isStatus
?
(
<>
{
isChart
&&
!
isStatus
?
(
<>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
曲线选择
<
/div
>
<
div
className
=
{
`
${
prefixCls
}
-cover-item`
}
>
<
Radio
.
Group
value
=
{
lineDataType
}
onChange
=
{
switchLineDataType
}
>
...
...
@@ -808,14 +653,9 @@ const HistoryView = (props) => {
/
>
<
/Tooltip
>
<
/div
>
<
/
>
)
:
(
''
)}
{
isChart
&&
isSingle
&&
showBoxOption
&&
!
isStatus
&&
!
grid
?
(
<>
{
lineDataType
!==
'原始曲线'
?
(
<>
<
/>
)
:
(
''
)
}
{
isChart
&&
isSingle
&&
showBoxOption
&&
!
isStatus
&&
!
grid
?
(
<>
{
lineDataType
!==
'原始曲线'
?
(
<>
<
div
style
=
{{
marginLeft
:
7
}}
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
曲线形态
<
/div
>
...
...
@@ -831,30 +671,20 @@ const HistoryView = (props) => {
<
Radio
.
Button
value
=
{
'lineChart'
}
>
线形图
<
/Radio.Button
>
<
Radio
.
Button
value
=
{
'boxChart'
}
>
箱线图
<
/Radio.Button
>
<
/Radio.Group
>
<
/
>
)
:
(
''
)}
<
/
>
)
:
(
''
)}
{
!
isStatus
?
(
<>
<
/>
)
:
(
''
)
}
<
/>
)
:
(
''
)
}
{
!
isStatus
?
(
<>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
{
activeTabKey
!==
'table'
?
'曲线设置'
:
'表格设置'
}
<
/div
>
{
checkboxData
.
map
((
child
)
=>
{
const
box
=
renderCheckbox
(
child
,
isChart
&&
isSingle
);
if
(
!
box
)
return
null
;
return
(
<
div
key
=
{
child
.
key
}
className
=
{
`
${
prefixCls
}
-cover-item`
}
>
return
(
<
div
key
=
{
child
.
key
}
className
=
{
`
${
prefixCls
}
-cover-item`
}
>
{
box
}
<
/div
>
);
<
/div>
)
;
})}
{
activeTabKey
===
'table'
&&
(
<
Select
{
activeTabKey
===
'table'
&&
(
<
Select
value
=
{
dataThinKey
}
style
=
{{
width
:
90
}}
onChange
=
{
onTimeIntervalChange
}
...
...
@@ -867,20 +697,13 @@ const HistoryView = (props) => {
return
!
(
_diffDays
>
7
&&
item
.
key
===
'1min'
);
})
.
map
((
child
)
=>
{
return
(
<
Option
key
=
{
child
.
key
}
unit
=
{
child
.
unit
}
value
=
{
child
.
key
}
>
return
(
<
Option
key
=
{
child
.
key
}
unit
=
{
child
.
unit
}
value
=
{
child
.
key
}
>
{
child
.
name
}
<
/Option
>
);
<
/Option>
)
;
})}
<
/Select
>
)}
<
/
>
)
:
(
''
)}
<
/div
>
);
<
/Select>
)
}
<
/>
)
:
(
''
)
}
<
/div>
)
;
};
const
exportExcelBtn
=
()
=>
{
...
...
@@ -888,9 +711,7 @@ const HistoryView = (props) => {
deviceParams
.
forEach
((
i
,
r
)
=>
{
let
timeFrom
=
dateRange
[
r
]?.
dateFrom
||
moment
().
format
(
startFormat
);
let
timeTo
=
dateRange
[
r
]?.
dateTo
||
moment
().
format
(
timeFormat
);
let
fileName
=
`数据报表-
${
i
.
deviceType
}
-
${
i
.
deviceCode
}
-
${
moment
(
timeFrom
).
format
(
dateFormat
,
)}
至
${
moment
(
timeTo
).
format
(
dateFormat
)}
`
;
let
fileName
=
`数据报表-
${
i
.
deviceType
}
-
${
i
.
deviceCode
}
-
${
moment
(
timeFrom
).
format
(
dateFormat
,)}
至
${
moment
(
timeTo
).
format
(
dateFormat
)}
`
;
let
_quotas
=
i
.
sensors
.
split
(
','
)
.
filter
((
item
)
=>
item
!==
'是否在线'
)
...
...
@@ -935,9 +756,7 @@ const HistoryView = (props) => {
let
_columns
=
[...
columns
];
let
timeFrom
=
dateRange
?.[
0
]?.
dateFrom
||
moment
().
format
(
startFormat
);
let
timeTo
=
dateRange
?.[
0
]?.
dateTo
||
moment
().
format
(
timeFormat
);
let
fileName
=
`特征数据-
${
moment
(
timeFrom
).
format
(
dateFormat
)}
至
${
moment
(
timeTo
).
format
(
dateFormat
,
)}
`
;
let
fileName
=
`特征数据-
${
moment
(
timeFrom
).
format
(
dateFormat
)}
至
${
moment
(
timeTo
).
format
(
dateFormat
,)}
`
;
let
_dataIndex
=
[];
let
_titleWidth
=
[];
let
_title
=
_columns
.
map
((
item
)
=>
{
...
...
@@ -951,22 +770,15 @@ const HistoryView = (props) => {
return
_titleStr
;
});
ExportExcel
({
name
:
fileName
,
content
:
[
{
sheetData
:
_dataSource
,
sheetFilter
:
_dataIndex
,
sheetHeader
:
_title
,
columnWidths
:
_titleWidth
,
},
],
name
:
fileName
,
content
:
[{
sheetData
:
_dataSource
,
sheetFilter
:
_dataIndex
,
sheetHeader
:
_title
,
columnWidths
:
_titleWidth
,
},],
});
};
const
exportCanvas
=
()
=>
{
setExportFlag
(
Math
.
random
());
};
const
handleTableData
=
useCallback
(
(
data
)
=>
{
const
handleTableData
=
useCallback
((
data
)
=>
{
// eslint-disable-next-line no-param-reassign
// data = data.filter(item => item.sensorName !== '是否在线');
const
ignoreOutliers
=
checkboxData
.
find
((
item
)
=>
item
.
key
===
'ignoreOutliers'
).
checked
;
...
...
@@ -1022,8 +834,7 @@ const HistoryView = (props) => {
};
data
.
forEach
((
item
,
index
)
=>
{
const
{
stationCode
,
sensorName
,
dataModel
}
=
item
;
dataModel
&&
dataModel
.
forEach
((
data
)
=>
{
dataModel
&&
dataModel
.
forEach
((
data
)
=>
{
const
formatTime
=
moment
(
data
.
pt
).
format
(
format
);
let
time
=
formatTime
;
...
...
@@ -1038,8 +849,7 @@ const HistoryView = (props) => {
data
.
forEach
((
child
,
index
)
=>
{
const
{
dataModel
}
=
child
;
const
dataIndex
=
dataIndexAccess
(
child
,
index
);
dataModel
&&
dataModel
.
forEach
((
value
,
j
)
=>
{
dataModel
&&
dataModel
.
forEach
((
value
,
j
)
=>
{
const
formatTime
=
moment
(
value
.
pt
).
format
(
format
);
const
dataRow
=
timeData
[
formatTime
];
if
(
dataRow
)
{
...
...
@@ -1048,8 +858,7 @@ const HistoryView = (props) => {
});
});
const
timeSort
=
(
a
,
b
)
=>
{
let
aa
=
a
,
bb
=
b
;
let
aa
=
a
,
bb
=
b
;
if
(
timeValue
===
'contrast'
)
{
aa
=
a
.
slice
(
contrastOption
===
'day'
?
11
:
8
,
16
);
bb
=
b
.
slice
(
contrastOption
===
'day'
?
11
:
8
,
16
);
...
...
@@ -1060,9 +869,7 @@ const HistoryView = (props) => {
const
tableData
=
times
.
map
((
time
)
=>
timeData
[
time
]);
setColumns
([
timeColumn
,
...
columnsData
]);
setTableData
(
tableData
);
},
[
timeOrder
,
timeValue
,
contrastOption
],
);
},
[
timeOrder
,
timeValue
,
contrastOption
],);
const
[
deviceAlarmSchemes
,
setDeviceAlarmSchemes
]
=
useState
([]);
const
beforChangeParams
=
(
value
=
{})
=>
{
...
...
@@ -1081,8 +888,7 @@ const HistoryView = (props) => {
})),
})
.
then
((
res
)
=>
{
if
(
res
.
code
===
0
)
setDeviceAlarmSchemes
(
res
.
data
||
[]);
else
setDeviceAlarmSchemes
([]);
if
(
res
.
code
===
0
)
setDeviceAlarmSchemes
(
res
.
data
||
[]);
else
setDeviceAlarmSchemes
([]);
return
Promise
.
resolve
();
})
.
catch
((
err
)
=>
{
...
...
@@ -1141,8 +947,7 @@ const HistoryView = (props) => {
return
_item
;
})
.
forEach
((
i
)
=>
{
if
(
i
.
sensors
&&
i
.
deviceCode
)
acrossTables
.
push
(
_
.
omit
(
i
,
[
'pointAddressID'
]));
if
(
i
.
sensors
&&
i
.
deviceCode
)
acrossTables
.
push
(
_
.
omit
(
i
,
[
'pointAddressID'
]));
// 这部分功能有问题,等待解决后上线 2024年3月13日
if
(
discreteDeviceType
.
includes
(
i
.
deviceType
))
{
hasDiscreteDeviceType
=
true
;
...
...
@@ -1167,12 +972,10 @@ const HistoryView = (props) => {
let
diffYears
=
moment
(
item
.
dateTo
).
diff
(
moment
(
item
.
dateFrom
),
'years'
);
let
diffDays
=
moment
(
item
.
dateTo
).
diff
(
moment
(
item
.
dateFrom
),
'days'
);
let
diffHours
=
moment
(
item
.
dateTo
).
diff
(
moment
(
item
.
dateFrom
),
'hours'
);
let
zoomParam
=
activeTabKey
===
'curve'
?
handleDataThinKey
(
diffYears
,
diffDays
,
diffHours
,
lineDataType
)
:
!
isDilute
?
{
zoom
:
''
,
unit
:
''
}
:
{};
// 表格也支持全数据模式;
let
zoomParam
=
activeTabKey
===
'curve'
?
handleDataThinKey
(
diffYears
,
diffDays
,
diffHours
,
lineDataType
)
:
!
isDilute
?
{
zoom
:
''
,
unit
:
''
}
:
{};
// 表格也支持全数据模式;
let
_finalParams
=
{...
param
,
...
zoomParam
};
// 2024年1月8日 抽稀间隔大于等于12小时时,会存在线性插值导致抽稀间隔内数据条数大于预期的问题。需要增加一个额外参数处理该情况。
if
(
_finalParams
.
zoom
)
{
...
...
@@ -1222,11 +1025,7 @@ const HistoryView = (props) => {
minPV
=
pv
;
}
return
{
...
item
,
firstPV
,
lastPV
,
maxPV
,
minPV
,
...
item
,
firstPV
,
lastPV
,
maxPV
,
minPV
,
};
});
});
...
...
@@ -1241,9 +1040,7 @@ const HistoryView = (props) => {
}
}
const
list
=
sensors
.
map
((
s
)
=>
{
const
dataItem
=
res
.
data
.
find
(
(
d
)
=>
d
.
stationCode
===
p
.
deviceCode
&&
d
.
sensorName
===
s
,
);
const
dataItem
=
res
.
data
.
find
((
d
)
=>
d
.
stationCode
===
p
.
deviceCode
&&
d
.
sensorName
===
s
,);
if
(
dataItem
)
{
dataItem
.
dateFrom
=
dateFrom
||
''
;
dataItem
.
dateTo
=
dateTo
||
''
;
...
...
@@ -1282,32 +1079,34 @@ const HistoryView = (props) => {
useEffect
(()
=>
{
if
(
!
completeInit
)
return
;
const
{
dataThin
,
ignoreOutliers
,
zoom
,
unit
}
=
dataConfig
;
// 简易模式下,在获取到时间参数后,将时间修改为 00:00:00 - 23:59:59
let
_dateRange
=
cloneDeep
(
dateRange
)
if
(
_dateRange
?.
length
===
1
)
{
let
_date
=
dateRange
[
0
];
_dateRange
=
[{
dateFrom
:
moment
(
_date
.
dateFrom
).
format
(
'YYYY-MM-DD 00:00:00'
),
dateTo
:
moment
(
_date
.
dateTo
).
format
(
'YYYY-MM-DD 23:59:59'
),
}];
}
beforChangeParams
().
finally
(()
=>
{
onChangeParams
({
isDilute
:
dataThin
,
ignoreOutliers
,
zoom
,
unit
,
dateRange
,
isBoxPlots
:
isBoxPlots
,
isDilute
:
dataThin
,
ignoreOutliers
,
zoom
,
unit
,
dateRange
:
_dateRange
,
isBoxPlots
:
isBoxPlots
,
});
});
},
[
dateRange
,
dataConfig
,
deviceParams
,
chartType
,
lineDataType
,
completeInit
,
algorithmValue
]);
},
[
dateRange
,
dataConfig
,
deviceParams
,
chartType
,
lineDataType
,
completeInit
,
algorithmValue
,
timeFormatter
]);
const
handleChange
=
(
pagination
,
filter
,
sort
)
=>
{
if
(
sort
.
field
===
'time'
)
{
setTimeOrder
(
sort
.
order
);
}
};
const
tableMemo
=
useMemo
(()
=>
{
return
(
<>
return
(
<>
<
div
className
=
{
`
${
prefixCls
}
-options`
}
>
{
renderTimeOption
}
{
renderCurveOption
()}
<
/div
>
<
div
className
=
{
`
${
prefixCls
}
-content`
}
ref
=
{
tableRef
}
>
{
chartDataSource
.
length
>
0
?
(
// <BasicTable
{
chartDataSource
.
length
>
0
?
(
// <BasicTable
<
VirtualTable
className
=
{
`
${
prefixCls
}
-virtual-table`
}
theme
=
{
theme
}
...
...
@@ -1335,23 +1134,10 @@ const HistoryView = (props) => {
x
:
'max-content'
,
y
:
tableRef
.
current
?
tableRef
.
current
.
getBoundingClientRect
().
height
-
40
:
0
,
}}
/
>
)
:
(
<
PandaEmpty
/>
)}
/>
)
:
(
<PandaEmpty/
>
)}
<
/div
>
<
/
>
);
},
[
timeOrder
,
chartDataSource
,
columns
,
tableProps
,
tableData
,
isSingleStatusSensor
,
dateRange
,
tableRef
.
current
,
]);
<
/>
)
;
},
[
timeOrder
,
chartDataSource
,
columns
,
tableProps
,
tableData
,
isSingleStatusSensor
,
dateRange
,
tableRef
.
current
,
timeFormatter
]);
const
returnLongestPeriod
=
(
data
)
=>
{
let
_earliest
=
''
;
let
_latest
=
''
;
...
...
@@ -1374,24 +1160,15 @@ const HistoryView = (props) => {
};
const
renderPanel
=
(
model
)
=>
{
if
(
model
===
'curve'
)
{
return
(
<>
return
(
<>
<
div
className
=
{
`
${
prefixCls
}
-options`
}
>
{
renderTimeOption
}
{
renderCurveOption
(
true
,
deviceParams
?.
length
===
1
&&
deviceParams
?.[
0
]?.
sensors
?.
split
(
','
).
length
===
1
,
isSingleStatusSensor
,
)}
{
renderCurveOption
(
true
,
deviceParams
?.
length
===
1
&&
deviceParams
?.[
0
]?.
sensors
?.
split
(
','
).
length
===
1
,
isSingleStatusSensor
,)}
<
/div
>
{
lineDataType
===
'原始曲线'
&&
false
?
(
<
div
style
=
{{
marginTop
:
10
}}
>
展示区间:
{
returnLongestPeriod
(
chartDataSource
)}
<
/div
>
)
:
(
''
)}
<
div
style
=
{{
marginTop
:
10
}}
>
展示区间:
{
returnLongestPeriod
(
chartDataSource
)}
<
/div>
)
:
(
''
)
}
<
div
className
=
{
`
${
prefixCls
}
-content`
}
>
{
grid
===
true
?
(
<
GridChart
{
grid
===
true
?
(
<
GridChart
emptyOrError
=
{
emptyOrError
.
current
}
curveCenter
=
{
curveCenter
}
prefixCls
=
{
prefixCls
}
...
...
@@ -1404,9 +1181,7 @@ const HistoryView = (props) => {
allSensorType
=
{
allSensorType
}
loading
=
{
loading
}
setLoading
=
{
setLoading
}
/
>
)
:
(
<
SingleChart
/>
)
:
(
<SingleChar
t
exportCanvas
=
{{
exportFlag
,
setExportFlag
}}
emptyOrError
=
{
emptyOrError
.
current
}
dateRange
=
{
dateRange
}
...
...
@@ -1424,14 +1199,11 @@ const HistoryView = (props) => {
theme
=
{
theme
}
special
=
{{
special1
,
// 频率业务
allPointAddress
,
allSensorType
,
// 后续新增的开关量的特殊业务,用来处理开关量业务
allPointAddress
,
allSensorType
,
// 后续新增的开关量的特殊业务,用来处理开关量业务
}}
/
>
)}
/>
)
}
<
/div
>
<
/
>
);
<
/>
)
;
}
if
(
model
===
'table'
)
{
return
tableMemo
;
...
...
@@ -1439,66 +1211,37 @@ const HistoryView = (props) => {
};
// 获取字段配置
const
getDefaultOptions
=
async
()
=>
{
// 特定设备
// 这部分功能有问题,等待解决后上线 2024年3月13日
getDictionaryInfoAll
({
level
:
'离散算法设备类型'
,
}).
then
(
res
=>
{
if
(
res
.
code
===
0
&&
res
.
data
.
length
)
{
let
deviceType
=
res
.
data
.
find
(
item
=>
item
.
fieldName
===
'设备类型'
)?.
fieldValue
;
setDiscreteDeviceType
(
deviceType
.
split
(
','
).
filter
(
item
=>
item
))
}
})
let
_dictionaryList
=
await
searchDataDictionaryList
({
key
:
'组件_ec_historyview'
,
type
:
0
});
let
_item
=
_dictionaryList
?.
data
?.[
0
]
??
{}
let
_nodeID
=
_item
?.
nodeName
===
'组件_ec_historyview'
?
_dictionaryList
?.
data
?.[
0
]?.
nodeID
:
null
;
// 非单曲线、单指标不执行
if
(
deviceParams
?.
length
!==
1
||
(
deviceParams
?.
length
===
1
&&
deviceParams
?.[
0
]?.
sensors
?.
split
(
','
)?.
length
>
1
)
)
return
setCompleteInit
(
true
);
if
(
deviceParams
?.
length
!==
1
||
(
deviceParams
?.
length
===
1
&&
deviceParams
?.[
0
]?.
sensors
?.
split
(
','
)?.
length
>
1
))
return
setCompleteInit
(
true
);
setLoading
(
true
);
const
{
deviceCode
,
deviceType
,
sensors
}
=
deviceParams
[
0
];
let
_id
=
(
await
getPointAddress
({
let
_id
=
(
await
getPointAddress
({
code
:
deviceCode
,
})
)?.
data
?.[
0
]?.
id
;
}))?.
data
?.[
0
]?.
id
;
let
_params
=
{};
if
(
_id
)
_params
.
versionId
=
_id
;
// 多曲线的居中,容易导致曲线被截断,故多曲线时,不请求
let
_request0
=
getDictionaryInfoAll
({
level
:
'组件_ec_historyview'
,
let
_request0
=
_nodeID
?
getDataDictionaryList
({
nodeID
:
_nodeID
})
:
new
Promise
((
resolve
,
reject
)
=>
{
resolve
()
});
// 以下请求为处理状态值、开关值的图表,只允许单曲线单指标情况下展示
let
_request1
=
getPointAddressEntry
(
_params
);
let
_request2
=
getSensorType
();
// let _request3 = getPredicateSensor({deviceCode, sensors});
await
Promise
.
all
([
_request0
,
_request1
,
_request2
]).
then
((
result
)
=>
{
if
(
result
)
{
let
_res0
=
result
[
0
];
let
_res1
=
result
[
1
];
let
_res2
=
result
[
2
];
// let _res3 = result[3];
let
_checkboxData
=
[...
checkboxData
];
// 单设备单曲线时,查询是否配置为预测点
/* if (_res3.code === 0 && _res3.data) {
// 1. 如果是单曲线,并且配置了预测,那么默认开启预测;
// 2024年3月11日 物联预测功能支撑后,再开发这部分
_checkboxData.push({
key: 'predicate',
label: '数据预测',
checked: true,
showInCurve: true,
showInTable: true,
})
setPredicateDevice({..._res3.data, deviceType: '预测'});
} else {
setPredicateDevice(null);
}*/
// 查字典配置
if
(
_res0
.
code
===
0
)
{
if
(
_res0
?
.
code
===
0
)
{
let
_opt
=
_res0
.
data
.
reduce
((
final
,
cur
)
=>
{
final
[
cur
.
fieldName
]
=
cur
.
field
Value
;
final
[
cur
.
nodeName
]
=
cur
.
node
Value
;
return
final
;
},
{});
_checkboxData
=
_checkboxData
.
map
((
item
)
=>
{
...
...
@@ -1509,6 +1252,13 @@ const HistoryView = (props) => {
return
_item
;
});
setCheckboxData
(
_checkboxData
);
// 大数据量设备类型,例如:水厂
let
deviceType
=
_res0
.
data
.
find
(
item
=>
item
.
nodeName
===
'离散算法设备类型'
)?.
nodeValue
??
''
;
setDiscreteDeviceType
(
deviceType
.
split
(
','
).
filter
(
item
=>
item
));
let
_timeFormatter
=
_res0
.
data
.
find
(
item
=>
item
.
nodeName
===
'日期模式'
);
if
(
_timeFormatter
)
{
setTimeFormatter
(
_timeFormatter
.
nodeName
);
}
}
// 查点表配置
if
(
_res1
.
code
===
0
)
{
...
...
@@ -1519,8 +1269,7 @@ const HistoryView = (props) => {
let
_statusConfig
=
_res1
.
data
.
find
((
item
)
=>
item
?.
name
.
trim
()
===
_statusName
.
trim
());
let
_valDesc
=
_statusConfig
?.
valDesc
||
''
;
setSpecial1
({
name
:
_statusName
,
valDesc
:
_valDesc
.
split
(
';'
).
reduce
((
final
,
cur
)
=>
{
name
:
_statusName
,
valDesc
:
_valDesc
.
split
(
';'
).
reduce
((
final
,
cur
)
=>
{
let
_arr
=
cur
.
split
(
':'
);
final
[
_arr
[
0
]]
=
_arr
[
1
];
return
final
;
...
...
@@ -1559,25 +1308,17 @@ const HistoryView = (props) => {
}
else
{
clearInterval
(
percentTimer
.
current
.
timer
);
setPercent
(
100
);
setTimeout
(
()
=>
{
setTimeout
(()
=>
{
setPercent
(
0
);
},
lineDataType
===
'原始曲线'
?
500
:
0
,
);
},
lineDataType
===
'原始曲线'
?
500
:
0
,);
}
},
[
loading
]);
return
(
<
div
return
(
<
div
className
=
{
classNames
(
prefixCls
,
theme
===
'BI'
?
BIStyles
[
`
${
prefixCls
}
-historyViewComponents`
]
:
''
,
'wkt-scroll-light'
)}
style
=
{{
background
:
theme
===
'BI'
?
'#282b34'
:
'#ffffff'
}}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-spin`
)}
style
=
{{
position
:
'relative'
}}
>
{
loading
||
percent
!==
0
?
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-progressWrapper`
)}
>
{
lineDataType
===
'原始曲线'
||
(
lineDataType
===
'特征曲线'
&&
moment
(
dateRange
?.[
0
]?.
dateTo
).
diff
(
moment
(
dateRange
?.[
0
]?.
dateFrom
),
'days'
)
>=
30
)
?
{
loading
||
percent
!==
0
?
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-progressWrapper`
)}
>
{
lineDataType
===
'原始曲线'
||
(
lineDataType
===
'特征曲线'
&&
moment
(
dateRange
?.[
0
]?.
dateTo
).
diff
(
moment
(
dateRange
?.[
0
]?.
dateFrom
),
'days'
)
>=
30
)
?
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contentWrapper`
)}
>
<
Progress
percent
=
{
percent
}
...
...
@@ -1586,44 +1327,30 @@ const HistoryView = (props) => {
showInfo
=
{
false
}
/
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-tip`
)}
>
加载中
...
<
/div
>
<
/div>
:
<
Spin
spinning
=
{
loading
||
false
}
tip
=
{
'数据加载中...'
}
delay
=
{
1000
}
style
=
{{
background
:
'transparent'
}}
/
>
}
<
/div
>
)
:
(
''
)}
<
/div> : <Spin spinning={loading || false} tip={'数据加载中...'} delay=
{1000}
style
=
{{
background
:
'transparent'
}}
/>
}
<
/div>
)
:
(
''
)
}
{
showModels
.
length
===
1
&&
(
<
div
className
=
{
`
${
prefixCls
}
-single-panel`
}
>
{
renderPanel
(
showModels
[
0
])}
<
/div
>
)}
{
showModels
.
length
>
1
&&
(
<
Tabs
<
div
className
=
{
`
${
prefixCls
}
-single-panel`
}
>
{
renderPanel
(
showModels
[
0
])}
<
/div>
)
}
{
showModels
.
length
>
1
&&
(
<
Tabs
activeKey
=
{
activeTabKey
}
onChange
=
{(
key
)
=>
setActiveTabKey
(
key
)}
centered
tabBarExtraContent
=
{{
left
:
<
h3
>
{
title
}
<
/h3>
,
right
:
(
<
div
className
=
{
`
${
prefixCls
}
-extra-right`
}
>
{
activeTabKey
===
'table'
&&
(
<>
left
:
<
h3
>
{
title
}
<
/h3>, right:
(
<div className={`${prefixCls}-extra-right`}
>
{
activeTabKey
===
'table'
&&
(
<>
<
Button
type
=
"link"
onClick
=
{
exportFeatureBtn
}
>
<
DownloadOutlined
/>
下载
<
/Button
>
<
/
>
)}
{
activeTabKey
===
'curve'
&&
(
<>
<
/>
)
}
{
activeTabKey
===
'curve'
&&
(
<>
<
Button
type
=
"link"
onClick
=
{
exportCanvas
}
>
<
DownloadOutlined
/>
下载
<
/Button
>
<
/
>
)}
<
/div
>
),
<
/>
)
}
<
/div>
)
,
}}
>
<
Tabs
.
TabPane
key
=
"curve"
tab
=
"曲线"
forceRender
=
{
true
}
>
...
...
@@ -1632,11 +1359,9 @@ const HistoryView = (props) => {
<
Tabs
.
TabPane
key
=
"table"
tab
=
"表格"
>
{
renderPanel
(
'table'
)}
<
/Tabs.TabPane
>
<
/Tabs
>
)}
<
/div
>
<
/Tabs>
)
}
<
/div
>
)
<
/div>
)
};
HistoryView
.
propTypes
=
{
...
...
@@ -1644,14 +1369,12 @@ HistoryView.propTypes = {
title
:
PropTypes
.
string
,
defaultChecked
:
PropTypes
.
oneOf
([
'twelveHours'
,
'roundClock'
,
'oneWeek'
,
'oneMonth'
]),
tableProps
:
PropTypes
.
object
,
deviceParams
:
PropTypes
.
arrayOf
(
PropTypes
.
objectOf
({
deviceParams
:
PropTypes
.
arrayOf
(
PropTypes
.
objectOf
({
deviceCode
:
PropTypes
.
string
,
sensors
:
PropTypes
.
string
,
deviceType
:
PropTypes
.
string
,
pointAddressID
:
PropTypes
.
number
,
// 可选,配置了将会查询相关报警方案配置
}),
),
}),),
defaultModel
:
PropTypes
.
oneOf
([
'curve'
,
'table'
]),
showModels
:
PropTypes
.
arrayOf
(
PropTypes
.
oneOf
([
'curve'
,
'table'
])),
defaultDate
:
PropTypes
.
string
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment