robot_bigScreen/src/components/AlarmStatistics copy.vue
2025-06-09 15:11:47 +08:00

404 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="alarm-statistics">
<div class="time-filter">
<div
v-for="period in periods"
:key="period.value"
:class="['filter-item', { active: currentPeriod === period.value }]"
@click="handleManualSelect(period.value)"
>
{{ period.label }}
</div>
</div>
<div class="chart-container" ref="chartRef"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch, computed } from "vue";
import * as echarts from "echarts";
import { homeApi } from '../api/index';
import emptyList from '../assets/img/empty_list.png';
const chartRef = ref(null);
let chart = null;
let autoSwitchTimer = null;
let checkInterval = null;
const isLoading = ref(false);
const isManualMode = ref(false); // 是否处于手动选择模式
// 告警事件类型映射
const eventTypeMap = {
'0': '读表告警',
'1': '高温感知报警',
'2': '吸烟报警',
'3': '长时间滞留报警',
'4': '空气质量报警',
'5': '急停按下',
'6': '语音未接通',
'7': '日常巡检'
};
// 存储API返回的数据
const apiData = ref({
'1': [], // 天
'7': [], // 周
'30': [], // 月
});
// 判断当前时间段是否有数据
const hasData = computed(() => {
return apiData.value[currentPeriod.value] && apiData.value[currentPeriod.value].length > 0;
});
// 转换API数据为图表格式
const transformData = (data) => {
const xAxisData = [];
const seriesData = [];
if (!data || data.length === 0) {
return { xAxis: [], series: [] };
}
// 按事件类型分组并排序
data.forEach(item => {
const eventTypeName = eventTypeMap[item.eventType] || `未知类型(${item.eventType})`;
xAxisData.push(eventTypeName);
seriesData.push(item.count);
});
return {
xAxis: xAxisData,
series: seriesData
};
};
const periods = [
{ label: "天", value: "1" },
{ label: "周", value: "7" },
{ label: "月", value: "30" },
];
const currentPeriod = ref("1");
// 获取指定时间段的告警统计数据
const fetchAlarmStatistics = async (day) => {
console.log(`获取${day}天的数据`);
isLoading.value = true;
try {
const res = await homeApi.getAlarmStatistics(day);
if (res.code === 200) {
apiData.value[day] = res.data || [];
console.log(`获取${day}天告警统计数据成功:`, res.data);
} else {
console.error(`获取${day}天告警统计数据失败:`, res);
apiData.value[day] = [];
}
} catch (err) {
console.error(`获取${day}天告警统计数据错误:`, err);
apiData.value[day] = [];
} finally {
isLoading.value = false;
// 确保当前还是这个时间段才更新图表
if (currentPeriod.value === day) {
updateChart();
}
}
};
// 更新图表数据
const updateChart = () => {
if (!chartRef.value || !chart) return;
console.log(`更新图表数据,当前时间段: ${currentPeriod.value}`);
// 获取当前时间段的数据
const chartData = transformData(apiData.value[currentPeriod.value]);
// 基础配置,无论是否有数据都会显示
const option = {
grid: {
top: "10%",
left: "5%",
right: "4%",
bottom: "15%",
containLabel: true,
},
xAxis: {
type: "category",
// 如果没有数据,使用空数组但仍显示坐标轴
data: chartData.xAxis.length > 0 ? chartData.xAxis : ['暂无数据'],
axisLine: {
show: true,
lineStyle: {
color: "rgba(185, 232, 255, 0.1)",
},
},
axisTick: {
show: false,
},
axisLabel: {
color: "#B9E8FF",
fontSize: 12,
interval: 0,
rotate: 45,
},
},
yAxis: {
type: "value",
name: "数量: 次",
nameTextStyle: {
color: "#B9E8FF",
fontSize: 12,
padding: [0, 30, 0, 0],
},
splitLine: {
show: true,
lineStyle: {
color: "rgba(185, 232, 255, 0.1)",
type: "dashed",
},
},
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
color: "#B9E8FF",
fontSize: 12,
},
},
series: [
{
// 当没有数据时,显示一个空数据点
data: chartData.series.length > 0 ? chartData.series : [0],
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 8,
itemStyle: {
color: "#FF8A00",
},
lineStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#FF8A00",
},
{
offset: 1,
color: "rgba(255, 138, 0, 0)",
},
],
},
width: 3,
},
areaStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "rgba(255, 138, 0, 0.3)",
},
{
offset: 1,
color: "rgba(255, 138, 0, 0)",
},
],
},
},
label: {
show: true,
position: 'top',
color: '#FF8A00',
fontSize: 14,
fontWeight: 'bold',
},
},
],
};
console.log('设置图表选项');
chart.setOption(option, true); // 使用true参数完全覆盖之前的配置
};
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
if (chart) {
chart.dispose();
}
chart = echarts.init(chartRef.value);
updateChart(); // 初始更新图表
};
// 开始自动轮播
const startAutoSwitch = () => {
stopAutoSwitch(); // 先停止现有的定时器
autoSwitchTimer = setInterval(async () => {
// 如果处于手动模式,不自动切换
if (isManualMode.value) return;
const currentIndex = periods.findIndex(p => p.value === currentPeriod.value);
const nextIndex = (currentIndex + 1) % periods.length;
const nextPeriod = periods[nextIndex].value;
console.log(`自动切换到: ${periods[nextIndex].label}(${nextPeriod})`);
// 先切换时间段
currentPeriod.value = nextPeriod;
// 然后获取数据
await fetchAlarmStatistics(nextPeriod);
}, 10000); // 每10秒切换一次
};
// 停止自动轮播
const stopAutoSwitch = () => {
if (autoSwitchTimer) {
clearInterval(autoSwitchTimer);
autoSwitchTimer = null;
}
};
// 处理手动选择
const handleManualSelect = async (period) => {
console.log(`手动选择时间段: ${period}`);
// 进入手动模式
isManualMode.value = true;
// 如果点击的是当前已选择的时间段,不做任何操作
if (currentPeriod.value === period) return;
// 更新当前选中时间段
currentPeriod.value = period;
// 获取该时间段的数据
await fetchAlarmStatistics(period);
// 5秒后恢复自动切换
setTimeout(() => {
console.log('恢复自动模式');
isManualMode.value = false;
}, 30000); // 30秒后恢复自动模式
};
// 监听窗口大小变化
const handleResize = () => {
chart && chart.resize();
};
// 监听当前选中的时间段变化
watch(currentPeriod, (newPeriod) => {
console.log(`当前选中时间段变为: ${newPeriod}`);
});
onMounted(async () => {
console.log('组件挂载');
// 初始化时获取默认数据1天
await fetchAlarmStatistics('1');
// 然后初始化其他时间段数据
Promise.all([
fetchAlarmStatistics('7'),
fetchAlarmStatistics('30')
]);
initChart();
window.addEventListener("resize", handleResize);
// 启动自动轮播
console.log('开始自动轮播');
startAutoSwitch();
// 定期检查轮播是否还在进行
checkInterval = setInterval(() => {
if (!autoSwitchTimer) {
console.log('检测到轮播已停止,重新启动');
startAutoSwitch();
}
}, 20000); // 每20秒检查一次
});
onUnmounted(() => {
// 清理定时器
stopAutoSwitch();
if (checkInterval) {
clearInterval(checkInterval);
checkInterval = null;
}
// 销毁图表
if (chart) {
chart.dispose();
chart = null;
}
window.removeEventListener("resize", handleResize);
console.log('组件卸载,停止自动轮播');
});
</script>
<style scoped>
.alarm-statistics {
width: 100%;
height: 100%;
position: relative;
}
.chart-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
.time-filter {
display: flex;
justify-content: flex-end;
gap: 5px;
padding: 0 10px;
position: relative;
z-index: 3;
}
.filter-item {
color: #b9e8ff;
cursor: pointer;
padding: 2px 10px;
border-radius: 2px;
transition: all 0.3s;
}
.filter-item.active {
padding: 2px 10px;
background: url("../assets/img/alarm_tri.png") no-repeat;
background-size: 100% 100%;
color: #00ffff;
}
</style>