From 1ba430d58ea3fd662d09b99f6e22ed3b3564a356 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期五, 03 二月 2023 14:15:31 +0800
Subject: [PATCH] 2023-02-03

---
 src/menu/components/timeline/normal-timeline/index.jsx                           |   14 
 src/mob/mobshell/index.jsx                                                       |   20 
 src/components/resetPassword/index.jsx                                           |  182 ++
 src/menu/components/card/balcony/options.jsx                                     |   20 
 src/menu/components/chart/antv-scatter/index.jsx                                 |   12 
 src/tabviews/zshare/actionList/newpagebutton/index.jsx                           |    4 
 src/views/design/sidemenu/index.jsx                                              |    2 
 src/locales/en-US/login.js                                                       |    2 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx             |   13 
 src/tabviews/zshare/actionList/changeuserbutton/index.jsx                        |    4 
 src/menu/stylecontroller/styleInput/index.scss                                   |    2 
 src/assets/css/main.scss                                                         |    4 
 src/menu/normalCss/index.scss                                                    |   21 
 src/menu/components/card/cardcellcomponent/index.jsx                             |    1 
 src/menu/components/card/data-card/options.jsx                                   |   13 
 src/menu/components/form/tab-form/index.jsx                                      |   14 
 src/pc/menushell/card.jsx                                                        |   19 
 src/menu/components/carousel/prop-card/index.jsx                                 |   12 
 src/menu/components/chart/antv-pie/index.jsx                                     |   12 
 src/menu/components/share/actioncomponent/actionform/index.jsx                   |   13 
 src/tabviews/custom/index.jsx                                                    |   11 
 src/views/menudesign/index.scss                                                  |    2 
 src/menu/components/card/prop-card/index.jsx                                     |   14 
 src/menu/components/tabs/tabcomponents/card.jsx                                  |    4 
 src/views/appmanage/submutilform/index.jsx                                       |   12 
 src/templates/zshare/modalform/modaleditable/index.jsx                           |   46 
 src/assets/css/viewstyle.scss                                                    |   32 
 src/views/login/loginform.jsx                                                    |    2 
 src/tabviews/custom/components/module/account/index.jsx                          |   30 
 src/pc/menushell/index.jsx                                                       |   20 
 src/tabviews/custom/popview/index.scss                                           |    5 
 src/tabviews/zshare/actionList/exceloutbutton/index.jsx                          |   42 
 src/menu/components/form/simple-form/index.jsx                                   |   14 
 src/menu/components/chart/antv-bar/index.jsx                                     |   12 
 src/mob/components/tabs/tabcomponents/index.jsx                                  |   20 
 src/tabviews/zshare/actionList/index.jsx                                         |    1 
 src/menu/stylecombcontroller/styleInput/index.scss                               |    2 
 src/menu/components/table/edit-table/index.jsx                                   |   14 
 src/mob/mobshell/card.jsx                                                        |   32 
 src/menu/components/carousel/data-card/index.jsx                                 |   12 
 src/mob/components/search/single-search/index.jsx                                |   11 
 src/tabviews/custom/components/card/table-card/index.jsx                         |    2 
 src/menu/components/module/voucher/options.jsx                                   |   44 
 src/tabviews/zshare/tablenodes/index.jsx                                         |   44 
 src/menu/components/form/step-form/index.jsx                                     |   14 
 src/tabviews/zshare/mutilform/mkCheckCard/index.jsx                              |   30 
 src/views/pcdesign/index.jsx                                                     |    2 
 src/mob/components/tabs/tabcomponents/card.jsx                                   |    4 
 src/views/systemfunc/sidemenu/index.jsx                                          |   10 
 src/locales/zh-CN/login.js                                                       |    2 
 src/menu/components/search/main-search/index.jsx                                 |   14 
 src/tabviews/custom/components/module/voucher/voucherTable/index.jsx             | 1027 ++++++++++----
 src/views/systemfunc/sidemenu/config.jsx                                         |   18 
 src/templates/zshare/modalform/modaleditable/index.scss                          |    9 
 src/views/login/index.jsx                                                        |   77 
 src/menu/components/editor/braft-editor/options.jsx                              |   10 
 src/tabviews/custom/components/card/cardItem/index.scss                          |   10 
 src/menu/components/card/table-card/index.jsx                                    |   14 
 src/tabviews/zshare/actionList/popupbutton/index.jsx                             |    4 
 src/components/resetPassword/index.scss                                          |   22 
 src/tabviews/zshare/actionList/excelInbutton/index.jsx                           |    4 
 public/options.json                                                              |   16 
 src/pc/components/login/normal-login/options.jsx                                 |   18 
 src/menu/components/module/voucher/index.jsx                                     |   64 
 src/menu/components/tabs/tabcomponents/index.jsx                                 |   20 
 src/menu/tablenodes/index.jsx                                                    |   25 
 src/views/pcdesign/index.scss                                                    |    2 
 src/menu/components/tree/antd-tree/index.jsx                                     |   14 
 src/tabviews/custom/index.scss                                                   |    5 
 src/views/billprint/index.jsx                                                    |    2 
 src/menu/menushell/card.jsx                                                      |    4 
 src/locales/en-US/main.js                                                        |    6 
 src/tabviews/zshare/actionList/normalbutton/index.jsx                            |   58 
 src/views/mobdesign/index.jsx                                                    |    2 
 src/views/menudesign/index.jsx                                                   |    2 
 src/tabviews/custom/components/card/data-card/index.jsx                          |    5 
 src/views/design/index.scss                                                      |    5 
 src/tabviews/custom/components/module/voucher/index.jsx                          |  413 +++++
 src/menu/components/share/actioncomponent/formconfig.jsx                         |    8 
 src/tabviews/basetable/index.scss                                                |    5 
 src/templates/sharecomponent/actioncomponent/actionform/index.jsx                |   11 
 src/menu/stylecontroller/styleInput/index.jsx                                    |   14 
 src/views/tabledesign/popview/index.scss                                         |    2 
 src/menu/components/card/data-card/index.jsx                                     |   26 
 src/menu/components/chart/antv-dashboard/index.jsx                               |   12 
 src/views/appmanage/index.jsx                                                    |    7 
 src/menu/components/table/normal-table/index.jsx                                 |   14 
 src/views/design/sidemenu/thdmenuplus/index.jsx                                  |    1 
 src/menu/components/card/cardcomponent/options.jsx                               |    3 
 src/menu/components/group/normal-group/index.jsx                                 |   39 
 src/views/design/index.jsx                                                       |    2 
 src/components/resetPassword/resetpwd/index.jsx                                  |  317 ++++
 src/menu/components/chart/antv-G6/index.jsx                                      |   12 
 src/components/header/index.jsx                                                  |  115 -
 src/tabviews/custom/components/card/cardItem/index.jsx                           |    8 
 src/menu/components/iframe/index.jsx                                             |   12 
 src/templates/sharecomponent/fieldscomponent/index.jsx                           |   34 
 src/menu/components/code/sandbox/index.jsx                                       |    2 
 src/views/mobdesign/index.scss                                                   |    2 
 src/menu/normalCss/index.jsx                                                     |   70 +
 src/tabviews/custom/components/card/data-card/index.scss                         |    5 
 src/tabviews/custom/components/card/table-card/index.scss                        |    7 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx            |   45 
 src/index.js                                                                     |    6 
 src/menu/components/card/balcony/index.jsx                                       |   28 
 src/tabviews/zshare/actionList/tabbutton/index.jsx                               |    4 
 src/locales/zh-CN/main.js                                                        |    6 
 src/menu/stylecontroller/index.jsx                                               |   30 
 src/templates/zshare/formconfig.jsx                                              |    4 
 src/tabviews/custom/components/module/voucher/voucherTable/index.scss            |  140 +
 src/tabviews/zshare/actionList/printbutton/index.jsx                             |    4 
 src/pc/components/login/normal-login/index.jsx                                   |   16 
 /dev/null                                                                        |  259 ---
 src/tabviews/custom/components/module/voucher/index.scss                         |   28 
 src/menu/components/editor/braft-editor/index.jsx                                |    7 
 src/tabviews/custom/components/card/balcony/index.jsx                            |   19 
 src/menu/components/module/voucher/index.scss                                    |   32 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx |    7 
 src/menu/menushell/index.jsx                                                     |   20 
 src/views/menudesign/popview/index.scss                                          |    2 
 120 files changed, 3,024 insertions(+), 1,105 deletions(-)

diff --git a/public/options.json b/public/options.json
index dd29f4f..b906330 100644
--- a/public/options.json
+++ b/public/options.json
@@ -1,22 +1,22 @@
 {
-  "appId": "202011020835217933120E25C41C54A8988AA",
-  "appkey": "20201102081641237BDDE0D5F2E98420BA7EC",
+  "appId": "201912101635586033882D350DED94BC08AB8",
+  "appkey": "2019120316231227060CDBAFCB3BF4582BBF8",
   "mainSystemApi": "https://cloud.positecgroup.com/webapi/dostars",
   "systemType": "",
-  "externalDatabase": "mkdata_oms_test",
+  "externalDatabase": "",
   "lineColor": "",
   "filter": "false",
   "defaultApp": "",
   "defaultLang": "zh-CN",
-  "WXAppID": "wxa5dd6f28cae613fc",
+  "WXAppID": "",
   "WXminiAppID": "",
   "nginx": "true",
-  "debugger": false,
+  "debugger": true,
   "licenseKey": "",
   "probation": "",
-  "transfer": "false",
+  "transfer": true,
   "keepPassword": "true",
   "platforms": ["H5", "wechat", "android", "ios", "wxMiniProgram"],
-  "host": "http://oms-test.positecgroup.com",
-  "service": "oms_new/"
+  "host": "https://css-test.positecgroup.com",
+  "service": ""
 }
\ No newline at end of file
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 630b514..eb2dcfb 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -488,4 +488,8 @@
   display: flex;
   flex: auto;
   min-height: 100%;
+}
+
+.component-wrap >.ant-col {
+  min-height: 0;
 }
\ No newline at end of file
diff --git a/src/assets/css/viewstyle.scss b/src/assets/css/viewstyle.scss
index d18d02f..931d12a 100644
--- a/src/assets/css/viewstyle.scss
+++ b/src/assets/css/viewstyle.scss
@@ -26,19 +26,6 @@
           }
         }
       }
-
-      .ant-tabs-nav .ant-tabs-tab-active {
-        color: $color6;
-      }
-      .ant-tabs-nav .ant-tabs-ink-bar {
-        background-color: $color6;
-      }
-      .ant-tabs-nav .ant-tabs-tab:active {
-        color: $color7;
-      }
-      .ant-tabs-nav .ant-tabs-tab:hover {
-        color: $color5;
-      }
     }
     >.mk-breadview-wrap {
       >.ant-breadcrumb {
@@ -205,6 +192,19 @@
     }
   }
 
+  .ant-tabs-nav .ant-tabs-tab-active {
+    color: $color6;
+  }
+  .ant-tabs-nav .ant-tabs-ink-bar {
+    background-color: $color6;
+  }
+  .ant-tabs-nav .ant-tabs-tab:active {
+    color: $color7;
+  }
+  .ant-tabs-nav .ant-tabs-tab:hover {
+    color: $color5;
+  }
+
   // 绯荤粺鏍峰紡淇敼
   .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) {
     background-color: $color1;
@@ -361,6 +361,12 @@
       background-color: $color6;
     }
   }
+  .ant-tree li .ant-tree-node-content-wrapper:hover {
+    background-color: $color1;
+  }
+  .ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
+    background-color: $color2;
+  }
 }
 
 body.hidden-split-line #root { // 鍘婚櫎鐧诲綍椤靛垎鍓茬嚎
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index 7f2669a..0f878e0 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -3,7 +3,6 @@
 import PropTypes from 'prop-types'
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
-import moment from 'moment'
 import { Dropdown, Menu, Modal, notification, Switch, Input } from 'antd'
 import { SearchOutlined, DownOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'
 
@@ -16,15 +15,13 @@
 import Api from '@/api'
 import MKEmitter from '@/utils/events.js'
 import options from '@/store/options.js'
-import zhCN from '@/locales/zh-CN/main.js'
-import enUS from '@/locales/en-US/main.js'
 import Utils from '@/utils/utils.js'
 import avatar from '@/assets/img/avatar.jpg'
 import './index.scss'
 
 const { confirm } = Modal
 const { Search } = Input
-const Resetpwd = asyncComponent(() => import('./resetpwd'))
+const Resetpwd = asyncComponent(() => import('@/components/resetPassword'))
 const LoginForm = asyncComponent(() => import('./loginform'))
 
 class Header extends Component {
@@ -33,9 +30,6 @@
   }
   state = {
     menulist: null, // 涓�绾ц彍鍗�
-    visible: false, // 淇敼瀵嗙爜妯℃�佹
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    confirmLoading: false,
     userName: '',
     fullName: '',
     logourl: window.GLOB.mainlogo,
@@ -57,60 +51,12 @@
 
   changePassword = () => {
     // 鐐瑰嚮淇敼瀵嗙爜锛屾樉绀哄脊绐�
-    this.setState({
-      visible: true
-    })
-  }
-
-  resetPwdSubmit = () => {
-    if (!this.formRef) return
-
-    this.formRef.handleConfirm().then(res => {
-      this.setState({
-        confirmLoading: true
-      })
-
-      let _param = {
-        func: 's_PwdUpt',
-        LText: `select '${res.originpwd}','${res.password}'`
-      }
-      
-      _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
-      _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
-      _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
-  
-      Api.getSystemConfig(_param).then(result => {
-        this.setState({
-          visible: !result.status,
-          confirmLoading: false
-        })
-
-        if (result.status) {
-          notification.success({
-            top: 92,
-            message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
-            duration: 2
-          })
-          setTimeout(() => {
-            sessionStorage.clear()
-            this.props.logout()
-            this.props.history.replace('/login')
-          }, 2000)
-        } else {
-          notification.warning({
-            top: 92,
-            message: result.message,
-            duration: 5
-          })
-        }
-      })
-    }, () => {})
-  }
-
-  handleCancel = () => {
-    // 鍙栨秷鏃跺叧闂慨鏀瑰瘑鐮佹ā鎬佹锛屾竻绌鸿〃鍗曟暟鎹�
-    this.setState({
-      visible: false
+    MKEmitter.emit('resetpassword', () => {
+      setTimeout(() => {
+        sessionStorage.clear()
+        this.props.logout()
+        this.props.history.replace('/login')
+      }, 2000)
     })
   }
 
@@ -118,7 +64,7 @@
     // 閫�鍑虹櫥褰�
     let _this = this
     confirm({
-      title: this.state.dict['main.logout.hint'],
+      title: '鎮ㄧ‘瀹氳閫�鍑哄悧?',
       content: '',
       onOk() {
         sessionStorage.clear()
@@ -225,6 +171,8 @@
   getMenulist = (result) => {
     let thdMenuList = []
     let menulist = []
+    let names = new Map()
+    let doublenames = new Map()
     result.fst_menu && result.fst_menu.forEach(fst => {
       let fstItem = {
         MenuID: fst.MenuID,
@@ -268,6 +216,7 @@
                 ParentId: snd.MenuID,
                 MenuID: trd.MenuID,
                 MenuName: trd.MenuName,
+                menu_name: trd.MenuName,
                 ParentNames: [fst.MenuName, snd.MenuName],
                 MenuNo: trd.MenuNo,
                 EasyCode: trd.EasyCode,
@@ -296,6 +245,12 @@
 
               trdItem.OpenType = trdItem.OpenType.toLowerCase() // NewPage涓烘墦寮�澶栭儴椤甸潰鍦板潃
 
+              if (names.has(trdItem.menu_name)) {
+                doublenames.set(trdItem.menu_name, true)
+              } else {
+                names.set(trdItem.menu_name, true)
+              }
+
               thdMenuList.push(trdItem)
 
               return trdItem
@@ -309,6 +264,13 @@
       }
 
       menulist.push(fstItem)
+    })
+
+    thdMenuList = thdMenuList.map(item => {
+      if (doublenames.has(item.menu_name)) {
+        item.menu_name += '锛�' + item.ParentNames.join('-') + '锛�'
+      }
+      return item
     })
 
     return { menulist, thdMenuList }
@@ -594,23 +556,23 @@
     const menu = (
       <Menu className="header-dropdown">
         {debug && <Menu.Item key="switch">
-          {this.state.dict['main.edit']}
+          缂栬緫
           <Switch size="small" style={{marginLeft: '7px'}} checked={false} onChange={this.changeEditState} />
         </Menu.Item>}
-        <Menu.Item key="password" onClick={this.changePassword}>{this.state.dict['main.password']}</Menu.Item>
+        <Menu.Item key="password" onClick={this.changePassword}>淇敼瀵嗙爜</Menu.Item>
         {this.state.systems.length ? <Menu.SubMenu style={{minWidth: '110px'}} title="鍒囨崲绯荤粺">
           {this.state.systems.map((system, index) => (
             <Menu.Item style={{minWidth: '100px', lineHeight: '30px'}} key={'sub' + index} onClick={() => {this.changeSystem(system)}}> {system.AppName} </Menu.Item>
           ))}
         </Menu.SubMenu> : null}
-        <Menu.Item key="doc" onClick={this.gotoDoc}>{this.state.dict['main.doc']}</Menu.Item>
+        <Menu.Item key="doc" onClick={this.gotoDoc}>鏂囨。涓績</Menu.Item>
         <Menu.Item key="verup" onClick={this.verup}>
           椤甸潰鏇存柊
         </Menu.Item>
         {appVersion ? <Menu.Item key="version" onClick={this.about}>
           鍏充簬
         </Menu.Item> : null}
-        <Menu.Item key="logout" onClick={this.logout}>{this.state.dict['main.logout']}</Menu.Item>
+        <Menu.Item key="logout" onClick={this.logout}>閫�鍑�</Menu.Item>
       </Menu>
     )
 
@@ -740,12 +702,12 @@
                         option.MenuNo.toLowerCase().indexOf(searchkey.toLowerCase()) >= 0 ||
                         option.EasyCode.toLowerCase().indexOf(searchkey.toLowerCase()) >= 0
                       ) {
-                        return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.MenuName}</Menu.Item>
+                        return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.menu_name}</Menu.Item>
                       } else {
                         return null
                       }
                     }
-                    return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.MenuName}</Menu.Item>
+                    return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.menu_name}</Menu.Item>
                   })}
                 </Menu>
               </div>
@@ -763,29 +725,20 @@
             </span>
           </div>
         </Dropdown>
-        {/* 淇敼瀵嗙爜 */}
-        <Modal
-          title={this.state.dict['main.password']}
-          visible={this.state.visible}
-          onOk={this.resetPwdSubmit}
-          confirmLoading={this.state.confirmLoading}
-          onCancel={this.handleCancel}
-          destroyOnClose
-        >
-          <Resetpwd dict={this.state.dict} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
-        </Modal>
         {/* 缂栬緫鐘舵�佺櫥褰� */}
         <Modal
-          title={this.state.dict['main.login.develop']}
+          title="鐧诲綍寮�鍙戞満"
           visible={this.state.loginVisible}
           onOk={this.loginSubmit}
           width={'430px'}
           confirmLoading={this.state.loginLoading}
           onCancel={() => {this.setState({ loginVisible: false, loginLoading: false })}}
           destroyOnClose
-        >
+          >
           <LoginForm handleSubmit={() => this.loginSubmit()} wrappedComponentRef={(inst) => this.loginRef = inst}/>
         </Modal>
+        {/* 淇敼瀵嗙爜 */}
+        <Resetpwd />
       </header>
     )
   }
