react antdesign table表格有部分点击按钮可编辑并保存

192 阅读1分钟

举例一

  • 在table中 点击编辑,输入内容
  • 表格有总计。在第一行
  • 举例说明 第一周 第二周 第三周 第四周

子组件部分


interface Item {
  key: string,
  id: string;
  media_name: string;
  account_name: string;
  account_id: string;
  month: string;
  reference: string;
  total_budget: string;
  first_week: string;
  second_week: string;
  third_week: string;
  fourth_week: string;
  create_user: string;
  ctime: string;
  chang_user: string;
  change_time: string;
  is_edit: string;
}


interface TableParams {
  pagination?: TablePaginationConfig
  sortField?: string
  sortOrder?: string
  filters?: Record<string, FilterValue>
}
interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
  editing: boolean;
  dataIndex: string;
  editable: boolean;
  title: any;
  inputType: true | false;
  record: Item;
  children: React.ReactNode;
}

const EditableCell: React.FC<EditableCellProps> = ({
  editing,
  dataIndex,
  editable,
  title,
  inputType,
  record,
  children,
  ...restProps
}) => {
  // const inputNode = inputType == true ? <InputNumber /> : <Input />;
  const inputNode = inputType == true ? <Input /> : null;
  const formatAmountInput = (amount) => {
    if (amount == '--') {
      return '--'
    } else {
      return Number(amount).toLocaleString();
    }

  };


  const handeInputPrice = (e: any) => {
    // console.log('e', e.target.value)
    // isZero(e)、 
  }

  return (
    <td {...restProps}>
      {editing ? (
        <Form.Item
          name={dataIndex}
          style={{ margin: 0 }}
          rules={[
            {
              validator: (_, value) => {
                const numericValue = parseInt(value, 10);

                  if (!isNaN(numericValue) && numericValue >=0 && numericValue < 99999999) {
                    return Promise.resolve();
                  }
                  return Promise.reject(new Error("请输入大于等于0的且小于99999999的整数"));
              },
            },
          ]}
        >
          <InputNumber
            formatter={value => formatAmountInput(value)}
            parser={value => parseFloat(value.replace(/\$\s?|(,*)/g, ''))}
            controls={false}
            style={{ width: '100%' }} onBlur={handeInputPrice} />
        </Form.Item>
      ) : (
        children
      )}
    </td>
  );
};
type EditableTableProps = Parameters<typeof Table>[0];
type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
let parent_params = {}


columns 部分


操作的方法部分
  //点击保存按钮 保存当前条
  const save = async (record: any) => {
    try {
      const row = (await form.validateFields()) as Item;

      const newData = [...tableData];
      const index = newData.findIndex(item => record.id === item.id);
      if (index > -1) {
        const item = newData[index];
        console.log(item, '===item===')
        // 修改4周的值,并计算预算合计总值
        let edit_first_week = item.first_week && item.first_week != '--' ? Number(item.first_week) : 0
        let edit_second_week = item.second_week && item.second_week != '--' ? Number(item.second_week) : 0
        let edit_third_week = item.third_week && item.third_week != '--' ? Number(item.third_week) : 0
        let edit_fourth_week = item.fourth_week && item.fourth_week != '--' ? Number(item.fourth_week) : 0
        //输入的特殊值做兼容。 也可不用
        const modifiedItem = {
          ...item,
          first_week: edit_first_week,
          second_week: edit_second_week,
          third_week: edit_third_week,
          fourth_week: edit_fourth_week,

        };

        // 处理修改后的值, 个位进位取整
        let up_first_week = upNumber(row.first_week)
        let up_second_week = upNumber(row.second_week)
        let up_third_week = upNumber(row.third_week)
        let up_fourth_week = upNumber(row.fourth_week)

        // 当前修改后的值 替换修改前的值
        const rowItemObj = {
          ...row,
          first_week: up_first_week.toString(),
          second_week: up_second_week.toString(),
          third_week: up_third_week.toString(),
          fourth_week: up_fourth_week.toString(),
        }
       
        //预算合计
        let result_total_budget = Number(up_first_week) + Number(up_second_week) + Number(up_third_week) + Number(up_fourth_week)
        const totalobj = {
          total_budget: result_total_budget.toString()
        }

        //合并全部修改 ,进位,合计的值。
        newData.splice(index, 1, {
          ...modifiedItem,
          ...rowItemObj,
          ...totalobj
        });
        // 保存到 提交参数 , 带id
        const rowIdObj ={
          ...rowItemObj,
          id:item.id
        }
        console.log(row, '===row===', rowItemObj,rowIdObj)
        console.log(newData, '==newData==')
        if (result_total_budget !== 0) {
          runSave(rowIdObj).then((res:any)=>{
            console.log(res, '====')
            if(res.error_code!=0) {
              return 
            }
            setTableData(newData);
            setEditingKey('');
            console.log('提交成功')
          })
        } else {
          message.error('预测金额之和不能为0');
        }
  
      
      } else {
        newData.push(row);
        setTableData(newData);
        setEditingKey('');
      }
    } catch (errInfo) {
      console.log('Validate Failed:', errInfo);
    }
  };

 const defaultColumns: (ColumnTypes[number] & { editable?: boolean; dataIndex: string })[] = [
    {
      title: '序号',
      dataIndex: 'id',
      key: 'id',
      width: 60,
      fixed: 'left',
      render: (text, record, index) => {
        return index + 1
      }
    },
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
      width: 100,
      editable: false,
      render: (text) => (
        <Tooltip placement="topLeft" title={text}>
          {text ? text : '--'}
        </Tooltip>
      ),
    },
  
    {
      title: '预算合计',
      dataIndex: 'total_budget',
      key: 'total_budget',
      width: 150,
      editable: false,
      align:'right',
      render: (text) => (
        <Tooltip placement="topLeft" title={formatAmount(text)}>
          {formatAmount(text)}
        </Tooltip>
      ),
    },
    {
      title: '第一周',
      dataIndex: 'first_week',
      key: 'first_week',
      width: 150,
      editable: true,
      align:'right',
      render: (text) => (
        <Tooltip placement="topLeft" title={formatAmount(text)}>
          {formatAmount(text)}
        </Tooltip>
      ),
    },
    {
      title: '第二周',
      dataIndex: 'second_week',
      key: 'second_week',
      width: 150,
      editable: true,
      align:'right',
      render: (text) => (
        <Tooltip placement="topLeft" title={formatAmount(text)}>
        {formatAmount(text)}
      </Tooltip>
      ),
    },
    {
      title: '第三周',
      dataIndex: 'third_week',
      key: 'third_week',
      width: 150,
      editable: true,
      align:'right',
      render: (text) => (
        <Tooltip placement="topLeft" title={formatAmount(text)}>
          {formatAmount(text)}
        </Tooltip>
      ),
    },
    {
      title: '第四周',
      dataIndex: 'fourth_week',
      key: 'fourth_week',
      width: 150,
      editable: true,
      align:'right',
      render: (text) => (
        <Tooltip placement="topLeft" title={formatAmount(text)}>
        {formatAmount(text)}
      </Tooltip>
      ),
    },
   
    {
      title: '操作',
      dataIndex: 'action',
      key: 'action',
      fixed: 'right',
      width: 100,
      render: (_: any, record: Item,) => {
        const editable = isEditing(record);
        return record.is_edit == '1' ? (
          editable ? (
            <span>
              <Typography.Link onClick={() => save(record)} style={{ marginRight: 8 }}>
                保存
              </Typography.Link>
              <Popconfirm title="确定取消保存吗?" onConfirm={cancel}>
                <a>取消</a>
              </Popconfirm>
            </span>
          ) : (
            <Typography.Link disabled={editingKey !== ''} onClick={() => edit(record)}>
              编辑
            </Typography.Link>
          )
        ) : (<span><Typography.Link disabled >
        编辑2
      </Typography.Link></span>)
      },
    },
  ];

