做棋牌网站一般多少钱,网站建设 成功案例,大连模版网站,微信小程序app在前端开发中#xff0c;除了将数据呈现后#xff0c;我们往往需要为用户提供#xff0c;打印#xff0c;导出等能力#xff0c;导出是为了存档或是二次分析#xff0c;而打印则因为很多单据需要打印出来作为主要的单据来进行下一环节的票据支撑#xff0c; 而前端打印可…在前端开发中除了将数据呈现后我们往往需要为用户提供打印导出等能力导出是为了存档或是二次分析而打印则因为很多单据需要打印出来作为主要的单据来进行下一环节的票据支撑 而前端打印可以说是非常令人头疼的一件事。为什么令大家头疼呢因为前端打印要强依赖与浏览器的打印预览页面会天然存在以下弊端每一次打印都要弹出来打印预览对话框如果前端需要批量打印那么意味着客户要点击无数个关闭按钮才能实现批量打印如果一次性打印几百张上千张的报表则会成为“NightMare”。前端打印强依赖于浏览器主流的思路是先将内容转换为PDF文件再调用浏览器的打印功能进行打印而生成PDF文件是依赖于浏览器对于字体边线等的处理因此浏览器的异同则直接导致打印出来的效果差距很大有的边线加粗有的1页数据打印出来呈现2页也是让开发者十分苦恼的事情对于一些打印要求比较高的行业这就是灾难。因此如何在前端实现无预览打印也就是用户点击打印之后直接就使用默认打印机打印出来。针对这个需求我们验证了一个解决该问题的方案本贴就来介绍该方案如何实现。实现思路如下后端实现一个接口接收Blob类型PDF流然后调用系统默认打印机将PDF进行静默打印。前端利用ACTIVEREPORTSJS自带的导出PDF导出Blob类型然后通过POST请求调用后端接口将Blob流传给后端进行打印。具体实现步骤前端实现方法前端利用ActivereportsJS的PDF.exportDocument无预览导出PDF该接口返回的result包含data属性和download方法然后调用后端接口将result.data传递给后端。functionprintPDF() {varACTIVEREPORTSJS GC.ActiveReports.Core;varPDF GC.ActiveReports.PdfExport;var settings {info: {title: test,author: GrapeCity inc.,},pdfVersion: 1.7,};var pageReport newACTIVEREPORTSJS.PageReport();pageReport.load(1.rdlx-json).then(function () {return pageReport.run();}).then(function (pageDocument) {returnPDF.exportDocument(pageDocument, settings);}).then(function (result) {let formData newFormData();formData.append(file, result.data);fetch(http://localhost:8088/print, {method: POST,mode: cors,body: formData})});}后端实现方式我这边是采用python实现了一个接口接收前端传递的Blob文件流然后调用后端部署的服务器默认打印机直接进行静默打印。后端程序可以部署到服务器上如果是windows服务器可以直接下载exe在服务器上运行。下载下来是2个exe程序需要放在同一个文件夹然后运行PrintAgent.exe切记这两个程序需要放在同一个文件夹。注意如果exe只给服务器上部署那么前端在打印时调用服务器地址接口打印最终都会从服务器上连接的打印机打出来。如果exe给客户端部署了那么前端打印就可以代码调用localhost地址去打印最终就会从客户端所连接的默认打印机打印出来切换打印机的话就调整windows的默认打印机就可以。Linux服务器的话需要将源码拷贝到服务器去运行。在实现 cli 的过程中会涉及到组件名称命名方式的转换、执行cmd命令等操作所以在开始实现创建组件前先准备一些工具类。在 cli/src/util/ 目录上一篇文章中已经创建了一个 log-utils.ts 文件现继续创建下列四个文件cmd-utils.ts、loading-utils.ts、name-utils.ts、template-utils.ts1.1 name-utils.ts该文件提供一些名称组件转换的函数如转换为首字母大写或小写的驼峰命名、转换为中划线分隔的命名等/*** 将首字母转为大写*/exportconst convertFirstUpper (str: string): string {return${str.substring(0, 1).toUpperCase()}${str.substring(1)}
}
/*** 将首字母转为小写*/exportconst convertFirstLower (str: string): string {return${str.substring(0, 1).toLowerCase()}${str.substring(1)}
}
/*** 转为中划线命名*/exportconst convertToLine (str: string): string {returnconvertFirstLower(str).replace(/([A-Z])/g, -$1).toLowerCase()
}
/*** 转为驼峰命名首字母大写*/exportconst convertToUpCamelName (str: string): string {let ret const list str.split(-)list.forEach(item {ret convertFirstUpper(item)})returnconvertFirstUpper(ret)
}
/*** 转为驼峰命名首字母小写*/exportconst convertToLowCamelName (componentName: string): string {returnconvertFirstLower(convertToUpCamelName(componentName))
}1.2 loading-utils.ts在命令行中创建组件时需要有 loading 效果该文件使用 ora 库提供显示 loading 和关闭 loading 的函数import ora fromoraletspinner: ora.Ora | null nullexportconstshowLoading (msg: string) {spinner ora(msg).start()
}exportconstcloseLoading () {if (spinner ! null) {spinner.stop()}
}1.3 cmd-utils.ts该文件封装 shelljs 库的 execCmd 函数用于执行 cmd 命令import shelljs fromshelljsimport { closeLoading } from./loading-utilsexportconstexecCmd (cmd: string) newPromise((resolve, reject) {shelljs.exec(cmd, (err, stdout, stderr) {if (err) {closeLoading()reject(newError(stderr))}returnresolve()})
})1.4 template-utils.ts由于自动创建组件需要生成一些文件template-utils.ts 为这些文件提供函数获取模板。由于内容较多这些函数在使用到的时候再讨论。2 参数实体类执行 gen 命令时会提示开发人员输入组件名、中文名、类型此外还有一些组件名的转换故可以将新组件的这些信息封装为一个实体类后面在各种操作中传递该对象即可从而避免传递一大堆参数。2.1 component-info.ts在 src 目录下创建 domain 目录并在该目录中创建 component-info.ts 该类封装了组件的这些基础信息import * as path frompathimport { convertToLine, convertToLowCamelName, convertToUpCamelName } from../util/name-utilsimport { Config } from../configexportclassComponentInfo {/** 中划线分隔的名称如nav-bar */lineName: string/** 中划线分隔的名称带组件前缀 如yyg-nav-bar */lineNameWithPrefix: string/** 首字母小写的驼峰名 如navBar */lowCamelName: string/** 首字母大写的驼峰名 如NavBar */upCamelName: string/** 组件中文名 如左侧导航 */zhName: string/** 组件类型 如tsx */type: tsx | vue/** packages 目录所在的路径 */parentPath: string/** 组件所在的路径 */fullPath: string/** 组件的前缀 如yyg */prefix: string/** 组件全名 如yyg-demo-ui/xxx */nameWithLib: stringconstructor (componentName: string, description: string, componentType: string) {this.prefix Config.COMPONENT_PREFIXthis.lineName convertToLine(componentName)this.lineNameWithPrefix ${this.prefix}-${this.lineName}this.upCamelName convertToUpCamelName(this.lineName)this.lowCamelName convertToLowCamelName(this.upCamelName)this.zhName descriptionthis.type componentType vue ? vue : tsxthis.parentPath path.resolve(__dirname, ../../../packages)this.fullPath path.resolve(this.parentPath, this.lineName)this.nameWithLib ${Config.COMPONENT_LIB_NAME}/${this.lineName}}
}2.2 config.ts上面的实体中引用了 config.ts 文件该文件用于设置组件的前缀和组件库的名称。在 src 目录下创建 config.tsexportconstConfig {/** 组件名的前缀 */COMPONENT_PREFIX: yyg,/** 组件库名称 */COMPONENT_LIB_NAME: yyg-demo-ui
}3 创建新组件模块3.1 概述上一篇开篇讲了cli 组件新组件要做四件事创建新组件模块创建样式 scss 文件并导入在组件库入口模块安装新组件模块为依赖并引入新组件创建组件库文档和 demo。本文剩下的部分分享第一点其余三点下一篇文章分享。在 src 下创建 service 目录上面四个内容拆分在不同的 service 文件中并统一由 cli/src/command/create-component.ts 调用这样层次结构清晰也便于维护。首先在 src/service 目录下创建 init-component.ts 文件该文件用于创建新组件模块在该文件中要完成如下几件事创建新组件的目录使用 pnpm init 初始化 package.json 文件修改 package.json 的 name 属性安装通用工具包 yyg-demo-ui/utils 到依赖中创建 src 目录在 src 目录中创建组件本体文件 xxx.tsx 或 xxx.vue在 src 目录中创建 types.ts 文件创建组件入口文件 index.ts。