最近项目接到一个新的需求,需要对接一个可以在线签合同的的功能,知道需要后马上开干,经过一番斗争,终于终于下班啦
开个玩笑,废话不多说,直接上代码,因为代码是直接项目中搬出来的,没有依赖其他插件纯手工,小伙伴们要看清除那些是自己需要的,不需要的就删掉啦。

目前只测试小程序 , 其他端需要自己去适配

效果图:

页面有两个,一个表单提交也需要上传身份证正反面,第二个页面有合同展示,签字面板是以弹窗形式

第一个页面(表单也不需要的可以删除):


<template><view><form @submit="formSubmit"><view class="Rboy-box"><view class="Rboy-obverse"><image class="obverseimg" :src="ALMain_drawing" @click="obverse_btn" mode="aspectFill"></image><input style="display: none;" name="ALMain_drawing" /><view class="bottom"><text>身份证正面照</text></view></view><view class="Rboy-reverse"><image class="reverseimg" :src="ALPicture" @click="reverse_btn" mode="aspectFill"></image><input style="display: none;" name="ALPicture" /><view class="bottom"><text>身份证反面照</text></view></view></view><view class="Rboy-form"><view class="Rboy-form-row"><label>姓名</label><view class="form-rowDom"><input placeholder="请输入姓名" disabled name="name":value="RealName.username" /></view></view><view class="Rboy-form-row"><label>身份证号码</label><view class="form-rowDom"><input placeholder="请输入身份证" disabled name="certificates":value="RealName.id_card" /></view></view><view class="Rboy-form-row"><label>电话号码</label><view class="form-rowDom"><input placeholder="请输入电话" disabled name="phone":value="RealName.phone" /></view></view><view class="Rboy-form-row"><label>支付宝账号</label><view class="form-rowDom"><input placeholder="请输入电话" disabled name="phone":value="RealName.alipay" /></view></view></view><view class="agreement"><view class="agreement-row" @click="JumpSee"><view class="agreement-name">《自由职业合作服务协议》</view><view class="agreement-row-label"><text:style="{ color: signStatus === false?'#f97777':'#666' }">{{ signStatus === false ? '去签字':'已签署' }}</text><tui-icon name="arrowright" size="18"></tui-icon></view></view></view><view class="application"><view class="application-tips" @click="readValve"><tui-icon :color=" prevent === 'circle' ?'#999':'#fea12e' " size="14" :name="prevent"></tui-icon><text style="margin-left: 10upx;">我已同意并签署《自由职业合作服务协议》</text></view><button form-type="submit">提交认证</button><!-- <label>提交认证</label> --></view></form></view>
</template>
<script>export default {data() {return {identity: 0, //实名状态  ban:禁止实名 true:成功实名ALMain_drawing: 'https://res.gaaqoo.com/mapp/img/comm/identity_topside.png', //身份默认证正面ALPicture: 'https://res.gaaqoo.com/mapp/img/comm/identity_backside.png', //身份默认证反面     RealName: {Main_drawing: '', //身份证正面Picture: '', //身份证反面    username: '', //姓名id_card: '', //身份证号phone: '', //手机号alipay: '', //支付宝agreement: '' //协议},signStatus: false, //签署状态prevent: 'circle',// InformationRealName:true}},async onLoad() {const t = this;const result = await t.$req('/user/getIdentityInfo', {})let rd = result.data;if (rd.code == 0) {let data = rd.data;t.RealName.username = data.username;t.RealName.id_card = data.id_card;t.RealName.phone = data.phone;t.RealName.alipay = data.alipay;}},onShow() {const t = this;uni.getStorage({key: 'autograph_key',success: function(res) {if (res.data !== '') {t.signStatus = truet.RealName.agreement = res.data}}});},methods: {async obverse_btn() {const t = this;uni.chooseImage({count: 1, //默认9sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有sourceType: ['album'], //从相册选择success: function(res) {let ImgType = res.tempFilePaths[0].split(".")uni.getFileSystemManager().readFile({filePath: res.tempFilePaths[0],encoding: 'base64',success: async (res) => {t.RealName.Main_drawing = 'data:image/png;base64,' + res.data;// t.ALMain_drawing = t.RealName.Main_drawing;uni.showLoading({title: '加载中'});// console.log(res.data)const result = await t.$req("/user/upload/img", {uid: t.user.uid,type: ImgType[1],img: res.data,place: 'identity'})let rd = result.data// console.log(rd)if (rd.code == 0) {let data = rd.datat.ALMain_drawing = data.url;uni.hideLoading();t.RealName.Main_drawing = data.url;}}})}});},async reverse_btn() {const t = this;uni.chooseImage({count: 1, //默认9sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有sourceType: ['album'], //从相册选择success: function(res) {let ImgType = res.tempFilePaths[0].split(".")uni.getFileSystemManager().readFile({filePath: res.tempFilePaths[0],encoding: 'base64',success: async (res) => {t.RealName.Picture = 'data:image/png;base64,' + res.data;uni.showLoading({title: '加载中'});// console.log(res.data)const result = await t.$req("/user/upload/img", {uid: t.user.uid,type: ImgType[1],img: res.data,place: 'identity'})// https://ganqiao-dev.oss-cn-hangzhou.aliyuncs.com 测试环境路径let rd = result.data// console.log(rd)if (rd.code == 0) {let data = rd.datat.ALPicture = data.url;uni.hideLoading();t.RealName.Picture = data.url;}}})}});},readValve() {const t = this;if (t.prevent == "circle") {t.prevent = "circle-fill"} else {t.prevent = "circle"}},JumpSee() {const t = this;uni.navigateTo({url: '/pages/login/seeagreement'})},async formSubmit(e) {const t = this;var formdata = e.detail.valueif (t.RealName.Main_drawing == '') {uni.showToast({title: '请上传身份证正面照',icon: "none",duration: 2000});return false}if (t.RealName.Picture == '') {uni.showToast({title: '请上传身份证反面照',icon: "none",duration: 2000});return false}if (t.RealName.agreement == '') {uni.showToast({title: '请签署《自由职业合作服务协议》',icon: "none",duration: 2000});return false}if (t.prevent == 'circle') {uni.showToast({title: '请同意勾选《自由职业合作服务协议》',icon: "none",duration: 2000});return false}let RealName = t.RealName;const result = await t.$req('/user/ysUpdateIdentity', {topside: RealName.Main_drawing,backside: RealName.Picture,agree: 1,user_sign: RealName.agreement})let rd = result.dataif (rd.code == 0) {let data = rd.data;uni.showToast({title: '提交成功',icon: 'none',default: 200})}}}}
</script>
<style scoped lang="less">
page{background:#fff!important}.Rboy-box{width:100%;display:flex;flex-direction:row;padding:30upx 3%;align-items:center;justify-content:space-between}.Rboy-box,.Rboy-obverse{height:auto;box-sizing:border-box}.Rboy-obverse{width:48%;margin-bottom:0upx;position:relative;box-shadow:0 3px 13px rgba(0,0,0,.05);padding:0}.Rboy-reverse{width:80%;padding:20px 3%}.obverseimg{width:100%;height:240rpx}.bottom{text-align:center;margin:auto}.bottom,.bottom text{width:100%;height:80upx;line-height:80upx}.bottom text{display:block;background:#fff;font-size:14px;color:#777}.Rboy-reverse{width:48%;height:auto;box-sizing:border-box;margin-bottom:0upx;position:relative;box-shadow:0 3px 13px rgba(0,0,0,.05);padding:0}.reverseimg{width:100%;height:240rpx}.application{width:100%;height:auto;display:flex;flex-direction:column;justify-content:center;position:fixed;bottom:20upx;left:0;right:0;padding-bottom:20upx}.application button,.application label{width:90%;height:90upx;line-height:90upx;display:block;margin:auto;text-align:center;background:linear-gradient(180deg,#efc480,#f8dca5 25%,#ffd5a2 98%);border-radius:50px;font-weight:700;font-size:15px;color:#fd972e;box-shadow:0 5px 3px #fdb964}.application button:after{border:none}.Rboy-form{width:94%;height:auto;background:#fff;margin:auto;box-shadow:0 3px 13px rgba(0,0,0,.05;);box-sizing:border-box;padding:0upx 3%}.Rboy-form-row{width:100%;display:flex;flex-direction:row;justify-content:space-between;align-items:center;border-bottom:1px solid #f5f3f3;height:100upx;line-height:100upx}.Rboy-form-row label{width:25%;font-size:14px}.form-rowDom{width:75%}.form-rowDom input{width:100%;font-size:12px}.agreement{width:94%;height:auto;background:#fff;margin:30upx auto;box-shadow:0 3px 13px rgba(0,0,0,.05);box-sizing:border-box;padding:0 3%}.agreement-row{width:100%;height:auto;display:flex;flex-direction:row;justify-content:space-between;align-items:center}.agreement-name{width:70%;height:100upx;line-height:100upx;text-align:left;font-size:14px;color:#2ebbfe}.agreement-row-label{width:30%;height:100upx;line-height:100upx;display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.agreement-row-label text{font-size:12px}.application-tips{width:90%;height:auto;margin:0 auto;line-height:80upx}.application-tips text{color:#999}
</style>

第二个页面:(签名页-请把接口改成自己的 不然容易报错)


<template><view class="content"><view class="authentication_top"><image v-if="PreviewContract" :src="contractImg" mode="widthFix"></image><!-- 创建合成画布 --><view class="bgCoverBox" v-if="publish"><canvas :style="{width:height +'px',height:width +'px'}" canvas-id="mycontract" class="canvsborder2"></canvas></view><!-- 创建合成画布 --></view><view class="authentication_bottom" v-if="NavAutograph" style="background:#ffe9e9" @click="agreeSign"><button style="color:#f00">我已阅读上述内容,同意签字>></button></view><view class="authentication_fun" v-if="Navpreservation" style="background:#fff; "><!-- <button style="color: #1789ff"  @click="preservationImg">保存到本地</button><button style="color: #1789ff"  @click="ReSign">重新签署</button> --><button style="color:#fd972e;"  @click="SigningCompleted">签署完成,去提交>></button></view><!-- 签字弹窗 status --><view class="signMask" v-if="autographStatus"><view class="sigh-btns"><button class="btn" @tap="handleCancel">取消</button><button class="btn" @tap="handleReset">重写</button><button class="btn" @tap="handleConfirm">确认</button></view><view class="sign-box"><canvas class="mycanvas" :style="{width:width +'px',height:height +'px'}" canvas-id="mycanvas"@touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas><canvas canvas-id="camCacnvs" :style="{width:height +'px',height:width +'px'}"class="canvsborder"></canvas></view></view><!-- 签字弹窗 end --></view>
</template>
<script>var x = 20;var y = 20;var tempPoint = []; //用来存放当前画纸上的轨迹点var id = 0;var type = '';let that;let canvasw;let canvash;export default {data() {return {contractImg: '../../static/motu.jpg', //合同路径ctx: '', //绘图图像points: [], //路径点集合,width: 0,height: 0,autographStatus: false,publish: false,PreviewContract:true,NavAutograph: true,Navpreservation:false}},onLoad(option) {that = this;id = option.id;type = option.type;this.ctx = uni.createCanvasContext('mycanvas', this); //创建绘图对象//设置画笔样式this.ctx.lineWidth = 4;this.ctx.lineCap = 'round';this.ctx.lineJoin = 'round';uni.getSystemInfo({success: function(res) {that.width = res.windowWidth * 0.8;that.height = res.windowHeight * 0.85;}});},onShow() {const t = this;uni.getStorage({key: 'autograph_key',success: function (res) {if( res.data !== '' ){t.contractImg = res.datat.PreviewContract = true;t.publish = false;t.NavAutograph = false}}});               },      methods: {agreeSign() {this.autographStatus = true;},//触摸开始,获取到起点touchstart: function(e) {let startX = e.changedTouches[0].x;let startY = e.changedTouches[0].y;let startPoint = {X: startX,Y: startY};/* **************************************************#由于uni对canvas的实现有所不同,这里需要把起点存起来* **************************************************/this.points.push(startPoint);//每次触摸开始,开启新的路径this.ctx.beginPath();},//触摸移动,获取到路径点touchmove: function(e) {let moveX = e.changedTouches[0].x;let moveY = e.changedTouches[0].y;let movePoint = {X: moveX,Y: moveY};this.points.push(movePoint); //存点let len = this.points.length;if (len >= 2) {this.draw(); //绘制路径}tempPoint.push(movePoint);},// 触摸结束,将未绘制的点清空防止对后续路径产生干扰touchend: function() {this.points = [];},/* *********************************************** #   绘制笔迹#   1.为保证笔迹实时显示,必须在移动的同时绘制笔迹#   2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)#   3.将上一次的终点作为下一次绘制的起点(即清除第一个点)************************************************ */draw: function() {let point1 = this.points[0];let point2 = this.points[1];this.points.shift();this.ctx.moveTo(point1.X, point1.Y);this.ctx.lineTo(point2.X, point2.Y);this.ctx.stroke();this.ctx.draw(true);},handleCancel() {uni.navigateBack({delta: 1});},//清空画布handleReset: function() {console.log('handleReset');that.ctx.clearRect(0, 0, that.width, that.height);that.ctx.draw(true);tempPoint = [];},//将签名笔迹上传到服务器,并将返回来的地址存到本地handleConfirm: function() {const t = this;if (tempPoint.length == 0) {uni.showToast({title: '请先签名',icon: 'none',duration: 2000});return;}uni.showLoading({title: '生成中'});uni.canvasToTempFilePath({canvasId: 'mycanvas',success: function(res) {let tempPath = res.tempFilePath;const ctx = uni.createCanvasContext('camCacnvs', that);ctx.translate(0, that.width);ctx.rotate((-90 * Math.PI) / 180);ctx.drawImage(tempPath, 0, 0, that.width, that.height);ctx.draw();setTimeout(() => {//保存签名图片到本地uni.canvasToTempFilePath({canvasId: 'camCacnvs',success: function(res) {//这是签名图片文件的本地临时地址let path = res.tempFilePath;console.log(path, "保存签名图片到本地")t.autographStatus = false// 开始合成var _this = this;t.publish = true;t.PreviewContract = false;t.NavAutograph = false;t.Navpreservation = true;const loy = uni.createCanvasContext('mycontract', this);// loy.clearRect(0, 0, that.width, that.height);// loy.translate(0, 0);// loy.rotate((0 * Math.PI) / 180);let imgGao = ''uni.getSystemInfo({success:function(res){imgGao = res.screenWidth }})loy.drawImage(t.contractImg, 0, 0, 375 , 600);loy.drawImage(path, 260, 500, 100, 50);loy.draw();setTimeout(() =>{uni.canvasToTempFilePath({canvasId: 'mycontract',success: function(res) {uni.hideLoading();t.contractImg = res.tempFilePath;// console.log("合同图片",res.tempFilePath)} })} ,200)// 合成完毕},fail: err => {// console.log('fail', err);}},this);}, 200);}});},preservationImg(){const t = this;uni.downloadFile({url: t.contractImg,success: res => {if (res.statusCode === 200) {uni.saveImageToPhotosAlbum({filePath: res.tempFilePath,success: function() {uni.showToast({title: '保存成功',icon: 'none',duration: 2000});},fail: function() {uni.showToast({title: '保存失败',icon: 'none',duration: 2000});}});} else {uni.showToast({title: '第三方网络错误',icon: 'none',duration: 2000});}}});},SigningCompleted(){const t = this;let ImgType = t.contractImg.split(".")uni.getFileSystemManager().readFile({filePath: t.contractImg,encoding: 'base64',success: async(res) =>{t.contractImg = 'data:image/png;base64,' + res.data;uni.showLoading({title: '提交中'});// console.log(res.data)const result = await t.$req("/user/upload/img",{ uid: t.user.uid,type: ImgType[1],img: res.data,place: 'sign'   })let rd = result.data// console.log(rd)if(rd.code == 0){let data = rd.datat.contractImg = data.url;                               uni.hideLoading();uni.setStorage({key: 'autograph_key',data: t.contractImg,success: function () {console.log("签字",'success');}});uni.navigateBack({ delta: 1 });    // 返回上一页                              }}})                },ReSign:function(){// console.log(this.ctx)this.autographStatus = true}}}
</script>
<style>
.authentication_top{width:100%;height:90%;position:fixed;top:0;left:0;right:0;margin:auto;overflow-y:scroll;padding-bottom:40rpx}.authentication_top image{width:100%;display:inline-block}.authentication_bottom{width:100%;height:10%;position:fixed;bottom:0;left:0;right:0;margin:auto;display:flex;flex-direction:column;justify-content:center;align-items:center;background:#ffe9e9}.authentication_bottom button{background:0 0;border:none;font-size:15px;color:red;width:100%;text-align:center}.authentication_bottom button:after{display:none}.authentication_fun{width:100%;height:10%;position:fixed;bottom:30rpx;left:0;right:0;margin:auto;display:flex;flex-direction:row;justify-content:center;align-items:center;background:#ffe9e9;padding:0 3%;width:90%;border-radius:50px;box-shadow:0 3px 13px rgba(0,0,0,.2);border:4px solid #fd972e;box-sizing:border-box}.authentication_fun button{border:none;font-size:15px;background:0 0;width:100%;text-align:center}.authentication_fun button:after{display:none}.signMask{width:100%;height:100%;background:#fff;position:fixed;top:0;bottom:0;left:0;right:0;flex-direction:row}.sign-box,.signMask{margin:auto;display:flex}.sign-box{width:80%;height:90%;flex-direction:column;text-align:center}.sigh-btns,.sign-view{height:100%}.sigh-btns{margin:auto;display:flex;flex-direction:column;justify-content:space-around}.btn{margin:auto;padding:8rpx 40rpx;font-size:14px;transform:rotate(90deg);border:1rpx solid grey}.mycanvas{margin:auto 0rpx;background-color:#ececec}.canvsborder{border:1rpx solid #333;position:fixed;top:0;left:10000rpx}.bgCoverBox{width:100%;height:auto}.canvsborder2{height:700px!important}</style>

uniapp 实现在线签合同/签名/信息认证(无插件依赖)相关推荐

  1. 【校招VIP】出品:在线实习“职查查”大V信息认证实战

    本课程出自校招VIP原创内容,请勿擅自转载,测试项目课程「在线实习"职查查"大V信息认证实战」持续更新中...... 查看课程:[测试]在线实习"职查查"大V信 ...

  2. 【校招VIP】出品:产品在线实习“职查查”大V信息认证实战

    本课程出自[校招VIP]原创内容,请勿擅自转载,产品(项目课程)「在线实习"职查查"大V信息认证实战」持续更新中...... ​查看课程:「在线实习"职查查"大 ...

  3. 网关信息认证服务器不可达,网关消息认证服务器不可达

    网关消息认证服务器不可达 内容精选 换一换 API的响应码如何定义?响应信息由后端API服务定义,API网关只做透传.响应信息由后端API服务定义,API网关只做透传.使用VPC通道,后端服务的主机端 ...

  4. dsa签名 linux_linux SElinux防护 加密解密 gpg签名与认证

    SElinux Security-Enhanced Linux 由美国国家安全局主导开发 一套强化linux安全的mac扩展模块 selinux的运作机制: 集成到linux内核上(2.6及以上) 操 ...

  5. 使用aspose方式使excel,ppt,word进行在线预览。(无水印)

    使用aspose方式使excel,ppt,word进行在线预览.(无水印) 1.首先,页面需要用jquery中window.open();打开一个新页面. window.open(../fileMan ...

  6. 利用FastReport传递图片参数,在报表上展示签名信息

    在一个项目中,客户要求对报表中的签名进行仿手写的签名处理,因此我们原先只是显示相关人员的姓名的地方,需要采用手写方式签名,我们的报表是利用FastReport处理的,在利用楷体处理的时候,开发展示倒是 ...

  7. linux C++ 使用openssl rsa算法实现对计算机物理地址进行签名和认证

    首先需要使用openssl生成公钥和私钥,然后对字符串进行签名和认证. license.h #pragma once #include <iostream> #include <st ...

  8. 360在线无插件直播html,360直播高清版

    360直播是360直播网推出的手机直播软件,专注于各种足球.篮球直播,为广大球迷们提供高清流畅的足球比赛直播视频,想来观看体育赛事的可以来搜一搜手游网上下载360直播高清版,观看360直播无插件高清足 ...

  9. 编出个区块链:实现区块链的椭圆曲线签名和认证

    前两章我们了解了有限群和椭圆曲线,特别是了解了椭圆曲线上的点如何进行"加法"操作.有意思的是,如果我们将有限群里面的点与椭圆曲线结合起来能产生非常奇妙的化学反应.从上一节我们看到, ...

最新文章

  1. C++ 指针 vs 数组
  2. 有源则至清——我读《移山之道》
  3. Spring boot日志关系
  4. 汇编语言的准备知识--给初次接触汇编者 (1-4) 转载
  5. 牛客网【每日一题】7月8日 Alliances
  6. Extjs chart 总结 reload-chart.js 修改
  7. [渝粤教育] 西南科技大学 国际贸易理论与实务 在线考试复习资料2021版(1)
  8. Android 应用签名的创建
  9. 电大计算机本科离散数学考试题,2017年电大本科离散数学期末考试复习试题及答案.doc...
  10. VB.net 调用FFmpeg简单处理视频(类库——6)
  11. 视频本地化之 AE 处理流程
  12. 2020年基金收益盘点
  13. 项目管理过程组与知识领域关系
  14. python 应用程序无法正常启动 000007b_“应用程序无法正常启动(oxc000007b)”解决方案...
  15. 关于poi操作word,word转换pdf预览,这边文章就够了
  16. 快速了解会话管理三剑客cookie、session和JWT
  17. 康奈尔本科学计算机要什么条件,康奈尔大学计算机专业申请条件详细解读
  18. MySQL数据库(三)-表行的语句使用
  19. python四则运算器编写_0007 编程入门python语言之四则运算器
  20. 2019郑州大学计算机专业分数线,2019年郑州大学优势专业排名及分数线

热门文章

  1. 终端服务器 英文,面向终端的服务语言,TOSL Terminal C Oriented Service Language,音标,读音,翻译,英文例句,英语词典...
  2. IP、邮箱、ICON图标收集实战
  3. ae破碎效果在哪_利用Ae制作出破碎效果的详细步骤
  4. 2018-12-15全球区块链今日热点
  5. java基础入门第二版第二章课后答案,知识点总结+面试题解析
  6. 哈工大计算机专业师资队伍,黄荷姣 - 教师名录 - 教师队伍 - 哈尔滨工业大学(深圳)...
  7. 为什么特斯拉车钥匙电池,使用不到1年就需更换一次,而蒙迪欧致胜2.0T时尚版车钥匙电池可以使用10年。前期文章对特斯拉车钥匙功耗情况做了专题评测,用低功耗分析仪再来看看这款福特车钥匙的低功耗控制情况。
  8. LinkedList 底层实现
  9. php redis 实现点赞,使用redis实现点赞功能的几种思路
  10. 吃鸡买个自定义服务器,绝地求生自定义服务器不测试 可自由设置武器刷新道具掉落...