king
2019-12-23 55071f5a06673369ceba07e36cd7f85e584c3eac
2019-12-23
19个文件已修改
10个文件已添加
5个文件已删除
3566 ■■■■ 已修改文件
src/components/sidemenu/editthdmenu/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/comtable.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/comtable.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/mainAction/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/mainTable/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.jsx 511 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.scss 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/mutilform/index.jsx 443 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/mutilform/index.scss 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/subAction/index.jsx 809 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/subAction/index.scss 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/subSearch/index.jsx 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/subSearch/index.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/subTable/index.jsx 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/subTable/index.scss 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/actionform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 84 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/settingform/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/source.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/tabdragelement/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/tabform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/actionform/index.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/dragelement/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.jsx 407 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/menuform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/settingform/index.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/source.jsx 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/tabdragelement/card.jsx 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/tabdragelement/index.jsx 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/tabdragelement/index.scss 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/tabform/index.jsx 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/tabform/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/index.jsx
@@ -402,13 +402,13 @@
      }
    } else if (type === 'tab') {
      console.log(item)
      // if (item.type === 'SubTable') {
      //   this.setState({
      //     editMenu: originMenu,
      //     editTab: item,
      //     tabview: 'SubTable'
      //   })
      // }
      if (item.type === 'SubTable') {
        this.setState({
          editMenu: originMenu,
          editTab: config,
          tabview: 'SubTable'
        })
      }
    }
  }
@@ -541,9 +541,9 @@
        }
        {this.state.tabview === 'SubTable' &&
          <SubTable
            menu={this.state.editMenu}
            editTab={this.state.editTab}
            config={this.state.editTab}
            handleConfig={this.handleConfig}
            handleSubConfig={this.handleSubConfig}
          />
        }
        {/* 图片预览 */}
src/locales/en-US/comtable.js
@@ -32,6 +32,8 @@
  'header.menu.page.configurable': 'Configuration Page',
  'header.menu.menuID': 'Menu ID',
  'header.menu.menuName': 'Menu Name',
  'header.menu.tabName': '标签名称',
  'header.menu.Remark': '备注',
  'header.menu.menuNo': 'Menu Parameter',
  'header.menu.supMenu': 'Superior Menu',
  'header.menu.icon': 'Icon',
src/locales/zh-CN/comtable.js
@@ -32,6 +32,8 @@
  'header.menu.page.configurable': '页面配置',
  'header.menu.menuID': '菜单ID',
  'header.menu.menuName': '菜单名称',
  'header.menu.tabName': '标签名称',
  'header.menu.Remark': '备注',
  'header.menu.menuNo': '菜单参数',
  'header.menu.supMenu': '上级菜单',
  'header.menu.icon': '图标',
