This commit is contained in:
lcw
2025-08-27 17:26:29 +08:00
parent 42f5e37f65
commit f4c108b4b4
47 changed files with 4087 additions and 300 deletions

View File

@ -0,0 +1,78 @@
// import jsPDF from 'jspdf';
// import html2canvas from 'html2canvas';
// export function useExportToPDF() {
// const exportToImage = async (element, filename = 'screenshot.png') => {
// const canvas = await html2canvas(element, {
// scale: 2,
// useCORS: true,
// });
// // 转换为图片并下载
// const link = document.createElement('a');
// link.download = filename;
// link.href = canvas.toDataURL('image/png');
// link.click();
// };
// // 将div导出为PDF的方法
// const exportDivToPDF = async (element, filename = 'document.pdf') => {
// try {
// // 使用html2canvas将div转换为canvas
// const canvas = await html2canvas(element, {
// scale: 2, // 提高清晰度
// useCORS: true, // 允许跨域图片
// logging: false, // 关闭日志
// width: element.offsetWidth,
// height: element.offsetHeight,
// windowWidth: element.scrollWidth,
// windowHeight: element.scrollHeight,
// backgroundColor: '#ffffff' // 设置背景色为白色
// });
// // 获取canvas的宽高
// const imgWidth = 210; // A4纸宽度(mm)
// const pageHeight = 297; // A4纸高度(mm)
// const imgHeight = canvas.height * imgWidth / canvas.width;
// let heightLeft = imgHeight;
// let position = 0;
// // 创建PDF文档
// const pdf = new jsPDF({
// orientation: 'portrait',
// unit: 'mm',
// format: 'a4'
// });
// // 将canvas转换为图片并添加到PDF
// const imgData = canvas.toDataURL('image/png');
// pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
// heightLeft -= pageHeight;
// // 如果内容超出一页,添加新页面
// while (heightLeft > 0) {
// position = heightLeft - imgHeight;
// pdf.addPage();
// pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
// heightLeft -= pageHeight;
// }
// // 下载PDF
// pdf.save(filename);
// } catch (error) {
// console.error('导出PDF失败:', error);
// alert('导出PDF失败请稍后重试');
// }
// };
// return {
// exportToImage,
// exportDivToPDF
// };
// }
// exportToImage
// };
// }
export function exportDivToPDF(divId, filename) {
}

View File

@ -0,0 +1,129 @@
<template>
<div class="box" ref="chartDom"></div>
</template>
<script setup>
import { ref, onMounted,watch } from "vue";
import * as echarts from "echarts";
let chartDom = ref(null); //注意变量名 和 ref名字要对应
const props = defineProps({
title: {
type: String,
default: '2023年1月1日至2023年12月31日'
},
xAxisData: {
type: Array,
default: () => ['A', 'B', 'C', 'D', 'E', 'F']
},
seriesData: {
type: Array,
default: () => [[2549], [12421], [2637],[ 3146],[ 15189], [9562]]
},
// yAxisData: {
// type: Array,
// default: () => [2549, 12421, 2637, 3146, 15189, 9562]
// },
})
const chartInstance = ref(null);
onMounted(() => {
initChart();
});
watch([
() => props.seriesData,
() => props.xAxisData,
], () => {
initChart();
});
const initChart = () => {
chartInstance.value = props.seriesData.map((item, index) => {
console.log(item,"xxxxxxxx");
return {
name: props.xAxisData[index],
data: item,
type: "bar",
barWidth: "20",
// barGap: 20, // 系列之间的间距
barCategoryGap: 100, // 类别之间的间距
label: {
show: true,
position: 'top',
formatter: function (params) {
// 值为0或null时不显示
if (params.value === 0 || params.value === null) {
return '';
}
// 格式化数值显示
return params.value.toLocaleString();
},
color: '#2c3e50',
fontSize: 12,
fontWeight: 'bold',
distance: 10 // 标签与柱子的距离
},
}
})
console.log(chartInstance.value);
var myChart = echarts.init(chartDom.value);
var option = {
title: {
text: props.title,
left: 'center'
},
tooltip: {
// 鼠标悬浮提示数据
trigger: "axis",
backgroundColor: "rgba(32, 33, 36,.7)",
borderColor: "rgba(32, 33, 36,0.20)",
borderWidth: 15,
textStyle: {
// 文字提示样式
color: "#fff",
fontSize: "12",
},
axisPointer: {
// 坐标轴虚线
type: "cross",
label: {
backgroundColor: "#6a7985",
},
},
},
legend: {
right: 0
},
// },
grid: {
// 控制图表的位置
left: "5%",
right: "5%",
top: "18%",
bottom: "5%",
containLabel: true,
},
xAxis: {
data: props.xAxisData,
},
yAxis: {
// axisLabel: {
// // y轴线 标签修改
// textStyle: {
// color: "white", //坐标值得具体的颜色
// },
// },
// data: props.xAxisData,
},
series: chartInstance.value
};
option && myChart.setOption(option);
};
</script>
<style scoped>
.box {
width: 100%;
height: 60vh;
/* background-color: #031a67; */
}
</style>

