king
2020-08-22 835b48025a582b1c19c4de128906aff6a5e63612
2020-08-22
31个文件已修改
18个文件已添加
5776 ■■■■■ 已修改文件
src/assets/mobimg/bar.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/bar1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/mob.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/mob.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/model.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.scss 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/mob-login-2/index.jsx 423 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/mob-login-2/index.scss 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/header/index.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/header/index.scss 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/card.jsx 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/index.jsx 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/index.scss 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modelsource/dragsource/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modelsource/dragsource/index.scss 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modelsource/index.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modelsource/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modelsource/option.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/calendarconfig/index.jsx 684 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 1055 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/menuform/index.jsx 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/menuconfig/editthdmenu/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/menuconfig/editthdmenu/menuform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/index.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/chartgroupcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/chartgroupcomponent/index.scss 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/fieldscomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/treesettingcomponent/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.jsx 817 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/menuform/index.jsx 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/treepageconfig/index.jsx 817 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 190 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.scss 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/bar.png
src/assets/mobimg/bar1.png
src/components/header/index.jsx
@@ -744,9 +744,9 @@
        {this.props.editLevel === 'HS' ? <Button className="level4-close" type="primary" onClick={this.exitManage}>退出</Button> : null}
        {/* 进入编辑按钮 */}
        {this.props.editState && !this.props.editLevel ? <Icon onClick={this.enterEdit} className="edit-check" type="edit" /> : null}
        {this.props.editState && !this.props.editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' ?
        {/* {this.props.editState && !this.props.editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' ?
          <a href="#/mobmanage" target="_blank" className="mobile" type="edit"> 应用管理 <Icon type="arrow-right" /></a> : null
        }
        } */}
        {/* 编辑菜单 */}
        {this.props.editLevel === 'level1' ? <EditMenu menulist={this.state.menulist} reload={this.reload} exitEdit={this.exitEdit}/> : null}
        {/* 头像、用户名 */}
src/locales/en-US/mob.js
@@ -7,6 +7,9 @@
  'mob.logout': '退出',
  'mob.name': '名称',
  'mob.param': '参数',
  'mob.enable': '启',
  'mob.disable': '停',
  'mob.save': '保存',
  'mob.menu': '菜单',
  'mob.menu.first': '一级',
  'mob.menu.second': '二级',
src/locales/zh-CN/mob.js
@@ -7,6 +7,9 @@
  'mob.logout': '退出',
  'mob.name': '名称',
  'mob.param': '参数',
  'mob.enable': '启',
  'mob.disable': '停',
  'mob.save': '保存',
  'mob.menu': '菜单',
  'mob.menu.first': '一级',
  'mob.menu.second': '二级',
src/locales/zh-CN/model.js
@@ -257,7 +257,7 @@
  'form.required.input': '请输入',
  'form.required.select': '请选择',
  'form.required.add': '请添加',
  'model.tooltip.table.guide': '添加页面配置相关的常用表,可通过常用表字段批量添加搜索条件、显示列、数据源字段集。',
  'model.tooltip.table.guide': '添加页面配置相关的常用表,可通过常用表字段批量添加搜索条件、显示列、数据源字段集等。',
  'model.tooltip.search.guide': '在左侧工具栏《搜索》中,选择对应搜索框拖至此处添加;或点击按钮《添加搜索条件》批量添加,选择批量添加时,需提前选择使用表。',
  'model.tooltip.action.guide': '在左侧工具栏《按钮》中,选择对应类型的按钮拖至此处添加,如选择按钮类型为表单、新标签页等含有配置页面的按钮,可在左侧工具栏-按钮-可配置按钮处,点击按钮完成相关配置。注:当设置按钮显示位置为表格时,显示列会增加操作列。',
  'model.tooltip.column.guide': '在左侧工具栏《显示列》中,选择对应类型的显示列拖至此处添加;或点击《添加显示列》按钮批量添加,选择批量添加时,需提前选择使用表。注:添加合并列时,需设置可选列。',
src/menu/components/chart/antv-bar/index.jsx
New file
@@ -0,0 +1,227 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { InputItem, Icon, Checkbox, List, Button } from 'antd-mobile'
// import { createForm } from 'rc-form'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
import Utils from '@/utils/utils.js'
import ContentUpdate from '@/mob/contupdate'
import mklogo from '@/assets/mobimg/mklogo.png'
import './index.scss'
const CheckboxItem = Checkbox.CheckboxItem
class MobLogin extends Component {
  static propTpyes = {
    card: PropTypes.object,
    editId: PropTypes.any,
    triggerEdit: PropTypes.func,
    updateConfig: PropTypes.func,
    onDoubleClick: PropTypes.func
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    rember: true,
    param: {
      type: 'login',
      subtype: 'mob-login-1',
      box: { uuid: Utils.getuuid(), eleType: 'box', style: {color: '#ffffff', backgroundImage: 'linear-gradient(#378DBE, #46C29E, #48A9D6)'}},
      logo: { uuid: Utils.getuuid(), eleType: 'img', content: mklogo, style: {marginTop: '17vh', marginBottom: '15px'} },
      title: { uuid: Utils.getuuid(), eleType: 'text', content: '明科商业智能开放平台', style: {fontSize: '20px', fontWeight: 'bold', color: '#ffffff', textAlign: 'center', marginTop: '15px', marginBottom: '30px'}},
      login: { uuid: Utils.getuuid(), eleType: 'button', content: '登录', style: {fontSize: '18px', color: '#ffffff', textAlign: 'center', lineHeight: 2.4, borderRadius: '25px', marginBottom: '15vh'}},
      copyright: { uuid: Utils.getuuid(), eleType: 'textarea', content: 'Copyright©2017  所有相关版权归  北京明科普华信息技术有限公司', style: {fontSize: '12px', color: '#ffffff', textAlign: 'center'} }
    }
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    if (card.isNew) {
      // this.props.updateConfig({...param, ...card})
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  onChange = (e) => {
    const { rember } = this.state
    e.stopPropagation()
    this.setState({
      rember: !rember
    })
  }
  onChangeLang = (value) => {
    this.setState({
      lang: value
    })
  }
  editLogo = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.logo.style).toJS(),
      componentId: card.uuid,
      uuid: card.logo.uuid,
      items: ['margin']
    }
    this.props.triggerEdit(element)
  }
  editTitle = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.title.style).toJS(),
      componentId: card.uuid,
      uuid: card.title.uuid,
      items: ['font', 'margin'],
    }
    this.props.triggerEdit(element)
  }
  editMsg = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.copyright.style).toJS(),
      componentId: card.uuid,
      uuid: card.copyright.uuid,
      items: ['font'],
    }
    this.props.triggerEdit(element)
  }
  editLogin = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.login.style).toJS(),
      componentId: card.uuid,
      uuid: card.login.uuid,
      items: ['font', 'background', 'border', 'margin']
    }
    this.props.triggerEdit(element)
  }
  editBox = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.box.style).toJS(),
      componentId: card.uuid,
      uuid: card.box.uuid,
      items: ['font', 'padding', 'background'],
    }
    this.props.triggerEdit(element)
  }
  updateContent = (card) => {
    Object.keys(card).forEach(key => {
      if (card[key] === null) {
        delete card[key]
      }
    })
    this.props.updateConfig(card)
  }
  render () {
    const { card, editId } = this.props
    // const { getFieldProps } = this.props.form
    const { rember } = this.state
    if (!card.box) return null
    let logoStyle = card.logo && card.logo.style ? fromJS(card.logo.style).toJS() : null
    if (logoStyle && logoStyle.marginTop && /vh$/ig.test(logoStyle.marginTop)) {
      let percent = parseInt(logoStyle.marginTop)
      logoStyle.marginTop = `calc(${(percent / 100) * 615}px)`
    }
    if (logoStyle && logoStyle.marginBottom && /vh$/ig.test(logoStyle.marginBottom)) {
      let percent = parseInt(logoStyle.marginBottom)
      logoStyle.marginBottom = `calc(${(percent / 100) * 625}px)`
    }
    let titleStyle = card.title && card.title.style ? fromJS(card.title.style).toJS() : null
    if (titleStyle && titleStyle.marginTop && /vh$/ig.test(titleStyle.marginTop)) {
      let percent = parseInt(titleStyle.marginTop)
      titleStyle.marginTop = `calc(${(percent / 100) * 615}px)`
    }
    if (titleStyle && titleStyle.marginBottom && /vh$/ig.test(titleStyle.marginBottom)) {
      let percent = parseInt(titleStyle.marginBottom)
      titleStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
    }
    let loginStyle = fromJS(card.login.style).toJS()
    if (loginStyle.marginTop && /vh$/ig.test(loginStyle.marginTop)) {
      let percent = parseInt(loginStyle.marginTop)
      loginStyle.marginTop = `calc(${(percent / 100) * 615}px)`
    }
    if (loginStyle.marginBottom && /vh$/ig.test(loginStyle.marginBottom)) {
      let percent = parseInt(loginStyle.marginBottom)
      loginStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
    }
    return (
      <div className="mob-login-1" onClick={this.editBox} style={card.box.style}>
        {card.logo ? <div className={'logo ' + (editId === card.logo.uuid ? 'editing' : '')} style={logoStyle} onClick={this.editLogo}>
          <ContentUpdate element={card.logo} updateContent={(ele) => this.updateContent({...card, logo: ele})}/>
          <img src={card.logo.content} alt=""/>
        </div> : null}
        {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
          <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
          {card.title.content}
        </div> : null}
        <InputItem
          placeholder={"UserName"}
          prefixListCls="mk-login-item am-list"
          disabled={true}
        >
          <Icon type="check-circle-o" />
        </InputItem>
        <InputItem
          placeholder="Password"
          prefixListCls="mk-login-item am-list"
          type={'password'}
          disabled={true}
        >
          <Icon type="check-circle" />
        </InputItem>
        <div className="other-setting">
          <CheckboxItem checked={rember} onChange={this.onChange}>
            <span onClick={this.onChange}>记住密码</span>
          </CheckboxItem>
          {/* <Picker data={langs} value={lang} cols={1} onChange={this.onChangeLang} className="forss">
            <List.Item>{lang}</List.Item>
          </Picker> */}
          <List.Item className="lang">中文简体</List.Item>
          <div className="clear-both"></div>
        </div>
        <Button
          type="primary"
          className={'login ' + (editId === card.login.uuid ? 'editing' : '')}
          onDoubleClick={() => this.props.doubleClickCard(card.login)}
          style={loginStyle}
          onClick={this.editLogin}
        >
          <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
          {card.login.content}
        </Button>
        {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
          <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
          {card.copyright.content}
        </div> : null}
      </div>
    )
  }
}
// export default createForm()(MobLogin)
export default MobLogin
src/menu/components/chart/antv-bar/index.scss
New file
@@ -0,0 +1,192 @@
.mob-login-1 {
  position: relative;
  width: 100%;
  min-height: 100%;
  overflow-x: hidden;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center center;
  border-top: 1px solid transparent;
  .logo {
    position: relative;
    font-size: 14px;
    max-width: 280px;
    min-height: 10px;
    margin: 0 auto;
    text-align: center;
    line-height: 1.5;
    border: 1px dotted transparent;
    img {
      max-width: 100%;
    }
  }
  .logo.editing {
    border: 1px solid #1890ff;
    box-shadow: 0px 0px 2px #1890ff;
  }
  .logo:not(.editing):hover {
    border-color: #535353;
  }
  .plat-name {
    position: relative;
    max-width: 280px;
    min-height: 10px;
    margin: 0 auto;
    margin-top: 15px;
    margin-bottom: 30px;
    text-align: center;
    line-height: 1.5;
    font-size: 20px;
    color: #ffffff;
    font-weight: bold;
    letter-spacing: 0px;
    border: 1px dotted transparent;
  }
  .plat-name.editing {
    border: 1px solid #1890ff;
    box-shadow: 0px 0px 2px #1890ff;
  }
  .plat-name:not(.editing):hover {
    border-color: #535353;
  }
  .mk-login-item.am-list-item {
    position: relative;
    z-index: 1;
    width: 245px;
    font-size: 14px;
    max-width: 270px;
    line-height: 1.5;
    margin: 0 auto;
    margin-bottom: 10px;
    border-radius: 30px;
    background-color: rgba(255, 255, 255, 0.3);
    .am-input-label {
      width: 30px;
      color: inherit;
      padding-top: 10px;
    }
    input {
      color: inherit;
    }
    input::-webkit-input-placeholder {
      color: inherit;
    }
    input:-moz-placeholder {
      color: inherit;
    }
    input::-moz-placeholder {
      color: inherit;
    }
    input:-ms-input-placeholder {
      color: inherit;
    }
    .am-input-control input:disabled {
      background-color: transparent;
    }
  }
  .am-list-item:not(:last-child) .am-list-line {
    border: none;
  }
  .other-setting {
    position: relative;
    z-index: 1;
    font-size: 14px;
    width: 245px;
    max-width: 270px;
    line-height: 1.5;
    margin: 0 auto;
    margin-bottom: 10px;
    .am-list-item {
      float: left;
      background: transparent;
      width: 50%;
      padding: 0;
      .am-list-thumb:first-child {
        margin-right: 5px;
        cursor: pointer;
        .am-checkbox-inner {
          width: 18px;
          height: 18px;
        }
        .am-checkbox-inner:after {
          width: 5px;
          height: 9px;
        }
      }
      .am-list-line .am-list-content {
        font-size: 14px;
        color: inherit;
        cursor: pointer;
      }
      .am-list-extra {
        display: none;
      }
    }
    .am-list-item.lang {
      float: right;
      .am-list-line {
        padding-right: 10px;
        .am-list-content {
          text-align: right;
          cursor: default;
        }
      }
    }
  }
  .am-button {
    position: relative;
    z-index: 1;
    width: 245px;
    max-width: 270px;
    margin: 0 auto;
    border: 1px dotted transparent;
    overflow: visible;
    letter-spacing: 0px;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
    span {
      font-style: inherit;
      font-weight: inherit;
    }
  }
  .am-button:hover {
    color: #fff;
    border-color: #535353;
  }
  .company-msg {
    max-width: 280px;
    min-height: 10px;
    margin: 0 auto;
    font-size: 12px;
    color: #fafafa;
    text-align: center;
    line-height: 1.5;
    letter-spacing: 0px;
    border: 1px dotted transparent;
  }
  .company-msg.editing {
    border: 1px solid #1890ff;
    box-shadow: 0px 0px 2px #1890ff;
  }
  .company-msg:not(.editing):hover {
    border-color: #535353;
  }
}
.am-picker-popup-wrap {
  left: calc(50vw - 305px);
  right: calc(50vw - 45px);
  bottom: 54px;
  overflow: hidden;
}
.clear-both {
  float: none!important;
  clear: both;
}
src/menu/components/chart/mob-login-2/index.jsx
New file
@@ -0,0 +1,423 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { InputItem, Button } from 'antd-mobile'
import { Icon } from 'antd'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
import Utils from '@/utils/utils.js'
import ContentUpdate from '@/mob/contupdate'
import ContentDelete from '@/mob/contdelete'
import './index.scss'
class MobLogin2 extends Component {
  static propTpyes = {
    card: PropTypes.object,
    editId: PropTypes.any,
    triggerEdit: PropTypes.func,
    updateConfig: PropTypes.func,
    onDoubleClick: PropTypes.func
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    view: 'account',
    param: {
      type: 'login',
      subtype: 'mob-login-2',
      box: { uuid: Utils.getuuid(), eleType: 'box', style: {}},
      title: {
        uuid: Utils.getuuid(), eleType: 'text', content: '登录',
        style: {
          fontSize: '18px', fontWeight: 'bold', color: '#000000', textAlign: 'center', marginTop: '10vh', marginBottom: '10vh'
        }
      },
      user: { uuid: Utils.getuuid(), eleType: 'input', content: '邮箱/手机', style: {}},
      password: { uuid: Utils.getuuid(), eleType: 'input', content: '密码', style: {}},
      login: {
        uuid: Utils.getuuid(), eleType: 'button', content: '登录',
        style: {
          fontSize: '16px', color: '#ffffff', textAlign: 'center', lineHeight: 2.4, backgroundColor: '#44a8f2'
        }
      },
      phone: {
        uuid: Utils.getuuid(), eleType: 'button', content: '手机短信登录',
        style: {
          fontSize: '16px', color: '#44a8f2', textAlign: 'center', lineHeight: 2.4, border: '1px solid #44a8f2'
        }
      },
      register: {
        uuid: Utils.getuuid(), eleType: 'text', content: '注册',
        style: {
          fontSize: '14px', color: '#44a8f2', textAlign: 'left'
        }
      },
      lose: {
        uuid: Utils.getuuid(), eleType: 'text', content: '忘记密码?',
        style: {
          fontSize: '14px', color: '#44a8f2', textAlign: 'right', textDecoration: 'underline'
        }
      },
      auth: {
        uuid: Utils.getuuid(), eleType: 'text', content: '其他登录方式',
        style: {
          fontSize: '14px', color: '#bcbcbc', textAlign: 'center', marginTop: '30px', marginBottom: '20px'
        }
      },
      authlist: {
        uuid: Utils.getuuid(),
        subItems: [
          {uuid: 'qq', type: 'qq', icon: 'qq', label: 'QQ'},
          {uuid: 'wechat', type: 'wechat', icon: 'wechat', label: '微信'},
        ],
      },
      copyright: {
        uuid: Utils.getuuid(), eleType: 'textarea', content: 'Copyright©2017  所有相关版权归  北京明科普华信息技术有限公司',
        style: {
          fontSize: '12px', textAlign: 'center', color: 'rgba(0, 0, 0, 0.65)'
        }
      },
      links: {
        uuid: Utils.getuuid(), eleType: 'link', substyle: false,
        subItems: [
          {eleType: 'link', content: '隐私政策', url: '', uuid: Utils.getuuid()},
          {eleType: 'link', content: '使用条款', url: '', uuid: Utils.getuuid()},
        ],
        style: {
          fontSize: '12px', textAlign: 'center', color: '#44a8f2', textDecoration: 'underline'
        }
      },
      account: {
        uuid: Utils.getuuid(), eleType: 'button', content: '账号密码登录',
        style: {
          fontSize: '16px', color: '#44a8f2', textAlign: 'center', lineHeight: 2.4, border: '1px solid #44a8f2'
        }
      },
    }
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    const { param } = this.state
    if (!card.box) {
      this.props.updateConfig({...param, ...card})
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  editTitle = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.title.style).toJS(),
      componentId: card.uuid,
      uuid: card.title.uuid,
      items: ['font', 'margin'],
    }
    this.props.triggerEdit(element)
  }
  editPlaceholder = (e, type) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      componentId: card.uuid,
      uuid: card[type].uuid,
      items: [''],
    }
    this.props.triggerEdit(element)
  }
  editMsg = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.copyright.style).toJS(),
      componentId: card.uuid,
      uuid: card.copyright.uuid,
      items: ['font', 'margin'],
    }
    this.props.triggerEdit(element)
  }
  editLinks = (e, item) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.links.style).toJS(),
      componentId: card.uuid,
      classId: card.links.uuid,
      uuid: item.uuid,
      items: ['font'],
    }
    this.props.triggerEdit(element)
  }
  editLogin = (e, type) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card[type].style).toJS(),
      componentId: card.uuid,
      uuid: card[type].uuid,
      items: ['font', 'background', 'border', 'margin']
    }
    this.props.triggerEdit(element)
  }
  editLose = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.lose.style).toJS(),
      componentId: card.uuid,
      uuid: card.lose.uuid,
      items: ['font'],
    }
    this.props.triggerEdit(element)
  }
  editRegister = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.register.style).toJS(),
      componentId: card.uuid,
      uuid: card.register.uuid,
      items: ['font'],
    }
    this.props.triggerEdit(element)
  }
  editAuth = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.auth.style).toJS(),
      componentId: card.uuid,
      uuid: card.auth.uuid,
      items: ['font', 'margin'],
    }
    this.props.triggerEdit(element)
  }
  editBox = (e) => {
    const { card } = this.props
    e.stopPropagation()
    let element = {
      ...fromJS(card.box.style).toJS(),
      componentId: card.uuid,
      uuid: card.box.uuid,
      items: ['font', 'padding', 'background'],
    }
    this.props.triggerEdit(element)
  }
  linkItemAdd = (e) => {
    let card = fromJS(this.props.card).toJS()
    e.stopPropagation()
    card.links.subItems.push({
      eleType: 'link',
      content: 'link',
      url: '',
      uuid: Utils.getuuid()
    })
    this.props.updateConfig(card)
  }
  updateContent = (card) => {
    this.props.updateConfig(card)
  }
  updateLinkItem = (val, item) => {
    let card = fromJS(this.props.card).toJS()
    if (!val) {
      card.links.subItems = card.links.subItems.filter(cell => cell.uuid !== item.uuid)
    } else {
      card.links.subItems = card.links.subItems.map(cell => {
        if (cell.uuid === item.uuid) {
          return val
        } else {
          return cell
        }
      })
    }
    this.props.updateConfig(card)
  }
  render () {
    const { card, editId } = this.props
    const { view } = this.state
    if (!card.box) return null
    let titleStyle = card.title && card.title.style ? fromJS(card.title.style).toJS() : null
    if (titleStyle && titleStyle.marginTop && /vh$/ig.test(titleStyle.marginTop)) {
      let percent = parseInt(titleStyle.marginTop)
      titleStyle.marginTop = `calc(${(percent / 100) * 615}px)`
    }
    if (titleStyle && titleStyle.marginBottom && /vh$/ig.test(titleStyle.marginBottom)) {
      let percent = parseInt(titleStyle.marginBottom)
      titleStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
    }
    if (view === 'account') {
      return (
        <div className="mob-login-2" onClick={this.editBox} style={card.box.style}>
          {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
            <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
            {card.title.content}
          </div> : null}
          <div className={`mk-login-input ${editId === card.user.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'user')}>
            <ContentUpdate element={card.user} deletable={false} updateContent={(ele) => this.updateContent({...card, user: ele})}/>
            <InputItem disabled={true} placeholder={card.user.content}></InputItem>
          </div>
          <div className={`mk-login-input ${editId === card.password.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'password')}>
            <ContentUpdate element={card.password} deletable={false} updateContent={(ele) => this.updateContent({...card, password: ele})}/>
            <InputItem disabled={true} placeholder={card.password.content}></InputItem>
          </div>
          <Button
            className={'login ' + (editId === card.login.uuid ? 'editing' : '')}
            onDoubleClick={() => this.props.doubleClickCard(card.login)}
            style={card.login.style}
            onClick={(e) => this.editLogin(e, 'login')}
          >
            <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
            {card.login.content}
          </Button>
          <Button
            className={'login ' + (editId === card.phone.uuid ? 'editing' : '')}
            onDoubleClick={() => this.setState({view: 'phone'})}
            style={card.phone.style}
            onClick={(e) => this.editLogin(e, 'phone')}
          >
            <ContentUpdate element={card.phone} updateContent={(ele) => this.updateContent({...card, phone: ele})}/>
            {card.phone.content}
          </Button>
          <div className="row-box">
            {card.register ? <div className={'col-item ' + (editId === card.register.uuid ? 'editing' : '')} style={card.register.style} onClick={this.editRegister}>
              <ContentUpdate element={card.register} updateContent={(ele) => this.updateContent({...card, register: ele})}/>
              {card.register.content}
            </div> : null}
            {card.lose ? <div className={'col-item right ' + (editId === card.lose.uuid ? 'editing' : '')} style={card.lose.style} onClick={this.editLose}>
              <ContentUpdate element={card.lose} updateContent={(ele) => this.updateContent({...card, lose: ele})}/>
              {card.lose.content}
            </div> : null}
            <div style={{clear: 'both'}}></div>
          </div>
          {card.auth ? <div className={'plat-name ' + (editId === card.auth.uuid ? 'editing' : '')} style={card.auth.style} onClick={this.editAuth}>
            <ContentUpdate element={card.auth} updateContent={(ele) => this.updateContent({...card, auth: ele})}/>
            {card.auth.content}
          </div> : null}
          {card.authlist ? <div className="other-auth">
            {card.authlist.subItems.map(cell => (
              <span className="deletable-item" key={cell.type}>
                <ContentDelete element={cell} list={card.authlist} updateContent={(ele) => this.updateContent({...card, authlist: ele})}/>
                <Icon type={cell.icon} />
                <p>{cell.label}</p>
              </span>
            ))}
          </div> : null}
          {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
            <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
            {card.copyright.content}
          </div> : null}
          {card.links ? <div className="links" style={card.links.style}>
            {card.links.subItems.map(item => (
              <span className={(editId === item.uuid ? 'editing' : '')} key={item.uuid} onClick={(e) => this.editLinks(e, item)}>
                <ContentUpdate element={item} updateContent={(val) => this.updateLinkItem(val, item)}/>
                {item.content}
              </span>
            ))}
            <Icon type="plus" onClick={this.linkItemAdd} />
          </div> : null}
        </div>
      )
    } else if (view === 'phone') {
      return (
        <div className="mob-login-2" onClick={this.editBox} style={card.box.style}>
          {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
            <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
            {card.title.content}
          </div> : null}
          <div className={`mk-login-input ${editId === card.user.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'user')}>
            <ContentUpdate element={card.user} deletable={false} updateContent={(ele) => this.updateContent({...card, user: ele})}/>
            <InputItem disabled={true} placeholder={card.user.content}></InputItem>
          </div>
          <div className={`mk-login-input ${editId === card.password.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'password')}>
            <ContentUpdate element={card.password} deletable={false} updateContent={(ele) => this.updateContent({...card, password: ele})}/>
            <InputItem disabled={true} placeholder={card.password.content}></InputItem>
          </div>
          <Button
            className={'login ' + (editId === card.login.uuid ? 'editing' : '')}
            onDoubleClick={() => this.props.doubleClickCard(card.login)}
            style={card.login.style}
            onClick={(e) => this.editLogin(e, 'login')}
          >
            <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
            {card.login.content}
          </Button>
          <Button
            className={'login ' + (editId === card.account.uuid ? 'editing' : '')}
            onDoubleClick={() => this.setState({view: 'account'})}
            style={card.account.style}
            onClick={(e) => this.editLogin(e, 'account')}
          >
            <ContentUpdate element={card.account} updateContent={(ele) => this.updateContent({...card, account: ele})}/>
            {card.account.content}
          </Button>
          <div className="row-box">
            {card.register ? <div className={'col-item ' + (editId === card.register.uuid ? 'editing' : '')} style={card.register.style} onClick={this.editRegister}>
              <ContentUpdate element={card.register} updateContent={(ele) => this.updateContent({...card, register: ele})}/>
              {card.register.content}
            </div> : null}
            {card.lose ? <div className={'col-item right ' + (editId === card.lose.uuid ? 'editing' : '')} style={card.lose.style} onClick={this.editLose}>
              <ContentUpdate element={card.lose} updateContent={(ele) => this.updateContent({...card, lose: ele})}/>
              {card.lose.content}
            </div> : null}
            <div style={{clear: 'both'}}></div>
          </div>
          {card.auth ? <div className={'plat-name ' + (editId === card.auth.uuid ? 'editing' : '')} style={card.auth.style} onClick={this.editAuth}>
            <ContentUpdate element={card.auth} updateContent={(ele) => this.updateContent({...card, auth: ele})}/>
            {card.auth.content}
          </div> : null}
          {card.authlist ? <div className="other-auth">
            {card.authlist.subItems.map(cell => (
              <span className="deletable-item" key={cell.type}>
                <ContentDelete element={cell} list={card.authlist} updateContent={(ele) => this.updateContent({...card, authlist: ele})}/>
                <Icon type={cell.icon} />
                <p>{cell.label}</p>
              </span>
            ))}
          </div> : null}
          {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
            <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
            {card.copyright.content}
          </div> : null}
          {card.links ? <div className="links" style={card.links.style}>
            {card.links.subItems.map(item => (
              <span className={(editId === item.uuid ? 'editing' : '')} key={item.uuid} onClick={(e) => this.editLinks(e, item)}>
                <ContentUpdate element={item} updateContent={(val) => this.updateLinkItem(val, item)}/>
                {item.content}
              </span>
            ))}
            <Icon type="plus" onClick={this.linkItemAdd} />
          </div> : null}
        </div>
      )
    }
  }
}
export default MobLogin2
src/menu/components/chart/mob-login-2/index.scss
New file
@@ -0,0 +1,201 @@
.mob-login-2 {
  position: relative;
  width: 100%;
  min-height: 100%;
  overflow-x: hidden;
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center center;
  .plat-name {
    position: relative;
    max-width: 280px;
    min-height: 10px;
    margin: 0 auto;
    text-align: center;
    line-height: 1.5;
    font-size: 18px;
    color: #ffffff;
    border: 1px dotted transparent;
  }
  .plat-name.editing {
    border: 1px solid #1890ff;
    box-shadow: 0px 0px 2px #1890ff;
  }
  .plat-name:not(.editing):hover {
    border-color: #535353;
  }
  .row-box {
    position: relative;
    width: 280px;
    margin: 0 auto;
    line-height: 1.5;
    .col-item {
      position: relative;
      display: inline-block;
      width: 50%;
      border: 1px dotted transparent;
    }
    .col-item.right {
      float: right;
    }
    .col-item.editing {
      border: 1px solid #1890ff;
      box-shadow: 0px 0px 2px #1890ff;
    }
    .col-item:not(.editing):hover {
      border-color: #535353;
    }
  }
  .other-auth {
    text-align: center;
    font-size: 26px;
    color: rgb(68, 168, 242);
    span {
      position: relative;
      display: inline-block;
      vertical-align: top;
      p {
        font-size: 12px;
        margin-bottom: 10px;
      }
    }
    span:not(:last-child) {
      margin-right: 15px;
    }
  }
  .am-list-item {
    position: relative;
    z-index: 1;
    width: 100%;
    font-size: 14px;
    height: 38px;
    min-height: 38px;
    line-height: 1.5;
    margin-bottom: 10px;
    border: 1px solid #dddddd;
    .am-input-control input:disabled {
      color: rgba(0, 0, 0, 0.65);
    }
    .am-input-label {
      width: 30px;
      color: inherit;
      padding-top: 10px;
    }
    input {
      font-size: 14px;
      color: inherit;
    }
    input::-webkit-input-placeholder {
      color: inherit;
      opacity: 0.5;
    }
    input:-moz-placeholder {
      color: inherit;
      opacity: 0.5;
    }
    input::-moz-placeholder {
      color: inherit;
      opacity: 0.5;
    }
    input:-ms-input-placeholder {
      color: inherit;
      opacity: 0.5;
    }
  }
  .am-list-item:not(:last-child) .am-list-line {
    border: none;
  }
  .mk-login-input {
    width: 280px;
    position: relative;
    margin: 0 auto;
  }
  .am-button {
    position: relative;
    z-index: 1;
    width: 280px;
    margin: 0 auto 10px;
    border: 1px dotted transparent;
    overflow: visible;
    letter-spacing: 0px;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
    border-radius: 0;
    span {
      font-style: inherit;
      font-weight: inherit;
    }
  }
  .am-button:hover {
    color: unset;
    border-color: #535353;
  }
  .company-msg {
    width: 88%;
    min-height: 10px;
    margin-left: 6%;
    font-size: 12px;
    text-align: center;
    line-height: 1.5;
    letter-spacing: 0px;
    border: 1px dotted transparent;
  }
  .company-msg.editing {
    border: 1px solid #1890ff;
    box-shadow: 0px 0px 2px #1890ff;
  }
  .company-msg:not(.editing):hover {
    border-color: #535353;
  }
  .links {
    min-height: 10px;
    font-size: 12px;
    text-align: center;
    line-height: 1.5;
    span {
      display: inline-block;
      position: relative;
      text-decoration: inherit;
      font-style: inherit;
      min-width: 40px;
      border: 1px dotted transparent;
    }
    span:not(:last-child) {
      margin-right: 10px;
    }
    span:hover {
      border-color: #535353;
    }
    span.editing {
      border: 1px solid #1890ff;
      box-shadow: 0px 0px 2px #1890ff;
    }
    >.anticon-plus {
      cursor: pointer;
      color: #26C281;
    }
  }
}
.am-picker-popup-wrap {
  left: calc(50vw - 305px);
  right: calc(50vw - 45px);
  bottom: 54px;
  overflow: hidden;
}
.clear-both {
  float: none!important;
  clear: both;
}
src/menu/header/index.jsx
@@ -3,7 +3,7 @@
import { is, fromJS } from 'immutable'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import {Dropdown, Menu, Icon, Modal, Tooltip, Button } from 'antd'
import {Dropdown, Menu, Icon, Modal } from 'antd'
import { logout } from '@/store/action'
import zhCN from '@/locales/zh-CN/mob.js'
@@ -73,24 +73,8 @@
  render () {
    return (
      <header className="mob-header-container">
      <header className="menu-header-container">
        <div className="header-logo"><img src={this.state.logourl} alt=""/></div>
        <Menu
          mode="inline"
          theme="dark"
          inlineCollapsed={this.state.collapsed}
        >
          <Menu.Item key="1">
            <Tooltip placement="bottom" title="关闭">
              <Icon type="close" onClick={this.props.closeView} />
            </Tooltip>
          </Menu.Item>
          <Menu.Item key="2">
            <Tooltip placement="bottom" title="保存">
              <Button icon="save" loading={this.props.saveIng} onClick={this.props.triggerSave}></Button>
            </Tooltip>
          </Menu.Item>
        </Menu>
        <Dropdown className="header-setting" overlay={
          <Menu>
            <Menu.Item key="2" onClick={this.logout}>{this.state.dict['mob.logout']}</Menu.Item>
src/menu/header/index.scss
@@ -1,7 +1,6 @@
.mob-header-container {
.menu-header-container {
  width: 100%;
  height: 48px;
  padding-right: 320px;
  color: rgba(255, 255, 255, 0.65);
  position: fixed;
  top: 0px;
@@ -46,14 +45,7 @@
      }
    }
  }
  .mob-manage-title {
    position: absolute;
    left: calc(50vw - 45px);
    color: #ffffff;
    font-size: 16px;
    line-height: 48px;
    letter-spacing: 2px;
  }
  >.ant-menu {
    float: left;
    width: unset;
src/menu/menushell/card.jsx
New file
@@ -0,0 +1,53 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Icon } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
const Card = ({ id, card, moveCard, findCard, editId, editCard, delCard, hasDrop, doubleClickCard, updateConfig }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'menu', id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'menu',
    canDrop: () => true,
    drop: (item) => {
      if (!item.hasOwnProperty('originalIndex')) {
        hasDrop(card)
      }
    },
    hover({ id: draggedId }) {
      if (!draggedId) return
      if (draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    },
  })
  let style = { opacity: 1}
  if (isDragging) {
    style = { opacity: 0.3}
  }
  const getCardComponent = () => {
    if (card.type === 'bar') {
      return (<AntvBar card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />)
    }
  }
  return (
    <div className="mk-component-card" ref={node => drag(drop(node))} style={style}>
      {getCardComponent()}
      <Icon className="remove-component" title="delete" type="delete" onClick={() => delCard(id)} />
    </div>
  )
}
export default Card
src/menu/menushell/index.jsx
New file
@@ -0,0 +1,95 @@
import React, { useState } from 'react'
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Empty } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
import './index.scss'
const Container = ({config, editId, handleList, editCard, deleteCard, doubleClickCard }) => {
  let target = null
  const [cards, setCards] = useState(config.components)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    handleList({...config, components: _cards})
  }
  if (!is(fromJS(cards), fromJS(config.components))) {
    setCards(config.components)
  }
  const findCard = id => {
    const card = cards.filter(c => `${c.uuid}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
  const hasDrop = (item) => {
    target = item
  }
  const updateConfig = (element) => {
    handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)})
  }
  const [, drop] = useDrop({
    accept: 'menu',
    drop(item) {
      if (item.hasOwnProperty('originalIndex')) {
        return
      }
      let newcard = {
        uuid: Utils.getuuid(),
        type: item.component,
        subtype: item.subtype,
        isNew: true
      }
      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
      if (target) {
        targetId = target.uuid
      }
      const { index: overIndex } = findCard(`${targetId}`)
      let targetIndex = overIndex
      targetIndex++
      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
      handleList({...config, components: _cards})
      target = null
    }
  })
  return (
    <div ref={drop} className="menu-shell-inner">
      {cards.map(card => (
        <Card
          id={card.uuid}
          key={card.uuid}
          card={card}
          editId={editId}
          moveCard={moveCard}
          editCard={editCard}
          delCard={deleteCard}
          findCard={findCard}
          hasDrop={hasDrop}
          updateConfig={updateConfig}
          doubleClickCard={doubleClickCard}
        />
      ))}
      {cards.length === 0 ?
        <Empty description="请添加组件" /> : null
      }
    </div>
  )
}
export default Container
src/menu/menushell/index.scss
New file
@@ -0,0 +1,25 @@
.menu-shell-inner {
  min-height: calc(100vh - 150px);
  .mk-component-card {
    position: relative;
    .remove-component {
      position: absolute;
      right: 2px;
      top: 50%;
      background: #ff4d4f;
      border-radius: 2px;
      padding: 4px;
      color: #ffffff;
      cursor: pointer;
      display: none;
    }
  }
  .mk-component-card:hover {
    .remove-component {
      display: inline-block;
    }
  }
  >.ant-empty {
    padding-top: 150px;
  }
}
src/menu/modelsource/dragsource/index.jsx
New file
@@ -0,0 +1,13 @@
import React from 'react'
import { useDrag } from 'react-dnd'
import './index.scss'
const MobSourceElement = ({content}) => {
  const [, drag] = useDrag({ item: content })
  return (
    <div ref={drag} className="menu-source-item">
      <img style={{width: '100%'}} src={content.url} alt=""/>
    </div>
  )
}
export default MobSourceElement
src/menu/modelsource/dragsource/index.scss
New file
@@ -0,0 +1,25 @@
.menu-source-item {
  display: inline-block;
  width: 100%;
  margin-bottom: 15px;
  cursor: move;
  height: auto;
  box-shadow: 0px 0px 1px #1890ff;
  background-size: cover;
  background-position: top center;
  background-repeat: no-repeat;
  .tooltip-block {
    width: 100%;
    height: 100%;
    background: transparent;
  }
}
.menu-source-tooltip-box {
  margin-left: 20px;
  .ant-tooltip-content {
    width: 250px;
  }
}
src/menu/modelsource/index.jsx
New file
@@ -0,0 +1,22 @@
import React, {Component} from 'react'
import { is, fromJS } from 'immutable'
import { menuOptions } from './option'
import SourceWrap from './dragsource'
import './index.scss'
class CardChart extends Component {
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  render() {
    return (
      <div className="mob-card-source-box">
        {menuOptions.map((item, index) => (<SourceWrap key={index} content={item} />))}
      </div>
    )
  }
}
export default CardChart
src/menu/modelsource/index.scss
New file
@@ -0,0 +1,9 @@
.mob-card-source-box {
  padding: 20px 0px;
  position: relative;
  p {
    color: rgba(0, 0, 0, 0.85);
    margin-bottom: 10px;
  }
}
src/menu/modelsource/option.jsx
New file
@@ -0,0 +1,12 @@
// import zhCN from '@/locales/zh-CN/mob.js'
// import enUS from '@/locales/en-US/mob.js'
import bar from '@/assets/mobimg/bar.png'
import bar1 from '@/assets/mobimg/bar1.png'
// const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
// 组件配置信息
export const menuOptions = [
  { type: 'menu', url: bar, component: 'bar', subtype: 'bar' },
  { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1' },
]
src/templates/calendarconfig/index.jsx
@@ -11,12 +11,11 @@
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import Utils from '@/utils/utils.js'
import { getMainMenuForm } from '@/templates/zshare/formconfig'
import asyncComponent from '@/utils/asyncComponent'
import SearchComponent from '@/templates/sharecomponent/searchcomponent'
import MenuForm from '@/templates/zshare/menuform'
import MenuForm from '@/templates/comtableconfig/menuform'
// import EditComponent from '@/templates/zshare/editcomponent'
import SourceElement from '@/templates/zshare/dragsource'
import Source from './source'
@@ -46,7 +45,6 @@
    visible: false,          // 搜索条件、按钮、显示列,模态框显示控制
    tableFields: [],         // 已选表字段集
    fields: null,            // 搜索条件及显示列,可选字段
    menuformlist: null,      // 基本信息表单字段
    formlist: null,          // 搜索条件、按钮、显示列表单字段
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
@@ -99,13 +97,19 @@
      }
    }
    // 页面配置中保留菜单信息,只用于数据传递
    _config.ParentId = menu.ParentId
    _config.fstMenuId = menu.fstMenuId
    _config.MenuName = menu.MenuName || ''
    _config.MenuNo = menu.MenuNo || ''
    _config.OpenType = menu.PageParam ? menu.PageParam.OpenType : ''
    this.setState({
      openEdition: menu.open_edition || '',
      optionLibs: optionLibs,
      activeKey: menu.activeKey || '0',
      config: _config,
      originMenu: fromJS(menu).toJS(),
      menuformlist: getMainMenuForm(menu, _config),
      originMenu: fromJS(_config).toJS(),
      mockdata: this.getMockData(moment().format('YYYY'))
    })
  }
@@ -267,252 +271,235 @@
   */
  submitConfig = () => {
    const { menu } = this.props
    const { originMenu, openEdition } = this.state
    const { openEdition } = this.state
    let config = fromJS(this.state.config).toJS()
    let _config = fromJS(this.state.config).toJS()
    this.menuformRef.handleConfirm().then(res => {
      if (config.isAdd) {
        config.search = config.search.filter(item => !item.origin)
      }
      if (config.type === 'user') { // 使用已有菜单时,默认添加关联标签id
        if (config.tab && !config.tab.linkTab) {
          config.tab.linkTab = Utils.getuuid()
        }
      }
      let _LongParam = ''
      let _config = {...config, easyCode: res.easyCode}
      let _pageParam = {...menu.PageParam, OpenType: res.opentype}
      // 未设置数据源或标签不合法时,启用状态为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 || 'inner',
        interface: _config.setting.interface || '',
        tableName: _config.setting.tableName || '',
        innerFunc: _config.setting.innerFunc || '',
        outerFunc: _config.setting.outerFunc || ''
      })
      if (_config.tab) {
        _config.funcs.push({
          type: 'tab',
          subtype: 'tab',
          uuid: _config.tab.uuid,
          label: _config.tab.label,
          linkTab: _config.tab.linkTab
        })
      }
      if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
        this.setState({
          menucloseloading: true
        })
      } else {
        this.setState({
          menuloading: true
        })
      }
      new Promise(resolve => {
        if (_config.tab) {
          Api.getSystemConfig({
            func: 'sPC_Get_LongParam',
            MenuID: _config.tab.linkTab
          }).then(result => {
            if (result.status && result.LongParam) {
              let _LongParam = ''
              if (result.LongParam) {
                try {
                  _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                } catch (e) {
                  console.warn('Parse Failure')
                  _LongParam = ''
                }
              }
              if (_LongParam) {
                _config.funcs[1].menuNo = _LongParam.tabNo || ''
                _config.funcs[1].subfuncs = _LongParam.funcs || []
              }
            }
            resolve()
          })
        } else {
          resolve()
        }
      }).then(() => {
        // 保存时删除配置类型,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 tabParam = { // 添加菜单tab页
          func: 'sPC_sMenusTab_AddUpt',
          MenuID: menu.MenuID
        }
        if (_config.tab) {
          tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'${_config.tab.linkTab}' as Tabid,'${_config.tab.label}' as TabName ,'0' as Sort`)
        } else {
          tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`)
        }
        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
        let _vals = this.getFuncNames(_config.funcs, [], [])
        let _tables = Array.from(new Set(_vals.table))
        let param = {
          func: 'sPC_TrdMenu_AddUpt',
          FstID: res.fstMenuId,
          SndID: res.parentId,
          ParentID: res.parentId,
          MenuID: menu.MenuID,
          MenuNo: res.MenuNo,
          EasyCode: res.easyCode,
          Template: menu.PageParam.Template || '',
          MenuName: res.MenuName,
          PageParam: JSON.stringify(_pageParam),
          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 (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') + '.000'
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        if (openEdition) { // 版本管理
          param.open_edition = openEdition
        }
        // 保存本地
        let localParam = fromJS(param).toJS()
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            let _FMenu = originMenu.fstMenuList.filter(fstM => fstM.MenuID === res.fstMenuId)[0]
            let _supMenuList = []
            if (_FMenu) {
              _supMenuList = _FMenu.options
            }
            this.setState({
              config: _config,
              openEdition: response.open_edition || '',
              originMenu: {
                ...originMenu,
                LongParam: _config,
                PageParam: _pageParam,
                MenuName: res.MenuName,
                MenuNo: res.MenuNo,
                ParentID: res.parentId,
                fstMenuId: res.fstMenuId,
                supMenuList: _supMenuList
              }
            })
            this.props.reloadmenu()
            // 标签信息保存
            Api.getSystemConfig(tabParam).then(result => {
              if (result.status) {
                notification.success({
                  top: 92,
                  message: '保存成功',
                  duration: 2
                })
                if (this.state.closeVisible) {
                  this.handleViewBack()
                } else {
                  this.setState({
                    menuloading: false,
                    menucloseloading: false
                  })
                }
              } else {
                notification.warning({
                  top: 92,
                  message: result.message,
                  duration: 5
                })
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
              }
            })
            localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
            delete localParam.LongParam
            delete localParam.PageParam
            delete localParam.Template
            delete localParam.Sort
            delete localParam.EasyCode
            delete localParam.open_edition
            Api.getLocalConfig(localParam)
          } else {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          }
        })
      })
    }, () => {
    // 基本信息验证
    if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
      return
    }
    if (_config.isAdd) {
      _config.search = _config.search.filter(item => !item.origin)
    }
    if (_config.type === 'user') { // 使用已有菜单时,默认添加关联标签id
      if (_config.tab && !_config.tab.linkTab) {
        _config.tab.linkTab = Utils.getuuid()
      }
    }
    // 未设置数据源或标签不合法时,启用状态为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 || 'inner',
      interface: _config.setting.interface || '',
      tableName: _config.setting.tableName || '',
      innerFunc: _config.setting.innerFunc || '',
      outerFunc: _config.setting.outerFunc || ''
    })
    if (_config.tab) {
      _config.funcs.push({
        type: 'tab',
        subtype: 'tab',
        uuid: _config.tab.uuid,
        label: _config.tab.label,
        linkTab: _config.tab.linkTab
      })
    }
    if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
      this.setState({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
    new Promise(resolve => {
      if (_config.tab) {
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          MenuID: _config.tab.linkTab
        }).then(result => {
          if (result.status && result.LongParam) {
            let _LongParam = ''
            if (result.LongParam) {
              try {
                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
              } catch (e) {
                console.warn('Parse Failure')
                _LongParam = ''
              }
            }
            if (_LongParam) {
              _config.funcs[1].menuNo = _LongParam.tabNo || ''
              _config.funcs[1].subfuncs = _LongParam.funcs || []
            }
          }
          resolve()
        })
      } else {
        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 tabParam = { // 添加菜单tab页
        func: 'sPC_sMenusTab_AddUpt',
        MenuID: menu.MenuID
      }
      if (_config.tab) {
        tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'${_config.tab.linkTab}' as Tabid,'${_config.tab.label}' as TabName ,'0' as Sort`)
      } else {
        tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`)
      }
      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
      let _vals = this.getFuncNames(_config.funcs, [], [])
      let _tables = Array.from(new Set(_vals.table))
      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 (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') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      if (openEdition) { // 版本管理
        param.open_edition = openEdition
      }
      // 保存本地
      let localParam = fromJS(param).toJS()
      Api.getSystemConfig(param).then(response => {
        if (response.status) {
          this.setState({
            config: _config,
            openEdition: response.open_edition || '',
            originMenu: fromJS(_config).toJS()
          })
          this.props.reloadmenu()
          // 标签信息保存
          Api.getSystemConfig(tabParam).then(result => {
            if (result.status) {
              notification.success({
                top: 92,
                message: '保存成功',
                duration: 2
              })
              if (this.state.closeVisible) {
                this.handleViewBack()
              } else {
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
              }
            } else {
              notification.warning({
                top: 92,
                message: result.message,
                duration: 5
              })
              this.setState({
                menuloading: false,
                menucloseloading: false
              })
            }
          })
          localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
          delete localParam.LongParam
          delete localParam.PageParam
          delete localParam.Template
          delete localParam.Sort
          delete localParam.EasyCode
          delete localParam.open_edition
          Api.getLocalConfig(localParam)
        } else {
          this.setState({
            menuloading: false,
            menucloseloading: false
          })
          notification.warning({
            top: 92,
            message: response.message,
            duration: 5
          })
        }
      })
    })
  }
  cancelConfig = () => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    let _this = this
    if (config.isAdd) {
@@ -526,31 +513,13 @@
        onCancel() {}
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, easyCode: res.easyCode}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.MenuName,
          MenuNo: res.MenuNo,
          ParentID: res.parentId,
          fstMenuId: res.fstMenuId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
          this.setState({
            closeVisible: true
          })
        } else {
          this.props.handleView()
        }
      }, () => {
      if (!is(fromJS(originMenu), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      })
      } else {
        this.props.handleView()
      }
    }
  }
@@ -568,99 +537,101 @@
        duration: 5
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, easyCode: res.easyCode}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.MenuName,
          MenuNo: res.MenuNo,
          ParentID: res.parentId,
          fstMenuId: res.fstMenuId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) { // 菜单信息变化时,提示保存
          notification.warning({
            top: 92,
            message: this.state.dict['header.menu.config.update'],
            duration: 5
          })
          return
        }
        // 菜单信息验证通过后,跳转子配置页面
        _originMenu.activeKey = activeKey       // 保存当前打开页签
        _originMenu.open_edition = openEdition  // 更新版本号
        let param = {
          optionLibs: optionLibs,
          editMenu: _originMenu,
          editTab: fromJS(config.tab).toJS(),
          tabConfig: null,
          editSubTab: null,
          subTabConfig: null,
          btnTab: null,
          btnTabConfig: null,
          editAction: '',
          subConfig: '',
          tabview: config.tab.type
        }
        // 当子表使用主页搜索条件时,将主页搜索向下传递
        if (param.editTab && param.editTab.searchPass === 'true') {
          param.editTab.mainsearch = fromJS(_config.search).toJS()
        }
        this.setState({
          loading: true
      // 基本信息验证
      if (!config.fstMenuId || !config.ParentId || !config.MenuName || !config.MenuNo) {
        notification.warning({
          top: 92,
          message: this.state.dict['model.menu.basemsg'],
          duration: 5
        })
        return
      }
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          MenuID: config.tab.linkTab
        }).then(res => {
          if (res.status) {
            this.setState({
              loading: false
            })
            let _LongParam = ''
            if (res.LongParam) {
              try {
                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
              } catch (e) {
                console.warn('Parse Failure')
                _LongParam = ''
              }
            }
            if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
              param.subConfig = _LongParam
            }
            if (param.editTab) {
              param.editTab.open_edition = res.open_edition || ''
            }
            this.props.handleView(param)
          } else {
            this.setState({
              loading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
        })
      }, () => {
      if (!is(fromJS(originMenu), fromJS(config))) { // 菜单信息变化时,提示保存
        notification.warning({
          top: 92,
          message: this.state.dict['header.menu.config.update'],
          duration: 5
        })
        return
      }
      let submenu = menu.fstMenuList.filter(item => item.MenuID === config.fstMenuId)[0]
      let _Menu = {
        ...menu,
        LongParam: config,
        PageParam: {...menu.PageParam, Template: config.Template, OpenType: config.OpenType},
        MenuName: config.MenuName,
        MenuNo: config.MenuNo,
        ParentId: config.ParentId,
        fstMenuId: config.fstMenuId,
        supMenuList: submenu ? submenu.options : []
      }
      // 菜单信息验证通过后,跳转子配置页面
      _Menu.activeKey = activeKey       // 保存当前打开页签
      _Menu.open_edition = openEdition  // 更新版本号
      let param = {
        optionLibs: optionLibs,
        editMenu: _Menu,
        editTab: fromJS(config.tab).toJS(),
        tabConfig: null,
        editSubTab: null,
        subTabConfig: null,
        btnTab: null,
        btnTabConfig: null,
        editAction: '',
        subConfig: '',
        tabview: config.tab.type
      }
      // 当子表使用主页搜索条件时,将主页搜索向下传递
      if (param.editTab && param.editTab.searchPass === 'true') {
        param.editTab.mainsearch = fromJS(config.search).toJS()
      }
      this.setState({
        loading: true
      })
      Api.getSystemConfig({
        func: 'sPC_Get_LongParam',
        MenuID: config.tab.linkTab
      }).then(res => {
        if (res.status) {
          this.setState({
            loading: false
          })
          let _LongParam = ''
          if (res.LongParam) {
            try {
              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
            } catch (e) {
              console.warn('Parse Failure')
              _LongParam = ''
            }
          }
          if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
            param.subConfig = _LongParam
          }
          if (param.editTab) {
            param.editTab.open_edition = res.open_edition || ''
          }
          this.props.handleView(param)
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    }
  }
@@ -692,15 +663,11 @@
   * @description 校验配置信息的合法性
   */
  verifyconfig = (config) => {
    // let hasKey = false
    let cols = []
    config.columns.forEach(col => {
      if (col.field) {
        cols.push(col.field)
      }
      // if (config.setting.primaryKey === col.field) {
      //   hasKey = true
      // }
    })
    let calvaild = true
@@ -716,10 +683,6 @@
    if (config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.default !== 'false' && !config.setting.dataresource) {
      return '菜单尚未设置数据源,不可启用!'
    // } else if (!config.setting.primaryKey) {
    //   return '菜单尚未设置主键,不可启用!'
    // } else if (!hasKey) {
    //   return '显示列中不存在主键字段,不可启用!'
    } else if (!calvaild) {
      return '日历关联字段未设置,不可启用!'
    } else {
@@ -787,6 +750,7 @@
  }
  render () {
    const { menu } = this.props
    const { activeKey, config, tabviews, mockdata } = this.state
    return (
@@ -799,9 +763,10 @@
              <Panel forceRender={true} header={'标签基本信息'} key="0" id="subtable-basedata">
                {/* 菜单信息 */}
                <MenuForm
                  menu={menu}
                  config={config}
                  dict={this.state.dict}
                  formlist={this.state.menuformlist}
                  wrappedComponentRef={(inst) => this.menuformRef = inst}
                  updatemenu={this.updateconfig}
                />
                {/* 表名添加 */}
                <TableComponent
@@ -842,14 +807,13 @@
            } style={{ width: '100%' }}>
              <SettingComponent
                config={config}
                MenuID={config.uuid}
                menuformRef={this.menuformRef}
                MenuID={menu.MenuID}
                tableFields={this.state.tableFields}
                permFuncField={this.props.permFuncField}
                updateConfig={this.updateconfig}
              />
              <SearchComponent
                menu={{MenuID: config.uuid, MenuName: config.tabName}}
                menu={{MenuID: menu.MenuID, MenuName: config.MenuName}}
                config={config}
                pasteContent={this.state.pasteContent}
                sysRoles={this.props.sysRoles}
src/templates/comtableconfig/index.jsx
@@ -11,14 +11,13 @@
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getMainMenuForm } from '@/templates/zshare/formconfig'
import asyncComponent from '@/utils/asyncComponent'
import SearchComponent from '@/templates/sharecomponent/searchcomponent'
import ActionComponent from '@/templates/sharecomponent/actioncomponent'
import ColumnComponent from '@/templates/sharecomponent/columncomponent'
import MenuForm from '@/templates/zshare/menuform'
import MenuForm from './menuform'
import SourceElement from '@/templates/zshare/dragsource'
import Source from './source'
import './index.scss'
@@ -46,8 +45,6 @@
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    config: null,            // 页面配置
    tableFields: [],         // 表格显示列
    fields: null,            // 搜索条件及显示列,可选字段
    menuformlist: null,      // 基本信息表单字段
    formlist: null,          // 搜索条件、按钮、显示列表单字段
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
@@ -101,6 +98,13 @@
        }
      })
    }
    // 页面配置中保留菜单信息,只用于数据传递
    _config.ParentId = menu.ParentId
    _config.fstMenuId = menu.fstMenuId
    _config.MenuName = menu.MenuName || ''
    _config.MenuNo = menu.MenuNo || ''
    _config.OpenType = menu.PageParam ? menu.PageParam.OpenType : ''
    if (!_config.version || _config.version < '1.0') {
      // 配置默认值,兼容
@@ -221,8 +225,7 @@
      activeKey: menu.activeKey || '0',
      optionLibs: optionLibs,
      originActions: _oriActions,
      originMenu: fromJS(menu).toJS(),
      menuformlist: getMainMenuForm(menu, _config)
      originMenu: fromJS(_config).toJS()
    })
  }
@@ -314,435 +317,422 @@
   */
  submitConfig = () => {
    const { menu } = this.props
    const { originMenu, delActions, thawButtons, openEdition } = this.state
    const { delActions, thawButtons, openEdition } = this.state
    let config = fromJS(this.state.config).toJS()
    let _config = fromJS(this.state.config).toJS()
    this.menuformRef.handleConfirm().then(res => {
      if (config.isAdd) {
        config.search = config.search.filter(item => !item.origin)
        config.action = config.action.filter(item => !item.origin)
        config.columns = config.columns.filter(item => !item.origin)
        config.tabgroups[0].sublist = config.tabgroups[0].sublist.filter(item => !item.origin)
      }
    // 基本信息验证
    if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
      return
    }
      if (config.type === 'user') { // 使用已有菜单时,默认添加关联标签id
        config.action = config.action.map(item => {
          if (item.OpenType === 'popview' && !item.linkTab) {
            item.linkTab = Utils.getuuid()
    // 新建菜单,清除默认项
    if (_config.isAdd) {
      _config.search = _config.search.filter(item => !item.origin)
      _config.action = _config.action.filter(item => !item.origin)
      _config.columns = _config.columns.filter(item => !item.origin)
      _config.tabgroups[0].sublist = _config.tabgroups[0].sublist.filter(item => !item.origin)
    }
    // 使用已有菜单时,默认添加关联标签id
    if (_config.type === 'user') {
      _config.action = _config.action.map(item => {
        if (item.OpenType === 'popview' && !item.linkTab) {
          item.linkTab = Utils.getuuid()
        }
        return item
      })
      _config.tabgroups.forEach(group => {
        group.sublist = group.sublist.map(tab => {
          if (!tab.linkTab) {
            tab.linkTab = Utils.getuuid()
          }
          return item
          return tab
        })
        config.tabgroups.forEach(group => {
          group.sublist = group.sublist.map(tab => {
            if (!tab.linkTab) {
              tab.linkTab = Utils.getuuid()
            }
            return tab
          })
      })
    }
    // 未设置数据源或标签不合法时,启用状态为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 || 'inner',
      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 === 'inner' && !item.innerFunc) {
        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({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
    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 = ''
                if (result.LongParam) {
                  try {
                    _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                  } catch (e) {
                    console.warn('Parse Failure')
                    _LongParam = ''
                  }
                }
                if (_LongParam) {
                  item.menuNo = _LongParam.tabNo || ''
                  item.subfuncs = _LongParam.funcs || []
                }
              }
              resolve()
            })
          })
          deffers.push(deffer)
        }
      })
      if (deffers.length === 0) {
        resolve()
      } else {
        Promise.all(deffers).then(() => {
          resolve()
        })
      }
    }).then(() => {
      // 保存时删除配置类型,system 、user
      delete _config.type
      delete _config.isAdd
      let _LongParam = ''
      let _config = {...config, easyCode: res.easyCode}
      let _pageParam = {...menu.PageParam, OpenType: res.opentype}
      // 未设置数据源或标签不合法时,启用状态为false
      let vresult = this.verifyconfig(_config)
      if (vresult !== true) {
        _config.enabled = false
      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
      }
      _config.funcs = [] // 页面及子页面存储过程集
      let _sort = 0
      let btntabs = []
      _config.funcs.push({
        type: 'view',
        subtype: 'view',
        uuid: menu.MenuID,
        intertype: _config.setting.interType || 'inner',
        interface: _config.setting.interface || '',
        tableName: _config.setting.tableName || '',
        innerFunc: _config.setting.innerFunc || '',
        outerFunc: _config.setting.outerFunc || ''
      })
      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 => {
        let tablename = item.OpenType === 'excelIn' ? (item.sheet || '') : (item.sql || '')
        if (item.OpenType === 'excelOut' && item.intertype === 'inner' && !item.innerFunc) {
          tablename = _config.setting.tableName || ''
        }
        if (item.OpenType === 'tab' || item.OpenType === 'blank') {
          _config.funcs.push({
            type: 'tab',
            subtype: 'btn',
        _sort++
        if (item.OpenType === 'popview') {
          btntabs.push({
            uuid: item.uuid,
            linkTab: item.linkTab,
            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 || ''
            sort: _sort
          })
        }
        btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${_sort * 10}' as Sort`)
      })
      _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({
          menucloseloading: true
        })
      } else {
        this.setState({
          menuloading: true
        })
      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.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
      let tabParam = { // 添加菜单tab页
        func: 'sPC_sMenusTab_AddUpt',
        MenuID: menu.MenuID
      }
      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 = ''
                  if (result.LongParam) {
                    try {
                      _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                    } catch (e) {
                      console.warn('Parse Failure')
                      _LongParam = ''
                    }
                  }
                  if (_LongParam) {
                    item.menuNo = _LongParam.tabNo || ''
                    item.subfuncs = _LongParam.funcs || []
                  }
                }
                resolve()
              })
            })
      let _LText = []
            deffers.push(deffer)
          }
        })
        if (deffers.length === 0) {
          resolve()
        } else {
          Promise.all(deffers).then(() => {
            resolve()
          })
        }
      }).then(() => {
        // 保存时删除配置类型,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: res.MenuNo,
          Template: menu.PageParam.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
          _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
        })
      })
      _LText = _LText.join(' union all ')
      // 清空菜单下关联的标签
      if (!_LText) {
        _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
      }
      tabParam.LText = Utils.formatOptions(_LText)
      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
      let _vals = this.getFuncNames(_config.funcs, [], [])
      let _tables = Array.from(new Set(_vals.table))
      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 (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') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      if (openEdition) { // 版本管理
        param.open_edition = openEdition
      }
      // 有按钮或标签删除时,先进行删除操作
      // 删除成功后,保存页面配置
      new Promise(resolve => {
        if (delActions.length > 0) {
          let deffers = delActions.map(item => {
            let _param = {
              func: 'sPC_MainMenu_Del',
              MenuID: item.card ? item.card.uuid : item.uuid
            }
            if (item.type === 'action') {
              let _ParentParam = null
              try {
                _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
              } catch (e) {
                console.warn('Stringify Failure')
                _ParentParam = null
              }
              if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
                _param.ParentParam = _ParentParam
              }
            }
            return new Promise(resolve => {
              Api.getSystemConfig(_param).then(response => {
                resolve(response)
              })
            })
          }
          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') + '.000'
        btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
        let tabParam = { // 添加菜单tab页
          func: 'sPC_sMenusTab_AddUpt',
          MenuID: menu.MenuID
        }
        let _LText = []
        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`)
          })
        })
        _LText = _LText.join(' union all ')
        // 清空菜单下关联的标签
        if (!_LText) {
          _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
        }
        tabParam.LText = Utils.formatOptions(_LText)
        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
          Promise.all(deffers).then(result => {
            let error = null
            result.forEach(response => {
              if (!response.status) {
                error = response
              }
            })
  
        let _vals = this.getFuncNames(_config.funcs, [], [])
        let _tables = Array.from(new Set(_vals.table))
        let param = {
          func: 'sPC_TrdMenu_AddUpt',
          FstID: res.fstMenuId,
          SndID: res.parentId,
          ParentID: res.parentId,
          MenuID: menu.MenuID,
          MenuNo: res.MenuNo,
          EasyCode: res.easyCode,
          Template: menu.PageParam.Template || '',
          MenuName: res.MenuName,
          PageParam: JSON.stringify(_pageParam),
          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 (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') + '.000'
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        if (openEdition) { // 版本管理
          param.open_edition = openEdition
        }
        // 有按钮或标签删除时,先进行删除操作
        // 删除成功后,保存页面配置
        new Promise(resolve => {
          if (delActions.length > 0) {
            let deffers = delActions.map(item => {
              let _param = {
                func: 'sPC_MainMenu_Del',
                MenuID: item.card ? item.card.uuid : item.uuid
              }
              if (item.type === 'action') {
                let _ParentParam = null
                try {
                  _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
                } catch (e) {
                  console.warn('Stringify Failure')
                  _ParentParam = null
                }
                if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
                  _param.ParentParam = _ParentParam
                }
              }
              return new Promise(resolve => {
                Api.getSystemConfig(_param).then(response => {
                  resolve(response)
                })
              })
            })
            Promise.all(deffers).then(result => {
              let error = null
              result.forEach(response => {
                if (!response.status) {
                  error = response
                }
              })
              if (error) {
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
                notification.warning({
                  top: 92,
                  message: error.message,
                  duration: 5
                })
                resolve(false)
              } else {
                this.setState({
                  delActions: []
                })
                resolve(true)
              }
            })
          } else if (delActions.length === 0) {
            resolve(true)
          }
        }).then(resp => {
          if (resp === false) return
          if (thawButtons.length > 0) {
            let defers = thawButtons.map(item => {
              return new Promise((resolve) => {
                Api.getSystemConfig({
                  func: 'sPC_MainMenu_ReDel',
                  MenuID: item
                }).then(res => {
                  if (res.status) {
                    resolve('')
                  } else {
                    resolve(res.message)
                  }
                })
              })
            })
            return Promise.all(defers)
          } else {
            return true
          }
        }).then(res => {
          if (res === true || res === false) return res
          let msg = res.filter(Boolean)[0]
          if (msg) {
            notification.warning({
              top: 92,
              message: msg,
              duration: 5
            })
            return false
          } else {
            this.setState({
              thawButtons: []
            })
            return true
          }
        }).then(resp => {
          if (resp === false) return
          let localParam = fromJS(param).toJS()
          Api.getSystemConfig(param).then(response => {
            if (response.status) {
              let _FMenu = originMenu.fstMenuList.filter(fstM => fstM.MenuID === res.fstMenuId)[0]
              let _supMenuList = []
              if (_FMenu) {
                _supMenuList = _FMenu.options
              }
              this.setState({
                config: _config,
                openEdition: response.open_edition || '',
                originMenu: {
                  ...originMenu,
                  LongParam: _config,
                  PageParam: _pageParam,
                  MenuName: res.MenuName,
                  MenuNo: res.MenuNo,
                  ParentID: res.parentId,
                  fstMenuId: res.fstMenuId,
                  supMenuList: _supMenuList
                }
              })
              this.props.reloadmenu()
              this.submitAction(btnParam, tabParam)
              localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
              delete localParam.LongParam
              delete localParam.PageParam
              delete localParam.Template
              delete localParam.Sort
              delete localParam.EasyCode
              delete localParam.open_edition
              Api.getLocalConfig(localParam)
            } else {
            if (error) {
              this.setState({
                menuloading: false,
                menucloseloading: false
              })
              notification.warning({
                top: 92,
                message: response.message,
                message: error.message,
                duration: 5
              })
              resolve(false)
            } else {
              this.setState({
                delActions: []
              })
              resolve(true)
            }
          })
        } else if (delActions.length === 0) {
          resolve(true)
        }
      }).then(resp => {
        if (resp === false) return
        if (thawButtons.length > 0) {
          let defers = thawButtons.map(item => {
            return new Promise((resolve) => {
              Api.getSystemConfig({
                func: 'sPC_MainMenu_ReDel',
                MenuID: item
              }).then(res => {
                if (res.status) {
                  resolve('')
                } else {
                  resolve(res.message)
                }
              })
            })
          })
          return Promise.all(defers)
        } else {
          return true
        }
      }).then(res => {
        if (res === true || res === false) return res
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.warning({
            top: 92,
            message: msg,
            duration: 5
          })
          return false
        } else {
          this.setState({
            thawButtons: []
          })
          return true
        }
      }).then(resp => {
        if (resp === false) return
        let localParam = fromJS(param).toJS()
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            this.setState({
              config: _config,
              openEdition: response.open_edition || '',
              originMenu: fromJS(_config).toJS()
            })
            this.props.reloadmenu()
            this.submitAction(btnParam, tabParam)
            localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
            delete localParam.LongParam
            delete localParam.PageParam
            delete localParam.Template
            delete localParam.Sort
            delete localParam.EasyCode
            delete localParam.open_edition
            Api.getLocalConfig(localParam)
          } else {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          }
        })
      })
    }, () => {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
    })
  }
@@ -889,7 +879,7 @@
                func: 'sPC_ButtonParam_AddUpt',
                ParentID: this.props.menu.MenuID,
                MenuID: action.curBtn.uuid,
                MenuNo: this.props.menu.MenuNo,
                MenuNo: config.MenuNo,
                Template: _temp,
                MenuName: action.curBtn.label,
                PageParam: JSON.stringify({Template: _temp}),
@@ -930,7 +920,6 @@
   * @description 点击返回时,判断配置保存状态
   */
  cancelConfig = () => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    let _this = this
@@ -946,31 +935,13 @@
        onCancel() {}
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, easyCode: res.easyCode}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.MenuName,
          MenuNo: res.MenuNo,
          ParentID: res.parentId,
          fstMenuId: res.fstMenuId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
          this.setState({
            closeVisible: true
          })
        } else {
          this.props.handleView()
        }
      }, () => {
      if (!is(fromJS(originMenu), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      })
      } else {
        this.props.handleView()
      }
    }
  }
@@ -988,127 +959,129 @@
        duration: 5
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, easyCode: res.easyCode}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.MenuName,
          MenuNo: res.MenuNo,
          ParentID: res.parentId,
          fstMenuId: res.fstMenuId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) { // 菜单信息变化时,提示保存
          notification.warning({
            top: 92,
            message: this.state.dict['header.menu.config.update'],
            duration: 5
          })
          return
        }
        // 菜单信息验证通过后,跳转子配置页面
        let _view = ''
        let uuid = item.uuid
        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    // 新标签页模板
          _btnTab = item
        } else if (type === 'button' && item.OpenType === 'popview') {
          _view = item.tabType        // 新弹窗标签模板
          uuid = item.linkTab
          isbutton = false
        } else if (type === 'tab') {
          _view = item.type           // 标签模板
          uuid = item.linkTab
          isbutton = false
        }
        _originMenu.activeKey = activeKey       // 保存当前打开页签
        _originMenu.open_edition = openEdition  // 更新版本号
        let param = {
          optionLibs: optionLibs,
          editMenu: _originMenu,
          editTab: !isbutton ? item : '',
          tabConfig: null,
          editSubTab: null,
          subTabConfig: null,
          btnTab: _btnTab,
          btnTabConfig: null,
          editAction: isbutton ? item : '',
          subConfig: '',
          tabview: _view
        }
        // 当子表使用主页搜索条件时,将主页搜索向下传递
        if (param.editTab && param.editTab.searchPass === 'true') {
          param.editTab.mainsearch = fromJS(_config.search).toJS()
        }
        this.setState({
          loading: true
      // 基本信息验证
      if (!config.fstMenuId || !config.ParentId || !config.MenuName || !config.MenuNo) {
        notification.warning({
          top: 92,
          message: this.state.dict['model.menu.basemsg'],
          duration: 5
        })
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          MenuID: uuid
        }).then(res => {
          if (res.status) {
            this.setState({
              loading: false
            })
            let _LongParam = ''
            if (res.LongParam) {
              try {
                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
              } catch (e) {
                console.warn('Parse Failure')
                _LongParam = ''
              }
            }
            if (_LongParam && param.tabview === 'Modal' && _LongParam.type === 'Modal') {
              param.subConfig = _LongParam
            } else if (_LongParam && param.tabview === 'FormTab' && _LongParam.type === 'FormTab') {
              param.subConfig = _LongParam
            } 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) {
              param.editAction.open_edition = res.open_edition || ''
            } else if (param.btnTab) {
              param.btnTab.open_edition = res.open_edition || ''
            }
            this.props.handleView(param)
          } else {
            this.setState({
              loading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
        })
      }, () => {
        return
      }
      if (!is(fromJS(originMenu), fromJS(config))) { // 菜单信息变化时,提示保存
        notification.warning({
          top: 92,
          message: this.state.dict['header.menu.config.update'],
          duration: 5
        })
        return
      }
      let submenu = menu.fstMenuList.filter(item => item.MenuID === config.fstMenuId)[0]
      let _Menu = {
        ...menu,
        LongParam: config,
        PageParam: {...menu.PageParam, Template: config.Template, OpenType: config.OpenType},
        MenuName: config.MenuName,
        MenuNo: config.MenuNo,
        ParentId: config.ParentId,
        fstMenuId: config.fstMenuId,
        supMenuList: submenu ? submenu.options : []
      }
      // 菜单信息验证通过后,跳转子配置页面
      let _view = ''
      let uuid = item.uuid
      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    // 新标签页模板
        _btnTab = item
      } else if (type === 'button' && item.OpenType === 'popview') {
        _view = item.tabType        // 新弹窗标签模板
        uuid = item.linkTab
        isbutton = false
      } else if (type === 'tab') {
        _view = item.type           // 标签模板
        uuid = item.linkTab
        isbutton = false
      }
      _Menu.activeKey = activeKey       // 保存当前打开页签
      _Menu.open_edition = openEdition  // 更新版本号
      let param = {
        optionLibs: optionLibs,
        editMenu: _Menu,
        editTab: !isbutton ? item : '',
        tabConfig: null,
        editSubTab: null,
        subTabConfig: null,
        btnTab: _btnTab,
        btnTabConfig: null,
        editAction: isbutton ? item : '',
        subConfig: '',
        tabview: _view
      }
      // 当子表使用主页搜索条件时,将主页搜索向下传递
      if (param.editTab && param.editTab.searchPass === 'true') {
        param.editTab.mainsearch = fromJS(config.search).toJS()
      }
      this.setState({
        loading: true
      })
      Api.getSystemConfig({
        func: 'sPC_Get_LongParam',
        MenuID: uuid
      }).then(res => {
        if (res.status) {
          this.setState({
            loading: false
          })
          let _LongParam = ''
          if (res.LongParam) {
            try {
              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
            } catch (e) {
              console.warn('Parse Failure')
              _LongParam = ''
            }
          }
          if (_LongParam && param.tabview === 'Modal' && _LongParam.type === 'Modal') {
            param.subConfig = _LongParam
          } else if (_LongParam && param.tabview === 'FormTab' && _LongParam.type === 'FormTab') {
            param.subConfig = _LongParam
          } 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) {
            param.editAction.open_edition = res.open_edition || ''
          } else if (param.btnTab) {
            param.btnTab.open_edition = res.open_edition || ''
          }
          this.props.handleView(param)
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    }
  }
@@ -1301,6 +1274,7 @@
  }
  render () {
    const { menu } = this.props
    const { activeKey, config, chartview } = this.state
    const confActions = config.action.filter(_action => !_action.origin && ['pop', 'popview', 'blank', 'tab'].includes(_action.OpenType))
@@ -1320,9 +1294,10 @@
              <Panel forceRender={true} header={this.state.dict['header.menu.basedata']} key="0" id="main-basedata">
                {/* 菜单信息 */}
                <MenuForm
                  menu={menu}
                  config={config}
                  dict={this.state.dict}
                  formlist={this.state.menuformlist}
                  wrappedComponentRef={(inst) => this.menuformRef = inst}
                  updatemenu={this.updateconfig}
                />
                {/* 表名添加 */}
                <TableComponent
@@ -1429,12 +1404,11 @@
                type="main"
                config={config}
                MenuID={this.props.menu.MenuID}
                menuformRef={this.menuformRef}
                permFuncField={this.props.permFuncField}
                updatesetting={this.updateconfig}
              />
              <SearchComponent
                menu={{MenuID: this.props.menu.MenuID, MenuName: this.props.menu.MenuName}}
                menu={{MenuID: this.props.menu.MenuID, MenuName: config.MenuName}}
                config={config}
                pasteContent={this.state.pasteContent}
                sysRoles={this.props.sysRoles}
@@ -1457,10 +1431,9 @@
                        {config.charts.length > 1 && item.title ? <p className="chart-title">{item.title}</p> : null}
                        <ActionComponent
                          type="main"
                          menu={{ MenuID: this.props.menu.MenuID, MenuName: this.props.menu.MenuName, MenuNo: this.props.menu.MenuNo, fstMenuList: this.props.menu.fstMenuList }}
                          menu={{ MenuID: this.props.menu.MenuID, MenuName: config.MenuName, MenuNo: config.MenuNo, fstMenuList: this.props.menu.fstMenuList }}
                          config={config}
                          tabs={this.state.tabviews}
                          menuformRef={this.menuformRef}
                          pasteContent={this.state.pasteContent}
                          usefulFields={this.props.permFuncField}
                          setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')}
src/templates/comtableconfig/menuform/index.jsx
New file
@@ -0,0 +1,214 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Input, Select } from 'antd'
import { formRule } from '@/utils/option.js'
import './index.scss'
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    menu: PropTypes.object,
    config: PropTypes.object,
    updatemenu: PropTypes.func
  }
  state = {
    menulist: [],
    submenulist: []
  }
  UNSAFE_componentWillMount () {
    const { menu } = this.props
    this.setState({
      menulist: menu.fstMenuList,
      submenulist: menu.supMenuList
    })
  }
  selectChange = (key, value) => {
    const { config } = this.props
    const { menulist } = this.state
    if (key === 'fstMenuId') {
      let _menu = menulist.filter(cell => cell.MenuID === value)[0]
      let options = _menu ? _menu.options : []
      let ParentId = options[0] ? options[0].MenuID : ''
      this.setState({
        submenulist: options
      }, () => {
        this.props.form.setFieldsValue({ParentId: ParentId})
      })
      this.props.updatemenu({...config, fstMenuId: value, ParentId: ParentId})
    } else if (key === 'ParentId') {
      this.setState({}, () => {
        this.props.updatemenu({...config, ParentId: value})
      })
    } else if (key === 'opentype') {
      this.setState({}, () => {
        this.props.updatemenu({...config, OpenType: value})
      })
    }
  }
  changeName = (e) => {
    let value = e.target.value || ''
    if (value.length > 100) return
    this.setState({}, () => {
      this.props.updatemenu({...this.props.config, MenuName: value})
    })
  }
  changeNo = (e) => {
    let value = e.target.value || ''
    if (value.length > 100) return
    this.setState({}, () => {
      this.props.updatemenu({...this.props.config, MenuNo: value})
    })
  }
  changeEasyCode = (e) => {
    let value = e.target.value || ''
    if (value.length > 100) return
    this.setState({}, () => {
      this.props.updatemenu({...this.props.config, easyCode: value})
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return is(fromJS(this.props), fromJS(nextProps))
  }
  render() {
    const { dict, menu, config } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 24 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 24 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form" id="subqazxcvbn">
        <Row gutter={24}>
          <Col span={24}>
            <Form.Item label={dict['model.menu.level1']}>
              {getFieldDecorator('fstMenuId', {
                initialValue: menu.fstMenuId,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.select'] + dict['model.menu.level1'] + '!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.selectChange('fstMenuId', value)}}>
                  {this.state.menulist.map(option =>
                    <Select.Option key={option.MenuID} value={option.MenuID}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['model.menu.level2']}>
              {getFieldDecorator('ParentId', {
                initialValue: menu.ParentId,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.select'] + dict['model.menu.level2'] + '!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.selectChange('ParentId', value)}}>
                  {this.state.submenulist.map(option =>
                    <Select.Option key={option.MenuID} value={option.MenuID}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['model.menu'] + dict['model.name']}>
              {getFieldDecorator('MenuName', {
                initialValue: menu.MenuName,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.input'] + dict['model.menu'] + dict['model.name'] + '!'
                  },
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeName}/>)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['model.menu'] + dict['model.param']}>
              {getFieldDecorator('MenuNo', {
                initialValue: menu.MenuNo,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.input'] + dict['model.menu'] + dict['model.param'] + '!'
                  },
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeNo}/>)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['model.openway']}>
              {getFieldDecorator('opentype', {
                initialValue: menu.PageParam ? menu.PageParam.OpenType : 'newtab',
                rules: [
                  {
                    required: true,
                    message: dict['form.required.select'] + dict['model.openway'] + '!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.selectChange('opentype', value)}}>
                  <Select.Option value="newtab">{dict['model.form.tab']}</Select.Option>
                  <Select.Option value="newpage">{dict['model.form.newpage']}</Select.Option>
                  {/* <Select.Option value="currenttab">{dict['model.form.currenttab']}</Select.Option> */}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['header.form.easyCode']}>
              {getFieldDecorator('easyCode', {
                initialValue: config.easyCode,
                rules: [
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeEasyCode}/>)}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/templates/comtableconfig/menuform/index.scss
src/templates/menuconfig/editthdmenu/index.jsx
@@ -149,7 +149,6 @@
          return
        }
        _menu.ParentID = this.props.supMenu.MenuID
        _menu.supMenuList = this.props.supMenuList
        _menu.fstMenuId = this.state.fstMenuId || ''
        _menu.fstMenuList = this.state.fstMenuList || []
@@ -185,7 +184,6 @@
          }
          _menu.LongParam = _LongParam
          _menu.ParentID = this.props.supMenu.MenuID
          _menu.supMenuList = this.props.supMenuList
          _menu.fstMenuId = this.state.fstMenuId || ''
          _menu.fstMenuList = this.state.fstMenuList || []
@@ -273,7 +271,7 @@
          PageParam: '',
          LongParam: '',
          isSubtable: '', // 是否为主子表
          ParentID: this.props.supMenu.MenuID,
          ParentId: this.props.supMenu.MenuID,
          supMenuList: this.props.supMenuList,
          fstMenuId: this.state.fstMenuId,
          fstMenuList: this.state.fstMenuList,
@@ -456,7 +454,7 @@
        MenuID: Utils.getuuid(),
        MenuName: template.title,
        Template: template.type,
        ParentID: this.props.supMenu.MenuID,
        ParentId: this.props.supMenu.MenuID,
      }
      this.setState({
src/templates/menuconfig/editthdmenu/menuform/index.jsx
@@ -91,7 +91,7 @@
          <Col span={24}>
            <Form.Item label={'二级菜单'}>
              {getFieldDecorator('ParentID', {
                initialValue: menu.ParentID,
                initialValue: menu.ParentId,
                rules: [
                  {
                    required: true,
src/templates/sharecomponent/actioncomponent/index.jsx
@@ -29,7 +29,6 @@
    type: PropTypes.string,          // 菜单类型,主表或子表
    menu: PropTypes.object,          // 菜单信息(菜单id,菜单参数,菜单名称)
    config: PropTypes.object,        // 菜单配置信息
    menuformRef: PropTypes.any,      // 菜单基本信息表单对象
    pasteContent: PropTypes.object,  // 粘贴配置信息
    usefulFields: PropTypes.array,   // 自定义函数可用字段
    tabs: PropTypes.array,           // 所有标签
@@ -199,14 +198,9 @@
   * 4、下拉菜单数据源语法验证
   */
  handleSubmit = () => {
    const { config, menuformRef } = this.props
    const { config, menu } = this.props
    const { card } = this.state
    let _actionlist = fromJS(this.state.actionlist).toJS()
    let menu = fromJS(this.props.menu).toJS() // 菜单信息,存在表单对象时,从菜单中更新
    if (menuformRef) {
      menu = {...menu, MenuName: menuformRef.props.form.getFieldValue('MenuName'), MenuNo: menuformRef.props.form.getFieldValue('MenuNo')}
    }
    this.actionFormRef.handleConfirm().then(btn => {
      _actionlist = _actionlist.filter(item => !item.origin || item.uuid === btn.uuid)
@@ -694,13 +688,8 @@
   * @description 创建按钮存储过程
   */
  creatFunc = () => {
    const { config, menuformRef } = this.props
    const { config, menu } = this.props
    let _config = fromJS(this.props.config).toJS()
    let menu = fromJS(this.props.menu).toJS() // 菜单信息,存在表单对象时,从菜单中更新
    if (menuformRef) {
      menu = {...menu, MenuName: menuformRef.props.form.getFieldValue('MenuName'), MenuNo: menuformRef.props.form.getFieldValue('MenuNo')}
    }
    this.actionFormRef.handleConfirm().then(res => {
      let btn = res         // 按钮信息
@@ -866,12 +855,7 @@
   * @description 创建按钮接口(写入)
   */
  btnCreatInterface = () => {
    const { config, type, menuformRef } = this.props
    let menu = fromJS(this.props.menu).toJS() // 菜单信息,存在表单对象时,从菜单中更新
    if (menuformRef) {
      menu = {...menu, MenuName: menuformRef.props.form.getFieldValue('MenuName'), MenuNo: menuformRef.props.form.getFieldValue('MenuNo')}
    }
    const { config, type, menu } = this.props
    this.actionFormRef.handleConfirm().then(result => {
      if (result.Ot === 'requiredOnce') {
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -779,7 +779,12 @@
              </Row>
            </Form>
          </TabPane>
          <TabPane tab="Excel列设置" key="excelcolumn">
          <TabPane tab={
            <span>
              Excel列设置
              {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null}
            </span>
          } key="excelcolumn">
            <ColumnForm
              dict={this.props.dict}
              columns={verify.columns}
@@ -801,7 +806,12 @@
              pagination={false}
            />
          </TabPane>
          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab="唯一性验证" key="unique">
          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={
            <span>
              唯一性验证
              {verify.uniques.length ? <span className="count-tip">{verify.uniques.length}</span> : null}
            </span>
          } key="unique">
            <UniqueForm
              fields={verify.columns}
              dict={this.props.dict}
@@ -817,7 +827,12 @@
              pagination={false}
            />
          </TabPane> : null}
          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab="自定义脚本" key="scripts">
          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={
            <span>
              自定义脚本
              {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null}
            </span>
          } key="scripts">
            <CustomScript
              dict={this.props.dict}
              btn={this.props.card}
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
@@ -12,6 +12,12 @@
  .ant-input-number {
    width: 100%;
  }
  .count-tip {
    position: absolute;
    top: 0px;
    color: #1890ff;
    font-size: 12px;
  }
  .verify-form {
    .sql {
      .ant-col-sm-8 {
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -448,7 +448,12 @@
    return (
      <div id="verify-excelout-box-tab">
        <Tabs defaultActiveKey="1" className="verify-card-box" onChange={this.tabchange}>
          <TabPane tab="Excel导出列" key="1">
          <TabPane tab={
            <span>
              Excel导出列
              {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null}
            </span>
          } key="1">
            <ColumnForm
              dict={this.props.dict}
              columnChange={this.columnChange}
@@ -469,7 +474,12 @@
              pagination={false}
            />
          </TabPane>
          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab="自定义脚本" key="6">
          {card.intertype === 'inner' && !card.innerFunc ? <TabPane tab={
            <span>
              自定义脚本
              {verify.enable === 'true' ? <span className="count-tip">1</span> : null}
            </span>
          } key="6">
            <Form {...formItemLayout} className="verify-form">
              <Row gutter={24}>
                <Col span={8}>
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
@@ -12,6 +12,12 @@
  .ant-input-number {
    width: 100%;
  }
  .count-tip {
    position: absolute;
    top: 0px;
    color: #1890ff;
    font-size: 12px;
  }
  .verify-form {
    .sql {
      .ant-col-sm-8 {
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -332,7 +332,12 @@
              </Row>
            </Form>
          </TabPane>
          <TabPane tab="打印类型" key="2">
          <TabPane tab={
            <span>
              打印类型
              {verify.printerTypeList.length ? <span className="count-tip">{verify.printerTypeList.length}</span> : null}
            </span>
          } key="2">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col span={24} className="print-tip">
src/templates/sharecomponent/actioncomponent/verifyprint/index.scss
@@ -54,6 +54,12 @@
      }
    }
  }
  .count-tip {
    position: absolute;
    top: 0px;
    color: #1890ff;
    font-size: 12px;
  }
}
.print-template-setting {
  .ant-select-dropdown-menu-item {
src/templates/sharecomponent/chartgroupcomponent/index.jsx
@@ -263,7 +263,7 @@
    return (
      <div className="model-table-chartview-list">
        <Icon type="plus" onClick={() => this.handleChart()} />
        {chartlist.length > 1 ? <Icon type={config.expand ? 'up' : 'down'} onClick={this.onChartChange} /> : null}
        {chartlist.length > 1 ? <Icon type={config.expand ? 'up' : 'down'} title="展开/合并" onClick={this.onChartChange} /> : null}
        {chartlist.length > 1 ? <DragChartView
          activeKey={chartview}
          list={chartlist}
src/templates/sharecomponent/chartgroupcomponent/index.scss
@@ -19,6 +19,9 @@
    z-index: 11;
    cursor: pointer;
    font-size: 16px;
    margin-top: 18px;
    margin-top: 17px;
  }
  .anticon-up {
    color: #1890ff;
  }
}
src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -254,7 +254,7 @@
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
src/templates/sharecomponent/settingcomponent/index.jsx
@@ -22,7 +22,6 @@
    MenuID: PropTypes.string,        // 菜单ID
    config: PropTypes.object,        // 菜单配置信息
    permFuncField: PropTypes.array,  // 存储过程可用开头字段
    menuformRef: PropTypes.any,      // 菜单基本信息表单
    updatesetting: PropTypes.func
  }
@@ -38,15 +37,9 @@
   * @description 全局设置触发
   */
  changeSetting = () => {
    const { menuformRef, MenuID, config, type, permFuncField, mainsearch } = this.props
    let menu = {MenuID: MenuID}
    if (menuformRef) {
      menu = {MenuID: MenuID, MenuName: menuformRef.props.form.getFieldValue('MenuName') || '', MenuNo: menuformRef.props.form.getFieldValue('MenuNo') || ''}
    }
    const { MenuID, config, type, permFuncField, mainsearch } = this.props
    let menu = {MenuID: MenuID, MenuName: config.MenuName, MenuNo: config.MenuNo}
    let _columns = fromJS(config.columns).toJS()
    let primaryKey = config.setting.primaryKey || ''
    if (!primaryKey || _columns.filter(column => column.field === primaryKey).length === 0) {
src/templates/sharecomponent/treesettingcomponent/index.jsx
@@ -20,7 +20,6 @@
    MenuID: PropTypes.string,        // 菜单ID
    config: PropTypes.object,        // 菜单配置信息
    permFuncField: PropTypes.array,  // 存储过程可用开头字段
    menuformRef: PropTypes.any,      // 菜单基本信息表单
    updatesetting: PropTypes.func
  }
@@ -36,12 +35,8 @@
   * @description 全局设置触发
   */
  changeSetting = () => {
    const { menuformRef, MenuID, config, permFuncField } = this.props
    let menu = {MenuID: MenuID}
    if (menuformRef) {
      menu = {MenuID: MenuID, MenuName: menuformRef.props.form.getFieldValue('MenuName') || '', MenuNo: menuformRef.props.form.getFieldValue('MenuNo') || ''}
    }
    const { MenuID, config, permFuncField } = this.props
    let menu = {MenuID: MenuID, MenuName: config.MenuName, MenuNo: config.MenuNo}
    let _config = fromJS(config).toJS()
src/templates/subtableconfig/index.jsx
@@ -11,14 +11,13 @@
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import Utils from '@/utils/utils.js'
import { getSubMenuForm } from '@/templates/zshare/formconfig'
import asyncComponent from '@/utils/asyncComponent'
import SearchComponent from '@/templates/sharecomponent/searchcomponent'
import ActionComponent from '@/templates/sharecomponent/actioncomponent'
import ColumnComponent from '@/templates/sharecomponent/columncomponent'
import MenuForm from '@/templates/zshare/menuform'
import MenuForm from './menuform'
import EditComponent from '@/templates/zshare/editcomponent'
import SourceElement from '@/templates/zshare/dragsource'
import Source from './source'
@@ -52,9 +51,6 @@
    config: null,            // 页面配置
    visible: false,          // 搜索条件、按钮、显示列,模态框显示控制
    tableFields: [],         // 已选表字段集
    fields: null,            // 搜索条件及显示列,可选字段
    menuformlist: null,      // 基本信息表单字段
    formlist: null,          // 搜索条件、按钮、显示列表单字段
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
    loading: false,          // 加载中,页面spin
@@ -83,12 +79,12 @@
    let _config = null
    if (!config) {
      _config = JSON.parse(JSON.stringify(Source.baseConfig))
      _config = fromJS(Source.baseConfig).toJS()
      _config.uuid = editSubTab ? editSubTab.linkTab : editTab.linkTab
      _config.tabName = editSubTab ? editSubTab.label : editTab.label
      _config.isAdd = true
    } else {
      _config = JSON.parse(JSON.stringify(config))
      _config = fromJS(config).toJS()
      _config.search.forEach(item => {
        if (
@@ -114,7 +110,7 @@
        let uuid = Utils.getuuid()
        if (item.OpenType === 'pop') { // 含有子配置项的按钮
          _oriActions.push({
            prebtn: JSON.parse(JSON.stringify(item)),
            prebtn: fromJS(item).toJS(),
            curuuid: uuid,
            Template: 'Modal'
          })
@@ -185,8 +181,7 @@
      optionLibs: optionLibs,
      config: _config,
      activeKey: _activeKey || '0',
      originConfig: _config,
      menuformlist: getSubMenuForm(_config)
      originConfig: fromJS(_config).toJS(),
    })
  }
@@ -305,345 +300,347 @@
   * @description 标签页保存
   */
  submitConfig = () => {
    const { delActions, thawButtons, originConfig, openEdition } = this.state
    let config = JSON.parse(JSON.stringify(this.state.config))
    const { delActions, thawButtons, openEdition } = this.state
    let _config = fromJS(this.state.config).toJS()
    let copyreg = /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/ig
    this.menuformRef.handleConfirm().then(res => {
      if (copyreg.test(res.MenuNo) || copyreg.test(res.MenuName)) {
    // 基本信息验证
    if (!_config.tabName || !_config.tabNo) {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
      return
    }
    if (copyreg.test(_config.tabNo) || copyreg.test(_config.tabName)) {
      notification.warning({
        top: 92,
        message: '此标签为复制标签,请修改标签名称和标签参数,不可以时间格式 YYYY-MM-DD HH:mm:ss 结尾!',
        duration: 5
      })
      return
    }
    if (_config.isAdd) {
      if (_config.search[0] && _config.search[0].origin) {
        _config.search = _config.search.filter(item => !item.origin)
      }
      if (_config.action[0] && _config.action[0].origin) {
        _config.action = _config.action.filter(item => !item.origin)
      }
      if (_config.columns[0] && _config.columns[0].origin) {
        _config.columns = _config.columns.filter(item => !item.origin)
      }
    }
    // 未设置数据源或主键时,启用状态为false
    let result = this.verifyconfig(_config)
    if (result !== true) {
      _config.enabled = false
    }
    _config.funcs = []
    _config.funcs.push({
      type: 'view',
      subtype: 'view',
      uuid: _config.uuid,
      intertype: _config.setting.interType || 'inner',
      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 === 'inner' && !item.innerFunc) {
        tablename = _config.setting.tableName || ''
      }
      if (item.OpenType === 'popview') {
        _config.funcs.push({
          type: 'tab',
          subtype: 'btn',
          uuid: item.uuid,
          label: item.label,
          linkTab: item.linkTab
        })
      } else {
        _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 || ''
        })
      }
    })
    if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
      this.setState({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
    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 = ''
                if (result.LongParam) {
                  try {
                    _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                  } catch (e) {
                    console.warn('Parse Failure')
                    _LongParam = ''
                  }
                }
                if (_LongParam) {
                  item.menuNo = _LongParam.tabNo
                  item.subfuncs = _LongParam.funcs || []
                }
              }
              resolve()
            })
          })
          deffers.push(deffer)
        }
      })
      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: '请修改标签名称和标签参数,不可以时间格式 YYYY-MM-DD HH:mm:ss 结尾!',
          message: '编译错误',
          duration: 5
        })
        this.setState({
          menucloseloading: false,
          menuloading: false
        })
        return
      }
      if (originConfig.isAdd) {
        if (config.search[0] && config.search[0].origin) {
          config.search = config.search.filter(item => !item.origin)
        }
        if (config.action[0] && config.action[0].origin) {
          config.action = config.action.filter(item => !item.origin)
        }
        if (config.columns[0] && config.columns[0].origin) {
          config.columns = config.columns.filter(item => !item.origin)
        }
      let btnParam = {
        func: 'sPC_Button_AddUpt',
        Type: 40,
        ParentID: _config.uuid,
        MenuNo: _config.tabNo,
        Template: 'SubTable',
        PageParam: '',
        LongParam: '',
        LText: []
      }
      let _LongParam = ''
      let _config = {...config, tabName: res.MenuName, tabNo: res.MenuNo, Remark: res.Remark}
      let btntabs = []
      // 未设置数据源或主键时,启用状态为false
      let result = this.verifyconfig(_config)
      if (result !== true) {
        _config.enabled = false
      }
      _config.funcs = []
      _config.funcs.push({
        type: 'view',
        subtype: 'view',
        uuid: _config.uuid,
        intertype: _config.setting.interType || 'inner',
        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 === 'inner' && !item.innerFunc) {
          tablename = _config.setting.tableName || ''
        }
      _config.action.forEach((item, index) => {
        if (item.OpenType === 'popview') {
          _config.funcs.push({
            type: 'tab',
            subtype: 'btn',
            uuid: item.uuid,
            label: item.label,
            linkTab: item.linkTab
          })
        } else {
          _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 || ''
          })
          btntabs.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`)
        }
        btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
      })
      if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
        this.setState({
          menucloseloading: true
        })
      } else {
        this.setState({
          menuloading: true
        })
      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.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
      let tabParam = { // 添加标签按钮tab页
        func: 'sPC_sMenusTab_AddUpt',
        MenuID: _config.uuid,
        LText: btntabs.join(' union all ')
      }
      tabParam.LText = Utils.formatOptions(tabParam.LText)
      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
      let param = {
        func: 'sPC_Tab_AddUpt',
        MenuID: _config.uuid,
        MenuNo: _config.tabNo,
        Template: 'SubTable',
        MenuName: _config.tabName,
        Remark: _config.Remark,
        Sort: 0,
        PageParam: JSON.stringify({Template: 'SubTable'}),
        LongParam: _LongParam
      }
      if (openEdition) {
        param.open_edition = openEdition
      }
      // 有按钮或标签删除时,先进行删除操作
      // 删除成功后,保存页面配置
      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 = ''
                  if (result.LongParam) {
                    try {
                      _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                    } catch (e) {
                      console.warn('Parse Failure')
                      _LongParam = ''
                    }
                  }
                  if (_LongParam) {
                    item.menuNo = _LongParam.tabNo
                    item.subfuncs = _LongParam.funcs || []
                  }
                }
                resolve()
        if (delActions.length > 0) {
          let deffers = delActions.map(item => {
            let _param = {
              func: 'sPC_MainMenu_Del',
              MenuID: item.card.uuid
            }
            let _ParentParam = null
            try {
              _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
            } catch (e) {
              console.warn('Stringify Failure')
              _ParentParam = null
            }
            if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
              _param.ParentParam = _ParentParam
            }
            return new Promise(resolve => {
              Api.getSystemConfig(_param).then(response => {
                resolve(response)
              })
            })
            deffers.push(deffer)
          }
        })
        if (deffers.length === 0) {
          resolve()
        } else {
          Promise.all(deffers).then(() => {
            resolve()
          })
        }
      }).then(() => {
        // 保存时删除配置类型,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 btnParam = {
          func: 'sPC_Button_AddUpt',
          Type: 40,
          ParentID: _config.uuid,
          MenuNo: res.MenuNo,
          Template: 'SubTable',
          PageParam: '',
          LongParam: '',
          LText: []
        }
        let btntabs = []
        config.action.forEach((item, index) => {
          if (item.OpenType === 'popview') {
            btntabs.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`)
          }
          btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 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') + '.000'
        btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
        let tabParam = { // 添加标签按钮tab页
          func: 'sPC_sMenusTab_AddUpt',
          MenuID: _config.uuid,
          LText: btntabs.join(' union all ')
        }
        tabParam.LText = Utils.formatOptions(tabParam.LText)
        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
        let param = {
          func: 'sPC_Tab_AddUpt',
          MenuID: _config.uuid,
          MenuNo: res.MenuNo,
          Template: 'SubTable',
          MenuName: res.MenuName,
          Remark: res.Remark,
          Sort: 0,
          PageParam: JSON.stringify({Template: 'SubTable'}),
          LongParam: _LongParam
        }
        if (openEdition) {
          param.open_edition = openEdition
        }
        // 有按钮或标签删除时,先进行删除操作
        // 删除成功后,保存页面配置
        new Promise(resolve => {
          if (delActions.length > 0) {
            let deffers = delActions.map(item => {
              let _param = {
                func: 'sPC_MainMenu_Del',
                MenuID: item.card.uuid
              }
              let _ParentParam = null
              try {
                _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
              } catch (e) {
                console.warn('Stringify Failure')
                _ParentParam = null
              }
              if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
                _param.ParentParam = _ParentParam
              }
              return new Promise(resolve => {
                Api.getSystemConfig(_param).then(response => {
                  resolve(response)
                })
              })
            })
            Promise.all(deffers).then(result => {
              let error = null
              result.forEach(response => {
                if (!response.status) {
                  error = response
                }
              })
              if (error) {
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
                notification.warning({
                  top: 92,
                  message: error.message,
                  duration: 5
                })
                resolve(false)
              } else {
                this.setState({
                  delActions: []
                })
                resolve(true)
          Promise.all(deffers).then(result => {
            let error = null
            result.forEach(response => {
              if (!response.status) {
                error = response
              }
            })
          } else if (delActions.length === 0) {
            resolve(true)
          }
        }).then(resp => {
          if (resp === false) return
          if (thawButtons.length > 0) {
            let defers = thawButtons.map(item => {
              return new Promise((resolve) => {
                Api.getSystemConfig({
                  func: 'sPC_MainMenu_ReDel',
                  MenuID: item
                }).then(res => {
                  if (res.status) {
                    resolve('')
                  } else {
                    resolve(res.message)
                  }
                })
              })
            })
            return Promise.all(defers)
          } else {
            return true
          }
        }).then(res => {
          if (res === true || res === false) return res
          let msg = res.filter(Boolean)[0]
          if (msg) {
            notification.warning({
              top: 92,
              message: msg,
              duration: 5
            })
            return false
          } else {
            this.setState({
              thawButtons: []
            })
            return true
          }
        }).then(resp => {
          if (resp === false) return
  
          Api.getSystemConfig(param).then(response => {
            if (response.status) {
              this.setState({
                openEdition: response.open_edition || '',
                config: _config,
                originConfig: _config
              }, () => {
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
                this.submitAction(btnParam, tabParam)
              })
            } else {
            if (error) {
              this.setState({
                menuloading: false,
                menucloseloading: false
              })
              notification.warning({
                top: 92,
                message: response.message,
                message: error.message,
                duration: 5
              })
              resolve(false)
            } else {
              this.setState({
                delActions: []
              })
              resolve(true)
            }
          })
        } else if (delActions.length === 0) {
          resolve(true)
        }
      }).then(resp => {
        if (resp === false) return
        if (thawButtons.length > 0) {
          let defers = thawButtons.map(item => {
            return new Promise((resolve) => {
              Api.getSystemConfig({
                func: 'sPC_MainMenu_ReDel',
                MenuID: item
              }).then(res => {
                if (res.status) {
                  resolve('')
                } else {
                  resolve(res.message)
                }
              })
            })
          })
          return Promise.all(defers)
        } else {
          return true
        }
      }).then(res => {
        if (res === true || res === false) return res
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.warning({
            top: 92,
            message: msg,
            duration: 5
          })
          return false
        } else {
          this.setState({
            thawButtons: []
          })
          return true
        }
      }).then(resp => {
        if (resp === false) return
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            this.setState({
              openEdition: response.open_edition || '',
              config: _config,
              originConfig: fromJS(_config).toJS()
            }, () => {
              this.setState({
                menuloading: false,
                menucloseloading: false
              })
              this.submitAction(btnParam, tabParam)
            })
          } else {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          }
        })
      })
    }, () => {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
    })
  }
  /**
@@ -792,21 +789,13 @@
        onCancel() {}
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, tabName: res.MenuName, tabNo: res.MenuNo, Remark: res.Remark}
        if (!is(fromJS(originConfig), fromJS(_config))) {
          this.setState({
            closeVisible: true
          })
        } else {
          this.handleViewBack()
        }
      }, () => {
      if (!is(fromJS(originConfig), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      })
      } else {
        this.handleViewBack()
      }
    }
  }
@@ -824,103 +813,93 @@
        duration: 5
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, tabName: res.MenuName, tabNo: res.MenuNo, Remark: res.Remark}
        if (!is(fromJS(originConfig), fromJS(_config))) {
          notification.warning({
            top: 92,
            message: '菜单配置已修改,请保存!',
            duration: 5
          })
        } else {
          this.setState({
            loading: true
          })
          // 子菜单信息验证通过后,跳转子按钮配置页面
          let _view = ''
          let _subtab = editSubTab
          if (btn.OpenType === 'pop') {
            _view = 'Modal'             // 表单页面
          } else if (btn.OpenType === 'popview') {
            _view = btn.tabType        // 新弹窗标签模板
            _subtab = btn
          }
          if (editSubTab) {
            editSubTab.activeKey = activeKey
            editSubTab.open_edition = openEdition  // 更新版本号
          } else {
            editTab.activeKey = activeKey
            editTab.open_edition = openEdition     // 更新版本号
          }
          let param = {
            editMenu: menu,
            optionLibs: this.state.optionLibs,
            editTab: editTab,
            tabConfig: editSubTab ? tabConfig : originConfig,
            editSubTab: _subtab,
            subTabConfig: editSubTab ? originConfig : null,
            btnTab: btnTab,
            btnTabConfig: btnTabConfig,
            editAction: btn,
            subConfig: '',
            tabview: _view
          }
          Api.getSystemConfig({
            func: 'sPC_Get_LongParam',
            MenuID: btn.OpenType === 'popview' ? btn.linkTab : btn.uuid
          }).then(res => {
            if (res.status) {
              this.setState({
                loading: false
              })
              let _LongParam = ''
              if (res.LongParam) {
                try {
                  _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
                } catch (e) {
                  console.warn('Parse Failure')
                  _LongParam = ''
                }
              }
              if (_LongParam && param.tabview === 'Modal' && _LongParam.type === 'Modal') {
                param.subConfig = _LongParam
              } else if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
                param.subConfig = _LongParam
              }
              if (param.editAction) {
                param.editAction.open_edition = res.open_edition || ''
              } else if (param.editSubTab) {
                param.editSubTab.open_edition = res.open_edition || ''
              }
              this.props.handleView(param)
            } else {
              this.setState({
                loading: false
              })
              notification.warning({
                top: 92,
                message: res.message,
                duration: 5
              })
            }
          })
        }
      }, () => {
      if (!is(fromJS(originConfig), fromJS(config))) {
        notification.warning({
          top: 92,
          message: '菜单基本信息已修改,请保存!',
          message: '菜单配置已修改,请保存!',
          duration: 5
        })
      })
      } else {
        this.setState({
          loading: true
        })
        // 子菜单信息验证通过后,跳转子按钮配置页面
        let _view = ''
        let _subtab = editSubTab
        if (btn.OpenType === 'pop') {
          _view = 'Modal'             // 表单页面
        } else if (btn.OpenType === 'popview') {
          _view = btn.tabType        // 新弹窗标签模板
          _subtab = btn
        }
        if (editSubTab) {
          editSubTab.activeKey = activeKey
          editSubTab.open_edition = openEdition  // 更新版本号
        } else {
          editTab.activeKey = activeKey
          editTab.open_edition = openEdition     // 更新版本号
        }
        let param = {
          editMenu: menu,
          optionLibs: this.state.optionLibs,
          editTab: editTab,
          tabConfig: editSubTab ? tabConfig : originConfig,
          editSubTab: _subtab,
          subTabConfig: editSubTab ? originConfig : null,
          btnTab: btnTab,
          btnTabConfig: btnTabConfig,
          editAction: btn,
          subConfig: '',
          tabview: _view
        }
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          MenuID: btn.OpenType === 'popview' ? btn.linkTab : btn.uuid
        }).then(res => {
          if (res.status) {
            this.setState({
              loading: false
            })
            let _LongParam = ''
            if (res.LongParam) {
              try {
                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
              } catch (e) {
                console.warn('Parse Failure')
                _LongParam = ''
              }
            }
            if (_LongParam && param.tabview === 'Modal' && _LongParam.type === 'Modal') {
              param.subConfig = _LongParam
            } else if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
              param.subConfig = _LongParam
            }
            if (param.editAction) {
              param.editAction.open_edition = res.open_edition || ''
            } else if (param.editSubTab) {
              param.editSubTab.open_edition = res.open_edition || ''
            }
            this.props.handleView(param)
          } else {
            this.setState({
              loading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
        })
      }
    }
  }
@@ -1101,8 +1080,8 @@
                {/* 菜单信息 */}
                <MenuForm
                  dict={this.state.dict}
                  formlist={this.state.menuformlist}
                  wrappedComponentRef={(inst) => this.menuformRef = inst}
                  config={config}
                  updatemenu={this.updateconfig}
                />
                {/* 表名添加 */}
                <TableComponent
@@ -1190,7 +1169,6 @@
                config={config}
                mainsearch={!this.props.editSubTab && this.props.editTab.mainsearch ? this.props.editTab.mainsearch : ''}
                MenuID={config.uuid}
                menuformRef={this.menuformRef}
                permFuncField={this.props.permFuncField}
                updatesetting={this.updateconfig}
              />
@@ -1221,7 +1199,6 @@
                          menu={{MenuID: config.uuid, MenuName: config.tabName, MenuNo: config.tabNo, fstMenuList: this.props.menu.fstMenuList}}
                          config={config}
                          tabs={this.state.tabviews}
                          menuformRef={this.menuformRef}
                          pasteContent={this.state.pasteContent}
                          usefulFields={this.props.permFuncField}
                          setSubConfig={this.setSubConfig}
src/templates/subtableconfig/menuform/index.jsx
New file
@@ -0,0 +1,114 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Input } from 'antd'
import { formRule } from '@/utils/option.js'
import './index.scss'
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    config: PropTypes.object,
    updatemenu: PropTypes.func
  }
  changeName = (e) => {
    let value = e.target.value || ''
    if (value.length > 100) return
    this.setState({}, () => {
      this.props.updatemenu({...this.props.config, tabName: value})
    })
  }
  changeNo = (e) => {
    let value = e.target.value || ''
    if (value.length > 100) return
    this.setState({}, () => {
      this.props.updatemenu({...this.props.config, tabNo: value})
    })
  }
  changeRemark = (e) => {
    let value = e.target.value || ''
    if (value.length > 100) return
    this.setState({}, () => {
      this.props.updatemenu({...this.props.config, Remark: value})
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return is(fromJS(this.props), fromJS(nextProps))
  }
  render() {
    const { dict, config } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 24 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 24 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form" id="subqazxcvbn">
        <Row gutter={24}>
          <Col span={24}>
            <Form.Item label={dict['header.menu.viewName']}>
              {getFieldDecorator('tabName', {
                initialValue: config.tabName,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.input'] + dict['header.menu.viewName'] + '!'
                  },
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeName}/>)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['model.menu'] + dict['model.param']}>
              {getFieldDecorator('tabNo', {
                initialValue: config.tabNo,
                rules: [
                  {
                    required: true,
                    message: dict['form.required.input'] + dict['model.menu'] + dict['model.param'] + '!'
                  },
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeNo}/>)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['header.menu.Remark']}>
              {getFieldDecorator('Remark', {
                initialValue: config.Remark,
                rules: [
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeRemark}/>)}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/templates/subtableconfig/menuform/index.scss
src/templates/treepageconfig/index.jsx
@@ -11,11 +11,10 @@
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getMainMenuForm } from '@/templates/zshare/formconfig'
import asyncComponent from '@/utils/asyncComponent'
import MenuForm from '@/templates/zshare/menuform'
import MenuForm from '@/templates/comtableconfig/menuform'
import EditComponent from '@/templates/zshare/editcomponent'
import SourceElement from '@/templates/zshare/dragsource'
import Source from './source'
@@ -38,7 +37,6 @@
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    config: null,            // 页面配置
    menuformlist: null,      // 基本信息表单字段
    formlist: null,          // 搜索条件、按钮、显示列表单字段
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
@@ -72,6 +70,13 @@
      _config = _LongParam
    }
    // 页面配置中保留菜单信息,只用于数据传递
    _config.ParentId = menu.ParentId
    _config.fstMenuId = menu.fstMenuId
    _config.MenuName = menu.MenuName || ''
    _config.MenuNo = menu.MenuNo || ''
    _config.OpenType = menu.PageParam ? menu.PageParam.OpenType : ''
    // 配置默认值,兼容
    _config.Template = 'TreePage'
    _config.easyCode = _config.easyCode || ''
@@ -96,8 +101,7 @@
      openEdition: menu.open_edition || '',
      activeKey: menu.activeKey || '0',
      optionLibs: optionLibs,
      originMenu: fromJS(menu).toJS(),
      menuformlist: getMainMenuForm(menu, _config)
      originMenu: fromJS(_config).toJS()
    })
  }
@@ -189,339 +193,326 @@
   */
  submitConfig = () => {
    const { menu } = this.props
    const { originMenu, delTabs, openEdition } = this.state
    const { delTabs, openEdition } = this.state
    let config = fromJS(this.state.config).toJS()
    let _config = fromJS(this.state.config).toJS()
    this.menuformRef.handleConfirm().then(res => {
      if (config.isAdd) {
        config.tabgroups[0].sublist = config.tabgroups[0].sublist.filter(item => !item.origin)
      }
    // 基本信息验证
    if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
      return
    }
      if (config.type === 'user') { // 使用已有菜单时,默认添加关联标签id
        config.tabgroups.forEach(group => {
          group.sublist = group.sublist.map(tab => {
            if (!tab.linkTab) {
              tab.linkTab = Utils.getuuid()
            }
            return tab
    // 新建验证
    if (_config.isAdd) {
      _config.tabgroups[0].sublist = _config.tabgroups[0].sublist.filter(item => !item.origin)
    }
    // 使用已有菜单时,默认添加关联标签id
    if (_config.type === 'user') {
      _config.tabgroups.forEach(group => {
        group.sublist = group.sublist.map(tab => {
          if (!tab.linkTab) {
            tab.linkTab = Utils.getuuid()
          }
          return tab
        })
      })
    }
    // 未设置数据源或标签不合法时,启用状态为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 || 'inner',
      interface: _config.setting.interface || '',
      tableName: _config.setting.tableName || '',
      innerFunc: _config.setting.innerFunc || '',
      outerFunc: _config.setting.outerFunc || ''
    })
    _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({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
    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 = ''
                if (result.LongParam) {
                  try {
                    _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                  } catch (e) {
                    console.warn('Parse Failure')
                    _LongParam = ''
                  }
                }
                if (_LongParam) {
                  item.menuNo = _LongParam.tabNo || ''
                  item.subfuncs = _LongParam.funcs || []
                }
              }
              resolve()
            })
          })
          deffers.push(deffer)
        }
      })
      if (deffers.length === 0) {
        resolve()
      } else {
        Promise.all(deffers).then(() => {
          resolve()
        })
      }
    }).then(() => {
      // 保存时删除配置类型,system 、user
      delete _config.type
      delete _config.isAdd
      let _LongParam = ''
      let _config = {...config, easyCode: res.easyCode}
      let _pageParam = {...menu.PageParam, OpenType: res.opentype}
      // 未设置数据源或标签不合法时,启用状态为false
      let vresult = this.verifyconfig(_config)
      if (vresult !== true) {
        _config.enabled = false
      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
      }
      _config.funcs = [] // 页面及子页面存储过程集
      _config.funcs.push({
        type: 'view',
        subtype: 'view',
        uuid: menu.MenuID,
        intertype: _config.setting.interType || 'inner',
        interface: _config.setting.interface || '',
        tableName: _config.setting.tableName || '',
        innerFunc: _config.setting.innerFunc || '',
        outerFunc: _config.setting.outerFunc || ''
      })
      _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({
          menucloseloading: true
        })
      } else {
        this.setState({
          menuloading: true
        })
      }
      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 = ''
                  if (result.LongParam) {
                    try {
                      _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                    } catch (e) {
                      console.warn('Parse Failure')
                      _LongParam = ''
                    }
                  }
      let _sort = 0
      let btntabs = []
      
                  if (_LongParam) {
                    item.menuNo = _LongParam.tabNo || ''
                    item.subfuncs = _LongParam.funcs || []
                  }
                }
                resolve()
      let tabParam = { // 添加菜单tab页
        func: 'sPC_sMenusTab_AddUpt',
        MenuID: menu.MenuID
      }
      let _LText = []
      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`)
        })
      })
      _LText = _LText.join(' union all ')
      tabParam.LText = Utils.formatOptions(_LText)
      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
      let _vals = this.getFuncNames(_config.funcs, [], [])
      let _tables = Array.from(new Set(_vals.table))
      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 (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') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      if (openEdition) { // 版本管理
        param.open_edition = openEdition
      }
      // 有按钮或标签删除时,先进行删除操作
      // 删除成功后,保存页面配置
      new Promise(resolve => {
        if (delTabs.length > 0) {
          let deffers = delTabs.map(item => {
            let _param = {
              func: 'sPC_MainMenu_Del',
              MenuID: item.uuid
            }
            return new Promise(resolve => {
              Api.getSystemConfig(_param).then(response => {
                resolve(response)
              })
            })
            deffers.push(deffer)
          }
        })
        if (deffers.length === 0) {
          resolve()
        } else {
          Promise.all(deffers).then(() => {
            resolve()
          })
        }
      }).then(() => {
        // 保存时删除配置类型,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 tabParam = { // 添加菜单tab页
          func: 'sPC_sMenusTab_AddUpt',
          MenuID: menu.MenuID
        }
        let _LText = []
        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`)
          })
        })
        _LText = _LText.join(' union all ')
        tabParam.LText = Utils.formatOptions(_LText)
        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
        let _vals = this.getFuncNames(_config.funcs, [], [])
        let _tables = Array.from(new Set(_vals.table))
        let param = {
          func: 'sPC_TrdMenu_AddUpt',
          FstID: res.fstMenuId,
          SndID: res.parentId,
          ParentID: res.parentId,
          MenuID: menu.MenuID,
          MenuNo: res.MenuNo,
          EasyCode: res.easyCode,
          Template: menu.PageParam.Template || '',
          MenuName: res.MenuName,
          PageParam: JSON.stringify(_pageParam),
          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 (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') + '.000'
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        if (openEdition) { // 版本管理
          param.open_edition = openEdition
        }
        // 有按钮或标签删除时,先进行删除操作
        // 删除成功后,保存页面配置
        new Promise(resolve => {
          if (delTabs.length > 0) {
            let deffers = delTabs.map(item => {
              let _param = {
                func: 'sPC_MainMenu_Del',
                MenuID: item.uuid
              }
              return new Promise(resolve => {
                Api.getSystemConfig(_param).then(response => {
                  resolve(response)
                })
              })
            })
            Promise.all(deffers).then(result => {
              let error = null
              result.forEach(response => {
                if (!response.status) {
                  error = response
                }
              })
              if (error) {
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
                notification.warning({
                  top: 92,
                  message: error.message,
                  duration: 5
                })
                resolve(false)
              } else {
                this.setState({
                  delTabs: []
                })
                resolve(true)
          Promise.all(deffers).then(result => {
            let error = null
            result.forEach(response => {
              if (!response.status) {
                error = response
              }
            })
          } else if (delTabs.length === 0) {
            resolve(true)
          }
        }).then(resp => {
          if (resp === false) return
          let localParam = fromJS(param).toJS()
          Api.getSystemConfig(param).then(response => {
            if (response.status) {
              let _FMenu = originMenu.fstMenuList.filter(fstM => fstM.MenuID === res.fstMenuId)[0]
              let _supMenuList = []
              if (_FMenu) {
                _supMenuList = _FMenu.options
              }
              this.setState({
                config: _config,
                openEdition: response.open_edition || '',
                originMenu: {
                  ...originMenu,
                  LongParam: _config,
                  PageParam: _pageParam,
                  MenuName: res.MenuName,
                  MenuNo: res.MenuNo,
                  ParentID: res.parentId,
                  fstMenuId: res.fstMenuId,
                  supMenuList: _supMenuList
                }
              })
              this.props.reloadmenu()
              // 存在标签页时
              if (tabParam.LText) {
                Api.getSystemConfig(tabParam).then(result => {
                  if (result.status) {
                    notification.success({
                      top: 92,
                      message: '保存成功',
                      duration: 2
                    })
                    if (this.state.closeVisible) {
                      this.props.handleView()
                    } else {
                      this.setState({
                        menuloading: false,
                        menucloseloading: false
                      })
                    }
                  } else {
                    notification.warning({
                      top: 92,
                      message: result.message,
                      duration: 5
                    })
                    this.setState({
                      menuloading: false,
                      menucloseloading: false
                    })
                  }
                })
              } else {
                notification.success({
                  top: 92,
                  message: '保存成功',
                  duration: 2
                })
                if (this.state.closeVisible) {
                  this.props.handleView()
                } else {
                  this.setState({
                    menuloading: false,
                    menucloseloading: false
                  })
                }
              }
              localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
              delete localParam.LongParam
              delete localParam.PageParam
              delete localParam.Template
              delete localParam.Sort
              delete localParam.EasyCode
              delete localParam.open_edition
              Api.getLocalConfig(localParam)
            } else {
            if (error) {
              this.setState({
                menuloading: false,
                menucloseloading: false
              })
              notification.warning({
                top: 92,
                message: response.message,
                message: error.message,
                duration: 5
              })
              resolve(false)
            } else {
              this.setState({
                delTabs: []
              })
              resolve(true)
            }
          })
        } else if (delTabs.length === 0) {
          resolve(true)
        }
      }).then(resp => {
        if (resp === false) return
        let localParam = fromJS(param).toJS()
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            this.setState({
              config: _config,
              openEdition: response.open_edition || '',
              originMenu: fromJS(_config).toJS()
            })
            this.props.reloadmenu()
            // 存在标签页时
            if (tabParam.LText) {
              Api.getSystemConfig(tabParam).then(result => {
                if (result.status) {
                  notification.success({
                    top: 92,
                    message: '保存成功',
                    duration: 2
                  })
                  if (this.state.closeVisible) {
                    this.props.handleView()
                  } else {
                    this.setState({
                      menuloading: false,
                      menucloseloading: false
                    })
                  }
                } else {
                  notification.warning({
                    top: 92,
                    message: result.message,
                    duration: 5
                  })
                  this.setState({
                    menuloading: false,
                    menucloseloading: false
                  })
                }
              })
            } else {
              notification.success({
                top: 92,
                message: '保存成功',
                duration: 2
              })
              if (this.state.closeVisible) {
                this.props.handleView()
              } else {
                this.setState({
                  menuloading: false,
                  menucloseloading: false
                })
              }
            }
            localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
            delete localParam.LongParam
            delete localParam.PageParam
            delete localParam.Template
            delete localParam.Sort
            delete localParam.EasyCode
            delete localParam.open_edition
            Api.getLocalConfig(localParam)
          } else {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          }
        })
      })
    }, () => {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.basemsg'],
        duration: 5
      })
    })
  }
@@ -530,9 +521,7 @@
   * @description 点击返回时,判断配置保存状态
   */
  cancelConfig = () => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    let _this = this
    if (config.isAdd) {
@@ -546,135 +535,120 @@
        onCancel() {}
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, easyCode: res.easyCode}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.MenuName,
          MenuNo: res.MenuNo,
          ParentID: res.parentId,
          fstMenuId: res.fstMenuId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
          this.setState({
            closeVisible: true
          })
        } else {
          this.props.handleView()
        }
      }, () => {
      if (!is(fromJS(originMenu), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      })
      } else {
        this.props.handleView()
      }
    }
  }
  /**
   * @description 设置可配置按钮
   */
  setSubConfig = (item, type) => {
  setSubConfig = (item) => {
    const { menu } = this.props
    const { config, originMenu, optionLibs, activeKey, openEdition } = this.state
    if (!originMenu.MenuID) { // menuID不存在时,为新建菜单,提示菜单尚未保存
    if (config.isAdd) { // menuID不存在时,为新建菜单,提示菜单尚未保存
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.config.notsave'],
        duration: 5
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, easyCode: res.easyCode}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.MenuName,
          MenuNo: res.MenuNo,
          ParentID: res.parentId,
          fstMenuId: res.fstMenuId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) { // 菜单信息变化时,提示保存
          notification.warning({
            top: 92,
            message: this.state.dict['header.menu.config.update'],
            duration: 5
          })
          return
        }
        _originMenu.activeKey = activeKey       // 保存当前打开页签
        _originMenu.open_edition = openEdition  // 更新版本号
        let param = {
          optionLibs: optionLibs,
          editMenu: _originMenu,
          editTab: item,
          tabConfig: null,
          editSubTab: null,
          subTabConfig: null,
          btnTab: null,
          btnTabConfig: null,
          editAction: null,
          subConfig: '',
          tabview: item.type
        }
        this.setState({
          loading: true
      // 基本信息验证
      if (!config.fstMenuId || !config.ParentId || !config.MenuName || !config.MenuNo) {
        notification.warning({
          top: 92,
          message: this.state.dict['model.menu.basemsg'],
          duration: 5
        })
        return
      }
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          MenuID: item.linkTab
        }).then(res => {
          if (res.status) {
            this.setState({
              loading: false
            })
            let _LongParam = ''
            if (res.LongParam) {
              try {
                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
              } catch (e) {
                console.warn('Parse Failure')
                _LongParam = ''
              }
            }
            if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
              param.subConfig = _LongParam
            }
            if (param.editTab) {
              param.editTab.open_edition = res.open_edition || ''
            }
            this.props.handleView(param)
          } else {
            this.setState({
              loading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
        })
      }, () => {
      // 菜单信息变化时,提示保存
      if (!is(fromJS(originMenu), fromJS(config))) {
        notification.warning({
          top: 92,
          message: this.state.dict['header.menu.config.update'],
          duration: 5
        })
        return
      }
      let submenu = menu.fstMenuList.filter(item => item.MenuID === config.fstMenuId)[0]
      let _Menu = {
        ...menu,
        LongParam: config,
        PageParam: {...menu.PageParam, Template: config.Template, OpenType: config.OpenType},
        MenuName: config.MenuName,
        MenuNo: config.MenuNo,
        ParentId: config.ParentId,
        fstMenuId: config.fstMenuId,
        supMenuList: submenu ? submenu.options : []
      }
      _Menu.activeKey = activeKey       // 保存当前打开页签
      _Menu.open_edition = openEdition  // 更新版本号
      let param = {
        optionLibs: optionLibs,
        editMenu: _Menu,
        editTab: item,
        tabConfig: null,
        editSubTab: null,
        subTabConfig: null,
        btnTab: null,
        btnTabConfig: null,
        editAction: null,
        subConfig: '',
        tabview: item.type
      }
      this.setState({
        loading: true
      })
      Api.getSystemConfig({
        func: 'sPC_Get_LongParam',
        MenuID: item.linkTab
      }).then(res => {
        if (res.status) {
          this.setState({
            loading: false
          })
          let _LongParam = ''
          if (res.LongParam) {
            try {
              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
            } catch (e) {
              console.warn('Parse Failure')
              _LongParam = ''
            }
          }
          if (_LongParam && param.tabview === 'SubTable' && _LongParam.Template === 'SubTable') {
            param.subConfig = _LongParam
          }
          if (param.editTab) {
            param.editTab.open_edition = res.open_edition || ''
          }
          this.props.handleView(param)
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    }
  }
@@ -767,6 +741,7 @@
  }
  render () {
    const { menu } = this.props
    const { activeKey, config } = this.state
    let configTabs = []
@@ -784,9 +759,10 @@
              <Panel forceRender={true} header={this.state.dict['header.menu.basedata']} key="0" id="main-basedata">
                {/* 菜单信息 */}
                <MenuForm
                  menu={menu}
                  config={config}
                  dict={this.state.dict}
                  formlist={this.state.menuformlist}
                  wrappedComponentRef={(inst) => this.menuformRef = inst}
                  updatemenu={this.updateconfig}
                />
              </Panel>
              {/* 添加标签 */}
@@ -811,7 +787,7 @@
                        className="config-button"
                        icon={item.icon}
                        style={{marginBottom: '10px'}}
                        onClick={() => this.setSubConfig(item, 'tab')}
                        onClick={() => this.setSubConfig(item)}
                      >{item.label}</Button>
                    </div>
                  )
@@ -838,7 +814,6 @@
                  <TreeSettingComponent
                    config={config}
                    MenuID={this.props.menu.MenuID}
                    menuformRef={this.menuformRef}
                    permFuncField={this.props.permFuncField}
                    updatesetting={this.updateconfig}
                  />
@@ -876,7 +851,7 @@
                  <TabsComponent
                    config={config}
                    tabs={this.state.tabviews}
                    setSubConfig={(item) => this.setSubConfig(item, 'tab')}
                    setSubConfig={(item) => this.setSubConfig(item)}
                    updatetabs={this.updatetabs}
                  />
                </Col>
src/templates/zshare/formconfig.jsx
@@ -517,108 +517,6 @@
}
/**
 * @description 获取主菜单基本信息表单配置信息
 * @param {object} menu    // 主表基本信息
 * @param {object} config  // 主表配置信息
 */
export function getMainMenuForm (menu, _config) {
  return [
    {
      type: 'select',
      key: 'fstMenuId',
      label: Formdict['model.menu.level1'],
      initVal: menu.fstMenuId,
      required: true,
      readonly: false,
      options: menu.fstMenuList
    },
    {
      type: 'select',
      key: 'parentId',
      label: Formdict['model.menu.level2'],
      initVal: menu.ParentID,
      required: true,
      readonly: false,
      options: menu.supMenuList
    },
    {
      type: 'text',
      key: 'MenuName',
      label: Formdict['model.menu'] + Formdict['model.name'],
      initVal: menu.MenuName,
      required: true,
      readonly: false
    },
    {
      type: 'text',
      key: 'MenuNo',
      label: Formdict['model.menu'] + Formdict['model.param'],
      initVal: menu.MenuNo,
      required: true,
      readonly: false
    },
    {
      type: 'select',
      key: 'opentype',
      label: Formdict['model.openway'],
      initVal: menu.PageParam.OpenType,
      required: true,
      options: [{
        MenuID: 'newtab',
        text: Formdict['model.form.tab']
      }, {
        MenuID: 'newpage',
        text: Formdict['model.form.newpage']
      }, {
        MenuID: 'currenttab',
        text: Formdict['header.form.currenttab']
      }]
    },
    {
      type: 'text',
      key: 'easyCode',
      label: Formdict['header.form.easyCode'],
      initVal: _config.easyCode,
      required: false,
      readonly: false
    }
  ]
}
/**
 * @description 获取子菜单基本信息表单配置信息
 * @param {object} config  // 子表配置信息
 */
export function getSubMenuForm (config) {
  return [
    {
      type: 'text',
      key: 'MenuName',
      label: Formdict['header.menu.viewName'],
      initVal: config.tabName,
      required: true,
      readonly: false
    },
    {
      type: 'text',
      key: 'MenuNo',
      label: Formdict['model.menu'] + Formdict['model.param'],
      initVal: config.tabNo,
      required: true,
      readonly: false
    },
    {
      type: 'text',
      key: 'Remark',
      label: Formdict['header.menu.Remark'],
      initVal: config.Remark,
      required: false,
      readonly: false
    }
  ]
}
/**
 * @description 获取搜索条件表单配置信息
 * @param {object} card           // 搜索条件对象
 * @param {Array}  roleList       // 角色列表
src/templates/zshare/verifycard/index.jsx
@@ -1651,7 +1651,12 @@
              </Row>
            </Form>
          </TabPane>
          <TabPane tab="比较验证" key="2x">
          <TabPane tab={
            <span>
              比较验证
              {verify.contrasts.length ? <span className="count-tip">{verify.contrasts.length}</span> : null}
            </span>
          } key="2x">
            <ContrastForm
              dict={this.props.dict}
              contrastChange={this.contrastChange}
@@ -1666,7 +1671,12 @@
              pagination={false}
            />
          </TabPane>
          <TabPane tab="自定义验证" key="3">
          <TabPane tab={
            <span>
              自定义验证
              {verify.customverifys.length ? <span className="count-tip">{verify.customverifys.length}</span> : null}
            </span>
          } key="3">
            <CustomForm
              dict={this.props.dict}
              btn={this.props.card}
@@ -1684,7 +1694,12 @@
              pagination={false}
            />
          </TabPane>
          <TabPane tab="单号生成" key="4">
          <TabPane tab={
            <span>
              单号生成
              {verify.billcodes.length ? <span className="count-tip">{verify.billcodes.length}</span> : null}
            </span>
          } key="4">
            <BillcodeForm
              fields={fields}
              btn={this.props.card}
@@ -1705,7 +1720,12 @@
              pagination={false}
            />
          </TabPane>
          <TabPane tab={card.Ot !== 'requiredOnce' ? '唯一性验证' : '同类数据验证'} key="2">
          <TabPane tab={
            <span>
              {card.Ot !== 'requiredOnce' ? '唯一性验证' : '同类数据验证'}
              {verify.uniques.length ? <span className="count-tip">{verify.uniques.length}</span> : null}
            </span>
          } key="2">
            <UniqueForm
              btn={card}
              fields={card.Ot !== 'requiredOnce' ? fields : columnsFields}
@@ -1722,7 +1742,12 @@
              pagination={false}
            />
          </TabPane>
          <TabPane tab="创建凭证" key="5">
          <TabPane tab={
            <span>
              创建凭证
              {verify.voucher && verify.voucher.enabled ? <span className="count-tip">1</span> : null}
            </span>
          } key="5">
            <VoucherForm
              dict={this.props.dict}
              voucher={voucher}
@@ -1733,7 +1758,12 @@
              wrappedComponentRef={(inst) => this.voucherForm = inst}
            />
          </TabPane>
          <TabPane tab="自定义脚本" key="6">
          <TabPane tab={
            <span>
              自定义脚本
              {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null}
            </span>
          } key="6">
            <CustomScript
              usefulfields={this.state.usefulfields}
              initsql={this.state.initsql}
src/templates/zshare/verifycard/index.scss
@@ -9,6 +9,12 @@
    word-wrap: break-word;
    word-break: break-word;
  }
  .count-tip {
    position: absolute;
    top: 0px;
    color: #1890ff;
    font-size: 12px;
  }
  .verify-form {
    .ant-input-number {
      width: 100%;
src/utils/option.js
@@ -4,7 +4,7 @@
import mainsubtable from '@/assets/img/mainsubtable.jpg'
import treepage from '@/assets/img/treepage.jpg'
import calendar from '@/assets/img/calendar.jpg'
import customImg from '@/assets/img/custom.jpg'
// import customImg from '@/assets/img/custom.jpg'
import rolemanage from '@/assets/img/rolemanage.jpg'
const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
@@ -78,13 +78,13 @@
    baseconfig: '',
    isSystem: true
  },
  {
    title: '自定义',
    type: 'CustomPage',
    url: customImg,
    baseconfig: '',
    isSystem: true
  },
  // {
  //   title: '自定义',
  //   type: 'CustomPage',
  //   url: customImg,
  //   baseconfig: '',
  //   isSystem: true
  // },
  {
    title: '角色权限分配',
    type: 'RolePermission',
src/views/menudesign/index.jsx
@@ -4,8 +4,7 @@
import { is, fromJS } from 'immutable'
import moment from 'moment'
import HTML5Backend from 'react-dnd-html5-backend'
import { Icon, notification, Modal, Collapse } from 'antd'
import html2canvas from 'html2canvas'
import { notification, Modal, Collapse, Card, Icon, Switch, Button } from 'antd'
import Api from '@/api'
import Utils from '@/utils/utils.js'
@@ -21,8 +20,8 @@
const Header = asyncComponent(() => import('@/menu/header'))
const MenuForm = asyncComponent(() => import('@/menu/menuform'))
// const Controller = asyncComponent(() => import('@/mob/controller'))
const SourceWrap = asyncComponent(() => import('@/mob/modelsource'))
const SourceWrap = asyncComponent(() => import('@/menu/modelsource'))
const MenuShell = asyncComponent(() => import('@/menu/menushell'))
// const DataSource = asyncComponent(() => import('@/mob/datasource'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -30,11 +29,11 @@
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    MenuId: this.props.match.params.MenuId,
    tableFields: [],
    activeKey: 'basedata',
    oriConfig: null,
    parentId: '',
    openEdition: '',
    saveIng: false,
    config: null,
    editElem: null
  }
@@ -73,12 +72,8 @@
    }
  }
  triggerSave = () => {
  submitConfig = () => {
    const { config, openEdition, parentId } = this.state
    this.setState({
      saveIng: true
    })
    let param = {
      func: 'sPC_TrdMenu_AddUpt',
@@ -113,8 +108,7 @@
      if (response.status) {
        this.setState({
          oriConfig: fromJS(config).toJS(),
          openEdition: response.open_edition || '',
          saveIng: false
          openEdition: response.open_edition || ''
        })
      } else {
        notification.warning({
@@ -124,77 +118,6 @@
        })
      }
    })
  }
  testFunc = () => {
    let datas = [{
      name: 'a',
      arr_field: 'MapCode,Country',
      par_tablename: '',
      type: '',
      primaryKey: 'MapCode',
      foreign_key: '',
      sql: `select MapCode,Country from @tc1`,
      script: `declare @tc1 table (MapCode nvarchar(50),Country nvarchar(50)) insert into @tc1 (MapCode,Country) select MapCode,Country from sMap where Province=''`
    }, {
      name: 'b',
      arr_field: 'MapCode,Province,ParMapCode',
      par_tablename: 'a',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Province,ParMapCode from @tc2`,
      script: `declare @tc2 table (MapCode nvarchar(50),Province nvarchar(50),ParMapCode nvarchar(50)) insert into @tc2 (MapCode,Province,ParMapCode) select MapCode,Province,ParMapCode from sMap where Province!='' and City=''`
    }, {
      name: 'c',
      arr_field: 'MapCode,City,ParMapCode',
      par_tablename: 'b',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,City,ParMapCode from @tc3`,
      script: `declare @tc3 table (MapCode nvarchar(50),City nvarchar(50),ParMapCode nvarchar(50)) insert into @tc3 (MapCode,City,ParMapCode) select MapCode,City,ParMapCode from sMap where City!='' and Area=''`
    }, {
      name: 'd',
      arr_field: 'MapCode,Area,ParMapCode',
      par_tablename: 'c',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Area,ParMapCode from sMap where Area!=''`,
      script: ``
    }]
    let LText = datas.map((item, index) => {
      // item.par_tablename = ''
      // item.foreign_key = ''
      let _orderBy = 'MapCode desc'
      let _search = ''
      let _sql = `select top 1000 ${item.arr_field} from (select ${item.arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from (${item.sql}) tb ${_search}) tmptable order by tmptable.rows `
      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(_sql))}' as LText,'${window.btoa(window.encodeURIComponent(item.script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
    })
    let LText_field = []
    datas.forEach(item => {
      item.arr_field.split(',').forEach(cell => {
        LText_field.push(`Select '${item.name}' as tablename,'${cell}' as fieldname,'nvarchar(50)' as field_type`)
      })
    })
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText_field: LText_field.join(' union all ')
    }
    param.LText = Utils.formatOptions(param.LText)
    param.LText_field = Utils.formatOptions(param.LText_field)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    Api.getLocalConfig(param)
  }
  getMenuParam = () => {
@@ -268,57 +191,41 @@
    })
  }
  updateStyle = (proper) => {
  onEnabledChange = () => {
    const { config } = this.state
    config.components = config.components.map(component => {
      if (component.uuid === proper.componentId) {
        Object.keys(component).forEach(key => {
          let _uuid = component[key].uuid
          if (_uuid && (_uuid === proper.uuid || _uuid === proper.classId)) {
            if (component[key].substyle) {
            } else {
              component[key].style = {...component[key].style, ...proper.style}
              // eslint-disable-next-line
              for (let index in component[key].style) {
                if (component[key].style[index] === '') {
                  delete component[key].style[index]
                }
              }
            }
          }
        })
      }
      return component
    this.setState({
      config: {...config, enabled: !config.enabled}
    })
    this.setState({config})
  }
  // 更新配置信息
  updateConfig = (config) => {
    this.setState({
      config: config
    })
  }
  updatetable = (config) => {
    // this.setState({
    //   config: config
    // })
  }
  save = () => {
    html2canvas(document.getElementById('view')).then(canvas => {
      let imgUri = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); // 获取生成的图片的url
      window.location.href = imgUri; // 下载图片
  /**
   * @description 更新常用表信息,快捷添加后更新配置信息
   */
  updatetable = (config, fields) => {
    const { tableFields } = this.state
    this.setState({
      config: config,
      tableFields: fields ? fields : tableFields
    })
  }
  render () {
    const { activeKey, saveIng, dict, MenuId, config } = this.state
    const { activeKey, dict, MenuId, config } = this.state
    return (
      <div className="pc-menu-view" id="view">
        <Header view="design" closeView={this.closeView} triggerSave={this.triggerSave} saveIng={saveIng} />
        <Header view="design" closeView={this.closeView} />
        <DndProvider backend={HTML5Backend}>
          <div className="menu-body">
            <div className="menu-setting">
@@ -336,45 +243,28 @@
                    updateConfig={this.updateConfig}
                  />
                  {/* 表名添加 */}
                  {config ? <TableComponent
                    config={config}
                    // containerId="main-basedata"
                    updatetable={this.updatetable}
                  /> : null}
                  {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                </Panel>
                {/* 搜索条件添加 */}
                {/* <Panel header={dict['mob.component']} key="component">
                  <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}
                  />
                </Panel> */}
                {/* 组件添加 */}
                <Panel header={dict['mob.component']} key="component">
                  <SourceWrap />
                </Panel>
              </Collapse>
              {/* <Tabs defaultActiveKey="1" animated={false} size="small">
                <TabPane tab="配置" key="1">
                  <Controller editElem={editElem} updateStyle={this.updateStyle} />
                </TabPane>
                <TabPane tab="数据源" key="2">
                  <DataSource config={config} updateConfig={this.updateConfig} />
                </TabPane>
              </Tabs> */}
            </div>
            <div className="menu-tool">
              <div className="menu-tool-content">
                <div className="plus-content">
                  <Icon type="plus-circle" />添 加 组 件
            <div className="menu-view">
              <Card title={
                <div>
                  {config && config.MenuName}
                  <Icon type="redo" style={{marginLeft: '10px'}} title="刷新标签列表" onClick={() => this.reloadTab(true)} />
                </div>
                <div className="useable-component">
                  <SourceWrap appType="Menu" />
              } bordered={false} extra={
                <div>
                  {config ? <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config.enabled} onChange={this.onEnabledChange} /> : null}
                  <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{dict['mob.save']}</Button>
                </div>
              </div>
              <div className="menu-tool-other"></div>
              } style={{ width: '100%' }}>
                {config ? <MenuShell config={config} handleList={this.updateConfig} /> : null}
              </Card>
            </div>
          </div>
        </DndProvider>
src/views/menudesign/index.scss
@@ -7,71 +7,19 @@
    overflow-x: hidden;
    position: relative;
    background: #ffffff;
    padding: 50px 300px 0px 40px;
    padding: 50px 0px 0px 0px;
    .menu-tool {
      position: fixed;
      left: 0;
      top: 48px;
      height: 100%;
      width: 40px;
      background: #262626;
      box-shadow: 2px 0px 2px #000;
      .menu-tool-content {
        width: 100%;
        .plus-content {
          position: relative;
          color: #ffffff;
          width: 100%;
          display: flex;
          align-items: center;
          writing-mode: tb-rl;
          padding: 16px 0;
          border-bottom: 1px solid #000;
          cursor: pointer;
          z-index: 10;
          background: #202735;
          i {
            margin-bottom: 5px;
            margin-left: 2px;
          }
        }
        .useable-component {
          position: absolute;
          width: 305px;
          top: 0;
          bottom: 0;
          left: -340px;
          background: #fff;
          opacity: 0;
          transition: left 0.3s linear 0.1s, opacity 0.3s linear 0.1s;
          overflow-y: auto;
        }
      }
      .menu-tool-content:hover {
        .useable-component {
          opacity: 1;
          left: 40px;
        }
      }
      .menu-tool-other {
        position: relative;
        z-index: 10;
        height: 1000px;
        background: #202735;
      }
    }
    .menu-setting {
      position: fixed;
      left: 0;
      top: 48px;
      z-index: 10;
      height: 100%;
      height: calc(100vh - 48px);
      width: 300px;
      background: #ffffff;
      box-shadow: 0px 2px 5px #bcbcbc;
      overflow-y: auto;
      > .ant-collapse {
        .ant-collapse-item.ant-collapse-item-active {
@@ -86,6 +34,36 @@
        .ant-collapse-content-box {
          .ant-form-item {
            margin-bottom: 10px;
          }
          .model-table-tablemanage-view {
            >.ant-list {
              margin-top: 20px;
              .ant-list-item {
                display: -webkit-box;
                padding-right: 20px;
                position: relative;
                padding-left: 5px;
                overflow: hidden;
                text-overflow: ellipsis;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
                min-height: 55px;
                width: 100%;
                .anticon {
                  position: absolute;
                  top: 0px;
                  right: 0px;
                  padding: 3px 3px 10px 10px;
                  cursor: pointer;
                }
              }
            }
            >.tables {
              width: 66.66666667%!important;
            }
            >.ant-form-item-label {
              width: 33.33333333%;
            }
          }
        }
      }
@@ -105,30 +83,72 @@
        }
      }
    }
  }
    .menu-setting::-webkit-scrollbar {
      width: 4px;
    }
    .menu-setting::-webkit-scrollbar-thumb {
      border-radius: 5px;
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
      background: rgba(0, 0, 0, 0.08);
    }
    .menu-setting::-webkit-scrollbar-track {
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
      border-radius: 3px;
      border: 1px solid rgba(0, 0, 0, 0.07);
      background: rgba(0, 0, 0, 0);
    }
  .flex-container {
    margin: 0 15px;
  }
  .flex-container .inline {
    width: 80px!important;
    margin: 9px 9px 9px 0;
  }
  .flex-container .small {
    height: 20px!important;
    line-height: 20px!important;
  }
  .sub-title {
    color: #888;
    font-size: 14px;
    padding: 30px 0 18px 0;
  }
  .placeholder {
    background-color: #ebebef;
    color: #bbb;
    text-align: center;
    height: 30px;
    line-height: 30px;
    width: 100%;
    .menu-view {
      position: relative;
      width: calc(100vw - 300px);
      margin-left: 300px;
      height: calc(100vh - 50px);
      overflow-y: auto;
      > .ant-card {
        >.ant-card-head {
          .ant-card-head-title {
            color: #1890ff;
            padding: 5px 0;
          }
          .ant-card-extra {
            padding: 5px 0;
            button {
              margin-left: 20px;
            }
            .ant-switch.big {
              min-width: 60px;
              height: 28px;
              line-height: 28px;
              margin-top: -2px;
              .ant-switch-inner {
                font-size: 14px;
              }
            }
            .ant-switch.big:after {
              width: 24px;
              height: 24px;
            }
          }
        }
        >.ant-card-body {
          padding: 20px;
        }
      }
    }
    .menu-view::-webkit-scrollbar {
      width: 7px;
    }
    .menu-view::-webkit-scrollbar-thumb {
      border-radius: 5px;
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
      background: rgba(0, 0, 0, 0.08);
    }
    .menu-view::-webkit-scrollbar-track {
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
      border-radius: 3px;
      border: 1px solid rgba(0, 0, 0, 0.07);
      background: rgba(0, 0, 0, 0);
    }
  }
}
src/views/mobdesign/index.jsx
@@ -5,6 +5,7 @@
import moment from 'moment'
import HTML5Backend from 'react-dnd-html5-backend'
import { Icon, Tabs, notification, Modal } from 'antd'
// import html2canvas from 'html2canvas'
import Api from '@/api'
import Utils from '@/utils/utils.js'
@@ -191,6 +192,84 @@
    })
  }
  testFunc = () => {
    let datas = [{
      name: 'a',
      arr_field: 'MapCode,Country',
      par_tablename: '',
      type: '',
      primaryKey: 'MapCode',
      foreign_key: '',
      sql: `select MapCode,Country from @tc1`,
      script: `declare @tc1 table (MapCode nvarchar(50),Country nvarchar(50)) insert into @tc1 (MapCode,Country) select MapCode,Country from sMap where Province=''`
    }, {
      name: 'b',
      arr_field: 'MapCode,Province,ParMapCode',
      par_tablename: 'a',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Province,ParMapCode from @tc2`,
      script: `declare @tc2 table (MapCode nvarchar(50),Province nvarchar(50),ParMapCode nvarchar(50)) insert into @tc2 (MapCode,Province,ParMapCode) select MapCode,Province,ParMapCode from sMap where Province!='' and City=''`
    }, {
      name: 'c',
      arr_field: 'MapCode,City,ParMapCode',
      par_tablename: 'b',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,City,ParMapCode from @tc3`,
      script: `declare @tc3 table (MapCode nvarchar(50),City nvarchar(50),ParMapCode nvarchar(50)) insert into @tc3 (MapCode,City,ParMapCode) select MapCode,City,ParMapCode from sMap where City!='' and Area=''`
    }, {
      name: 'd',
      arr_field: 'MapCode,Area,ParMapCode',
      par_tablename: 'c',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Area,ParMapCode from sMap where Area!=''`,
      script: ``
    }]
    let LText = datas.map((item, index) => {
      // item.par_tablename = ''
      // item.foreign_key = ''
      let _orderBy = 'MapCode desc'
      let _search = ''
      let _sql = `select top 1000 ${item.arr_field} from (select ${item.arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from (${item.sql}) tb ${_search}) tmptable order by tmptable.rows `
      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(_sql))}' as LText,'${window.btoa(window.encodeURIComponent(item.script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
    })
    let LText_field = []
    datas.forEach(item => {
      item.arr_field.split(',').forEach(cell => {
        LText_field.push(`Select '${item.name}' as tablename,'${cell}' as fieldname,'nvarchar(50)' as field_type`)
      })
    })
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText_field: LText_field.join(' union all ')
    }
    param.LText = Utils.formatOptions(param.LText)
    param.LText_field = Utils.formatOptions(param.LText_field)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    Api.getLocalConfig(param)
  }
  // save = () => {
  //   html2canvas(document.getElementById('view')).then(canvas => {
  //     let imgUri = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); // 获取生成的图片的url
  //     window.location.href = imgUri; // 下载图片
  //   })
  // }
  editCard = (element) => {
    this.setState({
      editElem: element