From 992f25d08ea2b5a6438ccc792a5c723b8a72f674 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期五, 06 八月 2021 18:19:39 +0800
Subject: [PATCH] 2021-08-06

---
 package-lock.json                                                |   66 +++
 src/tabviews/custom/components/card/balcony/index.scss           |   11 
 src/menu/components/group/groupcomponents/index.jsx              |    3 
 src/tabviews/zshare/normalTable/index.jsx                        |   47 --
 src/views/main/index.jsx                                         |    2 
 src/menu/components/card/cardcellcomponent/elementform/index.jsx |    5 
 src/menu/components/card/balcony/options.jsx                     |    2 
 src/menu/components/card/cardcellcomponent/dragaction/card.jsx   |    8 
 src/menu/components/card/cardsimplecomponent/options.jsx         |   17 
 src/menu/components/card/balcony/index.scss                      |   10 
 src/menu/components/tabs/tabcomponents/index.jsx                 |    3 
 src/components/imgScale/index.jsx                                |  133 +++++++
 src/mob/components/tabs/tabcomponents/index.jsx                  |   11 
 src/tabviews/custom/components/share/normalTable/index.jsx       |   46 ++
 src/tabviews/zshare/actionList/normalbutton/index.jsx            |    5 
 src/tabviews/custom/components/card/data-card/index.jsx          |   54 ++
 src/menu/components/card/balcony/index.jsx                       |    3 
 src/tabviews/custom/components/card/cardcellList/index.jsx       |   77 ++++
 src/components/imgScale/index.scss                               |  238 ++++++++++++++
 src/tabviews/custom/components/share/tabtransfer/index.jsx       |    7 
 src/menu/components/card/cardcellcomponent/index.jsx             |    6 
 src/tabviews/custom/components/group/normal-group/index.jsx      |    7 
 src/tabviews/custom/components/table/normal-table/index.jsx      |   16 
 src/mob/components/tabs/tabcomponents/card.jsx                   |    3 
 src/menu/components/card/cardcomponent/index.jsx                 |    5 
 src/menu/components/card/cardsimplecomponent/index.jsx           |    5 
 src/menu/components/group/groupcomponents/card.jsx               |    3 
 /dev/null                                                        |   20 -
 src/menu/components/card/cardcellcomponent/formconfig.jsx        |   22 +
 src/components/normalform/index.jsx                              |    3 
 src/tabviews/custom/index.jsx                                    |   71 +++
 src/tabviews/custom/components/card/balcony/index.jsx            |   57 +-
 package.json                                                     |    1 
 src/tabviews/custom/components/card/cardcellList/index.scss      |    3 
 src/menu/components/tabs/tabcomponents/card.jsx                  |    3 
 src/menu/components/card/cardcomponent/options.jsx               |   17 
 36 files changed, 805 insertions(+), 185 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 2a72c49..c23f03b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,9 +27,54 @@
       "integrity": "sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA=="
     },
     "@ant-design/icons": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
-      "integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w=="
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.6.2.tgz",
+      "integrity": "sha512-QsBG2BxBYU/rxr2eb8b2cZ4rPKAPBpzAR+0v6rrZLp/lnyvflLH3tw1vregK+M7aJauGWjIGNdFmUfpAOtw25A==",
+      "requires": {
+        "@ant-design/colors": "^6.0.0",
+        "@ant-design/icons-svg": "^4.0.0",
+        "@babel/runtime": "^7.11.2",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.9.4"
+      },
+      "dependencies": {
+        "@ant-design/colors": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
+          "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
+          "requires": {
+            "@ctrl/tinycolor": "^3.4.0"
+          }
+        },
+        "@babel/runtime": {
+          "version": "7.14.8",
+          "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
+          "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
+          "requires": {
+            "regenerator-runtime": "^0.13.4"
+          }
+        },
+        "rc-util": {
+          "version": "5.13.2",
+          "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.13.2.tgz",
+          "integrity": "sha512-eYc71XXGlp96RMzg01Mhq/T3BL6OOVTDSS0urFEuvpi+e7slhJRhaHGCKy2hqJm18m9ff7VoRoptplKu60dYog==",
+          "requires": {
+            "@babel/runtime": "^7.12.5",
+            "react-is": "^16.12.0",
+            "shallowequal": "^1.1.0"
+          }
+        },
+        "react-is": {
+          "version": "16.13.1",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+          "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+        },
+        "regenerator-runtime": {
+          "version": "0.13.9",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
+          "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+        }
+      }
     },
     "@ant-design/icons-react": {
       "version": "2.0.1",
@@ -39,6 +84,11 @@
         "@ant-design/colors": "^3.1.0",
         "babel-runtime": "^6.26.0"
       }
