king
2019-12-19 ff045a6a19e2e0bd5c2433aae71145401627c22d
2019-12-19
14个文件已修改
865 ■■■■ 已修改文件
src/api/index.js 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/mainAction/index.jsx 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/mainTable/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/mainTable/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/actionform/index.jsx 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/editcard/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 284 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/searchform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/settingform/index.jsx 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/editcard/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.jsx 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js
@@ -34,7 +34,6 @@
axios.interceptors.response.use((response) => {
  if (response.data.ErrCode === 'LoginError') {
    setCurrentUrl()
    // return Promise.resolve(response.data)
  } else {
    return Promise.resolve(response.data)
  }
@@ -204,15 +203,50 @@
  /**
   * @description 导出Excel
   */
  getExcelOut (param) {
  getExcelOut (param, name) {
    param.userid = sessionStorage.getItem('UserID')
    param.lang = localStorage.getItem('lang') || ''
    param.SessionUid = sessionStorage.getItem('SessionUid') || ''
    param.LoginUID = sessionStorage.getItem('LoginUID') || ''
    
    return axios({
      url: '/webapi/doexcel',
      data: param
    return new Promise(resolve => {
      axios({
        url: '/webapi/doexcel',
        responseType: 'blob',
        data: param
      }).then(res => {
        try {
          const blob = new Blob([res])
          if (res.type === 'application/json') {
            const reader = new FileReader()
            reader.onload = e => resolve(JSON.parse(e.target.result))
            reader.readAsText(blob)
          } else {
            if ('download' in document.createElement('a')) { // 非IE下载
              const elink = document.createElement('a')
              elink.download = name
              elink.style.display = 'none'
              elink.href = URL.createObjectURL(blob)
              document.body.appendChild(elink)
              elink.click()
              URL.revokeObjectURL(elink.href) // 释放URL 对象
              document.body.removeChild(elink)
            } else { // IE10+下载
              navigator.msSaveBlob(blob, name)
            }
            resolve()
          }
        } catch {
          resolve({
            ErrCode: 'E',
            ErrMesg: '文件解析错误',
            message: '',
            status: false
          })
        }
      })
    })
  }
src/components/tabview/index.jsx
@@ -79,15 +79,15 @@
  selectcomponent (view) {
    // 根据tab页中菜单信息,选择所需的组件
    if (view.type === 'CommonTable') {
      return (<Comps.CommonTable MenuNo={view.MenuNo} MenuID={view.MenuID} key={view.MenuID}/>)
      return (<Comps.CommonTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    } else if (view.type === 'DataManage') {
      return (<Comps.DataManage MenuNo={view.MenuNo} MenuID={view.MenuID} key={view.MenuID}/>)
      return (<Comps.DataManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    } else if (view.type === 'RoleManage') {
      return (<Comps.RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} key={view.MenuID}/>)
      return (<Comps.RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    } else if (view.type === 'TabForm') {
      return (<Comps.TabForm MenuNo={view.MenuNo} MenuID={view.MenuID} key={view.MenuID} param={view.param}/>)
      return (<Comps.TabForm MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
    } else if (view.type === 'iframe') {
      return (<Comps.Iframe key={view.MenuID} title={view.MenuName} url={service + view.LinkUrl}/>)
      return (<Comps.Iframe key={view.MenuID} title={view.MenuName} MenuName={view.MenuName} url={service + view.LinkUrl}/>)
    } else {
      return (<NotFount key={view.MenuID} />)
    }
src/tabviews/commontable/index.jsx
@@ -16,8 +16,9 @@
export default class NormalTable extends Component {
  static propTpyes = {
    MenuNo: PropTypes.string,  // 菜单参数
    MenuID: PropTypes.string   // 菜单Id
    MenuNo: PropTypes.string,    // 菜单参数
    MenuName: PropTypes.string,  // 菜单参数
    MenuID: PropTypes.string     // 菜单Id
  }
  state = {
@@ -233,13 +234,70 @@
  async loadmaindata () {
    const { setting } = this.state
    let param = ''
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam()
    } else {
      param = this.getDefaultParam()
    }
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
          return item
        }),
        total: result.total,
        loading: false
      })
    } else {
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 15
      })
    }
  }
  getCustomParam = () => {
    const { pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
    let _search = Utils.formatCustomMainSearch(search)
    let param = {
      PageIndex: pageIndex,
      PageSize: pageSize,
      OrderCol: orderColumn,
      OrderType: orderType,
      ..._search
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      param.rduri = setting.interface
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  getDefaultParam = () => {
    const { arr_field, pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
    let _search = Utils.joinMainSearchkey(search)
    _search = _search ? 'where (' + _search + ')' : ''
    // 获取列表数据
    let param = {
      func: setting.innerFunc || 'sPC_Get_TableData',
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field
    }
@@ -254,39 +312,7 @@
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = Utils.formatOptions(DateCount)
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
          return item
        }),
        total: result.total,
        loading: false
      })
    } else {
      // this.setState({
      //   data: [1,2,3,4,5,6,7,8,9,10].map((item, index) => {
      //     let cell = {}
      //     this.state.config.columns.forEach(column => {
      //       if (!column.field) return
      //       cell[column.field] = 'test' + item
      //     })
      //     cell.key = index
      //     return cell
      //   }),
      //   total: 329,
      //   loading: false
      // })
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 15
      })
    }
    return param
  }
  refreshbysearch = (searches) => {
@@ -369,32 +395,54 @@
    } else if (btn.execError === 'view' && type === 'error') {
      this.reloadview()
    } else if (type === 'excelOut') {
      this.handleExcelout()
      this.handleDefaultExcelout(btn)
    }
  }
  handleExcelout = () => {
    const { arr_field, orderColumn, orderType, search, setting } = this.state
  handleDefaultExcelout = (btn) => {
    const { MenuName } = this.props
    const { arr_field, orderColumn, orderType, search, setting, config } = this.state
    let _arr_labels = []      // 列名称集
    let _arr_label_field = [] // 列名称字段集
    config.columns.forEach(col => {
      if (col.field) {
        _arr_labels.push(col.label)
        _arr_label_field.push(`${col.field} as ${col.label}`)
      }
    })
    _arr_labels = _arr_labels.join(',')
    _arr_label_field = _arr_label_field.join(',')
    let _search = Utils.joinMainSearchkey(search)
    _search = _search ? 'where (' + _search + ')' : ''
    // 获取列表数据
    let param = {
      func: setting.innerFunc || 'sPC_Get_TableData',
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field
      arr_field: _arr_labels
    }
    let orderBy = orderColumn ? (orderColumn + ' ' + orderType) : setting.order
    let LText = `select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${setting.dataresource} ${_search}) tmptable order by tmptable.rows`
    let LText = `select ${_arr_label_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${setting.dataresource} ${_search}) tmptable order by tmptable.rows`
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = ''
    Api.genericInterface(param)
    let name = `${MenuName}${moment().format('YYYYMMDDHHmmss')}.xlsx`
    Api.getExcelOut(param, name).then(res => {
      if (res && res.status === false) {
        this.refs.mainButton.execError(res, btn)
      } else {
        this.refs.mainButton.execSuccess(btn)
      }
    })
  }
  gettableselected = () => {
src/tabviews/commontable/mainAction/index.jsx
@@ -32,11 +32,15 @@
    this.props.refreshdata(item, type)
  }
  
  actionTrigger = (item) => {
  actionTrigger = (item, record) => {
    const { setting } = this.props
    let _this = this
    let data = this.props.gettableselected() || []
    if (record) { // 表格中触发按钮
      data = [record]
    }
    if (item.Ot !== 'notRequired' && data.length === 0) {
      // 需要选择行时,校验数据
@@ -88,6 +92,7 @@
        this.improveAction(item)
      })
    } else if (item.OpenType === 'excelOut') {
      this.setState({loadingUuid: item.uuid})
      this.refreshdata(item, 'excelOut')
    } else {
      notification.warning({
@@ -497,11 +502,17 @@
  }
  execSuccess = (btn) => {
    notification.success({
      top: 92,
      message: this.props.dict['main.action.confirm.success'],
      duration: 2
    })
    if (btn.OpenType === 'excelOut') {
      this.setState({
        loadingUuid: ''
      })
    } else {
      notification.success({
        top: 92,
        message: this.props.dict['main.action.confirm.success'],
        duration: 2
      })
    }
    
    if (btn.OpenType === 'pop' && btn.setting && btn.setting.finish !== 'unclose') {
      this.setState({
@@ -512,11 +523,18 @@
  }
  execError = (res, btn) => {
    notification.error({
      top: 92,
      message: res.message,
      duration: 15
    })
    if (!res.ErrCode || res.ErrCode === 'E') {
      notification.error({
        top: 92,
        message: res.message || res.ErrMesg,
        duration: 15
      })
    } else if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || res.ErrMesg
      })
    }
    this.refreshdata(btn, 'error')
  }
src/tabviews/commontable/mainTable/index.jsx
@@ -96,7 +96,8 @@
      }
      if (content && item.format === 'thdSeparator') {
        content = `${content}`
        content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
      }
      content = (item.prefix || '') + content + (item.postfix || '')
@@ -109,7 +110,7 @@
          </div>
        </div>
      )
    } else if (item.type === 'operation') {
    } else if (item.type === 'action') {
      return (
        <div className={item.style} style={{ minWidth: (item.Width || 120) + 'px' }}>
          {item.operations.map(btn => {
src/tabviews/commontable/mainTable/index.scss
@@ -77,6 +77,11 @@
          margin-right: 5px;
        }
      }
      .ant-table-tbody > tr > td .button {
        .ant-btn {
          margin-bottom: 10px;
        }
      }
    }
  }
  .ant-table-body::-webkit-scrollbar {
src/templates/comtableconfig/actionform/index.jsx
@@ -41,6 +41,26 @@
    }, {
      MenuID: 'requiredOnce',
      text: this.props.dict['header.form.requiredOnce']
    }],
    insertUpdateOptions: [{
      MenuID: '',
      text: this.props.dict['header.form.empty']
    }, {
      MenuID: 'insert',
      text: this.props.dict['header.form.action.insert']
    }, {
      MenuID: 'update',
      text: this.props.dict['header.form.action.update']
    }],
    deleteOptions: [{
      MenuID: '',
      text: this.props.dict['header.form.empty']
    }, {
      MenuID: 'LogicDelete',
      text: this.props.dict['header.form.action.LogicDelete']
    }, {
      MenuID: 'delete',
      text: this.props.dict['header.form.action.delete']
    }]
  }
@@ -86,6 +106,12 @@
          } else {
            item.options = this.state.reqOptionsMutil
          }
        } else if (item.key === 'sqlType') {
          if (['prompt', 'exec'].includes(_opentype)) {
            item.options = this.state.deleteOptions
          } else {
            item.options = this.state.insertUpdateOptions
          }
        }
        item.hidden = !_options.includes(item.key)
        return item
@@ -129,14 +155,21 @@
            if (value === 'innerpage' || this.state.position === 'grid') {
              item.options = this.state.reqOptionSgl
              item.initVal = 'requiredSgl'
              item.hidden = true
            } else if (['outerpage', 'blank', 'tab', 'popview'].includes(value)) {
              item.options = this.state.reqOptions
              item.initVal = 'requiredSgl'
              item.hidden = true
            } else {
              item.options = this.state.reqOptionsMutil
            }
            item.hidden = true
          } else if (item.key === 'sqlType') {
            if (['prompt', 'exec'].includes(value)) {
              item.options = this.state.deleteOptions
            } else {
              item.options = this.state.insertUpdateOptions
            }
            item.initVal = ''
            item.hidden = true
          }
          return item
        })
@@ -146,6 +179,8 @@
        this.setState({
          formlist: this.state.formlist.map(item => {
            if (item.key === 'Ot') {
              item.hidden = false
            } else if (item.key === 'sqlType' && ['prompt', 'exec', 'pop'].includes(value)) {
              item.hidden = false
            }
            return item
@@ -213,16 +248,13 @@
        let _rules = []
        if (item.key === 'innerFunc') {
          let str = '^(' + item.fields.join('|') + ')'
          let _patten = new RegExp(str + '[0-9a-zA-Z_]*', 'ig')
          let _patten = new RegExp(str + '[0-9a-zA-Z_]*$', 'g')
          _rules = [{
            pattern: _patten,
            message: '名称只允许包含数字、字母和下划线,且以指定字符开始。'
          }, {
            min: 6,
            message: '内部函数名称不小于6个字符。'
          }, {
            max: 100,
            message: '内部函数名称不超过100个字符。'
            max: 50,
            message: '内部函数名称不超过50个字符。'
          }]
        }
        fields.push(
src/templates/comtableconfig/editcard/index.jsx
@@ -10,14 +10,14 @@
    let _type = props.card.type
    if (props.type === 'columns') {
      if (_type !== 'picture') {
      if (_type === 'date' || _type === 'datetime') {
        _type = 'text'
      }
    } else if (props.type === 'search') {
      if (_type === 'number') {
        _type = 'text'
      } else if (_type === 'datetime') {
        _type = 'date'
        _type = 'daterange'
      }
    }
@@ -40,6 +40,8 @@
    const { card } = this.state
    this.setState({
      card: {...card, type: e.target.value}
    }, () => {
      this.props.changeCard(this.state.card)
    })
  }
@@ -62,6 +64,7 @@
        {type === 'columns' ?
          <Radio.Group onChange={this.changeType} value={card.type} disabled={!card.selected}>
            <Radio value="text">text</Radio>
            <Radio value="number">number</Radio>
            <Radio value="picture">picture</Radio>
          </Radio.Group> : null
        }
src/templates/comtableconfig/index.jsx
@@ -650,20 +650,6 @@
            text: this.state.dict['header.form.refresh.view']
          }]
        },
        // {
        //   type: 'select',
        //   key: 'method',
        //   label: this.state.dict['header.form.request.method'],
        //   initVal: card.method || 'POST',
        //   required: true,
        //   options: [{
        //     MenuID: 'POST',
        //     text: 'POST'
        //   }, {
        //     MenuID: 'GET',
        //     text: 'GET'
        //   }]
        // },
        {
          type: 'select',
          key: 'icon',
@@ -695,22 +681,7 @@
          initVal: card.sqlType || '',
          tooltip: this.state.dict['header.form.actionhelp.sqlType'],
          required: false,
          options: [{
            MenuID: '',
            text: this.state.dict['header.form.empty']
          }, {
            MenuID: 'insert',
            text: this.state.dict['header.form.action.insert']
          }, {
            MenuID: 'update',
            text: this.state.dict['header.form.action.update']
          }, {
            MenuID: 'LogicDelete',
            text: this.state.dict['header.form.action.LogicDelete']
          }, {
            MenuID: 'delete',
            text: this.state.dict['header.form.action.delete']
          }]
          options: []
        }
      ]
    })
