实现原理)

通过拖拽功能实现 (主要vue代码,通过后台将pdf转换 统一格式的图片,前端分页 再不同页面添加签章。)

签章 使用 draggable="true" @dragstart="drag($event)"

签章容器 使用

@drop="drop($event, docindex+1)" @dragover="allowDrop($event)"

本源码实现是pdf   分页签章功能,  计算单位是磅。

pt_y: 842, // pdf 的磅宽

pt_x: 595, // pdf 的磅高      此为基础

优势特点

签章不会出现夸页面问题。

响应式开发,适用于不同屏幕尺寸  (pc 端为主。移动端设备效果不佳)


代码如下  (附带了滚动分页功能)

<template><Row class="treaty"><i-col span="3" class="pageList"><p class="pageTitle">页码切换</p><div ref="pagePanel" class="pagePanel"><div v-for="(item, index) in imgList" :key="index" class="item" :class="{on: index == selectPage }" @click="selectItem(index)"><img :src="`data:image/png;base64,${item.url}`"><p>{{ index+1 }}</p></div></div></i-col><i-col span="17"><div ref="docContainer" class="imgListpanel"><div class="imgpanel"><div v-for="(docItem, docindex) in imgList" :key="docindex" ref="docItem" class="imgList" @drop="drop($event, docindex+1)" @dragover="allowDrop($event)"><img :src="`data:image/png;base64,${docItem.url}`"></div></div></div></i-col><i-col span="4"><div class="rightPanel"><div class="item"><p class="title">发起人</p><p>{{ initiatorLoginName }}<span class="on">{{ contractStatus(contractDetail.status) }}</span></p></div><active v-if="contractDetail.contractType === '01'"><div class="item"><p class="title">签署人</p><div v-for="(singItem, index) in signPersonList" :key="index"><p>{{ singItem.participantLoginName }}<span :class="{on: singItem.operationResult === '01' }">{{ singItem.operationResult ? operationResultStatus[singItem.operationResult] : '未签署' }}</span></p><p>{{ signPersonList[index].instName }}</p><p class="line" /></div></div><div v-if="optype === 'sign'" class="item"><p class="title">签章</p><div v-if="signStr"><p class="fic">拖拽签章到合同中</p><div class="dropDom" draggable="true" @dragstart="drag($event)"><img :src="`data:image/png;base64,${signStr}`"><span><Icon type="close-circled" style="cursor: pointer;" /></span></div></div><div v-else style="text-align: center;"><p class="fic">暂无签章,请先上传</p><Button type="ghost" @click="toSignatureManege">立即上传</Button></div></div></active></div></i-col></Row>
</template>
<script>
import tool from '@/utils/tool'let dom = null
export default {name: 'TreatyContentPreview',directives: {drag (el) {el.onmousedown = (e) => {let disx = e.pageX - el.offsetLeftlet disy = e.pageY - el.offsetTope.preventDefault()document.onmousemove = (e) => {el.style.left = e.pageX - disx + 'px'el.style.top = e.pageY - disy + 'px'e.preventDefault()}document.onmouseup = () => {document.onmousemove = document.onmouseup = null}}}},props: {imgList: {type: Array,default: () => { return [] }},optype: {type: String,default: ''},initiatorLoginName: {type: String,default: ''},signStr: {type: String,default: ''},contractDetail: {type: Array,default: () => { return {} }},signPersonList: {type: Array,default: () => { return [] }}},data () {return {selectPage: 0,mouseInSealX: 0,mouseInSealY: 0,operationResultStatus: {'01': '已签署','02': '拒签','03': '已撤销'},sealWidth: 0,sealHeight: 0,pt_y: 842, // pdf 的磅宽pt_x: 595, // pdf 的磅高signaturelocation: null}},computed: {docWidth () {return this.$refs.docItem[0].offsetWidth},docHeight () {return this.$refs.docItem[0].offsetHeight},naturalWidth () {return this.$refs.docItem[0].children[0].naturalWidth},naturalHeight () {return this.$refs.docItem[0].children[0].naturalHeight}},watch: {selectPage (oldVal, newVal) {console.log(oldVal + 'qss' + newVal)}},activated () {this.sealWidth = 0dom = null// 监听这个dom的scroll事件this.$refs.docContainer.addEventListener('scroll', () => {let step = this.$refs.docContainer.scrollHeight / this.imgList.lengthlet scrollTop = this.$refs.docContainer.scrollTopif (Math.round(scrollTop / step) < this.imgList.length) {this.selectPage = Math.round(scrollTop / step)}let pageStep = this.$refs.pagePanel.scrollHeight / this.imgList.lengththis.$refs.pagePanel.scrollTop = pageStep * this.selectPage}, false)},beforeDestroy () {this.sealWidth = 0dom = null},methods: {contractStatus (status) {let statusText = {'01': '草稿','02': '用印中','03': '签约完成','04': '拒签','05': '已撤销','06': '已过期','07': '文件归档','08': '文件作废'}let returnList = ['02', '05', '07', '08']if (returnList.indexOf(status) !== -1) {// 电子签约if (status === '05') {return '已撤销'}if (this.contractDetail.contractType === '01') {return ''}return statusText[status]} else {return ''}},removeElement (_element) {let _parentElement = _element.parentNodeif (_parentElement) {_parentElement.removeChild(_element)}},toSignatureManege () {this.$router.push({ path: '/account/signatureManege', query: { backPath: '/contract/list', menuName: 'SignatureManege' } })},iconClick () {if (dom) {// dom.remove()this.removeElement(dom)dom = nullthis.signaturelocation = null}},drag (event) {if (dom) {// dom.remove()this.removeElement(dom)dom = nullthis.signaturelocation = null}let scale = this.naturalWidth / this.docHeightdom = event.currentTarget.cloneNode(true)this.mouseInSealX = event.offsetXthis.mouseInSealY = event.offsetYthis.sealWidth = event.currentTarget.offsetWidth / scalethis.sealHeight = event.currentTarget.offsetHeight / scale// 30 和 50 是 外框边距。用于删除this.sealWidth = dom.children[0].naturalWidth / scale + 50this.sealHeight = dom.children[0].naturalHeight / scale + 30},drop (event, index) {if (this.optype !== 'sign') {return false}event.preventDefault()let target = event.currentTarget// let docWidth = this.$refs.docItem.offsetWidth// docOffsetLeft 文档到docment的offsetLeftlet docOffsetLeft = tool.getPos(target).leftlet docOffsetTop = tool.getPos(target).toplet scrollTop = this.$refs.docContainer.scrollTop// inDocLeft 签章在doc中的leftlet inDocLeft = event.clientX - docOffsetLeft - this.mouseInSealX// inDocTop 签章在doc中的toplet inDocTop = event.clientY - (docOffsetTop - scrollTop) - this.mouseInSealYdom.style.position = 'absolute'dom.style.left = inDocLeft + 'px'dom.style.top = inDocTop + 'px'dom.children[1].style.display = 'block'dom.style.width = this.sealWidth + 'px'dom.style.height = this.sealHeight + 'px'// 以当前页面左下角位原点 ,取 左下角 (offsetX,offsetY) 右上角 (locationX,locationY)let offsetX = inDocLeftlet offsetY = this.docHeight - (inDocTop + this.sealHeight)console.log('(' + offsetX + ',' + offsetY + ')')// 30 和 50 是 外框边距this.signaturelocation = {locationX: ((offsetX + this.sealWidth - 25) / this.docWidth * this.pt_x).toFixed(0),locationY: ((offsetY + this.sealHeight - 15) / this.docHeight * this.pt_y).toFixed(0),offsetX: ((offsetX + 25) / this.docWidth * this.pt_x).toFixed(0),offsetY: ((offsetY + 15) / this.docHeight * this.pt_y).toFixed(0),signMode: '1',signOnPage: index.toString()}console.log(this.signaturelocation)let isAdd = (this.signaturelocation.locationX <= 0 || this.signaturelocation.locationX >= this.pt_x ||this.signaturelocation.locationY <= 0 || this.signaturelocation.locationY >= this.pt_y ||this.signaturelocation.offsetX <= 0 || this.signaturelocation.offsetX >= this.pt_x ||this.signaturelocation.offsetY <= 0 || this.signaturelocation.offsetY >= this.pt_y)if (isAdd) {this.$Message.error('签章不在合同内部')// dom.remove()this.removeElement(dom)dom = nullreturn false}if (event.target.parentElement && this.sealWidth) {dom.children[1].addEventListener('click', () => {this.iconClick()})event.target.parentElement.appendChild(dom)} else {console.log(event)}},allowDrop (event) {event.preventDefault()},selectItem (index) {this.selectPage = indexlet step = this.$refs.docContainer.scrollHeight / this.imgList.lengththis.$refs.docContainer.scrollTop = index * step},getSubmitData () {let data = {'locationX': '250','locationY': '380','offsetX': '100','offsetY': '250','signMode': '1','signOnPage': '1'}if (data) {return this.signaturelocation}}}
}
</script><style lang='scss' scoped>
.treaty {width:100%;.pageList {padding-top:10px;text-align: center;.pageTitle {text-align: left;border-bottom:1px solid #E3E3E3;display:inline-block;height: 28px;line-height:28px;margin-bottom:10px;width:80px;}.pagePanel {height: calc(100vh - #{$web_header_height} - 176px);text-align: center;overflow: auto;overflow-x: hidden;.item {width: 78px;height: 92px;text-align: center;margin: 0px auto 8px auto;border: 1px solid #EBEBEB;position: relative;img {width: 100%;height: 100%;float:left;}> p {position: absolute;top:73px;left:0;float:left;text-align: center;width:100%;height:18px;font-size: 12px;color: #FFFFFF;letter-spacing: 0;opacity: 0.4;background: #626262;}&.on {border: 1px solid #92D2CC;>p{opacity: 0.5;background: #24A599;}}}}}.imgListpanel{height: calc(100vh - #{$web_header_height} - 132px);text-align:center;overflow:auto;overflow-x:hidden;.imgpanel{width:100%;margin:0 auto}.imgList{display:inline-block;zoom: 1;text-align: center;position: relative;width:100%;float:left;img{width: 100%;height: 100%;float:left;}.dropDom{padding: 15px 25px;background: transparent;border:1px solid #EDEDED;>span{width: 30px;height: 30px;position: absolute;right: -15px;top: -12px;font-size: 16px;}}}}.dropDom{padding: 15px 25px;background:#fff;>span{display:none}}.rightPanel {height: calc(100vh - #{$web_header_height} - 132px);overflow:auto;overflow-x:hidden;padding: 10px 18px;.item {min-height:100px;.title {font-size: 14px;color: #292929;width: 100%;border-bottom: 1px solid #E3E3E3;display: inline-block;height: 30px;line-height:30px;margin-bottom: 10px;}p {font-size: 12px;color: #666666;padding-bottom: 5px;&.fic {color: #999;text-align: center;}}.line{height:10px;border-bottom: 1px solid #E3E3E3;margin-bottom: 10px;}span{font-size: 12px;color:#999;float:right;&.on { color: #4ED5A4; }}}}
}
</style>

vue 开发拖拽签章功能。 主要应用,pdf 合同 盖章, 文件水印, 图文打码相关推荐

  1. java和vue实现拖拽可视化_Vue拖拽组件开发实例详解

    摘要:这篇Vue栏目下的"Vue拖拽组件开发实例详解",介绍的技术点是"Vue拖拽组件开发实例.vue拖拽组件.拖拽组件.组件开发.开发实例.实例详解",希望对 ...

  2. 拖拽功能 php,基于Vue实现拖拽功能

    这篇文章主要为大家详细介绍了Vue实现拖拽功能,拖动方块进行移动,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了Vue实现拖拽功能的具体代码,供大家参考,具体内容如下 效果图: ...

  3. vue 实现文本的拖拽_基于Vue实现拖拽功能

    本文实例为大家分享了Vue实现拖拽功能的具体代码,供大家参考,具体内容如下 效果图: HTML代码: 位置 x:{{val.x}} y:{{val.y}} //注意这里要通过指令绑定函数将当前元素的位 ...

  4. sortable vue 排序_vue 使用 sortable 实现 el-table 拖拽排序功能

    本文给大家介绍vue 使用 sortable 实现 el-table 拖拽排序功能,具体内容如下所示: npm 下载: npm install sortablejs --save 引入: import ...

  5. vue使用高德地图搜索地址添加标记marker,定位,拖拽选址功能

    目录 JSAPI 的加载 使用 JSAPI Loader (推荐) 实现效果: 需求:点击输入框弹窗地图弹窗,输入框输入地址模糊搜索列表结果,点击列表添加相应得marker标记,并且添加标记拖拽选址功 ...

  6. vue 左树右表增加左右拖拽的功能

    左树右表 是后台很常见的功能,当左树内容过长,可能就要考虑到拖拽的功能了 这里简单说一下我的实现思路, <div class='left-tree'> <div>......这 ...

  7. 基于Vue实现拖拽效果以及解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突

    本人在开发中遇到实现一个基于vue的悬浮框拖动效果,经过努力研究最终实现了功能,一下是我的方法和部分代码,希望对您有所帮助,如有不对的地方还请指出.谢谢!下面步入正题: 首先展示一下功能的效果图: 要 ...

  8. vue.js 拖拽排序_快速轻巧的Vue.js拖放可排序库

    vue.js 拖拽排序 vue-smooth-dnd (vue-smooth-dnd) A fast and lightweight drag&drop, sortable library f ...

  9. dialog弹框通过自定义指令实现可拖拽位移功能

    给dialog弹框加上自定义指令,实现可拖拽功能 1.在utils文件夹内新建directives.js文件,代码如下 import Vue from 'vue'// v-dialogDrag: 弹窗 ...

最新文章

  1. Golang 入门系列(十) mysql数据库的使用
  2. 深度学习armv8/armv9 cache的原理
  3. jdbc不能识别别名_Spark基础:读写JDBC
  4. android碎片化的解决方法,解决 Android 设备碎片化--屏幕适配
  5. 计算机网络传输复用技术,计算机网络 23-24 复用技术 数字传输.ppt
  6. 盘点十个最伟大的公式,1+1=2仅排到了第七
  7. Qt文档阅读笔记-QIODevice解析及Audio Example实例解析
  8. 无意间发现BAT大佬总结的一份目标检测、卷积神经网络和OpenCV学习资料(教程/PPT/代码)...
  9. 台达s1变频器参数表_各大品牌变频器万能密码汇总
  10. xtrabackup 排错
  11. pythonspark实践_基于Python的Spark Streaming Kafka编程实践
  12. Taking a serious look at grids
  13. 匹配数据库 帆软 查询条件_帆软报表学习笔记①——根据参数查询
  14. 桌面太单调?一起用Python做个自定义动态壁纸,竟然还可以放视频!
  15. b站服务器崩溃大会员自动续费,[财经]B站因服务器故障赠送用户1天大会员!回应补偿会自动续费会退款 - 南方财富网...
  16. Eureka(eureka)服务集群搭建搭建
  17. Bad man and Bad man
  18. 宽带认证计费系统的认证技术主要有哪些
  19. 产品经理应该知道的产品战略图
  20. [贴装专题] 基于halcon的最小二乘法计算吸嘴或机械轴旋转中心

热门文章

  1. 入坑python第一滴血
  2. 用微信小程序连接WordPress网站
  3. 自媒体去哪里找素材?易撰素材下载工具带你下载素材
  4. 面试技巧--非技术题
  5. ios 跳转苹果wifi页面
  6. greg名字寓意_EA的Greg Rinaldi谈团结
  7. iPhone健康资料删除方法教程
  8. 关于idea的方法注释、类注释、sql注释、修改方法注释纪录
  9. Python序列练习题【第十二周】
  10. 从局部到全局的多模式电影场景分割