js はデータ関連付けの検索と更新を実装します。データ合計検証

ここに画像の説明を挿入
この機能を実現するために、バックエンドでデータ構造を定義しました。

data:{
	id:‘’,
	formInfo:'',
	formInfo2:'',
	formInfo3:'',
	formInfo4:'', 
	......
	deailData:[ // 明细数据  // saleData 查询带出的对应明细序列号数据
		{	id:'',	ocopyId:'',	copyId:'',	odoId:'',	......,  saleData:[ {	id:'',	ocopyId:'', odoId:'',	......,} ] },
		{	id:'',	ocopyId:'',	copyId:'',	odoId:'',	......,  saleData:[ {	id:'',	ocopyId:'', odoId:'',	......,} ] },
		{	id:'',	ocopyId:'',	copyId:'',	odoId:'',	......,  saleData:[ {	id:'',	ocopyId:'', odoId:'',	......,} ] }
	]
}

この下にコードを入力してください

/**
 * 编辑页面
 */ 
	import React from 'react';
	import { TForm, ELImport_3, ElNotification, ElRowContainer, TCollapse } from '@/cloudt/component';
	import { TEditTable } from '@/cloudt/pro-component';
	import {
	  getDetailColumns,
	  getSerialButtons,
	  getDetailButtons,
	  getTopButtons,
	  getBasicForm,
	  getControlForm,
	  getReceivingForm,
	  getSerialEdittabColumns,
	} from './config';
	import dayjs from 'dayjs';
	import { asserts } from '@/utils';
	import { save, getDetailById, getFileCode } from './service';
	import { FileUpload } from '@/cloudt/component/ItemComponent';
	import { maths } from '@/utils';
	import { Spin } from 'antd';
	import { closeCurrentToPath, frameHistoryPush } from '@/cloudt/frame-history';
	interface Props {
	  match: any;
	}
	
	interface State {
	  loading: boolean;
	  pageType: string;
	  id: string | number;
	  bascicFormData: any;
	  OrderInfoData: Array<any>;
	  recvCountryCode: any;
	  fileList: Array<any>;
	  preSelectedRow: Record<string, any> | null; //记录上次选中的明细行
	  importRequestParams: Record<string, any>;
	}
	
	class SaleOrderEdit extends React.Component<Props, State> {
	  basicFormRef: any; //基础信息表单ref
	  controlFormRef: any; //制单信息
	  receiveFormRef: any; //客户收货信息表单ref
	  deatilTableRef: any; //明细信息可编辑表格ref
	  serialTableRef: any; // 序列号ref
	  importModalRef: any; //导入组件ref
	  constructor(props) {
	    super(props);
	    this.state = {
	      fileList: [],
	      id: this.props.match?.params?.id, //单据id
	      pageType: this.props.match.path.includes('/edit/') ? 'edit' : 'view', // 编辑或详情页面
	      loading: false, // 页面级loading
	      bascicFormData: {}, //基本信息
	      OrderInfoData: [], //明细数据
	      recvCountryCode: '', // 国家
	      preSelectedRow: null,
	      importRequestParams: {},
	    };
	  }
	  async componentDidMount() {
	    await this.getDetail(this.state.id);
	  }
	
	  getDetail = async (id) => {
	    this.setState({
	      loading: true,
	    });
	    const res = await getDetailById(id);
	    if (res && res.success) {
	      const bascicFormData = await this.handleBasicFormData(res?.data);
	      const newSalSoDSaveVOList = this.handleDetailEditData(res?.data?.odoDList);
	      // 查询附件
	      const fileCode = res.data?.fileCode;
	      if (fileCode) {
	        await this.handleFilesData(res.data?.fileCode.split(','));
	      }
	      this.setState({
	        bascicFormData,
	        OrderInfoData: newSalSoDSaveVOList,
	      });
	    } else {
	      ElNotification({
	        type: 'error',
	        message: res.msg || '查询失败',
	      });
	    }
	    this.setState({
	      loading: false,
	    });
	  };
	
	  handleBasicFormData = async (data) => {
	    const basicData = {
	      ...data,
	      recvArea: [data?.recvProvince, data?.recvCity, data?.recvCounty],
	      whId: {
	        whId: data?.whId,
	        whCode: data?.whCode,
	        whName: data?.whName,
	        // deter2: data?.deter2,
	        // deter2Name: data?.deter2Name,
	      },
	    };
	    this.setState({
	      recvCountryCode: data?.recvCountry,
	    });
	    return basicData;
	  };
	
	  handleFilesData = async (fileCode) => {
	    const res = await getFileCode(fileCode);
	    if (res && res.success) {
	      this.setState({
	        fileList: res.data,
	      });
	    }
	  };
	
	  /**
	   * 查详情明细行数据处理 -- 明细行原始数据
	   */
	  handleDetailEditData = (odoDSaveVOList) => {
	    const newSalSoDSaveVOList =
	      odoDSaveVOList &&
	      Array.isArray(odoDSaveVOList) &&
	      odoDSaveVOList.map((item) => {
	        return {
	          ...item,
	          // createTime: asserts.isExist(item?.createTime) ? dayjs(item?.createTime).format('YYYY-MM-DD') : null,
	          // modifyTime: asserts.isExist(item?.modifyTime) ? dayjs(item?.modifyTime).format('YYYY-MM-DD') : null,
	          serialRespVOs: item.serialRespVOs ? item.serialRespVOs : [],
	          lotNo: item?.lotNo,
	        };
	      });
	    return newSalSoDSaveVOList;
	  };
	
	  // 明细信息行选择事件 更新下边的序号编辑
	  handleOrderInfoSelect = async (selectedRowKeys, selectedRows) => {
	    await this.deatilTableRef.quitEditState(); // 明细行退出编辑状态
	    await this.serialTableRef.quitEditState(); // 序列号退出编辑状态
	    const TableValues = await this.serialTableRef.getRows(); // 获取序列号数据
	    const detailSelectedRow = selectedRows[0];
	    if (this.state.preSelectedRow) {
	      this.deatilTableRef.updateRows({ serialRespVOs: TableValues }, [this.state.preSelectedRow.id]);
	    }
	    const nowSerialData = detailSelectedRow?.serialRespVOs;
	    await this.serialTableRef?.clearRows(); //清除可编辑表格的数据
	    this.serialTableRef?.addRows(nowSerialData); //重新添加查询的数据
	    this.setState({
	      preSelectedRow: detailSelectedRow,
	    });
	  };
	
	  // 明细行复制
	  handleCopy = async (selectedRowKeys, selectedRows) => {
	    const selectedRow = selectedRows[0];
	    const isCopyedRow = selectedRow.ocopyId;
	    if (isCopyedRow) {
	      return ElNotification({
	        type: 'warning',
	        message: '不能复制已经复制的信息,请重新选择',
	      });
	    }
	    await this.deatilTableRef.quitEditState();
	    const dataSouce = await this.deatilTableRef.getRows();
	    const index = dataSouce?.findLastIndex((v) => selectedRow?.relateDocLineno === v.relateDocLineno);
	    const copyRow = {
	      ...selectedRow,
	      odoId: this.state.id, // 单头id
	      ocopyId: selectedRow.id, // 复制行时把id给ocopyId,
	      id: maths.genFakeId(-1),
	      demandQty: null,
	      qty: 0,
	      serialRespVOs: [],
	    };
	    dataSouce.splice(index + 1, 0, copyRow);
	    await this.deatilTableRef.clearRows();
	    await this.deatilTableRef.addRows(dataSouce);
	  };
	
	  // 明细信息行删除事件
	  handleDelClick = async (selectedRowKeys, selectedRows) => {
	    const selectedRow = selectedRows[0];
	    const isCopyedRow = selectedRow.ocopyId;
	    if (!isCopyedRow) {
	      return ElNotification({
	        type: 'warning',
	        message: '只能删除复制行,请重新选择',
	      });
	    }
	    // 删除明细信息
	    this.deatilTableRef.removeRowsByKeys(selectedRowKeys, 'rowKey');
	    await this.serialTableRef.quitEditState(); // 序列号退出编辑状态
	    await this.serialTableRef?.clearRows(); //清除可编辑表格的数据
	  };
	
	  // 序列号信息添加
	  handleAddDataRow = async () => {
	    const selectionData = await this.deatilTableRef?.getSelectionData();
	    if (selectionData.selectedRows.length !== 1) {
	      return ElNotification({
	        type: 'warning',
	        message: '请选中一行明细',
	      });
	    }
	    const detailSelectedRow = selectionData.selectedRows[0];
	    const newRow = {
	      id: maths.genFakeId(-1),
	      odoId: this.state.id, // 关联单id
	      odoDid: detailSelectedRow?.id, // 序列号新增时,赋值选中的明细行id
	    };
	    this.serialTableRef?.addRow(newRow); //重新添加查询的数据
	  };
	
	  // 序列号信息删除
	  handleDistributionDelete = async (selectedRowKeys) => {
	    await this.serialTableRef.quitEditState();
	    this.serialTableRef.removeRowsByKeys(selectedRowKeys, 'rowKey');
	  };
	
	  // 序列号导入
	  handleImport = async () => {
	    const selectionData = await this.deatilTableRef?.getSelectionData();
	    if (selectionData.selectedRows.length !== 1) {
	      return ElNotification({
	        type: 'warning',
	        message: '请选中一行明细',
	      });
	    }
	    this.setState({
	      importRequestParams: { odoDid: selectionData.selectedRows[0].id, odoId: this.state.id },
	    });
	    this.importModalRef.openModal();
	  };
	  // 导入方法回调
	  importCallBack = async (res) => {
	    if (res && res.success) {
	      const importSuccessData = res.data.map((x) => {
	        return {
	          ...x,
	          id: maths.genFakeId(-1),
	        };
	      });
	      this.serialTableRef?.addRows(importSuccessData);
	      ElNotification({
	        type: 'success',
	        message: '操作成功!',
	      });
	    } else if (res && !res.success) {
	      ElNotification({
	        type: 'error',
	        message: res?.msg || '操作失败',
	      });
	    }
	  };
	
	  /**
	   * 返回
	   */
	  onBack = () => {
	    closeCurrentToPath('/inventory/outboundDelivery/searchOrder');
	  };
	
	  // 保存
	  saveParams = async () => {
	    //保存之前先把序列号信息退出编辑状态,同步到明细数据中
	    const selectionData = await this.deatilTableRef?.getSelectionData();
	    const detailSelectedRow = selectionData?.selectedRows[0];
	    await this.serialTableRef.quitEditState(); // 序列号退出编辑状态
	    const serialEditTableValues = await this.serialTableRef.validateTableRows();
	    if (!serialEditTableValues?.msg?.success) {
	      ElNotification({
	        type: 'warning',
	        message: '请添加序列号必填信息!',
	      });
	      return;
	    }
	
	    const TableValues = await this.serialTableRef.getRows(); // 获取序列号数据
	    if (this.state.preSelectedRow) {
	      this.deatilTableRef.updateRows({ serialRespVOs: TableValues }, [detailSelectedRow?.id]);
	      // this.deatilTableRef.updateRows({ serialRespVOs: TableValues }, [this.state.preSelectedRow.id]);
	    }
	    const data = await this.processData();
	    if (data?.odoDSaveVOList?.length === 0) {
	      ElNotification({
	        type: 'warning',
	        message: '明细信息不允许为空',
	      });
	      return;
	    }
	    if (data) {
	      this.setState({ loading: true });
	      const res = await save(data);
	      this.setState({ loading: false });
	      if (res.success) {
	        ElNotification({
	          type: 'success',
	          message: res.msg || '操作成功',
	        });
	        this.onBack();
	      } else {
	        ElNotification({
	          type: 'error',
	          message: res.msg || res.data || '操作失败!',
	        });
	      }
	    }
	  };
	
	  /*
	  入参基本信息处理
	  baseFormDataRes 基本信息
	  custFormDataRes 客户信息
	  */
	  paramsBasicFormData = (baseFormDataRes, custFormDataRes) => {
	    baseFormDataRes.whId = baseFormDataRes.whId?.whId;
	    baseFormDataRes.whCode = baseFormDataRes.whId?.whCode;
	    baseFormDataRes.whName = baseFormDataRes.whId?.whName;
	
	    custFormDataRes.recvArea = undefined;
	  };
	
	  /*  delSameObjValue 数组对象相同值相加去重
	    arr 需要处理的数组   -- editTableValues?.data
	    resultNum 最终计算结果的键名 -- sumConfirmQty
	    keyName  用于计算判断的键名 这里是以数组的方式传过来的可以这支持接收多个参数判断】 -- relateDocLineno
	    keyValue 用于计算结果的键名 这里是以数组的方式传过来的可以这支持接收多个参数判断】 对应的键值为number类型 -- qty
	    */
	  delSameObjValue = (arr, resultNum, keyName, keyValue) => {
	    const warp = new Map();
	    arr.forEach((i) => {
	      const str = keyName.map((v) => i[v]).join('_');
	      i[resultNum] = keyValue.reduce((p, c) => (p += i[c]), 0);
	      warp.has(str) ? (warp.get(str)[resultNum] += i[resultNum]) : warp.set(str, i);
	    });
	    return Array.from(warp).map(([, v]) => v);
	  };
	
	  // 校验表单信息
	  processData = async () => {
	    // 基本信息
	    const baseFormDataRes = await this.basicFormRef?.validateFields().catch(() => {
	      ElNotification({
	        type: 'warning',
	        message: '请检查【基本信息】必填信息',
	      });
	      return Promise.reject();
	    });
	    // 客户信息
	    const custFormDataRes = await this.receiveFormRef?.getFieldsValue();
	    // 制单信息
	    const otherFormDataRes = await this.controlFormRef?.getFieldsValue();
	
	    this.paramsBasicFormData(baseFormDataRes, custFormDataRes);
	    // 附件信息
	    const { fileList } = this.state;
	    const fileCodes =
	      Array.isArray(fileList) &&
	      fileList?.map((x) => {
	        return x.fileCode;
	      });
	    const fileCode = fileCodes.toString();
	
	    // 商品明细信息
	    await this.deatilTableRef.quitEditState(); //保存退出明细行编辑状态
	    const editTableValues = await this.deatilTableRef.validateTableRows();
	    const sum = this.delSameObjValue(editTableValues?.data, 'sumConfirmQty', ['relateDocLineno'], ['qty']);
	    const flag = sum.some((val) => val.sumConfirmQty !== val.demandQty);
	    if (flag) {
	      return ElNotification({
	        type: 'warning',
	        message: '相同【来源单据行号】的数据信息【实发数量】必须等于【要求发货数量】!',
	      });
	    }
	    if (!editTableValues?.msg?.success) {
	      return ElNotification({
	        type: 'warning',
	        message: '请添加明细必填信息!',
	      });
	    }
	
	    const ruleLotFlagAddlotNo = editTableValues?.data.some(
	      (item) => item.lotFlag && (item.lotNo === null || item.lotNo === ''),
	    );
	    if (ruleLotFlagAddlotNo) {
	      return ElNotification({
	        type: 'warning',
	        message: '明细商品中包含【启用批次】,请检查并完善【批次】',
	      });
	    }
	
	    const itemDataSource = editTableValues?.data?.map((item) => {
	      return {
	        ...item,
	        odoId: this.state.id,
	        lotNo: item?.lotNo?.lotNo,
	        olotNo: item?.orlotNo,
	        odoSerialSaveVOs: item.serialRespVOs ? item.serialRespVOs : [],
	        sumConfirmQty: undefined, // 提示汇总字段不要
	        serialRespVOs: undefined, // 返回的数组字段不要
	        orlotNo: undefined,
	      };
	    });
	
	    // 根据公司查询组织
	    return {
	      ...this.state.bascicFormData,
	      id: this.state.bascicFormData?.id, //复制按钮时,入参需要处理
	      ...baseFormDataRes, //基础信息
	      ...custFormDataRes, //客户信息
	      ...otherFormDataRes, // 制单信息
	      odoDSaveVOList: itemDataSource, // 明细
	      fileCode, // 附件
	      odoDList: undefined,
	    };
	  };
	
	  render() {
	    const {
	      pageType,
	      bascicFormData: bascicFormDate,
	      loading,
	      OrderInfoData,
	      fileList,
	      importRequestParams,
	    } = this.state;
	
	    return (
	      <Spin spinning={loading}>
	        <div className="inner-content">
	          <ElRowContainer onBack={this.onBack} blocks={getTopButtons(this.saveParams, pageType)} position="top" />
	          <TCollapse className="formAlignment" title="基本信息" levelOne>
	            <TForm
	              data={bascicFormDate}
	              onRef={(ref) => {
	                this.basicFormRef = ref;
	              }}
	              formProps={getBasicForm(pageType)}
	            />
	            <TCollapse title="收货信息" defaultOpen={false} className="formAlignment">
	              <TForm
	                data={bascicFormDate}
	                onRef={(ref) => {
	                  this.receiveFormRef = ref;
	                }}
	                formProps={getReceivingForm(this.state.recvCountryCode)}
	              />
	            </TCollapse>
	            <TCollapse title="制单信息" defaultOpen={false} className="formAlignment">
	              <TForm
	                data={bascicFormDate}
	                onRef={(ref) => {
	                  this.controlFormRef = ref;
	                }}
	                formProps={getControlForm()}
	              />
	            </TCollapse>
	          </TCollapse>
	          <TCollapse title="明细信息">
	            <TEditTable
	              tableId="middleGround_inventoryCenter_supply_saleorder_orderDetail"
	              bordered
	              rowKey="id"
	              scroll={
   
   { y: 20000 }}
	              onRef={(ref) => (this.deatilTableRef = ref)}
	              dataSource={OrderInfoData}
	              actionButtons={getDetailButtons(pageType, this.handleCopy, this.handleDelClick)}
	              needToolBar={true}
	              columns={getDetailColumns(pageType, this)}
	              rowSelectionConfig={
   
   {
	                type: 'radio',
	                fixed: true,
	                disabledRowIds: [],
	                onChange: ({ selectedRowKeys, selectedRows }) => {
	                  this.handleOrderInfoSelect(selectedRowKeys, selectedRows);
	                },
	              }}
	              defaultTableConfig={
   
   {
	                onBottomPressEnter: 'trigger',
	                onTableIntoEdit: 'dbclick',
	              }}
	            />
	          </TCollapse>
	          <TCollapse title="序列号信息">
	            <TEditTable
	              tableId="middleGround_inventoryCenter_supply_saleorder_distributionInformation"
	              rowKey="id"
	              bordered
	              scroll={
   
   { y: 'calc(100vh - 430px)' }}
	              dataSource={[]}
	              actionButtons={getSerialButtons(
	                pageType,
	                this.handleAddDataRow,
	                this.handleDistributionDelete,
	                this.handleImport,
	              )}
	              onRef={(ref) => (this.serialTableRef = ref)}
	              columns={getSerialEdittabColumns(pageType)}
	            />
	          </TCollapse>
	
	          <TCollapse title="相关附件" levelOne={true}>
	            <FileUpload
	              useType="outTable"
	              fileListLen={999}
	              uploadInfo="支持所有类型文件,文件不能超过10M"
	              value={fileList}
	              onUploadErr={(err) => {
	                ElNotification({
	                  type: 'error',
	                  message: err?.msg || '上传失败',
	                });
	              }}
	              onRemoveErr={(err) => {
	                ElNotification({
	                  type: 'error',
	                  message: err?.msg || '删除失败',
	                });
	              }}
	              onChange={(value) => {
	                this.setState({
	                  fileList: value,
	                });
	              }}
	              multiple={true}
	              fileList={fileList}
	              prefix="/cloudt/system"
	              disabled={pageType === 'view'}
	            />
	          </TCollapse>
	
	          <ELImport_3
	            push={frameHistoryPush}
	            prefix="/yst/inv"
	            templateCode="INV_ODO_SERIAL_IMPORT"
	            downTemplateConfig={
   
   {
	              mode: 'templateCode',
	              fileName: '序列号导入模版',
	            }}
	            importConfig={
   
   {
	              mode: 'request',
	              url: '/yst/inv/inv/odod/serial/importOdoSerial',
	              maxSize: 1,
	              sizeUnit: 'MB',
	              note: '仅支持xlsx文件,不能大于20mb',
	              accept: 'xlsx|xls|xlsx',
	              onSuccess: this.importCallBack,
	            }}
	            requestParams={importRequestParams}
	            onRef={(ref) => (this.importModalRef = ref)}
	          />
	        </div>
	      </Spin>
	    );
	  }
	}
	
	export default SaleOrderEdit;

おすすめ

転載: blog.csdn.net/lzfengquan/article/details/132510742
おすすめ