king
2024-12-24 2998f413a5e196e99df887787aa4b250cd9f3b78
Merge branch 'positec' into dms
85个文件已修改
2个文件已添加
3990 ■■■■ 已修改文件
public/manifest.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/mkpublic.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.scss 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/sysmessage/icon.jsx 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/sysmessage/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/sysmessage/index.scss 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/sysmessage/msg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkTable/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/options.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/options.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/double-data-card/options.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/editor/braft-editor/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/editor/braft-editor/options.jsx 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/dragsearch/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/formconfig.jsx 153 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/markcomponent/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/options.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/options.jsx 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/debug/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.scss 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/replaceField/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/replaceField/settingform/index.jsx 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/menubar/normal-menubar/menucomponent/options.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/menus/menuform/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/balcony/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/prop-card/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/editor/braft-editor/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/editor/braft-editor/index.scss 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/simple-form/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/step-form/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/tab-form/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/interfaces/interItem/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/resetAttach/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.scss 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/base-table/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.jsx 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/tree/antd-tree/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.scss 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/popupbutton/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/billcodeform/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/callbackcustomscript/index.jsx 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customform/index.jsx 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customscript/index.jsx 203 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 1481 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/transmenu/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/billprint/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mkiframe/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/rolemanage/index.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/manifest.json
@@ -6,5 +6,5 @@
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff",
  "mk_version": "20241106"
  "mk_version": "20241202"
}
src/api/index.js
@@ -206,12 +206,7 @@
   * @description 游客登录
   */
  getTouristMsg (binding_type, appid, openid, memberid, scanId) {
    let _SessionUid = localStorage.getItem('SessionUid')
    if (!_SessionUid) { // 手动清除SessionUid时,实时生成
      _SessionUid = Utils.getuuid()
      localStorage.setItem('SessionUid', _SessionUid)
    }
    let _SessionUid = localStorage.getItem('SessionUid') || ''
    let param = {
      func: 's_visitor_login',
@@ -1296,7 +1291,7 @@
  /**
   * @description sql检验
   */
  sDebug (sql) {
  sDebug (sql, skip = false) {
    let param = {
      func: 's_debug_sql',
      exec_type: window.GLOB.execType || 'y',
@@ -1324,6 +1319,8 @@
    window.mkInfo(`/* sql 验证 */\n${sql.replace(/\n\s{6,20}/ig, '\n')}`)
    if (skip) return
    sql = sql.replace(/\n/ig, ' ')
    param.LText = Utils.formatOptions(sql, param.exec_type)
src/assets/css/main.scss
@@ -167,6 +167,31 @@
  border: 1px solid rgba(0, 0, 0, 0.07);
  background: rgba(0, 0, 0, 0);
}
.ant-calendar-header .ant-calendar-prev-century-btn::before, .ant-calendar-header .ant-calendar-prev-decade-btn::before, .ant-calendar-header .ant-calendar-prev-year-btn::before, .ant-calendar-header .ant-calendar-prev-century-btn::after, .ant-calendar-header .ant-calendar-prev-decade-btn::after, .ant-calendar-header .ant-calendar-prev-year-btn::after {
  border-color: rgba(0, 0, 0, 0.65)!important;
}
.ant-calendar-header .ant-calendar-next-century-btn::before, .ant-calendar-header .ant-calendar-next-decade-btn::before, .ant-calendar-header .ant-calendar-next-year-btn::before, .ant-calendar-header .ant-calendar-next-century-btn::after, .ant-calendar-header .ant-calendar-next-decade-btn::after, .ant-calendar-header .ant-calendar-next-year-btn::after {
  border-color: rgba(0, 0, 0, 0.65)!important;
}
.ant-calendar-header .ant-calendar-next-century-btn:hover::before, .ant-calendar-header .ant-calendar-next-decade-btn:hover::before, .ant-calendar-header .ant-calendar-next-year-btn:hover::before, .ant-calendar-header .ant-calendar-next-century-btn:hover::after, .ant-calendar-header .ant-calendar-next-decade-btn:hover::after, .ant-calendar-header .ant-calendar-next-year-btn:hover::after {
  border-color: rgba(0, 0, 0, 0.85)!important;
}
.ant-calendar-header .ant-calendar-prev-century-btn:hover::before, .ant-calendar-header .ant-calendar-prev-decade-btn:hover::before, .ant-calendar-header .ant-calendar-prev-year-btn:hover::before, .ant-calendar-header .ant-calendar-prev-century-btn:hover::after, .ant-calendar-header .ant-calendar-prev-decade-btn:hover::after, .ant-calendar-header .ant-calendar-prev-year-btn:hover::after {
  border-color: rgba(0, 0, 0, 0.85)!important;
}
.ant-calendar-header .ant-calendar-prev-month-btn::before, .ant-calendar-header .ant-calendar-prev-month-btn::after {
  border-color: rgba(0, 0, 0, 0.65)!important;
}
.ant-calendar-header .ant-calendar-next-month-btn::before, .ant-calendar-header .ant-calendar-next-month-btn::after {
  border-color: rgba(0, 0, 0, 0.65)!important;
}
.ant-calendar-header .ant-calendar-prev-month-btn:hover::before, .ant-calendar-header .ant-calendar-prev-month-btn:hover::after {
  border-color: rgba(0, 0, 0, 0.85)!important;
}
.ant-calendar-header .ant-calendar-next-month-btn:hover::before, .ant-calendar-header .ant-calendar-next-month-btn:hover::after {
  border-color: rgba(0, 0, 0, 0.85)!important;
}
// 重置模态框滚动条
.ant-modal-wrap::-webkit-scrollbar, .ant-drawer-wrapper-body::-webkit-scrollbar {
  width: 7px;
@@ -818,3 +843,12 @@
.mk-hover-underline:hover {
  text-decoration: underline!important;
}
// 隐藏空值时的图标
body .mk-empty-hide .ant-empty, body .mk-empty-hide + .ant-empty {
  min-height: 50px;
  padding-top: 0px;
  margin: 0px;
  .ant-empty-image, .ant-empty-description {
    display: none;
  }
}
src/assets/img/mkpublic.jpg
src/components/header/index.jsx
@@ -11,6 +11,7 @@
import Utils from '@/utils/utils.js'
import avatar from '@/assets/img/avatar.jpg'
import wxicon from '@/assets/img/wx-icon.png'
import mkpublic from '@/assets/img/mkpublic.jpg'
import './index.scss'
const { confirm } = Modal
@@ -27,6 +28,7 @@
    fullName: '',
    logourl: window.GLOB.mainlogo,
    wxVisible: false,
    wxStep: 1,
    loginVisible: false,
    loginLoading: false,
    avatar: Utils.getrealurl(sessionStorage.getItem('avatar')),
@@ -638,7 +640,7 @@
        <Menu.Item key="verup" onClick={this.verup}>
          {dict['page_upd'] || '页面更新'}
        </Menu.Item>
        {window.GLOB.WXNotice ? <Menu.Item key="wxnotice" onClick={() => this.setState({wxVisible: true})}>
        {window.GLOB.WXNotice ? <Menu.Item key="wxnotice" onClick={() => this.setState({wxVisible: true, wxStep: 1})}>
          微信消息
        </Menu.Item> : null}
        {window.GLOB.appVersion ? <Menu.Item key="version" onClick={this.about}>
@@ -823,14 +825,22 @@
          footer={null}
          destroyOnClose
        >
          <div className="wx-sms-wrap">
          {this.state.wxStep !== 2 ? <div className="wx-sms-wrap">
            <img className="mk-img" src={mkpublic} alt=""/>
            <div className="mk-tip">
              <span>微信扫码</span>
              <span>关注公众号</span>
              <span>关注公众号且授权后方可接收消息。</span>
              <span onClick={() => this.setState({wxStep: 2})}>下一步</span>
            </div>
          </div> : <div className="wx-sms-wrap">
            <QrCode card={{qrWidth: 200, color: '#000000'}} value={window.GLOB.baseurl + 'mob/wxnotice.html?userid=' + sessionStorage.getItem('UserID') + '&loginuid=' + sessionStorage.getItem('LoginUID')}/>
            <div className="tip">
              <img src={wxicon} alt=""/>
              <span>微信扫码</span>
              <span>关注公众号</span>
              <span>获取用户授权</span>
            </div>
          </div>
          </div>}
        </Modal>
      </header>
    )
src/components/header/index.scss
@@ -287,6 +287,7 @@
  }
  .wx-sms-wrap {
    text-align: center;
    position: relative;
    .tip {
      margin: 215px 15px 15px;
@@ -305,6 +306,47 @@
        font-weight: bold;
      }
    }
    .mk-img {
      width: 258px;
      height: 258px;
      position: relative;
      top: -15px;
    }
    .mk-tip {
      margin: 0px 15px 15px;
      position: relative;
      top: -20px;
      span {
        font-size: 16px;
        letter-spacing: 2px;
        font-weight: 500;
        color: #333;
      }
      span:nth-child(2) {
        color: #45B449;
        font-weight: bold;
      }
      span:nth-child(3) {
        display: block;
        font-size: 13px;
      }
      span:nth-child(4) {
        display: block;
        position: absolute;
        right: -10px;
        bottom: -25px;
        padding: 0 5px;
        font-size: 14px;
        font-weight: 600;
        cursor: pointer;
        color: rgba(0, 0, 0, 0.65);
        transition: color 0.2s;
      }
      span:nth-child(4):hover {
        color: rgba(0, 0, 0, 0.85);
      }
    }
    .qrcode-box + .tip {
      margin-top: 15px;
    }
src/components/header/sysmessage/icon.jsx
@@ -1,13 +1,14 @@
import React, { Component } from 'react'
import { notification } from 'antd'
import { MessageFilled } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import MKEmitter from '@/utils/events.js'
import url from './msg.png'
class SysIcon extends Component {
  state = {
    notices: []
    notices: null
  }
  componentDidMount () {
@@ -18,15 +19,60 @@
  getMsgList = () => {
    let param = {
      func: 's_get_kei'
      func: 's_get_unread_oa_mail_v1'
    }
    Api.getSystemConfig(param).then(result => {
    Api.genericInterface(param).then(result => {
      if (result.status) {
        let notices = result.data || []
        notices.forEach(item => {
          let time = new Date(item.submitdate).getTime()
          let _val = item.submitdate
          if (!isNaN(time)) {
            time = parseInt(time / 60000)                                     // 时间值
            let now = parseInt(new Date().getTime() / 60000)                  // 当前时间值
            let start = new Date(new Date().toDateString()).getTime() / 60000 // 今天零点时间值
            let split = now - time
            if (split < 0) { // 时间值在当前时间之后
              _val = moment(_val).format('MM月DD日 HH:mm')
            } else if (split < 3) {
              _val = '刚刚'
            } else if (split < 5) {
              _val = '3分钟前'
            } else if (split < 10) {
              _val = '5分钟前'
            } else if (split < 20) {
              _val = '10分钟前'
            } else if (split < 30) {
              _val = '20分钟前'
            } else if (split < 60) {
              _val = '30分钟前'
            } else if (split < 420 || time > start) { // 7小时内或时间值在今天零点后
              _val = parseInt(split / 60) + '小时前'
            } else {                                  // 时间值在今天零点之前
              let _day = parseInt((start - time) / (24 * 60)) + 1
              if (_day === 1) {
                _val = '昨天'
              } else if (_day <= 30) {
                _val = _day + '天前'
              } else {
                _val = moment(_val).format('MM月DD日 HH:mm')
              }
            }
          }
          item.time = _val
        })
        this.setState({ notices })
        MKEmitter.emit('sysMessageChange', notices)
        MKEmitter.emit('sysMessageChange', notices.slice(0, 5))
        if (notices.length > 0) {
          setTimeout(() => {
            MKEmitter.emit('sysMessageOpen')
          }, 50)
        }
        setTimeout(() => {
          this.getMsgList()
@@ -42,14 +88,40 @@
  }
  open = () => {
    const { notices } = this.state
    if (notices.length === 0) {
      this.toMenu()
    } else {
    MKEmitter.emit('sysMessageOpen')
    }
  }
  toMenu = () => {
    let menu = {
      MenuID: '1731250110643ivgpv9gdgiif5lggh4e',
      MenuName: '内部邮箱',
      type: 'CustomPage',
      param: {$BID: ''}
    }
    if (window.GLOB.mkThdMenus.has(menu.MenuID)) {
      menu.MenuName = window.GLOB.mkThdMenus.get(menu.MenuID).MenuName
    }
    MKEmitter.emit('modifyTabs', menu)
  }
  render() {
    const { notices } = this.state
    if (!notices) return null
    return (
      <MessageFilled className="mk-msg-icon" data-title={notices.length ? notices.length : ''} onClick={this.open} />
      <span className="mk-msg-icon" onClick={this.open}>
        <img src={url} alt=""/>
        <span>{notices.length ? notices.length : ''}</span>
      </span>
    )
  }
}
src/components/header/sysmessage/index.jsx
@@ -1,5 +1,5 @@
import React, { Component } from 'react'
import { CloseOutlined } from '@ant-design/icons'
import { CloseOutlined, SoundOutlined } from '@ant-design/icons'
import MKEmitter from '@/utils/events.js'
@@ -26,6 +26,10 @@
  sysMessageChange = (notices) => {
    this.setState({ notices })
    if (notices.length === 0) {
      this.setState({ visible: false })
    }
  }
  sysMessageOpen = () => {
@@ -36,20 +40,39 @@
    this.setState({ visible: false })
  }
  toMenu = () => {
    let menu = {
      MenuID: '1731250110643ivgpv9gdgiif5lggh4e',
      MenuName: '内部邮箱',
      type: 'CustomPage',
      param: {$BID: ''}
    }
    if (window.GLOB.mkThdMenus.has(menu.MenuID)) {
      menu.MenuName = window.GLOB.mkThdMenus.get(menu.MenuID).MenuName
    }
    MKEmitter.emit('modifyTabs', menu)
    this.setState({ visible: false })
  }
  render() {
    const { visible, notices } = this.state
    return (
      <div className={'mk-msg-wrap' + (visible ? ' visible' : '')}>
        <div className="title">
          系统消息
          <SoundOutlined />
          <CloseOutlined onClick={this.close}/>
        </div>
        <div className="msg-list">{notices.map((item, index) => {
          return <div className="msg-item" key={index}>
            {item.remark}
          return <div className={'msg-item ' + (item.urgent_type === 'Y' ? 'red' : '')} key={index} onClick={this.toMenu}>
            <span>{item.createstaff}</span><span className="time">{item.time}</span>
            <span>{item.title}</span>
          </div>
        })}</div>
        <span className="jump" onClick={this.toMenu}>详情&nbsp;&nbsp;&gt;</span>
      </div>
    )
  }
src/components/header/sysmessage/index.scss
@@ -1,48 +1,52 @@
.mk-msg-icon {
  display: inline-block;
  position: relative;
  font-size: 16px;
  margin-top: 17px;
  margin-top: 12px;
  margin-right: 20px;
  margin-left: 0px;
  color: #1CD66C;
  cursor: pointer;
}
.mk-msg-icon[data-title] {
  position: relative;
  &::before {
    content: " ";
    position: absolute;
    top: 6px;
    left: 2px;
    z-index: -1;
    width: 12px;
    height: 3px;
    display: block;
    background: #fff;
  img {
    width: 22px;
    height: 22px;
  }
  &::after {
  span {
    position: absolute;
    top: -10px;
    left: 15px;
    top: -6px;
    left: 19px;
    color: #f5222d;
    font-size: 12px;
    line-height: 16px;
    white-space: nowrap;
    font-weight: 600;
    content: attr(data-title);
  }
}
// .mk-msg-icon[data-title] {
//   position: relative;
//   &::after {
//     position: absolute;
//     top: -10px;
//     left: 15px;
//     color: #f5222d;
//     font-size: 12px;
//     line-height: 16px;
//     white-space: nowrap;
//     font-weight: 600;
//     content: attr(data-title);
//   }
// }
.mk-msg-wrap {
  position: fixed;
  width: 200px;
  height: 400px;
  top: 92px;
  right: 15px;
  width: 300px;
  top: 50px;
  right: 120px;
  z-index: -1;
  opacity: 0;
  padding: 10px;
  padding: 7px 10px 24px;
  font-size: 13px;
  background-color: #fff;
  background-color: var(--mk-sys-color1);
  background-clip: padding-box;
  color: rgba(0, 0, 0, 0.85);
  border: 0;
@@ -53,28 +57,62 @@
  transition: all 0.2s;
  .title {
    text-align: center;
    position: relative;
    text-align: left;
    font-size: 14px;
    .anticon-close {
      position: absolute;
      right: 10px;
      color: rgba(0, 0, 0, 0.45);
      right: 5px;
      top: 1px;
      cursor: pointer;
      transition: color 0.2s;
    }
    .anticon-close:hover {
      color: rgba(0, 0, 0, 0.85);
    }
  }
  .msg-list {
    .msg-item {
      height: 80px;
      background: rgba(0, 0, 0, 0.05);
      position: relative;
      height: 55px;
      background: #ffffff;
      margin: 10px 0px;
      padding: 5px;
      border-radius: 2px;
      padding: 8px;
      border-radius: 4px;
      font-size: 14px;
      cursor: pointer;
      span {
        display: block;
        overflow: hidden;
        word-break: break-word;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
  }
    .msg-item:first-child {
      margin-top: 7px;
    }
    .msg-item.red {
      color: #C32539;
    }
    .time {
      position: absolute;
      top: 5px;
      right: 8px;
      font-size: 13px;
    }
  }
  .jump {
    position: absolute;
    right: 15px;
    bottom: 7px;
    font-size: 14px;
    cursor: pointer;
    color: #1890ff;
    transition: color 0.2s;
  }
  .jump:hover {
    color: #ffffff;
  }
}
.mk-msg-wrap.visible {
  z-index: 3000;
src/components/header/sysmessage/msg.png
src/components/normalform/modalform/mkTable/index.jsx
@@ -220,21 +220,8 @@
  changeMenu = (record) => {
    let MenuId = record.menu
    if (MenuId === 'IM') {
      if (!sessionStorage.getItem('instantMessage')) return
      let param = {
        MenuID: sessionStorage.getItem('instantMessage'),
        copyMenuId: '',
        type: 'view'
      }
      param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
      MKEmitter.emit('changeEditMenu', {routerUrl: '/imdesign/' + param})
    } else {
      MKEmitter.emit('changeEditMenu', { ...record, MenuID: MenuId})
    }
  }
  isEditing = record => record.uuid === this.state.editingKey
src/index.js
@@ -12,14 +12,23 @@
import '@/assets/css/viewstyle.scss'
if (!localStorage.getItem('SessionUid')) {
  localStorage.setItem('SessionUid', (() => {
  let sid = (() => {
    let uuid = []
    let _options = '0123456789abcdefghigklmnopqrstuv'
    for (let i = 0; i < 32; i++) {
      uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
    }
    return uuid.join('')
  })())
  })()
  if (/_mk_sid=[0-9a-z]{32}/.test(document.cookie)) {
    sid = document.cookie.match(/_mk_sid=[0-9a-z]{32}/)[0].split('=')[1]
  } else {
    document.cookie = '_mk_sid=' + sid
  }
  localStorage.setItem('SessionUid', sid)
}
sessionStorage.setItem('UserID', localStorage.getItem('UserID') || '')
@@ -365,12 +374,16 @@
    }
    if (config.systemRun === 'backend') {
      if (sessionStorage.getItem('systemRun') === 'front') {
        GLOB.debugger = true
      } else {
      GLOB.debugger = false
      Object.defineProperty(window, 'backend', {
        writable: false,
        value: true
      })
    }
    }
    if (config.debugger === 'forbid') {
      sessionStorage.removeItem('breakpoint')
      GLOB.debugger = false
src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -241,7 +241,7 @@
    _style_ = {float: 'right'}
  }
  let mark = ['text', 'number', 'slider', 'sequence', 'formula'].includes(card.eleType)
  let mark = ['text', 'number', 'slider', 'sequence', 'formula', 'icon'].includes(card.eleType)
  if (parent.setting && parent.setting.cardRole === 'header') {
    mark = false
  } else if (card.eleType === 'formula' && card.eval === 'func') {
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -124,6 +124,9 @@
    } else {
      appMenus = []
    }
    // if (appType === 'mob') {
    //   appMenus.push({value: 'sign', text: '签名(系统页)'})
    // }
    appMenus.push({value: 'goback', text: '返回(上一页)'})
  }
src/menu/components/card/cardcomponent/index.jsx
@@ -417,42 +417,14 @@
    const { card, appType } = this.state
    if (card.setting.click === 'menu' && card.setting.menu) {
      if (['IM'].includes(card.setting.menu)) {
        if (!sessionStorage.getItem('instantMessage')) return
        let param = {
          MenuID: sessionStorage.getItem('instantMessage'),
          copyMenuId: '',
          type: 'view'
        }
        param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
        MKEmitter.emit('changeEditMenu', {routerUrl: '/imdesign/' + param})
      } else {
        MKEmitter.emit('changeEditMenu', {MenuID: card.setting.menu})
      }
    } else if (card.setting.click === 'menus' && card.menus && card.menus.length > 0 && cards.subtype === 'datacard' && appType) {
      this.setState({visible: true})
    }
  }
  changeMenu = (MenuId) => {
    if (MenuId === 'IM') {
      if (!sessionStorage.getItem('instantMessage')) return
      let param = {
        MenuID: sessionStorage.getItem('instantMessage'),
        copyMenuId: '',
        type: 'view'
      }
      param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
      MKEmitter.emit('changeEditMenu', {routerUrl: '/imdesign/' + param})
    } else {
      MKEmitter.emit('changeEditMenu', {MenuID: MenuId})
    }
  }
  render() {
src/menu/components/card/cardcomponent/options.jsx
@@ -18,11 +18,11 @@
    } else {
      menulist = []
    }
    if (appType === 'mob' && (subtype === 'datacard' || subtype === 'propcard') && cardType !== 'extendCard') { // 数据卡可打开即时通信
      menulist.push({
        value: 'IM', label: '即时通信(系统页)'
      })
    }
    // if (appType === 'mob' && (subtype === 'datacard' || subtype === 'propcard') && cardType !== 'extendCard') { // 数据卡可打开即时通信
    //   menulist.push({
    //     value: 'IM', label: '即时通信(系统页)'
    //   })
    // }
  } else {
    menulist = sessionStorage.getItem('fstMenuList')
    if (menulist) {
src/menu/components/card/data-card/options.jsx
@@ -456,6 +456,22 @@
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
      controlFields: [
        {field: 'empSign', values: ['show']},
      ]
    },
    {
      type: 'radio',
      field: 'empSign',
      label: '空值图标',
      initval: wrap.empSign || 'show',
      tooltip: '当查询数据为空时,是否显示空值提示图标。',
      required: false,
      options: [
        {value: 'show', label: '显示'},
        {value: 'hidden', label: '隐藏'},
      ],
      forbid: subtype === 'propcard'
    },
    {
      type: 'select',
src/menu/components/card/double-data-card/options.jsx
@@ -173,6 +173,21 @@
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
      controlFields: [
        {field: 'empSign', values: ['show']},
      ]
    },
    {
      type: 'radio',
      field: 'empSign',
      label: '空值图标',
      initval: wrap.empSign || 'show',
      tooltip: '当查询数据为空时,是否显示空值提示图标。',
      required: false,
      options: [
        {value: 'show', label: '显示'},
        {value: 'hidden', label: '隐藏'},
      ]
    },
    {
      type: 'select',
src/menu/components/editor/braft-editor/index.jsx
@@ -149,9 +149,19 @@
    const { card } = this.state
    if (res.tbStyle) {
      if (res.tbStyle.includes('no-border') && (res.tbStyle.includes('bold-border') || res.tbStyle.includes('deep-border'))) {
        res.tbStyle = res.tbStyle.filter(item => item !== 'no-border')
      }
      if (res.splitLine === 'true') {
        res.tbStyle.push('deep-split')
      }
      res.tbStyle = res.tbStyle.join(' ')
    }
    delete res.splitLine
    let _card = {...card, wrap: res}
    if (res.datatype === 'public') {
src/menu/components/editor/braft-editor/options.jsx
@@ -31,6 +31,13 @@
    roleList = []
  }
  let tbStyle = wrap.tbStyle ? wrap.tbStyle.split(' ') : []
  let splitLine = 'false'
  if (tbStyle.includes('deep-split')) {
    tbStyle = tbStyle.filter(n => n !== 'deep-split')
    splitLine = 'true'
  }
  const cardWrapForm = [
    {
      type: 'text',
@@ -134,26 +141,29 @@
      type: 'checkbox',
      field: 'tbStyle',
      label: '表格样式',
      initval: wrap.tbStyle ? wrap.tbStyle.split(' ') : [],
      initval: tbStyle,
      tooltip: '富文本中表格的样式,注:选择“边框加粗”或“边框颜色加深”时“无边框”无效。',
      required: false,
      options: [
        {value: 'th-light', label: '表头透明'},
        {value: 'no-border', label: '无边框'},
        {value: 'tb-flex', label: '列等宽'},
      ]
        {value: 'no-border', label: '无边框'},
        {value: 'bold-border', label: '边框加粗'},
        {value: 'deep-border', label: '边框颜色加深'},
      ],
      span: 24
    },
    // {
    //   type: 'radio',
    //   field: 'firstTr',
    //   label: '表格首行',
    //   initval: wrap.firstTr || 'deep',
    //   tooltip: '富文本中table的首行背景颜色。',
    //   required: false,
    //   options: [
    //     {value: 'deep', label: '深色'},
    //     {value: 'light', label: '浅色'},
    //   ]
    // },
    {
      type: 'radio',
      field: 'splitLine',
      label: '分割线加深',
      initval: splitLine,
      required: false,
      options: [
        {value: 'false', label: '否'},
        {value: 'true', label: '是'},
      ],
    },
    {
      type: 'radio',
      field: 'permission',
src/menu/components/search/main-search/dragsearch/card.jsx
@@ -152,7 +152,7 @@
            wrapperCol={{style: {width: (100 - labelwidth) + '%'}}}
            label={card.labelShow !== 'false' ? card.label : ''}
            required={card.required === 'true'}
            help={card.field + (card.datefield ? ', ' + card.datefield : '') + (card.advanced === 'true' ? '(高级搜索)' : '')}
            help={`${card.field || ''} ${card.datefield ? ', ' + card.datefield : ''} ${card.Hide === 'true' ? '(隐藏)' : ''} ${card.advanced === 'true' ? '(高级搜索)' : ''}`}
          >
            {formItem}
          </Form.Item>
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -15,16 +15,16 @@
const CodeMirror = asyncComponent(() => import('@/templates/zshare/codemirror'))
const MKTable = asyncComponent(() => import('@/components/normalform/modalform/mkTable'))
const acTyOptions = {
  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'hoverTitle', 'hidden', 'preButton'],
  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hoverTitle', 'hidden', 'preButton'],
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hoverTitle', 'hidden', 'preButton'],
  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'hoverTitle', 'hidden', 'preButton', 'extBtn', 'reload'],
  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hoverTitle', 'hidden', 'preButton', 'reload'],
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hoverTitle', 'hidden', 'preButton', 'reload'],
  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'hover', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden', 'refreshTab'],
  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'hover', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden', 'refreshTab'],
  popview: ['label', 'Ot', 'OpenType', 'show', 'hover', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'maskStyle', 'closeButton', 'hidden'],
  tab: ['label', 'Ot', 'OpenType', 'show', 'hover', 'icon', 'class', 'color', 'linkmenu', 'width', 'hidden', 'openTab'],
  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
  funcbutton: ['label', 'OpenType', 'funcType', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
  form: ['label', 'OpenType', 'formType', 'intertype', 'Ot', 'execSuccess', 'execError', 'syncComponent', 'width', 'openmenu', 'refreshTab', 'title', 'hidden']
  form: ['label', 'OpenType', 'formType', 'intertype', 'Ot', 'execSuccess', 'execError', 'syncComponent', 'width', 'openmenu', 'refreshTab', 'title', 'hidden', 'reload']
}
class ActionForm extends Component {
@@ -248,9 +248,12 @@
      } else {
        reOptions.sqlType = this.state.insertUpdateOptions
      }
      // if (this.record.execSuccess === 'goback') {
        shows.push('reload')
      // }
      if (openType === 'pop') {
        shows.push('extBtn')
        if (this.record.extBtn === 'true') {
          shows.push('extLabel', 'extStyle', 'confLabel', 'confStyle', 'extValue')
        }
      }
    } else if (openType === 'form') {
      let intertype = this.record.intertype
@@ -302,9 +305,6 @@
        shows.push('sql', 'sqlType', 'database')
      }
      if (this.record.execSuccess === 'goback') {
        shows.push('reload')
      }
      if (['grid'].includes(this.record.execSuccess) || ['grid'].includes(this.record.execError)) {
        shows.push('resetPageIndex')
      }
@@ -926,6 +926,11 @@
              }]
            }
          }
        } else if (item.key === 'extValue') {
          rules.push(
            { pattern: /^[0-9a-zA-Z_]*$/, message: '请使用字母、数字以及_' },
            { max: 50, message: '最多50个字符。' }
          )
        } else {
          rules.push({ max: formRule.input.max, message: formRule.input.message })
        }
@@ -1235,6 +1240,9 @@
          if (values.outerBlacklist) {
            values.outerBlacklist = values.outerBlacklist.replace(/\s/ig, '')
          }
          if (values.controlVal) {
            values.controlVal = values.controlVal.replace(/\t+|\v+|\s+/g, '')
          }
          if (values.openmenu && Array.isArray(values.openmenu) && values.openmenu.length > 0) {
            let list = null
src/menu/components/share/actioncomponent/formconfig.jsx
@@ -1,5 +1,5 @@
import React from 'react'
import { btnClasses } from '@/utils/option.js'
import { btnClasses, modalClasses } from '@/utils/option.js'
/**
 * @description 获取按钮表单配置信息
@@ -187,6 +187,9 @@
    } else {
      appMenus = []
    }
    // if (appType === 'mob') {
    //   appMenus.push({value: 'sign', text: '签名(系统页)'})
    // }
    appMenus.push({value: 'goback', text: '返回(上一页)'})
  } else {
    menulist = sessionStorage.getItem('fstMenuList')
@@ -217,6 +220,7 @@
      { value: 'expPdf', text: '导出PDF' },
      { value: 'shareLink', text: '分享链接' },
      { value: 'openLocation', text: '打开地图'},
      { value: 'wxPublicAuth', text: '微信公众号授权'},
      { value: 'logout', text: '退出' },
      { value: 'goBack', text: '返回' },
    ]
@@ -838,6 +842,10 @@
        value: 'never',
        text: '不刷新'
      }, {
        value: 'line',
        text: '刷新行',
        $disabled: !['table_normaltable', 'table_editable', 'table_basetable', 'card_datacard', 'card_dualdatacard'].includes(alltype)
      }, {
        value: 'grid',
        text: '刷新当前组件'
      }, {
@@ -1409,21 +1417,6 @@
      initVal: card.reason || '',
      required: false
    },
    // {
    //   type: 'radio',
    //   key: 'formCache',
    //   label: '表单缓存',
    //   initVal: card.formCache || 'false',
    //   tooltip: '主要用于数据修改后,更新相关表单的选项,清空缓存后表单再次打开时数据会重新加载。',
    //   required: false,
    //   options: [{
    //     value: 'false',
    //     text: '不清空'
    //   }, {
    //     value: 'clear',
    //     text: '清空'
    //   }]
    // },
    {
      type: 'radio',
      key: 'hidden',
@@ -1463,6 +1456,64 @@
        {value: 'false', text: '禁用'},
      ],
      forbid: viewType === 'popview'
    },
    {
      type: 'radio',
      key: 'extBtn',
      label: '扩展按钮',
      initVal: card.extBtn || 'false',
      tooltip: '点击扩展按钮时,变量 mk_submit_type 将被赋值。',
      required: false,
      options: [
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
      forbid: appType === 'mob'
    },
    {
      type: 'text',
      key: 'extValue',
      label: '扩展值',
      initVal: card.extValue || '',
      required: true,
      readonly: false,
      forbid: appType === 'mob'
    },
    {
      type: 'text',
      key: 'extLabel',
      label: '扩展名称',
      initVal: card.extLabel || '',
      required: true,
      readonly: false,
      forbid: appType === 'mob'
    },
    {
      type: 'select',
      key: 'extStyle',
      label: '扩展样式',
      initVal: card.extStyle || '',
      required: false,
      options: modalClasses,
      forbid: appType === 'mob'
    },
    {
      type: 'text',
      key: 'confLabel',
      label: '确定名称',
      initVal: card.confLabel || '',
      required: false,
      readonly: false,
      forbid: appType === 'mob'
    },
    {
      type: 'select',
      key: 'confStyle',
      label: '确定样式',
      initVal: card.confStyle || '',
      required: false,
      options: modalClasses,
      forbid: appType === 'mob'
    },
    {
      type: 'splitLine',
@@ -2268,6 +2319,9 @@
        value: 'never',
        text: '不刷新'
      }, {
        value: 'line',
        text: '刷新行'
      }, {
        value: 'grid',
        text: '刷新当前组件'
      }, {
@@ -2669,21 +2723,6 @@
      initVal: card.reason || '',
      required: false
    },
    // {
    //   type: 'radio',
    //   key: 'formCache',
    //   label: '表单缓存',
    //   initVal: card.formCache || 'false',
    //   tooltip: '主要用于数据修改后,更新相关表单的选项,清空缓存后表单再次打开时数据会重新加载。',
    //   required: false,
    //   options: [{
    //     value: 'false',
    //     text: '不清空'
    //   }, {
    //     value: 'clear',
    //     text: '清空'
    //   }]
    // },
    {
      type: 'radio',
      key: 'hidden',
@@ -2726,6 +2765,58 @@
    },
    {
      type: 'radio',
      key: 'extBtn',
      label: '扩展按钮',
      initVal: card.extBtn || 'false',
      tooltip: '点击扩展按钮时,变量 mk_submit_type 将被赋值。',
      required: false,
      options: [
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
    },
    {
      type: 'text',
      key: 'extValue',
      label: '扩展值',
      initVal: card.extValue || '',
      required: true,
      readonly: false
    },
    {
      type: 'text',
      key: 'extLabel',
      label: '扩展名称',
      initVal: card.extLabel || '',
      required: true,
      readonly: false
    },
    {
      type: 'select',
      key: 'extStyle',
      label: '扩展样式',
      initVal: card.extStyle || '',
      required: false,
      options: modalClasses
    },
    {
      type: 'text',
      key: 'confLabel',
      label: '确定名称',
      initVal: card.confLabel || '',
      required: false,
      readonly: false
    },
    {
      type: 'select',
      key: 'confStyle',
      label: '确定样式',
      initVal: card.confStyle || '',
      required: false,
      options: modalClasses
    },
    {
      type: 'radio',
      key: 'execType',
      label: '请求方式',
      initVal: card.execType || 'multi',
src/menu/components/share/markcomponent/index.jsx
@@ -112,7 +112,7 @@
        options: [],
        render: text => {
          let sign = {
            'font': '文字',
            'font': '字体颜色',
            'background': '背景',
            'underline': '下划线',
            'line-through': '中划线',
@@ -267,7 +267,7 @@
    let signs = [
      {
        value: 'font',
        label: '文字'
        label: '字体颜色'
      },
      {
        value: 'background',
@@ -324,6 +324,11 @@
      signs.pop()
      signs.pop()
      signs.pop()
    } else if (type === 'icon') {
      signs = [{
        value: 'font',
        label: '字体颜色'
      }]
    } else if (type === 'slider') {
      markColumns = markColumns.filter(col => {
        col.width = '20%'
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -673,6 +673,21 @@
    },
    {
      type: 'radio',
      key: 'showValue',
      label: '显示值',
      initVal: card.showValue || 'label',
      tooltip: '单元格不可编辑时显示的信息。',
      required: false,
      options: [{
        value: 'value',
        text: '值·字段'
      }, {
        value: 'label',
        text: '文本·字段'
      }]
    },
    {
      type: 'radio',
      key: 'dropdown',
      label: '下拉宽度',
      initVal: card.dropdown || 'flex',
src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -83,7 +83,7 @@
        } else if (this.record.editType === 'popSelect') {
          _options.push('required', 'enter', 'linkSubField', 'columns', 'dataSource', 'primaryKey', 'order', 'showField', 'controlField', 'searchKey', 'popWidth', 'laypage', 'cache', 'onload')
        } else if (this.record.editType === 'select') {
          _options.push('required', 'enter', 'resourceType', 'linkSubField', 'dropdown')
          _options.push('required', 'enter', 'resourceType', 'linkSubField', 'dropdown', 'showValue')
          if (this.record.resourceType === '0') {
            _options.push('options')
src/menu/components/table/edit-table/options.jsx
@@ -228,6 +228,21 @@
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
      controlFields: [
        {field: 'empSign', values: ['show']},
      ]
    },
    {
      type: 'radio',
      field: 'empSign',
      label: '空值图标',
      initval: wrap.empSign || 'show',
      tooltip: '当查询数据为空时,是否显示空值提示图标。',
      required: false,
      options: [
        {value: 'show', label: '显示'},
        {value: 'hidden', label: '隐藏'},
      ],
    },
    {
      type: 'select',
src/menu/components/table/normal-table/options.jsx
@@ -306,6 +306,21 @@
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
      controlFields: [
        {field: 'empSign', values: ['show']},
      ]
    },
    {
      type: 'radio',
      field: 'empSign',
      label: '空值图标',
      initval: wrap.empSign || 'show',
      tooltip: '当查询数据为空时,是否显示空值提示图标。',
      required: false,
      options: [
        {value: 'show', label: '显示'},
        {value: 'hidden', label: '隐藏'},
      ],
    },
    {
      type: 'radio',
@@ -374,6 +389,67 @@
      forbid: !!appType || isprint
    },
    {
      type: 'radio',
      field: 'tree',
      label: '结构树',
      initval: wrap.tree || 'false',
      tooltip: '使用结构树时,显示列首列请使用文本类型。',
      required: false,
      options: [
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      controlFields: [
        {field: 'valueField', values: ['true']},
        {field: 'parentField', values: ['true']},
        {field: 'mark', values: ['true']},
        {field: 'defOpen', values: ['true']},
      ],
      forbid: appType === 'mob' || isprint
    },
    {
      type: 'select',
      field: 'valueField',
      label: '值字段',
      initval: wrap.valueField || '',
      tooltip: '数据值字段,结构树中节点ID值,与上级字段配合组织数据的上下级关系。',
      required: true,
      options: columns,
      forbid: appType === 'mob' || isprint
    },
    {
      type: 'select',
      field: 'parentField',
      label: '上级字段',
      initval: wrap.parentField || '',
      tooltip: '上级字段,用于组织数据的上下级关系。',
      required: true,
      options: columns,
      forbid: appType === 'mob' || isprint
    },
    {
      type: 'text',
      field: 'mark',
      label: '顶级标识',
      initval: wrap.mark || '',
      tooltip: '上级字段值与顶级标识相同时,视为顶级节点。',
      required: false,
      forbid: appType === 'mob' || isprint
    },
    {
      type: 'radio',
      field: 'defOpen',
      label: '默认展开',
      initval: wrap.defOpen || '',
      required: false,
      options: [
        {value: '', label: '无'},
        {value: 'topline', label: '首行'},
        {value: 'all', label: '全部'},
      ],
      forbid: appType === 'mob' || isprint
    },
    {
      type: 'multiselect',
      field: 'blacklist',
      label: '黑名单',
src/menu/datasource/verifycard/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Tabs, Popconfirm, notification, Modal, Typography, Spin, message, Button, Input } from 'antd'
import { Form, Tabs, Popconfirm, notification, Modal, Typography, Spin, message, Button, Input, Switch } from 'antd'
import { StopOutlined, CheckCircleOutlined, TableOutlined, EditOutlined, SwapOutlined, DeleteOutlined, CopyOutlined, BorderOutlined, SnippetsOutlined } from '@ant-design/icons'
import moment from 'moment'
@@ -40,6 +40,7 @@
    subColumns: [],
    activeKey: 'setting',
    loading: false,
    skip: false,
    colLoading: false,
    searchKey: '',
    usefulfields: '',
@@ -832,7 +833,7 @@
  }
  triggerConfirm = () => {
    const { script, scriptValue, scripts } = this.state
    const { script, scriptValue, scripts, skip } = this.state
    let _scripts = fromJS(scripts).toJS()
    if (!scriptValue) {
@@ -865,9 +866,13 @@
      _scripts.push(_script)
    }
    if (skip) {
      this.setState({scripts: _scripts, script: null, scriptValue: '', editLineId})
    } else {
    this.setState({loading: true, editLineId})
    this.sqlverify(() => {this.setState({scripts: _scripts, script: null, scriptValue: '', loading: false})}, () => {this.setState({loading: false})}, 'script', _scripts)
    }
  }
  updatefields = (columns) => {
@@ -1228,7 +1233,7 @@
  render() {
    const { config } = this.props
    const { columns, subColumns, median, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches, defaultsql, visible, pvisible, reload, script, scriptValue, searchKey, editLineId } = this.state
    const { columns, subColumns, median, skip, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches, defaultsql, visible, pvisible, reload, script, scriptValue, searchKey, editLineId } = this.state
    return (
      <div className="model-data-source-wrap">
@@ -1313,7 +1318,7 @@
                })
                return
              }
              this.setState({visible: true, script: null, scriptValue: '', editLineId: ''})
              this.setState({visible: true, skip: false, script: null, scriptValue: '', editLineId: ''})
            }}/> : null}
            <CustomScriptsForm
              type={config.type}
@@ -1321,7 +1326,6 @@
              setting={setting}
              searches={searches}
              defaultsql={defaultsql}
              customScripts={scripts}
              systemScripts={this.state.systemScripts}
              scriptsChange={this.scriptsChange}
              scriptSubmit={this.scriptSubmit}
@@ -1405,6 +1409,10 @@
            <Button onClick={() => {this.setState({script: null, scriptValue: ''})}} style={{marginBottom: 15, marginLeft: 10}}>
              取消
            </Button>
            <span style={{paddingLeft: '20px', fontSize: '12px'}}>
              强制保存:
              <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
            </span>
          </div>
          <CodeMirror value={scriptValue} onChange={(val) => {this.setState({scriptValue: val})}}></CodeMirror>
        </Modal>
src/menu/debug/index.jsx
@@ -637,9 +637,12 @@
    if (!_prev) return _back
    let tbs = []
    _prev.replace(/\n|\r/g, ' ').split(/\sdeclare\s/ig).forEach(line => {
      if (!/^\s*(@|#)[a-zA-Z0-9_]+\s+table\s+\(/ig.test(line)) return
      let tb = line.match(/(@|#)[a-zA-Z0-9_]+\s+table\s+\(.+(\)|date|datetime)\s*\)/ig)
    _prev.replace(/\/\*[^/*]+\*\//g, '').replace(/\n|\r/g, ' ').split(/\sdeclare\s+|\screate\s+table\s+/ig).forEach(line => {
      if (/^\s*(@|#)[a-zA-Z0-9_]+\s+table\s+\(/ig.test(line)) {
        line = line.replace(/\s+table\s+\(/, '(')
      }
      if (!/^\s*(@|#)[a-zA-Z0-9_]+\s*\(/ig.test(line)) return
      let tb = line.match(/(@|#)[a-zA-Z0-9_]+\s*\(.+(\)|date|datetime)\s*\)/ig)
      if (tb && tb.length === 1) {
        tbs.push(tb[0])
@@ -651,7 +654,7 @@
      if (!tbName) return
      let content = tb.replace(/(@|#)[a-zA-Z0-9_]+\s+table\s+\(\s*/, '').replace(/\s*\)$/, '')
      let content = tb.replace(/(@|#)[a-zA-Z0-9_]+\s*\(\s*/, '').replace(/\s*\)$/, '')
      content = content.replace(/decimal\(\s*\d+\s*,\s*\d+\s*\)/ig, 'decimal')
      let keys = []
@@ -754,7 +757,7 @@
    })
  
    // 需要声明的变量集
    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 _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', 'mk_submit_type']
  
    // 主键字段
    let primaryKey = setting.primaryKey || 'id'
@@ -935,7 +938,7 @@
    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}
    _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),@mk_submit_type nvarchar(50)${_declarefields}
      `
    let userName = 'User_Name'
@@ -953,7 +956,7 @@
    // 初始化凭证及用户信息字段
    _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=''
        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}', @mk_submit_type='', @BillCode='', @ModularDetailCode=''
        `
  
    // 表单变量赋值
src/menu/modalconfig/index.jsx
@@ -431,14 +431,24 @@
                  </div>
                </div>
                <div className="ant-modal-footer">
                  <div>
                  {btn.extBtn === 'true' ? <div>
                    <button type="button" className="ant-btn">
                      <span>取消</span>
                    </button>
                    <button type="button" className={'ant-btn extend-btn ' + (btn.extStyle || '')}>
                      <span>{btn.extLabel}</span>
                    </button>
                    <button type="button" className={'ant-btn confirm-btn ' + (btn.confStyle || '')}>
                      <span>{btn.confLabel || '确定'}</span>
                    </button>
                  </div> : <div>
                    <button type="button" className="ant-btn">
                      <span>取消</span>
                    </button>
                    <button type="button" className="ant-btn ant-btn-primary">
                      <span>确定</span>
                    </button>
                  </div>
                  </div>}
                  <div className="action-mask"></div>
                </div>
              </div>
src/menu/modalconfig/index.scss
@@ -152,7 +152,79 @@
        .ant-modal-footer {
          position: relative;
          button {
            opacity: 0.3;
            opacity: 0.5;
          }
          .extend-btn {
            color: var(--mk-sys-color)!important;
            border-color: var(--mk-sys-color)!important;
            background-color: #ffffff!important;
          }
          .confirm-btn {
            background-color: var(--mk-sys-color)!important;
            border-color: var(--mk-sys-color)!important;
            color: #ffffff!important;
          }
          .extend-btn.primary, .confirm-btn.primary {
            background-color: #1890ff!important;
            border-color: #1890ff!important;
            color: #ffffff!important;
          }
          .extend-btn.yellow, .confirm-btn.yellow {
            background-color: #fadb14!important;
            border-color: #fadb14!important;
            color: #ffffff!important;
          }
          .extend-btn.orange, .confirm-btn.orange {
            background-color: #fa8c16!important;
            border-color: #fa8c16!important;
            color: #ffffff!important;
          }
          .extend-btn.danger, .confirm-btn.danger {
            background-color: #f5222d!important;
            border-color: #f5222d!important;
            color: #ffffff!important;
          }
          .extend-btn.green, .confirm-btn.green {
            background-color: #52c41a!important;
            border-color: #52c41a!important;
            color: #ffffff!important;
          }
          .extend-btn.purple, .confirm-btn.purple {
            background-color: #722ed1!important;
            border-color: #722ed1!important;
            color: #ffffff!important;
          }
          .extend-btn.border-primary, .confirm-btn.border-primary {
            color:  #1890ff!important;
            border-color:  #1890ff!important;
            background-color: #ffffff!important;
          }
          .extend-btn.border-yellow, .confirm-btn.border-yellow {
            color:  #fadb14!important;
            border-color:  #fadb14!important;
            background-color: #ffffff!important;
          }
          .extend-btn.border-orange, .confirm-btn.border-orange {
            color:  #fa8c16!important;
            border-color:  #fa8c16!important;
            background-color: #ffffff!important;
          }
          .extend-btn.border-danger, .confirm-btn.border-danger {
            color:  #f5222d!important;
            border-color:  #f5222d!important;
            background-color: #ffffff!important;
          }
          .extend-btn.border-green, .confirm-btn.border-green {
            color:  #52c41a!important;
            border-color:  #52c41a!important;
            background-color: #ffffff!important;
          }
          .extend-btn.border-purple, .confirm-btn.border-purple {
            color:  #722ed1!important;
            border-color:  #722ed1!important;
            background-color: #ffffff!important;
          }
        }
        .action-mask {
src/menu/replaceField/index.jsx
@@ -89,9 +89,9 @@
      if (res.resource === 'custom') {
        if (res.reType === 'name') {
          let map = {[res.label.toLowerCase()]: {
            FieldDec: res.label,
            FieldName: res.field,
          let map = {[res.field.toLowerCase()]: {
            FieldDec: res.field,
            FieldName: res.label,
            datatype: ''
          }}
  
src/menu/replaceField/settingform/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Tooltip, Select, Radio, AutoComplete, Modal } from 'antd'
import { Form, Row, Col, Tooltip, Select, Radio, AutoComplete, Input, Modal } from 'antd'
import { QuestionCircleOutlined, SwapRightOutlined, DeleteOutlined } from '@ant-design/icons'
// import './index.scss'
@@ -14,27 +14,38 @@
  state = {
    resource: 'custom',
    reType: 'field',
    field: '',
    label: '',
    fields: [],
    labels: []
    records: []
  }
  UNSAFE_componentWillMount() {
  componentDidMount () {
    let records = localStorage.getItem('replaceRecord')
    if (records) {
      records = JSON.parse(records)
      let fields = records.fields || []
      let labels = records.labels || []
      this.setState({fields, labels, field: fields[0] || '', label: labels[0] || ''})
      if (!Array.isArray(records)) {
        localStorage.removeItem('replaceRecord')
        records = []
    }
      this.setState({records})
      let field = ''
      let label = ''
      records.forEach(item => {
        if (item.reType !== 'field' || field) return
        field = item.value
        label = item.label
      })
      this.props.form.setFieldsValue({field, label})
    }
  }
  handleConfirm = () => {
    const { reType } = this.state
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
@@ -42,28 +53,30 @@
          if (values.resource === 'custom') {
            let records = localStorage.getItem('replaceRecord')
            if (reType === 'name') {
              values.field = values.orifield
              values.label = values.name
              delete values.orifield
              delete values.name
            }
            if (records) {
              records = JSON.parse(records)
            } else {
              records = {fields: [], labels: []}
              records = []
            }
            records.fields.unshift(values.field)
            records.labels.unshift(values.label)
            let field = values.field.toLowerCase()
            records = records.filter(item => item.reType !== reType || item.value.toLowerCase() !== field)
            let _fields = []
            let _labels = []
            records.unshift({
              value: values.field,
              label: values.label,
              reType
            })
            records.fields = records.fields.filter(m => {
              if (_fields.includes(m.toLowerCase())) return false
              _fields.push(m.toLowerCase())
              return true
            })
            records.labels = records.labels.filter(m => {
              if (_labels.includes(m.toLowerCase())) return false
              _labels.push(m.toLowerCase())
              return true
            })
            this.setState({records: records})
            localStorage.setItem('replaceRecord', JSON.stringify(records))
          }
@@ -82,16 +95,33 @@
      content: '',
      onOk() {
        localStorage.removeItem('replaceRecord')
        that.setState({fields: [], labels: []})
        that.setState({records: []})
      },
      onCancel() {}
    })
  }
  complete = (key) => {
    const { records, reType } = this.state
    let label = ''
    records.forEach(item => {
      if (item.reType === reType && key === item.value) {
        label = item.label
      }
    })
    if (reType === 'name') {
      this.props.form.setFieldsValue({name: label})
    } else {
      this.props.form.setFieldsValue({label: label})
    }
  }
  render() {
    const { tables } = this.props
    const { getFieldDecorator } = this.props.form
    const { resource, fields, labels, field, label, reType } = this.state
    const { resource, records, reType } = this.state
    const formItemLayout = {
      labelCol: {
@@ -104,14 +134,15 @@
      }
    }
    let _fields = fields
    if (field) {
      _fields = fields.filter(item => item.toLowerCase().indexOf(field.toLowerCase()) > -1)
    let _fields1 = []
    let _fields2 = []
    records.forEach(item => {
      if (item.reType === 'field') {
        _fields1.push(item.value)
      } else {
        _fields2.push(item.value)
    }
    let _labels = labels
    if (label) {
      _labels = labels.filter(item => item.indexOf(label) > -1)
    }
    })
    return (
      <Form {...formItemLayout}>
@@ -170,56 +201,56 @@
          {resource === 'custom' && reType === 'field' ? <Col span={20}>
            <Form.Item label="字段">
              {getFieldDecorator('field', {
                initialValue: field,
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入字段!'
                  }
                ]
              })(<AutoComplete dataSource={_fields} autoFocus onSearch={(val) => this.setState({ field: val})} placeholder="" />)}
              })(<AutoComplete dataSource={_fields1} onSelect={this.complete} filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} autoFocus placeholder="" />)}
            </Form.Item>
          </Col> : null}
          {resource === 'custom' && reType === 'field' ? <Col span={20}>
            <Form.Item label="名称">
              {getFieldDecorator('label', {
                initialValue: label,
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入名称!'
                  }
                ]
              })(<AutoComplete dataSource={_labels} onSearch={(val) => this.setState({ label: val})} placeholder="" />)}
              })(<Input autoComplete="off"/>)}
            </Form.Item>
          </Col> : null}
          {resource === 'custom' && reType === 'name' ? <Col span={20}>
            <Form.Item label="原字段">
              {getFieldDecorator('label', {
                initialValue: label,
              {getFieldDecorator('orifield', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入名称!'
                    message: '请输入原字段!'
                  }
                ]
              })(<AutoComplete dataSource={_labels} autoFocus onSearch={(val) => this.setState({ label: val})} placeholder="" />)}
              })(<AutoComplete dataSource={_fields2} onSelect={this.complete} filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} autoFocus placeholder="" />)}
            </Form.Item>
          </Col> : null}
          {resource === 'custom' && reType === 'name' ? <Col span={20}>
            <Form.Item label="替换为">
              {getFieldDecorator('field', {
                initialValue: field,
              {getFieldDecorator('name', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入字段!'
                  }
                ]
              })(<AutoComplete dataSource={_fields} onSearch={(val) => this.setState({ field: val})} placeholder="" />)}
              })(<Input autoComplete="off"/>)}
            </Form.Item>
          </Col> : null}
          {resource === 'custom' && fields.length > 0 ? <Col span={24}>
          {resource === 'custom' && records.length > 0 ? <Col span={24}>
            <DeleteOutlined onClick={this.clear} style={{float: 'right', fontSize: '18px', marginTop: '-10px', cursor: 'pointer', color: '#ff4d4f'}} title="清空历史记录" />
          </Col> : null}
        </Row>
src/mob/components/menubar/normal-menubar/menucomponent/options.jsx
@@ -108,7 +108,6 @@
      extendName: 'MenuNo',
      options: [
        ...menulist,
        // {value: 'IM', label: '即时通信(系统页)'},
        {value: 'AIService', label: '智能客服(系统页)'}
      ]
    },
