feat: 初始化医护端与患者端页面骨架

完成两个 Vite 应用的基础工程化配置、路由、状态管理及第一版业务页面,当前使用演示数据,尚未接入真实后端接口。
This commit is contained in:
yelan
2026-08-27 11:27:16 +08:00
parent 01827bf304
commit 36fa15487c
28 changed files with 2089 additions and 37 deletions
@@ -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>