+    },
+    "@ant-design/icons-svg": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.1.0.tgz",
+      "integrity": "sha512-Fi03PfuUqRs76aI3UWYpP864lkrfPo0hluwGqh7NJdLhvH4iRDc3jbJqZIvRDLHKbXrvAfPPV3+zjUccfFvWOQ=="
     },
     "@antv/adjust": {
       "version": "0.2.3",
@@ -1540,6 +1590,11 @@
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-9.0.1.tgz",
       "integrity": "sha512-6It2EVfGskxZCQhuykrfnALg7oVeiI6KclWSmGDqB0AiInVrTGB9Jp9i4/Ad21u9Jde/voVQz6eFX/eSg/UsPA=="
+    },
+    "@ctrl/tinycolor": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
+      "integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ=="
     },
     "@fast-csv/format": {
       "version": "4.3.5",
@@ -3125,6 +3180,11 @@
         "warning": "~4.0.3"
       },
       "dependencies": {
+        "@ant-design/icons": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
+          "integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w=="
+        },
         "rc-animate": {
           "version": "2.11.1",
           "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.11.1.tgz",
diff --git a/package.json b/package.json
index aaef24f..b31ef50 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@ant-design/icons": "^4.6.2",
     "@antv/data-set": "^0.11.4",
     "@antv/g2": "^4.1.14",
     "@antv/util": "^2.0.13",
diff --git a/src/components/imgScale/index.jsx b/src/components/imgScale/index.jsx
new file mode 100644
index 0000000..8363674
--- /dev/null
+++ b/src/components/imgScale/index.jsx
@@ -0,0 +1,133 @@
+import React, {Component} from 'react'
+import {
+  RotateLeftOutlined,
+  RotateRightOutlined,
+  CloseOutlined,
+  ZoomOutOutlined,
+  ZoomInOutlined,
+  LeftOutlined,
+  RightOutlined
+} from '@ant-design/icons'
+
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class ImgScale extends Component {
+  state = {
+    className: 'close',
+    url: '',
+    list: [],
+    scale: 1,
+    rotate: 0,
+    index: 0
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('mkImageScale', this.mkImageScale)
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('mkImageScale', this.mkImageScale)
+  }
+
+  mkImageScale = (src, list = []) => {
+    const { url } = this.state
+
+    if (url || !src) return
+
+    let index = 0
+
+    if (list.length > 0) {
+      index = list.indexOf(src)
+    }
+
+    this.setState({url: src, className: 'opening', list, scale: 1, rotate: 0, index})
+    setTimeout(() => {
+      this.setState({className: 'open'})
+    }, 300)
+  }
+
+  close = () => {
+    this.setState({className: 'closeing'})
+    setTimeout(() => {
+      this.setState({className: 'close', url: ''})
+    }, 300)
+  }
+
+  zoomIn = () => {
+    this.setState({scale: this.state.scale + 1})
+  }
+
+  zoomOut = () => {
+    const { scale } = this.state
+
+    if (scale === 1) return
+
+    this.setState({scale: scale - 1})
+  }
+
+  rotateRight = () => {
+    this.setState({rotate: this.state.rotate + 90})
+  }
+
+  rotateLeft = () => {
+    this.setState({rotate: this.state.rotate - 90})
+  }
+
+  prev = () => {
+    const { list, index } = this.state
+    
+    this.setState({url: list[index - 1], index: index - 1})
+  }
+
+  next = () => {
+    const { list, index } = this.state
+    
+    this.setState({url: list[index + 1], index: index + 1})
+  }
+
+  render() {
+    const { index, url, scale, rotate, className, list } = this.state
+
+    return (
+      <div className={'mk-preview ' + className}>
+        <div className="mk-image-preview-mask"></div>
+        <div className="mk-image-preview-wrap">
+          <div className="mk-image-preview">
+            <div className="mk-image-preview-content">
+              <div className="mk-image-preview-body">
+                <ul className="mk-image-preview-operations">
+                  <li className="mk-image-preview-operations-operation" onClick={this.close}>
+                    <CloseOutlined />
+                  </li>
+                  <li className="mk-image-preview-operations-operation" onClick={this.zoomIn}>
+                    <ZoomInOutlined />
+                  </li>
+                  <li className={'mk-image-preview-operations-operation ' + (scale === 1 ? 'mk-image-preview-operations-operation-disabled' : '')} onClick={this.zoomOut}>
+                    <ZoomOutOutlined />
+                  </li>
+                  <li className="mk-image-preview-operations-operation" onClick={this.rotateRight}>
+                    <RotateRightOutlined />
+                  </li>
+                  <li className="mk-image-preview-operations-operation" onClick={this.rotateLeft}>
+                    <RotateLeftOutlined />
+                  </li>
+                </ul>
+                <div className="mk-image-preview-img-wrapper" style={{transform: 'translate3d(0px, 0px, 0px)'}}>
+                  {url ? <img className="mk-image-preview-img" alt="" src={url} style={{transform: `scale3d(${scale}, ${scale}, 1) rotate(${rotate}deg)`}}/> : null}
+                </div>
+                {index ? <LeftOutlined className="mk-image-preview-switch-left" onClick={this.prev}/> : null}
+                {list.length > index + 1 ? <RightOutlined className="mk-image-preview-switch-right" onClick={this.next}/> : null}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+}
+
+export default ImgScale
\ No newline at end of file
diff --git a/src/components/imgScale/index.scss b/src/components/imgScale/index.scss
new file mode 100644
index 0000000..0c899e1
--- /dev/null
+++ b/src/components/imgScale/index.scss
@@ -0,0 +1,238 @@
+
+.mk-image-preview {
+  pointer-events: none;
+  height: 100%;
+  text-align: center;
+}
+.mk-image-preview.zoom-enter,
+.mk-image-preview.zoom-appear {
+  -webkit-transform: none;
+          transform: none;
+  opacity: 0;
+  -webkit-animation-duration: 0.3s;
+          animation-duration: 0.3s;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+}
+.mk-image-preview-mask {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1100;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.65);
+}
+.mk-image-preview-mask-hidden {
+  display: none;
+}
+.mk-image-preview-wrap {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: auto;
+  outline: 0;
+  -webkit-overflow-scrolling: touch;
+}
+.mk-image-preview-body {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+}
+.mk-image-preview-img {
+  max-width: 100%;
+  max-height: 100%;
+  vertical-align: middle;
+  -webkit-transform: scale3d(1, 1, 1);
+          transform: scale3d(1, 1, 1);
+  // cursor: -webkit-grab;
+  // cursor: grab;
+  -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  transition: -webkit-transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  transition: transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  transition: transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s, -webkit-transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  pointer-events: auto;
+}
+.mk-image-preview-img-wrapper {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  transition: -webkit-transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  transition: transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+  transition: transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s, -webkit-transform 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) 0s;
+}
+.mk-image-preview-img-wrapper::before {
+  display: inline-block;
+  width: 1px;
+  height: 50%;
+  margin-right: -1px;
+  content: '';
+}
+.mk-image-preview-moving .mk-image-preview-img {
+  cursor: -webkit-grabbing;
+  cursor: grabbing;
+}
+.mk-image-preview-moving .mk-image-preview-img-wrapper {
+  -webkit-transition-duration: 0s;
+          transition-duration: 0s;
+}
+.mk-image-preview-wrap {
+  z-index: 1180;
+}
+.mk-image-preview-operations {
+  -webkit-box-sizing: border-box;
+          box-sizing: border-box;
+  margin: 0;
+  padding: 0;
+  color: rgba(0, 0, 0, 0.85);
+  font-size: 14px;
+  font-variant: tabular-nums;
+  line-height: 1.5715;
+  -webkit-font-feature-settings: 'tnum';
+          font-feature-settings: 'tnum';
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 1;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-orient: horizontal;
+  -webkit-box-direction: reverse;
+      -ms-flex-direction: row-reverse;
+          flex-direction: row-reverse;
+  -webkit-box-align: center;
+      -ms-flex-align: center;
+          align-items: center;
+  width: 100%;
+  color: rgba(255, 255, 255, 0.85);
+  list-style: none;
+  background: rgba(0, 0, 0, 0.5);
+  pointer-events: auto;
+}
+.mk-image-preview-operations-operation {
+  margin-left: 12px;
+  padding: 10px 12px;
+  cursor: pointer;
+  font-size: 18px;
+}
+.mk-image-preview-operations-operation-disabled {
+  color: rgba(255, 255, 255, 0.25);
+  pointer-events: none;
+}
+.mk-image-preview-operations-operation:last-of-type {
+  margin-left: 0;
+}
+.mk-image-preview-switch-left,
+.mk-image-preview-switch-right {
+  font-size: 20px;
+  position: absolute;
+  top: 50%;
+  right: 10px;
+  z-index: 1;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-align: center;
+      -ms-flex-align: center;
+          align-items: center;
+  -webkit-box-pack: center;
+      -ms-flex-pack: center;
+          justify-content: center;
+  width: 44px;
+  height: 44px;
+  margin-top: -22px;
+  color: rgba(255, 255, 255, 0.85);
+  background: rgba(0, 0, 0, 0.1);
+  border-radius: 50%;
+  cursor: pointer;
+  pointer-events: auto;
+}
+
+.mk-image-preview-switch-left {
+  left: 10px;
+}
+.mk-image-preview-switch-right {
+  right: 10px;
+}
+
+.mk-drawer.mk-drawer-open .mk-drawer-mask {
+  height: 100%;
+  opacity: 1;
+  transition: none;
+  -webkit-animation: antdDrawerFadeIn 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
+          animation: antdDrawerFadeIn 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
+  pointer-events: auto;
+}
+.mk-preview {
+  z-index: 1100;
+  opacity: 0;
+}
+.mk-preview.close {
+  display: none;
+}
+.mk-preview.open {
+  opacity: 1;
+}
+
+.mk-preview.opening {
+  transition: none;
+  -webkit-animation: antdDrawerFadeIn 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
+          animation: antdDrawerFadeIn 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
+  pointer-events: auto;
+}
+.mk-preview.closeing {
+  opacity: 1;
+  transition: none;
+  -webkit-animation: antdDrawerFadeOut 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
+          animation: antdDrawerFadeOut 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
+  pointer-events: auto;
+}
+
+@-webkit-keyframes antdDrawerFadeIn {
+  0% {
+    opacity: 0;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+@keyframes antdDrawerFadeIn {
+  0% {
+    opacity: 0;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+@-webkit-keyframes antdDrawerFadeOut {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}
+@keyframes antdDrawerFadeOut {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0;
+  }
+}
diff --git a/src/components/normalform/index.jsx b/src/components/normalform/index.jsx
index 6c2d87a..5e1057e 100644
--- a/src/components/normalform/index.jsx
+++ b/src/components/normalform/index.jsx
@@ -68,13 +68,12 @@
           visible={visible}
           width={width}
           maskClosable={false}
-          okText={dict['model.submit']}
+          okText={dict['model.confirm']}
           onOk={this.submit}
           onCancel={() => { this.setState({ visible: false }) }}
           destroyOnClose
         >
           <ModalForm
-            dict={dict}
             formlist={formlist}
             inputSubmit={this.submit}
             wrappedComponentRef={(inst) => this.Ref = inst}
diff --git a/src/menu/components/card/balcony/index.jsx b/src/menu/components/card/balcony/index.jsx
index 9683031..fc5ae1b 100644
--- a/src/menu/components/card/balcony/index.jsx
+++ b/src/menu/components/card/balcony/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Icon, Popover } from 'antd'
+import { Icon, Popover, Checkbox } from 'antd'
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -227,6 +227,7 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
+        {card.wrap.checkAll === 'show' ? <div className="check-all"><Checkbox>鍏ㄩ��</Checkbox></div> : null}
         <CardCellComponent cards={card} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
       </div>
     )
diff --git a/src/menu/components/card/balcony/index.scss b/src/menu/components/card/balcony/index.scss
index 1e071bd..8359299 100644
--- a/src/menu/components/card/balcony/index.scss
+++ b/src/menu/components/card/balcony/index.scss
@@ -6,7 +6,17 @@
   background-repeat: no-repeat;
   background-size: cover;
   min-height: 30px;
+  display: flex;
   
+  .check-all {
+    width: 70px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .model-menu-card-cell-list {
+    flex: 1;
+  }
   .card-control {
     position: absolute;
     top: 0px;
diff --git a/src/menu/components/card/balcony/options.jsx b/src/menu/components/card/balcony/options.jsx
index 4bb345d..45fb759 100644
--- a/src/menu/components/card/balcony/options.jsx
+++ b/src/menu/components/card/balcony/options.jsx
@@ -75,6 +75,7 @@
       field: 'supModule',
       label: '涓婄骇缁勪欢',
       initval: wrap.supModule || '',
+      // tooltip: '褰撲笂绾х粍浠朵笉瀛樺湪鎴栨病鏈夋潈闄愭椂锛屽綋鍓嶇粍浠朵笉鏄剧ず銆�',
       required: true,
       options: supmodules
     },
@@ -95,6 +96,7 @@
       field: 'syncModule',
       label: '鍚屾缁勪欢',
       initval: wrap.syncModule || '',
+      tooltip: '褰撳悓姝ョ粍浠朵笉瀛樺湪鎴栨病鏈夋潈闄愭椂锛屽綋鍓嶇粍浠朵笉鏄剧ず銆�',
       required: true,
       options: modules
     },
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
index 9982b08..ce5e4d4 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -141,6 +141,12 @@
           {`${card.prefix || ''}${moment().format(card.dateFormat)}${card.postfix || ''}`}
         </div>
       )
+    } else if (card.eleType === 'formula') {
+      return (
+        <div className="ant-mk-date">
+          {`${card.prefix || ''}${card.formula}${card.postfix || ''}`}
+        </div>
+      )
     }
   }
 
@@ -158,7 +164,7 @@
         <Icon className="copy" title="澶嶅埗" type="copy" onClick={() => copyCard(id)} />
         <Icon className="close" title="鍒犻櫎" type="close" onClick={() => delCard(id)} />
         <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => changeStyle(id)} type="font-colors" />
-        {['text', 'number', 'slider', 'sequence'].includes(card.eleType) ? <MarkColumn columns={fields} type={card.eleType} marks={card.marks} onSubmit={(vals) => updateMarks({...card, marks: vals})} /> : null }
+        {['text', 'number', 'slider', 'sequence', 'formula'].includes(card.eleType) ? <MarkColumn columns={fields} type={card.eleType} marks={card.marks} onSubmit={(vals) => updateMarks({...card, marks: vals})} /> : null }
       </div>
     } trigger="hover">
       <div ref={node => drag(drop(node))} className={'ant-col card-cell ant-col-' + card.width}>
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.jsx b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
index 874d82a..84ae886 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -16,7 +16,7 @@
   sequence: ['eleType', 'width'],
   text: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix', 'link'],
   number: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix'],
-  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'maxWidth', 'link'],
+  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'maxWidth', 'link', 'scale'],
   video: ['eleType', 'datatype', 'width', 'aspectRatio', 'autoPlay', 'loop'],
   icon: ['eleType', 'icon', 'datatype', 'width'],
   slider: ['eleType', 'datatype', 'width', 'color', 'maxValue'],
@@ -24,6 +24,7 @@
   barcode: ['eleType', 'datatype', 'width', 'barHeight', 'displayValue', 'interval'],
   qrcode: ['eleType', 'datatype', 'width', 'qrWidth', 'color', 'url'],
   currentDate: ['eleType', 'width', 'dateFormat', 'prefix', 'postfix'],
+  formula: ['eleType', 'width', 'height', 'prefix', 'postfix', 'formula'],
 }
 
 class MainSearch extends Component {
@@ -299,7 +300,7 @@
                     message: formRule.input.message
                   }
                 ]
-              })(<TextArea rows={2} disabled={item.readonly} />)}
+              })(<TextArea rows={2} disabled={item.readonly} placeholder={item.placeholder || ''} />)}
             </Form.Item>
           </Col>
         )
diff --git a/src/menu/components/card/cardcellcomponent/formconfig.jsx b/src/menu/components/card/cardcellcomponent/formconfig.jsx
index d7896a6..60a2c1b 100644
--- a/src/menu/components/card/cardcellcomponent/formconfig.jsx
+++ b/src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -20,6 +20,7 @@
     { value: 'barcode', text: '鏉″舰鐮�'},
     { value: 'qrcode', text: '浜岀淮鐮�'},
     { value: 'currentDate', text: '褰撳墠鏃堕棿'},
+    { value: 'formula', text: '鍏紡'},
   ]
 
   if (type === 'table' || (type === 'card' && subtype === 'datacard')) {
@@ -295,6 +296,17 @@
       required: false,
     },
     {
+      type: 'radio',
+      key: 'scale',
+      label: '鍥剧墖鏀惧ぇ',
+      initVal: card.scale || 'false',
+      required: false,
+      options: [
+        { value: 'false', text: '涓嶅彲浠�' },
+        { value: 'true', text: '鍙互' }
+      ]
+    },
+    {
       type: 'select',
       key: 'aspectRatio',
       label: '闀垮姣�',
@@ -328,7 +340,6 @@
       forbid: !isApp,
       options: [
         { value: '', text: '鏃�' },
-        // { value: 'page', text: '鑿滃崟' },
         { value: 'linkpage', text: '鍏宠仈鑿滃崟' },
         { value: 'custom', text: '閾炬帴' }
       ]
@@ -385,6 +396,15 @@
       required: true,
       options: []
     },
+    {
+      type: 'textarea',
+      key: 'formula',
+      label: '鍏紡',
+      initVal: card.formula || '',
+      tooltip: '鎵ц鏃朵細浣跨敤鏌ヨ鍒扮殑鏁版嵁鏇挎崲鐩稿簲鐨勫瓧娈碉紝灞曠ず鑾峰緱鐨勭粨鏋溿��',
+      placeholder: '渚嬪锛欯price@ * @number@',
+      required: true
+    },
   ]
 
   return forms
diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx
index 3a03296..170df16 100644
--- a/src/menu/components/card/cardcellcomponent/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/index.jsx
@@ -178,7 +178,7 @@
   resetCardStyle = (card, style) => {
     let _card = fromJS(card).toJS()
     
-    if (_card.eleType === 'text' || _card.eleType === 'number') {
+    if (['text', 'number', 'formula'].includes(_card.eleType)) {
       _card.style = style
 
       let fontSize = 14
@@ -315,6 +315,8 @@
       elements: _elements,
       visible: false,
       actvisible: false
+    }, () => {
+      this.props.updateElement(_elements)
     })
   }
 
