king
2022-11-07 af6486b3629d23e426ce85b87dbc20dfa15b1afe
src/templates/comtableconfig/index.jsx
@@ -1,17 +1,16 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Spin, Icon, Switch, Tooltip, Col } from 'antd'
import { Button, Card, Modal, Collapse, notification, Spin, Switch, Tooltip, Col } from 'antd'
import { QuestionCircleOutlined, RedoOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import UtilsUpdate from '@/utils/utils-update.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import MKEmitter from '@/utils/events.js'
import { updateCommonTable } from '@/utils/utils-update.js'
import asyncComponent from '@/utils/asyncComponent'
import SearchComponent from '@/templates/sharecomponent/searchcomponent'
@@ -25,6 +24,12 @@
const { Panel } = Collapse
const { confirm } = Modal
const Versions = asyncComponent(() => import('@/menu/versions'))
const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const UpdateTable = asyncComponent(() => import('./updatetable'))
const Unattended = asyncComponent(() => import('@/templates/zshare/unattended'))
const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
const SettingComponent = asyncComponent(() => import('@/templates/sharecomponent/settingcomponent'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -37,32 +42,26 @@
class ComTableConfig extends Component {
  static propTpyes = {
    menu: PropTypes.any,
    optionLibs: PropTypes.any,
    reloadmenu: PropTypes.func,
    handleView: PropTypes.func
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    config: null,            // 页面配置
    tableFields: [],         // 表格显示列
    formlist: null,          // 搜索条件、按钮、显示列表单字段
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
    loading: false,          // 加载中,页面spin
    closeVisible: false,     // 关闭模态框
    tables: [],              // 可用表名
    originMenu: null,        // 原始菜单
    originActions: null,     // 原始按钮信息,使用已有用户模板
    delActions: [],          // 删除按钮列表
    copyActions: [],         // 复制按钮组
    tabviews: [],            // 所有标签页
    optionLibs: null,        // 自定义下拉选项库
    thawButtons: [],         // 已选择要解冻的按钮
    activeKey: '0',          // 默认展开基本信息
    chartview: null,         // 当前视图
    pasteContent: null,      // 粘贴配置信息
    openEdition: ''          // 编辑版本标记,防止多人操作
    openEdition: '',         // 编辑版本标记,防止多人操作
  }
  /**
@@ -71,33 +70,15 @@
   * 2、设置操作类型、原始菜单信息(每次保存后重置)、已使用表及基本信息表单
   */
  UNSAFE_componentWillMount () {
    const { menu, optionLibs } = this.props
    const { menu } = this.props
    let _LongParam = menu.LongParam
    let _config = ''
    if (!_LongParam) {
      _config = fromJS(Source.baseConfig).toJS()
      if (!menu.isSubtable) { // 不是选择主子表时,隐藏标签页
        _config.tabgroups = [{ uuid: 'tabs', sublist: [] }]
      }
      _config.isAdd = true
    } else {
      _config = _LongParam
      _config.search.forEach(item => {
        if (
          (item.type === 'select' || item.type === 'multiselect' || item.type === 'link') &&
          item.resourceType === '0' &&
          item.options && item.options.length > 0
        ) {
          optionLibs.set(menu.MenuID + item.uuid, {
            uuid: menu.MenuID + item.uuid,
            label: item.label,
            parname: menu.MenuName,
            type: 'search',
            options: item.options
          })
        }
      })
    }
    // 页面配置中保留菜单信息,只用于数据传递
@@ -107,9 +88,10 @@
    _config.MenuNo = menu.MenuNo || ''
    _config.OpenType = menu.PageParam ? menu.PageParam.OpenType : ''
    _config.easyCode = _config.easyCode || ''
    _config.uuid = menu.MenuID || ''
    // 版本兼容
    _config = UtilsUpdate.updateCommonTable(_config)
    _config = updateCommonTable(_config)
    
    let _oriActions = []
    if (_config.type === 'user') {
@@ -120,17 +102,11 @@
          item.linkTab = ''
        }
        if (item.OpenType === 'pop') { // 含有子配置项的按钮(表单)
        if (item.OpenType === 'pop' || item.execMode === 'pop') { // 含有子配置项的按钮(表单)
          _oriActions.push({
            prebtn: fromJS(item).toJS(),
            curuuid: uuid,
            Template: 'Modal'
          })
        } else if (item.OpenType === 'tab' || item.OpenType === 'blank') { // 含有子配置项的按钮(标签后当前页打开)
          _oriActions.push({
            prebtn: fromJS(item).toJS(),
            curuuid: uuid,
            Template: item.tabTemplate
          })
        }
@@ -153,11 +129,10 @@
    }
    this.setState({
      chartview: _config.charts[0].uuid,
      chartview: _config.charts ? _config.charts[0].uuid : '',
      config: _config,
      openEdition: menu.open_edition || '',
      activeKey: menu.activeKey || '0',
      optionLibs: optionLibs,
      originActions: _oriActions,
      originMenu: fromJS(_config).toJS()
    })
@@ -168,6 +143,55 @@
   */
  componentDidMount () {
    this.reloadTab(false)
    document.onkeydown = (event) => {
      let e = event || window.event
      let keyCode = e.keyCode || e.which || e.charCode
      let preKey = ''
      if (e.ctrlKey) {
        preKey = 'ctrl'
      }
      if (e.shiftKey) {
        preKey = 'shift'
      } else if (e.altKey) {
        preKey = 'alt'
      }
      if (!preKey || !keyCode) return
      let _shortcut = `${preKey}+${keyCode}`
      if (_shortcut === 'ctrl+83') {
        let modals = document.querySelectorAll('.mk-pop-modal')
        let msg = null
        for (let i = 0; i < modals.length; i++) {
          if (msg) {
            break
          }
          let node = modals[i].querySelector('.mk-com-name')
          if (node) {
            msg = node.innerText
          }
        }
        if (msg) {
          notification.warning({
            top: 92,
            message: '请保存' + msg,
            duration: 5
          })
          return false
        }
        let node = document.getElementById('save-config')
        if (node && node.click) {
          node.click()
        }
        return false
      }
    }
  }
  /**
@@ -177,6 +201,7 @@
    this.setState = () => {
      return
    }
    document.onkeydown = () => {}
  }
  /**
@@ -222,23 +247,41 @@
    })
  }
  getFuncNames = (data, funcNames, tableNames) => {
    data.forEach(item => {
      if (item.subfuncs) {
        this.getFuncNames(item.subfuncs, funcNames, tableNames)
      } else {
        if (item.tableName) {
          tableNames.push(item.tableName)
  getFuncNames = (config) => {
    let funcNames = []
    let tableNames = []
    if (config.setting.tableName) {
      tableNames.push(config.setting.tableName)
    }
    if (config.setting.innerFunc) {
      funcNames.push({func: config.setting.innerFunc, label: config.MenuName || ''})
    }
    if (config.setting.outerFunc) {
      funcNames.push({func: config.setting.outerFunc, label: config.MenuName || ''})
    }
    config.action.forEach(item => {
      let tablename = item.OpenType === 'excelIn' ? (item.sheet || '') : (item.sql || '')
      if (item.OpenType === 'excelOut' && item.intertype === 'system') {
        tablename = config.setting.tableName || ''
      }
      if (['pop', 'prompt', 'exec', 'excelIn', 'excelOut', 'funcbutton'].includes(item.OpenType)) {
        if (tablename) {
          tableNames.push(tablename)
        }
        if (item.innerFunc) {
          funcNames.push({func: item.innerFunc, label: item.label || ''})
        }
        if (item.callbackFunc) {
          funcNames.push({func: item.callbackFunc, label: item.label || ''})
        }
      }
    })
    tableNames = Array.from(new Set(tableNames))
    return {
      func: funcNames,
@@ -259,7 +302,7 @@
    if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        message: '请完善菜单基本信息!',
        duration: 5
      })
      this.setState({activeKey: '0'})
@@ -293,75 +336,16 @@
      })
    }
    // 按钮不存在时,去掉绑定的双击按钮
    if (_config.setting.doubleClick && _config.action.findIndex((item) => item.uuid === _config.setting.doubleClick) === -1) {
      _config.setting.doubleClick = ''
    }
    // 未设置数据源或标签不合法时,启用状态为false
    let vresult = this.verifyconfig(_config)
    if (vresult !== true) {
      _config.enabled = false
    }
    _config.funcs = [] // 页面及子页面存储过程集
    _config.funcs.push({
      type: 'view',
      subtype: 'view',
      uuid: menu.MenuID,
      intertype: _config.setting.interType || 'system',
      interface: _config.setting.interface || '',
      tableName: _config.setting.tableName || '',
      innerFunc: _config.setting.innerFunc || '',
      outerFunc: _config.setting.outerFunc || ''
    })
    _config.action.forEach(item => {
      let tablename = item.OpenType === 'excelIn' ? (item.sheet || '') : (item.sql || '')
      if (item.OpenType === 'excelOut' && item.intertype === 'system') {
        tablename = _config.setting.tableName || ''
      }
      if (item.OpenType === 'tab' || item.OpenType === 'blank') {
        _config.funcs.push({
          type: 'tab',
          subtype: 'btn',
          uuid: item.uuid,
          label: item.label,
          linkTab: item.uuid
        })
      } else if (item.OpenType === 'popview') {
        _config.funcs.push({
          type: 'tab',
          subtype: 'btn',
          uuid: item.uuid,
          label: item.label,
          linkTab: item.linkTab
        })
      } else if (['pop', 'prompt', 'exec', 'excelIn', 'excelOut'].includes(item.OpenType)) {
        _config.funcs.push({
          type: 'button',
          subtype: 'btn',
          uuid: item.uuid,
          label: item.label,
          tableName: tablename,
          intertype: item.intertype,
          interface: item.interface || '',
          innerFunc: item.innerFunc || '',
          outerFunc: item.outerFunc || '',
          callbackFunc: item.callbackFunc || ''
        })
      }
    })
    _config.tabgroups.forEach(group => {
      group.sublist.forEach(tab => {
        _config.funcs.push({
          type: 'tab',
          subtype: 'tab',
          uuid: tab.uuid,
          label: tab.label,
          linkTab: tab.linkTab
        })
      })
    })
    if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
      this.setState({
@@ -373,164 +357,124 @@
      })
    }
    new Promise(resolve => {
      let deffers = []
      _config.funcs.forEach(item => {
        if (item.type === 'tab') {
          let deffer = new Promise(resolve => {
            Api.getSystemConfig({
              func: 'sPC_Get_LongParam',
              MenuID: item.linkTab
            }).then(result => {
              if (result.status && result.LongParam) {
                let _LongParam = ''
    let _LongParam = ''
    let reload = _config.isAdd
    // 保存时删除配置类型,system 、user
    delete _config.type
    delete _config.isAdd
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
    } catch (e) {
      notification.warning({
        top: 92,
        message: '编译错误',
        duration: 5
      })
      this.setState({
        menucloseloading: false,
        menuloading: false
      })
      return
    }
    let _sort = 0
    let btntabs = []
    let btnParam = {             // 添加菜单按钮
      func: 'sPC_Button_AddUpt',
      Type: 40,                  // 添加菜单下的按钮type为40,按钮下的按钮type为60
      ParentID: menu.MenuID,
      MenuNo: _config.MenuNo,
      Template: _config.Template || '',
      PageParam: '',
      LongParam: '',
      LText: []
    }
    _config.action.forEach(item => {
      if (item.hidden === 'true') return
      _sort++
      if (item.OpenType === 'popview') {
        btntabs.push({
          uuid: item.uuid,
          linkTab: item.linkTab,
          label: item.label,
          sort: _sort
        })
      }
      
                if (result.LongParam) {
                  try {
                    _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                  } catch (e) {
                    console.warn('Parse Failure')
                    _LongParam = ''
                  }
                }
      btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${_sort * 10}' as Sort`)
    })
    btnParam.LText = btnParam.LText.join(' union all ')
    btnParam.LText = Utils.formatOptions(btnParam.LText)
    btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
    
                if (_LongParam) {
                  item.menuNo = _LongParam.tabNo || ''
                  item.subfuncs = _LongParam.funcs || []
                }
              }
              resolve()
            })
          })
    let tabParam = { // 添加菜单tab页
      func: 'sPC_sMenusTab_AddUpt',
      MenuID: menu.MenuID
    }
          deffers.push(deffer)
        }
      })
    let _LText = []
      if (deffers.length === 0) {
        resolve()
      } else {
        Promise.all(deffers).then(() => {
          resolve()
        })
      }
    }).then(() => {
      // 保存时删除配置类型,system 、user
      delete _config.type
      delete _config.isAdd
      let _LongParam = ''
      try {
        _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
      } catch (e) {
        notification.warning({
          top: 92,
          message: '编译错误',
          duration: 5
        })
        this.setState({
          menucloseloading: false,
          menuloading: false
        })
        return
      }
      let _sort = 0
      let btntabs = []
      let btnParam = {             // 添加菜单按钮
        func: 'sPC_Button_AddUpt',
        Type: 40,                  // 添加菜单下的按钮type为40,按钮下的按钮type为60
        ParentID: menu.MenuID,
        MenuNo: _config.MenuNo,
        Template: _config.Template || '',
        PageParam: '',
        LongParam: '',
        LText: []
      }
      _config.action.forEach(item => {
    btntabs.forEach(item => {
      _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
    })
    _config.tabgroups.forEach(group => {
      group.sublist.forEach(item => {
        _sort++
        if (item.OpenType === 'popview') {
          btntabs.push({
            uuid: item.uuid,
            linkTab: item.linkTab,
            label: item.label,
            sort: _sort
          })
        }
        btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${_sort * 10}' as Sort`)
        _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
      })
    })
      btnParam.LText = btnParam.LText.join(' union all ')
      btnParam.LText = Utils.formatOptions(btnParam.LText)
      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
      let tabParam = { // 添加菜单tab页
        func: 'sPC_sMenusTab_AddUpt',
        MenuID: menu.MenuID
      }
    _LText = _LText.join(' union all ')
      let _LText = []
    // 清空菜单下关联的标签
    if (!_LText) {
      _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
    }
      btntabs.forEach(item => {
        _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
      })
      _config.tabgroups.forEach(group => {
        group.sublist.forEach(item => {
          _sort++
          _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
        })
      })
    tabParam.LText = Utils.formatOptions(_LText)
    tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
      _LText = _LText.join(' union all ')
    let _vals = this.getFuncNames(_config)
      // 清空菜单下关联的标签
      if (!_LText) {
        _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
      }
    let param = {
      func: 'sPC_TrdMenu_AddUpt',
      FstID: _config.fstMenuId,
      SndID: _config.ParentId,
      ParentID: _config.ParentId,
      MenuID: menu.MenuID,
      MenuNo: _config.MenuNo,
      EasyCode: _config.easyCode || '',
      Template: _config.Template || '',
      MenuName: _config.MenuName,
      PageParam: JSON.stringify({...menu.PageParam, Template: _config.Template, OpenType: _config.OpenType, hidden: _config.hidden || 'false'}),
      LongParam: _LongParam,
      LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
      LTexttb: _vals.table.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
    }
      tabParam.LText = Utils.formatOptions(_LText)
      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
    if (menu.menuSort) { // 菜单新建时设置排序
      param.Sort = menu.menuSort
    }
      let _vals = this.getFuncNames(_config.funcs, [], [])
      let _tables = Array.from(new Set(_vals.table))
    param.LText = param.LText.join(' union all ')
    param.LText = Utils.formatOptions(param.LText)
    param.LTexttb = param.LTexttb.join(' union all ')
    param.LTexttb = Utils.formatOptions(param.LTexttb)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        FstID: _config.fstMenuId,
        SndID: _config.ParentId,
        ParentID: _config.ParentId,
        MenuID: menu.MenuID,
        MenuNo: _config.MenuNo,
        EasyCode: _config.easyCode || '',
        Template: _config.Template || '',
        MenuName: _config.MenuName,
        PageParam: JSON.stringify({...menu.PageParam, Template: _config.Template, OpenType: _config.OpenType}),
        LongParam: _LongParam,
        LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
        LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
      }
    if (openEdition) { // 版本管理
      param.open_edition = openEdition
    }
      if (menu.menuSort) { // 菜单新建时设置排序
        param.Sort = menu.menuSort
      }
      param.LText = param.LText.join(' union all ')
      param.LText = Utils.formatOptions(param.LText)
      param.LTexttb = param.LTexttb.join(' union all ')
      param.LTexttb = Utils.formatOptions(param.LTexttb)
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      if (openEdition) { // 版本管理
        param.open_edition = openEdition
      }
    setTimeout(() => {
      // 有按钮或标签删除时,先进行删除操作
      // 删除成功后,保存页面配置
      new Promise(resolve => {
@@ -569,7 +513,7 @@
                error = response
              }
            })
            if (error) {
              this.setState({
                menuloading: false,
@@ -640,11 +584,9 @@
              config: _config,
              openEdition: response.open_edition || '',
              originMenu: fromJS(_config).toJS()
            }, () => {
              reload && MKEmitter.emit('revert')
            })
            this.props.reloadmenu()
            this.submitAction(btnParam, tabParam)
            localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
            delete localParam.LongParam
@@ -654,7 +596,7 @@
            delete localParam.EasyCode
            delete localParam.open_edition
            Api.getLocalConfig(localParam)
            this.submitAction(btnParam, tabParam, localParam)
          } else {
            this.setState({
              menuloading: false,
@@ -668,13 +610,13 @@
          }
        })
      })
    })
    }, +sessionStorage.getItem('mkDelay'))
  }
  /**
   * @description 保存或修改菜单按钮集
   */
  submitAction = (btnParam, tabParam) => {
  submitAction = (btnParam, tabParam, localParam) => {
    const { config } = this.state
    new Promise(resolve => {
@@ -701,29 +643,25 @@
        deffers.push(defer)
      }
      if (deffers.length === 0) {
        resolve(true)
      } else {
        Promise.all(deffers).then(result => {
          let error = false
          result.forEach(res => {
            if (!res.status) {
              error = res
            }
          })
          if (error) {
            notification.warning({
              top: 92,
              message: error.message,
              duration: 5
            })
            resolve(false)
          } else {
            resolve(true)
      Promise.all(deffers).then(result => {
        let error = false
        result.forEach(res => {
          if (!res.status) {
            error = res
          }
        })
      }
        if (error) {
          notification.warning({
            top: 92,
            message: error.message,
            duration: 5
          })
          resolve(false)
        } else {
          resolve(true)
        }
      })
    }).then(response => {
      if (response === false) return response
@@ -734,6 +672,7 @@
        let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 查看初始化按钮是否存在
        if (!curBtn) return
        if (curBtn.OpenType !== item.prebtn.OpenType) return
        if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
        oriActions.push({
          prebtn: item.prebtn,
@@ -751,76 +690,30 @@
          MenuID: action.prebtn.uuid
        }).then(result => {
          if (result.status && result.LongParam) {
            let _LongParam = ''
            let _temp = ''
            if (result.LongParam) {
              let _subconfig = ''
              try {
                _subconfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                _temp = _subconfig.type
              } catch (e) {
                console.warn('Parse Failure')
                _subconfig = ''
              }
              if (_temp === 'FormTab') {
                try {
                  _subconfig.action = _subconfig.action.map(_btn => {
                    _btn.uuid = Utils.getuuid()
                    return _btn
                  })
                  // 兼容已有结构
                  if (!_subconfig.tabgroups) {
                    _subconfig.tabgroups = [{ uuid: 'tabs', sublist: [] }]
                  } else if (typeof(_subconfig.tabgroups[0]) === 'string') {
                    let _tabgroups = []
                    _subconfig.tabgroups.forEach(groupId => {
                      let _group = {
                        uuid: groupId,
                        sublist: fromJS(_subconfig[groupId]).toJS()
                      }
                      delete _subconfig[groupId]
                      _tabgroups.push(_group)
                    })
                    _subconfig.tabgroups = _tabgroups
                  }
                  _subconfig.tabgroups.forEach(group => {
                    group.sublist = group.sublist.map(_tab => {
                      _tab.uuid = Utils.getuuid()
                      _tab.linkTab = Utils.getuuid()
                      return _tab
                    })
                  })
                  _subconfig = window.btoa(window.encodeURIComponent(JSON.stringify(_subconfig)))
                } catch {
                  console.warn('Stringify Failure')
                  _subconfig = ''
                }
                _LongParam = _subconfig
              } else if (_subconfig) {
                _LongParam = result.LongParam
              }
            let _subconfig = ''
            try {
              _subconfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
              _temp = _subconfig.type
            } catch (e) {
              console.warn('Parse Failure')
              _subconfig = ''
            }
            if (_LongParam) {
              let param = {
                func: 'sPC_ButtonParam_AddUpt',
                ParentID: this.props.menu.MenuID,
                MenuID: action.curBtn.uuid,
                MenuNo: config.MenuNo,
                Template: _temp,
                MenuName: action.curBtn.label,
                PageParam: JSON.stringify({Template: _temp}),
                LongParam: _LongParam
              }
              Api.getSystemConfig(param).then(() => {})
            if (!_subconfig) return
            let param = {
              func: 'sPC_ButtonParam_AddUpt',
              ParentID: this.props.menu.MenuID,
              MenuID: action.curBtn.uuid,
              MenuNo: config.MenuNo,
              Template: _temp,
              MenuName: action.curBtn.label,
              PageParam: JSON.stringify({Template: _temp}),
              LongParam: result.LongParam
            }
            Api.getSystemConfig(param).then(() => {})
          }
        })
      })
@@ -841,6 +734,8 @@
            menucloseloading: false
          })
        }
        this.props.reloadmenu()
        Api.genericInterface(localParam)
      } else {
        this.setState({
          menuloading: false,
@@ -882,35 +777,25 @@
   */
  setSubConfig = (item, type) => {
    const { menu } = this.props
    const { config, originMenu, optionLibs, activeKey, openEdition } = this.state
    const { config, originMenu, activeKey, openEdition } = this.state
    if (config.isAdd) { // 新建菜单,提示菜单尚未保存
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.config.notsave'],
        message: '菜单尚未保存,请先保存菜单配置!',
        duration: 5
      })
    } else {
      // 基本信息验证
      if (!config.fstMenuId || !config.ParentId || !config.MenuName || !config.MenuNo) {
        notification.warning({
          top: 92,
          message: this.state.dict['model.menu.basemsg'],
          duration: 5
        })
        this.setState({activeKey: '0'})
        return
      }
      if (!is(fromJS(originMenu), fromJS(config))) { // 菜单信息变化时,提示保存
        notification.warning({
          top: 92,
          message: this.state.dict['header.menu.config.update'],
          message: '菜单配置已修改,请保存!',
          duration: 5
        })
        return
      }
      let submenu = menu.fstMenuList.filter(item => item.MenuID === config.fstMenuId)[0]
      let submenu = menu.fstMenuList.filter(_menu => _menu.MenuID === config.fstMenuId)[0]
      let _Menu = {
        ...menu,
@@ -920,7 +805,7 @@
        MenuNo: config.MenuNo,
        ParentId: config.ParentId,
        fstMenuId: config.fstMenuId,
        supMenuList: submenu ? submenu.options : []
        supMenuList: submenu ? submenu.children : []
      }
      // 菜单信息验证通过后,跳转子配置页面
@@ -929,17 +814,17 @@
      let isbutton = true
      let _btnTab = null
      
      if (type === 'button' && item.OpenType === 'pop') {
        _view = 'Modal'             // 表单页面
      } else if (type === 'button' && (item.OpenType === 'tab' || item.OpenType === 'blank')) {
        _view = item.tabTemplate    // 新标签页模板
      if (type === 'button' && (item.OpenType === 'pop' || item.execMode === 'pop')) {
        _view = 'Modal'      // 表单页面
      } else if (type === 'button' && item.OpenType === 'tab') {
        _view = 'FormTab'    // 表单标签页模板
        _btnTab = item
      } else if (type === 'button' && item.OpenType === 'popview') {
        _view = item.tabType        // 新弹窗标签模板
        _view = 'SubTable'   // 新弹窗标签模板 tabType 属性已去除
        uuid = item.linkTab
        isbutton = false
      } else if (type === 'tab') {
        _view = item.type           // 标签模板
        _view = 'SubTable'   // 标签模板
        uuid = item.linkTab
        isbutton = false
      }
@@ -948,7 +833,6 @@
      _Menu.open_edition = openEdition  // 更新版本号
      let param = {
        optionLibs: optionLibs,
        editMenu: _Menu,
        editTab: !isbutton ? item : '',
        tabConfig: null,
@@ -995,7 +879,7 @@
          } else if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
            param.subConfig = _LongParam
          }
          if (param.editTab) {
            param.editTab.open_edition = res.open_edition || ''
          } else if (param.editAction) {
@@ -1090,9 +974,39 @@
      }
    })
    
    config.action && config.action.forEach((btn) => {
      if (['prompt', 'exec', 'pop'].includes(btn.OpenType) && btn.Ot === 'required' && btn.verify && btn.verify.scripts && btn.verify.scripts.length > 0) {
        let hascheck = false
        btn.verify.scripts.forEach(item => {
          if (item.status === 'false') return
          if (/\$check@|@check\$/ig.test(item.sql)) {
            hascheck = true
          }
        })
        if (hascheck) {
          notification.warning({
            top: 92,
            message: `可选择多行的按钮《${btn.label}》中 $check@ 或 @check$ 将不会生效!`,
            duration: 5
          })
        }
      }
      if (btn.intertype === 'custom' && btn.callbackType === 'script' && (!btn.verify || !btn.verify.cbScripts || !btn.verify.cbScripts.filter(item => item.status !== 'false').length === 0)) {
        notification.warning({
          top: 92,
          message: `按钮《${btn.label}》未设置回调脚本, 将不会生效!`,
          duration: 5
        })
      }
    })
    if (config.setting.interType === 'system' && config.setting.default !== 'false' && !config.setting.dataresource) {
      return '菜单尚未设置数据源,不可启用!'
    if ((config.setting.interType === 'system' || config.setting.requestMode === 'system') && config.setting.default === 'false' && config.setting.scripts && config.setting.scripts.filter(item => item.status !== 'false').length === 0) {
      return '数据源中不执行默认sql,且未添加自定义脚本,不可启用!'
    } else if (config.setting.interType === 'custom' && config.setting.procMode !== 'inner' && config.setting.preScripts && config.setting.preScripts.filter(item => item.status !== 'false').length === 0) {
      return '数据源未设置前置脚本,不可启用!'
    } else if (config.setting.interType === 'custom' && config.setting.callbackType === 'script' && config.setting.cbScripts && config.setting.cbScripts.filter(item => item.status !== 'false').length === 0) {
      return '数据源未设置回调脚本,不可启用!'
    } else if (!config.setting.primaryKey) {
      return '菜单尚未设置主键,不可启用!'
    } else if (config.columns.length === 0) {
@@ -1126,62 +1040,18 @@
   * @description 编辑功能完成更新,包括解冻按钮、粘贴、替换等
   */
  editConfig = (res) => {
    if (res.type === 'thaw') {
      this.setState({
        thawButtons: res.thawButtons,
        config: res.config
      })
    } else if (res.type === 'paste') {
      this.setState({
        pasteContent: res.content
      }, () => {
        this.setState({
          pasteContent: null
        })
      })
    } else if (res.type === 'replace') {
      let config = fromJS(this.state.config).toJS()
      if (res.repType === 'field') {
        let origin = res.origin.toLowerCase()
        let value = res.value
        config.search = config.search.map(item => {
          if (item.field && item.field.toLowerCase() === origin) {
            item.field = value
          } else if (item.datefield && item.datefield.toLowerCase() === origin) {
            item.datefield = value
          }
          return item
        })
        config.columns = config.columns.map(item => {
          if (item.field && item.field.toLowerCase() === origin) {
            item.field = value
          } else if (item.nameField && item.nameField.toLowerCase() === origin) {
            item.nameField = value
          }
          return item
        })
      }
      notification.success({
        top: 92,
        message: '替换成功。',
        duration: 2
      })
      this.setState({ config })
    }
    this.setState({
      thawButtons: res.thawButtons,
      config: res.config
    })
  }
  /**
   * @description 更新搜索条件配置信息
   */
  updatesearch = (config, options) => {
    const { optionLibs } = this.state
  updatesearch = (config) => {
    this.setState({
      config: config,
      optionLibs: options || optionLibs
      config: config
    })
  }
@@ -1209,28 +1079,6 @@
  }
  
  /**
   * @description 更新常用表信息,快捷添加后更新配置信息
   */
  updatetable = (config, fields) => {
    const { tableFields } = this.state
    this.setState({
      config: config,
      tableFields: fields ? fields : tableFields
    })
  }
  /**
   * @description 更新标签配置信息
   */
  updatetabs = (config) => {
    this.setState({
      config: config
    })
  }
  /**
   * @description 更新配置信息
   */
  updateconfig = (config) => {
@@ -1239,11 +1087,74 @@
    })
  }
  refreshConfig = () => {
    const { menu } = this.props
    let param = {
      func: 'sPC_Get_LongParam',
      MenuID: menu.MenuID
    }
    Api.getSystemConfig(param).then(res => {
      if (res.status) {
        let _config = ''
        if (res.LongParam) {
          try {
            _config = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
          } catch (e) {
            console.warn('Parse Failure')
            _config = ''
          }
        }
        if (!_config) {
          notification.warning({
            top: 92,
            message: '未获取到配置信息!',
            duration: 5
          })
          return
        }
        _config.ParentId = menu.ParentId
        _config.fstMenuId = menu.fstMenuId
        _config.MenuName = menu.MenuName || ''
        _config.MenuNo = menu.MenuNo || ''
        _config.OpenType = menu.PageParam ? menu.PageParam.OpenType : ''
        _config.easyCode = _config.easyCode || ''
        // 版本兼容
        _config = updateCommonTable(_config)
        this.setState({
          config: null
        }, () => {
          this.setState({
            chartview: _config.charts ? _config.charts[0].uuid : '',
            config: _config,
            openEdition: res.open_edition || '',
            activeKey: menu.activeKey || '0',
            originActions: [],
            originMenu: fromJS(_config).toJS()
          })
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      }
    })
  }
  render () {
    const { menu } = this.props
    const { activeKey, config, chartview } = this.state
    const { activeKey, config, chartview, openEdition } = this.state
    const confActions = config.action.filter(_action => !_action.origin && ['pop', 'popview', 'blank', 'tab'].includes(_action.OpenType))
    if (!config) return null
    const confActions = config.action.filter(_action => !_action.origin && (['pop', 'popview'].includes(_action.OpenType) || (_action.OpenType === 'tab' && _action.tabTemplate === 'FormTab') || (_action.OpenType === 'funcbutton' && _action.execMode === 'pop')))
    let configTabs = []
    config.tabgroups.forEach(group => {
@@ -1257,35 +1168,33 @@
          <div className="tools">
            <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
              {/* 基本信息 */}
              <Panel forceRender={true} header={this.state.dict['header.menu.basedata']} key="0" id="main-basedata">
              <Panel forceRender={true} header="基本信息" key="0" id="main-basedata">
                {/* 菜单信息 */}
                <MenuForm
                  menu={menu}
                  config={config}
                  dict={this.state.dict}
                  updatemenu={this.updateconfig}
                />
                {config ? <UrlFieldComponent
                  config={config}
                  updateConfig={this.updateconfig}
                /> : null}
                {/* 表名添加 */}
                <TableComponent
                  config={config}
                  containerId="main-basedata"
                  updatetable={this.updatetable}
                  updatetable={this.updateconfig}
                />
              </Panel>
              {/* 搜索条件添加 */}
              <Panel header={this.state.dict['header.menu.search']} key="1">
              <Panel header="搜索" key="1">
                <div className="search-element">
                  {Source.searchItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                <FieldsComponent
                  config={config}
                  type="search"
                  tableFields={this.state.tableFields}
                  updatefield={this.updateconfig}
                />
                <FieldsComponent config={config} type="search" />
              </Panel>
              {/* 按钮添加 */}
              <Panel header={this.state.dict['header.menu.action']} key="2">
              <Panel header="按钮" key="2">
                <div className="search-element">
                  {Source.actionItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
@@ -1293,9 +1202,9 @@
                  {confActions.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.action.configurable']}
                      按钮配置
                    </p> : null
                  }
                </div>
@@ -1313,28 +1222,23 @@
                })}
              </Panel>
              {/* 添加显示列 */}
              <Panel header={this.state.dict['header.menu.column']} key="3">
              <Panel header="显示列" key="3">
                <div className="search-element">
                  {Source.columnItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                <FieldsComponent
                  config={config}
                  type="columns"
                  tableFields={this.state.tableFields}
                  updatefield={this.updateconfig}
                />
                <FieldsComponent config={config} type="columns"/>
              </Panel>
              {/* 添加标签 */}
              <Panel header={this.state.dict['header.menu.tab']} key="4">
              <Panel header="标签页" key="4">
                <div className="search-element">
                  {Source.tabItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                {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) => {
@@ -1355,38 +1259,36 @@
          <div className="setting">
            <Card title={
              <div>
                {this.state.dict['header.menu.page.configurable']}
                <Icon type="redo" style={{marginLeft: '10px'}} title="刷新标签列表" onClick={() => this.reloadTab(true)} />
                页面配置
                <RedoOutlined style={{marginLeft: '10px'}} title="刷新标签列表" onClick={() => this.reloadTab(true)} />
              </div>
            } bordered={false} extra={
              <div>
                <EditComponent dict={this.state.dict} type="maintable" config={this.state.config} MenuID={this.props.menu.MenuID} thawButtons={this.state.thawButtons} refresh={this.editConfig}/>
                <Switch className="big" checkedChildren={this.state.dict['model.enable']} unCheckedChildren={this.state.dict['model.disable']} checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                <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>
                <Unattended config={config} updateConfig={this.updateconfig}/>
                <Versions MenuId={menu.MenuID} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} MenuID={this.props.menu.MenuID} thawButtons={this.state.thawButtons} refresh={this.editConfig}/>
                <UpdateTable config={config}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
                <Button onClick={this.cancelConfig}>关闭</Button>
              </div>
            } style={{ width: '100%' }}>
              <SettingComponent
                config={config}
                MenuID={this.props.menu.MenuID}
                permFuncField={this.props.permFuncField}
                MenuID={menu.MenuID}
                updatesetting={this.updateconfig}
              />
              <SearchComponent
                menu={{MenuID: this.props.menu.MenuID, MenuName: config.MenuName}}
                config={config}
                pasteContent={this.state.pasteContent}
                sysRoles={this.props.sysRoles}
                optionLibs={this.state.optionLibs}
                updatesearch={this.updatesearch}
              />
              <div className="chart-view" style={{position: 'relative'}}>
                {/* 视图组 权限 会员等级20+ */}
                {this.props.memberLevel >= 20 ? <ChartGroupComponent
              {config.charts ? <div className="chart-view" style={{position: 'relative'}}>
                {/* 视图组 已弃用 */}
                <ChartGroupComponent
                  config={config}
                  sysRoles={this.props.sysRoles}
                  updatechartgroup={this.updatechartgroup}
                /> : null}
                />
                {config.charts.map(item => {
                  if (!config.expand && chartview !== item.uuid) return ''
@@ -1399,16 +1301,12 @@
                          menu={{ MenuID: this.props.menu.MenuID, MenuName: config.MenuName, MenuNo: config.MenuNo, fstMenuList: this.props.menu.fstMenuList }}
                          config={config}
                          tabs={this.state.tabviews}
                          pasteContent={this.state.pasteContent}
                          usefulFields={this.props.permFuncField}
                          setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')}
                          updateaction={this.updateaction}
                        />
                        <ColumnComponent
                          config={config}
                          menu={this.props.menu}
                          sysRoles={this.props.sysRoles}
                          pasteContent={this.state.pasteContent}
                          updatecolumn={this.updateconfig}
                        />
                      </Col>
@@ -1435,13 +1333,27 @@
                    )
                  }
                })}
              </div>
              </div> : <>
                <ActionComponent
                  type="main"
                  menu={{ MenuID: this.props.menu.MenuID, MenuName: config.MenuName, MenuNo: config.MenuNo, fstMenuList: this.props.menu.fstMenuList }}
                  config={config}
                  tabs={this.state.tabviews}
                  setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')}
                  updateaction={this.updateaction}
                />
                <ColumnComponent
                  config={config}
                  menu={this.props.menu}
                  updatecolumn={this.updateconfig}
                />
              </>}
              {/* 标签组 */}
              <TabsComponent
                config={config}
                tabs={this.state.tabviews}
                setSubConfig={(item) => this.setSubConfig(item, 'tab')}
                updatetabs={this.updatetabs}
                updatetabs={this.updateconfig}
              />
            </Card>
          </div>
@@ -1454,13 +1366,13 @@
          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['model.save']}</Button>,
            <Button key="notsave" className="mk-btn mk-yellow" onClick={this.notsave}>{this.state.dict['model.notsave']}</Button>,
            <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['model.cancel']}</Button>
            <Button key="save" className="mk-btn mk-green" loading={this.state.menucloseloading} onClick={this.submitConfig}>保存</Button>,
            <Button key="notsave" className="mk-btn mk-yellow" onClick={this.notsave}>不保存</Button>,
            <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>取消</Button>
          ]}
          destroyOnClose
        >
          {this.state.dict['header.menu.config.placeholder']}
          配置已修改,是否保存配置信息?
        </Modal>
        {this.state.loading && <Spin size="large" />}
      </div>
@@ -1468,16 +1380,4 @@
  }
}
const mapStateToProps = (state) => {
  return {
    sysRoles: state.sysRoles,
    permFuncField: state.permFuncField,
    memberLevel: state.memberLevel
  }
}
const mapDispatchToProps = () => {
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(ComTableConfig)
export default ComTableConfig