react+antd的Table组件编辑单元格

需求:新增加一行,且单元格可以编辑

场景:真实的业务需求(antd 3 版本+react)

效果图:1. 默认增加一行时,第一列是下拉选择框,第2 3列是TextArea,图1

               2. 当下拉选择的数据不同,展示出的第4567列也不同

               3. 有直接调接口默认回显数据、有Input输入框形式(当增加一行新的,默认显示图片2的效果。当选择了“纸质普票”,这一行就变成图3 的效果。当选择“纸质普票”以外的选项,又会变成图2 的形式。“纸质普票”比较特殊)。

               4.  编辑好当前行,不保存无法再新增一行

代码仅供参考,里面涉及的业务逻辑可以忽略,可以看主要内容

图1:

图2:

图3:

图4:

图5:

 完整代码:

// 父级
import EditableFormTable from './EditableFormTable' // 子级

class Editable extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      IsFPLX: '', // 发票类型
      value: [], // 
      disabled: false, // 控制表格的是否可以新增一行
      zyfp: [
        {key:'纸质普票', label:'纸质普票'},
        {key:'纸质专票', label:'纸质专票'},
        {key:'电子专用发票', label:'电子专用发票'},
        {key:'数电专票', label:'数电专票'}  
       ]
    
  
  render() {
    const { value, IsFPLX, disabled, zyfp } = this.state;
    const propsObj = {
      IsFPLX,
      value,
      onChange: (value) => {
        const values = value   
        this.props.onChange([...value]) // 这块是我这表单平台专有的方法,你那可能不适用。这里做更显数据的
      }
      disabled,
      zyfp,
      
    };
    return (
      <div>
        <EditableFormTable {...propsObj} />     
      </div>
    );
  }
}

export default Editable

2.

import { Table, Input, Button, Popconfirm, Form,  } from 'antd';
const EditableContext = React.createContext();

const { TextArea } = Input
const Option = Select.Option

