小程序 uniapp 实现电子合同签名
签名部分引用的组件 ambler-wxcanvas
签名的放大缩小和旋转引用组件 canvas-drag
实现流程
- 将后端返回的imge图片暂时
- 点击签名用户输入签名
- 将签名返回的图片位置设置完成
- 利用canvas将两张图片合成一张图
html部分
<view class="page-container">
<NavBar center-title="待签署合同"></NavBar>
<view class="body-box">
<view class="header-title">
{{richData.temTitle}}
</view>
<view class="rich-box">
<image id="HTimageInfo" :style="{width:'690rpx',height:(HTimgIngo.height/HTimgIngo.width)*690+'rpx'}"
:src="richData.contractImg">
</image>
</view>
</view>
<canvas canvas-id="shareCanvas" class="canvas" bindlongpress="saveImg" catchtouchmove="true"
:style="{width:HTimgIngo.width+'px',height:HTimgIngo.height+'px',position:'fixed',left:'-9999px'}">
</canvas>
<canvas-drag @clear="getCanvasInfoClear" ref="canvasRef" id="canvas-drag" :graph="graph" :width="690"
:height="(HTimgIngo.height/HTimgIngo.width)*690"
:style="{position:'fixed',left:'30rpx',top:(totalHeight*2+HTImgeTop*2)-20+'rpx'}"
enableUndo="true"></canvas-drag>
<view class="bottom-box">
<view class="bottom-left-box">
<view class="btn-box" @click="toSign">
<view class="btn-box-img">
<text class="iconfont icon-a-Group58197"></text>
</view>
<view class="btn-text">
签字
</view>
</view>
</view>
<view class="bottom-right-box">
<view class="btn-box" v-if="!QMImage">
<view class="btn-text">
请先签字
</view>
</view>
<view class="btn-box-select" v-else @click="exportPost">
<view class="btn-text">
确定签署
</view>
</view>
</view>
</view>
</view>
js部分
<script>
import canvasDrag from "@/components/canvas-drag/index";
export default {
components: {
canvasDrag
},
data() {
return {
statusBarHeight: 0, //状态栏的高度
navigatorHeight: 0, //导航栏高度
totalHeight: 0, //总高度
HTImgeTop: 0,
fromType: 1,
richData: null,
QMImage: '',
HTimgIngo: {
},
ctx: null,
currentSinImgPost: {
x: 10,
y: 10
},
finalImg: ''
}
},
onReady() {
this.ctx = wx.createCanvasContext('shareCanvas')
},
onLoad(params) {
//获取系统信息
uni.getSystemInfo({
success: res => {
this.system = res
}
})
//获取胶囊信息
this.menu = uni.getMenuButtonBoundingClientRect()
//计算组件高度
this.statusBarHeight = this.system.statusBarHeight //状态栏高度
this.navigatorHeight = (this.menu.top - this.system.statusBarHeight) * 2 + this.menu.height //导航栏高度
this.totalHeight = this.statusBarHeight + this.navigatorHeight //总高度
//获取图片距离顶部的距离
let that = this;
const query = uni.createSelectorQuery();
query.select('#HTimageInfo').boundingClientRect();
query.exec(res => {
that.HTImgeTop = res[0].top;
});
uni.$on('QMdata', (res) => {
this.QMImage = res
this.onAddTest()
})
let curtoken = uni.getStorageSync('token')
if (curtoken) {
this.selectHtSignDetail(params.contractId)
} else {
uni.showToast({
title: '请先登录',
icon: 'none'
})
uni.switchTab({
url: '/pages/home/person'
})
}
// params.isShare==1是分享的页面params.isShare==0不是分享的页面
this.isFromShare = params.isShare
if (params.isShare == 1) {
this.$api.updateHtSignStatus({
contractId: params.contractId,
type: 1
}).then((res) => {
if (res.code == 200) {
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
})
} else {
}
},
components: {
TimeFormat
},
methods: {
/**
* 添加签名图片图片
*/
onAddTest() {
this.setData({
graph: {
w: 120,
h: 50,
type: 'image',
url: this.QMImage
}
});
},
//删除签名重新签字
getCanvasInfoClear(data) {
this.QMImage = ''
},
toSign() {
//type==2为我的合同模板详情页面的签署------type==1为用户账号待我签署页面的签署
uni.navigateTo({
url: '/pages/sign/sign?type=' + this.fromType
})
},
//打开签名时间弹窗
openSelectTimeFormat() {
// this.$refs.timeFormat.openPopup()
},
//获取签署日期的格式
getTimeFormat(data) {
console.log(data, "获取日期")
},
selectHtSignDetail(contractId) {
let that = this
this.$api.selectHtSignDetail({
contractId
}).then((res) => {
if (res.code == 200) {
this.richData = res.data
wx.getImageInfo({
src: res.data.contractImg,
success: (res) => {
that.HTimgIngo = res
}
})
}
})
},
//获取图片的基本信息,即将网络图片转成本地图片,
getImageInfo(src) {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src,
success: (res) => resolve(res),
fail: (res) => reject(res)
})
});
},
//合成合同和签名图片
exportPost() {
/**
* 将签名导出
*/
let sinImage = ''
this.$refs.canvasRef.exportFun().then(imgArr => {
console.log(JSON.stringify(imgArr), "生成的签名图片");
sinImage = imgArr
let that = this
uni.showLoading({
title: '生成中'
})
//image是画布的底图
let image = that.richData.contractImg
uni.getSystemInfo({
success: function(res) {
that.windowObj = res
that.windowObj.ratio = that.windowObj.windowWidth /
750 //因为小程序是用rpx单位,为了是后期合成的图片更好是适应各个手机屏幕的尺寸,这里先计算出一个比率,后面除以这个比率就可以对各个手机尺寸进行适配了
that.canvasWidth = that.windowObj.windowWidth / that.windowObj
.ratio //设置画布的宽高
that.canvasHeight = that.windowObj.windowHeight / that.windowObj.ratio
Promise.all([that.getImageInfo(image), that.getImageInfo(sinImage)])
.then(res => {
that.ctx.drawImage(res[0].path, 0, 0, res[0].width, res[0]
.height);
that.ctx.drawImage(res[1].path, 0, 0, res[0].width, res[0]
.height);
that.ctx.draw(false, function() {
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: res[0].width || that.windowObj
.windowWidth,
height: res[0].height || that.windowObj
.windowHeight,
destWidth: res[0].width * 2 || that
.windowObj
.windowWidth *
2, //这里乘以2是为了保证合成图片的清晰度
destHeight: res[0].height * 2 || that
.windowObj
.windowHeight * 2,
canvasId: 'shareCanvas',
fileType: 'png', //设置导出图片的后缀名
quality: 1,
success: function(res) {
uni.hideLoading()
//保存图片到本地
that.finalImg = res
.tempFilePath
console.log(that.finalImg,
"合成后的合同图");
//调用签署接口
that.updateHtSignF()
}
})
});
})
}
})
}).catch(e => {
console.error(e);
uni.showToast({
title: '签名生成失败',
icon: 'none'
})
});
},
updateHtSignF() {
console.log(this)
let _that = this
this.$api.uploadLgImg(this.finalImg).then(resImg => {
// form.value[text + "List"].push(JSON.parse(resImg).data.imgUrl)
this.$api.updateHtSign({
contractId: _that.richData.contractId,
contractImg: JSON.parse(resImg).data.url
}).then((res) => {
if (res.code == 200) {
uni.showToast({
title: '签约成功',
icon: 'none'
})
}
})
})
}
}
}
</script>
实现过程中借鉴了小程序 uniapp 实现pdf 电子合同签名 并导出功能_uniapp pdf转canvas-CSDN博客