- 统一处理 purchaseOrderVO.orderDealer 可能为空的情况,避免运行时错误 - 修复多个组件中颜色样式结尾多余的分号导致的渲染异常 - 调整 OrderCost 组件中 selected 状态的判断逻辑,确保 count 大于 0 才选中 - 优化 PurchasePreview 组件中空箱使用明细的条件渲染,仅在有数据时显示 - 完善成本校验逻辑,在没有启用的"我方"费用项时标记为有效 - 修正 WorkerAdvanceSection 中费用类型的初始值设置错误 - 更新市场报价计算逻辑,根据是否包含包装费标志位决定计算方式 - 加强 SupplierWeightCalculator 中数值计算的空值防护,防止 NaN问题 - 移除冗余的控制台日志输出,清理调试代码- 调整部分组件结构和类名,提升代码可读性和一致性
2370 lines
88 KiB
TypeScript
2370 lines
88 KiB
TypeScript
import hocAuth from "@/hocs/auth";
|
||
import { CommonComponent } from "@/types/typings";
|
||
import { ReactNode, useEffect, useRef, useState } from "react";
|
||
import { Text, View } from "@tarojs/components";
|
||
import {
|
||
Button,
|
||
DatePicker,
|
||
Dialog,
|
||
Input,
|
||
PickerOption,
|
||
SafeArea,
|
||
Step,
|
||
Steps,
|
||
Toast,
|
||
} from "@nutui/nutui-react-taro";
|
||
import shipOrder from "@/constant/shipOrder";
|
||
import Taro from "@tarojs/taro";
|
||
import classNames from "classnames";
|
||
import { business } from "@/services";
|
||
import dayjs from "dayjs";
|
||
import buildUrl from "@/utils/buildUrl";
|
||
import { Icon } from "@/components";
|
||
|
||
export default hocAuth(function Page(props: CommonComponent) {
|
||
const { router, setLoading } = props;
|
||
const shipOrderId = router.params
|
||
.shipOrderId as BusinessAPI.ShipOrderVO["shipOrderId"];
|
||
|
||
// 当天和未来10天
|
||
const startDate = new Date();
|
||
const endDate = new Date(startDate.getTime() + 86400000 * 10);
|
||
const [show, setShow] = useState(false);
|
||
|
||
const formatter = (type: string, option: PickerOption) => {
|
||
switch (type) {
|
||
case "year":
|
||
option.label += "年";
|
||
break;
|
||
case "month":
|
||
option.label += "月";
|
||
break;
|
||
case "day":
|
||
option.label += "日";
|
||
break;
|
||
case "hour":
|
||
option.label += "时";
|
||
break;
|
||
case "minute":
|
||
option.label += "分";
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return option;
|
||
};
|
||
|
||
const [scale, setScale] = useState(0.5); // 缩放比例
|
||
const [step, setStep] = useState(1);
|
||
const [moduleList, setModuleList] = useState<any[]>([]);
|
||
const [height, setHeight] = useState<number>();
|
||
const [shipOrderVO, setShipOrderVO] = useState<BusinessAPI.ShipOrderVO>();
|
||
const [deliveryTemplate, setDeliveryTemplate] = useState<string>();
|
||
const [purchaseDocument, setPurchaseDocument] = useState<string>();
|
||
|
||
const [tempFilePath, setTempFilePath] = useState<string>();
|
||
|
||
// 表单错误状态
|
||
const [formErrors, setFormErrors] = useState<{
|
||
watermelonGrade?: boolean;
|
||
shippingAddress?: boolean;
|
||
estimatedArrivalDate?: boolean;
|
||
remark?: boolean;
|
||
itemGrades?: { [key: string]: boolean };
|
||
}>({});
|
||
|
||
const init = async (shipOrderId: BusinessAPI.ShipOrderVO["shipOrderId"]) => {
|
||
setLoading(true);
|
||
const { data } = await business.shipOrder.showShipOrder({
|
||
shipOrderShowQry: {
|
||
shipOrderId,
|
||
},
|
||
});
|
||
const shipOrderVO = data.data;
|
||
if (shipOrderVO) {
|
||
setShipOrderVO(shipOrderVO);
|
||
if (shipOrderVO.purchaseDocument) {
|
||
setStep(3);
|
||
setPurchaseDocument(shipOrderVO.purchaseDocument);
|
||
}
|
||
|
||
const { data } = await business.dealer.showDealer({
|
||
dealerShowQry: {
|
||
dealerId: shipOrderVO.dealerId,
|
||
},
|
||
});
|
||
|
||
setDeliveryTemplate(data.data?.deliveryTemplate!);
|
||
}
|
||
setLoading(false);
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (shipOrderId) {
|
||
init(shipOrderId).then();
|
||
}
|
||
}, [shipOrderId]);
|
||
|
||
useEffect(() => {
|
||
if (deliveryTemplate && shipOrderVO) {
|
||
const template = JSON.parse(deliveryTemplate);
|
||
// 将 shipOrderVO 转换为 examples 的数据格式,然后再替换 moduleList 里面的 config 数据
|
||
const convertedData = convertShipOrderVOToExamplesFormat(shipOrderVO);
|
||
const updatedTemplate = updateTemplateConfig(template, convertedData);
|
||
setModuleList(updatedTemplate);
|
||
}
|
||
}, [shipOrderVO, deliveryTemplate]);
|
||
|
||
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 }); // 起始位置
|
||
|
||
// 将 shipOrderVO 转换为 examples 的数据格式
|
||
const convertShipOrderVOToExamplesFormat = (
|
||
shipOrderVO: BusinessAPI.ShipOrderVO,
|
||
) => {
|
||
return {
|
||
title: {
|
||
title: "西瓜发货清单",
|
||
},
|
||
dealerInfo: {
|
||
dealerName: shipOrderVO.dealerName || "",
|
||
vehicleNumber: `第 ${shipOrderVO.vehicleNo || ""} 车`,
|
||
destination: shipOrderVO.receivingAddress || "",
|
||
watermelonGrade: shipOrderVO.watermelonGrade || "",
|
||
},
|
||
shippingInfo: {
|
||
shippingFrom: shipOrderVO.shippingAddress || "",
|
||
date: shipOrderVO.shippingDate || "",
|
||
},
|
||
weightInfo: {
|
||
data: shipOrderVO.shipOrderItemList,
|
||
accountCompany: shipOrderVO.companyName || "",
|
||
sumAmount:
|
||
shipOrderVO.shipOrderItemList?.reduce(
|
||
(acc, item) => acc + item?.totalAmount!,
|
||
0,
|
||
) || "",
|
||
},
|
||
packingSpec: {
|
||
data:
|
||
shipOrderVO.shipOrderPackageList?.map((item) => ({
|
||
boxSpecId: item.boxSpecId || "",
|
||
boxSpecName: item.boxSpecName || "",
|
||
boxType: item.boxProduct || "",
|
||
quantity: item.quantity?.toString() || "",
|
||
unitPrice: item.unitPrice?.toString() || "",
|
||
amount: item.itemAmount?.toString() || "",
|
||
unitWeight: item.singleWeight?.toString() || "",
|
||
weight: item.totalWeight?.toString() || "",
|
||
})) || [],
|
||
},
|
||
vehicleInfo: {
|
||
driverPhone: shipOrderVO?.driverPhone || "",
|
||
licensePlate: shipOrderVO.licensePlate || "",
|
||
estimatedArrivalTime: shipOrderVO.estimatedArrivalDate
|
||
? dayjs(shipOrderVO?.estimatedArrivalDate).format("YYYY年MM月DD日")
|
||
: "",
|
||
freightDebt: shipOrderVO.freightDebt?.toString() || "",
|
||
strawMatDebt: shipOrderVO.strawMatDebt?.toString() || "",
|
||
remarks: shipOrderVO.remark || "",
|
||
},
|
||
otherFees: {
|
||
trademark: shipOrderVO.trademarkFee?.toString() || "",
|
||
labor: shipOrderVO.laborFee?.toString() || "",
|
||
paperBox: shipOrderVO.cartonFee?.toString() || "",
|
||
fee: shipOrderVO.provisionFee?.toString() || "",
|
||
codingFee: shipOrderVO.codingFee?.toString() || "",
|
||
},
|
||
totalAmount: {
|
||
amount: shipOrderVO.totalAmount?.toString() || "",
|
||
farmer: shipOrderVO.farmerInfo || "",
|
||
},
|
||
otherInfo: {
|
||
origin: "",
|
||
supplier: "",
|
||
departureTime: "",
|
||
arrivalTime: "",
|
||
productName: "",
|
||
},
|
||
};
|
||
};
|
||
|
||
// 更新模板配置
|
||
const updateTemplateConfig = (template: any[], data: any) => {
|
||
return template.map((module: any) => {
|
||
const newModule = { ...module };
|
||
if (data[module.type]) {
|
||
newModule.config = { ...module.config, ...data[module.type] };
|
||
}
|
||
return newModule;
|
||
});
|
||
};
|
||
|
||
// 渲染内容配置表单字段
|
||
const renderContentFields = (module) => {
|
||
const contentSchema = module.schemas.find(
|
||
(schema) => schema.title === "内容配置",
|
||
);
|
||
if (
|
||
!contentSchema ||
|
||
!contentSchema.columns ||
|
||
contentSchema.columns.length === 0
|
||
) {
|
||
return null;
|
||
}
|
||
|
||
const contentFields: ReactNode[] = [];
|
||
|
||
contentSchema.columns.forEach((column: any, index: number) => {
|
||
if (
|
||
column.dataIndex === "requiredWatermelonGrade" &&
|
||
module.config.showWatermelonGrade
|
||
) {
|
||
contentFields.push(
|
||
<View key={index} className="mb-2.5">
|
||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||
{column.title}
|
||
</View>
|
||
<View className="mb-2.5">
|
||
<View
|
||
className={`flex h-10 w-full items-center rounded-md ${formErrors.watermelonGrade ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||
>
|
||
<Input
|
||
value={shipOrderVO?.watermelonGrade || ""}
|
||
onChange={(value) => {
|
||
// 清除错误状态
|
||
if (formErrors.watermelonGrade && value) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
watermelonGrade: false,
|
||
}));
|
||
}
|
||
|
||
setShipOrderVO((prev) => {
|
||
return {
|
||
...prev!,
|
||
watermelonGrade: value,
|
||
};
|
||
});
|
||
}}
|
||
onBlur={() => {
|
||
// 失焦时校验
|
||
if (!shipOrderVO?.watermelonGrade) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
watermelonGrade: true,
|
||
}));
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title:
|
||
column.fieldProps?.placeholder ||
|
||
`请填写${column.title}`,
|
||
});
|
||
}
|
||
}}
|
||
placeholder={
|
||
column.fieldProps?.placeholder || `请${column.title}`
|
||
}
|
||
type="text"
|
||
className="flex-1"
|
||
/>
|
||
</View>
|
||
|
||
{formErrors.watermelonGrade && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
{`请${column.title}`}
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>,
|
||
);
|
||
}
|
||
|
||
if (
|
||
column.dataIndex === "requiredShippingFrom" &&
|
||
module.config.showShippingFrom
|
||
) {
|
||
contentFields.push(
|
||
<View key={index} className="mb-2.5">
|
||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||
{column.title}
|
||
</View>
|
||
<View className="mb-2.5">
|
||
<View
|
||
className={`flex h-10 w-full items-center rounded-md ${formErrors.shippingAddress ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||
>
|
||
<Input
|
||
value={shipOrderVO?.shippingAddress || ""}
|
||
onChange={(value) => {
|
||
// 清除错误状态
|
||
if (formErrors.shippingAddress && value) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
shippingAddress: false,
|
||
}));
|
||
}
|
||
|
||
setShipOrderVO((prev) => {
|
||
return {
|
||
...prev!,
|
||
shippingAddress: value,
|
||
};
|
||
});
|
||
}}
|
||
onBlur={() => {
|
||
// 失焦时校验
|
||
if (!shipOrderVO?.shippingAddress) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
shippingAddress: true,
|
||
}));
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title:
|
||
column.fieldProps?.placeholder ||
|
||
`请填写${column.title}`,
|
||
});
|
||
}
|
||
}}
|
||
placeholder={
|
||
column.fieldProps?.placeholder || `请${column.title}`
|
||
}
|
||
type="text"
|
||
className="flex-1"
|
||
/>
|
||
</View>
|
||
|
||
{formErrors.shippingAddress && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
{`请${column.title}`}
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>,
|
||
);
|
||
}
|
||
|
||
if (
|
||
column.dataIndex === "requiredEstimatedArrivalTime" &&
|
||
module.config.showEstimatedArrivalTime
|
||
) {
|
||
contentFields.push(
|
||
<View key={index} className="mb-2.5">
|
||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||
{column.title}
|
||
</View>
|
||
<View className="mb-2.5">
|
||
<View
|
||
className={`flex h-10 w-full items-center rounded-md ${formErrors.estimatedArrivalDate ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||
>
|
||
<View
|
||
className={
|
||
"flex flex-1 flex-row items-center justify-between px-5"
|
||
}
|
||
style={{
|
||
color: "var(--nutui-color-title, #1a1a1a)",
|
||
}}
|
||
onClick={() => setShow(true)}
|
||
>
|
||
<View className={"text-sm"}>
|
||
{shipOrderVO?.estimatedArrivalDate
|
||
? dayjs(shipOrderVO?.estimatedArrivalDate).format(
|
||
"YYYY年MM月DD日",
|
||
)
|
||
: column.fieldProps?.placeholder || `请${column.title}`}
|
||
</View>
|
||
<Icon name={"chevron-down"} />
|
||
</View>
|
||
<DatePicker
|
||
title="发货时间选择"
|
||
type="date"
|
||
startDate={startDate}
|
||
endDate={endDate}
|
||
visible={show}
|
||
defaultValue={new Date()}
|
||
formatter={formatter}
|
||
onClose={() => setShow(false)}
|
||
onConfirm={(_, values) => {
|
||
// 选择日期后清除错误状态
|
||
if (formErrors.estimatedArrivalDate) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
estimatedArrivalDate: false,
|
||
}));
|
||
}
|
||
|
||
setShipOrderVO((prev) => {
|
||
return {
|
||
...prev!,
|
||
estimatedArrivalDate: dayjs(values.join("-")).format(
|
||
"YYYY-MM-DD",
|
||
),
|
||
};
|
||
});
|
||
}}
|
||
/>
|
||
</View>
|
||
|
||
{formErrors.estimatedArrivalDate && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
{`请${column.title}`}
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>,
|
||
);
|
||
}
|
||
|
||
if (column.dataIndex === "requiredRemarks" && module.config.showRemarks) {
|
||
contentFields.push(
|
||
<View key={index} className="mb-2.5">
|
||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||
{column.title}
|
||
</View>
|
||
<View className="mb-2.5">
|
||
<View
|
||
className={`flex h-10 w-full items-center rounded-md ${formErrors.remark ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||
>
|
||
<Input
|
||
value={shipOrderVO?.remark || ""}
|
||
onChange={(value) => {
|
||
// 清除错误状态
|
||
if (formErrors.remark && value) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
remark: false,
|
||
}));
|
||
}
|
||
|
||
setShipOrderVO((prev) => {
|
||
return {
|
||
...prev!,
|
||
remark: value,
|
||
};
|
||
});
|
||
}}
|
||
onBlur={() => {
|
||
// 失焦时校验
|
||
if (!shipOrderVO?.remark) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
remark: true,
|
||
}));
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title:
|
||
column.fieldProps?.placeholder ||
|
||
`请填写${column.title}`,
|
||
});
|
||
}
|
||
}}
|
||
placeholder={
|
||
column.fieldProps?.placeholder || `请${column.title}`
|
||
}
|
||
type="text"
|
||
className="flex-1"
|
||
/>
|
||
</View>
|
||
|
||
{formErrors.remark && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
{`请${column.title}`}
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>,
|
||
);
|
||
}
|
||
|
||
if (column.dataIndex === "requiredGrade" && module.config.showGrade) {
|
||
contentFields.push(
|
||
<View key={index} className="mb-2.5">
|
||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||
{column.title}
|
||
</View>
|
||
{shipOrderVO?.shipOrderItemList?.map((shipOrderItem, index) => {
|
||
return (
|
||
<View key={"shipOrderItem" + index} className="mb-2.5">
|
||
<View
|
||
key={shipOrderItem.itemId}
|
||
className={"flex flex-row gap-2.5"}
|
||
>
|
||
<View className="flex flex-1 items-center text-sm font-normal text-[#000000]">
|
||
单价:{shipOrderItem.unitPrice} 元/斤
|
||
</View>
|
||
|
||
<View
|
||
className={`flex h-10 items-center rounded-md ${formErrors.itemGrades?.[shipOrderItem.itemId] ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||
>
|
||
<Input
|
||
value={shipOrderItem.watermelonGrade || ""}
|
||
onChange={(value) => {
|
||
// 清除该项的错误状态
|
||
if (
|
||
formErrors.itemGrades?.[shipOrderItem.itemId] &&
|
||
value
|
||
) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
itemGrades: {
|
||
...prev.itemGrades,
|
||
[shipOrderItem.itemId]: false,
|
||
},
|
||
}));
|
||
}
|
||
|
||
setShipOrderVO((prev) => {
|
||
return {
|
||
...prev!,
|
||
shipOrderItemList: prev?.shipOrderItemList?.map(
|
||
(item) => {
|
||
if (item.itemId === shipOrderItem.itemId) {
|
||
return {
|
||
...item,
|
||
watermelonGrade: value,
|
||
};
|
||
}
|
||
return item;
|
||
},
|
||
),
|
||
};
|
||
});
|
||
}}
|
||
onBlur={() => {
|
||
// 失焦时校验
|
||
if (!shipOrderItem.watermelonGrade) {
|
||
setFormErrors((prev) => ({
|
||
...prev,
|
||
itemGrades: {
|
||
...prev.itemGrades,
|
||
[shipOrderItem.itemId]: true,
|
||
},
|
||
}));
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title:
|
||
column.fieldProps?.placeholder ||
|
||
`请填写第${index + 1}项的品级`,
|
||
});
|
||
}
|
||
}}
|
||
placeholder={
|
||
column.fieldProps?.placeholder || `请${column.title}`
|
||
}
|
||
type="text"
|
||
className="flex-1"
|
||
/>
|
||
</View>
|
||
</View>
|
||
|
||
{formErrors.itemGrades?.[shipOrderItem.itemId] && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
{`请${column.title}`}
|
||
</View>
|
||
)}
|
||
</View>
|
||
);
|
||
})}
|
||
</View>,
|
||
);
|
||
}
|
||
});
|
||
|
||
if (contentFields.length > 0) {
|
||
return contentFields;
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
// 表单校验
|
||
const validateForm = () => {
|
||
const errors: any = {};
|
||
let hasErrors = false;
|
||
|
||
// 检查各模块中的必填字段是否已填写
|
||
for (const module of moduleList) {
|
||
const contentSchema = module.schemas.find(
|
||
(schema) => schema.title === "内容配置",
|
||
);
|
||
|
||
if (
|
||
!contentSchema ||
|
||
!contentSchema.columns ||
|
||
contentSchema.columns.length === 0
|
||
) {
|
||
continue;
|
||
}
|
||
|
||
for (const column of contentSchema.columns) {
|
||
// 检查西瓜品级字段是否开启且已填写
|
||
if (
|
||
column.dataIndex === "requiredWatermelonGrade" &&
|
||
module.config.showWatermelonGrade
|
||
) {
|
||
if (!shipOrderVO?.watermelonGrade) {
|
||
errors.watermelonGrade = true;
|
||
hasErrors = true;
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: column.fieldProps?.placeholder || `请填写${column.title}`,
|
||
});
|
||
}
|
||
}
|
||
// 检查发货地字段是否开启且已填写
|
||
else if (
|
||
column.dataIndex === "requiredShippingFrom" &&
|
||
module.config.showShippingFrom
|
||
) {
|
||
if (!shipOrderVO?.shippingAddress) {
|
||
errors.shippingAddress = true;
|
||
hasErrors = true;
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: column.fieldProps?.placeholder || `请填写${column.title}`,
|
||
});
|
||
}
|
||
}
|
||
// 检查预计到仓时间字段是否开启且已填写
|
||
else if (
|
||
column.dataIndex === "requiredEstimatedArrivalTime" &&
|
||
module.config.showEstimatedArrivalTime
|
||
) {
|
||
if (!shipOrderVO?.estimatedArrivalDate) {
|
||
errors.estimatedArrivalDate = true;
|
||
hasErrors = true;
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: column.fieldProps?.placeholder || `请选择${column.title}`,
|
||
});
|
||
}
|
||
}
|
||
// 检查备注字段是否开启且已填写
|
||
else if (
|
||
column.dataIndex === "requiredRemarks" &&
|
||
module.config.showRemarks
|
||
) {
|
||
if (!shipOrderVO?.remark) {
|
||
errors.remark = true;
|
||
hasErrors = true;
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: column.fieldProps?.placeholder || `请填写${column.title}`,
|
||
});
|
||
}
|
||
}
|
||
// 检查品级字段是否开启且已填写
|
||
else if (
|
||
column.dataIndex === "requiredGrade" &&
|
||
module.config.showGrade
|
||
) {
|
||
if (shipOrderVO?.shipOrderItemList) {
|
||
const itemGradesErrors: { [key: string]: boolean } = {};
|
||
for (let i = 0; i < shipOrderVO.shipOrderItemList.length; i++) {
|
||
const item = shipOrderVO.shipOrderItemList[i];
|
||
if (!item.watermelonGrade) {
|
||
itemGradesErrors[item.itemId] = true;
|
||
hasErrors = true;
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: `请填写第${i + 1}项的品级`,
|
||
});
|
||
}
|
||
}
|
||
|
||
if (Object.keys(itemGradesErrors).length > 0) {
|
||
errors.itemGrades = itemGradesErrors;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
setFormErrors(errors);
|
||
return !hasErrors;
|
||
};
|
||
|
||
// 预览确认
|
||
const previewAndConfirm = () => {
|
||
console.log(step);
|
||
if (step === 1) {
|
||
// 在第一步时校验表单
|
||
if (!validateForm()) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (step === 2) {
|
||
// 显示确认对话框
|
||
Dialog.open("dialog", {
|
||
title: "生成发货单据",
|
||
content: "即将生成发货单据,请确认发货单据是否正确。",
|
||
confirmText: "确认生成",
|
||
cancelText: "取消",
|
||
onConfirm: async () => {
|
||
// 截图预览内容
|
||
await capturePreview();
|
||
Dialog.close("dialog");
|
||
// 进入第三步
|
||
setStep(3);
|
||
},
|
||
onCancel: () => {
|
||
Dialog.close("dialog");
|
||
},
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (step < 3) {
|
||
setStep(step + 1);
|
||
}
|
||
};
|
||
|
||
// 生成发货单据
|
||
const generateShippingDocument = async () => {
|
||
// 显示确认对话框
|
||
Dialog.open("dialog", {
|
||
title: "生成发货单据",
|
||
content: "即将生成发货单据,请确认发货单据是否正确。",
|
||
confirmText: "确认生成",
|
||
cancelText: "取消",
|
||
onConfirm: async () => {
|
||
// 截图预览内容
|
||
await capturePreview();
|
||
Dialog.close("dialog");
|
||
// 进入第三步
|
||
setStep(3);
|
||
},
|
||
onCancel: () => {
|
||
Dialog.close("dialog");
|
||
},
|
||
});
|
||
};
|
||
|
||
// 将预览内容转换为HTML字符串的函数
|
||
const generateHtmlString = () => {
|
||
let htmlString = `
|
||
<style> @page {size: 210mm 297mm;margin: 0;padding: 0;}* {outline: none;box-sizing: border-box;margin: 0;padding: 0;border: 0 solid;}body {background-color: #fff;color: #4d4d4d;font-size: 14px;font-style: normal;box-sizing: border-box;}.page-wrap {width: 210mm;min-height: 297mm;margin: 0 auto;}.page-content {position: relative;box-sizing: border-box;width: 100%;height: 100%;padding: 20mm 10mm 0;display: flex;flex-direction: column;gap: 2mm;}@media print {.print-controls {display: none !important;}body {padding: 0;margin: 0;}}.print-module {margin-bottom: 15px;text-align: center;}.print-controls {position: fixed;top: 10px;right: 10px;z-index: 9999;}.print-button,.close-button {padding: 8px 16px;margin-left: 10px;cursor: pointer;border: 1px solid #d9d9d9;border-radius: 4px;}.print-button {background-color: #1890ff;color: white;}.close-button {background-color: #fff;color: #000;}.preview {width: 19cm;div {height: 0.7cm;}}.table-border {border: 2px solid #000;}.table-border>div {border-bottom: 1px solid #000;}.table-border>div>div {border-right: 1px solid #000;}.table-border>div>div:last-child {border-right: none;}.table-border>div:last-child {border-bottom: none;}.col-span-1 {grid-column: span 1 / span 1;}.col-span-2 {grid-column: span 2 / span 2;}.col-span-3 {grid-column: span 3 / span 3;}.col-span-6 {grid-column: span 6 / span 6;}.col-span-8 {grid-column: span 8 / span 8;}.flex {display: flex;}.items-center {align-items: center;}.grid {display: grid;}.w-full {width: 100%;}.grid-cols-1 {grid-template-columns: repeat(1, minmax(0, 1fr));}.grid-cols-2 {grid-template-columns: repeat(2, minmax(0, 1fr));}.grid-cols-3 {grid-template-columns: repeat(3, minmax(0, 1fr));}.grid-cols-4 {grid-template-columns: repeat(4, minmax(0, 1fr));}.grid-cols-5 {grid-template-columns: repeat(5, minmax(0, 1fr));}.grid-cols-6 {grid-template-columns: repeat(6, minmax(0, 1fr));}.grid-cols-7 {grid-template-columns: repeat(7, minmax(0, 1fr));}.grid-cols-8 {grid-template-columns: repeat(8, minmax(0, 1fr));}.items-end {align-items: flex-end;}.justify-center {justify-content: center;}.border-t-0 {border-top-width: 0px;}.border-b {border-bottom-width: 1px;}.border-black {border-color: #000000;}.bg-white {background-color: #ffffff;}.text-2xl {font-size: 24px;line-height: 1;}.text-base {font-size: 16px;line-height: 1;}.text-lg {font-size: 18px;line-height: 1;}.font-bold {font-weight: bold;}.preview {width: 19cm;div {height: 0.69cm;}}.table-border {border: 2px solid #000;}.table-border>div {border-bottom: 1px solid #000;}.table-border>div>div {border-right: 1px solid #000;}.table-border>div>div:last-child {border-right: none;}.table-border>div:last-child {border-bottom: none;} </style>
|
||
<div class="page-wrap">
|
||
<div class="page-content">
|
||
`;
|
||
|
||
moduleList.forEach((module) => {
|
||
const config = module.config;
|
||
|
||
if (module.type === "title") {
|
||
htmlString += `
|
||
<div class="preview grid w-full grid-cols-8 gap-0 text-2xl font-bold">
|
||
<div class="col-span-8 flex items-end justify-center">
|
||
${config.title || ""}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (module.type === "dealerInfo") {
|
||
htmlString += `
|
||
<div class="preview grid w-full grid-cols-8 gap-0 text-lg font-bold">
|
||
<div class="col-span-1"></div>
|
||
`;
|
||
|
||
if (config.showDealerName || config.showWatermelonGrade) {
|
||
htmlString += `
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${
|
||
config.showWatermelonGrade
|
||
? `${config.dealerName || ""}-${config.watermelonGrade || ""}`
|
||
: config.dealerName || ""
|
||
}
|
||
</div>
|
||
`;
|
||
} else {
|
||
htmlString += `<div class="col-span-3"></div>`;
|
||
}
|
||
|
||
if (config.showDestination || config.showVehicleNumber) {
|
||
htmlString += `
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.destination || ""} ${config.vehicleNumber || ""}
|
||
</div>
|
||
`;
|
||
} else {
|
||
htmlString += `<div class="col-span-3"></div>`;
|
||
}
|
||
|
||
htmlString += `
|
||
<div class="col-span-1"></div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (module.type === "shippingInfo") {
|
||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||
|
||
if (config.showShippingFrom) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">发货地:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.shippingFrom || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showDate) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">日期:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.date || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
}
|
||
|
||
if (module.type === "weightInfo") {
|
||
if (config.data) {
|
||
config.data.forEach((item: any) => {
|
||
htmlString += `<div class="preview grid w-full grid-cols-2 gap-0 text-base">`;
|
||
|
||
if (config.showNetWeight) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">净重:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${item.netWeight || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||
${config.netWeightUnit === "1" ? "斤" : "公斤"}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showBoxWeight) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">箱重:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${item.boxWeight || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||
${config.boxWeightUnit === "1" ? "斤" : "公斤"}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showGrossWeight) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">毛重:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${item.grossWeight || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||
${config.grossWeightUnit === "1" ? "斤" : "公斤"}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showUnitPrice) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">单价:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${item.unitPrice || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||
${config.unitPriceUnit === "1" ? "元/斤" : "元/公斤"}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showAmount) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">金额:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${item.totalAmount || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">元</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showGrade) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">品级:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${item.watermelonGrade || ""}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
});
|
||
}
|
||
|
||
htmlString += `<div class="preview grid w-full grid-cols-2 gap-0 text-base">`;
|
||
|
||
if (config.showAccountCompany) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">入账公司:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.accountCompany || ""}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showSumAmount) {
|
||
htmlString += `
|
||
<div class="col-span-1 grid grid-cols-4">
|
||
<div class="col-span-1 flex items-end justify-center">总计:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${config.sumAmount || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">元</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
}
|
||
|
||
if (module.type === "packingSpec") {
|
||
htmlString += `<div>`;
|
||
// 计算需要显示的列数
|
||
const visibleColumnCount =
|
||
[
|
||
config.showBoxType,
|
||
config.showQuantity,
|
||
config.showUnitPrice,
|
||
config.showAmount,
|
||
config.showUnitWeight,
|
||
config.showWeight,
|
||
].filter(Boolean).length + 1; // +1 是因为"规格:"列总是显示
|
||
|
||
const gridClass = `grid w-full gap-0 text-base grid-cols-${visibleColumnCount}`;
|
||
|
||
htmlString += `
|
||
<div class="${gridClass}">
|
||
<div class="grid-span-1 flex items-end justify-center">规格:</div>
|
||
</div>
|
||
`;
|
||
|
||
htmlString += `<div class="${gridClass}">`;
|
||
|
||
if (config.columns) {
|
||
config.columns.forEach((column: any, index: number) => {
|
||
if (index === 0) {
|
||
htmlString += `<div class=""> </div>`;
|
||
return;
|
||
}
|
||
|
||
if (
|
||
(column.dataIndex === "boxType" && config.showBoxType) ||
|
||
(column.dataIndex === "quantity" && config.showQuantity) ||
|
||
(column.dataIndex === "unitPrice" && config.showUnitPrice) ||
|
||
(column.dataIndex === "amount" && config.showAmount) ||
|
||
(column.dataIndex === "unitWeight" && config.showUnitWeight) ||
|
||
(column.dataIndex === "weight" && config.showWeight)
|
||
) {
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${column.title || ""}</div>
|
||
`;
|
||
}
|
||
});
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
htmlString += `<div class="table-border">`;
|
||
|
||
if (config.data) {
|
||
config.data.forEach((item: any, index: number) => {
|
||
htmlString += `
|
||
<div class="${gridClass} ${index > 0 ? "border-t-0" : ""}">
|
||
<div class="flex items-end justify-center">
|
||
${item.boxSpecName}
|
||
</div>
|
||
`;
|
||
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${item.boxType || ""}</div>
|
||
`;
|
||
|
||
if (config.showQuantity) {
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${item.quantity || ""}</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showUnitPrice) {
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${item.unitPrice || ""}</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showAmount) {
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${item.amount || ""}</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showUnitWeight) {
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${item.unitWeight || ""}</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showWeight) {
|
||
htmlString += `
|
||
<div class="flex items-end justify-center">${item.weight || ""}</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
});
|
||
}
|
||
|
||
htmlString += `
|
||
<div class="${gridClass}">
|
||
<div class="col-span-2 flex items-end justify-center">总件数</div>
|
||
`;
|
||
|
||
if (config.showQuantity) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
${
|
||
config.data?.reduce(
|
||
(acc: any, cur: any) => acc + Number(cur.quantity || 0),
|
||
0,
|
||
) || 0
|
||
}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showUnitPrice) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showAmount) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
${
|
||
config.data?.reduce(
|
||
(acc: any, cur: any) => acc + Number(cur.amount || 0),
|
||
0,
|
||
) || 0
|
||
}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showUnitWeight) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showWeight) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
${
|
||
config.data?.reduce(
|
||
(acc: any, cur: any) => acc + Number(cur.weight || 0),
|
||
0,
|
||
) || 0
|
||
}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `
|
||
</div>
|
||
</div>
|
||
`;
|
||
htmlString += `</div>`;
|
||
}
|
||
|
||
if (module.type === "vehicleInfo") {
|
||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||
|
||
if (config.showDriverPhone) {
|
||
htmlString += `
|
||
<div class="col-span-2 flex items-end justify-center">司机号码:</div>
|
||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||
${config.driverPhone || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showLicensePlate) {
|
||
htmlString += `
|
||
<div class="col-span-2 flex items-end justify-center">车牌:</div>
|
||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||
${config.licensePlate || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showEstimatedArrivalTime) {
|
||
htmlString += `
|
||
<div class="col-span-2 flex items-end justify-center">预计到仓时间:</div>
|
||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||
${config.estimatedArrivalTime || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showRemarks) {
|
||
htmlString += `
|
||
<div class="col-span-2 flex items-end justify-center">备注:</div>
|
||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||
${config.remarks || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showFreightDebt) {
|
||
htmlString += `
|
||
<div class="col-span-2 flex items-end justify-center">
|
||
${config.freightDebtTitle || "运费欠"}:
|
||
</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${config.freightDebt || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showStrawMatDebt) {
|
||
htmlString += `
|
||
<div class="col-span-2 flex items-end justify-center">草帘欠:</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${config.strawMatDebt || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
}
|
||
|
||
if (module.type === "otherFees") {
|
||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||
|
||
if (config.feeItems) {
|
||
config.feeItems.forEach((feeType: any) => {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
${(config.feeLabels && config.feeLabels[feeType]) || ""}:
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||
${config[feeType] || ""}元
|
||
</div>
|
||
`;
|
||
});
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
}
|
||
|
||
if (module.type === "totalAmount") {
|
||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||
|
||
if (config.showTotalAmount) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">
|
||
${config.sumTitle || "合计金额"}:
|
||
</div>
|
||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||
${config.amount || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center border-b border-black">元</div>
|
||
`;
|
||
}
|
||
|
||
if (config.showFarmer) {
|
||
htmlString += `
|
||
<div class="col-span-1 flex items-end justify-center">瓜农:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.farmer || ""}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
htmlString += `</div>`;
|
||
}
|
||
|
||
if (module.type === "otherInfo") {
|
||
htmlString += `
|
||
<div class="preview grid w-full grid-cols-8 gap-0 text-base">
|
||
<div class="col-span-1 flex items-end justify-center">产地:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.origin || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center">供应商:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.supplier || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center">发车时间:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.departureTime || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center">到达时间:</div>
|
||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||
${config.arrivalTime || ""}
|
||
</div>
|
||
<div class="col-span-1 flex items-end justify-center">产品名称:</div>
|
||
<div class="col-span-7 flex items-end justify-center border-b border-black">
|
||
${config.productName || ""}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
});
|
||
|
||
htmlString += `</div></div>`;
|
||
return htmlString;
|
||
};
|
||
|
||
// 截图预览内容
|
||
const capturePreview = async () => {
|
||
// 请求 poster.qilincloud168.com/api/v1/pdfs 接口 请求参数是 html 内容 的json 格式响应结果为
|
||
// 调用API生成PDF
|
||
const { data } = await Taro.request({
|
||
url: "https://poster.qilincloud168.com/api/v1/pdf",
|
||
method: "POST",
|
||
header: {
|
||
"content-type": "application/json",
|
||
},
|
||
data: {
|
||
html: generateHtmlString(),
|
||
},
|
||
});
|
||
|
||
// 存储 至 shipOrder previewUrl
|
||
if (shipOrderVO) {
|
||
let formData: BusinessAPI.ShipOrderGenerateDocumentCmd = {
|
||
shipOrderId: shipOrderVO?.shipOrderId,
|
||
shipDocument: data.path,
|
||
};
|
||
// 检查各模块中的必填字段是否已填写
|
||
for (const module of moduleList) {
|
||
const contentSchema = module.schemas.find(
|
||
(schema) => schema.title === "内容配置",
|
||
);
|
||
|
||
if (
|
||
!contentSchema ||
|
||
!contentSchema.columns ||
|
||
contentSchema.columns.length === 0
|
||
) {
|
||
continue;
|
||
}
|
||
|
||
for (const column of contentSchema.columns) {
|
||
// 检查西瓜品级字段是否开启且已填写
|
||
if (column.dataIndex === "requiredWatermelonGrade") {
|
||
formData.watermelonGrade = shipOrderVO?.watermelonGrade;
|
||
}
|
||
// 检查发货地字段是否开启且已填写
|
||
else if (column.dataIndex === "requiredShippingFrom") {
|
||
formData.shippingAddress = shipOrderVO?.shippingAddress;
|
||
}
|
||
// 检查预计到仓时间字段是否开启且已填写
|
||
else if (column.dataIndex === "requiredEstimatedArrivalTime") {
|
||
formData.estimatedArrivalDate = shipOrderVO?.estimatedArrivalDate;
|
||
}
|
||
// 检查备注字段是否开启且已填写
|
||
else if (column.dataIndex === "requiredRemarks") {
|
||
formData.remark = shipOrderVO?.remark;
|
||
}
|
||
// 检查品级字段是否开启且已填写
|
||
else if (column.dataIndex === "requiredGrade") {
|
||
formData.shipOrderItemList = shipOrderVO?.shipOrderItemList;
|
||
}
|
||
}
|
||
}
|
||
business.shipOrder.generateDocumentShipOrder(formData).then();
|
||
}
|
||
|
||
if (data && data.path) {
|
||
setPurchaseDocument(data.path);
|
||
}
|
||
};
|
||
|
||
// 返回上一步
|
||
const goToPrevStep = () => {
|
||
if (step > 0) {
|
||
setStep(step - 1);
|
||
}
|
||
};
|
||
|
||
// 重置表单
|
||
const resetForm = () => {
|
||
setStep(1);
|
||
// 重置表单错误状态
|
||
setFormErrors({});
|
||
// 重新加载初始数据
|
||
if (shipOrderId) {
|
||
init(shipOrderId).then();
|
||
}
|
||
};
|
||
|
||
// 重新生成单据
|
||
const regenerateDocument = () => {
|
||
setStep(1);
|
||
};
|
||
|
||
// 放大
|
||
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) => {
|
||
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) => {
|
||
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) => {
|
||
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) => {
|
||
// 可以在这里添加触摸结束后的处理逻辑
|
||
console.log("Touch ended", e);
|
||
};
|
||
|
||
const [topBarHeight, setTopBarHeight] = useState<number>(0);
|
||
const [bottomBarHeight, setBottomBarHeight] = useState<number>(0);
|
||
const topBarRef = useRef<any>(null);
|
||
const bottomBarRef = useRef<any>(null);
|
||
|
||
// 查看文档
|
||
const handleView = async () => {
|
||
if (!tempFilePath) {
|
||
Taro.showToast({
|
||
title: "请先下载发货单据",
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
Taro.openDocument({
|
||
filePath: tempFilePath,
|
||
showMenu: true,
|
||
});
|
||
};
|
||
|
||
// 处理下载功能
|
||
const handleDownload = async () => {
|
||
Taro.showToast({
|
||
title: "正在生成并下载发货单据",
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
|
||
// 下载文件
|
||
Taro.downloadFile({
|
||
url: purchaseDocument!,
|
||
}).then((downloadRes) => {
|
||
if (downloadRes.tempFilePath) {
|
||
setTempFilePath(downloadRes.tempFilePath);
|
||
Taro.showToast({
|
||
title: "发货单据已下载成功,您可以将生成的PDF发送给好友",
|
||
icon: "none",
|
||
duration: 3000,
|
||
});
|
||
|
||
// Taro.getFileSystemManager().mkdir({
|
||
// dirPath: `${Taro.env.USER_DATA_PATH}/${shipOrderVO?.dealerName}/发货单据`,
|
||
// recursive: true,
|
||
// });
|
||
//
|
||
// // 保存到文件系统
|
||
// Taro.getFileSystemManager().saveFile({
|
||
// tempFilePath: downloadRes.tempFilePath,
|
||
// filePath: `${Taro.env.USER_DATA_PATH}/${shipOrderVO?.dealerName}/发货单据/${shipOrderVO?.vehicleNo}_${shipOrderVO?.dealerName}_发货单据_${shipOrderVO?.orderSn}.pdf`,
|
||
// success: function () {
|
||
// Taro.showToast({
|
||
// title: "发货单据已保存到本地,您可以将生成的PDF发送给好友",
|
||
// icon: "none",
|
||
// duration: 3000,
|
||
// });
|
||
// },
|
||
// fail: function (err) {
|
||
// console.log("保存失败", err);
|
||
// Taro.showToast({
|
||
// title: "保存失败",
|
||
// icon: "none",
|
||
// duration: 3000,
|
||
// });
|
||
// }
|
||
// });
|
||
}
|
||
});
|
||
};
|
||
|
||
// 处理分享功能
|
||
const handleShare = async () => {
|
||
if (!tempFilePath) {
|
||
Taro.showToast({
|
||
title: "请先下载发货单据",
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
Taro.showToast({
|
||
title: "正在分享到微信",
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
|
||
// 下载完成后转发
|
||
Taro.shareFileMessage({
|
||
filePath: tempFilePath,
|
||
fileName: `第${shipOrderVO?.vehicleNo}车_${shipOrderVO?.dealerName}_发货单据_${shipOrderVO?.orderSn}.pdf`,
|
||
complete: (res) => {
|
||
console.log("complete", res);
|
||
},
|
||
});
|
||
};
|
||
|
||
useEffect(() => {
|
||
// 获取 topBar 和 bottomBar 的实际高度
|
||
const queryTopBar = Taro.createSelectorQuery();
|
||
queryTopBar
|
||
.select("#topBar")
|
||
.boundingClientRect((rect: any) => {
|
||
if (rect) {
|
||
setTopBarHeight(rect.height);
|
||
}
|
||
})
|
||
.exec();
|
||
|
||
const queryBottomBar = Taro.createSelectorQuery();
|
||
queryBottomBar
|
||
.select("#bottomBar")
|
||
.boundingClientRect((rect: any) => {
|
||
if (rect) {
|
||
setBottomBarHeight(rect.height);
|
||
}
|
||
})
|
||
.exec();
|
||
}, [step]);
|
||
|
||
useEffect(() => {
|
||
// 计算滚动区域高度:窗口高度 - topBar高度 - bottomBar高度
|
||
const windowHeight = Taro.getSystemInfoSync().windowHeight;
|
||
setHeight(windowHeight - topBarHeight - bottomBarHeight);
|
||
}, [topBarHeight, bottomBarHeight]);
|
||
|
||
return (
|
||
<View
|
||
className={
|
||
"flex flex-1 flex-col overflow-x-hidden overflow-y-auto bg-[#D1D5DB]"
|
||
}
|
||
>
|
||
<View id={"topBar"} ref={topBarRef}>
|
||
<View className={"p-2.5"}>
|
||
<View className={"rounded-lg bg-white p-4 shadow-md"}>
|
||
<Steps value={step} status="dynamic" layout="single">
|
||
{shipOrder.steps.map((item, index) => (
|
||
<Step key={index} {...item} />
|
||
))}
|
||
</Steps>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
<View
|
||
className={classNames("px-2.5", {
|
||
"overflow-hidden": step === 2,
|
||
})}
|
||
style={{
|
||
height: height,
|
||
}}
|
||
>
|
||
{step === 1 && (
|
||
<View className="flex flex-col rounded-lg bg-white p-2.5 shadow-md">
|
||
{moduleList.map((module) => {
|
||
const contentFields = renderContentFields(module);
|
||
// 如果没有内容配置字段,则不渲染该模块
|
||
if (!contentFields) return null;
|
||
|
||
return (
|
||
<View key={module.id} className="flex flex-col gap-2.5">
|
||
<View className="border-b border-b-gray-200 pb-2.5">
|
||
<Text className="text-base font-semibold">
|
||
{module.title}
|
||
</Text>
|
||
</View>
|
||
{contentFields}
|
||
</View>
|
||
);
|
||
})}
|
||
</View>
|
||
)}
|
||
|
||
{step === 2 && (
|
||
<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",
|
||
}}
|
||
>
|
||
{moduleList.map((module) => {
|
||
const config = module.config;
|
||
if (module.type === "title") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-2xl font-bold"
|
||
}
|
||
>
|
||
<View className="col-span-8 flex items-end justify-center">
|
||
{config.title}
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
if (module.type === "dealerInfo") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-lg font-bold"
|
||
}
|
||
>
|
||
<View className="col-span-1"></View>
|
||
{config.showDealerName || config.showWatermelonGrade ? (
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.showWatermelonGrade
|
||
? `${config.dealerName}-${config.watermelonGrade}`
|
||
: config.dealerName}
|
||
</View>
|
||
) : (
|
||
<View className="col-span-3"></View>
|
||
)}
|
||
{config.showDestination || config.showVehicleNumber ? (
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.destination}
|
||
{config.vehicleNumber}
|
||
</View>
|
||
) : (
|
||
<View className="col-span-3"></View>
|
||
)}
|
||
<View className="col-span-1"></View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
if (module.type === "shippingInfo") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-base"
|
||
}
|
||
>
|
||
{config.showShippingFrom && (
|
||
<>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
发货地:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.shippingFrom}
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showDate && (
|
||
<>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
日期:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.date}
|
||
</View>
|
||
</>
|
||
)}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
if (module.type === "weightInfo") {
|
||
return (
|
||
<>
|
||
{config.data?.map((item: any, index: number) => {
|
||
return (
|
||
<View
|
||
key={"weightInfo" + index}
|
||
className={
|
||
"preview grid w-full grid-cols-2 gap-0 text-base"
|
||
}
|
||
>
|
||
{config.showNetWeight && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
净重:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{item.netWeight}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
{config.netWeightUnit === "1"
|
||
? "斤"
|
||
: "公斤"}
|
||
</View>
|
||
</View>
|
||
)}
|
||
{config.showBoxWeight && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
箱重:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{item.boxWeight}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
{config.boxWeightUnit === "1"
|
||
? "斤"
|
||
: "公斤"}
|
||
</View>
|
||
</View>
|
||
)}
|
||
{config.showGrossWeight && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
毛重:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{item.grossWeight}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
{config.grossWeightUnit === "1"
|
||
? "斤"
|
||
: "公斤"}
|
||
</View>
|
||
</View>
|
||
)}
|
||
{config.showUnitPrice && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
单价:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{item.unitPrice}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
{config.unitPriceUnit === "1"
|
||
? "元/斤"
|
||
: "元/公斤"}
|
||
</View>
|
||
</View>
|
||
)}
|
||
{config.showAmount && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
金额:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{item.totalAmount}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
元
|
||
</View>
|
||
</View>
|
||
)}
|
||
{config.showGrade && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
品级:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{item.watermelonGrade}
|
||
</View>
|
||
</View>
|
||
)}
|
||
</View>
|
||
);
|
||
})}
|
||
<View
|
||
className={
|
||
"preview grid w-full grid-cols-2 gap-0 text-base"
|
||
}
|
||
>
|
||
{config.showAccountCompany && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
入账公司:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.accountCompany}
|
||
</View>
|
||
</View>
|
||
)}
|
||
{config.showSumAmount && (
|
||
<View className={"col-span-1 grid grid-cols-4"}>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
总计:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{config.sumAmount}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
元
|
||
</View>
|
||
</View>
|
||
)}
|
||
</View>
|
||
</>
|
||
);
|
||
}
|
||
|
||
if (module.type === "packingSpec") {
|
||
// 计算需要显示的列数
|
||
const visibleColumnCount =
|
||
[
|
||
config.showBoxType,
|
||
config.showQuantity,
|
||
config.showUnitPrice,
|
||
config.showAmount,
|
||
config.showUnitWeight,
|
||
config.showWeight,
|
||
].filter(Boolean).length + 1; // +1 是因为"规格:"列总是显示
|
||
return (
|
||
<>
|
||
<View
|
||
className={classNames(`grid w-full gap-0 text-base`, {
|
||
"grid-cols-1": visibleColumnCount === 1,
|
||
"grid-cols-2": visibleColumnCount === 2,
|
||
"grid-cols-3": visibleColumnCount === 3,
|
||
"grid-cols-4": visibleColumnCount === 4,
|
||
"grid-cols-5": visibleColumnCount === 5,
|
||
"grid-cols-6": visibleColumnCount === 6,
|
||
"grid-cols-7": visibleColumnCount === 7,
|
||
"grid-cols-8": visibleColumnCount === 8,
|
||
})}
|
||
>
|
||
<div
|
||
className={`grid-span-1 flex items-end justify-center`}
|
||
>
|
||
规格:
|
||
</div>
|
||
</View>
|
||
|
||
<View
|
||
className={classNames(`grid w-full gap-0 text-base`, {
|
||
"grid-cols-1": visibleColumnCount === 1,
|
||
"grid-cols-2": visibleColumnCount === 2,
|
||
"grid-cols-3": visibleColumnCount === 3,
|
||
"grid-cols-4": visibleColumnCount === 4,
|
||
"grid-cols-5": visibleColumnCount === 5,
|
||
"grid-cols-6": visibleColumnCount === 6,
|
||
"grid-cols-7": visibleColumnCount === 7,
|
||
"grid-cols-8": visibleColumnCount === 8,
|
||
})}
|
||
>
|
||
{config.columns.map((column: any, index: number) => {
|
||
if (index === 0) {
|
||
return (
|
||
<div key={"title" + index} className="">
|
||
|
||
</div>
|
||
);
|
||
}
|
||
|
||
if (
|
||
(column.dataIndex === "boxType" &&
|
||
config.showBoxType) ||
|
||
(column.dataIndex === "quantity" &&
|
||
config.showQuantity) ||
|
||
(column.dataIndex === "unitPrice" &&
|
||
config.showUnitPrice) ||
|
||
(column.dataIndex === "amount" &&
|
||
config.showAmount) ||
|
||
(column.dataIndex === "unitWeight" &&
|
||
config.showUnitWeight) ||
|
||
(column.dataIndex === "weight" &&
|
||
config.showWeight)
|
||
) {
|
||
return (
|
||
<div
|
||
key={"title" + index}
|
||
className="flex items-end justify-center"
|
||
>
|
||
{column.title}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return <></>;
|
||
})}
|
||
</View>
|
||
<View className={"table-border"}>
|
||
{config.data?.map((item: any, index: number) => (
|
||
<View
|
||
key={index}
|
||
className={classNames(
|
||
`grid w-full gap-0 text-base`,
|
||
{
|
||
"grid-cols-1": visibleColumnCount === 1,
|
||
"grid-cols-2": visibleColumnCount === 2,
|
||
"grid-cols-3": visibleColumnCount === 3,
|
||
"grid-cols-4": visibleColumnCount === 4,
|
||
"grid-cols-5": visibleColumnCount === 5,
|
||
"grid-cols-6": visibleColumnCount === 6,
|
||
"grid-cols-7": visibleColumnCount === 7,
|
||
"grid-cols-8": visibleColumnCount === 8,
|
||
"border-t-0": index > 0,
|
||
},
|
||
)}
|
||
>
|
||
<View className={"flex items-end justify-center"}>
|
||
{item.boxSpecName}
|
||
</View>
|
||
|
||
<View className={"flex items-end justify-center"}>
|
||
{item.boxType}
|
||
</View>
|
||
|
||
{config.showQuantity && (
|
||
<View
|
||
className={"flex items-end justify-center"}
|
||
>
|
||
{item.quantity}
|
||
</View>
|
||
)}
|
||
|
||
{config.showUnitPrice && (
|
||
<View
|
||
className={"flex items-end justify-center"}
|
||
>
|
||
{item.unitPrice}
|
||
</View>
|
||
)}
|
||
|
||
{config.showAmount && (
|
||
<View
|
||
className={"flex items-end justify-center"}
|
||
>
|
||
{item.amount}
|
||
</View>
|
||
)}
|
||
|
||
{config.showUnitWeight && (
|
||
<View
|
||
className={"flex items-end justify-center"}
|
||
>
|
||
{item.unitWeight}
|
||
</View>
|
||
)}
|
||
|
||
{config.showWeight && (
|
||
<View
|
||
className={"flex items-end justify-center"}
|
||
>
|
||
{item.weight}
|
||
</View>
|
||
)}
|
||
</View>
|
||
))}
|
||
|
||
<View
|
||
className={classNames(
|
||
`grid w-full gap-0 text-base`,
|
||
{
|
||
"grid-cols-1": visibleColumnCount === 1,
|
||
"grid-cols-2": visibleColumnCount === 2,
|
||
"grid-cols-3": visibleColumnCount === 3,
|
||
"grid-cols-4": visibleColumnCount === 4,
|
||
"grid-cols-5": visibleColumnCount === 5,
|
||
"grid-cols-6": visibleColumnCount === 6,
|
||
"grid-cols-7": visibleColumnCount === 7,
|
||
"grid-cols-8": visibleColumnCount === 8,
|
||
},
|
||
)}
|
||
>
|
||
<View
|
||
className={`col-span-2 flex items-end justify-center`}
|
||
>
|
||
总件数
|
||
</View>
|
||
{config.showQuantity && (
|
||
<View
|
||
className={`col-span-1 flex items-end justify-center`}
|
||
>
|
||
{config.data?.reduce(
|
||
(acc: any, cur: any) =>
|
||
acc + Number(cur.quantity),
|
||
0,
|
||
)}
|
||
</View>
|
||
)}
|
||
{config.showUnitPrice && (
|
||
<View
|
||
className={`col-span-1 flex items-end justify-center`}
|
||
></View>
|
||
)}
|
||
{config.showAmount && (
|
||
<View
|
||
className={`col-span-1 flex items-end justify-center`}
|
||
>
|
||
{config.data?.reduce(
|
||
(acc: any, cur: any) =>
|
||
acc + Number(cur.amount),
|
||
0,
|
||
)}
|
||
</View>
|
||
)}
|
||
{config.showUnitWeight && (
|
||
<View
|
||
className={`col-span-1 flex items-end justify-center`}
|
||
></View>
|
||
)}
|
||
{config.showWeight && (
|
||
<View
|
||
className={`col-span-1 flex items-end justify-center`}
|
||
>
|
||
{config.data?.reduce(
|
||
(acc: any, cur: any) =>
|
||
acc + Number(cur.weight),
|
||
0,
|
||
)}
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>
|
||
</>
|
||
);
|
||
}
|
||
|
||
if (module.type === "vehicleInfo") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-base"
|
||
}
|
||
>
|
||
{config.showDriverPhone && (
|
||
<>
|
||
<View className="col-span-2 flex items-end justify-center">
|
||
司机号码:
|
||
</View>
|
||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||
{config.driverPhone}
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showLicensePlate && (
|
||
<>
|
||
<View className="col-span-2 flex items-end justify-center">
|
||
车牌:
|
||
</View>
|
||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||
{config.licensePlate}
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showEstimatedArrivalTime && (
|
||
<>
|
||
<View className="col-span-2 flex items-end justify-center">
|
||
预计到仓时间:
|
||
</View>
|
||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||
{config.estimatedArrivalTime}
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showRemarks && (
|
||
<>
|
||
<View className="col-span-2 flex items-end justify-center">
|
||
备注:
|
||
</View>
|
||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||
{config.remarks}
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showFreightDebt && (
|
||
<>
|
||
<View className="col-span-2 flex items-end justify-center">
|
||
{config.freightDebtTitle || "运费欠"}:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{config.freightDebt}
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showStrawMatDebt && (
|
||
<>
|
||
<View className="col-span-2 flex items-end justify-center">
|
||
草帘欠:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{config.strawMatDebt}
|
||
</View>
|
||
</>
|
||
)}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
if (module.type === "otherFees") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-base"
|
||
}
|
||
>
|
||
{config.feeItems?.map((feeType: any) => (
|
||
<>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
{config.feeLabels[feeType]}:
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
{config[feeType]}元
|
||
</View>
|
||
</>
|
||
))}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
if (module.type === "totalAmount") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-base"
|
||
}
|
||
>
|
||
{config.showTotalAmount && (
|
||
<>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
{config.sumTitle || "合计金额"}:
|
||
</View>
|
||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||
{config.amount}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||
元
|
||
</View>
|
||
</>
|
||
)}
|
||
{config.showFarmer && (
|
||
<>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
瓜农:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.farmer}
|
||
</View>
|
||
</>
|
||
)}
|
||
</View>
|
||
);
|
||
}
|
||
|
||
if (module.type === "otherInfo") {
|
||
return (
|
||
<View
|
||
key={module.id}
|
||
className={
|
||
"preview grid w-full grid-cols-8 gap-0 text-base"
|
||
}
|
||
>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
产地:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.origin}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
供应商:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.supplier}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
发车时间:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.departureTime}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
到达时间:
|
||
</View>
|
||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||
{config.arrivalTime}
|
||
</View>
|
||
<View className="col-span-1 flex items-end justify-center">
|
||
产品名称:
|
||
</View>
|
||
<View className="col-span-7 flex items-end justify-center border-b border-black">
|
||
{config.productName}
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
})}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
)}
|
||
|
||
{step === 3 && purchaseDocument && (
|
||
<View className="flex flex-1 flex-col items-center justify-center rounded-lg bg-white p-4 shadow-md">
|
||
<View className="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-green-100">
|
||
<Text className="text-2xl text-green-600">✓</Text>
|
||
</View>
|
||
<View className="mb-2 text-xl font-bold text-gray-800">
|
||
发货单据生成成功
|
||
</View>
|
||
<View className="mb-8 text-gray-600">
|
||
您的发货单据已生成,可以下载或转发给好友
|
||
</View>
|
||
|
||
<View className="mb-6 flex w-full flex-row justify-center gap-4">
|
||
{purchaseDocument && !tempFilePath && (
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="default"
|
||
size="large"
|
||
block
|
||
onClick={handleDownload}
|
||
>
|
||
下载文档
|
||
</Button>
|
||
</View>
|
||
)}
|
||
{purchaseDocument && tempFilePath && (
|
||
<>
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="default"
|
||
size="large"
|
||
block
|
||
onClick={handleView}
|
||
>
|
||
查看文档
|
||
</Button>
|
||
</View>
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="primary"
|
||
size="large"
|
||
block
|
||
onClick={handleShare}
|
||
>
|
||
转发好友
|
||
</Button>
|
||
</View>
|
||
</>
|
||
)}
|
||
</View>
|
||
|
||
<View className="text-sm text-gray-500">
|
||
提示:您可以随时在发货单据列表中重新下载
|
||
</View>
|
||
</View>
|
||
)}
|
||
</View>
|
||
|
||
{/* 步骤控制按钮 */}
|
||
<View
|
||
ref={bottomBarRef}
|
||
className={"fixed bottom-0 left-0 z-10 w-full bg-white"}
|
||
id={"bottomBar"}
|
||
>
|
||
<View className={"flex flex-row gap-2.5 p-2.5"}>
|
||
{step == 1 && (
|
||
<View className={"flex-1"}>
|
||
<Button type="default" block size={"large"} onClick={resetForm}>
|
||
重置
|
||
</Button>
|
||
</View>
|
||
)}
|
||
{step == 1 && (
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="primary"
|
||
block
|
||
size={"large"}
|
||
onClick={previewAndConfirm}
|
||
>
|
||
下一步
|
||
</Button>
|
||
</View>
|
||
)}
|
||
{step == 2 && (
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="default"
|
||
block
|
||
size={"large"}
|
||
onClick={goToPrevStep}
|
||
>
|
||
返回修改
|
||
</Button>
|
||
</View>
|
||
)}
|
||
{step == 2 && (
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="primary"
|
||
block
|
||
size={"large"}
|
||
onClick={generateShippingDocument}
|
||
>
|
||
生成发货单据
|
||
</Button>
|
||
</View>
|
||
)}
|
||
{step == 3 && (
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="default"
|
||
block
|
||
size={"large"}
|
||
onClick={() =>
|
||
Taro.switchTab({
|
||
url: buildUrl("/pages/main/index/index"),
|
||
})
|
||
}
|
||
>
|
||
返回首页
|
||
</Button>
|
||
</View>
|
||
)}
|
||
{step == 3 && (
|
||
<View className={"flex-1"}>
|
||
<Button
|
||
type="primary"
|
||
block
|
||
size={"large"}
|
||
onClick={regenerateDocument}
|
||
>
|
||
重新生成
|
||
</Button>
|
||
</View>
|
||
)}
|
||
</View>
|
||
<SafeArea position={"bottom"} />
|
||
</View>
|
||
</View>
|
||
);
|
||
});
|