@@ -332,7 +334,7 @@
           if (res.eleType === 'splitline' && cell.eleType !== 'splitline') {
             res.style.paddingTop = '5px'
             res.style.paddingBottom = '5px'
-          } else if (res.eleType === 'text' || res.eleType === 'number') {
+          } else if (['text', 'number', 'formula'].includes(res.eleType)) {
             let fontSize = 14
             let lineHeight = 1.5
             let line = res.height || null
diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index 895c2e3..0709e4f 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/src/menu/components/card/cardcomponent/index.jsx
@@ -178,11 +178,6 @@
   updateSetting = (res) => {
     const { card, side } = this.state
 
-    if (res.appmenu) {
-      res.menu = res.appmenu
-    }
-    delete res.appmenu
-
     this.setState({
       card: {...card, setting: res}
     })
diff --git a/src/menu/components/card/cardcomponent/options.jsx b/src/menu/components/card/cardcomponent/options.jsx
index 01ee4a9..cd79835 100644
--- a/src/menu/components/card/cardcomponent/options.jsx
+++ b/src/menu/components/card/cardcomponent/options.jsx
@@ -101,29 +101,18 @@
       ],
       controlFields: [
         {field: 'menu', values: ['menu']},
-        {field: 'appmenu', values: ['menu']},
         {field: 'linkurl', values: ['link']},
         {field: 'open', values: ['menu', 'link']},
         {field: 'joint', values: ['menu', 'link']},
       ]
     },
     {
-      type: 'cascader',
+      type: appType ? 'select' : 'cascader',
       field: 'menu',
-      label: '鑿滃崟',
-      initval: setting.menu || [],
-      required: true,
-      options: menulist,
-      forbid: !!appType
-    },
-    {
-      type: 'select',
-      field: 'appmenu',
       label: '鍏宠仈鑿滃崟',
-      initval: setting.menu || '',
+      initval: setting.menu || (appType ? '' : []),
       required: true,
-      options: appmenulist,
-      forbid: !appType
+      options: appType ? appmenulist : menulist,
     },
     {
       type: 'textarea',
diff --git a/src/menu/components/card/cardsimplecomponent/index.jsx b/src/menu/components/card/cardsimplecomponent/index.jsx
index f6dff48..cdda53a 100644
--- a/src/menu/components/card/cardsimplecomponent/index.jsx
+++ b/src/menu/components/card/cardsimplecomponent/index.jsx
@@ -146,11 +146,6 @@
   updateSetting = (res) => {
     const { card } = this.state
 
-    if (res.appmenu) {
-      res.menu = res.appmenu
-    }
-    delete res.appmenu
-
     let _card = {...card, setting: res}
 
     this.setState({ card: _card })
diff --git a/src/menu/components/card/cardsimplecomponent/options.jsx b/src/menu/components/card/cardsimplecomponent/options.jsx
index c9affe0..2dcda21 100644
--- a/src/menu/components/card/cardsimplecomponent/options.jsx
+++ b/src/menu/components/card/cardsimplecomponent/options.jsx
@@ -112,29 +112,18 @@
       ],
       controlFields: [
         {field: 'menu', values: ['menu']},
-        {field: 'appmenu', values: ['menu']},
         {field: 'linkurl', values: ['link']},
         {field: 'open', values: ['menu', 'link']},
         {field: 'joint', values: ['menu', 'link']},
       ]
     },
     {
-      type: 'cascader',
+      type: appType ? 'select' : 'cascader',
       field: 'menu',
-      label: '鑿滃崟',
-      initval: setting.menu || [],
-      required: true,
-      options: menulist,
-      forbid: !!appType
-    },
-    {
-      type: 'select',
-      field: 'appmenu',
       label: '鍏宠仈鑿滃崟',
-      initval: setting.menu || '',
+      initval: setting.menu || (appType ? '' : []),
       required: true,
-      options: appmenulist,
-      forbid: !appType
+      options: appType ? appmenulist : menulist,
     },
     {
       type: 'textarea',
diff --git a/src/menu/components/group/groupcomponents/card.jsx b/src/menu/components/group/groupcomponents/card.jsx
index 0e01f26..4f58886 100644
--- a/src/menu/components/group/groupcomponents/card.jsx
+++ b/src/menu/components/group/groupcomponents/card.jsx
@@ -18,6 +18,7 @@
 const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
 const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
+const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
@@ -84,6 +85,8 @@
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/components/group/groupcomponents/index.jsx b/src/menu/components/group/groupcomponents/index.jsx
index ac14bfa..52d00b5 100644
--- a/src/menu/components/group/groupcomponents/index.jsx
+++ b/src/menu/components/group/groupcomponents/index.jsx
@@ -67,7 +67,7 @@
 
       let name = ''
       let names = {
-        bbar: '鏌辩姸鍥�',
+        bar: '鏌辩姸鍥�',
         line: '鎶樼嚎鍥�',
         tabs: '鏍囩缁�',
         pie: '楗煎浘',
@@ -81,6 +81,7 @@
         dashboard: '浠〃鐩�',
         scatter: '鏁g偣鍥�',
         tree: '鏍戝舰鍒楄〃',
+        balcony: '娴姩鍗�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index 017966a..bfc1471 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -10,6 +10,7 @@
 const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
 const AntvScatter = asyncComponent(() => import('@/menu/components/chart/antv-scatter'))
 const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs'))
+const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 const DataCard = asyncComponent(() => import('@/menu/components/card/data-card'))
 const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
 const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
@@ -93,6 +94,8 @@
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/components/tabs/tabcomponents/index.jsx b/src/menu/components/tabs/tabcomponents/index.jsx
index 412a698..657c5d9 100644
--- a/src/menu/components/tabs/tabcomponents/index.jsx
+++ b/src/menu/components/tabs/tabcomponents/index.jsx
@@ -92,7 +92,7 @@
 
       let name = ''
       let names = {
-        bbar: '鏌辩姸鍥�',
+        bar: '鏌辩姸鍥�',
         line: '鎶樼嚎鍥�',
         tabs: '鏍囩缁�',
         pie: '楗煎浘',
@@ -106,6 +106,7 @@
         dashboard: '浠〃鐩�',
         scatter: '鏁g偣鍥�',
         tree: '鏍戝舰鍒楄〃',
+        balcony: '娴姩鍗�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/mob/components/tabs/tabcomponents/card.jsx b/src/mob/components/tabs/tabcomponents/card.jsx
index 6e8be3e..96b9d8d 100644
--- a/src/mob/components/tabs/tabcomponents/card.jsx
+++ b/src/mob/components/tabs/tabcomponents/card.jsx
@@ -22,6 +22,7 @@
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 const NormalMenuBar = asyncComponent(() => import('@/mob/components/menubar/normal-menubar'))
+const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
@@ -96,6 +97,8 @@
       return (<NormalMenuBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/mob/components/tabs/tabcomponents/index.jsx b/src/mob/components/tabs/tabcomponents/index.jsx
index 2259bf2..7bac2ee 100644
--- a/src/mob/components/tabs/tabcomponents/index.jsx
+++ b/src/mob/components/tabs/tabcomponents/index.jsx
@@ -92,7 +92,7 @@
 
       let name = ''
       let names = {
-        bbar: '鏌辩姸鍥�',
+        bar: '鏌辩姸鍥�',
         line: '鎶樼嚎鍥�',
         tabs: '鏍囩缁�',
         pie: '楗煎浘',
@@ -102,12 +102,13 @@
         editor: '瀵屾枃鏈�',
         code: '鑷畾涔�',
         carousel: '杞挱',
-        form: '琛ㄥ崟',
         dashboard: '浠〃鐩�',
-        scatter: '鏁g偣鍥�',
+        form: '琛ㄥ崟',
+        card: '鍗$墖',
+        navbar: '瀵艰埅鏍�',
         menubar: '鑿滃崟鏍�',
-        tree: '鏍戝舰鍒楄〃',
-        card: '鍗$墖'
+        balcony: '娴姩鍗�',
+        login: '鐧诲綍'
       }
       let i = 1
       
diff --git a/src/tabviews/custom/components/card/balcony/index.jsx b/src/tabviews/custom/components/card/balcony/index.jsx
index 879d8f5..9ac4da5 100644
--- a/src/tabviews/custom/components/card/balcony/index.jsx
+++ b/src/tabviews/custom/components/card/balcony/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification } from 'antd'
+import { Spin, notification, Checkbox } from 'antd'
 
 import Api from '@/api'
 // import Utils from '@/utils/utils.js'
@@ -15,7 +15,6 @@
 class BalconyComponent extends Component {
   static propTpyes = {
     BID: PropTypes.any,
-    menu: PropTypes.object,
     data: PropTypes.array,
     config: PropTypes.object,
     menuType: PropTypes.any,
@@ -28,11 +27,13 @@
     loading: false,
     sync: false,
     data: {},
-    show: true
+    syncData: [],
+    show: true,
+    checked: false
   }
 
   UNSAFE_componentWillMount () {
-    const { data, BID, menu } = this.props
+    const { data, BID } = this.props
     let _config = fromJS(this.props.config).toJS()
     let _cols = new Map()
 
@@ -75,32 +76,11 @@
     let show = true
     let syncConfig = null
     if (_config.wrap.linkType === 'sync') {
-      _config.wrap.syncModule = _config.wrap.syncModule.pop()
-      
-      let filterComponent = (components) => {
-        components.forEach(item => {
-          if (syncConfig) return
-          if (item.type === 'tabs') {
-            item.subtabs.forEach(tab => {
-              filterComponent(tab.components)
-            })
-          } else if (item.type === 'group') {
-            filterComponent(item.components)
-          } else if (_config.wrap.syncModule === item.uuid) {
-            syncConfig = {
-              uuid: item.uuid,
-              wrap: item.wrap,
-              setting: item.setting,
-              columns: item.columns
-            }
-          }
-        })
-      }
+      syncConfig = _config.syncConfig
 
-      filterComponent(menu.components)
       _config.elements = _config.elements.map(item => {
-        if (item.eleType === 'button') {
-          item.$syncModule = _config.wrap.syncModule
+        if (item.eleType === 'button' || item.eleType === 'formula') {
+          item.$sync = true
         }
         return item
       })
@@ -128,6 +108,7 @@
 
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('syncBalconyData', this.syncBalconyData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
@@ -141,6 +122,7 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('syncBalconyData', this.syncBalconyData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
@@ -199,6 +181,14 @@
       supModule && MKEmitter.emit('reloadData', supModule, (BID || 'empty'))
       btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
     }
+  }
+
+  syncBalconyData = (menuId, data, checked) => {
+    const { syncConfig } = this.state
+
+    if (!syncConfig || syncConfig.uuid !== menuId) return
+
+    this.setState({syncData: data, checked})
   }
 
   resetParentParam = (MenuID, id) => {
@@ -281,8 +271,14 @@
     }
   }
 
+  checkAll = (e) => {
+    const { syncConfig } = this.state
+
+    MKEmitter.emit('mkCheckAll', syncConfig.uuid, e.target.checked)
+  }
+
   render() {
-    const { config, loading, data, show, syncConfig } = this.state
+    const { config, loading, data, show, syncConfig, syncData, checked } = this.state
 
     return (
       <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} style={config.style}>
@@ -292,7 +288,8 @@
             <Spin />
           </div> : null
         }
-        <CardCellComponent data={data} cards={syncConfig || config} cardCell={config} elements={config.elements}/>
+        {config.wrap.checkAll === 'show' ? <div className="check-all"><Checkbox checked={checked} onChange={this.checkAll}>鍏ㄩ��</Checkbox></div> : null}
+        <CardCellComponent data={data} syncData={syncData || []} cards={syncConfig || config} cardCell={config} elements={config.elements}/>
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/card/balcony/index.scss b/src/tabviews/custom/components/card/balcony/index.scss
index 37c4a31..e49a9ee 100644
--- a/src/tabviews/custom/components/card/balcony/index.scss
+++ b/src/tabviews/custom/components/card/balcony/index.scss
@@ -4,6 +4,17 @@
   background-repeat: no-repeat;
   background-size: cover;
   position: relative;
+  display: flex;
+
+  >.check-all {
+    width: 70px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  >.card-cell-list {
+    flex: 1;
+  }
 
   .card-row-list::after {
     content: ' ';
diff --git a/src/tabviews/custom/components/card/cardcellList/index.jsx b/src/tabviews/custom/components/card/cardcellList/index.jsx
index 8b5fa84..9b4d0fd 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.jsx
+++ b/src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -7,6 +7,7 @@
 import asyncComponent from './asyncButtonComponent'
 import asyncElementComponent from '@/utils/asyncComponent'
 
+import MKEmitter from '@/utils/events.js'
 import LostPng from '@/assets/img/lost.png'
 import './index.scss'
 
@@ -32,6 +33,7 @@
     cards: PropTypes.object,         // 鑿滃崟閰嶇疆淇℃伅
     cardCell: PropTypes.object,
     data: PropTypes.object,
+    syncData: PropTypes.array,
     elements: PropTypes.array,       // 鍏冪礌闆�
   }
 
@@ -473,10 +475,23 @@
         _style.cursor = 'pointer'
       }
 
+      let scale = url && card.scale === 'true'
       return (
         <Col key={card.uuid} span={card.width}>
           <div style={_style} onClick={(e) => {this.openNewView(e, card)}}>
-            <div className="ant-mk-picture" style={_imagestyle}></div>
+            <div
+              className={'ant-mk-picture' + (scale ? ' scale' : '')}
+              onClick={(e) => {
+                if (scale) {
+                  e.stopPropagation()
+                } else {
+                  return
+                }
+
+                MKEmitter.emit('mkImageScale', url)
+              }}
+              style={_imagestyle}
+            ></div>
           </div>
         </Col>
       )
@@ -549,8 +564,66 @@
           </div>
         </Col>
       )
+    } else if (card.eleType === 'formula') {
+      let val = 0
+      let _style = card.style ? {...card.style} : {}
+
+      if (card.$sync) {
+        this.props.syncData.forEach(item => {
+          let _val = card.formula
+          Object.keys(item).forEach(key => {
+            let reg = new RegExp('@' + key + '@', 'ig')
+            _val = _val.replace(reg, item[key])
+          })
+          try {
+            // eslint-disable-next-line
+            _val = eval(_val)
+          } catch {
+            _val = 0
+          }
+
+          val += _val
+        })
+      } else if (data) {
+        let _val = card.formula
+        Object.keys(data).forEach(key => {
+          let reg = new RegExp('@' + key + '@', 'ig')
+          _val = _val.replace(reg, data[key])
+        })
+
+        try {
+          // eslint-disable-next-line
+          _val = eval(_val)
+        } catch {
+          _val = 0
+        }
+
+        val = _val
+      }
+
+      if (val !== '') {
+        val = `${card.prefix || ''}${val}${card.postfix || ''}`
+      }
+
+      if (card.marks) {
+        val = this.getMark(card.marks, _style, val)
+      }
+
+      return (
+        <Col key={card.uuid} span={card.width}>
+          <div style={_style}>
+            <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
+          </div>
+        </Col>
+      )
     } else if (card.eleType === 'button') {
-      let _data = data.$$type === 'extendCard' ? [] : [data]
+      let _data = [data]
+
+      if (data.$$type === 'extendCard') {
+        _data = []
+      } else if (card.$sync) {
+        _data = this.props.syncData
+      }
 
       if (['exec', 'prompt', 'pop'].includes(card.OpenType)) {
         return (
diff --git a/src/tabviews/custom/components/card/cardcellList/index.scss b/src/tabviews/custom/components/card/cardcellList/index.scss
index 76a5991..f8e195f 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.scss
+++ b/src/tabviews/custom/components/card/cardcellList/index.scss
@@ -142,6 +142,9 @@
     background-position: center center;
     background-repeat: no-repeat;
   }
+  .ant-mk-picture.scale {
+    cursor: zoom-in;
+  }
 }
 .card-cell-list::after {
   content: ' ';
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index 3a65f13..187e922 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { connect } from 'react-redux'
-import { Spin, Empty, notification, Row, Col, Pagination } from 'antd'
+import { Spin, Empty, notification, message, Row, Col, Pagination } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -146,7 +146,7 @@
 
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
-    MKEmitter.addListener('getSyncData', this.getSyncData)
+    MKEmitter.addListener('mkCheckAll', this.mkCheckAll)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
     MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
@@ -186,18 +186,10 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
-    MKEmitter.removeListener('getSyncData', this.getSyncData)
+    MKEmitter.removeListener('mkCheckAll', this.mkCheckAll)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
     MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
-  }
-
-  getSyncData = (syncModule, btnId) => {
-    const { config, selectedData } = this.state
-
-    if (config.uuid !== syncModule) return
-
-    MKEmitter.emit('triggerBtnId', btnId, (selectedData || []))
   }
 
   /**
@@ -230,6 +222,35 @@
     } else if (position === 'popclose') {                                      // 鏍囩鍏抽棴鍒锋柊
       config.setting.supModule && MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty'))
       btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
+    }
+  }
+
+  mkCheckAll = (menuId, checked) => {
+    const { config, data } = this.state
+
+    if (config.uuid !== menuId) return
+
+    if (checked) {
+      this.setState({
+        activeKey: '',
+        selectKeys: data.map((item, index) => index),
+        selectedData: data
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      MKEmitter.emit('syncBalconyData', config.uuid, data, data.length > 0)
+      if (data.length === 0) {
+        message.warning('鏈幏鍙栧埌鏁版嵁锛�')
+      }
+    } else {
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        selectedData: []
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      MKEmitter.emit('syncBalconyData', config.uuid, [], false)
     }
   }
 
@@ -299,6 +320,9 @@
         loading: false
       })
       MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      if (config.setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
+      }
       return
     }
 
@@ -346,6 +370,9 @@
         loading: false
       })
       MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      if (config.setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
+      }
     } else {
       this.setState({
         loading: false
@@ -464,7 +491,7 @@
   }
   
   changeCard = (index, item) => {
-    const { config, selectKeys, selectedData, activeKey } = this.state
+    const { config, selectKeys, selectedData, activeKey, data } = this.state
 
     this.openView(item)
 
@@ -504,6 +531,9 @@
     })
 
     MKEmitter.emit('resetSelectLine', config.uuid, (_item ? _item.$$uuid : ''), _item)
+    if (config.setting.$hasSyncModule) {
+      MKEmitter.emit('syncBalconyData', config.uuid, _selectedData, data.length === _selectedData.length)
+    }
   }
 
   openView = (item) => {
diff --git a/src/tabviews/custom/components/group/normal-group/index.jsx b/src/tabviews/custom/components/group/normal-group/index.jsx
index 0ffbce3..0122473 100644
--- a/src/tabviews/custom/components/group/normal-group/index.jsx
+++ b/src/tabviews/custom/components/group/normal-group/index.jsx
@@ -28,6 +28,7 @@
 const NormalTree = asyncComponent(() => import('@/tabviews/custom/components/tree/antd-tree'))
 const CarouselDataCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/prop-card'))
+const Balcony = asyncComponent(() => import('@/tabviews/custom/components/card/balcony'))
 
 class TabTransfer extends Component {
   static propTpyes = {
@@ -221,6 +222,12 @@
             <SandBox config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'balcony') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <Balcony config={item} data={data} BID={_bid} menuType={menuType} />
+          </Col>
+        )
       } else {
         return null
       }
diff --git a/src/tabviews/custom/components/share/normalTable/index.jsx b/src/tabviews/custom/components/share/normalTable/index.jsx
index 2d53f40..f0ba8f3 100644
--- a/src/tabviews/custom/components/share/normalTable/index.jsx
+++ b/src/tabviews/custom/components/share/normalTable/index.jsx
@@ -3,7 +3,7 @@
 import md5 from 'md5'
 import { connect } from 'react-redux'
 import { is, fromJS } from 'immutable'
-import { Table, Typography, Icon, Col, Switch } from 'antd'
+import { Table, Typography, Icon, Col, Switch, message } from 'antd'
 
 import { modifyTabview } from '@/store/action'
 import asyncComponent from '@/utils/asyncComponent'
@@ -496,6 +496,7 @@
   }
 
   componentDidMount () {
+    MKEmitter.addListener('mkCheckAll', this.mkCheckAll)
     MKEmitter.addListener('resetTable', this.resetTable)
   }
 
@@ -506,7 +507,39 @@
     this.setState = () => {
       return
     }
+    MKEmitter.removeListener('mkCheckAll', this.mkCheckAll)
     MKEmitter.removeListener('resetTable', this.resetTable)
+  }
+
+  mkCheckAll = (menuId, checked) => {
+    const { MenuID, data } = this.props
+
+    if (MenuID !== menuId) return
+
+    if (checked) {
+      this.setState({
+        activeIndex: '',
+        selectedRowKeys: data.map((item, index) => index)
+      })
+
+      this.props.chgSelectData(data)
+
+      MKEmitter.emit('resetSelectLine', MenuID, '', '')
+      MKEmitter.emit('syncBalconyData', MenuID, data, data.length > 0)
+      if (data.length === 0) {
+        message.warning('鏈幏鍙栧埌鏁版嵁锛�')
+      }
+    } else {
+      this.setState({
+        activeIndex: '',
+        selectedRowKeys: [],
+      })
+
+      this.props.chgSelectData([])
+  
+      MKEmitter.emit('resetSelectLine', MenuID, '', '')
+      MKEmitter.emit('syncBalconyData', MenuID, [], false)
+    }
   }
 
   // 瀛楁閫忚
@@ -585,7 +618,7 @@
    * 
    */
   onSelectChange = selectedRowKeys => {
-    const { setting } = this.props
+    const { setting, MenuID, data } = this.props
 
     let index = ''
     let _activeIndex = null
@@ -604,13 +637,16 @@
     let selects = this.props.data.filter((item, _index) => selectedRowKeys.includes(_index))
 
     this.props.chgSelectData(selects)
+    if (setting.$hasSyncModule) {
+      MKEmitter.emit('syncBalconyData', MenuID, selects, data.length === selects.length)
+    }
   }
 
   /**
    * @description 鐐瑰嚮鏁磋锛岃Е鍙戝垏鎹紝 鍒ゆ柇鏄惁鍙�夛紝鍗曢�夋垨澶氶�夛紝杩涜瀵瑰簲鎿嶄綔
    */
   changeRow = (record, index) => {
-    const { setting } = this.props
+    const { setting, MenuID, data } = this.props
 
     if (!setting.tableType || this.state.pickup) return
     
@@ -640,6 +676,10 @@
     let selects = this.props.data.filter((item, _index) => newkeys.includes(_index))
     
     this.props.chgSelectData(selects)
+
+    if (setting.$hasSyncModule) {
+      MKEmitter.emit('syncBalconyData', MenuID, selects, data.length === selects.length)
+    }
   }
 
   changeTable = (pagination, filters, sorter) => {
diff --git a/src/tabviews/custom/components/share/tabtransfer/index.jsx b/src/tabviews/custom/components/share/tabtransfer/index.jsx
index 62512b7..ff7f3f2 100644
--- a/src/tabviews/custom/components/share/tabtransfer/index.jsx
+++ b/src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -31,6 +31,7 @@
 const NormalTree = asyncComponent(() => import('@/tabviews/custom/components/tree/antd-tree'))
 const CarouselDataCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/prop-card'))
+const Balcony = asyncComponent(() => import('@/tabviews/custom/components/card/balcony'))
 
 class TabTransfer extends Component {
   static propTpyes = {
@@ -259,6 +260,12 @@
             <SandBox config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'balcony') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <Balcony config={item} data={data} BID={BID} menuType={menuType} />
+          </Col>
+        )
       } else {
         return null
       }
diff --git a/src/tabviews/custom/components/table/normal-table/index.jsx b/src/tabviews/custom/components/table/normal-table/index.jsx
index 2c57e82..b8e44a2 100644
--- a/src/tabviews/custom/components/table/normal-table/index.jsx
+++ b/src/tabviews/custom/components/table/normal-table/index.jsx
@@ -148,6 +148,9 @@
       })
       MKEmitter.emit('resetSelectLine', config.uuid, '', '') // 骞挎挱鏁版嵁鍒囨崲
       reset && MKEmitter.emit('resetTable', config.uuid, repage) // 鍒楄〃閲嶇疆
+      if (setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
+      }
       return
     }
 
@@ -195,6 +198,9 @@
         total: result.total,
         loading: false
       })
