king
2021-12-30 09e0de52a398dd08a0dc3f4b43e4589d211e9c27
src/templates/formtabconfig/index.jsx
@@ -5,47 +5,48 @@
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import moment from 'moment'
import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty, Switch, Tooltip } from 'antd'
import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Empty, Switch, Tooltip } from 'antd'
import { QuestionCircleOutlined, CloseOutlined, RedoOutlined, SettingOutlined, PlusOutlined, DeleteOutlined, EditOutlined, SnippetsOutlined } from '@ant-design/icons'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/comtable.js'
import enUS from '@/locales/en-US/comtable.js'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import Utils, { FuncUtils } from '@/utils/utils.js'
import { getModalForm, getActionForm } from '@/templates/zshare/formconfig'
import { queryTableSql } from '@/utils/option.js'
import ModalForm from '@/templates/zshare/modalform'
import TabsComponent from '@/templates/sharecomponent/tabscomponent'
import PasteForm from '@/templates/zshare/pasteform'
import ActionForm from './actionform'
import SettingForm from './settingform'
import DragElement from './dragelement'
import GroupForm from './groupform'
import TabForm from '@/templates/zshare/tabform'
import EditCard from '@/templates/zshare/editcard'
import VerifyCard from '@/templates/zshare/verifycard'
import MenuForm from '@/templates/zshare/menuform'
import TabDragElement from '@/templates/zshare/tabdragelement'
import SourceElement from '@/templates/zshare/dragelement/source'
import CreateFunc from '@/templates/zshare/createfunc'
import SourceElement from '@/templates/zshare/dragsource'
import asyncComponent from '@/utils/asyncComponent'
import Source from './source'
import './index.scss'
const { Panel } = Collapse
const { Option } = Select
const { confirm } = Modal
const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
const CreateFunc = asyncComponent(() => import('@/templates/zshare/createfunc'))
const VerifyCard = asyncComponent(() => import('@/templates/zshare/verifycard'))
class ComTableConfig extends Component {
  static propTpyes = {
    menu: PropTypes.any,
    optionLibs: PropTypes.any,
    btnTab: PropTypes.object,
    config: PropTypes.any,
    handleView: PropTypes.func
  }
  state = {
    dict: CommonDict,        // 字典
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,        // 字典
    config: null,            // 页面配置
    modaltype: '',           // 模态框类型,控制模态框显示
    tableVisible: false,     // 数据表字段模态框
@@ -67,10 +68,10 @@
    profileVisible: false,   // 验证信息模态框
    editgroup: null,         // 当前编辑组
    groupVisible: false,     // 编辑组模态框
    optionLibs: null,        // 自定义下拉选项库
    activeKey: '0',          // 默认展开基本信息
    pasteVisible: false,     // 粘贴模态框
    sqlVerifing: false       // sql验证
    sqlVerifing: false,      // sql验证
    openEdition: ''          // 编辑版本标记,防止多人操作
  }
  /**
@@ -79,7 +80,7 @@
   * 2、设置操作类型、原始菜单信息(每次保存后重置)、已使用表及基本信息表单
   */
  UNSAFE_componentWillMount () {
    const { menu, btnTab, config, optionLibs } = this.props
    const { menu, btnTab, config } = this.props
    let _config = ''
    let columns = []
@@ -103,34 +104,43 @@
      if (menu && menu.LongParam && menu.LongParam.setting) {
        _config.setting.primaryKey = menu.LongParam.setting.primaryKey
      }
    }
      _config.groups.forEach(group => {
        group.sublist.forEach(item => {
          if (
            (item.type === 'select' || item.type === 'multiselect' || item.type === 'link') &&
            item.resourceType === '0' &&
            item.options && item.options.length > 0
          ) {
            optionLibs.set(btnTab.uuid + item.uuid, {
              uuid: btnTab.uuid + item.uuid,
              label: item.label,
              parname: btnTab.label,
              type: 'Modal',
              options: item.options
            })
          }
        })
    if (!_config.tabgroups) {
      _config.tabgroups = [{ uuid: 'tabs', sublist: [] }]
    } else if (typeof(_config.tabgroups[0]) === 'string') {
      let _tabgroups = []
      _config.tabgroups.forEach(groupId => {
        let _group = {
          uuid: groupId,
          sublist: fromJS(_config[groupId]).toJS()
        }
        delete _config[groupId]
        _tabgroups.push(_group)
      })
      _config.tabgroups = _tabgroups
    }
    if (menu && menu.LongParam && menu.LongParam.columns) {
      columns = menu.LongParam.columns
    }
    // 配置默认值,兼容
    _config.Template = 'FormTab'
    _config.action = _config.action.map(item => {
      if (item.intertype === 'inner' && !item.innerFunc) {
        item.intertype = 'system'
      }
      return item
    })
    this.setState({
      config: _config,
      activeKey: btnTab.activeKey || '0',
      optionLibs: optionLibs,
      openEdition: btnTab.open_edition || '',
      columns: columns,
      originMenu: JSON.parse(JSON.stringify(_config)),
      selectedTables: _config.tables,
@@ -138,7 +148,7 @@
        {
          type: 'text',
          key: 'menuName',
          label: this.state.dict['header.menu.menuName'],
          label: this.state.dict['model.menu'] + this.state.dict['model.name'],
          initVal: menu.MenuName,
          readonly: true
        },
@@ -168,8 +178,10 @@
    }
    param.LText = Utils.formatOptions(param.LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    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) {
@@ -180,7 +192,7 @@
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
          duration: 5
        })
      }
    })
