king
2021-07-05 41e2d4b6af42302bb37bb54394a489e017c0de4f
2021-07-05
11个文件已修改
6个文件已添加
1105 ■■■■■ 已修改文件
src/menu/components/form/normal-form/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/card.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/controller.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/index.jsx 458 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/index.scss 321 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/pastecomponent/index.jsx 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/pastecomponent/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/source.jsx 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/normal-form/index.jsx
@@ -483,7 +483,8 @@
      if (_form.uuid === item.uuid) {
        index = i
      }
      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
@@ -576,7 +577,7 @@
        return
      }
      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -264,7 +264,6 @@
      key: 'postfix',
      label: Formdict['header.form.postfix'],
      initVal: card.postfix || '',
      tooltipClass: 'middle',
      required: false,
      readonly: false
    },
src/menu/components/table/normal-table/columns/editColumn/index.jsx
@@ -168,7 +168,7 @@
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
@@ -190,7 +190,7 @@
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
@@ -241,7 +241,7 @@
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
              <Tooltip placement="topLeft" title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
src/menu/modalconfig/index.jsx
@@ -123,7 +123,7 @@
      if (card.uuid === item.uuid) {
        index = i
      }
      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
@@ -218,7 +218,7 @@
      _config.fields = _config.fields.filter(item => !item.origin)
      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
src/mob/components/formdragelement/card.jsx
@@ -166,9 +166,9 @@
  } else if (card.type === 'checkcard') {
    formItem = (<div className="am-list-item check-card">
      <div className="am-list-line">
        <div className="am-input-label">{card.label}</div>
        {card.hidelabel !== 'true' ? <div className="am-input-label">{card.label}</div> : null}
        <div className="am-input-control">
          <CheckCard config={card} />
          <CheckCard config={card} />
        </div>
      </div>
    </div>)
@@ -185,7 +185,7 @@
      <div className="page-card" style={{ opacity: opacity}}>
        <div ref={node => drag(drop(node))}>
          {card.type === 'split' ? formItem : <Form.Item
            className={'ant-form-item ' + (card.required === 'true' ? 'required' : '')}
            className={'ant-form-item' + (card.required === 'true' ? ' required' : '') + (card.splitline === 'false' ? ' no-boder' : '')}
          >
            {formItem}
            {showField ? <div className="field-name">{card.field}{card.hidden === 'true' ? '(隐藏)' : ''}</div> : ''}
src/mob/components/formdragelement/index.scss
@@ -195,6 +195,9 @@
    .field-name {
      margin-left: 10px;
    }
    .ant-form-item-children {
      vertical-align: top;
    }
  }
  .ant-form-item.required {
    .am-input-label::before {
@@ -207,6 +210,11 @@
      content: '*';
    }
  }
  .ant-form-item.no-boder {
    .am-list-line {
      border-bottom: none;
    }
  }
}
.mob-form.modal-fields-row {
  .page-card {
src/mob/modalconfig/index.jsx
@@ -123,7 +123,7 @@
      if (card.uuid === item.uuid) {
        index = i
      }
      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
@@ -218,7 +218,7 @@
      _config.fields = _config.fields.filter(item => !item.origin)
      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
src/mob/searchconfig/controller.jsx
New file
@@ -0,0 +1,64 @@
import React, {Component} from 'react'
import { is, fromJS } from 'immutable'
import MKEmitter from '@/utils/events.js'
import SearchConfig from '@/mob/searchconfig'
class SearchController extends Component {
  state = {
    btn: null,
    config: null,
    visible: false
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    MKEmitter.addListener('changeSearch', this.initConfig)
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('changeSearch', this.initConfig)
  }
  initConfig = (config, btn) => {
    this.setState({
      visible: true,
      config: fromJS(config).toJS(),
      btn: fromJS(btn).toJS()
    })
  }
  handleBack = () => {
    this.setState({
      visible: false,
      config: null,
      btn: null
    })
  }
  handleSave = (modal) => {
    const { config, btn } = this.state
    MKEmitter.emit('submitSearch', config, btn, modal)
  }
  render () {
    const { config, btn, visible } = this.state
    if (!visible) return null
    return (
      <SearchConfig btn={btn} componentConfig={config} handleBack={this.handleBack} handleSave={this.handleSave}/>
    )
  }
}
export default SearchController
src/mob/searchconfig/index.jsx
New file
@@ -0,0 +1,458 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import moment from 'moment'
import { Button, Modal, Collapse, notification, Switch, Icon } from 'antd'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getModalForm } from '@/templates/zshare/formconfig'
import ModalForm from '@/templates/zshare/modalform'
import SourceElement from '@/templates/modalconfig/dragelement/source'
import SettingForm from '@/templates/modalconfig/settingform'
import asyncComponent from '@/utils/asyncComponent'
import { SearchItems } from './source'
import './index.scss'
const { Panel } = Collapse
const { confirm } = Modal
const CommonDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const PasteComponent = asyncComponent(() => import('./pastecomponent'))
const DragElement = asyncComponent(() => import('@/mob/components/formdragelement'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
class ComModalConfig extends Component {
  static propTpyes = {
    btn: PropTypes.object,
    handleSave: PropTypes.func,
    handleBack: PropTypes.func
  }
  state = {
    dict: CommonDict,      // 字典
    config: null,          // 页面配置,包括模板类型、模态框设置、添加表名、表单列表
    visible: false,        // 表单编辑模态框,显示控制
    formlist: null,        // 表单编辑模态框,可编辑字段
    card: null,            // 编辑元素
    settingVisible: false, // 全局配置模态框
    originConfig: null,    // 原始菜单
    sqlVerifing: false,    // sql验证
    showField: false,      // 显示表单字段值
    standardform: null
  }
  /**
   * @description 数据预处理
   */
  UNSAFE_componentWillMount () {
    const { btn } = this.props
    let _config = btn.modal
    _config.version = '1.0'
    this.setState({
      config: _config,
      originConfig: fromJS(_config).toJS()
    })
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  /**
   * @description 表单变化
   * 1、表单拖拽添加时,检查是否存在示例表单,如存在则去除示例
   * 2、表单移动后,保存移动后的顺序
   * 3、新增表单时,直接打开编辑框
   */
  handleList = (list, newcard) => {
    let _config = fromJS(this.state.config).toJS()
    if (list.length > _config.fields.length) {
      _config.fields = list.filter(item => !item.origin)
      this.setState({
        config: _config
      }, () => {
        this.handleForm(newcard)
      })
    } else {
      _config.fields = list
      this.setState({config: _config})
    }
  }
  /**
   * @description 表单编辑
   * 1、显示编辑弹窗-visible
   * 2、保存编辑项-card
   * 3、设置编辑参数项-formlist
   */
  handleForm = (_card) => {
    const { componentConfig } = this.props
    const { config } = this.state
    let card = fromJS(_card).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = [{
      value: '',
      text: '空'
    }]
    let standardform = null
    _inputfields = config.fields.filter(item => item.type === 'text' || item.type === 'number' || item.type === 'textarea' || item.type === 'color')
    _tabfields = config.fields.filter(item => card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
    _tabfields.unshift({field: '', text: '原表单'})
    let uniq = new Map()
    uniq.set(card.field, true)
    let index = null
    config.fields.forEach((item, i) => {
      if (card.uuid === item.uuid) {
        index = i
      }
      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
        _linkableFields.push({
          value: item.field,
          text: item.label + ' (表单)'
        })
        _linksupFields.push({
          value: item.field,
          text: item.label
        })
      }
    })
    if (index !== null) {
      if (index === 0) {
        standardform = config.fields[index + 1] || null
      } else {
        standardform = config.fields[index - 1] || null
      }
    }
    componentConfig.columns.forEach(col => {
      if (col.field && !uniq.has(col.field)) {
        uniq.set(col.field, true)
        _linkableFields.push({
          value: col.field,
          text: col.label + ' (显示列)'
        })
      }
    })
    if (card.linkSubField && card.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      card.linkSubField = card.linkSubField.filter(item => fields.includes(item))
    }
    if (!card.span && standardform && standardform.span) {
      card.span = standardform.span
      card.labelwidth = standardform.labelwidth
    }
    this.setState({
      standardform,
      visible: true,
      card: card,
      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, !!this.props.editTab)
    })
  }
  /**
   * @description 编辑后提交
   * 1、获取编辑后的表单信息
   * 2、去除可能存在的示例表单
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.config).toJS()
      let fieldrepet = false // 字段重复
      let labelrepet = false // 提示文字重复
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        } else if (res.label && item.uuid !== res.uuid && item.label === res.label) {
          labelrepet = true
        }
        if (item.uuid === res.uuid) {
          return res
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      } else if (labelrepet) {
        notification.warning({
          top: 92,
          message: '名称已存在!',
          duration: 10
        })
        return
      }
      _config.fields = _config.fields.filter(item => !item.origin)
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: res.dataSource
        }
        param.LText = param.LText.replace(/@\$|\$@/ig, '')
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.secretkey = Utils.encrypt('', param.timestamp)
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          param.rduri = window.GLOB.mainSystemApi
        }
        Api.getLocalConfig(param).then(result => {
          if (result.status) {
            this.setState({
              sqlVerifing: false,
              config: _config,
              card: null,
              visible: false
            })
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        })
      } else {
        this.setState({
          config: _config,
          card: null,
          visible: false
        })
      }
    })
  }
  /**
   * @description 表单删除并刷新
   */
  closeForm = (card) => {
    let _this = this
    confirm({
      content: `确定删除${card.label ? `<<${card.label}>>` : ''}吗?`,
      onOk() {
        let _config = fromJS(_this.state.config).toJS()
        _config.fields = _config.fields.filter(item => !(item.uuid === card.uuid))
        _this.setState({
          config: _config,
        })
      },
      onCancel() {}
    })
  }
  submitConfig = () => {
    const { config } = this.state
    this.setState({originConfig: fromJS(config).toJS()})
    this.props.handleSave(config)
    notification.success({
      top: 92,
      message: '保存成功。',
      duration: 2
    })
  }
  cancelConfig = () => {
    const { config, originConfig } = this.state
    if (!is(fromJS(config), fromJS(originConfig))) {
      let _this = this
      confirm({
        content: '配置信息未保存,确定返回吗?',
        onOk() {
          _this.props.handleBack()
        },
        onCancel() {}
      })
    } else {
      this.props.handleBack()
    }
  }
  /**
   * @description 全局设置模态框
   */
  changeSetting = () => {
    this.setState({
      settingVisible: true
    })
  }
  /**
   * @description 保存全局设置
   */
  settingSave = () => {
    const {config} = this.state
    this.settingRef.handleConfirm().then(res => {
      this.setState({
        config: {...config, setting: res},
        settingVisible: false
      })
    })
  }
  editModalCancel = () => {
    const { config, card } = this.state
    if (card.focus) {
      let _fields = config.fields.filter(item => item.uuid !== card.uuid)
      let _config = {...config, fields: _fields}
      this.setState({
        card: null,
        config: _config,
        visible: false
      })
    } else {
      this.setState({
        card: null,
        visible: false
      })
    }
  }
  /**
   * @description 更新
   */
  updateConfig = (config) => {
    this.setState({
      config
    })
  }
  render () {
    const { config, dict } = this.state
    return (
      <div className="mob-search-board">
        <DndProvider backend={HTML5Backend}>
          <div className="tools">
            <Collapse accordion defaultActiveKey="1" bordered={false}>
              <Panel header={dict['header.menu.form']} key="1">
                <div className="search-element">
                  {SearchItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                <FieldsComponent
                  config={config}
                  type="form"
                  updatefield={this.updateConfig}
                />
              </Panel>
            </Collapse>
          </div>
          <div className="modal-control">
            <Button icon="setting" onClick={this.changeSetting}>设置</Button>
            <Button type="primary" onClick={this.submitConfig}>保存</Button>
            <Button onClick={this.cancelConfig}>返回</Button>
            <PasteComponent type="menu" Tab={null} insert={this.insert} />
            <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
          </div>
          <div className="setting">
            <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
              <div className="mob-shell-inner">
                <div className="am-navbar">
                  <Icon type="close" />
                  <div className="am-navbar-title">{config.setting.title}</div>
                </div>
                <DragElement
                  list={config.fields}
                  setting={config.setting}
                  showField={this.state.showField}
                  placeholder={this.state.dict['header.form.modal.placeholder']}
                  handleList={this.handleList}
                  handleForm={this.handleForm}
                  closeForm={this.closeForm}
                />
                <Button className="modal-submit" type="primary">确定</Button>
              </div>
            </div>
          </div>
        </DndProvider>
        <Modal
          title={this.state.dict['model.edit']}
          visible={this.state.visible}
          width={850}
          onCancel={this.editModalCancel}
          onOk={this.handleSubmit}
          confirmLoading={this.state.sqlVerifing}
          destroyOnClose
        >
          <ModalForm
            dict={this.state.dict}
            card={this.state.card}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
        <Modal
          title={this.state.dict['model.edit']}
          visible={this.state.settingVisible}
          width={850}
          maskClosable={false}
          onOk={this.settingSave}
          onCancel={() => { this.setState({ settingVisible: false }) }}
          destroyOnClose
        >
          <SettingForm
            config={config}
            dict={this.state.dict}
            isSubTab={!!this.props.editTab}
            inputSubmit={this.settingSave}
            wrappedComponentRef={(inst) => this.settingRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default ComModalConfig
src/mob/searchconfig/index.scss
New file
@@ -0,0 +1,321 @@
.mob-search-board {
  position: fixed;
  z-index: 1070;
  top: 48px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background: rgba(0, 0, 0, 1);
  .tools {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1;
    width: 235px;
    background: #ffffff;
    border-right: 1px solid #d9d9d9;
    height: 100%;
    overflow-y: auto;
    padding-bottom: 30px;
    .ant-collapse-borderless {
      background-color: #ffffff;
    }
    .ant-collapse-item {
      border: 0;
    }
    .ant-input-search {
      margin-top: 10px;
    }
    .ant-collapse-item.ant-collapse-item-active {
      border-bottom: 1px solid #d9d9d9;
    }
    .ant-collapse .ant-collapse-header {
      padding: 11px 16px 10px 40px;
      border-bottom: 1px solid #d9d9d9;
      background: #1890ff;
      color: #ffffff;
    }
    .ant-collapse-content-box {
      .ant-form-item {
        margin-bottom: 10px;
        .ant-form-item-label {
          text-align: left;
          height: 25px;
          line-height: 25px;
        }
      }
      .ant-btn {
        margin-bottom: 10px;
      }
    }
    .search-element {
      padding-top: 10px;
      li {
        padding: 0px 16px 10px;
        div {
          cursor: move;
        }
      }
    }
    .tables {
      .ant-select-selection-selected-value {
        opacity: 0.4!important;
      }
    }
    .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;
        width: 100%;
        .anticon {
          position: absolute;
          top: 0px;
          right: 0px;
          padding: 3px 3px 10px 10px;
          cursor: pointer;
        }
        .bottom-mask {
          position: absolute;
          width: 100%;
          height: 8px;
          bottom: 0;
          left: 0;
          background: #ffffff;
          border-radius: 8px;
        }
      }
    }
  }
  .tools::-webkit-scrollbar {
    width: 4px;
  }
  .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);
  }
  .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);
  }
  .modal-control {
    position: absolute;
    right: 0;
    top: 0;
    width: 120px;
    height: 100vh;
    padding: 20px 10px;
    background: #ffffff;
    z-index: 10;
    transition: right 0.3s;
    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;
      }
    }
    .ant-switch.big:after {
      width: 22px;
      height: 22px;
    }
  }
  .setting {
    position: relative;
    width: 100vw;
    height: 100%;
    background: #959595;
    .mob-shell {
      margin: 0 auto;
      background: #000000;
      background-size: 100% 100%;
      padding: 25px 13px 40px;
      border-radius: 30px;
      .am-navbar {
        height: 45px;
        line-height: 45px;
        position: relative;
        border-bottom: 1px solid #f0f0f0;
        margin-bottom: 10px;
        .anticon-close {
          position: absolute;
          line-height: 45px;
          font-size: 18px;
          right: 10px;
        }
        .am-navbar-title {
          font-size: 16px;
          text-align: center;
        }
      }
      .modal-submit {
        width: 100%;
        border-radius: 0;
        opacity: 0.5;
        cursor: default;
        font-size: 18px;
        height: 40px;
      }
      .modal-fields-row {
        min-height: calc(100% - 95px);
        padding: 0 10px 35px;
      }
      .modal-form {
        padding: 0px 24px;
        min-height: 87px;
        .group-title {
          position: relative;
          min-height: 22px;
          margin-bottom: 10px;
          padding-top: 10px;
          border-bottom: 1px solid #e8e8e8;
          span {
            padding: 0 5px 5px;
          }
        }
        > .ant-row {
          min-height: 120px;
        }
        .ant-row .ant-col-6 {
          padding: 0 12px!important;
        }
        .ant-row.ant-form-item .ant-col {
          padding: 0;
        }
        .textarea2, .textarea4 {
          padding-left: 7px;
        }
        .page-card {
          position: relative;
          background: #ffffff;
          border-radius: 2px;
          margin-bottom: 15px;
          .ant-form-item {
            cursor: move;
            display: flex;
            margin-bottom: 0px;
            .ant-form-item-label {
              overflow: visible;
              position: relative;
              height: 40px;
              label {
                width: 100%;
                cursor: move;
                overflow: hidden;
                display: inline-block;
                text-overflow: ellipsis;
                white-space: nowrap;
              }
            }
            .ant-form-item-control-wrapper {
              position: relative;
              .ant-select {
                width: 100%;
                margin-top: 4px;
              }
              .ant-calendar-picker {
                width: 100%;
                margin-top: 4px;
              }
              .ant-input-number {
                width: 100%;
                margin-top: 4px;
              }
              .normal-braft-editor {
                border: 1px solid #d9d9d9;
                border-radius: 4px;
              }
            }
            .ant-form-item-control-wrapper::after {
              content: '';
              position: absolute;
              top: 0;
              left: 0;
              right: 0;
              bottom: 0;
              opacity: 0;
              z-index: 1;
            }
            .ant-col-cuslabel {
              width: 10.5%;
            }
            .ant-col-cuswrap {
              width: 89.5%;
            }
          }
        }
        .ant-calendar-picker {
          min-width: 100px!important;
        }
      }
    }
  }
  .setting {
    overflow-y: auto;
  }
  .setting::-webkit-scrollbar {
    width: 7px;
  }
  .setting::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .setting::-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);
  }
}
.modal-fields {
  .ant-modal {
    top: 50px;
    padding-bottom: 5px;
    .ant-modal-body {
      max-height: calc(100vh - 190px);
      overflow-y: auto;
      .ant-empty {
        margin: 15vh 8px;
      }
    }
    .ant-modal-body::-webkit-scrollbar {
      width: 7px;
    }
    .ant-modal-body::-webkit-scrollbar-thumb {
      border-radius: 5px;
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
      background: rgba(0, 0, 0, 0.13);
    }
    .ant-modal-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);
    }
  }
}
src/mob/searchconfig/pastecomponent/index.jsx
New file
@@ -0,0 +1,76 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Button, Modal, notification } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
class PasteController extends Component {
  static propTpyes = {
    config: PropTypes.object,        // 组件配置
    updateConfig: PropTypes.func
  }
  state = {
    visible: false
  }
  pasteSubmit = () => {
    const { config } = this.props
    this.pasteFormRef.handleConfirm().then(res => {
      if (res.copyType !== 'form') {
        notification.warning({ top: 92, message: '配置信息格式错误!', duration: 5 })
        return
      }
      let keys = config.fields.map(item => item.field ? item.field.toLowerCase() : '$emp_ty$')
      if (['multiselect', 'color', 'brafteditor'].includes(res.type)) {
        res.type = 'text'
      }
      if (res.field && keys.includes(res.field.toLowerCase())) {
        notification.warning({
          top: 92,
          message: '搜索字段已存在!',
          duration: 5
        })
        return
      }
      this.props.updateConfig(config)
      this.setState({visible: false})
      notification.success({
        top: 92,
        message: '粘贴成功!',
        duration: 2
      })
    })
  }
  render() {
    const { visible } = this.state
    return (
      <div style={{display: 'inline-block'}}>
        <Button icon="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} >粘贴</Button>
        <Modal
          title="粘贴"
          visible={visible}
          width={600}
          maskClosable={false}
          onOk={this.pasteSubmit}
          onCancel={() => {this.setState({visible: false})}}
          destroyOnClose
        >
          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
        </Modal>
      </div>
    )
  }
}
export default PasteController
src/mob/searchconfig/pastecomponent/index.scss
src/mob/searchconfig/source.jsx
New file
@@ -0,0 +1,104 @@
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
const CommonDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
export const SearchItems = [
  {
    type: 'form',
    label: CommonDict['model.form.text'],
    subType: 'text',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.number'],
    subType: 'number',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.select'],
    subType: 'select',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.link'],
    subType: 'link',
    url: ''
  },
  {
    type: 'form',
    label: '开关',
    subType: 'switch',
    url: ''
  },
  {
    type: 'form',
    label: '多选框',
    subType: 'checkbox',
    url: ''
  },
  {
    type: 'form',
    label: '单选框',
    subType: 'radio',
    url: ''
  },
  {
    type: 'form',
    label: '选项卡',
    subType: 'checkcard',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['header.form.fileupload'],
    subType: 'fileupload',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.dateday'],
    subType: 'date',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.datemonth'],
    subType: 'datemonth',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.datetime'],
    subType: 'datetime',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['model.form.textarea'],
    subType: 'textarea',
    url: ''
  },
  {
    type: 'form',
    label: CommonDict['header.form.funcvar'],
    subType: 'funcvar',
    url: ''
  },
  {
    type: 'form',
    label: '提示',
    subType: 'hint',
    url: ''
  },
  {
    type: 'form',
    label: '分割线',
    subType: 'split',
    url: ''
  }
]
src/templates/modalconfig/index.jsx
@@ -218,7 +218,7 @@
      if (card.uuid === item.uuid) {
        index = i
      }
      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
      if (!['select', 'link', 'radio', ''].includes(item.type)) return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
