From ecbe0dc46ce2b8f607b9afd063104adeb7f10fe8 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期二, 30 三月 2021 15:19:31 +0800
Subject: [PATCH] 2021-03-30

---
 src/views/pcdesign/index.jsx                           |    4 
 src/views/mobdesign/menuform/index.jsx                 |  138 +++
 src/mob/modulesource/dragsource/index.jsx              |   15 
 src/mob/mobshell/index.jsx                             |  136 ++
 src/mob/modulesource/index.jsx                         |   93 ++
 src/mob/modulesource/option.jsx                        |   42 
 src/pc/menushell/index.jsx                             |   15 
 /dev/null                                              |   16 
 src/tabviews/zshare/mutilform/index.jsx                |  282 ++++--
 src/templates/sharecomponent/columncomponent/index.jsx |    2 
 src/mob/modulesource/index.scss                        |    2 
 src/views/mobdesign/index.scss                         |  282 +++--
 src/views/mobdesign/menuform/index.scss                |   10 
 src/views/mobdesign/index.jsx                          | 1548 +++++++++++++++++++++++++++++---
 src/assets/mobimg/navbar-mob.png                       |    0 
 src/menu/menushell/index.jsx                           |   15 
 src/mob/mobshell/card.jsx                              |   74 +
 src/mob/modulesource/dragsource/index.scss             |   46 +
 18 files changed, 2,242 insertions(+), 478 deletions(-)

diff --git a/src/assets/mobimg/mobile.png b/src/assets/mobimg/mobile.png
deleted file mode 100644
index c17bc0b..0000000
--- a/src/assets/mobimg/mobile.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/mobimg/navbar-mob.png b/src/assets/mobimg/navbar-mob.png
new file mode 100644
index 0000000..d6be81a
--- /dev/null
+++ b/src/assets/mobimg/navbar-mob.png
Binary files differ
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index 05c87c4..6ac5ace 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -1,6 +1,5 @@
 import React, { useState } from 'react'
 import { useDrop } from 'react-dnd'
-import { is, fromJS } from 'immutable'
 import update from 'immutability-helper'
 import { Empty, notification, Modal } from 'antd'
 
@@ -18,10 +17,7 @@
     const { card, index } = findCard(id)
     const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
     handleList({...menu, components: _cards})
-  }
-
-  if (!is(fromJS(cards), fromJS(menu.components))) {
-    setCards(menu.components)
+    setCards(_cards)
   }
   
   const findCard = id => {
@@ -33,7 +29,9 @@
   }
 
   const updateConfig = (element) => {
-    handleList({...menu, components: cards.map(item => item.uuid === element.uuid ? element : item)})
+    const _cards = cards.map(item => item.uuid === element.uuid ? element : item)
+    handleList({...menu, components: _cards})
+    setCards(_cards)
   }
 
   const deleteCard = (id) => {
@@ -54,8 +52,10 @@
       title: `纭畾鍒犻櫎銆�${card.name}銆嬪悧锛焋,
       content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
       onOk() {
+        const _cards = cards.filter(item => item.uuid !== card.uuid)
         MKEmitter.emit('delButtons', uuids)
-        handleList({...menu, components: cards.filter(item => item.uuid !== card.uuid)})
+        handleList({...menu, components: _cards})
+        setCards(_cards)
       },
       onCancel() {}
     })
@@ -130,6 +130,7 @@
       const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
 
       handleList({...menu, components: _cards})
+      setCards(_cards)
     }
   })
 
diff --git a/src/mob/contdelete/index.jsx b/src/mob/contdelete/index.jsx
deleted file mode 100644
index d96e1b6..0000000
--- a/src/mob/contdelete/index.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-// import { is, fromJS } from 'immutable'
-import { Icon, Modal } from 'antd'
-
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import './index.scss'
-
-const { confirm } = Modal
-
-class ContentDelete extends Component {
-  static propTpyes = {
-    element: PropTypes.object,
-    list: PropTypes.array,
-    updateContent: PropTypes.func
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    images: [],
-    visible: false
-  }
-
-  UNSAFE_componentWillMount () {
-
-  }
-
-  // shouldComponentUpdate (nextProps, nextState) {
-  //   return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  // }
-
-  deleteElement = () => {
-    const { list, element } = this.props
-    const _this = this
-
-    confirm({
-      title: '纭畾鍒犻櫎鍏冪礌鍚楋紵',
-      onOk() {
-        _this.props.updateContent({...list, subItems: list.subItems.filter(item => item.uuid !== element.uuid)})
-      },
-      onCancel() {}
-    })
-  }
-
-  
-
-  render () {
-    return (
-      <div className="mob-content-list-delete">
-        <Icon type="close" onClick={this.deleteElement} />
-      </div>
-    )
-  }
-}
-
-export default ContentDelete
\ No newline at end of file
diff --git a/src/mob/contdelete/index.scss b/src/mob/contdelete/index.scss
deleted file mode 100644
index a36b973..0000000
--- a/src/mob/contdelete/index.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-.mob-content-list-delete {
-  position: absolute;
-  top: -10px;
-  left: -10px;
-  border-radius: 2px;
-  font-size: 14px;
-  display: none;
-  line-height: 1.5;
-  z-index: 1;
-
-  i {
-    padding: 2px 5px;
-    cursor: pointer;
-  }
-  .anticon-close {
-    color: #ff4d4f;
-  }
-}
-.deletable-item {
-  position: relative;
-}
-.deletable-item:hover .mob-content-list-delete {
-  display: inline-block;
-}
-
diff --git a/src/mob/controller/index.jsx b/src/mob/controller/index.jsx
deleted file mode 100644
index 21878d7..0000000
--- a/src/mob/controller/index.jsx
+++ /dev/null
@@ -1,480 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { Collapse, Form, Input, Col, Icon, InputNumber, Select, Radio, Popover, Menu } from 'antd'
-
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import ColorSketch from '@/mob/colorsketch'
-import FileUpload from '@/tabviews/zshare/fileupload'
-import './index.scss'
-
-const { Panel } = Collapse
-const { Option } = Select
-
-class MobController extends Component {
-  static propTpyes = {
-    editElem: PropTypes.any,
-    updateStyle: PropTypes.func,
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    card: null,
-    fontColor: '#000000',
-    backgroundColor: '#ffffff',
-    bgimages: [],
-    marginTop: '',
-    marginTopVal: '',
-    marginBottom: '',
-    marginBottomVal: '',
-  }
-
-  UNSAFE_componentWillReceiveProps (nextProps) {
-    if (!is(fromJS(this.props.editElem), fromJS(nextProps.editElem))) {
-      this.setState({
-        card: null
-      }, () => {
-        if (!nextProps.editElem) return
-        let _card = fromJS(nextProps.editElem).toJS()
-        let bgImg = _card.backgroundImage || ''
-
-        if (bgImg && /^linear-gradient/.test(bgImg)) {
-          bgImg = bgImg.replace('linear-gradient(', '')
-          bgImg = bgImg.replace(')', '')
-        } else if (bgImg && /^url/.test(bgImg)) {
-          bgImg = bgImg.replace('url(', '')
-          bgImg = bgImg.replace(')', '')
-        }
-
-        this.setState({
-          card: _card,
-          fontColor: _card.color || '#000000',
-          backgroundColor: _card.backgroundColor || '#ffffff',
-          backgroundImage: bgImg,
-          marginTop: _card.marginTop ? _card.marginTop : '',
-          marginTopVal: _card.marginTop ? parseInt(_card.marginTop) : '',
-          marginBottom: _card.marginBottom ? _card.marginBottom : '',
-          marginBottomVal: _card.marginBottomVal ? parseInt(_card.marginBottomVal) : ''
-        })
-      })
-    }
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  updateStyle = (style) => {
-    const { card } = this.state
-
-    this.props.updateStyle({componentId: card.componentId, classId: card.classId, uuid: card.uuid, style})
-  }
-
-  /**
-   * @description 瀛椾綋澶у皬鍒囨崲锛岃秴鍑鸿寖鍥村拷鐣�
-   */
-  changeFontSize = (val) => {
-    let value = parseInt(val)
-
-    if (isNaN(value) || value < 12 || value > 100) return
-
-    this.updateStyle({fontSize: `${value}px`})
-  }
-
-  /**
-   * @description 淇敼琛岄棿璺濓紝瓒呭嚭鑼冨洿蹇界暐
-   */
-  changeLineHeight = (val) => {
-    let value = parseFloat(val)
-
-    if (isNaN(value) || value < 1 || value > 10) return
-
-    this.updateStyle({lineHeight: value})
-  }
-
-  /**
-   * @description 瀛椾綋闂磋窛淇敼锛岃秴鍑鸿寖鍥村拷鐣�
-   */
-  changeLetterSpacing = (val) => {
-    let value = parseFloat(val)
-
-    if (isNaN(value) || value < 0 || value > 100) return
-
-    this.updateStyle({letterSpacing: `${value}px`})
-  }
-
-  /**
-   * @description 淇敼瀛椾綋绮楃粏
-   */
-  boldChange = (val) => {
-    this.updateStyle({fontWeight: val})
-  }
-
-  /**
-   * @description 淇敼瀛椾綋棰滆壊 锛岄鑹叉帶浠�
-   */
-  changeFontColor = (val) => {
-    this.setState({
-      fontColor: val
-    })
-    this.updateStyle({color: val})
-  }
-
-  /**
-   * @description 淇敼瀛椾綋棰滆壊 锛屾墜鍔ㄨ緭鍏�
-   */
-  changeFontColorInput = (e) => {
-    this.setState({
-      fontColor: e.target.value
-    })
-  }
-
-  /**
-   * @description 瀛椾綋瀵归綈
-   */
-  changeTextAlign = (e) => {
-    this.updateStyle({textAlign: e.target.value})
-  }
-
-  /**
-   * @description 瀛椾綋鏍峰紡锛屽�炬枩
-   */
-  changeFontStyle = (e) => {
-    this.updateStyle({fontStyle: e.target.value})
-  }
-
-  /**
-   * @description 瀛椾綋瑁呴グ锛屼笅鍒掔嚎銆佽疮绌跨嚎銆佷笂鍒掔嚎
-   */
-  changeTextDecoration = (e) => {
-    this.updateStyle({textDecoration: e.target.value})
-  }
-
-  /**
-   * @description 淇敼鑳屾櫙棰滆壊 锛岄鑹叉帶浠�
-   */
-  changeBackgroundColor = (val) => {
-    this.setState({
-      backgroundColor: val
-    })
-    this.updateStyle({backgroundColor: val})
-  }
-
-  /**
-   * @description 淇敼瀛椾綋棰滆壊 锛屾墜鍔ㄨ緭鍏�
-   */
-  changeBackgroundColorInput = (e) => {
-    this.setState({
-      backgroundColor: e.target.value
-    })
-  }
-
-  imgChange = (list) => {
-    if (list[0] && list[0].response) {
-      this.setState({
-        bgimages: [],
-        backgroundImage: list[0].response
-      })
-      this.updateStyle({backgroundImage: `url(${list[0].response})`})
-    } else {
-      this.setState({bgimages: list})
-    }
-  }
-
-  changeBackgroundImageInput = (e) => {
-    this.setState({
-      backgroundImage: e.target.value
-    })
-  }
-
-  submitBackgroundImage = (e) => {
-    let val = e.target.value
-    val = val.replace(/^\s*|\s*$/ig, '')
-
-    if (/^http|^\/\//.test(val)) {
-      val = `url(${val})`
-    } else if (/^#|,/ig.test(val)) {
-      val = `linear-gradient(${val})`
-    }
-
-    this.updateStyle({backgroundImage: val})
-  }
-
-  submitBorder = (val, type) => {
-    this.updateStyle({[type]: val})
-  }
-
-  changeBorderRadius = (val) => {
-    let value = parseFloat(val)
-
-    if (isNaN(value) || value < 0 || value > 500) return
-
-    this.updateStyle({borderRadius: `${value}px`})
-  }
-
-  changeMarginTop = (e) => {
-    let val = e.target.value
-    let _val = parseInt(val)
-
-    this.setState({
-      marginTop: val
-    })
-
-    if (isNaN(_val)) return
-
-    this.setState({
-      marginTopVal: _val
-    })
-  }
-
-  submitMarginTop = (val) => {
-    this.setState({
-      marginTop: val
-    })
-    this.updateStyle({marginTop: val})
-  }
-
-  changeMarginBottom = (e) => {
-    let val = e.target.value
-    let _val = parseInt(val)
-
-    this.setState({
-      marginBottom: val
-    })
-
-    if (isNaN(_val)) return
-
-    this.setState({
-      marginBottomVal: _val
-    })
-  }
-
-  submitMarginBottom = (val) => {
-    this.setState({
-      marginBottom: val
-    })
-    this.updateStyle({marginBottom: val})
-  }
-
-  render () {
-    const { card, backgroundImage, bgimages, marginTop, marginTopVal, marginBottom, marginBottomVal } = this.state
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 }
-      }
-    }
-
-    return (
-      <div className="mob-controller">
-        <Form {...formItemLayout}>
-          {card ? <Collapse expandIconPosition="right" defaultActiveKey={card.items[0]} accordion={true}>
-            {card.items.includes('font') ? <Panel header="瀛椾綋" key="font">
-              <Col span={12}>
-                <Form.Item colon={false} label={<Icon title="瀛椾綋澶у皬" type="font-size" />}>
-                  <InputNumber defaultValue={card.fontSize || 14} min={12} max={100} precision={0} onChange={this.changeFontSize} />
-                </Form.Item>
-              </Col>
-              <Col span={12}>
-                <Form.Item colon={false} label={<Icon title="瀛椾綋绮楃粏" type="bold" />}>
-                  <Select defaultValue={card.fontWeight || 'normal'} onChange={this.boldChange}>
-                    <Option value="normal">normal</Option>
-                    <Option value="bold">bold</Option>
-                    <Option value="bolder">bolder</Option>
-                    <Option value="lighter">lighter</Option>
-                    <Option value="100">100</Option>
-                    <Option value="200">200</Option>
-                    <Option value="300">300</Option>
-                    <Option value="400">400</Option>
-                    <Option value="500">500</Option>
-                    <Option value="600">600</Option>
-                    <Option value="700">700</Option>
-                    <Option value="800">800</Option>
-                    <Option value="900">900</Option>
-                  </Select>
-                </Form.Item>
-              </Col>
-              <Col span={12}>
-                <Form.Item colon={false} label={<Icon title="琛岄棿璺�" type="line-height" />}>
-                  <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 || 0} min={0} max={100} precision={0} onChange={this.changeLetterSpacing}/>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="瀛椾綋棰滆壊" type="font-colors" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <ColorSketch value={card.color || '#000000'} onChange={this.changeFontColor} />
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={' '}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Radio.Group defaultValue={card.fontStyle || 'normal'} onChange={this.changeFontStyle}>
-                    <Radio.Button value="normal"><span title="鏍囧噯">N</span></Radio.Button>
-                    <Radio.Button value="italic"><Icon title="鏂滀綋" type="italic" /></Radio.Button>
-                    <Radio.Button value="oblique" style={{fontStyle: 'oblique'}}><span title="鍊炬枩">B</span></Radio.Button>
-                  </Radio.Group>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={' '}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Radio.Group className="text-align" defaultValue={card.textAlign || 'left'} onChange={this.changeTextAlign}>
-                    <Radio.Button value="left"><Icon title="宸﹀榻�" type="align-left" /></Radio.Button>
-                    <Radio.Button value="center"><Icon title="灞呬腑瀵归綈" type="align-center" /></Radio.Button>
-                    <Radio.Button value="right"><Icon title="鍙冲榻�" type="align-right" /></Radio.Button>
-                  </Radio.Group>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={' '}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Radio.Group className="text-decoration" defaultValue={card.textDecoration || 'none'} onChange={this.changeTextDecoration}>
-                    <Radio.Button value="none"><span title="鏍囧噯">N</span></Radio.Button>
-                    <Radio.Button value="underline"><Icon title="涓嬪垝绾�" type="underline" /></Radio.Button>
-                    <Radio.Button value="line-through"><Icon title="涓垝绾�" type="strikethrough" /></Radio.Button>
-                    <Radio.Button value="overline" style={{textDecoration: 'overline'}}><span title="涓婂垝绾�">O</span></Radio.Button>
-                  </Radio.Group>
-                </Form.Item>
-              </Col>
-            </Panel> : null}
-            {card.items.includes('background') ? <Panel header="鑳屾櫙" key="background">
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="鑳屾櫙棰滆壊" type="bg-colors" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <ColorSketch value={card.backgroundColor || '#ffffff'} onChange={this.changeBackgroundColor} />
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="鑳屾櫙鍥剧墖" type="picture" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <FileUpload accept=".jpg,.png,.gif,.svg" value={bgimages} maxFile={2} fileType="text" onChange={this.imgChange}/>
-                  <Input placeholder="" value={backgroundImage} autoComplete="off" onBlur={this.submitBackgroundImage} onPressEnter={this.submitBackgroundImage} onChange={this.changeBackgroundImageInput} />
-                </Form.Item>
-              </Col>
-            </Panel> : null}
-            {card.items.includes('border') ? <Panel header="杈规" key="border">
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="澶栬竟妗�" type="border-outer" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Input placeholder="" defaultValue={card.border || ''} autoComplete="off" onBlur={(e) => this.submitBorder(e.target.value, 'border')} onPressEnter={(e) => this.submitBorder(e.target.value, 'border')}/>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="宸﹁竟妗�" type="border-left" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Input placeholder="" defaultValue={card.borderLeft || ''} autoComplete="off" onBlur={(e) => this.submitBorder(e.target.value, 'borderLeft')} onPressEnter={(e) => this.submitBorder(e.target.value, 'borderLeft')}/>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="鍙宠竟妗�" type="border-right" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Input placeholder="" defaultValue={card.borderRight || ''} autoComplete="off" onBlur={(e) => this.submitBorder(e.target.value, 'borderRight')} onPressEnter={(e) => this.submitBorder(e.target.value, 'borderRight')}/>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="涓婅竟妗�" type="border-top" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Input placeholder="" defaultValue={card.borderTop || ''} autoComplete="off" onBlur={(e) => this.submitBorder(e.target.value, 'borderTop')} onPressEnter={(e) => this.submitBorder(e.target.value, 'borderTop')}/>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="涓嬭竟妗�" type="border-bottom" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <Input placeholder="" defaultValue={card.borderBottom || ''} autoComplete="off" onBlur={(e) => this.submitBorder(e.target.value, 'borderBottom')} onPressEnter={(e) => this.submitBorder(e.target.value, 'borderBottom')}/>
-                </Form.Item>
-              </Col>
-              <Col span={24}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="鍦嗚" type="radius-setting" />}
-                  labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
-                >
-                  <InputNumber defaultValue={card.borderRadius || 0} min={0} max={500} precision={0} onChange={this.changeBorderRadius}/>
-                </Form.Item>
-              </Col>
-            </Panel> : null}
-            {card.items.includes('margin') ? <Panel header="澶栬竟璺�" key="margin">
-              <Col span={12}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="涓婅竟璺�" type="vertical-align-top"/>}
-                >
-                  <Popover placement="bottom" overlayClassName="margin-popover" content={
-                    marginTopVal !== '' ?
-                    <Menu>
-                      <Menu.Item onClick={() => this.submitMarginTop(`${marginTopVal}px`)}>{marginTopVal} px</Menu.Item>
-                      <Menu.Item onClick={() => this.submitMarginTop(`${marginTopVal}vh`)}>{marginTopVal} vh</Menu.Item>
-                    </Menu> : null
-                  } trigger="hover">
-                    <Input value={marginTop} onChange={this.changeMarginTop}/>
-                  </Popover>
-                </Form.Item>
-              </Col>
-              <Col span={12}>
-                <Form.Item
-                  colon={false}
-                  label={<Icon title="涓嬭竟璺�" type="vertical-align-bottom"/>}
-                >
-                  <Popover placement="bottom" overlayClassName="margin-popover" content={
-                    marginBottomVal !== '' ?
-                    <Menu>
-                      <Menu.Item onClick={() => this.submitMarginBottom(`${marginBottomVal}px`)}>{marginBottomVal} px</Menu.Item>
-                      <Menu.Item onClick={() => this.submitMarginBottom(`${marginBottomVal}vh`)}>{marginBottomVal} vh</Menu.Item>
-                    </Menu> : null
-                  } trigger="hover">
-                    <Input value={marginBottom} onChange={this.changeMarginBottom}/>
-                  </Popover>
-                </Form.Item>
-              </Col>
-            </Panel> : null}
-          </Collapse> : null}
-        </Form>
-      </div>
-    )
-  }
-}
-
-export default MobController
\ No newline at end of file
diff --git a/src/mob/controller/index.scss b/src/mob/controller/index.scss
deleted file mode 100644
index 6acbf69..0000000
--- a/src/mob/controller/index.scss
+++ /dev/null
@@ -1,147 +0,0 @@
-.mob-controller {
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-  >.ant-form >.ant-collapse {
-    border: 0;
-    background: #262E3F;
-
-    > .ant-collapse-item {
-      border-color: #202735;
-      > .ant-collapse-header {
-        padding: 10px 40px 10px 16px;
-        background: #262E3F;
-        color: rgba(255, 255, 255, 0.85);
-      }
-      >.ant-collapse-content {
-        color: rgba(255, 255, 255, 0.85);
-        background-color: #202735;
-        border-top: 1px solid #202735;
-        .ant-input-number {
-          width: 100%;
-        }
-        .ant-form-item {
-          margin-bottom: 5px;
-
-          .ant-form-item-label > label {
-            color: rgba(255, 255, 255, 0.85);
-            .anticon {
-              vertical-align: middle;
-              font-size: 18px;
-            }
-          }
-          .ant-form-item-control-wrapper  {
-            .ant-form-item-control {
-              input {
-                background: transparent;
-                color: rgba(255, 255, 255, 0.65);
-              }
-              .ant-input {
-                height: 28px;
-              }
-              .ant-input-number {
-                height: 28px;
-                background: transparent;
-                .ant-input-number-input {
-                  height: 28px;
-                }
-              }
-              .ant-select-selection {
-                background: transparent;
-                color: rgba(255, 255, 255, 0.65);
-              }
-              .color-sketch-block {
-                position: relative;
-                top: 10px;
-              }
-              .color-sketch-block + .ant-input {
-                float: right;
-                width: 70%;
-                margin-top: 9px;
-                padding-right: 5px;
-                padding-left: 5px;
-              }
-              .ant-select-arrow {
-                color: inherit;
-              }
-              .ant-input-number-handler-wrap {
-                background: transparent;
-                .ant-input-number-handler {
-                  color: rgba(255, 255, 255, 0.65);
-                  .ant-input-number-handler-up-inner, .ant-input-number-handler-down-inner {
-                    color: rgba(255, 255, 255, 0.65);
-                  }
-                }
-                .ant-input-number-handler:active {
-                  background: transparent;
-                }
-              }
-              .ant-radio-group {
-                .ant-radio-button-wrapper {
-                  background: transparent;
-                  color: rgba(255, 255, 255, 0.65);
-                  height: 27px;
-                  line-height: 25px;
-                  span {
-                    font-style: inherit;
-                  }
-                }
-              }
-              .fileupload-form-container {
-                .ant-btn {
-                  height: 28px;
-                }
-                .ant-upload-list-item {
-                  .ant-upload-list-item-info {
-                    background: transparent;
-                    color: rgba(255, 255, 255, 0.85);
-                    i {
-                      color: rgba(255, 255, 255, 0.85);
-                    }
-                  }
-                  .anticon-close {
-                    color: rgba(255, 255, 255, 0.85);
-                  }
-                  .anticon-close:hover {
-                    color: rgba(255, 255, 255, 0.85);
-                  }
-                }
-                .ant-upload-list-item:hover .ant-upload-list-item-info {
-                  background: transparent;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-.margin-popover {
-  padding-top: 0px;
-  .ant-popover-inner-content {
-    width: 90px;
-    padding: 0px 5px;
-    .ant-menu-root.ant-menu-vertical {
-      border: 0;
-      .ant-menu-item {
-        height: 30px;
-        cursor: pointer;
-        line-height: 30px;
-      }
-      .ant-menu-item:not(:last-child) {
-        margin-bottom: 0px;
-      }
-      .ant-menu-item:first-child {
-        margin-top: 10px;
-      }
-      .ant-menu-item:last-child {
-        margin-bottom: 10px;
-      }
-    }
-  }
-  .ant-popover-arrow {
-    display: none;
-  }
-}
\ No newline at end of file
diff --git a/src/mob/contupdate/index.jsx b/src/mob/contupdate/index.jsx
deleted file mode 100644
index 95734cf..0000000
--- a/src/mob/contupdate/index.jsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-// import { is, fromJS } from 'immutable'
-import { Form, Icon, Popover, Input, Modal } from 'antd'
-
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import FileUpload from '@/tabviews/zshare/fileupload'
-import './index.scss'
-
-const { TextArea } = Input
-const { confirm } = Modal
-
-class ContentUpdate extends Component {
-  static propTpyes = {
-    deletable: PropTypes.any,
-    element: PropTypes.object,
-    updateContent: PropTypes.func
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    images: [],
-    visible: false
-  }
-
-  UNSAFE_componentWillMount () {
-
-  }
-
-  // shouldComponentUpdate (nextProps, nextState) {
-  //   return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  // }
-
-  onVisibleChange = (visible) => {
-    const { element } = this.props
-    let val = this.props.form.getFieldValue('content')
-    let _url = this.props.form.getFieldValue('url')
-
-    this.setState({
-      visible: visible
-    })
-
-    if (element.eleType === 'link') {
-      if ((val && element.content !== val) || (_url && element.url !== _url)) {
-        this.props.updateContent({...element, content: val, url: _url})
-      } else {
-        this.props.form.setFieldsValue({content: element.content, url: element.url})
-      }
-    } else {
-      if (val && element.content !== val) {
-        this.props.updateContent({...element, content: val})
-      } else {
-        this.props.form.setFieldsValue({content: element.content})
-      }
-    }
-  }
-
-  handleSubmit = () => {
-    const { element } = this.props
-    let val = this.props.form.getFieldValue('content')
-
-    this.setState({
-      visible: false
-    })
-
-    if (val && element.content !== val) {
-      this.props.updateContent({...element, content: val})
-    } else {
-      this.props.form.setFieldsValue({content: element.content})
-    }
-  }
-
-  deleteElement = () => {
-    const _this = this
-
-    confirm({
-      title: '纭畾鍒犻櫎鍏冪礌鍚楋紵',
-      onOk() {
-        _this.props.updateContent(null)
-      },
-      onCancel() {}
-    })
-  }
-
-  imgChange = (list) => {
-    const { element } = this.props
-
-    this.setState({images: list})
-    if (list && list.length && list[0].response) {
-      this.setState({
-        visible: false,
-        images: []
-      })
-      let val = list[0].response
-      if (val && element.content !== val) {
-        this.props.updateContent({...element, content: val})
-      }
-      this.props.form.setFieldsValue({content: val})
-    }
-  }
-
-  render () {
-    const { element, deletable } = this.props
-    const { getFieldDecorator } = this.props.form
-    const { visible, images } = this.state
-
-    return (
-      <div className="mob-content-update">
-        {deletable !== false ? <Icon type="delete" onClick={this.deleteElement} /> : null}
-        <Popover content={
-          <div>
-            {element.eleType === 'img' ? <FileUpload accept=".jpg,.png,.gif,.svg" value={images} maxFile={1} fileType="text" onChange={this.imgChange}/> : null}
-            {getFieldDecorator('content', {
-              initialValue: element.content
-            })(element.eleType !== 'textarea' ?
-              <Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} /> :
-              <TextArea autoSize={{ minRows: 2, maxRows: 3 }} onPressEnter={this.handleSubmit} />
-            )}
-            {element.eleType === 'link' ? <div className="link-url">
-              <p>閾炬帴鍦板潃:</p>
-              {getFieldDecorator('url', {
-                initialValue: element.url
-              })(
-                <Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />
-              )}
-            </div> : null}
-          </div>
-        } overlayClassName="mob-content-update-popover" placement="bottomRight" title="" visible={visible} trigger="click" onVisibleChange={this.onVisibleChange}>
-          <Icon type="edit" />
-        </Popover>
-      </div>
-    )
-  }
-}
-
-export default Form.create()(ContentUpdate)
\ No newline at end of file
diff --git a/src/mob/contupdate/index.scss b/src/mob/contupdate/index.scss
deleted file mode 100644
index 34a4615..0000000
--- a/src/mob/contupdate/index.scss
+++ /dev/null
@@ -1,53 +0,0 @@
-.mob-content-update {
-  position: absolute;
-  top: -22px;
-  right: -1px;
-  border-radius: 2px;
-  color: #ffffff;
-  font-size: 14px;
-  display: none;
-  line-height: 1.5;
-  z-index: 1;
-  white-space: nowrap;
-
-  i {
-    padding: 2px 5px;
-    cursor: pointer;
-    background: #2f54eb;
-  }
-  .anticon-delete {
-    background: #ff4d4f;
-  }
-}
-.editing .mob-content-update {
-  display: inline-block;
-}
-.mob-content-update-popover {
-  .ant-popover-content {
-    margin-top: -5px;
-    .ant-popover-arrow {
-      top: 1px;
-    }
-
-    .fileupload-form-container {
-      display: block;
-      margin-bottom: 10px;
-      .ant-upload-list {
-        width: 250px;
-      }
-    }
-  }
-  input {
-    width: 250px;
-  }
-  textarea {
-    width: 270px;
-  }
-  .link-url {
-    p {
-      margin: 10px 0px 5px 5px;
-      font-size: 14px;
-      color: #959595;
-    }
-  }
-}
diff --git a/src/mob/datasource/index.jsx b/src/mob/datasource/index.jsx
deleted file mode 100644
index 06abe17..0000000
--- a/src/mob/datasource/index.jsx
+++ /dev/null
@@ -1,161 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { Icon, Modal } from 'antd'
-
-import Utils from '@/utils/utils.js'
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import VerifyCard from './verifycard'
-import './index.scss'
-
-const { confirm } = Modal
-
-class DataSource extends Component {
-  static propTpyes = {
-    config: PropTypes.any,
-    updateConfig: PropTypes.func
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    sourcelist: [],
-    searches: [],
-    visible: false,
-    loading: false,
-    source: null
-  }
-
-  UNSAFE_componentWillMount () {
-    const { config } = this.props
-
-    this.setState({sourcelist: config.sourcelist || []})
-  }
-
-  UNSAFE_componentWillReceiveProps(nextProps) {
-
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  editDataSource = (item) => {
-    // const { config } = this.props
-
-    if (!item) {
-      item = {
-        uuid: Utils.getuuid(),
-        setting: {},
-        columns: [],
-        scripts: []
-      }
-    }
-
-    this.setState({
-      visible: true,
-      source: item,
-      searches: []
-    })
-  }
-
-  closeDataSource = (item) => {
-    const { config } = this.props
-    let sourcelist = fromJS(this.state.sourcelist).toJS()
-    const _this = this
-
-    sourcelist = sourcelist.filter(cell => cell.uuid !== item.uuid)
-
-    confirm({
-      title: '纭畾鍒犻櫎鏁版嵁婧愬悧锛�',
-      content: '',
-      onOk() {
-        _this.setState({sourcelist})
-        _this.props.updateConfig({...config, sourcelist: fromJS(sourcelist).toJS()})
-      },
-      onCancel() {}
-    })
-  }
-
-  verifySubmit = () => {
-    const { config } = this.props
-    let sourcelist = fromJS(this.state.sourcelist).toJS()
-
-    this.setState({loading: true})
-    this.verifyRef.submitDataSource().then((res) => {
-      let isadd = true
-      sourcelist = sourcelist.map(item => {
-        if (item.uuid === res.uuid) {
-          isadd = false
-          return res
-        } else {
-          return item
-        }
-      })
-
-      if (isadd) {
-        sourcelist.push(res)
-      }
-      
-      this.setState({loading: false, visible: false, sourcelist})
-      this.props.updateConfig({...config, sourcelist: fromJS(sourcelist).toJS()})
-    }, () => {
-      this.setState({loading: false})
-    })
-  }
-
-  render () {
-    const { config } = this.props
-    const { sourcelist, visible, source, dict, searches, loading } = this.state
-
-    let addable = true
-    if (config.components && config.components.length === 1 && config.components[0].type === 'login') {
-      addable = false
-    }
-
-    return (
-      <div className="mob-datasource">
-        {sourcelist.map(item => (
-          <span className="mob-input-group-wrapper" key={item.uuid}>
-            <span className="mob-input-wrapper">
-              <span className="mob-input-value">{item.setting.name}</span>
-              <span className="mob-input-group-addon">
-                <Icon type="setting" onClick={() => this.editDataSource(item)} />
-                <Icon type="close" onClick={() => this.closeDataSource(item)} />
-              </span>
-            </span>
-          </span>
-        ))}
-        {addable ? <span className="mob-input-group-wrapper">
-          <span className="mob-input-wrapper">
-            <span className="mob-input-insert" onClick={() => this.editDataSource()}>
-              <Icon type="plus" />
-            </span>
-          </span>
-        </span> : null}
-        <Modal
-          wrapClassName="mob-datasource-verify-modal popview-modal"
-          title={'鏁版嵁婧愰厤缃�'}
-          visible={visible}
-          width={'75vw'}
-          maskClosable={false}
-          okText={dict['mob.submit']}
-          onOk={this.verifySubmit}
-          confirmLoading={loading}
-          onCancel={() => { this.setState({ visible: false }) }}
-          destroyOnClose
-        >
-          <VerifyCard
-            dict={dict}
-            card={source}
-            menuId={this.props.config.uuid}
-            searches={searches}
-            wrappedComponentRef={(inst) => this.verifyRef = inst}
-          />
-        </Modal>
-      </div>
-    )
-  }
-}
-
-export default DataSource
\ No newline at end of file
diff --git a/src/mob/datasource/index.scss b/src/mob/datasource/index.scss
deleted file mode 100644
index ea28922..0000000
--- a/src/mob/datasource/index.scss
+++ /dev/null
@@ -1,89 +0,0 @@
-.mob-datasource {
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-  padding-top: 15px;
-
-  .mob-input-group-wrapper {
-    padding: 0 20px;
-    display: inline-block;
-    width: 100%;
-    text-align: start;
-    vertical-align: top;
-    margin-bottom: 15px;
-
-    .mob-input-wrapper {
-      position: relative;
-      display: table;
-      width: 100%;
-      border-collapse: separate;
-      border-spacing: 0;
-
-      .mob-input-value {
-        display: table-cell;
-        width: 100%;
-        border: 1px solid #d9d9d9;
-        border-radius: 4px 0px 0px 4px;
-        overflow: hidden;
-        text-overflow:ellipsis;
-        white-space: nowrap;
-        padding: 2px 10px;
-        color: #ffffff;
-      }
-
-      .mob-input-group-addon {
-        display: table-cell;
-        width: 1px;
-        position: relative;
-        padding: 0 11px;
-        color: rgba(0, 0, 0, 0.65);
-        font-weight: normal;
-        font-size: 14px;
-        line-height: 1;
-        text-align: center;
-        background-color: #fafafa;
-        border: 1px solid #d9d9d9;
-        border-radius: 0px 4px 4px 0px;
-        white-space: nowrap;
-      }
-
-      .mob-input-insert {
-        display: table-cell;
-        width: 100%;
-        border: 1px dotted #d9d9d9;
-        border-radius: 4px;
-        text-align: center;
-        cursor: pointer;
-
-        .anticon-plus {
-          padding: 6px;
-          font-size: 16px;
-          color: rgb(38, 194, 129);
-        }
-      }
-    }
-    .anticon-setting {
-      margin-right: 5px;
-      padding: 6px;
-      cursor: pointer;
-    }
-    .anticon-setting:hover {
-      color: #1890ff;
-    }
-    .anticon-close {
-      padding: 6px;
-      cursor: pointer;
-    }
-    .anticon-close:hover {
-      color: #ff4d4f;
-    }
-  }
-}
-.mob-datasource-verify-modal {
-  .ant-modal {
-    top: 50px;
-    .ant-modal-body {
-      max-height: calc(100vh - 190px);
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/columnform/index.jsx b/src/mob/datasource/verifycard/columnform/index.jsx
deleted file mode 100644
index 31fbe81..0000000
--- a/src/mob/datasource/verifycard/columnform/index.jsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Form, Row, Col, Select, Button, Input } from 'antd'
-import './index.scss'
-
-
-class UniqueForm extends Component {
-  static propTpyes = {
-    dict: PropTypes.object,       // 瀛楀吀椤�
-    columnChange: PropTypes.func  // 淇敼鍑芥暟
-  }
-
-  state = {
-    editItem: null // 缂栬緫鍏冪礌
-  }
-
-  edit = (record) => {
-    this.setState({
-      editItem: record
-    })
-
-    this.props.form.setFieldsValue({
-      label: record.label,
-      field: record.field,
-      datatype: record.datatype
-    })
-  }
-
-
-  handleConfirm = () => {
-    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
-    this.props.form.validateFieldsAndScroll((err, values) => {
-      if (!err) {
-        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
-
-        this.setState({
-          editItem: null
-        }, () => {
-          this.props.columnChange(values)
-        })
-        this.props.form.setFieldsValue({
-          label: '',
-          field: ''
-        })
-      }
-    })
-  }
-
-  render() {
-    const { getFieldDecorator } = this.props.form
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 }
-      }
-    }
-
-    return (
-      <Form {...formItemLayout} className="verify-form" id="verifycard1">
-        <Row gutter={24}>
-          <Col span={7}>
-            <Form.Item label={'鍚嶇О'}>
-              {getFieldDecorator('label', {
-                initialValue: '',
-                rules: [
-                  {
-                    required: true,
-                    message: this.props.dict['form.required.input'] + '鍚嶇О!'
-                  }
-                ]
-              })(<Input placeholder="" autoComplete="off" />)}
-            </Form.Item>
-          </Col>
-          <Col span={7}>
-            <Form.Item label={'瀛楁'}>
-              {getFieldDecorator('field', {
-                initialValue: '',
-                rules: [
-                  {
-                    required: true,
-                    message: this.props.dict['form.required.input'] + '瀛楁!'
-                  }
-                ]
-              })(<Input placeholder="" autoComplete="off" />)}
-            </Form.Item>
-          </Col>
-          <Col span={7}>
-            <Form.Item label={'鏁版嵁绫诲瀷'}>
-              {getFieldDecorator('datatype', {
-                initialValue: '',
-                rules: [
-                  {
-                    required: true,
-                    message: this.props.dict['form.required.select'] + '鏁版嵁绫诲瀷!'
-                  }
-                ]
-              })(
-                <Select>
-                  <Select.Option value="Nvarchar(10)"> Nvarchar(10) </Select.Option>
-                  <Select.Option value="Nvarchar(20)"> Nvarchar(20) </Select.Option>
-                  <Select.Option value="Nvarchar(50)"> Nvarchar(50) </Select.Option>
-                  <Select.Option value="Nvarchar(100)"> Nvarchar(100) </Select.Option>
-                  <Select.Option value="Nvarchar(512)"> Nvarchar(512) </Select.Option>
-                  <Select.Option value="Nvarchar(1024)"> Nvarchar(1024) </Select.Option>
-                  <Select.Option value="Nvarchar(2048)"> Nvarchar(2048) </Select.Option>
-                  <Select.Option value="Nvarchar(max)"> Nvarchar(max) </Select.Option>
-                  <Select.Option value="Int"> Int </Select.Option>
-                  <Select.Option value="Decimal(18,0)"> Decimal(18,0) </Select.Option>
-                  <Select.Option value="Decimal(18,1)"> Decimal(18,1) </Select.Option>
-                  <Select.Option value="Decimal(18,2)"> Decimal(18,2) </Select.Option>
-                  <Select.Option value="Decimal(18,3)"> Decimal(18,3) </Select.Option>
-                  <Select.Option value="Decimal(18,4)"> Decimal(18,4) </Select.Option>
-                  <Select.Option value="Decimal(18,5)"> Decimal(18,5) </Select.Option>
-                  <Select.Option value="Decimal(18,6)"> Decimal(18,6) </Select.Option>
-                  <Select.Option value="Decimal(18,7)"> Decimal(18,7) </Select.Option>
-                  <Select.Option value="Decimal(18,8)"> Decimal(18,8) </Select.Option>
-                  <Select.Option value="date"> date </Select.Option>
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-          <Col span={3} className="add">
-            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
-              淇濆瓨
-            </Button>
-          </Col>
-        </Row>
-      </Form>
-    )
-  }
-}
-
-export default Form.create()(UniqueForm)
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/columnform/index.scss b/src/mob/datasource/verifycard/columnform/index.scss
deleted file mode 100644
index e69de29..0000000
--- a/src/mob/datasource/verifycard/columnform/index.scss
+++ /dev/null
diff --git a/src/mob/datasource/verifycard/customscript/index.jsx b/src/mob/datasource/verifycard/customscript/index.jsx
deleted file mode 100644
index 5267ea7..0000000
--- a/src/mob/datasource/verifycard/customscript/index.jsx
+++ /dev/null
@@ -1,229 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Form, Row, Col, Button, notification, Select } from 'antd'
-
-import Utils from '@/utils/utils.js'
-import CodeMirror from '@/templates/zshare/codemirror'
-import './index.scss'
-
-class CustomForm extends Component {
-  static propTpyes = {
-    type: PropTypes.string,         // 鑿滃崟绫诲瀷
-    dict: PropTypes.object,         // 瀛楀吀椤�
-    setting: PropTypes.object,      // 璁剧疆
-    searches: PropTypes.array,      // 鎼滅储鏉′欢
-    swhere: PropTypes.string,       // where鏉′欢
-    arr_field: PropTypes.string,    // 鍒楀瓧娈�
-    regoptions: PropTypes.array,    // 姝e垯鏇挎崲
-    systemScripts: PropTypes.array, // 绯荤粺鑴氭湰
-    scriptSubmit: PropTypes.func,   // 鑴氭湰楠岃瘉鍚庢彁浜�
-    scriptsChange: PropTypes.func   // 鑴氭湰楠岃瘉
-  }
-
-  state = {
-    editItem: null,
-    loading: false,
-    usefulFields: ''
-  }
-
-  UNSAFE_componentWillMount() {
-    const { searches } = this.props
-
-    let _usefulFields = []
-    searches.forEach(item => {
-      if (item.type === 'group') {
-        if (item.transfer === 'true') {
-          _usefulFields.push(item.field)
-        }
-        _usefulFields.push(item.datefield)
-        _usefulFields.push(item.datefield + '1')
-      } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
-        _usefulFields.push(item.field)
-        _usefulFields.push(item.field + '1')
-      } else if (_usefulFields.includes(item.field)) {
-        _usefulFields.push(item.field + '1')
-      } else {
-        _usefulFields.push(item.field)
-      }
-    })
-
-    this.setState({
-      usefulFields: _usefulFields.join(', ')
-    })
-  }
-
-  edit = (record) => {
-    this.setState({
-      editItem: record
-    })
-
-    this.props.form.setFieldsValue({
-      sql: record.sql
-    })
-  }
-
-  handleCancel = () => {
-    this.setState({
-      editItem: null
-    })
-    this.props.form.setFieldsValue({
-      sql: ''
-    })
-  }
-
-  handleConfirm = () => {
-    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
-    this.props.form.validateFieldsAndScroll((err, values) => {
-      if (!err) {
-        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
-
-        let _quot = values.sql.match(/'{1}/g)
-        let _lparen = values.sql.match(/\({1}/g)
-        let _rparen = values.sql.match(/\){1}/g)
-
-        _quot = _quot ? _quot.length : 0
-        _lparen = _lparen ? _lparen.length : 0
-        _rparen = _rparen ? _rparen.length : 0
-
-        if (_quot % 2 !== 0) {
-          notification.warning({
-            top: 92,
-            message: 'sql涓璡'蹇呴』鎴愬鍑虹幇',
-            duration: 5
-          })
-          return
-        } else if (_lparen !== _rparen) {
-          notification.warning({
-            top: 92,
-            message: 'sql涓�()蹇呴』鎴愬鍑虹幇',
-            duration: 5
-          })
-          return
-        } else if (/--/ig.test(values.sql)) {
-          notification.warning({
-            top: 92,
-            message: '鑷畾涔塻ql璇彞涓紝涓嶅彲鍑虹幇瀛楃 -- 锛屾敞閲婅鐢� /*鍐呭*/',
-            duration: 5
-          })
-          return
-        }
-
-        let error = Utils.verifySql(values.sql, 'customscript')
-
-        if (error) {
-          notification.warning({
-            top: 92,
-            message: 'sql涓笉鍙娇鐢�' + error,
-            duration: 5
-          })
-          return
-        }
-
-        this.setState({loading: true})
-        this.props.scriptsChange(values).then(() => {
-          this.setState({
-            editItem: null,
-            loading: false
-          })
-          this.props.form.setFieldsValue({
-            sql: ''
-          })
-          this.props.scriptSubmit(values)
-        })
-      }
-    })
-  }
-
-  selectScript = (value, option) => {
-    let _sql = this.props.form.getFieldValue('sql')
-    if (_sql) {
-      _sql = _sql + ` 
-
-      `
-    }
-
-    _sql = _sql.replace(/\s{6}$/, '')
-    _sql = _sql + `/*${option.props.children}*/
-    `
-    _sql = _sql.replace(/\s{4}$/, '')
-    _sql = _sql + value
-
-    this.props.form.setFieldsValue({
-      sql: _sql
-    })
-  }
-
-  render() {
-    const { systemScripts, setting } = this.props
-    const { getFieldDecorator } = this.props.form
-    const { usefulFields } = this.state
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 }
-      }
-    }
-
-    return (
-      <Form {...formItemLayout} className="modal-menu-setting-script">
-        <Row gutter={24}>
-          {setting.tableName ? <Col span={8}>
-            <Form.Item label={'琛ㄥ悕'} style={{whiteSpace: 'nowrap', margin: 0}}>
-              {setting.tableName}
-            </Form.Item>
-          </Col> : null}
-          <Col span={16}>
-            <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0}}>
-              ErrorCode, retmsg
-            </Form.Item>
-          </Col>
-          <Col span={24} className="sqlfield">
-            <Form.Item label={'鍙敤瀛楁'}>
-              id, bid, loginuid, sessionuid, userid, appkey, time_id, orderBy{setting.laypage !== 'false' ? ', pageSize, pageIndex': ''}{usefulFields ? ', ' + usefulFields : ''}
-            </Form.Item>
-          </Col>
-          <Col span={10}>
-            <Form.Item label={'蹇嵎娣诲姞'} style={{marginBottom: 0}}>
-              <Select
-                showSearch
-                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-                onChange={this.selectScript}
-              >
-                {systemScripts.map((option, i) =>
-                  <Select.Option style={{whiteSpace: 'normal'}} key={i} value={option.value}>{option.name}</Select.Option>
-                )}
-              </Select>
-            </Form.Item>
-          </Col>
-          <Col span={6} className="add">
-            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginTop: 5, marginBottom: 15, marginLeft: 30}}>
-              淇濆瓨
-            </Button>
-            <Button onClick={this.handleCancel} style={{marginTop: 5, marginBottom: 15, marginLeft: 10}}>
-              鍙栨秷
-            </Button>
-          </Col>
-          <Col span={24} className="sql">
-            <Form.Item label={'sql'}>
-              {getFieldDecorator('sql', {
-                initialValue: '',
-                rules: [
-                  {
-                    required: true,
-                    message: this.props.dict['mob.required.input'] + 'sql!'
-                  }
-                ]
-              })(<CodeMirror />)}
-            </Form.Item>
-          </Col>
-        </Row>
-      </Form>
-    )
-  }
-}
-
-export default Form.create()(CustomForm)
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/customscript/index.scss b/src/mob/datasource/verifycard/customscript/index.scss
deleted file mode 100644
index 2a1d2d8..0000000
--- a/src/mob/datasource/verifycard/customscript/index.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-.modal-menu-setting-script {
-  .sqlfield {
-    .ant-form-item {
-      margin-bottom: 5px;
-    }
-    .ant-form-item-control {
-      line-height: 24px;
-    }
-    .ant-form-item-label {
-      line-height: 25px;
-    }
-    .ant-form-item-children {
-      line-height: 22px;
-    }
-    .ant-col-sm-8 {
-      width: 10.5%;
-    }
-    .ant-col-sm-16 {
-      width: 89.5%;
-    }
-  }
-  .sql {
-    .ant-col-sm-8 {
-      width: 10.5%;
-    }
-    .ant-col-sm-16 {
-      width: 89.5%;
-      padding-top: 4px;
-    }
-    .CodeMirror {
-      height: 350px;
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/index.jsx b/src/mob/datasource/verifycard/index.jsx
deleted file mode 100644
index 2d619ec..0000000
--- a/src/mob/datasource/verifycard/index.jsx
+++ /dev/null
@@ -1,519 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { fromJS } from 'immutable'
-import { Form, Tabs, Table, Popconfirm, Icon, notification, Modal, Typography, Spin } from 'antd'
-import moment from 'moment'
-
-import Api from '@/api'
-import Utils from '@/utils/utils.js'
-
-import ColForm from './columnform'
-import CustomScriptsForm from './customscript'
-import SettingForm from './settingform'
-import SettingUtils from './utils'
-import './index.scss'
-
-const { TabPane } = Tabs
-const { Paragraph } = Typography
-
-class VerifyCard extends Component {
-  static propTpyes = {
-    dict: PropTypes.object,     // 瀛楀吀椤�
-    card: PropTypes.object,     // 鏁版嵁婧愪俊鎭�
-    menuId: PropTypes.string,   // 鑿滃崟Id
-    searches: PropTypes.array,  // 鎼滅储鏉′欢
-  }
-
-  state = {
-    columns: [],
-    activeKey: 'setting',
-    loading: false,
-    initsql: '',          // sql楠岃瘉鏃跺彉閲忓0鏄庡強璧嬪��
-    usefulfields: '',
-    defaultsql: '',         // 榛樿Sql
-    systemScripts: [],
-    colColumns: [
-      {
-        title: '鍚嶇О',
-        dataIndex: 'label',
-        width: '25%'
-      },
-      {
-        title: '瀛楁',
-        dataIndex: 'field',
-        width: '25%'
-      },
-      {
-        title: '鏁版嵁绫诲瀷',
-        dataIndex: 'datatype',
-        width: '25%',
-      },
-      {
-        title: '鎿嶄綔',
-        align: 'center',
-        width: '25%',
-        dataIndex: 'operation',
-        render: (text, record) =>
-          (<div>
-            <span className="operation-btn" title={this.props.dict['mob.edit']} onClick={() => this.handleEdit(record, 'columns')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
-            <Popconfirm
-              overlayClassName="popover-confirm"
-              title={this.props.dict['mob.query.delete']}
-              onConfirm={() => this.deleteColumn(record)
-            }>
-              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
-            </Popconfirm>
-          </div>)
-      }
-    ],
-    scriptsColumns: [
-      {
-        title: 'SQL',
-        dataIndex: 'sql',
-        width: '60%',
-        render: (text) => (
-          <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
-        )
-      },
-      {
-        title: '鐘舵��',
-        dataIndex: 'status',
-        width: '20%',
-        render: (text, record) => record.status === 'false' ?
-          (
-            <div>
-              {this.props.dict['mob.status.forbidden']}
-              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
-            </div>
-          ) :
-          (
-            <div>
-              {this.props.dict['mob.status.open']}
-              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
-            </div>
-          )
-      },
-      {
-        title: '鎿嶄綔',
-        align: 'center',
-        width: '20%',
-        dataIndex: 'operation',
-        render: (text, record) =>
-          (<div>
-            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
-            <span className="operation-btn" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
-            <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
-            <span className="operation-btn" title={this.props.dict['mob.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
-            <Popconfirm
-              overlayClassName="popover-confirm"
-              title={this.props.dict['mob.query.delete']}
-              onConfirm={() => this.deleteScript(record)
-            }>
-              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
-            </Popconfirm>
-          </div>)
-      }
-    ]
-  }
-
-  UNSAFE_componentWillMount() {
-    const { card } = this.props
-
-    this.setState({
-      columns: fromJS(card.columns).toJS(),
-      setting: fromJS(card.setting).toJS(),
-      scripts: fromJS(card.scripts).toJS()
-    })
-  }
-
-  getsysScript = () => {
-    let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from聽 s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
-
-    _scriptSql = Utils.formatOptions(_scriptSql)
-
-    let _sParam = {
-      func: 'sPC_Get_SelectedList',
-      LText: _scriptSql,
-      obj_name: 'data',
-      arr_field: 'funcname,longparam'
-    }
-    
-    _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
-
-    _sParam.open_key = Utils.encryptOpenKey(_sParam.secretkey, _sParam.timestamp) // 浜戠鏁版嵁楠岃瘉
-    
-    Api.getSystemConfig(_sParam).then(res => {
-      if (res.status) {
-        let _scripts = []
-
-        res.data.forEach(item => {
-          let _item = {
-            name: item.funcname,
-            value: window.decodeURIComponent(window.atob(item.longparam))
-          }
-
-          _scripts.push(_item)
-        })
-
-        this.setState({
-          systemScripts: _scripts
-        })
-      } else {
-        notification.warning({
-          top: 92,
-          message: res.message,
-          duration: 5
-        })
-      }
-    })
-  }
-
-  columnChange = (values) => {
-    let columns = fromJS(this.state.columns).toJS()
-
-    if (values.uuid) {
-      columns = columns.map(item => {
-        if (item.uuid === values.uuid) {
-          return values
-        } else {
-          return item
-        }
-      })
-    } else {
-      values.uuid = Utils.getuuid()
-      columns.push(values)
-    }
-
-    this.setState({ columns })
-  }
-
-  deleteColumn = (record) => {
-    this.setState({ columns: this.state.columns.filter(item => item.uuid !== record.uuid) })
-  }
-
-  deleteScript = (record) => {
-    this.setState({ scripts: this.state.scripts.filter(item => item.uuid !== record.uuid) })
-  }
-
-  handleEdit = (record, type) => {
-    if (type === 'scripts') {
-      this.scriptsForm.edit(record)
-    } else if (type === 'columns') {
-      this.contrastForm.edit(record)
-    }
-
-    let node = document.getElementById('mob-verify-card-box-tab').parentNode
-
-    if (node && node.scrollTop) {
-      let inter = Math.ceil(node.scrollTop / 10)
-
-      let timer = setInterval(() => {
-        if (node.scrollTop - inter > 0) {
-          node.scrollTop = node.scrollTop - inter
-        } else {
-          node.scrollTop = 0
-          clearInterval(timer)
-        }
-      }, 10)
-    }
-  }
-
-  handleStatus = (record) => {
-    let scripts = fromJS(this.state.scripts).toJS()
-    record.status = record.status === 'false' ? 'true' : 'false'
-
-    scripts = scripts.map(item => {
-      if (item.uuid === record.uuid) {
-        return record
-      } else {
-        return item
-      }
-    })
-
-    this.setState({ scripts })
-  }
-
-  handleUpDown = (record, direction) => {
-    let scripts = fromJS(this.state.scripts).toJS()
-    let index = 0
-
-    scripts = scripts.filter((item, i) => {
-      if (item.uuid === record.uuid) {
-        index = i
-      }
-
-      return item.uuid !== record.uuid
-    })
-    if ((index === 0 && direction === 'up') || (index === scripts.length && direction === 'down')) {
-      return
-    }
-
-    if (direction === 'up') {
-      scripts.splice(index - 1, 0, record)
-    } else {
-      scripts.splice(index + 1, 0, record)
-    }
-
-    this.setState({ scripts })
-  }
-
-  scriptsChange = (values) => {
-    let scripts = fromJS(this.state.scripts).toJS()
-
-    if (values.uuid) {
-      scripts = scripts.map(item => {
-        if (item.uuid === values.uuid) {
-          return values
-        } else {
-          return item
-        }
-      })
-    } else {
-      scripts.push(values)
-    }
-
-    return new Promise((resolve, reject) => {
-      this.sqlverify(resolve, reject, false, scripts)
-    })
-  }
-
-  scriptSubmit = (values) => {
-    let scripts = fromJS(this.state.scripts).toJS()
-
-    if (values.uuid) {
-      scripts = scripts.map(item => {
-        if (item.uuid === values.uuid) {
-          return values
-        } else {
-          return item
-        }
-      })
-    } else {
-      values.uuid = Utils.getuuid()
-      scripts.push(values)
-    }
-
-    this.setState({ scripts })
-  }
-
-  changeTab = (val) => {
-    const { activeKey } = this.state
-
-    this.setState({loading: true})
-    if (activeKey === 'setting') {
-      this.settingForm.handleConfirm().then(res => {
-        this.setState({
-          setting: res
-        }, () => {
-          this.sqlverify(() => { // 楠岃瘉鎴愬姛
-            this.setState({
-              activeKey: val,
-              loading: false
-            })
-          }, () => {             // 楠岃瘉澶辫触
-            this.setState({
-              loading: false
-            })
-          }, true)
-        })
-      }, () => {
-        this.setState({loading: false})
-      })
-    } else if (activeKey === 'columns') {
-      this.sqlverify(() => { // 楠岃瘉鎴愬姛
-        this.setState({
-          activeKey: val,
-          loading: false
-        })
-      }, () => {             // 楠岃瘉澶辫触
-        this.setState({
-          loading: false
-        })
-      }, true)
-    } else if (activeKey === 'scripts') {
-      let _loading = false
-      if (this.scriptsForm && this.scriptsForm.state.editItem) {
-        _loading = true
-      } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
-        _loading = true
-      }
-
-      if (_loading) {
-        notification.warning({
-          top: 92,
-          message: '瀛樺湪鏈繚瀛樿剼鏈紝璇风偣鍑荤‘瀹氫繚瀛橈紝鎴栫偣鍑诲彇娑堟斁寮冧慨鏀癸紒',
-          duration: 5
-        })
-        this.setState({
-          loading: false
-        })
-        return
-      }
-
-      this.sqlverify(() => { // 楠岃瘉鎴愬姛
-        this.setState({
-          activeKey: val,
-          loading: false
-        })
-      }, () => {             // 楠岃瘉澶辫触
-        this.setState({
-          loading: false
-        })
-      }, true)
-    }
-  }
-
-  submitDataSource = () => {
-    const { card } = this.props
-    const { activeKey, setting, columns, scripts } = this.state
-
-    return new Promise((resolve, reject) => {
-      if (activeKey === 'setting') {
-        this.settingForm.handleConfirm().then(res => {
-          this.setState({
-            setting: res
-          }, () => {
-            this.sqlverify(() => { resolve({uuid: card.uuid, setting: res, columns, scripts }) }, reject, false)
-          })
-        }, () => {
-          reject()
-        })
-      } else if (activeKey === 'columns') {
-        this.sqlverify(() => { resolve({uuid: card.uuid, setting, columns, scripts }) }, reject, false)
-      } else if (activeKey === 'scripts') {
-        let _loading = false
-        if (this.scriptsForm && this.scriptsForm.state.editItem) {
-          _loading = true
-        } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
-          _loading = true
-        }
-
-        if (_loading) {
-          notification.warning({
-            top: 92,
-            message: '瀛樺湪鏈繚瀛樿剼鏈紝璇风偣鍑荤‘瀹氫繚瀛橈紝鎴栫偣鍑诲彇娑堟斁寮冧慨鏀癸紒',
-            duration: 5
-          })
-          reject()
-          return
-        }
-
-        this.sqlverify(() => { resolve({uuid: card.uuid, setting, columns, scripts }) }, reject, false)
-      }
-    })
-  }
-
-  sqlverify = (resolve, reject, change = false, testScripts) => {
-    const { searches } = this.props
-    const { columns, setting, scripts } = this.state
-
-    let _scripts = scripts.filter(item => item.status !== 'false')
-
-    if (testScripts) {
-      _scripts = testScripts.filter(item => item.status !== 'false')
-    }
-    if (!change && setting.interType === 'system' && setting.execute === 'false' && _scripts.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '涓嶆墽琛岄粯璁ql鏃讹紝璇锋坊鍔犺嚜瀹氫箟鑴氭湰锛�',
-        duration: 5
-      })
-      reject()
-      return
-    }
-
-    if ((setting.interType === 'system' && setting.execute !== 'false') || _scripts.length > 0) {
-      let param = {
-        func: 's_debug_sql',
-        exec_type: 'y',
-        LText: SettingUtils.getDebugSql(setting, _scripts, columns, searches)
-      }
-      param.LText = Utils.formatOptions(param.LText)
-      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      param.secretkey = Utils.encrypt('', param.timestamp)
-      
-      Api.getLocalConfig(param).then(result => {
-        if (result.status) {
-          resolve()
-        } else {
-          reject()
-          Modal.error({
-            title: result.message
-          })
-        }
-      })
-    } else {
-      resolve()
-    }
-  }
-
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-  }
-
-  render() {
-    const { columns, setting, scripts, colColumns, scriptsColumns, activeKey, loading } = this.state
-
-    return (
-      <div id="mob-verify-card-box-tab">
-        {loading && <Spin size="large" />}
-        <Tabs activeKey={activeKey} className="verify-card-box" onChange={this.changeTab}>
-          <TabPane tab="鏁版嵁婧�" key="setting">
-            <SettingForm
-              menuId={this.props.menuId}
-              dict={this.props.dict}
-              columns={columns}
-              setting={setting}
-              scripts={scripts}
-              wrappedComponentRef={(inst) => this.settingForm = inst}
-            />
-          </TabPane>
-          <TabPane tab="瀛楁闆�" key="columns">
-            <ColForm
-              dict={this.props.dict}
-              columnChange={this.columnChange}
-              wrappedComponentRef={(inst) => this.contrastForm = inst}
-            />
-            <Table
-              bordered
-              rowKey="uuid"
-              className="custom-table"
-              dataSource={columns}
-              columns={colColumns}
-              pagination={false}
-            />
-          </TabPane>
-          <TabPane tab="鑷畾涔夎剼鏈�" key="scripts">
-            <CustomScriptsForm
-              setting={setting}
-              searches={this.props.searches}
-              initsql={this.state.initsql}
-              dict={this.props.dict}
-              customScripts={scripts}
-              systemScripts={this.state.systemScripts}
-              scriptsChange={this.scriptsChange}
-              scriptSubmit={this.scriptSubmit}
-              wrappedComponentRef={(inst) => this.scriptsForm = inst}
-            />
-            <Table
-              bordered
-              rowKey="uuid"
-              className="custom-table"
-              dataSource={scripts}
-              columns={scriptsColumns}
-              pagination={false}
-            />
-          </TabPane>
-        </Tabs>
-      </div>
-    )
-  }
-}
-
-export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/index.scss b/src/mob/datasource/verifycard/index.scss
deleted file mode 100644
index 6a7c5e3..0000000
--- a/src/mob/datasource/verifycard/index.scss
+++ /dev/null
@@ -1,74 +0,0 @@
-#mob-verify-card-box-tab {
-  .ant-spin {
-    position: absolute;
-    left: calc(50% - 16px);
-    top: 220px;
-    z-index: 1;
-  }
-  .verify-card-box {
-    .ant-tabs-nav-scroll {
-      text-align: center;
-    }
-    .ant-tabs-content {
-      min-height: 40vh;
-    }
-    table tr td {
-      word-wrap: break-word;
-      word-break: break-word;
-    }
-    .verify-form {
-      .ant-input-number {
-        width: 100%;
-      }
-      .sql {
-        .ant-col-sm-8 {
-          width: 10.5%;
-        }
-        .ant-col-sm-16 {
-          width: 89.5%;
-          padding-top: 4px;
-        }
-      }
-      .sqlfield {
-        .ant-form-item {
-          margin-bottom: 5px;
-        }
-        .ant-form-item-control {
-          line-height: 24px;
-        }
-        .ant-form-item-label {
-          line-height: 25px;
-        }
-        .ant-form-item-children {
-          line-height: 22px;
-        }
-        .ant-col-sm-8 {
-          width: 10.5%;
-        }
-        .ant-col-sm-16 {
-          width: 89.5%;
-        }
-      }
-      .add {
-        padding-top: 4px;
-      }
-      .anticon-question-circle {
-        color: #c49f47;
-        margin-right: 3px;
-      }
-    }
-    .custom-table .ant-empty {
-      margin: 20px 8px!important;
-    }
-    .errorval {
-      display: inline-block;
-      width: 30px;
-    }
-    .operation-btn {
-      display: inline-block;
-      font-size: 16px;
-      padding: 0 5px;
-      cursor: pointer;
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/settingform/index.jsx b/src/mob/datasource/verifycard/settingform/index.jsx
deleted file mode 100644
index 41c3e3f..0000000
--- a/src/mob/datasource/verifycard/settingform/index.jsx
+++ /dev/null
@@ -1,334 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-// import { fromJS } from 'immutable'
-import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon, notification } from 'antd'
-import moment from 'moment'
-
-import Api from '@/api'
-import Utils from '@/utils/utils.js'
-// import SettingUtils from './utils.jsx'
-import CodeMirror from '@/templates/zshare/codemirror'
-import './index.scss'
-
-class SettingForm extends Component {
-  static propTpyes = {
-    dict: PropTypes.object,      // 瀛楀吀椤�
-    menuId: PropTypes.string,    // 鑿滃崟Id
-    setting: PropTypes.object,   // 鏁版嵁婧愰厤缃�
-    columns: PropTypes.array,    // 鍒楄缃�
-    scripts: PropTypes.array,    // 鑷畾涔夎剼鏈�
-  }
-
-  state = {
-    interType: this.props.setting.interType || 'system',
-    structure: this.props.setting.structure || 'array'
-  }
-
-  handleConfirm = (otype) => {
-    const { setting } = this.props
-    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
-    return new Promise((resolve, reject) => {
-      this.props.form.validateFieldsAndScroll((err, values) => {
-        if (!err) {
-          // 鏁版嵁婧愬墠绔獙璇�
-          if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && !values.dataresource) {
-            notification.warning({
-              top: 92,
-              message: '璇峰~鍐欏唴閮ㄥ嚱鏁版垨鏁版嵁婧愶紒',
-              duration: 5
-            })
-            reject()
-            return
-          } else if (values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' && values.dataresource) {
-            let _quot = values.dataresource.match(/'{1}/g)
-            let _lparen = values.dataresource.match(/\({1}/g)
-            let _rparen = values.dataresource.match(/\){1}/g)
-
-            _quot = _quot ? _quot.length : 0
-            _lparen = _lparen ? _lparen.length : 0
-            _rparen = _rparen ? _rparen.length : 0
-
-            if (_quot % 2 !== 0) {
-              notification.warning({
-                top: 92,
-                message: '鏁版嵁婧愪腑\'蹇呴』鎴愬鍑虹幇',
-                duration: 5
-              })
-              reject()
-              return
-            } else if (_lparen !== _rparen) {
-              notification.warning({
-                top: 92,
-                message: '鏁版嵁婧愪腑()蹇呴』鎴愬鍑虹幇',
-                duration: 5
-              })
-              reject()
-              return
-            } else if (/--/ig.test(values.dataresource)) {
-              notification.warning({
-                top: 92,
-                message: '鏁版嵁婧愪腑锛屼笉鍙嚭鐜板瓧绗� -- 锛屾敞閲婅鐢� /*鍐呭*/',
-                duration: 5
-              })
-              reject()
-              return
-            }
-
-            let error = Utils.verifySql(values.dataresource)
-
-            if (error) {
-              notification.warning({
-                top: 92,
-                message: '鏁版嵁婧愪腑涓嶅彲浣跨敤' + error,
-                duration: 5
-              })
-              reject()
-              return
-            }
-          }
-
-          // 鏁版嵁婧愪繚瀛�
-          if (
-            values.interType === 'inner' && !values.innerFunc && values.execute !== 'false' &&
-            /[^\s]+\s+[^\s]+/ig.test(values.dataresource) && setting.dataresource !== values.dataresource
-          ) {
-            let param = {
-              func: 's_DataSrc_Save',
-              LText: values.dataresource,
-              MenuID: this.props.menuId
-            }
-    
-            param.LText = Utils.formatOptions(param.LText)
-            param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-            param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-    
-            Api.getLocalConfig(param)
-          }
-
-          resolve(values)
-        } else {
-          reject(err)
-        }
-      })
-    })
-  }
-
-  onRadioChange = (e, key) => {
-    let value = e.target.value
-
-    if (key === 'interType') {
-      this.setState({
-        interType: value
-      })
-    } else if (key === 'structure') {
-      this.setState({
-        structure: value
-      })
-    }
-  }
-
-  render() {
-    const { columns, setting } = this.props
-    const { getFieldDecorator } = this.props.form
-    const { interType, structure } = this.state
-
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 }
-      }
-    }
-
-    return (
-      <div className="mob-datasource-setting-form-box">
-        <Form {...formItemLayout} className="mob-setting-form">
-          <Row gutter={24}>
-            <Col span={8}>
-              <Form.Item label="鍚嶇О">
-                {getFieldDecorator('name', {
-                  initialValue: setting.name,
-                  rules: [
-                    {
-                      required: true,
-                      message: this.props.dict['mob.required.input'] + '鍚嶇О!'
-                    },
-                  ]
-                })(<Input placeholder={''} autoComplete="off" />)}
-              </Form.Item>
-            </Col>
-            <Col span={8}>
-              <Form.Item label="琛ㄥ悕">
-                {getFieldDecorator('tableName', {
-                  initialValue: setting.tableName,
-                  rules: [
-                    {
-                      required: true,
-                      message: this.props.dict['mob.required.input'] + '琛ㄥ悕!'
-                    },
-                  ]
-                })(<Input placeholder={''} autoComplete="off" />)}
-              </Form.Item>
-            </Col>
-            <Col span={8}>
-              <Form.Item label="鏁版嵁缁撴瀯">
-                {getFieldDecorator('structure', {
-                  initialValue: structure,
-                  rules: [
-                    {
-                      required: true,
-                      message: this.props.dict['mob.required.select'] + '琛ㄥ悕!'
-                    },
-                  ]
-                })(
-                <Radio.Group onChange={(e) => {this.onRadioChange(e, 'structure')}}>
-                  <Radio value="array">鏁扮粍</Radio>
-                  <Radio value="field">瀛楁</Radio>
-                </Radio.Group>)}
-              </Form.Item>
-            </Col>
-            <Col span={8}>
-              <Form.Item label="鎺ュ彛绫诲瀷">
-                {getFieldDecorator('interType', {
-                  initialValue: interType,
-                  rules: [
-                    {
-                      required: true,
-                      message: this.props.dict['mob.required.select'] + '鎺ュ彛绫诲瀷!'
-                    },
-                  ]
-                })(
-                <Radio.Group onChange={(e) => {this.onRadioChange(e, 'interType')}}>
-                  <Radio value="inner">鍐呴儴</Radio>
-                  <Radio value="outer">澶栭儴</Radio>
-                </Radio.Group>)}
-              </Form.Item>
-            </Col>
-            {interType === 'inner' ? <Col span={8}>
-              <Form.Item label="鍐呴儴鍑芥暟">
-                {getFieldDecorator('innerFunc', {
-                  initialValue: setting.innerFunc || '',
-                  rules: [
-                    
-                  ]
-                })(<Input placeholder={''} autoComplete="off" />)}
-              </Form.Item>
-            </Col> : null}
-            {interType === 'outer' ? <Col span={8}>
-              <Form.Item label="鎺ュ彛鍦板潃">
-                {getFieldDecorator('interface', {
-                  initialValue: setting.interface || '',
-                  rules: [
-                    {
-                      required: true,
-                      message: this.props.dict['mob.required.input'] + '鎺ュ彛鍦板潃!'
-                    },
-                  ]
-                })(<Input placeholder={''} autoComplete="off" />)}
-              </Form.Item>
-            </Col> : null}
-            {interType === 'outer' ? <Col span={8}>
-              <Form.Item label="澶栭儴鍑芥暟">
-                {getFieldDecorator('outerFunc', {
-                  initialValue: setting.outerFunc || '',
-                  rules: [
-
-                  ]
-                })(<Input placeholder={''} autoComplete="off" />)}
-              </Form.Item>
-            </Col> : null}
-            {interType === 'inner' ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}>
-              <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 2 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 22 }} } label={
-                <Tooltip placement="topLeft" title={'浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\''}>
-                  <Icon type="question-circle" />
-                  鏁版嵁婧�
-                </Tooltip>
-              }>
-                {getFieldDecorator('dataresource', {
-                  initialValue: setting.dataresource || ''
-                })(<CodeMirror />)}
-              </Form.Item>
-            </Col> : null}
-            {interType === 'inner' ? <Col span={8}>
-              <Form.Item label={
-                <Tooltip placement="topLeft" title={'鏌ヨ鏃讹紝鎼滅储鏉′欢浠here鏉′欢鎷兼帴杩涘叆sql锛岀粺璁℃椂锛屽皢鏁版嵁婧愪腑浠モ�淍+鎼滅储瀛楁+@鈥濈殑鍐呭锛屼互鎼滅储鏉′欢涓殑鍊艰繘琛屾浛鎹㈠悗锛屾彁浜ゆ煡璇紝娉細鏌ヨ绫诲瀷浠呭湪浣跨敤绯荤粺鍑芥暟鏃舵湁鏁堛��'}>
-                  <Icon type="question-circle" />
-                  鏌ヨ绫诲瀷
-                </Tooltip>
-              }>
-                {getFieldDecorator('queryType', {
-                  initialValue: setting.queryType || 'query'
-                })(
-                <Radio.Group>
-                  <Radio value="query">鏌ヨ</Radio>
-                  <Radio value="statistics">缁熻</Radio>
-                </Radio.Group>)}
-              </Form.Item>
-            </Col> : null}
-            {structure === 'array' ? <Col span={8}>
-              <Form.Item label="涓婚敭">
-                {getFieldDecorator('primaryKey', {
-                  initialValue: setting.primaryKey || ''
-                })(
-                  <Select onChange={(value) => {this.selectChange('primaryKey', value)}}>
-                    {columns.map((option, i) =>
-                      <Select.Option key={i} value={option.value}>
-                        {option.text}
-                      </Select.Option>
-                    )}
-                  </Select>
-                )}
-              </Form.Item>
-            </Col> : null}
-            {structure === 'array' ? <Col span={8}>
-              <Form.Item label="榛樿鎺掑簭">
-                {getFieldDecorator('order', {
-                  initialValue: setting.order || 'ID asc'
-                })(<Input placeholder={'ID asc, UID desc'} autoComplete="off" />)}
-              </Form.Item>
-            </Col> : null}
-            {structure === 'array' ? <Col span={8}>
-              <Form.Item label="鍒嗛〉">
-                {getFieldDecorator('laypage', {
-                  initialValue: setting.laypage || 'true'
-                })(
-                <Radio.Group>
-                  <Radio value="true">鏄�</Radio>
-                  <Radio value="false">鍚�</Radio>
-                </Radio.Group>)}
-              </Form.Item>
-            </Col> : null}
-            
-            {interType === 'inner' ? <Col span={8}>
-              <Form.Item label="榛樿sql">
-                {getFieldDecorator('execute', {
-                  initialValue: setting.execute || 'true'
-                })(
-                <Radio.Group>
-                  <Radio value="true">鎵ц</Radio>
-                  <Radio value="false">涓嶆墽琛�</Radio>
-                </Radio.Group>)}
-              </Form.Item>
-            </Col> : null}
-            <Col span={8}>
-              <Form.Item label="鎼滅储鏉′欢">
-                {getFieldDecorator('search', {
-                  initialValue: setting.search || 'true'
-                })(
-                <Radio.Group>
-                  <Radio value="true">鎺ユ敹</Radio>
-                  <Radio value="false">涓嶆帴鏀�</Radio>
-                </Radio.Group>)}
-              </Form.Item>
-            </Col>
-          </Row>
-        </Form>
-      </div>
-    )
-  }
-}
-
-export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/settingform/index.scss b/src/mob/datasource/verifycard/settingform/index.scss
deleted file mode 100644
index f9bc3f3..0000000
--- a/src/mob/datasource/verifycard/settingform/index.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-.mob-datasource-setting-form-box {
-  position: relative;
-
-  .mob-setting-form {
-    .data-source {
-      .ant-form-item-label {
-        width: 11%;
-      }
-      .ant-form-item-control-wrapper {
-        width: 89%;
-      }
-      .CodeMirror {
-        height: 150px;
-      }
-    }
-    .anticon-question-circle {
-      color: #c49f47;
-      margin-right: 3px;
-    }
-  }
-
-}
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/settingform/utils.jsx b/src/mob/datasource/verifycard/settingform/utils.jsx
deleted file mode 100644
index a1e29d0..0000000
--- a/src/mob/datasource/verifycard/settingform/utils.jsx
+++ /dev/null
@@ -1,84 +0,0 @@
-
-export default class SettingUtils {
-  /**
-   * @description 鐢熸垚椤甸潰鏌ヨ璇彞
-   * @return {String}  arr_field     鏄剧ず鍒楀瓧娈�
-   * @return {String}  search        鎼滅储鏉′欢
-   * @return {Object}  setting       椤甸潰璁剧疆
-   * @return {Array}   regoptions    鎼滅储鏉′欢姝e垯鏇挎崲
-   */
-  static getDebugSql (setting, arr_field, regoptions, search) {
-    let sql = ''
-    let _dataresource = setting.dataresource
-    let _customScript = setting.customScript
-
-    if (setting.interType === 'system' && setting.default === 'false') {
-      _dataresource = ''
-    }
-    
-    if (_dataresource) {
-      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
-    }
-    if (_customScript) {
-      _customScript = _customScript.replace(/@\$|\$@/ig, '')
-    }
-    
-    // 姝e垯鏇挎崲
-    let _regoptions = regoptions.map(item => {
-      return {
-        reg: new RegExp('@' + item.key + '@', 'ig'),
-        value: `'${item.value}'`
-      }
-    })
-    let _search = search
-
-    if (setting.queryType === 'statistics' && _dataresource) {
-      _regoptions.forEach(item => {
-        _dataresource = _dataresource.replace(item.reg, item.value)
-      })
-
-      _search = ''
-    }
-
-    if (_customScript) {
-      _regoptions.push({
-        reg: new RegExp('@orderBy@', 'ig'),
-        value: setting.order
-      })
-      if (setting.laypage !== 'false') {
-        _regoptions.push({
-          reg: new RegExp('@pageSize@', 'ig'),
-          value: 10
-        }, {
-          reg: new RegExp('@pageIndex@', 'ig'),
-          value: 1
-        })
-      }
-      _regoptions.forEach(item => {
-        _customScript = _customScript.replace(item.reg, item.value)
-      })
-    }
-
-    // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 
-    if (arr_field && _dataresource) {
-      if (/\s/.test(_dataresource)) {
-        _dataresource = '(' + _dataresource + ') tb'
-      }
-
-      _dataresource = `select ${setting.laypage !== 'false' ?  'top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ?  'where rows > 0' : ''} order by tmptable.rows`
-    }
-
-    if (_customScript) {
-      sql = `${_customScript}
-        ${_dataresource}
-        aaa:
-        if @ErrorCode!=''
-          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
-      `
-    } else {
-      sql = _dataresource
-    }
-    
-    return sql
-  }
-}
\ No newline at end of file
diff --git a/src/mob/datasource/verifycard/utils.jsx b/src/mob/datasource/verifycard/utils.jsx
deleted file mode 100644
index 8a3cf2e..0000000
--- a/src/mob/datasource/verifycard/utils.jsx
+++ /dev/null
@@ -1,99 +0,0 @@
-
-export default class SettingUtils {
-  /**
-   * @description 鐢熸垚椤甸潰鏌ヨ璇彞
-   * @return {String}  scripts       鑷畾涔夎剼鏈�
-   * @return {String}  searches      鎼滅储鏉′欢
-   * @return {Object}  setting       椤甸潰璁剧疆
-   * @return {Array}   columns       鏄剧ず瀛楁
-   */
-  static getDebugSql (setting, scripts, columns, searches) {
-    let sql = ''
-    let _dataresource = ''
-    let _customScript = ''
-    let arr_field = columns.map(item => item.field).join(',')
-
-    if (scripts.length > 0) {
-      scripts.forEach(item => {
-        _customScript += `
-          ${item.sql}
-        `
-      })
-    }
-
-    if (_customScript) {
-      _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg =''
-        ${_customScript}
-      `
-    }
-
-    if (setting.interType === 'system' && setting.execute !== 'false') {
-      _dataresource = setting.dataresource
-    }
-    
-    if (_dataresource) {
-      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
-    }
-    if (_customScript) {
-      _customScript = _customScript.replace(/@\$|\$@/ig, '')
-    }
-    
-    // 姝e垯鏇挎崲
-    let _regoptions = searches.map(item => {
-      return {
-        reg: new RegExp('@' + item.key + '@', 'ig'),
-        value: `'${item.value}'`
-      }
-    })
-    let _search = ''
-
-    if (setting.queryType === 'statistics' && _dataresource) {
-      _regoptions.forEach(item => {
-        _dataresource = _dataresource.replace(item.reg, item.value)
-      })
-
-      _search = ''
-    }
-
-    if (_customScript) {
-      _regoptions.push({
-        reg: new RegExp('@orderBy@', 'ig'),
-        value: setting.order
-      })
-      if (setting.laypage !== 'false') {
-        _regoptions.push({
-          reg: new RegExp('@pageSize@', 'ig'),
-          value: 10
-        }, {
-          reg: new RegExp('@pageIndex@', 'ig'),
-          value: 1
-        })
-      }
-      _regoptions.forEach(item => {
-        _customScript = _customScript.replace(item.reg, item.value)
-      })
-    }
-
-    // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 
-    if (arr_field && _dataresource) {
-      if (/\s/.test(_dataresource)) {
-        _dataresource = '(' + _dataresource + ') tb'
-      }
-
-      _dataresource = `select ${setting.laypage !== 'false' ?  'top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ?  'where rows > 0' : ''} order by tmptable.rows`
-    }
-
-    if (_customScript) {
-      sql = `${_customScript}
-        ${_dataresource}
-        aaa:
-        if @ErrorCode!=''
-          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
-      `
-    } else {
-      sql = _dataresource
-    }
-    
-    return sql
-  }
-}
\ No newline at end of file
diff --git a/src/mob/mobcard/index.jsx b/src/mob/mobcard/index.jsx
deleted file mode 100644
index 6b732c9..0000000
--- a/src/mob/mobcard/index.jsx
+++ /dev/null
@@ -1,222 +0,0 @@
-import React, {Component} from 'react'
-import { is, fromJS } from 'immutable'
-import PropTypes from 'prop-types'
-import { Card, Spin, Icon, Row, Col, Modal, notification } from 'antd'
-
-import Api from '@/api'
-import Utils from '@/utils/utils.js'
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import asyncComponent from '@/utils/asyncSpinComponent'
-import './index.scss'
-
-const { confirm } = Modal
-const MutilForm = asyncComponent(() => import('./mutilform'))
-
-class CardChart extends Component {
-  static propTpyes = {
-    jumpMenu: PropTypes.func  // 椤甸潰璺宠浆
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    loading: true,
-    visible: false,
-    confirmloading: false,
-    data: [],
-    card: null
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  UNSAFE_componentWillMount() {
-    this.getMobCards()
-  }
-
-  getMobCards = () => {
-    let param = {
-      func: 's_get_kei'
-    }
-
-    Api.getCloudConfig(param).then(result => {
-      if (result.status) {
-        this.setState({
-          loading: false,
-          data: result.data.map(item => {
-            return {
-              uuid: item.ID,
-              keiNo: item.kei_no,
-              name: item.remark,
-              type: item.typename
-            }
-          })
-        })
-
-      } else {
-        this.setState({
-          loading: false
-        })
-        notification.warning({
-          top: 92,
-          message: result.message,
-          duration: 5
-        })
-      }
-    })
-  }
-
-  editCard = (card) => {
-    this.setState({
-      card: card || null,
-      visible: true
-    })
-  }
-
-  deleteCard = (card) => {
-    let _this = this
-
-    confirm({
-      title: '纭畾鍒犻櫎銆�' + card.name + '銆嬪悧锛�',
-      content: '',
-      onOk() {
-        return new Promise(resolve => {
-          let param = {
-            func: 's_kei_del',
-            ID: card.uuid,
-            kei_no: card.keiNo
-          }
-    
-          Api.getCloudConfig(param).then(result => {
-            if (result.status) {
-              notification.success({
-                top: 92,
-                message: '鍒犻櫎鎴愬姛锛�',
-                duration: 5
-              })
-
-              _this.getMobCards()
-            } else {
-              notification.warning({
-                top: 92,
-                message: result.message,
-                duration: 5
-              })
-            }
-            resolve()
-          })
-        })
-      },
-      onCancel() {}
-    })
-  }
-
-  submitCard = () => {
-    const { card } = this.state
-
-    this.mobcardRef.handleConfirm().then(res => {
-      this.setState({
-        confirmloading: true
-      })
-
-      let param = {
-        func: 's_kei_addupt',
-        ID: card ? card.uuid : Utils.getuuid(),
-        TypeName: res.type,
-        remark: res.name,
-        kei_no: res.keiNo
-      }
-
-      Api.getCloudConfig(param).then(result => {
-        if (result.status) {
-          notification.success({
-            top: 92,
-            message: card ? '淇敼鎴愬姛锛�' : '娣诲姞鎴愬姛锛�',
-            duration: 5
-          })
-
-          this.setState({
-            confirmloading: false,
-            visible: false,
-            loading: true
-          })
-          this.getMobCards()
-        } else {
-          this.setState({
-            confirmloading: false
-          })
-          notification.warning({
-            top: 92,
-            message: result.message,
-            duration: 5
-          })
-        }
-      }, () => {
-        this.setState({
-          confirmloading: false
-        })
-      })
-    })
-  }
-
-  render() {
-    const { data, loading, card, dict } = this.state
-
-    return (
-      <div className="mob-card-row-box">
-        {loading ?
-          <div className="loading-mask">
-            <div className="ant-spin-blur"></div>
-            <Spin />
-          </div> : null
-        }
-        <Row gutter={24}>
-          {data && data.length > 0 &&
-            data.map(item => (
-              <Col key={item.uuid} span={6}>
-                <Card
-                  size="small"
-                  className="chart-card"
-                  actions={[
-                    <Icon title="edit" onClick={() => this.editCard(item)} type="edit" />,
-                    <Icon title="delete" onClick={() => this.deleteCard(item)} type="close" />,
-                    <Icon title="detail" onClick={() => this.props.jumpMenu(item)} type="arrow-right" />
-                  ]}
-                >
-                  <div className="mk-mob-card-title">
-                    {item.name}
-                  </div>
-                  <div className="mk-mob-card-type">
-                    {item.type === 'mob' ? '绉诲姩绔�' : 'PC绔�'}
-                  </div>
-                </Card>
-              </Col>
-            ))
-          }
-          
-          <Col span={6} key="insert">
-            <div className="chart-card insert" onClick={() => this.editCard()}>
-              <Icon type="plus" />
-            </div>
-          </Col>
-        </Row>
-        <Modal
-          className="mob-card-modal"
-          title={card ? '缂栬緫搴旂敤' : '鏂板缓搴旂敤'}
-          width={'600px'}
-          maskClosable={false}
-          visible={this.state.visible}
-          onCancel={() => this.setState({visible: false})}
-          confirmLoading={this.state.confirmloading}
-          onOk={this.submitCard}
-          destroyOnClose
-        >
-          <MutilForm card={card} dict={dict} wrappedComponentRef={(inst) => this.mobcardRef = inst} inputSubmit={this.submitCard} />
-        </Modal>
-      </div>
-    )
-  }
-}
-
-export default CardChart
\ No newline at end of file
diff --git a/src/mob/mobcard/index.scss b/src/mob/mobcard/index.scss
deleted file mode 100644
index 54c55cc..0000000
--- a/src/mob/mobcard/index.scss
+++ /dev/null
@@ -1,64 +0,0 @@
-.mob-card-row-box {
-  padding: 40px 20px;
-  position: relative;
-
-  .chart-card {
-    height: 250px;
-    border: 1px solid #e8e8e8;
-    .ant-card-body {
-      height: 201px;
-      .mk-mob-card-title {
-        margin-top: 40px;
-        font-size: 24px;
-        font-weight: 600;
-        text-align: center;
-      }
-      .mk-mob-card-type {
-        font-size: 14px;
-        color: rgba(0, 0 , 0, 0.55);
-        text-align: center;
-      }
-    }
-
-    .ant-card-actions > li > span {
-      > .anticon-close:hover {
-        color: #ff4d4f;
-      }
-      > .anticon-arrow-right:hover {
-        color: rgb(38, 194, 129);
-      }
-    }
-  }
-
-  .chart-card.insert {
-    text-align: center;
-    cursor: pointer;
-
-    .anticon-plus {
-      color: rgb(38, 194, 129);
-      font-size: 100px;
-      line-height: 250px;
-    }
-  }
-
-  .loading-mask {
-    position: absolute;
-    left: 20px;
-    top: 0;
-    right: 20px;
-    bottom: 0;
-    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;
-    }
-  }
-}
diff --git a/src/mob/mobcard/mutilform/index.jsx b/src/mob/mobcard/mutilform/index.jsx
deleted file mode 100644
index 0ba42e2..0000000
--- a/src/mob/mobcard/mutilform/index.jsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Select, Radio } from 'antd'
-import './index.scss'
-
-class MainSearch extends Component {
-  static propTpyes = {
-    dict: PropTypes.object,      // 瀛楀吀椤�
-    card: PropTypes.any,         // 缂栬緫搴旂敤
-    inputSubmit: PropTypes.func  // input鍥炶溅鎻愪氦
-  }
-
-  state = {}
-
-  /**
-   * @description 鑾峰彇琛ㄥ崟鍊�
-   */
-  handleConfirm = () => {
-    return new Promise(resolve => {
-      this.props.form.validateFieldsAndScroll((err, values) => {
-        if (!err) {
-          resolve(values)
-        }
-      })
-    })
-  }
-
-  /**
-   * @description 鍥炶溅鎻愪氦
-   */
-  handleSubmit = (e) => {
-    e.preventDefault()
-    this.props.inputSubmit()
-  }
-
-  render() {
-    const { card } = this.props
-    const { getFieldDecorator } = this.props.form
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 16 }
-      }
-    }
-    return (
-      <Form {...formItemLayout} className="mob-card-edit-form">
-        <Row gutter={24}>
-          <Col span={24}>
-            <Form.Item label="搴旂敤鍚�">
-              {getFieldDecorator('name', {
-                initialValue: card ? card.name : '',
-                rules: [{
-                  required: true,
-                  message: this.props.dict['mob.required.input'] + '搴旂敤鍚�!'
-                }, {
-                  max: 20,
-                  message: '搴旂敤鍚嶄笉鍙秴杩�20涓瓧绗�!'
-                }]
-              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
-            </Form.Item>
-          </Col>
-          <Col span={24}>
-            <Form.Item label="搴旂敤绫诲瀷">
-              {getFieldDecorator('type', {
-                initialValue: card ? card.type : 'mob',
-                rules: [
-                  {
-                    required: true,
-                    message: this.props.dict['mob.required.select'] + '搴旂敤绫诲瀷!'
-                  }
-                ]
-              })(
-                <Select>
-                  <Select.Option value="mob">绉诲姩绔�</Select.Option>
-                  <Select.Option value="pc">PC绔�</Select.Option>
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-          <Col span={24}>
-            <Form.Item label="搴旂敤缂栫爜">
-              {getFieldDecorator('keiNo', {
-                initialValue: card ? card.keiNo : '',
-                rules: [{
-                  required: true,
-                  message: this.props.dict['mob.required.input'] + '搴旂敤缂栫爜!'
-                }, {
-                  pattern: /^[a-zA-Z_]*$/ig,
-                  message: '搴旂敤缂栫爜鍙厑璁稿寘鍚ぇ灏忓啓瀛楁瘝鍙奯!'
-                }, {
-                  max: 20,
-                  message: '搴旂敤缂栫爜涓嶅彲瓒呰繃20涓瓧绗�!'
-                }]
-              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
-            </Form.Item>
-          </Col>
-          <Col span={24}>
-            <Form.Item label="鏉冮檺绠$悊">
-              {getFieldDecorator('role_manage', {
-                initialValue: card ? card.role_manage || 'false' : 'false',
-                rules: [{
-                  required: true,
-                  message: this.props.dict['mob.required.select'] + '鏄惁鍚敤鏉冮檺绠$悊!'
-                }]
-              })(
-                <Radio.Group>
-                  <Radio value="true">鍚敤</Radio>
-                  <Radio value="false">涓嶅惎鐢�</Radio>
-                </Radio.Group>
-              )}
-            </Form.Item>
-          </Col>
-        </Row>
-      </Form>
-    )
-  }
-}
-
-export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/mob/mobcard/mutilform/index.scss b/src/mob/mobcard/mutilform/index.scss
deleted file mode 100644
index 28344fe..0000000
--- a/src/mob/mobcard/mutilform/index.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-.mob-card-edit-form {
-  padding: 0px 24px 20px;
-
-}
\ No newline at end of file
diff --git a/src/mob/mobshell/card.jsx b/src/mob/mobshell/card.jsx
index 5b7a510..30225a7 100644
--- a/src/mob/mobshell/card.jsx
+++ b/src/mob/mobshell/card.jsx
@@ -2,56 +2,86 @@
 import { useDrag, useDrop } from 'react-dnd'
 
 import asyncComponent from '@/utils/asyncComponent'
-
 import './index.scss'
 
-// const Home = asyncComponent(() => import('@/mob/home'))
-const MobLogin1 = asyncComponent(() => import('@/mob/components/login/mob-login-1'))
-const MobLogin2 = asyncComponent(() => import('@/mob/components/login/mob-login-2'))
+const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
+const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
+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 CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
+const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
+const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
+const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
+const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
+const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
+const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 
-const Card = ({ id, card, moveCard, findCard, editId, editCard, delCard, doubleClickCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
-    item: { type: 'mob', id, originalIndex },
+    item: { type: 'menu', id, originalIndex, floor: card.floor },
     collect: monitor => ({
       isDragging: monitor.isDragging(),
     }),
   })
   const [, drop] = useDrop({
-    accept: 'mob',
+    accept: 'menu',
     canDrop: () => true,
     drop: (item) => {
-      const { id: draggedId, originalIndex } = item
-
+      const { id: draggedId, originalIndex, floor } = item
       if (originalIndex === undefined) {
         item.dropTargetId = id
-      } else if (draggedId && draggedId !== id) {
+      } else if (draggedId && floor === card.floor) {
+        if (draggedId === id) return
+        const { index: originIndex } = findCard(draggedId)
+
+        if (originIndex === -1) return
+
         const { index: overIndex } = findCard(id)
+
         moveCard(draggedId, overIndex)
       }
     }
   })
 
   let style = { opacity: 1}
-  if (isDragging && card.type !== 'login') {
+  if (isDragging) {
     style = { opacity: 0.3}
-  }
-  if (card.type === 'login') {
-    style.height = '100%'
   }
 
   const getCardComponent = () => {
-    if (card.type === 'login') {
-      if (card.subtype === 'mob-login-1') {
-        return (<MobLogin1 card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />)
-      } else if (card.subtype === 'mob-login-2') {
-        return (<MobLogin2 card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />)
-      }
+    if (card.type === 'bar' || card.type === 'line') {
+      return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'search') {
+      return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'pie') {
+      return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'form') {
+      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'tabs') {
+      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}/>)
+    } else if (card.type === 'carousel' && card.subtype === 'datacard') {
+      return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'carousel' && card.subtype === 'propcard') {
+      return (<CarouselPropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'table' && card.subtype === 'tablecard') {
+      return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'table' && card.subtype === 'normaltable') {
+      return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'group' && card.subtype === 'normalgroup') {
+      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'code') {
+      return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
-
   return (
-    <div className="mk-component-card" ref={node => drag(drop(node))} style={style}>
+    <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}>
       {getCardComponent()}
     </div>
   )
diff --git a/src/mob/mobshell/index.jsx b/src/mob/mobshell/index.jsx
index 2dd4b00..ee23621 100644
--- a/src/mob/mobshell/index.jsx
+++ b/src/mob/mobshell/index.jsx
@@ -1,23 +1,23 @@
 import React, { useState } from 'react'
 import { useDrop } from 'react-dnd'
-import { is, fromJS } from 'immutable'
 import update from 'immutability-helper'
-import { message, Empty } from 'antd'
+import { Empty, notification, Modal } from 'antd'
 
 import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import MenuUtils from '@/utils/utils-custom.js'
 import Card from './card'
 import './index.scss'
 
-const Container = ({config, editId, handleList, editCard, deleteCard, doubleClickCard }) => {
-  const [cards, setCards] = useState(config.components)
+const { confirm } = Modal
+
+const Container = ({menu, handleList }) => {
+  const [cards, setCards] = useState(menu.components)
   const moveCard = (id, atIndex) => {
     const { card, index } = findCard(id)
     const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
-    handleList({...config, components: _cards})
-  }
-
-  if (!is(fromJS(cards), fromJS(config.components))) {
-    setCards(config.components)
+    handleList({...menu, components: _cards})
+    setCards(_cards)
   }
   
   const findCard = id => {
@@ -29,27 +29,94 @@
   }
 
   const updateConfig = (element) => {
-    handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)})
+    const _cards = cards.map(item => item.uuid === element.uuid ? element : item)
+    handleList({...menu, components: _cards})
+    setCards(_cards)
+  }
+
+  const deleteCard = (id) => {
+    const { card } = findCard(id)
+
+    let hasComponent = false
+    if (card.type === 'tabs') {
+      card.subtabs.forEach(tab => {
+        if (tab.components.length > 0) {
+          hasComponent = true
+        }
+      })
+    }
+
+    let uuids = MenuUtils.getDelButtonIds(card)
+
+    confirm({
+      title: `纭畾鍒犻櫎銆�${card.name}銆嬪悧锛焋,
+      content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
+      onOk() {
+        MKEmitter.emit('delButtons', uuids)
+        const _cards = cards.filter(item => item.uuid !== card.uuid)
+        handleList({...menu, components: _cards})
+        setCards(_cards)
+      },
+      onCancel() {}
+    })
   }
 
   const [, drop] = useDrop({
-    accept: 'mob',
+    accept: 'menu',
     drop(item) {
-      if (item.hasOwnProperty('originalIndex')) {
+      if (item.hasOwnProperty('originalIndex') || item.added) {
+        delete item.added // 鍒犻櫎缁勪欢娣诲姞鏍囪
         return
       }
 
-      if (cards.length > 0 && cards[0].type === 'login') {
-        message.warning('鐧诲綍椤典笉鍙坊鍔犲叾浠栧厓绱狅紒')
-        return
+      if (item.component === 'search') { // 鎼滅储缁勪欢涓嶅彲閲嶅娣诲姞
+        if (cards.filter(card => card.type === 'search').length > 0) {
+          notification.warning({
+            top: 92,
+            message: '鎼滅储鏉′欢涓嶅彲閲嶅娣诲姞锛�',
+            duration: 5
+          })
+          return
+        }
+      }
+
+      let name = ''
+      let names = {
+        bar: '鏌辩姸鍥�',
+        line: '鎶樼嚎鍥�',
+        tabs: '鏍囩缁�',
+        pie: '楗煎浘',
+        search: '鎼滅储',
+        table: '琛ㄦ牸',
+        group: '鍒嗙粍',
+        editor: '瀵屾枃鏈�',
+        code: '鑷畾涔�',
+        carousel: '杞挱',
+        form: '琛ㄥ崟',
+        card: '鍗$墖'
+      }
+      let i = 1
+      
+      while (!name && names[item.component]) {
+        let _name = names[item.component] + i
+        if (menu.components.filter(com => com.name === _name).length === 0) {
+          name = _name
+        }
+        i++
       }
 
       let newcard = {
         uuid: Utils.getuuid(),
-        type: item.componentType,
+        type: item.component,
         subtype: item.subtype,
+        config: item.config,
+        width: item.width || 24,
+        dataName: Utils.getdataName(),
+        name: name,
+        floor: 1,   // 缁勪欢鐨勫眰绾�
+        isNew: true // 鏂版坊鍔犳爣蹇楋紝鐢ㄤ簬鍒濆鍖�
       }
-
+      
       let targetId = ''
 
       if (item.dropTargetId) {
@@ -59,29 +126,29 @@
         targetId = cards.slice(-1)[0].uuid
       }
 
-      const { index: overIndex } = findCard(`${targetId}`) // cards涓虹┖鏃� overIndex 涓� -1
+      const { index: overIndex } = findCard(`${targetId}`)
       const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
 
-      handleList({...config, components: _cards})
+      handleList({...menu, components: _cards})
+      setCards(_cards)
     }
   })
 
   return (
-    <div ref={drop} className="mob-shell-inner">
-      {cards.map(card => (
-        <Card
-          id={card.uuid}
-          key={card.uuid}
-          card={card}
-          editId={editId}
-          moveCard={moveCard}
-          editCard={editCard}
-          delCard={deleteCard}
-          findCard={findCard}
-          updateConfig={updateConfig}
-          doubleClickCard={doubleClickCard}
-        />
-      ))}
+    <div ref={drop} className="mob-shell-inner" id="menu-shell-inner" style={menu.style}>
+      <div className="ant-row">
+        {cards.map(card => (
+          <Card
+            id={card.uuid}
+            key={card.uuid}
+            card={card}
+            moveCard={moveCard}
+            delCard={deleteCard}
+            findCard={findCard}
+            updateConfig={updateConfig}
+          />
+        ))}
+      </div>
       {cards.length === 0 ?
         <Empty description="璇锋坊鍔犵粍浠�" /> : null
       }
@@ -89,3 +156,4 @@
   )
 }
 export default Container
+
diff --git a/src/mob/modelsource/dragsource/index.jsx b/src/mob/modelsource/dragsource/index.jsx
deleted file mode 100644
index 6ae90a6..0000000
--- a/src/mob/modelsource/dragsource/index.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react'
-import { useDrag } from 'react-dnd'
-import { Tooltip } from 'antd'
-import './index.scss'
-
-const MobSourceElement = ({content}) => {
-  const [, drag] = useDrag({ item: content })
-  return (
-    <div ref={drag} className="mob-source-item" style={{backgroundImage: 'url(' + content.url + ')', ...content.style}}>
-      <Tooltip placement="right" overlayClassName="mob-source-tooltip-box" mouseEnterDelay={0.3} mouseLeaveDelay={0} title={
-        <div><img style={{width: '100%'}} src={content.url} alt=""/></div>
-      }>
-        <div className="tooltip-block"></div>
-      </Tooltip>
-    </div>
-  )
-}
-export default MobSourceElement
\ No newline at end of file
diff --git a/src/mob/modelsource/dragsource/index.scss b/src/mob/modelsource/dragsource/index.scss
deleted file mode 100644
index 9884d46..0000000
--- a/src/mob/modelsource/dragsource/index.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-.mob-source-item {
-  display: inline-block;
-  width: 130px;
-  margin-right: 15px;
-  cursor: move;
-  height: 130px;
-  box-shadow: 0px 0px 3px #cdcdcd;
-
-  background-size: cover;
-  background-position: top center;
-  background-repeat: no-repeat;
-
-  .tooltip-block {
-    width: 100%;
-    height: 100%;
-    background: transparent;
-  }
-}
-
-.mob-source-tooltip-box {
-  margin-left: 20px;
-  .ant-tooltip-content {
-    width: 250px;
-  }
-}
\ No newline at end of file
diff --git a/src/mob/modelsource/index.jsx b/src/mob/modelsource/index.jsx
deleted file mode 100644
index 9adfe9c..0000000
--- a/src/mob/modelsource/index.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, {Component} from 'react'
-import { is, fromJS } from 'immutable'
-import PropTypes from 'prop-types'
-
-import { mobOptions } from './option'
-import SourceWrap from './dragsource'
-import './index.scss'
-
-class CardChart extends Component {
-  static propTpyes = {
-    appType: PropTypes.string  // 搴旂敤绫诲瀷
-  }
-
-  state = {}
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  render() {
-    const { appType } = this.props
-
-    return (
-      <div className="mob-card-source-box">
-        {appType === 'mob' && mobOptions.map((item, index) => (
-          <div key={index}>
-            <p>{item.title}</p>
-            {item.options.map((cell, i) => (<SourceWrap key={i} content={cell} />))}
-          </div>
-        ))}
-      </div>
-    )
-  }
-}
-
-export default CardChart
\ No newline at end of file
diff --git a/src/mob/modelsource/option.jsx b/src/mob/modelsource/option.jsx
deleted file mode 100644
index 0123971..0000000
--- a/src/mob/modelsource/option.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import mobLogin1 from '@/assets/mobimg/mob-login1.png'
-import mobLogin2 from '@/assets/mobimg/mob-login2.png'
-
-const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
-
-// 缁勪欢閰嶇疆淇℃伅
-export const mobOptions = [{
-  title: _dict['mob.login'],
-  sourceType: 'login',
-  options: [
-    { subtype: 'mob-login-1', componentType: 'login', type: 'mob', url: mobLogin1,  style: {} },
-    { subtype: 'mob-login-2', componentType: 'login', type: 'mob', url: mobLogin2,  style: {} },
-  ]
-}]
diff --git a/src/mob/modulesource/dragsource/index.jsx b/src/mob/modulesource/dragsource/index.jsx
new file mode 100644
index 0000000..0f13372
--- /dev/null
+++ b/src/mob/modulesource/dragsource/index.jsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import { useDrag } from 'react-dnd'
+import { Icon } from 'antd'
+import './index.scss'
+
+const MobSourceElement = ({item, triggerDel}) => {
+  const [, drag] = useDrag({ item })
+  return (
+    <div className="menu-source-item">
+      <div className="property"><span>{item.title}</span>{item.config ? <Icon onClick={() => triggerDel(item)} type="close-circle" /> : null}</div>
+      <img ref={drag} src={item.url} alt=""/>
+    </div>
+  )
+}
+export default MobSourceElement
\ No newline at end of file
diff --git a/src/mob/modulesource/dragsource/index.scss b/src/mob/modulesource/dragsource/index.scss
new file mode 100644
index 0000000..ac891ba
--- /dev/null
+++ b/src/mob/modulesource/dragsource/index.scss
@@ -0,0 +1,46 @@
+.menu-source-item {
+  display: inline-block;
+  width: 100%;
+  margin-bottom: 15px;
+  height: auto;
+  min-height: 70px;
+
+  .property {
+    font-size: 14px;
+    color: rgba(0, 0, 0, 0.65);
+    margin-bottom: 2px;
+
+    .anticon-close-circle {
+      opacity: 0;
+      cursor: pointer;
+      padding: 0 3px;
+      color: #ff4d4f;
+      transition: all 0.3s;
+    }
+  }
+
+  img {
+    width: 100%;
+    cursor: move;
+    box-shadow: 0px 0px 1px #1890ff;
+  }
+
+  .tooltip-block {
+    width: 100%;
+    height: 100%;
+    background: transparent;
+  }
+}
+
+.menu-source-item:hover .property {
+  .anticon-close-circle {
+    opacity: 1;
+  }
+}
+
+.menu-source-tooltip-box {
+  margin-left: 20px;
+  .ant-tooltip-content {
+    width: 250px;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/modulesource/index.jsx b/src/mob/modulesource/index.jsx
new file mode 100644
index 0000000..f4705bf
--- /dev/null
+++ b/src/mob/modulesource/index.jsx
@@ -0,0 +1,93 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Modal, notification } from 'antd'
+
+import Api from '@/api'
+import { menuOptions } from './option'
+import SourceWrap from './dragsource'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { confirm } = Modal
+
+class ModelSource extends Component {
+  state = {
+    menuOptions: null,
+  }
+
+  UNSAFE_componentWillMount () {
+    const { components } = this.props
+    let options = []
+    
+    if (components) {
+      options = fromJS(components).toJS()
+    } else {
+      options = fromJS(menuOptions).toJS()
+    }
+
+    this.setState({
+      menuOptions: options
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (nextProps.components && !is(fromJS(this.props.components), fromJS(nextProps.components))) {
+      this.setState({
+        menuOptions: fromJS(nextProps.components).toJS()
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  triggerDel = (item) => {
+    confirm({
+      title: `纭畾鍒犻櫎<${item.title}>鍚楋紵`,
+      content: '',
+      onOk() {
+        return new Promise(resolve => {
+          Api.getSystemConfig({
+            func: 's_custom_components_adduptdel',
+            c_id: item.uuid,
+            images: '',
+            c_name: item.title,
+            long_param: '',
+            del_type: 'Y'
+          }).then(result => {
+            if (result.status) {
+              notification.success({
+                top: 92,
+                message: '鍒犻櫎鎴愬姛锛�',
+                duration: 5
+              })
+
+              MKEmitter.emit('updateCustomComponent')
+            } else {
+              notification.warning({
+                top: 92,
+                message: result.message,
+                duration: 5
+              })
+            }
+            resolve()
+          })
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  render() {
+    const { menuOptions } = this.state
+
+    return (
+      <div className="mob-card-source-box">
+        {menuOptions.map((item, index) => (<SourceWrap key={index} item={item} triggerDel={this.triggerDel} />))}
+      </div>
+    )
+  }
+}
+
+export default ModelSource
\ No newline at end of file
diff --git a/src/mob/modelsource/index.scss b/src/mob/modulesource/index.scss
similarity index 78%
rename from src/mob/modelsource/index.scss
rename to src/mob/modulesource/index.scss
index db58054..cd91c8f 100644
--- a/src/mob/modelsource/index.scss
+++ b/src/mob/modulesource/index.scss
@@ -1,5 +1,5 @@
 .mob-card-source-box {
-  padding: 20px 0px 20px 15px;
+  padding: 20px 0px;
   position: relative;
 
   p {
diff --git a/src/mob/modulesource/option.jsx b/src/mob/modulesource/option.jsx
new file mode 100644
index 0000000..7fa85b7
--- /dev/null
+++ b/src/mob/modulesource/option.jsx
@@ -0,0 +1,42 @@
+import bar from '@/assets/mobimg/bar.png'
+import bar1 from '@/assets/mobimg/bar1.png'
+import line from '@/assets/mobimg/line.png'
+import line1 from '@/assets/mobimg/line1.png'
+import tabs from '@/assets/mobimg/tabs.png'
+import group from '@/assets/mobimg/group.png'
+import card1 from '@/assets/mobimg/card1.png'
+import card2 from '@/assets/mobimg/card2.png'
+import TableCard from '@/assets/mobimg/table-card.png'
+import NormalTable from '@/assets/mobimg/normal-table.png'
+import Pie from '@/assets/mobimg/pie.png'
+import SandBox from '@/assets/mobimg/sandbox.png'
+import Pie1 from '@/assets/mobimg/ring.png'
+import Pie2 from '@/assets/mobimg/nightingale.png'
+import Mainsearch from '@/assets/mobimg/mainsearch.png'
+import Navbar from '@/assets/mobimg/navbar-mob.png'
+import Carousel from '@/assets/mobimg/carousel.png'
+import Carousel1 from '@/assets/mobimg/carousel1.png'
+import form from '@/assets/mobimg/form.png'
+
+// 缁勪欢閰嶇疆淇℃伅
+export const menuOptions = [
+  { type: 'menu', url: Navbar, component: 'navbar', subtype: 'mobnavbar', title: '瀵艰埅鏍�', width: 1200 },
+  { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '鏍囩椤�', width: 24 },
+  { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24 },
+  { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', width: 24 },
+  { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', width: 24 },
+  { type: 'menu', url: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟', width: 24 },
+  { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24 },
+  { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24 },
+  { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 },
+  { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸', width: 12 },
+  { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
+  { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
+  { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '鏌辩姸鍥�', width: 24 },
+  { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '鏉″舰鍥�', width: 24 },
+  { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '楗煎浘', width: 12 },
+  { type: 'menu', url: Pie1, component: 'pie', subtype: 'ring', title: '鐜浘', width: 12 },
+  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
+  { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
+  { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24 },
+]
diff --git a/src/pc/menushell/index.jsx b/src/pc/menushell/index.jsx
index 7dac00b..29be748 100644
--- a/src/pc/menushell/index.jsx
+++ b/src/pc/menushell/index.jsx
@@ -1,6 +1,5 @@
 import React, { useState } from 'react'
 import { useDrop } from 'react-dnd'
-import { is, fromJS } from 'immutable'
 import update from 'immutability-helper'
 import { Empty, notification, Modal } from 'antd'
 
@@ -18,10 +17,7 @@
     const { card, index } = findCard(id)
     const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
     handleList({...menu, components: _cards})
-  }
-
-  if (!is(fromJS(cards), fromJS(menu.components))) {
-    setCards(menu.components)
+    setCards(_cards)
   }
   
   const findCard = id => {
@@ -33,7 +29,9 @@
   }
 
   const updateConfig = (element) => {
-    handleList({...menu, components: cards.map(item => item.uuid === element.uuid ? element : item)})
+    const _cards = cards.map(item => item.uuid === element.uuid ? element : item)
+    handleList({...menu, components: _cards})
+    setCards(_cards)
   }
 
   const deleteCard = (id) => {
@@ -55,7 +53,9 @@
       content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
       onOk() {
         MKEmitter.emit('delButtons', uuids)
-        handleList({...menu, components: cards.filter(item => item.uuid !== card.uuid)})
+        const _cards = cards.filter(item => item.uuid !== card.uuid)
+        handleList({...menu, components: _cards})
+        setCards(_cards)
       },
       onCancel() {}
     })
@@ -139,6 +139,7 @@
       const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
 
       handleList({...menu, components: _cards})
+      setCards(_cards)
     }
   })
 
diff --git a/src/tabviews/zshare/mutilform/index.jsx b/src/tabviews/zshare/mutilform/index.jsx
index f25ea69..bd8f48f 100644
--- a/src/tabviews/zshare/mutilform/index.jsx
+++ b/src/tabviews/zshare/mutilform/index.jsx
@@ -76,6 +76,7 @@
     formlist = formlist.map(item => {
       if (item.labelwidth) {
         item.labelCol = {style: {width: item.labelwidth + '%'}}
+        item.wrapperCol = {style: {width: (100 - item.labelwidth) + '%'}}
       }
       if (item.type === 'split' || item.type === 'hint') return item
 
@@ -716,7 +717,13 @@
       } else if (item.type === 'hint') {
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item colon={!!item.label} label={item.label || ' '} labelCol={item.labelCol} className="hint">
+            <Form.Item
+              colon={!!item.label}
+              label={item.label || ' '}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              className="hint"
+            >
               <div className="message">{item.message}</div>
             </Form.Item>
           </Col>
@@ -754,12 +761,17 @@
 
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval + '',
                 rules: [
@@ -782,12 +794,17 @@
 
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -810,12 +827,17 @@
       } else if (item.type === 'color') { // 棰滆壊閫夋嫨
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval || 'transparent',
                 rules: [
@@ -833,12 +855,18 @@
       } else if (item.type === 'checkcard') { // 澶氶�夋
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            } className="checkcard">
+            <Form.Item
+              className="checkcard"
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -854,12 +882,17 @@
       } else if (item.type === 'switch') { // 澶氶�夋
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -877,12 +910,17 @@
         
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: _initval,
                 rules: [
@@ -902,12 +940,17 @@
       } else if (item.type === 'radio') { // 鍗曢�夋
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -927,12 +970,17 @@
       } else if (item.type === 'select' || item.type === 'link') { // 涓嬫媺鎼滅储
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -961,12 +1009,17 @@
         let _initval = item.initval ? item.initval.split(',').filter(Boolean) : []
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: _initval,
                 rules: [
@@ -993,12 +1046,17 @@
       } else if (item.type === 'date') { // 鏃堕棿鎼滅储
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -1016,12 +1074,17 @@
       } else if (item.type === 'datemonth') {
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -1039,12 +1102,17 @@
       } else if (item.type === 'datetime') {
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -1081,12 +1149,17 @@
 
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: filelist,
                 rules: [
@@ -1104,12 +1177,17 @@
       } else if (item.type === 'linkMain') {
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -1135,12 +1213,17 @@
         }
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : item.label
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: [
@@ -1163,12 +1246,17 @@
 
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.hidelabel !== 'true' && item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <Icon type="question-circle" />
-                {item.label}
-              </Tooltip> : (item.hidelabel !== 'true' ? item.label : '')
-            }>
+            <Form.Item
+              extra={item.extra || null}
+              labelCol={item.labelCol}
+              wrapperCol={item.wrapperCol}
+              label={item.hidelabel !== 'true' && item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <Icon type="question-circle" />
+                  {item.label}
+                </Tooltip> : (item.hidelabel !== 'true' ? item.label : '')
+              }
+            >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval || '',
                 rules: [
diff --git a/src/templates/sharecomponent/columncomponent/index.jsx b/src/templates/sharecomponent/columncomponent/index.jsx
index c8061d3..a37af66 100644
--- a/src/templates/sharecomponent/columncomponent/index.jsx
+++ b/src/templates/sharecomponent/columncomponent/index.jsx
@@ -186,7 +186,7 @@
         _columnlist = _columnlist.filter(item => !item.origin || item.uuid === res.uuid) // 鍘婚櫎鍒濆鍒�
         _columnlist = _columnlist.map(item => {
           if (item.uuid !== res.uuid && res.field && item.field) {
-            if (item.field === res.field) {
+            if (item.field.toLowerCase() === res.field.toLowerCase()) {
               fieldrepet = true
             }
           }
diff --git a/src/views/mobdesign/index.jsx b/src/views/mobdesign/index.jsx
index a126428..bd6570b 100644
--- a/src/views/mobdesign/index.jsx
+++ b/src/views/mobdesign/index.jsx
@@ -1,46 +1,130 @@
 import React, { Component } from 'react'
 import { connect } from 'react-redux'
 import { DndProvider } from 'react-dnd'
-import { fromJS } from 'immutable'
+import { withRouter } from 'react-router'
+import { is, fromJS } from 'immutable'
 import moment from 'moment'
 import HTML5Backend from 'react-dnd-html5-backend'
-import { Icon, Tabs, notification, Modal } from 'antd'
-// import html2canvas from 'html2canvas'
+import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
+import antdEnUS from 'antd/es/locale/en_US'
+import antdZhCN from 'antd/es/locale/zh_CN'
+import MKEmitter from '@/utils/events.js'
+import MenuUtils from '@/utils/utils-custom.js'
 import asyncComponent from '@/utils/asyncComponent'
+import { modifyCustomMenu } from '@/store/action'
 
 import './index.scss'
 
-const { TabPane } = Tabs
+const { Panel } = Collapse
 const { confirm } = Modal
 
 const Header = asyncComponent(() => import('@/mob/header'))
-const Controller = asyncComponent(() => import('@/mob/controller'))
+const MenuForm = asyncComponent(() => import('./menuform'))
 const MobShell = asyncComponent(() => import('@/mob/mobshell'))
-const SourceWrap = asyncComponent(() => import('@/mob/modelsource'))
-const DataSource = asyncComponent(() => import('@/mob/datasource'))
+const SourceWrap = asyncComponent(() => import('@/mob/modulesource'))
+const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
+const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
+const Quotecomponent = asyncComponent(() => import('@/pc/quotecomponent'))
+const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
+const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
+const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
+const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
+const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller'))
+const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller'))
+const StyleCombControlButton = asyncComponent(() => import('@/menu/stylecombcontrolbutton'))
+const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
 
-class Mobile extends Component {
+sessionStorage.setItem('isEditState', 'true')
+sessionStorage.setItem('editMenuType', 'menu') // 缂栬緫鑿滃崟绫诲瀷
+sessionStorage.setItem('appType', 'mob')       // 搴旂敤绫诲瀷
+document.body.className = ''
+window.GLOB.UserComponentMap = new Map() // 缂撳瓨鐢ㄦ埛鑷畾涔夌粍浠�
+window.GLOB.CacheIndependent = new Map()
+window.GLOB.urlFields = []               // url鍙橀噺
+
+class MobDesign extends Component {
   state = {
+    localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS,
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    appId: this.props.match.params.appId,
-    appType: this.props.match.params.appType,
-    appCode: this.props.match.params.appCode,
-    appName: this.props.match.params.appName,
+    loading: true,
+    MenuId: '',
+    MenuName: '',
+    MenuNo: '',
+    delButtons: [],
+    copyButtons: [],
+    thawButtons: [],
+    activeKey: 'basedata',
+    menuloading: false,
     oriConfig: null,
-    parentId: '',
-    openEdition: '',
     config: null,
-    pageIndex: 0,
-    editElem: null
+    visible: false,
+    customComponents: [],
   }
 
   UNSAFE_componentWillMount() {
-    this.getAppParam(this.props.match.params.appId)
+    if (this.props.memberLevel < 30) return
+    try {
+      let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
+
+      if (param.type === 'app') {
+        sessionStorage.setItem('appId', param.ID || '')
+        sessionStorage.setItem('lang', param.lang || 'zh-CN')
+        sessionStorage.setItem('kei_no', param.kei_no || '')
+        sessionStorage.setItem('link_type', param.link_type || 'true')
+        sessionStorage.setItem('role_type', param.role_type || 'true')
+        sessionStorage.setItem('login_types', param.login_types || 'true')
+
+        this.setState({
+          localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS,
+          dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+        })
+        this.getAppMessage()
+      } else if (param.type === 'view') {
+        this.setState({
+          MenuId: param.MenuID
+        }, () => {
+          this.getMenuParam(param)
+        })
+      }
+    } catch {
+      notification.warning({
+        top: 92,
+        message: '鑿滃崟淇℃伅瑙f瀽閿欒锛�',
+        duration: 5
+      })
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (this.props.match.params.param !== nextProps.match.params.param) {
+      window.location.reload()
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    if (this.props.memberLevel < 30) {
+      document.getElementById('mk-mob-design-view').innerHTML = '<div style="text-align: center; font-size: 30px; margin-top: 40vh; height: 100vh; background: #fff;">鏈簲鐢ㄦ病鏈塒C绔〉闈㈢殑缂栬緫鏉冮檺锛岃鑱旂郴绠$悊鍛橈紒</div>'
+      return
+    }
+    MKEmitter.addListener('delButtons', this.delButtons)
+    MKEmitter.addListener('thawButtons', this.thawButtons)
+    MKEmitter.addListener('copyButtons', this.copyButtons)
+    MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
+    MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
+    MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent)
+    setTimeout(() => {
+      this.updateCustomComponent()
+      this.getAppPictures()
+    }, 1000)
   }
 
   /**
@@ -50,214 +134,1324 @@
     this.setState = () => {
       return
     }
+    MKEmitter.removeListener('delButtons', this.delButtons)
+    MKEmitter.removeListener('thawButtons', this.thawButtons)
+    MKEmitter.removeListener('copyButtons', this.copyButtons)
+    MKEmitter.removeListener('changeEditMenu', this.changeEditMenu)
+    MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
+    MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent)
   }
 
-  triggerSave = () => {
-    const { config, openEdition, parentId } = this.state
+  changeEditMenu = (menu) => {
+    const { oriConfig, config } = this.state
+
+    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
+      notification.warning({
+        top: 92,
+        message: '閰嶇疆淇℃伅鏈繚瀛橈紒',
+        duration: 5
+      })
+      return
+    }
 
     let param = {
-      func: 'sPC_TrdMenu_AddUpt',
-      ParentID: config.entrance ? '' : parentId,
-      MenuID: config.uuid,
-      MenuNo: config.MenuNo,
-      EasyCode: '',
-      Template: '',
-      MenuName: '',
-      PageParam: '',
-      LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(config))),
-      // LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
-      // LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`),
-      TypeCharOne: 'mob'
+      MenuID: menu.MenuID,
+      copyMenuId: menu.copyMenuId || '',
+      type: 'view'
     }
 
-    let _LText = ''
-    // _LText = _LText.join(' union all ')
-    let _LTexttb = ''
-    // _LTexttb = _LTexttb.join(' union all ')
-    
-    param.LText = Utils.formatOptions(_LText)
-    param.LTexttb = Utils.formatOptions(_LTexttb)
-    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-
-    if (openEdition) { // 鐗堟湰绠$悊
-      param.open_edition = openEdition
+    if (menu.fixed && menu.MenuNo && menu.MenuName) {
+      param.fixed = true
+      param.MenuNo = menu.MenuNo
+      param.MenuName = menu.MenuName
     }
 
-    Api.getSystemConfig(param).then(response => {
-      if (response.status) {
-        this.setState({
-          oriConfig: fromJS(config).toJS(),
-          openEdition: response.open_edition || '',
-        })
-      } else {
-        notification.warning({
-          top: 92,
-          message: response.message,
-          duration: 5
-        })
-      }
-    })
-    
+    param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
+
+    if (param === this.props.match.params.param) return
+
+    this.props.history.push('/mobdesign/' + param)
   }
 
-  getAppParam = (id) => {
+  getAppMessage = () => {
     Api.getSystemConfig({
-      func: 'sPC_Get_LongParam',
-      MenuID: id,
-      TypeCharOne: 'mob'
-    }).then(result => {
-      if (result.status) {
-        let config = null
+      func: 's_get_keyids',
+      bid: sessionStorage.getItem('appId')
+    }).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
 
-        if (result.LongParam) {
-          try {
-            config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
-          } catch (e) {
-            console.warn('Parse Failure')
-            config = null
+      let homeId = ''
+      let appViewList = []
+      if (res.data && res.data.length > 0) {
+        appViewList = res.data
+        appViewList.forEach(item => {
+          if (item.keys_type === 'index') {
+            homeId = item.keys_id
           }
+        })
+      }
+
+      if (!homeId) {
+        homeId = Utils.getuuid()
+
+        let param = {
+          func: 's_kei_link_keyids_addupt',
+          BID: sessionStorage.getItem('appId'),
+          exec_type: 'y',
+          LText: ''
         }
 
-        if (!config) {
-          config = {
-            version: 1.0,
-            entrance: true,
-            label: '',
-            uuid: this.props.match.params.appId,
-            pageIndex: 0,
-            MenuNo: this.props.match.params.appCode,
-            sourcelist: [],
-            components: []
+        appViewList.unshift({
+          appkey: window.GLOB.appkey || '',
+          bid: sessionStorage.getItem('appId') || '',
+          kei_no: sessionStorage.getItem('kei_no') || '',
+          keys_id: homeId,
+          keys_type: 'index',
+          remark: '棣栭〉'
+        })
+
+        param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
+        param.LText = param.LText.join(' union all ')
+        param.LText = Utils.formatOptions(param.LText)
+  
+        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+        param.secretkey = Utils.encrypt('', param.timestamp)
+
+        Api.getSystemConfig(param).then(result => {
+          if (!result.status) {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          } else {
+            sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
+            sessionStorage.setItem('appHomeId', homeId)
+            this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
           }
-        }
-        this.setState({
-          oriConfig: config,
-          config: fromJS(config).toJS(),
-          openEdition: result.open_edition || '',
         })
       } else {
+        sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
+        sessionStorage.setItem('appHomeId', homeId)
+        this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
+      }
+    })
+  }
+
+  getAppPictures = () => {
+    if (sessionStorage.getItem('app_videos') || sessionStorage.getItem('app_pictures')) return
+
+    Api.getSystemConfig({
+      func: 's_url_db_adduptdel',
+      PageIndex: 0,  // 0 浠h〃鍏ㄩ儴
+      PageSize: 0,   // 0 浠h〃鍏ㄩ儴
+      typecharone: 'image',
+      type: 'search'
+    }).then(res => {
+      if (res.status) {
+        sessionStorage.setItem('app_pictures', JSON.stringify(res.data || []))
+      }
+
+      Api.getSystemConfig({
+        func: 's_url_db_adduptdel',
+        PageIndex: 0,  // 0 浠h〃鍏ㄩ儴
+        PageSize: 0,   // 0 浠h〃鍏ㄩ儴
+        typecharone: 'video',
+        type: 'search'
+      }).then(res => {
+        if (res.status) {
+          sessionStorage.setItem('app_videos', JSON.stringify(res.data || []))
+        }
+      })
+    })
+  }
+
+  updateCustomComponent = () => {
+    Api.getSystemConfig({
+      func: 's_get_custom_components',
+      typecharone: ''
+    }).then(res => {
+      let coms = []
+      if (res.cus_list && res.cus_list.length > 0) {
+        res.cus_list.forEach(item => {
+          let config = ''
+
+          try {
+            config = JSON.parse(window.decodeURIComponent(window.atob(item.long_param)))
+          } catch (e) {
+            console.warn('Parse Failure')
+            config = ''
+          }
+
+          if (!config || !item.c_name) return
+
+          window.GLOB.UserComponentMap.set(item.c_id, item.c_name)
+          coms.push({
+            uuid: item.c_id,
+            type: 'menu',
+            title: item.c_name,
+            url: item.images,
+            component: config.type,
+            subtype: config.subtype,
+            width: config.width || 24,
+            config
+          })
+        })
+      }
+      this.setState({customComponents: coms})
+      this.getRoleFields()
+    })
+  }
+
+  updateComponentStyle = (parentId, keys, style) => {
+    const { config } = this.state
+
+    if (config.uuid !== parentId) return
+
+    let components = config.components.map(item => {
+      if (keys.includes(item.uuid)) {
+        item.style = {...item.style, ...style}
+      }
+      return item
+    })
+
+    this.setState({
+      config: {...config, components: []}
+    }, () => {
+      this.setState({
+        config: {...config, components: components}
+      })
+    })
+  }
+
+  delButtons = (items) => {
+    const { copyButtons, delButtons } = this.state
+
+    this.setState({
+      delButtons: [...delButtons, ...items],
+      copyButtons: copyButtons.filter(item => !items.includes(item.uuid))
+    })
+  }
+
+  copyButtons = (items) => {
+    this.setState({copyButtons: [...this.state.copyButtons, ...items]})
+  }
+  
+  thawButtons = (item) => {
+    this.setState({thawButtons: [...this.state.thawButtons, item]})
+  }
+
+  closeView = () => {
+    const { oriConfig, config } = this.state
+
+    if (!config) {
+      window.close()
+      return
+    }
+
+    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
+      confirm({
+        title: '閰嶇疆淇℃伅鏈繚瀛橈紝纭畾鍏抽棴鍚楋紵',
+        content: '',
+        onOk() {
+          window.close()
+        },
+        onCancel() {}
+      })
+    } else {
+      window.close()
+    }
+  }
+
+  getMenuParam = (urlParam) => {
+    const { MenuId } = this.state
+
+    let param = {
+      func: 'sPC_Get_LongParam',
+      TypeCharOne: sessionStorage.getItem('kei_no'),
+      typename: 'mob',
+      MenuID: MenuId
+    }
+
+    Api.getSystemConfig(param).then(result => {
+      if (!result.status) {
         notification.warning({
           top: 92,
           message: result.message,
           duration: 5
         })
+        this.setState({loading: false})
+        return
+      } else if (!result.LongParam && urlParam.copyMenuId) {
+        this.getCopyParam(urlParam)
+      } else {
+        let config = null
+        let isCreate = false
+
+        try {
+          config = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : null
+        } catch (e) {
+          console.warn('Parse Failure')
+          config = null
+        }
+
+        if (!config) {
+          isCreate = true
+          config = {
+            version: 1.0,
+            uuid: MenuId,
+            MenuID: MenuId,
+            Template: 'webPage',
+            enabled: false,
+            MenuName: '',
+            MenuNo: '',
+            tables: [],
+            components: [],
+            viewType: 'menu',
+            style: {
+              backgroundColor: '#ffffff', backgroundImage: '', paddingLeft: '20px', paddingRight: '20px'
+            }
+          }
+        }
+        
+        config.uuid = MenuId
+        config.MenuID = MenuId
+        config.open_edition = result.open_edition || ''
+        window.GLOB.urlFields = config.urlFields || []
+
+        if (urlParam.fixed) {
+          config.fixed = true
+          config.MenuName = urlParam.MenuName
+          config.MenuNo = urlParam.MenuNo
+        }
+
+        let indeComs = []
+        config.components.forEach(item => {
+          if (item.type === 'navbar') {
+            indeComs.push(fromJS(item).toJS())
+          }
+        })
+
+        if (indeComs.length === 0) {
+          this.setState({
+            oriConfig: isCreate ? null : config,
+            config: fromJS(config).toJS(),
+            loading: false
+          })
+  
+          this.props.modifyCustomMenu(config)
+        } else {
+          this.jointComponents(config, indeComs, isCreate)
+        }
+      }
+    })
+    this.getAppMenus()
+  }
+
+  getAppMenus = () => {
+    let _param = {
+      func: 's_get_app_menus',
+      TypeCharOne: sessionStorage.getItem('kei_no'),
+      typename: 'mob',
+      LText: `select '${window.GLOB.appkey}'`,
+      timestamp: moment().format('YYYY-MM-DD HH:mm:ss')
+    }
+
+    _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
+
+    Api.getSystemConfig(_param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      let appIndeList = sessionStorage.getItem('appViewList')
+      appIndeList = JSON.parse(appIndeList)
+      appIndeList = appIndeList.map(item => (item.keys_type !== 'index' ? item.keys_id : '')).join(',')
+
+      let menus = res.menus.filter(item => appIndeList.indexOf(item.MenuID) === -1)
+      sessionStorage.setItem('appMenus', JSON.stringify(menus))
+    })
+  }
+
+  getCopyParam = (urlParam) => {
+    const { MenuId } = this.state
+
+    let param = {
+      func: 'sPC_Get_LongParam',
+      TypeCharOne: sessionStorage.getItem('kei_no'),
+      typename: 'mob',
+      MenuID: urlParam.copyMenuId
+    }
+
+    Api.getSystemConfig(param).then(result => {
+      if (!result.status) {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        this.setState({loading: false})
+        return
+      } else if (!result.LongParam) {
+        notification.warning({
+          top: 92,
+          message: '鏈煡璇㈠埌澶嶅埗鑿滃崟閰嶇疆淇℃伅锛�',
+          duration: 5
+        })
+      }
+
+      let config = null
+
+      try {
+        config = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : null
+      } catch (e) {
+        console.warn('Parse Failure')
+        config = null
+      }
+
+      
+      if (!config) {
+        config = {
+          version: 1.0,
+          uuid: MenuId,
+          MenuID: MenuId,
+          Template: 'webPage',
+          enabled: false,
+          MenuName: '',
+          MenuNo: '',
+          tables: [],
+          components: [],
+          viewType: 'menu',
+          style: {
+            backgroundColor: '#ffffff', backgroundImage: '', paddingLeft: '20px', paddingRight: '20px'
+          }
+        }
+      } else {
+        config.components = MenuUtils.resetConfig(config.components)
+        message.success('澶嶅埗鎴愬姛锛屼繚瀛樺悗鐢熸晥銆�')
+      }
+      
+      config.uuid = MenuId
+      config.MenuID = MenuId
+      config.open_edition = ''
+
+      let indeComs = []
+      config.components.forEach(item => {
+        if (item.type === 'navbar') {
+          indeComs.push(fromJS(item).toJS())
+        }
+      })
+
+      if (indeComs.length === 0) {
+        this.setState({
+          oriConfig: null,
+          config: fromJS(config).toJS(),
+          loading: false
+        })
+
+        this.props.modifyCustomMenu(config)
+      } else {
+        this.jointComponents(config, indeComs, true)
       }
     })
   }
 
-  deleteCard = (id) => {
-    let _this = this
+  jointComponents = (config, indeComs, isCreate) => {
+    let deffers = indeComs.map(item => {
+      return new Promise(resolve => {
+        Api.getSystemConfig({
+          func: 'sPC_Get_LongParam',
+          TypeCharOne: sessionStorage.getItem('kei_no'),
+          typename: 'mob',
+          MenuID: item.uuid
+        }).then(res => {
+          res.uuid = item.uuid
+
+          if (!res.status) {
+            notification.warning({
+              top: 92,
+              message: res.message,
+              duration: 5
+            })
+          }
+          
+          resolve(res)
+        })
+      })
+    })
+    Promise.all(deffers).then(result => {
+      let _conf = {}
+      result.forEach(res => {
+        let _config = null
+        try {
+          _config = res.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(res.LongParam))) : null
+        } catch (e) {
+          console.warn('Parse Failure')
+          _config = null
+        }
+
+        if (_config) {
+          _config.open_edition = res.open_edition || ''
+          _conf[res.uuid] = _config
+          window.GLOB.CacheIndependent.set(res.uuid, fromJS(_config).toJS())
+        }
+      })
+
+      let _length = config.components.length
+      config.components = config.components.map(item => {
+        if (item.type === 'navbar') {
+          if (_conf[item.uuid]) {
+            item = _conf[item.uuid]
+          } else {
+            item = null
+          }
+        }
+        return item
+      })
+
+      config.components = config.components.filter(Boolean)
+
+      if (_length > config.components.length) {
+        notification.warning({
+          top: 92,
+          message: '閮ㄥ垎缁勪欢宸插垹闄わ紒',
+          duration: 5
+        })
+      }
+
+      this.setState({
+        oriConfig: isCreate ? null : fromJS(config).toJS(),
+        config: config,
+        loading: false
+      })
+
+      this.props.modifyCustomMenu(config)
+    })
+  }
+
+  getMenuMessage = () => {
+    const { config } = this.state
+    let buttons = []
+    let _sort = 1
+
+    let traversal = (components) => {
+      components.forEach(item => {
+        if (item.type === 'tabs') {
+          item.subtabs.forEach(tab => {
+            traversal(tab.components)
+          })
+        } else if (item.type === 'group') {
+          traversal(item.components)
+        } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
+          item.action && item.action.forEach(btn => {
+            this.checkBtn(btn)
+            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
+            _sort++
+          })
+          item.subcards.forEach(card => {
+            card.elements && card.elements.forEach(cell => {
+              if (cell.eleType !== 'button') return
+              this.checkBtn(cell)
+              buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
+              _sort++
+            })
+            card.backElements && card.backElements.forEach(cell => {
+              if (cell.eleType !== 'button') return
+              this.checkBtn(cell)
+              buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
+              _sort++
+            })
+          })
+        } else if (item.type === 'line' || item.type === 'bar') {
+          item.action && item.action.forEach(btn => {
+            this.checkBtn(btn)
+            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
+            _sort++
+          })
+        } else if (item.type === 'table' && item.subtype === 'normaltable') {
+          item.action && item.action.forEach(btn => {
+            this.checkBtn(btn)
+            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
+            _sort++
+          })
+          item.cols && item.cols.forEach(col => {
+            if (col.type !== 'action') return
+            col.elements.forEach(btn => {
+              this.checkBtn(btn)
+              buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
+              _sort++
+            })
+          })
+        }
+      })
+    }
+
+    traversal(config.components)
+
+    return buttons
+  }
+
+  checkBtn = (btn) => {
+    if (['prompt', 'exec', 'pop'].includes(btn.OpenType) && btn.Ot === 'required' && btn.verify && btn.verify.scripts && btn.verify.scripts.length > 0) {
+      let hascheck = false
+      btn.verify.scripts.forEach(item => {
+        if (item.status === 'false') return
+  
+        if (/\$check@|@check\$/ig.test(item.sql)) {
+          hascheck = true
+        }
+      })
+      if (hascheck) {
+        notification.warning({
+          top: 92,
+          message: `鍙�夋嫨澶氳鐨勬寜閽��${btn.label}銆嬩腑 $check@ 鎴� @check$ 灏嗕笉浼氱敓鏁堬紒`,
+          duration: 5
+        })
+      }
+    }
+  }
+
+  filterConfig = (components) => {
+    return components.map(item => {
+      if (item.type === 'tabs') {
+        item.subtabs.forEach(tab => {
+          tab.components = this.filterConfig(tab.components)
+        })
+      } else if (item.type === 'group') {
+        item.components = this.filterConfig(item.components)
+      } else if (item.type === 'table' && item.subtype === 'normaltable') {
+        item.search = item.search.filter(a => !a.origin)
+        item.action = item.action.filter(a => !a.origin)
+        item.cols = item.cols.filter(a => !a.origin)
+      }
+      return item
+    })
+  }
+
+  submitConfig = () => {
+    const { delButtons, copyButtons, thawButtons } = this.state
     let config = fromJS(this.state.config).toJS()
 
-    confirm({
-      title: '纭畾鍒犻櫎鍏冪礌鍚楋紵',
-      content: '',
-      okText: this.state.dict['mob.confirm'],
-      cancelText: this.state.dict['mob.cancel'],
-      onOk() {
-        config.components = config.components.filter(item => item.uuid !== id)
+    if (!config.MenuName || !config.MenuNo || (config.cacheUseful === 'true' && !config.cacheTime)) {
+      notification.warning({
+        top: 92,
+        message: '璇峰畬鍠勮彍鍗曞熀鏈俊鎭紒',
+        duration: 5
+      })
+      this.setState({
+        activeKey: 'basedata'
+      })
+      return
+    }
 
-        _this.setState({
-          config: config
+    this.setState({
+      menuloading: true
+    })
+
+    setTimeout(() => {
+      config.components = this.filterConfig(config.components)
+
+      if (config.enabled && this.verifyConfig()) {
+        config.enabled = false
+      }
+
+      let parMenuId = sessionStorage.getItem('kei_no') + 'pc' + sessionStorage.getItem('lang')
+      let param = {
+        func: 'sPC_TrdMenu_AddUpt',
+        FstID: parMenuId,
+        SndID: parMenuId,
+        ParentID: parMenuId,
+        MenuID: config.uuid,
+        MenuNo: config.MenuNo || '',
+        EasyCode: '',
+        Template: 'webPage',
+        TypeCharOne: sessionStorage.getItem('kei_no'),
+        Typename: 'pc',
+        MenuName: config.MenuName || '',
+        PageParam: JSON.stringify({Template: 'webPage'}),
+        open_edition: config.open_edition,
+        LText: '',
+        LTexttb: ''
+      }
+
+      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+      param.secretkey = Utils.encrypt('', param.timestamp)
+
+      let btnParam = {             // 娣诲姞鑿滃崟鎸夐挳
+        func: 'sPC_Button_AddUpt',
+        Type: 40,                  // 娣诲姞鑿滃崟涓嬬殑鎸夐挳type涓�40锛屾寜閽笅鐨勬寜閽畉ype涓�60
+        ParentID: config.uuid,
+        MenuNo: config.MenuNo,
+        Template: 'webPage',
+        PageParam: '',
+        LongParam: '',
+        LText: []
+      }
+
+      btnParam.LText = this.getMenuMessage()
+      btnParam.LText = btnParam.LText.join(' union all ')
+
+      let btnIds = btnParam.LText // 鐢ㄤ簬澶嶅埗鎸夐挳鐨勮繃婊�
+
+      btnParam.LText = Utils.formatOptions(btnParam.LText)
+      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
+
+      new Promise(resolve => {
+        let _config = fromJS(config).toJS()
+        let indeComs = []
+        _config.components = _config.components.map(item => {
+          if (item.type === 'navbar') {
+            indeComs.push(item)
+            return {
+              type: 'navbar',
+              uuid: item.uuid
+            }
+          }
+          return item
+        })
+
+        param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
+
+        if (indeComs.length === 0) {
+          resolve(true)
+        } else {
+          let new_open_edition = {}
+          let deffers = indeComs.map(item => {
+            return new Promise(resolve => {
+              let _item = window.GLOB.CacheIndependent.get(item.uuid)
+              if (_item && is(fromJS(_item), fromJS(item))) {
+                new_open_edition[item.uuid] = item.open_edition || ''
+                resolve()
+                return
+              }
+
+              let _param = {
+                func: 'sPC_TrdMenu_AddUpt',
+                FstID: parMenuId,
+                SndID: parMenuId,
+                ParentID: parMenuId,
+                MenuID: item.uuid,
+                MenuNo: item.wrap.MenuNo || '',
+                EasyCode: '',
+                Template: item.type,
+                TypeCharOne: sessionStorage.getItem('kei_no'),
+                Typename: 'pc',
+                MenuName: item.name || '',
+                PageParam: JSON.stringify({Template: item.type}),
+                open_edition: item.open_edition || '',
+                LText: '',
+                LTexttb: ''
+              }
+
+              _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(item)))
+              _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+              _param.secretkey = Utils.encrypt('', _param.timestamp)
+
+              let appMenuParam = null
+              if (item.type === 'navbar') {
+                appMenuParam = {
+                  func: 's_appmenus_addupt',
+                  exec_type: 'y'
+                }
+  
+                appMenuParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+                appMenuParam.secretkey = Utils.encrypt('', _param.timestamp)
+
+                let LText = []
+                let app_param = []
+                let kei_no = sessionStorage.getItem('kei_no')
+                let userid = sessionStorage.getItem('CloudUserID') || ''
+
+                item.menus.forEach((fst, findex) => {
+                  // LText.push(`select '${fst.MenuID}','${fst.name}','','0','${sessionStorage.getItem('appId')}','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`)
+                  LText.push(`select '${fst.MenuID}','${fst.name}','','0','0','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`)
+                  app_param.push(`select '${window.GLOB.appkey}','${fst.MenuID}','${userid}','${(findex + 1) * 10}','','${fst.name}','${fst.MenuNo || ''}','0','10','${kei_no}','pc'`)
+                  if (fst.property === 'classify' && fst.sublist.length > 0) {
+                    fst.sublist.forEach(scd => {
+                      LText.push(`select '${scd.MenuID}','${scd.name}','','0','${fst.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${scd.MenuNo || ''}','${kei_no}','pc'`)
+                      app_param.push(`select '${window.GLOB.appkey}','${scd.MenuID}','${userid}','${(findex + 1) * 10}','','${scd.name}','${scd.MenuNo || ''}','${fst.MenuID}','20','${kei_no}','pc'`)
+                    
+                      if (scd.property === 'classify' && scd.sublist.length > 0) {
+                        scd.sublist.forEach(thd => {
+                          LText.push(`select '${thd.MenuID}','${thd.name}','','0','${scd.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${thd.MenuNo || ''}','${kei_no}','pc'`)
+                          app_param.push(`select '${window.GLOB.appkey}','${thd.MenuID}','${userid}','${(findex + 1) * 10}','','${thd.name}','${thd.MenuNo || ''}','${scd.MenuID}','20','${kei_no}','pc'`)
+                        })
+                      }
+                    })
+                  }
+                })
+                appMenuParam.LText = Utils.formatOptions(LText.join(' union '))
+                appMenuParam.LText1 = Utils.formatOptions(app_param.join(' union '))
+              }
+
+              if (appMenuParam) {
+                Api.getSystemConfig(appMenuParam).then(_res => {
+                  if (!_res.status) {
+                    notification.warning({
+                      top: 92,
+                      message: _res.message,
+                      duration: 5
+                    })
+                    this.setState({ menuloading: false })
+                    return
+                  }
+
+                  Api.getSystemConfig(_param).then(res => {
+                    if (!res.status) {
+                      notification.warning({
+                        top: 92,
+                        message: res.message,
+                        duration: 5
+                      })
+                      this.setState({ menuloading: false })
+                      return
+                    }
+    
+                    new_open_edition[item.uuid] = res.open_edition || ''
+                    
+                    resolve()
+                  })
+                })
+              } else {
+                Api.getSystemConfig(_param).then(res => {
+                  if (!res.status) {
+                    notification.warning({
+                      top: 92,
+                      message: res.message,
+                      duration: 5
+                    })
+                    this.setState({ menuloading: false })
+                    return
+                  }
+  
+                  new_open_edition[item.uuid] = res.open_edition || ''
+                  resolve()
+                })
+              }
+            })
+          })
+          Promise.all(deffers).then(() => {
+            let appViewList = sessionStorage.getItem('appViewList')
+            appViewList = JSON.parse(appViewList)
+            let _length = appViewList.length
+            let appIndeList = appViewList.map(item => item.keys_id).join(',')
+            
+
+            config.components = config.components.map(item => {
+              if (item.type === 'navbar') {
+                item.open_edition = new_open_edition[item.uuid] || ''
+                window.GLOB.CacheIndependent.set(item.uuid, fromJS(item).toJS())
+
+                if (appIndeList.indexOf(item.uuid) === -1) {
+                  appViewList.unshift({
+                    appkey: window.GLOB.appkey || '',
+                    bid: sessionStorage.getItem('appId') || '',
+                    kei_no: sessionStorage.getItem('kei_no') || '',
+                    keys_id: item.uuid,
+                    keys_type: 'navbar',
+                    remark: item.name
+                  })
+                }
+              }
+              return item
+            })
+
+            if (appViewList.length > _length) {
+              let param = {
+                func: 's_kei_link_keyids_addupt',
+                BID: sessionStorage.getItem('appId'),
+                exec_type: 'y',
+                LText: ''
+              }
+    
+              param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
+              param.LText = param.LText.join(' union all ')
+              param.LText = Utils.formatOptions(param.LText)
+        
+              param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+              param.secretkey = Utils.encrypt('', param.timestamp)
+    
+              Api.getSystemConfig(param).then(result => {
+                if (!result.status) {
+                  notification.warning({
+                    top: 92,
+                    message: result.message,
+                    duration: 5
+                  })
+                  this.setState({ menuloading: false })
+                } else {
+                  sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
+                  resolve(true)
+                }
+              })
+            } else {
+              resolve(true)
+            }
+          })
+        }
+      }).then(res => { // 鎸夐挳鎴栬彍鍗曞垹闄�
+        if (!res) return
+
+        if (delButtons.length === 0) {
+          return { status: true, nonexec: true }
+        } else {
+          let appHomeId = sessionStorage.getItem('appHomeId')
+          let _param = {
+            func: 'sPC_MainMenu_Del',
+            MenuID: delButtons.filter(id => id !== appHomeId).join(',')
+          }
+          return Api.getSystemConfig(_param)
+        }
+      }).then(res => { // 鎸夐挳瑙i櫎鍐荤粨
+        if (!res) return
+        if (!res.status) {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+          return false
+        } else if (!res.nonexec) { // 鎵ц鍒犻櫎鍚庡埛鏂拌彍鍗曞垪琛�
+          this.getAppMenus()
+        }
+
+        let ids = thawButtons.filter(item => btnIds.indexOf(item) !== -1)
+        if (ids.length === 0) {
+          return { status: true }
+        } else {
+          return Api.getSystemConfig({
+            func: 'sPC_MainMenu_ReDel',
+            MenuID: ids.join(',')
+          })
+        }
+      }).then(res => { // 椤甸潰淇濆瓨
+        if (!res) return
+
+        if (res.status) {
+          return Api.getSystemConfig(param)
+        } else {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+          return false
+        }
+      }).then(res => { // 椤甸潰鎸夐挳鍏崇郴淇濆瓨
+        if (!res) return
+
+        if (res.status) {
+          config.open_edition = res.open_edition || ''
+
+          this.setState({
+            oriConfig: fromJS(config).toJS(),
+          })
+
+          if (btnParam.LText) {
+            return Api.getSystemConfig(btnParam)
+          } else {
+            return {
+              status: true
+            }
+          }
+        } else {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+          return false
+        }
+      }).then(res => { // 鎸夐挳澶嶅埗
+        if (!res) return
+        if (!res.status) {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+          return false
+        }
+
+        if (copyButtons.length === 0) {
+          return {
+            status: true
+          }
+        } else {
+          return new Promise(resolve => {
+            let deffers = copyButtons.map(item => {
+              return new Promise(resolve => {
+                if (btnIds.indexOf(item.uuid) === -1) { // 澶嶅埗鐨勬寜閽凡鍒犻櫎
+                  resolve({
+                    status: true
+                  })
+                  return
+                }
+
+                Api.getSystemConfig({
+                  func: 'sPC_Get_LongParam',
+                  MenuID: item.$originUuid
+                }).then(result => {
+                  if (result.status) {
+                    let _conf = ''
+              
+                    try {
+                      _conf = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : ''
+                    } catch (e) {
+                      console.warn('Parse Failure')
+                      _conf = ''
+                    }
+                    
+                    if (_conf) {
+                      _conf.components = MenuUtils.resetConfig(_conf.components)
+                      _conf.uuid = item.uuid
+                      _conf.MenuID = item.uuid
+                      _conf.Template = 'webPage'
+                    } else {
+                      resolve({
+                        status: true
+                      })
+                      return
+                    }
+
+                    let _param = {
+                      func: 'sPC_ButtonParam_AddUpt',
+                      ParentID: config.uuid,
+                      MenuID: item.uuid,
+                      MenuNo: '',
+                      Template: 'webPage',
+                      MenuName: item.label,
+                      PageParam: JSON.stringify({Template: 'webPage'}),
+                      LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(_conf)))
+                    }
+            
+                    Api.getSystemConfig(_param).then(response => {
+                      resolve(response)
+                    })
+                  }
+                })
+              })
+            })
+            Promise.all(deffers).then(result => {
+              let error = null
+              result.forEach(response => {
+                if (!response.status) {
+                  error = response
+                }
+              })
+    
+              if (error) {
+                notification.warning({
+                  top: 92,
+                  message: error.message,
+                  duration: 5
+                })
+                resolve(false)
+              } else {
+                resolve({
+                  status: true
+                })
+              }
+            })
+          })
+        }
+      }).then(res => {
+        if (res && res.status) {
+          this.setState({
+            delButtons: [],
+            copyButtons: [],
+            thawButtons: [],
+            menuloading: false,
+            config: {...config, components: []}
+          }, () => {
+            this.setState({
+              config: {...this.state.config, components: this.state.oriConfig.components}
+            })
+          })
+          notification.success({
+            top: 92,
+            message: '淇濆瓨鎴愬姛',
+            duration: 2
+          })
+        } else {
+          this.setState({
+            menuloading: false
+          })
+        }
+      })
+    }, 300)
+  }
+
+  getRoleFields = () => {
+    if (sessionStorage.getItem('sysRoles') || sessionStorage.getItem('permFuncField')) return
+    Api.getSystemConfig({func: 'sPC_Get_Roles_sModular'}).then(res => {
+      if (res.status) {
+        let _permFuncField = []
+        let _sysRoles = []
+
+        if (res.Roles && res.Roles.length > 0) {
+          _sysRoles = res.Roles.map(role => {
+            return {
+              uuid: Utils.getuuid(),
+              value: role.RoleID,
+              text: role.RoleName
+            }
+          })
+        }
+
+        if (res.sModular && res.sModular.length > 0) {
+          res.sModular.forEach(field => {
+            if (field.ModularNo) {
+              _permFuncField.push(field.ModularNo)
+            }
+          })
+          _permFuncField = _permFuncField.sort()
+        }
+
+        sessionStorage.setItem('sysRoles', JSON.stringify(_sysRoles))
+        sessionStorage.setItem('permFuncField', JSON.stringify(_permFuncField))
+      }
+    })
+  }
+
+  onEnabledChange = () => {
+    const { config } = this.state
+
+    if (!config || (!config.enabled && this.verifyConfig(true))) {
+      return
+    }
+
+    this.setState({
+      config: {...config, enabled: !config.enabled}
+    })
+  }
+
+  verifyConfig = (show) => {
+    const { config } = this.state
+    let error = ''
+
+    config.components.forEach(item => {
+      if (error) return
+      if (['propcard', 'brafteditor', 'sandbox'].includes(item.subtype) && 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) {
+          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+        } else if (item.setting.interType && !item.setting.primaryKey) {
+          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
+        }
+      }
+      if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
+        if (!item.plot.Xaxis) {
+          error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
+        }
+      }
+    })
+
+    if (show && error) {
+      notification.warning({
+        top: 92,
+        message: error,
+        duration: 5
+      })
+    }
+
+    return error
+  }
+
+  // 鏇存柊閰嶇疆淇℃伅
+  updateConfig = (config) => {
+    this.setState({
+      config: config
+    })
+
+    this.props.modifyCustomMenu(config)
+  }
+
+  insert = (item) => {
+    let config = fromJS(this.state.config).toJS()
+
+    config.components.push(item)
+
+    this.setState({config})
+    this.props.modifyCustomMenu(config)
+  }
+
+  refreshView = () => {
+    const { oriConfig, config } = this.state
+
+    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
+      notification.warning({
+        top: 92,
+        message: '閰嶇疆淇℃伅鏈繚瀛橈紒',
+        duration: 5
+      })
+      return
+    }
+
+    // Api.getSystemConfig({
+    //   func: 'sPC_MainMenu_Del',
+    //   MenuID: '1614740497468ku800sbg853vupf65v4'
+    // })
+
+    sessionStorage.removeItem('sysRoles')
+    sessionStorage.removeItem('permFuncField')
+    sessionStorage.removeItem('app_videos')
+    sessionStorage.removeItem('app_pictures')
+    
+    window.location.reload()
+  }
+
+  setHomeView = () => {
+    const { oriConfig, config } = this.state
+
+    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
+      notification.warning({
+        top: 92,
+        message: '閰嶇疆淇℃伅鏈繚瀛橈紒',
+        duration: 5
+      })
+      return
+    }
+
+    let param = {
+      func: 's_kei_link_keyids_addupt',
+      BID: sessionStorage.getItem('appId'),
+      exec_type: 'y',
+      LText: ''
+    }
+
+    let appViewList = sessionStorage.getItem('appViewList')
+    appViewList = appViewList ? JSON.parse(appViewList) : []
+    appViewList = appViewList.filter(item => item.keys_type !== 'index')
+
+    appViewList.unshift({
+      appkey: window.GLOB.appkey || '',
+      bid: sessionStorage.getItem('appId') || '',
+      kei_no: sessionStorage.getItem('kei_no') || '',
+      keys_id: config.MenuID,
+      keys_type: 'index',
+      remark: config.MenuName
+    })
+
+    param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
+    param.LText = param.LText.join(' union all ')
+    param.LText = Utils.formatOptions(param.LText)
+
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    param.secretkey = Utils.encrypt('', param.timestamp)
+
+    confirm({
+      title: '纭畾璁剧疆鏈〉闈负棣栭〉鍚楋紵',
+      content: '',
+      onOk() {
+        Api.getSystemConfig(param).then(result => {
+          if (!result.status) {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          } else {
+            sessionStorage.setItem('appHomeId', config.MenuID)
+            sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
+          }
         })
       },
       onCancel() {}
     })
   }
 
-  editCard = (element) => {
-    this.setState({
-      editElem: element
-    })
-  }
-
-  updateStyle = (proper) => {
-    const { config } = this.state
-
-    config.components = config.components.map(component => {
-      if (component.uuid === proper.componentId) {
-        Object.keys(component).forEach(key => {
-          let _uuid = component[key].uuid
-          if (_uuid && (_uuid === proper.uuid || _uuid === proper.classId)) {
-            if (component[key].substyle) {
-
-            } else {
-              component[key].style = {...component[key].style, ...proper.style}
-              // eslint-disable-next-line
-              for (let index in component[key].style) {
-                if (component[key].style[index] === '') {
-                  delete component[key].style[index]
-                }
-              }
-            }
-          }
-        })
-      }
-      return component
-    })
-    this.setState({config})
-  }
-
-  updateConfig = (config) => {
-    this.setState({
-      config: config
-    })
-  }
-
   render () {
-    const { appType, config, editElem } = this.state
+    const { localedict, loading, activeKey, dict, MenuId, config, menuloading, customComponents } = this.state
 
     return (
-      <div className="mobile-view">
-        <Header />
-        <DndProvider backend={HTML5Backend}>
-          <div className="mob-body">
-            <div className="mob-tool">
-              <div className="mob-tool-content">
-                <div className="plus-content">
-                  <Icon type="plus-circle" />娣� 鍔� 缁� 浠�
-                </div>
-                <div className="useable-component">
-                  <SourceWrap appType={appType} />
-                </div>
+      <ConfigProvider locale={localedict}>
+        <div className="mk-mob-view" id="mk-mob-design-view">
+          <Header />
+          {loading ? <Spin className="view-spin" size="large" /> : null}
+          <DndProvider backend={HTML5Backend}>
+            <div className="menu-setting">
+              <div className="pc-setting-tools">
+                <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
+                  {/* 鍩烘湰淇℃伅 */}
+                  <Panel header={dict['mob.basemsg']} key="basedata">
+                    {/* 鑿滃崟淇℃伅 */}
+                    {config ? <MenuForm
+                      dict={dict}
+                      config={config}
+                      MenuId={MenuId}
+                      updateConfig={this.updateConfig}
+                    /> : null}
+                    {config ? <UrlFieldComponent config={config} updateConfig={this.updateConfig}/> : null}
+                    {/* 琛ㄥ悕娣诲姞 */}
+                    {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
+                  </Panel>
+                  {/* 缁勪欢娣诲姞 */}
+                  <Panel header={dict['mob.component']} key="component">
+                    <SourceWrap />
+                  </Panel>
+                  {customComponents && customComponents.length ? <Panel header="鑷畾涔夌粍浠�" key="cuscomponent">
+                    <SourceWrap components={customComponents} />
+                  </Panel> : null}
+                  <Panel header={'椤甸潰鏍峰紡'} key="background">
+                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
+                  </Panel>
+                </Collapse>
               </div>
-              <div className="mob-tool-other"></div>
             </div>
-            {appType === 'mob' && config ?
+            <div className="menu-control">
+              <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button>
+              <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config && config.enabled} onChange={this.onEnabledChange} />
+              <PasteController type="menu" Tab={null} insert={this.insert} />
+              <StyleCombControlButton menu={config} />
+              <SysInterface config={config} updateConfig={this.updateConfig}/>
+              <PictureController/>
+              <Quotecomponent config={config} updateConfig={this.updateConfig}/>
+              <Button className="mk-border-green" icon="home" onClick={this.setHomeView}>璁句负棣栭〉</Button>
+              <Button className="mk-border-danger" icon="redo" onClick={this.refreshView}>寮哄埗鍒锋柊</Button>
+              <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>
+            </div>
+            <div className={'menu-body' + (menuloading ? 'saving' : '')}>
               <div className="mob-shell">
-                <MobShell
-                  config={config}
-                  deleteCard={this.deleteCard}
-                  editCard={this.editCard}
-                  editId={editElem ? editElem.uuid : ''}
-                  handleList={this.updateConfig}
-                />
-              </div> : null
-            }
-            <div className="mob-setting">
-              {config ? <Tabs defaultActiveKey="1" animated={false} size="small">
-                <TabPane tab="閰嶇疆" key="1">
-                  <Controller editElem={editElem} updateStyle={this.updateStyle} />
-                </TabPane>
-                <TabPane tab="鏁版嵁婧�" key="2">
-                  <DataSource config={config} updateConfig={this.updateConfig} />
-                </TabPane>
-              </Tabs> : null}
+                {config ? <MobShell menu={config} handleList={this.updateConfig} /> : null}
+              </div>
             </div>
-          </div>
-        </DndProvider>
-      </div>
+          </DndProvider>
+          <StyleController />
+          <StyleCombController />
+          <ModalController />
+        </div>
+      </ConfigProvider>
     )
   }
 }
 
-const mapStateToProps = () => {
-  return {}
+const mapStateToProps = (state) => {
+  return {
+    memberLevel: state.memberLevel
+  }
 }
 
-const mapDispatchToProps = () => {
-  return {}
+const mapDispatchToProps = (dispatch) => {
+  return {
+    modifyCustomMenu: (customMenu) => dispatch(modifyCustomMenu(customMenu))
+  }
 }
 
-export default connect(mapStateToProps, mapDispatchToProps)(Mobile)
\ No newline at end of file
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MobDesign))
\ No newline at end of file
diff --git a/src/views/mobdesign/index.scss b/src/views/mobdesign/index.scss
index 7251e22..7699f0b 100644
--- a/src/views/mobdesign/index.scss
+++ b/src/views/mobdesign/index.scss
@@ -1,78 +1,77 @@
-.mobile-view {
-  background: #000;
+.mk-mob-view {
   min-height: 100vh;
-  .mob-body {
-    width: 100vw;
-    height: 100vh;
-    overflow-x: hidden;
-    position: relative;
-    background: #262626;
-    padding: 50px 300px 0px 40px;
 
-    .mob-tool {
-      position: fixed;
-      left: 0;
-      top: 48px;
-      height: 100%;
-      width: 40px;
-      background: #262626;
-      box-shadow: 2px 0px 2px #000;
-      .mob-tool-content {
-        width: 100%;
-        .plus-content {
-          position: relative;
+  >.view-spin {
+    position: absolute;
+    z-index: 3;
+    left: calc(50% - 16px);
+    top: calc(50vh - 70px);
+  }
+  .modal-form-board {
+    padding-top: 0;
+  }
+  .menu-setting {
+    position: fixed;
+    left: 0;
+    top: 48px;
+    z-index: 10;
+    transition: left 0.3s;
+
+    .pc-setting-tools {
+      height: calc(100vh - 48px);
+      width: 300px;
+      background: #ffffff;
+      overflow-y: auto;
+      overflow-x: hidden;
+
+      > .ant-collapse {
+        background-color: #ffffff;
+        .ant-collapse-item.ant-collapse-item-active {
+          border-bottom: 1px solid #d9d9d9;
+        }
+        .ant-collapse-header {
+          padding: 11px 16px 10px 40px;
+          border-bottom: 1px solid #d9d9d9;
+          background: #1890ff;
           color: #ffffff;
-          width: 100%;
-          display: flex;
-          align-items: center;
-          writing-mode: tb-rl;
-          padding: 16px 0;
-          border-bottom: 1px solid #000;
-          cursor: pointer;
-          z-index: 10;
-          background: #202735;
-          i {
-            margin-bottom: 5px;
-            margin-left: 2px;
+        }
+        .ant-collapse-content-box {
+          .ant-form-item {
+            margin-bottom: 10px;
+          }
+          .model-table-tablemanage-view {
+            >.ant-list {
+              margin-top: 20px;
+              .ant-list-item {
+                display: -webkit-box;
+                padding-right: 20px;
+                position: relative;
+                padding-left: 5px;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                -webkit-line-clamp: 2;
+                -webkit-box-orient: vertical;
+                min-height: 55px;
+                width: 100%;
+                .anticon {
+                  position: absolute;
+                  top: 0px;
+                  right: 0px;
+                  padding: 3px 3px 10px 10px;
+                  cursor: pointer;
+                }
+              }
+            }
+            >.tables {
+              width: 66.66666667%!important;
+            }
+            >.ant-form-item-label {
+              width: 33.33333333%;
+            }
           }
         }
-
-        .useable-component {
-          position: absolute;
-          width: 305px;
-          top: 0;
-          bottom: 0;
-          left: -340px;
-          background: #fff;
-          opacity: 0;
-          transition: left 0.3s linear 0.1s, opacity 0.3s linear 0.1s;
-          overflow-y: auto;
-        }
       }
-      .mob-tool-content:hover {
-        .useable-component {
-          opacity: 1;
-          left: 40px;
-        }
-      }
-      .mob-tool-other {
-        position: relative;
-        z-index: 10;
-        height: 1000px;
-        background: #202735;
-      }
-    }
-
-    .mob-setting {
-      position: fixed;
-      right: 0;
-      top: 0;
-      z-index: 10;
-      height: 100%;
-      width: 300px;
-      background: #202735;
-      box-shadow: 0px 2px 2px #000;
-
+  
       >.ant-tabs {
         >.ant-tabs-bar {
           border-bottom: 1px solid #181F29;
@@ -88,62 +87,113 @@
         }
       }
     }
+    .pc-setting-tools::-webkit-scrollbar {
+      width: 4px;
+    }
+    .pc-setting-tools::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+      background: rgba(0, 0, 0, 0.08);
+    }
+    .pc-setting-tools::-webkit-scrollbar-track {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+      border-radius: 3px;
+      border: 1px solid rgba(0, 0, 0, 0.07);
+      background: rgba(0, 0, 0, 0);
+    }
+  }
+  .mob-shell {
+    width: 375px;
+    height: 680px;
+    margin: 0 auto;
+    background: #000000;
+    background-size: 100% 100%;
+    padding: 25px 13px 40px;
+    border-radius: 30px;
 
-    .mob-shell {
-      width: 375px;
-      height: 680px;
-      margin: 0 auto;
+    .mob-shell-inner {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+      overflow-x: hidden;
       background: #ffffff;
-      background-size: 100% 100%;
-      padding: 25px 13px 40px;
-      border-radius: 30px;
+      box-shadow: 0px 0px 2px #000000;
+    }
+    .mob-shell-inner::-webkit-scrollbar {
+      width: 2px;
+    }
+    .mob-shell-inner::-webkit-scrollbar-thumb {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+      background: rgba(0, 0, 0, 0.23);
+      border-radius: 5px;
+    }
+    .mob-shell-inner::-webkit-scrollbar-track {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+      border: 1px solid rgba(0, 0, 0, 0.07);
+      background: rgba(0, 0, 0, 0);
+      border-radius: 3px;
+    }
+  }
+  .menu-control {
+    position: fixed;
+    right: 0;
+    top: 48px;
+    height: 100vh;
+    padding: 20px 10px;
+    background: #ffffff;
+    z-index: 10;
+    transition: right 0.3s;
 
-      .mob-shell-inner {
-        width: 100%;
-        height: 100%;
-        overflow-y: auto;
-        overflow-x: hidden;
-        box-shadow: 0px 0px 2px #000000;
+    div:not(.draw), button:not(.ant-switch) {
+      display: block!important;
+      margin-bottom: 15px;
+      width: 100%;
+    }
+    .ant-switch.big {
+      min-width: 60px;
+      height: 24px;
+      line-height: 24px;
+      margin-bottom: 15px;
+      .ant-switch-inner {
+        font-size: 14px;
       }
-      .mob-shell-inner::-webkit-scrollbar {
-        width: 2px;
-      }
-      .mob-shell-inner::-webkit-scrollbar-thumb {
-        box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-        background: rgba(0, 0, 0, 0.23);
-        border-radius: 5px;
-      }
-      .mob-shell-inner::-webkit-scrollbar-track {
-        box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
-        border: 1px solid rgba(0, 0, 0, 0.07);
-        background: rgba(0, 0, 0, 0);
-        border-radius: 3px;
-      }
+    }
+    .ant-switch.big:after {
+      width: 22px;
+      height: 22px;
     }
   }
 
-  .flex-container {
-    margin: 0 15px;
+  .menu-body {
+    width: 100vw;
+    height: 100vh;
+    overflow-x: hidden;
+    position: relative;
+    background: #959595;
+    padding: 50px 0px 0px;
+    overflow-y: auto;
+    .menu-shell-inner {
+      min-height: 100vh;
+      margin: 0 auto;
+    }
   }
-  .flex-container .inline {
-    width: 80px!important;
-    margin: 9px 9px 9px 0;
+  .menu-body.saving {
+    .anticon-tool {
+      display: none;
+    }
   }
-  .flex-container .small {
-    height: 20px!important;
-    line-height: 20px!important;
+  .menu-body::-webkit-scrollbar {
+    width: 7px;
   }
-  .sub-title {
-    color: #888;
-    font-size: 14px;
-    padding: 30px 0 18px 0;
+  .menu-body::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+    background: rgba(0, 0, 0, 0.08);
   }
-  .placeholder {
-    background-color: #ebebef;
-    color: #bbb;
-    text-align: center;
-    height: 30px;
-    line-height: 30px;
-    width: 100%;
+  .menu-body::-webkit-scrollbar-track {
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+    border-radius: 3px;
+    border: 1px solid rgba(0, 0, 0, 0.07);
+    background: rgba(0, 0, 0, 0);
   }
-}
+}
\ No newline at end of file
diff --git a/src/views/mobdesign/menuform/index.jsx b/src/views/mobdesign/menuform/index.jsx
new file mode 100644
index 0000000..2335bcf
--- /dev/null
+++ b/src/views/mobdesign/menuform/index.jsx
@@ -0,0 +1,138 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Icon, Tooltip, InputNumber } from 'antd'
+
+import './index.scss'
+
+class CustomMenuForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object, // 瀛楀吀椤�
+    config: PropTypes.object,
+    MenuId: PropTypes.string,
+    updateConfig: PropTypes.func
+  }
+
+  state = {}
+
+  // 涓�浜岀骇鑿滃崟鍒囨崲
+  selectChange = (key, value) => {
+    const { config } = this.props
+
+    if (key === 'cacheUseful') {
+      this.props.updateConfig({...config, cacheUseful: value})
+    } else if (key === 'timeUnit') {
+      this.props.updateConfig({...config, timeUnit: value})
+    }
+  }
+
+  // 鑿滃崟鍚嶇О
+  changeName = (e) => {
+    this.props.updateConfig({...this.props.config, MenuName: e.target.value})
+  }
+
+  // 鑿滃崟鍙傛暟
+  changeNo = (e) => {
+    this.props.updateConfig({...this.props.config, MenuNo: e.target.value})
+  }
+
+  changeCacheDay = (val) => {
+    if (typeof(val) !== 'number') {
+      val = ''
+    }
+    this.props.updateConfig({...this.props.config, cacheTime: val})
+  }
+
+  render() {
+    const { dict, config } = this.props
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="custom-menu-form">
+        <Row>
+          <Col span={24}>
+            <Form.Item label={dict['mob.menu'] + dict['mob.name']}>
+              {getFieldDecorator('MenuName', {
+                initialValue: config.MenuName,
+                rules: [
+                  {
+                    required: true,
+                    message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.name'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeName}/>)}
+            </Form.Item>
+          </Col>
+          <Col span={24}>
+            <Form.Item label={dict['mob.menu'] + dict['mob.param']}>
+              {getFieldDecorator('MenuNo', {
+                initialValue: config.MenuNo,
+                rules: [
+                  {
+                    required: true,
+                    message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.param'] + '!'
+                  }
+                ]
+              })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeNo}/>)}
+            </Form.Item>
+          </Col>
+          <Col span={24}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="瀵逛簬涓嶇粡甯告�у彉鍔ㄧ殑淇℃伅锛岀紦瀛樻暟鎹湁鍔╀簬鎻愰珮鏌ヨ鏁堢巼銆�">
+                <Icon type="question-circle" />
+                缂撳瓨鏁版嵁
+              </Tooltip>
+            }>
+              {getFieldDecorator('cacheUseful', {
+                initialValue: config.cacheUseful || 'false'
+              })(
+                <Radio.Group onChange={(e) => {this.selectChange('cacheUseful', e.target.value)}}>
+                  <Radio value="true">浣跨敤</Radio>
+                  <Radio value="false">涓嶄娇鐢�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {config.cacheUseful === 'true' ? <Col span={24}>
+            <Form.Item label="鍗曚綅">
+              {getFieldDecorator('timeUnit', {
+                initialValue: config.timeUnit || 'day'
+              })(
+                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
+                  <Radio value="day">澶�</Radio>
+                  <Radio value="hour">灏忔椂</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {config.cacheUseful === 'true' ? <Col span={24}>
+            <Form.Item label="鏃堕暱">
+              {getFieldDecorator('cacheTime', {
+                initialValue: config.cacheTime,
+                rules: [
+                  {
+                    required: true,
+                    message: dict['mob.required.input'] + '鏃堕暱!'
+                  }
+                ]
+              })(
+                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
+              )}
+            </Form.Item>
+          </Col> : null}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(CustomMenuForm)
\ No newline at end of file
diff --git a/src/views/mobdesign/menuform/index.scss b/src/views/mobdesign/menuform/index.scss
new file mode 100644
index 0000000..71a1a33
--- /dev/null
+++ b/src/views/mobdesign/menuform/index.scss
@@ -0,0 +1,10 @@
+.custom-menu-form {
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/views/pcdesign/index.jsx b/src/views/pcdesign/index.jsx
index a6c55e8..c814a3f 100644
--- a/src/views/pcdesign/index.jsx
+++ b/src/views/pcdesign/index.jsx
@@ -31,6 +31,7 @@
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
+const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
 const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
 const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller'))
 const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller'))
@@ -43,6 +44,7 @@
 document.body.className = ''
 window.GLOB.UserComponentMap = new Map() // 缂撳瓨鐢ㄦ埛鑷畾涔夌粍浠�
 window.GLOB.CacheIndependent = new Map()
+window.GLOB.urlFields = []               // url鍙橀噺
 
 class MenuDesign extends Component {
   state = {
@@ -446,6 +448,7 @@
         config.uuid = MenuId
         config.MenuID = MenuId
         config.open_edition = result.open_edition || ''
+        window.GLOB.urlFields = config.urlFields || []
 
         if (urlParam.fixed) {
           config.fixed = true
@@ -1424,6 +1427,7 @@
                       MenuId={MenuId}
                       updateConfig={this.updateConfig}
                     /> : null}
+                    {config ? <UrlFieldComponent config={config} updateConfig={this.updateConfig}/> : null}
                     {/* 琛ㄥ悕娣诲姞 */}
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                   </Panel>

--
Gitblit v1.8.0