猪齿鱼(Choerodon UI )dataSet.delete通用删除的封装 —— 解决两个dataSet.delete的自身问题

贡威
2023-12-01

通用删除(comDelete) —— 两次删除的解决方案

一、背景与简介

删除的三个通用问题 —— 详情请看「猪齿鱼“可分页表格”的四个通用问题以及解决方案」

  1. 通用删除(@common/utils/ciecUtils中的commonDelete)的不稳定(依赖于dataSet.totalCount),不能保证在所有场景下均稳定执行成功删除后执行的代码,比如合同锁货反写货物行 货物行的删除,引用预合同新建合同场景等 —— 不再基于dataSet.totalCount,而是基于两次删除
  2. 勾选已保存的数据和新增的数据,一起删除时,dataSet.delete先删除新增的数据(一定成功),再删除已保存的数据(可能失败),导致删除的后续方法没有执行 —— 先删除已保存数据,再删除新增的数据
  3. 新增行数大于当前分页的大小时,再删除已保存的数据,会导致表格只会剩余<=10条的数据 —— 使用axios.delete + dataSet.remove来模拟dataSet.delete

一、勾选已保存的数据和新增的数据,一起删除时,dataSet.delete先删除新增的数据(一定成功),再删除已保存的数据(可能失败),导致删除的后续方法没有执行

前提:该表格有分页,且使用了dataSet.delete方法进行立即删除(后端删除);

1、问题描述 —— hzrl-0001-9894【销售合同】销售合同复制货物行未保存 删除复制的货物行价格构成行未同步删除

  • 勾选新增的行和已保存的行,进行后端删除,会使用dataSet.delete(selectedRecords)进行删除;
  • 但是这个猪齿鱼的方法,会先删除新增的行,删除成功后,再调用接口删除已保存的行,当删除失败后,会自动弹窗,并抛出异常,除非用catch捕获,后续联动代码不会执行;

2、解决方案

  1. 用catch来捕获报错,并同时进行后续的联动操作 —— 改动最小,但是还是会有下面的”问题四“;
  2. 基于两次删除来解决这个问题 —— 先删除已保存的数据,删除成功后再删除新增的数据,但是还是会有“问题四”;

3、注意事项

使用最新的comDelete,基于两次删除,同时也兼容了”问题四“;

二、新增行数大于当前分页的大小时,再删除已保存的数据,会导致表格只会剩余<=10条的数据

前提:该表格有分页,且使用了dataSet.delete方法进行立即删除(后端删除);

1、问题描述 —— hzrl-0001-10935【采购合同】采购合同导入后删除点击保存系统提示:明细行对应的uuid无效 —— 猪齿鱼组件问题

  • 当前表格存在已保存的数据,新增行,使得行数大于每页行数(10条),比如说12条;
  • 删除一条已经保存的数据,删除成功后,发现本应该剩余11条数据的表格,仅剩余10条数据;
  • 既不符合预期,也会导致表格联动有问题;

2、解决方案

使用axios.delete + dataSet.remove来模拟dataSet.delete

二、基本用法

import { comDelete } from '@common/utils/comMethod';

{
  type: 'delete',
  permissionList: {
    code: `${permissionCode}.button.delete1`,
    type: 'button',
    meaning: '按钮定义-删除',
  },
  condition: () => {
    /** 存在勾选数据为开单完成 */
    return !goodsInfoDS.selected.some((res: Record) => isCompleted(res) || isInitFlag(res));
  },
  handleSubmit: async () => {
    const { selected } = goodsInfoDS;
    /**
     * 通用删除
     * @param dataSet 需要删除的数据源
     * @param type 删除的类型 ‘delete/remove’
     * @param url 启用axios来模拟删除的接口,接口类型DELETE,不传则使用dataSet.delete进行删除
     * @param hideDeletedRecord 是否需要隐藏删除的行,默认隐藏
     * @param tip 删除之前的confirm弹窗提示语,默认“确认删除选中行?”
     */
    //* 如果是分页表格的删除,建议传入第三个参数(删除的url);
    const deleteSuccess = await comDelete(goodsInfoDS, 'delete');
    if (deleteSuccess) { //* 成功删除后,执行后续关联操作
      afterDelete(selected);
    }
  },
},

三、组件代码详情

文件路径:hzero-front/packages/ciec-front-common/src/utils/comMethod/index.tsx

