Commit 7fa4df59 authored by 李纪文's avatar 李纪文

feat: 增加报警配置曲线弹框

parent 2f182887
...@@ -131,6 +131,7 @@ export default { ...@@ -131,6 +131,7 @@ export default {
'EC_ConfigurationView', 'EC_ConfigurationView',
'EC_HistoryView', 'EC_HistoryView',
'EC_StatisticalHistoryView', 'EC_StatisticalHistoryView',
'EC_AlarmCurve',
], ],
}, },
], ],
......
...@@ -168,18 +168,19 @@ ...@@ -168,18 +168,19 @@
"highcharts-react-official": "^3.0.0", "highcharts-react-official": "^3.0.0",
"install": "^0.13.0", "install": "^0.13.0",
"js-export-excel": "^1.1.4", "js-export-excel": "^1.1.4",
"js-sha256": "^0.10.1",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"less": "^3.13.1", "less": "^3.13.1",
"mathjs": "^12.2.0",
"mqtt-client": "^1.0.12", "mqtt-client": "^1.0.12",
"npm": "^9.6.4", "npm": "^9.6.4",
"optimize-css-assets-webpack-plugin": "^6.0.1", "optimize-css-assets-webpack-plugin": "^6.0.1",
"parseForm": "1.0.0", "parseForm": "1.0.0",
"rc-resize-observer": "1.4.0",
"react-redux": "^8.0.5", "react-redux": "^8.0.5",
"react-resizable": "^3.0.4", "react-resizable": "^3.0.4",
"sha1": "^1.1.1", "react-window": "1.8.9",
"js-sha256": "^0.10.1", "sha1": "^1.1.1"
"rc-resize-observer": "1.4.0",
"react-window": "1.8.9"
}, },
"size-limit": [ "size-limit": [
{ {
......
# `@wisdom-components/ec_alarmcurve`
> TODO: description
## Usage
```
const ecLimitCurve = require('@wisdom-components/ec_alarmcurve');
// TODO: DEMONSTRATE API
```
{
"name": "@wisdom-components/ec_alarmcurve",
"version": "1.0.0",
"description": "> TODO: description",
"author": "lijiwen <961370825@qq.com>",
"homepage": "",
"license": "ISC",
"sideEffects": [
"*.less"
],
"module": "es/index.js",
"main": "lib/index.js",
"files": [
"lib",
"es",
"dist"
],
"directories": {
"lib": "lib",
"es": "es",
"dist": "dist",
"test": "__tests__"
},
"publishConfig": {
"registry": "https://g.civnet.cn:4873/"
},
"repository": {
"type": "git",
"url": "https://g.civnet.cn:8443/ReactWeb5/wisdom-components.git"
},
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"@babel/runtime": "^7.17.9"
}
}
\ No newline at end of file
---
title: EC_LimitCurve - 报警曲线
nav:
title: 业务组件
path: /extend-components
group:
path: /
---
# EC_LimitCurve 报警曲线
基础业务组件
- 报警配置曲线查看
## 何时使用
- 在限制报警配置中使用。
## 代码演示
<code src="./demos/Basic.tsx">
## 何时使用
- 在经验报警配置中使用。
## 代码演示
<code src="./demos/Basic1.tsx">
## 何时使用
- 在预测报警配置中使用。
## 代码演示
<code src="./demos/Basic2.tsx">
## 限制报警API
| 参数 | 说明 | 类型 | 默认值 |
| ---- | ---- | ---- | ------ |
import { request } from '@wisdom-utils/utils';
const REQUEST_METHOD_GET = 'get';
const REQUEST_METHOD_POST = 'post';
// eslint-disable-next-line no-undef
const baseURI = typeof DUMI_TYPE !== 'undefined' && DUMI_TYPE === 'dumi' ? '/api' : '';
// 获取历史数据
export function getHistoryInfo(data) {
return request({
url: `${baseURI}/PandaMonitor/Monitor/Device/GetSensorsDataForStation`,
method: REQUEST_METHOD_POST,
data,
});
}
// 获取统计数据
export function getStatisticsInfo(data) {
return request({
url: `${baseURI}/PandaMonitor/Monitor/Device/EquipmentDataReports`,
method: REQUEST_METHOD_POST,
data,
});
}
\ No newline at end of file
import React from 'react';
import { LimitCurve } from '../index';
const Demos = () => {
return (
<>
<LimitCurve />
</>
);
};
export default Demos;
import React from 'react';
import {EmpiricalCurve} from '../index';
const Demos = () => {
return (
<>
<EmpiricalCurve />
</>
);
};
export default Demos;
import React from 'react';
import { PredictionCurve } from '../index';
const Demos = () => {
return (
<>
<PredictionCurve />
</>
);
};
export default Demos;
import React, { useContext } from 'react';
import { ConfigProvider } from 'antd';
import classNames from 'classnames';
import './index.less';
const EmpiricalCurve = () => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('empirical-curve');
return (
<>
<div className={classNames(`${prefixCls}`)}>经验报警</div>
</>
);
};
export default EmpiricalCurve;
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@tree-custom-prefix-cls: ~'@{ant-prefix}-empirical-curve';
.@{tree-custom-prefix-cls} {
background: red;
}
\ No newline at end of file
import LimitCurve from './limitCurve'; // 限制报警曲线
import EmpiricalCurve from './empiricalCurve'; // 经验报警曲线
import PredictionCurve from './predictionCurve'; // 预测曲线报警
export { LimitCurve, EmpiricalCurve, PredictionCurve };
import React, { useContext, useEffect, useRef, useState } from 'react';
import { ConfigProvider, Modal, Radio, Slider, InputNumber } from 'antd';
import classNames from 'classnames';
import moment from 'moment';
import { BasicChart } from '@wisdom-components/basicchart';
import { getHistoryInfo } from '../apis';
import { std,median } from 'mathjs';
import './index.less';
const LimitCurve = (props) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('limit-curve');
const { width, deviceCode, sensors, deviceType, getContainer, title } = props;
const [open, isOpen] = useState(true);
const [cluster, setCluster] = useState('K-means'); // 聚集算法
const [outlier, setOutlier] = useState(1); // 过滤异常
const [curve, setCurve] = useState('特征曲线'); // 曲线类型
const [sensitive, setSensitive] = useState(10); // 敏感度
const [stdVal, setStdVal] = useState(null); // 均方差
const [medianVal, setMedianVal] = useState(null); // 平均值
const [sensorData, setSensorData] = useState([]); // 所有数据
const [chartData, setChartData] = useState([]); // 图表数据
const [options, setOptions] = useState({});
const chartRef = useRef(null);
// 确定
const onOk = () => {
props.onOk && props.onOk(123);
};
// 取消
const onCancel = () => {};
// 获取历史数据
const getSensorsData = async () => {
const params = {
isDilute: true,
zoom: '',
unit: '',
dateFrom: moment().subtract(7, 'day').format('YYYY-MM-DD 00:00:00'),
dateTo: moment().format('YYYY-MM-DD 23:59:59'),
acrossTables: [
{ deviceCode: 'EGBF00000120', sensors: '出水瞬时流量', deviceType: '二供泵房' },
],
isBoxPlots: true,
};
const results = await getHistoryInfo(params);
const historyData = results?.data?.[0] || {};
const dataArr = historyData?.dataModel.map((item) => {
return item.pv;
});
setSensorData(() => {
setStdVal(std(dataArr));
setMedianVal(median(dataArr));
return historyData;
});
console.log(historyData, std(dataArr),median(dataArr));
};
useEffect(() => {
getSensorsData();
}, []);
useEffect(() => {
const {dataModel= []} = sensorData;
const range = {
min: medianVal - stdVal*outlier,
min: medianVal + stdVal*outlier,
}
const data = dataModel.map((item) => {
return item.pv >= range.min && item.pv<=range.max;
})
console.log(data);
}, [sensorData, cluster, outlier])
// useEffect(() => {
// const option = {
// xAxis: {},
// yAxis: {},
// series: [
// {
// symbolSize: 20,
// data: [
// [10.0, 8.04],
// [8.07, 6.95],
// [13.0, 7.58],
// [9.05, 8.81],
// [11.0, 8.33],
// [14.0, 7.66],
// [13.4, 6.81],
// [10.0, 6.33],
// [14.0, 8.96],
// [12.5, 6.82],
// [9.15, 7.2],
// [11.5, 7.2],
// [3.03, 4.23],
// [12.2, 7.83],
// [2.02, 4.47],
// [1.05, 3.33],
// [4.05, 4.96],
// [6.03, 7.24],
// [12.0, 6.26],
// [12.0, 8.84],
// [7.08, 5.82],
// [5.02, 5.68],
// ],
// type: 'scatter',
// },
// ],
// };
// setOptions(option);
// }, [sensorData]);
return (
<>
<Modal
title={`${sensors || ''}近7天历史数据`}
centered
okText={'确定'}
width={width || '1200px'}
cancelText={'取消'}
open={open}
onOk={onOk}
onCancel={onCancel}
wrapClassName={classNames(`${prefixCls}`)}
getContainer={getContainer || document.body}
>
<div className={classNames(`${prefixCls}-box`)}>
<div className={classNames(`${prefixCls}-header`)}>
<div className={classNames(`${prefixCls}-header-list`)}>
<span className={classNames(`${prefixCls}-header-item`)}>
聚类算法:
<Radio.Group
options={clusterArr}
optionType={'button'}
value={cluster}
onChange={(value) => {
setCluster(value);
}}
/>
</span>
<span className={classNames(`${prefixCls}-header-item`)}>
异常过滤:
<Radio.Group
options={outlierArr}
optionType={'button'}
value={outlier}
onChange={(value) => {
setOutlier(value);
}}
/>
</span>
<span className={classNames(`${prefixCls}-header-item`)}>
敏感度:
<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',
}}
addonAfter="%"
value={sensitive}
onChange={(value) => {
setSensitive(value);
}}
/>
</span>
</div>
<div className={classNames(`${prefixCls}-header-list`)}>
<span className={classNames(`${prefixCls}-header-item`)}>
曲线选择:
<Radio.Group
options={chartArr}
optionType={'button'}
value={curve}
onChange={(value) => {
setCurve(value);
}}
/>
</span>
</div>
</div>
<div className={classNames(`${prefixCls}-content`)}>
<BasicChart
ref={chartRef}
option={options}
notMerge
style={{ width: '100%', height: '100%' }}
/>
</div>
</div>
</Modal>
</>
);
};
const outlierArr = [
{
label: '低',
value: 1,
},
{
label: '中',
value: 2,
},
{
label: '高',
value: 3,
},
];
const clusterArr = [
{
label: 'K-means',
value: 'K-means',
},
];
const chartArr = [
{
label: '特征曲线',
value: '特征曲线',
},
{
label: '原始曲线',
value: '原始曲线',
},
];
export default LimitCurve;
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@tree-custom-prefix-cls: ~'@{ant-prefix}-limit-curve';
.@{tree-custom-prefix-cls} {
.@{ant-prefix}-modal-body {
height: 650px;
}
&-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
&-header {
flex: none;
&-list {
display: flex;
align-items: center;
width: 100%;
&:last-of-type {
margin-top: 10px;
}
}
&-item {
margin-right: 16px;
display: flex;
align-items: center;
justify-content: center;
}
}
&-content {
flex: 1;
overflow: hidden;
}
}
\ No newline at end of file
export const variance = (numbers) => {
let mean = 0;
let sum = 0;
for (const i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
mean = sum / numbers.length;
sum = 0;
for (const i = 0; i < numbers.length; i++) {
sum += Math.pow(numbers[i] - mean, 2);
}
return sum / numbers.length;
};
import React, { useContext } from 'react';
import { ConfigProvider } from 'antd';
import classNames from 'classnames';
import './index.less';
const PredictionCurve = () => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('prediction-curve');
return (
<>
<div className={classNames(`${prefixCls}`)}>预测报警</div>
</>
);
};
export default PredictionCurve;
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@tree-custom-prefix-cls: ~'@{ant-prefix}-prediction-curve';
.@{tree-custom-prefix-cls} {
background: red;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment