1
0
forked from dyf/dyf-vue-ui
Files
dyf-vue-ui/src/views/homeIndex/components/DeviceUsage.vue
2025-10-09 14:38:00 +08:00

292 lines
7.5 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="vchartPage">
<div class="btn_mounth_box">
<div class="btn_mounth" :class="{ cur: activeTab == 'month' }" @click="switchTab('month')">近一月</div>
<div class="btn_mounth" :class="{ cur: activeTab === 'halfYear' }" @click="switchTab('halfYear')">近半年</div>
</div>
<div ref="chartContainerRef" class="chartContainer" :class="{ 'show-scroll': showScroll }">
<div ref="chartRef" class="chartRef"></div>
</div>
</div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts';
import { getDeviceUsageFrequency } from '@/api/homeIndex/index';
const chartRef = ref<HTMLDivElement | null>(null);
const chartContainerRef = ref<HTMLDivElement | null>(null);
const activeTab = ref('month');
const showScroll = ref(false); // 控制是否显示滚动条
let myChart: echarts.ECharts | null = null;
let dataTimer: NodeJS.Timeout | null = null;
// 根据天数获取数据并更新图表
const fetchDataAndUpdate = (days: number) => {
getDeviceUsageFrequency({ days }).then((res) => {
if (res.code === 200 && res.data && myChart) {
// 模拟数据(根据需求调整数量)
const dataCount = activeTab.value === 'month' ? 8 : 25; // 一月8条半年25条
const mockData = Array.from({ length: dataCount }, (_, index) => ({
deviceName: `设备${index + 1}`,
frequency: Math.floor(Math.random() * 100)
}));
const chartData = res.data.map(item => ({
name: item.deviceName,
value: item.frequency
}));
const scrollThreshold = 20;
showScroll.value = chartData.length > scrollThreshold;
// 动态计算图表高度
const baseItemHeight = 20;
const minHeight = 200;
const maxHeight = 600;
let chartHeight;
if (showScroll.value) {
chartHeight = Math.min(chartData.length * baseItemHeight, maxHeight);
} else {
chartHeight = Math.max(chartData.length * baseItemHeight, minHeight);
}
if (chartRef.value) {
chartRef.value.style.height = `${chartHeight}px`;
}
// 更新图表
myChart.setOption({
yAxis: {
data: chartData.map(item => item.name)
},
series: [{
data: chartData.map(item => item.value)
}]
});
// 数据更新后,重新调整图表尺寸
setTimeout(() => {
if (myChart) {
myChart.resize();
}
}, 0);
}
}).catch(err => {
console.error(err);
});
};
// 切换标签逻辑
const switchTab = (tab: string) => {
activeTab.value = tab;
const days = tab === 'month' ? 30 : 180;
fetchDataAndUpdate(days);
startDataTimer();
// 重置滚动位置
if (chartContainerRef.value) {
chartContainerRef.value.scrollTop = 10;
}
};
// 开始数据定时器
const startDataTimer = () => {
if (dataTimer) {
clearInterval(dataTimer);
}
dataTimer = setInterval(() => {
const days = activeTab.value === 'month' ? 30 : 180;
fetchDataAndUpdate(days);
}, 300000);
};
// 清除数据定时器
const clearDataTimer = () => {
if (dataTimer) {
clearInterval(dataTimer);
dataTimer = null;
}
};
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
myChart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' }
},
grid: {
left: '5%',
right: '5%',
bottom: '2%',
top: '12%',
containLabel: true
},
yAxis: {
type: 'category',
inverse: true,
data: [],
axisLine: {
lineStyle: {
color: '#1e3a8a',
show: false
}
},
axisLabel: {
color: '#DEEFFF',
fontSize: 12
},
axisTick: {
alignWithLabel: true
}
},
xAxis: {
type: 'value',
axisLine: { show: false },
axisLabel: { show: false },
splitLine: {
show: true,
lineStyle: {
color: 'rgba(30, 58, 138, 0.3)',
type: 'dashed'
}
}
},
series: [{
name: '使用频次',
type: 'bar',
data: [],
barWidth: '12px',
stack: 'total',
label: {
show: true,
position: 'right',
valueAnimation: true,
color: '#DEEFFF',
fontSize: 11
},
itemStyle: {
color: new echarts.graphic.LinearGradient(
0, 0, 1, 0,
[
{ offset: 0, color: '#0768D4' },
{ offset: 1, color: '#0EC4DF' }
]
),
borderRadius: 4
},
barGap: '30%',
barCategoryGap: '40%'
}]
};
myChart.setOption(option);
fetchDataAndUpdate(30);
startDataTimer();
};
// 处理窗口大小变化
const handleResize = () => {
if (myChart) {
myChart.resize();
}
};
onMounted(() => {
initChart();
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
clearDataTimer();
window.removeEventListener('resize', handleResize);
if (myChart) {
myChart.dispose();
myChart = null;
}
});
</script>
<style scoped lang="scss">
.vchartPage {
margin-top: 4.9vh;
position: relative;
height: 100%;
}
.btn_mounth_box {
display: flex;
position: absolute;
right: 1vh;
top: 0vh;
z-index: 1;
}
.btn_mounth {
width: 4.5vw;
height: 4.5vh;
background: url(@/assets/homeIndex/btn.png) no-repeat;
background-size: 100% 100%;
text-align: center;
line-height: 4.4vh;
color: #fff;
font-size: 0.8vw;
cursor: pointer;
margin-left: 0.5vw;
}
.cur {
background: url(@/assets/homeIndex/btn_cur.png) no-repeat;
background-size: 100% 100%;
}
.chartContainer {
width: 100%;
height: auto;
overflow-y: hidden;
overflow-x: hidden;
position: relative;
// margin-top: 2vh;
transition: all 0.3s ease;
// 当需要显示滚动条时的样式
&.show-scroll {
height: 24vh;
overflow-y: auto;
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-thumb {
background-color: rgba(7, 104, 212, 0.8);
border-radius: 4px;
border: 2px solid transparent;
background-clip: content-box;
}
&::-webkit-scrollbar-thumb:hover {
background-color: rgba(7, 104, 212, 1);
}
&::-webkit-scrollbar-track {
background-color: rgba(30, 58, 138, 0.1);
border-radius: 4px;
}
&::-webkit-scrollbar-track:hover {
background-color: rgba(30, 58, 138, 0.2);
}
}
}
.chartRef {
width: 100%;
min-height: 100px;
box-sizing: border-box;
}
</style>