src/mob/components/navbar/normal-navbar/menus/menuform/index.jsx
@@ -149,7 +149,6 @@
                    option.props.extend.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {appMenus.map(item => (<Select.Option key={item.MenuID} extend={item.MenuNo || ''} value={item.MenuID}>{item.MenuName}</Select.Option>))}
                  {/* <Select.Option key="IM" value="IM">即时通信(系统页)</Select.Option> */}
                  <Select.Option key="AIService" extend={''} value="AIService">智能客服(系统页)</Select.Option>
                </Select>
              )}
src/tabviews/custom/components/card/balcony/index.jsx
@@ -331,7 +331,9 @@
  
      if (id !== this.state.BID || id !== '') {
        this.setState({ BID: id, BData: data }, () => {
          if (config.wrap.datatype !== 'public') {
          this.loadData()
          }
        })
      }
    }
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -224,8 +224,16 @@
      return
    }
    
    if (/^http.+(.txt|.doc|.docx|.pdf|.xlsx|.xls|.zip|.rar|.ppt)$/i.test(url)) {
      let name = url.replace(/.+\//g, '').replace(/\.{1}[^.]*$/g, '')
    if (/^http.+(.txt|.doc|.docx|.pdf|.xlsx|.xls|.zip|.rar|.ppt)$/i.test(url) || card.linkType === 'download') {
      let name = ''
      if (card.datatype === 'static') {
        name = card.value || ''
      } else if (data.hasOwnProperty(card.field)) {
        name = data[card.field] + ''
      }
      name = name.replace(/\.{1}[^.]*$/g, '')
      name = name ? name + url.replace(/.+\./g, '.') : ''
      let d = document.createElement('a')
      d.href = url
      d.setAttribute('download', name)
@@ -648,10 +656,21 @@
          }
        }
        let _style = {...card.style}
        if (card.marks) {
          let _s = {}
          getMark(card.marks, data, _s)
          if (_s.color) {
            _style.color = _s.color
          }
        }
        if (card.tipType === 'text') {
          contents.push(
            <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
              <div style={card.style}>
              <div style={_style}>
                {val ? <Tooltip title={val}>
                  <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight}}>{icon}</div>
                </Tooltip> : <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight}}>{icon}</div>}
@@ -661,7 +680,7 @@
        } else {
          contents.push(
            <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
              <div style={card.style}>
              <div style={_style}>
                {val ? <Tooltip title={val}>
                  <MkIcon className="ant-mk-icon" style={{height: card.innerHeight}} type={icon}/>
                </Tooltip> : <MkIcon className="ant-mk-icon" style={{height: card.innerHeight}} type={icon}/>}
@@ -967,6 +986,8 @@
            if (key === 'children') return
            if (/^1949-10-01/.test(data[key])) {
              _data[key.toLowerCase()] = ''
            } else if (/\d{4}-\d{2}-\d{2}\s00:00:00/.test(data[key])) {
              _data[key.toLowerCase()] = data[key].replace(/\s00:00:00/g, '')
            } else {
              _data[key.toLowerCase()] = data[key]
            }
@@ -1030,7 +1051,7 @@
        if (val !== '') {
          if (val && typeof(val) === 'string') {
            if (!card.evalchars || card.evalchars.includes('enter')) {
              val = val.replace(/\n/ig, '<br/>')
              val = val.replace(/\\n|\n/ig, '<br/>')
            }
            if ((!card.evalchars || card.evalchars.includes('space')) && !/<(span|div|p|a|img)\s/g.test(val)) {
              val = val.replace(/\s/ig, '&nbsp;')
src/tabviews/custom/components/card/data-card/index.jsx
@@ -128,7 +128,7 @@
    _config.wrap.scale = _config.wrap.scale === 'true' ? 'scale' : ''
    _config.wrap.layout = (_config.wrap.layout || 'grid') + '-layout float-' + (_config.wrap.cardFloat || 'left')
    _config.wrap.wrapClass = `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${_config.wrap.scale} ${config.wrap.hover === 'true' ? 'mk-hover' : ''}`
    _config.wrap.wrapClass = `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${_config.wrap.scale} ${config.wrap.hover === 'true' ? 'mk-hover' : ''} ${config.wrap.empSign === 'hidden' ? 'mk-empty-hide' : ''}`
    if (_config.wrap.shifting === 'true') {
      _config.wrap.shifting = 'shifting'
src/tabviews/custom/components/card/data-card/index.scss
@@ -286,6 +286,10 @@
      border-color: var(--mk-sys-color);
    }
  }
  .ant-empty-image svg {
    max-width: 100%;
  }
}
.custom-data-card-box.shifting {
  .normal-header:not(.header-search) + .toolbar-button {
src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -127,7 +127,7 @@
    _config.wrap.selStyle = _config.wrap.selStyle || 'active'
    _config.wrap.pagestyle = _config.wrap.pagestyle || 'page'
    _config.wrap.wrapClass =  `${_config.wrap.selStyle} ${_config.wrap.cardType || ''}`
    _config.wrap.wrapClass =  `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${config.wrap.empSign === 'hidden' ? 'mk-empty-hide' : ''}`
    if (_config.wrap.zHeight || _config.wrap.minWidth) {
      _config.wrap.zoomStyle = {
src/tabviews/custom/components/card/double-data-card/index.scss
@@ -321,6 +321,10 @@
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
  .ant-empty-image svg {
    max-width: 100%;
  }
}
.double-data-card-box.shifting {
  .normal-header:not(.header-search) + .toolbar-button {
src/tabviews/custom/components/card/prop-card/index.jsx
@@ -473,7 +473,9 @@
    
    if (id !== this.state.BID || id !== '') {
      this.setState({ BID: id, BData: data }, () => {
        if (config.wrap.datatype !== 'public') {
        this.loadData()
        }
      })
    }
  }
src/tabviews/custom/components/card/table-card/index.jsx
@@ -602,7 +602,7 @@
            selectedData={[]}
          /> : null
        }
        <Row className={`card-row-list ${config.wrap.hover === 'true' ? 'mk-hover' : ''}`} style={{height: config.wrap.contentHeight}}>
        <Row className={`card-row-list ${config.wrap.hover === 'true' ? 'mk-hover' : ''} ${config.wrap.empSign === 'hidden' ? 'mk-empty-hide' : ''}`} style={{height: config.wrap.contentHeight}}>
          {precards.map((item, index) => (
            <Col key={index} className="extend-card" span={24}>
              <div className="card-item-box" style={item.style}>
src/tabviews/custom/components/card/table-card/index.scss
@@ -113,6 +113,10 @@
      height: 60px;
    }
  }
  .ant-empty-image svg {
    max-width: 100%;
  }
}
.custom-card-box::after {
src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -168,7 +168,9 @@
    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
    if (id !== this.state.BID || id !== '') {
      this.setState({ BID: id }, () => {
        if (config.wrap.datatype !== 'public') {
        this.loadData()
        }
      })
    }
  }
src/tabviews/custom/components/editor/braft-editor/index.scss
@@ -49,6 +49,24 @@
    }
  }
}
.custom-braft-editor-box.bold-border {
  .braft-content {
    table {
      td, th {
        border-width: 2px!important;
      }
    }
  }
}
.custom-braft-editor-box.deep-border {
  .braft-content {
    table {
      td, th {
        border-color: rgba(0, 0, 0, 0.85)!important;
      }
    }
  }
}
.custom-braft-editor-box.tb-flex {
  .braft-content {
    table {
@@ -56,6 +74,11 @@
    }
  }
}
.custom-braft-editor-box.deep-split {
  .braft-content hr {
    border-color: rgba(0, 0, 0, 0.85)!important;
  }
}
.custom-braft-editor-box::after {
  content: ' ';
src/tabviews/custom/components/form/simple-form/index.jsx
@@ -308,7 +308,9 @@
        })
      } else {
        this.setState({ BID: id, BData: data }, () => {
          if (config.wrap.datatype !== 'public') {
          this.loadData()
          }
        })
      }
    }
src/tabviews/custom/components/form/step-form/index.jsx
@@ -306,7 +306,9 @@
        })
      } else {
        this.setState({ BID: id, BData: data }, () => {
          if (config.wrap.datatype !== 'public') {
          this.loadData()
          }
        })
      }
    }
src/tabviews/custom/components/form/tab-form/index.jsx
@@ -269,7 +269,9 @@
        })
      } else {
        this.setState({ BID: id, BData: data }, () => {
          if (config.wrap.datatype !== 'public') {
          this.loadData()
          }
        })
      }
    }
src/tabviews/custom/components/interfaces/interItem/index.jsx
@@ -15,6 +15,7 @@
  }
  loading = false
  loadTimer = null
  
  state = {
    BID: ''
@@ -39,9 +40,7 @@
    }
    if (config.setting.onload !== 'false') {
      setTimeout(() => {
        this.loadData()
      }, config.setting.delay)
    } else {
      MKEmitter.addListener('initFinish', this.initFinish)
    }
@@ -84,9 +83,7 @@
    if (config.MenuID !== MenuID) return
    if (config.setting.onload === 'false') {
      setTimeout(() => {
        this.loadData()
      }, config.setting.delay)
    }
  }
@@ -107,13 +104,25 @@
    this.loadData()
  }
  async loadData () {
  loadData = () => {
    const { config } = this.props
    this.loadTimer && clearTimeout(this.loadTimer)
    this.loadTimer = setTimeout(() => {
      this.execLoadData()
    }, config.setting.delay)
  }
  async execLoadData () {
    const { config } = this.props
    const { BID } = this.state
    if (config.setting.supModule && !BID) {
      setTimeout(() => {
      MKEmitter.emit('mkPublicData', config.uuid, { $$empty: true, $$uuid: '' })
      MKEmitter.emit('resetSelectLine', config.uuid, '', { $$empty: true, $$uuid: '' })
      }, 20)
      this.loading = false
      return
    }
src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx
@@ -131,8 +131,8 @@
                  message: '请输入文件名!'
                },
                {
                  max: 50,
                  message: '最大长度为50位!'
                  max: 100,
                  message: '最大长度为100位!'
                }
              ]
            })(<Input />)}
