vue-electron 批量生成 pdf

最近有个需求,需要批量下载 pdf,单份还好,但多份时会超时。
需要改成一份一份下载,先选择下载的存储路径,再自动下载到选择的目录中,一开始使用了 will-download,但在测试过程中,测服下载速度很慢,发现保存地址还是会弹出来,下载一次弹出一份。
因此打算试试利用 electron 原来的生成 pdf 功能

计划利用一个隐藏窗口来生成PDF,打开隐藏窗口后,加载数据,判断加载完成后,开始生成 PDF 页面,会涉及到 electron 的打开新窗口、选择文件夹、生成 PDF 三个功能

官方API

开发环境:electron4+

选择存储目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// html
created: function() {
// 监听方法一般放在 created 就行
ipcRenderer.on('selected-directory', (event, path) => {
this.fileSavePath = path
})
}
// 调用
ipcRenderer.send('select-file-dialog')

beforeDestroy() {
// 因为 .on 监听方法会一直存在,导致多次监听,所以每次退出页面把监听移除掉就行了
ipcRenderer.removeAllListeners('selected-directory')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--main.js-->
const {ipcMain, dialog} = require('electron')
ipcMain.on('select-file-dialog', (event) => {
dialog.showOpenDialog({
title: '选择文件夹',
buttonLabel: '确定',
properties: ['openFile', 'openDirectory']
}, (files) => {
if (files) {
// 将得到的路径传回页面存起来
event.sender.send('selected-directory', files)
}
})
})

打开新窗口

主进程打开新窗口并跳到某个页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let {href} = this.$router.resolve({
name: urlName,
query: { id: this.id, pdfPath: this.pdfPath}
});
ipcRenderer.send('open-window', `${href}`)

let sideWIndow
ipcMain.on('open-window', (event, _data) => {
// 判断下隐藏窗口是否存在,如果不存在才打开一个新窗口
if (!sideWIndow) {
sideWIndow = new BrowserWindow({
width: 1280,
height: 720,
show: false // 是否隐藏窗口,在测试过程中,可以先改成 true 来看跳转的页面是否正确
})
}
// 判断了下是否是开发环境
let url = `file://${__dirname}/index.html${_data}`
if (process.env.NODE_ENV === 'development') {
url = `http://localhost:9080${_data}`
}
// 子窗口加载页面
sideWIndow.loadURL(url)
sideWIndow.on('closed', () => {
sideWIndow = null
})
})
// 关闭窗口的指令
ipcMain.on('close-window', (event, _data) => {
if (sideWIndow) {
sideWIndow.close()
}
})

关闭窗口

1
2
3
4
5
6
7
8
9
10
11
12
// 退出此页面时,关闭窗口
beforeDestroy() {
ipcRenderer.send('close-window')
}

// 主窗口有个关闭窗口事件,我们在这里也加个判断,把隐藏窗口一起关了
mainWindow.on('closed', () => {
mainWindow = null
if (sideWindow) {
sideWindow.close()
}
})

生成 pdf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 这里生成报告页还是一份一份生成的,只要在前端遍历,有接收到生成成功的信号,就在下载下一份就可以了
// html
// 生成 PDF 需要一个存储路径,以及文件名
ipcRenderer.send('print-all-pdf', 'E:\name.pdf')
// 接收
ipcRenderer.on('wrote-all-pdf', (event, data) => {
console.log('报告下载成功!')
})

<!--main.js-->
// 生成 PDF 放在同个页面新建窗口的同一个页面
// mainWindow 是主窗口,用来接收子窗口下载报告成功的指令
const fs = require('fs')
ipcMain.on('print-all-pdf', (event, _data) => {
const pdfPath = _data
sideWindow.webContents.printToPDF({}, (error, data) => {
if (error) console.error(error)
fs.writeFile(pdfPath, data, (error) => {
if (error) {
console.error(error)
}
if (error) {
mainWindow.webContents.send('wrote-all-pdf-err', pdfPath)
} else {
mainWindow.webContents.send('wrote-all-pdf', pdfPath)
}
})
})
})
ipcMain.on('print-err-pdf', (event, _data) => {
mainWindow.webContents.send('wrote-all-pdf-err')
})

在下载成功的时候,可以触发事件去下载下一份报告