// 子级中的单个单元格
class EditableCell extends React.Component {
    constructor(props) {
    super(props);
    this.state={
     };
  
    //
    handleChange = (e, form) => {
        const { value, record } = this.props;
        if(e === '纸质普票'){
            this.props.changeSelectFlag(3) // 发票代码字段不用非要输入
        } else if (e === '数电专票'){
            this.props.changeSelectFlag(1) // 发票代码字段置灰,不可输入
        } else {
            this.props.changeSelectFlag(0) // 发票代码字段是否输入不作校验
        }
    }
    
    //
    getInput = (form, record) => {
        const type = this.props.inputType()
        const flag = this.props.IsFPLX
        const optionList = this.props.zyfp
        const selectView = optionList && optionList[0] && optionList.map(item => { return (<Option value={item.key}>{item.label}</Option>)})
        let view = null
        if(record.fplx !== '纸质普票'){
            switch(type){
                case 'select':
                    view=(<Select style={{ width: '100%'}} onSelect={this.handleChange(e, form)}>{selectView}</Select>)
                    break;
                case 'TextArea1':
                    view=this.props.selectFlag===1? (<fragment style={{background: this.props.selectFlag===1 ? '#f5f5f5': ''}}><TextArea autoSize disabled={this.props.selectFlag ===1} /></fragment>) : <TextArea autoSize disabled={this.props.selectFlag ===1} onChange={value => this.props.onbillnumChange(value)} />
                    break;
                case 'TextArea2':
                    view = <TextArea autoSize disabled={this.props.selectFlag ===1} onChange={value => this.props.onbillnumChange(value)} />
                    break;
                defalut:
                    view=<Input />
                    break;
            }
        } else {
            switch(type){
                case 'select':
                    view=(<Select style={{ width: '100%'}} onSelect={this.handleChange(e, form)}>{selectView}</Select>)
                    break;
                case 'TextArea1':
                    view=<TextArea autoSize />
                    break;
                case 'TextArea2':
                    view=<TextArea autoSize />
                    break;
                case 'InputNumber3':
                    view=<TextArea autoSize />
                    break;
                case 'InputNumber4':
                    view=<TextArea autoSize />
                    break;
                case 'InputNumber5':
                    view=<TextArea autoSize />
                    break;
                case 'InputNumber6':
                    view=<TextArea autoSize />
                    break;
                default:
                    view=<Input />
                    break;
            }
        }
        return type
    }

    renderCell = (form) => {
        const { editing, dataIndex, title, inputType, record, index, children, onbillnumChange, selectFlag, ...restPropr} = this.proops
        return (
            td {...restProps}>
                {editable ? (
                  <Form.Item>{form.getFieldDecorator(dataIndex, {
                    rules:[] // 注意:这里写规则校验,getInput方法里校验就失效
                    initialValue: record[dataIndex],
                })(this.getInput(form, record))}</Form.Item>
            ) : (
              children
            )}
          </td>        
        )
    }

    render() {
        return <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
    }
}






// 子级页面
class EditableFormTable extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      IsFPLX: '', // 发票类型
      value: [], // 
      editingKey: '', // index,标记当前这条数据正在编辑
      selectFlag: 0, // 0:可编辑状态,这个字段控制当下拉选项为“数电专票”时,发票代码字段不可编辑
     };
     this.columns = [
      {
        title: '发票类型',
        dataIndex: 'fplx',
        width: '10%',
        align: 'center',
        editable: true,
        render: (text, record, index) => {
            const { zyfp =[], IsFPLX=''} = this.props;
            return <span>{text}</span>
        }
      },
      {
        title: '发票代码',
        dataIndex: 'billcode',
        width: '10%',
        align: 'center',
        editable: true,
      },
      {
        title: '发票号码',
        dataIndex: 'billnum',
        width: '10%',
        align: 'center',
        editable: true,
       },
       {
          title: '价税合计金额',
          dataIndex: 'je',
          width: '8%',
          align: 'center',
          editable: true,
        },
       {
          title: '增值税额',
          dataIndex: 'se',
          width: '8%',
          align: 'center',
          editable: true,
        },
        {
          title: '未匹配价税合计金额',
          dataIndex: 'dppje',
          width: '8%',
          align: 'center',
          editable: true,
        },
        {
          title: '未匹配税额',
          dataIndex: 'dppse',
          width: '8%',
          align: 'center',
          editable: true,
        },
        {
          title: '核验结果',
          dataIndex: 'result',
          width: '20%',
          align: 'center',
          editable: true,
        },
    ];

   }

    componentWillMount () {
        if(!this.props.disabled){
            this.columns.push({
                title: '操作',
                dataIndex: 'operation',
                width: '15%',
                align: 'center',
                render: (text, record, index) => {
                    const editable = this.isEditing(index)
                    return editable ? (
                        <span>
                            <EditableContext.Consumer>
                                { form => (
                                      <div>
                                        <a onClick={() => this.save(form, index)} style={{ marginRight:8 }}>保存</a>
                                        <a onClick={() => this.deleteFun(form, index)} style={{ color: 'red', marginLeft:'15px' }}>删除</a>
                                      </div>
                                  )}
                            </EditableContext.Consumer>
                        </span>
                    ) : (
                        <div>
                             <a onClick={() => this.edit(index)} disabled={editingKey !==''}>编辑</a>
                              <a onClick={() => this.deleteFun(form, index)} disabled={editingKey !=='' style={{ color: editingKey !== '' ? '' : 'red', marginLeft:'15px' }}>删除</a>
                         </div>
                    )
                }
            })
        }
    }
    
     // 添加一行
    addTableFun = () => {
        this.changeSelectFlag(0) // 还原最初编辑状态 
        if(this.state.editingKey !== ''){
            return alert('请先保存当前行信息')
        }
        const valueList = this.state.value
        valueList.push({
            fplx: '',
            billcode: '',
            billnum: '',
            je: '',
            se: '',
            dppje: '',
            dppse: '',
            result: '',
            editFlag: true, // 新增一行,带个标识(当新增一行点保存后又想编辑,如何识别点击编辑按钮这行就能编辑呢,就通过这个标识)意味着这行正处在可输入状态中
        })
        this.setState({
            value: valueList,
            editingKey: this.state.value.length-1 // 新增的这行的索引
        })
        this.props.onChange(valueList) // 更新表格数据
    }

    // 
        changeSelectFlag = (selectFlag) => {
            this.setState({
                selectFlag,
            })
        }

    // 当更改发票号码、发票代码、发票类型时
    onbillnumChange = (value) => {
        this.props.form.validateFields((error, row) => {
            if(error){
                return;
            }
            if((row && row.fplx !== '纸质普票') || (value && value,fplx !== '纸质普票')){
                if(value && value.isFetch === 0){
                    const obj = { billnum: value.billnum, fplx, billcode}
                    const requestParams = {
                        "paramsObject": {
                              "vatInvaiceList": [obj],
                          },
                         "userId": window.params.userId,
                         "sysId": window.params.sysId,
                    };
                    const that = this
                    // 调接口
                    window.$.ajax({
                        type: "POST",
                        url: '',
                        contentType: "application/json",
                        data: JSON.stringify(requestParams),
                        dataType: "json",
                        success(data) {
                            if(data.resultData){
                                const { editingKey } = this.state;
                                const valueList = this.state.value
                                 valueList[editingKey].billcode = data.resultData[0].billcode
                                valueList[editingKey].billnum = data.resultData[0].billnum
                                valueList[editingKey].je = data.resultData[0].je
                                valueList[editingKey].se = data.resultData[0].se
                                valueList[editingKey].dppje = data.resultData[0].dppje
                                valueList[editingKey].dppse = data.resultData[0].dppse
                                valueList[editingKey].journalNum = data.resultData[0].journalNum
                                valueList[editingKey].result = ''
                                valueList[editingKey].id = data.resultData[0].id
                                valueList[editingKey].vatInvoceId = new Date().getTime()
                                that.props.onChange(valueList)
                                that.setState({
                                    value: valueList,
                                })
                            } else {
                                alert('获取增值税发票信息失败!')
                            }
                        }
                    })
                }
            } else{
                const that = this
                const { editingKey } = this.state;
                const valueList = this.state.value
                valueList[editingKey].vatInvoceId = new Date().getTime() // 创造唯一id
                valueList[editingKey].fplx = row && row.fplx ? row.fplx : ''
                that.props.onChange(valueList)

            }
        })
        return value
    }

    //
    ChangeVal = (val) => {
         this.setState({ value: val })
    }

    // 编辑
    edit = (key) => {
        const valueList = this.state.value
        if(valueList[key] !== '纸质普票'){
            this.onbillnumChange({
                billcode: valueList && valueList[key] && valueList[key].billcode,
                billnum: valueList && valueList[key] && valueList[key].billnum,
                fplx: valueList && valueList[key] && valueList[key].fplx,
                isFetch: 1, // 编辑标识
            })
            this.setState({ editingKey: key })
            
        } else {
           valueList[key].editFlag = true,
           this.setState({
               value: valueList,
                editingKey: key,
           }) 
        }
    }

    // 编辑的索引
    isEditing = (index) => {
        return index === this.state.editingKey
    }

    // 删除
    deleteFun = (index) => {
        const valueList = this.state.value
        valueList.splice(index, 1)
        this.setState({
            value: valueList,
            editingKey: '',
        })
        this.props.onChange(valueList)
    }

    // 保存
    save = (form, index) => {
        form.validateFields((error, row) => {
            if(error){ return;}
            if(!row.fplx){
                alert('请选择发票类型!')
            } else {
                const newData = JSON.parse(JSON.stringify(this.state.value)) // 用个深拷贝,防止嵌套表格里的数据拿不到
                if(index >-1){ // 索引不等于-1,说明表格最少有一条数据
                    const item = newData[index]
                    newData.splice(index, 1, {  // splice有三个参数时,splice方法功能:替换
                        ...item,
                        ...row,
                        editFlag: false,
                    })
                    this.props.onChange(JSON.parse(JSON.stringify(newData)))
                    this.setState({
                        value: newData,
                        editingKey: '',
                    })
                } else { // 对第一次新增数据进行保存
                    newData.push(row)
                    this.props.onChange(JSON.parse(JSON.stringify(newData)))
                    this.setState({
                        value: newData,
                        editingKey: '',
                    })
                }
            }
        })
    }

  render() {
    const { value, IsFPLX, zyfp } = this.state;
    const components = {
        body: {
          cell: EditableCell, // 在最上面,可以看成一个组件
      },
    };
    
     const columns = this.columns.map(col => {
      if (!col.editable) {
        return col;
      }
      return {
        ...col,
        onCell: (record,index) => {
           return {
                // 下面这一块操作另外一个作用是传值,把值和方法传给<EditableCell />这个组件使用
               record,
                inputType: () => {
                    let type=''
                    switch (col.dataIndex) {
                        case 'fplx':
                            type = 'select';
                            break;
                        case 'billcode':
                            type = 'TextArea1';
                            break;
                        case 'billnum':
                            type = 'TextArea2';
                            break;
                        case 'je':
                            type = 'InputNumber3';
                            break;
                        case 'se':
                            type = 'InputNumber4';
                            break;
                        case 'dppje':
                            type = 'InputNumber5';
                            break;
                        case 'dppse':
                            type = 'InputNumber6';
                            break;
                        default:
                            break;
                    }
                    return type
                },
                dataIndex: col.dataIndex,
                title: col.title,
                IsFPLX: this..state.IsFPLX,
                zyfp: this.props.zyfp // 父级传过来的
                onbillnumChange: (value) => this.onbillnumChange(value) // 改变发票号码调接口
                editing: record.fplx==='纸质普票' ? (col.dataIndex==='fplx' || col.dataIndex==='billcode' || col.dataIndex==='billnum' || col.dataIndex==='je' || col.dataIndex==='se' || col.dataIndex==='dppje' || col.dataIndex==='dppse') && this.isEditing(index) : (col.dataIndex==='fplx' || col.dataIndex==='billcode' || col.dataIndex==='billnum') && this.isEditing(index) // 当下拉选择为“纸质普票”时,前7个都可以输入。反之,前三个可以输入
                selectFlag: this.state.selectFlag, // 
                changeSelectFlag: this.changeSelectFlag, // 单元格作为子级想要改变selectFlag的值,所以在这里往单元格组件中传个方法,通过方法改变(大致意思为:子级没办法直接改变父级中的值,但可以通过父级传过去的方法进而改变父级中的值)
                ChangeVal: this.ChangeVal,
                value: this.state.value,
           }
          
        },
      };
    });


    return (
      <div>
        <EditableContext.Provider value={this.props.form}>
          <Table 
             bordered
             pagination={false}
             dataSource={this.state.value} 
             columns={columns}
             components={components}
             rowClassName="editable-row"
          />
        </EditableContext.Provider>
        {this.props.disabled ? '' : 
            <div style={{textAlign: 'center'}}>
                <a onClick={() => {this.addTableFun()}}><Icon type='plus' style={{fontSize: '16px', color: '#08c'}} /></a>
            </div>
        }    
      </div>
    );
  }
}

