起源
大一下有了大物实验,每周要打印实验报告,宿舍楼下的打印店拆了,然后就有很多人叫我帮忙打印。由于人太多了,我就用nodejs和elementUI写了个自助打印的程序,然后内网穿透到公网上,别人访问网站上传文件打印就可以了
附上github链接
moneypiaorui/PrintingServe: supply self-service printing service (github.com)
demo链接
效果
打印界面
用户需要注册登录,上传文件然后选择文件打印
管理界面
管理员用户可以登录后台查看所有用户,打印记录和所有用户上传的文件(筛选功能还没写),左侧的时间是时间戳,方便使用el-table的排序
文件预览
由于打印使用的pdf-to-printer包,采用libreoffice的api将docx,doc和图片转成pdf,但是libreoffice转pdf格式会出问题(毕竟开源项目),也没搞明白微软的pdf打印机api怎么使用,所以还是建议自己转成pdf再上传打印。
提供文件预览功能,防止docx和doc转pdf格式不符合预期
代码结构
编辑
- components是一些nodejs的组件,包括用户认证的中间件,数据库载入,转pdf等
- dist放的是vue-cli项目build后的代码,可以删掉,前端用VUE-cli覆写虽然完成了,但代码太丑暂时搁置优化
- public是静态资源,前端路由文件
- router存放路由处理的代码
- uploads存放用户上传的文件
- app.js程序主入口
- pretectedRouter.js无用,本来打算做用户权限管理,但在用户中间件实现了
- user.db是SQLite数据库文件,里面有三个表,详细看数components下的据库组件
项目部署
- 安装nodejs,最新版就行,并配置好环境变量,保证nodejs能在终端使用
- clone本项目,或者github下载压缩包解压
- 下载libreoffice并配置环境变量保证soffice可以在终端调用
- 项目目录打开终端,npm run test或者node app.js启动服务
ps:暂只在windows上部署成功,linux没试
如果不想配置libreoffice,修改如下:
将printRouter.js替换如下
const path = require('path');
const printer = require('pdf-to-printer');
const express = require('express');
const { PDFDocument } = require('pdf-lib');
const fs = require('fs').promises;
const printRouter = express.Router();
const authMiddleware = require('../components/authMiddleware');
const wordToPdf = require('../components/officeToPdf');
const db = require('../components/database');
// 处理打印操作的路由
printRouter.post('/', authMiddleware, async (req, res) => {
const { filename, timestamp } = req.body;
const completeFilename = `${timestamp}-${filename}`;
// 执行打印操作的逻辑
if (filename) {
let filePath = path.join(__dirname, '../uploads', completeFilename);
const ext = path.extname(filename);
printer
.print(filePath, {
printDialog: 0,
monochrome: 1,//黑白打印
copies: 1
})
.then(async () => {
console.log(`文件${completeFilename}已打印`);
if (path.extname(filePath) == ".pdf") {
await getPageCount(filePath)
.then(pageCount => {
res.status(200).json({ message: '文件已发送到打印机进行打印', pages: pageCount });
db.run(`INSERT INTO printLogs (filename, username, printTimestamp,pages) VALUES (?, ?, ?, ?)`, [filename, req.username, Date.now(), pageCount], function (err) {
if (err) {
} else {
}
})
})
.catch(err => {
res.status(200).json({ message: '文件已发送到打印机进行打印', err: "获取pdf页数时出错", pages: 0 });
console.error('获取 PDF 文件页数时出错:', err);
});
} else {
res.status(200).json({ message: '文件已发送到打印机进行打印', err: "不是PDF", pages: 1 });
}
})
.catch((err) => {
console.error('打印失败:', err);
res.status(500).json({ message: '打印失败' });
});
} else {
res.status(400).send('未选择文件');
}
});
async function getPageCount(pdfPath) {
try {
// 读取 PDF 文件
const pdfBytes = await fs.readFile(pdfPath);
// 打开 PDF 文档
const pdfDoc = await PDFDocument.load(pdfBytes);
// 获取 PDF 文件的页数
const pageCount = pdfDoc.getPageCount();
return pageCount;
} catch (error) {
console.error('读取 PDF 文件时出错:', error);
return 0;
}
}
module.exports = printRouter;
然后在public/index.html中100行左右找到fileType数组,删除doc和docx即可禁止用户上传该类文件
Comments NOTHING