Initial commit

This commit is contained in:
yuchenglong
2025-11-20 10:00:02 +08:00
commit 8aa5f7802f
147 changed files with 132905 additions and 0 deletions

284
src/pages/UI7/UI7.tsx Normal file
View File

@@ -0,0 +1,284 @@
import React, { useState, useEffect, useRef } from "react";
import "./UI7.css";
import "../../assets/css/basic.css";
import { useNavigate } from "react-router-dom";
import BackButton from "../../components/BackButton";
import ConfirmButton from "../../components/ConfirmButton";
import DecorLine from "../../components/DecorLine";
import WaitButton from "../../components/WaitButton";
const UI6: React.FC = () => {
const navigate = useNavigate();
const [countdown, setCountdown] = useState(5);
const [showWaitButton, setShowWaitButton] = useState(true);
const canvasRef = useRef<HTMLCanvasElement>(null);
const [isDrawing, setIsDrawing] = useState(false);
const dprRef = useRef<number>(1);
const lastPointRef = useRef<{ x: number; y: number } | null>(null);
useEffect(() => {
if (countdown > 0) {
const timer = setTimeout(() => {
setCountdown(countdown - 1);
}, 1000);
return () => clearTimeout(timer);
} else {
setShowWaitButton(false);
}
}, [countdown]);
useEffect(() => {
const initCanvas = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d", {
willReadFrequently: false,
alpha: true
});
if (!ctx) return;
// 获取 canvas 的显示尺寸
const rect = canvas.getBoundingClientRect();
// 使用更高的缩放倍数3倍来提高分辨率
const scale = 3;
dprRef.current = scale;
// 设置 canvas 内部尺寸高分辨率3倍
canvas.width = rect.width * scale;
canvas.height = rect.height * scale;
// 缩放上下文以匹配显示尺寸
ctx.scale(scale, scale);
// 设置 canvas 的 CSS 尺寸为显示尺寸
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;
// 设置绘制样式(启用抗锯齿,优化参数)
ctx.strokeStyle = "#000000";
ctx.lineWidth = 2;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
ctx.globalCompositeOperation = "source-over";
};
// 延迟初始化以确保 DOM 完全渲染
const timer = setTimeout(initCanvas, 100);
return () => clearTimeout(timer);
}, []);
const getCoordinates = (e: React.MouseEvent<HTMLCanvasElement> | React.TouchEvent<HTMLCanvasElement>) => {
const canvas = canvasRef.current;
if (!canvas) return { x: 0, y: 0 };
const rect = canvas.getBoundingClientRect();
if ("touches" in e) {
return {
x: e.touches[0].clientX - rect.left,
y: e.touches[0].clientY - rect.top,
};
} else {
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top,
};
}
};
const startDrawing = (e: React.MouseEvent<HTMLCanvasElement> | React.TouchEvent<HTMLCanvasElement>) => {
e.preventDefault();
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const { x, y } = getCoordinates(e);
// 记录起始点
lastPointRef.current = { x, y };
ctx.beginPath();
ctx.moveTo(x, y);
setIsDrawing(true);
};
const draw = (e: React.MouseEvent<HTMLCanvasElement> | React.TouchEvent<HTMLCanvasElement>) => {
e.preventDefault();
if (!isDrawing || !lastPointRef.current) return;
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
const { x, y } = getCoordinates(e);
const lastPoint = lastPointRef.current;
// 使用二次贝塞尔曲线平滑绘制
const midX = (lastPoint.x + x) / 2;
const midY = (lastPoint.y + y) / 2;
ctx.quadraticCurveTo(lastPoint.x, lastPoint.y, midX, midY);
ctx.stroke();
// 更新最后一个点
lastPointRef.current = { x, y };
};
const stopDrawing = () => {
setIsDrawing(false);
lastPointRef.current = null;
};
const clearCanvas = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
// 清除整个 canvas使用显示坐标系统
const rect = canvas.getBoundingClientRect();
ctx.clearRect(0, 0, rect.width, rect.height);
// 重新初始化绘制样式
ctx.strokeStyle = "#000000";
ctx.lineWidth = 2;
ctx.lineCap = "round";
ctx.lineJoin = "round";
};
const handleBack = () => {
navigate(-1);
};
const handleConfirm = () => {
const canvas = canvasRef.current;
if (!canvas) {
navigate("/UI7");
return;
}
// 下载签名图片
canvas.toBlob((blob) => {
if (!blob) return;
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `签名_${new Date().getTime()}.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, "image/png");
navigate("/UI7");
};
return (
<div className="basic-root">
<div className="basic-white-block">
<div className="basic-content">
<span className="basic-title"></span>
<DecorLine />
<div className="ui7-text-wrapper">
<div className="ui7-text-content">
<span className="paragraph_1">
<br />
<br />
<br />
<br />
<br />
<br />
1.
<br />
<br />
2.
<br />
<br />
3.
<br />
B超等项目需空腹8小时以上
<br />
4.
<br />
CT等
<br />
5.
<br />
<br />
<br />
<br />
<br />
<br />
1.
<br />
<br />
2.
<br />
<br />
3.
<br />
X射线CT
<br />
<br />
</span>
</div>
</div>
<span className="ui7-text_4"></span>
<div className="ui7-signature-wrapper">
<canvas
ref={canvasRef}
className="ui7-signature-canvas"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseLeave={stopDrawing}
onTouchStart={startDrawing}
onTouchMove={draw}
onTouchEnd={stopDrawing}
/>
<button className="ui7-clear-button" onClick={clearCanvas}>
</button>
</div>
<div className="basic-confirm-section">
<BackButton text="返回" onClick={handleBack} />
{showWaitButton ? (
<WaitButton text={`等待(${countdown})S`} onClick={handleConfirm} />
) : (
<ConfirmButton text="提交" onClick={handleConfirm} />
)}
</div>
</div>
</div>
</div>
);
};
export default UI6;