king
2020-11-06 00de865d827da6687928b10f031482628a5144c8
2020-11-06
28个文件已修改
7个文件已添加
1058 ■■■■ 已修改文件
src/menu/components/card/cardcellcomponent/dragaction/card.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/elementform/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/wrapsetting/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/wrapsetting/settingform/index.jsx 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/prop-card/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/cardcomponent/index.jsx 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/cardcomponent/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/cardcomponent/settingform/index.jsx 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/cardcomponent/settingform/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/index.jsx 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/index.scss 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.scss 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.jsx 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.scss 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/tabcomponents/card.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/tabcomponents/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/card.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modelsource/option.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/asyncButtonComponent.jsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.jsx 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.scss 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/tabtransfer/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/createinterface/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -38,7 +38,11 @@
  }
  const getContent = () => {
    if (card.eleType === 'text' || card.eleType === 'number') {
    if (card.eleType === 'sequence') {
      return (
        <div className={'ant-mk-text'}>1</div>
      )
    } else if (card.eleType === 'text' || card.eleType === 'number') {
      let val = `${card.prefix || ''}${card.datatype === 'static' ? (card.value || '') : (card.field || '')}${card.postfix || ''}`
      return (
        <div className={'ant-mk-text line' + card.height} style={{height: card.innerHeight || 21}}>{val}</div>
src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -9,6 +9,7 @@
import './index.scss'
const cardTypeOptions = {
  sequence: ['eleType', 'width'],
  text: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix'],
  number: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix'],
  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'url'],
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -10,7 +10,21 @@
 * @param {*} permFuncField  存储过程可用的开始字段
 * @param {*} type           按钮类型,用于区分可选的打开方式
 */
export function getCardCellForm (card) {
export function getCardCellForm (card, type) {
  let _options = [
    { value: 'text', text: '文本'},
    { value: 'number', text: '数值'},
    { value: 'picture', text: '图片'},
    { value: 'icon', text: '图标'},
    { value: 'link', text: '链接'},
    { value: 'slider', text: '进度条'},
    { value: 'splitline', text: '分割线'},
  ]
  if (type === 'table') {
    _options.push({value: 'sequence', text: '序号'})
  }
  let forms = [
    {
      type: 'select',
@@ -18,15 +32,7 @@
      label: '元素类型',
      initVal: card.eleType,
      required: true,
      options: [
        { value: 'text', text: '文本'},
        { value: 'number', text: '数值'},
        { value: 'picture', text: '图片'},
        { value: 'icon', text: '图标'},
        { value: 'link', text: '链接'},
        { value: 'slider', text: '进度条'},
        { value: 'splitline', text: '分割线'},
      ]
      options: _options
    },
    {
      type: 'select',
src/menu/components/card/cardcellcomponent/index.jsx
@@ -217,13 +217,15 @@
   * @description 元素编辑,获取元素表单信息
   */
  handleElement = (card) => {
    const { cards } = this.props
    if (card.eleType === 'button') {
      this.handleAction(card)
    } else {
      this.setState({
        visible: true,
        card: card,
        formlist: getCardCellForm(card)
        formlist: getCardCellForm(card, cards.type)
      })
    }
  }
src/menu/components/card/data-card/index.jsx
@@ -19,7 +19,7 @@
const { confirm } = Modal
class antvBarLineChart extends Component {
class DataCardEditComponent extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
@@ -186,13 +186,14 @@
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
      <div className="menu-data-card-edit-box" style={{...card.style, minHeight: card.wrap.minHeight}}>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <WrapComponent sysRoles={this.props.menu.sysRoles} config={card} updateConfig={this.updateComponent} />
            <WrapComponent sysRoles={menu ? menu.sysRoles : []} config={card} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            <SettingComponent config={card} updateConfig={this.updateComponent} />
@@ -217,4 +218,4 @@
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(antvBarLineChart)
export default connect(mapStateToProps, mapDispatchToProps)(DataCardEditComponent)
src/menu/components/card/data-card/wrapsetting/index.jsx
@@ -59,7 +59,7 @@
        <Icon type="edit" onClick={() => this.editDataSource()} />
        <Modal
          wrapClassName="popview-modal"
          title={'卡片设置'}
          title={config.type === 'table' ? '表格设置' : '卡片设置'}
          visible={visible}
          width={700}
          maskClosable={false}
src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
@@ -53,6 +53,13 @@
      <div className="model-menu-setting-form">
        <Form {...formItemLayout}>
          <Row gutter={24}>
            {config.subtype === 'tablecard' ? <Col span={12}>
              <Form.Item label="标题">
                {getFieldDecorator('title', {
                  initialValue: wrap.title || ''
                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col> : null}
            <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="用于组件间的区分。">
@@ -123,7 +130,7 @@
                )}
              </Form.Item>
            </Col> : null}
            <Col span={12}>
            {config.subtype !== 'tablecard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="选择卡片切换时,可向其他组件传递主键值。">
                  <Icon type="question-circle" />
@@ -139,8 +146,8 @@
                  </Radio.Group>
                )}
              </Form.Item>
            </Col>
            <Col span={12}>
            </Col> : null}
            {config.subtype !== 'tablecard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="卡片外边框的最小高度,控制数据加载时组件的占位。">
                  <Icon type="question-circle" />
@@ -151,7 +158,19 @@
                  initialValue: wrap.minHeight || 100
                })(<InputNumber min={20} max={2000} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
            </Col> : null}
            {config.subtype === 'tablecard' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="表格高度,超出时滚动,高度为空时根据内容自适应。">
                  <Icon type="question-circle" />
                  高度
                </Tooltip>
              }>
                {getFieldDecorator('height', {
                  initialValue: wrap.height
                })(<InputNumber min={100} max={2000} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col> : null}
            <Col span={12}>
              <Form.Item label="黑名单">
                {getFieldDecorator('blacklist', {
src/menu/components/card/prop-card/index.jsx
@@ -19,7 +19,7 @@
const { confirm } = Modal
class antvBarLineChart extends Component {
class PropCardEditComponent extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
@@ -221,6 +221,7 @@
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
@@ -228,7 +229,7 @@
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加卡片" onClick={this.addCard} type="plus" />
            <WrapComponent config={card} sysRoles={this.props.menu.sysRoles} updateConfig={this.updateComponent} />
            <WrapComponent config={card} sysRoles={menu ? menu.sysRoles : []} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
@@ -252,4 +253,4 @@
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(antvBarLineChart)
export default connect(mapStateToProps, mapDispatchToProps)(PropCardEditComponent)
src/menu/components/card/table-card/cardcomponent/index.jsx
New file
@@ -0,0 +1,208 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal, Popover, Icon } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import SettingForm from './settingform'
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const CardCellComponent = asyncComponent(() => import('../../cardcellcomponent'))
class CardBoxComponent extends Component {
  static propTpyes = {
    cards: PropTypes.object,         // 卡片行配置信息
    card: PropTypes.object,          // 卡片配置信息
    deleteElement: PropTypes.func,   // 卡片删除
    updateElement: PropTypes.func    // 菜单配置更新
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    card: null,            // 卡片信息,包括正反面
    formlist: null,        // 设置表单信息
    elements: null,        // 编辑组
    visible: false,        // 模态框控制
    settingVisible: false,
  }
  /**
   * @description 搜索条件初始化
   */
  UNSAFE_componentWillMount () {
    const { card } = this.props
    this.setState({
      card: fromJS(card).toJS(),
      elements: fromJS(card.elements).toJS(),
    })
  }
  componentDidMount () {
    MKEmitter.addListener('submitStyle', this.getStyle)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props.cards), fromJS(nextProps.cards)) || !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('submitStyle', this.getStyle)
  }
  getStyle = (comIds, style) => {
    const { cards } = this.props
    const { card } = this.state
    if (comIds.length !== 2 || comIds[0] !== cards.uuid || comIds[1] !== card.uuid) return
    let _card = fromJS(card).toJS()
    _card.style = style
    this.setState({
      card: _card
    })
    this.props.updateElement(_card)
  }
  updateCard = (elements) => {
    const { card } = this.state
    let _card = {...card, elements: elements}
    this.setState({
      card: _card
    })
    this.props.updateElement(_card)
  }
  addElement = () => {
    const { cards } = this.props
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.eleType = 'text'
    newcard.datatype = 'dynamic'
    newcard.color = 'rgba(0,0,0,0.85)'
    newcard.padding = '5px'
    newcard.align = 'left'
    // 注册事件-添加元素
    MKEmitter.emit('cardAddElement', [cards.uuid, card.uuid], newcard)
  }
  addButton = () => {
    const { cards } = this.props
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.eleType = 'button'
    newcard.label = 'button'
    newcard.sqlType = ''
    newcard.Ot = 'requiredSgl'
    newcard.OpenType = 'prompt'
    newcard.icon = ''
    newcard.class = 'primary'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.popClose = 'never'
    newcard.errorTime = 10
    newcard.verify = null
    newcard.show = 'link'
    // 注册事件-添加元素
    MKEmitter.emit('cardAddElement', [cards.uuid, card.uuid], newcard)
  }
  changeStyle = () => {
    const { cards } = this.props
    const { card } = this.state
    let _style = null
    let options = ['height', 'background', 'border', 'padding', 'margin']
    _style = card.style ? fromJS(card.style).toJS() : {}
    MKEmitter.emit('changeStyle', [cards.uuid, card.uuid], options, _style)
  }
  settingSubmit = () => {
    const { card } = this.state
    this.settingRef.handleConfirm().then(res => {
      this.setState({
        settingVisible: false,
        card: {...card, setting: res}
      })
      this.props.updateElement({...card, setting: res})
    })
  }
  render() {
    const { cards } = this.props
    const { card, elements, settingVisible, dict } = this.state
    return (
      <div className="ant-col ant-col-24">
        <div className="card-item" style={card.style}>
          <CardCellComponent cards={cards} cardCell={card} elements={elements} updateElement={this.updateCard}/>
          <div className="card-control">
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <Icon className="plus" title="添加元素" onClick={this.addElement} type="plus" />
                <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
                <Icon className="edit" type="edit" onClick={() => this.setState({settingVisible: true})} />
                <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
                <Icon className="close" title="删除卡片" type="delete" onClick={() => this.props.deleteElement(card)} />
              </div>
            } trigger="hover">
              <Icon type="tool" />
            </Popover>
          </div>
        </div>
        <Modal
          wrapClassName="popview-modal"
          title={'行设置'}
          visible={settingVisible}
          width={700}
          maskClosable={false}
          okText={dict['model.submit']}
          onOk={this.settingSubmit}
          onCancel={() => { this.setState({ settingVisible: false }) }}
          destroyOnClose
        >
          <SettingForm
            dict={dict}
            cards={cards}
            setting={card.setting}
            inputSubmit={this.settingSubmit}
            wrappedComponentRef={(inst) => this.settingRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default CardBoxComponent
src/menu/components/card/table-card/cardcomponent/index.scss
src/menu/components/card/table-card/cardcomponent/settingform/index.jsx
New file
@@ -0,0 +1,131 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Radio, Tooltip, Icon, Input, Select } from 'antd'
import './index.scss'
class SettingForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,      // 字典项
    cards: PropTypes.object,     // 卡片集
    setting: PropTypes.object,   // 数据源配置
    inputSubmit: PropTypes.func  // 回车事件
  }
  state = {
    condition: this.props.setting.condition || 'false'
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  render() {
    const { setting, cards } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <div className="model-menu-setting-form">
        <Form {...formItemLayout}>
          <Row gutter={24}>
            <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="当选择“有”时,只有符合条件的数据才会展示。">
                  <Icon type="question-circle" />
                  显示条件
                </Tooltip>
              }>
                {getFieldDecorator('condition', {
                  initialValue: setting.condition || 'false'
                })(
                  <Radio.Group onChange={(e) => this.setState({ condition: e.target.value })}>
                    <Radio value="true">有</Radio>
                    <Radio value="false">无</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col>
            {this.state.condition === 'true' ? <Col span={12}>
              <Form.Item label="控制字段">
                {getFieldDecorator('controlField', {
                  initialValue: setting.controlField || '',
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.select'] + '控制字段!'
                    }
                  ]
                })(
                  <Select>
                    {cards.columns.map((option, index) =>
                      <Select.Option key={index} value={option.field}>
                        {option.label}
                      </Select.Option>
                    )}
                  </Select>
                )}
              </Form.Item>
            </Col> : null}
            {this.state.condition === 'true' ? <Col span={12}>
              <Form.Item label="对比方式">
                {getFieldDecorator('controlType', {
                  initialValue: setting.controlType || '=',
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.select'] + '对比方式!'
                    }
                  ]
                })(
                  <Radio.Group>
                    <Radio value="=">=</Radio>
                    <Radio value="!=">!=</Radio>
                    <Radio value=">">&gt;</Radio>
                    <Radio value="<">&lt;</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {this.state.condition === 'true' ? <Col span={12}>
              <Form.Item label="对比值">
                {getFieldDecorator('controlValue', {
                  initialValue: setting.controlValue || ''
                })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit}/>)}
              </Form.Item>
            </Col> : null}
          </Row>
        </Form>
      </div>
    )
  }
}
export default Form.create()(SettingForm)
src/menu/components/card/table-card/cardcomponent/settingform/index.scss
New file
@@ -0,0 +1,11 @@
.model-menu-setting-form {
  position: relative;
  .anticon-question-circle {
    color: #c49f47;
    margin-right: 3px;
  }
  .ant-input-number {
    width: 100%;
  }
}
src/menu/components/card/table-card/index.jsx
@@ -15,11 +15,12 @@
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('../data-card/wrapsetting'))
const CardComponent = asyncComponent(() => import('../cardcomponent'))
const SearchComponent = asyncComponent(() => import('@/menu/searchcomponent'))
const CardComponent = asyncComponent(() => import('./cardcomponent'))
const { confirm } = Modal
class antvBarLineChart extends Component {
class TableCardEditComponent extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
@@ -53,9 +54,7 @@
          uuid: Utils.getuuid(),
          setting: { width: 24, type: 'simple'},
          style: {
            borderWidth: '1px', borderColor: '#e8e8e8',
            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
            paddingTop: '5px', paddingBottom: '5px', paddingLeft: '15px', paddingRight: '15px',
          },
          elements: []
        }]
@@ -72,15 +71,18 @@
        switchable: false,  // 组件属性 - 数据是否可切换
        dataName: card.dataName || '',
        width: 12,
        search: [],
        name: card.name,
        subtype: card.subtype,
        setting: { interType: 'system' },
        wrap: { name: card.name, width: 12, addable: 'false', switch: 'false', datatype: 'dynamic' },
        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
        wrap: { name: card.name, width: 12 },
        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
        headerStyle: { fontSize: '16px' },
        columns: [],
        scripts: [],
        subcards: subcards
      }
      this.setState({
        card: _card
      })
@@ -165,12 +167,25 @@
    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
  }
  changeTitleStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', [card.uuid, 'header'], ['font', 'border'], card.headerStyle)
  }
  getStyle = (comIds, style) => {
    const { card } = this.state
    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
    if (comIds[0] !== card.uuid) return
    let _card = {...card, style}
    let _card = {}
    if (comIds.length === 1) {
      _card = {...card, style}
    } else if (comIds.length === 2 && comIds[1] === 'header') {
      _card = {...card, headerStyle: style}
    } else {
      return
    }
    this.setState({
      card: _card
@@ -186,9 +201,7 @@
      uuid: Utils.getuuid(),
      setting: { width: 6, type: 'simple'},
      style: {
        borderWidth: '1px', borderColor: '#e8e8e8',
        paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
        marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
        paddingTop: '5px', paddingBottom: '5px', paddingLeft: '15px', paddingRight: '15px',
      },
      elements: []
    }
@@ -208,15 +221,48 @@
    this.props.updateConfig(card)
  }
  addSearch = () => {
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.label = 'label'
    newcard.initval = ''
    newcard.type = 'select'
    newcard.resourceType = '0'
    newcard.options = []
    newcard.setAll = 'false'
    newcard.orderType = 'asc'
    newcard.display = 'dropdown'
    newcard.match = '='
    // 注册事件-添加搜索
    MKEmitter.emit('addSearch', card.uuid, newcard)
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
      <div className="menu-prop-card-edit-box" style={{...card.style, minHeight: card.wrap.minHeight}}>
      <div className="menu-table-card-edit-box" style={{...card.style, height: card.wrap.height}}>
        <div className="table-header" style={card.headerStyle}>
          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
              <Icon className="style" title="调整样式" onClick={this.changeTitleStyle} type="font-colors" />
            </div>
          } trigger="hover">
            <span className="table-title">{card.wrap.title || ''}</span>
          </Popover>
          <SearchComponent config={card} updatesearch={this.updateComponent}/>
        </div>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加卡片" onClick={this.addCard} type="plus" />
            <WrapComponent config={card} sysRoles={this.props.menu.sysRoles} updateConfig={this.updateComponent} />
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <WrapComponent config={card} sysRoles={menu ? menu.sysRoles : []} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
@@ -240,4 +286,4 @@
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(antvBarLineChart)
export default connect(mapStateToProps, mapDispatchToProps)(TableCardEditComponent)
src/menu/components/card/table-card/index.scss
@@ -1,4 +1,4 @@
.menu-prop-card-edit-box {
.menu-table-card-edit-box {
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
@@ -7,6 +7,23 @@
  background-size: cover;
  min-height: 100px;
  
  .table-header {
    position: relative;
    height: 45px;
    overflow: hidden;
    padding-right: 35px;
    .table-title {
      text-decoration: inherit;
      font-weight: inherit;
      font-style: inherit;
      float: left;
      line-height: 45px;
      margin-left: 10px;
      position: relative;
      z-index: 1;
    }
  }
  .card-control {
    position: absolute;
    top: 0px;
@@ -65,11 +82,11 @@
    }
  }
}
.menu-prop-card-edit-box::after {
.menu-table-card-edit-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.menu-prop-card-edit-box:hover {
.menu-table-card-edit-box:hover {
  box-shadow: 0px 0px 2px #e8e8e8;
}
src/menu/components/chart/antv-bar/index.jsx
@@ -731,6 +731,7 @@
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
@@ -743,23 +744,20 @@
          } trigger="hover">
            <span className="chart-title">{card.plot.title || ''}</span>
          </Popover>
          <SearchComponent
            config={card}
            updatesearch={this.updateComponent}
          />
          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
              <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
              <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
              <ChartCompileForm config={card} sysRoles={this.props.menu.sysRoles} dict={this.state.dict} plotchange={this.updateComponent}/>
              <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
              <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
              <SettingComponent config={card} updateConfig={this.updateComponent}/>
            </div>
          } trigger="hover">
            <Icon type="tool" />
          </Popover>
          <SearchComponent config={card} updatesearch={this.updateComponent}/>
        </div>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <ChartCompileForm config={card} sysRoles={menu ? menu.sysRoles : []} dict={this.state.dict} plotchange={this.updateComponent}/>
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            <SettingComponent config={card} updateConfig={this.updateComponent}/>
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <ActionComponent
          type="chart"
          plus="false"
src/menu/components/chart/antv-bar/index.scss
@@ -20,18 +20,6 @@
    overflow: hidden;
    padding-right: 35px;
    >.anticon-tool {
      position: absolute;
      right: 1px;
      top: 1px;
      z-index: 1;
      font-size: 16px;
      padding: 5px;
      cursor: pointer;
      color: rgba(0, 0, 0, 0.85);
      background: rgba(255, 255, 255, 0.55);
    }
    .chart-title {
      text-decoration: inherit;
      font-weight: inherit;
@@ -44,6 +32,18 @@
    }
  }
  >.anticon-tool {
    position: absolute;
    right: 1px;
    top: 1px;
    z-index: 1;
    font-size: 16px;
    padding: 5px;
    cursor: pointer;
    color: rgba(0, 0, 0, 0.85);
    background: rgba(255, 255, 255, 0.55);
  }
  .model-menu-action-list {
    position: absolute;
    right: 0px;
src/menu/components/chart/antv-pie/index.jsx
@@ -408,6 +408,7 @@
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
@@ -420,22 +421,19 @@
          } trigger="hover">
            <span className="chart-title">{card.plot.title || ''}</span>
          </Popover>
          <SearchComponent
            config={card}
            updatesearch={this.updateComponent}
          />
          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
              <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
              <ChartCompileForm config={card} sysRoles={this.props.menu.sysRoles} dict={this.state.dict} plotchange={this.updateComponent}/>
              <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
              <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
              <SettingComponent config={card} updateConfig={this.updateComponent}/>
            </div>
          } trigger="hover">
            <Icon type="tool" />
          </Popover>
          <SearchComponent config={card} updatesearch={this.updateComponent}/>
        </div>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <ChartCompileForm config={card} sysRoles={menu ? menu.sysRoles : []} dict={this.state.dict} plotchange={this.updateComponent}/>
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            <SettingComponent config={card} updateConfig={this.updateComponent}/>
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <div className="canvas" id={card.uuid}></div>
      </div>
    )
