电子签名

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