From 3cbad93c94c39730e45600efeabdfebcd424c2cc Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期四, 14 一月 2021 19:00:19 +0800
Subject: [PATCH] 2021-01-14

---
 src/menu/components/chart/antv-bar/chartcompile/index.jsx       |    2 
 src/menu/components/share/logcomponent/index.jsx                |    4 
 src/views/printTemplate/index.jsx                               |   74 ++++
 src/views/printTemplate/index.scss                              |   28 +
 src/menu/components/card/cardcellcomponent/dragaction/index.jsx |    8 
 src/menu/components/share/usercomponent/index.scss              |    7 
 src/tabviews/zshare/settingcomponent/index.jsx                  |    8 
 src/menu/components/share/actioncomponent/dragaction/index.jsx  |    8 
 src/menu/components/group/groupsetting/index.jsx                |    2 
 src/menu/components/card/data-card/wrapsetting/index.jsx        |    2 
 src/views/menudesign/index.jsx                                  |  226 ++++++++++++--
 src/menu/components/share/usercomponent/settingform/index.jsx   |   83 +++++
 src/menu/components/share/usercomponent/index.jsx               |  117 +++++++
 src/menu/components/share/pastecomponent/index.jsx              |   81 +++-
 src/menu/components/chart/antv-pie/chartcompile/index.jsx       |    2 
 src/menu/components/share/usercomponent/settingform/index.scss  |    8 
 src/menu/pastecontroller/index.jsx                              |   67 +++-
 src/menu/components/card/data-card/index.jsx                    |   81 +++--
 src/menu/components/chart/antv-pie/index.jsx                    |    5 
 src/menu/modelsource/option.jsx                                 |    4 
 src/views/login/index.scss                                      |    3 
 src/menu/components/table/normal-table/index.jsx                |    2 
 src/tabviews/zshare/settingcomponent/editTable/index.jsx        |    4 
 src/menu/components/table/normal-table/columns/index.jsx        |    4 
 src/menu/modelsource/index.jsx                                  |   12 
 src/menu/modelsource/dragsource/index.scss                      |    5 
 src/menu/popview/index.jsx                                      |   42 ++
 27 files changed, 741 insertions(+), 148 deletions(-)

diff --git a/src/menu/components/card/cardcellcomponent/dragaction/index.jsx b/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
index fdd2796..c90814c 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
@@ -38,14 +38,16 @@
     let copycard = fromJS(card).toJS()
     let _cards = fromJS(cards).toJS()
 
-    copycard.uuid = Utils.getuuid()
     copycard.copyType = 'customCardElement'
     copycard.focus = true
 
-    let _val = ''
+    let _val = fromJS(copycard).toJS()
+
+    copycard.uuid = Utils.getuuid()
+    copycard.originCard = card
 
     try {
-      _val = window.btoa(window.encodeURIComponent(JSON.stringify(copycard)))
+      _val = window.btoa(window.encodeURIComponent(JSON.stringify(_val)))
     } catch {
       console.warn('Stringify Failure')
       _val = ''
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index ec36bb8..5ced615 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/src/menu/components/card/data-card/index.jsx
@@ -18,6 +18,7 @@
 const CardComponent = asyncComponent(() => import('../cardcomponent'))
 const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
 const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
 const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
 const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
@@ -41,37 +42,6 @@
     const { card } = this.props
 
     if (card.isNew) {
-      let subcards = null
-
-      if (card.config) {
-        subcards = JSON.parse(card.config)
-        subcards = subcards.map(scard => {
-          scard.uuid = Utils.getuuid()
-          scard.elements = scard.elements.map(elem => {
-            elem.uuid = Utils.getuuid()
-            return elem
-          })
-          scard.backElements = scard.backElements.map(elem => {
-            elem.uuid = Utils.getuuid()
-            return elem
-          })
-          return scard
-        })
-      } else {
-        subcards = [{
-          uuid: Utils.getuuid(),
-          setting: { width: 6, type: 'simple'},
-          style: {
-            borderWidth: '1px', borderColor: '#e8e8e8',
-            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
-            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
-          },
-          backStyle: {},
-          elements: [],
-          backElements: []
-        }]
-      }
-
       let _card = {
         uuid: card.uuid,
         type: card.type,
@@ -93,8 +63,54 @@
         scripts: [],
         action: [],
         btnlog: [],
-        subcards: subcards
+        subcards: [{
+          uuid: Utils.getuuid(),
+          setting: { width: 6, type: 'simple'},
+          style: {
+            borderWidth: '1px', borderColor: '#e8e8e8',
+            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+          },
+          backStyle: {},
+          elements: [],
+          backElements: []
+        }]
       }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.setting = config.setting
+        _card.wrap = config.wrap
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+
+        _card.subcards = config.subcards.map(scard => {
+          scard.uuid = Utils.getuuid()
+          scard.elements = scard.elements.map(elem => {
+            elem.uuid = Utils.getuuid()
+            return elem
+          })
+          scard.backElements = scard.backElements.map(elem => {
+            elem.uuid = Utils.getuuid()
+            return elem
+          })
+          return scard
+        })
+        _card.columns = config.columns.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+        _card.scripts = config.scripts.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+        _card.action = config.action.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+      }
+
       this.setState({
         card: _card
       })
@@ -394,6 +410,7 @@
             <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} />
+            <UserComponent config={card}/>
             <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
             <SettingComponent config={card} updateConfig={this.updateComponent} />
           </div>