src/menu/components/chart/antv-pie/index.scss
@@ -19,18 +19,6 @@
    overflow: hidden;
    padding-right: 35px;
    >.anticon-tool {
      position: absolute;
      right: 1px;
      top: 1px;
      z-index: 1;
      font-size: 16px;
      padding: 5px;
      cursor: pointer;
      color: rgba(0, 0, 0, 0.85);
      background: rgba(255, 255, 255, 0.55);
    }
    .chart-title {
      text-decoration: inherit;
      font-weight: inherit;
@@ -43,6 +31,18 @@
    }
  }
  >.anticon-tool {
    position: absolute;
    right: 1px;
    top: 1px;
    z-index: 1;
    font-size: 16px;
    padding: 5px;
    cursor: pointer;
    color: rgba(0, 0, 0, 0.85);
    background: rgba(255, 255, 255, 0.55);
  }
  .model-menu-action-list {
    position: absolute;
    right: 0px;
src/menu/components/search/main-search/index.jsx
@@ -339,6 +339,7 @@
  }
  render() {
    const { menu } = this.props
    const { dict, card, visible, sqlVerifing } = this.state
    return (
@@ -353,7 +354,7 @@
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加" onClick={this.addSearch} type="plus" />
            <WrapComponent config={card} sysRoles={this.props.menu.sysRoles} updateConfig={this.updateComponent}/>
            <WrapComponent config={card} sysRoles={menu ? menu.sysRoles : []} updateConfig={this.updateComponent}/>
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
          </div>
src/menu/components/tabs/antv-tabs/index.jsx
@@ -227,6 +227,7 @@
  }
  render() {
    const { menu } = this.props
    const { tabs, dict, labelvisible, editab } = this.state
    return (
@@ -252,7 +253,7 @@
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <Icon className="plus" title="添加标签" type="plus" onClick={this.tabAdd} />
                <SettingComponent config={tabs} sysRoles={this.props.menu.sysRoles} updateConfig={this.updateComponent} />
                <SettingComponent config={tabs} sysRoles={menu ? menu.sysRoles : []} updateConfig={this.updateComponent} />
                <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
                <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(tabs.uuid)} />
              </div>
src/menu/components/tabs/tabcomponents/card.jsx
@@ -58,7 +58,7 @@
      return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />)
    } else if (card.type === 'card' && card.subtype === 'propcard') {
      return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'card' && card.subtype === 'tablecard') {
    } else if (card.type === 'table' && card.subtype === 'tablecard') {
      return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
src/menu/components/tabs/tabcomponents/index.jsx
@@ -89,6 +89,7 @@
        tabs: '标签组',
        pie: '饼图',
        search: '搜索',
        table: '表格',
        card: '卡片'
      }
      let i = 1
