import { PlusOutlined } from '@ant-design/icons' ; import { Button , Divider , Input , Popconfirm , Table , message } from 'antd' ; import React , { Fragment , Component } from 'react' ; import isEqual from 'lodash.isequal' ; import styles from '../style.less' ; type TableFormDateType = { key : string ; workId ? : string ; name ? : string ; department ? : string ; isNew ? : boolean ; editable ? : boolean ; } ; type TableFormProps = { loading ? : boolean ; value ? : TableFormDateType [ ] ; onChange ? : ( value : TableFormDateType [ ] ) => void ; } ; type TableFormState = { loading ? : boolean ; value ? : TableFormDateType [ ] ; data ? : TableFormDateType [ ] ; } ; class TableForm extends Component < TableFormProps , TableFormState > { static getDerivedStateFromProps ( nextProps , preState ) { if ( isEqual ( nextProps . value , preState . value ) ) { return null ; } return { data : nextProps . value , value : nextProps . value , } ; } clickedCancel : boolean = false ; index = 0 ; cacheOriginData = { } ; columns = [ { title : '成员姓名' , dataIndex : 'name' , key : 'name' , width : '20%' , render : ( text , record ) => { if ( record . editable ) { return ( < Input value = { text } autoFocus onChange = { ( e ) => { this . handleFieldChange ( e , 'name' , record . key ) ; } } onKeyPress = { ( e ) => { this . handleKeyPress ( e , record . key ) ; } } placeholder = "成员姓名" / > ) ; } return text ; } , } , { title : '工号' , dataIndex : 'workId' , key : 'workId' , width : '20%' , render : ( text , record ) => { if ( record . editable ) { return ( < Input value = { text } onChange = { ( e ) => { this . handleFieldChange ( e , 'workId' , record . key ) ; } } onKeyPress = { ( e ) => { this . handleKeyPress ( e , record . key ) ; } } placeholder = "工号" / > ) ; } return text ; } , } , { title : '所属部门' , dataIndex : 'department' , key : 'department' , width : '40%' , render : ( text , record ) => { if ( record . editable ) { return ( < Input value = { text } onChange = { ( e ) => { this . handleFieldChange ( e , 'department' , record . key ) ; } } onKeyPress = { ( e ) => { this . handleKeyPress ( e , record . key ) ; } } placeholder = "所属部门" / > ) ; } return text ; } , } , { title : '操作' , key : 'action' , render : ( text , record ) => { const { loading } = this . state ; if ( ! ! record . editable && loading ) { return null ; } if ( record . editable ) { if ( record . isNew ) { return ( < span > < a onClick = { ( e ) => { this . saveRow ( e , record . key ) ; } } > 添加 < /a> < Divider type = "vertical" / > < Popconfirm title = "是否要删除此行？" onConfirm = { ( ) => { this . remove ( record . key ) ; } } > < a > 删除 < /a> < /Popconfirm> < /span>); } return ( < span > < a onClick = { ( e ) => { this . saveRow ( e , record . key ) ; } } > 保存 < /a> < Divider type = "vertical" / > < a onClick = { ( e ) => { this . cancel ( e , record . key ) ; } } > 取消 < /a> < /span>); } return ( < span > < a onClick = { ( e ) => { this . toggleEditable ( e , record . key ) ; } } > 编辑 < /a> < Divider type = "vertical" / > < Popconfirm title = "是否要删除此行？" onConfirm = { ( ) => { this . remove ( record . key ) ; } } > < a > 删除 < /a> < /Popconfirm> < /span>); } , } , ] ; constructor ( props ) { super ( props ) ; this . state = { data : props . value , loading : false , value : props . value , } ; } getRowByKey ( key , newData ? ) { const { data = [ ] } = this . state ; return ( newData || data ) . filter ( ( item ) => item . key === key ) [ 0 ] ; } toggleEditable = ( e , key ) => { e . preventDefault ( ) ; const { data = [ ] } = this . state ; const newData = data . map ( ( item ) => ( { ... item } ) ) ; const target = this . getRowByKey ( key , newData ) ; if ( target ) { if ( ! target . editable ) { this . cacheOriginData [ key ] = { ... target } ; } target . editable = ! target . editable ; this . setState ( { data : newData } ) ; } } ; newMember = ( ) => { const { data = [ ] } = this . state ; const newData = data . map ( ( item ) => ( { ... item } ) ) ; newData . push ( { key : `NEW_TEMP_ID_${ this . index }` , workId : '' , name : '' , department : '' , editable : true , isNew : true , } ) ; this . index += 1 ; this . setState ( { data : newData } ) ; } ; remove ( key ) { const { data = [ ] } = this . state ; const { onChange } = this . props ; const newData = data . filter ( ( item ) => item . key !== key ) ; this . setState ( { data : newData } ) ; if ( onChange ) { onChange ( newData ) ; } } handleKeyPress ( e , key ) { if ( e . key === 'Enter' ) { this . saveRow ( e , key ) ; } } handleFieldChange ( e , fieldName , key ) { const { data = [ ] } = this . state ; const newData = [ ... data ] ; const target = this . getRowByKey ( key , newData ) ; if ( target ) { target [ fieldName ] = e . target . value ; this . setState ( { data : newData } ) ; } } saveRow ( e , key ) { e . persist ( ) ; this . setState ( { loading : true , } ) ; setTimeout ( ( ) => { if ( this . clickedCancel ) { this . clickedCancel = false ; return ; } const target = this . getRowByKey ( key ) || { } ; if ( ! target . workId || ! target . name || ! target . department ) { message . error ( '请填写完整成员信息。' ) ; ( e . target as HTMLInputElement ) . focus ( ) ; this . setState ( { loading : false , } ) ; return ; } delete target . isNew ; this . toggleEditable ( e , key ) ; const { data = [ ] } = this . state ; const { onChange } = this . props ; if ( onChange ) { onChange ( data ) ; } this . setState ( { loading : false , } ) ; } , 500 ) ; } cancel ( e , key ) { this . clickedCancel = true ; e . preventDefault ( ) ; const { data = [ ] } = this . state ; const newData = [ ... data ] ; let cacheOriginData = [ ] ; cacheOriginData = newData . map ( ( item ) => { if ( item . key === key ) { if ( this . cacheOriginData [ key ] ) { const originItem = { ... item , ... this . cacheOriginData [ key ] , editable : false , } ; delete this . cacheOriginData [ key ] ; return originItem ; } } return item ; } ) ; this . setState ( { data : cacheOriginData } ) ; this . clickedCancel = false ; } render ( ) { const { loading , data } = this . state ; return ( < Fragment > < Table < TableFormDateType > loading = { loading } columns = { this . columns } dataSource = { data } pagination = { false } rowClassName = { ( record ) => ( record . editable ? styles . editable : '' ) } /> < Button style = { { width : '100%' , marginTop : 16 , marginBottom : 8 } } type = "dashed" onClick = { this . newMember } > < PlusOutlined /> 新增成员 < /Button> < /Fragment>); } } export default TableForm ;