@@ -242,7 +254,7 @@
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
            duration: 5
          })
        }
      })
@@ -269,7 +281,7 @@
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
          duration: 5
        })
      }
    })
@@ -318,7 +330,7 @@
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
          duration: 5
        })
      }
    })
@@ -330,7 +342,6 @@
    let _tabview = menu ? menu.LongParam.Template : ''
    let param = {
      editMenu: menu,
      optionLibs: this.state.optionLibs,
      editTab: null,
      tabConfig: null,
      editSubTab: null,
@@ -348,15 +359,7 @@
  handleList = (type, list, card, groupId, elementId) => {
    const { config } = this.state
    if (type === 'tabs') { // 标签页调整顺序或添加元素
      if (list.length > config[card.groupId].length) {
        list = list.filter(item => !item.origin)
        this.handleTab(card)
      }
      this.setState({config: {...config, [card.groupId]: list}})
    } else if (type === 'action') {
    if (type === 'action') {
      if (list.length > config.action.length) {
  
        this.handleAction(card)
@@ -425,21 +428,19 @@
    const { menu } = this.props
    const { config } = this.state
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = [{
      value: '',
      text: '空'
    }]
    let _linksupFields = []
    let _formfields = []
    // 设置下拉菜单可关联字段
    config.groups.forEach(group => {
      let sublist = group.sublist.filter(item => item.type === 'text' || item.type === 'number')
      _inputfields = [..._inputfields, ...sublist]
      let suplist = group.sublist.filter(item => item.type === 'select' || item.type === 'link')
        _formfields = [..._formfields, ...suplist]
      _formfields = [..._formfields, ...group.sublist]
    })
    _inputfields = _formfields.filter(item => ['text', 'number', 'textarea', 'color'].includes(item.type) && card.field !== item.field)
    _tabfields = _formfields.filter(item => card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
    _tabfields.unshift({field: '', text: '原表单'})
    
    if (card.linkSubField && card.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
@@ -450,6 +451,7 @@
    uniq.set(card.field, true)
    _formfields.forEach(item => {
      if (item.type !== 'select' && item.type !== 'link') return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
@@ -477,150 +479,37 @@
      })
    }
    let roleList = []
    if (this.props.sysRoles && this.props.sysRoles.length > 0) {
      roleList = this.props.sysRoles.map(role => {
        return {
          uuid: role.uuid,
          field: role.value,
          label: role.text
        }
      })
    }
    this.setState({
      modaltype: 'search',
      card: card,
      formlist: getModalForm(card, _inputfields, _linkableFields, _linksupFields, false, roleList)
      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields).map(item => {
        if (item.key === 'type') {
          item.options = item.options.filter(option => !['switch', 'checkbox', 'radio', 'checkcard', 'hint'].includes(option.value))
        }
        return item
      })
    })
  }
  handleAction = (card) => {
    let ableField = this.props.permFuncField.join(', ')
    let functip = <div>
      <p style={{marginBottom: '5px'}}>{this.state.dict['header.modal.func.innerface'].replace('@ableField', ableField)}</p>
      <p>{this.state.dict['header.modal.func.outface']}</p>
    </div>
    let usefulFields = sessionStorage.getItem('permFuncField')
    if (usefulFields) {
      try {
        usefulFields = JSON.parse(usefulFields)
      } catch (e) {
        usefulFields = []
      }
    } else {
      usefulFields = []
    }
    this.setState({
      modaltype: 'actionEdit',
      card: card,
      formlist: getActionForm(card, functip, this.state.config, this.props.permFuncField)
      formlist: getActionForm(card, this.state.config, usefulFields)
    })
  }
  handleTab = (card) => {
    const { config } = this.state
    let menus = [
      {value: '', text: '空'},
      {value: 'mainTable', text: '主数据'}
    ]
    let equalTabs = []
    let supMenu = card.supMenu || ''
    let equalTab = card.equalTab || []
    let isuptab = true
    let equalTabIds = []
    config.tabgroups.forEach((groupId, i) => {
      if (groupId === card.groupId) {
        isuptab = false
        config[card.groupId].forEach(tab => { // 可关联的同级标签
          if (tab.uuid === card.uuid) return
          equalTabIds.push(tab.uuid)
          equalTabs.push(tab)
        })
      } else if (isuptab) {
        config[groupId].forEach(tab => {
          menus.push({
            value: tab.uuid,
            text: tab.label
          })
        })
      }
    })
    if (supMenu && menus.filter(menu => menu.value === supMenu).length === 0) {
      supMenu = ''
    }
    if (equalTab.length > 0) {
      equalTab = equalTab.filter(tabId => equalTabIds.includes(tabId))
    }
    this.setState({
      modaltype: 'tabs',
      card: card,
      formlist: [
        {
          type: 'text',
          key: 'label',
          label: this.state.dict['header.menu.tabName'],
          initVal: card.label || '',
          required: true
        },
        {
          type: 'select',
          key: 'type',
          label: this.state.dict['header.form.tabType'],
          initVal: card.type || 'SubTable',
          required: true,
          options: [{
            value: 'SubTable',
            text: this.state.dict['header.menu.tab.subtable']
          }]
        },
        {
          type: 'select',
          key: 'linkTab',
          label: '关联标签',
          initVal: card.linkTab || '',
          required: false,
          options: []
        },
        {
          type: 'select',
          key: 'icon',
          label: this.state.dict['header.menu.icon'],
          initVal: card.icon || '',
          required: false,
          options: [{
            value: '',
            text: this.state.dict['header.form.empty']
          }, {
            value: 'table',
            text: 'table'
          }, {
            value: 'bar-chart',
            text: 'bar-chart'
          }, {
            value: 'pie-chart',
            text: 'pie-chart'
          }, {
            value: 'line-chart',
            text: 'line-chart'
          }]
        },
        {
          type: 'select',
          key: 'supMenu',
          label: this.state.dict['header.form.supTab'],
          initVal: supMenu,
          required: false,
          options: menus
        },
        {
          type: 'mutilselect',
          key: 'equalTab',
          label: this.state.dict['header.form.equalTab'],
          initVal: equalTab,
          required: false,
          options: equalTabs
        }
      ]
    })
  }
  /**
   * @description 搜索、按钮、显示列修改后提交保存
@@ -629,8 +518,7 @@
   * 3、添加或编辑列,保存时,如按钮位置设置为表格,则修改操作列显示状态
   */
  handleSubmit = () => {
    const { btnTab } = this.props
    const { config, modaltype, optionLibs, card } = this.state
    const { config, modaltype, card } = this.state
    if (modaltype === 'search') {
      this.modalFormRef.handleConfirm().then(res => {
@@ -640,27 +528,13 @@
          notification.warning({
            top: 92,
            message: '表单中字段名不可与主键重复!',
            duration: 10
            duration: 5
          })
          return
        }
        if ( // 更新下拉字典
          (res.type === 'select' || res.type === 'multiselect' || res.type === 'link') &&
          res.resourceType === '0' &&
          res.options && res.options.length > 0
        ) {
          optionLibs.set(btnTab.uuid + res.uuid, {
            uuid: btnTab.uuid + res.uuid,
            label: res.label,
            parname: btnTab.label,
            type: 'Modal',
            options: res.options
          })
        }
        let _groups = null
        let fieldrepet = false  // 字段重复
        let labelrepeat = false // 提示文字重复
        if (card.iscopy) {
          _groups = _config.groups.map(group => {
@@ -672,8 +546,6 @@
              if (item.uuid !== res.uuid && item.field === res.field) {
                fieldrepet = true
              } else if (item.uuid !== res.uuid && item.label === res.label) {
                labelrepeat = true
              }
            })
@@ -691,8 +563,6 @@
            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) {
                labelrepeat = true
              }
              if (item.uuid === res.uuid) {
@@ -712,14 +582,7 @@
          notification.warning({
            top: 92,
            message: '字段已存在!',
            duration: 10
          })
          return
        } else if (labelrepeat) {
          notification.warning({
            top: 92,
            message: '名称已存在!',
            duration: 10
            duration: 5
          })
          return
        }
@@ -731,11 +594,15 @@
  
          let param = {
            func: 's_debug_sql',
            exec_type: 'y',
            LText: res.dataSource
          }
          param.LText = param.LText.replace(/@\$|\$@/ig, '')
          param.LText = Utils.formatOptions(param.LText)
          param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
          param.secretkey = Utils.encrypt(param.LText, param.timestamp)
          param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
          param.secretkey = Utils.encrypt('', param.timestamp)
  
          if (window.GLOB.mainSystemApi && res.database === 'sso') {
            param.rduri = window.GLOB.mainSystemApi
@@ -746,7 +613,6 @@
              this.setState({
                sqlVerifing: false,
                config: {..._config, groups: _groups},
                optionLibs: optionLibs,
                modaltype: ''
              })
            } else {
@@ -760,7 +626,6 @@
        } else {
          this.setState({
            config: {..._config, groups: _groups},
            optionLibs: optionLibs,
            modaltype: ''
          })
        }
@@ -777,22 +642,6 @@
        this.setState({
          config: {...config, action: _action},
          modaltype: ''
        })
      })
    } else if (modaltype === 'tabs') {
      this.tabsFormRef.handleConfirm().then(res => {
        let _tabgroup = config[res.groupId].map(item => {
          if (item.uuid === res.uuid) {
            return res
          } else {
            return item
          }
        })
        _tabgroup = _tabgroup.filter(item => !item.origin)
        this.setState({
          config: {...config, [res.groupId]: _tabgroup},
          modaltype: ''
        })
      })
@@ -813,9 +662,6 @@
      } else if (modaltype === 'actionEdit') {
        let _action = config.action.filter(item => item.uuid !== card.uuid)
        _config = {...config, action: _action}
      } else if (modaltype === 'tabs') {
        let _tabgroup = config[card.groupId].filter(item => item.uuid !== card.uuid)
        _config = {...config, [card.groupId]: _tabgroup}
      } else {
        _config = config
      }
@@ -850,7 +696,7 @@
        notification.warning({
          top: 92,
          message: '请填写内部函数!',
          duration: 10
          duration: 5
        })
        return
      }
@@ -867,30 +713,10 @@
        menuNo: menu.MenuNo
      }
      newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config))
      DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
      newLText = Utils.formatOptions(FuncUtils.getfunc(_param, btn, menu, _config))
      DelText = Utils.formatOptions(FuncUtils.dropfunc(_param.funcName))
      this.refs.btnCreatFunc.exec(btn.innerFunc, newLText, DelText).then(result => {
        if (result !== 'success') return
        let isupdate = false
        _config.action = _config.action.map(item => {
          if (item.uuid === btn.uuid) {
            isupdate = true
            return btn
          } else {
            return item
          }
        })
        if (!isupdate) { // 操作不是修改,添加元素至列表
          _config.action.push(btn)
        }
        this.setState({
          config: _config
        })
      })
      this.refs.btnCreatFunc.exec(btn.innerFunc, newLText, DelText)
    })
  }