@@ -338,7 +338,7 @@
      _config.fields = _config.fields.filter(item => !item.origin)
      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
src/templates/zshare/formconfig.jsx
@@ -2819,6 +2819,20 @@
    },
    {
      type: 'radio',
      key: 'splitline',
      label: '分割线',
      initVal: card.splitline || 'true',
      forbid: appType !== 'mob',
      options: [{
        value: 'true',
        text: '显示'
      }, {
        value: 'false',
        text: '隐藏'
      }]
    },
    {
      type: 'radio',
      key: 'count',
      label: '计数功能',
      initVal: card.count || 'false',
src/templates/zshare/modalform/index.jsx
@@ -16,25 +16,25 @@
const DataTable = asyncComponent(() => import('./datatable'))
const modalTypeOptions = {
  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'scan'],
  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor'],
  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter'],
  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'tooltip', 'extra'],
  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText'],
  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'fieldlength', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'borderColor'],
  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline'],
  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline'],
  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline'],
  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline'],
  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText', 'splitline'],
  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'fieldlength', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'borderColor', 'splitline'],
  multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra'],
  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter'],
  fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress'],
  switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode'],
  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType'],
  datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode'],
  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline'],
  fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress', 'splitline'],
  switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline'],
  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline'],
  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'splitline'],
  datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline'],
  textarea: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'span', 'labelwidth', 'maxRows', 'encryption', 'interception', 'tooltip', 'extra', 'count'],
  color: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
  hint: ['label', 'type', 'blacklist', 'message', 'span', 'labelwidth'],
  hint: ['label', 'type', 'blacklist', 'message', 'span', 'labelwidth', 'splitline'],
  split: ['label', 'type'],
  brafteditor: ['required', 'hidelabel', 'hidden', 'readin', 'fieldlength', 'readonly', 'span', 'labelwidth', 'tooltip', 'extra', 'encryption'],
  funcvar: ['span', 'labelwidth'],
  funcvar: ['span', 'labelwidth', 'splitline'],
  linkMain: ['readonly', 'required', 'hidden', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra']
}
src/views/mobdesign/index.jsx
@@ -35,6 +35,7 @@
const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
const ModalController = asyncComponent(() => import('@/mob/modalconfig/controller'))
const SearchController = asyncComponent(() => import('@/mob/searchconfig/controller'))
const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller'))
const StyleCombControlButton = asyncComponent(() => import('@/menu/stylecombcontrolbutton'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -1536,6 +1537,7 @@
          <StyleController />
          <StyleCombController />
          <ModalController />
          <SearchController />
        </div>
      </ConfigProvider>
    )