export default EditableFormTable

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/941864.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot的数码产品抢购系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

LabVIEW电机控制中的主动消抖

在LabVIEW电机控制系统中&#xff0c;抖动现象&#xff08;如控制信号波动或机械振动&#xff09;会影响系统的稳定性和精度。通过使用主动消抖算法&#xff0c;可以有效降低抖动&#xff0c;提高控制性能。本文将介绍几种主流的主动消抖算法&#xff0c;并结合具体应用案例进行…

连续自成核退火热分级(SSA)技术表征共聚聚丙烯(PP)分子链结构

共聚聚丙烯是一种多相多组分高分子体系&#xff0c;体系中同时存在多种链组成、序列结构和相结构。研究表明&#xff0c;共聚聚丙烯中除了均聚聚丙烯外&#xff0c;还有乙丙无规共聚物&#xff08;又称乙丙橡胶&#xff0c;EPR&#xff09;及不同序列长度的乙丙嵌段共聚物&…

游戏AI实现-寻路算法(Dijkstra)

戴克斯特拉算法&#xff08;英语&#xff1a;Dijkstras algorithm&#xff09;&#xff0c;又称迪杰斯特拉算法、Dijkstra算法&#xff0c;是由荷兰计算机科学家艾兹赫尔戴克斯特拉在1956年发现的算法。 算法过程&#xff1a; 1.首先设置开始节点的成本值为0&#xff0c;并将…

