king
2024-06-01 4cc738e535d1a20701d206e12cf9de8cc5a01170
Merge branch 'develop'
69个文件已修改
6个文件已添加
3519 ■■■■■ 已修改文件
public/README.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/options.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/design.scss 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/map.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkRadio/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkSelect/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/options.jsx 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/options.jsx 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/prop-card/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/editor/braft-editor/options.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.jsx 112 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.scss 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/index.jsx 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/options.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.jsx 112 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/tableIn/index.jsx 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/options.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/debug/index.jsx 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/formfork/index.jsx 376 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/formfork/index.scss 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.jsx 133 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.scss 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecombcontroller/index.scss 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/index.scss 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/txmap/index.jsx 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/txmap/index.scss 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/txmap/options.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/card.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/index.jsx 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modulesource/option.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/basetable/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/balcony/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/balcony/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-X6/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/invoice/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/base-table/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 275 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 266 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkSelect/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx 138 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/baseform/index.jsx 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/README.txt
@@ -14,6 +14,7 @@
nginx             -- 是否开启了nginx服务,值为 true 时开启,如需使用微信模板消息等服务,请先设置nginx服务并开启此配置
debugger          -- 值为 true 时开启调试模式,开启后移动端子应用中会有控制台
licenseKey        -- 许可密钥,在内部网络中使用系统时,会跳过epc验证
storeKey          -- 电子档案本地授权码,使用本地许可密钥时有效
probation         -- 试用期(YYYY-MM-DD),在正式系统中,试用期内调用系统接口的脚本会记录下来
transfer          -- 是否使用转接口,使用转接口时请设置为 true, 使用转接口时,外部接口调用前不会做登录验证
keepPassword      -- 记住密码,默认开启,当值为 false 时禁用
public/options.json
@@ -14,6 +14,7 @@
  "nginx": "true",
  "debugger": false,
  "licenseKey": "",
  "storeKey": "",
  "probation": "",
  "transfer": "false",
  "keepPassword": "true",