src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx
@@ -1,4 +1,5 @@
import React, {Component} from 'react'
import { fromJS } from 'immutable'
class Documents extends Component {
  state = {
@@ -7,9 +8,16 @@
  }
  UNSAFE_componentWillMount() {
    const { documents } = this.props
    const { documents, list } = this.props
    let actFolder = documents[0] || null
    let actFolder = null
    if (documents[0]) {
      actFolder = fromJS(documents[0]).toJS()
      let ids = list.map(item => item.id)
      actFolder.attachments = actFolder.attachments.filter(doc => !ids.includes(doc.id))
    }
    this.setState({selectKey: [], actFolder: actFolder})
  }
@@ -31,15 +39,17 @@
  }
  checkfolder = (id) => {
    const { documents } = this.props
    const { documents, list } = this.props
    const { actFolder } = this.state
    if (!actFolder || actFolder.id === id) return
    let _actFolder = null
    let ids = list.map(item => item.id)
    documents.forEach(item => {
      if (item.id === id) {
        _actFolder = item
        _actFolder = fromJS(item).toJS()
        _actFolder.attachments = _actFolder.attachments.filter(doc => !ids.includes(doc.id))
      }
    })
src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
@@ -202,7 +202,6 @@
  docSubmit = () => {
    const { selectDocs, list } = this.state
    if (selectDocs.length > 0 && list.length > 0) {
      let _list = fromJS(list).toJS()
      let err = ''
@@ -241,7 +240,7 @@
          title="添加附件"
          wrapClassName="voucher-attach-wrap"
          visible={visible}
          width={700}
          width={'62vw'}
          maskClosable={false}
          onOk={this.submit}
          onCancel={() => { this.setState({ visible: false })}}
@@ -270,7 +269,7 @@
          title="添加附件"
          wrapClassName="voucher-attach-add-wrap"
          visible={upVisible}
          width={700}
          width={'62vw'}
          maskClosable={false}
          onOk={this.upSubmit}
          onCancel={() => { this.setState({ upVisible: false })}}
@@ -282,13 +281,13 @@
          title="电子档案"
          wrapClassName="voucher-attach-document-wrap"
          visible={docVisible}
          width={700}
          width={'62vw'}
          maskClosable={false}
          onOk={this.docSubmit}
          onCancel={() => { this.setState({ docVisible: false, selectDocs: [] })}}
          destroyOnClose
        >
          {docVisible ? <Documents documents={documents} onChange={(vals) => this.setState({selectDocs: vals})}/> : null}
          {docVisible ? <Documents documents={documents} list={list} onChange={(vals) => this.setState({selectDocs: vals})}/> : null}
        </Modal>
      </>
    )
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -2,7 +2,8 @@
import PropTypes from 'prop-types'
import md5 from 'md5'
import { is, fromJS } from 'immutable'
import { Table, Typography, Col, Switch, message } from 'antd'
import { Table, Typography, Col, Switch, message, Pagination } from 'antd'
import { CaretRightOutlined, CaretDownOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import { getMark } from '@/utils/utils.js'
@@ -152,7 +153,7 @@
  }
  render() {
    let { col, config, record, className, style, ...resProps } = this.props
    let { col, config, record, className, style, openChange, ...resProps } = this.props
    if (!col) return (<td {...resProps} className={className} style={style}/>)
@@ -209,6 +210,21 @@
      if (col.rowspan === 'true') {
        resProps.rowSpan = record['$$' + col.field]
      }
      if (col.$tree && record.$mk_floor) {
        className += ' mk-tree-td'
        if (record.$open) {
          content = <>
            <span className="mk-tree-node" style={{width: `calc(var(--tree-node-width) * ${record.$mk_floor})`}}><CaretRightOutlined onClick={(e) => openChange(e, record.$key)} /><CaretDownOutlined onClick={(e) => openChange(e, record.$key)}/></span>
            {content}
          </>
        } else {
          content = <>
            <span className="mk-tree-node" style={{width: `calc(var(--tree-node-width) * ${record.$mk_floor})`}}></span>
            {content}
          </>
        }
      }
      
      resProps.children = content
@@ -539,11 +555,12 @@
    orderfields: {},      // 排序id与field转换
    pageOptions: [],
    allColumns: null,
    reseting: false
    reseting: false,
    openkeys: []
  }
  UNSAFE_componentWillMount () {
    const { setting, columns, fields, colsCtrls } = this.props
    const { setting, columns, fields, colsCtrls, data } = this.props
    let radio = 5          // 虚化比例
    let _format = false    // 是否虚化处理
    let rowspans = []
@@ -594,6 +611,7 @@
                record,
                col: item,
                config: item.type === 'custom' ? {setting, columns: fields} : null,
                openChange: item.$tree ? this.openChange : null,
              })
            }
          }
@@ -653,6 +671,10 @@
      _columns = this.getCurColumns(_columns, this.props.allSearch)
    }
    if (setting.$tree) {
      this.resetOpenKeys(data)
    }
    this.setState({
      pageSize: setting.pageSize || 10,
      pageOptions,
@@ -669,7 +691,7 @@
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    const { allSearch, parCtrl } = this.props
    const { allSearch, parCtrl, setting, data } = this.props
    const { allColumns } = this.state
    if (allSearch && !is(fromJS(allSearch), fromJS(nextProps.allSearch))) {
@@ -698,6 +720,7 @@
                record,
                col: item,
                config: item.type === 'custom' ? {setting: this.props.setting, columns: this.props.fields} : null,
                openChange: item.$tree ? this.openChange : null,
              })
            }
          }
@@ -709,6 +732,10 @@
      this.setState({
        columns: getColumns(nextProps.columns)
      })
    }
    if (setting.$tree && !is(fromJS(data), fromJS(nextProps.data))) {
      this.resetOpenKeys(nextProps.data)
    }
  }