@@ -907,7 +733,7 @@
        notification.warning({
          top: 92,
          message: '接口类型为-内部,且存在内部函数时,才可以创建存储过程!',
          duration: 10
          duration: 5
        })
        return
      }
@@ -920,15 +746,15 @@
        }
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        Api.getLocalConfig(param)
      }
      let _config = {...config, setting: setting}
      let newLText = Utils.formatOptions(Utils.getTableFunc(setting, menu, _config)) // 创建存储过程sql
      let DelText = Utils.formatOptions(Utils.dropfunc(setting.innerFunc))          // 删除存储过程sql
      let newLText = Utils.formatOptions(FuncUtils.getTableFunc(setting, menu, _config)) // 创建存储过程sql
      let DelText = Utils.formatOptions(FuncUtils.dropfunc(setting.innerFunc))          // 删除存储过程sql
      this.refs.tableCreatFunc.exec(setting.innerFunc, newLText, DelText).then(result => {
        if (result === 'success') {
@@ -944,22 +770,11 @@
    let _this = this
    confirm({
      content: `确定删除<<${element.card.label}>>吗?`,
      okText: this.state.dict['header.confirm'],
      cancelText: this.state.dict['header.cancel'],
      onOk() {
        let _config = JSON.parse(JSON.stringify(_this.state.config))
        let _delActions = _this.state.delActions
        if (element.type === 'tabs') {
          _config[element.card.groupId] = _config[element.card.groupId].filter(item => {
            if (item.uuid === element.card.uuid) {
              return false
            } else {
              return true
            }
          })
          _delActions.push(element.card.uuid)
        } else if (element.type === 'search') {
        if (element.type === 'search') {
          _config.groups = _config.groups.map(group => {
            group.sublist = group.sublist.filter(item => item.uuid !== element.card.uuid)
            return group
@@ -1000,20 +815,21 @@
  verifySubmit = () => {
    const { card } = this.state
    let config = JSON.parse(JSON.stringify(this.state.config))
    let _verify = this.verifyRef.state.verify
    config.action = config.action.map(item => {
      if (item.uuid === card.uuid) {
        item.verify = _verify
      }
      return item
    })
    this.setState({
      profileVisible: false,
      config: config,
      card: '',
    this.verifyRef.handleConfirm().then(res => {
      config.action = config.action.map(item => {
        if (item.uuid === card.uuid) {
          item.verify = res
        }
        return item
      })
      this.setState({
        profileVisible: false,
        config: config,
        card: ''
      })
    })
  }
@@ -1022,19 +838,27 @@
   */
  submitConfig = () => {
    const { menu, btnTab } = this.props
    const { delActions } = this.state
    const { delActions, openEdition } = this.state
    let config = JSON.parse(JSON.stringify(this.state.config))
    this.menuformRef.handleConfirm().then(res => {
      if (config.isAdd) {
        if (config.groups[0] && config.groups[0].sublist[0] && config.groups[0].sublist[0].origin) {
          config.groups[0].sublist = config.groups[0].sublist.filter(item => !item.origin)
        }
        if (config.tabs[0] && config.tabs[0].origin) {
          config.tabs = config.tabs.filter(item => !item.origin)
        }
        config.tabgroups[0].sublist = config.tabgroups[0].sublist.filter(item => !item.origin)
      }
      let btnNames = config.action.map(item => item.label)
      btnNames = Array.from(new Set(btnNames))
      if (btnNames.length < config.action.length) {
        notification.warning({
          top: 92,
          message: '按钮名称不可相同!',
          duration: 5
        })
        return
      }
      let _LongParam = ''
@@ -1049,8 +873,8 @@
      // 标签不合法时,启用状态为false
      if (_config.tabgroups.length > 1) {
        _config.tabgroups.forEach(groupId => {
          if (_config[groupId].length === 0) {
        _config.tabgroups.forEach(group => {
          if (group.sublist.length === 0) {
            _config.enabled = false
          }
        })
@@ -1064,7 +888,7 @@
        if (_ismutil && group.sublist.length === 0) {
          _config.enabled = false
        }
        let arr = group.sublist.filter(item => item.field.toLowerCase() === _primary)
        let arr = group.sublist.filter(item => item.field && item.field.toLowerCase() === _primary)
        if (arr.length > 0) {
          _config.enabled = false
@@ -1103,10 +927,8 @@
        }
      })
      _config.tabgroups.forEach(groupId => {
        if (_config[groupId].length === 0) return
        _config[groupId].forEach(tab => {
      _config.tabgroups.forEach(group => {
        group.sublist.forEach(tab => {
          _config.funcs.push({
            type: 'tab',
            subtype: 'tab',
@@ -1179,7 +1001,7 @@
          notification.warning({
            top: 92,
            message: '编译错误',
            duration: 10
            duration: 5
          })
          this.setState({
@@ -1207,7 +1029,7 @@
  
        btnParam.LText = btnParam.LText.join(' union all ')
        btnParam.LText = Utils.formatOptions(btnParam.LText)
        btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
        
        let tabParam = { // 添加菜单tab页
@@ -1217,8 +1039,8 @@
        
        let _LText = []
        config.tabgroups.forEach(groupId => {
          config[groupId].forEach(item => {
        config.tabgroups.forEach(group => {
          group.sublist.forEach(item => {
            _sort++
            _LText.push(`select '${btnTab.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
          })
@@ -1228,7 +1050,7 @@
        tabParam.LText = Utils.formatOptions(_LText)
        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
  
        let param = {
@@ -1240,6 +1062,10 @@
          MenuName: btnTab.label,
          PageParam: JSON.stringify({Template: 'FormTab'}),
          LongParam: _LongParam
        }
        if (openEdition) {
          param.open_edition = openEdition
        }
        // 有按钮或标签删除时,先进行删除操作
@@ -1273,7 +1099,7 @@
                notification.warning({
                  top: 92,
                  message: error.message,
                  duration: 10
                  duration: 5
                })
                resolve(false)
              } else {
@@ -1292,6 +1118,7 @@
          Api.getSystemConfig(param).then(response => {
            if (response.status) {
              this.setState({
                openEdition: response.open_edition || '',
                config: _config,
                originMenu: _config
              })
@@ -1305,7 +1132,7 @@
              notification.warning({
                top: 92,
                message: response.message,
                duration: 10
                duration: 5
              })
            }
          })
@@ -1314,8 +1141,8 @@
    }, () => {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.basemsg'],
        duration: 10
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
    })
  }
@@ -1360,7 +1187,7 @@
            notification.warning({
              top: 92,
              message: error.message,
              duration: 10
              duration: 5
            })
            resolve(false)
          } else {
@@ -1400,8 +1227,6 @@
    if (config.isAdd) {
      confirm({
        content: '按钮配置尚未提交,确定放弃保存吗?',
        okText: this.state.dict['header.confirm'],
        cancelText: this.state.dict['header.cancel'],
        onOk() {
          _this.handleViewBack()
        },
@@ -1427,7 +1252,7 @@
      notification.warning({
        top: 92,
        message: '请选择表名!',
        duration: 10
        duration: 5
      })
      return
    }
@@ -1499,7 +1324,6 @@
        initval: '',
        type: item.type,
        resourceType: '0',
        setAll: 'false',
        options: [],
        orderType: 'asc'
      }
@@ -1573,7 +1397,7 @@
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
            duration: 5
          })
        }
      })
@@ -1613,7 +1437,7 @@
        }
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        Api.getLocalConfig(param)
@@ -1626,12 +1450,15 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: res.dataresource
        }
        param.LText = param.LText.replace(/@\$|\$@/ig, '')
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.secretkey = Utils.encrypt('', param.timestamp)
        
        Api.getLocalConfig(param).then(result => {
          if (result.status) {
@@ -1662,13 +1489,13 @@
   */
  setSubConfig = (btn) => {
    const {menu, btnTab} = this.props
    const { config, originMenu, activeKey } = this.state
    const { config, originMenu, activeKey, openEdition } = this.state
    if (config.isAdd) {
      notification.warning({
        top: 92,
        message: '菜单尚未保存,请保存菜单配置!',
        duration: 10
        duration: 5
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
@@ -1678,19 +1505,18 @@
          notification.warning({
            top: 92,
            message: '菜单配置已修改,请保存!',
            duration: 10
            duration: 5
          })
        } else {
          this.setState({
            loading: true
          })
          // 保存当前打开页签
          btnTab.activeKey = activeKey
          btnTab.activeKey = activeKey       // 保存当前打开页签
          btnTab.open_edition = openEdition  // 更新版本号
          let param = {
            editMenu: menu,
            optionLibs: this.state.optionLibs,
            editTab: btn,
            tabConfig: null,
            editSubTab: null,
@@ -1724,6 +1550,10 @@
                param.subConfig = _LongParam
              }
              if (param.editTab) {
                param.editTab.open_edition = res.open_edition || ''
              }
              this.props.handleView(param)
            } else {
              this.setState({
@@ -1732,7 +1562,7 @@
              notification.warning({
                top: 92,
                message: res.message,
                duration: 10
                duration: 5
              })
            }
          })
@@ -1741,7 +1571,7 @@
        notification.warning({
          top: 92,
          message: '菜单基本信息已修改,请保存!',
          duration: 10
          duration: 5
        })
      })
    }
@@ -1753,7 +1583,7 @@
    let tabinvalid = true
    if (config.tabgroups.length > 1) {
      config.tabgroups.forEach(group => {
        if (config[group].length === 0) {
        if (group.sublist.length === 0) {
          tabinvalid = false
        }
      })
@@ -1771,7 +1601,7 @@
    let primaryrepeat = false
    config.groups.forEach(group => {
      let arr = group.sublist.filter(item => item.field.toLowerCase() === _primary)
      let arr = group.sublist.filter(item => item.field && item.field.toLowerCase() === _primary)
      if (arr.length > 0) {
        primaryrepeat = true
@@ -1782,31 +1612,31 @@
      notification.warning({
        top: 92,
        message: '尚未设置数据源,不可启用!',
        duration: 10
        duration: 5
      })
    } else if (config.setting.datatype === 'query' && !config.setting.primaryKey) {
      notification.warning({
        top: 92,
        message: '尚未设置主键,不可启用!',
        duration: 10
        duration: 5
      })
    } else if (!tabinvalid) {
      notification.warning({
        top: 92,
        message: '存在多余标签组,不可启用!',
        duration: 10
        duration: 5
      })
    } else if (!forminvalid) {
      notification.warning({
        top: 92,
        message: '存在多余空表单组,不可启用!',
        duration: 10
        duration: 5
      })
    } else if (primaryrepeat) {
      notification.warning({
        top: 92,
        message: '表单字段与主键重复,不可启用!',
        duration: 10
        duration: 5
      })
    } else {
      this.setState({
@@ -1815,48 +1645,7 @@
    }
  }
  addTabGroup = () => {
    let _this = this
    let _config = JSON.parse(JSON.stringify(this.state.config))
    confirm({
      content: `确定新建标签组吗?`,
      okText: this.state.dict['header.confirm'],
      cancelText: this.state.dict['header.cancel'],
      onOk() {
        let newgroup = 'tabs' + Utils.getuuid()
        _config.tabgroups.push(newgroup)
        _config[newgroup] = []
        _this.setState({
          config: _config,
        })
      },
      onCancel() {}
    })
  }
  delTabGroup = (groupId) => {
    let _this = this
    let _config = JSON.parse(JSON.stringify(this.state.config))
    confirm({
      content: `确定删除标签组吗?`,
      okText: this.state.dict['header.confirm'],
      cancelText: this.state.dict['header.cancel'],
      onOk() {
        _config.tabgroups = _config.tabgroups.filter(group => group !== groupId)
        delete _config[groupId]
        _this.setState({
          config: _config
        })
      },
      onCancel() {}
    })
  }
  handleGroup = (group) => {
    let editgroup = {
@@ -1882,8 +1671,6 @@
    confirm({
      content: `确定删除分组<<${group.label}>>吗?`,
      okText: this.state.dict['header.confirm'],
      cancelText: this.state.dict['header.cancel'],
      onOk() {
        let groups = config.groups.filter(item => !(item.uuid === group.uuid))
        groups = groups.map(item => {
@@ -1925,25 +1712,6 @@
    })
  }
  handleTabGroup = (index, type) => {
    let config = JSON.parse(JSON.stringify(this.state.config))
    if (type === 'up') {
      config.tabgroups.splice(index, 0, config.tabgroups.splice(index - 1, 1)[0])
    } else {
      config.tabgroups.splice(index, 0, config.tabgroups.splice(index + 1, 1)[0])
    }
    this.setState({
      config: config
    })
    notification.success({
      top: 92,
      message: '调整成功',
      duration: 2
    })
  }
  pasteSubmit = () => {
    let _config = JSON.parse(JSON.stringify(this.state.config))
@@ -1960,7 +1728,7 @@
          notification.warning({
            top: 92,
            message: '不支持此表单类型!',
            duration: 10
            duration: 5
          })
          return
        }
@@ -1975,9 +1743,21 @@
        notification.warning({
          top: 92,
          message: '配置信息格式错误!',
          duration: 10
          duration: 5
        })
      }
    })
  }
  /**
   * @description 更新标签配置信息
   */
  updatetabs = (config, delcards) => {
    const { delActions } = this.state
    this.setState({
      config: config,
      delActions: delcards ? [...delActions, ...delcards.map(item => item.uuid)] : delActions
    })
  }
@@ -1986,8 +1766,8 @@
    let _length = config.groups.length
    let configTabs = []
    this.state.config.tabgroups.forEach(group => {
      configTabs.push(...this.state.config[group])
    config.tabgroups.forEach(group => {
      configTabs.push(...group.sublist)
    })
    return (
@@ -2008,7 +1788,7 @@
                <div className="ant-col ant-form-item-label">
                  <label>
                    <Tooltip placement="topLeft" title="此处可以添加配置相关的常用表,在添加搜索条件和显示列时,可通过工具栏中的添加按钮,批量添加表格相关字段。">
                      <Icon type="question-circle" />
                      <QuestionCircleOutlined className="mk-form-tip" />
                      {this.state.dict['header.menu.table.add']}
                    </Tooltip>
                  </label>
@@ -2018,7 +1798,7 @@
                  className="tables"
                  style={{ width: '100%' }}
                  optionFilterProp="children"
                  value={this.state.dict['header.menu.table.placeholder']}
                  value="请选择表名"
                  onChange={this.onTableChange}
                  showArrow={false}
                  getPopupContainer={() => document.getElementById('common-basedata')}
@@ -2037,7 +1817,7 @@
                  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)}/>
                    <CloseOutlined onClick={() => this.deleteTable(item)}/>
                    <div className="bottom-mask"></div>
                  </List.Item>}
                />}
@@ -2049,7 +1829,7 @@
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                <Button type="primary" block onClick={() => this.queryField('search')}>{this.state.dict['header.menu.form.add']}</Button>
                <Button type="primary" block onClick={() => this.queryField('search')}>批量添加</Button>
              </Panel>
              {/* 按钮添加 */}
              <Panel header={this.state.dict['header.menu.action']} key="2">
@@ -2069,9 +1849,9 @@
                {configTabs.length > 0 ?
                  <p className="config-btn-title">
                    <Tooltip placement="topLeft" title="点击按钮,可完成或查看标签配置信息。">
                      <Icon type="question-circle" />
                      <QuestionCircleOutlined className="mk-form-tip" />
                    </Tooltip>
                    {this.state.dict['header.menu.tab.configurable']}
                    标签配置
                  </p> : null
                }
                {configTabs.map((item, index) => {
@@ -2092,20 +1872,19 @@
          <div className="setting">
            <Card title={
              <div>
                {this.state.dict['header.menu.page.configurable']}
                <Icon type="redo" style={{marginLeft: '10px'}} title="刷新标签列表" onClick={this.reloadTab} />
                页面配置
                <RedoOutlined style={{marginLeft: '10px'}} title="刷新标签列表" onClick={this.reloadTab} />
              </div>
            } bordered={false} extra={
              <div>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['header.save']}</Button>
                <Button onClick={this.cancelConfig}>{this.state.dict['header.return']}</Button>
                <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>
              </div>
            } style={{ width: '100%' }}>
              <Icon type="setting" onClick={this.changeSetting} />
              <Icon type="snippets" title={this.state.dict['header.form.paste']} onClick={() => {this.setState({pasteVisible: true})}} />
              <SettingOutlined onClick={this.changeSetting} />
              <Tooltip placement="bottomLeft" overlayClassName="middle" title="在左侧工具栏《搜索》中,选择对应搜索框拖至此处添加;或点击按钮《添加搜索条件》批量添加,选择批量添加时,需提前选择使用表。">
                <Icon type="question-circle" />
                <QuestionCircleOutlined style={{position: 'relative', color: '#c49f47', left: '5px', top: '20px'}} />
              </Tooltip>
              <Collapse
                activeKey={config.groups.map(group => group.uuid)}
@@ -2114,20 +1893,16 @@
                {config.groups.map((group, index) => (
                  <Panel showArrow={false} header={group.label} key={group.uuid} extra={(
                    <span>
                      {index === _length - 1 ? <Icon
                        type="plus"
                      {index === _length - 1 ? <PlusOutlined
                        onClick={() => { this.handleGroup()}}
                      /> : null}
                      {_length > 1 && index !== _length - 1 ? <Icon
                        type="delete"
                      {_length > 1 && index !== _length - 1 ? <DeleteOutlined
                        onClick={() => { this.closeGroup(group) }}
                      /> : null}
                      <Icon
                        type="edit"
                        onClick={() => { this.handleGroup(group) }}
                      />
                      <EditOutlined onClick={() => { this.handleGroup(group) }}/>
                    </span>
                  )}>
                    {group.isDefault ? <SnippetsOutlined title={this.state.dict['header.form.paste']} onClick={() => {this.setState({pasteVisible: true})}} /> : null}
                    <DragElement
                      type="search"
                      groupId={group.uuid}
@@ -2136,14 +1911,13 @@
                      setting={config.setting}
                      handleMenu={this.handleSearch}
                      deleteMenu={this.deleteElement}
                      placeholder={this.state.dict['header.form.modal.placeholder']}
                    />
                  </Panel>
                ))}
              </Collapse>
              <div className="action-list">
                <Tooltip placement="bottomLeft" overlayClassName="middle" title="在左侧工具栏《按钮》中,选择对应类型的按钮拖至此处添加,如选择按钮类型为表单、新标签页等含有配置页面的按钮,可在左侧工具栏-按钮-可配置按钮处,点击按钮完成相关配置。注:当设置按钮显示位置为表格时,显示列会增加操作列。">
                  <Icon type="question-circle" />
                  <QuestionCircleOutlined style={{position: 'absolute', color: '#c49f47', left: '5px', top: '5px'}} />
                </Tooltip>
                <DragElement
                  type="action"
@@ -2152,40 +1926,21 @@
                  handleMenu={this.handleAction}
                  deleteMenu={this.deleteElement}
                  profileMenu={this.profileAction}
                  placeholder={this.state.dict['header.form.action.placeholder']}
                />
              </div>
              {/* 标签组 */}
              {this.state.config.tabgroups.map((groupId, index) => {
                return (
                  <div key={index} className="tab-list">
                    {index === 0 ? <Tooltip placement="bottomLeft" overlayClassName="middle" title="在左侧工具栏《标签页》中,选择对应类型的标签页拖至此处添加。">
                      <Icon type="question-circle" />
                    </Tooltip> : null}
                    {index !== (this.state.config.tabgroups.length - 1) ?
                      <Icon type="arrow-down" onClick={() => {this.handleTabGroup(index, 'down')}} /> : null
                    }
                    {index !== 0 ? <Icon type="arrow-up" onClick={() => {this.handleTabGroup(index, 'up')}} /> : null}
                    {index === 0 ? <Icon type="plus" onClick={this.addTabGroup} /> : null}
                    {index !== 0 ? <Icon type="delete" onClick={() => {this.delTabGroup(groupId)}} /> : null}
                    <TabDragElement
                      type="tabs"
                      groupId={groupId}
                      list={this.state.config[groupId]}
                      handleList={this.handleList}
                      handleMenu={this.handleTab}
                      deleteMenu={this.deleteElement}
                      doubleClickCard={(tab) => this.setSubConfig(tab, 'tab')}
                      placeholder={this.state.dict['header.form.tab.placeholder']}
                    />
                  </div>)
              })}
              <TabsComponent
                config={config}
                tabs={this.state.tabviews}
                setSubConfig={(item) => this.setSubConfig(item, 'tab')}
                updatetabs={this.updatetabs}
              />
            </Card>
          </div>
        </DndProvider>
        {/* 编辑表单 */}
        <Modal
          title={this.state.card && this.state.card.iscopy ? this.state.dict['header.modal.form.copy'] : this.state.dict['header.modal.form.edit']}
          title={this.state.card && this.state.card.iscopy ? '表单-复制' : '表单-编辑'}
          visible={modaltype === 'search'}
          width={700}
          maskClosable={false}
@@ -2199,22 +1954,21 @@
            card={this.state.card}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            optionLibs={this.state.optionLibs}
            wrappedComponentRef={(inst) => this.modalFormRef = inst}
          />
        </Modal>
        {/* 编辑按钮:复制、编辑 */}
        <Modal
          title={this.state.dict['header.modal.action.edit']}
          title={this.state.dict['model.action'] + '-' + this.state.dict['model.edit']}
          visible={modaltype === 'actionEdit'}
          width={700}
          width={900}
          maskClosable={false}
          onCancel={this.editModalCancel}
          footer={[
            this.state.card && this.state.card.btnType !== 'cancel' ?
            <CreateFunc key="create" dict={this.state.dict} ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
            <Button key="cancel" onClick={this.editModalCancel}>{this.state.dict['header.cancel']}</Button>,
            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
            <Button key="cancel" onClick={this.editModalCancel}>{this.state.dict['model.cancel']}</Button>,
            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['model.confirm']}</Button>
          ]}
          destroyOnClose
        >
@@ -2227,35 +1981,14 @@
            wrappedComponentRef={(inst) => this.actionFormRef = inst}
          />
        </Modal>
        {/* 标签编辑 */}
        <Modal
          title={this.state.dict['header.modal.tabs.edit']}
          visible={modaltype === 'tabs'}
          width={700}
          maskClosable={false}
          onOk={this.handleSubmit}
          onCancel={this.editModalCancel}
          destroyOnClose
        >
          <TabForm
            type="tabs"
            dict={this.state.dict}
            card={this.state.card}
            tabs={this.state.tabviews}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            wrappedComponentRef={(inst) => this.tabsFormRef = inst}
          />
        </Modal>
        {/* 根据字段名添加显示列及搜索条件 */}
        <Modal
          wrapClassName="common-table-fields-modal"
          title={this.state.dict['header.edit']}
          title={this.state.dict['model.edit']}
          visible={this.state.tableVisible}
          width={'65vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          cancelText={this.state.dict['header.close']}
          cancelText={this.state.dict['model.close']}
          onOk={this.addFieldSubmit}
          onCancel={() => { // 取消添加
            this.setState({
@@ -2278,9 +2011,17 @@
          visible={this.state.profileVisible}
          width={'75vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          okText={this.state.dict['model.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ profileVisible: false }) }}
          onCancel={() => {
            if (this.verifyRef.handleCancel) {
              this.verifyRef.handleCancel().then(() => {
                this.setState({ profileVisible: false })
              })
            } else {
              this.setState({ profileVisible: false })
            }
          }}
          destroyOnClose
        >
          <VerifyCard
@@ -2294,7 +2035,7 @@
        </Modal>
        {/* 设置全局配置及列表数据源 */}
        <Modal
          title={this.state.dict['header.edit']}
          title={this.state.dict['model.edit']}
          visible={this.state.settingVisible}
          width={700}
          maskClosable={false}
@@ -2305,8 +2046,8 @@
          }}
          footer={[
            <CreateFunc key="create" dict={this.state.dict} ref="tableCreatFunc" trigger={this.tableCreatFunc}/>,
            <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['header.cancel']}</Button>,
            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['header.confirm']}</Button>
            <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['model.cancel']}</Button>,
            <Button key="confirm" type="primary" loading={this.state.sqlVerifing} onClick={this.settingSave}>{this.state.dict['model.confirm']}</Button>
          ]}
          destroyOnClose
        >
@@ -2315,7 +2056,6 @@
            menu={this.props.menu}
            config={this.state.config}
            inputSubmit={this.settingSave}
            usefulFields={this.props.permFuncField}
            wrappedComponentRef={(inst) => this.settingRef = inst}
          />
        </Modal>
@@ -2326,16 +2066,16 @@
          visible={this.state.closeVisible}
          onCancel={() => { this.setState({closeVisible: false}) }}
          footer={[
            <Button key="save" className="mk-btn mk-green" loading={this.state.menucloseloading} onClick={this.submitConfig}>{this.state.dict['header.save']}</Button>,
            <Button key="confirm" className="mk-btn mk-yellow" onClick={this.handleViewBack}>{this.state.dict['header.notsave']}</Button>,
            <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['header.cancel']}</Button>
            <Button key="save" className="mk-btn mk-green" loading={this.state.menucloseloading} 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="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['model.cancel']}</Button>
          ]}
          destroyOnClose
        >
          {this.state.dict['header.menu.config.placeholder']}
        </Modal>
        <Modal
          title={this.state.dict['header.menu.group.manage']}
          title="分组管理"
          visible={this.state.groupVisible}
          width={700}
          maskClosable={false}
@@ -2372,11 +2112,8 @@
  }
}
const mapStateToProps = (state) => {
  return {
    sysRoles: state.sysRoles,
    permFuncField: state.permFuncField
  }
const mapStateToProps = () => {
  return {}
}
const mapDispatchToProps = () => {