From c7df940632b5f238f524da651fbf27a91ff6ad36 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期一, 26 十月 2020 16:54:46 +0800
Subject: [PATCH] 2020-10-26

---
 src/menu/components/card/cardcomponent/settingform/index.jsx           |   10 
 src/tabviews/custom/components/chart/antv-bar-line/index.scss          |    2 
 src/menu/components/card/cardcellcomponent/index.scss                  |    4 
 src/menu/padcontroller/index.jsx                                       |   97 ++++++
 src/menu/components/card/prop-card/index.scss                          |   72 ++++
 src/menu/components/card/cardcellcomponent/dragaction/action.jsx       |    4 
 src/menu/components/card/cardcellcomponent/elementform/index.jsx       |   17 
 src/menu/components/tabs/antv-tabs/index.scss                          |    2 
 src/tabviews/custom/components/chart/antv-pie/index.scss               |    2 
 src/menu/components/card/cardcellcomponent/dragaction/card.jsx         |    9 
 src/menu/components/chart/antv-bar/index.scss                          |    4 
 src/menu/padcontroller/index.scss                                      |    9 
 src/menu/components/card/data-card/index.scss                          |    8 
 src/menu/menushell/card.jsx                                            |    3 
 src/menu/components/card/data-card/wrapsetting/index.jsx               |    2 
 src/tabviews/custom/components/card/data-card/index.scss               |    9 
 src/views/menudesign/index.jsx                                         |   20 
 src/tabviews/custom/components/card/data-card/index.jsx                |    5 
 src/assets/css/main.scss                                               |    5 
 src/tabviews/custom/components/card/prop-card/index.scss               |  106 ++++++
 src/utils/events.js                                                    |    5 
 src/tabviews/custom/components/card/cardcellList/index.jsx             |    4 
 src/tabviews/custom/components/card/prop-card/index.jsx                |  124 +++++++
 src/menu/stylecontroller/index.jsx                                     |   32 +-
 src/menu/components/chart/antv-pie/index.scss                          |    4 
 src/tabviews/custom/components/tabs/antv-tabs/index.scss               |    2 
 src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx |   34 ++
 src/menu/components/card/cardcomponent/index.jsx                       |   32 +
 src/menu/components/card/data-card/index.jsx                           |    6 
 src/menu/components/card/cardcellcomponent/formconfig.jsx              |    1 
 src/menu/modelsource/option.jsx                                        |    2 
 src/tabviews/custom/index.jsx                                          |    9 
 src/menu/components/card/data-card/wrapsetting/settingform/index.jsx   |   28 +
 src/menu/components/card/prop-card/index.jsx                           |  264 ++++++++++++++++
 src/menu/components/tabs/tabcomponents/card.jsx                        |    3 
 src/menu/menushell/index.scss                                          |    9 
 36 files changed, 855 insertions(+), 94 deletions(-)

diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 05d3e30..b5e917f 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -9,6 +9,9 @@
   -webkit-font-smoothing: antialiased;
   box-sizing: border-box;
   font-weight: normal;
+  border-style: solid;
+  border-width: 0;
+  border-color: transparent;
   &:hover {
     outline: none;
   }
@@ -254,7 +257,7 @@
 
 .popview-modal {
   .ant-modal-body {
-    min-height: 300px;
+    min-height: 250px;
     max-height: calc(100vh - 190px);
     overflow-y: auto;
   }
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
index 0ebf81e..3a4dcf0 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -62,8 +62,8 @@
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control">
-        <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
-        <Icon className="close" title="close" type="close" onClick={() => delCard(id)} />
+        <Icon className="edit" title="缂栬緫" type="edit" onClick={() => editCard(id)} />
+        <Icon className="close" title="鍒犻櫎" type="close" onClick={() => delCard(id)} />
         <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => changeStyle(id)} type="font-colors" />
         {hasProfile ? <Icon className="profile" title="setting" type="profile" onClick={() => profileCard(id)} /> : null}
       </div>
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
index 35078a7..8f39701 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -44,11 +44,12 @@
     } else if (card.eleType === 'icon') {
       return (<Icon type={card.icon}/>)
     } else if (card.eleType === 'slider') {
+      let val = card.value ? (card.value / card.maxValue) * 100 : 30
       return (
         <div className="ant-mk-slider">
           <div className="ant-mk-slider-rail"></div>
-          <div className="ant-mk-slider-track" style={{width: '30%', backgroundColor: card.color}}></div>
-          <div className="ant-mk-slider-handle" style={{left: '30%', borderColor: card.color}}></div>
+          <div className="ant-mk-slider-track" style={{width: `${val}%`, backgroundColor: card.color}}></div>
+          <div className="ant-mk-slider-handle" style={{left: `${val}%`, borderColor: card.color}}></div>
         </div>
       )
     } else if (card.eleType === 'picture') {
@@ -91,8 +92,8 @@
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control">
-        <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
-        <Icon className="close" title="close" type="close" onClick={() => delCard(id)} />
+        <Icon className="edit" title="缂栬緫" type="edit" onClick={() => editCard(id)} />
+        <Icon className="close" title="鍒犻櫎" type="close" onClick={() => delCard(id)} />
         <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => changeStyle(id)} type="font-colors" />
       </div>
     } trigger="hover">
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.jsx b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
index 2a4422b..5f8e47e 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -14,7 +14,7 @@
   picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'radius', 'padding', 'url'],
   icon: ['eleType', 'icon', 'datatype', 'fontSize', 'width', 'align', 'padding'],
   link: ['eleType', 'datatype', 'labelfield', 'fontSize', 'width', 'height', 'align', 'padding', 'prefix'],
-  slider: ['eleType', 'field', 'width', 'color', 'padding', 'maxValue'],
+  slider: ['eleType', 'datatype', 'width', 'color', 'padding', 'maxValue'],
   splitline: ['eleType', 'color', 'width', 'padding'],
 }
 
@@ -37,7 +37,7 @@
   UNSAFE_componentWillMount () {
     const { card, config } = this.props
     let _options = this.getOptions(card.eleType, card.datatype)
-
+    
     this.setState({
       eleType: card.eleType,
       datatype: card.datatype,
@@ -69,6 +69,9 @@
               })
             }
           })
