Commit ff3a820a authored by 陈龙's avatar 陈龙

feat: 滚动组件增加设备类型监听;历史曲线增加快捷功能

parent 1e1be112
import React from 'react';
import React, {useState} from 'react';
import AlarmScrollAssembly from '../index';
import {Button} from "antd";
window.globalConfig = {
userInfo: { OID: 1 },
userInfo: {OID: 1},
};
export default () => {
return (
<AlarmScrollAssembly
deviceType={'二供泵房,二供机组'}
prefix={'报警信息:'}
showTotal={false}
interval={1}
userAccess={true}
/>
); // 最小宽度930px
const [deviceType, setDeviceType] = useState('二供泵房,二供机组');
return (<>
<AlarmScrollAssembly
deviceType={deviceType}
prefix={'报警信息:'}
showTotal={false}
interval={0.1}
userAccess={true}
/>
<Button onClick={() => {
if (deviceType === '二供泵房') {
setDeviceType('二供泵房,二供机组')
} else {
setDeviceType('二供泵房')
}
}}>点击切换</Button>
</>
); // 最小宽度930px
};
import React, { useState, useEffect, useRef } from 'react';
import React, {useState, useEffect, useRef} from 'react';
import styles from './index.less';
import PropTypes from 'prop-types';
import { Tag, Tooltip, Modal } from 'antd';
import { EnvironmentOutlined } from '@ant-design/icons';
import { monitorService } from './api';
import {Tag, Tooltip, Modal} from 'antd';
import {EnvironmentOutlined} from '@ant-design/icons';
import {monitorService} from './api';
import classnames from 'classnames';
import { switchTimeToPeriod } from './utils';
import { Swiper, SwiperSlide } from 'swiper/react';
import {switchTimeToPeriod} from './utils';
import {Swiper, SwiperSlide} from 'swiper/react';
import 'swiper/swiper.min.css';
import 'swiper/components/pagination/pagination.min.css';
import 'swiper/components/navigation/navigation.min.css';
import SwiperCore, { Autoplay, Pagination, Navigation } from 'swiper/core';
import SwiperCore, {Autoplay, Pagination, Navigation} from 'swiper/core';
SwiperCore.use([Autoplay, Pagination, Navigation]);
/*
......@@ -19,144 +19,148 @@ SwiperCore.use([Autoplay, Pagination, Navigation]);
* 3. 初始化进入时,取截止到当前时间为止的所有的实时报警数据。
* 4. 播放结束后,重新获取实时报警数据进行第二轮的播放。
* */
const InfoItem = ({ info }) => {
const returnClassName = (type, key) => {
let _className = '';
if (type === '普通') {
_className = 'normal';
} else if (type === '紧急') {
_className = 'warning';
}
return `${_className}${key}`;
};
const { alertLevel, startTime, stationName, alertMsg, deviceAddress } = info;
const InfoItem = ({info}) => {
const returnClassName = (type, key) => {
let _className = '';
if (type === '普通') {
_className = 'normal';
} else if (type === '紧急') {
_className = 'warning';
}
return `${_className}${key}`;
};
const {alertLevel, startTime, stationName, alertMsg, deviceAddress} = info;
return (
<div className={styles[returnClassName(alertLevel, 'Wrapper')]}>
<Tag className={styles[returnClassName(alertLevel, 'Tag')]}>{alertLevel}</Tag>
<span className={classnames(styles.time, styles.fontSize13)}>{startTime}</span>
<Tooltip title={deviceAddress} placement={'topLeft'}>
return (
<div className={styles[returnClassName(alertLevel, 'Wrapper')]}>
<Tag className={styles[returnClassName(alertLevel, 'Tag')]}>{alertLevel}</Tag>
<span className={classnames(styles.time, styles.fontSize13)}>{startTime}</span>
<Tooltip title={deviceAddress} placement={'topLeft'}>
<span className={styles.location}>
<EnvironmentOutlined
style={{ fontSize: 12, color: '#666666', marginRight: 5, verticalAlign: 'middle' }}
style={{fontSize: 12, color: '#666666', marginRight: 5, verticalAlign: 'middle'}}
/>
{deviceAddress || ' - '}
{deviceAddress || ' - '}
</span>
</Tooltip>
<Tooltip title={alertMsg} placement={'topLeft'}>
<span className={styles[returnClassName(alertLevel, 'Content')]}>{alertMsg}</span>
</Tooltip>
<div className={styles.periodWrapper}>
<span className={styles.period}>{switchTimeToPeriod(startTime)}</span>
</div>
</div>
);
</Tooltip>
<Tooltip title={alertMsg} placement={'topLeft'}>
<span className={styles[returnClassName(alertLevel, 'Content')]}>{alertMsg}</span>
</Tooltip>
<div className={styles.periodWrapper}>
<span className={styles.period}>{switchTimeToPeriod(startTime)}</span>
</div>
</div>
);
};
let timer = null;
const AlarmScrollAssembly = (props) => {
// const [modalVisible, setModalVisible] = useState(false);
const [currentInfo, setCurrentInfo] = useState({});
const [enableToGetData, setEnableToGetData] = useState(false);
const constanceRef = useRef({
level: '1,2',
type: '直接取值,取变化量,取变化率,取是否',
userID: window.globalConfig.userInfo.OID,
userAccess: true,
});
const [realTimeDataList, setRealTimeDataList] = useState(null);
const getRealTimeData = (pagination) => {
return monitorService.GetAlarmListRealTime({
deviceType: props.deviceType,
...constanceRef.current,
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
userAccess: props.userAccess === void 0 ? true : props.userAccess,
// const [modalVisible, setModalVisible] = useState(false);
const [currentInfo, setCurrentInfo] = useState({});
const [enableToGetData, setEnableToGetData] = useState(false);
const constanceRef = useRef({
level: '1,2',
type: '直接取值,取变化量,取变化率,取是否',
userID: window.globalConfig.userInfo.OID,
userAccess: true,
});
};
const getData = async () => {
let secondRequest = await getRealTimeData({
pageIndex: 1,
pageSize: 10,
});
setRealTimeDataList(secondRequest?.data?.list || []);
setEnableToGetData(false);
runTimer(secondRequest?.data?.list.length || 0);
};
const runTimer = (num) => {
let _interval = props.interval || 0;
if (num > 200) _interval = 0;
timer = setTimeout(() => {
setEnableToGetData(true);
}, 1000 * 60 * _interval);
};
useEffect(() => {
getData();
}, []);
return (
<div className={styles.alarmScrollAssemblyWrapper}>
{realTimeDataList && realTimeDataList.length ? (
<div className={styles.content} style={{ display: 'flex' }}>
{props.prefix ? (
<span style={{ ...props.style, flex: 'none', marginRight: 10 }}>{props.prefix}</span>
) : (
''
)}
<div
className={classnames(
styles.alarmScrollAssembly,
realTimeDataList?.length > 1000 ? styles.moreThan1000 : styles.lessThan1000,
const [realTimeDataList, setRealTimeDataList] = useState(null);
const getRealTimeData = (pagination) => {
return monitorService.GetAlarmListRealTime({
deviceType: props.deviceType,
...constanceRef.current,
pageIndex: pagination.pageIndex,
pageSize: pagination.pageSize,
userAccess: props.userAccess === void 0 ? true : props.userAccess,
});
};
const getData = async () => {
let secondRequest = await getRealTimeData({
pageIndex: 1,
pageSize: 10,
});
setRealTimeDataList(secondRequest?.data?.list || []);
setEnableToGetData(false);
runTimer(secondRequest?.data?.list.length || 0);
};
const runTimer = (num) => {
let _interval = props.interval || 0;
if (num > 200) _interval = 0;
timer = setTimeout(() => {
setEnableToGetData(true);
}, 1000 * 60 * _interval);
};
useEffect(() => {
timer && clearTimeout(timer);
getData();
}, [props.deviceType]);
useEffect(() => {
return () => timer && clearTimeout(timer)
}, [])
return (
<div className={styles.alarmScrollAssemblyWrapper}>
{realTimeDataList && realTimeDataList.length ? (
<div className={styles.content} style={{display: 'flex'}}>
{props.prefix ? (
<span style={{...props.style, flex: 'none', marginRight: 10}}>{props.prefix}</span>
) : (
''
)}
<div
className={classnames(
styles.alarmScrollAssembly,
realTimeDataList?.length > 1000 ? styles.moreThan1000 : styles.lessThan1000,
)}
id={'alarmListDiv'}
>
<Swiper
slidesPerView={1}
navigation={props.showTotal ? true : false}
autoplay={{
delay: 3000,
disableOnInteraction: false,
}}
loop
direction="vertical"
onSlideChange={(e) => {
if (e.activeIndex === realTimeDataList.length - 1 && enableToGetData) getData();
}}
>
{realTimeDataList.map((item, index) => {
return (
<SwiperSlide
key={index}
virtualIndex={index}
onClick={() => {
setCurrentInfo(item);
// setModalVisible(true);
}}
>
<InfoItem key={index} info={item}/>
</SwiperSlide>
);
})}
</Swiper>
</div>
</div>
) : (
''
)}
id={'alarmListDiv'}
>
<Swiper
slidesPerView={1}
navigation={props.showTotal ? true : false}
autoplay={{
delay: 3000,
disableOnInteraction: false,
}}
loop
direction="vertical"
onSlideChange={(e) => {
if (e.activeIndex === realTimeDataList.length - 1 && enableToGetData) getData();
}}
>
{realTimeDataList.map((item, index) => {
return (
<SwiperSlide
key={index}
virtualIndex={index}
onClick={() => {
setCurrentInfo(item);
// setModalVisible(true);
}}
>
<InfoItem key={index} info={item} />
</SwiperSlide>
);
})}
</Swiper>
</div>
</div>
) : (
''
)}
</div>
);
);
};
AlarmScrollAssembly.defaultProps = {
deviceType: '二供泵房,二供机组',
prefix: '',
showTotal: true,
interval: 5,
userAccess: false,
deviceType: '二供泵房,二供机组',
prefix: '',
showTotal: true,
interval: 5,
userAccess: false,
};
AlarmScrollAssembly.propTypes = {
deviceType: PropTypes.string,
prefix: PropTypes.string,
showTotal: PropTypes.bool,
interval: PropTypes.number,
userAccess: PropTypes.bool,
deviceType: PropTypes.string,
prefix: PropTypes.string,
showTotal: PropTypes.bool,
interval: PropTypes.number,
userAccess: PropTypes.bool,
};
export default AlarmScrollAssembly;
......@@ -57,6 +57,37 @@ const timeList = [
},
];
// 同期对比 日 快捷按钮
const shortcutsForDay = [
{
label: '近3天',
value: '近3天'
},
{
label: '近5天',
value: '近5天'
},
/* {
label: '去年同期',
value: '去年同期',
}*/
];
// 同期对比 月 快捷按钮
const shortcutsForMonth = [
{
label: '近3月',
value: '近3月'
},
{
label: '近5月',
value: '近5月'
},
/* {
label: '去年同期',
value: '去年同期',
}*/
]
const CheckboxData = [
{
key: 'curveCenter',
......@@ -217,7 +248,6 @@ const timeColumn = {
const HistoryView = (props) => {
const {getPrefixCls} = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('history-view');
const {
title,
grid,
......@@ -296,12 +326,15 @@ const HistoryView = (props) => {
const chartGrid = checkboxData.find((item) => item.key === 'chartGrid')?.checked;
return [curveCenter, chartGrid];
}, [checkboxData]);
// 同期对比快捷键
// shortcutsValue
// onShortcutsChange
const [shortcutsValue, setShortcutsValue] = useState('');
// 自定义模式: 快速选择
const onCustomerTimeChange = (key) => {
if (key === 'oneMonth' && lineDataType === '原始曲线') {
setLineDataType('特征曲线');
message.info('时间区间超过7天,已切换为特征曲线')
message.info('月模式数据量较大,不支持原始曲线模式,已切换为特征曲线')
}
setCustomerChecked(key);
!!customerTime && setCustomerTime(null);
......@@ -326,6 +359,10 @@ const HistoryView = (props) => {
// 同期对比模式: 选择(日/月)
const onContrastChange = (value) => {
if (value === 'month') {
message.info('月模式数据量较大,不支持原始曲线模式,已切换为特征曲线')
setLineDataType('特征曲线');
}
setContrastOption(value);
// 模式为日时,默认对比时间根据defaultDate判断 是昨天、上月、还是去年
setDatePickerArr([...DefaultDatePicker(value === 'day' && defaultDate ? defaultDate : value)]);
......@@ -333,6 +370,8 @@ const HistoryView = (props) => {
// 同期对比模式: 时间段选择
const onContrastPickerChange = (date, dateString, item) => {
// 操作时间就清除掉快捷键选用状态
setShortcutsValue('');
const arr = [...datePickerArr];
arr.forEach((child) => {
if (child.key === item.key) {
......@@ -344,6 +383,8 @@ const HistoryView = (props) => {
// 同期对比模式: 新增日期选择组件
const handleAddDatePicker = () => {
// 操作时间就清除掉快捷键选用状态
setShortcutsValue('');
setDatePickerArr([
...datePickerArr,
{
......@@ -355,6 +396,8 @@ const HistoryView = (props) => {
// 同期对比模式: 删除日期选择组件
const handleDeleteDatePicker = (index) => {
// 操作时间就清除掉快捷键选用状态
setShortcutsValue('');
const arr = [...datePickerArr];
arr.splice(index, 1);
setDatePickerArr(arr);
......@@ -362,6 +405,11 @@ const HistoryView = (props) => {
// 时间设置切换(自定义/同期对比)
const onTimeSetChange = (e) => {
// 操作时间就清除掉快捷键选用状态
setShortcutsValue('');
if (e.target.value === 'customer') {
setLineDataType('特征曲线')
}
setTimeValue(e.target.value);
if (e.target.value === 'contrast') {
// 同期对比
......@@ -377,7 +425,46 @@ const HistoryView = (props) => {
onCheckboxChange({target: {value: true}}, 'chartType');
}
};
const onShortcutsChange = (e) => {
let _val = e.target.value;
setShortcutsValue(_val);
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')},
]
break;
case '近5天':
_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')},
]
break;
case '近3月':
_arr = [
{key: 1, value: moment()},
{key: 2, value: moment().subtract(1, 'months')},
{key: 3, value: moment().subtract(2, 'months')},
]
break;
case '近5月':
_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')},
]
break;
}
setDatePickerArr(_arr);
};
const renderTimeOption = () => {
return (
<div className={classNames(`${prefixCls}-date`)}>
......@@ -407,6 +494,16 @@ const HistoryView = (props) => {
<Option value="day"></Option>
<Option value="month"></Option>
</Select>
{/*增加快捷日期*/}
<Radio.Group value={shortcutsValue} onChange={onShortcutsChange}>
{
(contrastOption === 'day' ? shortcutsForDay : shortcutsForMonth).map(item => {
return <Radio.Button value={item.value}>
{item.label}
</Radio.Button>
})
}
</Radio.Group>
{datePickerArr.map((child, index) => (
<div key={child.key} className={classNames(`${prefixCls}-contrast-list`)}>
<div className={classNames(`${prefixCls}-contrast-wrap`)}>
......@@ -473,13 +570,14 @@ const HistoryView = (props) => {
};
// 切换数据类型
const switchLineDataType = (e) => {
let _val = e.target.value
let _startDate = dateRange[0]?.dateFrom;
let _endDate = dateRange[0]?.dateTo;
let diffDays = moment(_endDate).diff(moment(_startDate), 'days');
if (e === '原始曲线' && diffDays > 7) {
if (_val === '原始曲线' && diffDays > 7) {
return message.info('查阅原始曲线时,请选择小于或等于7天的时间间隔');
}
setLineDataType(e)
setLineDataType(_val)
};
const renderCheckbox = (child, showJustLine) => {
const curveAccess = activeTabKey === 'curve' && child.showInCurve;
......@@ -509,27 +607,43 @@ const HistoryView = (props) => {
className={classNames(`${prefixCls}-cover`)}
style={isChart && isSingle ? {width: '100%'} : {}}
>
{isChart && isSingle && showBoxOption ? (
<>
<div key={''} className={`${prefixCls}-cover-item`}>
<Segmented value={lineDataType} options={['特征曲线', '原始曲线']} onChange={switchLineDataType}/>
{
isChart ? <>
<div className={classNames(`${prefixCls}-label`)}>曲线选择</div>
<div className={`${prefixCls}-cover-item`}>
<Radio.Group
value={lineDataType}
onChange={switchLineDataType}
>
<Radio.Button value={'特征曲线'}>特征曲线</Radio.Button>
<Radio.Button value={'原始曲线'}>原始曲线</Radio.Button>
</Radio.Group>
{/*<Segmented value={lineDataType} options={['特征曲线', '原始曲线']} onChange={switchLineDataType}/>*/}
<Tooltip title={'原始曲线数据量较大,请查阅小于7天的数据~'}>
<QuestionCircleFilled style={{marginLeft: 6}} className={`${prefixCls}-question`}/>
</Tooltip>
</div>
<div className={classNames(`${prefixCls}-label`)}>曲线形态</div>
<Radio.Group
value={chartType}
style={{marginRight: 16}}
onChange={(e) => {
let _value = e.target.value;
setChartType(_value);
onCheckboxChange({target: {value: _value !== 'boxChart'}}, 'chartType');
}}
>
<Radio.Button value={'lineChart'}>线形图</Radio.Button>
<Radio.Button value={'boxChart'}>箱线图</Radio.Button>
</Radio.Group>
</> : ''
}
{isChart && isSingle && showBoxOption ? (
<>
{
lineDataType !== '原始曲线' ? <>
<div style={{marginLeft: 7}} className={classNames(`${prefixCls}-label`)}>曲线形态</div>
<Radio.Group
value={chartType}
style={{marginRight: 16}}
onChange={(e) => {
let _value = e.target.value;
setChartType(_value);
onCheckboxChange({target: {value: _value !== 'boxChart'}}, 'chartType');
}}
>
<Radio.Button value={'lineChart'}>线形图</Radio.Button>
<Radio.Button value={'boxChart'}>箱线图</Radio.Button>
</Radio.Group>
</> : ''
}
</>
) : (
''
......
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