View File

@ -0,0 +1,200 @@
<template>
<!-- 将固定id改为ref引用 -->
<div ref="chartContainer" style="height: 100%;"></div>
</template>
<script setup>
import * as echarts from 'echarts';
import { onMounted, onUnmounted, ref, watch, defineProps } from 'vue';
// 定义组件的属性,使其可复用
const props = defineProps({
// 图表数据
chartData: {
type: Array,
default: () => [
{ value: 40, name: 'rose 1' },
{ value: 38, name: 'rose 2' },
{ value: 32, name: 'rose 3' },
{ value: 30, name: 'rose 4' },
{ value: 28, name: 'rose 5' },
{ value: 26, name: 'rose 6' },
{ value: 22, name: 'rose 7' },
{ value: 18, name: 'rose 8' }
]
},
// 图表标题
chartName: {
type: String,
default: 'Nightingale Chart'
},
// 是否显示工具箱
showToolbox: {
type: Boolean,
default: true
},
// 是否显示图例
showLegend: {
type: Boolean,
default: true
},
// 内半径
innerRadius: {
type: Number,
default: 0
},
// 外半径
outerRadius: {
type: Number,
default: 200
},
// 扇形间距
padAngle: {
type: Number,
default: 0
},
title: {
type: Object,
default: () => ({
text: 'Nightingale Chart',
left: 'center'
})
},
roseType: {
type: String,
default: 'radius'
}
});
// 图表容器引用
const chartContainer = ref(null);
// 图表实例引用
const chartInstance = ref(null);
// 初始化图表
const initChart = () => {
const chartDom = chartContainer.value;
if (!chartDom) return;
// 如果已经存在实例,先销毁
if (chartInstance.value) {
chartInstance.value.dispose();
}
// 创建新实例
chartInstance.value = echarts.init(chartDom);
// 设置图表选项
const option = {
title: props.title,
legend: props.showLegend ? {
top: 'bottom'
} : false,
toolbox: props.showToolbox ? {
show: true,
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
} : false,
series: [
{
name: props.chartName,
type: 'pie',
radius: [props.innerRadius, props.outerRadius],
center: ['50%', '50%'],
roseType: props.roseType,
// 在 ECharts 5.3.3 中,当 roseType 为 'area' 时padAngle 需要特殊处理
// 为了确保间距生效我们需要添加一个小的非零值来替代0
// padAngle: props.padAngle === 0 ? 0.1 : props.padAngle,
itemStyle: {
borderColor: '#fff',
borderWidth:props.padAngle
},
// 显示百分比
label: {
show: true,
formatter: function(params) {
// 对于值为0的项显示0%而不是极小值计算出的百分比
if (props.chartData.find(d => d.name === params.name && d.value === 0)) {
return params.name + ': 0%';
}
return params.name + ': ' + params.percent + '%';
}
},
// 鼠标悬停时的样式
emphasis: {
label: {
show: true,
fontSize: '16',
fontWeight: 'bold',
formatter: function(params) {
// 对于值为0的项显示0%而不是极小值计算出的百分比
if (props.chartData.find(d => d.name === params.name && d.value === 0)) {
return params.name + ': 0%';
}
return params.name + ': ' + params.percent + '%';
}
}
},
// 处理数据确保值为0的项也能显示
data: props.chartData.map(item => ({
...item,
// 对于值为0的数据设置一个极小值来确保它在饼图中显示
value: item.value === 0 ? 0.0000001 : item.value
}))
}
]
};
// 应用选项
chartInstance.value.setOption(option);
};
// 处理窗口大小变化,自动调整图表大小
const handleResize = () => {
if (chartInstance.value) {
chartInstance.value.resize();
}
};
// 组件挂载时初始化图表
onMounted(() => {
initChart();
window.addEventListener('resize', handleResize);
});
// 组件卸载时销毁图表实例并移除事件监听
onUnmounted(() => {
if (chartInstance.value) {
chartInstance.value.dispose();
}
window.removeEventListener('resize', handleResize);
});
// 监听数据变化,更新图表
watch(() => props.chartData, () => {
initChart();
}, { deep: true });
// 监听其他配置变化,更新图表
watch([
() => props.chartName,
() => props.showToolbox,
() => props.showLegend,
() => props.innerRadius,
() => props.outerRadius,
() => props.padAngle,
()=> props.roseType,
], () => {
initChart();
});
</script>
<style scoped>
:deep(div) {
width: 100%;
height: 100%;
/* min-height: 400px; */
}
</style>