import React, {Component} from 'react'
|
import { is, fromJS } from 'immutable'
|
import { Table, Input, Button, Popconfirm, Form, Icon } from 'antd'
|
import Utils from '@/utils/utils.js'
|
import './index.scss'
|
|
const EditableContext = React.createContext()
|
|
const EditableRow = ({ form, index, ...props }) => (
|
<EditableContext.Provider value={form}>
|
<tr {...props} />
|
</EditableContext.Provider>
|
)
|
|
const EditableFormRow = Form.create()(EditableRow)
|
|
class EditableCell extends Component {
|
state = {
|
editing: false
|
}
|
|
toggleEdit = () => {
|
const editing = !this.state.editing
|
this.setState({ editing }, () => {
|
if (editing && this.input && this.input.select) {
|
this.input.select()
|
} else if (editing && this.input && this.input.focus) {
|
this.input.focus()
|
}
|
})
|
}
|
|
save = e => {
|
const { record, handleSave } = this.props
|
this.form.validateFields((error, values) => {
|
handleSave({ ...record, ...values })
|
if (error && error[e.currentTarget.id]) {
|
return
|
}
|
this.toggleEdit()
|
})
|
}
|
|
renderCell = form => {
|
this.form = form
|
const { children, dataIndex, record } = this.props
|
const { editing } = this.state
|
|
return editing ? (
|
<Form.Item style={{ margin: 0 }}>
|
{form.getFieldDecorator(dataIndex, {
|
rules: [
|
{
|
required: dataIndex === 'Value' || dataIndex === 'Text',
|
message: 'NOT NULL.',
|
},
|
],
|
initialValue: record[dataIndex]
|
})(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
|
</Form.Item>
|
) : (
|
<div
|
className="editable-cell-value-wrap"
|
onClick={this.toggleEdit}
|
>
|
{children}
|
</div>
|
)
|
}
|
|
render() {
|
const {
|
editable,
|
dataIndex,
|
title,
|
record,
|
index,
|
handleSave,
|
children,
|
...restProps
|
} = this.props
|
return (
|
<td {...restProps}>
|
{editable ? (
|
<EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
|
) : (
|
children
|
)}
|
</td>
|
)
|
}
|
}
|
|
class EditTable extends Component {
|
constructor(props) {
|
super(props)
|
|
let _width = '40%'
|
let fields = []
|
|
if (props.type === 'link') {
|
_width = '27%'
|
} else if (props.type === 'select') {
|
_width = Math.floor(80 / (props.linkSubFields.length + 2)) + '%'
|
fields = props.linkSubFields.map(field => {
|
return {
|
title: field.label,
|
dataIndex: field.field,
|
width: _width,
|
editable: true
|
}
|
})
|
}
|
|
let columns = [
|
{
|
title: 'Value',
|
dataIndex: 'Value',
|
width: _width,
|
editable: true
|
},
|
{
|
title: 'Text',
|
dataIndex: 'Text',
|
width: _width,
|
editable: true
|
},
|
...fields,
|
{
|
title: '操作',
|
align: 'center',
|
dataIndex: 'operation',
|
render: (text, record) =>
|
this.state.dataSource.length >= 1 ? (
|
<div>
|
<span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
|
<span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
|
<Popconfirm
|
title={props.dict['header.form.query.delete']}
|
okText={props.dict['header.confirm']}
|
cancelText={props.dict['header.cancel']}
|
onConfirm={() => this.handleDelete(record.key)
|
}>
|
<span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
|
</Popconfirm>
|
</div>
|
) : null,
|
}
|
]
|
|
if (props.type === 'link') {
|
columns.unshift({
|
title: 'ParentID',
|
dataIndex: 'ParentID',
|
width: '27%',
|
editable: true
|
})
|
}
|
|
this.state = {
|
columns: columns,
|
dataSource: props.data,
|
count: props.data.length,
|
type: props.type,
|
linkSubFields: props.linkSubFields
|
}
|
}
|
|
handleUpDown = (record, direction) => {
|
const { dataSource } = this.state
|
let index = 0
|
|
let _data = dataSource.filter((item, i) => {
|
if (item.key === record.key) {
|
index = i
|
}
|
|
return item.key !== record.key
|
})
|
if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) {
|
return
|
}
|
|
if (direction === 'up') {
|
_data.splice(index - 1, 0, record)
|
} else {
|
_data.splice(index + 1, 0, record)
|
}
|
|
this.setState({
|
dataSource: _data
|
})
|
}
|
|
handleDelete = key => {
|
const dataSource = [...this.state.dataSource]
|
this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
|
}
|
|
handleAdd = () => {
|
const { type, count, dataSource } = this.state
|
const newData = {
|
key: Utils.getuuid(),
|
Value: `${count}`,
|
Text: `${count}`
|
}
|
if (type === 'link') {
|
newData.ParentID = `${count}`
|
}
|
this.setState({
|
dataSource: [...dataSource, newData],
|
count: count + 1
|
})
|
}
|
|
handleSave = row => {
|
const newData = [...this.state.dataSource]
|
const index = newData.findIndex(item => row.key === item.key)
|
const item = newData[index]
|
newData.splice(index, 1, {
|
...item,
|
...row
|
})
|
this.setState({ dataSource: newData })
|
}
|
|
resetColumn = (type, linkSubFields) => {
|
let dataSource = JSON.parse(JSON.stringify(this.state.dataSource))
|
let _width = '40%'
|
let fields = []
|
|
if (type === 'select' && linkSubFields.length > this.state.linkSubFields) {
|
let addcol = linkSubFields[linkSubFields.length - 1]
|
dataSource = dataSource.map(data => {
|
data[addcol.field] = data.Text
|
return data
|
})
|
}
|
|
if (type === 'link') {
|
_width = '27%'
|
} else if (type === 'select') {
|
_width = Math.floor(80 / (linkSubFields.length + 2)) + '%'
|
fields = linkSubFields.map(field => {
|
return {
|
title: field.label,
|
dataIndex: field.field,
|
width: _width,
|
editable: true
|
}
|
})
|
}
|
|
let columns = [
|
{
|
title: 'Value',
|
dataIndex: 'Value',
|
width: _width,
|
editable: true
|
},
|
{
|
title: 'Text',
|
dataIndex: 'Text',
|
width: _width,
|
editable: true
|
},
|
...fields,
|
{
|
title: '操作',
|
align: 'center',
|
dataIndex: 'operation',
|
render: (text, record) =>
|
this.state.dataSource.length >= 1 ? (
|
<div>
|
<span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
|
<span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
|
<Popconfirm
|
title={this.props.dict['header.form.query.delete']}
|
okText={this.props.dict['header.confirm']}
|
cancelText={this.props.dict['header.cancel']}
|
onConfirm={() => this.handleDelete(record.key)
|
}>
|
<span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
|
</Popconfirm>
|
</div>
|
) : null,
|
}
|
]
|
|
if (type === 'link') {
|
columns.unshift({
|
title: 'ParentID',
|
dataIndex: 'ParentID',
|
width: '27%',
|
editable: true
|
})
|
}
|
|
this.setState({
|
columns: columns,
|
dataSource: dataSource,
|
type: type
|
})
|
}
|
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
if (!is(fromJS(this.props.linkSubFields), fromJS(nextProps.linkSubFields)) || this.props.type !== nextProps.type) {
|
this.resetColumn(nextProps.type, nextProps.linkSubFields)
|
} else if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
|
let _data = []
|
nextProps.data.forEach(item => {
|
let _item = {key: Utils.getuuid()}
|
this.state.columns.forEach(col => {
|
_item[col.dataIndex] = item[col.dataIndex] || ''
|
if (col.dataIndex !== 'ParentID' && !_item[col.dataIndex]) {
|
_item[col.dataIndex] = item.Text
|
}
|
})
|
_data.push(_item)
|
})
|
this.setState({
|
dataSource: _data,
|
count: nextProps.data.length
|
})
|
}
|
}
|
|
render() {
|
const { dataSource } = this.state
|
const components = {
|
body: {
|
row: EditableFormRow,
|
cell: EditableCell
|
}
|
}
|
const columns = this.state.columns.map(col => {
|
if (!col.editable) {
|
return col
|
}
|
return {
|
...col,
|
onCell: record => ({
|
record,
|
editable: col.editable,
|
dataIndex: col.dataIndex,
|
title: col.title,
|
handleSave: this.handleSave,
|
})
|
}
|
})
|
return (
|
<div className="common-modal-edit-table">
|
<Button onClick={this.handleAdd} type="primary" className="add-row">
|
添加
|
</Button>
|
<Table
|
components={components}
|
rowClassName={() => 'editable-row'}
|
bordered
|
dataSource={dataSource}
|
columns={columns}
|
pagination={false}
|
/>
|
</div>
|
)
|
}
|
}
|
|
export default EditTable
|