import { View } from "@tarojs/components"; import { Icon } from "@/components"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import { business } from "@/services"; import { Button, Checkbox, Input, Toast } from "@nutui/nutui-react-taro"; import { CostItem, SupplierVO } from "@/types/typings"; import { generateShortId } from "@/utils/generateShortId"; // 定义ref暴露的方法接口 export interface OrderCostRef { validate: () => boolean; } export interface IOrderCostProps { value: CostItem[]; supplierVO: SupplierVO; onChange?: (costItemList: CostItem[]) => void; onAdd: () => void; } export default forwardRef( function OrderCost(IOrderCostProps, ref) { const { value, supplierVO, onChange, onAdd } = IOrderCostProps; const [costItemVOList, setCostItemVOList] = useState(); // 总的工头姓名状态 const [principal, setPrincipal] = useState(""); // 工头姓名错误状态 const [principalError, setPrincipalError] = useState(false); const init = async () => { const { data } = await business.costItem.listCostItem({ costItemListQry: { status: true, showInEntry: true, }, }); const costItemList = data.data; if (costItemList) { // 人工辅料选中 const initialList = costItemList ?.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 ? existingItem.orderCostId : generateShortId(), itemId: item.itemId, name: item.name, price: item.price, unit: item.unit, selected: existingItem ? existingItem.selected : false, count: existingItem ? existingItem.count : 1, payerType: existingItem ? existingItem.payerType : undefined, principal: existingItem ? existingItem.principal : "", costType: item.costType, requireQuantityAndPrice: existingItem ? existingItem.requireQuantityAndPrice : false, }; }) || []; setCostItemVOList([ ...(initialList || []), ...(value ?.filter( (item) => item.costType === "WORKER_ADVANCE" || item.costType === "PRODUCTION_ADVANCE", ) .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, }; }) || []), ]); // 初始化总的工头姓名(如果有启用且费用承担方为"我方"的项目) const enabledUsItems = initialList.filter( (item) => item.selected && item.payerType === "US" && item.costType === "HUMAN_COST", ); if (enabledUsItems.length > 0 && enabledUsItems[0].principal) { setPrincipal(enabledUsItems[0].principal || ""); } } }; // 当传入的value发生变化时,重新初始化列表 useEffect(() => { init().then(); }, []); // 当内部状态发生变化时,通知父组件更新 useEffect(() => { if (costItemVOList && onChange) { // 更新所有启用且费用承担方为"我方"的人工费用项的工头姓名 const updatedList = costItemVOList.map((item) => { if ( item.costType === "HUMAN_COST" && item.selected && item.payerType === "US" ) { return { ...item, principal }; } return item; }); onChange(updatedList); } }, [costItemVOList, principal]); // 错误状态 const [countError, setCountError] = useState<{ [key: string]: boolean }>( {}, ); const [payerTypeError, setPayerTypeError] = useState<{ [key: string]: boolean; }>({}); // 设置人工项目选择状态 const setArtificialSelect = (id: string, selected: boolean) => { if (!costItemVOList) return; const newList = costItemVOList.map((item) => item.orderCostId === id ? { ...item, selected } : item, ); setCostItemVOList(newList); }; // 处理数量变化 const handleCountChange = (id: string, value: number) => { if (!costItemVOList) return; const newList = costItemVOList.map((item) => item.orderCostId === id ? { ...item, count: value } : item, ); setCostItemVOList(newList); // 校验数量 if (costItemVOList.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; setPrincipalError(!isValid); return isValid; }; // 处理费用承担方变化 const handlePayerTypeChange = ( id: string, value: CostItem["payerType"], ) => { if (!costItemVOList) return; const newList = costItemVOList.map((item) => item.orderCostId === id ? { ...item, payerType: value } : item, ); setCostItemVOList(newList); // 校验费用承担方 if (costItemVOList.find((item) => item.orderCostId === id)?.selected) { validatePayerType(id, value); } }; // 处理工头姓名变化 const handlePrincipalChange = (value: string) => { setPrincipal(value); // 如果有启用且费用承担方为"我方"的项目,则校验工头姓名 const enabledUsItems = costItemVOList?.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 (!costItemVOList) return true; let isValid = true; costItemVOList.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 = costItemVOList.filter( (item) => item.costType === "HUMAN_COST" && item.selected && item.payerType === "US", ); if (enabledUsItems.length > 0) { if (!validatePrincipal(principal)) { isValid = false; } } if (!isValid) { Toast.show("toast", { icon: "fail", title: "提示", content: "请完善人工信息后再进行下一步操作", }); } return isValid; }; useImperativeHandle(ref, () => ({ validate, })); // 获取指定类型的项目列表 const getItemsByCostType = (costType: string) => { return costItemVOList?.filter((item) => item.costType === costType) || []; }; // 渲染项目列表 const renderItemList = (items: CostItem[], type: string) => { return items.map((item) => ( {item.name} { setArtificialSelect(item.orderCostId, checked); }} > 用了 {item.selected && type === "HUMAN_COST" && ( {/* 费用承担方改为按钮形式,参考OrderPackage中的样式 */} 谁出钱: {payerTypeError[item.orderCostId] && item.selected && ( 请选择谁出这笔钱 )} )} {item.selected && ( 用多少: { const count = item.count || 1; handleCountChange( item.orderCostId, Math.max(1, count - 1), ); }} > { handleCountChange(item.orderCostId, Number(value)); }} formatter={(value) => Math.max(1, Number(value)).toString() } onBlur={() => handleCountBlur(item.orderCostId, item.count) } /> { const count = item.count || 1; handleCountChange(item.orderCostId, count + 1); }} > {item.unit} {countError[item.orderCostId] && item.selected && ( 请填写正确的数量 )} )} )); }; // 检查是否有人工费用项被启用且费用承担方为"我方" const shouldShowPrincipalInput = () => { return ( costItemVOList?.some( (item) => item.costType === "HUMAN_COST" && item.selected && item.payerType === "US", ) || false ); }; return ( 人工费用 对方出钱可以不勾选 {renderItemList(getItemsByCostType("HUMAN_COST"), "HUMAN_COST")} {/* 总的工头姓名输入框 */} {shouldShowPrincipalInput() && ( 工头叫什么名字 { handlePrincipalChange(value); }} onBlur={() => handlePrincipalBlur(principal)} /> {principalError && ( 工头叫啥子填一下 )} )} 辅料费用 用了几包就填几包 {renderItemList( getItemsByCostType("PACKAGING_MATERIALS"), "PACKAGING_MATERIALS", )} {/**/} {/* 空纸箱费用*/} {/* {renderItemList(getItemsByCostType("OTHER_COST"), "OTHER_COST")}*/} {/**/} {/**/} {/* 空礼盒费用*/} {/* {renderItemList(getItemsByCostType("OTHER_COST"), "OTHER_COST")}*/} {/**/} {/* 只有当用户选择"否"时才显示添加按钮 */} {!supplierVO.isLast && ( )} ); }, );