From f3d4db769ba9b51b799d981511a710fd443d0e08 Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期一, 21 四月 2025 12:18:03 +0800 Subject: [PATCH] Merge branch 'master' into positec --- src/templates/zshare/modalform/modaleditable/index.jsx | 691 +++++++++++++++++++++++++++----------------------------- 1 files changed, 334 insertions(+), 357 deletions(-) diff --git a/src/templates/zshare/modalform/modaleditable/index.jsx b/src/templates/zshare/modalform/modaleditable/index.jsx index a6fe297..0427a95 100644 --- a/src/templates/zshare/modalform/modaleditable/index.jsx +++ b/src/templates/zshare/modalform/modaleditable/index.jsx @@ -1,457 +1,434 @@ 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 { formRule } from '@/utils/option.js' +import { DndProvider, DragSource, DropTarget } from 'react-dnd' +import { Table, Input, Popconfirm, message } from 'antd' +import { DeleteOutlined, PlusOutlined, SwapOutlined, DragOutlined } from '@ant-design/icons' + import Utils from '@/utils/utils.js' +import asyncComponent from '@/utils/asyncComponent' import './index.scss' -const EditableContext = React.createContext() +const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent')) -const EditableRow = ({ form, index, ...props }) => ( - <EditableContext.Provider value={form}> - <tr {...props} /> - </EditableContext.Provider> +class MoveTd extends React.Component { + render() { + const { connectDragSource, connectDropTarget } = this.props + + return connectDragSource( + connectDropTarget(<td className="mk-move-col"><DragOutlined /></td>), + ) + } +} + +const rowSource = { + beginDrag(props) { + 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 DragableTd = DropTarget('td', rowTarget, connect => ({ + connectDropTarget: connect.dropTarget(), +}))( + DragSource('td', rowSource, (connect, monitor) => ({ + connectDragSource: connect.dragSource(), + // isDragging: monitor.isDragging() + }))(MoveTd), ) - -const EditableFormRow = Form.create()(EditableRow) class EditableCell extends Component { state = { - editing: false + editing: false, + value: '' } - toggleEdit = () => { - const editing = !this.state.editing - this.setState({ editing }, () => { - if (editing && this.input && this.input.select) { + trigger = () => { + const { dataIndex, record } = this.props + + this.setState({ editing: true, value: record[dataIndex] }, () => { + if (this.input && this.input.select) { this.input.select() - } else if (editing && this.input && this.input.focus) { + } else if (this.input && this.input.focus) { this.input.focus() } }) } - save = e => { - const { record, handleSave, datatype } = this.props - this.form.validateFields((error, values) => { - if (datatype === 'number') { - Object.keys(values).forEach(key => { - values[key] = parseFloat(values[key]) - }) - } - handleSave({ ...record, ...values }) - if (error && error[e.currentTarget.id]) { - return - } - this.toggleEdit() - }) + save = () => { + const { record, handleSave, dataIndex } = this.props + const { value } = this.state + + handleSave({ ...record, [dataIndex]: value }) + + this.setState({ editing: false, value: '' }) } - renderCell = form => { - this.form = form - const { children, dataIndex, record, datatype } = this.props + changeUrl = (val) => { + const { record, handleSave, dataIndex } = this.props + + handleSave({ ...record, [dataIndex]: val }) + } + + renderCell = () => { + const { dataIndex, inputType, record } = this.props const { editing } = this.state - let rules = [] - if (datatype === 'number') { - rules.push({ - pattern: /^(-?\d+)(\.\d+)?$/, - message: formRule.input.numbermsg - }) + if (inputType === 'file') { + return <SourceComponent initialValue={record[dataIndex]} type="" onChange={this.changeUrl} placement="right"/> } - return editing ? ( - <Form.Item style={{ margin: 0 }}> - {form.getFieldDecorator(dataIndex, { - rules: [ - { - required: dataIndex === 'Value' || dataIndex === 'Text', - message: 'NOT NULL.', - }, - ...rules - ], - 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> - ) + if (!editing) { + return ( + <div + className="editable-cell-value-wrap" + onClick={this.trigger} + > + {record[dataIndex]} + </div> + ) + } else { + return <Input ref={node => (this.input = node)} defaultValue={record[dataIndex]} autoComplete="off" onChange={(e) => this.setState({value: e.target.value})} onPressEnter={this.save} onBlur={this.save} /> + } } render() { - const { - editable, - dataIndex, - title, - record, - index, - handleSave, - children, - ...restProps - } = this.props + const { editable, dataIndex, index } = this.props + + if (dataIndex === '$move') { + return (<DragableTd key={index} {...this.props} />) + } + + if (editable) { + return ( + <td>{this.renderCell()}</td> + ) + } + return ( - <td {...restProps}> - {editable ? ( - <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer> - ) : ( - children - )} - </td> + <td {...this.props}/> ) } } class EditTable extends Component { - constructor(props) { - super(props) - - let _width = '40%' - let fields = [] - let dataItem = props.data ? props.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 => { - return { - title: field.label, - dataIndex: field.field, - width: _width, - editable: true, - datatype: dataItem && typeof(dataItem[field.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' - }, - ...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 - 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> - </Popconfirm> - </div> - ) : null, - } - ] - - if (props.type === 'link') { - columns.unshift({ - title: 'ParentID', - dataIndex: 'ParentID', - width: '27%', - editable: true, - datatype: dataItem && typeof(dataItem.ParentID) === 'number' ? 'number' : 'string' - }) - } - - this.state = { - 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 - } + static propTpyes = { + type: PropTypes.any, + module: PropTypes.string, + columns: PropTypes.array, + onChange: PropTypes.func } - getColumnSearchProps = column => ({ - filterDropdown: () => ( - <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}} /> - ) - }) + state = { + columns: [], + dataSource: [], + count: 0 + } - changeDatatype = (column, e) => { - const { columns, dataSource } = this.state - let value = e.target.value + UNSAFE_componentWillMount () { + const { columns, value } = this.props + let data = value || [] this.setState({ - dataSource: dataSource.map(item => { - let val = item[column.dataIndex] - if (value === 'number') { - try { - val = parseFloat(val) - if (isNaN(val)) { - val = '' - } - } catch { - val = '' - } - } else { - val = '' + val - } - - item[column.dataIndex] = val - + columns: this.getColumns(), + dataSource: data.map(item => { + columns.forEach(n => { + if (item[n.key] !== undefined) return + item[n.key] = ['ParentID', '$url', '$color', '$value'].includes(n.key) ? '' : item.Text || '' + }) return item }), - columns: columns.map(col => { - if (col.dataIndex === column.dataIndex) { - col.datatype = value - } - - if (col.dataIndex !== 'operation') { - col = {...col, ...this.getColumnSearchProps(col)} - } - - return col - }) + count: data.length }) } - handleUpDown = (record, direction) => { + moveRow = (dragId, hoverId) => { const { dataSource } = this.state - let index = 0 - - let _data = dataSource.filter((item, i) => { - if (item.key === record.key) { - index = i + let dragIndex = -1 + let hoverIndex = -1 + + dataSource.forEach((item, i) => { + if (item.key === dragId) { + dragIndex = i + } else if (item.key === hoverId) { + hoverIndex = i } - - return item.key !== record.key }) - if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) { - return - } + + if (dragIndex === -1 || hoverIndex === -1) return - if (direction === 'up') { - _data.splice(index - 1, 0, record) - } else { - _data.splice(index + 1, 0, record) - } + let _data = fromJS(dataSource).toJS() + + _data.splice(hoverIndex, 0, ..._data.splice(dragIndex, 1)) this.setState({ dataSource: _data + }, () => { + this.props.onChange(_data) }) } - handleDelete = key => { - const dataSource = [...this.state.dataSource] - this.setState({ dataSource: dataSource.filter(item => item.key !== key) }) + handleHide = (key) => { + let _data = this.state.dataSource.map(item => { + if (item.key === key) { + item.Hide = !item.Hide + } + return item + }) + + this.setState({ + dataSource: _data + }, () => { + this.props.onChange(_data) + }) + } + + handleDelete = (key) => { + const { dataSource } = this.state + let _data = dataSource.filter(item => item.key !== key) + + this.setState({ dataSource: _data }, () => { + this.props.onChange(_data) + }) } handleAdd = () => { - const { type, count, dataSource } = this.state - const newData = { - key: Utils.getuuid(), - Value: `${count}`, - Text: `${count}` + const { columns } = this.props + const { count, dataSource } = this.state + + let item = { key: Utils.getuuid() } + + columns.forEach(m => { + item[m.key] = '' + }) + + if (item.Value === '') { + item.Value = `${count + 1}` } - if (type === 'link') { - newData.ParentID = `${count}` + if (item.$value === '') { + item.$value = `${count + 1}` } + + item.Text = `${count + 1}` + + let _data = [...dataSource, item] + this.setState({ - dataSource: [...dataSource, newData], + dataSource: _data, count: count + 1 + }, () => { + this.props.onChange(_data) }) } handleSave = row => { + const { columns, type } = this.props const newData = [...this.state.dataSource] const index = newData.findIndex(item => row.key === item.key) const item = newData[index] + + if (type === 'proc') { + // if (!row.origin || /^\s+$/.test(row.origin)) { + // message.warning(columns[0].title + '涓虹┖鏃舵棤鏁堬紒') + // } + } else { + let val = '' + let repeat = false + let _type = '' + columns.forEach(col => { + if (!col.strict) return + + if (col.key === 'ParentID') { + _type = 'mutil' + } + + val += row[col.key] + }) + + newData.forEach(item => { + if (row.key === item.key) return + + let _val = '' + columns.forEach(col => { + if (!col.strict) return + + _val += item[col.key] + }) + + if (val === _val) { + repeat = true + } + }) + if (repeat) { + if (_type === 'mutil') { + message.warning('鐩稿悓ParentID涓嬶紝姝alue鍊煎凡瀛樺湪锛�') + } else { + message.warning('姝alue鍊煎凡瀛樺湪锛�') + } + } + } + newData.splice(index, 1, { ...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 = [] + getColumns = () => { + const { columns } = this.props - 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 + let fields = [{ + title: ' ', + width: '60px', + dataIndex: '$move', + onCell: (record) => ({ + index: record.key, + dataIndex: '$move', + moveRow: this.moveRow }) - } - - let dataItem = dataSource ? dataSource[0] : '' - - 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, + }] + columns.forEach(n => { + let col = { + title: n.title, + dataIndex: n.key, + onCell: record => ({ + record, editable: true, - datatype: dataItem && typeof(dataItem[field.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' - }, - ...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 - 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> - </Popconfirm> - </div> - ) : null, + inputType: n.type || 'text', + dataIndex: n.key, + handleSave: this.handleSave + }) } - ] - if (type === 'link') { - columns.unshift({ - title: 'ParentID', - dataIndex: 'ParentID', - width: '27%', - editable: true, - datatype: dataItem && typeof(dataItem.ParentID) === 'number' ? 'number' : 'string' - }) + if (n.width) { + col.width = n.width + } + if (n.fixed) { + delete col.onCell + } + + fields.push(col) + }) + + fields.push({ + title: '鎿嶄綔', + align: 'center', + width: '110px', + dataIndex: 'operation', + render: (text, record) => + ( + <div style={{fontSize: '15px'}}> + <span className="operation-btn" title="鏄剧ず/闅愯棌" onClick={() => this.handleHide(record.key)} style={{color: 'rgb(142, 68, 173)'}}><SwapOutlined /></span> + <Popconfirm + title="纭畾鍒犻櫎鍚楋紵" + overlayClassName="popover-confirm" + onConfirm={() => this.handleDelete(record.key) + }> + <span style={{color: '#ff4d4f', cursor: 'pointer'}}><DeleteOutlined /></span> + </Popconfirm> + </div> + ) + }) + + return fields + } + + handleEmpty = () => { + const { columns, module } = this.props + const { dataSource } = this.state + + if (dataSource.filter(item => item.Value === '').length > 0) { + message.warning('Value涓虹┖宸插瓨鍦紒') + return } + + let item = { key: Utils.getuuid() } + + columns.forEach(m => { + item[m.key] = '' + }) + + item.Text = module === 'form' ? '绌�' : '鍏ㄩ儴' + + let _data = [item, ...dataSource] this.setState({ - columns: columns.map(col => { - if (col.dataIndex !== 'operation') { - col = {...col, ...this.getColumnSearchProps(col)} - } - return col - }), - dataSource: dataSource, - type: type + dataSource: _data, + }, () => { + this.props.onChange(_data) + }) + } + + resetColumn = () => { + const { columns, value } = this.props + + let data = fromJS(value).toJS().map(item => { + columns.forEach(n => { + if (item[n.key] !== undefined) return + item[n.key] = ['ParentID', '$url', '$color', '$value'].includes(n.key) ? '' : item.Text || '' + }) + return item + }) + + this.setState({ + columns: this.getColumns(), + dataSource: data, + count: data.length + }, () => { + this.props.onChange(data) }) } 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 + if (!is(fromJS(this.props.columns), fromJS(nextProps.columns))) { + this.setState({}, () => { + this.resetColumn() }) } } render() { - const { dataSource } = this.state + const { module } = this.props + const { dataSource, columns } = 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, - datatype: col.datatype, - handleSave: this.handleSave, - }) - } - }) + return ( <div className="common-modal-edit-table"> - <Icon className="add-row" type="plus" onClick={this.handleAdd} /> - <Table - components={components} - rowClassName={() => 'editable-row'} - bordered - dataSource={dataSource} - columns={columns} - pagination={false} - /> + {module ? <span className="add-row add-row-empty" onClick={this.handleEmpty}>{module === 'form' ? '绌�' : '鍏ㄩ儴'}</span> : null} + <PlusOutlined className="add-row" onClick={this.handleAdd} /> + <DndProvider> + <Table + components={components} + rowClassName={(record) => record.Hide ? 'editable-row hide' : 'editable-row'} + bordered + dataSource={dataSource} + columns={columns} + pagination={false} + /> + </DndProvider> </div> ) } -- Gitblit v1.8.0