feat(components): 添加图片预览组件并重构交付单预览功能

- 新增 ImagePreview 组件支持图片缩放和拖拽功能
- 将 Step2Preview 中的预览逻辑提取到 ImagePreview 组件
- 移除 Step3Success 中的重复利润计算代码
- 添加利润明细表预览功能到成本差异模块
- 优化上传组件支持 PDF 文件类型显示
- 修复 OCR 相机页面闪关灯默认状态问题
- 更新供应商信息识别结果字段映射
- 调整版本号至 v0.0.75
This commit is contained in:
shenyifei 2026-01-14 11:35:00 +08:00
parent 0742491943
commit e3b6f056b8
15 changed files with 460 additions and 223 deletions

View File

@ -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 (
<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>
);
}

View File

@ -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";

View File

@ -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 (
<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>
<ImagePreview>
{moduleList.map((module) => {
if (module.type === "title") {
return <TitleInfo key={"title"} module={module} />;
}
{/* 预览区域 */}
<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",
}}
>
{moduleList.map((module) => {
if (module.type === "title") {
return <TitleInfo key={"title"} module={module} />;
}
if (module.type === "dealerInfo") {
return <DealerInfo key={"dealerInfo"} module={module} />;
}
if (module.type === "dealerInfo") {
return <DealerInfo key={"dealerInfo"} module={module} />;
}
if (module.type === "shippingInfo") {
return <ShippingInfo key={"shippingInfo"} module={module} />;
}
if (module.type === "shippingInfo") {
return <ShippingInfo key={"shippingInfo"} module={module} />;
}
if (module.type === "weightInfo") {
return <WeightInfo key={"weightInfo"} module={module} />;
}
if (module.type === "weightInfo") {
return <WeightInfo key={"weightInfo"} module={module} />;
}
if (module.type === "packingSpec") {
return <PackingSpec key={"packingSpec"} module={module} />;
}
if (module.type === "packingSpec") {
return <PackingSpec key={"packingSpec"} module={module} />;
}
if (module.type === "vehicleInfo") {
return <VehicleInfo key={"vehicleInfo"} module={module} />;
}
if (module.type === "vehicleInfo") {
return <VehicleInfo key={"vehicleInfo"} module={module} />;
}
if (module.type === "otherFees") {
return <OtherFees key={"otherFees"} module={module} />;
}
if (module.type === "otherFees") {
return <OtherFees key={"otherFees"} module={module} />;
}
if (module.type === "totalAmount") {
return <TotalAmount key={"totalAmount"} module={module} />;
}
if (module.type === "totalAmount") {
return <TotalAmount key={"totalAmount"} module={module} />;
}
if (module.type === "otherInfo") {
return <OtherInfo key={"otherInfo"} module={module} />;
}
})}
</View>
</View>
</View>
if (module.type === "otherInfo") {
return <OtherInfo key={"otherInfo"} module={module} />;
}
})}
</ImagePreview>
);
}

View File