diff --git a/src/menu/components/card/data-card/wrapsetting/index.jsx b/src/menu/components/card/data-card/wrapsetting/index.jsx
index b55aef2..eca0dc3 100644
--- a/src/menu/components/card/data-card/wrapsetting/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/index.jsx
@@ -55,7 +55,7 @@
 
     return (
       <div className="model-menu-setting-wrap">
-        <Icon type="edit" onClick={() => this.editDataSource()} />
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
         <Modal
           wrapClassName="popview-modal"
           title={config.type === 'table' ? '琛ㄦ牸璁剧疆' : '鍗$墖璁剧疆'}
diff --git a/src/menu/components/chart/antv-bar/chartcompile/index.jsx b/src/menu/components/chart/antv-bar/chartcompile/index.jsx
index 97c1471..db034f3 100644
--- a/src/menu/components/chart/antv-bar/chartcompile/index.jsx
+++ b/src/menu/components/chart/antv-bar/chartcompile/index.jsx
@@ -492,7 +492,7 @@
 
     return (
       <div className="line-chart-drawer-form">
-        <Icon type="edit" onClick={this.showDrawer} />
+        <Icon type="edit" title="缂栬緫" onClick={this.showDrawer} />
         <Modal
           wrapClassName="popview-modal menu-chart-edit-modal"
           title="鍥捐〃缂栬緫"
diff --git a/src/menu/components/chart/antv-pie/chartcompile/index.jsx b/src/menu/components/chart/antv-pie/chartcompile/index.jsx
index ad68d31..2152dde 100644
--- a/src/menu/components/chart/antv-pie/chartcompile/index.jsx
+++ b/src/menu/components/chart/antv-pie/chartcompile/index.jsx
@@ -318,7 +318,7 @@
 
     return (
       <div className="line-chart-drawer-form">
-        <Icon type="edit" onClick={this.showDrawer} />
+        <Icon type="edit" title="缂栬緫" onClick={this.showDrawer} />
         <Modal
           wrapClassName="popview-modal menu-chart-edit-modal"
           title="鍥捐〃缂栬緫"
diff --git a/src/menu/components/chart/antv-pie/index.jsx b/src/menu/components/chart/antv-pie/index.jsx
index 881fc39..c17b950 100644
--- a/src/menu/components/chart/antv-pie/index.jsx
+++ b/src/menu/components/chart/antv-pie/index.jsx
@@ -392,11 +392,6 @@
     let _card = {...card, style}
 
     this.updateComponent(_card)
-    // this.setState({
-    //   card: _card
-    // })
-    
-    // this.props.updateConfig(_card)
   }
 
   handleLog = (type, logs, item) => {
diff --git a/src/menu/components/group/groupsetting/index.jsx b/src/menu/components/group/groupsetting/index.jsx
index b913fc8..7cb078c 100644
--- a/src/menu/components/group/groupsetting/index.jsx
+++ b/src/menu/components/group/groupsetting/index.jsx
@@ -54,7 +54,7 @@
 
     return (
       <div className="model-menu-setting-wrap">
-        <Icon type="edit" onClick={() => this.editDataSource()} />
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
         <Modal
           wrapClassName="popview-modal"
           title={'鏍囩椤甸厤缃�'}
diff --git a/src/menu/components/share/actioncomponent/dragaction/index.jsx b/src/menu/components/share/actioncomponent/dragaction/index.jsx
index 08044d4..afa3b70 100644
--- a/src/menu/components/share/actioncomponent/dragaction/index.jsx
+++ b/src/menu/components/share/actioncomponent/dragaction/index.jsx
@@ -54,19 +54,19 @@
 
   const copyCard = id => {
     const { card } = findCard(id)
+
     let copycard = fromJS(card).toJS()
 
-    copycard.uuid = Utils.getuuid()
     copycard.origin = false
     copycard.copyType = 'action'
     copycard.focus = true
 
-    copycard.originCard = card
-
     let _val = fromJS(copycard).toJS()
 
+    copycard.uuid = Utils.getuuid()
+    copycard.originCard = card
+
     try {
-      _val.uuid = Utils.getuuid()
       _val = window.btoa(window.encodeURIComponent(JSON.stringify(_val)))
     } catch {
       console.warn('Stringify Failure')
diff --git a/src/menu/components/share/logcomponent/index.jsx b/src/menu/components/share/logcomponent/index.jsx
index dd2112b..573aced 100644
--- a/src/menu/components/share/logcomponent/index.jsx
+++ b/src/menu/components/share/logcomponent/index.jsx
@@ -5,6 +5,7 @@
 
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
+import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 const { confirm } = Modal
@@ -71,6 +72,7 @@
     const data = this.state.data.filter(d => d.uuid !== item.uuid)
 
     this.setState({data})
+    MKEmitter.emit('thawButtons', item.uuid)
     this.props.handlelog('revert', data, item)
   }
 
@@ -99,7 +101,7 @@
 
     return (
       <div className="btn-log-wrap">
-        <Icon type="rollback" onClick={this.trigger} />
+        <Icon type="rollback" title="瑙i櫎鍐荤粨" onClick={this.trigger} />
         <Modal
           wrapClassName="popview-modal"
           title="鍘嗗彶璁板綍"
diff --git a/src/menu/components/share/pastecomponent/index.jsx b/src/menu/components/share/pastecomponent/index.jsx
index 95ffb34..2d12bb3 100644
--- a/src/menu/components/share/pastecomponent/index.jsx
+++ b/src/menu/components/share/pastecomponent/index.jsx
@@ -4,6 +4,7 @@
 import { Icon, Modal, notification } from 'antd'
 
 import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
@@ -23,8 +24,19 @@
     this.setState({visible: true})
   }
 
-  resetconfig = (item) => {
-    item.uuid = Utils.getuuid()
+  resetconfig = (item, copyBtns) => {
+    let _uuid = Utils.getuuid()
+
+    if (item.OpenType === 'popview') {
+      let _cell = fromJS(item).toJS()
+      _cell.$originUuid = _cell.uuid
+      _cell.uuid = _uuid
+      copyBtns.set(_uuid, _cell)
+    }
+
+    if (item.uuid) {
+      item.uuid = _uuid
+    }
 
     if (item.copyType === 'cardcell') {
       item.setting = item.setting || {}
@@ -42,7 +54,7 @@
           return cell
         })
       }
-    } else if (item.copyType === 'table') {
+    } else if (item.copyType === 'cols') {
       let loopCol = (col) => {
         col.subcols = col.subcols.map(c => {
           c.uuid = Utils.getuuid()
@@ -54,11 +66,6 @@
               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
         })
@@ -66,19 +73,30 @@
         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
-        })
-      }
+      item.cols = item.cols.map(_item => {
+        _item.uuid = Utils.getuuid()
+        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 => {
+            let _uuid = Utils.getuuid()
+            if (cell.OpenType === 'popview') {
+              let _cell = fromJS(cell).toJS()
+              _cell.$originUuid = _cell.uuid
+              _cell.uuid = _uuid
+              copyBtns.set(_uuid, _cell)
+            }
+            cell.uuid = _uuid
+            return cell
+          })
+        }
+        return _item
+      })
     }
 
     return item
