king
2020-11-26 89fb1308d92e10a27cf8f91f4dd766eb38976e12
2020-11-26
31个文件已修改
15个文件已添加
2899 ■■■■■ 已修改文件
src/locales/en-US/model.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/model.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/actionform/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/dragaction/index.jsx 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/cardcomponent/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/cardcomponent/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/colspanform/index.jsx 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/colspanform/index.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/columnform/index.jsx 336 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/columnform/index.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/dragcolumn/card.jsx 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/dragcolumn/index.jsx 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/dragcolumn/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/gridbtnform/index.jsx 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/gridbtnform/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/index.jsx 509 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/index.scss 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/markcolumn/index.jsx 242 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/markcolumn/index.scss 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/markcolumn/markform/index.jsx 384 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columncomponent/markcolumn/markform/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/index.jsx 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/index.scss 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-pie/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/tabtransfer/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/source.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/dragelement/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/dragaction/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/source.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/menuform/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/model.js
@@ -198,7 +198,6 @@
  'header.form.topPicBottomText': '上图下文',
  'header.form.leftPicRightText': '左图右文',
  'model.form.selectItem.error': '下拉选项设置错误!',
  'header.form.request.method': '请求方式',
  'header.form.readonly': '只读',
  'header.form.queryType': '查询类型',
  'header.form.query': '查询',
src/locales/zh-CN/model.js
@@ -198,7 +198,6 @@
  'header.form.topPicBottomText': '上图下文',
  'header.form.leftPicRightText': '左图右文',
  'model.form.selectItem.error': '下拉选项设置错误!',
  'header.form.request.method': '请求方式',
  'header.form.readonly': '只读',
  'header.form.queryType': '查询类型',
  'header.form.query': '查询',
