From 31ec63f0419895876cbaba99637a884a32d33d0d Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期三, 01 九月 2021 10:31:45 +0800 Subject: [PATCH] 2021-09-01 --- src/templates/zshare/editTable/index.jsx | 412 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 330 insertions(+), 82 deletions(-) diff --git a/src/templates/zshare/editTable/index.jsx b/src/templates/zshare/editTable/index.jsx index bfeffd6..2d487c4 100644 --- a/src/templates/zshare/editTable/index.jsx +++ b/src/templates/zshare/editTable/index.jsx @@ -1,16 +1,79 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { is, fromJS } from 'immutable' -import { Table, Input, InputNumber, Popconfirm, Form, Icon, Select, Radio, Cascader, notification } from 'antd' +import { DndProvider, DragSource, DropTarget } from 'react-dnd' +import { Table, Input, InputNumber, Popconfirm, Form, Icon, Select, Radio, Cascader, notification, message, Modal, Typography } from 'antd' +import Utils from '@/utils/utils.js' import ColorSketch from '@/mob/colorsketch' +import PasteForm from '@/templates/zshare/pasteform' import CusSwitch from './cusSwitch' import zhCN from '@/locales/zh-CN/model.js' import enUS from '@/locales/en-US/model.js' import './index.scss' -let eTDict = localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS +let eTDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS const EditableContext = React.createContext() +const { confirm } = Modal +let dragingIndex = -1 +const { Paragraph } = Typography + +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) => { @@ -47,7 +110,7 @@ </Radio.Group> ) } else { - return <Input onPressEnter={() => this.getValue(form)} /> + return <Input onPressEnter={() => this.getValue(form)}/> } } @@ -102,52 +165,76 @@ state = { data: [], editingKey: '', + visible: false, columns: [] } UNSAFE_componentWillMount () { const { data, actions } = this.props let columns = fromJS(this.props.columns).toJS() + let operation = null - columns.push({ - title: eTDict['model.operation'], - dataIndex: 'operation', - width: '140px', - render: (text, record) => { - const { editingKey } = this.state - const editable = this.isEditing(record) - return editable ? ( - <span style={{textAlign: 'center', display: 'block'}}> - <EditableContext.Consumer> - {form => ( - <span onClick={() => this.save(form, record.uuid)} style={{ marginRight: 8 , color: '#1890ff', cursor: 'pointer'}}> - {eTDict['model.save']} - </span> - )} - </EditableContext.Consumer> - <span style={{ color: '#1890ff', cursor: 'pointer'}} onClick={() => this.cancel(record.uuid)}>{eTDict['model.cancel']}</span> + if (actions && (actions.includes('edit') || actions.includes('copy') || actions.includes('del'))) { + let _operation = null + columns = columns.filter(item => { + if (item.dataIndex === 'operation') { + _operation = item + } + return item.dataIndex !== 'operation' + }) + + operation = { + title: (<div> + {eTDict['model.operation']} + <span className="copy-control"> + {actions.includes('copy') ? <Icon type="copy" title="澶嶅埗" onClick={() => this.copy()} /> : null} + {actions.includes('copy') ? <Icon type="snippets" title="绮樿创" onClick={this.paste} /> : null} + {actions.includes('clear') ? <Icon type="delete" title="娓呯┖" onClick={this.clear} /> : null} </span> - ) : ( - <div className={'edit-operation-btn' + (editingKey !== '' ? ' disabled' : '')}> - {!actions || actions.includes('edit') ? <span className="primary" onClick={() => {editingKey === '' && this.edit(record.uuid)}}><Icon type="edit" /></span> : null} - {!actions || actions.includes('up') ? <span className="primary" onClick={() => {editingKey === '' && this.handleUpDown(record.uuid, 'up')}}><Icon type="arrow-up" /></span> : null} - {!actions || actions.includes('down') ? <span className="danger" onClick={() => {editingKey === '' && this.handleUpDown(record.uuid, 'down')}}><Icon type="arrow-down" /></span> : null} - {(!actions || actions.includes('del')) && editingKey === '' ? <Popconfirm - overlayClassName="popover-confirm" - title={eTDict['model.query.delete']} - onConfirm={() => this.handleDelete(record.uuid) - }> - <span className="danger"><Icon type="delete" /></span> - </Popconfirm> : null} - {(!actions || actions.includes('del')) && editingKey !== '' ? <span className="danger"><Icon type="delete" /></span> : null} - </div> - ) + </div>), + dataIndex: 'operation', + width: '140px', + render: (text, record) => { + const { editingKey } = this.state + const editable = this.isEditing(record) + return editable ? ( + <div style={{textAlign: 'center', minWidth: '110px'}}> + <EditableContext.Consumer> + {form => ( + <span onClick={() => this.save(form, record.uuid)} style={{ marginRight: 8 , color: '#1890ff', cursor: 'pointer'}}> + {eTDict['model.save']} + </span> + )} + </EditableContext.Consumer> + <span style={{ color: '#1890ff', cursor: 'pointer'}} onClick={() => this.cancel(record.uuid)}>{eTDict['model.cancel']}</span> + </div> + ) : ( + <div className={'edit-operation-btn' + (editingKey !== '' ? ' disabled' : '')} style={{minWidth: '110px'}}> + {actions.includes('edit') ? <span className="primary" onClick={() => {editingKey === '' && this.edit(record.uuid)}}><Icon type="edit" /></span> : null} + {actions.includes('copy') ? <span className="copy" onClick={() => {editingKey === '' && this.copy(record)}}><Icon type="copy" /></span> : null} + {actions.includes('del') && editingKey === '' ? <Popconfirm + overlayClassName="popover-confirm" + title={eTDict['model.query.delete']} + onConfirm={() => this.handleDelete(record.uuid) + }> + <span className="danger"><Icon type="delete" /></span> + </Popconfirm> : null} + {actions.includes('del') && editingKey !== '' ? <span className="danger"><Icon type="delete" /></span> : null} + </div> + ) + } } - }) + + if (_operation) { + operation.render = _operation.render + operation.width = _operation.width + } + columns.push(operation) + } this.setState({ data: data || [], - oricolumns: fromJS(this.props.columns).toJS(), + operation, columns }) } @@ -155,19 +242,26 @@ UNSAFE_componentWillReceiveProps (nextProps) { if (!is(fromJS(this.state.data), fromJS(nextProps.data))) { this.setState({data: nextProps.data, editingKey: ''}) - } else if (!is(fromJS(this.state.oricolumns), fromJS(nextProps.columns))) { - let cols = {} - nextProps.columns.forEach(col => {cols[col.dataIndex] = col}) - - this.setState({ - oricolumns: fromJS(nextProps.columns).toJS(), - columns: this.state.columns.map(col => { - if (cols[col.dataIndex]) { - return cols[col.dataIndex] - } - return col + } else if (!is(fromJS(this.props.columns), fromJS(nextProps.columns))) { + if (nextProps.columns.length === this.props.columns.length) { + let cols = {} + nextProps.columns.forEach(col => {cols[col.dataIndex] = col}) + + this.setState({ + columns: this.state.columns.map(col => { + if (cols[col.dataIndex]) { + return cols[col.dataIndex] + } + return col + }) }) - }) + } else { + let columns = fromJS(nextProps.columns).toJS() + if (this.state.operation) { + columns.push(this.state.operation) + } + this.setState({columns}) + } } } @@ -175,6 +269,123 @@ cancel = () => { this.setState({ editingKey: '' }) + } + + clear = () => { + const _this = this + + confirm({ + title: '纭畾娓呯┖鍒楄〃鍚楋紵', + content: '', + onOk() { + _this.setState({ data: [], editingKey: '' }, () => { + _this.props.onChange([]) + }) + }, + onCancel() {} + }) + } + + copy = (item) => { + const { type } = this.props + const { data } = this.state + + if (!data || data.length === 0) { + message.warning('鏈幏鍙栧埌閰嶇疆淇℃伅') + return + } + + let msg = { key: type } + + if (item) { + msg.type = 'line' + msg.data = item + } else { + msg.type = 'array' + msg.data = data + } + + try { + msg = window.btoa(window.encodeURIComponent(JSON.stringify(msg))) + } catch (e) { + console.warn('Stringify Failure') + msg = '' + } + + if (msg) { + let oInput = document.createElement('input') + oInput.value = msg + document.body.appendChild(oInput) + oInput.select() + document.execCommand('Copy') + document.body.removeChild(oInput) + message.success('澶嶅埗鎴愬姛銆�') + } + } + + paste = () => { + this.setState({visible: true}) + } + + pasteSubmit = () => { + const { type } = this.props + const { columns } = this.state + let data = fromJS(this.state.data).toJS() + + this.pasteFormRef.handleConfirm().then(res => { + if (res.key !== type) { + message.warning('閰嶇疆淇℃伅鏍煎紡閿欒锛�') + return + } + + if (res.type === 'line') { + let unique = true + res.data.uuid = Utils.getuuid() + columns.forEach(col => { + if (col.unique !== true || !unique) return + + let _index = data.findIndex(item => res.data[col.dataIndex] === item[col.dataIndex]) + + if (_index > -1) { + notification.warning({ + top: 92, + message: col.title + '涓嶅彲閲嶅锛�', + duration: 5 + }) + unique = false + } + }) + + if (!unique) return + + data.unshift(res.data) + this.setState({ data, editingKey: '', visible: false }, () => { + this.props.onChange(data) + }) + } else if (res.type === 'array') { + res.data.forEach(cell => { + let unique = true + cell.uuid = Utils.getuuid() + columns.forEach(col => { + if (col.unique !== true || !unique) return + let _index = data.findIndex(item => cell[col.dataIndex] === item[col.dataIndex]) + + if (_index > -1) { + unique = false + } + }) + + if (!unique) return + + data.push(cell) + }) + + this.setState({ data, editingKey: '', visible: false }, () => { + this.props.onChange(data) + }) + } + message.success('绮樿创鎴愬姛銆�') + }) } onSave = (record) => { @@ -218,27 +429,6 @@ handleDelete = (uuid) => { const { data } = this.state let _data = data.filter(item => uuid !== item.uuid) - - this.setState({ - data: _data - }, () => { - this.props.onChange(_data) - }) - } - - handleUpDown = (uuid, direction) => { - let _data = fromJS(this.state.data).toJS() - const index = _data.findIndex(item => uuid === item.uuid) - - 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 @@ -296,14 +486,41 @@ this.setState({ editingKey: uuid }) } + 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 components = { + const { actions } = this.props + + let components = { body: { - cell: EditableCell, + cell: EditableCell } } + + let moveprops = {} + if (actions.includes('move')) { + components.body.row = DragableBodyRow + moveprops.moveAble = !this.state.editingKey + moveprops.moveRow = this.moveRow + } - const columns = this.state.columns.map(col => { + let columns = this.state.columns.map(col => { + if (col.copy) { + col.render = (text) => (<Paragraph copyable>{text}</Paragraph>) + } if (!col.editable) return col return { ...col, @@ -323,18 +540,49 @@ } }) + columns.unshift({ + title: '搴忓彿', + dataIndex: '$index', + className: 'mk-index', + width: '60px', + }) + + const data = this.state.data.map((item, index) => { + item.$index = index + 1 + + return item + }) + return ( <EditableContext.Provider value={this.props.form}> <div className="modal-edit-table"> - <Table - bordered - rowKey="uuid" - components={components} - dataSource={this.state.data} - columns={columns} - rowClassName="editable-row" - pagination={false} - /> + <DndProvider> + <Table + bordered + rowKey="uuid" + components={components} + dataSource={data} + columns={columns} + rowClassName="editable-row" + pagination={false} + onRow={(record, index) => ({ + index, + ...moveprops + })} + /> + </DndProvider> + {/* 淇℃伅绮樿创 */} + <Modal + title={eTDict['header.form.paste']} + visible={this.state.visible} + width={600} + maskClosable={false} + onOk={this.pasteSubmit} + onCancel={() => {this.setState({visible: false})}} + destroyOnClose + > + <PasteForm dict={eTDict} wrappedComponentRef={(inst) => this.pasteFormRef = inst}/> + </Modal> </div> </EditableContext.Provider> ) -- Gitblit v1.8.0