@@ -1125,7 +1096,7 @@
              }
              newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config.columns))
              DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
              resolve(false)
              resolve(true)
            } else {
              resolve(false)
              notification.warning({
@@ -1144,7 +1115,7 @@
          }
          newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config.columns))
          DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
          resolve(false)
          resolve(true)
        }
      }).then(res => {
        // 获取云端及本地,是否已存在该存储过程的信息
@@ -1201,8 +1172,8 @@
        
        if ((newLText === localTVPText) && (newLText === sysTVPText)) {
          return 'drop'
        } else if (!localTVPText || (sysTVPText === localTVPText)) {
          // 本地存储过程不存在,或云端和本地存储过程一致时,将新的存储过程更新至云端
        } else if (!localTVPText || (localTVPText === sysTVPText)) {
          // 本地存储过程不存在,将新的存储过程更新至云端
          return Api.getSystemConfig({
            func: 'sPC_TVP_InUp',
            TVPName: btn.innerFunc,
@@ -1364,6 +1335,227 @@
          this.setState({
            actionloading: false
          })
        })
      })
    })
  }
  /**
   * @description 创建表格存储过程
   */
  tableCreatFunc = () => {
    const { menu } = this.props
    let config = JSON.parse(JSON.stringify(this.state.config))
    this.settingRef.handleConfirm().then(res => {
      const setting = res
      if (!(setting.interType === 'inner') || !setting.innerFunc) {
        notification.warning({
          top: 92,
          message: '接口类型为-内部,且存在内部函数时,才可以创建存储过程!',
          duration: 10
        })
        return
      }
      if (setting.dataresource.length > 50 && config.setting.dataresource !== setting.dataresource) {
        let param = {
          func: 's_DataSrc_Save',
          LText: setting.dataresource,
          MenuID: menu.MenuID
        }
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        Api.getLocalConfig(param)
      }
      this.setState({
        funcLoading: true
      })
      let newLText = Utils.formatOptions(Utils.getTableFunc(setting, menu, config)) // 创建存储过程sql
      let DelText = Utils.formatOptions(Utils.dropfunc(setting.innerFunc))          // 删除存储过程sql
      new Promise(resolve => {
        let sysDefer = new Promise(resolve => {
          Api.getSystemConfig({
            func: 'sPC_Get_TVP', // 云端获取存储结果
            TVPName: setting.innerFunc
          }).then(result => {
            if (!result.status) {
              notification.warning({
                top: 92,
                message: result.message,
                duration: 10
              })
              resolve(false)
            } else {
              resolve(result)
            }
          })
        })
        let localDefer = new Promise(resolve => {
          let _param = { // 获取本地存储过程信息
            func: 's_get_userproc',
            LText: setting.innerFunc
          }
          _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
          _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
          Api.getLocalConfig(_param).then(result => {
            if (!result.status) {
              notification.warning({
                top: 92,
                message: result.message,
                duration: 10
              })
              resolve(false)
            } else {
              resolve(result)
            }
          })
        })
        Promise.all([sysDefer, localDefer]).then(result => {
          resolve(result)
        })
      }).then(res => {
        // 获取云端及本地,是否已存在该存储过程的信息
        if (res === false) return res
        if (res[0] === false || res[1] === false) return false
        let cloudfunc = ''
        let localfunc = ''
        res.forEach((item, index) => {
          if (index === 0 && item.TVPText) {
            cloudfunc = item.TVPText
          } else if (index === 1 && item.Ltext) {
            localfunc = Utils.formatOptions(item.Ltext)
          }
        })
        if ((newLText === localfunc) && (newLText === cloudfunc)) {
          return 'drop'
        } else if (!localfunc || (cloudfunc === localfunc)) {
          // 本地存储过程不存在,或云端和本地存储过程一致时,将新的存储过程更新至云端
          return Api.getSystemConfig({
            func: 'sPC_TVP_InUp',
            TVPName: setting.innerFunc,
            TVPText: newLText,
            TypeName: 'P'
          })
        } else {
          return new Promise(resolve => {
            Api.getSystemConfig({ // 添加现有的本地存储过程至云端
              func: 'sPC_TVP_InUp',
              TVPName: setting.innerFunc,
              TVPText: localfunc,
              TypeName: 'P'
            }).then(result => {
              if (result.status) {
                Api.getSystemConfig({
                  func: 'sPC_TVP_InUp', // 添加最新的存储过程至云端
                  TVPName: setting.innerFunc,
                  TVPText: newLText,
                  TypeName: 'P'
                }).then(response => {
                  resolve(response)
                })
              } else {
                resolve(result)
              }
            })
          })
        }
      }).then(res => {
        // 云端信息更新后,判断是删除或是直接新建存储过程
        if (res === false || res === 'drop') return res
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
          return false
        } else {
          return 'create'
        }
      }).then(res => {
        // 删除存储过程
        if (res === false || res === 'create') return res
        let _param = {
          func: 'sPC_TableData_InUpDe',
          LText: DelText,
          TypeCharOne: 'proc' // 删除或创建存储过程
        }
        _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
        return Api.getLocalConfig(_param)
      }).then(res => {
        // 根据上述操作结果,判断是否新建存储过程
        if (res === false || res === 'create') return res
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
          return false
        } else {
          return 'create'
        }
      }).then(res => {
        // 新建存储过程
        if (res === false) return res
        let _param = {
          func: 'sPC_TableData_InUpDe',
          LText: newLText,
          TypeCharOne: 'proc' // 删除或创建存储过程
        }
        _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
        return Api.getLocalConfig(_param)
      }).then(res => {
        // 处理新建结果
        if (res === false) return res
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
          return false
        } else {
          notification.success({
            top: 92,
            message: '创建成功',
            duration: 2
          })
          return true
        }
      }).then(res => {
        // 新建成功后,更新页面按钮信息
        if (res === false) {
          this.setState({
            funcLoading: false
          })
          return
        }
        this.setState({
          config: {...config, setting: setting}
        })
      })
    })