src/menu/actioncomponent/actionform/index.jsx
@@ -48,9 +48,6 @@
      text: this.props.dict['header.form.requiredOnce']
    }],
    insertUpdateOptions: [{
      value: '',
      text: this.props.dict['model.empty']
    }, {
      value: 'insert',
      text: this.props.dict['header.form.action.insert']
    }, {
@@ -153,7 +150,7 @@
          _options.push('execMode', 'intertype', 'innerFunc', 'Ot', 'execSuccess', 'execError')
        }
      }
    } else if (_opentype === 'popview' && _opentype === 'tab') {
    } else if (_opentype !== 'popview' && _opentype !== 'tab') {
      if (_intertype === 'outer') {
        _options.push('innerFunc', 'sysInterface', 'interface', 'outerFunc', 'callbackFunc')
      } else if (_intertype === 'inner') {
@@ -598,9 +595,7 @@
              values.OpenType = values.execMode
            }
          } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) {
            if (values.Ot === 'requiredOnce' && ['notRequired', 'requiredSgl', 'required'].includes(this.props.card.Ot)) {
              values.verify.uniques = []
            } else if (this.props.card.Ot === 'requiredOnce' && ['notRequired', 'requiredSgl', 'required'].includes(values.Ot)) {
            if ((values.Ot === 'requiredOnce' || this.props.card.Ot === 'requiredOnce') && this.props.card.Ot !== values.Ot) {
              values.verify.uniques = []
            }
          }
src/menu/actioncomponent/dragaction/index.jsx
@@ -2,13 +2,12 @@
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Icon } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
import './index.scss'
const Container = ({plus, list, handleList, handleMenu, deleteMenu, profileMenu, doubleClickCard }) => {
const Container = ({list, handleList, handleMenu, deleteMenu, profileMenu, doubleClickCard }) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
@@ -90,38 +89,6 @@
    drop() {}
  })
  const addaction = () => {
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    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 = 'icon'
    let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0
    const { index: overIndex } = findCard(`${targetId}`)
    let targetIndex = overIndex
    targetIndex++
    const _cards = update(cards, { $splice: [[targetIndex, 0, newcard]] })
    handleList(_cards, newcard)
  }
  return (
    <div ref={drop} className="ant-row">
      {cards.map(card => (
@@ -138,7 +105,6 @@
          doubleClickCard={doubleClickBtn}
        />
      ))}
      {plus !== 'false' ? <Icon type="plus" title="添加按钮" onClick={addaction}/> : null}
    </div>
  )
}
src/menu/actioncomponent/index.jsx
@@ -25,7 +25,6 @@
class ActionComponent extends Component {
  static propTpyes = {
    type: PropTypes.string,          // 菜单类型,主表或子表
    plus: PropTypes.any,             // 是否存在添加按钮,值为false时隐藏
    config: PropTypes.object,        // 菜单配置信息
    setSubConfig: PropTypes.func,    // 设置子配置信息
    updateaction: PropTypes.func     // 菜单配置更新
@@ -177,7 +176,17 @@
      <p>{this.state.dict['model.tooltip.func.outface']}</p>
    </div>
    let menulist = menu.fstMenuList ? menu.fstMenuList : []
    let menulist = sessionStorage.getItem('fstMenuList')
    if (menulist) {
      try {
        menulist = JSON.parse(menulist)
      } catch {
        menulist = []
      }
    } else {
      menulist = []
    }
    let modules = this.getModules(menu.components, config.uuid)
    this.setState({
@@ -409,13 +418,12 @@
  }
  render() {
    const { config, plus } = this.props
    const { config } = this.props
    const { actionlist, visible, card, dict, profVisible } = this.state
    return (
      <div className="model-menu-action-list">
      <div className={'model-menu-action-list length' + actionlist.length}>
        <DragElement
          plus={plus}
          list={actionlist}
          handleList={this.handleList}
          handleMenu={this.handleAction}
src/menu/components/card/cardcellcomponent/index.jsx
@@ -261,28 +261,15 @@
      <p>{this.state.dict['model.tooltip.func.outface']}</p>
    </div>
    let menulist = []
    if (menu.fstMenuList) {
      let trees = fromJS(menu.fstMenuList).toJS()
      menulist = trees.map(fst => {
        fst.value = fst.MenuID
        fst.label = fst.MenuName
        fst.isLeaf = false
        fst.children = fst.children.map(snd => {
          snd.value = snd.MenuID
          snd.label = snd.MenuName
          snd.children = snd.children.map(thd => {
            thd.value = thd.MenuID
            thd.label = thd.MenuName
            thd.disabled = thd.MenuID === menu.MenuID
            return thd
          })
          return snd
        })
        return fst
      })
    let menulist = sessionStorage.getItem('fstMenuList')
    if (menulist) {
      try {
        menulist = JSON.parse(menulist)
      } catch {
        menulist = []
      }
    } else {
      menulist = []
    }
    let modules = this.getModules(menu.components, cards.uuid)
src/menu/components/card/cardcomponent/index.jsx
@@ -158,7 +158,6 @@
    newcard.icon = ''
    newcard.class = 'primary'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.popClose = 'never'
src/menu/components/card/table-card/cardcomponent/index.jsx
@@ -123,7 +123,6 @@
    newcard.icon = ''
    newcard.class = 'primary'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.popClose = 'never'
src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx
@@ -6,9 +6,20 @@
/**
 * @description 获取图表视图配置表单
 * @param {object} card       // 图表对象
 * @param {Array}  columns    // 显示列
 * @param {Array}  MenuType   // 菜单类型
 */
export function getBaseForm (card, MenuType) {
  let menulist = sessionStorage.getItem('fstMenuList')
  if (menulist) {
    try {
      menulist = JSON.parse(menulist)
    } catch {
      menulist = []
    }
  } else {
    menulist = []
  }
  let roleList = sessionStorage.getItem('sysRoles')
  if (roleList) {
    try {
@@ -66,6 +77,16 @@
      required: false,
      forbid: MenuType === 'billPrint',
      options: roleList
    },
    {
      type: 'cascader',
      key: 'linkmenu',
      label: '关联菜单',
      initVal: card.linkmenu || [],
      tooltip: '在使用柱形图且未启用自定义设置时有效。',
      required: false,
      forbid: MenuType === 'billPrint',
      options: menulist
    }
  ]
}
src/menu/components/chart/antv-bar/index.jsx
@@ -791,7 +791,6 @@
    newcard.sysInterface = card.setting.sysInterface || ''
    newcard.outerFunc = card.setting.outerFunc || ''
    newcard.interface = card.setting.interface || ''
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.popClose = 'never'
@@ -866,7 +865,6 @@
        </Popover>
        {menu && menu.MenuType !== 'billPrint' ? <ActionComponent
          type="chart"
          plus="false"
          config={card}
          updateaction={this.updateComponent}
        /> : null}
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
@@ -6,9 +6,20 @@
/**
 * @description 获取图表视图配置表单
 * @param {object} card       // 图表对象
 * @param {Array}  columns    // 显示列
 * @param {Array}  MenuType   // 菜单类型
 */
export function getBaseForm (card, MenuType, fstMenuList = []) {
export function getBaseForm (card, MenuType) {
  let menulist = sessionStorage.getItem('fstMenuList')
  if (menulist) {
    try {
      menulist = JSON.parse(menulist)
    } catch {
      menulist = []
    }
  } else {
    menulist = []
  }
  let roleList = sessionStorage.getItem('sysRoles')
  if (roleList) {
    try {
@@ -75,7 +86,7 @@
      tooltip: '双击饼图,会打开关联的菜单。',
      required: false,
      forbid: MenuType === 'billPrint',
      options: fstMenuList
      options: menulist
    }
  ]
}
src/menu/components/chart/antv-pie/chartcompile/index.jsx
@@ -16,7 +16,7 @@
class LineChartDrawerForm extends Component {
  static propTpyes = {
    menu: PropTypes.any,
    MenuType: PropTypes.any,
    dict: PropTypes.object,
    plot: PropTypes.object,
    config: PropTypes.object,
@@ -51,13 +51,13 @@
  }
  showDrawer = () => {
    const { config, menu } = this.props
    const { config, MenuType } = this.props
    this.setState({
      visible: true,
      view: 'normal',
      plot: fromJS(config.plot).toJS(),
      baseFormlist: getBaseForm(config.plot, menu.MenuType, menu.fstMenuList),
      baseFormlist: getBaseForm(config.plot, MenuType),
      formlist: getOptionForm(config.plot, config.columns)
    })
  }
src/menu/components/chart/antv-pie/index.jsx
@@ -426,7 +426,7 @@
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            {menu && menu.MenuType !== 'billPrint' ? <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" /> : null}
            <ChartCompileForm config={card} menu={menu} dict={this.state.dict} plotchange={this.updateComponent}/>
            {menu ? <ChartCompileForm config={card} MenuType={menu.MenuType} dict={this.state.dict} plotchange={this.updateComponent}/> : null}
            <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}/>
src/menu/components/table/normal-table/cardcomponent/index.jsx
@@ -123,7 +123,6 @@
    newcard.icon = ''
    newcard.class = 'primary'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.popClose = 'never'
src/menu/components/table/normal-table/columncomponent/colspanform/index.jsx
New file
@@ -0,0 +1,211 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, InputNumber, Select, Radio, Tooltip, Icon } from 'antd'
import { formRule } from '@/utils/option.js'
import TransferForm from '@/templates/zshare/transferform'
import './index.scss'
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    columns: PropTypes.array,
    card: PropTypes.any,
    inputSubmit: PropTypes.any   // 回车提交事件
  }
  componentDidMount () {
    try {
      let _form = document.getElementById('label')
      if (_form && _form.select) {
        _form.select()
      }
    } catch {
      console.warn('表单focus失败!')
    }
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          let targetKeys = this.refs['column-transfer'].state.targetKeys
          delete values.type // 删除type,此处值为'合并列'文字
          let subfield = []  // 用于查看合并列字段
          this.props.columns.forEach(col => {
            if (col.field && targetKeys.includes(col.uuid)) {
              subfield.push(col.field)
            }
          })
          subfield = subfield.join(', ')
          let _card = {...this.props.card, ...values, sublist: targetKeys, subfield: subfield}
          delete _card.focus
          resolve(_card)
        } else {
          reject(err)
        }
      })
    })
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  render() {
    const { card } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 18 }
      }
    }
    return (
      <Form {...formItemLayout} className="commontable-cospan-column-form" id="columncolspan">
        <Row gutter={24}>
          <Col span={12}>
            <Form.Item label={this.props.dict['model.name']}>
              {getFieldDecorator('label', {
                initialValue: card.label,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + this.props.dict['model.name'] + '!'
                  },
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={this.props.dict['model.form.type']}>
              {getFieldDecorator('type', {
                initialValue: this.props.dict['model.form.colspan'],
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + this.props.dict['model.form.type'] + '!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" disabled={true}/>)}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={this.props.dict['model.form.align']}>
              {getFieldDecorator('Align', {
                initialValue: card.Align,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + this.props.dict['model.form.align'] + '!'
                  }
                ]
              })(
                <Select
                  getPopupContainer={() => document.getElementById('columncolspan')}
                >
                  <Select.Option value="left">{this.props.dict['model.form.alignLeft']}</Select.Option>
                  <Select.Option value="right">{this.props.dict['model.form.alignRight']}</Select.Option>
                  <Select.Option value="center">{this.props.dict['model.form.alignCenter']}</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={this.props.dict['model.form.columnWidth']}>
              {getFieldDecorator('Width', {
                initialValue: card.Width,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + this.props.dict['model.form.columnWidth'] + '!'
                  }
                ]
              })(<InputNumber min={1} max={1000} precision={0} />)}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="选择显示分组,表格会展开添加分组的子列,此时排列方式会失效。">
                <Icon type="question-circle" />
                显示分组
              </Tooltip>
            }>
              {getFieldDecorator('unfold', {
                initialValue: card.unfold || 'false'
              })(
                <Radio.Group>
                  <Radio value="true">{this.props.dict['model.true']}</Radio>
                  <Radio value="false">{this.props.dict['model.false']}</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={this.props.dict['model.hidden']}>
              {getFieldDecorator('Hide', {
                initialValue: card.Hide || 'false',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + this.props.dict['model.hidden'] + '!'
                  }
                ]
              })(
                <Radio.Group>
                  <Radio value="true">{this.props.dict['model.true']}</Radio>
                  <Radio value="false">{this.props.dict['model.false']}</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={this.props.dict['header.form.order']}>
              {getFieldDecorator('order', {
                initialValue: card.order,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + this.props.dict['header.form.order'] + '!'
                  }
                ]
              })(
                <Select
                  getPopupContainer={() => document.getElementById('columncolspan')}
                >
                  <Select.Option value="vertical">{this.props.dict['header.form.vertical']}</Select.Option>
                  <Select.Option value="horizontal">{this.props.dict['header.form.horizontal']}</Select.Option>
                  <Select.Option value="vertical2">{this.props.dict['header.form.vertical2']}</Select.Option>
                  <Select.Option value="topPicBottomText">{this.props.dict['header.form.topPicBottomText']}</Select.Option>
                  <Select.Option value="leftPicRightText">{this.props.dict['header.form.leftPicRightText']}</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <TransferForm columns={this.props.columns} ref="column-transfer" selected={card.sublist}/>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/menu/components/table/normal-table/columncomponent/colspanform/index.scss
New file
@@ -0,0 +1,13 @@
.commontable-cospan-column-form {
  min-height: 190px;
  .ant-form-item {
    .ant-input-number {
      width: 100%;
    }
  }
  .anticon-question-circle {
    color: #c49f47;
    position: relative;
    left: -3px;
  }
}
src/menu/components/table/normal-table/columncomponent/columnform/index.jsx
New file
@@ -0,0 +1,336 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Icon, Cascader } from 'antd'
import { formRule } from '@/utils/option.js'
import './index.scss'
const columnTypeOptions = {
  text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'textFormat', 'fieldlength', 'blacklist', 'perspective', 'rowspan'],
  number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'blacklist', 'perspective', 'sum'],
  link: ['label', 'field', 'type', 'nameField', 'Align', 'Hide', 'IsSort', 'joint', 'Width', 'fieldlength', 'blacklist'],
  textarea: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'fieldlength', 'blacklist'],
  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'fieldlength', 'blacklist', 'scale', 'maxHeight']
}
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object,     // 字典项
    formlist: PropTypes.any,
    card: PropTypes.any,
    inputSubmit: PropTypes.any  // 回车提交事件
  }
  state = {
    formlist: null,
    type: '',
    menulist: null
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    let _menulist = this.props.formlist.filter(form => form.key === 'linkmenu')[0] || ''
    let _options = JSON.parse(JSON.stringify(columnTypeOptions[card.type]))
    if (card.type === 'text' || card.type === 'number') {
      if (card.perspective !== 'linkurl') {
        _options.push('linkmenu')
      } else {
        _options.push('linkurl')
      }
    }
    this.setState({
      type: card.type,
      menulist: _menulist.options || [],
      formlist: this.props.formlist.map(item => {
        item.hidden = !_options.includes(item.key)
        return item
      })
    })
  }
  /**
   * @description 初次添加的显示列元素,聚焦提示文字
   */
  componentDidMount () {
    const { card } = this.props
    if (card.focus) {
      try {
        let _form = document.getElementById('label')
        _form.select()
      } catch {
        console.warn('表单focus失败!')
      }
    }
  }
  typeChange = (key, value) => {
    const { card } = this.props
    if (key === 'type') {
      let _options = JSON.parse(JSON.stringify(columnTypeOptions[value]))
      if (card.type === 'text' || card.type === 'number') {
        if (card.perspective !== 'linkurl') {
          _options.push('linkmenu')
        } else {
          _options.push('linkurl')
        }
      }
      let fieldlength = 50
      if (value !== 'text') {
        fieldlength = 512
      }
      this.setState({
        type: value,
        formlist: this.props.formlist.map(item => {
          item.hidden = !_options.includes(item.key)
          return item
        })
      }, () => {
        if (this.props.form.getFieldValue('fieldlength') !== undefined) {
          this.props.form.setFieldsValue({fieldlength: fieldlength})
        }
      })
    } else if (key === 'format' && value === 'percent') {
      this.props.form.setFieldsValue({postfix: '%'})
    }
  }
  changeRadio = (key, value) => {
    if (key === 'perspective') {
      let _options = JSON.parse(JSON.stringify(columnTypeOptions[this.state.type]))
      if (value !== 'linkurl') {
        _options.push('linkmenu')
      } else {
        _options.push('linkurl')
      }
      this.setState({
        formlist: this.props.formlist.map(item => {
          item.hidden = !_options.includes(item.key)
          return item
        })
      })
    }
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.hidden) return
      if (item.type === 'text') { // 文本搜索
        let rules = []
        if (item.key === 'field' || item.key === 'nameField') {
          rules = [{
            pattern: formRule.field.pattern,
            message: formRule.field.message
          }, {
            max: formRule.field.max,
            message: formRule.field.maxMessage
          }]
        } else if (item.key !== 'linkurl') {
          rules = [{
            max: formRule.input.max,
            message: formRule.input.message
          }]
        }
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  },
                  ...rules
                ]
              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'number') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(item.unlimit ? <InputNumber /> :
                  <InputNumber min={item.min} max={item.max} precision={item.decimal} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    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.typeChange(item.key, value)}}
                  getPopupContainer={() => document.getElementById('columnwinter')}
                >
                  {item.options.map((option, index) =>
                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'radio') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.tooltip ?
              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
                <Icon type="question-circle" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Radio.Group onChange={(e) => {this.changeRadio(item.key, e.target.value)}}>
                  {
                    item.options.map(option => {
                      return (
                        <Radio key={option.value} value={option.value}>{option.text}</Radio>
                      )
                    })
                  }
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'multiselect') { // 多选
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || []
              })(
                <Select
                  showSearch
                  mode="multiple"
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {item.options.map((option, i) =>
                    <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'cascader') { // 多选
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || []
              })(
                <Cascader
                  options={this.state.menulist}
                  placeholder=""
                  getPopupContainer={() => document.getElementById('columnwinter')}
                />
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values.uuid = this.props.card.uuid
          values.marks = this.props.card.marks || ''
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 18 }
      }
    }
    return (
      <Form {...formItemLayout} className="commontable-column-form" id="columnwinter">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/menu/components/table/normal-table/columncomponent/columnform/index.scss
New file
@@ -0,0 +1,19 @@
.commontable-column-form {
  min-height: 190px;
  .ant-form-item {
    .ant-input-number {
      width: 100%;
    }
  }
  .anticon-question-circle {
    color: #c49f47;
    position: relative;
    left: -3px;
  }
  .ant-cascader-menus {
    padding: 5px 0px;
    .ant-cascader-menu:last-child {
      padding-right: 3px;
    }
  }
}
src/menu/components/table/normal-table/columncomponent/dragcolumn/card.jsx
New file
@@ -0,0 +1,62 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Icon, Popover } from 'antd'
import './index.scss'
const Card = ({ id, card, showfield, moveCard, findCard, editCard, delCard, markCard }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'columns', id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'columns',
    canDrop: () => true,
    drop: (item) => {
      const { id: draggedId, originalIndex } = item
      if (originalIndex === undefined) {
        item.dropTargetId = id
      } else if (draggedId && draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    }
  })
  const opacity = isDragging ? 0 : 1
  return (
    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
      <div className="mk-popover-control">
        <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
        <Icon className="close" title="delete" type="close" onClick={() => delCard(id)} />
        {['text', 'number'].includes(card.type) && !card.origin ? <Icon className="profile" title="mark" type="ant-design" onClick={() => markCard(id)} /> : null}
      </div>
    } trigger="hover">
      <div className="page-card" style={{ flex: card.Width, opacity: opacity}}>
        <div ref={node => drag(drop(node))}>
          <span className="ant-table-header-column">
            <div className="ant-table-column-sorters" title={card.label} style={{textAlign: card.Align}}>
              <span className="ant-table-column-title">{card.label}</span>
              {card.IsSort === 'true' ?
                <span className="ant-table-column-sorter">
                  <Icon type="caret-up" />
                  <Icon type="caret-down" />
                </span> : null
              }
            </div>
            {showfield ?
              <div className="ant-table-column-fields">
                <span className="ant-table-column-title">{card.type === 'colspan' ? card.subfield : card.field}</span>
              </div> : null
            }
          </span>
        </div>
      </div>
    </Popover>
  )
}
export default Card
src/menu/components/table/normal-table/columncomponent/dragcolumn/index.jsx
New file
@@ -0,0 +1,174 @@
import React, { useState } from 'react'
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Icon, Popover } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
import './index.scss'
const Container = ({list, setting, gridBtn, showfield, placeholder, handleList, handleMenu, handleGridBtn, deleteMenu, markMenu }) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    handleList(_cards)
  }
  if (!is(fromJS(cards), fromJS(list))) {
    setCards(list)
  }
  const findCard = id => {
    const card = cards.filter(c => `${c.uuid}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
  const editCard = id => {
    const { card } = findCard(id)
    delete card.focus // 兼容早期的合并列
    handleMenu(card)
  }
  const delCard = id => {
    const { card } = findCard(id)
    deleteMenu(card)
  }
  const markCard = id => {
    const { card } = findCard(id)
    markMenu(card)
  }
  const [, drop] = useDrop({
    accept: 'columns',
    drop(item) {
      if (item.hasOwnProperty('originalIndex')) {
        return
      }
      let newcard = {}
      newcard.uuid = Utils.getuuid()
      newcard.focus = true
      newcard.Align = 'left'
      newcard.label = 'label'
      newcard.field = ''
      newcard.Hide = 'false'
      newcard.contrastType = 'static'
      newcard.IsSort = 'true'
      newcard.type = item.subType
      newcard.Width = 120
      if (item.subType === 'colspan') {
        newcard.sublist = []
        newcard.subfield = []
        newcard.IsSort = 'false'
        newcard.order = 'vertical'
      }
      let targetId = ''
      if (item.dropTargetId) {
        targetId = item.dropTargetId
        delete item.dropTargetId
      } else if (cards.length > 0) {
        targetId = cards[cards.length - 1].uuid
      }
      const { index: overIndex } = findCard(`${targetId}`)
      const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
      handleList(_cards, newcard)
    }
  })
  let columns = []
  let _colCards = []
  // 过滤合并列
  let _hideCol = []
  if (!showfield) {
    cards.forEach(col => {
      if (col.type === 'colspan' && col.sublist) {
        _hideCol.push(...col.sublist)
      }
    })
  }
  cards.forEach(col => {
    if (_hideCol.includes(col.uuid)) return
    _colCards.push(col)
  })
  // 显示列分行
  if (_colCards.length > 10) {
    let number = Math.ceil(_colCards.length / Math.ceil(_colCards.length / 10))
    for (let i = 0, len = _colCards.length; i < len; i += number) {
      columns.push(_colCards.slice(i, i + number))
    }
  } else {
    columns.push(_colCards)
  }
  return (
    <div ref={drop} className="ant-row">
      {columns.map((column, i) => (
        <div key={i} className="column-box">
          {/* 多选 */}
          {i === 0 && column.length > 0 && setting.tableType === 'checkbox' ?
            <div className="page-card" style={{flex: 60}}>
              <span className="ant-checkbox-inner"></span>
            </div> : null
          }
          {/* 单选 */}
          {i === 0 && column.length > 0 && setting.tableType === 'radio' ?
            <div className="page-card" style={{flex: 60}}></div> : null
          }
          {column.map(card => (
            <Card
              key={card.uuid}
              id={card.uuid}
              card={card}
              showfield={showfield}
              moveCard={moveCard}
              editCard={editCard}
              delCard={delCard}
              markCard={markCard}
              findCard={findCard}
            />
          ))}
          {i === (columns.length - 1) && gridBtn && gridBtn.display ?
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <Icon className="edit" type="edit" onClick={handleGridBtn}/>
              </div>
            } trigger="hover">
              <div className="page-card" style={{flex: gridBtn.Width}}>
                <div style={{cursor: 'default'}}>
                  <span className="ant-table-header-column">
                    <div className="ant-table-column-sorters" title={gridBtn.label} style={{textAlign: gridBtn.Align}}>
                      <span className="ant-table-column-title">{gridBtn.label}</span>
                    </div>
                  </span>
                </div>
              </div>
            </Popover> : null
          }
        </div>
      ))}
      {cards.length === 0 ?
        <div className="common-drawarea-placeholder">
          {placeholder}
        </div> : null
      }
    </div>
  )
}
export default Container
src/menu/components/table/normal-table/columncomponent/dragcolumn/index.scss
New file
@@ -0,0 +1,6 @@
.common-drawarea-placeholder {
  width: 100%;
  line-height: 65px;
  text-align: center;
  color: #bcbcbc;
}
src/menu/components/table/normal-table/columncomponent/gridbtnform/index.jsx
New file
@@ -0,0 +1,218 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, InputNumber, Radio } from 'antd'
import { formRule } from '@/utils/option.js'
import './index.scss'
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object,     // 字典项
    card: PropTypes.any,
    inputSubmit: PropTypes.any  // 回车提交事件
  }
  state = {
    formlist: [
      {
        type: 'text',
        key: 'label',
        label: this.props.dict['model.name'],
        initVal: this.props.card.label,
        required: true
      },
      {
        type: 'select',
        key: 'Align',
        label: this.props.dict['model.form.align'],
        initVal: this.props.card.Align,
        required: true,
        options: [{
          MenuID: 'left',
          text: this.props.dict['model.form.alignLeft']
        }, {
          MenuID: 'right',
          text: this.props.dict['model.form.alignRight']
        }, {
          MenuID: 'center',
          text: this.props.dict['model.form.alignCenter']
        }]
      },
      {
        type: 'number',
        key: 'Width',
        decimal: 0,
        label: this.props.dict['model.form.columnWidth'],
        initVal: this.props.card.Width,
        required: true
      },
      // {
      //   type: 'select',
      //   key: 'style',
      //   label: this.props.dict['model.form.style'],
      //   initVal: this.props.card.style,
      //   required: true,
      //   options: [{
      //     MenuID: 'button',
      //     text: this.props.dict['header.form.button']
      //   }, {
      //     MenuID: 'text',
      //     text: this.props.dict['model.form.href']
      //   }]
      // },
      // {
      //   type: 'select',
      //   key: 'show',
      //   label: this.props.dict['header.form.order'],
      //   initVal: this.props.card.show,
      //   required: true,
      //   options: [{
      //     MenuID: 'horizontal',
      //     text: this.props.dict['header.form.horizontal']
      //   }, {
      //     MenuID: 'vertical',
      //     text: this.props.dict['header.form.vertical']
      //   }]
      // }
    ]
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.type === 'text') { // 文本搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  },
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'number') { // 文本搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<InputNumber min={1} max={1000} precision={item.decimal} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  getPopupContainer={() => document.getElementById('gridbtncolumnwinter')}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.MenuID} title={option.text} key={option.MenuID} value={option.MenuID}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'radio') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Radio.Group>
                  {
                    item.options.map(option => {
                      return (
                        <Radio key={option.MenuID} value={option.MenuID}>{option.text}</Radio>
                      )
                    })
                  }
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          resolve({...this.props.card, ...values})
        } else {
          reject(err)
        }
      })
    })
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 18 }
      }
    }
    return (
      <Form {...formItemLayout} className="commontable-gridbtn-column-form" id="gridbtncolumnwinter">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/menu/components/table/normal-table/columncomponent/gridbtnform/index.scss
New file
@@ -0,0 +1,8 @@
.commontable-gridbtn-column-form {
  min-height: 190px;
  .ant-form-item {
    .ant-input-number {
      width: 100%;
    }
  }
}
src/menu/components/table/normal-table/columncomponent/index.jsx
New file
@@ -0,0 +1,509 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Modal, notification, Switch, message, Spin } from 'antd'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getColumnForm } from '@/templates/zshare/formconfig'
import ColumnForm from './columnform'
import ColspanForm from './colspanform'
import GridBtnForm from './gridbtnform'
import DragElement from './dragcolumn'
import MarkColumn from './markcolumn'
import './index.scss'
const { confirm } = Modal
class ColumnComponent extends Component {
  static propTpyes = {
    config: PropTypes.object,        // 配置信息
    updatecolumn: PropTypes.func     // 更新
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    columnlist: null,    // 显示列
    loading: false,      // 查询显示列联动菜单
    showField: false,    // 显示列字段
    modaltype: '',       // 模态框控制
    card: null           // 编辑中元素
  }
  /**
   * @description 显示列初始化
   */
  UNSAFE_componentWillMount () {
    this.setState({
      columnlist: fromJS(this.props.config.cols).toJS()
    })
  }
  /**
   * @description 监听到显示列复制时,触发显示列编辑
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
    const { config } = this.props
    const { columnlist } = this.state
    if (!is(fromJS(nextProps.config.cols), fromJS(config.cols)) && !is(fromJS(nextProps.config.cols), fromJS(columnlist))) {
      this.setState({columnlist: fromJS(nextProps.config.cols).toJS()})
    }
  }
  /**
   * @description 显示列顺序调整,或拖拽添加
   */
  handleList = (list, card) => {
    const { config } = this.props
    if (card) {
      this.setState({columnlist: list})
      this.handleColumn(card)
    } else {
      this.setState({columnlist: list}, ()=> {
        this.props.updatecolumn({...config, cols: list})
      })
    }
  }
  /**
   * @description 显示列与合并列编辑,获取表单信息
   */
  handleColumn = (card) => {
    if (card.type !== 'colspan') {
      let menulist = sessionStorage.getItem('fstMenuList')
      if (menulist) {
        try {
          menulist = JSON.parse(menulist)
        } catch {
          menulist = []
        }
      } else {
        menulist = []
      }
      this.setState({
        modaltype: 'cols',
        card: card,
        formlist: getColumnForm(card, menulist)
      })
    } else {
      this.setState({
        modaltype: 'colspan',
        card: card
      })
    }
  }
  /**
   * @description 设置标志
   */
  markElement = (card) => {
    this.setState({
      modaltype: 'mark',
      card: card
    })
  }
  /**
   * @description 操作列编辑
   */
  handleGridBtn = () => {
    this.setState({
      modaltype: 'gridbtn'
    })
  }
  /**
   * @description 取消保存,如果元素为新添元素,则从序列中删除
   */
  editModalCancel = () => {
    const { card } = this.state
    if (card && card.focus) {
      let _columnlist = fromJS(this.state.columnlist).toJS()
      _columnlist = _columnlist.filter(item => item.uuid !== card.uuid)
      this.setState({
        card: null,
        modaltype: '',
        columnlist: _columnlist
      })
    } else {
      this.setState({
        card: null,
        modaltype: ''
      })
    }
  }
  /**
   * @description 搜索修改后提交保存
   * 1、去除系统默认显示列
   * 2、字段及提示文字重复校验
   * 3、更新下拉菜单可选集合
   * 4、下拉菜单数据源语法验证
   */
  handleSubmit = () => {
    const { config } = this.props
    const { modaltype, card } = this.state
    let _columnlist = fromJS(this.state.columnlist).toJS()
    if (modaltype === 'cols' || modaltype === 'colspan') {
      this.columnFormRef.handleConfirm().then(res => {
        let fieldrepet = false // 字段重复
        let labelrepet = false // 提示文字重复
        let rowspanLabel = ''  // 已存在的行合并字段
        _columnlist = _columnlist.filter(item => !item.origin || item.uuid === res.uuid) // 去除初始列
        _columnlist = _columnlist.map(item => {
          if (item.uuid !== res.uuid && res.field && item.field) {
            if (item.field === res.field) {
              fieldrepet = true
            } else if (item.label === res.label) {
              labelrepet = true
            } else if (res.rowspan === 'true' && item.rowspan === 'true') {
              rowspanLabel = item.label
            }
          }
          if (item.uuid === res.uuid) {
            return res
          } else {
            return item
          }
        })
        if (fieldrepet) {
          notification.warning({
            top: 92,
            message: this.state.dict['model.field.exist'] + ' !',
            duration: 5
          })
          return
        } else if (labelrepet) {
          notification.warning({
            top: 92,
            message: this.state.dict['model.name.exist'] + ' !',
            duration: 5
          })
          return
        } else if (rowspanLabel) {
          notification.warning({
            top: 92,
            message: `已存在行合并字段《${rowspanLabel}》!`,
            duration: 5
          })
          return
        }
        if (!card.focus && (card.type !== res.type || (res.field && card.field !== res.field))) {
          let refers = []
          _columnlist.forEach(column => {
            if (column.marks && column.marks.filter(mark => mark.field === card.field || mark.contrastField === card.field).length > 0) {
              refers.push(column.label)
            }
            if (column.type === 'colspan') {
              let _length = column.sublist.length
              column.sublist = column.sublist.filter(cell => cell !== card.uuid)
              if (column.sublist.length < _length) {
                let subfield = []  // 合并列字段
                _columnlist.forEach(col => {
                  if (col.field && column.sublist.includes(col.uuid)) {
                    subfield.push(col.field)
                  }
                })
                column.subfield = subfield.join(', ')
              }
            }
          })
          if (refers.length > 0) {
            notification.warning({
              top: 92,
              message: '显示列《' + refers.join('、') + '》标记中含有该字段,此次修改会导致标记失效,请修改相应的标记设置!',
              duration: 5
            })
          }
        }
        this.setState({
          card: null,
          columnlist: _columnlist,
          modaltype: ''
        }, ()=> {
          this.props.updatecolumn({...config, cols: _columnlist})
        })
      })
    } else if (modaltype === 'gridbtn') {
      this.gridBtnFormRef.handleConfirm().then(res => {
        this.setState({
          modaltype: ''
        })
        this.props.updatecolumn({...config, gridBtn: res})
      })
    }
  }
  /**
   * @description 显示列删除
   */
  deleteElement = (card) => {
    const { config } = this.props
    const { dict } = this.state
    let _this = this
    confirm({
      content: dict['model.confirm'] + dict['model.delete'] + ` - ${card.label} ?`,
      onOk() {
        let _columnlist = fromJS(_this.state.columnlist).toJS()
        _columnlist = _columnlist.filter(item => item.uuid !== card.uuid)
        if (card.field) {
          let refers = []
          _columnlist.forEach(column => {
            if (column.marks && column.marks.filter(mark => mark.field === card.field || mark.contrastField === card.field).length > 0) {
              refers.push(column.label)
            }
            if (column.type === 'colspan') {
              let _length = column.sublist.length
              column.sublist = column.sublist.filter(cell => cell !== card.uuid)
              if (column.sublist.length < _length) {
                let subfield = []  // 合并列字段
                _columnlist.forEach(col => {
                  if (col.field && column.sublist.includes(col.uuid)) {
                    subfield.push(col.field)
                  }
                })
                column.subfield = subfield.join(', ')
              }
            }
          })
          if (refers.length > 0) {
            notification.warning({
              top: 92,
              message: '显示列《' + refers.join('、') + '》标记中含有该字段,删除会导致标记失效,请修改相应的标记设置!',
              duration: 5
            })
          }
        }
        _this.setState({
          columnlist: _columnlist
        }, ()=> {
          _this.props.updatecolumn({...config, cols: _columnlist})
        })
      },
      onCancel() {}
    })
  }
  /**
   * @description 显示列复制
   */
  copycolumn = () => {
    const { columnlist } = this.state
    let oInput = document.createElement('input')
    let val = {
      copyType: 'columns',
      columns: columnlist
    }
    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
    document.body.appendChild(oInput)
    oInput.select()
    document.execCommand('Copy')
    oInput.className = 'oInput'
    oInput.style.display = 'none'
    message.success('复制成功。')
    document.body.removeChild(oInput)
  }
  /**
   * @description 显示列字段名显示或隐藏控制
   */
  onFieldChange = () => {
    const { showField, columnlist } = this.state
    if (!showField) {
      let fields = []
      columnlist.forEach(col => {
        if (col.field) {
          fields.push(col.field)
        }
      })
      fields = fields.join(',')
      let textArea = document.createElement('textarea')
      textArea.value = fields
      document.body.appendChild(textArea)
      textArea.select()
      try {
        document.execCommand('copy')
        document.body.removeChild(textArea)
      } catch (err) {
        document.body.removeChild(textArea)
      }
    }
    this.setState({
      showField: !showField
    })
  }
  markSubmit = () => {
    const { config } = this.props
    const { card } = this.state
    let _columnlist = fromJS(this.state.columnlist).toJS()
    let _marks = this.refs.markRef.state.marks
    if (_marks.length === 0) {
      _marks = ''
    }
    _columnlist = _columnlist.map(item => {
      if (item.uuid === card.uuid) {
        item.marks = _marks
      }
      return item
    })
    this.setState({
      card: null,
      columnlist: _columnlist,
      modaltype: ''
    }, ()=> {
      this.props.updatecolumn({...config, cols: _columnlist})
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  render() {
    const { config } = this.props
    const { modaltype, columnlist, dict, card } = this.state
    return (
      <div className="model-custom-table-column-list">
        {columnlist && columnlist.length > 0 ?
          <Icon className="column-copy" title="copy" type="copy" onClick={this.copycolumn} /> : null
        }
        <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={this.onFieldChange} />
        <DragElement
          list={columnlist}
          setting={config.setting}
          gridBtn={config.gridBtn}
          handleList={this.handleList}
          handleMenu={this.handleColumn}
          deleteMenu={this.deleteElement}
          markMenu={this.markElement}
          handleGridBtn={this.handleGridBtn}
          showfield={this.state.showField}
          placeholder={this.state.dict['header.form.column.placeholder']}
        />
        {/* 显示列编辑 */}
        <Modal
          title={dict['header.modal.column.edit']}
          visible={modaltype === 'cols'}
          width={800}
          maskClosable={false}
          onOk={this.handleSubmit}
          onCancel={this.editModalCancel}
          destroyOnClose
        >
          <ColumnForm
            dict={dict}
            card={card}
            inputSubmit={this.handleSubmit}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.columnFormRef = inst}
          />
        </Modal>
        {/* 合并列编辑 */}
        <Modal
          title={dict['model.form.colspan'] + '-' + dict['model.edit']}
          visible={modaltype === 'colspan'}
          width={800}
          maskClosable={false}
          onOk={this.handleSubmit}
          onCancel={this.editModalCancel}
          destroyOnClose
        >
          <ColspanForm
            dict={dict}
            card={card}
            inputSubmit={this.handleSubmit}
            columns={columnlist}
            wrappedComponentRef={(inst) => this.columnFormRef = inst}
          />
        </Modal>
        {/* 操作列编辑 */}
        <Modal
          title={dict['header.modal.gridbtn.edit']}
          visible={modaltype === 'gridbtn'}
          width={800}
          maskClosable={false}
          onOk={this.handleSubmit}
          onCancel={this.editModalCancel}
          destroyOnClose
        >
          <GridBtnForm
            dict={dict}
            inputSubmit={this.handleSubmit}
            card={config.gridBtn}
            wrappedComponentRef={(inst) => this.gridBtnFormRef = inst}
          />
        </Modal>
        {/* 按钮使用系统存储过程时,验证信息模态框 */}
        <Modal
          wrapClassName="model-table-column-mark-modal"
          title={'标记设置'}
          visible={modaltype === 'mark'}
          width={'75vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          okText={dict['model.submit']}
          onOk={this.markSubmit}
          onCancel={() => { this.setState({ modaltype: '' }) }}
          destroyOnClose
        >
          <MarkColumn
            ref="markRef"
            card={card}
            dict={dict}
            columns={columnlist}
          />
        </Modal>
        {this.state.loading && <Spin size="large" />}
      </div>
    )
  }
}
export default ColumnComponent
src/menu/components/table/normal-table/columncomponent/index.scss
New file
@@ -0,0 +1,99 @@
.model-custom-table-column-list {
  position: relative;
  padding: 0px 0px 50px;
  .ant-switch {
    position: absolute;
    right: 5px;
    top: -25px;
  }
  .column-copy {
    position: absolute;
    font-size: 16px;
    right: 70px;
    top: -22px;
    color: #26C281;
    cursor: pointer;
  }
  > .ant-row {
    background: #fafafa;
    border-radius: 4px;
    min-height: 47px;
    border: 1px solid #e8e8e8;
    .column-box {
      display: flex;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .column-box:not(:first-child) {
      border-top: 1px solid #e8e8e8;
    }
    .page-card {
      position: relative;
      padding: 0px;
      min-height: 45px;
      > div {
        padding: 12px 0px 0px;
        cursor: move;
        height: 100%;
        .ant-table-column-sorters {
          padding: 0px 8px 12px;
          // white-space: nowrap;
        }
        .ant-table-column-fields {
          padding: 0px 8px 5px;
        }
      }
      .ant-table-column-sorter {
        position: relative;
        display: inline-block;
        width: 24px;
        font-size: 12px;
        color: #bfbfbf;
        .anticon-caret-up {
          position: relative;
          left: 10px;
          top: -3px;
        }
        .anticon-caret-down {
          position: relative;
          left: -2px;
          top: 3px;
        }
      }
      .ant-checkbox-inner {
        margin-top: 14px;
        margin-left: calc(50% - 8px);
      }
    }
    .page-card:not(:last-child) {
      border-right: 1px solid #e8e8e8;
    }
  }
}
.model-table-column-mark-modal {
  .ant-modal {
    top: 50px;
    padding-bottom: 5px;
    .ant-modal-body {
      max-height: calc(100vh - 190px);
      min-height: 350px;
      overflow-y: auto;
    }
    .ant-modal-body::-webkit-scrollbar {
      width: 7px;
    }
    .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/menu/components/table/normal-table/columncomponent/markcolumn/index.jsx
New file
@@ -0,0 +1,242 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Table, Popconfirm, Icon } from 'antd'
import Utils from '@/utils/utils.js'
import MarkForm from './markform'
import './index.scss'
import '@/assets/css/table.scss'
class MarkColumn extends Component {
  static propTpyes = {
    columns: PropTypes.array,  // 显示列
    dict: PropTypes.object,    // 字典项
    card: PropTypes.object,
  }
  state = {
    marks: null,
    columns: null,
    markColumns: [
      {
        title: '字段',
        dataIndex: 'field',
        width: '20%',
        render: (text, record) => {
          let item = this.props.columns.filter(col => col.field === record.field)[0]
          if (item) {
            return item.label + '(' + item.field + ')'
          } else {
            return ''
          }
        }
      },
      {
        title: '对比类型',
        dataIndex: 'contrastType',
        width: '15%',
        render: (text, record) => {
          if (record.contrastType === 'static') {
            return '静态'
          } else {
            return '动态'
          }
        }
      },
      {
        title: '对比值/字段',
        dataIndex: 'contrastValue',
        width: '20%',
        render: (text, record) => {
          if (record.contrastType === 'static') {
            return '对比值: ' + text
          } else {
            let item = this.props.columns.filter(col => col.field === record.contrastField)[0]
            if (item) {
              return '字段: ' + item.label + '(' + item.field + ')'
            } else {
              return ''
            }
          }
        }
      },
      {
        title: '对比方式',
        dataIndex: 'match',
        width: '12%'
      },
      {
        title: '标记效果',
        dataIndex: 'signType',
        width: '13%',
        render: (text, record) => {
          let item = this.props.columns.filter(col => col.field === record.field)[0]
          if (!item) return ''
          let content = ''
          if (item.type === 'text') {
            content = '文本'
          } else {
            content = Math.ceil(Math.random() * 100) * 10
          }
          let _outerclass = ''
          if (record.signType === 'font') {
            _outerclass = 'font ' + record.color[1]
          } else if (record.signType === 'background') {
            _outerclass = 'background ' + record.color[1]
          } else if (record.signType === 'card') {
            _outerclass = 'background ' + record.color[1]
            content = '效果在卡片中可见'
          } else if (record.signType === 'icon') {
            if (record.position === 'front') {
              content = <div><Icon className={'font ' + record.color[1]} type={record.icon} /> {content} </div>
            } else {
              content = <div> {content} <Icon className={'font ' + record.color[1]} type={record.icon} /> </div>
            }
          }
          return <div className={_outerclass}>
            <div className="baseboard"></div>
            <div className="content">
              {content}
            </div>
          </div>
        }
      },
      {
        title: '操作',
        align: 'center',
        dataIndex: 'operation',
        render: (text, record) =>
          (
            <div>
              <span className="operation-btn" title={this.props.dict['model.edit']} onClick={() => this.handleEdit(record)} style={{color: '#1890ff'}}><Icon type="edit" /></span>
              <span className="operation-btn" title={this.props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
              <span className="operation-btn" title={this.props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
              <Popconfirm
                overlayClassName="popover-confirm"
                title={this.props.dict['model.query.delete']}
                onConfirm={() => this.handleDelete(record)
              }>
                <span className="operation-btn" style={{color: '#ff4d4f'}}><Icon type="delete" /></span>
              </Popconfirm>
            </div>
          )
      }
    ]
  }
  UNSAFE_componentWillMount() {
    const { columns, card } = this.props
    this.setState({
      columns: columns.filter(col => col.type === 'text' || col.type === 'number'),
      marks: card.marks ? fromJS(card.marks).toJS() : []
    })
  }
  markChange = (values) => {
    let _marks = fromJS(this.state.marks).toJS()
    if (values.uuid) {
      _marks = _marks.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      _marks.push(values)
    }
    this.setState({
      marks: _marks
    })
  }
  handleDelete = (record) => {
    const { marks } = this.state
    let _marks = marks.filter(item => item.uuid !== record.uuid)
    this.setState({ marks: _marks })
  }
  handleEdit = (record) => {
    this.markForm.edit(record)
    let node = document.getElementById('mark-column-box-modal').parentNode
    if (node && node.scrollTop) {
      let inter = Math.ceil(node.scrollTop / 10)
      let timer = setInterval(() => {
        if (node.scrollTop - inter > 0) {
          node.scrollTop = node.scrollTop - inter
        } else {
          node.scrollTop = 0
          clearInterval(timer)
        }
      }, 10)
    }
  }
  handleUpDown = (record, direction) => {
    let _marks = fromJS(this.state.marks).toJS()
    let index = 0
    _marks = _marks.filter((item, i) => {
      if (item.uuid === record.uuid) {
        index = i
      }
      return item.uuid !== record.uuid
    })
    if ((index === 0 && direction === 'up') || (index === _marks.length && direction === 'down')) {
      return
    }
    if (direction === 'up') {
      _marks.splice(index - 1, 0, record)
    } else {
      _marks.splice(index + 1, 0, record)
    }
    this.setState({
      marks: _marks
    })
  }
  render() {
    const { card } = this.props
    const { marks, markColumns, columns } = this.state
    return (
      <div id="mark-column-box-modal" className="">
        <MarkForm
          dict={this.props.dict}
          card={card}
          columns={columns}
          markChange={this.markChange}
          wrappedComponentRef={(inst) => this.markForm = inst}
        />
        <Table
          bordered
          rowKey="uuid"
          className="mingke-table"
          dataSource={marks}
          rowClassName={(record) => record.signType === 'line' ? 'mk-table-line background ' + record.color[1] : ''}
          columns={markColumns}
          pagination={false}
        />
      </div>
    )
  }
}
export default MarkColumn
src/menu/components/table/normal-table/columncomponent/markcolumn/index.scss
New file
@@ -0,0 +1,67 @@
#mark-column-box-modal {
  .ant-form-item-label .anticon-question-circle {
    color: #c49f47;
    position: relative;
    left: -3px;
  }
  table tr td {
    word-wrap: break-word;
    word-break: break-word;
  }
  .ant-input-number {
    width: 100%;
  }
  .mingke-table .ant-empty {
    margin: 20px 8px!important;
  }
  .mingke-table {
    td {
      position: relative;
    }
  }
  .errorval {
    display: inline-block;
    width: 30px;
  }
  .operation-btn {
    display: inline-block;
    font-size: 16px;
    padding: 0 5px;
    cursor: pointer;
  }
  .ant-tabs-tabpane {
    position: relative;
    .excel-col-add {
      position: absolute;
      right: 0;
      top: 90px;
    }
  }
  .ant-table-tbody tr.background td {
    background: unset!important;
  }
  .background {
    .baseboard {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
    }
    .content {
      position: relative;
    }
  }
  .mk-table-line.background {
    .baseboard {
      background: unset!important;
    }
  }
  .ant-form-item {
    white-space: nowrap;
  }
}
src/menu/components/table/normal-table/columncomponent/markcolumn/markform/index.jsx
New file
@@ -0,0 +1,384 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Select, Button, Input, InputNumber, Radio, Icon, Cascader, Tooltip } from 'antd'
import { minkeColorSystem, minkeIconSystem } from '@/utils/option.js'
import './index.scss'
class UniqueForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    card: PropTypes.object,         // 字段信息
    columns: PropTypes.array,       // 列名集合
    markChange: PropTypes.func      // 修改函数
  }
  state = {
    editItem: null, // 编辑元素
    contrastType: 'static',
    originField: this.props.card,
    signType: 'background',
    selectIcon: '',
    options: JSON.parse(JSON.stringify(minkeColorSystem)),
    icons: minkeIconSystem.direction
  }
  UNSAFE_componentWillMount() {
    this.setState({
      options: this.state.options.map(option => {
        option.children = option.children.map(cell => {
          cell.label = <div className={'background ' + cell.value}>{cell.value}</div>
          return cell
        })
        return option
      })
    })
  }
  edit = (record) => {
    const { columns } = this.props
    let item = columns.filter(col => col.field === record.field)[0]
    let _type = 'background '
    if (record.signType === 'icon' || record.signType === 'font') {
      _type = 'font '
    }
    this.setState({
      originField: item || '',
      editItem: record,
      contrastType: record.contrastType || '',
      signType: record.signType || '',
      selectIcon: record.icon || '',
      options: this.state.options.map(option => {
        option.children = option.children.map(cell => {
          cell.label = <div className={_type + cell.value}>{record.icon ? <Icon type={record.icon} /> : cell.value}</div>
          return cell
        })
        return option
      })
    }, () => {
      let fieldvalue = {}
      Object.keys(record).forEach(key => {
        if (this.props.form.getFieldValue(key) !== undefined) {
          fieldvalue[key] = record[key]
        }
      })
      this.props.form.setFieldsValue(fieldvalue)
    })
  }
  /**
   * @description 字段切换
   */
  fieldChange = (value) => {
    const { columns } = this.props
    let item = columns.filter(col => col.field === value)[0]
    this.setState({
      originField: item
    })
    if (this.state.contrastType !== 'static') {
      this.props.form.setFieldsValue({contrastField: ''})
    } else {
      this.props.form.setFieldsValue({contrastValue: ''})
    }
  }
  /**
   * @description 对比值类型切换
   */
  changeType = (val) => {
    this.setState({
      contrastType: val
    })
  }
  /**
   * @description 标记类型切换
   */
  changeSignType = (val) => {
    let _type = 'background '
    if (val === 'icon' || val === 'font') {
      _type = 'font '
    }
    let newState = {
      signType: val,
      selectIcon: ''
    }
    if (val !== 'icon') {
      newState.options = this.state.options.map(option => {
        option.children = option.children.map(cell => {
          cell.label = <div className={_type + cell.value}>{cell.value}</div>
          return cell
        })
        return option
      })
    }
    this.setState(newState)
  }
  /**
   * @description 图标类型切换
   */
  changeIconType = (val) => {
    this.setState({
      icons: minkeIconSystem[val],
      selectIcon: ''
    })
    this.props.form.setFieldsValue({icon: ''})
  }
  /**
   * @description 切换图标
   */
  changeIcon = (val) => {
    this.setState({
      selectIcon: val,
      options: this.state.options.map(option => {
        option.children = option.children.map(cell => {
          cell.label = <div className={'font ' + cell.value}><Icon type={val} /></div>
          return cell
        })
        return option
      })
    })
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        values.uuid = this.state.editItem ? this.state.editItem.uuid : ''
        this.props.markChange(values)
        this.setState({
          editItem: null
        })
      }
    })
  }
  render() {
    const { columns } = this.props
    const { originField, contrastType, signType, options, selectIcon, icons } = this.state
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    let contFields = columns.filter(col => originField.field !== col.field && originField.type === col.type)
    return (
      <Form {...formItemLayout} id="model-mark-form-box" className="mingke-table">
        <Row gutter={24}>
          <Col span={6}>
            <Form.Item label={'字段'}>
              {getFieldDecorator('field', {
                initialValue: originField.field,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '字段!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={this.fieldChange}
                >
                  {columns.map(item => (
                    <Select.Option key={item.uuid} title={item.label + '(' + item.field + ')'} value={item.field}>{item.label + '(' + item.field + ')'}</Select.Option>
                  ))}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={6}>
            <Form.Item label={'对比类型'}>
              {getFieldDecorator('contrastType', {
                initialValue: 'static'
              })(
                <Radio.Group onChange={(e) => this.changeType(e.target.value)}>
                  <Radio value="static">静态</Radio>
                  <Radio value="dynamic">动态</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={6}>
            <Form.Item label={'对比方式'}>
              {getFieldDecorator('match', {
                initialValue: '=',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '对比方式!'
                  }
                ]
              })(
                <Select>
                  <Select.Option value="="> = </Select.Option>
                  <Select.Option value="!="> != </Select.Option>
                  {originField.type === 'number' ? <Select.Option value=">"> > </Select.Option> : null}
                  {originField.type === 'number' ? <Select.Option value="<"> &lt; </Select.Option> : null}
                  {originField.type === 'text' ? <Select.Option value="like"> like </Select.Option> : null}
                </Select>
              )}
            </Form.Item>
          </Col>
          {contrastType === 'static' ? <Col span={6}>
            <Form.Item label={'对比值'}>
              {getFieldDecorator('contrastValue', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '对比值!'
                  }
                ]
              })(originField.type === 'number' ? <InputNumber /> : <Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col> : null}
          {contrastType === 'dynamic' ? <Col span={6}>
            <Form.Item label={'对比字段'}>
              {getFieldDecorator('contrastField', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '对比字段!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {contFields.map(item => (
                    <Select.Option key={item.uuid} title={item.label + '(' + item.field + ')'} value={item.field}>{item.label + '(' + item.field + ')'}</Select.Option>
                  ))}
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          <Col span={6}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="卡片类型,在卡片图表中起效">
                <Icon type="question-circle" />
                {'标记'}
              </Tooltip>
            }>
              {getFieldDecorator('signType', {
                initialValue: 'background',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '标记方式!'
                  }
                ]
              })(
                <Select onChange={this.changeSignType}>
                  <Select.Option value="font">单元格(文字)</Select.Option>
                  <Select.Option value="background">单元格(背景)</Select.Option>
                  <Select.Option value="line">行</Select.Option>
                  <Select.Option value="icon">图标</Select.Option>
                  <Select.Option value="card">卡片</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          {signType === 'icon' ? <Col span={6}>
            <Form.Item label={'图标位置'}>
              {getFieldDecorator('position', {
                initialValue: 'back'
              })(
                <Radio.Group>
                  <Radio value="front">前</Radio>
                  <Radio value="back">后</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
          {signType === 'icon' ? <Col span={6}>
            <Form.Item label={'图标类型'}>
              {getFieldDecorator('iconType', {
                initialValue: 'direction'
              })(
                <Select onChange={this.changeIconType}>
                  <Select.Option value="direction">方向性图标</Select.Option>
                  <Select.Option value="hint">提示建议性图标</Select.Option>
                  <Select.Option value="edit">编辑类图标</Select.Option>
                  <Select.Option value="data">数据类图标</Select.Option>
                  <Select.Option value="trademark">品牌和标识</Select.Option>
                  <Select.Option value="normal">网站通用图标</Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          {signType === 'icon' ? <Col span={6}>
            <Form.Item label={'图标'}>
              {getFieldDecorator('icon', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '图标!'
                  }
                ]
              })(
                <Select onChange={this.changeIcon} getPopupContainer={() => document.getElementById('model-mark-form-box')}>
                  {icons.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                </Select>
              )}
            </Form.Item>
          </Col> : null}
          {(signType === 'icon' && selectIcon) || signType !== 'icon' ? <Col span={6}>
            <Form.Item label="颜色">
              {getFieldDecorator('color', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '颜色!'
                  }
                ]
              })(
                <Cascader
                  options={options}
                  placeholder=""
                  displayRender={(label, selectedOptions) => selectedOptions[0] ? selectedOptions[0].label + (selectedOptions[1] ? ' / ' + selectedOptions[1].value : '') : ''}
                  getPopupContainer={() => document.getElementById('model-mark-form-box')}
                />
              )}
            </Form.Item>
          </Col> : null}
          <Col span={signType === 'icon' ? (!selectIcon ? 24 : 18) : 12} style={{textAlign: 'right', marginBottom: 10}}>
            <Button onClick={this.handleConfirm} type="primary" className="mk-green">
              保存
            </Button>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(UniqueForm)
src/menu/components/table/normal-table/columncomponent/markcolumn/markform/index.scss
New file
@@ -0,0 +1,7 @@
#model-mark-form-box {
  .ant-select-dropdown-menu-item {
    .anticon {
      font-size: 18px;
    }
  }
}
src/menu/components/table/normal-table/index.jsx
@@ -4,7 +4,7 @@
import { is, fromJS } from 'immutable'
import { Icon, Popover, Modal } from 'antd'
// import asyncComponent from '@/utils/asyncComponent'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import MKEmitter from '@/utils/events.js'
@@ -12,10 +12,12 @@
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import SearchComponent from '@/templates/sharecomponent/searchcomponent'
import './index.scss'
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const SearchComponent = asyncComponent(() => import('@/templates/sharecomponent/searchcomponent'))
const ActionComponent = asyncComponent(() => import('@/menu/actioncomponent'))
const ColumnComponent = asyncComponent(() => import('./columncomponent'))
// const WrapComponent = asyncIconComponent(() => import('../data-card/wrapsetting'))
// const SearchComponent = asyncComponent(() => import('@/menu/searchcomponent'))
@@ -46,17 +48,31 @@
        parentId: card.parentId || '',
        format: 'array',    // 组件属性 - 数据格式
        pageable: true,     // 组件属性 - 是否可分页
        switchable: false,  // 组件属性 - 数据是否可切换
        switchable: true,   // 组件属性 - 数据是否可切换
        dataName: card.dataName || '',
        width: 12,
        search: [],
        width: 24,
        search: [
          { origin: true, uuid: Utils.getuuid(), label: 'label', type: 'text', match: 'like' },
          { origin: true, uuid: Utils.getuuid(), label: 'label', type: 'select', match: 'equal' },
          { origin: true, uuid: Utils.getuuid(), label: 'label', type: 'date', match: 'greater' }
        ],
        action: [
          { origin: true, uuid: Utils.getuuid(), label: '添加', intertype: 'system', OpenType: 'pop', icon: 'plus', class: 'green' },
          { origin: true, uuid: Utils.getuuid(), label: '修改', intertype: 'system', OpenType: 'pop', icon: 'form', class: 'purple' },
          { origin: true, uuid: Utils.getuuid(), label: '删除', intertype: 'system', OpenType: 'prompt', icon: 'delete', class: 'red' }
        ],
        name: card.name,
        subtype: card.subtype,
        setting: { interType: 'system' },
        wrap: { name: card.name, width: 12 },
        wrap: { name: card.name, width: 24 },
        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
        headerStyle: { fontSize: '16px' },
        columns: [],
        cols: [
          { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 },
          { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 },
          { origin: true, uuid: Utils.getuuid(), Align: 'left', label: 'label', field: '', Hide: 'false', IsSort: 'true', type: 'text', Width: 120 }
        ],
        scripts: []
      }
      
@@ -171,53 +187,91 @@
  }
  addSearch = () => {
    const { card } = this.state
    let card = fromJS(this.state.card).toJS()
    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.type = 'text'
    newcard.match = '='
    // 注册事件-添加搜索
    MKEmitter.emit('addSearch', card.uuid, newcard)
    card.search.push(newcard)
    this.setState({card})
  }
  addButton = () => {
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.label = 'label'
    newcard.sqlType = ''
    newcard.Ot = 'requiredSgl'
    newcard.OpenType = 'pop'
    newcard.icon = ''
    newcard.class = 'green'
    newcard.intertype = card.setting.interType || 'system'
    newcard.innerFunc = card.setting.innerFunc || ''
    newcard.sysInterface = card.setting.sysInterface || ''
    newcard.outerFunc = card.setting.outerFunc || ''
    newcard.interface = card.setting.interface || ''
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.errorTime = 10
    newcard.verify = null
    newcard.show = 'button'
    // 注册事件-添加按钮
    MKEmitter.emit('addButton', card.uuid, newcard)
  }
  /**
   * @description 更新搜索条件配置信息
   */
  updatesearch = (config) => {
  updateconfig = (config) => {
    this.setState({
      card: config
    })
    this.props.updateConfig(config)
  }
  setSubConfig = (btn) => {
  }
  updateaction = (config) => {
  }
  render() {
    const { menu } = this.props
    const { card } = this.state
    return (
      <div className="menu-normal-table-edit-box" style={{...card.style, height: card.wrap.height}}>
        <SearchComponent config={card} updatesearch={this.updatesearch}/>
        <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" />
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            {menu && menu.MenuType !== 'billPrint' ? <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" /> : null}
            {menu && menu.MenuType !== 'billPrint' ? <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" /> : null}
            {/* {menu ? <WrapComponent config={card} MenuType={menu.MenuType} updateConfig={this.updateComponent} /> : null} */}
            <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}
            <SettingComponent config={card} updateConfig={this.updateComponent} />
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <SearchComponent config={card} updatesearch={this.updateconfig}/>
        <ActionComponent
          type="normaltable"
          config={card}
          updateaction={this.updateComponent}
        />
        <ColumnComponent config={card} updatecolumn={this.updateconfig}/>
      </div>
    )
  }
src/menu/components/table/normal-table/index.scss
@@ -7,32 +7,18 @@
  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;
  .model-table-search-list {
    padding: 10px 0px 0px;
    min-height: 65px;
    >.anticon-question-circle {
      display: none;
    }
    .page-card {
      background: transparent;
    }
  }
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  .model-table-search-list.length0 {
    display: none;
  }
  .anticon-tool {
    position: absolute;
@@ -44,32 +30,12 @@
    padding: 5px;
    background: rgba(255, 255, 255, 0.55);
  }
  .card-item {
    overflow-y: hidden;
    position: relative;
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
    min-height: 20px;
  }
  .card-item:hover {
    box-shadow: 0px 0px 2px #e8e8e8;
  }
  .model-menu-card-cell-list .card-detail-row > .anticon-plus {
    position: absolute;
    right: -30px;
    font-size: 16px;
  }
  .model-menu-action-list {
    line-height: 40px;
    .ant-row > .anticon-plus {
      position: absolute;
      right: -30px;
      font-size: 16px;
    }
    padding: 15px 0px 10px;
  }
  .model-menu-action-list.length0 {
    display: none;
  }
  .card-add-button {
    text-align: right;
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -2,6 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Chart } from '@antv/g2'
import { connect } from 'react-redux'
import DataSet from '@antv/data-set'
import { Spin, Empty, Select, notification } from 'antd'
@@ -11,6 +12,7 @@
import Api from '@/api'
import Utils from '@/utils/utils.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import { modifyTabview } from '@/store/action'
import './index.scss'
const ExcelOutButton = asyncComponent(() => import('@/tabviews/zshare/actionList/exceloutbutton'))
@@ -1157,6 +1159,55 @@
      }
    }
    if (plot.linkmenu && plot.linkmenu.length > 0) {
      let menu_id = plot.linkmenu[plot.linkmenu.length - 1]
      let menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || ''
      chart.on('element:dblclick', (ev) => {
        if (!menu) {
          notification.warning({
            top: 92,
            message: '菜单已删除或没有访问权限!',
            duration: 5
          })
          return
        }
        try {
          let data = ev.data.data
          let primaryId = ''
          if (this.state.config.setting.primaryKey && data) {
            primaryId = data[this.state.config.setting.primaryKey] || ''
          }
          let newtab = {
            ...menu,
            selected: true,
            param: {
              BID: primaryId,
              data: data
            }
          }
          let tabs = this.props.tabviews.filter(tab => {
            tab.selected = false
            return tab.MenuID !== newtab.MenuID
          })
          if (this.props.tabviews.length !== tabs.length) {
            this.props.modifyTabview(fromJS(tabs).toJS())
          }
          this.setState({}, () => {
            tabs.push(newtab)
            this.props.modifyTabview(tabs)
          })
        } catch {
          console.warn('菜单打开失败!')
        }
      })
    }
    chart.render()
  }
@@ -1237,4 +1288,17 @@
  }
}
export default LineChart
const mapStateToProps = (state) => {
  return {
    tabviews: state.tabviews,
    permMenus: state.permMenus,
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews))
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(LineChart)
src/tabviews/custom/components/chart/antv-pie/index.jsx
@@ -551,7 +551,6 @@
  }
}
const mapStateToProps = (state) => {
  return {
    tabviews: state.tabviews,
src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -179,7 +179,7 @@
    const { config } = this.props
    let LText_field = []
    let diffUser = false
    let LText = params.map((item, index) => {
    let _LText = params.map((item, index) => {
      let _script = item.script
      if (index === 0) {
@@ -199,11 +199,15 @@
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText: _LText.join(' union all '),
      LText_field: LText_field.join(' union all ')
    }
    param.LText = Utils.formatOptions(param.LText)
    let { LText, LText1, LText2 } = Utils.sPCInUpDeFormatOptions(param.LText)
    param.LText1 = LText1
    param.LText = LText
    param.LText2 = LText2
    param.LText_field = Utils.formatOptions(param.LText_field)
    if (config.cacheUseful === 'true') {
src/tabviews/custom/index.jsx
@@ -374,7 +374,7 @@
    const { config } = this.state
    let LText_field = []
    let diffUser = false
    let LText = params.map((item, index) => {
    let _LText = params.map((item, index) => {
      let _script = item.script
      if (index === 0) {
@@ -392,14 +392,19 @@
      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(item.sql))}' as LText,'${window.btoa(window.encodeURIComponent(_script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
    })
    // 把大接口sPC_Get_structured_data的ltext拆成三份,第一段:@LText1,第二段@LText,第三段@LText2
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText: _LText.join(' union all '),
      LText_field: LText_field.join(' union all '),
      BID: this.state.BID || ''
    }
    param.LText = Utils.formatOptions(param.LText)
    let { LText, LText1, LText2 } = Utils.sPCInUpDeFormatOptions(param.LText)
    param.LText1 = LText1
    param.LText = LText
    param.LText2 = LText2
    param.LText_field = Utils.formatOptions(param.LText_field)
    if (config.cacheUseful === 'true') {
src/templates/comtableconfig/source.jsx
@@ -74,8 +74,7 @@
        origin: true,
        uuid: Utils.getuuid(),
        label: 'add',
        intertype: 'inner',
        method: 'POST',
        intertype: 'system',
        Ot: 'notRequired',
        position: 'toolbar',
        execSuccess: 'grid',
@@ -89,10 +88,9 @@
        origin: true,
        uuid: Utils.getuuid(),
        label: 'update',
        intertype: 'inner',
        method: 'POST',
        intertype: 'system',
        Ot: 'requiredSgl',
        position: 'grid',
        position: 'toolbar',
        execSuccess: 'grid',
        execError: 'never',
        errorTime: 15,
@@ -104,8 +102,7 @@
        origin: true,
        uuid: Utils.getuuid(),
        label: 'delete',
        intertype: 'inner',
        method: 'POST',
        intertype: 'system',
        Ot: 'required',
        position: 'toolbar',
        execSuccess: 'grid',
src/templates/formtabconfig/dragelement/index.jsx
@@ -127,7 +127,6 @@
        newcard.linkTab = ''
        newcard.class = 'default'
        newcard.intertype = 'inner'
        newcard.method = 'POST'
        newcard.position = 'toolbar'
        newcard.execSuccess = 'grid'
        newcard.execError = 'never'
src/templates/sharecomponent/actioncomponent/dragaction/index.jsx
@@ -106,7 +106,6 @@
      newcard.icon = ''
      newcard.class = 'default'
      newcard.intertype = 'system'
      newcard.method = 'POST'
      newcard.position = 'toolbar'
      newcard.execSuccess = 'grid'
      newcard.execError = 'never'
src/templates/sharecomponent/actioncomponent/index.jsx
@@ -62,7 +62,7 @@
    if (!is(fromJS(nextProps.config.action), fromJS(this.props.config.action)) && !is(fromJS(nextProps.config.action), fromJS(actionlist))) {
      let len = nextProps.config.action.length
      let item = nextProps.config.action[len - 1]
      if (item.copyType && item.focus) {
      if (item && item.focus) {
        this.handleAction(item)
      }
      this.setState({actionlist: fromJS(nextProps.config.action).toJS()})
src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
@@ -2,7 +2,7 @@
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Col } from 'antd'
import { Col, Button } from 'antd'
import Utils from '@/utils/utils.js'
import Card from './card'
import './index.scss'
@@ -138,7 +138,17 @@
          />
        </Col>
      ))}
      {cards.length > 0 ? <Col key="action" className="action" span={6}>
        <div className="ant-row ant-form-item" style={{lineHeight: '40px', height: '55px', marginBottom: 0}}>
          <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8">
          </div>
          <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16">
            <Button type="primary">搜索</Button>
            <Button style={{ marginLeft: 8 }}>重置</Button>
            <div style={{position: 'absolute', top: 0, bottom: 0, left: 0, right: 0}}></div>
          </div>
        </div>
      </Col> : null}
      {cards.length === 0 ?
        <div className="common-drawarea-placeholder">
          {placeholder}
src/templates/sharecomponent/searchcomponent/index.jsx
@@ -48,7 +48,7 @@
    if (!is(fromJS(nextProps.config.search), fromJS(this.props.config.search)) && !is(fromJS(nextProps.config.search), fromJS(searchlist))) {
      let len = nextProps.config.search.length
      let item = nextProps.config.search[len - 1]
      if (item.copyType && item.focus) {
      if (item && item.focus) {
        this.handleSearch(item)
      }
      this.setState({searchlist: fromJS(nextProps.config.search).toJS()})
@@ -277,7 +277,7 @@
    const { dict, searchlist, visible, sqlVerifing, card } = this.state
    return (
      <div className="model-table-search-list">
      <div className={'model-table-search-list length' + searchlist.length}>
        <Tooltip placement="bottomLeft" overlayClassName="middle" title={dict['model.tooltip.search.guide']}>
          <Icon type="question-circle" />
        </Tooltip>
src/templates/subtableconfig/source.jsx
@@ -73,8 +73,7 @@
        origin: true,
        uuid: Utils.getuuid(),
        label: 'add',
        intertype: 'inner',
        method: 'POST',
        intertype: 'system',
        Ot: 'notRequired',
        position: 'toolbar',
        execSuccess: 'grid',
@@ -88,8 +87,7 @@
        origin: true,
        uuid: Utils.getuuid(),
        label: 'update',
        intertype: 'inner',
        method: 'POST',
        intertype: 'system',
        Ot: 'requiredSgl',
        position: 'grid',
        execSuccess: 'grid',
@@ -103,8 +101,7 @@
        origin: true,
        uuid: Utils.getuuid(),
        label: 'delete',
        intertype: 'inner',
        method: 'POST',
        intertype: 'system',
        Ot: 'required',
        position: 'toolbar',
        execSuccess: 'grid',
src/utils/utils.js
@@ -252,11 +252,21 @@
      return window.btoa(_value)
    }
    let len = value.length
    // 注:LText 与 LText1 顺序颠倒
    return {
      LText: encodesql(value.substring(5000, 10000)),
      LText1: encodesql(value.substring(0, 5000)),
      LText2: encodesql(value.substring(10000))
    if (len > 1000) {
      let limit = Math.floor(len / 3)
      return {
        LText1: encodesql(value.substring(0, limit)),
        LText: encodesql(value.substring(limit, limit * 2)),
        LText2: encodesql(value.substring(limit * 2))
      }
    } else {
      return {
        LText1: '',
        LText: encodesql(value),
        LText2: ''
      }
    }
  }
src/views/menudesign/index.jsx
@@ -97,7 +97,6 @@
    }
    let _config = fromJS(config).toJS()
    delete _config.fstMenuList
    delete _config.tableFields
    if (!is(fromJS(oriConfig), fromJS(_config))) {
@@ -262,7 +261,6 @@
    }
    let _config = fromJS(config).toJS()
    delete _config.fstMenuList
    delete _config.tableFields
    let param = {
@@ -418,13 +416,6 @@
    })
  }
  initMenuList = (msg) => {
    let config = {...this.state.config, ...msg}
    this.setState({config})
    this.props.modifyCustomMenu(config)
  }
  onEnabledChange = () => {
    const { config } = this.state
@@ -518,7 +509,6 @@
                      parentId={ParentId}
                      MenuName={MenuName}
                      MenuNo={MenuNo}
                      initMenuList={this.initMenuList}
                      updateConfig={this.updateConfig}
                    /> : null}
                    {config && MenuType === 'home' ? <HomeForm
src/views/menudesign/menuform/index.jsx
@@ -1,6 +1,5 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, notification, Radio, Icon, Tooltip, InputNumber } from 'antd'
import Api from '@/api'
@@ -15,7 +14,6 @@
    MenuName: PropTypes.string,
    MenuNo: PropTypes.string,
    parentId: PropTypes.string,
    initMenuList: PropTypes.func,
    updateConfig: PropTypes.func
  }
@@ -26,7 +24,7 @@
  }
  UNSAFE_componentWillMount () {
    const { MenuId } = this.props
    const { MenuId, config } = this.props
    let _param = {func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}
    if (options.sysType !== 'cloud' && window.GLOB.systemType !== 'production') {
      _param.linkurl = window.GLOB.linkurl
@@ -89,8 +87,8 @@
            smenulist = item.children
          }
        })
        this.props.initMenuList({fstMenuList: fromJS(menulist).toJS(), fstMenuId: thdMenu ? thdMenu.FstId : ''})
        sessionStorage.setItem('fstMenuList', JSON.stringify(menulist))
        this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
        this.setState({
          fstMenuId: thdMenu ? thdMenu.FstId : '',
src/views/mobdesign/index.jsx
@@ -192,77 +192,6 @@
    })
  }
  testFunc = () => {
    let datas = [{
      name: 'a',
      arr_field: 'MapCode,Country',
      par_tablename: '',
      type: '',
      primaryKey: 'MapCode',
      foreign_key: '',
      sql: `select MapCode,Country from @tc1`,
      script: `declare @tc1 table (MapCode nvarchar(50),Country nvarchar(50)) insert into @tc1 (MapCode,Country) select MapCode,Country from sMap where Province=''`
    }, {
      name: 'b',
      arr_field: 'MapCode,Province,ParMapCode',
      par_tablename: 'a',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Province,ParMapCode from @tc2`,
      script: `declare @tc2 table (MapCode nvarchar(50),Province nvarchar(50),ParMapCode nvarchar(50)) insert into @tc2 (MapCode,Province,ParMapCode) select MapCode,Province,ParMapCode from sMap where Province!='' and City=''`
    }, {
      name: 'c',
      arr_field: 'MapCode,City,ParMapCode',
      par_tablename: 'b',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,City,ParMapCode from @tc3`,
      script: `declare @tc3 table (MapCode nvarchar(50),City nvarchar(50),ParMapCode nvarchar(50)) insert into @tc3 (MapCode,City,ParMapCode) select MapCode,City,ParMapCode from sMap where City!='' and Area=''`
    }, {
      name: 'd',
      arr_field: 'MapCode,Area,ParMapCode',
      par_tablename: 'c',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Area,ParMapCode from sMap where Area!=''`,
      script: ``
    }]
    let LText = datas.map((item, index) => {
      // item.par_tablename = ''
      // item.foreign_key = ''
      let _orderBy = 'MapCode desc'
      let _search = ''
      let _sql = `select top 1000 ${item.arr_field} from (select ${item.arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from (${item.sql}) tb ${_search}) tmptable order by tmptable.rows `
      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(_sql))}' as LText,'${window.btoa(window.encodeURIComponent(item.script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
    })
    let LText_field = []
    datas.forEach(item => {
      item.arr_field.split(',').forEach(cell => {
        LText_field.push(`Select '${item.name}' as tablename,'${cell}' as fieldname,'nvarchar(50)' as field_type`)
      })
    })
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText_field: LText_field.join(' union all ')
    }
    param.LText = Utils.formatOptions(param.LText)
    param.LText_field = Utils.formatOptions(param.LText_field)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    Api.getLocalConfig(param)
  }
  // save = () => {
  //   html2canvas(document.getElementById('view')).then(canvas => {
  //     let imgUri = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); // 获取生成的图片的url