2025-04-16 23:06:01 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div style="height:100%;width:100%" :id="echartsId"></div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import * as echarts from "echarts";
|
2026-01-30 12:10:31 +08:00
|
|
|
|
import { onMounted, ref, defineEmits, defineProps, onUnmounted, watch, nextTick } from "vue";
|
2025-04-16 23:06:01 +08:00
|
|
|
|
const props = defineProps({
|
2026-01-16 12:40:42 +08:00
|
|
|
|
echartsId: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: '3DbarId'
|
2025-04-16 23:06:01 +08:00
|
|
|
|
},
|
2026-01-16 12:40:42 +08:00
|
|
|
|
data: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: () => { }
|
2025-04-16 23:06:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-01-30 12:10:31 +08:00
|
|
|
|
const emit = defineEmits(['click']);
|
2025-04-16 23:06:01 +08:00
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
// 保存echarts实例
|
|
|
|
|
|
const myChart = ref(null);
|
2025-04-16 23:06:01 +08:00
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
// 定义resize处理函数
|
|
|
|
|
|
const handleResize = () => {
|
|
|
|
|
|
if (myChart.value) {
|
|
|
|
|
|
myChart.value.resize();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-16 12:40:42 +08:00
|
|
|
|
// 组织数据
|
|
|
|
|
|
const setData = function (data, constData, showData) {
|
|
|
|
|
|
data.filter(function (item) {
|
|
|
|
|
|
if (item) {
|
|
|
|
|
|
constData.push(1);
|
|
|
|
|
|
showData.push(item);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
constData.push(0);
|
|
|
|
|
|
showData.push({
|
|
|
|
|
|
value: 1,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
normal: {
|
|
|
|
|
|
borderColor: "rgba(0,0,0,0)",
|
|
|
|
|
|
borderWidth: 2,
|
|
|
|
|
|
color: "rgba(0,0,0,0)",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 组织颜色
|
|
|
|
|
|
const setColor = function (colorArr) {
|
|
|
|
|
|
let color = {
|
|
|
|
|
|
type: "linear",
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
x2: 1,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
y2: 0,
|
|
|
|
|
|
colorStops: [{
|
|
|
|
|
|
offset: 0,
|
|
|
|
|
|
color: colorArr[0],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
offset: 0.5,
|
|
|
|
|
|
color: colorArr[0],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
offset: 0.5,
|
|
|
|
|
|
color: colorArr[1],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
offset: 1,
|
|
|
|
|
|
color: colorArr[1],
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
};
|
|
|
|
|
|
return color
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
function chartFn() {
|
|
|
|
|
|
// 如果已有实例,先销毁
|
|
|
|
|
|
if (myChart.value) {
|
|
|
|
|
|
myChart.value.dispose();
|
|
|
|
|
|
}
|
2026-01-16 12:40:42 +08:00
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
// 创建新实例
|
|
|
|
|
|
myChart.value = echarts.init(document.getElementById(props.echartsId));
|
2026-01-16 12:40:42 +08:00
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
// 处理数据
|
2026-01-16 12:40:42 +08:00
|
|
|
|
const barWidth = 30;
|
|
|
|
|
|
const constData = [];
|
|
|
|
|
|
const showData = [];
|
|
|
|
|
|
const values = props.data.list && Array.isArray(props.data.list) ? props.data.list.map(v => v.val || v.value) : [];
|
|
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(values)) {
|
|
|
|
|
|
setData(values, constData, showData);
|
|
|
|
|
|
}
|
2025-12-27 11:10:31 +08:00
|
|
|
|
|
2026-01-16 12:40:42 +08:00
|
|
|
|
// 处理颜色
|
|
|
|
|
|
const colorArr = props.data.colors || ["#345A8B", "#387ABD", "#51C0DB"];
|
|
|
|
|
|
const color = setColor(colorArr);
|
|
|
|
|
|
|
|
|
|
|
|
// 安全获取标签数据
|
|
|
|
|
|
const labels = props.data.list && Array.isArray(props.data.list) ? props.data.list.map(v => v.label) : [];
|
2025-12-27 11:10:31 +08:00
|
|
|
|
|
|
|
|
|
|
const option = {
|
2025-04-16 23:06:01 +08:00
|
|
|
|
grid: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
top: '15%',
|
2025-12-27 11:10:31 +08:00
|
|
|
|
left: '2%',
|
|
|
|
|
|
right: '2%',
|
2026-01-16 12:40:42 +08:00
|
|
|
|
bottom: '15%',
|
2025-04-16 23:06:01 +08:00
|
|
|
|
containLabel: true
|
|
|
|
|
|
},
|
2025-12-27 11:10:31 +08:00
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
type: 'shadow'
|
2025-12-27 11:10:31 +08:00
|
|
|
|
},
|
|
|
|
|
|
backgroundColor: 'rgba(255,255,255,1)',
|
|
|
|
|
|
padding: [5, 10],
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#7588E4'
|
|
|
|
|
|
},
|
|
|
|
|
|
extraCssText: 'box-shadow: 0 0 5px rgba(0,0,0,0.3)'
|
2025-04-16 23:06:01 +08:00
|
|
|
|
},
|
2025-12-27 11:10:31 +08:00
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
2026-01-16 12:40:42 +08:00
|
|
|
|
data: labels,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#FFFFFF'
|
2025-12-27 11:10:31 +08:00
|
|
|
|
},
|
|
|
|
|
|
axisLine: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
show: false,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#1B3F66'
|
|
|
|
|
|
}
|
2025-12-27 11:10:31 +08:00
|
|
|
|
},
|
2026-01-16 12:40:42 +08:00
|
|
|
|
axisTick: {
|
|
|
|
|
|
show: true
|
2026-01-30 12:10:31 +08:00
|
|
|
|
},
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
interval: 1, // 控制标签的显示间隔,0 表示全部显示,可以根据需要调整为其他值,例如 1 表示每隔一个显示一个标签。
|
|
|
|
|
|
color: '#666666'
|
|
|
|
|
|
}
|
2025-12-27 11:10:31 +08:00
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
type: "value",
|
2025-12-27 11:10:31 +08:00
|
|
|
|
splitLine: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
show:true ,
|
2025-12-27 11:10:31 +08:00
|
|
|
|
lineStyle: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
type:'dashed',
|
|
|
|
|
|
color: "rgba(14,95,255,0.5)"
|
2025-12-27 11:10:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-01-16 12:40:42 +08:00
|
|
|
|
axisTick: { show: false },
|
|
|
|
|
|
axisLine: { show: false },
|
|
|
|
|
|
axisLabel: { color: props.color },
|
|
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
},
|
2025-04-16 23:06:01 +08:00
|
|
|
|
series: [
|
|
|
|
|
|
{
|
2025-12-27 11:10:31 +08:00
|
|
|
|
z: 1,
|
2026-01-16 12:40:42 +08:00
|
|
|
|
type: 'bar',
|
|
|
|
|
|
name: '柱子',
|
|
|
|
|
|
barWidth: barWidth,
|
2025-04-16 23:06:01 +08:00
|
|
|
|
itemStyle: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
borderRadius: [0, 0, 0, 0],
|
|
|
|
|
|
color: color
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'top'
|
|
|
|
|
|
},
|
|
|
|
|
|
data: values
|
2025-04-16 23:06:01 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
2025-12-27 11:10:31 +08:00
|
|
|
|
z: 2,
|
2026-01-16 12:40:42 +08:00
|
|
|
|
name: '柱子底部',
|
|
|
|
|
|
type: "pictorialBar",
|
|
|
|
|
|
data: constData,
|
|
|
|
|
|
symbol: "diamond",
|
|
|
|
|
|
symbolOffset: ["0%", "50%"],
|
|
|
|
|
|
symbolSize: [barWidth - 4, 10],
|
2025-12-27 11:10:31 +08:00
|
|
|
|
itemStyle: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
normal: {
|
|
|
|
|
|
color: color
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
},
|
2025-04-16 23:06:01 +08:00
|
|
|
|
{
|
2026-01-16 12:40:42 +08:00
|
|
|
|
z: 3,
|
|
|
|
|
|
name: '柱子顶部',
|
|
|
|
|
|
type: "pictorialBar",
|
|
|
|
|
|
symbolPosition: "end",
|
|
|
|
|
|
data: showData,
|
|
|
|
|
|
|
|
|
|
|
|
symbol: "diamond",
|
|
|
|
|
|
symbolOffset: ["0%", "-50%"],
|
|
|
|
|
|
symbolSize: [barWidth - 4, 10],
|
2025-04-16 23:06:01 +08:00
|
|
|
|
itemStyle: {
|
2026-01-16 12:40:42 +08:00
|
|
|
|
normal: {
|
2026-01-29 16:47:04 +08:00
|
|
|
|
color: props.data.topColor || colorArr[2]
|
2026-01-16 12:40:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
show: false,
|
2025-04-16 23:06:01 +08:00
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
};
|
2026-01-16 12:40:42 +08:00
|
|
|
|
|
2025-12-27 11:10:31 +08:00
|
|
|
|
option && myChart.value.setOption(option);
|
2026-01-30 12:10:31 +08:00
|
|
|
|
myChart.value.on('click', function (param) {
|
|
|
|
|
|
emit('click', param.name);
|
|
|
|
|
|
});
|
2025-04-16 23:06:01 +08:00
|
|
|
|
}
|
2025-12-27 11:10:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听数据变化
|
|
|
|
|
|
watch(() => props.data, val => {
|
|
|
|
|
|
nextTick(() => { chartFn() })
|
|
|
|
|
|
}, { immediate: true, deep: true })
|
|
|
|
|
|
|
|
|
|
|
|
// 组件挂载时初始化图表并添加事件监听
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
chartFn();
|
|
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理资源
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
if (myChart.value) {
|
|
|
|
|
|
myChart.value.dispose();
|
|
|
|
|
|
myChart.value = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
window.removeEventListener('resize', handleResize);
|
|
|
|
|
|
});
|
2025-04-16 23:06:01 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
2026-01-16 12:40:42 +08:00
|
|
|
|
<style lang="scss" scoped></style>
|