电子签名
This commit is contained in:
parent
6ca132970b
commit
31ccf971d9
|
|
@ -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) => {
|
||||
|
||||
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))
|
||||
|
|
|
|||
Loading…
Reference in New Issue