@@ -738,6 +765,83 @@
    MKEmitter.removeListener('autoQueryData', this.autoQueryData)
    MKEmitter.removeListener('autoSelectData', this.autoSelectData)
    MKEmitter.removeListener('mkCheckTopLine', this.mkCheckTopLine)
  }
  resetOpenKeys = (data) => {
    const { setting } = this.props
    if (!data || data.length === 0 || !setting.defOpen) {
      this.setState({openkeys: []})
    } else if (setting.defOpen === 'topline') {
      let keys = []
      if (data[0].$open) {
        keys = [data[0].$key]
        data.forEach(item => {
          if (item.$pkeys && item.$pkeys.length > 1 && item.$pkeys.includes(data[0].$key)) {
            keys.push(...item.$pkeys)
          }
        })
        keys = Array.from(new Set(keys))
      }
      this.setState({openkeys: keys})
    } else {
      this.setState({openkeys: data.filter(item => !!item.$open).map(item => item.$key)})
    }
  }
  openChange = (e, key) => {
    const { setting, MenuID, data } = this.props
    const { openkeys, selectedRowKeys } = this.state
    e.stopPropagation()
    let _openkeys = []
    if (openkeys.includes(key)) {
      _openkeys = openkeys.filter(k => k !== key)
    } else {
      _openkeys = [...openkeys, key]
    }
    if (!setting.tableType || _openkeys.length > openkeys.length) {
      this.setState({openkeys: _openkeys})
      return
    }
    let newkeys = fromJS(selectedRowKeys).toJS()
    newkeys = newkeys.filter(k => {
      if (!data[k]) return false
      if (!data[k].$pkeys) return true
      return data[k].$pkeys.every(key => _openkeys.includes(key))
    })
    if (newkeys.length === selectedRowKeys.length) {
      this.setState({openkeys: _openkeys})
      return
    }
    let _index = ''
    if (newkeys.length > 0) {
      _index = newkeys.slice(-1)[0]
    }
    this.changedata(_index)
    this.setState({ openkeys: _openkeys, selectedRowKeys: newkeys, activeIndex: _index !== '' ? _index : null })
    let selects = data.filter((item, _index) => newkeys.includes(_index))
    this.props.chgSelectData(selects)
    if (setting.$hasSyncModule) {
      MKEmitter.emit('syncBalconyData', MenuID, selects, false)
    }
  }
  getCurColumns = (columns, allSearch) => {
@@ -974,8 +1078,23 @@
  }
  changeTable = (pagination, filters, sorter) => {
    const { orderfields } = this.state
    const { setting } = this.props
    const { orderfields, pageSize } = this.state
    if (orderfields) {
      sorter.field = orderfields[sorter.field] || ''
    }
    if (setting.$tree) {
      this.setState({
        pageIndex: 1,
        selectedRowKeys: [],
        activeIndex: null,
        pickup: false
      })
      this.props.refreshdata({current: 1, pageSize: pageSize}, sorter)
    } else {
    this.setState({
      pageIndex: pagination.current,
      pageSize: pagination.pageSize,
@@ -984,11 +1103,19 @@
      pickup: false
    })
    if (orderfields) {
      sorter.field = orderfields[sorter.field] || ''
      this.props.refreshdata(pagination, sorter)
    }
    }
    this.props.refreshdata(pagination, filters, sorter)
  onPaginationChange = (current, pageSize) => {
    this.setState({
      pageIndex: current,
      pageSize: pageSize,
      selectedRowKeys: [],
      activeIndex: null
    })
    this.props.refreshdata({current: current, pageSize: pageSize, fixed: true}, {})
  }
  changedata = (index) => {
@@ -1125,7 +1252,7 @@
  render() {
    const { setting, statFValue, lineMarks, data } = this.props
    const { selectedRowKeys, activeIndex, pickup, pageOptions, columns, reseting } = this.state
    const { selectedRowKeys, activeIndex, pickup, pageOptions, columns, reseting, openkeys } = this.state
    if (reseting) return null
@@ -1152,14 +1279,16 @@
    // 数据收起时,过滤已选数据
    let _data = data || []
    if (!setting.$tree) {
    if (pickup) {
      _data = _data.filter((item, index) => selectedRowKeys.includes(index))
    }
    _data = this.handleRowspan(_data)
    }
    
    let _pagination = false
    if (setting.laypage !== 'false' && setting.laypage !== false) {
    if (setting.laypage && !setting.$tree) {
      _pagination = {
        current: this.state.pageIndex,
        pageSize: this.state.pageSize,
@@ -1209,8 +1338,8 @@
    }
    return (
      <div className={`normal-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-table-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length} ${fixed}`} style={style}>
        {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 ?
      <div className={`normal-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-table-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length} ${fixed} ${setting.empSign === 'hidden' ? 'mk-empty-hide' : ''}`} style={style}>
        {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 && !setting.$tree ?
          <Switch title="收起" className="main-pickup" checkedChildren={window.GLOB.dict['open'] || '开'} unCheckedChildren={window.GLOB.dict['shut'] || '关'} checked={pickup} onChange={this.pickupChange} /> : null
        }
        <Table
@@ -1223,11 +1352,26 @@
          loading={loading}
          scroll={{ x: '100%', y: height }}
          onRow={(record, index) => {
            let className = ''
            if (index === activeIndex) {
              className = ' mk-row-active '
            }
            if (setting.$tree) {
              if (record.$open && openkeys.includes(record.$key)) {
                className += ' mk-tree-open '
              }
              if (record.$pkeys && !record.$pkeys.every(key => openkeys.includes(key))) {
                className += ' mk-tree-hide '
              }
            }
            return {
              lineMarks: setting.tableMode !== 'fast' ? lineMarks : null,
              lineMarks: lineMarks,
              data: record,
              title: setting.tipField ? record[setting.tipField] : '',
              className: index === activeIndex ? ' mk-row-active ' : '',
              className: className,
              onClick: () => {this.changeRow(record, index)},
              onDoubleClick: () => {this.doubleClickLine(record)}
            }
@@ -1235,6 +1379,17 @@
          onChange={this.changeTable}
          pagination={_pagination}
        />
        {setting.laypage && setting.$tree ? <Pagination
          showSizeChanger
          className="mk-tree-pagination"
          onChange={this.onPaginationChange}
          onShowSizeChange={this.onPaginationChange}
          current={this.state.pageIndex}
          pageSize={this.state.pageSize}
          pageSizeOptions={pageOptions}
          total={this.props.total || 0}
          showTotal={(total, range) => `${range[0]}-${range[1]} ${window.GLOB.dict['of'] || '共'} ${total} ${window.GLOB.dict['items'] || '条'}`}
        /> : null}
        {_footer ? <div className={'normal-table-footer ' + (_pagination ? 'pagination' : '')}>{_footer}</div> : null}
      </div>
    )
src/tabviews/custom/components/share/normalTable/index.scss
@@ -170,6 +170,14 @@
  }
  .ant-table-small.ant-table-bordered {
    border-right: 1px solid #e8e8e8;
    .ant-table-content {
      border-radius: inherit;
      .ant-table-scroll {
        border-radius: inherit;
      }
    }
  }
  table, tr, th, td, .ant-table-small {
@@ -192,6 +200,43 @@
  table tbody tr {
    color: var(--mk-table-color);
  }
  .mk-tree-node {
    display: inline-block;
    text-align: right;
    --tree-node-width: 18px;
    .anticon-caret-right, .anticon-caret-down {
      cursor: pointer;
      padding-right: 3px;
    }
    .anticon-caret-down {
      display: none;
    }
  }
  .mk-tree-open {
    .mk-tree-node {
      .anticon-caret-right {
        display: none;
      }
      .anticon-caret-down {
        display: inline-block;
      }
    }
  }
  .mk-tree-hide {
    display: none;
  }
  .mk-tree-td {
    overflow: hidden;
    word-break: break-word;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .mk-tree-pagination {
    float: right;
    margin: 16px 0;
  }
}
.normal-custom-table.mk-parity {
  .ant-table-tbody tr:nth-child(even) {
src/tabviews/custom/components/table/base-table/index.jsx
@@ -73,6 +73,10 @@
      _config.setting.onload = 'false'
    }
    if (setting.tableMode === 'fast') {
      _config.lineMarks = null
    }
    _config.style = _config.style || {}
    this.setState({
@@ -454,7 +458,7 @@
  /**
   * @description 表格条件改变时重置数据(分页或排序)
   */
  refreshbytable = (pagination, filters, sorter) => {
  refreshbytable = (pagination, sorter) => {
    if (!sorter) { // 无人值守
      this.setState({
        pageIndex: pagination.pageIndex
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -20,7 +20,6 @@
class MkSwitch extends Component {
  static propTpyes = {
    autoFocus: PropTypes.bool,
    defaultValue: PropTypes.any,
    config: PropTypes.object,
    onChange: PropTypes.func
@@ -78,12 +77,10 @@
    if (config.$ctrl) {
      MKEmitter.emit('colBlur' + config.tableId, lineId, config.uuid)
    }
    this.props.onBlur && this.props.onBlur()
  }
  render() {
    const { config, autoFocus } = this.props
    const { config } = this.props
    const { status } = this.state
    return (
@@ -91,7 +88,6 @@
        ref={ref => this.node = ref}
        checkedChildren={config.openText}
        checked={status}
        autoFocus={autoFocus}
        onFocus={this.onFocus}
        onBlur={this.onBlur}
        unCheckedChildren={config.closeText}
@@ -763,7 +759,7 @@
        content = `${record[col.field]}`
      }
      if (col.editType === 'select' && col.options.length > 0) {
      if (col.editType === 'select' && col.showValue !== 'value' && col.options.length > 0) {
        content = col.map.get(content) || content
      } else if (col.editType === 'switch') {
        if (content === col.openVal) {
@@ -820,16 +816,17 @@
      }
      if (col.editable === 'true' && !disabled) {
        if (editing) {
        if (col.editType === 'switch') {
          let _value = record[col.field] !== undefined ? record[col.field] : ''
          return (<td onClick={(e) => e.stopPropagation()} className="editing_table_cell">
            <MkSwitch config={col} lineId={record.$$uuid} defaultValue={_value} onChange={this.onColChange}/>
          </td>)
        } else if (editing) {
          let _value = record[col.field] !== undefined ? record[col.field] : ''
          if (!col.editType || col.editType === 'text') {
            return (<td onClick={(e) => e.stopPropagation()} className="editing_table_cell">
              <MkInput config={col} lineId={record.$$uuid} defaultValue={_value} autoFocus={true} onChange={this.onColChange} onBlur={() => this.setState({editing: false})}/>
            </td>)
          } else if (col.editType === 'switch') {
            return (<td onClick={(e) => e.stopPropagation()} className="editing_table_cell">
              <MkSwitch config={col} lineId={record.$$uuid} defaultValue={_value} autoFocus={true} onChange={this.onColChange} onBlur={() => this.setState({editing: false})}/>
            </td>)
          } else if (col.editType === 'date') {
            return (<td onClick={(e) => e.stopPropagation()} className="editing_table_cell">
@@ -1099,7 +1096,7 @@
          )
        } else if (col.editType === 'switch') {
          children = (
            <MkSwitch config={col} lineId={record.$$uuid} defaultValue={_value} autoFocus={false} onChange={this.onColChange}/>
            <MkSwitch config={col} lineId={record.$$uuid} defaultValue={_value} onChange={this.onColChange}/>
          )
        } else if (col.editType === 'date') {
          children = (
@@ -1125,7 +1122,7 @@
          content = `${record[col.field]}`
        }
        if (col.editType === 'select' && col.options.length > 0) {
        if (col.editType === 'select' && col.showValue !== 'value' && col.options.length > 0) {
          content = col.map.get(content) || content
        } else if (col.editType === 'switch') {
          if (content === col.openVal) {
@@ -2140,6 +2137,12 @@
      delete result.message
      delete result.status
      this.props.columns.forEach(item => {
        if (item.arr_field && result[item.field]) {
          result[item.uuid] = result[item.field]
        }
      })
      this.resetFormList(result)
    })
  }
@@ -2920,7 +2923,7 @@
        {setting.hasSubmit && edData.length > 0 ? <div className="edit-custom-table-btn-wrap" style={submit.wrapStyle}>
          <Button style={submit.style} onClick={() => setTimeout(() => {this.submit()}, 10)} loading={loading} className="submit-table" type="link">{dict['submit'] || '提交'}</Button>
        </div> : null}
        <div className={`edit-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-table-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'}`} style={style}>
        <div className={`edit-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-table-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'} ${setting.empSign === 'hidden' ? 'mk-empty-hide' : ''}`} style={style}>
          <Table
            rowKey="$$uuid"
            components={components}
src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -232,6 +232,14 @@
  }
  .ant-table-small.ant-table-bordered {
    border-right: 1px solid #e8e8e8;
    .ant-table-content {
      border-radius: inherit;
      .ant-table-scroll {
        border-radius: inherit;
      }
    }
  }
  table, tr, th, td, .ant-table-small {
    border-color: var(--mk-table-border-color)!important;
src/tabviews/custom/components/table/normal-table/index.jsx
@@ -153,6 +153,10 @@
      _config.colsCtrls = null
    }
    if (setting.$tree && _config.cols[0]) {
      _config.cols[0].$tree = true
    }
    let columns = _config.cols
    if (_config.hasExtend) {
      columns = this.getCols(_config.cols, BData, _config.setting.extendTime)
@@ -610,6 +614,10 @@
        return item
      })
      if (setting.$tree && data.length) {
        data = this.getTree(data)
      }
      let total = result.total || 0
      if (config.setting.custompage && data.length) {
        total = data[data.length - 1].mk_total || 0
@@ -665,6 +673,90 @@
      
      UtilsDM.queryFail(result)
    }
  }
  getTree = (data) => {
    const { setting } = this.state
    let options = []
    let pnodes = []
    let _data = []
    data.forEach(item => {
      let pval = item[setting.parentField] + ''
      let val = item[setting.valueField] + ''
      if (pval === setting.mark) {
        pnodes.push({
          ...item,
          $mk_floor: 1,
          $key: val,
          $pid: ''
        })
      } else if (pval) {
        options.push({
          ...item,
          $mk_floor: 0,
          $key: val,
          $pid: pval
        })
      }
    })
    let get_tree = (parents) => {
      parents.forEach(parent => {
        parent.children = []
        options = options.filter(option => {
          if (option.$pid === parent.$key) {
            option.$mk_floor = parent.$mk_floor + 1
            option.$pkeys = parent.$pkeys ? [...parent.$pkeys, parent.$key] : [parent.$key]
            parent.children.push(option)
            return false
          }
          return true
        })
        if (parent.children.length === 0) {
          parent.children = null
        } else {
          parent.$open = true
          parent.children = get_tree(parent.children)
        }
      })
      return parents
    }
    let tree = get_tree(pnodes)
    let get_data = (parents) => {
      parents.forEach(parent => {
        let children = parent.children
        delete parent.children
        _data.push(parent)
        if (children) {
          get_data(children)
        }
      })
    }
    get_data(tree)
    if (options.length) {
      _data.push(...options)
    }
    _data = _data.map((item, index) => {
      item.key = index
      return item
    })
    return _data
  }
  /**
@@ -825,7 +917,7 @@
  /**
   * @description 表格条件改变时重置数据(分页或排序)
   */
  refreshbytable = (pagination, filters, sorter) => {
  refreshbytable = (pagination, sorter) => {
    if (sorter.order) {
      let _chg = {
        ascend: 'asc',
@@ -837,7 +929,7 @@
    this.setState({
      pageIndex: pagination.current,
      pageSize: pagination.pageSize,
      orderBy: (sorter.field && sorter.order) ? `${sorter.field} ${sorter.order}` : ''
      orderBy: (sorter.field && sorter.order) ? `${sorter.field} ${sorter.order}` : (pagination.fixed ? this.state.orderBy : '')
    }, () => {
      this.loadData()
    })
src/tabviews/custom/components/tree/antd-tree/index.jsx
@@ -36,6 +36,7 @@
  }
  loaded = false
  options = null
  UNSAFE_componentWillMount () {
    const { config } = this.props
@@ -364,11 +365,12 @@
      return
    }
    let parentNodes = []
    let _options = []
    let logMap = new Map()
    let selectKey = selectedKeys[0] || ''
    let selectData = ''
    let hasSelectKey = false
    this.options = []
    data.forEach(item => {
      let pval = item[config.wrap.parentField] + ''
@@ -399,7 +401,7 @@
          $parentId: ''
        })
      } else if (pval) {
        _options.push({
        this.options.push({
          ...item,
          $$uuid: uuid,
          $title: item[config.wrap.labelField] || '',
@@ -408,7 +410,17 @@
        })
      }
    })
    let _treedata = this.getTree(parentNodes, _options)
    let _treedata = this.getTree(parentNodes)
    if (this.options.length) {
      this.options.forEach(item => {
        _treedata.push({
          ...item,
          mk_floor: 1,
          $$title: <span style={{color: '#f5222d'}}>{item.$title}</span>
        })
      })
    }
    let _treeNodes = []
@@ -485,11 +497,11 @@
  /**
   * @description 获取结构树信息
   */
  getTree = (parents, options) => {
  getTree = (parents) => {
    parents.forEach(parent => {
      parent.children = []
      // 添加菜单的子元素
      options = options.filter(option => {
      this.options = this.options.filter(option => {
        if (option.$parentId === parent.$key) {
          option.mk_floor = parent.mk_floor + 1
          parent.children.push(option)
@@ -501,7 +513,7 @@
      if (parent.children.length === 0) {
        parent.children = null
      } else {
        parent.children = this.getTree(parent.children, options)
        parent.children = this.getTree(parent.children)
      }
    })
    return parents
@@ -519,7 +531,7 @@
          </TreeNode>
        )
      }
      return <TreeNode icon={<FileOutlined />} key={item.$key} title={item.$title} dataRef={item} isLeaf />
      return <TreeNode icon={<FileOutlined />} key={item.$key} title={item.$$title || item.$title} dataRef={item} isLeaf />
    })
  }
@@ -528,7 +540,7 @@
      let title = null
      if (actShow === 'line') {
        title = <>
          {item.$title}
          {item.$$title || item.$title}
          <MainAction
            BID={this.state.BID}
            BData={this.state.BData}
@@ -540,7 +552,7 @@
        </>
      } else {
        title = <>
          {item.$title}
          {item.$$title || item.$title}
          <Dropdown overlay={
            <div className="mk-tree-dropdown-wrap" onClick={(e) => e.stopPropagation()}>
              <MainAction
@@ -661,6 +673,7 @@
          </Tree>
        </div> : null}
        {treeNodes && treeNodes.length === 0 ? <Empty description={false}/> : null}
        {!treeNodes ? <div style={{height: '100px'}}></div> : null}
      </div>
    )
  }
src/tabviews/custom/index.jsx
@@ -702,6 +702,12 @@
          item.colsCtrls = null
        }
        if (item.wrap.tree === 'true') {
          item.setting.sync = 'false'
          item.$cache = false
          item.setting.$tree = true
        }
        if (item.subtype === 'editable') {
          item.submit.logLabel = item.$menuname + '-提交'
          item.submit.$menuId = item.uuid
@@ -922,6 +928,10 @@
          item.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(item.setting.dataresource + item.setting.customScript)
          if (item.setting.$tree) {
            item.setting.custompage = true
          }
          if (!item.setting.execute || item.setting.custompage) {
            item.forbidLine = true
          }
src/tabviews/custom/popview/index.jsx
@@ -420,6 +420,12 @@
          item.colsCtrls = null
        }
        if (item.wrap.tree === 'true') {
          item.setting.sync = 'false'
          item.$cache = false
          item.setting.$tree = true
        }
        if (item.subtype === 'editable') {
          item.submit.logLabel = item.$menuname + '-提交'
          item.submit.$menuId = item.uuid
@@ -618,6 +624,10 @@
          item.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(item.setting.dataresource + item.setting.customScript)
          if (item.setting.$tree) {
            item.setting.custompage = true
          }
          if (!item.setting.execute || item.setting.custompage) {
            item.forbidLine = true
          }
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -13,7 +13,8 @@
import MKEmitter from '@/utils/events.js'
import MkIcon from '@/components/mk-icon'
import MkCounter from './mkcounter'
// import './index.scss'
import './index.scss'
const MutilForm = asyncSpinComponent(() => import('@/tabviews/zshare/mutilform'))
const { confirm } = Modal
@@ -45,7 +46,8 @@
    autoMatic: false,
    check: false,
    count: 0,
    dict: window.GLOB.dict
    dict: window.GLOB.dict,
    submitType: ''
  }
  preCallback = null
@@ -445,6 +447,7 @@
  getSystemParam = (data, formdata, retmsg) => {
    const { setting, columns, btn } = this.props
    const { submitType } = this.state
    let _params = []
    if ( btn.Ot === 'notRequired' || btn.Ot === 'requiredSgl' || btn.Ot === 'requiredOnce' ) {
@@ -468,11 +471,11 @@
        param.ID = primaryId
        if (retmsg) {
          const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, data[0], columns, retmsg) // 数据源
          const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, data[0], columns, retmsg, submitType) // 数据源
          param.LText = sql
          param.$callbacksql = callbacksql
        } else {
          param.LText = getSysDefaultSql(btn, setting, '', param, data[0], columns, false) // 数据源
          param.LText = getSysDefaultSql(btn, setting, '', param, data[0], columns, false, submitType) // 数据源
          if (btn.output) {
            param.key_back_type = 'Y'
          }
@@ -495,11 +498,11 @@
          param.ID = Utils.getguid()
          if (retmsg) {
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg) // 数据源
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg, submitType) // 数据源
            param.LText = sql
            param.$callbacksql = callbacksql
          } else {
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false) // 数据源
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false, submitType) // 数据源
            if (btn.output) {
              param.key_back_type = 'Y'
            }
@@ -521,11 +524,11 @@
          param.ID = primaryId
          if (retmsg) {
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg) // 数据源
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg, submitType) // 数据源
            param.LText = sql
            param.$callbacksql = callbacksql
          } else {
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false) // 数据源
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false, submitType) // 数据源
            if (btn.output) {
              param.key_back_type = 'Y'
            }
@@ -587,11 +590,11 @@
          param.ID = primaryId
          if (retmsg) {
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, cell, columns, retmsg) // 数据源
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, cell, columns, retmsg, submitType) // 数据源
            param.LText = sql
            param.$callbacksql = callbacksql
          } else {
            param.LText = getSysDefaultSql(btn, setting, '', param, cell, columns, false) // 数据源
            param.LText = getSysDefaultSql(btn, setting, '', param, cell, columns, false, submitType) // 数据源
            if (btn.output) {
              param.key_back_type = 'Y'
            }
@@ -627,11 +630,11 @@
            param.ID = Utils.getguid()
            if (retmsg) {
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg) // 数据源
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg, submitType) // 数据源
              param.LText = sql
              param.$callbacksql = callbacksql
            } else {
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false) // 数据源
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false, submitType) // 数据源
              if (btn.output) {
                param.key_back_type = 'Y'
              }
@@ -653,11 +656,11 @@
            param.ID = primaryId
            if (retmsg) {
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg) // 数据源
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg, submitType) // 数据源
              param.LText = sql
              param.$callbacksql = callbacksql
            } else {
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false) // 数据源
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false, submitType) // 数据源
              if (btn.output) {
                param.key_back_type = 'Y'
              }
@@ -808,6 +811,8 @@
  getExps = (ex, formdata, cell, id, process) => {
    const { columns, BID, btn } = this.props
    const { submitType } = this.state
    let exps = []
    let values = {
      time_id: Utils.getguid(),
@@ -826,6 +831,7 @@
      datam: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      datam_begin: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      datam_end: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
      mk_submit_type: submitType || ''
      // mk_check_begin: '',
      // mk_check_end: ''
    }
@@ -836,8 +842,6 @@
    let formkeys = []
    formdata && formdata.forEach(form => {
      // if (!ex.reps.includes(form.key)) return
      formkeys.push(form.key)
      let val = form.value
@@ -889,6 +893,13 @@
        })
      }
    })
    if (btn.verify && btn.verify.printEnable === 'true' && !btn.output && !ex.reps.includes('ID') && values.id) {
      exps.push({
        key: 'ID',
        value: values.id
      })
    }
    if (process && btn.verify.workFlow === 'true') {
      let flow = window.GLOB.UserCacheMap.get(btn.$flowId)
@@ -1289,9 +1300,11 @@
   * @description 获取回调脚本的字段定义
   */
  getSysDeclareSql = (btn, formdata, data, columns, BID = '') => {
    const { submitType } = this.state
    let datavars = {}                 // 声明的变量,表单及显示列
    // 需要声明的变量集
    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 _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', 'mk_submit_type']
  
    // sql语句
    let _sql = ''
@@ -1421,7 +1434,7 @@
      _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}
        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),@mk_submit_type nvarchar(50)${_declarefields}
      `
  
    let userName = sessionStorage.getItem('User_Name') || ''
@@ -1439,7 +1452,7 @@
    // 初始化凭证及用户信息字段
    _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=''
        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}', @mk_submit_type='${submitType}', @BillCode='', @ModularDetailCode=''
        `
  
    // 表单变量赋值
@@ -1575,7 +1588,7 @@
              }, 600)
            }
            this.triggerNote(res, _param.ID) // 消息
            this.triggerNote(res, _param) // 消息
            this.execSuccess(res)
          } else {
            this.execError(res)
@@ -1600,7 +1613,7 @@
            setTimeout(() => {
              Api.genericInterface(param).then(res => {
                if (res.status) {
                  this.triggerNote(res, param.ID) // 消息
                  this.triggerNote(res, param) // 消息
                }
                resolve(res)
              }, (error) => {
@@ -1812,6 +1825,16 @@
      })
    }
    if (/@.*@/.test(url)) {
      Object.keys(param).forEach(key => {
        let reg = new RegExp('@' + key + '@', 'ig')
        if (reg.test(url)) {
          url = url.replace(reg, param[key])
          delete param[key]
        }
      })
    }
    let _params = {
      url: url,
      method: btn.method || 'post'
@@ -1978,7 +2001,7 @@
    Api.genericInterface(param, btn.$callbackScript, 'callback').then(res => {
      if (res.status) {
        this.triggerNote(res, param.ID) // 消息
        this.triggerNote(res, param) // 消息
        if (params.length === 0) {
          this.execSuccess(res)
@@ -2325,7 +2348,7 @@
    Api.genericInterface(param).then(res => {
      if (res.status) {
        this.triggerNote(res, param.ID) // 消息
        this.triggerNote(res, param) // 消息
        if (params.length === 0) {
          this.execSuccess(res)
@@ -2359,7 +2382,7 @@
    Api.genericInterface(param).then(res => {
      if (res.status) {
        this.triggerNote(res, param.ID) // 消息
        this.triggerNote(res, param) // 消息
        if (params.length === 0) {
          this.execSuccess(res)
@@ -2383,7 +2406,7 @@
            return new Promise(resolve => {
              Api.genericInterface(unCheckParam).then(result => {
                if (result.status) {
                  that.triggerNote(result, param.ID) // 消息
                  that.triggerNote(result, param) // 消息
          
                  if (params.length === 0) {
                    that.execSuccess(result)
@@ -2640,7 +2663,7 @@
    Api.genericInterface(param, btn.$callbackScript, 'callback').then(res => {
      if (res.status) {
        this.triggerNote(res, param.ID) // 消息
        this.triggerNote(res, param) // 消息
        // 一次请求成功,进行下一项请求
        if (params.length === 0) {
@@ -3068,7 +3091,7 @@
    })
  }
  triggerNote = (res, ID) => {
  triggerNote = (res, param) => {
    const { btn } = this.props
    if (!btn.verify) return
@@ -3080,7 +3103,16 @@
    }
    if (btn.verify.printEnable === 'true') {
      this.billPrint(id || ID)
      let _id = id || param.ID
      if (!_id && param.data && param.data[0] && param.data[0].exps) {
        param.data[0].exps.forEach(cell => {
          if (cell.key === 'ID') {
            _id = cell.value
          }
        })
      }
      this.billPrint(_id)
    }
    if (!id) return
@@ -3895,11 +3927,11 @@
  /**
   * @description 模态框(表单),确认
   */
  handleOk = () => {
  handleOk = (submitType = '') => {
    if (!this.formRef) return
    
    this.formRef.handleConfirm().then(res => {
      this.setState({ confirmLoading: true })
      this.setState({ confirmLoading: true, submitType: submitType })
      this.execSubmit(this.state.selines, () => { this.setState({ confirmLoading: false }) }, res)
    })
@@ -3912,7 +3944,8 @@
    this.setState({
      loading: false,
      visible: false,
      confirmLoading: false
      confirmLoading: false,
      submitType: ''
    })
    this.preCallback && this.preCallback()
@@ -4085,7 +4118,7 @@
   */
  getModels = () => {
    const { BID, btn, BData } = this.props
    const { btnconfig, visible, dict } = this.state
    const { btnconfig, visible, dict, confirmLoading, submitType } = this.state
    if (!btnconfig || !btnconfig.setting) return null
@@ -4114,19 +4147,23 @@
          <MutilForm
            BID={BID}
            action={btnconfig}
            inputSubmit={this.handleOk}
            inputSubmit={() => this.handleOk()}
            data={this.state.selines[0]}
            BData={BData}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
          <div className="ant-drawer-footer" style={{ position: 'absolute', zIndex: 1, right: 0, bottom: 0, width: '100%', borderTop: '1px solid #e9e9e9', padding: '10px 16px', background: '#fff', textAlign: 'right'}}>
          {btnconfig.setting.formType === 'check' ? <div className="ant-drawer-footer" style={{ position: 'absolute', zIndex: 1, right: 0, bottom: 0, width: '100%', borderTop: '1px solid #e9e9e9', padding: '10px 16px', background: '#fff', textAlign: 'right'}}>
            <Button onClick={this.handleCancel} style={{ marginRight: 8 }}>
              {btnconfig.setting.formType !== 'check' ? dict['cancel'] || '取消' : dict['close'] || '关闭'}
              {dict['close'] || '关闭'}
            </Button>
            {btnconfig.setting.formType !== 'check' ? <Button onClick={this.handleOk} loading={this.state.confirmLoading} type="primary">
              {dict['ok'] || '确定'}
            </Button> : null}
          </div>
          </div> : <div className="ant-drawer-footer" style={{ position: 'absolute', zIndex: 1, right: 0, bottom: 0, width: '100%', borderTop: '1px solid #e9e9e9', padding: '10px 16px', background: '#fff', textAlign: 'right'}}>
            <Button onClick={this.handleCancel} style={{ marginRight: 8 }}>
              {dict['cancel'] || '取消'}
            </Button>
            {btn.extBtn === 'true' ? <Button className={'extend-btn ' + (btn.extStyle || '')} disabled={confirmLoading && submitType !== btn.extValue} loading={confirmLoading && submitType === btn.extValue} onClick={() => this.handleOk(btn.extValue)}>{btn.extLabel}</Button> : null}
            {btn.extBtn === 'true' ? <Button className={'confirm-btn ' + (btn.confStyle || '')} disabled={confirmLoading && submitType !== ''} loading={confirmLoading && submitType === ''} onClick={() => this.handleOk()}>{btn.confLabel || dict['ok'] || '确定'}</Button> : null}
            {btn.extBtn !== 'true' ? <Button type="primary" loading={confirmLoading} onClick={() => this.handleOk()}>{dict['ok'] || '确定'}</Button> : null}
          </div>}
        </Drawer>
      )
    } else {
@@ -4152,18 +4189,20 @@
          wrapClassName={'action-modal' + (btnconfig.setting.moveable === 'true' ? ' moveable-modal modal-' + btn.uuid : '')}
          visible={visible}
          width={width}
          okText={dict['ok'] || '确定'}
          cancelText={dict['cancel'] || '取消'}
          onOk={this.handleOk}
          maskStyle={btnconfig.setting.moveable === 'true' ?  {backgroundColor: 'rgba(0, 0, 0, 0.15)'} : null}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.handleCancel}
          footer={[
            <Button key="cancel" onClick={this.handleCancel}>{dict['cancel'] || '取消'}</Button>,
            btn.extBtn === 'true' ? <Button key="extend" className={'extend-btn ' + (btn.extStyle || '')} disabled={confirmLoading && submitType !== btn.extValue} loading={confirmLoading && submitType === btn.extValue} onClick={() => this.handleOk(btn.extValue)}>{btn.extLabel}</Button> : null,
            btn.extBtn === 'true' ? <Button key="confirm" className={'confirm-btn ' + (btn.confStyle || '')} disabled={confirmLoading && submitType !== ''} loading={confirmLoading && submitType === ''} onClick={() => this.handleOk()}>{btn.confLabel || dict['ok'] || '确定'}</Button> : null,
            btn.extBtn !== 'true' ? <Button key="confirm" type="primary" loading={confirmLoading} onClick={() => this.handleOk()}>{dict['ok'] || '确定'}</Button> : null
          ]}
          destroyOnClose
        >
          <MutilForm
            BID={BID}
            action={btnconfig}
            inputSubmit={this.handleOk}
            inputSubmit={() => this.handleOk()}
            data={this.state.selines[0]}
            BData={BData}
            wrappedComponentRef={(inst) => this.formRef = inst}
src/tabviews/zshare/actionList/normalbutton/index.scss
@@ -0,0 +1,72 @@
.extend-btn {
  color: var(--mk-sys-color)!important;
  border-color: var(--mk-sys-color)!important;
  background-color: #ffffff!important;
}
.confirm-btn {
  background-color: var(--mk-sys-color)!important;
  border-color: var(--mk-sys-color)!important;
  color: #ffffff!important;
}
.extend-btn.primary, .confirm-btn.primary {
  background-color: #1890ff!important;
  border-color: #1890ff!important;
  color: #ffffff!important;
}
.extend-btn.yellow, .confirm-btn.yellow {
  background-color: #fadb14!important;
  border-color: #fadb14!important;
  color: #ffffff!important;
}
.extend-btn.orange, .confirm-btn.orange {
  background-color: #fa8c16!important;
  border-color: #fa8c16!important;
  color: #ffffff!important;
}
.extend-btn.danger, .confirm-btn.danger {
  background-color: #f5222d!important;
  border-color: #f5222d!important;
  color: #ffffff!important;
}
.extend-btn.green, .confirm-btn.green {
  background-color: #52c41a!important;
  border-color: #52c41a!important;
  color: #ffffff!important;
}
.extend-btn.purple, .confirm-btn.purple {
  background-color: #722ed1!important;
  border-color: #722ed1!important;
  color: #ffffff!important;
}
.extend-btn.border-primary, .confirm-btn.border-primary {
  color:  #1890ff!important;
  border-color:  #1890ff!important;
  background-color: #ffffff!important;
}
.extend-btn.border-yellow, .confirm-btn.border-yellow {
  color:  #fadb14!important;
  border-color:  #fadb14!important;
  background-color: #ffffff!important;
}
.extend-btn.border-orange, .confirm-btn.border-orange {
  color:  #fa8c16!important;
  border-color:  #fa8c16!important;
  background-color: #ffffff!important;
}
.extend-btn.border-danger, .confirm-btn.border-danger {
  color:  #f5222d!important;
  border-color:  #f5222d!important;
  background-color: #ffffff!important;
}
.extend-btn.border-green, .confirm-btn.border-green {
  color:  #52c41a!important;
  border-color:  #52c41a!important;
  background-color: #ffffff!important;
}
.extend-btn.border-purple, .confirm-btn.border-purple {
  color:  #722ed1!important;
  border-color:  #722ed1!important;
  background-color: #ffffff!important;
}
src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -131,11 +131,11 @@
    if (btn.$view === 'popview') {
      if (btn.popClose !== 'never') {
        MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.popClose, btn)
        MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.popClose, btn, '', this.state.popData ? [this.state.popData] : null)
      }
    } else {
      let position = btn.popClose !== 'never' ? btn.popClose : 'grid'
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, position, btn)
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, position, btn, '', this.state.popData ? [this.state.popData] : null)
    }
  }
@@ -207,7 +207,7 @@
    })
    if (btn.popClose !== 'never') {
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.popClose, btn)
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.popClose, btn, '', this.state.popData ? [this.state.popData] : null)
    }
    if (btn.syncComponentId) {
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -180,6 +180,7 @@
      let modal = this.state.btnconfig
      if (!modal && btn.modal) {
        modal = this.handleModelConfig(btn.modal)
        modal.uuid = btn.uuid
      }
      this.setState({
@@ -2129,6 +2130,7 @@
        } else {
          _LongParam = updateForm(_LongParam)
          _LongParam = this.handleModelConfig(_LongParam)
          _LongParam.uuid = btn.uuid
          this.setState({
            btnconfig: _LongParam
src/tabviews/zshare/mutilform/index.jsx
@@ -297,6 +297,14 @@
        } else {
          item.showValue = ''
        }
      } else if (item.type === 'brafteditor') {
        if (window.backend && newval && /<\/span>/.test(newval) && item.encryption === 'true') {
          try {
            newval = window.btoa(window.encodeURIComponent(newval))
          } catch (e) {
            newval = ''
          }
        }
      }
      if (newval !== '$empty') {
src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
@@ -155,7 +155,7 @@
            wrapperCol={{style: {width: (100 - labelwidth) + '%'}}}
            label={card.labelShow !== 'false' ? card.label : ''}
            required={card.required === 'true'}
            help={(card.field || '') + (card.datefield ? ', ' + card.datefield : '') + (card.advanced === 'true' ? '(高级搜索)' : '')}
            help={`${card.field || ''} ${card.datefield ? ', ' + card.datefield : ''} ${card.Hide === 'true' ? '(隐藏)' : ''} ${card.advanced === 'true' ? '(高级搜索)' : ''}`}
          >
            {formItem}
          </Form.Item>
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -724,6 +724,10 @@
            values.field = values.field.join(',')
          }
          if (values.initval && ['text', 'select', 'radio', 'multiselect', 'link', 'checkcard'].includes(values.type)) {
            values.initval = values.initval.replace(/^\s+|\s+$/ig, '')
          }
          if (['select', 'link'].includes(values.type)) {
            if (values.resourceType === '1') {
              if (/\$first/.test(values.initval) && values.initval.replace(/\s/g, '') === '$first') {
src/templates/zshare/editTable/index.jsx
@@ -526,7 +526,12 @@
      if (!unique) return
      if (type === 'excelcolumn') {
        data.push(res.data)
      } else {
      data.unshift(res.data)
      }
      this.setState({ data, editingKey: '', editLineId: res.data.uuid || '' }, () => {
        this.props.onChange(data)
      })
src/templates/zshare/verifycard/billcodeform/index.jsx
@@ -8,13 +8,13 @@
class BillCodeForm extends Component {
  static propTpyes = {
    btn: PropTypes.object,          // 按钮信息
    fields: PropTypes.array,        // 表单
    billcodes: PropTypes.array,     // 表单
    columns: PropTypes.array,       // 表单
    modular: PropTypes.array,       // 表单
    modularDetail: PropTypes.array, // 表单
    orderChange: PropTypes.func     // 表单
    btn: PropTypes.object,
    fields: PropTypes.array,
    billcodes: PropTypes.array,
    columns: PropTypes.array,
    modular: PropTypes.array,
    modularDetail: PropTypes.array,
    orderChange: PropTypes.func
  }
  state = {
src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -1,22 +1,19 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Button, Modal, Tooltip, Radio, Select, Switch, notification } from 'antd'
import { Form, Row, Col, Button, Tooltip, Radio, Select, Switch, notification } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import Api from '@/api'
import { checkSQL } from '@/utils/utils-custom.js'
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
class CustomForm extends Component {
  static propTpyes = {
    btn: PropTypes.object,          // 按钮信息
    initsql: PropTypes.string,      // 初始化脚本
    btn: PropTypes.object,
    formfields: PropTypes.string,
    colfields: PropTypes.string,
    systemScripts: PropTypes.array, // 系统脚本
    customScripts: PropTypes.array, // 自定义脚本
    scriptsChange: PropTypes.func   // 表单
    systemScripts: PropTypes.array,
    cbScriptsChange: PropTypes.func
  }
  state = {
@@ -47,17 +44,9 @@
    const { editItem, skip } = this.state
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (type === 'fullscreen' && err) {
        notification.warning({
          top: 92,
          message: '请输入sql!',
          duration: 5
        })
        return
      }
      if (err) return
      if (!err) {
        if (/^[\s\n]+$/.test(values.sql)) {
      if (!values.sql || /^[\s\n]+$/.test(values.sql)) {
          notification.warning({
            top: 92,
            message: '请输入sql!',
@@ -77,89 +66,29 @@
        if (!pass && !skip) return
        let tail = `
          aaa:
        `
        let _prevCustomScript = '' // 默认sql前执行脚本
        let _backCustomScript = '' // 默认sql后执行脚本
        this.props.customScripts.forEach(item => {
          if (item.status === 'false') return
          if (item.position === 'front') {
            _prevCustomScript += `
            /* 默认sql前脚本 */
            ${values.uuid === item.uuid ? values.sql : item.sql}
            `
          } else {
            _backCustomScript += `
            /* 默认sql后脚本 */
            ${values.uuid === item.uuid ? values.sql : item.sql}
            `
          }
        })
        if (!values.uuid) {
          if (values.position === 'front') {
            _prevCustomScript += `
            /* 默认sql前脚本 */
            ${values.sql}
            `
          } else {
            _backCustomScript += `
            /* 默认sql后脚本 */
            ${values.sql}
            `
          }
        }
        let sql = this.props.initsql +  _prevCustomScript + _backCustomScript + tail
        // if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
        //   window.GLOB.funcs.forEach(item => {
        //     let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
        //     sql = sql.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
        //   })
        // }
        // 数据权限
        sql = sql.replace(/@\$|\$@/ig, '').replace(/\$check@|@check\$/ig, '')
        sql = sql.replace(/@datam@/ig, `''`)
        sql = sql.replace(/@typename@/ig, `'debug'`)
        if (skip) {
          this.setState({
            skip: false,
            editItem: null
          }, () => {
            this.props.scriptsChange(values)
          })
          this.props.form.setFieldsValue({
            sql: ' '
          })
        this.props.cbScriptsChange(values)
        } else {
          this.setState({loading: true})
          Api.sDebug(sql).then(res => {
            if (res.status || res.ErrCode === '-2') {
        this.props.cbScriptsChange(values, () => {
              this.setState({
                loading: false,
                editItem: null
              }, () => {
                this.props.scriptsChange(values)
              })
              this.props.form.setFieldsValue({
                sql: ' '
              })
            } else {
        }, () => {
              this.setState({loading: false})
              Modal.error({
                title: res.message
              })
            }
          })
        }
      }
    })
  }
@@ -228,7 +157,7 @@
          {!type ? <Col span={24} className="sqlfield">
            <Form.Item label="可用字段">
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, time_id, typename, datam</span></Tooltip>,&nbsp;
              <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: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted, mk_submit_type</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {formfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="表单变量,系统会定义变量并赋值。">, <span style={{color: '#8E44AD'}}>{formfields}</span></Tooltip> : ''}
              {colfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="字段集变量,系统会定义变量并赋值。">, {colfields}</Tooltip> : ''}
@@ -280,15 +209,9 @@
            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
          </Col>
          <Col span={24} className="sql">
            <Form.Item label="sql">
            <Form.Item label="sql" required>
              {getFieldDecorator('sql', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入sql!'
                  }
                ]
                initialValue: ''
              })(<CodeMirror />)}
            </Form.Item>
          </Col>
src/templates/zshare/verifycard/customform/index.jsx
@@ -1,24 +1,23 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, Button, notification, Modal, Tooltip } from 'antd'
import { Form, Row, Col, Input, Select, Button, notification, Tooltip, Switch } from 'antd'
import Api from '@/api'
import { checkSQL } from '@/utils/utils-custom.js'
import CodeMirror from '@/templates/zshare/codemirror'
// import './index.scss'
class CustomForm extends Component {
  static propTpyes = {
    btn: PropTypes.object,          // 按钮
    btn: PropTypes.object,
    formfields: PropTypes.string,
    colfields: PropTypes.string,
    initsql: PropTypes.string,      // 可用字段
    customChange: PropTypes.func    // 表单
    customChange: PropTypes.func
  }
  state = {
    editItem: null,
    loading: false
    loading: false,
    skip: false
  }
  edit = (record) => {
@@ -46,10 +45,11 @@
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    const { skip, editItem } = this.state
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        if (/^[\s\n]+$/.test(values.sql)) {
        if (!values.sql || /^[\s\n]+$/.test(values.sql)) {
          notification.warning({
            top: 92,
            message: '请输入sql!',
@@ -58,55 +58,41 @@
          return
        }
        
        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
        values.uuid = editItem ? editItem.uuid : ''
        values.resultName = values.result === 'false' ? '不存在' : '存在'
        let pass = checkSQL(values.sql, 'customscript')
        if (!pass) return
        if (!pass && !skip) return
        let sql = `${this.props.initsql}
          /* 自定义验证 */
          select @tbid='', @ErrorCode='',@retmsg=''
          select top 1 @tbid='X' from (${values.sql}) a
          If @tbid = ''
          Begin
            select @ErrorCode='${values.errorCode}',@retmsg='${values.errmsg}'
            goto aaa
          end
          aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
        // if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
        //   window.GLOB.funcs.forEach(item => {
        //     let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
        //     sql = sql.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
        //   })
        // }
        // 数据权限
        sql = sql.replace(/@\$|\$@/ig, '')
        this.setState({loading: true})
        Api.sDebug(sql).then(res => {
          if (res.status || res.ErrCode === '-2') {
        if (skip) {
            this.setState({
              loading: false,
            skip: false,
              editItem: null
            }, () => {
              this.props.customChange(values)
            })
            this.props.form.setFieldsValue({
              sql: ' ',
              errmsg: ''
            })
          this.props.customChange(values)
          } else {
            this.setState({loading: false})
          this.setState({loading: true})
            
            Modal.error({
              title: res.message
          this.props.customChange(values, () => {
            this.setState({
              loading: false,
              editItem: null
            })
            this.props.form.setFieldsValue({
              sql: '',
              errmsg: ''
            })
          }, () => {
            this.setState({
              loading: false
            })
            })
          }
        })
      }
    })
  }
@@ -114,6 +100,7 @@
  render() {
    const { formfields, colfields, btn } = this.props
    const { getFieldDecorator } = this.props.form
    const { skip } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -131,22 +118,16 @@
          <Col span={21} className="sqlfield">
            <Form.Item label={'可用字段'}>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, time_id</span></Tooltip>,&nbsp;
              <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: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted, mk_submit_type</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {formfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="表单变量,系统会定义变量并赋值。">, <span style={{color: '#8E44AD'}}>{formfields}</span></Tooltip> : ''}
              {colfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="字段集变量,系统会定义变量并赋值。">, {colfields}</Tooltip> : ''}
            </Form.Item>
          </Col>
          <Col span={21} className="sql">
            <Form.Item label="sql">
            <Form.Item label="sql" required>
              {getFieldDecorator('sql', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入sql!'
                  }
                ]
                initialValue: ''
              })(<CodeMirror />)}
            </Form.Item>
          </Col>
@@ -161,9 +142,13 @@
            {btn.sql ? <div style={{marginTop: '31px'}}>
              表名:  <div style={{wordBreak: 'break-all'}}>{btn.sql}</div>
            </div> : null}
            <div style={{paddingTop: '20px', fontSize: '12px'}}>
              强制保存:
              <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
            </div>
          </Col>
          <Col span={7}>
            <Form.Item label={'结果处理'}>
            <Form.Item label="结果处理">
              {getFieldDecorator('result', {
                initialValue: 'true',
                rules: [
@@ -198,7 +183,7 @@
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'报错编码'}>
            <Form.Item label="报错编码">
              {getFieldDecorator('errorCode', {
                initialValue: 'E',
                rules: [
@@ -219,7 +204,6 @@
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
src/templates/zshare/verifycard/customscript/index.jsx
@@ -1,9 +1,8 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Button, notification, Modal, Tooltip, Radio, Select, Switch } from 'antd'
import { Form, Row, Col, Button, notification, Tooltip, Radio, Select, Switch } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import Api from '@/api'
import { checkSQL } from '@/utils/utils-custom.js'
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
@@ -14,11 +13,8 @@
    btn: PropTypes.object,
    formfields: PropTypes.string,
    colfields: PropTypes.string,
    initsql: PropTypes.string,
    defaultsql: PropTypes.string,
    useDefaultSql: PropTypes.any,
    getSysDefSql: PropTypes.func,
    systemScripts: PropTypes.array,
    customScripts: PropTypes.array,
    scriptsChange: PropTypes.func
  }
@@ -46,11 +42,13 @@
  }
  handleConfirm = () => {
    const { type, workFlow, flowType, flowSql, flowRemark, useDefaultSql, defaultsql } = this.props
    const { type } = this.props
    const { editItem, skip } = this.state
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (type === 'fullscreen' && err) {
      if (err) return
      if (!values.sql || /^[\s\n]+$/.test(values.sql)) {
        notification.warning({
          top: 92,
          message: '请输入sql!',
@@ -58,15 +56,7 @@
        })
        return
      }
      if (!err) {
        if (/^[\s\n]+$/.test(values.sql)) {
          notification.warning({
            top: 92,
            message: '请输入sql!',
            duration: 5
          })
          return
        }
        values.uuid = editItem ? editItem.uuid : ''
        values.position = values.position || (editItem ? editItem.position : 'front')
@@ -78,179 +68,31 @@
        if (!pass && !skip) return
        let tail = `
          aaa:
        `
        let _initCustomScript = '' // 初始化脚本
        let _prevCustomScript = '' // 默认sql前执行脚本
        let _backCustomScript = '' // 默认sql后执行脚本
        this.props.customScripts.forEach(item => {
          let _item = values.uuid === item.uuid ? values : item
          if (_item.status === 'false') return
          if (_item.position === 'init') {
            _initCustomScript += `
            /* 初始化脚本 */
            ${_item.sql}
            `
          } else if (_item.position === 'front') {
            _prevCustomScript += `
            /* 默认sql前脚本 */
            ${_item.sql}
            `
          } else {
            _backCustomScript += `
            /* 默认sql后脚本 */
            ${_item.sql}
            `
          }
        })
        if (!values.uuid) {
          if (values.position === 'init') {
            _initCustomScript += `
            /* 初始化脚本 */
            ${values.sql}
            `
          } else if (values.position === 'front') {
            _prevCustomScript += `
            /* 默认sql前脚本 */
            ${values.sql}
            `
          } else {
            _backCustomScript += `
            /* 默认sql后脚本 */
            ${values.sql}
            `
          }
        }
        let sql = this.props.initsql + _initCustomScript + _prevCustomScript
        if (useDefaultSql) {
          sql += `\n/* 默认sql */
            ${defaultsql}
          `
        }
        if (window.GLOB.process && workFlow === 'true' && flowSql === 'true') {
          if (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,bid,createuserid,CreateUser,CreateStaff,upid)
              select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@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@
              insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid,typecharone)
              select @ID@,@works_flow_code@,@userid@,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@,'begin'
            `
          } 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(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname${flowRemark ? ',remark=@' + flowRemark : ''}
              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,bid,createuserid,CreateUser,CreateStaff,upid${flowRemark ? ',remark' : ''})
              select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@${flowRemark ? ',@' + flowRemark : ''}
              update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
              where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
              if @check_userids@ != ''
              begin
                    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
                    update n
                    set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
                    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
            `
          }
        }
        sql += _backCustomScript + tail
        // if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
        //   window.GLOB.funcs.forEach(item => {
        //     let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
        //     sql = sql.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
        //   })
        // }
        // 数据权限
        sql = sql.replace(/@\$|\$@/ig, '').replace(/\$check@|@check\$/ig, '')
        sql = sql.replace(/@datam@/ig, `''`)
        sql = sql.replace(/@typename@/ig, `'debug'`)
        if (window.GLOB.process && workFlow === 'true') {
          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')
          if (flowType === 'start') {
            sql = sql.replace(/@start_type@/ig, `'开始'`)
          } else {
            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_sign@/ig, `''`)
          }
        }
        if (skip) {
          this.setState({
            skip: false,
            editItem: null
          }, () => {
            this.props.scriptsChange(values)
          })
          this.props.form.setFieldsValue({
            sql: ' '
          })
        this.props.scriptsChange(values)
        } else {
          this.setState({loading: true})
          Api.sDebug(sql).then(res => {
            if (res.status || res.ErrCode === '-2') {
        this.props.scriptsChange(values, () => {
              this.setState({
                loading: false,
                editItem: null
              }, () => {
                this.props.scriptsChange(values)
              })
              this.props.form.setFieldsValue({
                sql: ' '
              })
            } else {
              this.setState({loading: false})
              Modal.error({
                title: res.message
        }, () => {
          this.setState({
            loading: false
              })
            }
          })
        }
      }
    })
  }
@@ -266,7 +108,7 @@
  }
  selectScript = (value, option) => {
    const { flowType, flowRemark } = this.props
    const { flowType, flowRemark, getSysDefSql } = this.props
    if (!value || !option) return
@@ -364,6 +206,11 @@
      }
      value = value.replace(/\n\s{8}/g, '\n')
    } else if (value === 'defaultsql') {
      value = ''
      if (getSysDefSql) {
        value = getSysDefSql()
      }
    }
    _sql = _sql.replace(/\s{6}$/, '')
@@ -411,7 +258,7 @@
            <Form.Item label={'可用字段'}>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="公共值,请按照@xxx@格式使用。"><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, time_id, typename, datam</span></Tooltip>,&nbsp;
              {window.GLOB.process && workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={`工作流变量,请按照@xxx@格式使用${flowType !== 'start' ? ',works_flow_sign 为分支启用高级设置时的标记值' : ''}。`}><span style={{color: '#26C281'}}>works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, {flowType === 'start' ? 'start_type,' : 'check_type, notice_type, check_userids, notice_userids, works_flow_sign,'} </span></Tooltip> : null}
              <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: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted, mk_submit_type</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="系统变量,系统会定义变量并在单号生成或创建凭证时使用。"><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {formfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="表单变量,系统会定义变量并赋值。">, <span style={{color: '#8E44AD'}}>{formfields}</span></Tooltip> : ''}
              {colfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="字段集变量,系统会定义变量并赋值。">, {colfields}</Tooltip> : ''}
@@ -443,7 +290,7 @@
                onSelect={this.selectScript}
                getPopupContainer={() => document.getElementById('verify-custom-scripts' + _type)}
              >
                <Select.Option key="default" value={this.props.defaultsql}>默认sql</Select.Option>
                <Select.Option key="default" value="defaultsql">默认sql</Select.Option>
                {window.GLOB.process && workFlow === 'true' ? <Select.Option key="flow" value="flowSql">默认sql(工作流)</Select.Option> : null}
                <Select.Option key="debugger" value={`z_debug: select @ErrorCode='E',@retmsg='测试断点' goto aaa`}>
                  测试断点
@@ -472,15 +319,9 @@
                <QuestionCircleOutlined className="mk-form-tip" />
                sql
              </Tooltip>
            }>
            } required>
              {getFieldDecorator('sql', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: '请输入sql!'
                  }
                ]
              })(<CodeMirror />)}
            </Form.Item>
          </Col>
src/templates/zshare/verifycard/index.jsx
@@ -36,7 +36,6 @@
  }
  state = {
    initsql: '',            // sql验证时变量声明及赋值
    verifyInter: 'system',  // 接口类型
    activeKey: 'base',
    appType: sessionStorage.getItem('appType'),
@@ -46,7 +45,6 @@
    fields: [],
    formfields: '',
    colfields: '',
    defaultsql: '',         // 默认Sql
    orderModular: [],
    orderModularDetail: [],
    voucher: [],
@@ -54,7 +52,6 @@
    systemScripts: [],
    columnsFields: [],
    unionFields: [],
    uniqueFields: [],  // 唯一性验证,表单字段
    uniqueColumns: [
      {
        title: '名称',
@@ -613,7 +610,15 @@
      _verify.limitInvalid = true
      _verify.limitText = '静态数据源,不可使用失效验证'
      _invalid = 'false'
    } else if (config.setting && config.setting.maxScript && config.setting.maxScript >= 300) {
    } else if (!config.setting || config.setting.interType !== 'system') {
      _verify.limitInvalid = true
      _verify.limitText = '数据源未使用系统接口,不能使用失效验证!'
      _invalid = 'false'
    } else if (config.setting.execute !== 'true' || !config.setting.dataresource) {
      _verify.limitInvalid = true
      _verify.limitText = '尚未添加数据源,不能使用失效验证!'
      _invalid = 'false'
    } else if (config.setting.maxScript && config.setting.maxScript >= 300) {
      _verify.limitInvalid = true
      _verify.limitText = '数据源中自定义脚本过于复杂,不能使用失效验证!'
      _invalid = 'false'
@@ -714,99 +719,93 @@
    let _fields = []
    if (card.OpenType === 'form') {
      _fields.push({
      let item = {
        field: card.field,
        label: card.label,
        type: 'text'
      })
    } else if (card.modal && (card.OpenType === 'pop' || !card.OpenType)) {
      _fields = card.modal.fields || []
        type: 'text',
        writein: true,
        fieldlen: 50
    }
    let sysfields = ['UserName', 'FullName', 'RoleID', 'mk_departmentcode', 'mk_organization', 'mk_user_type', 'mk_nation', 'mk_province', 'mk_city', 'mk_district', 'mk_address', 'BillCode', 'BVoucher', 'FIBVoucherDate', 'FiYear', 'ModularDetailCode', 'tbid', 'mk_deleted', 'bid']
    let _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)', '@BillCode nvarchar(50)', '@BVoucher nvarchar(50)', '@FIBVoucherDate nvarchar(50)', '@FiYear nvarchar(50)', '@ModularDetailCode nvarchar(50)', '@bid nvarchar(50)', '@tbid nvarchar(50)', '@mk_deleted int']
    let _select = ['@UserName=\'\'', '@FullName=\'\'', '@RoleID=\'\'', '@mk_departmentcode=\'\'', '@mk_organization=\'\'', '@mk_user_type=\'\'', '@mk_nation=\'\'', '@mk_province=\'\'', '@mk_city=\'\'', '@mk_district=\'\'', '@mk_address=\'\'', '@ErrorCode=\'\'', '@retmsg=\'\'', '@BillCode=\'\'', '@BVoucher=\'\'', '@FIBVoucherDate=\'\'', '@FiYear=\'\'', '@ModularDetailCode=\'\'', '@bid=\'\'', '@mk_deleted=1']
      if (card.formType === 'counter') {
        item.type = 'number'
        item.fieldlen = 0
      } else if (card.formType === 'switch' || card.formType === 'radio') {
        if (typeof(card.openVal) === 'number') {
          item.type = 'number'
          item.fieldlen = 0
        }
      }
    
    let fieldArr = sysfields.map(_f => _f.toLowerCase())
    let hasBid = false
      _fields.push(item)
    } else if (card.modal && (card.OpenType === 'pop' || !card.OpenType)) {
      _fields = fromJS(card.modal.fields || []).toJS()
      _fields = _fields.filter(_f => {
        if (!_f.field) return false
        _f.writein = _f.writein !== 'false'
        _f.fieldlen = _f.fieldlength || 50
        if (_f.type === 'datemonth') {
          _f.type = 'text'
        } else if (_f.type === 'number' || _f.type === 'rate') {
          _f.fieldlen = _f.decimal || 0
        } else if (_f.type === 'date') {
          _f.type = _f.declareType === 'nvarchar(50)' ? 'text' : 'date'
        } else if (_f.type === 'datetime') {
          _f.type = 'date'
        } else if (_f.declare === 'decimal') {
          _f.type = 'number'
          _f.fieldlen = _f.decimal || 0
        }
        return true
      })
    }
    let verIndex = _fields.findIndex(item => item.type === 'vercode')
    if (verIndex > -1) {
      _fields = fromJS(_fields).toJS()
      _fields.splice(verIndex, 0, {
        type: 'text',
        fieldlength: 50,
        writein: 'false',
        fieldlen: 50,
        writein: false,
        field: 'mk_timestamp'
      }, {
        type: 'text',
        fieldlength: 50,
        writein: 'false',
        fieldlen: 50,
        writein: false,
        field: 'mk_send_type'
      }, {
        type: 'text',
        fieldlength: 50,
        writein: 'false',
        fieldlen: 50,
        writein: false,
        field: 'mk_n_id'
      })
    }
    let sysfields = ['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', 'mk_submit_type']
    let hasBid = false
    let formfields = []
    _fields = _fields.filter(_f => _f.field)
    _fields.forEach(_f => {
      let key = _f.field.toLowerCase()
      if (key === 'bid') {
        hasBid = true
      }
      if (fieldArr.includes(key)) return
      fieldArr.push(key)
      if (sysfields.includes(key)) return
      formfields.push(_f.field)
      let _fieldlen = _f.fieldlength || 50
      if (_f.type === 'number') {
        _fieldlen = _f.decimal ? _f.decimal : 0
      }
      if (_fieldlen > 4000) {
        _fieldlen = 'max'
      }
      let _type = `nvarchar(${_fieldlen})`
      if (_f.type.match(/date/ig)) {
        _type = 'datetime'
        _select.push(`@${_f.field}='1949-10-01'`)
      } else if (_f.type === 'number') {
        _type = `decimal(18,${_fieldlen})`
        _select.push(`@${_f.field}=1`)
      } else if (_f.declare === 'decimal') {
        _type = `decimal(18,${_f.decimal || 0})`
        _select.push(`@${_f.field}=1`)
      } else if (_f.type === 'rate') {
        _type = `decimal(18,2)`
        _select.push(`@${_f.field}=1`)
      } else {
        _select.push(`@${_f.field}=''`)
      }
      if (['appkey'].includes(key)) return
      _declare.push(`@${_f.field} ${_type}`)
    })
    let uniqueFields = fromJS(_fields).toJS()
    if (!hasBid) { // 唯一性验证添加BID
      uniqueFields.unshift({ uuid: 'BID', field: 'BID', label: 'BID', type: 'text' })
      _fields.unshift({ uuid: 'BID', field: 'BID', label: 'BID', type: 'text' })
    if (!hasBid) {
      _fields.unshift({ uuid: 'BID', field: 'BID', label: 'BID', type: 'text', writein: false, fieldlen: 50 })
    }
    let unionFields = fromJS(_fields).toJS()
    let formArr = _fields.map(_f => _f.field.toLowerCase())
    let fieldArr = [...sysfields, ...formArr]
    let colfields = []
    if (card.Ot !== 'notRequired' && columns) {
@@ -815,215 +814,14 @@
        let key = _f.field.toLowerCase()
        if (!formArr.includes(key)) {
          formArr.push(key)
        if (formArr.includes(key)) return
          unionFields.push(_f)
        }
        if (fieldArr.includes(key)) return
        fieldArr.push(key)
        colfields.push(_f.field)
        if (_f.datatype) { // 自定义字段
          if (/decimal|int/ig.test(_f.datatype)) {
            _select.push(`@${_f.field}=1`)
          } else if (/date/ig.test(_f.datatype)) {
            _select.push(`@${_f.field}='1949-10-01'`)
          } else {
            _select.push(`@${_f.field}=''`)
          }
          if (['appkey'].includes(key)) return
          _declare.push(`@${_f.field} ${_f.datatype}`)
        } else {
          let _fieldlen = _f.fieldlength || 50
          if (_fieldlen > 4000) {
            _fieldlen = 'max'
          }
          let _type = `nvarchar(${_fieldlen})`
          if (_f.type === 'number') {
            _type = `decimal(18,${_f.decimal ? _f.decimal : 0})`
          } else if (_f.type === 'picture' || _f.type === 'textarea') {
            _type = `nvarchar(${_fieldlen})`
          }
          if (_f.type === 'number') {
            _select.push(`@${_f.field}=1`)
          } else {
            _select.push(`@${_f.field}=''`)
          }
          if (['appkey'].includes(key)) return
          _declare.push(`@${_f.field} ${_type}`)
        }
      })
    }
    let _sql = `Declare ${_declare.join(', ')}
      Select ${_select.join(', ')}
    `
    // 默认sql
    let _defaultsql = ''
    let _insertsql = ''
    let _updatesql = ''
    let _primaryKey = config.setting.primaryKey || 'id'
    if (this.props.side === 'sub') {
      _primaryKey = config.setting.subKey || 'id'
    }
    if (card.sqlType === 'insert' || card.sqlType === 'insertOrUpdate') {
      let keys = []
      let values = []
      _fields.forEach(item => {
        if (!item.field || item.writein === 'false') return
        keys.push(item.field.toLowerCase())
        if (item.field.toLowerCase() === 'bid' && item.uuid === 'BID') {
          values.push('@BID@')
        } else {
          values.push('@' + item.field)
        }
      })
      if (!keys.includes(_primaryKey.toLowerCase())) {
        keys.push(_primaryKey.toLowerCase())
        values.push('@ID@')
      }
      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 ${card.sql} (${keys}) select ${values};`
    }
    if (card.sqlType === 'update' || card.sqlType === 'audit' || card.sqlType === 'insertOrUpdate') {
      let _form = []
      let _arr = []
      _fields.forEach(item => {
        if (!item.field || item.writein === 'false' || item.uuid === 'BID') return
        _arr.push(item.field.toLowerCase())
        if (item.field.toLowerCase() === 'bid') {
          _form.push(item.field + '=@BID@')
        } else {
          _form.push(item.field + '=@' + item.field)
        }
      })
      if (this.props.card.sqlType === '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@')
        }
        if (!_arr.includes('typename')) {
          _form.push(`typename=@typename@`)
        }
      } 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 (!_arr.includes('typename')) {
          _form.push(`typename=@typename@`)
        }
      }
      if (_verify.voucher && _verify.voucher.enabled) {
        if (!_arr.includes('bvoucher')) {
          _form.push('BVoucher=@BVoucher')
        }
        if (!_arr.includes('fibvoucherdate')) {
          _form.push('FIBVoucherDate=@FIBVoucherDate')
        }
        if (!_arr.includes('fiyear')) {
          _form.push('FiYear=@FiYear')
        }
      }
      _form = _form.join(', ')
      _updatesql = `update ${card.sql} set ${_form} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
    }
    if (card.sqlType === 'insert') {
      _defaultsql = _insertsql
    } else if (card.sqlType === 'update' || card.sqlType === 'audit') {
      _defaultsql = _updatesql
    } else if (card.sqlType === 'insertOrUpdate') {
      _defaultsql += `select @tbid=''
        select @tbid='X' from ${card.sql} where ${_primaryKey}=@ID@
        if @tbid=''
          begin
          ${_insertsql}
          end
        else
          begin
          ${_updatesql}
          end
      `
    } else if (card.sqlType === 'LogicDelete' || card.sqlType === 'custom') {
      let _voucher = ''
      if (_verify.voucher && _verify.voucher.enabled) {
        _voucher = ',BVoucher=@BVoucher,FIBVoucherDate=@FIBVoucherDate,FiYear=@FiYear'
      }
      _defaultsql = `update ${card.sql} set deleted=@mk_deleted,modifydate=getdate(),modifyuser=@username,modifystaff=@fullname,modifyuserid=@userid@${_voucher} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
    } else if (card.sqlType === 'delete') {
      let _msg = ''
      if (columns && columns.length > 0 && card.Ot !== 'notRequired') {
        let _index = 0
        columns.forEach(col => {
          if (!col.field || col.Hide === 'true' || _index >= 4) return
          _msg += col.label + '=\'\','
          _index++
        })
      }
      _defaultsql += `insert into snote (remark,createuserid,CreateUser,CreateStaff,typename) select left('删除表:${card.sql} 数据: ${_msg}${_primaryKey}='+@ID@,200),@userid@,@username,@fullname,@typename@ delete ${card.sql} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
    }
    let _columns = []
@@ -1046,13 +844,11 @@
    this.setState({
      fields: _fields,
      columnsFields: _columns,
      initsql: _sql,
      defaultsql: _defaultsql,
      formfields: formfields.join(', '),
      colfields: colfields.join(', '),
      uniqueColumns: this.state.uniqueColumns.map(col => {
        if (col.dataIndex === 'field') {
          col.options = uniqueFields
          col.options = _fields
        }
        return col
      }),
@@ -1062,8 +858,7 @@
        }
        return col
      }),
      unionFields,
      uniqueFields
      unionFields
    })
  }
@@ -1172,6 +967,1014 @@
    })
  }
  getSysExecSql = (verify, retmsg) => {
    const { columns, config, card } = this.props
    const { fields } = this.state
    let btn = card
    let primaryId = Utils.getuuid()
    let BID = Utils.getuuid()
    let _actionType = null
    let setting = config.setting || {}
    if (verify.uniques && verify.uniques.length > 0 && btn.Ot === 'requiredOnce') {
      if (config.wrap && (config.wrap.datatype === 'static' || config.wrap.datatype === 'public')) {
        verify.uniques = []
      }
    }
    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', 'mk_submit_type']
    // 主键字段
    let primaryKey = setting.primaryKey || 'id'
    if (this.props.side === 'sub') {
      primaryKey = setting.subKey || 'id'
    }
    // sql语句
    let _sql = ''
    let _initvars = [] // 已赋值字段集
    let _initFormfields = []
    let _initColfields = []
    let _declarefields = []
    let formdata = fields.filter(item => item.uuid !== 'BID')
    formdata = formdata.length ? formdata : null
    // 获取字段键值对
    formdata && formdata.forEach(form => {
      let _key = form.field.toLowerCase()
      if (!_initvars.includes(_key)) {
        _initvars.push(_key)
        if (form.type === 'number' || form.type === 'rate') {
          _initFormfields.push(`@${form.field}=1`)
        } else if (form.type === 'date') {
          _initFormfields.push(`@${form.field}='1949-10-01'`)
        } else if (form.type === 'select' || form.type === 'link' || form.type === 'radio') {
          _initFormfields.push(`@${form.field}='1'`)
        } else {
          _initFormfields.push(`@${form.field}='mk'`)
        }
      }
      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)`
        }
        if (['appkey'].includes(_key)) return
        _declarefields.push(`@${form.field} ${_type}`)
      }
    })
    // 添加数据中字段,表单值优先(按钮不选行或多行拼接时跳过)
    if (btn.Ot !== 'notRequired' && columns.length > 0) {
      columns.forEach(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(`@${col.field}='1949-10-01'`)
          } else if (col.type === 'number') {
            _initColfields.push(`@${col.field}=1`)
          } else {
            _initColfields.push(`@${col.field}='mk'`)
          }
        }
        if (!_vars.includes(_key) && !['appkey'].includes(_key)) {
          _vars.push(_key)
          _declarefields.push(`@${col.field} ${col.datatype || 'nvarchar(50)'}`)
        }
      })
    }
    // 变量声明
    _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),@mk_submit_type 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}', @mk_submit_type='', @BillCode='', @ModularDetailCode=''
        `
    // 表单变量赋值
    if (_initFormfields.length > 0) {
      _sql += `
        /* 表单变量赋值 */
        select ${_initFormfields.join(',')}
        `
    }
    // 显示列变量赋值
    if (_initColfields.length > 0) {
      _sql += `
        /* 显示列变量赋值 */
        select ${_initColfields.join(',')}
        `
    }
    if (retmsg) {
      return _sql
    }
    // 去除禁用的验证
    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 (verify.invalid === 'true') {
      let datasource = setting.dataresource
      let customScript = ''
      config.scripts && config.scripts.forEach(script => {
        if (script.status === 'false' || script.position === 'back') return
        customScript += `
        ${script.sql}
        `
      })
      if (/\s/.test(datasource)) {
        datasource = '(' + datasource + ') tb'
      }
      let regoptions = [{
        reg: new RegExp('@userName@', 'ig'),
        value: `'${userName}'`
      }, {
        reg: new RegExp('@fullName@', 'ig'),
        value: `'${fullName}'`
      }, {
        reg: new RegExp('@orderBy@', 'ig'),
        value: setting.order || primaryKey
      }, {
        reg: new RegExp('@pageSize@', 'ig'),
        value: 1
      }, {
        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.field.toLowerCase()) // 表单字段
      verify.billcodes.forEach(item => {
        let _key = item.field.toLowerCase()
        let _linkKey = item.linkField ? item.linkField.toLowerCase() : ''
        if (!keys.includes(_key)) return // 表单中不含单号生成字段
        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)`
          }
        } else if (item.TypeCharOne === 'BN') {
          if (_linkKey === 'bid' && BID) { // 替换bid
            _lpline = `set @ModularDetailCode= 'BN'+ right(@BID@,48)`
          } else {
            _lpline = `set @ModularDetailCode= 'BN'+ right(@${_linkKey},48)`
          }
        } else {
          _lpline = `set @ModularDetailCode= right('${item.ModularDetailCode}',50)`
        }
        _billcodesSql += `
        /* 单号生成 */
        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') {
      let dateForms = []
      let numForms = []
      formdata.forEach(form => {
        let _key = form.field.toLowerCase()
        if (form.type === 'date') {
          dateForms.push(_key)
        } else if (form.type === 'number' || form.type === 'rate') {
          numForms.push(_key)
        }
      })
      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 = ''
          arr.push(_key)
          if (_key === 'bid') { // 表单中没有bid则使用系统bid变量
            _val = BID
          } else if (numForms.includes(_key)) {
            _val = '1'
          } else if (dateForms.includes(_key)) {
            _val = '1949-10-01'
          }
          _fieldValue.push(`${_key}='${_val}'`)
          _value.push(`${_labels[index] || ''}:${_val || ''}`)
        })
        if (!arr.includes(primaryKey.toLowerCase())) {
          _fieldValue.push(`${primaryKey} !='${primaryId}'`)
        }
        _sql += `
        /* 唯一性验证 */
        select @tbid='', @ErrorCode='',@retmsg=''
        select @tbid='X' from ${btn.sql} where ${_fieldValue.join(' and ')}${item.verifyType === 'logic' ? ' and deleted=0' : ''}
        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.field.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.field.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 || col.field === primaryKey) 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' && window.GLOB.process) {
      let status = 888
      let statusName = '结束'
      let detailId = '0'
      if (verify.flowSql === 'true') {
        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,bid,createuserid,CreateUser,CreateStaff,upid)
            select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@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@
            insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid,typecharone)
            select @ID@,@works_flow_code@,@userid@,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@,'begin'
          `
        } 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(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname${verify.flowRemark ? ',remark=@' + verify.flowRemark : ''}
            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,bid,createuserid,CreateUser,CreateStaff,upid${verify.flowRemark ? ',remark' : ''})
            select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@${verify.flowRemark ? ',@' + verify.flowRemark : ''}
            update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
            where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
            if @check_userids@ != ''
            begin
                  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
                  update n
                  set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
                  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
          `
        }
      }
      if (_backCustomScript) {
        _sql += _backCustomScript
      }
      _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 (verify.flowType === 'start') {
        _sql = _sql.replace(/@start_type@/ig, `'开始'`)
      } else {
        _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_sign@/ig, `''`)
      }
    } else 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(/@typename@/ig, `'typename'`)
    _sql = _sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, `''`)
    return _sql
  }
  getSysBackSql = (scripts, cbTable) => {
    let _prev = ''
    let _back = ''
    scripts.forEach(script => {
      if (script.status === 'false') return
      if (script.position === 'front') {
        _prev += `
      /* 自定义脚本 */
      ${script.sql}
      `
      } else {
        _back += `
      /* 自定义脚本 */
      ${script.sql}
      `
      }
    })
    if (!_prev) return _back
    let tbs = []
    _prev.replace(/\/\*[^/*]+\*\//g, '').replace(/\n|\r/g, ' ').split(/\sdeclare\s+|\screate\s+table\s+/ig).forEach(line => {
      if (/^\s*(@|#)[a-zA-Z0-9_]+\s+table\s+\(/ig.test(line)) {
        line = line.replace(/\s+table\s+\(/, '(')
      }
      if (!/^\s*(@|#)[a-zA-Z0-9_]+\s*\(/ig.test(line)) return
      let tb = line.match(/(@|#)[a-zA-Z0-9_]+\s*\(.+(\)|date|datetime)\s*\)/ig)
      if (tb && tb.length === 1) {
        tbs.push(tb[0])
      }
    })
    tbs.forEach(tb => {
      let tbName = tb.match(/(@|#)[a-zA-Z0-9_]+/ig)[0]
      if (!tbName) return
      let content = tb.replace(/(@|#)[a-zA-Z0-9_]+\s*\(\s*/, '').replace(/\s*\)$/, '')
      content = content.replace(/decimal\(\s*\d+\s*,\s*\d+\s*\)/ig, 'decimal')
      let keys = []
      let vals = []
      let error = false
      let istop = new RegExp(cbTable + '$', 'ig').test(tbName)
      let id = tbName.replace(/@|#/, '')
      content.split(/\s*,\s*/).forEach(m => {
        let ms = m.split(/\s+/)
        if (ms.length > 1) {
          keys.push(ms[0])
          if (/^mk_level$/i.test(ms[0])) {
            vals.push(istop ? `'1'` : `'2'`)
          } else if (/^mk_id$/i.test(ms[0])) {
            vals.push(istop ? `'${cbTable}'` : `'${id}'`)
          } else if (/^mk_bid$/i.test(ms[0])) {
            vals.push(istop ? `''` : `'${cbTable}'`)
          } else if (/nvarchar/i.test(ms[1])) {
            vals.push(`'mk'`)
          } else if (/date/i.test(ms[1])) {
            vals.push(`'1949-10-01'`)
          } else if (/int|decimal/i.test(ms[1])) {
            vals.push('0')
          } else {
            error = true
          }
        } else {
          error = true
        }
      })
      if (error || vals.length === 0) return
      _prev += `
      Insert into ${tbName} (${keys.join(',')})
      Select ${vals.join(',')}
      `
    })
    return _prev + _back
  }
  getSysDefSql = () => {
    const { columns, config, card } = this.props
    const { fields, verify } = this.state
    let btn = card
    let _actionType = btn.sqlType
    let setting = config.setting || {}
    // 主键字段
    let primaryKey = setting.primaryKey || 'id'
    if (this.props.side === 'sub') {
      primaryKey = setting.subKey || 'id'
    }
    let _sql = ''
    let _insertsql = ''
    if (_actionType === 'insert' || _actionType === 'insertOrUpdate') { // 添加语句
      let keys = []
      let values = []
      fields.forEach(item => {
        if (item.writein === false) return
        let _key = item.field.toLowerCase()
        keys.push(_key)
        values.push('@' + _key)
      })
      if (!keys.includes(primaryKey.toLowerCase())) {
        keys.push(primaryKey.toLowerCase())
        values.push('@ID@')
      }
      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 = []
      fields.forEach(item => {
        if (item.writein === false) return
        let _key = item.field.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@')
        }
      }
      let hasvoucher = false
      // 凭证-显示列中选取,必须选行
      if (verify.voucher && verify.voucher.enabled && btn.Ot !== 'requiredOnce') {
        hasvoucher = true
      }
      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 (_actionType === 'insert') {
      _sql = _insertsql
    } else if (_actionType === 'update' || _actionType === 'audit') {
      _sql = _updatesql
    } else if (_actionType === 'LogicDelete' || _actionType === 'custom') { // 逻辑删除
      let _ID = '=@ID@'
      if (btn.Ot === 'requiredOnce') {
        _ID = ' in (select ID from  dbo.SplitComma(@ID@))'
      }
      _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 || col.field === primaryKey) return
          _msg += col.label + '=0,'
          _index++
        })
      }
      let _ID = '=@ID@'
      if (btn.Ot === 'requiredOnce') {
        _ID = ' in (select ID from  dbo.SplitComma(@ID@))'
      }
      _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
          ${_insertsql}
          end
        else
          begin
          ${_updatesql}
          end
      `
    }
    return _sql
  }
  orderSql = (record) => {
    let _lpline = ''
    if (record.TypeCharOne === 'Lp') {
@@ -1242,7 +2045,7 @@
    this.setState({ verify })
  }
  customChange = (values) => {
  customChange = (values, resolve, reject) => {
    let verify = fromJS(this.state.verify).toJS()
    if (values.uuid) {
@@ -1258,10 +2061,32 @@
      verify.customverifys.push(values)
    }
    if (resolve) {
      let sql = this.getSysExecSql(verify, false)
      Api.sDebug(sql).then(res => {
        if (res.status || res.ErrCode === '-2') {
          resolve()
          this.setState({ verify })
        } else {
          reject()
          Modal.error({
            title: res.message
          })
        }
      })
    } else {
      let sql = this.getSysExecSql(verify, false)
      Api.sDebug(sql, true)
    this.setState({ verify })
  }
  }
  scriptsChange = (values) => {
  scriptsChange = (values, resolve, reject) => {
    const { columns, card } = this.props
    let verify = fromJS(this.state.verify).toJS()
@@ -1308,12 +2133,36 @@
      }
    }
    if (resolve) {
      let sql = this.getSysExecSql(verify, false)
      Api.sDebug(sql).then(res => {
        if (res.status || res.ErrCode === '-2') {
          resolve()
          values && MKEmitter.emit('editLineId', values.uuid)
          this.setState({ verify })
        } else {
          reject()
          Modal.error({
            title: res.message
          })
        }
      })
    } else {
      let sql = this.getSysExecSql(verify, false)
      Api.sDebug(sql, true)
    MKEmitter.emit('editLineId', values.uuid)
    this.setState({ verify })
  }
  }
  cbScriptsChange = (values) => {
  cbScriptsChange = (values, resolve, reject) => {
    const { card } = this.props
    let verify = fromJS(this.state.verify).toJS()
    if (values.uuid) {
@@ -1329,9 +2178,75 @@
      verify.cbScripts.push(values)
    }
    if (resolve) {
      let sql = this.getSysBackSql(verify.cbScripts, card.cbTable)
      if (sql) {
        let defSql = this.getSysExecSql(verify, true)
        sql = `${defSql}
          ${sql}
        `
        if (card.output) {
          sql += `
            aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg,${card.output} as mk_b_id`
        } else {
          sql += `
            aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
        }
        sql = sql.replace(/@typename@/ig, `'typename'`)
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, `''`)
        Api.sDebug(sql).then(res => {
          if (res.status || res.ErrCode === '-2') {
            resolve()
    MKEmitter.emit('editLineId', values.uuid)
    this.setState({ verify })
          } else {
            reject()
            Modal.error({
              title: res.message
            })
          }
        })
      } else {
        MKEmitter.emit('editLineId', values.uuid)
        this.setState({ verify })
      }
    } else {
      let sql = this.getSysBackSql(verify.cbScripts, card.cbTable)
      if (sql) {
        let defSql = this.getSysExecSql(verify, true)
        sql = `${defSql}
          ${sql}
        `
        if (card.output) {
          sql += `
            aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg,${card.output} as mk_b_id`
        } else {
          sql += `
            aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
        }
        sql = sql.replace(/@typename@/ig, `'typename'`)
        sql = sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, `''`)
        Api.sDebug(sql, true)
      }
      MKEmitter.emit('editLineId', values.uuid)
      this.setState({ verify })
    }
  }
  orderChange = (values) => {
@@ -1682,7 +2597,7 @@
  render() {
    const { card, columns } = this.props
    const { activeKey, verifyInter, verify, fields, uniqueFields, uniqueColumns, unionFields, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, cbScriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes, emailCodes, appType, formfields, colfields } = this.state
    const { activeKey, verifyInter, verify, fields, uniqueColumns, unionFields, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, cbScriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes, emailCodes, appType, formfields, colfields } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -1723,7 +2638,6 @@
          } key="customverifys" id="mk-custom-script">
            <CustomForm
              btn={this.props.card}
              initsql={this.state.initsql}
              formfields={formfields}
              colfields={colfields}
              customChange={this.customChange}
@@ -1757,7 +2671,7 @@
          } key="uniques">
            <UniqueForm
              btn={card}
              fields={card.Ot !== 'requiredOnce' ? uniqueFields : columnsFields}
              fields={card.Ot !== 'requiredOnce' ? fields : columnsFields}
              uniqueChange={this.uniqueChange}
            />
            <EditTable actions={['edit', 'move', 'del', 'status', 'sql']} data={verify.uniques} columns={card.Ot !== 'requiredOnce' ? uniqueColumns : onceUniqueColumns} onChange={this.changeUniques}/>
@@ -1793,14 +2707,10 @@
              <CustomScript
                type="fullscreen"
                btn={this.props.card}
                initsql={this.state.initsql}
                workFlow={verify.workFlow}
                flowRemark={verify.flowRemark}
                flowType={verify.flowType}
                flowSql={verify.flowSql}
                customScripts={verify.scripts}
                useDefaultSql={verify.default !== 'false'}
                defaultsql={this.state.defaultsql}
                formfields={formfields}
                colfields={colfields}
                systemScripts={this.state.systemScripts}
@@ -1810,14 +2720,11 @@
            </FullScripts>
            <CustomScript
              btn={this.props.card}
              initsql={this.state.initsql}
              workFlow={verify.workFlow}
              flowRemark={verify.flowRemark}
              flowType={verify.flowType}
              flowSql={verify.flowSql}
              customScripts={verify.scripts}
              useDefaultSql={verify.default !== 'false'}
              defaultsql={this.state.defaultsql}
              getSysDefSql={this.getSysDefSql}
              formfields={formfields}
              colfields={colfields}
              systemScripts={this.state.systemScripts}
@@ -1842,23 +2749,19 @@
              <CallBackCustomScript
                type="fullscreen"
                btn={this.props.card}
                initsql={this.state.initsql}
                customScripts={verify.cbScripts}
                formfields={formfields}
                colfields={colfields}
                systemScripts={this.state.systemScripts}
                scriptsChange={this.cbScriptsChange}
                cbScriptsChange={this.cbScriptsChange}
                wrappedComponentRef={(inst) => this.cbscriptsFullForm = inst}
              />
            </FullScripts>
            <CallBackCustomScript
              btn={this.props.card}
              initsql={this.state.initsql}
              customScripts={verify.cbScripts}
              formfields={formfields}
              colfields={colfields}
              systemScripts={this.state.systemScripts}
              scriptsChange={this.cbScriptsChange}
              cbScriptsChange={this.cbScriptsChange}
              wrappedComponentRef={(inst) => this.cbscriptsForm = inst}
            />
            <EditTable actions={['move']} data={verify.cbScripts} columns={cbScriptsColumns} onChange={(cbScripts) => {this.setState({verify: {...verify, cbScripts}})}}/>
src/utils/option.js
@@ -360,6 +360,45 @@
  text: '白底紫框'
}]
// 按钮颜色集
export const modalClasses = [{
  value: 'primary',
  text: '蓝色'
}, {
  value: 'yellow',
  text: '黄色'
}, {
  value: 'orange',
  text: '橙色'
}, {
  value: 'danger',
  text: '红色'
}, {
  value: 'green',
  text: '绿色'
}, {
  value: 'purple',
  text: '紫色'
}, {
  value: 'border-primary',
  text: '白底蓝框'
}, {
  value: 'border-yellow',
  text: '白底黄框'
}, {
  value: 'border-orange',
  text: '白底橙框'
}, {
  value: 'border-danger',
  text: '白底红框'
}, {
  value: 'border-green',
  text: '白底绿框'
}, {
  value: 'border-purple',
  text: '白底紫框'
}]
export const calendarColors = [
  {name: 'red', value: '#d0021b'},
  {name: 'orange', value: '#f5a623'},
src/utils/utils-custom.js
@@ -3084,11 +3084,18 @@
GOTO_RETURN:
  ROLLBACK TRAN`
  let filterComponent = (components, mainSearch, label = '') => {
  let filterComponent = (components, mainSearch, label = '', ispop) => {
    components.forEach(item => {
      item.$menuname = (config.MenuName || '') + label + '-' + (item.name || '')
      if (item.type === 'tabs') {
        if (config.Template === 'BaseTable') {
          item.subtabs.forEach(tab => {
            if (tab.permission !== 'true' && tab.components[0] && tab.components[0].wrap) {
              tab.components[0].wrap.permission = 'false'
            }
          })
        }
        item.subtabs.forEach(tab => {
          let _mainSearch = mainSearch || []
@@ -3099,10 +3106,11 @@
              _mainSearch = com.search || []
            })
          }
          filterComponent(tab.components, _mainSearch, label)
          filterComponent(tab.components, _mainSearch, label, ispop)
        })
      } else if (item.type === 'group') {
        filterComponent(item.components, mainSearch, label)
        filterComponent(item.components, mainSearch, label, ispop)
      } else {
        if (item.wrap && item.setting) {
          if (item.wrap.datatype === 'public' || item.wrap.datatype === 'static') {
@@ -3140,6 +3148,8 @@
            roleId = ''
          } else if (item.setting.database === 'sso') {
            roleId = ''
          } else if (ispop) {
            roleId = ''
          }
          sqls.push({uuid: item.uuid, roleId: roleId, type: 'datasource', ...msg})
@@ -3154,7 +3164,7 @@
        item.action && item.action.forEach(cell => {
          if (cell.hidden === 'true') return false
          
          resetButton(item, cell)
          resetButton(item, cell, false, ispop)
        })
        if (item.type === 'table') {
@@ -3169,7 +3179,7 @@
                col.elements.forEach(cell => {
                  if (cell.eleType !== 'button' || cell.hidden === 'true') return
                  
                  resetButton(item, cell)
                  resetButton(item, cell, false, ispop)
                })
              } else if (item.subtype === 'editable' && col.editable === 'true') {
                if (col.editType === 'select' && col.resourceType === '1') {
@@ -3206,7 +3216,7 @@
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              
              resetButton(item, cell)
              resetButton(item, cell, false, ispop)
            })
  
            if (!card.backElements || card.backElements.length === 0) return
@@ -3214,14 +3224,14 @@
            card.backElements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              
              resetButton(item, cell, true)
              resetButton(item, cell, true, ispop)
            })
          })
        } else if (item.type === 'balcony') {
          item.elements.forEach(cell => {
            if (cell.eleType !== 'button' || cell.hidden === 'true') return
            
            resetButton(item, cell)
            resetButton(item, cell, false, ispop)
          })
        } else if (item.type === 'form') {
          item.subcards.forEach(group => {
@@ -3234,7 +3244,7 @@
              fields: group.fields
            }
            resetButton(item, group.subButton)
            resetButton(item, group.subButton, false, ispop)
          })
        } else if (item.type === 'module' && item.subtype === 'invoice') {
          if (item.buyer.setting && item.buyer.setting.interType === 'system') {
@@ -3265,7 +3275,7 @@
    })
  }
  let resetButton = (item, cell, isback) => {
  let resetButton = (item, cell, isback, ispop) => {
    cell.logLabel = item.$menuname + '-' + cell.label
    let roleId = cell.uuid
    if (item.wrap && item.wrap.permission === 'false') {
@@ -3273,6 +3283,8 @@
    } else if (cell.hidden === 'true' || cell.permission === 'false') {
      roleId = ''
    } else if (cell.database === 'sso') {
      roleId = ''
    } else if (ispop) {
      roleId = ''
    }
@@ -3378,7 +3390,7 @@
        sqls.push({uuid: cell.uuid, roleId: roleId, type: 'pay', ...msg})
      }
    } else if (cell.OpenType === 'popview') {
      if (cell.config && cell.config.components) {
      if (cell.config && cell.config.components && cell.config.enabled) {
        let _mainSearch = []
        if (appType === 'mob') {
@@ -3402,7 +3414,7 @@
          })
        }
        filterComponent(cell.config.components, _mainSearch, '-' + cell.label)
        filterComponent(cell.config.components, _mainSearch, '-' + cell.label, true)
      }
    }
  }
@@ -4393,6 +4405,12 @@
      }
    })
    if (new RegExp('@mk_submit_type[^0-9a-z_]', 'ig').test(_sql)) {
      decSql.push(`@mk_submit_type nvarchar(50)`)
      secSql.push(`@mk_submit_type=@mk_submit_type@`)
      reps.push('mk_submit_type')
    }
    decSql = [...decSql, ..._declares]
    // INSERT INTO s_paas_api_log (appkey,api_name,api_count,menuname,createuserid,createuser,createstaff,cdefine1,cdefine2) 
