CMVR-BID/src/views/device/register/components/DexHand/RightTopCharts.vue
zhanghao 181cff4277 feat: 更新样式并增强深色主题的图表配置
- 调整了StatCards.vue中的字母间距,以提高可读性。
- 更新了RightBottomCharts.vue和RightTopCharts.vue中的图表样式,通过新的调色板和背景设置增强了视觉吸引力。
- 修改了图表中的工具提示和轴样式,以提高对比度和可见性。
- 将流程编辑器中的背景颜色更改为使用CSS变量,以保持一致性。
- 引入了新的网络主题风格,包括渐变和阴影,以提供沉浸式的暗色模式体验。
- 为各种组件添加了深色覆盖,以确保与新主题的兼容性。
2026-08-27 11:43:58 +08:00

200 lines
5.4 KiB
Vue

<template>
<div class="right-chart-panel" ref="containerRef">
<div ref="topChart" class="chart"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';
const props = defineProps({
topSeriesData: {
type: Array,
default: () => [0, 0, 0, 0, 0, 0],
validator: (value) => value.length === 6 && value.every((v) => typeof v === 'number'),
},
maxData: {
type: Object,
required: true,
default: () => ({
thumb: { end: 0, tip: 0, middle: 0, palm: 0 },
indexFinger: { end: 0, tip: 0, middle: 0 },
middleFinger: { end: 0, tip: 0, middle: 0 },
ringFinger: { end: 0, tip: 0, middle: 0 },
littleFinger: { end: 0, tip: 0, middle: 0 },
palm: { touch: 0 }
})
},
avgData: {
type: Object,
required: true,
default: () => ({
thumb: { end: 0, tip: 0, middle: 0, palm: 0 },
indexFinger: { end: 0, tip: 0, middle: 0 },
middleFinger: { end: 0, tip: 0, middle: 0 },
ringFinger: { end: 0, tip: 0, middle: 0 },
littleFinger: { end: 0, tip: 0, middle: 0 },
palm: { touch: 0 }
})
}
});
const topChart = ref(null);
const containerRef = ref(null); // 新增:引用父容器
let chart1Instance = null;
// 防抖函数
const debounce = (func, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(null, args), delay);
};
};
const topChartData = ref({
xAxis: {
type: 'category',
data: ['小拇指', '无名指', '中指', '食指', '大拇指弯曲', '大拇指旋转'],
},
yAxis: {
name: '受力',
type: 'value',
min: 0,
max: 10000,
interval: 2500,
axisLine: { show: true, lineStyle: { color: '#1f77b4' } },
axisLabel: { formatter: '{value} g' },
axisTick: { show: true },
},
series: [{ data: props.topSeriesData, type: 'bar' }],
});
Object.assign(topChartData.value, {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow', shadowStyle: { color: 'rgba(6, 182, 212, 0.08)' } },
backgroundColor: 'rgba(10, 14, 23, 0.94)',
borderColor: 'rgba(6, 182, 212, 0.48)',
textStyle: { color: 'rgba(255, 255, 255, 0.88)' },
},
grid: { left: 54, right: 20, top: 24, bottom: 42 },
});
Object.assign(topChartData.value.xAxis, {
axisLine: { lineStyle: { color: 'rgba(6, 182, 212, 0.36)' } },
axisTick: { show: false },
axisLabel: { color: 'rgba(255, 255, 255, 0.68)', interval: 0 },
});
Object.assign(topChartData.value.yAxis, {
axisLine: { show: true, lineStyle: { color: 'rgba(6, 182, 212, 0.36)' } },
axisLabel: { formatter: '{value} g', color: 'rgba(255, 255, 255, 0.62)' },
axisTick: { show: true, lineStyle: { color: 'rgba(6, 182, 212, 0.3)' } },
splitLine: { lineStyle: { color: 'rgba(148, 163, 184, 0.12)', type: 'dashed' } },
nameTextStyle: { color: 'rgba(255, 255, 255, 0.68)' },
});
Object.assign(topChartData.value.series[0], {
barMaxWidth: 34,
itemStyle: {
borderRadius: [4, 4, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#67E8F9' },
{ offset: 0.5, color: '#06B6D4' },
{ offset: 1, color: 'rgba(168, 85, 247, 0.5)' },
]),
shadowBlur: 14,
shadowColor: 'rgba(6, 182, 212, 0.42)',
},
});
const data = ref({
resizeObserver: null,
debouncedResize: null,
});
onMounted(() => {
try {
if (!topChart.value) {
console.error('Chart element is null');
return;
}
chart1Instance = echarts.init(topChart.value);
chart1Instance.setOption(topChartData.value);
// 使用 ResizeObserver 监听父容器尺寸变化
const container = containerRef.value;
if (container) {
const resizeObserver = new ResizeObserver(debounce(() => {
if (chart1Instance) {
console.log('Container resized:', container.offsetWidth, container.offsetHeight);
chart1Instance.resize();
}
}, 10));
resizeObserver.observe(container);
data.value.resizeObserver = resizeObserver;
} else {
console.error('Failed to find container for ResizeObserver');
}
// 保留 window 的 resize 事件监听
const debouncedResize = debounce(() => {
if (chart1Instance) {
chart1Instance.resize();
}
}, 10);
window.addEventListener('resize', debouncedResize);
data.value.debouncedResize = debouncedResize;
} catch (error) {
console.error('图表初始化失败:', error);
}
});
onUnmounted(() => {
// 清理图表实例
if (chart1Instance) {
chart1Instance.dispose();
chart1Instance = null;
}
// 清理 ResizeObserver
if (data.value.resizeObserver) {
data.value.resizeObserver.disconnect();
data.value.resizeObserver = null;
}
// 清理 window 的 resize 事件
if (data.value.debouncedResize) {
window.removeEventListener('resize', data.value.debouncedResize);
data.value.debouncedResize = null;
}
});
// 监听 props.topSeriesData
watch(
() => props.topSeriesData,
(newTopData) => {
if (chart1Instance) {
chart1Instance.setOption({ series: [{ data: newTopData, type: 'bar' }] });
}
},
{ immediate: true }
);
</script>
<style scoped>
.right-chart-panel {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 50%;
padding: 10px;
}
.chart {
flex: 1;
height: 100%;
margin: 10px 0;
min-height: 200px; /* 确保图表有足够的高度 */
}
</style>