@ -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 {

View File

@ -71,7 +71,6 @@ const Step1Form = forwardRef<Step1FormRef, Step1FormProps>((props, ref) => {
const [formErrors, setFormErrors] = useState<{
warehouse?: boolean;
estimatedArrivalDate?: boolean;
remark?: boolean;
}>({});
// 暴露方法给父组件
@ -233,7 +232,7 @@ const Step1Form = forwardRef<Step1FormRef, Step1FormProps>((props, ref) => {
</View>
<View
className={`flex w-full items-center rounded-md ${formErrors.remark ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
className={`flex w-full items-center rounded-md border-4 border-gray-300`}
>
<TextArea
className={"flex-1"}
@ -243,14 +242,6 @@ const Step1Form = forwardRef<Step1FormRef, Step1FormProps>((props, ref) => {
showCount
value={orderShipVO?.remark || ""}
onChange={(value) => {
// 清除错误状态
if (formErrors.remark && value) {
setFormErrors((prev) => ({
...prev,
remark: false,
}));
}
setOrderShipVO((prev: any) => {
return {
...prev!,

View File

@ -51,7 +51,7 @@ export type { MarketPriceSectionRef } from "./section/MarketPriceSection";
export { default as RebateCalcSection } from "./section/RebateCalcSection";
export { default as TaxSubsidySection } from "./section/TaxSubsidySection";
export { default as TaxProvisionSection } from "./section/TaxProvisionSection";
export { default as CostDifferenceSection } from "./section/CostDifferenceSection";
export { CostDifferenceSection } from "./section/CostDifferenceSection";
export { default as MaterialCostSection } from "./section/MaterialCostSection";
export { default as ProductionAdvanceSection } from "./section/ProductionAdvanceSection";
export { default as WorkerAdvanceSection } from "./section/WorkerAdvanceSection";

View File

@ -770,6 +770,7 @@ export default forwardRef<SupplierInfoRef, ISupplierInfoProps>(
console.log("识别结果为:", res.result);
setSupplierVO({
...supplierVO,
bankName: res.result.bankName,
bankCard: res.result.number,
});

View File

@ -145,11 +145,21 @@ export default function TicketUpload(props: ITicketUploadProps) {
className="bg-primary/10 flex flex-col gap-2.5 rounded-lg p-2.5"
>
<View className="flex items-center">
<View className="relative mr-3 h-16 w-16 overflow-hidden rounded-lg">
<Image
className="h-full w-full object-cover"
src={uploadFileItem.filePath!}
/>
<View className="relative mr-3 h-16 w-16 flex-shrink-0 overflow-hidden rounded-lg">
{uploadFileItem.fileType !== "pdf" ? (
<Image
className="h-full w-full object-cover"
src={uploadFileItem.filePath!}
/>
) : (
<Icon
className={
"bg-primary/10 flex h-16 w-16 items-center justify-center"
}
name="file-pdf"
size={32}
/>
)}
</View>
<View className="flex-1">
<View className="font-medium" id="invoice-filename">
@ -222,6 +232,14 @@ export default function TicketUpload(props: ITicketUploadProps) {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
if (!url) {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: "上传失败",
});
return Promise.reject();
}
setSupplierVO({
...supplierVO!,
invoiceImg: [
@ -263,6 +281,14 @@ export default function TicketUpload(props: ITicketUploadProps) {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
if (!url) {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: "上传失败",
});
return Promise.reject();
}
setSupplierVO({
...supplierVO!,
invoiceImg: [
@ -319,7 +345,7 @@ export default function TicketUpload(props: ITicketUploadProps) {
className="bg-primary/10 flex flex-col gap-2.5 rounded-lg p-2.5"
>
<View className="flex items-center">
<View className="relative mr-3 h-16 w-16 overflow-hidden rounded-lg">
<View className="relative mr-3 h-16 w-16 flex-shrink-0 overflow-hidden rounded-lg">
<Image
className="h-full w-full object-cover"
src={uploadFileItem.filePath!}
@ -355,6 +381,11 @@ export default function TicketUpload(props: ITicketUploadProps) {
(newContractImg && newContractImg.length > 0) ||
false,
});
Toast.show("toast", {
title: "删除成功",
icon: "success",
content: "合同已删除",
});
}}
>
<View></View>
@ -376,12 +407,22 @@ export default function TicketUpload(props: ITicketUploadProps) {
success: (res) => {
setLoading(true);
const uploadPromises = res.tempFiles.map((file) =>
uploadFile(file.path).then(({ url }) => ({
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
})),
uploadFile(file.path).then(({ url }) => {
if (!url) {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: "上传失败",
});
return Promise.reject();
}
return {
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
};
}),
);
Promise.all(uploadPromises)
@ -438,12 +479,22 @@ export default function TicketUpload(props: ITicketUploadProps) {
success: (res) => {
setLoading(true);
const uploadPromises = res.tempFiles.map((file) =>
uploadFile(file.path).then(({ url }) => ({
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
})),
uploadFile(file.path).then(({ url }) => {
if (!url) {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: "上传失败",
});
return Promise.reject();
}
return {
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
};
}),
);
Promise.all(uploadPromises)

View File

@ -1,8 +1,13 @@
import { Text, View } from "@tarojs/components";
import { OrderCalculator } from "@/utils";
import { PriceEditor } from "@/components";
import { OrderCalculator, ProfitTableRow } from "@/utils";
import { Icon, ImagePreview, PriceEditor } from "@/components";
import { Button, Popup } from "@nutui/nutui-react-taro";
import { useState } from "react";
import dayjs from "dayjs";
import { business } from "@/services";
import { ProfitCalculationService } from "@/utils/classes/calculators";
export default function CostDifferenceSection(props: {
export function CostDifferenceSection(props: {
orderVO: BusinessAPI.OrderVO;
onChange?: (orderVO: BusinessAPI.OrderVO) => void;
readOnly?: boolean;
@ -11,6 +16,74 @@ export default function CostDifferenceSection(props: {
const { orderVO, onChange, readOnly, calculator } = props;
const orderDealer = orderVO.orderDealer;
const [previewVisible, setPreviewVisible] = useState(false);
// 获取当前月份
const currentMonth = dayjs(orderVO.orderVehicle.deliveryTime).format(
"YYYY-MM-01",
);
const [profitData, setProfitData] = useState<ProfitTableRow[]>([]);
const init = async (currentMonth: string) => {
// 查询本月的所有订单数据
let {
data: { data: orderVOList = [] },
} = await business.order.listOrder({
orderListQry: {
dealerId: orderVO.orderDealer.dealerId,
month: currentMonth,
state: "COMPLETED", // 只查询已完成的订单
},
});
orderVOList.push(orderVO);
// 获取当前车次
const currentVehicleNo = orderVO.orderVehicle.vehicleNo;
// 筛选截止到当前车次之前的数据
const profitData: ProfitTableRow[] = [];
let includeNext = true;
// orderVOList 根据车次正序
orderVOList.sort((a, b) => {
return (
Number(a.orderVehicle.vehicleNo) - Number(b.orderVehicle?.vehicleNo)
);
});
for (const order of orderVOList) {
// 如果还没有到达当前车次,继续
if (includeNext) {
const profitRow = ProfitCalculationService.calculateOrderProfit(order);
profitData.push(profitRow);
// 如果是当前车次,停止添加
if (order.orderVehicle.vehicleNo === currentVehicleNo) {
includeNext = false;
}
}
}
setProfitData(profitData);
};
// 预览发货单操作
const handlePreview = () => {
init(currentMonth);
setPreviewVisible(true);
};
// 计算合计
const totalOriginCost = profitData.reduce(
(sum, row) => sum + row.originCost,
0,
);
const totalQuoteAmount = profitData.reduce(
(sum, row) => sum + row.quoteAmount,
0,
);
const totalProfit = profitData.reduce((sum, row) => sum + row.profit, 0);
return (
<View className={"flex flex-col gap-2.5"}>
{/* 卡片形式展示分成信息 */}
@ -56,6 +129,105 @@ export default function CostDifferenceSection(props: {
</View>
</View>
</View>
{/* 预览利润表 */}
<View className={"flex-1"}>
<Button
icon={<Icon name="eye" size={18} />}
size={"large"}
type="primary"
fill="outline"
block
onClick={handlePreview}
>
</Button>
</View>
{/* 预览发货单 */}
<Popup
duration={150}
style={{
minHeight: "auto",
}}
className={"!bg-[#D1D5DB]"}
visible={previewVisible}
position="bottom"
onClose={() => {
setPreviewVisible(false);
}}
closeable
destroyOnClose
title={"预览利润单"}
>
<View className={"overflow-hidden p-2.5"}>
<ImagePreview>
<View className="table-border">
<View className="table-title flex items-end justify-center text-base">
</View>
<View className={"grid w-full grid-cols-5 gap-0 text-base"}>
<View className={"col-span-1 flex items-end justify-center"}>
</View>
<View className={"col-span-1 flex items-end justify-center"}>
</View>
<View className={"col-span-1 flex items-end justify-center"}>
</View>
<View className={"col-span-1 flex items-end justify-center"}>
</View>
<View className={"col-span-1 flex items-end justify-center"}>
</View>
</View>
{profitData.map((row, index) => (
<View
className={"grid w-full grid-cols-5 gap-0 text-base"}
key={index}
>
<View className={"col-span-1 flex items-end justify-center"}>
{row.vehicleNo}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{row.shippingDate}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{row.originCost}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{row.quoteAmount}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{row.profit.toFixed(2)}
</View>
</View>
))}
<View className={"grid w-full grid-cols-5 gap-0 text-base"}>
<View
className={
"col-span-2 flex items-end justify-center bg-yellow-500"
}
>
{dayjs(currentMonth).format("MMMM")}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{totalOriginCost.toFixed(2)}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{totalQuoteAmount.toFixed(2)}
</View>
<View className={"col-span-1 flex items-end justify-center"}>
{totalProfit.toFixed(2)}
</View>
</View>
</View>
</ImagePreview>
</View>
</Popup>
</View>
);
}

View File

@ -1,2 +1,2 @@
// App 相关常量
export const APP_VERSION = "v0.0.73";
export const APP_VERSION = "v0.0.75";

View File

@ -285,9 +285,9 @@ export default hocAuth(function Page(props: CommonComponent) {
}
// 检查预计到仓时间字段是否开启且已填写
else if (column.dataIndex === "requiredEstimatedArrivalTime") {
formData.estimatedArrivalDate = dayjs(
orderShip?.estimatedArrivalDate,
).format("YYYY-MM-DD");
formData.estimatedArrivalDate = orderShip?.estimatedArrivalDate
? dayjs(orderShip?.estimatedArrivalDate).format("YYYY-MM-DD")
: undefined;
}
// 检查备注字段是否开启且已填写
else if (column.dataIndex === "requiredRemarks") {

View File

@ -38,7 +38,7 @@ export default function Page() {
const [data, setData] = useState({
skipphotoStatus: "0",
flash: true,
flash: false,
bottom: 125,
windowWidth: 300,
touchPadding: 36,

View File

@ -7,3 +7,4 @@
export { OrderCalculator } from "./OrderCalculator";
export { WeightCalculationService } from "./services/WeightCalculationService";
export { ProfitCalculationService } from "./services/ProfitCalculationService";

View File

@ -0,0 +1,34 @@
import { OrderCalculator, ProfitTableRow } from "@/utils";
import dayjs from "dayjs";
export class ProfitCalculationService {
// 计算单车的利润数据
static 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,
};
}
}

View File

@ -121,5 +121,6 @@ export const convertOrderToOrderShip = (
state: "WAIT_PAYMENT",
receivableAmount: calculator.getMarketPrice(),
orderShipItemList,
remark: oldOrderShip?.remark || "",
};
};