@@ -98,15 +116,22 @@
 
       let type = res.copyType
       let config = fromJS(this.props.config).toJS()
+      let copyBtns = new Map()
 
-      res = this.resetconfig(res)
+      res = this.resetconfig(res, copyBtns)
       delete res.copyType
+
+      copyBtns = [...copyBtns.values()]
+
+      if (copyBtns.length > 0) {
+        MKEmitter.emit('copyButtons', copyBtns)
+      }
 
       if (type === 'action') {
         config.action = config.action || []
         config.action = config.action.filter(item => !item.origin)
 
-        config.action.push(res)
+        MKEmitter.emit('addButton', config.uuid, res)
       } else if (type === 'search' || type === 'form') {
         config.search = config.search || []
         config.search = config.search.filter(item => !item.origin)
@@ -137,6 +162,16 @@
         config.search.push(res)
       } else if (type === 'cardcell') {
         config.subcards.push(res)
+      } else if (type === 'cols') {
+        config.cols = config.cols.filter(col => !col.origin)
+
+        let keys = config.cols.map(col => (col.field || '$empty'))
+
+        res.cols.forEach(col => {
+          if (!keys.includes(col.field)) {
+            config.cols.push(col)
+          }
+        })
       }
 
       this.props.updateConfig(config)
diff --git a/src/menu/components/share/usercomponent/index.jsx b/src/menu/components/share/usercomponent/index.jsx
new file mode 100644
index 0000000..ab376c6
--- /dev/null
+++ b/src/menu/components/share/usercomponent/index.jsx
@@ -0,0 +1,117 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal, notification } from 'antd'
+import html2canvas from 'html2canvas'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import UserForm from './settingform'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    btnlog: PropTypes.array,
+    handlelog: PropTypes.func
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    loading: false
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  trigger = () => {
+    this.setState({
+      visible: true,
+      loading: false
+    })
+  }
+
+  submit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+      this.setState({loading: true})
+      document.getElementsByClassName('menu-view')[0].classList.add('saving')
+
+      html2canvas(document.getElementById(config.uuid)).then(canvas => {
+        let img = canvas.toDataURL('image/png') // 鑾峰彇鐢熸垚鐨勫浘鐗�
+        Api.fileuploadbase64(img, 'cloud').then(result => {
+          if (result.status) {
+            Api.getSystemConfig({
+              func: 's_custom_components_adduptdel',
+              c_id: config.uuid,
+              images: Utils.getcloudurl(result.Images),
+              c_name: res.name,
+              long_param: window.btoa(window.encodeURIComponent(JSON.stringify(config))),
+              del_type: ''
+            }).then(response => {
+              if (response.status) {
+                this.setState({loading: false, visible: false})
+                notification.success({
+                  top: 92,
+                  message: '淇濆瓨鎴愬姛',
+                  duration: 2
+                })
+                document.getElementsByClassName('menu-view')[0].classList.remove('saving')
+                MKEmitter.emit('updateCustomComponent')
+              } else {
+                this.setState({loading: false})
+                notification.warning({
+                  top: 92,
+                  message: response.message,
+                  duration: 5
+                })
+              }
+            })
+          } else {
+            this.setState({loading: false})
+            notification.warning({
+              top: 92,
+              message: result.ErrMesg,
+              duration: 5
+            })
+          }
+        })
+      })
+    })
+  }
+
+  cancel = () => {
+    this.setState({ visible: false })
+    document.getElementsByClassName('menu-view')[0].classList.remove('saving')
+  }
+
+  render () {
+    const { visible, dict, loading } = this.state
+
+    return (
+      <div className="user-component-wrap">
+        <Icon type="user" title="鐢熸垚鑷畾涔夌粍浠�" onClick={this.trigger} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="鑷畾涔夌粍浠�"
+          visible={visible}
+          width={500}
+          maskClosable={false}
+          confirmLoading={loading}
+          onOk={this.submit}
+          onCancel={this.cancel}
+          destroyOnClose
+        >
+          <UserForm dict={dict} inputSubmit={this.submit} wrappedComponentRef={(inst) => this.verifyRef = inst}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/menu/components/share/usercomponent/index.scss b/src/menu/components/share/usercomponent/index.scss
new file mode 100644
index 0000000..cdfe23d
--- /dev/null
+++ b/src/menu/components/share/usercomponent/index.scss
@@ -0,0 +1,7 @@
+.user-component-wrap {
+  display: inline-block;
+
+  >.anticon-user {
+    color: purple;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/share/usercomponent/settingform/index.jsx b/src/menu/components/share/usercomponent/settingform/index.jsx
new file mode 100644
index 0000000..7c45ae5
--- /dev/null
+++ b/src/menu/components/share/usercomponent/settingform/index.jsx
@@ -0,0 +1,83 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Tooltip, Icon } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,       // 瀛楀吀椤�
+    inputSubmit: PropTypes.func   // 鍥炶溅浜嬩欢
+  }
+
+  state = {}
+
+  UNSAFE_componentWillMount () {
+
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={22}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit}/>)}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/menu/components/share/usercomponent/settingform/index.scss b/src/menu/components/share/usercomponent/settingform/index.scss
new file mode 100644
index 0000000..c53f945
--- /dev/null
+++ b/src/menu/components/share/usercomponent/settingform/index.scss
@@ -0,0 +1,8 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/table/normal-table/columns/index.jsx b/src/menu/components/table/normal-table/columns/index.jsx
index ec78012..d779374 100644
--- a/src/menu/components/table/normal-table/columns/index.jsx
+++ b/src/menu/components/table/normal-table/columns/index.jsx
@@ -395,8 +395,8 @@
 
     let oInput = document.createElement('input')
     let val = {
-      copyType: 'columns',
-      columns: columns
+      copyType: 'cols',
+      cols: columns.filter(col => !col.origin)
     }
 
     oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
diff --git a/src/menu/components/table/normal-table/index.jsx b/src/menu/components/table/normal-table/index.jsx
index ac84f2b..dcd3573 100644
--- a/src/menu/components/table/normal-table/index.jsx
+++ b/src/menu/components/table/normal-table/index.jsx
@@ -338,7 +338,7 @@
             <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} />
