feat(purchase): 优化瓜农信息添加逻辑与包装信息删除确认

- 移除了 MelonFarmer 组件中冗余的 isLastFarmer 状态和相关逻辑
- 调整了添加瓜农按钮的显示条件,仅在当前为最后一个瓜农且不为最后时显示
- 在 OrderPackage 中添加删除纸箱品牌时的确认对话框
- 修改了包装信息编辑按钮文本为“修改数量”,删除按钮文本为“不使用了”
- 优化了 OrderCost 组件中添加瓜农按钮的显示逻辑
- 调整了称重信息中提示文本的表述
- 统一了页面中添加瓜农的逻辑处理,避免重复代码
- 修复了保存草稿时的异步调用问题,确保流程正确执行
This commit is contained in:
shenyifei 2025-11-10 17:59:48 +08:00
parent f77acab4cb
commit 6c3b60f7b8
7 changed files with 114 additions and 134 deletions

View File

@ -25,7 +25,6 @@ interface IMelonFarmerProps {
value: SupplierVO;
onChange: (supplierVO: SupplierVO) => void;
onRemove: (supplierVO: SupplierVO) => void;
onAdd: () => void;
isLast: boolean; // 添加一个属性来标识是否是最后一个瓜农
supplierCount: number;
// 添加已选择的供应商ID列表属性
@ -40,7 +39,6 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
value,
onChange,
onRemove,
onAdd,
isLast,
supplierCount,
selectedSupplierIds,
@ -54,9 +52,6 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
// 初始化数据
useEffect(() => {
setSupplierVO(value);
if (value.isLast !== undefined) {
setIsLastFarmer(value.isLast);
}
// 初始化微信二维码图片列表
if (value.wechatQr) {
setPicList([
@ -77,7 +72,6 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
}, [supplierVO]);
const [picList, setPicList] = useState<UploaderFileItem[]>([]);
const [isLastFarmer, setIsLastFarmer] = useState<boolean | null>(null); // 修改状态类型null表示未选择
// 微信二维码变更处理函数
const handleWechatQrChange = (files: UploaderFileItem[]) => {
@ -167,7 +161,10 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
const isNameValid = validateName(supplierVO.name || "");
if (selectedSupplierNames && selectedSupplierNames.includes(supplierVO.name || "")) {
if (
selectedSupplierNames &&
selectedSupplierNames.includes(supplierVO.name || "")
) {
Toast.show("toast", {
icon: "fail",
title: "提示",
@ -568,8 +565,6 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
...supplierVO,
isLast: isLastValue,
});
setIsLastFarmer(isLastValue!);
}}
>
<Radio value="false"></Radio>
@ -655,7 +650,7 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
<View className={"text-primary text-sm font-bold"}>
{supplierVO.name || "瓜农"}
</View>
{supplierCount > 1 && (
{supplierCount > 1 && isLast && (
<View
className="cursor-pointer text-sm text-red-500"
onClick={() => handleRemoveConfirm(supplierVO)}
@ -862,23 +857,6 @@ export default forwardRef<MelonFarmerRef, IMelonFarmerProps>(
/>
</View>
</View>
{/* 只有当用户选择"否"时才显示添加按钮 */}
{isLast && !isLastFarmer && isLastFarmer !== null && (
<Button
icon={<Icon name={"plus"} size={20} />}
type={"primary"}
size={"xlarge"}
fill={"outline"}
block
className="border-primary text-primary flex w-full items-center justify-center !border-4 !bg-white"
onClick={() => {
onAdd();
}}
>
<View></View>
</Button>
)}
</View>
);
},

View File

@ -3,7 +3,7 @@ import { Icon } from "@/components";
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { business } from "@/services";
import { Button, Checkbox, Input, Toast } from "@nutui/nutui-react-taro";
import { CostItem } from "@/types/typings";
import { CostItem, SupplierVO } from "@/types/typings";
import { generateShortId } from "@/utils/generateShortId";
// 定义ref暴露的方法接口
@ -13,12 +13,14 @@ export interface OrderCostRef {
export interface IOrderCostProps {
value: CostItem[];
supplierVO: SupplierVO;
onChange?: (costItemList: CostItem[]) => void;
onAdd: () => void;
}
export default forwardRef<OrderCostRef, IOrderCostProps>(
function OrderCost(IOrderCostProps, ref) {
const { value, onChange } = IOrderCostProps;
const { value, supplierVO, onChange, onAdd } = IOrderCostProps;
const [costItemVOList, setCostItemVOList] = useState<CostItem[]>();
@ -274,7 +276,7 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
<View>
{/* 费用承担方改为按钮形式参考OrderPackage中的样式 */}
<View className="flex items-center justify-between">
<View className="text-sm flex-shrink-0">:</View>
<View className="flex-shrink-0 text-sm">:</View>
<View className="flex gap-2">
<Button
size="small"
@ -308,7 +310,7 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
{item.selected && (
<View>
<View className="flex items-center justify-between gap-2">
<View className="text-sm flex-shrink-0">:</View>
<View className="flex-shrink-0 text-sm">:</View>
<View className="flex items-center">
<View
className="rounded-l-button flex !size-12 flex-none items-center justify-center bg-gray-200 text-sm"
@ -446,6 +448,23 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
{/* <View className="mb-2.5 text-sm font-bold">空礼盒费用</View>*/}
{/* {renderItemList(getItemsByCostType("OTHER_COST"), "OTHER_COST")}*/}
{/*</View>*/}
{/* 只有当用户选择"否"时才显示添加按钮 */}
{!supplierVO.isLast && (
<Button
icon={<Icon name={"plus"} size={20} />}
type={"primary"}
size={"xlarge"}
fill={"outline"}
block
className="border-primary text-primary flex w-full items-center justify-center !border-4 !bg-white"
onClick={() => {
onAdd();
}}
>
<View></View>
</Button>
)}
</View>
);
},

View File

@ -2,6 +2,7 @@ import { ScrollView, View } from "@tarojs/components";
import { Icon } from "@/components";
import {
Button,
Dialog,
Image,
Input,
Popup,
@ -98,33 +99,12 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
}
// 检查所需选项是否都已做出选择不是1就是2不能是0
console.log("requiredTypes", requiredTypes, packageTypeEnabled);
const allRequiredAnswered = requiredTypes.every(
(type) =>
packageTypeEnabled[type] === 1 || packageTypeEnabled[type] === 2,
);
// 检查必须回答的问题
let requiredQuestionsAnswered = true;
if (supplierVO.isPaper && supplierVO.isLast) {
// 最后一个瓜农需要回答"空车带来的纸箱用完了吗?"
requiredQuestionsAnswered = packageTypeEnabled.REMAIN !== 0;
} else if (supplierVO.isPaper && !supplierVO.isLast) {
// 非最后一个瓜农不需要回答额外问题
} else if (!supplierVO.isPaper) {
// 空磅不包含纸箱的情况
}
if (!requiredQuestionsAnswered) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "请回答所有必答问题",
});
return false;
}
if (!allRequiredAnswered) {
if (!allRequiredAnswered || requiredTypes.length === 0) {
Toast.show("toast", {
icon: "fail",
title: "提示",
@ -140,18 +120,6 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
)
.map(([type, _]) => type);
console.log("enabledTypes", enabledTypes);
// 如果没有任何纸箱类型被启用,提示用户至少选择一种
if (requiredTypes.length > 0 && enabledTypes.length === 0) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "请至少选择一种纸箱使用情况",
});
return false;
}
// 检查每个启用的类型是否有对应的纸箱数据
for (const type of enabledTypes) {
const hasPackagesOfType = orderPackageList.some(
@ -408,10 +376,22 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
// 删除包装信息
const removePackageInfo = (boxBrandId: string) => {
Dialog.open('dialog', {
title: "提示",
content: "确定要移除此纸箱品牌吗?",
confirmText: "确定",
cancelText: "取消",
onConfirm: () => {
const newList = [
...orderPackageList.filter((item) => item.boxBrandId !== boxBrandId),
];
setOrderPackageList(newList);
Dialog.close('dialog');
},
onCancel: () => {
Dialog.close('dialog');
}
})
};
// 处理纸箱类型启用状态切换
@ -675,13 +655,13 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
className="cursor-pointer rounded-lg bg-blue-100 px-3 py-1 text-xs font-medium text-blue-600 transition-colors hover:bg-blue-200"
onClick={() => handleEditItem(item, index)}
>
</View>
<View
className="cursor-pointer rounded-lg bg-red-100 px-3 py-1 text-xs font-medium text-red-600 transition-colors hover:bg-red-200"
onClick={() => removePackageInfo(item.boxBrandId)}
>
使
</View>
</View>
</View>
@ -1390,7 +1370,7 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
{packageTypeEnabled.OWN === 2 && (
/* 当没有选择使用自己的纸箱时 */
<>
{renderPackageByType("EXTRA")}
{renderPackageByType("EXTRA_USED")}
{/* 分隔线 */}
<View className="my-4 h-px bg-gray-200" />
</>

View File

@ -267,7 +267,7 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
<View className="flex flex-1 flex-col gap-2.5 p-2.5">
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
<View className={"flex items-center justify-between gap-2.5"}>
<View className="text-sm"></View>
<View className="text-sm"></View>
<View className="text-neutral-darkest text-sm font-medium">
{supplierCount == 1 ? (
<Radio.Group

View File

@ -1,7 +1,6 @@
import { useEffect, useState } from "react";
import { View, Text } from "@tarojs/components";
import { Button, Input, Popup, Radio, SafeArea } from "@nutui/nutui-react-taro";
import { Icon } from "@/components";
import { formatCurrency, validatePrice } from "@/utils/format";
import {
getSalesAmount,

View File

@ -189,6 +189,42 @@ export default hocAuth(function Page(props: CommonComponent) {
return;
}
const onAdd = () => {
// 获取当前选中的供应商
const selectedIndex = orderSupplierList.findIndex(
(supplier) => supplier.selected,
);
if (active === 2 && !melonFarmerRefs.current[selectedIndex]?.validate()) {
return;
}
// 在第三步(称重信息)时进行校验
else if (active === 3 && !weighRefs.current[selectedIndex]?.validate()) {
return;
} // 在第四步(包装信息)时进行校验
else if (
active === 4 &&
!orderPackageRefs.current[selectedIndex]?.validate()
) {
return;
}
setOrderSupplierList([
...orderSupplierList.map((supplierVO: SupplierVO) => {
supplierVO.selected = false;
return supplierVO;
}),
{
orderSupplierId: generateShortId(),
supplierId: "",
name: "瓜农" + (orderSupplierList.length + 1),
idCard: "",
bankCard: "",
phone: "",
selected: true,
orderPackageList: [],
},
]);
};
const onFinish = async (preview?: boolean) => {
// 预览操作和暂存操作都显示确认对话框
if (preview) {
@ -224,14 +260,14 @@ export default hocAuth(function Page(props: CommonComponent) {
};
// 保存草稿的函数(用于下一步)
const saveDraftNextStep = async () => {
const saveDraftNextStep = () => {
if (!purchaseOrder) {
return;
}
let tempOrderId = orderId;
try {
if (tempOrderId) {
await business.purchaseOrder.updatePurchaseOrder({
business.purchaseOrder.updatePurchaseOrder({
active: active,
orderId: tempOrderId,
orderVehicle: purchaseOrder.orderVehicle,
@ -242,7 +278,8 @@ export default hocAuth(function Page(props: CommonComponent) {
orderDealer: purchaseOrder.orderDealer,
});
} else {
const { data } = await business.purchaseOrder.createPurchaseOrder({
business.purchaseOrder
.createPurchaseOrder({
active: active,
orderVehicle: purchaseOrder.orderVehicle,
orderSupplierList: purchaseOrder.orderSupplierList,
@ -250,9 +287,10 @@ export default hocAuth(function Page(props: CommonComponent) {
(item: CostItem) => item.selected,
),
orderDealer: purchaseOrder.orderDealer,
});
})
.then(({ data }) => {
setOrderId(data.data?.orderId);
});
}
} catch (error) {
Toast.show("toast", {
@ -461,47 +499,6 @@ export default hocAuth(function Page(props: CommonComponent) {
}
}}
value={item}
onAdd={() => {
// 获取当前选中的供应商
const selectedIndex = orderSupplierList.findIndex(
(supplier) => supplier.selected,
);
if (
active === 2 &&
!melonFarmerRefs.current[selectedIndex]?.validate()
) {
return;
}
// 在第三步(称重信息)时进行校验
else if (
active === 3 &&
!weighRefs.current[selectedIndex]?.validate()
) {
return;
} // 在第四步(包装信息)时进行校验
else if (
active === 4 &&
!orderPackageRefs.current[selectedIndex]?.validate()
) {
return;
}
setOrderSupplierList([
...orderSupplierList.map((supplierVO: SupplierVO) => {
supplierVO.selected = false;
return supplierVO;
}),
{
orderSupplierId: generateShortId(),
supplierId: "",
name: "瓜农" + (orderSupplierList.length + 1),
idCard: "",
bankCard: "",
phone: "",
selected: true,
orderPackageList: [],
},
]);
}}
onRemove={(supplierVO: SupplierVO) => {
if (orderSupplierList.length <= 1) {
setOrderSupplierList([
@ -609,6 +606,12 @@ export default hocAuth(function Page(props: CommonComponent) {
{/* 人工和辅料信息 */}
{step.value === 6 && (
<OrderCost
supplierVO={orderSupplierList[orderSupplierList.length - 1]}
onAdd={() => {
saveDraftNextStep();
setActive(2);
onAdd();
}}
ref={orderCostRef}
value={orderCostList}
onChange={(costItemList: CostItem[]) =>
@ -662,7 +665,7 @@ export default hocAuth(function Page(props: CommonComponent) {
// 在第一步(车辆信息)时进行校验
if (active === 1) {
if (vehicleRef.current?.validate()) {
await saveDraftNextStep();
saveDraftNextStep();
setActive(active + 1);
}
}
@ -676,7 +679,7 @@ export default hocAuth(function Page(props: CommonComponent) {
selectedIndex !== -1 &&
melonFarmerRefs.current[selectedIndex]?.validate()
) {
await saveDraftNextStep();
saveDraftNextStep();
setActive(active + 1);
}
}
@ -690,7 +693,7 @@ export default hocAuth(function Page(props: CommonComponent) {
selectedIndex !== -1 &&
weighRefs.current[selectedIndex]?.validate()
) {
await saveDraftNextStep();
saveDraftNextStep();
setActive(active + 1);
}
} // 在第四步(包装信息)时进行校验
@ -699,15 +702,16 @@ export default hocAuth(function Page(props: CommonComponent) {
const selectedIndex = orderSupplierList.findIndex(
(supplier) => supplier.selected,
);
console.log("selectedIndex", selectedIndex)
if (
selectedIndex !== -1 &&
orderPackageRefs.current[selectedIndex]?.validate()
) {
await saveDraftNextStep();
saveDraftNextStep();
setActive(active + 1);
}
} else {
await saveDraftNextStep();
saveDraftNextStep();
setActive(active + 1);
}
}}

View File

@ -2385,7 +2385,7 @@ declare namespace BusinessAPI {
/** 销售单价(元/个) */
boxSalePrice?: number;
/** 箱子类型:1_本次使用2_额外运输3_已使用额外运输4_车上剩余 */
boxType: "USED" | "EXTRA" | "EXTRA_USED" | "REMAIN";
boxType: "USED" | "EXTRA" | "EXTRA_USED" | "REMAIN" | "OWN";
};
type OrderRebate = {