From 9f3a0655391c42dc7fb9a3cfa6d8fc4ca935bd9d Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期二, 29 十二月 2020 18:29:37 +0800
Subject: [PATCH] 2020-12-29

---
 src/menu/components/share/pastecomponent/index.jsx          |  175 +++++++++++++++++++
 src/menu/components/card/table-card/index.jsx               |    9 
 src/templates/zshare/pasteform/index.jsx                    |   11 
 src/menu/components/card/cardcomponent/index.jsx            |   14 +
 src/menu/components/share/pastecomponent/index.scss         |    0 
 src/menu/pastecontroller/index.jsx                          |  193 +++++++++++++++++++++
 src/menu/components/card/data-card/index.jsx                |    4 
 src/menu/components/chart/antv-pie/index.jsx                |    4 
 src/menu/components/search/main-search/index.jsx            |    4 
 src/templates/zshare/editcomponent/index.jsx                |    2 
 src/menu/components/chart/antv-bar/index.jsx                |    4 
 src/menu/pastecontroller/index.scss                         |    0 
 src/menu/components/card/table-card/cardcomponent/index.jsx |    5 
 src/menu/components/share/copycomponent/index.jsx           |   46 +++++
 src/menu/components/card/prop-card/index.jsx                |   29 ++
 src/menu/components/table/normal-table/index.jsx            |    4 
 src/menu/components/share/copycomponent/index.scss          |    0 
 src/menu/components/tabs/antv-tabs/index.jsx                |   17 +
 src/views/menudesign/index.jsx                              |   17 +
 19 files changed, 521 insertions(+), 17 deletions(-)

diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index 1fb88ef..b16e051 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/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>
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index aec0a96..95244bc 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/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)} />
diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx
index aefe5b6..0040e4d 100644
--- a/src/menu/components/card/prop-card/index.jsx
+++ b/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>
     )
   }
diff --git a/src/menu/components/card/table-card/cardcomponent/index.jsx b/src/menu/components/card/table-card/cardcomponent/index.jsx
index 7cf24f4..09b052e 100644
--- a/src/menu/components/card/table-card/cardcomponent/index.jsx
+++ b/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>
diff --git a/src/menu/components/card/table-card/index.jsx b/src/menu/components/card/table-card/index.jsx
index eae5304..7486c33 100644
--- a/src/menu/components/card/table-card/index.jsx
+++ b/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>
diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx
index 14f13f7..95f9131 100644
--- a/src/menu/components/chart/antv-bar/index.jsx
+++ b/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)} />
diff --git a/src/menu/components/chart/antv-pie/index.jsx b/src/menu/components/chart/antv-pie/index.jsx
index 3535bbb..b5d947d 100644
--- a/src/menu/components/chart/antv-pie/index.jsx
+++ b/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)} />
diff --git a/src/menu/components/search/main-search/index.jsx b/src/menu/components/search/main-search/index.jsx
index 87bbadc..12b5278 100644
--- a/src/menu/components/search/main-search/index.jsx
+++ b/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>
diff --git a/src/menu/components/share/copycomponent/index.jsx b/src/menu/components/share/copycomponent/index.jsx
new file mode 100644
index 0000000..a4c90ed
--- /dev/null
+++ b/src/menu/components/share/copycomponent/index.jsx
@@ -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
\ No newline at end of file
diff --git a/src/menu/components/share/copycomponent/index.scss b/src/menu/components/share/copycomponent/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/components/share/copycomponent/index.scss
diff --git a/src/menu/components/share/pastecomponent/index.jsx b/src/menu/components/share/pastecomponent/index.jsx
new file mode 100644
index 0000000..95ffb34
--- /dev/null
+++ b/src/menu/components/share/pastecomponent/index.jsx
@@ -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
\ No newline at end of file
diff --git a/src/menu/components/share/pastecomponent/index.scss b/src/menu/components/share/pastecomponent/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/components/share/pastecomponent/index.scss
diff --git a/src/menu/components/table/normal-table/index.jsx b/src/menu/components/table/normal-table/index.jsx
index 7d72415..fbf625e 100644
--- a/src/menu/components/table/normal-table/index.jsx
+++ b/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)} />
diff --git a/src/menu/components/tabs/antv-tabs/index.jsx b/src/menu/components/tabs/antv-tabs/index.jsx
index 720b8b4..7aaaeef 100644
--- a/src/menu/components/tabs/antv-tabs/index.jsx
+++ b/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>
diff --git a/src/menu/pastecontroller/index.jsx b/src/menu/pastecontroller/index.jsx
new file mode 100644
index 0000000..1578179
--- /dev/null
+++ b/src/menu/pastecontroller/index.jsx
@@ -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
\ No newline at end of file
diff --git a/src/menu/pastecontroller/index.scss b/src/menu/pastecontroller/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/pastecontroller/index.scss
diff --git a/src/templates/zshare/editcomponent/index.jsx b/src/templates/zshare/editcomponent/index.jsx
index 18bc492..769e66a 100644
--- a/src/templates/zshare/editcomponent/index.jsx
+++ b/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>
     )
diff --git a/src/templates/zshare/pasteform/index.jsx b/src/templates/zshare/pasteform/index.jsx
index b843b94..016a03f 100644
--- a/src/templates/zshare/pasteform/index.jsx
+++ b/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) { // 姣忔绮樿创鏃舵洿鏂癐D锛岄槻姝㈤噸澶嶇矘璐存椂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>
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index ab016ad..dd9c02a 100644
--- a/src/views/menudesign/index.jsx
+++ b/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>

--
Gitblit v1.8.0