From 73a5124745890650d0fc91234bdbaa66d9bcbc6a Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期三, 09 六月 2021 17:52:01 +0800
Subject: [PATCH] 2021-06-09

---
 src/templates/sharecomponent/settingcomponent/index.jsx                 |   33 +
 src/views/design/index.jsx                                              |    5 
 src/menu/datasource/verifycard/utils.jsx                                |   11 
 src/pc/modulesource/option.jsx                                          |    2 
 src/assets/mobimg/ratioboard.png                                        |    0 
 src/menu/components/chart/antv-dashboard/chartcompile/index.jsx         |   32 -
 src/tabviews/custom/components/chart/antv-dashboard/index.jsx           |  186 +++++++++-
 src/components/header/index.jsx                                         |  105 +++++
 src/templates/zshare/verifycard/callbackcustomscript/index.jsx          |    7 
 src/templates/zshare/verifycard/customscript/index.jsx                  |    7 
 src/menu/datasource/index.jsx                                           |   14 
 src/menu/components/chart/antv-bar/index.scss                           |    9 
 src/menu/components/chart/antv-bar/index.jsx                            |   26 +
 src/menu/components/chart/antv-scatter/index.jsx                        |   27 
 src/templates/zshare/verifycard/customform/index.jsx                    |    7 
 src/api/index.js                                                        |   28 +
 src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx   |   19 
 src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx    |   88 ++++
 src/templates/sharecomponent/settingcomponent/settingform/index.jsx     |   18 +
 src/menu/components/chart/antv-dashboard/index.scss                     |    5 
 src/templates/sharecomponent/settingcalcomponent/index.jsx              |   11 
 src/views/mobdesign/index.jsx                                           |    3 
 src/menu/components/chart/antv-dashboard/chartcompile/index.scss        |    5 
 src/templates/sharecomponent/settingcomponent/settingform/utils.jsx     |   15 
 src/views/menudesign/index.jsx                                          |    3 
 src/menu/datasource/verifycard/index.jsx                                |   15 
 src/menu/modulesource/option.jsx                                        |    2 
 src/utils/utils.js                                                      |   40 ++
 src/api/cacheutils.js                                                   |   31 +
 src/views/pcdesign/index.jsx                                            |    3 
 src/menu/components/chart/antv-scatter/index.scss                       |   13 
 src/templates/zshare/verifycard/index.jsx                               |   30 +
 src/menu/components/chart/antv-pie/index.scss                           |    5 
 src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx   |    8 
 src/menu/components/chart/antv-pie/index.jsx                            |   14 
 src/menu/components/search/main-search/index.jsx                        |   16 
 src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx |   12 
 src/menu/components/chart/antv-dashboard/index.jsx                      |  198 +++++++++-
 src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx |    8 
 src/templates/sharecomponent/treesettingcomponent/index.jsx             |   11 
 40 files changed, 948 insertions(+), 124 deletions(-)

diff --git a/src/api/cacheutils.js b/src/api/cacheutils.js
index 2aa5642..aa742fc 100644
--- a/src/api/cacheutils.js
+++ b/src/api/cacheutils.js
@@ -5,7 +5,7 @@
   /**
    * @description 鎵撳紑websql
    */
-  static openWebSql () {
+  static openWebSql (sysType) {
     let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : ''
     try {
       window.GLOB.WebSql = openDatabase(`mkdb${service}`, '1', 'mk-pc-database', 50 * 1024 * 1024)
@@ -22,6 +22,15 @@
           // eslint-disable-next-line
           throw 'CREATE TABLE ERROR'
         })
+
+        if (sysType === 'local' && window.GLOB.systemType === '') {
+          tx.executeSql('CREATE TABLE IF NOT EXISTS FUNCS (func_code varchar(50), key_sql text, CDefine1 varchar(50), CDefine2 varchar(50), CDefine3 varchar(50))', [], () => {
+
+          }, () => {
+            // eslint-disable-next-line
+            throw 'CREATE TABLE ERROR'
+          })
+        }
       })
       // window.GLOB.WebSql.transaction(tx => {
       //   tx.executeSql('DROP TABLE VERSIONS')
@@ -42,16 +51,13 @@
     }
     return new Promise((resolve, reject) => {
       window.GLOB.WebSql.transaction(tx => {
-        tx.executeSql('SELECT * FROM VERSIONS', [], (tx, results) => {
+        tx.executeSql("SELECT * FROM VERSIONS where CDefine1='LongParam'", [], (tx, results) => {
           if (results.rows.length === 0) {
-            tx.executeSql('DELETE FROM CONFIGS')
-            resolve({version: '', createDate: ''})
-          } else if (results.rows.length === 1) {
-            resolve(results.rows[0])
-          } else if (results.rows.length > 1) {
             tx.executeSql('DELETE FROM VERSIONS')
             tx.executeSql('DELETE FROM CONFIGS')
             resolve({version: '', createDate: ''})
+          } else {
+            resolve(results.rows[0])
           }
         }, (tx, results) => {
           window.GLOB.WebSql = null
@@ -107,7 +113,7 @@
   static updateWebSqlTime (curTime) {
     if (!window.GLOB.WebSql || !curTime) return
     window.GLOB.WebSql.transaction(tx => {
-      tx.executeSql(`UPDATE VERSIONS SET createDate='${curTime}'`, [], () => {}, () => {
+      tx.executeSql(`UPDATE VERSIONS SET createDate='${curTime}' where CDefine1='LongParam'`, [], () => {}, () => {
         window.GLOB.WebSql = null
       })
     })
@@ -119,7 +125,7 @@
   static updateWebSqlversion (version, curTime) {
     if (!window.GLOB.WebSql || !curTime || !version) return
     window.GLOB.WebSql.transaction(tx => {
-      tx.executeSql(`UPDATE VERSIONS SET version='${version}', createDate='${curTime}'`, [], () => {}, () => {
+      tx.executeSql(`UPDATE VERSIONS SET version='${version}', createDate='${curTime}' where CDefine1='LongParam'`, [], () => {}, () => {
         window.GLOB.WebSql = null
       })
     })
@@ -131,7 +137,7 @@
   static createWebSqlversion (version, curTime) {
     if (!window.GLOB.WebSql || !curTime || !version) return
     window.GLOB.WebSql.transaction(tx => {
-      tx.executeSql('INSERT INTO VERSIONS (version, createDate) VALUES (?, ?)', [version, curTime], () => {}, () => {
+      tx.executeSql('INSERT INTO VERSIONS (version, createDate, CDefine1) VALUES (?, ?, ?)', [version, curTime, 'LongParam'], () => {}, () => {
         window.GLOB.WebSql = null
       })
     })
@@ -182,7 +188,7 @@
   /**
    * @description 鎵撳紑IndexedDB
    */
-  static openIndexDB () {
+  static openIndexDB (sysType) {
     let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : ''
     try {
       let request = window.indexedDB.open(`mkdb${service}`, 1)
@@ -202,6 +208,9 @@
           objectStore.createIndex('menuid', 'menuid', { unique: false })
           objectStore.createIndex('userid', 'userid', { unique: false })
         }
+        if (window.GLOB.systemType === '' && sysType === 'local' && !window.GLOB.IndexDB.objectStoreNames.contains('funcs')) {
+          window.GLOB.IndexDB.createObjectStore('funcs', { keyPath: 'id' })
+        }
       }
     } catch (e) {
       console.warn('IndexedDB 鍒濆鍖栧け璐ワ紒')
diff --git a/src/api/index.js b/src/api/index.js
index 87db4d9..4ef1cb0 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -17,9 +17,9 @@
   1578479100252lfbp29v1kafk4s4q4ig,1577971621421tg4v0i1ur8873k7e0ob,1577929944419lgc5h3hepum765e2k7u,1588493493409k9guqp067d31lu7blsv`
 
 if (window.openDatabase) {
-  CacheUtils.openWebSql()
+  CacheUtils.openWebSql(options.sysType)
 } else if (window.indexedDB) {
-  CacheUtils.openIndexDB()
+  CacheUtils.openIndexDB(options.sysType)
 }
 
 axios.defaults.crossDomain = true
@@ -431,6 +431,30 @@
   /**
    * @description 鑾峰彇鎴栦慨鏀圭郴缁熼厤缃紝澧炲姞appkey
    */
+  getSystemFuncs (time) {
+    let param = {
+      func: 's_get_func_base_sso',
+      update_date: time,
+      userid: sessionStorage.getItem('UserID') || '',
+      lang: sessionStorage.getItem('lang') || '',
+      SessionUid: localStorage.getItem('SessionUid') || '',
+      LoginUID: sessionStorage.getItem('LoginUID') || '',
+      appkey: window.GLOB.appkey
+    }
+
+    let url = window.GLOB.mainSystemApi
+    param = this.encryptParam(param)
+
+    return axios({
+      url: `${url}/${param.func}`,
+      method: 'post',
+      data: param
+    })
+  }
+
+  /**
+   * @description 鑾峰彇鎴栦慨鏀圭郴缁熼厤缃紝澧炲姞appkey
+   */
   getSystemConfig (param) {
     param.userid = param.userid || sessionStorage.getItem('UserID') || ''
     param.lang = param.lang || sessionStorage.getItem('lang') || ''
diff --git a/src/assets/mobimg/ratioboard.png b/src/assets/mobimg/ratioboard.png
new file mode 100644
index 0000000..53498da
--- /dev/null
+++ b/src/assets/mobimg/ratioboard.png
Binary files differ
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index 075ba1e..0fab405 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -371,7 +371,7 @@
     // 淇敼缂栬緫鐘舵��
     let UserID = sessionStorage.getItem('CloudUserID')
     let LoginUID = sessionStorage.getItem('CloudLoginUID')
-
+    
     if (!UserID || !LoginUID) {
       this.setState({
         loginVisible: true
@@ -408,6 +408,8 @@
           sessionStorage.setItem('dataM', res.dataM ? 'true' : '')
           sessionStorage.setItem('isEditState', 'true')
 
+          this.setSystemFuncs()
+
           this.props.modifyMenuTree([])
           this.props.modifyMainMenu(null)
           this.props.modifyTabview([])
@@ -431,6 +433,107 @@
     })
   }
 
+  setSystemFuncs = () => {
+    if (!window.GLOB.WebSql && !window.GLOB.IndexDB) {
+      return
+    }
+    this.getfuncTime().then(res => {
+      Api.getSystemFuncs(res.createDate).then(result => {
+        if (!result.status) {
+          notification.error({
+            top: 92,
+            message: result.message,
+            duration: 10
+          })
+          return
+        } else if (result.func_detail && result.func_detail.length > 0) {
+          this.writeFuncs(result.func_detail)
+        }
+      })
+    })
+  }
+
+  writeFuncs = (funcs) => {
+    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+
+    let sys_datetime = sessionStorage.getItem('sys_datetime')
+    let app_datetime = sessionStorage.getItem('app_datetime')
+    if (sys_datetime && app_datetime) {
+      let seconds = Math.floor((new Date().getTime() - app_datetime) / 1000)
+      timestamp = moment(sys_datetime, 'YYYY-MM-DD HH:mm:ss').add(seconds, 'seconds').format('YYYY-MM-DD HH:mm:ss')
+    }
+
+    if (window.GLOB.WebSql) {
+      window.GLOB.WebSql.transaction(tx => {
+        tx.executeSql('DELETE FROM FUNCS')
+
+        funcs.forEach(item => {
+          if (!item.key_sql) return
+          tx.executeSql('INSERT INTO FUNCS (func_code, key_sql) VALUES (?, ?)', [item.func_code, item.key_sql])
+        })
+        tx.executeSql(`UPDATE VERSIONS SET createDate='${timestamp}' where CDefine1='funcs'`)
+      })
+    } else {
+      let objectStore = window.GLOB.IndexDB.transaction(['funcs'], 'readwrite').objectStore('funcs')
+
+      objectStore.clear()
+
+      funcs.forEach(item => {
+        if (!item.key_sql) return
+        item.id = item.func_code
+        objectStore.add(item)
+      })
+
+      let funcStore = window.GLOB.IndexDB.transaction(['version'], 'readwrite').objectStore('version')
+      funcStore.put({id: 'funcs', version: '1.0', createDate: timestamp})
+    }
+  }
+
+  getfuncTime = () => {
+    return new Promise((resolve, reject) => {
+      if (window.GLOB.WebSql) {
+        window.GLOB.WebSql.transaction(tx => {
+          tx.executeSql("SELECT * FROM VERSIONS where CDefine1='funcs'", [], (tx, results) => {
+            let rows = results.rows
+            if (rows.length === 0) {
+              tx.executeSql('DELETE FROM FUNCS')
+              tx.executeSql('INSERT INTO VERSIONS (version, createDate, CDefine1) VALUES (?, ?, ?)', ['1.0', '1970-01-01 14:59:09.000', 'funcs'])
+              resolve({createDate: '1970-01-01 14:59:09.000'})
+            } else {
+              resolve(rows[0])
+            }
+          }, (tx, results) => {
+            reject()
+            console.warn(results)
+          })
+        })
+      } else {
+        let objectStore = window.GLOB.IndexDB.transaction(['version'], 'readwrite').objectStore('version')
+        let request = objectStore.get('funcs')
+
+        request.onerror = (event) => {
+          console.warn(event)
+          reject()
+        }
+
+        request.onsuccess = () => {
+          if (request.result) {
+            resolve(request.result)
+          } else {
+            let add = objectStore.add({id: 'funcs', version: '1.0', createDate: '1970-01-01 14:59:09.000'})
+    
+            add.onerror = () => {
+              reject()
+            }
+            add.onsuccess = () => {
+              resolve({id: 'funcs', version: '1.0', createDate: '1970-01-01 14:59:09.000'})
+            }
+          }
+        }
+      }
+    })
+  }
+
   changeSystem = (system) => {
     let url = system.LinkUrl1
 
diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx
index 87789f7..547d9f4 100644
--- a/src/menu/components/chart/antv-bar/index.jsx
+++ b/src/menu/components/chart/antv-bar/index.jsx
@@ -123,9 +123,11 @@
   }
 
   componentDidMount () {
-    this.viewrender()
     MKEmitter.addListener('submitStyle', this.getStyle)
     MKEmitter.addListener('tabsChange', this.handleTabsChange)
+    setTimeout(() => {
+      this.viewrender()
+    }, 1000)
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -196,10 +198,14 @@
    */
   linerender = () => {
     const { card } = this.state
-    let plot = {...card.plot, height: card.plot.height - 70} // 鍘婚櫎title鎵�鍗犵┖闂�
+    let plot = {...card.plot} // 鍘婚櫎title鎵�鍗犵┖闂�
     let color = plot.color || 'rgba(0, 0, 0, 0.65)'
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || ['y']
+
+    if (card.plot.title || card.search.length > 0) {
+      plot.height = card.plot.height - 70
+    }
 
     let data = this.getdata(X_axis, Y_axis)
 
@@ -383,12 +389,16 @@
    */
   customrender = (data) => {
     let card = fromJS(this.state.card).toJS()
-    let plot = {...card.plot, height: card.plot.height - 70} // 鍘婚櫎title鎵�鍗犵┖闂�
+    let plot = {...card.plot} // 鍘婚櫎title鎵�鍗犵┖闂�
     let color = plot.color || 'rgba(0, 0, 0, 0.65)'
     let fields = []
     let legends = []
     let transfield = {}
     let Bar_axis = []
+
+    if (card.plot.title || card.search.length > 0) {
+      plot.height = card.plot.height - 70
+    }
 
     card.columns.forEach(col => {
       if (col.field) {
@@ -792,10 +802,14 @@
    */
   barrender = () => {
     const { card } = this.state
-    let plot = {...card.plot, height: card.plot.height - 70}
+    let plot = {...card.plot}
     let color = plot.color || 'rgba(0, 0, 0, 0.65)'
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || ['y']
+
+    if (card.plot.title || card.search.length > 0) {
+      plot.height = card.plot.height - 70
+    }
 
     let data = this.getdata(X_axis, Y_axis)
     
@@ -1154,7 +1168,6 @@
 
     return (
       <div className="menu-line-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
-        <NormalHeader config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             {!ismob ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
@@ -1172,12 +1185,13 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
+        <div className="canvas" id={card.uuid + 'canvas'}></div>
         <ActionComponent
           type="chart"
           config={card}
           updateaction={this.updateComponent}
         />
-        <div className="canvas" id={card.uuid + 'canvas'}></div>
       </div>
     )
   }
diff --git a/src/menu/components/chart/antv-bar/index.scss b/src/menu/components/chart/antv-bar/index.scss
index bc94603..0c212d3 100644
--- a/src/menu/components/chart/antv-bar/index.scss
+++ b/src/menu/components/chart/antv-bar/index.scss
@@ -10,7 +10,10 @@
     margin: 0px;
     padding: 15px 10px 10px;
     letter-spacing: 0px;
-    min-height: calc(100% - 45px);
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
   }
 
   .chart-header {
@@ -47,6 +50,7 @@
   .model-menu-action-list {
     position: absolute;
     right: 0px;
+    top: 30px;
     z-index: 4;
     font-size: 16px;
   
@@ -58,6 +62,9 @@
       float: right;
     }
   }
+  .normal-header + .canvas + .model-menu-action-list {
+    top: 45px;
+  }
 }
 .menu-line-chart-edit-box:hover {
   z-index: 1;
diff --git a/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx b/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx
index 3449d39..335df94 100644
--- a/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx
+++ b/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx
@@ -143,3 +143,91 @@
     }
   ]
 }
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ * @param {Array}  columns    // 鏄剧ず鍒�
+ */
+export function getRadioOptionForm (card, columns) {
+  let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
+  let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
+
+  return [
+    {
+      type: 'select',
+      key: 'labelField',
+      label: '鎸囨爣',
+      initVal: card.labelField || '',
+      required: true,
+      options: xfields
+    },
+    {
+      type: 'select',
+      key: 'valueField',
+      label: '鍊�',
+      initVal: card.valueField || '',
+      required: true,
+      options: yfields
+    },
+    {
+      type: 'number',
+      key: 'maxValue',
+      label: '鏈�澶у��',
+      initVal: card.maxValue || 100,
+      min: 0,
+      max: 999999,
+      decimal: 1,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'radius',
+      label: '澶栫幆',
+      initVal: card.radius || 75,
+      tooltip: '鍥惧舰鎵�鍗犲尯鍩熺殑鐧惧垎鐜囥��',
+      min: 30,
+      max: 100,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'fontSize',
+      label: '瀛椾綋澶у皬',
+      initVal: card.fontSize || 28,
+      min: 12,
+      max: 200,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'radio',
+      key: 'percent',
+      label: '鐧惧垎鐜�',
+      initVal: card.percent || 'true',
+      required: false,
+      options: [{
+        value: 'true',
+        text: '浣跨敤'
+      }, {
+        value: 'false',
+        text: '涓嶄娇鐢�'
+      }]
+    },
+    {
+      type: 'color',
+      key: 'backColor',
+      label: '鑳屾櫙鑹�',
+      initVal: card.backColor || '#ebedf0',
+      required: false
+    },
+    {
+      type: 'color',
+      key: 'labelColor',
+      label: '瀛椾綋棰滆壊',
+      initVal: card.labelColor || '#8c8c8c',
+      required: false
+    }
+  ]
+}
diff --git a/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx b/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx
index 051a639..76effa8 100644
--- a/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx
+++ b/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx
@@ -4,7 +4,7 @@
 import { Modal, Form, Row, Col, Select, Icon, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
 
 import Utils from '@/utils/utils.js'
-import { getBaseForm, getOptionForm } from './formconfig'
+import { getBaseForm, getOptionForm, getRadioOptionForm } from './formconfig'
 import asyncComponent from '@/utils/asyncComponent'
 import ColorSketch from '@/mob/colorsketch'
 import './index.scss'
@@ -32,7 +32,7 @@
       {
         title: '鎸囨爣',
         dataIndex: 'tick',
-        inputType: 'number',
+        inputType: this.props.config.subtype === 'ratioboard' ? 'text' : 'number',
         editable: true,
         width: '40%'
       },
@@ -57,30 +57,8 @@
       view: 'normal',
       plot: fromJS(config.plot).toJS(),
       baseFormlist: getBaseForm(config.plot),
-      formlist: getOptionForm(config.plot, config.columns)
+      formlist: config.subtype === 'ratioboard' ? getRadioOptionForm(config.plot, config.columns) : getOptionForm(config.plot, config.columns)
     })
-  }
-
-  radioChange = (e, key) => {
-    const { formlist } = this.state
-    let val = e.target.value
-
-    if (key === 'shape') {
-      this.setState({
-        formlist: formlist.map(item => {
-          if (item.key === 'innerRadius') {
-            item.hidden = val === 'pie'
-          }
-          return item
-        })
-      }, () => {
-        if (val === 'ring') {
-          this.props.form.setFieldsValue({innerRadius: 50})
-        } else if (val === 'nightingale') {
-          this.props.form.setFieldsValue({innerRadius: 0})
-        }
-      })
-    }
   }
 
   getFields() {
@@ -184,7 +162,7 @@
                   }
                 ]
               })(
-                <Radio.Group disabled={item.readonly} onChange={(e) => this.radioChange(e, item.key)}>
+                <Radio.Group disabled={item.readonly}>
                   {item.options.map(option => {
                     return (
                       <Radio key={option.value} value={option.value}>{option.text}</Radio>
@@ -197,7 +175,7 @@
         )
       } else if (item.type === 'color') {
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={12} key={index} className="color-col">
             <Form.Item label={item.tooltip ?
               <Tooltip placement="topLeft" title={item.tooltip}>
                 <Icon type="question-circle" />
diff --git a/src/menu/components/chart/antv-dashboard/chartcompile/index.scss b/src/menu/components/chart/antv-dashboard/chartcompile/index.scss
index 25a7c53..607a36d 100644
--- a/src/menu/components/chart/antv-dashboard/chartcompile/index.scss
+++ b/src/menu/components/chart/antv-dashboard/chartcompile/index.scss
@@ -33,6 +33,11 @@
         position: relative;
         z-index: 1;
       }
+      .color-col {
+        .ant-form-item-control {
+          height: 40px;
+        }
+      }
     }
   }
 }
diff --git a/src/menu/components/chart/antv-dashboard/index.jsx b/src/menu/components/chart/antv-dashboard/index.jsx
index d4646d1..62bde3e 100644
--- a/src/menu/components/chart/antv-dashboard/index.jsx
+++ b/src/menu/components/chart/antv-dashboard/index.jsx
@@ -50,6 +50,12 @@
   },
 })
 
+registerShape('point', 'hidden', {
+  draw(cfg, container) {
+    return container.addGroup({})
+  }
+})
+
 class antvDashboardChart extends Component {
   static propTpyes = {
     card: PropTypes.object,
@@ -68,17 +74,34 @@
     const { card, ismob } = this.props
 
     if (card.isNew) {
-      let _plot = {
-        width: card.width || 12,
-        height: 400,
-        label: '',
-        valueField: '',
-        name: card.name,
-        maxValue: 100,
-        tickInterval: 10,
-        labelColor: '#545454',
-        tickColor: '#CBCBCB',
-        percent: 'true'
+      let _plot = null
+      if (card.subtype === 'ratioboard') {
+        _plot = {
+          width: card.width || 12,
+          height: 400,
+          labelField: '',
+          valueField: '',
+          name: card.name,
+          maxValue: 100,
+          radius: 75,
+          fontSize: 28,
+          percent: 'true',
+          backColor: '#ebedf0',
+          labelColor: '#8c8c8c'
+        }
+      } else {
+        _plot = {
+          width: card.width || 12,
+          height: 400,
+          label: '',
+          valueField: '',
+          name: card.name,
+          maxValue: 100,
+          tickInterval: 10,
+          labelColor: '#545454',
+          tickColor: '#CBCBCB',
+          percent: 'true'
+        }
       }
 
       if (ismob) {
@@ -91,7 +114,7 @@
         floor: card.floor,
         tabId: card.tabId || '',
         parentId: card.parentId || '',
-        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        format: card.subtype === 'ratioboard' ? 'array' : 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
         pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
         switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
         dataName: card.dataName || '',
@@ -133,7 +156,7 @@
   }
 
   componentDidMount () {
-    this.dashboardrender()
+    this.viewrender()
     MKEmitter.addListener('tabsChange', this.handleTabsChange)
     MKEmitter.addListener('submitStyle', this.getStyle)
   }
@@ -163,8 +186,131 @@
       }
 
       this.$timer && clearTimeout(this.$timer)
-      this.$timer = setTimeout(this.dashboardrender, 100)
+      this.$timer = setTimeout(this.viewrender, 100)
     }
+  }
+
+  viewrender = () => {
+    const { card } = this.state
+    if (card.subtype === 'ratioboard') {
+      this.ratioboardrender()
+    } else {
+      this.dashboardrender()
+    }
+  }
+
+  getratiodata = () => {
+    const { card } = this.state
+
+    let val = (Math.random() * card.plot.maxValue).toFixed(1)
+    let data = [
+      { type: '鏂扮敤鎴�', value: val, $percent: val / card.plot.maxValue, $color: '#1890ff' },
+    ]
+    if (card.plot.colors && card.plot.colors.length > 0) {
+      data = []
+      card.plot.colors.forEach(item => {
+        let _val = (Math.random() * card.plot.maxValue).toFixed(1)
+        data.push({
+          type: item.tick,
+          value: _val,
+          $percent: _val / card.plot.maxValue,
+          $color: item.color
+        })
+      })
+    }
+
+    return data
+  }
+
+  ratioboardrender = () => {
+    const { card } = this.state
+    const plot = card.plot
+
+    const data = this.getratiodata()
+    
+    const chart = new Chart({
+      container: card.uuid + 'dashboard',
+      autoFit: true,
+      height: plot.title ? plot.height - 45 : plot.height,
+    })
+    
+    chart.data(data)
+    chart.coordinate('polar', {
+      startAngle: -Math.PI / 2,
+      endAngle: 3 * Math.PI / 2,
+      radius: (plot.radius || 75) / 100
+    })
+    chart.scale('$percent', {
+      min: 0,
+      max: 1,
+      tickInterval: 1,
+    })
+    chart.axis(false)
+    chart.facet('rect', {
+      fields: ['type'],
+      showTitle: false,
+      eachView: function eachView(view, facet) {
+        const data = facet.data[0]
+
+        view.point().position('').shape('hidden')
+
+        view.annotation().arc({
+          top: false,
+          start: [0, 1],
+          end: [0.9999, 1],
+          style: {
+            stroke: plot.backColor,
+            lineWidth: 10
+          }
+        })
+
+        let _tick = data.$percent
+        if (_tick >= 1) {
+          _tick = 0.9999
+        }
+
+        view.annotation().arc({
+          start: [0, 1],
+          end: [_tick, 1],
+          style: {
+            stroke: data.$color,
+            lineWidth: 10,
+          }
+        })
+        // 浠〃鐩樹俊鎭�
+        let text = ''
+        if (plot.percent === 'true') {
+          text = +(data.$percent * 100).toFixed(2) + '%'
+        } else {
+          text = data.value
+        }
+    
+        view.annotation().text({
+          position: ['50%', '45%'],
+          content: data.type,
+          style: {
+            fontSize: plot.fontSize * 0.8,
+            fill: plot.labelColor,
+            fontWeight: 300,
+            textAlign: 'center'
+          },
+          offsetX: 0
+        })
+        view.annotation().text({
+          position: ['50%', '55%'],
+          content: text,
+          style: {
+            fontSize: plot.fontSize,
+            fill: plot.labelColor,
+            fontWeight: 500,
+            textAlign: 'center'
+          },
+          offsetX: 0,
+          offsetY: 10
+        })
+      }
+    })
+    chart.render()
   }
 
   getdata = () => {
@@ -184,22 +330,22 @@
     const chart = new Chart({
       container: card.uuid + 'dashboard',
       autoFit: true,
-      height: plot.height ? (plot.height - 75) : 325,
+      height: plot.title ? plot.height - 45 : plot.height,
       padding: [0, 0, 0, 0],
     })
-    chart.data(data);
+    chart.data(data)
     chart.scale('value', {
       min: 0,
       max: plot.maxValue,
       tickInterval: plot.tickInterval,
-    });
+    })
     chart.coordinate('polar', {
       startAngle: (-9 / 8) * Math.PI,
       endAngle: (1 / 8) * Math.PI,
       radius: 0.75,
-    });
+    })
 
-    chart.axis('1', false);
+    chart.axis('1', false)
     chart.axis('value', {
       line: null,
       label: {
@@ -218,9 +364,9 @@
         }
       },
       grid: null,
-    });
-    chart.legend(false);
-    chart.tooltip(false);
+    })
+    chart.legend(false)
+    chart.tooltip(false)
     chart
       .point()
       .position('value*1')
@@ -243,7 +389,7 @@
         appear: {
           animation: 'fade-in'
         }
-      });
+      })
 
     // 缁樺埗浠〃鐩樿儗鏅�
     chart.annotation().arc({
@@ -251,7 +397,7 @@
       start: [0, 1],
       end: [plot.maxValue, 1],
       style: {
-        stroke: '#CBCBCB',
+        stroke: '#ebedf0',
         lineWidth: 18,
         lineDash: null,
       },
@@ -324,7 +470,7 @@
       }
       this.$timer && clearTimeout(this.$timer)
       this.$timer = setTimeout(() => {
-        this.dashboardrender()
+        this.viewrender()
       }, 150)
     }
 
@@ -366,7 +512,6 @@
 
     return (
       <div className="menu-dashboard-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
-        <NormalHeader config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
@@ -380,6 +525,7 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
+        {card.plot.title ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
         <div className="canvas" id={card.uuid + 'dashboard'}></div>
       </div>
     )
diff --git a/src/menu/components/chart/antv-dashboard/index.scss b/src/menu/components/chart/antv-dashboard/index.scss
index d4bdc91..efb4267 100644
--- a/src/menu/components/chart/antv-dashboard/index.scss
+++ b/src/menu/components/chart/antv-dashboard/index.scss
@@ -10,7 +10,10 @@
     margin: 0px;
     padding: 15px;
     letter-spacing: 0px;
-    min-height: calc(100% - 45px);
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
   }
 
   >.anticon-tool {
diff --git a/src/menu/components/chart/antv-pie/index.jsx b/src/menu/components/chart/antv-pie/index.jsx
index 343f9ae..cfbbd96 100644
--- a/src/menu/components/chart/antv-pie/index.jsx
+++ b/src/menu/components/chart/antv-pie/index.jsx
@@ -210,6 +210,10 @@
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || 'y'
     let type = plot.type || 'type'
+    let height = plot.height || 400
+    if (card.plot.title || card.search.length > 0) {
+      height = height - 45
+    }
 
     const _data = this.getnestdata(X_axis, Y_axis, type)
     const dvx = new DataView().source(_data)
@@ -241,7 +245,7 @@
     const chart = new Chart({
       container: card.uuid + 'canvas',
       autoFit: true,
-      height: card.plot.height ? (card.plot.height - 75) : 325,
+      height: height,
       padding: 0,
     })
 
@@ -419,6 +423,10 @@
     let color = plot.color || 'rgba(0, 0, 0, 0.85)'
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || 'y'
+    let height = plot.height || 400
+    if (card.plot.title || card.search.length > 0) {
+      height = height - 45
+    }
 
     let data = this.getdata(X_axis, Y_axis)
 
@@ -428,7 +436,7 @@
     const chart = new Chart({
       container: card.uuid + 'canvas',
       autoFit: true,
-      height: card.plot.height ? (card.plot.height - 75) : 325
+      height: height
     })
 
     if (plot.shape !== 'nightingale' && plot.show !== 'value') {
@@ -683,7 +691,6 @@
 
     return (
       <div className="menu-pie-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
-        <NormalHeader config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             {!ismob ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
@@ -699,6 +706,7 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
         <div className="canvas" id={card.uuid + 'canvas'}></div>
       </div>
     )
diff --git a/src/menu/components/chart/antv-pie/index.scss b/src/menu/components/chart/antv-pie/index.scss
index 042b9b8..43bf1c5 100644
--- a/src/menu/components/chart/antv-pie/index.scss
+++ b/src/menu/components/chart/antv-pie/index.scss
@@ -10,7 +10,10 @@
     margin: 0px;
     padding: 15px;
     letter-spacing: 0px;
-    min-height: calc(100% - 45px);
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
   }
 
   >.anticon-tool {
diff --git a/src/menu/components/chart/antv-scatter/index.jsx b/src/menu/components/chart/antv-scatter/index.jsx
index 46abf2f..41a896b 100644
--- a/src/menu/components/chart/antv-scatter/index.jsx
+++ b/src/menu/components/chart/antv-scatter/index.jsx
@@ -110,9 +110,11 @@
   }
 
   componentDidMount () {
-    this.ponitrender()
     MKEmitter.addListener('submitStyle', this.getStyle)
     MKEmitter.addListener('tabsChange', this.handleTabsChange)
+    setTimeout(() => {
+      this.ponitrender()
+    }, 1000)
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -185,11 +187,16 @@
     const { card } = this.state
     const plot = card.plot
     const data = this.getdata()
+    let height = plot.height - 25
+
+    if (card.plot.title || card.search.length > 0) {
+      height = plot.height - 70
+    }
 
     const chart = new Chart({
       container: card.uuid + 'canvas',
       autoFit: true,
-      height: plot.height - 70
+      height: height
     })
 
     chart.data(data);
@@ -368,27 +375,27 @@
     let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-line-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
-        <NormalHeader config={card} updateComponent={this.updateComponent}/>
+      <div className="menu-scatter-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
-            {!ismob ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
+            {!ismob ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle"/> : null}
             <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
             <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
             <CopyComponent type="line" card={card}/>
-            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
-            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
-            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
+            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors"/>
+            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog}/>
             <ClockComponent config={card} updateConfig={this.updateComponent}/>
             <UserComponent config={card}/>
-            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)}/>
             <SettingComponent config={card} updateConfig={this.updateComponent}/>
           </div>
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
-        <ActionComponent type="chart" config={card} updateaction={this.updateComponent} />
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
         <div className="canvas" id={card.uuid + 'canvas'}></div>
+        <ActionComponent type="chart" config={card} updateaction={this.updateComponent}/>
       </div>
     )
   }
diff --git a/src/menu/components/chart/antv-scatter/index.scss b/src/menu/components/chart/antv-scatter/index.scss
index bc94603..4403718 100644
--- a/src/menu/components/chart/antv-scatter/index.scss
+++ b/src/menu/components/chart/antv-scatter/index.scss
@@ -1,4 +1,4 @@
-.menu-line-chart-edit-box {
+.menu-scatter-chart-edit-box {
   position: relative;
   box-sizing: border-box;
   background: #ffffff;
@@ -10,7 +10,10 @@
     margin: 0px;
     padding: 15px 10px 10px;
     letter-spacing: 0px;
-    min-height: calc(100% - 45px);
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
   }
 
   .chart-header {
@@ -47,6 +50,7 @@
   .model-menu-action-list {
     position: absolute;
     right: 0px;
+    top: 30px;
     z-index: 4;
     font-size: 16px;
   
@@ -58,8 +62,11 @@
       float: right;
     }
   }
+  .normal-header + .canvas + .model-menu-action-list {
+    top: 45px;
+  }
 }
-.menu-line-chart-edit-box:hover {
+.menu-scatter-chart-edit-box:hover {
   z-index: 1;
   box-shadow: 0px 0px 4px #1890ff;
 }
diff --git a/src/menu/components/search/main-search/index.jsx b/src/menu/components/search/main-search/index.jsx
index 4eacfae..e56dafa 100644
--- a/src/menu/components/search/main-search/index.jsx
+++ b/src/menu/components/search/main-search/index.jsx
@@ -123,6 +123,20 @@
     this.props.updateConfig(component)
   }
 
+  checkComponent = (component) => {
+    this.updateComponent(component)
+
+    let _item = null
+    component.search.forEach(item => {
+      if (!_item && item.focus) {
+        _item = item
+      }
+    })
+    if (_item) {
+      this.handleSearch(_item)
+    }
+  }
+
   /**
    * @description 鎼滅储鏉′欢椤哄簭璋冩暣锛屾垨鎷栨嫿娣诲姞
    */
@@ -375,7 +389,7 @@
             <Icon className="plus" title="娣诲姞" onClick={this.addSearch} type="plus" />
             <WrapComponent config={card} updateConfig={this.updateComponent}/>
             <CopyComponent type="mainsearch" card={card}/>
-            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.updateComponent} />
+            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.checkComponent} />
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
             <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
           </div>
diff --git a/src/menu/datasource/index.jsx b/src/menu/datasource/index.jsx
index 9732b5a..01d1c81 100644
--- a/src/menu/datasource/index.jsx
+++ b/src/menu/datasource/index.jsx
@@ -100,7 +100,19 @@
           return item
         })
       }
-      
+
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          if (res.setting.dataresource) {
+            res.setting.dataresource = res.setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          }
+          res.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+        })
+      }
+
       this.setState({loading: false, visible: false})
       this.props.updateConfig({...config, ...res})
     }, () => {
diff --git a/src/menu/datasource/verifycard/index.jsx b/src/menu/datasource/verifycard/index.jsx
index 0e0666e..594f176 100644
--- a/src/menu/datasource/verifycard/index.jsx
+++ b/src/menu/datasource/verifycard/index.jsx
@@ -194,11 +194,24 @@
     getcomponentmarks(menu, config)
 
     let _setting = fromJS(config.setting).toJS()
+    let scripts = fromJS(config.scripts).toJS()
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+        scripts && scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+      })
+    }
 
     this.setState({
+      scripts,
       columns: fromJS(config.columns).toJS(),
       setting: _setting,
-      scripts: fromJS(config.scripts).toJS(),
       searches: search,
       varMarks: Marks
     })
diff --git a/src/menu/datasource/verifycard/utils.jsx b/src/menu/datasource/verifycard/utils.jsx
index 9858c7d..3b3b266 100644
--- a/src/menu/datasource/verifycard/utils.jsx
+++ b/src/menu/datasource/verifycard/utils.jsx
@@ -26,6 +26,14 @@
       _dataresource = setting.dataresource || ''
     }
     
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
+
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
     _dataresource = _dataresource.replace(/@select\$|\$select@/ig, '')
@@ -52,8 +60,7 @@
         _customScript = _customScript.replace(reg, '0')
       })
     }
-    
-    
+
     // 姝e垯鏇挎崲
     let _regoptions = []
     let _fields = []
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index 4b6f0d6..99e6ef6 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -19,6 +19,7 @@
 import Carousel1 from '@/assets/mobimg/carousel1.png'
 import form from '@/assets/mobimg/form.png'
 import dashboard from '@/assets/mobimg/dashboard.png'
+import ratioboard from '@/assets/mobimg/ratioboard.png'
 import scatter from '@/assets/mobimg/scatter.png'
 import tree from '@/assets/mobimg/tree.png'
 
@@ -43,6 +44,7 @@
   { type: 'menu', url: Pie3, component: 'pie', subtype: 'nest', title: '宓屽楗煎浘', width: 12 },
   { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
   { type: 'menu', url: dashboard, component: 'dashboard', subtype: 'dashboard', title: '浠〃鐩�', width: 12 },
+  { type: 'menu', url: ratioboard, component: 'dashboard', subtype: 'ratioboard', title: '鍗犳瘮鍥�', width: 12 },
   { type: 'menu', url: scatter, component: 'scatter', subtype: 'scatter', title: '鏁g偣鍥�', width: 24 },
   { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '瀵屾枃鏈�', width: 24 },
   { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
diff --git a/src/pc/modulesource/option.jsx b/src/pc/modulesource/option.jsx
index 8926ac7..25fdbd9 100644
--- a/src/pc/modulesource/option.jsx
+++ b/src/pc/modulesource/option.jsx
@@ -21,6 +21,7 @@
 import form from '@/assets/mobimg/form.png'
 import Login from '@/assets/mobimg/login.png'
 import dashboard from '@/assets/mobimg/dashboard.png'
+import ratioboard from '@/assets/mobimg/ratioboard.png'
 import scatter from '@/assets/mobimg/scatter.png'
 import tree from '@/assets/mobimg/tree.png'
 
@@ -46,6 +47,7 @@
   { type: 'menu', url: Pie3, component: 'pie', subtype: 'nest', title: '宓屽楗煎浘', width: 12 },
   { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
   { type: 'menu', url: dashboard, component: 'dashboard', subtype: 'dashboard', title: '浠〃鐩�', width: 12 },
+  { type: 'menu', url: ratioboard, component: 'dashboard', subtype: 'ratioboard', title: '鍗犳瘮鍥�', width: 12 },
   { type: 'menu', url: scatter, component: 'scatter', subtype: 'scatter', title: '鏁g偣鍥�', width: 24 },
   { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '瀵屾枃鏈�', width: 24 },
   { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
diff --git a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
index e702da2..6fcdc2f 100644
--- a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
@@ -45,6 +45,12 @@
   },
 })
 
+registerShape('point', 'hidden', {
+  draw(cfg, container) {
+    return container.addGroup({})
+  }
+})
+
 class DashboardChart extends Component {
   static propTpyes = {
     BID: PropTypes.any,              // 鐖剁骇Id
@@ -69,21 +75,25 @@
     const { config, data, initdata, BID } = this.props
     let _config = fromJS(config).toJS()
 
-    let _data = {}
+    let _data = null
     let _sync = _config.setting.sync === 'true'
-    
+
     if (_sync && data) {
-      _data = data[_config.dataName] || {}
-      if (_data && Array.isArray(_data)) {
-        _data = _data[0] || {}
-      }
+      _data = data[config.dataName] || []
       _sync = false
     } else if (_sync && initdata) {
-      _data = initdata || {}
+      _data = initdata || []
+      _sync = false
+    }
+
+    if (_config.subtype === 'ratioboard') {
+      _data = _data || []
+    } else {
       if (_data && Array.isArray(_data)) {
         _data = _data[0] || {}
+      } else {
+        _data = {}
       }
-      _sync = false
     }
 
     let height = config.plot.height || 400
@@ -105,7 +115,7 @@
     }, () => {
       if (config.setting.sync !== 'true' && config.setting.onload === 'true') {
         this.loadData()
-      } else if (config.setting.sync === 'true' && _data) {
+      } else if (config.setting.sync === 'true') {
         this.handleData()
       }
     })
@@ -118,12 +128,21 @@
     const { sync, config } = this.state
 
     if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
-      let _data = {}
-      if (nextProps.data && nextProps.data[config.dataName]) {
-        _data = nextProps.data[config.dataName] || {}
-      }
-      if (_data.hasOwnProperty(config.plot.valueField)) {
-        _data.value = _data[config.plot.valueField]
+      let _data = null
+
+      if (config.subtype === 'ratioboard') {
+        _data = []
+        if (nextProps.data && nextProps.data[config.dataName]) {
+          _data = nextProps.data[config.dataName] || []
+        }
+      } else {
+        _data = {}
+        if (nextProps.data && nextProps.data[config.dataName]) {
+          _data = nextProps.data[config.dataName] || {}
+        }
+        if (_data.hasOwnProperty(config.plot.valueField)) {
+          _data.value = _data[config.plot.valueField]
+        }
       }
 
       this.setState({sync: false, data: _data}, () => {
@@ -234,7 +253,7 @@
     if (_element) {
       _element.innerHTML = ''
     }
-    this.dashboardrender()
+    this.viewrender()
   }
 
   async loadData (hastimer) {
@@ -279,9 +298,14 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      let data = {}
-      if (result.data && result.data[0] && result.data[0].hasOwnProperty(config.plot.valueField)) {
-        data.value = result.data[0][config.plot.valueField]
+      let data = null
+      if (config.subtype === 'ratioboard') {
+        data = result.data || []
+      } else {
+        let data = {}
+        if (result.data && result.data[0] && result.data[0].hasOwnProperty(config.plot.valueField)) {
+          data.value = result.data[0][config.plot.valueField]
+        }
       }
 
       this.setState({
@@ -303,6 +327,130 @@
     }
   }
 
+  viewrender = () => {
+    const { config } = this.state
+    if (config.subtype === 'ratioboard') {
+      this.ratioboardrender()
+    } else {
+      this.dashboardrender()
+    }
+  }
+
+  getratiodata = () => {
+    const { data, plot } = this.state
+
+    let colors = {}
+    if (plot.colors && plot.colors.length > 0) {
+      plot.colors.forEach(item => {
+        colors[item.tick] = item.color
+      })
+    }
+
+    return data.map(item => {
+      let val = +item[plot.valueField]
+      let type = item[plot.labelField] || ''
+      if (isNaN(val)) {
+        val = 0
+      }
+      return {
+        type: type,
+        value: val,
+        $percent: val / plot.maxValue,
+        $color: colors[type] || '#1890ff'
+      }
+    })
+  }
+
+  ratioboardrender = () => {
+    const { plot, chartId } = this.state
+
+    const data = this.getratiodata()
+
+    const chart = new Chart({
+      container: chartId,
+      autoFit: true,
+      height: plot.height,
+    })
+    
+    chart.data(data)
+    chart.coordinate('polar', {
+      startAngle: -Math.PI / 2,
+      endAngle: 3 * Math.PI / 2,
+      radius: (plot.radius || 75) / 100
+    })
+    chart.scale('$percent', {
+      min: 0,
+      max: 1,
+      tickInterval: 1,
+    })
+    chart.axis(false)
+    chart.facet('rect', {
+      fields: ['type'],
+      showTitle: false,
+      eachView: function eachView(view, facet) {
+        const data = facet.data[0]
+
+        view.point().position('').shape('hidden')
+
+        view.annotation().arc({
+          top: false,
+          start: [0, 1],
+          end: [0.9999, 1],
+          style: {
+            stroke: plot.backColor,
+            lineWidth: 10
+          }
+        })
+
+        let _tick = data.$percent
+        if (_tick >= 1) {
+          _tick = 0.9999
+        }
+
+        view.annotation().arc({
+          start: [0, 1],
+          end: [_tick, 1],
+          style: {
+            stroke: data.$color,
+            lineWidth: 10,
+          }
+        })
+        // 浠〃鐩樹俊鎭�
+        let text = ''
+        if (plot.percent === 'true') {
+          text = +(data.$percent * 100).toFixed(2) + '%'
+        } else {
+          text = data.value
+        }
+    
+        view.annotation().text({
+          position: ['50%', '45%'],
+          content: data.type,
+          style: {
+            fontSize: plot.fontSize * 0.8,
+            fill: plot.labelColor,
+            fontWeight: 300,
+            textAlign: 'center'
+          },
+          offsetX: 0
+        })
+        view.annotation().text({
+          position: ['50%', '55%'],
+          content: text,
+          style: {
+            fontSize: plot.fontSize,
+            fill: plot.labelColor,
+            fontWeight: 500,
+            textAlign: 'center'
+          },
+          offsetX: 0,
+          offsetY: 10
+        })
+      }
+    })
+    chart.render()
+  }
+
   /**
    * @description 浠〃鐩樻覆鏌�
    */
diff --git a/src/templates/sharecomponent/settingcalcomponent/index.jsx b/src/templates/sharecomponent/settingcalcomponent/index.jsx
index 416e27d..9aa21fa 100644
--- a/src/templates/sharecomponent/settingcalcomponent/index.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/index.jsx
@@ -44,6 +44,17 @@
 
     this.setState({loading: true})
     this.verifyRef.submitDataSource().then(res => {
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          res.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          if (res.setting.dataresource) {
+            res.setting.dataresource = res.setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          }
+        })
+      }
 
       this.setState({loading: false, visible: false})
       this.props.updateConfig({...config, ...res})
diff --git a/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx b/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
index 0a20347..8e00256 100644
--- a/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
@@ -71,10 +71,25 @@
   UNSAFE_componentWillMount() {
     const { config } = this.props
 
+    let _setting = fromJS(config.setting).toJS()
+    let _scripts = fromJS(config.scripts).toJS()
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+      })
+    }
+
     this.setState({
-      setting: fromJS(config.setting).toJS(),
+      setting: _setting,
       columns: fromJS(config.columns).toJS(),
-      scripts: fromJS(config.scripts).toJS()
+      scripts: _scripts
     })
   }
 
diff --git a/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx b/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx
index da2b30d..fa3d829 100644
--- a/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx
@@ -30,6 +30,14 @@
     if (setting.execute !== 'false') {
       _dataresource = setting.dataresource || ''
     }
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
     
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
diff --git a/src/templates/sharecomponent/settingcomponent/index.jsx b/src/templates/sharecomponent/settingcomponent/index.jsx
index bad5664..dfd1ac0 100644
--- a/src/templates/sharecomponent/settingcomponent/index.jsx
+++ b/src/templates/sharecomponent/settingcomponent/index.jsx
@@ -59,7 +59,8 @@
     this.setState({
       loading: true
     })
-    this.settingRef.handleConfirm().then(res => {
+    this.settingRef.handleConfirm().then(setting => {
+      let res = this.resetSetting(setting)
       this.setState({
         visible: false,
         loading: false
@@ -83,7 +84,8 @@
     const { menu } = this.state
 
     this.settingRef.handleConfirm('func').then(setting => {
-      let _config = {...config, setting: setting}
+      let res = this.resetSetting(setting)
+      let _config = {...config, setting: res}
       let newLText = Utils.formatOptions(FuncUtils.getTableFunc(setting, menu, _config)) // 鍒涘缓瀛樺偍杩囩▼sql
       let DelText = Utils.formatOptions(FuncUtils.dropfunc(setting.innerFunc))          // 鍒犻櫎瀛樺偍杩囩▼sql
 
@@ -103,7 +105,8 @@
     const { menu } = this.state
 
     this.settingRef.handleConfirm('interface').then(setting => {
-      let _config = {...config, setting: setting}
+      let res = this.resetSetting(setting)
+      let _config = {...config, setting: res}
       let _menu = {
         type: config.Template === 'CommonTable' ? 'main' : 'subtable',
         MenuID: menu.MenuID,
@@ -115,6 +118,30 @@
     })
   }
 
+  resetSetting = (s) => {
+    let setting = fromJS(s).toJS()
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+        setting.scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        })
+        setting.preScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        })
+        setting.cbScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        })
+        if (setting.dataresource) {
+          setting.dataresource = setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        }
+      })
+    }
+
+    return setting
+  }
+
   shouldComponentUpdate (nextProps, nextState) {
     return !is(fromJS(this.state), fromJS(nextState))
   }
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/index.jsx b/src/templates/sharecomponent/settingcomponent/settingform/index.jsx
index 42d2f4e..bb46fba 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/index.jsx
+++ b/src/templates/sharecomponent/settingcomponent/settingform/index.jsx
@@ -97,6 +97,24 @@
       })
     }
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _preScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _cbScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+      })
+    }
+
     this.setState({
       setting: _setting,
       search: _search,
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx b/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
index 3bd809f..003b030 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
+++ b/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
@@ -26,6 +26,14 @@
     if (setting.default === 'false') {
       _dataresource = ''
     }
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
     
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
@@ -139,6 +147,13 @@
       `
     }
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
+
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@userName@|@fullName@|@login_city@/ig, `''`)
     // 澶栬仈鏁版嵁搴撴浛鎹�
diff --git a/src/templates/sharecomponent/treesettingcomponent/index.jsx b/src/templates/sharecomponent/treesettingcomponent/index.jsx
index 359d52f..db18c0b 100644
--- a/src/templates/sharecomponent/treesettingcomponent/index.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/index.jsx
@@ -45,6 +45,17 @@
       loading: true
     })
     this.settingRef.handleConfirm().then(res => {
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          res.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          if (res.dataresource) {
+            res.dataresource = res.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          }
+        })
+      }
       this.setState({
         visible: false,
         loading: false
diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
index 056813e..3f3d3a4 100644
--- a/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
@@ -35,6 +35,18 @@
     let _setting = fromJS(config.setting).toJS()
     let _scripts = _setting.scripts || []
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+      })
+    }
+
     this.setState({
       setting: _setting,
       scripts: _scripts
diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx
index 721c7c9..332934c 100644
--- a/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx
@@ -26,6 +26,14 @@
     if (setting.default === 'false') {
       _dataresource = ''
     }
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
     
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
diff --git a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
index 5d9f5e7..bed203c 100644
--- a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
+++ b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -127,6 +127,13 @@
           LText: this.props.initsql +  _prevCustomScript + _backCustomScript + tail
         }
 
+        if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+          window.GLOB.funcs.forEach(item => {
+            let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+            param.LText = param.LText.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+          })
+        }
+
         // 鏁版嵁鏉冮檺
         param.LText = param.LText.replace(/@\$|\$@/ig, '')
 
diff --git a/src/templates/zshare/verifycard/customform/index.jsx b/src/templates/zshare/verifycard/customform/index.jsx
index c9be94d..d203f25 100644
--- a/src/templates/zshare/verifycard/customform/index.jsx
+++ b/src/templates/zshare/verifycard/customform/index.jsx
@@ -101,6 +101,13 @@
           LText: this.props.initsql + values.sql
         }
 
+        if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+          window.GLOB.funcs.forEach(item => {
+            let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+            param.LText = param.LText.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+          })
+        }
+        
         // 鏁版嵁鏉冮檺
         param.LText = param.LText.replace(/@\$|\$@/ig, '')
 
diff --git a/src/templates/zshare/verifycard/customscript/index.jsx b/src/templates/zshare/verifycard/customscript/index.jsx
index f7f1d2e..a5a1162 100644
--- a/src/templates/zshare/verifycard/customscript/index.jsx
+++ b/src/templates/zshare/verifycard/customscript/index.jsx
@@ -139,6 +139,13 @@
           LText: this.props.initsql + _initCustomScript + _prevCustomScript + _backCustomScript + tail
         }
 
+        if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+          window.GLOB.funcs.forEach(item => {
+            let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+            param.LText = param.LText.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+          })
+        }
+
         // 鏁版嵁鏉冮檺
         param.LText = param.LText.replace(/@\$|\$@/ig, '')
         // check
diff --git a/src/templates/zshare/verifycard/index.jsx b/src/templates/zshare/verifycard/index.jsx
index 13b0889..5fbf286 100644
--- a/src/templates/zshare/verifycard/index.jsx
+++ b/src/templates/zshare/verifycard/index.jsx
@@ -556,6 +556,21 @@
     _verify.scripts = _verify.scripts || []
     _verify.cbScripts = _verify.cbScripts || []
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _verify.customverifys.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _verify.scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _verify.cbScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+      })
+    }
+
     this.setState({
       verify: _verify
     })
@@ -1336,6 +1351,21 @@
         verify.noteCode = ''
       }
 
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          verify.customverifys.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          verify.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          verify.cbScripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+        })
+      }
+
       if (msg) {
         confirm({
           content: msg + '鏈繚瀛橈紝纭畾鎻愪氦鍚楋紵',
diff --git a/src/utils/utils.js b/src/utils/utils.js
index c99abbb..891d2fd 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -1754,6 +1754,46 @@
 }
 
 /**
+ * @description 鐢熸垚鏇挎崲鍑芥暟鍒楄〃
+ */
+export function setGLOBFuncs () {
+  window.GLOB.funcs = []
+  if (!window.GLOB.WebSql && !window.GLOB.IndexDB) {
+    return
+  }
+
+  if (window.GLOB.WebSql) {
+    window.GLOB.WebSql.transaction(tx => {
+      tx.executeSql("SELECT * FROM FUNCS", [], (tx, results) => {
+        let rows = results.rows
+        if (!rows || rows.length === 0) return
+        for (let i = 0; i < rows.length; i++) {
+          window.GLOB.funcs.push({
+            func_code: rows[i].func_code,
+            key_sql: window.decodeURIComponent(window.atob(rows[i].key_sql))
+          })
+        }
+      })
+    })
+  } else {
+    let objectStore = window.GLOB.IndexDB.transaction('funcs').objectStore('funcs')
+
+    objectStore.openCursor().onsuccess = (event) => {
+      let cursor = event.target.result
+
+      if (cursor) {
+        window.GLOB.funcs.push({
+          func_code: cursor.value.func_code,
+          key_sql: window.decodeURIComponent(window.atob(cursor.value.key_sql))
+        })
+        cursor.continue()
+      }
+    }
+  }
+
+}
+
+/**
  * @description 鍒涘缓瀛樺偍杩囩▼绫�
  */
 export class FuncUtils {
diff --git a/src/views/design/index.jsx b/src/views/design/index.jsx
index 167b576..51fe335 100644
--- a/src/views/design/index.jsx
+++ b/src/views/design/index.jsx
@@ -5,6 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import Header from './header'
+import { setGLOBFuncs } from '@/utils/utils.js'
 import Sidemenu from './sidemenu'
 
 import './index.scss'
@@ -13,6 +14,10 @@
 const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
 
 class Design extends Component {
+  componentDidMount() {
+    setGLOBFuncs()
+  }
+  
   render () {
     return (
       <div className="mk-main-view">
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 1297c91..375ea08 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -8,7 +8,7 @@
 
 import Api from '@/api'
 import options from '@/store/options.js'
-import Utils from '@/utils/utils.js'
+import Utils, { setGLOBFuncs } from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
 import antdEnUS from 'antd/es/locale/en_US'
@@ -106,6 +106,7 @@
     setTimeout(() => {
       this.updateCustomComponent()
       this.getAppPictures()
+      setGLOBFuncs()
     }, 1000)
   }
 
diff --git a/src/views/mobdesign/index.jsx b/src/views/mobdesign/index.jsx
index b80811c..d44e5f9 100644
--- a/src/views/mobdesign/index.jsx
+++ b/src/views/mobdesign/index.jsx
@@ -8,7 +8,7 @@
 import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin } from 'antd'
 
 import Api from '@/api'
-import Utils from '@/utils/utils.js'
+import Utils, { setGLOBFuncs } from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
 import antdEnUS from 'antd/es/locale/en_US'
@@ -125,6 +125,7 @@
       this.updateCustomComponent()
       this.getAppPictures()
       this.getSmStemp()
+      setGLOBFuncs()
     }, 1000)
   }
 
diff --git a/src/views/pcdesign/index.jsx b/src/views/pcdesign/index.jsx
index 183c884..2ed7bdc 100644
--- a/src/views/pcdesign/index.jsx
+++ b/src/views/pcdesign/index.jsx
@@ -8,7 +8,7 @@
 import { ConfigProvider, notification, Modal, Collapse, Switch, Button, Icon, message, Spin } from 'antd'
 
 import Api from '@/api'
-import Utils from '@/utils/utils.js'
+import Utils, { setGLOBFuncs } from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
 import antdEnUS from 'antd/es/locale/en_US'
@@ -128,6 +128,7 @@
       this.updateCustomComponent()
       this.getAppPictures()
       this.getSmStemp()
+      setGLOBFuncs()
     }, 1000)
   }
 

--
Gitblit v1.8.0