C# OpenCV机器视觉:缺陷检测

在一个阳光明媚的早晨&#xff0c;阿强正准备享受他的一杯咖啡&#xff0c;突然接到了老板的电话。“阿强&#xff0c;我们的生产线出现了问题&#xff01;有几个产品的质量不合格&#xff0c;客户投诉不断&#xff01;你能不能想办法解决这个问题&#xff1f;” 阿强一听&…

模型 ADDIE(分析、设计、开发、实施、评估)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。分析、设计、开发、实施、评估教学法。 1 模型ADDIE(分析、设计、开发、实施、评估)的应用 1.1 个人IP私域运营体系构建 在个人IP私域运营领域&#xff0c;ADDIE模型被应用于构建一个系统的运营体系…

【微信小程序】3|首页搜索框 | 我的咖啡店-综合实训

首页-搜索框-跳转 引言 在微信小程序中&#xff0c;首页的搜索框是用户交互的重要入口。本文将通过“我的咖啡店”小程序的首页搜索框实现&#xff0c;详细介绍如何在微信小程序中创建和处理搜索框的交互。 1. 搜索函数实现 onClickInput函数在用户点击搜索框时触发&#x…

upload-labs-master第21关超详细教程

目录 环境配置解题思路利用漏洞 操作演示 环境配置 需要的东西 phpstudy-2018 链接&#xff1a; phpstudy-2018 提取码&#xff1a;0278 32 位 vc 9 和 11 运行库 链接&#xff1a; 运行库 提取码&#xff1a;0278 upload-labs-master 靶场 链接&#xff1a; upload-lasb-ma…

Elasticsearch:确保业务规则与语义搜索无缝协作

