电子签名

This commit is contained in:
bb_pan 2025-08-30 10:28:52 +08:00
parent 6ca132970b
commit 31ccf971d9
1 changed files with 124 additions and 34 deletions

View File

@ -68,13 +68,17 @@ if (memberStore.userInfo.nickName && memberStore.userInfo.nickName.length < 5) {
nickName.value = '正楷字书写'
}
const paths = ref([]) //
const PEN = { width: 6, color: '#000000' } //
watch(
() => props.modelValue,
(val) => {
if (val) {
// canvas
setTimeout(() => {
uni.createSelectorQuery()
uni
.createSelectorQuery()
.in(_this)
.select('#mycanvas')
.fields({ size: true, rect: true }, (data) => {
@ -86,7 +90,7 @@ watch(
.exec()
}, 50) // 30~100ms
}
}
},
)
const showRotateToast = (msg) => {
@ -143,43 +147,62 @@ const drawBackground = (ctx, width = 100, height = 100) => {
//
const touchstart = (e) => {
let startX = e.changedTouches[0].x
let startY = e.changedTouches[0].y
let startPoint = { X: startX, Y: startY }
points.push(startPoint)
const x = e.changedTouches[0].x
const y = e.changedTouches[0].y
const p = { X: x, Y: y }
//
paths.value.push([p])
// 便
canvaCtx.setLineWidth(PEN.width)
canvaCtx.setStrokeStyle(PEN.color)
canvaCtx.setLineCap('round')
canvaCtx.setLineJoin('round')
canvaCtx.beginPath()
}
//
const touchmove = (e) => {
let moveX = e.changedTouches[0].x
let moveY = e.changedTouches[0].y
let movePoint = { X: moveX, Y: moveY }
points.push(movePoint)
if (points.length >= 2) {
draw()
hasDrawn.value = true //
}
}
//
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.moveTo(x, y)
// 线
canvaCtx.lineTo(x + 0.1, y + 0.1)
canvaCtx.stroke()
canvaCtx.draw(true)
points = [points[points.length - 1]]
}
//
const touchmove = (e) => {
const x = e.changedTouches[0].x
const y = e.changedTouches[0].y
const p = { X: x, Y: y }
//
const cur = paths.value[paths.value.length - 1]
if (cur) cur.push(p)
//
canvaCtx.setLineWidth(PEN.width)
canvaCtx.setStrokeStyle(PEN.color)
canvaCtx.setLineCap('round')
canvaCtx.setLineJoin('round')
if (cur && cur.length >= 2) {
const prev = cur[cur.length - 2]
canvaCtx.beginPath()
canvaCtx.moveTo(prev.X, prev.Y)
canvaCtx.lineTo(p.X, p.Y)
canvaCtx.stroke()
canvaCtx.draw(true)
}
}
const touchend = () => {
// paths便 points points
points = []
hasDrawn.value = paths.value.length > 0
}
//
const clear = () => {
return new Promise((resolve, reject) => {
uni.createSelectorQuery()
uni
.createSelectorQuery()
.in(_this)
.select('#mycanvas')
.fields({ size: true, rect: true }, (data) => {
@ -188,9 +211,14 @@ const clear = () => {
return
}
const { width, height } = data
//
canvaCtx.clearRect(0, 0, width, height)
// flush drawBackground ctx.draw
canvaCtx.draw(false, () => {
drawBackground(canvaCtx, width, height) //
// drawBackground ctx.draw
drawBackground(canvaCtx, width, height)
//
paths.value = []
hasDrawn.value = false
resolve()
})
@ -205,11 +233,73 @@ const confirm = () => {
showRotateToast('请先签名再确认')
return
}
uni.canvasToTempFilePath({ canvasId: 'mycanvas' }, _this, _this.parent).then((res) => {
emits('complete', res.tempFilePath)
cancel()
})
uni
.createSelectorQuery()
.in(_this)
.select('#mycanvas')
.fields({ size: true, rect: true }, (data) => {
if (!data) return
const { width, height } = data
// 1)
canvaCtx.clearRect(0, 0, width, height)
// 2)
canvaCtx.setLineWidth(PEN.width)
canvaCtx.setStrokeStyle(PEN.color)
canvaCtx.setLineCap('round')
canvaCtx.setLineJoin('round')
canvaCtx.setFillStyle(PEN.color)
paths.value.forEach((path) => {
if (!path || !path.length) return
if (path.length === 1) {
//
const p = path[0]
canvaCtx.beginPath()
canvaCtx.arc(p.X, p.Y, Math.max(1, PEN.width / 2), 0, Math.PI * 2)
canvaCtx.fill()
} else {
canvaCtx.beginPath()
canvaCtx.moveTo(path[0].X, path[0].Y)
for (let i = 1; i < path.length; i++) {
canvaCtx.lineTo(path[i].X, path[i].Y)
}
canvaCtx.stroke()
}
})
// 3) flush
canvaCtx.draw(false, () => {
uni
.canvasToTempFilePath(
{
canvasId: 'mycanvas',
width,
height,
destWidth: width,
destHeight: height,
fileType: 'png',
quality: 1,
},
_this,
_this.parent,
)
.then((res) => {
emits('complete', res.tempFilePath)
//
cancel()
})
.catch((err) => {
console.error('导出签名失败', err)
showRotateToast('导出失败,请重试')
})
})
})
.exec()
}
//
const cancel = () => {
clear().then(() => emits('update:modelValue', false))