king
2020-06-19 cd42d41344f0f780e0c0ac0a3625aeb78160f9dd
2020-06-19
17个文件已修改
3个文件已添加
2个文件已删除
1090 ■■■■ 已修改文件
package-lock.json 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/customscript/index.jsx 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/customscript/index.scss 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/index.jsx 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/settingform/index.jsx 376 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/settingform/index.scss 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/settingform/utils.jsx 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/dragsource/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/dragsource/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/login/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobcard/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobcard/mutilform/index.jsx 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/card.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/index.jsx 97 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/dragsource/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/option.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -1269,6 +1269,11 @@
        "@hapi/hoek": "8.2.2"
      }
    },
    "@icons/material": {
      "version": "0.2.4",
      "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
      "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
    },
    "@jest/console": {
      "version": "24.9.0",
      "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
@@ -10771,6 +10776,11 @@
        "object-visit": "1.0.1"
      }
    },
    "material-colors": {
      "version": "1.2.6",
      "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
      "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
    },
    "math-random": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
@@ -13949,6 +13959,19 @@
      "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.1.0.tgz",
      "integrity": "sha512-Rel0QbPnCTjHxgZYt6TkGw4icSZXNyONHb72a+1wWA+PlYJIvzFAv4pZlDPG0rpKpKmy4kSUlkoWgneH7w3A0g=="
    },
    "react-color": {
      "version": "2.18.1",
      "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.1.tgz",
      "integrity": "sha512-X5XpyJS6ncplZs74ak0JJoqPi+33Nzpv5RYWWxn17bslih+X7OlgmfpmGC1fNvdkK7/SGWYf1JJdn7D2n5gSuQ==",
      "requires": {
        "@icons/material": "0.2.4",
        "lodash": "4.17.15",
        "material-colors": "1.2.6",
        "prop-types": "15.7.2",
        "reactcss": "1.2.3",
        "tinycolor2": "1.4.1"
      }
    },
    "react-dev-utils": {
      "version": "9.0.3",
      "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.3.tgz",
@@ -14234,6 +14257,14 @@
        "tween-functions": "1.2.0"
      }
    },
    "reactcss": {
      "version": "1.2.3",
      "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
      "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
      "requires": {
        "lodash": "4.17.15"
      }
    },
    "read-pkg": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
package.json
@@ -64,6 +64,7 @@
    "react": "^16.9.0",
    "react-app-polyfill": "^1.0.2",
    "react-codemirror2": "^7.1.0",
    "react-color": "^2.18.1",
    "react-dev-utils": "^9.0.3",
    "react-dnd": "^9.4.0",
    "react-dnd-html5-backend": "^9.4.0",
src/components/header/index.jsx
@@ -678,9 +678,9 @@
        {this.props.editLevel === 'HS' ? <Button className="level4-close" type="primary" onClick={this.exitManage}>退出</Button> : null}
        {/* 进入编辑按钮 */}
        {this.props.editState && !this.props.editLevel ? <Icon onClick={this.enterEdit} className="edit-check" type="edit" /> : null}
        {this.props.editState && !this.props.editLevel && options.systemType === 'local' && window.GLOB.systemType !== 'official' ?
        {/* {this.props.editState && !this.props.editLevel && options.systemType === 'local' && window.GLOB.systemType !== 'official' ?
          <a href="#/mobmanage" target="_blank" className="mobile" type="edit"> 应用管理 <Icon type="arrow-right" /></a> : null
        }
        } */}
        {/* 编辑菜单 */}
        {this.props.editLevel === 'level1' ? <EditMenu menulist={this.state.menulist} reload={this.reload} exitEdit={this.exitEdit}/> : null}
        {/* 头像、用户名 */}
src/mob/datasource/verifycard/customscript/index.jsx
@@ -1,9 +1,10 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Button, notification, Modal, Tooltip, Icon, Radio, Select } from 'antd'
import { Form, Row, Col, Input, Button, notification, Modal, Select } from 'antd'
import moment from 'moment'
import Utils from '@/utils/utils.js'
import SettingUtils from '../utils.jsx'
import Api from '@/api'
import './index.scss'
@@ -11,18 +12,47 @@
class CustomForm extends Component {
  static propTpyes = {
    type: PropTypes.string,         // 菜单类型
    dict: PropTypes.object,         // 字典项
    btn: PropTypes.object,          // 按钮信息
    usefulfields: PropTypes.string, // 可用字段
    initsql: PropTypes.string,      // sql前缀
    setting: PropTypes.object,      // 设置
    searches: PropTypes.array,      // 搜索条件
    swhere: PropTypes.string,       // where条件
    arr_field: PropTypes.string,    // 列字段
    regoptions: PropTypes.array,    // 正则替换
    systemScripts: PropTypes.array, // 系统脚本
    customScripts: PropTypes.array, // 自定义脚本
    scriptsChange: PropTypes.func   // 表单
  }
  state = {
    editItem: null,
    loading: false
    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) => {
@@ -31,12 +61,22 @@
    })
    this.props.form.setFieldsValue({
      sql: record.sql,
      position: record.position || 'back'
      sql: record.sql
    })
  }
  handleCancel = () => {
    this.setState({
      editItem: null
    })
    this.props.form.setFieldsValue({
      sql: ''
    })
  }
  handleConfirm = () => {
    const { setting, arr_field, regoptions, swhere } = this.props
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
@@ -84,27 +124,37 @@
          return
        }
        let tail = `
          aaa:
        `
        let _initsql = ''
        this.props.customScripts.forEach(script => {
          if (this.state.editItem && this.state.editItem.uuid === script.uuid) return
          if (script.status === 'false' || script.position !== 'init') return
          _initsql += `
        let _customScript = ''
        setting.scripts && setting.scripts.forEach(script => {
          if (this.state.editItem && this.state.editItem.uuid === script.uuid) {
            _customScript += `
            ${values.sql}
            `
          } else if (script.status !== 'false') {
            _customScript += `
            ${script.sql}
            `
          }
        })
        if (!this.state.editItem) {
          _customScript += `
            ${values.sql}
            `
        }
        if (_customScript) {
          _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg =''
            ${_customScript}
          `
        }
        let _setting = {...setting, customScript: _customScript}
        let param = {
          func: 's_debug_sql',
          LText: this.props.initsql + _initsql + values.sql + tail
          LText: SettingUtils.getDebugSql(_setting, arr_field, regoptions, swhere)
        }
        // 数据权限
        param.LText = param.LText.replace(/@\$|\$@/ig, '')
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
@@ -134,16 +184,6 @@
    })
  }
  handleCancel = () => {
    this.setState({
      editItem: null
    })
    this.props.form.setFieldsValue({
      sql: ''
    })
  }
  selectScript = (value, option) => {
    let _sql = this.props.form.getFieldValue('sql')
    if (_sql) {
@@ -164,8 +204,9 @@
  }
  render() {
    const { usefulfields, systemScripts, btn } = this.props
    const { systemScripts, setting, type } = this.props
    const { getFieldDecorator } = this.props.form
    const { usefulFields } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -178,11 +219,11 @@
    }
    return (
      <Form {...formItemLayout} className="verify-form" id="verify-custom-scripts">
      <Form {...formItemLayout} className="modal-menu-setting-script">
        <Row gutter={24}>
          {btn.sql ? <Col span={8}>
          {setting.tableName ? <Col span={8}>
            <Form.Item label={'表名'} style={{whiteSpace: 'nowrap', margin: 0}}>
              {btn.sql}
              {setting.tableName}
            </Form.Item>
          </Col> : null}
          <Col span={16}>
@@ -190,27 +231,9 @@
              ErrorCode, retmsg
            </Form.Item>
          </Col>
          {usefulfields ? <Col span={24} className="sqlfield">
          <Col span={24} className="sqlfield">
            <Form.Item label={'可用字段'}>
              {usefulfields}
            </Form.Item>
          </Col> : null}
          <Col span={8} style={{whiteSpace: 'nowrap'}}>
            <Form.Item style={{marginBottom: 0}} label={
              <Tooltip placement="bottomLeft" title={'自定义脚本与默认sql位置关系。'}>
                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
                执行位置
              </Tooltip>
            }>
              {getFieldDecorator('position', {
                initialValue: 'front'
              })(
                <Radio.Group>
                  <Radio value="init">初始化</Radio>
                  <Radio value="front">sql前</Radio>
                  <Radio value="back">sql后</Radio>
                </Radio.Group>
              )}
              id, bid, loginuid, sessionuid, userid, appkey, {type === 'main' ? 'out_id, ' : '' }time_id, orderBy{setting.laypage !== 'false' ? ', pageSize, pageIndex': ''}{usefulFields ? ', ' + usefulFields : ''}
            </Form.Item>
          </Col>
          <Col span={10}>
@@ -219,19 +242,18 @@
                showSearch
                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                onChange={this.selectScript}
                getPopupContainer={() => document.getElementById('verify-custom-scripts')}
              >
                {systemScripts.map((option, i) =>
                  <Select.Option key={i} value={option.value}>{option.name}</Select.Option>
                  <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={{marginBottom: 15, marginLeft: 40}}>
            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginTop: 5, marginBottom: 15, marginLeft: 30}}>
              保存
            </Button>
            <Button onClick={this.handleCancel} style={{marginBottom: 15, marginLeft: 10}}>
            <Button onClick={this.handleCancel} style={{marginTop: 5, marginBottom: 15, marginLeft: 10}}>
              取消
            </Button>
          </Col>
src/mob/datasource/verifycard/customscript/index.scss
@@ -1,5 +1,31 @@
#verify-custom-scripts {
  .ant-select-dropdown-menu-item {
    white-space: normal;
.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;
    }
  }
}
src/mob/datasource/verifycard/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
// import { fromJS } from 'immutable'
import { Form, Tabs, Row, Col, Radio, Table, Popconfirm, Icon, notification, Modal, message, Tooltip, Typography } from 'antd'
import { Form, Tabs, Table, Popconfirm, Icon, notification, Modal, message, Typography } from 'antd'
import moment from 'moment'
import Api from '@/api'
@@ -10,7 +10,7 @@
import UniqueForm from './uniqueform'
import ContrastForm from './contrastform'
import CustomForm from './customform'
import CustomScript from './customscript'
import SettingForm from './settingform'
import BillcodeForm from './billcodeform'
import VoucherForm from './voucherform'
import './index.scss'
@@ -924,54 +924,12 @@
  render() {
    const { card } = this.props
    const { verify, fields, uniqueColumns, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <div id="verify-card-box-tab">
        <Tabs defaultActiveKey="1" className="verify-card-box">
          <TabPane tab="基础验证" key="1">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                {this.props.card.sqlType !== 'custom' ? <Col span={8}>
                  <Form.Item label={
                    <Tooltip placement="bottomLeft" title={'默认sql执行顺序为自定义脚本之前'}>
                      <Icon type="question-circle" style={{color: '#c49f47', marginRight: '5px'}} />
                      默认sql
                    </Tooltip>
                  }>
                    <Radio.Group value={verify.default} onChange={(e) => {this.onOptionChange(e, 'default')}}>
                      <Radio value="true">执行</Radio>
                      <Radio value="false">不执行</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col> : null}
                <Col span={8}>
                  <Form.Item label={'账期验证'}>
                    <Radio.Group value={verify.accountdate} onChange={(e) => {this.onOptionChange(e, 'accountdate')}}>
                      <Radio value="true">开启</Radio>
                      <Radio value="false">不开启</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col>
                <Col span={8}>
                  <Form.Item label={'失效验证'}>
                    <Radio.Group value={verify.invalid} onChange={(e) => {this.onOptionChange(e, 'invalid')}}>
                      <Radio value="true">开启</Radio>
                      <Radio value="false">不开启</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col>
              </Row>
            </Form>
          <TabPane tab="数据源" key="1">
            <SettingForm dict={this.props.dict} />
          </TabPane>
          <TabPane tab="比较验证" key="2x">
            <ContrastForm
@@ -1056,7 +1014,7 @@
            />
          </TabPane>
          <TabPane tab="自定义脚本" key="6">
            <CustomScript
            {/* <CustomScript
              usefulfields={this.state.usefulfields}
              initsql={this.state.initsql}
              dict={this.props.dict}
@@ -1065,7 +1023,7 @@
              systemScripts={this.state.systemScripts}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
            /> */}
            <Table
              bordered
              rowKey="uuid"
src/mob/datasource/verifycard/settingform/index.jsx
New file
@@ -0,0 +1,376 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon, notification, InputNumber } from 'antd'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
// import SettingUtils from './utils.jsx'
import './index.scss'
const { TextArea } = Input
class SettingForm extends Component {
  static propTpyes = {
    type: PropTypes.string,      // 菜单类型
    dict: PropTypes.object,      // 字典项
    menu: PropTypes.object,      // 菜单信息
    config: PropTypes.object,    // 页面配置信息
    formlist: PropTypes.array,   // 表单信息
  }
  state = {
  }
  handleConfirm = (otype) => {
    const { menu } = this.props
    const { setting } = this.state
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values = {...setting, ...values}
          // 数据源前端验证
          if (values.interType === 'inner' && !values.innerFunc && values.default !== 'false' && !values.dataresource) {
            notification.warning({
              top: 92,
              message: '请填写内部函数或数据源!',
              duration: 5
            })
            reject()
            return
          } else if (values.interType === 'inner' && !values.innerFunc && values.default !== '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
              })
              return
            } else if (_lparen !== _rparen) {
              notification.warning({
                top: 92,
                message: '数据源中()必须成对出现',
                duration: 5
              })
              return
            } else if (/--/ig.test(values.dataresource)) {
              notification.warning({
                top: 92,
                message: '数据源中,不可出现字符 -- ,注释请用 /*内容*/',
                duration: 5
              })
              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.default !== 'false' &&
            /[^\s]+\s+[^\s]+/ig.test(values.dataresource) &&
            this.props.config.setting.dataresource !== values.dataresource
          ) {
            let param = {
              func: 's_DataSrc_Save',
              LText: values.dataresource,
              MenuID: menu.MenuID
            }
            param.LText = Utils.formatOptions(param.LText)
            param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
            param.secretkey = Utils.encrypt(param.LText, param.timestamp)
            Api.getLocalConfig(param)
          }
          if (otype === 'change') {
            this.setState({
              setting: values,
            }, () => {
              resolve()
            })
          } else {
            values.customScript = this.getCustomScript(values)
            this.sqlverify(values, resolve, reject)
          }
        } else {
          reject(err)
        }
      })
    })
  }
  onRadioChange = (e, key) => {
    let value = e.target.value
    let _formlist = fromJS(this.state.formlist).toJS()
    if (key === 'interType') {
      this.setState({
        formlist: _formlist.map(item => {
          item.hidden = false
          if (value === 'inner' && ['sysInterface', 'interface', 'outerFunc'].includes(item.key)) {
            item.initVal = this.props.form.getFieldValue(item.key)
            item.hidden = true
          } else if (value === 'outer' && ['innerFunc', 'dataresource', 'queryType'].includes(item.key)) {
            item.initVal = this.props.form.getFieldValue(item.key)
            item.hidden = true
          }
          return item
        })
      })
    } else if (key === 'sysInterface') {
      if (value === 'true') {
        this.props.form.setFieldsValue({
          interface: window.GLOB.mainSystemApi || ''
        })
      }
      this.setState({
        formlist: _formlist.map(item => {
          if (item.key === 'interface') {
            item.readonly = value === 'true'
          }
          return item
        })
      })
    }
  }
  getFields(formlist) {
    const { getFieldDecorator } = this.props.form
    const fields = []
    formlist.forEach((item, index) => {
      if (item.hidden || item.forbid) return
      if (item.type === 'text') { // 文本搜索
        let rules = item.rules || []
        fields.push(
          <Col span={8} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  },
                  ...rules
                ]
              })(<Input placeholder={item.placeholder || ''} autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'number') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || 6,
                rules: [
                  {
                    required: item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<InputNumber min={item.min} max={item.max} precision={0} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => {
                    return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
                      option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                  }}
                  onChange={(value) => {this.selectChange(item.key, value)}}
                  getPopupContainer={() => document.getElementById('model-table-setting-form')}
                >
                  {item.options.map((option, i) =>
                    <Select.Option id={i} key={i} value={option.value}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'radio') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Radio.Group onChange={(e) => {this.onRadioChange(e, item.key)}}>
                  {
                    item.options.map((option, i) => {
                      return (
                        <Radio key={i} value={option.value}>{option.text}</Radio>
                      )
                    })
                  }
                </Radio.Group>,
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'datasource') {
        fields.push(
          <Col span={24} key={index} style={{paddingLeft: '7px'}}>
            <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } help={item.help} label={
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip>
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal
              })(<TextArea rows={4} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'textarea') {
        fields.push(
          <Col span={20} offset={4} key={index}>
            <Form.Item className="text-area">
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<TextArea rows={4} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'multiselect') { // 多选
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || []
              })(
                <Select
                  showSearch
                  mode="multiple"
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {item.options.map((option, i) =>
                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  render() {
    const { getFieldDecorator } = this.props.form
    // const { formlist } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <div className="model-table-setting-form-box">
        <Form {...formItemLayout} className="model-table-setting-form">
          <Row gutter={24}>
            <Col span={8}>
              <Form.Item label="名称">
                {getFieldDecorator('label', {
                  initialValue: '',
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '名称!'
                    },
                  ]
                })(<Input placeholder={''} autoComplete="off" />)}
              </Form.Item>
            </Col>
          </Row>
        </Form>
      </div>
    )
  }
}
export default Form.create()(SettingForm)
src/mob/datasource/verifycard/settingform/index.scss
New file
@@ -0,0 +1,45 @@
.model-table-setting-form-box {
  position: relative;
  .model-table-setting-form {
    .textarea {
      .ant-form-item-label {
        width: 16.3%;
      }
      .ant-form-item-control-wrapper {
        width: 83.33333333%;
      }
    }
    .anticon-question-circle {
      color: #c49f47;
      margin-right: 3px;
    }
  }
  .operation-btn {
    display: inline-block;
    font-size: 16px;
    padding: 0 5px;
    cursor: pointer;
  }
  td {
    word-break: break-all;
  }
  .setting-custom-back {
    position: absolute;
    top: -20px;
    left: -10px;
    font-size: 16px;
    z-index: 1;
    cursor: pointer;
    padding: 10px;
    color: rgb(24, 144, 255);
  }
  .to-custom-script {
    float: right;
    color: #1890ff;
    margin-right: 12px;
    margin-top: 15px;
    cursor: pointer;
    border: 0;
    box-shadow: unset;
  }
}
src/mob/datasource/verifycard/settingform/utils.jsx
New file
@@ -0,0 +1,84 @@
export default class SettingUtils {
  /**
   * @description 生成页面查询语句
   * @return {String}  arr_field     显示列字段
   * @return {String}  search        搜索条件
   * @return {Object}  setting       页面设置
   * @return {Array}   regoptions    搜索条件正则替换
   */
  static getDebugSql (setting, arr_field, regoptions, search) {
    let sql = ''
    let _dataresource = setting.dataresource
    let _customScript = setting.customScript
    if (setting.interType === 'inner' && !setting.innerFunc && setting.default === 'false') {
      _dataresource = ''
    }
    if (_dataresource) {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
    }
    if (_customScript) {
      _customScript = _customScript.replace(/@\$|\$@/ig, '')
    }
    // 正则替换
    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
  }
}
src/mob/dragsource/index.jsx
File was deleted
src/mob/dragsource/index.scss
File was deleted
src/mob/login/index.scss
@@ -3,7 +3,7 @@
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: linear-gradient(#378DBE, #46C29E, #48A9D6);
  background: linear-gradient(#378DBE, #46C29E, #48A9D6, yellow);
  .logo {
    max-width: 280px;
src/mob/mobcard/index.jsx
@@ -127,7 +127,7 @@
        ID: card ? card.uuid : Utils.getuuid(),
        TypeName: res.type,
        remark: res.name,
        kei_no: res.type
        kei_no: res.keiNo
      }
      Api.getCloudConfig(param).then(result => {
src/mob/mobcard/mutilform/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select } from 'antd'
import { Form, Row, Col, Input, Select, Radio } from 'antd'
import './index.scss'
class MainSearch extends Component {
@@ -81,6 +81,39 @@
              )}
            </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>
    )
src/mob/mobshell/card.jsx
@@ -10,16 +10,15 @@
const Login = asyncComponent(() => import('@/mob/login'))
const Card = ({ id, card, moveCard, findCard, editCard, delCard, hasDrop, doubleClickCard }) => {
  const originalIndex = null
  // const originalIndex = findCard(id).index
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'action', id, originalIndex },
    item: { type: 'mob', id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'action',
    accept: 'mob',
    canDrop: () => true,
    drop: (item) => {
      if (!item.hasOwnProperty('originalIndex')) {
@@ -34,10 +33,15 @@
      }
    },
  })
  const opacity = isDragging ? 0.3 : 1
  console.log(card)
  const style = isDragging ? { opacity: 0.3} : { opacity: 1}
  if (card.type === 'login') {
    style.height = '100%'
  }
  return (
    <div ref={node => drag(drop(node))} style={{ opacity: opacity, height: '100%'}}>
    <div ref={node => drag(drop(node))} style={style}>
      <Login />
      {/* <div className="page-card">
        <Button
src/mob/mobshell/index.jsx
@@ -1,33 +1,35 @@
import React from 'react'
// import React, { useState } from 'react'
import React, { useState } from 'react'
import { useDrop } from 'react-dnd'
// import { is, fromJS } from 'immutable'
// import update from 'immutability-helper'
// import Utils from '@/utils/utils.js'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { message } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
import './index.scss'
const Container = ({list, placeholder, handleList, handleMenu, deleteMenu, doubleClickCard }) => {
  // let target = null
const Container = ({config, handleList, handleMenu, deleteMenu, doubleClickCard }) => {
  let target = null
  // const [cards, setCards] = useState(list)
  // const moveCard = (id, atIndex) => {
  //   const { card, index } = findCard(id)
  //   const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
  //   handleList(_cards)
  // }
  const [cards, setCards] = useState(config.components)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    handleList({...config, components: _cards})
    console.log(_cards)
  }
  // if (!is(fromJS(cards), fromJS(list))) {
  //   setCards(list)
  // }
  if (!is(fromJS(cards), fromJS(config.components))) {
    setCards(config.components)
  }
  
  // const findCard = id => {
  //   const card = cards.filter(c => `${c.uuid}` === id)[0]
  //   return {
  //     card,
  //     index: cards.indexOf(card),
  //   }
  // }
  const findCard = id => {
    const card = cards.filter(c => `${c.uuid}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
  // const doubleClickBtn = id => {
  //   const { card } = findCard(id)
@@ -44,54 +46,57 @@
  //   deleteMenu(card)
  // }
  // const hasDrop = (item) => {
  //   target = item
  // }
  const hasDrop = (item) => {
    target = item
  }
  const [, drop] = useDrop({
    accept: 'action',
    accept: 'mob',
    drop(item) {
      if (item.hasOwnProperty('originalIndex')) {
        return
      }
      // let newcard = {}
      // newcard.uuid = Utils.getuuid()
      if (cards.length > 0 && cards[0].type === 'login') {
        message.warning('登录页不可添加其他元素!')
        return
      }
      let newcard = fromJS(item.param).toJS()
      newcard.uuid = Utils.getuuid()
      
      // let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
      // if (target) {
      //   targetId = target.uuid
      // }
      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
      if (target) {
        targetId = target.uuid
      }
      // const { index: overIndex } = findCard(`${targetId}`)
      // let targetIndex = overIndex
      const { index: overIndex } = findCard(`${targetId}`)
      let targetIndex = overIndex
      // targetIndex++
      targetIndex++
      // const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
      const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
      // handleList(_cards, newcard)
      // target = null
      handleList({...config, components: _cards})
      target = null
    }
  })
  return (
    <div ref={drop} className="mob-shell-inner">
      {/* {cards.map(card => (
      {cards.map(card => (
        <Card
          id={card.uuid}
          key={card.uuid}
          card={card}
          moveCard={moveCard}
          editCard={editCard}
          delCard={delCard}
          // editCard={editCard}
          // delCard={delCard}
          findCard={findCard}
          hasDrop={hasDrop}
          doubleClickCard={doubleClickBtn}
          // doubleClickCard={doubleClickBtn}
        />
      ))} */}
      <Card />
      ))}
      {/* {cards.length === 0 ?
        <div className="common-drawarea-placeholder">
          {placeholder}
src/mob/modelsource/dragsource/index.jsx
@@ -3,7 +3,7 @@
import { Tooltip } from 'antd'
import './index.scss'
const SourceElement = ({content}) => {
const MobSourceElement = ({content}) => {
  const [, drag] = useDrag({ item: content })
  return (
    <div ref={drag} className="mob-source-item" style={{backgroundImage: 'url(' + content.url + ')', ...content.style}}>
@@ -15,4 +15,4 @@
    </div>
  )
}
export default SourceElement
export default MobSourceElement
src/mob/modelsource/option.jsx
@@ -4,11 +4,15 @@
const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
// 表单校验规则
// 组件配置信息
export const mobOptions = [{
  title: _dict['mob.login'],
  type: 'login',
  sourceType: 'login',
  options: [
    {type: 'mob-login-1', sourceType: 'mob', url: mobLogin1,  style: {}},
    {sourceType: 'mob-login-1', type: 'mob', url: mobLogin1,  style: {}, param: {
      type: 'login', subtype: 'mob-login-1', components: [
        {}
      ]
    }},
  ]
}]
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -279,7 +279,11 @@
          }
        }
        if (this.props.menuType === 'HS' && param.timestamp) { // 云端验证
        if (this.props.menuType === 'HS' && param.timestamp) { // 函数 sPC_TableData_InUpDe 云端验证
          param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
        } else if (this.props.menuType === 'HS' && param.func === 's_sDataDictb_TBBack' && param.LTextOut) { // 函数 s_sDataDictb_TBBack 云端验证
          param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
          param.secretkey = Utils.encrypt(param.LTextOut, param.timestamp)
          param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
        }
@@ -387,7 +391,11 @@
            }
          }
          if (this.props.menuType === 'HS' && param.timestamp) { // 云端验证
          if (this.props.menuType === 'HS' && param.timestamp) { // 函数 sPC_TableData_InUpDe 云端验证
            param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
          } else if (this.props.menuType === 'HS' && param.func === 's_sDataDictb_TBBack' && param.LTextOut) { // 函数 s_sDataDictb_TBBack 云端验证
            param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
            param.secretkey = Utils.encrypt(param.LTextOut, param.timestamp)
            param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
          }
@@ -539,6 +547,14 @@
      // 内部请求
      if (btn.innerFunc) {
        param.func = btn.innerFunc
        // 函数 s_sDataDictb_TBBack 云端验证
        if (this.props.menuType === 'HS' && param.func === 's_sDataDictb_TBBack' && param.LTextOut) {
          param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
          param.secretkey = Utils.encrypt(param.LTextOut, param.timestamp)
          param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true)
        }
        // 存在内部函数时,数据预处理
        Api.genericInterface(param).then(res => {
          if (res.status) {
@@ -571,11 +587,21 @@
      // 外部请求
      _outParam = JSON.parse(JSON.stringify(res))
      if (btn.outerFunc) {
        res.func = btn.outerFunc
      }
      if (this.props.menuType === 'HS') {
        if (btn.sysInterface === 'true' && options.cloudServiceApi) {
          res.rduri = options.cloudServiceApi
        } else if (btn.sysInterface !== 'true') {
          res.rduri = btn.interface
        }
        // 函数 s_sDataDictb_TBBack 云端验证
        if (res.func === 's_sDataDictb_TBBack' && res.LTextOut) {
          res.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
          res.secretkey = Utils.encrypt(res.LTextOut, res.timestamp)
          res.open_key = Utils.encrypt(res.secretkey, res.timestamp, true)
        }
      } else {
        if (btn.sysInterface === 'true' && window.GLOB.mainSystemApi) {
@@ -583,10 +609,6 @@
        } else if (btn.sysInterface !== 'true') {
          res.rduri = btn.interface
        }
      }
      if (btn.outerFunc) {
        res.func = btn.outerFunc
      }
      return Api.genericInterface(res)
@@ -601,6 +623,14 @@
        response.func = btn.callbackFunc
        let _callbackparam = {..._outParam, ...response}
        // 函数 s_sDataDictb_TBBack 云端验证
        if (this.props.menuType === 'HS' && _callbackparam.func === 's_sDataDictb_TBBack' && _callbackparam.LTextOut) {
          _callbackparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
          _callbackparam.secretkey = Utils.encrypt(_callbackparam.LTextOut, _callbackparam.timestamp)
          _callbackparam.open_key = Utils.encrypt(_callbackparam.secretkey, _callbackparam.timestamp, true)
        }
        return Api.genericInterface(_callbackparam)
      } else {
        if (response.status) {
src/utils/utils.js
@@ -1066,21 +1066,31 @@
        datasource = '(' + datasource + ') tb'
      }
      let _ID = '=@ID@'
      if (btn.Ot === 'requiredOnce') {
        _ID = ' in (select ID from  dbo.SplitComma(@ID@))'
      }
      _sql += `
        _sql += `
        /* 失效验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select @tbid=${primaryKey} from ${datasource} where ${primaryKey} ${_ID}
        select @tbid='X' from ${datasource} right join (select ID from  dbo.SplitComma(@ID@)) sp
        on tb.id =sp.id where tb.id is null
        If @tbid!=''
        Begin
          select @ErrorCode='E',@retmsg='数据已失效'
          goto aaa
        end
        `
      } else {
        _sql += `
        /* 失效验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select @tbid=${primaryKey} from ${datasource} where ${primaryKey}=@ID@
        If @tbid=''
        Begin
          select @ErrorCode='E',@retmsg='数据已失效'
          goto aaa
        end
        `
      }
    }
    // 比较验证
src/views/mobdesign/index.jsx
@@ -1,8 +1,10 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { DndProvider } from 'react-dnd'
import { fromJS } from 'immutable'
import HTML5Backend from 'react-dnd-html5-backend'
import { Icon, Tabs } from 'antd'
import { SketchPicker } from 'react-color'
import { Icon, Tabs, notification } from 'antd'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/mob.js'
@@ -23,12 +25,14 @@
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    appId: this.props.match.params.appId,
    appType: this.props.match.params.appType,
    appConfig: null,
    saveIng: false,
    config: null
    config: null,
    pageIndex: 0
  }
  UNSAFE_componentWillMount() {
    this.getPageParam(this.props.match.params.appId)
    this.getAppParam(this.props.match.params.appId)
  }
  /**
@@ -51,17 +55,54 @@
    })
  }
  getPageParam = (id) => {
  getAppParam = (id) => {
    Api.getSystemConfig({
      func: 'sPC_Get_LongParam',
      MenuID: id
    }).then(result => {
      if (result.status) {
        let appConfig = null
        if (result.LongParam) {
          try {
            appConfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
          } catch (e) {
            console.warn('Parse Failure')
            appConfig = null
          }
        }
        if (!appConfig) {
          appConfig = {
            version: 1.0,
            label: '',
            uuid: this.props.match.params.appId,
            pageIndex: 0,
            sourcelist: [],
            components: []
          }
        }
        this.setState({
          appConfig: appConfig,
          config: fromJS(appConfig).toJS()
        })
      } else {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  updateConfig = () => {
  updateConfig = (config) => {
    this.setState({
      config: config
    })
  }
  render () {
@@ -83,18 +124,20 @@
              </div>
              <div className="mob-tool-other"></div>
            </div>
            <div className="mob-shell">
              <MobShell />
            </div>
            {appType === 'mob' && config ?
              <div className="mob-shell">
                <MobShell config={config} handleList={this.updateConfig} />
              </div> : null
            }
            <div className="mob-setting">
              <Tabs defaultActiveKey="2" animated={false} size="small">
              {config ? <Tabs defaultActiveKey="2" animated={false} size="small">
                <TabPane tab="配置" key="1">
                  Content of Tab Pane 1
                  <SketchPicker />
                </TabPane>
                <TabPane tab="数据源" key="2">
                  <DataSource config={config} updateConfig={this.updateConfig} />
                </TabPane>
              </Tabs>
              </Tabs> : null}
            </div>
          </div>
        </DndProvider>
src/views/mobdesign/index.scss
@@ -86,7 +86,7 @@
        height: 100%;
        overflow-y: auto;
        overflow-x: hidden;
        background-color: #f5f5f9;
        box-shadow: 0px 0px 3px #d1d1d5;
      }
      .mob-shell-inner::-webkit-scrollbar {
        width: 4px;