king
2023-10-01 437c6d72f76072e5ab1b09e78101370805113c4b
Merge branch 'master' into positec
57个文件已修改
2个文件已删除
4612 ■■■■■ 已修改文件
src/api/index.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/group/paste/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/dragsearch/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.jsx 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/paste/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/customscript/index.jsx 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.jsx 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.scss 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/utils.jsx 84 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/debug/index.jsx 1995 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/debug/index.scss 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/search/single-search/options.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/settingform/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/basetable/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/index.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/exceloutbutton/index.jsx 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/fileupload/index.jsx 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 86 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/fieldscomponent/editcard/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/fieldscomponent/editcard/index.scss 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/fieldscomponent/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/index.jsx 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx 500 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.scss 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx 109 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/tablecomponent/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/customscript/index.jsx 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/callbackcustomscript/index.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customform/index.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customscript/index.jsx 81 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 144 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/menuelement/index.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js
@@ -743,7 +743,7 @@
    }
  }
  visitOuterSystem (param, _resolve) {
  visitOuterSystem (param, _resolve, _reject) {
    let token = param.$token
    delete param.$token
@@ -799,6 +799,8 @@
        data: JSON.stringify(param)
      }).then(res => {
        _resolve(res)
      }, () => {
        _reject()
      })
    } else {
      let _param = {
@@ -846,9 +848,22 @@
            data: JSON.stringify(param)
          }).then(res => {
            _resolve(res)
          }, () => {
            _reject()
          })
        } else {
          _resolve(result)
        }
      }, (e) => {
        if (!e || !e.status) {
          let msg = '网络连接不正常。'
          if (/^http:/.test(token.interface) && /https:/.test(window.location.protocol)) {
            msg = '网络连接不正常,接口地址可能不支持https。'
          }
          _resolve({status: false, ErrCode: 'E', message: msg})
        } else {
          _reject()
        }
      })
    }
@@ -868,7 +883,7 @@
    if (param.$token === '') {
      return Promise.resolve({status: false, ErrCode: 'token_error', message: '接口地址尚未设置!'})
    } else if (param.$token) {
      return new Promise(resolve => this.visitOuterSystem(param, resolve))
      return new Promise((resolve, reject) => this.visitOuterSystem(param, resolve, reject))
    }
    if (['sPC_TableData_InUpDe', 'sPC_TableData_InUpDe_debug'].includes(param.func)) {
@@ -928,6 +943,17 @@
          } else {
            resolve(res)
          }
        }, (e) => {
          if (!e || !e.status) {
            let msg = '网络连接不正常。'
            if (/^http:/.test(rduri) && /https:/.test(window.location.protocol)) {
              msg = '网络连接不正常,接口地址可能不支持https。'
            }
            resolve({status: false, ErrCode: 'E', message: msg})
          } else {
            reject()
          }
        })
      })
    } else {
src/menu/components/form/simple-form/index.jsx
@@ -539,6 +539,7 @@
    _card.subcards[0].setting.align = _card.wrap.align
    _card.subcards[0].setting.enable = _card.wrap.enable
    _card.subcards[0].setting.verticalSpace = _card.wrap.verticalSpace
    _card.subcards[0].subButton.enable = _card.wrap.enable
    if (_card.wrap.closeEnable === 'true' && !_card.subcards[0].closeButton) {
      _card.subcards[0].closeButton = {label: '关闭', enable: 'true', type: 'close', style: {backgroundColor: '#ffffff', color: 'rgba(0,0,0,0.65)', borderColor: '#d9d9d9', borderWidth: '1px', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px', marginLeft: '10px'}}
src/menu/components/group/paste/index.jsx
@@ -20,7 +20,7 @@
  pasteSubmit = () => {
    let appType = sessionStorage.getItem('appType')
    let options = ['datacard', 'propcard', 'balcony', 'timeline', 'simpleform', 'stepform', 'tabform', 'normaltable', 'tablecard', 'editor', 'line', 'bar', 'pie', 'scatter', 'sandbox']
    let options = ['datacard', 'propcard', 'balcony', 'timeline', 'simpleform', 'stepform', 'tabform', 'basetable', 'normaltable', 'tablecard', 'editor', 'line', 'bar', 'pie', 'scatter', 'sandbox']
    let types = {
      login: '登录',
      navbar: '导航栏',
@@ -53,6 +53,11 @@
        return
      }
      if (res.copyType === 'basetable') {
        res.copyType = 'normaltable'
        res.subtype = 'normaltable'
      }
      res = MenuUtils.resetComponentConfig(res, appType)
      delete res.copyType
src/menu/components/search/main-search/dragsearch/card.jsx
@@ -133,7 +133,7 @@
        <CloseOutlined className="close" onClick={() => delCard(id)} />
      </div>
    } trigger="hover">
      <div className={'page-card ' + (card.labelShow === 'false' ? 'label-hide ' : '') + card.type + (card.advanced === 'true' ? ' advanced' : '')} style={{ opacity: opacity}}>
      <div className={'page-card ' + (card.labelShow === 'false' ? 'label-hide ' : '') + card.type + (card.advanced === 'true' ? ' advanced' : '') + (card.query === 'false' ? ' no-query' : '')} style={{ opacity: opacity}}>
        <div ref={node => drag(drop(node))}>
          <Form.Item
            labelCol={{xs: { span: 24 }, sm: { span: 8 }}}
src/menu/components/search/main-search/index.scss
@@ -89,6 +89,11 @@
      color: orange;
    }
  }
  .page-card.no-query {
    .ant-form-explain {
      color: #13c2c2;
    }
  }
  .mk-search-item-wrap.action {
    .ant-form-item {
      white-space: nowrap;
src/menu/components/table/base-table/columns/index.jsx
@@ -3,7 +3,7 @@
import { is, fromJS } from 'immutable'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Popover, Modal, message, notification } from 'antd'
import { PlusOutlined, PlusSquareOutlined, EditOutlined, CopyOutlined, DeleteOutlined, FontColorsOutlined, CloseCircleOutlined, AntDesignOutlined, InfoOutlined } from '@ant-design/icons'
import { PlusOutlined, PlusSquareOutlined, EditOutlined, CopyOutlined, DeleteOutlined, FontColorsOutlined, CloseCircleOutlined, AntDesignOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -615,26 +615,26 @@
    })
  }
  copyFields = () => {
    const { config } = this.props
    let m = []
    let n = []
  // copyFields = () => {
  //   const { config } = this.props
  //   let m = []
  //   let n = []
    config.columns.forEach(col => {
      m.push(`${col.field} ${col.datatype}`)
      n.push(col.field)
    })
  //   config.columns.forEach(col => {
  //     m.push(`${col.field} ${col.datatype}`)
  //     n.push(col.field)
  //   })
    let oInput = document.createElement('input')
    oInput.value = `/*${m.join(',')}*/
      ${n.join(',')}`
    document.body.appendChild(oInput)
    oInput.select()
    document.execCommand('Copy')
    document.body.removeChild(oInput)
  //   let oInput = document.createElement('input')
  //   oInput.value = `/*${m.join(',')}*/
  //     ${n.join(',')}`
  //   document.body.appendChild(oInput)
  //   oInput.select()
  //   document.execCommand('Copy')
  //   document.body.removeChild(oInput)
    message.success('复制成功。')
  }
  //   message.success('复制成功。')
  // }
  componentDidMount () {
    MKEmitter.addListener('plusColumns', this.plusColumns)
@@ -680,7 +680,7 @@
          <FieldsComponent config={config} type="columns" />
          <CopyOutlined title="复制显示列" onClick={this.copycolumn} />
          <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
          <InfoOutlined title="复制字段" style={{color: 'orange'}} onClick={this.copyFields}/>
          {/* <InfoOutlined title="复制字段" style={{color: 'orange'}} onClick={this.copyFields}/> */}
        </div>
        <DndProvider>
          {groups ? groups.map((group, i) => {
src/menu/components/table/base-table/index.jsx
@@ -259,12 +259,23 @@
    config.cols.forEach(col => {
      if (!col.field) return
      if (['text', 'picture', 'video', 'textarea'].includes(col.type)) {
        let datatype = `Nvarchar(${col.fieldlength || 50})`
        let type = 'text'
        if (col.type === 'text') {
          if (col.textFormat === 'YYYY-MM-DD') {
            datatype = 'date'
          } else if (col.textFormat === 'YYYY-MM-DD HH:mm:ss') {
            datatype = 'datetime'
          }
        }
        config.columns.push({
          datatype: `Nvarchar(${col.fieldlength || 50})`,
          datatype: datatype,
          field: col.field,
          fieldlength: col.fieldlength || 50,
          label: col.label,
          type: 'text',
          type: type,
          uuid: col.uuid
        })
      } else if (col.type === 'link') {
src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx
@@ -131,6 +131,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql, 'customscript')
src/menu/components/table/normal-table/index.jsx
@@ -381,7 +381,7 @@
        } trigger="hover">
          <ToolOutlined />
        </Popover>
        <SearchComponent config={card} updatesearch={this.updateComponent}/>
        {appType !== 'mob' ? <SearchComponent config={card} updatesearch={this.updateComponent}/> : null}
        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
        <ColumnComponent config={card} updatecolumn={this.updateComponent}/>
        <div className="component-name">
src/menu/components/tabs/paste/index.jsx
@@ -53,7 +53,7 @@
  pasteSubmit = () => {
    const { Tab } = this.props
    let appType = sessionStorage.getItem('appType')
    let options = ['tabs', 'group', 'datacard', 'propcard', 'timeline', 'balcony', 'normaltable', 'mainsearch', 'simpleform', 'stepform', 'tabform', 'editor', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'sandbox']
    let options = ['tabs', 'group', 'datacard', 'propcard', 'timeline', 'balcony', 'basetable', 'normaltable', 'mainsearch', 'simpleform', 'stepform', 'tabform', 'editor', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'sandbox']
    let types = {
      login: '登录',
      navbar: '导航栏',
@@ -83,6 +83,11 @@
        return
      }
      if (res.copyType === 'basetable') {
        res.copyType = 'normaltable'
        res.subtype = 'normaltable'
      }
      res = this.resetconfig(res, appType)
      delete res.copyType
src/menu/datasource/index.jsx
@@ -6,6 +6,7 @@
import VerifyCard from './verifycard'
import CreateFunc from '@/templates/zshare/createfunc'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class DataSource extends Component {
@@ -146,6 +147,14 @@
        res.setting.supModule = ['empty']
      }
      if (!res.setting.primaryKey && res.columns && res.columns.length > 0) {
        res.columns.forEach(col => {
          if (col.field.toLowerCase() === 'id') {
            res.setting.primaryKey = col.field
          }
        })
      }
      if (res.columns) {
        res.columns = res.columns.map(item => {
    
@@ -226,8 +235,13 @@
      } else {
        delete res.cols
      }
      this.props.updateConfig({...config, ...res})
      if (res.setting && res.setting.tableName && config.setting && !config.setting.tableName) {
        setTimeout(() => {
          MKEmitter.emit('publicTableChange', res.setting.tableName, 'init')
        }, 150)
      }
    }, () => {
      this.setState({loading: false})
    })
src/menu/datasource/verifycard/customscript/index.jsx
@@ -33,74 +33,41 @@
  UNSAFE_componentWillMount() {
    const { searches } = this.props
    this.getSearchField(searches)
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.searches), fromJS(nextProps.searches))) {
      this.getSearchField(nextProps.searches)
    }
  }
  getSearchField = (searches) => {
    let _usefulFields = []
    searches.forEach(item => {
      if (!item.field) return
      if (item.type === 'group') {
        _usefulFields.push(item.field)
        _usefulFields.push(item.datefield)
        _usefulFields.push(item.datefield + '1')
      } else if (['dateweek', 'datemonth'].includes(item.type)) {
        _usefulFields.push(item.field)
        _usefulFields.push(item.field + '1')
      if (['dateweek', 'datemonth'].includes(item.type)) {
        _usefulFields.push(item.key)
        _usefulFields.push(item.key + '1')
      } else if (item.type === 'daterange') {
        let _skey = item.field
        let _ekey = item.field + '1'
        let _skey = item.key
        let _ekey = item.key + '1'
        if (/,/.test(item.field)) {
          _skey = item.field.split(',')[0]
          _ekey = item.field.split(',')[1]
        if (/,/.test(item.key)) {
          _skey = item.key.split(',')[0]
          _ekey = item.key.split(',')[1]
        }
        _usefulFields.push(_skey)
        _usefulFields.push(_ekey)
      } else if (item.type === 'date' && _usefulFields.includes(item.field)) {
        _usefulFields.push(item.field + '1')
      } else if (item.type === 'date' && _usefulFields.includes(item.key)) {
        _usefulFields.push(item.key + '1')
      } else {
        _usefulFields.push(item.field)
        _usefulFields.push(item.key)
      }
    })
    this.setState({
      usefulFields: _usefulFields.join(', ')
    })
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.searches), fromJS(nextProps.searches))) {
      let _usefulFields = []
      nextProps.searches.forEach(item => {
        if (!item.field) return
        if (item.type === 'group') {
          _usefulFields.push(item.field)
          _usefulFields.push(item.datefield)
          _usefulFields.push(item.datefield + '1')
        } else if (['dateweek', 'datemonth'].includes(item.type)) {
          _usefulFields.push(item.field)
          _usefulFields.push(item.field + '1')
        } else if (item.type === 'daterange') {
          let _skey = item.field
          let _ekey = item.field + '1'
          if (/,/.test(item.field)) {
            _skey = item.field.split(',')[0]
            _ekey = item.field.split(',')[1]
          }
          _usefulFields.push(_skey)
          _usefulFields.push(_ekey)
        } else if (item.type === 'date' && _usefulFields.includes(item.field)) {
          _usefulFields.push(item.field + '1')
        } else {
          _usefulFields.push(item.field)
        }
      })
      this.setState({
        usefulFields: _usefulFields.join(', ')
      })
    }
  }
  edit = (record) => {
@@ -176,6 +143,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql, 'customscript')
@@ -230,6 +216,8 @@
  }
  selectScript = (value, option) => {
    const { setting } = this.props
    let _sql = this.props.form.getFieldValue('sql')
    if (_sql === ' ') {
      _sql = ''
@@ -241,8 +229,17 @@
    if (value === 'defaultsql') {
      value = this.props.defaultsql
    } else if (value === 'flowsql') {
      value = `/* select a.*,w.remark as remark_w,w.statusname as statusname_w,w.status as status_w,w.works_flow_param from (数据源) a inner join (select * from  s_my_works_flow  where works_flow_code=@works_flow_code@ and status=0 and deleted=0) w on a.id=w.works_flow_id */`
    } else if (value === 'flowstart') {
      value = `/* select a.*, w.remark as remark_w, w.statusname  as statusname_w,w.status as status_w,w.works_flow_param,w.modifydate as modifydate_w  from (select * from ${setting.tableName} where status=0 and deleted=0 $@ and createuserid=@userid@ @$) a
      inner join (select * from  s_my_works_flow  where works_flow_code=@works_flow_code@ and status=0 and deleted=0) w on a.id=w.works_flow_id */`
      this.props.addProcess()
    } else if (value === 'flowcheck') {
      value = `/* select a.*, w.remark as remark_w, w.statusname  as statusname_w,w.status as status_w,w.works_flow_param,w.modifydate as modifydate_w
      from (select * from ${setting.tableName} where status=0 and deleted=0 ) a
      inner join (select * from  s_my_works_flow  where works_flow_code=@works_flow_code@ and status>0 and status<888 and deleted=0) w
      on a.id=w.works_flow_id
      $@ inner join (select works_flow_id  from s_my_works_flow_role where userid=@userid@ and  works_flow_code=@works_flow_code@ and deleted=0 ) r
      on r.works_flow_id=w.works_flow_id @$ */`
      this.props.addProcess()
    }
@@ -338,6 +335,7 @@
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'排序、分页以及搜索条件变量,请按照@xxx@格式使用。使用@pageSize@或@orderBy@代表自定义分页,总数请以mk_total返回。'}>orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}{type === 'calendar' ? ', mk_year' : ''}</Tooltip>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'url变量,请按照@xxx@格式使用。'}>{urlFields ? ', ' : ''}<span style={{color: '#13c2c2'}}>{urlFields}</span></Tooltip>
              {window.GLOB.process ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'工作流变量,请按照@xxx@格式使用。'}>, <span style={{color: 'purple'}}>works_flow_code</span></Tooltip> : null}
            </Form.Item>
          </Col>
          <Col span={8} style={{whiteSpace: 'nowrap'}}>
@@ -365,7 +363,8 @@
                onSelect={this.selectScript}
              >
                <Select.Option style={{whiteSpace: 'normal'}} key="default" value="defaultsql">默认sql</Select.Option>
                {window.GLOB.process ? <Select.Option style={{whiteSpace: 'normal'}} key="default" value="flowsql">默认sql(工作流)</Select.Option> : null}
                {window.GLOB.process ? <Select.Option style={{whiteSpace: 'normal'}} key="flowstart" value="flowstart">默认sql(工作流-发起)</Select.Option> : null}
                {window.GLOB.process ? <Select.Option style={{whiteSpace: 'normal'}} key="flowcheck" value="flowcheck">默认sql(工作流-审核)</Select.Option> : null}
                <Select.Option key="debugger" value={`z_debug: select @ErrorCode='E',@retmsg='测试断点' goto aaa`}>
                  测试断点
                </Select.Option>
src/menu/datasource/verifycard/index.jsx
@@ -8,7 +8,7 @@
import Api from '@/api'
import Utils from '@/utils/utils.js'
import { formatSearch, joinMainSearchkey } from '@/utils/utils-custom.js'
import asyncComponent from '@/utils/asyncComponent'
import ColForm from './columnform'
import CustomScriptsForm from './customscript'
@@ -40,11 +40,11 @@
    subColumns: [],
    activeKey: 'setting',
    loading: false,
    colLoading: false,
    searchKey: '',
    initsql: '',          // sql验证时变量声明及赋值
    usefulfields: '',
    defaultsql: '',       // 默认Sql
    defaultSearch: '',
    systemScripts: [],
    median: {},
    visible: false,
@@ -210,16 +210,32 @@
      })
    }
    let _search = this.formatSearch(search)
    _search = Utils.joinMainSearchkey(_search)
    _search = _search.replace(/@\$@/ig, '')
    _search = _search ? 'where ' + _search : ''
    let columns = config.columns ? fromJS(config.columns).toJS() : []
    let subColumns = config.subColumns ? fromJS(config.subColumns).toJS() : []
    columns.reverse()
    subColumns.reverse()
    columns.forEach(col => {
      if (!col.datatype) return
      if (/^nvarchar/.test(col.datatype)) {
        col.datatype = col.datatype.replace(/^nvarchar/, 'Nvarchar')
      } else if (/^decimal/.test(col.datatype)) {
        col.datatype = col.datatype.replace(/^decimal/, 'Decimal')
      } else if (/^int/.test(col.datatype)) {
        col.datatype = col.datatype.replace(/^int/, 'Int')
      }
    })
    subColumns.forEach(col => {
      if (!col.datatype) return
      if (/^nvarchar/.test(col.datatype)) {
        col.datatype = col.datatype.replace(/^nvarchar/, 'Nvarchar')
      } else if (/^decimal/.test(col.datatype)) {
        col.datatype = col.datatype.replace(/^decimal/, 'Decimal')
      } else if (/^int/.test(col.datatype)) {
        col.datatype = col.datatype.replace(/^int/, 'Int')
      }
    })
    this.setState({
      scripts,
@@ -227,8 +243,7 @@
      subColumns: subColumns,
      setting: _setting,
      median: _setting,
      searches: search,
      defaultSearch: _search,
      searches: formatSearch(search),
      searchKey: '',
      debugId: _setting.debugId || ''
    })
