ERPTurbo_Client/packages/app-client/src/components/purchase/module/OrderPackage.tsx
shenyifei dfe9a89213 refactor(components): 优化采购模块空箱和费用组件实现
- 移除 PageList 组件中对全局 loading 状态的依赖
- 简化 EmptyBoxModule 组件逻辑,使用 PackageList 组件替代原有复杂实现
- 移除冗余的状态管理和弹窗渲染逻辑
- 优化 OrderCost 组件样式和费用项匹配逻辑
- 修复成本项 ID 匹配问题,确保数据正确关联
- 添加边框样式增强视觉效果
- 移除调试日志和无用代码
- 简化组件间数据传递方式
2025-12-11 12:42:01 +08:00

491 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { View } from "@tarojs/components";
import { Button, Toast } from "@nutui/nutui-react-taro";
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { business } from "@/services";
import { BoxBrand, BoxProduct, BoxSpec } from "@/types/typings";
import { generateShortId } from "@/utils";
import { PackageList } from "@/components";
import { globalStore } from "@/store/global-store";
// 定义ref暴露的方法接口
export interface OrderPackageRef {
validate: () => boolean;
}
interface IOrderPackageProps {
index: number;
value: BusinessAPI.PurchaseOrderVO;
onChange: (purchaseOrderVO: BusinessAPI.PurchaseOrderVO) => void;
}
export default forwardRef<OrderPackageRef, IOrderPackageProps>(
function OrderPackage(props, ref) {
const { value, onChange, index } = props;
const { setLoading } = globalStore((state: any) => state);
const { orderSupplierList } = value;
const supplierVO = orderSupplierList[index];
const orderPackageList =
supplierVO.orderPackageList as BusinessAPI.OrderPackage[];
useEffect(() => {
// 初始化数据
// 确定当前供应商需要检查哪些纸箱类型
const initializePackageTypeEnabled = () => {
const usageMap = (supplierVO.packageUsage || []).reduce(
(acc, item) => {
if (item.boxType) {
acc[item.boxType] = item.isUsed || 0;
}
return acc;
},
{} as Record<string, number>,
);
if (supplierVO.isPaper && supplierVO.isLast) {
setPackageTypeEnabled({
EXTRA: 0,
EXTRA_USED: usageMap["EXTRA_USED"] || 0,
REMAIN: usageMap["REMAIN"] || 0,
});
} else if (supplierVO.isPaper && !supplierVO.isLast) {
setPackageTypeEnabled({
EXTRA: usageMap["EXTRA"] || 0,
EXTRA_USED: 0,
REMAIN: 0,
});
} else if (!supplierVO.isPaper) {
setPackageTypeEnabled({
EXTRA: 0,
EXTRA_USED: 0,
REMAIN: 0,
});
}
};
initializePackageTypeEnabled();
}, []);
const setOrderPackageList = (
orderPackageList: BusinessAPI.OrderPackage[],
) => {
onChange?.({
...value,
orderSupplierList: orderSupplierList.map((item, index1) => {
if (index1 === index) {
return {
...item,
orderPackageList,
};
}
return item;
}),
});
};
// 将校验方法暴露给父组件
useImperativeHandle(ref, () => ({
validate,
}));
// 校验函数
const validate = () => {
// 根据当前供应商确定需要检查的纸箱类型
let requiredTypes: string[] = [];
// 确定当前供应商需要检查哪些纸箱类型
if (supplierVO.isPaper && supplierVO.isLast) {
// 空磅包含纸箱 + 最后一个瓜农
requiredTypes = ["EXTRA_USED", "REMAIN"];
} else if (supplierVO.isPaper && !supplierVO.isLast) {
requiredTypes = ["EXTRA"];
}
console.log("requiredTypes", requiredTypes);
if (requiredTypes.length > 0) {
// 检查所需选项是否都已做出选择不是1就是2不能是0
const allRequiredAnswered = requiredTypes.every(
(type) =>
packageTypeEnabled[type] === 1 || packageTypeEnabled[type] === 2,
);
if (!allRequiredAnswered || requiredTypes.length === 0) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "请回答相关的纸箱使用情况问题",
});
return false;
}
}
requiredTypes.push("USED");
// 检查所有启用的纸箱类型是否都填写了信息
const enabledTypes = Object.entries(packageTypeEnabled)
.filter(
([type, enabled]) => requiredTypes.includes(type) && enabled === 1,
)
.map(([type, _]) => type);
// 检查每个启用的类型是否有对应的纸箱数据
for (const type of enabledTypes) {
const hasPackagesOfType = orderPackageList.some(
(item) => item.boxType === type,
);
if (!hasPackagesOfType) {
const typeLabels = {
USED: "记录装车用的纸箱",
EXTRA_USED: "记录用的额外运输纸箱",
EXTRA: "记录额外运输来的所有纸箱",
REMAIN: "记录车上没用完的纸箱",
};
Toast.show("toast", {
icon: "fail",
title: "提示",
content: `已选择使用${typeLabels[type]},请添加对应的纸箱信息`,
});
return false;
}
}
return true;
};
// 纸箱品牌数据
const [boxBrandList, setBoxBrandList] = useState<BoxBrand[]>();
const initBoxBrandList = async () => {
setLoading(true);
const { data } = await business.boxBrand.listBoxBrand({
boxBrandListQry: {
status: true,
withProduct: true,
},
});
const boxBrandList =
data.data
?.filter(
(boxBrand) =>
boxBrand.status &&
boxBrand.boxProductVOList &&
boxBrand.boxProductVOList.length > 0,
)
.map((boxBrand) => {
// 将产品按规格分类
const boxSpecList: BoxSpec[] =
boxBrand.boxSpecVOList?.map((item) => {
return {
id: generateShortId(),
boxSpecId: item.specId,
boxSpecName: item.name,
boxProductList: [],
};
}) || [];
const boxProductList = boxBrand.boxProductVOList?.map(
(boxProductVO) => {
const boxProduct: BoxProduct = {
id: generateShortId(),
boxProductId: boxProductVO.productId,
boxProductName: boxProductVO.name,
boxProductWeight: boxProductVO.weight,
boxSpecId: boxProductVO.specId,
boxSpecName: boxProductVO.specName,
boxCostPrice: boxProductVO.costPrice,
boxSalePrice: boxProductVO.salePrice,
boxBrandId: boxBrand.brandId,
boxBrandName: boxBrand.name,
boxCount: 0,
};
return boxProduct;
},
);
return {
id: generateShortId(),
boxBrandId: boxBrand.brandId,
boxBrandName: boxBrand.name,
boxBrandImage: boxBrand.image,
boxBrandType: boxBrand.type,
boxSpecList:
boxSpecList
.map((boxSpec) => {
return {
id: generateShortId(),
boxSpecId: boxSpec.boxSpecId,
boxSpecName: boxSpec.boxSpecName,
boxProductList:
boxProductList?.filter(
(boxProduct) =>
boxProduct.boxSpecId === boxSpec.boxSpecId,
) || [],
};
})
.filter(
(boxSpec) =>
boxSpec.boxProductList &&
boxSpec.boxProductList.length > 0,
) || [],
};
}) || [];
setBoxBrandList(boxBrandList as any);
setLoading(false);
};
useEffect(() => {
initBoxBrandList().then();
}, []);
// 新增状态:跟踪每种纸箱类型的启用状态
// 0: 未选, 1: 选择是, 2: 选择否
const [packageTypeEnabled, setPackageTypeEnabled] = useState({
EXTRA_USED: 0,
EXTRA: 0,
REMAIN: 0,
});
console.log("packageTypeEnabled", packageTypeEnabled);
useEffect(() => {
if (packageTypeEnabled) {
onChange?.({
...value,
orderSupplierList: orderSupplierList.map((item, index1) => {
if (index1 === index) {
return {
...item,
packageUsage: [
...(Object.entries(
packageTypeEnabled || {
EXTRA_USED: 0,
EXTRA: 0,
REMAIN: 0,
},
).map(
([boxType, isUsed]: [
BusinessAPI.OrderPackage["boxType"],
number,
]) => {
return {
boxType: boxType,
isUsed: isUsed,
};
},
) || []),
],
};
}
return item;
}),
});
}
}, [packageTypeEnabled]);
return (
<View className="flex flex-1 flex-col gap-2.5 p-2.5">
{/* 替换原来的Tab导航为问答式选择 */}
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
<View className="flex flex-col gap-2.5">
<View className="text-base font-bold">
{supplierVO.name}使
</View>
<PackageList
boxType={"USED"}
orderPackageList={orderPackageList}
setOrderPackageList={setOrderPackageList}
boxBrandList={boxBrandList}
/>
</View>
</View>
{/* 根据供应商属性显示不同的问题 */}
{supplierVO.isPaper && supplierVO.isLast && (
<>
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
<View className="flex flex-col gap-2.5">
{/* 空车带来的纸箱用完了吗? */}
<View className="flex items-center justify-between">
<View className="text-sm"></View>
<View className="flex flex-shrink-0 gap-2">
<Button
size="small"
type={
packageTypeEnabled.REMAIN === 2 ? "primary" : "default"
}
onClick={() => {
setPackageTypeEnabled({
...packageTypeEnabled,
REMAIN: 2,
});
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.REMAIN === 1) {
setOrderPackageList(
orderPackageList.filter(
(item) => item.boxType !== "REMAIN",
),
);
}
}}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.REMAIN === 1 ? "primary" : "default"
}
onClick={() => {
setPackageTypeEnabled({
...packageTypeEnabled,
REMAIN: 1,
});
}}
>
</Button>
</View>
</View>
{packageTypeEnabled.REMAIN === 1 && (
<PackageList
boxType={"REMAIN"}
orderPackageList={orderPackageList}
setOrderPackageList={setOrderPackageList}
boxBrandList={boxBrandList}
/>
)}
</View>
</View>
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
<View className="flex flex-col gap-2.5">
{/* 用额外运输纸箱的了吗? */}
<View className="flex items-center justify-between">
<View className="text-sm"></View>
<View className="flex flex-shrink-0 gap-2">
<Button
size="small"
type={
packageTypeEnabled.EXTRA_USED === 1
? "primary"
: "default"
}
onClick={() => {
setPackageTypeEnabled({
...packageTypeEnabled,
EXTRA_USED: 1,
});
}}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.EXTRA_USED === 2
? "primary"
: "default"
}
onClick={() => {
setPackageTypeEnabled({
...packageTypeEnabled,
EXTRA_USED: 2,
});
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.EXTRA_USED === 1) {
setOrderPackageList(
orderPackageList.filter(
(item) => item.boxType !== "EXTRA_USED",
),
);
}
}}
>
</Button>
</View>
</View>
{packageTypeEnabled.EXTRA_USED === 1 && (
<PackageList
boxType={"EXTRA_USED"}
orderPackageList={orderPackageList}
setOrderPackageList={setOrderPackageList}
boxBrandList={boxBrandList}
/>
)}
</View>
</View>
</>
)}
{supplierVO.isPaper && !supplierVO.isLast && (
/* 非最后一个瓜农 */
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
<View className="flex flex-col gap-2.5">
{/* 有额外运输纸箱过来吗? */}
<View className="flex items-center justify-between">
<View className="text-sm"></View>
<View className="flex flex-shrink-0 gap-2">
<Button
size="small"
type={
packageTypeEnabled.EXTRA === 1 ? "primary" : "default"
}
onClick={() => {
setPackageTypeEnabled({
...packageTypeEnabled,
EXTRA: 1,
});
}}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.EXTRA === 2 ? "primary" : "default"
}
onClick={() => {
setPackageTypeEnabled({
...packageTypeEnabled,
EXTRA: 2,
});
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.EXTRA === 1) {
setOrderPackageList(
orderPackageList.filter(
(item) => item.boxType !== "EXTRA",
),
);
}
}}
>
</Button>
</View>
</View>
{packageTypeEnabled.EXTRA === 1 && (
<PackageList
boxType={"EXTRA"}
orderPackageList={orderPackageList}
setOrderPackageList={setOrderPackageList}
boxBrandList={boxBrandList}
/>
)}
</View>
</View>
)}
</View>
);
},
);