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