123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- import { getArrValue, getRandom, isNullES, isNumber, isString } from 'js-fast-way'
- //PDF签章
- export default class HcPdfSign {
- static iframeDom = null
- static pdfViewer = null
- static signImgCss = {}
- static signType = ''
- static disX = 0
- static disY = 0
- static curSignDom = null
- static signList = []
- static signChange = null
- static pdfLoadFunc = null
- static batchSign = false
- static signNum = 0
- /**
- * 初始化创建PDF预览
- * @param ele 元素的ref,或id值
- * @param url pdf的url
- * @param img 签章图片url
- * @param func 回调函数
- */
- static createPdf({ ele, url, img, change, load }) {
- this.initVarNull()
- //判断参数是否合法
- if (isNullES(ele)) {
- console.warn('请传入参数,必须是,ref的dom元素,或id值')
- return false
- }
- //是否为字符串或数值类型
- let dom = null, errTip = 'ele参数不合法,必须是ref的dom元素,或id值'
- if (isString(ele) || isNumber(ele)) {
- try {
- dom = document.getElementById(ele)
- } catch (e) {
- console.error(errTip)
- return false
- }
- } else {
- try {
- ele.cloneNode(true)
- if (ele.nodeType === 1 || ele.nodeType === 9) {
- dom = ele
- } else {
- console.error(errTip)
- return false
- }
- } catch (e) {
- console.error(errTip)
- return false
- }
- }
- //清空dom
- const children = dom.children
- if (children.length > 0) {
- for (let i = children.length - 1; i >= 0; i--) {
- dom.removeChild(children[i])
- }
- }
- if (isNullES(url)) {
- console.warn('请传入Pdf的url参数')
- return false
- }
- //创建iframe
- const iframe = document.createElement('iframe')
- iframe.setAttribute('id', 'pdf-sign-' + getRandom(6))
- iframe.src = `/plugins/pdfjs/web/viewer.html?file=${url}#zoom=100`
- iframe.style.width = '100%'
- iframe.style.height = '100%'
- iframe.style.border = '1px solid #ccc'
- iframe.name = 'HcPdfSign'
- iframe.addEventListener('load', () => {
- this.iframeLoad()
- })
- dom.appendChild(iframe)
- this.iframeDom = iframe
- //设置签章图片
- if (isNullES(img)) {
- console.warn('请传入签章图片')
- return false
- }
- this.signImage(img)
- //设置回调事件
- if (!isNullES(change)) {
- this.addEventFunc(change)
- }
- //设置回调事件
- if (!isNullES(load)) {
- this.addPdfLoadFunc(load)
- }
- }
- //初始化空值
- static initVarNull() {
- this.iframeDom = null
- this.pdfViewer = null
- this.signImgCss = {}
- this.signType = ''
- this.disX = 0
- this.disY = 0
- this.curSignDom = null
- this.signList = []
- this.signChange = null
- this.pdfLoadFunc = null
- this.batchSign = false
- this.signNum = 0
- }
- //设置回调事件
- static addEventFunc(func) {
- if (typeof func !== 'function') {
- console.warn('请传入函数')
- return false
- } else {
- this.signChange = func
- }
- }
- //触发回调事件
- static signChangeFunc() {
- if (typeof this.signChange !== 'function') {
- return false
- } else {
- this.signChange(this.signList)
- }
- }
- //设置加载完成的回调事件
- static addPdfLoadFunc(func) {
- if (typeof func !== 'function') {
- console.warn('请传入函数')
- return false
- } else {
- this.pdfLoadFunc = func
- }
- }
- //加载完成
- static setPdfLoadFunc(val) {
- if (typeof this.pdfLoadFunc !== 'function') {
- return false
- } else {
- this.pdfLoadFunc(val)
- }
- }
- //设置签章图片
- static signImage(url) {
- this.signImgCss = { url: url, width: 100, height: 26 }
- }
- //创建签章图片
- static async createSignImage(event) {
- //创建图片元素
- const { url, width, height } = this.signImgCss
- const uuid = 'pdf-sign-img-' + getRandom(6)
- const signImg = document.createElement('img')
- signImg.setAttribute('id', uuid)
- signImg.src = url
- signImg.style.position = 'absolute'
- signImg.style.width = width + 'px'
- signImg.style.height = height + 'px'
- signImg.style.left = (event.layerX - (width / 2)) + 'px'
- signImg.style.top = (event.layerY - (height / 2)) + 'px'
- signImg.style.pointerEvents = 'auto'
- signImg.style.zIndex = 999
- return signImg
- }
- /**
- * 是否批量签章
- * @param val true/false
- */
- static setBatchSign(val = false) {
- this.batchSign = val
- }
- //让PDF页面全部渲染一下
- static async setPageScrolling() {
- const pageDom = this.pdfViewer?.children ?? []
- await this.toPdfPage('firstPage')
- for (let i = 0; i < pageDom.length; i++) {
- await this.toPdfPage('next')
- }
- await this.toPdfPage('firstPage')
- }
- /**
- * 跳转pdf的页面
- * @param pageId 最后一页:lastPage,第一页:firstPage,上一页:previous,下一页:next
- */
- static async toPdfPage(pageId) {
- return new Promise((resolve) => {
- this.iframeDom?.contentDocument?.getElementById(pageId)?.click()
- setTimeout(() => {
- resolve(true)
- }, 100)
- })
- }
- //PDF加载完成
- static iframeLoad() {
- const viewer = this.iframeDom?.contentDocument?.getElementById('viewer')
- //页面被点击
- viewer.addEventListener('click', (event) => {
- this.viewerClick(event).then()
- })
- //鼠标移动
- viewer.addEventListener('mousemove', (event) => {
- event.preventDefault()
- if (this.signType !== '移动' || !this.curSignDom) {
- return
- }
- //鼠标位置
- const left = (event.clientX - this.disX) + 'px'
- const top = (event.clientY - this.disY) + 'px'
- this.curSignDom.style.left = left
- this.curSignDom.style.top = top
- //批量处理
- if (this.batchSign) {
- const curDom = this.curSignDom
- let { data: curSign } = this.getSignImgDom(curDom)
- if (!curSign) return
- const newArr = this.signList.filter(item => {
- return item.type === curSign.type
- })
- newArr.forEach(item => {
- item.dom.style.left = left
- item.dom.style.top = top
- })
- }
- })
- //鼠标抬起
- viewer.addEventListener('mouseup', () => {
- if (!this.curSignDom) return
- this.signType = '签名'
- this.curSignDom.style.cursor = 'default'
- const curDom = this.curSignDom
- //获取数据
- let { data: curSign } = this.getSignImgDom(curDom)
- if (!curSign) return
- //计算坐标
- const left = curDom.style.left.replace('px', '')
- const top = curDom.style.top.replace('px', '')
- const { width, height } = this.signImgCss
- const lefts = Number(left) + Number(width / 2)
- const tops = Number(top) + Number(height / 2)
- const lx = ((lefts * 100) / curDom.parentNode.clientWidth).toFixed(4)
- const ly = ((tops * 100) / curDom.parentNode.clientHeight).toFixed(4)
- //批量处理
- if (this.batchSign) {
- const newArr = this.signList.filter(item => {
- return item.type === curSign.type
- })
- newArr.forEach(item => {
- item.lx = lx
- item.ly = ly
- })
- } else {
- curSign.lx = lx
- curSign.ly = ly
- }
- this.signChangeFunc()
- })
- //监听按键
- const container = this.iframeDom?.contentDocument?.getElementById('outerContainer')
- container.addEventListener('keyup', (event) => {
- //删除签章
- if (event.keyCode === 8 && event.key === 'Backspace') {
- const curDom = this.curSignDom
- const { index } = this.getSignImgDom(curDom)
- if (index <= -1) return
- this.delSignImg(index).then()
- }
- })
- this.pdfViewer = viewer
- //处理pdf渲染
- if (this.batchSign) {
- setTimeout(async () => {
- await this.setPageScrolling()
- this.setPdfLoadFunc(true)
- }, 500)
- } else {
- setTimeout(async () => {
- this.setPdfLoadFunc(true)
- }, 100)
- }
- }
- //删除签章
- static async delSignImg(index) {
- if (index <= -1) return
- if (this.batchSign) {
- const list = this.signList, curDom = list[index]
- //倒序删除签章
- for (let i = list.length - 1; i >= 0; i--) {
- if (list[i].type === curDom.type) {
- list[i].dom.remove()
- delete list[i].dom
- list.splice(i, 1)
- }
- }
- this.signList = list
- this.signChangeFunc()
- } else {
- this.signList[index].dom.remove()
- this.signList.splice(index, 1)
- this.signChangeFunc()
- }
- }
- //获取签章图片的数据
- static getSignImgDom(curDom) {
- if (isNullES(curDom)) {
- return { data: null, index: -1 }
- }
- //获取数据
- const id = curDom?.getAttribute('id')
- let curSign = null, index = -1
- for (let i = 0; i < this.signList.length; i++) {
- const item = this.signList[i]
- if (item.id === id) {
- curSign = item
- index = i
- break
- }
- }
- return { data: curSign, index }
- }
- //页面被点击
- static async viewerClick(event) {
- const target = event.target
- //当前为移动模式
- if (this.signType === '移动') {
- return
- }
- //不在PDF页面上点击
- if (target.className !== 'textLayer') {
- return
- }
- //批量签章
- this.signNum ++
- if (this.batchSign) {
- const parent = target?.parentNode?.parentNode?.children ?? []
- for (let i = 0; i < parent.length; i++) {
- await this.setPdfNodeSign(parent[i], parent[i]?.children[1], event)
- }
- this.signChangeFunc()
- } else {
- await this.setPdfNodeSign(target?.parentNode, target, event)
- this.signChangeFunc()
- }
- }
- //设置PDF节点签章
- static async setPdfNodeSign(node, textLayer, event) {
- if (isNullES(node) || isNullES(textLayer) || isNullES(event)) {
- return
- }
- if (node.children.length < 3) {
- node.prepend('<div class="signLayer" style="position: absolute;height: 100%;width: 100%;z-index: 999;pointer-events: none;overflow: hidden"></div>')
- }
- //插入图片
- const signImgDom = await this.createSignImage(event)
- node.children[0].append(signImgDom)
- //鼠标按下
- signImgDom.addEventListener('mousedown', (e) => {
- //新的当前选中项
- this.curSignDom = e.target
- this.signType = '移动'
- e.target.style.cursor = 'move'
- //鼠标相对于图片的位置
- this.disX = e.clientX - e.target.offsetLeft
- this.disY = e.clientY - e.target.offsetTop
- })
- //保存签章信息
- this.signList.push({
- type: this.signNum,
- url: this.signImgCss?.url ?? '',
- page: node.getAttribute('data-page-number'),
- id: signImgDom.getAttribute('id'),
- lx: ((event.layerX * 100) / textLayer.clientWidth).toFixed(4),
- ly: ((event.layerY * 100) / textLayer.clientHeight).toFixed(4),
- dom: signImgDom,
- })
- return signImgDom
- }
- //设置PDF签章图片
- static async setPdfSignImg(arr) {
- const list = getArrValue(arr)
- if (list.length <= 0) return
- const pageDom = this.pdfViewer?.children ?? []
- for (let i = 0; i < list.length; i++) {
- const page = Number(list[i].page) - 1
- const dom = pageDom[page].getElementsByClassName('canvasWrapper')[0]
- //创建图片元素
- const signImg = document.createElement('img')
- signImg.setAttribute('id', list[i].id)
- signImg.src = list[i].url
- signImg.style.position = 'absolute'
- signImg.style.width = list[i].dom.style.width
- signImg.style.height = list[i].dom.style.height
- signImg.style.left = list[i].dom.style.left
- signImg.style.top = list[i].dom.style.top
- signImg.style.pointerEvents = 'auto'
- signImg.style.zIndex = 999
- dom.append(signImg)
- //鼠标按下
- signImg.addEventListener('mousedown', (e) => {
- //新的当前选中项
- this.curSignDom = e.target
- this.signType = '移动'
- e.target.style.cursor = 'move'
- //鼠标相对于图片的位置
- this.disX = e.clientX - e.target.offsetLeft
- this.disY = e.clientY - e.target.offsetTop
- })
- //保存签章信息
- this.signList.push({
- ...list[i],
- dom: signImg,
- })
- }
- }
- }
|