table部分



  <Form form={form} component={false}>
        <Table
          components={{
            body: {
              cell: EditableCell,
            },
          }}
          bordered
          loading={loading}
          size="small"
          sticky={{ offsetHeader: 50 }}
          scroll={{ x: 1200 }}
          dataSource={tableData}
          columns={mergedColumns as ColumnTypes}
          rowKey="id"
          rowClassName="editable-row"
          pagination={tableParams.pagination}
          summary={(pageData) => {
            let t_total_budget = 0;
            let t_first_week = 0;
            let t_second_week = 0;
            let t_third_week = 0;
            let t_fourth_week = 0;
            pageData.forEach(({ total_budget, first_week, second_week, third_week, fourth_week }: any) => {
              if (total_budget != '--') {
                t_total_budget += Number(total_budget)
              }
              if (first_week != '--') {
                t_first_week += Number(first_week)
              }
              if (second_week != '--') {
                t_second_week += Number(second_week)
              }
              if (third_week != '--') {
                t_third_week += Number(third_week)
              }
              if (fourth_week != '--') {
                t_fourth_week += Number(fourth_week)
              }

            })
            return (
              <Table.Summary fixed="top">
                <Table.Summary.Row>
                  {
                    mergedColumns.map((item: any, index: number,) => {
                      let document_flag: any = ''
                      if (item.key == 'id') {
                        document_flag = (<Table.Summary.Cell key={item.key} index={index}>总计</Table.Summary.Cell>)
                      } else if (item.key == 'total_budget') {
                        document_flag = (<Table.Summary.Cell align="right" key={item.key} index={index}>{formatAmount(t_total_budget)}</Table.Summary.Cell>)
                      } else if (item.key == 'first_week') {
                        document_flag = (<Table.Summary.Cell align="right"  key={item.key} index={index}>{formatAmount(t_first_week)}</Table.Summary.Cell>)
                      }
                      else if (item.key == 'second_week') {
                        document_flag = (<Table.Summary.Cell align="right"  key={item.key} index={index}>{formatAmount(t_second_week)}</Table.Summary.Cell>)
                      }
                      else if (item.key == 'third_week') {
                        document_flag = (<Table.Summary.Cell align="right" key={item.key} index={index}>{formatAmount(t_third_week)}</Table.Summary.Cell>)
                      }
                      else if (item.key == 'fourth_week') {
                        document_flag = (<Table.Summary.Cell align="right" key={item.key} index={index}>{formatAmount(t_fourth_week)}</Table.Summary.Cell>)
                      }
                      else {
                        document_flag = (<Table.Summary.Cell key={item.key} index={index}></Table.Summary.Cell>)
                      }
                      return document_flag
                    })
                  }
                </Table.Summary.Row>
              </Table.Summary>
            )
          }}
        />
      </Form>

分页设置部分

初始化

  const [tableParams, setTableParams] = useState<TableParams>({
    pagination: {
      current: 1,
      showSizeChanger: true,
      defaultCurrent: 1,
      defaultPageSize: 100,
      pageSizeOptions: [100, 200, 500, 1000],
      onChange: function () {
        window.scrollTo(0, 0)
      },
      showTotal: (total) => `共 ${total} 条`,
    },
  })
  

设置

   setTableParams({
        ...tableParams,
        pagination: {
          ...tableParams.pagination,
          pageSizeOptions:data.page.pageSizeMap,
          pageSize:data.page.pageSize,
          current: data.page.pageNum,
          total: data.page.totalCnt,
          showTotal: (total) => `共 ${total} 条`,
        },
      })