思路:
1. 因为html转为图片再加入到PDF中 会导致截断,因此前端自定义分页添加 类 (page)
2. 通过page生成图片 在加入PDF中
<template>
<div id="pdf-content">
<div class="page first-page">
<div>
<div class="first-page-header">
<p>监控报告</p>
<p>物流有限公司</p>
</div>
<img style="width: 100%" src="@/assets/vehicleDriving/bg.jpg" />
<div class="first-page-info">
<div class="item">
<div class="label">账户</div>
<div class="value"></div>
</div>
<div class="item">
<div class="label">运单名称</div>
<div class="value"></div>
</div>
<div class="item">
<div class="label">运单号</div>
<div class="value"></div>
</div>
<div class="item">
<div class="label">设备名称</div>
<div class="value"></div>
</div>
<div class="item">
<div class="label">设备id</div>
<div class="value">1111</div>
</div>
</div>
</div>
</div>
<div class="page">
<p>运单开始时间:2024-09-10 03:43:38</p>
<p>运单结束时间:2024-09-10 05:59:59</p>
<p>设备起点:xxx</p>
<p>设备终点:xxx</p>
<p>时长:2小时16分21秒</p>
<p>共:56条数</p>
<sv-table :data="list" :height="300" border="inner">
<sv-column v-for="item in columns" :key="item.field" :field="item.field" :title="item.title"></sv-column>
</sv-table>
<sv-table :data="list" :height="300" border="inner">
<sv-column title="事件类型" field="eventType"></sv-column>
<sv-column title="发生次数" field="count"></sv-column>
</sv-table>
</div>
<div class="page">
<e-line class="line-item"></e-line>
<e-line class="line-item"></e-line>
</div>
<div class="page">
<e-line class="line-item"></e-line>
<e-line class="line-item"></e-line>
</div>
<div class="page">
<e-line class="line-item"></e-line>
<e-line class="line-item"></e-line>
</div>
<div class="map-route page">
<e-map-route></e-map-route>
<p style="margin-top: 20px">起点:xxxx</p>
<p>终点:xxxx</p>
</div>
<div class="page">
<p>报警数据列表</p>
<sv-table :data="list" :height="300" border="inner">
<sv-column title="时间" field="eventType"></sv-column>
<sv-column title="参数类型" field="count"></sv-column>
<sv-column title="具体数值" field="count"></sv-column>
</sv-table>
</div>
</div>
</template>
<script>
import ELine from './components/ELine.vue'
import EMapRoute from './components/EMapRoute.vue'
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
export default {
name: 'ExportPdf',
components: {
ELine,
EMapRoute
},
data() {
return {
JsPDF: jsPDF,
spinning: false,
list: [
{
statusParam: 'speed',
eventType: '超速',
count: 10
},
{
statusParam: 'speed',
eventType: '疲劳驾驶',
count: 20
}
],
columns: [
{
title: '状态参数',
field: 'statusParam'
},
{
title: '阈值',
field: 'threshold'
},
{
title: '最高',
field: 'max'
},
{
title: '最低',
field: 'min'
},
{
title: '平均',
field: 'avg'
},
{
title: '超阀值',
field: 'overThreshold'
},
{
title: '报警条数',
field: 'alarmCount'
},
{
title: '安全指数',
field: 'safeIndex'
}
]
}
},
methods: {
async getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
list: [
{
statusParam: 'speed',
eventType: '超速',
count: 10
},
{
statusParam: 'speed',
eventType: '疲劳驾驶',
count: 20
}
]
})
}, 2000)
})
},
async print() {
await this.getData()
const contentDiv = document.getElementById('pdf-content')
const pages = contentDiv.querySelectorAll('.page')
const promises = []
for (const page of pages) {
const p = await html2canvas(page)
promises.push(p)
}
const canvases = await Promise.all(promises)
const pdf = new this.JsPDF('', 'pt', 'a4')
for (let i = 0; i < canvases.length; i++) {
const canvas = canvases[i]
const imgData = canvas.toDataURL('image/jpeg', 1.0)
const imgProps = pdf.getImageProperties(imgData)
const pdfWidth = pdf.internal.pageSize.getWidth()
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight)
if (i < canvases.length - 1) {
pdf.addPage()
}
}
pdf.save('车载数据报告.pdf')
this.$emit('success')
}
}
}
</script>
<style scoped lang="less">
#pdf-content {
width: 900px;
padding: 20px;
font-size: 16px;
color: #000;
.line-item {
width: 100%;
height: 400px;
}
.map-route {
width: 100%;
}
.page {
height: 850px;
}
.first-page {
box-sizing: border-box;
padding-top: 80px;
.first-page-header {
text-align: center;
font-size: 30px;
font-weight: bold;
}
.first-page-info {
font-weight: bold;
width: 500px;
margin: 0 auto;
}
.item {
display: flex;
.label {
width: 150px;
font-size: 24px;
text-align: right;
}
.value {
width: 300px;
font-size: 22px;
border-bottom: 1px solid #000;
}
}
}
}
</style>
echarts 测试代码
<template>
<div class="e-line" ref="eLineRef"></div>
</template>
<script>
import * as echarts from 'echarts'
export default {
data() {
return {}
},
mounted() {
this.initChart()
},
methods: {
initChart() {
const eLineRef = this.$refs.eLineRef
const myChart = echarts.init(eLineRef)
const option = {
title: {},
tooltip: {},
grid: {
left: 0,
right: 0,
containLabel: true
},
legend: {
data: ['Sales']
},
xAxis: {
data: [
'shirt',
'cardign',
'chiffon shirt',
'pants',
'heels',
'socks',
'book',
'poster',
'notebook',
'glass',
'toilet paper'
]
},
yAxis: {},
series: [
{
name: 'Sales',
type: 'line',
data: [5, 20, 36, 10, 10, 20, 8, 20, 10, 10, 20]
}
]
}
myChart.setOption(option)
}
}
}
</script>
<style scoped lang="less">
.e-line {
width: 100%;
height: 100%;
}
</style>
高德测试代码
<template>
<div id="e-map-route"></div>
</template>
<script>
export default {
data() {
return {
lnglats: [[121.473702, 31.230416]],
map: null
}
},
methods: {
initMap() {
const map = new AMap.Map('e-map-route', {
viewMode: '2D',
zoom: 11,
WebGLParams: {
preserveDrawingBuffer: true
}
})
this.map = map
this.setDriveRoute()
},
setDriveRoute() {
const _this = this
AMap.plugin('AMap.Driving', function () {
const driving = new AMap.Driving({
map: _this.map
})
const start = [121.473702, 31.230416]
const end = [120.193636, 30.259244]
const waypoints = []
driving.search(start, end, waypoints, function (status, result) {
if (status === 'complete') {
_this.map.setFitView()
}
})
})
}
},
mounted() {
this.initMap()
}
}
</script>
<style lang="less">
#e-map-route {
height: 500px;
width: 100%;
}
</style>