作者&#xff1a;来自 Elastic Kathleen DeRusso 利用查询规则与语义搜索和重新排序相结合的强大功能。 更多阅读&#xff1a; Elasticsearch 8.10 中引入查询规则 - query rules Elasticsearch 查询规则现已正式发布 - query rules 你是否知道查询规则&#xff08;query ru…

mysql联表查询

创建多个表&#xff0c;语句如下&#xff1a; CREATE DATABASE /*!32312 IF NOT EXISTS*/sg_security /*!40100 DEFAULT CHARACTER SET utf8mb4 */;USE sg_security;/*Table structure for table sys_menu */DROP TABLE IF EXISTS sys_menu;CREATE TABLE sys_menu (id bigint(2…

(Orin NX - Ubuntu 20.04)环境配置-Mid360雷达版

换源 换到阿里云的源&#xff08;不要清华的&#xff0c;有些东西会下载失败&#xff09; 如有需要&#xff0c;可以安装一下基础终端工具 sudo apt-get update sudo apt-get install terminator byobu net-tools openssh-server -y 如果有需要&#xff0c;下载deb并安装NoM…

在 Vue3 项目中安装和配置 Three.js

简介 Three.js 是一个轻量级的 WebGL 封装库&#xff0c;用于在浏览器中渲染复杂的 3D 图形。它提供了便捷的 API&#xff0c;可以快速构建 3D 场景、对象和动画。 Vue.js 是一个渐进式 JavaScript 框架&#xff0c;擅长构建用户界面。其响应式数据绑定和组件系统使得复杂的交…

【踩坑记录】C编程变量未初始化导致的程序异常

1、在编程的时候养成良好的习惯&#xff0c;定义变量以后记得给变量初始化&#xff0c;不然可能会产生一些意想不到的Bug。 2、比如下面的例子&#xff0c;如果定义的变量没有被初始化就有可能是一个随机值。如果代码少还好&#xff0c;很容易排查出来。但如果是一个比较大的项…

51c自动驾驶~合集42

我自己的原文哦~ https://blog.51cto.com/whaosoft/12888355 #DriveMM 六大数据集全部SOTA&#xff01;最新DriveMM&#xff1a;自动驾驶一体化多模态大模型&#xff08;美团&中山大学&#xff09; 近年来&#xff0c;视觉-语言数据和模型在自动驾驶领域引起了广泛关注…

CosyVoice安装过程详解

CosyVoice安装过程详解 安装过程参考官方文档 前情提要 环境&#xff1a;Windows子系统WSL下安装的Ubunt22.4python环境管理&#xff1a;MiniConda3git 1. Clone代码 $ git clone --recursive https://github.com/FunAudioLLM/CosyVoice.git # 若是submodule下载失败&…

逻辑的诗:类与对象(下)

一、初始化列表 初始化列表的使用方式是以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个“成员变量”后面跟一个放在括号中的初始化值或表达式&#xff1b; 每个成员变量在初始化列表中只能出现一次&#xff0c;语法理解上初始化列表可以认为…

什么是EMI测试,如何进行EMI测试?

什么是EMI测试&#xff1f; EMI&#xff08;Electromagnetic Interference&#xff0c;电磁干扰&#xff09;是指电子设备自身工作过程中产生的电磁波对外发射&#xff0c;从而对设备其它部分或外部其它设备造成干扰&#xff0c;属于电磁兼容的一种。实际测试中&#xff0c;主…

KingbaseES(金仓数据库)入门学习

前言 金仓是一种多进程架构&#xff0c;每一个连接到服务器的会话&#xff0c;在服务器上面都会为该会话分配进程 图形化界面管理 新建数据库名 然后新建一个模式 再创建一个表 新建一个表&#xff0c;然后设置列名 记得要保存 查询数据 也可以新建数据表&#xff0c;用命令…

Burp Suite的安装

1.安装Java 8环境: https://www.java.com/ 2.安装Burp Suite: 3.导出证书&#xff0c;安装证书&#xff1a; 不安装的话无法抓包https协议 4.设置浏览器的代理为Burp Suite: 将浏览器代理端口改为Burp Suite的默认端口 ###我个人在安装中遇到的一些问题&#xff1a; #浏览…

利用Spring Cloud Gateway Predicate优化微服务路由策略

利用Spring Cloud Gateway Predicate优化微服务路由策略 一、Predicate简介 Spring Cloud Gateway 是 Spring 生态系统中用于构建 API 网关的框架&#xff0c;它基于 Project Reactor 和 Netty 构建&#xff0c;旨在提供一种高效且灵活的方式来处理 HTTP 请求和响应。 Spring …