src/api/index.js
@@ -865,8 +865,8 @@
    if (script) {
      try {
        // eslint-disable-next-line
        let func = new Function('axios', 'Api', 'param', 'position', 'systemType', script)
        let promise = func(axios, this, param, position, window.GLOB.systemType)
        let func = new Function('axios', 'Api', 'param', 'position', 'systemType', 'notification', script)
        let promise = func(axios, this, param, position, window.GLOB.systemType, notification)
        if (promise instanceof Promise) {
          return promise
src/assets/css/design.scss
@@ -110,3 +110,27 @@
  }
}
// 表单工具
.mk-form-tool {
  float: right;
  padding-right: 15px;
  .anticon {
    margin-right: 15px;
    font-size: 16px;
    cursor: pointer!important;
    position: relative;
    top: 2px;
  }
  .anticon-copy {
    color: #26C281;
  }
  .anticon-swap {
    color: #1890ff;
  }
  .anticon-fork {
    color: purple;
  }
  .anticon-delete {
    color: #f5222d;
  }
}
src/assets/img/map.jpg
src/components/header/index.jsx
@@ -578,6 +578,8 @@
          } else {
            Api.updateAppVersion()
            Api.delCacheConfig('all')
            localStorage.removeItem(window.location.href.split('#')[0] + 'AuthCode')
            setTimeout(() => {
              notification.success({
                top: 92,
src/components/normalform/modalform/index.jsx
@@ -7,7 +7,6 @@
import asyncComponent from '@/utils/asyncComponent'
import MKEInput from './mkInput'
import MKNumberInput from './mkNumberInput'
import MKEmitter from '@/utils/events.js'
import MKSelect from './mkSelect'
import './index.scss'
@@ -155,7 +154,7 @@
      if (item.linkField) {
        let supInitVal = fieldMap.get(item.linkField).initval || ''
        
        item.options = item.oriOptions.filter(option => option.ParentID === supInitVal)
        item.options = item.oriOptions.filter(option => option.ParentID === supInitVal || option.ParentID === '')
      }
      return item
@@ -243,32 +242,29 @@
          if (item && item.linkField) {
            let supInitVal = this.record[item.linkField] || ''
            
            item.options = item.oriOptions.filter(option => option.ParentID === supInitVal)
            item.options = item.oriOptions.filter(option => option.ParentID === supInitVal || option.ParentID === '')
          }
          return item || cell
        })
      })
    } else if (item.reset_source) {
      let map = new Map()
      this.state.formlist.forEach(cell => {
        if (!cell.field) return
        map.set(cell.field, cell)
      })
      let reOptions = item.callback(this.record)
      item.callback(map, this.record, MKEmitter)
      if (reOptions) {
      this.setState({
        formlist: this.state.formlist.map(cell => {
          if (!cell.field) return cell
            if (!cell.field || !reOptions[cell.field]) return cell
          let item = map.get(cell.field)
            cell.options = reOptions[cell.field]
            cell.timestamp = new Date().getTime()
          return item || cell
            return cell
        })
      })
    }
  }
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
src/components/normalform/modalform/mkRadio/index.jsx
@@ -22,6 +22,15 @@
    MKEmitter.addListener('mkFC', this.mkFormControl)
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (nextProps.config.timestamp && nextProps.config.timestamp !== this.state.config.timestamp) {
      this.setState({
        config: fromJS(nextProps.config).toJS(),
        options: fromJS(nextProps.config.options).toJS(),
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
@@ -48,7 +57,7 @@
    if (field !== config.field) return
    let options = config.oriOptions ? config.oriOptions.filter(option => option.ParentID === parentId) : []
    let options = config.oriOptions ? config.oriOptions.filter(option => option.ParentID === parentId || option.ParentID === '') : []
    let val = options[0] ? options[0].value : ''
    this.setState({
src/components/normalform/modalform/mkSelect/index.jsx
@@ -31,6 +31,15 @@
    MKEmitter.addListener('mkFC', this.mkFormControl)
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (nextProps.config.timestamp && nextProps.config.timestamp !== this.state.config.timestamp) {
      this.setState({
        config: fromJS(nextProps.config).toJS(),
        options: fromJS(nextProps.config.options).toJS(),
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
@@ -57,7 +66,7 @@
    const { config } = this.state
    let options = config.oriOptions ? config.oriOptions.filter(option => option.ParentID === parentId) : []
    let options = config.oriOptions ? config.oriOptions.filter(option => option.ParentID === parentId || option.ParentID === '') : []
    let val = options[0] ? options[0].value : ''
    this.setState({
src/index.js
@@ -254,6 +254,31 @@
    let lang = localStorage.getItem(_href + 'lang') || (config.defaultLang !== 'en-US' ? 'zh-CN' : 'en-US')
    sessionStorage.setItem('lang', lang)
    if (localStorage.getItem(_href + 'files') === md5(_href + 'files')) {
      let d = localStorage.getItem(_href + 'filesDate')
      GLOB.storeFiles = true
      GLOB.storeDate = Math.ceil((new Date(d).getTime() - new Date().getTime()) / 86400000)
    } else if (GLOB.licenseKey && config.storeKey && config.storeKey.length === 16) {
      let trans = {A:0, B:1, C:2, D:3, E:4, F:5, G:6, H:7, I:8, J:9}
      let d = config.storeKey.slice(0, 8)
      d = d.split('').map(k => trans[k]).join('')
      let key = config.storeKey.slice(8)
      let _key = GLOB.appId + GLOB.appkey + 'e_files_key' + d
      _key = md5(_key.toLowerCase())
      _key = _key.toUpperCase()
      _key = _key.slice(-8)
      if (key === _key) {
        GLOB.storeFiles = true
        d = d.slice(0, 4) + '-' + d.slice(4, 6) + '-' + d.slice(6)
        GLOB.storeDate = Math.ceil((new Date(d).getTime() - new Date().getTime()) / 86400000)
      }
    }
    GLOB.mkActions = {}  // 按钮权限集
    Object.defineProperty(GLOB, 'appId', {
src/menu/components/card/balcony/index.jsx
@@ -6,7 +6,7 @@
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { resetStyle, getTables, checkComponent } from '@/utils/utils-custom.js'
import { resetStyle, getTables, checkComponent, getInterfaces } from '@/utils/utils-custom.js'
import MKEmitter from '@/utils/events.js'
import Utils from '@/utils/utils.js'
import getWrapForm from './options'
@@ -243,9 +243,9 @@
    let _card = {...this.state.card, wrap: res}
    if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let interfaces = getInterfaces()
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      let d = interfaces.filter(m => m.value === res.publicId)[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
src/menu/components/card/balcony/options.jsx
@@ -1,5 +1,5 @@
import React from 'react'
import MenuUtils from '@/utils/utils-custom.js'
import MenuUtils, { getLinkModules, getInterfaces } from '@/utils/utils-custom.js'
/**
 * @description Wrap表单配置信息
@@ -9,22 +9,12 @@
  let isprint = sessionStorage.getItem('MenuType') === 'billPrint'
  let ispop = sessionStorage.getItem('editMenuType') === 'popview'
  let modules = MenuUtils.getLinkModules(menu.components) || []
  let modules = getLinkModules(menu.components) || []
  let supmodules = MenuUtils.getSupModules(menu.components, '', menu.interfaces)
  let roleList = sessionStorage.getItem('sysRoles')
  let appType = sessionStorage.getItem('appType')
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
        })
      }
    })
  }
  let interfaces = getInterfaces()
  if (roleList) {
    try {
@@ -61,7 +51,7 @@
      field: 'datatype',
      label: '数据来源',
      initval: wrap.datatype || 'static',
      tooltip: '选择静态值,无需配置数据源。',
      tooltip: '选择静态时,无需配置数据源,可展示上级组件或url参数字段。',
      required: false,
      options: [
        {value: 'dynamic', label: '动态'},
@@ -82,23 +72,15 @@
      required: true,
      options: interfaces,
      reset_source: true,
      callback: (map, record) => {
      callback: (record) => {
        if (!record.publicId) return
        let interfaces = window.GLOB.customMenu.interfaces || []
        let d = interfaces.filter(m => m.uuid === record.publicId && m.status === 'true')[0]
        let d = interfaces.filter(m => m.value === record.publicId)[0]
        if (!d || !d.columns) return
        let columns = JSON.parse(JSON.stringify(d.columns))
        let _bgField = map.get('bgField')
        if (_bgField && !_bgField.forbid) {
          _bgField.options = columns
          _bgField.oriOptions = columns
          map.set('bgField', _bgField)
        return {
          bgField: d.columns
        }
      }
    },
@@ -108,15 +90,13 @@
      label: '受控类型',
      initval: wrap.linkType || 'static',
      tooltip: <div>
        <div>组件与其他组件之间的控制类型: </div>
        <div>1、独立表示与其他组件没有关联。</div>
        <div>2、同步类型中公式、按钮以及全选元素比较特殊,操作数据为其同步组件的数据。</div>
        <div>3、上级类型需添加当前组件的上级组件,并可设置当前组件为始终显示,还是只有在上级组件选行后才显示。</div>
        <div>同步类型:此类型时公式、按钮以及全选元素比较特殊,操作数据为其同步组件选中的数据。</div>
        <div>上级类型:可设置当前组件的显示条件(始终显示或上级选行时显示),与静态数据源配合也可用于展示上级组件选中的信息。</div>
      </div>,
      toolWidth: 400,
      required: false,
      options: [
        {value: 'static', label: '独立'},
        {value: 'static', label: '无'},
        {value: 'sync', label: '同步'},
        {value: 'sup', label: '上级'},
      ],
@@ -133,7 +113,6 @@
      field: 'supModule',
      label: '上级组件',
      initval: wrap.supModule || [],
      // tooltip: '当上级组件不存在或没有权限时,当前组件不显示。',
      required: true,
      options: supmodules,
      forbid: isprint
@@ -149,6 +128,16 @@
        {value: 'hidden', label: '选行'},
        {value: 'show', label: '始终'},
      ],
      forbid: isprint
    },
    {
      type: 'cascader',
      field: 'syncModule',
      label: '同步组件',
      initval: wrap.syncModule || '',
      tooltip: '当同步组件不存在或没有权限时,当前组件不显示。',
      required: true,
      options: modules,
      forbid: isprint
    },
    {
@@ -193,6 +182,7 @@
      label: '背景图',
      initval: wrap.bgField || '',
      tooltip: '动态背景,背景图片由字段值控制。请注意调整背景样式。',
      timestamp: new Date().getTime(),
      required: false,
      options: columns
    },
src/menu/components/card/data-card/options.jsx
@@ -1,4 +1,4 @@
import MenuUtils from '@/utils/utils-custom.js'
import MenuUtils, { getInterfaces } from '@/utils/utils-custom.js'
/**
 * @description Wrap表单配置信息
@@ -9,16 +9,10 @@
  let ispop = sessionStorage.getItem('editMenuType') === 'popview'
  let menu = window.GLOB.customMenu
  let laypage = setting && setting.laypage !== 'false'
  let interfaces = []
  if (subtype === 'propcard' && menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
        })
      }
    })
  if (subtype === 'propcard') {
    interfaces = getInterfaces()
  }
  let modules = []
  if (subtype === 'propcard' || subtype === 'datacard') {
@@ -159,7 +153,7 @@
      field: 'datatype',
      label: '数据来源',
      initval: wrap.datatype || 'dynamic',
      tooltip: '选择静态值,无需配置数据源。',
      tooltip: '选择静态时,无需配置数据源,可展示上级组件或url参数字段。',
      required: false,
      options: [
        {value: 'dynamic', label: '动态', priKeyType: 'static'},
@@ -187,38 +181,17 @@
      options: interfaces,
      reset_source: true,
      forbid: subtype !== 'propcard',
      callback: (map, record) => {
      callback: (record) => {
        if (!record.publicId) return
        
        let interfaces = window.GLOB.customMenu.interfaces || []
        let d = interfaces.filter(m => m.uuid === record.publicId && m.status === 'true')[0]
        let d = interfaces.filter(m => m.value === record.publicId)[0]
        
        if (!d || !d.columns) return
        let columns = JSON.parse(JSON.stringify(d.columns))
        let _broadcast = map.get('broadcast')
        if (_broadcast && !_broadcast.forbid) {
          _broadcast.options = columns
          _broadcast.oriOptions = columns
          map.set('broadcast', _broadcast)
        }
        let _jumpField = map.get('jumpField')
        if (_jumpField && !_jumpField.forbid) {
          _jumpField.options = columns
          _jumpField.oriOptions = columns
          map.set('jumpField', _jumpField)
        }
        let _link = map.get('link')
        if (_link && !_link.forbid) {
          _link.options = columns
          _link.oriOptions = columns
          map.set('link', _link)
        return {
          broadcast: d.columns,
          jumpField: d.columns,
          link: d.columns
        }
      }
    },
@@ -287,11 +260,9 @@
      required: false,
      linkField: 'datatype',
      options: [
        {ParentID: 'static', value: 'static', label: '静态值'},
        {ParentID: 'dynamic', value: 'static', label: '静态值'},
        {ParentID: '', value: 'static', label: '静态值'},
        {ParentID: 'dynamic', value: 'dynamic', label: '动态值'},
        {ParentID: 'dynamic', value: 'joint', label: '拼接值'},
        {ParentID: 'public', value: 'static', label: '静态值'},
        {ParentID: 'public', value: 'dynamic', label: '动态值'},
        {ParentID: 'public', value: 'joint', label: '拼接值'},
      ],
@@ -427,6 +398,7 @@
      label: '语音播报',
      initval: wrap.broadcast || '',
      tooltip: '语音播报在移动端有效。注:在H5中请使用音频链接,添加定时器时,可循环播报',
      timestamp: new Date().getTime(),
      required: false,
      options: columns,
      forbid: !columns || appType !== 'mob' || subtype !== 'propcard'
@@ -525,6 +497,7 @@
      label: '控制字段',
      initval: wrap.jumpField || '',
      tooltip: '当字段值为true时触发跳转。',
      timestamp: new Date().getTime(),
      required: true,
      options: columns,
      forbid: subtype !== 'propcard' || appType !== 'mob'
@@ -544,6 +517,7 @@
      label: '链接字段',
      initval: wrap.link || '',
      tooltip: '跳转链接为查询数据的返回值。',
      timestamp: new Date().getTime(),
      required: true,
      options: columns,
      forbid: subtype !== 'propcard' || appType !== 'mob'
src/menu/components/card/prop-card/index.jsx
@@ -6,7 +6,7 @@
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { resetStyle, getTables, checkComponent } from '@/utils/utils-custom.js'
import { resetStyle, getTables, checkComponent, getInterfaces } from '@/utils/utils-custom.js'
import MKEmitter from '@/utils/events.js'
import Utils from '@/utils/utils.js'
import getWrapForm from '../data-card/options'
@@ -331,9 +331,9 @@
        _card.setting.supModule = ''
      }
    } else if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let interfaces = getInterfaces()
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      let d = interfaces.filter(m => m.value === res.publicId)[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
src/menu/components/editor/braft-editor/options.jsx
@@ -7,14 +7,15 @@
  let isprint = sessionStorage.getItem('MenuType') === 'billPrint'
  let ispop = sessionStorage.getItem('editMenuType') === 'popview'
  let menu = window.GLOB.customMenu
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
          label: item.name,
          columns: JSON.parse(JSON.stringify(item.columns))
        })
      }
    })
@@ -84,23 +85,15 @@
      required: true,
      options: interfaces,
      reset_source: true,
      callback: (map, record) => {
      callback: (record) => {
        if (!record.publicId) return
        let interfaces = window.GLOB.customMenu.interfaces || []
        let d = interfaces.filter(m => m.uuid === record.publicId && m.status === 'true')[0]
        let d = interfaces.filter(m => m.value === record.publicId)[0]
        if (!d || !d.columns) return
        let columns = JSON.parse(JSON.stringify(d.columns))
        let _field = map.get('field')
        if (_field) {
          _field.options = columns
          _field.oriOptions = columns
          map.set('field', _field)
        return {
          field: d.columns
        }
      }
    },
@@ -109,6 +102,7 @@
      field: 'field',
      label: '文本字段',
      initval: wrap.field || '',
      timestamp: new Date().getTime(),
      required: false,
      options: columns
    },
src/menu/components/form/simple-form/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover, Modal, Button, Switch, message } from 'antd'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, SwapOutlined, FontColorsOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -19,6 +19,7 @@
const CardComponent = asyncComponent(() => import('@/templates/modalconfig/dragelement'))
const MobCardComponent = asyncComponent(() => import('@/mob/components/formdragelement'))
const FormAction = asyncComponent(() => import('../formaction'))
const FormFork = asyncComponent(() => import('@/menu/modalconfig/formfork'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteForms = asyncIconComponent(() => import('@/menu/components/share/pasteforms'))
@@ -41,8 +42,7 @@
    visible: false,
    editform: null,
    formlist: null,
    sqlVerifing: false,
    standardform: null
    sqlVerifing: false
  }
  UNSAFE_componentWillMount () {
@@ -346,90 +346,14 @@
   * @description 表单编辑
   */
  handleForm = (_item) => {
    const { card, appType } = this.state
    const { card } = this.state
    let _form = fromJS(_item).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = []
    let standardform = null
    let index = null
    card.subcards[0].fields.forEach((item, i) => {
      if (_form.uuid === item.uuid) {
        index = i
      }
      if (!item.field || _form.field === item.field) return
      if (['text', 'number', 'textarea', 'color'].includes(item.type)) {
        _inputfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
        _tabfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (['switch', 'check', 'popSelect'].includes(item.type)) {
        _linksupFields.push({
          field: item.field,
          label: item.label
        })
      }
      if (!['select', 'link', 'radio', 'checkcard', 'multiselect'].includes(item.type)) return
      _linksupFields.push({
        field: item.field,
        label: item.label
      })
      if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) return
      _linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    })
    if (index !== null) {
      if (index === 0) {
        standardform = card.subcards[0].fields[index + 1] || null
      } else {
        standardform = card.subcards[0].fields[index - 1] || null
      }
    }
    let _fields = _linkableFields.map(cell => cell.field)
    card.columns.forEach(col => {
      if (col.field && !_fields.includes(col.field)) {
        _linkableFields.push({
          field: col.field,
          label: col.label + '-显示列'
        })
      }
    })
    if (_form.linkSubField && _form.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      _form.linkSubField = _form.linkSubField.filter(item => fields.includes(item))
    }
    if (appType !== 'mob' && !_form.span && standardform && standardform.span) {
      _form.span = standardform.span
      _form.labelwidth = standardform.labelwidth
    }
    this.setState({
      standardform,
      visible: true,
      editform: _form,
      formlist: getModalForm(_form, _inputfields, _tabfields, _linkableFields, _linksupFields, card.columns)
      formlist: getModalForm(_form, card.subcards[0].fields, card.columns)
    })
  }
@@ -442,7 +366,7 @@
  handleSubmit = () => {
    let _config = fromJS(this.state.card).toJS()
    this.formRef.handleConfirm(_config.subcards[0].fields).then(res => {
    this.formRef.handleConfirm().then(res => {
      _config.subcards[0].fields = _config.subcards[0].fields.map(item => {
        delete item.focus
@@ -626,12 +550,22 @@
        <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
          <PlusOutlined className="plus" title="添加表单" onClick={this.addForm}/>
          <FieldsComponent config={card.subcards[0]} type="form" plusFields={this.plusFields} />
          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>清空</span>
          <div className="mk-form-tool">
            <DeleteOutlined title="清空" onClick={this.clearGroup} />
            {appType !== 'mob' ? <Popover title="切换布局" overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(1)}>1列</Button>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(2)}>2列</Button>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(3)}>3列</Button>
                <Button onClick={() => this.changecols(4)}>4列</Button>
              </>
            } trigger="hover">
              <SwapOutlined />
            </Popover> : null}
            <FormFork forms={card.subcards[0].fields}/>
            {/* <CopyOutlined title="复制" onClick={this.triggerCopy} /> */}
          <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button> : null}
          </div>
          <div style={{clear: 'both'}}></div>
          {appType !== 'mob' ? <CardComponent
            list={card.subcards[0].fields}
@@ -687,7 +621,7 @@
            card={this.state.editform}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            fields={card.subcards[0].fields}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
src/menu/components/form/simple-form/index.scss
@@ -34,14 +34,6 @@
      cursor: pointer;
      padding: 4px 10px;
    }
    >button {
      float: right;
      margin-right: 10px;
    }
    >.mk-cols-change {
      height: 24px;
      padding: 0 10px;
    }
    >.quickly-add {
      display: inline-block;
      margin-left: 10px;
@@ -78,12 +70,12 @@
  //   }
  // }
}
.menu-normal-form-edit-box::after {
.menu-simple-form-edit-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.menu-normal-form-edit-box:hover {
.menu-simple-form-edit-box:hover {
  z-index: 1;
  box-shadow: 0px 0px 4px #1890ff;
}
src/menu/components/form/step-form/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover, Modal, Button, Switch, notification, message } from 'antd'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, SwapOutlined, FontColorsOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -20,6 +20,7 @@
const MobCardComponent = asyncComponent(() => import('@/mob/components/formdragelement'))
const FormTitle = asyncComponent(() => import('../dragtitle'))
const FormAction = asyncComponent(() => import('../formaction'))
const FormFork = asyncComponent(() => import('@/menu/modalconfig/formfork'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -42,8 +43,7 @@
    visible: false,
    editform: null,
    formlist: null,
    sqlVerifing: false,
    standardform: null
    sqlVerifing: false
  }
  UNSAFE_componentWillMount () {
@@ -447,91 +447,14 @@
   * @description 表单编辑
   */
  handleForm = (_item) => {
    const { card, group, appType } = this.state
    const { card, group } = this.state
    let _form = fromJS(_item).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = []
    let standardform = null
    let index = null
    group.fields.forEach((item, i) => {
      if (_form.uuid === item.uuid) {
        index = i
      }
      if (!item.field || _form.field === item.field) return
      if (['text', 'number', 'textarea', 'color'].includes(item.type)) {
        _inputfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
        _tabfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (['switch', 'check', 'popSelect'].includes(item.type)) {
        _linksupFields.push({
          field: item.field,
          label: item.label
        })
      }
      if (!['select', 'link', 'radio', 'checkcard', 'multiselect'].includes(item.type)) return
      _linksupFields.push({
        field: item.field,
        label: item.label
      })
      if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) return
      _linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    })
    if (index !== null) {
      if (index === 0) {
        standardform = group.fields[index + 1] || null
      } else {
        standardform = group.fields[index - 1] || null
      }
    }
    let _fields = _linkableFields.map(cell => cell.field)
    card.columns.forEach(col => {
      if (col.field && !_fields.includes(col.field)) {
        _linkableFields.push({
          field: col.field,
          label: col.label + '-显示列'
        })
      }
    })
    if (_form.linkSubField && _form.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      _form.linkSubField = _form.linkSubField.filter(item => fields.includes(item))
    }
    if (appType !== 'mob' && !_form.span && standardform && standardform.span) {
      _form.span = standardform.span
      _form.labelwidth = standardform.labelwidth
    }
    this.setState({
      standardform,
      visible: true,
      editform: _form,
      formlist: getModalForm(_form, _inputfields, _tabfields, _linkableFields, _linksupFields, card.columns)
      formlist: getModalForm(_form, group.fields, card.columns)
    })
  }
@@ -544,7 +467,7 @@
  handleSubmit = () => {
    let _config = fromJS(this.state.group).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
    this.formRef.handleConfirm().then(res => {
      _config.fields = _config.fields.map(item => {
        delete item.focus
@@ -742,12 +665,22 @@
        {group ? <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
          <PlusOutlined className="plus" title="添加表单" onClick={this.addForm}/>
          <FieldsComponent config={group} type="form" plusFields={this.plusFields} />
          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>清空</span>
          <div className="mk-form-tool">
            <DeleteOutlined title="清空" onClick={this.clearGroup} />
            {appType !== 'mob' ? <Popover title="切换布局" overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(1)}>1列</Button>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(2)}>2列</Button>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(3)}>3列</Button>
                <Button onClick={() => this.changecols(4)}>4列</Button>
              </>
            } trigger="hover">
              <SwapOutlined />
            </Popover> : null}
            <FormFork forms={group.fields}/>
            {/* <CopyOutlined title="复制" onClick={this.triggerCopy} /> */}
          <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button> : null}
          </div>
          <div style={{clear: 'both'}}></div>
          {appType !== 'mob' ? <CardComponent
            list={group.fields}
@@ -803,7 +736,7 @@
            card={this.state.editform}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            fields={group.fields}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
src/menu/components/form/step-form/index.scss
@@ -35,14 +35,6 @@
      cursor: pointer;
      padding: 4px 10px;
    }
    >button {
      float: right;
      margin-right: 10px;
    }
    >.mk-cols-change {
      height: 24px;
      padding: 0 10px;
    }
    >.quickly-add {
      display: inline-block;
      margin-left: 10px;
src/menu/components/form/step-form/options.jsx
@@ -35,7 +35,8 @@
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
          label: item.name,
          columns: JSON.parse(JSON.stringify(item.columns))
        })
      }
    })
@@ -87,23 +88,15 @@
      required: true,
      options: interfaces,
      reset_source: config.subtype !== 'tabform',
      callback: (map, record) => {
      callback: (record) => {
        if (!record.publicId) return
        let interfaces = window.GLOB.customMenu.interfaces || []
        let d = interfaces.filter(m => m.uuid === record.publicId && m.status === 'true')[0]
        let d = interfaces.filter(m => m.value === record.publicId)[0]
        if (!d || !d.columns) return
        let columns = JSON.parse(JSON.stringify(d.columns))
        let _sCtrl = map.get('statusControl')
        if (_sCtrl && !_sCtrl.forbid) {
          _sCtrl.options = columns
          _sCtrl.oriOptions = columns
          map.set('statusControl', _sCtrl)
        return {
          statusControl: d.columns
        }
      }
    },
@@ -113,6 +106,7 @@
      label: '状态控制',
      initval: wrap.statusControl || '',
      tooltip: '表单加载时的状态,当字段值与表单组的状态值一致时,启用对应的表单组。',
      timestamp: new Date().getTime(),
      required: false,
      options: config.columns,
      forbid: config.subtype === 'tabform'
src/menu/components/form/tab-form/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover, Modal, Button, Switch, notification, message } from 'antd'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, SwapOutlined, FontColorsOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -20,6 +20,7 @@
const MobCardComponent = asyncComponent(() => import('@/mob/components/formdragelement'))
const FormTitle = asyncComponent(() => import('../dragtitle'))
const FormAction = asyncComponent(() => import('../formaction'))
const FormFork = asyncComponent(() => import('@/menu/modalconfig/formfork'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -42,8 +43,7 @@
    visible: false,
    editform: null,
    formlist: null,
    sqlVerifing: false,
    standardform: null
    sqlVerifing: false
  }
  UNSAFE_componentWillMount () {
@@ -453,90 +453,14 @@
   * @description 表单编辑
   */
  handleForm = (_item) => {
    const { card, group, appType } = this.state
    const { card, group } = this.state
    let _form = fromJS(_item).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = []
    let standardform = null
    let index = null
    group.fields.forEach((item, i) => {
      if (_form.uuid === item.uuid) {
        index = i
      }
      if (!item.field || _form.field === item.field) return
      if (['text', 'number', 'textarea', 'color'].includes(item.type)) {
        _inputfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
        _tabfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (['switch', 'check', 'popSelect'].includes(item.type)) {
        _linksupFields.push({
          field: item.field,
          label: item.label
        })
      }
      if (!['select', 'link', 'radio', 'checkcard', 'multiselect'].includes(item.type)) return
      _linksupFields.push({
        field: item.field,
        label: item.label
      })
      if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) return
      _linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    })
    if (index !== null) {
      if (index === 0) {
        standardform = group.fields[index + 1] || null
      } else {
        standardform = group.fields[index - 1] || null
      }
    }
    let _fields = _linkableFields.map(cell => cell.field)
    card.columns.forEach(col => {
      if (col.field && !_fields.includes(col.field)) {
        _linkableFields.push({
          field: col.field,
          label: col.label + '-显示列'
        })
      }
    })
    if (_form.linkSubField && _form.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      _form.linkSubField = _form.linkSubField.filter(item => fields.includes(item))
    }
    if (appType !== 'mob' && !_form.span && standardform && standardform.span) {
      _form.span = standardform.span
      _form.labelwidth = standardform.labelwidth
    }
    this.setState({
      standardform,
      visible: true,
      editform: _form,
      formlist: getModalForm(_form, _inputfields, _tabfields, _linkableFields, _linksupFields, card.columns)
      formlist: getModalForm(_form, group.fields, card.columns)
    })
  }
@@ -549,7 +473,7 @@
  handleSubmit = () => {
    let _config = fromJS(this.state.group).toJS()
    this.formRef.handleConfirm(_config.fields).then(res => {
    this.formRef.handleConfirm().then(res => {
      _config.fields = _config.fields.map(item => {
        delete item.focus
@@ -744,12 +668,22 @@
        {group ? <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
          <PlusOutlined className="plus" title="添加表单" onClick={this.addForm}/>
          <FieldsComponent config={group} type="form" plusFields={this.plusFields} />
          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>清空</span>
          <div className="mk-form-tool">
            <DeleteOutlined title="清空" onClick={this.clearGroup} />
            {appType !== 'mob' ? <Popover title="切换布局" overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(1)}>1列</Button>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(2)}>2列</Button>
                <Button style={{marginRight: '10px'}} onClick={() => this.changecols(3)}>3列</Button>
                <Button onClick={() => this.changecols(4)}>4列</Button>
              </>
            } trigger="hover">
              <SwapOutlined />
            </Popover> : null}
            <FormFork forms={group.fields}/>
            {/* <CopyOutlined title="复制" onClick={this.triggerCopy} /> */}
          <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button> : null}
          </div>
          <div style={{clear: 'both'}}></div>
          {appType !== 'mob' ? <CardComponent
            list={group.fields}
@@ -805,7 +739,7 @@
            card={this.state.editform}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            fields={group.fields}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
src/menu/components/form/tab-form/index.scss
@@ -34,14 +34,6 @@
      cursor: pointer;
      padding: 4px 10px;
    }
    >button {
      float: right;
      margin-right: 10px;
    }
    >.mk-cols-change {
      height: 24px;
      padding: 0 10px;
    }
    >.quickly-add {
      display: inline-block;
      margin-left: 10px;
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -723,6 +723,10 @@
      } else if (value === 'custom') {
        _fieldval.Ot = 'required'
      }
      if (_fieldval.Ot === 'required' && this.record.execError === 'never') {
        this.record.execError = 'grid'
        _fieldval.execError = 'grid'
      }
      if (this.props.type === 'card' && _fieldval.Ot === 'required') { // 卡片中无多行选项
        _fieldval.Ot = 'requiredSgl'
@@ -741,6 +745,9 @@
      if (appType !== 'mob' && value === 'notRequired') {
        this.record.control = ''
        _fieldval.control = ''
      } else if (value === 'required' && this.record.execError === 'never') {
        this.record.execError = 'grid'
        _fieldval.execError = 'grid'
      }
    } else if (key === 'pageTemplate') {
      if (value === 'pay') {
src/menu/components/table/base-table/columns/index.scss
@@ -45,7 +45,7 @@
      }
      td:not(.ant-table-selection-column) {
        position: relative;
        padding: 12px 8px;
        // padding: 12px 8px;
        >.profile {
          position: absolute;
          top: 2px;
src/menu/components/table/edit-table/columns/index.jsx
@@ -637,10 +637,6 @@
    })
  }
  componentDidMount () {
    MKEmitter.addListener('submitStyle', this.getStyle)
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
@@ -648,7 +644,6 @@
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('submitStyle', this.getStyle)
  }
  handlecolumns = (columns, fields, config, pId) => {
src/menu/components/table/edit-table/columns/tableIn/index.jsx
@@ -104,6 +104,92 @@
            </div>
          )
      },
      {
        dataIndex: 'sqlRender',
        render: (record) => {
          let columns = this.props.config.columns
          let textFields = []
          let numberFields = []
          let dateFields = []
          columns.forEach((col) => {
            if (/Nvarchar/ig.test(col.datatype)) {
              textFields.push(col.field)
            } else if (/Decimal|int/ig.test(col.datatype)) {
              numberFields.push(col.field)
            } else if (/date/ig.test(col.datatype)) {
              dateFields.push(col.field)
            }
          })
          let _sheet = this.state.verify.sheet
          if (window.GLOB.externalDatabase !== null) {
            _sheet = _sheet.replace(/@db@/ig, window.GLOB.externalDatabase)
          }
          let database = _sheet.match(/(.*)\.(.*)\./ig)
          let sheet = _sheet.replace(/(.*)\.(.*)\./ig, '')
          database = database ? (database[0] || '') : ''
          let _fields = record.field.split(',')
          let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
          _fields_ = _fields_.join(' and ')
          let _where = []
          _fields.forEach(f => {
            if (textFields.includes(f)) {
              _where.push(`${f}!=''`)
            } else if (numberFields.includes(f)) {
              _where.push(`${f}!=0`)
            } else if (dateFields.includes(f)) {
              _where.push(`${f}>'1949-10-01'`)
            }
          })
          _where = _where.length ? `where ${_where.join(' and ')} ` : ''
          if (record.verifyType === 'logic' || record.verifyType === 'logic_temp') {
            _fields_ += ' and b.deleted=0'
          }
          let _afields = []
          _fields = _fields.map(f => {
            if (numberFields.includes(f)) {
              _afields.push(`cast(a.${f} as nvarchar(50))`)
              return `cast(${f} as nvarchar(50))`
            } else if (dateFields.includes(f)) {
              _afields.push(`CONVERT(nvarchar(50), a.${f}, 21)`)
              return `CONVERT(nvarchar(50), ${f}, 21)`
            }
            _afields.push(`a.${f}`)
            return f
          })
          let sql = `
          /* 重复性验证 */
          Set @tbid=''
          Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${record.field} from #${sheet} ) a group by ${record.field} having sum(n)>1
          If @tbid!=''
          Begin
            select @ErrorCode='${record.errorCode}',@retmsg=@tbid+' 重复'
            goto aaa
          end
          ${record.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
          Select top 1 @tbid=${_afields.join('+\' \'+')} from ${_where ? `(select * from #${sheet} ${_where})` : `#${sheet}`} a Inner join ${database}${sheet} b on ${_fields_}
          If @tbid!=''
          Begin
            select @ErrorCode='${record.errorCode}',@retmsg=@tbid+' 与已有数据重复'
            goto aaa
          end` : ''}
          `
          return sql.split(/\n\s{10}/ig).map(n => n.replace(/^\s{2}/ig, '&nbsp;&nbsp;'))
        }
      }
    ],
    scriptsColumns: [
      {
@@ -611,7 +697,7 @@
            </span>
          } key="unique">
            <UniqueForm fields={fields} uniqueChange={this.uniqueChange}/>
            <EditTable actions={['edit', 'move', 'del']} data={verify.uniques} columns={uniqueColumns} onChange={this.changeUniques}/>
            <EditTable actions={['edit', 'move', 'del', 'sql']} data={verify.uniques} columns={uniqueColumns} onChange={this.changeUniques}/>
          </TabPane>
          <TabPane disabled={verify.intertype !== 'system'} tab={
            <span>
src/menu/components/table/edit-table/index.jsx
@@ -284,6 +284,10 @@
    res.borderRadius = card.wrap.borderRadius || 0
    res.resetContrl = card.wrap.resetContrl || 'init'
    if (res.commit === 'check' && !res.tableType) {
      res.tableType = 'radio'
    }
    let _card = {...card, wrap: res}
    if (res.tableType) {
src/menu/components/table/edit-table/options.jsx
@@ -67,18 +67,13 @@
        {value: 'check', label: '勾选项'},
      ],
      reset_source: true,
      callback: (map, record, MKEmitter) => {
        let _tableType = map.get('tableType')
        _tableType.options[0].disabled = record.commit === 'check'
        _tableType.oriOptions[0].disabled = record.commit === 'check'
        map.set('tableType', _tableType)
        if (record.commit === 'check' && !record.tableType) {
          setTimeout(() => {
            MKEmitter.emit('mkFC', 'input', 'tableType', 'radio')
          }, 50)
      callback: (record) => {
        return {
          tableType: [
            {value: '', label: '不可选', disabled: record.commit === 'check'},
            {value: 'radio', label: '单选'},
            {value: 'checkbox', label: '多选'},
          ]
        }
      }
    },
@@ -112,6 +107,7 @@
      label: '表格属性',
      initval: wrap.tableType || '',
      required: false,
      timestamp: new Date().getTime(),
      options: [
        {value: '', label: '不可选', disabled: wrap.commit === 'check'},
        {value: 'radio', label: '单选'},
src/menu/components/table/normal-table/columns/index.scss
@@ -42,7 +42,7 @@
      }
      td:not(.ant-table-selection-column) {
        position: relative;
        padding: 12px 8px;
        // padding: 12px 8px;
        >.profile {
          position: absolute;
          top: 2px;
src/menu/datasource/index.jsx
@@ -264,6 +264,12 @@
      if (res.setting && res.setting.tableName && config.setting && !config.setting.tableName) {
        setTimeout(() => {
          MKEmitter.emit('publicTableChange', res.setting.tableName, 'init')
        }, 100)
      }
      if ((config.type === 'card' && config.subtype === 'datacard') || (config.type === 'table' && config.subtype === 'normaltable')) {
        setTimeout(() => {
          MKEmitter.emit('mkUpdateInter', {uuid: config.uuid, columns: res.columns}, {delay: 0})
        }, 150)
      }
    }, () => {
src/menu/datasource/verifycard/index.jsx
@@ -962,13 +962,18 @@
  copyColumns = () => {
    const { config } = this.props
    const { columns, setting } = this.state
    const { columns, subColumns, setting } = this.state
    let _columns = columns
    let m = []
    let n = []
    let s = []
    columns.forEach(col => {
    if (subColumns && subColumns.length) {
      _columns = [...columns, ...subColumns]
    }
    _columns.forEach(col => {
      m.unshift(`${col.field} ${col.datatype}`)
      n.unshift(col.field)
      if (/decimal|int/ig.test(col.datatype)) {
@@ -993,7 +998,7 @@
        cols.forEach(col => {
          if (col.type === 'extend') {
            let datatype = 'Nvarchar(50)'
            columns.forEach(c => {
            _columns.forEach(c => {
              if (c.field === col.field) {
                datatype = c.datatype
              }
@@ -1069,8 +1074,6 @@
  addProcess = () => {
    const { config } = this.props
    const { columns } = this.state
    if (config.subtype === 'dualdatacard') return
    let fields = []
    let cols = []
src/menu/datasource/verifycard/settingform/index.jsx
@@ -414,10 +414,10 @@
                {getFieldDecorator('primaryKey', {
                  initialValue: setting.primaryKey || ''
                })(
                  <Select>
                  <Select showSearch filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
                    {columns.map((option, i) =>
                      <Select.Option key={i} value={option.field}>
                        {option.label}
                        {`${option.label}(${option.field})`}
                      </Select.Option>
                    )}
                  </Select>
@@ -652,10 +652,10 @@
                {getFieldDecorator('subKey', {
                  initialValue: setting.subKey || ''
                })(
                  <Select>
                  <Select showSearch filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
                    {this.props.subColumns.map((option, i) =>
                      <Select.Option key={i} value={option.field}>
                        {option.label}
                        {`${option.label}(${option.field})`}
                      </Select.Option>
                    )}
                  </Select>
@@ -667,10 +667,10 @@
                {getFieldDecorator('subBID', {
                  initialValue: setting.subBID || ''
                })(
                  <Select>
                  <Select showSearch filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
                    {this.props.subColumns.map((option, i) =>
                      <Select.Option key={i} value={option.field}>
                        {option.label}
                        {`${option.label}(${option.field})`}
                      </Select.Option>
                    )}
                  </Select>
src/menu/debug/index.jsx
@@ -430,7 +430,7 @@
      }
    } else if (cell.OpenType === 'excelIn') {
      if (cell.intertype === 'system') {
        sql = this.getExcelInSql(cell)
        sql = this.getExcelInSql(cell, process)
      }
    } else if (cell.OpenType === 'excelOut') {
      if (cell.intertype === 'system' && cell.verify && cell.verify.dataType === 'custom') {
@@ -1470,17 +1470,54 @@
    let _uniquesql = ''
    if (btn.uniques && btn.uniques.length > 0) {
      let textFields = []
      let numberFields = []
      let dateFields = []
      btn.columns.forEach((col) => {
        if (/Nvarchar/ig.test(col.type)) {
          textFields.push(col.Column)
        } else if (/Decimal|int/ig.test(col.type)) {
          numberFields.push(col.Column)
        } else if (/date/ig.test(col.type)) {
          dateFields.push(col.Column)
        }
      })
      btn.uniques.forEach(unique => {
        if (unique.status === 'false' || !unique.verifyType) return
        let _fields = unique.field.split(',')
        let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
        let _afields = _fields.map(_field => `a.${_field}`)
        _fields_ = _fields_.join(' and ')
        let _where = []
        _fields.forEach(f => {
          if (textFields.includes(f)) {
            _where.push(`${f}!=''`)
          } else if (numberFields.includes(f)) {
            _where.push(`${f}!=0`)
          } else if (dateFields.includes(f)) {
            _where.push(`${f}>'1949-10-01'`)
          }
        })
        _where = _where.length ? `where ${_where.join(' and ')} ` : ''
        if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
          _fields_ += ' and b.deleted=0'
        }
        let _afields = []
        _fields = _fields.map(f => {
          if (numberFields.includes(f)) {
            _afields.push(`cast(a.${f} as nvarchar(50))`)
            return `cast(${f} as nvarchar(50))`
          } else if (dateFields.includes(f)) {
            _afields.push(`CONVERT(nvarchar(50), a.${f}, 21)`)
            return `CONVERT(nvarchar(50), ${f}, 21)`
          }
          _afields.push(`a.${f}`)
          return f
        })
        _uniquesql += `
      /* 重复性验证 */
@@ -1494,7 +1531,7 @@
      end
      
      ${unique.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
      Select top 1 @tbid=${_afields.join('+\' \'+')} from  #${sheet} a Inner join ${sheet} b on ${_fields_}
      Select top 1 @tbid=${_afields.join('+\' \'+')} from ${_where ? `(select * from #${sheet} ${_where})` : `#${sheet}`} a Inner join ${sheet} b on ${_fields_}
      
      If @tbid!=''
      Begin
@@ -1543,12 +1580,54 @@
      ${_uniquesql}
      ${_prevCustomScript}
      ${_insert}
      ${_insert}`
    if (btn.workFlow === 'true' && process) {
      if (btn.flowSql === 'true') {
        sql += `
        /* 工作流默认sql */
        insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
        select jskey,@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@
        from #${sheet}
        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 jskey,@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@
        from #${sheet}
        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 jskey,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
        from #${sheet}
        insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid,typecharone)
        select jskey,@works_flow_code@,@userid@,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@,'begin'
        from #${sheet}
        `
      }
      sql += `
      ${_backCustomScript}
      drop table #${sheet}
      
      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
      sql = sql.replace(/@start_type@/ig, `'开始'`)
      sql = sql.replace(/@works_flow_code@/ig, `'mk'`)
      sql = sql.replace(/@works_flow_name@/ig, `'mk'`)
      sql = sql.replace(/@works_flow_param@/ig, `''`)
      sql = sql.replace(/@works_flow_detail_id@/ig, `'0'`)
      sql = sql.replace(/@status@/ig, `'888'`)
      sql = sql.replace(/@statusname@/ig, `'结束'`)
      sql = sql.replace(/@work_group@/ig, `'mk'`)
      sql = sql.replace(/@work_grade@/ig, `'0'`)
    } else {
      sql += `
        ${_backCustomScript}
        drop table #${sheet}
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    }
    return sql
  }
@@ -1662,17 +1741,54 @@
    let _uniquesql = ''
    if (btn.uniques && btn.uniques.length > 0) {
      let textFields = []
      let numberFields = []
      let dateFields = []
      columns.forEach((col) => {
        if (/Nvarchar/ig.test(col.datatype)) {
          textFields.push(col.field)
        } else if (/Decimal|int/ig.test(col.datatype)) {
          numberFields.push(col.field)
        } else if (/date/ig.test(col.datatype)) {
          dateFields.push(col.field)
        }
      })
      btn.uniques.forEach(unique => {
        if (unique.status === 'false' || !unique.verifyType) return
        let _fields = unique.field.split(',')
        let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
        let _afields = _fields.map(_field => `a.${_field}`)
        _fields_ = _fields_.join(' and ')
        let _where = []
        _fields.forEach(f => {
          if (textFields.includes(f)) {
            _where.push(`${f}!=''`)
          } else if (numberFields.includes(f)) {
            _where.push(`${f}!=0`)
          } else if (dateFields.includes(f)) {
            _where.push(`${f}>'1949-10-01'`)
          }
        })
        _where = _where.length ? `where ${_where.join(' and ')} ` : ''
        if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
          _fields_ += ' and b.deleted=0'
        }
        let _afields = []
        _fields = _fields.map(f => {
          if (numberFields.includes(f)) {
            _afields.push(`cast(a.${f} as nvarchar(50))`)
            return `cast(${f} as nvarchar(50))`
          } else if (dateFields.includes(f)) {
            _afields.push(`CONVERT(nvarchar(50), a.${f}, 21)`)
            return `CONVERT(nvarchar(50), ${f}, 21)`
          }
          _afields.push(`a.${f}`)
          return f
        })
        _uniquesql += `
      /* 重复性验证 */
@@ -1686,7 +1802,7 @@
      end
      
      ${unique.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
      Select top 1 @tbid=${_afields.join('+\' \'+')} from  #${sheet} a Inner join ${sheet} b on ${_fields_}
      Select top 1 @tbid=${_afields.join('+\' \'+')} from ${_where ? `(select * from #${sheet} ${_where})` : `#${sheet}`} a Inner join ${sheet} b on ${_fields_}
      
      If @tbid!=''
      Begin
src/menu/modalconfig/formfork/index.jsx
New file
@@ -0,0 +1,376 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal, Empty, Radio } from 'antd'
import { ForkOutlined } from '@ant-design/icons'
import './index.scss'
class FormFork extends Component {
  static propTpyes = {
    forms: PropTypes.array
  }
  state = {
    visible: false,
    empty: false,
    ctrlFields: [],
    subFields: [],
    subRFields: [],
    linkFields: [],
    tabFields: [],
    type: '',
    forward: 'true',
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  trigger = () => {
    const { forms } = this.props
    let linkFields = {}    // 关联菜单
    let controlFields = {} // 控制表单
    let fieldMap = new Map()
    let formlist = fromJS(forms).toJS()
    formlist.forEach(item => {
      if (item.supField) { // 多层表单控制
        if (['hint', 'split', 'formula'].includes(item.type)) {
          item.field = item.uuid
        }
        let supvals = []
        if (item.supvalue) {
          item.supvalue.split(',').forEach(val => {
            supvals.push(val)
          })
        } else {
          supvals.push('')
        }
        supvals = Array.from(new Set(supvals))
        controlFields[item.supField] = controlFields[item.supField] || []
        controlFields[item.supField].push({field: item.field, values: supvals.join(','), type: item.type})
      } else {
        delete item.supField
        delete item.supvalue
      }
      if (item.linkField) {
        linkFields[item.linkField] = linkFields[item.linkField] || []
        linkFields[item.linkField].push({field: item.field, label: item.label, uuid: item.uuid})
      } else {
        delete item.linkField
      }
      Object.keys(item).forEach(key => {
        if (!['type', 'uuid', 'field', 'label', 'supField', 'supvalue', 'linkField', 'linkSubField', 'multiple', 'enter', 'tabField'].includes(key)) {
          delete item[key]
        }
      })
      if (!item.field) return
      fieldMap.set(item.field, item)
    })
    Object.keys(controlFields).forEach(key => {
      if (!fieldMap.has(key)) return
      let supItem = fieldMap.get(key)
      let fields = []
      controlFields[key].forEach(item => {
        if (!fieldMap.has(item.field)) return
        item.label = fieldMap.get(item.field).label
        fields.push(item)
      })
      if (fields.length === 0) return
      supItem.controlFields = fields
      fieldMap.set(key, supItem)
    })
    let _f = fromJS([...fieldMap.values()]).toJS()
    _f.forEach(item => {
      // 下级表单控制-字段写入
      if (item.linkSubField && item.linkSubField.length > 0) {
        item.subFields = []
        if ((['select', 'radio', 'link', 'cascader'].includes(item.type) || (item.type === 'checkcard' && item.multiple !== 'true'))) {
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m,
                label: n.label
              })
            }
          })
        } else if (item.type === 'switch') {
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m,
                label: n.label
              })
            }
          })
        } else if (item.type === 'fileupload') {
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m,
                label: n.label
              })
            }
          })
        } else if (item.type === 'popSelect') {
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m,
                label: n.label
              })
            }
          })
        }
        if (item.subFields.length === 0) {
          delete item.subFields
        }
      }
      if (linkFields[item.field]) {
        item.linkFields = linkFields[item.field]
      }
      if (item.enter === 'tab' || item.enter === 'sub') {
        if (item.tabField) {
          if (!fieldMap.has(item.tabField)) {
            delete item.tabField
          } else {
            item.tabLabel = fieldMap.get(item.tabField).label
          }
        } else {
          delete item.tabField
        }
      } else {
        delete item.tabField
      }
      if (item.linkField) {
        if (!fieldMap.has(item.linkField)) {
          item.linkLabel = '字段集'
        } else {
          item.linkLabel = fieldMap.get(item.linkField).label
        }
      }
      delete item.enter
      delete item.supField
      delete item.multiple
      delete item.linkSubField
      fieldMap.set(item.field, item)
    })
    let _t = fromJS([...fieldMap.values()]).toJS()
    _t.forEach(item => {
      if (item.subFields) {
        item.subFields.forEach(cell => {
          let _cell = fieldMap.get(cell.field)
          _cell.resubFields = _cell.resubFields || []
          _cell.resubFields.push({
            uuid: item.uuid,
            field: item.field,
            label: item.label
          })
          fieldMap.set(cell.field, _cell)
        })
      }
    })
    let _n = [...fieldMap.values()]
    let ctrlFields = []
    let subFields = []
    let subRFields = []
    let _linkFields = []
    let tabFields = []
    _n.forEach(cell => {
      if (cell.controlFields) {
        ctrlFields.push({
          field: cell.field,
          label: cell.label,
          children: cell.controlFields.map(m => {
            return {
              field: ['hint', 'split', 'formula'].includes(m.type) ? '' : m.field,
              label: m.label,
              tail: `${m.values}`
            }
          })
        })
      }
      if (cell.subFields) {
        subFields.push({
          field: cell.field,
          label: cell.label,
          children: cell.subFields
        })
      }
      if (cell.resubFields) {
        subRFields.push({
          field: cell.field,
          label: cell.label,
          children: cell.resubFields
        })
      }
      if (cell.linkFields) {
        _linkFields.push({
          field: cell.field,
          label: cell.label,
          children: cell.linkFields
        })
      }
      if (cell.tabField) {
        tabFields.push({
          field: cell.field,
          label: cell.label,
          children: [{
            field: cell.tabField,
            label: cell.tabLabel,
          }]
        })
      }
    })
    let type = ''
    if (ctrlFields.length > 0) {
      type = 'ctrl'
    } else if (subFields.length > 0) {
      type = 'input'
    } else if (_linkFields.length > 0) {
      type = 'link'
    } else if (tabFields.length > 0) {
      type = 'switch'
    }
    this.setState({
      type,
      forward: 'true',
      empty: type === '',
      ctrlFields,
      subFields,
      subRFields,
      linkFields: _linkFields,
      tabFields,
      visible: true
    })
  }
  getcontent = () => {
    const { ctrlFields, subFields, subRFields, linkFields, tabFields, visible, type, forward } = this.state
    if (!visible) return null
    let header = <div className="fork-tabs">
      {ctrlFields.length ? <div onClick={() => this.setState({type: 'ctrl', forward: 'true'})} className={'tab-item' + (type === 'ctrl' ? ' active' : '')}>表单控制</div> : null}
      {subFields.length ? <div onClick={() => this.setState({type: 'input', forward: 'true'})} className={'tab-item' + (type === 'input' ? ' active' : '')}>表单填充</div> : null}
      {linkFields.length ? <div onClick={() => this.setState({type: 'link', forward: 'true'})} className={'tab-item' + (type === 'link' ? ' active' : '')}>表单关联</div> : null}
      {tabFields.length ? <div onClick={() => this.setState({type: 'switch', forward: 'true'})} className={'tab-item' + (type === 'switch' ? ' active' : '')}>表单切换</div> : null}
    </div>
    let items = []
    if (type === 'ctrl') {
      items = ctrlFields
    } else if (type === 'input') {
      if (forward === 'true') {
        items = subFields
      } else {
        items = subRFields
      }
    } else if (type === 'link') {
      items = linkFields
    } else if (type === 'switch') {
      items = tabFields
    }
    let content = items.map((item, i) => {
      return <div className="fork-item-wrap" key={i}>
        <div className="fork-left">
          <div className="fork-item">
            <span>{item.label}</span>
            <span>{item.field}</span>
          </div>
        </div>
        <div className="fork-right">
          {item.children.map((cell, n) => <div className="fork-item" key={n}>
            <span>{cell.label}</span>
            <span>{cell.field}</span>
            {cell.tail ? <span title={cell.tail} className="fork-tail">{cell.tail}</span> : null}
          </div>)}
        </div>
      </div>
    })
    return <div>
      {header}
      <div className="forward-wrap">
        {type === 'ctrl' ? <div className="legend"><span>主表单</span><span>受控表单</span></div> : null}
        {type === 'input' ? <div className="legend"><span>主表单</span><span>被填入表单</span></div> : null}
        {type === 'link' ? <div className="legend"><span>上级表单</span><span>下级表单</span></div> : null}
        {type === 'switch' ? <div className="legend"><span>源表单</span><span>跳转表单</span></div> : null}
        {type === 'input' ? <Radio.Group value={forward} onChange={(e) => this.setState({forward: e.target.value})}>
          <Radio value="true">正向</Radio>
          <Radio value="false">反向</Radio>
        </Radio.Group> : null}
      </div>
      <div className={'fork-wrap fork-' + forward}>
        {content}
      </div>
    </div>
  }
  render() {
    const { visible, empty } = this.state
    return (
      <>
        <ForkOutlined title="表单关系图" onClick={this.trigger}/>
        <Modal
          title={empty ? '表单关系图' : ''}
          wrapClassName="form-fork-modal mk-scroll-modal"
          visible={visible}
          width={900}
          maskClosable={true}
          closable={false}
          cancelText="关闭"
          onOk={() => { this.setState({ visible: false })}}
          onCancel={() => { this.setState({ visible: false })}}
          destroyOnClose
        >
          {empty ? <Empty description="无表单关联信息。" /> : this.getcontent()}
        </Modal>
      </>
    )
  }
}
export default FormFork
src/menu/modalconfig/formfork/index.scss
New file
@@ -0,0 +1,177 @@
.form-fork-modal {
  .ant-modal-header {
    text-align: center;
  }
  .ant-modal-body {
    min-height: 350px!important;
    .ant-empty {
      margin-top: 50px;
    }
    .fork-tabs {
      border-bottom: 1px solid #e8e8e8;
      text-align: center;
      color: rgba(0, 0, 0, 0.85);
      .tab-item {
        display: inline-block;
        padding: 4px 12px;
        border-bottom: 2px solid transparent;
        transition: all 0.3s;
        cursor: pointer;
      }
      .tab-item:not(:last-child) {
        margin-right: 10px;
      }
      .tab-item.active {
        border-color: #1890ff;
      }
    }
    .forward-wrap {
      position: relative;
      padding: 5px;
      .ant-radio-group {
        position: absolute;
        top: 5px;
        right: 0px;
      }
      .legend {
        span {
          display: inline-block;
          margin-right: 20px;
          position: relative;
          margin-left: 60px;
        }
        span::before {
          content: ' ';
          display: block;
          position: absolute;
          width: 50px;
          height: 6px;
          left: -55px;
          top: 10px;
        }
        span:first-child::before {
          background: #8E44AD;
        }
        span:last-child::before {
          background: rgb(38, 194, 129);
        }
      }
    }
    .fork-wrap {
      padding-top: 15px;
    }
    .fork-wrap.fork-false {
      .fork-item-wrap {
        .fork-left {
          .fork-item {
            border-color: rgb(38, 194, 129);
            color: #26c281;
          }
        }
        .fork-right {
          .fork-item {
            border-color: #8E44AD;
            color: #8E44AD;
          }
        }
      }
    }
    .fork-item-wrap {
      display: inline-flex;
      width: 50%;
      margin-bottom: 20px;
      .fork-left {
        position: relative;
        display: flex;
        width: 50%;
        align-items: center;
        .fork-item {
          border-color: #8E44AD;
          color: #8E44AD;
        }
        .fork-item::before {
          content: '';
          display: block;
          border-top: 1px solid #bcbcbc;
          position: absolute;
          top: 28px;
          width: 58px;
          right: -58px;
        }
      }
      .fork-right {
        position: relative;
        display: inline-block;
        width: 50%;
        padding-left: 30px;
        .fork-item {
          border-color: rgb(38, 194, 129);
          color: #26c281;
        }
        .fork-item:not(:last-child) {
          margin-bottom: 10px;
        }
        .fork-item::before {
          content: '';
          display: block;
          border-top: 1px solid #bcbcbc;
          position: absolute;
          top: 28px;
          width: 56px;
          left: -56px;
        }
      }
      .fork-right::before {
        content: '';
        display: block;
        border-left: 1px solid #bcbcbc;
        position: absolute;
        top: 29px;
        bottom: 27px;
        left: -26px;
      }
      .fork-item {
        position: relative;
        display: block;
        width: 130px;
        border: 1px solid #bcbcbc;
        padding: 5px 10px;
        height: 56px;
        border-radius: 4px;
        span:not(.fork-tail) {
          display: block;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
        .fork-tail {
          display: inline-block;
          position: absolute;
          color: rgba(0, 0, 0, 0.85);
          top: 10px;
          right: 135px;
          max-width: 45px;
          display: block;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
      }
    }
  }
  .ant-modal-footer {
    .ant-btn-primary {
      display: none;
    }
  }
}
src/menu/modalconfig/index.jsx
@@ -3,8 +3,8 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, Switch, message } from 'antd'
import { SettingOutlined, CopyOutlined } from '@ant-design/icons'
import { Button, Card, Modal, Collapse, Switch, message, Popover } from 'antd'
import { SettingOutlined, CopyOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
import { getModalForm } from '@/templates/zshare/formconfig'
import SourceElement from '@/templates/modalconfig/dragelement/source'
@@ -21,6 +21,7 @@
const TableComponent = asyncComponent(() => import('./tablecomponent'))
const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
const PasteForms = asyncComponent(() => import('@/menu/components/share/pasteforms'))
const FormFork = asyncComponent(() => import('@/menu/modalconfig/formfork'))
const DragElement = asyncComponent(() => import('@/templates/modalconfig/dragelement'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -40,7 +41,6 @@
    originConfig: null,    // 原始菜单
    sqlVerifing: false,    // sql验证
    showField: false,      // 显示表单字段值
    standardform: null,
    saving: false
  }
@@ -61,7 +61,6 @@
  componentDidMount () {
    MKEmitter.addListener('completeSave', this.completeSave)
    MKEmitter.addListener('submitStyle', this.getStyle)
  }
  /**
@@ -72,7 +71,6 @@
      return
    }
    MKEmitter.removeListener('completeSave', this.completeSave)
    MKEmitter.removeListener('submitStyle', this.getStyle)
  }
  /**
@@ -100,121 +98,21 @@
  /**
   * @description 表单编辑
   * 1、显示编辑弹窗-visible
   * 2、保存编辑项-card
   * 3、设置编辑参数项-formlist
   */
  handleForm = (_card) => {
    const { componentConfig, btn } = this.props
    const { config } = this.state
    let card = fromJS(_card).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = []
    let standardform = null
    let index = null
    config.fields.forEach((item, i) => {
      if (card.uuid === item.uuid) {
        index = i
      }
      if (!item.field || card.field === item.field) return
      if (['text', 'number', 'textarea', 'color'].includes(item.type)) {
        _inputfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
        _tabfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (['switch', 'check', 'popSelect'].includes(item.type)) {
        _linksupFields.push({
          field: item.field,
          label: item.label
        })
      }
      if (!['select', 'link', 'radio', 'checkcard', 'multiselect'].includes(item.type)) return
      _linksupFields.push({
        field: item.field,
        label: item.label
      })
      if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) return
      _linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    })
    if (index !== null) {
      if (index === 0) {
        standardform = config.fields[index + 1] || null
      } else {
        standardform = config.fields[index - 1] || null
      }
    }
    let columns = componentConfig.columns
    if (btn.$sub) {
      columns = componentConfig.subColumns || []
    }
    let _fields = _linkableFields.map(cell => cell.field)
    columns.forEach(col => {
      if (col.field && !_fields.includes(col.field)) {
        _linkableFields.push({
          field: col.field,
          label: col.label + '-显示列'
        })
      }
    })
    if (card.linkSubField && card.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      card.linkSubField = card.linkSubField.filter(item => fields.includes(item))
    }
    if (!card.span && standardform && standardform.span) {
      card.span = standardform.span
      card.labelwidth = standardform.labelwidth
    } else if (!card.span) {
      card.span = 12
      card.labelwidth = 33.3
    }
    this.setState({
      standardform,
      visible: true,
      card: card,
      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, columns)
    })
  }
  getStyle = (comIds, style) => {
    const { config } = this.state
    if (comIds[0] !== 'form') return
    let Index = config.fields.findIndex(n => n.uuid === comIds[1])
    if (Index === -1) return
    let _config = fromJS(config).toJS()
    _config.fields[Index].style = style
    this.setState({
      config: _config
      formlist: getModalForm(card, config.fields, columns)
    })
  }
@@ -494,7 +392,6 @@
          <div className="setting">
            <Card title="表单配置" bordered={false} extra={
              <div>
                <Button type="danger" onClick={this.clearConfig}>清空</Button>
                <PasteForms type="toolbar" config={config} update={this.pasteFields}/>
                <Button type="primary" id="save-modal-config" loading={saving} onClick={this.submitConfig}>保存</Button>
                <Button onClick={this.cancelConfig}>返回</Button>
@@ -504,12 +401,22 @@
              <div className="ant-modal-content" style={{width: config.setting.width > 100 ? config.setting.width : config.setting.width + '%'}}>
                <div className="ant-modal-header">
                  <div className="ant-modal-title">{config.setting.icon ? <span className={'mk-modal-icon-' + config.setting.iconType} style={{background: config.setting.iconColor || 'unset', color: config.setting.iconColor || 'inherit'}}><MkIcon type={config.setting.icon}/></span> : null}{btn.label}</div>
                  <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button>
                  <div className="mk-form-tool">
                    <DeleteOutlined title="清空" onClick={this.clearConfig} />
                    <Popover title="切换布局" overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                      <>
                        <Button style={{marginRight: '10px'}} onClick={() => this.changecols(1)}>1列</Button>
                        <Button style={{marginRight: '10px'}} onClick={() => this.changecols(2)}>2列</Button>
                        <Button style={{marginRight: '10px'}} onClick={() => this.changecols(3)}>3列</Button>
                        <Button onClick={() => this.changecols(4)}>4列</Button>
                      </>
                    } trigger="hover">
                      <SwapOutlined />
                    </Popover>
                    <FormFork forms={config.fields}/>
                  <CopyOutlined title="复制" onClick={this.triggerCopy} />
                  <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
                  </div>
                </div>
                <div className="ant-modal-body">
                  <div className="modal-form">
@@ -553,7 +460,7 @@
            card={card}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            fields={config.fields}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
src/menu/modalconfig/index.scss
@@ -125,7 +125,8 @@
          z-index: 10;
          background: transparent;
          min-height: 50px;
          padding-right: 80px;
          padding-right: 10px;
          .ant-modal-title {
            display: inline-block;
            height: 22px;
@@ -143,23 +144,6 @@
              text-align: center;
              line-height: 30px;
            }
          }
          .anticon-copy {
            position: absolute;
            top: 18px;
            color: #26C281;
            right: 65px;
            font-size: 16px;
          }
          .ant-switch {
            position: absolute;
            top: 15px;
            right: 10px;
          }
          .mk-cols-change {
            float: right;
            height: 25px;
            margin-right: 10px;
          }
        }
        .ant-modal-close {
@@ -253,12 +237,6 @@
              bottom: 0;
              opacity: 0;
              z-index: 1;
            }
            .ant-col-cuslabel {
              width: 10.5%;
            }
            .ant-col-cuswrap {
              width: 89.5%;
            }
          }
        }
src/menu/stylecombcontroller/index.scss
@@ -115,34 +115,6 @@
  }
}
.margin-popover {
  padding-top: 0px;
  .ant-popover-inner-content {
    width: 90px;
    padding: 0px 5px;
    .ant-menu-root.ant-menu-vertical {
      border: 0;
      .ant-menu-item {
        height: 30px;
        cursor: pointer;
        line-height: 30px;
      }
      .ant-menu-item:not(:last-child) {
        margin-bottom: 0px;
      }
      .ant-menu-item:first-child {
        margin-top: 10px;
      }
      .ant-menu-item:last-child {
        margin-bottom: 10px;
      }
    }
  }
  .ant-popover-arrow {
    display: none;
  }
}
.menu-style-drawer {
  .ant-drawer-body {
    height: calc(100vh - 50px);
src/menu/stylecontroller/index.scss
@@ -156,34 +156,6 @@
  }
}
.margin-popover {
  padding-top: 0px;
  .ant-popover-inner-content {
    width: 90px;
    padding: 0px 5px;
    .ant-menu-root.ant-menu-vertical {
      border: 0;
      .ant-menu-item {
        height: 30px;
        cursor: pointer;
        line-height: 30px;
      }
      .ant-menu-item:not(:last-child) {
        margin-bottom: 0px;
      }
      .ant-menu-item:first-child {
        margin-top: 10px;
      }
      .ant-menu-item:last-child {
        margin-bottom: 10px;
      }
    }
  }
  .ant-popover-arrow {
    display: none;
  }
}
.menu-style-drawer {
  .ant-drawer-body {
    height: calc(100vh - 50px);
src/mob/components/txmap/index.jsx
New file
@@ -0,0 +1,135 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover } from 'antd'
import { ToolOutlined, EditOutlined, FontColorsOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons'
import { resetStyle } from '@/utils/utils-custom.js'
import asyncIconComponent from '@/utils/asyncIconComponent'
import getWrapForm from './options'
import MKEmitter from '@/utils/events.js'
import MkMap from '@/assets/img/map.jpg'
import './index.scss'
const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
class MapComponent extends Component {
  static propTpyes = {
    card: PropTypes.object,
    updateConfig: PropTypes.func,
    deletecomponent: PropTypes.func
  }
  state = {}
  /**
   * @description 搜索条件初始化
   */
  UNSAFE_componentWillMount () {
    const { card } = this.props
    if (card.isNew) {
      let _card = {
        uuid: card.uuid,
        type: card.type,
        width: 24,
        name: card.name,
        subtype: card.subtype,
        setting: { interType: 'system' },
        wrap: { name: card.name, width: 24, datatype: 'static' },
        style: {marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px', height: '100vh'},
        columns: [],
        scripts: [],
      }
      this.setState({
        card: _card
      })
      this.props.updateConfig(_card)
    } else {
      this.setState({
        card: fromJS(card).toJS()
      })
    }
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  getStyle = (style) => {
    let _card = {...this.state.card, style}
    this.setState({
      card: _card
    })
    this.props.updateConfig(_card)
  }
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', ['height', 'padding', 'margin'], card.style, this.getStyle)
  }
  /**
   * @description 卡片行外层信息更新(数据源,样式等)
   */
  updateComponent = (component) => {
    this.setState({
      card: component
    })
    component.width = component.wrap.width
    component.name = component.wrap.name
    this.props.updateConfig(component)
  }
  getWrapForms = () => {
    const { wrap } = this.state.card
    return getWrapForm(wrap)
  }
  updateWrap = (res) => {
    this.updateComponent({...this.state.card, wrap: res})
  }
  render() {
    const { card } = this.state
    let _style = resetStyle(card.style)
    return (
      <div className="map-wrap" id={card.uuid} style={_style}>
        <div className="map-image" style={{backgroundImage: `url('${MkMap}')`}}></div>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <NormalForm title="设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
              <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
            </NormalForm>
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <DeleteOutlined className="close" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
            {card.wrap.datatype === 'static' ? <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/> : null}
          </div>
        } trigger="hover">
          <ToolOutlined />
        </Popover>
        <div className="component-name"><div className="center">{card.name}</div></div>
      </div>
    )
  }
}
export default MapComponent
src/mob/components/txmap/index.scss
New file
@@ -0,0 +1,35 @@
.map-wrap {
  min-height: 84px;
  position: relative;
  background: #ffffff;
  overflow: hidden;
  >.anticon-tool {
    position: absolute;
    z-index: 3;
    font-size: 16px;
    right: 1px;
    top: 1px;
    cursor: pointer;
    padding: 5px;
    background: rgba(255, 255, 255, 0.55);
  }
  .map-image {
    background: #ffffff;
    overflow: hidden;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    height: 100%;
  }
}
.map-wrap::after {
  display: block;
  content: ' ';
  clear: both;
}
.map-wrap:hover {
  z-index: 1;
  box-shadow: 0px 0px 4px #1890ff;
}
src/mob/components/txmap/options.jsx
New file
@@ -0,0 +1,28 @@
/**
 * @description Wrap表单配置信息
 */
export default function (wrap) {
  const wrapForm = [
    {
      type: 'text',
      field: 'name',
      label: '组件名称',
      initval: wrap.name || '',
      tooltip: '用于组件间的区分。',
      required: true
    },
    {
      type: 'number',
      field: 'width',
      label: '宽度',
      initval: wrap.width || 24,
      tooltip: '栅格布局,每行等分为24列。',
      min: 1,
      max: 24,
      precision: 0,
      required: true
    }
  ]
  return wrapForm
}
src/mob/mobshell/card.jsx
@@ -31,6 +31,7 @@
const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
const OfficialAccount = asyncComponent(() => import('@/mob/components/official'))
const ShareCode = asyncComponent(() => import('@/mob/components/sharecode'))
const TxMap = asyncComponent(() => import('@/mob/components/txmap'))
const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
@@ -150,6 +151,8 @@
      return (<Iframe card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'sharecode') {
      return (<ShareCode card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'map') {
      return (<TxMap card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
src/mob/mobshell/index.jsx
@@ -162,6 +162,7 @@
        timeline: '时间轴',
        officialAccount: '关注公众号',
        sharecode: '分享码',
        map: '地图',
        iframe: 'iframe',
        login: '登录'
      }
src/mob/modalconfig/index.jsx
@@ -38,7 +38,6 @@
    originConfig: null,    // 原始菜单
    sqlVerifing: false,    // sql验证
    showField: false,      // 显示表单字段值
    standardform: null,
    saving: false
  }
@@ -59,7 +58,6 @@
  componentDidMount () {
    window.GLOB.formId = ''
    MKEmitter.addListener('submitStyle', this.getStyle)
    MKEmitter.addListener('completeSave', this.completeSave)
  }
@@ -70,30 +68,11 @@
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('submitStyle', this.getStyle)
    MKEmitter.removeListener('completeSave', this.completeSave)
  }
  completeSave = () => {
    this.setState({saving: false})
  }
  getStyle = (comIds, style) => {
    const { config } = this.state
    if (comIds[0] !== 'form') return
    let Index = config.fields.findIndex(n => n.uuid === comIds[1])
    if (Index === -1) return
    let _config = fromJS(config).toJS()
    _config.fields[Index].style = style
    this.setState({
      config: _config
    })
  }
  /**
@@ -127,89 +106,18 @@
  handleForm = (_card) => {
    const { componentConfig, btn } = this.props
    const { config } = this.state
    let card = fromJS(_card).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = []
    let standardform = null
    let index = null
    config.fields.forEach((item, i) => {
      if (card.uuid === item.uuid) {
        index = i
      }
      if (!item.field || card.field === item.field) return
      if (['text', 'number', 'textarea', 'color'].includes(item.type)) {
        _inputfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
        _tabfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.type === 'switch' || item.type === 'check') {
        _linksupFields.push({
          field: item.field,
          label: item.label
        })
      }
      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
      _linksupFields.push({
        field: item.field,
        label: item.label
      })
      if (item.type === 'checkcard' && item.multiple === 'true') return
      _linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    })
    if (index !== null) {
      if (index === 0) {
        standardform = config.fields[index + 1] || null
      } else {
        standardform = config.fields[index - 1] || null
      }
    }
    let columns = componentConfig.columns
    if (btn.$sub) {
      columns = componentConfig.subColumns || []
    }
    let _fields = _linkableFields.map(cell => cell.field)
    columns.forEach(col => {
      if (col.field && !_fields.includes(col.field)) {
        _linkableFields.push({
          field: col.field,
          label: col.label + '-显示列'
        })
      }
    })
    if (card.linkSubField && card.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      card.linkSubField = card.linkSubField.filter(item => fields.includes(item))
    }
    this.setState({
      standardform,
      visible: true,
      card: card,
      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, columns)
      formlist: getModalForm(card, config.fields, columns)
    })
  }
@@ -488,7 +396,7 @@
            card={card}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            fields={config.fields}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
src/mob/modalconfig/index.scss
@@ -233,12 +233,6 @@
              opacity: 0;
              z-index: 1;
            }
            .ant-col-cuslabel {
              width: 10.5%;
            }
            .ant-col-cuswrap {
              width: 89.5%;
            }
          }
        }
        .ant-calendar-picker {
src/mob/modulesource/option.jsx
@@ -28,6 +28,7 @@
import officialAccount from '@/assets/mobimg/guanzhu.jpg'
import Iframe from '@/assets/img/newpage.jpg'
import Share from '@/assets/mobimg/share.jpg'
import MkMap from '@/assets/img/map.jpg'
// 组件配置信息
export const menuOptions = [
@@ -61,6 +62,7 @@
  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '自定义', width: 24 },
  { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '分组', width: 24 },
  { type: 'menu', url: Login, component: 'login', subtype: 'normallogin', title: '注册/登录', width: 24 },
  { type: 'menu', url: MkMap, component: 'map', subtype: 'txmap', title: '地图', width: 24, adapter: 'mini' },
  { type: 'menu', url: officialAccount, component: 'officialAccount', subtype: 'officialAccount', title: '关注公众号(小程序中)', width: 24, adapter: 'mini' },
  { type: 'menu', url: Share, component: 'sharecode', subtype: 'sharecode', title: '分享码', width: 24 },
  { type: 'menu', url: Iframe, component: 'iframe', subtype: 'iframe', title: 'iframe', width: 24 }
src/mob/searchconfig/index.scss
@@ -258,12 +258,6 @@
              opacity: 0;
              z-index: 1;
            }
            .ant-col-cuslabel {
              width: 10.5%;
            }
            .ant-col-cuswrap {
              width: 89.5%;
            }
          }
        }
        .ant-calendar-picker {
src/tabviews/basetable/index.jsx
@@ -512,8 +512,11 @@
      }
    }
    if (cell.verify && cell.verify.invalid === 'true') {
      if (item.setting.maxScript && item.setting.maxScript >= 300) {
    if (cell.verify) {
      if (cell.verify.invalid === 'true') {
        if (item.wrap && (item.wrap.datatype === 'static' || item.wrap.datatype === 'public')) {
          cell.verify.invalid = 'false'
        } else if (item.setting && item.setting.maxScript && item.setting.maxScript >= 300) {
        cell.verify.invalid = 'false'
      } else if (cell.intertype !== 'system' && cell.procMode !== 'system') {
        cell.verify.invalid = 'false'
@@ -524,7 +527,11 @@
      }
    }
    if (cell.verify && cell.verify.preHandle === 'true') {
      if (cell.verify.linkEnable === 'true' && /@/.test(cell.verify.linkUrl)) {
        cell.returnValue = 'true'
      }
      if (cell.verify.preHandle === 'true') {
      let script = cell.verify.pre_func
      if (!/#position-/.test(script) || /#position-init/.test(script)) {
        try {
@@ -545,6 +552,7 @@
        cell.$callbackScript = script
      }
    }
    }
    if (cell.syncComponentId) {
      if (cell.syncComponentId === item.setting.supModule) {
src/tabviews/custom/components/card/balcony/index.jsx
@@ -25,7 +25,6 @@
    data: {},
    BData: null,
    syncData: [],
    show: true,
    checked: false
  }
@@ -112,7 +111,6 @@
      }
    }
    let show = true
    let syncConfig = null
    if (_config.wrap.linkType === 'sync') {
      syncConfig = _config.syncConfig
@@ -123,12 +121,9 @@
        }
        return item
      })
    } else if (_config.wrap.linkType === 'sup' && _config.wrap.supControl === 'hidden') {
      show = false
    }
    this.setState({
      show,
      syncConfig,
      data: _data,
      BID: BID || '',
@@ -330,10 +325,6 @@
    } else {
      if (!config.wrap.supModule || config.wrap.supModule !== MenuID) return
  
      if (config.wrap.supControl === 'hidden') {
        this.setState({ show: id ? true : false })
      }
      if (id !== this.state.BID || id !== '') {
        this.setState({ BID: id, BData: data }, () => {
          this.loadData()
@@ -461,9 +452,10 @@
  }
  render() {
    const { config, loading, data, show, syncConfig, syncData, checked } = this.state
    const { config, loading, data, syncConfig, syncData, checked, BID } = this.state
    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
    if (config.wrap.supControl === 'hidden' && !BID) return null
    let style = {...config.style}
    if (config.wrap.bgField) {
@@ -471,7 +463,7 @@
    }
    
    return (
      <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} id={'anchor' + config.uuid} style={style} onClick={this.triggerButton}>
      <div className="custom-balcony-box" id={'anchor' + config.uuid} style={style} onClick={this.triggerButton}>
        {loading ?
          <div className="loading-mask" onClick={(e) => e.stopPropagation()}>
            <div className="ant-spin-blur"></div>
src/tabviews/custom/components/card/balcony/index.scss
@@ -66,9 +66,6 @@
    }
  }
}
.custom-balcony-box.hidden {
  display: none;
}
.custom-balcony-box::after {
  content: ' ';
src/tabviews/custom/components/card/data-card/index.jsx
@@ -750,6 +750,10 @@
      if (config.setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      }
      if (config.$hasTopModule) {
        window.GLOB.CacheData.set(config.uuid + 'tb', { $$empty: true, $$uuid: '' })
        MKEmitter.emit('mkPublicData', config.uuid + 'tb', { $$empty: true, $$uuid: '' })
      }
      return
    }
@@ -852,6 +856,11 @@
        loading: false
      })
      if (config.$hasTopModule) {
        window.GLOB.CacheData.set(config.uuid + 'tb', data[0] || { $$empty: true, $$uuid: '' })
        MKEmitter.emit('mkPublicData', config.uuid + 'tb', data[0] || { $$empty: true, $$uuid: '' })
      }
      if (config.timer && config.clearField && result.data && result.data[0]) {
        let vals = (config.clearValue || '').split(',')
        if (vals.includes(result.data[0][config.clearField])) {
src/tabviews/custom/components/chart/antv-X6/index.jsx
@@ -1938,6 +1938,16 @@
          this.selectNode.attr('line/strokeDasharray', 0)
        }
      } else if (key === 'mkdata') {
        if (!node.mkdata) {
          if (node.target && node.target.cell) {
            let cell = this.mkGraph.getCellById(node.target.cell)
            if (cell) {
              cell.prop('mkdata', {status: value.status, statusName: value.statusName || ''})
            }
          }
        }
        this.selectNode.prop('mkdata', value)
      }
    } else if (node.shape === 'lane') {
src/tabviews/custom/components/module/invoice/index.jsx
@@ -541,6 +541,22 @@
  outBill = () => {
    const { config, BID, saveType } = this.state
    if (window.GLOB.storeFiles) {
      if (!window.GLOB.storeDate || window.GLOB.storeDate < 0) {
        Modal.warning({
          title: `电子档案存储包已过期。`,
          okText: '知道了'
        })
        return
      } else if (window.GLOB.storeDate < 30) {
        notification.warning({
          top: 92,
          message: `电子档案存储包还剩${window.GLOB.storeDate}天。`,
          duration: 5
        })
      }
    }
    if (window.GLOB.systemType === 'production' && !config.billOutBtn.proInterface) {
      notification.warning({
        top: 92,
@@ -797,6 +813,10 @@
    param.data.invoiceTypeCode = trans[param.data.invoiceTypeCode] || ''
    if (window.GLOB.storeFiles) {
      param.store = true
    }
    let url = ''
    if (window.GLOB.systemType === 'production') {
      url = config.billOutBtn.proInterface
src/tabviews/custom/components/table/base-table/index.jsx
@@ -110,9 +110,9 @@
      
      MKEmitter.emit('resetSelectLine', config.uuid, '', '') // 广播数据切换
      reset && MKEmitter.emit('resetTable', config.uuid, 'true') // 列表重置
      if (setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      }
      // if (setting.$hasSyncModule) {
      //   MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      // }
      this.requestId = ''
      return
@@ -173,9 +173,9 @@
        }
      } else {
        MKEmitter.emit('resetSelectLine', config.uuid, '', '') // 广播数据切换
        if (setting.$hasSyncModule) {
          MKEmitter.emit('syncBalconyData', config.uuid, [], false)
        }
        // if (setting.$hasSyncModule) {
        //   MKEmitter.emit('syncBalconyData', config.uuid, [], false)
        // }
      }
      
      reset && MKEmitter.emit('resetTable', config.uuid, repage) // 列表重置
src/tabviews/custom/components/table/normal-table/index.jsx
@@ -530,6 +530,10 @@
      if (setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      }
      if (config.$hasTopModule) {
        window.GLOB.CacheData.set(config.uuid + 'tb', { $$empty: true, $$uuid: '' })
        MKEmitter.emit('mkPublicData', config.uuid + 'tb', { $$empty: true, $$uuid: '' })
      }
      this.loaded = true
      this.requestId = ''
@@ -653,6 +657,11 @@
        loading: false
      })
      if (config.$hasTopModule) {
        window.GLOB.CacheData.set(config.uuid + 'tb', data[0] || { $$empty: true, $$uuid: '' })
        MKEmitter.emit('mkPublicData', config.uuid + 'tb', data[0] || { $$empty: true, $$uuid: '' })
      }
      if (config.timer && config.clearField && result.data && result.data[0]) {
        let vals = (config.clearValue || '').split(',')
        if (vals.includes(result.data[0][config.clearField])) {
src/tabviews/custom/index.jsx
@@ -204,6 +204,7 @@
      // 权限过滤
      let roleId = sessionStorage.getItem('role_id') || '' // 角色ID
      let balMap = new Map()
      let tbMap = new Map()
      let skip = config.permission === 'false' || window.GLOB.mkHS
      let urlparam = {} // url参数
      if (param) {
@@ -261,7 +262,7 @@
      let initInters = []
      config.interfaces = this.formatInterSetting(config.interfaces, regs, MenuID, initInters, config.MenuName)
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, balMap, skip, urlparam, MenuID, config.interfaces, config.$cache, config.$time, config.MenuName, MenuID, MenuID, config.process === 'true')
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, balMap, tbMap, skip, urlparam, MenuID, config.$cache, config.$time, config.MenuName, MenuID, MenuID, config.process === 'true', regs)
      let params = []
      let BID = urlparam.$BID || ''
@@ -284,11 +285,7 @@
        }
      })
      config.components = this.formatSetting(config.components, params, inherit, regs, balMap)
      if (balMap.size > 0) {
        config.components = this.filterBalcony(config.components, balMap)
      }
      config.components = this.formatSetting(config.components, params, inherit, config.interfaces, balMap, tbMap)
      if (initInters.length > 0) {
        this.stepInter = {
@@ -380,7 +377,7 @@
    }
  }
  filterComponent = (components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, cache, time, MenuName, searchId, syncId, process) => {
  filterComponent = (components, roleId, permAction, balMap, tbMap, skip, urlparam, pageId, cache, time, MenuName, searchId, syncId, process, regs) => {
    return components.filter(item => {
      item.$pageId = pageId
      item.$searchId = searchId
@@ -497,7 +494,7 @@
            _searchId = tab.uuid
          }
          tab.components = this.filterComponent(tab.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, cache, time, MenuName, _searchId, tab.uuid, process)
          tab.components = this.filterComponent(tab.components, roleId, permAction, balMap, tbMap, skip, urlparam, pageId, cache, time, MenuName, _searchId, tab.uuid, process, regs)
          
          if (_searchId === tab.uuid) {
            tab.components.forEach(cell => {
@@ -521,7 +518,7 @@
          return false
        }
        item.components = this.filterComponent(item.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, cache, time, MenuName, searchId, syncId, process)
        item.components = this.filterComponent(item.components, roleId, permAction, balMap, tbMap, skip, urlparam, pageId, cache, time, MenuName, searchId, syncId, process, regs)
        return true
      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter', 'chart', 'antvG6', 'antvX6'].includes(item.type)) {
@@ -537,16 +534,6 @@
          item.wrap.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
        ) {
          return false
        }
        if (item.wrap.datatype === 'public') {
          let inter = interfaces.filter(int => item.wrap.publicId === int.uuid)[0]
          if (!inter) {
            item.wrap.datatype = 'static'
          } else {
            item.setting = {...inter.setting}
            item.$searchId = inter.$searchId
          }
        }
      }
@@ -785,6 +772,9 @@
          item.wrap.supModule = item.wrap.supModule.pop()
          item.setting.supModule = item.wrap.supModule
        }
        if (item.wrap.datatype === 'public') {
          balMap.set(item.wrap.publicId + 'public', true)
        }
        item.elements = item.elements.filter(cell => {
          if (cell.eleType === 'button') {
            if (cell.hidden === 'true') return false
@@ -844,42 +834,90 @@
        }
      }
      
      return true
      // 整理数据源
      if (item.setting && item.format && (!item.wrap || !['public', 'static'].includes(item.wrap.datatype))) {
        item.setting.arr_field = item.columns ? item.columns.map(col => col.field).join(',') : ''
        item.setting.useMSearch = item.setting.useMSearch === 'true'
        item.setting.laypage = item.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
        if (item.wrap && item.wrap.goback === 'true') {
          item.setting.sync = 'false'
        }
        if (item.format === 'object') {
          item.setting.laypage = false
          item.setting.$top = true
        }
        if (item.setting.interType !== 'system') { // 不使用系统函数时
          item.setting.sync = 'false'
          item.setting.dataresource = ''
        } else {
          let _customScript = ''
          let _tailScript = ''
          item.scripts && item.scripts.forEach(script => {
            if (script.status === 'false') return
            if (script.position !== 'back') {
              _customScript += `
              ${script.sql}
              `
            } else {
              _tailScript += `
              ${script.sql}
              `
            }
    })
          delete item.scripts
          item.setting.$name = item.$menuname || ''
          item.setting.execute = item.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
          if (!item.setting.execute) {
            item.setting.dataresource = ''
          }
          if (/\s/.test(item.setting.dataresource)) {
            item.setting.dataresource = '(' + item.setting.dataresource + ') tb'
  }
  filterBalcony = (components, balMap) => {
    return components.filter(item => {
      if (item.type === 'tabs') {
        item.subtabs = item.subtabs.map(tab => {
          tab.components = this.filterBalcony(tab.components, balMap)
          return tab
          if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
            item.setting.dataresource = item.setting.dataresource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
            _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
            _tailScript = _tailScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
          } else {
            item.setting.dataresource = item.setting.dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
            _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
            _tailScript = _tailScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
          }
          regs.forEach(cell => {
            item.setting.dataresource = item.setting.dataresource.replace(cell.reg, cell.value)
            _customScript = _customScript.replace(cell.reg, cell.value)
            _tailScript = _tailScript.replace(cell.reg, cell.value)
        })
      } else if (item.type === 'group') {
        item.components = this.filterBalcony(item.components, balMap)
          item.setting.customScript = _customScript // 整理后自定义脚本
          item.setting.tailScript = _tailScript     // 后置自定义脚本
          item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
          if (!item.setting.execute || item.setting.custompage) {
            item.forbidLine = true
      }
      if (item.type === 'balcony' && item.wrap.linkType === 'sync') {
        let conf = balMap.get(item.wrap.syncModuleId)
          if (item.setting.sync === 'true') {
            // pageable 是否分页,组件属性,不分页的组件才可以统一查询
            if ((!item.pageable || (item.pageable && !item.setting.laypage)) && item.setting.onload === 'true') {
        if (!conf || conf === true) {
          return false
            } else {
              item.setting.sync = 'false'
            }
          }
        }
        }
        
        item.syncConfig = {
          uuid: conf.uuid,
          wrap: conf.wrap,
          setting: conf.setting,
          columns: conf.columns
        }
        if (item.wrap.checkAll === 'show') {
          if (conf.subtype === 'datacard' && conf.wrap.cardType !== 'checkbox') {
            item.wrap.checkAll = 'hidden'
          } else if (conf.subtype === 'normaltable' && conf.wrap.tableType !== 'checkbox') {
            item.wrap.checkAll = 'hidden'
          }
        }
      if (item.type === 'card' && item.subtype === 'datacard') {
        tbMap.set(item.uuid, item)
      } else if (item.type === 'table' && item.subtype !== 'editable') {
        tbMap.set(item.uuid, item)
      }
      
      return true
@@ -931,7 +969,8 @@
      cell.modal.uuid = cell.uuid + 'pop'
    }
    if (cell.verify && cell.verify.invalid === 'true') {
    if (cell.verify) {
      if (cell.verify.invalid === 'true') {
      if (item.wrap && (item.wrap.datatype === 'static' || item.wrap.datatype === 'public')) {
        cell.verify.invalid = 'false'
      } else if (item.setting && item.setting.maxScript && item.setting.maxScript >= 300) {
@@ -945,7 +984,11 @@
      }
    }
    if (cell.verify && cell.verify.preHandle === 'true') {
      if (cell.verify.linkEnable === 'true' && /@/.test(cell.verify.linkUrl)) {
        cell.returnValue = 'true'
      }
      if (cell.verify.preHandle === 'true') {
      let script = cell.verify.pre_func
      if (!/#position-/.test(script) || /#position-init/.test(script)) {
        try {
@@ -964,6 +1007,7 @@
      }
      if (/#position-callback/.test(script)) {
        cell.$callbackScript = script
        }
      }
    }
@@ -1083,20 +1127,64 @@
  }
  // 格式化默认设置
  formatSetting = (components, params, inherit, regs, balMap) => {
  formatSetting = (components, params, inherit, interfaces, balMap, tbMap) => {
    let delay = 20
    return components.map(component => {
      if (component.type === 'tabs') {
        component.subtabs = component.subtabs.map(tab => {
          tab.components = this.formatSetting(tab.components, null, inherit, regs, balMap)
          tab.components = this.formatSetting(tab.components, null, inherit, interfaces, balMap, tbMap)
          tab = {...tab, ...inherit}
          return tab
        })
        return component
      } else if (component.type === 'group') {
        component.components = this.formatSetting(component.components, params, null, regs, balMap)
        component.components = this.formatSetting(component.components, params, null, interfaces, balMap, tbMap)
        return component
      } else if (component.wrap && component.wrap.datatype === 'public') {
      }
      if (component.type === 'balcony') {
        if (component.wrap.linkType === 'sync') {
          let conf = tbMap.get(component.wrap.syncModuleId)
          if (conf) {
            component.syncConfig = {
              uuid: conf.uuid,
              wrap: conf.wrap,
              setting: conf.setting,
              columns: conf.columns
            }
            if (component.wrap.checkAll === 'show') {
              if (conf.subtype === 'datacard' && conf.wrap.cardType !== 'checkbox') {
                component.wrap.checkAll = 'hidden'
              } else if (conf.subtype === 'normaltable' && conf.wrap.tableType !== 'checkbox') {
                component.wrap.checkAll = 'hidden'
              }
            }
          }
        }
      } else if (balMap.has(component.uuid)) {
        component.setting.$hasSyncModule = true
      }
      if (balMap.has(component.uuid + 'public')) {
        component.$hasTopModule = true
      }
      if (component.wrap && component.wrap.datatype === 'public') {
        if (tbMap.has(component.wrap.publicId)) {
          let tb = tbMap.get(component.wrap.publicId)
          component.setting = {...tb.setting}
          component.$searchId = tb.$searchId
          component.wrap.publicId = component.wrap.publicId + 'tb'
        } else {
          let inter = interfaces.filter(int => component.wrap.publicId === int.uuid)[0]
          if (!inter) {
            component.wrap.datatype = 'static'
          } else {
            component.setting = {...inter.setting}
            component.$searchId = inter.$searchId
          }
        }
        return component
      } else if (component.wrap && component.wrap.datatype === 'static') {
        component.format = ''
@@ -1108,10 +1196,6 @@
      } else if (!component.setting || !component.format) {
        return component
      }
      component.setting.arr_field = component.columns ? component.columns.map(col => col.field).join(',') : ''
      component.setting.useMSearch = component.setting.useMSearch === 'true'
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      
      if (component.setting.useMSearch) {
        if (!window.GLOB.SearchBox.has(component.$searchId)) {
@@ -1127,79 +1211,7 @@
        }
      }
      if (component.wrap && component.wrap.goback === 'true') {
        component.setting.sync = 'false'
      }
      if (component.format === 'object') {
        component.setting.laypage = false
        component.setting.$top = true
      }
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.dataresource = ''
        return component
      }
      let _customScript = ''
      let _tailScript = ''
      component.scripts && component.scripts.forEach(script => {
        if (script.status === 'false') return
        if (script.position !== 'back') {
          _customScript += `
          ${script.sql}
          `
        } else {
          _tailScript += `
          ${script.sql}
          `
        }
      })
      delete component.scripts
      component.setting.$name = component.$menuname || ''
      component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
      if (!component.setting.execute) {
        component.setting.dataresource = ''
      }
      if (/\s/.test(component.setting.dataresource)) {
        component.setting.dataresource = '(' + component.setting.dataresource + ') tb'
      }
      if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
        component.setting.dataresource = component.setting.dataresource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
        _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
        _tailScript = _tailScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
      } else {
        component.setting.dataresource = component.setting.dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
        _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
        _tailScript = _tailScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
      }
      regs.forEach(cell => {
        component.setting.dataresource = component.setting.dataresource.replace(cell.reg, cell.value)
        _customScript = _customScript.replace(cell.reg, cell.value)
        _tailScript = _tailScript.replace(cell.reg, cell.value)
      })
      component.setting.customScript = _customScript // 整理后自定义脚本
      component.setting.tailScript = _tailScript     // 后置自定义脚本
      component.setting.custompage = /@pageSize@|@orderBy@/i.test(component.setting.dataresource + component.setting.customScript)
      if (!component.setting.execute || component.setting.custompage) {
        component.forbidLine = true
      }
      if (component.setting.sync === 'true') {
        // pageable 是否分页,组件属性,不分页的组件才可以统一查询
        if ((!component.pageable || (component.pageable && !component.setting.laypage)) && component.setting.onload === 'true') {
        } else {
          component.setting.sync = 'false'
        }
      }
      if (component.setting.interType !== 'system') return component
      // dataName 系统生成的数据源名称
      if (component.setting.sync === 'true') {
@@ -1229,11 +1241,6 @@
      
      component.setting.delay = delay
      delay += 20
      if (balMap.has(component.uuid)) {
        component.setting.$hasSyncModule = true
        balMap.set(component.uuid, component)
      }
      return component
    })
src/tabviews/custom/popview/index.jsx
@@ -106,6 +106,7 @@
    // 权限过滤
    let roleId = sessionStorage.getItem('role_id') || '' // 角色ID
    let balMap = new Map()
    let tbMap = new Map()
    let urlparam = {} // url参数
    if (param) {
      Object.keys(param).forEach(key => {
@@ -139,7 +140,7 @@
      regs.push({ reg: /@works_flow_code@/ig, value: `'${flow.flow_code || ''}'` })
    }
    config.components = this.filterComponent(config.components, roleId, balMap, urlparam, Tab, Tab.uuid, Tab.uuid)
    config.components = this.filterComponent(config.components, roleId, balMap, tbMap, urlparam, Tab, Tab.uuid, Tab.uuid, regs)
    
    // 获取主搜索条件
    config.components.forEach(component => {
@@ -155,11 +156,7 @@
    let params = []
    let BID = urlparam.$BID || ''
    config.components = this.formatSetting(config.components, params, regs, balMap)
    if (balMap.size > 0) {
      config.components = this.filterBalcony(config.components, balMap)
    }
    config.components = this.formatSetting(config.components, params, balMap, tbMap)
    this.setState({
      BID: BID,
@@ -171,7 +168,7 @@
    })
  }
  filterComponent = (components, roleId, balMap, urlparam, Tab, searchId, syncId) => {
  filterComponent = (components, roleId, balMap, tbMap, urlparam, Tab, searchId, syncId, regs) => {
    return components.filter(item => {
      item.$pageId = Tab.uuid
      item.$searchId = searchId
@@ -271,7 +268,7 @@
            _searchId = tab.uuid
          }
          tab.components = this.filterComponent(tab.components, roleId, balMap, urlparam, Tab, _searchId, tab.uuid)
          tab.components = this.filterComponent(tab.components, roleId, balMap, tbMap, urlparam, Tab, _searchId, tab.uuid, regs)
          if (_searchId === tab.uuid) {
            tab.components.forEach(cell => {
@@ -295,7 +292,7 @@
          return false
        }
        item.components = this.filterComponent(item.components, roleId, balMap, urlparam, Tab, searchId, syncId)
        item.components = this.filterComponent(item.components, roleId, balMap, tbMap, urlparam, Tab, searchId, syncId, regs)
        return true
      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter', 'chart'].includes(item.type)) {
@@ -501,6 +498,9 @@
          item.wrap.supModule = item.wrap.supModule.pop()
          item.setting.supModule = item.wrap.supModule
        }
        if (item.wrap.datatype === 'public') {
          balMap.set(item.wrap.publicId + 'public', true)
        }
        item.elements = item.elements.filter(cell => {
          if (cell.eleType === 'button') {
            if (cell.hidden === 'true' || cell.OpenType === 'popview') return false
@@ -546,42 +546,90 @@
        })
      }
      
      return true
      // 整理数据源
      if (item.setting && item.format && (!item.wrap || !['public', 'static'].includes(item.wrap.datatype))) {
        item.setting.arr_field = item.columns ? item.columns.map(col => col.field).join(',') : ''
        item.setting.useMSearch = item.setting.useMSearch === 'true'
        item.setting.laypage = item.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
        if (item.wrap && item.wrap.goback === 'true') {
          item.setting.sync = 'false'
        }
        if (item.format === 'object') {
          item.setting.laypage = false
          item.setting.$top = true
        }
        if (item.setting.interType !== 'system') { // 不使用系统函数时
          item.setting.sync = 'false'
          item.setting.dataresource = ''
        } else {
          let _customScript = ''
          let _tailScript = ''
          item.scripts && item.scripts.forEach(script => {
            if (script.status === 'false') return
            if (script.position !== 'back') {
              _customScript += `
              ${script.sql}
              `
            } else {
              _tailScript += `
              ${script.sql}
              `
            }
    })
          delete item.scripts
          item.setting.$name = item.$menuname || ''
          item.setting.execute = item.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
          if (!item.setting.execute) {
            item.setting.dataresource = ''
          }
          if (/\s/.test(item.setting.dataresource)) {
            item.setting.dataresource = '(' + item.setting.dataresource + ') tb'
  }
  filterBalcony = (components, balMap) => {
    return components.filter(item => {
      if (item.type === 'tabs') {
        item.subtabs = item.subtabs.map(tab => {
          tab.components = this.filterBalcony(tab.components, balMap)
          return tab
          if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
            item.setting.dataresource = item.setting.dataresource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
            _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
            _tailScript = _tailScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
          } else {
            item.setting.dataresource = item.setting.dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
            _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
            _tailScript = _tailScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
          }
          regs.forEach(cell => {
            item.setting.dataresource = item.setting.dataresource.replace(cell.reg, cell.value)
            _customScript = _customScript.replace(cell.reg, cell.value)
            _tailScript = _tailScript.replace(cell.reg, cell.value)
        })
      } else if (item.type === 'group') {
        item.components = this.filterBalcony(item.components, balMap)
          item.setting.customScript = _customScript // 整理后自定义脚本
          item.setting.tailScript = _tailScript     // 后置自定义脚本
          item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
          if (!item.setting.execute || item.setting.custompage) {
            item.forbidLine = true
      }
      if (item.type === 'balcony' && item.wrap.linkType === 'sync') {
        let conf = balMap.get(item.wrap.syncModuleId)
          if (item.setting.sync === 'true') {
            // pageable 是否分页,组件属性,不分页的组件才可以统一查询
            if ((!item.pageable || (item.pageable && !item.setting.laypage)) && item.setting.onload === 'true') {
        if (!conf || conf === true) {
          return false
            } else {
              item.setting.sync = 'false'
            }
          }
        }
        }
        
        item.syncConfig = {
          uuid: conf.uuid,
          wrap: conf.wrap,
          setting: conf.setting,
          columns: conf.columns
        }
        if (item.wrap.checkAll === 'show') {
          if (conf.subtype === 'datacard' && conf.wrap.cardType !== 'checkbox') {
            item.wrap.checkAll = 'hidden'
          } else if (conf.subtype === 'normaltable' && conf.wrap.tableType !== 'checkbox') {
            item.wrap.checkAll = 'hidden'
          }
        }
      if (item.type === 'card' && item.subtype === 'datacard') {
        tbMap.set(item.uuid, item)
      } else if (item.type === 'table' && item.subtype !== 'editable') {
        tbMap.set(item.uuid, item)
      }
      
      return true
@@ -628,21 +676,26 @@
      }
    }
    if (cell.verify && cell.verify.invalid === 'true') {
      if (item.wrap && item.wrap.datatype === 'static') {
    if (cell.verify) {
      if (cell.verify.invalid === 'true') {
        if (item.wrap && (item.wrap.datatype === 'static' || item.wrap.datatype === 'public')) {
        cell.verify.invalid = 'false'
      } else if (item.setting && item.setting.maxScript && item.setting.maxScript >= 300) {
          cell.verify.invalid = 'false'
        } else if (cell.intertype !== 'system' && cell.procMode !== 'system') {
        cell.verify.invalid = 'false'
      } else if (cell.sqlType === 'insert') {
        cell.verify.invalid = 'false'
      } else if (cell.Ot === 'notRequired') {
        cell.verify.invalid = 'false'
      } else if (cell.intertype !== 'system' && cell.procMode !== 'system') {
        cell.verify.invalid = 'false'
      }
    }
    if (cell.verify && cell.verify.preHandle === 'true') {
      if (cell.verify.linkEnable === 'true' && /@/.test(cell.verify.linkUrl)) {
        cell.returnValue = 'true'
      }
      if (cell.verify.preHandle === 'true') {
      let script = cell.verify.pre_func
      if (!/#position-/.test(script) || /#position-init/.test(script)) {
        try {
@@ -661,6 +714,7 @@
      }
      if (/#position-callback/.test(script)) {
        cell.$callbackScript = script
        }
      }
    }
@@ -760,20 +814,63 @@
  }
  // 格式化默认设置
  formatSetting = (components, params, regs, balMap) => {
  formatSetting = (components, params, balMap, tbMap) => {
    let delay = 20
    return components.map(component => {
      if (component.type === 'tabs') {
        component.subtabs = component.subtabs.map(tab => {
          tab.components = this.formatSetting(tab.components, null, regs, balMap)
          tab.components = this.formatSetting(tab.components, null, balMap, tbMap)
          return tab
        })
        return component
      } else if (component.type === 'group') {
        component.components = this.formatSetting(component.components, params, regs, balMap)
        component.components = this.formatSetting(component.components, params, balMap, tbMap)
        return component
      } else if (component.wrap && (component.wrap.datatype === 'static' || component.wrap.datatype === 'public')) {
      }
      if (component.type === 'balcony') {
        if (component.wrap.linkType === 'sync') {
          let conf = tbMap.get(component.wrap.syncModuleId)
          if (conf) {
            component.syncConfig = {
              uuid: conf.uuid,
              wrap: conf.wrap,
              setting: conf.setting,
              columns: conf.columns
            }
            if (component.wrap.checkAll === 'show') {
              if (conf.subtype === 'datacard' && conf.wrap.cardType !== 'checkbox') {
                component.wrap.checkAll = 'hidden'
              } else if (conf.subtype === 'normaltable' && conf.wrap.tableType !== 'checkbox') {
                component.wrap.checkAll = 'hidden'
              }
            }
          }
        }
      } else if (balMap.has(component.uuid)) {
        component.setting.$hasSyncModule = true
      }
      if (balMap.has(component.uuid + 'public')) {
        component.$hasTopModule = true
      }
      if (component.wrap && component.wrap.datatype === 'public') {
        if (tbMap.has(component.wrap.publicId)) {
          let tb = tbMap.get(component.wrap.publicId)
          component.setting = {...tb.setting}
          component.$searchId = tb.$searchId
          component.wrap.publicId = component.wrap.publicId + 'tb'
        } else {
        component.wrap.datatype = 'static'
          component.setting = component.setting || {}
          component.setting.useMSearch = false
          component.setting.sync = 'false'
        }
        return component
      } else if (component.wrap && component.wrap.datatype === 'static') {
        component.format = ''
        component.setting = component.setting || {}
        component.setting.useMSearch = false
@@ -784,10 +881,6 @@
        return component
      }
      component.setting.arr_field = component.columns ? component.columns.map(col => col.field).join(',') : ''
      component.setting.useMSearch = component.setting.useMSearch === 'true'
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      if (component.setting.useMSearch) {
        if (!window.GLOB.SearchBox.has(component.$searchId)) {
          component.setting.useMSearch = false
@@ -796,75 +889,7 @@
        }
      }
      if (component.format === 'object') {
        component.setting.laypage = false
        component.setting.$top = true
      }
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.dataresource = ''
        return component
      }
      let _customScript = ''
      let _tailScript = ''
      component.scripts && component.scripts.forEach(script => {
        if (script.status === 'false') return
        if (script.position !== 'back') {
          _customScript += `
          ${script.sql}
          `
        } else {
          _tailScript += `
          ${script.sql}
          `
        }
      })
      delete component.scripts
      component.setting.$name = component.$menuname || ''
      component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
      if (!component.setting.execute) {
        component.setting.dataresource = ''
      }
      if (/\s/.test(component.setting.dataresource)) {
        component.setting.dataresource = '(' + component.setting.dataresource + ') tb'
      }
      if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
        component.setting.dataresource = component.setting.dataresource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
        _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
        _tailScript = _tailScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
      } else {
        component.setting.dataresource = component.setting.dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
        _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
        _tailScript = _tailScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
      }
      regs.forEach(cell => {
        component.setting.dataresource = component.setting.dataresource.replace(cell.reg, cell.value)
        _customScript = _customScript.replace(cell.reg, cell.value)
        _tailScript = _tailScript.replace(cell.reg, cell.value)
      })
      component.setting.customScript = _customScript // 整理后自定义脚本
      component.setting.tailScript = _tailScript     // 后置自定义脚本
      component.setting.custompage = /@pageSize@|@orderBy@/i.test(component.setting.dataresource + component.setting.customScript)
      if (!component.setting.execute || component.setting.custompage) {
        component.forbidLine = true
      }
      if (component.setting.sync === 'true') {
        // pageable 是否分页,组件属性,不分页的组件才可以统一查询
        if ((!component.pageable || (component.pageable && !component.setting.laypage)) && component.setting.onload === 'true') {
        } else {
          component.setting.sync = 'false'
        }
      }
      if (component.setting.interType !== 'system') return component
      // dataName 系统生成的数据源名称
      if (component.setting.sync === 'true') {
@@ -894,11 +919,6 @@
      component.setting.delay = delay
      delay += 20
      if (balMap.has(component.uuid)) {
        component.setting.$hasSyncModule = true
        balMap.set(component.uuid, component)
      }
      return component
    })
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -2320,7 +2320,7 @@
      Modal.success({
        title: msg,
        onOk: () => {
          this.successContinue(sign, id)
          this.successContinue(sign, id, res)
        }
      })
      return
@@ -2328,10 +2328,10 @@
    }
    this.successContinue(sign, id)
    this.successContinue(sign, id, res)
  }
  successContinue = (sign, id) => {
  successContinue = (sign, id, res) => {
    const { btn } = this.props
    const { btnconfig } = this.state
@@ -2452,6 +2452,16 @@
      } else {
        url = btn.verify.linkUrl
      }
      if (/@/.test(url)) {
        Object.keys(res).forEach(key => {
          url = url.replace(new RegExp('@' + key + '@', 'ig'), res[key])
        })
      }
      if (!/^http/.test(url)) {
        url = window.location.origin + url
      }
      window.open(url)
    }
  }
@@ -2586,9 +2596,9 @@
      if (verify.wxNoteLink === 'url' && verify.wxNoteLinkUrl) {
        _param.url = verify.wxNoteLinkUrl
      } else if (verify.wxNoteLink === 'miniProgram' && window.GLOB.WXminiAppID) {
      } else if (verify.wxNoteLink === 'miniProgram' && (window.GLOB.WXminiAppID || verify.wxNoteMiniId)) {
        _param.miniprogram = {
          appid: window.GLOB.WXminiAppID,
          appid: verify.wxNoteMiniId || window.GLOB.WXminiAppID,
          pagepath: '/pages/index/index'
        }
src/tabviews/zshare/mutilform/index.jsx
@@ -476,6 +476,12 @@
            message: '请选择' + item.label + '!'
          })
        }
        if (['cascader', 'checkbox', 'checkcard', 'fileupload', 'multiselect'].includes(item.type) && item.fieldlength) {
          item.rules.push({
            max: item.fieldlength,
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
          })
        }
      }
      if (item.rules.length === 0) {
@@ -547,7 +553,7 @@
          item.subFields = []
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea'].includes(n.type)) {
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m
@@ -570,7 +576,7 @@
          item.subFields = []
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea'].includes(n.type)) {
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m
@@ -590,7 +596,7 @@
          item.subFields = []
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea'].includes(n.type)) {
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m
@@ -602,7 +608,7 @@
          item.subFields = []
          item.linkSubField.forEach(m => {
            let n = fieldMap.get(m)
            if (n && ['text', 'number', 'textarea'].includes(n.type)) {
            if (n && ['text', 'number', 'textarea', 'select'].includes(n.type)) {
              item.subFields.push({
                uuid: n.uuid,
                field: m
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx
@@ -270,6 +270,14 @@
      })
    }
    if (config.linkFields) {
      config.linkFields.forEach((m, i) => {
        setTimeout(() => {
          MKEmitter.emit('mkFP', m.uuid, val, 0)
        }, (i + 1) * 100)
      })
    }
    this.props.onChange(val, other)
    this.setState({value: val, showValue: ''}, () => {
      if (config.enter === 'tab') {
src/tabviews/zshare/mutilform/mkSelect/index.jsx
@@ -79,12 +79,15 @@
    MKEmitter.removeListener('mkFC', this.mkFormFocus)
  }
  mkFormFocus = (type, uuid) => {
  mkFormFocus = (type, uuid, val, level) => {
    if (uuid !== this.props.config.uuid) return
    if (type !== 'focus') return
    if (type === 'focus') {
    let _div = document.getElementById(uuid)
    _div && _div.click && _div.click()
    } else if (type === 'input' && (!level || level < 10)) {
      let _level = level || 1
      this.selectChange(val, _level++)
    }
  }
  mkFormHandle = (uuid, parentId, level) => {
@@ -123,7 +126,7 @@
    }
  }
  selectChange = (val) => {
  selectChange = (val, level) => {
    const { config } = this.state
    let other = {}
@@ -132,7 +135,7 @@
      option && config.subFields.forEach((n, i) => {
        other[n.field] = option[n.field]
        setTimeout(() => {
          MKEmitter.emit('mkFC', 'input', n.uuid, option[n.field])
          MKEmitter.emit('mkFC', 'input', n.uuid, option[n.field], level)
        }, i * 5)
      })
    }
@@ -177,7 +180,7 @@
          value={value}
          dropdownMatchSelectWidth={config.dropdown !== 'false'}
          filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
          onSelect={this.selectChange}
          onSelect={(val) => this.selectChange(val)}
          onChange={(val) => val === undefined && this.selectChange('')}
          disabled={config.readonly}
        >
src/templates/modalconfig/dragelement/index.scss
@@ -128,12 +128,6 @@
      opacity: 0;
      z-index: 1;
    }
    .ant-col-cuslabel {
      width: 10.5%;
    }
    .ant-col-cuswrap {
      width: 89.5%;
    }
  }
  .ant-form-item label > .anticon {
    vertical-align: middle;
src/templates/modalconfig/index.jsx
@@ -14,7 +14,6 @@
import asyncComponent from '@/utils/asyncComponent'
import { BaseConfig, SearchItems } from './source'
import { updateForm } from '@/utils/utils-update.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const { Panel } = Collapse
@@ -124,7 +123,7 @@
  componentDidMount() {
    window.GLOB.formId = ''
    MKEmitter.addListener('submitStyle', this.getStyle)
    document.onkeydown = (event) => {
      let e = event || window.event
      let keyCode = e.keyCode || e.which || e.charCode
@@ -157,7 +156,6 @@
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    MKEmitter.removeListener('submitStyle', this.getStyle)
    this.setState = () => {
      return
    }
@@ -184,24 +182,6 @@
    }
    this.props.handleView(param)
  }
  getStyle = (comIds, style) => {
    const { config } = this.state
    if (comIds[0] !== 'form') return
    let Index = config.fields.findIndex(n => n.uuid === comIds[1])
    if (Index === -1) return
    let _config = fromJS(config).toJS()
    _config.fields[Index].style = style
    this.setState({
      config: _config
    })
  }
  /**
@@ -236,112 +216,21 @@
  handleForm = (_card) => {
    const { menu, tabConfig, subTabConfig } = this.props
    const { config } = this.state
    let card = fromJS(_card).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = []
    let standardform = null
    let index = null
    config.fields.forEach((item, i) => {
      if (card.uuid === item.uuid) {
        index = i
      }
      if (!item.field || card.field === item.field) return
      if (['text', 'number', 'textarea', 'color'].includes(item.type)) {
        _inputfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
        _tabfields.push({
          field: item.field,
          label: item.label
        })
      }
      if (['switch', 'check', 'popSelect'].includes(item.type)) {
        _linksupFields.push({
          field: item.field,
          label: item.label
        })
      }
      if (!['select', 'link', 'radio', 'checkcard', 'multiselect'].includes(item.type)) return
      _linksupFields.push({
        field: item.field,
        label: item.label
      })
      if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) return
      _linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    })
    if (index !== null) {
      if (index === 0) {
        standardform = config.fields[index + 1] || null
      } else {
        standardform = config.fields[index - 1] || null
      }
    }
    let _fields = _linkableFields.map(cell => cell.field)
    let columns = []
    if (subTabConfig) {
      subTabConfig.columns.forEach(col => {
        if (col.field && !_fields.includes(col.field)) {
          _linkableFields.push({
            field: col.field,
            label: col.label + '-显示列'
          })
        }
      })
      columns = subTabConfig.columns
    } else if (tabConfig) {
      tabConfig.columns.forEach(col => {
        if (col.field && !_fields.includes(col.field)) {
          _linkableFields.push({
            field: col.field,
            label: col.label + '-显示列'
          })
        }
      })
      columns = tabConfig.columns
    } else if (menu.LongParam) {
      menu.LongParam.columns.forEach(col => {
        if (col.field && !_fields.includes(col.field)) {
          _linkableFields.push({
            field: col.field,
            label: col.label + '-显示列'
          })
        }
      })
    }
    if (card.linkSubField && card.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      card.linkSubField = card.linkSubField.filter(item => fields.includes(item))
    }
    if (!card.span && standardform && standardform.span) {
      card.span = standardform.span
      card.labelwidth = standardform.labelwidth
    } else if (!card.span) {
      card.span = 12
      card.labelwidth = 33.3
      columns = menu.LongParam.columns
    }
    this.setState({
      standardform,
      visible: true,
      card: card,
      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields)
      formlist: getModalForm(card, config.fields, columns)
    })
  }
@@ -772,7 +661,7 @@
            card={this.state.card}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            fields={config.fields}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
src/templates/modalconfig/settingform/index.jsx
@@ -25,25 +25,16 @@
    icon: this.props.config.setting.icon || '',
    appType: sessionStorage.getItem('appType'),
    viewType: sessionStorage.getItem('editMenuType') || '',
    dialogInput: false
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    const { appType, display } = this.state
    let fields = []
    let dialogInput = null
    config.fields.forEach(f => {
      if (f.field && ['select', 'link', 'text', 'number', 'textarea'].includes(f.type) && f.hidden !== 'true' && f.readonly !== 'true') {
        fields.push(f)
      }
      if (f.field && f.hidden !== 'true' && f.readonly !== 'true') {
        if (dialogInput === null) {
          dialogInput = ['text', 'number'].includes(f.type)
        } else {
          dialogInput = false
        }
      }
    })
@@ -56,8 +47,7 @@
    this.setState({
      fields: fields,
      display: _display,
      dialogInput
      display: _display
    })
  }
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -81,7 +81,7 @@
  }
  handleConfirm = () => {
    const { type, btn } = this.props
    const { type, btn, workFlow } = this.props
    const { editItem, skip } = this.state
    // 表单提交时检查输入值是否正确
@@ -169,6 +169,18 @@
        let sql = this.state.verifySql + _initCustomScript + _prevCustomScript + _backCustomScript + tail
        sql = sql.replace(/@\$|\$@/ig, '').replace(/\$check@|@check\$/ig, '').replace(/@datam@/ig, `''`).replace(/@typename@/ig, `'debug'`)
        
        if (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')
          sql = sql.replace(/@start_type@/ig, `'开始'`)
        }
        if (skip) {
          this.setState({
            skip: false,
@@ -233,6 +245,24 @@
      database = database ? (database[0] || '') : ''
      _value = `Insert into ${database}${sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid@,@username,@fullname,@BID@ From #${sheet}`
    } else if (value === 'flowSql') {
      let sheet = btn.sheet.replace(/(.*)\.(.*)\.|@db@/ig, '')
      _value = `insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
      select jskey,@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@
      from #${sheet}
      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 jskey,@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@
      from #${sheet}
      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 jskey,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
      from #${sheet}
      insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid,typecharone)
      select jskey,@works_flow_code@,@userid@,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@,'begin'
      from #${sheet}`
    } else {
      _value = value
    }
@@ -259,7 +289,7 @@
  }
  render() {
    const { systemScripts, btn, type } = this.props
    const { systemScripts, btn, type, workFlow } = this.props
    const { usefulfields, editItem, skip } = this.state
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
@@ -289,6 +319,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, time_id, typename</span></Tooltip>,&nbsp;
              {workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="工作流变量,请按照@xxx@格式使用。"><span style={{color: '#26C281'}}>works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, start_type, </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</span></Tooltip>,&nbsp;
              {usefulfields}
            </Form.Item>
@@ -319,9 +350,8 @@
                onSelect={this.selectScript}
                getPopupContainer={() => document.getElementById('verify-excelin-custom-scripts')}
              >
                <Select.Option key="default" value={'default'}>
                  默认sql
                </Select.Option>
                <Select.Option key="default" value="default">默认sql</Select.Option>
                {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`}>
                  测试断点
                </Select.Option>
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -205,6 +205,89 @@
            </div>
          )
      },
      {
        dataIndex: 'sqlRender',
        render: (record) => {
          let columns = this.state.verify.columns
          let textFields = []
          let numberFields = []
          let dateFields = []
          columns.forEach((col) => {
            if (/Nvarchar/ig.test(col.type)) {
              textFields.push(col.Column)
            } else if (/Decimal|int/ig.test(col.type)) {
              numberFields.push(col.Column)
            } else if (/date/ig.test(col.type)) {
              dateFields.push(col.Column)
            }
          })
          let _fields = record.field.split(',')
          let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
          _fields_ = _fields_.join(' and ')
          let _where = []
          _fields.forEach(f => {
            if (textFields.includes(f)) {
              _where.push(`${f}!=''`)
            } else if (numberFields.includes(f)) {
              _where.push(`${f}!=0`)
            } else if (dateFields.includes(f)) {
              _where.push(`${f}>'1949-10-01'`)
            }
          })
          _where = _where.length ? `where ${_where.join(' and ')} ` : ''
          if (record.verifyType === 'logic' || record.verifyType === 'logic_temp') {
            _fields_ += ' and b.deleted=0'
          }
          let _afields = []
          _fields = _fields.map(f => {
            if (numberFields.includes(f)) {
              _afields.push(`cast(a.${f} as nvarchar(50))`)
              return `cast(${f} as nvarchar(50))`
            } else if (dateFields.includes(f)) {
              _afields.push(`CONVERT(nvarchar(50), a.${f}, 21)`)
              return `CONVERT(nvarchar(50), ${f}, 21)`
            }
            _afields.push(`a.${f}`)
            return f
          })
          let _sheet = this.props.card.sheet
          let database = _sheet.match(/(.*)\.(.*)\.|@db@/ig) || ''
          let sheet = _sheet.replace(/(.*)\.(.*)\.|@db@/ig, '')
          database = database ? (database[0] || '') : ''
          let sql = `
          /* 重复性验证 */
          Set @tbid=''
          Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${record.field} from #${sheet} ${_where}) a group by ${record.field} having sum(n)>1
          If @tbid!=''
          Begin
            select @ErrorCode='${record.errorCode}',@retmsg=@tbid+' 重复'
            goto aaa
          end
          ${record.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
          Select top 1 @tbid=${_afields.join('+\' \'+')} from ${_where ? `(select * from #${sheet} ${_where})` : `#${sheet}`} a Inner join ${database}${sheet} b on ${_fields_}
          If @tbid!=''
          Begin
            select @ErrorCode='${record.errorCode}',@retmsg=@tbid+' 与已有数据重复'
            goto aaa
          end` : ''}
          `
          return sql.split(/\n\s{10}/ig).map(n => n.replace(/^\s{2}/ig, '&nbsp;&nbsp;'))
        }
      }
    ],
    scriptsColumns: [
      {
@@ -316,6 +399,16 @@
    _verify.columns = _columns
    _verify.scripts = _verify.scripts || []
    _verify.uniques = _verify.uniques || []
    if (window.GLOB.process && card.intertype === 'system') {
      _verify.workFlow = _verify.workFlow || 'false'
      _verify.flowType = 'start'
      _verify.flowSql = _verify.flowSql || 'true'
    } else {
      delete _verify.workFlow
      delete _verify.flowType
      delete _verify.flowSql
    }
    this.setState({
      searchKey: '',
@@ -792,21 +885,11 @@
    })
  }
  onOptionChange = (e) => {
  onOptionChange = (value, key) => {
    const { verify } = this.state
    let value = e.target.value
    this.setState({
      verify: {...verify, default: value}
    })
  }
  onHandleChange = (e) => {
    const { verify } = this.state
    let value = e.target.value
    this.setState({
      verify: {...verify, excelHandle: value}
      verify: {...verify, [key]: value}
    })
  }
@@ -888,8 +971,8 @@
            <Form {...formItemLayout}>
              <Row gutter={24}>
                {card.intertype === 'system' ? <Col span={8}>
                  <Form.Item label={'默认sql'}>
                    <Radio.Group value={verify.default} onChange={this.onOptionChange}>
                  <Form.Item label="默认sql">
                    <Radio.Group value={verify.default} onChange={(e) => this.onOptionChange(e.target.value, 'default')}>
                      <Radio value="true">执行</Radio>
                      <Radio value="false">不执行</Radio>
                    </Radio.Group>
@@ -905,7 +988,7 @@
                    {getFieldDecorator('excelHandle', {
                      initialValue: verify.excelHandle
                    })(
                    <Radio.Group onChange={this.onHandleChange}>
                    <Radio.Group onChange={(e) => this.onOptionChange(e.target.value, 'excelHandle')}>
                      <Radio value="false">默认</Radio>
                      <Radio value="true">自定义</Radio>
                    </Radio.Group>)}
@@ -954,6 +1037,27 @@
                    })(<CodeMirror mode="text/javascript" theme="cobalt" />)}
                  </Form.Item>
                </Col> : null}
                {window.GLOB.process && card.intertype === 'system' ? <Col span={8}>
                  <Form.Item label={
                    <Tooltip placement="bottomLeft" title="导入Excel工作流仅支持发起流程。">
                      <QuestionCircleOutlined className="mk-form-tip" />
                      工作流
                    </Tooltip>
                  }>
                    <Radio.Group value={verify.workFlow} onChange={(e) => {this.onOptionChange(e.target.value, 'workFlow')}}>
                      <Radio value="true">开启</Radio>
                      <Radio value="false">不开启</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col> : null}
                {verify.workFlow === 'true' ? <Col span={8}>
                  <Form.Item label="默认sql(工作流)">
                    <Radio.Group value={verify.flowSql} onChange={(e) => {this.onOptionChange(e.target.value, 'flowSql')}}>
                      <Radio value="true">执行</Radio>
                      <Radio value="false">不执行</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col> : null}
              </Row>
            </Form>
          </TabPane>
@@ -980,7 +1084,7 @@
            </span>
          } key="unique">
            <UniqueForm fields={verify.columns} uniqueChange={this.uniqueChange}/>
            <EditTable actions={['edit', 'move', 'del', 'status']} data={verify.uniques} columns={uniqueColumns} onChange={this.changeUniques}/>
            <EditTable actions={['edit', 'move', 'del', 'status', 'sql']} data={verify.uniques} columns={uniqueColumns} onChange={this.changeUniques}/>
          </TabPane> : null}
          {card.intertype === 'system' ? <TabPane tab={
            <span>
@@ -1000,6 +1104,7 @@
                btn={this.props.card}
                usefulfields={verify.columns}
                scripts={verify.scripts}
                workFlow={verify.workFlow}
                systemScripts={this.state.systemScripts}
                scriptsChange={this.scriptsChange}
                wrappedComponentRef={(inst) => this.scriptsFullForm = inst}
@@ -1009,6 +1114,7 @@
              btn={this.props.card}
              usefulfields={verify.columns}
              scripts={verify.scripts}
              workFlow={verify.workFlow}
              systemScripts={this.state.systemScripts}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
src/templates/zshare/editTable/index.jsx
@@ -366,7 +366,7 @@
    if (list) {
      Modal.info({
        title: '',
        width: 500,
        width: 700,
        className: 'sql-example',
        icon: null,
        content: list.map((n, index) => <div key={index} dangerouslySetInnerHTML={{ __html: n }}></div>)
@@ -828,7 +828,7 @@
    
    let  columns = this.state.columns.map(col => {
      if (col.copy) {
        col.render = (text) => (<Paragraph copyable>{text}</Paragraph>)
        col.render = (text, record) => (<Paragraph copyable={{ text: text, onCopy: () => this.setState({editLineId: record.uuid}) }}>{text}</Paragraph>)
      }
      if (!col.editable) return col
src/templates/zshare/formconfig.jsx
@@ -731,13 +731,8 @@
/**
 * @description 获取表单配置信息
 * @param {*} card            // 表单对象
 * @param {*} inputfields     // 可写入表单
 * @param {*} tabfields       // 可切换表单
 * @param {*} linkableFields  // 可关联表单
 * @param {*} linksupFields   // 上级表单
 */
export function getModalForm (card, inputfields = [], tabfields = [], linkableFields, linksupFields, columns = []) {
export function getModalForm (card, fields, columns = []) {
  let appType = sessionStorage.getItem('appType')
  let roleList = sessionStorage.getItem('sysRoles')
  if (roleList) {
@@ -774,6 +769,64 @@
    msgTemps = []
  }
  let inputfields = []
  let tabfields = []
  let linkableFields = []
  let linksupFields = []
  fields.forEach(item => {
    if (!item.field || card.field === item.field) return
    if (['text', 'number', 'textarea', 'select'].includes(item.type)) {
      inputfields.push({
        field: item.field,
        label: item.label
      })
    }
    if (item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
      tabfields.push({
        field: item.field,
        label: item.label
      })
    }
    if (['switch', 'check', 'popSelect'].includes(item.type)) {
      linksupFields.push({
        field: item.field,
        label: item.label
      })
    }
    if (['select', 'link', 'radio', 'checkcard', 'multiselect'].includes(item.type)) {
      linksupFields.push({
        field: item.field,
        label: item.label
      })
    }
    if (['select', 'link', 'radio', 'popSelect'].includes(item.type) || (item.type === 'checkcard' && item.multiple !== 'true')) {
      linkableFields.push({
        field: item.field,
        label: item.label + '-表单'
      })
    }
  })
  let _fields = linkableFields.map(cell => cell.field)
  columns.forEach(col => {
    if (col.field && !_fields.includes(col.field)) {
      linkableFields.push({
        field: col.field,
        label: col.label + '-显示列'
      })
    }
  })
  if (card.linkSubField && card.linkSubField.length > 0) {
    let fields = inputfields.map(item => item.field)
    card.linkSubField = card.linkSubField.filter(item => fields.includes(item))
  }
  inputfields = inputfields.map((item, index) => {
    item.label = `${index + 1}、${item.field || ''}(${item.label})`
    return item
src/templates/zshare/modalform/index.jsx
@@ -51,7 +51,7 @@
class MainSearch extends Component {
  static propTpyes = {
    formlist: PropTypes.any,
    standardform: PropTypes.any,
    fields: PropTypes.array,
    card: PropTypes.object,
    inputSubmit: PropTypes.any
  }
@@ -537,18 +537,21 @@
  changeVal = (val, type) => {
    if (type !== 'span' || ![24, 12, 8, 6].includes(val)) return
    const { standardform } = this.props
    const { card, fields } = this.props
    if (!standardform || ![24, 12, 8, 6].includes(standardform.span) || !standardform.labelwidth) return
    let index = fields.findIndex(item => card.uuid === item.uuid)
    let stform = fields[index - 1]
    if (!stform || ![24, 12, 8, 6].includes(stform.span) || !stform.labelwidth) return
    let labelwidth = null
    if (standardform.span === val) {
      labelwidth = standardform.labelwidth
    } else if (standardform.span > val) {
    if (stform.span === val) {
      labelwidth = stform.labelwidth
    } else if (stform.span > val) {
      labelwidth = 33.3
    } else {
      switch(standardform.span) {
      switch(stform.span) {
        case 12:
          labelwidth = 16.2
          break;
@@ -930,8 +933,8 @@
    }
  }
  handleConfirm = (fields) => {
    const { card } = this.props
  handleConfirm = () => {
    const { card, fields } = this.props
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
src/templates/zshare/verifycard/baseform/index.jsx
@@ -159,36 +159,37 @@
    let _verify = {...verify, [key]: value}
    if (_verify.noteEnable !== 'true') {
      _verify.noteCode = ''
      _verify.noteId = ''
      delete _verify.noteCode
      delete _verify.noteId
    }
    if (_verify.emailEnable !== 'true') {
      _verify.emailCode = ''
      _verify.emailId = ''
      delete _verify.emailCode
      delete _verify.emailId
    }
    if (_verify.printEnable !== 'true') {
      _verify.printTempId = ''
      delete _verify.printTempId
    }
    if (_verify.linkEnable !== 'true') {
      delete _verify.linkUrl
      delete _verify.linkProUrl
    }
    if (_verify.accountdate !== 'true') {
      _verify.accountfield = ''
      _verify.voucherdate = ''
      delete _verify.accountfield
      delete _verify.voucherdate
    }
    if (_verify.preHandle !== 'true') {
      _verify.pre_func = ''
      delete _verify.pre_func
    }
    if (_verify.wxNote !== 'true') {
      _verify.wxTemplateId = ''
      _verify.wxNoteLink = ''
      _verify.wxNoteLinkUrl = ''
      _verify.wxNoteLinkMenuId = ''
      _verify.wxNoteCallback = 'false'
      _verify.wxNoteKeys = null
      delete _verify.wxTemplateId
      delete _verify.wxNoteLink
      delete _verify.wxNoteLinkUrl
      delete _verify.wxNoteMiniId
      delete _verify.wxNoteLinkMenuId
      delete _verify.wxNoteCallback
      delete _verify.wxCustomTempId
      _verify.wxNoteKeys = null
      if (this.state.selectTemp) {
        this.setState({selectTemp: null})
@@ -342,12 +343,7 @@
      <Form {...formItemLayout}>
        <Row gutter={24}>
          {card.sqlType !== 'custom' && card.intertype !== 'inner' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title={'默认sql执行顺序为自定义脚本之前'}>
                <QuestionCircleOutlined className="mk-form-tip" />
                默认sql
              </Tooltip>
            }>
            <Form.Item label="默认sql">
              <Radio.Group value={verify.default} onChange={(e) => {this.onOptionChange(e.target.value, 'default')}}>
                <Radio value="true">执行</Radio>
                <Radio value="false">不执行</Radio>
@@ -548,7 +544,7 @@
          <Col span={24}></Col>
          <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title="按钮执行成功后需要打开的链接地址。">
              <Tooltip placement="bottomLeft" overlayStyle={{maxWidth: 350}} title="按钮执行成功后需要打开的链接地址。如果地址不是http开始,会拼接当前系统域名,例如:地址为 /xxxx 时,会打开 http://***.***.**/xxxx。">
                <QuestionCircleOutlined className="mk-form-tip" />
                打开链接
              </Tooltip>
@@ -696,6 +692,16 @@
          </Col> : null}
          {verify.wxNoteLink === 'miniProgram' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="top" title="可指定跳转小程序的ID,未设置时默认使用配置文件中的小程序ID。">
                <QuestionCircleOutlined className="mk-form-tip" />
                小程序ID
              </Tooltip>
            }>
              <Input placeholder="" autoComplete="off" value={verify.wxNoteMiniId || ''} onChange={(e) => {this.onOptionChange(e.target.value, 'wxNoteMiniId')}}/>
            </Form.Item>
          </Col> : null}
          {verify.wxNoteLink === 'miniProgram' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="top" title="添加菜单ID可跳转至小程序指定页面,空值默认跳转至小程序首页。注:数据里中如果有bid字段(值不为空),打开小程序时会做为BID传入页面中。">
                <QuestionCircleOutlined className="mk-form-tip" />
                菜单ID
src/templates/zshare/verifycard/index.jsx
@@ -86,7 +86,7 @@
        title: '验证类型',
        dataIndex: 'verifyType',
        width: '14%',
        render: (text, record) => record.verifyType === 'logic' ? '逻辑验证' : '物理验证',
        render: (text) => text === 'logic' ? '逻辑验证' : '物理验证',
        inputType: 'select',
        editable: true,
        options: [
@@ -124,7 +124,7 @@
          record.field.split(',').forEach((_field, index) => {
            let _key = _field.toLowerCase()
            _fieldValue.push(`${_key}=${_key === 'bid' ? '@BID@' : ''}`)
            _fieldValue.push(`${_key}=${_key === 'bid' ? '@BID@' : `''`}`)
            _value.push(`${_labels[index] || ''}:xxx`)
          })
@@ -641,8 +641,6 @@
    _verify.uniques = _verify.uniques || []
    _verify.contrasts = _verify.contrasts || []
    _verify.accountdate = _verify.accountdate || 'false'
    _verify.accountfield = _verify.accountfield || ''
    _verify.voucherdate = _verify.voucherdate || ''
    _verify.customverifys = _verify.customverifys || []
    _verify.billcodes = _verify.billcodes || []
    _verify.voucher = _verify.voucher || {enabled: false}
src/utils/utils-custom.js
@@ -364,80 +364,6 @@
  }
  /**
   * @description 获取可关联模块
   */
  static getLinkModules (components) {
    let modules = components.map(item => {
      if ((item.type === 'card' && item.subtype === 'datacard') || (item.type === 'table' && item.subtype === 'normaltable')) {
        return {
          value: item.uuid,
          label: item.name
        }
      } else if (item.type === 'tabs') {
        let _item = {
          value: item.uuid,
          label: item.name,
          children: item.subtabs.map(f_tab => {
            let subItem = {
              value: f_tab.uuid,
              label: f_tab.label,
              children: this.getLinkModules(f_tab.components)
            }
            if (!subItem.children || subItem.children.length === 0) {
              return {children: null}
            }
            return subItem
          })
        }
        _item.children = _item.children.filter(t => t.children !== null)
        if (_item.children.length === 0) {
          return {children: null}
        }
        return _item
      } else if (item.type === 'group') {
        let _item = {
          value: item.uuid,
          label: item.name,
          children: item.components.map(f_tab => {
            if ((f_tab.type === 'card' && f_tab.subtype === 'datacard') || (f_tab.type === 'table' && f_tab.subtype === 'normaltable')) {
              return {
                value: f_tab.uuid,
                label: f_tab.name
              }
            }
            return {
              children: null
            }
          })
        }
        _item.children = _item.children.filter(t => t.children !== null)
        if (_item.children.length === 0) {
          return {children: null}
        }
        return _item
      } else {
        return {
          children: null
        }
      }
    })
    modules = modules.filter(mod => mod.children !== null)
    if (modules.length === 0) {
      return null
    }
    return modules
  }
  /**
   * @description 生成32位uuid string + 时间
   * @return {String}  uuid
   */
@@ -1014,6 +940,128 @@
}
/**
 * @description 获取可关联模块
 */
export function getLinkModules (components) {
  let modules = components.map(item => {
    if ((item.type === 'card' && item.subtype === 'datacard') || (item.type === 'table' && item.subtype === 'normaltable')) {
      return {
        value: item.uuid,
        label: item.name
      }
    } else if (item.type === 'tabs') {
      let _item = {
        value: item.uuid,
        label: item.name,
        children: item.subtabs.map(f_tab => {
          let subItem = {
            value: f_tab.uuid,
            label: f_tab.label,
            children: getLinkModules(f_tab.components)
          }
          if (!subItem.children || subItem.children.length === 0) {
            return {children: null}
          }
          return subItem
        })
      }
      _item.children = _item.children.filter(t => t.children !== null)
      if (_item.children.length === 0) {
        return {children: null}
      }
      return _item
    } else if (item.type === 'group') {
      let _item = {
        value: item.uuid,
        label: item.name,
        children: item.components.map(f_tab => {
          if ((f_tab.type === 'card' && f_tab.subtype === 'datacard') || (f_tab.type === 'table' && f_tab.subtype === 'normaltable')) {
            return {
              value: f_tab.uuid,
              label: f_tab.name
            }
          }
          return {
            children: null
          }
        })
      }
      _item.children = _item.children.filter(t => t.children !== null)
      if (_item.children.length === 0) {
        return {children: null}
      }
      return _item
    } else {
      return {
        children: null
      }
    }
  })
  modules = modules.filter(mod => mod.children !== null)
  if (modules.length === 0) {
    return null
  }
  return modules
}
/**
 * @description 获取公共数据源
 */
export function getInterfaces () {
  let menu = window.GLOB.customMenu
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name,
          columns: JSON.parse(JSON.stringify(item.columns))
        })
      }
    })
  }
  let mapComponents = (components = []) => {
    components.forEach(item => {
      if (item.type === 'card' && item.subtype === 'datacard') {
        interfaces.push({
          value: item.uuid,
          label: item.name + '(数据卡)',
          columns: JSON.parse(JSON.stringify(item.columns))
        })
      } else if (item.type === 'table' && item.subtype === 'normaltable') {
        interfaces.push({
          value: item.uuid,
          label: item.name + '(常用表)',
          columns: JSON.parse(JSON.stringify(item.columns))
        })
      } else if (item.type === 'tabs') {
        item.subtabs.forEach(f_tab => {
          mapComponents(f_tab.components)
        })
      } else if (item.type === 'group') {
        mapComponents(item.components)
      }
    })
  }
  mapComponents(menu.components)
  return interfaces
}
/**
 * @description 格式化搜索条件
 */
export function formatSearch (searches) {
src/utils/utils.js
@@ -1048,9 +1048,15 @@
          }
        } else if (typeof(val) === 'string') {
          val = val.replace(/(^\s+$)|\t+|\v+/ig, '')
          if (!val && col.required === 'true') {           // 时间必填校验
          if (!val) {
            if (col.required === 'true') {         // 时间必填校验
            errors.push(_position + '内容不可为空')
          } else if (val && !/^[1-9][0-9]{3}/.test(val)) { // 时间正则校验
            } else if (col.type === 'date') {
              val = '1949-10-01'
            } else if (col.type === 'datetime') {
              val = '1949-10-01 00:00:00'
            }
          } else if (!/^[1-9][0-9]{3}/.test(val)) { // 时间正则校验
            errors.push(_position + '时间格式错误')
          }
        } else {                                           // 时间格式错误
@@ -1128,9 +1134,15 @@
    let _uniquesql = ''
    if (btn.uniques && btn.uniques.length > 0) {
      let textFields = []
      let numberFields = []
      let dateFields = []
      btn.columns.forEach((col) => {
        if (/^Nvarchar/ig.test(col.type)) {
        if (/Nvarchar/ig.test(col.type)) {
          textFields.push(col.Column)
        } else if (/Decimal|int/ig.test(col.type)) {
          numberFields.push(col.Column)
        } else if (/date/ig.test(col.type)) {
          dateFields.push(col.Column)
        }
      })
@@ -1139,13 +1151,17 @@
        let _fields = unique.field.split(',')
        let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
        let _afields = _fields.map(_field => `a.${_field}`)
        _fields_ = _fields_.join(' and ')
        let _where = []
        _fields.forEach(f => {
          if (textFields.includes(f)) {
            _where.push(`${f}!=''`)
          } else if (numberFields.includes(f)) {
            _where.push(`${f}!=0`)
          } else if (dateFields.includes(f)) {
            _where.push(`${f}>'1949-10-01'`)
          }
        })
        _where = _where.length ? `where ${_where.join(' and ')} ` : ''
@@ -1153,6 +1169,20 @@
        if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
          _fields_ += ' and b.deleted=0'
        }
        let _afields = []
        _fields = _fields.map(f => {
          if (numberFields.includes(f)) {
            _afields.push(`cast(a.${f} as nvarchar(50))`)
            return `cast(${f} as nvarchar(50))`
          } else if (dateFields.includes(f)) {
            _afields.push(`CONVERT(nvarchar(50), a.${f}, 21)`)
            return `CONVERT(nvarchar(50), ${f}, 21)`
          }
          _afields.push(`a.${f}`)
          return f
        })
        _uniquesql += `
      /* 重复性验证 */
@@ -1226,12 +1256,84 @@
      ${_uniquesql}
      ${_prevCustomScript}
      ${_insert}
      ${_insert}`
    if (item.$process && btn.workFlow === 'true' && window.GLOB.UserCacheMap.has(item.$flowId)) {
      let flow = window.GLOB.UserCacheMap.get(item.$flowId)
      let target = flow.cells.filter(cell => cell.mknode === 'start')[0]
      let flowsql = ''
      let status = 0
      let statusName = ''
      let detailId = ''
      let work_grade = sessionStorage.getItem('work_grade') || 0
      if (target) {
        detailId = target.id
        status = target.mkdata.status
        statusName = target.mkdata.statusName
      }
      if (!target) {
        status = 0
        statusName = '异常'
        flowsql = `
        /* 工作流异常sql */
        select @ErrorCode='E',@retmsg='工作流无开始节点' goto aaa
        `
      } else if (btn.flowSql === 'true') {
        flowsql = `
        /* 工作流默认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 jskey,@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@
        from #${sheet}
        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 jskey,@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@
        from #${sheet}
        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 jskey,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
        from #${sheet}
        insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid,typecharone)
        select jskey,@works_flow_code@,@userid@,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@,'begin'
        from #${sheet}
        `
      }
      sql += `
      ${flowsql}
      ${_backCustomScript}
      drop table #${sheet}
      
      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
      sql = sql.replace(/@start_type@/ig, `'开始'`)
      sql = sql.replace(/@works_flow_code@/ig, `'${flow.flow_code}'`)
      sql = sql.replace(/@works_flow_name@/ig, `'${flow.flow_name}'`)
      if (target) {
        let label = target.attrs && target.attrs.text && target.attrs.text.text ? target.attrs.text.text : ''
        let msg = {...target.mkdata, label: label, id: target.id, checkIds: [], checkUsers: []}
        sql = sql.replace(/@works_flow_param@/ig, `'${window.btoa(window.encodeURIComponent(JSON.stringify(msg)))}'`)
      } else {
        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, `'${sessionStorage.getItem('work_group') || ''}'`)
      sql = sql.replace(/@work_grade@/ig, `'${work_grade}'`)
    } else {
      sql += `
      ${_backCustomScript}
      drop table #${sheet}
      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    }
    sql = sql.replace(/\n\s{6}/ig, '\n')
@@ -1362,17 +1464,54 @@
    let _uniquesql = ''
    if (btn.uniques && btn.uniques.length > 0) {
      let textFields = []
      let numberFields = []
      let dateFields = []
      columns.forEach((col) => {
        if (/Nvarchar/ig.test(col.datatype)) {
          textFields.push(col.field)
        } else if (/Decimal|int/ig.test(col.datatype)) {
          numberFields.push(col.field)
        } else if (/date/ig.test(col.datatype)) {
          dateFields.push(col.field)
        }
      })
      btn.uniques.forEach(unique => {
        if (unique.status === 'false' || !unique.verifyType) return
        let _fields = unique.field.split(',')
        let _fields_ = _fields.map(_field => `a.${_field}=b.${_field}`)
        let _afields = _fields.map(_field => `a.${_field}`)
        _fields_ = _fields_.join(' and ')
        let _where = []
        _fields.forEach(f => {
          if (textFields.includes(f)) {
            _where.push(`${f}!=''`)
          } else if (numberFields.includes(f)) {
            _where.push(`${f}!=0`)
          } else if (dateFields.includes(f)) {
            _where.push(`${f}>'1949-10-01'`)
          }
        })
        _where = _where.length ? `where ${_where.join(' and ')} ` : ''
        if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
          _fields_ += ' and b.deleted=0'
        }
        let _afields = []
        _fields = _fields.map(f => {
          if (numberFields.includes(f)) {
            _afields.push(`cast(a.${f} as nvarchar(50))`)
            return `cast(${f} as nvarchar(50))`
          } else if (dateFields.includes(f)) {
            _afields.push(`CONVERT(nvarchar(50), a.${f}, 21)`)
            return `CONVERT(nvarchar(50), ${f}, 21)`
          }
          _afields.push(`a.${f}`)
          return f
        })
        _uniquesql += `
      /* 重复性验证 */
@@ -1386,7 +1525,7 @@
      end
      
      ${unique.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
      Select top 1 @tbid=${_afields.join('+\' \'+')} from  #${sheet} a Inner join ${database}${sheet} b on ${_fields_}
      Select top 1 @tbid=${_afields.join('+\' \'+')} from ${_where ? `(select * from #${sheet} ${_where})` : `#${sheet}`} a Inner join ${database}${sheet} b on ${_fields_}
      
      If @tbid!=''
      Begin
src/views/login/index.jsx
@@ -465,6 +465,16 @@
            box = box.join(',')
            localStorage.setItem(_authUrl, box)
    
            if (res.e_files === 'true') {
              localStorage.setItem(_href + 'files', md5(_href + 'files'))
              localStorage.setItem(_href + 'filesDate', res.e_files_end_date)
              window.GLOB.storeFiles = true
              window.GLOB.storeDate = Math.ceil((new Date(res.e_files_end_date).getTime() - new Date().getTime()) / 86400000)
            } else {
              localStorage.removeItem(_href + 'files')
              window.GLOB.storeFiles = false
            }
            this.setState({
              auth: true
            })
@@ -477,6 +487,9 @@
            }
          } else {
            localStorage.removeItem(_authUrl)
            localStorage.removeItem(_href + 'files')
            window.GLOB.storeFiles = false
            this.setState({
              auth: false
            })