/**
 * 通用删除
 * @param dataSet 需要删除的数据源
 * @param type 删除的类型 ‘delete/remove’
 * @param url 启用axios来模拟删除的接口,接口类型DELETE,不传则使用dataSet.delete进行删除
 * @param hideDeletedRecord 是否需要隐藏删除的行,默认隐藏
 * @param tip 删除之前的confirm弹窗提示语,默认“确认删除选中行?”
 */
const comDelete = async (
  dataSet: DataSet,
  type?: string,
  url?: string,
  hideDeletedRecord: boolean = true,
  tip?: string
) => {
  const { selected = []} = dataSet;
  if (!selected.length) {
    notification.warning({
      message: intl.get(`cice.common.massage.data.choice`).d('请先勾选数据'),
      description: intl.get(`cice.common.massage.data.choice`).d('请先勾选数据'),
    });
    return;
  }
  const btntype = await Modal.confirm({
    children: tip || intl.get(`cice.common.massage.data.confirmDelete`).d('确认删除选中行?'),
  });
  if (btntype === 'ok') { //* 点击确定
    if (type === 'remove') { //* 临时删除操作
      dataSet.remove(selected);
      return true;
    } else {
      const savedRecords :Record[] = []; //? 已经保存过的数据,需要调用接口删除
      const addedRecords :Record[] = []; //? 新增的数据,无需调用接口进行删除
      selected.forEach(selectedRecord => {
        if (selectedRecord.status !== 'add') { //* 已经保存的数据
          savedRecords.push(selectedRecord);
        } else {
          addedRecords.push(selectedRecord);
        }
      })
      if (url) { //* 使用axios进行删除
        try {
          //* 使用try-catch是因为如果这个接口调用抛异常,状态一直处于submitting,就无法继续操作了
          const json = savedRecords.map(record => record?.toData());
          dataSet.status = DataSetStatus.submitting;
          await axios.delete(url, { data: json }); //* 接口报错,将会抛出异常
          //* 通过remove来删除页面所有的数据
          selected.forEach((res: any) => {
            if (res.status !== 'add') {
              res.status = 'add';
            }
            dataSet.remove(res);
          });
          dataSet.status = DataSetStatus.ready;
          commonNotification('success', intl.get('cice.common.massage.submit.success').d('操作成功'));
          return true;
        } catch (error) {
          //@ts-ignore 接口抛错时,提示并重置数据源状态
          commonNotification('error', error.message || intl.get('cice.common.massage.notification.error').d('操作失败'));
          dataSet.status = DataSetStatus.ready;
          return false;
        }
      } //* 使用delete进行删除
      const resultDelete = await dataSet.delete(savedRecords, false); //* 先删除已经保存的数据
      dataSet.remove(addedRecords, false); //* 再删除新增的数据
      if (resultDelete && hideDeletedRecord) { //* 已有数据,调用接口,删除成功后,如果需要隐藏删除后的数据
        selected.forEach((res: any) => {
          if (res.status !== 'add') {
            res.status = 'add';
            dataSet.remove(res);
          }
        });
      }
      return true;
    }
  }
  //* 点击【取消】或者其他
  return false;
};

四、涉及场景

操作 —— dataSet.delete的行为 —— comDelete的行为

1、删除时,点击【取消】—— 不会走到delete —— 返回false,不执行删除成功后的关联操作

2、已有数据,删除失败 —— delete后不会继续执行 —— 没有返回,不执行删除成功后的关联操作

3、已有数据,删除成功 —— delete返回Object —— 返回true,执行删除成功后的关联操作

4、新增数据,删除成功,—— delete返回undefined —— 返回true,执行删除成功后的关联操作

5、新增数据,一般不会删除失败

6、新增数据和已有数据的删除失败 —— delete后不会继续执行 —— 没有返回,不执行删除成功后的关联操作

7、新增数据和已有数据的删除成功 —— delete返回Object —— 返回true,执行删除成功后的关联操作

五、使用注意事项

1、根据数据源delete删除方法的特性(新增数据和已有数据的删除,会先删除新增的数据,删除成功后再删除可能会删除失败的已保存的数据),该方法采用两次删除的方案,先删除已保存的数据,删除成功后再删除新增的数据;

2、dataSet.delete,删除已有数据后,如果失败,会弹窗提示并抛出异常,后续代码不会执行,但是会被catch捕获;

3、dataSet.delete自身的问题,新增行数大于当前分页的大小时,再删除已保存的数据,会导致表格只会剩余<=10条的数据,所以使用axios.delete + dataSet.remove来模拟dataSet.delete;使用comDelete传入第三个参数即可;

 类似资料: