king
2021-06-09 73a5124745890650d0fc91234bdbaa66d9bcbc6a
2021-06-09
39个文件已修改
1个文件已添加
1072 ■■■■ 已修改文件
src/api/cacheutils.js 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/ratioboard.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.scss 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/chartcompile/index.jsx 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/chartcompile/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/index.jsx 198 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/index.scss 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.scss 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-scatter/index.jsx 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-scatter/index.scss 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/index.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/utils.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulesource/option.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/modulesource/option.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-dashboard/index.jsx 186 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcalcomponent/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/index.jsx 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/treesettingcomponent/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/callbackcustomscript/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customform/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customscript/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 初始化失败!')
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') || ''
src/assets/mobimg/ratioboard.png
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
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>
    )
  }
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;
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
    }
  ]
}
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" />
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;
        }
      }
    }
  }
}
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>
    )
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 {
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>
    )
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 {
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>
    )
  }
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;
}
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>
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})
    }, () => {
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
    })
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')
      })
    }
    // 正则替换
    let _regoptions = []
    let _fields = []
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: '散点图', width: 24 },
  { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '富文本', width: 24 },
  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '自定义', width: 24 },
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: '散点图', width: 24 },
  { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '富文本', width: 24 },
  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '自定义', width: 24 },
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 仪表盘渲染
   */
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})
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
    })
  }
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, '')
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))
  }
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,
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, `''`)
    // 外联数据库替换
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
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
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, '')
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, '')
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, '')
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
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 + '未保存,确定提交吗?',
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 {
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">
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)
  }
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)
  }
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)
  }