| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Table, Input, Popconfirm, Form, Icon, Radio } from 'antd' |
| | | import { Table, Input, Popconfirm, Form, Radio } from 'antd' |
| | | import { ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined, PlusOutlined, SwapOutlined } from '@ant-design/icons' |
| | | |
| | | import { formRule } from '@/utils/option.js' |
| | | import Utils from '@/utils/utils.js' |
| | | import './index.scss' |
| | |
| | | } |
| | | |
| | | class EditTable extends Component { |
| | | constructor(props) { |
| | | super(props) |
| | | static propTpyes = { |
| | | type: PropTypes.string, // 表单类型 |
| | | linkSubFields: PropTypes.array, // 关联字段 |
| | | onChange: PropTypes.func // 数据变化 |
| | | } |
| | | |
| | | let _width = '40%' |
| | | state = { |
| | | columns: [], |
| | | dataSource: [], |
| | | count: 0, |
| | | type: null, |
| | | linkSubFields: [] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { linkSubFields, type } = this.props |
| | | let data = this.props['data-__meta'].initialValue |
| | | |
| | | if (!data) { |
| | | data = [] |
| | | } |
| | | |
| | | let fields = [] |
| | | let dataItem = props.data ? props.data[0] : '' |
| | | let dataItem = data[0] || '' |
| | | |
| | | if (props.type === 'link') { |
| | | _width = '27%' |
| | | } else if (props.type === 'select') { |
| | | _width = Math.floor(80 / (props.linkSubFields.length + 2)) + '%' |
| | | fields = props.linkSubFields.map(field => { |
| | | if (type === 'select' || type === 'radio' || type === 'link') { |
| | | fields = linkSubFields.map(cell => { |
| | | return { |
| | | title: field.label, |
| | | dataIndex: field.field, |
| | | width: _width, |
| | | title: cell.label, |
| | | dataIndex: cell.field, |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem[field.field]) === 'number' ? 'number' : 'string' |
| | | datatype: dataItem && typeof(dataItem[cell.field]) === 'number' ? 'number' : 'string' |
| | | } |
| | | }) |
| | | } |
| | | |
| | | |
| | | |
| | | let columns = [ |
| | | { |
| | | title: 'Value', |
| | | dataIndex: 'Value', |
| | | width: _width, |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem.Value) === 'number' ? 'number' : 'string' |
| | | }, |
| | | { |
| | | title: 'Text', |
| | | dataIndex: 'Text', |
| | | width: _width, |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem.Text) === 'number' ? 'number' : 'string' |
| | | }, |
| | |
| | | { |
| | | title: '操作', |
| | | align: 'center', |
| | | width: '20%', |
| | | 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> |
| | | <span className="operation-btn" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><ArrowUpOutlined /></span> |
| | | <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><ArrowDownOutlined /></span> |
| | | <Popconfirm |
| | | overlayClassName="popover-confirm" |
| | | title={props.dict['header.form.query.delete']} |
| | | onConfirm={() => this.handleDelete(record.key) |
| | | }> |
| | | <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> |
| | | <span style={{color: '#ff4d4f', cursor: 'pointer'}}><DeleteOutlined /></span> |
| | | </Popconfirm> |
| | | </div> |
| | | ) : null, |
| | | } |
| | | ] |
| | | |
| | | if (props.type === 'link') { |
| | | if (type === 'link') { |
| | | columns.unshift({ |
| | | title: 'ParentID', |
| | | dataIndex: 'ParentID', |
| | | width: '27%', |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem.ParentID) === 'number' ? 'number' : 'string' |
| | | }) |
| | | } |
| | | |
| | | this.state = { |
| | | this.setState({ |
| | | columns: columns.map(col => { |
| | | if (col.dataIndex !== 'operation') { |
| | | col = {...col, ...this.getColumnSearchProps(col)} |
| | | } |
| | | return col |
| | | }), |
| | | dataSource: props.data, |
| | | count: props.data.length, |
| | | type: props.type, |
| | | linkSubFields: props.linkSubFields |
| | | } |
| | | dataSource: data, |
| | | count: data.length, |
| | | type: type, |
| | | linkSubFields: linkSubFields |
| | | }) |
| | | } |
| | | |
| | | getColumnSearchProps = column => ({ |
| | |
| | | <div style={{ padding: 8 }}> |
| | | <Radio.Group onChange={(e) => this.changeDatatype(column, e)} value={column.datatype}> |
| | | <Radio style={{display: 'block', height: '30px', lineHeight: '30px'}} value="string"> |
| | | String |
| | | 字符串 |
| | | </Radio> |
| | | <Radio style={{display: 'block', height: '30px', lineHeight: '30px'}} value="number"> |
| | | Number |
| | | 数字 |
| | | </Radio> |
| | | </Radio.Group> |
| | | </div> |
| | | ), |
| | | filterIcon: () => ( |
| | | <Icon type="swap" style={{ color: column.datatype === 'number' ? '#1890ff' : undefined}} /> |
| | | <SwapOutlined style={{ color: column.datatype === 'number' ? '#1890ff' : ''}} /> |
| | | ) |
| | | }) |
| | | |
| | | changeDatatype = (column, e) => { |
| | | const { columns, dataSource } = this.state |
| | | let value = e.target.value |
| | | |
| | | this.setState({ |
| | | dataSource: dataSource.map(item => { |
| | | let val = item[column.dataIndex] |
| | | if (value === 'number') { |
| | | try { |
| | | val = parseFloat(val) |
| | | if (isNaN(val)) { |
| | | val = '' |
| | | } |
| | | } catch { |
| | | let _data = dataSource.map(item => { |
| | | let val = item[column.dataIndex] |
| | | if (value === 'number') { |
| | | try { |
| | | val = parseFloat(val) |
| | | if (isNaN(val)) { |
| | | val = '' |
| | | } |
| | | } else { |
| | | val = '' + val |
| | | } catch (e) { |
| | | val = '' |
| | | } |
| | | } else { |
| | | val = '' + val |
| | | } |
| | | |
| | | item[column.dataIndex] = val |
| | | item[column.dataIndex] = val |
| | | |
| | | return item |
| | | }), |
| | | return item |
| | | }) |
| | | |
| | | this.setState({ |
| | | dataSource: _data, |
| | | columns: columns.map(col => { |
| | | if (col.dataIndex === column.dataIndex) { |
| | | col.datatype = value |
| | |
| | | |
| | | return col |
| | | }) |
| | | }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | |
| | | |
| | | this.setState({ |
| | | dataSource: _data |
| | | }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | | handleDelete = key => { |
| | | const dataSource = [...this.state.dataSource] |
| | | this.setState({ dataSource: dataSource.filter(item => item.key !== key) }) |
| | | const { dataSource } = this.state |
| | | let _data = dataSource.filter(item => item.key !== key) |
| | | |
| | | this.setState({ dataSource: _data }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | | handleAdd = () => { |
| | | handleAdd = (e) => { |
| | | e.stopPropagation() |
| | | const { type, count, dataSource } = this.state |
| | | const newData = { |
| | | key: Utils.getuuid(), |
| | |
| | | if (type === 'link') { |
| | | newData.ParentID = `${count}` |
| | | } |
| | | |
| | | let _data = [...dataSource, newData] |
| | | |
| | | this.setState({ |
| | | dataSource: [...dataSource, newData], |
| | | dataSource: _data, |
| | | count: count + 1 |
| | | }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | |
| | | ...item, |
| | | ...row |
| | | }) |
| | | this.setState({ dataSource: newData }) |
| | | this.setState({ dataSource: newData }, () => { |
| | | this.props.onChange(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] |
| | | if ((type === 'select' || type === 'radio') && linkSubFields.length > this.state.linkSubFields) { |
| | | let addcol = linkSubFields.slice(-1)[0] |
| | | dataSource = dataSource.map(data => { |
| | | data[addcol.field] = data.Text |
| | | return data |
| | |
| | | |
| | | let dataItem = dataSource ? dataSource[0] : '' |
| | | |
| | | if (type === 'link') { |
| | | _width = '27%' |
| | | } else if (type === 'select') { |
| | | _width = Math.floor(80 / (linkSubFields.length + 2)) + '%' |
| | | if (type === 'select' || type === 'radio' || type === 'link') { |
| | | fields = linkSubFields.map(field => { |
| | | return { |
| | | title: field.label, |
| | | dataIndex: field.field, |
| | | width: _width, |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem[field.field]) === 'number' ? 'number' : 'string' |
| | | } |
| | |
| | | { |
| | | title: 'Value', |
| | | dataIndex: 'Value', |
| | | width: _width, |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem.Value) === 'number' ? 'number' : 'string' |
| | | }, |
| | | { |
| | | title: 'Text', |
| | | dataIndex: 'Text', |
| | | width: _width, |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem.Text) === 'number' ? 'number' : 'string' |
| | | }, |
| | |
| | | { |
| | | title: '操作', |
| | | align: 'center', |
| | | width: '20%', |
| | | 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> |
| | | <span className="operation-btn" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><ArrowUpOutlined /></span> |
| | | <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><ArrowDownOutlined /></span> |
| | | <Popconfirm |
| | | overlayClassName="popover-confirm" |
| | | title={this.props.dict['header.form.query.delete']} |
| | | onConfirm={() => this.handleDelete(record.key) |
| | | }> |
| | | <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span> |
| | | <span style={{color: '#ff4d4f', cursor: 'pointer'}}><DeleteOutlined /></span> |
| | | </Popconfirm> |
| | | </div> |
| | | ) : null, |
| | |
| | | columns.unshift({ |
| | | title: 'ParentID', |
| | | dataIndex: 'ParentID', |
| | | width: '27%', |
| | | editable: true, |
| | | datatype: dataItem && typeof(dataItem.ParentID) === 'number' ? 'number' : 'string' |
| | | }) |
| | |
| | | }), |
| | | dataSource: dataSource, |
| | | type: type |
| | | }, () => { |
| | | this.props.onChange(dataSource) |
| | | }) |
| | | } |
| | | |
| | | 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 |
| | | }) |
| | | } |
| | | } |
| | | |
| | |
| | | }) |
| | | return ( |
| | | <div className="common-modal-edit-table"> |
| | | <Icon className="add-row" type="plus" onClick={this.handleAdd} /> |
| | | <PlusOutlined className="add-row" onClick={this.handleAdd} /> |
| | | <Table |
| | | components={components} |
| | | rowClassName={() => 'editable-row'} |