src/menu/datasource/verifycard/settingform/index.jsx
@@ -406,7 +406,7 @@
                )}
              </Form.Item>
            </Col> : null}
            {config.pageable ? <Col span={8}>
            {config.pageable && laypage !== 'false' ? <Col span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="选择分页时有效。">
                  <Icon type="question-circle" />
src/menu/menushell/card.jsx
@@ -54,11 +54,10 @@
      return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'card' && card.subtype === 'propcard') {
      return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'card' && card.subtype === 'tablecard') {
    } else if (card.type === 'table' && card.subtype === 'tablecard') {
      return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
  return (
    <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}>
      {getCardComponent()}
src/menu/menushell/index.jsx
@@ -81,6 +81,7 @@
        tabs: '标签组',
        pie: '饼图',
        search: '搜索',
        table: '表格',
        card: '卡片'
      }
      let i = 1
src/menu/modelsource/option.jsx
@@ -21,7 +21,7 @@
  { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '搜索条件', width: 24 },
  { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '数据卡', config: `[{"uuid":"160135809128212dm7i29fim9ksto9od","setting":{"width":6},"style":{"paddingTop":"15px","marginTop":"4px","paddingRight":"15px","marginRight":"8px","marginLeft":"8px","backgroundColor":"rgba(255, 255, 255, 1)","borderColor":"#e8e8e8","paddingLeft":"15px","marginBottom":"4px","borderWidth":"1px","paddingBottom":"10px"},"backStyle":{},"elements":[{"datatype":"static","width":12,"marks":null,"height":1,"value":"关单","style":{},"prefix":"","postfix":"","format":"","eleType":"text","uuid":"160231860159931untbea62sgokunc5s"},{"datatype":"dynamic","width":12,"marks":null,"style":{"color":"rgba(250, 219, 20, 1)","textAlign":"right"},"btnstyle":{},"eleType":"icon","icon":"question-circle","field":"nvarchar2","uuid":"1602318768361nv8ql4t47sgcsn88b0u"},{"datatype":"static","width":24,"marks":null,"height":1,"innerHeight":36,"value":"100","style":{"fontSize":"24px","fontWeight":"500","color":"rgba(0, 0, 0, 1)"},"prefix":"","btnstyle":{},"postfix":"","format":"","eleType":"text","uuid":"1602318817884v70gtgb65ubnm8mbcvv"},{"color":"#1890ff","width":24,"marks":null,"maxValue":100,"style":{"color":"rgba(250, 140, 22, 1)","paddingTop":"20px","paddingBottom":"10px"},"btnstyle":{},"eleType":"slider","field":"int1","uuid":"16023188871233rkktuvpp1h077igrsu"},{"eleType":"splitline","width":24,"color":"#e8e8e8","uuid":"1602320017038n31bk9o831ggug0tu0b","marks":null,"style":{"marginTop":"10px","marginBottom":"10px"},"btnstyle":{}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"marginTop":"6px"},"prefix":"关单","btnstyle":{},"postfix":"","format":"","eleType":"text","uuid":"1602320061243drd7lf3agvn04kgr175"}],"backElements":[]}]` },
  { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '属性卡', config: `[{"uuid":"1603681387259qaqf1127f72esmtchge","setting":{"width":6,"type":"simple"},"style":{"paddingTop":"15px","marginTop":"8px","paddingRight":"15px","marginRight":"8px","marginLeft":"8px","borderColor":"#e8e8e8","paddingLeft":"15px","marginBottom":"8px","borderWidth":"1px","paddingBottom":"15px"},"backStyle":{},"elements":[{"datatype":"static","width":12,"marks":null,"height":1,"value":"超时工单","style":{"color":"rgba(67, 67, 67, 0.51)"},"prefix":"","postfix":"","format":"","eleType":"text","uuid":"1603681402945qnkgm7q8cng65evn5ev"},{"eleType":"icon","datatype":"static","width":12,"icon":"question-circle","tooltip":"超时工单","uuid":"1603681473384i2crkbtofg4pu76k06a","marks":null,"style":{"textAlign":"right","color":"rgba(250, 219, 20, 1)"}},{"datatype":"static","width":24,"marks":null,"height":1,"innerHeight":36,"value":"100","style":{"fontSize":"24px","color":"rgba(0, 0, 0, 1)"},"prefix":"","postfix":"","format":"","eleType":"number","uuid":"1603681539870d704ufqf98kc6t7537t"},{"color":"rgba(250, 219, 20, 1)","datatype":"static","width":24,"marks":null,"maxValue":100,"value":50,"style":{"paddingTop":"10px","paddingBottom":"10px"},"eleType":"slider","uuid":"1603683067556mvupau0odvrtv45u7o8"},{"eleType":"splitline","width":24,"color":"#e8e8e8","uuid":"1603683117981t9k55k8an430fuppmci","marks":null,"style":{"paddingTop":"5px","paddingBottom":"5px"}},{"datatype":"static","width":12,"marks":null,"height":1,"value":"100","style":{"color":"rgba(0, 0, 0, 0.65)","marginTop":"10px"},"prefix":"超时工单  ","postfix":"","format":"","eleType":"text","uuid":"1603683136553uvsmkfohkft9idbfkhu"}],"backElements":[]}]` },
  { type: 'menu', url: TableCard, component: 'card', subtype: 'tablecard', title: '表格' },
  { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '表格', width: 12 },
  { type: 'menu', url: line, component: 'line', subtype: 'line', title: '折线图' },
  { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '阶梯折线图' },
  { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '柱状图' },
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -21,6 +21,7 @@
class CardCellComponent extends Component {
  static propTpyes = {
    BID: PropTypes.any,              // 上级ID
    seq: PropTypes.any,              // 序号
    cards: PropTypes.object,         // 菜单配置信息
    cardCell: PropTypes.object,
    data: PropTypes.object,
@@ -89,9 +90,17 @@
  }
  getContent = (card) => {
    const { data, BID, cards } = this.props
    const { data, BID, cards, seq } = this.props
    if (card.eleType === 'text') {
    if (card.eleType === 'sequence') {
      return (
        <Col key={card.uuid} span={card.width}>
          <div style={card.style}>
            <div className={'ant-mk-text'}>{seq}</div>
          </div>
        </Col>
      )
    } else if (card.eleType === 'text') {
      let val = ''
      if (card.datatype === 'static') {
src/tabviews/custom/components/card/table-card/asyncButtonComponent.jsx
New file
@@ -0,0 +1,34 @@
import React, {Component} from 'react'
import { Button } from 'antd'
/**
 * @description 异步加载模块
 * @param {*} importComponent
 */
export default function asyncComponent(importComponent) {
  return class extends Component {
    constructor(props) {
      super(props)
      this.state = {
        component: null
      }
    }
    async componentDidMount() {
      const {default: component} = await importComponent()
      this.setState({component})
    }
    // <Button className="loading-skeleton" disabled={true}></Button> // 骨架按钮
    render() {
      const C = this.state.component
      const btn = this.props.btn || {}
      return C ?
        <C {...this.props} /> :
        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
    }
  }
}
src/tabviews/custom/components/card/table-card/index.jsx
New file
@@ -0,0 +1,245 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Spin, notification, Col, Empty } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import Api from '@/api'
import UtilsDM from '@/utils/utils-datamanage.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const CardCellComponent = asyncComponent(() => import('../cardcellList'))
class TableCard extends Component {
  static propTpyes = {
    BID: PropTypes.any,              // 父级Id
    data: PropTypes.array,           // 统一查询数据
    config: PropTypes.object,        // 组件配置信息
    mainSearch: PropTypes.any,       // 外层搜索条件
    menuType: PropTypes.any,         // 菜单类型
    dataManager: PropTypes.any,      // 数据权限
  }
  state = {
    config: null,              // 图表配置信息
    loading: false,            // 数据加载状态
    sync: false,               // 是否统一请求数据
    data: null,                // 数据
    title: '',                 // 标题
    showHeader: false          // 存在标题、搜索
  }
  UNSAFE_componentWillMount () {
    const { data } = this.props
    let _config = fromJS(this.props.config).toJS()
    let _cols = new Map()
    let _data = null
    let _sync = _config.setting.sync === 'true'
    if (_config.setting.sync === 'true' && data) {
      _data = data[_config.dataName] || []
      _sync = false
    }
    let showHeader = false
    if (_config.wrap.title || _config.search.length > 0) {
      showHeader = true
    }
    _config.columns.forEach(item => {
      _cols.set(item.field, item)
    })
    _config.subcards.forEach(card => {
      card.elements = card.elements.map(item => {
        if (item.field && _cols.has(item.field)) {
          item.col = _cols.get(item.field)
        }
        return item
      })
    })
    this.setState({
      showHeader: showHeader,
      title: _config.wrap.title,
      sync: _sync,
      data: _data,
      config: _config,
      arr_field: _config.columns.map(col => col.field).join(','),
    }, () => {
      if (_config.setting.sync !== 'true' && _config.setting.onload === 'true') {
        this.loadData()
      } else if (_sync && !_data) {
        this.setState({
          loading: true
        })
      }
    })
  }
  componentDidMount () {
    MKEmitter.addListener('syncRefreshComponentId', this.reload)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('syncRefreshComponentId', this.reload)
  }
  /**
   * @description 图表数据更新,刷新内容
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
    const { sync, config } = this.state
    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _data = []
      if (nextProps.data && nextProps.data[config.dataName]) {
        _data = nextProps.data[config.dataName] || []
      }
      this.setState({sync: false, loading: false, data: _data})
    } else if (!is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      if (config.setting.syncRefresh === 'true') {
        this.setState({}, () => {
          this.loadData()
        })
      }
    }
  }
  reload = (syncId) => {
    const { config } = this.state
    if (syncId && syncId !== config.uuid) return
    this.loadData()
  }
  async loadData () {
    const { mainSearch, BID, menuType, dataManager } = this.props
    const { config, arr_field } = this.state
    let searches = []
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      let keys = searches.map(item => item.key)
      mainSearch.forEach(item => {
        if (!keys.includes(item.key)) {
          searches.push(item)
        }
      })
    }
    this.setState({
      loading: true
    })
    let _orderBy = config.setting.order || ''
    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, 1, 1, BID, menuType, dataManager)
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data,
        loading: false
      })
    } else {
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 10
      })
    }
  }
  updateStatus = (type, position, btn) => {
    const { config } = this.state
    if (type === 'refresh' && position === 'grid') {
      this.loadData()
      if (btn && btn.syncComponent && btn.syncComponent[0]) {
        let syncId = btn.syncComponent[btn.syncComponent.length - 1]
        if (config.uuid !== syncId) {
          MKEmitter.emit('syncRefreshComponentId', syncId)
        }
      }
    }
  }
  getLines = (data, seq) => {
    const { BID } = this.props
    const { config } = this.state
    let line = []
    config.subcards.forEach((item, index) => {
      let display = item.setting.condition !== 'true'
      if (!display && item.setting.controlField) {
        let val = data[item.setting.controlField]
        if (val || val === 0) {
          val = `${val}`
        }
        if (item.setting.controlType === '=' && val === item.setting.controlValue) {
          display = true
        } else if (item.setting.controlType === '!=' && val !== item.setting.controlValue) {
          display = true
        } else if (item.setting.controlType === '>' && val > item.setting.controlValue) {
          display = true
        } else if (item.setting.controlType === '<' && val < item.setting.controlValue) {
          display = true
        }
      }
      if (!display) return
      line.push(
        <Col key={index} span={24}>
          <div className="card-item-box" style={item.style}>
            <CardCellComponent BID={BID} seq={seq} data={data} cards={config} cardCell={item} elements={item.elements} updateStatus={this.updateStatus}/>
          </div>
        </Col>
      )
    })
    return line
  }
  render() {
    const { config, loading, data, title, showHeader } = this.state
    return (
      <div className="custom-table-card-box" style={{...config.style, height: config.wrap.height}}>
        {loading ?
          <div className="loading-mask">
            <div className="ant-spin-blur"></div>
            <Spin />
          </div> : null
        }
        {showHeader ? <div className="table-header" style={config.headerStyle}>
          <span className="table-title">{title}</span>
          {/* <searchLine /> */}
        </div> : null}
        {data && data.length > 0 ? <div className="card-row-list" style={{height: config.wrap.height - (showHeader ? 45 : 0)}}>
          {data.map((item, index) => this.getLines(item, index + 1))}
        </div> : null}
        {data && data.length === 0 ? <Empty description={false}/> : null}
      </div>
    )
  }
}
export default TableCard
src/tabviews/custom/components/card/table-card/index.scss
New file
@@ -0,0 +1,89 @@
.custom-table-card-box {
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 100px;
  position: relative;
  overflow-y: hidden;
  > .table-header {
    height: 45px;
    // border-bottom: 1px solid #e8e8e8;
    overflow: hidden;
    .table-title {
      // font-size: 16px;
      float: left;
      line-height: 45px;
      margin-left: 10px;
      text-decoration: inherit;
      font-weight: inherit;
      font-style: inherit;
    }
  }
  .card-row-list::after {
    content: ' ';
    display: block;
    clear: both;
  }
  .card-row-list {
    overflow-y: auto;
    .card-item-box {
      transition: all 0.3s;
    }
    >.active >.card-item-box {
      border-color: #1890ff!important;
      box-shadow: 0 0 3px #1890ff;
    }
  }
  .card-row-list::-webkit-scrollbar {
    width: 7px;
  }
  .card-row-list::-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);
  }
  .card-row-list::-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);
  }
  .card-item-box {
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
  }
  .loading-mask {
    position: absolute;
    left: 40px;
    top: 0;
    right: 40px;
    bottom: 0px;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: justify;
    z-index: 1;
    .ant-spin-blur {
      position: absolute;
      width: 100%;
      height: 100%;
      opacity: 0.5;
      background: #ffffff;
    }
  }
}
.custom-card-box::after {
  content: ' ';
  display: block;
  clear: both;
}
src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -17,6 +17,7 @@
const AntvPie = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-pie'))
const AntvTabs = asyncComponent(() => import('@/tabviews/custom/components/tabs/antv-tabs'))
const DataCard = asyncComponent(() => import('@/tabviews/custom/components/card/data-card'))
const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
class TabTransfer extends Component {
@@ -270,6 +271,12 @@
            <PropCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'table' && item.subtype === 'tablecard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <TableCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else {
        return null
      }
