king
2019-11-22 67e7787f24a1ca3dc45f77fb7bbcb76edc33fe55
2019-11-22-01
22 文件已重命名
4个文件已修改
13 文件已复制
10个文件已添加
3089 ■■■■■ 已修改文件
src/components/header/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/index.jsx 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/comtable.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/comtable.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/actionform/index.jsx 304 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/actionform/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/columnform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/columnform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/dragelement/card.jsx 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/dragelement/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/dragelement/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/dragelement/itemtypes.js 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/dragelement/source.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/editable/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/editable/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/editcard/index.jsx 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/editcard/index.scss 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 1448 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.scss 368 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/menuform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/searchform/index.jsx 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/searchform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/settingform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/settingform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/source.jsx 274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/actionform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/actionform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/columnform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/columnform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/card.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/itemtypes.js 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/source.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/editable/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/editable/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/editcard/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/editcard/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/menuform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/searchform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/searchform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/source.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/asyncLoadComponent.jsx 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx
@@ -12,8 +12,8 @@
import zhCN from '@/locales/zh-CN/header.js'
import enUS from '@/locales/en-US/header.js'
import Utils from '@/utils/utils.js'
import logourl from '../../assets/img/mlogo.png'
import avatar from '../../assets/img/avatar.jpg'
import logourl from '@/assets/img/mlogo.png'
import avatar from '@/assets/img/avatar.jpg'
import './index.scss'
const EditMenu = asyncComponent(() => import('./editmenu'))
src/components/sidemenu/editthdmenu/index.jsx
@@ -8,16 +8,15 @@
import TransferForm from '@/components/transferform'
import Utils from '@/utils/utils.js'
import DragElement from '../menuelement'
// import MenuForm from '../menuform'
// import ComTableConfig from '../comtableconfig'
import asyncComponent from '@/utils/asyncComponent'
import asyncLoadComponent from '@/utils/asyncLoadComponent'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/header.js'
import enUS from '@/locales/en-US/header.js'
import nortable from '@/assets/img/normaltable.jpg'
import './index.scss'
const ComTableConfig = asyncComponent(() => import('../comtableconfig'))
const ComTableConfig = asyncLoadComponent(() => import('@/templates/comtableconfig'))
const ModalConfig = asyncLoadComponent(() => import('@/templates/modalconfig'))
const { confirm } = Modal
const { TabPane } = Tabs
const illust = {
@@ -43,7 +42,6 @@
    tabview: '', // 选择模板窗口(template)、基础表格配置(CommonTable)
    formlist: null,
    editMenu: null, // 编辑菜单
    editMvisible: false, // 编辑菜单模态框
    thawMvisible: false, // 解除冻结模态框
    confirmLoading: false, // 提交中。。。
    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
@@ -118,6 +116,7 @@
            }
          }
          _menu.LongParam = _LongParam
          _menu.ParentID = this.props.supMenu.MenuID
          // console.log(_menu)
          // 检测模板是否存在
          let _Template = this.state.baseTemplates.filter(temp => temp.type === _menu.PageParam.Template)
