diff --git a/src/vendors/pdf/PdfView.vue b/src/vendors/pdf/PdfView.vue
index 45a782b..3464e1e 100644
--- a/src/vendors/pdf/PdfView.vue
+++ b/src/vendors/pdf/PdfView.vue
@@ -53,7 +53,9 @@ export default {
initColor: null,
fileParentInfo: null,
selectedCategory:null,
- formatData:[]
+ formatData:[],
+ // 带水印的 PDF 字节,供外部打印使用
+ pdfBytes: null
}
},
mounted() {
@@ -78,7 +80,8 @@ export default {
return
}
this.pdf_scale = this.pdf_scale + 0.1
- this.loadFile()
+ // 只重新渲染 canvas,不重新加载文档,避免大文件每次缩放都卡顿
+ this.renderPagePdf()
},
scaleX() {
// 缩小
@@ -87,7 +90,7 @@ export default {
return
}
this.pdf_scale = this.pdf_scale - 0.1
- this.loadFile()
+ this.renderPagePdf()
},
formateTime() {
const time = new Date()
@@ -114,35 +117,8 @@ export default {
await getInitWatermark().then((res) => {
this.watermarkInfo = res
if (res.watermarkType === '1') {
- // 图片水印
- let dom = document.getElementsByClassName('page')
- let canvas = document.createElement('canvas')
- let cxt = canvas.getContext('2d')
- let divImg = document.createElement('div')
-
- let imgScale = 0.1
- //创建新的图片对象
- let img = new Image();
- //指定图片的URL
- img.src = this.watermarkInfo.context;
- let _this = this;
- //浏览器加载图片完毕后再绘制图片
- img.onload = function() {
- //cxt.drawImage(img,0,0);
- cxt.rotate(-20 * Math.PI / 180)
- let whScale = img.width / img.height
- cxt.clearRect(0, 0, canvas.width, canvas.height);
- cxt.drawImage(img, //规定要使用的图像、画布或视频。
- 0, 0, //开始剪切的 x 坐标位置。
- img.width, img.height, //被剪切图像的高度。
- 0, 50,//在画布上放置图像的 x 、y坐标位置。
- img.width * imgScale, img.height * imgScale //要使用的图像的宽度、高度
- )
-
- divImg.style.opacity = parseFloat(_this.watermarkInfo.transparency) / 100
- divImg.style.background = 'url(' + canvas.toDataURL('image/png') + ') left top repeat'
- _this.drawImage2(divImg,dom)
- }
+ // 图片水印画到 DOM 层(.page div),延迟到页面渲染后再画,避免此时 .page div 还未渲染导致 drawImage2 取不到节点
+ this._pendingImageWatermark = true
} else if (res.watermarkType === '0') {
const rgbaValue = this.watermarkInfo.transparency;
const startIndex = rgbaValue.indexOf('('); // 找到第一个括号的位置
@@ -195,9 +171,14 @@ export default {
})
const pdfBytes = await pdfDoc.save()
+ this.pdfBytes = pdfBytes
this.pdfDoc = await PDFJS.getDocument(pdfBytes).promise
this.pdf_pages = this.pdfDoc.numPages
- this.$nextTick(() => this.renderPagePdf())
+ this.$nextTick(() => {
+ this.renderPagePdf()
+ // 归档章只在文档加载后调一次,不在每页渲染时重复请求
+ this.getFilingsealFormat()
+ })
},
drawImage2 (div,dom) {
div.style.pointerEvents = 'none'
@@ -273,9 +254,32 @@ export default {
return this.renderPagePdf(num + 1)
})
}
-
- // 归档章数据获取操作
- this.getFilingsealFormat()
+
+ // 图片水印延迟到第一页渲染后画,此时 .page div 已存在
+ if (num === 1 && this._pendingImageWatermark) {
+ this._pendingImageWatermark = false
+ this.drawImageWatermarkToDom()
+ }
+ },
+ // 图片水印画到 DOM 层(.page div),从 loadFile 延迟到此调用,解决 .page div 未渲染时画不上的竞态
+ drawImageWatermarkToDom() {
+ if (!this.watermarkInfo || this.watermarkInfo.watermarkType !== '1') return
+ const dom = document.getElementsByClassName('page')
+ if (!dom || dom.length === 0) return
+ const canvas = document.createElement('canvas')
+ const cxt = canvas.getContext('2d')
+ const divImg = document.createElement('div')
+ const imgScale = 0.1
+ const img = new Image()
+ img.src = this.watermarkInfo.context
+ img.onload = () => {
+ cxt.rotate(-20 * Math.PI / 180)
+ cxt.clearRect(0, 0, canvas.width, canvas.height)
+ cxt.drawImage(img, 0, 0, img.width, img.height, 0, 50, img.width * imgScale, img.height * imgScale)
+ divImg.style.opacity = parseFloat(this.watermarkInfo.transparency) / 100
+ divImg.style.background = 'url(' + canvas.toDataURL('image/png') + ') left top repeat'
+ this.drawImage2(divImg, dom)
+ }
},
getFilingsealFormat() {
FetchGetFilingsealFormat().then((res) => {
diff --git a/src/views/preview/index.vue b/src/views/preview/index.vue
index ba727a2..decded0 100644
--- a/src/views/preview/index.vue
+++ b/src/views/preview/index.vue
@@ -43,7 +43,7 @@
-
+
@@ -221,6 +221,49 @@ export default {
this.downloading = false
})
},
+ // 打印入口:按文件类型分流,保证水印带入打印
+ handlePrint() {
+ if (!this.fileCurrent || !this.fileCurrent.file_name) {
+ this.$message.warning('请先选择文件')
+ return
+ }
+ const extend = getExtend(this.fileCurrent.file_name)
+ if (extend.includes('pdf')) {
+ // PDF:水印已用 pdf-lib 打进内容,直接 iframe 打印带水印字节
+ this.printPdf()
+ } else {
+ // 非 PDF:水印是 DOM 覆盖层,打印前克隆注入 printArea,打印完清理
+ this.printWithWatermark()
+ }
+ },
+ printPdf() {
+ // 用原始文件 Blob(不含 pdf-lib 打的水印)打印
+ if (!this.toFile) {
+ this.$message.warning('PDF 尚未加载完成,请稍候')
+ return
+ }
+ const iframe = document.createElement('iframe')
+ iframe.style.cssText = 'position:absolute;width:0;height:0;border:0;'
+ document.body.appendChild(iframe)
+ const url = URL.createObjectURL(this.toFile)
+ iframe.src = url
+ iframe.onload = () => {
+ iframe.contentWindow.focus()
+ iframe.contentWindow.print()
+ }
+ const cleanup = () => {
+ URL.revokeObjectURL(url)
+ if (iframe.parentNode) iframe.parentNode.removeChild(iframe)
+ window.removeEventListener('afterprint', cleanup)
+ }
+ window.addEventListener('afterprint', cleanup)
+ },
+ printWithWatermark() {
+ // 非 PDF:直接打印 printArea 内容,不注入水印,预览水印不受影响
+ const printArea = document.getElementById('printArea')
+ if (!printArea) return
+ printJS({ printable: 'printArea', type: 'html', scanStyles: true })
+ },
selectFile(item) {
this.fileCurrent = item
this.getBase64ByFileId()
@@ -258,18 +301,13 @@ export default {
}
},
base64ToFile(base64String, fileName, mimeType) {
- var byteCharacters = atob(base64String)
- var byteArrays = []
- for (var offset = 0; offset < byteCharacters.length; offset += 512) {
- var slice = byteCharacters.slice(offset, offset + 512)
- var byteNumbers = new Array(slice.length)
- for (var i = 0; i < slice.length; i++) {
- byteNumbers[i] = slice.charCodeAt(i)
- }
- var byteArray = new Uint8Array(byteNumbers)
- byteArrays.push(byteArray)
+ const binaryString = atob(base64String)
+ // 一次性创建 Uint8Array,避免 512 字节切片循环带来的多次内存分配
+ const bytes = new Uint8Array(binaryString.length)
+ for (let i = 0; i < binaryString.length; i++) {
+ bytes[i] = binaryString.charCodeAt(i)
}
- var file = new Blob(byteArrays, { type: mimeType })
+ const file = new Blob([bytes], { type: mimeType })
file.name = fileName
return file
},
@@ -436,41 +474,32 @@ export default {
async handleChange(e) {
try {
clearTimeout(this.timer)
- // const [file] = e.target.files
- // console.log('file', file)
- const fileReader = new FileReader()
- fileReader.readAsArrayBuffer(this.toFile)
- fileReader.onload = () => {
- this.src = fileReader.result
- }
+ // 直接用 readBuffer 读取 Blob,不再用 FileReader 重复读取同一文件
const arrayBuffer = await readBuffer(this.toFile)
this.last = await this.displayResult(arrayBuffer, this.toFile)
this.$nextTick(() => {
- // 取得扩展名
const extend = getExtend(this.toFile.name)
- // 加水印
- const maskDiv = document.getElementsByClassName('mask_div')
- const imgMaskDiv = document.getElementsByClassName('weterbox')
-
- if (imgMaskDiv.length === 1) {
- document.getElementsByClassName('water-mask')[0].removeChild(imgMaskDiv[0])
- }
- // docx-wrapper docx
- for (var j = maskDiv.length - 1; j >= 0; j--) {
- document.getElementsByClassName('water-mask')[0].removeChild(maskDiv[j])
+ // 切换文件时清除所有外部水印层(DOM + canvas),避免 PDF 与非 PDF 切换时水印残留
+ const container = document.getElementsByClassName('water-mask')[0]
+ if (container) {
+ container.querySelectorAll('.mask_div, .weterbox, canvas.wm-canvas').forEach(el => el.remove())
}
if (!extend.includes('pdf')) {
+ // 非 PDF:重新渲染外部水印并启动防篡改守卫
this.getWatermark()
+ } else {
+ // PDF 自带水印,停掉外部水印守卫,避免守卫把已清除的水印又恢复
+ this.stopWatermarkGuard()
}
})
} catch (e) {
console.error(e)
+ this.$message.error('文件预览失败')
} finally {
- this.timer = setTimeout(() => {
- this.loading = false
- }, 1000)
+ // 渲染完成即关闭 loading,不再固定等 1 秒
+ this.loading = false
}
},
displayResult(buffer, file) {
diff --git a/src/views/system/fileLibraryManage/processManage/index-old.vue b/src/views/system/fileLibraryManage/processManage/index-old.vue
new file mode 100644
index 0000000..419b41f
--- /dev/null
+++ b/src/views/system/fileLibraryManage/processManage/index-old.vue
@@ -0,0 +1,167 @@
+
+
+
+
{{ item.name }}
+
{{ item.flowName }}
+
+
+
+
+
+
+
+
+