第一种:跳转签名页面
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、签名页面效果展示