From 44fa8b4f4b4c4ae93570b14b9835b2d61552cb95 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期四, 14 十月 2021 15:09:48 +0800
Subject: [PATCH] 2021-10-14

---
 src/index.js                                                       |    1 
 src/components/header/index.jsx                                    |   15 
 src/templates/sharecomponent/fieldscomponent/editcard/index.jsx    |    2 
 src/menu/components/chart/chart-custom/chartcompile/formconfig.jsx |  500 +++++++++++
 src/menu/components/chart/chart-custom/index.jsx                   | 1324 +++++++++++++++++++++++++++++
 src/menu/components/share/actioncomponent/actionform/index.jsx     |   12 
 src/menu/components/chart/chart-custom/chartcompile/index.scss     |   44 
 src/assets/mobimg/chart.png                                        |    0 
 src/menu/components/chart/chart-custom/chartcompile/index.jsx      |  696 +++++++++++++++
 src/views/design/header/versions/index.jsx                         |    2 
 src/menu/components/chart/chart-custom/index.scss                  |   71 +
 src/menu/modulesource/option.jsx                                   |    2 
 src/views/login/index.jsx                                          |    4 
 13 files changed, 2,665 insertions(+), 8 deletions(-)

diff --git a/src/assets/mobimg/chart.png b/src/assets/mobimg/chart.png
new file mode 100644
index 0000000..dc16666
--- /dev/null
+++ b/src/assets/mobimg/chart.png
Binary files differ
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index ac930a4..fc866fa 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -38,6 +38,7 @@
     confirmLoading: false,
     userName: sessionStorage.getItem('User_Name'),
     logourl: window.GLOB.mainlogo,
+    appVersion: window.GLOB.appVersion,
     loginVisible: false,
     loginLoading: false,
     avatar: Utils.getrealurl(sessionStorage.getItem('avatar')),
@@ -621,7 +622,7 @@
 
   verup = () => {
     confirm({
-      title: '鐗堟湰鍗囩骇',
+      title: '椤甸潰鏇存柊',
       content: '閲嶆柊鍔犺浇搴旂敤淇℃伅',
       onOk() {
         return new Promise(resolve => {
@@ -649,10 +650,15 @@
     })
   }
 
+  about = () => {
+    Modal.success({
+      title: '绯荤粺鐗堟湰v' + this.state.appVersion
+    })
+  }
 
   render () {
     const { mainMenu, collapse } = this.props
-    const { thdMenuList, searchkey, debug, menulist, navBar, menuType } = this.state
+    const { thdMenuList, searchkey, debug, menulist, navBar, menuType, appVersion } = this.state
 
     const menu = (
       <Menu className="header-dropdown">
@@ -668,8 +674,11 @@
         </Menu.SubMenu> : null}
         <Menu.Item key="doc" onClick={this.gotoDoc}>{this.state.dict['main.doc']}</Menu.Item>
         <Menu.Item key="verup" onClick={this.verup}>
-          鐗堟湰鍗囩骇
+          椤甸潰鏇存柊
         </Menu.Item>
+        {appVersion ? <Menu.Item key="version" onClick={this.about}>
+          鍏充簬
+        </Menu.Item> : null}
         <Menu.Item key="logout" onClick={this.logout}>{this.state.dict['main.logout']}</Menu.Item>
       </Menu>
     )
diff --git a/src/index.js b/src/index.js
index 3f455ef..13aafa7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -153,6 +153,7 @@
         GLOB.style = _systemMsg.style
         GLOB.showline = _systemMsg.showline || ''
         GLOB.navBar = _systemMsg.navBar || ''
+        GLOB.appVersion = _systemMsg.app_version || ''
 
         if (GLOB.favicon) {
           let link = document.querySelector("link[rel*='icon']") || document.createElement('link')
diff --git a/src/menu/components/chart/chart-custom/chartcompile/formconfig.jsx b/src/menu/components/chart/chart-custom/chartcompile/formconfig.jsx
new file mode 100644
index 0000000..ac311aa
--- /dev/null
+++ b/src/menu/components/chart/chart-custom/chartcompile/formconfig.jsx
@@ -0,0 +1,500 @@
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+
+const Formdict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ */
+export function getBaseForm (card) {
+  let roleList = sessionStorage.getItem('sysRoles')
+  if (roleList) {
+    try {
+      roleList = JSON.parse(roleList)
+    } catch (e) {
+      roleList = []
+    }
+  } else {
+    roleList = []
+  }
+
+  return [
+    {
+      type: 'text',
+      key: 'title',
+      label: '鏍囬',
+      initVal: card.title,
+      required: false
+    },
+    {
+      type: 'text',
+      key: 'name',
+      label: '缁勪欢鍚嶇О',
+      initVal: card.name,
+      tooltip: '鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�',
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'width',
+      label: '瀹藉害',
+      initVal: card.width,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      min: 1,
+      max: 24,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'height',
+      label: '楂樺害',
+      initVal: card.height,
+      min: 100,
+      max: 1000,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'select',
+      key: 'blacklist',
+      label: '榛戝悕鍗�',
+      initVal: card.blacklist || [],
+      multi: true,
+      required: false,
+      options: roleList
+    },
+    // {
+    //   type: 'cascader',
+    //   key: 'linkmenu',
+    //   label: '鍏宠仈鑿滃崟',
+    //   initVal: card.linkmenu || [],
+    //   tooltip: '鍦ㄤ娇鐢ㄦ煴褰㈠浘涓旀湭鍚敤鑷畾涔夎缃椂鏈夋晥銆�',
+    //   required: false,
+    //   forbid: appType === 'pc' || appType === 'mob',
+    //   options: menulist
+    // },
+    // {
+    //   type: 'select',
+    //   key: 'linkmenu',
+    //   label: '鍏宠仈鑿滃崟',
+    //   initVal: card.linkmenu || '',
+    //   tooltip: '鍙屽嚮鏌辩姸鍥撅紝浼氭墦寮�鍏宠仈鐨勮彍鍗曘��',
+    //   required: false,
+    //   forbid: appType !== 'pc',
+    //   options: menulist
+    // },
+    // {
+    //   type: 'radio',
+    //   key: 'open',
+    //   label: '鎵撳紑鏂瑰紡',
+    //   initVal: card.open || 'blank',
+    //   required: false,
+    //   forbid: appType !== 'pc',
+    //   options: [
+    //     { value: 'blank', text: '鏂扮獥鍙�' },
+    //     { value: 'self', text: '褰撳墠绐楀彛' }
+    //   ]
+    // }
+  ]
+}
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ * @param {Array}  columns    // 鏄剧ず鍒�
+ */
+export function getOptionForm (card, columns) {
+  let appType = sessionStorage.getItem('appType')
+  let shapes = []
+
+  if (card.chartType === 'line') {
+    shapes = [
+      { field: 'smooth', label: 'smooth' },
+      { field: 'line', label: 'line' },
+      { field: 'dot', label: 'dot' },
+      { field: 'dash', label: 'dash' },
+      { field: 'hv', label: 'hv' },
+      { field: 'vh', label: 'vh' },
+      { field: 'hvh', label: 'hvh' },
+      { field: 'vhv', label: 'vhv' }
+    ]
+  } else if (card.chartType === 'bar') {
+    shapes = [
+      { field: 'rect', label: 'rect' },
+      { field: 'hollow-rect', label: 'hollow-rect' },
+      { field: 'line', label: 'line' },
+      { field: 'tick', label: 'tick' },
+      { field: 'funnel', label: 'funnel' },
+      { field: 'pyramid', label: 'pyramid' }
+    ]
+  }
+
+  let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
+  let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
+
+  let labelOptions = [{
+    value: 'false',
+    text: '闅愯棌'
+  }, {
+    value: 'true',
+    text: '鏄剧ず'
+  }]
+
+  if (card.chartType === 'bar') {
+    labelOptions[1].text = '澶栭儴'
+    labelOptions.push(...[{
+      value: 'top',
+      text: '椤堕儴'
+    }, {
+      value: 'middle',
+      text: '涓棿'
+    }, {
+      value: 'bottom',
+      text: '搴曢儴'
+    }])
+  }
+
+  return [
+    {
+      type: 'radio',
+      key: 'datatype',
+      label: '鏁版嵁绫诲瀷',
+      initVal: card.datatype || 'query',
+      tooltip: '缁熻鍥捐〃閫傜敤浜庡睍绀烘暟鎹被鍨嬩负鍔ㄦ�佸�笺��',
+      required: false,
+      options: [
+        { value: 'query', text: Formdict['header.form.query'] },
+        { value: 'statistics', text: Formdict['header.form.statistics'] }
+      ]
+    }, {
+      type: 'select',
+      key: 'Xaxis',
+      label: 'X-杞�',
+      initVal: card.Xaxis || '',
+      required: true,
+      options: xfields
+    }, {
+      type: 'select',
+      key: 'InfoType',
+      label: '绫诲瀷',
+      initVal: card.InfoType || '',
+      hidden: card.datatype !== 'statistics',
+      required: true,
+      options: xfields
+    }, {
+      type: 'select',
+      key: 'InfoValue',
+      label: '鍊�',
+      initVal: card.InfoValue || '',
+      hidden: card.datatype !== 'statistics',
+      required: true,
+      options: yfields
+    }, {
+      type: 'select',
+      key: 'legend',
+      label: '鍥句緥浣嶇疆',
+      initVal: card.legend || 'bottom',
+      required: false,
+      options: [
+        { field: 'bottom', label: '涓�' },
+        { field: 'bottom-left', label: '涓嬪乏' },
+        { field: 'bottom-right', label: '涓嬪彸' },
+        { field: 'top', label: '涓�' },
+        { field: 'top-left', label: '涓婂乏' },
+        { field: 'top-right', label: '涓婂彸' },
+        { field: 'right', label: '鍙�' },
+        { field: 'right-top', label: '鍙充笂' },
+        { field: 'right-bottom', label: '鍙充笅' },
+        { field: 'left', label: '宸�' },
+        { field: 'left-top', label: '宸︿笂' },
+        { field: 'left-bottom', label: '宸︿笅' },
+        { field: 'hidden', label: '闅愯棌' }
+      ]
+    }, {
+      type: 'select',
+      key: 'Yaxis',
+      label: 'Y-杞�',
+      initVal: card.Yaxis || [],
+      multi: true, // 澶氶��
+      hidden: card.datatype === 'statistics',
+      required: true,
+      options: yfields
+    }, {
+      type: 'select',
+      key: 'shape',
+      label: '褰㈢姸',
+      initVal: card.shape || (shapes[0] && shapes[0].field),
+      required: false,
+      options: shapes
+    }, {
+      type: 'radio',
+      key: 'tooltip',
+      label: '鎮诞鎻愮ず',
+      initVal: card.tooltip || 'true',
+      required: false,
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    }, {
+      type: 'radio',
+      key: 'point',
+      label: '鐐瑰浘',
+      initVal: card.point || 'false',
+      required: false,
+      forbid: !['line'].includes(card.chartType),
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    }, {
+      type: 'radio',
+      key: 'transpose',
+      label: '鍙樻崲',
+      initVal: card.transpose || 'false',
+      tooltip: '妯旱鍧愭爣杞翠氦鎹�',
+      required: false,
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    }, {
+      type: 'radio',
+      key: 'show',
+      label: '鏍煎紡鍖�',
+      initVal: card.show || 'value',
+      required: false,
+      options: [{
+        value: 'value',
+        text: '鏃�'
+      }, {
+        value: 'percent',
+        text: '鐧惧垎姣�'
+      }]
+    }, {
+      type: labelOptions.length > 20 ? 'select' : 'radio',
+      key: 'label',
+      label: '鏍囩',
+      initVal: card.label || 'false',
+      required: false,
+      options: labelOptions
+    }, {
+      type: 'radio',
+      key: 'labelColor',
+      label: '鏍囩棰滆壊',
+      initVal: card.labelColor || 'system',
+      tooltip: '浣跨敤绯荤粺鑹叉椂锛屼娇鐢ㄨ壊绯婚�夐」璁剧疆鐨勭郴缁熼鑹诧紝浣跨敤鑷畾涔変负棰滆壊璁剧疆涓畾涔夌殑鍥惧舰棰滆壊銆�',
+      required: false,
+      options: [{
+        value: 'system',
+        text: '绯荤粺'
+      }, {
+        value: 'custom',
+        text: '鑷畾涔�'
+      }]
+    // }, {
+    //   type: 'radio',
+    //   key: 'offset',
+    //   label: '鏍囨敞浣嶇疆',
+    //   initVal: card.offset || 'outer',
+    //   required: false,
+    //   options: [{
+    //     value: 'outer',
+    //     text: '澶栭儴'
+    //   }, {
+    //     value: 'inner',
+    //     text: '鍐呴儴'
+    //   }],
+    //   forbid: card.chartType !== 'bar'
+    }, {
+      type: 'radio',
+      key: 'adjust',
+      label: '澶氭煴鎺掑垪',
+      initVal: card.adjust || 'dodge',
+      required: false,
+      forbid: !['bar'].includes(card.chartType),
+      options: [{
+        value: 'dodge',
+        text: '鍒嗙粍'
+      }, {
+        value: 'stack',
+        text: '鍫嗗彔'
+      }]
+    }, {
+      type: 'radio',
+      key: 'area',
+      label: '闈㈢Н鍥�',
+      initVal: card.area || 'false',
+      // tooltip: '浠呭湪褰㈢姸涓簊mooth鏃舵湁鏁堛��',
+      required: false,
+      forbid: ['bar'].includes(card.chartType),
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '涓嶆樉绀�'
+      }]
+    }, {
+      type: 'radio',
+      key: 'repeat',
+      label: '閲嶅鏁版嵁',
+      initVal: card.repeat || 'unrepeat',
+      required: false,
+      options: [{
+        value: 'unrepeat',
+        text: '鍘婚噸'
+      }, {
+        value: 'average',
+        text: '骞冲潎'
+      }, {
+        value: 'cumsum',
+        text: '绱姞'
+      }]
+    }, {
+      type: 'radio',
+      key: 'coordinate',
+      label: '鍧愭爣',
+      initVal: card.coordinate || 'angle',
+      required: false,
+      options: [{
+        value: 'angle',
+        text: '浜岀淮鍧愭爣'
+      }, {
+        value: 'polar',
+        text: '鏋佸潗鏍�'
+      }]
+    }, {
+      type: 'radio',
+      key: 'grid',
+      label: '缃戞牸绾�',
+      initVal: card.grid || 'show',
+      required: false,
+      options: [{
+        value: 'show',
+        text: '鏄剧ず'
+      }, {
+        value: 'hidden',
+        text: '闅愯棌'
+      }]
+    }, {
+      type: 'radio',
+      key: 'y_line',
+      label: 'y杞磋竟绾�',
+      initVal: card.y_line || 'hidden',
+      tooltip: '鍥惧舰宸︿晶鎴栧彸渚х殑杈圭嚎銆�',
+      required: false,
+      options: [{
+        value: 'show',
+        text: '鏄剧ず'
+      }, {
+        value: 'hidden',
+        text: '闅愯棌'
+      }]
+    }, {
+      type: 'number',
+      key: 'barSize',
+      label: '鏌卞舰瀹藉害',
+      tooltip: '绌哄�兼椂锛屽搴﹁嚜閫傚簲銆�',
+      min: 5,
+      max: 100,
+      decimal: 0,
+      initVal: card.barSize,
+      forbid: !['bar'].includes(card.chartType),
+      required: false
+    }, {
+      type: 'number',
+      key: 'barRadius',
+      label: '鏌卞舰鍦嗚',
+      tooltip: '鏌卞舰鍥句笂绔渾瑙掋��',
+      min: 0,
+      max: 200,
+      decimal: 0,
+      initVal: card.barRadius || 0,
+      forbid: !['bar'].includes(card.chartType),
+      required: false
+    }, {
+      type: 'number',
+      key: 'min',
+      label: '鏈�灏忓��',
+      tooltip: 'y杞存渶灏忓�硷紝涓虹┖鏃惰嚜閫傚簲銆�',
+      initVal: card.min,
+      required: false
+    }, {
+      type: 'number',
+      key: 'max',
+      label: '鏈�澶у��',
+      tooltip: 'y杞存渶澶у�硷紝涓虹┖鏃惰嚜閫傚簲銆�',
+      initVal: card.max,
+      required: false
+    }, {
+      type: 'color',
+      key: 'color',
+      label: '鑹茬郴',
+      initVal: card.color || 'rgba(0, 0, 0, 0.65)',
+      tooltip: '鍧愭爣杞存彁绀烘枃瀛楀強绀轰緥鐨勯鑹层��',
+      required: false
+    }, {
+      type: 'color',
+      key: 'lineColor',
+      label: '杞寸嚎棰滆壊',
+      initVal: card.lineColor,
+      tooltip: '鍧愭爣杞寸嚎鐨勯鑹诧紝鍖呮嫭x杞淬�亂杞村強缃戞牸绾裤��',
+      allowClear: true,
+      required: false
+    }, {
+      type: 'color',
+      key: 'selectColor',
+      label: '閫変腑棰滆壊',
+      initVal: card.selectColor || '',
+      tooltip: '閫変腑鏌卞舰鍥剧殑棰滆壊锛屽湪浜や簰鏁堟灉銆婂厓绱犻�変腑锛堝閫夛級銆嬪拰銆婂厓绱犻�変腑锛堝崟閫夛級銆嬩腑鏈夋晥锛岃嚜瀹氫箟璁剧疆涓棤鏁堛��',
+      forbid: !['bar'].includes(card.chartType),
+      allowClear: true,
+      required: false
+    }, {
+      type: 'number',
+      key: 'rotate',
+      label: '鏃嬭浆',
+      tooltip: '鍧愭爣杞存爣娉ㄦ枃鏈殑鏃嬭浆瑙掑害銆�',
+      min: 0,
+      max: 360,
+      decimal: 0,
+      initVal: card.rotate,
+      forbid: appType !== 'mob',
+      required: false
+    }, {
+      type: 'select',
+      key: 'interaction',
+      label: '浜や簰鏁堟灉',
+      initVal: card.interaction || [],
+      multi: true,
+      required: false,
+      forbid: appType === 'mob',
+      options: [
+        { value: 'element-active', label: '鍏冪礌鑱氱劍' },
+        { value: 'element-selected', label: '鍏冪礌閫変腑锛堝閫夛級' },
+        { value: 'element-single-selected', label: '鍏冪礌閫変腑锛堝崟閫夛級' },
+        { value: 'active-region', label: '鑳屾櫙妗�' },
+        { value: 'view-zoom', label: '瑙嗗浘缂╂斁' },
+        { value: 'element-highlight', label: '鍏冪礌楂樹寒' },
+        { value: 'element-highlight-by-color', label: '鍚岃壊鍏冪礌楂樹寒' },
+        { value: 'element-highlight-by-x', label: '鍚孹杞村厓绱犻珮浜�' },
+        { value: 'legend-filter', label: '鍥句緥杩囨护' },
+        { value: 'legend-active', label: '鍥句緥鑱氱劍' },
+        { value: 'legend-highlight', label: '鍥句緥楂樹寒' },
+        { value: 'brush', label: '閫夋杩囨护' },
+      ]
+    }
+  ]
+}
diff --git a/src/menu/components/chart/chart-custom/chartcompile/index.jsx b/src/menu/components/chart/chart-custom/chartcompile/index.jsx
new file mode 100644
index 0000000..3f31823
--- /dev/null
+++ b/src/menu/components/chart/chart-custom/chartcompile/index.jsx
@@ -0,0 +1,696 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal, Form, Row, Col, Select, Icon, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import { chartColors } from '@/utils/option.js'
+import { getBaseForm, getOptionForm } from './formconfig'
+import asyncComponent from '@/utils/asyncComponent'
+import ColorSketch from '@/mob/colorsketch'
+import './index.scss'
+
+const { TabPane } = Tabs
+const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
+const NormalForm = asyncComponent(() => import('@/menu/components/share/normalform'))
+
+class LineChartDrawerForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    plot: PropTypes.object,
+    config: PropTypes.object,
+    plotchange: PropTypes.func
+  }
+
+  state = {
+    view: 'normal',
+    ramp: 'false',
+    visible: false,
+    datatype: '',
+    plot: null,
+    formlist: null,
+    baseFormlist: null,
+    fieldName: null,
+    colorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'label',
+        editable: false,
+        width: '40%'
+      },
+      {
+        title: '棰滆壊',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '40%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
+    rampColorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'label',
+        editable: false,
+        width: '20%'
+      },
+      {
+        title: '棰滆壊1',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+      {
+        title: '棰滆壊2',
+        dataIndex: 'color1',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
+    statColorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'type',
+        inputType: 'input',
+        editable: true,
+        width: '40%'
+      },
+      {
+        title: '棰滆壊',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '40%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
+    rampStatColorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'type',
+        inputType: 'input',
+        editable: true,
+        width: '20%'
+      },
+      {
+        title: '棰滆壊1',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+      {
+        title: '棰滆壊2',
+        dataIndex: 'color1',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
+    cusColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'name',
+        editable: false,
+        width: '14%'
+      },
+      {
+        title: '褰㈢姸',
+        dataIndex: 'shape',
+        inputType: 'cascader',
+        editable: true,
+        width: '12%',
+        render: (text, record) => {
+          return text.join(' / ').replace('line', '鎶樼嚎').replace('bar', '鏌卞舰')
+        },
+        options: [
+          {
+            value: 'line',
+            label: '鎶樼嚎',
+            children: [
+              { value: 'smooth', label: 'smooth' },
+              { value: 'line', label: 'line' },
+              { value: 'dot', label: 'dot' },
+              { value: 'dash', label: 'dash' },
+              { value: 'hv', label: 'hv' },
+              { value: 'vh', label: 'vh' },
+              { value: 'hvh', label: 'hvh' },
+              { value: 'vhv', label: 'vhv' }
+            ]
+          },
+          {
+            value: 'bar',
+            label: '鏌卞舰',
+            children: [
+              { value: 'rect', label: 'rect' },
+              { value: 'hollow-rect', label: 'hollow-rect' },
+              { value: 'line', label: 'line' },
+              { value: 'tick', label: 'tick' },
+              { value: 'funnel', label: 'funnel' },
+              { value: 'pyramid', label: 'pyramid' }
+            ],
+          }
+        ]
+      },
+      {
+        title: '鍧愭爣杞�',
+        dataIndex: 'axis',
+        inputType: 'select',
+        editable: true,
+        width: '12%',
+        options: [
+          { value: 'true', text: '鏄剧ず'},
+          { value: 'false', text: '闅愯棌'}
+        ],
+        render: (text, record) => {
+          let trans = {'true': '鏄剧ず', 'false': '闅愯棌'}
+          return trans[text] || '闅愯棌'
+        }
+      },
+      {
+        title: '鏍囨敞',
+        dataIndex: 'label',
+        inputType: 'select',
+        editable: true,
+        width: '12%',
+        options: [
+          { value: 'true', text: '鏄剧ず'},
+          { value: 'false', text: '闅愯棌'}
+        ],
+        render: (text, record) => {
+          let trans = {'true': '鏄剧ず', 'false': '闅愯棌'}
+          return trans[text] || '闅愯棌'
+        }
+      },
+      {
+        title: '鏍囬',
+        dataIndex: 'title',
+        inputType: 'select',
+        editable: true,
+        width: '12%',
+        options: [
+          { value: 'true', text: '鏄剧ず'},
+          { value: 'false', text: '闅愯棌'}
+        ],
+        render: (text, record) => {
+          let trans = {'true': '鏄剧ず', 'false': '闅愯棌'}
+          return trans[text] || '鏄剧ず'
+        }
+      },
+      {
+        title: '鏈�灏忓��',
+        dataIndex: 'min',
+        inputType: 'number',
+        editable: true,
+        required: false,
+        width: '12%'
+      },
+      {
+        title: '鏈�澶у��',
+        dataIndex: 'max',
+        inputType: 'number',
+        editable: true,
+        required: false,
+        width: '12%'
+      },
+    ]
+  }
+
+  showDrawer = () => {
+    const { config } = this.props
+
+    let fieldName = {}
+    config.columns.forEach(col => {
+      if (col.field) {
+        fieldName[col.field] = col.label
+      }
+    })
+
+    if (config.plot.correction) {
+      delete config.plot.correction // 鏁版嵁淇锛堝凡寮冪敤锛�
+      config.plot.barSize = 35
+    }
+
+    this.setState({
+      visible: true,
+      view: 'normal',
+      ramp: config.plot.ramp || 'false',
+      datatype: config.plot.datatype || 'query',
+      fieldName: fieldName,
+      plot: fromJS(config.plot).toJS(),
+      baseFormlist: getBaseForm(config.plot),
+      formlist: getOptionForm(config.plot, config.columns)
+    })
+  }
+
+  radioChange = (e, key) => {
+    const { formlist } = this.state
+    let val = e.target.value
+
+    if (key === 'datatype') {
+      this.setState({
+        datatype: val,
+        formlist: formlist.map(item => {
+          if (['Yaxis'].includes(item.key)) {
+            item.hidden = val === 'statistics'
+          } else if (['InfoType', 'InfoValue'].includes(item.key)) {
+            item.hidden = val !== 'statistics'
+          }
+          return item
+        })
+      })
+    }
+  }
+
+  getFields() {
+    const { formlist } = this.state
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+
+    if (!formlist) {
+      return fields
+    }
+
+    formlist.forEach((item, index) => {
+      if (item.hidden || item.forbid) return
+      
+      if (item.type === 'text') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.onSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} onPressEnter={this.onSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select mode={item.multi ? 'multiple' : ''}>
+                  {item.options.map((option, index) =>
+                    <Select.Option key={index} value={option.field || option.value}>
+                      {option.label || option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group style={{whiteSpace: 'nowrap'}} disabled={item.readonly} onChange={(e) => this.radioChange(e, item.key)}>
+                  {item.options.map(option => {
+                    return (
+                      <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                    )
+                  })}
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'color') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(
+                <ColorSketch allowClear={item.allowClear} />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  enabledChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+
+    this.setState({plot: {...plot, enabled: val}})
+  }
+
+  mutilBarChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+
+    this.setState({plot: {...plot, mutilBar: val}})
+  }
+
+  rampChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+    let colors = plot.colors || []
+
+    if (val === 'true') {
+      colors = colors.map(item => {
+        item.color1 = item.color1 || item.color
+        return item
+      })
+    }
+
+    this.setState({plot: {...plot, colors, ramp: val}, ramp: val})
+  }
+
+  rampDirectionChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+
+    this.setState({plot: {...plot, rampDirection: val}})
+  }
+
+  onSubmit = () => {
+    const { config } = this.props
+    const { plot, view } = this.state
+
+    if (view === 'normal') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _plot = {...plot, ...values}
+
+          if (values.datatype === 'statistics' || values.datatype !== plot.datatype) {
+            _plot.enabled = 'false'
+            _plot.customs = []
+          } else if (!values.Yaxis || !plot.Yaxis || !is(fromJS(values.Yaxis), fromJS(plot.Yaxis))) {
+            _plot.enabled = 'false'
+            _plot.customs = []
+            _plot.colors = null
+          }
+
+          if (values.datatype !== plot.datatype) {
+            _plot.colors = null
+          }
+
+          this.setState({
+            plot: _plot,
+            visible: false
+          })
+
+          this.props.plotchange({...config, plot: _plot})
+        }
+      })
+    } else if (view === 'base') {
+      this.baseRef.handleConfirm().then(res => {
+        let _plot = {...plot, ...res}
+
+        this.setState({
+          plot: _plot,
+          visible: false
+        })
+
+        this.props.plotchange({...config, plot: _plot})
+      })
+    } else {
+      this.setState({
+        visible: false
+      })
+      this.props.plotchange({...config, plot})
+    }
+  }
+
+  changeTab = (tab) => {
+    const { config } = this.props
+    const { plot, view } = this.state
+
+    if (view === 'normal') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _plot = {...plot, ...values}
+
+          if (values.datatype === 'statistics' || values.datatype !== plot.datatype) {
+            _plot.enabled = 'false'
+            _plot.customs = []
+          } else if (!values.Yaxis || !plot.Yaxis || !is(fromJS(values.Yaxis), fromJS(plot.Yaxis))) {
+            _plot.enabled = 'false'
+            _plot.customs = []
+            _plot.colors = null
+          }
+
+          let labels = {}
+          config.columns.forEach(col => {
+            labels[col.field] = col.label
+          })
+
+          if (values.datatype !== 'statistics' && (!_plot.customs || _plot.customs.length === 0)) {
+            _plot.customs = _plot.Yaxis.map((item, i) => {
+              return {
+                uuid: Utils.getuuid(),
+                type: item,
+                name: labels[item] || item,
+                axis: i === 0 ? 'true' : 'false',
+                label: 'false',
+                title: 'true',
+                shape: _plot.chartType === 'bar' && i === 0 ? ['bar', 'rect'] : ['line', 'smooth']
+              }
+            })
+          }
+          if (values.datatype !== plot.datatype || !_plot.colors) {
+            _plot.colors = []
+            if (_plot.datatype === 'query') {
+              let limit = chartColors.length
+
+              _plot.colors = _plot.Yaxis.map((item, i) => {
+                return {
+                  uuid: Utils.getuuid(),
+                  type: item,
+                  label: labels[item] || item,
+                  color: chartColors[i % limit],
+                  color1: chartColors[i % limit]
+                }
+              })
+            }
+          }
+
+          this.setState({
+            datatype: _plot.datatype,
+            plot: _plot,
+            view: tab
+          })
+        }
+      })
+    } else if (view === 'base') {
+      this.baseRef.handleConfirm().then(res => {
+        this.setState({
+          plot: {...plot, ...res},
+          view: tab
+        })
+      })
+    } else {
+      this.setState({
+        view: tab
+      })
+    }
+  }
+
+  addColor = () => {
+    let plot = fromJS(this.state.plot).toJS()
+    plot.colors = plot.colors || []
+
+    plot.colors.push({
+      uuid: Utils.getuuid(),
+      type: `鎸囨爣${plot.colors.length}`,
+      color: 'rgb(91, 143, 249)',
+      color1: 'rgb(91, 143, 249)'
+    })
+
+    this.setState({plot})
+  }
+
+  changeColor = (colors) => {
+    const { plot } = this.state
+
+    this.setState({plot: {...plot, colors}})
+  }
+
+  changeCustom = (customs) => {
+    const { plot } = this.state
+
+    this.setState({plot: {...plot, customs}})
+  }
+
+  render() {
+    const { view, visible, datatype, plot, ramp, colorColumns, rampColorColumns, statColorColumns, rampStatColorColumns, cusColumns, baseFormlist } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <div className="line-chart-drawer-form">
+        <Icon type="edit" title="缂栬緫" onClick={this.showDrawer} />
+        <Modal
+          wrapClassName="popview-modal menu-chart-edit-modal"
+          title="鍥捐〃缂栬緫"
+          visible={visible}
+          width={950}
+          maskClosable={false}
+          onOk={this.onSubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <Tabs activeKey={view} className="menu-chart-edit-box" onChange={this.changeTab}>
+            <TabPane tab="缁勪欢璁剧疆" key="base">
+              <NormalForm dict={this.props.dict} formlist={baseFormlist} inputSubmit={this.onSubmit} wrappedComponentRef={(inst) => this.baseRef = inst}/>
+            </TabPane>
+            <TabPane tab="鍥捐〃璁剧疆" key="normal">
+              <Form {...formItemLayout}>
+                <Row gutter={16}>{this.getFields()}</Row>
+              </Form>
+            </TabPane>
+            {plot ? <TabPane tab="棰滆壊璁剧疆" key="color">
+              <div>
+                <Col span={8} style={{height: '40px', top: '-5px', zIndex: 1}}>
+                  <Form {...formItemLayout}>
+                    <Form.Item label="娓愬彉鑹�" style={{marginBottom: 10}}>
+                      <Radio.Group value={plot.ramp || 'false'} onChange={this.rampChange}>
+                        <Radio value="false">涓嶄娇鐢�</Radio>
+                        <Radio value="true">浣跨敤</Radio>
+                      </Radio.Group>
+                    </Form.Item>
+                  </Form>
+                </Col>
+                {plot.chartType === 'line' ? <Col span={8} style={{height: '40px', top: '-5px', zIndex: 1}}>
+                  <Form {...formItemLayout}>
+                    <Form.Item label="娓愬彉鏂瑰悜" style={{marginBottom: 10}}>
+                      <Radio.Group value={plot.rampDirection || 'horizontal'} onChange={this.rampDirectionChange}>
+                        <Radio value="horizontal">姘村钩</Radio>
+                        <Radio value="vertical">鍨傜洿</Radio>
+                      </Radio.Group>
+                    </Form.Item>
+                  </Form>
+                </Col> : null}
+                {datatype === 'statistics' ? <Button className="color-add mk-green" onClick={this.addColor}>{this.props.dict['model.add']}</Button> : null}
+                {datatype === 'statistics' ? <EditTable actions={['edit', 'move', 'del']} data={plot.colors || []} columns={ramp ==='true' ? rampStatColorColumns : statColorColumns} onChange={this.changeColor}/> : null}
+                {datatype !== 'statistics' ? <EditTable actions={['edit']} data={plot.colors || []} columns={ramp ==='true' ? rampColorColumns : colorColumns} onChange={this.changeColor}/> : null}
+              </div>
+            </TabPane> : null}
+            {plot ? <TabPane tab="鑷畾涔夎缃�" disabled={datatype === 'statistics'} key="custom">
+              <Col span={12}>
+                <Form {...formItemLayout}>
+                  <Form.Item label="鏄惁鍚敤" style={{marginBottom: 10}}>
+                    <Radio.Group value={plot.enabled || 'false'} onChange={this.enabledChange}>
+                      <Radio value="true">鏄�</Radio>
+                      <Radio value="false">鍚�</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Form>
+              </Col>
+              <Col span={12}>
+                <Form {...formItemLayout}>
+                  <Form.Item label="澶氭煴鎺掑垪" style={{marginBottom: 10}}>
+                    <Radio.Group value={plot.mutilBar || 'dodge'} onChange={this.mutilBarChange}>
+                      <Radio value="dodge">鍒嗙粍</Radio>
+                      <Radio value="stack">鍫嗗彔</Radio>
+                      <Radio value="overlap">閲嶅彔</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Form>
+              </Col>
+              <Col style={{fontSize: '12px', color: '#757575', paddingLeft: '10px'}} span={24}>娉細浣跨敤鑷畾涔夎缃椂锛屾樉绀虹殑鍧愭爣杞寸涓�涓湪宸︿晶锛岀浜屼釜鍦ㄥ彸渚э紝澶氫綑鐨勪笉鐢熸晥銆�</Col>
+              <EditTable actions={['edit', 'move']} data={plot.customs || []} columns={cusColumns} onChange={this.changeCustom}/>
+            </TabPane> : null}
+          </Tabs>
+        </Modal>
+      </div>
+    );
+  }
+}
+
+export default Form.create()(LineChartDrawerForm)
\ No newline at end of file
diff --git a/src/menu/components/chart/chart-custom/chartcompile/index.scss b/src/menu/components/chart/chart-custom/chartcompile/index.scss
new file mode 100644
index 0000000..244c6aa
--- /dev/null
+++ b/src/menu/components/chart/chart-custom/chartcompile/index.scss
@@ -0,0 +1,44 @@
+.line-chart-drawer-form {
+  display: inline-block;
+  > .anticon-edit {
+    color: #1890ff;
+  }
+}
+.menu-chart-edit-modal {
+  .ant-modal {
+    top: 50px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      min-height: 50vh;
+      padding-top: 10px;
+      .menu-chart-edit-box {
+        .anticon-question-circle {
+          color: #c49f47;
+          position: relative;
+          left: -3px;
+        }
+        .ant-input-number {
+          width: 100%;
+        }
+        .ant-radio-wrapper {
+          margin-right: 5px;
+        }
+        .ant-tabs-nav-wrap {
+          text-align: center;
+        }
+        .color-sketch-block {
+          position: relative;
+          top: 5px;
+          width: 240px;
+        }
+        .color-add {
+          float: right;
+          margin-bottom: 10px;
+          position: relative;
+          z-index: 1;
+        }
+      }
+    }
+  }
+}
+
diff --git a/src/menu/components/chart/chart-custom/index.jsx b/src/menu/components/chart/chart-custom/index.jsx
new file mode 100644
index 0000000..467f90b
--- /dev/null
+++ b/src/menu/components/chart/chart-custom/index.jsx
@@ -0,0 +1,1324 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+import { Chart } from '@antv/g2'
+import DataSet from '@antv/data-set'
+
+import MKEmitter from '@/utils/events.js'
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import Utils from '@/utils/utils.js'
+import { chartColors } from '@/utils/option.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+
+class ChartCustom extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    updateConfig: PropTypes.func,
+    deletecomponent: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    appType: sessionStorage.getItem('appType'),
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _plot = {
+        chartType: card.type, // 鍥捐〃绫诲瀷
+        enabled: 'false',     // 鏄惁浣跨敤鑷畾涔夎缃�
+        datatype: 'query',    // 鏁版嵁绫诲瀷鏌ヨ鎴栫粺璁�
+        customs: [],
+        width: card.width || 24,
+        height: 400,
+        barSize: 35,
+        color: 'rgba(0, 0, 0, 0.65)',
+        name: card.name
+      }
+
+
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: 'array',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,   // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false, // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: card.dataName || '',
+        width: _plot.width,
+        name: _plot.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        style: {
+          borderWidth: '1px', borderColor: 'rgb(217, 217, 217)',
+          marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+        },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        scripts: [],
+        search: [],
+        action: [],
+        plot: _plot,
+        btnlog: [],
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.plot = config.plot
+        _card.plot.name = card.name
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+
+        _card.action = config.action.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+        _card.search = config.search.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+    MKEmitter.addListener('tabsChange', this.handleTabsChange)
+    setTimeout(() => {
+      this.viewrender()
+    }, 1000)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+    MKEmitter.removeListener('tabsChange', this.handleTabsChange)
+  }
+
+  handleTabsChange = (parentId) => {
+    const { card } = this.state
+
+    if (parentId === card.parentId) {
+      let _element = document.getElementById(card.uuid + 'canvas')
+      if (_element) {
+        _element.innerHTML = ''
+      }
+
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(this.viewrender, 100)
+    }
+  }
+
+  getdata = (X_axis, Y_axis) => {
+    let data = []
+    let xdata = ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩']
+    let point = 7
+
+    for (let i = 0; i < point; i++) {
+      let item = {}
+
+      item[X_axis] = xdata[i]
+
+      if (typeof(Y_axis) === 'string') {
+        item[Y_axis] = Math.floor(Math.random() * 5 * (i + 1)) + i
+      } else {
+        Y_axis.forEach(y => {
+          item[y] = Math.floor(Math.random() * 5 * (i + 1)) + i
+        })
+      }
+
+      data.push(item)
+    }
+
+    return data
+  }
+
+  viewrender = () => {
+    const { card } = this.state
+
+    if (card.plot.chartType === 'line') {
+      this.linerender()
+    } else if (card.plot.chartType === 'bar') {
+      this.barrender()
+    }
+  }
+
+  /**
+   * @description 鎶樼嚎鍥�
+   */
+  linerender = () => {
+    const { card } = this.state
+    const 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']
+
+    let data = this.getdata(X_axis, Y_axis)
+
+    if (plot.enabled !== 'true') {
+      const ds = new DataSet()
+      const dv = ds.createView().source(data)
+      let transfield = {}
+      card.columns.forEach(col => {
+        if (col.field) {
+          transfield[col.field] = col.label
+        }
+      })
+
+      dv.transform({
+        type: 'fold',
+        fields: [...Y_axis],
+        key: 'key',
+        value: 'value'
+      })
+
+      if (plot.Xaxis) {
+        dv.transform({
+          type: 'map',
+          callback(row) {
+            row.key = transfield[row.key] || row.key
+            return row
+          },
+        })
+      }
+
+      const chart = new Chart({
+        container: card.uuid + 'canvas',
+        autoFit: true,
+        height: this.wrap.offsetHeight - 25
+      })
+  
+      chart.data(dv.rows)
+
+      // chart.axis(X_axis, { label: { style: { fill: color } }, tickLine: {style: { stroke: color }}, line: { style: { stroke: color } } })
+      // chart.axis('value', { grid: { line: { style: { stroke: color } }}, label: { style: { fill: color } } })
+
+      let xc = {label: { style: { fill: color } }}
+      let yc = {label: { style: { fill: color } }}
+      if (plot.grid === 'hidden') {
+        yc.grid = null
+      }
+      if (plot.y_line === 'show') {
+        yc.line = {style: { stroke: '#D1D2CE' }}
+      }
+      if (plot.lineColor) {
+        xc.tickLine = {style: { stroke: plot.lineColor }}
+        xc.line = { style: { stroke: plot.lineColor } }
+        if (yc.grid !== null) {
+          yc.grid = { line: { style: { stroke: plot.lineColor } }}
+        }
+        if (yc.line) {
+          yc.line = { style: { stroke: plot.lineColor } }
+        }
+      }
+      chart.axis(X_axis, xc)
+      chart.axis('value', yc)
+  
+      if (plot.coordinate !== 'polar') {
+        chart.scale(X_axis, {
+          range: [0, 1]
+        })
+      }
+      chart.scale('value', {
+        nice: true,
+        range: [0, 0.9]
+      })
+  
+      if (!plot.legend || plot.legend === 'hidden') {
+        chart.legend(false)
+      } else {
+        chart.legend({
+          position: plot.legend,
+          itemName: { style: { fill: color } }
+        })
+      }
+  
+      if (plot.tooltip !== 'true') {
+        chart.tooltip(false)
+      } else {
+        chart.tooltip({
+          shared: true
+        })
+      }
+  
+      if (plot.transpose === 'true') {
+        chart.coordinate().transpose()
+      }
+  
+      if (plot.coordinate === 'polar') {
+        chart.coordinate('polar', {
+          innerRadius: 0.1,
+          radius: 0.8
+        })
+      }
+
+      let colors = new Map()
+      let colorIndex = 0
+
+      if (plot.colors && plot.colors.length > 0) {
+        if (plot.ramp === 'true') {
+          let _s = 'l(0) '
+          if (plot.rampDirection === 'vertical') {
+            _s = 'l(90) '
+          }
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], `${_s}0:${item.color} 1:${item.color1}` )
+            }
+          })
+        } else {
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], item.color)
+            }
+          })
+        }
+      }
+  
+      let _chart = chart
+        .line()
+        .position(`${X_axis}*value`)
+        .shape(plot.shape || 'smooth')
+        .tooltip(`${X_axis}*value*key`, (name, value, type) => {
+          if (plot.show === 'percent') {
+            value = value + '%'
+          }
+          return {
+            name: type,
+            value: value
+          }
+        })
+  
+      if (plot.colors && plot.colors.length > 0) {
+        let limit = chartColors.length
+        _chart.color('key', (key) => {
+          if (colors.has(key)) {
+            if (plot.area === 'true' && plot.rampDirection === 'vertical') {
+              return colors.get(key).replace(/l\(9?0\) 0:|\s1:.*/ig, '')
+            }
+            return colors.get(key)
+          } else {
+            colorIndex++
+            return chartColors[(colorIndex - 1) % limit]
+          }
+        })
+      } else {
+        _chart.color('key')
+      }
+      if (plot.label !== 'false') {
+        _chart.label('value*key', (value, key) => {
+          if (plot.show === 'percent') {
+            value = value + '%'
+          }
+          let _color = color
+
+          if (plot.labelColor === 'custom' && colors.has(key)) {
+            _color = colors.get(key)
+          }
+          return {
+            content: value,
+            style: {
+              fill: _color
+            }
+          }
+        })
+      }
+
+      if (plot.point === 'true') {
+        chart
+          .point()
+          .position(`${X_axis}*value`)
+          .color('key')
+          .size(3)
+          .shape('circle')
+      }
+
+      if (plot.area === 'true') {
+        let area = chart.area().position(`${X_axis}*value`).tooltip(false)
+        if (plot.shape === 'smooth') {
+          area.shape('smooth')
+        }
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          area.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          area.color('key')
+        }
+      }
+
+      if (plot.interaction && plot.interaction.length) {
+        plot.interaction.forEach(t => {
+          chart.interaction(t)
+        })
+      }
+      chart.render()
+    } else {
+      this.customrender(data)
+    }
+  }
+
+  /**
+   * @description 鑷畾涔夊浘
+   */
+  customrender = (data) => {
+    let card = fromJS(this.state.card).toJS()
+    let plot = card.plot
+    let color = plot.color || 'rgba(0, 0, 0, 0.65)'
+    let fields = []
+    let legends = []
+    let transfield = {}
+    let Bar_axis = []
+
+    card.columns.forEach(col => {
+      if (col.field) {
+        transfield[col.field] = col.label
+      }
+    })
+
+    let colors = new Map()
+    let colorIndex = 0
+    let limit = chartColors.length
+
+    if (plot.colors && plot.colors.length > 0) {
+      if (plot.ramp === 'true') {
+        let bars = {}
+        plot.customs.forEach(item => {
+          if (!item.shape || !item.shape[0] || item.shape[0] === 'bar') {
+            bars[item.type] = true
+          }
+        })
+        plot.colors.forEach(item => {
+          if (!colors.has(transfield[item.type])) {
+            if (bars[item.type]) {
+              colors.set(transfield[item.type], `l(90) 0:${item.color} 1:${item.color1}` )
+            } else {
+              colors.set(transfield[item.type], `l(0) 0:${item.color} 1:${item.color1}` )
+            }
+          }
+        })
+      } else {
+        plot.colors.forEach(item => {
+          if (!colors.has(transfield[item.type])) {
+            colors.set(transfield[item.type], item.color)
+          }
+        })
+      }
+    }
+
+    let axisIndex = 0
+    let hasBar = false
+
+    plot.$paddingLeft = 30
+    plot.$paddingRight = 30
+
+    plot.customs.forEach(item => {
+      item.name = transfield[item.type] || item.type
+      item.chartType = item.shape ? (item.shape[0] || 'bar') : 'bar'
+      item.shape = item.shape ? (item.shape[1] || '') : ''
+
+      if (colors.has(item.name)) {
+        item.color = colors.get(item.name)
+      } else {
+        item.color = chartColors[colorIndex % limit]
+        colorIndex++
+      }
+
+      if (item.chartType === 'bar') {
+        Bar_axis.push(item.type)
+        hasBar = true
+      }
+
+      if (item.axis === 'true' && axisIndex < 2) {
+        if (axisIndex === 0) {
+          // item.axis = { grid: {line: { style: { stroke: color } }}, title: { style: { fill: color } }, label: {style: { fill: color }} }
+          item.axis = { label: {style: { fill: color }} }
+          if (item.title !== 'false') {
+            item.axis.title = { style: { fill: color } }
+            plot.$paddingLeft = 50
+          }
+          if (plot.grid === 'hidden') {
+            item.axis.grid = null
+          }
+          if (plot.y_line === 'show') {
+            item.axis.line = {style: { stroke: '#D1D2CE' }}
+          }
+          if (plot.lineColor) {
+            if (item.axis.grid !== null) {
+              item.axis.grid = { line: { style: { stroke: plot.lineColor } }}
+            }
+            if (item.axis.line) {
+              item.axis.line = { style: { stroke: plot.lineColor } }
+            }
+          }
+          
+          fields.unshift(item)
+        } else {
+          item.axis = { grid: null, label: {style: { fill: color }} }
+          if (item.title !== 'false') {
+            item.axis.title = { style: { fill: color } }
+            plot.$paddingRight = 60
+          }
+          if (plot.y_line === 'show') {
+            item.axis.line = {style: { stroke: '#D1D2CE' }}
+          }
+          if (plot.lineColor && item.axis.line) {
+            item.axis.line = { style: { stroke: plot.lineColor } }
+          }
+          fields.splice(1, 0, item)
+        }
+        axisIndex++
+      } else {
+        item.axis = { grid: null, title: null, label: null }
+        fields.push(item)
+      }
+      
+      legends.push({
+        value: item.name,
+        name: item.name,
+        marker: { symbol: item.chartType === 'bar' ? 'square' : 'hyphen', style: { stroke: item.color,fill: item.color, r: 5, lineWidth: 2 } }
+      })
+    })
+
+    const ds = new DataSet()
+    const dv = ds.createView().source(data)
+    dv.transform({
+      type: 'map',
+      callback(row) {
+        fields.forEach(line => {
+          row[line.name] = row[line.type]
+        })
+        return row
+      }
+    })
+
+    let padding = [10, 30, 30, 30]
+    if (plot.mutilBar === 'overlap') {
+      Bar_axis = []
+    }
+
+    if (!Bar_axis.length) {
+      padding = [10, plot.$paddingRight, 30, plot.$paddingLeft]
+    }
+
+    const chart = new Chart({
+      container: card.uuid + 'canvas',
+      autoFit: true,
+      height: this.wrap.offsetHeight - 25,
+    })
+
+    // chart.axis(plot.Xaxis, { label: { style: { fill: color } }, tickLine: {style: { stroke: color }}, line: { style: { stroke: color } } })
+
+    let xc = {label: { style: { fill: color } }}
+    if (plot.lineColor) {
+      xc.tickLine = {style: { stroke: plot.lineColor }}
+      xc.line = { style: { stroke: plot.lineColor } }
+    }
+    chart.axis(plot.Xaxis, xc)
+
+    if (!hasBar) {
+      chart.scale(plot.Xaxis, {
+        range: [0, 1]
+      })
+    }
+
+    if (!plot.legend || plot.legend === 'hidden') {
+      chart.legend(false)
+    } else {
+      chart.legend({
+        custom: true,
+        position: plot.legend,
+        items: legends,
+        itemName: { style: { fill: color } }
+      })
+    }
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        shared: true,
+      })
+    }
+
+    chart.scale({
+      nice: true
+    })
+
+    let lablecfg = {
+      position: 'top',
+      offset: 2,
+      style: {
+        fill: '#fff'
+      }
+    }
+
+    if (plot.label === 'top') {
+      lablecfg.offset = -5
+      lablecfg.style.textBaseline = 'top'
+    } else if (plot.label === 'middle') {
+      lablecfg.position = 'middle'
+      lablecfg.offset = 0
+    } else if (plot.label === 'bottom') {
+      lablecfg.position = 'bottom'
+      lablecfg.offset = 0
+    } else if (plot.label === 'true') {
+      lablecfg.style.fill = color
+    }
+    
+    if (Bar_axis.length) {
+      const view1 = chart.createView({
+        region: {
+          start: { x: 0, y: 0 },
+          end: { x: 1, y: 1 }
+        },
+        padding
+      })
+      const dst = new DataSet()
+      const dvt = dst.createView().source(data)
+  
+      dvt.transform({
+        type: 'fold',
+        fields: [...Bar_axis],
+        key: 'key',
+        value: 'value'
+      })
+  
+      dvt.transform({
+        type: 'map',
+        callback(row) {
+          row.key = transfield[row.key] || row.key
+          return row
+        },
+      })
+
+      view1.data(dvt.rows)
+      view1.scale('value', {
+        nice: true,
+        range: [0, 0.9]
+      })
+
+      let yc = {label: { style: { fill: color } }}
+      if (plot.grid === 'hidden') {
+        yc.grid = null
+      }
+      if (plot.y_line === 'show') {
+        yc.line = {style: { stroke: '#D1D2CE' }}
+      }
+      if (plot.lineColor) {
+        if (yc.grid !== null) {
+          yc.grid = { line: { style: { stroke: plot.lineColor } }}
+        }
+        if (yc.line) {
+          yc.line = { style: { stroke: plot.lineColor } }
+        }
+      }
+      view1.axis('value', yc)
+  
+      view1.legend(false)
+  
+      if (plot.mutilBar !== 'stack') {
+        let _chart = view1
+          .interval()
+          .position(`${plot.Xaxis}*value`)
+          .adjust([
+            {
+              type: 'dodge',
+              marginRatio: 0
+            }
+          ])
+          .shape(plot.shape || 'rect')
+          .tooltip(`${plot.Xaxis}*value*key`, (name, value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: key,
+              value: value
+            }
+          })
+
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      } else if (plot.mutilBar === 'stack') {
+        let _chart = view1
+          .interval()
+          .position(`${plot.Xaxis}*value`)
+          .adjust('stack')
+          .shape(plot.shape || 'rect')
+          .tooltip(`${plot.Xaxis}*value*key`, (name, value, type) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: type,
+              value: value
+            }
+          })
+  
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      }
+    }
+
+    const view2 = chart.createView({
+      region: {
+        start: { x: 0, y: 0 },
+        end: { x: 1, y: 1 }
+      },
+      padding
+    })
+
+    view2.data(dv.rows)
+
+    view2.legend(false)
+
+    fields.forEach(item => {
+      if (item.chartType === 'bar' && !Bar_axis.length) {
+        view2.axis(item.name, item.axis)
+      
+        view2.scale(item.name, {
+          nice: true,
+          range: [0, 0.9]
+        })
+
+        let _chart = view2
+          .interval()
+          .position(`${plot.Xaxis}*${item.name}`)
+          .color(item.color)
+          .shape(item.shape)
+          .tooltip(`${item.name}`, (value) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: item.name,
+              value: value
+            }
+          })
+
+        if (plot.barSize) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (item.label !== 'false') {
+          _chart.label(item.name, (value) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom') {
+              lablecfg.style.fill = item.color
+            }
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      } else if (item.chartType === 'line') {
+        if (!Bar_axis.length) {
+          view2.axis(item.name, item.axis)
+        } else {
+          view2.axis(item.name, { grid: null, title: null, label: null })
+        }
+        view2.scale(item.name, {
+          nice: true,
+          range: [0, 0.9]
+        })
+        let _chart = view2
+          .line()
+          .position(`${plot.Xaxis}*${item.name}`)
+          .color(item.color)
+          .shape(item.shape)
+          .tooltip(`${item.name}`, (value) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: item.name,
+              value: value
+            }
+          })
+
+        if (item.label !== 'false') {
+          _chart.label(item.name, (value) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            let _color = color
+
+            if (plot.labelColor === 'custom') {
+              _color = item.color
+            }
+            return {
+              content: value,
+              style: {
+                fill: _color
+              }
+            }
+          })
+        }
+
+        if (plot.point === 'true') {
+          chart
+            .point()
+            .position(`${plot.Xaxis}*${item.name}`)
+            .color(item.color)
+            .size(3)
+            .shape('circle')
+        }
+      }
+    })
+
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        if (t === 'element-active' || t === 'element-highlight') {
+          chart.interaction(t)
+        }
+      })
+    }
+
+    chart.render()
+  }
+
+  /**
+   * @description 鏌卞舰鍥�
+   */
+  barrender = () => {
+    const { card } = this.state
+    const 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']
+
+    let data = this.getdata(X_axis, Y_axis)
+    
+    if (plot.enabled !== 'true') {
+      const ds = new DataSet()
+      const dv = ds.createView().source(data)
+      let transfield = {}
+
+      card.columns.forEach(col => {
+        if (col.field) {
+          transfield[col.field] = col.label
+        }
+      })
+  
+      dv.transform({
+        type: 'fold',
+        fields: [...Y_axis],
+        key: 'key',
+        value: 'value'
+      })
+  
+      if (plot.Xaxis) {
+        dv.transform({
+          type: 'map',
+          callback(row) {
+            row.key = transfield[row.key] || row.key
+            return row
+          },
+        })
+      }
+
+      const chart = new Chart({
+        container: card.uuid + 'canvas',
+        autoFit: true,
+        height: this.wrap.offsetHeight - 25
+      })
+
+      chart.data(dv.rows)
+
+      // chart.axis(X_axis, { label: { style: { fill: color } }, tickLine: {style: { stroke: color }}, line: { style: { stroke: color } } })
+      // chart.axis('value', { grid: { line: { style: { stroke: color } }}, label: { style: { fill: color } } })
+
+      let xc = {label: { style: { fill: color } }}
+      let yc = {label: { style: { fill: color } }}
+      if (plot.grid === 'hidden') {
+        yc.grid = null
+      }
+      if (plot.y_line === 'show') {
+        yc.line = {style: { stroke: '#D1D2CE' }}
+      }
+      if (plot.lineColor) {
+        xc.tickLine = {style: { stroke: plot.lineColor }}
+        xc.line = { style: { stroke: plot.lineColor } }
+        if (yc.grid !== null) {
+          yc.grid = { line: { style: { stroke: plot.lineColor } }}
+        }
+        if (yc.line) {
+          yc.line = { style: { stroke: plot.lineColor } }
+        }
+      }
+      chart.axis(X_axis, xc)
+      chart.axis('value', yc)
+  
+      chart.scale('value', {
+        nice: true,
+        range: [0, 0.9]
+      })
+  
+      if (!plot.legend || plot.legend === 'hidden') {
+        chart.legend(false)
+      } else {
+        chart.legend({
+          position: plot.legend,
+          itemName: { style: { fill: color } }
+        })
+      }
+  
+      if (plot.tooltip !== 'true') {
+        chart.tooltip(false)
+      } else {
+        chart.tooltip({
+          shared: true
+        })
+      }
+  
+      if (plot.coordinate === 'polar') {
+        chart.coordinate('polar', {
+          innerRadius: 0.1,
+          radius: 0.8
+        })
+      }
+
+      let colors = new Map()
+      let colorIndex = 0
+      let lablecfg = {
+        position: 'top',
+        offset: 2,
+        style: {
+          fill: '#fff'
+        }
+      }
+
+      if (plot.label === 'top') {
+        lablecfg.offset = -5
+        lablecfg.style.textBaseline = 'top'
+      } else if (plot.label === 'middle') {
+        lablecfg.position = 'middle'
+        lablecfg.offset = 0
+      } else if (plot.label === 'bottom') {
+        lablecfg.position = 'bottom'
+        lablecfg.offset = 0
+      } else if (plot.label === 'true') {
+        lablecfg.style.fill = color
+      }
+
+      if (plot.transpose === 'true') {
+        chart.coordinate().transpose()
+        if (plot.label === 'top') {
+          delete lablecfg.style.textBaseline
+          lablecfg.position = 'right'
+          lablecfg.offset = -3
+          lablecfg.style.textAlign = 'end'
+        } else if (plot.label === 'middle') {
+          lablecfg.position = 'middle'
+          lablecfg.offset = 0
+        } else if (plot.label === 'bottom') {
+          lablecfg.position = 'left'
+          lablecfg.offset = 2
+        } else if (plot.label === 'true') {
+          lablecfg.position = 'right'
+          lablecfg.offset = 2
+        }
+      }
+
+      if (plot.colors && plot.colors.length > 0) {
+        if (plot.ramp === 'true') {
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], `l(90) 0:${item.color} 1:${item.color1}` )
+            }
+          })
+        } else {
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], item.color)
+            }
+          })
+        }
+      }
+  
+      if (plot.adjust !== 'stack') {
+        let _chart = chart
+          .interval()
+          .position(`${X_axis}*value`)
+          .adjust([
+            {
+              type: 'dodge',
+              marginRatio: 0
+            }
+          ])
+          .shape(plot.shape || 'rect')
+          .tooltip(`${X_axis}*value*key`, (name, value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: key,
+              value: value
+            }
+          })
+
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+            
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.selectColor) {
+          _chart.state({
+            selected: {
+              style: {
+                fill: plot.selectColor,
+              }
+            }
+          })
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      } else if (plot.adjust === 'stack') {
+        let _chart = chart
+          .interval()
+          .position(`${X_axis}*value`)
+          .adjust('stack')
+          .shape(plot.shape || 'rect')
+          .tooltip(`${X_axis}*value*key`, (name, value, type) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: type,
+              value: value
+            }
+          })
+  
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.selectColor) {
+          _chart.state({
+            selected: {
+              style: {
+                fill: plot.selectColor,
+              }
+            }
+          })
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      }
+
+      if (plot.interaction && plot.interaction.length) {
+        plot.interaction.forEach(t => {
+          chart.interaction(t)
+        })
+      }
+  
+      chart.render()
+    } else {
+      this.customrender(data)
+    }
+  }
+
+  updateComponent = (component) => {
+    const card = fromJS(this.state.card).toJS()
+    if (!is(fromJS(component.plot), fromJS(card.plot)) || !is(fromJS(component.style), fromJS(card.style))) {
+      let _element = document.getElementById(card.uuid + 'canvas')
+      if (_element) {
+        _element.innerHTML = ''
+      }
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(() => {
+        this.viewrender()
+      }, 150)
+    }
+
+    component.width = component.plot.width
+    component.name = component.plot.name
+    
+    this.setState({
+      card: component
+    })
+    this.props.updateConfig(component)
+  }
+
+  addSearch = () => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+
+    newcard.label = 'label'
+    newcard.initval = ''
+    newcard.type = 'select'
+    newcard.resourceType = '0'
+    newcard.options = []
+    newcard.setAll = 'false'
+    newcard.orderType = 'asc'
+    newcard.display = 'dropdown'
+    newcard.match = '='
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎼滅储
+    MKEmitter.emit('addSearch', card.uuid, newcard)
+  }
+
+  addButton = () => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+    
+    newcard.label = '瀵煎嚭Excel'
+    newcard.sqlType = ''
+    newcard.Ot = 'requiredSgl'
+    newcard.OpenType = 'excelOut'
+    newcard.icon = 'download'
+    newcard.class = 'dgreen'
+    newcard.intertype = card.setting.interType
+    newcard.innerFunc = card.setting.innerFunc || ''
+    newcard.sysInterface = card.setting.sysInterface || ''
+    newcard.outerFunc = card.setting.outerFunc || ''
+    newcard.interface = card.setting.interface || ''
+    newcard.execSuccess = 'grid'
+    newcard.execError = 'never'
+    newcard.popClose = 'never'
+    newcard.verify = null
+    newcard.show = 'icon'
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
+    MKEmitter.emit('addButton', card.uuid, newcard)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin', 'shadow'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid || comIds.length > 1) return
+
+    let _card = {...card, style}
+
+    this.updateComponent(_card)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card, appType } = this.state
+    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}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" /> : null}
+            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
+            <CopyComponent type="line" card={card}/>
+            <PasteComponent config={card} options={['action']} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <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>
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
+        <div className="canvas" id={card.uuid + 'canvas'} ref={ref => this.wrap = ref}></div>
+        {appType !== 'mob' ? <ActionComponent
+          type="chart"
+          config={card}
+          updateaction={this.updateComponent}
+        /> : null}
+      </div>
+    )
+  }
+}
+
+export default ChartCustom
\ No newline at end of file
diff --git a/src/menu/components/chart/chart-custom/index.scss b/src/menu/components/chart/chart-custom/index.scss
new file mode 100644
index 0000000..19c0e63
--- /dev/null
+++ b/src/menu/components/chart/chart-custom/index.scss
@@ -0,0 +1,71 @@
+.menu-line-chart-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  display: flex;
+  flex-flow: column;
+
+  .canvas {
+    margin: 0px;
+    padding: 15px 10px 10px;
+    letter-spacing: 0px;
+    flex: 1;
+  }
+
+  .chart-header {
+    position: relative;
+    height: 45px;
+    border-bottom: 1px solid #e8e8e8;
+    overflow: hidden;
+    padding-right: 35px;
+
+    .chart-title {
+      text-decoration: inherit;
+      font-weight: inherit;
+      font-style: inherit;
+      float: left;
+      line-height: 45px;
+      margin-left: 10px;
+      position: relative;
+      z-index: 1;
+    }
+  }
+
+  >.anticon-tool {
+    position: absolute;
+    right: 1px;
+    top: 1px;
+    z-index: 2;
+    font-size: 16px;
+    padding: 5px;
+    cursor: pointer;
+    color: rgba(0, 0, 0, 0.85);
+    background: rgba(255, 255, 255, 0.55);
+  }
+
+  .model-menu-action-list {
+    position: absolute;
+    right: 0px;
+    top: 30px;
+    z-index: 4;
+    font-size: 16px;
+  
+    .ant-row .anticon-plus {
+      float: right;
+    }
+  
+    .page-card {
+      float: right;
+    }
+  }
+  .normal-header + .canvas + .model-menu-action-list {
+    top: 45px;
+  }
+}
+.menu-line-chart-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/share/actioncomponent/actionform/index.jsx b/src/menu/components/share/actioncomponent/actionform/index.jsx
index a1d74e9..880e257 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -118,7 +118,11 @@
           item.options = this.state.interTypeOptions.filter(op => (iscustom || op.value !== 'custom'))
         } else if (item.key === 'Ot') {
           if (type === 'card') {
-            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            if (card.sqlType === 'insert') {
+              item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
+            } else {
+              item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            }
           } else if (_pageTemplate === 'pay') { // 琛岀骇鎸夐挳銆佹敮浠樻寜閽紝鍙兘閫夊崟琛�
             item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value))
           } else if (['innerpage', 'tab', 'popview', 'excelIn'].includes(_opentype)) {
@@ -327,7 +331,11 @@
       this.setState({
         formlist: this.state.formlist.map(item => {
           if (item.key === 'Ot' && type === 'card') {
-            item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            if (value === 'insert') {
+              item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
+            } else {
+              item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
+            }
           } else if (item.key === 'Ot' && value === 'insert') {
             item.options = this.state.requireOptions.filter(op => ['notRequired'].includes(op.value))
           } else if (item.key === 'Ot') {
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index de74d45..20d8b54 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -22,6 +22,7 @@
 import dashboard from '@/assets/mobimg/dashboard.png'
 import ratioboard from '@/assets/mobimg/ratioboard.png'
 import scatter from '@/assets/mobimg/scatter.png'
+// import chart from '@/assets/mobimg/chart.png'
 import tree from '@/assets/mobimg/tree.png'
 
 // 缁勪欢閰嶇疆淇℃伅
@@ -50,6 +51,7 @@
   { 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: chart, component: 'chart', subtype: 'custom', 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 },
   { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24, forbid: ['billPrint'] },
diff --git a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
index 8f97ec6..c5d19f5 100644
--- a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
@@ -156,7 +156,7 @@
       <div className="common-modal-edit-card">
         <Row className="search-row">
           <Col span={8}>
-            <Search placeholder="璇疯緭鍏ュ瓧娈�" onSearch={value => {this.setState({searchKey: value})}} enterButton />
+            <Search placeholder="璇疯緭鍏ュ瓧娈�" autoFocus onSearch={value => {this.setState({searchKey: value})}} enterButton />
           </Col>
           <Col span={8}>
             <Button onClick={this.reset}>閲嶇疆</Button>
diff --git a/src/views/design/header/versions/index.jsx b/src/views/design/header/versions/index.jsx
index 74243b2..1d7d987 100644
--- a/src/views/design/header/versions/index.jsx
+++ b/src/views/design/header/versions/index.jsx
@@ -406,7 +406,7 @@
 
     return (
       <>
-        <div style={{padding: '5px 25px'}} onClick={this.verup}>鐗堟湰鍗囩骇</div>
+        <div style={{padding: '5px 25px'}} onClick={this.verup}>搴旂敤鍗囩骇</div>
         <Modal
           wrapClassName="version-up-modal"
           title="搴旂敤鍗囩骇"
diff --git a/src/views/login/index.jsx b/src/views/login/index.jsx
index ef337c1..ed9e6c3 100644
--- a/src/views/login/index.jsx
+++ b/src/views/login/index.jsx
@@ -423,7 +423,8 @@
               style: res.CSS || '',
               showline: res.split_line_show || 'true',
               webSite: res.WebSite || '',
-              navBar: res.menu_type
+              navBar: res.menu_type,
+              app_version: res.app_version
             }
 
             sessionStorage.setItem('home_background', res.index_background_color || '')
@@ -479,6 +480,7 @@
             window.GLOB.mainlogo = systemMsg.mainlogo
             window.GLOB.style = systemMsg.style
             window.GLOB.navBar = systemMsg.navBar
+            window.GLOB.appVersion = systemMsg.app_version
         
             if (window.GLOB.style && styles[window.GLOB.style]) {
               document.body.className = styles[window.GLOB.style] + ' ' + (res.split_line_show === 'false' ? 'hidden-split-line' : '')

--
Gitblit v1.8.0