- 统一调整多个 Picker 组件的内边距类名从 p-4 到 p-2.5 - 修改 OrderCost 和 OrderPackage 中图片容器的尺寸类名以适应全屏显示 - 移除 TicketUpload 中冗余的查看计算公式相关 UI 元素 - 更新 DealerInfoSection 中 DealerPicker 的手动输入属性为 false - 优化 PackagingCostSection 中固定成本选择器的可见性控制逻辑 - 调整 SupplierPicker 内部列表项的内边距类名 - 移除 center 页面中角色选中状态的勾选图标显示逻辑 - 格式化 invoice 页面中的导入语句以提高可读性
1534 lines
52 KiB
TypeScript
1534 lines
52 KiB
TypeScript
import { ScrollView, View } from "@tarojs/components";
|
||
import { Icon } from "@/components";
|
||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||
import { business } from "@/services";
|
||
import {
|
||
Button,
|
||
Checkbox,
|
||
Dialog,
|
||
Image,
|
||
Input,
|
||
Popup,
|
||
SafeArea,
|
||
Toast,
|
||
} from "@nutui/nutui-react-taro";
|
||
import {
|
||
BoxBrand,
|
||
BoxProduct,
|
||
BoxSpec,
|
||
CostItem,
|
||
SupplierVO,
|
||
} from "@/types/typings";
|
||
import { generateShortId } from "@/utils/generateShortId";
|
||
import {
|
||
convertBoxBrandToOrderPackages,
|
||
convertOrderPackagesToBoxBrands,
|
||
} from "@/utils/orderPackage";
|
||
import classNames from "classnames";
|
||
import { Decimal } from "decimal.js";
|
||
|
||
// 定义ref暴露的方法接口
|
||
export interface OrderCostRef {
|
||
validate: () => boolean;
|
||
}
|
||
|
||
export interface IOrderCostProps {
|
||
value: CostItem[];
|
||
supplierVO: SupplierVO;
|
||
onChange?: (costItemList: CostItem[]) => void;
|
||
emptyBoxList: BusinessAPI.OrderPackage[];
|
||
onEmptyBoxChange?: (orderPackageList: BusinessAPI.OrderPackage[]) => void;
|
||
onAdd: () => void;
|
||
costItemVOList: BusinessAPI.CostItemVO[];
|
||
foreman: string;
|
||
setForeman: (foreman: string) => void;
|
||
}
|
||
|
||
export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||
function OrderCost(IOrderCostProps, ref) {
|
||
const {
|
||
value,
|
||
supplierVO,
|
||
onChange,
|
||
onAdd,
|
||
onEmptyBoxChange,
|
||
emptyBoxList: defaultEmptyBoxList,
|
||
costItemVOList,
|
||
foreman,
|
||
setForeman,
|
||
} = IOrderCostProps;
|
||
console.log("defaultEmptyBoxList", defaultEmptyBoxList);
|
||
|
||
const [costItemList, setCostItemList] = useState<CostItem[]>();
|
||
|
||
// 新增状态:跟踪每种纸箱类型的启用状态
|
||
// 0: 未选, 1: 选择是
|
||
const [packageTypeEnabled, setPackageTypeEnabled] = useState({
|
||
EMPTY: 0,
|
||
});
|
||
|
||
// 空箱相关状态
|
||
const [emptyBoxList, setEmptyBoxList] = useState<
|
||
BusinessAPI.OrderPackage[]
|
||
>([]);
|
||
const [boxBrandList, setBoxBrandList] = useState<BoxBrand[]>();
|
||
|
||
const [emptyBoxCostItem, setEmptyBoxCostItem] = useState<CostItem>();
|
||
|
||
// 批量添加空箱相关状态
|
||
const [selectedBrand, setSelectedBrand] = useState<BoxBrand | null>(null);
|
||
const [productCounts, setProductCounts] = useState<Map<string, number>>(
|
||
new Map(),
|
||
);
|
||
const [showBatchModal, setShowBatchModal] = useState(false);
|
||
|
||
// 编辑空箱弹窗状态
|
||
const [showEditModal, setShowEditModal] = useState(false);
|
||
const [editingItem, setEditingItem] = useState<BoxBrand | null>(null);
|
||
|
||
// 处理纸箱类型启用状态切换
|
||
const togglePackageType = (
|
||
type: BusinessAPI.OrderPackage["boxType"],
|
||
value: number, // 0: 未选, 1: 选择是, 2: 选择否
|
||
) => {
|
||
setPackageTypeEnabled((prev) => ({
|
||
...prev,
|
||
[type]: value,
|
||
}));
|
||
};
|
||
|
||
// 当空箱列表变化时,生成空箱费固定费用项
|
||
useEffect(() => {
|
||
// 检查是否启用了空箱
|
||
if (packageTypeEnabled.EMPTY === 1) {
|
||
Decimal.set({
|
||
precision: 20,
|
||
rounding: 0, // 向下舍入(更保守的计算方式)
|
||
toExpNeg: -7,
|
||
toExpPos: 21,
|
||
});
|
||
|
||
// 计算空箱总数量
|
||
const totalEmptyBoxCount = emptyBoxList.reduce(
|
||
(sum, pkg) => new Decimal(sum).plus(pkg.boxCount || 0).toNumber(),
|
||
0,
|
||
);
|
||
|
||
// 如果有空箱且还没有空箱费项目,则添加空箱费固定费用项
|
||
if (totalEmptyBoxCount > 0) {
|
||
setCostItemList((prev) => {
|
||
if (!prev) return prev;
|
||
|
||
// 检查是否已存在空箱费项目
|
||
const hasEmptyBoxFee = prev.some(
|
||
(item) =>
|
||
item.name === "空箱费" && item.costType === "FIXED_COST",
|
||
);
|
||
|
||
const price = emptyBoxList?.reduce(
|
||
(sum, pkg) =>
|
||
new Decimal(sum)
|
||
.plus(
|
||
new Decimal(pkg.boxCount || 0).mul(pkg.boxCostPrice || 0),
|
||
)
|
||
.toNumber(),
|
||
0,
|
||
);
|
||
|
||
// 如果不存在空箱费项目,则添加
|
||
if (!hasEmptyBoxFee) {
|
||
const emptyBoxFeeItem: CostItem = {
|
||
orderCostId: generateShortId(),
|
||
itemId: emptyBoxCostItem?.itemId || "",
|
||
name: "空箱费",
|
||
price: price,
|
||
unit: "项",
|
||
selected: true,
|
||
count: 1,
|
||
payerType: "US",
|
||
principal: "",
|
||
costType: "FIXED_COST",
|
||
requireQuantityAndPrice: false,
|
||
};
|
||
|
||
return [...prev, emptyBoxFeeItem];
|
||
} else {
|
||
// 如果已存在空箱费项目,更新其数量
|
||
return prev.map((item) => {
|
||
if (item.name === "空箱费" && item.costType === "FIXED_COST") {
|
||
return {
|
||
...item,
|
||
price: price,
|
||
count: 1,
|
||
};
|
||
}
|
||
return item;
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// 通知父组件空箱列表变化
|
||
onEmptyBoxChange?.(
|
||
emptyBoxList?.map((item) => {
|
||
return {
|
||
...item,
|
||
id: generateShortId(),
|
||
};
|
||
}),
|
||
);
|
||
}, [emptyBoxList, packageTypeEnabled.EMPTY]);
|
||
|
||
// 工头姓名错误状态
|
||
const [foremanError, setForemanError] = useState<boolean>(false);
|
||
|
||
// 初始化空箱品牌数据
|
||
const initBoxBrandList = async () => {
|
||
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);
|
||
};
|
||
|
||
const init = async (costItemVOList) => {
|
||
if (costItemVOList) {
|
||
setEmptyBoxCostItem({
|
||
orderCostId: generateShortId(),
|
||
count: 0,
|
||
selected: true,
|
||
...costItemVOList?.find(
|
||
(item) => item.name === "空箱费" && item.costType === "FIXED_COST",
|
||
)!,
|
||
});
|
||
// 人工辅料选中
|
||
const initialList =
|
||
costItemVOList
|
||
?.filter(
|
||
(item) =>
|
||
item.costType === "HUMAN_COST" ||
|
||
item.costType === "PACKAGING_MATERIALS",
|
||
)
|
||
.map((item) => {
|
||
// 查找是否在purchaseOrder中已有该item的记录
|
||
const existingItem = value?.find(
|
||
(costItem) => costItem.itemId === item.itemId,
|
||
);
|
||
|
||
return {
|
||
orderCostId: existingItem?.orderCostId || generateShortId(),
|
||
itemId: item.itemId,
|
||
name: item.name,
|
||
price: item.price,
|
||
unit: item.unit,
|
||
selected: existingItem
|
||
? existingItem.selected && existingItem.count > 0
|
||
: false,
|
||
count: existingItem ? existingItem.count : 1,
|
||
payerType: existingItem ? existingItem.payerType : undefined,
|
||
principal: existingItem ? existingItem.principal : "",
|
||
costType: item.costType,
|
||
requireQuantityAndPrice: existingItem
|
||
? existingItem.requireQuantityAndPrice
|
||
: false,
|
||
};
|
||
}) || [];
|
||
|
||
setCostItemList([
|
||
...(initialList || []),
|
||
...(value
|
||
?.filter(
|
||
(item) =>
|
||
item.costType === "WORKER_ADVANCE" ||
|
||
item.costType === "PRODUCTION_ADVANCE" ||
|
||
item.costType === "FIXED_COST",
|
||
)
|
||
.map((item) => {
|
||
return {
|
||
orderCostId: item.orderCostId,
|
||
itemId: item.itemId,
|
||
name: item.name,
|
||
price: item.price,
|
||
unit: item.unit,
|
||
selected: item.selected,
|
||
count: item.count,
|
||
payerType: item.payerType,
|
||
principal: item.principal,
|
||
costType: item.costType,
|
||
requireQuantityAndPrice: item.requireQuantityAndPrice,
|
||
};
|
||
}) || []),
|
||
]);
|
||
}
|
||
};
|
||
|
||
// 当传入的value发生变化时,重新初始化列表
|
||
useEffect(() => {
|
||
init(costItemVOList).then();
|
||
initBoxBrandList().then();
|
||
setEmptyBoxList(defaultEmptyBoxList);
|
||
|
||
if (defaultEmptyBoxList.length > 0) {
|
||
// 根据当前供应商确定需要检查的纸箱类型
|
||
let requiredTypes: string[] = ["EMPTY"];
|
||
|
||
requiredTypes.map((type) => {
|
||
setPackageTypeEnabled((prev) => {
|
||
return {
|
||
...prev,
|
||
[type]: defaultEmptyBoxList.some((item) => item.boxType === type)
|
||
? 1
|
||
: 0,
|
||
};
|
||
});
|
||
});
|
||
}
|
||
}, []);
|
||
|
||
// 当内部状态发生变化时,通知父组件更新
|
||
useEffect(() => {
|
||
if (costItemList && onChange) {
|
||
// 更新所有启用且费用承担方为"我方"的人工费用项的工头姓名
|
||
const updatedList = costItemList.map((item) => {
|
||
if (
|
||
item.costType === "HUMAN_COST" &&
|
||
item.selected &&
|
||
item.payerType === "US"
|
||
) {
|
||
return { ...item, principal: foreman };
|
||
}
|
||
return item;
|
||
});
|
||
|
||
onChange(updatedList);
|
||
}
|
||
}, [costItemList, foreman]);
|
||
|
||
// 错误状态
|
||
const [countError, setCountError] = useState<{ [key: string]: boolean }>(
|
||
{},
|
||
);
|
||
const [payerTypeError, setPayerTypeError] = useState<{
|
||
[key: string]: boolean;
|
||
}>({});
|
||
|
||
// 设置人工项目选择状态
|
||
const setArtificialSelect = (id: string, selected: boolean) => {
|
||
if (!costItemList) return;
|
||
const newList = costItemList.map((item) =>
|
||
item.orderCostId === id ? { ...item, selected } : item,
|
||
);
|
||
setCostItemList(newList);
|
||
};
|
||
|
||
// 处理数量变化
|
||
const handleCountChange = (id: string, value: number) => {
|
||
if (!costItemList) return;
|
||
const newList = costItemList.map((item) =>
|
||
item.orderCostId === id ? { ...item, count: value } : item,
|
||
);
|
||
setCostItemList(newList);
|
||
|
||
// 校验数量
|
||
if (costItemList.find((item) => item.orderCostId === id)?.selected) {
|
||
validateCount(id, value);
|
||
}
|
||
};
|
||
|
||
// 校验数量
|
||
const validateCount = (id: string, value: number) => {
|
||
const isValid = value > 0;
|
||
setCountError((prev) => ({
|
||
...prev,
|
||
[id]: !isValid,
|
||
}));
|
||
return isValid;
|
||
};
|
||
|
||
// 校验费用承担方
|
||
const validatePayerType = (id: string, value: CostItem["payerType"]) => {
|
||
const isValid = value === "US" || value === "OTHER";
|
||
setPayerTypeError((prev) => ({
|
||
...prev,
|
||
[id]: !isValid,
|
||
}));
|
||
return isValid;
|
||
};
|
||
|
||
// 校验工头姓名
|
||
const validatePrincipal = (value: string) => {
|
||
const isValid = value.trim().length > 0;
|
||
setForemanError(!isValid);
|
||
return isValid;
|
||
};
|
||
|
||
// 处理费用承担方变化
|
||
const handlePayerTypeChange = (
|
||
id: string,
|
||
value: CostItem["payerType"],
|
||
) => {
|
||
if (!costItemList) return;
|
||
const newList = costItemList.map((item) =>
|
||
item.orderCostId === id ? { ...item, payerType: value } : item,
|
||
);
|
||
setCostItemList(newList);
|
||
|
||
// 校验费用承担方
|
||
if (costItemList.find((item) => item.orderCostId === id)?.selected) {
|
||
validatePayerType(id, value);
|
||
}
|
||
};
|
||
|
||
// 处理工头姓名变化
|
||
const handleForemanChange = (value: string) => {
|
||
setForeman(value);
|
||
|
||
// 如果有启用且费用承担方为"我方"的项目,则校验工头姓名
|
||
const enabledUsItems = costItemList?.filter(
|
||
(item) =>
|
||
item.costType === "HUMAN_COST" &&
|
||
item.selected &&
|
||
item.payerType === "US",
|
||
);
|
||
if (enabledUsItems && enabledUsItems.length > 0) {
|
||
validatePrincipal(value);
|
||
}
|
||
};
|
||
|
||
// 失去焦点时校验数量
|
||
const handleCountBlur = (id: string, value: number) => {
|
||
validateCount(id, value);
|
||
};
|
||
|
||
// 失去焦点时校验工头姓名
|
||
const handlePrincipalBlur = (value: string) => {
|
||
validatePrincipal(value);
|
||
};
|
||
|
||
// 对外暴露的校验方法
|
||
const validate = () => {
|
||
if (!costItemList) return true;
|
||
|
||
let isValid = true;
|
||
|
||
// 校验人工和辅料费用
|
||
costItemList.forEach((item) => {
|
||
if (item.selected) {
|
||
// 校验数量
|
||
if (!validateCount(item.orderCostId, item.count)) {
|
||
isValid = false;
|
||
}
|
||
|
||
if (item.costType === "HUMAN_COST") {
|
||
// 校验费用承担方
|
||
if (!validatePayerType(item.orderCostId, item.payerType)) {
|
||
isValid = false;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// 校验总的工头姓名(如果有启用且费用承担方为"我方"的项目)
|
||
const enabledUsItems = costItemList.filter(
|
||
(item) =>
|
||
item.costType === "HUMAN_COST" &&
|
||
item.selected &&
|
||
item.payerType === "US",
|
||
);
|
||
|
||
isValid = true;
|
||
if (enabledUsItems.length > 0) {
|
||
if (!validatePrincipal(foreman)) {
|
||
isValid = false;
|
||
}
|
||
}
|
||
|
||
if (!isValid) {
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: "提示",
|
||
content: "请完善人工信息后再进行下一步操作",
|
||
});
|
||
}
|
||
|
||
return isValid;
|
||
};
|
||
|
||
useImperativeHandle(ref, () => ({
|
||
validate,
|
||
}));
|
||
|
||
// 获取指定类型的项目列表
|
||
const getItemsByCostType = (costType: string) => {
|
||
return costItemList?.filter((item) => item.costType === costType) || [];
|
||
};
|
||
|
||
// 渲染项目列表
|
||
const renderItemList = (items: CostItem[], type: string) => {
|
||
return items.map((item) => (
|
||
<View key={item.orderCostId}>
|
||
<View className={"flex flex-col gap-2.5 rounded-lg bg-white p-2.5"}>
|
||
<View className={"flex flex-row justify-between"}>
|
||
<View className="block text-sm font-normal text-[#000000]">
|
||
{item.name}
|
||
</View>
|
||
<Checkbox
|
||
className={"flex flex-row items-center"}
|
||
checked={item.selected}
|
||
onChange={(checked) => {
|
||
setArtificialSelect(item.orderCostId, checked);
|
||
}}
|
||
>
|
||
<View className={"text-sm font-normal text-[#000000]"}>
|
||
用了
|
||
</View>
|
||
</Checkbox>
|
||
</View>
|
||
|
||
{item.selected && type === "HUMAN_COST" && (
|
||
<View>
|
||
{/* 费用承担方改为按钮形式,参考OrderPackage中的样式 */}
|
||
<View className="flex items-center justify-between">
|
||
<View className="flex-shrink-0 text-sm">谁出钱:</View>
|
||
<View className="flex gap-2">
|
||
<Button
|
||
size="small"
|
||
type={item.payerType === "US" ? "primary" : "default"}
|
||
onClick={() => {
|
||
handlePayerTypeChange(item.orderCostId, "US");
|
||
}}
|
||
>
|
||
我们出
|
||
</Button>
|
||
<Button
|
||
size="small"
|
||
type={item.payerType === "OTHER" ? "primary" : "default"}
|
||
onClick={() => {
|
||
handlePayerTypeChange(item.orderCostId, "OTHER");
|
||
}}
|
||
>
|
||
对方出
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
|
||
{payerTypeError[item.orderCostId] && item.selected && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
请选择谁出这笔钱
|
||
</View>
|
||
)}
|
||
</View>
|
||
)}
|
||
|
||
{item.selected && (
|
||
<View>
|
||
<View className="flex items-center justify-between gap-2">
|
||
<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"
|
||
onClick={() => {
|
||
const count = item.count || 1;
|
||
handleCountChange(
|
||
item.orderCostId,
|
||
Math.max(1, count - 1),
|
||
);
|
||
}}
|
||
>
|
||
<Icon name="minus" size={20} />
|
||
</View>
|
||
<View
|
||
className={`flex h-12 w-full shrink items-center border-4 border-gray-200`}
|
||
>
|
||
<Input
|
||
type="number"
|
||
value={item.count.toString()}
|
||
align={"center"}
|
||
placeholder={"用了多少"}
|
||
onChange={(value) => {
|
||
handleCountChange(item.orderCostId, Number(value));
|
||
}}
|
||
formatter={(value) =>
|
||
Math.max(1, Number(value)).toString()
|
||
}
|
||
onBlur={() =>
|
||
handleCountBlur(item.orderCostId, item.count)
|
||
}
|
||
/>
|
||
</View>
|
||
<View
|
||
className="rounded-r-button flex !size-12 flex-none items-center justify-center bg-gray-200 text-sm"
|
||
onClick={() => {
|
||
const count = item.count || 1;
|
||
handleCountChange(item.orderCostId, count + 1);
|
||
}}
|
||
>
|
||
<Icon name="plus" size={20} />
|
||
</View>
|
||
|
||
<View className={"ml-2.5 text-sm text-gray-500"}>
|
||
{item.unit}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{countError[item.orderCostId] && item.selected && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
请填写正确的数量
|
||
</View>
|
||
)}
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>
|
||
));
|
||
};
|
||
|
||
// 检查是否有人工费用项被启用且费用承担方为"我方"
|
||
const shouldShowPrincipalInput = () => {
|
||
return (
|
||
costItemList?.some(
|
||
(item) =>
|
||
item.costType === "HUMAN_COST" &&
|
||
item.selected &&
|
||
item.payerType === "US",
|
||
) || false
|
||
);
|
||
};
|
||
|
||
// 处理批量添加时的品牌选择
|
||
const handleBatchBrandSelect = (brand: BoxBrand) => {
|
||
// 检查是否已存在该品牌
|
||
const isBrandAlreadySelected = emptyBoxList.some(
|
||
(pkg) => pkg.boxBrandId === brand.boxBrandId,
|
||
);
|
||
|
||
if (isBrandAlreadySelected) {
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: "提示",
|
||
content: "该空箱品牌已存在,请选择其他品牌或编辑现有信息",
|
||
});
|
||
return;
|
||
}
|
||
|
||
setSelectedBrand(brand);
|
||
// 初始化所有产品的数量为0
|
||
const initialCounts = new Map<string, number>();
|
||
brand.boxSpecList?.forEach((boxSpec) => {
|
||
boxSpec.boxProductList.forEach((product) => {
|
||
initialCounts.set(product.id, 0);
|
||
});
|
||
});
|
||
setProductCounts(initialCounts);
|
||
};
|
||
|
||
// 处理产品数量变化
|
||
const handleProductCountChange = (productId: string, count: number) => {
|
||
setProductCounts((prev) => {
|
||
const newCounts = new Map(prev);
|
||
newCounts.set(productId, Math.max(0, count)); // 允许为0,表示不使用
|
||
return newCounts;
|
||
});
|
||
|
||
// 同时更新selectedBrand中的产品数量
|
||
if (selectedBrand) {
|
||
const updatedBrand = { ...selectedBrand };
|
||
|
||
updatedBrand.boxSpecList = updatedBrand.boxSpecList?.map((boxSpec) => {
|
||
const updatedProducts = boxSpec.boxProductList.map((product) => {
|
||
if (product.id === productId) {
|
||
return { ...product, boxCount: count };
|
||
}
|
||
return product;
|
||
});
|
||
return { ...boxSpec, boxProductList: updatedProducts };
|
||
});
|
||
setSelectedBrand(updatedBrand);
|
||
}
|
||
};
|
||
|
||
// 批量添加空箱信息
|
||
const addBatchEmptyBoxInfo = () => {
|
||
if (!selectedBrand) {
|
||
return;
|
||
}
|
||
|
||
// 使用convertBoxBrandToOrderPackages转换数据
|
||
const newOrderPackages = convertBoxBrandToOrderPackages(
|
||
selectedBrand,
|
||
"EMPTY",
|
||
);
|
||
|
||
// 过滤掉数量为0的项目
|
||
const filteredOrderPackages = newOrderPackages.filter((pkg) => {
|
||
// 从productCounts中获取对应产品的数量
|
||
const product = selectedBrand.boxSpecList
|
||
?.flatMap((c) => c.boxProductList)
|
||
.find((p) => p.id === pkg.orderPackageId);
|
||
const count = product ? productCounts.get(product.id) || 0 : 0;
|
||
return count > 0;
|
||
});
|
||
|
||
// 更新数量信息
|
||
const updatedOrderPackages = filteredOrderPackages.map((pkg) => {
|
||
// 从productCounts中获取对应产品的数量
|
||
const product = selectedBrand.boxSpecList
|
||
?.flatMap((c) => c.boxProductList)
|
||
.find((p) => p.id === pkg.orderPackageId);
|
||
const count = product ? productCounts.get(product.id) || 0 : 0;
|
||
return {
|
||
...pkg,
|
||
boxCount: count,
|
||
};
|
||
});
|
||
|
||
// 添加到emptyBoxList中
|
||
setEmptyBoxList((prev) => [...prev, ...updatedOrderPackages]);
|
||
|
||
// 重置选择并关闭弹窗
|
||
setSelectedBrand(null);
|
||
setProductCounts(new Map());
|
||
setShowBatchModal(false);
|
||
};
|
||
|
||
// 删除空箱信息
|
||
const removeEmptyBoxInfo = (boxBrandId: string) => {
|
||
console.log("removeEmptyBoxInfo", boxBrandId);
|
||
Dialog.open("dialog", {
|
||
title: "提示",
|
||
content: "确定要移除此空箱品牌吗?",
|
||
confirmText: "确定",
|
||
cancelText: "取消",
|
||
onConfirm: () => {
|
||
const newList = [
|
||
...emptyBoxList.filter((item) => item.boxBrandId !== boxBrandId),
|
||
];
|
||
setEmptyBoxList(newList);
|
||
Dialog.close("dialog");
|
||
},
|
||
onCancel: () => {
|
||
Dialog.close("dialog");
|
||
},
|
||
});
|
||
};
|
||
|
||
// 处理编辑按钮点击
|
||
const handleEditItem = (item: BoxBrand) => {
|
||
// 从emptyBoxList中找到完整的品牌信息用于编辑
|
||
const brandToEdit = convertOrderPackagesToBoxBrands(
|
||
emptyBoxList.filter((pkg) => pkg.boxBrandId === item.boxBrandId),
|
||
)[0];
|
||
|
||
// 获取完整品牌信息(包括所有规格)
|
||
const fullBrandInfo = boxBrandList?.find(
|
||
(brand) => brand.boxBrandId === item.boxBrandId,
|
||
);
|
||
|
||
// 合并已有的数据和完整品牌信息
|
||
const mergedBrandInfo = fullBrandInfo
|
||
? ({
|
||
...fullBrandInfo,
|
||
boxType: "EMPTY", // 保持boxType
|
||
boxSpecList: fullBrandInfo.boxSpecList?.map((boxSpec) => {
|
||
// 找到对应的已存在分类数据
|
||
const existingSpec = brandToEdit?.boxSpecList?.find(
|
||
(spec) => spec.boxSpecId === boxSpec.boxSpecId,
|
||
);
|
||
|
||
return {
|
||
...boxSpec,
|
||
boxProductList: boxSpec.boxProductList.map((product) => {
|
||
// 找到对应的产品数据
|
||
const existingProduct = existingSpec?.boxProductList.find(
|
||
(prod) => prod.boxProductId === product.boxProductId,
|
||
);
|
||
|
||
return {
|
||
...product,
|
||
boxCount: existingProduct?.boxCount || 0,
|
||
};
|
||
}),
|
||
};
|
||
}),
|
||
} as BoxBrand)
|
||
: brandToEdit;
|
||
|
||
if (mergedBrandInfo) {
|
||
setEditingItem(mergedBrandInfo);
|
||
setShowEditModal(true);
|
||
}
|
||
};
|
||
|
||
// 更新编辑项中的数量
|
||
const updateEditingItemCount = (
|
||
specIndex: number,
|
||
detailIndex: number,
|
||
count: number,
|
||
) => {
|
||
if (!editingItem) return;
|
||
|
||
// 获取完整品牌信息
|
||
const fullBrandInfo = boxBrandList?.find(
|
||
(brand) => brand.boxBrandId === editingItem.boxBrandId,
|
||
);
|
||
|
||
if (!fullBrandInfo) return;
|
||
|
||
const updatedItem = { ...editingItem };
|
||
|
||
// 确保boxSpecList存在
|
||
if (!updatedItem.boxSpecList) {
|
||
updatedItem.boxSpecList = fullBrandInfo.boxSpecList.map((boxSpec) => ({
|
||
...boxSpec,
|
||
boxProductList: boxSpec.boxProductList.map((product) => ({
|
||
...product,
|
||
boxCount: 0,
|
||
})),
|
||
}));
|
||
}
|
||
|
||
// 确保spec存在
|
||
if (!updatedItem.boxSpecList[specIndex]) {
|
||
updatedItem.boxSpecList[specIndex] = {
|
||
...fullBrandInfo.boxSpecList[specIndex],
|
||
boxProductList: fullBrandInfo.boxSpecList[
|
||
specIndex
|
||
].boxProductList.map((product) => ({
|
||
...product,
|
||
boxCount: 0,
|
||
})),
|
||
};
|
||
}
|
||
|
||
// 更新对应的产品数量
|
||
const boxSpec = { ...updatedItem.boxSpecList[specIndex] };
|
||
|
||
// 确保boxProductList存在
|
||
if (!boxSpec.boxProductList) {
|
||
boxSpec.boxProductList = fullBrandInfo.boxSpecList[
|
||
specIndex
|
||
].boxProductList.map((product) => ({
|
||
...product,
|
||
boxCount: 0,
|
||
}));
|
||
}
|
||
|
||
const boxProductList = [...boxSpec.boxProductList];
|
||
|
||
// 确保产品存在
|
||
if (!boxProductList[detailIndex]) {
|
||
boxProductList[detailIndex] = {
|
||
...fullBrandInfo.boxSpecList[specIndex].boxProductList[detailIndex],
|
||
boxCount: 0,
|
||
};
|
||
}
|
||
|
||
boxProductList[detailIndex] = {
|
||
...boxProductList[detailIndex],
|
||
boxCount: count,
|
||
};
|
||
|
||
boxSpec.boxProductList = boxProductList;
|
||
const updatedSpecList = [...updatedItem.boxSpecList];
|
||
updatedSpecList[specIndex] = boxSpec;
|
||
updatedItem.boxSpecList = updatedSpecList;
|
||
|
||
setEditingItem(updatedItem);
|
||
};
|
||
|
||
// 保存编辑的空箱信息
|
||
const saveEditedItem = () => {
|
||
if (editingItem) {
|
||
// 检查是否尝试更改为已存在的品牌(排除自身)
|
||
const isBrandAlreadySelected = emptyBoxList.some(
|
||
(pkg) =>
|
||
pkg.boxBrandId === editingItem.boxBrandId &&
|
||
!(pkg.boxBrandId === editingItem.boxBrandId),
|
||
);
|
||
|
||
if (isBrandAlreadySelected) {
|
||
Toast.show("toast", {
|
||
icon: "fail",
|
||
title: "提示",
|
||
content: "该空箱品牌已存在,请选择其他品牌",
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 使用convertBoxBrandToOrderPackages转换编辑后的数据
|
||
const updatedOrderPackages = convertBoxBrandToOrderPackages(
|
||
editingItem,
|
||
"EMPTY",
|
||
).filter((pkg) => pkg.boxCount > 0);
|
||
|
||
// 更新emptyBoxList
|
||
const newList = [...emptyBoxList];
|
||
// 找到对应品牌和类型的现有项目并替换
|
||
const startIndex = newList.findIndex(
|
||
(pkg) => pkg.boxBrandId === editingItem.boxBrandId,
|
||
);
|
||
|
||
if (startIndex !== -1) {
|
||
// 移除旧的项目
|
||
const filteredList = newList.filter(
|
||
(pkg) => !(pkg.boxBrandId === editingItem.boxBrandId),
|
||
);
|
||
|
||
// 添加更新后的项目
|
||
setEmptyBoxList([...filteredList, ...updatedOrderPackages]);
|
||
} else {
|
||
// 如果没有找到,直接添加
|
||
setEmptyBoxList((prev) => [...prev, ...updatedOrderPackages]);
|
||
}
|
||
}
|
||
setShowEditModal(false);
|
||
setEditingItem(null);
|
||
};
|
||
|
||
// 渲染单个空箱信息模块
|
||
const renderEmptyBoxItem = (item: BoxBrand) => {
|
||
// 获取品牌信息用于展示品牌图片
|
||
const brandInfo = boxBrandList?.find(
|
||
(brand) => brand.boxBrandId === item.boxBrandId,
|
||
);
|
||
|
||
return (
|
||
<View
|
||
className="mb-2.5 overflow-hidden rounded-xl border border-gray-200 bg-white p-2.5 shadow-sm"
|
||
key={item.id}
|
||
>
|
||
{/* 品牌背景水印 */}
|
||
{brandInfo?.boxBrandImage && (
|
||
<View className="absolute top-2 right-2 opacity-10">
|
||
<Image
|
||
src={brandInfo.boxBrandImage}
|
||
className="h-full w-full"
|
||
mode="aspectFit"
|
||
/>
|
||
</View>
|
||
)}
|
||
|
||
{/* 品牌信息和操作按钮放在同一行 */}
|
||
<View className="mb-3 flex items-start justify-between">
|
||
<View className="flex items-center">
|
||
{brandInfo?.boxBrandImage && (
|
||
<View className="mr-3 h-10 w-10 overflow-hidden rounded-lg border border-gray-200">
|
||
<Image
|
||
src={brandInfo.boxBrandImage}
|
||
className="h-full w-full"
|
||
mode="aspectFit"
|
||
/>
|
||
</View>
|
||
)}
|
||
<View>
|
||
<View className="text-lg font-bold text-gray-800">
|
||
{item.boxBrandName || "未选择品牌"}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 操作按钮与品牌信息放在同一行 */}
|
||
<View className="flex gap-2">
|
||
<View
|
||
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)}
|
||
>
|
||
编辑
|
||
</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={() => {
|
||
console.log("removeEmptyBoxInfo", item.boxBrandId);
|
||
removeEmptyBoxInfo(item.boxBrandId);
|
||
}}
|
||
>
|
||
移除
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 详细信息展示,按分类显示 */}
|
||
<View className="space-y-2">
|
||
{item.boxSpecList &&
|
||
item.boxSpecList.map((boxSpec, boxIndex) => (
|
||
<View
|
||
key={boxIndex}
|
||
className="rounded-lg bg-gray-50 p-3 text-sm text-gray-600"
|
||
>
|
||
<View className="mb-1 font-medium text-gray-700">
|
||
{boxSpec.boxSpecName}
|
||
</View>
|
||
<View>
|
||
{boxSpec.boxProductList
|
||
.map(
|
||
(detail) =>
|
||
`${detail.boxProductName} 共 ${detail.boxCount} 个`,
|
||
)
|
||
.join(",")}
|
||
</View>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
);
|
||
};
|
||
|
||
// 渲染批量添加空箱弹窗
|
||
const renderBatchAddModal = () => {
|
||
// 检查是否至少有一个产品的数量大于0
|
||
const hasAnyProductWithCount = selectedBrand
|
||
? Array.from(productCounts.values()).some((count) => count > 0)
|
||
: false;
|
||
|
||
return (
|
||
<Popup
|
||
duration={150}
|
||
style={{
|
||
minHeight: "auto",
|
||
}}
|
||
visible={showBatchModal}
|
||
position="bottom"
|
||
onClose={() => {
|
||
setShowBatchModal(false);
|
||
setSelectedBrand(null);
|
||
setProductCounts(new Map());
|
||
}}
|
||
title={"批量添加空箱"}
|
||
round
|
||
>
|
||
<View className="p-2.5">
|
||
<ScrollView
|
||
scrollY
|
||
style={{
|
||
height: "65vh",
|
||
width: "100%",
|
||
}}
|
||
>
|
||
{/* 品牌选择 */}
|
||
<View className="mb-4">
|
||
<View className="mb-2 text-sm text-gray-600">选择品牌</View>
|
||
<ScrollView className="mb-2.5" scrollX>
|
||
<View className="flex w-fit flex-row gap-2.5">
|
||
{boxBrandList
|
||
?.filter((item) => item.boxBrandType !== "FARMER_BOX")
|
||
?.map((boxBrand) => (
|
||
<View
|
||
key={boxBrand.id}
|
||
className={
|
||
"flex flex-col items-center justify-center"
|
||
}
|
||
onClick={() => handleBatchBrandSelect(boxBrand)}
|
||
>
|
||
<View
|
||
className={classNames(
|
||
"border-primary box-content !size-16 overflow-hidden rounded-xl border-4 object-cover",
|
||
{
|
||
"border-primary":
|
||
selectedBrand?.id === boxBrand.id,
|
||
"border-transparent":
|
||
selectedBrand?.id !== boxBrand.id,
|
||
},
|
||
)}
|
||
>
|
||
<Image
|
||
src={boxBrand.boxBrandImage}
|
||
className="h-full w-full"
|
||
mode={"aspectFill"}
|
||
alt={boxBrand.boxBrandImage}
|
||
/>
|
||
</View>
|
||
<View className="text-center text-xs">
|
||
{boxBrand.boxBrandName}
|
||
</View>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</ScrollView>
|
||
</View>
|
||
|
||
{/* 未选择品牌时的提示 */}
|
||
{!selectedBrand && (
|
||
<View className="mb-4 rounded-lg bg-yellow-50 p-4 text-center">
|
||
<View className="text-yellow-800">请先选择一个品牌</View>
|
||
</View>
|
||
)}
|
||
|
||
{/* 产品展示 */}
|
||
{selectedBrand && (
|
||
<View className="mb-4">
|
||
<View className="mb-2 text-sm text-gray-600">
|
||
空箱规格(点击 +/- 修改数量,0表示不使用)
|
||
</View>
|
||
{selectedBrand.boxSpecList?.map((boxSpec) => (
|
||
<View key={boxSpec.id} className="mb-4">
|
||
<View className="mb-2 text-base font-medium">
|
||
{boxSpec.boxSpecName}
|
||
</View>
|
||
<View className="space-y-3">
|
||
{boxSpec.boxProductList.map((boxProduct) => {
|
||
const currentCount =
|
||
productCounts.get(boxProduct.id) || 0;
|
||
return (
|
||
<View
|
||
key={boxProduct.id}
|
||
className="flex items-center justify-between rounded-lg bg-gray-50 p-3"
|
||
>
|
||
<View className="text-gray-800">
|
||
{boxProduct.boxProductName}
|
||
</View>
|
||
<View className="flex items-center">
|
||
<View
|
||
className="flex h-8 w-8 items-center justify-center rounded-l bg-gray-200"
|
||
onClick={() => {
|
||
handleProductCountChange(
|
||
boxProduct.id,
|
||
Math.max(0, currentCount - 1),
|
||
);
|
||
}}
|
||
>
|
||
<Icon name="minus" size={16} />
|
||
</View>
|
||
<View className="flex h-8 w-12 items-center justify-center border-y border-gray-200">
|
||
<Input
|
||
type="number"
|
||
value={currentCount.toString()}
|
||
align={"center"}
|
||
className="!h-8 !w-12 !p-0 !text-center"
|
||
onChange={(value) => {
|
||
const num = Number(value);
|
||
if (!Number.isNaN(num) && num >= 0) {
|
||
handleProductCountChange(
|
||
boxProduct.id,
|
||
num,
|
||
);
|
||
}
|
||
}}
|
||
/>
|
||
</View>
|
||
<View
|
||
className="flex h-8 w-8 items-center justify-center rounded-r bg-gray-200"
|
||
onClick={() => {
|
||
handleProductCountChange(
|
||
boxProduct.id,
|
||
currentCount + 1,
|
||
);
|
||
}}
|
||
>
|
||
<Icon name="plus" size={16} />
|
||
</View>
|
||
<View className="ml-2 text-gray-800">个</View>
|
||
</View>
|
||
</View>
|
||
);
|
||
})}
|
||
</View>
|
||
</View>
|
||
))}
|
||
</View>
|
||
)}
|
||
</ScrollView>
|
||
|
||
{/* 底部按钮 */}
|
||
<View className="flex gap-2 pt-4">
|
||
<View className="flex-1">
|
||
<Button
|
||
type={"default"}
|
||
size={"large"}
|
||
block
|
||
onClick={() => {
|
||
setShowBatchModal(false);
|
||
setSelectedBrand(null);
|
||
setProductCounts(new Map());
|
||
}}
|
||
>
|
||
取消
|
||
</Button>
|
||
</View>
|
||
<View className="flex-1">
|
||
<Button
|
||
type={"primary"}
|
||
size={"large"}
|
||
block
|
||
disabled={!selectedBrand || !hasAnyProductWithCount}
|
||
onClick={addBatchEmptyBoxInfo}
|
||
>
|
||
保存
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
<SafeArea position={"bottom"} />
|
||
</View>
|
||
</Popup>
|
||
);
|
||
};
|
||
|
||
// 渲染编辑空箱弹窗
|
||
const renderEditModal = () => {
|
||
if (!editingItem) return null;
|
||
|
||
// 获取品牌信息
|
||
const brandInfo = boxBrandList?.find(
|
||
(brand) => brand.boxBrandId === editingItem.boxBrandId,
|
||
);
|
||
|
||
return (
|
||
<Popup
|
||
duration={150}
|
||
style={{
|
||
minHeight: "auto",
|
||
}}
|
||
visible={showEditModal}
|
||
position="bottom"
|
||
onClose={() => setShowEditModal(false)}
|
||
title={"编辑空箱信息"}
|
||
round
|
||
>
|
||
<View className="p-2.5">
|
||
<ScrollView
|
||
scrollY
|
||
style={{
|
||
height: "65vh",
|
||
width: "100%",
|
||
}}
|
||
>
|
||
{/* 品牌信息 */}
|
||
<View className="mb-4">
|
||
<View className="mb-2 text-sm text-gray-600">品牌信息</View>
|
||
<View className="flex items-center rounded-lg bg-gray-50 p-3">
|
||
{brandInfo?.boxBrandImage && (
|
||
<View className="border-primary mr-3 h-16 w-16 overflow-hidden rounded-xl border-4 object-cover">
|
||
<Image
|
||
src={brandInfo.boxBrandImage}
|
||
className="h-full w-full"
|
||
mode="aspectFill"
|
||
/>
|
||
</View>
|
||
)}
|
||
<View className="text-base font-medium text-gray-800">
|
||
{editingItem.boxBrandName}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 详细信息 */}
|
||
<View className="mb-4">
|
||
<View className="mb-2 text-sm text-gray-600">空箱详情</View>
|
||
<View className="space-y-3">
|
||
{editingItem?.boxSpecList &&
|
||
editingItem.boxSpecList.map((boxSpec, specId) => (
|
||
<View key={specId} className="rounded-lg bg-gray-50 p-3">
|
||
<View className="mb-2 text-base font-medium text-gray-800">
|
||
{boxSpec.boxSpecName}
|
||
</View>
|
||
<View className="space-y-2">
|
||
{boxSpec.boxProductList.map((detail, detailIndex) => {
|
||
const currentCount = detail?.boxCount || 0;
|
||
|
||
return (
|
||
<View
|
||
key={detailIndex}
|
||
className="flex items-center justify-between py-1"
|
||
>
|
||
<View className="text-gray-600">
|
||
{detail.boxProductName}
|
||
</View>
|
||
<View className="flex items-center">
|
||
<View
|
||
className="flex h-8 w-8 items-center justify-center rounded-l bg-gray-200"
|
||
onClick={() => {
|
||
const newCount = Math.max(
|
||
0,
|
||
currentCount - 1,
|
||
);
|
||
updateEditingItemCount(
|
||
specId,
|
||
detailIndex,
|
||
newCount,
|
||
);
|
||
}}
|
||
>
|
||
<Icon name="minus" size={16} />
|
||
</View>
|
||
<View className="flex h-8 w-12 items-center justify-center border-y border-gray-200">
|
||
<Input
|
||
type="number"
|
||
value={currentCount.toString()}
|
||
align={"center"}
|
||
className="!h-8 !w-12 !p-0 !text-center"
|
||
onChange={(value) => {
|
||
const num = Number(value);
|
||
if (!Number.isNaN(num) && num >= 0) {
|
||
updateEditingItemCount(
|
||
specId,
|
||
detailIndex,
|
||
num,
|
||
);
|
||
}
|
||
}}
|
||
/>
|
||
</View>
|
||
<View
|
||
className="flex h-8 w-8 items-center justify-center rounded-r bg-gray-200"
|
||
onClick={() => {
|
||
updateEditingItemCount(
|
||
specId,
|
||
detailIndex,
|
||
currentCount + 1,
|
||
);
|
||
}}
|
||
>
|
||
<Icon name="plus" size={16} />
|
||
</View>
|
||
<View className="ml-2 font-medium text-gray-800">
|
||
个
|
||
</View>
|
||
</View>
|
||
</View>
|
||
);
|
||
})}
|
||
</View>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
</ScrollView>
|
||
|
||
{/* 底部按钮 */}
|
||
<View className="flex gap-2 pt-4">
|
||
<View className="flex-1">
|
||
<Button
|
||
size={"large"}
|
||
type={"default"}
|
||
block
|
||
onClick={() => setShowEditModal(false)}
|
||
>
|
||
取消
|
||
</Button>
|
||
</View>
|
||
<View className="flex-1">
|
||
<Button
|
||
type="primary"
|
||
size={"large"}
|
||
block
|
||
onClick={saveEditedItem}
|
||
>
|
||
保存
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
<SafeArea position={"bottom"} />
|
||
</View>
|
||
</Popup>
|
||
);
|
||
};
|
||
|
||
// 获取空箱列表
|
||
const emptyBoxes = convertOrderPackagesToBoxBrands(emptyBoxList);
|
||
|
||
return (
|
||
<View className="flex flex-1 flex-col gap-2.5 bg-[#D1D5DB] p-2.5 pt-2.5">
|
||
<View className={"flex flex-1 flex-col gap-2.5"}>
|
||
<View className="text-sm font-bold">人工费用</View>
|
||
<View className="flex items-center rounded-lg border border-blue-200 bg-blue-50 p-2.5">
|
||
<Icon
|
||
className={"mr-1"}
|
||
name="circle-info"
|
||
color={"var(--color-blue-700)"}
|
||
size={18}
|
||
/>
|
||
<View className={"text-sm text-blue-700"}>对方出钱可以不勾选</View>
|
||
</View>
|
||
{renderItemList(getItemsByCostType("HUMAN_COST"), "HUMAN_COST")}
|
||
|
||
{/* 总的工头姓名输入框 */}
|
||
{shouldShowPrincipalInput() && (
|
||
<View>
|
||
<View className="mb-1 text-sm font-medium">工头叫什么名字</View>
|
||
<View
|
||
className={`flex h-12 items-center rounded-md px-3 ${foremanError ? "border-2 border-red-500 bg-red-100" : "border-2 border-gray-300 bg-white"}`}
|
||
>
|
||
<Input
|
||
className="text-base"
|
||
type="text"
|
||
placeholder={"工头的名字"}
|
||
value={foreman}
|
||
onChange={(value) => {
|
||
handleForemanChange(value);
|
||
}}
|
||
onBlur={() => handlePrincipalBlur(foreman)}
|
||
/>
|
||
</View>
|
||
{foremanError && (
|
||
<View className="mt-1 text-xs text-red-500">
|
||
工头叫啥子填一下
|
||
</View>
|
||
)}
|
||
</View>
|
||
)}
|
||
</View>
|
||
<View className={"flex flex-1 flex-col gap-2.5"}>
|
||
<View className="text-sm font-bold">辅料费用</View>
|
||
<View className="flex items-center rounded-lg border border-blue-200 bg-blue-50 p-2.5">
|
||
<Icon
|
||
className={"mr-1"}
|
||
name="circle-info"
|
||
color={"var(--color-blue-700)"}
|
||
size={18}
|
||
/>
|
||
<View className={"text-sm text-blue-700"}>用了几包就填几包</View>
|
||
</View>
|
||
{renderItemList(
|
||
getItemsByCostType("PACKAGING_MATERIALS"),
|
||
"PACKAGING_MATERIALS",
|
||
)}
|
||
</View>
|
||
<View className={"flex flex-1 flex-col gap-2.5"}>
|
||
<View className="text-sm font-bold">空箱费用</View>
|
||
<View className="flex flex-col gap-2.5 rounded-lg bg-white p-2.5 shadow-sm">
|
||
<View className="flex items-center justify-between">
|
||
<View className="text-sm">带空箱了吗?</View>
|
||
<View className="flex flex-shrink-0 gap-2">
|
||
<Checkbox
|
||
className={"flex flex-row items-center"}
|
||
checked={packageTypeEnabled.EMPTY === 1}
|
||
onChange={(checked) => {
|
||
togglePackageType("EMPTY", checked ? 1 : 0);
|
||
if (!checked) {
|
||
setEmptyBoxList([]);
|
||
}
|
||
}}
|
||
>
|
||
<View className={"text-sm font-normal text-[#000000]"}>
|
||
带了
|
||
</View>
|
||
</Checkbox>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 空箱信息展示 */}
|
||
{packageTypeEnabled.EMPTY === 1 && (
|
||
<View>
|
||
{emptyBoxes.length > 0 ? (
|
||
emptyBoxes.map((item) => renderEmptyBoxItem(item))
|
||
) : (
|
||
<View className="mb-4 rounded-lg bg-gray-50 p-4 text-center text-gray-500">
|
||
还没有添加空箱
|
||
</View>
|
||
)}
|
||
|
||
<Button
|
||
icon={<Icon name={"plus"} size={20} />}
|
||
type={"primary"}
|
||
size={"large"}
|
||
fill={"outline"}
|
||
block
|
||
className="border-primary text-primary flex w-full items-center justify-center !border-2 !bg-white"
|
||
onClick={() => {
|
||
setShowBatchModal(true);
|
||
}}
|
||
>
|
||
<View>添加空箱</View>
|
||
</Button>
|
||
</View>
|
||
)}
|
||
</View>
|
||
</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>
|
||
)}
|
||
|
||
{/* 批量添加弹窗 */}
|
||
{renderBatchAddModal()}
|
||
{/* 编辑弹窗 */}
|
||
{renderEditModal()}
|
||
</View>
|
||
);
|
||
},
|
||
);
|