- 新增 ImagePreview 组件支持图片缩放和拖拽功能 - 将 Step2Preview 中的预览逻辑提取到 ImagePreview 组件 - 移除 Step3Success 中的重复利润计算代码 - 添加利润明细表预览功能到成本差异模块 - 优化上传组件支持 PDF 文件类型显示 - 修复 OCR 相机页面闪关灯默认状态问题 - 更新供应商信息识别结果字段映射 - 调整版本号至 v0.0.75
140 lines
4.1 KiB
TypeScript
140 lines
4.1 KiB
TypeScript
import React, { useState } from "react";
|
|
import { Text, View } from "@tarojs/components";
|
|
import { Button } from "@nutui/nutui-react-taro";
|
|
|
|
interface IImagePreview {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export default function ImagePreview(props: IImagePreview) {
|
|
const { children } = props;
|
|
|
|
const [scale, setScale] = useState(0.5); // 缩放比例
|
|
const [touchInfo, setTouchInfo] = useState({
|
|
startDistance: 0,
|
|
startScale: 0.5,
|
|
}); // 触摸信息
|
|
const [position, setPosition] = useState({ x: 0, y: -(29.7 * 37.8 * 0.5) }); // 当前位置
|
|
const [startPosition, setStartPosition] = useState({ x: 0, y: 0 }); // 起始位置
|
|
|
|
// 放大
|
|
const zoomIn = () => {
|
|
setScale((prev) => Math.min(prev + 0.1, 3)); // 最大放大到3倍
|
|
};
|
|
|
|
// 缩小
|
|
const zoomOut = () => {
|
|
setScale((prev) => Math.max(prev - 0.1, 0.5)); // 最小缩小到0.5倍
|
|
};
|
|
|
|
// 重置缩放
|
|
const resetZoom = () => {
|
|
setScale(0.5);
|
|
setPosition({ x: 0, y: -(29.7 * 37.8 * 0.5) }); // 重置位置
|
|
};
|
|
|
|
// 计算两点间距离
|
|
const getDistance = (touches: any) => {
|
|
const dx = touches[0].clientX - touches[1].clientX;
|
|
const dy = touches[0].clientY - touches[1].clientY;
|
|
return Math.sqrt(dx * dx + dy * dy);
|
|
};
|
|
|
|
// 处理触摸开始事件
|
|
const handleTouchStart = (e: any) => {
|
|
const touches = e.touches;
|
|
if (touches.length === 2) {
|
|
// 双指触摸,记录初始距离和当前缩放值
|
|
const distance = getDistance(touches);
|
|
setTouchInfo({
|
|
startDistance: distance,
|
|
startScale: scale,
|
|
});
|
|
} else if (touches.length === 1) {
|
|
// 单指触摸,记录起始位置
|
|
setStartPosition({
|
|
x: touches[0].clientX - position.x,
|
|
y: touches[0].clientY - position.y,
|
|
});
|
|
}
|
|
};
|
|
|
|
// 处理触摸移动事件
|
|
const handleTouchMove = (e: any) => {
|
|
const touches = e.touches;
|
|
e.preventDefault(); // 阻止默认滚动行为
|
|
|
|
if (touches.length === 2) {
|
|
// 双指触摸,计算缩放比例
|
|
const currentDistance = getDistance(touches);
|
|
const newScale =
|
|
touchInfo.startScale * (currentDistance / touchInfo.startDistance);
|
|
// 限制缩放范围在0.5到3之间
|
|
setScale(Math.min(Math.max(0.5, newScale), 3));
|
|
} else if (touches.length === 1 && scale > 0.5) {
|
|
// 单指触摸且已放大,允许拖动
|
|
setPosition({
|
|
x: touches[0].clientX - startPosition.x,
|
|
y: touches[0].clientY - startPosition.y,
|
|
});
|
|
}
|
|
};
|
|
|
|
// 处理触摸结束事件
|
|
const handleTouchEnd = (e: any) => {
|
|
// 可以在这里添加触摸结束后的处理逻辑
|
|
console.log("Touch ended", e);
|
|
};
|
|
|
|
return (
|
|
<View className="flex flex-1 flex-col items-center overflow-hidden">
|
|
{/* 缩放控制按钮 */}
|
|
<View className="mb-2 flex w-full justify-center gap-2 bg-white p-2">
|
|
<Button size="small" onClick={zoomOut}>
|
|
-
|
|
</Button>
|
|
<Button size="small" onClick={resetZoom}>
|
|
重置
|
|
</Button>
|
|
<Button size="small" onClick={zoomIn}>
|
|
+
|
|
</Button>
|
|
<Text className="ml-2 flex items-center">
|
|
{Math.round(scale * 100)}%
|
|
</Text>
|
|
</View>
|
|
|
|
{/* 预览区域 */}
|
|
<View
|
|
className="flex-1 overflow-auto"
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
overflow: "hidden",
|
|
}}
|
|
onTouchStart={handleTouchStart}
|
|
onTouchMove={handleTouchMove}
|
|
onTouchEnd={handleTouchEnd}
|
|
>
|
|
<View
|
|
id="preview"
|
|
className="rounded-lg bg-white shadow-md"
|
|
style={{
|
|
width: "21cm",
|
|
padding: "2cm 1cm 0 1cm",
|
|
margin: "0 auto",
|
|
height: "29.7cm", // A4纸高度
|
|
transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
|
|
transformOrigin: "center center",
|
|
transition:
|
|
scale === touchInfo.startScale ? "transform 0.2s ease" : "none",
|
|
}}
|
|
>
|
|
{children}
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|