From 1ac1564ec2739451970301d0d0a715b457213e95 Mon Sep 17 00:00:00 2001 From: shenyifei Date: Tue, 4 Nov 2025 22:36:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(purchase):=20=E6=B7=BB=E5=8A=A0=E6=8B=BC?= =?UTF-8?q?=E8=BD=A6=E9=80=89=E6=8B=A9=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96UI=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在MelonFarmer组件中新增supplierCount属性用于判断是否显示拼车选项 - 修改"是否为最后一个瓜农"为"是否要拼车"的逻辑与文案 - 更新多个图标引用,包括新增address-book图标 - 调整输入框样式,增加图标前缀提升用户体验 - 优化称重信息页面的提示文字,使其更清晰易懂 - 增加OrderPackage相关类型定义及转换工具函数 - 更新页面审核和创建流程中的样式与交互逻辑 - 升级iconfont字体文件版本,支持新图标 - 修复部分组件样式问题,如SupplierList底部间距等 --- .../app-client/src/components/icon/Icon.tsx | 1 + .../src/components/purchase/MelonFarmer.tsx | 153 +- .../src/components/purchase/OrderPackage.tsx | 1874 +++++++++++------ .../src/components/purchase/SupplierList.tsx | 2 +- .../src/components/purchase/Weigh.tsx | 94 +- .../components/supplier/SupplierPicker.tsx | 2 +- packages/app-client/src/iconfont.css | 10 +- .../src/pages/purchase/order/audit.tsx | 26 +- .../src/pages/purchase/order/create.tsx | 36 +- .../src/services/business/typings.d.ts | 3 +- packages/app-client/src/types/typings.ts | 6 +- packages/app-client/src/utils/orderPackage.ts | 112 + 12 files changed, 1587 insertions(+), 732 deletions(-) create mode 100644 packages/app-client/src/utils/orderPackage.ts diff --git a/packages/app-client/src/components/icon/Icon.tsx b/packages/app-client/src/components/icon/Icon.tsx index 42488fc..9bb01c2 100644 --- a/packages/app-client/src/components/icon/Icon.tsx +++ b/packages/app-client/src/components/icon/Icon.tsx @@ -3,6 +3,7 @@ import classNames from "classnames"; import React from "react"; export type IconNames = + | "address-book" | "pen-to-square" | "location-dot" | "clock" diff --git a/packages/app-client/src/components/purchase/MelonFarmer.tsx b/packages/app-client/src/components/purchase/MelonFarmer.tsx index 1019550..6622ada 100644 --- a/packages/app-client/src/components/purchase/MelonFarmer.tsx +++ b/packages/app-client/src/components/purchase/MelonFarmer.tsx @@ -25,11 +25,12 @@ interface IMelonFarmerProps { onRemove: (supplierVO: SupplierVO) => void; onAdd: () => void; isLast: boolean; // 添加一个属性来标识是否是最后一个瓜农 + supplierCount: number; } export default forwardRef( function MelonFarmer(props, ref) { - const { value, onChange, onRemove, onAdd, isLast } = props; + const { value, onChange, onRemove, onAdd, isLast, supplierCount } = props; const [supplierVO, setSupplierVO] = useState(); console.log("supplierVO", supplierVO); @@ -94,7 +95,7 @@ export default forwardRef( ); const [isLastFarmerError, setIsLastFarmerError] = useState<{ [key: string]: boolean; - }>({}); // 添加是否为最后一个瓜农的错误状态 + }>({}); // 添加是否要拼车的错误状态 // 校验姓名函数 const validateName = (name: string) => { @@ -136,9 +137,10 @@ export default forwardRef( return phoneRegex.test(phone); }; - // 校验是否为最后一个瓜农函数 + // 校验是否要拼车函数 + // 校验是否要拼车函数 const validateIsLastFarmer = (isLast?: boolean) => { - // 必须选择是或否 + // 必须选择要不要 return isLast !== undefined; }; @@ -151,7 +153,7 @@ export default forwardRef( const isIdCardValid = validateIdCard(supplierVO.idCard || ""); const isBankCardValid = validateBankCard(supplierVO.bankCard || ""); const isPhoneValid = validatePhone(supplierVO.phone || ""); - const isLastFarmerValid = validateIsLastFarmer(supplierVO?.isLast); // 校验是否为最后一个瓜农 + const isLastFarmerValid = validateIsLastFarmer(supplierVO?.isLast); // 校验是否需要拼车 // 更新错误状态 setNameError((prev) => ({ @@ -384,7 +386,13 @@ export default forwardRef( } return ( - + {/* 功能提醒 */} ( + {/* 只有最后一个瓜农才显示是否为最后一个瓜农的选项和添加按钮 */} + {isLast && ( + + + {supplierCount > 1 ? ( + 这车货还要继续拼车吗? + ) : ( + 这车货要拼车吗? + )} + + + { + // 清除错误状态 + setIsLastFarmerError((prev) => ({ + ...prev, + [supplierVO.orderSupplierId]: false, + })); + + // 根据用户选择设置是否为最后一个瓜农 + const isLastValue = + value === "true" + ? true + : value === "false" + ? false + : undefined; + setSupplierVO({ + ...supplierVO, + isLast: isLastValue, + }); + + setIsLastFarmer(isLastValue!); + }} + > + + 不要 + + + + {isLastFarmerError[supplierVO.orderSupplierId] && ( + + 请选择本车货要不要拼车 + + )} + + )} + {/* 快捷工具 */} @@ -477,15 +540,22 @@ export default forwardRef( - + 姓名 - 点我选瓜农 - + + + + 点我选瓜农 + + } onFinish={(supplierVO1) => { setSupplierVO({ @@ -516,6 +586,7 @@ export default forwardRef( + ( supplierVO.orderSupplierId, ) } + className="flex-1" /> {nameError[supplierVO.orderSupplierId] && ( @@ -540,6 +612,7 @@ export default forwardRef( + ( supplierVO.orderSupplierId, ) } + className="flex-1" /> {idCardError[supplierVO.orderSupplierId] && ( @@ -566,6 +640,12 @@ export default forwardRef( + ( supplierVO.orderSupplierId, ) } + className="flex-1" /> {bankCardError[supplierVO.orderSupplierId] && ( @@ -592,6 +673,7 @@ export default forwardRef( + ( supplierVO.orderSupplierId, ) } + className="flex-1" /> {phoneError[supplierVO.orderSupplierId] && ( @@ -639,56 +722,6 @@ export default forwardRef( - {/* 只有最后一个瓜农才显示是否为最后一个瓜农的选项和添加按钮 */} - {isLast && ( - - - 是否为最后一个瓜农 - - { - // 清除错误状态 - setIsLastFarmerError((prev) => ({ - ...prev, - [supplierVO.orderSupplierId]: false, - })); - - // 根据用户选择设置是否为最后一个瓜农 - const isLastValue = - value === "true" - ? true - : value === "false" - ? false - : undefined; - setSupplierVO({ - ...supplierVO, - isLast: isLastValue, - }); - - setIsLastFarmer(isLastValue!); - }} - > - - - - - - {isLastFarmerError[supplierVO.orderSupplierId] && ( - - 请选择是否为最后一个瓜农 - - )} - - )} - {/* 只有当用户选择"否"时才显示添加按钮 */} {isLast && !isLastFarmer && isLastFarmer !== null && ( + + ); + }; + + // 渲染批量添加纸箱弹窗 + const renderBatchAddModal = () => { + // 检查是否至少有一个产品的数量大于0 + const hasAnyProductWithCount = selectedBrand + ? Array.from(productCounts.values()).some((count) => count > 0) + : false; + + return ( + { + setShowBatchModal(false); + setSelectedBrand(null); + setProductCounts(new Map()); + }} + title={"批量添加纸箱"} + round + > + + + {/* 品牌选择 */} + + 选择品牌 + + + {boxBrandList?.map((boxBrand) => ( + handleBatchBrandSelect(boxBrand)} + > + + {boxBrand.boxBrandImage} + + + {boxBrand.boxBrandName} + + + ))} + + - - { - handleBoxCountChange(index, value); + + {/* 未选择品牌时的提示 */} + {!selectedBrand && ( + + 请先选择一个品牌 + + )} + + {/*/!* 未设置数量时的提示 *!/*/} + {/*{selectedBrand && !hasAnyProductWithCount && (*/} + {/* */} + {/* */} + {/* 请为至少一个纸箱规格设置数量*/} + {/* */} + {/* */} + {/*)}*/} + + {/* 产品展示 */} + {selectedBrand && ( + + + 纸箱规格(点击 +/- 修改数量,0表示不使用) + + {selectedBrand.boxCategoryList?.map((category) => ( + + + {category.boxCategoryName} + + + {category.boxProductList.map((boxProduct) => { + const currentCount = + productCounts.get(boxProduct.id) || 0; + return ( + + + {boxProduct.boxProductName} + + + { + handleProductCountChange( + boxProduct.id, + Math.max(0, currentCount - 1), + ); + }} + > + + + + { + const num = Number(value); + if (!Number.isNaN(num) && num >= 0) { + handleProductCountChange( + boxProduct.id, + num, + ); + } + }} + /> + + { + handleProductCountChange( + boxProduct.id, + currentCount + 1, + ); + }} + > + + + + + + ); + })} + + + ))} + + )} + + + {/* 底部按钮 */} + + + - { - const count = item.boxCount || 1; - handleBoxCountChange(index, count + 1); - }} - > - + + + - )} + + ); + }; + + // 渲染编辑纸箱弹窗 + const renderEditModal = () => { + if (!editingItem) return null; + + // 获取品牌信息 + const brandInfo = boxBrandList?.find( + (brand) => brand.boxBrandId === editingItem.boxBrandId, + ); + + return ( + setShowEditModal(false)} + title={"编辑纸箱信息"} + round + > + + + {/* 品牌信息 */} + + 品牌信息 + + {brandInfo?.boxBrandImage && ( + + + + )} + + {editingItem.boxBrandName} + + + + + {/* 详细信息 */} + + 纸箱详情 + + {editingItem?.boxCategoryList && + editingItem.boxCategoryList.map( + (categoryData, categoryIndex) => ( + + + {categoryData.boxCategoryName} + + + {categoryData.boxProductList.map( + (detail, detailIndex) => { + const currentCount = detail?.boxCount || 0; + + return ( + + + {detail.boxProductName} + + + { + const newCount = Math.max( + 0, + currentCount - 1, + ); + updateEditingItemCount( + categoryIndex, + detailIndex, + newCount, + ); + }} + > + + + + { + const num = Number(value); + if ( + !Number.isNaN(num) && + num >= 0 + ) { + updateEditingItemCount( + categoryIndex, + detailIndex, + num, + ); + } + }} + /> + + { + updateEditingItemCount( + categoryIndex, + detailIndex, + currentCount + 1, + ); + }} + > + + + + 个 + + + + ); + }, + )} + + + ), + )} + + + + + {/* 底部按钮 */} + + + + + + + + + + + + ); + }; + + return ( + + {/* 替换原来的Tab导航为问答式选择 */} + + + {supplierVO.name}的纸箱使用情况 + + + {/* 是否使用瓜农自己的纸箱 */} + + 有没有用瓜农的纸箱? + + + + + + + {/* 所有选项都可以自由选择,不再受瓜农自己的纸箱选项影响 */} + <> + {supplierVO.isPaper && supplierVO.isLast && ( + <> + + 有没有用本次拉来的纸箱? + + + + + + + + 有没有用额外拿来的纸箱? + + + + + + + + 车上还剩纸箱吗? + + + + + + + )} + + {supplierVO.isPaper && !supplierVO.isLast && ( + <> + + 有没有用本次拉来的纸箱? + + + + + + + + 有没有用额外拿来的纸箱? + + + + + + + )} + + {!supplierVO.isPaper && ( + <> + + 有没有用额外拿来的纸箱? + + + + + + + )} + + + {/* 根据启用的类型渲染对应的内容 */} + {renderPackageByType("OWN")} + {renderPackageByType("USED")} + {renderPackageByType("EXTRA_USED")} + {renderPackageByType("EXTRA")} + {renderPackageByType("REMAIN")} + + {/* 当选择了使用自己的纸箱时才渲染 */} + {/* 批量添加弹窗 */} + {renderBatchAddModal()} + {/* 编辑弹窗 */} + {renderEditModal()} ); - }; - - return ( - - {supplierVO.isPaper && supplierVO.isLast && ( - - handleBoxTypeChange("USED")} - > - 本次使用纸箱 - {getCurrentTypeCount("USED") > 0 && ( - - {getCurrentTypeCount("USED")} - - )} - - handleBoxTypeChange("EXTRA_USED")} - > - 已用额外运输纸箱 - {getCurrentTypeCount("EXTRA_USED") > 0 && ( - - {getCurrentTypeCount("EXTRA_USED")} - - )} - - handleBoxTypeChange("REMAIN")} - > - 车上剩余纸箱 - {getCurrentTypeCount("REMAIN") > 0 && ( - - {getCurrentTypeCount("REMAIN")} - - )} - - - - )} - {supplierVO.isPaper && !supplierVO.isLast && ( - - handleBoxTypeChange("USED")} - > - 本次使用纸箱 - {getCurrentTypeCount("USED") > 0 && ( - - {getCurrentTypeCount("USED")} - - )} - - handleBoxTypeChange("EXTRA")} - > - 额外运输纸箱 - {getCurrentTypeCount("EXTRA") > 0 && ( - - {getCurrentTypeCount("EXTRA")} - - )} - - - - - )} - {!supplierVO.isPaper && ( - - handleBoxTypeChange("USED")} - > - 本次使用纸箱 - {getCurrentTypeCount("USED") > 0 && ( - - {getCurrentTypeCount("USED")} - - )} - - - - - )} - - {/* 根据当前选择的类型过滤显示列表 */} - {orderPackageList.map((item, index) => { - return renderOrderPackageItem(item, index); - })} - - - - ); -} + }, +); diff --git a/packages/app-client/src/components/purchase/SupplierList.tsx b/packages/app-client/src/components/purchase/SupplierList.tsx index 4ae23f8..ad53602 100644 --- a/packages/app-client/src/components/purchase/SupplierList.tsx +++ b/packages/app-client/src/components/purchase/SupplierList.tsx @@ -19,7 +19,7 @@ export default function SupplierList(props: ISupplierListProps) { console.log("value", value); return ( - + {value.map((supplierVO: SupplierVO) => ( diff --git a/packages/app-client/src/components/purchase/Weigh.tsx b/packages/app-client/src/components/purchase/Weigh.tsx index 5cc6893..bab2ccb 100644 --- a/packages/app-client/src/components/purchase/Weigh.tsx +++ b/packages/app-client/src/components/purchase/Weigh.tsx @@ -264,61 +264,57 @@ export default forwardRef(function Weigh(props, ref) { return ( + + + 空车来的时候带纸箱了吗? + + { + // 清除错误状态 + setIsPaperError((prev) => ({ + ...prev, + [supplierVO.orderSupplierId]: false, + })); + + // 根据用户选择设置是否包含空纸箱 + const isPaperValue = + value === "true" + ? true + : value === "false" + ? false + : undefined; + setSupplierVO({ + ...supplierVO, + isPaper: isPaperValue, + }); + }} + > + 带了 + 没带 + + + + {isPaperError[supplierVO.orderSupplierId] && ( + + 请选择车来的时候有没有带纸箱 + + )} + + {supplierVO.name}的称重信息 - - - 空磅包含空纸箱 - - { - // 清除错误状态 - setIsPaperError((prev) => ({ - ...prev, - [supplierVO.orderSupplierId]: false, - })); - - // 根据用户选择设置是否包含空纸箱 - const isPaperValue = - value === "true" - ? true - : value === "false" - ? false - : undefined; - setSupplierVO({ - ...supplierVO, - isPaper: isPaperValue, - }); - }} - > - - - - - - {isPaperError[supplierVO.orderSupplierId] && ( - - 请选择空磅是否包含空纸箱 - - )} - - diff --git a/packages/app-client/src/components/supplier/SupplierPicker.tsx b/packages/app-client/src/components/supplier/SupplierPicker.tsx index 1ae8b90..7930184 100644 --- a/packages/app-client/src/components/supplier/SupplierPicker.tsx +++ b/packages/app-client/src/components/supplier/SupplierPicker.tsx @@ -37,7 +37,7 @@ export default function SupplierPicker(props: ISupplierPickerProps) { }; return ( - + { setVisible(true); diff --git a/packages/app-client/src/iconfont.css b/packages/app-client/src/iconfont.css index 5246c31..1ade110 100644 --- a/packages/app-client/src/iconfont.css +++ b/packages/app-client/src/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 5042354 */ - src: url('//at.alicdn.com/t/c/font_5042354_lmz58v86a1h.woff2?t=1761549950025') format('woff2'), - url('//at.alicdn.com/t/c/font_5042354_lmz58v86a1h.woff?t=1761549950025') format('woff'), - url('//at.alicdn.com/t/c/font_5042354_lmz58v86a1h.ttf?t=1761549950025') format('truetype'); + src: url('//at.alicdn.com/t/c/font_5042354_wqti51yo9xk.woff2?t=1762227792781') format('woff2'), + url('//at.alicdn.com/t/c/font_5042354_wqti51yo9xk.woff?t=1762227792781') format('woff'), + url('//at.alicdn.com/t/c/font_5042354_wqti51yo9xk.ttf?t=1762227792781') format('truetype'); } .iconfont { @@ -13,6 +13,10 @@ -moz-osx-font-smoothing: grayscale; } +.icon-address-book:before { + content: "\e623"; +} + .icon-pen-to-square:before { content: "\e630"; } diff --git a/packages/app-client/src/pages/purchase/order/audit.tsx b/packages/app-client/src/pages/purchase/order/audit.tsx index f2da2fb..494a9d8 100644 --- a/packages/app-client/src/pages/purchase/order/audit.tsx +++ b/packages/app-client/src/pages/purchase/order/audit.tsx @@ -70,67 +70,67 @@ const sectionList = { const sectionConfig = { supplierInfo: { title: "销售方信息", - containerClass: "border-l-4 border-l-blue-500", + containerClass: "border-l-8 border-l-blue-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, dealerInfo: { title: "下游经销商信息", - containerClass: "border-l-4 border-l-green-500", + containerClass: "border-l-8 border-l-green-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, basicInfo: { title: "基础信息", - containerClass: "border-l-4 border-l-yellow-500", + containerClass: "border-l-8 border-l-yellow-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, farmerInfo: { title: "瓜农信息", - containerClass: "border-l-4 border-l-purple-500", + containerClass: "border-l-8 border-l-purple-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, purchaseCostInfo: { title: "采购成本", - containerClass: "border-l-4 border-l-red-500", + containerClass: "border-l-8 border-l-red-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, packageInfo: { title: "包装纸箱费", - containerClass: "border-l-4 border-l-indigo-500", + containerClass: "border-l-8 border-l-indigo-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, emptyBoxInfo: { title: "空箱费用", - containerClass: "border-l-4 border-l-pink-500", + containerClass: "border-l-8 border-l-pink-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, laborInfo: { title: "用工信息", - containerClass: "border-l-4 border-l-teal-500", + containerClass: "border-l-8 border-l-teal-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, packagingCost: { title: "包装费", - containerClass: "border-l-4 border-l-orange-500", + containerClass: "border-l-8 border-l-orange-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, costSummary: { title: "成本合计", - containerClass: "border-l-4 border-l-cyan-500", + containerClass: "border-l-8 border-l-cyan-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, marketPrice: { title: "市场报价", - containerClass: "border-l-4 border-l-lime-500", + containerClass: "border-l-8 border-l-lime-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, rebateCalc: { title: "返点计算", - containerClass: "border-l-4 border-l-amber-500", + containerClass: "border-l-8 border-l-amber-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, profitCalc: { title: "利润计算", - containerClass: "border-l-4 border-l-emerald-500", + containerClass: "border-l-8 border-l-emerald-500", contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto", }, }; diff --git a/packages/app-client/src/pages/purchase/order/create.tsx b/packages/app-client/src/pages/purchase/order/create.tsx index 7034719..4078516 100644 --- a/packages/app-client/src/pages/purchase/order/create.tsx +++ b/packages/app-client/src/pages/purchase/order/create.tsx @@ -22,6 +22,7 @@ import { business } from "@/services"; import { generateShortId } from "@/utils/generateShortId"; import Taro from "@tarojs/taro"; import buildUrl from "@/utils/buildUrl"; +import { OrderPackageRef } from "@/components/purchase/OrderPackage"; const defaultSupplierList: SupplierVO[] = [ { @@ -62,8 +63,10 @@ export default hocAuth(function Page(props: CommonComponent) { const melonFarmerRefs = useRef([]); // 创建Weigh组件的ref数组 const weighRefs = useRef([]); - // 创建Artificial组件的ref - const artificialRef = useRef(null); + // 创建OrderCost组件的ref + const orderCostRef = useRef(null); + // 创建OrderPackage组件的ref + const orderPackageRefs = useRef([]); const [purchaseOrder, setPurchaseOrder] = useState(); @@ -355,6 +358,7 @@ export default hocAuth(function Page(props: CommonComponent) { return ( { if (ref) { @@ -442,9 +446,21 @@ export default hocAuth(function Page(props: CommonComponent) { // 包装信息 if (step.value === 4) { + // 确保ref数组足够长 + while (orderPackageRefs.current.length <= index) { + orderPackageRefs.current.push({ + validate: () => true, // 默认验证方法 + } as OrderPackageRef); + } + return ( { + if (ref) { + orderPackageRefs.current[index] = ref; + } + }} value={item} onChange={(supplierVO: SupplierVO) => { orderSupplierList[index] = { ...item, ...supplierVO }; @@ -472,7 +488,7 @@ export default hocAuth(function Page(props: CommonComponent) { {/* 人工和辅料信息 */} {step.value === 6 && ( setOrderCostList(costItemList) @@ -553,6 +569,18 @@ export default hocAuth(function Page(props: CommonComponent) { ) { setActive(active + 1); } + } // 在第四步(包装信息)时进行校验 + else if (active === 4) { + // 获取当前选中的供应商 + const selectedIndex = orderSupplierList.findIndex( + (supplier) => supplier.selected, + ); + if ( + selectedIndex !== -1 && + orderPackageRefs.current[selectedIndex]?.validate() + ) { + setActive(active + 1); + } } else { setActive(active + 1); } @@ -572,7 +600,7 @@ export default hocAuth(function Page(props: CommonComponent) { className="btn-large bg-primary ml-2 flex-1 text-white" onClick={async () => { // 第六步(人工辅料)时进行校验 - if (artificialRef.current?.validate()) { + if (orderCostRef.current?.validate()) { await onFinish(true); } }} diff --git a/packages/app-client/src/services/business/typings.d.ts b/packages/app-client/src/services/business/typings.d.ts index f508dad..92367eb 100644 --- a/packages/app-client/src/services/business/typings.d.ts +++ b/packages/app-client/src/services/business/typings.d.ts @@ -2165,6 +2165,7 @@ declare namespace BusinessAPI { boxBrandId: string; /** 箱子品牌名称 */ boxBrandName: string; + boxBrandImage: string; /** 箱子分类ID */ boxCategoryId: string; /** 箱子产品ID */ @@ -2180,7 +2181,7 @@ declare namespace BusinessAPI { /** 销售单价(元/个) */ boxSalePrice?: number; /** 箱子类型:1_本次使用;2_额外运输;3_已使用额外运输;4_车上剩余; */ - boxType: "USED" | "EXTRA" | "EXTRA_USED" | "REMAIN"; + boxType: "USED" | "EXTRA" | "EXTRA_USED" | "REMAIN" | "OWN" | "DEFAULT"; }; type OrderRebate = { diff --git a/packages/app-client/src/types/typings.ts b/packages/app-client/src/types/typings.ts index 54f1a99..65a2667 100644 --- a/packages/app-client/src/types/typings.ts +++ b/packages/app-client/src/types/typings.ts @@ -32,14 +32,18 @@ export interface BoxBrand { id: string; boxBrandId: string; boxBrandName: string; - boxBrandImage: string | undefined; + boxBrandImage: string; + boxType: "USED" | "EXTRA" | "EXTRA_USED" | "REMAIN" | "OWN" | "DEFAULT"; boxCategoryList: BoxCategory[]; } export interface BoxProduct { id: string; + boxBrandId: string; + boxBrandName: string; boxProductId: string; boxProductName: string; + boxCount: number; boxProductWeight: number; boxCategoryId: "FOUR_GRAIN" | "TWO_GRAIN"; boxCostPrice: number; diff --git a/packages/app-client/src/utils/orderPackage.ts b/packages/app-client/src/utils/orderPackage.ts new file mode 100644 index 0000000..1a6f277 --- /dev/null +++ b/packages/app-client/src/utils/orderPackage.ts @@ -0,0 +1,112 @@ +// 将BoxBrand转换为OrderPackage数组 +import { BoxBrand, BoxCategory, BoxProduct } from "@/types/typings"; +import { generateShortId } from "@/utils/generateShortId"; + +// 添加一个辅助函数用于分组 +const groupBy = ( + array: T[], + keyFn: (item: T) => string, +): Record => { + return array.reduce( + (groups, item) => { + const key = keyFn(item); + if (!groups[key]) { + groups[key] = []; + } + groups[key].push(item); + return groups; + }, + {} as Record, + ); +}; + +export const convertBoxBrandToOrderPackages = ( + boxBrand: BoxBrand, + boxType: BusinessAPI.OrderPackage["boxType"] = "USED" +): BusinessAPI.OrderPackage[] => { + const orderPackages: BusinessAPI.OrderPackage[] = []; + + boxBrand.boxCategoryList?.forEach((category) => { + category.boxProductList.forEach((product) => { + orderPackages.push({ + orderPackageId: product.id, + boxBrandId: product.boxBrandId, + boxBrandName: product.boxBrandName, + boxBrandImage: boxBrand.boxBrandImage, + boxCategoryId: product.boxCategoryId, + boxProductId: product.boxProductId, + boxProductName: product.boxProductName, + boxProductWeight: product.boxProductWeight, + boxCount: product.boxCount || 0, + boxCostPrice: product.boxCostPrice, + boxSalePrice: product.boxSalePrice, + boxType: boxType, + }); + }); + }); + + return orderPackages; +}; + +// 将OrderPackage数组转换为BoxBrand数组 +export const convertOrderPackagesToBoxBrands = ( + orderPackages: BusinessAPI.OrderPackage[] +): BoxBrand[] => { + // 按品牌ID分组 + const packagesByBrand = groupBy( + orderPackages, + (pkg) => pkg.boxBrandId + ); + + // 转换为BoxBrand数组 + return Object.entries(packagesByBrand).map(([brandId, packages]) => { + const firstPackage = packages[0]; + + // 按分类ID分组 + const packagesByCategory = groupBy( + packages, + (pkg) => pkg.boxCategoryId + ); + + // 创建BoxCategory数组 + const boxCategories: BoxCategory[] = Object.entries(packagesByCategory).map( + ([categoryId, categoryPackages]) => { + const firstCategoryPackage = categoryPackages[0]; + + // 创建BoxProduct数组 + const boxProducts: BoxProduct[] = categoryPackages.map((pkg) => ({ + id: pkg.orderPackageId || generateShortId(), + boxBrandId: pkg.boxBrandId, + boxBrandName: pkg.boxBrandName, + boxProductId: pkg.boxProductId, + boxProductName: pkg.boxProductName, + boxProductWeight: pkg.boxProductWeight, + boxCategoryId: pkg.boxCategoryId, + boxCostPrice: pkg.boxCostPrice, + boxSalePrice: pkg.boxSalePrice, + boxCount: pkg.boxCount, + } as BoxProduct)); + + return { + id: generateShortId(), + boxCategoryId: categoryId as "FOUR_GRAIN" | "TWO_GRAIN", + boxCategoryName: firstCategoryPackage.boxCategoryId === "FOUR_GRAIN" + ? "4粒装" + : firstCategoryPackage.boxCategoryId === "TWO_GRAIN" + ? "2粒装" + : "未知", + boxProductList: boxProducts, + }; + } + ); + + return { + id: brandId, + boxBrandId: brandId, + boxType: firstPackage.boxType, + boxBrandName: firstPackage.boxBrandName, + boxBrandImage: firstPackage.boxBrandImage, + boxCategoryList: boxCategories, + }; + }); +};