Commit 2a5e388d authored by 陈龙's avatar 陈龙

feat: 历史曲线版本更新

parent c327eac2
import { request } from '@wisdom-utils/utils';
import {request} from '@wisdom-utils/utils';
const REQUEST_METHOD_GET = 'get';
const REQUEST_METHOD_POST = 'post';
......@@ -6,6 +6,7 @@ const REQUEST_METHOD_POST = 'post';
const baseUrl = typeof DUMI_TYPE !== 'undefined' && DUMI_TYPE === 'dumi' ? '/api' : '';
const monitorDeviceUrl = `${baseUrl}/PandaMonitor/Monitor/Device`;
// 获取历史数据
export function getHistoryInfo(data) {
return request({
......@@ -32,3 +33,11 @@ export function getExportDeviceHistoryUrl(data) {
data,
});
}
export function getDictionaryInfoAll(params) {
return request({
url: `${baseUrl}/PandaCore/GCK/Common/GetDictionaryInfoAll`,
method: REQUEST_METHOD_GET,
params
})
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="38.8px" height="24.8px" viewBox="0 0 38.8 24.8" enable-background="new 0 0 38.8 24.8" xml:space="preserve">
<image overflow="visible" opacity="0.55" enable-background="new " width="48" height="33" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAhCAYAAACfiCi5AAAACXBIWXMAAAsSAAALEgHS3X78AAAA
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtpJREFUeNrsWIlO20AQzTq7IakT
CjSUtur38NF8UA+pbYAmEHx2Fr1Bk8n6qLAtgrD0xGJ7N+/N4Z3Z0ejAL9PXwvbqamft7PKyPAgB
IC7hr5LRtRDTA/GIMAYiPC4IOVB0KcR0TN6TdoQJYYqxv1JCQnjA+FFIFyJMixg2LdcZg/iMsCDM
MR6B+Aa4w/8Ze6Nm3bIpf0xDKEQqlqvERIL8e8IHYIE5nvSKcA2slYg90iJvirqwMwHyHL8WIWCF
mCoj+HeOQHhJuAAWmOcF/Cb8Ala4lyCcNDEmnQFpVf5YRT4SZGJYdIp74wov8By2/jnhE/6ygC3h
jHCKd7yYv7ifKauPQDaDl+4hdgshO2FnA5acIn59CJxgfIRnJmB9KeAYHlhi7gzPE6yzwDtnCCMm
VSoRucibG4TdDcQkZOwnL9iA9d/hB74SPmMcI8ZNhYgxRM5AlBPY4XkOw8QQ8FGQzwNxn4KsJ/6T
8F3kQy69YFUoOAjwrv4CEUsQchV5IMU7EJ2I9w1+zIpEP9ZxreI/h4AV1uMvWcLz2AtWkJDJOIfl
z4G5sGZIgPxqWfUFY8s6sU9MBfFSCWBLb/GewdiLuUVYRRC5lwPsBU7iWISEa7GfmJowk5tdGUhc
/RWaYLxFPsUqFx89ayssyZZy4lNqO9z5mzZHFsV5NQuE5VPc14VDVGHRIarkqGI/MnUCXmK5bxRx
ozehg77eBLwJeOUCZEkd2vT2BOgavAhNGoh4IarSVDVAwWq0VBNTgWzgvaAQLeg9V6FN5TSTT1UL
uMZzN5AIWQtdC2xEF1fqapRvcBPhSf9BZVqioXAD5YyuRn+gpOZ+YKcNtWpiKvrXbyC/aegH+kja
UD/AbWgqTzQsd/1UX3MPegfrG3iiriPrS0SoI7vFvbwuBzLEHsfhukVP3DX5xp5YNvVdnEr0lQet
TiW6Ohfqwwv/fy70jJO5XsX0dbL9Iq5/AgwASlVPrbqGdyMAAAAASUVORK5CYII=" transform="matrix(-1 0 0 -1 43 29.5848)">
</image>
<g>
<g>
<g>
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" fill="#05C2BC" enable-background="new " d="M4.4,0.5h29
c1.7,0,3,1.3,3,3v10c0,1.7-1.3,3-3,3H22.7l-4.2,4l-4.7-4H4.3c-1.7,0-3-1.3-3-3v-10C1.4,1.8,2.7,0.5,4.4,0.5z"/>
<path fill="none" stroke="#05C2BC" stroke-width="0.5" stroke-linecap="round" d="M4.4,0.5h29c1.7,0,3,1.3,3,3v10
c0,1.7-1.3,3-3,3H22.7l-4.2,4l-4.7-4H4.3c-1.7,0-3-1.3-3-3v-10C1.4,1.8,2.7,0.5,4.4,0.5z"/>
</g>
</g>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M29.2,11.6c-0.5-1.7-1.1-3.5-1.9-5.6l1.2-0.7
c0.8,2.1,1.5,4,1.9,5.5L29.2,11.6z M24,13.6h-1.7L22,12.4c0.6,0.1,1.1,0.1,1.6,0.1s0.7-0.2,0.7-0.7V2.9h1.3v9.2
C25.6,13.1,25.1,13.6,24,13.6z M19,10.6c0.9-1.2,1.6-2.9,2-4.9l1.3,0.5c-0.5,2.4-1.3,4.2-2.1,5.4L19,10.6z M15.6,12.8
c-0.5,0.4-1.2,0.8-1.9,1.1l-0.6-1c0.7-0.3,1.2-0.6,1.7-0.9c-0.6-0.6-1-1.4-1.2-2.1h-0.4v-1h4.2v0.9c-0.2,0.8-0.5,1.6-1,2.2
c0.4,0.3,1,0.6,1.7,0.9l-0.6,1C16.8,13.5,16.1,13.1,15.6,12.8z M14.7,9.8c0.2,0.5,0.5,1,0.9,1.4c0.4-0.4,0.6-0.9,0.8-1.4H14.7z
M12.8,11.8c0.3-0.1,0.5-0.1,0.6-0.1v0.9c-0.3,0.1-0.5,0.1-0.6,0.1v1.1h-1.2v-1c-1,0.1-2.3,0.2-4,0.4L7.4,12h1V8.1h-1v-1h10.7v1
h-5.3V11.8z M11.6,8.2h-2v0.6h2V8.2z M11.6,9.8h-2v0.7h2V9.8z M11.6,11.3h-2v0.8c0.7,0,1.4-0.1,2-0.2V11.3z M8.8,3h8v3.7h-8
C8.8,6.7,8.8,3,8.8,3z M10,5.9h5.6V5.3H10V5.9z M10,4.5h5.6V3.9H10V4.5z"/>
</svg>
......@@ -42,7 +42,12 @@ const deviceParams = [
"deviceCode": "LLJ00000004",
"sensors": "瞬时流量",
"deviceType": "流量计"
} */
}*/
/* {
"deviceCode": "JFJ00000001",
"sensors": "沉淀池投矾量瞬时,是否在线",
"deviceType": "加矾间"
}*/
];
const Demo = () => {
return (
......
......@@ -24,7 +24,7 @@ import _ from 'lodash';
import TimeRangePicker from '@wisdom-components/timerangepicker';
import PandaEmpty from '@wisdom-components/empty';
import BasicTable from '@wisdom-components/basictable';
import {getHistoryInfo, getDeviceAlarmScheme, getExportDeviceHistoryUrl} from './apis';
import {getHistoryInfo, getDeviceAlarmScheme, getExportDeviceHistoryUrl, getDictionaryInfoAll} from './apis';
import SimgleChart from './SingleChart';
import GridChart from './GridChart';
import './index.less';
......@@ -81,15 +81,6 @@ const CheckboxData = [
showInTable: true,
tooltip: '本算法采用递推平均滤波法(滑动平均滤波法)对采样数据进行均值化平滑处理。',
},
// 需求变更,剔除
/* {
key: 'justLine',
label: '仅查看曲线',
type: '',
checked: false,
showInCurve: false,
showInTable: false,
},*/
{
key: 'dataThin',
label: '数据抽稀',
......@@ -777,14 +768,10 @@ const HistoryView = (props) => {
});
setLoading(false);
handleTableData(data);
/* //
let _dataModel = data[0].dataModel;
data[0].dataModel[0].pv = 0.123451
data[0].dataModel[_dataModel.length - 1].pv = 1000000*/
setChartDataSource(data);
}
}).catch(err => {
message.error('数据请求失败,请重试~')
message.info('未查询到数据,请重试~');
setLoading(false)
});
};
......@@ -887,7 +874,30 @@ const HistoryView = (props) => {
return tableMemo;
}
};
// 获取字段配置
const getDefaultOptions = () => {
getDictionaryInfoAll({
level: '组件_ec_historyview'
}).then(res => {
if (res.code === 0) {
let _opt = res.data.reduce((final, cur) => {
final[cur.fieldName] = cur.fieldValue
return final
}, {});
let _checkboxData = [...checkboxData].map(item => {
let _item = {...item};
if (_opt[item.label] !== undefined) {
_item.checked = _opt[item.label] === 'true'
}
return _item;
});
setCheckboxData(_checkboxData);
}
})
};
useEffect(() => {
getDefaultOptions();
}, [])
return (
<div className={classNames(prefixCls, 'wkt-scroll-light')}>
<Spin spinning={loading} wrapperClassName={classNames(`${prefixCls}-spin`)}>
......
......@@ -42,7 +42,7 @@ const MobileHistoryChart = (
const {getPrefixCls} = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('history-view');
const isBoxPlots =
deviceParams?.length === 1 && deviceParams[0]?.sensors?.split(',').length === 1;
deviceParams?.length === 1 && deviceParams?.[0]?.sensors?.split(',').length === 1;
const handleDataThinKey = (diffDays) => {
// 移动端缩放的抽稀一倍,需要实际调试
if (diffDays >= 7 && diffDays < 15) {
......
import moment from 'moment';
import _, { isArray } from 'lodash';
import _, {isArray} from 'lodash';
import maxIcon from './assets/最大实心.svg';
import minIcon from './assets/最小实心.svg';
import minIconDownArrow from './assets/最小实心箭头朝下.svg';
/** 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸 */
const AXIS_WIDTH = 40;
......@@ -71,7 +72,7 @@ const currentOption = isMobile() ? MOBILE_OPTION : PC_OPTION;
* @returns
*/
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;
if (contrast) {
const time = dateFrom.slice(0, contrastOption === 'day' ? 10 : 7).replace(/-/g, '');
......@@ -106,7 +107,7 @@ const dataAccessor = (data, contrast, contrastOption) => {
* @returns Null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
*/
const areaStyleFormatter = (data) => {
const { sensorName } = data;
const {sensorName} = data;
return sensorName && sensorName.indexOf('流量') > -1 ? {} : null;
};
......@@ -117,7 +118,7 @@ const areaStyleFormatter = (data) => {
* @returns
*/
const minMax = (data) => {
const { dataModel } = data;
const {dataModel} = data;
let min = Number.MAX_SAFE_INTEGER;
let max = Number.MIN_SAFE_INTEGER;
dataModel.forEach((item) => {
......@@ -148,7 +149,7 @@ const markLineItem = (name, value, color) => {
export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
// 只有一个数据曲线时显示markline
if (!dataItem || !schemes || dataSource.length !== 1) return {};
const { deviceType, stationCode, sensorName, decimalPoint } = dataItem;
const {deviceType, stationCode, sensorName, decimalPoint} = dataItem;
const curSchemes = schemes.filter(
(item) =>
item.deviceCode === stationCode &&
......@@ -157,7 +158,7 @@ export const alarmMarkLine = (dataItem, index, dataSource, schemes) => {
);
const data = [];
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'));
hLimit !== null && hLimit !== void 0 && data.push(markLineItem('高限', hLimit, '#fa8c16'));
llLimit !== null && llLimit !== void 0 && data.push(markLineItem('低低限', llLimit, '#FF0000'));
......@@ -249,7 +250,7 @@ export const decorateAxisGridLine = (axis, showGrid) => {
*/
export const offlineArea = (dataItem) => {
if (!dataItem) return {};
const { dataModel } = dataItem;
const {dataModel} = dataItem;
let datas = new Array();
let offlineData = [];
let hasOffline = false;
......@@ -280,7 +281,7 @@ export const offlineArea = (dataItem) => {
};
export const buildDefaultLegend = (option) => {
const { title } = option;
const {title} = option;
let paddingRight = 0;
if (title && title.show) paddingRight = 80; // 给标题留够空间
......@@ -303,7 +304,7 @@ export const buildDefaultLegend = (option) => {
const headTemplate = (param, opt) => {
if (!param) return '';
const { name, axisValueLabel, axisType, axisValue } = param;
const {name, axisValueLabel, axisType, axisValue} = param;
const timeFormat = opt && opt.contrast ? (opt.contrastOption === 'day' ? 'HH:mm:ss' : 'DD日') : 'YYYY-MM-DD HH:mm:ss';
const text =
axisType === 'xAxis.time' ? moment(axisValue).format(timeFormat) : name || axisValueLabel;
......@@ -311,7 +312,7 @@ const headTemplate = (param, opt) => {
};
const seriesTemplate = (param, unit) => {
if (!param) return '';
const { value, encode } = param;
const {value, encode} = param;
// const val = value[encode.y[0]];
const _unit = unit || '';
const color = '#008CFF';
......@@ -384,13 +385,13 @@ const returnXAxis = ({
showPoint,
restOption,
smooth
}) => {
}) => {
// 根据"指标名称"分类yAxis
const yAxisInterator = (() => {
const map = new Map();
let current = -1;
const get = (name) => (map.has(name) ? map.get(name) : map.set(name, ++current).get(name));
return { get };
return {get};
})();
let _offlineData = [];
let series = dataSource
......@@ -401,7 +402,7 @@ const returnXAxis = ({
return item.sensorName !== '是否在线';
})
.map((item, index) => {
const { sensorName, unit } = item;
const {sensorName, unit} = item;
const name = nameFormatter(item, contrast, contrastOption, nameWithSensor);
const data = dataAccessor(item, contrast, contrastOption);
const type = 'line';
......@@ -415,9 +416,9 @@ const returnXAxis = ({
// 需求变更:设备离线改用“是否在线”的数据,离线的状态标记的数据用该部分的数据。 2023年4月25日09:36:55
let _offlineAreasData = _offlineData
.map((item) => {
let _item = { ...item };
let _item = {...item};
_item.dataModel = item.dataModel.map((d) => {
let _d = { ...d };
let _d = {...d};
_d.pv = 0;
return _d;
});
......@@ -452,7 +453,7 @@ const returnXAxis = ({
.map((item) => item.data?.[item.data.length - 1]?.[0])
.filter((item) => item !== undefined),
);
return { xAxis: { type: 'time', min, max }, series };
return {xAxis: {type: 'time', min, max}, series};
}
const handleDefault = (config, cusOption) => {
const needUnit = _.get(config, 'needUnit', false);
......@@ -480,11 +481,11 @@ const handleDefault = (config, cusOption) => {
restOption
}
}
const handleYAxis = ({ dataSource, needUnit, curveCenter, showGridLine }) => {
const handleYAxis = ({dataSource, needUnit, curveCenter, showGridLine}) => {
// 一种指标一个y轴
const yAxisMap = new Map();
dataSource.forEach((item, index) => {
const { sensorName, unit } = item;
const {sensorName, unit} = item;
const key = sensorName;
if (!yAxisMap.has(key)) {
......@@ -530,12 +531,12 @@ const handleYAxis = ({ dataSource, needUnit, curveCenter, showGridLine }) => {
const axis = yAxisMap.get(key);
decorateAxisGridLine(axis, showGridLine);
});
const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : { type: 'value' };
const yAxis = yAxisMap.size > 0 ? [...yAxisMap.values()] : {type: 'value'};
// 根据y轴个数调整边距
const leftNum = Math.ceil(yAxisMap.size / 2);
const rightNum = Math.floor(yAxisMap.size / 2);
return { leftNum, rightNum, yAxis };
return {leftNum, rightNum, yAxis};
}
const assignOptions = (restOption, xAxis, legendData) => {
restOption.dataZoom = [
......@@ -561,7 +562,7 @@ const assignOptions = (restOption, xAxis, legendData) => {
];
xAxis.minInterval = 3600 * (1 * 1000);
if (legendData) {
restOption.legend = { ...buildDefaultLegend({}), ...{ data: legendData } };
restOption.legend = {...buildDefaultLegend({}), ...{data: legendData}};
}
};
......@@ -586,7 +587,7 @@ const returnMaxOrMinNumber = (dataSource, type) => {
let _value = [];
if (_obj?.pt) {
_value = [moment(_obj.pt).valueOf(), _obj.pv];
let _img = type === 'max' ? maxIcon : minIcon;
let _img = type === 'max' ? maxIcon : minIconDownArrow;
_value.push(_img);
_value.push(type);
}
......@@ -595,28 +596,29 @@ const returnMaxOrMinNumber = (dataSource, type) => {
const handleGrid = (dataSource, needUnit, leftNum, rightNum, chartType) => {
// 如果是单曲线,_grid的top需要一行的高度,用来放置最值最小值
let _base = 60;
let _base = 70;
let _topForUnit = needUnit ? 20 : 0;
let _topForValue = chartType && dataSource.length === 1 ? 50 : 0;
return {
top: _base + _topForUnit + _topForValue,
left: 30 + leftNum * AXIS_WIDTH,
top: _base + _topForUnit,
left: leftNum * AXIS_WIDTH,
right: rightNum === 0 ? 40 : rightNum * AXIS_WIDTH,
bottom: 60,
containLabel: true
};
};
const renderItem = (params, api) => {
let _numberStringWidth = String(api.value(1)).length * 15;
let _base = params.dataIndex + 1;
let _numberStringWidth = String(api.value(1)).length * 12;
let _base = params.dataIndex;
let _left = 40;
let _baseWidth = 190 + _numberStringWidth;
let _imgWidth = 50;
let _dateWidth = 140;
let _imageX = api.getWidth() - _base * _baseWidth;
let _timeX = api.getWidth() - (_base * _baseWidth - _imgWidth);
let _valueX = api.getWidth() - (_base * _baseWidth - _imgWidth - _dateWidth);
let _imgWidth = 45;
let _dateWidth = 128;
let _imageX = _left + _base * _baseWidth;
let _timeX = _left + _base * _baseWidth + _imgWidth;
let _valueX = _left + _base * _baseWidth + _imgWidth + _dateWidth;
let _color = api.value(3) === 'min' ? '#05C2BC' : '#1685FF';
let topValue = 60
let topValue = 25;
let _trimmer = -2;
return {
type: 'group',
children: [
......@@ -635,7 +637,7 @@ const renderItem = (params, api) => {
text: moment(api.value(0)).format('YYYY-MM-DD HH:mm:ss') + ': ',
textVerticalAlign: 'top'
},
position: [_timeX, topValue]
position: [_timeX, topValue + _trimmer],
},
{
type: 'text',
......@@ -645,9 +647,9 @@ const renderItem = (params, api) => {
fill: _color,
font: 'bolder 16px cursive',
lineWidth: 10,
y: 2
y: 3
},
position: [_valueX, topValue]
position: [_valueX, topValue + _trimmer]
}
]
}
......@@ -686,9 +688,9 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
showBoxOption,
restOption
} = handleDefault(config, cusOption);
const { leftNum, rightNum, yAxis } = handleYAxis({ dataSource, needUnit, curveCenter, showGridLine });
const {leftNum, rightNum, yAxis} = handleYAxis({dataSource, needUnit, curveCenter, showGridLine});
const grid = handleGrid(dataSource, needUnit, leftNum, rightNum, chartType);
let { xAxis, series } = returnXAxis({
let {xAxis, series} = returnXAxis({
dataSource,
contrast,
contrastOption,
......@@ -711,16 +713,16 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
if (chartType === 'boxChart') {
const otherData =
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];
}) || []; //当存在othersData的时候,只是单曲线
xAxis = { type: 'time' };
xAxis = {type: 'time'};
decorateAxisGridLine(xAxis, showGridLine);
let unit = [];
series = series.map((item) => {
if (item.unit) unit.push(item.unit);
item.areaStyle = null;
return { ...item, showSymbol: false };
return {...item, showSymbol: false};
});
series.push({
type: 'candlestick',
......@@ -746,20 +748,20 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
: `${_currentYear}-01-DD HH:mm:00`; // 用来做同期对比,把日期拉到同一区间
let _maxValues = [];
dataSource?.[0]?.dataModel.forEach((item) => {
const { firstPV, lastPV, maxPV, minPV, pt } = item;
const {firstPV, lastPV, maxPV, minPV, pt} = item;
_maxValues.push(maxPV);
let time = contrast ? moment(pt).format(formatStr) : pt;
_maxData.push([moment(time).valueOf(), (maxPV - minPV).toFixed(2)]);
_minData.push([moment(time).valueOf(), minPV]);
}); //当存在othersData的时候,只是单曲线
// 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);
let _unit = '';
series = series.map((item) => {
_unit = item.unit;
item.areaStyle = null;
return { ...item, showSymbol: false };
return {...item, showSymbol: false};
});
[[..._minData], [..._maxData]].forEach((item, index) => {
series.push({
......@@ -817,7 +819,7 @@ const optionGenerator = (dataSource, cusOption, contrast, contrastOption, smooth
series.push(_customSeries)
}
} else {
tooltip = tooltipAccessor(series.map(item => item.unit), { contrastOption, contrast });
tooltip = tooltipAccessor(series.map(item => item.unit), {contrastOption, contrast});
}
tooltip.timeFormat = tooltipTimeFormat;
let _legendData = series.filter(item => !['周期最大值', '周期最小值', '自定义'].includes(item.name)).map(item => item.name);
......
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