+        } else if (item.key === 'value' && card.eleType === 'slider') {
+          item.type = 'number'
+          item.label = '鍊�'
         }
 
         return item
@@ -79,7 +82,7 @@
   getOptions = (eleType, datatype) => {
     let _options = fromJS(cardTypeOptions[eleType]).toJS() // 閫夐」鍒楄〃
     
-    if (['text', 'number', 'picture', 'link'].includes(eleType)) {
+    if (['text', 'number', 'picture', 'link', 'slider'].includes(eleType)) {
       if (datatype === 'dynamic') {
         _options.push('field')
       } else if (eleType !== 'picture') {
@@ -127,6 +130,14 @@
               })
             }
           })
+        } else if (item.key === 'value') {
+          if (value === 'slider') {
+            item.type = 'number'
+            item.label = '鍊�'
+          } else {
+            item.type = 'text'
+            item.label = '鍐呭'
+          }
         }
 
         return item
diff --git a/src/menu/components/card/cardcellcomponent/formconfig.jsx b/src/menu/components/card/cardcellcomponent/formconfig.jsx
index 482842f..312db9d 100644
--- a/src/menu/components/card/cardcellcomponent/formconfig.jsx
+++ b/src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -99,6 +99,7 @@
     {
       type: 'text',
       key: 'value',
+      min: 0,
       label: '鍐呭',
       initVal: card.value || '',
       required: true
diff --git a/src/menu/components/card/cardcellcomponent/index.scss b/src/menu/components/card/cardcellcomponent/index.scss
index 83c954a..9d969a0 100644
--- a/src/menu/components/card/cardcellcomponent/index.scss
+++ b/src/menu/components/card/cardcellcomponent/index.scss
@@ -16,10 +16,6 @@
     cursor: pointer;
   }
 
-  .card-cell {
-    border-style: solid;
-    border-width: 0;
-  }
   .card-button-cell {
     float: left;
     button {
diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index cc22efb..68c173b 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/src/menu/components/card/cardcomponent/index.jsx
@@ -213,21 +213,23 @@
     }
 
     return (
-      <div className={'ant-col card-item ant-col-' + (card.setting.width || 6)} style={_style}>
-        <CardCellComponent cards={cards} cardCell={card} side={side} elements={elements} updateElement={this.updateCard}/>
-        <div className="card-control">
-          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
-            <div className="mk-popover-control">
-              <Icon className="plus" title="娣诲姞鍏冪礌" onClick={this.addElement} type="plus" />
-              <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
-              <Icon className="edit" type="edit" onClick={() => this.setState({settingVisible: true})} />
-              <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
-              <Icon className="close" title="鍒犻櫎鍗$墖" type="delete" onClick={() => this.props.deleteElement(card)} />
-              {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
-            </div>
-          } trigger="hover">
-            <Icon type="tool" />
-          </Popover>
+      <div className={'ant-col ant-col-' + (card.setting.width || 6)}>
+        <div className="card-item" style={_style}>
+          <CardCellComponent cards={cards} cardCell={card} side={side} elements={elements} updateElement={this.updateCard}/>
+          <div className="card-control">
+            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+              <div className="mk-popover-control">
+                <Icon className="plus" title="娣诲姞鍏冪礌" onClick={this.addElement} type="plus" />
+                <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
+                <Icon className="edit" type="edit" onClick={() => this.setState({settingVisible: true})} />
+                <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+                {cards.subtype === 'propcard' ? <Icon className="close" title="鍒犻櫎鍗$墖" type="delete" onClick={() => this.props.deleteElement(card)} /> : null}
+                {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
+              </div>
+            } trigger="hover">
+              <Icon type="tool" />
+            </Popover>
+          </div>
         </div>
         <Modal
           wrapClassName="popview-modal"
diff --git a/src/menu/components/card/cardcomponent/settingform/index.jsx b/src/menu/components/card/cardcomponent/settingform/index.jsx
index 2d570db..be9b7e0 100644
--- a/src/menu/components/card/cardcomponent/settingform/index.jsx
+++ b/src/menu/components/card/cardcomponent/settingform/index.jsx
@@ -10,6 +10,10 @@
     setting: PropTypes.object, // 鏁版嵁婧愰厤缃�
   }
 
+  state = {
+    type: this.props.setting.type || 'simple'
+  }
+
   handleConfirm = () => {
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     return new Promise((resolve, reject) => {
@@ -70,14 +74,14 @@
                 {getFieldDecorator('type', {
                   initialValue: setting.type || 'simple'
                 })(
-                  <Radio.Group>
+                  <Radio.Group onChange={(e) => this.setState({ type: e.target.value })}>
                     <Radio value="simple">鍗曞崱</Radio>
                     <Radio value="multi">澶嶅紡鍗�</Radio>
                   </Radio.Group>
                 )}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {this.state.type === 'multi' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="澶嶅紡鍗$墖榧犳爣鎮诞淇℃伅鐨勫姩鐢绘晥鏋溿��">
                   <Icon type="question-circle" />
@@ -93,7 +97,7 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
           </Row>
         </Form>
       </div>
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index c7d9847..029154a 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/src/menu/components/card/data-card/index.jsx
@@ -67,7 +67,11 @@
         subcards = [{
           uuid: Utils.getuuid(),
           setting: { width: 6, type: 'simple'},
-          style: {borderWidth: '1px', borderColor: '#e8e8e8', paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px'},
+          style: {
+            borderWidth: '1px', borderColor: '#e8e8e8',
+            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+          },
           backStyle: {},
           elements: [],
           backElements: []
diff --git a/src/menu/components/card/data-card/index.scss b/src/menu/components/card/data-card/index.scss
index e6cfc02..234c373 100644
--- a/src/menu/components/card/data-card/index.scss
+++ b/src/menu/components/card/data-card/index.scss
@@ -5,9 +5,7 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
-  min-height: 100px;
+  min-height: 50px;
   
   .card-control {
     position: absolute;
@@ -27,15 +25,13 @@
     top: 1px;
     cursor: pointer;
     padding: 5px;
-    background: #ffffff;
+    background: rgba(255, 255, 255, 0.55);
   }
 
   .card-item {
     overflow-y: hidden;
     position: relative;
     min-height: 50px;
-    border-style: solid;
-    border-width: 0;
   }
   
   .card-item:hover {
diff --git a/src/menu/components/card/data-card/wrapsetting/index.jsx b/src/menu/components/card/data-card/wrapsetting/index.jsx
index e3dba86..81632e9 100644
--- a/src/menu/components/card/data-card/wrapsetting/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/index.jsx
@@ -50,6 +50,7 @@
   }
 
   render () {
+    const { config } = this.props
     const { visible, dict, wrap } = this.state
 
     return (
@@ -69,6 +70,7 @@
           <SettingForm
             dict={dict}
             wrap={wrap}
+            config={config}
             wrappedComponentRef={(inst) => this.verifyRef = inst}
           />
         </Modal>
diff --git a/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx b/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
index 0d87bc9..863b152 100644
--- a/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
@@ -6,8 +6,9 @@
 
 class SettingForm extends Component {
   static propTpyes = {
-    dict: PropTypes.object,    // 瀛楀吀椤�
-    wrap: PropTypes.object,    // 鏁版嵁婧愰厤缃�
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    config: PropTypes.object,    // 鍗$墖琛屼俊鎭�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
   }
 
   handleConfirm = () => {
@@ -24,7 +25,7 @@
   }
 
   render() {
-    const { wrap } = this.props
+    const { wrap, config } = this.props
     const { getFieldDecorator } = this.props.form
 
     const formItemLayout = {
@@ -78,7 +79,24 @@
                 })(<InputNumber min={1} max={24} precision={0} />)}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {config.subtype === 'propcard' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="閫夋嫨闈欐�佸�硷紝鏃犻渶閰嶇疆鏁版嵁婧愩��">
+                  <Icon type="question-circle" />
+                  鏁版嵁鏉ユ簮
+                </Tooltip>
+              }>
+                {getFieldDecorator('datatype', {
+                  initialValue: wrap.datatype || 'dynamic'
+                })(
+                  <Radio.Group>
+                    <Radio value="dynamic">鍔ㄦ��</Radio>
+                    <Radio value="static">闈欐��</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {config.subtype === 'datacard' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="閫夋嫨鍚湁娣诲姞鎸夐挳鏃讹紝璇峰畬鍠勬寜閽厤缃俊鎭��">
                   <Icon type="question-circle" />
@@ -94,7 +112,7 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="閫夋嫨鍗$墖鍒囨崲鏃讹紝鍙悜鍏朵粬缁勪欢浼犻�掍富閿�笺��">
diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx
new file mode 100644
index 0000000..c7715d5
--- /dev/null
+++ b/src/menu/components/card/prop-card/index.jsx
@@ -0,0 +1,264 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import {connect} from 'react-redux'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover, Modal } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+
+import MKEmitter from '@/utils/events.js'
+import Utils from '@/utils/utils.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 WrapComponent = asyncIconComponent(() => import('../data-card/wrapsetting'))
+const CardComponent = asyncComponent(() => import('../cardcomponent'))
+
+const { confirm } = Modal
+
+class antvBarLineChart extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card, menu } = this.props
+
+    if (card.isNew) {
+      let dataName = ''
+      if (card.floor === 1) {
+        while (!dataName) {
+          let _dataName = Utils.getdataName()
+          if (menu.components.filter(com => com.dataName === _dataName).length === 0) {
+            dataName = _dataName
+          }
+        }
+      }
+
+      let subcards = null
+
+      if (card.config) {
+        subcards = JSON.parse(card.config)
+        subcards = subcards.map(scard => {
+          scard.uuid = Utils.getuuid()
+          scard.elements = scard.elements.map(elem => {
+            elem.uuid = Utils.getuuid()
+            return elem
+          })
+          scard.backElements = scard.backElements.map(elem => {
+            elem.uuid = Utils.getuuid()
+            return elem
+          })
+          return scard
+        })
+      } else {
+        subcards = [{
+          uuid: Utils.getuuid(),
+          setting: { width: 6, type: 'simple'},
+          style: {
+            borderWidth: '1px', borderColor: '#e8e8e8',
+            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+          },
+          backStyle: {},
+          elements: [],
+          backElements: []
+        }]
+      }
+
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: true,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: dataName,
+        width: 24,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, width: 24, addable: 'false', switch: 'false', datatype: 'dynamic' },
+        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
+        columns: [],
+        scripts: [],
+        subcards: subcards
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  updateCard = (cell) => {
+    let card = fromJS(this.state.card).toJS()
+
+    card.subcards = card.subcards.map(item => {
+      if (item.uuid === cell.uuid) return cell
+      return item
+    })
+
+    this.setState({card})
+
+    this.props.updateConfig(card)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  deleteCard = (cell) => {
+    let card = fromJS(this.state.card).toJS()
+    let _this = this
+
+    confirm({
+      content: '纭畾鍒犻櫎鍗$墖鍚楋紵',
+      onOk() {
+        card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
+    
+        _this.setState({card})
+        _this.props.updateConfig(card)
+      },
+      onCancel() {}
+    })
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  addCard = () => {
+    let card = fromJS(this.state.card).toJS()
+
+    let newcard = {
+      uuid: Utils.getuuid(),
+      setting: { width: 6, type: 'simple'},
+      style: {
+        borderWidth: '1px', borderColor: '#e8e8e8',
+        paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+        marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+      },
+      backStyle: {},
+      elements: [],
+      backElements: []
+    }
+
+    if (card.subcards.length > 0) {
+      newcard = fromJS(card.subcards[card.subcards.length - 1]).toJS()
+      newcard.uuid = Utils.getuuid()
+      newcard.elements = newcard.elements.map(elem => {
+        elem.uuid = Utils.getuuid()
+        return elem
+      })
+      newcard.backElements = newcard.backElements.map(elem => {
+        elem.uuid = Utils.getuuid()
+        return elem
+      })
+    }
+
+    card.subcards.push(newcard)
+    
+    this.setState({card})
+    this.props.updateConfig(card)
+  }
+
+  render() {
+    const { card } = this.state
+    return (
+      <div className="menu-prop-card-edit-box" style={card.style}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <Icon className="plus" title="娣诲姞鍗$墖" onClick={this.addCard} type="plus" />
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        {card.subcards.map(subcard => (<CardComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
+      </div>
+    )
+  }
+}
+
+const mapStateToProps = (state) => {
+  return {
+    menu: state.customMenu
+  }
+}
+
+const mapDispatchToProps = () => {
+  return {}
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(antvBarLineChart)
\ No newline at end of file
diff --git a/src/menu/components/card/prop-card/index.scss b/src/menu/components/card/prop-card/index.scss
new file mode 100644
index 0000000..e3ef5a7
--- /dev/null
+++ b/src/menu/components/card/prop-card/index.scss
@@ -0,0 +1,72 @@
+.menu-prop-card-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 50px;
+  
+  .card-control {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    .anticon-tool {
+      right: auto;
+      left: 1px;
+      padding: 1px;
+    }
+  }
+  .anticon-tool {
+    position: absolute;
+    z-index: 1;
+    font-size: 16px;
+    right: 1px;
+    top: 1px;
+    cursor: pointer;
+    padding: 5px;
+    background: rgba(255, 255, 255, 0.55);
+  }
+
+  .card-item {
+    overflow-y: hidden;
+    position: relative;
+    min-height: 50px;
+  }
+  
+  .card-item:hover {
+    box-shadow: 0px 0px 2px #e8e8e8;
+  }
+
+  .model-menu-card-cell-list .card-detail-row > .anticon-plus {
+    position: absolute;
+    right: -30px;
+    font-size: 16px;
+  }
+  .model-menu-action-list {
+    line-height: 40px;
+    .ant-row > .anticon-plus {
+      position: absolute;
+      right: -30px;
+      font-size: 16px;
+    }
+  }
+  .card-add-button {
+    text-align: right;
+    clear: left;
+    .anticon-plus {
+      font-size: 20px;
+      color: #26C281;
+      padding: 5px;
+      margin-right: 10px;
+    }
+  }
+}
+.menu-prop-card-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-prop-card-edit-box:hover {
+  box-shadow: 0px 0px 2px #e8e8e8;
+}
diff --git a/src/menu/components/chart/antv-bar/index.scss b/src/menu/components/chart/antv-bar/index.scss
index 9df114e..0b34294 100644
--- a/src/menu/components/chart/antv-bar/index.scss
+++ b/src/menu/components/chart/antv-bar/index.scss
@@ -5,8 +5,6 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
   
   .canvas {
     margin: 0px;
@@ -32,7 +30,7 @@
       padding: 5px;
       cursor: pointer;
       color: rgba(0, 0, 0, 0.85);
-      background: #ffffff;
+      background: rgba(255, 255, 255, 0.55);
     }
 
     .chart-title {
diff --git a/src/menu/components/chart/antv-pie/index.scss b/src/menu/components/chart/antv-pie/index.scss
index 30c3b20..d42ee49 100644
--- a/src/menu/components/chart/antv-pie/index.scss
+++ b/src/menu/components/chart/antv-pie/index.scss
@@ -5,8 +5,6 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
   
   .canvas {
     margin: 0px;
@@ -32,7 +30,7 @@
       padding: 5px;
       cursor: pointer;
       color: rgba(0, 0, 0, 0.85);
-      background: #ffffff;
+      background: rgba(255, 255, 255, 0.55);
     }
 
     .chart-title {
diff --git a/src/menu/components/tabs/antv-tabs/index.scss b/src/menu/components/tabs/antv-tabs/index.scss
index 990650f..b459cec 100644
--- a/src/menu/components/tabs/antv-tabs/index.scss
+++ b/src/menu/components/tabs/antv-tabs/index.scss
@@ -5,8 +5,6 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
 
   .ant-tabs-tabpane-active {
     min-height: 200px;
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index e5f121e..9273227 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -8,6 +8,7 @@
 const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
 const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs'))
 const DataCard = asyncComponent(() => import('@/menu/components/card/data-card'))
+const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -47,6 +48,8 @@
       return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard} />)
     } else if (card.type === 'card' && card.subtype === 'datacard') {
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />)
+    } else if (card.type === 'card' && card.subtype === 'propcard') {
+      return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index e359ec6..5f2af92 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -8,6 +8,7 @@
 const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
 const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs'))
 const DataCard = asyncComponent(() => import('@/menu/components/card/data-card'))
+const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -47,6 +48,8 @@
       return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'card' && card.subtype === 'datacard') {
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'propcard') {
+      return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/menushell/index.scss b/src/menu/menushell/index.scss
index 18ca1c9..21f8a7d 100644
--- a/src/menu/menushell/index.scss
+++ b/src/menu/menushell/index.scss
@@ -1,6 +1,5 @@
 .menu-shell-inner {
-  min-height: calc(100vh - 150px);
-  padding: 16px;
+  min-height: calc(100vh - 100px);
   width: 100%;
   background-size: 100%;
 
@@ -15,4 +14,10 @@
   >.ant-empty {
     padding-top: 150px;
   }
+  .anticon-tool {
+    color: rgba(0, 0, 0, 0.55);
+  }
+  .anticon-tool:hover {
+    color: #1890ff;
+  }
 }
\ No newline at end of file
diff --git a/src/menu/modelsource/option.jsx b/src/menu/modelsource/option.jsx
index adb04f4..3b75bf0 100644
--- a/src/menu/modelsource/option.jsx
+++ b/src/menu/modelsource/option.jsx
@@ -17,7 +17,7 @@
 export const menuOptions = [
   { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '鏍囩椤�', width: 24 },
   { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', config: `[{"uuid":"160135809128212dm7i29fim9ksto9od","setting":{"width":6},"style":{"paddingTop":"15px","marginTop":"4px","paddingRight":"15px","marginRight":"8px","marginLeft":"8px","backgroundColor":"rgba(255, 255, 255, 1)","borderColor":"#e8e8e8","paddingLeft":"15px","marginBottom":"4px","borderWidth":"1px","paddingBottom":"10px"},"backStyle":{},"elements":[{"datatype":"static","width":12,"marks":null,"height":1,"value":"鍏冲崟","style":{},"prefix":"","postfix":"","format":"","eleType":"text","uuid":"160231860159931untbea62sgokunc5s"},{"datatype":"dynamic","width":12,"marks":null,"style":{"color":"rgba(250, 219, 20, 1)","textAlign":"right"},"btnstyle":{},"eleType":"icon","icon":"question-circle","field":"nvarchar2","uuid":"1602318768361nv8ql4t47sgcsn88b0u"},{"datatype":"static","width":24,"marks":null,"height":1,"value":"100","style":{"fontSize":"24px","fontWeight":"500","color":"rgba(0, 0, 0, 1)"},"prefix":"","btnstyle":{},"postfix":"","format":"","eleType":"text","uuid":"1602318817884v70gtgb65ubnm8mbcvv"},{"color":"#1890ff","width":24,"marks":null,"maxValue":100,"style":{"color":"rgba(250, 140, 22, 1)","paddingTop":"20px","paddingBottom":"10px"},"btnstyle":{},"eleType":"slider","field":"int1","uuid":"16023188871233rkktuvpp1h077igrsu"},{"eleType":"splitline","width":24,"color":"#e8e8e8","uuid":"1602320017038n31bk9o831ggug0tu0b","marks":null,"style":{"marginTop":"10px","marginBottom":"10px"},"btnstyle":{}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"marginTop":"6px"},"prefix":"鍏冲崟","btnstyle":{},"postfix":"","format":"","eleType":"text","uuid":"1602320061243drd7lf3agvn04kgr175"}],"backElements":[]}]` },
-  { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱' },
+  { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', config: `[{"uuid":"1603681387259qaqf1127f72esmtchge","setting":{"width":6,"type":"simple"},"style":{"paddingTop":"15px","marginTop":"8px","paddingRight":"15px","marginRight":"8px","marginLeft":"8px","borderColor":"#e8e8e8","paddingLeft":"15px","marginBottom":"8px","borderWidth":"1px","paddingBottom":"15px"},"backStyle":{},"elements":[{"datatype":"static","width":12,"marks":null,"height":1,"value":"瓒呮椂宸ュ崟","style":{"color":"rgba(67, 67, 67, 0.51)"},"prefix":"","postfix":"","format":"","eleType":"text","uuid":"1603681402945qnkgm7q8cng65evn5ev"},{"eleType":"icon","datatype":"static","width":12,"icon":"question-circle","tooltip":"瓒呮椂宸ュ崟","uuid":"1603681473384i2crkbtofg4pu76k06a","marks":null,"style":{"textAlign":"right","color":"rgba(250, 219, 20, 1)"}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"fontSize":"24px","color":"rgba(0, 0, 0, 1)"},"prefix":"","postfix":"","format":"","eleType":"number","uuid":"1603681539870d704ufqf98kc6t7537t"},{"color":"rgba(250, 219, 20, 1)","datatype":"static","width":24,"marks":null,"maxValue":100,"value":50,"style":{"paddingTop":"10px","paddingBottom":"10px"},"eleType":"slider","uuid":"1603683067556mvupau0odvrtv45u7o8"},{"eleType":"splitline","width":24,"color":"#e8e8e8","uuid":"1603683117981t9k55k8an430fuppmci","marks":null,"style":{"paddingTop":"5px","paddingBottom":"5px"}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"color":"rgba(0, 0, 0, 0.65)","marginTop":"10px"},"prefix":"瓒呮椂宸ュ崟  ","postfix":"","format":"","eleType":"text","uuid":"1603683136553uvsmkfohkft9idbfkhu"}],"backElements":[]}]` },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�' },
   { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�' },
   { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '鏌辩姸鍥�' },
diff --git a/src/menu/padcontroller/index.jsx b/src/menu/padcontroller/index.jsx
new file mode 100644
index 0000000..7a50d27
--- /dev/null
+++ b/src/menu/padcontroller/index.jsx
@@ -0,0 +1,97 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Form, Col, Icon } from 'antd'
+
+import zhCN from '@/locales/zh-CN/mob.js'
+import enUS from '@/locales/en-US/mob.js'
+import StyleInput from '../stylecontroller/styleInput'
+import './index.scss'
+
+class MobController extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    paddingTop: '',
+    paddingBottom: '',
+    paddingLeft: '',
+    paddingRight: ''
+  }
+
+  UNSAFE_componentWillMount () {
+
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 淇敼鑳屾櫙棰滆壊 锛岄鑹叉帶浠�
+   */
+  changePadding = (val, type) => {
+    let config = fromJS(this.props.config).toJS()
+
+    config.style[type] = val
+    this.props.updateConfig(config)
+  }
+
+  render () {
+    const { config } = this.props
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <div className="menu-padding-controller">
+        <Form {...formItemLayout}>
+          <Col span={12}>
+            <Form.Item
+              colon={false}
+              label={<Icon title="涓婅竟璺�" type="arrow-up"/>}
+            >
+              <StyleInput defaultValue={config.style.paddingTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changePadding(val, 'paddingTop')}/>
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item
+              colon={false}
+              label={<Icon title="涓嬭竟璺�" type="arrow-down"/>}
+            >
+              <StyleInput defaultValue={config.style.paddingBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changePadding(val, 'paddingBottom')}/>
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item
+              colon={false}
+              label={<Icon title="宸﹁竟璺�" type="arrow-left"/>}
+            >
+              <StyleInput defaultValue={config.style.paddingLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changePadding(val, 'paddingLeft')}/>
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item
+              colon={false}
+              label={<Icon title="鍙宠竟璺�" type="arrow-right"/>}
+            >
+              <StyleInput defaultValue={config.style.paddingRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changePadding(val, 'paddingRight')}/>
+            </Form.Item>
+          </Col>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default MobController
\ No newline at end of file
diff --git a/src/menu/padcontroller/index.scss b/src/menu/padcontroller/index.scss
new file mode 100644
index 0000000..95c0abe
--- /dev/null
+++ b/src/menu/padcontroller/index.scss
@@ -0,0 +1,9 @@
+.menu-padding-controller {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  .ant-form-item label > .anticon {
+    font-size: 16px;
+    vertical-align: middle;
+  }
+}
diff --git a/src/menu/stylecontroller/index.jsx b/src/menu/stylecontroller/index.jsx
index 2e80909..c0e8205 100644
--- a/src/menu/stylecontroller/index.jsx
+++ b/src/menu/stylecontroller/index.jsx
@@ -309,7 +309,7 @@
               {options.includes('font') ? <Panel header="瀛椾綋" key="font">
                 <Col span={12}>
                   <Form.Item colon={false} label={<Icon title="瀛椾綋澶у皬" type="font-size" />}>
-                    <InputNumber defaultValue={card.fontSize} min={12} max={100} precision={0} onChange={this.changeFontSize} />
+                    <InputNumber defaultValue={card.fontSize || 14} min={12} max={100} precision={0} onChange={this.changeFontSize} />
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -333,12 +333,12 @@
                 </Col>
                 <Col span={12}>
                   <Form.Item colon={false} label={<Icon title="琛岄珮" type="line-height" />}>
-                    <InputNumber defaultValue={card.lineHeight} min={1} max={10} precision={1} onChange={this.changeLineHeight} />
+                    <InputNumber defaultValue={card.lineHeight || 1.5} min={1} max={10} precision={1} onChange={this.changeLineHeight} />
                   </Form.Item>
                 </Col>
                 <Col span={12}>
                   <Form.Item colon={false} label={<Icon title="瀛楅棿璺�" type="column-width" />}>
-                    <InputNumber defaultValue={card.letterSpacing} min={0} max={100} precision={0} onChange={this.changeLetterSpacing}/>
+                    <InputNumber defaultValue={card.letterSpacing || 0} min={0} max={100} precision={0} onChange={this.changeLetterSpacing}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -472,11 +472,11 @@
                     label={<Icon title="杈规瀹藉害" type="column-width" />}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    {borposition === 'outer' ? <StyleInput defaultValue={card.borderWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'left' ? <StyleInput defaultValue={card.borderLeftWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'right' ? <StyleInput defaultValue={card.borderRightWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'top' ? <StyleInput defaultValue={card.borderTopWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'bottom' ? <StyleInput defaultValue={card.borderBottomWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'outer' ? <StyleInput defaultValue={card.borderWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'left' ? <StyleInput defaultValue={card.borderLeftWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'right' ? <StyleInput defaultValue={card.borderRightWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'top' ? <StyleInput defaultValue={card.borderTopWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'bottom' ? <StyleInput defaultValue={card.borderBottomWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -508,7 +508,7 @@
                     colon={false}
                     label={<Icon title="涓婅竟璺�" type="arrow-up"/>}
                   >
-                    <StyleInput defaultValue={card.marginTop} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
+                    <StyleInput defaultValue={card.marginTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -516,7 +516,7 @@
                     colon={false}
                     label={<Icon title="涓嬭竟璺�" type="arrow-down"/>}
                   >
-                    <StyleInput defaultValue={card.marginBottom} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
+                    <StyleInput defaultValue={card.marginBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -524,7 +524,7 @@
                     colon={false}
                     label={<Icon title="宸﹁竟璺�" type="arrow-left"/>}
                   >
-                    <StyleInput defaultValue={card.marginLeft} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
+                    <StyleInput defaultValue={card.marginLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -532,7 +532,7 @@
                     colon={false}
                     label={<Icon title="鍙宠竟璺�" type="arrow-right"/>}
                   >
-                    <StyleInput defaultValue={card.marginRight} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
+                    <StyleInput defaultValue={card.marginRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
@@ -542,7 +542,7 @@
                     colon={false}
                     label={<Icon title="涓婅竟璺�" type="arrow-up"/>}
                   >
-                    <StyleInput defaultValue={card.paddingTop} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
+                    <StyleInput defaultValue={card.paddingTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -550,7 +550,7 @@
                     colon={false}
                     label={<Icon title="涓嬭竟璺�" type="arrow-down"/>}
                   >
-                    <StyleInput defaultValue={card.paddingBottom} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
+                    <StyleInput defaultValue={card.paddingBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -558,7 +558,7 @@
                     colon={false}
                     label={<Icon title="宸﹁竟璺�" type="arrow-left"/>}
                   >
-                    <StyleInput defaultValue={card.paddingLeft} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
+                    <StyleInput defaultValue={card.paddingLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
                   </Form.Item>
                 </Col>
                 <Col span={12}>
@@ -566,7 +566,7 @@
                     colon={false}
                     label={<Icon title="鍙宠竟璺�" type="arrow-right"/>}
                   >
-                    <StyleInput defaultValue={card.paddingRight} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
+                    <StyleInput defaultValue={card.paddingRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
diff --git a/src/tabviews/custom/components/card/cardcellList/index.jsx b/src/tabviews/custom/components/card/cardcellList/index.jsx
index 5a1d9c8..23ed5e1 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.jsx
+++ b/src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -88,7 +88,9 @@
     } else if (card.eleType === 'slider') {
       let val = 0
 
-      if (data.hasOwnProperty(card.field)) {
+      if (card.datatype === 'static') {
+        val = card.value
+      } else if (data.hasOwnProperty(card.field)) {
         val = parseFloat(data[card.field])
         if (isNaN(val)) {
           val = 0
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index 06a8198..02f4756 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -29,7 +29,6 @@
     dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 瀛楀吀
     config: null,              // 鍥捐〃閰嶇疆淇℃伅
     pageIndex: 1,
-    empty: false,
     loading: false,            // 鏁版嵁鍔犺浇鐘舵��
     data: null,                // 鏁版嵁
     total: null
@@ -124,7 +123,7 @@
   }
 
   render() {
-    const { config, empty, loading, data, pageIndex, total } = this.state
+    const { config, loading, data, pageIndex, total } = this.state
 
     let _total = config.setting.pageSize * pageIndex
     let pageable = config.pageable && config.setting.laypage
@@ -147,7 +146,7 @@
           ))}
         </div> : null}
         {pageable ? <div className={'prev-page ' + (total <= _total ? 'disabled' : '')} onClick={this.nextPage}><div><div><img src={nextImg} alt=""/></div></div></div> : null}
-        {empty ? <Empty description={false}/> : null}
+        {data && data.length === 0 ? <Empty description={false}/> : null}
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/card/data-card/index.scss b/src/tabviews/custom/components/card/data-card/index.scss
index 5ce4120..c117a33 100644
--- a/src/tabviews/custom/components/card/data-card/index.scss
+++ b/src/tabviews/custom/components/card/data-card/index.scss
@@ -3,7 +3,7 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  min-height: 100px;
+  min-height: 50px;
   display: flex;
   position: relative;
 
@@ -39,7 +39,6 @@
     flex: 10;
   }
   .card-item-box {
-    border-style: solid;
     .card-cell-list::after {
       content: ' ';
       display: block;
@@ -102,9 +101,9 @@
   }
 
   .ant-empty {
-    position: absolute;
-    top: calc(50% - 34px);
-    left: calc(50% - 92px);
+    width: 100%;
+    min-height: 100px;
+    padding-top: 15px;
 
     .ant-empty-image {
       height: 60px;
diff --git a/src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx b/src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx
new file mode 100644
index 0000000..5fb9c1a
--- /dev/null
+++ b/src/tabviews/custom/components/card/prop-card/asyncButtonComponent.jsx
@@ -0,0 +1,34 @@
+import React, {Component} from 'react'
+import { Button } from 'antd'
+
+/**
+ * @description 寮傛鍔犺浇妯″潡
+ * @param {*} importComponent
+ */
+export default function asyncComponent(importComponent) {
+  return class extends Component {
+    constructor(props) {
+      super(props)
+
+      this.state = {
+        component: null
+      }
+    }
+
+    async componentDidMount() {
+      const {default: component} = await importComponent()
+
+      this.setState({component})
+    }
+
+    // <Button className="loading-skeleton" disabled={true}></Button> // 楠ㄦ灦鎸夐挳
+    render() {
+      const C = this.state.component
+      const btn = this.props.btn || {}
+
+      return C ?
+        <C {...this.props} /> :
+        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/prop-card/index.jsx b/src/tabviews/custom/components/card/prop-card/index.jsx
new file mode 100644
index 0000000..ae6f094
--- /dev/null
+++ b/src/tabviews/custom/components/card/prop-card/index.jsx
@@ -0,0 +1,124 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Spin, notification } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import Api from '@/api'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import zhCN from '@/locales/zh-CN/main.js'
+import enUS from '@/locales/en-US/main.js'
+import './index.scss'
+
+const CardItem = asyncComponent(() => import('../cardItem'))
+
+class DataCard extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,              // 鐖剁骇Id
+    data: PropTypes.array,           // 缁熶竴鏌ヨ鏁版嵁
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 鍏ㄥ眬鎼滅储鏉′欢
+    menuType: PropTypes.any,         // 鑿滃崟绫诲瀷
+    dataManager: PropTypes.any,      // 鏁版嵁鏉冮檺
+  }
+
+  state = {
+    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 瀛楀吀
+    config: null,              // 鍥捐〃閰嶇疆淇℃伅
+    loading: true,             // 鏁版嵁鍔犺浇鐘舵��
+    data: null,                // 鏁版嵁
+  }
+
+  UNSAFE_componentWillMount () {
+    let _config = fromJS(this.props.config).toJS()
+
+    this.setState({
+      config: _config,
+      arr_field: _config.columns.map(col => col.field).join(','),
+    }, () => {
+      this.loadData()
+    })
+  }
+
+  /**
+   * @description 鏍¢獙鍥捐〃鐨勬寜閽粍锛屽鏋滀负缁熻鍥捐〃锛岃绠楀浘琛ㄥ瓧娈�
+   */
+  componentDidMount () {
+
+  }
+
+  /**
+   * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  async loadData () {
+    const { mainSearch, BID, menuType, dataManager } = this.props
+    const { config, arr_field } = this.state
+    
+    let searches = []
+    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      searches = [...mainSearch, ...searches]
+    }
+
+    if (config.wrap.datatype === 'static') {
+      this.setState({
+        loading: false,
+        data: []
+      })
+      return
+    } else {
+      this.setState({
+        loading: true
+      })
+    }
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, 1, 1, BID, menuType, dataManager)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      this.setState({
+        data: result.data,
+        loading: false
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  render() {
+    const { config, loading, data } = this.state
+
+    return (
+      <div className="custom-card-box" style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        {data ? <div className="card-row-list">
+          {config.subcards.map((item, index) => (
+            <CardItem key={index} card={item} cards={config} data={data[0] || {}} />
+          ))}
+        </div> : null}
+      </div>
+    )
+  }
+}
+
+export default DataCard
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/prop-card/index.scss b/src/tabviews/custom/components/card/prop-card/index.scss
new file mode 100644
index 0000000..3eb80db
--- /dev/null
+++ b/src/tabviews/custom/components/card/prop-card/index.scss
@@ -0,0 +1,106 @@
+.custom-card-box {
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 50px;
+  display: flex;
+  position: relative;
+
+  .card-row-list::after {
+    content: ' ';
+    display: block;
+    clear: both;
+  }
+  .card-row-list {
+    flex: 10;
+  }
+  .card-item-box {
+    .card-cell-list::after {
+      content: ' ';
+      display: block;
+      clear: both;
+    }
+  }
+
+  .card-cell-list {
+    position: relative;
+  
+    .ant-mk-slider {
+      box-sizing: border-box;
+      margin: 0;
+      color: rgba(0, 0, 0, 0.65);
+      font-size: 14px;
+      font-variant: tabular-nums;
+      line-height: 1.5;
+      list-style: none;
+      font-feature-settings: 'tnum', "tnum";
+      position: relative;
+      height: 12px;
+      padding: 3px 0;
+      cursor: pointer;
+      touch-action: none;
+  
+      .ant-mk-slider-track {
+        height: 7px;
+        position: absolute;
+        background-color: #91d5ff;
+        border-radius: 4px;
+        transition: background-color 0.3s;
+      }
+      .ant-mk-slider-rail {
+        height: 7px;
+        position: absolute;
+        width: 100%;
+        background-color: #f5f5f5;
+        border-radius: 2px;
+        transition: background-color 0.3s;
+      }
+      .ant-mk-slider-handle {
+        position: absolute;
+        width: 14px;
+        height: 14px;
+        margin-top: -4px;
+        margin-left: -7px;
+        background-color: #fff;
+        border: solid 2px #91d5ff;
+        border-radius: 50%;
+        cursor: pointer;
+        transition: border-color 0.3s, box-shadow 0.6s, transform 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28), -webkit-box-shadow 0.6s, -webkit-transform 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
+      }
+    }
+    .ant-mk-splitline {
+      height: 1px;
+    }
+    .ant-slider {
+      margin: 0px;
+    }
+  }
+
+  .loading-mask {
+    position: absolute;
+    left: 40px;
+    top: 0;
+    right: 40px;
+    bottom: 0px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    text-align: justify;
+    z-index: 1;
+
+    .ant-spin-blur {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      opacity: 0.5;
+      background: #ffffff;
+    }
+  }
+}
+
+.custom-card-box::after {
+  content: ' ';
+  display: block;
+  clear: both;
+}
diff --git a/src/tabviews/custom/components/chart/antv-bar-line/index.scss b/src/tabviews/custom/components/chart/antv-bar-line/index.scss
index 9b1e815..f086d2d 100644
--- a/src/tabviews/custom/components/chart/antv-bar-line/index.scss
+++ b/src/tabviews/custom/components/chart/antv-bar-line/index.scss
@@ -3,8 +3,6 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
   min-height: 100px;
 
   > .chart-header {
diff --git a/src/tabviews/custom/components/chart/antv-pie/index.scss b/src/tabviews/custom/components/chart/antv-pie/index.scss
index 5ab17b5..aa04a3d 100644
--- a/src/tabviews/custom/components/chart/antv-pie/index.scss
+++ b/src/tabviews/custom/components/chart/antv-pie/index.scss
@@ -3,8 +3,6 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
   min-height: 100px;
 
   > .chart-header {
diff --git a/src/tabviews/custom/components/tabs/antv-tabs/index.scss b/src/tabviews/custom/components/tabs/antv-tabs/index.scss
index a2e2337..c9f78da 100644
--- a/src/tabviews/custom/components/tabs/antv-tabs/index.scss
+++ b/src/tabviews/custom/components/tabs/antv-tabs/index.scss
@@ -5,6 +5,4 @@
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
-  border-style: solid;
-  border-width: 0;
 }
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 7a3c2f1..cd29a77 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -21,6 +21,7 @@
 const AntvPie = asyncSpinComponent(() => import('./components/chart/antv-pie'))
 const AntvTabs = asyncSpinComponent(() => import('./components/tabs/antv-tabs'))
 const DataCard = asyncSpinComponent(() => import('./components/card/data-card'))
+const PropCard = asyncSpinComponent(() => import('./components/card/prop-card'))
 
 class CustomPage extends Component {
   static propTpyes = {
@@ -176,7 +177,7 @@
         }
       }
 
-      if (!component.format) return component // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
+      if (!component.format || (component.subtype === 'propcard' && component.wrap.datatype === 'static')) return component // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
 
       let _customScript = ''
       component.scripts && component.scripts.forEach(script => {
@@ -465,6 +466,12 @@
               <DataCard config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
             </Col>
           )
+        } else if (item.subtype === 'propcard') {
+          return (
+            <Col span={item.width} key={item.uuid}>
+              <PropCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
+            </Col>
+          )
         } else {
           return null
         }
diff --git a/src/utils/events.js b/src/utils/events.js
index 7489dac..de5c33a 100644
--- a/src/utils/events.js
+++ b/src/utils/events.js
@@ -1,5 +1,6 @@
 import EventEmitter from 'events'
 
-class MKEmitter extends EventEmitter {}
+const Emitter = new EventEmitter()
+Emitter.setMaxListeners(1000)
 
-export default new MKEmitter()
\ No newline at end of file
+export default Emitter
\ No newline at end of file
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 93c3398..a21d6c6 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -26,7 +26,8 @@
 const MenuForm = asyncComponent(() => import('@/menu/menuform'))
 const SourceWrap = asyncComponent(() => import('@/menu/modelsource'))
 const MenuShell = asyncComponent(() => import('@/menu/menushell'))
-const Controller = asyncComponent(() => import('@/menu/bgcontroller'))
+const BgController = asyncComponent(() => import('@/menu/bgcontroller'))
+const PaddingController = asyncComponent(() => import('@/menu/padcontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller'))
 const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -235,7 +236,10 @@
             MenuNo: MenuNo,
             tables: [],
             components: [],
-            style: {backgroundColor: '#ffffff', backgroundImage: ''}
+            style: {
+              backgroundColor: '#ffffff', backgroundImage: '',
+              paddingTop: '16px', paddingBottom: '80px', paddingLeft: '16px', paddingRight: '16px'
+            }
           }
         } else {
           config.uuid = MenuId
@@ -338,7 +342,10 @@
     }
 
     config.components.forEach(item => {
-      if (!error && item.setting) {
+      if (error) return
+      if (item.subtype === 'propcard' && item.wrap.datatype === 'static') return
+
+      if (item.setting) {
         if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
           error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
         } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
@@ -347,7 +354,7 @@
           error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
         }
       }
-      if (!error && (item.type === 'bar' || item.type === 'line' || item.type === 'pie')) {
+      if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
         if (!item.plot.Xaxis) {
           error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
         }
@@ -422,7 +429,10 @@
                     <SourceWrap />
                   </Panel>
                   <Panel header={'鑳屾櫙'} key="background">
-                    {config ? <Controller config={config} updateConfig={this.updateConfig} /> : null}
+                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
+                  </Panel>
+                  <Panel header={'鍐呰竟璺�'} key="padding">
+                    {config ? <PaddingController config={config} updateConfig={this.updateConfig} /> : null}
                   </Panel>
                 </Collapse>
               </div>

--
Gitblit v1.8.0