签名优化
This commit is contained in:
parent
21952c3eef
commit
461bb7fd56
|
|
@ -1,10 +1,19 @@
|
|||
<template>
|
||||
<view class="whole canvas-autograph flexc" @touchmove.prevent.stop @wheel.prevent.stop v-show="modelValue">
|
||||
<canvas class="scroll-view" id="mycanvas" canvas-id="mycanvas"
|
||||
<view
|
||||
class="whole canvas-autograph flexc"
|
||||
@touchmove.prevent.stop
|
||||
@wheel.prevent.stop
|
||||
v-show="modelValue"
|
||||
>
|
||||
<canvas
|
||||
class="scroll-view"
|
||||
id="mycanvas"
|
||||
canvas-id="mycanvas"
|
||||
@touchstart="touchstart"
|
||||
@touchmove="touchmove"
|
||||
@touchend="touchend"
|
||||
disable-scroll="true"/>
|
||||
disable-scroll="true"
|
||||
/>
|
||||
<view class="fun-box">
|
||||
<div class="hint">
|
||||
<text class="rotate">请在下方空白区域横向书写签名</text>
|
||||
|
|
@ -19,146 +28,116 @@
|
|||
<text>取消</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 横向提示 -->
|
||||
<view v-if="showToast" class="rotate-toast">
|
||||
<text class="rotate-text">{{ toastMsg }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/*
|
||||
使用如下
|
||||
<canvas-autograph v-model="isCanvas" @complete="complete"/>
|
||||
import { ref, reactive, watch, getCurrentInstance } from 'vue'
|
||||
|
||||
// 打开、关闭
|
||||
let isCanvas = ref(false)
|
||||
// 确认事件
|
||||
const complete = e=>{
|
||||
console.log(e)
|
||||
}
|
||||
const emits = defineEmits(['update:modelValue', 'complete'])
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
})
|
||||
const _this = getCurrentInstance()
|
||||
|
||||
*/
|
||||
import { ref, reactive, watch, getCurrentInstance } from 'vue'
|
||||
let points = reactive([]) // 路径点集合
|
||||
let canvaCtx = reactive(uni.createCanvasContext('mycanvas', _this)) // 创建绘图对象
|
||||
canvaCtx.lineWidth = 6
|
||||
canvaCtx.lineCap = 'round'
|
||||
canvaCtx.lineJoin = 'round'
|
||||
|
||||
const emits = defineEmits(['update:modelValue','complete'])
|
||||
// 是否有签名
|
||||
let hasDrawn = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
modelValue:Boolean,
|
||||
})
|
||||
const _this = getCurrentInstance()
|
||||
watch(()=>props.modelValue,e=>{
|
||||
// 这里可进行 tabbar 的 显示、隐藏 不要也可以
|
||||
// 自己写
|
||||
},{
|
||||
immediate:true, // 是否默认执行一次 默认为false
|
||||
})
|
||||
// 横向提示
|
||||
const showToast = ref(false)
|
||||
const toastMsg = ref('')
|
||||
const showRotateToast = (msg) => {
|
||||
toastMsg.value = msg
|
||||
showToast.value = true
|
||||
setTimeout(() => (showToast.value = false), 2000)
|
||||
}
|
||||
|
||||
let points = reactive([]) //路径点集合
|
||||
|
||||
let canvaCtx = reactive(uni.createCanvasContext('mycanvas', _this)) //创建绘图对象
|
||||
//设置画笔样式
|
||||
canvaCtx.lineWidth = 6;
|
||||
canvaCtx.lineCap = 'round'
|
||||
canvaCtx.lineJoin = 'round'
|
||||
|
||||
|
||||
//触摸开始,获取到起点
|
||||
const touchstart = e=>{
|
||||
// 触摸开始
|
||||
const touchstart = (e) => {
|
||||
let startX = e.changedTouches[0].x
|
||||
let startY = e.changedTouches[0].y
|
||||
let startPoint = {X:startX,Y:startY}
|
||||
points.push(startPoint);
|
||||
//每次触摸开始,开启新的路径
|
||||
canvaCtx.beginPath();
|
||||
}
|
||||
//触摸移动,获取到路径点
|
||||
const touchmove = e=>{
|
||||
let startPoint = { X: startX, Y: startY }
|
||||
points.push(startPoint)
|
||||
canvaCtx.beginPath()
|
||||
hasDrawn.value = true // 标记已签名
|
||||
}
|
||||
// 触摸移动
|
||||
const touchmove = (e) => {
|
||||
let moveX = e.changedTouches[0].x
|
||||
let moveY = e.changedTouches[0].y
|
||||
let movePoint = {X:moveX,Y:moveY}
|
||||
points.push(movePoint) //存点
|
||||
let len = points.length
|
||||
if(len>=2){
|
||||
let movePoint = { X: moveX, Y: moveY }
|
||||
points.push(movePoint)
|
||||
if (points.length >= 2) {
|
||||
draw()
|
||||
}
|
||||
}
|
||||
//绘制路径
|
||||
// const draw = ()=> {
|
||||
// let point1 = points[0]
|
||||
// let point2 = points[1]
|
||||
// points.shift()
|
||||
// canvaCtx.moveTo(point1.X, point1.Y)
|
||||
// canvaCtx.lineTo(point2.X, point2.Y)
|
||||
// canvaCtx.stroke()
|
||||
// canvaCtx.draw(true)
|
||||
// }
|
||||
const draw = () => {
|
||||
if (points.length < 2) return;
|
||||
|
||||
canvaCtx.beginPath();
|
||||
canvaCtx.moveTo(points[0].X, points[0].Y);
|
||||
}
|
||||
// 绘制
|
||||
const draw = () => {
|
||||
if (points.length < 2) return
|
||||
canvaCtx.beginPath()
|
||||
canvaCtx.moveTo(points[0].X, points[0].Y)
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
canvaCtx.lineTo(points[i].X, points[i].Y);
|
||||
canvaCtx.lineTo(points[i].X, points[i].Y)
|
||||
}
|
||||
canvaCtx.stroke();
|
||||
canvaCtx.draw(true);
|
||||
|
||||
// 绘制后清空已绘制点
|
||||
points = [points[points.length - 1]]; // 保留最后一个点作为下一次起点
|
||||
}
|
||||
// 触摸结束,将未绘制的点清空防止对后续路径产生干扰
|
||||
const touchend = e=>{
|
||||
points = [];
|
||||
}
|
||||
// 清空画布
|
||||
// const clear = ()=>{
|
||||
// return uni.getSystemInfo()
|
||||
// .then(res=>{
|
||||
// canvaCtx.clearRect(0, 0, res.windowWidth, res.windowHeight);
|
||||
// canvaCtx.draw(true);
|
||||
// return res
|
||||
// })
|
||||
// .catch(err=>{
|
||||
// // console.log(err);
|
||||
// })
|
||||
// }
|
||||
canvaCtx.stroke()
|
||||
canvaCtx.draw(true)
|
||||
points = [points[points.length - 1]]
|
||||
}
|
||||
// 触摸结束
|
||||
const touchend = () => {
|
||||
points = []
|
||||
}
|
||||
// 清空画布
|
||||
const clear = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.createSelectorQuery()
|
||||
uni
|
||||
.createSelectorQuery()
|
||||
.in(_this)
|
||||
.select('#mycanvas') // 确保 id 和 canvas 的一致性
|
||||
.fields({ size: true, rect: true }, data => {
|
||||
.select('#mycanvas')
|
||||
.fields({ size: true, rect: true }, (data) => {
|
||||
if (!data) {
|
||||
reject('Canvas not found')
|
||||
return
|
||||
}
|
||||
|
||||
const { width, height } = data
|
||||
|
||||
// 真正按 canvas 实际尺寸清除
|
||||
canvaCtx.clearRect(0, 0, width, height)
|
||||
canvaCtx.draw(true)
|
||||
hasDrawn.value = false
|
||||
resolve()
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
}
|
||||
|
||||
// 确认
|
||||
const confirm = ()=>{
|
||||
uni.canvasToTempFilePath({ canvasId: 'mycanvas', }, _this, _this.parent)
|
||||
.then(res=>{
|
||||
console.log(res.tempFilePath);
|
||||
emits('complete',res.tempFilePath)
|
||||
// 确认
|
||||
const confirm = () => {
|
||||
if (!hasDrawn.value) {
|
||||
showRotateToast('请先签名再确认')
|
||||
return
|
||||
}
|
||||
uni.canvasToTempFilePath({ canvasId: 'mycanvas' }, _this, _this.parent).then((res) => {
|
||||
emits('complete', res.tempFilePath)
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
// 取消
|
||||
const cancel = ()=>{
|
||||
clear().then(res=>emits('update:modelValue',false))
|
||||
}
|
||||
|
||||
}
|
||||
// 取消
|
||||
const cancel = () => {
|
||||
clear().then(() => emits('update:modelValue', false))
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.canvas-autograph {
|
||||
.canvas-autograph {
|
||||
position: fixed;
|
||||
z-index: 998;
|
||||
width: 100vw;
|
||||
|
|
@ -169,23 +148,21 @@ const clear = () => {
|
|||
.scroll-view {
|
||||
width: calc(100% - 120rpx);
|
||||
height: 99.6%;
|
||||
background-color: #FFFFFF;
|
||||
background-color: #ffffff;
|
||||
border: 2px solid #333;
|
||||
}
|
||||
.fun-box {
|
||||
position: absolute;
|
||||
height: 90rpx;
|
||||
right: 0;
|
||||
bottom: 0px;
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.fun-box-btn {
|
||||
width: 100rpx;
|
||||
height: 160rpx;
|
||||
color: #FFFFFF;
|
||||
color: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
border: 1rpx solid #C0C0C0;
|
||||
border: 1rpx solid #c0c0c0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -195,14 +172,14 @@ const clear = () => {
|
|||
}
|
||||
.clear {
|
||||
color: #909399;
|
||||
background-color: #F4F4F5;
|
||||
background-color: #f4f4f5;
|
||||
}
|
||||
.confirm {
|
||||
background-color: #409EFF;
|
||||
background-color: #409eff;
|
||||
margin: 3px 0;
|
||||
}
|
||||
.cancel {
|
||||
background-color: #F67D7D;
|
||||
background-color: #f67d7d;
|
||||
}
|
||||
.hint {
|
||||
width: 100rpx;
|
||||
|
|
@ -210,19 +187,43 @@ const clear = () => {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #F67D7D;
|
||||
color: #f67d7d;
|
||||
background: transparent;
|
||||
margin-bottom: 150rpx;
|
||||
|
||||
.rotate {
|
||||
display: inline-block;
|
||||
transform: rotate(90deg);
|
||||
transform-origin: center;
|
||||
white-space: nowrap;
|
||||
font-size: 33rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/* 横向提示样式 */
|
||||
.rotate-toast {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
padding: 20rpx;
|
||||
border-radius: 24rpx;
|
||||
z-index: 999;
|
||||
|
||||
/* 重点调整 */
|
||||
width: 100rpx; /* 宽度只需少量,留给旋转文字 */
|
||||
min-height: 400rpx; /* 高度拉长,保证横向文字能完整显示 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rotate-text {
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
transform: rotate(90deg);
|
||||
display: inline-block;
|
||||
white-space: nowrap; /* 保证一行显示 */
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
个人电子签名维护,支持手机拍照、上传图片以及手写签名,推荐使用手写签名,请横向书写签名!
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button class="btn" type="primary" @click="handlePhoto">拍照/上传</button>
|
||||
<!-- <button class="btn" type="primary" @click="handlePhoto">拍照/上传</button> -->
|
||||
<button class="btn" type="primary" @click="open">手写签名</button>
|
||||
</div>
|
||||
<miliu-autograph v-model="isCanvas" @complete="complete"></miliu-autograph>
|
||||
|
|
@ -327,10 +327,10 @@ const uploadSignUrl = async (url) => {
|
|||
margin: 10rpx;
|
||||
border-radius: 20rpx;
|
||||
.btn {
|
||||
width: 40%;
|
||||
&:first-child {
|
||||
width: 100%;
|
||||
/* &:first-child {
|
||||
margin-right: 20px;
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
.signature-page {
|
||||
|
|
|
|||
Loading…
Reference in New Issue