king
2020-06-18 f59a500d24291d7f54b71dcca939a2a23dedca7c
2020-06-18
19个文件已修改
29个文件已添加
3649 ■■■■■ 已修改文件
src/assets/mobimg/mob-login1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/mob.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/mob.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/index.jsx 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/index.scss 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/billcodeform/index.jsx 374 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/billcodeform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/contrastform/index.jsx 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/contrastform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/customform/index.jsx 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/customform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/customscript/index.jsx 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/customscript/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/index.jsx 1084 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/index.scss 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/uniqueform/index.jsx 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/uniqueform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/voucherform/index.jsx 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/datasource/verifycard/voucherform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/dragsource/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/dragsource/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/header/index.jsx 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/header/index.scss 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobcard/index.jsx 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobcard/index.scss 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobcard/mutilform/index.jsx 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobcard/mutilform/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/card.jsx 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/index.jsx 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/dragsource/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/dragsource/index.scss 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/index.jsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modelsource/option.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/rolemanage/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 98 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobmanage/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobmanage/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/mob-login1.png
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' ?
          <a href="#/mobmanage" target="_blank" className="mobile" type="edit"> 移动端 <Icon type="arrow-right" /></a> : null
        } */}
        {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/index.js
@@ -94,7 +94,7 @@
}
if (process.env.NODE_ENV === 'production') { // 用于校验是否存在开发权限
  let _service = window.location.href.replace(/\/index.html(.*)/ig, '').replace(new RegExp(document.location.origin + '/?', 'ig'), '')
  let _service = window.location.href.replace(/\/index.html(.*)|\/#(.*)/ig, '').replace(new RegExp(document.location.origin + '/?', 'ig'), '')
  window.GLOB.linkurl = window.location.href.split('#')[0]
  window.GLOB.service = _service ? _service + '/' : ''
} else {
src/locales/en-US/mob.js
@@ -1,6 +1,10 @@
export default {
  'mob.login': '登录',
  'mob.confirm': '确定',
  'mob.submit': '提交',
  'mob.cancel': '取消',
  'mob.header.logout': '退出',
  'mob.header.logout.hint': '您确定要退出吗?',
  'mob.required.input': '请输入',
  'mob.required.select': '请选择',
}
src/locales/zh-CN/mob.js
@@ -1,6 +1,10 @@
export default {
  'mob.login': '登录',
  'mob.confirm': '确定',
  'mob.submit': '提交',
  'mob.cancel': '取消',
  'mob.header.logout': '退出',
  'mob.header.logout.hint': '您确定要退出吗?',
  'mob.required.input': '请输入',
  'mob.required.select': '请选择',
}
src/mob/datasource/index.jsx
New file
@@ -0,0 +1,96 @@
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'
class DataSource extends Component {
  static propTpyes = {
    config: PropTypes.any,
    updateConfig: PropTypes.func
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    sourcelist: [],
    visible: false,
    source: null
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  editDataSource = (item) => {
    if (!item) {
      item = {
        uuid: Utils.getuuid()
      }
    }
    this.setState({
      visible: true,
      source: item
    })
  }
  closeDataSource = () => {
  }
  render () {
    const { sourcelist, visible, source, dict } = this.state
    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.label}</span>
              <span className="mob-input-group-addon">
                <Icon type="setting" onClick={() => this.editDataSource(item)} />
                <Icon type="close" onClick={() => this.closeDataSource(item)} />
              </span>
            </span>
          </span>
        ))}
        <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>
        <Modal
          wrapClassName="mob-datasource-verify-modal"
          title={'数据源配置'}
          visible={visible}
          width={'75vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          okText={dict['mob.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <VerifyCard
            card={source}
            dict={dict}
            wrappedComponentRef={(inst) => this.verifyRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default DataSource
src/mob/datasource/index.scss
New file
@@ -0,0 +1,79 @@
.mob-datasource {
  width: 100%;
  height: 100%;
  overflow: hidden;
  .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;
      }
      .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;
    }
  }
}
src/mob/datasource/verifycard/billcodeform/index.jsx
New file
@@ -0,0 +1,374 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Select, Button, InputNumber, Input, Tooltip, Icon } from 'antd'
import { formRule } from '@/utils/option.js'
import './index.scss'
class UniqueForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    btn: PropTypes.object,          // 按钮信息
    fields: PropTypes.array,        // 表单
    billcodes: PropTypes.array,     // 表单
    columns: PropTypes.array,       // 表单
    modular: PropTypes.array,       // 表单
    modularDetail: PropTypes.array, // 表单
    orderChange: PropTypes.func     // 表单
  }
  state = {
    editItem: null,
    modularDetail: [],
    funFields: [],
    billFields: [],
    type: '1',
    TypeCharOne: 'Lp'
  }
  UNSAFE_componentWillMount() {
    let _modularDetail = []
    let _billFields = []
    if (this.props.modular.length > 0) {
      _modularDetail = this.props.modularDetail.filter(item => item.BID === this.props.modular[0].ID)
    }
    let fieldMap = new Map()
    this.props.fields.forEach(_field => {
      if (_field.type === 'text' && !fieldMap.has(_field.field)) {
        _billFields.push(_field)
        fieldMap.set(_field.field, true)
      }
    })
    if (this.props.btn.Ot !== 'notRequired') {
      this.props.columns.forEach(_field => {
        if (_field.type === 'text' && !fieldMap.has(_field.field)) {
          _billFields.push(_field)
          fieldMap.set(_field.field, true)
        }
      })
    }
    let _usedfields = this.props.billcodes.map(item => item.field)
    this.setState({
      modularDetail: _modularDetail,
      funFields: this.props.fields.filter(field => field.type === 'funcvar' && !_usedfields.includes(field.field)),
      billFields: _billFields
    })
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.modular), fromJS(nextProps.modular))) {
      let _detail = nextProps.modularDetail.filter(item => item.BID === nextProps.modular[0].ID)
      this.setState({
        modularDetail: _detail
      })
    }
  }
  edit = (record) => {
    let _usedfields = this.props.billcodes.map(item => item.field)
    let _funFields = this.props.fields.filter(field => field.type === 'funcvar' && (!_usedfields.includes(field.field) || field.field === record.field))
    if (record.TypeCharOne === 'Y' || record.TypeCharOne === 'n') {
      let _detail = this.props.modularDetail.filter(item => item.BID === record.ModularCode)
      let _modularDetailCode = ''
      if (_detail.filter(item => item.ModularDetailCode === record.ModularDetailCode).length > 0) {
        _modularDetailCode = record.ModularDetailCode
      }
      this.setState({
        type: '2',
        funFields: _funFields,
        editItem: record,
        modularDetail: _detail,
        TypeCharOne: record.TypeCharOne
      }, () => {
        this.props.form.setFieldsValue({
          field: record.field,
          TypeCharOne: record.TypeCharOne,
          ModularCode: record.ModularCode,
          ModularDetailCode: _modularDetailCode,
        })
      })
    } else {
      this.setState({
        type: '1',
        funFields: _funFields,
        editItem: record,
        TypeCharOne: record.TypeCharOne
      }, () => {
        let _form = {
          field: record.field,
          TypeCharOne: record.TypeCharOne,
          Type: record.Type,
          linkField: record.linkField
        }
        if (record.TypeCharOne === 'Lp') {
          _form.mark = record.mark || ''
        }
        this.props.form.setFieldsValue(_form)
      })
    }
  }
  voucherChange = (value) => {
    let _detail = this.props.modularDetail.filter(item => item.BID === value)
    this.setState({
      modularDetail: _detail
    })
    this.props.form.setFieldsValue({
      ModularDetailCode: _detail[0] ? _detail[0].ModularDetailCode : ''
    })
  }
  TypeCharOneChange = (value) => {
    if (value === 'Y' || value === 'n') {
      this.setState({
        type: '2',
        TypeCharOne: value
      })
    } else {
      this.setState({
        type: '1',
        TypeCharOne: value
      })
    }
  }
  handleConfirm = () => {
    const { funFields, billFields } = this.state
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
        let _funField = funFields.filter(item => item.field === values.field)[0]
        values.fieldName = _funField ? _funField.label : ''
        // 一级菜单值为20190203125926873D6029A9C511041719420时TypeCharTwo=TableCode,其他用BillCode
        if (values.ModularCode === '20190203125926873D6029A9C511041719420') {
          values.TypeCharTwo = 'TableCode'
        } else {
          values.TypeCharTwo = 'BillCode'
        }
        // 设置类型名称,用于列表显示
        let billType = {
          Y: '单号',
          n: '编码',
          Lp: '行号',
          BN: '批次',
        }
        values.billType = billType[values.TypeCharOne]
        if (values.TypeCharOne === 'Y' || values.TypeCharOne === 'n') {
          // 设置凭证类型中文名
          let ModularCode = this.props.modular.filter(item => item.ID === values.ModularCode)[0]
          values.ModularCodeName = ModularCode.NameNO
          // 设置流水号位数
          let _detail = this.state.modularDetail.filter(item => item.ModularDetailCode === values.ModularDetailCode)[0]
          values.Type = _detail.Type
        } else {
          let _billField = billFields.filter(item => item.field === values.linkField)[0]
          values.linkFieldName = _billField ? _billField.label : ''
        }
        this.setState({
          editItem: null
        }, () => {
          this.props.orderChange(values)
          let _usedfields = this.props.billcodes.map(item => item.field)
          this.setState({
            funFields: this.props.fields.filter(field => field.type === 'funcvar' && !_usedfields.includes(field.field)),
          })
        })
        let _form = {
          field: ''
        }
        if (this.state.TypeCharOne === 'Lp') {
          _form.mark = ''
        }
        this.props.form.setFieldsValue(_form)
      }
    })
  }
  render() {
    const { getFieldDecorator } = this.props.form
    const { type, TypeCharOne } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 10 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 14 }
      }
    }
    return (
      <Form {...formItemLayout} className="verify-form">
        <Row gutter={24}>
          <Col span={7}>
            <Form.Item label={this.props.dict['header.form.funcvar']}>
              {getFieldDecorator('field', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + this.props.dict['header.form.funcvar'] + '!'
                  }
                ]
              })(
                <Select>
                  {this.state.funFields.map(option =>
                    <Select.Option title={option.label} id={option.uuid} key={option.uuid} value={option.field}>
                      {option.label}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'类型'}>
              {getFieldDecorator('TypeCharOne', {
                initialValue: 'Lp',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '类型!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.TypeCharOneChange(value)}}>
                  <Select.Option value="Y"> 单号 </Select.Option>
                  <Select.Option value="n"> 编码 </Select.Option>
                  <Select.Option value="Lp"> 行号 </Select.Option>
                  <Select.Option value="BN"> 批次 </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          {type === '1' ? <Col span={7}>
            <Form.Item label={'关联字段'}>
              {getFieldDecorator('linkField', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '关联字段!'
                  }
                ]
              })(
                <Select>
                  {this.state.billFields.map(option =>
                    <Select.Option title={option.label} id={option.uuid} key={option.uuid} value={option.field}>
                      {option.label}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          {type === '2' ? <Col span={7}>
            <Form.Item label={'凭证类型'}>
              {getFieldDecorator('ModularCode', {
                initialValue: this.props.modular[0] ? this.props.modular[0].ID : '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '凭证类型!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(value) => {this.voucherChange(value)}}
                >
                  {this.props.modular.map(option =>
                    <Select.Option title={option.NameNO} id={option.ID} key={option.ID} value={option.ID}>
                      {option.NameNO}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          <Col span={3} className="add">
            <Button onClick={this.handleConfirm} className="mk-green">
              保存
            </Button>
          </Col>
          {type === '1' ? <Col span={7}>
            <Form.Item label={'位数'}>
              {getFieldDecorator('Type', {
                initialValue: 4,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '位数!'
                  }
                ]
              })(<InputNumber min={1} max={10} precision={0} />)}
            </Form.Item>
          </Col> : null}
          {type === '2' ? <Col span={7}>
            <Form.Item label={'凭证标识'}>
              {getFieldDecorator('ModularDetailCode', {
                initialValue: this.state.modularDetail[0] ? this.state.modularDetail[0].ModularDetailCode : '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '凭证标识!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {this.state.modularDetail.map(option =>
                    <Select.Option style={{whiteSpace: 'unset'}} title={option.CodeName} id={option.ModularDetailCode} key={option.ModularDetailCode} value={option.ModularDetailCode}>
                      {option.CodeName}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          {TypeCharOne === 'Lp' ? <Col span={7}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="该标识用于生成行号规则,为空时使用按钮ID">
                <Icon type="question-circle" />
                {'标识'}
              </Tooltip>
            }>
              {getFieldDecorator('mark', {
                initialValue: '',
                rules: [
                  {
                    pattern: /^[a-zA-Z0-9]*$/ig,
                    message: formRule.input.letternummsg
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col> : null}
        </Row>
      </Form>
    )
  }
}
export default Form.create()(UniqueForm)
src/mob/datasource/verifycard/billcodeform/index.scss
src/mob/datasource/verifycard/contrastform/index.jsx
New file
@@ -0,0 +1,166 @@
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,       // 字典项
    contrastChange: PropTypes.func  // 修改函数
  }
  state = {
    editItem: null // 编辑元素
  }
  edit = (record) => {
    this.setState({
      editItem: record
    })
    this.props.form.setFieldsValue({
      frontfield: record.frontfield,
      operator: record.operator,
      backfield: record.backfield,
      errmsg: record.errmsg,
      errorCode: record.errorCode
    })
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
        this.setState({
          editItem: null
        }, () => {
          this.props.contrastChange(values)
        })
        this.props.form.setFieldsValue({
          frontfield: '',
          backfield: '',
          errmsg: ''
        })
      }
    })
  }
  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={'内容1'}>
              {getFieldDecorator('frontfield', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '内容1!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'运算符'}>
              {getFieldDecorator('operator', {
                initialValue: '=',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '运算符!'
                  }
                ]
              })(
                <Select>
                  <Select.Option value="="> = </Select.Option>
                  <Select.Option value="!="> != </Select.Option>
                  <Select.Option value=">"> &gt; </Select.Option>
                  <Select.Option value="<"> &lt; </Select.Option>
                  <Select.Option value=">="> &gt;= </Select.Option>
                  <Select.Option value="<="> &lt;= </Select.Option>
                  <Select.Option value="in"> in </Select.Option>
                  <Select.Option value="like"> like </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'内容2'}>
              {getFieldDecorator('backfield', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '内容2!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={3} className="add">
            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
              保存
            </Button>
          </Col>
          <Col span={7}>
            <Form.Item label={'提示信息'}>
              {getFieldDecorator('errmsg', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '提示信息!'
                  },
                  {
                    pattern: /^[^']*$/ig,
                    message: '提示信息不允许包含\''
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'报错编码'}>
              {getFieldDecorator('errorCode', {
                initialValue: 'E',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '报错编码!'
                  }
                ]
              })(
                <Select>
                  <Select.Option value="E"> E </Select.Option>
                  <Select.Option value="N"> N </Select.Option>
                  <Select.Option value="F"> F </Select.Option>
                  <Select.Option value="NM"> NM </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(UniqueForm)
src/mob/datasource/verifycard/contrastform/index.scss
src/mob/datasource/verifycard/customform/index.jsx
New file
@@ -0,0 +1,232 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, Button, notification, Modal } from 'antd'
import moment from 'moment'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import './index.scss'
const { TextArea } = Input
class CustomForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    btn: PropTypes.object,          // 按钮
    usefulfields: PropTypes.string, // 可用字段
    initsql: PropTypes.string,      // 可用字段
    customChange: PropTypes.func    // 表单
  }
  state = {
    editItem: null,
    loading: false
  }
  edit = (record) => {
    this.setState({
      editItem: record
    })
    this.props.form.setFieldsValue({
      sql: record.sql,
      result: record.result,
      errmsg: record.errmsg,
      errorCode: record.errorCode
    })
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
        values.resultName = values.result === 'false' ? '不存在' : '存在'
        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: '自定义sql语句中,不可出现字符 -- ,注释请用 /*内容*/',
            duration: 5
          })
          return
        }
        let error = Utils.verifySql(values.sql)
        if (error) {
          notification.warning({
            top: 92,
            message: 'sql中不可使用' + error,
            duration: 5
          })
          return
        }
        let param = {
          func: 's_debug_sql',
          LText: this.props.initsql + values.sql
        }
        // 数据权限
        param.LText = param.LText.replace(/@\$|\$@/ig, '')
        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)
        this.setState({loading: true})
        Api.getLocalConfig(param).then(res => {
          if (res.status) {
            this.setState({
              loading: false,
              editItem: null
            }, () => {
              this.props.customChange(values)
            })
            this.props.form.setFieldsValue({
              sql: '',
              errmsg: ''
            })
          } else {
            this.setState({loading: false})
            Modal.error({
              title: res.message
            })
          }
        })
      }
    })
  }
  render() {
    const { usefulfields, btn } = 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="verify-form" id="verifycard2">
        <Row gutter={24}>
          {usefulfields ? <Col span={21} className="sqlfield">
            <Form.Item label={'可用字段'}>
              {usefulfields}
            </Form.Item>
          </Col> : null}
          <Col span={21} className="sql">
            <Form.Item label={'sql'}>
              {getFieldDecorator('sql', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + 'sql!'
                  }
                ]
              })(<TextArea rows={15} />)}
            </Form.Item>
          </Col>
          <Col span={3} className="add">
            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green">
              保存
            </Button>
            {btn.sql ? <div style={{marginTop: '31px'}}>
              表名:  <div style={{wordBreak: 'break-all'}}>{btn.sql}</div>
            </div> : null}
          </Col>
          <Col span={7}>
            <Form.Item label={'结果处理'}>
              {getFieldDecorator('result', {
                initialValue: 'true',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '结果处理!'
                  }
                ]
              })(
                <Select>
                  <Select.Option value="true"> 存在 </Select.Option>
                  <Select.Option value="false"> 不存在 </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'提示信息'}>
              {getFieldDecorator('errmsg', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '提示信息!'
                  },
                  {
                    pattern: /^[^']*$/ig,
                    message: '提示信息不允许包含\''
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'报错编码'}>
              {getFieldDecorator('errorCode', {
                initialValue: 'E',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '报错编码!'
                  }
                ]
              })(
                <Select
                  getPopupContainer={() => document.getElementById('verifycard2')}
                >
                  <Select.Option value="E"> E </Select.Option>
                  <Select.Option value="N"> N </Select.Option>
                  <Select.Option value="F"> F </Select.Option>
                  <Select.Option value="NM"> NM </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(CustomForm)
src/mob/datasource/verifycard/customform/index.scss
src/mob/datasource/verifycard/customscript/index.jsx
New file
@@ -0,0 +1,257 @@
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 moment from 'moment'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import './index.scss'
const { TextArea } = Input
class CustomForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    btn: PropTypes.object,          // 按钮信息
    usefulfields: PropTypes.string, // 可用字段
    initsql: PropTypes.string,      // sql前缀
    systemScripts: PropTypes.array, // 系统脚本
    customScripts: PropTypes.array, // 自定义脚本
    scriptsChange: PropTypes.func   // 表单
  }
  state = {
    editItem: null,
    loading: false
  }
  edit = (record) => {
    this.setState({
      editItem: record
    })
    this.props.form.setFieldsValue({
      sql: record.sql,
      position: record.position || 'back'
    })
  }
  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: '自定义sql语句中,不可出现字符 -- ,注释请用 /*内容*/',
            duration: 5
          })
          return
        }
        let error = Utils.verifySql(values.sql, 'customscript')
        if (error) {
          notification.warning({
            top: 92,
            message: 'sql中不可使用' + error,
            duration: 5
          })
          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 += `
            ${script.sql}
            `
        })
        let param = {
          func: 's_debug_sql',
          LText: this.props.initsql + _initsql + values.sql + tail
        }
        // 数据权限
        param.LText = param.LText.replace(/@\$|\$@/ig, '')
        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)
        this.setState({loading: true})
        Api.getLocalConfig(param).then(res => {
          if (res.status) {
            this.setState({
              loading: false,
              editItem: null
            }, () => {
              this.props.scriptsChange(values)
            })
            this.props.form.setFieldsValue({
              sql: ''
            })
          } else {
            this.setState({loading: false})
            Modal.error({
              title: res.message
            })
          }
        })
      }
    })
  }
  handleCancel = () => {
    this.setState({
      editItem: null
    })
    this.props.form.setFieldsValue({
      sql: ''
    })
  }
  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 { usefulfields, systemScripts, btn } = 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="verify-form" id="verify-custom-scripts">
        <Row gutter={24}>
          {btn.sql ? <Col span={8}>
            <Form.Item label={'表名'} style={{whiteSpace: 'nowrap', margin: 0}}>
              {btn.sql}
            </Form.Item>
          </Col> : null}
          <Col span={16}>
            <Form.Item label={'报错字段'} style={{margin: 0}}>
              ErrorCode, retmsg
            </Form.Item>
          </Col>
          {usefulfields ? <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>
              )}
            </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}
                getPopupContainer={() => document.getElementById('verify-custom-scripts')}
              >
                {systemScripts.map((option, i) =>
                  <Select.Option 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>
            <Button onClick={this.handleCancel} style={{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['form.required.input'] + 'sql!'
                  }
                ]
              })(<TextArea rows={15} />)}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(CustomForm)
src/mob/datasource/verifycard/customscript/index.scss
New file
@@ -0,0 +1,5 @@
#verify-custom-scripts {
  .ant-select-dropdown-menu-item {
    white-space: normal;
  }
}
src/mob/datasource/verifycard/index.jsx
New file
@@ -0,0 +1,1084 @@
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 moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import UniqueForm from './uniqueform'
import ContrastForm from './contrastform'
import CustomForm from './customform'
import CustomScript from './customscript'
import BillcodeForm from './billcodeform'
import VoucherForm from './voucherform'
import './index.scss'
const { TabPane } = Tabs
const { confirm } = Modal
const { Paragraph } = Typography
class VerifyCard extends Component {
  static propTpyes = {
    floor: PropTypes.any,      // 是否为子表
    btnTab: PropTypes.any,     // 表单标签页(按钮)参数
    config: PropTypes.any,     // 表单标签页参数
    dict: PropTypes.object,    // 字典项
    card: PropTypes.object,    // 按钮信息
    columns: PropTypes.array
  }
  state = {
    initsql: '',          // sql验证时变量声明及赋值
    verify: {},
    fields: [],
    usefulfields: '',
    defaultsql: '',         // 默认Sql
    orderModular: [],
    orderModularDetail: [],
    voucher: [],
    voucherDetail: [],
    systemScripts: [],
    columnsFields: [],
    uniqueColumns: [
      {
        title: '字段名',
        dataIndex: 'field',
        width: '35%'
      },
      {
        title: '报错编码',
        dataIndex: 'errorCode',
        width: '12%'
      },
      {
        title: '验证类型',
        dataIndex: 'verifyType',
        width: '13%',
        render: (text, record) => record.verifyType === 'logic' ? '逻辑验证' : '物理验证'
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '15%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
      },
      {
        title: '操作',
        align: 'center',
        width: '25%',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div>
            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              title={this.props.dict['header.form.query.delete']}
              okText={this.props.dict['model.confirm']}
              cancelText={this.props.dict['header.cancel']}
              onConfirm={() => this.handleDelete(record, 'unique')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
            </Popconfirm>
          </div>)
      }
    ],
    onceUniqueColumns: [
      {
        title: '字段名',
        dataIndex: 'field',
        width: '45%'
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '30%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
      },
      {
        title: '操作',
        align: 'center',
        width: '25%',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div>
            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'unique')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'unique', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'unique', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'unique')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              title={this.props.dict['header.form.query.delete']}
              okText={this.props.dict['model.confirm']}
              cancelText={this.props.dict['header.cancel']}
              onConfirm={() => this.handleDelete(record, 'unique')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
            </Popconfirm>
          </div>)
      }
    ],
    contrastColumns: [
      {
        title: '内容1',
        dataIndex: 'frontfield',
        width: '13%'
      },
      {
        title: '运算符',
        dataIndex: 'operator',
        width: '13%'
      },
      {
        title: '内容2',
        dataIndex: 'backfield',
        width: '13%',
      },
      {
        title: '提示信息',
        dataIndex: 'errmsg',
        width: '13%'
      },
      {
        title: '报错编码',
        dataIndex: 'errorCode',
        width: '13%'
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '15%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.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, 'contrast')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'contrast', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'contrast', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'contrast')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              title={this.props.dict['header.form.query.delete']}
              okText={this.props.dict['model.confirm']}
              cancelText={this.props.dict['header.cancel']}
              onConfirm={() => this.handleDelete(record, 'contrast')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
            </Popconfirm>
          </div>)
      }
    ],
    customColumns: [
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '45%',
        render: (text) => (
          <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
        )
      },
      {
        title: '结果处理',
        dataIndex: 'resultName',
        width: '9%'
      },
      {
        title: '提示信息',
        dataIndex: 'errmsg',
        width: '13%'
      },
      {
        title: '报错编码',
        dataIndex: 'errorCode',
        width: '9%'
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '9%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
      },
      {
        title: '操作',
        align: 'center',
        width: '15%',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div>
            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'customverify')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'customverify', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'customverify', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'customverify')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              title={this.props.dict['header.form.query.delete']}
              okText={this.props.dict['model.confirm']}
              cancelText={this.props.dict['header.cancel']}
              onConfirm={() => this.handleDelete(record, 'customverify')
            }>
              <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: 'position',
        width: '10%',
        render: (text, record) => {
          if (record.position === 'init') {
            return '初始化'
          } else if (record.position === 'front') {
            return 'sql前'
          } else {
            return 'sql后'
          }
        }
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '10%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.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" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'scripts', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'scripts', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              title={this.props.dict['header.form.query.delete']}
              okText={this.props.dict['model.confirm']}
              cancelText={this.props.dict['header.cancel']}
              onConfirm={() => this.handleDelete(record, 'scripts')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
            </Popconfirm>
          </div>)
      }
    ],
    orderColumns: [
      {
        title: this.props.dict['header.form.funcvar'],
        dataIndex: 'fieldName',
        width: '12%',
        render: (text, record) => (`${record.fieldName || ''}(${record.field})`)
      },
      {
        title: '类型',
        dataIndex: 'billType',
        width: '6%',
      },
      {
        title: '凭证类型',
        dataIndex: 'ModularCodeName',
        width: '11%'
      },
      {
        title: '凭证标识',
        dataIndex: 'ModularDetailCode',
        width: '11%'
      },
      {
        title: '关联字段',
        dataIndex: 'linkFieldName',
        width: '10%',
        render: (text, record) => (record.linkField ? `${record.linkFieldName || ''}(${record.linkField})` : '')
      },
      {
        title: '位数',
        dataIndex: 'Type',
        width: '6%'
      },
      {
        title: '示例',
        dataIndex: 'example',
        width: '13%',
        render: (text, record) => {
          let _text = ''
          let _type = record.Type
          if (_type && typeof(_type) === 'string') {
            _type = parseInt(_type)
          } else {
            _type = 4
          }
          if (record.TypeCharOne === 'n') {
            _text = record.ModularDetailCode + Array(_type).join('0') + '1'
          } else if (record.TypeCharOne === 'Y') {
            _text = record.ModularDetailCode + moment().format('YYYYMMDD') + Array(_type).join('0') + '1'
          } else if (record.TypeCharOne === 'Lp') {
            _text = Array(_type).join('0') + '10'
          } else if (record.TypeCharOne === 'BN') {
            _text = moment().format('YYYYMMDD') + Array(_type).join('0') + '1'
          }
          return _text
        }
      },
      {
        title: '标识',
        dataIndex: 'mark',
        width: '8%'
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '8%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['header.form.status.forbidden']}
              <Icon style={{marginLeft: '5px'}} type="stop" theme="twoTone" twoToneColor="#ff4d4f" />
            </div>
          ) :
          (
            <div>
              {this.props.dict['header.form.status.open']}
              <Icon style={{marginLeft: '5px'}} type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
            </div>
          )
      },
      {
        title: '操作',
        align: 'center',
        width: '15%',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div>
            <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record, 'ordercode')} style={{color: '#1890ff'}}><Icon type="edit" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'ordercode', 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'ordercode', 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record, 'ordercode')} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              title={this.props.dict['header.form.query.delete']}
              okText={this.props.dict['model.confirm']}
              cancelText={this.props.dict['header.cancel']}
              onConfirm={() => this.handleDelete(record, 'ordercode')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
            </Popconfirm>
          </div>)
      }
    ]
  }
  UNSAFE_componentWillMount() {
  }
  componentDidMount() {
  }
  getsysScript = () => {
    const { defaultsql } = this.state
    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') + '.000'
    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
    _sParam.open_key = Utils.encrypt(_sParam.secretkey, _sParam.timestamp, true) // 云端数据验证
    Api.getSystemConfig(_sParam).then(res => {
      if (res.status) {
        let _scripts = []
        if (defaultsql) {
          _scripts.push({
            name: '默认sql',
            value: defaultsql
          })
        }
        res.data.forEach(item => {
          let _item = {
            name: item.funcname,
            value: Utils.formatOptions(item.longparam, true)
          }
          _scripts.push(_item)
        })
        this.setState({
          systemScripts: _scripts
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      }
    })
  }
  uniqueChange = (values) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
      verify.uniques = verify.uniques.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      verify.uniques.push(values)
    }
    this.setState({
      verify: verify
    })
  }
  contrastChange = (values) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
      verify.contrasts = verify.contrasts.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      verify.contrasts.push(values)
    }
    this.setState({
      verify: verify
    })
  }
  customChange = (values) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
      verify.customverifys = verify.customverifys.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      verify.customverifys.push(values)
    }
    this.setState({
      verify: verify
    })
  }
  scriptsChange = (values) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
      verify.scripts = verify.scripts.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      verify.scripts.push(values)
    }
    this.setState({
      verify: verify
    })
  }
  orderChange = (values) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
      verify.billcodes = verify.billcodes.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      verify.billcodes.push(values)
    }
    this.setState({
      verify: verify
    })
  }
  onOptionChange = (e, key) => {
    const { verify } = this.state
    let value = e.target.value
    this.setState({
      verify: {...verify, [key]: value}
    })
  }
  handleDelete = (record, type) => {
    const { verify } = this.state
    if (type === 'customverify') {
      verify.customverifys = verify.customverifys.filter(item => item.uuid !== record.uuid)
    } else if (type === 'unique') {
      verify.uniques = verify.uniques.filter(item => item.uuid !== record.uuid)
    } else if (type === 'ordercode') {
      verify.billcodes = verify.billcodes.filter(item => item.uuid !== record.uuid)
    } else if (type === 'scripts') {
      verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid)
    } else if (type === 'contrast') {
      verify.contrasts = verify.contrasts.filter(item => item.uuid !== record.uuid)
    }
    this.setState({ verify: verify })
  }
  handleEdit = (record, type) => {
    if (type === 'customverify') {
      this.customForm.edit(record)
    } else if (type === 'unique') {
      this.uniqueForm.edit(record)
    } else if (type === 'ordercode') {
      this.orderForm.edit(record)
    } else if (type === 'scripts') {
      this.scriptsForm.edit(record)
    } else if (type === 'contrast') {
      this.contrastForm.edit(record)
    }
    let node = document.getElementById('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, type) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    record.status = record.status === 'false' ? 'true' : 'false'
    if (type === 'customverify') {
      verify.customverifys = verify.customverifys.map(item => {
        if (item.uuid === record.uuid) {
          return record
        } else {
          return item
        }
      })
    } else if (type === 'unique') {
      verify.uniques = verify.uniques.map(item => {
        if (item.uuid === record.uuid) {
          return record
        } else {
          return item
        }
      })
    } else if (type === 'contrast') {
      verify.contrasts = verify.contrasts.map(item => {
        if (item.uuid === record.uuid) {
          return record
        } else {
          return item
        }
      })
    } else if (type === 'ordercode') {
      verify.billcodes = verify.billcodes.map(item => {
        if (item.uuid === record.uuid) {
          return record
        } else {
          return item
        }
      })
    } else if (type === 'scripts') {
      verify.scripts = verify.scripts.map(item => {
        if (item.uuid === record.uuid) {
          return record
        } else {
          return item
        }
      })
    }
    this.setState({
      verify: verify
    })
  }
  handleUpDown = (record, type, direction) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    let index = 0
    if (type === 'customverify') {
      verify.customverifys = verify.customverifys.filter((item, i) => {
        if (item.uuid === record.uuid) {
          index = i
        }
        return item.uuid !== record.uuid
      })
      if ((index === 0 && direction === 'up') || (index === verify.customverifys.length && direction === 'down')) {
        return
      }
      if (direction === 'up') {
        verify.customverifys.splice(index - 1, 0, record)
      } else {
        verify.customverifys.splice(index + 1, 0, record)
      }
    } else if (type === 'unique') {
      verify.uniques = verify.uniques.filter((item, i) => {
        if (item.uuid === record.uuid) {
          index = i
        }
        return item.uuid !== record.uuid
      })
      if ((index === 0 && direction === 'up') || (index === verify.uniques.length && direction === 'down')) {
        return
      }
      if (direction === 'up') {
        verify.uniques.splice(index - 1, 0, record)
      } else {
        verify.uniques.splice(index + 1, 0, record)
      }
    } else if (type === 'contrast') {
      verify.contrasts = verify.contrasts.filter((item, i) => {
        if (item.uuid === record.uuid) {
          index = i
        }
        return item.uuid !== record.uuid
      })
      if ((index === 0 && direction === 'up') || (index === verify.contrasts.length && direction === 'down')) {
        return
      }
      if (direction === 'up') {
        verify.contrasts.splice(index - 1, 0, record)
      } else {
        verify.contrasts.splice(index + 1, 0, record)
      }
    } else if (type === 'ordercode') {
      verify.billcodes = verify.billcodes.filter((item, i) => {
        if (item.uuid === record.uuid) {
          index = i
        }
        return item.uuid !== record.uuid
      })
      if ((index === 0 && direction === 'up') || (index === verify.billcodes.length && direction === 'down')) {
        return
      }
      if (direction === 'up') {
        verify.billcodes.splice(index - 1, 0, record)
      } else {
        verify.billcodes.splice(index + 1, 0, record)
      }
    } else if (type === 'scripts') {
      verify.scripts = verify.scripts.filter((item, i) => {
        if (item.uuid === record.uuid) {
          index = i
        }
        return item.uuid !== record.uuid
      })
      if ((index === 0 && direction === 'up') || (index === verify.scripts.length && direction === 'down')) {
        return
      }
      if (direction === 'up') {
        verify.scripts.splice(index - 1, 0, record)
      } else {
        verify.scripts.splice(index + 1, 0, record)
      }
    }
    this.setState({
      verify: verify
    })
  }
  voucherChange = (voucher) => {
    const { verify } = this.state
    this.setState({
      verify: {
        ...verify,
        voucher: voucher
      }
    })
  }
  showError = (errorType) => {
    if (errorType === 'S') {
      notification.success({
        top: 92,
        message: '执行成功!',
        duration: 2
      })
    } else if (errorType === 'Y') {
      Modal.success({
        title: '执行成功!'
      })
    } else if (errorType === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: '执行失败!',
        duration: 10
      })
    } else if (errorType === 'N') {
      notification.error({
        top: 92,
        message: '执行失败!',
        duration: 10
      })
    } else if (errorType === 'E') {
      Modal.error({
        title: '执行失败!'
      })
    } else if (errorType === 'NM') {
      message.error('执行失败!')
    }
  }
  timeChange = (val, type) => {
    const { verify } = this.state
    this.setState({
      verify: {...verify, [type]: val}
    })
  }
  handleConfirm = () => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      if (verify.default === 'false' && verify.scripts.length === 0) {
        notification.warning({
          top: 92,
          message: '不执行默认sql时,必须设置自定义脚本!',
          duration: 5
        })
        return
      }
      let _loading = false
      if (this.customForm && this.customForm.state.editItem) {
        _loading = true
      } else if (this.uniqueForm && this.uniqueForm.state.editItem) {
        _loading = true
      } else if (this.orderForm && this.orderForm.state.editItem) {
        _loading = true
      } else if (this.scriptsForm && this.scriptsForm.state.editItem) {
        _loading = true
      } else if (this.contrastForm && this.contrastForm.state.editItem) {
        _loading = true
      }
      if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
        _loading = true
      } else if (this.customForm && this.customForm.props.form.getFieldValue('sql')) {
        _loading = true
      }
      if (_loading) {
        confirm({
          content: `存在未保存项,确定提交吗?`,
          okText: this.props.dict['model.confirm'],
          cancelText: this.props.dict['header.cancel'],
          onOk() {
            resolve(verify)
          },
          onCancel() {}
        })
      } else {
        resolve(verify)
      }
    })
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  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>
          <TabPane tab="比较验证" key="2x">
            <ContrastForm
              dict={this.props.dict}
              contrastChange={this.contrastChange}
              wrappedComponentRef={(inst) => this.contrastForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={verify.contrasts}
              columns={contrastColumns}
              pagination={false}
            />
          </TabPane>
          <TabPane tab={card.Ot !== 'requiredOnce' ? '唯一性验证' : '同类数据验证'} key="2">
            <UniqueForm
              btn={card}
              fields={card.Ot !== 'requiredOnce' ? fields : columnsFields}
              dict={this.props.dict}
              uniqueChange={this.uniqueChange}
              wrappedComponentRef={(inst) => this.uniqueForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={verify.uniques}
              columns={card.Ot !== 'requiredOnce' ? uniqueColumns : onceUniqueColumns}
              pagination={false}
            />
          </TabPane>
          <TabPane tab="自定义验证" key="3">
            <CustomForm
              dict={this.props.dict}
              btn={this.props.card}
              initsql={this.state.initsql}
              usefulfields={this.state.usefulfields}
              customChange={this.customChange}
              wrappedComponentRef={(inst) => this.customForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={verify.customverifys}
              columns={customColumns}
              pagination={false}
            />
          </TabPane>
          <TabPane tab="单号生成" key="4">
            <BillcodeForm
              fields={fields}
              btn={this.props.card}
              billcodes={verify.billcodes}
              columns={this.props.columns}
              dict={this.props.dict}
              modular={orderModular}
              modularDetail={orderModularDetail}
              orderChange={this.orderChange}
              wrappedComponentRef={(inst) => this.orderForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={verify.billcodes}
              columns={orderColumns}
              pagination={false}
            />
          </TabPane>
          <TabPane tab="创建凭证" key="5">
            <VoucherForm
              dict={this.props.dict}
              voucher={voucher}
              columns={this.props.columns}
              voucherobj={verify.voucher}
              voucherDetail={voucherDetail}
              voucherChange={this.voucherChange}
              wrappedComponentRef={(inst) => this.voucherForm = inst}
            />
          </TabPane>
          <TabPane tab="自定义脚本" key="6">
            <CustomScript
              usefulfields={this.state.usefulfields}
              initsql={this.state.initsql}
              dict={this.props.dict}
              btn={this.props.card}
              customScripts={verify.scripts}
              systemScripts={this.state.systemScripts}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={verify.scripts}
              columns={scriptsColumns}
              pagination={false}
            />
          </TabPane>
        </Tabs>
      </div>
    )
  }
}
export default Form.create()(VerifyCard)
src/mob/datasource/verifycard/index.scss
New file
@@ -0,0 +1,66 @@
.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;
  }
}
src/mob/datasource/verifycard/uniqueform/index.jsx
New file
@@ -0,0 +1,157 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Select, Button } from 'antd'
import './index.scss'
class UniqueForm extends Component {
  static propTpyes = {
    btn: PropTypes.object,       // 字典项
    dict: PropTypes.object,       // 字典项
    fields: PropTypes.array,      // 表单字段
    uniqueChange: PropTypes.func  // 修改函数
  }
  state = {
    editItem: null // 编辑元素
  }
  edit = (record) => {
    const { btn } = this.props
    this.setState({
      editItem: record
    })
    let _value = {
      field: record.field.split(',')
    }
    if (btn.Ot !== 'requiredOnce') {
      _value.errorCode = record.errorCode
      _value.verifyType = record.verifyType || 'physical'
    }
    this.props.form.setFieldsValue(_value)
  }
  handleConfirm = () => {
    const { fields } = this.props
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
        values.fieldlabel = values.field.map(field => {
          let item = fields.filter(cell => cell.field === field)[0]
          let label = ''
          if (item) {
            label = item.label
          }
          return label
        })
        values.fieldlabel = values.fieldlabel.join(',')
        values.field = values.field.join(',')
        this.setState({
          editItem: null
        }, () => {
          this.props.uniqueChange(values)
        })
        this.props.form.setFieldsValue({
          field: [],
        })
      }
    })
  }
  render() {
    const { getFieldDecorator } = this.props.form
    const { fields, btn } = this.props
    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={8}>
            <Form.Item label={'字段名'}>
              {getFieldDecorator('field', {
                initialValue: [],
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '字段名!'
                  }
                ]
              })(
                <Select
                  mode="multiple"
                >
                  {fields.map(item => (
                    <Select.Option key={item.uuid} value={item.field}>{item.field}</Select.Option>
                  ))}
                </Select>
              )}
            </Form.Item>
          </Col>
          {btn.Ot !== 'requiredOnce' ? <Col span={6}>
            <Form.Item label={'报错编码'}>
              {getFieldDecorator('errorCode', {
                initialValue: 'E',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '报错编码!'
                  }
                ]
              })(
                <Select>
                  <Select.Option value="E"> E </Select.Option>
                  <Select.Option value="N"> N </Select.Option>
                  <Select.Option value="F"> F </Select.Option>
                  <Select.Option value="NM"> NM </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          {btn.Ot !== 'requiredOnce' ? <Col span={6}>
            <Form.Item label={'验证类型'}>
              {getFieldDecorator('verifyType', {
                initialValue: 'physical',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '验证类型!'
                  }
                ]
              })(
                <Select>
                  <Select.Option value="physical"> 物理验证 </Select.Option>
                  <Select.Option value="logic"> 逻辑验证 </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          <Col span={4} className="add">
            <Button onClick={this.handleConfirm} className="mk-green">
              保存
            </Button>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(UniqueForm)
src/mob/datasource/verifycard/uniqueform/index.scss
src/mob/datasource/verifycard/voucherform/index.jsx
New file
@@ -0,0 +1,269 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Select, Switch, notification } from 'antd'
import './index.scss'
class UniqueForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    voucherobj: PropTypes.object,   // 凭证信息
    voucher: PropTypes.array,       // 表单
    columns: PropTypes.array,       // 表单
    voucherDetail: PropTypes.array, // 表单
    voucherChange: PropTypes.func   // 表单
  }
  state = {
    voucher: [],
    voucherDetail: [],
    columns: []
  }
  UNSAFE_componentWillMount() {
    let _voucher = []
    let _voucherDetail = []
    if (this.props.voucherobj.BVoucherType && this.props.voucher.length > 0) {
      _voucher = this.props.voucher.filter(item => item.TypeCharOne === this.props.voucherobj.BVoucherType)
      _voucherDetail = this.props.voucherDetail.filter(item => item.BID === this.props.voucherobj.VoucherType)
    } else if (this.props.voucher.length > 0) {
      _voucher = this.props.voucher.filter(item => item.TypeCharOne === 'MES')
      _voucherDetail = this.props.voucherDetail.filter(item => _voucher[0] && item.BID === _voucher[0].ID)
    }
    this.setState({
      voucher: _voucher,
      voucherDetail: _voucherDetail,
      columns: this.props.columns.filter(col => col.type === 'text')
    })
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.voucher), fromJS(nextProps.voucher)) && nextProps.voucher.length > 0) {
      if (this.props.voucherobj.BVoucherType) {
        let _voucher = nextProps.voucher.filter(item => item.TypeCharOne === this.props.voucherobj.BVoucherType)
        let _voucherDetail = nextProps.voucherDetail.filter(item => item.BID === this.props.voucherobj.VoucherType)
        this.setState({
          voucher: _voucher,
          voucherDetail: _voucherDetail
        })
      } else {
        let _voucher = nextProps.voucher.filter(item => item.TypeCharOne === 'MES')
        let _voucherDetail = nextProps.voucherDetail.filter(item => _voucher[0] && item.BID === _voucher[0].ID)
        this.setState({
          voucher: _voucher,
          voucherDetail: _voucherDetail
        })
        this.props.form.setFieldsValue({
          VoucherType: _voucher[0] ? _voucher[0].ID : '',
          VoucherTypeOne: _voucherDetail[0] ? _voucherDetail[0].ModularDetailCode : ''
        })
      }
    }
  }
  voucherTypeChange = (value) => {
    const { voucherobj } = this.props
    let _voucher = this.props.voucher.filter(item => item.TypeCharOne === value)
    let _voucherDetail = this.props.voucherDetail.filter(item => _voucher[0] && item.BID === _voucher[0].ID)
    this.setState({
      voucher: _voucher,
      voucherDetail: _voucherDetail
    })
    this.props.form.setFieldsValue({
      VoucherType: _voucher[0] ? _voucher[0].ID : '',
      VoucherTypeOne: _voucherDetail[0] ? _voucherDetail[0].ModularDetailCode : ''
    })
    if (voucherobj.enabled) {
      this.props.voucherChange({...voucherobj, enabled: false})
    }
  }
  voucherSChange = (value) => {
    const { voucherobj } = this.props
    let _detail = this.props.voucherDetail.filter(item => item.BID === value)
    this.setState({
      voucherDetail: _detail
    })
    this.props.form.setFieldsValue({
      VoucherTypeOne: _detail[0] ? _detail[0].ModularDetailCode : ''
    })
    if (voucherobj.enabled) {
      this.props.voucherChange({...voucherobj, enabled: false})
    }
  }
  contentChange = () => {
    const { voucherobj } = this.props
    if (voucherobj.enabled) {
      this.props.voucherChange({...voucherobj, enabled: false})
    }
  }
  onEnabledChange = () => {
    const { voucherobj } = this.props
    if (voucherobj.enabled) {
      this.props.voucherChange({...voucherobj, enabled: false})
    } else {
      this.handleConfirm()
    }
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        values.enabled = true
        let _detail = this.state.voucherDetail.filter(item => item.ModularDetailCode === values.VoucherTypeOne)[0]
        if (!_detail) {
          notification.warning({
            top: 92,
            message: '凭证类型或凭证标识不存在!',
            duration: 5
          })
          return
        }
        values.VoucherTypeTwo = _detail.VoucherTypeTwo
        values.Type = _detail.IDefine1
        this.props.voucherChange(values)
      }
    })
  }
  render() {
    const { getFieldDecorator } = this.props.form
    const { voucherobj } = this.props
    const { columns } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 10 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 14 }
      }
    }
    return (
      <Form {...formItemLayout} className="verify-form">
        <Row gutter={24}>
          <Col span={11}>
            <Form.Item label={'主类型'}>
              {getFieldDecorator('BVoucherType', {
                initialValue: voucherobj.BVoucherType || 'MES',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '主类型!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.voucherTypeChange(value)}}>
                  <Select.Option value="MES"> 业务类凭证 </Select.Option>
                  <Select.Option value="FCC"> 财务类凭证 </Select.Option>
                  <Select.Option value="WMS"> 物流类凭证 </Select.Option>
                  <Select.Option value="Z"> 自定义 </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={11}>
            <Form.Item label={'凭证类型'}>
              {getFieldDecorator('VoucherType', {
                initialValue: voucherobj.VoucherType || (this.state.voucher[0] && this.state.voucher[0].ID) || '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '凭证类型!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(value) => {this.voucherSChange(value)}}
                >
                  {this.state.voucher.map(option =>
                    <Select.Option title={option.NameNO} id={option.ID} key={option.ID} value={option.ID}>
                      {option.NameNO}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={11}>
            <Form.Item label={'凭证标识'}>
              {getFieldDecorator('VoucherTypeOne', {
                initialValue: voucherobj.VoucherTypeOne || (this.state.voucherDetail[0] && this.state.voucherDetail[0].ModularDetailCode) || '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '凭证标识!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={this.contentChange}
                >
                  {this.state.voucherDetail.map(option =>
                    <Select.Option title={option.CodeName} id={option.ModularDetailCode} key={option.ModularDetailCode} value={option.ModularDetailCode}>
                      {option.CodeName}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={11}>
            <Form.Item label={'关联字段'}>
              {getFieldDecorator('linkField', {
                initialValue: voucherobj.linkField || (columns[0] && columns[0].field) || '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '关联字段!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={this.contentChange}
                >
                  {columns.map((option, index) =>
                    <Select.Option title={option.label} id={index + option.uuid} key={index + option.uuid} value={option.field}>
                      {option.label}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={11}>
            <Form.Item label={'是否启用'}>
              <Switch checkedChildren="启" unCheckedChildren="停" checked={voucherobj.enabled} onChange={this.onEnabledChange} />
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(UniqueForm)
src/mob/datasource/verifycard/voucherform/index.scss
src/mob/dragsource/index.jsx
New file
@@ -0,0 +1,13 @@
import React from 'react'
import { useDrag } from 'react-dnd'
import './index.scss'
const SourceElement = ({content}) => {
  const [, drag] = useDrag({ item: content })
  return (
    <div ref={drag} className="common-source-item">
      {content.label}
    </div>
  )
}
export default SourceElement
src/mob/dragsource/index.scss
New file
@@ -0,0 +1,9 @@
.common-source-item {
  display: block;
  box-shadow: 0px 0px 2px #bcbcbc;
  padding: 0.4rem 0.7rem;
  background-color: white;
  margin: 0px 0px 10px;
  cursor: move;
  border-radius: 4px;
}
src/mob/header/index.jsx
@@ -3,7 +3,7 @@
import { is, fromJS } from 'immutable'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import {Dropdown, Menu, Icon, Modal } from 'antd'
import {Dropdown, Menu, Icon, Modal, Tooltip, Button } from 'antd'
import { logout } from '@/store/action'
import zhCN from '@/locales/zh-CN/mob.js'
@@ -16,6 +16,9 @@
class MobHeader extends Component {
  static propTpyes = {
    view: PropTypes.string,
    saveIng: PropTypes.any,
    triggerSave: PropTypes.func,
    jumpToManage: PropTypes.func
  }
  state = {
@@ -54,9 +57,27 @@
        <div className="header-logo"><img src={this.state.logourl} alt=""/></div>
        {view === 'manage' ?
          <div className="mob-manage-title">
            移动端管理
            应用管理
          </div> :null
        }
        {view === 'design' ?
          <Menu
            mode="inline"
            theme="dark"
            inlineCollapsed={this.state.collapsed}
          >
            <Menu.Item key="1">
              <Tooltip placement="bottom" title="返回应用管理">
                <Icon type="arrow-left" onClick={this.props.jumpToManage} />
              </Tooltip>
            </Menu.Item>
            <Menu.Item key="2">
              <Tooltip placement="bottom" title="保存">
                <Button icon="save" loading={this.props.saveIng} onClick={this.props.triggerSave}></Button>
              </Tooltip>
            </Menu.Item>
          </Menu> : null
        }
        <Dropdown className="header-setting" overlay={
          <Menu>
            <Menu.Item key="2" onClick={this.logout}>{this.state.dict['mob.header.logout']}</Menu.Item>
src/mob/header/index.scss
@@ -50,4 +50,41 @@
    line-height: 48px;
    letter-spacing: 2px;
  }
  >.ant-menu {
    float: left;
    width: unset;
    .ant-menu-item {
      margin-bottom: 0;
      float: left;
      width: unset;
      cursor: default;
      .anticon-arrow-left {
        height: 24px;
        cursor: pointer;
      }
      .ant-btn {
        color: #fff;
        width: unset;
        cursor: pointer;
        height: 37px;
        background: transparent;
        border: 0;
        .anticon-save {
          margin-right: 0;
        }
      }
      .ant-btn[ant-click-animating-without-extra-node="true"]::after {
        display: none!important;
      }
      .ant-btn::before {
        display: none!important;
      }
    }
    .ant-menu-item.ant-menu-item-selected {
      background-color: transparent;
    }
    .ant-menu-item:not(:last-child) {
      border-right: 1px solid #353535;
    }
  }
}
src/mob/mobcard/index.jsx
@@ -1,15 +1,30 @@
import React, {Component} from 'react'
import { is, fromJS } from 'immutable'
import { Button, Card, Spin, Icon, Row, Col } from 'antd'
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 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 = {
    loading: false,
    data: []
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    loading: true,
    visible: false,
    confirmloading: false,
    data: [],
    card: null
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -24,18 +39,131 @@
    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: '',
      okText: this.state.dict['mob.confirm'],
      cancelText: this.state.dict['mob.cancel'],
      onOk() {
        return new Promise(resolve => {
          let param = {
            func: 's_kei_del',
            ID: card.uuid,
            kei_no: card.keiNo
          }
    
    // _param.LText = Utils.formatOptions(_param.LText)                   // 关键字符替换,base64加密
    // _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' // 时间戳
    // _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5密钥
          Api.getCloudConfig(param).then(result => {
            if (result.status) {
              notification.success({
                top: 92,
                message: '删除成功!',
                duration: 5
              })
    Api.getCloudConfig(param).then(res => {
              _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.type
      }
      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 } = this.state
    const { data, loading, card, dict } = this.state
    return (
      <div className="mob-card-row-box">
@@ -47,17 +175,22 @@
        }
        <Row gutter={24}>
          {data && data.length > 0 &&
            data.map((item, i) => (
              <Col key={i} span={6}>
            data.map(item => (
              <Col key={item.uuid} span={6}>
                <Card
                  size="small"
                  className="chart-card"
                  actions={[
                    <Button />,
                    <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="ant-card-meta-detail">
                  <div className="mk-mob-card-title">
                    {item.name}
                  </div>
                  <div className="mk-mob-card-type">
                    {item.type === 'mob' ? '移动端' : 'PC端'}
                  </div>
                </Card>
              </Col>
@@ -65,11 +198,26 @@
          }
          
          <Col span={6} key="insert">
            <div className="chart-card insert" onClick={() => {}}>
            <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}
          okText={this.state.dict['mob.confirm']}
          cancelText={this.state.dict['mob.cancel']}
          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>
    )
  }
src/mob/mobcard/index.scss
@@ -1,9 +1,33 @@
.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 {
src/mob/mobcard/mutilform/index.jsx
New file
@@ -0,0 +1,90 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select } 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>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/mob/mobcard/mutilform/index.scss
New file
@@ -0,0 +1,4 @@
.mob-card-edit-form {
  padding: 0px 24px 20px;
}
src/mob/mobshell/card.jsx
New file
@@ -0,0 +1,57 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
// import { Icon } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
// const Home = asyncComponent(() => import('@/mob/home'))
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 [{ isDragging }, drag] = useDrag({
    item: { type: 'action', id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'action',
    canDrop: () => true,
    drop: (item) => {
      if (!item.hasOwnProperty('originalIndex')) {
        hasDrop(card)
      }
    },
    hover({ id: draggedId }) {
      if (!draggedId) return
      if (draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    },
  })
  const opacity = isDragging ? 0.3 : 1
  return (
    <div ref={node => drag(drop(node))} style={{ opacity: opacity, height: '100%'}}>
      <Login />
      {/* <div className="page-card">
        <Button
          className={'mk-btn mk-' + card.class}
          icon={card.icon}
          key={card.uuid}
          onDoubleClick={() => doubleClickCard(id)}
        >
          {card.label}{card.position === 'grid' && <Icon type="table" />}
        </Button>
      </div> */}
      {/* <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
      <Icon className="edit close" title="close" type="close" onClick={() => delCard(id)} /> */}
    </div>
  )
}
export default Card
src/mob/mobshell/index.jsx
New file
@@ -0,0 +1,103 @@
import React 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 Card from './card'
import './index.scss'
const Container = ({list, placeholder, 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)
  // }
  // if (!is(fromJS(cards), fromJS(list))) {
  //   setCards(list)
  // }
  // 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)
  //   doubleClickCard(card)
  // }
  // const editCard = id => {
  //   const { card } = findCard(id)
  //   handleMenu(card)
  // }
  // const delCard = id => {
  //   const { card } = findCard(id)
  //   deleteMenu(card)
  // }
  // const hasDrop = (item) => {
  //   target = item
  // }
  const [, drop] = useDrop({
    accept: 'action',
    drop(item) {
      if (item.hasOwnProperty('originalIndex')) {
        return
      }
      // let newcard = {}
      // newcard.uuid = Utils.getuuid()
      // let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
      // if (target) {
      //   targetId = target.uuid
      // }
      // const { index: overIndex } = findCard(`${targetId}`)
      // let targetIndex = overIndex
      // targetIndex++
      // const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
      // handleList(_cards, newcard)
      // target = null
    }
  })
  return (
    <div ref={drop} className="mob-shell-inner">
      {/* {cards.map(card => (
        <Card
          id={card.uuid}
          key={card.uuid}
          card={card}
          moveCard={moveCard}
          editCard={editCard}
          delCard={delCard}
          findCard={findCard}
          hasDrop={hasDrop}
          doubleClickCard={doubleClickBtn}
        />
      ))} */}
      <Card />
      {/* {cards.length === 0 ?
        <div className="common-drawarea-placeholder">
          {placeholder}
        </div> : null
      } */}
    </div>
  )
}
export default Container
src/mob/mobshell/index.scss
New file
@@ -0,0 +1,6 @@
.common-drawarea-placeholder {
  width: 100%;
  line-height: 65px;
  text-align: center;
  color: #bcbcbc;
}
src/mob/modelsource/dragsource/index.jsx
New file
@@ -0,0 +1,18 @@
import React from 'react'
import { useDrag } from 'react-dnd'
import { Tooltip } from 'antd'
import './index.scss'
const SourceElement = ({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 SourceElement
src/mob/modelsource/dragsource/index.scss
New file
@@ -0,0 +1,25 @@
.mob-source-item {
  display: inline-block;
  width: 130px;
  margin-right: 15px;
  cursor: move;
  height: 130px;
  box-shadow: 0px 0px 3px #dddddd;
  background-size: contain;
  background-position: center 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;
  }
}
src/mob/modelsource/index.jsx
New file
@@ -0,0 +1,34 @@
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() {
    return (
      <div className="mob-card-source-box">
        {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
src/mob/modelsource/index.scss
New file
@@ -0,0 +1,9 @@
.mob-card-source-box {
  padding: 20px 0px 20px 15px;
  position: relative;
  p {
    color: rgba(0, 0, 0, 0.85);
    margin-bottom: 10px;
  }
}
src/mob/modelsource/option.jsx
New file
@@ -0,0 +1,14 @@
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
import mobLogin1 from '@/assets/mobimg/mob-login1.png'
const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
// 表单校验规则
export const mobOptions = [{
  title: _dict['mob.login'],
  type: 'login',
  options: [
    {type: 'mob-login-1', sourceType: 'mob', url: mobLogin1,  style: {}},
  ]
}]
src/router/index.js
@@ -18,7 +18,7 @@
  {path: '/ssologin/:param', name: 'ssologin', auth: true},
  {path: '/main', name: 'main', component: Main, auth: true},
  {path: '/mobmanage', name: 'mobmanage', component: MobManage, auth: true},
  {path: '/mobdesign', name: 'mobdesign', component: MobDesign, auth: true},
  {path: '/mobdesign/:appId/:appType', name: 'mobdesign', component: MobDesign, auth: true},
  {path: '/main/:param', name: 'pmain', component: Main, auth: true}
]
src/tabviews/rolemanage/index.jsx
@@ -118,7 +118,12 @@
      // ParentID(父级Id)、Selected(是否选中-已失效)、Tabs( 标签类型)、TypeCharOne 菜单类型PC或其他
      let _tree = this.getTree(fromJS(mainMenus).toJS(), result.data)
      if (_tree[0]) {
        this.getOpenNode(_tree[0], _openKeys)
        if (_tree[0].key === 'PC' && _tree[0].children) {
          // _openKeys = _tree[0].children.map(cell => cell.key)
          this.getOpenNode(_tree[0].children[0], _openKeys)
        } else {
          this.getOpenNode(_tree[0], _openKeys)
        }
      }
      this.setState({
@@ -163,7 +168,11 @@
        this.getCheckedKeys(fromJS(menuTrees).toJS(), _initKeys)
        if (menuTrees[0]) {
          this.getOpenNode(menuTrees[0], _openKeys)
          if (menuTrees[0].key === 'PC' && menuTrees[0].children) {
            this.getOpenNode(menuTrees[0].children[0], _openKeys)
          } else {
            this.getOpenNode(menuTrees[0], _openKeys)
          }
        }
        this.setState({
@@ -177,7 +186,11 @@
        let _tree = this.getSelectTree(fromJS(menuTrees).toJS(), Keys)
        if (_tree[0]) {
          this.getOpenNode(_tree[0], _openKeys)
          if (_tree[0].key === 'PC' && _tree[0].children) {
            this.getOpenNode(_tree[0].children[0], _openKeys)
          } else {
            this.getOpenNode(_tree[0], _openKeys)
          }
        }
        this.setState({
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -554,7 +554,7 @@
      } catch (e) {
        configParam = ''
      }
      if (!configParam) {
        error = '打印模板解析错误!'
      } else {
@@ -611,7 +611,7 @@
            item.LabelSize = element.fontSize
          } else if (item.Type === 'qrcode') {
            item.Type = 'barcode'
            item.BarcodeType = element.barcodeType
            item.BarcodeType = element.qrcodeType
            item.BarcodeWidth = element.qrcodeWidth
            item.BarcodeHeight = element.qrcodeWidth
            item.BarcodeLabel = false
src/tabviews/zshare/mutilform/index.jsx
@@ -935,12 +935,25 @@
    let _formlist = []
    let rowIndex = 0
    let colIndex = 0
    let filtration = {}
    // 表单分行,避免排列不整齐
    formlist.forEach(item => {
      if ((!item.field && item.type !== 'title') || item.hidden === 'true' || item.type === 'funcvar') return
      if (item.supField) { // 多层表单控制
        let _supVal = this.props.form.getFieldValue(item.supField)
      if (item.supField && !item.supvalue.includes(this.props.form.getFieldValue(item.supField))) return
        if (_supVal === undefined && filtration[item.supField]) {
          _supVal = filtration[item.supField]
        }
        if (item.supvalue.includes(_supVal)) {
          let _subVal = this.props.form.getFieldValue(item.field)
          filtration[item.field] = _subVal === undefined ? item.initval : _subVal
        } else {
          return
        }
      }
      _formlist[rowIndex] = _formlist[rowIndex] || []
      if (item.type === 'textarea' || item.type === 'title') {
src/templates/comtableconfig/index.jsx
@@ -1311,9 +1311,7 @@
              {/* 搜索条件添加 */}
              <Panel header={this.state.dict['header.menu.search']} key="1">
                <div className="search-element">
                  {Source.searchItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                  {Source.searchItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                <FieldsComponent
                  config={config}
@@ -1325,9 +1323,7 @@
              {/* 按钮添加 */}
              <Panel header={this.state.dict['header.menu.action']} key="2">
                <div className="search-element">
                  {Source.actionItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                  {Source.actionItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                <div className="config-btn">
                  {confActions.length > 0 ?
@@ -1355,9 +1351,7 @@
              {/* 添加显示列 */}
              <Panel header={this.state.dict['header.menu.column']} key="3">
                <div className="search-element">
                  {Source.columnItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                  {Source.columnItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                <FieldsComponent
                  config={config}
@@ -1369,9 +1363,7 @@
              {/* 添加标签 */}
              <Panel header={this.state.dict['header.menu.tab']} key="4">
                <div className="search-element">
                  {Source.tabItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                  {Source.tabItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                </div>
                {configTabs.length > 0 ?
                  <p className="config-btn-title">
src/templates/zshare/formconfig.jsx
@@ -6,8 +6,12 @@
/**
 * @description 获取页面设置表单配置信息
 * @param {object} setting   // 菜单全局设置信息
 * @param {string} type      // 菜单类型
 * @param {object} setting       // 菜单全局设置信息
 * @param {array}  usefulFields  // 内部函数可用的开头字符
 * @param {string} MenuID        // 菜单ID
 * @param {string} primaryKey    // 主键
 * @param {zrray}  columns       // 显示列
 * @param {string} type          // 菜单类型,main(主表)
 */
export function getSettingForm (setting, usefulFields = [], MenuID, primaryKey, columns, type) {
  let str = '^(' + usefulFields.join('|') + ')'
@@ -237,8 +241,9 @@
/**
 * @description 获取树形页面设置表单配置信息
 * @param {object} setting   // 菜单全局设置信息
 * @param {string} type      // 菜单类型
 * @param {object} setting       // 菜单全局设置信息
 * @param {array}  usefulFields  // 可用开始字符
 * @param {string} MenuID        // 菜单ID
 */
export function getTreeSettingForm (setting, usefulFields = [], MenuID) {
  let str = '^(' + usefulFields.join('|') + ')'
@@ -1505,6 +1510,7 @@
 * @description 获取图表视图外部配置表单
 * @param {object} card       // 搜索条件对象
 * @param {Array}  roleList   // 角色列表-黑名单
 * @param {Array}  columns    // 显示列
 */
export function getChartViewForm (card, roleList = [], _columns) {
  let _charts = [{
@@ -1931,7 +1937,6 @@
      label: '重复数据',
      initVal: card.repeat || 'unrepeat',
      required: false,
      // forbid: !['bar', 'pie', 'line'].includes(card.chartType),
      options: [{
        value: 'unrepeat',
        text: '去重'
@@ -2367,7 +2372,12 @@
/**
 * @description 获取子菜单基本信息表单配置信息
 * @param {object} card  // 标签配置信息
 * @param {object} card      // 标签配置信息
 * @param {string} supMenu   // 上级菜单ID
 * @param {array}  menus     // 可选的上级菜单列表
 * @param {array}  equalTab  // 同级菜单IDs
 * @param {array}  equalTabs // 可选的同级菜单列表
 * @param {string} type      // 菜单类型,主表或树形结构
 */
export function getTabForm (card, supMenu, menus, equalTab, equalTabs, type) {
  return [
@@ -2477,7 +2487,11 @@
/**
 * @description 获取卡片详情表单配置信息
 * @param {object} card  // 标签配置信息
 * @param {object}  card        // 标签配置信息
 * @param {array}   _columns    // 显示列
 * @param {string}  _type       // 类型,卡片的部位
 * @param {array}   _actions    // 按钮列表
 * @param {boolean} isRatioCard // 表格宽度类型,是否为比例
 */
export function getCardDetailForm (card, _columns, _type, _actions = [], isRatioCard) {
  let actions = ''
@@ -2716,7 +2730,6 @@
        value: 'all',
        text: '全部'
      }]
    },
    }
  ]
}
src/views/login/index.jsx
@@ -1,4 +1,4 @@
import React, {Component} from 'react'
import React, { Component } from 'react'
import { message, Modal } from 'antd'
import { connect } from 'react-redux'
import md5 from 'md5'
src/views/mobdesign/index.jsx
@@ -1,27 +1,34 @@
import React, {Component} from 'react'
import {connect} from 'react-redux'
import { Icon } from 'antd'
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Icon, Tabs } from 'antd'
import zhCN from '@/locales/zh-CN/login.js'
import enUS from '@/locales/en-US/login.js'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { TabPane } = Tabs
const Header = asyncComponent(() => import('@/mob/header'))
const Home = asyncComponent(() => import('@/mob/home'))
const Login = asyncComponent(() => import('@/mob/login'))
const MobShell = asyncComponent(() => import('@/mob/mobshell'))
const SourceWrap = asyncComponent(() => import('@/mob/modelsource'))
const DataSource = asyncComponent(() => import('@/mob/datasource'))
class Mobile extends Component {
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    view: null
    appId: this.props.match.params.appId,
    appType: this.props.match.params.appType,
    saveIng: false,
    config: null
  }
  UNSAFE_componentWillMount() {
    this.setState({
      view: {uuid: 'login', type: 'home', parentId: null, parentType: null}
    })
    this.getPageParam(this.props.match.params.appId)
  }
  /**
@@ -33,31 +40,64 @@
    }
  }
  jumpToManage = () => {
    this.props.history.replace('/mobmanage')
    // this.props.history.push('/mobdesign/sdafadjfidsf/dsfsdf')
  }
  triggerSave = () => {
    this.setState({
      saveIng: true
    })
  }
  getPageParam = (id) => {
    Api.getSystemConfig({
      func: 'sPC_Get_LongParam',
      MenuID: id
    }).then(result => {
    })
  }
  updateConfig = () => {
  }
  render () {
    const { view } = this.state
    const { saveIng, appType, config } = this.state
    return (
      <div className="mobile-view">
        <Header />
        <div className="mob-body">
          <div className="mob-tool">
            <div className="mob-tool-content">
              <div className="plus-content">
                <Icon type="plus-circle" />添 加 内 容
        <Header view="design" jumpToManage={this.jumpToManage} triggerSave={this.triggerSave} saveIng={saveIng} />
        <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>
              </div>
              <div className="useable-component"></div>
              <div className="mob-tool-other"></div>
            </div>
            <div className="mob-tool-other"></div>
            <div className="mob-shell">
              <MobShell />
            </div>
            <div className="mob-setting">
              <Tabs defaultActiveKey="2" animated={false} size="small">
                <TabPane tab="配置" key="1">
                  Content of Tab Pane 1
                </TabPane>
                <TabPane tab="数据源" key="2">
                  <DataSource config={config} updateConfig={this.updateConfig} />
                </TabPane>
              </Tabs>
            </div>
          </div>
          <div className="mob-shell">
            {view ? <div className="mob-shell-inner">
              {view.type === 'login' ? <Login /> : null}
              {view.type === 'home' ? <Home /> : null}
            </div> : null}
          </div>
          <div className="mob-setting">
          </div>
        </div>
        </DndProvider>
      </div>
    )
  }
src/views/mobdesign/index.scss
@@ -38,13 +38,14 @@
        .useable-component {
          position: absolute;
          width: 300px;
          width: 305px;
          top: 0;
          bottom: 0;
          left: -340px;
          background: #fff;
          opacity: 0;
          transition: left 0.3s, opacity 0.3s;
          transition: left 0.3s linear 0.1s, opacity 0.3s linear 0.1s;
          overflow-y: auto;
        }
      }
      .mob-tool-content:hover {
@@ -67,7 +68,7 @@
      top: 0;
      height: 100%;
      width: 300px;
      background: #262626;
      background: #ffffff;
      box-shadow: 0px 2px 2px #000;
    }
src/views/mobmanage/index.jsx
@@ -15,11 +15,15 @@
    }
  }
  jumpMenu = (card) => {
    this.props.history.replace('/mobdesign/' + card.uuid + '/' + card.type)
  }
  render () {
    return (
      <div className="mobile-manage">
        <Header view="manage" />
        <MobCard />
        <MobCard jumpMenu={this.jumpMenu}/>
      </div>
    )
  }
src/views/mobmanage/index.scss
@@ -1,4 +1,4 @@
.mobile-manage {
  background: #fff;
  min-height: 100vh;
}