import { forwardRef, ReactNode, useImperativeHandle, useState } from "react"; import { Text, View } from "@tarojs/components"; import { DatePicker, Input, PickerOption, Toast, } from "@nutui/nutui-react-taro"; import dayjs from "dayjs"; import { Icon } from "@/components"; interface Step1FormProps { readOnly?: boolean; moduleList: any[]; orderShip: any; setOrderShip: (value: any) => void; } export interface Step1FormRef { validateForm: () => boolean; } const Step1Form = forwardRef((props, ref) => { const { moduleList, orderShip, setOrderShip, readOnly = false } = props; console.log("moduleList", moduleList, orderShip); // 当天和未来10天 const startDate = new Date(); const endDate = new Date(startDate.getTime() + 86400000 * 10); const [show, setShow] = useState(false); const formatter = (type: string, option: PickerOption) => { switch (type) { case "year": option.label += "年"; break; case "month": option.label += "月"; break; case "day": option.label += "日"; break; case "hour": option.label += "时"; break; case "minute": option.label += "分"; break; default: break; } return option; }; // 表单错误状态 const [formErrors, setFormErrors] = useState<{ watermelonGrade?: boolean; shippingAddress?: boolean; estimatedArrivalDate?: boolean; remark?: boolean; itemGrades?: { [key: string]: boolean }; }>({}); // 暴露方法给父组件 useImperativeHandle(ref, () => ({ validateForm, })); // 渲染内容配置表单字段 const renderContentFields = (module: any) => { const contentSchema = module.schemas.find( (schema: any) => schema.title === "内容配置", ); if ( !contentSchema || !contentSchema.columns || contentSchema.columns.length === 0 ) { return null; } const contentFields: ReactNode[] = []; contentSchema.columns.forEach((column: any, index: number) => { if ( column.dataIndex === "requiredWatermelonGrade" && module.config.showWatermelonGrade ) { contentFields.push( {column.title} { // 清除错误状态 if (formErrors.watermelonGrade && value) { setFormErrors((prev) => ({ ...prev, watermelonGrade: false, })); } setOrderShip({ ...orderShip!, watermelonGrade: value, }); }} onBlur={() => { // 失焦时校验 if (!orderShip?.watermelonGrade) { setFormErrors((prev) => ({ ...prev, watermelonGrade: true, })); Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写${column.title}`, }); } }} placeholder={ column.fieldProps?.placeholder || `请${column.title}` } type="text" className="flex-1" /> {formErrors.watermelonGrade && ( {`请${column.title}`} )} , ); } if ( column.dataIndex === "requiredShippingFrom" && module.config.showShippingFrom ) { contentFields.push( {column.title} { // 清除错误状态 if (formErrors.shippingAddress && value) { setFormErrors((prev) => ({ ...prev, shippingAddress: false, })); } setOrderShip({ ...orderShip!, shippingAddress: value, }); }} onBlur={() => { // 失焦时校验 if (!orderShip?.shippingAddress) { setFormErrors((prev) => ({ ...prev, shippingAddress: true, })); Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写${column.title}`, }); } }} placeholder={ column.fieldProps?.placeholder || `请${column.title}` } type="text" className="flex-1" /> {formErrors.shippingAddress && ( {`请${column.title}`} )} , ); } if ( column.dataIndex === "requiredEstimatedArrivalTime" && module.config.showEstimatedArrivalTime ) { contentFields.push( {column.title} readOnly || setShow(true)} > {orderShip?.estimatedArrivalDate ? dayjs(orderShip?.estimatedArrivalDate).format( "YYYY年MM月DD日", ) : column.fieldProps?.placeholder || `请${column.title}`} setShow(false)} onConfirm={(_, values) => { // 选择日期后清除错误状态 if (formErrors.estimatedArrivalDate) { setFormErrors((prev) => ({ ...prev, estimatedArrivalDate: false, })); } setOrderShip({ ...orderShip!, estimatedArrivalDate: dayjs(values.join("-")).format( "YYYY-MM-DD", ), }); }} /> {formErrors.estimatedArrivalDate && ( {`请${column.title}`} )} , ); } if (column.dataIndex === "requiredRemarks" && module.config.showRemarks) { contentFields.push( {column.title} { // 清除错误状态 if (formErrors.remark && value) { setFormErrors((prev) => ({ ...prev, remark: false, })); } setOrderShip({ ...orderShip!, remark: value, }); }} onBlur={() => { // 失焦时校验 if (!orderShip?.remark) { setFormErrors((prev) => ({ ...prev, remark: true, })); Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写${column.title}`, }); } }} placeholder={ column.fieldProps?.placeholder || `请${column.title}` } type="text" className="flex-1" /> {formErrors.remark && ( {`请${column.title}`} )} , ); } if (column.dataIndex === "requiredGrade" && module.config.showGrade) { contentFields.push( {column.title} {orderShip?.orderShipItemList?.map( (shipOrderItem: any, index: number) => { return ( 单价:{shipOrderItem.unitPrice} 元/斤 { // 清除该项的错误状态 if ( formErrors.itemGrades?.[shipOrderItem.itemId] && value ) { setFormErrors((prev) => ({ ...prev, itemGrades: { ...prev.itemGrades, [shipOrderItem.itemId]: false, }, })); } setOrderShip({ ...orderShip!, orderShipItemList: orderShip?.orderShipItemList?.map( (item: any) => { if (item.itemId === shipOrderItem.itemId) { return { ...item, watermelonGrade: value, }; } return item; }, ), }); }} onBlur={() => { // 失焦时校验 if (!shipOrderItem.watermelonGrade) { setFormErrors((prev) => ({ ...prev, itemGrades: { ...prev.itemGrades, [shipOrderItem.itemId]: true, }, })); Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写第${index + 1}项的品级`, }); } }} placeholder={ column.fieldProps?.placeholder || `请${column.title}` } type="text" className="flex-1" /> {formErrors.itemGrades?.[shipOrderItem.itemId] && ( {`请${column.title}`} )} ); }, )} , ); } }); if (contentFields.length > 0) { return contentFields; } return null; }; // 表单校验 const validateForm = () => { const errors: any = {}; let hasErrors = false; // 检查各模块中的必填字段是否已填写 for (const module of moduleList) { const contentSchema = module.schemas.find( (schema: any) => schema.title === "内容配置", ); if ( !contentSchema || !contentSchema.columns || contentSchema.columns.length === 0 ) { continue; } for (const column of contentSchema.columns) { // 检查西瓜品级字段是否开启且已填写 if ( column.dataIndex === "requiredWatermelonGrade" && module.config.showWatermelonGrade ) { if (!orderShip?.watermelonGrade) { errors.watermelonGrade = true; hasErrors = true; Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写${column.title}`, }); } } // 检查发货地字段是否开启且已填写 else if ( column.dataIndex === "requiredShippingFrom" && module.config.showShippingFrom ) { if (!orderShip?.shippingAddress) { errors.shippingAddress = true; hasErrors = true; Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写${column.title}`, }); } } // 检查预计到仓时间字段是否开启且已填写 else if ( column.dataIndex === "requiredEstimatedArrivalTime" && module.config.showEstimatedArrivalTime ) { if (!orderShip?.estimatedArrivalDate) { errors.estimatedArrivalDate = true; hasErrors = true; Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请选择${column.title}`, }); } } // 检查备注字段是否开启且已填写 else if ( column.dataIndex === "requiredRemarks" && module.config.showRemarks ) { if (!orderShip?.remark) { errors.remark = true; hasErrors = true; Toast.show("toast", { icon: "fail", title: column.fieldProps?.placeholder || `请填写${column.title}`, }); } } // 检查品级字段是否开启且已填写 else if ( column.dataIndex === "requiredGrade" && module.config.showGrade ) { console.log( "orderShip?.orderShipItemList", orderShip?.orderShipItemList, ); if (orderShip?.orderShipItemList) { const itemGradesErrors: { [key: string]: boolean } = {}; for (let i = 0; i < orderShip.orderShipItemList.length; i++) { const item = orderShip.orderShipItemList[i]; if (!item.watermelonGrade) { itemGradesErrors[item.itemId] = true; hasErrors = true; Toast.show("toast", { icon: "fail", title: `请填写第${i + 1}项的品级`, }); } } if (Object.keys(itemGradesErrors).length > 0) { errors.itemGrades = itemGradesErrors; } } } } } setFormErrors(errors); return !hasErrors; }; return moduleList.map((module) => { const contentFields = renderContentFields(module); // 如果没有内容配置字段,则不渲染该模块 if (!contentFields) return null; return ( {module.title} {contentFields} ); }); }); export default Step1Form;