@@ -4427,10 +4445,6 @@
      return true
    })
    reps.forEach(n => {
      _sql = _sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(_sql)) {
      _sql = _sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
@@ -4445,6 +4459,11 @@
        reps.push('mk_check_begin', 'mk_check_end')
      }
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end', 'mk_check_begin', 'mk_check_end'].includes(n)) return
      _sql = _sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(_sql)) {
      reps.push('db')
    }
@@ -4705,6 +4724,12 @@
      }
    })
    if (new RegExp('@mk_submit_type[^0-9a-z_]', 'ig').test(_sql)) {
      decSql.push(`@mk_submit_type nvarchar(50)`)
      secSql.push(`@mk_submit_type=@mk_submit_type@`)
      reps.push('mk_submit_type')
    }
    decSql = [...decSql, ..._declares]
    _sql = `/* ${btn.logLabel}(回调) */
@@ -4737,14 +4762,15 @@
      return true
    })
    reps.forEach(n => {
      _sql = _sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(_sql)) {
      _sql = _sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end'].includes(n)) return
      _sql = _sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(_sql)) {
      reps.push('db')
    }
@@ -4876,7 +4902,7 @@
    let DateCount = ''
    if (_dataresource) {
      /*system_query*/
      if (/@pageSize@|@orderBy@|@mk_total/i.test(testSql)) {
      if (/@pageSize@|@orderBy@|@mk_total/i.test(testSql) || (item.wrap && item.wrap.tree === 'true')) {
        LText = `select ${arr_field} from ${_dataresource} ${_search} `
      } else if (item.setting.laypage === 'true' && item.setting.order) {
        LText = `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 `
@@ -5012,15 +5038,15 @@
      return true
    })
    
    reps.forEach(n => {
      if (['orderBy', 'pageSize', 'pageIndex'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(sql)) {
      sql = sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['orderBy', 'pageSize', 'pageIndex', 'datam_begin', 'datam_end'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(sql)) {
      reps.push('db')
    }
@@ -5315,10 +5341,6 @@
      return true
    })
    reps.forEach(n => {
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(sql)) {
      sql = sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
@@ -5327,6 +5349,12 @@
      sql = sql.replace(/\$check@/ig, '@mk_check_begin@').replace(/@check\$/ig, '@mk_check_end@')
      reps.push('mk_check_begin', 'mk_check_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end', 'mk_check_begin', 'mk_check_end'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(sql)) {
      reps.push('db')
    }
@@ -5591,14 +5619,15 @@
      return true
    })
    reps.forEach(n => {
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(sql)) {
      sql = sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(sql)) {
      reps.push('db')
    }
@@ -5875,14 +5904,15 @@
      return true
    })
    reps.forEach(n => {
      _sql = _sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(_sql)) {
      _sql = _sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end'].includes(n)) return
      _sql = _sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(_sql)) {
      reps.push('db')
    }
@@ -5988,14 +6018,15 @@
    reps.push(...sysVars)
    reps.forEach(n => {
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(sql)) {
      sql = sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(sql)) {
      reps.push('db')
    }
@@ -6113,15 +6144,15 @@
      return true
    })
    reps.forEach(n => {
      if (['orderBy', 'pageSize', 'pageIndex'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(sql)) {
      sql = sql.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['orderBy', 'pageSize', 'pageIndex', 'datam_begin', 'datam_end'].includes(n)) return
      sql = sql.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(sql)) {
      reps.push('db')
    }
@@ -6160,13 +6191,15 @@
      }
    })
    reps.forEach(n => {
      _script = _script.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(_script)) {
      _script = _script.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end'].includes(n)) return
      _script = _script.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(_script)) {
      reps.push('db')
    }
@@ -6282,15 +6315,17 @@
      }
    })
    reps.forEach(n => {
      _prev = _prev.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
      _back = _back.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/\$@/ig.test(testSql)) {
      _prev = _prev.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      _back = _back.replace(/\$@/ig, '@datam_begin@').replace(/@\$/ig, '@datam_end@')
      reps.push('datam_begin', 'datam_end')
    }
    reps.forEach(n => {
      if (['datam_begin', 'datam_end'].includes(n)) return
      _prev = _prev.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
      _back = _back.replace(new RegExp('@' + n + '@', 'ig'), `'@${n}@'`)
    })
    if (/@db@/ig.test(testSql)) {
      reps.push('db')
    }
src/utils/utils.js
@@ -1771,7 +1771,7 @@
 * @return {Array}   columns   显示列
 * @return {Boolean} retmsg    是否需要数据返回
 */
export function getSysDefaultSql (btn, setting, formdata, param, data, columns, retmsg = false) {
export function getSysDefaultSql (btn, setting, formdata, param, data, columns, retmsg = false, submitType = '') {
  let primaryId = param.ID
  let BID = param.BID || ''
  let verify = btn.verify || {}
@@ -1809,7 +1809,7 @@
  })
  // 需要声明的变量集
  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 _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', 'mk_submit_type']
  // 主键字段
  let primaryKey = setting.primaryKey || 'id'
@@ -1942,7 +1942,7 @@
    _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}
      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),@mk_submit_type nvarchar(50)${_declarefields}
    `
  let userName = sessionStorage.getItem('User_Name') || '' 
