uniapp H5实现签名

news/2024/5/6 23:12:28

第一种:跳转签名页面

1、创建审核页面audit.vue

<template><view><uni-section title=""><view class="auditClass"><uni-forms :model="baseFormData" ref="baseFormRef" :rules="rules" label-position="top"labelWidth="80px"><uni-forms-item label="审核意见" required name="advice"><uni-easyinput type="textarea" v-model="baseFormData.advice" placeholder="请输入审核意见" /></uni-forms-item><image :src='baseFormData.signUrl.replace(/[\r\n]/g, "")' v-if="baseFormData.signUrl"></image><button type="primary" style="margin-bottom: 15px;" :disabled="isClick" @click="signBtn">签名</button><button type="primary" :disabled="isClick" @click="submit('baseFormRef')">提交</button></uni-forms></view></uni-section></view>
</template><script>import config from '@/config';import {getUserProfile} from "@/api/system/user"const baseUrl = config.baseUrl;export default {data() {return {loading: false,user: {},// 基础表单数据baseFormData: {signUrl: '',advice: '',},isClick: false,}},computed: {},onLoad(options) {this.baseFormData.proId = options.proId;},onReady() {this.$refs.baseFormRef.setRules(this.rules)},onShow() {uni.$on("imageUrl", (data) => {console.log("接收事件imageUrl成功,data=", data);this.baseFormData.signUrl = data.imageUrl;});},methods: {getUser() {getUserProfile().then(response => {this.user = response.datathis.getTableData();})},submit(ref) {let self = this;self.$refs[ref].validate().then(res => {console.log('success', res);if (self.baseFormData.signUrl == '' || self.baseFormData.signUrl == null) {uni.showToast({title: '请签名',icon: "error"});} else {self.isClick = true;uni.showLoading({title: '提交中'});uni.request({withCredentials: true,url: baseUrl + '',data: JSON.stringify(self.baseFormData),method: 'post',success: function(res) {console.log(res.data);self.isClick = false;uni.hideLoading();if (res.data.code == 0) {uni.showToast({title: res.data.msg,icon: "error"});} else {uni.navigateBack({delta: 1,success() {setTimeout(() => {uni.showToast({title: res.data.msg,icon: 'success'})}, 500)}});}}});}}).catch(err => {console.log('err', err);});},// 签名signBtn() {this.$tab.navigateTo('/pages/processAudit/sign');},}}
</script><style scoped>.auditClass {padding: 15px;background-color: #ffffff;}
</style>

2、创建签名页面sign.vue

<template><view><view class="main-content" @touchmove.stop.prevent=""><!-- 签字canvas --><canvas class="mycanvas" id="mycanvas" canvas-id="mycanvas" @touchstart="touchstart" @touchmove="touchmove"@touchend="touchend"></canvas><canvas class="mycanvas":style="{ 'z-index': -1, width: `${screenWidth}px`, height: `${(screenWidth * screenWidth) / screenHeight}px` }"id="rotatCanvas" canvas-id="rotatCanvas"></canvas><cover-view class="button-line"><cover-view class="save-button" @tap="finish">保存</cover-view><cover-view class="clear-button" @tap="clear">清空</cover-view></cover-view></view></view>
</template><script>export default {data() {return {ctx: '', //绘图图像points: [], //路径点集合screenWidth: '',screenHeight: '',img: '',isDraw: false,};},mounted() {this.createCanvas();uni.getSystemInfo({success: e => {this.screenWidth = e.screenWidth;this.screenHeight = e.screenHeight;}});},methods: {//创建并显示画布createCanvas() {this.showCanvas = true;this.ctx = uni.createCanvasContext('mycanvas', this);//设置画笔样式this.ctx.lineWidth = 2;this.ctx.lineCap = 'round';this.ctx.lineJoin = 'round';},//触摸开始,获取到起点touchstart(e) {this.isDraw = truelet startX = e.changedTouches[0].x;let startY = e.changedTouches[0].y;let startPoint = {X: startX,Y: startY};this.points.push(startPoint);//每次触摸开始,开启新的路径this.ctx.beginPath();},//触摸移动,获取到路径点touchmove(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(); //绘制路径}},// 触摸结束,将未绘制的点清空防止对后续路径产生干扰touchend() {this.points = [];},/* ***********************************************#   绘制笔迹#	1.为保证笔迹实时显示,必须在移动的同时绘制笔迹#	2.为保证笔迹连续,每次从路径集合中区两个点作为起点(moveTo)和终点(lineTo)#	3.将上一次的终点作为下一次绘制的起点(即清除第一个点)************************************************ */draw() {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);},//清空画布clear() {this.isDraw = falsethis.ctx.clearRect(0, 0, this.screenWidth, this.screenHeight);this.ctx.draw(true);},//完成绘画并保存到本地finish() {if (this.isDraw) {uni.canvasToTempFilePath({canvasId: 'mycanvas',fileType: 'png',quality: 1, //图片质量success: res => {console.log("sign" + res.tempFilePath);this.rotate(res.tempFilePath);},complete: com => {}});} else {uni.$emit("imageUrl", {imageUrl: ''});uni.navigateBack();}},rotate(tempFilePath) {let that = thiswx.getImageInfo({src: tempFilePath,success: (res1) => {let canvasContext = wx.createCanvasContext('rotatCanvas')let rate = res1.height / res1.widthlet width = 300 / ratelet height = 300canvasContext.translate(height / 2, width / 2)canvasContext.rotate((270 * Math.PI) / 180)canvasContext.drawImage(tempFilePath, -width / 2, -height / 2, width, height)canvasContext.draw(false, () => {wx.canvasToTempFilePath({canvasId: 'rotatCanvas',fileType: 'png',quality: 1, //图片质量success(res) {console.log("====="+JSON.stringify(res))uni.$emit("imageUrl", {imageUrl: res.tempFilePath,});uni.navigateBack();}})})}})},}};
</script>
<style lang="scss" scoped>.main-content {width: 100vw;height: 100vh;background-color: red;position: fixed;top: 0rpx;left: 0rpx;z-index: 9999;}.mycanvas {width: 100vw;height: 100vh;background-color: #fafafa;position: fixed;left: 0rpx;top: 0rpx;z-index: 2;}.button-line {transform: rotate(90deg);position: fixed;bottom: 170rpx;left: -100rpx;width: 340rpx;height: 80rpx;display: flex;align-items: center;justify-content: space-between;z-index: 999;font-size: 34rpx;font-weight: 600;}.save-button {color: #ffffff;width: 150rpx;height: 80rpx;text-align: center;line-height: 80rpx;border-radius: 10rpx;background-color: #007aff;}.clear-button {color: #ffffff;width: 150rpx;height: 80rpx;text-align: center;line-height: 80rpx;border-radius: 10rpx;background-color: #aaaaaa;}
</style>

3、签名页面效果展示

第二种:签名页面嵌入

1、创建审核页面audit.vue

<template><view><uni-section title=""><view class="auditClass"><uni-forms :model="baseFormData" ref="baseFormRef" :rules="rules" label-position="top"labelWidth="80px"><uni-forms-item label="审核意见" required name="advice"><uni-easyinput type="textarea" v-model="baseFormData.advice" placeholder="请输入审核意见" /></uni-forms-item><button type="primary" style="margin-bottom: 15px;" @click="signBtn">签名</button><sign v-if='signShow' @closeCanvas="closeCanvas" @change="change"></sign><button type="primary" @click="submit('baseFormRef')">提交</button></uni-forms></view></uni-section></view>
</template><script>import config from '@/config';import {getUserProfile} from "@/api/system/user"const baseUrl = config.baseUrl;import sign from './sign.vue'export default {components: {sign},data() {return {loading: false,user: {},// 基础表单数据baseFormData: {signUrl: '',advice: '',},signShow: false,}},computed: {},onLoad(options) {console.log("proId====" + options.proId)this.baseFormData.proId = options.proId;},onReady() {// 设置自定义表单校验规则,必须在节点渲染完毕后执行this.$refs.baseFormRef.setRules(this.rules)},methods: {submit(ref) {let self = this;self.$refs[ref].validate().then(res => {console.log('success', res);if (self.baseFormData.signUrl == '' || self.baseFormData.signUrl == null) {uni.showToast({title: '请签名',icon: "error"});} else {//获取表单数据并发送请求self.baseFormData.userId = self.user.userId;uni.request({withCredentials: true, // 加入这一行即可url: baseUrl + '/api/saveProcessAuditInfo',data: JSON.stringify(self.baseFormData),method: 'post',success: function(res) {console.log(res.data);if (res.data.code == 0) {uni.showToast({title: res.data.msg,icon: "error"});} else {uni.navigateBack({delta: 1,success() {setTimeout(() => {uni.showToast({title: res.data.msg,icon: 'success'})}, 500)}});}}});}}).catch(err => {console.log('err', err);});},// 签名signBtn() {this.signShow = true},// 关闭画布closeCanvas(e) {this.signShow = false},// 用户签名数据change(e) {console.log(e) //返回的base64地址this.baseFormData.signUrl = e;},}}
</script><style scoped>.auditClass {padding: 15px;background-color: #ffffff;}
</style>

2、创建签名页面sign.vue

<template><view><view class="box" :style="{height:height}"><view class="top"><canvas class="canvas-box" @touchstart='touchstart' @touchmove="touchmove" @touchend="touchend"canvas-id="myCanvas"></canvas><view>请在此处签名</view></view><view class=" bottom"><uni-tag text="完成" mode="dark" @click="finish" /><uni-tag text="重签" mode="dark" @click="clear" /><uni-tag text="取消" mode="dark" @click="close" /></view></view></view>
</template><script>export default {data() {return {ctx: '', //绘图图像points: [], //路径点集合height: '200px', //高度canvasShoww: false, //提示isDraw: false,}},created() {let that = this// uni.getSystemInfo({// 	success: function(res) {// 		that.height = res.windowHeight + 'px';// 	},// });},mounted() {this.createCanvas()},methods: {//创建并显示画布createCanvas() {this.ctx = uni.createCanvasContext('myCanvas', this); //创建绘图对象//设置画笔样式this.ctx.lineWidth = 4;this.ctx.lineCap = 'round';this.ctx.lineJoin = 'round';},// 触摸开始touchstart(e) {// 在签名前调用禁用滚动this.disableScroll();this.isDraw = truelet startX = e.changedTouches[0].x;let startY = e.changedTouches[0].y;let startPoint = {X: startX,Y: startY};this.points.push(startPoint);//每次触摸开始,开启新的路径this.ctx.beginPath();},// 移动touchmove(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(); //绘制路径}},// 触摸结束,将未绘制的点清空防止对后续路径产生干扰touchend(e) {// 在签名完成后调用启用滚动this.enableScroll();this.points = [];},//绘制笔迹draw() {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);},//清空画布clear() {let that = this;if (this.imageShow) {if (this.imageUrl) {this.imageUrl = '';this.imageShow = false;}} else {uni.getSystemInfo({success: function(res) {// 设置画笔样式let canvasw = res.windowWidth;let canvash = res.windowHeight;that.ctx.clearRect(0, 0, canvasw, canvash);that.ctx.draw(true);}});}this.createCanvas();},//关闭并清空画布close() {this.$emit('closeCanvas');this.createCanvas();this.clear();},//完成绘画并保存到本地finish() {if (this.isDraw) {let that = this;uni.canvasToTempFilePath({canvasId: 'myCanvas',success: function(res) {that.imageShow = true;that.imageUrl = res.tempFilePath;that.$emit('closeCanvas');that.$emit('change', res.tempFilePath);that.close();}},// this);return}this.$u.func.showToast({title: '请签名',})},// 禁用页面滚动disableScroll() {var box=function(e){passive: false ;};document.body.style.overflow='hidden';document.addEventListener("touchmove",box,false);},// 启用页面滚动enableScroll() {var box=function(e){passive: false };document.body.style.overflow=''; // 出现滚动条document.removeEventListener("touchmove",box,false);},}}
</script><style lang="scss" scoped>.box {width: 100%;margin-bottom: 50px;display: flex;flex-direction: column;background-color: #fff;.top {height: 95%;margin: 50rpx;border: 1px solid #000;position: relative;.canvas-box {width: 100%;height: 100%;}}.bottom {height: 5%;display: flex;align-items: flex-start;justify-content: space-around;}}
</style>

3、签名页面效果展示


http://www.mrgr.cn/p/03222844

相关文章

zigbee开发,低功耗,通信加密开发

一。低功耗 1.低功耗应用场景1、不利于更换电池的设备2、手持便携设备3、实时性要求不高的设备 2.低功耗工作原理1、时钟降至最低2、暂时不用的外设关闭、需要在启动3、I/O配置 用电情况可以简化为: 等一会运行一下。 3.zigbee实现低功耗 1.协调器+路由器+终端 补充:CC2530(…

爽了!免费的SSL,还能自动续期!

作者:小傅哥 博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获!😄大家好,我是技术UP主小傅哥。 兄弟👬🏻,当你手里有不少域名,每个域名又配置子域名,那么ssl将是一笔不小的费用。当然各个云厂商,也都有提供免费的ssl证书,但这里有一个问题,…

【C++】---STL之list的模拟实现

【C】---STL之list的模拟实现 一、list模拟实现思路二、结点类的实现三、list迭代器的实现1、ListIterator类2、构造函数3、operator*运算符重载5、operator->运算符重载6、operator&#xff01;运算符重载7、operator运算符重载8、前置9、后置10、前置--11、后置-- 四、lis…

华为云Stack8.3面向香港正式发布,六大亮点激发云上跃迁

近日,在华为云香港峰会2024上,华为混合云副总裁胡玉海面向香港市场发布华为云Stack8.3,提供110+本地云服务和六大亮点,帮助中国香港政企持续提升用云深度,激发业务创新。本文分享自华为云社区《华为云Stack8.3面向香港正式发布,六大亮点激发云上跃迁》,作者:华为云头条…

【AIGC调研系列】Bunny-Llama-3-8B-V与其他多模态大模型相比的优劣

Bunny-Llama-3-8B-V作为基于Llama-3的多模态大模型&#xff0c;其优势主要体现在以下几个方面&#xff1a; 性能超越其他模型&#xff1a;根据我搜索到的资料&#xff0c;Bunny-Llama-3-8B-V在多个主流Benchmark上表现良好&#xff0c;超越了LLaVA-7B、LLaVA-13B、Mini-Gemini…

抽象的代理模式1.0版本

前言&#xff1a; 在阅读Spring Security官方文档时&#xff0c;里面设计到了一种设计模式——代理模式Proxy 众里寻她千百度&#xff0c;蓦然回首&#xff0c;那人却在灯火阑珊处 开始 在之前的文章里陈述了一个观点——编程语言和语言没有区别 现看看我们日常生活中的代理…

怎么设置 idea terminal 窗口的编码格式

1 修改Terminal 窗口为 Git bash 窗口 打开 settings 设置界面&#xff0c;选择 Tools 中的 Terminal (File -> settings -> Tools -> Terminal) 修改 Shell path 为你的 Git bash 安装路径&#xff0c;我的在 C:\my_software\java\Git\bin\bash.exe 2 解决中文显示…

python r代表什么意思

r/R&#xff0c;即raw的缩写&#xff0c;意思是未经加工的&#xff1b;自然状态的&#xff1b;未经处理的&#xff1b;未经分析的&#xff1b;原始的。 在Python中r/R表示非转义的原始字符串。与普通字符相比&#xff0c;其他相对特殊的字符&#xff0c;其中可能包含转义字符&…

添加阿里云yum源

添加阿里云yum源 要添加阿里云的 yum 源&#xff0c;可以执行以下步骤&#xff1a; 首先&#xff0c;备份你的现有 yum 源配置文件&#xff0c;以防止意外更改&#xff1a; sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup然后&#xf…

探讨mfc100u.dll丢失的解决方法,修复mfc100u.dll有效方法解析

mfc100u.dll丢失是一个比较常见的情况&#xff0c;由于你电脑的各种操作&#xff0c;是有可能引起dll文件的缺失的&#xff0c;而mfc100u.dll就是其中的一个重要的dll文件&#xff0c;它的确实严重的话是会导致程序打不开&#xff0c;系统错误的。今天我们就来给大家科普一下mf…

【白盒测试】单元测试的理论基础及用例设计技术(6种)详解

目录 &#x1f31e;前言 &#x1f3de;️1. 单元测试的理论基础 &#x1f30a;1.1 单元测试是什么 &#x1f30a;1.2 单元测试的好处 &#x1f30a;1.3 单元测试的要求 &#x1f30a;1.4 测试框架-Junit4的介绍 &#x1f30a;1.5 单元测试为什么要mock &#x1f3de;️…

【产品经理修炼之道】- 从需求到功能的转化过程

产品经理的最大作用是将需求转化为产品或者功能&#xff0c;从需求到功能&#xff0c;会经历哪些过程&#xff1f;本文总结了从需求到功能的转化过程&#xff0c;希望对你进一步了解有所帮助。 “大部分的产品经理特别是数字化产品经理其核心价值就是如何去解决如何把需求转化为…

韩国机器人公司Rainbow Robotics推出RB-Y1轮式双臂机器人

文 | BFT机器人 近日&#xff0c;韩国机器人领域的佼佼者Rainbow Robotics揭开了RB-Y1移动机器人的神秘面纱&#xff0c;这款机器人以其创新的设计和卓越的功能引起了业界的广泛关注。与此同时&#xff0c;Rainbow Robotics还携手舍弗勒集团&#xff08;提供汽车、工业技术服务…

[转帖]历代x86架构IPC提升及12代酷睿与至强洋垃圾的简单对比

https://www.bilibili.com/read/cv16170718/ 好奇查找了一下历代x86架构CPU的IPC性能提升,发现知乎用户@MebiuW已经总结了10代酷睿和ZEN3之前历代架构的情况,于是摘录下来。IPC指的是每个周期CPU核心处理的指令数,频率代表CPU核心每1秒钟计算多少个周期,二者的乘积就是CPU…

浅谈菊风实时音视频 (RTC)与实时操作系统 (RTOS) 在智能硬件领域应用

近年来&#xff0c;菊风通过实时音视频赋能智能手表、智能门禁、智能门锁/门铃、智能眼镜等数十种智能硬件&#xff0c;与一众合作伙伴共同探索在IoT智能硬件领域的不同场景应用&#xff0c;积累了丰富的实践经验。在智能硬件中&#xff0c;RTOS因其轻量化的系统内核&#xff0…

Docker 的数据管理 端口映射 容器互联 镜像的创建

目录 概念 概念 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;。总结&#xff1a;因为容器数据是临时保存的为了安全&#xff0c;就要让数据保持持久化。 1&#…

.NET 个人博客-添加RSS订阅功能

个人博客-添加RSS订阅功能 前言 个人博客系列已经完成了 留言板文章归档推荐文章优化推荐文章排序 博客地址 然后博客开源的原作者也是百忙之中添加了一个名为RSS订阅的功能&#xff0c;那么我就来简述一下这个功能是干嘛的&#xff0c;然后照葫芦画瓢实现一下。 RSS简述…

专利视角下的量子竞赛:《2024全球专利格局白皮书》

2024年1月&#xff0c;欧洲量子产业联盟&#xff08;QuIC&#xff09;发布了题为《全球量子技术专利格局描述》的综合白皮书。 该文件以透明的视角展示了当今的知识产权格局&#xff0c;包括知识产权持有人的地理分布。该文件由 QuIC 知识产权&#xff08;IP&#xff09;与贸易…

VMware配置centos虚拟机实现内网互通

VMware配置centos虚拟机实现内网互通 一、安装无桌面模式 环境说明&#xff1a; VMWare版本&#xff1a;VMware Workstation 17 Pro Centos版本&#xff1a;CentOS-7.9-x86_64-DVD-2009.iso 一键下载本文资源包 1. 安装虚拟机 下面是创建具体步骤,其中需要注意的是&#xff1…

42. UE5 RPG 实现火球术伤害

上一篇&#xff0c;我们解决了火球术于物体碰撞的问题&#xff0c;现在火球术能够正确的和攻击目标产生碰撞。接下来&#xff0c;我们要实现火球术的伤害功能&#xff0c;在火球术击中目标后&#xff0c;给目标造成伤害。 实现伤害功能的思路是给技能一个GameplayEffect&#x…