@@ -1783,10 +1975,10 @@
      date: 'like'
    }
    const selectmatch = { // 选择select时匹配规则
      text: 'equal',
      number: 'equal',
      datetime: 'equal',
      date: 'equal'
      text: '=',
      number: '=',
      datetime: '=',
      date: '='
    }
    const datematch = { // 选择dateRange时匹配规则
      text: 'between',
@@ -1894,8 +2086,8 @@
            label: item.label,
            field: item.field,
            Hide: 'false',
            IsSort: 'true',
            type: 'text',
            IsSort: item.type === 'picture' ? 'false' : 'true',
            type: item.type,
            Width: 120
          }
@@ -2301,7 +2493,7 @@
          visible={this.state.visible}
          width={700}
          onCancel={() => { this.setState({ visible: false }) }}
          onOk={this.handleSubmit}
          // onOk={this.handleSubmit}
          footer={[
            this.state.formtemp === 'action' ?
            <Button key="delete" className="mk-btn mk-purple" onClick={this.creatFunc} loading={this.state.funcLoading}>{this.state.dict['header.menu.func.create']}</Button> : null,
@@ -2379,19 +2571,25 @@
          title={this.state.dict['header.edit']}
          visible={this.state.settingVisible}
          width={700}
          onOk={this.settingSave}
          // onOk={this.settingSave}
          onCancel={() => { // 取消修改
            this.setState({
              settingVisible: false
            })
          }}
          footer={[
            <Button key="delete" className="mk-btn mk-purple" onClick={this.tableCreatFunc} loading={this.state.funcLoading}>{this.state.dict['header.menu.func.create']}</Button>,
            <Button key="cancel" onClick={() => { this.setState({ settingVisible: false }) }}>{this.state.dict['header.cancel']}</Button>,
            <Button key="confirm" type="primary" onClick={this.settingSave}>{this.state.dict['header.confirm']}</Button>
          ]}
          destroyOnClose
        >
          <SettingForm
            dict={this.state.dict}
            menu={this.props.menu}
            data={this.state.config.setting}
            columns={this.state.config.columns}
            dict={this.state.dict}
            usefulFields={this.props.permFuncField}
            wrappedComponentRef={(inst) => this.settingRef = inst}
          />
        </Modal>
src/templates/comtableconfig/searchform/index.jsx
@@ -89,7 +89,7 @@
      if (value === 'link') {
        _options = [..._options, 'linkField']
      }
      console.log(value)
      this.setState({
        openType: value,
        formlist: this.state.formlist.map(form => {
src/templates/comtableconfig/settingform/index.jsx
@@ -10,11 +10,13 @@
    dict: PropTypes.object, // 字典项
    menu: PropTypes.object,
    data: PropTypes.object,
    columns: PropTypes.array
    columns: PropTypes.array,
    usefulFields: PropTypes.array
  }
  state = {
    interType: this.props.data.interType || 'inner'
    interType: this.props.data.interType || 'inner',
    columns: this.props.columns.filter(item => item.field && item.type !== 'colspan')
  }
  handleConfirm = () => {
@@ -22,6 +24,8 @@
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values.actionfixed = values.actionfixed === 'true'
          values.columnfixed = values.columnfixed === 'true'
          if (values.interType === 'inner' && !values.innerFunc && !values.dataresource) {
            notification.warning({
@@ -46,9 +50,9 @@
  }
  render() {
    const { data, dict, menu } = this.props
    const { data, dict, menu, usefulFields } = this.props
    const { getFieldDecorator } = this.props.form
    const { interType } = this.state
    const { interType, columns } = this.state
    const formItemLayout = {
      labelCol: {
@@ -63,12 +67,14 @@
    let primaryKey = data.primaryKey
    if (primaryKey) {
      let field = this.props.columns.filter(column => column.field === primaryKey)
      let field = columns.filter(column => column.field === primaryKey)
      if (field.length !== 1) {
        primaryKey = ''
      }
    }
    console.log(menu)
    let str = '^(' + usefulFields.join('|') + ')'
    let _patten = new RegExp(str + '[0-9a-zA-Z_]*$', 'g')
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form commontable-setting-form" id="commontable-setting-form">
@@ -134,9 +140,23 @@
            </Form.Item>
          </Col> : null}
          {interType !== 'outer' ? <Col span={12}>
            <Form.Item label={dict['header.form.innerFunc']}>
            <Form.Item label={
              <Tooltip placement="topLeft" overlayClassName="middle" title={`可自定义数据处理函数,函数名称需以${usefulFields.join(', ')}等字符开始;未设置时会调用系统函数,使用系统函数需完善数据源。`}>
                <Icon type="question-circle" />
                {dict['header.form.innerFunc']}
              </Tooltip>
            }>
              {getFieldDecorator('innerFunc', {
                initialValue: data.innerFunc || ''
                initialValue: data.innerFunc || '',
                rules: [
                  {
                    pattern: _patten,
                    message: '名称只允许包含数字、字母和下划线,且以指定字符开始。'
                  }, {
                    max: 50,
                    message: '内部函数名称不超过50个字符。'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col> : null}
@@ -155,41 +175,41 @@
          <Col span={12}>
            <Form.Item label="固定按钮">
              {getFieldDecorator('actionfixed', {
                initialValue: data.actionfixed
                initialValue: data.actionfixed ? 'true' : 'false'
              })(
                <Radio.Group>
                  <Radio value={true}>是</Radio>
                  <Radio value={false}>否</Radio>
                </Radio.Group>
                <Select>
                  <Select.Option value="true">是</Select.Option>
                  <Select.Option value="false">否</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="固定列">
              {getFieldDecorator('columnfixed', {
                initialValue: data.columnfixed
                initialValue: data.columnfixed ? 'true' : 'false'
              })(
                <Radio.Group>
                  <Radio value={true}>是</Radio>
                  <Radio value={false}>否</Radio>
                </Radio.Group>
                <Select>
                  <Select.Option value="true">是</Select.Option>
                  <Select.Option value="false">否</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="主键">
              {getFieldDecorator('primaryKey', {
                initialValue: primaryKey ? primaryKey : (this.props.columns.length === 0 ? 'ID' : '')
                initialValue: primaryKey ? primaryKey : (columns.length === 0 ? 'ID' : '')
              })(
                <Select
                  getPopupContainer={() => document.getElementById('commontable-setting-form')}
                >
                  <Select.Option value="">不设置</Select.Option>
                  {this.props.columns.length === 0 ?
                    <Select.Option value="ID">ID</Select.Option> : null
                  <Select.Option key='unset' value="">不设置</Select.Option>
                  {columns.length === 0 ?
                    <Select.Option key='id' value="ID">ID</Select.Option> : null
                  }
                  {this.props.columns.map(option =>
                    <Select.Option id={option.uuid} title={option.label} key={option.uuid} value={option.field}>{option.label}</Select.Option>
                  {columns.map((option, index) =>
                    <Select.Option id={option.uuid} title={option.label} key={index} value={option.field}>{option.label}</Select.Option>
                  )}
                </Select>
              )}
src/templates/modalconfig/editcard/index.jsx
@@ -27,6 +27,8 @@
    const { card } = this.state
    this.setState({
      card: {...card, type: e.target.value}
    }, () => {
      this.props.changeCard(this.state.card)
    })
  }
@@ -44,7 +46,6 @@
          <Radio value="number">number</Radio>
          <Radio value="select">select</Radio>
          <Radio value="date">date</Radio>
          <Radio value="datetime">datetime</Radio>
        </Radio.Group>
      </div>
    )
src/templates/modalconfig/settingform/index.jsx
@@ -32,7 +32,7 @@
        }
      })
    }
    console.log(fields)
    this.setState({
      fields: fields
    })
@@ -106,6 +106,19 @@
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="列数">
              {getFieldDecorator('cols', {
                initialValue: config.setting.cols || '2'
              })(
                <Select>
                  <Select.Option value="1">1列</Select.Option>
                  <Select.Option value="2">2列</Select.Option>
                  <Select.Option value="3">3列</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="完成后">
              {getFieldDecorator('finish', {
                initialValue: config.setting.finish || 'close'
@@ -125,19 +138,6 @@
                <Radio.Group>
                  <Radio value="close">关闭</Radio>
                  <Radio value="unclose">不关闭</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="列数">
              {getFieldDecorator('cols', {
                initialValue: config.setting.cols
              })(
                <Radio.Group>
                  <Radio value="1">1列</Radio>
                  <Radio value="2">2列</Radio>
                  <Radio value="3">3列</Radio>
                </Radio.Group>
              )}
            </Form.Item>
src/utils/utils.js
@@ -223,6 +223,58 @@
  }
  /**
   * @description 初始化搜索条件
   * @param {Array}   searches     搜索条件
   * @return {String}  searches    格式化后结果
   */
  static formatCustomMainSearch (searches) {
    if (!searches || searches.length === 0) return {}
    let newsearches = {}
    searches.forEach(item => {
      if (item.type === 'date') {
        let timetail = ''
        if (item.match === '<' || item.match === '<=') {
          timetail = ' 23:59:59.999'
        } else if (item.match === '>' || item.match === '>=') {
          timetail = ' 00:00:00.000'
        }
        if (newsearches[item.key]) {
          newsearches[item.key + '1'] = item.value ? item.value + timetail : null
        } else {
          newsearches[item.key] = item.value ? item.value + timetail : null
        }
      } else if (item.type === 'datemonth') {
        // 月-过滤条件,从月开始至结束
        let _startval = null
        let _endval = null
        if (item.value) {
          _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
          _endval = moment(item.value, 'YYYY-MM').endOf('month').format('YYYY-MM-DD') + ' 23:59:59.999'
        }
        newsearches[item.key] = _startval
        newsearches[item.key + '1'] = _endval
      } else if (item.type === 'dateweek') {
        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : null
        newsearches[item.key + '1'] = item.value ? item.value[1] + ' 23:59:59.999' : null
      } else if (item.type === 'daterange') {
        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : null
        newsearches[item.key + '1'] = item.value ? item.value[1] + ' 23:59:59.999' : null
      } else {
        newsearches[item.key] = item.value
      }
    })
    return newsearches
  }
  /**
   * @description 拼接搜索条件main
   * @param {Array}   searches     搜索条件
   * @return {String}  searchText  拼接结果
@@ -361,7 +413,7 @@
    } else if ((btn.OpenType === 'prompt' || btn.OpenType === 'exec') && btn.sqlType === 'delete') {
      _sql = `insert into snote (remark,createuserid) select '删除表:${btn.sql} 数据: id='+@id,@userid delete ${btn.sql} where ${setting.primaryKey}=@id`
    }
    console.log(_sql)
    return _sql
  }
@@ -374,14 +426,139 @@
  }
  /**
   * @description 创建页面存储过程
   * @return {String}
   */
  static getTableFunc (param, menu, config) {
    let form = ''
    let formParam = ''
    let _columns = []
    if (config.search && config.search.length > 0) {
      let _fields = new Map()
      config.search.forEach(item => {
        if (item.field) {
          let type = ''
          let _f = item.field
          if (item.type.match(/date/ig)) {
            type = 'datetime=null'
          } else {
            type = 'nvarchar(50)=\'\''
          }
          if (_fields.has(item.field)) {
            _f = _f + '1'
          }
          _fields.set(item.field, true)
          formParam = formParam + `mchr13k@${_f} ${type},`
        }
      })
    }
    if (config.columns && config.columns.length > 0) {
      config.columns.forEach(item => {
        if (item.field) {
          _columns.push(`${item.field} as ${item.label}`)
        }
      })
      form = `
        declare @dc table (${_columns.join(',')})
        @tableid ='${menu.MenuID}'
      `
    }
    let Ltext = `create proc ${param.innerFunc}
    ( /*${menu.MenuName}*/
    @BID nvarchar(50)='',
    @ID nvarchar(50)='',${formParam}
    @PageIndex nvarchar(50)='',
    @PageSize nvarchar(50)='',
    @OrderCol nvarchar(50)='',
    @OrderType nvarchar(50)='',
    @sEPTMenuNo nvarchar(50)='${menu.MenuNo}',
    @lang nvarchar(50)='',
    @debug nvarchar(50)='',
    @LoginUID nvarchar(50)='',
    @SessionUid nvarchar(50)='',
    @UserID nvarchar(50),
    @ErrorCode nvarchar(50) out,
    @retmsg nvarchar(4000) out
    )
    as
    begin
    declare  @BegindateTest datetime,@EnddateTest datetime
    select  @BegindateTest=getdate()
    set @ErrorCode=''
    set @retmsg=''
    BEGIN TRY
      /*事务操作*/
      BEGIN TRAN
        /*具体业务操作*/
         /*
        select top 10 * from sProcExcep order by id desc
        declare @UserName  nvarchar(50),@FullName nvarchar(50)
        select @UserName=UserName,@FullName=FullName from SUsers where UID=@UserID
        ${form}
        if 1=2
        begin
          set @ErrorCode='E'
          set @retmsg='在此写报错'
          goto GOTO_RETURN
        end
        insert into sNote (remark,createuserid,CreateUser,CreateStaff)
        select '在此写日志',@UserID,@UserName,@FullName
        */
      COMMIT TRAN
      SET NOCOUNT ON
      RETURN
    END TRY
    BEGIN CATCH
      /*错误处理*/
      ROLLBACK TRAN
      DECLARE @ErrorMessage NVARCHAR(4000);
      DECLARE @ErrorSeverity INT;
      DECLARE @ErrorState INT;
      /*把自定义的友好的错误信息提示加上*/
      set @ErrorCode=cast(ERROR_NUMBER() as nvarchar(50))
      SET @retmsg=ERROR_MESSAGE();
      SELECT @ErrorMessage=ERROR_MESSAGE(),
        @ErrorSeverity=ERROR_SEVERITY(),
        @ErrorState=ERROR_STATE();
      RAISERROR(@ErrorMessage, /*-- Message text.*/
        @ErrorSeverity, /*-- Severity.*/
        @ErrorState  /*-- State.*/
        );
    END CATCH
    GOTO_RETURN:
      ROLLBACK TRAN
    END`
    console.log(Ltext)
    Ltext = Ltext.replace(/\n\s{4}/ig, 'mchr13k')
    return Ltext
  }
  /**
   * @description 创建存储过程
   * @return {String}
   */
  static getfunc (param, btn, menu, columns) {
    let form = ''
    let formParam = ''
    console.log(menu)
    console.log(columns)
    if (param.fields && param.fields.length > 0) {
      let _fields = []
      param.fields.forEach(item => {
@@ -511,7 +688,7 @@
      ROLLBACK TRAN
      
    END`
    console.log(Ltext)
    Ltext = Ltext.replace(/\n\s{4}/ig, 'mchr13k')
    return Ltext