From e3b6f056b870f7f5b90e7c433154e314c2a4c0c4 Mon Sep 17 00:00:00 2001 From: shenyifei Date: Wed, 14 Jan 2026 11:35:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(components):=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=A2=84=E8=A7=88=E7=BB=84=E4=BB=B6=E5=B9=B6=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E4=BA=A4=E4=BB=98=E5=8D=95=E9=A2=84=E8=A7=88=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 ImagePreview 组件支持图片缩放和拖拽功能 - 将 Step2Preview 中的预览逻辑提取到 ImagePreview 组件 - 移除 Step3Success 中的重复利润计算代码 - 添加利润明细表预览功能到成本差异模块 - 优化上传组件支持 PDF 文件类型显示 - 修复 OCR 相机页面闪关灯默认状态问题 - 更新供应商信息识别结果字段映射 - 调整版本号至 v0.0.75 --- .../src/components/biz/ImagePreview.tsx | 139 +++++++++++++ .../app-client/src/components/biz/index.ts | 1 + .../src/components/delivery/Step2Preview.tsx | 188 +++--------------- .../src/components/delivery/Step3Success.tsx | 30 --- .../components/order/document/Step1Form.tsx | 11 +- .../app-client/src/components/order/index.ts | 2 +- .../components/order/module/SupplierInfo.tsx | 1 + .../components/order/module/TicketUpload.tsx | 87 ++++++-- .../order/section/CostDifferenceSection.tsx | 178 ++++++++++++++++- packages/app-client/src/constant/app.ts | 2 +- .../src/pages/delivery/document.tsx | 6 +- .../src/pages/public/camera/ocr.tsx | 2 +- .../src/utils/classes/calculators/index.ts | 1 + .../services/ProfitCalculationService.ts | 34 ++++ .../src/utils/converters/orderConverter.ts | 1 + 15 files changed, 460 insertions(+), 223 deletions(-) create mode 100644 packages/app-client/src/components/biz/ImagePreview.tsx create mode 100644 packages/app-client/src/utils/classes/calculators/services/ProfitCalculationService.ts diff --git a/packages/app-client/src/components/biz/ImagePreview.tsx b/packages/app-client/src/components/biz/ImagePreview.tsx new file mode 100644 index 0000000..7aec986 --- /dev/null +++ b/packages/app-client/src/components/biz/ImagePreview.tsx @@ -0,0 +1,139 @@ +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 ( + + {/* 缩放控制按钮 */} + + + + + + {Math.round(scale * 100)}% + + + + {/* 预览区域 */} + + + {children} + + + + ); +} diff --git a/packages/app-client/src/components/biz/index.ts b/packages/app-client/src/components/biz/index.ts index b30a75e..3935e6c 100644 --- a/packages/app-client/src/components/biz/index.ts +++ b/packages/app-client/src/components/biz/index.ts @@ -10,6 +10,7 @@ export { CustomTheme } from "./CustomTheme"; export { TabBar } from "./TabBar"; export { default as PriceEditor } from "./PriceEditor"; export { default as VersionChecker } from "./VersionChecker"; +export { default as ImagePreview } from "./ImagePreview"; export type { TabBarProps } from "./TabBar"; export * from "./typing"; diff --git a/packages/app-client/src/components/delivery/Step2Preview.tsx b/packages/app-client/src/components/delivery/Step2Preview.tsx index 70987c8..2aaf639 100644 --- a/packages/app-client/src/components/delivery/Step2Preview.tsx +++ b/packages/app-client/src/components/delivery/Step2Preview.tsx @@ -1,6 +1,4 @@ -import { useState } from "react"; -import { Text, View } from "@tarojs/components"; -import { Button } from "@nutui/nutui-react-taro"; +import { ImagePreview } from "@/components"; import { DealerInfo, OtherFees, @@ -20,167 +18,45 @@ interface Step2PreviewProps { export default function Step2Preview(props: Step2PreviewProps) { const { moduleList } = 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 ( - - {/* 缩放控制按钮 */} - - - - - - {Math.round(scale * 100)}% - - + + {moduleList.map((module) => { + if (module.type === "title") { + return ; + } - {/* 预览区域 */} - - - {moduleList.map((module) => { - if (module.type === "title") { - return ; - } + if (module.type === "dealerInfo") { + return ; + } - if (module.type === "dealerInfo") { - return ; - } + if (module.type === "shippingInfo") { + return ; + } - if (module.type === "shippingInfo") { - return ; - } + if (module.type === "weightInfo") { + return ; + } - if (module.type === "weightInfo") { - return ; - } + if (module.type === "packingSpec") { + return ; + } - if (module.type === "packingSpec") { - return ; - } + if (module.type === "vehicleInfo") { + return ; + } - if (module.type === "vehicleInfo") { - return ; - } + if (module.type === "otherFees") { + return ; + } - if (module.type === "otherFees") { - return ; - } + if (module.type === "totalAmount") { + return ; + } - if (module.type === "totalAmount") { - return ; - } - - if (module.type === "otherInfo") { - return ; - } - })} - - - + if (module.type === "otherInfo") { + return ; + } + })} + ); } diff --git a/packages/app-client/src/components/delivery/Step3Success.tsx b/packages/app-client/src/components/delivery/Step3Success.tsx index 5b4345f..8d22154 100644 --- a/packages/app-client/src/components/delivery/Step3Success.tsx +++ b/packages/app-client/src/components/delivery/Step3Success.tsx @@ -6,7 +6,6 @@ import { Icon } from "@/components"; import { business, poster } from "@/services"; import { exportProfitTableExcel, - OrderCalculator, ProfitTableRow, ProfitTableTemplate, } from "@/utils"; @@ -256,35 +255,6 @@ export default function Step3Success(props: Step3SuccessProps) { } }; - // 计算单车的利润数据 - const calculateOrderProfit = (order: BusinessAPI.OrderVO): ProfitTableRow => { - // 车次 - const vehicleNo = `第${order.orderVehicle.vehicleNo || ""}车`; - - // 发货日期 - 从 orderShipList 获取 - const shippingDate = dayjs(order.orderVehicle.deliveryTime).format( - "YYYY/MM/DD", - ); - - const orderCalculator = new OrderCalculator(order); - // 计算产地成本 - const originCost = orderCalculator - .getCostCalculator() - .calculateMelonPurchaseCost(); - // 报价金额 - const quoteAmount = orderCalculator.getSalesAmount(); - // 计算利润 - const profit = orderCalculator.getPersonalProfit(); - - return { - vehicleNo, - shippingDate, - originCost, - quoteAmount, - profit, - }; - }; - // 生成利润表 const generateProfitTable = async () => { try { diff --git a/packages/app-client/src/components/order/document/Step1Form.tsx b/packages/app-client/src/components/order/document/Step1Form.tsx index eb77836..fb41705 100644 --- a/packages/app-client/src/components/order/document/Step1Form.tsx +++ b/packages/app-client/src/components/order/document/Step1Form.tsx @@ -71,7 +71,6 @@ const Step1Form = forwardRef((props, ref) => { const [formErrors, setFormErrors] = useState<{ warehouse?: boolean; estimatedArrivalDate?: boolean; - remark?: boolean; }>({}); // 暴露方法给父组件 @@ -233,7 +232,7 @@ const Step1Form = forwardRef((props, ref) => { 备注