1、安装插件
npm i vue-ele-sign
2、封装sign.vue
组件
<template>
<van-action-sheet v-model:show="show" :title="!showBig ? '签名' : ''" :class="showBig ? 'aa' : ''">
<div class="big" v-if="!showBig">
<div class="tips1"><van-icon name="warning" class="tips1-icon"/>使用正楷在框内签署您的名字即可完成签字</div>
<div class="tips2">{{`请在下面签字`}}</div>
<vue-ele-sign ref="VueEleSign" color="#000000" :lineWidth="8" class="xxx" />
<div class="clear_box">
<img src="@/assets/images/clear.png" @click="clearIt" class="clear_icon" alt="" />
</div>
<img src="@/assets/images/big.png" @click="bigIt" class="bigit" alt="" />
<div class="button_list">
<div class="cancel" @click="cancelIt">返回</div>
<div class="ok" @click="sureIt">确认签署</div>
</div>
</div>
<div class="all_big" v-else>
<vue-ele-sign ref="VueEleSignBig" color="#000000" :lineWidth="8" class="all_big" />
<img src="@/assets/images/clear.png" @click="clearBigIt" class="clear_icon_big" alt="" />
<div class="big_list">
<div class="cancel" @click="cancelIt">返回</div>
<div class="ok" @click="sureIt1">确认签署</div>
</div>
</div>
</van-action-sheet>
</template>
<script>
import VueEleSign from 'vue-ele-sign'
import { uploadBase64 } from '@/api/user.js'
export default {
props: {
signItem: {
type: Object,
default: () => {}
}
},
data() {
return {
show: false,
showBig: false,
bindPrintValue: ''
}
},
components: {
VueEleSign
},
mounted() {
},
methods: {
bigIt() {
this.showBig = true
},
showIt() {
this.show = true
this.showBig = false
this.clearIt()
},
clearIt() {
this.$refs.VueEleSign && this.$refs.VueEleSign.clear()
},
clearBigIt() {
this.$refs.VueEleSignBig && this.$refs.VueEleSignBig.clear()
},
cancelIt() {
this.show = false
},
sureIt() {
if (this.$refs.VueEleSign.isEmpty()) {
this.$Toast({
message: '请签名'
})
} else {
const data = this.$refs.VueEleSign.toPng()
const base64String = data.replace('data:image/png;base64,', '')
uploadBase64({
base64String,
fileName: new Date().getTime() + '.png'
}).then(res => {
const sendData = {
signCode: this.signItem.code,
bindValue: res.data,
showImgValue: data
}
if (this.signItem.type === 'SignatureDate') {
sendData.signDateTime = new Date().getTime()
sendData.type = this.signItem.type
sendData.signatureType = this.signItem.signatureType
}
this.$emit('signOk', sendData)
})
this.cancelIt()
}
},
sureIt1() {
if (this.$refs.VueEleSignBig.isEmpty()) {
this.$Toast({
message: '请签名'
})
} else {
const data = this.$refs.VueEleSignBig.toPng()
this.rotateBase64Img(data, 270, re => {
const base64String = re.replace('data:image/png;base64,', '')
uploadBase64({
base64String,
fileName: new Date().getTime() + '.png'
}).then(res => {
const sendData = {
signCode: this.signItem.code,
bindValue: res.data,
showImgValue: data
}
if (this.signItem.type === 'SignatureDate') {
sendData.signDateTime = new Date().getTime()
sendData.type = this.signItem.type
sendData.signatureType = this.signItem.signatureType
}
this.$emit('signOk', sendData)
})
this.cancelIt()
})
}
},
rotateBase64Img(src, edg, callback) {
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
var imgW // 图片宽度
var imgH // 图片高度
var size // canvas初始大小
if (edg % 90 != 0) {
console.error('旋转角度必须是90的倍数!')
throw '旋转角度必须是90的倍数!'
}
edg < 0 && (edg = (edg % 360) + 360)
const quadrant = (edg / 90) % 4 // 旋转象限
const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 } // 裁剪坐标
var image = new Image()
image.crossOrigin = 'anonymous'
image.src = src
image.onload = function() {
imgW = image.width
imgH = image.height
size = imgW > imgH ? imgW : imgH
canvas.width = size * 2
canvas.height = size * 2
switch (quadrant) {
case 0:
cutCoor.sx = size
cutCoor.sy = size
cutCoor.ex = size + imgW
cutCoor.ey = size + imgH
break
case 1:
cutCoor.sx = size - imgH
cutCoor.sy = size
cutCoor.ex = size
cutCoor.ey = size + imgW
break
case 2:
cutCoor.sx = size - imgW
cutCoor.sy = size - imgH
cutCoor.ex = size
cutCoor.ey = size
break
case 3:
cutCoor.sx = size
cutCoor.sy = size - imgW
cutCoor.ex = size + imgH
cutCoor.ey = size + imgW
break
}
ctx.translate(size, size)
ctx.rotate((edg * Math.PI) / 180)
ctx.drawImage(image, 0, 0)
var imgData = ctx.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey)
if (quadrant % 2 == 0) {
canvas.width = imgW
canvas.height = imgH
} else {
canvas.width = imgH
canvas.height = imgW
}
ctx.putImageData(imgData, 0, 0)
callback(canvas.toDataURL())
}
}
}
}
</script>
<style lang="scss" scoped>
.xxx {
width: 100%;
height: 300px;
background: #f1f1f1;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.big {
width: 100%;
height: 500px;
position: relative;
.tips1{
color:#4284F5;
font-size: 12px;
margin-bottom:8px;
font-family:'PingFangSC-Regular';
padding-left:16px;
.tips1-icon{
margin-right:6px;
}
}
.tips2{
color:#323233;
font-size: 14px;
font-family:'PingFang SC';
padding-left:16px;
}
}
.bigit {
position: absolute;
right: 20px;
top: 65px;
z-index: 888888;
height: 16px;
width: 16px;
}
.button_list {
display: flex;
position: fixed;
bottom: 50px;
width: 100%;
left: 50%;
transform: translateX(-50%);
padding: 0 16px;
box-sizing: border-box;
align-items: center;
justify-content: space-between;
.cancel {
border-radius: 20px;
margin-right: 5px;
height: 40px;
flex: 1;
background: #f1f1f1;
border: 1px solid #fda21d;
display: flex;
align-items: center;
justify-content: center;
font-family: 'PingFangSC-Regular';
font-weight: 400;
font-size: 14px;
line-height: 20px;
text-align: center;
color: #fda21d;
}
.ok {
flex: 1;
border-radius: 20px;
margin-left: 5px;
height: 40px;
background: #fda21d;
display: flex;
align-items: center;
justify-content: center;
font-family: 'PingFangSC-Regular';
font-weight: 400;
font-size: 14px;
line-height: 20px;
text-align: center;
color: #fff;
}
}
.clear_box {
display: flex;
width: 100%;
justify-content: flex-end;
.clear_icon {
height: 30px;
width: 30px;
margin: 10px 30px 0 0;
}
}
.all_big {
height: 100vh;
width: 100%;
background: #f1f1f1;
position: relative;
}
.aa {
height: 100%;
max-height: 100%;
border-radius: 0;
}
.big_list {
transform: rotate(90deg);
position: absolute;
left: -100px;
width: 300px;
height: 40px;
top: 50%;
display: flex;
.cancel {
border-radius: 20px;
margin-right: 5px;
height: 40px;
flex: 1;
background: #f1f1f1;
border: 1px solid #fda21d;
display: flex;
align-items: center;
justify-content: center;
font-family: 'PingFangSC-Regular';
font-weight: 400;
font-size: 14px;
line-height: 20px;
text-align: center;
color: #fda21d;
}
.ok {
flex: 1;
border-radius: 20px;
margin-left: 5px;
height: 40px;
background: #fda21d;
display: flex;
align-items: center;
justify-content: center;
font-family: 'PingFangSC-Regular';
font-weight: 400;
font-size: 14px;
line-height: 20px;
text-align: center;
color: #fff;
}
}
.clear_icon_big {
position: absolute;
height: 30px;
width: 30px;
right: 20px;
bottom: 20px;
transform: rotate(90deg);
}
</style>
3、使用
<template>
<!-- 电子签名 -->
<sign ref="sign" :signItem="signItem" @signOk="signOk"></sign>
</template>
<script>
import sign from '@/components/sign.vue'
data(){
return{
signItem:{}
}
},
methods:{
// 签名
handleSignature(item)
this.signItem = item
this.$refs.sign.showIt()
},
signOk(obj) {
//返回数据obj
}
}
</script>