src/tabviews/custom/index.jsx
@@ -22,6 +22,7 @@
const AntvTabs = asyncComponent(() => import('./components/tabs/antv-tabs'))
const DataCard = asyncComponent(() => import('./components/card/data-card'))
const PropCard = asyncComponent(() => import('./components/card/prop-card'))
const TableCard = asyncComponent(() => import('./components/card/table-card'))
const MainSearch = asyncComponent(() => import('./components/search/main-search'))
class CustomPage extends Component {
@@ -496,6 +497,12 @@
            <PropCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'table' && item.subtype === 'tablecard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <TableCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else {
        return null
      }
src/templates/sharecomponent/settingcomponent/index.jsx
@@ -37,7 +37,7 @@
   */
  changeSetting = () => {
    const { MenuID, config, mainsearch } = this.props
    let menu = { MenuID: MenuID, MenuName: config.MenuName, MenuNo: config.MenuNo }
    let menu = { MenuID: MenuID, MenuName: config.MenuName || config.tabName || '', MenuNo: config.MenuNo || config.tabNo || '' }
    let _search = fromJS(config.search).toJS()
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
@@ -87,7 +87,7 @@
    } else {
      sql = _dataresource
    }
    return sql
  }
}
src/templates/zshare/createinterface/index.jsx
@@ -276,12 +276,7 @@
    }).then(res => {
      if (res === false) return res
      if (window.GLOB.mainSystemApi) {
        _mainParam.rduri = window.GLOB.mainSystemApi
        return Api.getLocalConfig(_mainParam)
      }
      return 'success'
      return Api.getCloudConfig(_mainParam)
    }).then(result => {
      if (result === false || result === 'success') return result