|
|
@ -118,7 +118,11 @@ export default { |
|
|
fileCurrent: null, |
|
|
fileCurrent: null, |
|
|
fileParentInfo: null, |
|
|
fileParentInfo: null, |
|
|
pdfsArray: [], |
|
|
pdfsArray: [], |
|
|
documentId: null |
|
|
|
|
|
|
|
|
documentId: null, |
|
|
|
|
|
// 水印防篡改:MutationObserver + 定时兜底 |
|
|
|
|
|
watermarkObserver: null, |
|
|
|
|
|
watermarkTimer: null, |
|
|
|
|
|
watermarkRerenderLock: false |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
computed: { |
|
|
computed: { |
|
|
@ -160,6 +164,9 @@ export default { |
|
|
} |
|
|
} |
|
|
this.getBase64ByFileId() |
|
|
this.getBase64ByFileId() |
|
|
}, |
|
|
}, |
|
|
|
|
|
beforeDestroy() { |
|
|
|
|
|
this.stopWatermarkGuard() |
|
|
|
|
|
}, |
|
|
methods: { |
|
|
methods: { |
|
|
getFileSize(fileSize) { |
|
|
getFileSize(fileSize) { |
|
|
// 1. 先将接口返回的KB值转为数字,处理非数字/空值情况 |
|
|
// 1. 先将接口返回的KB值转为数字,处理非数字/空值情况 |
|
|
@ -240,7 +247,6 @@ export default { |
|
|
'bucketType': 2 |
|
|
'bucketType': 2 |
|
|
} |
|
|
} |
|
|
FetchMinioReDocumentBase64ByFileId(params).then(res => { |
|
|
FetchMinioReDocumentBase64ByFileId(params).then(res => { |
|
|
console.log('res', res) |
|
|
|
|
|
var base64String = res |
|
|
var base64String = res |
|
|
var fileName = this.fileCurrent && this.fileCurrent.file_name |
|
|
var fileName = this.fileCurrent && this.fileCurrent.file_name |
|
|
var mimeType = this.fileCurrent && this.fileCurrent.file_type |
|
|
var mimeType = this.fileCurrent && this.fileCurrent.file_type |
|
|
@ -284,39 +290,149 @@ export default { |
|
|
}) |
|
|
}) |
|
|
}, |
|
|
}, |
|
|
getWatermark() { |
|
|
getWatermark() { |
|
|
getInitWatermark().then((res) => { |
|
|
|
|
|
|
|
|
return getInitWatermark().then((res) => { |
|
|
this.watermarkInfo = res |
|
|
this.watermarkInfo = res |
|
|
// this.isEnable = this.watermarkInfo.isEnable |
|
|
|
|
|
|
|
|
|
|
|
if (res.watermarkType === '1') { |
|
|
if (res.watermarkType === '1') { |
|
|
watermark({ |
|
|
watermark({ |
|
|
watermark_txt: this.watermarkInfo.context, |
|
|
watermark_txt: this.watermarkInfo.context, |
|
|
watermark_alpha: parseFloat(this.watermarkInfo.transparency) / 100 |
|
|
watermark_alpha: parseFloat(this.watermarkInfo.transparency) / 100 |
|
|
}, 'water-mask', 'img') |
|
|
}, 'water-mask', 'img') |
|
|
} else if (res.watermarkType === '0') { |
|
|
} else if (res.watermarkType === '0') { |
|
|
// if (parent.length > 0) { |
|
|
|
|
|
// for (let i = 0; i < parent.length; i++) { |
|
|
|
|
|
// const childImg = parent[i].getElementsByClassName('weterbox') |
|
|
|
|
|
// if (childImg.length > 0) { |
|
|
|
|
|
// for (let i = 0; i < childImg.length; i++) { |
|
|
|
|
|
// parent[i].removeChild(childImg[i]) |
|
|
|
|
|
// } |
|
|
|
|
|
// } |
|
|
|
|
|
// } |
|
|
|
|
|
// } |
|
|
|
|
|
watermark({ |
|
|
watermark({ |
|
|
watermark_txt: this.watermarkInfo.context, |
|
|
watermark_txt: this.watermarkInfo.context, |
|
|
watermark_color: this.watermarkInfo.transparency, |
|
|
watermark_color: this.watermarkInfo.transparency, |
|
|
watermark_fontsize: this.watermarkInfo.watermarkFont + 'px' |
|
|
watermark_fontsize: this.watermarkInfo.watermarkFont + 'px' |
|
|
}, 'water-mask', 'text') |
|
|
}, 'water-mask', 'text') |
|
|
|
|
|
// 第二层:canvas 水印,独立于 DOM 水印,增加绕过难度 |
|
|
|
|
|
this.drawCanvasWatermark() |
|
|
} |
|
|
} |
|
|
if (document.getElementById('error-tip')) { |
|
|
if (document.getElementById('error-tip')) { |
|
|
document.getElementsByClassName('water-mask')[0].innerHTML = '' |
|
|
document.getElementsByClassName('water-mask')[0].innerHTML = '' |
|
|
} |
|
|
} |
|
|
|
|
|
// 首次渲染后启动防篡改守卫(幂等:已存在则不重复启动) |
|
|
|
|
|
if (!this.watermarkObserver) { |
|
|
|
|
|
this.startWatermarkGuard() |
|
|
|
|
|
} |
|
|
}).catch(err => { |
|
|
}).catch(err => { |
|
|
console.log(err) |
|
|
console.log(err) |
|
|
}) |
|
|
}) |
|
|
}, |
|
|
}, |
|
|
|
|
|
// canvas 层水印:用 canvas API 平铺绘制,与 DOM 水印独立,用户需同时隐藏两层 |
|
|
|
|
|
drawCanvasWatermark() { |
|
|
|
|
|
if (!this.watermarkInfo) return |
|
|
|
|
|
const container = document.querySelector('.water-mask') |
|
|
|
|
|
if (!container) return |
|
|
|
|
|
const oldCanvas = container.querySelector('canvas.wm-canvas') |
|
|
|
|
|
if (oldCanvas) oldCanvas.remove() |
|
|
|
|
|
const txt = this.watermarkInfo.context || '' |
|
|
|
|
|
if (!txt) return |
|
|
|
|
|
const canvas = document.createElement('canvas') |
|
|
|
|
|
canvas.className = 'wm-canvas' |
|
|
|
|
|
canvas.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:1;' |
|
|
|
|
|
container.appendChild(canvas) |
|
|
|
|
|
const dpr = window.devicePixelRatio || 1 |
|
|
|
|
|
const rect = container.getBoundingClientRect() |
|
|
|
|
|
if (rect.width === 0 || rect.height === 0) return |
|
|
|
|
|
canvas.width = rect.width * dpr |
|
|
|
|
|
canvas.height = rect.height * dpr |
|
|
|
|
|
const ctx = canvas.getContext('2d') |
|
|
|
|
|
ctx.scale(dpr, dpr) |
|
|
|
|
|
ctx.font = `${this.watermarkInfo.watermarkFont || 15}px 微软雅黑` |
|
|
|
|
|
ctx.fillStyle = this.watermarkInfo.watermarkType === '0' ? (this.watermarkInfo.transparency || '#000') : '#000' |
|
|
|
|
|
ctx.globalAlpha = 0.12 |
|
|
|
|
|
ctx.textAlign = 'center' |
|
|
|
|
|
ctx.textBaseline = 'middle' |
|
|
|
|
|
const stepX = 180 |
|
|
|
|
|
const stepY = 120 |
|
|
|
|
|
for (let y = -stepY; y < rect.height + stepY; y += stepY) { |
|
|
|
|
|
for (let x = -stepX; x < rect.width + stepX; x += stepX) { |
|
|
|
|
|
ctx.save() |
|
|
|
|
|
ctx.translate(x, y) |
|
|
|
|
|
ctx.rotate(-15 * Math.PI / 180) |
|
|
|
|
|
ctx.fillText(txt, 0, 0) |
|
|
|
|
|
ctx.restore() |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
// 启动防篡改守卫:MutationObserver 监听 DOM 篡改 + 定时兜底检查 |
|
|
|
|
|
startWatermarkGuard() { |
|
|
|
|
|
this.stopWatermarkGuard() |
|
|
|
|
|
const container = document.querySelector('.water-mask') |
|
|
|
|
|
if (!container) return |
|
|
|
|
|
this.watermarkObserver = new MutationObserver((mutations) => { |
|
|
|
|
|
if (this.watermarkRerenderLock) return |
|
|
|
|
|
let needRerender = false |
|
|
|
|
|
for (const m of mutations) { |
|
|
|
|
|
if (m.type === 'childList' && m.removedNodes.length > 0) { |
|
|
|
|
|
needRerender = true |
|
|
|
|
|
break |
|
|
|
|
|
} |
|
|
|
|
|
if (m.type === 'attributes' && m.target && m.target.style) { |
|
|
|
|
|
const s = m.target.style |
|
|
|
|
|
if (s.display === 'none' || s.visibility === 'hidden' || parseFloat(s.opacity) === 0) { |
|
|
|
|
|
needRerender = true |
|
|
|
|
|
break |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (needRerender) this.rerenderWatermark() |
|
|
|
|
|
}) |
|
|
|
|
|
this.watermarkObserver.observe(container, { |
|
|
|
|
|
childList: true, |
|
|
|
|
|
subtree: true, |
|
|
|
|
|
attributes: true, |
|
|
|
|
|
attributeFilter: ['style', 'class'] |
|
|
|
|
|
}) |
|
|
|
|
|
// 定时兜底:observer 监听不到容器自身被隐藏的情况,用定时器补位 |
|
|
|
|
|
this.watermarkTimer = setInterval(() => { |
|
|
|
|
|
this.checkWatermarkAlive() |
|
|
|
|
|
}, 2000) |
|
|
|
|
|
}, |
|
|
|
|
|
stopWatermarkGuard() { |
|
|
|
|
|
if (this.watermarkObserver) { |
|
|
|
|
|
this.watermarkObserver.disconnect() |
|
|
|
|
|
this.watermarkObserver = null |
|
|
|
|
|
} |
|
|
|
|
|
if (this.watermarkTimer) { |
|
|
|
|
|
clearInterval(this.watermarkTimer) |
|
|
|
|
|
this.watermarkTimer = null |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
// 定时检查:容器或水印元素被隐藏/删除时重新渲染 |
|
|
|
|
|
checkWatermarkAlive() { |
|
|
|
|
|
if (this.watermarkRerenderLock) return |
|
|
|
|
|
const container = document.querySelector('.water-mask') |
|
|
|
|
|
if (!container) return |
|
|
|
|
|
const cs = getComputedStyle(container) |
|
|
|
|
|
if (cs.display === 'none' || cs.visibility === 'hidden' || parseFloat(cs.opacity) === 0) { |
|
|
|
|
|
// 容器被隐藏:强制恢复显示再重渲染 |
|
|
|
|
|
container.style.setProperty('display', 'block', 'important') |
|
|
|
|
|
this.rerenderWatermark() |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
const masks = container.querySelectorAll('.mask_div, .weterbox, canvas.wm-canvas') |
|
|
|
|
|
if (masks.length === 0) { |
|
|
|
|
|
this.rerenderWatermark() |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
// 重新渲染水印(断开 observer 避免重入,渲染完再接回) |
|
|
|
|
|
rerenderWatermark() { |
|
|
|
|
|
if (this.watermarkRerenderLock) return |
|
|
|
|
|
this.watermarkRerenderLock = true |
|
|
|
|
|
if (this.watermarkObserver) this.watermarkObserver.disconnect() |
|
|
|
|
|
this.getWatermark().then(() => { |
|
|
|
|
|
const container = document.querySelector('.water-mask') |
|
|
|
|
|
if (container && this.watermarkObserver) { |
|
|
|
|
|
this.watermarkObserver.observe(container, { |
|
|
|
|
|
childList: true, |
|
|
|
|
|
subtree: true, |
|
|
|
|
|
attributes: true, |
|
|
|
|
|
attributeFilter: ['style', 'class'] |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
this.watermarkRerenderLock = false |
|
|
|
|
|
}) |
|
|
|
|
|
}, |
|
|
async handleChange(e) { |
|
|
async handleChange(e) { |
|
|
try { |
|
|
try { |
|
|
clearTimeout(this.timer) |
|
|
clearTimeout(this.timer) |
|
|
|