feat: 初始化医护端与患者端页面骨架
完成两个 Vite 应用的基础工程化配置、路由、状态管理及第一版业务页面,当前使用演示数据,尚未接入真实后端接口。
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
const hasSignature = ref(false)
|
||||
|
||||
let drawingContext: CanvasRenderingContext2D | null = null
|
||||
let drawing = false
|
||||
|
||||
function resizeCanvas() {
|
||||
const canvas = canvasRef.value
|
||||
if (!canvas) {
|
||||
return
|
||||
}
|
||||
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const ratio = Math.max(window.devicePixelRatio || 1, 1)
|
||||
canvas.width = Math.floor(rect.width * ratio)
|
||||
canvas.height = Math.floor(rect.height * ratio)
|
||||
|
||||
const context = canvas.getContext('2d')
|
||||
if (!context) {
|
||||
return
|
||||
}
|
||||
|
||||
context.setTransform(ratio, 0, 0, ratio, 0, 0)
|
||||
context.lineCap = 'round'
|
||||
context.lineJoin = 'round'
|
||||
context.lineWidth = 2.4
|
||||
context.strokeStyle = '#173b56'
|
||||
drawingContext = context
|
||||
hasSignature.value = false
|
||||
}
|
||||
|
||||
function getPoint(event: PointerEvent) {
|
||||
const canvas = canvasRef.value
|
||||
if (!canvas) {
|
||||
return null
|
||||
}
|
||||
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
return {
|
||||
x: event.clientX - rect.left,
|
||||
y: event.clientY - rect.top,
|
||||
}
|
||||
}
|
||||
|
||||
function startDrawing(event: PointerEvent) {
|
||||
const point = getPoint(event)
|
||||
if (!drawingContext || !point) {
|
||||
return
|
||||
}
|
||||
|
||||
const canvas = canvasRef.value
|
||||
canvas?.setPointerCapture(event.pointerId)
|
||||
drawing = true
|
||||
drawingContext.beginPath()
|
||||
drawingContext.moveTo(point.x, point.y)
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
function draw(event: PointerEvent) {
|
||||
if (!drawing || !drawingContext) {
|
||||
return
|
||||
}
|
||||
|
||||
const point = getPoint(event)
|
||||
if (!point) {
|
||||
return
|
||||
}
|
||||
|
||||
drawingContext.lineTo(point.x, point.y)
|
||||
drawingContext.stroke()
|
||||
hasSignature.value = true
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
function stopDrawing(event: PointerEvent) {
|
||||
const canvas = canvasRef.value
|
||||
if (drawing && canvas?.hasPointerCapture(event.pointerId)) {
|
||||
canvas.releasePointerCapture(event.pointerId)
|
||||
}
|
||||
drawing = false
|
||||
}
|
||||
|
||||
function clearSignature() {
|
||||
const canvas = canvasRef.value
|
||||
if (!canvas || !drawingContext) {
|
||||
return
|
||||
}
|
||||
|
||||
drawingContext.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight)
|
||||
hasSignature.value = false
|
||||
}
|
||||
|
||||
function isEmpty() {
|
||||
return !hasSignature.value
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
resizeCanvas()
|
||||
window.addEventListener('resize', resizeCanvas)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', resizeCanvas)
|
||||
})
|
||||
|
||||
defineExpose({ clearSignature, isEmpty })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="signature-pad">
|
||||
<div class="signature-pad-heading">
|
||||
<span>请在框内手写签名</span>
|
||||
<span class="signature-hint">签名需清晰完整</span>
|
||||
</div>
|
||||
<canvas
|
||||
ref="canvasRef"
|
||||
class="signature-canvas"
|
||||
aria-label="手写签名区域"
|
||||
@pointerdown="startDrawing"
|
||||
@pointermove="draw"
|
||||
@pointerup="stopDrawing"
|
||||
@pointercancel="stopDrawing"
|
||||
@pointerleave="stopDrawing"
|
||||
/>
|
||||
<button class="clear-button" type="button" @click="clearSignature">清除重签</button>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user