+      if (setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
+      }
     } else {
       this.setState({
         loading: false
@@ -489,14 +495,6 @@
     }
   }
 
-  getSyncData = (syncModule, btnId) => {
-    const { config, selectedData } = this.state
-
-    if (config.uuid !== syncModule) return
-
-    MKEmitter.emit('triggerBtnId', btnId, (selectedData || []))
-  }
-
   UNSAFE_componentWillReceiveProps(nextProps) {
     const { sync, config, BID } = this.state
 
@@ -527,7 +525,6 @@
 
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
-    MKEmitter.addListener('getSyncData', this.getSyncData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
     MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
@@ -541,7 +538,6 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
-    MKEmitter.removeListener('getSyncData', this.getSyncData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
     MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 22c148f..985546b 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -130,7 +130,8 @@
 
       // 鏉冮檺杩囨护
       let roleId = sessionStorage.getItem('role_id') || '' // 瑙掕壊ID
-      config.components = this.filterComponent(config.components, roleId, permAction, permMenus)
+      let balMap = new Map()
+      config.components = this.filterComponent(config.components, roleId, permAction, permMenus, balMap)
       
       // 鑾峰彇涓绘悳绱㈡潯浠�
       let mainSearch = []
@@ -190,7 +191,11 @@
         })
       }
 
-      config.components = this.formatSetting(config.components, params, mainSearch, inherit, regs)
+      config.components = this.formatSetting(config.components, params, mainSearch, inherit, regs, balMap)
+
+      if ([...balMap.keys()].length > 0) {
+        config.components = this.filterBalcony(config.components, balMap)
+      }
 
       this.setState({
         BID: BID,
@@ -439,7 +444,7 @@
     })
   }
 
