可编辑Table列表,根据antd案列修改

772 阅读2分钟

需求:要求点击按钮增加一行,增加的一行部分字段可以设置初始值,剩余未填写的字段空白,可以手动输入,也可以点击地图获取坐标后自动填入,还可以根据选择某一个列表的数据,选择完成后自动合并。

分析:所有的操作都是对目标列表的数据源的修改,本质是维护一个数组。将数据源放在全局里,每次修改都修改全局的状态,取值也是全局的状态,便于数据通信。

    import React, { useContext, useEffect, useRef, useState } from 'react';
    import styles from './index.less';
    import { Button, Form, Input, Popconfirm, Table } from 'antd';
    import { useSelector, useDispatch } from 'umi';
    import { PlusOutlined } from '@ant-design/icons';

    const EditableContext = React.createContext(null);

    //------------
    const EditableRow = ({ index, ...props }) => {
      const [form] = Form.useForm();
      return (
        <Form form={form} component={false}>
          <EditableContext.Provider value={form}>
            <tr {...props} />
          </EditableContext.Provider>
        </Form>
      );
    };

    const EditableCell = ({
      title,
      editable,
      children,
      dataIndex,
      record,
      handleSave,
      ...restProps
    }) => {
      const [editing, setEditing] = useState(false);
      const inputRef = useRef(null);
      const form = useContext(EditableContext);
      useEffect(() => {
        if (editing) {
          inputRef.current.focus();
        }
      }, [editing]);

      // 编辑开关
      const toggleEdit = () => {
        setEditing(!editing);
        form.setFieldsValue({
          [dataIndex]: record[dataIndex],
        });
      };

      // 保存编辑后的状态
      const save = async () => {
        try {
          const values = await form.validateFields();
          toggleEdit();
          handleSave({ ...record, ...values });
        } catch (errInfo) {
          console.log('Save failed:', errInfo);
        }
      };

      let childNode = children;

      if (editable) {
        childNode = editing ? (
          <Form.Item
            style={{
              margin: 0,
            }}
            name={dataIndex}
            // rules={[
            //   {
            //     required: true,
            //     message: `${title} is required.`,
            //   },
            // ]}
          >
            <Input ref={inputRef} onPressEnter={save} onBlur={save} style={{width: '100px',height: '38px'}}/>
          </Form.Item>
        ) : (
          <div
            className="editable-cell-value-wrap"
            style={{
              // paddingRight: 24,
            }}
            onClick={toggleEdit}
          >
            {children}
          </div>
        );
      }

      return <td {...restProps}>{childNode}</td>;
    };

    const LastTable = () => {
      const dispatch = useDispatch();
      const baseLast = useSelector((state) => state.addPath.baseLast);
      const baseLastTable = useSelector((state) => state.addPath.baseLastTable)
      console.log(baseLast,'baseLast')



      // ----------- antd

      const saveTableData = (data) => {
        dispatch({
          type: 'addPath/saveBaseLastTable',
          payload: data,
        });
      }
      
      // 这里是判断坐标选点后,并且判断列表的最后一行的值为空,将数据合并
      // 当用户添加多行后才进行选点操作,判断最后一行为空,有bug,需要使用遍历,当遍历到目标值为空就进行合并操作
      useEffect(() => {
        if(baseLastTable.length !=0 && baseLastTable[baseLastTable.length-1].lastLa =='') {
          let transData = JSON.parse(JSON.stringify(baseLastTable))
          transData[transData.length-1].lastLa=baseLast.lastLa
          transData[transData.length-1].lastLg=baseLast.lastLg
          saveTableData(transData)
        }
      },[baseLast])

      const handleDelete = (key) => {
        const newData = baseLastTable.filter((item) => item.key !== key);
        saveTableData(newData)
      };

      const defaultColumns = [
        {
          title: '序号',
          dataIndex: 'order',
          width:'50px'
        },
        {
          title: '阵地名称',
          dataIndex: 'name',
          // editable: true, // 编辑开关
          width:'100px'
        },
        {
          title: '经度',
          dataIndex: 'lastLg',
          // editable: true,
        },
        {
          title: '纬度',
          dataIndex: 'lastLa',
          // editable: true,
        },
        {
          title: '操作',
          dataIndex: 'operation',
          render: (_, record) =>
          baseLastTable.length >= 1 ? (
              <Popconfirm
                title="是否确认删除?"
                onConfirm={() => handleDelete(record.key)}
              >
                <a>删除</a>
              </Popconfirm>
            ) : null,
        },
      ];

      const handleAdd = (type) => {
        const newData = {
          key: baseLastTable.length+1,
          order: baseLastTable.length+1,
          name:'输入',
          lastLg: '',
          lastLa: '',
        };
        saveTableData([...baseLastTable, newData])
        dispatch({
          type: 'addPath/saveIfShow',
          payload: type,
        });
      };
      // 更新数据源
      const handleSave = (row) => {
        const newData = [...baseLastTable];
        const index = newData.findIndex((item) => row.key === item.key);
        const item = newData[index];
        newData.splice(index, 1, { ...item, ...row });
        saveTableData(newData)
      };
      
      // 传给table
      const components = {
        body: {
          row: EditableRow,
          cell: EditableCell,
        },
      };
      const columns = defaultColumns.map((col) => {
        if (!col.editable) {
          return col;
        }

        return {
          ...col,
          onCell: (record) => ({
            record,
            editable: col.editable,
            dataIndex: col.dataIndex,
            title: col.title,
            handleSave,
          }),
        };
      });

      return (
        <div className={styles.timeTable}>
          <div className={styles.startBox}>
            <div className={styles.start}>终点</div>
            {/* <div className={styles.icon} onClick={ () =>  handleAdd('last')}>
              <PlusOutlined/>
            </div> */}
          </div>
          <Table
            components={components}
            rowClassName={() => 'editable-row'}
            bordered
            dataSource={baseLastTable}
            columns={columns}
            pagination={false}
          />
        </div>
      );
    };

    export default LastTable;

这里只写了动态添加行,和坐标选取后的操作。在某一列表选取数据后,只需要合并数据源dispatch到全局状态即可。