import React, { useContext, useEffect, useRef, useState, useMemo } from 'react'; import { ConfigProvider, Modal, Radio, Select, InputNumber, Spin, message } from 'antd'; 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'; const FORMAT = 'yyyy-MM-DD HH:mm:ss'; const PredictionCurve = (props) => { const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); 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 ( <> <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 PredictionCurve;