Files
cz-app/src/pages/contract-center/sign/components/SignaturePad.vue
2026-09-17 15:48:51 +08:00

169 lines
3.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { getCurrentInstance, nextTick, ref, watch } from 'vue'
const props = defineProps<{
visible: boolean
}>()
const emit = defineEmits<{
close: []
confirm: [imagePath: string]
}>()
const instance = getCurrentInstance()
const hasStroke = ref(false)
const canvasWidth = ref(300)
const canvasHeight = ref(500)
let ctx: UniApp.CanvasContext | null = null
let drawing = false
let lastX = 0
let lastY = 0
watch(
() => props.visible,
async (visible) => {
if (!visible)
return
await nextTick()
const query = uni.createSelectorQuery().in(instance)
query.select('#signature-canvas').boundingClientRect((rect) => {
if (rect && !Array.isArray(rect)) {
canvasWidth.value = rect.width
canvasHeight.value = rect.height
}
initCanvas()
}).exec()
},
)
function initCanvas() {
ctx = uni.createCanvasContext('signature-canvas', instance)
ctx.setStrokeStyle('#1a1a1a')
ctx.setLineWidth(3)
ctx.setLineCap('round')
ctx.setLineJoin('round')
clearCanvas()
}
function clearCanvas() {
if (!ctx)
return
ctx.clearRect(0, 0, canvasWidth.value, canvasHeight.value)
ctx.draw()
hasStroke.value = false
}
function getTouchPoint(event: TouchEvent) {
const touch = event.touches[0] || event.changedTouches[0]
return { x: touch.x, y: touch.y }
}
function handleTouchStart(event: TouchEvent) {
if (!ctx)
return
const point = getTouchPoint(event)
lastX = point.x
lastY = point.y
drawing = true
}
function handleTouchMove(event: TouchEvent) {
if (!drawing || !ctx)
return
const point = getTouchPoint(event)
ctx.beginPath()
ctx.moveTo(lastX, lastY)
ctx.lineTo(point.x, point.y)
ctx.stroke()
ctx.draw(true)
lastX = point.x
lastY = point.y
hasStroke.value = true
}
function handleTouchEnd() {
drawing = false
}
function handleConfirm() {
if (!hasStroke.value) {
uni.showToast({ title: '请先签名', icon: 'none' })
return
}
uni.canvasToTempFilePath({
canvasId: 'signature-canvas',
success: (res) => {
emit('confirm', res.tempFilePath)
},
fail: () => {
emit('confirm', '')
},
}, instance)
}
function handleClose() {
emit('close')
}
</script>
<template>
<view
v-if="visible"
class="signature-pad"
>
<view class="signature-pad__body">
<view class="signature-pad__actions">
<view
class="signature-pad__action-btn"
@tap="clearCanvas"
>
清除重写
</view>
<view
class="signature-pad__action-btn"
@tap="handleConfirm"
>
确认签署
</view>
</view>
<view class="signature-pad__canvas-wrap">
<canvas
id="signature-canvas"
canvas-id="signature-canvas"
class="signature-pad__canvas"
disable-scroll
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd"
/>
<text
v-if="!hasStroke"
class="signature-pad__placeholder"
>
我是签名
</text>
</view>
</view>
<view
class="signature-pad__close"
@tap="handleClose"
>
<text class="signature-pad__close-icon">
×
</text>
</view>
</view>
</template>
<style scoped lang="scss">
@import './SignaturePad.scss';
</style>