king
2020-10-23 407c0f1765c7d085218a91ad8842784977383d05
src/menu/modalconfig/index.jsx
@@ -5,14 +5,13 @@
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import moment from 'moment'
import { Button, Card, Modal, Collapse, notification, Select, List, Icon, Empty, Popover } from 'antd'
import { Button, Card, Modal, Collapse, notification, Icon, Empty, Popover } from 'antd'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getModalForm } from '@/templates/zshare/formconfig'
import { queryTableSql } from '@/utils/option.js'
import ModalForm from '@/templates/zshare/modalform'
import DragElement from '@/templates/modalconfig/dragelement'
@@ -20,28 +19,19 @@
import SettingForm from '@/templates/modalconfig/settingform'
import GroupForm from '@/templates/modalconfig/groupform'
import EditCard from '@/templates/modalconfig/editcard'
import MenuForm from '@/templates/modalconfig/menuform'
import EditComponent from '@/templates/zshare/editcomponent'
import { BaseConfig, SearchItems } from '@/templates/modalconfig/source'
import { SearchItems } from '@/templates/modalconfig/source'
import './index.scss'
const { Panel } = Collapse
const { Option } = Select
const { confirm } = Modal
const CommonDict = localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
class ComModalConfig extends Component {
  static propTpyes = {
    menu: PropTypes.any,
    editTab: PropTypes.any,
    editSubTab: PropTypes.any,
    tabConfig: PropTypes.any,
    subTabConfig: PropTypes.any,
    btnTab: PropTypes.any,
    btnTabConfig: PropTypes.any,
    editAction: PropTypes.object,
    subConfig: PropTypes.any,
    handleView: PropTypes.func
    btn: PropTypes.object,
    handleSave: PropTypes.func,
    handleBack: PropTypes.func
  }
  state = {
@@ -49,14 +39,11 @@
    dict: CommonDict,      // 字典
    config: null,          // 页面配置,包括模板类型、模态框设置、添加表名、表单列表
    visible: false,        // 表单编辑模态框,显示控制
    modalType: null,       // 表单编辑类型,编辑或复制
    tableVisible: false,   // 数据表字段列表模态框,显示控制
    tableColumns: [],      // 表格字段名列表
    fields: null,          // 表单,可选字段(去重后)
    modalformlist: null,   // 基本信息表单字段
    formlist: null,        // 表单编辑模态框,可编辑字段
    card: null,            // 编辑元素
    menuloading: false,    // 菜单保存中
    closeloading: false,   // 菜单保存中
    settingVisible: false, // 全局配置模态框
    closeVisible: false,   // 关闭模态框
@@ -72,73 +59,15 @@
  /**
   * @description 数据预处理
   * 1、按钮配置存在时使用按钮配置,不存在时使用默认配置(示例)
   * 2、模态框标题不存在时,使用按钮标题
   * 3、设置已选表
   * 4、设置按钮基本信息
   */
  UNSAFE_componentWillMount () {
    const {menu, editAction, tabConfig, subTabConfig, subConfig} = this.props
    const { btn } = this.props
    let _config = ''
    let _tab = subTabConfig ? subTabConfig : tabConfig
    let _menu = { // 上级菜单是三级菜单或标签页
      type: _tab ? _tab.Template : menu.type,
      tables: _tab ? _tab.tables : menu.LongParam.tables,
      MenuID: _tab ? _tab.uuid : menu.MenuID,
      MenuNo: _tab ? _tab.tabNo : menu.MenuNo,
      MenuName: _tab ? _tab.tabName : menu.MenuName
    }
    if (subConfig) {
      _config = subConfig
    } else {
      _config = JSON.parse(JSON.stringify(BaseConfig))
    }
    if (!_config.setting.title) {
      _config.setting.title = editAction.label
    }
    // 主菜单已有选择的表名,模态框没有表名时,复制主菜单表名
    _config.tables = _config.tables.length === 0 ? _menu.tables : _config.tables
    let _source = JSON.parse(JSON.stringify(SearchItems))
    if (!!this.props.editTab) {
      _source.push({
        type: 'form',
        label: this.state.dict['header.form.linkMain'],
        subType: 'linkMain',
        url: ''
      })
    }
    let _config = btn.modal
    this.setState({
      openEdition: editAction.open_edition || '',
      menu: _menu,
      source: _source,
      config: _config,
      selectedTables: _config.tables || [],
      originConfig: JSON.parse(JSON.stringify(_config)),
      modalformlist: [
        {
          type: 'text',
          key: 'supMenu',
          label: this.state.dict['model.super'] + this.state.dict['model.menu'],
          initVal: _menu.MenuName,
          required: true,
          readonly: true
        },
        {
          type: 'text',
          key: 'btnName',
          label: '按钮名称',
          initVal: editAction.label,
          required: true,
          readonly: true
        }
      ]
      originConfig: fromJS(_config).toJS()
    })
  }
@@ -148,90 +77,7 @@
   * 2、根据已选表名,获取表格字段列表
   */
  componentDidMount () {
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: queryTableSql,
      obj_name: 'data',
      arr_field: 'TbName,Remark'
    }
    param.LText = Utils.formatOptions(param.LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
    Api.getSystemConfig(param).then(res => {
      if (res.status) {
        this.setState({
          tables: res.data
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
        })
      }
    })
    let deffers = this.state.selectedTables.map(item => {
      return new Promise(resolve => {
        Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: item.TbName}).then(res => {
          res.TBName = item.TbName
          resolve(res)
        })
      })
    })
    // 获取字段后数据处理,根据类型分为text、number、datetime、date
    Promise.all(deffers).then(response => {
      let _columns = []
      response.forEach(res => {
        if (res.status) {
          let tabmsg = {
            tableName: res.TBName,
            columns: res.FDName.map(item => {
              let _type = item.FieldType.toLowerCase()
              let _decimal = 0
              if (/^nvarchar/.test(_type)) {
                _type = 'text'
              } else if (/^int/.test(_type)) {
                _type = 'number'
              } else if (/^decimal/.test(_type)) {
                _decimal = _type.split(',')[1]
                _decimal = parseInt(_decimal)
                _type = 'number'
              } else if (/^datetime/.test(_type)) {
                _type = 'datetime'
              } else if (/^date/.test(_type)) {
                _type = 'date'
              } else {
                _type = 'text'
              }
              return {
                field: item.FieldName,
                label: item.FieldDec,
                type: _type,
                decimal: _decimal
              }
            })
          }
          _columns.push(tabmsg)
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
        }
      })
      this.setState({
        tableColumns: _columns
      })
    })
  }
  /**
@@ -243,28 +89,6 @@
    }
  }
  // 页面返回
  handleViewBack = () => {
    const {menu, editTab, editSubTab, tabConfig, subTabConfig, btnTab, btnTabConfig} = this.props
    let _view = (subTabConfig && subTabConfig.Template) || (tabConfig && tabConfig.Template) || menu.LongParam.Template
    let param = {
      editMenu: menu,
      editTab: editTab,
      tabConfig: tabConfig,
      editSubTab: editSubTab,
      subTabConfig: subTabConfig,
      btnTab: btnTab,
      btnTabConfig: btnTabConfig,
      editAction: null,
      subConfig: subTabConfig || tabConfig || null,
      tabview: _view
    }
    this.props.handleView(param)
  }
  /**
   * @description 表单变化
   * 1、表单拖拽添加时,检查是否存在示例表单,如存在则去除示例
@@ -272,7 +96,7 @@
   * 3、新增表单时,直接打开编辑框
   */
  handleList = (list, group, elementId, newcard) => {
    let _config = JSON.parse(JSON.stringify(this.state.config))
    let _config = fromJS(this.state.config).toJS()
    if (!group && !elementId) {
      // 没有分组时(拖拽添加)
@@ -352,31 +176,9 @@
   * 2、保存编辑项-card
   * 3、设置编辑参数项-formlist
   */
  handleForm = (_card, type) => {
    const {menu, tabConfig, subTabConfig} = this.props
    let card = JSON.parse(JSON.stringify(_card))
    if (type === 'copy') {
      card.originUuid = card.uuid
      card.uuid = Utils.getuuid()
      card.focus = true
      // 复制到剪切板
      let oInput = document.createElement('input')
      let val = JSON.parse(JSON.stringify(card))
      val.copyType = 'form'
      val.uuid = Utils.getuuid()
      delete val.originUuid
      oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
      document.body.appendChild(oInput)
      oInput.select()
      document.execCommand('Copy')
      oInput.className = 'oInput'
      oInput.style.display = 'none'
      document.body.removeChild(oInput)
    }
  handleForm = (_card) => {
    const { componentConfig } = this.props
    let card = fromJS(_card).toJS()
    const { config } = this.state
    let _inputfields = []
@@ -419,40 +221,17 @@
      }
    })
    if (subTabConfig) {
      subTabConfig.columns.forEach(col => {
        if (col.field && !uniq.has(col.field)) {
          uniq.set(col.field, true)
    componentConfig.columns.forEach(col => {
      if (col.field && !uniq.has(col.field)) {
        uniq.set(col.field, true)
          _linkableFields.push({
            value: col.field,
            text: col.label + ' (显示列)'
          })
        }
      })
    } else if (tabConfig) {
      tabConfig.columns.forEach(col => {
        if (col.field && !uniq.has(col.field)) {
          uniq.set(col.field, true)
          _linkableFields.push({
            value: col.field,
            text: col.label + ' (显示列)'
          })
        }
      })
    } else if (menu.LongParam) {
      menu.LongParam.columns.forEach(col => {
        if (col.field && !uniq.has(col.field)) {
          uniq.set(col.field, true)
          _linkableFields.push({
            value: col.field,
            text: col.label + ' (显示列)'
          })
        }
      })
    }
        _linkableFields.push({
          value: col.field,
          text: col.label + ' (显示列)'
        })
      }
    })
    if (card.linkSubField && card.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
@@ -472,7 +251,6 @@
    this.setState({
      visible: true,
      modalType: type,
      card: card,
      formlist: getModalForm(card, _inputfields, _linkableFields, _linksupFields, !!this.props.editTab, roleList)
    })
@@ -485,70 +263,14 @@
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    const { card, modalType } = this.state
    this.formRef.handleConfirm().then(res => {
      let _config = JSON.parse(JSON.stringify(this.state.config))
      let _config = fromJS(this.state.config).toJS()
      let fieldrepet = false // 字段重复
      let labelrepet = false // 提示文字重复
      if (modalType === 'copy' && card.originUuid) {
        if (_config.groups.length > 0) {
          _config.groups = _config.groups.map(group => {
            let _index = null
            group.sublist.forEach((item, index) => {
              if (item.uuid === card.originUuid) {
                _index = index
              }
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              } else if (item.uuid !== res.uuid && item.label === res.label) {
                labelrepet = true
              }
            })
            if (_index !== null) {
              group.sublist.splice(_index + 1, 0, res)
            }
            return group
          })
        } else {
          let _index = null
          _config.fields.forEach((item, index) => {
            if (item.uuid === card.originUuid) {
              _index = index
            }
            if (item.uuid !== res.uuid && item.field === res.field) {
              fieldrepet = true
            } else if (item.uuid !== res.uuid && item.label === res.label) {
              labelrepet = true
            }
          })
          _config.fields.splice(_index + 1, 0, res)
        }
      } else {
        if (_config.groups.length > 0) {
          _config.groups.forEach(group => {
            group.sublist = group.sublist.map(item => {
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              } else if (item.uuid !== res.uuid && item.label === res.label) {
                labelrepet = true
              }
              if (item.uuid === res.uuid) {
                return res
              } else {
                return item
              }
            })
          })
        } else {
          _config.fields = _config.fields.map(item => {
      if (_config.groups.length > 0) {
        _config.groups.forEach(group => {
          group.sublist = group.sublist.map(item => {
            if (item.uuid !== res.uuid && item.field === res.field) {
              fieldrepet = true
            } else if (item.uuid !== res.uuid && item.label === res.label) {
@@ -561,7 +283,21 @@
              return item
            }
          })
        }
        })
      } else {
        _config.fields = _config.fields.map(item => {
          if (item.uuid !== res.uuid && item.field === res.field) {
            fieldrepet = true
          } else if (item.uuid !== res.uuid && item.label === res.label) {
            labelrepet = true
          }
          if (item.uuid === res.uuid) {
            return res
          } else {
            return item
          }
        })
      }
      if (fieldrepet) {
@@ -607,7 +343,6 @@
            this.setState({
              sqlVerifing: false,
              config: _config,
              modalType: null,
              card: null,
              visible: false
            })
@@ -622,7 +357,6 @@
      } else {
        this.setState({
          config: _config,
          modalType: null,
          card: null,
          visible: false
        })
@@ -639,7 +373,7 @@
    confirm({
      content: `确定删除<<${card.label}>>吗?`,
      onOk() {
        let _config = JSON.parse(JSON.stringify(_this.state.config))
        let _config = fromJS(_this.state.config).toJS()
        if (_config.groups.length > 0) {
          _config.groups.forEach(group => {
@@ -658,108 +392,20 @@
  }
  submitConfig = () => {
    const { editAction } = this.props
    const { config, menu, openEdition } = this.state
    const { config } = this.state
    if ((!config.groups[0] && !config.fields[0]) || (config.fields[0] && config.fields[0].origin)) {
      notification.warning({
        top: 92,
        message: '请添加表单',
        duration: 10
      })
      return
    }
    let _LongParam = ''
    let _config = {...config, tables: this.state.selectedTables}
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
    } catch (e) {
      notification.warning({
        top: 92,
        message: '编译错误',
        duration: 10
      })
      return
    }
    let param = {
      func: 'sPC_ButtonParam_AddUpt',
      ParentID: menu.MenuID,
      MenuID: editAction.uuid,
      MenuNo: menu.MenuNo,
      Template: 'Modal',
      MenuName: editAction.label,
      PageParam: JSON.stringify({Template: 'Modal'}),
      LongParam: _LongParam
    }
    if (openEdition) {
      param.open_edition = openEdition
    }
    if (this.state.closeVisible) {
      this.setState({
        closeloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
    Api.getSystemConfig(param).then(response => {
      if (response.status) {
        this.setState({
          openEdition: response.open_edition || '',
          menuloading: false,
          closeloading: false,
          closeVisible: false,
          originConfig: _config,
          config: _config
        })
        notification.success({
          top: 92,
          message: '保存成功',
          duration: 2
        })
      } else {
        this.setState({
          closeloading: false,
          menuloading: false
        })
        notification.warning({
          top: 92,
          message: response.message,
          duration: 10
        })
      }
    })
    this.props.handleSave(config)
  }
  cancelConfig = () => {
    const { config, originConfig } = this.state
    let _this = this
    let isOrigin = config.fields.filter(item => item.origin).length > 0
    if (isOrigin) {
      confirm({
        content: '尚未提交,确定放弃保存吗?',
        onOk() {
          _this.handleViewBack()
        },
        onCancel() {}
    if (!is(fromJS(config), fromJS(originConfig))) {
      this.setState({
        closeVisible: true
      })
    } else {
      if (!is(fromJS(config), fromJS(originConfig))) {
        this.setState({
          closeVisible: true
        })
      } else {
        this.handleViewBack()
      }
      this.props.handleBack()
    }
  }
@@ -770,8 +416,10 @@
   * 3、检查表单中的已选字段,并标记已选
   */
  queryField = () => {
    const {selectedTables, tableColumns, config} = this.state
    if (selectedTables.length === 0) {
    const { menu } = this.props
    const { config } = this.state
    if (menu.tables.length === 0) {
      notification.warning({
        top: 92,
        message: '请选择表名!',
@@ -781,7 +429,7 @@
    }
    let columns = new Map()
    tableColumns.forEach(table => {
    menu.tableFields.forEach(table => {
      table.columns.forEach(column => {
        columns.set(column.field, column)
      })
@@ -823,7 +471,7 @@
      })
    }
    let _config = JSON.parse(JSON.stringify(this.state.config))
    let _config = fromJS(this.state.config).toJS()
    let cards = this.refs.searchcard.state.selectCards
    let columns = new Map()
@@ -865,11 +513,6 @@
          resourceType: '0',
          setAll: 'false',
          options: [],
          dataSource: '',
          linkField: '',
          valueField: '',
          valueText: '',
          orderBy: '',
          orderType: 'asc',
          decimal: 0,
          min: '',
@@ -912,11 +555,6 @@
            resourceType: '0',
            setAll: 'false',
            options: [],
            dataSource: '',
            linkField: '',
            valueField: '',
            valueText: '',
            orderBy: '',
            orderType: 'asc',
            readonly: 'false',
            required: 'true'
@@ -936,79 +574,6 @@
      top: 92,
      message: '添加成功',
      duration: 2
    })
  }
  /**
   * @description 添加表名
   * 1、获取表信息
   * 2、检验是否已经添加,已添加时跳过
   * 3、通过表名获取字段集,并设置数据类型
   */
  onTableChange = (value) => {
    const {tables, selectedTables, tableColumns} = this.state
    let _table = tables.filter(item => item.TbName === value)[0]
    let isSelected = !!selectedTables.filter(cell => cell.TbName === value)[0]
    if (isSelected) return
    this.setState({
      selectedTables: [...selectedTables, _table]
    })
    Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => {
      if (res.status) {
        let tabmsg = {
          tableName: _table.name,
          columns: res.FDName.map(item => {
            let _type = item.FieldType.toLowerCase()
            let _decimal = 0
            if (/^nvarchar/.test(_type)) {
              _type = 'text'
            } else if (/^int/.test(_type)) {
              _type = 'number'
            } else if (/^decimal/.test(_type)) {
              _decimal = _type.split(',')[1]
              _decimal = parseInt(_decimal)
              _type = 'number'
            } else if (/^datetime/.test(_type)) {
              _type = 'datetime'
            } else if (/^date/.test(_type)) {
              _type = 'date'
            } else {
              _type = 'text'
            }
            return {
              field: item.FieldName,
              label: item.FieldDec,
              type: _type,
              decimal: _decimal
            }
          })
        }
        this.setState({
          tableColumns: [...tableColumns, tabmsg]
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
        })
      }
    })
  }
  /**
   * @description 删除表名,删除对应字段集
   */
  deleteTable = (table) => {
    const {selectedTables, tableColumns} = this.state
    this.setState({
      selectedTables: selectedTables.filter(item => item.TbName !== table.TbName),
      tableColumns: tableColumns.filter(item => item.tableName !== table.TbName)
    })
  }
@@ -1061,7 +626,7 @@
    confirm({
      content: `确定删除分组<<${group.label}>>吗?`,
      onOk() {
        let _config = JSON.parse(JSON.stringify(_this.state.config))
        let _config = fromJS(_this.state.config).toJS()
        _config.groups = _config.groups.filter(item => !(item.uuid === group.uuid))
        let _length = _config.groups.length
        
@@ -1081,8 +646,8 @@
  }
  handleGroupSave = () => {
    let _group = JSON.parse(JSON.stringify(this.state.curgroup))
    let config = JSON.parse(JSON.stringify(this.state.config))
    let _group = fromJS(this.state.curgroup).toJS()
    let config = fromJS(this.state.config).toJS()
    this.groupRef.handleConfirm().then(res => {
      _group = {..._group, ...res.target}
@@ -1169,54 +734,16 @@
  }
  render () {
    const { config, source } = this.state
    const { config } = this.state
    return (
      <div className="modal-form-board">
        <DndProvider backend={HTML5Backend}>
          <div className="tools">
            <Collapse accordion defaultActiveKey="1" bordered={false}>
              <Panel header={this.state.dict['header.menu.basedata']} key="0" id="modal-basedata">
                <MenuForm
                  dict={this.state.dict}
                  formlist={this.state.modalformlist}
                />
                <div className="ant-col ant-form-item-label">
                  <label title={this.state.dict['header.menu.table.add']}>
                    {this.state.dict['header.menu.table.add']}
                  </label>
                </div>
                <Select
                  showSearch
                  showArrow={false}
                  className="tables"
                  style={{ width: '100%' }}
                  optionFilterProp="children"
                  value={this.state.dict['header.menu.table.placeholder']}
                  onChange={this.onTableChange}
                  getPopupContainer={() => document.getElementById('modal-basedata')}
                  filterOption={(input, option) => {
                    return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                  }}
                >
                  {this.state.tables.map((table, index) => (
                    <Option key={index} title={table.TbName} value={table.TbName}>{table.Remark}</Option>
                  ))}
                </Select>
                {this.state.selectedTables.length > 0 && <List
                  size="small"
                  bordered
                  dataSource={this.state.selectedTables}
                  renderItem={(item, index) => <List.Item key={index} title={item.Remark + ' (' + item.TbName + ')'}>
                    {item.Remark + ' (' + item.TbName + ')'}
                    <Icon type="close" onClick={() => this.deleteTable(item)}/>
                    <div className="bottom-mask"></div>
                  </List.Item>}
                />}
              </Panel>
              <Panel header={this.state.dict['header.menu.form']} key="1">
                <div className="search-element">
                  {source.map((item, index) => {
                  {SearchItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
@@ -1229,8 +756,8 @@
            <Card title={this.state.dict['header.menu.form.configurable']} bordered={false} extra={
              <div>
                <EditComponent dict={this.state.dict} type="form" config={this.state.config} refresh={this.updateConfig}/>
                <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['model.save']}</Button>
                <Button onClick={this.cancelConfig}>{this.state.dict['model.back']}</Button>
                <Button type="primary" onClick={this.submitConfig}>{this.state.dict['model.confirm']}</Button>
                <Button onClick={this.cancelConfig}>{this.state.dict['model.cancel']}</Button>
              </div>
            } style={{ width: '100%' }}>
              <Icon type="setting" onClick={this.changeSetting} />
@@ -1299,7 +826,7 @@
          </div>
        </DndProvider>
        <Modal
          title={this.state.modalType !== 'copy' ? this.state.dict['model.edit'] : this.state.dict['header.modal.form.copy']}
          title={this.state.dict['model.edit']}
          visible={this.state.visible}
          width={700}
          onCancel={this.editModalCancel}
@@ -1359,7 +886,7 @@
          onCancel={() => { this.setState({closeVisible: false}) }}
          footer={[
            <Button key="save" className="mk-btn mk-green" loading={this.state.closeloading} onClick={this.submitConfig}>{this.state.dict['model.save']}</Button>,
            <Button key="confirm" className="mk-btn mk-yellow" onClick={this.handleViewBack}>{this.state.dict['model.notsave']}</Button>,
            <Button key="confirm" className="mk-btn mk-yellow" onClick={this.props.handleBack}>{this.state.dict['model.notsave']}</Button>,
            <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['model.cancel']}</Button>
          ]}
          destroyOnClose
@@ -1390,7 +917,8 @@
const mapStateToProps = (state) => {
  return {
    sysRoles: state.sysRoles
    sysRoles: state.sysRoles,
    menu: state.customMenu
  }
}