Commit 365230d8 authored by 陈龙's avatar 陈龙

fix: 修复历史曲线频率、状态的图表显示异常

parent 4ea22fe6
import React, {useContext, useEffect, useMemo, useState, useCallback, useRef} from 'react'; import React, { useContext, useEffect, useMemo, useState, useCallback, useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { import {
...@@ -11,7 +11,8 @@ import { ...@@ -11,7 +11,8 @@ import {
Tabs, Tabs,
Tooltip, Tooltip,
Button, Button,
message, Progress, message,
Progress,
} from 'antd'; } from 'antd';
import { import {
CloseCircleFilled, CloseCircleFilled,
...@@ -29,17 +30,18 @@ import { ...@@ -29,17 +30,18 @@ import {
getDeviceAlarmScheme, getDeviceAlarmScheme,
getExportDeviceHistoryUrl, getExportDeviceHistoryUrl,
getDictionaryInfoAll, getDictionaryInfoAll,
getPointAddress, getPointAddressEntry getPointAddress,
getPointAddressEntry,
} from './apis'; } from './apis';
import SingleChart from './SingleChart'; import SingleChart from './SingleChart';
import GridChart from './GridChart'; import GridChart from './GridChart';
import './index.less'; import './index.less';
import {globalConfig} from 'antd/lib/config-provider'; import { globalConfig } from 'antd/lib/config-provider';
import {getSensorType} from "./apis/index"; import { getSensorType } from './apis/index';
import {ExportExcel} from '@wisdom-components/exportexcel'; import { ExportExcel } from '@wisdom-components/exportexcel';
const {RangePicker} = DatePicker; const { RangePicker } = DatePicker;
const {Option} = Select; const { Option } = Select;
const startFormat = 'YYYY-MM-DD 00:00:00'; const startFormat = 'YYYY-MM-DD 00:00:00';
const endFormat = 'YYYY-MM-DD 23:59:59'; const endFormat = 'YYYY-MM-DD 23:59:59';
...@@ -57,7 +59,7 @@ const timeList = [ ...@@ -57,7 +59,7 @@ const timeList = [
}, },
{ {
key: 'yesterday', key: 'yesterday',
name: '昨日' name: '昨日',
}, },
{ {
key: 'oneWeek', key: 'oneWeek',
...@@ -73,11 +75,11 @@ const timeList = [ ...@@ -73,11 +75,11 @@ const timeList = [
const shortcutsForDay = [ const shortcutsForDay = [
{ {
label: '近3天', label: '近3天',
value: '近3天' value: '近3天',
}, },
{ {
label: '近7天', label: '近7天',
value: '近7天' value: '近7天',
}, },
/* { /* {
label: '去年同期', label: '去年同期',
...@@ -88,17 +90,17 @@ const shortcutsForDay = [ ...@@ -88,17 +90,17 @@ const shortcutsForDay = [
const shortcutsForMonth = [ const shortcutsForMonth = [
{ {
label: '近3月', label: '近3月',
value: '近3月' value: '近3月',
}, },
{ {
label: '近6月', label: '近6月',
value: '近6月' value: '近6月',
}, },
/* { /* {
label: '去年同期', label: '去年同期',
value: '去年同期', value: '去年同期',
}*/ }*/
] ];
const CheckboxData = [ const CheckboxData = [
{ {
...@@ -123,7 +125,7 @@ const CheckboxData = [ ...@@ -123,7 +125,7 @@ const CheckboxData = [
showInCurve: true, showInCurve: true,
showInTable: true, showInTable: true,
tooltip: '采用递推平均滤波法(滑动平均滤波法)对采样数据中的异常离群值进行识别与去除。', tooltip: '采用递推平均滤波法(滑动平均滤波法)对采样数据中的异常离群值进行识别与去除。',
hasSub: true hasSub: true,
}, },
{ {
key: 'dataThin', key: 'dataThin',
...@@ -136,6 +138,12 @@ const CheckboxData = [ ...@@ -136,6 +138,12 @@ const CheckboxData = [
]; ];
const timeIntervalList = [ const timeIntervalList = [
{
key: '1min',
zoom: '1',
unit: 'min',
name: '1分钟',
},
{ {
key: '5', key: '5',
zoom: '5', zoom: '5',
...@@ -265,7 +273,7 @@ const OriginMaxDays = 31; // 原始曲线请求数据的最大天数 ...@@ -265,7 +273,7 @@ const OriginMaxDays = 31; // 原始曲线请求数据的最大天数
const CharacteristicMaxDays = null; // 特征曲线或者其他曲线的最大天数 const CharacteristicMaxDays = null; // 特征曲线或者其他曲线的最大天数
const HistoryView = (props) => { const HistoryView = (props) => {
const [completeInit, setCompleteInit] = useState(false); const [completeInit, setCompleteInit] = useState(false);
const {getPrefixCls} = useContext(ConfigProvider.ConfigContext); const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('history-view'); const prefixCls = getPrefixCls('history-view');
const { const {
title, title,
...@@ -295,7 +303,9 @@ const HistoryView = (props) => { ...@@ -295,7 +303,9 @@ const HistoryView = (props) => {
const [datePickerArr, setDatePickerArr] = useState(DefaultDatePicker(defaultDate)); // 对比时间段配置值 const [datePickerArr, setDatePickerArr] = useState(DefaultDatePicker(defaultDate)); // 对比时间段配置值
const [checkboxData, setCheckboxData] = useState(() => [...CheckboxData]); // 曲线设置项 const [checkboxData, setCheckboxData] = useState(() => [...CheckboxData]); // 曲线设置项
const [dataThinKey, setDataThinKey] = useState(timeIntervalList[0].key); // 曲线抽稀时间设置 const [dataThinKey, setDataThinKey] = useState(
timeIntervalList[0].key === '1min' ? timeIntervalList[1].key : timeIntervalList[0].key,
); // 曲线抽稀时间设置
const [algorithmValue, setAlgorithmValue] = useState(1); const [algorithmValue, setAlgorithmValue] = useState(1);
const [columns, setColumns] = useState([]); const [columns, setColumns] = useState([]);
...@@ -319,11 +329,16 @@ const HistoryView = (props) => { ...@@ -319,11 +329,16 @@ const HistoryView = (props) => {
const [isSingleStatusSensor, setIsSingleStatusSensor] = useState(false); const [isSingleStatusSensor, setIsSingleStatusSensor] = useState(false);
// 历史数据相关的特征描述 // 历史数据相关的特征描述
const deviceConfig = useRef({ const deviceConfig = useRef({
oneDevice: deviceParams.length === 1,//单设备 oneDevice: deviceParams.length === 1, //单设备
oneSensor: [...new Set(deviceParams.reduce((final, cur) => { oneSensor:
[
...new Set(
deviceParams.reduce((final, cur) => {
let _sensors = cur.sensors.split(','); let _sensors = cur.sensors.split(',');
return final.concat(_sensors); return final.concat(_sensors);
}, []))].length === 1, // 单指标 }, []),
),
].length === 1, // 单指标
}); });
// 选择的时间范围值 // 选择的时间范围值
const dateRange = useMemo(() => { const dateRange = useMemo(() => {
...@@ -334,7 +349,12 @@ const HistoryView = (props) => { ...@@ -334,7 +349,12 @@ const HistoryView = (props) => {
return handleBatchTime(_dateArr, contrastOption); return handleBatchTime(_dateArr, contrastOption);
} }
}, [contrastOption, customerChecked, customerTime, datePickerArr, timeValue, shortcutsValue]); }, [contrastOption, customerChecked, customerTime, datePickerArr, timeValue, shortcutsValue]);
useEffect(() => {
let _diffDays = moment(dateRange[0].dateTo).diff(dateRange[0].dateFrom, 'days');
if (_diffDays > 7 && dataThinKey === '1min') {
setDataThinKey(timeIntervalList[1].key);
}
}, [dateRange]);
const [dates, setDates] = useState(null); const [dates, setDates] = useState(null);
const configDependence = checkboxData const configDependence = checkboxData
...@@ -400,7 +420,8 @@ const HistoryView = (props) => { ...@@ -400,7 +420,8 @@ const HistoryView = (props) => {
// 同期对比模式: 选择(日/月) // 同期对比模式: 选择(日/月)
const onContrastChange = (value) => { const onContrastChange = (value) => {
if (value === 'month') { if (value === 'month') {
if (lineDataType === '原始曲线') message.info('月模式数据量较大,不支持原始曲线模式,已切换为特征曲线') if (lineDataType === '原始曲线')
message.info('月模式数据量较大,不支持原始曲线模式,已切换为特征曲线');
setLineDataType('特征曲线'); setLineDataType('特征曲线');
} }
setShortcutsValue(''); setShortcutsValue('');
...@@ -458,13 +479,13 @@ const HistoryView = (props) => { ...@@ -458,13 +479,13 @@ const HistoryView = (props) => {
onContrastChange(contrastOption); onContrastChange(contrastOption);
setShowBoxOption(false); setShowBoxOption(false);
setChartType('lineChart'); setChartType('lineChart');
onCheckboxChange({target: {value: false}}, 'chartType'); onCheckboxChange({ target: { value: false } }, 'chartType');
onCheckboxChange({target: {value: false}}, 'ignoreOutliers'); onCheckboxChange({ target: { value: false } }, 'ignoreOutliers');
} else { } else {
// 自定义 // 自定义
// 不需要处理 // 不需要处理
setShowBoxOption(true); setShowBoxOption(true);
onCheckboxChange({target: {value: true}}, 'chartType'); onCheckboxChange({ target: { value: true } }, 'chartType');
} }
}; };
const onShortcutsChange = (e) => { const onShortcutsChange = (e) => {
...@@ -474,38 +495,38 @@ const HistoryView = (props) => { ...@@ -474,38 +495,38 @@ const HistoryView = (props) => {
switch (_val) { switch (_val) {
case '近3天': case '近3天':
_arr = [ _arr = [
{key: 1, value: moment()}, { key: 1, value: moment() },
{key: 2, value: moment().subtract(1, 'days')}, { key: 2, value: moment().subtract(1, 'days') },
{key: 3, value: moment().subtract(2, 'days')}, { key: 3, value: moment().subtract(2, 'days') },
] ];
break; break;
case '近7天': case '近7天':
_arr = [ _arr = [
{key: 1, value: moment()}, { key: 1, value: moment() },
{key: 2, value: moment().subtract(1, 'days')}, { key: 2, value: moment().subtract(1, 'days') },
{key: 3, value: moment().subtract(2, 'days')}, { key: 3, value: moment().subtract(2, 'days') },
{key: 4, value: moment().subtract(3, 'days')}, { key: 4, value: moment().subtract(3, 'days') },
{key: 5, value: moment().subtract(4, 'days')}, { key: 5, value: moment().subtract(4, 'days') },
{key: 6, value: moment().subtract(5, 'days')}, { key: 6, value: moment().subtract(5, 'days') },
{key: 7, value: moment().subtract(6, 'days')}, { key: 7, value: moment().subtract(6, 'days') },
] ];
break; break;
case '近3月': case '近3月':
_arr = [ _arr = [
{key: 1, value: moment()}, { key: 1, value: moment() },
{key: 2, value: moment().subtract(1, 'months')}, { key: 2, value: moment().subtract(1, 'months') },
{key: 3, value: moment().subtract(2, 'months')}, { key: 3, value: moment().subtract(2, 'months') },
] ];
break; break;
case '近6月': case '近6月':
_arr = [ _arr = [
{key: 1, value: moment()}, { key: 1, value: moment() },
{key: 2, value: moment().subtract(1, 'months')}, { key: 2, value: moment().subtract(1, 'months') },
{key: 3, value: moment().subtract(2, 'months')}, { key: 3, value: moment().subtract(2, 'months') },
{key: 4, value: moment().subtract(3, 'months')}, { key: 4, value: moment().subtract(3, 'months') },
{key: 5, value: moment().subtract(4, 'months')}, { key: 5, value: moment().subtract(4, 'months') },
{key: 6, value: moment().subtract(5, 'months')}, { key: 6, value: moment().subtract(5, 'months') },
] ];
break; break;
} }
setShortcutsDatePickerArr(_arr); setShortcutsDatePickerArr(_arr);
...@@ -516,9 +537,7 @@ const HistoryView = (props) => { ...@@ -516,9 +537,7 @@ const HistoryView = (props) => {
<div className={classNames(`${prefixCls}-label`)}>时间选择</div> <div className={classNames(`${prefixCls}-label`)}>时间选择</div>
<Radio.Group value={timeValue} onChange={onTimeSetChange}> <Radio.Group value={timeValue} onChange={onTimeSetChange}>
<Radio.Button value="customer">自定义</Radio.Button> <Radio.Button value="customer">自定义</Radio.Button>
{ {!grid ? <Radio.Button value="contrast">同期对比</Radio.Button> : ''}
!grid ? <Radio.Button value="contrast">同期对比</Radio.Button> : ''
}
</Radio.Group> </Radio.Group>
{timeValue === 'customer' && ( // 自定义 {timeValue === 'customer' && ( // 自定义
<> <>
...@@ -560,30 +579,29 @@ const HistoryView = (props) => { ...@@ -560,30 +579,29 @@ const HistoryView = (props) => {
}} }}
showTime={{ showTime={{
format: 'YYYY-MM-DD HH:mm', format: 'YYYY-MM-DD HH:mm',
minuteStep: 10 minuteStep: 10,
}} }}
/> />
</> </>
)} )}
{timeValue === 'contrast' && ( // 同期对比 {timeValue === 'contrast' && ( // 同期对比
<> <>
<Select value={contrastOption} style={{width: 60}} onChange={onContrastChange}> <Select value={contrastOption} style={{ width: 60 }} onChange={onContrastChange}>
<Option value="day"></Option> <Option value="day"></Option>
<Option value="month" disabled={lineDataType === '原始曲线'}></Option> <Option value="month" disabled={lineDataType === '原始曲线'}>
</Option>
</Select> </Select>
{/*增加快捷日期*/} {/*增加快捷日期*/}
{ {deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1 ? (
deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1 ?
<Radio.Group value={shortcutsValue} onChange={onShortcutsChange}> <Radio.Group value={shortcutsValue} onChange={onShortcutsChange}>
{ {(contrastOption === 'day' ? shortcutsForDay : shortcutsForMonth).map((item) => {
(contrastOption === 'day' ? shortcutsForDay : shortcutsForMonth).map(item => { return <Radio.Button value={item.value}>{item.label}</Radio.Button>;
return <Radio.Button value={item.value}> })}
{item.label} </Radio.Group>
</Radio.Button> ) : (
}) ''
} )}
</Radio.Group> : ''
}
{datePickerArr.map((child, index) => ( {datePickerArr.map((child, index) => (
<div key={child.key} className={classNames(`${prefixCls}-contrast-list`)}> <div key={child.key} className={classNames(`${prefixCls}-contrast-list`)}>
<div className={classNames(`${prefixCls}-contrast-wrap`)}> <div className={classNames(`${prefixCls}-contrast-wrap`)}>
...@@ -592,14 +610,14 @@ const HistoryView = (props) => { ...@@ -592,14 +610,14 @@ const HistoryView = (props) => {
picker={contrastOption === 'day' ? undefined : contrastOption} picker={contrastOption === 'day' ? undefined : contrastOption}
value={child.value} value={child.value}
onChange={(date, dateString) => onContrastPickerChange(date, dateString, child)} onChange={(date, dateString) => onContrastPickerChange(date, dateString, child)}
style={{width: 130, border: !shortcutsValue ? '1px solid #1890ff' : ''}} style={{ width: 130, border: !shortcutsValue ? '1px solid #1890ff' : '' }}
/> />
{datePickerArr.length > 2 && ( {datePickerArr.length > 2 && (
<div <div
className={classNames(`${prefixCls}-contrast-delete`)} className={classNames(`${prefixCls}-contrast-delete`)}
onClick={() => handleDeleteDatePicker(index)} onClick={() => handleDeleteDatePicker(index)}
> >
<CloseCircleFilled/> <CloseCircleFilled />
</div> </div>
)} )}
</div> </div>
...@@ -608,12 +626,21 @@ const HistoryView = (props) => { ...@@ -608,12 +626,21 @@ const HistoryView = (props) => {
)} )}
</div> </div>
))} ))}
{datePickerArr.length < 4 && <PlusCircleOutlined onClick={handleAddDatePicker}/>} {datePickerArr.length < 4 && <PlusCircleOutlined onClick={handleAddDatePicker} />}
</> </>
)} )}
</div> </div>
); );
}, [timeValue, customerChecked, lineDataType, datePickerArr, deviceParams, dates, customerTime, chartDataSource]); }, [
timeValue,
customerChecked,
lineDataType,
datePickerArr,
deviceParams,
dates,
customerTime,
chartDataSource,
]);
// 曲线设置项选择/取消 // 曲线设置项选择/取消
const onCheckboxChange = (e, key, showJustLine) => { const onCheckboxChange = (e, key, showJustLine) => {
...@@ -651,7 +678,7 @@ const HistoryView = (props) => { ...@@ -651,7 +678,7 @@ const HistoryView = (props) => {
}; };
// 切换数据类型 // 切换数据类型
const switchLineDataType = (e) => { const switchLineDataType = (e) => {
let _val = e.target.value let _val = e.target.value;
let _startDate = dateRange[0]?.dateFrom; let _startDate = dateRange[0]?.dateFrom;
let _endDate = dateRange[0]?.dateTo; let _endDate = dateRange[0]?.dateTo;
let diffDays = moment(_endDate).diff(moment(_startDate), 'days'); let diffDays = moment(_endDate).diff(moment(_startDate), 'days');
...@@ -662,7 +689,7 @@ const HistoryView = (props) => { ...@@ -662,7 +689,7 @@ const HistoryView = (props) => {
if (_val === '原始曲线') { if (_val === '原始曲线') {
setContrastOption('day'); setContrastOption('day');
} }
setLineDataType(_val) setLineDataType(_val);
}; };
const renderCheckbox = (child, showJustLine) => { const renderCheckbox = (child, showJustLine) => {
const curveAccess = activeTabKey === 'curve' && child.showInCurve; const curveAccess = activeTabKey === 'curve' && child.showInCurve;
...@@ -678,18 +705,22 @@ const HistoryView = (props) => { ...@@ -678,18 +705,22 @@ const HistoryView = (props) => {
</Checkbox> </Checkbox>
{child.tooltip && ( {child.tooltip && (
<Tooltip title={child.tooltip}> <Tooltip title={child.tooltip}>
<QuestionCircleFilled className={`${prefixCls}-question`}/> <QuestionCircleFilled className={`${prefixCls}-question`} />
</Tooltip> </Tooltip>
)} )}
{ {child.hasSub && child.checked && false ? (
child.hasSub && child.checked && false ? <Select
<Select style={{width: 80, marginLeft: 10}} value={algorithmValue} style={{ width: 80, marginLeft: 10 }}
onChange={(e) => setAlgorithmValue(e)}> value={algorithmValue}
onChange={(e) => setAlgorithmValue(e)}
>
<Option value={1}></Option> <Option value={1}></Option>
<Option value={5}></Option> <Option value={5}></Option>
<Option value={10}></Option> <Option value={10}></Option>
</Select> : '' </Select>
} ) : (
''
)}
</> </>
) )
); );
...@@ -699,51 +730,56 @@ const HistoryView = (props) => { ...@@ -699,51 +730,56 @@ const HistoryView = (props) => {
return ( return (
<div <div
className={classNames(`${prefixCls}-cover`)} className={classNames(`${prefixCls}-cover`)}
style={isChart && isSingle ? {width: '100%'} : {}} style={isChart && isSingle ? { width: '100%' } : {}}
> >
{ {isChart && !isStatus ? (
isChart && !isStatus ? <> <>
<div className={classNames(`${prefixCls}-label`)}>曲线选择</div> <div className={classNames(`${prefixCls}-label`)}>曲线选择</div>
<div className={`${prefixCls}-cover-item`}> <div className={`${prefixCls}-cover-item`}>
<Radio.Group <Radio.Group value={lineDataType} onChange={switchLineDataType}>
value={lineDataType}
onChange={switchLineDataType}
>
<Radio.Button value={'特征曲线'}>特征曲线</Radio.Button> <Radio.Button value={'特征曲线'}>特征曲线</Radio.Button>
<Radio.Button value={'原始曲线'}>原始曲线</Radio.Button> <Radio.Button value={'原始曲线'}>原始曲线</Radio.Button>
</Radio.Group> </Radio.Group>
{/*<Segmented value={lineDataType} options={['特征曲线', '原始曲线']} onChange={switchLineDataType}/>*/} {/*<Segmented value={lineDataType} options={['特征曲线', '原始曲线']} onChange={switchLineDataType}/>*/}
<Tooltip title={'原始曲线数据量较大,单次查询最多展示1万条数据'}> <Tooltip title={'原始曲线数据量较大,单次查询最多展示1万条数据'}>
<QuestionCircleFilled style={{marginLeft: 6}} className={`${prefixCls}-question`}/> <QuestionCircleFilled
style={{ marginLeft: 6 }}
className={`${prefixCls}-question`}
/>
</Tooltip> </Tooltip>
</div> </div>
</> : '' </>
} ) : (
''
)}
{isChart && isSingle && showBoxOption && !isStatus ? ( {isChart && isSingle && showBoxOption && !isStatus ? (
<> <>
{ {lineDataType !== '原始曲线' ? (
lineDataType !== '原始曲线' ? <> <>
<div style={{marginLeft: 7}} className={classNames(`${prefixCls}-label`)}>曲线形态</div> <div style={{ marginLeft: 7 }} className={classNames(`${prefixCls}-label`)}>
曲线形态
</div>
<Radio.Group <Radio.Group
value={chartType} value={chartType}
style={{marginRight: 16}} style={{ marginRight: 16 }}
onChange={(e) => { onChange={(e) => {
let _value = e.target.value; let _value = e.target.value;
setChartType(_value); setChartType(_value);
onCheckboxChange({target: {value: _value !== 'boxChart'}}, 'chartType'); onCheckboxChange({ target: { value: _value !== 'boxChart' } }, 'chartType');
}} }}
> >
<Radio.Button value={'lineChart'}>线形图</Radio.Button> <Radio.Button value={'lineChart'}>线形图</Radio.Button>
<Radio.Button value={'boxChart'}>箱线图</Radio.Button> <Radio.Button value={'boxChart'}>箱线图</Radio.Button>
</Radio.Group> </Radio.Group>
</> : ''
}
</> </>
) : ( ) : (
'' ''
)} )}
{ </>
!isStatus ? ) : (
''
)}
{!isStatus ? (
<> <>
<div className={classNames(`${prefixCls}-label`)}> <div className={classNames(`${prefixCls}-label`)}>
{activeTabKey !== 'table' ? '曲线设置' : '表格设置'} {activeTabKey !== 'table' ? '曲线设置' : '表格设置'}
...@@ -760,19 +796,28 @@ const HistoryView = (props) => { ...@@ -760,19 +796,28 @@ const HistoryView = (props) => {
{activeTabKey === 'table' && ( {activeTabKey === 'table' && (
<Select <Select
value={dataThinKey} value={dataThinKey}
style={{width: 90}} style={{ width: 90 }}
onChange={onTimeIntervalChange} onChange={onTimeIntervalChange}
disabled={!dataConfig.dataThin} disabled={!dataConfig.dataThin}
> >
{timeIntervalList.map((child) => ( {timeIntervalList
.filter((item) => {
let _diffDays = moment(dateRange[0].dateTo).diff(dateRange[0].dateFrom, 'days');
return !(_diffDays > 7 && item.key === '1min');
})
.map((child) => {
return (
<Option key={child.key} unit={child.unit} value={child.key}> <Option key={child.key} unit={child.unit} value={child.key}>
{child.name} {child.name}
</Option> </Option>
))} );
})}
</Select> </Select>
)} )}
</> : '' </>
} ) : (
''
)}
</div> </div>
); );
}; };
...@@ -785,7 +830,10 @@ const HistoryView = (props) => { ...@@ -785,7 +830,10 @@ const HistoryView = (props) => {
let fileName = `数据报表-${i.deviceType}-${i.deviceCode}-${moment(timeFrom).format( let fileName = `数据报表-${i.deviceType}-${i.deviceCode}-${moment(timeFrom).format(
dateFormat, dateFormat,
)}${moment(timeTo).format(dateFormat)}`; )}${moment(timeTo).format(dateFormat)}`;
let _quotas = i.sensors.split(',').filter(item => item !== '是否在线').join(',') let _quotas = i.sensors
.split(',')
.filter((item) => item !== '是否在线')
.join(',');
getExportDeviceHistoryUrl({ getExportDeviceHistoryUrl({
deviceType: i.deviceType, deviceType: i.deviceType,
deviceCode: i.deviceCode, deviceCode: i.deviceCode,
...@@ -802,15 +850,14 @@ const HistoryView = (props) => { ...@@ -802,15 +850,14 @@ const HistoryView = (props) => {
aDom.click(); aDom.click();
aDom.remove(); aDom.remove();
}) })
.catch((err) => { .catch((err) => {});
});
}); });
}; };
const exportFeatureBtn = () => { const exportFeatureBtn = () => {
message.info('报表生成中,请稍后~'); message.info('报表生成中,请稍后~');
let _dataSource = tableData.sort((a, b) => { let _dataSource = tableData.sort((a, b) => {
let _a = a.time; let _a = a.time;
let _b = b.time let _b = b.time;
if (timeValue === 'contrast') { if (timeValue === 'contrast') {
if (contrastOption === 'day') { if (contrastOption === 'day') {
_a = `2000-01-01 ${a.time}:00`; _a = `2000-01-01 ${a.time}:00`;
...@@ -822,37 +869,40 @@ const HistoryView = (props) => { ...@@ -822,37 +869,40 @@ const HistoryView = (props) => {
} }
} }
return timeOrder === 'ascend' ? moment(_a) - moment(_b) : moment(_b) - moment(_a); return timeOrder === 'ascend' ? moment(_a) - moment(_b) : moment(_b) - moment(_a);
}) });
let _columns = [...columns]; let _columns = [...columns];
let timeFrom = dateRange?.[0]?.dateFrom || moment().format(startFormat); let timeFrom = dateRange?.[0]?.dateFrom || moment().format(startFormat);
let timeTo = dateRange?.[0]?.dateTo || moment().format(timeFormat); let timeTo = dateRange?.[0]?.dateTo || moment().format(timeFormat);
let fileName = `特征数据-${moment(timeFrom).format( let fileName = `特征数据-${moment(timeFrom).format(dateFormat)}${moment(timeTo).format(
dateFormat, dateFormat,
)}${moment(timeTo).format(dateFormat)}`; )}`;
let _dataIndex = []; let _dataIndex = [];
let _titleWidth = []; let _titleWidth = [];
let _title = _columns.map(item => { let _title = _columns.map((item) => {
_dataIndex.push(item.dataIndex); _dataIndex.push(item.dataIndex);
let _titleStr = [item.name, item.title].filter(item => item).join('-'); let _titleStr = [item.name, item.title].filter((item) => item).join('-');
_titleWidth.push(_titleStr.length * 1); _titleWidth.push(_titleStr.length * 1);
return _titleStr; return _titleStr;
}); });
ExportExcel({ ExportExcel({
name: fileName, name: fileName,
content: [{ content: [
{
sheetData: _dataSource, sheetData: _dataSource,
sheetFilter: _dataIndex, sheetFilter: _dataIndex,
sheetHeader: _title, sheetHeader: _title,
columnWidths: _titleWidth columnWidths: _titleWidth,
}] },
}) ],
});
}; };
const handleTableData = useCallback((data) => { const handleTableData = useCallback(
(data) => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
// data = data.filter(item => item.sensorName !== '是否在线'); // data = data.filter(item => item.sensorName !== '是否在线');
const ignoreOutliers = checkboxData.find((item) => item.key === 'ignoreOutliers').checked; const ignoreOutliers = checkboxData.find((item) => item.key === 'ignoreOutliers').checked;
const dataIndexAccess = (dataItem, index) => { const dataIndexAccess = (dataItem, index) => {
const {stationCode, sensorName} = dataItem; const { stationCode, sensorName } = dataItem;
return `${stationCode}-${sensorName}-${index}`; return `${stationCode}-${sensorName}-${index}`;
}; };
...@@ -863,13 +913,13 @@ const HistoryView = (props) => { ...@@ -863,13 +913,13 @@ const HistoryView = (props) => {
// 判断是否是单设备,单设备则不显示设备名称 // 判断是否是单设备,单设备则不显示设备名称
// 处理表头数据 // 处理表头数据
const columnsData = data.map((item, index) => { const columnsData = data.map((item, index) => {
const {stationCode, equipmentName, sensorName, unit, dataModel} = item; const { stationCode, equipmentName, sensorName, unit, dataModel } = item;
const dataIndex = dataIndexAccess(item, index); const dataIndex = dataIndexAccess(item, index);
let _title = ''; let _title = '';
if (deviceConfig.current.oneDevice) { if (deviceConfig.current.oneDevice) {
_title = `${sensorName}${unit ? `(${unit})` : ''}`; _title = `${sensorName}${unit ? `(${unit})` : ''}`;
} else { } else {
_title = `${equipmentName}-${sensorName}${unit ? `(${unit})` : ''}` _title = `${equipmentName}-${sensorName}${unit ? `(${unit})` : ''}`;
} }
let col = { let col = {
title: _title, title: _title,
...@@ -878,7 +928,7 @@ const HistoryView = (props) => { ...@@ -878,7 +928,7 @@ const HistoryView = (props) => {
ellipsis: true, ellipsis: true,
align: 'center', align: 'center',
width: 200, width: 200,
name: equipmentName name: equipmentName,
}; };
// 同期对比 // 同期对比
if (timeValue === 'contrast' && dataModel[0]) { if (timeValue === 'contrast' && dataModel[0]) {
...@@ -893,7 +943,7 @@ const HistoryView = (props) => { ...@@ -893,7 +943,7 @@ const HistoryView = (props) => {
// 格式化时间对齐数据, 生成行数 // 格式化时间对齐数据, 生成行数
const timeData = {}; const timeData = {};
const buildDefaultData = (time) => { const buildDefaultData = (time) => {
const obj = {key: time, time: time}; const obj = { key: time, time: time };
data.forEach((item, index) => { data.forEach((item, index) => {
const dataIndex = dataIndexAccess(item, index); const dataIndex = dataIndexAccess(item, index);
obj[dataIndex] = ''; obj[dataIndex] = '';
...@@ -902,7 +952,7 @@ const HistoryView = (props) => { ...@@ -902,7 +952,7 @@ const HistoryView = (props) => {
return obj; return obj;
}; };
data.forEach((item, index) => { data.forEach((item, index) => {
const {stationCode, sensorName, dataModel} = item; const { stationCode, sensorName, dataModel } = item;
dataModel && dataModel &&
dataModel.forEach((data) => { dataModel.forEach((data) => {
const formatTime = moment(data.pt).format(format); const formatTime = moment(data.pt).format(format);
...@@ -917,7 +967,7 @@ const HistoryView = (props) => { ...@@ -917,7 +967,7 @@ const HistoryView = (props) => {
}); });
// 处理表格数据 // 处理表格数据
data.forEach((child, index) => { data.forEach((child, index) => {
const {dataModel} = child; const { dataModel } = child;
const dataIndex = dataIndexAccess(child, index); const dataIndex = dataIndexAccess(child, index);
dataModel && dataModel &&
dataModel.forEach((value, j) => { dataModel.forEach((value, j) => {
...@@ -941,7 +991,9 @@ const HistoryView = (props) => { ...@@ -941,7 +991,9 @@ const HistoryView = (props) => {
const tableData = times.map((time) => timeData[time]); const tableData = times.map((time) => timeData[time]);
setColumns([timeColumn, ...columnsData]); setColumns([timeColumn, ...columnsData]);
setTableData(tableData); setTableData(tableData);
}, [timeOrder, timeValue, contrastOption]); },
[timeOrder, timeValue, contrastOption],
);
const [deviceAlarmSchemes, setDeviceAlarmSchemes] = useState([]); const [deviceAlarmSchemes, setDeviceAlarmSchemes] = useState([]);
const beforChangeParams = (value = {}) => { const beforChangeParams = (value = {}) => {
...@@ -966,40 +1018,45 @@ const HistoryView = (props) => { ...@@ -966,40 +1018,45 @@ const HistoryView = (props) => {
}; };
const handleDataThinKey = (diffYears, diffDays, diffHours, lineDataType) => { const handleDataThinKey = (diffYears, diffDays, diffHours, lineDataType) => {
if (lineDataType === '原始曲线') { if (lineDataType === '原始曲线') {
return {unit: '', zoom: ''} return { unit: '', zoom: '' };
} }
// edit by zy 根据选择的时长控制抽稀频度 // edit by zy 根据选择的时长控制抽稀频度
if (diffYears > 0) { if (diffYears > 0) {
if (diffYears === 1) return {unit: 'h', zoom: '24'} if (diffYears === 1) return { unit: 'h', zoom: '24' };
return {unit: 'h', zoom: '48'} return { unit: 'h', zoom: '48' };
} else if (diffYears === 0 && diffDays > 0) { } else if (diffYears === 0 && diffDays > 0) {
if (diffDays > 90) return {unit: 'h', zoom: '24'} if (diffDays > 90) return { unit: 'h', zoom: '24' };
if (diffDays > 30) return {unit: 'h', zoom: '4'} if (diffDays > 30) return { unit: 'h', zoom: '4' };
if (diffDays > 15) return {unit: 'h', zoom: '2'} if (diffDays > 15) return { unit: 'h', zoom: '2' };
if (diffDays > 7) return {unit: 'h', zoom: '1'} if (diffDays > 7) return { unit: 'h', zoom: '1' };
if (diffDays > 3) return {unit: 'min', zoom: '20'} if (diffDays > 3) return { unit: 'min', zoom: '20' };
if (diffDays > 1) return {unit: 'min', zoom: '15'} if (diffDays > 1) return { unit: 'min', zoom: '15' };
if (diffDays === 1) return {unit: 'min', zoom: '5'} if (diffDays === 1) return { unit: 'min', zoom: '5' };
} else if (diffYears === 0 && diffDays === 0 && diffHours > 0) { } else if (diffYears === 0 && diffDays === 0 && diffHours > 0) {
if (diffHours > 12) return {unit: 'min', zoom: '5'} if (diffHours > 12) return { unit: 'min', zoom: '5' };
if (diffHours > 4) return {unit: 'min', zoom: '1'} if (diffHours > 4) return { unit: 'min', zoom: '1' };
if (diffHours > 1) return {unit: 's', zoom: '30'} if (diffHours > 1) return { unit: 's', zoom: '30' };
if (diffHours > 0) return {unit: 's', zoom: '5'} if (diffHours > 0) return { unit: 's', zoom: '5' };
return {unit: 's', zoom: '5'} return { unit: 's', zoom: '5' };
} else { } else {
return {unit: '', zoom: ''} return { unit: '', zoom: '' };
} }
}; };
// 处理接口服务参数的变化 // 处理接口服务参数的变化
const onChangeParams = (value = {}) => { const onChangeParams = (value = {}) => {
const {dateRange, isDilute, ignoreOutliers, zoom, unit} = value; const { dateRange, isDilute, ignoreOutliers, zoom, unit } = value;
let _diffDays = moment(dateRange[0].dateTo).diff(dateRange[0].dateFrom, 'days');
// 查询时段大于7天时,不提供1分钟的抽稀选项。
if (_diffDays > 7 && zoom === '1' && unit === 'min') {
return false;
}
const requestArr = []; const requestArr = [];
const acrossTables = []; const acrossTables = [];
const zoomArray = []; const zoomArray = [];
deviceParams deviceParams
.map((item) => { .map((item) => {
let _item = {...item}; let _item = { ...item };
// 历史曲线中,是否在线暂时去除,不显示 要显示是否在线解开这里即可 2023-09-15 // 历史曲线中,是否在线暂时去除,不显示 要显示是否在线解开这里即可 2023-09-15
/* _item.sensors = /* _item.sensors =
item.sensors && !item.sensors.includes('是否在线') item.sensors && !item.sensors.includes('是否在线')
...@@ -1037,17 +1094,21 @@ const HistoryView = (props) => { ...@@ -1037,17 +1094,21 @@ const HistoryView = (props) => {
let diffYears = moment(item.dateTo).diff(moment(item.dateFrom), 'years'); let diffYears = moment(item.dateTo).diff(moment(item.dateFrom), 'years');
let diffDays = moment(item.dateTo).diff(moment(item.dateFrom), 'days'); let diffDays = moment(item.dateTo).diff(moment(item.dateFrom), 'days');
let diffHours = moment(item.dateTo).diff(moment(item.dateFrom), 'hours'); let diffHours = moment(item.dateTo).diff(moment(item.dateFrom), 'hours');
let zoomParam = activeTabKey === 'curve' ? handleDataThinKey(diffYears, diffDays, diffHours, lineDataType) : {}; let zoomParam =
zoomArray.push(zoomParam); activeTabKey === 'curve'
requestArr.push(getHistoryInfo({...param, ...zoomParam})); ? handleDataThinKey(diffYears, diffDays, diffHours, lineDataType)
: {};
requestArr.push(getHistoryInfo({ ...param, ...zoomParam }));
}); });
setLoading(true); setLoading(true);
Promise.all(requestArr).then((results) => { Promise.all(requestArr)
.then((results) => {
setLoading(false); setLoading(false);
if (results.length) { if (results.length) {
let data = []; let data = [];
results.forEach((res, index) => { results.forEach((res, index) => {
const {dateFrom, dateTo} = dateRange?.[index] ?? {}; const { dateFrom, dateTo } = dateRange?.[index] ?? {};
if (res.code === 0 && res.data.length) { if (res.code === 0 && res.data.length) {
res.data.forEach((d) => { res.data.forEach((d) => {
d.dateFrom = dateFrom || ''; d.dateFrom = dateFrom || '';
...@@ -1062,7 +1123,8 @@ const HistoryView = (props) => { ...@@ -1062,7 +1123,8 @@ const HistoryView = (props) => {
sensors.push(special1.name); sensors.push(special1.name);
} }
} }
const list = sensors.map((s) => { const list = sensors
.map((s) => {
const dataItem = res.data.find( const dataItem = res.data.find(
(d) => d.stationCode === p.deviceCode && d.sensorName === s, (d) => d.stationCode === p.deviceCode && d.sensorName === s,
); );
...@@ -1073,7 +1135,8 @@ const HistoryView = (props) => { ...@@ -1073,7 +1135,8 @@ const HistoryView = (props) => {
} else { } else {
return {}; return {};
} }
}).filter(item => item.sensorName); })
.filter((item) => item.sensorName);
data = data.concat(list); data = data.concat(list);
}); });
} }
...@@ -1082,15 +1145,16 @@ const HistoryView = (props) => { ...@@ -1082,15 +1145,16 @@ const HistoryView = (props) => {
handleTableData(data); handleTableData(data);
setChartDataSource(data); setChartDataSource(data);
} }
}).catch(err => { })
.catch((err) => {
message.info('未查询到数据,请重试~'); message.info('未查询到数据,请重试~');
setLoading(false) setLoading(false);
}); });
}; };
useEffect(() => { useEffect(() => {
if (!completeInit) return; if (!completeInit) return;
const {dataThin, ignoreOutliers, zoom, unit} = dataConfig; const { dataThin, ignoreOutliers, zoom, unit } = dataConfig;
beforChangeParams().finally(() => { beforChangeParams().finally(() => {
onChangeParams({ onChangeParams({
isDilute: dataThin, isDilute: dataThin,
...@@ -1104,11 +1168,12 @@ const HistoryView = (props) => { ...@@ -1104,11 +1168,12 @@ const HistoryView = (props) => {
}, [dateRange, dataConfig, deviceParams, chartType, lineDataType, completeInit, algorithmValue]); }, [dateRange, dataConfig, deviceParams, chartType, lineDataType, completeInit, algorithmValue]);
const handleChange = (pagination, filter, sort) => { const handleChange = (pagination, filter, sort) => {
if (sort.field === 'time') { if (sort.field === 'time') {
setTimeOrder(sort.order) setTimeOrder(sort.order);
} }
}; };
const tableMemo = useMemo(() => { const tableMemo = useMemo(() => {
return <> return (
<>
<div className={`${prefixCls}-options`}> <div className={`${prefixCls}-options`}>
{renderTimeOption} {renderTimeOption}
{renderCurveOption()} {renderCurveOption()}
...@@ -1118,7 +1183,7 @@ const HistoryView = (props) => { ...@@ -1118,7 +1183,7 @@ const HistoryView = (props) => {
<BasicTable <BasicTable
dataSource={tableData.sort((a, b) => { dataSource={tableData.sort((a, b) => {
let _a = a.time; let _a = a.time;
let _b = b.time let _b = b.time;
if (timeValue === 'contrast') { if (timeValue === 'contrast') {
if (contrastOption === 'day') { if (contrastOption === 'day') {
_a = `2000-01-01 ${a.time}:00`; _a = `2000-01-01 ${a.time}:00`;
...@@ -1135,32 +1200,33 @@ const HistoryView = (props) => { ...@@ -1135,32 +1200,33 @@ const HistoryView = (props) => {
{...tableProps} {...tableProps}
pagination={false} pagination={false}
onChange={handleChange} onChange={handleChange}
scroll={{x: 'max-content', y: 'calc(100% - 40px)'}} scroll={{ x: 'max-content', y: 'calc(100% - 40px)' }}
/> />
) : ( ) : (
<PandaEmpty/> <PandaEmpty />
)} )}
</div> </div>
</> </>
}, [timeOrder, chartDataSource, columns, tableProps, tableData, isSingleStatusSensor]) );
}, [timeOrder, chartDataSource, columns, tableProps, tableData, isSingleStatusSensor, dateRange]);
const returnLongestPeriod = (data) => { const returnLongestPeriod = (data) => {
let _earliest = '' let _earliest = '';
let _latest = ''; let _latest = '';
data.forEach(item => { data.forEach((item) => {
let _length = item.dataModel.length; let _length = item.dataModel.length;
let _tempFirst = item.dataModel[0].pt; let _tempFirst = item.dataModel[0].pt;
let _tempLast = item.dataModel[_length - 1].pt; let _tempLast = item.dataModel[_length - 1].pt;
if (_earliest) { if (_earliest) {
_earliest = moment(_earliest) > moment(_tempFirst) ? _tempFirst : _earliest _earliest = moment(_earliest) > moment(_tempFirst) ? _tempFirst : _earliest;
} else { } else {
_earliest = _tempFirst _earliest = _tempFirst;
} }
if (_latest) { if (_latest) {
_latest = moment(_latest) < moment(_tempLast) ? _tempLast : _latest _latest = moment(_latest) < moment(_tempLast) ? _tempLast : _latest;
} else { } else {
_latest = _tempLast; _latest = _tempLast;
} }
}) });
return `${_earliest} - ${_latest}`; return `${_earliest} - ${_latest}`;
}; };
const renderPanel = (model) => { const renderPanel = (model) => {
...@@ -1172,16 +1238,17 @@ const HistoryView = (props) => { ...@@ -1172,16 +1238,17 @@ const HistoryView = (props) => {
{renderCurveOption( {renderCurveOption(
true, true,
deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1, deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1,
isSingleStatusSensor isSingleStatusSensor,
)} )}
</div> </div>
{ {lineDataType === '原始曲线' && false ? (
lineDataType === '原始曲线' && false ? <div style={{ marginTop: 10 }}>展示区间:{returnLongestPeriod(chartDataSource)}</div>
<div style={{marginTop: 10}}>展示区间:{returnLongestPeriod(chartDataSource)}</div> : '' ) : (
} ''
)}
<div className={`${prefixCls}-content`}> <div className={`${prefixCls}-content`}>
{!chartDataSource.length ? ( {!chartDataSource.length ? (
<PandaEmpty/> <PandaEmpty />
) : grid === true ? ( ) : grid === true ? (
<GridChart <GridChart
curveCenter={curveCenter} curveCenter={curveCenter}
...@@ -1221,24 +1288,28 @@ const HistoryView = (props) => { ...@@ -1221,24 +1288,28 @@ const HistoryView = (props) => {
// 获取字段配置 // 获取字段配置
const getDefaultOptions = async () => { const getDefaultOptions = async () => {
// 非单曲线、单指标不执行 // 非单曲线、单指标不执行
if (deviceParams?.length !== 1 || (deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',')?.length > 1)) return setCompleteInit(true); if (
deviceParams?.length !== 1 ||
(deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',')?.length > 1)
)
return setCompleteInit(true);
setLoading(true); setLoading(true);
const {deviceCode, deviceType, sensors} = deviceParams[0]; const { deviceCode, deviceType, sensors } = deviceParams[0];
let _id = (await getPointAddress({ let _id = (
code: deviceCode await getPointAddress({
}))?.data?.[0]?.id; code: deviceCode,
let _params = { })
// deviceType: deviceType )?.data?.[0]?.id;
}; let _params = {};
if (_id) _params.versionId = _id; if (_id) _params.versionId = _id;
// 多曲线的居中,容易导致曲线被截断,故多曲线时,不请求 // 多曲线的居中,容易导致曲线被截断,故多曲线时,不请求
let _request0 = getDictionaryInfoAll({ let _request0 = getDictionaryInfoAll({
level: '组件_ec_historyview' level: '组件_ec_historyview',
}); });
// 以下请求为处理状态值、开关值的图表,只允许单曲线单指标情况下展示 // 以下请求为处理状态值、开关值的图表,只允许单曲线单指标情况下展示
let _request1 = getPointAddressEntry(_params); let _request1 = getPointAddressEntry(_params);
let _request2 = getSensorType(); let _request2 = getSensorType();
await Promise.all([_request0, _request1, _request2]).then(result => { await Promise.all([_request0, _request1, _request2]).then((result) => {
if (result) { if (result) {
let _res0 = result[0]; let _res0 = result[0];
let _res1 = result[1]; let _res1 = result[1];
...@@ -1246,13 +1317,13 @@ const HistoryView = (props) => { ...@@ -1246,13 +1317,13 @@ const HistoryView = (props) => {
// 查字典配置 // 查字典配置
if (_res0.code === 0) { if (_res0.code === 0) {
let _opt = _res0.data.reduce((final, cur) => { let _opt = _res0.data.reduce((final, cur) => {
final[cur.fieldName] = cur.fieldValue final[cur.fieldName] = cur.fieldValue;
return final return final;
}, {}); }, {});
let _checkboxData = [...checkboxData].map(item => { let _checkboxData = [...checkboxData].map((item) => {
let _item = {...item}; let _item = { ...item };
if (_opt[item.label] !== undefined) { if (_opt[item.label] !== undefined) {
_item.checked = _opt[item.label] === 'true' _item.checked = _opt[item.label] === 'true';
} }
return _item; return _item;
}); });
...@@ -1260,19 +1331,19 @@ const HistoryView = (props) => { ...@@ -1260,19 +1331,19 @@ const HistoryView = (props) => {
} }
// 查点表配置 // 查点表配置
if (_res1.code === 0) { if (_res1.code === 0) {
let _sensorConfig = _res1.data.find(item => item?.name.trim() === sensors.trim()); let _sensorConfig = _res1.data.find((item) => item?.name.trim() === sensors.trim());
let _statusName = _sensorConfig?.statusName; let _statusName = _sensorConfig?.statusName;
setAllPointAddress(_res1.data); setAllPointAddress(_res1.data);
if (_statusName) { if (_statusName) {
let _statusConfig = _res1.data.find(item => item?.name.trim() === _statusName.trim()); let _statusConfig = _res1.data.find((item) => item?.name.trim() === _statusName.trim());
let _valDesc = _statusConfig?.valDesc || ''; let _valDesc = _statusConfig?.valDesc || '';
setSpecial1({ setSpecial1({
name: _statusName, name: _statusName,
valDesc: _valDesc.split(';').reduce((final, cur) => { valDesc: _valDesc.split(';').reduce((final, cur) => {
let _arr = cur.split(':'); let _arr = cur.split(':');
final[_arr[0]] = _arr[1]; final[_arr[0]] = _arr[1];
return final return final;
}, {}) }, {}),
}); });
} }
} }
...@@ -1280,8 +1351,8 @@ const HistoryView = (props) => { ...@@ -1280,8 +1351,8 @@ const HistoryView = (props) => {
if (_res2.code === 0) { if (_res2.code === 0) {
setAllSensorType(_res2.data); setAllSensorType(_res2.data);
let _sensorID = _res1.data?.find(item => item.name === sensors)?.sensorTypeID; let _sensorID = _res1.data?.find((item) => item.name === sensors)?.sensorTypeID;
let _sensor = _res2.data?.find(item => item.id === _sensorID)?.type; let _sensor = _res2.data?.find((item) => item.id === _sensorID)?.type;
let _isStatusSensor = ['状态值', '开关值'].includes(_sensor); let _isStatusSensor = ['状态值', '开关值'].includes(_sensor);
setIsSingleStatusSensor(_isStatusSensor); setIsSingleStatusSensor(_isStatusSensor);
} }
...@@ -1291,10 +1362,11 @@ const HistoryView = (props) => { ...@@ -1291,10 +1362,11 @@ const HistoryView = (props) => {
}; };
useEffect(() => { useEffect(() => {
getDefaultOptions(); getDefaultOptions();
}, [deviceParams]) }, [deviceParams]);
let percentTimer = useRef({ let percentTimer = useRef({
timer: null timer: null,
}); });
// 加载动画
useEffect(() => { useEffect(() => {
if (loading === null) return; if (loading === null) return;
if (loading) { if (loading) {
...@@ -1303,34 +1375,45 @@ const HistoryView = (props) => { ...@@ -1303,34 +1375,45 @@ const HistoryView = (props) => {
_percent += 5; _percent += 5;
if (_percent > 95) return clearInterval(percentTimer.current.timer); if (_percent > 95) return clearInterval(percentTimer.current.timer);
setPercent(_percent); setPercent(_percent);
}, 100) }, 100);
} else { } else {
clearInterval(percentTimer.current.timer); clearInterval(percentTimer.current.timer);
setPercent(100); setPercent(100);
setTimeout(() => { setTimeout(
() => {
setPercent(0); setPercent(0);
}, lineDataType === '原始曲线' ? 500 : 0) },
lineDataType === '原始曲线' ? 500 : 0,
);
} }
}, [loading]) }, [loading]);
return ( return (
<div className={classNames(prefixCls, 'wkt-scroll-light')}> <div className={classNames(prefixCls, 'wkt-scroll-light')}>
<div className={classNames(`${prefixCls}-spin`)} style={{position: "relative"}}> <div className={classNames(`${prefixCls}-spin`)} style={{ position: 'relative' }}>
{ {loading || percent !== 0 ? (
(loading || percent !== 0) ? <div className={classNames(`${prefixCls}-progressWrapper`)}> <div className={classNames(`${prefixCls}-progressWrapper`)}>
<div className={classNames(`${prefixCls}-contentWrapper`)}> <div className={classNames(`${prefixCls}-contentWrapper`)}>
{ {lineDataType === '原始曲线' ||
lineDataType === '原始曲线' || lineDataType === '特征曲线' && moment(dateRange?.[0]?.dateTo).diff(moment(dateRange?.[0]?.dateFrom), 'days') >= 30 ? <> (lineDataType === '特征曲线' &&
<Progress percent={percent} moment(dateRange?.[0]?.dateTo).diff(moment(dateRange?.[0]?.dateFrom), 'days') >=
30) ? (
<>
<Progress
percent={percent}
steps={20} steps={20}
className={classNames(`${prefixCls}-progress`, `${prefixCls}-blink-2`)} className={classNames(`${prefixCls}-progress`, `${prefixCls}-blink-2`)}
showInfo={false}/> showInfo={false}
/>
<div className={classNames(`${prefixCls}-tip`)}>加载中...</div> <div className={classNames(`${prefixCls}-tip`)}>加载中...</div>
</> : <Spin spinning={loading || false}/> </>
} ) : (
<Spin spinning={loading || false} />
)}
</div> </div>
</div> : '' </div>
} ) : (
''
)}
{showModels.length === 1 && ( {showModels.length === 1 && (
<div className={`${prefixCls}-single-panel`}>{renderPanel(showModels[0])}</div> <div className={`${prefixCls}-single-panel`}>{renderPanel(showModels[0])}</div>
)} )}
...@@ -1346,11 +1429,11 @@ const HistoryView = (props) => { ...@@ -1346,11 +1429,11 @@ const HistoryView = (props) => {
{activeTabKey === 'table' && ( {activeTabKey === 'table' && (
<> <>
<Button type="link" onClick={exportFeatureBtn}> <Button type="link" onClick={exportFeatureBtn}>
<DownloadOutlined/> <DownloadOutlined />
特征数据 特征数据
</Button> </Button>
<Button type="link" onClick={exportExcelBtn}> <Button type="link" onClick={exportExcelBtn}>
<DownloadOutlined/> <DownloadOutlined />
原始数据 原始数据
</Button> </Button>
</> </>
...@@ -1360,9 +1443,7 @@ const HistoryView = (props) => { ...@@ -1360,9 +1443,7 @@ const HistoryView = (props) => {
}} }}
> >
<Tabs.TabPane key="curve" tab="曲线" forceRender={true}> <Tabs.TabPane key="curve" tab="曲线" forceRender={true}>
{ {activeTabKey === 'curve' ? renderPanel('curve') : ''}
activeTabKey === 'curve' ? renderPanel('curve') : ''
}
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane key="table" tab="表格"> <Tabs.TabPane key="table" tab="表格">
{renderPanel('table')} {renderPanel('table')}
......
import moment from 'moment'; import moment from 'moment';
import _, {isArray} from 'lodash'; import _, { isArray } from 'lodash';
import maxIcon from './assets/最大实心.svg'; import maxIcon from './assets/最大实心.svg';
import minIcon from './assets/最小实心.svg'; import minIcon from './assets/最小实心.svg';
import minIconDownArrow from './assets/最小实心箭头朝下.svg'; import minIconDownArrow from './assets/最小实心箭头朝下.svg';
import lineChart from '@wisdom-components/basicchart/es/LineChart'; import lineChart from '@wisdom-components/basicchart/es/LineChart';
import * as echarts from "echarts"; import * as echarts from 'echarts';
/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */ /** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const AXIS_WIDTH = 40; const AXIS_WIDTH = 40;
...@@ -68,7 +68,7 @@ const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION; ...@@ -68,7 +68,7 @@ const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION;
* @returns * @returns
*/ */
const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => { const nameFormatter = (data, contrast, contrastOption, nameWithSensor) => {
const {equipmentName, sensorName, unit, dataModel, dateFrom, dateTo} = data; const { equipmentName, sensorName, unit, dataModel, dateFrom, dateTo } = data;
let name = nameWithSensor ? `${equipmentName}-${sensorName}` : equipmentName; let name = nameWithSensor ? `${equipmentName}-${sensorName}` : equipmentName;
if (contrast) { if (contrast) {
const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, ''); const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
...@@ -103,7 +103,7 @@ const dataAccessor = (data, contrast, contrastOption) => { ...@@ -103,7 +103,7 @@ const dataAccessor = (data, contrast, contrastOption) => {
* @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图. * @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
*/ */
const areaStyleFormatter = (data) => { const areaStyleFormatter = (data) => {
const {sensorName} = data; const { sensorName } = data;
return sensorName && sensorName.indexOf('流量') > -1 ? {} : null; return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
}; };
...@@ -114,7 +114,7 @@ const areaStyleFormatter = (data) => { ...@@ -114,7 +114,7 @@ const areaStyleFormatter = (data) => {
* @returns * @returns
*/ */
const minMax = (data) => { const minMax = (data) => {
const {dataModel} = data; const { dataModel } = data;
let min = Number.MAX_SAFE_INTEGER; let min = Number.MAX_SAFE_INTEGER;
let max = Number.MIN_SAFE_INTEGER; let max = Number.MIN_SAFE_INTEGER;
dataModel.forEach((item) => { dataModel.forEach((item) => {
...@@ -145,7 +145,7 @@ const markLineItem = (name, value, color) => { ...@@ -145,7 +145,7 @@ const markLineItem = (name, value, color) => {
export const alarmMarkLine = (dataItem, index, dataSource, schemes) => { export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
// 只有一个数据曲线时显示markline // 只有一个数据曲线时显示markline
if (!dataItem || !schemes || dataSource.length !== 1) return {}; if (!dataItem || !schemes || dataSource.length !== 1) return {};
const {deviceType, stationCode, sensorName, decimalPoint} = dataItem; const { deviceType, stationCode, sensorName, decimalPoint } = dataItem;
const curSchemes = schemes.filter( const curSchemes = schemes.filter(
(item) => (item) =>
item.deviceCode === stationCode && item.deviceCode === stationCode &&
...@@ -154,7 +154,7 @@ export const alarmMarkLine = (dataItem, index, dataSource, schemes) => { ...@@ -154,7 +154,7 @@ export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
); );
const data = []; const data = [];
curSchemes.forEach((scheme) => { curSchemes.forEach((scheme) => {
const {hLimit, hhLimit, lLimit, llLimit} = scheme; const { hLimit, hhLimit, lLimit, llLimit } = scheme;
lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16')); lLimit !== null && lLimit !== void 0 && data.push(markLineItem('低限', lLimit, '#fa8c16'));
hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16')); hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000')); llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
...@@ -246,7 +246,7 @@ export const decorateAxisGridLine = (axis, showGrid) => { ...@@ -246,7 +246,7 @@ export const decorateAxisGridLine = (axis, showGrid) => {
*/ */
export const offlineArea = (dataItem) => { export const offlineArea = (dataItem) => {
if (!dataItem) return {}; if (!dataItem) return {};
const {dataModel} = dataItem; const { dataModel } = dataItem;
let datas = new Array(); let datas = new Array();
let offlineData = []; let offlineData = [];
let hasOffline = false; let hasOffline = false;
...@@ -256,7 +256,7 @@ export const offlineArea = (dataItem) => { ...@@ -256,7 +256,7 @@ export const offlineArea = (dataItem) => {
{ {
name: '离线', name: '离线',
xAxis: new Date(item.pt), xAxis: new Date(item.pt),
label: {show: !datas?.length}, label: { show: !datas?.length },
}, },
]; ];
hasOffline = true; hasOffline = true;
...@@ -280,7 +280,7 @@ export const offlineArea = (dataItem) => { ...@@ -280,7 +280,7 @@ export const offlineArea = (dataItem) => {
// tooltip 模板 // tooltip 模板
const headTemplate = (param, opt) => { const headTemplate = (param, opt) => {
if (!param) return ''; if (!param) return '';
const {name, axisValueLabel, axisType, axisValue} = param; const { name, axisValueLabel, axisType, axisValue } = param;
const timeFormat = const timeFormat =
opt && opt.contrast opt && opt.contrast
? opt.contrastOption === 'day' ? opt.contrastOption === 'day'
...@@ -296,57 +296,65 @@ const headTemplate = (param, opt) => { ...@@ -296,57 +296,65 @@ const headTemplate = (param, opt) => {
}; };
const seriesTemplate = (param, unit) => { const seriesTemplate = (param, unit) => {
if (!param || param.seriesName === '自定义') return ''; if (!param || param.seriesName === '自定义') return '';
const {value, encode} = param; const { value, encode } = param;
// const val = value[encode.y[0]]; // const val = value[encode.y[0]];
const _unit = unit || ''; const _unit = unit || '';
const color = '#008CFF'; const color = '#008CFF';
if (!isArray(value)) if (!isArray(value))
return ` <div style="display: flex; align-items: center;"> return ` <div style="display: flex; align-items: center;">
<span style="${isMobile() <span style="${
isMobile()
? 'width: ' + ? 'width: ' +
handlePx(90, 'px') + handlePx(90, 'px') +
';overflow:hidden;text-overflow:ellipsis;white-space:nowrap' ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
: '' : ''
}">${param.seriesName}</span> }">${param.seriesName}</span>
<span style="display:inline-block;">:</span> <span style="display:inline-block;">:</span>
<span style="color:${color};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value?.toFixed(3) ?? '-' <span style="color:${color};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value?.toFixed(3) ?? '-'
}</span> }</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div>`; </div>`;
return param.componentSubType !== 'candlestick' return param.componentSubType !== 'candlestick'
? `<div style="display: flex; align-items: center;"> ? `<div style="display: flex; align-items: center;">
<span style="${isMobile() <span style="${
isMobile()
? 'width: ' + ? 'width: ' +
handlePx(90, 'px') + handlePx(90, 'px') +
';overflow:hidden;text-overflow:ellipsis;white-space:nowrap' ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
: '' : ''
}">${param.seriesName}</span><span style="display:inline-block;">:</span> }">${param.seriesName}</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[1] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value[1] ?? '-'
}</span> }</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div>` </div>`
: ` : `
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>首值</span><span style="display:inline-block;">:</span> <span>首值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[1] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value[1] ?? '-'
}</span> }</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>尾值</span><span style="display:inline-block;">:</span> <span>尾值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[2] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value[2] ?? '-'
}</span> }</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>周期最小值</span><span style="display:inline-block;">:</span> <span>周期最小值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[3] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value[3] ?? '-'
}</span> }</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span>周期最大值</span><span style="display:inline-block;">:</span> <span>周期最大值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${value[4] ?? '-' <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(5, 'px')} 0 auto;">${
value[4] ?? '-'
}</span> }</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
...@@ -409,7 +417,7 @@ const handleSpecial1 = (special, dataSource) => { ...@@ -409,7 +417,7 @@ const handleSpecial1 = (special, dataSource) => {
} else { } else {
final.push({ final.push({
lte: _pt, lte: _pt,
gte: _pt, gte: final[_length - 1].gte,
color: _colorMap[_valDesc[cur.pv]], color: _colorMap[_valDesc[cur.pv]],
value: cur.pv, value: cur.pv,
text: _valDesc[cur.pv], text: _valDesc[cur.pv],
...@@ -445,7 +453,7 @@ const handleSpecial1 = (special, dataSource) => { ...@@ -445,7 +453,7 @@ const handleSpecial1 = (special, dataSource) => {
}, },
}, },
name: item.text, name: item.text,
label: {show: true}, label: { show: true },
}, },
{ {
xAxis: item.lte, xAxis: item.lte,
...@@ -490,18 +498,18 @@ const returnXAxis = ({ ...@@ -490,18 +498,18 @@ const returnXAxis = ({
restOption, restOption,
smooth, smooth,
special, special,
yAxis yAxis,
}) => { }) => {
// 根据"指标名称"分类yAxis // 根据"指标名称"分类yAxis
const yAxisInterator = (() => { const yAxisInterator = (() => {
const map = new Map(); const map = new Map();
let current = -1; let current = -1;
const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name)); const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
return {get}; return { get };
})(); })();
let _offlineData = []; let _offlineData = [];
// 生成visualMap、markArea // 生成visualMap、markArea
let {visualMap, markArea} = handleSpecial1(special, dataSource); let { visualMap, markArea } = handleSpecial1(special, dataSource);
let _filterArr = ['是否在线']; let _filterArr = ['是否在线'];
if (special?.special1?.name) { if (special?.special1?.name) {
_filterArr.push(special.special1.name); _filterArr.push(special.special1.name);
...@@ -515,12 +523,12 @@ const returnXAxis = ({ ...@@ -515,12 +523,12 @@ const returnXAxis = ({
return !_filterArr.includes(item.sensorName); return !_filterArr.includes(item.sensorName);
}) })
.map((item, index) => { .map((item, index) => {
const {sensorName, unit} = item; const { sensorName, unit } = item;
const name = nameFormatter(item, contrast, contrastOption, nameWithSensor); const name = nameFormatter(item, contrast, contrastOption, nameWithSensor);
const data = dataAccessor(item, contrast, contrastOption); const data = dataAccessor(item, contrast, contrastOption);
const type = 'line'; const type = 'line';
const areaStyle = areaStyleFormatter(item); const areaStyle = areaStyleFormatter(item);
const _index = yAxis.findIndex(item => item.name === unit); const _index = yAxis.findIndex((item) => item.name === unit);
const yAxisIndex = _index > -1 ? _index : 0; const yAxisIndex = _index > -1 ? _index : 0;
const markLine = showMarkLine const markLine = showMarkLine
? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes) ? alarmMarkLine(item, index, dataSource, deviceAlarmSchemes)
...@@ -616,70 +624,69 @@ const handleMaxValue = (value) => { ...@@ -616,70 +624,69 @@ const handleMaxValue = (value) => {
if (value <= 1) return value.toFixed(2); if (value <= 1) return value.toFixed(2);
if (value >= 100000) return `${(value / 1000).toFixed(2)}k`; if (value >= 100000) return `${(value / 1000).toFixed(2)}k`;
return value.toFixed(2); return value.toFixed(2);
} };
const reduceYAxis = (arr, dataSource) => { const reduceYAxis = (arr, dataSource) => {
let _offsetValue = []; let _offsetValue = [];
// 1. 合并相同单位的坐标轴 // 1. 合并相同单位的坐标轴
let _arr = arr.reduce((final, cur) => { let _arr = arr.reduce((final, cur) => {
let _key = cur.name === null ? 'null' : cur.name let _key = cur.name === null ? 'null' : cur.name;
if (!final[_key]) { if (!final[_key]) {
final[_key] = cur final[_key] = cur;
} }
return final; return final;
}, {}); }, {});
// 2. 合并相同单位的数据,找出最大值 // 2. 合并相同单位的数据,找出最大值
let _maxValueArr = Object.values(dataSource.reduce((final, cur) => { let _maxValueArr = Object.values(
dataSource.reduce((final, cur) => {
let _key = cur.sensorName === null ? 'null' : cur.sensorName; let _key = cur.sensorName === null ? 'null' : cur.sensorName;
let _maxValue = cur.dataModel.reduce((final, cur) => { let _maxValue = cur.dataModel.reduce((final, cur) => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
if (cur.pv > final) final = cur.pv; if (cur.pv > final) final = cur.pv;
return final return final;
}, 0); }, 0);
if (final[_key] === undefined) { if (final[_key] === undefined) {
final[_key] = _maxValue final[_key] = _maxValue;
} else { } else {
final[_key] = Math.max([final[_key], _maxValue]); final[_key] = Math.max([final[_key], _maxValue]);
} }
return final return final;
}, {})); }, {}),
);
// 3. 合并,生成Y轴配置 // 3. 合并,生成Y轴配置
return Object.values(_arr).map((item, index) => { return Object.values(_arr).map((item, index) => {
let _key = item.name === null ? 'null' : item.name; let _key = item.name === null ? 'null' : item.name;
let _lastAxisNumber = _maxValueArr[index - 2]; let _lastAxisNumber = _maxValueArr[index - 2];
let _baseOffset = _offsetValue[index - 2] ?? 0; let _baseOffset = _offsetValue[index - 2] ?? 0;
let _finalOffset = ( let _finalOffset =
_lastAxisNumber !== undefined ? // 没有相邻的轴 (_lastAxisNumber !== undefined // 没有相邻的轴
(_lastAxisNumber === 0 ? 20 : _lastAxisNumber.toFixed(2).replaceAll('.', '').length) * 12 ? (_lastAxisNumber === 0 ? 20 : _lastAxisNumber.toFixed(2).replaceAll('.', '').length) * 12
: 0 : 0) + _baseOffset;
) + _baseOffset;
_offsetValue.push(_finalOffset); _offsetValue.push(_finalOffset);
return ({ return {
...item, ...item,
offset: _finalOffset, offset: _finalOffset,
position: index % 2 === 0 ? 'left' : 'right', position: index % 2 === 0 ? 'left' : 'right',
nameTextStyle: { nameTextStyle: {
align: index % 2 === 0 ? 'right' : 'left', align: index % 2 === 0 ? 'right' : 'left',
}, },
}) };
}); });
}; };
/** /**
* * 1. 生成常规的yAxis配置; 2. 处理sensorType为状态值的指标,生成yAxis配置
* 1. 生成常规的yAxis配置;
* 2. 处理sensorType为状态值的指标,生成yAxis配置
* *
* @param {array} dataSource 数据源 * @param {array} dataSource 数据源
* @param {boolean} needUnit 是否显示单位。 * @param {boolean} needUnit 是否显示单位。
* @param {boolean} curveCenter 曲线是否居中。 * @param {boolean} curveCenter 曲线是否居中。
* @param {boolean} showGridLine 是否显示网格线。 * @param {boolean} showGridLine 是否显示网格线。
* @return {object} 返回左右轴的margin、yAxis的配置。 * @returns {object} 返回左右轴的margin、yAxis的配置。
* */ */
const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => { const handleYAxis = ({ dataSource, needUnit, curveCenter, showGridLine }) => {
const yAxisMap = new Map(); const yAxisMap = new Map();
// 1. 找出最大值; 2. 计算出y轴最大宽度动态计算偏移距离; // 1. 找出最大值; 2. 计算出y轴最大宽度动态计算偏移距离;
dataSource.forEach((item, index) => { dataSource.forEach((item, index) => {
const {sensorName, unit} = item; const { sensorName, unit } = item;
const key = sensorName; const key = sensorName;
if (!yAxisMap.has(key)) { if (!yAxisMap.has(key)) {
const axis = { const axis = {
...@@ -688,7 +695,7 @@ const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => { ...@@ -688,7 +695,7 @@ const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => {
axisLabel: { axisLabel: {
formatter: (value) => { formatter: (value) => {
return handleMaxValue(value); return handleMaxValue(value);
} },
}, },
axisLine: { axisLine: {
show: true, show: true,
...@@ -718,25 +725,35 @@ const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => { ...@@ -718,25 +725,35 @@ const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => {
const axis = yAxisMap.get(key); const axis = yAxisMap.get(key);
decorateAxisGridLine(axis, showGridLine); decorateAxisGridLine(axis, showGridLine);
}); });
const yAxis = yAxisMap.size > 0 ? reduceYAxis([...yAxisMap.values()], dataSource) : {type: 'value'}; const yAxis =
yAxisMap.size > 0 ? reduceYAxis([...yAxisMap.values()], dataSource) : { type: 'value' };
const leftNum = Math.ceil(yAxisMap.size / 2); const leftNum = Math.ceil(yAxisMap.size / 2);
const rightNum = Math.floor(yAxisMap.size / 2); const rightNum = Math.floor(yAxisMap.size / 2);
return {leftNum, rightNum, yAxis}; return { leftNum, rightNum, yAxis };
}; };
/** /**
* 1. 最后的配置处理、合并 * 1. 最后的配置处理、合并
* dataZoom 缩放 * dataZoom 缩放
* xAxis.minInterval X轴的最小间隔 * xAxis.minInterval X轴的最小间隔
* legend legend配置 * legend legend配置
*
* @param {object} restOption 额外配置 * @param {object} restOption 额外配置
* @param {object} xAxis x轴的配置 * @param {object} xAxis X轴的配置
* @param {array} legendData legend数组 * @param {array} legendData Legend数组
* @param {string} chartType 线型 lineChart|boxChart * @param {string} chartType 线型 lineChart|boxChart
* @param {boolean} contrast 是否为同期对比 * @param {boolean} contrast 是否为同期对比
* @param {string} contrastOption 同期对比周期配置, day|month * @param {string} contrastOption 同期对比周期配置, day|month
* @param {object} config 其他的配置 * @param {object} config 其他的配置
* */ */
const assignOptions = (restOption, xAxis, legendData, chartType, contrast, contrastOption, config) => { const assignOptions = (
restOption,
xAxis,
legendData,
chartType,
contrast,
contrastOption,
config,
) => {
restOption.dataZoom = [ restOption.dataZoom = [
{ {
show: true, show: true,
...@@ -771,13 +788,15 @@ const assignOptions = (restOption, xAxis, legendData, chartType, contrast, contr ...@@ -771,13 +788,15 @@ const assignOptions = (restOption, xAxis, legendData, chartType, contrast, contr
restOption.legend = { restOption.legend = {
...{ ...{
show: true, show: true,
right:10, right: 10,
top: 30, top: 30,
icon: 'rect', icon: 'rect',
itemWidth: 14, itemWidth: 14,
itemHeight: 8, itemHeight: 8,
itemGap: 20, itemGap: 20,
}, ...restOption.legend, ...{data: legendData} },
...restOption.legend,
...{ data: legendData },
}; };
} }
}; };
...@@ -912,24 +931,24 @@ const renderStatusItem = (params, api) => { ...@@ -912,24 +931,24 @@ const renderStatusItem = (params, api) => {
x: start[0], x: start[0],
y: start[1] - height / 2, y: start[1] - height / 2,
width: end[0] - start[0], width: end[0] - start[0],
height: height height: height,
}, },
{ {
x: params.coordSys.x, x: params.coordSys.x,
y: params.coordSys.y, y: params.coordSys.y,
width: params.coordSys.width, width: params.coordSys.width,
height: params.coordSys.height height: params.coordSys.height,
} },
); );
return ( return (
rectShape && { rectShape && {
type: 'rect', type: 'rect',
transition: ['shape'], transition: ['shape'],
shape: rectShape, shape: rectShape,
style: api.style() style: api.style(),
} }
); );
} };
/** /**
* 图表配置项生成 * 图表配置项生成
...@@ -965,13 +984,13 @@ const optionGenerator = ( ...@@ -965,13 +984,13 @@ const optionGenerator = (
restOption, restOption,
special, special,
} = handleDefault(config, cusOption); } = handleDefault(config, cusOption);
const {leftNum, rightNum, yAxis} = handleYAxis({ const { leftNum, rightNum, yAxis } = handleYAxis({
dataSource, dataSource,
needUnit, needUnit,
curveCenter, curveCenter,
showGridLine, showGridLine,
}); });
let {xAxis, series, visualMap} = returnXAxis({ let { xAxis, series, visualMap } = returnXAxis({
dataSource, dataSource,
contrast, contrast,
contrastOption, contrastOption,
...@@ -982,7 +1001,7 @@ const optionGenerator = ( ...@@ -982,7 +1001,7 @@ const optionGenerator = (
smooth, smooth,
restOption, restOption,
special, special,
yAxis yAxis,
}); });
// 3. 判断是否开启网格; // 3. 判断是否开启网格;
const grid = handleGrid(dataSource, needUnit, leftNum, rightNum, chartType); const grid = handleGrid(dataSource, needUnit, leftNum, rightNum, chartType);
...@@ -998,19 +1017,20 @@ const optionGenerator = ( ...@@ -998,19 +1017,20 @@ const optionGenerator = (
if (chartType === 'boxChart' && lineDataType === '特征曲线') { if (chartType === 'boxChart' && lineDataType === '特征曲线') {
const otherData = const otherData =
dataSource?.[0]?.dataModel.map((item) => { dataSource?.[0]?.dataModel.map((item) => {
const {firstPV, lastPV, maxPV, minPV, pt} = item; const { firstPV, lastPV, maxPV, minPV, pt } = item;
return [moment(pt).valueOf(), firstPV, lastPV, minPV, maxPV]; return [moment(pt).valueOf(), firstPV, lastPV, minPV, maxPV];
}) || []; //当存在othersData的时候,只是单曲线 }) || []; //当存在othersData的时候,只是单曲线
xAxis = {type: 'time'}; xAxis = { type: 'time' };
decorateAxisGridLine(xAxis, showGridLine); decorateAxisGridLine(xAxis, showGridLine);
let unit = []; let unit = [];
series = series.map((item) => { series = series.map((item) => {
if (item.unit) unit.push(item.unit); if (item.unit) unit.push(item.unit);
item.areaStyle = null; item.areaStyle = null;
return {...item, showSymbol: false}; return { ...item, showSymbol: false };
}); });
// 箱线图去除曲线 2023年10月17日 // 箱线图去除曲线 2023年10月17日
series=[{ series = [
{
type: 'candlestick', type: 'candlestick',
name: '箱线图', name: '箱线图',
symbol: 'none', symbol: 'none',
...@@ -1021,7 +1041,8 @@ const optionGenerator = ( ...@@ -1021,7 +1041,8 @@ const optionGenerator = (
borderColor: '#FFA200', borderColor: '#FFA200',
borderColor0: '#44CD00', borderColor0: '#44CD00',
}, },
}]; },
];
tooltip = tooltipAccessor(unit); tooltip = tooltipAccessor(unit);
} }
if (chartType === 'lineChart' || lineDataType === '原始曲线') { if (chartType === 'lineChart' || lineDataType === '原始曲线') {
...@@ -1033,13 +1054,9 @@ const optionGenerator = ( ...@@ -1033,13 +1054,9 @@ const optionGenerator = (
? `${_currentYear}-01-01 HH:mm:00` ? `${_currentYear}-01-01 HH:mm:00`
: `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间 : `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间
let _maxValues = []; let _maxValues = [];
/** /** 生成泳道图,分两种情况 1. 当最大值最小值都是正数时; 2. 当最大值小于零时(此时,最小值一定小于零); */
* 生成泳道图,分两种情况
* 1. 当最大值最小值都是正数时;
* 2. 当最大值小于零时(此时,最小值一定小于零);
*/
dataSource?.[0]?.dataModel.forEach((item) => { dataSource?.[0]?.dataModel.forEach((item) => {
const {firstPV, lastPV, maxPV, minPV, pt} = item; const { firstPV, lastPV, maxPV, minPV, pt } = item;
_maxValues.push(maxPV); _maxValues.push(maxPV);
let time = contrast ? moment(pt).format(formatStr) : pt; let time = contrast ? moment(pt).format(formatStr) : pt;
_maxData.push([ _maxData.push([
...@@ -1049,13 +1066,13 @@ const optionGenerator = ( ...@@ -1049,13 +1066,13 @@ const optionGenerator = (
_minData.push([moment(time).valueOf(), maxPV > 0 ? minPV : maxPV]); _minData.push([moment(time).valueOf(), maxPV > 0 ? minPV : maxPV]);
}); //当存在othersData的时候,只是单曲线 }); //当存在othersData的时候,只是单曲线
// xAxis = {type: 'category', data: series[0].data.map(item => moment(item[0]).format('YYYY-MM-DD HH:mm:ss'))}; // xAxis = {type: 'category', data: series[0].data.map(item => moment(item[0]).format('YYYY-MM-DD HH:mm:ss'))};
xAxis = {type: 'time'}; xAxis = { type: 'time' };
decorateAxisGridLine(xAxis, showGridLine); decorateAxisGridLine(xAxis, showGridLine);
let _unit = ''; let _unit = '';
series = series.map((item) => { series = series.map((item) => {
_unit = item.unit ?? ''; _unit = item.unit ?? '';
item.areaStyle = null; item.areaStyle = null;
return {...item, showSymbol: false}; return { ...item, showSymbol: false };
}); });
[[..._minData], [..._maxData]].forEach((item, index) => { [[..._minData], [..._maxData]].forEach((item, index) => {
series.push({ series.push({
...@@ -1084,12 +1101,14 @@ const optionGenerator = ( ...@@ -1084,12 +1101,14 @@ const optionGenerator = (
${headTemplate(e[0])} ${headTemplate(e[0])}
<div> <div>
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<span style="${isMobile() <span style="${
isMobile()
? 'width: ' + ? 'width: ' +
handlePx(90, 'px') + handlePx(90, 'px') +
';overflow:hidden;text-overflow:ellipsis;white-space:nowrap' ';overflow:hidden;text-overflow:ellipsis;white-space:nowrap'
: '' : ''
}">${e[0].seriesName }">${
e[0].seriesName
}</span><span style="display:inline-block;">:</span> }</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.NORMAL};margin: 0 ${handlePx( <span style="color: ${COLOR.NORMAL};margin: 0 ${handlePx(
5, 5,
...@@ -1097,7 +1116,8 @@ const optionGenerator = ( ...@@ -1097,7 +1116,8 @@ const optionGenerator = (
)} 0 auto;">${e[0]?.value?.[1] ?? '-'}</span> )} 0 auto;">${e[0]?.value?.[1] ?? '-'}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: ${lineDataType === '特征曲线' ? 'flex' : 'none' <div style="display: ${
lineDataType === '特征曲线' ? 'flex' : 'none'
}; align-items: center;"> }; align-items: center;">
<span>周期最小值</span><span style="display:inline-block;">:</span> <span>周期最小值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx( <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(
...@@ -1106,7 +1126,8 @@ const optionGenerator = ( ...@@ -1106,7 +1126,8 @@ const optionGenerator = (
)} 0 auto;">${e?.[1]?.value?.[1] ?? '-'}</span> )} 0 auto;">${e?.[1]?.value?.[1] ?? '-'}</span>
<span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span> <span style="font-size: ${handlePx(12, 'px')};">${_unit ?? ''}</span>
</div> </div>
<div style="display: ${lineDataType === '特征曲线' ? 'flex' : 'none' <div style="display: ${
lineDataType === '特征曲线' ? 'flex' : 'none'
}; align-items: center;"> }; align-items: center;">
<span>周期最大值</span><span style="display:inline-block;">:</span> <span>周期最大值</span><span style="display:inline-block;">:</span>
<span style="color: ${COLOR.AVG};margin: 0 ${handlePx( <span style="color: ${COLOR.AVG};margin: 0 ${handlePx(
...@@ -1128,7 +1149,7 @@ const optionGenerator = ( ...@@ -1128,7 +1149,7 @@ const optionGenerator = (
} else { } else {
tooltip = tooltipAccessor( tooltip = tooltipAccessor(
series.map((item) => item.unit), series.map((item) => item.unit),
{contrastOption, contrast}, { contrastOption, contrast },
); );
} }
tooltip.timeFormat = tooltipTimeFormat; tooltip.timeFormat = tooltipTimeFormat;
...@@ -1157,7 +1178,7 @@ const handleDataSource = (dataSource) => { ...@@ -1157,7 +1178,7 @@ const handleDataSource = (dataSource) => {
// handleSpecial2() // handleSpecial2()
dataSource[0].dataModel.forEach((item, index) => { dataSource[0].dataModel.forEach((item, index) => {
if (index === 0) { if (index === 0) {
_data.push(item) _data.push(item);
} else if (index === _dataLength - 1) { } else if (index === _dataLength - 1) {
_data.push(item); _data.push(item);
} else { } else {
...@@ -1167,7 +1188,7 @@ const handleDataSource = (dataSource) => { ...@@ -1167,7 +1188,7 @@ const handleDataSource = (dataSource) => {
} }
_temp = item; _temp = item;
}); });
return _data return _data;
}; };
const returnLegend = (sensorType) => { const returnLegend = (sensorType) => {
const _colorMap = { const _colorMap = {
...@@ -1195,7 +1216,7 @@ const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => { ...@@ -1195,7 +1216,7 @@ const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => {
let _valDescMap = special.allValDesc[sensorName]?.split(';').reduce((final, cur) => { let _valDescMap = special.allValDesc[sensorName]?.split(';').reduce((final, cur) => {
let _arr = cur.split(':'); let _arr = cur.split(':');
final[_arr[0]] = _arr[1]; final[_arr[0]] = _arr[1];
return final return final;
}, {}); }, {});
name = _valDescMap[data1.pv]; name = _valDescMap[data1.pv];
color = _colorMap[name]; color = _colorMap[name];
...@@ -1205,48 +1226,64 @@ const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => { ...@@ -1205,48 +1226,64 @@ const handleSpecial2 = (special, sensorName, sensorType, data1, data2) => {
if (sensorType === '开关值') { if (sensorType === '开关值') {
const _switchColorMap = { const _switchColorMap = {
0: '#666666', 0: '#666666',
1: '#1685ff' 1: '#1685ff',
}; };
const _switchNameMap = { const _switchNameMap = {
0: '关', 0: '关',
1: '开' 1: '开',
} };
name = _switchNameMap[data1.pv]; name = _switchNameMap[data1.pv];
color = _switchColorMap[data1.pv]; color = _switchColorMap[data1.pv];
} }
value1 = moment(data1.pt).valueOf(); value1 = moment(data1.pt).valueOf();
value2 = moment(data2.pt).valueOf(); value2 = moment(data2.pt).valueOf();
return {color, value1, value2, name} return { color, value1, value2, name };
}; };
const handleDataToSeries = (special, sensorName, sensorType, data) => { const handleDataToSeries = (special, sensorName, sensorType, data) => {
let _data = []; let _data = [];
let _legend = []; let _legend = [];
data.forEach((item, index) => { data.forEach((item, index) => {
if (index === data.length - 1) return; if (index === data.length - 1) return;
let {color, value1, value2, name} = handleSpecial2(special, sensorName, sensorType, item, data[index + 1]) let { color, value1, value2, name } = handleSpecial2(
special,
sensorName,
sensorType,
item,
data[index + 1],
);
if (!_legend.includes(name)) _legend.push(name); if (!_legend.includes(name)) _legend.push(name);
_data.push({ _data.push({
itemStyle: {normal: {color}}, itemStyle: { normal: { color } },
name: name, name: name,
value: [0, value1, value2, `${item.pt}-${data[index + 1].pt}`] value: [0, value1, value2, `${item.pt}-${data[index + 1].pt}`],
}); });
}); });
return {data: _data, legend: _legend}; return { data: _data, legend: _legend };
}; };
const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contrastOption, smooth, config}) => { const specialTypeChartOptionGenerator = ({
const {special, sensorType} = config; dataSource,
const {allSensorType, allPointAddress} = special; cusOption,
contrast,
contrastOption,
smooth,
config,
}) => {
const { special, sensorType } = config;
const { allSensorType, allPointAddress } = special;
// 处理原始数据,处理数据为后series数据 // 处理原始数据,处理数据为后series数据
const sensorName = dataSource[0].sensorName; const sensorName = dataSource[0].sensorName;
let _data = handleDataSource(dataSource); let _data = handleDataSource(dataSource);
let {data, legend} = handleDataToSeries(special, sensorName, sensorType, _data); let { data, legend } = handleDataToSeries(special, sensorName, sensorType, _data);
// 1. x/y轴 // 1. x/y轴
let xAxis = { let xAxis = {
type: 'time', type: 'time',
axisLabel: { axisLabel: {
formatter: contrast ? (contrastOption === 'month' ? '{dd}日' : '{HH}:{mm}') formatter: contrast
? contrastOption === 'month'
? '{dd}日'
: '{HH}:{mm}'
: { : {
year: '{yyyy}', year: '{yyyy}',
month: '{MMM}', month: '{MMM}',
...@@ -1259,44 +1296,44 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr ...@@ -1259,44 +1296,44 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr
}, },
minorTick: { minorTick: {
lineStyle: { lineStyle: {
color: "#e2e2e2" color: '#e2e2e2',
}, },
show: true, show: true,
splitNumber: 2 splitNumber: 2,
}, },
minorSplitLine: { minorSplitLine: {
lineStyle: { lineStyle: {
color: "#e2e2e2", color: '#e2e2e2',
type: "dashed" type: 'dashed',
}, },
show: true show: true,
}, },
splitLine: { splitLine: {
show: true show: true,
}, },
minInterval: 3600 * 1000 minInterval: 3600 * 1000,
}; };
let yAxis = { let yAxis = {
data: [dataSource[0].sensorName], data: [dataSource[0].sensorName],
axisLine: { axisLine: {
show: true show: true,
}, },
minorTick: { minorTick: {
lineStyle: { lineStyle: {
color: "#e2e2e2" color: '#e2e2e2',
}, },
show: true, show: true,
splitNumber: 2 splitNumber: 2,
}, },
minorSplitLine: { minorSplitLine: {
lineStyle: { lineStyle: {
color: "#e2e2e2", color: '#e2e2e2',
type: "dashed" type: 'dashed',
}, },
show: true show: true,
}, },
splitLine: { splitLine: {
show: true show: true,
}, },
}; };
//2. series //2. series
...@@ -1305,15 +1342,15 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr ...@@ -1305,15 +1342,15 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr
type: 'custom', type: 'custom',
renderItem: renderStatusItem, renderItem: renderStatusItem,
itemStyle: { itemStyle: {
opacity: 0.8 opacity: 0.8,
}, },
encode: { encode: {
x: [1, 2], x: [1, 2],
y: 0 y: 0,
}, },
data data,
}, },
...legend.map(item => { ...legend.map((item) => {
let _map = { let _map = {
变频: '#1685ff', 变频: '#1685ff',
工频: '#00d0c7', 工频: '#00d0c7',
...@@ -1321,23 +1358,22 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr ...@@ -1321,23 +1358,22 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr
故障: '#ff6b37', 故障: '#ff6b37',
停止: '#666666', 停止: '#666666',
: '#666666', : '#666666',
: '#1685ff' : '#1685ff',
} };
return { return {
type: 'custom', type: 'custom',
name: item, name: item,
color: _map[item], color: _map[item],
renderItem: () => { renderItem: () => {},
} };
} }),
})
]; ];
let grid = { let grid = {
top: 80, top: 80,
left: 30, left: 30,
right: 10, right: 10,
bottom: 60, bottom: 60,
containLabel: true containLabel: true,
}; };
let legendConfig = { let legendConfig = {
show: true, show: true,
...@@ -1360,23 +1396,21 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr ...@@ -1360,23 +1396,21 @@ const specialTypeChartOptionGenerator = ({dataSource, cusOption, contrast, contr
trigger: 'item', trigger: 'item',
formatter: function (params) { formatter: function (params) {
return params.marker + params.name + ': ' + params?.value?.[3]; return params.marker + params.name + ': ' + params?.value?.[3];
} },
}, },
dataZoom: [ dataZoom: [
{ {
type: 'slider', type: 'slider',
filterMode: 'weakFilter', filterMode: 'weakFilter',
showDataShadow: false, showDataShadow: false,
labelFormatter: '' labelFormatter: '',
}, },
{ {
type: 'inside', type: 'inside',
filterMode: 'weakFilter' filterMode: 'weakFilter',
} },
], ],
} };
return _option; return _option;
}; };
export { export { specialTypeChartOptionGenerator };
specialTypeChartOptionGenerator
}
\ 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