<script setup>
import {
ref, onMounted, onUnmounted, nextTick, watch, computed,
} from 'vue';
// eslint-disable-next-line import/no-extraneous-dependencies
import * as echarts from 'echarts';
import dayjs from 'dayjs';
import './flexible.js';
import enums from '@/utils/enums.js';
const props = defineProps({
x: { // 是否使用月作为X坐标系
type: Boolean,
default: false,
},
unit: {
type: String,
default: '次',
},
name: {
type: String,
default: '',
},
data: {
type: Array,
default: () => [],
},
overlayData: {
type: Array,
default: () => [],
},
average: {
type: Number,
default: 0,
},
max: {
type: Number,
default: 0,
},
isSop: {
type: Boolean,
default: false,
},
});
const chartDom = ref(null);
const chartInstance = ref(null);
function getDaysInCurrentMonth() {
const firstDayOfMonth = dayjs().startOf('month');
const daysInMonth = firstDayOfMonth.daysInMonth();
const days = [];
for (let i = 1; i <= daysInMonth; i++) {
days.push(i);
}
return days;
}
const daysInCurrentMonth = getDaysInCurrentMonth();
const yearMonth = `${dayjs().year()}/${dayjs().month() + 1}/`;
const weekList = ['一', '二', '三', '四', '五', '六', '日'];
const dataOverlayData = computed(() => props.overlayData);
async function initPage() {
await nextTick(); // 确保DOM已经渲染完成
if (chartInstance.value) {
chartInstance.value.dispose();
}
chartInstance.value = echarts.init(chartDom.value);
const tooltip = {
formatter: params => `<div style="display: flex;align-items: center;gap: 10px;">
<div>${props.x ? yearMonth : '星期'}${params.name}</div>
<div>${params.data}${props.unit}</div>
</div>`,
};
const option = {
// 这里是ECharts的配置项,可以根据需要绘制不同类型的图表
grid: {
top: '10', // 距离容器上边界的距离
right: ' 0', // 距离容器右边界的距离
bottom: '0', // 距离容器下边界的距离
left: '0', // 距离容器左边界的距离
containLabel: true, // 包含标签的绘图区域
},
tooltip: props.isSop ? tooltip : {
formatter: params => `
<div>
<div>${params.seriesName}</div>
<div style="display: flex;align-items: center;gap: 10px;">
<div style="width: 10px;height: 10px;border-radius:50%;background-color: ${params.color}"></div>
<div style="display: flex;align-items: center;gap: 10px;">
<div>${props.x ? yearMonth : '星期'}${params.name}</div>
<div>${params.data}${props.unit}</div>
</div>
</div>
</div>`,
},
xAxis: {
type: 'category',
data: props.x ? daysInCurrentMonth : weekList,
axisTick: {
alignWithLabel: true,
show: false, // 不显示刻度线
},
axisLine: {
show: false, // 不显示横坐标轴线
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#F1F1F1',
},
},
axisLabel: {
formatter(value) {
return value;
},
},
},
yAxis: {
type: 'value',
position: 'right',
boundaryGap: [0, 0.01],
axisTick: {
alignWithLabel: true,
},
axisLabel: {
// show: false,
formatter: `{value}${props.unit}`,
},
// min: 0,
// max: props.max,
},
series: [
{
name: props.name,
data: props.data,
type: 'bar',
stack: 'total', // 添加堆积效果
barWidth: '50%', // 调整柱子宽度
itemStyle: {
borderRadius: [0, 0, 0, 0], // 只有顶部圆角
color: enums.COLOR_LIST[0], // 设置柱子颜色、枚举数组
},
},
...dataOverlayData.value,
{
name: '平均线',
type: 'line',
showSymbol: false,
smooth: true,
markLine: {
silent: true,
symbol: ['none', 'none'], // 去掉箭头
data: [
{
type: 'average',
name: '平均值',
lineStyle: {
color: '#00B42A', // 线条颜色
type: 'dashed', // 线条类型,可选 'solid', 'dashed', 'dotted'
width: 2, // 线条宽度
},
label: {
show: true, // 显示标签
position: 'end', // 标签位置
formatter: '平均', // 标签格式
color: '#00B42A', // 线条颜色
},
},
],
},
yAxisIndex: 0,
xAxisIndex: 0,
data: [
props.average,
],
stack: '总量', // 注意:虽然 line 类型不支持 stack,但这里设置是为了逻辑清晰
},
],
};
chartInstance.value.setOption(option);
}
const X = computed(() => props.x);
watch(X, value => {
// initPage();
});
// 初始化ECharts实例并设置配置项(这里以折线图为例,但可灵活替换)
onMounted(async () => {
// await initPage();
});
// 销毁ECharts实例
onUnmounted(() => {
window.removeEventListener('resize', () => {
if (chartInstance.value) {
chartInstance.value.resize();
}
});
if (chartInstance.value != null && chartInstance.value.dispose) {
chartInstance.value.dispose();
}
});
window.addEventListener('resize', () => {
if (chartInstance.value) {
// chartInstance.value.resize();
initPage();
}
});
defineExpose({
initPage,
});
</script>
<template>
<div ref="chartDom" style="width: 25.1875rem; height: 17.0625rem;"></div>
</template>
<style scoped lang="less">
</style>
在父组件中使用:
<DataVisualization
ref="DataVisualizationRef"
:name="props.data.name"
:x="props.data.x"
:data="props.data.data"
:unit="props.data.unit"
:average="props.data.average"
:overlay-data="props.data.overlayData"
:max="props.data.max"
:isSop="props.isSop"
/>
效果图: