react antd table组件的删除和移动排序实现逻辑

自定义实现排序按钮和删除按钮,当点了save按钮才是真正的保存成功。

table组件处的代码

<Table
  bordered={true}
  rowKey={'id'}
  columns={getColumns}
  dataSource={_.sortBy(_.filter(dataSource||[], item=>item.typeN !== 'delete'), ['sort'])}
  pagination={{
    current:pageNum,
    total:totalData?.length,
    hideOnSinglePage:false,
    showSizeChanger:true,
    onChange:pageNo=>{setPageNum(pageNo)},
    showTotal: showTotal=>`Total ${showTotal} data`,
    onShowSizeChange:current=>{
      setPageSize(current.size);
      setPageNum(current.current);
    },
  }}
/>

先来看一下dataSource大致有哪些数据

表格信息处的代码

const getColumns =()=>{
  const columnData = _.get(modelData, 'column'); //modelData是redux存下来的数据
  const data = _.filter(dataSource, item=>item.typeN !== 'delete');
  const maxSort = _.get(_.maxBy(data, 'sort'), 'sort') || data.length;
  const minSort = _.get(_.minBy(data, 'sort'), 'sort') || 1;
  let columns = [];
  if(!_.isEmpty(columnData)){
    columns = _.map(columnData, key=>({
      title: key.columnEn,
      dataIndex: key.propertyName,
      render: (value, record)=>{
        const {type} = key;
        if(type === 'input'){
          if(key.propertyName === 'fieldFormulaApproval'){ // 这里是groove编辑脚本
            return (
              <div className={styles.field}>
                <Input
                  id={`${record.id}_${key.propertyName}`}
                  value={value} 
                  disabled={true}
                  maxLengrh={50}
                />
                <span
                  className={styles.fieldBtn}
                  onClick={()=>handleClickEditFormulaButton(key,record)}
                >
                  ...
                </span>
              </div>
            );
          }
          return (
            <Input
              id={`${record.id}_${key.propertyName}`}
              value={value}
              maxLengrh={50}
              onChange={(e)=>handleChangeField({key, value: e.target.value},record)}
            />
          )
        }
        return value;
      },
    }));
  }
  columns.push({
    title: 'Operation',
    width: '15%',
    render: record=>(
      <div>
        <span
          style={{
            paddingRight: 12,
            color: '#255FF2',
          }}
          onClick={()=>handleRemoveField(record)}
          title={'Delete'}
        >
          <DeleteOutlined />
        </span>
        <span
          style={{
            pointerEvents: record.sort === minSort ? 'none' : 'auto',
            cursor: record.sort === minSort ? 'not-allowed' : 'pointer',
            paddingRight: 12,
            color: record.sort === minSort ? '#ddd' : '#255FF2',
          }}
          onClick={()=>handleMoveField(record, 'up')}
          title={'Up'}
        >
          <UpCircleOutlined />
        </span>
        <span
          style={{
            pointerEvents: record.sort === maxSort ? 'none' : 'auto',
            cursor: record.sort === maxSort ? 'not-allowed' : 'pointer',
            color: record.sort === maxSort ? '#ddd' : '#255FF2',
          }}
          onClick={()=>handleMoveField(record, 'down')}
          title={'Down'}
        >
          <DownCircleOutlined />
        </span>
      </div>
    ),
  });
  return columns;
}

表格删除处的代码

const handleRemoveField =(record)=>{
  if(_.find(dataSource, item=>String(item.id).tirm() === String(record.id).tirm())){
    // 删除的数据都拼上typeN作标记
    setDataSource(_.filter(dataSource, item=>String(item.id).tirm() !== String(record.id).tirm()).concat({...record, typeN: 'delete'}))
  }else{
    setDataSource(_.filter(dataSource, item=>String(item.id).tirm() !== String(record.id).tirm()))
  }
}

判断表格内的Input输入框是否变化,变化的话type就要变成update

const handleChangeField =(params, record)=>{
  // 找到修改当条数据的id index
  const fieldIndex = _.findIndex(dataSource, item=>String(item.id).trim() === String(record.id).trim());
  const newFieldData = {
    ...record,
    [params.key.propertyName]: params.value,
    type: record.type || 'update',
    // blockly生成的xml给后端,需要回显
    ...(params.xmlText ? {[`${params.key.propertyName}Xml`]: params.xmlText} : {})
  }
  setDataSource(dataSource.slice(0, fieldIndex).concat(newFieldData).concat(dataSource.slice(fieldIndex + 1)))
}

移动按钮(上,下)的实现逻辑

import helperByOpsexcel from '../../config/helper'

