出库逻辑添加,扫码识别编码成功,后续对应逻辑没有完成

This commit is contained in:
dxc
2026-02-04 17:22:20 +08:00
parent 596f366fc4
commit 797b611530
12 changed files with 919 additions and 28 deletions

View File

@ -0,0 +1,135 @@
<template>
<div class="signature-container">
<canvas
ref="canvasRef"
@mousedown="startDrawing"
@mousemove="draw"
@mouseup="stopDrawing"
@mouseleave="stopDrawing"
@touchstart.prevent="startDrawing"
@touchmove.prevent="draw"
@touchend.prevent="stopDrawing"
></canvas>
<div class="actions">
<el-button size="small" @click="clear">重签</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const canvasRef = ref<HTMLCanvasElement | null>(null)
const isDrawing = ref(false)
const ctx = ref<CanvasRenderingContext2D | null>(null)
// 初始化 Canvas
onMounted(() => {
if (canvasRef.value) {
const canvas = canvasRef.value
// 设置画布大小 (可以根据父容器调整)
canvas.width = canvas.offsetWidth
canvas.height = 300 // 固定高度
ctx.value = canvas.getContext('2d')
if (ctx.value) {
ctx.value.lineWidth = 3
ctx.value.lineCap = 'round'
ctx.value.strokeStyle = '#000'
}
}
})
// 获取坐标 (兼容鼠标和触摸)
const getPos = (e: MouseEvent | TouchEvent) => {
const canvas = canvasRef.value
if (!canvas) return { x: 0, y: 0 }
const rect = canvas.getBoundingClientRect()
let clientX, clientY
if ('touches' in e) {
clientX = e.touches[0].clientX
clientY = e.touches[0].clientY
} else {
clientX = (e as MouseEvent).clientX
clientY = (e as MouseEvent).clientY
}
return {
x: clientX - rect.left,
y: clientY - rect.top
}
}
const startDrawing = (e: MouseEvent | TouchEvent) => {
isDrawing.value = true
const { x, y } = getPos(e)
ctx.value?.beginPath()
ctx.value?.moveTo(x, y)
}
const draw = (e: MouseEvent | TouchEvent) => {
if (!isDrawing.value) return
const { x, y } = getPos(e)
ctx.value?.lineTo(x, y)
ctx.value?.stroke()
}
const stopDrawing = () => {
isDrawing.value = false
}
const clear = () => {
if (canvasRef.value && ctx.value) {
ctx.value.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)
}
}
/**
* 导出签名为 File 对象
*/
const generateFile = (): Promise<File | null> => {
return new Promise((resolve) => {
if (!canvasRef.value) {
resolve(null)
return
}
canvasRef.value.toBlob((blob) => {
if (blob) {
const file = new File([blob], `sign_${Date.now()}.png`, { type: 'image/png' })
resolve(file)
} else {
resolve(null)
}
}, 'image/png')
})
}
// 暴露方法给父组件
defineExpose({
clear,
generateFile
})
</script>
<style scoped>
.signature-container {
border: 1px solid #dcdfe6;
border-radius: 4px;
background: #f5f7fa;
position: relative;
width: 100%;
}
canvas {
display: block;
width: 100%; /* 响应式宽度 */
height: 300px;
cursor: crosshair;
background: #fff;
}
.actions {
position: absolute;
bottom: 10px;
right: 10px;
}
</style>