feat(purchase): 优化纸箱类型选择逻辑与界面交互

- 修改纸箱类型状态管理,使用数字状态替代布尔值
- 更新纸箱类型标签文案,提升业务准确性
- 重构供应商纸箱选择逻辑,支持更复杂的业务场景
- 添加必答题检查机制,确保用户完成所有必要选择
- 优化界面显示逻辑,根据选择动态渲染相关内容
- 修复纸箱品牌重复选择的验证逻辑
- 调整工作台菜单文案,统一为"工作台"
- 修复金额格式化函数,简化空值处理
- 更新工作台常量配置,添加页面路径
This commit is contained in:
shenyifei 2025-11-08 13:30:24 +08:00
parent f8e837c742
commit 4dbba0fa6b
8 changed files with 1546 additions and 544 deletions

View File

@ -36,7 +36,7 @@ config = {
list: [
{
pagePath: "pages/main/index/index",
text: "首页",
text: "工作台",
},
{
pagePath: "pages/main/menu/index",

View File

@ -34,7 +34,7 @@ export default function CustomTabBar(props: ICustomTabBarProps) {
iconPath: (
<Icon name={"house"} color={"#6B7280"} size={20 * scaleFactor} />
),
text: "首页",
text: "工作台",
},
{
pagePath: "/pages/main/menu/index",

View File

@ -37,41 +37,7 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
// 初始化数据
useEffect(() => {
setSupplierVO(value);
const orderPackageList = value.orderPackageList || [];
setOrderPackageList(value.orderPackageList || []);
// 根据orderPackageList和supplierVO属性初始化 packageTypeEnabled
const initialPackageTypeEnabled = {
USED: undefined,
EXTRA_USED: undefined,
EXTRA: undefined,
REMAIN: undefined,
OWN: undefined,
};
// 根据orderPackageList设置已有的纸箱类型
if (orderPackageList.some((item) => item.boxType === "USED")) {
// @ts-ignore
initialPackageTypeEnabled.USED = true;
}
if (orderPackageList.some((item) => item.boxType === "EXTRA_USED")) {
// @ts-ignore
initialPackageTypeEnabled.EXTRA_USED = true;
}
if (orderPackageList.some((item) => item.boxType === "EXTRA")) {
// @ts-ignore
initialPackageTypeEnabled.EXTRA = true;
}
if (orderPackageList.some((item) => item.boxType === "REMAIN")) {
// @ts-ignore
initialPackageTypeEnabled.REMAIN = true;
}
if (orderPackageList.some((item) => item.boxType === "OWN")) {
// @ts-ignore
initialPackageTypeEnabled.OWN = true;
}
setPackageTypeEnabled(initialPackageTypeEnabled);
}, []);
const [orderPackageList, setOrderPackageList] = useState<
@ -90,20 +56,64 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
// 确定当前供应商需要检查哪些纸箱类型
if (supplierVO.isPaper && supplierVO.isLast) {
requiredTypes = ["OWN", "USED", "EXTRA_USED", "REMAIN"];
// 空磅包含纸箱 + 最后一个瓜农
if (packageTypeEnabled.OWN === 1) {
requiredTypes = ["OWN", "USED"];
if (packageTypeEnabled.REMAIN === 1) {
requiredTypes.push("REMAIN");
}
} else if (packageTypeEnabled.OWN === 2) {
requiredTypes = ["USED", "OWN", "EXTRA_USED"];
if (packageTypeEnabled.REMAIN === 1) {
requiredTypes.push("REMAIN");
}
}
} else if (supplierVO.isPaper && !supplierVO.isLast) {
requiredTypes = ["OWN", "USED", "EXTRA"];
// 空磅包含纸箱 + 非最后一个瓜农
if (packageTypeEnabled.OWN === 1) {
requiredTypes = ["OWN", "USED"];
} else if (packageTypeEnabled.OWN === 2) {
requiredTypes = ["USED", "OWN", "EXTRA"];
}
} else if (!supplierVO.isPaper) {
requiredTypes = ["OWN", "USED"];
// 空磅不包含纸箱
if (packageTypeEnabled.OWN === 1) {
requiredTypes = ["OWN", "USED"];
} else if (packageTypeEnabled.OWN === 2) {
requiredTypes = ["USED", "OWN"];
}
}
// 检查所需选项是否都已做出选择不是true就是false不能是undefined
// 检查所需选项是否都已做出选择不是1就是2不能是0
console.log("requiredTypes", requiredTypes, packageTypeEnabled)
const allRequiredAnswered = requiredTypes.every(
(type) =>
packageTypeEnabled[type] === true ||
packageTypeEnabled[type] === false,
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) {
Toast.show("toast", {
icon: "fail",
@ -116,14 +126,14 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
// 检查所有启用的纸箱类型是否都填写了信息
const enabledTypes = Object.entries(packageTypeEnabled)
.filter(
([type, enabled]) => requiredTypes.includes(type) && enabled === true,
([type, enabled]) => requiredTypes.includes(type) && enabled === 1,
)
.map(([type, _]) => type);
console.log("enabledTypes", enabledTypes);
// 如果没有任何纸箱类型被启用,提示用户至少选择一种
if (enabledTypes.length === 0) {
if (requiredTypes.length > 0 && enabledTypes.length === 0) {
Toast.show("toast", {
icon: "fail",
title: "提示",
@ -140,11 +150,11 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
if (!hasPackagesOfType) {
const typeLabels = {
USED: "本次拉来的纸箱",
EXTRA_USED: "额外拿来的纸箱",
EXTRA: "额外拿来的纸箱",
REMAIN: "车上剩下的纸箱",
OWN: "瓜农自己的纸箱",
USED: "记录装车用的纸箱",
EXTRA_USED: "记录额外运输来的所有纸箱",
EXTRA: "记录额外运输来的所有纸箱",
REMAIN: "记录车上没用完的纸箱",
OWN: "记录装车用的瓜农的纸箱",
};
Toast.show("toast", {
@ -253,12 +263,13 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
useState<BusinessAPI.OrderPackage["boxType"]>("USED");
// 新增状态:跟踪每种纸箱类型的启用状态
// 0: 未选, 1: 选择是, 2: 选择否
const [packageTypeEnabled, setPackageTypeEnabled] = useState({
USED: undefined, // 默认不启用任何纸箱类型
EXTRA_USED: undefined,
EXTRA: undefined,
REMAIN: undefined,
OWN: undefined, // 添加OWN类型
USED: 0,
EXTRA_USED: 0,
EXTRA: 0,
REMAIN: 0,
OWN: 0,
});
// 监听供应商信息变化
@ -291,7 +302,7 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
const handleBatchBrandSelect = (brand: BoxBrand) => {
// 检查当前boxType下是否已存在该品牌
const isBrandAlreadySelected = orderPackageList.some(
(pkg) => pkg.boxType === boxType && pkg.boxBrandId === brand.boxBrandId
(pkg) => pkg.boxType === boxType && pkg.boxBrandId === brand.boxBrandId,
);
if (isBrandAlreadySelected) {
@ -396,11 +407,11 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
// 处理纸箱类型启用状态切换
const togglePackageType = (
type: BusinessAPI.OrderPackage["boxType"],
enabled: boolean,
value: number, // 0: 未选, 1: 选择是, 2: 选择否
) => {
setPackageTypeEnabled((prev) => ({
...prev,
[type]: enabled,
[type]: value,
}));
};
@ -554,7 +565,10 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
(pkg) =>
pkg.boxType === editingItem.boxType &&
pkg.boxBrandId === editingItem.boxBrandId &&
!(pkg.boxBrandId === editingItem.boxBrandId && pkg.boxType === editingItem.boxType)
!(
pkg.boxBrandId === editingItem.boxBrandId &&
pkg.boxType === editingItem.boxType
),
);
if (isBrandAlreadySelected) {
@ -690,23 +704,18 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
// 根据启用的纸箱类型渲染对应的内容
const renderPackageByType = (type: keyof typeof packageTypeEnabled) => {
// 如果该类型未启用,不渲染任何内容
if (!packageTypeEnabled[type]) {
return null;
}
// 获取该类型下所有的纸箱
const packagesOfType = convertOrderPackagesToBoxBrands(
orderPackageList.filter((pkg) => pkg.boxType === type),
);
// 定义类型显示名称
// 根据类型设置显示标题
const typeLabels = {
USED: "本次拉来的纸箱",
EXTRA_USED: "额外拿来的纸箱",
EXTRA: "额外拿来的纸箱",
REMAIN: "车上剩下的纸箱",
OWN: "瓜农自己的纸箱", // 添加OWN类型标签
USED: "记录装车用的纸箱",
EXTRA_USED: "记录用的额外运输纸箱纸箱",
EXTRA: "记录额外运输来的所有纸箱",
REMAIN: "记录车上没用完的纸箱",
OWN: "记录装车用的瓜农的纸箱",
};
return (
@ -739,7 +748,7 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
setShowBatchModal(true);
}}
>
<View>{typeLabels[type]}</View>
<View></View>
</Button>
</View>
);
@ -816,15 +825,6 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
</View>
)}
{/*/!* 未设置数量时的提示 *!/*/}
{/*{selectedBrand && !hasAnyProductWithCount && (*/}
{/* <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">
@ -1110,278 +1110,262 @@ export default forwardRef<OrderPackageRef, IOrderPackageProps>(
{/* 是否使用瓜农自己的纸箱 */}
<View className="mb-2.5 flex items-center justify-between">
<View className="text-sm"></View>
<View className="text-sm"></View>
<View className="flex flex-shrink-0 gap-2">
<Button
size="small"
type={packageTypeEnabled.OWN === true ? "primary" : "default"}
onClick={() => togglePackageType("OWN", true)}
type={packageTypeEnabled.OWN === 1 ? "primary" : "default"}
onClick={() => {
togglePackageType("USED", 2);
togglePackageType("OWN", 1);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.OWN === 2) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "USED" && item.boxType !== "EXTRA_USED" && item.boxType !== "EXTRA"),
);
togglePackageType("EXTRA_USED", 0)
togglePackageType("EXTRA", 0)
}
}}
>
</Button>
<Button
size="small"
type={packageTypeEnabled.OWN === false ? "primary" : "default"}
type={packageTypeEnabled.OWN === 2 ? "primary" : "default"}
onClick={() => {
togglePackageType("OWN", false);
togglePackageType("USED", 1);
togglePackageType("OWN", 2);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.OWN) {
if (packageTypeEnabled.OWN === 1) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "OWN"),
);
}
}}
>
</Button>
</View>
</View>
{/* 所有选项都可以自由选择,不再受瓜农自己的纸箱选项影响 */}
<>
{supplierVO.isPaper && supplierVO.isLast && (
<>
<View className="mb-2.5 flex items-center justify-between">
<View className="text-sm"></View>
<View className="flex flex-shrink-0 gap-2">
<Button
size="small"
type={
packageTypeEnabled.USED === true ? "primary" : "default"
}
onClick={() => togglePackageType("USED", true)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.USED === false
? "primary"
: "default"
}
onClick={() => {
togglePackageType("USED", false);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.USED) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "USED"),
);
}
}}
>
</Button>
</View>
</View>
{/* 根据供应商属性显示不同的问题 */}
{supplierVO.isPaper && supplierVO.isLast && (
/* 当前为最后一个瓜农 */
<>
{packageTypeEnabled.OWN === 1 && (
/* 当选择了使用自己的纸箱时 */
<>
{renderPackageByType("OWN")}
<View className="mb-2.5 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 === true
? "primary"
: "default"
}
onClick={() => togglePackageType("EXTRA_USED", true)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.EXTRA_USED === false
? "primary"
: "default"
}
onClick={() => {
togglePackageType("EXTRA_USED", false);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.EXTRA_USED) {
setOrderPackageList((list) =>
list.filter(
(item) => item.boxType !== "EXTRA_USED",
),
);
{/* 空车带来的纸箱用完了吗? */}
<View className="mb-2.5 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"
}
}}
>
</Button>
onClick={() => {
togglePackageType("REMAIN", 2);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.REMAIN === 1) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "REMAIN"),
);
}
}}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.REMAIN === 1
? "primary"
: "default"
}
onClick={() => togglePackageType("REMAIN", 1)}
>
</Button>
</View>
</View>
</View>
<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 === true
? "primary"
: "default"
}
onClick={() => togglePackageType("REMAIN", true)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.REMAIN === false
? "primary"
: "default"
}
onClick={() => {
togglePackageType("REMAIN", false);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.REMAIN) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "REMAIN"),
);
}
}}
>
</Button>
</View>
</View>
</>
)}
{packageTypeEnabled.REMAIN === 1 &&
renderPackageByType("REMAIN")}
</>
)}
{supplierVO.isPaper && !supplierVO.isLast && (
<>
<View className="mb-2.5 flex items-center justify-between">
<View className="text-sm"></View>
<View className="flex flex-shrink-0 gap-2">
<Button
size="small"
type={
packageTypeEnabled.USED === true ? "primary" : "default"
}
onClick={() => togglePackageType("USED", true)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.USED === false
? "primary"
: "default"
}
onClick={() => {
togglePackageType("USED", false);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.USED) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "USED"),
);
}
}}
>
</Button>
</View>
</View>
{packageTypeEnabled.OWN === 2 && (
/* 当没有选择使用自己的纸箱时 */
<>
{renderPackageByType("USED")}
<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 === true
? "primary"
: "default"
}
onClick={() => togglePackageType("EXTRA", true)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.EXTRA === false
? "primary"
: "default"
}
onClick={() => {
togglePackageType("EXTRA", false);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.EXTRA) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "EXTRA"),
);
{/* 空车带来的纸箱用完了吗? */}
<View className="mb-2.5 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"
}
}}
>
</Button>
onClick={() => {
togglePackageType("REMAIN", 2);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.REMAIN === 1) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "REMAIN"),
);
}
}}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.REMAIN === 1
? "primary"
: "default"
}
onClick={() => togglePackageType("REMAIN", 1)}
>
</Button>
</View>
</View>
</View>
</>
)}
{!supplierVO.isPaper && (
<>
<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.USED === true ? "primary" : "default"
}
onClick={() => togglePackageType("USED", true)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.USED === false
? "primary"
: "default"
}
onClick={() => {
togglePackageType("USED", false);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.USED) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "USED"),
);
{packageTypeEnabled.REMAIN === 1 &&
renderPackageByType("REMAIN")}
{/* 用额外运输纸箱的了吗? */}
<View className="mb-2.5 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"
}
}}
>
</Button>
onClick={() => togglePackageType("EXTRA_USED", 1)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.EXTRA_USED === 2
? "primary"
: "default"
}
onClick={() => {
togglePackageType("EXTRA_USED", 2);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.EXTRA_USED === 1) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "EXTRA_USED"),
);
}
}}
>
</Button>
</View>
</View>
</View>
</>
)}
</>
{packageTypeEnabled.EXTRA_USED === 1 &&
renderPackageByType("EXTRA_USED")}
</>
)}
</>
)}
{supplierVO.isPaper && !supplierVO.isLast && (
/* 非最后一个瓜农 */
<>
{packageTypeEnabled.OWN === 1 && (
/* 当选择了使用自己的纸箱时 */
<>
{renderPackageByType("OWN")}
</>
)}
{packageTypeEnabled.OWN === 2 && (
/* 当没有选择使用自己的纸箱时 */
<>
{renderPackageByType("USED")}
{/* 有额外运输纸箱过来吗? */}
<View className="mb-2.5 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={() => togglePackageType("EXTRA", 1)}
>
</Button>
<Button
size="small"
type={
packageTypeEnabled.EXTRA === 2
? "primary"
: "default"
}
onClick={() => {
togglePackageType("EXTRA", 2);
// 如果关闭,也需要清除相关数据
if (packageTypeEnabled.EXTRA === 1) {
setOrderPackageList((list) =>
list.filter((item) => item.boxType !== "EXTRA"),
);
}
}}
>
</Button>
</View>
</View>
{packageTypeEnabled.EXTRA === 1 &&
renderPackageByType("EXTRA")}
</>
)}
</>
)}
{!supplierVO.isPaper && (
/* 空磅不包含纸箱 */
<>
{packageTypeEnabled.OWN === 1 && (
/* 当选择了使用自己的纸箱时 */
<>
{renderPackageByType("OWN")}
</>
)}
{packageTypeEnabled.OWN === 2 && (
/* 当没有选择使用自己的纸箱时 */
<>{renderPackageByType("EXTRA")}</>
)}
</>
)}
</View>
{/* 根据启用的类型和supplierVO属性渲染对应的内容 */}
{renderPackageByType("OWN")}
{supplierVO.isPaper && supplierVO.isLast && (
<>
{renderPackageByType("USED")}
{renderPackageByType("EXTRA_USED")}
{renderPackageByType("REMAIN")}
</>
)}
{supplierVO.isPaper && !supplierVO.isLast && (
<>
{renderPackageByType("USED")}
{renderPackageByType("EXTRA")}
</>
)}
{!supplierVO.isPaper && renderPackageByType("USED")}
{/* 当选择了使用自己的纸箱时才渲染 */}
{/* 批量添加弹窗 */}
{renderBatchAddModal()}
{/* 编辑弹窗 */}

