fix(振动看板): 修复指标切换时阈值未重置和图表残留问题

- 修复质量页继承隐藏指标过滤条件的问题
- 优化散点图符号大小计算逻辑
- 切换指标时自动重置异常检测阈值
- 查询结果为空时主动清空图表实例
- 重构查询状态管理为模块级共享
main
zch 3 months ago
parent 8fbc702e86
commit 498dad2b15

@ -8,7 +8,7 @@
show-metric
@update:time-range="setTimeRange"
@update:sampling-interval="setSamplingInterval"
@update:vibration-param="setVibrationParam"
@update:vibration-param="handleMetricChange"
@query="handleQuery"
/>
@ -132,6 +132,7 @@ const {
setTimeRange,
setSamplingInterval,
setVibrationParam,
resetAnomalyThresholds,
buildQuery
} = useVibrationBoardQueryState();
@ -151,6 +152,12 @@ const applyThresholdDefaults = (data?: VibrationAnomalyPageVO) => {
queryForm.value.stddevThreshold = Number(data.stddevThreshold ?? queryForm.value.stddevThreshold ?? 0);
};
const handleMetricChange = (value: string) => {
//
resetAnomalyThresholds();
setVibrationParam(value);
};
const handleQuery = async () => {
loading.value = true;
try {

@ -98,7 +98,7 @@ const renderCharts = () => {
series: [
{
type: 'scatter',
symbolSize: (value: any[]) => Math.max(12, Math.min(30, value[2] * 2)),
symbolSize: (value: any[]) => Math.max(12, Math.min(40, 8 + Math.log(toNumber(value[2]) + 1) * 3)),
itemStyle: { color: metricColorMap[comparisonData.value.metricField || queryForm.value.vibrationParam] || '#5b8ff9', opacity: 0.8 },
label: { show: true, formatter: (params: any) => params.value[3], position: 'top', fontSize: 11 },
data: (comparisonData.value.scatterItems || []).map((item) => [

@ -2,30 +2,61 @@ import { getMonitorInfoTree } from '@/api/ems/base/baseMonitorInfo';
import type { VibrationBoardQuery } from '@/api/ems/types';
import { createDefaultTimeRange } from './vibrationBoardShared';
type VibrationBoardQueryForm = {
compareScope: string;
monitorId: string;
monitorIds: string[];
selectionLabel: string;
samplingInterval: number;
vibrationParam: string;
highThreshold: number | undefined;
warningThreshold: number | undefined;
minContinuousSamples: number | undefined;
rapidRiseThreshold: number | undefined;
stddevThreshold: number | undefined;
};
type BuildQueryOptions = {
includeVibrationParam?: boolean;
};
const createDefaultQueryForm = (defaultMetric = 'vibrationSpeed'): VibrationBoardQueryForm => ({
compareScope: 'all',
monitorId: '',
monitorIds: [],
selectionLabel: '全部振动设备',
samplingInterval: 5,
vibrationParam: defaultMetric,
highThreshold: undefined,
warningThreshold: undefined,
minContinuousSamples: undefined,
rapidRiseThreshold: undefined,
stddevThreshold: undefined
});
// 模块级缓存:同一浏览器会话内 7 个页面共享设备树与查询状态,避免重复请求和切页丢筛选。
const sharedState = reactive({
treeLoaded: false,
monitorTreeOptions: [] as any[],
deviceDisplayMap: {} as Record<string, string>,
daterangeRecordTime: createDefaultTimeRange() as string[],
queryForm: createDefaultQueryForm()
});
export function useVibrationBoardQueryState(defaultMetric = 'vibrationSpeed') {
const state = reactive({
const localState = reactive({
loading: false,
treeLoading: false,
monitorTreeOptions: [] as any[],
treeProps: { label: 'label', children: 'children' },
deviceDisplayMap: {} as Record<string, string>,
daterangeRecordTime: createDefaultTimeRange() as string[],
queryForm: {
compareScope: 'all',
monitorId: '',
monitorIds: [] as string[],
selectionLabel: '全部振动设备',
samplingInterval: 5,
vibrationParam: defaultMetric,
highThreshold: undefined as number | undefined,
warningThreshold: undefined as number | undefined,
minContinuousSamples: undefined as number | undefined,
rapidRiseThreshold: undefined as number | undefined,
stddevThreshold: undefined as number | undefined
}
treeProps: { label: 'label', children: 'children' }
});
const { loading, treeLoading, monitorTreeOptions, treeProps, deviceDisplayMap, daterangeRecordTime, queryForm } = toRefs(state);
// 仅在首次进入页面时应用默认主看指标,后续页面切换沿用用户最新选择。
if (!sharedState.queryForm.vibrationParam) {
sharedState.queryForm.vibrationParam = defaultMetric;
}
const { loading, treeLoading, treeProps } = toRefs(localState);
const { monitorTreeOptions, deviceDisplayMap, daterangeRecordTime, queryForm } = toRefs(sharedState);
const deviceCount = computed(() => queryForm.value.monitorIds?.length || (queryForm.value.monitorId ? 1 : 0));
const hasMultiDevice = computed(() => deviceCount.value > 1 || ['group', 'all'].includes(queryForm.value.compareScope));
@ -68,12 +99,27 @@ export function useVibrationBoardQueryState(defaultMetric = 'vibrationSpeed') {
queryForm.value.vibrationParam = value;
};
const resetAnomalyThresholds = () => {
// 主看指标切换后必须回到“未覆盖”状态,让后端按新指标重新下发默认阈值,
// 否则会把上一指标的阈值误当成当前指标的用户自定义值。
queryForm.value.highThreshold = undefined;
queryForm.value.warningThreshold = undefined;
queryForm.value.minContinuousSamples = undefined;
queryForm.value.rapidRiseThreshold = undefined;
queryForm.value.stddevThreshold = undefined;
};
const loadTree = async () => {
// 已加载且有缓存时直接复用,避免 7 个页面重复打同一个树接口。
if (sharedState.treeLoaded) {
return;
}
treeLoading.value = true;
try {
const response = await getMonitorInfoTree({ monitorType: 10 });
monitorTreeOptions.value = response.data || [];
deviceDisplayMap.value = buildDeviceDisplayMap(monitorTreeOptions.value);
sharedState.treeLoaded = true;
if (!queryForm.value.monitorIds.length && !queryForm.value.monitorId) {
applySelection(buildSelection(getLeafNodes(monitorTreeOptions.value), '全部振动设备', 'all'));
}
@ -91,9 +137,11 @@ export function useVibrationBoardQueryState(defaultMetric = 'vibrationSpeed') {
applySelection(buildSelection([data], data.label, 'single'));
};
const buildQuery = (): VibrationBoardQuery => ({
const buildQuery = (options?: BuildQueryOptions): VibrationBoardQuery => ({
samplingInterval: queryForm.value.samplingInterval,
vibrationParam: queryForm.value.vibrationParam,
// 质量页不展示主看指标时,必须禁掉这个隐藏筛选条件,
// 否则会继承其它页面的指标选择,悄悄改变质量统计口径。
vibrationParam: options?.includeVibrationParam === false ? undefined : queryForm.value.vibrationParam,
beginRecordTime: daterangeRecordTime.value[0],
endRecordTime: daterangeRecordTime.value[1],
highThreshold: queryForm.value.highThreshold,
@ -125,6 +173,7 @@ export function useVibrationBoardQueryState(defaultMetric = 'vibrationSpeed') {
setTimeRange,
setSamplingInterval,
setVibrationParam,
resetAnomalyThresholds,
buildQuery,
getMonitorDisplayName
};

@ -82,6 +82,13 @@ const distributionData = ref<VibrationDistributionPageVO>({
const toNumber = (value: number | string | undefined) => Number(value ?? 0);
const clearCharts = () => {
intervalChart.value?.setData(null);
histogramChart.value?.setData(null);
calendarChart.value?.setData(null);
hourlyChart.value?.setData(null);
};
const renderCharts = () => {
const intervalData = distributionData.value.intervalBuckets || [];
const histogramData = distributionData.value.histogramBuckets || [];
@ -89,6 +96,8 @@ const renderCharts = () => {
const hourlyData = (distributionData.value.hourlyHeatmap || []).map((item) => [toNumber(item.statHour), item.statDate, toNumber(item.avgValue)]);
const days = [...new Set(hourlyData.map((item) => item[1] as string))].sort();
if (!intervalData.length && !histogramData.length && !calendarData.length && !hourlyData.length) {
//
clearCharts();
return;
}

@ -87,7 +87,8 @@ const renderChart = () => {
const handleQuery = async () => {
loading.value = true;
try {
const { data } = await getVibrationQualityData(buildQuery());
//
const { data } = await getVibrationQualityData(buildQuery({ includeVibrationParam: false }));
qualityData.value = data || { metricQualityItems: [] };
await nextTick();
renderChart();

Loading…
Cancel
Save