king
2023-10-18 6781ba45775af16872ac68f7e459b1072b16c4cc
Merge branch 'master' into positec
73个文件已修改
4个文件已添加
4个文件已删除
4699 ■■■■■ 已修改文件
src/assets/css/main.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/prop-card/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/actionform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/formconfig.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.jsx 72 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/options.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/index.jsx 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.jsx 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/markcomponent/index.jsx 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/pastecomponent/index.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/sourcecomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/sourcecomponent/inputform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/sourcecomponent/inputform/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/editColumn/formconfig.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/index.jsx 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/index.scss 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.jsx 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/debug/index.jsx 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.jsx 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.scss 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulecell/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/sysinterface/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/index.jsx 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/index.jsx 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/nodeupdate/memberform.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/simple-form/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/account/index.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/exceloutbutton/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/index.scss 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx 372 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkPopSelect/index.scss 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/topSearch/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/card.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.jsx 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.jsx 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 350 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/datatable/index.jsx 502 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/datatable/index.scss 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/fieldtable/index.jsx 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/fieldtable/index.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 254 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/modaleditable/index.jsx 519 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/modaleditable/index.scss 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/baseform/index.jsx 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-datamanage.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 157 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemproc/proc/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemproc/transfer/index.jsx 289 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemproc/transfer/index.scss 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/source.jsx 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss
@@ -321,6 +321,25 @@
  .ant-modal {
    max-width: 95vw;
    top: 70px;
    .ant-modal-title {
      height: 22px;
      .mk-modal-icon-def {
        margin-right: 10px;
        background: transparent!important;
      }
      .mk-modal-icon-circle {
        display: inline-block;
        border-radius: 30px;
        margin-right: 10px;
        margin-top: -5px;
        color: #ffffff!important;
        width: 30px;
        height: 30px;
        text-align: center;
        line-height: 30px;
      }
    }
  }
  .ant-modal-body {
    max-height: calc(100vh - 205px);
src/menu/components/card/cardcellcomponent/index.jsx
@@ -451,10 +451,7 @@
          } else if (res.class !== cell.class || res.show !== cell.show || !res.style) {
            let cl = res.class.replace('border-', '')
            let style = {}
            if (res.show === 'link' || res.show === 'icon') {
              style.color = color[cl]
              style.backgroundColor = 'transparent'
            } else if (res.class === 'default') {
            if (res.class === 'default') {
              style.color = 'rgba(0, 0, 0, 0.65)'
              style.backgroundColor = '#fff'
              style.borderColor = '#d9d9d9'
src/menu/components/card/prop-card/index.scss
@@ -82,6 +82,7 @@
    color: orange;
    float: right;
    margin: 5px;
    clear: left;
  }
}
.menu-prop-card-edit-box::after {
src/menu/components/form/formaction/actionform/index.jsx
@@ -54,7 +54,7 @@
      shows = ['typeName', 'label', 'actionType']
    } else if (this.record.type === 'next') {
      shows = ['typeName', 'label', 'actionType']
    } else if (this.record.type === 'close') {
    } else if (this.record.type === 'close' || this.record.type === 'reset') {
      shows = ['typeName', 'label']
    } else {
      shows = ['typeName', 'label', 'intertype', 'Ot', 'execSuccess', 'syncComponent', 'anchors', 'linkmenu', 'output', 'reload'] // 选项列表
src/menu/components/form/formaction/formconfig.jsx
@@ -14,6 +14,8 @@
    _type = '下一步'
  } else if (card.type === 'close') {
    _type = '关闭'
  } else if (card.type === 'reset') {
    _type = '重置'
  }
  let menulist = []
src/menu/components/form/formaction/index.jsx
@@ -65,6 +65,8 @@
      group.nextButton.style = style
    } else if (card.type === 'close') {
      group.closeButton.style = style
    } else if (card.type === 'reset') {
      group.resetButton.style = style
    }
    this.props.updateconfig(group)
@@ -148,6 +150,9 @@
      } else if (res.type === 'close') {
        res.enable = group.closeButton.enable || 'true'
        group.closeButton = res
      } else if (res.type === 'reset') {
        res.enable = group.resetButton.enable || 'true'
        group.resetButton = res
      }
      this.setState({
@@ -220,13 +225,21 @@
        } trigger="hover">
          <Button type="link" className="submit mk-primary" onDoubleClick={this.changeMenu} style={resetStyle(group.subButton.style)}>{group.subButton.label}</Button>
        </Popover>
        {group.resetButton && group.resetButton.enable === 'true' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <EditOutlined className="edit" title="编辑" onClick={() => this.handleAction(group.resetButton)} />
            <FontColorsOutlined className="style" title="调整样式" onClick={() => this.handleStyle(group.resetButton)}/>
          </div>
        } trigger="hover">
          <Button type="link" className="reset" style={resetStyle(group.resetButton.style)}>{group.resetButton.label}</Button>
        </Popover> : null}
        {group.closeButton && group.closeButton.enable === 'true' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <EditOutlined className="edit" title="编辑" onClick={() => this.handleAction(group.closeButton)} />
            <FontColorsOutlined className="style" title="调整样式" onClick={() => this.handleStyle(group.closeButton)}/>
          </div>
        } trigger="hover">
          <Button type="link" style={resetStyle(group.closeButton.style)}>{group.closeButton.label}</Button>
          <Button type="link" className="reset" style={resetStyle(group.closeButton.style)}>{group.closeButton.label}</Button>
        </Popover> : null}
        {group.nextButton && group.nextButton.enable === 'true' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
src/menu/components/form/formaction/index.scss
@@ -18,4 +18,7 @@
    height: auto;
    right: 0px;
  }
  .reset {
    height: auto;
  }
}
src/menu/components/form/simple-form/index.jsx
@@ -1,10 +1,9 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover, Modal, Button, Switch, notification, message } from 'antd'
import { Popover, Modal, Button, Switch, message } from 'antd'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { getModalForm } from '@/templates/zshare/formconfig'
@@ -399,68 +398,33 @@
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.card).toJS()
      let fieldrepet = false // 字段重复
    let _config = fromJS(this.state.card).toJS()
    this.formRef.handleConfirm(_config.subcards[0].fields).then(res => {
      _config.subcards[0].fields = _config.subcards[0].fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
        delete item.focus
        if (item.uuid === res.uuid) {
          if (item.style) {
            res.style = item.style
          }
          return res
        if (item.uuid === res.values.uuid) {
          return res.values
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      window.GLOB.formId = res.uuid
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (res.loading) {
        this.setState({
          sqlVerifing: true
        })
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'1949-10-01 15:00:00'`)
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
              editform: null,
              visible: false
            })
            this.updateComponent(_config)
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        res.promise().then(() => {
          this.setState({
            sqlVerifing: false,
            editform: null,
            visible: false
          })
          this.updateComponent(_config)
        }, () => {
          this.setState({sqlVerifing: false})
        })
      } else {
        this.setState({
@@ -523,6 +487,7 @@
    res.enable = buttons.includes('enable') ? 'true' : 'false'
    res.closeEnable = buttons.includes('closeEnable') ? 'true' : 'false'
    res.resetEnable = buttons.includes('resetEnable') ? 'true' : 'false'
    _card.wrap = res
@@ -546,6 +511,11 @@
    } else if (_card.subcards[0].closeButton) {
      _card.subcards[0].closeButton.enable = _card.wrap.closeEnable
    }
    if (_card.wrap.resetEnable === 'true' && !_card.subcards[0].resetButton) {
      _card.subcards[0].resetButton = {label: '重置', enable: 'true', type: 'reset', style: {backgroundColor: '#ffffff', color: 'rgba(0,0,0,0.65)', borderColor: '#d9d9d9', borderWidth: '1px', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px', marginLeft: '10px'}}
    } else if (_card.subcards[0].resetButton) {
      _card.subcards[0].resetButton.enable = _card.wrap.resetEnable
    }
    this.updateComponent(_card)
  }
src/menu/components/form/simple-form/options.jsx
@@ -53,6 +53,9 @@
  if (wrap.closeEnable === 'true') {
    buttons.push('closeEnable')
  }
  if (wrap.resetEnable === 'true') {
    buttons.push('resetEnable')
  }
  const wrapForm = [
    {
@@ -152,6 +155,7 @@
      required: false,
      options: [
        {value: 'enable', label: '提交'},
        {value: 'resetEnable', label: '重置'},
        {value: 'closeEnable', label: '关闭'},
      ],
    },
src/menu/components/form/step-form/index.jsx
@@ -4,7 +4,6 @@
import { Popover, Modal, Button, Switch, notification, message } from 'antd'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { getModalForm } from '@/templates/zshare/formconfig'
@@ -501,68 +500,33 @@
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.group).toJS()
      let fieldrepet = false // 字段重复
    let _config = fromJS(this.state.group).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
        delete item.focus
        if (item.uuid === res.uuid) {
          if (item.style) {
            res.style = item.style
          }
          return res
        if (item.uuid === res.values.uuid) {
          return res.values
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      window.GLOB.formId = res.uuid
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (res.loading) {
        this.setState({
          sqlVerifing: true
        })
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'1949-10-01 15:00:00'`)
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
              editform: null,
              visible: false
            })
            this.updateGroup(_config)
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        res.promise().then(() => {
          this.setState({
            sqlVerifing: false,
            editform: null,
            visible: false
          })
          this.updateGroup(_config)
        }, () => {
          this.setState({sqlVerifing: false})
        })
      } else {
        this.setState({
src/menu/components/form/tab-form/index.jsx
@@ -4,7 +4,6 @@
import { Popover, Modal, Button, Switch, notification, message } from 'antd'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { getModalForm } from '@/templates/zshare/formconfig'
@@ -506,68 +505,33 @@
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.group).toJS()
      let fieldrepet = false // 字段重复
    let _config = fromJS(this.state.group).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
        delete item.focus
        if (item.uuid === res.uuid) {
          if (item.style) {
            res.style = item.style
          }
          return res
        if (item.uuid === res.values.uuid) {
          return res.values
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      window.GLOB.formId = res.uuid
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (res.loading) {
        this.setState({
          sqlVerifing: true
        })
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'1949-10-01 15:00:00'`)
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
              editform: null,
              visible: false
            })
            this.updateGroup(_config)
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        res.promise().then(() => {
          this.setState({
            sqlVerifing: false,
            editform: null,
            visible: false
          })
          this.updateGroup(_config)
        }, () => {
          this.setState({sqlVerifing: false})
        })
      } else {
        this.setState({
src/menu/components/share/actioncomponent/index.jsx
@@ -407,10 +407,11 @@
            btn.style = item.style || {}
            if (btn.class) {
              if (btn.class !== item.class || btn.show !== item.show || !btn.style.color || (item.focus && !btn.style.color)) {
                if (btn.show === 'icon') {
                  btn.style.color = color[btn.class]
                  btn.style.backgroundColor = 'transparent'
                } else if (btn.class === 'default') {
                // if (btn.show === 'icon') {
                //   btn.style.color = color[btn.class]
                //   btn.style.backgroundColor = 'transparent'
                // }
                if (btn.class === 'default') {
                  btn.style.color = 'rgba(0, 0, 0, 0.65)'
                  btn.style.backgroundColor = '#fff'
                  btn.style.borderColor = '#d9d9d9'
@@ -419,6 +420,7 @@
                  btn.style.color = color[_c]
                  btn.style.backgroundColor = '#fff'
                  btn.style.borderColor = color[_c]
                  btn.style.borderWidth = '1px'
                } else if (btn.class === 'gray') {
                  btn.style.color = 'rgba(0, 0, 0, 0.65)'
                  btn.style.backgroundColor = color[btn.class]
src/menu/components/share/markcomponent/index.jsx
@@ -118,7 +118,21 @@
            'line-through': '中划线',
            'icon': '图标',
            'iconfront': '图标',
            'iconback': '图标',
            'iconback': '图标'
          }
          if (text[0] === 'indent') {
            return (
              <div>缩进/{text[1]}个字符</div>
            )
          } else if (text[0] === 'pointfront') {
            return (
              <div><span style={{display: 'inline-block', width: '8px', height: '8px', borderRadius: '14px', background: 'black', verticalAlign: 'middle'}}></span> 点(前)</div>
            )
          } else if (text[0] === 'pointback') {
            return (
              <div>点(后) <span style={{display: 'inline-block', width: '8px', height: '8px', borderRadius: '14px', background: 'black', verticalAlign: 'middle'}}></span></div>
            )
          }
          return (
@@ -249,6 +263,7 @@
        })
      }
    ]
    let signs = [
      {
        value: 'font',
@@ -267,6 +282,14 @@
        label: '中划线'
      },
      {
        value: 'pointfront',
        label: '点(前)'
      },
      {
        value: 'pointback',
        label: '点(后)'
      },
      {
        value: 'iconfront',
        label: '图标(前)',
        children: icons
@@ -275,12 +298,32 @@
        value: 'iconback',
        label: '图标(后)',
        children: icons
      },
      {
        value: 'indent',
        label: '缩进',
        children: [{
          value: 2,
          label: '2个字符'
        }, {
          value: 4,
          label: '4个字符'
        }, {
          value: 6,
          label: '6个字符'
        }, {
          value: 8,
          label: '8个字符'
        }]
      }
    ]
    if (type === 'line' || type === 'sequence') {
      signs.pop()
      signs.pop()
      signs.pop()
      signs.pop()
      signs.pop()
    } else if (type === 'slider') {
      markColumns = markColumns.filter(col => {
        col.width = '20%'
src/menu/components/share/pastecomponent/index.jsx
@@ -170,11 +170,23 @@
        let keys = config.cols.map(col => (col.field || '$empty'))
        let cols = []
        res.cols.forEach(col => {
          if (!keys.includes(col.field)) {
            config.cols.push(col)
          if (!col.field || !keys.includes(col.field)) {
            cols.push(col)
          }
        })
        if (cols.length === 0) {
          notification.warning({
            top: 92,
            message: '显示列已存在!',
            duration: 5
          })
          return
        } else {
          config.cols.push(...cols)
        }
      }
      this.props.updateConfig(config, type)
src/menu/components/share/sourcecomponent/index.jsx
@@ -88,7 +88,7 @@
        </div> : null}
        <Modal
          visible={!!visible}
          width={visible !== 'system' ? 600 : 1000}
          width={visible !== 'system' ? 650 : 1000}
          closable={false}
          maskClosable={false}
          okText="确定"
src/menu/components/share/sourcecomponent/inputform/index.jsx
@@ -174,7 +174,7 @@
    
    return (
      <div className="mk-source-pop-wrap">
        {keyword === 'input' ? <Form.Item label="地址" labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={{xs: { span: 24 }, sm: { span: 20 }}}>
        {keyword === 'input' ? <Form.Item label="地址" help="可使用@mywebsite@代替域名(含虚拟目录),如:@mywebsite@/Content/images/xxx.jpg" labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={{xs: { span: 24 }, sm: { span: 20 }}}>
          <TextArea id="source-input" value={url} rows={4} onChange={this.changeValue}/>
        </Form.Item> : null}
        {keyword === 'upload' ? <Form.Item label="上传" labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={{xs: { span: 24 }, sm: { span: 20 }}}>
src/menu/components/share/sourcecomponent/inputform/index.scss
@@ -50,6 +50,10 @@
    position: relative;
    top: -15px;
  }
  .ant-form-explain {
    margin-top: 5px;
    word-break: break-all;
  }
}
.picture-edit-model {
  .ant-modal {
src/menu/components/table/base-table/columns/editColumn/formconfig.jsx
@@ -33,6 +33,12 @@
    value: 'number',
    text: '数字'
  }, {
    value: 'custom',
    text: '自定义列'
  }, {
    value: 'formula',
    text: '公式'
  }, {
    value: 'picture',
    text: '图片'
  }, {
@@ -45,14 +51,8 @@
    value: 'textarea',
    text: '多行文本'
  }, {
    value: 'custom',
    text: '自定义列'
  }, {
    value: 'colspan',
    text: '合并列'
  }, {
    value: 'formula',
    text: '公式'
  }, {
    value: 'index',
    text: '序号'
src/menu/components/table/base-table/columns/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Popover, Modal, message, notification } from 'antd'
import { Table, Popover, Modal, message, notification, Typography } from 'antd'
import { PlusOutlined, PlusSquareOutlined, EditOutlined, CopyOutlined, DeleteOutlined, FontColorsOutlined, CloseCircleOutlined, AntDesignOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
@@ -12,6 +12,7 @@
import './index.scss'
const { confirm } = Modal
const { Paragraph } = Typography
const EditColumn = asyncComponent(() => import('./editColumn'))
const MarkColumn = asyncIconComponent(() => import('@/menu/components/share/markcomponent'))
const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
@@ -199,7 +200,7 @@
      }
      return (
        <td style={{...style}} className={className}>
          {val}
          {column.field ? <Paragraph className="col-copy" copyable={{ text: column.field }}>{val}</Paragraph> : val}
          {column.Hide === 'true' ? <CloseCircleOutlined style={{marginLeft: '5px', color: 'orange', fontSize: '12px'}}/> : null}
          {column.marks && column.marks.length ? <AntDesignOutlined className="profile"/> : null}
        </td>
src/menu/components/table/base-table/columns/index.scss
@@ -23,6 +23,25 @@
    tr {
      td {
        background: #ffffff;
        .col-copy {
          margin-bottom: 0;
          display: inline-block;
          color: inherit;
          .ant-typography-copy {
            position: absolute;
            left: 2px;
            top: 0px;
            margin-left: 0px;
            font-size: 12px;
            opacity: 0;
            transition: opacity 0.2s;
          }
        }
      }
      td:hover .col-copy {
        .ant-typography-copy {
          opacity: 1;
        }
      }
      td:not(.ant-table-selection-column) {
        position: relative;
src/menu/components/table/base-table/index.scss
@@ -47,6 +47,9 @@
      padding-top: 10px;
      min-height: 55px;
    }
    button {
      min-width: 60px;
    }
  }
  .model-menu-action-list:not(.length0):not(.length1):not(.length2):not(.length3):not(.length4):not(.length5):not(.length6):not(.length7):not(.length8):not(.length9) {
    margin-bottom: 20px;
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -25,18 +25,18 @@
    value: 'number',
    text: '数字'
  }, {
    value: 'textarea',
    text: '多行文本'
  }, {
    value: 'custom',
    text: '自定义列'
  }, {
    value: 'colspan',
    text: '合并列'
  }, {
    value: 'formula',
    text: '公式'
  }, {
    value: 'textarea',
    text: '多行文本'
  }, {
    value: 'colspan',
    text: '合并列'
  }, {
    value: 'index',
    text: '序号'
  }]
src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -382,8 +382,19 @@
        className = 'text-area'
        let linkSubFields = this.record.linkSubField || []
        let columns = []
        columns.push({ title: 'Value', key: 'Value', strict: true })
        columns.push({ title: 'Text', key: 'Text' })
        linkSubFields.forEach(field => {
          if (field === 'Value' || field === 'Text') return
          columns.push({ title: transfield[field] || field, key: field })
        })
      
        content = <EditTable type={'select'} module="form" transfield={transfield} linkSubFields={linkSubFields} onChange={this.changeOptions}/>
        content = <EditTable columns={columns} module="form" onChange={this.changeOptions}/>
      }
      fields.push(
@@ -403,6 +414,29 @@
      )
    })
    return fields
  }
  transfer = (options) => {
    if (options.length === 0) return options
    let isNumber = true
    options.forEach(item => {
      if (!item.Value || isNaN(item.Value)) {
        isNumber = false
      }
    })
    if (isNumber) {
      return options.map(item => {
        item.Value = +item.Value
        return item
      })
    } else {
      return options.map(item => {
        item.Value = item.Value + ''
        return item
      })
    }
  }
  handleSubmit = () => {
@@ -431,6 +465,32 @@
          cols.forEach(col => {
            values.formula = values.formula.replace(col.reg, col.value)
          })
        } else if (values.type === 'text' && values.editable === 'true' && values.editType === 'select') {
          if (values.resourceType === '0') {
            values.options = values.options || []
            values.options = this.transfer(values.options)
            if (values.options.filter(op => op.Text === '').length > 0) {
              notification.warning({
                top: 92,
                message: '提示文本(Text)不可为空!',
                duration: 5
              })
              return
            } else {
              let arr = values.options.map(m => m.Value)
              let _arr = Array.from(new Set(arr))
              if (arr.length > _arr.length) {
                notification.warning({
                  top: 92,
                  message: 'Value值不可重复!',
                  duration: 5
                })
                return
              }
            }
          }
        }
        if (values.dataSource && /\s/.test(values.dataSource)) {
src/menu/components/table/edit-table/index.scss
@@ -6,7 +6,7 @@
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 100px;
  .model-table-search-list {
    padding: 10px 0px 15px;
    min-height: 65px;
@@ -73,6 +73,9 @@
      padding-top: 10px;
      min-height: 55px;
    }
    button {
      min-width: 60px;
    }
  }
  .ant-btn.mk-link {
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -40,6 +40,12 @@
    value: 'number',
    text: '数字'
  }, {
    value: 'custom',
    text: '自定义列'
  }, {
    value: 'formula',
    text: '公式'
  }, {
    value: 'picture',
    text: '图片'
  }, {
@@ -52,14 +58,8 @@
    value: 'textarea',
    text: '多行文本'
  }, {
    value: 'custom',
    text: '自定义列'
  }, {
    value: 'colspan',
    text: '合并列'
  }, {
    value: 'formula',
    text: '公式'
  }, {
    value: 'index',
    text: '序号'
src/menu/components/table/normal-table/columns/index.jsx
@@ -12,7 +12,7 @@
import './index.scss'
const { confirm } = Modal
const { Paragraph } = Typography
const { Paragraph } = Typography
const EditColumn = asyncComponent(() => import('./editColumn'))
const MarkColumn = asyncIconComponent(() => import('@/menu/components/share/markcomponent'))
const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
@@ -35,6 +35,32 @@
  updateMarks = (vals) => {
    const { column } = this.props
    this.props.updateCol({...column, marks: vals})
  }
  copycolumn = () => {
    const { column } = this.props
    let oInput = document.createElement('input')
    let val = {
      copyType: 'cols',
      cols: [column]
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
    document.body.appendChild(oInput)
    oInput.select()
    document.execCommand('Copy')
    oInput.className = 'oInput'
    oInput.style.display = 'none'
    message.success('复制成功。')
    document.body.removeChild(oInput)
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -76,6 +102,7 @@
            {column.type === 'custom' ? <PlusOutlined className="plus" title="添加元素" onClick={() => this.props.addElement(column)} /> : null}
            {column.type === 'custom' ? <PlusSquareOutlined className="plus" title="添加按钮" onClick={() => this.props.addElement(column, 'button')} /> : null}
            <EditOutlined className="edit" title="编辑" onClick={() => this.props.editColumn(column)} />
            <CopyOutlined title="复制显示列" style={{color: '#26C281'}} onClick={this.copycolumn} />
            {column.type === 'custom' ? <PasteComponent options={['customCardElement', 'action']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
            {column.type === 'custom' ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
            <DeleteOutlined className="close" title="删除" onClick={this.deleteCol} />
@@ -597,6 +624,12 @@
    })
  }
  addColumns = () => {
    const { config } = this.props
    MKEmitter.emit('addColumns', config.uuid)
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
@@ -623,6 +656,7 @@
    return (
      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''} table-col-${columns.length}`} id={tableId}>
        <div className="col-control">
          <PlusOutlined style={{color: '#26C281'}} title="添加列" onClick={this.addColumns}/>
          <CopyOutlined title="复制显示列" onClick={this.copycolumn} />
          <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
          <FileSyncOutlined title="同步字段集" onClick={this.syncfield} />
src/menu/components/table/normal-table/index.jsx
@@ -92,6 +92,7 @@
  componentDidMount () {
    MKEmitter.addListener('completeSave', this.completeSave)
    MKEmitter.addListener('addColumns', this.addColumns)
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -106,6 +107,7 @@
      return
    }
    MKEmitter.removeListener('completeSave', this.completeSave)
    MKEmitter.removeListener('addColumns', this.addColumns)
  }
  completeSave = () => {
@@ -210,12 +212,16 @@
    this.updateComponent(_card)
  }
  addColumns = () => {
    let card = fromJS(this.state.card).toJS()
  addColumns = (id) => {
    const { card } = this.state
    card.cols.push({ focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' })
    if (id && id !== card.uuid) return
    this.setState({card})
    let _card = fromJS(card).toJS()
    _card.cols.push({ focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' })
    this.setState({card: _card})
  }
  addSearch = () => {
@@ -365,7 +371,7 @@
        <NormalHeader hideSearch="true" config={card} updateComponent={this.updateComponent}/>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <PlusOutlined className="plus" title="添加列" onClick={this.addColumns}/>
            <PlusOutlined className="plus" title="添加列" onClick={() => this.addColumns()}/>
            {appType !== 'mob' ? <PlusCircleOutlined className="plus" title="添加搜索" onClick={this.addSearch}/> : null}
            <PlusSquareOutlined className="plus" title="添加按钮" onClick={this.addButton}/>
            <NormalForm title="表格设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
src/menu/components/table/normal-table/index.scss
@@ -73,6 +73,9 @@
      padding-top: 10px;
      min-height: 55px;
    }
    button {
      min-width: 60px;
    }
  }
  .ant-btn.mk-link {
src/menu/datasource/index.jsx
@@ -157,13 +157,15 @@
      if (res.columns) {
        res.columns = res.columns.map(item => {
          if (/int/ig.test(item.datatype)) {
            item.type = 'number'
            item.decimal = 0
          } else if (/Decimal/ig.test(item.datatype)) {
            item.type = 'number'
            item.decimal = +item.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
          } else if (/^date/ig.test(item.datatype)) {
            item.type = 'text'
            item.fieldlength = 50
          } else {
            item.type = 'text'
            item.fieldlength = +item.datatype.replace(/^Nvarchar\(/ig, '').replace(/\)/ig, '')
@@ -211,6 +213,23 @@
      if (config.subtype !== 'dualdatacard') {
        delete res.subColumns
      } else {
        res.subColumns = res.subColumns.map(item => {
          if (/int/ig.test(item.datatype)) {
            item.type = 'number'
            item.decimal = 0
          } else if (/Decimal/ig.test(item.datatype)) {
            item.type = 'number'
            item.decimal = +item.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
          } else if (/^date/ig.test(item.datatype)) {
            item.type = 'text'
            item.fieldlength = 50
          } else {
            item.type = 'text'
            item.fieldlength = +item.datatype.replace(/^Nvarchar\(/ig, '').replace(/\)/ig, '')
          }
          return item
        })
        res.subColumns.reverse()
      }
src/menu/datasource/verifycard/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Tabs, Popconfirm, notification, Modal, Typography, Spin, message, Button, Input } from 'antd'
import { StopOutlined, CheckCircleOutlined, EditOutlined, SwapOutlined, DeleteOutlined, CopyOutlined, BorderOutlined, SnippetsOutlined } from '@ant-design/icons'
import { StopOutlined, CheckCircleOutlined, TableOutlined, EditOutlined, SwapOutlined, DeleteOutlined, CopyOutlined, BorderOutlined, SnippetsOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
@@ -678,6 +678,55 @@
            resolve()
          })
        } else {
          if (/列名\s*'[a-zA-Z0-9_-]+'\s*无效/.test(result.message)) {
            let tail = ''
            let type = ''
            searches.forEach(item => {
              if (item.forbid) return
              item.key.split(',').forEach(field => {
                if (new RegExp(`'${field}'`).test(result.message)) {
                  tail = field
                  type = '搜索条件'
                }
              })
            })
            if (!tail) {
              let keys = setting.order.replace(/\s+(asc|desc)/ig, '').replace(/\s+/g, '')
              keys.split(',').forEach(field => {
                if (new RegExp(`'${field}'`).test(result.message)) {
                  tail = field
                  type = '排序'
                }
              })
            }
            if (!tail) {
              columns.forEach(item => {
                if (new RegExp(`'${item.field}'`).test(result.message)) {
                  tail = item.field
                  if (config.subtype === 'basetable') {
                    type = '显示列'
                  } else {
                    type = '字段集'
                  }
                }
              })
              if (!tail && config.subtype === 'dualdatacard') {
                subColumns.forEach(item => {
                  if (new RegExp(`'${item.field}'`).test(result.message)) {
                    tail = item.field
                    type = '子表字段集'
                  }
                })
              }
            }
            if (tail) {
              result.message = result.message.replace(/ROLLBACK TRANSACTION 请求没有对应的 BEGIN TRANSACTION。/, '')
              result.message = <>{result.message}<span style={{color: 'red'}}>注:{type}中存在字段{tail}</span></>
            }
          }
          if (type === 'submit') {
            Modal.confirm({
              title: result.message,
@@ -1053,7 +1102,7 @@
            <EditTable actions={['edit', 'move', 'copy', 'del', 'clear']} searchKey={searchKey} type="datasourcefield" wrappedComponentRef={(inst) => this.datasource = inst} data={columns} columns={colColumns} onChange={(columns) => this.setState({columns})}/>
          </TabPane> : <TabPane tab={
            <span>
              字段集
              字段集<TableOutlined style={{marginLeft: '5px', fontSize: '12px'}} />
              {columns.length ? <span className="count-tip">{columns.length}</span> : null}
            </span>
          } key="columns">
@@ -1078,8 +1127,8 @@
            <span>
              自定义脚本
              {scripts.length ? <span className="count-tip">{scripts.length}</span> : null}
              {config.type !== 'interface' && activeKey === 'setting' ? <CopyOutlined title="复制数据源" className="mk-copy-datasource" onClick={(e) => {e.stopPropagation();this.copyDatasource()}}/> : null}
              {config.type !== 'interface' && activeKey === 'setting' ? <SnippetsOutlined title="导入数据源" className="mk-paste-datasource" onClick={(e) => {e.stopPropagation();this.setState({pvisible: true})}}/> : null}
              {activeKey === 'setting' ? <CopyOutlined title="复制数据源" className="mk-copy-datasource" onClick={(e) => {e.stopPropagation();this.copyDatasource()}}/> : null}
              {activeKey === 'setting' ? <SnippetsOutlined title="导入数据源" className="mk-paste-datasource" onClick={(e) => {e.stopPropagation();this.setState({pvisible: true})}}/> : null}
              {activeKey === 'columns' ? <CopyOutlined title="以逗号拼接形式复制字段" className="mk-copy-fields" onClick={(e) => {e.stopPropagation();this.copyColumns()}}/> : null}
              {activeKey === 'subcolumns' ? <CopyOutlined title="以逗号拼接形式复制字段" className="mk-copy-fields" onClick={(e) => {e.stopPropagation();this.copySubColumns()}}/> : null}
              {activeKey === 'subcolumns' || activeKey === 'columns' ? <span onClick={(e) => {e.stopPropagation()}}><Search className="mk-search-fields" defaultValue={searchKey} allowClear onSearch={(val, e) => {e.stopPropagation();this.setState({searchKey: val})}} /></span> : null}
src/menu/debug/index.jsx
@@ -315,7 +315,7 @@
  
            card.backElements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              let sql = this.resetButton(item, cell, process)
              let sql = this.resetButton(item, cell, process, null, true)
              if (sql) {
                if (typeof(sql) === 'string') {
@@ -364,11 +364,18 @@
    })
  }
  resetButton = (item, cell, process, group) => {
  resetButton = (item, cell, process, group, isback) => {
    let sql = ''
    if (['exec', 'prompt', 'pop', 'form', 'formSubmit'].includes(cell.OpenType)) {
      if (cell.intertype === 'system' || cell.procMode === 'system') { // 系统接口
        sql = this.getSysDefaultSql(cell, item, process, group)
        if (item.subtype === 'dualdatacard' && isback) {
          let _item = fromJS(item).toJS()
          _item.columns = _item.subColumns || []
          _item.setting.primaryKey = _item.setting.subKey
          sql = this.getSysDefaultSql(cell, _item, process, group)
        } else {
          sql = this.getSysDefaultSql(cell, item, process, group)
        }
      }
    } else if (cell.OpenType === 'excelIn') {
      if (cell.intertype === 'system') {
src/menu/modalconfig/index.jsx
@@ -3,12 +3,10 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Switch, message } from 'antd'
import { Button, Card, Modal, Collapse, Switch, message } from 'antd'
import { SettingOutlined, CopyOutlined } from '@ant-design/icons'
import Api from '@/api'
import { getModalForm } from '@/templates/zshare/formconfig'
import SourceElement from '@/templates/modalconfig/dragelement/source'
import SettingForm from '@/templates/modalconfig/settingform'
import asyncComponent from '@/utils/asyncComponent'
@@ -18,6 +16,8 @@
const { Panel } = Collapse
const { confirm } = Modal
const MkIcon = asyncComponent(() => import('@/components/mk-icon'))
const TableComponent = asyncComponent(() => import('./tablecomponent'))
const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
const PasteForms = asyncComponent(() => import('@/menu/components/share/pasteforms'))
@@ -225,68 +225,33 @@
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.config).toJS()
      let fieldrepet = false // 字段重复
    let _config = fromJS(this.state.config).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
        delete item.focus
        if (item.uuid === res.uuid) {
          if (item.style) {
            res.style = item.style
          }
          return res
        if (item.uuid === res.values.uuid) {
          return res.values
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      window.GLOB.formId = res.uuid
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (res.loading) {
        this.setState({
          sqlVerifing: true
        })
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'1949-10-01 15:00:00'`)
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
              config: _config,
              card: null,
              visible: false
            })
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        res.promise().then(() => {
          this.setState({
            sqlVerifing: false,
            config: _config,
            card: null,
            visible: false
          })
        }, () => {
          this.setState({sqlVerifing: false})
        })
      } else {
        this.setState({
@@ -538,7 +503,7 @@
              <SettingOutlined onClick={this.changeSetting} />
              <div className="ant-modal-content" style={{width: config.setting.width > 100 ? config.setting.width : config.setting.width + '%'}}>
                <div className="ant-modal-header">
                  <div className="ant-modal-title">{btn.label}</div>
                  <div className="ant-modal-title">{config.setting.icon ? <span className={'mk-modal-icon-' + config.setting.iconType} style={{background: config.setting.iconColor || 'unset', color: config.setting.iconColor || 'inherit'}}><MkIcon type={config.setting.icon}/></span> : null}{btn.label}</div>
                  <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button>
src/menu/modalconfig/index.scss
@@ -120,6 +120,21 @@
          padding-right: 80px;
          .ant-modal-title {
            display: inline-block;
            height: 22px;
            .mk-modal-icon-def {
              margin-right: 10px;
              background: transparent!important;
            }
            .mk-modal-icon-circle {
              display: inline-block;
              border-radius: 30px;
              margin-right: 10px;
              color: #ffffff!important;
              width: 30px;
              height: 30px;
              text-align: center;
              line-height: 30px;
            }
          }
          .anticon-copy {
            position: absolute;
src/menu/modulecell/index.jsx
@@ -93,13 +93,13 @@
        children: [
          { subType: 'text', text: '文本', type: 'col', $init: true },
          { subType: 'number', text: '数字', type: 'col', $init: true },
          { subType: 'custom', text: '自定义列', type: 'col', $init: true },
          { subType: 'formula', text: '公式', type: 'col', $init: true },
          { subType: 'picture', text: '图片', type: 'col', $init: true },
          { subType: 'video', text: '视频', type: 'col', $init: true },
          { subType: 'link', text: '链接', type: 'col', $init: true },
          { subType: 'textarea', text: '多行文本', type: 'col', $init: true },
          { subType: 'custom', text: '自定义列', type: 'col', $init: true },
          { subType: 'colspan', text: '合并列', type: 'col', $init: true },
          { subType: 'formula', text: '公式', type: 'col', $init: true },
          { subType: 'index', text: '序号', type: 'col', $init: true }
        ]
      }
src/menu/sysinterface/index.jsx
@@ -176,7 +176,7 @@
    let trimreg = /(from|update|insert\s+into)\s+(@db@)?/ig
    if (record.setting.interType === 'system') {
      if (record.setting.execute !== 'false') {
      if (record.setting.execute !== 'false' && record.setting.dataresource) {
        let tbs = record.setting.dataresource.match(cutreg)
        tbs && cuts.push(...tbs)
      }
@@ -185,7 +185,7 @@
        let tbs = script.sql.match(cutreg)
        tbs && cuts.push(...tbs)
      })
    } else {
    } else if (record.setting.tableName) {
      let tb = record.setting.tableName.replace(/@db@|\s+/ig, '')
      if (/[a-z_]+/ig.test(tb)) {
        tables.push(tb)
@@ -211,6 +211,8 @@
    record.name = record.setting.name
    record.$tables = this.getTables(record)
    delete record.subColumns
    let interfaces = this.state.interfaces.map(item => {
      if (item.uuid !== record.uuid) {
        return item
src/mob/modalconfig/index.jsx
@@ -3,12 +3,10 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Modal, Collapse, notification, Switch, message } from 'antd'
import { Button, Modal, Collapse, Switch, message } from 'antd'
import { LeftOutlined } from '@ant-design/icons'
import Api from '@/api'
import { getModalForm } from '@/templates/zshare/formconfig'
import SourceElement from '@/templates/modalconfig/dragelement/source'
import SettingForm from '@/templates/modalconfig/settingform'
import asyncComponent from '@/utils/asyncComponent'
@@ -222,68 +220,33 @@
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.config).toJS()
      let fieldrepet = false // 字段重复
    let _config = fromJS(this.state.config).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
        delete item.focus
        if (item.uuid === res.uuid) {
          if (item.style) {
            res.style = item.style
          }
          return res
        if (item.uuid === res.values.uuid) {
          return res.values
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      window.GLOB.formId = res.uuid
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (res.loading) {
        this.setState({
          sqlVerifing: true
        })
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'1949-10-01 15:00:00'`)
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
              config: _config,
              card: null,
              visible: false
            })
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        res.promise().then(() => {
          this.setState({
            sqlVerifing: false,
            config: _config,
            card: null,
            visible: false
          })
        }, () => {
          this.setState({sqlVerifing: false})
        })
      } else {
        this.setState({
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -426,6 +426,14 @@
            } else {
              val = <span>{val} <MkIcon style={mark.innerStyle} type={mark.icon} /></span>
            }
          } else if (mark.space) {
            val = <><span style={{float: 'left'}} dangerouslySetInnerHTML={{__html: mark.space}}></span>{val}</>
          } else if (mark.point) {
            if (mark.position === 'front') {
              val = <>{mark.point}{val}</>
            } else {
              val = <>{val}{mark.point}</>
            }
          }
          className = mark.signType
        }
@@ -507,6 +515,14 @@
              val = <span><MkIcon style={mark.innerStyle} type={mark.icon} /> {val}</span>
            } else {
              val = <span>{val} <MkIcon style={mark.innerStyle} type={mark.icon} /></span>
            }
          } else if (mark.space) {
            val = <><span style={{float: 'left'}} dangerouslySetInnerHTML={{__html: mark.space}}></span>{val}</>
          } else if (mark.point) {
            if (mark.position === 'front') {
              val = <>{mark.point}{val}</>
            } else {
              val = <>{val}{mark.point}</>
            }
          }
          className = mark.signType
@@ -774,9 +790,7 @@
            let func = new Function('data', card.formula)
            val = func(_data)
          } catch (e) {
            if (window.GLOB.debugger === true) {
              console.warn(e)
            }
            console.warn(e)
            val = ''
          }
        } else if (card.$sync) {
@@ -794,10 +808,8 @@
                // eslint-disable-next-line
                _val = eval(_val)
              } catch (e) {
                if (window.GLOB.debugger === true) {
                  console.info(_val)
                  console.warn(e)
                }
                console.info(_val)
                console.warn(e)
                _val = 0
              }
            }
@@ -820,10 +832,8 @@
              // eslint-disable-next-line
              _val = eval(_val)
            } catch (e) {
              if (window.GLOB.debugger === true) {
                console.info(_val)
                console.warn(e)
              }
              console.info(_val)
              console.warn(e)
              _val = ''
            }
          }
@@ -882,6 +892,14 @@
            } else {
              val = <span>{val} <MkIcon style={mark.innerStyle} type={mark.icon} /></span>
            }
          } else if (mark.space) {
            val = <><span style={{float: 'left'}} dangerouslySetInnerHTML={{__html: mark.space}}></span>{val}</>
          } else if (mark.point) {
            if (mark.position === 'front') {
              val = <>{mark.point}{val}</>
            } else {
              val = <>{val}{mark.point}</>
            }
          }
          className = mark.signType
        }
src/tabviews/custom/components/chart/antv-X6/index.jsx
@@ -989,7 +989,7 @@
    })
    graph.on('edge:click', ({ edge }) => {
      this.selectNode = edge
      this.setState({node: edge.store.data})
      graph.clearTransformWidgets()
@@ -1561,19 +1561,41 @@
      let start_num = 0
      let end_num = 0
      let unvalid = false
      let map = new Map()
      let appMap = new Map()
      
      nodes.cells.forEach(item => {
        if (item.mknode === 'start') {
        if (item.shape === 'mk-text' || item.shape === 'lane') return
        if (!item.mkdata) {
          unvalid = true
        } else if (item.mknode === 'start') {
          start_num++
        } else if (item.mknode === 'end') {
          end_num++
        } else if (item.shape === 'edge' && item.mknode !== 'endEdge' && item.mknode !== 'startEdge') {
          if (!item.mkdata.members || item.mkdata.members.length === 0) {
        } else if (item.shape === 'edge') {
          if (item.mknode !== 'endEdge' && item.mknode !== 'startEdge' && (!item.mkdata.members || item.mkdata.members.length === 0)) {
            unvalid = true
          } else if (item.mknode === 'startEdge' || item.mkdata.flowType === 'reject') {
            if (map.has(item.source.cell)) {
              unvalid = true
            } else {
              map.set(item.source.cell, true)
            }
          } else if (item.mkdata.flowType === 'approval' || item.mknode === 'endEdge') {
            let val = ''
            if (item.mkdata.execCondition === 'open') {
              val = item.mkdata.match + item.mkdata.matchVal
            }
            if (appMap.has(item.source.cell + val)) {
              unvalid = true
            } else {
              appMap.set(item.source.cell + val, true)
            }
          }
        }
      })
      if (start_num !== 1 || end_num !== 1 || unvalid) {
        _status = 0
      }
@@ -1993,15 +2015,49 @@
      let start_num = 0
      let end_num = 0
      let unvalidId = ''
      let emptyNode = null
      let emptyEdge = null
      let map = new Map()
      let appMap = new Map()
      let rejectId = ''
      let approvalId = ''
      nodes.cells.forEach(item => {
        if (item.mknode === 'start') {
        if (item.shape === 'mk-text' || item.shape === 'lane') return
        if (!item.mkdata) {
          if (item.shape !== 'edge') {
            if (!emptyNode) {
              emptyNode = item
            }
          } else {
            if (!emptyEdge) {
              emptyEdge = item
            }
          }
        } else if (item.mknode === 'start') {
          start_num++
        } else if (item.mknode === 'end') {
          end_num++
        } else if (item.shape === 'edge' && item.mknode !== 'endEdge' && item.mknode !== 'startEdge') {
          if (!item.mkdata.members || item.mkdata.members.length === 0) {
        } else if (item.shape === 'edge' && !unvalidId && !rejectId && !approvalId) {
          if (item.mknode !== 'endEdge' && item.mknode !== 'startEdge' && (!item.mkdata.members || item.mkdata.members.length === 0)) {
            unvalidId = item.id
          } else if (item.mknode === 'startEdge' || item.mkdata.flowType === 'reject') {
            if (map.has(item.source.cell)) {
              rejectId = item.source.cell
            } else {
              map.set(item.source.cell, true)
            }
          } else if (item.mkdata.flowType === 'approval' || item.mknode === 'endEdge') {
            let val = ''
            if (item.mkdata.execCondition === 'open') {
              val = item.mkdata.match + item.mkdata.matchVal
            }
            if (appMap.has(item.source.cell + val)) {
              approvalId = item.source.cell
            } else {
              appMap.set(item.source.cell + val, item)
            }
          }
        }
      })
@@ -2030,21 +2086,97 @@
          message: '结束节点不可添加多个!',
          duration: 2
        })
      } else if (unvalidId) {
        let edge = this.mkGraph.getCellById(unvalidId)
      } else if (emptyNode) {
        let errmsg = '部分节点未设置基本信息。'
        if (emptyNode.attrs && emptyNode.attrs.text && emptyNode.attrs.text.text) {
          errmsg = '节点《' + emptyNode.attrs.text.text + '》未设置基本信息。'
        }
        notification.warning({
          top: 92,
          message: errmsg,
          duration: 2
        })
      } else if (emptyEdge) {
        let errmsg = '部分连线未设置基本信息。'
        let node = edge.getTargetCell()
        let edge = this.mkGraph.getCellById(emptyEdge.id)
        let target = edge.getTargetCell()
        let t_label = ''
        if (target.attrs && target.attrs.text && target.attrs.text.text) {
          t_label = target.attrs.text.text
        }
        let source = edge.getSourceCell()
        let s_label = ''
        if (source.attrs && source.attrs.text && source.attrs.text.text) {
          s_label = source.attrs.text.text
        }
        if (t_label && s_label) {
          errmsg = '节点《' + s_label + '》与节点《' + t_label + '》间连线未设置基本信息。'
        }
        notification.warning({
          top: 92,
          message: errmsg,
          duration: 2
        })
      } else if (rejectId) {
        let node = this.mkGraph.getCellById(rejectId)
        let title = ''
        if (node.attrs && node.attrs.text) {
          title = node.attrs.text.text + ''
        if (node.attrs && node.attrs.text && node.attrs.text.text) {
          title = '节点《' + node.attrs.text.text + '》'
        } else if (node.mkdata) {
          title = '状态:' + node.mkdata.status + ' - ' + node.mkdata.statusName
        }
        notification.warning({
          top: 92,
          message: '连接(' + title + ')的线未设置审批人!',
          message: title + ' 不可设置两条驳回连线!',
          duration: 2
        })
      } else if (approvalId) {
        let node = this.mkGraph.getCellById(approvalId)
        let title = ''
        if (node.attrs && node.attrs.text && node.attrs.text.text) {
          title = '节点《' + node.attrs.text.text + '》'
        } else if (node.mkdata) {
          title = '状态:' + node.mkdata.status + ' - ' + node.mkdata.statusName
        }
        notification.warning({
          top: 92,
          message: title + ' 后的审批分支执行条件重复!',
          duration: 2
        })
      } else if (unvalidId) {
        let edge = this.mkGraph.getCellById(unvalidId)
        let node = edge.getTargetCell()
        let title = ''
        if (node.attrs && node.attrs.text && node.attrs.text.text) {
          title = node.attrs.text.text
        } else if (node.mkdata) {
          title = '状态:' + node.mkdata.status + ' - ' + node.mkdata.statusName
        }
        let source = edge.getSourceCell()
        let s_label = ''
        if (source.attrs && source.attrs.text && source.attrs.text.text) {
          s_label = source.attrs.text.text
        } else if (source.mkdata) {
          s_label = '状态:' + source.mkdata.status + ' - ' + source.mkdata.statusName
        }
        notification.warning({
          top: 92,
          message: '节点《' + s_label + '》与《' + title + '》间连线未设置审批人!',
          duration: 2
        })
      } else {
src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx
@@ -499,7 +499,7 @@
          visible={visible}
          closable={false}
          maskClosable={false}
          width={1000}
          width={1050}
          onOk={this.confirm}
          onCancel={() => this.setState({visible: false})}
          destroyOnClose
src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss
@@ -130,6 +130,7 @@
    background-image: none;
    border: 1px solid #d9d9d9;
    border-radius: 4px;
    vertical-align: middle;
    .anticon-form {
      float: right;
@@ -170,6 +171,13 @@
      }
    }
  }
  .ant-transfer-operation {
    margin: 0 15px;
    .ant-btn:first-child {
      margin-bottom: 10px;
    }
  }
}
.member-modal {
src/tabviews/custom/components/chart/antv-X6/nodeupdate/memberform.jsx
@@ -175,7 +175,7 @@
    return (
      <>
        <div className="member-input">{value.length}人<FormOutlined onClick={this.trigger} /></div>
        <div className="member-input">{value.length > 0 ? value.length + '人' : ''}<FormOutlined onClick={this.trigger} /></div>
        <Modal
          wrapClassName="member-modal"
          title="选择人员"
src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Radio, Tooltip, InputNumber } from 'antd'
import { Form, Row, Col, Input, Radio, Tooltip, InputNumber, Switch } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import MemberForm from './memberform'
@@ -14,13 +14,23 @@
  }
  state = {
    flowType: this.props.data.flowType || 'approval'
    flowType: this.props.data.flowType || 'approval',
    execCondition: this.props.data.execCondition === 'open',
  }
  handleConfirm = () => {
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          if (values.execCondition === true) {
            values.execCondition = 'open'
          } else if (values.execCondition === false) {
            values.execCondition = 'close'
          }
          if (values.matchVal) {
            values.matchVal = values.matchVal.replace(/\t+|\v+|\s+/g, '')
          }
          resolve(values)
        } else {
          reject(err)
@@ -32,7 +42,7 @@
  render() {
    const { node, orgs } = this.props
    const { getFieldDecorator } = this.props.form
    const { flowType } = this.state
    const { flowType, execCondition } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -155,6 +165,60 @@
              )}
            </Form.Item>
          </Col> : null}
          {nodetype === 'edge' && flowType !== 'reject' ? <Col span={12}>
            <Form.Item label="执行条件">
              {getFieldDecorator('execCondition', {
                valuePropName: 'checked',
                initialValue: execCondition
              })(
                <Switch checkedChildren="开启" unCheckedChildren="关闭" onChange={(val) => this.setState({execCondition: val})} />
              )}
            </Form.Item>
          </Col> : null}
          {nodetype === 'edge' && flowType !== 'reject' && execCondition ? <Col span={12}>
            <Form.Item label="对比方式">
              {getFieldDecorator('match', {
                initialValue: data.match || '='
              })(
                <Radio.Group>
                  <Radio value="=">=</Radio>
                  <Radio value="<">&lt;</Radio>
                  <Radio value=">">&gt;</Radio>
                  <Radio value="<=">&lt;=</Radio>
                  <Radio value=">=">&gt;=</Radio>
                  <Radio value="!=">!=</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
          {nodetype === 'edge' && flowType !== 'reject' && execCondition ? <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对比值中不可包含制表符、空格、换行符等。">
                <QuestionCircleOutlined className="mk-form-tip" />
                对比值
              </Tooltip>
            }>
              {getFieldDecorator('matchVal', {
                initialValue: data.matchVal || ''
              })(
                <Input placeholder="" autoComplete="off"/>
              )}
            </Form.Item>
          </Col> : null}
          {nodetype === 'node' ? <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="标记将作为节点ID">
                <QuestionCircleOutlined className="mk-form-tip" />
                标记
              </Tooltip>
            }>
              {getFieldDecorator('sign', {
                initialValue: data.sign || ''
              })(
                <Input placeholder="" autoComplete="off"/>
              )}
            </Form.Item>
          </Col> : null}
          <Col span={24}>
            <Form.Item label="备注">
              {getFieldDecorator('remark', {
src/tabviews/custom/components/form/simple-form/index.jsx
@@ -63,7 +63,7 @@
    let _group = _config.subcards[0]
    if (_group.subButton.enable === 'false' && (!_group.closeButton || _group.closeButton.enable !== 'true')) {
    if (_group.subButton.enable === 'false' && (!_group.closeButton || _group.closeButton.enable !== 'true') && (!_group.resetButton || _group.resetButton.enable !== 'true')) {
      _group.subButton.style.display = 'none'
      _group.$button = 'no-button'
    }
@@ -318,6 +318,16 @@
    MKEmitter.emit('closeTabView', group.subButton.$MenuID)
  }
  resetTab = () => {
    const { data } = this.state
    this.setState({
      data: null
    }, () => {
      this.setState({data: data})
    })
  }
  render() {
    const { config, loading, BID, BData, data, group } = this.state
@@ -350,6 +360,7 @@
            columns={config.columns}
            selectedData={data.$$empty ? [] : [data]}
          />
          {group.resetButton && group.resetButton.enable === 'true' ? <Button type="link" onClick={this.resetTab} style={group.resetButton.style}>{group.resetButton.label}</Button> : null}
          {group.closeButton && group.closeButton.enable === 'true' ? <Button type="link" onClick={this.closeTab} style={group.closeButton.style}>{group.closeButton.label}</Button> : null}
        </div> : null}
      </div>
src/tabviews/custom/components/module/account/index.jsx
@@ -120,10 +120,12 @@
  }
  setBook = (item, resolve) => {
    const { config } = this.props
    if (!resolve) {
      this.setState({activeItem: item})
  
      MKEmitter.emit('resetSelectLine', this.props.config.uuid, item.id, item)
      MKEmitter.emit('resetSelectLine', config.uuid, item.id, item)
    }
    
    let userid = sessionStorage.getItem('UserID') || ''
@@ -152,6 +154,7 @@
      }
      if (resolve) {
        sessionStorage.setItem('ThirdMenu', config.$pageId)
        window.location.reload()
      }
    })
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -144,6 +144,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
      if (col.blur) {
@@ -208,6 +216,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
@@ -337,9 +353,7 @@
          let func = new Function('data', col.formula)
          content = func([record])
        } catch (e) {
          if (window.GLOB.debugger === true) {
            console.warn(e)
          }
          console.warn(e)
          content = ''
        }
      } else {
@@ -352,10 +366,8 @@
            // eslint-disable-next-line
            content = eval(content)
          } catch (e) {
            if (window.GLOB.debugger === true) {
              console.info(content)
              console.warn(e)
            }
            console.info(content)
            console.warn(e)
            content = ''
          }
  
@@ -389,6 +401,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -309,6 +309,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
@@ -397,6 +405,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
@@ -441,9 +457,7 @@
          let func = new Function('data', col.formula)
          content = func([record])
        } catch (e) {
          if (window.GLOB.debugger === true) {
            console.warn(e)
          }
          console.warn(e)
          content = ''
        }
      } else {
@@ -457,10 +471,8 @@
            // eslint-disable-next-line
            content = eval(content)
          } catch (e) {
            if (window.GLOB.debugger === true) {
              console.info(content)
              console.warn(e)
            }
            console.info(content)
            console.warn(e)
            content = ''
          }
        }
@@ -498,6 +510,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
@@ -750,6 +770,14 @@
            }
          } else if (mark.innerStyle) {
            content = <span style={mark.innerStyle}>{content}</span>
          } else if (mark.space) {
            content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
          } else if (mark.point) {
            if (mark.position === 'front') {
              content = <>{mark.point}{content}</>
            } else {
              content = <>{content}{mark.point}</>
            }
          }
        }
@@ -817,6 +845,14 @@
            }
          } else if (mark.innerStyle) {
            content = <span style={mark.innerStyle}>{content}</span>
          } else if (mark.space) {
            content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
          } else if (mark.point) {
            if (mark.position === 'front') {
              content = <>{mark.point}{content}</>
            } else {
              content = <>{content}{mark.point}</>
            }
          }
        }
@@ -850,9 +886,7 @@
          let func = new Function('data', col.formula)
          content = func([record])
        } catch (e) {
          if (window.GLOB.debugger === true) {
            console.warn(e)
          }
          console.warn(e)
          content = ''
        }
      } else {
@@ -866,10 +900,8 @@
            // eslint-disable-next-line
            content = eval(content)
          } catch (e) {
            if (window.GLOB.debugger === true) {
              console.info(content)
              console.warn(e)
            }
            console.info(content)
            console.warn(e)
            content = ''
          }
        }
@@ -907,6 +939,14 @@
          }
        } else if (mark.innerStyle) {
          content = <span style={mark.innerStyle}>{content}</span>
        } else if (mark.space) {
          content = <><span dangerouslySetInnerHTML={{__html: mark.space}}></span>{content}</>
        } else if (mark.point) {
          if (mark.position === 'front') {
            content = <>{mark.point}{content}</>
          } else {
            content = <>{content}{mark.point}</>
          }
        }
      }
src/tabviews/custom/index.jsx
@@ -238,6 +238,15 @@
      config.$cache = config.cacheLocal === 'true'
      config.$time = config.localCacheTime || 0
      if (window.GLOB.systemType !== 'production' && result.modifydate) {
        let s = (new Date().getTime() - new Date(result.modifydate).getTime()) / (1000 * 60 * 60)
        if (!isNaN(s) && s < 2) {
          config.$cache = false
          config.$time = 0
          config.cacheUseful = 'false'
        }
      }
      let initInters = []
      config.interfaces = this.formatInterSetting(config.interfaces, regs, MenuID, initInters)
src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -447,7 +447,7 @@
    const { btn } = this.props
    
    let imgCol = false
    let columns = btn.verify.columns.filter(col => {
    let columns = btn.verify.columns.map(col => {
      if (col.type === 'image') {
        imgCol = true
      }
src/tabviews/zshare/actionList/index.scss
@@ -1,17 +1,21 @@
.button-list.toolbar-button {
  position: relative;
  padding: 15px 0px 0px;
  background: #ffffff;
  min-height: 55px;
  background: transparent;
  button {
    min-width: 65px;
    min-width: 60px;
    margin-right: 15px;
    margin-bottom: 10px!important;
    overflow: hidden;
    min-height: 28px;
    height: auto;
  }
  .ant-btn-icon-only {
    width: auto;
    padding: 0 15px;
  }
  .loading-skeleton {
    background: -webkit-gradient(linear,left top,right top,color-stop(25%,#f5f5f5),color-stop(37%,#ffffff),color-stop(63%,#f5f5f5));
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -2882,7 +2882,19 @@
        _item.value = _item.value.replace(/\t+|\v+/g, '')       // 去除制表符
        if (item.interception !== 'false') {                    // 去除首尾空格
          _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
          if (item.interception === 'func') {
            try {
              // eslint-disable-next-line
              let func = new Function('value', 'data', item.func)
              _item.value = func(_item.value, _data)
              _item.value = _item.value !== undefined ? _item.value : ''
            } catch (e) {
              console.warn(e)
              _item.value = ''
            }
          } else {
            _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
          }
        }
        if (_item.type === 'text' && /@appkey@|@SessionUid@|@bid@/ig.test(_item.value)) { // 特殊字段替换
          _item.value = _item.value.replace(/^(\s*)@appkey@(\s*)$/ig, window.GLOB.appkey).replace(/^(\s*)@SessionUid@(\s*)$/ig, (localStorage.getItem('SessionUid') || '')).replace(/^(\s*)@bid@(\s*)$/ig, (BID || ''))
@@ -2996,6 +3008,13 @@
        container = () => document.getElementById(btn.ContainerId)
      }
      if (btnconfig.setting.icon) {
        title = <>
          <span className={'mk-modal-icon-' + btnconfig.setting.iconType} style={{background: btnconfig.setting.iconColor || 'unset', color: btnconfig.setting.iconColor || 'inherit'}}><MkIcon type={btnconfig.setting.icon}/></span>
          {title}
        </>
      }
      return (
        <Modal
          title={title}
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -2148,7 +2148,19 @@
        _item.value = _item.value.replace(/\t+|\v+/g, '')       // 去除制表符
        if (item.interception !== 'false') {                    // 去除首尾空格
          _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
          if (item.interception === 'func') {
            try {
              // eslint-disable-next-line
              let func = new Function('value', 'data', item.func)
              _item.value = func(_item.value, _data)
              _item.value = _item.value !== undefined ? _item.value : ''
            } catch (e) {
              console.warn(e)
              _item.value = ''
            }
          } else {
            _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
          }
        }
        if (_item.type === 'text' && /@appkey@|@SessionUid@|@bid@/ig.test(_item.value)) { // 特殊字段替换
          _item.value = _item.value.replace(/^(\s*)@appkey@(\s*)$/ig, window.GLOB.appkey).replace(/^(\s*)@SessionUid@(\s*)$/ig, (localStorage.getItem('SessionUid') || '')).replace(/^(\s*)@bid@(\s*)$/ig, (this.props.BID || ''))
@@ -2226,6 +2238,13 @@
      clickouter = true
    }
    if (btnconfig.setting.icon) {
      title = <>
        <span className={'mk-modal-icon-' + btnconfig.setting.iconType} style={{background: btnconfig.setting.iconColor || 'unset', color: btnconfig.setting.iconColor || 'inherit'}}><MkIcon type={btnconfig.setting.icon}/></span>
        {title}
      </>
    }
    return (
      <Modal
        title={title}
src/tabviews/zshare/mutilform/index.jsx
@@ -28,6 +28,7 @@
const MkFormula = asyncComponent(() => import('./mkFormula'))
const MkCascader = asyncComponent(() => import('./mkCascader'))
const MkVercode = asyncComponent(() => import('./mkVercode'))
const MKPopSelect = asyncComponent(() => import('./mkPopSelect'))
const MKEditor = asyncComponent(() => import('@/components/editor'))
class MutilFormComponent extends Component {
@@ -125,7 +126,7 @@
        item.precision = 'second'
      }
      if (!item.field || !['text', 'number', 'switch', 'check', 'rate', 'select', 'link', 'cascader', 'linkMain', 'funcvar', 'date', 'datemonth', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color', 'vercode'].includes(item.type)) return false
      if (!item.field || !['text', 'number', 'switch', 'check', 'rate', 'select', 'popSelect', 'link', 'cascader', 'linkMain', 'funcvar', 'date', 'datemonth', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color', 'vercode'].includes(item.type)) return false
      if (/^\s+$/.test(item.label)) {
        item.style = item.style || {}
@@ -292,26 +293,31 @@
        }
      }
      item.rules = []
      if (item.type === 'text') {
        item.initval = item.initval + ''
        let _rules = [{
          pattern: /^[^']*$/ig,
          message: '不可使用英文状态的单引号!'
        }, {
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
          })
        }
        item.rules.push({
          validator: (rule, value, callback) => {
            if (/--/ig.test(value)) {
            if (/'/.test(value)) {
              callback('不可使用英文状态的单引号!')
            } else if (/--/.test(value)) {
              callback('不可使用 -- !')
            } else {
              callback()
            }
          }
        }, {
          required: item.required === 'true',
          message: item.label + '不可为空!'
        }]
        })
        if (!item.lenControl || item.lenControl === 'limit') {
          _rules.push({
          item.rules.push({
            max: item.fieldlength,
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
          })
@@ -323,7 +329,7 @@
            if (item.regularExtra) {
              reg = new RegExp('^[0-9.-' + item.regularExtra.replace(/\.|-/g, '') + ']*$')
            }
            _rules.push({
            item.rules.push({
              pattern: reg,
              message: item.regularText || formRule.input.numbermsg
            })
@@ -332,7 +338,7 @@
            if (item.regularExtra) {
              reg = new RegExp('^[a-zA-Z' + item.regularExtra + ']*$')
            }
            _rules.push({
            item.rules.push({
              pattern: reg,
              message: item.regularText || formRule.input.lettermsg
            })
@@ -341,7 +347,7 @@
            if (item.regularExtra) {
              reg = new RegExp('^[a-zA-Z0-9' + item.regularExtra + ']*$')
            }
            _rules.push({
            item.rules.push({
              pattern: reg,
              message: item.regularText || '请输入数字或字母'
            })
@@ -350,80 +356,113 @@
            if (item.regularExtra) {
              reg = new RegExp('^[a-zA-Z0-9@_.' + item.regularExtra.replace(/\.|_|@/g, '') + ']*$')
            }
            _rules.push({
            item.rules.push({
              pattern: reg,
              message: item.regularText || '请输入数字、字母以及@_.'
            })
          } else if (item.regular === 'phone') {
            _rules.push({
            item.rules.push({
              pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
              message: item.regularText || '请正确输入手机号'
            })
          } else if (item.regular === 'email') {
            _rules.push({
            item.rules.push({
              pattern: /^([a-zA-Z0-9._-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/,
              message: item.regularText || '请正确输入邮箱地址'
            })
          }
        }
        item.rules = _rules
      } else if (item.type === 'number') {
        item.rules = [{
          required: true,
          message: item.label + '不可为空!'
        }, {
          validator: (rule, value, callback) => this.handleConfirmPassword(rule, value, callback, item)
        }]
      } else if (item.type === 'textarea') {
        let _rules = [
          {
            required: item.required === 'true',
            message: item.label + '不可为空!'
          },
          {
            max: item.fieldlength,
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
          },
          {
            pattern: /^[^']*$/ig,
            message: '不可使用英文状态的单引号!'
          }, {
        if (typeof(item.min) === 'number' || typeof(item.max) === 'number') {
          item.rules.push({
            validator: (rule, value, callback) => {
              if (/--/ig.test(value)) {
                callback('不可使用 -- !')
              if (isNaN(value)) {
                callback()
              } else if (typeof(item.min) === 'number' && value < item.min) {
                if (item.min < 1e-6) {
                  if (item.min === 1e-6) {
                    callback(item.label + '最小值为 0.000001')
                  } else if (item.min === 1e-7) {
                    callback(item.label + '最小值为 0.0000001')
                  } else if (item.min === 1e-8) {
                    callback(item.label + '最小值为 0.00000001')
                  } else if (item.min === 1e-9) {
                    callback(item.label + '最小值为 0.000000001')
                  } else if (item.min === 1e-10) {
                    callback(item.label + '最小值为 0.0000000001')
                  } else if (item.min === 1e-11) {
                    callback(item.label + '最小值为 0.00000000001')
                  } else {
                    callback(item.label + '最小值为 ' + item.min)
                  }
                } else {
                  callback(item.label + '最小值为 ' + item.min)
                }
              } else if (typeof(item.max) === 'number' && value > item.max) {
                callback(item.label + '最大值为 ' + item.max)
              } else {
                callback()
              }
            }
          })
        }
      } else if (item.type === 'textarea') {
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
          })
        }
        item.rules.push({
          validator: (rule, value, callback) => {
            if (/'/.test(value)) {
              callback('不可使用英文状态的单引号!')
            } else if (/--/.test(value)) {
              callback('不可使用 -- !')
            } else {
              callback()
            }
          }
        ]
        item.rules = _rules
        }, {
          max: item.fieldlength,
          message: formRule.input.formMessage.replace('@max', item.fieldlength)
        })
      } else if (item.type === 'brafteditor') {
        item.rules = [
          {
            required: item.required === 'true',
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
          },
          {
            max: item.fieldlength,
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
          }
        ]
          })
        }
        item.rules.push({
          max: item.fieldlength,
          message: formRule.input.formMessage.replace('@max', item.fieldlength)
        })
      } else if (item.type === 'linkMain' || item.type === 'vercode') {
        item.rules = [
          {
            required: item.required === 'true',
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
          }
        ]
          })
        }
      } else {
        item.rules = [
          {
            required: item.required === 'true',
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: '请选择' + item.label + '!'
          }
        ]
          })
        }
      }
      if (item.rules.length === 0) {
        item.rules = null
      }
      fieldMap.set(item.field, item)
@@ -530,6 +569,18 @@
            reFieldsVal[n.field] = val || ''
          })
        } else if (item.type === 'fileupload') {
          item.options = []
          item.subFields = []
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m
              })
            }
          })
        } else if (item.type === 'popSelect') {
          item.options = []
          item.subFields = []
          item.linkSubField.forEach(m => {
@@ -1002,22 +1053,6 @@
    })
  }
  handleConfirmPassword = (rule, value, callback, item) => {
    let val = parseFloat(value)
    if (!isNaN(val)) {
      if (typeof(item.min) === 'number' && val < item.min) {
        callback(item.label + '最小值为 ' + item.min)
      } else if (typeof(item.max) === 'number' && val > item.max) {
        callback(item.label + '最大值为 ' + item.max)
      } else {
        callback()
      }
    } else {
      callback()
    }
  }
  recordChange = (values, item) => {
    this.record = {...this.record, ...values}
@@ -1124,6 +1159,8 @@
          content = (<MKNumberInput config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
        } else if (item.type === 'select' || item.type === 'link' || item.type === 'multiselect') {
          content = (<MKSelect config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)} onSubmit={this.props.inputSubmit} />)
        } else if (item.type === 'popSelect') {
          content = (<MKPopSelect config={item} BID={this.props.BID} ID={this.state.ID} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)} onSubmit={this.props.inputSubmit} />)
        } else if (item.type === 'cascader') {
          content = (<MkCascader config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)}/>)
        } else if (item.type === 'color') {
@@ -1218,7 +1255,19 @@
            _item.value = _item.value.replace(/\t+|\v+/g, '')       // 去除制表符
    
            if (item.interception !== 'false') {                    // 去除首尾空格
              _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
              if (item.interception === 'func') {
                try {
                  // eslint-disable-next-line
                  let func = new Function('value', 'data', item.func)
                  _item.value = func(_item.value, record)
                  _item.value = _item.value !== undefined ? _item.value : ''
                } catch (e) {
                  console.warn(e)
                  _item.value = ''
                }
              } else {
                _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
              }
            }
            if (item.type === 'text' && /@appkey@|@SessionUid@|@bid@/ig.test(_item.value)) { // 特殊字段替换
              _item.value = _item.value.replace(/^(\s*)@appkey@(\s*)$/ig, window.GLOB.appkey).replace(/^(\s*)@SessionUid@(\s*)$/ig, (localStorage.getItem('SessionUid') || '')).replace(/^(\s*)@bid@(\s*)$/ig, (this.props.BID || ''))
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx
New file
@@ -0,0 +1,372 @@
import React, {Component} from 'react'
import { is, fromJS } from 'immutable'
import { Select } from 'antd'
import { notification, Modal, Table, Input } from 'antd'
import moment from 'moment'
import { TableOutlined } from '@ant-design/icons'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const { Search } = Input
class MKPopSelect extends Component {
  constructor(props) {
    super(props)
    let config = fromJS(props.config).toJS()
    let value = config.initval
    let arrfield = config.columns.map(f => f.field)
    if (config.subFields && config.subFields.length > 0) {
      config.subFields.forEach(n => {
        if (!arrfield.includes(n.field)) {
          arrfield.push(n.field)
        }
      })
    }
    if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
      config.dataSource = config.dataSource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
    } else {
      config.dataSource = config.dataSource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
    }
    config.dataSource = config.dataSource.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
    config.dataSource = config.dataSource.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    config.dataSource = config.dataSource.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    config.dataSource = config.dataSource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    if (/\s/.test(config.dataSource)) { // 拼接别名
      config.dataSource = '(' + config.dataSource + ') tb'
    }
    let columns = []
    let labels = {}
    config.columns.forEach(col => {
      labels[col.field] = col.label
      if (col.Hide === 'true') return
      columns.push({
        dataIndex: col.field,
        title: col.label,
        sorter: col.IsSort === 'true',
        width: 120
      })
    })
    let placeholder = ''
    if (!config.searchKey) {
      config.onload = 'true'
    } else {
      placeholder = []
      config.searchKey.split(',').forEach(key => {
        if (!labels[key]) {
          placeholder = ''
        } else if (placeholder) {
          placeholder.push(labels[key])
        }
      })
      placeholder = placeholder ? placeholder.join('、') : ''
    }
    this.state = {
      config: config,
      options: [],
      columns,
      value,
      placeholder,
      arr_field: arrfield.join(','),
      searchKey: '',
      pageIndex: 1,
      pageSize: 10,
      orderBy: '',
      visible: false,
      loading: false
    }
    this.timer = null
  }
  componentDidMount () {
    const { config } = this.state
    if (config.onload === 'true') {
      this.loadData()
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  loadData () {
    const { BID, ID } = this.props
    const { config, pageIndex, pageSize, arr_field, searchKey, orderBy } = this.state
    this.setState({
      loading: true
    })
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      exec_type: 'y',
      arr_field: arr_field,
      default_sql: 'true',
      custom_script: '',
      menuname: config.label
    }
    let sql = ''
    let DateCount = ''
    let _search = ''
    let _orderBy = orderBy || config.order || ''
    let _datasource = config.dataSource
    if (config.searchKey && searchKey) {
      let fields = config.searchKey.split(',').map(field => field + ` like '%${searchKey}%'`)
      _search = 'where ' + fields.join(' OR ')
    }
    _datasource = _datasource.replace(/@BID@/ig, `'${BID || ''}'`)
    _datasource = _datasource.replace(/@ID@/ig, `'${ID || ''}'`)
    if (config.laypage === 'true') {
      sql = `/*system_query*/select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_datasource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows `
      DateCount = `/*system_query*/select count(1) as total from ${_datasource} ${_search}`
    } else if (_orderBy) {
      sql = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from ${_datasource} ${_search}) tmptable order by tmptable.rows `
    } else {
      sql = `/*system_query*/select ${arr_field} from ${_datasource} ${_search}  `
    }
    let departmentcode = sessionStorage.getItem('departmentcode') || ''
    let organization = sessionStorage.getItem('organization') || ''
    let mk_user_type = sessionStorage.getItem('mk_user_type') || ''
    sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
      Select @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}'
      ${sql}`
    // 测试系统打印查询语句
    if (window.GLOB.debugger === true) {
      console.info(`/*${config.label} 数据源*/\n` + sql.replace(/\n\s{6}/ig, '\n'))
      DateCount && console.info(`/*${config.label} 总数查询*/\n` + DateCount.replace(/\n\s{6}/ig, '\n'))
    }
    param.LText = Utils.formatOptions(sql)
    param.DateCount = Utils.formatOptions(DateCount)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    param.username = sessionStorage.getItem('User_Name') || ''
    param.fullname = sessionStorage.getItem('Full_Name') || ''
    Api.genericInterface(param).then(result => {
      if (result.status) {
        let options = result.data.map((item, index) => {
          item.key = index
          item.$$uuid = item[config.primaryKey] || ''
          item.$label = item[config.showField]
          if (config.controlField && item[config.controlField] === 'true') {
            item.$disabled = true
          }
          return item
        })
        this.setState({
          options: options,
          total: result.total || 0,
          loading: false
        })
        if (result.message) {
          if (result.ErrCode === 'Y') {
            Modal.success({
              title: result.message
            })
          } else if (result.ErrCode === 'S') {
            notification.success({
              top: 92,
              message: result.message,
              duration: 2
            })
          }
        }
      } else {
        this.setState({
          loading: false
        })
        if (!result.message) return
        if (result.ErrCode === 'N') {
          Modal.error({
            title: result.message,
          })
        } else if (result.ErrCode !== '-2') {
          notification.error({
            top: 92,
            message: result.message,
            duration: 10
          })
        }
      }
    })
  }
  searchOption = (val) => {
    this.setState({searchKey: val})
    if (this.timer) {
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(() => {
      this.loadData()
    }, 500)
  }
  selectChange = (val, record) => {
    const { config } = this.state
    let other = {}
    if (config.subFields) {
      let option = record || null
      if (!option) {
        option = this.state.options.filter(m => m.$$uuid === val)[0]
      }
      option && config.subFields.forEach((n, i) => {
        other[n.field] = option[n.field]
        setTimeout(() => {
          MKEmitter.emit('mkFC', 'input', n.uuid, option[n.field])
        }, i * 5)
      })
    }
    this.props.onChange(val, other)
    this.setState({value: val}, () => {
      if (config.enter === 'tab') {
        MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      } else if (config.enter === 'sub') {
        if (config.subFields) {
          setTimeout(() => {
            this.props.onSubmit()
          }, 1000)
        } else {
          this.props.onSubmit()
        }
      }
    })
  }
  trigger = (e) => {
    e.stopPropagation()
    this.setState({visible: true})
  }
  changeRow = (record) => {
    if (record.$disabled) return
    this.selectChange(record.$$uuid, record)
    this.setState({visible: false})
  }
  changeTable = (pagination, filters, sorter) => {
    let orderBy = ''
    if (sorter.field && sorter.order) {
      if (sorter.order === 'ascend') {
        orderBy = `${sorter.field} asc`
      } else {
        orderBy = `${sorter.field} desc`
      }
    }
    this.setState({
      pageIndex: pagination.current,
      pageSize: pagination.pageSize,
      orderBy: orderBy,
    }, () => {
      this.loadData()
    })
  }
  render() {
    const { value, config, options, visible, loading, total, pageIndex, pageSize, columns, placeholder } = this.state
    return <>
      <Select
        className="mk-pop-select"
        showSearch={!!config.searchKey}
        allowClear
        value={value}
        onSearch={(val) => val && this.searchOption(val)}
        filterOption={false}
        onChange={(val) => this.selectChange(val === undefined ? '' : val)}
        disabled={config.readonly}
        suffixIcon={<TableOutlined onClick={this.trigger}/>}
      >
        {options.map(option =>
          <Select.Option disabled={option.$disabled} key={option.key} value={option.$$uuid}>{option.$label}</Select.Option>
        )}
      </Select>
      <Modal
        wrapClassName='mk-pop-select-modal'
        title={config.label}
        visible={visible}
        closable={true}
        centered={true}
        maskClosable={false}
        cancelText="关闭"
        width={config.popWidth < 100 ? config.popWidth + 'vw' : config.popWidth}
        onCancel={() => this.setState({visible: false})}
        destroyOnClose
      >
        {config.searchKey ? <Search placeholder={placeholder} onSearch={this.searchOption} enterButton /> : null}
        <Table
          rowKey="$$uuid"
          bordered={true}
          rowSelection={null}
          columns={columns}
          dataSource={options}
          loading={loading}
          onRow={(record) => {
            return {
              className: value === record.$$uuid ? ' ant-table-row-selected ' : '',
              onClick: () => {this.changeRow(record)},
            }
          }}
          onChange={this.changeTable}
          pagination={config.laypage === 'true' ? {
            current: pageIndex,
            pageSize: pageSize,
            showSizeChanger: true,
            total: total || 0,
            showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
          } : false}
        />
      </Modal>
    </>
  }
}
export default MKPopSelect
src/tabviews/zshare/mutilform/mkPopSelect/index.scss
New file
@@ -0,0 +1,64 @@
.mk-pop-select {
  .ant-select-selection__rendered {
    margin-right: 30px;
  }
  .ant-select-selection__clear {
    right: 35px;
  }
  .ant-select-arrow {
    transform: translate(8px, -9px);
    .ant-select-arrow-icon {
      padding: 7px;
      color: rgba(0, 0, 0, 0.25);
      transition: color 0.2s;
      font-size: 14px;
      svg {
        transition: none!important;
        transform: none!important;
      }
    }
    .ant-select-arrow-icon:hover {
      color: var(--mk-sys-color);
    }
  }
}
.mk-pop-select-modal {
  .ant-modal-body {
    min-height: 200px;
    max-height: calc(100vh - 210px);
    overflow-y: auto;
    .ant-input-search {
      max-width: 300px;
      margin-bottom: 20px;
    }
    table {
      tr:not(.ant-table-row-selected):hover > td {
        background-color: var(--mk-sys-color1);
      }
      tr.ant-table-row-selected td {
        background-color: var(--mk-sys-color3);
      }
    }
  }
  .ant-modal-body::-webkit-scrollbar {
    width: 7px;
  }
  .ant-modal-body::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .ant-modal-body::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
  .ant-modal-footer {
    .ant-btn-primary {
      display: none;
    }
  }
}
src/tabviews/zshare/topSearch/index.scss
@@ -1,5 +1,5 @@
.mk-search-wrap {
  background: #ffffff;
  // background: #ffffff;
  .mk-search-col {
    display: inline-block;
src/templates/modalconfig/dragelement/card.jsx
@@ -1,7 +1,7 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Select, DatePicker, Input, InputNumber, Button, Popover, Switch, Radio, Checkbox, Form, Rate } from 'antd'
import { QuestionCircleOutlined, UploadOutlined, EditOutlined, CopyOutlined, CloseOutlined, StarFilled, FontColorsOutlined } from '@ant-design/icons'
import { QuestionCircleOutlined, UploadOutlined, EditOutlined, CopyOutlined, CloseOutlined, StarFilled, SearchOutlined, FontColorsOutlined } from '@ant-design/icons'
import moment from 'moment'
import asyncComponent from '@/utils/asyncComponent'
@@ -80,6 +80,8 @@
    formItem = (<InputNumber value={card.initval} precision={card.decimal} />)
  } else if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link' || card.type === 'cascader') {
    formItem = (<Select value={selectval}></Select>)
  } else if (card.type === 'popSelect') {
    formItem = (<Select value={card.initval} suffixIcon={<SearchOutlined />}></Select>)
  } else if (card.type === 'color') {
    formItem = (<ColorSketch value={card.initval || 'transparent'}/>)
  } else if (card.type === 'date') {
src/templates/modalconfig/index.jsx
@@ -8,7 +8,6 @@
import Api from '@/api'
import { getModalForm } from '@/templates/zshare/formconfig'
import SourceElement from './dragelement/source'
import SettingForm from './settingform'
import MenuForm from './menuform'
@@ -348,73 +347,35 @@
  /**
   * @description 编辑后提交
   * 1、获取编辑后的表单信息
   * 2、去除可能存在的示例表单
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.config).toJS()
      let fieldrepet = false // 字段重复
    let _config = fromJS(this.state.config).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
        if (item.uuid === res.uuid) {
          if (item.style) {
            res.style = item.style
          }
          return res
        if (item.uuid === res.values.uuid) {
          return res.values
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      _config.fields = _config.fields.filter(item => !item.origin)
      window.GLOB.formId = res.uuid
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (res.loading) {
        this.setState({
          sqlVerifing: true
        })
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'1949-10-01 15:00:00'`)
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
              config: _config,
              card: null,
              visible: false
            })
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        res.promise().then(() => {
          this.setState({
            sqlVerifing: false,
            config: _config,
            card: null,
            visible: false
          })
        }, () => {
          this.setState({sqlVerifing: false})
        })
      } else {
        this.setState({
src/templates/modalconfig/settingform/index.jsx
@@ -5,7 +5,11 @@
// import { formRule } from '@/utils/option.js'
import StyleInput from '@/menu/stylecontroller/styleInput'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
class SettingForm extends Component {
  static propTpyes = {
@@ -18,6 +22,7 @@
    fields: null,
    display: this.props.config.setting.display || 'modal',
    placement: this.props.config.setting.placement || 'right',
    icon: this.props.config.setting.icon || '',
    appType: sessionStorage.getItem('appType'),
    viewType: sessionStorage.getItem('editMenuType') || '',
    dialogInput: false
@@ -80,7 +85,7 @@
  render() {
    const { config } = this.props
    const { fields, appType, display, placement } = this.state
    const { fields, appType, display, placement, icon } = this.state
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
@@ -197,6 +202,32 @@
              )}
            </Form.Item>
          </Col> : null}
          {appType !== 'mob' && display === 'modal' ? <Col span={12}>
            <Form.Item label="图标">
              {getFieldDecorator('icon', {
                initialValue: icon
              })(<MkEditIcon onChange={(value) => this.setState({icon: value})} allowClear={true}/>)}
            </Form.Item>
          </Col> : null}
          {appType !== 'mob' && display === 'modal' && icon ? <Col span={12}>
            <Form.Item label="图标样式">
              {getFieldDecorator('iconType', {
                initialValue: config.setting.iconType || 'def'
              })(
                <Radio.Group>
                  <Radio value="def">默认</Radio>
                  <Radio value="circle">圆形</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
          {appType !== 'mob' && display === 'modal' && icon ? <Col span={12}>
            <Form.Item label="图标颜色">
              {getFieldDecorator('iconColor', {
                initialValue: config.setting.iconColor || ''
              })(<ColorSketch allowClear={true}/>)}
            </Form.Item>
          </Col> : null}
          {appType === 'mob' && display === 'drawer' ? <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="表单元素与左侧边界的距离。">
src/templates/modalconfig/settingform/index.scss
@@ -5,4 +5,8 @@
      width: 16.5%;
    }
  }
  .color-sketch-block {
    position: relative;
    top: 9px;
  }
}
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -970,7 +970,7 @@
            <Button className="excel-col-add mk-red" title="清空Excel列" onClick={this.clearField}>
              清空Excel列
            </Button>
            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>如需导出序号,请使用字段 $Index;数值类型导出时可进行数据处理(取绝对值、保留小数位);红色标题导出时列头文字为红色。</div>
            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>如需导出序号,请使用字段 $Index;数值类型导出时可取绝对值以及设置小数位;导出为否时,不使用行信息;红色标题导出时列头文字为红色。</div>
            <EditTable actions={['edit', 'move', 'copy', 'del']} type="excelcolumn" wrappedComponentRef={(inst) => this.columnRef = inst} data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
          </TabPane>
          {card.intertype === 'system' ? <TabPane tab={
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
@@ -67,14 +67,7 @@
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    
    // 正则替换
    let _regoptions = regoptions.map(item => {
      return {
        reg: new RegExp('@' + item.key + '@', 'ig'),
        value: `'0'`
      }
    })
    _regoptions.push({
    regoptions.push({
      reg: new RegExp('@orderBy@', 'ig'),
      value: verify.order
    }, {
@@ -85,7 +78,7 @@
      value: 1
    })
    _regoptions.forEach(item => {
    regoptions.forEach(item => {
      _dataresource = _dataresource.replace(item.reg, item.value)
      _customScript = _customScript.replace(item.reg, item.value)
      _tailScript = _tailScript.replace(item.reg, item.value)
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -11,9 +11,8 @@
import './index.scss'
const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
const FieldsTable = asyncComponent(() => import('@/templates/zshare/modalform/fieldtable'))
const DataTable = asyncComponent(() => import('@/templates/zshare/modalform/datatable'))
const EditTable = asyncComponent(() => import('@/templates/zshare/modalform/modaleditable'))
const FieldsTable = asyncComponent(() => import('@/templates/zshare/editTable'))
const groupOptions = [
  {
@@ -190,6 +189,14 @@
      }
    } else if (type === 'checkcard') {
      reRequired.fields = false
      reOptions.multiple = [{
        value: 'false',
        text: '单选'
      }, {
        value: 'true',
        text: '多选'
      }]
      if (this.record.display === 'picture') {
        if (this.record.resourceType === '0') {        // 自定义资源
          shows.push('options', 'fields', 'picratio')
@@ -203,6 +210,20 @@
          shows.push('dataSource', 'cardValField', 'colorField', 'fields', 'orderBy', 'orderType', 'database')
        }
      } else {
        let appType = sessionStorage.getItem('appType')
        if (appType === '') {
          reOptions.multiple = [{
            value: 'false',
            text: '单选'
          }, {
            value: 'true',
            text: '多选'
          }, {
            value: 'dropdown',
            text: '下拉菜单'
          }]
        }
        reRequired.fields = true
        if (this.record.resourceType === '0') {        // 自定义资源
          shows.push('options', 'fields', 'selectStyle', 'border')
@@ -349,6 +370,9 @@
        this.record.match = 'like'
        _fieldval.match = 'like'
      }
    } else if (key === 'display') {
      this.record.multiple = 'false'
      _fieldval.multiple = 'false'
    } else if (key === 'items') {
      let _initval = this.props.form.getFieldValue('initval')
      if (_initval && !value.includes(_initval[0])) {
@@ -552,12 +576,44 @@
        let type = this.record.type
        
        if (type !== 'checkcard') {
          content = <EditTable type={type} module="search" transfield={{}} linkSubFields={[]} onChange={this.changeOptions}/>
          let columns = []
          if (type === 'link') {
            columns.push({ title: 'ParentID', key: 'ParentID', strict: true })
          }
          columns.push({ title: 'Value', key: 'Value', strict: true })
          columns.push({ title: 'Text', key: 'Text' })
          content = <EditTable columns={columns} module="search" onChange={this.changeOptions}/>
        } else {
          if (this.record.linkField) {
            type = 'link'
          }
          content = <DataTable type={type} multiple={this.record.multiple} display={this.record.display} linkSubFields={[]} transfield={{}} fields={this.record.fields || []} onChange={this.changeOptions}/>
          let columns = []
          let fields = this.record.fields || []
          let keys = ['ParentID', 'pid']
          if (type === 'link') {
            columns.push({ title: 'ParentID', key: 'ParentID', strict: true })
          } else if (this.record.multiple === 'dropdown' && this.record.display === 'text') {
            columns.push({ title: 'pid', key: 'pid', strict: true })
          }
          columns.push({ title: 'Value', key: '$value', strict: true })
          if (this.record.display === 'picture') {
            columns.push({ title: 'url', key: '$url', type: 'file' })
          } else if (this.record.display === 'color') {
            columns.push({ title: 'Color', key: '$color' })
          }
          fields.forEach(item => {
            keys.push(item.field)
            columns.push({ title: item.field, key: item.field })
          })
          content = <EditTable columns={columns} onChange={this.changeOptions}/>
        }
      } else if (item.type === 'fields') {
        span = 24
@@ -567,7 +623,7 @@
          { required: item.required, message: '请添加' + item.label + '!' }
        ]
        content = <FieldsTable onChange={this.changeField}/>
        content = <FieldsTable indexShow={false} actions={['edit', 'move', 'del', 'add']} columns={item.columns} data={this.record.fields || []} onChange={this.changeField}/>
      } else if (item.type === 'checkbox') {
        rules = [
          { required: item.required, message: '请选择' + item.label + '!' }
src/templates/zshare/editTable/index.jsx
@@ -3,7 +3,7 @@
import { is, fromJS } from 'immutable'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Input, InputNumber, Popconfirm, Form, Select, Radio, Cascader, notification, message, Modal, Typography } from 'antd'
import { CopyOutlined, EditOutlined, DeleteOutlined, SwapOutlined } from '@ant-design/icons'
import { CopyOutlined, EditOutlined, DeleteOutlined, SwapOutlined, PlusOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
import ColorSketch from '@/mob/colorsketch'
@@ -258,6 +258,7 @@
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.state.data), fromJS(nextProps.data))) {
      this.setState({data: nextProps.data, editingKey: ''})
    } else if (!is(fromJS(this.props.columns), fromJS(nextProps.columns))) {
@@ -518,6 +519,26 @@
      return
    }
    let forbid = false
    columns.forEach(col => {
      if (!col.forbids || forbid) return
      let key = record[col.dataIndex].toLowerCase()
      if (col.forbids.includes(key)) {
        forbid = col.title + '不可使用' + record[col.dataIndex]
      }
    })
    if (forbid) {
      notification.warning({
        top: 92,
        message: forbid,
        duration: 5
      })
      return
    }
    let unique = true
    columns.forEach(col => {
      if (col.unique !== true || !unique) return
@@ -582,6 +603,26 @@
        row = {...newData[index], ...row}
      } else {
        row.uuid = uuid
      }
      let forbid = false
      columns.forEach(col => {
        if (!col.forbids || forbid) return
        let key = row[col.dataIndex].toLowerCase()
        if (col.forbids.includes(key)) {
          forbid = col.title + '不可使用' + row[col.dataIndex]
        }
      })
      if (forbid) {
        notification.warning({
          top: 92,
          message: forbid,
          duration: 5
        })
        return
      }
      let unique = true
@@ -652,6 +693,37 @@
    })
  }
  handleAdd = () => {
    const { columns } = this.props
    const { data } = this.state
    let _index = data.length + 1
    let item = {
      uuid: Utils.getuuid()
    }
    columns.forEach(col => {
      if (!col.dataIndex) return
      item[col.dataIndex] = col.initval || ''
      if (col.unique) {
        while (data.filter(cell => cell[col.dataIndex] === item[col.dataIndex]).length > 0) {
          _index++
          item[col.dataIndex] = col.initval + _index
        }
      }
    })
    let _data = [...data, item]
    this.setState({
      data: _data
    }, () => {
      this.props.onChange(_data)
    })
  }
  render() {
    const { actions, indexShow, searchKey } = this.props
    const { editLineId } = this.state
@@ -714,6 +786,7 @@
    return (
      <EditableContext.Provider value={this.props.form}>
        <div className="modal-edit-table">
          {actions.includes('add') ? <PlusOutlined className="add-row" onClick={this.handleAdd} /> : null}
          <DndProvider>
            <Table
              bordered
src/templates/zshare/editTable/index.scss
@@ -4,6 +4,7 @@
      position: absolute;
      font-size: 12px;
      margin-top: -4px;
      white-space: nowrap;
    }
    .color-sketch-block {
      width: 200px;
@@ -112,5 +113,17 @@
      color: #ff4d4f;
    }
  }
  .ant-typography {
    margin: 3px 0px;
  }
  .add-row {
    position: absolute;
    z-index: 1;
    right: 10px;
    top: -30px;
    padding: 5px;
    font-size: 18px;
    color: #26C281;
  }
}
src/templates/zshare/formconfig.jsx
@@ -1,3 +1,4 @@
import React from 'react'
import { formRule, btnClasses } from '@/utils/option.js'
/**
@@ -549,18 +550,80 @@
      }]
    },
    {
      type: 'fields',
      key: 'fields',
      label: '字段集',
      initVal: card.fields || [],
      required: true
    },
    {
      type: 'codemirror',
      key: 'dataSource',
      label: '数据源',
      initVal: card.dataSource || '',
      tooltip: '数据权限替换符 $@ -> /* 或 \'\'、 @$ -> */ 或 \'\'',
      required: true
    },
    {
      type: 'fields',
      key: 'fields',
      label: '字段集',
      initVal: card.fields || [],
      required: true,
      columns: [
        {
          title: '字段名',
          dataIndex: 'field',
          inputType: 'input',
          editable: true,
          unique: true,
          strict: true,
          forbids: ['value', 'parentid', 'pid'],
          initval: 'field',
          rules: [{
            pattern: /^[\u4E00-\u9FA50-9a-zA-Z_-]*$/ig,
            message: '请使用数字、字母、汉字以及_-'
          }],
          width: '20%'
        },
        {
          title: '字体颜色',
          dataIndex: 'color',
          inputType: 'color',
          editable: true,
          initval: 'rgba(0, 0, 0, 0.85)',
          width: '20%',
          render: (text, record) => {
            return <span style={{color: text}}>示例</span>
          }
        },
        {
          title: '字体大小',
          dataIndex: 'fontSize',
          inputType: 'number',
          min: 12,
          max: 50,
          editable: true,
          initval: 14,
          width: '20%',
        },
        {
          title: '对齐方式',
          dataIndex: 'align',
          inputType: 'select',
          editable: true,
          width: '20%',
          initval: 'left',
          options: [
            {value: 'left', text: '居左'},
            {value: 'center', text: '居中'},
            {value: 'right', text: '居右'},
            // {value: 'justify', text: 'justify'}
          ],
          render: (text, record) => {
            if (text === 'center') {
              return '居中'
            } else if (text === 'right') {
              return '居右'
            } else {
              return '居左'
            }
          }
        }
      ]
    },
    {
      type: 'options',
@@ -644,7 +707,7 @@
      required: false
    },
    {
      type: 'select',
      type: 'radio',
      key: 'orderType',
      label: '排序方式',
      initVal: card.orderType || 'asc',
@@ -2567,6 +2630,9 @@
    value: 'link',
    text: '联动菜单'
  }, {
    value: 'popSelect',
    text: '选择器'
  }, {
    value: 'switch',
    text: '开关'
  }, {
@@ -2904,12 +2970,210 @@
    //   }]
    // },
    {
      type: 'codemirror',
      key: 'dataSource',
      label: '数据源',
      initVal: card.dataSource || '',
      tooltip: '数据权限替换符 $@ -> /* 或 \'\'、 @$ -> */ 或 \'\'',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值:@ID@、@BID@。',
      required: true,
      readonly: false
    },
    {
      type: 'fields',
      key: 'fields',
      label: '字段集',
      initVal: card.fields || [],
      required: true,
      readonly: false
      readonly: false,
      columns: [
        {
          title: '字段名',
          dataIndex: 'field',
          inputType: 'input',
          editable: true,
          unique: true,
          strict: true,
          forbids: ['value', 'parentid', 'pid'],
          initval: 'field',
          rules: [{
            pattern: /^[\u4E00-\u9FA50-9a-zA-Z_-]*$/ig,
            message: '请使用数字、字母、汉字以及_-'
          }],
          width: '20%'
        },
        {
          title: '字体颜色',
          dataIndex: 'color',
          inputType: 'color',
          editable: true,
          initval: 'rgba(0, 0, 0, 0.85)',
          width: '20%',
          render: (text, record) => {
            return <span style={{color: text}}>示例</span>
          }
        },
        {
          title: '字体大小',
          dataIndex: 'fontSize',
          inputType: 'number',
          min: 12,
          max: 50,
          editable: true,
          initval: 14,
          width: '20%',
        },
        {
          title: '对齐方式',
          dataIndex: 'align',
          inputType: 'select',
          editable: true,
          width: '20%',
          initval: 'left',
          options: [
            {value: 'left', text: '居左'},
            {value: 'center', text: '居中'},
            {value: 'right', text: '居右'},
            // {value: 'justify', text: 'justify'}
          ],
          render: (text, record) => {
            if (text === 'center') {
              return '居中'
            } else if (text === 'right') {
              return '居右'
            } else {
              return '居左'
            }
          }
        }
      ]
    },
    {
      type: 'fields',
      key: 'columns',
      label: '字段集',
      initVal: card.columns || [],
      required: true,
      readonly: false,
      columns: [
        {
          title: '名称',
          dataIndex: 'label',
          inputType: 'input',
          editable: true,
          initval: 'label',
          width: '20%'
        },
        {
          title: '字段',
          dataIndex: 'field',
          inputType: 'input',
          editable: true,
          unique: true,
          strict: true,
          copy: true,
          initval: 'field',
          rules: [{
            pattern: /^[\u4E00-\u9FA50-9a-zA-Z_-]*$/ig,
            message: '请使用数字、字母、汉字以及_-'
          }],
          width: '20%'
        },
        {
          title: '隐藏',
          dataIndex: 'Hide',
          inputType: 'radio',
          editable: true,
          width: '20%',
          initval: 'false',
          options: [
            {value: 'true', text: '是'},
            {value: 'false', text: '否'},
          ],
          render: (text, record) => {
            if (text === 'true') {
              return '是'
            } else {
              return '否'
            }
          }
        },
        {
          title: '排序',
          dataIndex: 'IsSort',
          inputType: 'radio',
          editable: true,
          width: '20%',
          initval: 'false',
          options: [
            {value: 'true', text: '是'},
            {value: 'false', text: '否'},
          ],
          render: (text, record) => {
            if (text === 'true') {
              return '是'
            } else {
              return '否'
            }
          }
        }
      ]
    },
    {
      type: 'select',
      key: 'primaryKey',
      label: '主键',
      initVal: card.primaryKey || '',
      required: true,
      readonly: false,
      options: 'columns'
    },
    {
      type: 'text',
      key: 'order',
      label: '默认排序',
      initVal: card.order || '',
      placeholder: 'ID asc',
      required: true
    },
    {
      type: 'select',
      key: 'showField',
      label: '显示字段',
      initVal: card.showField || '',
      tooltip: '用于控制选择框中的显示内容。',
      required: true,
      options: 'columns'
    },
    {
      type: 'select',
      key: 'controlField',
      label: '禁用字段',
      initVal: card.controlField || '',
      tooltip: '用于控制行数据是否可选择。字段值为true时,选项不可选。',
      required: false,
      allowClear: true,
      options: 'columns'
    },
    {
      type: 'text',
      key: 'searchKey',
      label: '搜索字段',
      initVal: card.searchKey || '',
      tooltip: '多个值请用逗号分隔。',
      required: false,
      rules: [{
        pattern: /^[0-9a-zA-Z,_-]*$/ig,
        message: '字段名只允许包含数字、字母以及_-',
      }]
    },
    {
      type: 'number',
      key: 'popWidth',
      label: '弹窗宽度',
      initVal: card.popWidth || 60,
      tooltip: '小于100时为百分率,大于100时为绝对值。',
      required: true
    },
    {
      type: 'options',
@@ -2920,13 +3184,33 @@
      readonly: false
    },
    {
      type: 'codemirror',
      key: 'dataSource',
      label: '数据源',
      initVal: card.dataSource || '',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值:@ID@、@BID@。',
      required: true,
      readonly: false
      type: 'radio',
      key: 'laypage',
      label: '分页',
      initVal: card.laypage || 'true',
      required: false,
      options: [{
        value: 'true',
        text: '是'
      }, {
        value: 'false',
        text: '否'
      }]
    },
    {
      type: 'radio',
      key: 'onload',
      label: '初始化',
      initVal: card.onload || 'true',
      tooltip: '当没有设置搜索字段时,初始化加载数据。',
      required: false,
      options: [{
        value: 'true',
        text: '加载'
      }, {
        value: 'false',
        text: '不加载'
      }]
    },
    {
      type: 'radio',
@@ -2985,7 +3269,7 @@
      readonly: false
    },
    {
      type: 'select',
      type: 'radio',
      key: 'orderType',
      label: '排序方式',
      initVal: card.orderType || 'asc',
@@ -3615,16 +3899,28 @@
    {
      type: 'radio',
      key: 'interception',
      label: '截取空格',
      label: '截取方式',
      initVal: card.interception || 'true',
      tooltip: '提交时,是否截取首尾的空白字符。',
      tooltip: '提交时的文本处理方式,空白字符指开头或结尾的空白字符。',
      options: [{
        value: 'true',
        text: '是'
      }, {
        value: 'false',
        text: '否'
        text: '无'
      }, {
        value: 'true',
        text: '空白字符'
      }, {
        value: 'func',
        text: '自定义函数'
      }]
    },
    {
      type: 'textarea',
      key: 'func',
      label: '函数',
      initVal: card.func || '',
      tooltip: '函数有两个入参(value, data),第一个为当前表单值,第二个为表单所有字段-值的对象,请返回处理后的值。',
      rows: 2,
      required: true
    },
    {
      type: 'textarea',
@@ -3858,7 +4154,7 @@
      type: 'radio',
      key: 'constant',
      label: 'Unicode常量',
      tooltip: '使用时将在提交内容前加上 N,代表存入数据库时以 Unicode 格式存储。',
      tooltip: `使用时将在提交内容前加上 N,代表存入数据库时以 Unicode 格式存储。例如:@nvarchar=N'ØW30041'。`,
      initVal: card.constant || 'false',
      options: [{
        value: 'true',
@@ -4004,7 +4300,11 @@
      initVal: card.regularExtra || '',
      tooltip: '正则验证时允许添加的自定义字符,包括~!@#$%^&*()_+:;{}<>,.-',
      required: false,
      readonly: false
      readonly: false,
      rules: [{
        pattern: /^[~!@#$%^&*()_+:;{}<>,.-]*$/,
        message: '扩展符包括~!@#$%^&*()_+:;{}<>,.-'
      }]
    },
    {
      type: 'text',
src/templates/zshare/modalform/datatable/index.jsx
File was deleted
src/templates/zshare/modalform/datatable/index.scss
File was deleted
src/templates/zshare/modalform/fieldtable/index.jsx
File was deleted
src/templates/zshare/modalform/fieldtable/index.scss
File was deleted
src/templates/zshare/modalform/index.jsx
@@ -1,9 +1,10 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, Radio, notification, InputNumber, Tooltip, Checkbox, AutoComplete } from 'antd'
import { Form, Row, Col, Input, Select, Radio, notification, InputNumber, Tooltip, Checkbox, AutoComplete, Modal } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import Api from '@/api'
import { formRule } from '@/utils/option.js'
import { dateOptions } from '@/utils/option.js'
import Utils from '@/utils/utils.js'
@@ -14,19 +15,18 @@
const { TextArea } = Input
const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
const FieldsTable = asyncComponent(() => import('./fieldtable'))
const DataTable = asyncComponent(() => import('./datatable'))
const FieldsTable = asyncComponent(() => import('@/templates/zshare/editTable'))
const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
const modalTypeOptions = {
  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'encryption', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline', 'placeholder', 'place', 'marginTop', 'marginBottom', 'lenControl', 'inputType', 'constant'],
  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline', 'place', 'marginTop', 'marginBottom'],
  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom', 'pickerMode'],
  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom', 'pickerMode'],
  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'setAll', 'emptyText', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'place', 'width', 'multiple', 'splitline', 'marginTop', 'marginBottom'],
  multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'dropdown'],
  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkField', 'linkSubField', 'span', 'place', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom', 'pickerMode'],
  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkField', 'linkSubField', 'span', 'place', 'labelwidth', 'tooltip', 'extra', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom', 'pickerMode'],
  fileupload: ['readonly', 'required', 'hidden', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'linkSubField', 'tooltip', 'extra', 'compress', 'miniSet', 'splitline', 'marginTop', 'marginBottom', 'maxSize'],
  switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'linkSubField', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom'],
  check: ['initval', 'openVal', 'closeVal', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom', 'checkTip'],
@@ -43,6 +43,7 @@
  brafteditor: ['required', 'hidelabel', 'hidden', 'readin', 'fieldlength', 'readonly', 'span', 'labelwidth', 'tooltip', 'extra', 'encryption', 'marginTop', 'marginBottom'],
  funcvar: ['span', 'labelwidth', 'splitline', 'marginTop', 'marginBottom'],
  linkMain: ['readonly', 'required', 'hidden','declare', 'span', 'labelwidth', 'tooltip', 'interception', 'extra', 'place', 'marginTop', 'marginBottom'],
  popSelect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'enter', 'dataSource', 'columns', 'primaryKey', 'order', 'controlField', 'laypage', 'onload', 'searchKey', 'showField', 'popWidth'],
  vercode: ['label', 'field', 'type', 'blacklist', 'supField', 'readonly', 'required', 'hidden', 'span', 'labelwidth', 'tooltip', 'marginTop', 'marginBottom', 'placeholder', 'enter', 'smsId', 'phoneField', 'sendType']
}
@@ -147,6 +148,9 @@
          shows.push('regularExtra')
        }
      }
      if (this.record.interception === 'func') {
        shows.push('func')
      }
    } else if (type === 'number') {
      reTypes.initval = 'number'
      reRequired.initval = true
@@ -165,6 +169,9 @@
        shows.push('fieldlength')
      } else if (this.record.declare === 'decimal') {
        shows.push('decimal')
      }
      if (this.record.interception === 'func') {
        shows.push('func')
      }
    } else if (['multiselect', 'select', 'link', 'radio', 'checkbox'].includes(type)) {
      if (this.record.resourceType === '0') {        // 自定义资源
@@ -277,6 +284,9 @@
    } else if (type === 'textarea') {
      if (this.record.encryption === 'false') {
        shows.push('enterReplace')
      }
      if (this.record.interception === 'func') {
        shows.push('func')
      }
    }
@@ -420,41 +430,45 @@
        this.record.readonly = 'false'
      }
      if (this.record.options.length > 0) {
        if (value === 'checkcard') {
      if (value === 'checkcard') {
        if (this.record.options.length > 0) {
          this.record.options = this.record.options.map(cell => {
            cell.$value = cell.Value || ''
            delete cell.Value
            return cell
          })
        }
  
          if (this.record.options[0].Text) {
            let key = Utils.getuuid()
            this.record.fields = [{
              $index: 1,
              align: 'left',
              color: 'rgba(0, 0, 0, 0.85)',
              field: 'Text',
              fontSize: 14,
              key: key,
              uuid: key
            }]
          }
        } else if (['multiselect', 'select', 'link', 'radio', 'checkbox'].includes(value)) {
        if (this.record.options[0] && this.record.options[0].Text) {
          let key = Utils.getuuid()
          this.record.fields = [{
            $index: 1,
            align: 'left',
            color: 'rgba(0, 0, 0, 0.85)',
            field: 'Text',
            fontSize: 14,
            key: key,
            uuid: key
          }]
        } else {
          this.record.fields = []
        }
      } else if (['multiselect', 'select', 'link', 'radio', 'checkbox'].includes(value)) {
        if (this.record.options.length > 0) {
          if (!this.record.options[0].Text && this.record.fields.length > 0) {
            let field = this.record.fields[0].field
    
            this.record.options = this.record.options.map(cell => {
              cell.Value = cell.Value || cell.$value || ''
              cell.Text = cell[field] || ''
              delete cell.$value
              return cell
            })
          } else {
            this.record.options = this.record.options.map(cell => {
              cell.Value = cell.Value || cell.$value || ''
              delete cell.$value
              return cell
            })
          }
@@ -505,12 +519,8 @@
    this.record[key] = value
  }
  changeField = (data) => {
    this.record.fields = data || []
  }
  changeOptions = (data) => {
    this.record.options = data || []
  changeOptions = (data, key) => {
    this.record[key] = data || []
  }
  changeVal = (val, type) => {
@@ -627,18 +637,15 @@
            message: '不可使用英文状态的单引号!'
          }
        ]
        if (item.key === 'field') {
        if (item.rules) {
          rules.push(...item.rules)
        } else if (item.key === 'field') {
          rules.push({
            pattern: formRule.field.pattern,
            message: formRule.field.message
          }, {
            max: formRule.field.max,
            message: formRule.field.maxMessage
          })
        } else if (item.key === 'regularExtra') {
          rules.push({
            pattern: /^[~!@#$%^&*()_+:;{}<>,.-]*$/,
            message: '扩展符包括~!@#$%^&*()_+:;{}<>,.-'
          })
        } else if (item.max) {
          rules.push({
@@ -664,7 +671,7 @@
            <Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />
          </AutoComplete>
        } else {
          content = <Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />
          content = <Input placeholder={item.placeholder || ''} autoComplete="off" onPressEnter={this.handleSubmit} />
        }
      } else if (item.type === 'number') {
        rules = [
@@ -681,6 +688,12 @@
        rules = [
          { required: item.required, message: '请选择' + item.label + '!' }
        ]
        let options = item.options
        if (typeof(item.options) === 'string') {
          options = this.record[item.options] || []
        }
        content = <Select
          showSearch
          allowClear={item.allowClear === true}
@@ -688,7 +701,7 @@
          onChange={(value) => {this.optionChange(item.key, value)}}
          getPopupContainer={() => document.getElementById('modal-fields-form-box')}
        >
          {item.options.map((option, i) =>
          {options.map((option, i) =>
            <Select.Option key={`${i}`} value={option.value || option.field || ''}>
              {option.text || option.label}
            </Select.Option>
@@ -769,7 +782,21 @@
              linkSubFields = []
            }
          }
          content = <EditTable type={type} module="form" transfield={transfield} linkSubFields={linkSubFields} onChange={this.changeOptions}/>
          let columns = []
          if (type === 'link') {
            columns.push({ title: 'ParentID', key: 'ParentID', strict: true })
          }
          columns.push({ title: 'Value', key: 'Value', strict: true })
          columns.push({ title: 'Text', key: 'Text' })
          linkSubFields.forEach(field => {
            if (field === 'Value' || field === 'Text') return
            columns.push({ title: transfield[field] || field, key: field })
          })
          content = <EditTable columns={columns} module="form" onChange={(data) => this.changeOptions(data, item.key)}/>
        } else {
          if (this.record.multiple === 'true') {
            linkSubFields = []
@@ -777,7 +804,34 @@
          if (this.record.linkField) {
            type = 'link'
          }
          content = <DataTable type={type} display={this.record.display} linkSubFields={linkSubFields} transfield={transfield} fields={this.record.fields || []} onChange={this.changeOptions}/>
          let columns = []
          let fields = this.record.fields || []
          let keys = ['ParentID', 'pid']
          if (type === 'link') {
            columns.push({ title: 'ParentID', key: 'ParentID', strict: true })
          }
          columns.push({ title: 'Value', key: '$value', strict: true })
          if (this.record.display === 'picture') {
            columns.push({ title: 'url', key: '$url', type: 'file' })
          } else if (this.record.display === 'color') {
            columns.push({ title: 'Color', key: '$color' })
          }
          fields.forEach(item => {
            keys.push(item.field)
            columns.push({ title: item.field, key: item.field })
          })
          linkSubFields.forEach(m => {
            if (keys.includes(m)) return
            columns.push({ title: transfield[m] || m, key: m })
          })
          content = <EditTable columns={columns} onChange={(data) => this.changeOptions(data, item.key)}/>
        }
      } else if (item.type === 'fields') {
        span = 24
@@ -786,7 +840,7 @@
          { required: item.required, message: '请添加' + item.label + '!' }
        ]
        content = <FieldsTable onChange={this.changeField}/>
        content = <FieldsTable indexShow={false} actions={['edit', 'move', 'del', 'add']} columns={item.columns} data={this.record[item.key] || []} onChange={(data) => this.changeOptions(data, item.key)}/>
      } else if (item.type === 'color') {
        className = 'color-form-item'
        rules = [
@@ -827,7 +881,7 @@
    let isNumber = true
    options.forEach(item => {
      if (!/^([0-9]|[1-9]\d{0,2})$/.test(item.Value)) {
      if (!item.Value || isNaN(item.Value)) {
        isNumber = false
      }
    })
@@ -868,12 +922,36 @@
    }
  }
  handleConfirm = () => {
  handleConfirm = (fields) => {
    const { card } = this.props
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values.uuid = this.props.card.uuid
          values.uuid = card.uuid
          if (card.style) {
            values.style = card.style
          }
          let fieldrepet = false // 字段重复
          fields.forEach(item => {
            if (item.uuid === card.uuid || !values.field || !item.field) return
            if (item.field.toLowerCase() === values.field.toLowerCase()) {
              fieldrepet = true
            }
          })
          if (fieldrepet) {
            notification.warning({
              top: 92,
              message: '字段已存在!',
              duration: 10
            })
            return
          }
          // 下拉菜单或联动菜单
          if (['multiselect', 'select', 'link', 'radio', 'checkbox'].includes(values.type)) {
            if (values.resourceType === '0') {
@@ -1011,7 +1089,93 @@
            return
          }
          resolve(values)
          window.GLOB.formId = card.uuid
          if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(values.type) && values.resourceType === '1' && values.dataSource) {
            let _option = Utils.getSelectQueryOptions(values)
            let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${_option.sql}`
            // LoginUID|SessionUid|UserID|Appkey 已替换
            sql = sql.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|time_id)@/ig, `'1949-10-01 15:00:00'`)
            let rduri = ''
            if (window.GLOB.mainSystemApi && values.database === 'sso') {
              rduri = window.GLOB.mainSystemApi
            }
            resolve({values, loading: true, promise: () => new Promise((resolve, reject) => {
              Api.sDebug(sql, rduri).then(result => {
                if (result.status || result.ErrCode === '-2') {
                  resolve()
                } else {
                  Modal.error({
                    title: result.message
                  })
                  reject()
                }
              })
            })})
          } else if (values.type === 'popSelect') {
            let arrfield = values.columns.map(f => f.field)
            if (values.linkSubField && values.linkSubField.length > 0) {
              values.linkSubField.forEach(n => {
                if (!arrfield.includes(n)) {
                  arrfield.push(n)
                }
              })
            }
            let _datasource = values.dataSource
            let sql = ''
            if (/\s/.test(_datasource)) { // 拼接别名
              _datasource = '(' + _datasource + ') tb'
            }
            arrfield = arrfield.join(',')
            let _search = ''
            if (values.searchKey) {
              let fields = values.searchKey.split(',').map(field => field + ' like \'%mk%\'')
              _search = 'where ' + fields.join(' OR ')
            }
            if (values.laypage === 'true') {
              sql = `/*system_query*/select top 10 ${arrfield} from (select ${arrfield} ,ROW_NUMBER() over(order by ${values.order}) as rows from ${_datasource} ${_search}) tmptable where rows > 0 order by tmptable.rows `
            } else if (values.order) {
              sql = `/*system_query*/select ${arrfield} from (select ${arrfield} ,ROW_NUMBER() over(order by ${values.order}) as rows from ${_datasource} ${_search}) tmptable order by tmptable.rows `
            } else {
              sql = `/*system_query*/select ${arrfield} from ${_datasource} ${_search}  `
            }
            sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
              ${sql}`
            sql = sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
            sql = sql.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
            sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
            sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
            sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
            resolve({values, loading: true, promise: () => new Promise((resolve, reject) => {
              Api.sDebug(sql).then(result => {
                if (result.status || result.ErrCode === '-2') {
                  resolve()
                } else {
                  Modal.error({
                    title: result.message
                  })
                  reject()
                }
              })
            })})
          } else {
            resolve({values})
          }
        } else {
          reject(err)
        }
src/templates/zshare/modalform/modaleditable/index.jsx
@@ -1,106 +1,138 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Table, Input, Popconfirm, Form, message } from 'antd'
import { ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined, PlusOutlined, SwapOutlined } from '@ant-design/icons'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Input, Popconfirm, message } from 'antd'
import { DeleteOutlined, PlusOutlined, SwapOutlined, DragOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const EditableContext = React.createContext()
const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
const EditableRow = ({ form, index, ...props }) => (
  <EditableContext.Provider value={form}>
    <tr {...props} />
  </EditableContext.Provider>
class MoveTd extends React.Component {
  render() {
    const { connectDragSource, connectDropTarget } = this.props
    return connectDragSource(
      connectDropTarget(<td className="mk-move-col"><DragOutlined /></td>),
    )
  }
}
const rowSource = {
  beginDrag(props) {
    return {
      index: props.index,
    }
  }
}
const rowTarget = {
  drop(props, monitor) {
    const dragIndex = monitor.getItem().index
    const hoverIndex = props.index
    if (dragIndex === hoverIndex) {
      return
    }
    props.moveRow(dragIndex, hoverIndex)
    monitor.getItem().index = hoverIndex
  },
}
const DragableTd = DropTarget('td', rowTarget, connect => ({
  connectDropTarget: connect.dropTarget(),
}))(
  DragSource('td', rowSource, (connect, monitor) => ({
    connectDragSource: connect.dragSource(),
    // isDragging: monitor.isDragging()
  }))(MoveTd),
)
const EditableFormRow = Form.create()(EditableRow)
class EditableCell extends Component {
  state = {
    editing: false
    editing: false,
    value: ''
  }
  toggleEdit = () => {
    const editing = !this.state.editing
    this.setState({ editing }, () => {
      if (editing && this.input && this.input.select) {
  trigger = () => {
    const { dataIndex, record } = this.props
    this.setState({ editing: true, value: record[dataIndex] }, () => {
      if (this.input && this.input.select) {
        this.input.select()
      } else if (editing && this.input && this.input.focus) {
      } else if (this.input && this.input.focus) {
        this.input.focus()
      }
    })
  }
  save = e => {
    const { record, handleSave } = this.props
    this.form.validateFields((error, values) => {
      handleSave({ ...record, ...values })
      if (error && error[e.currentTarget.id]) {
        return
      }
      this.toggleEdit()
    })
  save = () => {
    const { record, handleSave, dataIndex } = this.props
    const { value } = this.state
    handleSave({ ...record, [dataIndex]: value })
    this.setState({ editing: false, value: '' })
  }
  renderCell = form => {
    this.form = form
    const { children, dataIndex, record } = this.props
  changeUrl = (val) => {
    const { record, handleSave, dataIndex } = this.props
    handleSave({ ...record, [dataIndex]: val })
  }
  renderCell = () => {
    const { dataIndex, inputType, record } = this.props
    const { editing } = this.state
    return editing ? (
      <Form.Item style={{ margin: '0 -5px 0 -5px' }}>
        {form.getFieldDecorator(dataIndex, {
          rules: [
            {
              required: dataIndex === 'Text',
              message: '不可为空.',
            }
          ],
          initialValue: record[dataIndex]
        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
      </Form.Item>
    ) : (
      <div
        className="editable-cell-value-wrap"
        onClick={this.toggleEdit}
      >
        {children}
      </div>
    )
    if (inputType === 'file') {
      return <SourceComponent initialValue={record[dataIndex]} type="" onChange={this.changeUrl} placement="right"/>
    }
    if (!editing) {
      return (
        <div
          className="editable-cell-value-wrap"
          onClick={this.trigger}
        >
          {record[dataIndex]}
        </div>
      )
    } else {
      return <Input ref={node => (this.input = node)} defaultValue={record[dataIndex]} autoComplete="off" onChange={(e) => this.setState({value: e.target.value})} onPressEnter={this.save} onBlur={this.save} />
    }
  }
  render() {
    const {
      editable,
      dataIndex,
      title,
      record,
      index,
      handleSave,
      children,
      ...restProps
    } = this.props
    const { editable, dataIndex, index } = this.props
    if (dataIndex === '$move') {
      return (<DragableTd key={index} {...this.props} />)
    }
    if (editable) {
      return (
        <td>{this.renderCell()}</td>
      )
    }
    return (
      <td {...restProps}>
        {editable ? (
          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
        ) : (
          children
        )}
      </td>
      <td {...this.props}/>
    )
  }
}
class EditTable extends Component {
  static propTpyes = {
    type: PropTypes.string,         // 表单类型
    module: PropTypes.string,       // 元素类型
    linkSubFields: PropTypes.array, // 关联字段
    transfield: PropTypes.object,   // 表单字段名称
    onChange: PropTypes.func        // 数据变化
    type: PropTypes.any,
    module: PropTypes.string,
    columns: PropTypes.array,
    onChange: PropTypes.func
  }
  state = {
@@ -110,38 +142,40 @@
  }
  UNSAFE_componentWillMount () {
    const { linkSubFields, type } = this.props
    let data = this.props['data-__meta'].initialValue || []
    const { columns } = this.getColumns(type, linkSubFields, data)
    const { columns, value } = this.props
    let data = value || []
    this.setState({
      columns: columns,
      dataSource: data,
      columns: this.getColumns(),
      dataSource: data.map(item => {
        columns.forEach(n => {
          if (item[n.key] !== undefined) return
          item[n.key] = ['ParentID', '$url', '$color', '$value'].includes(n.key) ? '' : item.Text || ''
        })
        return item
      }),
      count: data.length
    })
  }
  handleUpDown = (record, direction) => {
  moveRow = (dragId, hoverId) => {
    const { dataSource } = this.state
    let index = 0
    let _data = dataSource.filter((item, i) => {
      if (item.key === record.key) {
        index = i
    let dragIndex = -1
    let hoverIndex = -1
    dataSource.forEach((item, i) => {
      if (item.key === dragId) {
        dragIndex = i
      } else if (item.key === hoverId) {
        hoverIndex = i
      }
      return item.key !== record.key
    })
    if ((index === 0 && direction === 'up') || (index === dataSource.length - 1 && direction === 'down')) {
      return
    }
    if (dragIndex === -1 || hoverIndex === -1) return
    if (direction === 'up') {
      _data.splice(index - 1, 0, record)
    } else {
      _data.splice(index + 1, 0, record)
    }
    let _data = fromJS(dataSource).toJS()
    _data.splice(hoverIndex, 0, ..._data.splice(dragIndex, 1))
    this.setState({
      dataSource: _data
@@ -150,13 +184,14 @@
    })
  }
  handleHide = (record) => {
  handleHide = (key) => {
    let _data = this.state.dataSource.map(item => {
      if (item.key === record.key) {
      if (item.key === key) {
        item.Hide = !item.Hide
      }
      return item
    })
    this.setState({
      dataSource: _data
    }, () => {
@@ -164,7 +199,7 @@
    })
  }
  handleDelete = key => {
  handleDelete = (key) => {
    const { dataSource } = this.state
    let _data = dataSource.filter(item => item.key !== key)
@@ -173,22 +208,26 @@
    })
  }
  handleAdd = (e) => {
    e.stopPropagation()
    const { linkSubFields } = this.props
  handleAdd = () => {
    const { columns } = this.props
    const { count, dataSource } = this.state
    const newData = {
      key: Utils.getuuid(),
      Value: `${count}`,
      Text: `${count}`,
      ParentID: ''
    }
    linkSubFields.forEach(m => {
      newData[m] = newData[m] || ''
    let item = { key: Utils.getuuid() }
    columns.forEach(m => {
      item[m.key] = ''
    })
    let _data = [...dataSource, newData]
    if (item.Value === '') {
      item.Value = `${count + 1}`
    }
    if (item.$value === '') {
      item.$value = `${count + 1}`
    }
    item.Text = `${count + 1}`
    let _data = [...dataSource, item]
    this.setState({
      dataSource: _data,
@@ -199,18 +238,49 @@
  }
  handleSave = row => {
    const { type } = this.props
    const { columns, type } = this.props
    const newData = [...this.state.dataSource]
    const index = newData.findIndex(item => row.key === item.key)
    const item = newData[index]
    if (type === 'link') {
      if (newData.filter(m => row.key !== m.key && row.Value === m.Value && row.ParentID === m.ParentID).length > 0) {
        message.warning('相同ParentID下,此Value值已存在!')
      }
    if (type === 'proc') {
      // if (!row.origin || /^\s+$/.test(row.origin)) {
      //   message.warning(columns[0].title + '为空时无效!')
      // }
    } else {
      if (newData.filter(m => row.key !== m.key && row.Value === m.Value).length > 0) {
        message.warning('此Value值已存在!')
      let val = ''
      let repeat = false
      let _type = ''
      columns.forEach(col => {
        if (!col.strict) return
        if (col.key === 'ParentID') {
          _type = 'mutil'
        }
        val += row[col.key]
      })
      newData.forEach(item => {
        if (row.key === item.key) return
        let _val = ''
        columns.forEach(col => {
          if (!col.strict) return
          _val += item[col.key]
        })
        if (val === _val) {
          repeat = true
        }
      })
      if (repeat) {
        if (_type === 'mutil') {
          message.warning('相同ParentID下,此Value值已存在!')
        } else {
          message.warning('此Value值已存在!')
        }
      }
    }
@@ -223,112 +293,83 @@
    })
  }
  getColumns = (type, linkSubFields, dataSource) => {
    const { transfield } = this.props
  getColumns = () => {
    const { columns } = this.props
    let _dataSource = fromJS(dataSource).toJS()
    let fields = []
    let subFields = linkSubFields.filter(m => m !== 'Value' && m !== 'Text')
    if (subFields.length > 0) {
      _dataSource = _dataSource.map(data => {
        subFields.forEach(n => {
          if (data[n] !== undefined) return
          data[n] = data.Text || ''
        })
        return data
    let fields = [{
      title: ' ',
      width: '60px',
      dataIndex: '$move',
      onCell: (record) => ({
        index: record.key,
        dataIndex: '$move',
        moveRow: this.moveRow
      })
      fields = subFields.map(field => {
        return {
          title: transfield[field] || field,
          $title: transfield[field] || field,
          dataIndex: field,
    }]
    columns.forEach(n => {
      let col = {
        title: n.title,
        dataIndex: n.key,
        onCell: record => ({
          record,
          editable: true,
        }
      })
    }
    let columns = [
      {
        title: 'Value',
        $title: 'Value',
        dataIndex: 'Value',
        editable: true
      },
      {
        title: 'Text',
        $title: 'Text',
        dataIndex: 'Text',
        editable: true
      },
      ...fields,
      {
        title: '操作',
        align: 'center',
        width: '20%',
        dataIndex: 'operation',
        render: (text, record) =>
          this.state.dataSource.length >= 1 ? (
            <div style={{fontSize: '15px'}}>
              <span className="operation-btn" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><ArrowUpOutlined /></span>
              <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><ArrowDownOutlined /></span>
              <span className="operation-btn" title="显示/隐藏" onClick={() => this.handleHide(record)} style={{color: 'rgb(142, 68, 173)'}}><SwapOutlined /></span>
              <Popconfirm
                title="确定删除吗?"
                overlayClassName="popover-confirm"
                onConfirm={() => this.handleDelete(record.key)
              }>
                <span style={{color: '#ff4d4f', cursor: 'pointer'}}><DeleteOutlined /></span>
              </Popconfirm>
            </div>
          ) : null,
          inputType: n.type || 'text',
          dataIndex: n.key,
          handleSave: this.handleSave
        })
      }
    ]
    if (type === 'link') {
      columns.unshift({
        title: 'ParentID',
        $title: 'ParentID',
        dataIndex: 'ParentID',
        editable: true
      })
    }
      if (n.width) {
        col.width = n.width
      }
      if (n.fixed) {
        delete col.onCell
      }
    return {
      columns: columns.map(col => {
        if (col.dataIndex !== 'operation') {
          col.title = <div>
            {col.$title}
      fields.push(col)
    })
    fields.push({
      title: '操作',
      align: 'center',
      width: '110px',
      dataIndex: 'operation',
      render: (text, record) =>
        (
          <div style={{fontSize: '15px'}}>
            <span className="operation-btn" title="显示/隐藏" onClick={() => this.handleHide(record.key)} style={{color: 'rgb(142, 68, 173)'}}><SwapOutlined /></span>
            <Popconfirm
              title="确定删除吗?"
              overlayClassName="popover-confirm"
              onConfirm={() => this.handleDelete(record.key)
            }>
              <span style={{color: '#ff4d4f', cursor: 'pointer'}}><DeleteOutlined /></span>
            </Popconfirm>
          </div>
        }
        return col
      }),
      dataSource: _dataSource
    }
        )
    })
    return fields
  }
  handleEmpty = (e) => {
    e.stopPropagation()
    const { linkSubFields, module } = this.props
  handleEmpty = () => {
    const { columns, module } = this.props
    const { dataSource } = this.state
    if (dataSource.filter(item => item.Value === '').length > 0) {
      message.warning('Value为空已存在!')
      return
    }
    const newData = {
      key: Utils.getuuid(),
      Value: '',
      Text: module === 'form' ? '空' : '全部',
      ParentID: ''
    }
    linkSubFields.forEach(m => {
      newData[m] = newData[m] || ''
    let item = { key: Utils.getuuid() }
    columns.forEach(m => {
      item[m.key] = ''
    })
    let _data = [newData, ...dataSource]
    item.Text = module === 'form' ? '空' : '全部'
    let _data = [item, ...dataSource]
    this.setState({
      dataSource: _data,
@@ -337,65 +378,57 @@
    })
  }
  resetColumn = (type, linkSubFields) => {
    const { columns, dataSource } = this.getColumns(type, linkSubFields, this.state.dataSource)
  resetColumn = () => {
    const { columns, value } = this.props
    let data = fromJS(value).toJS().map(item => {
      columns.forEach(n => {
        if (item[n.key] !== undefined) return
        item[n.key] = ['ParentID', '$url', '$color', '$value'].includes(n.key) ? '' : item.Text || ''
      })
      return item
    })
    if (!is(fromJS(dataSource), fromJS(this.state.dataSource))) {
      this.setState({
        columns,
        dataSource
      }, () => {
        this.props.onChange(dataSource)
      })
    } else {
      this.setState({
        columns
      })
    }
    this.setState({
      columns: this.getColumns(),
      dataSource: data,
      count: data.length
    }, () => {
      this.props.onChange(data)
    })
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.linkSubFields), fromJS(nextProps.linkSubFields)) || this.props.type !== nextProps.type) {
      this.resetColumn(nextProps.type, nextProps.linkSubFields)
    if (!is(fromJS(this.props.columns), fromJS(nextProps.columns))) {
      this.setState({}, () => {
        this.resetColumn()
      })
    }
  }
  render() {
    const { module } = this.props
    const { dataSource } = this.state
    const { dataSource, columns } = this.state
    const components = {
      body: {
        row: EditableFormRow,
        cell: EditableCell
      }
    }
    const columns = this.state.columns.map(col => {
      if (!col.editable) {
        return col
      }
      return {
        ...col,
        onCell: record => ({
          record,
          editable: col.editable,
          dataIndex: col.dataIndex,
          title: col.title,
          handleSave: this.handleSave
        })
      }
    })
    return (
      <div className="common-modal-edit-table">
        <span className="add-row add-row-empty" onClick={this.handleEmpty}>{module === 'form' ? '空' : '全部'}</span>
        {module ? <span className="add-row add-row-empty" onClick={this.handleEmpty}>{module === 'form' ? '空' : '全部'}</span> : null}
        <PlusOutlined className="add-row" onClick={this.handleAdd} />
        <Table
          components={components}
          rowClassName={(record) => record.Hide ? 'editable-row hide' : 'editable-row'}
          bordered
          dataSource={dataSource}
          columns={columns}
          pagination={false}
        />
        <DndProvider>
          <Table
            components={components}
            rowClassName={(record) => record.Hide ? 'editable-row hide' : 'editable-row'}
            bordered
            dataSource={dataSource}
            columns={columns}
            pagination={false}
          />
        </DndProvider>
      </div>
    )
  }
src/templates/zshare/modalform/modaleditable/index.scss
@@ -15,6 +15,15 @@
    color: #1890ff;
    cursor: pointer;
  }
  .mk-move-col {
    text-align: center;
    font-size: 16px;
    cursor: move;
    color: #c8c8c8;
  }
  .mk-source-wrap {
    min-width: 150px;
  }
  .ant-table-thead > tr > th {
    padding: 10px 16px;
    position: relative;
@@ -23,7 +32,6 @@
      position: absolute;
      right: 12px;
      font-size: 14px;
      // top: 12px;
      color: #b8b8b8;
    }
  }
@@ -52,7 +60,7 @@
    }
  }
  .operation-btn {
    margin-right: 10px;
    margin-right: 15px;
    cursor: pointer;
  }
  .editable-row.hide {
src/templates/zshare/verifycard/baseform/index.jsx
@@ -279,7 +279,7 @@
  }
  render() {
    const { unionFields, verify, notes, card, appType } = this.props
    const { unionFields, verify, notes, card, appType, columns } = this.props
    const { wxTemps, selectTemp } = this.state
    const formItemLayout = {
      labelCol: {
@@ -290,6 +290,17 @@
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    let _columns = []
    if (window.GLOB.process) {
      _columns = columns.filter(col => {
        if (!col.field) return false
        if (col.field.toLowerCase() === 'id') return false
        if (col.type === 'text' && col.fieldlength > 100)  return false
        return true
      })
    }
    return (
@@ -462,6 +473,22 @@
              </Radio.Group>
            </Form.Item>
          </Col> : null}
          {window.GLOB.process && verify.workFlow === 'true' && verify.flowType === 'approval' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title="如果审批存在多条分支,可添加审批流程的控制字段,通过行信息控制流程走向。注:需在流程图中完善分支的执行条件。">
                <QuestionCircleOutlined className="mk-form-tip" />
                流程控制
              </Tooltip>
            }>
              <Select allowClear value={verify.flowBranch} onChange={(val) => {this.onOptionChange(val || '', 'flowBranch')}}>
                {_columns.map(option =>
                  <Select.Option key={option.field} value={option.field}>
                    {option.label}
                  </Select.Option>
                )}
              </Select>
            </Form.Item>
          </Col> : null}
          <Col span={24}></Col>
          <Col span={8}>
            <Form.Item label={
src/templates/zshare/verifycard/index.jsx
@@ -626,7 +626,7 @@
      oriVerify: fromJS(_verify).toJS()
    })
    if (config.Template !== 'FormTab' && card.intertype === 'inner') {
    if (card.intertype === 'inner') {
      return
    }
@@ -637,11 +637,6 @@
          field: card.field,
          label: card.label,
          type: 'text'
        })
        resolve(_fields)
      } else if (config.Template === 'FormTab') {
        config.groups.forEach(group => {
          _fields.push(...group.sublist)
        })
        resolve(_fields)
      } else if (card.modal && (card.OpenType === 'pop' || !card.OpenType)) {
@@ -1553,7 +1548,7 @@
  }
  render() {
    const { card } = this.props
    const { card, columns } = this.props
    const { activeKey, verifyInter, setting, verify, fields, uniqueFields, uniqueColumns, unionFields, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, cbScriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes, appType } = this.state
    const formItemLayout = {
      labelCol: {
@@ -1576,7 +1571,7 @@
              {verify.default === 'false' ? <span className="count-tip"><ExclamationOutlined style={{color: 'orange'}}/></span> : null}
            </span>
          } key="base">
            <BaseForm card={card} appType={appType} unionFields={unionFields} setting={setting} verify={verify} notes={notes} onChange={(verify) => this.setState({verify})} wrappedComponentRef={(inst) => this.baseForm = inst}/>
            <BaseForm card={card} appType={appType} columns={columns} unionFields={unionFields} setting={setting} verify={verify} notes={notes} onChange={(verify) => this.setState({verify})} wrappedComponentRef={(inst) => this.baseForm = inst}/>
          </TabPane> : null}
          {verifyInter === 'system' ? <TabPane tab={
            <span>
@@ -1612,7 +1607,7 @@
              fields={fields}
              btn={this.props.card}
              billcodes={verify.billcodes}
              columns={this.props.columns}
              columns={columns}
              modular={orderModular}
              modularDetail={orderModularDetail}
              orderChange={this.orderChange}
@@ -1641,7 +1636,7 @@
          } key="voucher">
            <VoucherForm
              voucher={voucher}
              columns={this.props.columns}
              columns={columns}
              voucherobj={verify.voucher}
              voucherDetail={voucherDetail}
              voucherChange={this.voucherChange}
src/utils/utils-custom.js
@@ -919,6 +919,13 @@
    if (item.setting && item.setting.supModule && item.setting.supModule[0] !== 'empty') {
      item.setting.supModule = ''
    }
    if (item.wrap && item.wrap.supType === 'multi') {
      item.wrap.supType = 'single'
      delete item.supNodes
    }
    if (item.wrap && item.wrap.supModule) {
      item.wrap.supModule = ''
    }
@@ -1546,6 +1553,11 @@
    } else if (card.type !== 'balcony' && !card.setting.supModule) {  // 悬浮框上级组件需单独设置
      errors.push({ level: 0, detail: '未设置上级组件!'})
    }
    if (card.subtype === 'dualdatacard' && card.subColumns) {
      card.subColumns.forEach(col => {
        columns.push(col.field)
      })
    }
  } else if ((card.type === 'balcony' || card.type === 'card') && card.wrap.datatype === 'public') {
    columns = card.columns.map(c => c.field)
  }
@@ -1553,6 +1565,31 @@
  let doubleClick = ''
  if (card.type === 'table') {
    doubleClick = card.wrap.doubleClick || ''
  }
  let checkBtn = (cell) => {
    if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
      if (!cell.modal || cell.modal.fields.length === 0) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
      }
    } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
      errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
    } else if (cell.OpenType === 'excelOut') {
      if (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom' && card.$c_ds && columns.length > 0) {
        let cols = []
        cell.verify.columns.forEach(col => {
          if (col.output === 'false' || col.Column === '$Index') return
          if (!columns.includes(col.Column)) {
            cols.push(col.Column)
          }
        })
        if (cols.length) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列(${cols.join('、')})在字段集中不存在!`})
        }
      }
    }
  }
  if (card.$c_ac) {
@@ -1565,15 +1602,7 @@
      //     errors.push({ level: 0, detail: `按钮“${cell.label}”中弹窗标签未启用`})
      //   }
      // }
      if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
        if (!cell.modal || cell.modal.fields.length === 0) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
        }
      } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
      } else if (cell.OpenType === 'excelOut' && (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0)) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
      }
      checkBtn(cell)
      if (doubleClick === cell.uuid) {
        doubleClick = ''
      }
@@ -1586,15 +1615,7 @@
      item.elements.forEach(cell => {
        if (cell.eleType === 'button') {
          if (cell.hidden === 'true') return
          if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
            if (!cell.modal || cell.modal.fields.length === 0) {
              errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
            }
          } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
            errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
          } else if (cell.OpenType === 'excelOut' && (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0)) {
            errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
          }
          checkBtn(cell)
          if (linkbtn && linkbtn === cell.uuid) {
            linkbtn = ''
          }
@@ -1607,15 +1628,7 @@
        item.backElements.forEach(cell => {
          if (cell.eleType === 'button') {
            if (cell.hidden === 'true') return
            if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
              if (!cell.modal || cell.modal.fields.length === 0) {
                errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
              }
            } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
              errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
            } else if (cell.OpenType === 'excelOut' && (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0)) {
              errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
            }
            checkBtn(cell)
            if (linkbtn && linkbtn === cell.uuid) {
              linkbtn = ''
            }
@@ -1639,15 +1652,7 @@
    card.elements.forEach(cell => {
      if (cell.eleType === 'button') {
        if (cell.hidden === 'true') return
        if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
          if (!cell.modal || cell.modal.fields.length === 0) {
            errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
          }
        } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
        } else if (cell.OpenType === 'excelOut' && (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0)) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
        }
        checkBtn(cell)
      } else if (cell.datatype === 'dynamic' && cell.field && !columns.includes(cell.field)) {
        errors.push({ level: 1, detail: `卡片中动态字段“${cell.field}”无效`})
      }
@@ -1660,15 +1665,8 @@
        col.elements.forEach(cell => {
          if (cell.eleType === 'button') {
            if (cell.hidden === 'true') return
            if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
              if (!cell.modal || cell.modal.fields.length === 0) {
                errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
              }
            } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
              errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
            } else if (cell.OpenType === 'excelOut' && (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0)) {
              errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
            }
            checkBtn(cell)
            if (doubleClick === cell.uuid) {
              doubleClick = ''
src/utils/utils-datamanage.js
@@ -212,7 +212,14 @@
    }
    if (_customScript) {
      if (LText) {
      if (DateCount) {
        DateCount = `${DateCount}
          ${_tailScript}
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,'${sessionStorage.getItem('UserID') || ''}'
        `
      } else if (LText) {
        LText = `${LText}
          ${_tailScript}
          aaa:
@@ -227,6 +234,17 @@
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,'${sessionStorage.getItem('UserID') || ''}' 
        `
      }
    } else if (_tailScript && DateCount) {
      LText = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100)
        Select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}'
        ${LText}
      `
      DateCount = `${DateCount}
        ${_tailScript}
        aaa:
        if @ErrorCode!=''
          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,'${sessionStorage.getItem('UserID') || ''}'
      `
    } else if (_tailScript) {
      LText = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100)
        Select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}'
@@ -247,6 +265,7 @@
    if (window.GLOB.debugger === true) {
      _customScript && console.info(`${setting.$name ? `/*${setting.$name} 自定义脚本*/\n` : ''}${LText ? '' : '/*不执行默认sql*/\n'}${_customScript}`)
      LText && console.info(`${setting.$name ? `/*${setting.$name} 数据源*/\n` : ''}` + LText.replace(/\n\s{8}/ig, '\n'))
      DateCount && console.info(`${setting.$name ? `/*${setting.$name} 总数查询*/\n` : ''}` + DateCount.replace(/\n\s{8}/ig, '\n'))
    }
    if (setting.$name) {
src/utils/utils.js
@@ -1,3 +1,4 @@
import React from 'react'
import moment from 'moment'
import md5 from 'md5'
@@ -2117,6 +2118,7 @@
    let status = 0
    let statusName = ''
    let detailId = ''
    let error = ''
    if (verify.flowType === 'start') {
      target = flow.cells.filter(cell => cell.mknode === 'start')[0]
@@ -2125,17 +2127,112 @@
        detailId = target.id
        status = target.mkdata.status
        statusName = target.mkdata.statusName
      } else {
        error = '工作流无开始节点'
      }
    } else if (_data.works_flow_param) {
      node = JSON.parse(window.decodeURIComponent(window.atob(_data.works_flow_param)))
      try {
        node = JSON.parse(window.decodeURIComponent(window.atob(_data.works_flow_param)))
      } catch (e) {
        node = null
      }
      if (node) {
        let lines = flow.cells.filter(cell => cell.shape === 'edge' && cell.source.cell === node.id)
        if (verify.flowType === 'reject') {
          line = lines.filter(cell => cell.mkdata.flowType === 'reject' || cell.mknode === 'startEdge')[0]
        } else {
          line = lines.filter(cell => cell.mkdata.flowType !== 'reject' && cell.mknode !== 'startEdge')[0]
          let endEdge = null
          lines = lines.filter(cell => {
            if (cell.mknode === 'endEdge') {
              endEdge = cell
              return false
            }
            return cell.mkdata.flowType !== 'reject' && cell.mknode !== 'startEdge'
          })
          if (lines.length === 0) {
            if (!endEdge) {
              error = '无可执行的流程分支'
            } else {
              line = endEdge
            }
          } else {
            let branchKey = verify.flowBranch ? verify.flowBranch.toLowerCase() : ''
            if (!branchKey) {
              lines.forEach(line => {
                if (line.mkdata.execCondition === 'open') {
                  error = '按钮未设置流程控制字段。'
                }
              })
              if (!error) {
                line = lines[0]
              }
            } else if (!_data.hasOwnProperty(branchKey)) {
              error = '行信息中无流程控制字段。'
            } else {
              if (endEdge) {
                line = endEdge
              }
              let equalLine = null
              let gtOrLtLine = []
              let unEqualLine = null
              let branchVal = _data[branchKey]
              if (branchVal && typeof(branchVal) === 'string' && !isNaN(branchVal)) {
                branchVal = +branchVal
              }
              lines.forEach(item => {
                if (item.mkdata.execCondition !== 'open') {
                  line = item
                } else {
                  if (item.mkdata.match === '=') {
                    if (item.mkdata.matchVal === branchVal + '') {
                      equalLine = item
                    }
                  } else if (item.mkdata.match === '!=') {
                    if (item.mkdata.matchVal !== branchVal + '') {
                      unEqualLine = item
                    }
                  } else {
                    if (item.mkdata.match === '<') {
                      if (item.mkdata.matchVal < branchVal) {
                        gtOrLtLine.push({...item, dist: Math.abs(item.mkdata.matchVal - branchVal)})
                      }
                    } else if (item.mkdata.match === '>') {
                      if (item.mkdata.matchVal > branchVal) {
                        gtOrLtLine.push({...item, dist: Math.abs(item.mkdata.matchVal - branchVal)})
                      }
                    } else if (item.mkdata.match === '<=') {
                      if (item.mkdata.matchVal <= branchVal) {
                        gtOrLtLine.push({...item, dist: Math.abs(item.mkdata.matchVal - branchVal)})
                      }
                    } else if (item.mkdata.match === '>=') {
                      if (item.mkdata.matchVal >= branchVal) {
                        gtOrLtLine.push({...item, dist: Math.abs(item.mkdata.matchVal - branchVal)})
                      }
                    }
                  }
                }
              })
              if (equalLine) {
                line = equalLine
              } else if (gtOrLtLine.length > 0) {
                gtOrLtLine.sort((a, b) => a.dist - b.dist)
                line = gtOrLtLine[0]
              } else if (unEqualLine) {
                line = unEqualLine
              }
            }
          }
        }
      } else {
        error = '行信息中工作流参数无法解析'
      }
      
      if (line) {
@@ -2143,7 +2240,11 @@
        status = line.mkdata.status
        statusName = line.mkdata.statusName
        target = flow.cells.filter(cell => cell.id === line.target.cell)[0]
      } else if (!error) {
        error = '工作流中无对应流程'
      }
    } else {
      error = '行信息中无工作流参数'
    }
    if (verify.flowSql === 'true' && target) {
@@ -2184,20 +2285,12 @@
      `
      }
    } else if (verify.flowSql === 'true') {
      target = flow.cells.filter(cell => cell.mknode === 'start')[0]
      if (target) {
        detailId = target.id
      }
      status = 0
      statusName = '异常'
      _sql += `
      /* 工作流异常sql */
      update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
      where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
      insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
      select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
      select @ErrorCode='E',@retmsg='${error || '工作流执行异常'}' goto aaa
      `
    }
@@ -2302,10 +2395,7 @@
 * @description 获取标记信息
 */
export function getMark (marks, record, style = {}) {
  let icon = null
  let innerStyle = null
  let position = null
  let signType = ''
  let res = {}
  style = JSON.parse(JSON.stringify(style))
  marks.some(mark => {
@@ -2342,42 +2432,45 @@
    if (type === 'font') {
      style.color = mark.color
      innerStyle = {color: mark.color}
      signType = ' sign-font'
      res.innerStyle = {color: mark.color}
      res.signType = ' sign-font'
    } else if (type === 'background') {
      style.backgroundColor = mark.color
      if (mark.fontColor) {
        style.color = mark.fontColor
        innerStyle = {color: mark.fontColor}
        res.innerStyle = {color: mark.fontColor}
      }
    } else if (type === 'underline') {
      style.textDecoration = 'underline'
      style.color = mark.color
      innerStyle = {color: mark.color, textDecoration: 'underline'}
      res.innerStyle = {color: mark.color, textDecoration: 'underline'}
    } else if (type === 'line-through') {
      style.textDecoration = 'line-through'
      style.color = mark.color
      innerStyle = {color: mark.color, textDecoration: 'line-through'}
      res.innerStyle = {color: mark.color, textDecoration: 'line-through'}
    } else if (type.indexOf('icon') > -1) {
      icon = mark.signType[mark.signType.length - 1]
      innerStyle = {color: mark.color}
      res.icon = mark.signType[mark.signType.length - 1]
      res.innerStyle = {color: mark.color}
      if (type === 'iconfront' || mark.signType[1] === 'front') {
        position = 'front'
        res.position = 'front'
      } else {
        position = 'back'
        res.position = 'back'
      }
    } else if (type === 'indent') {
      style.color = mark.color
      res.space = Array(mark.signType[1] + 1).join('&nbsp;')
    } else if (type === 'pointfront') {
      res.position = 'front'
      res.point = <span style={{display: 'inline-block', marginRight: '3px', width: '8px', height: '8px', borderRadius: '14px', background: mark.color, verticalAlign: 'middle'}}></span>
    } else if (type === 'pointback') {
      res.position = 'back'
      res.point = <span style={{display: 'inline-block', marginLeft: '3px', width: '8px', height: '8px', borderRadius: '14px', background: mark.color, verticalAlign: 'middle'}}></span>
    }
    return true
  })
  return {
    style,
    icon,
    innerStyle,
    position,
    signType
  }
  return res
}
/**
src/views/systemproc/proc/index.jsx
@@ -6,6 +6,7 @@
import Utils from '@/utils/utils.js'
import Api from '@/api'
import CodeMirror from '@/templates/zshare/codemirror'
import Transfer from '../transfer'
import './index.scss'
const { confirm } = Modal
@@ -379,6 +380,7 @@
              {!inputing ? <Search placeholder="请输入存储过程名称" defaultValue={procName} disabled={loading} enterButton="确定" onSearch={this.search}/> : null}
            </div>
            <div className="action-wrap">
              {!procName || loading || !content ? null : <Transfer procName={procName} content={content} />}
              <Button key="save" className="mk-btn mk-green" disabled={loading} onClick={() => this.save()}>保存</Button>
              <Button key="prev" className="mk-btn mk-primary" disabled={!procName || loading} onClick={this.prev}>上一版本</Button>
              <Button key="next" className="mk-btn mk-primary" disabled={!procName || loading} onClick={this.next}>下一版本</Button>
src/views/systemproc/transfer/index.jsx
New file
@@ -0,0 +1,289 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Modal, notification, Form, Select } from 'antd'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const EditTable = asyncComponent(() => import('@/templates/zshare/modalform/modaleditable'))
class TransferWrap extends Component {
  static propTpyes = {
    MenuID: PropTypes.string
  }
  state = {
    visible: false,
    loading: false,
    VersionName: '',
    translist: [],
    options: []
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  verifySubmit = () => {
    const { content, procName } = this.props
    const { VersionName, options } = this.state
    let value = content.replace(/^(\s*)|(\s*)$/ig, '')
    if (!VersionName) {
      notification.warning({
        top: 92,
        message: '请选择传输号',
        duration: 5
      })
      return
    } else if (!value) {
      notification.warning({
        top: 92,
        message: '存储过程不可为空',
        duration: 5
      })
      return
    }
    let regs = []
    options.forEach(item => {
      if (item.origin && !/^\s+$/.test(item.origin) && item.origin !== item.value) {
        regs.push({reg: new RegExp(item.origin, 'g'), value: item.value})
      }
    })
    regs.forEach(item => {
      value = value.replace(item.reg, item.value)
    })
    let chars = [
      {key: 'drop', reg: /(^|\s)drop\s/ig},
      {key: 'alter', reg: /(^|\s)alter\s/ig},
      {key: 'object', reg: /(^|\s)object(\s|\()/ig},
      {key: 'kill', reg: /(^|\s)kill\s/ig},
      {key: '--', reg: /--/ig},
      {key: ',,', reg: /,,/ig}
    ]
    let error = ''
    if (!/create(\s+)proc/ig.test(value)) {
      error = '脚本中必须使用create proc'
    }
    chars.forEach(char => {
      if (!error && char.reg.test(value)) {
        error = '不可使用' + char.key
      }
    })
    if (error) {
      notification.warning({
        top: 92,
        message: error,
        duration: 5
      })
      return
    }
    let dropfunc = `IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('${procName}') AND type in (N'P', N'PC'))  mdrpk PROCEDURE ${procName}`
    let dropParam = {
      func: 's_sVersionDetail_Add',
      BID: VersionName,
      VType: 'VSQL',
      VSQL: window.btoa(window.encodeURIComponent(dropfunc))
    }
    let addParam = {
      func: 's_sVersionDetail_Add',
      BID: VersionName,
      VType: 'VSQL',
      VSQL: window.btoa(window.encodeURIComponent(value))
    }
    this.setState({
      loading: true
    })
    Api.genericInterface(dropParam).then(result => {
      if (!result.status) {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
        this.setState({
          loading: false
        })
        return
      }
      delete result.status
      delete result.message
      delete result.ErrCode
      delete result.ErrMesg
      result.func = 's_sVersionDetail_CloudAdd'
      Api.genericInterface(addParam).then(res => {
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          this.setState({
            loading: false
          })
          return
        }
        delete res.status
        delete res.message
        delete res.ErrCode
        delete res.ErrMesg
        res.func = 's_sVersionDetail_CloudAdd'
        Api.getCloudConfig(result).then(re => {
          if (!re.status) {
            notification.warning({
              top: 92,
              message: re.message,
              duration: 5
            })
            this.setState({
              loading: false
            })
            return
          }
          Api.getCloudConfig(res).then(r => {
            if (!r.status) {
              notification.warning({
                top: 92,
                message: r.message,
                duration: 5
              })
              this.setState({
                loading: false
              })
              return
            } else {
              notification.success({
                top: 92,
                message: '添加成功!',
                duration: 3
              })
              this.setState({
                loading: false,
                visible: false
              })
            }
          })
        })
      })
    })
  }
  getTransList = () => {
    const { content } = this.props
    let value = content.replace(/^(\s*)|(\s*)$/ig, '')
    if (!value) {
      notification.warning({
        top: 92,
        message: '存储过程不可为空',
        duration: 5
      })
      return
    }
    let param = {
      func: 's_get_sVersion',
      dataM: 'Y',
      PageSize: 9999,
      PageIndex: 1,
      OrderCol: 'ID desc'
    }
    let options = []
    let list = value.match(/\s+[a-z0-9_]+\.(dbo)?\./ig)
    list && list.forEach(str => {
      str = str.replace(/^\s/, '')
      options.push({
        key: Utils.getuuid(),
        origin: str,
        value: str
      })
    })
    this.setState({
      options: options,
      VersionName: '',
      visible: true,
      loading: false
    })
    Api.getCloudConfig(param).then(result => {
      if (result.status) {
        this.setState({
          translist: result.data
        })
      } else {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  changeOptions = (value) => {
    this.setState({options: value})
  }
  render () {
    const { visible, loading, translist, options } = this.state
    const columns = [{ title: '原信息', key: 'origin', width: '50%', fixed: true }, { title: '替换为', width: '50%', key: 'value' }]
    return (
      <>
        <Button icon="pull-request" className="mk-border-green" onClick={this.getTransList}>传输号</Button>
        <Modal
          title="加入传输号"
          wrapClassName="proc-transfer"
          visible={visible}
          width={900}
          maskClosable={false}
          okText="确定"
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          confirmLoading={loading}
          destroyOnClose
        >
          <Form.Item label="传输号">
            <Select onChange={(val) => this.setState({VersionName: val})}>
              {translist.map(option =>
                <Select.Option key={option.VersionName} value={option.VersionName}>{`${option.ProgramName}(${option.VersionName})`}</Select.Option>
              )}
            </Select>
          </Form.Item>
          {options.length > 0 ? <DndProvider backend={HTML5Backend}>
            <Form.Item label="替换项">
              <EditTable type="proc" columns={columns} value={options} onChange={this.changeOptions}/>
            </Form.Item>
          </DndProvider> : null}
        </Modal>
      </>
    )
  }
}
export default TransferWrap
src/views/systemproc/transfer/index.scss
New file
@@ -0,0 +1,18 @@
.proc-transfer {
  .ant-form-item {
    display: flex;
    .ant-form-item-control-wrapper {
      flex: 10;
      .ant-select {
        width: 300px;
      }
    }
  }
  .operation-btn {
    display: none;
  }
  .add-row {
    display: none;
  }
}
src/views/tabledesign/source.jsx
@@ -186,6 +186,18 @@
    },
    {
      type: 'col',
      label: '自定义列',
      subType: 'custom',
      $init: true
    },
    {
      type: 'col',
      label: '公式',
      subType: 'formula',
      $init: true
    },
    {
      type: 'col',
      label: '图片',
      subType: 'picture',
      $init: true
@@ -210,20 +222,8 @@
    },
    {
      type: 'col',
      label: '自定义列',
      subType: 'custom',
      $init: true
    },
    {
      type: 'col',
      label: '合并列',
      subType: 'colspan',
      $init: true
    },
    {
      type: 'col',
      label: '公式',
      subType: 'formula',
      $init: true
    },
    {