king
2020-12-29 9f3a0655391c42dc7fb9a3cfa6d8fc4ca935bd9d
2020-12-29
13个文件已修改
6个文件已添加
538 ■■■■■ 已修改文件
src/menu/components/card/cardcomponent/index.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/prop-card/index.jsx 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/cardcomponent/index.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/copycomponent/index.jsx 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/copycomponent/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/pastecomponent/index.jsx 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/pastecomponent/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/pastecontroller/index.jsx 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/pastecontroller/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/pasteform/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx
@@ -4,6 +4,7 @@
import { Modal, Popover, Icon, Switch, Col } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import SettingForm from './settingform'
@@ -13,12 +14,14 @@
import './index.scss'
const CardCellComponent = asyncComponent(() => import('../cardcellcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
class CardBoxComponent extends Component {
  static propTpyes = {
    offset: PropTypes.any,           // 偏移量
    cards: PropTypes.object,         // 卡片行配置信息
    card: PropTypes.object,          // 卡片配置信息
    move: PropTypes.func,            // 卡片移动
    deleteElement: PropTypes.func,   // 卡片删除
    updateElement: PropTypes.func    // 菜单配置更新
  }
@@ -233,8 +236,17 @@
              <div className="mk-popover-control">
                <Icon className="plus" title="添加元素" onClick={this.addElement} type="plus" />
                <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
                <Icon className="edit" type="edit" onClick={() => this.setState({settingVisible: true})} />
                <Icon className="edit" title="编辑" type="edit" onClick={() => this.setState({settingVisible: true})} />
                <CopyComponent type="cardcell" card={card}/>
                <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
                {cards.subtype === 'propcard' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                  <div className="mk-popover-control">
                    <Icon className="plus" title="左移" type="arrow-left" onClick={() => this.props.move(card, 'left')} />
                    <Icon className="close" title="右移" type="arrow-right" onClick={() => this.props.move(card, 'right')} />
                  </div>
                } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid)}>
                  <Icon type="swap" id={card.uuid}/>
                </Popover> : null}
                {cards.subtype === 'propcard' ? <Icon className="close" title="删除卡片" type="delete" onClick={() => this.props.deleteElement(card)} /> : null}
                {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
              </div>
src/menu/components/card/data-card/index.jsx
@@ -17,6 +17,8 @@
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
const CardComponent = asyncComponent(() => import('../cardcomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
@@ -381,6 +383,8 @@
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <CopyComponent type="datacard" card={card}/>
            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
src/menu/components/card/prop-card/index.jsx
@@ -16,6 +16,8 @@
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('../data-card/wrapsetting'))
const CardComponent = asyncComponent(() => import('../cardcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
@@ -304,8 +306,27 @@
    }
  }
  move = (item, direction) => {
    let card = fromJS(this.state.card).toJS()
    let dragIndex = card.subcards.findIndex(c => c.uuid === item.uuid)
    let hoverIndex = null
    if (direction === 'left') {
      hoverIndex = dragIndex - 1
    } else {
      hoverIndex = dragIndex + 1
    }
    if (hoverIndex === -1 || hoverIndex === card.subcards.length) return
    card.subcards.splice(hoverIndex, 0, ...card.subcards.splice(dragIndex, 1))
    this.setState({card})
    this.props.updateConfig(card)
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    let offset = 0
@@ -326,7 +347,9 @@
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加卡片" onClick={this.addCard} type="plus" />
            {menu ? <WrapComponent config={card} MenuType={menu.MenuType} updateConfig={this.updateComponent} /> : null}
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <CopyComponent type="propcard" card={card}/>
            <PasteComponent config={card} options={['cardcell']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -336,7 +359,7 @@
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        {card.subcards.map((subcard, index) => (<CardComponent key={subcard.uuid} offset={!index ? offset : 0} MenuType={menu ? menu.MenuType : ''} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
        {card.subcards.map((subcard, index) => (<CardComponent key={subcard.uuid} offset={!index ? offset : 0} cards={card} card={subcard} move={this.move} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
      </div>
    )
  }
src/menu/components/card/table-card/cardcomponent/index.jsx
@@ -4,6 +4,7 @@
import { Modal, Popover, Icon } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import SettingForm from './settingform'
@@ -13,6 +14,7 @@
import './index.scss'
const CardCellComponent = asyncComponent(() => import('../../cardcellcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
class CardBoxComponent extends Component {
  static propTpyes = {
@@ -171,7 +173,8 @@
              <div className="mk-popover-control">
                <Icon className="plus" title="添加元素" onClick={this.addElement} type="plus" />
                <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
                <Icon className="edit" type="edit" onClick={() => this.setState({settingVisible: true})} />
                <Icon className="edit" title="编辑" type="edit" onClick={() => this.setState({settingVisible: true})} />
                <CopyComponent type="cardcell" card={card}/>
                <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
                <Icon className="close" title="删除卡片" type="delete" onClick={() => this.props.deleteElement(card)} />
              </div>
src/menu/components/card/table-card/index.jsx
@@ -16,6 +16,8 @@
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('../data-card/wrapsetting'))
const CardComponent = asyncComponent(() => import('./cardcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
@@ -308,7 +310,6 @@
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
@@ -318,7 +319,9 @@
          <div className="mk-popover-control">
            <Icon className="plus" title="添加卡片" onClick={this.addCard} type="plus" />
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            {menu ? <WrapComponent config={card} MenuType={menu.MenuType} updateConfig={this.updateComponent} /> : null}
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <CopyComponent type="tablecard" card={card}/>
            <PasteComponent config={card} options={['cardcell', 'search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -328,7 +331,7 @@
          <Icon type="tool" />
        </Popover>
        <div style={{minHeight: card.wrap.height - 90}}>
          {card.subcards.map(subcard => (<CardComponent key={subcard.uuid} MenuType={menu ? menu.MenuType : ''} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
          {card.subcards.map(subcard => (<CardComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
        </div>
        {card.setting.laypage === 'true' ? <Pagination size="small" total={50} /> : null}
      </div>
src/menu/components/chart/antv-bar/index.jsx
@@ -19,6 +19,8 @@
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
@@ -861,6 +863,8 @@
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
            <CopyComponent type="line" card={card}/>
            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
src/menu/components/chart/antv-pie/index.jsx
@@ -17,6 +17,8 @@
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
@@ -432,6 +434,8 @@
          <div className="mk-popover-control">
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
            <CopyComponent type="pie" card={card}/>
            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
src/menu/components/search/main-search/index.jsx
@@ -20,6 +20,8 @@
const { confirm } = Modal
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
class MainSearchComponent extends Component {
  static propTpyes = {
@@ -353,6 +355,8 @@
          <div className="mk-popover-control">
            <Icon className="plus" title="添加" onClick={this.addSearch} type="plus" />
            <WrapComponent config={card} updateConfig={this.updateComponent}/>
            <CopyComponent type="mainsearch" card={card}/>
            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
          </div>
src/menu/components/share/copycomponent/index.jsx
New file
@@ -0,0 +1,46 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Icon, message } from 'antd'
import './index.scss'
class CopyComponent extends Component {
  static propTpyes = {
    btnlog: PropTypes.array,
    handlelog: PropTypes.func
  }
  trigger = () => {
    const { card, type } = this.props
    let copycard = fromJS(card).toJS()
    copycard.copyType = type
    let _val = ''
    try {
      _val = window.btoa(window.encodeURIComponent(JSON.stringify(copycard)))
    } catch {
      message.warning('复制失败,请重试!')
      _val = ''
    }
    if (_val) {
      let oInput = document.createElement('input')
      oInput.value = _val
      document.body.appendChild(oInput)
      oInput.select()
      document.execCommand('Copy')
      document.body.removeChild(oInput)
      message.success('复制成功。')
    }
  }
  render () {
    return (
      <Icon type="copy" title="复制" style={{color: '#26C281'}} onClick={this.trigger} />
    )
  }
}
export default CopyComponent
src/menu/components/share/copycomponent/index.scss
src/menu/components/share/pastecomponent/index.jsx
New file
@@ -0,0 +1,175 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Icon, Modal, notification } from 'antd'
import Utils from '@/utils/utils.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
class PasteController extends Component {
  static propTpyes = {
    config: PropTypes.object,        // 组件配置
    updateConfig: PropTypes.func
  }
  state = {
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  resetconfig = (item) => {
    item.uuid = Utils.getuuid()
    if (item.copyType === 'cardcell') {
      item.setting = item.setting || {}
      item.setting.width = item.setting.width || 6
      if (item.elements) {
        item.elements = item.elements.map(cell => {
          cell.uuid = Utils.getuuid()
          return cell
        })
      }
      if (item.backElements) {
        item.backElements = item.backElements.map(cell => {
          cell.uuid = Utils.getuuid()
          return cell
        })
      }
    } else if (item.copyType === 'table') {
      let loopCol = (col) => {
        col.subcols = col.subcols.map(c => {
          c.uuid = Utils.getuuid()
          if (c.type === 'colspan' && c.subcols) {
            c = loopCol(c)
          } else if (c.type === 'custom' && c.elements) {
            c.elements = c.elements.map(cell => {
              cell.uuid = Utils.getuuid()
              return cell
            })
          } else if (c.type === 'action' && c.elements) {
            c.elements = c.elements.map(cell => {
              cell.uuid = Utils.getuuid()
              return cell
            })
          }
          return c
        })
        return col
      }
      if (item.type === 'colspan' && item.subcols) {
        item = loopCol(item)
      } else if (item.type === 'custom' && item.elements) {
        item.elements = item.elements.map(cell => {
          cell.uuid = Utils.getuuid()
          return cell
        })
      } else if (item.type === 'action' && item.elements) {
        item.elements = item.elements.map(cell => {
          cell.uuid = Utils.getuuid()
          return cell
        })
      }
    }
    return item
  }
  pasteSubmit = () => {
    const { options } = this.props
    this.pasteFormRef.handleConfirm().then(res => {
      if (!options.includes(res.copyType)) {
        notification.warning({
          top: 92,
          message: '配置信息格式错误!',
          duration: 5
        })
        return
      }
      let type = res.copyType
      let config = fromJS(this.props.config).toJS()
      res = this.resetconfig(res)
      delete res.copyType
      if (type === 'action') {
        config.action = config.action || []
        config.action = config.action.filter(item => !item.origin)
        config.action.push(res)
      } else if (type === 'search' || type === 'form') {
        config.search = config.search || []
        config.search = config.search.filter(item => !item.origin)
        let keys = config.search.map(item => item.field.toLowerCase())
        if (type === 'form') {
          if (['number', 'switch', 'textarea', 'checkcard', 'fileupload', 'hint', 'color', 'funcvar'].includes(res.type)) {
            res.type = 'text'
          } else if (res.type === 'radio') {
            res.type = 'select'
          } else if (res.type === 'checkbox') {
            res.type = 'multiselect'
          } else if (res.type === 'datetime') {
            res.type = 'date'
          }
        }
        if (res.field && keys.includes(res.field.toLowerCase())) {
          notification.warning({
            top: 92,
            message: '搜索字段已存在!',
            duration: 5
          })
          return
        }
        config.search.push(res)
      } else if (type === 'cardcell') {
        config.subcards.push(res)
      }
      this.props.updateConfig(config)
      this.setState({visible: false})
      notification.success({
        top: 92,
        message: '粘贴成功!',
        duration: 2
      })
    })
  }
  render() {
    const { visible } = this.state
    return (
      <div style={{display: 'inline-block'}}>
        <Icon type="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} />
        <Modal
          title="粘贴"
          visible={visible}
          width={600}
          maskClosable={false}
          onOk={this.pasteSubmit}
          onCancel={() => {this.setState({visible: false})}}
          destroyOnClose
        >
          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
        </Modal>
      </div>
    )
  }
}
export default PasteController
src/menu/components/share/pastecomponent/index.scss
src/menu/components/table/normal-table/index.jsx
@@ -18,6 +18,8 @@
const SearchComponent = asyncComponent(() => import('@/templates/sharecomponent/searchcomponent'))
const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const ColumnComponent = asyncComponent(() => import('./columns'))
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
@@ -328,6 +330,8 @@
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <CopyComponent type="normaltable" card={card}/>
            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
src/menu/components/tabs/antv-tabs/index.jsx
@@ -15,6 +15,8 @@
import './index.scss'
const SettingComponent = asyncIconComponent(() => import('../tabsetting'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteController = asyncIconComponent(() => import('@/menu/pastecontroller'))
const TabLabelComponent = asyncComponent(() => import('../tablabelform'))
const TabComponents = asyncComponent(() => import('../tabcomponents'))
@@ -238,6 +240,19 @@
    this.props.updateConfig(tabs)
  }
  insert = (item, tab) => {
    let tabs = fromJS(this.state.tabs).toJS()
    tabs.subtabs.forEach(stab => {
      if (stab.uuid === tab.uuid) {
        stab.components.push(item)
      }
    })
    this.setState({tabs})
    this.props.updateConfig(tabs)
  }
  render() {
    const { tabs, dict, labelvisible, editab } = this.state
@@ -249,6 +264,7 @@
              <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                <div className="mk-popover-control">
                  <Icon className="edit" title="edit" type="edit" onClick={() => this.editTab(tab)} />
                  <PasteController type="tab" Tab={tab} insert={this.insert} />
                  <Icon className="close" title="delete" type="close" onClick={() => this.delTab(tab)} />
                </div>
              } trigger="hover">
@@ -263,6 +279,7 @@
              <div className="mk-popover-control">
                <Icon className="plus" title="添加标签" type="plus" onClick={this.tabAdd} />
                <SettingComponent config={tabs} updateConfig={this.updateComponent} />
                <CopyComponent type="tabs" card={tabs}/>
                <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
                <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(tabs.uuid)} />
              </div>
src/menu/pastecontroller/index.jsx
New file
@@ -0,0 +1,193 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Icon, Modal, Button, notification } from 'antd'
import Utils from '@/utils/utils.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
class PasteController extends Component {
  static propTpyes = {
    type: PropTypes.any,        // 组件类型
    Tab: PropTypes.any,         // 标签,添加菜单组件时为空
    insert: PropTypes.func
  }
  state = {
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  resetconfig = (item, Tab) => {
    item.uuid = Utils.getuuid()
    item.floor = Tab ? (Tab.floor + 1) : 1
    if (Tab) {
      item.tabId = Tab.uuid
      item.parentId = Tab.parentId
    }
    if (item.type === 'tabs') {
      item.subtabs.forEach(tab => {
        tab.uuid = Utils.getuuid()
        tab.parentId = item.uuid
        if (item.floor >= 3) {
          tab.components = tab.components.filter(cell => cell.type !== 'tabs')
        }
        tab.components = tab.components.map(cell => {
          cell = this.resetconfig(cell, tab)
          return cell
        })
      })
    } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
      item.subcards.forEach(card => {
        card.uuid = Utils.getuuid()
        if (card.elements) {
          card.elements = card.elements.map(cell => {
            cell.uuid = Utils.getuuid()
            return cell
          })
        }
        if (card.backElements) {
          card.backElements = card.backElements.map(cell => {
            cell.uuid = Utils.getuuid()
            return cell
          })
        }
      })
    } else if (item.type === 'table' && item.subtype === 'normaltable' && item.cols) {
      let loopCol = (col) => {
        col.subcols = col.subcols.map(c => {
          c.uuid = Utils.getuuid()
          if (c.type === 'colspan' && c.subcols) {
            c = loopCol(c)
          } else if (c.type === 'custom' && c.elements) {
            c.elements = c.elements.map(cell => {
              cell.uuid = Utils.getuuid()
              return cell
            })
          } else if (c.type === 'action' && c.elements) {
            c.elements = c.elements.map(cell => {
              cell.uuid = Utils.getuuid()
              return cell
            })
          }
          return c
        })
        return col
      }
      item.cols = item.cols.map(col => {
        col.uuid = Utils.getuuid()
        if (col.type === 'colspan' && col.subcols) {
          col = loopCol(col)
        } else if (col.type === 'custom' && col.elements) {
          col.elements = col.elements.map(cell => {
            cell.uuid = Utils.getuuid()
            return cell
          })
        } else if (col.type === 'action' && col.elements) {
          col.elements = col.elements.map(cell => {
            cell.uuid = Utils.getuuid()
            return cell
          })
        }
        return col
      })
    }
    if (item.btnlog) {
      item.btnlog = []
    }
    if (item.action) {
      item.action = item.action.map(cell => {
        cell.uuid = Utils.getuuid()
        return cell
      })
    }
    if (item.search) {
      item.search = item.search.map(cell => {
        cell.uuid = Utils.getuuid()
        return cell
      })
    }
    if (item.columns) {
      item.columns = item.columns.map(cell => {
        cell.uuid = Utils.getuuid()
        return cell
      })
    }
    return item
  }
  pasteSubmit = () => {
    const { Tab } = this.props
    this.pasteFormRef.handleConfirm().then(res => {
      if (!['tabs', 'datacard', 'propcard', 'mainsearch', 'normaltable', 'tablecard', 'line', 'bar', 'pie'].includes(res.copyType)) {
        notification.warning({
          top: 92,
          message: '配置信息格式错误!',
          duration: 5
        })
        return
      } else if (Tab && Tab.floor === 3 && res.type === 'tabs') {
        notification.warning({
          top: 92,
          message: '标签页最多为三重结构!',
          duration: 5
        })
        return
      }
      res = this.resetconfig(res, Tab)
      delete res.copyType
      this.props.insert(res, Tab)
      this.setState({visible: false})
      notification.success({
        top: 92,
        message: '粘贴成功!',
        duration: 2
      })
    })
  }
  render() {
    const { type } = this.props
    const { visible } = this.state
    return (
      <div style={{display: 'inline-block'}}>
        {type !== 'menu' ? <Icon type="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} /> : null}
        {type === 'menu' ? <Button type="link" style={{padding: '5px'}} icon="snippets" onClick={() => {this.setState({visible: true})}}>粘贴</Button> : null}
        <Modal
          title="粘贴"
          visible={visible}
          width={600}
          maskClosable={false}
          onOk={this.pasteSubmit}
          onCancel={() => {this.setState({visible: false})}}
          destroyOnClose
        >
          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
        </Modal>
      </div>
    )
  }
}
export default PasteController
src/menu/pastecontroller/index.scss
src/templates/zshare/editcomponent/index.jsx
@@ -312,7 +312,7 @@
          onCancel={() => {this.setState({pasteVisible: false})}}
          destroyOnClose
        >
          <PasteForm dict={dict} wrappedComponentRef={(inst) => this.pasteFormRef = inst}/>
          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst}/>
        </Modal>
      </div>
    )
src/templates/zshare/pasteform/index.jsx
@@ -1,14 +1,13 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, notification } from 'antd'
import Utils from '@/utils/utils.js'
import './index.scss'
const { TextArea } = Input
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object     // 字典项
    inputSubmit: PropTypes.func // 回车事件
  }
  componentDidMount () {
@@ -38,10 +37,6 @@
              duration: 5
            })
            _config = ''
          }
          if (_config && _config.uuid) { // 每次粘贴时更新ID,防止重复粘贴时id重复
            _config.uuid = Utils.getuuid()
          }
          if (_config) {
@@ -76,10 +71,10 @@
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '配置信息!'
                    message: '请输入配置信息!'
                  }
                ]
              })(<TextArea autoSize={{ minRows: 6, maxRows: 6 }} />)}
              })(<TextArea autoSize={{ minRows: 6, maxRows: 6 }} onPressEnter={() => this.props.inputSubmit && this.props.inputSubmit()}/>)}
            </Form.Item>
          </Col>
        </Row>
src/views/menudesign/index.jsx
@@ -30,6 +30,7 @@
const SourceWrap = asyncComponent(() => import('@/menu/modelsource'))
const MenuShell = asyncComponent(() => import('@/menu/menushell'))
const BgController = asyncComponent(() => import('@/menu/bgcontroller'))
const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
const PaddingController = asyncComponent(() => import('@/menu/padcontroller'))
const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller'))
@@ -48,6 +49,7 @@
    MenuNo: '',
    tableFields: [],
    delButtons: [],
    copyButtons: [],
    activeKey: 'basedata',
    menuloading: false,
    oriConfig: null,
@@ -85,6 +87,7 @@
  componentDidMount () {
    MKEmitter.addListener('delButtons', this.delButtons)
    MKEmitter.addListener('copyButtons', this.copyButtons)
    MKEmitter.addListener('changePopview', this.initPopview)
  }
@@ -96,11 +99,15 @@
      return
    }
    MKEmitter.removeListener('delButtons', this.delButtons)
    MKEmitter.removeListener('copyButtons', this.copyButtons)
    MKEmitter.removeListener('changePopview', this.initPopview)
  }
  delButtons = (items) => {
    this.setState({delButtons: [...this.state.delButtons, ...items]})
  }
  copyButtons = (items) => {
    this.setState({copyButtons: [...this.state.copyButtons, ...items]})
  }
  initPopview = (card, btn) => {
@@ -608,6 +615,15 @@
    this.props.modifyCustomMenu(config)
  }
  insert = (item) => {
    let config = fromJS(this.state.config).toJS()
    config.components.push(item)
    this.setState({config})
    this.props.modifyCustomMenu(config)
  }
  /**
   * @description 更新常用表信息,快捷添加后更新配置信息
   */
@@ -677,6 +693,7 @@
                  <div> {config && config.MenuName} </div>
                } bordered={false} extra={
                  <div>
                    <PasteController type="menu" Tab={null} insert={this.insert} />
                    {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={menuloading}>{dict['mob.save']}</Button>
                    <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>