实现原理)

通过拖拽功能实现 (主要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. 交通运输部部长李小鹏谈及自动驾驶:包容失败、反对垄断,力争在国家层面出台指导意见...
  2. 解析软件测试需要变革的因素
  3. python列表推导式_聊一聊:python的各种推导式(列表推导式、字典推导式、集合推导式)...
  4. Winform巧用窗体设计完成弹窗数值绑定-以重命名弹窗为例
  5. self-在类的外部给对象增加属性
  6. Leetcode47: Palindrome Linked List
  7. 深入进货单-价格跟踪----宇然电脑公司管理软件
  8. 查找占用内存最大进程所在路径命令
  9. java iqq_Linux开源QQ 2012(iQQ)
  10. watson机器人_使您的聊天机器人看起来更加智能! Watson Assistant的隐藏功能。
  11. 股票开户天载钢铁等板块跌幅居前
  12. IDEA启动Tomcat中文乱码(已解决)
  13. pytorch_预训练Se_resnet50_自定义类别数量_源码分享
  14. 2021全国省市区街道社区五级SQL文件以及JAVA爬取代码
  15. 饿了么建生鲜开放平台 买菜业务要推至全国500城
  16. Centos6.10系统迁移到新固态硬盘LVM
  17. oracle order by 排序之降序 null 排最后
  18. JS 对象直接量方法创建对象
  19. 使用Python对一张图像进行高斯模糊
  20. 一个tesseract ocr box 文件查看toy,python

热门文章

  1. MySQL中的大小写切换
  2. 从电竞练习生到B站UP主,年轻一代的AI生活
  3. 服务器配置DNS辅助区域出错
  4. 新买的笔记本电脑怎么分盘_为什么许多手机厂商开始做笔记本电脑,真有这么大的市场前景?|手机|笔记本|电脑|笔记本电脑...
  5. iPhone如何添加邮箱
  6. 程序员,男,工作7年,android语音通话开发
  7. 【木马】暗云系列木马
  8. (附源码)计算机毕业设计SSM化妆品网上商城数据分析系统
  9. java单例弊端,博客大牛总结的Java单例写法的优缺点及使用场景
  10. 关键词权重推送,权重推送接口,权重推送是什么,关键词权重推送的接口,手淘足迹接口,直通车接口,卡首屏升级版,打标和权重推送的区别