阅行客电子档案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
9.6 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. <template>
  2. <div class="box">
  3. <div class="top-container">
  4. <div class="top-left">
  5. <input
  6. class="file-select"
  7. type="file"
  8. @change="handleChange"
  9. >
  10. </div>
  11. <div class="top-middle">
  12. 文件预览
  13. </div>
  14. <div class="top-right">
  15. <el-button @click="printWindow">
  16. <i class="el-icon-printer" />window
  17. </el-button>
  18. <el-button v-print="printObj">vue-print打印</el-button>
  19. <el-button type="primary" @click="toImg">转图片打印</el-button>
  20. </div>
  21. </div>
  22. <div class="main-content">
  23. <div class="content-list">原文列表</div>
  24. <div v-loading="loading" class="content-right">
  25. <!-- <div v-show="loading" class="well loading">
  26. 正在加载中请耐心等待...
  27. </div> -->
  28. <div id="printArea" ref="output" class="well-box" />
  29. <div class="water-mask" />
  30. </div>
  31. </div>
  32. </div>
  33. </template>
  34. <script>
  35. import { getExtend, readBuffer, render } from '@/components/util'
  36. import { parse } from 'qs'
  37. // import { timeFormate } from '@/utils/index'
  38. import { watermark } from '@/utils/waterMark'
  39. import html2canvas from 'html2canvas' // 转图片打印需要先安装html2Canvas和print-js
  40. import printJS from 'print-js'
  41. export default {
  42. name: 'Preview',
  43. props: {
  44. msg: {
  45. type: String,
  46. default: ''
  47. }
  48. },
  49. data() {
  50. return {
  51. logo: require('../../assets/images/logo.png'),
  52. // 加载状态跟踪
  53. loading: false,
  54. // 上个渲染实例
  55. last: null,
  56. // 隐藏头部,当基于消息机制渲染,将隐藏
  57. hidden: false,
  58. printObj: {
  59. id: 'printArea',
  60. popTitle: '配置页眉标题', // 打印配置页上方的标题
  61. extraHead: '打印', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
  62. preview: true, // 是否启动预览模式,默认是false
  63. previewTitle: '预览的标题', // 打印预览的标题
  64. previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
  65. zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
  66. previewBeforeOpenCallback() { console.log('正在加载预览窗口!') }, // 预览窗口打开之前的callback
  67. previewOpenCallback() { console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
  68. beforeOpenCallback() { console.log('开始打印之前!') }, // 开始打印之前的callback
  69. openCallback() { console.log('执行打印了!') }, // 调用打印时的callback
  70. closeCallback() { console.log('关闭了打印工具!') }, // 关闭打印的callback(无法区分确认or取消)
  71. clickMounted() { console.log('点击v-print绑定的按钮了!') },
  72. // url: 'http://localhost:8080/', // 打印指定的URL,确保同源策略相同
  73. // asyncUrl (reslove) {
  74. // setTimeout(() => {
  75. // reslove('http://localhost:8080/')
  76. // }, 2000)
  77. // },
  78. standard: '',
  79. extarCss: ''
  80. },
  81. watermarkInfo: null,
  82. timer: null
  83. }
  84. },
  85. created() {
  86. // 允许使用预留的消息机制发送二进制数据,必须在url后添加?name=xxx.xxx&from=xxx
  87. const { from, name } = parse(location.search.substr(1))
  88. if (from) {
  89. window.addEventListener('message', (event) => {
  90. const { origin, data: blob } = event
  91. if (origin === from && blob instanceof Blob) {
  92. // 构造响应,自动渲染
  93. const file = new File([blob], name, {})
  94. this.hidden = true
  95. this.handleChange({ target: { files: [file] }})
  96. }
  97. })
  98. }
  99. },
  100. methods: {
  101. toImg() { // 转图片打印
  102. html2canvas(this.$refs.output, {
  103. backgroundColor: null,
  104. useCORS: true,
  105. windowHeight: document.body.scrollHeight
  106. }).then((canvas) => {
  107. // let url = canvas.toDataURL('image/jpeg', 1.0)
  108. const url = canvas.toDataURL()
  109. this.img = url
  110. printJS({
  111. printable: url,
  112. type: 'image',
  113. documentTitle: '打印图片'
  114. })
  115. console.log(url)
  116. })
  117. },
  118. async handleChange(e) {
  119. this.loading = true
  120. try {
  121. clearTimeout(this.timer)
  122. const [file] = e.target.files
  123. const arrayBuffer = await readBuffer(file)
  124. this.last = await this.displayResult(arrayBuffer, file)
  125. this.$nextTick(() => {
  126. // 取得扩展名
  127. const extend = getExtend(file.name)
  128. // 加水印
  129. const maskDiv = document.getElementsByClassName('mask_div')
  130. const imgMaskDiv = document.getElementsByClassName('weterbox')
  131. if (imgMaskDiv.length === 1) {
  132. document.getElementsByClassName('water-mask')[0].removeChild(imgMaskDiv[0])
  133. }
  134. // docx-wrapper docx
  135. for (var j = maskDiv.length - 1; j >= 0; j--) {
  136. document.getElementsByClassName('water-mask')[0].removeChild(maskDiv[j])
  137. }
  138. this.watermarkInfo = {
  139. 'id': '9C5384EE889C0A977FC8F6',
  140. 'watermarkType': '0',
  141. 'watermarkFont': '16',
  142. 'transparency': 'rgba(255, 69, 0, 0.45)',
  143. 'context': '安全水印',
  144. 'isEnable': true
  145. }
  146. if (!extend.includes('pdf')) {
  147. // watermark({ watermark_txt: '徐华姣' + timeFormate() }, 'water-mask', 'text')
  148. // watermark({ watermark_txt: this.logo }, 'water-mask', 'img')
  149. watermark({
  150. watermark_txt: this.watermarkInfo.context,
  151. watermark_color: this.watermarkInfo.transparency,
  152. watermark_fontsize: this.watermarkInfo.watermarkFont + 'px'
  153. }, 'water-mask', 'text')
  154. }
  155. })
  156. } catch (e) {
  157. console.error(e)
  158. } finally {
  159. this.timer = setTimeout(() => {
  160. this.loading = false
  161. }, 1000)
  162. }
  163. },
  164. displayResult(buffer, file) {
  165. // 取得文件名
  166. const { name } = file
  167. // 取得扩展名
  168. const extend = getExtend(name)
  169. // 输出目的地
  170. const { output } = this.$refs
  171. // 生成新的dom
  172. const node = document.createElement('div')
  173. // 添加孩子,防止vue实例替换dom元素
  174. if (this.last) {
  175. output.removeChild(this.last.$el)
  176. this.last.$destroy()
  177. }
  178. const child = output.appendChild(node)
  179. // 调用渲染方法进行渲染
  180. return new Promise((resolve, reject) =>
  181. render(buffer, extend, child).then(resolve).catch(reject)
  182. )
  183. },
  184. // 打印ofd文件
  185. async printWindow() {
  186. /* if (this.showScale !== 0) {
  187. this.showScale = 0;
  188. const divs = renderOfd(this.domWidth, this.ofdObj);
  189. await this.displayOfdDiv(divs);
  190. }*/
  191. const childs = this.$refs.output.children
  192. const list = []
  193. for (const page of childs) {
  194. list.push(page.cloneNode(true))
  195. }
  196. if (list.length > 0) {
  197. const printWindow = window.open('打印窗口', '_blank')
  198. // 给新打开的标签页添加画布内容
  199. const documentBody = printWindow.document.body
  200. // 需要给新打开的标签页添加样式,否则打印出来的内容会很错位
  201. documentBody.style.marginTop = '20px'
  202. for (const page of list) {
  203. // 为了让打印的内容不会太靠上,所以给每一页都添加一个marginBottom
  204. page.style.marginBottom = '20px'
  205. documentBody.appendChild(page)
  206. }
  207. // 焦点移到新打开的标签页
  208. printWindow.focus()
  209. // 执行打印的方法(注意打印方法是打印的当前窗口内的元素,所以前面才新建一个窗口:print()--打印当前窗口的内容。)
  210. printWindow.print()
  211. // 操作完成之后关闭当前标签页(点击确定或者取消都会关闭)
  212. printWindow.close()
  213. }
  214. }
  215. }
  216. }
  217. </script>
  218. <style>
  219. @media print {
  220. @page {
  221. size: auto;
  222. }
  223. body, html {
  224. height: auto !important;
  225. }
  226. }
  227. </style>
  228. <style lang="scss" scoped>
  229. .top-container{
  230. display: flex;
  231. justify-content: space-between;
  232. padding: 0 20px;
  233. height: 50px;
  234. line-height: 50px;
  235. overflow: hidden;
  236. text-align: center;
  237. align-items: center;
  238. color: #000;
  239. .top-left{
  240. }
  241. .top-middle{
  242. flex:1;
  243. text-align: center;
  244. font-size: 20px;
  245. font-weight: bold;
  246. }
  247. .top-right{
  248. text-align: center;
  249. align-items: center;
  250. display:flex;
  251. justify-content: flex-end;
  252. .el-button{
  253. padding: 0 4px;
  254. height: 30px;
  255. line-height: 30px;
  256. }
  257. }
  258. }
  259. .main-content{
  260. display: flex;
  261. justify-content: space-between;
  262. width: calc(100%);
  263. height: calc(100vh - 51px);
  264. border-top: 1px solid #ccc;
  265. .content-list{
  266. width: 300px;
  267. padding: 10px;
  268. }
  269. .content-right{
  270. position: relative;
  271. flex: 1;
  272. height: calc(100vh - 52px);
  273. background: #f2f2f2;
  274. border: 1px solid #ccc;
  275. border-top: none;
  276. overflow: hidden;
  277. overflow-y: auto;
  278. }
  279. }
  280. .well-box{
  281. position: relative;
  282. }
  283. .water-mask{
  284. position: fixed;
  285. left: 300px;
  286. top: 55px;
  287. bottom: 10px;
  288. right: 10px;
  289. width:100%;
  290. z-index:99;
  291. pointer-events: none;
  292. }
  293. </style>
  294. <style>
  295. .pptx-wrapper {
  296. max-width: 1000px;
  297. margin: 0 auto;
  298. }
  299. </style>