src/tabviews/commontable/index.jsx
@@ -1,17 +1,20 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { BackTop, notification, Spin} from 'antd'
import { BackTop, notification, Spin, Tabs} from 'antd'
import moment from 'moment'
import Api from '@/api'
import MainSearch from './mainSearch'
import MainAction from './mainAction'
import MainTable from './mainTable'
import SubTable from '@/tabviews/subtable'
import NotFount from '@/components/404'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import './index.scss'
const { TabPane } = Tabs
export default class NormalTable extends Component {
  static propTpyes = {
@@ -29,6 +32,7 @@
    searchlist: null,
    actions: null,
    columns: null,
    tabviews: null,
    arr_field: '',
    setting: null,
    data: null,
@@ -39,7 +43,8 @@
    orderColumn: '',
    orderType: 'asc',
    search: '',
    configMap: {}
    configMap: {},
    BID: ''
  }
  /**
@@ -136,6 +141,7 @@
        searchlist: config.search,
        actions: _actions,
        columns: _columns,
        tabviews: config.tabs,
        arr_field: _arrField.join(','),
        search: Utils.initMainSearch(config.search), // 搜索条件初始化(含有时间格式,需要转化)
        loading: true
@@ -467,8 +473,8 @@
  }
  render() {
    const { setting, searchlist, actions, columns, loadingview, viewlost } = this.state
    const { setting, searchlist, actions, columns, loadingview, viewlost, tabviews } = this.state
    console.log(setting)
    return (
      <div className="commontable" id={'commontable' + this.props.MenuID}>
        {loadingview && <Spin size="large" />}
@@ -504,6 +510,15 @@
            buttonTrigger={this.buttonTrigger}
          />
        }
        {setting && setting.tabshow !== 'vertical' && tabviews && tabviews.length > 0 &&
          <Tabs defaultActiveKey="0" tabPosition="top">
            {tabviews.map((_tab, index) => (
              <TabPane tab={ _tab.label } key={`${index}`}>
                {_tab.type === 'SubTable' ? <SubTable SupMenuID={this.props.MenuID} MenuID={this.props.MenuID} BID={this.state.BID} /> : null}
              </TabPane>
            ))}
          </Tabs>
        }
        <BackTop>
          <div className="ant-back-top">
            <div className="ant-back-top-content">
src/tabviews/commontable/index.scss
@@ -2,6 +2,7 @@
  position: relative;
  min-height: calc(100vh - 94px);
  padding-top: 16px;
  padding-bottom: 80px;
  .box404 {
    padding-top: 30px;
  }
@@ -23,6 +24,9 @@
    left: calc(50vw - 22px);
    top: calc(50vh - 70px);
  }
  > .ant-tabs {
    padding: 0px 20px;
  }
}
.ant-back-top {
  bottom: 30px;
src/tabviews/commontable/mainAction/index.scss
@@ -1,4 +1,4 @@
.button-list {
.commontable .button-list {
  padding: 10px 20px 5px;
  background: #ffffff;
  button {
src/tabviews/commontable/mainTable/index.scss
@@ -1,5 +1,5 @@
.main-table {
  padding: 0 20px 110px;
  padding: 0 20px 30px;
  table {
    max-width: 100%;
    width: 100%;
src/tabviews/subtable/index.jsx
New file
@@ -0,0 +1,511 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { notification, Spin} from 'antd'
import moment from 'moment'
import Api from '@/api'
import SubSearch from './subSearch'
import SubAction from './subAction'
import SubTable from './subTable'
import NotFount from '@/components/404'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import './index.scss'
export default class NormalTable extends Component {
  static propTpyes = {
    MenuNo: PropTypes.string,    // 菜单参数
    MenuName: PropTypes.string,  // 菜单参数
    MenuID: PropTypes.string     // 菜单Id
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    loadingview: true,    // 页面加载中
    viewlost: false,      // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
    lostmsg: '',          // 页面丢失时的提示信息
    config: {},
    searchlist: null,
    actions: null,
    columns: null,
    arr_field: '',
    setting: null,
    data: null,
    total: 0,
    loading: false,
    pageIndex: 1,
    pageSize: 10,
    orderColumn: '',
    orderType: 'asc',
    search: '',
    configMap: {}
  }
  /**
   * @description 获取页面配置信息
   */
  async loadconfig () {
    let param = {
      func: 'sPC_Get_LongParam',
      MenuID: this.props.MenuID
    }
    let result = await Api.getSystemCacheConfig(param)
    if (result.status && result.LongParam) {
      let config = ''
      try { // 配置信息解析
        config = window.decodeURIComponent(window.atob(result.LongParam))
        config = JSON.parse(config)
      } catch (e) {
        config = ''
      }
      // 页面配置解析错误时提示
      if (!config) {
        notification.warning({
          top: 92,
          message: this.state.dict['main.page.settingerror'],
          duration: 10
        })
        return
      }
      // 页面未启用时,显示未启用页面
      if (!config.enabled) {
        this.setState({
          loadingview: false,
          viewlost: true,
          lostmsg: this.state.dict['main.view.unenabled']
        })
        return
      }
      let _arrField = []     // 字段集
      let _columns = []      // 显示列
      let _hideCol = []      // 隐藏及合并列中字段的uuid集
      let colMap = new Map()
      // 1、筛选字段集,2、过滤隐藏列及合并列中的字段uuid
      config.columns.forEach(col => {
        if (col.field) {
          _arrField.push(col.field)
        }
        if (col.type === 'colspan' && col.sublist) { // 筛选隐藏列
          _hideCol = _hideCol.concat(col.sublist)
        } else if (col.Hide === 'true') {
          _hideCol.push(col.uuid)
        }
        colMap.set(col.uuid, col)
      })
      // 生成显示列,处理合并列中的字段
      config.columns.forEach(col => {
        if (_hideCol.includes(col.uuid)) return
        if (col.type === 'colspan' && col.sublist) {
          let _col = JSON.parse(JSON.stringify(col))
          let subColumn = []
          _col.sublist.forEach(sub => {
            if (colMap.has(sub)) {
              subColumn.push(colMap.get(sub))
            }
          })
          _col.subColumn = subColumn
          _columns.push(_col)
        } else {
          _columns.push(col)
        }
      })
      // 添加操作列(存在时)(未经过权限过滤)
      if (config.gridBtn && config.gridBtn.display) {
        _columns.push({
          ...config.gridBtn,
          operations: config.action.filter(item => item.position === 'grid')
        })
      }
      // 过滤工具栏按钮(未经过权限过滤)
      let _actions = config.action.filter(item => item.position === 'toolbar')
      this.setState({
        loadingview: false,
        config: config,
        setting: config.setting,
        searchlist: config.search,
        actions: _actions,
        columns: _columns,
        arr_field: _arrField.join(','),
        search: Utils.initMainSearch(config.search), // 搜索条件初始化(含有时间格式,需要转化)
        loading: true
      }, () => {
        this.improveSearch()
        this.loadmaindata()
      })
    } else {
      this.setState({
        loadingview: false,
        viewlost: true
      })
      notification.warning({
        top: 92,
        message: result.message,
        duration: 10
      })
    }
  }
  improveSearch = () => {
    let searchlist = JSON.parse(JSON.stringify(this.state.searchlist))
    let deffers = []
    searchlist.forEach(item => {
      if (item.type !== 'select' && item.type !== 'link') return
      if (item.setAll === 'true') {
        item.options.unshift({
          key: Utils.getuuid(),
          Value: '',
          Text: this.state.dict['main.all']
        })
      }
      if (item.resourceType === '1' && item.dataSource) {
        let arrfield = item.valueField + ',' + item.valueText
        if (item.type === 'link') {
          arrfield = arrfield + ',' + item.linkField
        }
        let param = {
          func: 'sPC_Get_SelectedList',
          LText: item.dataSourceSql,
          obj_name: 'data',
          arr_field: arrfield
        }
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
        let defer = new Promise(resolve => {
          Api.getSystemCacheConfig(param).then(res => {
            res.search = item
            resolve(res)
          })
        })
        deffers.push(defer)
      } else if (item.resourceType === '1' && !item.dataSource) {
        notification.warning({
          top: 92,
          message: item.label + ': ' + this.state.dict['main.datasource.settingerror'],
          duration: 10
        })
      }
    })
    this.setState({searchlist: JSON.parse(JSON.stringify(searchlist))})
    if (deffers.length === 0) return
    Promise.all(deffers).then(result => {
      result.forEach(res => {
        if (res.status) {
          searchlist = searchlist.map(item => {
            if (item.uuid === res.search.uuid) {
              res.data.forEach(cell => {
                item.options.push({
                  key: Utils.getuuid(),
                  Value: cell[res.search.valueField],
                  Text: cell[res.search.valueText]
                })
              })
            }
            return item
          })
        } else {
          notification.warning({
            top: 92,
            message: res.search.label + ':' + res.message,
            duration: 10
          })
        }
      })
      this.setState({searchlist})
    })
  }
  async loadmaindata () {
    const { setting } = this.state
    let param = ''
    if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) {
      param = this.getCustomParam()
    } else {
      param = this.getDefaultParam()
    }
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
          return item
        }),
        total: result.total,
        loading: false
      })
    } else {
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 15
      })
    }
  }
  getCustomParam = () => {
    const { pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
    let _search = Utils.formatCustomMainSearch(search)
    let param = {
      PageIndex: pageIndex,
      PageSize: pageSize,
      OrderCol: orderColumn,
      OrderType: orderType,
      ..._search
    }
    if (setting.interType === 'inner') {
      param.func = setting.innerFunc
    } else {
      param.rduri = setting.interface
      if (setting.outerFunc) {
        param.func = setting.outerFunc
      }
    }
    return param
  }
  getDefaultParam = () => {
    const { arr_field, pageIndex, pageSize, orderColumn, orderType, search, setting } = this.state
    let _search = Utils.joinMainSearchkey(search)
    _search = _search ? 'where ' + _search : ''
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: arr_field
    }
    let orderBy = orderColumn ? (orderColumn + ' ' + orderType) : setting.order
    let LText = `select top ${pageSize} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${setting.dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows`
    let DateCount = `select count(1) as total from ${setting.dataresource} ${_search}`
    console.log(LText)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = Utils.formatOptions(DateCount)
    return param
  }
  refreshbysearch = (searches) => {
    // 搜索条件变化
    this.refs.subTable.resetTable()
    this.setState({
      loading: true,
      pageIndex: 1,
      search: searches
    }, () => {
      this.loadmaindata()
    })
  }
  refreshbytable = (pagination, filters, sorter) => {
    // 表格查询条件修改
    if (sorter.order) {
      let _chg = {
        ascend: 'asc',
        descend: 'desc'
      }
      sorter.order = _chg[sorter.order]
    }
    this.setState({
      loading: true,
      pageIndex: pagination.current,
      pageSize: pagination.pageSize,
      orderColumn: sorter.field || this.state.setting.orderColumn,
      orderType: sorter.order || 'asc'
    }, () => {
      this.loadmaindata()
    })
  }
  reloadtable = () => {
    this.refs.subTable.resetTable()
    this.setState({
      loading: true,
      pageIndex: 1
    }, () => {
      this.loadmaindata()
    })
  }
  reloadview = () => {
    this.setState({
      loadingview: true,    // 页面加载中
      viewlost: false,      // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
      lostmsg: '',          // 页面丢失时的提示信息
      config: {},
      searchlist: null,
      actions: null,
      columns: null,
      arr_field: '',
      setting: null,
      data: null,
      total: 0,
      loading: false,
      pageIndex: 1,
      pageSize: 10,
      orderColumn: '',
      orderType: 'asc',
      search: '',
      configMap: {}
    }, () => {
      this.loadconfig()
    })
  }
  refreshbyaction = (btn, type) => {
    // 按钮操作后刷新表格,重置页码及选择项
    if (btn.execSuccess === 'grid' && type === 'success') {
      this.reloadtable()
    } else if (btn.execError === 'grid' && type === 'error') {
      this.reloadview()
    } else if (btn.execSuccess === 'view' && type === 'success') {
      this.reloadtable()
    } else if (btn.execError === 'view' && type === 'error') {
      this.reloadview()
    } else if (type === 'excelOut') {
      this.handleDefaultExcelout(btn)
    }
  }
  handleDefaultExcelout = (btn) => {
    const { MenuName } = this.props
    const { arr_field, orderColumn, orderType, search, setting, config } = this.state
    let _arr_labels = []      // 列名称集
    let _arr_label_field = [] // 列名称字段集
    config.columns.forEach(col => {
      if (col.field) {
        _arr_labels.push(col.label)
        _arr_label_field.push(`${col.field} as ${col.label}`)
      }
    })
    _arr_labels = _arr_labels.join(',')
    _arr_label_field = _arr_label_field.join(',')
    let _search = Utils.joinMainSearchkey(search)
    _search = _search ? 'where (' + _search + ')' : ''
    // 获取列表数据
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      arr_field: _arr_labels
    }
    let orderBy = orderColumn ? (orderColumn + ' ' + orderType) : setting.order
    let LText = `select ${_arr_label_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${setting.dataresource} ${_search}) tmptable order by tmptable.rows`
    console.log(LText)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.DateCount = ''
    let name = `${MenuName}${moment().format('YYYYMMDDHHmmss')}.xlsx`
    Api.getExcelOut(param, name).then(res => {
      if (res && res.status === false) {
        this.refs.subButton.execError(res, btn)
      } else {
        this.refs.subButton.execSuccess(btn)
      }
    })
  }
  gettableselected = () => {
    // 获取表格选择项
    let data = []
    this.refs.subTable.state.selectedRowKeys.forEach(item => {
      data.push(this.refs.subTable.props.data[item])
    })
    return data
  }
  buttonTrigger = (btn, record) => {
    this.refs.subButton.actionTrigger(btn, record)
  }
  UNSAFE_componentWillMount () {
    // 组件加载时,获取菜单数据
    this.loadconfig()
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  render() {
    const { setting, searchlist, actions, columns, loadingview, viewlost } = this.state
    return (
      <div className="subtable" id={'subtable' + this.props.MenuID}>
        {loadingview && <Spin size="large" />}
        {searchlist && searchlist.length > 0 ?
          <SubSearch
            refreshdata={this.refreshbysearch}
            searchlist={searchlist}
            dict={this.state.dict}
          /> : null
        }
        {actions &&
          <SubAction
            ref="subButton"
            MenuID={this.props.MenuID}
            setting={setting}
            refreshdata={this.refreshbyaction}
            gettableselected={this.gettableselected}
            actions={actions}
            dict={this.state.dict}
          />
        }
        {columns &&
          <SubTable
            ref="subTable"
            dict={this.state.dict}
            MenuID={this.props.MenuID}
            setting={setting}
            columns={columns}
            data={this.state.data}
            total={this.state.total}
            loading={this.state.loading}
            refreshdata={this.refreshbytable}
            buttonTrigger={this.buttonTrigger}
          />
        }
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
      </div>
    )
  }
}
src/tabviews/subtable/index.scss
New file
@@ -0,0 +1,30 @@
.subtable {
  position: relative;
  min-height: calc(100vh - 94px);
  padding-top: 16px;
  .box404 {
    padding-top: 30px;
  }
  .ant-modal-mask {
    position: absolute;
  }
  .ant-modal-wrap {
    position: absolute;
  }
  .action-modal .ant-modal {
    top: 40px;
    max-width: 95%;
    .ant-modal-body {
      max-height: calc(100vh - 265px);
    }
  }
  > .ant-spin {
    position: fixed;
    left: calc(50vw - 22px);
    top: calc(50vh - 70px);
  }
}
.ant-back-top {
  bottom: 30px;
  right: 30px;
}
src/tabviews/subtable/mutilform/index.jsx
New file
@@ -0,0 +1,443 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, InputNumber, Select, DatePicker, notification } from 'antd'
import moment from 'moment'
import Utils from '@/utils/utils.js'
import './index.scss'
const {MonthPicker} = DatePicker
class MainSearch extends Component {
  static propTpyes = {
    action: PropTypes.object,    // 按钮信息、表单列表
    dict: PropTypes.object,      // 字典项
    data: PropTypes.any,         // 表格数据
    configMap: PropTypes.object, // 按钮及下拉表单配置信息集
    inputSubmit: PropTypes.func  // input回车提交
  }
  state = {
    datatype: null,
    readtype: null,
    formlist: []
  }
  componentDidMount () {
    const { data } = this.props
    let action = JSON.parse(JSON.stringify(this.props.action))
    let datatype = {}
    let readtype = {}
    let formlist = []
    if (action.groups.length > 0) {
      action.groups.forEach(group => {
        if (group.sublist.length === 0) return
        if (!group.default) {
          formlist.push({
            type: 'title',
            label: group.label,
            uuid: group.uuid
          })
        }
        group.sublist.forEach(item => {
          datatype[item.field] = item.type
          readtype[item.field] = item.readonly === 'true'
          formlist.push(item)
        })
      })
    } else {
      formlist = action.fields.map(item => {
        datatype[item.field] = item.type
        readtype[item.field] = item.readonly === 'true'
        return item
      })
    }
    formlist = formlist.map(item => {
      if (item.type === 'select' || item.type === 'link') {
        if (item.setAll === 'true') {
          item.options.unshift({
            key: Utils.getuuid(),
            Value: '',
            Text: this.props.dict['main.all']
          })
        }
        if (item.resourceType === '1' && this.props.configMap.hasOwnProperty(item.uuid)) {
          item.options = [...item.options, ...this.props.configMap[item.uuid]]
        }
        item.oriOptions = item.options
      }
      if (!/^date/.test(item.type) && this.props.data && this.props.data.hasOwnProperty(item.field)) {
        item.initval = this.props.data[item.field]
      }
      return item
    })
    let error = false
    formlist = formlist.map(item => {
      if (item.type === 'link') {
        let supItem = formlist.filter(form => form.field === item.linkField)[0]
        if (!supItem && data && data.hasOwnProperty(item.linkField)) {
          supItem = {initval: data[item.linkField]}
        }
        if (!supItem) {
          error = true
        } else {
          item.options = item.oriOptions.filter(option => option.parentId === supItem.initval)
        }
      }
      return item
    })
    if (error) {
      notification.warning({
        top: 92,
        message: '关联菜单设置错误!',
        duration: 10
      })
    }
    this.setState({
      readtype: readtype,
      datatype: datatype,
      formlist: formlist
    }, () => {
      if (action.setting && action.setting.focus) {
        try {
          let _form = document.getElementById('main-form-box')
          let _item = _form.getElementsByTagName('input')
          _item = [..._item]
          _item.forEach(input => {
            if (!input || input.id !== action.setting.focus) return
            input.select()
          })
        } catch {
          console.warn('表单获取失败!')
        }
      }
    })
  }
  resetform = (formlist, supfields, index) => {
    index++
    let subfields = []
    supfields.forEach(supfield => {
      formlist = formlist.map(item => {
        if (item.type === 'link' && item.linkField === supfield.field) {
          item.options = item.oriOptions.filter(option => option.parentId === supfield.initval)
          item.initval = item.options[0] ? item.options[0].Value : ''
          item.hiden = true
          subfields.push(item)
        }
        return item
      })
    })
    if (subfields.length === 0 || index > 6) {
      return formlist
    } else {
      return this.resetform(formlist, subfields, index)
    }
  }
  selectChange = (_field, value) => {
    let formlist = JSON.parse(JSON.stringify(this.state.formlist))
    let subfields = []
    formlist = formlist.map(item => {
      if (item.type === 'link' && item.linkField === _field.field) {
        item.options = item.oriOptions.filter(option => option.parentId === value)
        item.initval = item.options[0] ? item.options[0].Value : ''
        item.hiden = true
        subfields.push(item)
      }
      return item
    })
    if (subfields.length === 0) return
    formlist = this.resetform(formlist, subfields, 0)
    this.setState({
      formlist: formlist
    }, () => {
      this.setState({
        formlist: formlist.map(item => {
          item.hiden = false
          return item
        })
      })
    })
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    let cols = 2
    if (this.props.action.setting && this.props.action.setting.cols) {
      cols = parseInt(this.props.action.setting.cols)
      if (cols > 3 || cols < 1) {
        cols = 2
      }
    }
    this.state.formlist.forEach((item, index) => {
      if ((!item.field && item.type !== 'title') || item.hiden) return
      if (item.type === 'title') {
        fields.push(
          <Col span={24} key={index}>
            <p>{item.label}</p>
          </Col>
        )
      } else if (item.type === 'text') {
        fields.push(
          <Col span={24 / cols} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval || '',
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" disabled={item.readonly === 'true'} onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'number') { // 数字
        let min = (item.min || item.min === 0) ? item.min : -Infinity
        let max = (item.max || item.max === 0) ? item.max : Infinity
        let _initval = item.initval
        let precision = (item.decimal || item.decimal === 0) ? item.decimal : null
        fields.push(
          <Col span={24 / cols} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: _initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(
                precision === null ?
                <InputNumber initialValue={_initval} min={min} max={max} disabled={item.readonly === 'true'} onPressEnter={this.handleSubmit} /> :
                <InputNumber initialValue={_initval} min={min} max={max} precision={precision} disabled={item.readonly === 'true'} onPressEnter={this.handleSubmit} />
                )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select' || item.type === 'link') { // 下拉搜索
        fields.push(
          <Col span={24 / cols} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: item.initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(value) => {this.selectChange(item, value)}}
                  // getPopupContainer={() => document.getElementById('form-box')}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.key} title={option.Text} key={option.key} value={option.Value}>{option.Text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'date') { // 时间搜索
        let _initval = this.props.data ? this.props.data[item.field] : ''
        if (_initval) {
          _initval = moment(_initval, 'YYYY-MM-DD')
        } else {
          _initval = item.initval ? moment().subtract(item.initval, 'days') : null
        }
        fields.push(
          <Col span={24 / cols} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: _initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <DatePicker />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'datemonth') {
        let _initval = this.props.data ? this.props.data[item.field] : ''
        if (_initval) {
          _initval = moment(_initval, 'YYYY-MM')
        } else {
          _initval = item.initval ? moment().subtract(item.initval, 'month') : null
        }
        fields.push(
          <Col span={24 / cols} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: _initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <MonthPicker />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'datetime') {
        let _initval = this.props.data ? this.props.data[item.field] : ''
        if (_initval) {
          _initval = moment(_initval, 'YYYY-MM-DD HH:mm:ss')
        } else {
          _initval = item.initval ? moment().subtract(item.initval, 'days') : null
        }
        fields.push(
          <Col span={24 / cols} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {
                initialValue: _initval,
                rules: [
                  {
                    required: item.required === 'true',
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                // <DatePicker showTime getCalendarContainer={() => document.getElementById('form-box')} />
                <DatePicker showTime />
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          let search = []
          Object.keys(values).forEach(key => {
            if (this.state.datatype[key] === 'datetime') {
              let _value = ''
              if (values[key]) {
                _value = moment(values[key]).format('YYYY-MM-DD HH:mm:ss')
              }
              search.push({
                type: this.state.datatype[key],
                readonly: this.state.readtype[key],
                key: key,
                value: _value
              })
            } else if (this.state.datatype[key] === 'datemonth') {
              let _value = ''
              if (values[key]) {
                _value = moment(values[key]).format('YYYY-MM')
              }
              search.push({
                type: this.state.datatype[key],
                readonly: this.state.readtype[key],
                key: key,
                value: _value
              })
            } else if (this.state.datatype[key] === 'date') {
              let _value = ''
              if (values[key]) {
                _value = moment(values[key]).format('YYYY-MM-DD')
              }
              search.push({
                type: this.state.datatype[key],
                readonly: this.state.readtype[key],
                key: key,
                value: _value
              })
            } else if (this.state.datatype[key] === 'number') {
              search.push({
                type: this.state.datatype[key],
                readonly: this.state.readtype[key],
                key: key,
                value: values[key]
              })
            } else {
              search.push({
                type: this.state.datatype[key],
                readonly: this.state.readtype[key],
                key: key,
                value: values[key].replace(/(^\s*|\s*$)/ig, '')
                // value: values[key].replace(/[\x00-\xff]+/ig, '')
              })
            }
          })
          resolve(search)
        } else {
          reject(err)
        }
      })
    })
  }
  handleSubmit = (e) => {
    e.preventDefault()
    this.props.inputSubmit()
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form main-form-field" id="main-form-box">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/tabviews/subtable/mutilform/index.scss
New file
@@ -0,0 +1,21 @@
.ant-advanced-search-form.main-form-field {
  position: relative;
  padding: 0px 24px 20px;
  .ant-form-item {
    display: flex;
    // margin-bottom: 10px;
  }
  .ant-form-item-control-wrapper {
    flex: 1;
  }
  .ant-form-item-label {
    min-width: 100px;
  }
  .ant-input-number {
    width: 100%;
  }
  p {
    color: #1890ff;
    border-bottom: 1px solid #d9d9d9;
  }
}
src/tabviews/subtable/subAction/index.jsx
New file
@@ -0,0 +1,809 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import moment from 'moment'
import { Button, Modal, notification, Spin } from 'antd'
import MutilForm from '../mutilform'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import './index.scss'
const { confirm } = Modal
class MainAction extends Component {
  static propTpyes = {
    MenuID: PropTypes.string,
    actions: PropTypes.array, // 搜索条件列表
    dict: PropTypes.object, // 字典项
    setting: PropTypes.any
  }
  state = {
    visible: false,
    formdata: null,
    tabledata: null,
    confirmLoading: false,
    execAction: null,
    loadingUuid: '',
    btnloading: false,
    configMap: {}
  }
  refreshdata = (item, type) => {
    this.props.refreshdata(item, type)
  }
  actionTrigger = (item, record) => {
    const { setting } = this.props
    let _this = this
    let data = this.props.gettableselected() || []
    if (record) { // 表格中触发按钮
      data = [record]
    }
    if (item.Ot !== 'notRequired' && data.length === 0) {
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: this.props.dict['main.action.confirm.selectline'],
        duration: 10
      })
      return
    } else if (item.Ot === 'requiredSgl' && data.length !== 1) {
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: this.props.dict['main.action.confirm.selectSingleLine'],
        duration: 10
      })
      return
    } else if (item.Ot !== 'notRequired' && !setting.primaryKey) {
      // 需要选择行时,校验是否设置主键
      notification.warning({
        top: 92,
        message: '未设置主键!',
        duration: 10
      })
      return
    }
    if (item.OpenType === 'prompt') {
      confirm({
        title: this.props.dict['main.action.confirm.tip'],
        onOk() {
          return new Promise(resolve => {
            _this.execSubmit(item, data, resolve)
          })
        },
        onCancel() {}
      })
    } else if (item.OpenType === 'exec') {
      this.setState({loadingUuid: item.uuid})
      this.execSubmit(item, data, () => {
        this.setState({loadingUuid: ''})
      })
    } else if (item.OpenType === 'pop') {
      this.setState({
        execAction: item,
        tabledata: data,
        btnloading: true
      }, () => {
        this.improveAction(item)
      })
    } else if (item.OpenType === 'excelOut') {
      this.setState({loadingUuid: item.uuid})
      this.refreshdata(item, 'excelOut')
    } else {
      notification.warning({
        top: 92,
        message: '完善中。。。',
        duration: 10
      })
    }
  }
  execSubmit = (btn, data, _resolve, formdata) => {
    const { setting } = this.props
    if (btn.intertype === 'inner') {
      // 使用内部接口时,内部函数和数据源不可同时为空, 使用系统函数时,类型不可为空
      if (!btn.innerFunc && (!btn.sql || (btn.sql && !btn.sqlType))) {
        this.actionSettingError()
        _resolve()
        return
      }
      if (
        btn.Ot === 'notRequired' ||
        btn.Ot === 'requiredSgl' ||
        (btn.Ot === 'requiredOnce' && btn.OpenType !== 'pop') ||
        (btn.OpenType === 'pop' && !btn.innerFunc && btn.sql && btn.sqlType === 'insert')
      ) {
        let param = { // 系统存储过程
          func: 'sPC_TableData_InUpDe'
        }
        if (btn.OpenType === 'prompt' || btn.OpenType === 'exec') { // 是否弹框或直接执行
          let ID = ''
          if (btn.Ot === 'notRequired') {
          } else if (btn.Ot === 'requiredSgl') {
            ID = data[0][setting.primaryKey]
          } else if (btn.Ot === 'requiredOnce') {
            let ids = data.map(d => { return d[setting.primaryKey]})
            ID = ids.join(',')
          }
          param.ID = ID
          param.BID = ''
          if (btn.innerFunc) {
            param.func = btn.innerFunc
          } else if (btn.sql) {
            param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting)) // 数据源
            param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
            param.secretkey = Utils.encrypt(param.LText, param.timestamp)
          }
        } else if (btn.OpenType === 'pop') { // 表单
          if (btn.innerFunc) {
            param.func = btn.innerFunc
            formdata.forEach(_data => {
              param[_data.key] = _data.value
            })
            if (setting.primaryKey) {
              if (!param.hasOwnProperty(setting.primaryKey) && data[0] && data[0][setting.primaryKey]) {
                param[setting.primaryKey] = data[0][setting.primaryKey]
              }
            }
            if (!param.hasOwnProperty('ID') && setting.primaryKey && data[0] && data[0][setting.primaryKey]) {
              param.ID = data[0][setting.primaryKey]
            }
            if (!param.hasOwnProperty('BID')) {
              param.BID = ''
            }
          } else if (btn.sql && btn.sqlType === 'insert') {
            param.ID = Utils.getguid()
            param.BID = ''
            param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting, formdata)) // 数据源
            param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
            param.secretkey = Utils.encrypt(param.LText, param.timestamp)
          } else if (btn.sql) {
            param.ID = data[0][setting.primaryKey]
            param.BID = ''
            param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting, formdata)) // 数据源
            param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
            param.secretkey = Utils.encrypt(param.LText, param.timestamp)
          }
        }
        Api.genericInterface(param).then((res) => {
          if (res.status) {
            this.execSuccess(btn)
          } else {
            this.execError(res, btn)
          }
          _resolve()
        })
      } else if (btn.Ot === 'required' || (btn.Ot === 'requiredOnce' && btn.OpenType === 'pop')) {
        let deffers = data.map(cell => {
          let param = {
            func: 'sPC_TableData_InUpDe'
          }
          if (btn.OpenType === 'prompt' || btn.OpenType === 'exec') { // 是否弹框或直接执行
            param.ID = cell[setting.primaryKey]
            param.BID = ''
            if (btn.innerFunc) {
              param.func = btn.innerFunc
            } else if (btn.sql) {
              param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting)) // 数据源
              param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
              param.secretkey = Utils.encrypt(param.LText, param.timestamp)
            }
          } else if (btn.OpenType === 'pop') { // 表单
            if (btn.innerFunc) {
              param.func = btn.innerFunc
              formdata.forEach(_data => {
                param[_data.key] = _data.value
              })
              if (!param.hasOwnProperty(setting.primaryKey) && cell[setting.primaryKey]) {
                param[setting.primaryKey] = cell[setting.primaryKey]
              }
              if (!param.hasOwnProperty('ID') && cell[setting.primaryKey]) {
                param.ID = cell[setting.primaryKey]
              }
            } else if (btn.sql) {
              param.ID = cell[setting.primaryKey]
              param.BID = ''
              param.LText = Utils.formatOptions(Utils.getSysDefaultSql(btn, setting, formdata)) // 数据源
              param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
              param.secretkey = Utils.encrypt(param.LText, param.timestamp)
            }
          }
          return new Promise(resolve => {
            Api.genericInterface(param).then(res => {
              resolve(res)
            })
          })
        })
        Promise.all(deffers).then(result => {
          let iserror = false
          let errorMsg = ''
          result.forEach(res => {
            if (res.status) {
            } else {
              iserror = true
              errorMsg = res.message
            }
          })
          if (!iserror) {
            this.execSuccess(btn)
          } else {
            notification.error({
              top: 92,
              message: errorMsg,
              duration: 15
            })
            this.refreshdata(btn, 'error')
          }
          _resolve()
        })
      } else {
        this.actionSettingError()
        _resolve()
        return
      }
    } else if (btn.intertype === 'outer') {
      /** *********************调用外部接口************************* */
      let param = {
        ID: '',
        BID: ''
      }
      if (!btn.interface) { // 接口地址不存在时报错
        this.actionSettingError()
        _resolve()
        return
      }
      if (btn.Ot === 'notRequired' || btn.Ot === 'requiredSgl' || btn.Ot === 'requiredOnce') {
        // 获取id
        if (btn.Ot === 'notRequired') {
        } else if (btn.Ot === 'requiredSgl') {
          param.ID = data[0][setting.primaryKey]
        } else if (btn.Ot === 'requiredOnce') {
          let ids = data.map(d => { return d[setting.primaryKey]})
          param.ID = ids.join(',')
        }
        new Promise(resolve => {
          // 内部请求
          if (btn.innerFunc) {
            param.func = btn.innerFunc
            // 存在内部函数时,数据预处理
            Api.genericInterface(param).then(res => {
              if (res.status) {
                delete res.ErrCode
                delete res.ErrMesg
                delete res.message
                delete res.status
                res.rduri = btn.interface
                // res.method = btn.method
                if (btn.outerFunc) {
                  res.func = btn.outerFunc
                }
                // 使用处理后的数据调用外部接口
                resolve(res)
              } else {
                this.execError(res, btn)
                _resolve()
              }
            })
          } else {
            // 不存在内部函数时,生成外部请求参数
            param.rduri = btn.interface
            // param.method = btn.method
            if (btn.outerFunc) {
              param.func = btn.outerFunc
            }
            resolve(param)
          }
        }).then(res => {
          if (!res) return
          // 外部请求
          return Api.genericInterface(res)
        }).then(response => {
          // 回调请求
          if (response.status) {
            if (btn.callbackFunc) {
              // 存在回调函数时,调用
              delete response.ErrCode
              delete response.ErrMesg
              delete response.message
              delete response.status
              response.func = btn.callbackFunc
              return Api.genericInterface(response)
            } else {
              this.execSuccess(btn)
              _resolve()
            }
          } else {
            this.execError(response, btn)
            _resolve()
          }
        }).then(res => {
          if (!res) return
          if (res.status) {
            this.execSuccess(btn)
          } else {
            this.execError(res, btn)
          }
          _resolve()
        })
      } else if (btn.Ot === 'required') {
        // 选择多行,循环调用
        new Promise(resolve => {
          // 内部请求
          if (btn.innerFunc) {
            let deffers = data.map(cell => {
              let _param = {
                BID: '',
                func: btn.innerFunc
              }
              _param.ID = cell[setting.primaryKey]
              return new Promise(resolve => {
                Api.genericInterface(_param).then(res => {
                  resolve(res)
                })
              })
            })
            Promise.all(deffers).then(result => {
              let iserror = false
              let errorMsg = ''
              result.forEach(res => {
                if (!res.status) {
                  iserror = true
                  errorMsg = res.message
                }
              })
              if (!iserror) {
                resolve(result)
              } else {
                notification.error({
                  top: 92,
                  message: errorMsg,
                  duration: 15
                })
                this.refreshdata(btn, 'error')
                _resolve()
              }
            })
          } else {
            let params = data.map(cell => {
              return {
                BID: '',
                ID: cell[setting.primaryKey]
              }
            })
            resolve(params)
          }
        }).then(result => {
          // 外部请求
          if (!result) return
          let deffers = result.map(res => {
            delete res.ErrCode
            delete res.ErrMesg
            delete res.message
            delete res.status
            res.rduri = btn.interface
            // res.method = btn.method
            if (btn.outerFunc) {
              res.func = btn.outerFunc
            }
            return new Promise(resolve => {
              Api.genericInterface(res).then(response => {
                resolve(response)
              })
            })
          })
          return Promise.all(deffers)
        }).then(result => {
          // 回调请求
          let iserror = false
          let errorMsg = ''
          result.forEach(res => {
            if (!res.status) {
              iserror = true
              errorMsg = res.message
            }
          })
          if (iserror) {
            notification.error({
              top: 92,
              message: errorMsg,
              duration: 15
            })
            this.refreshdata(btn, 'error')
            _resolve()
            return
          }
          if (btn.callbackFunc) {
            // 存在回调函数时,调用
            let deffers = result.map(res => {
              delete res.ErrCode
              delete res.ErrMesg
              delete res.message
              delete res.status
              res.func = btn.callbackFunc
              return new Promise(resolve => {
                Api.genericInterface(res).then(response => {
                  resolve(response)
                })
              })
            })
            return Promise.all(deffers)
          } else {
            _resolve()
            this.execSuccess(btn)
          }
        }).then(result => {
          if (!result) return
          let iserror = false
          let errorMsg = ''
          result.forEach(res => {
            if (!res.status) {
              iserror = true
              errorMsg = res.message
            }
          })
          if (iserror) {
            notification.error({
              top: 92,
              message: errorMsg,
              duration: 15
            })
            this.refreshdata(btn, 'error')
            return
          } else {
            this.execSuccess(btn)
          }
          _resolve()
        })
      } else {
        this.actionSettingError()
        _resolve()
        return
      }
    } else {
      this.actionSettingError()
      _resolve()
      return
    }
  }
  execSuccess = (btn) => {
    if (btn.OpenType === 'excelOut') {
      this.setState({
        loadingUuid: ''
      })
    } else {
      notification.success({
        top: 92,
        message: this.props.dict['main.action.confirm.success'],
        duration: 2
      })
    }
    if (btn.OpenType === 'pop' && btn.setting && btn.setting.finish !== 'unclose') {
      this.setState({
        visible: false
      })
    }
    this.refreshdata(btn, 'success')
  }
  execError = (res, btn) => {
    if (!res.ErrCode || res.ErrCode === 'E') {
      notification.error({
        top: 92,
        message: res.message || res.ErrMesg,
        duration: 15
      })
    } else if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || res.ErrMesg
      })
    }
    this.refreshdata(btn, 'error')
  }
  actionSettingError = () => {
    notification.warning({
      top: 92,
      message: this.props.dict['main.action.settingerror'],
      duration: 10
    })
  }
  improveAction = (action) => {
    const { configMap, execAction } = this.state
    let _config = configMap[action.uuid]
    if (_config) {
      this.setState({
        execAction: {..._config, ...execAction}
      }, () => {
        this.improveActionForm()
      })
    } else {
      Api.getSystemCacheConfig({
        func: 'sPC_Get_LongParam',
        MenuID: action.uuid
      }).then(res => {
        let _LongParam = ''
        if (res.status && res.LongParam) {
          _LongParam = window.decodeURIComponent(window.atob(res.LongParam))
          try {
            _LongParam = JSON.parse(_LongParam)
          } catch (e) {
            _LongParam = ''
          }
        }
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
          this.setState({
            execAction: null,
            tabledata: null,
            btnloading: false
          })
        } else if (!_LongParam || (action.OpenType === 'pop' && _LongParam.type !== 'Modal')) {
          notification.warning({
            top: 92,
            message: '未获取到按钮配置信息!',
            duration: 10
          })
          this.setState({
            execAction: null,
            tabledata: null,
            btnloading: false
          })
        } else {
          this.setState({
            configMap: {...configMap, [action.uuid]: _LongParam},
            execAction: {..._LongParam, ...execAction}
          }, () => {
            this.improveActionForm()
          })
        }
      })
    }
  }
  improveActionForm = () => {
    const { configMap, execAction } = this.state
    let subfields = []
    if (execAction.groups.length > 0) {
      execAction.groups.forEach(group => {
        group.sublist.forEach(field => {
          if ((field.type === 'select' || field.type === 'link') && field.resourceType === '1') {
            subfields.push(field)
          }
        })
      })
    } else {
      execAction.fields.forEach(field => {
        if ((field.type === 'select' || field.type === 'link') && field.resourceType === '1') {
          subfields.push(field)
        }
      })
    }
    if (subfields.length === 0) {
      this.setState({
        visible: true,
        btnloading: false
      })
      return
    }
    let deffers = subfields.map(item => {
      let arrfield = item.valueField + ',' + item.valueText
      if (item.type === 'link') {
        arrfield = arrfield + ',' + item.linkField
      }
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: item.dataSourceSql,
        obj_name: 'data',
        arr_field: arrfield
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      return new Promise(resolve => {
        Api.getSystemCacheConfig(param).then(res => {
          res.search = item
          resolve(res)
        })
      })
    })
    let _field = {}
    let error = ''
    Promise.all(deffers).then(result => {
      result.forEach(res => {
        if (res.status) {
          let options = res.data.map(cell => {
            let item = {
              key: Utils.getuuid(),
              Value: cell[res.search.valueField],
              Text: cell[res.search.valueText]
            }
            if (res.search.type === 'link') {
              item.parentId = cell[res.search.linkField]
            }
            return item
          })
          _field[res.search.uuid] = options
        } else {
          error = res
        }
      })
      if (error) {
        notification.warning({
          top: 92,
          message: error.message,
          duration: 10
        })
      }
      this.setState({
        configMap: {...configMap, ..._field}
      }, () => {
        this.setState({
          visible: true,
          btnloading: false
        })
      })
    })
  }
  handleOk = () => {
    this.formRef.handleConfirm().then(res => {
      this.setState({
        confirmLoading: true
      })
      this.execSubmit(this.state.execAction, this.state.tabledata, () => {
        this.setState({
          confirmLoading: false
        })
      }, res)
    }, () => {})
  }
  handleCancel = () => {
    this.setState({
      visible: false
    })
  }
  getModels = () => {
    const { execAction } = this.state
    if (!execAction || !this.state.visible) return
    let title = ''
    let width = '62vw'
    let clickouter = false
    let container = document.body
    if (execAction && execAction.setting) {
      title = execAction.setting.title
      width = execAction.setting.width + 'vw'
      if (execAction.setting.container === 'tab') {
        width = execAction.setting.width + '%'
        container = () => document.getElementById('commontable' + this.props.MenuID)
      }
      if (execAction.setting.clickouter === 'close') {
        clickouter = true
      }
    }
    return (
      <Modal
        title={title}
        maskClosable={clickouter}
        getContainer={container}
        wrapClassName='action-modal'
        visible={this.state.visible}
        width={width}
        onOk={this.handleOk}
        confirmLoading={this.state.confirmLoading}
        onCancel={this.handleCancel}
        destroyOnClose
      >
        <MutilForm
          dict={this.props.dict}
          action={execAction}
          inputSubmit={this.handleOk}
          configMap={this.state.configMap}
          data={this.state.tabledata[0]}
          wrappedComponentRef={(inst) => this.formRef = inst}
        />
      </Modal>
    )
  }
  render() {
    const { loadingUuid, btnloading } = this.state
    return (
      <div className="button-list">
        {this.props.actions.map((item, index) => {
          if (loadingUuid === item.uuid) {
            return (
              <Button
                className={'mk-btn mk-' + item.class}
                icon={item.icon}
                key={'action' + index}
                onClick={() => {this.actionTrigger(item)}}
                loading
              >{item.label}</Button>
            )
          } else {
            return (
              <Button
                className={'mk-btn mk-' + item.class}
                icon={item.icon}
                key={'action' + index}
                onClick={() => {this.actionTrigger(item)}}
              >{item.label}</Button>
            )
          }
        })}
        {this.getModels()}
        {btnloading && <Spin size="large" />}
      </div>
    )
  }
}
export default MainAction
src/tabviews/subtable/subAction/index.scss
New file
@@ -0,0 +1,41 @@
.subtable .button-list {
  padding: 10px 0px 5px;
  background: #ffffff;
  button {
    margin-right: 15px;
    margin-bottom: 10px;
  }
  .ant-spin {
    position: fixed;
    z-index: 1010;
    left: 50vw;
    top: calc(50vh - 70px);
  }
}
// 设置模态框样式,规定最大最小高度,重置滚动条
.action-modal {
  .ant-modal {
    max-width: 95vw;
  }
  .ant-modal-body {
    max-height: calc(100vh - 235px);
    min-height: 150px;
    overflow-y: auto;
    padding-bottom: 35px;
  }
  .ant-modal-body::-webkit-scrollbar {
    width: 10px;
    height: 10px;
  }
  .ant-modal-body::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .ant-modal-body::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
}
src/tabviews/subtable/subSearch/index.jsx
New file
@@ -0,0 +1,260 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Button, Select, DatePicker } from 'antd'
import moment from 'moment'
import './index.scss'
const {MonthPicker, WeekPicker, RangePicker} = DatePicker
class MainSearch extends Component {
  static propTpyes = {
    searchlist: PropTypes.array, // 搜索条件列表
    dict: PropTypes.object // 字典项
  }
  state = {
    match: null, // 搜索条件匹配规则
    style: null,
    searchlist: null
  }
  UNSAFE_componentWillMount () {
    let match = {}
    let style = {}
    let _list = []
    let fieldMap = new Map()
    this.props.searchlist.forEach(item => {
      if (fieldMap.has(item.field)) {
        item.field = item.field + '@tail@'
      }
      fieldMap.set(item.field, true)
      match[item.field] = item.match
      style[item.field] = item.type
      _list.push(item)
    })
    this.setState({
      match: match,
      style: style,
      searchlist: _list
    })
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.searchlist.forEach((item, index) => {
      if (item.type === 'text') { // 文本搜索
        fields.push(
          <Col span={6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {initialValue: item.initval })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {initialValue: item.initval })(
                <Select
                  showSearch
                  onChange={this.searchChange}
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.key} title={option.Text} key={option.key} value={option.Value}>{option.Text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'date') { // 时间搜索
        fields.push(
          <Col span={6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {initialValue: item.initval ? moment().subtract(item.initval, 'days') : null })(
                <DatePicker onChange={this.searchChange} />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'datemonth') {
        fields.push(
          <Col span={6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {initialValue: item.initval ? moment().subtract(item.initval, 'month') : null })(
                <MonthPicker onChange={this.searchChange} />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'dateweek') {
        fields.push(
          <Col span={6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field, {initialValue: item.initval ? moment().subtract(item.initval * 7, 'days') : null })(
                <WeekPicker onChange={this.searchChange} />
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'daterange') {
        let _defaultValue = [null, null]
        if (item.initval) {
          try {
            let _initval = JSON.parse(item.initval)
            _defaultValue = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
          } catch {
            _defaultValue = [null, null]
          }
        }
        fields.push(
          <Col className="daterange" span={6} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.field,
                {
                  initialValue: _defaultValue
                })(
                <RangePicker
                  placeholder={['开始日期', '结束日期']}
                  renderExtraFooter={() => 'extra footer'}
                  onChange={this.searchChange}
                />
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    if (this.props.searchlist.length >= 4) { // 添加搜索、重置按钮
      fields.push(
        <Col span={this.props.searchlist.length % 4 ? 6 : 24} style={{paddingLeft: '112px'}} key="actions">
          <Button type="primary" htmlType="submit">
            {this.props.dict['main.search']}
          </Button>
          <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
            {this.props.dict['main.reset']}
          </Button>
        </Col>
      )
    } else {
      fields.push(
        <Col span={6} style={{ paddingTop: '4px' }} key="actions">
          <Button type="primary" htmlType="submit">
            {this.props.dict['main.search']}
          </Button>
          <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
            {this.props.dict['main.reset']}
          </Button>
        </Col>
      )
    }
    return fields
  }
  handleSearch = (e) => {
    // 回车或点击搜索
    e.preventDefault()
    this.props.form.validateFields((err, values) => {
      let searches = this.getFieldsValues(values)
      this.props.refreshdata(searches)
    })
  }
  searchChange = () => {
    this.setState({}, () => {
      this.props.form.validateFields((err, values) => {
        let searches = this.getFieldsValues(values)
        this.props.refreshdata(searches)
      })
    })
  }
  handleReset = () => {
    // 重置
    this.props.form.resetFields()
    this.props.form.validateFields((err, values) => {
      let searches = this.getFieldsValues(values)
      this.props.refreshdata(searches)
    })
  }
  getFieldsValues = (values) => {
    // 获取搜索条件值
    let search = []
    Object.keys(values).forEach(key => {
      if (this.state.style[key] === 'daterange') {
        let _value = ''
        if (values[key].length > 0) {
          _value = [moment(values[key][0]).format('YYYY-MM-DD'), moment(values[key][1]).format('YYYY-MM-DD')]
        }
        search.push({
          type: this.state.style[key],
          key: key.replace(/@tail@$/, ''),
          value: _value,
          match: this.state.match[key]
        })
      } else if (this.state.style[key] === 'dateweek') {
        let _value = ''
        if (values[key]) {
          _value = [moment(values[key]).startOf('week').format('YYYY-MM-DD'), moment(values[key]).endOf('week').format('YYYY-MM-DD')]
        }
        search.push({
          type: this.state.style[key],
          key: key.replace(/@tail@$/, ''),
          value: _value,
          match: this.state.match[key]
        })
      } else if (this.state.style[key] === 'date') {
        let _value = ''
        if (values[key]) {
          _value = moment(values[key]).format('YYYY-MM-DD')
        }
        search.push({
          type: this.state.style[key],
          key: key.replace(/@tail@$/, ''),
          value: _value,
          match: this.state.match[key]
        })
      } else if (this.state.style[key] === 'datemonth') {
        let _value = ''
        if (values[key]) {
          _value = moment(values[key]).format('YYYY-MM')
        }
        search.push({
          type: this.state.style[key],
          key: key.replace(/@tail@$/, ''),
          value: _value,
          match: this.state.match[key]
        })
      } else {
        search.push({
          type: this.state.style[key],
          key: key.replace(/@tail@$/, ''),
          value: values[key].replace(/(^\s*|\s*$)/ig, ''),
          match: this.state.match[key]
        })
      }
    })
    return search
  }
  render() {
    return (
      <Form className="ant-advanced-search-form subtable-main-search" onSubmit={this.handleSearch}>
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/tabviews/subtable/subSearch/index.scss
New file
@@ -0,0 +1,19 @@
.ant-advanced-search-form.subtable-main-search {
  padding: 0px 0px 20px;
  border-bottom: 1px solid #e9e9e9;
  .ant-form-item {
    display: flex;
    margin-bottom: 10px;
  }
  .ant-form-item-control-wrapper {
    flex: 1;
  }
  .ant-form-item-label {
    width: 100px;
    text-overflow: ellipsis;
  }
  .daterange .ant-calendar-picker-input {
    padding: 4px 20px 4px 5px;
    font-size: 13px;
  }
}
src/tabviews/subtable/subTable/index.jsx
New file
@@ -0,0 +1,275 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
// import { is, fromJS } from 'immutable'
import { Table, message, Button } from 'antd'
import './index.scss'
export default class MainTable extends Component {
  static propTpyes = {
    dict: PropTypes.object,        // 字典项
    MenuID: PropTypes.string,      // 菜单Id
    setting: PropTypes.object,     // 表格全局设置:tableType(表格是否可选、单选、多选)、columnfixed(列固定)、actionfixed(按钮固定)
    columns: PropTypes.array,      // 表格列
    data: PropTypes.any,           // 表格数据
    total: PropTypes.number,       // 总数
    loading: PropTypes.bool,       // 表格加载中
    refreshdata: PropTypes.func,   // 表格中排序列、页码的变化时刷新
    buttonTrigger: PropTypes.func  // 表格中按钮触发操作
  }
  state = {
    selectedRowKeys: [], // 表格中选中行
    pageIndex: 1,        // 初始页面索引
    pageSize: 10,        // 每页数据条数
    columns: null        // 显示列
  }
  UNSAFE_componentWillMount () {
    const { columns } = this.props
    let _columns = []
    columns.forEach(item => {
      let cell = {
        align: item.Align,
        dataIndex: item.field || item.uuid,
        title: item.label,
        sorter: item.field && item.IsSort === 'true',
        width: item.Width || 120,
        render: (text, record) => {
          return this.getContent(item, record)
        }
      }
      _columns.push(cell)
    })
    // {item.FieldName === 'MenuNo' ? <Icon onClick={(e) => {this.copycontent(e, record[item.FieldName])}} type="copy"/> : ''}
    this.setState({columns: _columns})
  }
  getContent = (item, record) => {
    if (item.type === 'text') {
      let content = ''
      let match = false
      if (item.field && record.hasOwnProperty(item.field)) {
        content = `${record[item.field]}`
      }
      if (content && item.matchVal && content.indexOf(item.matchVal) > 0) {
        match = true
      }
      content = (item.prefix || '') + content + (item.postfix || '')
      return (
        <div className={match ? item.color : ''}>
          <div className="background"></div>
          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
            {content}
          </div>
        </div>
      )
    } else if (item.type === 'number') {
      let content = ''
      let match = false
      if (item.field && record.hasOwnProperty(item.field)) {
        content = +record[item.field]
      }
      if (content && item.match && item.matchVal) {
        if (item.match === '>') {
          if (content > item.matchVal) {
            match = true
          }
        } else if (item.match === '<') {
          if (content < item.matchVal) {
            match = true
          }
        } else if (item.match === '>=') {
          if (content >= item.matchVal) {
            match = true
          }
        } else if (item.match === '<=') {
          if (content <= item.matchVal) {
            match = true
          }
        }
      }
      if (content && item.format === 'thdSeparator') {
        content = `${content}`
        content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
      }
      content = (item.prefix || '') + content + (item.postfix || '')
      return (
        <div className={match ? item.color : ''}>
          <div className={'background'}></div>
          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
            {content}
          </div>
        </div>
      )
    } else if (item.type === 'action') {
      return (
        <div className={item.style} style={{ minWidth: (item.Width || 120) + 'px' }}>
          {item.operations.map(btn => {
            return <Button
              className={'mk-btn mk-' + btn.class}
              icon={btn.icon}
              key={btn.uuid}
              onClick={(e) => {this.actionTrigger(e, btn, record)}}
            >{btn.label}</Button>
          })}
        </div>
      )
    } else if (item.type === 'colspan') {
      let contents = ''
      if (item.subColumn.length > 0) {
        contents = item.subColumn.map(col => {
          let content = ''
          if (col.type === 'text' || col.type === 'textarea') {
            if (col.field && record.hasOwnProperty(col.field)) {
              content = `${record[col.field]}`
            }
            content = (col.prefix || '') + content + (col.postfix || '')
          } else if (col.type === 'number') {
            if (col.field && record.hasOwnProperty(col.field)) {
              content = +record[col.field]
            }
            if (content && col.format === 'thdSeparator') {
              content = `${content}`
              content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            content = (col.prefix || '') + content + (col.postfix || '')
          }
          return content
        })
      }
      if (contents && item.order === 'vertical2') {
        let _contents = []
        for(let i = 0; i < contents.length; i += 2) {
          _contents.push(contents.slice(i, i + 2).join(' '))
        }
        contents = _contents
      }
      return (
        <div>
          <div className="content" style={{ minWidth: (item.Width || 120) + 'px' }}>
            {contents && item.order === 'vertical' && contents.map((content, index) => {
              return (<p key={index}>{content}</p>)
            })}
            {contents && item.order === 'vertical2' && contents.map((content, index) => {
              return (<p key={index}>{content}</p>)
            })}
            {contents && item.order === 'horizontal' && contents.map((content, index) => {
              return (<span key={index}>{content}</span>)
            })}
          </div>
        </div>
      )
    }
  }
  actionTrigger = (e, btn, record) => {
    e.stopPropagation()
    this.props.buttonTrigger(btn, record)
  }
  copycontent = (e, content) => {
    // 表格中内容复制
    e.stopPropagation()
    let oInput = document.createElement('input')
    oInput.value = content
    document.body.appendChild(oInput)
    oInput.select()
    document.execCommand('Copy')
    oInput.className = 'oInput'
    oInput.style.display='none'
    message.success(this.props.dict['main.copy.success'])
  }
  onSelectChange = selectedRowKeys => {
    this.setState({ selectedRowKeys })
  }
  changeRow = (record, index) => {
    // 点击整行,触发切换,判断是否可选,单选或多选,进行对应操作
    if (!this.props.setting.tableType) return
    let newkeys = JSON.parse(JSON.stringify(this.state.selectedRowKeys))
    let _re = newkeys.includes(index)
    if (this.props.setting.tableType === 'radio') {
      this.setState({ selectedRowKeys: [index] })
    } else {
      if (_re) {
        newkeys = newkeys.filter(item => item !== index)
      } else {
        newkeys.push(index)
      }
      this.setState({ selectedRowKeys: newkeys })
    }
  }
  changeTable = (pagination, filters, sorter) => {
    this.setState({
      pageIndex: pagination.current,
      pageSize: pagination.pageSize,
      selectedRowKeys: []
    })
    this.props.refreshdata(pagination, filters, sorter)
  }
  resetTable = () => {
    this.setState({
      pageIndex: 1,
      selectedRowKeys: []
    })
  }
  render() {
    let { selectedRowKeys } = this.state
    let rowSelection = null
    if (this.props.setting.tableType) {
      rowSelection = {
        selectedRowKeys,
        type: this.props.setting.tableType === 'radio' ? 'radio' : 'checkbox',
        onChange: this.onSelectChange
      }
    }
    return (
      <div className="sub-table">
        <Table
          size="middle"
          bordered={true}
          rowSelection={rowSelection}
          columns={this.state.columns}
          dataSource={this.props.data ? this.props.data : []}
          loading={this.props.loading}
          scroll={{ x: '100%', y: false }}
          onRow={(record, index) => {
            return {
              onClick: () => {this.changeRow(record, index)}
            }
          }}
          onChange={this.changeTable}
          pagination={{
            current: this.state.pageIndex,
            pageSize: this.state.pageSize,
            pageSizeOptions: ['10', '25', '50', '100', '500', '1000'],
            showSizeChanger: true,
            total: this.props.total,
            showTotal: (total, range) => `${range[0]}-${range[1]} ${this.props.dict['main.pagination.of']} ${total} ${this.props.dict['main.pagination.items']}`
          }}
        />
      </div>
    )
  }
}
src/tabviews/subtable/subTable/index.scss
New file
@@ -0,0 +1,119 @@
.sub-table {
  padding: 0;
  table {
    max-width: 100%;
    width: 100%;
    .ant-table-column-title {
      white-space: nowrap;
    }
    .ant-table-selection-column {
      width: 60px;
      min-width: 60px;
      max-width: 60px;
    }
    // .ant-table-tbody > tr td:not(.ant-table-selection-column) {
    //   padding: 0!important;
    // }
    // .ant-table-tbody > tr td .content {
    //   padding: 12px 8px;
    //   height: 100%;
    //   background: lightblue;
    // }
    .ant-table-tbody > tr.ant-table-row-selected td {
      background-color: #c4ebfd;
    }
    .ant-table-tbody > tr.ant-table-row-selected:hover .ant-table-column-sort {
      background-color: #c4ebfd;
    }
  }
  .ant-table-body {
    overflow-x: auto!important;
    min-height: 90px;
    border: 1px solid #e8e8e8;
    border-radius: 4px;
    border-top: none;
    border-bottom: none;
    table {
      border-left: 0;
      .ant-table-thead > tr > th:last-child {
        border-right: 0;
      }
      .ant-table-tbody > tr > td:last-child {
        border-right: 0;
      }
      .ant-table-tbody > tr > td.ant-table-column-has-actions {
        position: relative;
        .background {
          position: absolute;
          top: 0px;
          left: 0px;
          right: 0px;
          bottom: 0px;
        }
        .content {
          position: relative;
          z-index: 1;
          word-wrap: break-word;
          word-break: break-word;
        }
        .red {
          .content {
            color: red;
          }
        }
        .redbg {
          .background {
            background: lightcoral;
          }
        }
      }
      .ant-table-tbody > tr > td .content {
        p {
          margin-bottom: 5px;
        }
        span {
          display: inline-block;
          margin-right: 5px;
        }
      }
      .ant-table-tbody > tr > td .button {
        .ant-btn {
          margin-bottom: 10px;
        }
      }
    }
  }
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
  }
  ::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  ::-webkit-scrollbar-track {/*滚动条里面轨道*/
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
  .fix-header {
    .ant-table-body {
      min-height: unset
    }
    .ant-table-placeholder {
      display: none;
    }
    .ant-table-wrapper {
      display: none;
    }
    .ant-affix .ant-table-wrapper {
      display: block;
    }
    // .ant-table-column-sorter, .anticon-filter {
    //   display: none;
    // }
  }
}
src/templates/comtableconfig/actionform/index.jsx
@@ -196,7 +196,7 @@
              item.options = this.state.reqOptionSgl
              item.initVal = 'requiredSgl'
              item.hidden = true
            } else if (['outerpage', 'blank', 'tab', 'pop', 'popview'].includes(this.state.openType)) {
            } else if (['outerpage', 'blank', 'tab', 'popview'].includes(this.state.openType)) {
              item.options = this.state.reqOptions
              item.initVal = 'requiredSgl'
              item.hidden = true
src/templates/comtableconfig/index.jsx
@@ -68,7 +68,8 @@
    originActions: null,     // 原始按钮信息,使用已有用户模板
    delActions: [],          // 删除按钮列表
    funcLoading: false,      // 存储过程创建中
    showColumnName: false    // 显示列字段名控制
    showColumnName: false,   // 显示列字段名控制
    tabviews: false          // 所有标签页
  }
  /**
@@ -83,13 +84,8 @@
    let _config = ''
    if (!_LongParam) {
      _config = JSON.parse(JSON.stringify((Source.baseConfig)))
      _config = JSON.parse(JSON.stringify(Source.baseConfig))
    } else {
      let _setting = Source.baseConfig.setting
      if (_LongParam.setting) {
        _setting = {..._setting, ..._LongParam.setting}
      }
      _LongParam.setting = _setting
      _config = _LongParam
    }
    
@@ -170,6 +166,7 @@
   * @description 加载完成后
   * 1、获取系统可使用表
   * 2、根据配置信息中已使用表获取相关字段信息
   * 3、获取所有标签页信息
   */
  componentDidMount () {
    let param = {
@@ -263,6 +260,31 @@
        tableColumns: _columns
      })
    })
    // let param = {
    //   func: 'sPC_Get_SelectedList',
    //   LText: 'select TbName ,Remark from sDataDictionary where IsKey!=\'\' and Deleted =0',
    //   obj_name: 'data',
    //   arr_field: 'TbName,Remark'
    // }
    // param.LText = Utils.formatOptions(param.LText)
    // param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    // param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    // Api.getSystemConfig(param).then(res => {
    //   if (res.status) {
    //     this.setState({
    //       tables: res.data
    //     })
    //   } else {
    //     notification.warning({
    //       top: 92,
    //       message: res.message,
    //       duration: 10
    //     })
    //   }
    // })
  }
  handleList = (type, list, card) => {
@@ -1768,7 +1790,7 @@
        return
      }
      let btnParam = {
      let btnParam = { // 添加菜单按钮
        func: 'sPC_Button_AddUpt',
        ParentID: menu.MenuID,
        MenuNo: res.menuNo,
@@ -1784,6 +1806,18 @@
      btnParam.LText = Utils.formatOptions(btnParam.LText)
      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
      let tabParam = { // 添加菜单tab页
        func: 'sPC_sMenusTab_AddUpt',
        LText: config.tabs.map((item, index) => {
          return `select '${menu.MenuID}' as MenuID ,'${item.uuid}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`
        })
      }
      tabParam.LText = tabParam.LText.join(' union all ')
      tabParam.LText = Utils.formatOptions(tabParam.LText)
      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
@@ -1832,7 +1866,7 @@
          this.props.reloadmenu()
          
          this.submitAction(btnParam)
          this.submitAction(btnParam, tabParam)
        } else {
          this.setState({
            menuloading: false,
@@ -1857,7 +1891,8 @@
  /**
   * @description 保存或修改菜单按钮
   */
  submitAction = (param) => {
  submitAction = (btnParam, tabParam) => {
    console.log(tabParam)
    const { config } = this.state
    new Promise(resolve => {
      // 内部请求
@@ -1892,17 +1927,17 @@
            this.setState({
              delActions: []
            })
            resolve(param)
            resolve(true)
          }
        })
      } else if (this.state.delActions.length === 0) {
        resolve(param)
        resolve(true)
      }
    }).then(res => {
      if (res === false) return res
      if (res.LText) {
        return Api.getSystemConfig(res)
      if (btnParam.LText) {
        return Api.getSystemConfig(btnParam)
      } else {
        return 'copy'
      }
@@ -2430,13 +2465,21 @@
            }
          })
        } else if (type === 'tab') {
          this.props.handleSubConfig(btn, originMenu, '', type)
          // this.setState({
          //   loading: true
          // })
          if (btn.linkTab) {
          } else {
            let _tab = {
              uuid: btn.linkId,
              create: true
            }
            this.props.handleSubConfig(btn, originMenu, _tab, type)
          }
          this.setState({
            loading: true
          })
          // Api.getSystemConfig({
          //   func: 'sPC_Get_LongParam',
          //   MenuID: btn.uuid
          //   MenuID: btn.linkId
          // }).then(res => {
          //   if (res.status) {
          //     this.setState({
@@ -2451,7 +2494,7 @@
          //         _LongParam = ''
          //       }
          //     }
          //     this.props.handleSubConfig(btn, originMenu, _LongParam)
          //     console.log(_LongParam)
          //   } else {
          //     this.setState({
          //       loading: false
@@ -2687,7 +2730,6 @@
                <Tooltip placement="bottomLeft" overlayClassName="middle" title="在左侧工具栏《标签页》中,选择对应类型的标签页拖至此处添加。">
                  <Icon type="question-circle" />
                </Tooltip>
                {/* {this.state.config.tabs.length > 0 ? <Icon type="setting" onClick={this.changeSetting} /> : null} */}
                {!this.state.tabloading ?
                  <TabDragElement
                    type="tabs"
src/templates/comtableconfig/settingform/index.jsx
@@ -228,6 +228,18 @@
              })(<Input placeholder="ID asc, UID desc" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="标签">
              {getFieldDecorator('tabshow', {
                initialValue: data.tabshow || 'horizontal'
              })(
                <Select>
                  <Select.Option value="horizontal">横向显示</Select.Option>
                  <Select.Option value="vertical">纵向显示</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
src/templates/comtableconfig/source.jsx
@@ -19,7 +19,8 @@
      interType: 'inner',
      innerFunc: '',
      interface: '',
      outerFunc: ''
      outerFunc: '',
      tabshow: 'horizontal'
    },
    tables: [],
    search: [
src/templates/comtableconfig/tabdragelement/index.jsx
@@ -43,8 +43,9 @@
      newcard.label = 'tab'
      newcard.icon = ''
      newcard.type = item.subType
      newcard.linkId = ''
      newcard.description = ''
      newcard.linkTab = ''
      newcard.linkId = Utils.getuuid()
      newcard.supMenu = ''
      
      let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
      if (target) {
@@ -77,7 +78,7 @@
  return (
    <div ref={drop} className="ant-row">
      <Tabs defaultActiveKey="0" tabPosition="top">
      <Tabs defaultActiveKey="0">
        {cards.map((card, index) => (
          <TabPane tab={
            <div key={card.uuid}>
src/templates/comtableconfig/tabform/index.jsx
@@ -1,6 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, Icon } from 'antd'
import Utils from '@/utils/utils.js'
import './index.scss'
@@ -116,6 +117,10 @@
          values.uuid = this.props.card.uuid
          if (!values.linkTab) { // 没有关联标签(新建时),创建新标签Id
            values.linkId = Utils.getuuid()
          }
          resolve({
            type: this.props.type,
            values
src/templates/subtableconfig/actionform/index.jsx
@@ -22,13 +22,6 @@
      MenuID: 'requiredSgl',
      text: this.props.dict['header.form.requiredSgl']
    }],
    reqOptions: [{
      MenuID: 'notRequired',
      text: this.props.dict['header.form.notRequired']
    }, {
      MenuID: 'requiredSgl',
      text: this.props.dict['header.form.requiredSgl']
    }],
    reqOptionsMutil: [{
      MenuID: 'notRequired',
      text: this.props.dict['header.form.notRequired']
@@ -70,13 +63,7 @@
    let _intertype = this.props.formlist.filter(form => form.key === 'intertype')[0].initVal
    let _position = this.props.formlist.filter(form => form.key === 'position')[0].initVal
    let _options = null
    if (_opentype === 'innerpage') { // 新页面(内部),可选模板
      _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
    } else if (_opentype === 'outerpage') { // 新页面(外部),需要页面地址
      _options = ['label', 'Ot', 'OpenType', 'url', 'icon', 'class', 'position']
    } else if (_opentype === 'blank' || _opentype === 'tab' || _opentype === 'popview') {
      _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position']
    } else if (_opentype === 'excelIn' || _opentype === 'excelOut') {
    if (_opentype === 'excelIn' || _opentype === 'excelOut') {
      if (_intertype === 'outer') {
        _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'execSuccess', 'execError', 'method']
      } else {
@@ -99,13 +86,7 @@
        } else if (item.key === 'icon') {
          item.options = btnIcons
        } else if (item.key === 'Ot') {
          if (_opentype === 'innerpage' || _position === 'grid') {
            item.options = this.state.reqOptionSgl
          } else if (['outerpage', 'blank', 'tab', 'popview'].includes(_opentype)) {
            item.options = this.state.reqOptions
          } else {
            item.options = this.state.reqOptionsMutil
          }
        } else if (item.key === 'sqlType') {
          if (['prompt', 'exec'].includes(_opentype)) {
            item.options = this.state.deleteOptions
@@ -123,13 +104,7 @@
  openTypeChange = (key, value) => {
    if (key === 'OpenType') {
      let _options = null
      if (value === 'innerpage') {
        _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
      } else if (value === 'outerpage') {
        _options = ['label', 'Ot', 'OpenType', 'url', 'icon', 'class', 'position']
      } else if (value === 'blank' || value === 'tab' || value === 'popview') {
        _options = ['label', 'Ot', 'OpenType', 'icon', 'class', 'position']
      } else if (value === 'excelIn' || value === 'excelOut') {
      if (value === 'excelIn' || value === 'excelOut') {
        if (this.state.interType === 'outer') {
          _options = ['label', 'OpenType', 'intertype', 'innerFunc', 'interface', 'outerFunc', 'callbackFunc', 'icon', 'class', 'execSuccess', 'execError', 'method']
        } else {
@@ -152,11 +127,8 @@
            }
          }
          if (item.key === 'Ot') {
            if (value === 'innerpage' || this.state.position === 'grid') {
            if (this.state.position === 'grid') {
              item.options = this.state.reqOptionSgl
              item.initVal = 'requiredSgl'
            } else if (['outerpage', 'blank', 'tab', 'popview'].includes(value)) {
              item.options = this.state.reqOptions
              item.initVal = 'requiredSgl'
            } else {
              item.options = this.state.reqOptionsMutil
@@ -192,16 +164,14 @@
        position: value,
        formlist: this.state.formlist.map(item => {
          if (item.key === 'Ot') {
            if (this.state.openType === 'innerpage' || value === 'grid') {
            if (value === 'grid') {
              item.options = this.state.reqOptionSgl
              item.initVal = 'requiredSgl'
              item.hidden = true
            } else if (['outerpage', 'blank', 'tab', 'pop', 'popview'].includes(this.state.openType)) {
              item.options = this.state.reqOptions
              item.initVal = 'requiredSgl'
              item.hidden = true
            } else {
              item.options = this.state.reqOptionsMutil
              item.initVal = 'requiredSgl'
              item.hidden = true
            }
          }
          return item
src/templates/subtableconfig/dragelement/index.jsx
@@ -102,8 +102,6 @@
        newcard.execSuccess = 'grid'
        newcard.execError = 'never'
        newcard.callbackFunc = ''
        newcard.pageTemplate = ''
        newcard.url = ''
        if (item.subType === 'excelIn' || item.subType === 'excelOut') {
          // 导入和导出excel,按钮名称直接为导入、导出
src/templates/subtableconfig/index.jsx
@@ -7,10 +7,8 @@
import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty, Switch, Tooltip } from 'antd'
import moment from 'moment'
import DragElement from './dragelement'
import TabDragElement from './tabdragelement'
import SourceElement from './dragelement/source'
import Api from '@/api'
import TabForm from './tabform'
import SearchForm from './searchform'
import ActionForm from './actionform'
import ColumnForm from './columnform'
@@ -30,11 +28,9 @@
const { confirm } = Modal
const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
class ComTableConfig extends Component {
class SubTableConfig extends Component {
  static propTpyes = {
    type: PropTypes.string,
    menu: PropTypes.any,
    reloadmenu: PropTypes.func,
    config: PropTypes.object,
    handleConfig: PropTypes.func,
    handleSubConfig: PropTypes.func,
    supMenuList: PropTypes.array
@@ -56,7 +52,6 @@
    searchloading: false,    // 搜索条件加载中
    actionloading: false,    // 按钮加载中
    columnsloading: false,   // 显示列加载中
    tabloading: false,       // 标签页加载中
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
    loading: false,          // 加载中,页面spin
@@ -64,7 +59,7 @@
    closeVisible: false,     // 关闭模态框
    tables: [],              // 可用表名
    selectedTables: [],      // 已选表名
    originMenu: null,        // 原始菜单
    originConfig: null,      // 原配置
    originActions: null,     // 原始按钮信息,使用已有用户模板
    delActions: [],          // 删除按钮列表
    funcLoading: false,      // 存储过程创建中
@@ -77,20 +72,17 @@
   * 2、设置操作类型、原始菜单信息(每次保存后重置)、已使用表及基本信息表单
   */
  UNSAFE_componentWillMount () {
    const { menu } = this.props
    const { config } = this.props
    console.log(config)
    let _config = null
    let _LongParam = menu.LongParam
    let _config = ''
    if (!_LongParam) {
      _config = JSON.parse(JSON.stringify((Source.baseConfig)))
    } else {
      let _setting = Source.baseConfig.setting
      if (_LongParam.setting) {
        _setting = {..._setting, ..._LongParam.setting}
    if (!config || config.create) {
      _config = JSON.parse(JSON.stringify(Source.baseConfig))
      if (config.uuid) {
        _config.uuid = config.uuid
      }
      _LongParam.setting = _setting
      _config = _LongParam
    } else {
      _config = JSON.parse(JSON.stringify(config))
    }
    
    let _oriActions = []
@@ -98,7 +90,7 @@
      _config.action = _config.action.map(item => {
        let uuid = Utils.getuuid()
        if (item.OpenType === 'pop') { // 含有子配置项的按钮。。。
        if (item.OpenType === 'pop') { // 含有子配置项的按钮
          _oriActions.push({
            prebtn: JSON.parse(JSON.stringify(item)),
            curuuid: uuid,
@@ -112,55 +104,35 @@
      })
    }
    _config.tabs = _config.tabs || []
    this.setState({
      originActions: _oriActions,
      config: _config,
      originMenu: JSON.parse(JSON.stringify(menu)),
      originConfig: _config,
      selectedTables: _config.tables || [],
      menuformlist: [
        {
          type: 'select',
          key: 'parentId',
          label: this.state.dict['header.menu.supMenu'],
          initVal: menu.ParentID,
          required: true,
          readonly: false,
          options: this.props.supMenuList
        },
        {
          type: 'text',
          key: 'menuName',
          label: this.state.dict['header.menu.menuName'],
          initVal: menu.MenuName,
          key: 'tabName',
          label: this.state.dict['header.menu.tabName'],
          initVal: _config.tabName,
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'menuNo',
          key: 'tabNo',
          label: this.state.dict['header.menu.menuNo'],
          initVal: menu.MenuNo,
          initVal: _config.tabNo,
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'opentype',
          label: this.state.dict['header.menu.openType'],
          initVal: menu.PageParam.OpenType,
          required: true,
          options: [{
            MenuID: 'newtab',
            text: this.state.dict['header.form.tab']
          }, {
            MenuID: 'newpage',
            text: this.state.dict['header.form.newpage']
          }, {
            MenuID: 'currenttab',
            text: this.state.dict['header.form.currenttab']
          }]
          type: 'text',
          key: 'Remark',
          label: this.state.dict['header.menu.Remark'],
          initVal: _config.Remark,
          required: false,
          readonly: false
        }
      ]
    })
@@ -286,8 +258,6 @@
          this.handleAction(card)
        } else if (type === 'columns') {
          this.handleColumn(card)
        } else if (type === 'tabs') {
          this.handleTab(card)
        }
      })
    } else {
@@ -509,48 +479,18 @@
            MenuID: 'pop',
            text: this.state.dict['header.form.popform']
          }, {
            MenuID: 'popview',
            text: this.state.dict['header.form.popview']
          }, {
            MenuID: 'prompt',
            text: this.state.dict['header.form.prompt']
          }, {
            MenuID: 'exec',
            text: this.state.dict['header.form.exec']
          }, {
            MenuID: 'tab',
            text: this.state.dict['header.form.tab']
          }, {
            MenuID: 'excelIn',
            text: this.state.dict['header.form.excelIn']
          }, {
            MenuID: 'excelOut',
            text: this.state.dict['header.form.excelOut']
          }, {
            MenuID: 'blank',
            text: this.state.dict['header.form.blank']
          }, {
            MenuID: 'innerpage',
            text: this.state.dict['header.form.newpage.inner']
          }, {
            MenuID: 'outerpage',
            text: this.state.dict['header.form.newpage.outer']
          }]
        },
        {
          type: 'select',
          key: 'pageTemplate',
          label: this.state.dict['header.form.pageTemplate'],
          initVal: card.pageTemplate,
          required: true,
          options: []
        },
        {
          type: 'text',
          key: 'url',
          label: this.state.dict['header.form.newpage.url'],
          initVal: card.url || '',
          required: true
        },
        {
          type: 'radio',
@@ -911,117 +851,6 @@
    }
  }
  handleTab = (card) => {
    const { config } = this.state
    let menus = []
    config.tabs.forEach(item => {
      if (item.origin || card.uuid === item.uuid) return
      let menu = {
        value: item.uuid,
        text: item.label
      }
      menus.push(menu)
    })
    if (card.supMenu && card.supMenu !== 'mainTable') {
      let _menu = menus.filter(item => item.value === card.supMenu)[0]
      if (!_menu) {
        card.supMenu = ''
      }
    }
    this.setState({
      visible: true,
      formtemp: 'tabs',
      modalTitle: '编辑-标签页',
      card: card,
      formlist: [
        {
          type: 'text',
          key: 'label',
          label: this.state.dict['header.form.name'],
          initVal: card.label || '',
          required: true
        },
        {
          type: 'select',
          key: 'type',
          label: this.state.dict['header.form.type'],
          initVal: card.type || '',
          required: true,
          options: [{
            value: 'SubTable',
            text: this.state.dict['header.menu.tab.subtable']
          }]
        },
        {
          type: 'select',
          key: 'linkTab',
          label: '关联标签',
          initVal: card.linkTab || '',
          required: false,
          options: [{
            value: '',
            text: '新建'
          }, {
            value: 'jadisfjiasodjIjjaidfoasdf',
            text: '子表1'
          }, {
            value: 'dasjfsioafjiaga',
            text: '子表2'
          }, {
            value: 'jadsifjasgfisag',
            text: '子表3'
          }]
        },
        {
          type: 'select',
          key: 'icon',
          label: this.state.dict['header.menu.icon'],
          initVal: card.icon || '',
          required: false,
          options: [{
            value: '',
            text: this.state.dict['header.form.empty']
          }, {
            value: 'table',
            text: 'table'
          }, {
            value: 'bar-chart',
            text: 'bar-chart'
          }, {
            value: 'pie-chart',
            text: 'pie-chart'
          }, {
            value: 'line-chart',
            text: 'line-chart'
          }]
        },
        {
          type: 'select',
          key: 'supMenu',
          label: '关联菜单',
          initVal: card.supMenu || '',
          required: false,
          options: [
            {
              value: '',
              text: this.state.dict['header.form.empty']
            }, {
              value: 'mainTable',
              text: '主表'
            },
            ...menus
          ]
        }
      ]
    })
  }
  handleGridBtn = () => {
    this.setState({
      visible: true,
@@ -1037,7 +866,6 @@
   * 3、添加或编辑列,保存时,如按钮位置设置为表格,则修改操作列显示状态
   */
  handleSubmit = () => {
    const { menu } = this.props
    const { card } = this.state
    let _config = JSON.parse(JSON.stringify(this.state.config))
@@ -1067,9 +895,9 @@
            if (result.status && result.LongParam) {
              let param = {
                func: 'sPC_ButtonParam_AddUpt',
                ParentID: menu.MenuID,
                ParentID: _config.uuid,
                MenuID: res.values.uuid,
                MenuNo: menu.MenuNo,
                MenuNo: _config.tabNo,
                Template: 'Modal',
                MenuName: res.values.label,
                PageParam: JSON.stringify({Template: 'Modal'}),
@@ -1132,14 +960,12 @@
          searchloading: true,
          actionloading: true,
          columnsloading: true,
          tabloading: true,
          visible: false
        }, () => {
          this.setState({
            searchloading: false,
            actionloading: false,
            columnsloading: false,
            tabloading: false
          })
        })
      })
@@ -1159,7 +985,6 @@
   * @description 创建按钮存储过程
   */
  creatFunc = () => {
    const { menu } = this.props
    let _config = JSON.parse(JSON.stringify(this.state.config))
    this.formRef.handleConfirm().then(res => {
@@ -1217,9 +1042,9 @@
                funcName: btn.innerFunc,
                name: _config.setting.tableName || '',
                fields: fields,
                menuNo: menu.MenuNo
                menuNo: _config.tabNo
              }
              newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config.columns))
              newLText = Utils.formatOptions(Utils.getfunc(_param, btn, {MenuID: _config.uuid, MenuName: _config.tabName}, _config.columns))
              DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
              resolve(true)
            } else {
@@ -1236,9 +1061,9 @@
            funcName: btn.innerFunc,
            name: _config.setting.tableName || '',
            fields: '',
            menuNo: menu.MenuNo
            menuNo: _config.tabNo
          }
          newLText = Utils.formatOptions(Utils.getfunc(_param, btn, menu, _config.columns))
          newLText = Utils.formatOptions(Utils.getfunc(_param, btn, {MenuID: _config.uuid, MenuName: _config.tabName}, _config.columns))
          DelText = Utils.formatOptions(Utils.dropfunc(_param.funcName))
          resolve(true)
        }
@@ -1469,7 +1294,6 @@
   * @description 创建表格存储过程
   */
  tableCreatFunc = () => {
    const { menu } = this.props
    let config = JSON.parse(JSON.stringify(this.state.config))
    this.settingRef.handleConfirm().then(res => {
@@ -1487,7 +1311,7 @@
        let param = {
          func: 's_DataSrc_Save',
          LText: setting.dataresource,
          MenuID: menu.MenuID
          MenuID: config.uuid
        }
        param.LText = Utils.formatOptions(param.LText)
@@ -1501,7 +1325,7 @@
        funcLoading: true
      })
      let newLText = Utils.formatOptions(Utils.getTableFunc(setting, menu, config)) // 创建存储过程sql
      let newLText = Utils.formatOptions(Utils.getTableFunc(setting, {MenuID: config.uuid, MenuName: config.tabName, MenuNo: config.tabNo}, config)) // 创建存储过程sql
      let DelText = Utils.formatOptions(Utils.dropfunc(setting.innerFunc))          // 删除存储过程sql
      new Promise(resolve => {
@@ -1704,10 +1528,6 @@
        let refreshtype = element.type + 'loading'
        if (/^tab/.test(refreshtype)) {
          refreshtype = 'tabloading'
        }
        _this.setState({
          config: _config,
          delActions: [..._this.state.delActions, element.card.uuid],
@@ -1727,12 +1547,9 @@
  }
  /**
   * @description 三级菜单保存
   * @description 标签页保存
   */
  submitConfig = () => {
    const { menu } = this.props
    const { originMenu } = this.state
    let config = JSON.parse(JSON.stringify(this.state.config))
    this.menuformRef.handleConfirm().then(res => {
@@ -1746,13 +1563,9 @@
      if (config.columns[0] && config.columns[0].origin) {
        config.columns = config.columns.filter(item => !item.origin)
      }
      if (config.tabs[0] && config.tabs[0].origin) {
        config.tabs = config.tabs.filter(item => !item.origin)
      }
      let _LongParam = ''
      let _config = {...config, tables: this.state.selectedTables}
      let _pageParam = {...menu.PageParam, OpenType: res.opentype}
      let _config = {...config, tables: this.state.selectedTables, ...res}
      // 保存时删除配置类型,system 、user
      delete _config.type
@@ -1770,9 +1583,9 @@
      let btnParam = {
        func: 'sPC_Button_AddUpt',
        ParentID: menu.MenuID,
        MenuNo: res.menuNo,
        Template: menu.PageParam.Template || '',
        ParentID: _config.uuid,
        MenuNo: res.tabNo,
        Template: 'SubTable',
        PageParam: '',
        LongParam: '',
        LText: config.action.map((item, index) => {
@@ -1786,14 +1599,14 @@
      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        ParentID: res.parentId,
        MenuID: menu.MenuID,
        MenuNo: res.menuNo,
        Template: menu.PageParam.Template || '',
        MenuName: res.menuName,
        Sort: (this.props.supMenuList.length + 1) * 10,
        PageParam: JSON.stringify(_pageParam),
        func: 'sPC_Tab_AddUpt',
        MenuID: _config.uuid,
        MenuNo: res.tabNo,
        Template: 'SubTable',
        MenuName: res.tabName,
        Remark: res.Remark,
        Sort: 0,
        PageParam: JSON.stringify({Template: 'SubTable'}),
        LongParam: _LongParam
      }
      
@@ -1811,14 +1624,7 @@
        if (response.status) {
          this.setState({
            config: _config,
            originMenu: {
              ...originMenu,
              LongParam: _config,
              PageParam: _pageParam,
              MenuName: res.menuName,
              MenuNo: res.menuNo,
              ParentID: res.parentId
            },
            originConfig: _config,
            searchloading: true,
            actionloading: true,
            columnsloading: true
@@ -1827,12 +1633,15 @@
              searchloading: false,
              actionloading: false,
              columnsloading: false
            }, () => {
              console.log(btnParam)
              this.setState({
                menuloading: false,
                menucloseloading: false
            })
          })
          this.props.reloadmenu()
          this.submitAction(btnParam)
            // this.submitAction(btnParam)
          })
        } else {
          this.setState({
            menuloading: false,
@@ -1956,9 +1765,9 @@
            if (_LongParam) {
              let param = {
                func: 'sPC_ButtonParam_AddUpt',
                ParentID: this.props.menu.MenuID,
                ParentID: config.uuid,
                MenuID: action.curBtn.uuid,
                MenuNo: this.props.menu.MenuNo,
                MenuNo: config.tabNo,
                Template: _LongParam.type,
                MenuName: action.curBtn.label,
                PageParam: JSON.stringify({Template: _LongParam.type}),
@@ -1995,8 +1804,7 @@
  }
  cancelConfig = () => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    const { config, originConfig } = this.state
    let _this = this
    let isAdd = false
@@ -2004,8 +1812,7 @@
    if (
      (config.search[0] && config.search[0].origin) ||
      (config.action[0] && config.action[0].origin) ||
      (config.columns[0] && config.columns[0].origin) ||
      (config.tabs[0] && config.tabs[0].origin)
      (config.columns[0] && config.columns[0].origin)
    ) {
      isAdd = true
    }
@@ -2022,18 +1829,9 @@
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, tables: this.state.selectedTables}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.menuName,
          MenuNo: res.menuNo,
          ParentID: res.parentId
        }
        let _config = {...config, tables: this.state.selectedTables, ...res}
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
        if (!is(fromJS(originConfig), fromJS(_config))) {
          this.setState({
            closeVisible: true
          })
@@ -2318,7 +2116,6 @@
  }
  settingSave = () => {
    const { menu } = this.props
    const {config} = this.state
    this.settingRef.handleConfirm().then(res => {
@@ -2331,7 +2128,7 @@
        let param = {
          func: 's_DataSrc_Save',
          LText: res.dataresource,
          MenuID: menu.MenuID
          MenuID: config.uuid
        }
        param.LText = Utils.formatOptions(param.LText)
@@ -2357,16 +2154,14 @@
   * @description 设置可配置按钮
   */
  setSubConfig = (btn, type) => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    const { config, originConfig } = this.state
    let isAdd = false
    if (
      (config.search[0] && config.search[0].origin) ||
      (config.action[0] && config.action[0].origin) ||
      (config.columns[0] && config.columns[0].origin) ||
      (config.tabs[0] && config.tabs[0].origin)
      (config.columns[0] && config.columns[0].origin)
    ) {
      isAdd = true
    }
@@ -2379,18 +2174,9 @@
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, tables: this.state.selectedTables}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.menuName,
          MenuNo: res.menuNo,
          ParentID: res.parentId
        }
        let _config = {...config, tables: this.state.selectedTables, ...res}
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
        if (!is(fromJS(originConfig), fromJS(_config))) {
          notification.warning({
            top: 92,
            message: '菜单配置已修改,请保存!',
@@ -2417,7 +2203,7 @@
                  _LongParam = ''
                }
              }
              this.props.handleSubConfig(btn, originMenu, _LongParam, type)
              this.props.handleSubConfig(btn, '', _LongParam, type)
            } else {
              this.setState({
                loading: false
@@ -2430,7 +2216,7 @@
            }
          })
        } else if (type === 'tab') {
          this.props.handleSubConfig(btn, originMenu, '', type)
          this.props.handleSubConfig(btn, '', '', type)
          // this.setState({
          //   loading: true
          // })
@@ -2451,7 +2237,7 @@
          //         _LongParam = ''
          //       }
          //     }
          //     this.props.handleSubConfig(btn, originMenu, _LongParam)
          //     this.props.handleSubConfig(btn, '', _LongParam)
          //   } else {
          //     this.setState({
          //       loading: false
@@ -2593,33 +2379,6 @@
                </div>
                <Button type="primary" block onClick={() => this.queryField('columns')}>{this.state.dict['header.menu.column.add']}</Button>
              </Panel>
              {/* 添加标签 */}
              <Panel header={this.state.dict['header.menu.tab']} key="4">
                <div className="search-element">
                  {Source.tabItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                {this.state.config.tabs.length > 0 ?
                  <p className="config-btn-title">
                    <Tooltip placement="topLeft" title="点击按钮,可完成或查看标签配置信息。">
                      <Icon type="question-circle" />
                    </Tooltip>
                    {this.state.dict['header.menu.tab.configurable']}
                  </p> : null
                }
                {this.state.config.tabs.map((item, index) => {
                  return (
                    <div key={index}>
                      <Button
                        icon={item.icon}
                        style={{marginBottom: '10px'}}
                        onClick={() => this.setSubConfig(item, 'tab')}
                      >{item.label}</Button>
                    </div>
                  )
                })}
              </Panel>
            </Collapse>
          </div>
          <div className="setting">
@@ -2683,23 +2442,6 @@
                  /> : null
                }
              </div>
              <div className="tab-list">
                <Tooltip placement="bottomLeft" overlayClassName="middle" title="在左侧工具栏《标签页》中,选择对应类型的标签页拖至此处添加。">
                  <Icon type="question-circle" />
                </Tooltip>
                {/* {this.state.config.tabs.length > 0 ? <Icon type="setting" onClick={this.changeSetting} /> : null} */}
                {!this.state.tabloading ?
                  <TabDragElement
                    type="tabs"
                    list={this.state.config.tabs}
                    setting={this.state.config.setting}
                    handleList={this.handleList}
                    handleMenu={this.handleTab}
                    deleteMenu={this.deleteElement}
                    placeholder={this.state.dict['header.form.tab.placeholder']}
                  /> : null
                }
              </div>
            </Card>
          </div>
        </DndProvider>
@@ -2756,15 +2498,6 @@
              wrappedComponentRef={(inst) => this.formRef = inst}
            /> : null
          }
          {this.state.formtemp === 'tabs' ?
            <TabForm
              type="tabs"
              dict={this.state.dict}
              card={this.state.card}
              formlist={this.state.formlist}
              wrappedComponentRef={(inst) => this.formRef = inst}
            /> : null
          }
        </Modal>
        {/* 根据字段名添加显示列及搜索条件 */}
        <Modal
@@ -2810,7 +2543,7 @@
        >
          <SettingForm
            dict={this.state.dict}
            menu={this.props.menu}
            tabId={this.state.config.uuid}
            data={this.state.config.setting}
            columns={this.state.config.columns}
            usefulFields={this.props.permFuncField}
@@ -2847,4 +2580,4 @@
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(ComTableConfig)
export default connect(mapStateToProps, mapDispatchToProps)(SubTableConfig)
src/templates/subtableconfig/menuform/index.jsx
@@ -11,6 +11,7 @@
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.props.formlist.forEach((item, index) => {
      if (item.type === 'text') { // 文本搜索
@@ -45,7 +46,7 @@
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  getPopupContainer={() => document.getElementById('qazxcvbn')}
                  getPopupContainer={() => document.getElementById('subqazxcvbn')}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.MenuID} title={option.text} key={option.MenuID} value={option.MenuID}>
@@ -87,7 +88,7 @@
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form" id="qazxcvbn">
      <Form {...formItemLayout} className="ant-advanced-search-form" id="subqazxcvbn">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
src/templates/subtableconfig/settingform/index.jsx
@@ -8,7 +8,7 @@
class SettingForm extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    menu: PropTypes.object,
    tabId: PropTypes.string,
    data: PropTypes.object,
    columns: PropTypes.array,
    usefulFields: PropTypes.array
@@ -50,7 +50,7 @@
  }
  render() {
    const { data, dict, menu, usefulFields } = this.props
    const { data, dict, tabId, usefulFields } = this.props
    const { getFieldDecorator } = this.props.form
    const { interType, columns } = this.state
@@ -161,7 +161,7 @@
            </Form.Item>
          </Col> : null}
          {interType !== 'outer' ? <Col span={24}>
            <Form.Item help={'数据ID:' + menu.MenuID} label={
            <Form.Item help={'数据ID:' + tabId} label={
              <Tooltip placement="topLeft" title="使用系统函数时,需填写数据源,自定义函数时,可忽略。">
                <Icon type="question-circle" />
                {'数据源'}
@@ -172,30 +172,6 @@
              })(<TextArea rows={4} />)}
            </Form.Item>
          </Col> : null}
          <Col span={12}>
            <Form.Item label="固定按钮">
              {getFieldDecorator('actionfixed', {
                initialValue: data.actionfixed ? 'true' : 'false'
              })(
                <Select>
                  <Select.Option value="true">是</Select.Option>
                  <Select.Option value="false">否</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="固定列">
              {getFieldDecorator('columnfixed', {
                initialValue: data.columnfixed ? 'true' : 'false'
              })(
                <Select>
                  <Select.Option value="true">是</Select.Option>
                  <Select.Option value="false">否</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="主键">
              {getFieldDecorator('primaryKey', {
src/templates/subtableconfig/source.jsx
@@ -4,13 +4,16 @@
const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
class CommonTableBaseData {
class SubTableBaseData {
  baseConfig = {
    type: 'system',
    Template: 'SubTable',
    enabled: false,
    tabName: '',
    tabNo: '',
    Remark: '',
    uuid: Utils.getuuid(),
    setting: {
      actionfixed: false,
      columnfixed: false,
      tableName: '',
      tableType: 'checkbox',
      primaryKey: '',
@@ -97,8 +100,6 @@
        execSuccess: 'grid',
        execError: 'never',
        OpenType: 'pop',
        pageTemplate: '',
        url: '',
        icon: 'plus',
        class: 'green'
      }, {
@@ -118,8 +119,6 @@
        execSuccess: 'grid',
        execError: 'never',
        OpenType: 'pop',
        pageTemplate: '',
        url: '',
        icon: 'form',
        class: 'purple'
      }, {
@@ -139,8 +138,6 @@
        execSuccess: 'grid',
        execError: 'never',
        OpenType: 'prompt',
        pageTemplate: '',
        url: '',
        icon: 'delete',
        class: 'red'
      }
@@ -198,27 +195,7 @@
      style: 'button',
      show: 'horizontal',
      Width: 120
    },
    tabs: [
      {
        origin: true,
        uuid: Utils.getuuid(),
        label: 'tab1',
        icon: '',
        type: 'SubTable',
        linkTab: '',
        supMenu: ''
      },
      {
        origin: true,
        uuid: Utils.getuuid(),
        label: 'tab2',
        icon: '',
        type: 'SubTable',
        linkTab: '',
        supMenu: ''
      }
    ]
  }
  searchItems = [
@@ -287,12 +264,6 @@
    },
    {
      type: 'action',
      label: CommonDict['header.form.tab'],
      subType: 'tab',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.excelIn'],
      subType: 'excelIn',
      url: ''
@@ -301,24 +272,6 @@
      type: 'action',
      label: CommonDict['header.form.excelOut'],
      subType: 'excelOut',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.blank'],
      subType: 'blank',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.newpage.inner'],
      subType: 'innerpage',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.newpage.outer'],
      subType: 'outerpage',
      url: ''
    }
  ]
@@ -349,14 +302,6 @@
      url: ''
    }
  ]
  tabItems = [
    {
      type: 'tabs',
      label: CommonDict['header.menu.tab.subtable'],
      subType: 'SubTable',
    }
  ]
}
export default new CommonTableBaseData()
export default new SubTableBaseData()
src/templates/subtableconfig/tabdragelement/card.jsx
File was deleted
src/templates/subtableconfig/tabdragelement/index.jsx
File was deleted
src/templates/subtableconfig/tabdragelement/index.scss
File was deleted
src/templates/subtableconfig/tabform/index.jsx
File was deleted
src/templates/subtableconfig/tabform/index.scss
File was deleted