- 集成消息服务API,实现消息列表分页加载功能 - 添加消息未读数量实时更新,每30秒自动刷新一次 - 实现消息标记已读、删除消息等操作功能 - 优化消息界面UI,支持无限滚动加载更多消息 - 添加消息内容预览和跳转到相关业务单据功能 - 在个人中心页面增加调试模式开关快捷入口 - 修复订单车辆组件中草帘价格验证逻辑问题 - 更新供应商称重模块,新增计价方式和定金支付验证 - 调整包装创建页面品牌选择样式布局 - 更新应用版本号至v0.0.76 - 集成经销商对账记录等相关业务服务模块
427 lines
14 KiB
TypeScript
427 lines
14 KiB
TypeScript
import { ScrollView, View } from "@tarojs/components";
|
||
import {
|
||
Button,
|
||
Image,
|
||
Input,
|
||
Popup,
|
||
SafeArea,
|
||
Toast,
|
||
} from "@nutui/nutui-react-taro";
|
||
import { Icon } from "@/components";
|
||
import classNames from "classnames";
|
||
import { convertBoxBrandToOrderPackages } from "@/utils";
|
||
import { useEffect, useState } from "react";
|
||
import { BoxBrand } from "@/types/typings";
|
||
|
||
interface IPackageCreateProps {
|
||
visible: boolean;
|
||
// 添加编辑模式的支持
|
||
editMode?: boolean;
|
||
onClose: () => void;
|
||
// 选中的纸箱品牌,编辑的时候使用
|
||
boxBrand?: BoxBrand;
|
||
// 全部纸箱品牌列表
|
||
boxBrandList: BoxBrand[];
|
||
orderPackageList: BusinessAPI.OrderPackage[];
|
||
onSave: (orderPackageList: BusinessAPI.OrderPackage[]) => void;
|
||
boxType: BusinessAPI.OrderPackage["boxType"];
|
||
}
|
||
|
||
export default function PackageCreate(props: IPackageCreateProps) {
|
||
const {
|
||
visible,
|
||
editMode = false,
|
||
boxBrand,
|
||
boxBrandList,
|
||
orderPackageList,
|
||
onClose,
|
||
onSave,
|
||
boxType,
|
||
} = props;
|
||
|
||
// 批量添加纸箱相关状态
|
||
const [selectedBrand, setSelectedBrand] = useState<BoxBrand | null>(null);
|
||
const [productCounts, setProductCounts] = useState<Map<string, number>>(
|
||
new Map(),
|
||
); // 产品数量映射
|
||
|
||
// 获取费用列表
|
||
useEffect(() => {
|
||
if (visible) {
|
||
// 如果是编辑模式并且有初始数据,在获取费用列表后设置初始状态
|
||
if (editMode && boxBrand) {
|
||
console.log("boxBrand", boxBrand);
|
||
// 查找对应的费用类型
|
||
const brand = boxBrandList?.find(
|
||
(c) => c.boxBrandId === boxBrand.boxBrandId,
|
||
);
|
||
if (brand) {
|
||
setSelectedBrand(brand);
|
||
// 初始化费用项目数量
|
||
const initialCounts = new Map<string, number>();
|
||
brand.boxSpecList?.forEach((boxSpec) => {
|
||
boxSpec.boxProductList.forEach((product) => {
|
||
const count = boxBrand.boxSpecList
|
||
.find((pkg) => pkg.boxSpecId === product.boxSpecId)
|
||
?.boxProductList.find(
|
||
(pkg) => pkg.boxProductId === product.boxProductId,
|
||
)?.boxCount;
|
||
|
||
initialCounts.set(product.boxProductId, count || 0);
|
||
});
|
||
});
|
||
|
||
setProductCounts(initialCounts);
|
||
}
|
||
}
|
||
}
|
||
}, [visible, editMode, boxBrandList]);
|
||
|
||
// 批量添加包装信息
|
||
const addBatchPackageInfo = () => {
|
||
if (!selectedBrand) {
|
||
return;
|
||
}
|
||
|
||
// 使用convertBoxBrandToOrderPackages转换数据
|
||
const newOrderPackages = convertBoxBrandToOrderPackages(
|
||
selectedBrand,
|
||
boxType,
|
||
);
|
||
|
||
// 过滤掉数量为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.boxProductId) || 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.boxProductId) || 0 : 0;
|
||
|
||
const orderPackage = orderPackageList.find((pkg) => {
|
||
return (
|
||
pkg.boxType === boxType && pkg.boxProductId === product?.boxProductId
|
||
);
|
||
});
|
||
|
||
return {
|
||
...(orderPackage || pkg)!,
|
||
boxCount: count,
|
||
};
|
||
});
|
||
|
||
onSave([
|
||
...(orderPackageList.filter(
|
||
(pkg) =>
|
||
pkg.boxType !== boxType ||
|
||
(pkg.boxType === boxType &&
|
||
pkg.boxBrandId !== selectedBrand?.boxBrandId),
|
||
) || []),
|
||
...updatedOrderPackages,
|
||
]);
|
||
|
||
// 重置选择并关闭弹窗
|
||
setSelectedBrand(null);
|
||
setProductCounts(new Map());
|
||
onClose();
|
||
};
|
||
|
||
// 处理批量添加时的品牌选择
|
||
const handleBatchBrandSelect = (brand: BoxBrand) => {
|
||
// 检查当前boxType下是否已存在该品牌
|
||
const isBrandAlreadySelected = orderPackageList.some(
|
||
(pkg) => pkg.boxType === boxType && 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 renderBrandSelection = () => {
|
||
// 编辑模式下不允许更改费用类型
|
||
if (editMode) {
|
||
return (
|
||
<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">
|
||
{selectedBrand?.boxBrandImage && (
|
||
<View className="border-primary mr-3 h-16 w-16 overflow-hidden rounded-xl border-4 object-cover">
|
||
<Image
|
||
src={selectedBrand.boxBrandImage}
|
||
className="h-full w-full"
|
||
mode="aspectFill"
|
||
/>
|
||
</View>
|
||
)}
|
||
<View className="text-base font-medium text-gray-800">
|
||
{selectedBrand?.boxBrandName}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<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) => {
|
||
return (
|
||
item.boxBrandType === "THIRD_PARTY_BOX" ||
|
||
item.boxBrandType === "FARMER_BOX" ||
|
||
item.boxBrandType === "OUR_BOX"
|
||
);
|
||
})
|
||
?.map((boxBrand) => (
|
||
<View
|
||
key={boxBrand.id}
|
||
className={"flex flex-col items-center justify-center gap-1"}
|
||
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="aspectFit"
|
||
alt={boxBrand.boxBrandImage}
|
||
/>
|
||
</View>
|
||
<View className="text-center text-xs text-nowrap">
|
||
{boxBrand.boxBrandName}
|
||
</View>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</ScrollView>
|
||
</View>
|
||
);
|
||
};
|
||
|
||
return (
|
||
<Popup
|
||
duration={150}
|
||
style={{
|
||
minHeight: "auto",
|
||
}}
|
||
visible={visible}
|
||
position="bottom"
|
||
title={editMode ? "批量编辑纸箱" : "批量添加纸箱"}
|
||
onClose={() => {
|
||
onClose();
|
||
setSelectedBrand(null);
|
||
setProductCounts(new Map());
|
||
}}
|
||
onOverlayClick={onClose}
|
||
lockScroll
|
||
>
|
||
<View className="p-2.5">
|
||
<ScrollView
|
||
scrollY
|
||
style={{
|
||
height: "65vh",
|
||
width: "100%",
|
||
}}
|
||
>
|
||
{renderBrandSelection()}
|
||
|
||
{/* 未选择品牌时的提示 */}
|
||
{!selectedBrand && !editMode && (
|
||
<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.boxProductId) || 0;
|
||
// 计算总重量
|
||
const totalWeight = boxProduct.boxProductWeight
|
||
? (boxProduct.boxProductWeight * currentCount).toFixed(
|
||
1,
|
||
)
|
||
: 0;
|
||
return (
|
||
<View
|
||
key={boxProduct.boxProductId}
|
||
className="flex items-center justify-between rounded-lg bg-gray-50 p-3"
|
||
>
|
||
<View className="flex flex-col">
|
||
<View className="text-gray-800">
|
||
型号 {boxProduct.boxProductName}
|
||
</View>
|
||
<View className={"flex flex-row gap-2.5"}>
|
||
{boxProduct.boxProductWeight > 0 && (
|
||
<View className="text-xs text-gray-500">
|
||
单重 {boxProduct.boxProductWeight} 斤
|
||
</View>
|
||
)}
|
||
{currentCount > 0 &&
|
||
boxProduct.boxProductWeight > 0 && (
|
||
<View className="text-primary text-xs font-medium">
|
||
总重 {totalWeight} 斤
|
||
</View>
|
||
)}
|
||
</View>
|
||
</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.boxProductId,
|
||
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.boxProductId,
|
||
num,
|
||
);
|
||
}
|
||
}}
|
||
/>
|
||
</View>
|
||
<View
|
||
className="flex h-8 w-8 items-center justify-center rounded-r bg-gray-200"
|
||
onClick={() => {
|
||
handleProductCountChange(
|
||
boxProduct.boxProductId,
|
||
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={() => {
|
||
onClose();
|
||
|
||
setSelectedBrand(null);
|
||
setProductCounts(new Map());
|
||
}}
|
||
>
|
||
取消
|
||
</Button>
|
||
</View>
|
||
<View className="flex-1">
|
||
<Button
|
||
size={"large"}
|
||
block
|
||
type={"primary"}
|
||
disabled={
|
||
!selectedBrand ||
|
||
Array.from(productCounts.values()).every((count) => count === 0)
|
||
}
|
||
onClick={addBatchPackageInfo}
|
||
>
|
||
{editMode ? "保存" : "添加"}
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
<SafeArea position={"bottom"} />
|
||
</View>
|
||
</Popup>
|
||
);
|
||
}
|