@@ -1960,7 +1960,7 @@
  // 初始化凭证及用户信息字段
  _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=''
      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}', @mk_submit_type='${submitType}', @BillCode='', @ModularDetailCode=''
      `
  // 表单变量赋值
src/views/appmanage/index.jsx
@@ -495,7 +495,6 @@
              }
              cell.userbind = _param.userbind || ''
              cell.instantMessage = _param.instantMessage || ''
            }
            if (cell.user_binding !== 'true') {
@@ -670,7 +669,6 @@
    sublist = sublist.map(item => {
      if (item.typename !== 'pc') {
        item.userbind = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{8}/, 'userbind')
        item.instantMessage = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{14}/, 'instantmessage')
      }
      return item
    })
@@ -951,7 +949,6 @@
        selectApp.sublist = selectApp.sublist.map(item => {
          if (item.typename !== 'pc') {
            item.userbind = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{8}/, 'userbind')
            item.instantMessage = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{14}/, 'instantmessage')
          }
          return item
        })
@@ -1005,9 +1002,6 @@
    }
    if (item.userbind) {
      _par.userbind = item.userbind
    }
    if (item.instantMessage) {
      _par.instantMessage = item.instantMessage
    }
    if (item.apptype) {
      _par.apptype = item.apptype
@@ -1098,7 +1092,6 @@
      sublist = sublist.map(item => {
        if (item.typename !== 'pc') {
          item.userbind = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{8}/, 'userbind')
          item.instantMessage = md5(selectApp.kei_no + item.typename + item.lang).replace(/^.{14}/, 'instantmessage')
        }
        return item
      })
src/views/appmanage/transmenu/index.jsx
@@ -97,7 +97,7 @@
      if (result.status) {
        let menus = []
        result.menus.forEach(item => {
          if (zhApp.userbind === item.MenuID || zhApp.instantMessage === item.MenuID) return
          if (zhApp.userbind === item.MenuID) return
          
          menus.push(item)
        })
src/views/billprint/index.jsx
@@ -99,10 +99,22 @@
        configurable: true,
        enumerable: true,
        set(value) {
          if (value + '' === 'false') {
            window.GLOB.debugger = false
          } else {
          if (value === true) {
            window.GLOB.debugger = true
          } else if (value === 0) {
            if (window.backend) {
              sessionStorage.setItem('systemRun', 'front')
              window.location.reload()
            } else {
              window.mkInfo('系统当前未使用后端脚本!')
            }
          } else if (value === false) {
            if (sessionStorage.getItem('systemRun') === 'front') {
              sessionStorage.removeItem('systemRun')
              window.location.reload()
            } else {
              window.GLOB.debugger = false
            }
          }
        }
      })
src/views/design/sidemenu/index.jsx
@@ -330,7 +330,7 @@
                {item.children.map(cell => {
                  return (
                    <Menu.Item key={cell.MenuID}>
                      <span className={'editable-menu-item ' + (cell.up_action ? 'unupdate' : '') + (window.backend && window.GLOB.systemType !== 'production' && cell.PageParam.backend !== 'level1' ? ' unbackend' : '')} onDoubleClick={() => this.editmenu(cell)}>{cell.PageParam.interfaces === 'true' ? <ApiOutlined title="菜单中使用了外部接口" /> : null}{cell.PageParam.msg === 'true' ? <SoundOutlined title="菜单中发送了消息" /> : null}{cell.MenuName}{cell.PageParam.pds === 'true' ? <DatabaseOutlined style={{marginLeft: '5px', color: 'inherit'}} title="菜单中使用了公共数据源" /> : null}</span>
                      <span className={'editable-menu-item ' + (cell.up_action ? 'unupdate' : '') + (window.backend && window.GLOB.systemType !== 'production' && cell.PageParam.backend !== 'level1' ? ' unbackend' : '')} onDoubleClick={() => this.editmenu(cell)}>{cell.PageParam.interfaces === 'true' ? <ApiOutlined title="菜单中使用了外部接口" /> : null}{cell.PageParam.msg === 'true' ? <SoundOutlined title="菜单中发送了消息" /> : null}{cell.MenuName}{cell.PageParam.pds === 'true' ? <DatabaseOutlined style={{marginLeft: '5px', color: 'orange'}} title="菜单中使用了公共数据源" /> : null}</span>
                    </Menu.Item>
                  )
                })}
src/views/main/index.jsx
@@ -32,10 +32,22 @@
        configurable: true,
        enumerable: true,
        set(value) {
          if (value + '' === 'false') {
            window.GLOB.debugger = false
          } else {
          if (value === true) {
            window.GLOB.debugger = true
          } else if (value === 0) {
            if (window.backend) {
              sessionStorage.setItem('systemRun', 'front')
              window.location.reload()
            } else {
              window.mkInfo('系统当前未使用后端脚本!')
            }
          } else if (value === false) {
            if (sessionStorage.getItem('systemRun') === 'front') {
              sessionStorage.removeItem('systemRun')
              window.location.reload()
            } else {
              window.GLOB.debugger = false
            }
          }
        }
      })
src/views/mkiframe/index.jsx
@@ -124,10 +124,22 @@
        configurable: true,
        enumerable: true,
        set(value) {
          if (value + '' === 'false') {
            window.GLOB.debugger = false
          } else {
          if (value === true) {
            window.GLOB.debugger = true
          } else if (value === 0) {
            if (window.backend) {
              sessionStorage.setItem('systemRun', 'front')
              window.location.reload()
            } else {
              window.mkInfo('系统当前未使用后端脚本!')
            }
          } else if (value === false) {
            if (sessionStorage.getItem('systemRun') === 'front') {
              sessionStorage.removeItem('systemRun')
              window.location.reload()
            } else {
              window.GLOB.debugger = false
            }
          }
        }
      })
src/views/mobdesign/index.jsx
@@ -114,7 +114,6 @@
        sessionStorage.setItem('sysBgColor', param.sysBgColor || '#ffffff')
        sessionStorage.setItem('direction', param.direction || 'vertical')
        sessionStorage.setItem('userbind', param.userbind || '')
        sessionStorage.setItem('instantMessage', param.instantMessage || '')
        if (param.applangList) {
          sessionStorage.setItem('applangList', param.applangList)
@@ -765,9 +764,6 @@
      // if (sessionStorage.getItem('userbind')) {
      //   appIndeList = appIndeList + ',' + sessionStorage.getItem('userbind')
      // }
      if (sessionStorage.getItem('instantMessage')) {
        appIndeList = appIndeList + ',' + sessionStorage.getItem('instantMessage')
      }
      let menus = res.menus.filter(item => appIndeList.indexOf(item.MenuID) === -1)
      menus = menus.map(item => {
src/views/rolemanage/index.jsx
@@ -30,7 +30,7 @@
          if (record.extra || this.state.appKeys.includes(record.MenuID)) {
            return <span className={className} style={{color: '#1890ff'}}>{text}</span>
          } else if (record.interfaces === 'true' || record.msg === 'true' || record.pds === 'true') {
            return <span className={className}>{record.interfaces === 'true' ? <ApiOutlined style={{color: 'orange', marginRight: '5px'}} title="菜单中使用了外部接口" /> : null}{record.msg === 'true' ? <SoundOutlined style={{color: 'orange', marginRight: '5px'}} title="菜单中发送了消息" /> : null}{text}{record.pds === 'true' ? <DatabaseOutlined style={{marginLeft: '5px'}} title="菜单中使用了公共数据源" /> : null}</span>
            return <span className={className}>{record.interfaces === 'true' ? <ApiOutlined style={{color: 'orange', marginRight: '5px'}} title="菜单中使用了外部接口" /> : null}{record.msg === 'true' ? <SoundOutlined style={{color: 'orange', marginRight: '5px'}} title="菜单中发送了消息" /> : null}{text}{record.pds === 'true' ? <DatabaseOutlined style={{color: 'orange', marginLeft: '5px'}} title="菜单中使用了公共数据源" /> : null}</span>
          }
          return <span className={className}>{text}</span>
        }
@@ -148,7 +148,6 @@
    Api.getCloudConfig(param).then(result => {
      if (result.status) {
        let ub = app.user_binding === 'true' && app.userbind ? false : true
        let im = app.instantMessage ? false : true
        let menus = result.menus.map(item => {
          item.nodes = ''
@@ -166,15 +165,13 @@
                item.type = pageParam.type
              }
              if (item.type === 'navbar' || item.type === 'im') {
              if (item.type === 'navbar') {
                item.backend = 'level1'
              }
              if (pageParam.version !== '1.0') {
                item.nodes = ''
              } else if (pageParam.login || pageParam.pass) {
                item.nodes = ''
              } else if (pageParam.type === 'im') {
                item.nodes = ''
              }
            } catch (e) {
@@ -188,17 +185,10 @@
            item.extra = true
            ub = true
          }
          if (app.instantMessage === item.MenuID) {
            item.extra = true
            im = true
          }
          
          return item
        })
        if (!im) {
          menus.push({nodes: '', type: 'none', backend: 'level1', extra: true, MenuID: app.instantMessage, MenuName: '即时通信'})
        }
        if (!ub) {
          menus.push({nodes: '', type: 'none', backend: 'level1', extra: true, MenuID: app.userbind, MenuName: '用户绑定'})
        }
@@ -554,8 +544,6 @@
                      item.nodes = ''
                    } else if (pageParam.login || pageParam.pass) {
                      item.nodes = ''
                    } else if (pageParam.type === 'im') {
                      item.nodes = ''
                    }
                  } catch (e) {
                    item.nodes = ''
@@ -893,10 +881,6 @@
        duration: 5
      })
      return
    }
    if (app.instantMessage && item.MenuID === app.instantMessage) {
      route = 'imdesign'
    }
    window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify({...app, MenuID: item.MenuID, type: 'app'})))}`))