@@ -426,15 +441,8 @@
          search = [...search, ...mainSearch]
        }
        let _search = this.formatSearch(search)
        _search = Utils.joinMainSearchkey(_search)
        _search = _search.replace(/@\$@/ig, '')
        _search = _search ? 'where ' + _search : ''
        this.setState({
          searches: search,
          defaultSearch: _search,
          searches: formatSearch(search),
          setting: res
        }, () => {
          this.sqlverify(() => { // 验证成功
@@ -513,9 +521,11 @@
  }
  getdefaultSql = () => {
    const { columns, setting, defaultSearch } = this.state
    const { columns, setting, searches } = this.state
    let defaultsql = ''
    let arr_field = columns.map(col => col.field).join(',')
    let _search = joinMainSearchkey(searches)
    if (setting.dataresource) {
      let _dataresource = setting.dataresource
@@ -524,59 +534,10 @@
        _dataresource = '(' + _dataresource + ') tb'
      }
      defaultsql = `select top @pageSize@ ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource} ${defaultSearch}) tmptable where rows > (@pageSize@ * (@pageIndex@ - 1)) order by tmptable.rows`
      defaultsql = `select top @pageSize@ ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource} ${_search}) tmptable where rows > (@pageSize@ * (@pageIndex@ - 1)) order by tmptable.rows`
    }
    this.setState({defaultsql})
  }
  /**
   * @description 获取全部搜索条件
   * @param {Array} searches 搜索条件数组
   */
  formatSearch (searches) {
    if (!searches) return []
    let newsearches = []
    searches.forEach(search => {
      if (!search.field) return
      let item = {
        key: search.field,
        match: search.match,
        type: search.type,
        label: search.label,
        value: search.initval,
        required: search.required === 'true'
      }
      if (item.type === 'group') {
        item.key = search.datefield
        item.type = 'daterange'
        item.match = 'between'
        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
        newsearches.push(item)
        return
      } else if (item.type === 'date') {
        item.value = moment().format('YYYY-MM-DD')
      } else if (item.type === 'datemonth') {
        item.value = moment().format('YYYY-MM')
      } else if (item.type === 'dateweek') {
        item.value = moment().format('YYYY-MM-DD')
      } else if (item.type === 'daterange') {
        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
      } else if (item.type === 'range') {
      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && search.multiple === 'true')) {
        item.type = 'multi'
        item.value = '@$@'
      } else {
        item.value = '@$@'
      }
      newsearches.push(item)
    })
    return newsearches
  }
  submitDataSource = () => {
@@ -611,15 +572,8 @@
            search = [...search, ...mainSearch]
          }
          let _search = this.formatSearch(search)
          _search = Utils.joinMainSearchkey(_search)
          _search = _search.replace(/@\$@/ig, '')
          _search = _search ? 'where ' + _search : ''
          this.setState({
            searches: search,
            defaultSearch: _search,
            searches: formatSearch(search),
            setting: res
          }, () => {
            this.sqlverify(() => { resolve({setting: res, columns, subColumns, scripts, cols }) }, reject, 'submit')
@@ -674,7 +628,7 @@
  sqlverify = (resolve, reject, type, testScripts) => {
    const { config } = this.props
    const { columns, setting, scripts, searches, defaultSearch, debugId } = this.state
    const { columns, setting, scripts, searches, debugId, subColumns } = this.state
    let _scripts = scripts.filter(item => item.status !== 'false')
@@ -697,7 +651,11 @@
    }
    if ((setting.interType === 'system' && setting.execute !== 'false') || _scripts.length > 0) {
      let r = SettingUtils.getDebugSql(setting, _scripts, columns, searches, defaultSearch, config.type)
      let _columns = columns
      if (config.subtype === 'dualdatacard') {
        _columns = [...columns, ...subColumns]
      }
      let r = SettingUtils.getDebugSql(setting, _scripts, _columns, searches, config.type)
      let _debugId = md5(r.sql)
@@ -907,11 +865,25 @@
    const { columns } = this.state
    let m = []
    let n = []
    let s = []
    columns.forEach(col => {
      m.push(`${col.field} ${col.datatype}`)
      n.push(col.field)
      m.unshift(`${col.field} ${col.datatype}`)
      n.unshift(col.field)
      if (/decimal|int/ig.test(col.datatype)) {
        s.unshift(`${Math.round(Math.random() * 10)} as ${col.field}`)
      } else if (/datetime/.test(col.datatype)) {
        s.unshift(`'${moment().format('YYYY-MM-DD HH:mm:ss')}' as ${col.field}`)
      } else if (/date/.test(col.datatype)) {
        s.unshift(`'${moment().format('YYYY-MM-DD')}' as ${col.field}`)
      } else {
        s.unshift(`'${col.label}' as ${col.field}`)
      }
    })
    if (window.debugger) {
      console.info('select ' + s.join(', '))
    }
    let oInput = document.createElement('input')
    oInput.value = `/*${m.join(',')}*/
@@ -988,6 +960,49 @@
    })
  }
  updateColumns = (tableName) => {
    const { config } = this.props
    const { colLoading, columns } = this.state
    if (colLoading || columns.length > 0) return
    if (config.subtype === 'basetable') return
    let param = {func: 'sPC_Get_FieldName', TBName: tableName}
    if (window.GLOB.cloudServiceApi) { // 且存在云端地址
      param.rduri = window.GLOB.cloudServiceApi
      param.userid = sessionStorage.getItem('CloudUserID') || ''
      param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
    }
    this.setState({colLoading: true})
    Api.getSystemCacheConfig(param).then(result => {
      this.setState({colLoading: false})
      if (!result.status) return
      let fields = []
      result.FDName.forEach(item => {
        if (item.f_type !== 0) return
        if (/nvarchar|int|decimal/ig.test(item.FieldType) || item.FieldType === 'date' || item.FieldType === 'datetime') {
          fields.unshift({
            uuid: Utils.getuuid(),
            label: item.FieldDec,
            field: item.FieldName,
            datatype: item.FieldType.toLowerCase()
          })
        }
      })
      if (fields.length === 0) return
      this.setState({columns: fields})
    }, () => {
      this.setState({colLoading: false})
    })
  }
  /**
   * @description 组件销毁,清除state更新
   */
@@ -1018,6 +1033,7 @@
              setting={setting}
              scripts={scripts}
              updateStatus={this.updateStatus}
              updateColumns={this.updateColumns}
              addProcess={this.addProcess}
              wrappedComponentRef={(inst) => this.settingForm = inst}
            /> : null}
@@ -1035,7 +1051,15 @@
              updatefield={this.updatefields}
            />
            <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> : null}
          </TabPane> : <TabPane tab={
            <span>
              字段集
              {columns.length ? <span className="count-tip">{columns.length}</span> : null}
            </span>
          } key="columns">
            <div className="base-table-columns"></div>
            <EditTable actions={[]} searchKey={searchKey} type="datasourcefield" data={columns} columns={colColumns}/>
          </TabPane>}
          {config.subtype === 'dualdatacard' ? <TabPane tab={
            <span>
              子表字段集
src/menu/datasource/verifycard/index.scss
@@ -5,6 +5,14 @@
    top: 220px;
    z-index: 1;
  }
  .base-table-columns {
    height: 15px;
  }
  .base-table-columns + .modal-edit-table {
    .editable-row > td:last-child {
      padding: 14px 10px;
    }
  }
  .data-source-card-box {
    .ant-tabs-nav-scroll {
      text-align: center;
src/menu/datasource/verifycard/settingform/index.jsx
@@ -1,8 +1,8 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Radio, Tooltip, notification, Select, InputNumber, Cascader } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { Form, Row, Col, Input, Radio, Tooltip, notification, Select, InputNumber, Cascader, Modal, Button } from 'antd'
import { QuestionCircleOutlined, PlusOutlined } from '@ant-design/icons'
import { formRule } from '@/utils/option.js'
import Utils from '@/utils/utils.js'
@@ -16,6 +16,7 @@
class SettingForm extends Component {
  static propTpyes = {
    updateStatus: PropTypes.func,
    updateColumns: PropTypes.func,
    addProcess: PropTypes.func,
    config: PropTypes.object,     // 组件配置
    setting: PropTypes.object,    // 数据源配置
@@ -29,7 +30,8 @@
    innerRules: [],
    innertip: '',
    MenuType: sessionStorage.getItem('MenuType') || '',
    ismain: false
    ismain: false,
    visible: false
  }
  UNSAFE_componentWillMount () {
@@ -182,21 +184,61 @@
  }
  addProcess = () => {
    let _sql = this.props.form.getFieldValue('dataresource')
    this.setState({visible: true})
  }
    _sql = _sql + `\n/* select a.*,w.remark as remark_w,w.statusname as statusname_w,w.status as status_w,w.works_flow_param from (数据源) a inner join (select * from  s_my_works_flow  where works_flow_code=@works_flow_code@ and status=0 and deleted=0) w on a.id=w.works_flow_id */`
  execAddProcess = (type) => {
    let _sql = this.props.form.getFieldValue('dataresource')
    let tableName = this.props.form.getFieldValue('tableName') || '表名'
    if (type === 'flowstart') {
      _sql = _sql + `\n/* select a.*, w.remark as remark_w, w.statusname  as statusname_w,w.status as status_w,w.works_flow_param,w.modifydate as modifydate_w  from (select * from ${tableName} where status=0 and deleted=0 $@ and createuserid=@userid@ @$) a
    inner join (select * from  s_my_works_flow  where works_flow_code=@works_flow_code@ and status=0 and deleted=0) w on a.id=w.works_flow_id */`
    } else if (type === 'flowcheck') {
      _sql = _sql + `\n/* select a.*, w.remark as remark_w, w.statusname  as statusname_w,w.status as status_w,w.works_flow_param,w.modifydate as modifydate_w
    from (select * from ${tableName} where status=0 and deleted=0 ) a
    inner join (select * from  s_my_works_flow  where works_flow_code=@works_flow_code@ and status>0 and status<888 and deleted=0) w
    on a.id=w.works_flow_id
    $@ inner join (select works_flow_id  from s_my_works_flow_role where userid=@userid@ and  works_flow_code=@works_flow_code@ and deleted=0 ) r
    on r.works_flow_id=w.works_flow_id @$ */`
    }
    this.props.form.setFieldsValue({
      dataresource: _sql
    })
    this.setState({visible: false})
    this.props.addProcess()
  }
  addSql = () => {
    let tableName = this.props.form.getFieldValue('tableName')
    if (!tableName) {
      notification.warning({
        top: 92,
        message: '请添加表名。',
        duration: 5
      })
      return
    }
    let _sql = this.props.form.getFieldValue('dataresource')
    if (/^\s*$/.test(_sql)) {
      this.props.form.setFieldsValue({
        dataresource: `select * from ${tableName} where deleted=0`
      })
    }
    this.props.updateColumns(tableName)
  }
  render() {
    const { columns, config } = this.props
    const { getFieldDecorator } = this.props.form
    const { setting, modules, innerRules, innertip, MenuType } = this.state
    const { setting, modules, innerRules, innertip, MenuType, visible } = this.state
    const formItemLayout = {
      labelCol: {
@@ -223,7 +265,7 @@
                      message: '请输入数据源名称!'
                    }
                  ]
                })(<Input placeholder={''} autoComplete="off" />)}
                })(<Input placeholder="" autoComplete="off" />)}
              </Form.Item>
            </Col> : null}
            <Col span={8}>
@@ -244,7 +286,11 @@
                      message: '表名只可使用字母、数字以及_'
                    }
                  ]
                })(<Input placeholder={''} autoComplete="off" />)}
                })(
                  setting.interType === 'system' && ((columns.length === 0 && config.subtype !== 'basetable') || !setting.dataresource) ?
                  <Input placeholder="" autoComplete="off" addonAfter={<PlusOutlined onClick={this.addSql} />}/> :
                  <Input placeholder="" autoComplete="off"/>
                  )}
              </Form.Item>
            </Col>
            <Col span={8}>
@@ -672,6 +718,20 @@
            </Col> : null}
          </Row>
        </Form>
        <Modal
          wrapClassName="mk-flow-type"
          visible={visible}
          width={400}
          maskClosable={false}
          closable={false}
          footer={[
            <Button key="cancel" className="mk-green" onClick={() => this.execAddProcess('flowstart')}>发起</Button>,
            <Button key="confirm" className="mk-primary" onClick={() => this.execAddProcess('flowcheck')}>审批</Button>
          ]}
          destroyOnClose
        >
          请选择工作流类型。
        </Modal>
      </div>
    )
  }
src/menu/datasource/verifycard/settingform/index.scss
@@ -34,4 +34,33 @@
    color: #1890ff;
    cursor: pointer;
  }
  .ant-input-group-addon {
    padding: 0;
    .anticon-plus {
      cursor: pointer;
      padding: 7px 9px;
    }
  }
  .ant-form-item-control.has-error {
    .ant-input-group-addon {
      display: none;
    }
  }
}
.mk-flow-type {
  .ant-modal-body {
    font-size: 16px;
    color: rgba(0, 0, 0, 0.85);
    text-align: center;
    padding: 40px 0 20px;
  }
  .ant-modal-footer {
    border: 0;
    text-align: center;
    padding: 25px 16px;
    button + button {
      margin-left: 15px;
    }
  }
}
src/menu/datasource/verifycard/utils.jsx
@@ -1,4 +1,6 @@
import { getSearchRegs, joinMainSearchkey } from '@/utils/utils-custom.js'
export default class SettingUtils {
  /**
   * @description 生成页面查询语句
@@ -7,7 +9,7 @@
   * @return {Object}  setting       页面设置
   * @return {Array}   columns       显示字段
   */
  static getDebugSql (setting, scripts, columns, searches = [], defSearch, type) {
  static getDebugSql (setting, scripts, columns, searches = [], type) {
    let sql = ''
    let error = ''
    let _dataresource = ''
@@ -95,85 +97,33 @@
    }
    // 正则替换
    let _regoptions = []
    let _fields = []
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    let _regoptions = getSearchRegs(searches)
    searches.forEach(item => {
      if (!item.field) return
      if (item.datefield) {
        _regoptions.push({
          reg: new RegExp('@' + item.datefield + '@', 'ig')
        })
        _regoptions.push({
          reg: new RegExp('@' + item.datefield + '1@', 'ig')
        })
      }
      if (['dateweek', 'datemonth', 'range'].includes(item.type)) {
        _regoptions.push({
          reg: new RegExp('@' + item.field + '@', 'ig')
        })
        _regoptions.push({
          reg: new RegExp('@' + item.field + '1@', 'ig')
        })
      } else if (item.type === 'daterange') {
        let _skey = item.field
        let _ekey = item.field + '1'
        if (/,/.test(item.field)) {
          _skey = item.field.split(',')[0]
          _ekey = item.field.split(',')[1]
        }
        _regoptions.push({
          reg: new RegExp('@' + _skey + '@', 'ig')
        })
        _regoptions.push({
          reg: new RegExp('@' + _ekey + '@', 'ig')
        })
      } else if (item.type === 'date') {
        if (_fields.includes(item.field)) {
          _regoptions.push({
            reg: new RegExp('@' + item.field + '1@', 'ig')
          })
        } else {
          _fields.push(item.field)
          _regoptions.push({
            reg: new RegExp('@' + item.field + '@', 'ig')
          })
        }
      } else if (item.type === 'text' || item.type === 'select') {
        item.field.split(',').forEach(field => {
          _regoptions.push({
            reg: new RegExp('@' + field + '@', 'ig')
          })
        })
      } else {
        _regoptions.push({
          reg: new RegExp('@' + item.field + '@', 'ig')
        })
      }
    })
    let _search = joinMainSearchkey(searches)
    _regoptions.push({
      reg: new RegExp('@userName@', 'ig'),
      value: `'mk'`
    }, {
      reg: new RegExp('@fullName@', 'ig'),
      value: `'mk'`
    }, {
      reg: new RegExp('@orderBy@', 'ig'),
    }, {
      reg: new RegExp('@UserName@', 'ig'),
    }, {
      reg: new RegExp('@FullName@', 'ig'),
      value: setting.order || ''
    }, {
      reg: new RegExp('@pageSize@', 'ig'),
      value: 9999
    }, {
      reg: new RegExp('@pageIndex@', 'ig'),
      value: 1
    })
    _regoptions.forEach(item => {
      _dataresource = _dataresource.replace(item.reg, '0')
      _customScript = _customScript.replace(item.reg, '0')
      _tailScript = _tailScript.replace(item.reg, '0')
      _dataresource = _dataresource.replace(item.reg, item.value || '0')
      _customScript = _customScript.replace(item.reg, item.value || '0')
      _tailScript = _tailScript.replace(item.reg, item.value || '0')
    })
    let _search = defSearch
    if (setting.queryType === 'statistics') {
      _search = ''
src/menu/debug/index.jsx
@@ -1,11 +1,12 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
// import { fromJS } from 'immutable'
import { Modal, Button } from 'antd'
// import moment from 'moment'
import { fromJS } from 'immutable'
import { Modal, Button, Drawer, Tooltip } from 'antd'
import { ClockCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, LoadingOutlined } from '@ant-design/icons'
// import Api from '@/api'
// import Utils from '@/utils/utils.js'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import { formatSearch, joinMainSearchkey, getSearchRegs } from '@/utils/utils-custom.js'
import './index.scss'
class DebugSql extends Component {
@@ -15,186 +16,1872 @@
  state = {
    visible: false,
    confirming: false,
    sqlList: [],
    status: '',
    successIds: [],
    errorIds: [],
    errorMsg: {},
    execId: ''
  }
  sqlList = []
  verSqls = []
  trigger = () => {
    // const { config } = this.props
    let config = fromJS(this.props.config).toJS()
    // let list = []
    // let mainSearch = []
    let error = ''
    let check = (components) => {
      components.forEach(item => {
        if (error) return
        if (item.type === 'tabs') {
          item.subtabs.forEach(tab => {
            check(tab.components)
          })
          return
        } else if (item.type === 'group') {
          check(item.components)
          return
        } else if (!item.errors || item.errors.length === 0) {
          return
        }
        item.errors.forEach(err => {
          if (err.level !== 0 || error) return
          error = `组件《${item.name}》${err.detail}`
        })
      })
    }
    check(config.components)
    if (error) {
      Modal.warning({
        title: error,
        okText: '知道了'
      })
      return
    }
    this.sqlList = []
    let regs = [
      { reg: /@userName@/ig, value: `'User_Name'` },
      { reg: /@fullName@/ig, value: `'Full_Name'` },
      { reg: /\$@/ig, value: '' },
      { reg: /@\$/ig, value: '' },
      { reg: /@datam@/ig, value: `''` },
    ]
    if (window.GLOB.externalDatabase !== null) {
      regs.push({
        reg: /@db@/ig,
        value: window.GLOB.externalDatabase
      })
    }
    if (config.urlFields) {
      config.urlFields.forEach(field => {
        regs.push({
          reg: new RegExp('@' + field + '@', 'ig'),
          value: `'mk'`
        })
      })
    }
    let process = config.process === 'true'
    if (process) {
      regs.push({ reg: /@works_flow_code@/ig, value: `'1949-10-01 15:00:00'` })
    }
    if (config.interfaces && config.interfaces.length > 0) {
      config.interfaces.forEach(m => {
        if (m.status !== 'true' || m.setting.interType !== 'system') return false
        let sql = this.formatDataSource(m, regs)
        this.sqlList.push({label: m.setting.name, children: [{label: '数据源', sql: sql}]})
      })
    }
    this.filterComponent(config.components, [], regs, process)
    let sqls = []
    let foreachSql = (list, name, tabName = '', supName = '') => {
      list.forEach(item => {
        if (item.children) {
          if (item.tabName) {
            item.children.forEach(cell => {
              if (cell.children) {
                foreachSql(cell.children, cell.label, item.tabName, name)
              }
            })
          } else {
            foreachSql(item.children, name, tabName, supName)
          }
        } else if (item.sql) {
          sqls.push({uuid: Utils.getuuid() ,label: item.label, name: name, tabName: tabName, supName: supName, sql: item.sql})
        }
      })
    }
    this.sqlList.forEach(item => {
      if (item.children) {
        foreachSql(item.children, item.label)
      }
    })
    if (sqls.length === 0) {
      Modal.warning({
        title: '当前菜单无可验证脚本。',
        okText: '知道了'
      })
      return
    }
    this.verSqls = sqls
    let that = this
    Modal.confirm({
      content: `当前菜单共${this.sqlList.length}个组件,${sqls.length}项脚本需要检验${sqls.length > 20 ? ',时间大概需要' + parseInt(sqls.length / 2) + '秒' : ''}。`,
      onOk() {
        that.setState({visible: true, status: 'loading', sqlList: fromJS(sqls).toJS(), successIds: [], errorIds: [], errorMsg: {}, execId: ''}, () => {
          that.roopSql()
        })
      },
      onCancel() {}
    })
    this.sqlList = []
  }
  // formatSearch (config) {
  //   if (!config.search) return []
  filterComponent = (components, mainSearch, regs, process, ispop = false) => {
    let appType = sessionStorage.getItem('appType')
    let _mainSearch = mainSearch || []
  //   let values = []
    if (appType === 'mob') {
      let search = []
      let ms = null
      components.forEach(item => {
        if (item.type === 'topbar' && item.wrap.type !== 'navbar' && item.search) {
          ms = item.search
        } else if (item.type === 'search' && item.wrap.field) {
          search.push({
            type: 'text',
            label: item.wrap.label,
            field: item.wrap.field,
            match: item.wrap.match,
            required: item.wrap.required,
            value: item.wrap.initval || ''
          })
        }
      })
  //   config.search.forEach(item => {
  //     item.hidden = item.Hide === 'true'
  //     item.required = !item.hidden && item.required === 'true'
  //     item.advanced = item.advanced === 'true'
  //     item.$forbid = item.query === 'false'
  //     item.precision = item.precision || 'day'
      if (ms) {
        if (ms.setting.type === 'search') {
          search.push({
            type: 'text',
            label: '搜索栏',
            field: ms.setting.field,
            match: ms.setting.match,
            required: ms.setting.required,
            value: ms.setting.initval || ''
          })
        }
        search.push(...ms.fields)
  //     if (item.type === 'date') { // 时间搜索
  //       let format = 'YYYY-MM-DD'
  //       if (item.precision === 'day') {
        ms.groups.forEach(group => {
          if (group.setting.type === 'search') {
            search.push({
              type: 'text',
              label: group.wrap.name,
              field: group.setting.field,
              match: group.setting.match,
              required: group.setting.required,
              value: group.setting.initval || ''
            })
          }
          search.push(...group.fields)
        })
      }
  //       } else if (item.precision === 'hour') {
  //         format = 'YYYY-MM-DD HH'
  //       } else if (item.precision === 'minute') {
  //         format = 'YYYY-MM-DD HH:mm'
  //       } else if (item.precision === 'second') {
  //         format = 'YYYY-MM-DD HH:mm:ss'
  //       }
      if (search.length > 0) {
        _mainSearch = search
      }
    } else {
      components.forEach(component => {
        if (component.type !== 'search') return
        _mainSearch = component.search || []
      })
    }
  //       item.initval = item.initval ? moment().subtract(item.initval, 'days').format(format) : ''
  //     } else if (item.type === 'datemonth') {
  //       item.initval = item.initval ? moment().subtract(item.initval, 'month').format('YYYY-MM') : ''
  //     } else if (item.type === 'dateweek') {
  //       item.initval = item.initval ? moment().subtract(item.initval * 7, 'days').format('YYYY-MM-DD') : ''
  //     } else if (item.type === 'daterange') {
  //       let format = 'YYYY-MM-DD'
  //       if (item.precision === 'day') {
    components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          this.filterComponent(tab.components, _mainSearch, regs, process)
        })
      } else if (item.type === 'group') {
        this.filterComponent(item.components, _mainSearch, regs, process)
      } else {
        let children = []
        if (item.wrap && item.setting) {
          if (item.wrap.datatype === 'public' || item.wrap.datatype === 'static') {
            item.setting.interType = 'other'
          }
        }
  //       } else if (item.precision === 'hour') {
  //         format = 'YYYY-MM-DD HH'
  //       } else if (item.precision === 'minute') {
  //         format = 'YYYY-MM-DD HH:mm'
  //       } else if (item.precision === 'second') {
  //         format = 'YYYY-MM-DD HH:mm:ss'
  //       }
  //       if (item.initval === 'week') {
  //         item.initval = [moment().startOf('week').format(format), moment().endOf('week').format(format)].join(',')
  //       } else if (item.initval === 'month') {
  //         item.initval = [moment().startOf('month').format(format), moment().endOf('month').format(format)].join(',')
  //       } else if (item.initval === 'lastMonth') {
  //         item.initval = [moment().subtract(1, 'months').startOf('month').format(format), moment().subtract(1, 'months').endOf('month').format(format)].join(',')
  //       } else if (item.initval) {
  //         try {
  //           let _initval = JSON.parse(item.initval)
  //           let _vals = [moment().subtract(_initval[0], 'days').format(format), moment().subtract(_initval[1], 'days').format(format)]
  //           item.initval = _vals.join(',')
  //         } catch (e) {
  //           item.initval = ''
  //         }
  //       }
  //     } else if (item.type === 'group') {
  //       if (item.initval && item.initval[0]) {
  //         let _type = item.initval[0]
  //         let _val = item.initval[1]
  //         let _dateRange = ''
        if (appType === 'mob' && item.type !== 'search' && item.type !== 'topbar' && item.search && item.search.length > 0) {
          item.search = []
        }
        if (item.subtype === 'tablecard') { // 兼容
          item.type = 'card'
        }
        if (item.setting && item.setting.interType === 'system') {
          let sql = this.formatDataSource(item, regs, _mainSearch)
          children.push({label: '数据源', sql: sql})
        } else if (item.setting && item.setting.useMSearch === 'true') {
          let searches = item.search || []
          if (_mainSearch.length > 0) {
            searches = [...searches, ..._mainSearch]
          }
          item.$searches = fromJS(searches).toJS()
        }
        item.action && item.action.forEach(cell => {
          if (cell.hidden === 'true') return false
          let sql = this.resetButton(item, cell, process)
          if (sql) {
            if (typeof(sql) === 'string') {
              children.push({label: cell.label, sql: sql})
            } else {
              children.push({label: cell.label, tabName: cell.label, sql: '', children: sql})
            }
          }
        })
        if (item.type === 'table') {
          let getCols = (cols) => {
            cols.forEach(col => {
              if (col.type === 'action') {
                col.type = 'custom'
              }
              if (col.type === 'colspan') {
                getCols(col.subcols || [])
              } else if (col.type === 'custom') {
                col.elements.forEach(cell => {
                  if (cell.eleType !== 'button' || cell.hidden === 'true') return
                  let sql = this.resetButton(item, cell, process)
                  if (sql) {
                    if (typeof(sql) === 'string') {
                      children.push({label: cell.label, sql: sql})
                    } else {
                      children.push({label: cell.label, tabName: cell.label, sql: '', children: sql})
                    }
                  }
                })
              }
            })
          }
          getCols(item.cols)
          if (item.subtype === 'editable' && item.submit.intertype === 'system') {
            let sql = this.getEditTableSql(item.submit, item.cols, item.columns)
            children.push({label: '提交', sql: sql})
          }
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.subcards && item.subcards.forEach(card => {
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              let sql = this.resetButton(item, cell, process)
              if (sql) {
                if (typeof(sql) === 'string') {
                  children.push({label: cell.label, sql: sql})
                } else {
                  children.push({label: cell.label, tabName: cell.label, sql: '', children: sql})
                }
              }
            })
            if (!card.backElements || card.backElements.length === 0) return
            card.backElements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              let sql = this.resetButton(item, cell, process)
              if (sql) {
                if (typeof(sql) === 'string') {
                  children.push({label: cell.label, sql: sql})
                } else {
                  children.push({label: cell.label, tabName: cell.label, sql: '', children: sql})
                }
              }
            })
          })
        } else if (item.type === 'balcony') {
          item.elements.forEach(cell => {
            if (cell.eleType !== 'button' || cell.hidden === 'true') return
            let sql = this.resetButton(item, cell, process)
            if (sql) {
              if (typeof(sql) === 'string') {
                children.push({label: cell.label, sql: sql})
              } else {
                children.push({label: cell.label, tabName: cell.label, sql: '', children: sql})
              }
            }
          })
        } else if (item.type === 'form') {
          item.subcards.forEach(group => {
            group.subButton.OpenType = 'formSubmit'
            if (!group.subButton.Ot) {
              group.subButton.Ot = item.wrap.datatype === 'static' ? 'notRequired' : 'requiredSgl'
            }
            let sql = this.resetButton(item, group.subButton, process, group)
            if (sql) {
              children.push({label: group.subButton.label, sql: sql})
            }
          })
        }
        if (children.length) {
          if (ispop) {
            this.sqlPopList.push({label: item.name, children: children})
          } else {
            this.sqlList.push({label: item.name, children: children})
          }
        }
      }
    })
  }
  resetButton = (item, cell, process, group) => {
    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)
      }
    } else if (cell.OpenType === 'excelIn') {
      if (cell.intertype === 'system') {
        sql = this.getExcelInSql(cell)
      }
    } else if (cell.OpenType === 'excelOut') {
      if (cell.intertype === 'system' && cell.verify && cell.verify.dataType === 'custom') {
        sql = this.getExcelOutSql(cell, item)
      }
    } else if (cell.OpenType === 'funcbutton') {
      if (cell.funcType === 'print') {
      }
    } else if (cell.OpenType === 'popview') {
      if (cell.config && cell.config.components) {
        this.sqlPopList = []
        let regs = [
          { reg: /@userName@/ig, value: `'User_Name'` },
          { reg: /@fullName@/ig, value: `'Full_Name'` },
          { reg: /\$@/ig, value: '' },
          { reg: /@\$/ig, value: '' },
          { reg: /@datam@/ig, value: `''` },
        ]
        if (window.GLOB.externalDatabase !== null) {
          regs.push({
            reg: /@db@/ig,
            value: window.GLOB.externalDatabase
          })
        }
    
  //         if (_type === 'day') {
  //           _dateRange = [moment().subtract(_val, 'days').format('YYYY-MM-DD'),
  //             moment().subtract(_val, 'days').format('YYYY-MM-DD')]
  //         } else if (_type === 'week') {
  //           _dateRange = [moment().subtract(_val * 7, 'days').startOf('week').format('YYYY-MM-DD'),
  //             moment().subtract(_val * 7, 'days').endOf('week').format('YYYY-MM-DD')]
  //         } else if (_type === 'month') {
  //           _dateRange = [moment().subtract(_val, 'month').startOf('month').format('YYYY-MM-DD'),
  //             moment().subtract(_val, 'month').endOf('month').format('YYYY-MM-DD')]
  //         } else if (_type === 'quarter') {
  //           let _differ = parseInt(moment().format('MM')) % 3
  //           let _pdiffer = 0
  //           let _ndiffer = 0
  //           // 差值计算
  //           switch(_differ) {
  //             case 0:
  //               _pdiffer = 2
  //               _ndiffer = 0
  //               break
  //             case 1:
  //               _pdiffer = 0
  //               _ndiffer = -2
  //               break
  //             case 2:
  //               _pdiffer = 1
  //               _ndiffer = -1
  //               break
  //             default:
  //           }
  //           _dateRange = [moment().subtract(_pdiffer + _val * 3, 'month').startOf('month').format('YYYY-MM-DD'),
  //             moment().subtract(_ndiffer + _val * 3, 'month').endOf('month').format('YYYY-MM-DD')]
  //         } else if (_type === 'year') {
  //           let _year = parseInt(moment().format('YYYY')) - _val
  //           _dateRange = [_year + '-01-01', _year + '-12-31']
  //         } else if (_type === 'customized') {
  //           try {
  //             _val = JSON.parse(_val)
  //           } catch (e) {
  //             _val = [0, 0]
  //           }
  //           _dateRange = [moment().subtract(_val[0], 'days').format('YYYY-MM-DD'),
  //             moment().subtract(_val[1], 'days').format('YYYY-MM-DD')]
  //         }
        if (process) {
          regs.push({ reg: /@works_flow_code@/ig, value: `'1949-10-01 15:00:00'` })
        }
        this.filterComponent(cell.config.components, [], regs, process, true)
  //         item.initval = _dateRange.join(',')
  //         item.initType = _type
  //       } else {
  //         item.initval = ''
  //         item.initType = ''
  //       }
  //     }
        if (this.sqlPopList.length) {
          sql = fromJS(this.sqlPopList).toJS()
        }
      }
    }
    return sql
  }
  getSysDefaultSql = (btn, component, process, group) => {
    let primaryId = 'id'
    let BID = 'bid'
    let verify = btn.verify || {}
    let _actionType = null
    let setting = component.setting
    let columns = component.columns || []
    if (verify.default !== 'false') { // 判断是否使用默认sql
      _actionType = btn.sqlType
    }
    let _initCustomScript = '' // 初始化脚本
    let _prevCustomScript = '' // 默认sql前执行脚本
    let _backCustomScript = '' // 默认sql后执行脚本
    verify.scripts && verify.scripts.forEach(item => {
      if (item.status === 'false') return
      if (item.position === 'init') {
        _initCustomScript += `
        /* 自定义脚本 */
        ${item.sql}
        `
      } else if (item.position === 'front') {
        _prevCustomScript += `
        /* 自定义脚本 */
        ${item.sql}
        `
      } else {
        _backCustomScript += `
        /* 自定义脚本 */
        ${item.sql}
        `
      }
    })
    // 需要声明的变量集
    let _vars = ['tbid', 'errorcode', 'retmsg', 'billcode', 'bvoucher', 'fibvoucherdate', 'fiyear', 'username', 'fullname', 'modulardetailcode', 'roleid', 'mk_departmentcode', 'mk_organization', 'mk_user_type', 'mk_nation', 'mk_province', 'mk_city', 'mk_district', 'mk_address', 'mk_deleted', 'bid']
    // 主键字段
    let primaryKey = setting.primaryKey || 'id'
    // sql语句
    let _sql = ''
    let _initvars = [] // 已赋值字段集
    let _initFormfields = []
    let _initColfields = []
    let _declarefields = []
    let formdata = null
    if (btn.OpenType === 'pop') {
      formdata = []
      if (btn.modal && btn.modal.fields) {
        btn.modal.fields.forEach(item => {
          if (!item.field) return
          let _item = {
            key: item.field,
            fieldlen: item.fieldlength || 50,
            writein: item.writein !== 'false',
            type: item.type
          }
          if (_item.type === 'datemonth') {
            _item.type = 'text'
          } else if (_item.type === 'number' || _item.type === 'rate') {
            _item.fieldlen = item.decimal || 0
          } else  if (_item.type === 'date') {
            _item.type = item.declareType === 'nvarchar(50)' ? 'text' : 'date'
          }
          formdata.push(_item)
        })
      }
    } else if (btn.OpenType === 'form') {
      formdata = []
      let item = {
        type: 'text',
        readin: true,
        writein: true,
        fieldlen: 50,
        key: btn.field
      }
      if (btn.formType === 'counter') {
        item.type = 'number'
        item.fieldlen = 0
      } else if (btn.formType === 'switch' || btn.formType === 'radio') {
        if (typeof(btn.openVal) === 'number') {
          item.type = 'number'
          item.fieldlen = 0
        }
      }
      formdata.push(item)
    } else if (btn.OpenType === 'formSubmit') {
      formdata = []
      if (group.fields) {
        group.fields.forEach(item => {
          if (!item.field) return
          let _item = {
            key: item.field,
            fieldlen: item.fieldlength || 50,
            writein: item.writein !== 'false',
            type: item.type
          }
          if (_item.type === 'datemonth') {
            _item.type = 'text'
          } else if (_item.type === 'number' || _item.type === 'rate') {
            _item.fieldlen = item.decimal || 0
          } else  if (_item.type === 'date') {
            _item.type = item.declareType === 'nvarchar(50)' ? 'text' : 'date'
          }
          formdata.push(_item)
        })
      }
    }
    // 获取字段键值对
    formdata && formdata.forEach(form => {
      let _key = form.key.toLowerCase()
      if (!_initvars.includes(_key)) {
        _initvars.push(_key)
        if (form.type === 'number' || form.type === 'rate') {
          _initFormfields.push(`@${_key}=1`)
        } else if (form.type === 'date') {
          _initFormfields.push(`@${_key}='1949-10-01'`)
        } else if (form.type === 'select' || form.type === 'link' || form.type === 'radio') {
          _initFormfields.push(`@${_key}='1'`)
        } else {
          _initFormfields.push(`@${_key}='mk'`)
        }
      }
      
  //     item.oriInitval = item.initval
      if (!_vars.includes(_key)) {
        _vars.push(_key)
        if (form.fieldlen && form.fieldlen > 4000) {
          form.fieldlen = 'max'
        }
        let _type = `nvarchar(${form.fieldlen})`
        if (form.type.match(/date/ig)) {
          _type = 'datetime'
        } else if (form.type === 'number') {
          _type = `decimal(18,${form.fieldlen})`
        } else if (form.type === 'rate') {
          _type = `decimal(18,2)`
        }
        _declarefields.push(`@${_key} ${_type}`)
      }
    })
    // 添加数据中字段,表单值优先(按钮不选行或多行拼接时跳过)
    if (btn.Ot !== 'notRequired' && columns && columns.length > 0) {
      const setField = (col) => {
        if (!col.field) return
        let _key = col.field.toLowerCase()
        if (!_initvars.includes(_key)) {
          _initvars.push(_key)
          if (col.datatype && /^date/ig.test(col.datatype)) {
            _initColfields.push(`@${_key}='1949-10-01'`)
          } else if (col.type === 'number') {
            _initColfields.push(`@${_key}=1`)
          } else {
            _initColfields.push(`@${_key}='mk'`)
          }
        }
        if (!_vars.includes(_key)) {
          _vars.push(_key)
          if (col.datatype) {
            _declarefields.push(`@${_key} ${col.datatype}`)
          } else {
            if (col.fieldlength && col.fieldlength > 4000) {
              col.fieldlength = 'max'
            }
            let _type = `nvarchar(${col.fieldlength || 50})`
            if (col.type === 'number') {
              let _length = col.decimal ? col.decimal : 0
              _type = `decimal(18,${_length})`
            } else if (col.type === 'picture' || col.type === 'textarea') {
              _type = `nvarchar(${col.fieldlength || 512})`
            }
            _declarefields.push(`@${_key} ${_type}`)
          }
        }
      }
      columns.forEach(col => {
        if (col.type === 'colspan' || col.type === 'old_colspan') {
          col.subcols.forEach(cell => {
            setField(cell)
          })
        } else {
          setField(col)
        }
      })
    }
    // 变量声明
    _declarefields = _declarefields.join(',')
    if (_declarefields) {
      _declarefields = ',' + _declarefields
    }
    _sql = `Declare @tbid nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@BillCode nvarchar(50),@BVoucher nvarchar(50),@FIBVoucherDate nvarchar(50), @FiYear nvarchar(50),@ModularDetailCode nvarchar(50), @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),@mk_deleted int,@bid nvarchar(50)${_declarefields}
      `
    let userName = 'User_Name'
    let fullName = 'Full_Name'
    let RoleID = 'role_id'
    let departmentcode = 'departmentcode'
    let organization = 'organization'
    let mk_user_type = 'mk_user_type'
    let nation = 'nation'
    let province = 'province'
    let city = 'city'
    let district = 'district'
    let address = 'address'
    // 初始化凭证及用户信息字段
    _sql += `
        /* 凭证及用户信息初始化赋值 */
        select @BVoucher='',@FIBVoucherDate='',@FiYear='',@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}', @mk_deleted=1, @bid='${BID}', @BillCode='', @ModularDetailCode=''
        `
    // 表单变量赋值
    if (_initFormfields.length > 0) {
      _sql += `
        /* 表单变量赋值 */
        select ${_initFormfields.join(',')}
        `
    }
    // 显示列变量赋值
    if (_initColfields.length > 0) {
      _sql += `
        /* 显示列变量赋值 */
        select ${_initColfields.join(',')}
        `
    }
    // 去除禁用的验证
    if (verify.contrasts) {
      verify.contrasts = verify.contrasts.filter(item => item.status !== 'false')
    }
    if (verify.uniques) {
      verify.uniques = verify.uniques.filter(item => item.status !== 'false')
    }
    if (verify.customverifys) {
      verify.customverifys = verify.customverifys.filter(item => item.status !== 'false')
    }
    if (verify.billcodes) {
      verify.billcodes = verify.billcodes.filter(item => item.status !== 'false')
    }
    if (_initCustomScript) {
      _sql += _initCustomScript
    }
    // 启用账期验证
    if (verify.accountdate === 'true') {
      let orgcode = `''`
      let date = `''`
      if (verify.accountfield && _initvars.includes(verify.accountfield.toLowerCase())) {
        orgcode = '@' + verify.accountfield
      }
      if (verify.voucherdate && _initvars.includes(verify.voucherdate.toLowerCase())) {
        date = '@' + verify.voucherdate
      }
      _sql += `
        /* 账期验证 */
        exec s_FIBVoucherDateCheck @OrgCode=${orgcode},@FIBVoucherDate=${date},@ErrorCode=@ErrorCode OUTPUT,@retmsg=@retmsg OUTPUT
        if @ErrorCode!=''
          GOTO aaa
        `
    }
    // 失效验证,添加数据时不用
    if (btn.sqlType !== 'insert' && btn.Ot !== 'notRequired' && verify.invalid === 'true' && setting.dataresource) {
      let datasource = setting.dataresource
      let customScript = setting.customScript || ''
      let orderBy = setting.order
  //     if (values) {
  //       item.initval = values[item.field] || ''
  //     }
      if (setting.queryType === 'statistics' || customScript) {
        let searches = formatSearch(component.$searches || [])
        let regoptions = getSearchRegs(searches)
        regoptions.push({
          reg: new RegExp('@userName@', 'ig'),
          value: `'${userName}'`
        }, {
          reg: new RegExp('@fullName@', 'ig'),
          value: `'${fullName}'`
        }, {
          reg: new RegExp('@orderBy@', 'ig'),
          value: orderBy
        }, {
          reg: new RegExp('@pageSize@', 'ig'),
          value: 999999
        }, {
          reg: new RegExp('@pageIndex@', 'ig'),
          value: 1
        })
        regoptions.forEach(item => {
          datasource = datasource.replace(item.reg, item.value)
          customScript = customScript.replace(item.reg, item.value)
        })
      }
      if (customScript) {
        _sql += `
        /* 数据源自定义脚本,请注意变量定义是否重复 */
        ${customScript}
        `
      }
      if (btn.Ot === 'requiredOnce') {
        _sql += `
        /* 失效验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select @tbid='X' from ${datasource} right join (select ID from  dbo.SplitComma(@ID@)) sp
        on tb.${primaryKey} =sp.id where tb.${primaryKey} is null
        If @tbid!=''
        Begin
          select @ErrorCode='E',@retmsg='数据已失效'
          goto aaa
        end
        `
      } else {
        _sql += `
        /* 失效验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select @tbid=${primaryKey} from ${datasource} where ${primaryKey}=@ID@
        If @tbid=''
        Begin
          select @ErrorCode='E',@retmsg='数据已失效'
          goto aaa
        end
        `
      }
    }
    // 比较验证
    if (verify.contrasts && verify.contrasts.length > 0) {
      verify.contrasts.forEach(item => {
        _sql += `
        /* 比较验证 */
        If ${item.frontfield} ${item.operator} ${item.backfield}
        Begin
          select @ErrorCode='${item.errorCode}',@retmsg='${item.errmsg}'
            goto aaa
        end
        `
      })
    }
    // 自定义验证
    verify.customverifys && verify.customverifys.forEach(item => {
      _sql += `
        /* 自定义验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select top 1 @tbid='X' from (${item.sql}) a
        If @tbid ${item.result === 'true' ? '!=' : '='}''
        Begin
          select @ErrorCode='${item.errorCode}',@retmsg='${item.errmsg}'
          goto aaa
        end
        `
    })
    // 单号生成,使用上级id(BID)或列表数据,声明变量(检验)
    let _billcodesSql  = ''
    if (formdata && verify.billcodes && verify.billcodes.length > 0) {
      let keys = formdata.map(item => item.key.toLowerCase()) // 表单字段
      verify.billcodes.forEach(item => {
        let _key = item.field.toLowerCase()
        let _linkKey = item.linkField ? item.linkField.toLowerCase() : ''
        if (!keys.includes(_key)) return // 表单中不含单号生成字段
        let _ModularDetailCode = ''
        let _lpline = ''
        if (item.TypeCharOne === 'Lp') {
          if (_linkKey === 'bid' && BID) { // 替换bid
            _lpline = `set @ModularDetailCode= 'Lp'+ right('${item.mark || btn.uuid}'+@BID@,48)`
          } else {
            _lpline = `set @ModularDetailCode= 'Lp'+ right('${item.mark || btn.uuid}'+@${_linkKey},48)`
          }
          _ModularDetailCode = '@ModularDetailCode'
        } else if (item.TypeCharOne === 'BN') {
          let _val = ''
          if (_linkKey === 'bid' && BID) { // 替换bid
            _val = BID
          } else {
            _val = 0
          }
          _ModularDetailCode = `'${item.TypeCharOne + _val}'`
        } else {
          _ModularDetailCode = `'${item.ModularDetailCode}'`
        }
        let _declare = ''
        if (!_vars.includes(_key)) {
          _declare = `Declare @${_key} nvarchar(50)`
          _vars.push(_key)
        }
        _billcodesSql += `
        /* 单号生成 */
        ${_declare}
        select @BillCode='', @${_key}='', @ModularDetailCode=''
        ${_lpline}
        exec s_get_BillCode
          @ModularDetailCode=${_ModularDetailCode},
          @Type=${item.Type},
          @TypeCharOne='${item.TypeCharOne}',
          @TypeCharTwo ='${item.TypeCharTwo}',
          @BillCode =@BillCode output,
          @ErrorCode =@ErrorCode output,
          @retmsg=@retmsg output
        if @ErrorCode!=''
          goto aaa
        set @${_key}=@BillCode
        `
      })
      if (_actionType !== 'insertOrUpdate') {
        _sql += _billcodesSql
      }
    }
    // 唯一性验证,必须存在表单(表单存在时,主键均为单值),必须填写数据源,多行拼接时不可用
    if (formdata && verify.uniques && verify.uniques.length > 0 && btn.Ot !== 'requiredOnce') {
      verify.uniques.forEach(item => {
        let _fieldValue = []                     // 表单键值对field=value
        let _value = []                          // 表单值,用于错误提示
        let _labels = item.fieldlabel.split(',') // 表单提示文字
        let arr = [] // 验证主键
        item.field.split(',').forEach((_field, index) => {
          let _key = _field.toLowerCase()
          let _val = ''
          let _fval = `'${_val}'`
          if (_key === 'bid') { // 表单中没有bid则使用系统bid变量
            _fval = '@BID@'
          }
  //     if (item.blacklist && item.blacklist.length > 0 && !item.hidden) {
  //       if (item.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
  //         item.hidden = true
  //         item.required = false
  //       }
  //     }
          arr.push(_key)
          _fieldValue.push(`${_key}=${_fval}`)
          _value.push(`${_labels[index] || ''}:${_val || ''}`)
        })
        let _verifyType = ''
        if (item.verifyType === 'logic') {
          _verifyType = ' and deleted=0'
        }
        if (!arr.includes(primaryKey.toLowerCase())) {
          _fieldValue.push(`${primaryKey} !='${primaryId}'`)
        }
        _sql += `
        /* 唯一性验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select @tbid='X' from ${btn.sql} where ${_fieldValue.join(' and ')}${_verifyType}
        If @tbid!=''
        Begin
          select @ErrorCode='${item.errorCode}',@retmsg='${_value.join(', ')} 已存在'
          goto aaa
        end
        `
      })
    } else if (verify.uniques && verify.uniques.length > 0 && btn.Ot === 'requiredOnce' && setting.dataresource) {
      let datasource = setting.dataresource
      if (/\s/.test(datasource)) { // 拼接别名
        if (!/tb$/.test(datasource)) {
          datasource = '(' + datasource + ') tb'
        }
      } else {
        datasource = datasource + ' tb'
      }
      if (setting.customScript) {
        _sql += `
        /* 数据源自定义脚本,请注意变量定义是否重复 */
        ${setting.customScript}
        `
      }
      verify.uniques.forEach(item => {
        _sql += `
        /* 同类数据验证 */
        Set @tbid=''
        Select top 1 @tbid='X' from (select distinct ${item.field},1 as n from ${datasource} inner join (select ID from  dbo.SplitComma(@ID@)) sp on tb.${primaryKey}=sp.ID ) a having sum(n)>1
        If @tbid!=''
        Begin
          Set @ErrorCode='E' Set @retmsg='${item.fieldlabel} 值不唯一'
          goto aaa
        end
        `
      })
    }
    let hasvoucher = false
    // 凭证-显示列中选取,必须选行
    if (verify.voucher && verify.voucher.enabled && btn.Ot !== 'requiredOnce') {
      let _voucher = verify.voucher
      hasvoucher = true
      _sql += `
        /* 创建凭证 */
        exec s_BVoucher_Create
          @Bill ='0',
          @BVoucherType ='${_voucher.BVoucherType}',
          @VoucherTypeOne ='${_voucher.VoucherTypeOne}',
          @VoucherTypeTwo ='${_voucher.VoucherTypeTwo}',
          @Type =${_voucher.Type},
          @UserID=@UserID@,
          @Username=@Username,
          @FullName=@FullName,
          @BVoucher =@BVoucher OUTPUT ,
          @FIBVoucherDate =@FIBVoucherDate OUTPUT ,
          @FiYear =@FiYear OUTPUT ,
          @ErrorCode =@ErrorCode OUTPUT,
          @retmsg=@retmsg OUTPUT
        if @ErrorCode!=''
          GOTO aaa
        `
    }
    let _insertsql = ''
    if (_actionType === 'insert' || _actionType === 'insertOrUpdate') { // 添加语句
      let keys = []
      let values = []
      formdata.forEach(item => {
        if (item.writein === false) return
        let _key = item.key.toLowerCase()
        keys.push(_key)
        values.push('@' + _key)
      })
      if (!keys.includes(primaryKey.toLowerCase())) {
        keys.push(primaryKey.toLowerCase())
        values.push('\'' + primaryId + '\'')
      }
      if (!keys.includes('createuserid')) {
        keys.push('createuserid')
        values.push('@userid@')
      }
      if (!keys.includes('createuser')) {
        keys.push('createuser')
        values.push('@username')
      }
      if (!keys.includes('createstaff')) {
        keys.push('createstaff')
        values.push('@fullname')
      }
      if (!keys.includes('bid')) {
        keys.push('bid')
        values.push('@BID@')
      }
      if (!keys.includes('typename')) {
        keys.push('typename')
        values.push('@typename@')
      }
      keys = keys.join(',')
      values = values.join(',')
      _insertsql = `insert into ${btn.sql} (${keys}) select ${values};`
    }
    let _updatesql = ''
    if (_actionType === 'update' || _actionType === 'audit' || _actionType === 'insertOrUpdate') { // 修改语句
      let _form = []
      let _arr = []
      formdata.forEach(item => {
        if (item.writein === false) return
        let _key = item.key.toLowerCase()
        _arr.push(_key)
        _form.push(_key + '=@' + _key)
      })
      if (_actionType === 'audit') {
        if (!_arr.includes('submitdate')) {
          _form.push('submitdate=getdate()')
        }
        if (!_arr.includes('submituser')) {
          _form.push('submituser=@username')
        }
        if (!_arr.includes('submitstaff')) {
          _form.push('submitstaff=@fullname')
        }
        if (!_arr.includes('submituserid')) {
          _form.push('submituserid=@userid@')
        }
      } else {
        if (!_arr.includes('modifydate')) {
          _form.push('modifydate=getdate()')
        }
        if (!_arr.includes('modifyuser')) {
          _form.push('modifyuser=@username')
        }
        if (!_arr.includes('modifystaff')) {
          _form.push('modifystaff=@fullname')
        }
        if (!_arr.includes('modifyuserid')) {
          _form.push('modifyuserid=@userid@')
        }
      }
      if (hasvoucher) {
        if (!_arr.includes('bvoucher')) {
          _form.push('BVoucher=@BVoucher')
        }
        if (!_arr.includes('fibvoucherdate')) {
          _form.push('FIBVoucherDate=@FIBVoucherDate')
        }
        if (!_arr.includes('fiyear')) {
          _form.push('FiYear=@FiYear')
        }
      }
      if (!_arr.includes('typename')) {
        _form.push('typename=@typename@')
      }
      _form = _form.join(',')
      let _ID = '=@ID@'
      if (btn.Ot === 'requiredOnce') {
        _ID = ' in (select ID from  dbo.SplitComma(@ID@))'
      }
      _updatesql = `update ${btn.sql} set ${_form} where ${primaryKey}${_ID};`
    }
    if (_prevCustomScript) {
      _sql += _prevCustomScript
    }
    // 添加、修改、逻辑删除、物理删除
    if (_actionType === 'insert') {
      _sql += `
        /* 默认sql */
        ${_insertsql}`
    } else if (_actionType === 'update' || _actionType === 'audit') {
      _sql += `
        /* 默认sql */
        ${_updatesql}`
    } else if (_actionType === 'LogicDelete') { // 逻辑删除
      let _ID = '=@ID@'
      if (btn.Ot === 'requiredOnce') {
        _ID = ' in (select ID from  dbo.SplitComma(@ID@))'
      }
      _sql += `
        /* 默认sql */
        update ${btn.sql} set deleted=@mk_deleted,modifydate=getdate(),modifyuser=@username,modifystaff=@fullname,modifyuserid=@userid@ where ${primaryKey}${_ID};`
    } else if (_actionType === 'delete') {      // 物理删除
      let _msg = ''
      if (columns && columns.length > 0 && btn.Ot !== 'notRequired') {
        let _index = 0
        columns.forEach(col => {
          if (!col.field || col.Hide === 'true' || _index >= 4) return
          _msg += col.label + '=0,'
          _index++
        })
      }
      let _ID = '=@ID@'
      if (btn.Ot === 'requiredOnce') {
        _ID = ' in (select ID from  dbo.SplitComma(@ID@))'
      }
      _sql += `
        /* 默认sql */
        insert into snote (remark,createuserid,CreateUser,CreateStaff,typename) select left('删除表:${btn.sql} 数据: ${_msg}${primaryKey}='+@ID@,200),@userid@,@username,@fullname,@typename@
        delete ${btn.sql} where ${primaryKey}${_ID};`
    } else if (_actionType === 'insertOrUpdate') {
      _sql += `
        /* 默认sql */
        select @tbid=''
        select @tbid='X' from ${btn.sql} where ${primaryKey}=@ID@
        if @tbid=''
          begin
          ${_billcodesSql}
          ${_insertsql}
          end
        else
          begin
          ${_updatesql}
          end
      `
    }
    if (verify.workFlow === 'true' && process) {
      let status = 888
      let statusName = '结束'
      let detailId = '0'
      if (verify.flowSql === 'true') {
        _sql += `
        /* 工作流默认sql */
        insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
        select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@
        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@
        insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
        select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
        `
      }
      _sql = _sql.replace(/@start_type@/ig, `'开始'`)
      _sql = _sql.replace(/@check_type@/ig, `'审核'`)
      _sql = _sql.replace(/@notice_type@/ig, `'抄送'`)
      _sql = _sql.replace(/@check_userids@/ig, `''`)
      _sql = _sql.replace(/@notice_userids@/ig, `''`)
      _sql = _sql.replace(/@works_flow_code@/ig, `'mk'`)
      _sql = _sql.replace(/@works_flow_name@/ig, `'mk'`)
      _sql = _sql.replace(/@works_flow_param@/ig, `''`)
      _sql = _sql.replace(/@works_flow_detail_id@/ig, `'${detailId}'`)
      _sql = _sql.replace(/@status@/ig, `'${status}'`)
      _sql = _sql.replace(/@statusname@/ig, `'${statusName}'`)
      _sql = _sql.replace(/@work_group@/ig, `'mk'`)
      _sql = _sql.replace(/@work_grade@/ig, `'0'`)
    }
    if (_backCustomScript) {
      _sql += _backCustomScript
    }
    if (btn.procMode === 'system') {
      _sql += `
        aaa: if @ErrorCode!=''
        insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@`
    } else if (btn.output) {
      _sql += `
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg,${btn.output} as mk_b_id`
    } else {
      _sql += `
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    }
    _sql = _sql.replace(/@ID@/ig, `'${primaryId || ''}'`)
    _sql = _sql.replace(/@BID@/ig, `'${BID}'`)
    _sql = _sql.replace(/@LoginUID@/ig, `'LoginUID'`)
    _sql = _sql.replace(/@SessionUid@/ig, `'SessionUid'`)
    _sql = _sql.replace(/@UserID@/ig, `'UserID'`)
    _sql = _sql.replace(/@Appkey@/ig, `'appkey'`)
    _sql = _sql.replace(/@typename@/ig, `'typename'`)
    _sql = _sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, `''`)
    return _sql
  }
  //     if (item.required) {
  //       required = true
  //     }
  getExcelInSql = (item) => {
    let btn = item.verify
    let userName = 'User_Name'
    let fullName = 'Full_Name'
    let RoleID = 'role_id'
    let departmentcode = 'departmentcode'
    let organization = 'organization'
    let mk_user_type = 'mk_user_type'
    let nation = 'nation'
    let province = 'province'
    let city = 'city'
    let district = 'district'
    let address = 'address'
    let _sheet = item.sheet
    if (window.GLOB.externalDatabase !== null) {
      _sheet = _sheet.replace(/@db@/ig, window.GLOB.externalDatabase)
    }
    let database = _sheet.match(/(.*)\.(.*)\./ig)
    let sheet = _sheet.replace(/(.*)\.(.*)\./ig, '')
    database = database ? (database[0] || '') : ''
    let getuuid = () => {
      let uuid = []
      let timestamp = new Date().getTime()
      let _options = '0123456789abcdefghigklmnopqrstuv'
      for (let i = 0; i < 19; i++) {
        uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
      }
      uuid = timestamp + uuid.join('')
      return uuid
    }
  //     if (item.type === 'text' || item.type === 'select') {
  //       if (/,/.test(item.field)) {
  //         item.field.split(',').forEach(field => {
  //           keys.push(field.toLowerCase())
  //         })
  //       } else {
  //         keys.push(item.field.toLowerCase())
  //       }
  //     } else if (item.type === 'group') {
  //       keys.push(item.field.toLowerCase())
  //       keys.push(item.datefield.toLowerCase())
  //     }
    let upId = getuuid()
    let vals = []
    btn.columns.forEach(col => {
      if (col.import === 'false') return
  //     return item
  //   })
      let val = ''
      if (col.import === 'init') {
        if (/^Nvarchar/ig.test(col.type)) {
          val = ''
        } else if (/^Decimal/ig.test(col.type) || /^int/ig.test(col.type)) {
          val = 0
        } else if (col.type === 'date') {
          val = '1949-10-01'
        } else if (col.type === 'datetime') {
          val = '1949-10-01 00:00:00'
        }
      } else if (/^Nvarchar/ig.test(col.type)) {
        val = 'mk'
      } else if (/^Decimal/ig.test(col.type) || /^int/ig.test(col.type)) {
        val = 1
      } else if (col.type === 'date') {
        val = '1949-10-01'
      } else if (col.type === 'datetime') {
        val = '1949-10-01 00:00:00'
      }
  //   config.$s_keys = keys
  //   config.$s_req = required
  // }
      vals.push(`'${val}'`)
    })
    vals.push(`'${upId}000010'`)
    vals.push(`'bid'`)
    vals =  `Select ${vals.join(',')}`
    let sql = ''
    let _initCustomScript = '' // 初始化脚本
    let _prevCustomScript = '' // 默认sql前执行脚本
    let _backCustomScript = '' // 默认sql后执行脚本
    let regs = [
      {reg: new RegExp('(^|\\s)@' + sheet + '(\\s|$)', 'ig'), value: ` #${sheet} `},
      {reg: new RegExp('(^|\\s)@' + sheet + '\\(', 'ig'), value: ` #${sheet}(`},
      {reg: new RegExp('(^|\\s)@' + sheet + '\\)', 'ig'), value: ` #${sheet})`},
      {reg: /@ID@/ig, value: `'id'`},
      {reg: /@BID@/ig, value: `'bid'`},
      {reg: /@LoginUID@/ig, value: `'LoginUID'`},
      {reg: /@SessionUid@/ig, value: `'SessionUid'`},
      {reg: /@UserID@/ig, value: `'UserID'`},
      {reg: /@Appkey@/ig, value: `'appkey'`},
      {reg: /@typename@/ig, value: `'admin'`},
      {reg: /\$@/ig, value: ''},
      {reg: /@\$/ig, value: ''},
      {reg: /@datam@/ig, value: `''`},
    ]
    if (window.GLOB.externalDatabase !== null) {
      regs.push({reg: /@db@/ig, value: window.GLOB.externalDatabase})
    }
    btn.scripts && btn.scripts.forEach(script => {
      if (script.status === 'false') return
      let _sql = script.sql
      regs.forEach(item => {
        _sql = _sql.replace(item.reg, item.value)
      })
      if (script.position === 'init') {
        _initCustomScript += `
      /* 自定义脚本 */
      ${_sql}
      `
      } else if (script.position === 'front') {
        _prevCustomScript += `
      /* 自定义脚本 */
      ${_sql}
      `
      } else {
        _backCustomScript += `
      /* 自定义脚本 */
      ${_sql}
      `
      }
    })
    let _uniquesql = ''
    if (btn.uniques && btn.uniques.length > 0) {
      btn.uniques.forEach(unique => {
        if (unique.status === 'false' || !unique.verifyType) return
        let _fields = unique.field.split(',')
        let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
        let _afields = _fields.map(_field => `a.${_field}`)
        _fields_ = _fields_.join(' and ')
        if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
          _fields_ += ' and b.deleted=0'
        }
        _uniquesql += `
      /* 重复性验证 */
      Set @tbid=''
      Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${unique.field} from #${sheet} ) a group by ${unique.field} having sum(n)>1
      If @tbid!=''
      Begin
        select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 重复'
        goto aaa
      end
      ${unique.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
      Select top 1 @tbid=${_afields.join('+\' \'+')} from  #${sheet} a Inner join ${sheet} b on ${_fields_}
      If @tbid!=''
      Begin
        select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 与已有数据重复'
        goto aaa
      end` : ''}
      `
      })
    }
    let declarefields = []
    let fields = []
    btn.columns.forEach(col => {
      if (col.import === 'false') return
      if (col.type === 'date') {
        declarefields.push(`${col.Column} Nvarchar(50)`)
      } else {
        declarefields.push(`${col.Column} ${col.type}`)
      }
      fields.push(col.Column)
    })
    fields = fields.join(',')
    let _insert = ''
    if (btn.default !== 'false') {
      _insert = `
      /* 默认sql */
      Insert into ${database}${sheet} (${fields},createuserid,createuser,createstaff,bid)
      Select ${fields},'${sessionStorage.getItem('UserID') || ''}',@username,@fullname,'bid' From #${sheet}
      `
    }
    sql = `create table #${sheet} (${declarefields.join(',')},jskey nvarchar(50),BID nvarchar(50) )
      Declare @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),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@tbid Nvarchar(512)
      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}'
      ${_initCustomScript}
      Insert into #${sheet} (${fields},jskey,BID)
      /* excel数据*/
      ${vals}
      ${_uniquesql}
      ${_prevCustomScript}
      ${_insert}
      ${_backCustomScript}
      drop table #${sheet}
      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    return sql
  }
  getEditTableSql = (verify, cols, columns) => {
    let btn = verify
    let userName = sessionStorage.getItem('User_Name') || ''
    let fullName = sessionStorage.getItem('Full_Name') || ''
    let RoleID = sessionStorage.getItem('role_id') || ''
    let departmentcode = sessionStorage.getItem('departmentcode') || ''
    let organization = sessionStorage.getItem('organization') || ''
    let mk_user_type = sessionStorage.getItem('mk_user_type') || ''
    let nation = sessionStorage.getItem('nation') || ''
    let province = sessionStorage.getItem('province') || ''
    let city = sessionStorage.getItem('city') || ''
    let district = sessionStorage.getItem('district') || ''
    let address = sessionStorage.getItem('address') || ''
    let _sheet = btn.sheet
    let BID = 'bid'
    if (window.GLOB.externalDatabase !== null) {
      _sheet = _sheet.replace(/@db@/ig, window.GLOB.externalDatabase)
    }
    let database = _sheet.match(/(.*)\.(.*)\./ig)
    let sheet = _sheet.replace(/(.*)\.(.*)\./ig, '')
    database = database ? (database[0] || '') : ''
    let vals = []
    let forms = []
    let _fields = {}
    columns.forEach(col => {
      _fields[col.field] = col.datatype
    })
    let getColumns = (cols) => {
      cols.forEach(item => {
        if (item.type === 'colspan') {
          getColumns(item.subcols)
        } else if (item.editable === 'true') {
          forms.push({
            field: item.field,
            type: item.type,
            datatype: _fields[item.field] || 'nvarchar(50)'
          })
        }
      })
    }
    getColumns(cols)
    forms.forEach(col => {
      if (col.type === 'number') {
        vals.push(`1`)
      } else {
        vals.push(`'mk'`)
      }
    })
    vals.push(`'uuid'`)
    vals.push(`'upt'`)
    vals.push(`'${BID}'`)
    vals = `Select ${vals.join(',')}`
    let sql = ''
    let _initCustomScript = '' // 初始化脚本
    let _prevCustomScript = '' // 默认sql前执行脚本
    let _backCustomScript = '' // 默认sql后执行脚本
    let isDM = sessionStorage.getItem('dataM') === 'true'
    let regs = [
      {reg: new RegExp('(^|\\s)@' + sheet + '(\\s|$)', 'ig'), value: ` #${sheet} `},
      {reg: new RegExp('(^|\\s)@' + sheet + '\\(', 'ig'), value: ` #${sheet}(`},
      {reg: new RegExp('(^|\\s)@' + sheet + '\\)', 'ig'), value: ` #${sheet})`},
      {reg: /@BID@/ig, value: `'${BID}'`},
      {reg: /@LoginUID@/ig, value: `'${sessionStorage.getItem('LoginUID') || ''}'`},
      {reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      {reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      {reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      {reg: /@typename@/ig, value: `'admin'`},
      {reg: /\$@/ig, value: isDM ? '/*' : ''},
      {reg: /@\$/ig, value: isDM ? '*/' : ''},
      {reg: /@datam@/ig, value: isDM ? `'Y'` : `''`},
    ]
    if (window.GLOB.externalDatabase !== null) {
      regs.push({reg: /@db@/ig, value: window.GLOB.externalDatabase})
    }
    btn.scripts && btn.scripts.forEach(script => {
      if (script.status === 'false') return
      let _sql = script.sql
      regs.forEach(item => {
        _sql = _sql.replace(item.reg, item.value)
      })
      if (script.position === 'init') {
        _initCustomScript += `
      /* 自定义脚本 */
      ${_sql}
      `
      } else if (script.position === 'front') {
        _prevCustomScript += `
      /* 自定义脚本 */
      ${_sql}
      `
      } else {
        _backCustomScript += `
      /* 自定义脚本 */
      ${_sql}
      `
      }
    })
    let _uniquesql = ''
    if (btn.uniques && btn.uniques.length > 0) {
      btn.uniques.forEach(unique => {
        if (unique.status === 'false' || !unique.verifyType) return
        let _fields = unique.field.split(',')
        let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
        let _afields = _fields.map(_field => `a.${_field}`)
        _fields_ = _fields_.join(' and ')
        if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
          _fields_ += ' and b.deleted=0'
        }
        _uniquesql += `
      /* 重复性验证 */
      Set @tbid=''
      Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${unique.field} from #${sheet} ) a group by ${unique.field} having sum(n)>1
      If @tbid!=''
      Begin
        select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 重复'
        goto aaa
      end
      ${unique.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
      Select top 1 @tbid=${_afields.join('+\' \'+')} from  #${sheet} a Inner join ${sheet} b on ${_fields_}
      If @tbid!=''
      Begin
        select @ErrorCode='${unique.errorCode}',@retmsg=@tbid+' 与已有数据重复'
        goto aaa
      end` : ''}
      `
      })
    }
    let declarefields = []
    let fields = []
    forms.forEach(col => {
      let key = col.field.toLowerCase()
      if (key === 'jskey' || key === 'bid' || key === 'data_type') return
      declarefields.push(`${col.field} ${col.datatype}`)
      fields.push(col.field)
    })
    fields = fields.join(',')
    let _insert = ''
    if (btn.default !== 'false') {
      _insert = `
      /* 默认sql */
      Insert into ${database}${sheet} (${fields},createuserid,createuser,createstaff,bid)
      Select ${fields},'${sessionStorage.getItem('UserID') || ''}',@username,@fullname,'${BID}' From #${sheet}
      `
    }
    sql = `create table #${sheet} (${declarefields.join(',')},jskey nvarchar(50),data_type nvarchar(50),BID nvarchar(50) )
      Declare @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),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@tbid Nvarchar(512)
      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}'
      ${_initCustomScript}
      Insert into #${sheet} (${fields},jskey,data_type,BID)
      /* excel数据*/
      ${vals}
      ${_uniquesql}
      ${_prevCustomScript}
      ${_insert}
      ${_backCustomScript}
      drop table #${sheet}
      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    return sql
  }
  getExcelOutSql = (btn, component) => {
    let item = {setting: {}, columns: [], search: []}
    btn.verify.columns.forEach(col => {
      if (col.Column && col.Column !== '$Index') {
        item.columns.push({
          field: col.Column
        })
      }
    })
    if (btn.verify.useSearch !== 'false') {
      item.search = component.$searches
    }
    item.setting.interType = 'system'
    item.setting.execute = btn.verify.defaultSql || 'true'
    item.setting.dataresource = btn.verify.dataresource || ''
    item.setting.primaryKey = btn.verify.primaryKey || component.setting.primaryKey || 'ID'
    item.setting.queryType = btn.verify.queryType
    item.setting.laypage = btn.pagination
    item.setting.order = btn.verify.order || ''
    item.scripts = btn.verify.scripts || []
    let regs = [
      { reg: /\$@/ig, value: '' },
      { reg: /@\$/ig, value: '' },
      { reg: /@datam@/ig, value: `''` },
    ]
    if (window.GLOB.externalDatabase !== null) {
      regs.push({
        reg: /@db@/ig,
        value: window.GLOB.externalDatabase
      })
    }
    let sql = this.formatDataSource(item, regs)
    return sql
  }
  formatDataSource = (item, regs, mainSearch = []) => {
    if (!item.setting || item.setting.interType !== 'system') return false
    let searches = item.search || []
    if (item.setting.useMSearch === 'true' && mainSearch.length > 0) {
      searches = [...searches, ...mainSearch]
    }
    item.$searches = fromJS(searches).toJS()
    searches = formatSearch(searches)
    let _columns = item.columns || []
    if (item.subtype === 'dualdatacard') {
      _columns = [...item.columns, ...item.subColumns]
    }
    let arr_field = _columns.map(col => col.field).join(',')
    let _customScript = ''
    let _tailScript = ''
    let _dataresource = ''
    item.scripts && item.scripts.forEach(script => {
      if (script.status === 'false') return
      if (script.position !== 'back') {
        _customScript += `
        ${script.sql}
        `
      } else {
        _tailScript += `
        ${script.sql}
        `
      }
    })
    if (item.setting.execute !== 'false') {
      _dataresource = item.setting.dataresource || ''
    }
    let _search = joinMainSearchkey(searches)
    if (item.setting.queryType === 'statistics') {
      _search = ''
    }
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    item.setting.dataresource = _dataresource
    item.setting.customScript = _customScript
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    if (_dataresource) {
      if (custompage) {
        _dataresource = `/*system_query*/select ${arr_field} from ${_dataresource} ${_search} `
      } else if (item.setting.laypage === 'true' && item.setting.order) {
        _dataresource = `/*system_query*/select top 10 ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${item.setting.order}) as rows from ${_dataresource} ${_search}) tmptable where rows > 0 order by tmptable.rows `
      } else if (item.setting.order) {
        _dataresource = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${item.setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
      } else {
        _dataresource = `/*system_query*/select ${arr_field} from ${_dataresource} ${_search} `
      }
    }
    let sql = ''
    if (_customScript) {
      sql = `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 =''
        ${_customScript}
        ${_dataresource}
        ${_tailScript}
        aaa:
        if @ErrorCode!=''
          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select '1949-10-01 15:00:00',@ErrorCode, @retmsg,'1949-10-01 15:00:00'
      `
    } else if (_tailScript) {
      sql = `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 =''
        ${_dataresource}
        ${_tailScript}
        aaa:
        if @ErrorCode!=''
          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select '1949-10-01 15:00:00',@ErrorCode, @retmsg,'1949-10-01 15:00:00'
      `
    } else {
      sql = `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 =''
        ${_dataresource}`
    }
    regs.forEach(cell => {
      sql = sql.replace(cell.reg, cell.value)
    })
    let regoptions = getSearchRegs(searches)
    regoptions.push(
      { reg: /@orderBy@/ig, value: item.setting.order || '' },
      { reg: /@pageSize@/ig, value: 9999 },
      { reg: /@pageIndex@/ig, value: 1},
      { reg: /@ID@/ig, value: `''`},
      { reg: /@BID@/ig, value: `''`},
      { reg: /@LoginUID@/ig, value: `'${sessionStorage.getItem('LoginUID') || ''}'`},
      { reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      { reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      { reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      { reg: /@typename@/ig, value: `'admin'`},
    )
    if (item.type === 'calendar') {
      regoptions.push({ reg: /@mk_year@/ig, value: '2023' })
    }
    regoptions.forEach(cell => {
      sql = sql.replace(cell.reg, cell.value)
    })
    return sql
  }
  continue = () => {
    this.setState({status: 'continue'}, () => {
      this.roopSql()
    })
  }
  roopSql = () => {
    if (this.verSqls.length === 0) {
      this.setState({status: 'over'})
      return
    }
    if (this.state.status === 'stop') return
    let item = this.verSqls.shift()
    this.setState({status: this.verSqls.length > 0 ? 'loading' : 'over', execId: item.uuid})
    console.info(`/* 组件:${item.name}  检验项:${item.label} */`)
    Api.sDebug(item.sql).then(result => {
      if (result.status || result.ErrCode === '-2') {
        this.setState({successIds: [...this.state.successIds, item.uuid], execId: ''})
        if (this.verSqls.length > 0) {
          setTimeout(() => {
            this.roopSql()
          }, 100)
        }
      } else {
        let errorMsg = fromJS(this.state.errorMsg).toJS()
        errorMsg[item.uuid] = result.message
        this.setState({
          execId: '',
          status: this.verSqls.length > 0 ? 'error' : 'over',
          errorIds: [...this.state.errorIds, item.uuid],
          errorMsg: errorMsg
        })
        Modal.error({
          title: result.message
        })
      }
    })
  }
  stop = () => {
    this.setState({status: 'stop'})
  }
  over = () => {
    this.verSqls = []
    this.setState({status: 'over', visible: false})
  }
  render() {
    const { visible, confirming } = this.state
    const { visible, sqlList, status, successIds, errorIds, execId, errorMsg } = this.state
    return (
      <>
        <Button className="mk-border-yellow" icon="bug" onClick={this.trigger}>调试</Button>
        <Modal
          title="SQL验证"
          wrapClassName="debug-modal"
          visible={visible}
        <Drawer
          className="debug-modal"
          width={600}
          maskClosable={false}
          onOk={this.submit}
          onCancel={() => { this.setState({ visible: false })}}
          confirmLoading={confirming}
          visible={visible}
          closable={false}
          placement="left"
          destroyOnClose
        >
        </Modal>
          <div className="mk-sql-wrap">
            {/* <div className="header">
              <div className="sql-item">
                <div className="sql-1">组件</div>
                <div className="sql-2">检验项</div>
                <div className="sql-3">其他</div>
                <div className="sql-4">状态</div>
              </div>
            </div> */}
            <div className="body">
              {sqlList.map(item => {
                let other = ''
                if (item.supName) {
                  other = `上级:${item.supName}-${item.tabName}`
                }
                let status = <ClockCircleOutlined />
                if (successIds.includes(item.uuid)) {
                  status = <CheckCircleOutlined />
                } else if (errorIds.includes(item.uuid)) {
                  if (errorMsg[item.uuid]) {
                    status = <Tooltip placement="topLeft" title={errorMsg[item.uuid]}>
                      <CloseCircleOutlined />
                    </Tooltip>
                  } else {
                    status = <CloseCircleOutlined />
                  }
                } else if (item.uuid === execId) {
                  status = <LoadingOutlined />
                }
                return <div className="sql-item" key={item.uuid}>
                  <div className="sql-1" title={item.name}><div>{item.name}</div></div>
                  <div className="sql-2" title={item.label}><div>{item.label}</div></div>
                  <div className="sql-3" title={other}><div>{other}</div></div>
                  <div className="sql-4">{status}</div>
                </div>
              })}
            </div>
          </div>
          <div className="mk-footer">
            {status === 'error' ? <Button key="skip" className="mk-border-green" onClick={this.roopSql}>
              跳过
            </Button> : null}
            {status === 'loading' ? <Button key="stop" className="mk-border-orange" onClick={this.stop}>
              暂停
            </Button> : null}
            {status === 'stop' ? <Button key="continue" className="mk-border-orange" onClick={this.continue}>
              继续
            </Button> : null}
            <Button key="colse" className="mk-border-danger" onClick={this.over}>
              关闭
            </Button>
          </div>
        </Drawer>
      </>
    )
  }
src/menu/debug/index.scss
@@ -1,9 +1,106 @@
.replace-field-modal {
  .ant-modal {
    top: 70px;
.debug-modal {
  .ant-drawer-body {
    position: relative;
    height: 100vh;
    padding: 0 0 50px 0;
    overflow: hidden;
    color: rgba(0, 0, 0, 0.85);
    .mk-sql-wrap {
      padding: 10px;
      .sql-item {
        display: flex;
        min-height: 30px;
        .sql-1, .sql-2 {
          flex: 1;
          width: 25%;
          max-width: 25%;
          display: flex;
          align-items: center;
          div {
            overflow: hidden;
            word-break: break-word;
            white-space: nowrap;
            text-overflow: ellipsis;
          }
        }
        .sql-3 {
          flex: 1;
          width: 30%;
          max-width: 30%;
          display: flex;
          align-items: center;
          div {
            overflow: hidden;
            word-break: break-word;
            white-space: nowrap;
            text-overflow: ellipsis;
          }
        }
        .sql-4 {
          flex: 1;
          width: 20%;
          max-width: 20%;
          display: flex;
          justify-content: center;
          align-items: center;
          .anticon {
            font-size: 16px;
          }
          .anticon-clock-circle {
            color: #c8c8c8;
          }
          .anticon-check-circle {
            color: #26C281;
          }
          .anticon-close-circle {
            color: red;
          }
          .anticon-loading {
            color: orange;
          }
        }
      }
      .header {
        border-bottom: 1px solid #e8e8e8;
      }
      .body {
        max-height: calc(100vh - 60px);
        overflow-y: auto;
      }
    }
    .mk-sql-wrap .body::-webkit-scrollbar {
      width: 7px;
    }
    .mk-sql-wrap .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);
    }
    .mk-sql-wrap .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-body {
    min-height: 150px;
    padding-top: 40px;
  .mk-footer {
    position: absolute;
    bottom: 0px;
    width: 100%;
    height: 45px;
    line-height: 50px;
    border-top: 1px solid #e8e8e8;
    text-align: right;
    padding-right: 20px;
    .ant-btn:not(:first-child) {
      margin-left: 15px;
    }
  }
}
src/mob/components/search/single-search/options.jsx
@@ -42,6 +42,7 @@
      field: 'initval',
      label: '初始值',
      initval: wrap.initval || '',
      tooltip: '可使用@username@、@fullName@',
      required: false
    },
    {
src/mob/searchconfig/settingform/index.jsx
@@ -127,7 +127,12 @@
            </Form.Item>
          </Col> : null}
          {type === 'search' ? <Col span={12}>
            <Form.Item label="初始值">
            <Form.Item label={
              <Tooltip placement="topLeft" title="可使用@username@、@fullName@。">
                <QuestionCircleOutlined className="mk-form-tip" />
                初始值
              </Tooltip>
            }>
              {getFieldDecorator('initval', {
                initialValue: config.setting.initval,
                rules: [
src/tabviews/basetable/index.jsx
@@ -112,7 +112,6 @@
            config.flow_code = result.works_flow_code
            config.flow_name = result.works_flow_name
            unset = false
            window.GLOB.UserCacheMap.set('flow' + MenuID, flowConfig)
          } catch (e) {
            unset = true
@@ -191,7 +190,7 @@
      }
      if (config.flow_code) {
        regs.push({ reg: /@works_flow_code@/ig, value: config.flow_code })
        regs.push({ reg: /@works_flow_code@/ig, value: `'${config.flow_code}'` })
      }
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, skip, param, MenuID, config.MenuName, config.process === 'true')
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -76,7 +76,7 @@
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props.data), fromJS(nextProps.data)) || (nextProps.syncData && !is(fromJS(this.props.syncData), fromJS(nextProps.syncData)))
    return !is(fromJS(this.props.data), fromJS(nextProps.data)) || (nextProps.syncData ? !is(fromJS(this.props.syncData), fromJS(nextProps.syncData)) : false)
  }
  /**
src/tabviews/custom/components/chart/antv-X6/index.jsx
@@ -1003,8 +1003,16 @@
      if (!isNew) return
      let target = edge.getTargetCell()
      let mkdata = target ? target.prop('mkdata') : null
      if (!target) return
      let mkdata = target.prop('mkdata')
      if (target.prop('mknode') === 'end') {
        edge.prop('mknode', 'endEdge')
      } else if (target.prop('mknode') === 'start') {
        edge.prop('mknode', 'startEdge')
      }
      if (mkdata) {
        edge.prop('mkdata', {status: mkdata.status, statusName: mkdata.statusName})
      }
@@ -1550,10 +1558,23 @@
    let _status = status
    if (plot.subtype === 'xflow' && status === 10) {
      let start_num = nodes.cells.filter(cell => cell.mknode === 'start').length
      let end_num = nodes.cells.filter(cell => cell.mknode === 'end').length
      let start_num = 0
      let end_num = 0
      let unvalid = false
      
      if (start_num !== 1 || end_num !== 1) {
      nodes.cells.forEach(item => {
        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) {
            unvalid = true
          }
        }
      })
      if (start_num !== 1 || end_num !== 1 || unvalid) {
        _status = 0
      }
    }
@@ -1968,8 +1989,22 @@
    
    if (plot.subtype === 'xflow' && _status === 10) {
      let nodes = this.mkGraph.toJSON()
      let start_num = nodes.cells.filter(cell => cell.mknode === 'start').length
      let end_num = nodes.cells.filter(cell => cell.mknode === 'end').length
      let start_num = 0
      let end_num = 0
      let unvalidId = ''
      nodes.cells.forEach(item => {
        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) {
            unvalidId = item.id
          }
        }
      })
      if (start_num === 0) {
        notification.warning({
@@ -1995,6 +2030,23 @@
          message: '结束节点不可添加多个!',
          duration: 2
        })
      } else if (unvalidId) {
        let edge = this.mkGraph.getCellById(unvalidId)
        let node = edge.getTargetCell()
        let title = ''
        if (node.attrs && node.attrs.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 {
        this.setState({status: _status})
      }
src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx
@@ -474,6 +474,7 @@
            {mkdata ? <div className="mk-data">
              <div>状态:{mkdata.status}<span style={{float: 'right'}}>{mkdata.statusName}</span></div>
              {mknode.shape !== 'edge' && !mknode.mknode ? <div>标记:{mkdata.sign || ''}</div> : null}
              {mknode.shape === 'edge' && mkdata.flowType ? <div>操作:{mkdata.flowType === 'reject' ? '驳回' : '审批'}</div> : null}
              {mkdata.members && mkdata.members.length ? <div>审批人:{mkdata.members.map(item => item.workername).join('、')}</div> : null}
              {mkdata.copys && mkdata.copys.length ? <div>抄送人:{mkdata.copys.map(item => item.workername).join('、')}</div> : null}
              <div>备注:{mkdata.remark || ''}</div>
src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx
@@ -13,7 +13,9 @@
    orgs: PropTypes.array
  }
  state = {}
  state = {
    flowType: this.props.data.flowType || 'approval'
  }
  handleConfirm = () => {
    return new Promise((resolve, reject) => {
@@ -30,6 +32,7 @@
  render() {
    const { node, orgs } = this.props
    const { getFieldDecorator } = this.props.form
    const { flowType } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -46,6 +49,10 @@
      nodetype = 'start'
    } else if (node.mknode === 'end') {
      nodetype = 'end'
    } else if (node.mknode === 'endEdge') {
      nodetype = 'endEdge'
    } else if (node.mknode === 'startEdge') {
      nodetype = 'startEdge'
    }
    return (
@@ -62,7 +69,7 @@
                  }
                ]
              })(
                <InputNumber precision={0}/>
                <InputNumber readOnly={nodetype !== 'node' && nodetype !== 'edge'} precision={0}/>
              )}
            </Form.Item>
          </Col>
@@ -90,6 +97,18 @@
            </Form.Item>
          </Col> : null}
          {nodetype === 'edge' ? <Col span={12}>
            <Form.Item label="操作类型">
              {getFieldDecorator('flowType', {
                initialValue: flowType
              })(
                <Radio.Group onChange={(e) => this.setState({flowType: e.target.value})}>
                  <Radio value="approval">审批</Radio>
                  <Radio value="reject">驳回</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
          {nodetype === 'edge' ? <Col span={12}>
            <Form.Item label="设置审批人">
              {getFieldDecorator('approver', {
                initialValue: data.approver || 'member'
@@ -102,7 +121,7 @@
              )}
            </Form.Item>
          </Col> : null}
          {nodetype === 'edge' ? <Col span={12}>
          {nodetype === 'edge' && flowType !== 'reject' ? <Col span={12}>
            <Form.Item label="审批方式">
              {getFieldDecorator('approvalMethod', {
                initialValue: data.approvalMethod || 'orsign'
src/tabviews/custom/index.jsx
@@ -232,7 +232,7 @@
      }
      if (config.flow_code) {
        regs.push({ reg: /@works_flow_code@/ig, value: config.flow_code })
        regs.push({ reg: /@works_flow_code@/ig, value: `'${config.flow_code}'` })
      }
      config.$cache = config.cacheLocal === 'true'
@@ -278,7 +278,7 @@
      config.components = this.formatSetting(config.components, params, inherit, regs, balMap)
      if ([...balMap.keys()].length > 0) {
      if (balMap.size > 0) {
        config.components = this.filterBalcony(config.components, balMap)
      }
src/tabviews/custom/popview/index.jsx
@@ -125,7 +125,7 @@
    if (Tab.$process && window.GLOB.UserCacheMap.has(Tab.$flowId)) {
      let flow = window.GLOB.UserCacheMap.get(Tab.$flowId)
      regs.push({ reg: /@works_flow_code@/ig, value: flow.flow_code || '' })
      regs.push({ reg: /@works_flow_code@/ig, value: `'${flow.flow_code || ''}'` })
    }
    config.components = this.filterComponent(config.components, roleId, balMap, param, Tab, Tab.uuid, Tab.uuid)
@@ -158,7 +158,7 @@
    config.components = this.formatSetting(config.components, params, regs, balMap)
    if ([...balMap.keys()].length > 0) {
    if (balMap.size > 0) {
      config.components = this.filterBalcony(config.components, balMap)
    }
src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -448,8 +448,6 @@
    
    let imgCol = false
    let columns = btn.verify.columns.filter(col => {
      if (col.output === 'false') return false
      if (col.type === 'image') {
        imgCol = true
      }
@@ -464,6 +462,7 @@
    if (data && data[0]) {
      let errors = []
      columns.forEach(col => {
        if (col.output === 'false') return
        if (col.Column && data[0][col.Column] === undefined) {
          errors.push(col.Text)
        }
@@ -509,7 +508,13 @@
  
          columns.forEach((col, i) => {
            let val = item[col.Column]
            if (col.type === 'number' && typeof(val) === 'number') {
            if (col.output === 'false') {
              if (col.type === 'number') {
                val = 0
              } else {
                val = ''
              }
            } else if (col.type === 'number' && typeof(val) === 'number') {
              if (col.abs === 'true') {
                val = Math.abs(val)
              }
@@ -594,7 +599,13 @@
          columns.forEach((col, i) => {
            let val = item[col.Column]
            if (col.type === 'number' && typeof(val) === 'number') {
            if (col.output === 'false') {
              if (col.type === 'number') {
                val = 0
              } else {
                val = ''
              }
            } else if (col.type === 'number' && typeof(val) === 'number') {
              if (col.abs === 'true') {
                val = Math.abs(val)
              }
@@ -766,7 +777,7 @@
      _setting.arr_field = _setting.arr_field.join(',')
      _setting.execute = btn.verify.defaultSql !== 'false'
      _setting.dataresource = btn.verify.dataresource || ''
      _setting.primaryKey = _setting.primaryKey || setting.primaryKey || 'ID'
      _setting.primaryKey = btn.verify.primaryKey || setting.primaryKey || 'ID'
      if (!_setting.execute) {
        _setting.dataresource = ''
@@ -813,8 +824,11 @@
      _orderBy = btn.verify.order || ''
    } else {
      _setting = {...setting}
      _setting.$name = btn.logLabel
      _setting.laypage = pagination
      _setting.arr_field = _setting.all_field || _setting.arr_field
      delete _setting.sub_field
    }
    let primaryId = ''
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -1442,7 +1442,22 @@
  getCallBackSql = (result, record) => {
    const { btn } = this.props
    let lines = []
    let pre = btn.callbackType === 'script' ? '@' : ''
    let pre = ''
    let tables = []
    if (btn.callbackType === 'script') { // 使用自定义脚本
      pre = '@'
      btn.verify.cbScripts.forEach(script => {
        if (script.status === 'false') return
        if (/\s#[a-z0-9_]+(\s|\()/ig.test(script.sql)) {
          tables.push(...script.sql.match(/\s#[a-z0-9_]+(\s|\()/ig))
        }
      })
      tables = tables.map(tb => tb.replace(/\s|\(/g, ''))
    }
    let errSql = ''
    if (result.$ErrCode === 'E') {
@@ -1459,6 +1474,11 @@
      let vals = []
      let subObjs = []
      let id = Utils.getuuid()
      let tbName = pre + tb
      if (tables.includes('#' + tb)) {
        tbName = '#' + tb
      }
      delete obj.$$key
@@ -1491,7 +1511,7 @@
      lines.push({
        table: md5(tb + keys),
        insert: `Insert into ${pre}${tb} (${keys},[mk_level],[mk_id],[mk_bid])`,
        insert: `Insert into ${tbName} (${keys},[mk_level],[mk_id],[mk_bid])`,
        select: `Select ${vals.join(',')},'${level}','${id}','${bid}'`
      })
@@ -1584,6 +1604,7 @@
      }
      if (window.GLOB.debugger === true) {
        console.info('%c' + btn.logLabel + '(回调)', 'color: blue')
        console.info(sql.replace(/\n\s{8}/ig, '\n'))
      }
@@ -1819,6 +1840,18 @@
        result.rduri = btn.interface
      }
      if (/function:/i.test(result.rduri)) {
        let rduri = result.rduri
        try {
          rduri = rduri.replace(/function:/i, '')
          // eslint-disable-next-line
          let func = new Function(rduri)
          result.rduri = func()
        } catch (e) {
          console.warn(e)
        }
      }
      let host = window.GLOB.baseurl.replace(/http(s):\/\//, '')
      if (result.rduri.indexOf(host) === -1 && /\/dostars/.test(result.rduri)) {
        result.$login = true
src/tabviews/zshare/fileupload/index.jsx
@@ -5,7 +5,9 @@
import { Upload, Button, Progress, notification } from 'antd'
import { UploadOutlined } from '@ant-design/icons'
import SparkMD5 from 'spark-md5'
import Api from '@/api'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class FileUpload extends Component {
@@ -129,7 +131,9 @@
    this.props.onChange(vals.join(','))
  }
  onUpdate = (url) => {
  onUpdate = (url, file_name) => {
    const { config } = this.props
    let filelist = fromJS(this.state.filelist).toJS()
    if (filelist[filelist.length -1]) {
@@ -151,7 +155,20 @@
    })
    this.setState({filelist})
    this.props.onChange(vals.join(','))
    if (config.subFields && file_name) {
      let other = {}
      config.subFields.forEach((n, i) => {
        other[n.field] = file_name
        setTimeout(() => {
          MKEmitter.emit('mkFC', 'input', n.uuid, file_name)
        }, i * 5)
      })
      this.props.onChange(vals.join(','), other)
    } else {
      this.props.onChange(vals.join(','))
    }
  }
  onFail = (msg) => {
@@ -171,7 +188,7 @@
    })
  }
  shardupload = (param) => {
  shardupload = (param, file_name) => {
    let form = new FormData()
    form.append('file', param.binary)
@@ -189,7 +206,7 @@
    Api.getLargeFileUpload(form).then(res => {
      if (res.status) {
        if (res.urlPath) {
          this.onUpdate(res.urlPath)
          this.onUpdate(res.urlPath, file_name)
        } else {
          this.onFail()
        }
@@ -253,6 +270,8 @@
      percent: 0
    })
    let file_name = file.name.replace(/\.{1}[^.]*$/ig, '')
    if (compress === 'true' || compress === 'base64') {
      let reader = new FileReader()
      let fileSize = file.size / 1024 / 1024
@@ -292,7 +311,7 @@
          let param = {Base64Img: cvs.toDataURL('image/jpeg', compressRate)}
          if (this.props.config.compress === 'base64') {
            this.onUpdate(param.Base64Img)
            this.onUpdate(param.Base64Img, file_name)
  
            this.setState({
              percent: 100
@@ -317,7 +336,7 @@
                  url = rduri.replace(/webapi(.*)$/, '') + result.Images
                }
  
                this.onUpdate(url)
                this.onUpdate(url, file_name)
  
                this.setState({
                  percent: 100
@@ -358,7 +377,7 @@
        if (res.status) {
          if (res.urlPath) {
            let path = (/^\/\//.test(res.urlPath) ? 'https:' : '') + res.urlPath
            this.onUpdate(path)
            this.onUpdate(path, file_name)
            this.setState({
              percent: 100
            }, () => {
@@ -403,7 +422,7 @@
      
      Api.getFilePreUpload(_param).then(res => {
        if (res.status && res.urlPath) {
          this.onUpdate(res.urlPath)
          this.onUpdate(res.urlPath, file_name)
          this.setState({
            percent: 100
          }, () => {
@@ -415,7 +434,7 @@
            }, 200)
          })
        } else {
          this.shardupload(param)
          this.shardupload(param, file_name)
        }
      })
    }
src/tabviews/zshare/mutilform/index.jsx
@@ -486,47 +486,42 @@
      let item = fieldMap.get(cell.field)
      // 下级表单控制-字段写入
      if ((['select', 'radio', 'link'].includes(item.type) || (item.type === 'checkcard' && item.multiple !== 'true') || (item.type === 'cascader' && item.resourceType !== '2')) && item.linkSubField) {
        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
            })
          }
        })
        if (item.subFields.length === 0) {
          item.subFields = null
        } else if (item.oriOptions.length > 0) {
          item.oriOptions = item.oriOptions.map(cell => {
            item.subFields.forEach(m => {
              cell[m.field] = cell[m.field] === undefined ? '' : cell[m.field]
            })
            return cell
      if (item.linkSubField && item.linkSubField.length > 0) {
        if ((['select', 'radio', 'link'].includes(item.type) || (item.type === 'checkcard' && item.multiple !== 'true') || (item.type === 'cascader' && item.resourceType !== '2'))) {
          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
              })
            }
          })
          item.options = fromJS(item.oriOptions).toJS()
        }
        item.linkSubField = null
      } else if (item.type === 'switch' && item.linkSubField) {
        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
          if (item.oriOptions.length > 0) {
            item.oriOptions = item.oriOptions.map(cell => {
              item.subFields.forEach(m => {
                cell[m.field] = cell[m.field] === undefined ? '' : cell[m.field]
              })
              return cell
            })
            item.options = fromJS(item.oriOptions).toJS()
          }
        })
        if (item.subFields.length === 0) {
          item.subFields = null
        } else {
        } else if (item.type === 'switch') {
          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
              })
            }
          })
          reFieldsVal = reFieldsVal || {}
          let val = item.initval === item.openVal ? item.openText : item.closeText
@@ -534,7 +529,20 @@
          item.subFields.forEach(n => {
            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
              })
            }
          })
        }
        item.linkSubField = null
      }
@@ -1136,7 +1144,7 @@
        } else if (item.type === 'fileupload') {
          className = item.readonly ? 'readonly' : ''
          className += item.fileType === 'picture-card' ? ' file-upload' : ''
          content = (<MKFileUpload config={item} onChange={(val) => this.recordChange({[item.field]: val})} />)
          content = (<MKFileUpload config={item} onChange={(val, other = {}) => this.recordChange({[item.field]: val, ...other})} />)
        } else if (item.type === 'textarea') {
          content = (<MKTextArea config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})}/>)
        } else if (item.type === 'rate') {
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -148,6 +148,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql, 'customscript')
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
@@ -183,6 +183,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql, 'customscript')
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -85,7 +85,9 @@
        editable: true,
        required: false,
        width: '12%',
        render: (text) => {
        render: (text, record) => {
          if (record.type !== 'number') return ''
          if (text === 'true') {
            return '是'
          } else {
@@ -105,7 +107,8 @@
        max: 18,
        editable: true,
        required: false,
        width: '12%'
        width: '12%',
        render: (text, record) => record.type === 'number' ? text : ''
      },
      {
        title: '导出',
@@ -231,6 +234,13 @@
        } else {
          col.type = 'text'
        }
      }
      if (col.type !== 'number') {
        col.decimal = ''
        col.abs = 'false'
      } else {
        col.abs = col.abs || 'false'
      }
      return col
@@ -884,7 +894,7 @@
      return
    }
    let sql = SettingUtils.getDebugSql(verify, scripts, (verify.useSearch === 'true' ? searches : []), Utils)
    let sql = SettingUtils.getDebugSql(verify, scripts, (verify.useSearch === 'true' ? searches : []))
    let _debugId = md5(sql)
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
@@ -1,19 +1,17 @@
import moment from 'moment'
import { formatSearch, getSearchRegs, joinMainSearchkey } from '@/utils/utils-custom.js'
export default class SettingUtils {
  /**
   * @description 生成页面查询语句
   */
  static getDebugSql (verify, scripts, searches, Utils) {
  static getDebugSql (verify, scripts, searches) {
    let sql = ''
    let _dataresource = verify.dataresource || ''
    let regoptions = this.getRegOptions(searches)
    let _search = this.formatSearch(searches)
    _search = Utils.joinMainSearchkey(_search)
    let _search = formatSearch(searches)
    let regoptions = getSearchRegs(_search)
    _search = _search.replace(/@\$@/ig, '')
    _search = _search ? 'where ' + _search : ''
    _search = joinMainSearchkey(_search)
    let arr_field = []
    verify.columns.forEach(item => {
@@ -129,127 +127,5 @@
    }
    return sql
  }
  /**
   * @description 获取全部搜索条件
   * @param {Array} searches 搜索条件数组
   */
  static formatSearch (searches) {
    if (!searches || searches.length === 0) return []
    let newsearches = []
    searches.forEach(search => {
      if (!search.field) return
      let item = {
        key: search.field,
        match: search.match,
        type: search.type,
        label: search.label,
        value: search.initval,
        required: search.required === 'true'
      }
      if (item.type === 'group') {
        item.key = search.datefield
        item.type = 'daterange'
        item.match = 'between'
        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
        newsearches.push(item)
        return
      } else if (item.type === 'date') {
        item.value = moment().format('YYYY-MM-DD')
      } else if (item.type === 'datemonth') {
        item.value = moment().format('YYYY-MM')
      } else if (item.type === 'dateweek') {
        item.value = moment().format('YYYY-MM-DD')
      } else if (item.type === 'daterange') {
        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && search.multiple === 'true')) {
        item.type = 'multi'
        item.value = '@$@'
      } else {
        item.value = '@$@'
      }
      newsearches.push(item)
    })
    return newsearches
  }
  /**
   * @description 获取搜索用于正则替换
   * @param {Array}   searches     搜索条件
   * @return {String}  searchText  拼接结果
   */
  static getRegOptions (searches) {
    if (!searches || searches.length === 0) return []
    let options = []
    let fieldmap = new Map()
    searches.forEach(search => {
      let item = {
        key: search.field,
        value: '0'
      }
      if (fieldmap.has(item.key)) {
        item.key = item.key + '1'
      }
      fieldmap.set(item.key, true)
      if (search.type === 'group') {
        options.push({
          key: search.field,
          value: '0'
        })
        options.push({
          key: search.datefield,
          value: '0'
        })
        options.push({
          key: search.datefield + '1',
          value: '0'
        })
        options.push(item)
      } else if (['datemonth', 'dateweek'].includes(search.type)) {
        options.push(item)
        options.push({
          key: item.key + '1',
          value: '0'
        })
      } else if (search.type === 'daterange') {
        let _skey = search.field
        let _ekey = search.field + '1'
        if (/,/.test(search.field)) {
          _skey = search.field.split(',')[0]
          _ekey = search.field.split(',')[1]
        }
        options.push({
          key: _skey,
          value: '0'
        })
        options.push({
          key: _ekey,
          value: '0'
        })
      } else if (search.type === 'text' || search.type === 'select') {
        item.key.split(',').forEach(field => {
          let cell = JSON.parse(JSON.stringify(item))
          cell.key = field
          options.push(cell)
        })
      } else {
        options.push(item)
      }
    })
    return options
  }
}
src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
@@ -13,11 +13,12 @@
    let _type = props.card.type
    if (!props.card.origin) {
      if (props.type === 'columns') {
        if (_type !== 'number') {
          _type = 'text'
        }
      } else if (props.type === 'search') {
      // if (props.type === 'columns') {
      //   if (_type !== 'number') {
      //     _type = 'text'
      //   }
      // }
      if (props.type === 'search') {
        if (_type === 'date' || _type === 'datetime') {
          _type = 'date'
        } else if (_type !== 'select') {
@@ -74,8 +75,11 @@
  render() {
    const { card, type } = this.state
    let hasPadding = type === 'search' || type === 'form'
    return (
      <div className={'ant-card ant-card-bordered ' + (card.selected ? 'selected' : '')  + (card.origin ? ' fixed' : '')} >
      <div className={'ant-card ant-card-bordered ' + (card.selected ? 'selected' : '')  + (card.origin ? ' fixed' : '') + (hasPadding ? ' has-padding' : '')} >
        <div className="base" onClick={this.changeSelect}>
          <CheckOutlined />
          <p title={card.field}>字段: <span>{card.field}</span></p>
@@ -88,12 +92,12 @@
            <Radio value="date">date</Radio>
          </Radio.Group> : null
        }
        {type === 'columns' ?
        {/* {type === 'columns' ?
          <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected || card.origin}>
            <Radio value="text">text</Radio>
            <Radio value="number">number</Radio>
          </Radio.Group> : null
        }
        } */}
        {type === 'form' ?
          <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected || card.origin}>
            <Radio value="text">text</Radio>
src/templates/sharecomponent/fieldscomponent/editcard/index.scss
@@ -4,7 +4,7 @@
  .ant-col {
    padding: 10px;
    .ant-card {
      padding: 0px 10px 10px;
      padding: 0px;
      p {
        margin-bottom: 5px;
        overflow: hidden;
@@ -25,10 +25,16 @@
        opacity: 0.4;
      }
      .base {
        padding-top: 10px;
        padding: 10px;
        cursor: pointer;
      }
    }
    .ant-card.has-padding {
      padding: 0px 10px 10px;
      .base {
        padding: 10px 0 0;
      }
    }
    .ant-card.selected, .ant-card.fixed {
      border-color: #1890ff;
      box-shadow: 0px 0px 4px #1890ff;
src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -58,6 +58,7 @@
            if (res.FDName && res.FDName.length > 0) {
              tabmsg.columns = res.FDName.map(item => {
                let _type = item.FieldType.toLowerCase()
                let _datatype = item.FieldType.toLowerCase()
                let _decimal = 0
                let _length = 50
                if (/^nvarchar/.test(_type)) {
@@ -80,6 +81,14 @@
                } else {
                  _type = 'text'
                }
                if (/^nvarchar/.test(_datatype)) {
                  _datatype = _datatype.replace(/^nvarchar/, 'Nvarchar')
                } else if (/^decimal/.test(_datatype)) {
                  _datatype = _datatype.replace(/^decimal/, 'Decimal')
                } else if (/^int/.test(_datatype)) {
                  _datatype = _datatype.replace(/^int/, 'Int')
                }
    
                return {
                  field: item.FieldName || '',
@@ -88,7 +97,7 @@
                  datatype: _type,
                  decimal: _decimal,
                  length: _length,
                  $datatype: item.FieldType.toLowerCase()
                  $datatype: _datatype
                }
              })
            }
@@ -232,7 +241,7 @@
          field: item.field,
          Hide: 'false',
          IsSort: 'true',
          type: item.type,
          type: item.type === 'number' ? 'number' : 'text',
          Width: item.type === 'number' ? 80 : 120
        }
@@ -240,6 +249,12 @@
          newcard.decimal = item.decimal
        } else {
          newcard.fieldlength = item.length || 50
        }
        if (item.type === 'date') {
          newcard.textFormat = 'YYYY-MM-DD'
        } else if (item.type === 'datetime') {
          newcard.textFormat = 'YYYY-MM-DD HH:mm:ss'
        }
        items.push(newcard)
@@ -257,6 +272,7 @@
          field: item.field,
          datatype: _t
        }
        items.unshift(newcard)
        keys.push(item.field.toLowerCase())
      })
src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
@@ -140,7 +140,7 @@
        <CloseOutlined className="close" onClick={() => delCard(id)} />
      </div>
    } trigger="hover">
      <div className={'page-card ' + (card.labelShow === 'false' ? 'label-hide ' : '') + type + (card.advanced === 'true' ? ' advanced' : '')} style={{ opacity: opacity}}>
      <div className={'page-card ' + (card.labelShow === 'false' ? 'label-hide ' : '') + type + (card.advanced === 'true' ? ' advanced' : '') + (card.query === 'false' ? ' no-query' : '')} style={{ opacity: opacity}}>
        <div ref={node => drag(drop(node))} onDoubleClick={() => editCard(id)}>
          <Form.Item
            labelCol={{style: {width: labelwidth + '%'}}}
src/templates/sharecomponent/searchcomponent/index.scss
@@ -104,6 +104,11 @@
      color: orange;
    }
  }
  .page-card.no-query {
    .ant-form-explain {
      color: #13c2c2;
    }
  }
  .ant-calendar-picker {
    min-width: 100px!important;
    width: 100%;
src/templates/sharecomponent/settingcomponent/settingform/index.jsx
@@ -3,10 +3,10 @@
import { fromJS } from 'immutable'
import { Form, notification, Modal, Spin, Tabs, Typography, Popconfirm, Button } from 'antd'
import { CheckCircleOutlined, StopOutlined, SwapOutlined, DeleteOutlined, BorderOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import { formatSearch, joinMainSearchkey } from '@/utils/utils-custom.js'
import SettingUtils from './utils.jsx'
import asyncComponent from '@/utils/asyncComponent'
import DataSource from './datasource'
@@ -30,9 +30,8 @@
    formlist: [],
    btnloading: false,
    activeKey: 'setting',
    search: '',
    searches: [],
    arr_field: '',
    regoptions: [],
    setting: null,
    defaultSql: '',
    visible: false,
@@ -78,25 +77,7 @@
      })
    }
    // 搜索的where条件
    let _search = this.formatSearch(search)
    _search = Utils.joinMainSearchkey(_search)
    _search = _search.replace(/@\$@/ig, '')
    _search = _search ? 'where ' + _search : ''
    let status = fromJS(_setting).toJS()
    let regoptions = this.getRegOptions(search)
    if (config.urlFields && config.urlFields.length > 0) {
      config.urlFields.forEach(field => {
        regoptions.push({
          key: field,
          value: '0',
          type: 'url'
        })
      })
    }
    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
      window.GLOB.funcs.forEach(m => {
@@ -112,9 +93,8 @@
    this.setState({
      setting: _setting,
      search: _search,
      searches: formatSearch(search),
      arr_field: arr_field.join(','),
      regoptions: regoptions, // 搜索条件,正则替换
      columns: columns,
      scripts: _scripts,
      status
@@ -123,123 +103,6 @@
  componentDidMount () {
    this.props.updRecord(this.state.status)
  }
  getRegOptions = (searches) => {
    if (!searches || searches.length === 0) return []
    let options = []
    let fieldmap = new Map()
    searches.forEach(search => {
      let item = {
        key: search.field,
        value: '0'
      }
      if (fieldmap.has(item.key)) {
        item.key = item.key + '1'
      }
      fieldmap.set(item.key, true)
      if (search.type === 'group') {
        options.push({
          key: search.field,
          value: '0'
        })
        options.push({
          key: search.datefield,
          value: '0'
        })
        options.push({
          key: search.datefield + '1',
          value: '0'
        })
        options.push(item)
      } else if (['datemonth', 'dateweek'].includes(search.type)) {
        options.push(item)
        options.push({
          key: item.key + '1',
          value: '0'
        })
      } else if (search.type === 'daterange') {
        let _skey = search.field
        let _ekey = search.field + '1'
        if (/,/.test(search.field)) {
          _skey = search.field.split(',')[0]
          _ekey = search.field.split(',')[1]
        }
        options.push({
          key: _skey,
          value: '0'
        })
        options.push({
          key: _ekey,
          value: '0'
        })
      } else if (search.type === 'text' || search.type === 'select') {
        item.key.split(',').forEach(field => {
          let cell = JSON.parse(JSON.stringify(item))
          cell.key = field
          options.push(cell)
        })
      } else {
        options.push(item)
      }
    })
    return options
  }
  /**
   * @description 获取全部搜索条件
   * @param {Array} searches 搜索条件数组
   */
  formatSearch (searches) {
    if (!searches || searches.length === 0) return []
    let newsearches = []
    searches.forEach(search => {
      if (!search.field) return
      let item = {
        key: search.field,
        match: search.match,
        type: search.type,
        label: search.label,
        value: search.initval,
        required: search.required === 'true'
      }
      if (item.type === 'group') {
        item.key = search.datefield
        item.type = 'daterange'
        item.match = 'between'
        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
        newsearches.push(item)
        return
      } else if (item.type === 'date') {
        item.value = moment().format('YYYY-MM-DD')
      } else if (item.type === 'datemonth') {
        item.value = moment().format('YYYY-MM')
      } else if (item.type === 'dateweek') {
        item.value = moment().format('YYYY-MM-DD')
      } else if (item.type === 'daterange') {
        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && search.multiple === 'true')) {
        item.type = 'multi'
        item.value = '@$@'
      } else {
        item.value = '@$@'
      }
      newsearches.push(item)
    })
    return newsearches
  }
  handleConfirm = (trigger) => {
@@ -297,7 +160,8 @@
  }
  sqlverify = (_resolve, _reject, type, uscripts) => {
    const { setting, scripts, arr_field, regoptions, search } = this.state
    const { config } = this.props
    const { setting, scripts, arr_field, searches } = this.state
    if (setting.interType !== 'system') { // 不使用系统接口时,不需要sql验证
      _resolve()
@@ -316,7 +180,7 @@
    } else if (type === 'scripts' && _scripts.length === 0) {
      _resolve()
    } else { // type 为 submit 、 verify ,以及其他需要验证的场景
      let r = SettingUtils.getDebugSql(setting, _scripts, arr_field, regoptions, search)
      let r = SettingUtils.getDebugSql(setting, _scripts, arr_field, searches, config.urlFields)
      if (r.errors) {
        notification.warning({
@@ -341,7 +205,7 @@
  // 标签切换
  changeTab = (val) => {
    const { activeKey, search, arr_field } = this.state
    const { activeKey, searches, arr_field } = this.state
    if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
      notification.warning({
@@ -357,11 +221,13 @@
        if (res.dataresource) {
          let _dataresource = res.dataresource
          let _search = joinMainSearchkey(searches)
          if (/\s/.test(_dataresource)) {
            _dataresource = '(' + _dataresource + ') tb'
          }
          _defaultSql = `select top @pageSize@ ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource} ${search}) tmptable where rows > (@pageSize@ * (@pageIndex@ - 1)) order by tmptable.rows`
          _defaultSql = `select top @pageSize@ ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource} ${_search}) tmptable where rows > (@pageSize@ * (@pageIndex@ - 1)) order by tmptable.rows`
        }
        
        this.setState({
@@ -517,7 +383,7 @@
              scripts={scripts}
              defaultSql={defaultSql}
              urlFields={config.urlFields}
              searches={this.props.search}
              searches={this.state.searches}
              scriptsChange={this.scriptsChange}
              scriptsUpdate={this.scriptsUpdate}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
File was deleted
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.scss
File was deleted
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
@@ -1,13 +1,11 @@
import { getSearchRegs, joinMainSearchkey } from '@/utils/utils-custom.js'
export default class SettingUtils {
  /**
   * @description 生成页面查询语句
   * @return {String}  arr_field     显示列字段
   * @return {String}  search        搜索条件
   * @return {Object}  setting       页面设置
   * @return {Array}   regoptions    搜索条件正则替换
   */
  static getDebugSql (setting, scripts, arr_field, regoptions, search) {
  static getDebugSql (setting, scripts, arr_field, searches = [], urlFields) {
    let sql = ''
    let _dataresource = setting.dataresource || ''
    let _customScript = ''
@@ -53,24 +51,29 @@
      _customScript = _customScript.replace(/@db@/ig, window.GLOB.externalDatabase)
    }
    
    let _regoptions = getSearchRegs(searches)
    let _search = joinMainSearchkey(searches)
    // 正则替换
    let _regoptions = regoptions.map(item => {
      return {
        reg: new RegExp('@' + item.key + '@', 'ig'),
        value: `'0'`,
        type: item.type || ''
      }
    })
    if (urlFields && urlFields.length > 0) {
      urlFields.forEach(field => {
        _regoptions.push({
          reg: new RegExp('@' + field + '@', 'ig'),
          value: `'0'`
        })
      })
    }
    _regoptions.push({
      reg: new RegExp('@userName@', 'ig'),
      value: `''`
      value: `'mk'`
    }, {
      reg: new RegExp('@fullName@', 'ig'),
      value: `''`
      value: `'mk'`
    }, {
      reg: new RegExp('@orderBy@', 'ig'),
      value: setting.order
      value: setting.order || ''
    }, {
      reg: new RegExp('@pageSize@', 'ig'),
      value: 10
@@ -79,24 +82,13 @@
      value: 1
    })
    let _search = search
    _regoptions.forEach(item => {
      _dataresource = _dataresource.replace(item.reg, item.value)
      _customScript = _customScript.replace(item.reg, item.value)
    })
    if (setting.queryType === 'statistics' && _dataresource) {
      _regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, item.value)
      })
      _search = ''
    } else if (_dataresource) {
      _regoptions.forEach(item => {
        if (item.type !== 'url') return
        _dataresource = _dataresource.replace(item.reg, item.value)
      })
    }
    if (_customScript) {
      _regoptions.forEach(item => {
        _customScript = _customScript.replace(item.reg, item.value)
      })
    }
    // 数据源处理, 存在显示列时 
@@ -139,62 +131,5 @@
    }
    return { sql, errors: errors.join(';') }
  }
  /**
   * @description 生成前置或后置语句
   * @return {String}  scripts       脚本
   * @return {Array}   regoptions    搜索条件正则替换
   */
  static getCustomDebugSql (scripts, regoptions) {
    let sql = ''
    let _customScript = ''
    scripts.forEach(script => {
      if (script.status === 'false') return
      _customScript += `
      ${script.sql}
      `
    })
    if (_customScript) {
      _customScript = `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 =''
        ${_customScript}
      `
    }
    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
      window.GLOB.funcs.forEach(item => {
        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
      })
    }
    _customScript = _customScript.replace(/@\$|\$@/ig, '')
    _customScript = _customScript.replace(/@userName@|@fullName@/ig, `''`)
    // 正则替换
    if (regoptions) {
      let _regoptions = regoptions.map(item => {
        return {
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'0'`
        }
      })
      _regoptions.forEach(item => {
        _customScript = _customScript.replace(item.reg, item.value)
      })
    }
    if (_customScript) {
      sql = `${_customScript}
        aaa:
        if @ErrorCode!=''
          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select '1949-10-01 15:00:00',@ErrorCode, @retmsg,'1949-10-01 15:00:00'
      `
    }
    return sql
  }
}
src/templates/sharecomponent/tablecomponent/index.jsx
@@ -51,6 +51,8 @@
      this.onTableChange(table)
    } else if (type === 'del') {
      this.deleteTable(table)
    } else if (type === 'init' && window.GLOB.publicTables.length === 0) {
      this.onTableChange(table)
    }
  }
@@ -102,7 +104,7 @@
    let _table = tables.filter(item => item.TbName === value)[0]
    if (selectedTables.findIndex(cell => cell.TbName === value) > -1) return
    if (!_table || selectedTables.findIndex(cell => cell.TbName === value) > -1) return
    let _tables = [...selectedTables, _table]
src/templates/zshare/customscript/index.jsx
@@ -94,18 +94,23 @@
    let _usefulFields = []
    searches.forEach(item => {
      if (!item.field) return
      if (item.type === 'group') {
        _usefulFields.push(item.field)
        _usefulFields.push(item.datefield)
        _usefulFields.push(item.datefield + '1')
      } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
        _usefulFields.push(item.field)
        _usefulFields.push(item.field + '1')
      } else if (_usefulFields.includes(item.field)) {
        _usefulFields.push(item.field + '1')
      if (['dateweek', 'datemonth'].includes(item.type)) {
        _usefulFields.push(item.key)
        _usefulFields.push(item.key + '1')
      } else if (item.type === 'daterange') {
        let _skey = item.key
        let _ekey = item.key + '1'
        if (/,/.test(item.key)) {
          _skey = item.key.split(',')[0]
          _ekey = item.key.split(',')[1]
        }
        _usefulFields.push(_skey)
        _usefulFields.push(_ekey)
      } else if (item.type === 'date' && _usefulFields.includes(item.key)) {
        _usefulFields.push(item.key + '1')
      } else {
        _usefulFields.push(item.field.replace(/,/ig, ', '))
        _usefulFields.push(item.key.replace(/,/ig, ', '))
      }
    })
@@ -238,6 +243,25 @@
        duration: 5
      })
      return
    } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
      let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
      let errors = []
      list.forEach(str => {
        str = str.replace(/^\s/, '')
        let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
        if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
          errors.push(str)
        }
      })
      if (errors.length > 0) {
        notification.warning({
          top: 92,
          message: '不可使用同一个表字段进行关联:' + errors.join('、'),
          duration: 5
        })
        return
      }
    }
    let error = Utils.verifySql(values.sql, 'customscript')
src/templates/zshare/formconfig.jsx
@@ -448,7 +448,7 @@
      type: 'text',
      key: 'initval',
      label: '初始值',
      tooltip: '类型为下拉菜单时,初始值应为数据的Value值(使用数据源时,应为《值·字段》的值);类型为数值(区间)时,初始值使用逗号拼接,例如 3,10',
      tooltip: '类型为下拉菜单时,初始值应为数据的Value值(使用数据源时,应为《值·字段》的值);类型为数值(区间)时,初始值使用逗号拼接,例如 3,10;文本与下拉菜单中可使用@username@、@fullName@',
      initVal: card.initval,
      required: false
    },
@@ -4094,9 +4094,10 @@
      type: 'multiselect',
      key: 'linkSubField',
      label: '填充表单',
      tooltip: '在切换选项时会把信息自动填入关联的表单(文本或数字表单)中,开关会将提示文本填入此表单。',
      tooltip: '在切换选项时会把信息自动填入关联的表单(文本或数字表单)中,开关会将提示文本填入此表单,文件上传会将原文件名填入此表单。',
      initVal: card.linkSubField || [],
      options: inputfields
      options: inputfields,
      allowClear: true
    },
    // {
    //   type: 'number',
src/templates/zshare/modalform/index.jsx
@@ -27,7 +27,7 @@
  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'],
  fileupload: ['readonly', 'required', 'hidden', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress', 'miniSet', 'splitline', 'marginTop', 'marginBottom', 'maxSize'],
  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'],
  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'place', 'marginTop', 'marginBottom', 'minDate', 'maxDate', 'precision'],
src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -78,6 +78,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql, 'customscript')
src/templates/zshare/verifycard/customform/index.jsx
@@ -96,6 +96,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql)
src/templates/zshare/verifycard/customscript/index.jsx
@@ -44,7 +44,7 @@
  }
  handleConfirm = () => {
    const { type, workFlow } = this.props
    const { type, workFlow, flowType } = this.props
    const { editItem, skip } = this.state
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
@@ -108,6 +108,25 @@
            duration: 5
          })
          return
        } else if (/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(values.sql)) {
          let list = values.sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
          let errors = []
          list.forEach(str => {
            str = str.replace(/^\s/, '')
            let strs = str.match(/(\s|=)[a-z0-9_]+\./ig)
            if (strs.length === 2 && (strs[0].replace(/\s|\./g, '') === strs[1].replace(/\s|\./g, ''))) {
              errors.push(str)
            }
          })
          if (errors.length > 0) {
            notification.warning({
              top: 92,
              message: '不可使用同一个表字段进行关联:' + errors.join('、'),
              duration: 5
            })
            return
          }
        }
        let error = Utils.verifySql(values.sql, 'customscript')
@@ -185,14 +204,22 @@
        sql = sql.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|datam|typename)@/ig, `'1949-10-01 15:00:00'`)
        if (window.GLOB.process && workFlow === 'true') {
          sql = sql.replace(/@works_flow_code@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@works_flow_name@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@works_flow_param@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@works_flow_detail_id@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@status@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@statusname@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@work_group@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@work_grade@/ig, `'1949-10-01 15:00:00'`)
          sql = sql.replace(/@works_flow_code@/ig, `'works_flow_code'`)
          sql = sql.replace(/@works_flow_name@/ig, `'works_flow_name'`)
          sql = sql.replace(/@works_flow_param@/ig, `'works_flow_param'`)
          sql = sql.replace(/@works_flow_detail_id@/ig, `'works_flow_detail_id'`)
          sql = sql.replace(/@status@/ig, `0`)
          sql = sql.replace(/@statusname@/ig, `'开始'`)
          sql = sql.replace(/@work_group@/ig, `'work_group'`)
          sql = sql.replace(/@work_grade@/ig, '0')
          sql = sql.replace(/@start_type@/ig, `'开始'`)
          sql = sql.replace(/@check_type@/ig, `'审核'`)
          sql = sql.replace(/@notice_type@/ig, `'抄送'`)
          if (flowType !== 'start') {
            sql = sql.replace(/@check_userids@/ig, `'checkuserids'`)
            sql = sql.replace(/@notice_userids@/ig, `'noticeuserids'`)
          }
        }
        
        if (skip) {
@@ -258,15 +285,34 @@
    if (value === 'flowSql') {
      if (flowType === 'start') {
        value = `insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff)
        select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName
        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)
        select @works_flow_id@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@`
        value = `insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
        select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@
        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@
        insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
        select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@`
      } else {
        value = `insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff)
        select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName
        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)
        select @works_flow_id@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@`
        value = `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@
        if @check_userids@ != ''
        begin
              delete s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
              insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
              select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
              insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
              select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@check_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
        end
        if @notice_userids@ != ''
        begin
              delete n
              from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
              inner join (select ID from dbo.SplitComma(@notice_userids@)) s
              on n.userid = s.id
              insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
              select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@notice_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@notice_userids@)
        end`
      }
      value = value.replace(/\n\s{8}/g, '\n')
@@ -321,6 +367,7 @@
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {usefulfields ? <span>, {usefulfields}</span> : ''}
              {window.GLOB.process && workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'工作流变量,请按照@xxx@格式使用。注:check_userids、notice_userids 在审批或驳回时有效。'}>,<span style={{color: 'purple'}}> works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, start_type, check_type, notice_type, check_userids, notice_userids</span></Tooltip> : null}
            </Form.Item>
          </Col> : null}
          {!_type ? <Col span={8} style={{whiteSpace: 'nowrap'}}>
src/utils/utils-custom.js
@@ -932,6 +932,178 @@
}
/**
 * @description 格式化搜索条件
 */
export function formatSearch (searches) {
  if (!searches) return []
  let newsearches = []
  searches.forEach(item => {
    if (!item.field) return
    if (item.type === 'group') {
      newsearches.push({
        key: item.field,
        match: '',
        type: item.type,
        value: 'customized',
        forbid: true
      }, {
        key: item.datefield,
        match: 'between',
        type: 'daterange',
        value: '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000',
        forbid: item.query === 'false'
      })
    } else {
      let value = item.initval
      let type = item.type
      if (item.type === 'date') {
        value = '1949-10-01 00:00:00.000'
      } else if (item.type === 'datemonth') {
        value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
      } else if (item.type === 'dateweek') {
        value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
      } else if (item.type === 'daterange') {
        value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
      } else if (item.type === 'range') {
        value = `${item.minValue},${item.maxValue}`
      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) {
        type = 'multi'
        value = '0'
      } else {
        value = '0'
      }
      newsearches.push({
        key: item.field,
        match: item.match,
        type: type,
        value: value,
        precision: item.precision || 'day',
        forbid: item.query === 'false'
      })
    }
  })
  return newsearches
}
/**
 * @description 拼接where条件
 */
export function joinMainSearchkey (searches) {
  if (!searches || searches.length === 0) return ''
  let searchText = []
  searches.forEach(item => {
    if (item.forbid) return
    if (item.type === 'text' || item.type === 'select') { // 综合搜索,文本或下拉,所有字段拼接
      let str = item.match === 'like' || item.match === 'not like' ? '%' : ''
      let fields = item.key.split(',').map(field => {
        return field + ' ' + item.match + ' \'' + str + item.value + str + '\''
      })
      searchText.push('(' + fields.join(' OR ') + ')')
    } else if (item.type === 'checkcard') {
      let str = item.match === 'like' || item.match === 'not like' ? '%' : ''
      searchText.push('(' + item.key + ' ' + item.match + ' \'' + str + item.value + str + '\')')
    } else if (item.type === 'multi') {
      searchText.push(`('${item.value}' ${item.match} '%'+${item.key}+'%')`)
    } else if (item.type === 'date') {
      searchText.push('(' + item.key + ' ' + item.match + ' \'' + item.value + '\')')
    } else if (item.type === 'datemonth' || item.type === 'dateweek' || item.type === 'range') {
      let val = item.value.split(',')
      searchText.push('(' + item.key + ' >= \'' + val[0] + '\' AND ' + item.key + ' < \'' + val[1] + '\')')
    } else if (item.type === 'daterange') {
      let val = item.value.split(',')
      let _skey = item.key
      let _ekey = item.key
      if (/,/.test(item.key)) {
        _skey = item.key.split(',')[0]
        _ekey = item.key.split(',')[1]
      }
      searchText.push('(' + _skey + ' >= \'' + val[0] + '\' AND ' + _ekey + ' < \'' + val[1] + '\')')
    } else {
      searchText.push('(' + item.key + ' ' + item.match + ' \'' + item.value + '\')')
    }
  })
  return searchText.length > 0 ? 'where ' + searchText.join(' AND ') : ''
}
/**
 * @description 获取搜索正则替换
 */
export function getSearchRegs (searches) {
  if (!searches) return []
  let options = []
  let fieldmap = new Map()
  searches.forEach(item => {
    if (item.type === 'date') {
      if (fieldmap.has(item.key)) {
        options.push({
          reg: new RegExp('@' + item.key + '1@', 'ig'),
          value: `'${item.value}'`
        })
      } else {
        fieldmap.set(item.key, true)
        options.push({
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        })
      }
    } else if (['dateweek', 'datemonth', 'range'].includes(item.type)) {
      let val = item.value.split(',')
      options.push({
        reg: new RegExp('@' + item.key + '@', 'ig'),
        value: `'${val[0]}'`
      }, {
        reg: new RegExp('@' + item.key + '1@', 'ig'),
        value: `'${val[1]}'`
      })
    } else if (item.type === 'daterange') {
      let val = item.value.split(',')
      let _skey = item.key
      let _ekey = item.key + '1'
      if (/,/.test(item.key)) {
        _skey = item.key.split(',')[0]
        _ekey = item.key.split(',')[1]
      }
      options.push({
        reg: new RegExp('@' + _skey + '@', 'ig'),
        value: `'${val[0]}'`
      }, {
        reg: new RegExp('@' + _ekey + '@', 'ig'),
        value: `'${val[1]}'`
      })
    } else if (item.type === 'text' || item.type === 'select') {
      item.key.split(',').forEach(field => {
        options.push({
          reg: new RegExp('@' + field + '@', 'ig'),
          value: `'${item.value}'`
        })
      })
    } else {
      options.push({
        reg: new RegExp('@' + item.key + '@', 'ig'),
        value: `'${item.value}'`
      })
    }
  })
  return options
}
/**
 * @description 重置移动端style
 * @return {Object}  style
 */
src/utils/utils.js
@@ -138,7 +138,7 @@
    ]
    
    if (type === 'customscript') {
      chars = chars.filter(char => !['insert', 'delete', 'update', 'set', 'if', 'exec'].includes(char.key))
      chars = chars.filter(char => !['create', 'insert', 'delete', 'update', 'set', 'drop', 'if', 'exec'].includes(char.key))
    }
    let error = ''
@@ -407,6 +407,10 @@
      }
      if (item.type === 'text' || item.type === 'select') {
        if (/@username@|@fullName@/ig.test(item.initval)) {
          item.initval = item.initval.replace(/@username@/ig, sessionStorage.getItem('User_Name') || '').replace(/@fullName@/ig, sessionStorage.getItem('Full_Name') || '')
          item.oriInitval = item.initval
        }
        if (/,/.test(item.field)) {
          item.field.split(',').forEach(field => {
            keys.push(field.toLowerCase())
@@ -1166,6 +1170,7 @@
    sql = sql.replace(/\n\s{6}/ig, '\n')
    if (window.GLOB.debugger === true) {
      console.info('%c' + item.logLabel, 'color: blue')
      console.info(sql)
    }
  } else {
@@ -1372,6 +1377,7 @@
    sql = sql.replace(/\n\s{6}/ig, '\n')
    if (window.GLOB.debugger === true) {
      console.info('%c' + btn.logLabel, 'color: blue')
      console.info(sql)
    }
  } else {
@@ -1557,8 +1563,6 @@
    }
    columns.forEach(col => {
      if (col.field === 'works_flow_param') return
      if (col.type === 'colspan' || col.type === 'old_colspan') {
        col.subcols.forEach(cell => {
          setField(cell)
@@ -1578,7 +1582,7 @@
      Declare @tbid nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@BillCode nvarchar(50),@BVoucher nvarchar(50),@FIBVoucherDate nvarchar(50), @FiYear nvarchar(50),@ModularDetailCode nvarchar(50), @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),@mk_deleted int,@bid nvarchar(50)${_declarefields}
    `
  let userName = sessionStorage.getItem('User_Name') || ''
  let userName = sessionStorage.getItem('User_Name') || ''
  let fullName = sessionStorage.getItem('Full_Name') || ''
  let RoleID = sessionStorage.getItem('role_id') || ''
  let departmentcode = sessionStorage.getItem('departmentcode') || ''
@@ -2114,42 +2118,116 @@
    let statusName = ''
    let detailId = ''
    if (verify.flowSql === 'true') {
      if (verify.flowType === 'start') {
        target = flow.cells.filter(cell => cell.mknode === 'start')[0]
        if (target) {
          detailId = target.id
          status = target.mkdata.status
          statusName = target.mkdata.statusName
        }
      } else if (_data.works_flow_param) {
        node = JSON.parse(window.decodeURIComponent(window.atob(_data.works_flow_param)))
        if (node) {
          line = flow.cells.filter(cell => cell.shape === 'edge' && cell.source.cell === node.id)[0]
        }
        if (line) {
          target = flow.cells.filter(cell => cell.id === line.target.cell)[0]
        }
      }
    if (verify.flowType === 'start') {
      target = flow.cells.filter(cell => cell.mknode === 'start')[0]
      if (target) {
        _sql += `
      /* 工作流默认sql */
      insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff)
      select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName
      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)
      select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@
      `
        detailId = target.id
        status = target.mkdata.status
        statusName = target.mkdata.statusName
      }
    } else if (_data.works_flow_param) {
      node = JSON.parse(window.decodeURIComponent(window.atob(_data.works_flow_param)))
      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]
        }
      }
      if (line) {
        detailId = line.id
        status = line.mkdata.status
        statusName = line.mkdata.statusName
        target = flow.cells.filter(cell => cell.id === line.target.cell)[0]
      }
    }
    if (verify.flowSql === 'true' && target) {
      if (verify.flowType === 'start') {
        _sql += `
      /* 工作流默认sql */
      insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
      select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@
      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@
      insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
      select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
      `
      } else {
        _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@
      if @check_userids@ != ''
      begin
            delete s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
            insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
            select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
            insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
            select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@check_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
      end
      if @notice_userids@ != ''
      begin
            delete n
            from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
            inner join (select ID from dbo.SplitComma(@notice_userids@)) s
            on n.userid = s.id
            insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
            select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@notice_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@notice_userids@)
      end
      `
      }
    } 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@
      `
    }
    if (verify.flowType !== 'start') {
      if (line) {
        let checkIds = []
        let noticeIds = []
        line.mkdata.members && line.mkdata.members.forEach(item => {
          checkIds.push(item.worker_id)
        })
        line.mkdata.copys && line.mkdata.copys.forEach(item => {
          noticeIds.push(item.worker_id)
        })
        _sql = _sql.replace(/@check_userids@/ig, `'${checkIds.join(',')}'`)
        _sql = _sql.replace(/@notice_userids@/ig, `'${noticeIds.join(',')}'`)
      } else {
        _sql = _sql.replace(/@check_userids@/ig, `''`)
        _sql = _sql.replace(/@notice_userids@/ig, `''`)
      }
    }
    _sql = _sql.replace(/@start_type@/ig, `'开始'`)
    _sql = _sql.replace(/@check_type@/ig, verify.flowType === 'reject' ? `'驳回'` : `'审核'`)
    _sql = _sql.replace(/@notice_type@/ig, `'抄送'`)
    _sql = _sql.replace(/@works_flow_code@/ig, `'${flow.flow_code}'`)
    _sql = _sql.replace(/@works_flow_name@/ig, `'${flow.flow_name}'`)
    if (target) {
      let msg = {...target.mkdata, id: target.id}
      let label = target.attrs && target.attrs.text && target.attrs.text.text ? target.attrs.text.text : ''
      let msg = {...target.mkdata, label: label, id: target.id}
      _sql = _sql.replace(/@works_flow_param@/ig, `'${window.btoa(window.encodeURIComponent(JSON.stringify(msg)))}'`)
    } else {
      _sql = _sql.replace(/@works_flow_param@/ig, `''`)
@@ -2206,7 +2284,7 @@
  }
  if (window.GLOB.debugger === true) {
    // _sql = _sql.replace(/\n\s{8}/ig, '\n')
    console.info('%c' + btn.logLabel, 'color: blue')
    console.info(_sql)
  }
src/views/design/sidemenu/menuelement/index.scss
@@ -21,7 +21,6 @@
  width: 98%;
  div {
    padding: 0px 0px 0px 30px;
    margin-right: 20px;
    height: 40px;
    line-height: 40px;
    cursor: move;
@@ -57,3 +56,16 @@
    }
  }
}
.side-card div:first-child::before {
  position: absolute;
  content: ' ';
  display: block;
  width: 100%;
  height: 8px;
  top: -8px;
  left: 0px;
}
.side-card:first-child div:first-child::before {
  height: 15px;
  top: -15px;
}
src/views/menudesign/index.jsx
@@ -36,7 +36,7 @@
const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
// const Debug = asyncComponent(() => import('@/menu/debug'))
const Debug = asyncComponent(() => import('@/menu/debug'))
const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
const Versions = asyncComponent(() => import('@/menu/versions'))
const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
@@ -1162,7 +1162,7 @@
              <div className={'menu-view' + (menuloading ? ' saving' : '') + (eyeopen ? ' eye-open' : '')}>
                <Card bordered={false} extra={
                  <div className="mk-opeartion-list">
                    {/* <Debug config={config}/> */}
                    {config ? <Debug config={config}/> : null}
                    <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
                    <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>
                    <TableNodes config={config} />
src/views/mobdesign/index.jsx
@@ -23,6 +23,7 @@
const { Paragraph } = Typography
const Header = asyncComponent(() => import('@/mob/header'))
const Debug = asyncComponent(() => import('@/menu/debug'))
const MenuForm = asyncComponent(() => import('./menuform'))
const MobShell = asyncComponent(() => import('@/mob/mobshell'))
const CreateView = asyncComponent(() => import('@/pc/createview'))
@@ -2115,6 +2116,7 @@
                <Button type="primary" className={needUpdate ? 'update-tip' : ''} onClick={this.submitConfig} id="save-config" loading={menuloading}>保存</Button>
                {config ? <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} /> : null}
                <ArrowLeftOutlined title="后退" className="back-view" onClick={this.backView}/>
                {config ? <Debug config={config}/> : null}
                <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
                <CreateView resetmenu={this.getAppMenus} />
                <PasteController insert={this.insert} />
src/views/pcdesign/index.jsx
@@ -24,6 +24,7 @@
const { Paragraph } = Typography
const MenuForm = asyncComponent(() => import('./menuform'))
const Debug = asyncComponent(() => import('@/menu/debug'))
const Header = asyncComponent(() => import('@/menu/header'))
const PopView = asyncComponent(() => import('@/views/menudesign/popview'))
const Transfer = asyncComponent(() => import('@/pc/transfer'))
@@ -1727,6 +1728,7 @@
                <Button type="primary" className={needUpdate ? 'update-tip' : ''} id="save-config" onClick={this.submitConfig} loading={menuloading}>保存</Button>
                {config ? <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} /> : null}
                <ArrowLeftOutlined title="后退" className="back-view" onClick={this.backView}/>
                {config ? <Debug config={config}/> : null}
                <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
                <CreateView resetmenu={this.getAppMenus} />
                <PasteController insert={this.insert} />
src/views/tabledesign/index.jsx
@@ -34,7 +34,7 @@
const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
// const Debug = asyncComponent(() => import('@/menu/debug'))
const Debug = asyncComponent(() => import('@/menu/debug'))
const Versions = asyncComponent(() => import('@/menu/versions'))
const Transfer = asyncComponent(() => import('@/menu/transfer'))
const Unattended = asyncComponent(() => import('@/templates/zshare/unattended'))
@@ -872,7 +872,7 @@
              <div className={'menu-view' + (menuloading ? ' saving' : '')}>
                <Card bordered={false} extra={
                  <div className="mk-opeartion-list">
                    {/* {config ? <Debug config={config}/> : null} */}
                    {config ? <Debug config={config}/> : null}
                    {config ? <Transfer config={config}/> : null}
                    {config ? <Unattended config={config} updateConfig={this.updateConfig}/> : null}
                    <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>