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
123dadab
Commit
123dadab
authored
Jan 12, 2024
by
李纪文
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 增加报警曲线设置
parent
599de965
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1022 additions
and
40 deletions
+1022
-40
index.js
packages/extend-components/EC_AlarmCurve/src/apis/index.js
+10
-0
Basic.tsx
packages/extend-components/EC_AlarmCurve/src/demos/Basic.tsx
+2
-1
Basic2.tsx
...ages/extend-components/EC_AlarmCurve/src/demos/Basic2.tsx
+27
-2
index.js
...onents/EC_AlarmCurve/src/limitCurve/historyTrend/index.js
+304
-0
index.less
...ents/EC_AlarmCurve/src/limitCurve/historyTrend/index.less
+43
-0
index copy.js
...end-components/EC_AlarmCurve/src/limitCurve/index copy.js
+0
-0
index.js
...s/extend-components/EC_AlarmCurve/src/limitCurve/index.js
+0
-0
index.less
...extend-components/EC_AlarmCurve/src/limitCurve/index.less
+26
-26
index.js
...nents/EC_AlarmCurve/src/limitCurve/intellectDraw/index.js
+324
-0
index.less
...nts/EC_AlarmCurve/src/limitCurve/intellectDraw/index.less
+68
-0
utils.js
...s/extend-components/EC_AlarmCurve/src/limitCurve/utils.js
+16
-6
index.js
...end-components/EC_AlarmCurve/src/predictionCurve/index.js
+142
-4
index.less
...d-components/EC_AlarmCurve/src/predictionCurve/index.less
+60
-1
No files found.
packages/extend-components/EC_AlarmCurve/src/apis/index.js
View file @
123dadab
...
...
@@ -21,4 +21,13 @@ export function getStatisticsInfo(data) {
method
:
REQUEST_METHOD_POST
,
data
,
});
}
// 获取节假日、工作日
export
function
getDateList
(
params
)
{
return
request
({
url
:
`
${
baseURI
}
/PandaMonitor/Monitor/Alert/GetDateList`
,
method
:
REQUEST_METHOD_GET
,
params
,
});
}
\ No newline at end of file
packages/extend-components/EC_AlarmCurve/src/demos/Basic.tsx
View file @
123dadab
...
...
@@ -6,8 +6,9 @@ const Demos = () => {
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
sensors
,
setSensors
]
=
useState
(
'出水瞬时流量'
);
const
onOk
=
()
=>
{
const
onOk
=
(
data
)
=>
{
setOpen
(
false
);
console
.
log
(
data
);
};
const
onCancel
=
()
=>
{
...
...
packages/extend-components/EC_AlarmCurve/src/demos/Basic2.tsx
View file @
123dadab
import
React
from
'react'
;
import
React
,
{
useState
}
from
'react'
;
import
{
PredictionCurve
}
from
'../index'
;
import
{
Button
}
from
'antd'
;
const
Demos
=
()
=>
{
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
sensors
,
setSensors
]
=
useState
(
'出水瞬时流量'
);
const
onOk
=
()
=>
{
setOpen
(
false
);
};
const
onCancel
=
()
=>
{
setOpen
(
false
);
};
return
(
<>
<
PredictionCurve
/>
<
Button
onClick=
{
()
=>
{
setOpen
(
true
);
}
}
>
打开预测曲线
</
Button
>
<
PredictionCurve
open=
{
open
}
onOk=
{
onOk
}
onCancel=
{
onCancel
}
deviceCode=
{
'EGBF00000120'
}
deviceType=
{
'二供泵房'
}
sensors=
{
sensors
}
/>
</>
);
};
...
...
packages/extend-components/EC_AlarmCurve/src/limitCurve/historyTrend/index.js
0 → 100644
View file @
123dadab
import
React
,
{
useContext
,
useEffect
,
useRef
,
useState
}
from
'react'
;
import
{
ConfigProvider
,
Radio
,
Slider
,
InputNumber
,
Input
}
from
'antd'
;
import
classNames
from
'classnames'
;
import
moment
from
'moment'
;
import
{
BasicChart
}
from
'@wisdom-components/basicchart'
;
import
{
getHistoryInfo
,
getDateList
}
from
'../../apis'
;
import
{
timeArr
}
from
'../utils'
;
import
'./index.less'
;
const
HistoryTrend
=
(
props
)
=>
{
const
{
getPrefixCls
}
=
useContext
(
ConfigProvider
.
ConfigContext
);
const
prefixCls
=
getPrefixCls
(
'history-trend'
);
const
{
deviceCode
,
sensors
,
deviceType
,
changeSpin
}
=
props
;
const
chartRef
=
useRef
(
null
);
const
[
sensitive
,
setSensitive
]
=
useState
(
10
);
// 敏感度
const
[
timeType
,
setTimeType
]
=
useState
(
'近7日'
);
// 时间
const
[
timeData
,
setTimeData
]
=
useState
([]);
// 时间
const
[
sensorData
,
setSensorData
]
=
useState
([]);
// 所有数据
const
[
ruleData
,
setRuleData
]
=
useState
([]);
// 预测数据
const
[
options
,
setOptions
]
=
useState
({});
// 日期处理
const
dateMethod
=
async
()
=>
{
const
arr
=
new
Array
(
7
).
fill
(
'list'
);
let
data
=
arr
.
map
((
item
,
index
)
=>
{
return
moment
()
.
subtract
(
index
+
1
,
'day'
)
.
format
(
'YYYY-MM-DD'
);
});
switch
(
timeType
)
{
case
'7工作日'
:
const
dateList1
=
await
getDateList
({
n
:
7
,
isHoliday
:
false
,
date
:
moment
().
subtract
(
1
,
'day'
).
format
(
'YYYY-MM-DD'
),
});
setTimeData
(
dateList1
?.
data
||
[]);
break
;
case
'7节假日'
:
const
dateList2
=
await
getDateList
({
n
:
7
,
isHoliday
:
false
,
date
:
moment
().
subtract
(
1
,
'day'
).
format
(
'YYYY-MM-DD'
),
});
setTimeData
(
dateList2
?.
data
||
[]);
break
;
default
:
setTimeData
([
data
.
join
(
','
)]);
break
;
}
};
// 获取历史数据
const
getSensorsData
=
async
()
=>
{
changeSpin
(
true
);
if
(
!
timeData
.
length
)
return
setOptions
({});
const
reqs
=
[];
timeData
.
forEach
((
item
)
=>
{
const
list
=
item
.
split
(
','
);
const
params
=
{
isDilute
:
true
,
zoom
:
'5'
,
unit
:
'min'
,
dateFrom
:
moment
(
list
[
list
.
length
-
1
]).
format
(
'YYYY-MM-DD 00:00:00'
),
dateTo
:
moment
(
list
[
0
]).
format
(
'YYYY-MM-DD 23:59:59'
),
acrossTables
:
[{
deviceCode
:
deviceCode
,
sensors
:
sensors
,
deviceType
:
deviceType
}],
isBoxPlots
:
true
,
ignoreOutliers
:
true
,
};
const
req
=
getHistoryInfo
(
params
);
reqs
.
push
(
req
);
});
Promise
.
all
(
reqs
).
then
((
results
)
=>
{
changeSpin
(
false
);
let
historyData
=
[];
results
.
forEach
((
result
)
=>
{
const
_historyData
=
result
?.
data
?.[
0
]?.
dataModel
||
[];
historyData
=
historyData
.
concat
([...
_historyData
]);
});
console
.
log
(
historyData
);
setSensorData
(()
=>
{
dataMonthod
(
historyData
);
return
historyData
;
});
});
};
// 数据处理
const
dataMonthod
=
(
data
)
=>
{
let
timeDatas
=
[];
const
chartData
=
[];
const
strTime
=
moment
().
format
(
'YYYY-MM-DD'
);
timeData
.
forEach
((
item
)
=>
{
const
list
=
item
.
split
(
','
);
timeDatas
=
timeDatas
.
concat
([...
list
]);
});
timeDatas
.
forEach
((
item
)
=>
{
const
seriesData
=
data
.
filter
((
list
)
=>
{
return
list
.
pt
.
indexOf
(
item
)
>
-
1
;
});
const
series
=
{
type
:
'line'
,
name
:
item
,
smooth
:
true
,
areaStyle
:
{},
data
:
seriesData
.
map
((
list
)
=>
{
const
pv
=
new
Date
(
moment
(
list
[
'pt'
]).
format
(
strTime
+
' HH:mm:ss'
)).
getTime
();
return
[
pv
,
list
[
'pv'
]];
}),
};
chartData
.
push
(
series
);
});
renderChart
(
chartData
);
};
// 渲染图表
const
renderChart
=
(
chartData
)
=>
{
const
option
=
{
xAxis
:
{
type
:
'time'
,
axisTick
:
{
alignWithLabel
:
true
,
},
axisLabel
:
{
formatter
:
(
value
)
=>
{
return
moment
(
value
).
format
(
'HH:mm:ss'
);
},
},
boundaryGap
:
false
,
},
yAxis
:
{
type
:
'value'
,
name
:
'm'
,
position
:
'left'
,
alignTicks
:
true
,
axisLabel
:
{
formatter
:
'{value}'
,
},
},
tooltip
:
{
formatter
:
function
(
params
)
{
const
title
=
moment
(
params
[
0
].
axisValue
).
format
(
'HH:mm:ss'
);
let
html
=
`<div style="border-bottom: 1px solid #F0F0F0;color: #808080;margin-bottom: 5px;padding-bottom: 5px;">
${
title
}
</div><div>`
;
params
.
forEach
((
item
)
=>
{
html
+=
`<span style="display: inline-block;margin: 0 7px 2px 0;border-radius: 5px;width: 5px;height: 5px;background:
${
item
.
color
}
;"></span>
${
item
.
seriesName
}
:<span style="color:
${
item
.
color
}
">
${
item
.
data
[
1
]}
</span><br />`
;
});
return
html
;
},
},
series
:
chartData
,
};
setOptions
(
option
);
};
// 限值处理
const
limitMethod
=
()
=>
{
const
pvArr
=
sensorData
.
map
((
item
)
=>
{
return
item
.
pv
;
});
let
max
=
Math
.
max
(...
pvArr
);
let
min
=
Math
.
min
(...
pvArr
);
console
.
log
(
max
,
min
);
const
data
=
[
(
min
*
(
1
-
sensitive
/
100
)).
toFixed
(
2
)
*
1
,
(
min
*
(
1
+
sensitive
/
100
)).
toFixed
(
2
)
*
1
,
(
max
*
(
1
-
sensitive
/
100
)).
toFixed
(
2
)
*
1
,
(
max
*
(
1
+
sensitive
/
100
)).
toFixed
(
2
)
*
1
,
];
const
color
=
[
'#CB2D2D'
,
'#0087F7'
];
const
name
=
[
'低低限'
,
'低限'
,
'高限'
,
'高高限'
];
const
mark
=
name
.
map
((
item
,
index
)
=>
{
return
{
name
:
item
,
yAxis
:
data
[
index
],
lineStyle
:
{
color
:
color
[
index
%
2
],
type
:
'dashed'
,
},
label
:
{
color
:
color
[
index
%
2
],
},
};
});
let
option
=
{
...
options
};
option
.
series
[
0
].
markLine
=
{
data
:
mark
,
};
setOptions
(
option
);
setRuleData
(
data
);
props
.
backData
(
data
);
};
useEffect
(()
=>
{
getSensorsData
();
// eslint-disable-next-line react-hooks/exhaustive-deps
},
[
timeData
]);
useEffect
(()
=>
{
dateMethod
();
},
[
timeType
]);
useEffect
(()
=>
{
if
(
options
?.
series
?.
length
&&
sensorData
.
length
)
limitMethod
();
},
[
sensitive
,
sensorData
]);
return
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-header`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-list`
)}
>
<
span
>
参考依据:
<
/span
>
<
Radio
.
Group
options
=
{
timeArr
}
optionType
=
{
'button'
}
value
=
{
timeType
}
onChange
=
{(
e
)
=>
{
setTimeType
(
e
.
target
.
value
);
}}
/
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-list`
)}
>
<
span
>
建议取值:
<
/span
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-read`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
value
=
{
ruleData
[
0
]}
addonBefore
=
"低低限"
disabled
/>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
value
=
{
ruleData
[
1
]}
addonBefore
=
"低限"
disabled
/>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
value
=
{
ruleData
[
2
]}
addonBefore
=
"高限"
disabled
/>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
value
=
{
ruleData
[
3
]}
addonBefore
=
"高高限"
disabled
/>
<
/div
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-range`
)}
>
允许浮动范围:
<
Slider
min
=
{
0
}
max
=
{
100
}
style
=
{{
width
:
'100px'
}}
onChange
=
{(
value
)
=>
{
setSensitive
(
value
);
}}
value
=
{
typeof
sensitive
===
'number'
?
sensitive
:
0
}
/
>
<
InputNumber
min
=
{
1
}
max
=
{
100
}
style
=
{{
margin
:
'0 16px'
,
width
:
'100px'
,
}}
formatter
=
{(
value
)
=>
`
${
value
}
%`
}
value
=
{
sensitive
}
onChange
=
{(
value
)
=>
{
setSensitive
(
value
);
}}
/
>
<
/div
>
<
/div
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-chart`
)}
>
<
BasicChart
ref
=
{
chartRef
}
option
=
{
options
}
notMerge
style
=
{{
width
:
'100%'
,
height
:
'100%'
}}
/
>
<
/div
>
<
/div
>
);
};
export
default
HistoryTrend
;
packages/extend-components/EC_AlarmCurve/src/limitCurve/historyTrend/index.less
0 → 100644
View file @
123dadab
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@tree-custom-prefix-cls: ~'@{ant-prefix}-history-trend';
.@{tree-custom-prefix-cls} {
height: 100%;
display: flex;
flex-direction: column;
&-header {
flex: none;
}
&-list {
display: flex;
margin-bottom: 10px;
align-items: center;
}
&-read {
display: flex;
align-items: center;
}
&-range {
display: flex;
align-items: center;
}
&-value {
margin-right: 10px;
.@{ant-prefix}-input[disabled] {
background-color: #ffffff;
}
}
&-chart {
flex: 1;
overflow: hidden;
}
}
\ No newline at end of file
packages/extend-components/EC_AlarmCurve/src/limitCurve/index copy.js
0 → 100644
View file @
123dadab
This diff is collapsed.
Click to expand it.
packages/extend-components/EC_AlarmCurve/src/limitCurve/index.js
View file @
123dadab
This diff is collapsed.
Click to expand it.
packages/extend-components/EC_AlarmCurve/src/limitCurve/index.less
View file @
123dadab
...
...
@@ -3,10 +3,6 @@
@tree-custom-prefix-cls: ~'@{ant-prefix}-limit-curve';
.@{tree-custom-prefix-cls} {
.@{ant-prefix}-modal-body {
height: 650px;
}
&-box {
width: 100%;
height: 100%;
...
...
@@ -15,38 +11,42 @@
position: relative;
}
&-header {
flex: none;
&-title {
display: flex;
width: 100%;
height: 100%;
position: relative;
&-list {
display: flex;
align-items: center;
width: 100%;
&-name {
position: absolute;
left: 0;
font-size: 16px;
}
&:last-of-typ
e {
margin-top: 10px
;
}
&-operat
e {
position: absolute
;
right: 0;
}
&-item {
margin-right: 16px;
display: flex;
align-items: center;
justify-content: center;
.@{ant-prefix}-tabs {
width: 100%;
}
&-value {
margin-right: 10px;
.@{ant-prefix}-tabs-content {
height: 100%;
}
.@{ant-prefix}-input[disabled] {
background-color: #ffffff;
}
.@{ant-prefix}-btn {
margin-left: 10px;
}
}
&-content {
flex: 1;
overflow: hidden;
.@{ant-prefix}-modal-body {
height: 650px;
}
.@{ant-prefix}-tabs-tabpane-active {
height: 100%;
}
&-load {
...
...
packages/extend-components/EC_AlarmCurve/src/limitCurve/intellectDraw/index.js
0 → 100644
View file @
123dadab
import
React
,
{
useContext
,
useEffect
,
useRef
,
useState
}
from
'react'
;
import
{
ConfigProvider
,
Modal
,
Radio
,
Slider
,
InputNumber
,
Input
,
Button
}
from
'antd'
;
import
classNames
from
'classnames'
;
import
moment
from
'moment'
;
import
{
BasicChart
}
from
'@wisdom-components/basicchart'
;
import
{
getHistoryInfo
}
from
'../../apis'
;
import
{
std
}
from
'mathjs'
;
import
skmeans
from
'skmeans'
;
import
{
outlierArr
,
timeArr
,
chartArr
,
average
,
markArr
}
from
'../utils'
;
import
'./index.less'
;
const
IntellectDraw
=
(
props
)
=>
{
const
{
getPrefixCls
}
=
useContext
(
ConfigProvider
.
ConfigContext
);
const
prefixCls
=
getPrefixCls
(
'intellect-draw'
);
const
{
deviceCode
,
sensors
,
deviceType
,
changeSpin
}
=
props
;
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
outlier
,
setOutlier
]
=
useState
(
3
);
// 过滤异常
const
[
sensorData
,
setSensorData
]
=
useState
([]);
// 所有数据
const
[
chartData
,
setChartData
]
=
useState
([]);
// 图表数据
const
[
sensitive
,
setSensitive
]
=
useState
(
10
);
// 敏感度
const
[
timeCycle
,
setTimeCycle
]
=
useState
(
60
);
const
[
timeDan
,
setTimeDan
]
=
useState
(
1
);
const
[
options
,
setOptions
]
=
useState
({});
const
chartRef
=
useRef
(
null
);
// 确定
const
onOk
=
()
=>
{
props
.
onOk
&&
props
.
onOk
(
123
);
};
// 取消
const
onCancel
=
()
=>
{
setOpen
(
false
);
props
.
onCancel
&&
props
.
onCancel
();
};
// 获取历史数据
const
getSensorsData
=
async
()
=>
{
changeSpin
(
true
);
const
params
=
{
isDilute
:
true
,
zoom
:
''
,
unit
:
''
,
dateFrom
:
moment
().
subtract
(
8
,
'day'
).
format
(
'YYYY-MM-DD 00:00:00'
),
dateTo
:
moment
().
subtract
(
1
,
'day'
).
format
(
'YYYY-MM-DD 23:59:59'
),
acrossTables
:
[{
deviceCode
:
deviceCode
,
sensors
:
sensors
,
deviceType
:
deviceType
}],
isBoxPlots
:
true
,
};
const
results
=
await
getHistoryInfo
(
params
);
changeSpin
(
false
);
const
historyData
=
results
?.
data
?.[
0
]
||
{};
setSensorData
(()
=>
{
return
historyData
;
});
};
// 图表数据处理
const
chartDataHandle
=
(
data
)
=>
{
const
times
=
moment
().
subtract
(
1
,
'day'
).
format
(
'YYYY-MM-DD'
);
const
chart
=
data
.
map
((
item
)
=>
{
return
{
...
item
,
time
:
moment
(
item
.
pt
).
format
(
times
+
' HH:mm:ss'
),
};
});
return
chart
;
};
// 聚集方法
const
clusteredMothod
=
()
=>
{};
// 渲染图表
const
renderChart
=
(
_chartData
)
=>
{
const
chartDatas
=
_chartData
.
map
((
item
)
=>
{
return
[
new
Date
(
item
.
time
).
getTime
(),
item
.
pv
];
});
const
clustered
=
skmeans
(
chartDatas
,
24
);
const
{
centroids
=
[]
}
=
clustered
;
const
_centroids
=
centroids
.
sort
((
a
,
b
)
=>
{
return
a
[
0
]
-
b
[
0
];
});
console
.
log
(
_centroids
);
const
option
=
{
xAxis
:
{
type
:
'time'
,
axisTick
:
{
alignWithLabel
:
true
,
},
boundaryGap
:
false
,
splitLine
:
{
show
:
true
,
lineStyle
:
{
type
:
'dashed'
,
},
},
},
yAxis
:
{
type
:
'value'
,
name
:
'm'
,
position
:
'left'
,
alignTicks
:
true
,
axisLine
:
{
show
:
true
,
},
axisLabel
:
{
formatter
:
'{value}'
,
},
},
series
:
[
{
type
:
'scatter'
,
name
:
sensors
,
sampling
:
'average'
,
large
:
true
,
symbolSize
:
5
,
data
:
_chartData
.
map
((
item
)
=>
{
return
[
new
Date
(
item
.
time
).
getTime
(),
item
.
pv
];
}),
},
{
type
:
'line'
,
name
:
sensors
,
sampling
:
'average'
,
large
:
true
,
data
:
_centroids
.
map
((
item
)
=>
{
return
[
Math
.
floor
(
item
[
0
]),
item
[
1
]];
}),
},
],
};
setOptions
(
option
);
};
const
proposeRender
=
()
=>
{
return
(
<>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-propose-list`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-propose-value`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value-list`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
addonBefore
=
"低低限"
disabled
/>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value-list`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
addonBefore
=
"低限"
disabled
/>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value-list`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
addonBefore
=
"高限"
disabled
/>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-value-list`
)}
>
<
Input
style
=
{{
width
:
'150px'
,
}}
addonBefore
=
"高高限"
disabled
/>
<
/div
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-propose-range`
)}
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
允许浮动范围:
<
/span
>
<
Slider
min
=
{
0
}
max
=
{
100
}
style
=
{{
width
:
'100px'
}}
onChange
=
{(
value
)
=>
{
setSensitive
(
value
);
}}
value
=
{
typeof
sensitive
===
'number'
?
sensitive
:
0
}
/
>
<
InputNumber
min
=
{
1
}
max
=
{
100
}
style
=
{{
margin
:
'0 16px'
,
width
:
'100px'
,
}}
formatter
=
{(
value
)
=>
`
${
value
}
%`
}
value
=
{
sensitive
}
onChange
=
{(
value
)
=>
{
setSensitive
(
value
);
}}
/
>
<
/div
>
<
/div
>
<
/
>
);
};
useEffect
(()
=>
{
open
&&
getSensorsData
();
// eslint-disable-next-line react-hooks/exhaustive-deps
},
[
open
]);
useEffect
(()
=>
{
const
{
dataModel
=
[]
}
=
sensorData
;
if
(
!
dataModel
.
length
)
return
setChartData
([]);
const
count
=
Math
.
floor
((
24
*
60
)
/
timeCycle
);
const
times
=
moment
().
subtract
(
1
,
'day'
).
format
(
'YYYY-MM-DD'
);
const
_dataModel
=
dataModel
.
map
((
item
)
=>
{
return
{
...
item
,
time
:
moment
(
item
.
pt
).
format
(
times
+
' HH:mm:ss'
),
};
});
const
_chartData
=
[];
const
_clustered
=
[];
for
(
let
i
=
0
;
i
<
count
;
i
++
)
{
const
data
=
_dataModel
.
filter
((
item
)
=>
{
const
time
=
new
Date
(
item
.
time
).
getTime
();
const
min
=
new
Date
(
moment
(
times
+
' 00:00:00'
).
add
(
i
*
timeCycle
,
'minute'
)).
getTime
();
const
max
=
new
Date
(
moment
(
times
+
' 00:00:00'
).
add
((
i
+
1
)
*
timeCycle
,
'minute'
),
).
getTime
();
return
time
&&
time
>=
min
&&
max
>=
time
;
});
const
clusteredArr
=
[];
const
dataArr
=
[];
const
pvArr
=
data
.
map
((
item
)
=>
{
return
item
.
pv
;
});
const
stdVal
=
pvArr
.
length
?
std
(
pvArr
)
:
0
;
const
medianVal
=
pvArr
.
length
?
average
(
pvArr
)
:
0
;
const
range
=
{
min
:
medianVal
-
outlier
*
stdVal
,
max
:
medianVal
+
outlier
*
stdVal
,
};
data
.
forEach
((
item
)
=>
{
if
(
item
.
pv
>=
range
.
min
&&
item
.
pv
<=
range
.
max
)
dataArr
.
push
(
item
);
clusteredArr
.
push
([
new
Date
(
item
.
time
).
getTime
(),
item
.
pv
]);
});
const
clustered
=
clusteredArr
.
length
?
skmeans
(
clusteredArr
,
1
)
:
{};
const
{
centroids
=
[]
}
=
clustered
;
_chartData
.
push
(...
dataArr
);
_clustered
.
push
(...
centroids
);
}
renderChart
(
_chartData
,
_clustered
);
// eslint-disable-next-line react-hooks/exhaustive-deps
},
[
sensorData
,
outlier
]);
useEffect
(()
=>
{
setOpen
(
props
.
open
);
},
[
props
.
open
]);
return
(
<>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-header`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-list`
)}
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-item`
)}
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
异常值剔除:
<
/span
>
<
Slider
marks
=
{
markArr
}
step
=
{
null
}
style
=
{{
width
:
'200px'
,
}}
defaultValue
=
{
1
}
onChange
=
{(
value
)
=>
{
console
.
log
(
outlierArr
);
setOutlier
(
outlierArr
[
value
]?.
value
||
0
);
}}
min
=
{
0
}
max
=
{
3
}
tooltip
=
{{
formatter
:
(
value
)
=>
{
return
markArr
[
value
];
},
}}
/
>
<
/span
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-item`
)}
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
限值时段个数:
<
/span
>
<
InputNumber
min
=
{
1
}
max
=
{
10
}
style
=
{{
width
:
'100px'
,
}}
value
=
{
timeDan
}
onChange
=
{(
value
)
=>
{
setTimeDan
(
value
);
}}
/
>
<
/span
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-propose`
)}
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
建议限值:
<
/span
>
{
proposeRender
()}
<
/div
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-chart`
)}
>
<
BasicChart
ref
=
{
chartRef
}
option
=
{
options
}
notMerge
style
=
{{
width
:
'100%'
,
height
:
'100%'
}}
/
>
<
/div
>
<
/div
>
<
/
>
);
};
export
default
IntellectDraw
;
packages/extend-components/EC_AlarmCurve/src/limitCurve/intellectDraw/index.less
0 → 100644
View file @
123dadab
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@tree-custom-prefix-cls: ~'@{ant-prefix}-intellect-draw';
.@{tree-custom-prefix-cls} {
height: 100%;
display: flex;
flex-direction: column;
&-header {
flex: none;
}
&-list {
display: flex;
margin-bottom: 10px;
align-items: center;
}
&-label {
display: flex;
height: 32px;
align-items: center;
}
&-item {
display: flex;
align-items: center;
margin-right: 20px;
}
.@{ant-prefix}-modal-body {
height: 650px;
}
&-propose {
display: flex;
}
&-propose-list {
display: flex;
align-items: center;
}
&-value-list {
margin-right: 10px;
.@{ant-prefix}-input[disabled] {
background-color: #ffffff;
}
}
&-propose-value {
display: flex;
align-items: center;
}
&-propose-range {
display: flex;
align-items: center;
}
&-chart {
flex: 1;
overflow: hidden;
}
}
\ No newline at end of file
packages/extend-components/EC_AlarmCurve/src/limitCurve/utils.js
View file @
123dadab
export
const
outlierArr
=
[
{
label
:
'关'
,
value
:
0
,
},
{
label
:
'低'
,
value
:
3
,
...
...
@@ -13,17 +17,24 @@ export const outlierArr = [
},
];
export
const
markArr
=
{
0
:
'关'
,
1
:
'低'
,
2
:
'中'
,
3
:
'高'
,
};
export
const
timeArr
=
[
{
label
:
'近7
天
'
,
value
:
'近7
天
'
,
label
:
'近7
日特征曲线
'
,
value
:
'近7
日
'
,
},
{
label
:
'7工作日'
,
label
:
'7工作日
特征曲线
'
,
value
:
'7工作日'
,
},
{
label
:
'7节假日'
,
label
:
'7节假日
特征曲线
'
,
value
:
'7节假日'
,
},
];
...
...
@@ -42,4 +53,4 @@ export const chartArr = [
// 平均值方法
export
const
average
=
(
arr
)
=>
{
return
arr
.
reduce
((
acc
,
cur
)
=>
acc
+
cur
,
0
)
/
arr
.
length
;
};
\ No newline at end of file
};
packages/extend-components/EC_AlarmCurve/src/predictionCurve/index.js
View file @
123dadab
import
React
,
{
useContext
}
from
'react'
;
import
{
ConfigProvider
}
from
'antd'
;
import
React
,
{
useContext
,
useEffect
,
useRef
,
useState
}
from
'react'
;
import
{
ConfigProvider
,
Modal
,
Radio
,
Slider
,
InputNumber
,
Input
,
Button
,
Tabs
,
Select
,
}
from
'antd'
;
import
classNames
from
'classnames'
;
import
LoadBox
from
'@wisdom-components/loadbox'
;
import
'./index.less'
;
const
PredictionCurve
=
()
=>
{
const
PredictionCurve
=
(
props
)
=>
{
const
{
getPrefixCls
}
=
useContext
(
ConfigProvider
.
ConfigContext
);
const
prefixCls
=
getPrefixCls
(
'prediction-curve'
);
const
{
width
,
deviceCode
,
sensors
,
deviceType
,
getContainer
,
title
}
=
props
;
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
spinning
,
setSpinning
]
=
useState
(
false
);
const
[
sensitive
,
setSensitive
]
=
useState
(
10
);
// 波动幅度
// 确定
const
onOk
=
()
=>
{
props
.
onOk
&&
props
.
onOk
(
123
);
};
// 取消
const
onCancel
=
()
=>
{
setOpen
(
false
);
props
.
onCancel
&&
props
.
onCancel
();
};
// spin控制
const
changeSpin
=
(
flag
)
=>
{
setSpinning
(
flag
);
};
const
renderTitle
=
()
=>
{
return
(
<>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-title`
)}
>
<
span
className
=
{
classNames
(
`
${
prefixCls
}
-title-name`
)}
>
预测算法预览
<
/span
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-title-operate`
)}
>
<
Button
onClick
=
{
onCancel
}
>
取消
<
/Button
>
<
Button
type
=
{
'primary'
}
onClick
=
{
onOk
}
>
确定
<
/Button
>
<
/div
>
<
/div
>
<
/
>
);
};
useEffect
(()
=>
{},
[
open
]);
useEffect
(()
=>
{
setOpen
(
props
.
open
);
},
[
props
.
open
]);
return
(
<>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
`
)}
>
预测报警
<
/div
>
<
Modal
closable
=
{
false
}
centered
width
=
{
width
||
'1200px'
}
footer
=
{
null
}
open
=
{
open
}
onOk
=
{
onOk
}
onCancel
=
{
onCancel
}
wrapClassName
=
{
classNames
(
`
${
prefixCls
}
`
)}
getContainer
=
{
getContainer
||
document
.
body
}
destroyOnClose
=
{
true
}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-box`
)}
>
{
renderTitle
()}
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-info`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-list`
)}
>
<
span
>
预测算法:
<
/span
>
<
Select
defaultValue
=
"滑动平均值"
style
=
{{
width
:
120
,
}}
onChange
=
{()
=>
{}}
options
=
{[
{
value
:
'滑动平均值'
,
label
:
'滑动平均值'
,
},
]}
/
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-list`
)}
>
<
span
>
预测模型:
<
/span
>
<
Select
defaultValue
=
"M1"
style
=
{{
width
:
120
,
}}
onChange
=
{()
=>
{}}
options
=
{[
{
value
:
'M1'
,
label
:
'M1'
,
},
]}
/
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-list`
)}
>
<
span
>
预测准确度
(
参考
)
:
<
/span
>
<
span
>
{
97
}
%<
/span
>
<
/div
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-info`
)}
>
允许波动幅度:
<
Slider
min
=
{
0
}
max
=
{
100
}
style
=
{{
width
:
'100px'
}}
onChange
=
{(
value
)
=>
{
setSensitive
(
value
);
}}
value
=
{
typeof
sensitive
===
'number'
?
sensitive
:
0
}
/
>
<
InputNumber
min
=
{
1
}
max
=
{
100
}
style
=
{{
margin
:
'0 16px'
,
width
:
'100px'
,
}}
formatter
=
{(
value
)
=>
`
${
value
}
%`
}
value
=
{
sensitive
}
onChange
=
{(
value
)
=>
{
setSensitive
(
value
);
}}
/
>
<
/div
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-chart`
)}
><
/div
>
{
spinning
&&
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-load`
)}
>
<
LoadBox
spinning
=
{
spinning
}
/
>
<
/div
>
)}
<
/div
>
<
/Modal
>
<
/
>
);
};
...
...
packages/extend-components/EC_AlarmCurve/src/predictionCurve/index.less
View file @
123dadab
...
...
@@ -3,5 +3,63 @@
@tree-custom-prefix-cls: ~'@{ant-prefix}-prediction-curve';
.@{tree-custom-prefix-cls} {
background: red;
&-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}
.@{ant-prefix}-modal-body {
height: 650px;
}
&-title {
display: flex;
width: 100%;
flex: none;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 10px;
margin-bottom: 20px;
&-name {
font-size: 16px;
}
.@{ant-prefix}-btn {
margin-left: 10px;
}
}
&-info {
display: flex;
align-items: center;
margin-bottom: 10px;
}
&-list {
margin-right: 20px;
}
&-chart {
flex: 1;
width: 100%;
overflow: hidden;
}
&-load {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.9);
z-index: 100;
}
}
\ No newline at end of file
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