king
2020-09-14 76427d51a079a5fd1f45bf7188249e7a4647ae05
src/utils/utils.js
@@ -2,7 +2,55 @@
import md5 from 'md5'
import options from '@/store/options.js'
const formatKeys = [
  { key: 'select', value: ' msltk ' },
  { key: 'from', value: ' mfrmk ' },
  { key: 'where', value: ' mwhrk ' },
  { key: 'order by', value: ' modbk ' },
  { key: 'asc', value: ' modack ' },
  { key: 'desc', value: ' moddesk ' },
  { key: 'top', value: ' mtpk ' },
  { key: 'like', value: ' mlkk ' },
  { key: 'not like', value: ' mnlkk ' },
  { key: 'between', value: ' mbtnk ' },
  { key: 'and', value: ' madk ' },
  { key: 'insert', value: ' mistk ' },
  { key: 'into', value: ' mitk ' },
  { key: 'update', value: ' muptk ' },
  { key: 'delete', value: ' mdelk ' },
  { key: 'begin', value: ' mbgink ' },
  { key: 'end', value: ' medk ' },
  { key: 'if', value: ' mefk ' },
  { key: 'while', value: ' mwilk ' },
  { key: 'create', value: ' mcrtk ' },
  { key: 'alter', value: ' matek ' },
  { key: 'len', value: ' mlnk ' },
  { key: 'left', value: ' mlftk ' },
  { key: 'right', value: ' mritk ' },
  { key: 'union', value: ' munok ' },
  { key: 'varchar', value: ' mvcrk ' },
  { key: 'getdate', value: ' mgtdtk ' },
  { key: 'TRY', value: ' mtryonek ' },
  { key: 'TRAN', value: ' mtrnk ' },
  { key: 'goto', value: ' mgtk ' },
  { key: 'set', value: ' mstk ' },
  { key: 'ROLLBACK', value: ' mrlbkk ' }
]
export default class Utils {
  /**
   * @description 数据源名称,用于统一查询
   * @return {String}  name
   */
  static getdataName () {
    let name = []
    let _options = 'abcdefghigklmnopqrstuvwxyz'
    for (let i = 0; i < 6; i++) {
      name.push(_options.substr(Math.floor(Math.random() * 26), 1))
    }
    return name.join('')
  }
  /**
   * @description 生成32位uuid string + 时间
   * @return {String}  uuid
@@ -38,22 +86,26 @@
   * @description md5加密
   * @return {String}  str         加密串
   * @return {String}  timestamp   时间戳
   * @return {Boolean} isopenkey   是否为云端密钥
   */
  static encrypt (str, timestamp, isopenkey) {
    let salt1 = 'mingke'    // sql语法盐值
    let salt2 = 'open_key'  // 云端数据操作盐值
    let _str = ''
    if (isopenkey) {
      _str = salt2 + timestamp + str
    } else {
      _str = str + salt1 + timestamp
    }
  static encrypt (str, timestamp) {
    let salt = 'mingke'    // sql语法盐值
    let _str = str + salt + timestamp
    if (_str.length > 8000) {
      _str = _str.slice(_str.length - 8000)
    }
    return md5(_str)
  }
  /**
   * @description md5加密 云端openkey加密
   * @return {String}  secretkey   Ltext密钥
   * @return {String}  timestamp   时间戳
   */
  static encryptOpenKey (secretkey, timestamp) {
    let salt = 'open_key'  // 云端数据操作盐值
    let _str = salt + timestamp + secretkey
    return md5(_str)
  }
@@ -96,90 +148,69 @@
  /**
   * @description sql加密
   * @return {String}  value
   * @return {String}   value
   */
  static formatOptions (value, isUnFormat = false) {
  static formatOptions (value) {
    if (!value) return ''
    let salt = 'minKe' // 盐值
    // 关键字转换规则
    let format = [
      { key: 'select', value: ' msltk ' },
      { key: 'from', value: ' mfrmk ' },
      { key: 'where', value: ' mwhrk ' },
      { key: 'order by', value: ' modbk ' },
      { key: 'asc', value: ' modack ' },
      { key: 'desc', value: ' moddesk ' },
      { key: 'top', value: ' mtpk ' },
      { key: 'like', value: ' mlkk ' },
      { key: 'not like', value: ' mnlkk ' },
      { key: 'between', value: ' mbtnk ' },
      { key: 'and', value: ' madk ' },
      { key: 'insert', value: ' mistk ' },
      { key: 'into', value: ' mitk ' },
      { key: 'update', value: ' muptk ' },
      { key: 'delete', value: ' mdelk ' },
      { key: 'begin', value: ' mbgink ' },
      { key: 'end', value: ' medk ' },
      { key: 'if', value: ' mefk ' },
      { key: 'while', value: ' mwilk ' },
      { key: 'create', value: ' mcrtk ' },
      { key: 'alter', value: ' matek ' },
      { key: 'len', value: ' mlnk ' },
      { key: 'left', value: ' mlftk ' },
      { key: 'right', value: ' mritk ' },
      { key: 'union', value: ' munok ' },
      { key: 'varchar', value: ' mvcrk ' },
      { key: 'getdate', value: ' mgtdtk ' },
      { key: 'TRY', value: ' mtryonek ' },
      { key: 'TRAN', value: ' mtrnk ' },
      { key: 'goto', value: ' mgtk ' },
      { key: 'set', value: ' mstk ' },
      { key: 'ROLLBACK', value: ' mrlbkk ' }
    ]
    if (!isUnFormat) { // 加密
      value = value.replace(/\n/ig, ' \n ')
      // 替换关键字
      format.forEach(item => {
        let reg = new RegExp('(^|\\s)' + item.key + '(\\s|$)', 'ig')
        value = value.replace(reg, item.value)
      })
      // 1、替换%符(数据库中解析后sql报错)
      value = value.replace(/%/ig, ' mpercent ')
      // 1、encode编码(中文字符超出base64加密范围),2、base64加密
      value = window.btoa(window.encodeURIComponent(value))
      // 插入字符
      let index = Math.floor(value.length / 2)
      value = value.slice(0, index) + salt + value.slice(index)
      // base64加密
      value = window.btoa(value)
    } else { // 解密
      try {
        value = window.atob(value)
        value = value.replace(salt, '')
        value = window.decodeURIComponent(window.atob(value))
        value = value.replace(/\smpercent\s/g, '%')
        format.forEach(item => {
          let reg = new RegExp(item.value, 'g')
          value = value.replace(reg, ' ' + item.key + ' ')
        })
        value = value.replace(/\s\n\s/ig, '\n')
        value = value.replace(/(^\s+|\s+$)/ig, '')
      } catch {
        console.warn('UnFormat Failure')
        value = ''
      }
    }
    value = value.replace(/\n/ig, ' \n ')
    // 替换关键字
    formatKeys.forEach(item => {
      let reg = new RegExp('(^|\\s)' + item.key + '(\\s|$)', 'ig')
      value = value.replace(reg, item.value)
    })
    // 1、替换%符(数据库中解析后sql报错)
    value = value.replace(/%/ig, ' mpercent ')
    // 1、encode编码(中文字符超出base64加密范围),2、base64加密
    value = window.btoa(window.encodeURIComponent(value))
    // 插入字符
    let index = Math.floor(value.length / 2)
    value = value.slice(0, index) + salt + value.slice(index)
    // base64加密
    value = window.btoa(value)
    return value
  }
  /**
   * @description 解密
   * @return {String}   value
   */
  static UnformatOptions (value) {
    if (!value) return ''
    let salt = 'minKe' // 盐值
    let _value = ''
    try {
      try {
        _value = JSON.parse(window.decodeURIComponent(window.atob(value)))
      } catch {
        _value = ''
      }
      if (!_value) {
        _value = window.atob(value)
        _value = _value.replace(salt, '')
        _value = window.decodeURIComponent(window.atob(_value))
        _value = _value.replace(/\smpercent\s/g, '%')
        formatKeys.forEach(item => {
          let reg = new RegExp(item.value, 'g')
          _value = _value.replace(reg, ' ' + item.key + ' ')
        })
        _value = _value.replace(/\s\n\s/ig, '\n')
        _value = _value.replace(/(^\s+|\s+$)/ig, '')
      }
    } catch {
      console.warn('UnFormat Failure')
      _value = ''
    }
    return _value
  }
  /**
@@ -188,47 +219,11 @@
   */
  static sPCInUpDeFormatOptions (value) {
    if (!value) return {LText: '', LText1: '', LText2: ''}
    let salt = 'minKe' // 盐值
    // 关键字转换规则
    let format = [
      { key: 'select', value: ' msltk ' },
      { key: 'from', value: ' mfrmk ' },
      { key: 'where', value: ' mwhrk ' },
      { key: 'order by', value: ' modbk ' },
      { key: 'asc', value: ' modack ' },
      { key: 'desc', value: ' moddesk ' },
      { key: 'top', value: ' mtpk ' },
      { key: 'like', value: ' mlkk ' },
      { key: 'not like', value: ' mnlkk ' },
      { key: 'between', value: ' mbtnk ' },
      { key: 'and', value: ' madk ' },
      { key: 'insert', value: ' mistk ' },
      { key: 'into', value: ' mitk ' },
      { key: 'update', value: ' muptk ' },
      { key: 'delete', value: ' mdelk ' },
      { key: 'begin', value: ' mbgink ' },
      { key: 'end', value: ' medk ' },
      { key: 'if', value: ' mefk ' },
      { key: 'while', value: ' mwilk ' },
      { key: 'create', value: ' mcrtk ' },
      { key: 'alter', value: ' matek ' },
      { key: 'len', value: ' mlnk ' },
      { key: 'left', value: ' mlftk ' },
      { key: 'right', value: ' mritk ' },
      { key: 'union', value: ' munok ' },
      { key: 'varchar', value: ' mvcrk ' },
      { key: 'getdate', value: ' mgtdtk ' },
      { key: 'TRY', value: ' mtryonek ' },
      { key: 'TRAN', value: ' mtrnk ' },
      { key: 'goto', value: ' mgtk ' },
      { key: 'set', value: ' mstk ' },
      { key: 'ROLLBACK', value: ' mrlbkk ' }
    ]
    value = value.replace(/\n/ig, ' \n ')
    // 替换关键字
    format.forEach(item => {
    formatKeys.forEach(item => {
      let reg = new RegExp('(^|\\s)' + item.key + '(\\s|$)', 'ig')
      value = value.replace(reg, item.value)
    })
@@ -689,7 +684,7 @@
    arrfield = arrfield.join(',')
    if (item.orderBy) {
      sql = 'select distinct ' + arrfield + ',' + item.orderBy + ' as orderfield from ' + _datasource + ' order by orderfield ' + item.orderType
      sql = `select ${arrfield} from (select distinct ${arrfield},${item.orderBy} as orderfield from ${_datasource} ) a order by orderfield ${item.orderType}`
    } else {
      sql = 'select distinct ' + arrfield + ' from ' + _datasource
    }
@@ -705,7 +700,7 @@
   * @return {String} btn   按钮
   * @return {String} data  excel数据
   */
  static getExcelInSql (item, data, dict) {
  static getExcelInSql (item, data, dict, BID) {
    let btn = item.verify
    let keys = ['delete', 'drop', 'insert', 'truncate', 'update']
    let userName = sessionStorage.getItem('User_Name') || ''
@@ -747,8 +742,11 @@
      })
    }
    // 控制台打印数据
    let conLtext = []
    let _Ltext = data.map((item, lindex) => {
      let vals = []
      let convals = []
      btn.columns.forEach((col, cindex) => {
        if (col.import === 'false') return
@@ -762,92 +760,91 @@
          val = val.replace(/(^\s*$)|\t*|\v*/ig, '')
          if (!val && col.required === 'true') { // 必填校验
            let _error =  _position + dict['main.excel.content.emptyerror']
            errors.push(_error)
          } else if (val.length > col.limit) {    // 长度校验
            let _error =  _position + dict['main.excel.content.maxlimit']
            errors.push(_error)
          } else {                               // 关键字校验
          if (!val && col.required === 'true') {            // 必填校验
            errors.push(_position + dict['main.excel.content.emptyerror'])
          } else if (col.limit && val.length > col.limit) { // 长度校验
            errors.push(_position + dict['main.excel.content.maxlimit'])
          } else {                                          // 关键字校验
            keys.forEach(key => {
              let _patten = new RegExp('(^' + key + '\\s+)|(\\s+' + key + '\\s+)', 'ig')
              if (_patten.test(val)) {
                let _error = _position + dict['main.excel.includekey'] + key
                errors.push(_error)
                errors.push(_position + dict['main.excel.includekey'] + key)
              }
            })
          }
        } else if (/^int/ig.test(col.type)) {
          if (!val && val !== 0) {
            let _error =  _position + dict['main.excel.content.emptyerror']
            errors.push(_error)
            errors.push(_position + dict['main.excel.content.emptyerror'])
          } else {
            let _val = val + ''
            if (!/^(([^0][0-9]+|0)$)|^(([1-9]+)$)/.test(_val)) {               // 检验是否为整数
              let _error = _position + dict['main.excel.content.interror']
              errors.push(_error)
              errors.push(_position + dict['main.excel.content.interror'])
            } else if ((col.min || col.min === 0) && val < col.min) {          // 最小值检验
              let _error = _position + dict['main.excel.content.limitmin']
              errors.push(_error)
              errors.push(_position + dict['main.excel.content.limitmin'])
            } else if ((col.max || col.max === 0) && val > col.max) {          // 最大值检验
              let _error = _position + dict['main.excel.content.limitmax']
              errors.push(_error)
              errors.push(_position + dict['main.excel.content.limitmax'])
            }
          }
        } else if (/^Decimal/ig.test(col.type)) {
          if (!val && val !== 0) {
            let _error =  _position + dict['main.excel.content.emptyerror']
            errors.push(_error)
            errors.push(_position + dict['main.excel.content.emptyerror'])
          } else {
            let _val = val + ''
            let _vals = _val.split('.')
            if (!/^(([^0][0-9]+|0)\.([0-9]+)$)|^(([^0][0-9]+|0)$)|^(([1-9]+)\.([0-9]+)$)|^(([1-9]+)$)/.test(_val)) {                           // 检验是否为浮点数
              let _error = _position + dict['main.excel.content.floaterror']
              errors.push(_error)
            } else if (_vals[0].length > 18) {                         // 检验整数位
              let _error = _position + dict['main.excel.content.floatIntover']
              errors.push(_error)
              errors.push(_position + dict['main.excel.content.floaterror'])
            } else if (_vals[0].length > 18) {                          // 检验整数位
              errors.push(_position + dict['main.excel.content.floatIntover'])
            } else if (_vals[1] && _vals[1].length > col.limit) {       // 最小值检验
              let _error = _position + dict['main.excel.content.floatPointover']
              errors.push(_error)
            } else if ((col.min || col.min === 0) && val < col.min) { // 最小值检验
              let _error = _position + dict['main.excel.content.limitmin']
              errors.push(_error)
            } else if ((col.max || col.max === 0) && val > col.max) { // 最大值检验
              let _error = _position + dict['main.excel.content.limitmax']
              errors.push(_error)
              errors.push(_position + dict['main.excel.content.floatPointover'])
            } else if ((col.min || col.min === 0) && val < col.min) {   // 最小值检验
              errors.push(_position + dict['main.excel.content.limitmin'])
            } else if ((col.max || col.max === 0) && val > col.max) {   // 最大值检验
              errors.push(_position + dict['main.excel.content.limitmax'])
            }
          }
        } else if (col.type === 'date') {
          val = val.replace(/(^\s*$)|\t*|\v*/ig, '')
          if (!val && col.required === 'true') { // 必填校验
            let _error =  _position + dict['main.excel.content.emptyerror']
            errors.push(_error)
          } else {                               // 关键字校验
            keys.forEach(key => {
              let _patten = new RegExp('(^' + key + '\\s+)|(\\s+' + key + '\\s+)', 'ig')
              if (_patten.test(val)) {
                let _error = _position + dict['main.excel.includekey'] + key
                errors.push(_error)
          if (typeof(val) === 'number') {
            if (val > 2958465 || val <= 0) {                 // 时间过大或小于等于0
              errors.push(_position + dict['main.excel.content.date.over'])
            } else {                                         // 时间格式化
              if (val < 60) {                                // 1900-2-29,excel中存在,实际不存在
                val++
              }
            })
              val = moment('19000101', 'YYYYMMDD').add(Math.floor(val - 2), 'days').format('YYYY-MM-DD')
            }
          } else if (typeof(val) === 'string') {
            val = val.replace(/(^\s*$)|\t*|\v*/ig, '')
            if (!val && col.required === 'true') {           // 时间必填校验
              errors.push(_position + dict['main.excel.content.emptyerror'])
            } else if (val && !/^[1-9][0-9]{3}/.test(val)) { // 时间正则校验
              errors.push(_position + dict['main.excel.content.date.formatError'])
            }
          } else {                                           // 时间格式错误
            errors.push(_position + dict['main.excel.content.date.formatError'])
          }
        }
        if (col.type === 'date') {
          vals.push(`case when ${col.Column}='' then '1900-01-01' else dateadd(day,cast('${val}' as int)-2,'1900-01-01') end as ${col.Column}`)
        } else {
          vals.push(`'${val}' as ${col.Column}`)
        vals.push(`'${val}'`)
        if (lindex < 40) {
          convals.push(`'${val}' as ${col.Column}`)
        }
      })
      let _lineIndex = '0000' + (lindex + 1) + '0'
      _lineIndex = _lineIndex.substring(_lineIndex.length - 6)
      vals.push(`'${upId + _lineIndex}' as jskey`)
      vals.push(`'${upId + _lineIndex}'`)
      vals.push(`'${BID}'`)
      if (lindex < 40) {
        convals.push(`'${upId + _lineIndex}' as jskey`)
        convals.push(`'${BID}' as BID`)
        conLtext.push(`Select ${convals.join(',')}`)
      }
      return `Select ${vals.join(',')}`
    })
@@ -861,7 +858,7 @@
    let _sqlInsert = ''
    let _sqlBottom = ''
    if (item.intertype === 'inner' && !item.innerFunc) {
    if (item.intertype === 'system') {
      let _uniquesql = ''
      if (btn.uniques && btn.uniques.length > 0) {
        btn.uniques.forEach(unique => {
@@ -926,13 +923,13 @@
      _sql = `
        /* 系统生成 */
        declare @${item.sheet} table (${declarefields.join(',')},jskey nvarchar(50) )
        declare @${item.sheet} table (${declarefields.join(',')},jskey nvarchar(50),BID nvarchar(50) )
        Declare @UserName nvarchar(50),@FullName nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@tbid Nvarchar(512)
        
        Select  @ErrorCode='', @retmsg='', @UserName='${userName}', @FullName='${fullName}'
        ${_initCustomScript}
        `
      _sqlInsert = `Insert into  @${item.sheet} (${fields},jskey)`
      _sqlInsert = `Insert into @${item.sheet} (${fields},jskey,BID)`
      _sqlBottom = `
        /* 默认sql */
        delete tmp_excel_in where upid=@upid@
@@ -946,13 +943,13 @@
        
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
      if (window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') {
      if ((window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') || window.debugger === true) {
        let fsql = `
        ${_sql}
        ${_sqlInsert}
        
        /* excel数据(前40条) */
        ${_Ltext.slice(0, 40).join(' Union all ')}
        ${conLtext.join(' Union all ')}
        ${_sqlBottom}
        `
        fsql = fsql.replace(/\n\s{8}/ig, '\n')
@@ -967,7 +964,7 @@
        Select  @ErrorCode='', @retmsg='', @UserName='${userName}', @FullName='${fullName}'
        `
    }
    return {
      sql: _sql,
      lines: result.map((list, index) => {
@@ -994,7 +991,7 @@
    let _formFieldValue = {}
    let _actionType = null
    let appkey = window.GLOB.appkey || ''
    let sessionUid = sessionStorage.getItem('SessionUid') || ''
    let sessionUid = localStorage.getItem('SessionUid') || ''
    if (verify.default !== 'false') { // 判断是否使用默认sql
      _actionType = btn.sqlType
@@ -1150,7 +1147,9 @@
    // 变量赋值
    _initfields = _initfields.join(',')
    if (_initfields) {
      _sql += `select ${_initfields}
      _sql += `
        select ${_initfields}
        `
    }
@@ -1199,8 +1198,15 @@
    // 失效验证,添加数据时不用
    if (btn.sqlType !== 'insert' && verify.invalid === 'true' && setting.dataresource) {
      let datasource = setting.dataresource
      if (/\s/.test(datasource)) { // 拼接别名
      if (/\s/.test(datasource) && !/tb$/.test(datasource)) { // 拼接别名
        datasource = '(' + datasource + ') tb'
      }
      if (setting.customScript) {
        _sql += `
        /* 数据源自定义脚本,请注意变量定义是否重复 */
        ${setting.customScript}
        `
      }
      if (btn.Ot === 'requiredOnce') {
@@ -1239,81 +1245,6 @@
        Begin
          select @ErrorCode='${item.errorCode}',@retmsg='${item.errmsg}'
            goto aaa
        end
        `
      })
    }
    // 唯一性验证,必须存在表单(表单存在时,主键均为单值),必须填写数据源,多行拼接时不可用
    if (formdata && verify.uniques && verify.uniques.length > 0 && btn.Ot !== 'requiredOnce') {
      let hasBid = false // 检验表单及列字段中是否有bid
      let _keys_ = Object.keys(_formFieldValue).map(key => key.toLowerCase())
      if (_keys_.includes('bid')) {
        hasBid = true
      }
      verify.uniques.forEach(item => {
        let _fieldValue = []                     // 表单键值对field=value
        let _value = []                          // 表单值,用于错误提示
        let _labels = item.fieldlabel.split(',') // 表单提示文字
        let arr = [] // 验证主键
        item.field.split(',').forEach((_field, index) => {
          let _fval = `'${_formFieldValue[_field]}'`
          if (_field.toLowerCase() === 'bid' && !hasBid) { // 表单中没有bid则使用系统bid变量
            _fval = '@BID@'
          }
          if (_field.toLowerCase() === 'bid' && tab && tab.foreignKey) {
            arr.push(tab.foreignKey.toLowerCase())
            _fieldValue.push(`${tab.foreignKey}=${_fval}`)
          } else {
            arr.push(_field.toLowerCase())
            _fieldValue.push(`${_field}=${_fval}`)
          }
          _value.push(`${_labels[index] || ''}:${_formFieldValue[_field] || ''}`)
        })
        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)) { // 拼接别名
        datasource = '(' + datasource + ') tb'
      } else {
        datasource = datasource + ' tb'
      }
      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
        `
      })
@@ -1390,6 +1321,90 @@
      }
    }
    // 唯一性验证,必须存在表单(表单存在时,主键均为单值),必须填写数据源,多行拼接时不可用
    if (formdata && verify.uniques && verify.uniques.length > 0 && btn.Ot !== 'requiredOnce') {
      let hasBid = false // 检验表单及列字段中是否有bid
      let _keys_ = Object.keys(_formFieldValue).map(key => key.toLowerCase())
      if (_keys_.includes('bid')) {
        hasBid = true
      }
      verify.uniques.forEach(item => {
        let _fieldValue = []                     // 表单键值对field=value
        let _value = []                          // 表单值,用于错误提示
        let _labels = item.fieldlabel.split(',') // 表单提示文字
        let arr = [] // 验证主键
        item.field.split(',').forEach((_field, index) => {
          let _fval = `'${_formFieldValue[_field]}'`
          if (_field.toLowerCase() === 'bid' && !hasBid) { // 表单中没有bid则使用系统bid变量
            _fval = '@BID@'
          }
          if (_field.toLowerCase() === 'bid' && tab && tab.foreignKey) {
            arr.push(tab.foreignKey.toLowerCase())
            _fieldValue.push(`${tab.foreignKey}=${_fval}`)
          } else {
            arr.push(_field.toLowerCase())
            _fieldValue.push(`${_field}=${_fval}`)
          }
          _value.push(`${_labels[index] || ''}:${_formFieldValue[_field] || ''}`)
        })
        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
    // 凭证-显示列中选取,必须选行
@@ -1425,6 +1440,8 @@
      let values = []
      formdata.forEach(item => {
        if (item.writein === false) return
        keys.push(item.key.toLowerCase())
        values.push('@' + item.key)
      })
@@ -1468,6 +1485,8 @@
      let _arr = []
      formdata.forEach(item => {
        if (item.writein === false) return
        _arr.push(item.key.toLowerCase())
        _form.push(item.key + '=@' + item.key)
      })
@@ -1551,7 +1570,8 @@
      _sql += `
        /* 默认sql */
        insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('删除表:${btn.sql} 数据: ${_msg}${primaryKey}='+@ID@,200),@userid@,@username,@fullname delete ${btn.sql} where ${primaryKey}${_ID};`
        insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('删除表:${btn.sql} 数据: ${_msg}${primaryKey}='+@ID@,200),@userid@,@username,@fullname
        delete ${btn.sql} where ${primaryKey}${_ID};`
    } else if (_actionType === 'insertOrUpdate') {
      _sql += `
        /* 默认sql */
@@ -1576,7 +1596,7 @@
    _sql += `
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    if (window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') {
    if ((window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') || window.debugger === true) {
      _sql = _sql.replace(/\n\s{8}/ig, '\n')
      console.log(_sql)
    }