king
2020-12-08 655ac8aef54bc134c1420c19975023182a10cae4
2020-12-08
20个文件已修改
6个文件已添加
2666 ■■■■ 已修改文件
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.jsx 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.scss 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/markcolumn/index.jsx 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/markcolumn/index.scss 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/markcolumn/markform/index.jsx 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/markcolumn/markform/index.scss 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 89 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/utils.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 810 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.scss 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/normalTable/index.jsx 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 426 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/columncomponent/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/fieldscomponent/index.jsx 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/tablecomponent/index.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/customscript/index.jsx 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/customscript/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -75,6 +75,14 @@
      options: fields
    },
    {
      type: 'select',
      key: 'nameField',
      label: Formdict['model.name'] + Formdict['model.form.field'],
      initVal: card.nameField || '',
      required: false,
      options: [{uuid: 'empty', field: '', label: '空'}, ...fields]
    },
    {
      type: 'number',
      key: 'Width',
      min: 20,
@@ -235,7 +243,7 @@
      readonly: false
    },
    {
      type: 'select',
      type: 'radio',
      key: 'lenWidRadio',
      label: '长宽比',
      initVal: card.lenWidRadio || '1:1',
@@ -249,6 +257,27 @@
    },
    {
      type: 'radio',
      key: 'picSort',
      label: '图片排列',
      initVal: card.picSort || '1',
      tooltip: '同一单元格内,含有多张图片时的列数。',
      required: false,
      options: [{
        value: '1',
        text: '1'
      }, {
        value: '2',
        text: '2'
      }, {
        value: '3',
        text: '3'
      }, {
        value: '4',
        text: '4'
      }]
    },
    {
      type: 'radio',
      key: 'scale',
      label: Formdict['header.form.clickscale'],
      initVal: card.scale || 'false',
src/menu/components/table/normal-table/columns/editColumn/index.jsx
@@ -10,9 +10,9 @@
const columnTypeOptions = {
  text: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'textFormat', 'blacklist', 'perspective', 'rowspan'],
  number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'blacklist', 'perspective', 'sum'],
  link: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'joint', 'Width', 'blacklist'],
  link: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'joint', 'Width', 'blacklist', 'nameField'],
  textarea: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'blacklist'],
  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'blacklist', 'scale', 'lenWidRadio'],
  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'blacklist', 'scale', 'lenWidRadio', 'picSort'],
  colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
  custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
  action: ['label', 'type', 'Align', 'Width']
@@ -213,7 +213,7 @@
                  getPopupContainer={() => document.getElementById('columnwinter')}
                >
                  {item.options.map((option, index) =>
                    <Select.Option key={`${index}`} value={option.value || option.field}>
                    <Select.Option key={`${option.value || option.field}${index}`} value={option.value || option.field}>
                      {option.text || option.label}
                    </Select.Option>
                  )}
