import moment from 'moment'; const CHART_FORMAT = 'yyyy-MM-DD HH'; const COLOR = { NORMAL: '#1685FF', UPER: '#fa8c16', UPUPER: '#FF0000', LOWER: '#fa8c16', LOWLOWER: '#FF0000', AVG: '#00B8B1', COMPARE: '#00b809', }; const dealCompareData = (compareData, experiVal, compareVal) => { let newData = [...compareData]; // 根据经验值类型和对比目标处理compareData if (experiVal === 'h' && compareVal === '同比') { newData = newData.map((item) => [ moment(item.occurrenceTime).add(1, 'days').format(CHART_FORMAT), item.value, ]); } if (experiVal === 'h' && compareVal === '环比') { newData = newData.map((item) => [ moment(item.occurrenceTime).add(1, 'hours').format(CHART_FORMAT), item.value, ]); } if (experiVal === 'day' && compareVal === '同比') { newData = newData.map((item) => [ moment(item.occurrenceTime).add(1, 'months').format(CHART_FORMAT), item.value, ]); } if (experiVal === 'day' && compareVal === '环比') { newData = newData.map((item) => [ moment(item.occurrenceTime).add(1, 'days').format(CHART_FORMAT), item.value, ]); } return newData; }; const getLabelTime = (time, experiVal, compareVal) => { let newTime = time; if (experiVal === 'h' && compareVal === '同比') { newTime = moment(time).subtract(1, 'days').format(CHART_FORMAT); } if (experiVal === 'h' && compareVal === '环比') { newTime = moment(time).subtract(1, 'hours').format(CHART_FORMAT); } if (experiVal === 'day' && compareVal === '同比') { newTime = moment(time).subtract(1, 'months').format(CHART_FORMAT); } if (experiVal === 'day' && compareVal === '环比') { newTime = moment(time).subtract(1, 'days').format(CHART_FORMAT); } return newTime; }; const grid = { top: 80, left: 30, right: 10, bottom: 60, containLabel: true, }; const yAxis = { type: 'value', axisLine: { show: true, }, minorTick: { lineStyle: { color: '#e2e2e2', }, show: true, splitNumber: 2, }, minorSplitLine: { lineStyle: { color: '#e2e2e2', type: 'dashed', }, show: true, }, splitLine: { show: true, }, // min: 'dataMin', // max: 'dataMax', }; const dataZoom = [ { type: 'slider', filterMode: 'weakFilter', showDataShadow: false, labelFormatter: '', }, { type: 'inside', filterMode: 'weakFilter', }, ]; const toFixedVal = (val, decimal = 2) => { if (val === null || val === undefined) return 0; return val.toFixed(decimal) * 1; }; // 将原始值处理成包含高限、高高限 const dealCompeletedData = (realData, highLimit, higherLimit, valTake) => { const dataSource = [...realData]; if (dataSource.length === 0) return []; if (valTake === '按偏移量') { // 存在高低限 if (highLimit && higherLimit) { dataSource.forEach((item) => { item.real_lower = toFixedVal(item.value - higherLimit); item.real_low = toFixedVal(item.value - highLimit); item.real_uper = toFixedVal(item.value + highLimit); item.real_upuper = toFixedVal(item.value + higherLimit); item.lower = item.real_lower; item.low = toFixedVal(item.real_low - item.real_lower); item.uper = toFixedVal(item.real_uper - item.real_low); item.upuper = toFixedVal(item.real_upuper - item.real_uper); }); } //只存在高限 if (highLimit && !higherLimit) { dataSource.forEach((item) => { item.real_low = toFixedVal(item.value - highLimit); item.real_uper = toFixedVal(item.value + highLimit); item.low = item.real_low; item.uper = toFixedVal(item.real_uper - item.real_low); }); } // 只存在高高限 if (!highLimit && higherLimit) { dataSource.forEach((item) => { item.real_lower = toFixedVal(item.value - higherLimit); item.real_upuper = toFixedVal(item.value + higherLimit); item.lower = item.real_lower; item.upuper = toFixedVal(item.real_upuper - item.real_uper); }); } } else { if (highLimit && higherLimit) { dataSource.forEach((item) => { item.real_lower = toFixedVal(item.value - higherLimit * 0.01 * item.value); item.real_low = toFixedVal(item.value - highLimit * 0.01 * item.value); item.real_uper = toFixedVal(item.value + highLimit * 0.01 * item.value); item.real_upuper = toFixedVal(item.value + higherLimit * 0.01 * item.value); item.lower = item.real_lower; item.low = toFixedVal(item.real_low - item.real_lower); item.uper = toFixedVal(item.real_uper - item.real_low); item.upuper = toFixedVal(item.real_upuper - item.real_uper); }); } if (highLimit && !higherLimit) { dataSource.forEach((item) => { item.real_low = toFixedVal(item.value - highLimit * 0.01 * item.value); item.real_uper = toFixedVal(item.value + highLimit * 0.01 * item.value); item.low = item.real_low; item.uper = toFixedVal(item.real_uper - item.real_low); }); } if (!highLimit && higherLimit) { dataSource.forEach((item) => { item.real_lower = toFixedVal(item.value - higherLimit * 0.01 * item.value); item.real_upuper = toFixedVal(item.value + higherLimit * 0.01 * item.value); item.lower = item.real_lower; item.upuper = toFixedVal(item.real_upuper - item.real_uper); }); } } return dataSource; }; // 获取低限、高限、低低限、高高限数据 const getLimitData = (limitType, item) => { const occurrenceTime = moment(item.occurrenceTime).format(CHART_FORMAT); return limitType ? [occurrenceTime, item[limitType]] : []; }; const getRealLimitVal = (item, data) => { const { seriesName, dataIndex } = item; let value = item.value; if (seriesName === '低限') { value = data[dataIndex].real_low; } else if (seriesName === '高限') { value = data[dataIndex].real_uper; } else if (seriesName === '低低限') { value = data[dataIndex].real_lower; } else if (seriesName === '高高限') { value = data[dataIndex].real_upuper; } return value; }; const getMinMaxValue = (data, highLimit, higherLimit) => { let minValue = 0, maxValue = 0; if (higherLimit) { minValue = Math.min(...data.map((item) => item.real_lower)); maxValue = Math.max(...data.map((item) => item.real_upuper)); } else if (highLimit) { minValue = Math.min(...data.map((item) => item.real_low)); maxValue = Math.max(...data.map((item) => item.real_uper)); } else { minValue = Math.min(...data.map((item) => item.value)); maxValue = Math.max(...data.map((item) => item.value)); } return [minValue, maxValue]; }; const getOptions = ( realData = [], compareData = [], experiVal, compareVal, // 对比值 highLimit, // 高限 higherLimit, // 高高限 valTake, // 取值方式 sensorData, // 指标配置数据 ) => { const { sensorName, unit = '' } = sensorData; // 根据偏差值算出低限、高限、低低限、高高限 const compeletedData = dealCompeletedData(realData, highLimit, higherLimit, valTake); // const [min, max] = getMinMaxValue(compeletedData, highLimit, higherLimit); // 原始数据 const realDataArr = realData.map((item) => [ moment(item.occurrenceTime).format(CHART_FORMAT), item.value, ]); // 对比数据 const compareDataArr = dealCompareData(compareData, experiVal, compareVal); //高限、高高限数据 const lowLimitArr = highLimit ? compeletedData.map((item) => getLimitData('low', item)) : []; const highLimitArr = highLimit ? compeletedData.map((item) => getLimitData('uper', item)) : []; const lowerLimitArr = higherLimit ? compeletedData.map((item) => getLimitData('upuper', item)) : []; const higherLimitArr = higherLimit ? compeletedData.map((item) => getLimitData('lower', item)) : []; let options = { grid, tooltip: { trigger: 'axis', show: true, formatter: (params) => { let result = ''; params.forEach((item) => { const labelTime = `${ item.seriesName === '对比值' ? getLabelTime(item.value[0], experiVal, compareVal) : item.value[0] }点`; const seriesName = item.seriesName; const value = item.seriesIndex > 1 ? getRealLimitVal(item, compeletedData) : item.value[1]; result += `<span>${item.seriesIndex > 1 ? seriesName : labelTime} : <b style="color: ${ item.color }">${value}</b> <span style="font-size: 12px">${unit}</span> </span><br />`; }); return result; }, }, legend: { show: true, selectedMode: 'multiple', data: ['原始值', '对比值'], }, xAxis: { type: 'time', // axisLabel: { // formatter: experiVal // ? experiVal === 'day' // ? '{dd}日' // : '{HH}:{mm}' // : { // year: '{yyyy}', // month: '{MMM}', // day: '{MMM}{d}日', // hour: '{HH}:{mm}', // minute: '{HH}:{mm}', // second: '{HH}:{mm}:{ss}', // none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}', // }, // }, minorTick: { lineStyle: { color: '#e2e2e2', }, show: true, splitNumber: 2, }, minorSplitLine: { lineStyle: { color: '#e2e2e2', type: 'dashed', }, show: true, }, splitLine: { show: true, }, minInterval: 3600 * 1000, }, yAxis, dataZoom, series: [ { name: '原始值', type: 'line', smooth: true, symbol: 'none', itemStyle: { color: COLOR.NORMAL, }, data: realDataArr, }, { name: '对比值', type: 'line', smooth: true, symbol: 'none', itemStyle: { color: COLOR.COMPARE, }, data: compareDataArr, }, ], }; /*生成泳道图 高限*/ [[...lowLimitArr], [...highLimitArr]].forEach((item, index) => { options.series.push({ name: index === 0 ? '低限' : '高限', type: 'line', itemStyle: { color: index === 0 ? COLOR.LOWER : COLOR.UPER, }, data: item, lineStyle: { opacity: 0, }, ...(index !== 0 ? { areaStyle: { color: options.series?.[0]?.itemStyle?.color ?? '#65a0d1', opacity: 0.2, }, } : {}), stack: 'confidence-band', symbol: 'none', }); }); /*生成泳道图 高高限*/ [[...lowerLimitArr], [...higherLimitArr]].forEach((item, index) => { options.series.push({ name: index === 0 ? '低低限' : '高高限', type: 'line', itemStyle: { color: index === 0 ? COLOR.LOWLOWER : COLOR.UPUPER, }, data: item, lineStyle: { opacity: 0, }, ...(index !== 0 ? { areaStyle: { color: 'red', opacity: 0.2, }, } : {}), stack: 'confidence-band', symbol: 'none', }); }); return options; }; const experiTypeOptions = [ { label: '小时', value: 'h', }, { label: '日', value: 'day', }, ]; const compareOptions = [ { label: '同比', value: '同比', }, { label: '环比', value: '环比', }, ]; const valTakeOptions = [ { label: '按偏移率', value: '按偏移率', }, { label: '按偏移量', value: '按偏移量', }, ]; export { dealCompareData, getLabelTime, getOptions, experiTypeOptions, compareOptions, valTakeOptions, };