+            <PasteComponent config={card} options={['action', 'search', 'form', 'cols']} 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/modelsource/dragsource/index.scss b/src/menu/modelsource/dragsource/index.scss
index 59efc99..a362607 100644
--- a/src/menu/modelsource/dragsource/index.scss
+++ b/src/menu/modelsource/dragsource/index.scss
@@ -3,10 +3,7 @@
   width: 100%;
   margin-bottom: 15px;
   height: auto;
-
-  // background-size: cover;
-  // background-position: top center;
-  // background-repeat: no-repeat;
+  min-height: 70px;
 
   .property {
     font-size: 14px;
diff --git a/src/menu/modelsource/index.jsx b/src/menu/modelsource/index.jsx
index 91f4c24..21d2a4c 100644
--- a/src/menu/modelsource/index.jsx
+++ b/src/menu/modelsource/index.jsx
@@ -7,12 +7,18 @@
 
 class ModelSource extends Component {
   state = {
-    menuOptions: null
+    menuOptions: null,
   }
 
   UNSAFE_componentWillMount () {
-    const { MenuType } = this.props
-    let options = fromJS(menuOptions).toJS()
+    const { MenuType, components } = this.props
+    let options = []
+    
+    if (components) {
+      options = fromJS(components).toJS()
+    } else {
+      options = fromJS(menuOptions).toJS()
+    }
 
     options = options.filter(item => !item.forbid || !item.forbid.includes(MenuType))
 
diff --git a/src/menu/modelsource/option.jsx b/src/menu/modelsource/option.jsx
index 55940f9..a47720f 100644
--- a/src/menu/modelsource/option.jsx
+++ b/src/menu/modelsource/option.jsx
@@ -18,8 +18,8 @@
   { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '鏍囩椤�', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24, forbid: ['billPrint'] },
-  { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', config: `[{"uuid":"160135809128212dm7i29fim9ksto9od","setting":{"width":6},"style":{"paddingTop":"15px","marginTop":"4px","paddingRight":"15px","marginRight":"8px","marginLeft":"8px","backgroundColor":"rgba(255, 255, 255, 1)","borderColor":"#e8e8e8","paddingLeft":"15px","marginBottom":"4px","borderWidth":"1px","paddingBottom":"10px"},"backStyle":{},"elements":[{"datatype":"static","width":12,"marks":null,"height":1,"value":"鍏冲崟","style":{},"prefix":"","postfix":"","format":"","eleType":"text","uuid":"160231860159931untbea62sgokunc5s"},{"datatype":"static","width":12,"marks":null,"style":{"color":"rgba(250, 219, 20, 1)","textAlign":"right"},"btnstyle":{},"eleType":"icon","icon":"question-circle","field":"","uuid":"1602318768361nv8ql4t47sgcsn88b0u"},{"datatype":"static","width":24,"marks":null,"height":1,"innerHeight":36,"value":"100","style":{"fontSize":"24px","fontWeight":"500","color":"rgba(0, 0, 0, 1)"},"prefix":"","btnstyle":{},"postfix":"","format":"","eleType":"text","uuid":"1602318817884v70gtgb65ubnm8mbcvv"},{"color":"#1890ff","width":24,"marks":null,"maxValue":100,"style":{"color":"rgba(250, 140, 22, 1)","paddingTop":"20px","paddingBottom":"10px"},"btnstyle":{},"eleType":"slider","field":"int1","uuid":"16023188871233rkktuvpp1h077igrsu"},{"eleType":"splitline","width":24,"color":"#e8e8e8","uuid":"1602320017038n31bk9o831ggug0tu0b","marks":null,"style":{"marginTop":"10px","marginBottom":"10px"},"btnstyle":{}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"marginTop":"6px"},"prefix":"鍏冲崟","btnstyle":{},"postfix":"","format":"","eleType":"text","uuid":"1602320061243drd7lf3agvn04kgr175"}],"backElements":[]}]` },
-  { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', config: `[{"uuid":"1603681387259qaqf1127f72esmtchge","setting":{"width":6,"type":"simple"},"style":{"paddingTop":"15px","marginTop":"8px","paddingRight":"15px","marginRight":"8px","marginLeft":"8px","borderColor":"#e8e8e8","paddingLeft":"15px","marginBottom":"8px","borderWidth":"1px","paddingBottom":"15px"},"backStyle":{},"elements":[{"datatype":"static","width":12,"marks":null,"height":1,"value":"瓒呮椂宸ュ崟","style":{"color":"rgba(67, 67, 67, 0.51)"},"prefix":"","postfix":"","format":"","eleType":"text","uuid":"1603681402945qnkgm7q8cng65evn5ev"},{"eleType":"icon","datatype":"static","width":12,"icon":"question-circle","tooltip":"瓒呮椂宸ュ崟","uuid":"1603681473384i2crkbtofg4pu76k06a","marks":null,"style":{"textAlign":"right","color":"rgba(250, 219, 20, 1)"}},{"datatype":"static","width":24,"marks":null,"height":1,"innerHeight":36,"value":"100","style":{"fontSize":"24px","color":"rgba(0, 0, 0, 1)"},"prefix":"","postfix":"","format":"","eleType":"number","uuid":"1603681539870d704ufqf98kc6t7537t"},{"color":"rgba(250, 219, 20, 1)","datatype":"static","width":24,"marks":null,"maxValue":100,"value":50,"style":{"paddingTop":"10px","paddingBottom":"10px"},"eleType":"slider","uuid":"1603683067556mvupau0odvrtv45u7o8"},{"eleType":"splitline","width":24,"color":"#e8e8e8","uuid":"1603683117981t9k55k8an430fuppmci","marks":null,"style":{"paddingTop":"5px","paddingBottom":"5px"}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"color":"rgba(0, 0, 0, 0.65)","marginTop":"10px"},"prefix":"瓒呮椂宸ュ崟  ","postfix":"","format":"","eleType":"text","uuid":"1603683136553uvsmkfohkft9idbfkhu"}],"backElements":[]}]` },
+  { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', config: '' },
+  { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', config: '' },
   { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 },
   { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸', width: 12 },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�' },
diff --git a/src/menu/pastecontroller/index.jsx b/src/menu/pastecontroller/index.jsx
index a227bf1..f8061f3 100644
--- a/src/menu/pastecontroller/index.jsx
+++ b/src/menu/pastecontroller/index.jsx
@@ -1,8 +1,10 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
 import { Icon, Modal, Button, notification } from 'antd'
 
 import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
@@ -23,7 +25,7 @@
     this.setState({visible: true})
   }
 
-  resetconfig = (item, Tab, isgroup) => {
+  resetconfig = (item, Tab, isgroup, copyBtns) => {
     item.uuid = Utils.getuuid()
     item.floor = Tab ? (Tab.floor + 1) : 1
 
@@ -49,13 +51,13 @@
         }
 
         tab.components = tab.components.map(cell => {
-          cell = this.resetconfig(cell, tab)
+          cell = this.resetconfig(cell, tab, copyBtns)
           return cell
         })
       })
     } else if (item.type === 'group') {
-      item.components = item.components.forEach(cell => {
-        cell = this.resetconfig(cell, item, true)
+      item.components = item.components.map(cell => {
+        cell = this.resetconfig(cell, item, true, copyBtns)
         return cell
       })
     } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
@@ -66,7 +68,14 @@
             card.elements = card.elements.filter(b => b.OpenType !== 'popview' && b.OpenType !== 'funcbutton')
           }
           card.elements = card.elements.map(cell => {
-            cell.uuid = Utils.getuuid()
+            let _uuid = Utils.getuuid()
+            if (cell.OpenType === 'popview') {
+              let _cell = fromJS(cell).toJS()
+              _cell.$originUuid = _cell.uuid
+              _cell.uuid = _uuid
+              copyBtns.set(_uuid, _cell)
+            }
+            cell.uuid = _uuid
             return cell
           })
         }
@@ -75,7 +84,14 @@
             card.elements = card.elements.filter(b => b.OpenType !== 'popview' && b.OpenType !== 'funcbutton')
           }
           card.backElements = card.backElements.map(cell => {
-            cell.uuid = Utils.getuuid()
+            let _uuid = Utils.getuuid()
+            if (cell.OpenType === 'popview') {
+              let _cell = fromJS(cell).toJS()
+              _cell.$originUuid = _cell.uuid
+              _cell.uuid = _uuid
+              copyBtns.set(_uuid, _cell)
+            }
+            cell.uuid = _uuid
             return cell
           })
         }
@@ -88,14 +104,6 @@
           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) {
-            if (sessionStorage.getItem('editMenuType') === 'popview') {
-              c.elements = c.elements.filter(b => b.OpenType !== 'popview' && b.OpenType !== 'funcbutton')
-            }
             c.elements = c.elements.map(cell => {
               cell.uuid = Utils.getuuid()
               return cell
@@ -122,7 +130,14 @@
             col.elements = col.elements.filter(c => c.OpenType !== 'popview' && c.OpenType !== 'funcbutton')
           }
           col.elements = col.elements.map(cell => {
-            cell.uuid = Utils.getuuid()
+            let _uuid = Utils.getuuid()
+            if (cell.OpenType === 'popview') {
+              let _cell = fromJS(cell).toJS()
+              _cell.$originUuid = _cell.uuid
+              _cell.uuid = _uuid
+              copyBtns.set(_uuid, _cell)
+            }
+            cell.uuid = _uuid
             return cell
           })
         }
@@ -139,7 +154,14 @@
         item.action = item.action.filter(c => c.OpenType !== 'popview' && c.OpenType !== 'funcbutton')
       }
       item.action = item.action.map(cell => {
-        cell.uuid = Utils.getuuid()
+        let _uuid = Utils.getuuid()
+        if (cell.OpenType === 'popview') {
+          let _cell = fromJS(cell).toJS()
+          _cell.$originUuid = _cell.uuid
+          _cell.uuid = _uuid
+          copyBtns.set(_uuid, _cell)
+        }
+        cell.uuid = _uuid
         return cell
       })
     }
