| | |
| | | import React, { Component } from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { fromJS } from 'immutable' |
| | | import { Table, Input, InputNumber, Popconfirm, Form, Icon, notification, Select } from 'antd' |
| | | import { notification } from 'antd' |
| | | import { PlusOutlined } from '@ant-design/icons' |
| | | |
| | | import ColorSketch from '@/mob/colorsketch' |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import Utils from '@/utils/utils.js' |
| | | import './index.scss' |
| | | |
| | | const EditableContext = React.createContext() |
| | | |
| | | class EditableCell extends Component { |
| | | getInput = (form) => { |
| | | const { inputType } = this.props |
| | | if (inputType === 'number') { |
| | | return <InputNumber min={12} max={50} precision={0} onPressEnter={() => this.getValue(form)} /> |
| | | } else if (inputType === 'color') { |
| | | return <ColorSketch /> |
| | | } else if (inputType === 'select') { |
| | | return <Select> |
| | | <Select.Option key="left" value="left"> left </Select.Option> |
| | | <Select.Option key="center" value="center"> center </Select.Option> |
| | | <Select.Option key="right" value="right"> right </Select.Option> |
| | | <Select.Option key="justify" value="justify"> justify </Select.Option> |
| | | </Select> |
| | | } 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, children, className } = this.props |
| | | |
| | | return ( |
| | | <td className={className}> |
| | | {editing ? ( |
| | | <Form.Item style={{ margin: 0 }}> |
| | | {getFieldDecorator(dataIndex, { |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: `Please Input ${title}!`, |
| | | }, |
| | | ], |
| | | initialValue: record[dataIndex], |
| | | })(this.getInput(form))} |
| | | </Form.Item> |
| | | ) : ( |
| | | children |
| | | )} |
| | | </td> |
| | | ) |
| | | } |
| | | |
| | | render() { |
| | | return <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer> |
| | | } |
| | | } |
| | | const EditTable = asyncComponent(() => import('@/templates/zshare/editTable')) |
| | | |
| | | class EdiFieldsTable extends Component { |
| | | static propTpyes = { |
| | |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | let data = this.props['data-__meta'].initialValue |
| | | let data = this.props['data-__meta'].initialValue || [] |
| | | |
| | | this.setState({ |
| | | data: data |
| | | data: data.map(item => { |
| | | item.uuid = item.uuid || item.key |
| | | return item |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | state = { |
| | | data: [], |
| | | editingKey: '', |
| | | columns: [ |
| | | { |
| | | title: '字段名', |
| | | dataIndex: 'field', |
| | | inputType: 'input', |
| | | editable: true, |
| | | width: '20%', |
| | | }, |
| | | { |
| | | title: '字体颜色', |
| | | dataIndex: 'color', |
| | | inputType: 'color', |
| | | editable: true, |
| | | width: '20%', |
| | | render: (text, record) => { |
| | | return <span style={{color: text}}>示例</span> |
| | | } |
| | |
| | | title: '字体大小', |
| | | dataIndex: 'fontSize', |
| | | inputType: 'number', |
| | | min: 12, |
| | | max: 50, |
| | | editable: true, |
| | | width: '20%', |
| | | }, |
| | | { |
| | | title: '对齐方式', |
| | | dataIndex: 'align', |
| | | inputType: 'select', |
| | | editable: true, |
| | | }, |
| | | { |
| | | title: 'operation', |
| | | dataIndex: 'operation', |
| | | 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)}}><Icon type="edit" /></span> |
| | | <span className="primary" onClick={() => {editingKey === '' && this.handleUpDown(record.key, 'up')}}><Icon type="arrow-up" /></span> |
| | | <span className="danger" onClick={() => {editingKey === '' && this.handleUpDown(record.key, 'down')}}><Icon type="arrow-down" /></span> |
| | | {editingKey === '' ? <Popconfirm |
| | | overlayClassName="popover-confirm" |
| | | title={this.props.dict['model.query.delete']} |
| | | onConfirm={() => this.handleDelete(record.key) |
| | | }> |
| | | <span className="danger"><Icon type="delete" /></span> |
| | | </Popconfirm> : null} |
| | | {editingKey !== '' ? <span className="danger"><Icon type="delete" /></span> : null} |
| | | </div> |
| | | ) |
| | | }, |
| | | }, |
| | | width: '20%', |
| | | options: [ |
| | | {value: 'left', text: 'left'}, |
| | | {value: 'center', text: 'center'}, |
| | | {value: 'right', text: 'right'}, |
| | | {value: 'justify', text: 'justify'} |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | | |
| | | isEditing = record => record.key === this.state.editingKey |
| | | |
| | | cancel = () => { |
| | | this.setState({ editingKey: '' }) |
| | | } |
| | | |
| | | onSave = (record) => { |
| | | const newData = [...this.state.data] |
| | | const index = newData.findIndex(item => record.key === item.key) |
| | | 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) |
| | | }) |
| | | } |
| | | |
| | | handleUpDown = (key, direction) => { |
| | | let _data = fromJS(this.state.data).toJS() |
| | | const index = _data.findIndex(item => key === item.key) |
| | | |
| | | if ((index === 0 && direction === 'up') || (index === _data.length - 1 && direction === 'down')) { |
| | | return |
| | | } |
| | | |
| | | if (direction === 'up') { |
| | | _data.splice(index - 1, 0, ..._data.splice(index, 1)) |
| | | } else { |
| | | _data.splice(index + 1, 0, ..._data.splice(index, 1)) |
| | | } |
| | | |
| | | this.setState({ |
| | | data: _data |
| | | }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | | save(form, key) { |
| | | form.validateFields((error, row) => { |
| | | if (error) { |
| | | return; |
| | | } |
| | | const newData = [...this.state.data] |
| | | const index = newData.findIndex(item => key === item.key) |
| | | 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 = () => { |
| | | if (this.state.editingKey) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '请保存编辑中的元素!', |
| | | duration: 5 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | let _index = this.state.data.length + 1 |
| | | let item = { |
| | | key: Utils.getuuid(), |
| | | field: `field${this.state.data.length + 1}`, |
| | | field: `field${_index}`, |
| | | color: 'rgba(0, 0, 0, 0.85)', |
| | | align: 'left', |
| | | fontSize: 14, |
| | | } |
| | | |
| | | item.uuid = item.key |
| | | |
| | | while (this.state.data.filter(cell => cell.field === item.field).length > 0) { |
| | | _index++ |
| | | item.field = `field${_index}` |
| | | } |
| | | |
| | | let data = [...this.state.data, item] |
| | |
| | | }) |
| | | } |
| | | |
| | | edit(key) { |
| | | this.setState({ editingKey: key }) |
| | | changeData = (data) => { |
| | | let fields = data.map(cell => cell.field) |
| | | fields = Array.from(new Set(fields)) |
| | | if (data.length > 1 && data.length > fields.length) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '字段名不可重复!', |
| | | duration: 5 |
| | | }) |
| | | return |
| | | } |
| | | Array.from(new Set(fields)) |
| | | this.setState({ data }, () => { |
| | | this.props.onChange(data) |
| | | }) |
| | | } |
| | | |
| | | render() { |
| | | const components = { |
| | | body: { |
| | | cell: EditableCell, |
| | | }, |
| | | } |
| | | |
| | | const columns = this.state.columns.map(col => { |
| | | if (!col.editable) { |
| | | return col |
| | | } |
| | | return { |
| | | ...col, |
| | | onCell: record => ({ |
| | | record, |
| | | inputType: col.inputType, |
| | | dataIndex: col.dataIndex, |
| | | title: col.title, |
| | | editing: this.isEditing(record), |
| | | onSave: this.onSave, |
| | | }), |
| | | } |
| | | }) |
| | | const { data, columns } = this.state |
| | | |
| | | return ( |
| | | <EditableContext.Provider value={this.props.form}> |
| | | <div className="modal-card-field-table"> |
| | | {this.state.data.length < 3 ? <Icon className="add-row" type="plus" onClick={this.handleAdd} /> : null} |
| | | <Table |
| | | components={components} |
| | | bordered |
| | | dataSource={this.state.data} |
| | | columns={columns} |
| | | rowClassName="editable-row" |
| | | pagination={false} |
| | | /> |
| | | </div> |
| | | </EditableContext.Provider> |
| | | <div className="modal-card-field-table"> |
| | | {data.length < 3 ? <PlusOutlined className="add-row" onClick={this.handleAdd} /> : null} |
| | | <EditTable actions={['edit', 'move', 'del']} data={data} columns={columns} onChange={this.changeData}/> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Form.create()(EdiFieldsTable) |
| | | export default EdiFieldsTable |