View File

@ -488,7 +488,7 @@ export default forwardRef<OrderVehicleRef, IOrderVehicleProps>(
const vehicleExtraction = async (message: string) => {
// 简单校验message避免无效的数据抽取
if (!message || message.trim() === "") {
Taro.showToast({
Toast.show("toast", {
title: "请输入有效内容",
icon: "none",
});

View File

@ -101,6 +101,7 @@ const quickActionMap = {
icon: "folder",
iconColor: "var(--color-blue-600)",
bgColorClass: "bg-blue-100",
path: "/pages/purchase/order/list",
},
{
id: "history",
@ -108,6 +109,7 @@ const quickActionMap = {
icon: "clipboard-list",
iconColor: "var(--color-green-600)",
bgColorClass: "bg-green-100",
path: "/pages/purchase/order/list",
},
{
id: "invoiceUpload",
@ -124,6 +126,7 @@ const quickActionMap = {
icon: "folder",
iconColor: "var(--color-blue-600)",
bgColorClass: "bg-blue-100",
path: "/pages/purchase/order/list",
},
{
id: "history",
@ -131,6 +134,7 @@ const quickActionMap = {
icon: "clipboard-list",
iconColor: "var(--color-green-600)",
bgColorClass: "bg-green-100",
path: "/pages/purchase/order/list",
},
{
id: "invoiceUpload",

File diff suppressed because it is too large Load Diff

View File

@ -2299,7 +2299,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 = {

View File

@ -54,10 +54,7 @@ export function convertSeconds(seconds, outputUnit) {
// 格式化金额显示
export const formatCurrency = (value: number) => {
if (value === null) {
return "0.00";
}
return Number(value).toFixed(2)?.toLocaleString();
return Number(value || 0)?.toLocaleString();
};
export const validatePrice = (value: string) => {