diff --git a/src/components/header/resetpwd/index.jsx b/src/components/header/resetpwd/index.jsx
deleted file mode 100644
index f796811..0000000
--- a/src/components/header/resetpwd/index.jsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import React, {Component} from 'react'
-import { Form, Input } from 'antd'
-
-class Resetpwd extends Component {
-  state = {
-    confirmDirty: false,
-    autoCompleteResult: [],
-    level: localStorage.getItem(window.location.href.split('#')[0] + 'pwdlevel') || ''
-  }
-
-  onEnterSubmit = (e) => {
-    // 琛ㄥ崟鍥炶溅鎻愪氦
-    if (e.key !== 'Enter') return
-    
-    if (!this.props.form.getFieldValue('originpwd')) {
-      this.focusInput('originpwd')
-    } else if (!this.props.form.getFieldValue('password')) {
-      this.focusInput('password')
-    } else if (!this.props.form.getFieldValue('confirm')) {
-      this.focusInput('confirm')
-    } else {
-      this.props.resetPwdSubmit()
-    }
-  }
-
-  focusInput = (selectId) => {
-    let _form = document.getElementById('reset-password-form')
-    let _inputs = _form.getElementsByTagName('input')
-    _inputs = [..._inputs]
-    _inputs.forEach(input => {
-      if (!input || input.id !== selectId) return
-
-      if (input.focus) {
-        input.focus()
-      }
-    })
-  }
-
-  handleConfirm = () => {
-    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
-    return new Promise((resolve, reject) => {
-      this.props.form.validateFieldsAndScroll((err, values) => {
-        if (!err) {
-          resolve(values)
-        } else {
-          reject(err)
-        }
-      })
-    })
-  }
-
-  handleConfirmBlur = e => {
-    const { value } = e.target
-    this.setState({ confirmDirty: this.state.confirmDirty || !!value })
-  }
-
-  compareToFirstPassword = (rule, value, callback) => {
-    const { form } = this.props
-    if (value && value !== form.getFieldValue('password')) {
-      callback('涓ゆ杈撳叆瀵嗙爜涓嶄竴鑷达紒')
-    } else {
-      callback()
-    }
-  }
-
-  validateToNextPassword = (rule, value, callback) => {
-    const { form } = this.props
-    const { level } = this.state
-
-    if (value && this.state.confirmDirty) {
-      form.validateFields(['confirm'], { force: true })
-    }
-
-    if (level === 'letter_num' && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*)$/.test(value)) {
-      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛楀拰瀛楁瘝銆�')
-    } else if ((level === 'char_num' || level === 'char_num_90' || level === 'char_num_90_sms') && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(value)) {
-      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛椼�佸瓧姣嶅拰鐗规畩瀛楃銆�')
-    } else {
-      callback()
-    }
-  }
-
-  render() {
-    const { getFieldDecorator } = this.props.form
-    const { level } = this.state
-
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 14 }
-      }
-    }
-
-    let rules = []
-    if (level) {
-      rules.push({
-        min: 8,
-        message: '瀵嗙爜闀垮害涓嶅彲灏忎簬8浣嶏紒'
-      })
-    }
-
-    return (
-      <Form {...formItemLayout} onKeyDown={this.onEnterSubmit} id="reset-password-form">
-        <Form.Item label="鍘熷瘑鐮�">
-          {getFieldDecorator('originpwd', {
-            rules: [
-              {
-                required: true,
-                message: '璇疯緭鍏ュ師瀵嗙爜锛�'
-              }
-            ]
-          })(<Input.Password autoFocus/>)}
-        </Form.Item>
-        <Form.Item label="鏂板瘑鐮�" hasFeedback>
-          {getFieldDecorator('password', {
-            rules: [
-              {
-                required: true,
-                message: '璇疯緭鍏ユ柊瀵嗙爜锛�'
-              },
-              {
-                pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
-                message: '瀵嗙爜鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶄互鍙�!@#$%&*()_銆�'
-              },
-              ...rules,
-              {
-                max: 50,
-                message: '鏈�澶у瘑鐮侀暱搴︿负50浣嶏紒'
-              },
-              {
-                validator: this.validateToNextPassword
-              }
-            ]
-          })(<Input.Password />)}
-        </Form.Item>
-        <Form.Item label="纭瀵嗙爜" hasFeedback>
-          {getFieldDecorator('confirm', {
-            rules: [
-              {
-                required: true,
-                message: '璇风‘璁ゅ瘑鐮侊紒'
-              },
-              {
-                validator: this.compareToFirstPassword
-              }
-            ]
-          })(<Input.Password onBlur={this.handleConfirmBlur} />)}
-        </Form.Item>
-      </Form>
-    )
-  }
-}
-
-export default Form.create()(Resetpwd)
\ No newline at end of file
diff --git a/src/components/resetPassword/index.jsx b/src/components/resetPassword/index.jsx
new file mode 100644
index 0000000..a72283a
--- /dev/null
+++ b/src/components/resetPassword/index.jsx
@@ -0,0 +1,182 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Modal, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import Resetpwd from './resetpwd'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class ResetPassword extends Component {
+  state = {
+    visible: false,
+    loading: false,
+    type: 'account',
+    okText: '纭畾',
+    smsId: '',
+    mob: '',
+    code: ''
+  }
+
+  callback = null
+
+  componentDidMount() {
+    MKEmitter.addListener('resetpassword', this.resetpassword)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+  
+  componentWillUnmount() {
+    MKEmitter.removeListener('resetpassword', this.resetpassword)
+  }
+
+  resetpassword = (callback) => {
+    this.callback = callback
+    this.setState({
+      visible: true,
+      loading: false,
+      type: 'account',
+      okText: '纭畾',
+      mob: '',
+      code: '',
+      smsId: sessionStorage.getItem('mk_sms_id') || ''
+    })
+  }
+
+  resetPwdSubmit = () => {
+    const { type } = this.state
+
+    if (type === 'account') {
+      this.formRef.handleConfirm().then(res => {
+        this.setState({
+          loading: true
+        })
+  
+        let _param = {
+          func: 's_PwdUpt',
+          LText: `select '${res.originpwd}','${res.password}'`
+        }
+        
+        _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
+        _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
+        _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
+    
+        Api.getSystemConfig(_param).then(result => {
+          if (result.status) {
+            this.setState({
+              visible: false,
+              loading: false
+            })
+            notification.success({
+              top: 92,
+              message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
+              duration: 2
+            })
+            this.callback && this.callback()
+          } else {
+            this.setState({
+              loading: false
+            })
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+        })
+      }, () => {})
+    } else if (type === 'mob') {
+      this.formRef.handleConfirm().then(res => {
+        if (!/^1[3456789]\d{9}$/.test(res.phone)) {
+          notification.warning({
+            top: 92,
+            message: '鎵嬫満鍙锋牸寮忛敊璇紝璇烽噸濉紒',
+            duration: 5
+          })
+          return
+        }
+
+        this.setState({
+          mob: res.phone,
+          type: 'code'
+        })
+      }, () => {})
+    } else if (type === 'code') {
+      this.formRef.handleConfirm().then(res => {
+        this.setState({
+          code: res.vercode,
+          type: 'phonepwd',
+          okText: '纭畾'
+        })
+      }, () => {})
+    } else if (type === 'phonepwd') {
+      this.formRef.handleConfirm().then(res => {
+        this.setState({
+          loading: true
+        })
+  
+        let _param = {
+          func: 's_PwdUpt',
+          LText: `select '','${res.password}'`,
+          mob: this.state.mob,
+          check_code: this.state.code
+        }
+        
+        _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
+        _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
+        _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
+    
+        Api.getSystemConfig(_param).then(result => {
+          if (result.status) {
+            this.setState({
+              visible: false,
+              loading: false
+            })
+            notification.success({
+              top: 92,
+              message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
+              duration: 2
+            })
+            this.callback && this.callback()
+          } else {
+            this.setState({
+              loading: false
+            })
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+        })
+      }, () => {})
+    }
+  }
+
+  render() {
+    const { visible, loading, okText, type, mob, smsId } = this.state
+
+    return (
+      <Modal
+        title="淇敼瀵嗙爜"
+        wrapClassName="reset-password-modal"
+        visible={visible}
+        maskClosable={false}
+        onOk={this.resetPwdSubmit}
+        onCancel={() => { this.setState({ visible: false })}}
+        okText={okText}
+        confirmLoading={loading}
+        destroyOnClose
+      >
+        <Resetpwd type={type} mob={mob} smsId={smsId} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
+        {type === 'account' && smsId ? <div className="forget-pwd"><span onClick={() => this.setState({type: 'mob', okText: '涓嬩竴姝�'})}>蹇樿瀵嗙爜锛�</span></div> : null}
+      </Modal>
+    )
+  }
+}
+
+export default ResetPassword
\ No newline at end of file
diff --git a/src/components/resetPassword/index.scss b/src/components/resetPassword/index.scss
new file mode 100644
index 0000000..f943fa2
--- /dev/null
+++ b/src/components/resetPassword/index.scss
@@ -0,0 +1,22 @@
+.reset-password-modal {
+  .ant-modal {
+    top: 70px;
+  }
+  .ant-modal-body {
+    min-height: 150px;
+
+    .forget-pwd {
+      text-align: right;
+      padding-right: 40px;
+      color: #1890ff;
+      span {
+        cursor: pointer;
+      }
+    }
+    .vercode-line {
+      .ant-form-item-control-wrapper {
+        margin-left: 8.3%;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/components/resetPassword/resetpwd/index.jsx b/src/components/resetPassword/resetpwd/index.jsx
new file mode 100644
index 0000000..ee7a60a
--- /dev/null
+++ b/src/components/resetPassword/resetpwd/index.jsx
@@ -0,0 +1,317 @@
+import React, {Component} from 'react'
+import { Form, Input, Button, message } from 'antd'
+import moment from 'moment'
+import md5 from 'md5'
+
+import Api from '@/api'
+
+class Resetpwd extends Component {
+  state = {
+    confirmDirty: false,
+    autoCompleteResult: [],
+    level: localStorage.getItem(window.location.href.split('#')[0] + 'pwdlevel') || ''
+  }
+
+  LoginTimer = null
+
+  onEnterSubmit = (e) => {
+    // 琛ㄥ崟鍥炶溅鎻愪氦
+    if (e.key !== 'Enter') return
+    
+    if (!this.props.form.getFieldValue('originpwd')) {
+      this.focusInput('originpwd')
+    } else if (!this.props.form.getFieldValue('password')) {
+      this.focusInput('password')
+    } else if (!this.props.form.getFieldValue('confirm')) {
+      this.focusInput('confirm')
+    } else {
+      this.props.resetPwdSubmit()
+    }
+  }
+
+  focusInput = (selectId) => {
+    let _form = document.getElementById('reset-password-form')
+    let _inputs = _form.getElementsByTagName('input')
+    _inputs = [..._inputs]
+    _inputs.forEach(input => {
+      if (!input || input.id !== selectId) return
+
+      if (input.focus) {
+        input.focus()
+      }
+    })
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleConfirmBlur = e => {
+    const { value } = e.target
+    this.setState({ confirmDirty: this.state.confirmDirty || !!value })
+  }
+
+  compareToFirstPassword = (rule, value, callback) => {
+    const { form } = this.props
+    if (value && value !== form.getFieldValue('password')) {
+      callback('涓ゆ杈撳叆瀵嗙爜涓嶄竴鑷达紒')
+    } else {
+      callback()
+    }
+  }
+
+  validateToNextPassword = (rule, value, callback) => {
+    const { form } = this.props
+    const { level } = this.state
+
+    if (value && this.state.confirmDirty) {
+      form.validateFields(['confirm'], { force: true })
+    }
+
+    if (level === 'letter_num' && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*)$/.test(value)) {
+      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛楀拰瀛楁瘝銆�')
+    } else if ((level === 'char_num' || level === 'char_num_90' || level === 'char_num_90_sms') && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(value)) {
+      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛椼�佸瓧姣嶅拰鐗规畩瀛楃銆�')
+    } else {
+      callback()
+    }
+  }
+
+  getvercode = () => {
+    const { mob, smsId } = this.props
+
+    let _param = {
+      func: 'mes_sms_send_code_sso',
+      send_type: 'reset_pwd',
+      mob: mob,
+      ID: smsId
+    }
+    _param.LText = 'minke'
+    _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    _param.secretkey = md5(`${_param.LText}mingke${_param.timestamp}`)
+    
+    _param.userid = sessionStorage.getItem('visitorUserID') || ''
+    _param.LoginUID = sessionStorage.getItem('visitorLoginUID') || ''
+
+    Api.getSystemConfig(_param).then(res => {
+      if (!res.status || !res.n_id) {
+        message.warning(res.message || '楠岃瘉鐮佽幏鍙栧け璐ワ紒')
+        return
+      }
+
+      let param = {
+        func: 'MSN_sms_send_code',
+        send_type: 'reset_pwd',
+        mob: mob,
+        timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+        ID: smsId,
+        n_id: res.n_id
+      }
+  
+      param.LText = md5(`${mob}mingke${window.GLOB.appkey}${param.timestamp}`)
+      param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
+
+      param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
+      param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
+      param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
+  
+      this.setState({
+        verdisabled: true,
+        delay: 60
+      })
+
+      this.LoginTimer = setTimeout(this.resetVerCodeDelay, 1000)
+  
+      Api.genericInterface(param).then(res => {
+        if (res.status) {
+  
+        } else {
+          clearTimeout(this.LoginTimer)
+          this.setState({
+            verdisabled: false,
+            delay: null
+          })
+          message.warning(res.message)
+        }
+      }, () => {
+        clearTimeout(this.LoginTimer)
+        this.setState({
+          verdisabled: false,
+          delay: null
+        })
+      })
+    })
+  }
+
+  resetVerCodeDelay = () => {
+    const { delay } = this.state
+    if (delay && delay > 1) {
+      this.setState({delay: delay - 1})
+      this.LoginTimer = setTimeout(this.resetVerCodeDelay, 1000)
+    } else {
+      this.setState({
+        verdisabled: false,
+        delay: null
+      })
+    }
+  }
+
+  render() {
+    const { type } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { level, delay, verdisabled } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    let rules = []
+    if (level) {
+      rules.push({
+        min: 8,
+        message: '瀵嗙爜闀垮害涓嶅彲灏忎簬8浣嶏紒'
+      })
+    }
+
+    return (
+      <>
+        {type === 'account' ? <Form {...formItemLayout} onKeyDown={this.onEnterSubmit} id="reset-password-form">
+          <Form.Item label="鍘熷瘑鐮�">
+            {getFieldDecorator('originpwd', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ュ師瀵嗙爜锛�'
+                }
+              ]
+            })(<Input.Password autoFocus/>)}
+          </Form.Item>
+          <Form.Item label="鏂板瘑鐮�" hasFeedback>
+            {getFieldDecorator('password', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ柊瀵嗙爜锛�'
+                },
+                {
+                  pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
+                  message: '瀵嗙爜鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶄互鍙�!@#$%&*()_銆�'
+                },
+                ...rules,
+                {
+                  max: 50,
+                  message: '鏈�澶у瘑鐮侀暱搴︿负50浣嶏紒'
+                },
+                {
+                  validator: this.validateToNextPassword
+                }
+              ]
+            })(<Input.Password />)}
+          </Form.Item>
+          <Form.Item label="纭瀵嗙爜" hasFeedback>
+            {getFieldDecorator('confirm', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇风‘璁ゅ瘑鐮侊紒'
+                },
+                {
+                  validator: this.compareToFirstPassword
+                }
+              ]
+            })(<Input.Password onBlur={this.handleConfirmBlur} />)}
+          </Form.Item>
+        </Form> : null}
+        {type === 'phonepwd' ? <Form {...formItemLayout} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
+          <Form.Item label="鏂板瘑鐮�" hasFeedback>
+            {getFieldDecorator('password', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ柊瀵嗙爜锛�'
+                },
+                {
+                  pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
+                  message: '瀵嗙爜鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶄互鍙�!@#$%&*()_銆�'
+                },
+                ...rules,
+                {
+                  max: 50,
+                  message: '鏈�澶у瘑鐮侀暱搴︿负50浣嶏紒'
+                },
+                {
+                  validator: this.validateToNextPassword
+                }
+              ]
+            })(<Input.Password />)}
+          </Form.Item>
+          <Form.Item label="纭瀵嗙爜" hasFeedback>
+            {getFieldDecorator('confirm', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇风‘璁ゅ瘑鐮侊紒'
+                },
+                {
+                  validator: this.compareToFirstPassword
+                }
+              ]
+            })(<Input.Password onBlur={this.handleConfirmBlur} />)}
+          </Form.Item>
+        </Form> : null}
+        {type === 'mob' ? <Form {...formItemLayout} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
+          <Form.Item label="鎵嬫満鍙�">
+            {getFieldDecorator('phone', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ墜鏈哄彿锛�'
+                }
+              ]
+            })(<Input placeholder="璇疯緭鍏ユ墜鏈哄彿" autoComplete="off" />)}
+          </Form.Item>
+        </Form> : null}
+        {type === 'code' ? <Form wrapperCol={{ xs: { span: 24 }, sm: { span: 20 }}} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
+          <Form.Item className="vercode-line" label="">
+            {getFieldDecorator('vercode', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ラ獙璇佺爜锛�'
+                }
+              ]
+            })(<Input
+              addonAfter={
+                <Button type="link" size="small" disabled={verdisabled} onClick={this.getvercode}>
+                  {delay ? `${delay}s鍚庨噸鏂拌幏鍙朻 : '鑾峰彇楠岃瘉鐮�'}
+                </Button>
+              }
+              placeholder="璇疯緭鍏ラ獙璇佺爜"
+              autoComplete="off"
+            />)}
+          </Form.Item>
+        </Form> : null}
+      </>
+    )
+  }
+}
+
+export default Form.create()(Resetpwd)
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 278a82b..2651e0b 100644
--- a/src/index.js
+++ b/src/index.js
@@ -110,7 +110,10 @@
 
       GLOB.mainSystemApi = 'https://cloud.positecgroup.com/webapi/dostars'
 
-      // GLOB.mainSystemApi = 'http://sso.mk9h.cn/cloud/webapi/dostars'
+      // GLOB.mainSystemApi = 'https://sso.mk9h.cn/cloud/webapi/dostars'
+      // if (!/^https/.test(window.location.protocol)) { // https杞崲
+      //   GLOB.mainSystemApi = 'http://sso.mk9h.cn/cloud/webapi/dostars'
+      // }
 
       if (GLOB.watermark) {
         GLOB.dataFormat = true
@@ -287,6 +290,7 @@
     })
 
     window.GLOB.CacheMap = new Map()     // 缂撳瓨閰嶇疆淇℃伅
+    window.GLOB.CacheVoucher = new Map() // 缂撳瓨鍑瘉淇℃伅
     window.GLOB.UserCacheMap = new Map() // 缂撳瓨鐢ㄦ埛鑷畾涔夎缃�
     window.GLOB.CacheData = new Map()    // 瀛樺偍閫変腑鏁版嵁
 
diff --git a/src/locales/en-US/login.js b/src/locales/en-US/login.js
index f2df2c1..9abd3b6 100644
--- a/src/locales/en-US/login.js
+++ b/src/locales/en-US/login.js
@@ -8,8 +8,6 @@
   'login.phone.empty': 'Please enter your cell phone number!',
   'login.vercode': 'Verification code',
   'login.vercode.empty': 'Please enter your verification code!',
-  'login.vercode.query': 'Get verify code',
-  'login.vercode.queryagain': 'Obtain again after @s',
   'login.password': 'Password',
   'login.password.empty': 'Please input your Password!',
   'login.remember': 'Remember me',
diff --git a/src/locales/en-US/main.js b/src/locales/en-US/main.js
index 2a9103e..1b18f24 100644
--- a/src/locales/en-US/main.js
+++ b/src/locales/en-US/main.js
@@ -1,17 +1,11 @@
 export default {
   'main.search': 'Search',
   'main.reset': 'Reset',
-  'main.edit': 'Edit',
   'main.confirm': 'OK',
   'main.submit': 'Submit',
   'main.return': 'Return',
   'main.close': 'Close',
   'main.cancel': 'Cancel',
-  'main.logout': 'Logout',
-  'main.doc': '鏂囨。涓績',
-  'main.logout.hint': 'Are you sure you want to log out?',
-  'main.password': 'Change the password',
-  'main.login.develop': 'Login developer',
   'main.revert.default': 'Restore default Settings',
   'main.copy.success': 'Copy success',
   'main.pagination.of': 'of',
diff --git a/src/locales/zh-CN/login.js b/src/locales/zh-CN/login.js
index 321aa63..ea06d7a 100644
--- a/src/locales/zh-CN/login.js
+++ b/src/locales/zh-CN/login.js
@@ -8,8 +8,6 @@
   'login.phone.empty': '璇疯緭鍏ユ墜鏈哄彿!',
   'login.vercode': '楠岃瘉鐮�',
   'login.vercode.empty': '璇疯緭鍏ラ獙璇佺爜!',
-  'login.vercode.query': '鑾峰彇楠岃瘉鐮�',
-  'login.vercode.queryagain': '@s鍚庨噸鏂拌幏鍙�',
   'login.password': '瀵嗙爜',
   'login.password.empty': '璇疯緭鍏ュ瘑鐮�!',
   'login.remember': '璁颁綇瀵嗙爜',
diff --git a/src/locales/zh-CN/main.js b/src/locales/zh-CN/main.js
index db616d0..cf33d24 100644
--- a/src/locales/zh-CN/main.js
+++ b/src/locales/zh-CN/main.js
@@ -1,17 +1,11 @@
 export default {
   'main.search': '鎼滅储',
   'main.reset': '閲嶇疆',
-  'main.edit': '缂栬緫',
   'main.confirm': '纭畾',
   'main.submit': '鎻愪氦',
   'main.return': '杩斿洖',
   'main.close': '鍏抽棴',
   'main.cancel': '鍙栨秷',
-  'main.logout': '閫�鍑�',
-  'main.doc': '鏂囨。涓績',
-  'main.logout.hint': '鎮ㄧ‘瀹氳閫�鍑哄悧?',
-  'main.password': '淇敼瀵嗙爜',
-  'main.login.develop': '鐧诲綍寮�鍙戞満',
   'main.revert.default': '鎭㈠榛樿璁剧疆',
   'main.copy.success': '澶嶅埗鎴愬姛',
   'main.pagination.of': '鍏�',
diff --git a/src/menu/components/card/balcony/index.jsx b/src/menu/components/card/balcony/index.jsx
index 4c89067..c0986a3 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 { Popover, Checkbox } from 'antd'
+import { Popover, Checkbox, message } from 'antd'
 import { PlusOutlined, PlusSquareOutlined, EditOutlined, FontColorsOutlined, DeleteOutlined, SettingOutlined, ToolOutlined, ClockCircleOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -191,7 +191,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -245,9 +245,19 @@
   }
 
   getWrapForms = () => {
-    const { wrap } = this.state.card
+    const { card } = this.state
 
-    return getWrapForm(wrap)
+    let buttons = []
+    card.elements && card.elements.forEach(item => {
+      if (item.eleType === 'button') {
+        buttons.push({
+          value: item.uuid,
+          label: item.label
+        })
+      }
+    })
+
+    return getWrapForm(card.wrap, buttons, card.columns)
   }
 
   updateWrap = (res) => {
@@ -297,7 +307,15 @@
         <CardCellComponent cards={card} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/card/balcony/options.jsx b/src/menu/components/card/balcony/options.jsx
index 86b84f5..4cce86c 100644
--- a/src/menu/components/card/balcony/options.jsx
+++ b/src/menu/components/card/balcony/options.jsx
@@ -4,7 +4,7 @@
 /**
  * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
  */
-export default function (wrap) {
+export default function (wrap, buttons, columns) {
   let menu = window.GLOB.customMenu
 
   let modules = MenuUtils.getLinkModules(menu.components) || []
@@ -69,6 +69,7 @@
       controlFields: [
         {field: 'empty', values: ['dynamic']},
         {field: 'publicId', values: ['public']},
+        {field: 'bgField', values: ['dynamic', 'public']},
       ]
     },
     {
@@ -248,6 +249,15 @@
       ],
     },
     {
+      type: 'select',
+      field: 'bgField',
+      label: '鑳屾櫙鍥�',
+      initval: wrap.bgField || '',
+      tooltip: '鍔ㄦ�佽儗鏅紝鑳屾櫙鍥剧墖鐢卞瓧娈靛�兼帶鍒躲�傝娉ㄦ剰璋冩暣鑳屾櫙鏍峰紡銆�',
+      required: false,
+      options: columns
+    },
+    {
       type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
@@ -260,6 +270,14 @@
       forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
     },
     {
+      type: 'select',
+      field: 'linkbtn',
+      label: '鍏宠仈鎸夐挳',
+      initval: wrap.linkbtn || '',
+      required: false,
+      options: buttons
+    },
+    {
       type: 'multiselect',
       field: 'blacklist',
       label: '榛戝悕鍗�',
diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx
index a71506f..f3d2af6 100644
--- a/src/menu/components/card/cardcellcomponent/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/index.jsx
@@ -149,6 +149,7 @@
         options = ['margin', 'float']
       } else {
         options.push('width', 'minHeight', 'float')
+        _style.minHeight = _style.minHeight || '28px'
       }
       if (element.wrapStyle) {
         _style.float = element.wrapStyle.textAlign || 'left'
diff --git a/src/menu/components/card/cardcomponent/options.jsx b/src/menu/components/card/cardcomponent/options.jsx
index f93e6f2..f3f79aa 100644
--- a/src/menu/components/card/cardcomponent/options.jsx
+++ b/src/menu/components/card/cardcomponent/options.jsx
@@ -109,7 +109,8 @@
       initval: setting.bgField || '',
       tooltip: '鍔ㄦ�佽儗鏅紝鑳屾櫙鍥剧墖鐢卞瓧娈靛�兼帶鍒躲�傝娉ㄦ剰璋冩暣鑳屾櫙鏍峰紡銆�',
       required: false,
-      options: columns
+      options: columns,
+      forbid: cardType === 'extendCard'
     },
     {
       type: ops.length === 0 ? 'radio' : 'select',
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index 46d05a9..d7f18a7 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/src/menu/components/card/data-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal, Pagination } from 'antd'
+import { Popover, Modal, Pagination, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, DownOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -288,7 +288,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'height', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'height', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -491,9 +491,9 @@
 
       let elements = []
       res.elements && res.elements.forEach(cell => {
-        if (cell.datatype === 'dynamic') {
-          cell.datatype = 'static'
-        }
+        // if (cell.datatype === 'dynamic') {
+        //   cell.datatype = 'static'
+        // }
 
         if (cell.eleType !== 'button') {
           cell.uuid = Utils.getuuid()
@@ -512,9 +512,9 @@
 
       if (appType !== 'mob') {
         res.backElements && res.backElements.forEach(cell => {
-          if (cell.datatype === 'dynamic') {
-            cell.datatype = 'static'
-          }
+          // if (cell.datatype === 'dynamic') {
+          //   cell.datatype = 'static'
+          // }
 
           if (cell.eleType !== 'button') {
             cell.uuid = Utils.getuuid()
@@ -623,7 +623,15 @@
         {card.wrap.pagestyle === 'more' && card.setting.laypage === 'true' ? <div className="mk-more">鏌ョ湅鏇村<DownOutlined/></div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/card/data-card/options.jsx b/src/menu/components/card/data-card/options.jsx
index 49358f7..a01a35f 100644
--- a/src/menu/components/card/data-card/options.jsx
+++ b/src/menu/components/card/data-card/options.jsx
@@ -282,6 +282,19 @@
     },
     {
       type: 'radio',
+      field: 'parity',
+      label: '濂囧伓鑳屾櫙',
+      initval: wrap.parity || 'false',
+      tooltip: '鍋舵暟琛屼細娣诲姞鑳屾櫙鑹层��',
+      required: false,
+      options: [
+        {value: 'false', label: '鏃�'},
+        {value: 'true', label: '鏈�'},
+      ],
+      forbid: subtype === 'propcard'
+    },
+    {
+      type: 'radio',
       field: 'printType',
       label: '缁勪欢绫诲瀷',
       initval: wrap.printType || 'content',
diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx
index 909dfa3..5508f0a 100644
--- a/src/menu/components/card/prop-card/index.jsx
+++ b/src/menu/components/card/prop-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal } from 'antd'
+import { Popover, Modal, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, ClockCircleOutlined, HeatMapOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -304,7 +304,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -530,7 +530,15 @@
         {card.wrap.display === 'hidden' ? <HeatMapOutlined className="prop-hidden"/> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/card/table-card/index.jsx b/src/menu/components/card/table-card/index.jsx
index 5596f30..3c014f4 100644
--- a/src/menu/components/card/table-card/index.jsx
+++ b/src/menu/components/card/table-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal, Pagination } from 'antd'
+import { Popover, Modal, Pagination, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, DownOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -254,7 +254,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -513,7 +513,15 @@
         {card.setting.laypage === 'true' && card.wrap.pagestyle === 'more' ? <div className="mk-more">鏌ョ湅鏇村<DownOutlined/></div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/carousel/data-card/index.jsx b/src/menu/components/carousel/data-card/index.jsx
index dceb119..5a1eee0 100644
--- a/src/menu/components/carousel/data-card/index.jsx
+++ b/src/menu/components/carousel/data-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal } from 'antd'
+import { Popover, Modal, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -268,7 +268,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/carousel/prop-card/index.jsx b/src/menu/components/carousel/prop-card/index.jsx
index 8efdbe0..9b25463 100644
--- a/src/menu/components/carousel/prop-card/index.jsx
+++ b/src/menu/components/carousel/prop-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal, Carousel } from 'antd'
+import { Popover, Modal, Carousel, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, ClockCircleOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -338,7 +338,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-G6/index.jsx b/src/menu/components/chart/antv-G6/index.jsx
index 82d8bf3..81c0e09 100644
--- a/src/menu/components/chart/antv-G6/index.jsx
+++ b/src/menu/components/chart/antv-G6/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import G6 from '@antv/g6'
 
@@ -1424,7 +1424,15 @@
         <div className="canvas" id={card.uuid + 'canvas'} ref={ref => this.wrap = ref}></div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx
index 082b5fa..8f865eb 100644
--- a/src/menu/components/chart/antv-bar/index.jsx
+++ b/src/menu/components/chart/antv-bar/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { PlusCircleOutlined, PlusSquareOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import { Chart } from '@antv/g2'
 import DataSet from '@antv/data-set'
@@ -1384,7 +1384,15 @@
         /> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-dashboard/index.jsx b/src/menu/components/chart/antv-dashboard/index.jsx
index 33c7c2e..b66d1d3 100644
--- a/src/menu/components/chart/antv-dashboard/index.jsx
+++ b/src/menu/components/chart/antv-dashboard/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import { Chart, registerShape } from '@antv/g2'
 
@@ -553,7 +553,15 @@
         <div className="canvas" id={card.uuid + 'dashboard'}></div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-pie/index.jsx b/src/menu/components/chart/antv-pie/index.jsx
index a7e3f8a..3f269b4 100644
--- a/src/menu/components/chart/antv-pie/index.jsx
+++ b/src/menu/components/chart/antv-pie/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined, PlusCircleOutlined } from '@ant-design/icons'
 import { Chart } from '@antv/g2'
 import DataSet, { DataView } from '@antv/data-set'
@@ -727,7 +727,15 @@
         <div className="canvas" id={card.uuid + 'canvas'}></div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-scatter/index.jsx b/src/menu/components/chart/antv-scatter/index.jsx
index 2534961..79b4684 100644
--- a/src/menu/components/chart/antv-scatter/index.jsx
+++ b/src/menu/components/chart/antv-scatter/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined, PlusCircleOutlined, PlusSquareOutlined } from '@ant-design/icons'
 import { Chart } from '@antv/g2'
 
@@ -399,7 +399,15 @@
         {appType !== 'mob' ? <ActionComponent config={card} updateaction={this.updateComponent}/> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/code/sandbox/index.jsx b/src/menu/components/code/sandbox/index.jsx
index d633dd7..cced2c3 100644
--- a/src/menu/components/code/sandbox/index.jsx
+++ b/src/menu/components/code/sandbox/index.jsx
@@ -128,7 +128,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
diff --git a/src/menu/components/editor/braft-editor/index.jsx b/src/menu/components/editor/braft-editor/index.jsx
index b032aec..21d0ab9 100644
--- a/src/menu/components/editor/braft-editor/index.jsx
+++ b/src/menu/components/editor/braft-editor/index.jsx
@@ -46,7 +46,7 @@
         name: card.name,
         subtype: card.subtype,
         setting: { interType: 'system' },
-        wrap: { name: card.name, datatype: 'dynamic', width: card.width || 24, encryption: 'true', minHeight: 100 },
+        wrap: { name: card.name, datatype: 'dynamic', width: card.width || 24, encryption: 'true' },
         style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
         headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
         columns: [],
@@ -128,7 +128,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -164,9 +164,6 @@
     const { card } = this.state
 
     let style = {...card.style}
-    if (card.wrap.minHeight) {
-      style.minHeight = card.wrap.minHeight
-    }
 
     return (
       <div className="menu-normal-editor-box" style={style} onClick={this.clickComponent} id={card.uuid}>
diff --git a/src/menu/components/editor/braft-editor/options.jsx b/src/menu/components/editor/braft-editor/options.jsx
index 9e7094f..f788ef9 100644
--- a/src/menu/components/editor/braft-editor/options.jsx
+++ b/src/menu/components/editor/braft-editor/options.jsx
@@ -80,16 +80,6 @@
       ]
     },
     {
-      type: 'number',
-      field: 'minHeight',
-      label: '鏈�灏忛珮搴�',
-      initval: wrap.minHeight || '',
-      min: 0,
-      max: 3000,
-      precision: 0,
-      required: false
-    },
-    {
       type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
diff --git a/src/menu/components/form/simple-form/index.jsx b/src/menu/components/form/simple-form/index.jsx
index a6de6f5..5848926 100644
--- a/src/menu/components/form/simple-form/index.jsx
+++ b/src/menu/components/form/simple-form/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal, Button, Switch, notification } from 'antd'
+import { Popover, Modal, Button, Switch, notification, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -194,7 +194,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -687,7 +687,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/form/step-form/index.jsx b/src/menu/components/form/step-form/index.jsx
index 55dd906..a10ff62 100644
--- a/src/menu/components/form/step-form/index.jsx
+++ b/src/menu/components/form/step-form/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal, Button, Switch, notification } from 'antd'
+import { Popover, Modal, Button, Switch, notification, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -201,7 +201,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -770,7 +770,15 @@
         </div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/form/tab-form/index.jsx b/src/menu/components/form/tab-form/index.jsx
index a354870..b3b5b18 100644
--- a/src/menu/components/form/tab-form/index.jsx
+++ b/src/menu/components/form/tab-form/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Modal, Button, Switch, notification } from 'antd'
+import { Popover, Modal, Button, Switch, notification, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -213,7 +213,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -798,7 +798,15 @@
         </div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/group/normal-group/index.jsx b/src/menu/components/group/normal-group/index.jsx
index 0544f9d..b635bea 100644
--- a/src/menu/components/group/normal-group/index.jsx
+++ b/src/menu/components/group/normal-group/index.jsx
@@ -1,8 +1,8 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Button } from 'antd'
-import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, PrinterOutlined } from '@ant-design/icons'
+import { Popover, Button, Modal } from 'antd'
+import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, PrinterOutlined, UngroupOutlined } from '@ant-design/icons'
 
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
@@ -11,6 +11,7 @@
 import getSettingForm from './options'
 import './index.scss'
 
+const { confirm } = Modal
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
@@ -21,6 +22,7 @@
   static propTpyes = {
     group: PropTypes.object,
     deletecomponent: PropTypes.func,
+    unGroup: PropTypes.func,
     updateConfig: PropTypes.func,
   }
 
@@ -70,7 +72,7 @@
   changeStyle = () => {
     const { group } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], group.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], group.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -129,6 +131,36 @@
     this.updateComponent(group)
   }
 
+  unGroup = () => {
+    const { group } = this.state
+
+    if (group.components.length === 0) return
+
+    const _this = this
+    confirm({
+      title: '纭畾閲婃斁鍒嗙粍鍏冪礌鍚楋紵',
+      content: '',
+      onOk() {
+        _this.props.unGroup(group.uuid)
+
+        setTimeout(() => {
+          _this.updataGroup()
+        }, 10)
+      },
+      onCancel() {}
+    })
+  }
+
+  updataGroup = () => {
+    const { group } = this.props
+
+    if (group.components.length === 0) {
+      this.setState({
+        group: fromJS(group).toJS()
+      })
+    }
+  }
+
   render() {
     const { group } = this.state
     let _style = resetStyle(group.style)
@@ -147,6 +179,7 @@
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="tabs" card={group}/>
+            <UngroupOutlined title="閲婃斁" style={group.components.length > 0 ? {color: '#32c5d2'} : {color: '#eeeeee', cursor: 'not-allowed'}} onClick={this.unGroup}/>
             <PasteComponent insert={this.insert} />
             <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
             <DeleteOutlined className="close" title="delete" onClick={() => this.props.deletecomponent(group.uuid)} />
diff --git a/src/menu/components/iframe/index.jsx b/src/menu/components/iframe/index.jsx
index 53645e2..d0f2d38 100644
--- a/src/menu/components/iframe/index.jsx
+++ b/src/menu/components/iframe/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Input } from 'antd'
+import { Popover, Input, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, SettingOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -173,7 +173,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/module/voucher/index.jsx b/src/menu/components/module/voucher/index.jsx
index def62fe..f1ac625 100644
--- a/src/menu/components/module/voucher/index.jsx
+++ b/src/menu/components/module/voucher/index.jsx
@@ -39,7 +39,7 @@
         name: '鍑瘉',
         subtype: card.subtype,
         // setting: { interType: 'system' },
-        wrap: { name: '鍑瘉', title: '', width: card.width || 12, type: 'edit' },
+        wrap: { name: '鍑瘉', title: '', width: card.width || 12, type: 'createVoucher' },
         style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px', paddingBottom: '20px' },
         headerStyle: {},
         columns: [],
@@ -84,7 +84,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -101,7 +101,6 @@
 
   updateWrap = (res) => {
     let _card = {...this.state.card, wrap: res}
-    _card.switchable = res.type !== 'edit'
 
     this.updateComponent(_card)
   }
@@ -123,31 +122,48 @@
           <ToolOutlined />
         </Popover>
         <div className="voucher-box">
-          <div className="voucher-header">
-            <Button className="add-background header-btn">鏂板</Button>
+          {card.wrap.type === 'createVoucher' ? <div className="voucher-header">
+            <Button className="add-background header-btn">淇濆瓨骞舵柊澧�</Button>
             <Button className="add-background header-btn">淇濆瓨</Button>
             <Button className="print-background header-btn">鎵撳嵃</Button>
-            <Button className="system-background header-btn">瀵煎叆</Button>
-            <Button className="out-background header-btn">瀵煎嚭</Button>
-          </div>
+            <Button className="out-background header-btn">鏇村</Button>
+          </div> : null}
+          {card.wrap.type === 'checkVoucher' ? <div className="voucher-header">
+            <Button className="add-background header-btn">淇濆瓨</Button>
+            <Button className="print-background header-btn">鎵撳嵃</Button>
+            <Button className="out-background header-btn">鍏抽棴</Button>
+          </div> : null}
           <div className="voucher-body">
-          <div className="pre-wrap">
-            <div className="voucher-code">
-              <div>璁�<DownOutlined/></div>
-              <div>1</div>
-              鍙�
-            </div>
-            <div className="voucher-date">
-              鏃ユ湡锛�<div>璇烽�夋嫨鏃ユ湡 <CalendarOutlined /></div>
-            </div>
-            <div className="voucher-affix">
-              闄勫崟鎹� <div>2</div> 寮�
-              <Button type="link" className="">闄勪欢</Button>
-              <Button type="link" className="">澶囨敞</Button>
-            </div>
+            {card.wrap.type === 'createVoucher' || card.wrap.type === 'checkVoucher' ? <div className="pre-wrap">
+              <div className="voucher-code">
+                <div>璁�<DownOutlined/></div>
+                <div>1</div>
+                鍙�
+              </div>
+              <div className="voucher-date">
+                鏃ユ湡锛�<div>璇烽�夋嫨鏃ユ湡 <CalendarOutlined /></div>
+              </div>
+              <div className="voucher-affix">
+                闄勫崟鎹� <div>2</div> 寮�
+                <Button type="link" className="">闄勪欢</Button>
+                <Button type="link" className="">澶囨敞</Button>
+              </div>
+            </div> : null}
+            {card.wrap.type === 'createTemp' || card.wrap.type === 'checkTemp' ? <div className="pre-wrap">
+              <div className="temp-code">
+                妯℃澘鍚嶇О:
+                <div>&nbsp;</div>
+              </div>
+              <div className="temp-code">
+                妯℃澘绫诲瀷:
+                <div>鏃ュ父鏀嚭<DownOutlined/></div>
+              </div>
+              <Button className="out-background header-btn">鍏抽棴</Button>
+              <Button className="add-background header-btn">淇濆瓨</Button>
+            </div> : null}
+            <VoucherTable config={card}/>
+            {card.wrap.type === 'createVoucher' || card.wrap.type === 'checkVoucher' ? <div className="user">鍒跺崟浜猴細</div> : null}
           </div>
-          <VoucherTable config={card}/>
-        </div>
         </div>
       </div>
     )
diff --git a/src/menu/components/module/voucher/index.scss b/src/menu/components/module/voucher/index.scss
index c7def70..98fb66f 100644
--- a/src/menu/components/module/voucher/index.scss
+++ b/src/menu/components/module/voucher/index.scss
@@ -30,7 +30,7 @@
     }
   }
   .voucher-body {
-    padding: 0 15px;
+    padding: 0 30px;
     .voucher-code {
       display: inline-block;
       width: 160px;
@@ -52,6 +52,33 @@
           margin-left: 5px;
         }
       }
+    }
+    .temp-code {
+      display: inline-block;
+      width: 180px;
+      margin-right: 15px;
+      
+      div {
+        display: inline-block;
+        min-width: 100px;
+        margin-right: 10px;
+        margin-left: 10px;
+        border: 1px solid #d9d9d9;
+        padding: 4px 10px;
+        border-radius: 4px;
+
+        .anticon-down {
+          position: relative;
+          left: 3px;
+          color: #c8c8c8;
+          font-size: 12px;
+          margin-left: 5px;
+        }
+      }
+    }
+    .header-btn {
+      float: right;
+      margin-left: 10px;
     }
     .pre-wrap {
       padding: 10px 0px;
@@ -87,6 +114,9 @@
         border-radius: 4px;
       }
     }
+    .user {
+      padding-top: 15px;
+    }
   }
 
   .add-background {
diff --git a/src/menu/components/module/voucher/options.jsx b/src/menu/components/module/voucher/options.jsx
index 343594e..b453c3c 100644
--- a/src/menu/components/module/voucher/options.jsx
+++ b/src/menu/components/module/voucher/options.jsx
@@ -29,14 +29,22 @@
     //   required: false
     // },
     {
-      type: 'radio',
+      type: 'select',
       field: 'type',
       label: '绫诲瀷',
-      initval: wrap.type || 'edit',
+      initval: wrap.type || 'createVoucher',
       required: true,
       options: [
-        {value: 'edit', label: '缂栬緫'},
-        {value: 'check', label: '鏌ョ湅'},
+        {value: 'createVoucher', label: '鏂板鍑瘉'},
+        {value: 'checkVoucher', label: '鏌ョ湅鍑瘉'},
+        {value: 'createTemp', label: '鏂板妯℃澘'},
+        {value: 'checkTemp', label: '缂栬緫妯℃澘'},
+      ],
+      controlFields: [
+        {field: 'businessType', values: ['createVoucher', 'checkVoucher']},
+        {field: 'voucherType', values: ['createVoucher', 'checkVoucher']},
+        {field: 'voucherTypeText', values: ['createVoucher', 'checkVoucher']},
+        {field: 'voucherSign', values: ['createVoucher', 'checkVoucher']},
       ]
     },
     {
@@ -68,6 +76,34 @@
       allowClear: true
     },
     {
+      type: 'text',
+      field: 'businessType',
+      label: '涓氬姟绫诲瀷',
+      initval: wrap.businessType || 'fcc01',
+      required: true
+    },
+    {
+      type: 'text',
+      field: 'voucherType',
+      label: '鍑瘉绫诲瀷',
+      initval: wrap.voucherType || 'fcc_keeping',
+      required: true
+    },
+    {
+      type: 'text',
+      field: 'voucherTypeText',
+      label: '鍑瘉绫诲瀷鏂囨湰',
+      initval: wrap.voucherTypeText || '璁拌处鍑瘉',
+      required: true
+    },
+    {
+      type: 'text',
+      field: 'voucherSign',
+      label: '鍑瘉绫诲瀷鏍囪瘑',
+      initval: wrap.voucherSign || 'fcc_keeping',
+      required: true
+    },
+    {
       type: 'cascader',
       field: 'supModule',
       label: '涓婄骇缁勪欢',
diff --git a/src/menu/components/search/main-search/index.jsx b/src/menu/components/search/main-search/index.jsx
index 8407229..fe83c62 100644
--- a/src/menu/components/search/main-search/index.jsx
+++ b/src/menu/components/search/main-search/index.jsx
@@ -1,7 +1,7 @@
 import React, { Component } from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Modal, notification, Popover, Switch } from 'antd'
+import { Modal, notification, Popover, Switch, message } from 'antd'
 import { PlusOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -413,7 +413,17 @@
         } trigger="hover">
           <ToolOutlined />
         </Popover>
-        <div className="component-name"><div className="center">{card.name}</div></div>
+        <div className="component-name">
+          <div className="center" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
+        </div>
         {/* 缂栬緫鎼滅储鏉′欢 */}
         <Modal
           title="鎼滅储鏉′欢-缂栬緫"
diff --git a/src/menu/components/share/actioncomponent/actionform/index.jsx b/src/menu/components/share/actioncomponent/actionform/index.jsx
index 5c0a14c..fd2da26 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -17,7 +17,7 @@
   prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hidden'],
   exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hidden'],
   excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden'],
-  excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden'],
+  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden'],
   popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'maskStyle', 'closeButton', 'hidden'],
   tab: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'linkmenu', 'width', 'hidden'],
   innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
@@ -328,6 +328,7 @@
       }
     } else if (openType === 'excelOut') {
       reOptions.intertype = this.state.interTypeOptions.filter(op => op.value !== 'custom')
+      reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredOnce'].includes(op.value))
 
       if (this.record.intertype === 'outer') {
         shows.push('innerFunc', 'sysInterface', 'outerFunc')
@@ -352,6 +353,9 @@
       }
       if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
         shows.push('resetPageIndex')
+      }
+      if (this.record.Ot !== 'notRequired' && this.record.Ot !== 'requiredOnce') {
+        this.record.Ot = 'notRequired'
       }
     } else if (openType === 'popview') {
       reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
@@ -466,7 +470,7 @@
     }
     
     if (appType === 'mob') {
-      if (Ot !== 'notRequired') {
+      if (Ot !== 'notRequired' && openType !== 'excelOut') {
         shows.push('control')
         reOptions.control = [
           { value: '', text: '鏃�' },
@@ -481,7 +485,7 @@
         }
       }
     } else {
-      if (Ot !== 'notRequired') {
+      if (Ot !== 'notRequired' && openType !== 'excelOut') {
         reOptions.control = [
           { value: '', text: '鏃�' },
           { value: 'disabled', text: '绂佺敤' },
@@ -566,6 +570,7 @@
         _fieldval.label = '瀵煎嚭Excel'
         _fieldval.class = 'dgreen'
         _fieldval.execSuccess = 'never'
+        _fieldval.Ot = 'notRequired'
         this.record.Ot = 'notRequired'
         this.record.label = '瀵煎嚭Excel'
         this.record.class = 'dgreen'
@@ -930,7 +935,7 @@
               values.icon = 'scan'
             }
           } else if (values.OpenType === 'excelOut') {
-            values.Ot = 'notRequired'
+            values.Ot = values.Ot || 'notRequired'
           } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) {
             if ((values.Ot === 'requiredOnce' || card.Ot === 'requiredOnce') && card.Ot !== values.Ot) {
               values.verify.uniques = []
diff --git a/src/menu/components/share/actioncomponent/formconfig.jsx b/src/menu/components/share/actioncomponent/formconfig.jsx
index ab5b23b..b5e6155 100644
--- a/src/menu/components/share/actioncomponent/formconfig.jsx
+++ b/src/menu/components/share/actioncomponent/formconfig.jsx
@@ -523,7 +523,7 @@
       key: 'execSuccess',
       label: '鎴愬姛鍚�',
       initVal: card.execSuccess || 'grid',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆�',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -546,7 +546,7 @@
       key: 'execError',
       label: '澶辫触鍚�',
       initVal: card.execError || 'never',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮��',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1468,7 +1468,7 @@
       key: 'execSuccess',
       label: '鎴愬姛鍚�',
       initVal: card.execSuccess || 'grid',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆�',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1490,7 +1490,7 @@
       key: 'execError',
       label: '澶辫触鍚�',
       initVal: card.execError || 'never',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮��',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
diff --git a/src/menu/components/table/edit-table/index.jsx b/src/menu/components/table/edit-table/index.jsx
index ecd404c..ec5c659 100644
--- a/src/menu/components/table/edit-table/index.jsx
+++ b/src/menu/components/table/edit-table/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -228,7 +228,7 @@
     style.fontSize = card.wrap.fontSize || 14
     style.fontWeight = card.wrap.fontWeight || 'normal'
 
-    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -405,7 +405,15 @@
         <ColumnComponent config={card} updatecolumn={this.updatecolumn}/>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/table/normal-table/index.jsx b/src/menu/components/table/normal-table/index.jsx
index cd6df52..873c345 100644
--- a/src/menu/components/table/normal-table/index.jsx
+++ b/src/menu/components/table/normal-table/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -280,7 +280,7 @@
     style.fontSize = card.wrap.fontSize || 14
     style.fontWeight = card.wrap.fontWeight || 'normal'
 
-    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -472,7 +472,15 @@
         <ColumnComponent config={card} updatecolumn={this.updateComponent}/>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index 7b1e17d..9115d53 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -29,7 +29,7 @@
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -102,7 +102,7 @@
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
diff --git a/src/menu/components/tabs/tabcomponents/index.jsx b/src/menu/components/tabs/tabcomponents/index.jsx
index a0ed8c1..bda63dd 100644
--- a/src/menu/components/tabs/tabcomponents/index.jsx
+++ b/src/menu/components/tabs/tabcomponents/index.jsx
@@ -34,6 +34,25 @@
     handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)})
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...config, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -146,6 +165,7 @@
           card={card}
           moveCard={moveCard}
           delCard={deleteCard}
+          unGroup={unGroup}
           findCard={findCard}
           updateConfig={updateConfig}
         />
diff --git a/src/menu/components/timeline/normal-timeline/index.jsx b/src/menu/components/timeline/normal-timeline/index.jsx
index 237e4fa..79df605 100644
--- a/src/menu/components/timeline/normal-timeline/index.jsx
+++ b/src/menu/components/timeline/normal-timeline/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -165,7 +165,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -217,7 +217,15 @@
         {card.subcards.map(subcard => (<CardSimpleComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard}/>))}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/tree/antd-tree/index.jsx b/src/menu/components/tree/antd-tree/index.jsx
index c3c8640..1e69697 100644
--- a/src/menu/components/tree/antd-tree/index.jsx
+++ b/src/menu/components/tree/antd-tree/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Tree } from 'antd'
+import { Popover, Tree, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, FileOutlined, FolderOpenOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -129,7 +129,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -197,7 +197,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index 0226f8f..5d9b196 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -32,7 +32,7 @@
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -105,7 +105,7 @@
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index 9024341..9533aa5 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -36,6 +36,25 @@
     setCards(_cards)
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...menu, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -155,6 +174,7 @@
             card={card}
             moveCard={moveCard}
             delCard={deleteCard}
+            unGroup={unGroup}
             findCard={findCard}
             updateConfig={updateConfig}
           />
diff --git a/src/menu/normalCss/index.jsx b/src/menu/normalCss/index.jsx
new file mode 100644
index 0000000..27c393a
--- /dev/null
+++ b/src/menu/normalCss/index.jsx
@@ -0,0 +1,70 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal } from 'antd'
+import { EditOutlined } from '@ant-design/icons'
+
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+class NormalCss extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false,
+    normalcss: ''
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  trigger = () => {
+    const { config } = this.props
+
+    this.setState({visible: true, normalcss: config.normalcss || ''})
+  }
+
+  onCssChange = (val) => {
+    this.setState({
+      normalcss: val
+    })
+  }
+
+  submit = () => {
+    const { normalcss } = this.state
+
+    this.setState({
+      visible: false
+    })
+
+    this.props.updateConfig({...this.props.config, normalcss: normalcss})
+  }
+
+  render() {
+    const { visible, normalcss } = this.state
+
+    return (
+      <div className="mk-normal-css">
+        鍏ㄥ眬鏍峰紡锛�<EditOutlined onClick={this.trigger} />
+        <Modal
+          title="鍏ㄥ眬鏍峰紡"
+          wrapClassName="normal-css-modal"
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          destroyOnClose
+        >
+          <CodeMirror mode="text/css" theme="cobalt" value={normalcss} onChange={this.onCssChange} />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default NormalCss
\ No newline at end of file
diff --git a/src/menu/normalCss/index.scss b/src/menu/normalCss/index.scss
new file mode 100644
index 0000000..872d481
--- /dev/null
+++ b/src/menu/normalCss/index.scss
@@ -0,0 +1,21 @@
+.mk-normal-css {
+  padding-left: 18px;
+
+  .anticon-edit {
+    color: #1890ff;
+    cursor: pointer;
+  }
+}
+.normal-css-modal {
+  .ant-modal {
+    top: 70px;
+  }
+  .ant-modal-body {
+    min-height: 250px;
+    padding-top: 10px;
+
+    .code-mirror-wrap .code-mirror-area .CodeMirror {
+      min-height: 400px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/stylecombcontroller/styleInput/index.scss b/src/menu/stylecombcontroller/styleInput/index.scss
index 5b4266b..0844abd 100644
--- a/src/menu/stylecombcontroller/styleInput/index.scss
+++ b/src/menu/stylecombcontroller/styleInput/index.scss
@@ -1,7 +1,7 @@
 .style-input-box {
   line-height: 32px;
   .ant-select {
-    width: 60px!important;
+    width: 65px!important;
   }
   .single-unit {
     width: 38px;
diff --git a/src/menu/stylecontroller/index.jsx b/src/menu/stylecontroller/index.jsx
index 053ee15..397fa05 100644
--- a/src/menu/stylecontroller/index.jsx
+++ b/src/menu/stylecontroller/index.jsx
@@ -435,12 +435,20 @@
   }
 
   changeWidth = (val) => {
-    let _val = val
-    if (_val === '0px') {
-      _val = 'auto'
+    const { card } = this.state
+    let _style = {...card}
+
+    if (val === '0px') {
+      delete _style.width
+    } else {
+      _style.width = val
     }
 
-    this.updateStyle({width: _val})
+    this.setState({
+      card: _style
+    })
+
+    this.callback && this.callback(_style)
   }
 
   changeHeight = (val) => {
@@ -495,7 +503,7 @@
                     label={<ColumnWidthOutlined title="瀹藉害"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw', '%']} onChange={this.changeWidth}/>
+                    <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw', '%', 'auto']} onChange={this.changeWidth}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
@@ -675,8 +683,14 @@
                   >
                     <Select defaultValue={card.backgroundPosition || 'center'} onChange={this.changeBackgroundPositon}>
                       <Option value="center">center</Option>
-                      <Option value="top">top</Option>
-                      <Option value="bottom">bottom</Option>
+                      <Option value="center top">center top</Option>
+                      <Option value="center bottom">center bottom</Option>
+                      <Option value="left top">left top</Option>
+                      <Option value="left center">left center</Option>
+                      <Option value="left bottom">left bottom</Option>
+                      <Option value="right top">right top</Option>
+                      <Option value="right center">right center</Option>
+                      <Option value="right bottom">right bottom</Option>
                     </Select>
                   </Form.Item>
                 </Col> : null}
@@ -907,7 +921,7 @@
                     label={<ColumnHeightOutlined title="鏈�灏忛珮搴�"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.minHeight || '28px'} options={['px']} onChange={(val) => this.changeNormalStyle(val, 'minHeight')}/>
+                    <StyleInput defaultValue={card.minHeight || ''} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'minHeight')}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
diff --git a/src/menu/stylecontroller/styleInput/index.jsx b/src/menu/stylecontroller/styleInput/index.jsx
index 8eea049..d7661d0 100644
--- a/src/menu/stylecontroller/styleInput/index.jsx
+++ b/src/menu/stylecontroller/styleInput/index.jsx
@@ -48,6 +48,8 @@
         unit = 'vw'
       } else if (val.indexOf('vh') > -1) {
         unit = 'vh'
+      } else if (val === 'auto' && _options.includes('auto')) {
+        unit = 'auto'
       }
     }
 
@@ -135,8 +137,14 @@
     const { value } = this.state
 
     this.setState({unit: val})
-    if (value && this.props.onChange) {
-      this.props.onChange(`${value}${val}`)
+
+    if (val === 'auto') {
+      this.setState({value: ''})
+      this.props.onChange('auto')
+    } else {
+      if (value && this.props.onChange) {
+        this.props.onChange(`${value}${val}`)
+      }
     }
   }
 
@@ -145,7 +153,7 @@
 
     return (
       <div className="style-input-box">
-        <Input value={value} addonAfter={
+        <Input value={value} disabled={unit === 'auto'} addonAfter={
           options.length > 1 ?
           <Select value={unit} onChange={this.changeUnit}>
             {options.map(item => <Option key={item} value={item}>{item}</Option>)}
diff --git a/src/menu/stylecontroller/styleInput/index.scss b/src/menu/stylecontroller/styleInput/index.scss
index 5b4266b..0844abd 100644
--- a/src/menu/stylecontroller/styleInput/index.scss
+++ b/src/menu/stylecontroller/styleInput/index.scss
@@ -1,7 +1,7 @@
 .style-input-box {
   line-height: 32px;
   .ant-select {
-    width: 60px!important;
+    width: 65px!important;
   }
   .single-unit {
     width: 38px;
diff --git a/src/menu/tablenodes/index.jsx b/src/menu/tablenodes/index.jsx
index 36281b2..e903da7 100644
--- a/src/menu/tablenodes/index.jsx
+++ b/src/menu/tablenodes/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Modal, Button, notification, Spin, Input } from 'antd'
+import { Modal, Button, notification, Spin, Input, message } from 'antd'
 import { ForkOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -158,6 +158,7 @@
               id: 'par' + i,
               direction: 'left',
               color: '#5AD8A6',
+              node: 'table',
               children: []
             }
 
@@ -232,7 +233,12 @@
     if (menu.direction !== 'right') return
 
     if (menu.depth === 1) {
+      sessionStorage.setItem('mk-table-node', menu.label)
       window.open('#/hs')
+
+      setTimeout(() => {
+        sessionStorage.removeItem('mk-table-node')
+      }, 50)
     } else if (menu.param) {
       if (menu.param.type === 'admin') {
         if (menu.param.MenuType === 'custom') {
@@ -354,6 +360,23 @@
           }
         })
 
+        if (model.direction === 'left') {
+          if (model.node === 'table') {
+            model.fontcolor = '#1890ff'
+            this.graph.updateItem(item, model, false)
+
+            let oInput = document.createElement('input')
+            oInput.value = model.label
+            document.body.appendChild(oInput)
+            oInput.select()
+            document.execCommand('Copy')
+            document.body.removeChild(oInput)
+            
+            message.success('琛ㄥ悕澶嶅埗鎴愬姛銆�')
+          }
+          return
+        }
+
         model.fontcolor = '#1890ff'
         this.graph.updateItem(item, model, false)
         
diff --git a/src/mob/components/search/single-search/index.jsx b/src/mob/components/search/single-search/index.jsx
index 43debf2..514a906 100644
--- a/src/mob/components/search/single-search/index.jsx
+++ b/src/mob/components/search/single-search/index.jsx
@@ -139,7 +139,16 @@
         } trigger="hover">
           <ToolOutlined />
         </Popover>
-        <div className="component-name"><div className="center">{card.name}</div></div>
+        <div className="component-name">
+          <div className="center" onDoubleClick={() => {
+            let oInput = document.createElement('input')
+            oInput.value = card.uuid
+            document.body.appendChild(oInput)
+            oInput.select()
+            document.execCommand('Copy')
+            document.body.removeChild(oInput)
+          }}>{card.name}</div>
+        </div>
       </div>
     )
   }
diff --git a/src/mob/components/tabs/tabcomponents/card.jsx b/src/mob/components/tabs/tabcomponents/card.jsx
index 700de18..76430f6 100644
--- a/src/mob/components/tabs/tabcomponents/card.jsx
+++ b/src/mob/components/tabs/tabcomponents/card.jsx
@@ -27,7 +27,7 @@
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -98,7 +98,7 @@
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'menubar') {
diff --git a/src/mob/components/tabs/tabcomponents/index.jsx b/src/mob/components/tabs/tabcomponents/index.jsx
index d202e5e..1d146b5 100644
--- a/src/mob/components/tabs/tabcomponents/index.jsx
+++ b/src/mob/components/tabs/tabcomponents/index.jsx
@@ -34,6 +34,25 @@
     handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)})
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...config, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -139,6 +158,7 @@
           card={card}
           moveCard={moveCard}
           delCard={deleteCard}
+          unGroup={unGroup}
           findCard={findCard}
           updateConfig={updateConfig}
         />
diff --git a/src/mob/mobshell/card.jsx b/src/mob/mobshell/card.jsx
index 517db7f..6dfc6c6 100644
--- a/src/mob/mobshell/card.jsx
+++ b/src/mob/mobshell/card.jsx
@@ -33,7 +33,7 @@
 const ShareCode = asyncComponent(() => import('@/mob/components/sharecode'))
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -72,21 +72,21 @@
   }
 
   let col = 'ant-col-' + (card.width || 24)
-  if (card.type === 'login') {
-    let height = ''
-    if (card.wrap && card.wrap.height) {
-      // scaleview
-      height = card.wrap.height.replace(/\d+vw/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winWidth || 420) / 100 + 'px'
-        // return parseFloat(word) * 350 / 100 + 'px'
-      }).replace(/\d+vh/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winHeight || 738) / 100 + 'px'
-        // return parseFloat(word) * 615 / 100 + 'px'
-      })
-    }
+  // if (card.type === 'login') {
+  //   let height = ''
+  //   if (card.wrap && card.wrap.height) {
+  //     // scaleview
+  //     height = card.wrap.height.replace(/\d+vw/ig, (word) => {
+  //       return parseFloat(word) * (window.GLOB.winWidth || 420) / 100 + 'px'
+  //       // return parseFloat(word) * 350 / 100 + 'px'
+  //     }).replace(/\d+vh/ig, (word) => {
+  //       return parseFloat(word) * (window.GLOB.winHeight || 738) / 100 + 'px'
+  //       // return parseFloat(word) * 615 / 100 + 'px'
+  //     })
+  //   }
     
-    style.minHeight = height
-  }
+  //   style.minHeight = height
+  // }
 
   const getCardComponent = () => {
     if (card.type === 'bar' || card.type === 'line') {
@@ -120,7 +120,7 @@
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
diff --git a/src/mob/mobshell/index.jsx b/src/mob/mobshell/index.jsx
index 0063894..c7b5442 100644
--- a/src/mob/mobshell/index.jsx
+++ b/src/mob/mobshell/index.jsx
@@ -36,6 +36,25 @@
     setCards(_cards)
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...menu, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -220,6 +239,7 @@
             card={card}
             moveCard={moveCard}
             delCard={deleteCard}
+            unGroup={unGroup}
             findCard={findCard}
             updateConfig={updateConfig}
           />
diff --git a/src/pc/components/login/normal-login/index.jsx b/src/pc/components/login/normal-login/index.jsx
index 286b250..60a3e17 100644
--- a/src/pc/components/login/normal-login/index.jsx
+++ b/src/pc/components/login/normal-login/index.jsx
@@ -71,6 +71,11 @@
       if (_card.wrap.classify === 'signin') {
         active = 'signin'
       }
+      if (!_card.style.minHeight && _card.wrap.height) {
+        _card.style.minHeight = _card.wrap.height
+        delete _card.wrap.height
+      }
+
       this.setState({
         active,
         card: _card
@@ -114,7 +119,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['width', 'background', 'border', 'padding', 'margin', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['width', 'background', 'border', 'padding', 'margin', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -190,7 +195,14 @@
         {card.wrap.signWays && active === 'signin' ? <SignForm wrap={card.wrap} changeway={() => this.setState({active: 'login'})}/> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/pc/components/login/normal-login/options.jsx b/src/pc/components/login/normal-login/options.jsx
index 0c49d34..634d7bf 100644
--- a/src/pc/components/login/normal-login/options.jsx
+++ b/src/pc/components/login/normal-login/options.jsx
@@ -70,15 +70,15 @@
     //   precision: 0,
     //   required: false
     // },
-    {
-      type: 'styleInput',
-      field: 'height',
-      label: '鏈�灏忛珮搴�',
-      initval: wrap.height || '',
-      tooltip: '缁勪欢鍗犵敤鐨勬渶灏忛珮搴︼紝鐢ㄤ簬椤甸潰甯冨眬銆�',
-      required: false,
-      options: ['px', 'vh', 'vw', '%']
-    },
+    // {
+    //   type: 'styleInput',
+    //   field: 'height',
+    //   label: '鏈�灏忛珮搴�',
+    //   initval: wrap.height || '',
+    //   tooltip: '缁勪欢鍗犵敤鐨勬渶灏忛珮搴︼紝鐢ㄤ簬椤甸潰甯冨眬銆�',
+    //   required: false,
+    //   options: ['px', 'vh', 'vw', '%']
+    // },
     // {
     //   type: 'styleInput',
     //   field: 'maxWidth',
diff --git a/src/pc/menushell/card.jsx b/src/pc/menushell/card.jsx
index 085daf7..e003785 100644
--- a/src/pc/menushell/card.jsx
+++ b/src/pc/menushell/card.jsx
@@ -32,7 +32,7 @@
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -71,21 +71,6 @@
   }
   
   let col = ' ant-col ant-col-' + (card.width || 24)
-  if (card.type === 'login') {
-    let height = ''
-    if (card.wrap && card.wrap.height) {
-      // scaleview
-      height = card.wrap.height.replace(/\d+vw/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winWidth || 420) / 100 + 'px'
-        // return parseFloat(word) * 350 / 100 + 'px'
-      }).replace(/\d+vh/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winHeight || 738) / 100 + 'px'
-        // return parseFloat(word) * 615 / 100 + 'px'
-      })
-    }
-    
-    style.minHeight = height
-  }
 
   const getCardComponent = () => {
     if (card.type === 'bar' || card.type === 'line') {
@@ -125,7 +110,7 @@
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
diff --git a/src/pc/menushell/index.jsx b/src/pc/menushell/index.jsx
index 3bd54a3..32b17b4 100644
--- a/src/pc/menushell/index.jsx
+++ b/src/pc/menushell/index.jsx
@@ -36,6 +36,25 @@
     setCards(_cards)
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...menu, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -173,6 +192,7 @@
             card={card}
             moveCard={moveCard}
             delCard={deleteCard}
+            unGroup={unGroup}
             findCard={findCard}
             updateConfig={updateConfig}
           />
diff --git a/src/tabviews/basetable/index.scss b/src/tabviews/basetable/index.scss
index 4a12545..ca8acd1 100644
--- a/src/tabviews/basetable/index.scss
+++ b/src/tabviews/basetable/index.scss
@@ -7,10 +7,7 @@
   padding-left: 16px;
   padding-right: 16px;
   background-size: 100%;
-  
-  .component-wrap >.ant-col {
-    min-height: 0;
-  }
+
   .box404 {
     padding-top: 30px;
   }
diff --git a/src/tabviews/custom/components/card/balcony/index.jsx b/src/tabviews/custom/components/card/balcony/index.jsx
index bf037dd..6283141 100644
--- a/src/tabviews/custom/components/card/balcony/index.jsx
+++ b/src/tabviews/custom/components/card/balcony/index.jsx
@@ -395,20 +395,33 @@
     MKEmitter.emit('mkCheckAll', syncConfig.uuid, e.target.checked)
   }
 
+  triggerButton = () => {
+    const { config, data } = this.state
+
+    if (config.wrap.linkbtn) {
+      MKEmitter.emit('triggerBtnId', config.wrap.linkbtn, data.$$empty ? [] : [data])
+    }
+  }
+
   render() {
     const { config, loading, data, show, syncConfig, syncData, checked } = this.state
 
     if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
+
+    let style = {...config.style}
+    if (config.wrap.bgField) {
+      style.backgroundImage = `url('${data[config.wrap.bgField] || ''}')`
+    }
     
     return (
-      <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} style={config.style}>
+      <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} id={'anchor' + config.uuid} style={style} onClick={this.triggerButton}>
         {loading ?
-          <div className="loading-mask">
+          <div className="loading-mask" onClick={(e) => e.stopPropagation()}>
             <div className="ant-spin-blur"></div>
             <Spin />
           </div> : null
         }
-        {config.wrap.checkAll === 'show' ? <div className="check-all"><Checkbox checked={checked} onChange={this.checkAll}>鍏ㄩ��</Checkbox></div> : null}
+        {config.wrap.checkAll === 'show' ? <div className="check-all" onClick={(e) => e.stopPropagation()}><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/cardItem/index.jsx b/src/tabviews/custom/components/card/cardItem/index.jsx
index 224438e..84d3eec 100644
--- a/src/tabviews/custom/components/card/cardItem/index.jsx
+++ b/src/tabviews/custom/components/card/cardItem/index.jsx
@@ -164,12 +164,20 @@
     const { card, data, cards } = this.props
     let style = {...card.style}
 
+    let bg = null
+
     if (card.setting.bgField) {
       style.backgroundImage = `url('${data[card.setting.bgField] || ''}')`
     }
 
+    if (style.backgroundImage) {
+      bg = <div className="card-background" style={{backgroundImage: style.backgroundImage}}></div>
+      style.backgroundImage = ''
+    }
+
     return (
       <div className={'card-item-box ' + (card.setting.btnControl || '')} style={style} onClick={this.openView} onDoubleClick={this.doubleClick}>
+        {bg}
         <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.elements}/>
         {card.setting.type === 'multi' ? <div className={'back-side ' + card.setting.transform} style={card.backStyle}>
           <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.backElements}/>
diff --git a/src/tabviews/custom/components/card/cardItem/index.scss b/src/tabviews/custom/components/card/cardItem/index.scss
index fdf37b0..0879249 100644
--- a/src/tabviews/custom/components/card/cardItem/index.scss
+++ b/src/tabviews/custom/components/card/cardItem/index.scss
@@ -38,6 +38,16 @@
   .back-side.scale {
     transform: scale(0, 0);
   }
+  .card-background {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-size: inherit;
+    background-position: inherit;
+    background-repeat: inherit;
+  }
 }
 .card-item-box:hover {
   .back-side.up, .back-side.down, .back-side.left, .back-side.right {
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index 7a4dd46..ec98383 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -907,6 +907,11 @@
             ))}
             {data && data.map((item, index) => {
               let className = card.setting.click ? 'mk-card pointer ' : 'mk-card '
+              if (config.wrap.parity === 'true') {
+                if (index % 2 === 1) {
+                  className += 'mk-parity-bg '
+                }
+              }
               if (item.$disabled) {
                 className = 'mk-disabled'
               } else if (activeKey === index) {
diff --git a/src/tabviews/custom/components/card/data-card/index.scss b/src/tabviews/custom/components/card/data-card/index.scss
index 77c2788..f0750ac 100644
--- a/src/tabviews/custom/components/card/data-card/index.scss
+++ b/src/tabviews/custom/components/card/data-card/index.scss
@@ -32,6 +32,11 @@
         }
       }
     }
+    .mk-parity-bg {
+      .card-item-box {
+        background-color: var(--mk-sys-color1);
+      }
+    }
   }
   .data-zoom.scale {
     .card-row-list {
diff --git a/src/tabviews/custom/components/card/table-card/index.jsx b/src/tabviews/custom/components/card/table-card/index.jsx
index 5629e18..deb7786 100644
--- a/src/tabviews/custom/components/card/table-card/index.jsx
+++ b/src/tabviews/custom/components/card/table-card/index.jsx
@@ -515,7 +515,7 @@
           </div> : null
         }
         <NormalHeader config={config} BID={BID} refresh={this.refreshSearch} />
-        {data && data.length > 0 ? <Row className="card-row-list" style={{height: config.wrap.contentHeight}}>
+        {data && data.length > 0 ? <Row className={'card-row-list' + (config.wrap.parity === 'true' ? ' mk-parity' : '')} style={{height: config.wrap.contentHeight}}>
           {data.map(item => this.getLines(item))}
         </Row> : null}
         {data && data.length === 0 ? <div className="card-row-list" style={{height: config.wrap.contentHeight}}>
diff --git a/src/tabviews/custom/components/card/table-card/index.scss b/src/tabviews/custom/components/card/table-card/index.scss
index c44fdec..c7b6fc8 100644
--- a/src/tabviews/custom/components/card/table-card/index.scss
+++ b/src/tabviews/custom/components/card/table-card/index.scss
@@ -33,6 +33,13 @@
     clear: both;
   }
 
+  .mk-parity {
+    >.ant-col:nth-child(even) {
+      .card-item-box {
+        background-color: var(--mk-sys-color1);
+      }
+    }
+  }
   .card-row-list {
     overflow-y: auto;
     .card-item-box {
diff --git a/src/tabviews/custom/components/module/account/index.jsx b/src/tabviews/custom/components/module/account/index.jsx
index 1a9a7b6..943e10d 100644
--- a/src/tabviews/custom/components/module/account/index.jsx
+++ b/src/tabviews/custom/components/module/account/index.jsx
@@ -3,8 +3,10 @@
 import { is, fromJS } from 'immutable'
 import { notification, Select, Divider } from 'antd'
 import { PlusOutlined } from '@ant-design/icons'
+import moment from 'moment'
 
 import Api from '@/api'
+import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
@@ -39,7 +41,9 @@
 
   loadData = () => {
     let param = {
-      func: 's_get_fcc_book_data'
+      func: 's_get_fcc_book_data',
+      dataM: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
+      mk_organization: sessionStorage.getItem('organization') || ''
     }
 
     Api.genericInterface(param).then(res => {
@@ -69,10 +73,6 @@
         return true
       })
 
-      if (!activeItem && books.length > 0) {
-        activeItem = books[0]
-      }
-
       this.setState({books, activeItem})
 
       if (activeItem) {
@@ -90,6 +90,22 @@
 
     if (activeItem) {
       MKEmitter.emit('resetSelectLine', this.props.config.uuid, activeItem.id, activeItem)
+      
+      let userid = sessionStorage.getItem('UserID') || ''
+      let sid = localStorage.getItem('SessionUid') || ''
+      let param = {
+        func: 'sPC_TableData_InUpDe',
+        LText: `delete  tmp_session_show_key where createuserid='${userid}' and createuser='${sid}' and key_type='fcc_years'
+          insert into tmp_session_show_key ( key_id,key_type,createuserid,CreateUser,CreateStaff) 
+          select '${activeItem.id}','fcc_years','${userid}','${sid}','${sessionStorage.getItem('Full_Name') || ''}'`,
+        exec_type: 'y'
+      }
+  
+      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+      param.secretkey = Utils.encrypt('', param.timestamp)
+      param.LText = Utils.formatOptions(param.LText)
+
+      Api.genericInterface(param)
     }
   }
 
@@ -132,11 +148,11 @@
           </div>
         )}>
           {books.map(item => (
-            <Option key={item.id}>{item.account_name}</Option>
+            <Option disabled={!item.months} key={item.id}>{item.account_name}</Option>
           ))}
         </Select> : <Select value={activeItem ? activeItem.id : ''} placeholder="璇烽�夋嫨璐﹀" onChange={this.changeBook}>
           {books.map(item => (
-            <Option key={item.id}>{item.account_name}</Option>
+            <Option disabled={!item.months} key={item.id}>{item.account_name}</Option>
           ))}
         </Select>}
         {activeItem ? <span className="date">{activeItem.date}</span> : null}
diff --git a/src/tabviews/custom/components/module/voucher/assistTable/index.jsx b/src/tabviews/custom/components/module/voucher/assistTable/index.jsx
deleted file mode 100644
index 4a5edb7..0000000
--- a/src/tabviews/custom/components/module/voucher/assistTable/index.jsx
+++ /dev/null
@@ -1,734 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { Table, Modal, Input, InputNumber, notification, message } from 'antd'
-// import { EditOutlined } from '@ant-design/icons'
-
-import Api from '@/api'
-import Utils from '@/utils/utils.js'
-import MKEmitter from '@/utils/events.js'
-import './index.scss'
-
-class BodyRow extends React.Component {
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props.data), fromJS(nextProps.data))
-  }
-
-  render() {
-    let { data, ...resProps } = this.props
-    let style = {}
-    let className = ''
-
-    return <tr {...resProps} className={className} style={style}/>
-  }
-}
-
-class BodyCell extends React.Component {
-  state = {
-    editing: false,
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props.record), fromJS(nextProps.record)) ||
-      nextState.editing !== this.state.editing
-  }
-
-  componentDidMount () {
-    MKEmitter.addListener('tdFocus', this.tdFocus)
-  }
-
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-    MKEmitter.removeListener('tdFocus', this.tdFocus)
-  }
-
-  tdFocus = (id) => {
-    const { col, record } = this.props
-
-    if (id !== col.uuid + record.uuid) return
-
-    this.focus()
-  }
-
-  enterPress = () => {
-    const { col, record } = this.props
-    const { value } = this.state
-
-    this.setState({editing: false})
-
-    if (value !== record[col.field]) {
-      let line = {...record, [col.field]: value}
-
-      if (col.field === 'debtor') {
-        line.creditor = ''
-      } else {
-        line.debtor = ''
-      }
-
-      MKEmitter.emit('changeRecord', col.tableId, line)
-    }
-
-    setTimeout(() => {
-      if (col.field === 'creditor') {
-        MKEmitter.emit('nextLine', col, record)
-      } else {
-        let cl = {remark: 'subject', subject: 'debtor', debtor: 'creditor'}
-        MKEmitter.emit('tdFocus', cl[col.uuid] + record.uuid)
-      }
-    }, 50)
-  }
-
-  focus = () => {
-    const { col, record } = this.props
-
-    if (record.type === 'total') return
-
-    this.setState({editing: true, value: record[col.field]}, () => {
-      let node = document.getElementById(col.uuid + record.uuid)
-      node && node.select()
-    })
-  }
-
-  onBlur = () => {
-    const { col, record } = this.props
-    const { value } = this.state
-
-    this.setState({editing: false})
-
-    if (value !== record[col.field]) {
-      let line = {...record, [col.field]: value}
-
-      if (col.field === 'debtor') {
-        line.creditor = ''
-      } else {
-        line.debtor = ''
-      }
-
-      MKEmitter.emit('changeRecord', col.tableId, line)
-    }
-  }
-  
-  onChange = (val) => {
-    this.setState({value: val})
-  }
-
-  render() {
-    let { col, record, className } = this.props
-    const { editing } = this.state
-
-    let children = null
-    let colSpan = 1
-
-    if (col.field === 'remark') {
-      let val = record.remark || ''
-
-      if (record.type === 'total') {
-        children = <div className="content-wrap" style={{lineHeight: '60px'}}>鍚堣: {val}</div>
-        colSpan = 2
-      } else {
-        if (editing) {
-          children = <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-        } else {
-          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
-        }
-      }
-    } else if (col.field === 'subject') {
-      if (record.type === 'total') {
-        colSpan = 0
-      } else {
-        let val = record.subject || ''
-  
-        if (editing) {
-          children = <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-        } else {
-          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
-        }
-      }
-    } else if (col.field === 'debtor') {
-      let val = record.debtor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
-
-      if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-      } else {
-        children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
-          <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
-          <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
-        </div>
-      }
-    } else if (col.field === 'creditor') {
-      let val = record.creditor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
-
-      if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-      } else {
-        children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
-        <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
-        <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
-      </div>
-      }
-    }
-
-    if (!colSpan) return null
-
-    return (<td colSpan={colSpan} className={className}>{children}</td>)
-  }
-}
-
-class AssistTable extends Component {
-  static propTpyes = {
-    config: PropTypes.object,        // 鑿滃崟Id
-    BID: PropTypes.any,              // 涓昏〃ID
-    data: PropTypes.any,             // 琛ㄦ牸鏁版嵁
-    total: PropTypes.any,            // 鎬绘暟
-    loading: PropTypes.bool,         // 琛ㄦ牸鍔犺浇涓�
-    refreshdata: PropTypes.func,     // 琛ㄦ牸涓帓搴忓垪銆侀〉鐮佺殑鍙樺寲鏃跺埛鏂�
-  }
-
-  state = {
-    data: [],
-    edData: [],
-    edColumns: [],
-    tableId: '',          // 琛ㄦ牸ID
-    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
-    columns: null,        // 鏄剧ず鍒�
-    loading: false,
-  }
-
-  UNSAFE_componentWillMount () {
-    const { config } = this.props
-
-    let data = [
-      {remark: '鎻愮幇', subject: '1001 搴撳瓨鐜伴噾', debtor: 124, creditor: ''},
-      {remark: '璐叆鍥哄畾璧勪骇', subject: '1001 搴撳瓨鐜伴噾', debtor: '', creditor: 124},
-      {remark: '杞粨閿�鍞垚鏈�', subject: '1001 搴撳瓨鐜伴噾', debtor: -524, creditor: ''},
-      {remark: '鎻愮幇', subject: '1001 搴撳瓨鐜伴噾', debtor: 34, creditor: ''},
-    ]
-
-    data = this.initData(data)
-    data.push(this.getTotalLine(data))
-
-    let columns = [
-      {
-        title: '鎽樿',
-        dataIndex: 'remark',
-        key: 'remark',
-        width: '22%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'remark', field: 'remark', tableId: config.uuid},
-        })
-      },
-      {
-        title: '浼氳绉戠洰',
-        dataIndex: 'subject',
-        key: 'subject',
-        width: '34%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'subject', field: 'subject', tableId: config.uuid},
-        })
-      },
-      {
-        title: () => (<>
-          <div className="money-title">鍊熸柟閲戦</div>
-          <div className="money-uint">
-            <span>浜�</span> <span>鍗�</span> <span>鐧�</span> <span>鍗�</span> <span>涓�</span> <span>鍗�</span>
-            <span>鐧�</span> <span>鍗�</span> <span>鍏�</span> <span>瑙�</span> <span className="last">鍒�</span>
-          </div>
-        </>),
-        dataIndex: 'debtor',
-        key: 'debtor',
-        width: '22%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'debtor', field: 'debtor', tableId: config.uuid},
-        })
-      },
-      {
-        title: () => (<>
-          <div className="money-title">璐锋柟閲戦</div>
-          <div className="money-uint">
-            <span>浜�</span> <span>鍗�</span> <span>鐧�</span> <span>鍗�</span> <span>涓�</span> <span>鍗�</span>
-            <span>鐧�</span> <span>鍗�</span> <span>鍏�</span> <span>瑙�</span> <span className="last">鍒�</span>
-          </div>
-        </>),
-        dataIndex: 'creditor',
-        key: 'creditor',
-        width: '22%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'creditor', field: 'creditor', tableId: config.uuid},
-        })
-      }
-    ]
-
-    this.setState({
-      data: data,
-      edData: fromJS(data).toJS(),
-      columns,
-      tableId: config.uuid
-    })
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  componentDidMount () {
-    MKEmitter.addListener('nextLine', this.nextLine)
-    MKEmitter.addListener('delRecord', this.delRecord)
-    MKEmitter.addListener('changeRecord', this.changeRecord)
-  }
-
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-    MKEmitter.removeListener('nextLine', this.nextLine)
-    MKEmitter.removeListener('delRecord', this.delRecord)
-    MKEmitter.removeListener('changeRecord', this.changeRecord)
-  }
-
-  UNSAFE_componentWillReceiveProps(nextProps) {
-    if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
-      this.setState({data: nextProps.data || []})
-    }
-  }
-
-  initData = (data) => {
-    let _data = data.map((item, i) => {
-      item.uuid = Utils.getuuid()
-      item.index = i
-      
-      return item
-    })
-
-    if (_data.length < 4) {
-      for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
-      }
-    }
-    return _data
-  }
-
-  getTotalLine = (data) => {
-    let totalLine = {uuid: Utils.getuuid(), type: 'total'}
-    let debtor = ''
-    let creditor = ''
-
-    data.forEach(item => {
-      if (typeof(item.debtor) === 'number') {
-        if (debtor === '') {
-          debtor = 0
-        }
-
-        debtor += item.debtor
-      } else if (typeof(item.creditor) === 'number') {
-        if (debtor === '') {
-          debtor = 0
-        }
-        if (creditor === '') {
-          creditor = 0
-        }
-        creditor += item.creditor
-      }
-    })
-
-    totalLine.debtor = debtor
-    totalLine.creditor = creditor
-
-    totalLine.remark = this.changeMoneyToChinese(debtor)
-    
-    return totalLine
-  }
-  
-  changeMoneyToChinese = (money) => {
-    let cnNums = ['闆�', '澹�', '璐�', '鍙�', '鑲�', '浼�', '闄�', '鏌�', '鎹�', '鐜�']
-    let cnIntRadice = ['', '鎷�', '浣�', '浠�']
-    let cnIntUnits = ['', '涓�', '浜�', '鍏�']
-    let cnDecUnits = ['瑙�', '鍒�', '姣�', '鍘�']
-    let cnInteger = '鏁�'
-    let cnIntLast = '鍏�'
-    let maxNum = 999999999999999.9999 // 鏈�澶у鐞嗙殑鏁板瓧
-    let IntegerNum = null
-    let DecimalNum = null
-    let ChineseStr = ''
-    let parts = null // 鍒嗙閲戦鍚庣敤鐨勬暟缁勶紝棰勫畾涔�
-    let Symbol = ''  // 姝h礋鍊兼爣璁�
-
-    if (money === '') return ''
-
-    if (money >= maxNum) return '瓒呭嚭鏈�澶у鐞嗘暟瀛�'
-
-    if (money === 0) {
-      ChineseStr = cnNums[0] + cnIntLast + cnInteger;
-      return ChineseStr
-    }
-    if(money < 0) {
-      money = -money
-      Symbol = '璐�'       
-    }
-    money = money.toString() // 杞崲涓哄瓧绗︿覆
-    if (money.indexOf('.') === -1) {
-      IntegerNum = money
-      DecimalNum = ''
-    } else {
-      parts = money.split('.')
-      IntegerNum = parts[0]
-      DecimalNum = parts[1].substr(0, 4)
-    }
-
-    if (parseInt(IntegerNum, 10) > 0) { // 鑾峰彇鏁村瀷閮ㄥ垎杞崲
-      let zeroCount = 0
-      let IntLen = IntegerNum.length
-      for (let i = 0; i < IntLen; i++) {
-        let n = IntegerNum.substr(i, 1)
-        let p = IntLen - i - 1
-        let q = p / 4
-        let m = p % 4
-        
-        if (n === '0') {
-          zeroCount++
-        } else {
-          if (zeroCount > 0) {
-            ChineseStr += cnNums[0]
-          }
-          zeroCount = 0 // 褰掗浂
-          ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
-        }
-
-        if (m === 0 && zeroCount < 4) {
-          ChineseStr += cnIntUnits[q]
-        }
-      }
-      ChineseStr += cnIntLast
-    }
-
-    if (DecimalNum !== '') { // 灏忔暟閮ㄥ垎
-      let decLen = DecimalNum.length
-
-      for (let i = 0; i < decLen; i++) {
-        let n = DecimalNum.substr(i, 1)
-        if (n !== '0') {
-          ChineseStr += cnNums[Number(n)] + cnDecUnits[i]
-        }
-      }
-    }
-    if (ChineseStr === '') {
-      ChineseStr += cnNums[0] + cnIntLast + cnInteger
-    } else if (DecimalNum === '') {
-      ChineseStr += cnInteger
-    }
-
-    ChineseStr = Symbol + ChineseStr
-    
-    return ChineseStr
-  }
-
-  nextLine = (col, record) => {
-    const { edData, tableId } = this.state
-
-    if (col.tableId !== tableId) return
-
-    if (record.index < edData.length - 2) {
-      MKEmitter.emit('tdFocus', 'remark' + edData[record.index + 1].uuid)
-    } else {
-      let _data = fromJS(edData).toJS()
-      let line = {uuid: Utils.getuuid(), index: _data.length - 1, remark: record.remark || '', subject: '', debtor: '', creditor: ''}
-
-      _data.splice(_data.length - 1, 0, line)
-
-      this.setState({edData: _data}, () => {
-        MKEmitter.emit('tdFocus', 'remark' + line.uuid)
-      })
-    }
-  }
-
-  plusLine = (initEditLine) => {
-    const { edData } = this.state
-
-    let item = {...edData[edData.length - 1]}
-
-    item.key = item.key + 1
-    item.$$uuid = '$new'
-
-    this.setState({edData: [...edData, item]}, () => {
-      MKEmitter.emit('tdFocus', initEditLine.uuid + item.uuid)
-    })
-  }
-
-  delRecord = (id, record) => {
-    const { tableId, edData } = this.state
-
-    if (id !== tableId) return
-
-    let _data = edData.filter(item => item.uuid !== record.uuid)
-
-    _data.pop()
-
-    if (_data.length < 4) {
-      for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
-      }
-    }
-
-    _data.push(this.getTotalLine(_data))
-
-    this.setState({edData: _data})
-  }
-
-  changeRecord = (tableId, record) => {
-    if (tableId !== this.state.tableId) return
-
-    let _data = this.state.edData.map(item => {
-      if (item.uuid === record.uuid) {
-        return record
-      } else {
-        return item
-      }
-    })
-
-    _data.pop()
-
-    if (record.index === _data.length - 1) {
-      _data.push({uuid: Utils.getuuid(), index: record.index + 1, remark: '', subject: '', debtor: '', creditor: ''})
-    }
-
-    _data.push(this.getTotalLine(_data))
-
-    this.setState({edData: _data})
-  }
-
-  addLine = () => {
-    const { BID } = this.props
-    const { edData } = this.state
-
-    let item = {}
-    if (edData.length > 0) {
-      item = {...edData[edData.length - 1]}
-      item.key = item.key + 1
-      item.$$uuid = '$new'
-    } else {
-      item.key = 0
-      item.$$uuid = '$new'
-      item.$$BID = BID || ''
-    }
-
-    this.setState({edData: [...edData, item]})
-  }
-
-  checkData = () => {
-    const { edData } = this.state
-
-    if (edData.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '鎻愪氦鏁版嵁涓嶅彲涓虹┖锛�',
-        duration: 5
-      })
-      return
-    }
-    let err = ''
-    let data = fromJS(edData).toJS().map(item => {
-      // let line = []
-      // fields.forEach(col => {
-      //   if (col.editable !== 'true' || item.$deleted) {
-      //     if (col.type === 'number') {
-      //       item[col.field] = +item[col.field]
-      //       if (isNaN(item[col.field])) {
-      //         item[col.field] = 0
-      //       }
-      //     } else {
-      //       item[col.field] = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     }
-      //     return
-      //   }
-      //   if (col.type === 'text') {
-      //     let val = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     if (col.required === 'true' && !val) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //     }
-      //     item[col.field] = val
-      //   } else if (col.type === 'number') {
-      //     let val = item[col.field]
-      //     if (!val && val !== 0) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //       return
-      //     }
-      //     val = +val
-      //     if (isNaN(val)) {
-      //       line.push(`${col.label}鏁版嵁鏍煎紡閿欒`)
-      //       return
-      //     }
-
-      //     val = +val.toFixed(col.decimal || 0)
-          
-      //     if (typeof(col.max) === 'number' && val > col.max) {
-      //       line.push(`${col.label}涓嶅彲澶т簬${col.max}`)
-      //     } else if (typeof(col.min) === 'number' && val < col.min) {
-      //       line.push(`${col.label}涓嶅彲灏忎簬${col.min}`)
-      //     }
-
-      //     item[col.field] = val
-      //   }
-      // })
-
-      return item
-    })
-
-    if (err) {
-      notification.warning({
-        top: 92,
-        message: err,
-        duration: 5
-      })
-    } else {
-      this.submit(data)
-    }
-  }
-
-  submit = (data) => {
-    const { BID } = this.props
-
-    let param = {
-      // excel_in: result.lines,
-      BID: BID || ''
-    }
-
-    this.setState({
-      loading: true
-    })
-
-    param.func = 'submit.innerFunc'
-
-    Api.genericInterface(param).then((res) => {
-      if (res.status) {
-        this.execSuccess(res)
-      } else {
-        this.execError(res)
-      }
-    }, () => {
-      this.execError({})
-    })
-  }
-
-  execSuccess = (res) => {
-    const { submit } = this.props
-
-    if (res && res.ErrCode === 'S') { // 鎵ц鎴愬姛
-      notification.success({
-        top: 92,
-        message: res.ErrMesg || '鎵ц鎴愬姛',
-        duration: submit.stime ? submit.stime : 2
-      })
-    } else if (res && res.ErrCode === 'Y') { // 鎵ц鎴愬姛
-      Modal.success({
-        title: res.ErrMesg || '鎵ц鎴愬姛'
-      })
-    } else if (res && res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
-
-    }
-
-    this.setState({
-      loading: false
-    })
-
-    if (submit.closetab === 'true') {
-      MKEmitter.emit('popclose')
-    }
-    if (submit.execSuccess !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit)
-    }
-  }
-
-  execError = (res) => {
-    const { submit } = this.props
-
-    if (res.ErrCode === 'E') {
-      Modal.error({
-        title: res.message || res.ErrMesg,
-      })
-    } else if (res.ErrCode === 'N') {
-      notification.error({
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ntime ? submit.ntime : 10
-      })
-    } else if (res.ErrCode === 'F') {
-      notification.error({
-        className: 'notification-custom-error',
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ftime ? submit.ftime : 10
-      })
-    } else if (res.ErrCode === 'NM') {
-      message.error(res.message || res.ErrMesg)
-    }
-    
-    this.setState({
-      loading: false
-    })
-
-    if (submit.execError !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execError, submit)
-    }
-  }
-
-  render() {
-    const { edData, columns} = this.state
-
-    const components = {
-      body: {
-        row: BodyRow,
-        cell: BodyCell
-      }
-    }
-
-    return (
-      <div className="voucher-table-wrap">
-        <Table
-          rowKey="uuid"
-          components={components}
-          columns={columns}
-          dataSource={edData}
-          bordered={true}
-          // loading={this.props.loading}
-          onRow={(record, index) => {
-            return {
-              data: record
-            }
-          }}
-          pagination={false}
-        />
-      </div>
-    )
-  }
-}
-
-export default AssistTable
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/assistTable/index.scss b/src/tabviews/custom/components/module/voucher/assistTable/index.scss
deleted file mode 100644
index e8175c8..0000000
--- a/src/tabviews/custom/components/module/voucher/assistTable/index.scss
+++ /dev/null
@@ -1,259 +0,0 @@
-.voucher-table-wrap {
-  position: relative;
-  padding: 0px;
-
-  .normal-table-footer {
-    padding: 10px 0px;
-    color: rgba(0, 0, 0, 0.65);
-  }
-  .normal-table-footer.pagination {
-    position: absolute;
-    bottom: 10px;
-  }
-  >.ant-table-wrapper {
-    position: relative;
-    z-index: 1;
-  }
-  .ant-table {
-    color: inherit;
-    font-size: inherit;
-  }
-
-  .money-uint {
-    display: flex;
-    span {
-      display: inline-block;
-      flex: 1;
-      text-align: center;
-      font-size: 12px;
-    }
-    span:not(.last) {
-      border-right: 1px solid #e9e9e9;
-    }
-    span:nth-child(3), span:nth-child(6) {
-      border-color: #91d5ff;
-    }
-    span:nth-child(9) {
-      border-color: #ffa39e;
-    }
-  }
-
-  table {
-    max-width: 100%;
-    width: 100%;
-    .ant-table-thead {
-      tr {
-        th {
-          position: relative;
-          background-color: transparent;
-          padding: 0;
-          height: 60px;
-          line-height: 60px;
-          text-align: center;
-
-          .ant-table-header-column {
-            display: block;
-            width: 100%;
-            height: 100%;
-
-            .ant-table-column-title {
-              display: block;
-              width: 100%;
-              height: 100%;
-              font-weight: bold;
-              font-size: 13px;
-            }
-          }
-          .money-title {
-            line-height: 30px;
-            font-weight: bold;
-            font-size: 13px;
-          }
-          .money-uint {
-            line-height: 30px;
-            border-top: 1px solid #dadada;
-          }
-        }
-      }
-    }
-    .ant-table-selection-column {
-      width: 60px;
-      min-width: 60px;
-      max-width: 60px;
-    }
-    .ant-table-tbody {
-      tr td {
-        position: relative;
-        background-color: transparent;
-        padding: 0;
-        height: 60px;
-        vertical-align: top;
-
-        .content-wrap {
-          padding: 5px;
-          height: 100%;
-          font-size: 13px;
-          font-weight: bold;
-        }
-        .money-uint {
-          height: 100%;
-          line-height: 60px;
-
-          span {
-            font-size: 14px;
-            font-weight: bold;
-          }
-        }
-        .money-uint.down {
-          span {
-            color: #ff4d4f;
-          }
-        }
-      }
-    }
-  }
-  .ant-input {
-    height: 60px;
-    border-radius: 0;
-    resize: none;
-  }
-  .ant-input-number {
-    height: 60px;
-    border-radius: 0;
-    
-    .ant-input-number-handler-wrap {
-      display: none;
-    }
-    .ant-input-number-input {
-      border-radius: 0;
-      height: 60px;
-    }
-  }
-  .editing_table_cell {
-    .ant-input {
-      padding: 0px;
-      position: absolute;
-      top: 0px;
-      left: 0px;
-      right: 0px;
-      bottom: 0px;
-      border: 1px solid #1890ff;
-    }
-    .ant-input-number-input {
-      position: absolute;
-      top: 0px;
-      left: 0px;
-      right: 0px;
-      bottom: 0px;
-      border: 1px solid #1890ff;
-    }
-    .anticon {
-      color: #ff4d4f;
-      position: absolute;
-      right: 3px;
-      top: calc(50% - 8px);
-    }
-  }
-  td.pointer {
-    position: relative;
-  }
-  td.pointer {
-    .mk-mask {
-      display: none;
-      cursor: pointer;
-      position: absolute;
-      top: 0;
-      left: 0;
-      bottom: 0;
-      right: 0;
-    }
-  }
-}
-.edit-custom-table.editable {
-  td {
-    background-color: #ffffff!important;
-  }
-  td.pointer .mk-mask {
-    display: block;
-  }
-  .mk-operation {
-    display: none;
-  }
-  .ant-table-placeholder {
-    display: none;
-  }
-}
-.edit-custom-table:not(.fixed-height) {
-  .ant-table-body::-webkit-scrollbar {
-    width: 8px;
-    height: 10px;
-  }
-  ::-webkit-scrollbar-thumb {
-    border-radius: 5px;
-    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-    background: rgba(0, 0, 0, 0.13);
-  }
-  ::-webkit-scrollbar-track {/*婊氬姩鏉¢噷闈㈣建閬�*/
-    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
-    border-radius: 3px;
-    border: 1px solid rgba(0, 0, 0, 0.07);
-    background: rgba(0, 0, 0, 0);
-  }
-}
-.edit-custom-table.fixed-height {
-  .ant-table-body {
-    border-bottom: 1px solid rgba(0, 0, 0, .05);
-    .ant-table-fixed {
-      border-bottom: 0;
-    }
-  }
-}
-.edit-custom-table.hidden {
-  thead {
-    display: none;
-  }
-}
-.edit-custom-table.ghost {
-  .ant-table-thead > tr {
-    > th {
-      color: inherit;
-      background: transparent;
-      .ant-table-column-sorter .ant-table-column-sorter-inner {
-        color: inherit;
-      }
-    }
-    > th:hover {
-      background: transparent;
-    }
-  }
-  .ant-table-body {
-    overflow-x: auto;
-    tr {
-      td {
-        background: transparent!important;
-      }
-    }
-    tr:hover td {
-      background: transparent!important;
-    }
-  }
-}
-.image-scale-modal {
-  width: 70vw;
-  min-height: 80vh;
-  top: 10vh;
-  .ant-modal-body {
-    min-height: calc(80vh - 110px);
-    line-height: calc(80vh - 160px);
-    text-align: center;
-  }
-  .ant-modal-footer {
-    text-align: center;
-    span {
-      display: inline-block;
-      color: #1890ff;
-      padding: 5px 15px;
-      cursor: pointer;
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/index.jsx b/src/tabviews/custom/components/module/voucher/index.jsx
index 1b18806..bc1fd7c 100644
--- a/src/tabviews/custom/components/module/voucher/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/index.jsx
@@ -1,14 +1,17 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Button, Select, Input, DatePicker, notification } from 'antd'
+import { Button, Select, Input, Modal, DatePicker, notification, InputNumber } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
+import Utils from '@/utils/utils.js'
 import asyncComponent from '@/utils/asyncComponent'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
+const { confirm } = Modal
+const { TextArea } = Input
 const VoucherTable = asyncComponent(() => import('./voucherTable'))
 
 class VoucherModule extends Component {
@@ -18,17 +21,24 @@
 
   state = {
     BID: '',
+    type: 'createVoucher',
     config: null,
     loading: false,
     data: [],
-    disableAdd: false,
-    disableSave: false,
+    tbdata: [],
     typeOptions: [],
-    subjects: [],
     charType: '',
+    charName: '',
     charInt: '',
     vouDate: null,
-    book: null
+    book: null,
+    username: sessionStorage.getItem('User_Name'),
+    remark: '',
+    remarkVisible: false,
+    attachments: 0,
+    title: '',
+    delItems: [],
+    status: '' // 鏂板缓鏃讹紝empty銆乧hange銆乻aved
   }
 
   UNSAFE_componentWillMount () {
@@ -46,12 +56,17 @@
       BID = BData.$BID || ''
     }
 
+    window.GLOB.CacheVoucher.delete(config.uuid)
+    let type = config.wrap.type || 'createVoucher'
+
     this.setState({
       config: fromJS(config).toJS(),
+      type: type,
       BID: BID || '',
+      status: 'empty',
       book: window.GLOB.CacheData.get(config.wrap.supBook) || null
     }, () => {
-      this.loadData()
+      this.getVoucher()
     })
   }
 
@@ -94,20 +109,21 @@
     if (!config.wrap.supModule || config.wrap.supModule !== MenuID) return
     if (id !== this.state.BID || id !== '') {
       this.setState({ BID: id, BData: data }, () => {
-        this.loadData()
+        this.getVoucher()
       })
     }
   }
 
   loadData = () => {
-    const { book } = this.state
+    const { book, config } = this.state
 
     if (!book) return
 
     let param = {
       func: 's_get_fcc_account_data',
-      account_code: book.account_code || '',
-      fcc_date: book.months ? book.months + '-01' : moment().format('YYYY-MM-DD')
+      // account_code: book.account_code || '',
+      fcc_date: book.months ? book.months + '-01' : moment().format('YYYY-MM-DD'),
+      BID: book.id
     }
 
     Api.genericInterface(param).then(res => {
@@ -125,91 +141,380 @@
       this.setState({
         typeOptions: typeOptions,
         charType: typeOptions[0] ? typeOptions[0].voucher_class : '',
+        charName: typeOptions[0] ? typeOptions[0].voucher_char : '',
         charInt: typeOptions[0] ? typeOptions[0].voucher_char_int : '',
-        subjects: res.subjects || [],
       })
 
-      setTimeout(() => {
-        this.getVoucher()
-      }, 200)
+      let names = {}
+      let supplier = []
+      let customer = []
+      let department = []
+      let project = []
+      let inventory = []
+      let employee = []
+      let cash_flow = []
+
+      res.sup && res.sup.forEach(item => {
+        names[item.sup_type_code] = item.sup_type_name
+      })
+
+      res.supplier && res.supplier.forEach(item => {
+        supplier.push({value: item.suppliercode, label: item.suppliername})
+      })
+
+      res.customer && res.customer.forEach(item => {
+        customer.push({value: item.customercode, label: item.customername})
+      })
+      
+      res.co_pro && res.co_pro.forEach(item => {
+        department.push({value: item.co_pro_code, label: item.co_pro_name})
+      })
+        
+      res.pm && res.pm.forEach(item => {
+        project.push({value: item.projectcode, label: item.projectname})
+      })
+        
+      res.materiel && res.materiel.forEach(item => {
+        inventory.push({value: item.productcode, label: item.productname})
+      })
+        
+      res.workers && res.workers.forEach(item => {
+        employee.push({value: item.workercode, label: item.workername})
+      })
+        
+      res.cash_flow && res.cash_flow.forEach(item => {
+        cash_flow.push({value: item.cash_flow_code, label: item.cash_flow_name})
+      })
+
+      let message = {
+        subjects: res.subjects || [],
+        names: names,
+        supplier: supplier,
+        customer: customer,
+        department: department,
+        project: project,
+        inventory: inventory,
+        currency: res.currency || [],
+        employee: employee,
+        cash_flow: cash_flow,
+        orgcode: res.orgcode,
+        orgname: res.orgname,
+        account_code: res.account_code,
+        account_year_code: res.account_year_code
+      }
+
+      window.GLOB.CacheVoucher.set(config.uuid, message)
     })
   }
 
-
   getVoucher = () => {
+    const { BID, type } = this.state
+
+    if (!BID || type === 'createVoucher' || type === 'createTemp') return
+
+    let param = {
+      func: 's_get_fcc_voucher',
+      BID: BID
+    }
+
     let data = [
       {remark: '鎻愮幇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: 124, creditor: ''},
       {remark: '璐叆鍥哄畾璧勪骇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: '', creditor: 124},
       {remark: '杞粨閿�鍞垚鏈�', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: -524, creditor: ''},
-      {remark: '鎻愮幇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: 34, creditor: ''},
+      {remark: '鎻愮幇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: 34, creditor: '', i: Math.random()},
     ]
 
-    this.setState({
-      data: data
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      this.setState({
+        data: data,
+        tbdata: fromJS(data).toJS()
+      })
     })
   }
 
-  triggeradd = () => {
-    
+  triggersave = (t) => {
+    const { tbdata, delItems } = this.state
+
+    let err = ''
+    let tip = ''
+    let list = []
+    let _Items = [...delItems]
+
+    tbdata.forEach((line, index) => {
+      if (err) return
+      if (line.type === 'total') {
+        if (line.debtor !== line.creditor) {
+          err = '鍊熻捶涓嶅钩琛★紒'
+        }
+        return
+      }
+
+      let _index = index + 1
+
+      if (!line.remark && !line.subjectscode && !line.debtor && line.debtor !== 0 && !line.creditor && line.creditor !== 0) {
+        if (_index === 1) {
+          err = '绗�1琛屼笉鍙负绌恒��'
+        } else if (line.$origin) {
+          _Items.push(line)
+        }
+
+        return
+      }
+
+      if (!line.remark) {
+        err = `绗�${_index}琛岋紝鎽樿涓嶅彲涓虹┖銆俙
+      } else if (!line.subjectscode) {
+        err = `绗�${_index}琛岋紝绉戠洰涓嶅彲涓虹┖銆俙
+      } else if (!line.debtor && line.debtor !== 0 && !line.creditor && line.creditor !== 0) {
+        err = `绗�${_index}琛岋紝璇疯緭鍏ラ噾棰濄�俙
+      } else if (line.debtor === 0 || line.creditor === 0) {
+        err = `绗�${_index}琛岋紝閲戦涓嶈兘涓�0銆俙
+      } else if (line.foreign_currency_type === 'Y' && !line.origin) {
+        err = `绗�${_index}琛岋紝鍘熷竵涓嶅彲涓虹┖鎴栦负0銆俙
+      } else if (line.sup_accounting) {
+        line.sup_accounting.split(',').forEach(item => {
+          if (!line[item]) {
+            err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+          }
+        })
+      }
+
+      if (line.count_type === 'Y' && !err) {
+        if (!line.count) {
+          tip += `绗�${_index}琛岋紝鏁伴噺涓虹┖鎴栦负0锛侊紱`
+        } else if (line.price) {
+          if (line.debtor && line.debtor !== line.count * line.price) {
+            tip += `绗�${_index}琛岋紝鏁伴噺鍜岄噾棰濅笉鍖归厤锛侊紱`
+          } else if (line.creditor && line.creditor !== line.count * line.price) {
+            tip += `绗�${_index}琛岋紝鏁伴噺鍜岄噾棰濅笉鍖归厤锛侊紱`
+          }
+        }
+      }
+
+      list.push(line)
+    })
+
+    if (!err && list.length === 0) {
+      err = '绗�1琛屼笉鍙负绌恒��'
+    }
+
+    if (err) {
+      notification.warning({
+        top: 92,
+        message: err,
+        duration: 5
+      })
+      return
+    }
+
+    if (tip) {
+      const _this = this
+      confirm({
+        content: tip + '纭瑕佷繚瀛樺悧锛�',
+        onOk() {
+          _this.voucherSave(list, _Items, t)
+        },
+        onCancel() {}
+      })
+    } else {
+      this.voucherSave(list, _Items, t)
+    }
   }
 
-  triggersave = () => {
+  voucherSave = (list, items, t) => {
+    const { config, charInt, charType, vouDate, book, remark, charName, attachments, title } = this.state
 
+    if (!book) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨璐﹀锛�',
+        duration: 5
+      })
+      return
+    }
+
+    let message = window.GLOB.CacheVoucher.get(config.uuid) || {}
+
+    let param = {
+      func: 's_fcc_voucher_addupt',
+      BID: book.id,
+      ID: Utils.getguid(),
+      voucher_code: '',
+      voucher_text: title,
+      remark: remark,
+      account_year_code: book.account_year_code || '',
+      voucher_type: config.wrap.voucherType || '',
+      voucher_type_text: config.wrap.voucherTypeText || '',
+      orgcode: message.orgcode || '',
+      orgname: message.orgname || '',
+      voucher_class: charType,
+      years: book.years,
+      business_type: config.wrap.businessType || '',
+      voucher_sign: config.wrap.voucherSign || '',
+      voucher_char: charName,
+      voucher_char_int: charInt,
+      account_code: book.account_code || '',
+      fibvoucherdate: moment(vouDate).format('YYYY-MM-DD'),
+      UserName: sessionStorage.getItem('User_Name') || '',
+      FullName: sessionStorage.getItem('Full_Name') || '',
+      attachments_int: attachments,
+      sup_data: '',
+      subject_data: ''
+    }
+
+    // subject_id,subject_voucher_code,voucher_lp,subject_code,subject_name
+    // ,subject_voucher_text,fcc_count,net_unitprice,unit,net_amount,direction_type
+    // ,exratecode,exratename,unitratio,sup_accounting ,direction_type_count,src_amount,deleted,local_exratecode
+    
+    let subject_data = list.map(item => {
+      let count = item.count_type === 'Y'
+      let curr = item.foreign_currency_type === 'Y'
+      return `${item.uuid},'','','${item.subjectscode}','${item.subjectsname}','${item.remark}',${count ? item.count || 0 : 0},${count ? item.price || 0 : 0},'${item.unit}',${item.debtor || item.creditor},'${item.debtor ? 'debit' : 'credit'}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.debtor ? 1 : -1},${curr ? item.origin || 0 : 0},0,'${item.local_currency || ''}'`
+    })
+
+    items.forEach(item => {
+      let count = item.count_type === 'Y'
+      let curr = item.foreign_currency_type === 'Y'
+      subject_data.push(`${item.uuid},'','','${item.subjectscode}','${item.subjectsname}','${item.remark}',${count ? item.count || 0 : 0},${count ? item.price || 0 : 0},'${item.unit}',${item.debtor || item.creditor},'${item.debtor ? 'debit' : 'credit'}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.debtor ? 1 : -1},${curr ? item.origin || 0 : 0},1,'${item.local_currency || ''}'`)
+    })
+
+    param.subject_data = window.btoa(window.encodeURIComponent(subject_data.join(';un')))
+
+    if (param) {
+      return
+    }
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      if (t === 'add') {
+        this.setState({
+          status: 'empty',
+          remark: '',
+          tbdata: [],
+          delItems: [],
+          charInt: charInt + 1
+        })
+        MKEmitter.emit('cleartable', config.uuid)
+      } else {
+        this.setState({
+          status: 'saved',
+          delItems: [],
+        })
+      }
+    })
   }
 
   triggerprint = () => {
+    this.setState({remarkVisible: true})
+  }
 
+  remarkSubmit = () => {
+    const { config } = this.state
+    let node = document.getElementById(config.uuid + 'remark')
+    let val = node.value
+
+    if (val && val.length > 512) {
+      notification.warning({
+        top: 92,
+        message: '褰撳墠鍐呭瓒呴暱锛屽娉ㄦ渶澶�512涓瓧绗︺��',
+        duration: 5
+      })
+      return
+    }
+    this.setState({remark: val, remarkVisible: false})
+  }
+
+  dataChange = (data, item) => {
+    if (item) {
+      this.setState({
+        status: 'change',
+        tbdata: data,
+        delItems: [...this.state.delItems, item]
+      })
+    } else {
+      this.setState({
+        status: 'change',
+        tbdata: data
+      })
+    }
+  }
+
+  changeAttach = (val) => {
+    let _val = val
+
+    if (isNaN(val) || val < 0) {
+      _val = 0
+    } else {
+      _val = parseInt(val)
+    }
+    
+    this.setState({attachments: _val})
   }
 
   render() {
-    const { config, disableSave, disableAdd, typeOptions, charType, charInt, data, vouDate, subjects } = this.state
+    const { type, status, loading, config, typeOptions, charType, charInt, data, vouDate, username, remark, remarkVisible, attachments, title } = this.state
 
     return (
       <div className="menu-voucher-wrap" style={config.style}>
-        <div className="voucher-header">
-          <Button className="add-background header-btn" disabled={disableAdd} onClick={this.triggeradd}>鏂板</Button>
-          <Button className="add-background header-btn" disabled={disableSave} onClick={this.triggersave}>淇濆瓨</Button>
-          <Button className="print-background header-btn" disabled={disableSave} onClick={this.triggerprint}>鎵撳嵃</Button>
-          <Button className="system-background header-btn" disabled={disableSave} onClick={this.triggerprint}>瀵煎叆</Button>
-          <Button className="out-background header-btn" disabled={disableSave} onClick={this.triggerprint}>瀵煎嚭</Button>
-        </div>
-        {config.wrap.type === 'edit' ? <div className="voucher-body">
-          <div className="pre-wrap">
+        {type === 'createVoucher' ? <div className="voucher-header">
+          <Button className="add-background header-btn" disabled={status === 'empty'} onClick={() => this.triggersave('add')}>淇濆瓨骞舵柊澧�</Button>
+          <Button className="add-background header-btn" disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>淇濆瓨</Button>
+          <Button className="print-background header-btn" disabled={status !== 'saved'} onClick={this.triggerprint}>鎵撳嵃</Button>
+          <Button className="out-background header-btn" onClick={this.triggerprint}>鏇村</Button>
+        </div> : null}
+        <div className="voucher-body">
+          {type === 'createVoucher' ? <div className="pre-wrap">
             <div className="voucher-code">
-              <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({charType: val, charInt: option.props.charint})}>
+              <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({charType: val, charName: option.props.charName, charInt: option.props.charint})}>
                 {typeOptions.map(option =>
-                  <Select.Option key={option.voucher_char_int} value={option.voucher_class} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
+                  <Select.Option key={option.voucher_char_int} value={option.voucher_class} charName={option.voucher_char} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
                 )}
               </Select>
-              <Input value={charInt} autoComplete="off" onChange={(e) => this.setState({charInt: e.target.value})}/> 鍙�
+              <InputNumber precision={0} min={1} value={charInt} autoComplete="off" onChange={(val) => this.setState({charInt: val})}/> 鍙�
             </div>
             <div className="voucher-date">
               鏃ユ湡锛�<DatePicker value={vouDate} onChange={(val) => this.setState({vouDate: val})}/>
             </div>
+            <div className="voucher-text">
+              <Input value={title} placeholder="鍑瘉鏂囨湰" autoComplete="off" onChange={(e) => this.setState({title: e.target.value})}/>
+            </div>
             <div className="voucher-affix">
-              闄勫崟鎹� <Input autoComplete="off" /> 寮�
+              闄勫崟鎹� <InputNumber precision={0} value={attachments || 0} autoComplete="off" onChange={this.changeAttach}/> 寮�
               <Button type="link" className="" onClick={this.triggerprint}>闄勪欢</Button>
               <Button type="link" className="" onClick={this.triggerprint}>澶囨敞</Button>
             </div>
-          </div>
-          <VoucherTable config={config} subjects={subjects} data={data}/>
-        </div> : null}
-        {config.wrap.type === 'check' ? <div className="voucher-body">
-          <div className="pre-wrap">
-            <div className="voucher-code">
-              璁� 1 鍙�
-            </div>
-            <div className="voucher-date">
-              鏃ユ湡锛�2022-02-24
-            </div>
-            <div className="voucher-affix">
-              闄勫崟鎹� 2 寮�
-              <Button type="link" className="" onClick={this.triggerprint}>闄勪欢</Button>
-              <Button type="link" className="" onClick={this.triggerprint}>澶囨敞</Button>
-            </div>
-          </div>
-          <VoucherTable config={config} data={data}/>
-        </div> : null}
+          </div> : null}
+          <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
+        </div>
+        <div className="user">鍒跺崟浜猴細{username}</div>
+        <Modal
+          title="澶囨敞"
+          visible={remarkVisible}
+          width={700}
+          maskClosable={false}
+          onOk={this.remarkSubmit}
+          onCancel={() => { this.setState({ remarkVisible: false })}}
+          destroyOnClose
+        >
+          <TextArea id={config.uuid + 'remark'} defaultValue={remark} rows={6}/>
+        </Modal>
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/module/voucher/index.scss b/src/tabviews/custom/components/module/voucher/index.scss
index e3b1dd9..aa48f4d 100644
--- a/src/tabviews/custom/components/module/voucher/index.scss
+++ b/src/tabviews/custom/components/module/voucher/index.scss
@@ -20,7 +20,7 @@
     }
   }
   .voucher-body {
-    padding: 0 15px;
+    padding: 0 30px;
     .voucher-code {
       display: inline-block;
       width: 160px;
@@ -33,6 +33,22 @@
       .ant-input {
         width: 60px;
       }
+      .ant-input-number {
+        display: inline-block;
+        width: 60px;
+        .ant-input-number-handler-wrap {
+          display: none;
+        }
+      }
+    }
+    .voucher-affix {
+      .ant-input-number {
+        display: inline-block;
+        width: 50px;
+        .ant-input-number-handler-wrap {
+          display: none;
+        }
+      }
     }
     .pre-wrap {
       padding: 10px 0px;
@@ -43,9 +59,14 @@
         width: 120px;
       }
     }
+    .voucher-text {
+      display: inline-block;
+      width: calc(56% - 350px);
+      margin-left: 12px;
+    }
     .voucher-affix {
       float: right;
-      width: 250px;
+      width: 240px;
       .ant-input {
         width: 60px;
       }
@@ -73,6 +94,9 @@
     border-color: var(--mk-sys-color);
     color: #ffffff;
   }
+  .user {
+    padding: 15px 30px 0px;
+  }
 }
 
 .mk-vcode-dropdown {
diff --git a/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx b/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
index b79fdd7..9a37f76 100644
--- a/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
@@ -1,13 +1,11 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Table, Modal, Input, InputNumber, notification, message, AutoComplete, Select } from 'antd'
+import { Table, Form, Input, InputNumber, notification, AutoComplete, Select, Popover, Button } from 'antd'
+import { PlusOutlined, CloseOutlined } from '@ant-design/icons'
 
-import Api from '@/api'
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
-import zhCN from '@/locales/zh-CN/main.js'
-import enUS from '@/locales/en-US/main.js'
 import './index.scss'
 
 class BodyRow extends React.Component {
@@ -24,14 +22,108 @@
   }
 }
 
+class Accounting extends React.Component {
+  state = {
+    subAccounts: [],
+    record: null
+  }
+
+  UNSAFE_componentWillMount() {
+    const { data, tableId } = this.props
+    let subAccounts = data.sup_accounting.split(',')
+    let msg = window.GLOB.CacheVoucher.get(tableId) || {}
+    let names = msg.names || {}
+
+    subAccounts = subAccounts.map(n => {
+      let item = {
+        field: n,
+        label: names[n] || n,
+        initval: data[n] || '',
+        options: []
+      }
+
+      if (msg[n]) {
+        item.options = msg[n]
+      }
+
+      return item
+    })
+
+    this.setState({subAccounts: subAccounts, record: fromJS(data).toJS()})
+  }
+
+  selectChange = (val, item) => {
+    this.setState({record: {...this.state.record, [item.field]: val || ''}})
+  }
+
+  getFields() {
+    const { subAccounts } = this.state
+
+    const fields = []
+
+    subAccounts.forEach((item) => {
+      fields.push(
+        <Form.Item label={item.label} key={item.field}>
+          <Select
+            showSearch
+            allowClear
+            defaultValue={item.initval}
+            dropdownMatchSelectWidth={false}
+            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+            onChange={(val) => this.selectChange(val, item)}
+          >
+            {item.options.map((option, i) =>
+              <Select.Option key={i} value={option.value}>{option.label}</Select.Option>
+            )}
+          </Select>
+        </Form.Item>
+      )
+    })
+    
+    return fields
+  }
+
+  confirm = () => {
+    const { subAccounts, record } = this.state
+
+    let empty = ''
+    subAccounts.forEach(item => {
+      if (!empty && !record[item.field]) {
+        empty = item.label
+      }
+    })
+
+    if (empty) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨' + empty,
+        duration: 5
+      })
+    } else {
+      this.props.confirm(record)
+    }
+  }
+
+  render() {
+    return <div>
+      {this.getFields()}
+      <div className="footer">
+        <Button onClick={this.props.cancel}>鍙栨秷</Button>
+        <Button onClick={this.confirm}>纭畾</Button>
+      </div>
+    </div>
+  }
+}
+
 class BodyCell extends React.Component {
   state = {
     editing: false,
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props.record), fromJS(nextProps.record)) ||
-      nextState.editing !== this.state.editing
+    visible: false,
+    counting: false,
+    priceing: false,
+    curring: false,
+    ratioing: false,
+    origining: false,
   }
 
   componentDidMount () {
@@ -62,20 +154,43 @@
 
     this.setState({editing: false})
 
-    if (value !== record[col.field]) {
-      let line = {...record, [col.field]: value}
+    let line = {...record}
+    line[col.field] = value
 
-      if (col.field === 'debtor') {
-        line.creditor = ''
-      } else {
+    if (col.field === 'debtor') {
+      line.creditor = ''
+      if (isNaN(line.debtor)) {
         line.debtor = ''
       }
-
-      MKEmitter.emit('changeRecord', col.tableId, line)
+    } else {
+      line.debtor = ''
+      if (isNaN(line.creditor)) {
+        line.creditor = ''
+      }
     }
 
+    if (line.count_type === 'Y' && line.count) {
+      if (line.debtor) {
+        line.price = Math.round(line.debtor / line.count * 10000) / 10000
+      } else if (line.creditor) {
+        line.price = Math.round(line.creditor / line.count * 10000) / 10000
+      }
+    }
+
+    if (line.foreign_currency_type === 'Y' && line.origin) {
+      if (line.debtor) {
+        line.unitratio = Math.round(line.debtor / line.origin * 100000) / 100000
+      } else if (line.creditor) {
+        line.unitratio = Math.round(line.creditor / line.origin * 100000) / 100000
+      }
+    }
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
     setTimeout(() => {
-      if (col.field === 'creditor') {
+      if (col.field === 'debtor' && (line.debtor || line.debtor === 0)) {
+        MKEmitter.emit('nextLine', col, record)
+      } else if (col.field === 'creditor') {
         MKEmitter.emit('nextLine', col, record)
       } else {
         let cl = {remark: 'subjectscode', subjectscode: 'debtor', debtor: 'creditor'}
@@ -91,10 +206,8 @@
 
     if (col.field === 'subjectscode') {
       this.setState({editing: true}, () => {
-        try {
-          let node = document.getElementById(col.uuid + record.uuid)
-          node.click()
-        } catch(e) {}
+        let node = document.getElementById(col.uuid + record.uuid)
+        node && node.click()
       })
     } else {
       this.setState({editing: true, value: record[col.field]}, () => {
@@ -110,15 +223,35 @@
 
     this.setState({editing: false})
 
-    if (col.field === 'subjectscode') return
-
     if (value !== record[col.field]) {
       let line = {...record, [col.field]: value}
 
       if (col.field === 'debtor') {
         line.creditor = ''
+        if (isNaN(line.debtor)) {
+          line.debtor = ''
+        }
       } else {
         line.debtor = ''
+        if (isNaN(line.creditor)) {
+          line.creditor = ''
+        }
+      }
+
+      if (line.count_type === 'Y' && line.count) {
+        if (line.debtor) {
+          line.price = Math.round(line.debtor / line.count * 10000) / 10000
+        } else if (line.creditor) {
+          line.price = Math.round(line.creditor / line.count * 10000) / 10000
+        }
+      }
+
+      if (line.foreign_currency_type === 'Y' && line.origin) {
+        if (line.debtor) {
+          line.unitratio = Math.round(line.debtor / line.origin * 100000) / 100000
+        } else if (line.creditor) {
+          line.unitratio = Math.round(line.creditor / line.origin * 100000) / 100000
+        }
       }
 
       MKEmitter.emit('changeRecord', col.tableId, line)
@@ -135,26 +268,382 @@
     })
   }
 
+  plusLine = () => {
+    const { col, record } = this.props
+
+    MKEmitter.emit('plusLine', col.tableId, record)
+  }
+
+  delRecord = () => {
+    const { col, record } = this.props
+
+    MKEmitter.emit('delRecord', col.tableId, record)
+  }
+
+  onSelectBlur = () => {
+    const { visible } = this.state
+
+    if (visible) return
+
+    this.setState({editing: false})
+  }
+
   onSelectChange = (val, option) => {
     const { col, record } = this.props
 
-    this.setState({editing: false})
+    let line = {...record, ...option.props.extra}
+
+    if (record.sup_accounting && !line.sup_accounting) {
+      record.sup_accounting.split(',').forEach(item => {
+        line[item] = ''
+      })
+    }
+
+    if (line.foreign_currency_type === 'Y' && line.foreign_currency) {
+      let msg = window.GLOB.CacheVoucher.get(col.tableId)
+      let cur = msg ? msg.currency.filter(n => n.exratename === line.foreign_currency)[0] : null
+      if (cur) {
+        line = {...line, ...cur}
+      }
+
+      this.currencyChange(line)
+    }
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    if (line.sup_accounting) {
+      setTimeout(() => {
+        this.setState({visible: true})
+      }, 100)
+    } else if (line.count_type === 'Y') {
+      this.setState({counting: true, value: line.count || 0}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'count')
+        node && node.select()
+      })
+    } else if (line.foreign_currency_type === 'Y') {
+      this.setState({curring: true}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'currency')
+        node && node.click()
+      })
+    } else {
+      this.setState({editing: false, visible: false, counting: false, priceing: false})
+      setTimeout(() => {
+        MKEmitter.emit('tdFocus', 'debtor' + record.uuid)
+      }, 50)
+    }
+  }
+
+  confirm = (res) => {
+    const { col } = this.props
+
+    MKEmitter.emit('changeRecord', col.tableId, fromJS(res).toJS())
+
+    this.setState({editing: false, visible: false})
+
+    if (res.count_type === 'Y') {
+      this.setState({counting: true, value: res.count || 0}, () => {
+        let node = document.getElementById(col.uuid + res.uuid + 'count')
+        node && node.select()
+      })
+    } else {
+      setTimeout(() => {
+        MKEmitter.emit('tdFocus', 'debtor' + res.uuid)
+      }, 50)
+    }
+  }
+
+  cancel = () => {
+    const { col } = this.props
+    let record = fromJS(this.props.record).toJS()
+    record.balance_direction = ''
+    record.count_type = ''
+    record.foreign_currency_type = ''
+    record.mnemonic_code = ''
+    record.subjectscode = ''
+    record.subjectsname = ''
+    record.sup_accounting.split(',').forEach(item => {
+      record[item] = ''
+    })
+
+    record.sup_accounting = ''
+
+    MKEmitter.emit('changeRecord', col.tableId, record)
+
+    this.setState({editing: false, visible: false})
+  }
+
+  editCount = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({counting: true, value: record.count || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'count')
+      node && node.select()
+    })
+  }
+
+  editPrice = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({priceing: true, value: record.price || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'price')
+      node && node.select()
+    })
+  }
+
+  countPress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.count = value || 0
+
+    if (isNaN(line.count)) {
+      line.count = 0
+    }
+
+    this.countChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({counting: false, priceing: true, value: line.price || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'price')
+      node && node.select()
+    })
+  }
+
+  countBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({counting: false})
+
+    let line = {...record}
+    line.count = value || 0
+
+    if (isNaN(line.count)) {
+      line.count = 0
+    }
+
+    this.countChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  pricePress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.price = value || 0
+
+    if (isNaN(line.price)) {
+      line.price = 0
+    }
+
+    this.countChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({priceing: false})
+    setTimeout(() => {
+      MKEmitter.emit('tdFocus', 'debtor' + record.uuid)
+    }, 50)
+  }
+
+  priceBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({priceing: false})
+
+    let line = {...record}
+    line.price = value || 0
+
+    if (isNaN(line.price)) {
+      line.price = 0
+    }
+
+    this.countChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  editCurrency = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({curring: true}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'currency')
+      node && node.click()
+    })
+  }
+
+  onCurrSelectChange = (val, option) => {
+    const { col, record } = this.props
 
     let line = {...record, ...option.props.extra}
 
+    this.currencyChange(line)
+
     MKEmitter.emit('changeRecord', col.tableId, line)
+
+    if (line.exratename === 'CNY') {
+      this.setState({curring: false, origining: true, value: line.origin || 0}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'origin')
+        node && node.select()
+      })
+    } else {
+      this.setState({curring: false, ratioing: true, value: line.unitratio || 1}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'ratio')
+        node && node.select()
+      })
+    }
+  }
+
+  editRatio = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({ratioing: true, value: record.unitratio || 1}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'ratio')
+      node && node.select()
+    })
+  }
+
+  ratioPress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.unitratio = value || 1
+
+    if (isNaN(line.unitratio)) {
+      line.unitratio = 1
+    }
+
+    this.currencyChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({ratioing: false, origining: true, value: line.origin || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'origin')
+        node && node.select()
+    })
+  }
+
+  ratioBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({ratioing: false})
+
+    let line = {...record}
+    line.unitratio = value || 1
+
+    if (isNaN(line.unitratio)) {
+      line.unitratio = 1
+    }
+
+    this.currencyChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  editOrigin = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({origining: true, value: record.origin || 1}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'origin')
+      node && node.select()
+    })
+  }
+
+  originPress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.origin = value || 0
+
+    if (isNaN(line.origin)) {
+      line.origin = 0
+    }
+
+    this.currencyChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({origining: false})
 
     setTimeout(() => {
       MKEmitter.emit('tdFocus', 'debtor' + record.uuid)
     }, 50)
   }
 
+  originBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({origining: false})
+
+    let line = {...record}
+    line.origin = value || 0
+
+    if (isNaN(line.origin)) {
+      line.origin = 0
+    }
+
+    this.currencyChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  countChange = (line) => {
+    if (line.count && line.price) {
+      if (line.creditor) {
+        line.creditor = Math.round(line.count * line.price * 100) / 100
+      } else {
+        line.debtor = Math.round(line.count * line.price * 100) / 100
+      }
+
+      if (line.foreign_currency_type === 'Y' && line.origin) {
+        if (line.debtor) {
+          line.unitratio = Math.round(line.debtor / line.origin * 100000) / 100000
+        } else if (line.creditor) {
+          line.unitratio = Math.round(line.creditor / line.origin * 100000) / 100000
+        }
+      }
+    }
+  }
+
+  currencyChange = (line) => {
+    if (line.unitratio && line.origin) {
+      if (line.creditor) {
+        line.creditor = Math.round(line.unitratio * line.origin * 100) / 100
+      } else {
+        line.debtor = Math.round(line.unitratio * line.origin * 100) / 100
+      }
+
+      if (line.count_type === 'Y' && line.count) {
+        if (line.debtor) {
+          line.price = Math.round(line.debtor / line.count * 10000) / 10000
+        } else if (line.creditor) {
+          line.price = Math.round(line.creditor / line.count * 10000) / 10000
+        }
+      }
+    }
+  }
+
   render() {
-    let { col, record, subjects, className } = this.props
-    const { editing } = this.state
+    let { col, record, className } = this.props
+    const { editing, visible, counting, priceing, curring, ratioing, origining } = this.state
 
     let children = null
     let colSpan = 1
+    let extra = null
 
     if (col.field === 'remark') {
       let val = record.remark || ''
@@ -163,6 +652,8 @@
         children = <div className="content-wrap" style={{lineHeight: '60px'}}>鍚堣: {val}</div>
         colSpan = 2
       } else {
+        extra = <PlusOutlined onClick={this.plusLine}/>
+
         if (editing) {
           let options = ['鐜伴噾', '鍙戠エ']
           children = <AutoComplete
@@ -186,60 +677,197 @@
         colSpan = 0
       } else {
         if (editing) {
-          children = <Select
-            showSearch
-            defaultValue={record.subjectscode || ''}
-            dropdownClassName="edit-table-dropdown"
-            id={col.uuid + record.uuid}
-            onBlur={this.onBlur}
-            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-            onSelect={this.onSelectChange}
-          >
-            {subjects.map((item, i) => (<Select.Option key={i} extra={item} value={item.subjectscode}>{item.subjectscode + ' ' + item.subjectsname}</Select.Option>))}
-          </Select>
+          let msg = window.GLOB.CacheVoucher.get(col.tableId)
+          let subjects = msg ? msg.subjects : []
+
+          children = <>
+            <Select
+              showSearch
+              defaultValue={record.subjectscode || ''}
+              dropdownClassName="edit-table-dropdown"
+              id={col.uuid + record.uuid}
+              onBlur={this.onSelectBlur}
+              filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+              onSelect={this.onSelectChange}
+            >
+              {subjects.map((item, i) => (<Select.Option key={i} extra={item} value={item.subjectscode}>{item.subjectscode + ' ' + item.subjectsname}</Select.Option>))}
+            </Select>
+            <Popover overlayClassName="subject-pop-wrap" placement="bottom" title="" visible={visible} content={<Accounting confirm={this.confirm} cancel={this.cancel} tableId={col.tableId} data={record}/>}>
+              <span className="pop-anchor"></span>
+            </Popover>
+          </>
         } else {
           let val = ''
           if (record.subjectscode) {
             val = (record.subjectscode || '') + ' ' + (record.subjectsname || '')
+
+            record.sup_accounting && record.sup_accounting.split(',').forEach(item => {
+              if (record[item]) {
+                val += '_' + record[item]
+              }
+            })
           }
-          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
+
+          let countNode = null
+          let currencyNode = null
+
+          if (record.count_type === 'Y') {
+            if (counting) {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={(e) => e.stopPropagation()}>
+                  <span>鏁伴噺锛�</span>
+                  <span><InputNumber precision={4} className="inner-input" id={col.uuid + record.uuid + 'count'} defaultValue={record.count || 0} onChange={(val) => this.onChange(val)} onPressEnter={this.countPress} onBlur={this.countBlur}/></span>
+                </span>
+                <span onClick={this.editPrice}>
+                  <span>鍗曚环锛�</span>
+                  <span>{record.price || 0}</span>
+                </span>
+              </div>
+            } else if (priceing) {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCount}>
+                  <span>鏁伴噺锛�</span>
+                  <span>{record.count || 0}</span>
+                </span>
+                <span onClick={(e) => e.stopPropagation()}>
+                  <span>鍗曚环锛�</span>
+                  <span><InputNumber precision={4} className="inner-input" id={col.uuid + record.uuid + 'price'} defaultValue={record.price || 0} onChange={(val) => this.onChange(val)} onPressEnter={this.pricePress} onBlur={this.priceBlur}/></span>
+                </span>
+              </div>
+            } else {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCount}>
+                  <span>鏁伴噺锛�</span>
+                  <span>{record.count || 0}</span>
+                </span>
+                <span onClick={this.editPrice}>
+                  <span>鍗曚环锛�</span>
+                  <span>{record.price || 0}</span>
+                </span>
+              </div>
+            }
+          }
+
+          if (record.foreign_currency_type === 'Y') {
+            if (curring) {
+              let msg = window.GLOB.CacheVoucher.get(col.tableId)
+              let currency = msg ? msg.currency : []
+
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={(e) => e.stopPropagation()}>
+                  <span>璐у竵锛�</span>
+                  <span>
+                    <Select
+                      className="currency-select"
+                      defaultValue={record.exratename || ''}
+                      dropdownClassName="edit-table-dropdown"
+                      id={col.uuid + record.uuid + 'currency'}
+                      onBlur={() => this.setState({curring: false})}
+                      onSelect={this.onCurrSelectChange}
+                    >
+                      {currency.map((item, i) => (<Select.Option key={i} extra={item} value={item.exratename}>{item.exratename}</Select.Option>))}
+                    </Select>
+                  </span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={this.editRatio}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span onClick={this.editOrigin}>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.origin || 0}</span>
+                </span>
+              </div>
+            } else if (ratioing) {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={(e) => e.stopPropagation()}>
+                  <span>姹囩巼锛�</span>
+                  <span><InputNumber precision={5} className="inner-input" id={col.uuid + record.uuid + 'ratio'} defaultValue={record.unitratio || 1} onChange={(val) => this.onChange(val)} onPressEnter={this.ratioPress} onBlur={this.ratioBlur}/></span>
+                </span>
+                <span onClick={this.editOrigin}>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.origin || 0}</span>
+                </span>
+              </div>
+            } else if (origining) {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={this.editRatio}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span onClick={(e) => e.stopPropagation()}>
+                  <span>鍘熷竵锛�</span>
+                  <span><InputNumber precision={2} className="inner-input" id={col.uuid + record.uuid + 'origin'} defaultValue={record.origin || 0} onChange={(val) => this.onChange(val)} onPressEnter={this.originPress} onBlur={this.originBlur}/></span>
+                </span>
+              </div>
+            } else {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={this.editRatio}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span onClick={this.editOrigin}>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.origin || 0}</span>
+                </span>
+              </div>
+            }
+          }
+
+          children = <div className="content-wrap" onClick={this.focus}>
+            {val}
+            {countNode}
+            {currencyNode}
+          </div>
         }
       }
     } else if (col.field === 'debtor') {
-      let val = record.debtor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
-
       if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
+        children = <InputNumber id={col.uuid + record.uuid} precision={2} defaultValue={record.debtor} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
       } else {
+        let val = record.debtor
+        let down = false
+        let vals = []
+        if (!isNaN(val) && val !== '') {
+          if (val < 0) {
+            down = true
+            val = Math.abs(val)
+          }
+          vals = (val * 100).toFixed(0).split('').reverse()
+        }
         children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
           <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
           <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
         </div>
       }
     } else if (col.field === 'creditor') {
-      let val = record.creditor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
+      extra = <CloseOutlined onClick={this.delRecord}/>
 
       if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
+        children = <InputNumber id={col.uuid + record.uuid} precision={2} defaultValue={record.creditor} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
       } else {
+        let val = record.creditor
+        let down = false
+        let vals = []
+        if (!isNaN(val) && val !== '') {
+          if (val < 0) {
+            down = true
+            val = Math.abs(val)
+          }
+          vals = (val * 100).toFixed(0).split('').reverse()
+        }
         children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
         <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
         <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
@@ -249,34 +877,27 @@
 
     if (!colSpan) return null
 
-    return (<td colSpan={colSpan} className={className}>{children}</td>)
+    return (<td colSpan={colSpan} className={className}>{children}{extra}</td>)
   }
 }
 
 class VoucherTable extends Component {
   static propTpyes = {
     config: PropTypes.object,        // 鑿滃崟Id
-    subjects: PropTypes.array,       // 浼氳绉戠洰
-    BID: PropTypes.any,              // 涓昏〃ID
     data: PropTypes.any,             // 琛ㄦ牸鏁版嵁
-    total: PropTypes.any,            // 鎬绘暟
     loading: PropTypes.bool,         // 琛ㄦ牸鍔犺浇涓�
-    refreshdata: PropTypes.func,     // 琛ㄦ牸涓帓搴忓垪銆侀〉鐮佺殑鍙樺寲鏃跺埛鏂�
+    onChange: PropTypes.func,        // 琛ㄦ牸鍙樺姩
   }
 
   state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     data: [],
     edData: [],
-    edColumns: [],
     tableId: '',          // 琛ㄦ牸ID
-    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
     columns: null,        // 鏄剧ず鍒�
-    loading: false,
   }
 
   UNSAFE_componentWillMount () {
-    const { config, subjects, data } = this.props
+    const { config, data } = this.props
 
     let columns = [
       {
@@ -296,7 +917,6 @@
         width: '34%',
         onCell: record => ({
           record,
-          subjects,
           col: {uuid: 'subjectscode', field: 'subjectscode', tableId: config.uuid},
         })
       },
@@ -347,7 +967,9 @@
 
   componentDidMount () {
     MKEmitter.addListener('nextLine', this.nextLine)
+    MKEmitter.addListener('plusLine', this.plusLine)
     MKEmitter.addListener('delRecord', this.delRecord)
+    MKEmitter.addListener('cleartable', this.cleartable)
     MKEmitter.addListener('changeRecord', this.changeRecord)
   }
 
@@ -359,40 +981,24 @@
       return
     }
     MKEmitter.removeListener('nextLine', this.nextLine)
+    MKEmitter.removeListener('plusLine', this.plusLine)
     MKEmitter.removeListener('delRecord', this.delRecord)
+    MKEmitter.removeListener('cleartable', this.cleartable)
     MKEmitter.removeListener('changeRecord', this.changeRecord)
   }
 
   UNSAFE_componentWillReceiveProps(nextProps) {
     if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
       this.resetData(fromJS(nextProps.data).toJS())
-    } else if (!is(fromJS(this.props.subjects), fromJS(nextProps.subjects))) {
-      this.resetSubjects(nextProps.subjects)
     }
   }
 
-  resetSubjects = (subjects) => {
-    const { config } = this.props
-    let columns = fromJS(this.state.columns).toJS()
+  cleartable = (tbid) => {
+    const { tableId } = this.state
 
-    this.setState({
-      columns: columns.map(col => {
-        if (col.key === 'subjectscode') {
-          return {
-            title: '浼氳绉戠洰',
-            dataIndex: 'subjectscode',
-            key: 'subjectscode',
-            width: '34%',
-            onCell: record => ({
-              record,
-              subjects,
-              col: {uuid: 'subjectscode', field: 'subjectscode', tableId: config.uuid},
-            })
-          }
-        }
-        return col
-      })
-    })
+    if (tbid !== tableId) return
+
+    this.resetData([])
   }
 
   resetData = (data) => {
@@ -400,39 +1006,44 @@
     data.push(this.getTotalLine(data))
 
     this.setState({
-      edData: data
+      edData: []
+    }, () => {
+      this.setState({
+        edData: data
+      })
     })
   }
 
   initData = (data) => {
     let _data = data.map((item, i) => {
-      item.uuid = Utils.getuuid()
+      // item.uuid = Utils.getguid()
       item.index = i
+      item.$origin = true
       
       return item
     })
 
     if (_data.length < 4) {
       for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
+        _data.push({uuid: Utils.getguid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
       }
     }
     return _data
   }
 
   getTotalLine = (data) => {
-    let totalLine = {uuid: Utils.getuuid(), type: 'total'}
+    let totalLine = {uuid: Utils.getguid(), type: 'total'}
     let debtor = ''
     let creditor = ''
 
     data.forEach(item => {
-      if (typeof(item.debtor) === 'number') {
+      if (!isNaN(item.debtor) && item.debtor !== '') {
         if (debtor === '') {
           debtor = 0
         }
 
         debtor += item.debtor
-      } else if (typeof(item.creditor) === 'number') {
+      } else if (!isNaN(item.creditor) && item.creditor !== '') {
         if (debtor === '') {
           debtor = 0
         }
@@ -543,27 +1154,33 @@
       MKEmitter.emit('tdFocus', 'remark' + edData[record.index + 1].uuid)
     } else {
       let _data = fromJS(edData).toJS()
-      let line = {uuid: Utils.getuuid(), index: _data.length - 1, remark: record.remark || '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''}
+      let line = {uuid: Utils.getguid(), index: _data.length - 1, remark: record.remark || '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''}
 
       _data.splice(_data.length - 1, 0, line)
 
       this.setState({edData: _data}, () => {
         MKEmitter.emit('tdFocus', 'remark' + line.uuid)
       })
+      this.props.onChange(_data)
     }
   }
 
-  plusLine = (initEditLine) => {
-    const { edData } = this.state
+  plusLine = (tid, record) => {
+    const { edData, tableId } = this.state
 
-    let item = {...edData[edData.length - 1]}
+    if (tid !== tableId) return
 
-    item.key = item.key + 1
-    item.$$uuid = '$new'
+    let _data = fromJS(edData).toJS()
+    let line = {uuid: Utils.getguid(), index: 0, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''}
 
-    this.setState({edData: [...edData, item]}, () => {
-      MKEmitter.emit('tdFocus', initEditLine.uuid + item.uuid)
+    _data.splice(record.index, 0, line)
+    _data = _data.map((item, index) => {
+      item.index = index
+      return item
     })
+
+    this.setState({edData: _data})
+    this.props.onChange(_data)
   }
 
   delRecord = (id, record) => {
@@ -571,19 +1188,25 @@
 
     if (id !== tableId) return
 
-    let _data = edData.filter(item => item.uuid !== record.uuid)
+    let _data = fromJS(edData).toJS().filter(item => item.uuid !== record.uuid)
 
     _data.pop()
 
     if (_data.length < 4) {
-      for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
+      for (let i = _data.length; i < 4; i++) {
+        _data.push({uuid: Utils.getguid(), index: 0, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
       }
     }
+
+    _data = _data.map((item, index) => {
+      item.index = index
+      return item
+    })
 
     _data.push(this.getTotalLine(_data))
 
     this.setState({edData: _data})
+    this.props.onChange(_data, record.$origin ? record : null)
   }
 
   changeRecord = (tableId, record) => {
@@ -600,187 +1223,13 @@
     _data.pop()
 
     if (record.index === _data.length - 1) {
-      _data.push({uuid: Utils.getuuid(), index: record.index + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
+      _data.push({uuid: Utils.getguid(), index: record.index + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
     }
 
     _data.push(this.getTotalLine(_data))
 
     this.setState({edData: _data})
-  }
-
-  addLine = () => {
-    const { BID } = this.props
-    const { edData } = this.state
-
-    let item = {}
-    if (edData.length > 0) {
-      item = {...edData[edData.length - 1]}
-      item.key = item.key + 1
-      item.$$uuid = '$new'
-    } else {
-      item.key = 0
-      item.$$uuid = '$new'
-      item.$$BID = BID || ''
-    }
-
-    this.setState({edData: [...edData, item]})
-  }
-
-  checkData = () => {
-    const { edData } = this.state
-
-    if (edData.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '鎻愪氦鏁版嵁涓嶅彲涓虹┖锛�',
-        duration: 5
-      })
-      return
-    }
-    let err = ''
-    let data = fromJS(edData).toJS().map(item => {
-      // let line = []
-      // fields.forEach(col => {
-      //   if (col.editable !== 'true' || item.$deleted) {
-      //     if (col.type === 'number') {
-      //       item[col.field] = +item[col.field]
-      //       if (isNaN(item[col.field])) {
-      //         item[col.field] = 0
-      //       }
-      //     } else {
-      //       item[col.field] = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     }
-      //     return
-      //   }
-      //   if (col.type === 'text') {
-      //     let val = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     if (col.required === 'true' && !val) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //     }
-      //     item[col.field] = val
-      //   } else if (col.type === 'number') {
-      //     let val = item[col.field]
-      //     if (!val && val !== 0) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //       return
-      //     }
-      //     val = +val
-      //     if (isNaN(val)) {
-      //       line.push(`${col.label}鏁版嵁鏍煎紡閿欒`)
-      //       return
-      //     }
-
-      //     val = +val.toFixed(col.decimal || 0)
-          
-      //     if (typeof(col.max) === 'number' && val > col.max) {
-      //       line.push(`${col.label}涓嶅彲澶т簬${col.max}`)
-      //     } else if (typeof(col.min) === 'number' && val < col.min) {
-      //       line.push(`${col.label}涓嶅彲灏忎簬${col.min}`)
-      //     }
-
-      //     item[col.field] = val
-      //   }
-      // })
-
-      return item
-    })
-
-    if (err) {
-      notification.warning({
-        top: 92,
-        message: err,
-        duration: 5
-      })
-    } else {
-      this.submit(data)
-    }
-  }
-
-  submit = (data) => {
-    const { BID } = this.props
-
-    let param = {
-      // excel_in: result.lines,
-      BID: BID || ''
-    }
-
-    this.setState({
-      loading: true
-    })
-
-    param.func = 'submit.innerFunc'
-
-    Api.genericInterface(param).then((res) => {
-      if (res.status) {
-        this.execSuccess(res)
-      } else {
-        this.execError(res)
-      }
-    }, () => {
-      this.execError({})
-    })
-  }
-
-  execSuccess = (res) => {
-    const { submit } = this.props
-
-    if (res && res.ErrCode === 'S') { // 鎵ц鎴愬姛
-      notification.success({
-        top: 92,
-        message: res.ErrMesg || this.state.dict['main.action.confirm.success'],
-        duration: submit.stime ? submit.stime : 2
-      })
-    } else if (res && res.ErrCode === 'Y') { // 鎵ц鎴愬姛
-      Modal.success({
-        title: res.ErrMesg || this.state.dict['main.action.confirm.success']
-      })
-    } else if (res && res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
-
-    }
-
-    this.setState({
-      loading: false
-    })
-
-    if (submit.closetab === 'true') {
-      MKEmitter.emit('popclose')
-    }
-    if (submit.execSuccess !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit)
-    }
-  }
-
-  execError = (res) => {
-    const { submit } = this.props
-
-    if (res.ErrCode === 'E') {
-      Modal.error({
-        title: res.message || res.ErrMesg,
-      })
-    } else if (res.ErrCode === 'N') {
-      notification.error({
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ntime ? submit.ntime : 10
-      })
-    } else if (res.ErrCode === 'F') {
-      notification.error({
-        className: 'notification-custom-error',
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ftime ? submit.ftime : 10
-      })
-    } else if (res.ErrCode === 'NM') {
-      message.error(res.message || res.ErrMesg)
-    }
-    
-    this.setState({
-      loading: false
-    })
-
-    if (submit.execError !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execError, submit)
-    }
+    this.props.onChange(_data)
   }
 
   render() {
@@ -801,7 +1250,7 @@
           columns={columns}
           dataSource={edData}
           bordered={true}
-          // loading={this.props.loading}
+          loading={this.props.loading}
           onRow={(record, index) => {
             return {
               data: record
diff --git a/src/tabviews/custom/components/module/voucher/voucherTable/index.scss b/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
index 4d4702a..fa2baa2 100644
--- a/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
+++ b/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
@@ -90,10 +90,30 @@
         vertical-align: top;
 
         .content-wrap {
-          padding: 5px;
+          padding: 0px 5px;
           height: 100%;
           font-size: 13px;
           font-weight: bold;
+
+          .count-wrap {
+            text-align: right;
+            height: 20px;
+          }
+          .currency-select {
+            height: 20px;
+            vertical-align: top;
+            .ant-select-selection--single {
+              height: 20px;
+            }
+            .ant-select-selection__rendered {
+              line-height: 20px;
+              margin-left: 8px;
+              margin-right: 22px;
+            }
+            .ant-select-arrow {
+              right: 6px;
+            }
+          }
         }
         .money-uint {
           height: 100%;
@@ -129,7 +149,7 @@
     border-radius: 0;
     resize: none;
   }
-  .ant-input-number {
+  .ant-input-number:not(.inner-input) {
     height: 60px;
     border-radius: 0;
     
@@ -141,7 +161,22 @@
       height: 60px;
     }
   }
-  .ant-select {
+  .ant-input-number.inner-input {
+    display: inline-block;
+    width: 50px;
+    border-radius: 0;
+    height: 20px;
+
+    .ant-input-number-handler-wrap {
+      display: none;
+    }
+    .ant-input-number-input {
+      border-radius: 0;
+      height: 18px;
+      padding: 0 3px;
+    }
+  }
+  .ant-select:not(.currency-select) {
     padding: 0px;
     position: absolute;
     top: 0px;
@@ -175,12 +210,12 @@
       bottom: 0px;
       border: 1px solid #1890ff;
     }
-    .anticon {
-      color: #ff4d4f;
-      position: absolute;
-      right: 3px;
-      top: calc(50% - 8px);
-    }
+    // .anticon {
+    //   color: #ff4d4f;
+    //   position: absolute;
+    //   right: 3px;
+    //   top: calc(50% - 8px);
+    // }
   }
   td.pointer {
     position: relative;
@@ -196,8 +231,93 @@
       right: 0;
     }
   }
-}
 
+  .anticon-plus {
+    position: absolute;
+    left: 0px;
+    height: 60px;
+    top: 0px;
+    line-height: 60px;
+    width: 25px;
+    color: #26C281;
+    cursor: pointer;
+    display: none;
+  }
+  .anticon-close {
+    position: absolute;
+    right: 0px;
+    height: 60px;
+    top: 0px;
+    line-height: 60px;
+    width: 25px;
+    color: #ff4d4f;
+    cursor: pointer;
+    display: none;
+  }
+  tr:hover {
+    .anticon-plus {
+      left: -25px;
+      display: inline-block;
+    }
+    .anticon-close {
+      right: -25px;
+      display: inline-block;
+    }
+  }
+  .pop-anchor {
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+  }
+}
+.subject-pop-wrap {
+  padding-top: 0px;
+  .ant-popover-arrow {
+    display: none;
+  }
+  .ant-popover-content {
+    position: relative;
+    z-index: 1;
+  }
+
+  .ant-form-item {
+    display: flex;
+    margin-bottom: 15px;
+    width: 200px;
+
+    .ant-form-item-label {
+      width: 60px;
+    }
+    .ant-form-item-control-wrapper {
+      width: calc(100% - 60px);
+      .ant-select {
+        width: 100%;
+      }
+    }
+  }
+  .ant-popover-inner-content {
+    padding-right: 30px;
+  }
+  .footer {
+    text-align: right;
+    .ant-btn {
+      border: none;
+      box-shadow: none;
+      margin-right: 15px;
+    }
+    .ant-btn:last-child {
+      color: var(--mk-sys-color);
+    }
+  }
+}
+.subject-pop-wrap::before {
+  content: '';
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
 .edit-table-dropdown {
   .ant-select-dropdown-menu-item {
     white-space: unset;
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 39687e8..7c1a501 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -241,6 +241,15 @@
         config,
         mainSearch
       }, () => {
+        if (config.normalcss) {
+          let node = document.getElementById(config.uuid)
+          node && node.remove()
+    
+          let ele = document.createElement('style')
+          ele.id = config.uuid
+          ele.innerHTML = config.normalcss
+          document.getElementsByTagName('head')[0].appendChild(ele)
+        }
         if (params.length === 0) {
           setTimeout(() => { // 寤舵椂鍔犺浇鐘舵��
             this.setState({
@@ -1314,7 +1323,7 @@
     return (
       <div className={'custom-page-wrap ' + (loadingview || loading ? 'loading' : '')} id={this.state.ContainerId} style={config ? config.style : null}>
         {(loadingview || (loading && !config.$cache)) ? <Spin className="view-spin" size="large" /> : null}
-        <Row className="component-wrap">{this.getComponents()}</Row>
+        <Row id={config ? 'menu' + config.uuid : ''} className="component-wrap">{this.getComponents()}</Row>
         {config && config.interfaces.length > 0 ? <MkInterfaces BID={BID} interfaces={config.interfaces}/> : null}
         {config && window.GLOB.breakpoint ? <DebugTable /> : null}
         {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <TableNodes config={config} /> : null}
diff --git a/src/tabviews/custom/index.scss b/src/tabviews/custom/index.scss
index b01f497..7d331eb 100644
--- a/src/tabviews/custom/index.scss
+++ b/src/tabviews/custom/index.scss
@@ -7,10 +7,7 @@
   padding-left: 16px;
   padding-right: 16px;
   background-size: 100%;
-  
-  .component-wrap >.ant-col {
-    min-height: 0;
-  }
+
   .box404 {
     padding-top: 30px;
   }
diff --git a/src/tabviews/custom/popview/index.scss b/src/tabviews/custom/popview/index.scss
index 6938042..b69e65d 100644
--- a/src/tabviews/custom/popview/index.scss
+++ b/src/tabviews/custom/popview/index.scss
@@ -7,10 +7,7 @@
   padding-left: 16px;
   padding-right: 16px;
   background-size: 100%;
-  
-  .component-wrap >.ant-col {
-    min-height: 0;
-  }
+
   .box404 {
     padding-top: 30px;
   }
diff --git a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
index 802daaf..b8e2081 100644
--- a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -34,7 +34,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -72,7 +72,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
diff --git a/src/tabviews/zshare/actionList/excelInbutton/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
index d0cba8c..d865dab 100644
--- a/src/tabviews/zshare/actionList/excelInbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -39,7 +39,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -77,7 +77,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
diff --git a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
index 3d93b36..41f9ddb 100644
--- a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -18,6 +18,7 @@
   static propTpyes = {
     BID: PropTypes.string,            // 涓昏〃ID
     BData: PropTypes.any,             // 涓昏〃鏁版嵁
+    selectedData: PropTypes.any,      // 瀛愯〃涓�夋嫨鏁版嵁
     btn: PropTypes.object,            // 鎸夐挳
     setting: PropTypes.any,           // 椤甸潰閫氱敤璁剧疆
     updateStatus: PropTypes.func,     // 鎸夐挳鐘舵�佹洿鏂�
@@ -776,6 +777,7 @@
    * @description 鑾峰彇鐢ㄦ埛鑷畾涔夊瓨鍌ㄨ繃绋嬩紶鍙�
    */
   getExcelCustomParam = (orderBy, search, pagination = false, pageIndex = 1, pageSize = 100) => {
+    const { btn, selectedData } = this.props
     let _search = Utils.formatCustomMainSearch(search)
 
     let param = {
@@ -786,6 +788,13 @@
     // 鏁版嵁绠$悊鏉冮檺
     if (sessionStorage.getItem('dataM') === 'true') {
       param.dataM = 'Y'
+    }
+
+    if (btn.Ot === 'requiredOnce' && selectedData && selectedData.length > 0) {
+      let primaryId = selectedData.map(d => d.$$uuid || '').filter(Boolean).join(',')
+      if (primaryId) {
+        param.ID = primaryId
+      }
     }
 
     if (this.props.BID) {
@@ -804,17 +813,19 @@
    * @description 鑾峰彇榛樿瀛樺偍杩囩▼璇锋眰鍙傛暟
    */
   getExcelDefaultParam = (arr_field, orderBy, search, pagination = false, pageIndex = 1, pageSize = 100) => {
-    const { setting, btn } = this.props
+    const { setting, btn, selectedData, BID } = this.props
 
     let defaultSql = setting.execute || setting.default || 'true'
     let customScript = setting.customScript || ''
     let _dataresource = setting.dataresource || ''
     let queryType = setting.queryType
+    let primaryKey = setting.primaryKey || 'ID'
 
     if (btn.verify.dataType === 'custom') {
       defaultSql = btn.verify.defaultSql || 'true'
       _dataresource = btn.verify.dataresource || ''
       queryType = btn.verify.queryType
+      primaryKey = btn.verify.primaryKey || 'ID'
 
       if (/\s/.test(_dataresource)) {
         _dataresource = '(' + _dataresource + ') tb'
@@ -857,8 +868,8 @@
       param.dataM = 'Y'
     }
 
-    if (this.props.BID) {
-      param.BID = this.props.BID
+    if (BID) {
+      param.BID = BID
     }
 
     let userName = sessionStorage.getItem('User_Name') || ''
@@ -914,6 +925,16 @@
       _search = ''
     }
 
+    let primaryId = ''
+    if (btn.Ot === 'requiredOnce' && selectedData && selectedData.length > 0) {
+      primaryId = selectedData.map(d => d.$$uuid || '').filter(Boolean).join(',')
+      if (_search && primaryId) {
+        _search += ` and ${primaryKey} in (select ID from  dbo.SplitComma('${primaryId}'))`
+      } else if (primaryId) {
+        _search = `where ${primaryKey} in (select ID from  dbo.SplitComma('${primaryId}'))`
+      }
+    }
+
     let LText = ''
 
     if (defaultSql !== 'false' && !pagination) {
@@ -949,6 +970,21 @@
       `
     }
 
+    LText = LText.replace(/@ID@/ig, `'${primaryId || ''}'`)
+    param.custom_script = param.custom_script.replace(/@ID@/ig, `'${primaryId || ''}'`)
+    LText = LText.replace(/@BID@/ig, `'${BID}'`)
+    param.custom_script = param.custom_script.replace(/@BID@/ig, `'${BID}'`)
+    LText = LText.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
+    param.custom_script = param.custom_script.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
+    LText = LText.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
+    param.custom_script = param.custom_script.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
+    LText = LText.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
+    param.custom_script = param.custom_script.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
+    LText = LText.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    param.custom_script = param.custom_script.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    LText = LText.replace(/@typename@/ig, `'admin'`)
+    param.custom_script = param.custom_script.replace(/@typename@/ig, `'admin'`)
+
     // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
     if (window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
       param.custom_script && console.info(`${LText ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${param.custom_script}`)
diff --git a/src/tabviews/zshare/actionList/index.jsx b/src/tabviews/zshare/actionList/index.jsx
index 94ab9c5..10871f6 100644
--- a/src/tabviews/zshare/actionList/index.jsx
+++ b/src/tabviews/zshare/actionList/index.jsx
@@ -94,6 +94,7 @@
             btn={item}
             BData={BData}
             setting={setting}
+            selectedData={selectedData}
           />
         )
       } else if (item.OpenType === 'popview') {
diff --git a/src/tabviews/zshare/actionList/newpagebutton/index.jsx b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
index 2ca6b55..57bfcaa 100644
--- a/src/tabviews/zshare/actionList/newpagebutton/index.jsx
+++ b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -30,7 +30,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -68,7 +68,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
diff --git a/src/tabviews/zshare/actionList/normalbutton/index.jsx b/src/tabviews/zshare/actionList/normalbutton/index.jsx
index 0654d5f..3a5c539 100644
--- a/src/tabviews/zshare/actionList/normalbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -52,7 +52,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -107,7 +107,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
@@ -1918,21 +1918,38 @@
    * 4銆佹ā鎬佹鎵ц鎴愬姛鍚庢槸鍚﹀叧闂�
    * 5銆侀�氱煡涓诲垪琛ㄥ埛鏂�
    */
-  execSuccess = (res) => {
+  execSuccess = (res = {}) => {
     const { btn } = this.props
     const { btnconfig, autoMatic } = this.state
 
-    if ((res && (res.ErrCode === 'S' || !res.ErrCode)) || autoMatic) { // 鎵ц鎴愬姛
+    if (res.message && /^@speak@/.test(res.message)) {
+      res.message = res.message.replace('@speak@', '')
+      let val = res.message.match(/<<.*>>/)
+      res.message = res.message.replace(/\s*<<.*>>\s*/g, '')
+      val = val ? val[0].replace(/<<|>>/g, '') : ''
+
+      if (/^http/.test(val)) {
+        let audio = document.createElement('audio')
+        audio.src = val
+        audio.play()
+      }
+
+      if (!res.message) {
+        res.ErrCode = '-1'
+      }
+    }
+
+    if ((res.ErrCode === 'S' || !res.ErrCode) || autoMatic) { // 鎵ц鎴愬姛
       notification.success({
         top: 92,
-        message: res.ErrMesg || this.state.dict['main.action.confirm.success'],
+        message: res.message || '鎵ц鎴愬姛锛�',
         duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
       })
-    } else if (res && res.ErrCode === 'Y') { // 鎵ц鎴愬姛
+    } else if (res.ErrCode === 'Y') { // 鎵ц鎴愬姛
       Modal.success({
-        title: res.ErrMesg || this.state.dict['main.action.confirm.success']
+        title: res.message || '鎵ц鎴愬姛锛�'
       })
-    } else if (res && res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
+    } else if (res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
 
     }
 
@@ -2295,25 +2312,42 @@
     const { btn } = this.props
     const { btnconfig, autoMatic } = this.state
 
+    if (res.message && /^@speak@/.test(res.message)) {
+      res.message = res.message.replace('@speak@', '')
+      let val = res.message.match(/<<.*>>/)
+      res.message = res.message.replace(/\s*<<.*>>\s*/g, '')
+      val = val ? val[0].replace(/<<|>>/g, '') : ''
+
+      if (/^http/.test(val)) {
+        let audio = document.createElement('audio')
+        audio.src = val
+        audio.play()
+      }
+
+      if (!res.message) {
+        res.ErrCode = '-1'
+      }
+    }
+
     if (res.ErrCode === 'E' && !autoMatic) {
       Modal.error({
-        title: res.message || res.ErrMesg,
+        title: res.message || '鎵ц澶辫触锛�',
       })
     } else if (res.ErrCode === 'N' || autoMatic) {
       notification.error({
         top: 92,
-        message: res.message || res.ErrMesg,
+        message: res.message || '鎵ц澶辫触锛�',
         duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
       })
     } else if (res.ErrCode === 'F') {
       notification.error({
         className: 'notification-custom-error',
         top: 92,
-        message: res.message || res.ErrMesg,
+        message: res.message || '鎵ц澶辫触锛�',
         duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
       })
     } else if (res.ErrCode === 'NM') {
-      message.error(res.message || res.ErrMesg)
+      message.error(res.message || '鎵ц澶辫触锛�')
     }
 
     if (autoMatic) {
diff --git a/src/tabviews/zshare/actionList/popupbutton/index.jsx b/src/tabviews/zshare/actionList/popupbutton/index.jsx
index 4449ae5..bf6178c 100644
--- a/src/tabviews/zshare/actionList/popupbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -39,7 +39,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -80,7 +80,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
diff --git a/src/tabviews/zshare/actionList/printbutton/index.jsx b/src/tabviews/zshare/actionList/printbutton/index.jsx
index 1f9b31a..dff3102 100644
--- a/src/tabviews/zshare/actionList/printbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -48,7 +48,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -92,7 +92,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
diff --git a/src/tabviews/zshare/actionList/tabbutton/index.jsx b/src/tabviews/zshare/actionList/tabbutton/index.jsx
index c4b2567..ffe92c1 100644
--- a/src/tabviews/zshare/actionList/tabbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -30,7 +30,7 @@
     const { btn, selectedData, BData } = this.props
     let disabled = false
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+    if (btn.control !== 'parent' && btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
       selectedData.forEach(item => {
         let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
         if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
@@ -68,7 +68,7 @@
     const { btn, selectedData, BData } = this.props
 
     let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+    if (btn.control !== 'parent' && btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
       if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
         nextProps.selectedData.forEach(item => {
           let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
diff --git a/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx b/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
index 58acdce..154b7bd 100644
--- a/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
@@ -23,8 +23,11 @@
     let config = fromJS(this.props.config).toJS()
 
     let selectKeys = config.initval
+    let initlength = 0
     if (config.multiple === 'true') {
       selectKeys = config.initval ? config.initval.split(',') : []
+      initlength = selectKeys.length
+      selectKeys = this.filterVals(config.options, selectKeys)
     }
 
     if (!config.selectStyle && config.backgroundColor) {
@@ -44,6 +47,10 @@
       config: config,
       options: fromJS(config.options).toJS(),
       selectKeys: selectKeys
+    }, () => {
+      if (config.multiple === 'true' && selectKeys.length < initlength) {
+        this.props.onChange(selectKeys.join(','))
+      }
     })
   }
 
@@ -60,9 +67,20 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { config } = this.state
+    const { config, selectKeys } = this.state
 
     if (!is(fromJS(config.oriOptions), fromJS(nextProps.config.oriOptions))) {
+      if (config.multiple === 'true') {
+        let keys = this.filterVals(nextProps.config.options, fromJS(selectKeys).toJS())
+        if (keys.length < selectKeys.length) {
+          this.setState({
+            selectKeys: keys
+          }, () => {
+            this.props.onChange(keys.join(','))
+          })
+        }
+      }
+
       this.setState({
         config: {...config, oriOptions: nextProps.config.oriOptions},
         options: fromJS(nextProps.config.options).toJS()
@@ -77,6 +95,16 @@
     MKEmitter.removeListener('mkFP', this.mkFormHandle)
   }
 
+  filterVals = (options, vals) => {
+    if (options.length === 0 || vals.length === 0) return vals
+
+    let ops = options.map(item => item.$value)
+
+    vals = vals.filter(val => ops.includes(val))
+
+    return vals
+  }
+
   mkFormHandle = (uuid, parentId, level) => {
     if (uuid !== this.state.config.uuid) return
 
diff --git a/src/tabviews/zshare/tablenodes/index.jsx b/src/tabviews/zshare/tablenodes/index.jsx
index df97bc4..f46b98d 100644
--- a/src/tabviews/zshare/tablenodes/index.jsx
+++ b/src/tabviews/zshare/tablenodes/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Modal, Button, notification, Spin, Input, Typography } from 'antd'
+import { Modal, Button, notification, Spin, Input, Typography, message } from 'antd'
 
 import Api from '@/api'
 import G6 from "@antv/g6"
@@ -166,6 +166,7 @@
               id: 'par' + i,
               direction: 'left',
               color: '#5AD8A6',
+              node: 'table',
               children: []
             }
 
@@ -345,6 +346,44 @@
         ev.preventDefault();
       },
     });
+
+    G6.registerBehavior('dice-mindmap', {
+      getEvents() {
+        return {
+          'node:dblclick': 'editNode',
+        };
+      },
+      editNode(evt) {
+        const item = evt.item;
+        const model = item.get('model');
+
+        // 閫変腑鑺傜偣
+        this.graph.getNodes().forEach(node => {
+          let _model = node.get('model')
+          if (_model.fontcolor === '#1890ff') {
+            _model.fontcolor = ''
+            this.graph.updateItem(node, _model, false)
+          }
+        })
+
+        if (model.direction === 'left') {
+          if (model.node === 'table') {
+            model.fontcolor = '#1890ff'
+            this.graph.updateItem(item, model, false)
+
+            let oInput = document.createElement('input')
+            oInput.value = model.label
+            document.body.appendChild(oInput)
+            oInput.select()
+            document.execCommand('Copy')
+            document.body.removeChild(oInput)
+            
+            message.success('琛ㄥ悕澶嶅埗鎴愬姛銆�')
+          }
+          return
+        }
+      }
+    });
     
     const dataTransform = (data) => {
       const changeData = (d, level = 0, color) => {
@@ -420,7 +459,8 @@
             },
           },
           'drag-canvas',
-          'zoom-canvas'
+          'zoom-canvas',
+          'dice-mindmap'
         ],
       },
     });
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
index 3c505eb..f599ffb 100644
--- a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -18,7 +18,7 @@
   prompt: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'openmenu', 'output', 'tipTitle', 'hidden'],
   exec: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'openmenu', 'output', 'hidden'],
   excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'icon', 'class', 'sheet', 'execSuccess', 'execError', 'hidden'],
-  excelOut: ['label', 'OpenType', 'intertype', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search', 'hidden'],
+  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search', 'hidden'],
   popview: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose', 'display', 'ratio', 'clickouter', 'hidden'],
   tab: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'linkmenu', 'hidden'],
   innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position', 'hidden'],
@@ -238,6 +238,7 @@
       }
     } else if (openType === 'excelOut') {
       reOptions.intertype = this.state.interTypeOptions.filter(op => op.value !== 'custom')
+      reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredOnce'].includes(op.value))
 
       if (this.record.intertype === 'outer') {
         shows.push('innerFunc', 'sysInterface', 'interface', 'outerFunc')
@@ -255,6 +256,9 @@
       } else if (this.record.intertype === 'inner') {
         shows.push('innerFunc')
         reRequired.innerFunc = true
+      }
+      if (this.record.Ot !== 'notRequired' && this.record.Ot !== 'requiredOnce') {
+        this.record.Ot = 'notRequired'
       }
     } else if (openType === 'popview') {
       reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
@@ -323,7 +327,7 @@
       reOptions.Ot = requireOptions.filter(op => op.value === 'requiredSgl')
     }
     
-    if (Ot !== 'notRequired') {
+    if (Ot !== 'notRequired' && openType !== 'excelOut') {
       reOptions.control = [
         { value: '', text: '鏃�' },
         { value: 'disabled', text: '绂佺敤' },
@@ -393,6 +397,7 @@
         _fieldval.label = '瀵煎嚭Excel'
         _fieldval.class = 'dgreen'
         _fieldval.execSuccess = 'never'
+        _fieldval.Ot = 'notRequired'
         this.record.Ot = 'notRequired'
         this.record.label = '瀵煎嚭Excel'
         this.record.class = 'dgreen'
@@ -689,7 +694,7 @@
           values.position = values.position || 'toolbar'
 
           if (values.OpenType === 'excelOut') {
-            values.Ot = 'notRequired'
+            values.Ot = values.Ot || 'notRequired'
           } else if (values.OpenType === 'popview' && !values.linkTab) { // 娌℃湁鍏宠仈鏍囩锛堟柊寤烘椂锛夛紝鍒涘缓鏂版爣绛綢d
             values.linkTab = Utils.getuuid()
           } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) {
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
index 5973e2d..6224ab7 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -249,7 +249,6 @@
       col.required = col.required || 'true'
       col.type = col.type || 'Nvarchar(50)'
       col.import = col.import || 'true'
-      col.required = col.required || 'true'
 
       if (col.type === 'text' || col.type === 'image') {
         col.type = 'Nvarchar(50)'
@@ -365,7 +364,7 @@
 
     let _columns = JSON.parse(JSON.stringify(verify.columns))
 
-    let _cols = _columns.map(col => col.Column )
+    let _cols = _columns.map(col => col.Column)
 
     columns.forEach(col => {
       if (col.field && !_cols.includes(col.field)) {
@@ -455,6 +454,13 @@
     const { verify } = this.state
 
     columns = columns.map(col => {
+      col.type = col.type || 'Nvarchar(50)'
+      if (col.type === 'text' || col.type === 'image') {
+        col.type = 'Nvarchar(50)'
+      } else if (col.type === 'number') {
+        col.type = 'Decimal(18,2)'
+      }
+
       if (/^Nvarchar/ig.test(col.type)) {
         col.limit = col.type.match(/\d+/) ? col.type.match(/\d+/)[0] : '20000'
       } else if (/^Decimal/ig.test(col.type)) {
@@ -466,6 +472,9 @@
         col.limit = ''
       }
 
+      col.required = col.required || 'true'
+      col.import = col.import || 'true'
+
       return col
     })
 
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
index 557bf84..c4df36d 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
@@ -199,6 +199,13 @@
               </Form.Item>
             </Col> : null}
             {dataType === 'custom' && defaultSql === 'true' ? <Col className="short-label" span={8}>
+              <Form.Item label="涓婚敭">
+                {getFieldDecorator('primaryKey', {
+                  initialValue: setting.primaryKey || 'ID',
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {dataType === 'custom' && defaultSql === 'true' ? <Col className="short-label" span={8}>
               <Form.Item label="鎺掑簭鏂瑰紡">
                 {getFieldDecorator('order', {
                   initialValue: setting.order || '',
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
index 8f566d2..ee401ec 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -811,22 +811,37 @@
   changeColumns = (columns) => {
     const { verify } = this.state
 
-    if (columns[0] && !['image', 'text', 'number'].includes(columns[0].type)) {
-      columns = columns.map(col => {
-        let _cell = {
-          uuid: Utils.getuuid(),
-          Column: col.Column,
-          Text: col.Text,
-          Width: 20,
-          abs: 'false',
-          output: col.output || 'true',
-          required: col.required || 'false',
-          type: 'text',
-        }
+    columns = columns.map(col => {
+      col.type = col.type || 'text'
+      col.output = col.output || 'true'
+      col.required = col.required || 'false'
 
-        return _cell
-      })
-    }
+      if (!['text', 'image', 'number'].includes(col.type)) {
+        if (/^Decimal/ig.test(col.type)) {
+          col.type = 'number'
+        } else {
+          col.type = 'text'
+        }
+      }
+
+      return col
+    })
+    // if (columns[0] && !['image', 'text', 'number'].includes(columns[0].type)) {
+    //   columns = columns.map(col => {
+    //     let _cell = {
+    //       uuid: Utils.getuuid(),
+    //       Column: col.Column,
+    //       Text: col.Text,
+    //       Width: 20,
+    //       abs: 'false',
+    //       output: col.output || 'true',
+    //       required: col.required || 'false',
+    //       type: 'text',
+    //     }
+
+    //     return _cell
+    //   })
+    // }
 
     this.setState({verify: {...verify, columns}})
   }
diff --git a/src/templates/sharecomponent/fieldscomponent/index.jsx b/src/templates/sharecomponent/fieldscomponent/index.jsx
index 41a9a0a..38fbab2 100644
--- a/src/templates/sharecomponent/fieldscomponent/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -169,10 +169,12 @@
 
       this.props.updatefield(items)
     } else if (type === 'form') {
-      let lastItem = config.fields[config.fields.length - 1]
+      let firstItem = config.fields[0]
       let span = this.state.appType === 'mob' ? 24 : 12
-      if (lastItem && lastItem.span) {
-        span = lastItem.span
+      let labelwidth = 33.3
+      if (firstItem && firstItem.span) {
+        span = firstItem.span
+        labelwidth = firstItem.labelwidth || 33.3
       }
       selectCards.forEach(item => { // 寰幆娣诲姞鏂板瀛楁
         let newcard = {
@@ -183,7 +185,7 @@
           type: item.type,
           resourceType: '0',
           span: span,
-          labelwidth: 33.3,
+          labelwidth: labelwidth,
           options: [],
           dataSource: '',
           decimal: item.decimal,
@@ -195,17 +197,19 @@
         if (item.type === 'text' && item.length >= 256) {
           newcard.type = 'textarea'
           newcard.fieldlength = item.length
-          if (lastItem && lastItem.type === newcard.type) {
-            newcard.span = lastItem.span
-            newcard.labelwidth = lastItem.labelwidth
-          } else if (lastItem) {
-            newcard.span = 24
-            if (lastItem.span === 12) {
-              newcard.labelwidth = 16.2
-            } else if (lastItem.span === 8) {
-              newcard.labelwidth = 10.5
-            } else if (lastItem.span === 8) {
-              newcard.labelwidth = 7.7
+          if (firstItem) {
+            if (firstItem.type === newcard.type) {
+              newcard.span = firstItem.span
+              newcard.labelwidth = firstItem.labelwidth
+            } else {
+              newcard.span = 24
+              if (firstItem.span === 12) {
+                newcard.labelwidth = 16.2
+              } else if (firstItem.span === 8) {
+                newcard.labelwidth = 10.5
+              } else if (firstItem.span === 6) {
+                newcard.labelwidth = 7.7
+              }
             }
           } else {
             newcard.span = 24
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index 6626b9b..83db912 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -1268,7 +1268,7 @@
       key: 'execSuccess',
       label: '鎴愬姛鍚�',
       initVal: card.execSuccess || 'grid',
-      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺��',
+      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1287,7 +1287,7 @@
       key: 'execError',
       label: '澶辫触鍚�',
       initVal: card.execError || 'never',
-      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺��',
+      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
diff --git a/src/templates/zshare/modalform/modaleditable/index.jsx b/src/templates/zshare/modalform/modaleditable/index.jsx
index 3e076af..9edfdf9 100644
--- a/src/templates/zshare/modalform/modaleditable/index.jsx
+++ b/src/templates/zshare/modalform/modaleditable/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Table, Input, Popconfirm, Form, Radio, message } from 'antd'
+import { Table, Input, Popconfirm, Form, message } from 'antd'
 import { ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined, PlusOutlined, SwapOutlined } from '@ant-design/icons'
 
 import { formRule } from '@/utils/option.js'
@@ -140,27 +140,9 @@
     })
   }
 
-  getColumnSearchProps = column => ({
-    filterDropdown: () => (
-      <div style={{ padding: 8 }}>
-        <Radio.Group onChange={(e) => this.changeDatatype(column, e)} value={column.datatype}>
-          <Radio style={{display: 'block', height: '30px', lineHeight: '30px'}} value="string">
-            瀛楃涓�
-          </Radio>
-          <Radio style={{display: 'block', height: '30px', lineHeight: '30px'}} value="number">
-            鏁板瓧
-          </Radio>
-        </Radio.Group>
-      </div>
-    ),
-    filterIcon: () => (
-      <SwapOutlined style={{ color: column.datatype === 'number' ? '#1890ff' : ''}} />
-    )
-  })
-
-  changeDatatype = (column, e) => {
+  changeDatatype = (column) => {
     const { columns, dataSource } = this.state
-    let value = e.target.value
+    let value = column.datatype !== 'number' ? 'number' : 'string'
     let _data = dataSource.map(item => {
       let val = item[column.dataIndex]
       if (value === 'number') {
@@ -185,7 +167,16 @@
         }
 
         if (col.dataIndex !== 'operation') {
-          col = {...col, ...this.getColumnSearchProps(col)}
+          col.title = <div>
+            Value
+            <Popconfirm
+              title={`纭畾鍒囨崲涓�${col.datatype === 'number' ? '鏂囨湰' : '鏁板��'}鍚楋紵`}
+              overlayClassName="popover-confirm"
+              onConfirm={() => this.changeDatatype(col)
+            }>
+              <SwapOutlined style={{ color: col.datatype === 'number' ? '#1890ff' : ''}} />
+            </Popconfirm>
+          </div>
         }
 
         return col
@@ -376,7 +367,16 @@
     return {
       columns: columns.map(col => {
         if (col.dataIndex !== 'operation') {
-          col = {...col, ...this.getColumnSearchProps(col)}
+          col.title = <div>
+            Value
+            <Popconfirm
+              title={`纭畾鍒囨崲涓�${col.datatype === 'number' ? '鏂囨湰' : '鏁板��'}鍚楋紵`}
+              overlayClassName="popover-confirm"
+              onConfirm={() => this.changeDatatype(col)
+            }>
+              <SwapOutlined style={{ color: col.datatype === 'number' ? '#1890ff' : ''}} />
+            </Popconfirm>
+          </div>
         }
         return col
       }),
diff --git a/src/templates/zshare/modalform/modaleditable/index.scss b/src/templates/zshare/modalform/modaleditable/index.scss
index ab53b8e..c802fbe 100644
--- a/src/templates/zshare/modalform/modaleditable/index.scss
+++ b/src/templates/zshare/modalform/modaleditable/index.scss
@@ -17,6 +17,15 @@
   }
   .ant-table-thead > tr > th {
     padding: 10px 16px;
+    position: relative;
+
+    .anticon-swap {
+      position: absolute;
+      right: 16px;
+      font-size: 14px;
+      top: 12px;
+      color: #b8b8b8;
+    }
   }
   .ant-table-tbody > tr > td {
     padding: 5px 10px;
diff --git a/src/views/appmanage/index.jsx b/src/views/appmanage/index.jsx
index 3b7bf87..a54a3b7 100644
--- a/src/views/appmanage/index.jsx
+++ b/src/views/appmanage/index.jsx
@@ -469,6 +469,7 @@
               cell.sysBgColor = _param.sysBgColor || '#ffffff'
               cell.direction = _param.direction || 'vertical'
               cell.adapter = _param.adapter || ''
+              cell.topHeight = _param.topHeight || ''
               cell.share = _param.share || 'false' // 鍒嗕韩
               cell.share_des = _param.share_des || '' // 鍒嗕韩鎻忚堪
               cell.share_url = _param.share_url || '' // 鍒嗕韩鍥剧墖
@@ -652,7 +653,7 @@
     })
 
     // 瀛愬簲鐢↖D銆乼ypename銆佸簲鐢↖D銆丆loudUserID銆乤ppkey銆乴ogin_types(鏄惁闇�瑕佺櫥褰曪紝宸插純鐢�)銆乴ink_type(鏄惁浣跨敤鐭繛鎺ワ紝宸插純鐢�)銆乺ole_type(鏄惁浣跨敤瑙掕壊绠$悊)銆乴ang銆乧ss(鐨偆)銆乼itle(鏍囬)銆乫avicon(鍥炬爣)銆乽ser_binding(鐢ㄦ埛缁戝畾)銆乻ms_id(鐭俊妯℃澘ID)銆佽嚜瀹氫箟
-    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
+    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
     param.LText = param.LText.join(' union all ')
     param.LText = Utils.formatOptions(param.LText)
     
@@ -898,7 +899,7 @@
           return item
         })
 
-        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
+        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
         param.LText = param.LText.join(' union all ')
         param.LText = Utils.formatOptions(param.LText)
       }
@@ -991,7 +992,7 @@
         return item
       })
 
-      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
+      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
       param.LText = param.LText.join(' union all ')
       param.LText = Utils.formatOptions(param.LText)
 
diff --git a/src/views/appmanage/submutilform/index.jsx b/src/views/appmanage/submutilform/index.jsx
index c9b5b5b..20d6daf 100644
--- a/src/views/appmanage/submutilform/index.jsx
+++ b/src/views/appmanage/submutilform/index.jsx
@@ -309,6 +309,18 @@
               )}
             </Form.Item>
           </Col> : null}
+          {typename === 'pad' && adapters.includes('app') ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鍦ㄦ槑绉戜簯APP涓紝鐘舵�佹爮鐨勬渶澶ч珮搴︼紝绌哄�兼椂浣跨敤APP鑾峰彇鍒扮殑鐘舵�佹爮楂樺害銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鐘舵�佹爮楂樺害
+              </Tooltip>
+            }>
+              {getFieldDecorator('topHeight', {
+                initialValue: card ? card.topHeight || '' : ''
+              })(<InputNumber min={0} max={5000} precision={0} onPressEnter={this.handleSubmit}/>)}
+            </Form.Item>
+          </Col> : null}
           <Col span={12}>
             <Form.Item className="sys-bgcolor" label={
               <Tooltip placement="topLeft" title="瀛愬簲鐢ㄩ�氱敤鐨勮儗鏅壊锛屽瓙搴旂敤椤甸潰鍒涘缓鏃朵細榛樿娣诲姞姝よ儗鏅壊銆�">
diff --git a/src/views/billprint/index.jsx b/src/views/billprint/index.jsx
index 1b0e280..8b1b229 100644
--- a/src/views/billprint/index.jsx
+++ b/src/views/billprint/index.jsx
@@ -886,7 +886,7 @@
       <div className="bill-print-wrap" >
         {loadingview && <Spin size="large" />}
         {pages ? <div id="bill-print">
-          {pages.map((components, index) => (<div className={'print-page' + (auto ? ' auto' : '')} key={index} style={{...config.style, overflow: 'hidden', boxSizing: 'border-box'}}><Row>{this.getComponents(components)}</Row></div>))}
+          {pages.map((components, index) => (<div className={'print-page' + (auto ? ' auto' : '')} key={index} style={{...config.style, overflow: 'hidden', boxSizing: 'border-box'}}><Row className="component-wrap">{this.getComponents(components)}</Row></div>))}
         </div> : null}
         {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
         {config && window.GLOB.breakpoint ? <DebugTable /> : null}
diff --git a/src/views/design/index.jsx b/src/views/design/index.jsx
index 9c1ea4c..5cd309f 100644
--- a/src/views/design/index.jsx
+++ b/src/views/design/index.jsx
@@ -23,7 +23,7 @@
   
   render () {
     return (
-      <div className="mk-main-view">
+      <div className={'mk-main-view ' + (window.GLOB.systemType || '')}>
         <ConfigProvider locale={_locale}>
           <Sidemenu key="sidemenu"/>
           <Header key="header"/>
diff --git a/src/views/design/index.scss b/src/views/design/index.scss
index 2dd743a..1445283 100644
--- a/src/views/design/index.scss
+++ b/src/views/design/index.scss
@@ -3,6 +3,11 @@
     background: #ffffff!important;
   }
 }
+.mk-main-view.production {
+  .edit-check {
+    display: none;
+  }
+}
 .mk-popover-control-wrap {
   .anticon-plus {
     color: #26C281;
diff --git a/src/views/design/sidemenu/index.jsx b/src/views/design/sidemenu/index.jsx
index ffef40e..8729535 100644
--- a/src/views/design/sidemenu/index.jsx
+++ b/src/views/design/sidemenu/index.jsx
@@ -109,6 +109,8 @@
   }
 
   editmenu = (cell) => {
+    if (window.GLOB.systemType === 'production') return
+    
     if (cell.type === 'CustomPage') {
       let _param = {
         MenuType: 'custom',
diff --git a/src/views/design/sidemenu/thdmenuplus/index.jsx b/src/views/design/sidemenu/thdmenuplus/index.jsx
index cbacb44..c10da0d 100644
--- a/src/views/design/sidemenu/thdmenuplus/index.jsx
+++ b/src/views/design/sidemenu/thdmenuplus/index.jsx
@@ -123,6 +123,7 @@
     let sysMenu = {
       MenuID: Utils.getuuid(),
       MenuName: template.title,
+      MenuNo: template.MenuNo ? template.MenuNo + '_01' : '',
       Template: template.type,
       fstMenuId: mainMenu.MenuID,
       ParentId: supMenu.MenuID,
diff --git a/src/views/login/index.jsx b/src/views/login/index.jsx
index 8a0d939..68d2181 100644
--- a/src/views/login/index.jsx
+++ b/src/views/login/index.jsx
@@ -5,6 +5,7 @@
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js' 
+import MKEmitter from '@/utils/events.js'
 import options, { styles } from '@/store/options.js'
 import zhCN from '@/locales/zh-CN/login.js'
 import enUS from '@/locales/en-US/login.js'
@@ -13,7 +14,7 @@
 import './index.scss'
 
 const LoginForm = asyncLoadComponent(() => import('./loginform'))
-const Resetpwd = asyncLoadComponent(() => import('@/components/header/resetpwd'))
+const Resetpwd = asyncLoadComponent(() => import('@/components/resetPassword'))
 const LoginCloudForm = asyncComponent(() => import('./logincloudform'))
 const LoginCodeForm = asyncComponent(() => import('./logincodeform'))
 const iszhCN = sessionStorage.getItem('lang') !== 'en-US'
@@ -39,8 +40,6 @@
     loginWays: null,
     touristLogin: false,
     syncing: false,
-    visible: false,
-    resetLoading: false
   }
 
   changelang (item) {
@@ -150,8 +149,14 @@
         if (visible) {
           message.warning(tip)
           this.setState({
-            isDisabled: false,
-            visible: true
+            isDisabled: false
+          })
+          
+          MKEmitter.emit('resetpassword', () => {
+            const input = document.getElementById('password')
+            if (input) {
+              input.select()
+            }
           })
           return
         }
@@ -658,7 +663,11 @@
                 login_ways.push({
                   type: item.way_no,
                   smsId: item.sms_id
-                }) 
+                })
+
+                if (item.way_no === 'sms_vcode' && item.sms_id) {
+                  sessionStorage.setItem('mk_sms_id', item.sms_id)
+                }
               })
             } else {
               login_ways.push({
@@ -899,48 +908,6 @@
     }, () => {})
   }
 
-  resetPwdSubmit = () => {
-    this.formRef.handleConfirm().then(res => {
-      this.setState({
-        resetLoading: true
-      })
-
-      let _param = {
-        func: 's_PwdUpt',
-        LText: `select '${res.originpwd}','${res.password}'`
-      }
-      
-      _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
-      _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
-      _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
-  
-      Api.getSystemConfig(_param).then(result => {
-        this.setState({
-          visible: !result.status,
-          resetLoading: false
-        })
-
-        if (result.status) {
-          notification.success({
-            top: 92,
-            message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
-            duration: 2
-          })
-          const input = document.getElementById('password')
-          if (input) {
-            input.select()
-          }
-        } else {
-          notification.warning({
-            top: 92,
-            message: result.message,
-            duration: 5
-          })
-        }
-      })
-    }, () => {})
-  }
-
   /**
    * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
    */
@@ -1000,19 +967,7 @@
           <LoginCloudForm handleSubmit={() => this.syncSubmit()} wrappedComponentRef={(inst) => this.logincloudRef = inst}/>
         </Modal>
         {/* 淇敼瀵嗙爜 */}
-        <Modal
-          title="淇敼瀵嗙爜"
-          okText={this.state.dict['login.ok']}
-          cancelText={this.state.dict['login.cancel']}
-          visible={this.state.visible}
-          onOk={this.resetPwdSubmit}
-          maskClosable={false}
-          confirmLoading={this.state.resetLoading}
-          onCancel={() => this.setState({visible: false, resetLoading: false})}
-          destroyOnClose
-        >
-          <Resetpwd wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
-        </Modal>
+        <Resetpwd />
         {/* 浜屾楠岃瘉 */}
         <Modal
           title="浜屾楠岃瘉"
diff --git a/src/views/login/loginform.jsx b/src/views/login/loginform.jsx
index c3ccfd1..da71b58 100644
--- a/src/views/login/loginform.jsx
+++ b/src/views/login/loginform.jsx
@@ -452,7 +452,7 @@
               <Input
                 addonAfter={
                   <Button type="link" className="vercode" size="small" disabled={verdisabled} onClick={this.getvercode}>
-                    {delay ? this.props.dict['login.vercode.queryagain'].replace('@', delay) : this.props.dict['login.vercode.query']}
+                    {delay ? `${delay}s鍚庨噸鏂拌幏鍙朻 : '鑾峰彇楠岃瘉鐮�'}
                   </Button>
                 }
                 placeholder={this.props.dict['login.vercode']}
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 67ee9a7..93dd0b6 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -37,6 +37,7 @@
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
 const Versions = asyncComponent(() => import('@/menu/versions'))
 const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
@@ -1151,6 +1152,7 @@
                     {/* 琛ㄥ悕娣诲姞 */}
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                     {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>鑿滃崟ID</Paragraph> : null}
+                    {config ? <NormalCss config={config} updateConfig={this.updateConfig}/> : null}
                   </Panel>
                   {/* 缁勪欢娣诲姞 */}
                   <Panel header="缁勪欢" key="component">
diff --git a/src/views/menudesign/index.scss b/src/views/menudesign/index.scss
index 6368ca8..1d47004 100644
--- a/src/views/menudesign/index.scss
+++ b/src/views/menudesign/index.scss
@@ -46,6 +46,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -56,6 +57,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/menudesign/popview/index.scss b/src/views/menudesign/popview/index.scss
index 2d06a62..2ea36fa 100644
--- a/src/views/menudesign/popview/index.scss
+++ b/src/views/menudesign/popview/index.scss
@@ -21,6 +21,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -31,6 +32,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/mobdesign/index.jsx b/src/views/mobdesign/index.jsx
index 1091b21..587199b 100644
--- a/src/views/mobdesign/index.jsx
+++ b/src/views/mobdesign/index.jsx
@@ -34,6 +34,7 @@
 const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
 const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
 const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const Quotecomponent = asyncComponent(() => import('@/pc/quotecomponent'))
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
@@ -2026,6 +2027,7 @@
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                     {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>鑿滃崟ID</Paragraph> : null}
                     {config ? <Paragraph style={{padding: '10px 0px 0px 18px'}} copyable={{ text:  `${window.GLOB.baseurl}mob/index.html#/index/${sessionStorage.getItem('kei_no')}/${sessionStorage.getItem('typename')}/${sessionStorage.getItem('lang')}/${MenuId}/@BID@` }}>鑿滃崟閾炬帴</Paragraph> : null}
+                    {config ? <NormalCss config={config} updateConfig={this.updateConfig}/> : null}
                   </Panel>
                   {/* 缁勪欢娣诲姞 */}
                   <Panel header="缁勪欢" className="component" key="component">
diff --git a/src/views/mobdesign/index.scss b/src/views/mobdesign/index.scss
index 1e12390..5c787d6 100644
--- a/src/views/mobdesign/index.scss
+++ b/src/views/mobdesign/index.scss
@@ -30,6 +30,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -40,6 +41,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/pcdesign/index.jsx b/src/views/pcdesign/index.jsx
index 15ac6d8..36018b0 100644
--- a/src/views/pcdesign/index.jsx
+++ b/src/views/pcdesign/index.jsx
@@ -39,6 +39,7 @@
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
 const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
@@ -1707,6 +1708,7 @@
                     {/* 琛ㄥ悕娣诲姞 */}
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                     {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>鑿滃崟ID</Paragraph> : null}
+                    {config ? <NormalCss config={config} updateConfig={this.updateConfig}/> : null}
                   </Panel>
                   {/* 缁勪欢娣诲姞 */}
                   <Panel header="缁勪欢" key="component">
diff --git a/src/views/pcdesign/index.scss b/src/views/pcdesign/index.scss
index d5f059d..ef0c9a0 100644
--- a/src/views/pcdesign/index.scss
+++ b/src/views/pcdesign/index.scss
@@ -34,6 +34,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -44,6 +45,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/systemfunc/sidemenu/config.jsx b/src/views/systemfunc/sidemenu/config.jsx
index c49b74a..9adbd43 100644
--- a/src/views/systemfunc/sidemenu/config.jsx
+++ b/src/views/systemfunc/sidemenu/config.jsx
@@ -5,8 +5,8 @@
   PageParam: {Icon: 'folder'},
   children: [{
     src: '',
-    PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
-    type: 'CommonTable',
+    PageParam: {OpenType: 'newtab', Template: 'CustomPage'},
+    type: 'CustomPage',
     MenuID: '1581067625930haged11ieaivpavv77k',
     MenuNo: 'sDatasM',
     MenuName: '鏁版嵁瀛楀吀',
@@ -77,13 +77,13 @@
     MenuNo: 's_custom_scriptM',
     MenuName: '鑷畾涔夊嚱鏁�',
   }, {
-    src: '',
-    PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
-    type: 'CommonTable',
-    MenuID: '1590458676585agbbr63t6ihighg2i1g',
-    MenuNo: 'LdropdownmenuNewM',
-    MenuName: '閫氱敤涓嬫媺鑿滃崟',
-  }, {
+  //   src: '',
+  //   PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
+  //   type: 'CommonTable',
+  //   MenuID: '1590458676585agbbr63t6ihighg2i1g',
+  //   MenuNo: 'LdropdownmenuNewM',
+  //   MenuName: '閫氱敤涓嬫媺鑿滃崟',
+  // }, {
     src: '',
     PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
     type: 'CommonTable',
diff --git a/src/views/systemfunc/sidemenu/index.jsx b/src/views/systemfunc/sidemenu/index.jsx
index b1ea702..21bd103 100644
--- a/src/views/systemfunc/sidemenu/index.jsx
+++ b/src/views/systemfunc/sidemenu/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import { Menu } from 'antd'
+import { fromJS } from 'immutable'
 import { FolderOutlined } from '@ant-design/icons'
 
 import { SySMenuList } from './config'
@@ -39,10 +40,19 @@
       menulist = menulist.filter(menu => menu.children.length > 0)
     }
 
+    let tb =  sessionStorage.getItem('mk-table-node')
+
     this.setState({
       subMenulist: menulist,
       rootSubmenuKeys: menulist.map(item => item.MenuID),
       openKeys: [menulist[0].MenuID]
+    }, () => {
+      if (tb && menulist[0] && menulist[0].children[0] && menulist[0].children[0].MenuNo === 'sDatasM') {
+        setTimeout(() => {
+          MKEmitter.emit('modifyTabs', fromJS(menulist[0].children[0]).toJS())
+        }, 500)
+      }
+      sessionStorage.removeItem('mk-table-node')
     })
   }
 
diff --git a/src/views/tabledesign/popview/index.scss b/src/views/tabledesign/popview/index.scss
index 2d06a62..2ea36fa 100644
--- a/src/views/tabledesign/popview/index.scss
+++ b/src/views/tabledesign/popview/index.scss
@@ -21,6 +21,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -31,6 +32,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {

--
Gitblit v1.8.0