import React, { Component } from 'react'
|
import PropTypes from 'prop-types'
|
import { is, fromJS } from 'immutable'
|
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
|
import { Table, Input, Popconfirm, Form, notification, message } from 'antd'
|
import { PlusOutlined, EditOutlined, DeleteOutlined, SwapOutlined } from '@ant-design/icons'
|
|
import Utils from '@/utils/utils.js'
|
import asyncComponent from '@/utils/asyncComponent'
|
// import FileUpload from '@/tabviews/zshare/fileupload'
|
import './index.scss'
|
|
const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
|
const EditableContext = React.createContext()
|
let dragingIndex = -1
|
|
class BodyRow extends React.Component {
|
render() {
|
const { isOver, moveAble, connectDragSource, connectDropTarget, moveRow, ...restProps } = this.props
|
let { className } = restProps
|
|
if (isOver && moveAble) {
|
if (restProps.index > dragingIndex) {
|
className += ' drop-over-downward'
|
}
|
if (restProps.index < dragingIndex) {
|
className += ' drop-over-upward'
|
}
|
}
|
|
if (moveAble) {
|
return connectDragSource(
|
connectDropTarget(<tr {...restProps} className={className} style={{...restProps.style, cursor: 'move'}} />),
|
)
|
} else {
|
return (<tr {...restProps} className={className} style={restProps.style} />)
|
}
|
}
|
}
|
|
const rowSource = {
|
beginDrag(props) {
|
dragingIndex = props.index
|
return {
|
index: props.index,
|
}
|
}
|
}
|
|
const rowTarget = {
|
drop(props, monitor) {
|
const dragIndex = monitor.getItem().index
|
const hoverIndex = props.index
|
|
if (dragIndex === hoverIndex) {
|
return
|
}
|
|
props.moveRow(dragIndex, hoverIndex)
|
|
monitor.getItem().index = hoverIndex
|
},
|
}
|
|
const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
|
connectDropTarget: connect.dropTarget(),
|
isOver: monitor.isOver(),
|
}))(
|
DragSource('row', rowSource, connect => ({
|
connectDragSource: connect.dragSource(),
|
}))(BodyRow),
|
)
|
|
class EditableCell extends Component {
|
getInput = (form) => {
|
const { inputType, record } = this.props
|
if (inputType === 'file') {
|
return <SourceComponent initialValue={record ? (record.$url || '') : ''} type="" placement="right"/>
|
// return <FileUpload config={{
|
// initval: record ? (record.$url || '') : '',
|
// suffix: '',
|
// maxfile: 1,
|
// fileType: 'picture-card'
|
// }}/>
|
} else {
|
return <Input onPressEnter={() => this.getValue(form)} />
|
}
|
}
|
|
getValue = (form) => {
|
const { record } = this.props
|
form.validateFields((error, row) => {
|
if (error) {
|
return
|
}
|
|
this.props.onSave({...record, ...row})
|
})
|
}
|
|
renderCell = (form) => {
|
const { getFieldDecorator } = form
|
const {
|
editing,
|
dataIndex,
|
title,
|
record,
|
inputType,
|
index,
|
children,
|
onSave,
|
...restProps
|
} = this.props;
|
|
let _val = ''
|
|
if (record && dataIndex) {
|
_val = record[dataIndex]
|
}
|
|
return (
|
<td {...restProps}>
|
{editing ? (
|
<Form.Item style={{ margin: '0 -5px 0 -5px' }}>
|
{getFieldDecorator(dataIndex, {
|
// rules: [
|
// {
|
// required: dataIndex === '$value',
|
// message: `Please Input ${title}!`,
|
// },
|
// ],
|
initialValue: _val,
|
})(this.getInput(form))}
|
</Form.Item>
|
) : (
|
children
|
)}
|
</td>
|
)
|
}
|
|
render() {
|
return <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
|
}
|
}
|
|
class EdiDataTable extends Component {
|
static propTpyes = {
|
transfield: PropTypes.object, // 字段名称
|
type: PropTypes.string, // 是否为关联表单
|
display: PropTypes.string, // 数据类型,文本、图片
|
fields: PropTypes.array, // 字段集
|
linkSubFields: PropTypes.array, // 填充字段
|
onChange: PropTypes.func // 数据变化
|
}
|
|
UNSAFE_componentWillMount () {
|
let data = this.props['data-__meta'].initialValue
|
|
this.setState({
|
data: data,
|
columns: this.getCloumns()
|
})
|
}
|
|
state = {
|
data: [],
|
editingKey: '',
|
columns: []
|
}
|
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
if (
|
!is(fromJS(this.props.fields), fromJS(nextProps.fields)) ||
|
!is(fromJS(this.props.linkSubFields), fromJS(nextProps.linkSubFields)) ||
|
this.props.display !== nextProps.display ||
|
this.props.type !== nextProps.type
|
) {
|
this.setState({editingKey: ''}, () => {
|
this.setState({
|
columns: this.getCloumns()
|
})
|
})
|
}
|
}
|
|
getCloumns = () => {
|
const { display, fields, linkSubFields, transfield, type } = this.props
|
let columns = []
|
let keys = ['ParentID']
|
|
if (display === 'picture') {
|
columns.push({
|
title: 'url',
|
dataIndex: '$url',
|
inputType: 'file',
|
// width: '40%',
|
editable: true,
|
render: (text) => {
|
if (!text) return ''
|
return <span style={{display: 'block', width: '70px', height: '70px'}}><img style={{width: '100%', height: '100%'}} src={text} alt="" /></span>
|
}
|
})
|
} else if (display === 'color') {
|
columns.push({
|
title: 'Color',
|
dataIndex: '$color',
|
inputType: 'text',
|
editable: true,
|
render: (text) => {
|
if (!text) return ''
|
return <div style={{height: '20px', background: text}}></div>
|
}
|
})
|
}
|
|
fields.forEach(item => {
|
keys.push(item.field)
|
columns.push({
|
title: item.field,
|
dataIndex: item.field,
|
editable: true,
|
})
|
})
|
|
if (linkSubFields.length > 0) {
|
linkSubFields.forEach(m => {
|
if (keys.includes(m)) return
|
|
columns.push({
|
title: transfield[m] || m,
|
dataIndex: m,
|
editable: true,
|
})
|
})
|
}
|
|
columns.unshift({
|
title: 'Value',
|
dataIndex: '$value',
|
editable: true,
|
})
|
|
if (type === 'link') {
|
columns.unshift({
|
title: 'ParentID',
|
dataIndex: 'ParentID',
|
editable: true,
|
})
|
}
|
|
columns.push({
|
title: '操作',
|
dataIndex: 'operation',
|
align: 'center',
|
width: '18%',
|
render: (text, record) => {
|
const { editingKey } = this.state
|
const editable = this.isEditing(record)
|
return editable ? (
|
<span>
|
<EditableContext.Consumer>
|
{form => (
|
<span onClick={() => this.save(form, record.key)} style={{ marginRight: 8 , color: '#1890ff', cursor: 'pointer'}}>
|
保存
|
</span>
|
)}
|
</EditableContext.Consumer>
|
<span style={{ color: '#1890ff', cursor: 'pointer'}} onClick={() => this.cancel(record.key)}>取消</span>
|
</span>
|
) : (
|
<div className={'operation-btn' + (editingKey !== '' ? ' disabled' : '')}>
|
<span className="primary" onClick={() => {editingKey === '' && this.edit(record.key)}}><EditOutlined /></span>
|
<span className="hide-control" title="显示/隐藏" onClick={() => {editingKey === '' && this.handleHide(record.key)}}><SwapOutlined /></span>
|
{editingKey === '' ? <Popconfirm
|
overlayClassName="popover-confirm"
|
title="确定删除吗?"
|
onConfirm={() => this.handleDelete(record.key)
|
}>
|
<span className="danger"><DeleteOutlined /></span>
|
</Popconfirm> : null}
|
{editingKey !== '' ? <span className="danger"><DeleteOutlined /></span> : null}
|
</div>
|
)
|
}
|
})
|
|
return columns
|
}
|
|
isEditing = record => record.key === this.state.editingKey
|
|
cancel = () => {
|
this.setState({ editingKey: '' })
|
}
|
|
onSave = (record) => {
|
const { type } = this.props
|
const newData = [...this.state.data]
|
const index = newData.findIndex(item => record.key === item.key)
|
|
if (type === 'link') {
|
if (newData.filter(m => record.key !== m.key && record.$value === m.$value && record.ParentID === m.ParentID).length > 0) {
|
message.warning('相同ParentID下,此Value值已存在!')
|
}
|
} else {
|
if (newData.filter(m => record.key !== m.key && record.$value === m.$value).length > 0) {
|
message.warning('此Value值已存在!')
|
}
|
}
|
|
if (index > -1) {
|
newData.splice(index, 1, record)
|
this.setState({ data: newData, editingKey: '' }, () => {
|
this.props.onChange(newData)
|
})
|
}
|
}
|
|
handleDelete = (key) => {
|
const { data } = this.state
|
let _data = data.filter(item => key !== item.key)
|
|
this.setState({
|
data: _data
|
}, () => {
|
this.props.onChange(_data)
|
})
|
}
|
|
save(form, key) {
|
const { type } = this.props
|
|
form.validateFields((error, row) => {
|
if (error) {
|
return;
|
}
|
|
const newData = [...this.state.data]
|
const index = newData.findIndex(item => key === item.key)
|
|
if (type === 'link') {
|
if (newData.filter(m => key !== m.key && row.$value === m.$value && row.ParentID === m.ParentID).length > 0) {
|
message.warning('相同ParentID下,此Value值已存在!')
|
}
|
} else {
|
if (newData.filter(m => key !== m.key && row.$value === m.$value).length > 0) {
|
message.warning('此Value值已存在!')
|
}
|
}
|
|
if (index > -1) {
|
const item = newData[index]
|
newData.splice(index, 1, {
|
...item,
|
...row,
|
})
|
this.setState({ data: newData, editingKey: '' }, () => {
|
this.props.onChange(newData)
|
})
|
} else {
|
newData.push(row);
|
this.setState({ data: newData, editingKey: '' }, () => {
|
this.props.onChange(newData)
|
})
|
}
|
})
|
}
|
|
handleAdd = () => {
|
const { fields, display } = this.props
|
if (this.state.data.length >= 100) {
|
notification.warning({
|
top: 92,
|
message: '最多可添加100项!',
|
duration: 5
|
})
|
return
|
}
|
|
let item = { key: Utils.getuuid(), $value: `${this.state.data.length + 1}`, ParentID: '' }
|
|
if (display === 'picture') {
|
item.$url = ''
|
} else if (display === 'color') {
|
item.$color = ''
|
}
|
|
fields.forEach(f => {
|
item[f.field] = `${this.state.data.length + 1}`
|
})
|
|
let data = [...this.state.data, item]
|
|
this.setState({ data, editingKey: '' }, () => {
|
this.props.onChange(data)
|
})
|
}
|
|
edit(key) {
|
this.setState({ editingKey: key })
|
}
|
|
handleHide = (key) => {
|
let _data = this.state.data.map(item => {
|
if (item.key === key) {
|
item.Hide = !item.Hide
|
}
|
return item
|
})
|
this.setState({
|
data: _data
|
}, () => {
|
this.props.onChange(_data)
|
})
|
}
|
|
moveRow = (dragIndex, hoverIndex) => {
|
const { editingKey } = this.state
|
let _data = fromJS(this.state.data).toJS()
|
|
if (editingKey) return
|
|
_data.splice(hoverIndex, 0, ..._data.splice(dragIndex, 1))
|
|
this.setState({
|
data: _data
|
}, () => {
|
this.props.onChange(_data)
|
})
|
}
|
|
render() {
|
const { display, fields } = this.props
|
|
const components = {
|
body: {
|
row: DragableBodyRow,
|
cell: EditableCell
|
}
|
}
|
|
const columns = this.state.columns.map(col => {
|
if (!col.editable) {
|
return col
|
}
|
return {
|
...col,
|
onCell: record => ({
|
record,
|
dataIndex: col.dataIndex,
|
inputType: col.inputType,
|
title: col.title,
|
editing: this.isEditing(record),
|
onSave: this.onSave,
|
}),
|
}
|
})
|
|
let addable = false
|
if (display === 'picture' || display === 'color') {
|
addable = true
|
} else if (fields && fields.length > 0) {
|
addable = true
|
}
|
|
return (
|
<EditableContext.Provider value={this.props.form}>
|
<div className="modal-card-data-table">
|
{addable ? <PlusOutlined className="add-row" onClick={this.handleAdd} /> : null}
|
<DndProvider>
|
<Table
|
components={components}
|
bordered
|
rowKey="key"
|
dataSource={this.state.data}
|
columns={columns}
|
rowClassName={(record) => record.Hide ? 'editable-row hide' : 'editable-row'}
|
onRow={(record, index) => ({
|
index,
|
moveAble: !this.state.editingKey,
|
moveRow: this.moveRow,
|
})}
|
pagination={false}
|
/>
|
</DndProvider>
|
</div>
|
</EditableContext.Provider>
|
)
|
}
|
}
|
|
export default Form.create()(EdiDataTable)
|