@@ -212,14 +211,6 @@
    }
  }
  // memuHandleCancel = () => {
  //   this.setState({
  //     editMvisible: false,
  //     visible: false
  //   })
  //   this.resetFormlist()
  // }
  thawMemuSubmit = () => {
    // 三级菜单解除冻结
    if (this.refs.trawmenu.state.targetKeys.length === 0) {
@@ -303,7 +294,8 @@
          text: '',
          type: template.type,
          PageParam: {OpenType: "newtab", Template: template.type},
          LongParam: ''
          LongParam: '',
          ParentID: this.props.supMenu.MenuID
        }
      })
    } else {
@@ -316,107 +308,6 @@
    }
    document.getElementById('root').style.overflowY = 'hidden'
  }
  // submitMenuConfig = () => {
  //   if (this.state.type !== 'edit') {
  //     this.setState({
  //       visible: true,
  //       title: this.state.dict['header.menu.addtitle'],
  //       formlist: [
  //         {
  //           type: 'text',
  //           key: 'parentId',
  //           label: this.state.dict['header.menu.supMenu'],
  //           initVal: this.props.supMenu.text,
  //           required: true,
  //           readonly: true
  //         },
  //         {
  //           type: 'text',
  //           key: 'menuName',
  //           label: this.state.dict['header.menu.menuName'],
  //           initVal: '',
  //           required: true,
  //           readonly: false
  //         },
  //         {
  //           type: 'text',
  //           key: 'menuNo',
  //           label: this.state.dict['header.menu.menuNo'],
  //           initVal: '',
  //           required: true,
  //           readonly: false
  //         },
  //         {
  //           type: 'select',
  //           key: 'opentype',
  //           label: '打开方式',
  //           initVal: 'newtab',
  //           required: true,
  //           options: [{
  //             MenuID: 'newtab',
  //             text: '新标签页'
  //           }, {
  //             MenuID: 'newpage',
  //             text: '新页面'
  //           }]
  //         }
  //       ]
  //     })
  //   } else {
  //     console.log(this.state.editMenu)
  //     // confirm({
  //     //   title: this.state.dict['header.menu.update'].replace('@M', menu.card.text),
  //     //   content: '',
  //     //   okText: this.state.dict['header.confirm'],
  //     //   cancelText: this.state.dict['header.cancel'],
  //     //   onOk() {
  //     //     let param = {
  //     //       func: 'sPC_MainMenu_Del',
  //     //       MenuID: menu.card.MenuID
  //     //     }
  //     //     return Api.getSystemConfig(param).then(res => {
  //     //       if (res.status) {
  //     //         _this.props.reload()
  //     //       } else {
  //     //         notification.warning({
  //     //           top: 92,
  //     //           message: res.message,
  //     //           duration: 10
  //     //         })
  //     //       }
  //     //     })
  //     //   },
  //     //   onCancel() {}
  //     // })
  //     this.setState({
  //       tabview: this.state.selectTemp.type
  //     })
  //   }
  // }
  // changeTemp = () => {
  //   this.setState({
  //     editMvisible: false,
  //     tabview: 'template'
  //   })
  //   this.resetFormlist()
  // }
  // changeConfig = () => {
  //   this.setState({
  //     editMvisible: false,
  //     tabview: this.state.editMenu.PageParam.Template,
  //     menuConfig: window.atob(this.state.editMenu.LongParam)
  //   })
  //   this.resetFormlist()
  // }
  // resetFormlist = () => {
  //   setTimeout(() => {
  //     this.setState({formlist: null})
  //   }, 300)
  // }
  getUsedTemplate = () => {
    Api.getSystemConfig({func: 'sPC_Get_UserTemp'}).then(res => {
@@ -449,6 +340,17 @@
  handleConfig = (type) => {
    this.setState({tabview: type})
    document.getElementById('root').style.overflowY = 'unset'
  }
  handleSubConfig = (item, originMenu, config) => {
    if (item.OpenType === 'pop') {
      // this.setState({
      //   editMenu: originMenu,
      //   tabview: 'Modal'
      // })
    }
    console.log(item)
    console.log(originMenu)
  }
  UNSAFE_componentWillMount () {
@@ -536,6 +438,14 @@
          <ComTableConfig
            type={this.state.type}
            menu={this.state.editMenu}
            supMenuList={this.props.supMenuList}
            handleConfig={this.handleConfig}
            handleSubConfig={this.handleSubConfig}
          />
        }
        {this.state.tabview === 'Modal' &&
          <ModalConfig
            menu={this.state.editMenu}
            supMenu={this.props.supMenu}
            supMenuList={this.props.supMenuList}
            handleConfig={this.handleConfig}
src/locales/en-US/comtable.js
@@ -30,6 +30,9 @@
  'header.form.innerFunc': '内部函数',
  'header.form.outerFunc': '外部函数',
  'header.form.callbackFunc': '回调函数',
  'header.form.position': '显示位置',
  'header.form.toolbar': '工具栏',
  'header.form.grid': '表格',
  'header.form.intertype': '接口类型',
  'header.form.interface': '接口地址',
  'header.form.interface.inner': '内部',
@@ -74,6 +77,7 @@
  'header.form.valueText': '文本·字段',
  'header.form.orderBy': '排序·字段',
  'header.form.orderType': '排序方式',
  'header.form.match': '匹配模式',
  'header.form.asc': '正序',
  'header.form.desc': '倒序',
  'header.form.linkField': '关联字段',
src/locales/zh-CN/comtable.js
@@ -30,6 +30,9 @@
  'header.form.innerFunc': '内部函数',
  'header.form.outerFunc': '外部函数',
  'header.form.callbackFunc': '回调函数',
  'header.form.position': '显示位置',
  'header.form.toolbar': '工具栏',
  'header.form.grid': '表格',
  'header.form.intertype': '接口类型',
  'header.form.interface': '接口地址',
  'header.form.interface.inner': '内部',
@@ -74,6 +77,7 @@
  'header.form.valueText': '文本·字段',
  'header.form.orderBy': '排序·字段',
  'header.form.orderType': '排序方式',
  'header.form.match': '匹配模式',
  'header.form.asc': '正序',
  'header.form.desc': '倒序',
  'header.form.linkField': '关联字段',
src/templates/comtableconfig/actionform/index.jsx
New file
@@ -0,0 +1,304 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, Icon, Radio } from 'antd'
import './index.scss'
const btnIcons = [{
  MenuID: '',
  text: 'unset'
}, {
  MenuID: 'plus',
  text: 'plus'
}, {
  MenuID: 'plus-circle',
  text: 'plus-circle'
}, {
  MenuID: 'edit',
  text: 'edit'
}, {
  MenuID: 'form',
  text: 'form'
}, {
  MenuID: 'close',
  text: 'close'
}, {
  MenuID: 'close-circle',
  text: 'close-circle'
}, {
  MenuID: 'delete',
  text: 'delete'
}]
const btnClasses = [{
  MenuID: 'default',
  text: '默认(黑边白底)'
}, {
  MenuID: 'primary',
  text: '蓝色'
}, {
  MenuID: 'yellow',
  text: '黄色'
}, {
  MenuID: 'danger',
  text: '红色'
}, {
  MenuID: 'green',
  text: '绿色'
}, {
  MenuID: 'dgreen',
  text: '深绿色'
}, {
  MenuID: 'purple',
  text: '紫色'
}, {
  MenuID: 'gray',
  text: '灰色'
}]
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    formlist: PropTypes.any,
    card: PropTypes.any
  }
  state = {
    formlist: null,
    openType: null,
    interType: null,
    expand: false
  }
  openTypeChange = (key, value) => {
    if (key === 'OpenType') {
      let _options = null
      if (value === 'newpage') {
        _options = ['label', 'position', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class']
      }
      this.setState({
        openType: value,
        expand: value === 'newpage' ? false : this.state.expand,
        formlist: this.state.formlist.map(item => {
          if (_options) {
            item.hidden = !_options.includes(item.key)
            if (item.key === 'intertype') {
              item.initVal = 'inner'
            }
            item.readonly = ['interface', 'outerFunc', 'callbackFunc'].includes(item.key)
          }
          return item
        })
      })
    }
  }
  onChange = (e, key) => {
    let value = e.target.value
    if (key === 'intertype') {
      this.setState({
        interType: value,
        formlist: this.state.formlist.map(item => {
          if (value === 'inner') {
            item.readonly = ['interface', 'outerFunc', 'callbackFunc'].includes(item.key)
          } else {
            item.readonly = false
          }
          return item
        })
      })
    }
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.hidden) return
      if (item.type === 'text') { // 文本搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: item.readonly ? false : !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(value) => {this.openTypeChange(item.key, value)}}
                  getPopupContainer={() => document.getElementById('winter')}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.MenuID} title={option.text} key={option.MenuID} value={option.MenuID}>
                      {item.key === 'icon' && option.MenuID && <Icon type={option.MenuID} />} {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'radio') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}>
                  {
                    item.options.map(option => {
                      return (
                        <Radio key={option.MenuID} value={option.MenuID}>{option.text}</Radio>
                      )
                    })
                  }
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values.id = this.props.card.id
          values.uuid = this.props.card.uuid
          if (!this.state.expand) {
            values.intertype = 'inner'
          }
          resolve({
            type: 'action',
            values
          })
        } else {
          reject(err)
        }
      })
    })
  }
  toggle = () => {
    let expand = !this.state.expand
    let _options = null
    if (expand) {
      _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class']
    } else {
      _options = ['label', 'position', 'OpenType', 'innerFunc', 'Ot', 'icon', 'class']
    }
    if (!expand) {
      this.setState({
        expand: !this.state.expand,
        formlist: this.state.formlist.map(item => {
          if (item.key === 'intertype') {
            item.initVal = 'inner'
          }
          item.readonly = ['interface', 'outerFunc', 'callbackFunc'].includes(item.key)
          item.hidden = !_options.includes(item.key)
          return item
        })
      })
    } else {
      this.setState({
        expand: !this.state.expand,
        formlist: this.state.formlist.map(item => {
          item.hidden = !_options.includes(item.key)
          return item
        })
      })
    }
  }
  UNSAFE_componentWillMount () {
    let _opentype = this.props.formlist.filter(form => form.key === 'OpenType')[0].initVal
    let _intertype = this.props.formlist.filter(form => form.key === 'intertype')[0].initVal
    let _options = null
    if (_opentype === 'newpage') {
      _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position']
    } else {
      if (_intertype === 'outer') {
      _options = ['label', 'position', 'OpenType', 'intertype', 'innerFunc', 'interface', 'outerFunc', 'callbackFunc', 'Ot', 'icon', 'class']
      } else {
        _options = ['label', 'position', 'OpenType', 'innerFunc', 'Ot', 'icon', 'class']
      }
    }
    this.setState({
      openType: _opentype,
      interType: _intertype,
      expand: _intertype === 'outer' ? true : false,
      formlist: this.props.formlist.map(item => {
        if (item.key === 'class') {
          item.options = btnClasses
        } else if (item.key === 'icon') {
          item.options = btnIcons
        }
        if (_intertype === 'inner') {
          item.readonly = ['interface', 'outerFunc', 'callbackFunc'].includes(item.key)
        }
        item.hidden = !_options.includes(item.key)
        return item
      })
    })
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 7 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 17 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form commontable-action-form" id="winter">
        <Row gutter={24}>{this.getFields()}</Row>
        {this.state.openType !== 'newpage' && <Row>
          <Col span={24} style={{ textAlign: 'right' }}>
            <span className="superconfig" onClick={this.toggle}>
              高级设置 <Icon type={this.state.expand ? 'up' : 'down'} />
            </span>
          </Col>
        </Row>}
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/templates/comtableconfig/actionform/index.scss
New file
@@ -0,0 +1,7 @@
.ant-advanced-search-form.commontable-action-form {
  min-height: 190px;
  .superconfig {
    color: #1890ff;
    cursor: pointer;
  }
}
src/templates/comtableconfig/columnform/index.jsx
src/templates/comtableconfig/columnform/index.scss
src/templates/comtableconfig/dragelement/card.jsx
New file
@@ -0,0 +1,89 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Icon, Button, Select, DatePicker, Input } from 'antd'
import moment from 'moment'
import ItemTypes from './itemtypes'
import './index.scss'
const Card = ({ id, type, card, moveCard, findCard, editCard, copyCard, hasDrop }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: ItemTypes[type], id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: ItemTypes[type],
    canDrop: () => true,
    drop: (item) => {
      if (!item.hasOwnProperty('originalIndex')) {
        hasDrop(card)
      }
    },
    hover({ id: draggedId }) {
      if (!draggedId) return
      if (draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    },
  })
  const opacity = isDragging ? 0 : 1
  const edit = () => {
    editCard(id)
  }
  const copy = () => {
    copyCard(id)
  }
  return (
    <div className="page-card" style={type === 'columns' ? { flex: card.Width, opacity: opacity} : { opacity: opacity}}>
      <div ref={node => drag(drop(node))}>
        {type === 'search' && <div className="ant-row ant-form-item">
          <div className="ant-col ant-form-item-label">
            <label title={card.label}>{card.label}</label>
          </div>
          <div className="ant-col ant-form-item-control-wrapper">
            {card.type === 'text' &&
              <Input style={{marginTop: '4px'}} defaultValue={card.initval} />
            }
            {(card.type === 'select' || card.type === 'link') &&
              <Select defaultValue={card.initval}></Select>
            }
            {card.type === 'date' &&
              <DatePicker defaultValue={card.initval ? moment(card.initval, 'YYYY-MM-DD') : null} />
            }
            {card.type === 'datetime' &&
              <DatePicker showTime defaultValue={card.initval ? moment(card.initval, 'YYYY-MM-DD HH:mm:ss') : null} />
            }
            <div className="input-mask"></div>
          </div>
        </div>}
        {type === 'action' &&
          <Button
            className={'mk-btn mk-' + card.class}
            icon={card.icon}
            key={card.uuid}
          >{card.label}{card.position === 'grid' && <Icon type="table" />}</Button>
        }
        {type === 'columns' &&
          <span className="ant-table-header-column">
            <div className="ant-table-column-sorters" title={card.label} style={{textAlign: card.Align}}>
              <span className="ant-table-column-title">{card.label}</span>
              {card.IsSort === 'true' && <span className="ant-table-column-sorter">
                <Icon type="caret-up" />
                <Icon type="caret-down" />
              </span>}
            </div>
          </span>
        }
      </div>
      <Icon className="edit" type="edit" onClick={edit} />
      {type === 'action' && <Icon className="edit copy" type="copy" onClick={copy} />}
    </div>
  )
}
export default Card
src/templates/comtableconfig/dragelement/index.jsx
src/templates/comtableconfig/dragelement/index.scss
src/templates/comtableconfig/dragelement/itemtypes.js
src/templates/comtableconfig/dragelement/source.jsx
src/templates/comtableconfig/editable/index.jsx
src/templates/comtableconfig/editable/index.scss
src/templates/comtableconfig/editcard/index.jsx
New file
@@ -0,0 +1,99 @@
import React, {Component} from 'react'
import { Row, Col, Icon, Radio } from 'antd'
import './index.scss'
class EditCardCell extends Component {
  constructor(props) {
    super(props)
    this.state = {
      card: props.card,
      type: props.type
    }
  }
  changeSelect = () => {
    const { card } = this.state
    this.setState({
      card: {...card, selected: !card.selected}
    })
  }
  changeType = (e) => {
    const { card } = this.state
    this.setState({
      card: {...card, type: e.target.value}
    })
  }
  render() {
    const { card, type } = this.state
    let _type = card.type
    if (type === 'columns') {
      if (_type !== 'picture') {
        _type = 'text'
      }
    } else if (type === 'search') {
      if (_type === 'number') {
        _type = 'text'
      } else if (_type === 'datetime') {
        _type = 'date'
      }
    }
    return (
      <div className={'ant-card ant-card-bordered ' + (card.selected ? 'selected' : '')} >
        <div className="base" onClick={this.changeSelect}>
          <Icon type="check" />
          <p title={card.field}>字段名: <span>{card.field}</span></p>
          <p title={card.label}>提示文字: <span>{card.label}</span></p>
        </div>
        {type === 'search' && <Radio.Group onChange={this.changeType} value={_type} disabled={!card.selected}>
          <Radio value="text">text</Radio>
          <Radio value="select">select</Radio>
          <Radio value="date">date</Radio>
        </Radio.Group>}
        {type === 'columns' && <Radio.Group onChange={this.changeType} value={_type} disabled={!card.selected}>
          <Radio value="text">text</Radio>
          <Radio value="picture">picture</Radio>
        </Radio.Group>}
      </div>
    )
  }
}
class EditCard extends Component {
  constructor(props) {
    super(props)
    this.state = {
      dataSource: props.data,
      type: props.type
    }
  }
  getSelectedCard = () => {
    let box = []
    this.state.dataSource.forEach((item, index) => {
      box.push(this.refs['cellCard' + index].state.card)
    })
    return box
  }
  render() {
    const { dataSource, type } = this.state
    return (
      <div className="common-modal-edit-card">
        <Row>
          {dataSource.map((item, index) => (
            <Col key={index} span={8}>
              <EditCardCell ref={'cellCard' + index} type={type} card={item} />
            </Col>
          ))}
        </Row>
      </div>
    )
  }
}
export default EditCard
src/templates/comtableconfig/editcard/index.scss
New file
@@ -0,0 +1,43 @@
.common-modal-edit-card {
  margin-left: -10px;
  margin-right: -10px;
  .ant-col {
    padding: 10px;
    .ant-card {
      padding: 10px;
      p {
        margin-bottom: 5px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
      label {
        margin-right: 15px;
        span.ant-radio + * {
          padding-right: 0px;
          padding-left: 4px;
        }
      }
      .anticon {
        position: absolute;
        top: 10px;
        right: 10px;
        opacity: 0.4;
      }
      .base {
        cursor: pointer;
      }
    }
    .ant-card.selected {
      border-color: #1890ff;
      box-shadow: 0px 0px 4px #1890ff;
      .anticon {
        opacity: 1;
        color: #1890ff;
      }
      p {
        color: #1890ff;
      }
    }
  }
}
src/templates/comtableconfig/index.jsx
New file
@@ -0,0 +1,1448 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Spin, Select, List, Icon, Empty } from 'antd'
import DragElement from './dragelement'
import SourceElement from './dragelement/source'
import Api from '@/api'
import SearchForm from './searchform'
import ActionForm from './actionform'
import ColumnForm from './columnform'
import SettingForm from './settingform'
import EditCard from './editcard'
import MenuForm from './menuform'
import zhCN from '@/locales/zh-CN/comtable.js'
import enUS from '@/locales/en-US/comtable.js'
import Utils from '@/utils/utils.js'
import Source from './source'
import './index.scss'
const { Panel } = Collapse
const { Option } = Select
const { confirm } = Modal
const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
class ComTableConfig extends Component {
  static propTpyes = {
    type: PropTypes.string,
    menu: PropTypes.any,
    handleConfig: PropTypes.func,
    handleSubConfig: PropTypes.func,
    supMenuList: PropTypes.array
  }
  state = {
    operaType: '', // 操作类型,新建或编辑
    dict: CommonDict, // 字典
    config: null, // 页面配置
    visible: false, // 搜索条件、按钮、显示列,模态框显示控制
    tableVisible: false, // 数据表字段模态框
    addType: '', // 添加类型-搜索条件或显示列
    tableColumns: [], // 表格显示列
    fields: null, // 搜索条件及显示列,可选字段
    menuformlist: null, // 基本信息表单字段
    formlist: null, // 搜索条件、按钮、显示列表单字段
    formtemp: '', // 表单类型,显示列、按钮、搜索条件
    card: null, // 编辑元素
    searchloading: false, // 搜索条件加载中
    actionloading: false, // 按钮加载中
    columnsloading: false, // 显示列加载中
    menuloading: false, // 菜单保存中
    loading: false, // 加载中,页面spin
    settingVisible: false, // 全局配置模态框
    closeVisible: false, // 关闭模态框
    tables: [], // 可用表名
    selectedTables: [], // 已选表名
    originMenu: null // 原始菜单
  }
  /**
   * @description 数据预处理
   * 1、设置页面配置信息,新建或无配置信息时(切换模板后无配置信息),使用模板默认配置
   * 2、设置操作类型、原始菜单信息(每次保存后重置)、已使用表及基本信息表单
   */
  UNSAFE_componentWillMount () {
    const { menu } = this.props
    let _LongParam = menu.LongParam
    let _config = ''
    if (this.props.type === 'add' || !_LongParam) {
      _config = JSON.parse(JSON.stringify((Source.baseConfig)))
    } else {
      let _setting = Source.baseConfig.setting
      if (_LongParam.setting) {
        _setting = {..._setting, ..._LongParam.setting}
      }
      _LongParam.setting = _setting
      _config = _LongParam
    }
    this.setState({
      config: _config,
      operaType: this.props.type,
      originMenu: JSON.parse(JSON.stringify({...menu})),
      selectedTables: _config.tables || [],
      menuformlist: [
        {
          type: 'select',
          key: 'parentId',
          label: this.state.dict['header.menu.supMenu'],
          initVal: menu.ParentID,
          required: true,
          readonly: false,
          options: this.props.supMenuList
        },
        {
          type: 'text',
          key: 'menuName',
          label: this.state.dict['header.menu.menuName'],
          initVal: menu.MenuName,
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'menuNo',
          label: this.state.dict['header.menu.menuNo'],
          initVal: menu.MenuNo,
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'opentype',
          label: this.state.dict['header.menu.openType'],
          initVal: menu.PageParam.OpenType,
          required: true,
          options: [{
            MenuID: 'newtab',
            text: this.state.dict['header.form.tab']
          }, {
            MenuID: 'newpage',
            text: this.state.dict['header.form.newpage']
          }]
        }
      ]
    })
  }
  /**
   * @description 加载完成后
   * 1、获取系统可使用表
   * 2、根据配置信息中已使用表获取相关字段信息
   */
  componentDidMount () {
    let _text = "select TbName ,Remark from sDataDictionary where IsKey!='' and Deleted =0"
    _text = Utils.formatOptions(_text)
    Api.getSystemConfig({func: 'sPC_Get_SelectedList', LText: _text, obj_name: 'data', arr_field: 'TbName,Remark'}).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)
        })
      })
    })
    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)
                if (_decimal > 4) {
                  _decimal = 4
                }
                _type = 'number'
              } else if (/^decimal/.test(_type)) {
                _decimal = _type.split(',')[1]
                _decimal = parseInt(_decimal)
                if (_decimal > 4) {
                  _decimal = 4
                }
                _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
      })
    })
  }
  handleList = (listObj) => {
    let config = this.state.config
    if (this.state.operaType === 'add') {
      let key = Object.keys(listObj)[0]
      let newlength = listObj[key].length
      if (newlength > config[key].length) {
        listObj[key] = listObj[key].filter(item => !item.origin)
      }
      if (newlength > listObj[key].length) {
        this.setState({
          [key + 'loading']: true,
          config: {...config, ...listObj}
        }, () => {
          // 刷新对应的配置信息
          this.setState({
            [key + 'loading']: false
          })
        })
      } else {
        this.setState({config: {...config, ...listObj}})
      }
    } else {
      this.setState({config: {...config, ...listObj}})
    }
  }
  handleSearch = (card) => {
    this.setState({
      visible: true,
      formtemp: 'search',
      card: card,
      formlist: [
        {
          type: 'text',
          key: 'label',
          label: this.state.dict['header.form.name'],
          initVal: card.label,
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'field',
          label: this.state.dict['header.form.field'],
          initVal: card.field,
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'type',
          label: this.state.dict['header.form.type'],
          initVal: card.type,
          required: true,
          options: [{
            MenuID: 'text',
            text: this.state.dict['header.form.text']
          }, {
            MenuID: 'select',
            text: this.state.dict['header.form.select']
          }, {
            MenuID: 'link',
            text: this.state.dict['header.form.link']
          }, {
            MenuID: 'date',
            text: this.state.dict['header.form.dateday']
          }, {
            MenuID: 'datetime',
            text: this.state.dict['header.form.datetime']
          }]
        },
        {
          type: 'text',
          key: 'initval',
          label: this.state.dict['header.form.initval'],
          initVal: card.initval,
          required: false
        },
        {
          type: 'radio',
          key: 'resourceType',
          label: this.state.dict['header.form.resourceType'],
          initVal: card.resourceType || '0',
          required: true,
          options: [{
            MenuID: '0',
            text: this.state.dict['header.form.custom']
          }, {
            MenuID: '1',
            text: this.state.dict['header.form.datasource']
          }]
        },
        {
          type: 'radio',
          key: 'setAll',
          label: this.state.dict['header.form.setAll'],
          initVal: card.setAll || 'false',
          options: [{
            MenuID: 'true',
            text: this.state.dict['header.form.true']
          }, {
            MenuID: 'false',
            text: this.state.dict['header.form.false']
          }]
        },
        {
          type: 'textarea',
          key: 'dataSource',
          label: this.state.dict['header.form.datasource'],
          initVal: card.dataSource || '',
          required: true,
          readonly: false
        },
        {
          type: 'options',
          key: 'options',
          label: '',
          initVal: card.options || [],
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'linkField',
          label: this.state.dict['header.form.linkField'],
          initVal: card.linkField || '',
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'valueField',
          label: this.state.dict['header.form.valueField'],
          initVal: card.valueField || '',
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'valueText',
          label: this.state.dict['header.form.valueText'],
          initVal: card.valueText || '',
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'orderBy',
          label: this.state.dict['header.form.orderBy'],
          initVal: card.orderBy || '',
          required: false,
          readonly: false
        },
        {
          type: 'select',
          key: 'orderType',
          label: this.state.dict['header.form.orderType'],
          initVal: card.orderType || 'asc',
          options: [{
            MenuID: 'asc',
            text: this.state.dict['header.form.asc']
          }, {
            MenuID: 'desc',
            text: this.state.dict['header.form.desc']
          }]
        },
        {
          type: 'select',
          key: 'match',
          label: this.state.dict['header.form.match'],
          initVal: card.match || 'like',
          required: true,
          options: [{
            MenuID: 'like',
            text: 'like'
          }, {
            MenuID: 'equal',
            text: 'equal'
          }, {
            MenuID: 'greater',
            text: '>'
          }, {
            MenuID: 'less',
            text: '<'
          }, {
            MenuID: 'greaterequal',
            text: '>='
          }]
        },
        {
          type: 'select',
          key: 'display',
          label: this.state.dict['header.form.display'],
          initVal: card.display || 'dropdown',
          required: true,
          options: [{
            MenuID: 'dropdown',
            text: this.state.dict['header.form.dropdown']
          }, {
            MenuID: 'button',
            text: this.state.dict['header.form.button']
          }]
        }
      ]
    })
  }
  handleAction = (card) => {
    this.setState({
      visible: true,
      formtemp: 'action',
      card: card,
      formlist: [
        {
          type: 'text',
          key: 'label',
          label: this.state.dict['header.form.name'],
          initVal: card.label,
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'OpenType',
          label: this.state.dict['header.form.openType'],
          initVal: card.OpenType,
          required: true,
          options: [{
            MenuID: 'pop',
            text: this.state.dict['header.form.pop']
          }, {
            MenuID: 'prompt',
            text: this.state.dict['header.form.prompt']
          }, {
            MenuID: 'exec',
            text: this.state.dict['header.form.exec']
          }, {
            MenuID: 'tab',
            text: this.state.dict['header.form.tab']
          }, {
            MenuID: 'blank',
            text: this.state.dict['header.form.blank']
          }, {
            MenuID: 'newpage',
            text: this.state.dict['header.form.newpage']
          }]
        },
        {
          type: 'select',
          key: 'position',
          label: this.state.dict['header.form.position'],
          initVal: card.position || 'toolbar',
          required: true,
          options: [{
            MenuID: 'toolbar',
            text: this.state.dict['header.form.toolbar']
          }, {
            MenuID: 'grid',
            text: this.state.dict['header.form.grid']
          }]
        },
        {
          type: 'select',
          key: 'pageTemplate',
          label: this.state.dict['header.form.pageTemplate'],
          initVal: card.pageTemplate,
          required: true,
          options: []
        },
        {
          type: 'text',
          key: 'innerFunc',
          label: this.state.dict['header.form.innerFunc'],
          initVal: card.innerFunc,
          required: false,
          readonly: false
        },
        {
          type: 'select',
          key: 'Ot',
          label: this.state.dict['header.form.isRequired'],
          initVal: card.Ot,
          required: true,
          options: [{
            MenuID: 'notRequired',
            text: this.state.dict['header.form.notRequired']
          }, {
            MenuID: 'requiredSgl',
            text: this.state.dict['header.form.requiredSgl']
          }, {
            MenuID: 'required',
            text: this.state.dict['header.form.required']
          }, {
            MenuID: 'requiredOnce',
            text: this.state.dict['header.form.requiredOnce']
          }]
        },
        {
          type: 'select',
          key: 'icon',
          label: this.state.dict['header.form.icon'],
          initVal: card.icon,
          required: false,
          options: []
        },
        {
          type: 'select',
          key: 'class',
          label: this.state.dict['header.form.class'],
          initVal: card.class,
          required: false,
          options: []
        },
        {
          type: 'radio',
          key: 'intertype',
          label: this.state.dict['header.form.intertype'],
          initVal: card.intertype,
          required: true,
          options: [{
            MenuID: 'inner',
            text: this.state.dict['header.form.interface.inner']
          }, {
            MenuID: 'outer',
            text: this.state.dict['header.form.interface.outer']
          }]
        },
        {
          type: 'text',
          key: 'interface',
          label: this.state.dict['header.form.interface'],
          initVal: card.interface,
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'outerFunc',
          label: this.state.dict['header.form.outerFunc'],
          initVal: card.outerFunc,
          required: false,
          readonly: false
        },
        {
          type: 'text',
          key: 'callbackFunc',
          label: this.state.dict['header.form.callbackFunc'],
          initVal: card.callbackFunc,
          required: false,
          readonly: false
        }
      ]
    })
  }
  handleColumn = (card) => {
    this.setState({
      visible: true,
      formtemp: 'columns',
      card: card,
      formlist: [
        {
          type: 'text',
          key: 'label',
          label: this.state.dict['header.form.name'],
          initVal: card.label,
          required: true
        },
        {
          type: 'text',
          key: 'field',
          label: this.state.dict['header.form.field'],
          initVal: card.field,
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'type',
          label: this.state.dict['header.form.type'],
          initVal: card.type,
          required: true,
          options: [{
            MenuID: 'text',
            text: this.state.dict['header.form.text']
          }, {
            MenuID: 'picture',
            text: this.state.dict['header.form.picture']
          }]
        },
        {
          type: 'select',
          key: 'Align',
          label: this.state.dict['header.form.align'],
          initVal: card.Align,
          required: true,
          options: [{
            MenuID: 'left',
            text: this.state.dict['header.form.alignLeft']
          }, {
            MenuID: 'right',
            text: this.state.dict['header.form.alignRight']
          }, {
            MenuID: 'center',
            text: this.state.dict['header.form.alignCenter']
          }]
        },
        {
          type: 'radio',
          key: 'Hide',
          label: this.state.dict['header.form.Hide'],
          initVal: card.Hide,
          required: true,
          options: [{
            MenuID: 'true',
            text: this.state.dict['header.form.true']
          }, {
            MenuID: 'false',
            text: this.state.dict['header.form.false']
          }]
        },
        {
          type: 'select',
          key: 'IsSort',
          label: this.state.dict['header.form.IsSort'],
          initVal: card.IsSort,
          required: true,
          options: [{
            MenuID: 'true',
            text: this.state.dict['header.form.true']
          }, {
            MenuID: 'false',
            text: this.state.dict['header.form.false']
          }]
        },
        {
          type: 'number',
          key: 'Width',
          decimal: 0,
          label: this.state.dict['header.form.columnWidth'],
          initVal: card.Width,
          required: true
        }
      ]
    })
  }
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = this.state.config
      if (this.state.operaType === 'add') {
        _config[res.type] = _config[res.type].map(item => {
          if (item.uuid === res.values.uuid) {
            return res.values
          } else {
            return item
          }
        })
        _config[res.type] = _config[res.type].filter(item => !item.origin)
      } else {
        _config[res.type] = _config[res.type].map(item => {
          if (item.uuid === res.values.uuid) {
            return res.values
          } else {
            return item
          }
        })
      }
      this.setState({
        config: _config,
        [res.type + 'loading']: true,
        visible: false
      }, () => {
        this.setState({
          [res.type + 'loading']: false
        })
      })
    })
  }
  deleteElement = () => {
    let _config = this.state.config
    _config[this.state.formtemp] = _config[this.state.formtemp].filter(item => {
      if (item.uuid === this.state.card.uuid) {
        return false
      } else {
        return true
      }
    })
    this.setState({
      config: _config,
      [this.state.formtemp + 'loading']: true,
      visible: false
    }, () => {
      this.setState({
        [this.state.formtemp + 'loading']: false
      })
    })
  }
  changeTemplate = () => {
    this.props.handleConfig('template')
  }
  submitConfig = () => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    this.menuformRef.handleConfirm().then(res => {
      if (config.search[0] && config.search[0].origin) {
        notification.warning({
          top: 92,
          message: '请设置搜索条件',
          duration: 10
        })
        return
      }
      if (config.action[0] && config.action[0].origin) {
        notification.warning({
          top: 92,
          message: '请设置按钮',
          duration: 10
        })
        return
      }
      if (config.columns[0] && config.columns[0].origin) {
        notification.warning({
          top: 92,
          message: '请设置显示列',
          duration: 10
        })
        return
      }
      let _LongParam = ''
      let _config = {...config, tables: this.state.selectedTables}
      let _pageParam = {...menu.PageParam, OpenType: res.opentype}
      try {
        _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
      } catch (e) {
        notification.warning({
          top: 92,
          message: '编译错误',
          duration: 10
        })
        return
      }
      if (this.state.operaType === 'add') {
        let param = {
          func: 'sPC_TrdMenu_Add',
          ParentID: res.parentId,
          MenuID: menu.MenuID,
          MenuNo: res.menuNo,
          Template: menu.PageParam.Template || '',
          MenuName: res.menuName,
          PageParam: JSON.stringify(_pageParam),
          LongParam: _LongParam
        }
        this.setState({
          menuloading: true
        })
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            this.setState({
              menuloading: false,
              operaType: 'edit',
              originMenu: {
                ...originMenu,
                LongParam: _config,
                PageParam: _pageParam,
                MenuName: res.menuName,
                MenuNo: res.menuNo,
                ParentID: res.parentId
              }
            })
            notification.success({
              top: 92,
              message: '保存成功',
              duration: 10
            })
          } else {
            this.setState({
              menuloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 10
            })
          }
        })
      } else {
        let param = {
          func: 'sPC_TrdMenu_Upt',
          ParentID: res.parentId,
          MenuID: menu.MenuID,
          MenuNo: res.menuNo,
          Template: menu.PageParam.Template || '',
          MenuName: res.menuName,
          PageParam: JSON.stringify(_pageParam),
          LongParam: _LongParam
        }
        this.setState({
          menuloading: true
        })
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            notification.success({
              top: 92,
              message: '保存成功',
              duration: 10
            })
            if (this.state.closeVisible) {
              this.props.handleConfig('')
            } else {
              this.setState({
                menuloading: false,
                originMenu: {
                  ...originMenu,
                  LongParam: _config,
                  PageParam: _pageParam,
                  MenuName: res.menuName,
                  MenuNo: res.menuNo,
                  ParentID: res.parentId
                }
              })
            }
          } else {
            this.setState({
              menuloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 10
            })
          }
        })
      }
    }, () => {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.basemsg'],
        duration: 10
      })
    })
  }
  cancelConfig = () => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    let _this = this
    if (this.state.operaType === 'add') {
      confirm({
        content: '菜单尚未提交,确定放弃保存吗?',
        okText: this.state.dict['header.confirm'],
        cancelText: this.state.dict['header.cancel'],
        onOk() {
          _this.props.handleConfig('')
        },
        onCancel() {}
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, tables: this.state.selectedTables}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.menuName,
          MenuNo: res.menuNo,
          ParentID: res.parentId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
          this.setState({
            closeVisible: true
          })
        } else {
          this.props.handleConfig('')
        }
      }, () => {
        this.setState({
          closeVisible: true
        })
      })
    }
  }
  queryField = (type) => {
    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 (type === 'search') {
      config.search.forEach(item => {
        if (columns.has(item.field)) {
          columns.set(item.field, {...item, selected: true, type: item.type})
        }
      })
    } else if (type === 'columns') {
      config.columns.forEach(item => {
        if (columns.has(item.field)) {
          columns.set(item.field, {...item, selected: true, type: item.type})
        }
      })
    }
    this.setState({
      addType: type,
      tableVisible: true,
      fields: [...columns.values()]
    })
  }
  addFieldSubmit = () => {
    if (!this.state.fields || this.state.fields.length === 0) {
      this.setState({
        tableVisible: false,
        addType: ''
      })
    }
    const {addType, config} = this.state
    let cards = this.refs.searchcard.getSelectedCard()
    let columns = new Map()
    cards.forEach(card => {
      columns.set(card.field, card)
    })
    let items = []
    if (addType === 'search') {
      config.search.forEach(item => {
        if (columns.has(item.field)) {
          let cell = columns.get(item.field)
          if (cell.selected) {
            items.push(item)
          }
          columns.delete(item.field)
        } else if (!item.origin) {
          items.push(item)
        }
      })
      let _columns = [...columns.values()]
      let indexes = items.map(card => {return card.id})
      let id = Math.max(...indexes, 0)
      _columns.forEach(item => {
        if (item.selected) {
          let newcard = {
            id: id,
            uuid: Utils.getuuid(),
            label: item.label,
            field: item.field,
            initval: '',
            type: item.type,
            resourceType: '0',
            setAll: 'false',
            options: [],
            dataSource: '',
            linkField: '',
            valueField: '',
            valueText: '',
            orderBy: '',
            orderType: 'asc',
            display: 'dropdown'
          }
          items.push(newcard)
          id++
        }
      })
    } else {
      config.columns.forEach(item => {
        if (columns.has(item.field)) {
          let cell = columns.get(item.field)
          if (cell.selected) {
            items.push(item)
          }
          columns.delete(item.field)
        } else if (!item.origin) {
          items.push(item)
        }
      })
      let _columns = [...columns.values()]
      let indexes = items.map(card => {return card.id})
      let id = Math.max(...indexes, 0)
      _columns.forEach(item => {
        if (item.selected) {
          let newcard = {
            id: id,
            uuid: Utils.getuuid(),
            Align: 'left',
            label: item.label,
            field: item.field,
            Hide: 'false',
            IsSort: 'true',
            type: 'text',
            Width: 120
          }
          items.push(newcard)
          id++
        }
      })
    }
    this.setState({
      tableVisible: false,
      [addType + 'loading']: true,
      addType: '',
      config: {...config, [addType]: items}
    }, () => {
      this.setState({
        [addType + 'loading']: false
      })
    })
  }
  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) {
      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)
                if (_decimal > 4) {
                  _decimal = 4
                }
                _type = 'number'
              } else if (/^decimal/.test(_type)) {
                _decimal = _type.split(',')[1]
                _decimal = parseInt(_decimal)
                if (_decimal > 4) {
                  _decimal = 4
                }
                _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
          })
        }
      })
    }
  }
  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)
    })
  }
  changeSetting = () => {
    this.setState({
      settingVisible: true
    })
  }
  settingSave = () => {
    const {config} = this.state
    this.settingRef.handleConfirm().then(res => {
      this.setState({
        config: {...config, setting: res},
        settingVisible: false
      })
    })
  }
  setSubConfig = (btn) => {
    const { menu } = this.props
    const { config, originMenu } = this.state
    if (this.state.operaType === 'add') {
      notification.warning({
        top: 92,
        message: '菜单尚未保存,请保存菜单配置!',
        duration: 10
      })
    } else {
      this.menuformRef.handleConfirm().then(res => {
        let _config = {...config, tables: this.state.selectedTables}
        let _pageParam = {...menu.PageParam, OpenType: res.opentype}
        let _originMenu = {
          ...originMenu,
          LongParam: _config,
          PageParam: _pageParam,
          MenuName: res.menuName,
          MenuNo: res.menuNo,
          ParentID: res.parentId
        }
        if (!is(fromJS(originMenu), fromJS(_originMenu))) {
          notification.warning({
            top: 92,
            message: '菜单配置已修改,请保存!',
            duration: 10
          })
        } else {
          this.setState({
            loading: true
          })
          Api.getSystemConfig({
            func: 'sPC_Get_FrozenMenu',
            ParentID: btn.uuid,
            TYPE: 30
          }).then(res => {
            if (res.status) {
              let btnconfig = ''
              this.setState({
                loading: false
              })
              this.props.handleSubConfig(btn, originMenu, btnconfig)
            } else {
              this.setState({
                loading: false
              })
              notification.warning({
                top: 92,
                message: res.message,
                duration: 10
              })
            }
          })
        }
      }, () => {
        notification.warning({
          top: 92,
          message: '菜单基本信息已修改,请保存!',
          duration: 10
        })
      })
    }
  }
  render () {
    const configAction = this.state.config.action.filter(_action => !_action.origin && (_action.OpenType === 'pop'))
    return (
      <div className="common-table-board">
        <DndProvider backend={HTML5Backend}>
          {/* 工具栏 */}
          <div className="tools">
            <Collapse accordion defaultActiveKey="0" bordered={false}>
              <Panel header="基本信息" key="0" id="common-basedata">
                <MenuForm
                  dict={this.state.dict}
                  formlist={this.state.menuformlist}
                  wrappedComponentRef={(inst) => this.menuformRef = inst}
                />
                <div className="ant-col ant-form-item-label">
                  <label title="添加表名">添加表名</label>
                </div>
                <Select
                  showSearch
                  className="tables"
                  style={{ width: '100%' }}
                  optionFilterProp="children"
                  value={'请选择表名'}
                  onChange={this.onTableChange}
                  showArrow={false}
                  getPopupContainer={() => document.getElementById('common-basedata')}
                  filterOption={(input, option) => {
                    return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
                      option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                  }}
                >
                  {this.state.tables.map((table, index) => (
                    <Option key={index} 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>}
                />}
              </Panel>
              <Panel header="搜索" key="1">
                <div className="search-element">
                  {Source.searchItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                <Button type="primary" block onClick={() => this.queryField('search')}>添加搜索条件</Button>
              </Panel>
              <Panel header="按钮" key="2">
                <div className="search-element">
                  {Source.actionItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                {configAction.length > 0 ?
                  <div>
                    <p style={{marginTop: '20px', marginBottom: '10px', color: '#1890ff'}}>可配置按钮:</p>
                    {configAction.map((item, index) => {
                      return (
                        <div key={index}>
                          <Button
                            icon={item.icon}
                            style={{marginBottom: '10px'}}
                            className={'mk-btn mk-' + item.class}
                            onClick={() => this.setSubConfig(item)}
                          >{item.label}</Button>
                        </div>
                      )
                    })}
                  </div> : null
                }
              </Panel>
              <Panel header="显示列" key="3">
                <div className="search-element">
                  {Source.columnItems.map((item, index) => {
                    return (<SourceElement key={index} content={item}/>)
                  })}
                </div>
                <Button type="primary" block onClick={() => this.queryField('columns')}>添加显示列</Button>
              </Panel>
            </Collapse>
          </div>
          <div className="setting">
            <Card title="页面配置" bordered={false} extra={
              <div>
                <Button type="primary" onClick={this.changeTemplate}>{this.state.dict['header.menu.template.change']}</Button>
                <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['header.save']}</Button>
                <Button onClick={this.cancelConfig}>{this.state.dict['header.return']}</Button>
              </div>
            } style={{ width: '100%' }}>
              <Icon type="setting" onClick={this.changeSetting} />
              <div className="search-list">
                {this.state.config.search && !this.state.searchloading &&
                <DragElement
                  list={this.state.config.search}
                  type="search"
                  placeholder={this.state.dict['header.form.search.placeholder']}
                  handleList={this.handleList}
                  handleMenu={this.handleSearch}
                />}
              </div>
              <div className="action-list">
                {this.state.config.action && !this.state.actionloading &&
                <DragElement
                  list={this.state.config.action}
                  type="action"
                  placeholder={this.state.dict['header.form.action.placeholder']}
                  handleList={this.handleList}
                  handleMenu={this.handleAction}
                />}
              </div>
              <div className="column-list">
                {this.state.config.columns && !this.state.columnsloading &&
                <DragElement
                  list={this.state.config.columns}
                  type="columns"
                  placeholder={this.state.dict['header.form.column.placeholder']}
                  handleList={this.handleList}
                  handleMenu={this.handleColumn}
                />}
              </div>
            </Card>
          </div>
        </DndProvider>
        {/* 编辑搜索条件、按钮、显示列 */}
        <Modal
          title={this.state.dict['header.edit']}
          visible={this.state.visible}
          width={700}
          onCancel={() => { this.setState({ visible: false }) }}
          footer={[
            <Button key="delete" type="danger" onClick={this.deleteElement}>{this.state.dict['header.delete']}</Button>,
            <Button key="cancel" onClick={() => { this.setState({ visible: false }) }}>{this.state.dict['header.cancel']}</Button>,
            <Button key="confirm" type="primary" onClick={this.handleSubmit}>{this.state.dict['header.confirm']}</Button>
          ]}
          destroyOnClose
        >
          {this.state.formtemp === 'search' && <SearchForm
            dict={this.state.dict}
            formlist={this.state.formlist}
            card={this.state.card}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />}
          {this.state.formtemp === 'action' && <ActionForm
            dict={this.state.dict}
            card={this.state.card}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />}
          {this.state.formtemp === 'columns' && <ColumnForm
            dict={this.state.dict}
            card={this.state.card}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />}
        </Modal>
        {/* 根据字段名添加显示列及搜索条件 */}
        <Modal
          wrapClassName="common-table-fields-modal"
          title={this.state.dict['header.edit']}
          visible={this.state.tableVisible}
          width={'65vw'}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          onOk={this.addFieldSubmit}
          onCancel={() => { // 取消添加
            this.setState({
              tableVisible: false,
              addType: ''
            })
          }}
          destroyOnClose
        >
          {this.state.addType === 'search' && this.state.fields.length > 0 &&
            <EditCard data={this.state.fields} ref="searchcard" type="search" />
          }
          {this.state.addType === 'columns' && this.state.fields.length > 0 &&
            <EditCard data={this.state.fields} ref="searchcard" type="columns" />
          }
          {(!this.state.fields || this.state.fields.length === 0) &&
            <Empty />
          }
        </Modal>
        {/* 设置全局配置及列表数据源 */}
        <Modal
          title={this.state.dict['header.edit']}
          visible={this.state.settingVisible}
          width={700}
          onOk={this.settingSave}
          onCancel={() => { // 取消修改
            this.setState({
              settingVisible: false
            })
          }}
          destroyOnClose
        >
          <SettingForm
            data={this.state.config.setting}
            dict={this.state.dict}
            wrappedComponentRef={(inst) => this.settingRef = inst}
          />
        </Modal>
        <Modal
          bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}}
          closable={false}
          visible={this.state.closeVisible}
          onCancel={() => { this.setState({closeVisible: false}) }}
          footer={[
            <Button key="save" className="mk-btn mk-green" onClick={this.submitConfig}>{this.state.dict['header.save']}</Button>,
            <Button key="confirm" className="mk-btn mk-yellow" onClick={() => {this.props.handleConfig('')}}>{this.state.dict['header.notsave']}</Button>,
            <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['header.cancel']}</Button>
          ]}
          destroyOnClose
        >
          菜单配置已修改,是否保存配置信息?
        </Modal>
        {this.state.loading && <Spin size="large" />}
      </div>
    )
  }
}
export default ComTableConfig
src/templates/comtableconfig/index.scss
New file
@@ -0,0 +1,368 @@
.common-table-board {
  position: fixed;
  z-index: 1070;
  padding-top: 48px;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background: rgba(0, 0, 0, 0.35);
  display: flex;
  .tools {
    flex: 1;
    background: #ffffff;
    border-right: 1px solid #d9d9d9;
    height: 100%;
    overflow-y: auto;
    padding-bottom: 30px;
    .ant-collapse-item {
      position: relative;
      border: 0;
    }
    .ant-input-search {
      margin-top: 10px;
    }
    .ant-collapse-item.ant-collapse-item-active {
      border-bottom: 1px solid #d9d9d9;
    }
    .ant-collapse-header {
      padding: 11px 16px 10px 40px;
      border-bottom: 1px solid #d9d9d9;
    }
    .ant-collapse-content-box {
      .ant-form-item {
        margin-bottom: 10px;
        .ant-form-item-label {
          text-align: left;
          height: 25px;
          line-height: 25px;
        }
      }
    }
    .search-element {
      padding-top: 10px;
      li {
        padding: 0px 16px 10px;
        div {
          cursor: move;
        }
      }
    }
    .tables {
      .ant-select-selection-selected-value {
        opacity: 0.4!important;
      }
    }
    .ant-list {
      margin-top: 20px;
      .ant-list-item {
        display: -webkit-box;
        padding-right: 20px;
        position: relative;
        padding-left: 5px;
        overflow: hidden;
        text-overflow: ellipsis;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        min-height: 55px;
        width: 100%;
        .anticon {
          position: absolute;
          top: 0px;
          right: 0px;
          padding: 3px 3px 10px 10px;
          cursor: pointer;
        }
        .bottom-mask {
          position: absolute;
          width: 100%;
          height: 8px;
          bottom: 0;
          left: 0;
          background: #ffffff;
          border-radius: 8px;
        }
      }
    }
  }
  .tools::-webkit-scrollbar {
    width: 7px;
  }
  .tools::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
  }
  .tools::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
  }
  .tools:hover::-webkit-scrollbar-thumb {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .tools:hover::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border: 1px solid rgba(0, 0, 0, 0.07);
  }
  .setting {
    position: relative;
    width: calc(100vw - 235px);
    height: 100%;
    overflow-y: hidden;
    background: #ffffff;
    .ant-card-head {
      min-height: 44px;
    }
    .ant-card-head-title {
      padding: 5px 0;
      color: #1890ff;
    }
    .ant-card-extra {
      padding: 5px 0;
      button {
        margin-left: 20px;
      }
    }
    .ant-card-body {
      position: relative;
      padding: 0;
      .search-list {
        padding: 1px 24px 20px;
        min-height: 87px;
        border-bottom: 1px solid #d9d9d9;
        > .ant-row {
          min-height: 65px;
        }
        .ant-row .ant-col-6 {
          padding: 0 12px!important;
        }
        .ant-row.ant-form-item .ant-col {
          padding: 0;
        }
        .page-card {
          position: relative;
          background: #ffffff;
          border-radius: 2px;
          padding-top: 15px;
          .ant-form-item {
            cursor: move;
            display: flex;
            margin-bottom: 0px;
            .ant-form-item-label {
              width: 100px;
              height: 40px;
              label {
                width: 100%;
                cursor: move;
                overflow: hidden;
                display: inline-block;
                text-overflow: ellipsis;
                white-space: nowrap;
              }
            }
            .ant-form-item-control-wrapper {
              flex: 1 1;
              .ant-select {
                width: 100%;
                margin-top: 4px;
              }
              .ant-calendar-picker {
                margin-top: 4px;
              }
              .input-mask {
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                opacity: 0;
              }
            }
          }
          .edit {
            position: absolute;
            left: 0;
            top: 5px;
            cursor: pointer;
            display: none;
          }
        }
        .page-card:hover {
          .edit {
            display: inline-block;
          }
        }
        .ant-calendar-picker {
          min-width: 100px!important;
        }
      }
      .action-list {
        padding: 0px 20px 15px;
        min-height: 82px;
        > .ant-row {
          min-height: 67px;
        }
        .page-card {
          display: inline-block;
          margin: 0px 0px 0px 0px;
          padding: 15px 10px 0 0;
          position: relative;
          div {
            cursor: move;
          }
          .edit {
            position: absolute;
            left: 0;
            top: 0px;
            cursor: pointer;
            display: none;
          }
          .edit.copy {
            left: 20px;
          }
          button {
            cursor: move;
            .anticon-table {
              font-size: 10px;
              position: absolute;
              right: 1px;
              bottom: 0px;
            }
          }
        }
        .page-card:hover {
          .edit {
            display: inline-block;
          }
        }
      }
      .element-add {
        font-size: 20px;
        padding: 10px 20px;
        cursor: pointer;
      }
      .column-list {
        padding: 0px 20px;
        > .ant-row {
          background: #fafafa;
          border-radius: 4px;
          min-height: 47px;
          border: 1px solid #e8e8e8;
          .column-box {
            display: flex;
          }
          .column-box:not(:first-child) {
            border-top: 1px solid #e8e8e8;
          }
          .page-card {
            position: relative;
            padding: 0px;
            min-height: 45px;
            > div {
              padding: 12px 8px;
              cursor: move;
              height: 100%;
            }
            .ant-table-column-sorter {
              position: relative;
              display: inline-block;
              width: 24px;
              font-size: 12px;
              color: #bfbfbf;
              .anticon-caret-up {
                position: relative;
                left: 10px;
                top: -3px;
              }
              .anticon-caret-down {
                position: relative;
                left: -2px;
                top: 3px;
              }
            }
            .edit {
              position: absolute;
              left: 0;
              top: 0px;
              cursor: pointer;
              display: none;
            }
            .ant-checkbox-inner {
              margin-top: 14px;
              margin-left: calc(50% - 8px);
            }
          }
          .page-card:hover {
            .edit {
              display: inline-block;
            }
          }
          .page-card:not(:last-child) {
            border-right: 1px solid #e8e8e8;
          }
        }
      }
      > .anticon-setting {
        position: absolute;
        font-size: 16px;
        right: 10px;
        top: 10px;
      }
    }
  }
  .setting:hover {
    overflow-y: auto;
  }
  .setting::-webkit-scrollbar {
    width: 7px;
  }
  .setting::-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);
  }
  .setting::-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);
  }
  .ant-spin {
    position: absolute;
    margin-left: calc(50vw - 22px);
    margin-top: 30vh;
  }
}
.common-table-fields-modal {
  .ant-modal {
    top: 50px;
    padding-bottom: 5px;
    .ant-modal-body {
      max-height: calc(100vh - 190px);
      overflow-y: auto;
      .ant-empty {
        margin: 15vh 8px;
      }
    }
    .ant-modal-body::-webkit-scrollbar {
      width: 7px;
    }
    .ant-modal-body::-webkit-scrollbar-thumb {
      border-radius: 5px;
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
      background: rgba(0, 0, 0, 0.13);
    }
    .ant-modal-body::-webkit-scrollbar-track {
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
      border-radius: 3px;
      border: 1px solid rgba(0, 0, 0, 0.07);
      background: rgba(0, 0, 0, 0);
    }
  }
}
src/templates/comtableconfig/menuform/index.jsx
src/templates/comtableconfig/menuform/index.scss
src/templates/comtableconfig/searchform/index.jsx
New file
@@ -0,0 +1,273 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, Icon, Radio, notification } from 'antd'
import moment from 'moment'
import EditTable from '../editable'
import './index.scss'
const { TextArea } = Input
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    formlist: PropTypes.any,
    card: PropTypes.object
  }
  state = {
    openType: null,
    resourceType: null,
    formlist: null
  }
  openTypeChange = (key, value) => {
    if (key === 'type') {
      let _options = ['label', 'field', 'initval', 'type', 'match']
      if (value === 'select' && this.state.resourceType === '0') {
        _options = [..._options, ...['resourceType', 'setAll', 'options', 'display']]
      } else if (value === 'select' && this.state.resourceType === '1') {
        _options = [..._options, ...['resourceType', 'setAll', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display']]
      } else if (value === 'link' && this.state.resourceType === '0') {
        _options = [..._options, ...['resourceType', 'setAll', 'options', 'linkField', 'display']]
      } else if (value === 'link' && this.state.resourceType === '1') {
        _options = [..._options, ...['resourceType', 'setAll', 'dataSource', 'linkField', 'valueField', 'valueText', 'orderBy', 'orderType', 'display']]
      }
      this.setState({
        openType: value,
        formlist: this.state.formlist.map(form => {
          form.hidden = !_options.includes(form.key)
          return form
        })
      })
    }
  }
  onChange = (e, key) => {
    let value = e.target.value
    if (key === 'resourceType') {
      let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'setAll']
      if (this.state.openType === 'select' && value === '0') {
        _options = [..._options, ...['options', 'display']]
      } else if (this.state.openType === 'select' && value === '1') {
        _options = [..._options, ...['dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display']]
      } else if (this.state.openType === 'link' && value === '0') {
        _options = [..._options, ...['options', 'linkField', 'display']]
      } else if (this.state.openType === 'link' && value === '1') {
        _options = [..._options, ...['dataSource', 'linkField', 'valueField', 'valueText', 'orderBy', 'orderType', 'display']]
      }
      this.setState({
        resourceType: value,
        formlist: this.state.formlist.map(form => {
          form.hidden = !_options.includes(form.key)
          return form
        })
      })
    }
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.hidden) return
      if (item.type === 'text') { // 文本搜索
        let placeholder = ''
        if (item.key === 'initval' && this.state.openType === 'date') {
          placeholder = '例:' + moment().format('YYYY-MM-DD')
        } else if (item.key === 'initval' && this.state.openType === 'datetime') {
          placeholder = '例:' + moment().format('YYYY-MM-DD HH:mm:ss')
        }
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<Input placeholder={placeholder} autoComplete="off" disabled={item.readonly} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'select') { // 下拉搜索
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal || '',
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(value) => {this.openTypeChange(item.key, value)}}
                  getPopupContainer={() => document.getElementById('commontable-search-form-box')}
                >
                  {item.options.map(option =>
                    <Select.Option id={option.MenuID} title={option.text} key={option.MenuID} value={option.MenuID}>
                      {item.key === 'icon' && <Icon type={option.text} />} {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'radio') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={item.label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                  }
                ]
              })(
                <Radio.Group onChange={(e) => {this.onChange(e, item.key)}}>
                  {
                    item.options.map(option => {
                      return (
                        <Radio key={option.MenuID} value={option.MenuID}>{option.text}</Radio>
                      )
                    })
                  }
                </Radio.Group>,
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'textarea') {
        fields.push(
          <Col span={20} offset={4} key={index}>
            <Form.Item className="text-area">
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                  }
                ]
              })(<TextArea rows={4} />)}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'options') {
        fields.push(
          <Col span={20} offset={4} key={index}>
            <EditTable data={item.initVal} type={this.state.openType} ref="editTable"/>
          </Col>
        )
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          let isvalid = true
          values.id = this.props.card.id
          values.uuid = this.props.card.uuid
          // 下拉菜单或关联菜单
          if ((values.type === 'select' || values.type === 'link') && values.resourceType === '0') {
            values.options = this.refs.editTable.state.dataSource
            values.dataSource = ''
            let emptys = []
            if (values.type === 'select') {
              emptys = values.options.filter(op => !(op.Value && op.Text))
            } else {
              emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID))
            }
            if (emptys.length > 0) {
              isvalid = false
            }
          } else if ((values.type === 'select' || values.type === 'link') && values.resourceType === '1') {
            values.options = []
          }
          if (isvalid) {
            resolve({
              type: 'search',
              values
            })
          } else {
            notification.warning({
              top: 92,
              message: this.props.dict['header.form.selectItem.error'],
              duration: 10
            })
          }
        } else {
          reject(err)
        }
      })
    })
  }
  resetForm = (formlist) => {
    if (!formlist) return
    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
    let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal
    let _options = ['label', 'field', 'initval', 'type', 'match']
    if (type === 'select' && resourceType === '0') {
      _options = [..._options, ...['resourceType', 'setAll', 'options', 'display']]
    } else if (type === 'select' && resourceType === '1') {
      _options = [..._options, ...['resourceType', 'setAll', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display']]
    } else if (type === 'link' && resourceType === '0') {
      _options = [..._options, ...['resourceType', 'setAll', 'options', 'linkField', 'display']]
    } else if (type === 'link' && resourceType === '1') {
      _options = [..._options, ...['resourceType', 'setAll', 'dataSource', 'linkField', 'valueField', 'valueText', 'orderBy', 'orderType', 'display']]
    }
    this.setState({
      openType: type,
      resourceType: resourceType,
      formlist: formlist.map(form => {
        form.hidden = !_options.includes(form.key)
        return form
      })
    })
  }
  UNSAFE_componentWillMount () {
    this.resetForm(this.props.formlist)
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form commontable-search-form" id="commontable-search-form-box">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/templates/comtableconfig/searchform/index.scss
src/templates/comtableconfig/settingform/index.jsx
src/templates/comtableconfig/settingform/index.scss
src/templates/comtableconfig/source.jsx
New file
@@ -0,0 +1,274 @@
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/comtable.js'
import enUS from '@/locales/en-US/comtable.js'
const CommonDict = (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS
class CommonTableBaseData {
  baseConfig = {
    type: 'system',
    setting: {
      actionfixed: false,
      columnfixed: false,
      dataresource: ''
    },
    tables: [],
    search: [
      {
        origin: true,
        id: 0,
        uuid: Utils.getuuid(),
        label: 'text',
        field: '',
        initval: '',
        type: 'text',
        resourceType: '0',
        setAll: 'false',
        options: [],
        dataSource: '',
        linkField: '',
        valueField: '',
        valueText: '',
        orderBy: '',
        orderType: 'asc',
        match: 'like',
        display: 'dropdown'
      }, {
        origin: true,
        id: 1,
        uuid: Utils.getuuid(),
        label: 'select',
        field: '',
        initval: '',
        type: 'select',
        resourceType: '0',
        setAll: 'false',
        options: [],
        dataSource: '',
        linkField: '',
        valueField: '',
        valueText: '',
        orderBy: '',
        orderType: 'asc',
        match: 'equal',
        display: 'dropdown'
      }, {
        origin: true,
        id: 2,
        uuid: Utils.getuuid(),
        label: 'date',
        field: '',
        initval: '',
        type: 'date',
        resourceType: '0',
        setAll: 'false',
        options: [],
        dataSource: '',
        linkField: '',
        valueField: '',
        valueText: '',
        orderBy: '',
        orderType: 'asc',
        match: 'greater',
        display: 'dropdown'
      }
    ],
    action: [
      {
        origin: true,
        id: 0,
        uuid: Utils.getuuid(),
        label: 'add',
        intertype: 'inner',
        innerFunc: '',
        interface: '',
        outerFunc: '',
        callbackFunc: '',
        Ot: 'notRequired',
        position: 'toolbar',
        OpenType: 'pop',
        pageTemplate: '',
        icon: 'plus',
        class: 'green'
      }, {
        origin: true,
        id: 1,
        uuid: Utils.getuuid(),
        label: 'update',
        intertype: 'inner',
        innerFunc: '',
        interface: '',
        outerFunc: '',
        callbackFunc: '',
        Ot: 'requiredSgl',
        position: 'grid',
        OpenType: 'pop',
        pageTemplate: '',
        icon: 'form',
        class: 'purple'
      }, {
        origin: true,
        id: 2,
        uuid: Utils.getuuid(),
        label: 'delete',
        intertype: 'inner',
        innerFunc: '',
        interface: '',
        outerFunc: '',
        callbackFunc: '',
        Ot: 'required',
        position: 'toolbar',
        OpenType: 'prompt',
        pageTemplate: '',
        icon: 'delete',
        class: 'red'
      }, {
        origin: true,
        id: 3,
        uuid: Utils.getuuid(),
        label: 'freeze',
        intertype: 'inner',
        innerFunc: '',
        interface: '',
        outerFunc: '',
        callbackFunc: '',
        Ot: 'requiredOnce',
        position: 'toolbar',
        OpenType: 'exec',
        pageTemplate: '',
        icon: '',
        class: 'default'
      }
    ],
    columns: [
      {
        origin: true,
        id: 0,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName1',
        field: '',
        Hide: 'false',
        IsSort: 'true',
        type: 'text',
        Width: 120
      }, {
        origin: true,
        id: 1,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName2',
        field: '',
        Hide: 'false',
        IsSort: 'true',
        type: 'text',
        Width: 120
      }, {
        origin: true,
        id: 2,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName3',
        field: '',
        Hide: 'false',
        IsSort: 'true',
        type: 'text',
        Width: 120
      }, {
        origin: true,
        id: 3,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName4',
        field: '',
        Hide: 'false',
        IsSort: 'true',
        type: 'text',
        Width: 120
      }
    ]
  }
  searchItems = [
    {
      type: 'search',
      label: '文本框',
      subType: 'text',
      url: ''
    },
    {
      type: 'search',
      label: '下拉框',
      subType: 'select',
      url: ''
    },
    {
      type: 'search',
      label: '时间框(天)',
      subType: 'date',
      url: ''
    },
    {
      type: 'search',
      label: '时间框(秒)',
      subType: 'datetime',
      url: ''
    }
  ]
  actionItems = [
    {
      type: 'action',
      label: CommonDict['header.form.pop'],
      subType: 'pop',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.prompt'],
      subType: 'prompt',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.exec'],
      subType: 'exec',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.tab'],
      subType: 'tab',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.newpage'],
      subType: 'newpage',
      url: ''
    },
    {
      type: 'action',
      label: CommonDict['header.form.blank'],
      subType: 'blank',
      url: ''
    }
  ]
  columnItems = [
    {
      type: 'columns',
      label: CommonDict['header.form.text'],
      subType: 'text',
      url: ''
    },
    {
      type: 'columns',
      label: CommonDict['header.form.picture'],
      subType: 'picture',
      url: ''
    }
  ]
}
export default new CommonTableBaseData()
src/templates/modalconfig/actionform/index.jsx
src/templates/modalconfig/actionform/index.scss
src/templates/modalconfig/columnform/index.jsx
copy from src/components/sidemenu/comtableconfig/columnform/index.jsx copy to src/templates/modalconfig/columnform/index.jsx
src/templates/modalconfig/columnform/index.scss
copy from src/components/sidemenu/comtableconfig/columnform/index.scss copy to src/templates/modalconfig/columnform/index.scss
src/templates/modalconfig/dragelement/card.jsx
src/templates/modalconfig/dragelement/index.jsx
copy from src/components/sidemenu/comtableconfig/dragelement/index.jsx copy to src/templates/modalconfig/dragelement/index.jsx
src/templates/modalconfig/dragelement/index.scss
copy from src/components/sidemenu/comtableconfig/dragelement/index.scss copy to src/templates/modalconfig/dragelement/index.scss
src/templates/modalconfig/dragelement/itemtypes.js
copy from src/components/sidemenu/comtableconfig/dragelement/itemtypes.js copy to src/templates/modalconfig/dragelement/itemtypes.js
src/templates/modalconfig/dragelement/source.jsx
copy from src/components/sidemenu/comtableconfig/dragelement/source.jsx copy to src/templates/modalconfig/dragelement/source.jsx
src/templates/modalconfig/editable/index.jsx
copy from src/components/sidemenu/comtableconfig/editable/index.jsx copy to src/templates/modalconfig/editable/index.jsx
src/templates/modalconfig/editable/index.scss
copy from src/components/sidemenu/comtableconfig/editable/index.scss copy to src/templates/modalconfig/editable/index.scss
src/templates/modalconfig/editcard/index.jsx
src/templates/modalconfig/editcard/index.scss
src/templates/modalconfig/index.jsx
src/templates/modalconfig/index.scss
src/templates/modalconfig/menuform/index.jsx
copy from src/components/sidemenu/comtableconfig/menuform/index.jsx copy to src/templates/modalconfig/menuform/index.jsx
src/templates/modalconfig/menuform/index.scss
copy from src/components/sidemenu/comtableconfig/menuform/index.scss copy to src/templates/modalconfig/menuform/index.scss
src/templates/modalconfig/searchform/index.jsx
src/templates/modalconfig/searchform/index.scss
copy from src/components/sidemenu/comtableconfig/searchform/index.scss copy to src/templates/modalconfig/searchform/index.scss
src/templates/modalconfig/settingform/index.jsx
copy from src/components/sidemenu/comtableconfig/settingform/index.jsx copy to src/templates/modalconfig/settingform/index.jsx
src/templates/modalconfig/settingform/index.scss
copy from src/components/sidemenu/comtableconfig/settingform/index.scss copy to src/templates/modalconfig/settingform/index.scss
src/templates/modalconfig/source.jsx
src/utils/asyncLoadComponent.jsx
New file
@@ -0,0 +1,32 @@
import React, {Component} from 'react'
import { Spin } from 'antd'
/**
 * @description 异步加载模块
 * @param {*} importComponent
 */
export default function asyncComponent(importComponent) {
  return class extends Component {
    constructor(props) {
      super(props)
      this.state = {
        component: null
      }
    }
    async componentDidMount() {
      const {default: component} = await importComponent()
      this.setState({component})
    }
    render() {
      const C = this.state.component
      return C ?
        <C {...this.props} /> :
        <Spin style={{position: 'fixed', left: 'calc(50vw - 22px)', top: 'calc(50vh - 70px)'}} size="large" />
    }
  }
}