import { Image, Text, View } from "@tarojs/components"; import { Button, Dialog, Input, Radio, Toast } from "@nutui/nutui-react-taro"; import { Icon, SupplierPicker } from "@/components"; import Taro from "@tarojs/taro"; import { forwardRef, useImperativeHandle, useState } from "react"; import { buildUrl, generateShortId, uploadFile } from "@/utils"; import { business } from "@/services"; import { globalStore } from "@/store/global-store"; // 定义ref暴露的方法接口 export interface SupplierInfoRef { validate: () => boolean; } interface ISupplierInfoProps { index: number; value: BusinessAPI.OrderVO; onChange: (orderVO: BusinessAPI.OrderVO) => void; } export default forwardRef( function MelonFarmer(props, ref) { const onRemove = (supplierVO: BusinessAPI.OrderSupplier) => { if (orderSupplierList.length <= 1) { setOrderSupplierList([ { orderSupplierId: generateShortId(), supplierId: "", name: "瓜农1", payeeName: "", idCard: "", bankName: "", bankCard: "", phone: "", selected: true, orderPackageList: [], packageUsage: [ { boxType: "USED", isUsed: 0, }, { boxType: "EXTRA_USED", isUsed: 0, }, { boxType: "EXTRA", isUsed: 0, }, { boxType: "REMAIN", isUsed: 0, }, ], } as any, ]); return; } else { let temp = orderSupplierList.filter( (item: BusinessAPI.OrderSupplier) => item.orderSupplierId !== supplierVO.orderSupplierId, ) as BusinessAPI.OrderSupplier[]; temp[0].selected = true; setOrderSupplierList(temp); } }; const { value, onChange, index } = props; const { orderSupplierList } = value; const supplierVO = orderSupplierList[index] as BusinessAPI.OrderSupplier; const supplierCount = orderSupplierList.length; const isLast = index === supplierCount - 1; const { setLoading } = globalStore((state: any) => state); // 获取已选择的供应商ID列表(排除当前项) const selectedSupplierIds = orderSupplierList .filter((supplier, idx) => idx !== index && supplier.supplierId) .map((supplier) => supplier.supplierId!); // 获取已选择的供应商ID列表(排除当前项) const selectedSupplierNames = orderSupplierList .filter((supplier, idx) => idx !== index && supplier.supplierId) .map((supplier) => supplier.name!); const setOrderSupplierList = ( newOrderSupplierList: BusinessAPI.OrderSupplier[], ) => { onChange({ ...value, orderSupplierList: newOrderSupplierList, }); }; const setSupplierVO = (newSupplierVO: BusinessAPI.OrderSupplier) => { console.log("setSupplierVO", newSupplierVO); setOrderSupplierList([ ...orderSupplierList.map((item: BusinessAPI.OrderSupplier) => { if (item.orderSupplierId == newSupplierVO.orderSupplierId) { return { ...item, ...newSupplierVO, }; } return item; }), ]); }; // 微信收款码上传处理函数 const handleWechatQrUpload = async () => { await Taro.chooseImage({ count: 1, sourceType: ["album", "camera"], success: (res) => { setLoading(true); const file = res.tempFiles[0]; uploadFile(file.path) .then(({ url }) => { setSupplierVO({ ...supplierVO, wechatQr: url, }); setLoading(false); Toast.show("toast", { title: "上传成功", icon: "success", content: "微信收款码已上传", }); }) .catch((err) => { Toast.show("toast", { title: "上传失败", icon: "fail", content: err.message || "上传过程中发生错误", }); setLoading(false); }); }, fail: (err) => { Toast.show("toast", { title: "选择图片失败", icon: "fail", content: err.errMsg, }); }, }); }; // 校验状态 const [nameError, setNameError] = useState<{ [key: string]: boolean }>({}); const [idCardError, setIdCardError] = useState<{ [key: string]: boolean }>( {}, ); const [bankCardError, setBankCardError] = useState<{ [key: string]: boolean; }>({}); const [bankNameError, setBankNameError] = useState<{ [key: string]: boolean; }>({}); const [phoneError, setPhoneError] = useState<{ [key: string]: boolean }>( {}, ); const [isLastFarmerError, setIsLastFarmerError] = useState<{ [key: string]: boolean; }>({}); // 添加是否要拼车的错误状态 // 校验姓名函数 const validateName = (name: string) => { if (!name) { return false; } // 姓名至少2个字符 return name.length >= 2; }; // 校验身份证号函数 const validateIdCard = (idCard: string) => { if (!idCard) { return false; } // 18位身份证号正则表达式 const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; return idCardRegex.test(idCard); }; // 校验银行卡号函数 const validateBankCard = (bankCard: string) => { if (!bankCard) { return false; } // 银行卡号一般为16-19位数字 const bankCardRegex = /^\d{16,19}$/; return bankCardRegex.test(bankCard); }; // 校验银行名称函数 const validateBankName = (bankName: string) => { if (!bankName) { return false; } // 银行名称至少2个字符 return bankName?.length >= 2; }; // 校验手机号函数 (使用项目中已有的规则) const validatePhone = (phone: string) => { if (!phone) { return false; } // 使用项目规范的手机号正则表达式 const phoneRegex = /^1[3456789]\d{9}$/; return phoneRegex.test(phone); }; // 校验是否要拼车函数 // 校验是否要拼车函数 const validateIsLastFarmer = (isLast?: boolean) => { // 必须选择要不要 return isLast !== undefined; }; // 对外暴露的校验方法 const validate = () => { const id = supplierVO?.orderSupplierId; if (!id) return false; const isNameValid = validateName(supplierVO.name || ""); if ( selectedSupplierNames && selectedSupplierNames.includes(supplierVO.name || "") ) { Toast.show("toast", { icon: "fail", title: "提示", content: "该瓜农已被选择,请输入其他名称", }); return false; } const isIdCardValid = validateIdCard(supplierVO.idCard || ""); const isBankNameValid = validateBankName(supplierVO.bankName || ""); const isBankCardValid = validateBankCard(supplierVO.bankCard || ""); const isPhoneValid = validatePhone(supplierVO.phone || ""); const isLastFarmerValid = validateIsLastFarmer(supplierVO?.isLast); // 校验是否需要拼车 // 更新错误状态 setNameError((prev) => ({ ...prev, [id]: !isNameValid, })); setIdCardError((prev) => ({ ...prev, [id]: !isIdCardValid, })); setBankNameError((prev) => ({ ...prev, [id]: !isBankNameValid, })); setBankCardError((prev) => ({ ...prev, [id]: !isBankCardValid, })); setPhoneError((prev) => ({ ...prev, [id]: !isPhoneValid, })); // 更新是否为最后一个瓜农的错误状态 setIsLastFarmerError((prev) => ({ ...prev, [id]: !isLastFarmerValid, })); const isValid = isNameValid && isIdCardValid && isBankNameValid && isBankCardValid && isPhoneValid && isLastFarmerValid; if (!isValid) { Toast.show("toast", { icon: "fail", title: "提示", content: "请完善瓜农信息后再进行下一步操作", }); } return isValid; }; // 将校验方法暴露给父组件 useImperativeHandle(ref, () => ({ validate, })); // 处理姓名变化 const handleNameChange = ( value: string, supplierVO: BusinessAPI.OrderSupplier, ) => { setSupplierVO({ ...supplierVO!, name: value, payeeName: value, }); const id = supplierVO.orderSupplierId; // 校验并更新错误状态 const isValid = validateName(value); setNameError((prev) => ({ ...prev, [id]: !isValid && value !== "", })); if (isValid) { setNameError((prev) => ({ ...prev, [id]: false, })); } if (selectedSupplierNames && selectedSupplierNames.includes(value)) { Toast.show("toast", { icon: "fail", title: "提示", content: "该瓜农已被选择,请输入其他名称", }); } }; // 处理姓名失焦 const handleNameBlur = async (value: string, id: any) => { if (value && !validateName(value)) { setNameError((prev) => ({ ...prev, [id]: true, })); return; } else { setNameError((prev) => ({ ...prev, [id]: false, })); } // 检查瓜农姓名是否在系统中存在 console.log("checkSupplier", value); if (value) { if (selectedSupplierNames && selectedSupplierNames.includes(value)) { Toast.show("toast", { icon: "fail", title: "提示", content: "该瓜农已被选择,请输入其他名称", }); return; } try { const { data: { data: newSupplierVO, success }, } = await business.supplier.checkSupplier({ supplierCheckQry: { name: value, }, }); if (success && newSupplierVO) { // 系统中已存在该瓜农信息,检查是否需要提示用户快速填入 // 条件1: 当前没有选择瓜农 (没有supplierId) // 条件2: 当前选择的瓜农与系统中找到的瓜农不一致 const shouldPrompt = !supplierVO?.supplierId || (supplierVO?.supplierId && supplierVO?.supplierId !== newSupplierVO.supplierId); if (shouldPrompt) { // 判断是首次填入还是冲突替换 const isConflict = supplierVO?.supplierId && supplierVO?.supplierId !== newSupplierVO.supplierId; Dialog.open("dialog", { title: "提示", content: isConflict ? `系统中存在瓜农"${value}"的信息与当前瓜农不同,是否替换为系统中的信息?` : `系统中已存在瓜农"${value}"的信息,是否快速填入?`, onConfirm: () => { // 用户确认,填入信息 setSupplierVO({ ...supplierVO!, ...newSupplierVO, }); // 清除所有错误状态 setNameError((prev) => ({ ...prev, [id]: false, })); setPhoneError((prev) => ({ ...prev, [id]: false, })); setBankCardError((prev) => ({ ...prev, [id]: false, })); setBankNameError((prev) => ({ ...prev, [id]: false, })); setIdCardError((prev) => ({ ...prev, [id]: false, })); Dialog.close("dialog"); }, onCancel: () => { Dialog.close("dialog"); }, }); } } } catch (error) { console.error("检查瓜农信息失败", error); } } }; // 处理身份证号变化 const handleIdCardChange = ( value: string, supplierVO: BusinessAPI.OrderSupplier, ) => { setSupplierVO({ ...supplierVO, idCard: value, }); const id = supplierVO.orderSupplierId; // 校验并更新错误状态 const isValid = validateIdCard(value); setIdCardError((prev) => ({ ...prev, [id]: !isValid && value !== "", })); if (isValid) { setIdCardError((prev) => ({ ...prev, [id]: false, })); } }; // 处理身份证号失焦 const handleIdCardBlur = (value: string, id: any) => { if (value && !validateIdCard(value)) { setIdCardError((prev) => ({ ...prev, [id]: true, })); Toast.show("toast", { icon: "fail", title: "提示", content: "请输入正确的身份证号", }); } else { setIdCardError((prev) => ({ ...prev, [id]: false, })); } }; // 处理银行卡号变化 const handleBankCardChange = ( value: string, supplierVO: BusinessAPI.OrderSupplier, ) => { setSupplierVO({ ...supplierVO, bankCard: value, }); const id = supplierVO.orderSupplierId; // 校验并更新错误状态 const isValid = validateBankCard(value); setBankCardError((prev) => ({ ...prev, [id]: !isValid && value !== "", })); if (isValid) { setBankCardError((prev) => ({ ...prev, [id]: false, })); } }; // 处理银行卡号失焦 const handleBankCardBlur = (value: string, id: any) => { if (value && !validateBankCard(value)) { setBankCardError((prev) => ({ ...prev, [id]: true, })); Toast.show("toast", { icon: "fail", title: "提示", content: "请输入正确的银行卡号", }); } else { setBankCardError((prev) => ({ ...prev, [id]: false, })); } }; // 处理银行名称变化 const handleBankNameChange = ( value: string, supplierVO: BusinessAPI.OrderSupplier, ) => { setSupplierVO({ ...supplierVO, bankName: value, }); const id = supplierVO.orderSupplierId; // 校验并更新错误状态 const isValid = validateBankName(value); setBankNameError((prev) => ({ ...prev, [id]: !isValid && value !== "", })); if (isValid) { setBankNameError((prev) => ({ ...prev, [id]: false, })); } }; // 处理银行名称失焦 const handleBankNameBlur = (value: string, id: any) => { if (value && !validateBankName(value)) { setBankNameError((prev) => ({ ...prev, [id]: true, })); Toast.show("toast", { icon: "fail", title: "提示", content: "请输入正确的银行名称", }); } else { setBankNameError((prev) => ({ ...prev, [id]: false, })); } }; // 处理手机号变化 const handlePhoneChange = ( value: string, supplierVO: BusinessAPI.OrderSupplier, ) => { setSupplierVO({ ...supplierVO, phone: value, }); const id = supplierVO.orderSupplierId; // 校验并更新错误状态 const isValid = validatePhone(value); setPhoneError((prev) => ({ ...prev, [id]: !isValid && value !== "", })); if (isValid) { setPhoneError((prev) => ({ ...prev, [id]: false, })); } }; // 处理手机号失焦 const handlePhoneBlur = (value: string, id: any) => { if (value && !validatePhone(value)) { setPhoneError((prev) => ({ ...prev, [id]: true, })); Toast.show("toast", { icon: "fail", title: "提示", content: "请输入正确的手机号", }); } else { setPhoneError((prev) => ({ ...prev, [id]: false, })); } }; // 处理删除瓜农确认 const handleRemoveConfirm = (supplierVO: BusinessAPI.OrderSupplier) => { Dialog.open("dialog", { title: "移除瓜农", content: `确定要移除"${supplierVO.name || "这个瓜农"}"吗?移除后如果需要可以重新添加。`, onConfirm: () => { onRemove(supplierVO); Dialog.close("dialog"); }, onCancel: () => { Dialog.close("dialog"); }, }); }; console.log("supplierVO", supplierVO); if (!supplierVO) { return; } return ( {/* 功能提醒 */} 收集瓜农信息的目的是用于打款 {/* 只有最后一个瓜农才显示是否为最后一个瓜农的选项和添加按钮 */} {isLast && ( {supplierCount > 1 ? ( 这车货还需继续拼车吗? ) : ( 这车货需拼车吗? )} { // 清除错误状态 setIsLastFarmerError((prev) => ({ ...prev, [supplierVO.orderSupplierId]: false, })); // 根据用户选择设置是否为最后一个瓜农 const isLastValue = value === "true" ? true : value === "false" ? false : undefined; setSupplierVO({ ...supplierVO, // @ts-ignore isLast: isLastValue, }); }} > 需要 不需要 {isLastFarmerError[supplierVO.orderSupplierId] && ( 请选择本车货要不要拼车 )} )} {/* 快捷工具 */} {/* 瓜农信息 */} {supplierVO.name || "瓜农"}的基本信息 {supplierCount > 1 && isLast && ( handleRemoveConfirm(supplierVO)} > 移除瓜农 )} 姓名 点我选瓜农 } onFinish={(supplierVO1) => { // 检查是否已经选择了该瓜农 if ( selectedSupplierIds && selectedSupplierIds.includes(supplierVO1.supplierId!) ) { Toast.show("toast", { icon: "fail", title: "提示", content: "该瓜农已被选择,请选择其他瓜农", }); return; } setSupplierVO({ ...supplierVO, ...supplierVO1, }); // 清除所有错误状态 setNameError((prev) => ({ ...prev, [supplierVO.orderSupplierId]: false, })); setPhoneError((prev) => ({ ...prev, [supplierVO.orderSupplierId]: false, })); setBankCardError((prev) => ({ ...prev, [supplierVO.orderSupplierId]: false, })); setBankNameError((prev) => ({ ...prev, [supplierVO.orderSupplierId]: false, })); setIdCardError((prev) => ({ ...prev, [supplierVO.orderSupplierId]: false, })); }} /> handleNameChange(value, supplierVO)} onBlur={() => handleNameBlur( supplierVO?.name || "", supplierVO.orderSupplierId, ) } className="flex-1" /> {nameError[supplierVO.orderSupplierId] && ( {`姓名"${supplierVO.name}"至少2个字符`} )} 身份证号 handleIdCardChange(value, supplierVO)} onBlur={() => handleIdCardBlur( supplierVO?.idCard || "", supplierVO.orderSupplierId, ) } className="flex-1" /> {idCardError[supplierVO.orderSupplierId] && ( 请输入正确的身份证号 )} 银行名称 handleBankNameChange(value, supplierVO)} onBlur={() => handleBankNameBlur( supplierVO?.bankName || "", supplierVO.orderSupplierId, ) } className="flex-1" /> {bankNameError[supplierVO.orderSupplierId] && ( {`银行名称"${supplierVO.bankName || ""}"至少2个字符`} )} 银行卡号 handleBankCardChange(value, supplierVO)} onBlur={() => handleBankCardBlur( supplierVO?.bankCard || "", supplierVO.orderSupplierId, ) } className="flex-1" /> {bankCardError[supplierVO.orderSupplierId] && ( 请输入正确的银行卡号 )} 手机号码 handlePhoneChange(value, supplierVO)} onBlur={() => handlePhoneBlur( supplierVO?.phone || "", supplierVO.orderSupplierId, ) } className="flex-1" /> {phoneError[supplierVO.orderSupplierId] && ( 请输入正确的手机号 )} {/* 若瓜农无法开发票,则可打款到微信 */} {supplierVO.name || "瓜农"}的微信收款码(可跳过) {supplierVO.wechatQr ? ( 微信收款码 已上传完成 若瓜农无法开发票,则可打款到微信 ) : ( 上传微信收款码 支持从相册选择或拍照 若瓜农无法开发票,则可打款到微信 )} ); }, );