const handleMoveField = (record, moveDirection)=>{
  // 过滤出typeN为delete的数据
  const deletedData = _.filter(dataSource || [], item=>item.typeN === 'delete');
  // 过滤出typeN不为delete的数据(需要处理移动的数据)
  const data = _.filter(dataSource || [], item=>item.typeN !== 'delete');
  let newData = [];
  // 找到当条移动的数据的index
  const current = _.findIndex(data, item=>String(item.id).trim() === String(record.id).trim());
  //对数据进行分组
  const groupBygroup = _.groupBy(data, o=>o.group);
  if(current > -1){
    // 向下移动的处理
    if(moveDirection === 'down'){
      const nextIndex = _.findIndex(data, (item, index)=>index > current);
      const nextGroup = _.get(_.find(data, o=>o.flag === nextIndex), 'group');
      const sortData = _.orderBy(data, 'sort', 'asc');
      _.each(data, (item,index)=>{
        if(index === current && ((!item.group && !nextGroup) || item.group === nextGroup )){
          // 点击的和下一条是同级的情况(目前项目只需要用到这一种情况即可)
          newData = helperByOpsexcel.getPeersMoveData(sortData, item, nextIndex);
        }else if(index === current && !item.group && nextGroup){
          //点击的是没有group的,下一条是有group的情况
          const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, nextGroup);
          newData = helperByOpsexcel.getAfterMoveData(sortData, groupLength, item, nextIndex, nextGroup);
        }else if(index === current && item.group && !nextGroup){
          //点击的是有group的,下一条是没有group的情况
          const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
          newData = helperByOpsexcel.getAfterMoveData(sortData, groupLength, item, nextIndex);
        }else if(index === current && item.group && nextGroup && item.group !== nextGroup){
          //当前点击的和下一条点击的都有group并且group不同
          const currentGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
          const nextGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, nextGroup);
          newData = helperByOpsexcel.getAfterMoveData(sortData, currentGroupLength, item, nextIndex, nextGroup, nextGroupLength);
        }
      });
    }else if(moveDirection === 'up'){
      // 向上移动的处理
      const prevIndex = _.findLastIndex(data, (item, index)=> index < current);
      const prevGroup = _.get(_.find(data, o=>o.flag === prevIndex), 'group');
      const sortData = _.orderBy(data, 'sort', 'asc');
      _.each(data, (item,index)=>{
        if(index === current && ((!item.group && !prevGroup) || item.group === prevGroup)){
          // 点击的和上一条是同级的情况(目前项目只需要用到这一种情况即可)
          newData = helperByOpsexcel.getPeersMoveData(sortData, item, prevIndex, 'up');
        }else if(index === current && !item.group && prevGroup){
          //点击的是没有group的,上一条是有group的情况
          const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, prevGroup);
          newData = helperByOpsexcel.getUpAfterMoveData(sortData, groupLength, item, prevIndex, prevGroup);
        }else if(index === current && item.group && !prevGroup){
          //点击的是有group的,上一条是没有group的情况
          const groupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
          newData = helperByOpsexcel.getUpAfterMoveData(sortData, groupLength, item, prevIndex);
        }else if(index === current && item.group && prevGroup && item.group !== prevGroup){
          //当前点击的和上一条点击的都有group并且group不同
          const currentGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, item.group);
          const prevGroupLength = helperByOpsexcel.getLengthByGroup(groupBygroup, prevGroup);
          newData = helperByOpsexcel.getUpAfterMoveData(sortData, currentGroupLength, item, index, prevGroup, prevGroupLength);
        }
      });
    }
  setDataSource(_.sortBy(newData, ['sort']).concat(deletedData));
  }
}

上面用到的一些方法是封装过的

import _ from 'lodash';

const helper = {
  //获取平级的移动数据
  getPeersMoveData(data, item, Index, direction){
    return _.map(data, (o, i)=>{
        if(o.id === item.id){
          // 点中的当条数据的sort变化
          return {...o, sort: _.get(data, `[${Index}].sort`), type: o.type ? o.type : 'update'}
        }
        if(i === Index){
          // 点中的当条的上(下)一条数据的sort变化
          return {...o, sort: item.sort, type: o.type ? o.type : 'update'}
        }
        return o;
      })
  }

  // 获取点击数据有group的长度
  getLengthByGroup(groupBygroup, group){
    let groupLength;
    for(const key in groupBygroup){
      if(key === group){
        groupLength = groupBygroup[key].length;
      }
    }
    return groupLength;
  }
}

脚本编辑框的一些代码

新增一条数据需要造一条空的数据

const handleAddField = () =>{
  const newData = {
    type: 'add',
    id: new Date().getTime(), // 新增多个如果不加id填值会跟着一起变化
    sort: (_.get(_.maxBy(_.filter(dataSource, item=>item.typeN !== 'delete'), 'sort'), 'sort') || 0) + 1,
    // ...  需要传给后端的字段
    isAdd: true, // 判断是否是新增,如果是,在调接口的时去掉新增时的id
  }
  if(typeof dataSource === 'undefined'){
    setDataSource([newData])
  }else{
    setDataSource([...dataSource, newData])
  }
  //新增时跳到最后一页
  const currentPage = Math.ceil((modelData?.length + 1) / pageSize) || 1;
  setPageNum(currentPage);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值