-  filterComponent = (components, roleId, permAction, permMenus) => {
+  filterComponent = (components, roleId, permAction, permMenus, balMap) => {
     return components.filter(item => {
       
       if (item.style && item.style.boxShadow) {
@@ -470,7 +475,7 @@
         })
 
         item.subtabs = item.subtabs.map(tab => {
-          tab.components = this.filterComponent(tab.components, roleId, permAction, permMenus)
+          tab.components = this.filterComponent(tab.components, roleId, permAction, permMenus, balMap)
           return tab
         })
 
@@ -493,7 +498,7 @@
           return false
         }
 
-        item.components = this.filterComponent(item.components, roleId, permAction, permMenus)
+        item.components = this.filterComponent(item.components, roleId, permAction, permMenus, balMap)
       } else if (['pie', 'bar', 'line', 'dashboard', 'scatter'].includes(item.type)) {
         if (
           item.plot.blacklist && item.plot.blacklist.length > 0 &&
@@ -638,6 +643,10 @@
           })
         })
       } else if (item.type === 'balcony') {
+        if (item.wrap.linkType === 'sync') {
+          item.wrap.syncModuleId = item.wrap.syncModule.pop()
+          balMap.set(item.wrap.syncModuleId, true)
+        }
         item.elements = item.elements.filter(cell => {
           if (cell.eleType === 'button') {
             cell.logLabel = item.$menuname + '-' + cell.label
@@ -729,6 +738,45 @@
     })
   }
 
+
+  filterBalcony = (components, balMap) => {
+    return components.filter(item => {
+      if (item.type === 'tabs') {
+        item.subtabs = item.subtabs.map(tab => {
+          tab.components = this.filterBalcony(tab.components, balMap)
+          return tab
+        })
+      } else if (item.type === 'group') {
+        item.components = this.filterBalcony(item.components, balMap)
+      }
+
+      if (item.type === 'balcony' && item.wrap.linkType === 'sync') {
+        let conf = balMap.get(item.wrap.syncModuleId)
+
+        if (!conf || conf === true) {
+          return false
+        }
+        
+        item.syncConfig = {
+          uuid: conf.uuid,
+          wrap: conf.wrap,
+          setting: conf.setting,
+          columns: conf.columns
+        }
+
+        if (item.wrap.checkAll === 'show') {
+          if (conf.subtype === 'datacard' && conf.wrap.cardType !== 'checkbox') {
+            item.wrap.checkAll = 'hidden'
+          } else if (conf.subtype === 'normaltable' && conf.wrap.tableType !== 'checkbox') {
+            item.wrap.checkAll = 'hidden'
+          }
+        }
+      }
+      
+      return true
+    })
+  }
+
   getPrinter = (item, parentId) => {
     let _item = window.GLOB.UserCacheMap.get(parentId + item.uuid)
 
@@ -748,17 +796,17 @@
   }
 
   // 鏍煎紡鍖栭粯璁よ缃�
-  formatSetting = (components, params, mainSearch, inherit, regs) => {
+  formatSetting = (components, params, mainSearch, inherit, regs, balMap) => {
     return components.map(component => {
       if (component.type === 'tabs') {
         component.subtabs = component.subtabs.map(tab => {
-          tab.components = this.formatSetting(tab.components, [], [], inherit, regs)
+          tab.components = this.formatSetting(tab.components, [], [], inherit, regs, balMap)
           tab = {...tab, ...inherit}
           return tab
         })
         return component
       } else if (component.type === 'group') {
-        component.components = this.formatSetting(component.components, [], [], inherit, regs)
+        component.components = this.formatSetting(component.components, [], [], inherit, regs, balMap)
         component = {...component, ...inherit}
         return component
       }
@@ -844,6 +892,11 @@
         }
       } else if (component.floor === 1) {
         component.setting.sync = 'false'
+      }
+
+      if (balMap.has(component.uuid)) {
+        component.setting.$hasSyncModule = true
+        balMap.set(component.uuid, component)
       }
 
       return component
@@ -1012,7 +1065,7 @@
       } else if (item.type === 'balcony') {
         return (
           <Col span={item.width} key={item.uuid}>
-            <Balcony menu={config} config={item} data={data} BID={_bid} menuType={menuType} />
+            <Balcony config={item} data={data} BID={_bid} menuType={menuType} />
           </Col>
         )
       } else if (item.type === 'carousel' && item.subtype === 'datacard') {
diff --git a/src/tabviews/zshare/actionList/normalbutton/index.jsx b/src/tabviews/zshare/actionList/normalbutton/index.jsx
index 5368ef5..097be7a 100644
--- a/src/tabviews/zshare/actionList/normalbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -158,11 +158,6 @@
       return
     }
 
-    if (btn.$syncModule && !triggerId) {
-      MKEmitter.emit('getSyncData', btn.$syncModule, btn.uuid)
-      return
-    }
-
     let _this = this
     let data = record || selectedData || []
 
diff --git a/src/tabviews/zshare/imgScale/index.jsx b/src/tabviews/zshare/imgScale/index.jsx
deleted file mode 100644
index dc4c542..0000000
--- a/src/tabviews/zshare/imgScale/index.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { Icon } from 'antd'
-
-import './index.scss'
-
-class ImgScale extends Component {
-  static propTpyes = {
-    data: PropTypes.object
-  }
-
-  state = {
-    list: [],
-    index: 0
-  }
-
-  UNSAFE_componentWillMount() {
-    const { data } = this.props
-
-    this.setState({
-      list: data.list || [],
-      index: data.index || 0
-    })
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-  }
-
-  reduce = () => {
-    const { index } = this.state
-
-    this.setState({index: index - 1})
-  }
-
-  plus = () => {
-    const { index } = this.state
-
-    this.setState({index: index + 1})
-  }
-
-  render() {
-    const { list, index } = this.state
-
-    return (
-      <div className="img-scale-wrap">
-        <img src={list[index]} alt="" />
-        {index > 0 ? <Icon type="left" onClick={this.reduce} /> : null}
-        {index < list.length -1 ? <Icon type="right" onClick={this.plus} /> : null}
-      </div>
-    )
-  }
-}
-
-export default ImgScale
\ No newline at end of file
diff --git a/src/tabviews/zshare/imgScale/index.scss b/src/tabviews/zshare/imgScale/index.scss
deleted file mode 100644
index db4944e..0000000
--- a/src/tabviews/zshare/imgScale/index.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-.img-scale-wrap {
-  position: relative;
-  img {
-    max-width: 100%;
-  }
-
-  .anticon {
-    position: absolute;
-    top: calc(50% - 25px);
-    font-size: 30px;
-    padding: 10px;
-  }
-
-  .anticon-left {
-    left: 20px;
-  }
-  .anticon-right {
-    right: 20px;
-  }
-}
diff --git a/src/tabviews/zshare/normalTable/index.jsx b/src/tabviews/zshare/normalTable/index.jsx
index aa989fb..105916e 100644
--- a/src/tabviews/zshare/normalTable/index.jsx
+++ b/src/tabviews/zshare/normalTable/index.jsx
@@ -3,7 +3,7 @@
 import md5 from 'md5'
 import { connect } from 'react-redux'
 import { is, fromJS } from 'immutable'
-import { Table, Affix, Typography, Modal, Icon } from 'antd'
+import { Table, Affix, Typography, Icon } from 'antd'
 
 import { modifyTabview } from '@/store/action'
 import asyncComponent from '@/utils/asyncComponent'
@@ -17,7 +17,6 @@
 const PopupButton = asyncComponent(() => import('@/tabviews/zshare/actionList/popupbutton'))
 const TabButton = asyncComponent(() => import('@/tabviews/zshare/actionList/tabbutton'))
 const NewPageButton = asyncComponent(() => import('@/tabviews/zshare/actionList/newpagebutton'))
-const ImgScale = asyncComponent(() => import('@/tabviews/zshare/imgScale'))
 
 class NormalTable extends Component {
   static propTpyes = {
@@ -45,8 +44,6 @@
     pageIndex: 1,         // 鍒濆椤甸潰绱㈠紩
     pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
     columns: null,        // 鏄剧ず鍒�
-    imgShow: false,       // 鍥剧墖鏀惧ぇ妯℃�佹
-    imgData: {},          // 鍥剧墖闆�
     lineMarks: null,      // 琛屾爣璁�
     activeIndex: null,    // 鏍囪褰撳墠閫変腑琛�
     rowspans: null        // 琛屽悎骞跺瓧娈典俊鎭�
@@ -558,7 +555,9 @@
         <div className="picture-col">
           {photos && photos.map((url, i) => {
             if (item.scale === 'true') {
-              return <img style={{maxHeight: maxHeight}} className="image-scale" onClick={() => this.imgScale(photos, i)} key={`${i}`} src={url} alt=""/>
+              return <img style={{maxHeight: maxHeight}} className="image-scale" onClick={() => {
+                MKEmitter.emit('mkImageScale', url, photos.length > 1 ? photos : '')
+              }} key={`${i}`} src={url} alt=""/>
             } else {
               return <img style={{maxHeight: maxHeight}} key={`${i}`} src={url} alt=""/>
             }
@@ -871,7 +870,9 @@
           <div className="content-fence-top" style={images[0] ? {textAlign: images[0].align} : null}>
             {images.map((_img, index) => {
               if (_img.scale) {
-                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={() => this.imgScale(images, index)} key={`${index}`} src={_img.url} alt=""/>
+                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={() => {
+                  MKEmitter.emit('mkImageScale', _img.url, images.length > 1 ? images.map(g => g.url) : '')
+                }} key={`${index}`} src={_img.url} alt=""/>
               } else {
                 return (<img style={{maxHeight: _img.maxHeight}} key={`${index}`} src={_img.url} alt=""/>)
               }
@@ -890,7 +891,9 @@
           <div className="content-fence-left" style={images[0] ? {textAlign: images[0].align} : null}>
             {images.map((_img, index) => {
               if (_img.scale) {
-                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={() => this.imgScale(images, index)} key={`${index}`} src={_img.url} alt=""/>
+                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={() => {
+                  MKEmitter.emit('mkImageScale', _img.url, images.length > 1 ? images.map(g => g.url) : '')
+                }} key={`${index}`} src={_img.url} alt=""/>
               } else {
                 return (<img style={{maxHeight: _img.maxHeight}} key={`${index}`} src={_img.url} alt=""/>)
               }
@@ -904,24 +907,6 @@
         </div>
       )
     }
-  }
-
-  /**
-   * @description 鍥剧墖缂╂斁
-   */
-  imgScale = (images, index) => {
-    this.setState({
-      imgShow: true,
-      imgData: {
-        list: images.map(item => {
-          if (typeof(item) === 'string') {
-            return item
-          }
-          return item.url
-        }),
-        index
-      }
-    })
   }
 
   /**
@@ -1232,18 +1217,6 @@
           pagination={_pagination}
         />
         {_footer ? <div className={'normal-table-footer ' + (_pagination ? 'pagination' : '')}>{_footer}</div> : null}
-        <Modal
-          className="image-scale-modal"
-          visible={this.state.imgShow}
-          width="70vw"
-          maskClosable={true}
-          onCancel={() => {this.setState({ imgShow: false })}}
-          title={this.props.dict['main.form.picture.check']}
-          footer={[<span key="close" onClick={() => {this.setState({ imgShow: false })}}>{this.props.dict['main.close']}</span>]}
-          destroyOnClose
-        >
-          <ImgScale data={this.state.imgData}/>
-        </Modal>
       </div>
     )
   }
diff --git a/src/views/main/index.jsx b/src/views/main/index.jsx
index 0abf7b6..41eab2a 100644
--- a/src/views/main/index.jsx
+++ b/src/views/main/index.jsx
@@ -7,6 +7,7 @@
 import Header from '@/components/header'
 import Sidemenu from '@/components/sidemenu'
 import QueryLog from '@/components/querylog'
+import ImgScale from '@/components/imgScale'
 
 import './index.scss'
 
@@ -32,6 +33,7 @@
           {!isSideMenu ? <Breadview key="breadview"/> : null}
           <QueryLog />
         </ConfigProvider>
+        <ImgScale />
       </div>
     )
   }

--
Gitblit v1.8.0