king
2023-08-27 da64ab0923bf8817fc8599a6e37b953ce38f64c8
src/templates/zshare/modalform/datatable/index.jsx
@@ -1,19 +1,87 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Table, Input, Popconfirm, Form, Icon, notification } from 'antd'
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 FileUpload from '@/tabviews/zshare/fileupload'
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 } = this.props
    const { inputType, record } = this.props
    if (inputType === 'file') {
      return <FileUpload maxFile={1} fileType="picture-card"/>
      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)} />
    }
@@ -26,15 +94,6 @@
        return
      }
      if (row.$url && Array.isArray(row.$url)) {
        if (!row.$url[0]) {
          row.$url = ''
        } else if (row.$url[0].origin) {
          row.$url = row.$url[0].url || ''
        } else if (!row.$url[0].origin && row.$url[0].status === 'done' && row.$url[0].response) {
          row.$url = row.$url[0].response
        }
      }
      this.props.onSave({...record, ...row})
    })
  }
@@ -59,29 +118,17 @@
      _val = record[dataIndex]
    }
    if (dataIndex === '$url' && _val) {
      _val = [{
        uid: `10086`,
        name: _val.slice(_val.lastIndexOf('/') + 1),
        status: 'done',
        url: _val,
        origin: true
      }]
    } else if (dataIndex === '$url') {
      _val = []
    }
    return (
      <td {...restProps}>
        {editing ? (
          <Form.Item style={{ margin: 0 }}>
          <Form.Item style={{ margin: '0 -5px 0 -5px' }}>
            {getFieldDecorator(dataIndex, {
              rules: [
                {
                  required: dataIndex === '$value',
                  message: `Please Input ${title}!`,
                },
              ],
              // rules: [
              //   {
              //     required: dataIndex === '$value',
              //     message: `Please Input ${title}!`,
              //   },
              // ],
              initialValue: _val,
            })(this.getInput(form))}
          </Form.Item>
@@ -99,9 +146,11 @@
class EdiDataTable extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    type: PropTypes.object,         // 数据类型,文本、图片
    transfield: PropTypes.object,   // 字段名称
    type: PropTypes.string,         // 是否为关联表单
    display: PropTypes.string,      // 数据类型,文本、图片
    fields: PropTypes.array,        // 字段集
    linkSubFields: PropTypes.array, // 填充字段
    onChange: PropTypes.func        // 数据变化
  }
@@ -121,7 +170,13 @@
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.fields), fromJS(nextProps.fields)) || !is(fromJS(this.props.type), fromJS(nextProps.type))) {
    if (
      !is(fromJS(this.props.fields), fromJS(nextProps.fields)) ||
      !is(fromJS(this.props.linkSubFields), fromJS(nextProps.linkSubFields)) ||
      this.props.display !== nextProps.display ||
      (nextProps.multiple && this.props.multiple !== nextProps.multiple) ||
      this.props.type !== nextProps.type
    ) {
      this.setState({editingKey: ''}, () => {
        this.setState({
          columns: this.getCloumns()
@@ -131,27 +186,54 @@
  }
  getCloumns = () => {
    const { type, fields } = this.props
    const { display, fields, linkSubFields, transfield, type, multiple } = this.props
    let columns = []
    let keys = ['ParentID', 'pid']
    if (type === 'picture') {
    if (display === 'picture') {
      columns.push({
        title: 'url',
        dataIndex: '$url',
        inputType: 'file',
        width: '40%',
        // 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 {
      columns = fields.map(item => ({
    } 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({
@@ -160,9 +242,26 @@
      editable: true,
    })
    if (multiple === 'dropdown' && display === 'text') {
      columns.unshift({
        title: 'pid',
        dataIndex: 'pid',
        editable: true,
      })
    }
    if (type === 'link') {
      columns.unshift({
        title: 'ParentID',
        dataIndex: 'ParentID',
        editable: true,
      })
    }
    columns.push({
      title: 'operation',
      title: '操作',
      dataIndex: 'operation',
      align: 'center',
      width: '18%',
      render: (text, record) => {
        const { editingKey } = this.state
@@ -180,17 +279,16 @@
          </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>
            <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={this.props.dict['model.query.delete']}
              title="确定删除吗?"
              onConfirm={() => this.handleDelete(record.key)
            }>
              <span className="danger"><Icon type="delete" /></span>
              <span className="danger"><DeleteOutlined /></span>
            </Popconfirm> : null}
            {editingKey !== '' ? <span className="danger"><Icon type="delete" /></span> : null}
            {editingKey !== '' ? <span className="danger"><DeleteOutlined /></span> : null}
          </div>
        )
      }
@@ -206,8 +304,20 @@
  }
  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: '' }, () => {
@@ -227,45 +337,27 @@
    })
  }
  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) {
    const { type } = this.props
    form.validateFields((error, row) => {
      if (error) {
        return;
      }
      if (row.$url && Array.isArray(row.$url)) {
        if (!row.$url[0]) {
          row.$url = ''
        } else if (row.$url[0].origin) {
          row.$url = row.$url[0].url || ''
        } else if (!row.$url[0].origin && row.$url[0].status === 'done' && row.$url[0].response) {
          row.$url = row.$url[0].response
      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值已存在!')
        }
      }
      const newData = [...this.state.data]
      const index = newData.findIndex(item => key === item.key)
      if (index > -1) {
        const item = newData[index]
        newData.splice(index, 1, {
@@ -285,36 +377,31 @@
  }
  handleAdd = () => {
    const { fields, type } = this.props
    if (this.state.editingKey) {
    const { fields, display } = this.props
    if (this.state.data.length >= 100) {
      notification.warning({
        top: 92,
        message: '请保存编辑中的元素!',
        duration: 5
      })
      return
    } else if (this.state.data.length >= 20) {
      notification.warning({
        top: 92,
        message: '最多可添加20项!',
        message: '最多可添加100项!',
        duration: 5
      })
      return
    }
    let item = { key: Utils.getuuid(), $value: `${this.state.data.length + 1}` }
    let item = { key: Utils.getuuid(), $value: `${this.state.data.length + 1}`, ParentID: '' }
    if (type === 'picture') {
    if (display === 'picture') {
      item.$url = ''
    } else {
      fields.forEach(f => {
        item[f.field] = `${this.state.data.length + 1}`
      })
    } 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 }, () => {
    this.setState({ data, editingKey: '' }, () => {
      this.props.onChange(data)
    })
  }
@@ -323,11 +410,43 @@
    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: {
        cell: EditableCell,
      },
        row: DragableBodyRow,
        cell: EditableCell
      }
    }
    const columns = this.state.columns.map(col => {
@@ -348,24 +467,32 @@
    })
    let addable = false
    if (this.props.type === 'picture') {
    if (display === 'picture' || display === 'color') {
      addable = true
    } else if (this.props.fields && this.props.fields.length > 0) {
    } else if (fields && fields.length > 0) {
      addable = true
    }
    return (
      <EditableContext.Provider value={this.props.form}>
        <div className="modal-card-data-table">
          {addable ? <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}
          />
          {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>
    )