src/menu/components/table/normal-table/columns/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Form, Popover, Icon, Modal } from 'antd'
import { Table, Form, Popover, Icon, Modal, message } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -15,6 +15,7 @@
const { confirm } = Modal
const coldict = localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const EditColumn = asyncIconComponent(() => import('./editColumn'))
const MarkColumn = asyncIconComponent(() => import('./markcolumn'))
const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
class HeaderCol extends Component {
@@ -30,6 +31,11 @@
    })
  }
  updateMarks = (vals) => {
    const { column } = this.props
    this.props.updateCol({...column, marks: vals})
  }
  shouldComponentUpdate (nextProps, nextState) {
    if (!nextProps.column) return false
@@ -40,18 +46,19 @@
  }
  render() {
    const { connectDragSource, connectDropTarget, moveCol, addElement, editColumn, deleteCol, index, column, align, fields, children, ...restProps } = this.props
    const { connectDragSource, connectDropTarget, moveCol, addElement, updateCol, editColumn, deleteCol, index, column, align, fields, children, ...restProps } = this.props
    if (index !== undefined) {
      return connectDragSource(
        connectDropTarget(<th {...restProps} index={index} style={{ cursor: 'move', textAlign: align }}>
          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
              {column && (column.type === 'custom' || column.type === 'colspan' || column.type === 'action') ?
              {column && ['custom', 'colspan', 'action'].includes(column.type) ?
                <Icon className="plus" title="添加" type="plus" onClick={() => this.props.addElement(column)} /> : null
              }
              <Icon className="edit" title="编辑" type="edit" onClick={() => this.props.editColumn(column)} />
              <Icon className="close" title="删除" type="delete" onClick={this.deleteCol} />
              {column && ['text', 'number'].includes(column.type) ? <MarkColumn dict={coldict} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
            </div>
          } trigger="hover">
            {children}
@@ -68,6 +75,7 @@
              }
              <Icon className="edit" title="编辑" type="edit" onClick={() => this.props.editColumn(column)} />
              <Icon className="close" title="删除" type="delete" onClick={this.deleteCol} />
              {column && ['text', 'number'].includes(column.type) ? <MarkColumn dict={coldict} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
            </div>
          } trigger="hover">
            {children}
@@ -145,6 +153,7 @@
      return (
        <td style={{...style, minWidth: column.Width || 100}} className={className}>
          {column.field}
          {column.marks && column.marks.length > 0 ? <Icon className="profile" type="ant-design"/> : null}
        </td>
      )
    } else {
@@ -166,7 +175,8 @@
  state = {
    data: [{uuid: Utils.getuuid()}],
    columns: [],
    fields: []
    fields: [],
    lineMarks: []
  }
  UNSAFE_componentWillMount () {
@@ -174,7 +184,8 @@
    this.setState({
      columns: fromJS(config.cols).toJS(),
      fields: fromJS(config.columns).toJS()
      fields: fromJS(config.columns).toJS(),
      lineMarks: config.lineMarks ? fromJS(config.lineMarks).toJS() : []
    })
  }
@@ -338,9 +349,41 @@
    })
  }
  updateLineMarks = (vals) => {
    this.setState({
      lineMarks: vals
    }, () => {
      this.props.updatecolumn({...this.props.config, lineMarks: vals})
    })
  }
  /**
   * @description 显示列复制
   */
  copycolumn = () => {
    const { columns } = this.state
    let oInput = document.createElement('input')
    let val = {
      copyType: 'columns',
      columns: columns
    }
    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)
  }
  render() {
    const { config } = this.props
    const { fields, card } = this.state
    const { fields, card, lineMarks } = this.state
    const components = {
      header: {
        cell: DragableHeaderCol
@@ -374,7 +417,9 @@
          }),
          onHeaderCell: () => ({
            column: cell,
            fields: fields,
            align: cell.Align,
            updateCol: this.updateCol,
            addElement: this.addElement,
            editColumn: this.editColumn,
            deleteCol: this.deleteCol,
@@ -383,8 +428,10 @@
        onHeaderCell: () => ({
          index,
          column: col,
          fields: fields,
          align: col.Align,
          moveCol: this.moveCol,
          updateCol: this.updateCol,
          addElement: this.addElement,
          editColumn: this.editColumn,
          deleteCol: this.deleteCol,
@@ -394,6 +441,10 @@
    return (
      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType}`}>
        <div className="col-control">
          <Icon title="复制" type="copy" onClick={this.copycolumn} />
          <MarkColumn dict={coldict} columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
        </div>
        <DndProvider>
          <Table
            rowKey="uuid"
src/menu/components/table/normal-table/columns/index.scss
@@ -1,10 +1,19 @@
.normal-table-columns {
  position: relative;
  .ant-table-body {
    overflow-x: auto;
    padding-bottom: 20px;
    tr td:not(.ant-table-selection-column) {
      position: relative;
      padding: 12px 8px;
      background: #ffffff;
      >.profile {
        position: absolute;
        top: 2px;
        right: 2px;
        color: purple;
        font-size: 12px;
      }
    }
    tr:hover td {
      background: #ffffff!important;
@@ -32,6 +41,23 @@
      }
    }
  }
  .col-control {
    position: absolute;
    z-index: 2;
    right: 0;
    top: -25px;
    >i, >div > i {
      font-size: 16px;
      margin-right: 10px;
      cursor: pointer;
    }
    >.anticon-copy {
      color: #26C281;
    }
    >div >.profile {
      color: purple;
    }
  }
}
.normal-table-columns.false {
  .ant-pagination {
src/menu/components/table/normal-table/columns/markcolumn/index.jsx
New file
@@ -0,0 +1,322 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Icon, Modal } from 'antd'
import Utils from '@/utils/utils.js'
import asyncComponent from '@/utils/asyncComponent'
import MarkForm from './markform'
import './index.scss'
import { minkeIconSystem } from '@/utils/option.js'
import '@/assets/css/table.scss'
const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
class MarkColumn extends Component {
  static propTpyes = {
    columns: PropTypes.array,  // 显示列
    dict: PropTypes.object,    // 字典项
    marks: PropTypes.object,
    onSubmit: PropTypes.func
  }
  state = {
    marks: null,
    columns: null,
    visible: false,
    markColumns: [
      {
        title: '对比字段',
        dataIndex: 'field',
        width: '16%',
        editable: true,
        inputType: 'cascader',
        options: [],
        render: text => {
          return (
            <div>{text[0]}  VS  {text[2] ? text[2] : '静态值'}</div>
          )
        }
      },
      {
        title: '对比方式',
        dataIndex: 'match',
        width: '16%',
        editable: true,
        inputType: 'select',
        options: [
          { value: '=', text: '=' },
          { value: '!=', text: '!=' },
          { value: '>', text: '>' },
          { value: '<', text: '<' },
          { value: 'like', text: 'like' }
        ]
      },
      {
        title: '对比值',
        dataIndex: 'contrastValue',
        width: '16%',
        editable: true,
        required: false,
        inputType: 'input'
      },
      {
        title: '颜色',
        dataIndex: 'color',
        inputType: 'color',
        editable: true,
        width: '16%',
        render: text => {
          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
        }
      },
      {
        title: '标记方式',
        dataIndex: 'signType',
        width: '16%',
        editable: true,
        inputType: 'cascader',
        options: [],
        render: text => {
          let sign = {
            'font': '文字颜色',
            'background': '背景',
            'underline': '下划线',
            'line-through': '中划线',
            'icon': '图标'
          }
          return (
            <div>{sign[text[0]]} {text[3] ? <Icon type={text[3]} /> : null}</div>
          )
        }
      }
    ]
  }
  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 })
  }
  resetMark = () => {
    const { marks, columns, type } = this.props
    let options = columns.map(col => {
      return {
        value: col.field,
        label: col.label,
        isLeaf: false,
        children: [
          {
            value: 'static',
            label: '静态值'
          },
          {
            value: 'dynamic',
            label: '动态值',
            children: columns.map(cell => {
              return {
                value: cell.field,
                label: cell.label
              }
            })
          }
        ]
      }
    })
    let icons = [
      {
        value: 'direction',
        label: '方向性图标',
        children: minkeIconSystem.direction.map(cell => {
          return {
            value: cell,
            label: (<Icon type={cell} />)
          }
        })
      },
      {
        value: 'hint',
        label: '提示建议性图标',
        children: minkeIconSystem.hint.map(cell => {
          return {
            value: cell,
            label: (<Icon type={cell} />)
          }
        })
      },
      {
        value: 'edit',
        label: '编辑类图标',
        children: minkeIconSystem.edit.map(cell => {
          return {
            value: cell,
            label: (<Icon type={cell} />)
          }
        })
      },
      {
        value: 'data',
        label: '数据类图标',
        children: minkeIconSystem.data.map(cell => {
          return {
            value: cell,
            label: (<Icon type={cell} />)
          }
        })
      },
      {
        value: 'trademark',
        label: '品牌和标识',
        children: minkeIconSystem.trademark.map(cell => {
          return {
            value: cell,
            label: (<Icon type={cell} />)
          }
        })
      },
      {
        value: 'normal',
        label: '网站通用图标',
        children: minkeIconSystem.normal.map(cell => {
          return {
            value: cell,
            label: (<Icon type={cell} />)
          }
        })
      }
    ]
    let signs = [
      {
        value: 'font',
        label: '文字颜色'
      },
      {
        value: 'background',
        label: '背景'
      },
      {
        value: 'underline',
        label: '下划线'
      },
      {
        value: 'line-through',
        label: '中划线'
      },
      {
        value: 'icon',
        label: '图标',
        children: [
          {
            value: 'front',
            label: '内容前',
            children: icons
          },
          {
            value: 'back',
            label: '内容后',
            children: icons
          }
        ]
      }
    ]
    if (type === 'line') {
      signs.pop()
    }
    this.setState({
      visible: true,
      marks: marks ? fromJS(marks).toJS() : [],
      markColumns: this.state.markColumns.map(col => {
        if (col.dataIndex === 'field') {
          col.options = options
        } else if (col.dataIndex === 'signType') {
          col.options = signs
        }
        return col
      }),
      options,
      signs
    })
  }
  markSubmit = () => {
    this.setState({
      visible: false
    })
    let marks = this.state.marks.map(item => {
      if (item.signType[0] === 'background') {
        try {
          let colors = item.color.match(/\d+/g)
          if ((colors[0] * 0.299 + colors[1] * 0.578 + colors[2] * 0.114) * colors[3] < 192) {
            item.fontColor = '#ffffff'
          } else {
            item.fontColor = ''
          }
        } catch {
          item.fontColor = ''
        }
      }
      return item
    })
    this.props.onSubmit(marks)
  }
  render() {
    const { dict } = this.props
    const { marks, markColumns, visible, options, signs } = this.state
    return (
      <div style={{display: 'inline-block'}}>
        <Icon className="profile" title="标记" type="ant-design" onClick={this.resetMark} />
        <Modal
          wrapClassName="model-table-column-mark-modal"
          title={'标记设置'}
          visible={visible}
          width={'75vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          okText={dict['model.submit']}
          onOk={this.markSubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <MarkForm dict={dict} signs={signs} columns={options} markChange={this.markChange}/>
          <EditTable data={marks} columns={markColumns} onChange={(marks) => this.setState({marks})}/>
        </Modal>
      </div>
    )
  }
}
export default MarkColumn
src/menu/components/table/normal-table/columns/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/columns/markcolumn/markform/index.jsx
New file
@@ -0,0 +1,130 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Select, Button, Input, Icon, Cascader, Tooltip } from 'antd'
import ColorSketch from '@/mob/colorsketch'
import './index.scss'
class UniqueForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,         // 字典项
    columns: PropTypes.array,       // 列名集合
    signs: PropTypes.array,         // 标记类型
    markChange: PropTypes.func      // 修改函数
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        this.props.markChange(values)
      }
    })
  }
  render() {
    const { columns, signs } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="normal-table-mark-form">
        <Row gutter={24}>
          <Col span={6}>
            <Form.Item label={'对比字段'}>
              {getFieldDecorator('field', {
                initialValue: [],
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '对比字段!'
                  }
                ]
              })(
                <Cascader options={columns} placeholder=""/>
              )}
            </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>
                  <Select.Option value=">"> > </Select.Option>
                  <Select.Option value="<"> &lt; </Select.Option>
                  <Select.Option value="like"> like </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={6}>
            <Form.Item label={<Tooltip placement="topLeft" title="对比静态值时,需要填写对比值,默认为空。">
                <Icon type="question-circle" />
                {'对比值'}
              </Tooltip>
            }>
              {getFieldDecorator('contrastValue', {
                initialValue: ''
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={6}>
            <Form.Item label="颜色">
              {getFieldDecorator('color', {
                initialValue: 'rgba(0, 0, 0, 0.85)',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '颜色!'
                  }
                ]
              })(
                <ColorSketch />
              )}
            </Form.Item>
          </Col>
          <Col span={6}>
            <Form.Item label="标记方式">
              {getFieldDecorator('signType', {
                initialValue: [],
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '标记方式!'
                  }
                ]
              })(
                <Cascader options={signs} placeholder=""/>
              )}
            </Form.Item>
          </Col>
          <Col span={18} 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/columns/markcolumn/markform/index.scss
New file
@@ -0,0 +1,17 @@
.normal-table-mark-form {
  .anticon-question-circle {
    color: #c49f47;
    position: relative;
    left: -3px;
  }
  .color-sketch-block {
    position: relative;
    top: 5px;
    .color-sketch-block-box {
      width: 100%;
    }
    .color-sketch-value {
      display: none;
    }
  }
}
src/menu/datasource/verifycard/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Tabs, Table, Popconfirm, Icon, notification, Modal, Typography, Spin } from 'antd'
import { Form, Tabs, Popconfirm, Icon, notification, Modal, Typography, Spin } from 'antd'
import moment from 'moment'
import Api from '@/api'
@@ -94,15 +94,24 @@
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '65%',
        render: (text) => (
          <Paragraph copyable ellipsis={{ rows: 4, expandable: true }}>{text}</Paragraph>
        )
        width: '72%',
        render: (text) => {
          let title = text.match(/^\s*\/\*.+\*\//)
          title = title && title[0] ? title[0] : ''
          text = title ? text.replace(title, '') : text
          return (
            <div>
              {title ? <span style={{color: '#a50'}}>{title}</span> : null}
              <Paragraph copyable ellipsis={{ rows: 4, expandable: true }}>{text}</Paragraph>
            </div>
          )
        }
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '15%',
        width: '13%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
@@ -120,13 +129,11 @@
      {
        title: '操作',
        align: 'center',
        width: '20%',
        width: '15%',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div>
          (<div style={{textAlign: 'center'}}>
            <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" onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
            <span className="operation-btn" onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
            <span className="operation-btn" title={this.props.dict['model.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
@@ -178,10 +185,6 @@
    let _setting = fromJS(config.setting).toJS()
    // if (_setting.varMark === undefined) {
    //   _setting.varMark = this.getMark(Marks)
    // }
    this.setState({
      columns: fromJS(config.columns).toJS(),
      setting: _setting,
@@ -191,27 +194,6 @@
    })
    this.getsysScript()
  }
  getMark = (varMarks) => {
    let m = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
    let i = 0
    let n = 25
    let name = ''
    while (!name) {
      name = `${m[n]}${m[i]}_`
      if (varMarks.includes(name) && n > 0) {
        i++
        if (i >= 26) {
          n--
          i = 0
        }
        name = ''
      }
    }
    return name
  }
  getsysScript = () => {
@@ -313,30 +295,6 @@
    this.setState({ scripts })
  }
  handleUpDown = (record, direction) => {
    let scripts = fromJS(this.state.scripts).toJS()
    let index = 0
    scripts = scripts.filter((item, i) => {
      if (item.uuid === record.uuid) {
        index = i
      }
      return item.uuid !== record.uuid
    })
    if ((index === 0 && direction === 'up') || (index === scripts.length && direction === 'down')) {
      return
    }
    if (direction === 'up') {
      scripts.splice(index - 1, 0, record)
    } else {
      scripts.splice(index + 1, 0, record)
    }
    this.setState({ scripts })
  }
  scriptsChange = (values) => {
    let scripts = fromJS(this.state.scripts).toJS()
@@ -355,6 +313,10 @@
    return new Promise((resolve, reject) => {
      this.sqlverify(resolve, reject, false, scripts)
    })
  }
  changeScripts = (scripts) => {
    this.setState({ scripts })
  }
  scriptSubmit = (values) => {
@@ -624,14 +586,7 @@
              scriptSubmit={this.scriptSubmit}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
            <Table
              bordered
              rowKey="uuid"
              className="custom-table"
              dataSource={scripts}
              columns={scriptsColumns}
              pagination={false}
            />
            <EditTable data={scripts} actions={[]} columns={scriptsColumns} onChange={this.changeScripts}/>
          </TabPane>
        </Tabs>
      </div>
src/menu/datasource/verifycard/utils.jsx
@@ -76,6 +76,13 @@
            reg: new RegExp('@' + item.field + '@', 'ig')
          })
        }
      } else if (item.type === 'text' || item.type === 'select') {
        item.field.split(',').forEach(field => {
          _regoptions.push({
            var: new RegExp('@' + field, 'ig'),
            reg: new RegExp('@' + field + '@', 'ig')
          })
        })
      } else {
        _regoptions.push({
          var: new RegExp('@' + item.field, 'ig'),
src/tabviews/custom/components/share/normalTable/index.jsx
New file
@@ -0,0 +1,810 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import md5 from 'md5'
import { connect } from 'react-redux'
import { is, fromJS } from 'immutable'
import { Table, Typography, Icon, Col } from 'antd'
import { modifyTabview } from '@/store/action'
import MKEmitter from '@/utils/events.js'
import '@/assets/css/table.scss'
import './index.scss'
const { Paragraph } = Typography
class BodyRow extends React.Component {
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props.data), fromJS(nextProps.data)) || !is(fromJS(this.props.className), fromJS(nextProps.className))
  }
  render() {
    let { lineMarks, data, className, ...resProps } = this.props
    let style = {}
    if (lineMarks && lineMarks.length > 0) {
      lineMarks.some(mark => {
        let originVal = data[mark.field[0]] + ''
        let contrastVal = ''
        let result = false
        if (mark.field[1] === 'static') {
          contrastVal = mark.contrastValue + ''
        } else {
          contrastVal = data[mark.field[2]] + ''
        }
        if (mark.match === '=') {
          result = originVal === contrastVal
        } else if (mark.match === '!=') {
          result = originVal !== contrastVal
        } else if (mark.match === 'like') {
          result = originVal.indexOf(contrastVal) > -1
        } else if (mark.match === '>') {
          try {
            originVal = parseFloat(originVal)
            contrastVal = parseFloat(contrastVal)
          } catch {
            originVal = NaN
          }
          if (!isNaN(originVal) && !isNaN(contrastVal) && originVal > contrastVal) {
            result = true
          }
        } else if (mark.match === '<') {
          try {
            originVal = parseFloat(originVal)
            contrastVal = parseFloat(contrastVal)
          } catch {
            originVal = NaN
          }
          if (!isNaN(originVal) && !isNaN(contrastVal) && originVal < contrastVal) {
            result = true
          }
        }
        if (result) {
          if (mark.signType[0] === 'font') {
            style.color = mark.color
          } else if (mark.signType[0] === 'background') {
            style.background = mark.color
            if (mark.fontColor) {
              style.color = mark.fontColor
            }
            className += className + ' background'
          } else if (mark.signType[0] === 'underline') {
            style.textDecoration = 'underline'
            style.color = mark.color
          } else if (mark.signType[0] === 'line-through') {
            style.textDecoration = 'line-through'
            style.color = mark.color
          }
        }
        return result
      })
    }
    return <tr {...resProps} className={className} style={style}/>
  }
}
class BodyCell extends React.Component {
  getMark = (record, marks, style, content) => {
    marks.some(mark => {
      let originVal = record[mark.field[0]] + ''
      let contrastVal = ''
      let result = false
      if (mark.field[1] === 'static') {
        contrastVal = mark.contrastValue + ''
      } else {
        contrastVal = record[mark.field[2]] + ''
      }
      if (mark.match === '=') {
        result = originVal === contrastVal
      } else if (mark.match === '!=') {
        result = originVal !== contrastVal
      } else if (mark.match === 'like') {
        result = originVal.indexOf(contrastVal) > -1
      } else if (mark.match === '>') {
        try {
          originVal = parseFloat(originVal)
          contrastVal = parseFloat(contrastVal)
        } catch {
          originVal = NaN
        }
        if (!isNaN(originVal) && !isNaN(contrastVal) && originVal > contrastVal) {
          result = true
        }
      } else if (mark.match === '<') {
        try {
          originVal = parseFloat(originVal)
          contrastVal = parseFloat(contrastVal)
        } catch {
          originVal = NaN
        }
        if (!isNaN(originVal) && !isNaN(contrastVal) && originVal < contrastVal) {
          result = true
        }
      }
      if (result) {
        if (mark.signType[0] === 'font') {
          style.color = mark.color
        } else if (mark.signType[0] === 'background') {
          style.background = mark.color
          if (mark.fontColor) {
            style.color = mark.fontColor
          }
        } else if (mark.signType[0] === 'underline') {
          style.textDecoration = 'underline'
          style.color = mark.color
        } else if (mark.signType[0] === 'line-through') {
          style.textDecoration = 'line-through'
          style.color = mark.color
        } else if (mark.signType[0] === 'icon') {
          let icon = (<Icon style={{color: mark.color}} type={mark.signType[3]} />)
          if (mark.signType[1] === 'front') {
            content = <span>{icon} {content}</span>
          } else {
            content = <span>{content} {icon}</span>
          }
        }
      }
      return result
    })
    return content
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !nextProps.record || !is(fromJS(this.props.record), fromJS(nextProps.record))
  }
  render() {
    let { col, record, className, style, triggerLink, ...resProps } = this.props
    if (!col) return (<td {...resProps} className={className} style={style}/>)
    if (col.type === 'text') {
      let content = ''
      if (record[col.field] !== undefined) {
        content = `${record[col.field]}`
      }
      if (content !== '') {
        if (col.textFormat === 'YYYY-MM-DD' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1])/.test(content)) {
          content = `${content.substr(0, 4)}-${content.substr(5, 2)}-${content.substr(8, 2)}`
        } else if (col.textFormat === 'YYYY-MM-DD HH:mm:ss' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/.test(content)) {
          content = `${content.substr(0, 4)}-${content.substr(5, 2)}-${content.substr(8, 2)} ${content.substr(11, 2)}:${content.substr(14, 2)}:${content.substr(17, 2)}`
        }
        content = col.prefix + content + col.postfix
      }
      if (col.marks) {
        style = style || {}
        content = this.getMark(record, col.marks, style, content)
      }
      if (col.blur) {
        content = md5(content)
      }
      if (col.rowspan === 'true') {
        resProps.rowSpan = record['$$' + col.field]
      }
      if (col.linkThdMenu || col.linkurl) {
        content = (
          <div>
            <div className="link-menu" onDoubleClick={() => this.triggerLink(col, record)}></div>
            {content}
          </div>
        )
      }
      resProps.children = content
    } else if (col.type === 'number') {
      let content = ''
      try {
        content = parseFloat(record[col.field])
        if (isNaN(content)) {
          content = ''
        }
      } catch {
        content = ''
      }
      if (content !== '') {
        let decimal = col.decimal || 0
        if (col.format === 'percent') {
          content = content * 100
          decimal = decimal > 2 ? decimal - 2 : 0
        }
        content = content.toFixed(decimal)
        if (col.format === 'thdSeparator') {
          content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
        }
        content = col.prefix + content + col.postfix
      }
      if (col.marks) {
        style = style || {}
        content = this.getMark(record, col.marks, style, content)
      }
      if (col.blur) {
        content = md5(content)
      }
      if (col.linkThdMenu || col.linkurl) {
        content = (
          <div>
            <div className="link-menu" onDoubleClick={() => this.triggerLink(col, record)}></div>
            {content}
          </div>
        )
      }
      resProps.children = content
    } else if (col.type === 'picture') {
      let photos = ''
      if (record[col.field]) {
        photos = `${record[col.field]}`
        photos = photos.split(',')
      }
      let cols = 24 / (col.picSort || 1)
      let paddingTop = '100%'
      if (col.lenWidRadio === '16:9') {
        paddingTop = '56.25%'
      } else if (col.lenWidRadio === '3:2') {
        paddingTop = '66.67%'
      } else if (col.lenWidRadio === '4:3') {
        paddingTop = '75%'
      }
      resProps.children = (
        <div>
          {photos.map((url, i) => (
            <Col key={i} span={cols}>
              <div className="ant-mk-picture" style={{paddingTop, backgroundImage: `url('${url}')`}}></div>
            </Col>
          ))}
        </div>
      )
    } else if (col.type === 'textarea') {
      let content = ''
      if (record[col.field] !== undefined) {
        content = `${record[col.field]}`
      }
      if (content) {
        content = col.prefix + content + col.postfix
      }
      if (col.blur) {
        content = md5(content)
      }
      resProps.children = (
        <div>
          {content ? <Paragraph copyable ellipsis={{ rows: 3, expandable: true }}>{content}</Paragraph> : null }
        </div>
      )
    } else if (col.type === 'link') {
      let content = ''
      let _href = record[col.field] || ''
      if (col.nameField) {
        content = record[col.nameField] || ''
      }
      if (!content && _href) {
        content = _href
      } else if (!_href) {
        content = ''
      }
      if (col.joint === 'true' && _href) {
        let _quary = `id=${record.$$uuid}&userid=${sessionStorage.getItem('UserID')}&appkey=${window.GLOB.appkey}&LoginUID=${sessionStorage.getItem('LoginUID')}`
        let _param = ''
        try {
          _param = window.btoa(_quary)
        } catch {
          _param = window.btoa(window.encodeURIComponent(_quary))
        }
        if (/\?/ig.test(_href)) {
          _href += '&' + _param
        } else {
          _href += '?' + _param
        }
      }
      if (col.blur) {
        content = md5(content)
      }
      resProps.children = (
        <div>
          {content && _href ? <a href={_href} target="_blank" rel="noopener noreferrer">{content}</a> : null }
        </div>
      )
    }
    if (resProps.rowSpan === 0) return null
    return (<td {...resProps} className={className} style={style}/>)
  }
}
class NormalTable extends Component {
  static propTpyes = {
    tableId: PropTypes.string,       // 列表Id
    statFValue: PropTypes.any,       // 合计字段数据
    pageSize: PropTypes.any,         // 每页数据
    MenuName: PropTypes.any,         // 菜单名称
    dict: PropTypes.object,          // 字典项
    MenuID: PropTypes.string,        // 菜单Id
    setting: PropTypes.object,       // 表格全局设置:tableType(表格是否可选、单选、多选)、columnfixed(列固定)、actionfixed(按钮固定)
    pickup: PropTypes.any,           // 数据收起
    columns: PropTypes.array,        // 表格列
    lineMarks: PropTypes.array,      // 行标记
    fields: PropTypes.array,         // 组件字段集
    BID: PropTypes.any,              // 主表Id
    ContainerId: PropTypes.any,      // 标签页外层Id
    BData: PropTypes.any,            // 主表数据
    data: PropTypes.any,             // 表格数据
    total: PropTypes.any,            // 总数
    loading: PropTypes.bool,         // 表格加载中
    refreshdata: PropTypes.func,     // 表格中排序列、页码的变化时刷新
    handleTableId: PropTypes.func,   // 数据切换
    chgSelectData: PropTypes.func,   // 数据切换
    refreshbyaction: PropTypes.func, // 按钮执行完成后刷新
  }
  state = {
    selectedRowKeys: [],  // 表格中选中行
    pageIndex: 1,         // 初始页面索引
    pageSize: 10,         // 每页数据条数
    columns: null,        // 显示列
    imgShow: false,       // 图片放大模态框
    imgSrc: '',           // 图片路径
    activeIndex: null,    // 标记当前选中行
    rowspans: null        // 行合并字段信息
  }
  UNSAFE_componentWillMount () {
    const { menuType, memberLevel, pageSize } = this.props
    let columns = fromJS(this.props.columns).toJS()
    let _columns = []
    let radio = 5          // 虚化比例
    let _format = false    // 是否虚化处理
    let rowspans = []
    if (window.GLOB.dataFormat && menuType !== 'HS' && memberLevel) {
      _format = true
      if (memberLevel >= 30) {
        radio = 20
      } else if (memberLevel >= 20) {
        radio = 10
      }
    }
    columns.forEach(item => {
      if (item.hidden === true || item.Hide === 'true') return
      let cell = null
      if (item.type === 'colspan') {
        cell = {title: item.label, children: []}
        item.subcols.forEach(col => {
          if (col.rowspan === 'true') {
            rowspans.push(col.field)
          }
          if (_format && !Math.floor(Math.random() * radio)) {
            col.blur = true
          }
          if (col.marks && col.marks.length === 0) {
            col.marks = ''
          }
          cell.children.push({
            align: col.Align,
            title: col.label,
            dataIndex: col.field || col.uuid,
            key: col.uuid,
            width: col.Width || 120,
            onCell: record => ({
              record,
              col: item,
              triggerLink: this.triggerLink
            })
          })
        })
      } else {
        if (item.rowspan === 'true') {
          rowspans.push(item.field)
        }
        if (_format && !Math.floor(Math.random() * radio)) {
          item.blur = true
        }
        if (item.marks && item.marks.length === 0) {
          item.marks = ''
        }
        cell = {
          align: item.Align,
          dataIndex: item.field || item.uuid,
          title: item.label,
          sorter: item.field && item.IsSort === 'true',
          width: item.Width || 120,
          onCell: record => ({
            record,
            col: item,
            triggerLink: this.triggerLink
          })
        }
      }
      _columns.push(cell)
    })
    if (rowspans.length === 0) {
      rowspans = null
    }
    this.setState({
      columns: _columns,
      pageSize: pageSize ? pageSize : 10,
      rowspans
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    MKEmitter.addListener('resetTable', this.resetTable)
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('resetTable', this.resetTable)
  }
  updateStatus = (type, positon, btn) => {
    if (type === 'refresh') {
      this.props.refreshbyaction(positon, btn)
    }
  }
  // 字段透视
  triggerLink = (item, record) => {
    const { tabviews, MenuID, setting } = this.props
    if (item.linkThdMenu) {
      let tabmenu = item.linkThdMenu
      tabmenu.param = {
        searchkey: item.field,
        searchval: record[item.field] || '',
        BID: record[setting.primaryKey]
      }
      tabmenu.selected = true
      let index = 0
      let isexit = false
      let tabs = tabviews.map((tab, i) => {
        tab.selected = false
        if (tab.MenuID === MenuID) {
          index = i
        } else if (tab.MenuID === tabmenu.MenuID) {
          tab.param = tabmenu.param
          tab.selected = true
          isexit = true
        }
        return tab
      })
      if (!isexit) {
        tabs.splice(index + 1, 0, tabmenu)
      }
      this.props.modifyTabview(tabs)
    } else {
      let src = item.linkurl
      if (item.linkurl.indexOf('paramsmain/') > -1) {
        try {
          let _url = item.linkurl.split('paramsmain/')[0] + 'paramsmain/'
          let _param = JSON.parse(window.decodeURIComponent(window.atob(item.linkurl.split('paramsmain/')[1])))
          let dataparam = {
            searchkey: item.field,
            searchval: record[item.field] || '',
            BID: record[setting.primaryKey]
          }
          _param.UserID = sessionStorage.getItem('UserID')
          _param.LoginUID = sessionStorage.getItem('LoginUID')
          _param.User_Name = sessionStorage.getItem('User_Name')
          _param.param = dataparam
          src = _url + window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
        } catch {
          console.warn('菜单参数解析错误!')
        }
      }
      window.open(src)
    }
  }
  /**
   *
   */
  onSelectChange = selectedRowKeys => {
    const { setting } = this.props
    let index = ''
    let _activeIndex = null
    if (selectedRowKeys.length > 0) {
      index = selectedRowKeys.slice(-1)[0]
    }
    if (setting.tableType === 'checkbox') {
      _activeIndex = index === '' ? null : index
    }
    this.changedata(index)
    this.setState({ selectedRowKeys, activeIndex: _activeIndex })
    let selects = this.props.data.filter((item, _index) => selectedRowKeys.includes(_index))
    this.props.chgSelectData(selects)
  }
  /**
   * @description 点击整行,触发切换, 判断是否可选,单选或多选,进行对应操作
   */
  changeRow = (record, index) => {
    const { setting, pickup } = this.props
    if (!setting.tableType || pickup) return
    let newkeys = fromJS(this.state.selectedRowKeys).toJS()
    if (setting.tableType === 'radio') {
      newkeys = [index]
      this.changedata(index)
      this.setState({ selectedRowKeys: newkeys })
    } else {
      let _index = ''
      if (newkeys.includes(index)) {
        newkeys = newkeys.filter(item => item !== index)
        if (newkeys.length > 0) {
          _index = newkeys.slice(-1)[0]
        }
        this.changedata(_index)
      } else {
        _index = index
        newkeys.push(index)
        this.changedata(index)
      }
      this.setState({ selectedRowKeys: newkeys, activeIndex: _index !== '' ? _index : null })
    }
    let selects = this.props.data.filter((item, _index) => newkeys.includes(_index))
    this.props.chgSelectData(selects)
  }
  changeTable = (pagination, filters, sorter) => {
    this.setState({
      pageIndex: pagination.current,
      pageSize: pagination.pageSize,
      selectedRowKeys: [],
      activeIndex: null
    })
    this.props.refreshdata(pagination, filters, sorter)
  }
  changedata = (index) => {
    const { data, setting } = this.props
    let _id = ''
    let _data = ''
    if (data && data.length > 0 && index !== '') {
      _id = data[index][setting.primaryKey] || ''
      _data = data[index] || ''
    }
    this.props.handleTableId(this.props.tableId, _id, _data)
  }
  resetTable = (id, repage) => {
    const { MenuID, tableId } = this.props
    if (id !== (MenuID + tableId)) return
    if (repage === 'false') {
      this.setState({
        selectedRowKeys: [],
        activeIndex: null
      })
    } else {
      this.setState({
        pageIndex: 1,
        selectedRowKeys: [],
        activeIndex: null
      })
    }
  }
  handleRowspan = (data) => {
    const { rowspans } = this.state
    if (!rowspans || data.length === 0) return data
    data = fromJS(data).toJS()
    data = data.reverse()
    data.forEach((item, index) => {
      if (index === 0) {
        rowspans.forEach(cell => {
          item['$' + cell] = 1
        })
      } else {
        let preItem = data[index - 1]
        rowspans.forEach((cell, i) => {
          if (i === 0) {
            if ((item[cell] || item[cell] === 0) && preItem[cell] === item[cell]) {
              item['$' + cell] = preItem['$' + cell] + 1
            } else {
              item['$' + cell] = 1
            }
          } else {
            if ((item[cell] || item[cell] === 0) && preItem[cell] === item[cell]) {
              item['$' + cell] = preItem['$' + cell] + 1
            } else {
              item['$' + cell] = 1
            }
            if (item['$' + cell] > item['$' + rowspans[i - 1]]) {
              item['$' + cell] = 1
            }
          }
        })
      }
    })
    data = data.reverse()
    data.forEach((item, index) => {
      if (index === 0) {
        rowspans.forEach(cell => {
          item['$$' + cell] = item['$' + cell]
        })
      } else {
        let preItem = data[index - 1]
        rowspans.forEach(cell => {
          if (preItem['$' + cell] > 1) {
            item['$$' + cell] = 0
          } else {
            item['$$' + cell] = item['$' + cell]
          }
        })
      }
    })
    return data
  }
  render() {
    const { setting, pickup, statFValue, lineMarks } = this.props
    const { selectedRowKeys, activeIndex } = this.state
    // 设置表格选择属性:单选、多选、不可选
    let rowSelection = null
    if (setting.tableType) {
      rowSelection = {
        selectedRowKeys,
        type: (setting.tableType === 'radio') ? 'radio' : 'checkbox',
        onChange: this.onSelectChange
      }
    }
    const components = {
      body: {
        row: BodyRow,
        cell: BodyCell
      }
    }
    // 数据收起时,过滤已选数据
    let _data = this.props.data ? this.props.data : []
    if (pickup) {
      _data = _data.filter((item, index) => selectedRowKeys.includes(index))
    }
    _data = this.handleRowspan(_data)
    let _pagination = false
    if (setting.laypage !== 'false' && setting.laypage !== false) {
      _pagination = {
        current: this.state.pageIndex,
        pageSize: this.state.pageSize,
        pageSizeOptions: ['10', '25', '50', '100', '500', '1000'],
        showSizeChanger: true,
        total: this.props.total || 0,
        showTotal: (total, range) => `${range[0]}-${range[1]} ${this.props.dict['main.pagination.of']} ${total} ${this.props.dict['main.pagination.items']}`
      }
    }
    let _footer = ''
    if (statFValue && statFValue.length > 0) {
      _footer = statFValue.map(f => `${f.label}(合计):${f.value}`).join(';')
    }
    return (
      <div className="normal-custom-table">
        <Table
          size="middle"
          components={components}
          bordered={setting.bordered !== 'false'}
          rowSelection={rowSelection}
          columns={this.state.columns}
          dataSource={_data}
          loading={this.props.loading}
          scroll={{ x: '100%', y: false }}
          onRow={(record, index) => {
            return {
              lineMarks,
              data: record,
              className: index === activeIndex ? ' mk-row-active ' : '',
              onClick: () => {this.changeRow(record, index)}
            }
          }}
          onChange={this.changeTable}
          pagination={_pagination}
        />
        {_footer ? <div className={'normal-table-footer ' + (_pagination ? 'pagination' : '')}>{_footer}</div> : null}
      </div>
    )
  }
}
const mapStateToProps = (state) => {
  return {
    menuType: state.editLevel,
    tabviews: state.tabviews,
    memberLevel: state.memberLevel
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews))
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(NormalTable)
src/tabviews/custom/components/share/normalTable/index.scss
New file
@@ -0,0 +1,174 @@
.normal-custom-table {
  position: relative;
  padding: 0 0px 30px;
  .normal-table-footer {
    padding: 10px 0px;
    color: rgba(0, 0, 0, 0.65);
  }
  .normal-table-footer.pagination {
    position: absolute;
    bottom: 40px;
  }
  >.ant-table-wrapper {
    position: relative;
    z-index: 1;
  }
  table {
    max-width: 100%;
    width: 100%;
    .ant-table-thead {
      tr {
        th {
          position: relative;
        }
      }
    }
    .ant-table-selection-column {
      width: 60px;
      min-width: 60px;
      max-width: 60px;
    }
    .ant-table-tbody > tr.ant-table-row-selected:not(.background) td {
      background-color: #c4ebfd;
    }
    .ant-table-tbody > tr.ant-table-row-selected:not(.background):hover .ant-table-column-sort {
      background-color: #c4ebfd;
    }
    .ant-table-tbody > tr.background td {
      background-color: unset!important;
    }
    .ant-table-tbody > tr.mk-row-active:not(.background) td {
      background-color: #91d5ff;
    }
    .ant-table-tbody > tr.ant-table-row-selected.mk-row-active:not(.background):hover .ant-table-column-sort {
      background-color: #91d5ff;
    }
    .ant-table-tbody > tr td .anticon.font {
      background-color: unset;
    }
  }
  .ant-table-body {
    overflow-x: auto!important;
    table {
      .ant-table-tbody > tr > td {
        vertical-align: top;
        .ant-mk-picture {
          background-position: center center;
          background-size: cover;
          margin: 2px;
        }
        .action-col {
          .ant-btn > .anticon + span {
            margin-left: 3px;
          }
          button {
            border: 0;
            background-color: transparent;
            color: #1890ff;
            box-shadow: none;
            padding: 0 5px;
            .anticon-loading {
              display: none;
            }
          }
          > div {
            margin: 0 3px;
          }
          > button {
            margin: 0 3px;
          }
          .ant-btn.ant-btn-loading:not(.ant-btn-circle):not(.ant-btn-circle-outline):not(.ant-btn-icon-only) {
            padding-left: 0px;
          }
        }
      }
      .ant-table-tbody > tr > td[rowspan] {
        vertical-align: middle;
      }
      .ant-table-tbody > tr > td.ant-table-column-has-actions {
        position: relative;
        .link-menu {
          position: absolute;
          top: 0px;
          left: 0px;
          right: 0px;
          bottom: 0px;
          opacity: 0;
          cursor: pointer;
        }
        .content {
          position: relative;
          z-index: 1;
          word-wrap: break-word;
          word-break: break-word;
        }
      }
      .ant-table-tbody > tr > td .content {
        p {
          margin-bottom: 2px;
        }
        span {
          display: inline-block;
          margin-right: 5px;
        }
      }
      .ant-table-tbody > tr > td .button {
        .ant-btn {
          margin-bottom: 10px;
        }
      }
    }
  }
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
  }
  ::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  ::-webkit-scrollbar-track {/*滚动条里面轨道*/
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
  .fix-header {
    .ant-table-body {
      min-height: unset
    }
    .ant-table-placeholder {
      display: none;
    }
    .ant-table-wrapper {
      display: none;
    }
    .ant-affix .ant-table-wrapper {
      display: block;
    }
  }
}
.image-scale-modal {
  width: 70vw;
  min-height: 80vh;
  top: 10vh;
  .ant-modal-body {
    min-height: calc(80vh - 110px);
    line-height: calc(80vh - 160px);
    text-align: center;
  }
  .ant-modal-footer {
    text-align: center;
    span {
      display: inline-block;
      color: #1890ff;
      padding: 5px 15px;
      cursor: pointer;
    }
  }
}
src/tabviews/custom/components/table/normal-table/index.jsx
@@ -17,7 +17,7 @@
// 通用组件
const MainAction = asyncSpinComponent(() => import('@/tabviews/zshare/actionList'))
const MainTable = asyncSpinComponent(() => import('@/tabviews/zshare/normalTable'))
const MainTable = asyncSpinComponent(() => import('@/tabviews/custom/components/share/normalTable'))
class NormalTable extends Component {
  static propTpyes = {
@@ -150,6 +150,7 @@
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
          item.$$uuid = item[setting.primaryKey] || ''
          return item
        }),
        total: result.total,
@@ -499,6 +500,7 @@
            fields={config.columns}
            total={this.state.total}
            MenuID={this.props.MenuID}
            lineMarks={config.lineMarks}
            loading={this.state.loading}
            refreshdata={this.refreshbytable}
            statFValue={this.state.statFValue}
src/tabviews/zshare/normalTable/index.jsx
@@ -5,7 +5,6 @@
import { is, fromJS } from 'immutable'
import { Table, Affix, Typography, Modal, Icon } from 'antd'
import Utils from '@/utils/utils.js'
import { modifyTabview } from '@/store/action'
import asyncComponent from '@/utils/asyncComponent'
import MKEmitter from '@/utils/events.js'
@@ -52,7 +51,7 @@
    imgSrc: '',           // 图片路径
    lineMarks: null,      // 行标记
    activeIndex: null,    // 标记当前选中行
    rowspan: null         // 行合并字段信息
    rowspans: null        // 行合并字段信息
  }
  UNSAFE_componentWillMount () {
@@ -62,7 +61,7 @@
    let _columns = []
    let radio = 5          // 虚化比例
    let _format = false    // 是否虚化处理
    let rowspan = null
    let rowspans = []
    if (window.GLOB.dataFormat && menuType !== 'HS' && memberLevel) {
      _format = true
@@ -83,7 +82,7 @@
        item.subcols.forEach(col => {
          if (col.rowspan === 'true') {
            rowspan = col
            rowspans.push(col.field)
          }
          if (_format && !Math.floor(Math.random() * radio)) {
            col.blur = true
@@ -141,7 +140,7 @@
        }
      } else {
        if (item.rowspan === 'true') {
          rowspan = item
          rowspans.push(item.field)
        }
        if (_format && !Math.floor(Math.random() * radio)) {
          item.blur = true
@@ -183,11 +182,15 @@
      _columns.push(cell)
    })
    if (rowspans.length === 0) {
      rowspans = null
    }
    this.setState({
      columns: _columns,
      pageSize: pageSize ? pageSize : 10,
      lineMarks: lineMarks,
      rowspan: rowspan
      lineMarks,
      rowspans
    })
  }
@@ -397,7 +400,7 @@
              </div>
            ),
            props: {
              rowSpan: record.$$rowspan,
              rowSpan: record['$$' + item.field],
            }
          }
        }
@@ -421,7 +424,7 @@
              </div>
            ),
            props: {
              rowSpan: record.$$rowspan,
              rowSpan: record['$$' + item.field],
            }
          }
        }
@@ -506,7 +509,8 @@
    } else if (item.type === 'picture') {
      let photos = ''
      if (item.field && record.hasOwnProperty(item.field)) {
        photos = record[item.field].split(',')
        photos = record[item.field] + ''
        photos = photos.split(',')
      } else {
        photos = ''
      }
@@ -696,7 +700,8 @@
        } else if (col.type === 'picture') {
          let photos = []
          try {
            photos = record[col.field].split(',')
            photos = record[col.field] + ''
            photos = photos.split(',')
          } catch {
            photos = []
          }
@@ -989,9 +994,63 @@
    }
  }
  handleRowspan = (data) => {
    const { rowspans } = this.state
    if (!rowspans || data.length === 0) return data
    data = fromJS(data).toJS()
    data = data.reverse()
    data.forEach((item, index) => {
      if (index === 0) {
        rowspans.forEach(cell => {
          item['$' + cell] = 1
        })
      } else {
        let preItem = data[index - 1]
        rowspans.forEach((cell, i) => {
          if (i === 0) {
            if ((item[cell] || item[cell] === 0) && preItem[cell] === item[cell]) {
              item['$' + cell] = preItem['$' + cell] + 1
            } else {
              item['$' + cell] = 1
            }
          } else {
            if ((item[cell] || item[cell] === 0) && preItem[cell] === item[cell]) {
              item['$' + cell] = preItem['$' + cell] + 1
            } else {
              item['$' + cell] = 1
            }
            if (item['$' + cell] > item['$' + rowspans[i - 1]]) {
              item['$' + cell] = 1
            }
          }
        })
      }
    })
    data = data.reverse()
    data.forEach((item, index) => {
      if (index === 0) {
        rowspans.forEach(cell => {
          item['$$' + cell] = item['$' + cell]
        })
      } else {
        let preItem = data[index - 1]
        rowspans.forEach(cell => {
          if (preItem['$' + cell] > 1) {
            item['$$' + cell] = 0
          } else {
            item['$$' + cell] = item['$' + cell]
          }
        })
      }
    })
    return data
  }
  render() {
    const { setting, pickup, statFValue } = this.props
    const { selectedRowKeys, lineMarks, activeIndex, rowspan } = this.state
    const { selectedRowKeys, lineMarks, activeIndex } = this.state
    // 设置表格选择属性:单选、多选、不可选
    let rowSelection = null
@@ -1025,35 +1084,8 @@
      _data = _data.filter((item, index) => selectedRowKeys.includes(index))
    }
    if (rowspan) {
      let marks = {}
      let premark = {val: '', mark: ''}
      _data = _data.map(item => {
        if (item[rowspan.field]) {
          if (item[rowspan.field] !== premark.val) {
            premark = {val: item[rowspan.field], mark: Utils.getuuid()}
            marks[premark.mark] = 1
            item.$$mark = premark.mark
          } else {
            marks[premark.mark]++
            item.$$mark = premark.mark
          }
        } else {
          item.$$rowspan = 1
        }
        return item
      })
      _data = _data.map(item => {
        if (item.$$mark) {
          item.$$rowspan = marks[item.$$mark]
          marks[item.$$mark] = 0
        }
        return item
      })
    }
    _data = this.handleRowspan(_data)
    let _pagination = false
    if (setting.laypage !== 'false' && setting.laypage !== false) {
      _pagination = {
src/templates/comtableconfig/index.jsx
@@ -44,13 +44,12 @@
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    config: null,            // 页面配置
    tableFields: [],         // 表格显示列
    tableFields: [],         // 已选的常用表
    formlist: null,          // 搜索条件、按钮、显示列表单字段
    menuloading: false,      // 菜单保存中
    menucloseloading: false, // 菜单关闭时,选择保存
    loading: false,          // 加载中,页面spin
    closeVisible: false,     // 关闭模态框
    tables: [],              // 可用表名
    originMenu: null,        // 原始菜单
    originActions: null,     // 原始按钮信息,使用已有用户模板
    delActions: [],          // 删除按钮列表
src/templates/modalconfig/index.jsx
@@ -5,30 +5,30 @@
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import moment from 'moment'
import { Button, Card, Modal, Collapse, notification, Select, List, Icon, Empty, Popover, Switch } from 'antd'
import { Button, Card, Modal, Collapse, notification, Icon, Popover, Switch } from 'antd'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import { getModalForm } from '@/templates/zshare/formconfig'
import { queryTableSql } from '@/utils/option.js'
import ModalForm from '@/templates/zshare/modalform'
import DragElement from './dragelement'
import SourceElement from './dragelement/source'
import SettingForm from './settingform'
import GroupForm from './groupform'
import EditCard from './editcard'
import MenuForm from './menuform'
import asyncComponent from '@/utils/asyncComponent'
import EditComponent from '@/templates/zshare/editcomponent'
import { BaseConfig, SearchItems } from './source'
import './index.scss'
const { Panel } = Collapse
const { Option } = Select
const { confirm } = Modal
const CommonDict = localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
class ComModalConfig extends Component {
  static propTpyes = {
@@ -47,11 +47,9 @@
  state = {
    menu: null,            // 上级菜单,三级菜单或标签
    dict: CommonDict,      // 字典
    tableFields: [],       // 已选的常用表
    config: null,          // 页面配置,包括模板类型、模态框设置、添加表名、表单列表
    visible: false,        // 表单编辑模态框,显示控制
    tableVisible: false,   // 数据表字段列表模态框,显示控制
    tableColumns: [],      // 表格字段名列表
    fields: null,          // 表单,可选字段(去重后)
    modalformlist: null,   // 基本信息表单字段
    formlist: null,        // 表单编辑模态框,可编辑字段
    card: null,            // 编辑元素
@@ -59,12 +57,9 @@
    closeloading: false,   // 菜单保存中
    settingVisible: false, // 全局配置模态框
    closeVisible: false,   // 关闭模态框
    tables: [],            // 可用表名
    selectedTables: [],    // 已选表名
    originConfig: null,    // 原始菜单
    groupVisible: false,   // 全局配置模态框
    curgroup: null,        // 当前组,新建或编辑
    sources: null,         // 表单类型
    sqlVerifing: false,    // sql验证
    openEdition: '',       // 编辑版本标记,防止多人操作
    showField: false       // 显示表单字段值
@@ -119,7 +114,6 @@
      menu: _menu,
      source: _source,
      config: _config,
      selectedTables: _config.tables || [],
      originConfig: fromJS(_config).toJS(),
      modalformlist: [
        {
@@ -139,98 +133,6 @@
          readonly: true
        }
      ]
    })
  }
  /**
   * @description 获取数据表信息
   * 1、获取系统中全部表名
   * 2、根据已选表名,获取表格字段列表
   */
  componentDidMount () {
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: queryTableSql,
      obj_name: 'data',
      arr_field: 'TbName,Remark'
    }
    param.LText = Utils.formatOptions(param.LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
    Api.getSystemConfig(param).then(res => {
      if (res.status) {
        this.setState({
          tables: res.data
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
        })
      }
    })
    let deffers = this.state.selectedTables.map(item => {
      return new Promise(resolve => {
        Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: item.TbName}).then(res => {
          res.TBName = item.TbName
          resolve(res)
        })
      })
    })
    // 获取字段后数据处理,根据类型分为text、number、datetime、date
    Promise.all(deffers).then(response => {
      let _columns = []
      response.forEach(res => {
        if (res.status) {
          let tabmsg = {
            tableName: res.TBName,
            columns: res.FDName.map(item => {
              let _type = item.FieldType.toLowerCase()
              let _decimal = 0
              if (/^nvarchar/.test(_type)) {
                _type = 'text'
              } else if (/^int/.test(_type)) {
                _type = 'number'
              } else if (/^decimal/.test(_type)) {
                _decimal = _type.split(',')[1]
                _decimal = parseInt(_decimal)
                _type = 'number'
              } else if (/^datetime/.test(_type)) {
                _type = 'datetime'
              } else if (/^date/.test(_type)) {
                _type = 'date'
              } else {
                _type = 'text'
              }
              return {
                field: item.FieldName,
                label: item.FieldDec,
                type: _type,
                decimal: _decimal
              }
            })
          }
          _columns.push(tabmsg)
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
        }
      })
      this.setState({
        tableColumns: _columns
      })
    })
  }
@@ -592,7 +494,7 @@
    }
    let _LongParam = ''
    let _config = {...config, tables: this.state.selectedTables}
    let _config = fromJS(config).toJS()
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
@@ -685,241 +587,14 @@
  }
  /**
   * @description 通过表字段添加表单
   * 1、检查是否已选表名,为选时警告提示
   * 2、表字段名通过map去重
   * 3、检查表单中的已选字段,并标记已选
   * @description 更新常用表信息,快捷添加后更新配置信息
   */
  queryField = () => {
    const {selectedTables, tableColumns, config} = this.state
    if (selectedTables.length === 0) {
      notification.warning({
        top: 92,
        message: '请选择表名!',
        duration: 10
      })
      return
    }
    let columns = new Map()
    tableColumns.forEach(table => {
      table.columns.forEach(column => {
        columns.set(column.field, column)
      })
    })
    if (config.groups.length > 1) {
      config.groups.forEach(group => {
        group.sublist.forEach(item => {
          if (columns.has(item.field)) {
            columns.set(item.field, {...item, selected: true})
          }
        })
      })
    } else {
      config.fields.forEach(item => {
        if (columns.has(item.field)) {
          columns.set(item.field, {...item, selected: true})
        }
      })
    }
  updatetable = (config, fields) => {
    const { tableFields } = this.state
    this.setState({
      tableVisible: true,
      fields: [...columns.values()]
    })
  }
  /**
   * @description 选择字段后提交
   * 1、没有可选字段时,直接关闭
   * 2、获取已选字段
   * 3、与已有字段对比
   * 4、添加新增字段
   */
  addFieldSubmit = () => {
    if (!this.state.fields || this.state.fields.length === 0) {
      this.setState({
        tableVisible: false
      })
    }
    let _config = fromJS(this.state.config).toJS()
    let cards = this.refs.searchcard.state.selectCards
    let columns = new Map()
    cards.forEach(card => {
      columns.set(card.field, card)
    })
    if (_config.groups.length > 1) {
      _config.groups.forEach(group => {
        let items = []
        group.sublist.forEach(item => {
          if (columns.has(item.field)) {
            let cell = columns.get(item.field)
            if (cell.selected && cell.type === item.type) { // 数据选择状态及类型未修改时,直接添加
              items.push(item)
            } else if (cell.selected) {                     // 数据类型修改时,重置类型及初始值
              item.type = cell.type
              item.initval = ''
              items.push(item)
            }
            columns.delete(item.field)
          } else if (!item.origin) {                        // 过滤示例项
            items.push(item)
          }
        })
        group.sublist = items
      })
      let _columns = [...columns.values()]
      let _additems = _columns.map(item => { // 循环添加新增字段
        return {
          uuid: Utils.getuuid(),
          label: item.label,
          field: item.field,
          initval: '',
          type: item.type,
          resourceType: '0',
          setAll: 'false',
          options: [],
          dataSource: '',
          orderType: 'asc',
          decimal: 0,
          readonly: 'false',
          required: 'true'
        }
      })
      _config.groups[_config.groups.length - 1].sublist = [..._config.groups.slice(-1)[0].sublist, ..._additems]
    } else {
      let items = []
      _config.fields.forEach(item => {
        if (columns.has(item.field)) {
          let cell = columns.get(item.field)
          if (cell.selected && cell.type === item.type) { // 数据选择状态及类型未修改时,直接添加
            items.push(item)
          } else if (cell.selected) {                     // 数据类型修改时,重置类型及初始值
            item.type = cell.type
            item.initval = ''
            items.push(item)
          }
          columns.delete(item.field)
        } else if (!item.origin) {                        // 过滤示例项
          items.push(item)
        }
      })
      let _columns = [...columns.values()]
      _columns.forEach(item => { // 循环添加新增字段
        if (item.selected) {
          let newcard = {
            uuid: Utils.getuuid(),
            label: item.label,
            field: item.field,
            initval: '',
            type: item.type,
            resourceType: '0',
            setAll: 'false',
            options: [],
            dataSource: '',
            orderType: 'asc',
            readonly: 'false',
            required: 'true'
          }
          items.push(newcard)
        }
      })
      _config.fields = items
    }
    this.setState({
      config: _config
    })
    notification.success({
      top: 92,
      message: '添加成功',
      duration: 2
    })
  }
  /**
   * @description 添加表名
   * 1、获取表信息
   * 2、检验是否已经添加,已添加时跳过
   * 3、通过表名获取字段集,并设置数据类型
   */
  onTableChange = (value) => {
    const {tables, selectedTables, tableColumns} = this.state
    let _table = tables.filter(item => item.TbName === value)[0]
    let isSelected = !!selectedTables.filter(cell => cell.TbName === value)[0]
    if (isSelected) return
    this.setState({
      selectedTables: [...selectedTables, _table]
    })
    Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: value}).then(res => {
      if (res.status) {
        let tabmsg = {
          tableName: _table.name,
          columns: res.FDName.map(item => {
            let _type = item.FieldType.toLowerCase()
            let _decimal = 0
            if (/^nvarchar/.test(_type)) {
              _type = 'text'
            } else if (/^int/.test(_type)) {
              _type = 'number'
            } else if (/^decimal/.test(_type)) {
              _decimal = _type.split(',')[1]
              _decimal = parseInt(_decimal)
              _type = 'number'
            } else if (/^datetime/.test(_type)) {
              _type = 'datetime'
            } else if (/^date/.test(_type)) {
              _type = 'date'
            } else {
              _type = 'text'
            }
            return {
              field: item.FieldName,
              label: item.FieldDec,
              type: _type,
              decimal: _decimal
            }
          })
        }
        this.setState({
          tableColumns: [...tableColumns, tabmsg]
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 10
        })
      }
    })
  }
  /**
   * @description 删除表名,删除对应字段集
   */
  deleteTable = (table) => {
    const {selectedTables, tableColumns} = this.state
    this.setState({
      selectedTables: selectedTables.filter(item => item.TbName !== table.TbName),
      tableColumns: tableColumns.filter(item => item.tableName !== table.TbName)
      config: config,
      tableFields: fields ? fields : tableFields
    })
  }
@@ -1071,13 +746,22 @@
  /**
   * @description 编辑功能完成更新,包括解冻按钮、粘贴、替换等
   */
  updateConfig = (res) => {
  updateEditConfig = (res) => {
    if (res.type === 'paste') {
      this.setState({
        config: res.content
      })
      this.handleForm(res.newform)
    }
  }
  /**
   * @description 更新配置信息
   */
  updateconfig = (config) => {
    this.setState({
      config: config
    })
  }
  render () {
@@ -1088,43 +772,17 @@
        <DndProvider backend={HTML5Backend}>
          <div className="tools">
            <Collapse accordion defaultActiveKey="1" bordered={false}>
              <Panel header={dict['header.menu.basedata']} key="0" id="modal-basedata">
              <Panel forceRender={true} header={dict['header.menu.basedata']} key="0" id="modal-basedata">
                <MenuForm
                  dict={dict}
                  formlist={this.state.modalformlist}
                />
                <div className="ant-col ant-form-item-label">
                  <label title={dict['header.menu.table.add']}>
                    {dict['header.menu.table.add']}
                  </label>
                </div>
                <Select
                  showSearch
                  showArrow={false}
                  className="tables"
                  style={{ width: '100%' }}
                  optionFilterProp="children"
                  value={dict['header.menu.table.placeholder']}
                  onChange={this.onTableChange}
                  getPopupContainer={() => document.getElementById('modal-basedata')}
                  filterOption={(input, option) => {
                    return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                  }}
                >
                  {this.state.tables.map((table, index) => (
                    <Option key={index} title={table.TbName} value={table.TbName}>{table.Remark}</Option>
                  ))}
                </Select>
                {this.state.selectedTables.length > 0 && <List
                  size="small"
                  bordered
                  dataSource={this.state.selectedTables}
                  renderItem={(item, index) => <List.Item key={index} title={item.Remark + ' (' + item.TbName + ')'}>
                    {item.Remark + ' (' + item.TbName + ')'}
                    <Icon type="close" onClick={() => this.deleteTable(item)}/>
                    <div className="bottom-mask"></div>
                  </List.Item>}
                />}
                {/* 表名添加 */}
                <TableComponent
                  config={config}
                  containerId="modal-basedata"
                  updatetable={this.updatetable}
                />
              </Panel>
              <Panel header={dict['header.menu.form']} key="1">
                <div className="search-element">
@@ -1132,7 +790,12 @@
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                <Button type="primary" block onClick={() => this.queryField()}>{dict['header.menu.form.add']}</Button>
                <FieldsComponent
                  config={config}
                  type="form"
                  tableFields={this.state.tableFields}
                  updatefield={this.updateconfig}
                />
                <Button type="primary" block onClick={() => this.handleGroup()}>{dict['header.menu.group.add']}</Button>
              </Panel>
            </Collapse>
@@ -1140,7 +803,7 @@
          <div className="setting">
            <Card title={dict['header.menu.form.configurable']} bordered={false} extra={
              <div>
                <EditComponent dict={dict} type="form" config={this.state.config} refresh={this.updateConfig}/>
                <EditComponent dict={dict} type="form" config={this.state.config} refresh={this.updateEditConfig}/>
                <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{dict['model.save']}</Button>
                <Button onClick={this.cancelConfig}>{dict['model.back']}</Button>
              </div>
@@ -1227,25 +890,6 @@
            inputSubmit={this.handleSubmit}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
        <Modal
          wrapClassName="modal-fields"
          title={dict['model.edit']}
          visible={this.state.tableVisible}
          width={'65vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          onOk={this.addFieldSubmit}
          cancelText={dict['model.close']}
          onCancel={() => { this.setState({ tableVisible: false }) }}
          destroyOnClose
        >
          {this.state.fields && this.state.fields.length > 0 ?
            <EditCard data={this.state.fields} ref="searchcard" type="search" /> : null
          }
          {(!this.state.fields || this.state.fields.length === 0) &&
            <Empty />
          }
        </Modal>
        <Modal
          title={dict['model.edit']}
src/templates/sharecomponent/columncomponent/index.jsx
@@ -172,18 +172,12 @@
    if (modaltype === 'columns' || 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
            }
          }
@@ -198,20 +192,6 @@
          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
src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -67,6 +67,24 @@
          columns.set(item.field, {...item, selected: true, datatype: _datatype})
        }
      })
    } else if (type === 'form') {
      if (config.groups.length > 1) {
        config.groups.forEach(group => {
          group.sublist.forEach(item => {
            if (columns.has(item.field)) {
              let _datatype = columns.get(item.field).datatype
              columns.set(item.field, {...item, selected: true, datatype: _datatype})
            }
          })
        })
      } else {
        config.fields.forEach(item => {
          if (columns.has(item.field)) {
            let _datatype = columns.get(item.field).datatype
            columns.set(item.field, {...item, selected: true, datatype: _datatype})
          }
        })
      }
    }
    // 显示字段集弹窗
@@ -153,6 +171,7 @@
          items.push(newcard)
        }
      })
      config.search = items
    } else if (type === 'columns') {
      config.columns.forEach(item => {
        if (columnsMap.has(item.field)) {
@@ -191,6 +210,7 @@
          items.push(newcard)
        }
      })
      config.columns = items
    } else if (type === 'fields') {
      config.columns.forEach(item => {
        if (columnsMap.has(item.field)) {
@@ -219,24 +239,96 @@
          items.push(newcard)
        }
      })
    } else if (type === 'form') {
      if (config.groups.length > 1) {
        config.groups.forEach(group => {
          group.sublist.forEach(item => {
            if (columnsMap.has(item.field)) {
              let cell = columnsMap.get(item.field)
              if (cell.selected && cell.type === item.type) { // 数据选择状态及类型未修改时,直接添加
                items.push(item)
              } else if (cell.selected) {                     // 数据类型修改时,重置类型及初始值
                item.type = cell.type
                item.initval = ''
                items.push(item)
              }
              columnsMap.delete(item.field)
            } else if (!item.origin) {                        // 过滤示例项
              items.push(item)
            }
          })
          group.sublist = items
        })
        let _columns = [...columnsMap.values()]
        let _additems = _columns.map(item => { // 循环添加新增字段
          return {
            uuid: Utils.getuuid(),
            label: item.label,
            field: item.field,
            initval: '',
            type: item.type,
            resourceType: '0',
            setAll: 'false',
            options: [],
            dataSource: '',
            orderType: 'asc',
            decimal: item.decimal,
            readonly: 'false',
            required: 'true'
          }
        })
        config.groups[config.groups.length - 1].sublist = [...config.groups.slice(-1)[0].sublist, ..._additems]
      } else {
        config.fields.forEach(item => {
          if (columnsMap.has(item.field)) {
            let cell = columnsMap.get(item.field)
            if (cell.selected && cell.type === item.type) { // 数据选择状态及类型未修改时,直接添加
              items.push(item)
            } else if (cell.selected) {                     // 数据类型修改时,重置类型及初始值
              item.type = cell.type
              item.initval = ''
              items.push(item)
            }
            columnsMap.delete(item.field)
          } else if (!item.origin) {                        // 过滤示例项
            items.push(item)
          }
        })
        let _columns = [...columnsMap.values()]
        _columns.forEach(item => { // 循环添加新增字段
          if (item.selected) {
            let newcard = {
              uuid: Utils.getuuid(),
              label: item.label,
              field: item.field,
              initval: '',
              type: item.type,
              resourceType: '0',
              setAll: 'false',
              options: [],
              dataSource: '',
              decimal: item.decimal,
              orderType: 'asc',
              readonly: 'false',
              required: 'true'
            }
            items.push(newcard)
          }
        })
        config.fields = items
      }
    }
    let _config = null
    if (type === 'search') {
      _config = {...this.props.config, search: items}
      this.props.updatefield(_config)
      notification.success({
        top: 92,
        message: '操作成功',
        duration: 2
      })
    } else if (type === 'columns') {
      _config = {...this.props.config, columns: items}
      this.props.updatefield(_config)
    if (type === 'search' || type === 'columns' || type === 'form') {
      this.props.updatefield(config)
      notification.success({
        top: 92,
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -330,7 +330,7 @@
        let rules = []
        if (item.key === 'field' || item.key === 'datefield') {
          rules = [{
            pattern: openType === 'text' ? formRule.field.multipattern : formRule.field.pattern,
            pattern: (openType === 'text' || openType === 'select') ? formRule.field.multipattern : formRule.field.pattern,
            message: formRule.field.message
          }, {
            max: formRule.field.max,
src/templates/sharecomponent/tablecomponent/index.jsx
@@ -5,6 +5,7 @@
import moment from 'moment'
import Api from '@/api'
import options from '@/store/options.js'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
@@ -24,10 +25,8 @@
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    tables: [],          // 系统表
    tableFields: [],    // 已选表字段集
    tableFields: [],     // 已选表字段集
    selectedTables: [],  // 已选表
    searchlist: null,    // 搜索条件集
    visible: false       // 模态框控制
  }
  /**
@@ -63,7 +62,13 @@
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
    Api.getSystemConfig(param).then(res => {
    if (options.cloudServiceApi) { // 且存在云端地址
      param.rduri = options.cloudServiceApi
      param.userid = sessionStorage.getItem('CloudUserID') || ''
      param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
    }
    Api.getSystemCacheConfig(param).then(res => {
      if (res.status) {
        this.setState({
          tables: res.data
@@ -81,7 +86,14 @@
  gettableFields = () => {
    let deffers = this.state.selectedTables.map(item => {
      return new Promise(resolve => {
        Api.getSystemConfig({func: 'sPC_Get_FieldName', TBName: item.TbName}).then(res => {
        let param = {func: 'sPC_Get_FieldName', TBName: item.TbName}
        if (options.cloudServiceApi) { // 且存在云端地址
          param.rduri = options.cloudServiceApi
          param.userid = sessionStorage.getItem('CloudUserID') || ''
          param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
        }
        Api.getSystemCacheConfig(param).then(res => {
          res.TBName = item.TbName
          resolve(res)
        })
src/templates/zshare/customscript/index.jsx
@@ -1,16 +1,17 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Icon, Button, notification, Select, Table, Popconfirm, Typography } from 'antd'
import { Form, Row, Col, Icon, Button, notification, Select, Popconfirm, Typography } from 'antd'
import moment from 'moment'
import Utils from '@/utils/utils.js'
// import SettingUtils from '../utils.jsx'
import Api from '@/api'
import CodeMirror from '@/templates/zshare/codemirror'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { Paragraph } = Typography
const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
class CustomForm extends Component {
  static propTpyes = {
@@ -32,15 +33,24 @@
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '70%',
        render: (text) => (
          <Paragraph copyable ellipsis={{ rows: 5, expandable: true }}>{text}</Paragraph>
        )
        width: '73%',
        render: (text) => {
          let title = text.match(/^\s*\/\*.+\*\//)
          title = title && title[0] ? title[0] : ''
          text = title ? text.replace(title, '') : text
          return (
            <div>
              {title ? <span style={{color: '#a50'}}>{title}</span> : null}
              <Paragraph copyable ellipsis={{ rows: 4, expandable: true }}>{text}</Paragraph>
            </div>
          )
        }
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '10%',
        width: '12%',
        render: (text, record) => record.status === 'false' ?
          (
            <div>
@@ -58,13 +68,11 @@
      {
        title: '操作',
        align: 'center',
        width: '20%',
        width: '15%',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div>
          (<div style={{textAlign: 'center'}}>
            <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>
            <span className="operation-btn" title={this.props.dict['header.form.status.change']} onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><Icon type="swap" /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
@@ -148,8 +156,6 @@
      }
    })
  }
  handleCancel = () => {
    this.setState({
@@ -307,27 +313,7 @@
    }
  }
  handleUpDown = (record, direction) => {
    let scripts = fromJS(this.state.scripts).toJS()
    let index = 0
    scripts = scripts.filter((item, i) => {
      if (item.uuid === record.uuid) {
        index = i
      }
      return item.uuid !== record.uuid
    })
    if ((index === 0 && direction === 'up') || (index === scripts.length && direction === 'down')) {
      return
    }
    if (direction === 'up') {
      scripts.splice(index - 1, 0, record)
    } else {
      scripts.splice(index + 1, 0, record)
    }
  changeScripts = (scripts) => {
    this.setState({scripts})
    this.props.scriptsUpdate(scripts)
  }
@@ -372,8 +358,8 @@
    }
    return (
      <div>
        <Form {...formItemLayout} className="modal-menu-setting-script">
      <div className="modal-menu-setting-script">
        <Form {...formItemLayout}>
          <Row gutter={24}>
            {setting.tableName ? <Col span={8}>
              <Form.Item label={'表名'} style={{whiteSpace: 'nowrap', margin: 0}}>
@@ -421,14 +407,7 @@
            </Col>
          </Row>
        </Form>
        <Table
          bordered
          rowKey="uuid"
          className="custom-table"
          dataSource={scripts}
          columns={scriptsColumns}
          pagination={false}
        />
        <EditTable data={scripts} actions={[]} columns={scriptsColumns} onChange={this.changeScripts}/>
      </div>
    )
  }
src/templates/zshare/customscript/index.scss
@@ -39,4 +39,7 @@
      height: 350px;
    }
  }
  div.ant-typography {
    margin-bottom: 0;
  }
}
src/templates/zshare/editTable/index.jsx
@@ -165,39 +165,41 @@
    const { data, actions } = this.props
    let columns = fromJS(this.props.columns).toJS()
    columns.push({
      title: eTDict['model.operation'],
      dataIndex: 'operation',
      width: '140px',
      render: (text, record) => {
        const { editingKey } = this.state
        const editable = this.isEditing(record)
        return editable ? (
          <span style={{textAlign: 'center', display: 'block'}}>
            <EditableContext.Consumer>
              {form => (
                <span onClick={() => this.save(form, record.uuid)} style={{ marginRight: 8 , color: '#1890ff', cursor: 'pointer'}}>
                  {eTDict['model.save']}
                </span>
              )}
            </EditableContext.Consumer>
            <span style={{ color: '#1890ff', cursor: 'pointer'}} onClick={() => this.cancel(record.uuid)}>{eTDict['model.cancel']}</span>
          </span>
        ) : (
          <div className={'edit-operation-btn' + (editingKey !== '' ? ' disabled' : '')}>
            {!actions || actions.includes('edit') ? <span className="primary" onClick={() => {editingKey === '' && this.edit(record.uuid)}}><Icon type="edit" /></span> : null}
            {(!actions || actions.includes('del')) && editingKey === '' ? <Popconfirm
              overlayClassName="popover-confirm"
              title={eTDict['model.query.delete']}
              onConfirm={() => this.handleDelete(record.uuid)
            }>
              <span className="danger"><Icon type="delete" /></span>
            </Popconfirm> : null}
            {(!actions || actions.includes('del')) && editingKey !== '' ? <span className="danger"><Icon type="delete" /></span> : null}
          </div>
        )
      }
    })
    if (!actions || actions.length > 0) {
      columns.push({
        title: eTDict['model.operation'],
        dataIndex: 'operation',
        width: '140px',
        render: (text, record) => {
          const { editingKey } = this.state
          const editable = this.isEditing(record)
          return editable ? (
            <span style={{textAlign: 'center', display: 'block'}}>
              <EditableContext.Consumer>
                {form => (
                  <span onClick={() => this.save(form, record.uuid)} style={{ marginRight: 8 , color: '#1890ff', cursor: 'pointer'}}>
                    {eTDict['model.save']}
                  </span>
                )}
              </EditableContext.Consumer>
              <span style={{ color: '#1890ff', cursor: 'pointer'}} onClick={() => this.cancel(record.uuid)}>{eTDict['model.cancel']}</span>
            </span>
          ) : (
            <div className={'edit-operation-btn' + (editingKey !== '' ? ' disabled' : '')}>
              {!actions || actions.includes('edit') ? <span className="primary" onClick={() => {editingKey === '' && this.edit(record.uuid)}}><Icon type="edit" /></span> : null}
              {(!actions || actions.includes('del')) && editingKey === '' ? <Popconfirm
                overlayClassName="popover-confirm"
                title={eTDict['model.query.delete']}
                onConfirm={() => this.handleDelete(record.uuid)
              }>
                <span className="danger"><Icon type="delete" /></span>
              </Popconfirm> : null}
              {(!actions || actions.includes('del')) && editingKey !== '' ? <span className="danger"><Icon type="delete" /></span> : null}
            </div>
          )
        }
      })
    }
    this.setState({
      data: data || [],
@@ -352,7 +354,7 @@
        cell: EditableCell
      }
    }
    if (!actions || actions.includes('down') || actions.includes('up')) {
    if (!actions || actions.length === 0 || actions.includes('down') || actions.includes('up')) {
      components.body.row = DragableBodyRow
    }
    
src/templates/zshare/formconfig.jsx
@@ -1200,7 +1200,7 @@
      key: 'rowspan',
      label: '行合并',
      initVal: card.rowspan || 'false',
      tooltip: '相邻行信息相同时,单元格合并。注:为防止表格信息错乱,行合并只能添加一个字段。',
      tooltip: '相邻行信息相同时,单元格合并。',
      required: false,
      options: [{
        value: 'true',
src/templates/zshare/verifycard/index.jsx
@@ -43,6 +43,7 @@
    voucherDetail: [],
    systemScripts: [],
    columnsFields: [],
    unionFields: [],
    uniqueColumns: [
      {
        title: '名称',
@@ -465,6 +466,7 @@
    _verify.uniques = _verify.uniques || []
    _verify.contrasts = _verify.contrasts || []
    _verify.accountdate = _verify.accountdate || 'false'
    _verify.accountfield = _verify.accountfield || ''
    _verify.customverifys = _verify.customverifys || []
    _verify.billcodes = _verify.billcodes || []
    _verify.voucher = _verify.voucher || {enabled: false}
@@ -595,12 +597,15 @@
        }
      }
      let unionFields = fromJS(_fields).toJS()
      if (hasColumn) {
        columns.forEach(_f => {
          if (!_f.field || fieldArr.includes(_f.field.toLowerCase())) return
          fieldArr.push(_f.field.toLowerCase())
          unionFields.push(_f)
          _usefulfields.push(_f.field)
          if (_f.datatype) { // 自定义字段
@@ -798,7 +803,8 @@
            col.options = _columns
          }
          return col
        })
        }),
        unionFields
      })
    })
  }
@@ -823,7 +829,13 @@
      {
        obj_name: 'voucherDetail',
        arr_field: 'ModularDetailCode,CodeName,BID,VoucherTypeTwo,IDefine1',
        LText: window.btoa(window.encodeURIComponent(`select distinct ModularDetailCode,ModularDetailCode+ModularDetailName as CodeName,ModularCode as BID, VoucherTypeTwo, IDefine1 from sModularDetail where Deleted=0 and VoucherTypeTwo!='' and Appkey=case when Appkey='' then '' else @Appkey@ end  order by ModularDetailCode`))
        LText: window.btoa(window.encodeURIComponent(`select distinct ModularDetailCode,ModularDetailCode+ModularDetailName as CodeName,ModularCode as BID, VoucherTypeTwo, IDefine1 from sModularDetail where Deleted=0 and VoucherTypeTwo!=''
          and Appkey=@Appkey@ union
          select distinct a.ModularDetailCode,a.ModularDetailCode+ModularDetailName as CodeName,ModularCode as BID, VoucherTypeTwo, IDefine1
          from (select * from sModularDetail where Deleted=0 and VoucherTypeTwo!='' and Appkey='') a
          left join (select distinct ModularDetailCode from sModularDetail where Deleted=0 and VoucherTypeTwo!=''
          and Appkey=@Appkey@) m on a.ModularDetailCode=m.ModularDetailCode where m.ModularDetailCode is null order by ModularDetailCode`
        ))
      },
      {
        obj_name: 'noteCodes',
@@ -982,6 +994,14 @@
    this.setState({
      verify: {...verify, [key]: value}
    })
  }
  changeAccField = (val) => {
    const { verify } = this.state
    this.setState({
      verify: {...verify, accountfield: val}
    })
  }
@@ -1216,6 +1236,13 @@
          duration: 5
        })
        return
      } else if (verify.accountdate === 'true' && !verify.accountfield) {
        notification.warning({
          top: 92,
          message: '开启账期时,需要选择验证公司!',
          duration: 5
        })
        return
      }
      let _loading = false
@@ -1264,7 +1291,7 @@
  render() {
    const { card } = this.props
    const { verify, fields, uniqueColumns, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes } = this.state
    const { verify, fields, uniqueColumns, unionFields, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -1303,6 +1330,17 @@
                    </Radio.Group>
                  </Form.Item>
                </Col>
                {verify.accountdate === 'true' ? <Col span={8}>
                  <Form.Item label={'验证公司'} required>
                    <Select defaultValue={verify.accountfield || ''} onChange={this.changeAccField}>
                      {unionFields.map(option =>
                        <Select.Option key={option.uuid} value={option.field}>
                          {option.label}
                        </Select.Option>
                      )}
                    </Select>
                  </Form.Item>
                </Col> : null}
                <Col span={8}>
                  <Form.Item label={'失效验证'}>
                    <Radio.Group value={verify.invalid} onChange={(e) => {this.onOptionChange(e, 'invalid')}}>
src/utils/utils.js
@@ -440,7 +440,7 @@
        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : ''
        newsearches[item.key + '1'] = item.value ? _endval + ' 00:00:00.000' : ''
      } else if (item.type === 'text') {
      } else if (item.type === 'text' || item.type === 'select') {
        item.key.split(',').forEach(field => { // 综合搜索,所字段拼接
          newsearches[field] = item.value
        })
@@ -473,17 +473,13 @@
      if (item.forbid || !item.value || (item.type === 'multiselect' && item.value.length === 0)) return
      
      searchText += (searchText !== '' ? ' AND ' : '')
      if (item.type === 'text') {
      if (item.type === 'text' || item.type === 'select') { // 综合搜索,文本或下拉,所有字段拼接
        let str = item.match === '=' ? '' : '%'
        let fields = item.key.split(',').map(field => { // 综合搜索,所字段拼接
        let fields = item.key.split(',').map(field => {
          return field + ' ' + item.match + ' \'' + str + item.value + str + '\''
        })
        searchText += '(' + fields.join(' OR ') + ')'
      } else if (item.type === 'select') {
        let str = item.match === '=' ? '' : '%'
        searchText += item.key + ' ' + item.match + ' \'' + str + item.value + str + '\''
      } else if (item.type === 'multiselect') {
        searchText += `'${item.value}' ` + item.match + ' \'%\'+' + item.key + '+\'%\''
@@ -595,12 +591,12 @@
        item.value = item.value ? item.value.join(',') : item.value
        options.push(item)
      } else if (item.type === 'text') {
      } else if (item.type === 'text' || item.type === 'select') {
        item.key.split(',').forEach(field => { // 综合搜索,所字段拼接
          let cell = JSON.parse(JSON.stringify(item))
          cell.key = field
          options.push(item)
          options.push(cell)
        })
      } else {
        options.push(item)
@@ -645,6 +641,13 @@
        options.push({
          key: item.key + '1',
          value: '0'
        })
      } else if (search.type === 'text' || search.type === 'select') {
        item.key.split(',').forEach(field => {
          let cell = JSON.parse(JSON.stringify(item))
          cell.key = field
          options.push(cell)
        })
      } else {
        options.push(item)
@@ -1258,7 +1261,7 @@
    if (verify.accountdate === 'true') {
      _sql += `
        /* 账期验证 */
        exec s_FIBVoucherDateCheck @ErrorCode=@ErrorCode OUTPUT,@retmsg=@retmsg OUTPUT
        exec s_FIBVoucherDateCheck @OrgCode=${verify.accountfield ? '@' + verify.accountfield : '\'\''}, @ErrorCode=@ErrorCode OUTPUT,@retmsg=@retmsg OUTPUT
        if @ErrorCode!=''
          GOTO aaa
        `