@@ -188,11 +210,20 @@
         return
       }
 
-      res = this.resetconfig(res, Tab, isgroup)
+      let copyBtns = new Map()
+
+      res = this.resetconfig(res, Tab, isgroup, copyBtns)
 
       delete res.copyType
-
+      
       this.props.insert(res, Tab)
+
+      copyBtns = [...copyBtns.values()]
+
+      if (copyBtns.length > 0) {
+        MKEmitter.emit('copyButtons', copyBtns)
+      }
+
       this.setState({visible: false})
 
       notification.success({
diff --git a/src/menu/popview/index.jsx b/src/menu/popview/index.jsx
index 59c0dcb..efb26ea 100644
--- a/src/menu/popview/index.jsx
+++ b/src/menu/popview/index.jsx
@@ -49,6 +49,7 @@
     oriConfig: null,
     openEdition: '',
     config: null,
+    customComponents: []
   }
 
   UNSAFE_componentWillMount() {
@@ -64,6 +65,8 @@
   componentDidMount () {
     MKEmitter.addListener('delButtons', this.delButtons)
     MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
+    MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent)
+    this.updateCustomComponent()
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -79,6 +82,40 @@
     }
     MKEmitter.removeListener('delButtons', this.delButtons)
     MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
+    MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent)
+  }
+
+  updateCustomComponent = () => {
+    Api.getSystemConfig({
+      func: 's_get_custom_components',
+      typecharone: ''
+    }).then(res => {
+      let coms = []
+      if (res.cus_list && res.cus_list.length > 0) {
+        res.cus_list.forEach(item => {
+          let config = ''
+
+          try {
+            config = JSON.parse(window.decodeURIComponent(window.atob(item.long_param)))
+          } catch (e) {
+            console.warn('Parse Failure')
+            config = ''
+          }
+
+          if (!config || !item.c_name) return
+
+          coms.push({
+            type: 'menu',
+            title: item.c_name,
+            url: item.images,
+            component: config.type,
+            subtype: config.subtype,
+            config
+          })
+        })
+      }
+      this.setState({customComponents: coms})
+    })
   }
 
   updateComponentStyle = (parentId, keys, style) => {
@@ -500,7 +537,7 @@
 
   render () {
     const { btn } = this.props
-    const { activeKey, MenuType, dict, config, menuloading } = this.state
+    const { activeKey, MenuType, dict, config, menuloading, customComponents } = this.state
 
     return (
       <DndProvider backend={HTML5Backend}>
@@ -518,6 +555,9 @@
               <Panel header={dict['mob.component']} key="component">
                 <SourceWrap MenuType={MenuType} />
               </Panel>
+              {customComponents && customComponents.length ? <Panel header="鑷畾涔夌粍浠�" key="cuscomponent">
+                <SourceWrap components={customComponents} MenuType={MenuType} />
+              </Panel> : null}
               <Panel header={'鑳屾櫙'} key="background">
                 {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
               </Panel>
diff --git a/src/tabviews/zshare/settingcomponent/editTable/index.jsx b/src/tabviews/zshare/settingcomponent/editTable/index.jsx
index e9a0b24..214f0ad 100644
--- a/src/tabviews/zshare/settingcomponent/editTable/index.jsx
+++ b/src/tabviews/zshare/settingcomponent/editTable/index.jsx
@@ -170,8 +170,8 @@
         children: []
       }
       Object.keys(shortkeycode).forEach(key => {
-        if (item === 'ctrl' && ['65', '67', '68', '86', '70', '72', '83'].includes(key)) return
-        if (item === 'alt' && key === '65') return
+        if (item === 'ctrl' && ['65', '67', '68', '69', '70', '71', '72', '74', '75', '76', '78', '79', '80', '82', '83', '84', '85', '86', '87', '88', '90'].includes(key)) return
+        if (item === 'alt' && ['65', '68', '69', '70'].includes(key)) return
 
         _op.children.push({
           value: +key,
diff --git a/src/tabviews/zshare/settingcomponent/index.jsx b/src/tabviews/zshare/settingcomponent/index.jsx
index 32f4eb9..e5820fb 100644
--- a/src/tabviews/zshare/settingcomponent/index.jsx
+++ b/src/tabviews/zshare/settingcomponent/index.jsx
@@ -361,9 +361,15 @@
         }
 
         socket.onerror = () => {
+          let tool = item.verify.linkUrl
+          if (item.verify.linkUrl === '127.0.0.1:13529') {
+            tool = '鏄庣閫氳缁勪欢'
+          } else if (item.verify.linkUrl === '127.0.0.1:13528') {
+            tool = 'CAINIAO鎵撳嵃缁勪欢'
+          }
           notification.warning({
             top: 92,
-            message: '鏃犳硶杩炴帴鍒�:' + item.verify.linkUrl,
+            message: '鏃犳硶杩炴帴鍒�: ' + tool,
             duration: 5
           })
         }
diff --git a/src/views/login/index.scss b/src/views/login/index.scss
index 38c9d1d..a54f936 100644
--- a/src/views/login/index.scss
+++ b/src/views/login/index.scss
@@ -22,6 +22,7 @@
       font-weight: 600;
       padding-left: 20px;
       font-family: "榛戜綋","瀹嬩綋",sans-serif,"Arial","Microsoft YaHei";
+      z-index: 1;
     }
   }
 
@@ -97,7 +98,7 @@
       min-width: 300px;
       border-radius: 5px;
       overflow: hidden;
-      border: 1px solid #e8e8e8;
+      border: 1px solid #bfbfbf;
 
       .form-item-wrap {
         padding: 0.6vw 1.6vw 1.6vw;
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index eee1ad2..04167a3 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -14,6 +14,7 @@
 import antdEnUS from 'antd/es/locale/en_US'
 import antdZhCN from 'antd/es/locale/zh_CN'
 import MKEmitter from '@/utils/events.js'
+import MenuUtils from '@/menu/utils/menuUtils.js'
 import asyncComponent from '@/utils/asyncComponent'
 import { modifyCustomMenu } from '@/store/action'
 
@@ -54,13 +55,15 @@
     tableFields: [],
     delButtons: [],
     copyButtons: [],
+    thawButtons: [],
     activeKey: 'basedata',
     menuloading: false,
     oriConfig: null,
     openEdition: '',
     config: null,
     popBtn: null,             // 寮圭獥鏍囩椤�
-    visible: false
+    visible: false,
+    customComponents: []
   }
 
   UNSAFE_componentWillMount() {
@@ -91,9 +94,12 @@
 
   componentDidMount () {
     MKEmitter.addListener('delButtons', this.delButtons)
+    MKEmitter.addListener('thawButtons', this.thawButtons)
     MKEmitter.addListener('copyButtons', this.copyButtons)
     MKEmitter.addListener('changePopview', this.initPopview)
     MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
+    MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent)
+    this.updateCustomComponent()
   }
 
   /**
@@ -104,9 +110,44 @@
       return
     }
     MKEmitter.removeListener('delButtons', this.delButtons)
+    MKEmitter.removeListener('thawButtons', this.thawButtons)
     MKEmitter.removeListener('copyButtons', this.copyButtons)
     MKEmitter.removeListener('changePopview', this.initPopview)
     MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
+    MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent)
+  }
+
+  updateCustomComponent = () => {
+    Api.getSystemConfig({
+      func: 's_get_custom_components',
+      typecharone: ''
+    }).then(res => {
+      let coms = []
+      if (res.cus_list && res.cus_list.length > 0) {
+        res.cus_list.forEach(item => {
+          let config = ''
+
+          try {
+            config = JSON.parse(window.decodeURIComponent(window.atob(item.long_param)))
+          } catch (e) {
+            console.warn('Parse Failure')
+            config = ''
+          }
+
+          if (!config || !item.c_name) return
+
+          coms.push({
+            type: 'menu',
+            title: item.c_name,
+            url: item.images,
+            component: config.type,
+            subtype: config.subtype,
+            config
+          })
+        })
+      }
+      this.setState({customComponents: coms})
+    })
   }
 
   updateComponentStyle = (parentId, keys, style) => {
@@ -131,10 +172,20 @@
   }
 
   delButtons = (items) => {
-    this.setState({delButtons: [...this.state.delButtons, ...items]})
+    const { copyButtons } = this.state
+
+    this.setState({
+      delButtons: [...this.state.delButtons, ...items],
+      copyButtons: copyButtons.filter(item => !items.includes(item.uuid))
+    })
   }
+
   copyButtons = (items) => {
     this.setState({copyButtons: [...this.state.copyButtons, ...items]})
+  }
+  
+  thawButtons = (item) => {
+    this.setState({thawButtons: [...this.state.thawButtons, item]})
   }
 
   initPopview = (card, btn) => {
@@ -161,7 +212,7 @@
   }
 
   handleBack = () => {
-    this.setState({popBtn: null, delButtons: []}, () => {
+    this.setState({popBtn: null, delButtons: [], copyButtons: []}, () => {
       sessionStorage.setItem('editMenuType', 'menu')
       this.props.modifyCustomMenu(this.state.config)
       this.setState({visible: false})
@@ -348,7 +399,7 @@
   }
 
   submitConfig = () => {
-    const { openEdition, MenuType, delButtons } = this.state
+    const { openEdition, MenuType, delButtons, copyButtons, thawButtons } = this.state
     let config = fromJS(this.state.config).toJS()
 
     if (MenuType === 'billPrint' && (!config.firstCount || !config.everyPCount)) {
@@ -418,9 +469,13 @@
       LText: []
     }
 
+    let btnIds = '' // 鐢ㄤ簬澶嶅埗鎸夐挳鐨勮繃婊�
     if (MenuType !== 'billPrint') {
       btnParam.LText = this.getMenuMessage()
       btnParam.LText = btnParam.LText.join(' union all ')
+
+      btnIds = btnParam.LText
+
       btnParam.LText = Utils.formatOptions(btnParam.LText)
       btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
       btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
@@ -432,7 +487,7 @@
       menuloading: true
     }, () => {
       new Promise(resolve => {
-        if (MenuType === 'billPrint') {
+        if (MenuType === 'billPrint') { // 鎵撳嵃鐢熸垚椤甸潰鏁堟灉鍥�
           html2canvas(document.getElementById('menu-shell-inner')).then(canvas => {
             let img = canvas.toDataURL('image/png') // 鑾峰彇鐢熸垚鐨勫浘鐗�
             Api.fileuploadbase64(img, 'cloud').then(result => {
@@ -452,9 +507,6 @@
                       message: response.message,
                       duration: 5
                     })
-                    this.setState({
-                      menuloading: false
-                    })
                     resolve(false)
                   }
                 })
@@ -464,9 +516,6 @@
                   message: result.ErrMesg,
                   duration: 5
                 })
-                this.setState({
-                  menuloading: false
-                })
                 resolve(false)
               }
             })
@@ -474,7 +523,7 @@
         } else {
           resolve(true)
         }
-      }).then(res => {
+      }).then(res => { // 鎸夐挳鍒犻櫎
         if (!res) return
 
         if (delButtons.length === 0) {
@@ -488,18 +537,9 @@
           }
           return Api.getSystemConfig(_param)
         }
-      }).then(res => {
+      }).then(res => { // 鎸夐挳瑙i櫎鍐荤粨
         if (!res) return
-
-        if (res.status) {
-          this.setState({
-            delButtons: []
-          })
-          return Api.getSystemConfig(param)
-        } else {
-          this.setState({
-            menuloading: false
-          })
+        if (!res.status) {
           notification.warning({
             top: 92,
             message: res.message,
@@ -507,7 +547,32 @@
           })
           return false
         }
-      }).then(res => {
+
+        let ids = thawButtons.filter(item => btnIds.indexOf(item) !== -1)
+        if (ids.length === 0) {
+          return {
+            status: true
+          }
+        } else {
+          return Api.getSystemConfig({
+            func: 'sPC_MainMenu_ReDel',
+            MenuID: ids.join(',')
+          })
+        }
+      }).then(res => { // 椤甸潰淇濆瓨
+        if (!res) return
+
+        if (res.status) {
+          return Api.getSystemConfig(param)
+        } else {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+          return false
+        }
+      }).then(res => { // 椤甸潰鎸夐挳鍏崇郴淇濆瓨
         if (!res) return
 
         if (res.status) {
@@ -524,9 +589,6 @@
             }
           }
         } else {
-          this.setState({
-            menuloading: false
-          })
           notification.warning({
             top: 92,
             message: res.message,
@@ -534,11 +596,105 @@
           })
           return false
         }
-      }).then(res => {
+      }).then(res => { // 鎸夐挳澶嶅埗
         if (!res) return
-        
-        if (res.status) {
+        if (!res.status) {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+          return false
+        }
+
+        if (copyButtons.length === 0) {
+          return {
+            status: true
+          }
+        } else {
+          return new Promise(resolve => {
+            let deffers = copyButtons.map(item => {
+              return new Promise(resolve => {
+                if (btnIds.indexOf(item.uuid) === -1) { // 澶嶅埗鐨勬寜閽凡鍒犻櫎
+                  resolve({
+                    status: true
+                  })
+                  return
+                }
+
+                Api.getSystemConfig({
+                  func: 'sPC_Get_LongParam',
+                  MenuID: item.$originUuid
+                }).then(result => {
+                  if (result.status) {
+                    let _conf = ''
+              
+                    try {
+                      _conf = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : ''
+                    } catch (e) {
+                      console.warn('Parse Failure')
+                      _conf = ''
+                    }
+                    
+                    if (_conf) {
+                      _conf.components = MenuUtils.resetConfig(_conf.components)
+                      _conf.uuid = item.uuid
+                      _conf.MenuID = item.uuid
+                      _conf.Template = 'CustomPage'
+                    } else {
+                      resolve({
+                        status: true
+                      })
+                      return
+                    }
+
+                    let _param = {
+                      func: 'sPC_ButtonParam_AddUpt',
+                      ParentID: _config.uuid,
+                      MenuID: item.uuid,
+                      MenuNo: '',
+                      Template: 'CustomPage',
+                      MenuName: item.label,
+                      PageParam: JSON.stringify({Template: 'CustomPage'}),
+                      LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(_conf)))
+                    }
+            
+                    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) {
+                notification.warning({
+                  top: 92,
+                  message: error.message,
+                  duration: 5
+                })
+                resolve(false)
+              } else {
+                resolve({
+                  status: true
+                })
+              }
+            })
+          })
+        }
+      }).then(res => {
+        if (res && res.status) {
           this.setState({
+            delButtons: [],
+            copyButtons: [],
+            thawButtons: [],
             menuloading: false,
             config: {...config, components: []}
           }, () => {
@@ -554,11 +710,6 @@
         } else {
           this.setState({
             menuloading: false
-          })
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
           })
         }
       })
@@ -678,7 +829,7 @@
   }
 
   render () {
-    const { activeKey, MenuType, popBtn, visible, dict, MenuId, config, ParentId, MenuName, MenuNo, menuloading } = this.state
+    const { activeKey, MenuType, popBtn, visible, dict, MenuId, config, ParentId, MenuName, MenuNo, menuloading, customComponents } = this.state
 
     return (
       <ConfigProvider locale={_locale}>
@@ -717,6 +868,9 @@
                   <Panel header={dict['mob.component']} key="component">
                     <SourceWrap MenuType={MenuType} />
                   </Panel>
+                  {customComponents && customComponents.length ? <Panel header="鑷畾涔夌粍浠�" key="cuscomponent">
+                    <SourceWrap components={customComponents} MenuType={MenuType} />
+                  </Panel> : null}
                   <Panel header={'鑳屾櫙'} key="background">
                     {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                   </Panel>
diff --git a/src/views/printTemplate/index.jsx b/src/views/printTemplate/index.jsx
index b84707d..887525b 100644
--- a/src/views/printTemplate/index.jsx
+++ b/src/views/printTemplate/index.jsx
@@ -2,7 +2,7 @@
 import { DndProvider } from 'react-dnd'
 import { is, fromJS } from 'immutable'
 import HTML5Backend from 'react-dnd-html5-backend'
-import { Card, notification, Row, Button, Modal } from 'antd'
+import { Card, notification, Row, Button, Modal, Input, Icon } from 'antd'
 import DragElement from './dragelement'
 import MutilForm from './mutilform'
 import SourceElement from './dragelement/source'
@@ -39,7 +39,11 @@
     editItemType: '',
     fields: [],
     formlist: null,
-    saveloading: false
+    saveloading: false,
+    upPlus: 1,
+    upMinus: 1,
+    leftPlus: 1,
+    leftMinus: 1
   }
 
   getclickpoint = (e) => {
@@ -814,17 +818,81 @@
     })
   }
 
+  change = (e, type) => {
+    let val = e.target.value
+    val = parseInt(val)
+
+    if (isNaN(val)) {
+      val = ''
+    }
+    this.setState({[type]: val})
+  }
+
+  updatePosition = (type) => {
+    let val = 0
+    if (type === 'upPlus') {
+      val = this.state.upPlus || 0
+    } else if (type === 'upMinus') {
+      val = this.state.upMinus || 0
+    } else if (type === 'leftPlus') {
+      val = this.state.leftPlus || 0
+    } else if (type === 'leftMinus') {
+      val = this.state.leftMinus || 0
+    }
+
+    if (!val) return
+
+    let config = fromJS(this.state.config).toJS()
+
+    if (type === 'upPlus') {
+      config.elements = config.elements.map(item => {
+        item.top = (item.top || 0) + val
+        return item
+      })
+    } else if (type === 'upMinus') {
+      config.elements = config.elements.map(item => {
+        item.top = (item.top || 0) - val
+        return item
+      })
+    } else if (type === 'leftPlus') {
+      config.elements = config.elements.map(item => {
+        item.left = (item.left || 0) + val
+        return item
+      })
+    } else if (type === 'leftMinus') {
+      config.elements = config.elements.map(item => {
+        item.left = (item.left || 0) - val
+        return item
+      })
+    }
+
+    this.setState({
+      config: config,
+      editItemId: config.uuid,
+      editItemType: config.type,
+      formlist: getpageform(config)
+    }, () => {
+      this.resetview()
+    })
+  }
+
   render () {
     return (
       <div className="print-template">
         <DndProvider backend={HTML5Backend}>
           <header className="print-header-container ant-menu-dark">妯℃澘鍒朵綔</header>
           <aside className="tools">
-            <Card title="宸ュ叿鏍�">
+            <Card className="tool-bar" title="宸ュ叿鏍�">
               {printItems.map((item, index) => {
                 return (<SourceElement key={index} content={item}/>)
               })}
             </Card>
+            <Card className="move-bar" title="鏁翠綋绉诲姩">
+              <Input addonBefore={<Icon title="璺濅笂" type="arrow-up" />} addonAfter={<Icon onClick={() => this.updatePosition('upPlus')} type="plus" />} onChange={(e) => this.change(e, 'upPlus')} value={this.state.upPlus} />
+              <Input addonBefore={<Icon title="璺濅笂" type="arrow-up" />} addonAfter={<Icon onClick={() => this.updatePosition('upMinus')} type="minus" />} onChange={(e) => this.change(e, 'upMinus')} value={this.state.upMinus} />
+              <Input addonBefore={<Icon title="璺濆乏" type="arrow-left" />} addonAfter={<Icon onClick={() => this.updatePosition('leftPlus')} type="plus" />} onChange={(e) => this.change(e, 'leftPlus')} value={this.state.leftPlus} />
+              <Input addonBefore={<Icon title="璺濆乏" type="arrow-left" />} addonAfter={<Icon onClick={() => this.updatePosition('leftMinus')} type="minus" />} onChange={(e) => this.change(e, 'leftMinus')} value={this.state.leftMinus} />
+            </Card>
           </aside>
           <div className="switchbox" onClick={this.switchbox}></div>
           <DragElement dropcard={this.dropcard} />
diff --git a/src/views/printTemplate/index.scss b/src/views/printTemplate/index.scss
index b5f0419..efb98b6 100644
--- a/src/views/printTemplate/index.scss
+++ b/src/views/printTemplate/index.scss
@@ -4,6 +4,9 @@
   padding: 75px 250px 30px 240px;
   text-align: center;
 
+  .ant-card-head {
+    min-height: 45px;
+  }
   .print-header-container {
     position: fixed;
     z-index: 1060;
@@ -27,7 +30,6 @@
     bottom: 0px;
     text-align: left;
     .ant-card {
-      height: 100%;
       .ant-card-head {
         background: #1890ff;
         color: #ffffff;
@@ -36,7 +38,29 @@
         padding: 10px 0;
       }
       .ant-card-body {
-        padding: 24px 12px;
+        padding: 24px 12px 0px;
+        .print-source-item:last-child {
+          margin-bottom: 0;
+        }
+      }
+    }
+    .ant-card.tool-bar {
+      height: 300px;
+      border-bottom: 0;
+    }
+    .ant-card.move-bar {
+      height: calc(100% - 300px);
+      .ant-input-group-wrapper {
+        margin-bottom: 15px;
+        input + .ant-input-group-addon {
+          padding: 0;
+        }
+        .anticon-plus, .anticon-minus {
+          cursor: pointer;
+          line-height: 25px;
+          padding-left: 15px;
+          padding-right: 15px;
+        }
       }
     }
   }

--
Gitblit v1.8.0