Commit bc1dfb66 authored by 刘梦焕's avatar 刘梦焕

feat: 新增经验报警曲线

parent 65e26fda
import React from 'react'; import React, { useState } from 'react';
import {EmpiricalCurve} from '../index'; import { Button } from 'antd';
import { EmpiricalCurve } from '../index';
const Demos = () => { const Demos = () => {
const [visible, setVisible] = useState(false);
const deviceParams = {
deviceCode: 'EGBF00000120',
sensors: '出水瞬时流量',
deviceType: '二供泵房',
title: '经验报警曲线',
visible,
onClose: () => {
setVisible(false);
},
};
return ( return (
<> <>
<EmpiricalCurve /> {visible && <EmpiricalCurve {...deviceParams} />}
<Button onClick={() => setVisible(true)}>打开经验报警曲线</Button>
</> </>
); );
}; };
......
import React, { useContext } from 'react'; import React, { useContext, useEffect, useRef, useState, useMemo } from 'react';
import { ConfigProvider } from 'antd'; import { ConfigProvider, Modal, Radio, Select, InputNumber, Spin, message } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { BasicChart } from '@wisdom-components/basicchart';
import { getStatisticsInfo } from '../apis';
import { getOptions, experiTypeOptions, compareOptions, valTakeOptions } from './utils';
import moment from 'moment';
import _ from 'lodash';
import './index.less'; import './index.less';
const EmpiricalCurve = () => { const FORMAT = 'yyyy-MM-DD HH:mm:ss';
const PredictionCurve = (props) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('empirical-curve'); const prefixCls = getPrefixCls('empirical-curve');
const {
width,
deviceCode,
sensors,
deviceType,
getContainer,
title,
visible,
onClose,
valTakeType = '按偏移量',
compareType = '同比',
experiType = 'h',
highLimit = 2,
higherLimit = 0,
} = props;
const [loading, setLoading] = useState(false);
const [experiVal, setExperiVal] = useState(experiType); // 经验值类型
const [compareVal, setCompareVal] = useState(compareType); // 对比目标
const [valTake, setValTake] = useState(valTakeType); // 取值方式
const [realData, setRealData] = useState([]); // 原始数据
const [compareData, setCompareData] = useState([]); // 对比数据
const [highLimitVal, setHighLimitVal] = useState(highLimit); // 高限值
const [higherLimitVal, setHigherLimitVal] = useState(higherLimit); // 高限值
const [sensorData, setSensorData] = useState({ sensorName: sensors }); // 指标配置数据
const chartRef = useRef(null);
const dayStart = moment().format('yyyy-MM-DD 00:00:00');
const dayEnd = moment().format('yyyy-MM-DD 23:59:59');
const monthStart = moment().startOf('month').format('yyyy-MM-DD 00:00:00');
const monthEnd = moment().endOf('month').format('yyyy-MM-DD 23:59:59');
// 当前时间
const [dateFrom1, dateTo1] = useMemo(() => {
if (experiVal === 'h') {
return [dayStart, dayEnd];
} else {
return [monthStart, monthEnd];
}
}, [experiVal]);
// 对比时间
const [dateFrom2, dateTo2] = useMemo(() => {
// 小时-同比:今日0点-24点对应昨日0点-24点
if (experiVal === 'h' && compareVal === '同比') {
return [
moment(dayStart).subtract(1, 'days').format(FORMAT),
moment(dayEnd).subtract(1, 'days').format(FORMAT),
];
}
// 小时-环比:今日0点-24点对比当前时间往前推1小时
if (experiVal === 'h' && compareVal === '环比') {
return [
moment(dayStart).subtract(1, 'hours').format(FORMAT),
moment(dayEnd).subtract(1, 'hours').format(FORMAT),
];
}
// 日-同比:本月1日-31日对比上个月1日-31日
if (experiVal === 'day' && compareVal === '同比') {
return [
moment(monthStart).subtract(1, 'months').format(FORMAT),
moment(monthEnd).subtract(1, 'months').format(FORMAT),
];
}
// 日-环比:本月1日-31日对比当前时间往前推一天
if (experiVal === 'day' && compareVal === '环比') {
return [
moment(monthStart).subtract(1, 'days').format(FORMAT),
moment(monthEnd).subtract(1, 'days').format(FORMAT),
];
}
return ['', ''];
}, [experiVal, compareVal]);
//chart options
const options = useMemo(() => {
const _options = getOptions(
realData,
compareData,
experiVal,
compareVal,
highLimitVal,
higherLimitVal,
valTake,
sensorData,
);
return _options;
}, [realData, compareData, highLimitVal, higherLimitVal, , valTake, sensorData]);
// 确定
const onOk = () => {
onClose();
};
// 取消
const onCancel = () => {
onClose();
};
// 获取统计服务数据
const getStatisticsData = async () => {
try {
const params1 = {
pageIndex: 1,
pageSize: 1,
q_DeviceReports: [
{
accountName: deviceType,
nameTypeList: [
{
name: sensors,
type: sensors.includes('累计') ? 'Sub' : 'Avg',
},
],
dateType: experiVal,
dateFrom: dateFrom1,
dateTo: dateTo1,
deviceCode,
},
],
dateType: experiVal,
};
const params2 = _.cloneDeep(params1);
params2.q_DeviceReports[0].dateFrom = dateFrom2;
params2.q_DeviceReports[0].dateTo = dateTo2;
setLoading(true);
const req1 = getStatisticsInfo(params1);
const req2 = getStatisticsInfo(params2);
const results = await Promise.all([req1, req2]);
setLoading(false);
const [res1, res2] = results;
if (res1.code === 0 && res2.code === 0) {
let _realData = res1?.data?.list?.[0]?.dNameDataList?.[0]?.nameDate ?? [];
let _compareData = res2?.data?.list?.[0]?.dNameDataList?.[0]?.nameDate ?? [];
_realData = _realData.map((item) => ({
...item,
value: typeof item.value === 'number' ? item.value.toFixed(2) * 1 : 0,
}));
_compareData = _compareData.map((item) => ({
...item,
value: typeof item.value === 'number' ? item.value.toFixed(2) * 1 : 0,
}));
setRealData(_realData);
setCompareData(_compareData);
setSensorData({
...sensorData,
unit: res1?.data?.list?.[0]?.dNameDataList?.[0]?.unit ?? '',
});
} else {
setRealData([]);
setCompareData([]);
}
} catch (error) {
setLoading(false);
console.log(error);
}
};
useEffect(() => {
getStatisticsData();
}, [experiVal, dateFrom1, dateTo1, dateFrom2, dateTo2]);
return ( return (
<> <>
<div className={classNames(`${prefixCls}`)}>经验报警</div> <Modal
title={title}
centered
okText={'确定'}
width={width || '1200px'}
cancelText={'取消'}
open={visible}
onOk={onOk}
onCancel={onCancel}
wrapClassName={classNames(`${prefixCls}`)}
getContainer={getContainer || document.body}
>
<Spin spinning={loading}>
<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={experiTypeOptions}
optionType={'button'}
value={experiVal}
onChange={(e) => {
setExperiVal(e.target.value);
}}
/>
</span>
<span className={classNames(`${prefixCls}-header-item`)}>
对比目标:
<Radio.Group
options={compareOptions}
optionType={'button'}
value={compareVal}
onChange={(e) => {
setCompareVal(e.target.value);
}}
/>
</span>
<span className={classNames(`${prefixCls}-header-item`)}>
取值方式:
<Select options={valTakeOptions} value={valTake} onChange={setValTake} />
</span>
<span className={classNames(`${prefixCls}-header-item`)}>
偏差范围: 高限
<InputNumber
addonAfter={valTake === '按偏移率' ? '%' : ''}
style={{
marginLeft: '2px',
marginRight: '8px',
width: valTake === '按偏移率' ? '110px' : '90px',
}}
value={highLimitVal}
onChange={(val) => {
if (val && higherLimitVal && val > higherLimitVal)
return message.info('高限值不能大于或等于高高限值!');
setHighLimitVal(val);
}}
min={0}
/>
高高限
<InputNumber
addonAfter={valTake === '按偏移率' ? '%' : ''}
style={{ marginLeft: '2px', width: valTake === '按偏移率' ? '110px' : '90px' }}
value={higherLimitVal}
onChange={(val) => {
if (val && highLimitVal && val <= highLimitVal)
return message.info('高高限值不能小于或等于高限值!');
setHigherLimitVal(val);
}}
min={0}
/>
</span>
</div>
</div>
<div className={classNames(`${prefixCls}-content`)}>
<BasicChart
ref={chartRef}
option={options}
notMerge
style={{ width: '100%', height: '100%' }}
/>
</div>
</div>
</Spin>
</Modal>
</> </>
); );
}; };
export default EmpiricalCurve; export default PredictionCurve;
...@@ -3,5 +3,50 @@ ...@@ -3,5 +3,50 @@
@tree-custom-prefix-cls: ~'@{ant-prefix}-empirical-curve'; @tree-custom-prefix-cls: ~'@{ant-prefix}-empirical-curve';
.@{tree-custom-prefix-cls} { .@{tree-custom-prefix-cls} {
background: red; .@{ant-prefix}-modal-body {
height: 650px;
.@{ant-prefix}-spin-nested-loading{
height: 100%;
.@{ant-prefix}-spin-container{
height: 100%;
}
}
}
&-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: 20px;
display: flex;
align-items: center;
justify-content: center;
.@{ant-prefix}-select {
width: 160px;
}
}
}
&-content {
flex: 1;
overflow: hidden;
}
} }
\ 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