king
2019-11-11 e1281cc04b886678a5d0561af556a312ef2b9394
2019-11-11
14个文件已修改
14个文件已添加
3247 ■■■■ 已修改文件
public/options.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/action.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/editmenu/index.jsx 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/dragelement/card.jsx 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/dragelement/index.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/dragelement/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/dragelement/itemtypes.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/editable/index.jsx 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/editable/index.scss 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/index.jsx 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/index.scss 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/menuform/index.jsx 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/comtableconfig/menuform/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editsecmenu/index.jsx 423 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editsecmenu/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/index.jsx 719 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/editthdmenu/index.scss 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/index.jsx 588 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/index.scss 90 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/menuform/index.jsx 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/header.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/header.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/setupProxy.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/options.js
@@ -1,3 +1,5 @@
window.GLOB = {
  service: 'mkwms'
  service: 'mkwms',
  appkey: '20191106103859640976D6E924E464D029CF0',
  mainSystemApi: ''
}
src/api/index.js
@@ -66,7 +66,7 @@
  }
  /**
   * @description 登录系统
   * @description 登录系统, 获取用户信息
   */
  getusermsg (username, password) {
    return axios({
@@ -75,19 +75,6 @@
        DBT: 'proc',
        DBS: 'webapi_login',
        DBP: JSON.stringify({ 'UserName': username, 'Password': password })
      }
    })
  }
  /**
   * @description 登出系统
   */
  logoutsystem () {
    return axios({
      url: '/local/dostar',
      data: {
        func: 'logout',
        userid: sessionStorage.getItem('UserID')
      }
    })
  }
@@ -108,36 +95,20 @@
  }
  /**
   * @description 获取主菜单数据
   * @description 获取系统配置,增加appkey
   */
  getMainMenuData () {
  getSystemConfig (param) {
    param.userid = sessionStorage.getItem('UserID')
    param.lang = localStorage.getItem('lang') || ''
    param.SessionUid = sessionStorage.getItem('SessionUid') || ''
    param.LoginUID = sessionStorage.getItem('LoginUID') || ''
    param.appkey = window.GLOB.appkey || ''
    if (window.GLOB.mainSystemApi) {
      param.rduri = window.GLOB.mainSystemApi
    }
    return axios({
      url: '/webapi/dostar',
      data: {
        func: 'sPC_Get_MainMenu',
        userid: sessionStorage.getItem('UserID'),
        lang: localStorage.getItem('lang') || '',
        SessionUid: sessionStorage.getItem('SessionUid') || '',
        LoginUID: sessionStorage.getItem('LoginUID') || ''
      }
    })
  }
  /**
   * @description 获取子菜单数据
   * @param {String} menuId 主菜单Id
   */
  getSubMenuData (menuId) {
    return axios({
      url: '/webapi/dostar',
      data: {
        func: 'sPC_Get_FunMenu',
        userid: sessionStorage.getItem('UserID'),
        lang: localStorage.getItem('lang') || '',
        SessionUid: sessionStorage.getItem('SessionUid') || '',
        LoginUID: sessionStorage.getItem('LoginUID') || '',
        ParentID: menuId
      }
      data: param
    })
  }
@@ -234,6 +205,19 @@
      data: param
    })
  }
  // /**
  //  * @description 登出系统
  //  */
  // logoutsystem () {
  //   return axios({
  //     url: '/local/dostar',
  //     data: {
  //       func: 'logout',
  //       userid: sessionStorage.getItem('UserID')
  //     }
  //   })
  // }
}
export default new Api()
src/assets/css/action.scss
@@ -1,4 +1,4 @@
#root {
body {
  .mk-btn:hover {
    opacity: 0.8;
  }
src/assets/css/main.scss
@@ -124,3 +124,22 @@
.ant-modal.ant-modal-confirm {
  top: 38vh;
}
// 自定义模态框按钮设置
.edit-modal-footer{
  padding: 10px 16px;
  text-align: right;
  background: transparent;
  border-top: 1px solid #e8e8e8;
  border-radius: 0 0 4px 4px;
  margin-left: -24px;
  margin-right: -24px;
  margin-bottom: -20px;
  .ant-btn {
    margin-right: 7px;
  }
}
.ant-popover {
  z-index: 1090!important;
}
src/components/header/editmenu/index.jsx
@@ -61,7 +61,7 @@
      this.setState({
        confirmLoading: true
      })
      Api.submitInterface(param).then(res => {
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          this.setState({
            confirmLoading: false,
@@ -100,7 +100,7 @@
      this.setState({
        confirmLoading: true
      })
      Api.submitInterface(param).then(res => {
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          this.setState({
            confirmLoading: false,
@@ -144,7 +144,7 @@
          func: 'sPC_MainMenu_Del',
          MenuID: _this.state.editMenu.MenuID
        }
        return Api.submitInterface(param).then(res => {
        return Api.getSystemConfig(param).then(res => {
          if (res.status) {
            _this.setState({
              editMvisible: false,
@@ -178,7 +178,7 @@
      })
      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
        return new Promise((resolve) => {
          Api.submitInterface({
          Api.getSystemConfig({
            func: 'sPC_MainMenu_ReDel',
            MenuID: item
          }).then(res => {
@@ -246,7 +246,7 @@
        okText: this.state.dict['header.confirm'],
        cancelText: this.state.dict['header.cancel'],
        onOk() {
          return Api.submitInterface(param).then(res => {
          return Api.getSystemConfig(param).then(res => {
            if (res.status) {
              _this.props.reload()
            } else {
@@ -264,7 +264,7 @@
      this.setState({
        thawMvisible: true
      })
      Api.submitInterface({
      Api.getSystemConfig({
        func: 'sPC_Get_FrozenMenu',
        ParentID: '0',
        TYPE: 10
@@ -347,8 +347,8 @@
        {/* 编辑菜单模态框 */}
        <Modal
          title={this.state.dict['header.menu.editTitle']}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          // okText={this.state.dict['header.confirm']}
          // cancelText={this.state.dict['header.cancel']}
          visible={this.state.editMvisible}
          footer={null}
          onCancel={this.editMemuCancel}
src/components/header/index.jsx
@@ -105,15 +105,16 @@
      okText: this.state.dict['header.confirm'],
      cancelText: this.state.dict['header.cancel'],
      onOk() {
        return Api.logoutsystem().then(res => {
          if (res.status) {
            sessionStorage.removeItem('UserID')
            _this.props.resetState()
            _this.props.history.replace('/login')
          } else {
            message.warning(res.message)
          }
        })
        // return Api.logoutsystem().then(res => {
        //   if (res.status) {
        //     sessionStorage.removeItem('UserID')
        //     _this.props.resetState()
        //     _this.props.history.replace('/login')
        //   } else {
        //     message.warning(res.message)
        //   }
        // })
      },
      onCancel() {}
    })
@@ -134,7 +135,7 @@
  async loadmenu () {
    // 获取主菜单
    let result = await Api.getMainMenuData()
    let result = await Api.getSystemConfig({func: 'sPC_Get_MainMenu'})
    if (result.status) {
      let _avatar = Utils.getrealurl(result.HeadIcon) // 头像
      if (_avatar) {
src/components/header/index.scss
@@ -116,16 +116,3 @@
.edit-switch {
  margin-left: 10px;
}
.edit-modal-footer{
  padding: 10px 16px;
  text-align: right;
  background: transparent;
  border-top: 1px solid #e8e8e8;
  border-radius: 0 0 4px 4px;
  margin-left: -24px;
  margin-right: -24px;
  margin-bottom: -20px;
  .ant-btn {
    margin-right: 7px;
  }
}
src/components/sidemenu/comtableconfig/dragelement/card.jsx
New file
@@ -0,0 +1,58 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Icon, Button } from 'antd'
import ItemTypes from './itemtypes'
import './index.scss'
const Card = ({ id, type, card, moveCard, findCard, editCard }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: ItemTypes.CARD, id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: ItemTypes.CARD,
    canDrop: () => false,
    hover({ id: draggedId }) {
      if (draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    },
  })
  const opacity = isDragging ? 0 : 1
  const edit = () => {
    editCard(id)
  }
  return (
    <div className="page-card" style={{ 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">
            <div className="ant-form-item-control">
              <span className="ant-form-item-children">
                <input placeholder="" autoComplete="off" type="text" readOnly={true}  className="ant-input" />
              </span>
            </div>
          </div>
        </div>}
        {type === 'action' &&
          <Button
            className={'mk-btn mk-' + card.class}
            icon={card.icon}
            key={card.uuid}
          >{card.label}</Button>
        }
      </div>
      <Icon className="edit" type="edit" onClick={edit} />
    </div>
  )
}
export default Card
src/components/sidemenu/comtableconfig/dragelement/index.jsx
New file
@@ -0,0 +1,64 @@
import React, { useState } from 'react'
import { useDrop } from 'react-dnd'
import update from 'immutability-helper'
import { Col } from 'antd'
import Card from './card'
import ItemTypes from './itemtypes'
import './index.scss'
const Container = ({list, type, handleList, handleMenu }) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    setCards(_cards)
    handleList(_cards)
  }
  const findCard = id => {
    const card = cards.filter(c => `${c.id}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
  const editCard = id => {
    const { card } = findCard(id)
    handleMenu(card)
  }
  const [, drop] = useDrop({ accept: ItemTypes.CARD })
  return (
    <div ref={drop} className="ant-row">
        {type === 'search' && cards.map(card => (
          <Col key={card.uuid} span={6}>
            <Card
              key={card.uuid}
              id={`${card.id}`}
              type={type}
              card={card}
              moveCard={moveCard}
              editCard={editCard}
              findCard={findCard}
            />
          </Col>
        ))}
        {/* {type === 'search' && <Col key="add" span={6}>
          <Icon className="element-add" type="plus"/>
        </Col>} */}
        {type === 'action' && cards.map(card => (
          <Card
            key={card.uuid}
            id={`${card.id}`}
            type={type}
            card={card}
            moveCard={moveCard}
            editCard={editCard}
            findCard={findCard}
          />
        ))}
    </div>
  )
}
export default Container
src/components/sidemenu/comtableconfig/dragelement/index.scss
src/components/sidemenu/comtableconfig/dragelement/itemtypes.js
New file
@@ -0,0 +1,3 @@
export default {
  CARD: 'card',
}
src/components/sidemenu/comtableconfig/editable/index.jsx
New file
@@ -0,0 +1,203 @@
import React, {Component} from 'react'
import { Table, Input, Button, Popconfirm, Form } from 'antd'
import Utils from '@/utils/utils.js'
import './index.scss'
const EditableContext = React.createContext()
const EditableRow = ({ form, index, ...props }) => (
  <EditableContext.Provider value={form}>
    <tr {...props} />
  </EditableContext.Provider>
);
const EditableFormRow = Form.create()(EditableRow)
class EditableCell extends Component {
  state = {
    editing: false,
  }
  toggleEdit = () => {
    const editing = !this.state.editing
    this.setState({ editing }, () => {
      if (editing) {
        this.input.focus()
      }
    })
  }
  save = e => {
    const { record, handleSave } = this.props
    this.form.validateFields((error, values) => {
      if (error && error[e.currentTarget.id]) {
        return
      }
      this.toggleEdit()
      handleSave({ ...record, ...values })
    })
  }
  renderCell = form => {
    this.form = form
    const { children, dataIndex, record, title } = this.props
    const { editing } = this.state
    return editing ? (
      <Form.Item style={{ margin: 0 }}>
        {form.getFieldDecorator(dataIndex, {
          rules: [
            {
              required: true,
              message: `${title} is required.`,
            },
          ],
          initialValue: record[dataIndex]
        })(<Input ref={node => (this.input = node)} onPressEnter={this.save} onBlur={this.save} />)}
      </Form.Item>
    ) : (
      <div
        className="editable-cell-value-wrap"
        onClick={this.toggleEdit}
      >
        {children}
      </div>
    )
  }
  render() {
    const {
      editable,
      dataIndex,
      title,
      record,
      index,
      handleSave,
      children,
      ...restProps
    } = this.props
    return (
      <td {...restProps}>
        {editable ? (
          <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
        ) : (
          children
        )}
      </td>
    )
  }
}
class EditTable extends Component {
  constructor(props) {
    super(props)
    this.columns = [
      {
        title: 'ID',
        dataIndex: 'ID',
        width: '35%',
        editable: true
      },
      {
        title: 'Value',
        dataIndex: 'value',
        width: '35%',
        editable: true
      },
      {
        title: 'operation',
        dataIndex: 'operation',
        render: (text, record) =>
          this.state.dataSource.length >= 1 ? (
            <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}>
              <span style={{color: '#1890ff', cursor: 'pointer'}}>Delete</span>
            </Popconfirm>
          ) : null,
      }
    ]
    this.state = {
      dataSource: [],
      count: 0
    }
  }
  handleDelete = key => {
    const dataSource = [...this.state.dataSource]
    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
  }
  handleAdd = () => {
    const { count, dataSource } = this.state
    const newData = {
      key: Utils.getuuid(),
      ID: `${count}`,
      value: `${count}`
    }
    this.setState({
      dataSource: [...dataSource, newData],
      count: count + 1
    })
  }
  handleSave = row => {
    const newData = [...this.state.dataSource]
    const index = newData.findIndex(item => row.key === item.key)
    const item = newData[index]
    newData.splice(index, 1, {
      ...item,
      ...row
    })
    this.setState({ dataSource: newData })
  }
  UNSAFE_componentWillMount () {
    if (this.props.data) {
      this.setState({
        dataSource: this.props.data,
        count: this.props.data.length
      })
    }
  }
  render() {
    const { dataSource } = this.state
    const components = {
      body: {
        row: EditableFormRow,
        cell: EditableCell
      }
    }
    const columns = this.columns.map(col => {
      if (!col.editable) {
        return col
      }
      return {
        ...col,
        onCell: record => ({
          record,
          editable: col.editable,
          dataIndex: col.dataIndex,
          title: col.title,
          handleSave: this.handleSave,
        })
      }
    })
    return (
      <div className="common-modal-edit-table">
        <Button onClick={this.handleAdd} type="primary" className="add-row">
          添加
        </Button>
        <Table
          components={components}
          rowClassName={() => 'editable-row'}
          bordered
          dataSource={dataSource}
          columns={columns}
          pagination={false}
        />
      </div>
    )
  }
}
export default EditTable
src/components/sidemenu/comtableconfig/editable/index.scss
New file
@@ -0,0 +1,40 @@
.common-modal-edit-table {
  .add-row {
    position: absolute;
    z-index: 1;
    right: 12px;
    top: -40px;
  }
  .ant-table-thead > tr > th {
    padding: 10px 16px;
  }
  .ant-table-tbody > tr > td {
    padding: 0px 16px;
  }
  .editable-cell-value-wrap {
    cursor: pointer;
    height: 40px;
    width: 100px;
    display: table-cell;
    vertical-align: middle;
    word-wrap: break-word;
    word-break: break-word;
    .ant-input {
      height: 30px;
      padding: 0 11px;
    }
  }
  .ant-form-item-control-wrapper {
    width: 100%;
  }
  .ant-table-placeholder {
    padding: 5px 16px;
    .ant-empty-normal {
      margin: 0;
    }
  }
  // .editable-cell-value-wrap:hover {
  //   padding: 0px;
  // }
}
src/components/sidemenu/comtableconfig/index.jsx
New file
@@ -0,0 +1,271 @@
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 } from 'antd'
import DragElement from './dragelement'
import MenuForm from './menuform'
import zhCN from '@/locales/zh-CN/header.js'
import enUS from '@/locales/en-US/header.js'
import Utils from '@/utils/utils.js'
import './index.scss'
class ComTableConfig extends Component {
  static propTpyes = {
    menuConfig: PropTypes.any
  }
  state = {
    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
    config: null,
    visible: false,
    formlist: null,
    baseconfig: {
      type: 'system',
      search: [{
        id: 0,
        uuid: Utils.getuuid(),
        label: 'fieldName1',
        initval: '',
        type: 'text'
      }, {
        id: 1,
        uuid: Utils.getuuid(),
        label: 'fieldName2',
        initval: '',
        type: 'select',
        resourceType: 0,
        options: [],
        dataSource: ''
      }, {
        id: 2,
        uuid: Utils.getuuid(),
        label: 'fieldName3',
        initval: '',
        type: 'dateday'
      }],
      action: [{
        id: 0,
        uuid: Utils.getuuid(),
        label: 'add',
        Ot: 'notRequired',
        OpenType: 'pop',
        icon: 'plus',
        class: 'green'
      }, {
        id: 1,
        uuid: Utils.getuuid(),
        label: 'update',
        Ot: 'requiredSgl',
        OpenType: 'pop',
        icon: 'form',
        class: 'purple'
      }, {
        id: 2,
        uuid: Utils.getuuid(),
        label: 'delete',
        Ot: 'required',
        OpenType: 'prompt',
        icon: 'delete',
        class: 'red'
      }, {
        id: 3,
        uuid: Utils.getuuid(),
        label: 'freeze',
        Ot: 'requiredOnce',
        OpenType: 'exec',
        icon: '',
        class: ''
      }],
      columns: [{
        id: 0,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName1',
        Hide: false,
        IsSort: true,
        Width: 120
      }, {
        id: 1,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName2',
        Hide: false,
        IsSort: true,
        Width: 120
      }, {
        id: 2,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName3',
        Hide: false,
        IsSort: true,
        Width: 120
      }, {
        id: 3,
        uuid: Utils.getuuid(),
        Align: 'left',
        label: 'fieldName4',
        Hide: false,
        IsSort: true,
        Width: 120
      }]
    }
  }
  handlesearchList = (searchlist) => {
    let config = this.state.config
    config.search = searchlist
    this.setState({config})
  }
  handleSearch = (card) => {
    this.setState({
      visible: true,
      formlist: [
        {
          type: 'text',
          key: 'label',
          label: this.state.dict['header.form.name'],
          initVal: card.label,
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'type',
          label: this.state.dict['header.form.type'],
          initVal: card.type,
          required: true,
          card: card,
          options: [{
            MenuID: 'text',
            text: this.state.dict['header.form.text']
          }, {
            MenuID: 'select',
            text: this.state.dict['header.form.select']
          }, {
            MenuID: 'dateday',
            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: '',
          required: false
        }
      ]
    })
  }
  handleactionList = (actionlist) => {
    let config = this.state.config
    config.action = actionlist
    this.setState({config})
  }
  handleAction = (card) => {
    console.log(card)
  }
  handleSubmit = () => {
    this.formRef.handleConfirm().then(values => {
      console.log(values)
    })
  }
  handleCancel = () => {
    this.setState({
      visible: false
    })
    this.resetFrom()
  }
  resetFrom = () => {
    setTimeout(() => {
      this.setState({
        formlist: null
      })
    }, 300)
  }
  UNSAFE_componentWillMount () {
    if (!this.props.menuConfig) {
      this.setState({
        config: JSON.parse(JSON.stringify((this.state.baseconfig)))
      })
    } else {
      this.setState({
        config: this.props.menuConfig
      })
    }
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.menulist), fromJS(nextProps.menulist))) {
    }
  }
  render () {
    return (
      <div className="common-table-board">
        <div className="tools"></div>
        <div className="setting">
          <Card title="页面配置" bordered={false} extra={
            <div>
              <Button type="primary">{this.state.dict['header.submit']}</Button>
              <Button>{this.state.dict['header.cancel']}</Button>
            </div>
          } style={{ width: '100%' }}>
            <div className="search-list">
              {this.state.config.search && <DndProvider backend={HTML5Backend}>
                <DragElement
                  list={this.state.config.search}
                  type="search"
                  handleList={this.handlesearchList}
                  handleMenu={this.handleSearch}
                />
              </DndProvider>}
            </div>
            <div className="action-list">
              {this.state.config.action && <DndProvider backend={HTML5Backend}>
                <DragElement
                  list={this.state.config.action}
                  type="action"
                  handleList={this.handleactionList}
                  handleMenu={this.handleAction}
                />
              </DndProvider>}
            </div>
          </Card>
        </div>
        <Modal
          title={this.state.dict['header.edit']}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.visible}
          onOk={this.handleSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.handleCancel}
          className="commontable-edit-modal"
        >
          {this.state.formlist && <MenuForm
            dict={this.state.dict}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />}
        </Modal>
      </div>
    )
  }
}
export default ComTableConfig
src/components/sidemenu/comtableconfig/index.scss
New file
@@ -0,0 +1,137 @@
.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;
  }
  .setting {
    position: relative;
    width: calc(100vw - 235px);
    height: 100%;
    overflow-y: auto;
    background: #ffffff;
    .ant-card-head-title {
      padding: 10px 0;
      color: #1890ff;
    }
    .ant-card-extra {
      padding: 10px 0;
      button {
        margin-left: 20px;
      }
    }
    .ant-card-body {
      padding: 0;
      .search-list {
        padding: 1px 24px 20px;
        min-height: 50px;
        border-bottom: 1px solid #d9d9d9;
        .ant-row .ant-col-6 {
          padding: 0 12px!important;
        }
        .ant-row.ant-form-item .ant-col {
          padding: 0;
        }
        .page-card {
          cursor: move;
          position: relative;
          background: #ffffff;
          border-radius: 2px;
          padding-top: 15px;
          .ant-form-item {
            display: flex;
            margin-bottom: 10px;
            .ant-form-item-label {
              width: 100px;
              label {
                cursor: move;
              }
            }
            .ant-form-item-control-wrapper {
              flex: 1 1;
              input {
                cursor: move;
              }
              input:hover {
                border-color: #d9d9d9;
              }
              input:active {
                border-color: #d9d9d9;
              }
              input:focus {
                border-color: #d9d9d9;
                box-shadow: none;
              }
            }
          }
          // .close {
          //   position: absolute;
          //   right: 0;
          //   top: 0;
          //   cursor: pointer;
          //   :hover {
          //     color: #ffffff;
          //   }
          // }
          .edit {
            position: absolute;
            left: 0;
            top: 5px;
            cursor: pointer;
            display: none;
          }
        }
        .page-card:hover {
          .edit {
            display: inline-block;
          }
        }
      }
      .action-list {
        padding: 0px 20px 5px;
        min-height: 50px;
        .page-card {
          display: inline-block;
          margin: 0px 15px 20px 0px;
          padding-top: 15px;
          cursor: move;
          position: relative;
          .edit {
            position: absolute;
            left: 0;
            top: 0px;
            cursor: pointer;
            display: none;
          }
          button {
            cursor: move;
          }
        }
        .page-card:hover {
          .edit {
            display: inline-block;
          }
        }
      }
      .element-add {
        font-size: 20px;
        padding: 10px 20px;
        cursor: pointer;
      }
    }
  }
}
.commontable-edit-modal {
  width: 650px!important;
}
src/components/sidemenu/comtableconfig/menuform/index.jsx
New file
@@ -0,0 +1,191 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, Icon, Radio } 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.array
  }
  state = {
    card: null,
    inputType: 'text',
    selectType: 0,
    options: null
  }
  openTypeChange = (key, value) => {
    if (key === 'type') {
      this.setState({
        inputType: value,
        selectType: 0
      })
    }
  }
  onChange = e => {
    this.setState({
      selectType: e.target.value
    })
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.props.formlist.forEach((item, index) => {
      if (item.type === 'text') { // 文本搜索
        let placeholder = ''
        if (item.key === 'initval' && this.state.inputType === 'dateday') {
          placeholder = '例:' + moment().format('YYYY-MM-DD')
        } else if (item.key === 'initval' && this.state.inputType === 'datetime') {
          placeholder = '例:' + moment().format('YYYY-MM-DD HH:mm:ss')
        }
        fields.push(
          <Col span={24} 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={24} 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('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>
        )
        if (item.key === 'type' && this.state.inputType === 'select') {
          fields.push(
            <Col span={24} key={'radio' + index}>
              <Form.Item label={'选项'}>
                <Radio.Group onChange={this.onChange} value={this.state.selectType}>
                  <Radio value={0}>自定义</Radio>
                  <Radio value={1}>数据源</Radio>
                </Radio.Group>
              </Form.Item>
            </Col>
          )
          if (this.state.selectType === 0) {
            fields.push(
              <Col span={18} offset={6} key={'table' + index}>
                <EditTable data={this.state.card.options} ref="editTable"/>
              </Col>
            )
          } else {
            fields.push(
              <Col span={18} offset={6} key={'table' + index}>
                <Form.Item className="text-area">
                  {getFieldDecorator('datasource', {
                    initialValue: '',
                    rules: [
                      {
                        required: true,
                        message: this.props.dict['form.required.input'] + 'datasource !'
                      }
                    ]
                  })(<TextArea rows={4} />)}
                </Form.Item>
              </Col>
            )
          }
        }
      }
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          if (this.state.inputType === 'select') {
            values.resourceType = this.state.selectType
            if (this.state.selectType === 0) {
              values.options = this.refs.editTable.state.dataSource
            } else {
              values.options = []
            }
          }
          values.id = this.state.card.id
          values.uuid = this.state.card.uuid
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  UNSAFE_componentWillMount () {
    let _item = this.props.formlist.filter(cell => cell.key === 'type')[0]
    if (_item.initVal === 'select') {
      this.setState({
        inputType: 'select',
        card: _item.card,
        selectType: _item.card.resourceType
      })
    } else {
      this.setState({
        inputType: _item.card.type,
        card: _item.card
      })
    }
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 18 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form commontable-form" id="form-box">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/components/sidemenu/comtableconfig/menuform/index.scss
New file
@@ -0,0 +1,12 @@
.ant-advanced-search-form.commontable-form {
  .ant-col-offset-6 {
    padding-left: 6px!important;
    padding-bottom: 20px;
  }
  .text-area {
    margin-bottom: 0px;
    .ant-form-item-control-wrapper {
      width: 100%;
    }
  }
}
src/components/sidemenu/editsecmenu/index.jsx
New file
@@ -0,0 +1,423 @@
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 { notification, Modal, Button, Spin, Icon } from 'antd'
// import { notification, Modal, Button, Icon } from 'antd'
import TransferForm from '@/components/transferform'
import Utils from '@/utils/utils.js'
import DragElement from '../dragelement'
import MenuForm from '../menuform'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/header.js'
import enUS from '@/locales/en-US/header.js'
import './index.scss'
const { confirm } = Modal
let previewList = null
class EditMenu extends Component {
  static propTpyes = {
    menulist: PropTypes.any, // 二级菜单列表
    supMenuList: PropTypes.array, // 一级菜单列表
    supMenu: PropTypes.object, // 二级菜单所对应的一级菜单
    reload: PropTypes.func, // 刷新二级菜单数据
    exitEdit: PropTypes.func // 退出编辑
  }
  state = {
    show: true,
    type: '', // 编辑类型,add or edit
    title: '', // 模态框标题
    visible: null, // 模态框是否可见
    formlist: null, // 表单信息
    editMenu: null, // 编辑菜单
    thawmenulist: null, // 已冻结的二级菜单
    thawMvisible: false, // 解除冻结模态框
    confirmLoading: false, // 提交中。。。
    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
  }
  handlePreviewList = (List) => {
    // 菜单顺序改变时,保存中间状态
    previewList = List
  }
  handleMenu = (menu) => {
    // 菜单编辑:修改、删除,如菜单顺序已改变,提示保存菜单顺序
    const _this = this
    if (previewList && !is(fromJS(previewList), fromJS(this.state.subMenulist))) {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.presave'],
        duration: 10
      })
    } else if (menu.type === 'close') {
      confirm({
        title: this.state.dict['header.menu.close'].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() {}
      })
    } else if (menu.type === 'edit') {
      this.setState({
        visible: true,
        title: this.state.dict['header.menu.editTitle'],
        type: 'edit',
        editMenu: menu.card,
        formlist: [
          { // 父级菜单
            type: 'select',
            key: 'parentId',
            label: this.state.dict['header.menu.supMenu'],
            initVal: this.props.supMenu.MenuID,
            required: true,
            options: this.props.supMenuList
          },
          { // 菜单名称
            type: 'text',
            key: 'menuName',
            label: this.state.dict['header.menu.menuName'],
            initVal: menu.card.text,
            required: true,
            readonly: false
          },
          { // 菜单图标
            type: 'select',
            key: 'icon',
            label: this.state.dict['header.menu.icon'],
            initVal: menu.card.PageParam.Icon,
            required: true,
            options: [{
              MenuID: 'folder',
              text: 'folder'
            }, {
              MenuID: 'api',
              text: 'api'
            }]
          }
        ]
      })
    }
  }
  handleSubBtn = (type) => {
    // 操作按钮
    if (type === 'add') { // 添加新菜单
      this.setState({
        visible: true,
        title: this.state.dict['header.menu.addtitle'],
        type: 'add',
        formlist: [
          { // 父级菜单
            type: 'select',
            key: 'parentId',
            label: this.state.dict['header.menu.supMenu'],
            initVal: this.props.supMenu.MenuID,
            required: true,
            options: this.props.supMenuList
          },
          { // 菜单名称
            type: 'text',
            key: 'menuName',
            label: this.state.dict['header.menu.menuName'],
            initVal: '',
            required: true,
            readonly: false
          },
          { // 菜单图标
            type: 'select',
            key: 'icon',
            label: this.state.dict['header.menu.icon'],
            initVal: 'folder',
            required: true,
            options: [{
              MenuID: 'folder',
              text: 'folder'
            }, {
              MenuID: 'api',
              text: 'api'
            }]
          }
        ]
      })
    } else if (type === 'thaw') { // 解冻已有菜单
      this.setState({
        thawMvisible: true
      })
      Api.getSystemConfig({
        func: 'sPC_Get_FrozenMenu',
        ParentID: this.props.supMenu.MenuID,
        TYPE: 20
      }).then(res => {
        if (res.status) {
          this.setState({
            thawmenulist: res.data.map(menu => {
              return {
                key: menu.MenuID,
                title: menu.MenuName
              }
            })
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
        }
      })
    } else if (type === 'confirm') { // 确定时入顺序改变,则提示保存,否则退出编辑
      if (previewList && !is(fromJS(previewList), fromJS(this.state.subMenulist))) {
        let _this = this
        let param  = {}
        param.func = 'sPC_Menu_SortUpt'
        param.LText = []
        previewList.forEach((item, index) => {
          param.LText.push('selectmspace\'' + item.MenuID + '\'mspaceasmspaceMenuid,' + (index + 1) * 10 + 'mspaceasmspacesort')
        })
        param.LText = param.LText.join('mspaceunionmspace')
        confirm({
          title: this.state.dict['header.menu.resetorder'],
          content: '',
          okText: this.state.dict['header.confirm'],
          cancelText: this.state.dict['header.cancel'],
          onOk() {
            return Api.getSystemConfig(param).then(res => {
              if (res.status) {
                _this.props.reload()
              } else {
                notification.warning({
                  top: 92,
                  message: res.message,
                  duration: 10
                })
              }
            })
          },
          onCancel() {}
        })
      } else {
        this.props.exitEdit()
      }
    } else if (type === 'close') { // 退出编辑
      this.props.exitEdit()
    }
  }
  memuHandleSubmit = () => {
    if (this.state.type === 'add') { // 新建菜单:提交
      this.menuFormRef.handleConfirm().then(values => {
        let param = {
          ParentID: values.parentId,
          MenuID: Utils.getuuid(),
          MenuName: values.menuName,
          PageParam: JSON.stringify({
            Icon: values.icon
          })
        }
        param.func = 'sPC_SndMenu_Add'
        param.Sort = (this.props.menulist.length + 1) * 10
        this.setState({
          confirmLoading: true
        })
        Api.getSystemConfig(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              visible: false
            })
            this.props.reload()
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      }, () => {})
    } else if (this.state.type === 'edit') { // 编辑菜单:提交
      this.menuFormRef.handleConfirm().then(values => {
        let param = {
          func: 'sPC_SndMenu_Upt',
          ParentID: values.parentId,
          MenuID: this.state.editMenu.MenuID,
          MenuName: values.menuName,
          PageParam: JSON.stringify({
            Icon: values.icon
          })
        }
        this.setState({
          confirmLoading: true
        })
        Api.getSystemConfig(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              visible: false
            })
            this.props.reload()
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      }, () => {})
    }
  }
  memuHandleCancel = () => { // 取消操作,关闭模态框
    this.setState({
      visible: false,
      type: '',
      formlist: null,
      editMenu: null
    })
  }
  thawMemuSubmit = () => { // 解冻菜单,提交,存在多个时,循环提交
    if (this.refs.trawmenu.state.targetKeys.length === 0) {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.thawmenu.select'],
        duration: 10
      })
    } else {
      this.setState({
        confirmLoading: true
      })
      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
        return new Promise((resolve) => {
          Api.getSystemConfig({
            func: 'sPC_MainMenu_ReDel',
            MenuID: item
          }).then(res => {
            if (res.status) {
              resolve('')
            } else {
              resolve(res.message)
            }
          })
        })
      })
      Promise.all(defers).then(res => {
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.error({
            top: 92,
            message: msg,
            duration: 15
          })
        } else {
          this.setState({
            confirmLoading: false,
            thawMvisible: false,
            thawmenulist: null
          })
          this.props.reload()
        }
      })
    }
  }
  thawMemuCancel = () => { // 解冻菜单取消
    this.setState({
      thawMvisible: false,
      thawmenulist: null
    })
  }
  UNSAFE_componentWillMount () {
    previewList = null
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.menulist), fromJS(nextProps.menulist))) {
      this.setState({show: false})
      setTimeout(() => {
        this.setState({show: true})
      }, 10)
    }
  }
  render () {
    return (
      <div className="second-edit-box">
        {this.state.show && <DndProvider backend={HTML5Backend}>
          <DragElement
            list={this.props.menulist}
            handlePreviewList={this.handlePreviewList}
            handleMenu={this.handleMenu}
          />
        </DndProvider>}
        <div className="menu-add" onClick={() => {this.handleSubBtn('add')}}>
          <Icon type="plus" />
        </div>
        <div className="menu-btn">
          <Button type="primary" onClick={() => {this.handleSubBtn('thaw')}}>{this.state.dict['header.thawmenu']}</Button>
          <Button type="primary" onClick={() => {this.handleSubBtn('confirm')}}>{this.state.dict['header.confirm']}</Button>
          <Button onClick={() => {this.handleSubBtn('close')}}>{this.state.dict['header.close']}</Button>
        </div>
        <Modal
          title={this.state.title}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.visible}
          onOk={this.memuHandleSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.memuHandleCancel}
        >
          {this.state.formlist &&
          <MenuForm
            dict={this.state.dict}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />}
        </Modal>
        <Modal
          title={this.state.dict['header.thawmenu']}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.thawMvisible}
          onOk={this.thawMemuSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.thawMemuCancel}
        >
          {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
          {this.state.thawmenulist && <TransferForm ref="trawmenu" dict={this.state.dict} menulist={this.state.thawmenulist}/>}
        </Modal>
      </div>
    )
  }
}
export default EditMenu
src/components/sidemenu/editsecmenu/index.scss
src/components/sidemenu/editthdmenu/index.jsx
New file
@@ -0,0 +1,719 @@
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 { notification, Modal, Button, Spin, Icon, Col, Card, Tabs, Row } from 'antd'
import Preview from '@/components/preview'
import TransferForm from '@/components/transferform'
import Utils from '@/utils/utils.js'
import DragElement from '../dragelement'
import MenuForm from '../menuform'
import ComTableConfig from '../comtableconfig'
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 { confirm } = Modal
const { TabPane } = Tabs
const illust = {
  CommonTable: nortable
}
let previewList = null
class EditMenu extends Component {
  static propTpyes = {
    menulist: PropTypes.any,
    supMenuList: PropTypes.array,
    supMenu: PropTypes.object,
    reload: PropTypes.func,
    exitEdit: PropTypes.func
  }
  state = {
    show: true,
    thawmenulist: null, // 已冻结的二级菜单
    visible: null,
    title: '',
    type: '',
    tabview: '', // 选择模板窗口(template)、基础表格配置(CommonTable)
    formlist: null,
    editMenu: null, // 编辑菜单
    editMvisible: false, // 编辑菜单模态框
    thawMvisible: false, // 解除冻结模态框
    confirmLoading: false, // 提交中。。。
    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
    selectTemp: '', // 选择模板
    usedTemplates: null,
    menuConfig: '',
    baseTemplates: [{
      title: '基础表格',
      type: 'CommonTable',
      url: illust['CommonTable']
    }, {
      title: '数据表格',
      type: 'datatable',
      url: illust['CommonTable']
    }]
  }
  handlePreviewList = (List) => {
    // 菜单顺序改变时,保存中间状态
    previewList = List
  }
  handleMenu = (menu) => {
    // 菜单编辑:修改、删除
    const _this = this
    if (previewList && !is(fromJS(previewList), fromJS(this.state.subMenulist))) {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.presave'],
        duration: 10
      })
    } else if (menu.type === 'close') {
      confirm({
        title: this.state.dict['header.menu.close'].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() {}
      })
    } else if (menu.type === 'edit') {
      let _menu = menu.card
      let param = {
        func: 'sPC_Get_LongParam',
        MenuID: _menu.MenuID
      }
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          this.setState({
            editMvisible: true,
            title: this.state.dict['header.menu.editTitle'],
            type: 'edit',
            editMenu: {..._menu, LongParam: res.LongParam},
            formlist: [
              {
                type: 'select',
                key: 'parentId',
                label: this.state.dict['header.menu.supMenu'],
                initVal: this.props.supMenu.MenuID,
                required: true,
                options: this.props.supMenuList
              },
              {
                type: 'text',
                key: 'menuName',
                label: this.state.dict['header.menu.menuName'],
                initVal: menu.card.text,
                required: true,
                readonly: false
              },
              {
                type: 'text',
                key: 'menuNo',
                label: this.state.dict['header.menu.menuNo'],
                initVal: menu.card.MenuNo,
                required: true,
                readonly: false
              },
              {
                type: 'select',
                key: 'opentype',
                label: '打开方式',
                initVal: menu.card.PageParam.OpenType || 'newtab',
                required: true,
                options: [{
                  MenuID: 'newtab',
                  text: '新标签页'
                }, {
                  MenuID: 'newpage',
                  text: '新页面'
                }]
              }
            ]
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
        }
      })
    }
  }
  handleSubBtn = (type) => {
    // 操作按钮:添加、解除冻结、确认及关闭
    if (type === 'add') { // 点击添加时,展开模板
      this.setState({tabview: 'template', type: 'add'})
    } else if (type === 'thaw') {
      this.setState({
        thawMvisible: true
      })
      Api.getSystemConfig({
        func: 'sPC_Get_FrozenMenu',
        ParentID: this.props.supMenu.MenuID,
        TYPE: 30
      }).then(res => {
        if (res.status) {
          this.setState({
            thawmenulist: res.data.map(menu => {
              return {
                key: menu.MenuID,
                title: menu.MenuName
              }
            })
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 10
          })
        }
      })
    } else if (type === 'confirm') {
      if (previewList && !is(fromJS(previewList), fromJS(this.state.subMenulist))) {
        let _this = this
        let param  = {}
        param.func = 'sPC_Menu_SortUpt'
        param.LText = []
        previewList.forEach((item, index) => {
          param.LText.push('selectmspace\'' + item.MenuID + '\'mspaceasmspaceMenuid,' + (index + 1) * 10 + 'mspaceasmspacesort')
        })
        param.LText = param.LText.join('mspaceunionmspace')
        confirm({
          title: this.state.dict['header.menu.resetorder'],
          content: '',
          okText: this.state.dict['header.confirm'],
          cancelText: this.state.dict['header.cancel'],
          onOk() {
            return Api.getSystemConfig(param).then(res => {
              if (res.status) {
                _this.props.reload()
              } else {
                notification.warning({
                  top: 92,
                  message: res.message,
                  duration: 10
                })
              }
            })
          },
          onCancel() {}
        })
      } else {
        this.props.exitEdit()
      }
    } else if (type === 'close') {
      this.props.exitEdit()
    }
  }
  memuHandleSubmit = () => {
    if (this.state.type === 'add') {
      // 新建菜单:提交
      this.menuFormRef.handleConfirm().then(values => {
        let param = {
          func: 'sPC_TrdMenu_Add',
          ParentID: this.props.supMenu.MenuID,
          MenuID: Utils.getuuid(),
          MenuNo: values.menuNo,
          Template: this.state.selectTemp.type,
          MenuName: values.menuName,
          Sort: (this.props.menulist.length + 1) * 10,
          PageParam: JSON.stringify({
            OpenType: values.opentype,
            Template: this.state.selectTemp.type
          }),
          LongParam: window.btoa(JSON.stringify(this.state.selectTemp.baseconfig))
        }
        this.setState({
          confirmLoading: true
        })
        Api.getSystemConfig(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              tabview: '',
              visible: false
            })
            this.props.reload()
            this.resetFormlist()
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      }, () => {})
    } else if (this.state.type === 'edit') {
      // 编辑菜单:提交
      this.menuFormRef.handleConfirm().then(values => {
        let param = {
          func: 'sPC_TrdMenu_Upt',
          ParentID: values.parentId,
          MenuID: this.state.editMenu.MenuID,
          MenuNo: values.menuNo,
          Template: this.state.editMenu.PageParam.Template || '',
          MenuName: values.menuName,
          PageParam: JSON.stringify(this.state.editMenu.PageParam),
          LongParam: this.state.editMenu.LongParam ? window.btoa(this.state.editMenu.LongParam) : ''
        }
        this.setState({
          confirmLoading: true
        })
        Api.getSystemConfig(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              editMvisible: false
            })
            this.props.reload()
            this.resetFormlist()
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      }, () => {})
    }
  }
  memuHandleCancel = () => {
    this.setState({
      editMvisible: false,
      visible: false
    })
    this.resetFormlist()
  }
  thawMemuSubmit = () => {
    // 三级菜单解除冻结
    if (this.refs.trawmenu.state.targetKeys.length === 0) {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.thawmenu.select'],
        duration: 10
      })
    } else {
      this.setState({
        confirmLoading: true
      })
      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
        return new Promise((resolve) => {
          Api.getSystemConfig({
            func: 'sPC_MainMenu_ReDel',
            MenuID: item
          }).then(res => {
            if (res.status) {
              resolve('')
            } else {
              resolve(res.message)
            }
          })
        })
      })
      Promise.all(defers).then(res => {
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.error({
            top: 92,
            message: msg,
            duration: 15
          })
        } else {
          this.setState({
            confirmLoading: false,
            thawMvisible: false,
            thawmenulist: null
          })
          this.props.reload()
        }
      })
    }
  }
  thawMemuCancel = () => {
    // 解除冻结-取消
    this.setState({
      thawMvisible: false,
      thawmenulist: null
    })
  }
  previewPicture = (url) => {
    // 图片预览
    this.setState({
      preview: url
    })
  }
  cancelPrePicture = () => {
    // 关闭图片预览
    this.setState({
      preview: null
    })
  }
  useTemplate = (template) => {
    console.log(template)
    // 选择模板:添加菜单时
    if (this.state.type === 'add') {
      this.setState({
        tabview: template.type,
        menuConfig: template.baseconfig
      })
      // this.setState({
      //   visible: true,
      //   title: this.state.dict['header.menu.addtitle'],
      //   selectTemp: template,
      //   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 {
      // this.setState({
      //   tabview: this.state.selectTemp.type
      // })
    }
  }
  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 => {
      this.setState({
        usedTemplates: res.UserTemp.map(temp => {
          let _config = ''
          if (temp.LongParam) {
            _config = window.atob(temp.LongParam)
            try {
              _config = JSON.parse(_config)
            } catch (e) {
              _config = ''
            }
          }
          return {
            title: temp.MenuName,
            type: temp.Template,
            url: illust[temp.Template],
            baseconfig: _config
          }
        })
      })
    })
  }
  exittabview = () => {
    this.setState({tabview: ''})
  }
  UNSAFE_componentWillMount () {
    previewList = null
    this.getUsedTemplate()
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.menulist), fromJS(nextProps.menulist))) {
      previewList = null
      this.setState({show: false})
      setTimeout(() => {
        this.setState({show: true})
      }, 10)
    }
  }
  render () {
    return (
      <div className="third-edit-box">
        <div className="cus-submenu-title">
          <Icon type={this.props.supMenu.PageParam.Icon} />
          <span>{this.props.supMenu.text}</span>
        </div>
        {this.state.show && <DndProvider backend={HTML5Backend}>
          <DragElement
            list={this.props.menulist}
            handlePreviewList={this.handlePreviewList}
            handleMenu={this.handleMenu}
          />
        </DndProvider>}
        <div className="menu-add" onClick={() => {this.handleSubBtn('add')}}>
          <Icon type="plus" />
        </div>
        <div className="menu-btn">
          <Button type="primary" onClick={() => {this.handleSubBtn('thaw')}}>{this.state.dict['header.thawmenu']}</Button>
          <Button type="primary" onClick={() => {this.handleSubBtn('confirm')}}>{this.state.dict['header.confirm']}</Button>
          <Button onClick={() => {this.handleSubBtn('close')}}>{this.state.dict['header.close']}</Button>
        </div>
        {this.state.tabview === 'template' &&
        <div className="editboard">
          <div className="workplace">
            <Button className="top-btn" onClick={this.exittabview}>{this.state.dict['header.cancel']}</Button>
            {this.state.tabview === 'template' && <Tabs defaultActiveKey="1">
              <TabPane tab="系统模板" key="1">
                <Row>
                  {this.state.baseTemplates.map(template => {
                    return (
                      <Col key={template.type} span={8}>
                        <Card
                          title={template.title}>
                          <img src={template.url} alt=""/>
                          <div className="card-operation">
                            <Button type="primary" onClick={() => {this.previewPicture(template.url)}}>预览</Button>
                            <Button type="primary" onClick={() => {this.useTemplate(template)}}>使用模板</Button>
                          </div>
                        </Card>
                      </Col>
                    )
                  })}
                </Row>
              </TabPane>
              <TabPane tab="已使用模板" key="2">
                <Row>
                  {this.state.usedTemplates && this.state.usedTemplates.map((template, index) => {
                    return (
                      <Col key={template.type + index} span={8}>
                        <Card
                          title={template.title}>
                          <img src={template.url} alt=""/>
                          <div className="card-operation">
                            <Button type="primary" onClick={() => {this.previewPicture(template.url)}}>预览</Button>
                            <Button type="primary" onClick={() => {this.useTemplate(template)}}>使用模板</Button>
                          </div>
                        </Card>
                      </Col>
                    )
                  })}
                </Row>
              </TabPane>
            </Tabs>}
          </div>
        </div>}
        {this.state.tabview === 'CommonTable' &&
          <ComTableConfig config={this.state.menuConfig} />
        }
        {/* 图片预览 */}
        <Preview cancel={this.cancelPrePicture} preview={this.state.preview}/>
        {/* 添加模态框 */}
        <Modal
          title={this.state.title}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.visible}
          onOk={this.memuHandleSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.memuHandleCancel}
        >
          {this.state.formlist && this.state.type === 'add' && <MenuForm
            dict={this.state.dict}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />}
        </Modal>
        {/* 编辑模态框 */}
        <Modal
          title={this.state.title}
          visible={this.state.editMvisible}
          footer={null}
          onCancel={this.memuHandleCancel}
        >
          {this.state.formlist && this.state.type === 'edit' && <MenuForm
            dict={this.state.dict}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />}
          <div className="edit-modal-footer">
            <Button className="mk-btn mk-green" onClick={this.changeTemp}>切换模板</Button>
            <Button className="mk-btn mk-purple" onClick={this.changeConfig}>更改配置</Button>
            <Button onClick={this.memuHandleCancel}>{this.state.dict['header.cancel']}</Button>
            <Button type="primary" onClick={this.memuHandleSubmit} loading={this.state.confirmLoading}>{this.state.dict['header.confirm']}</Button>
          </div>
        </Modal>
        {/* 解冻菜单模态框 */}
        <Modal
          title={this.state.dict['header.thawmenu']}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.thawMvisible}
          onOk={this.thawMemuSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.thawMemuCancel}
        >
          {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
          {this.state.thawmenulist && <TransferForm ref="trawmenu" dict={this.state.dict} menulist={this.state.thawmenulist}/>}
        </Modal>
      </div>
    )
  }
}
export default EditMenu
src/components/sidemenu/editthdmenu/index.scss
New file
@@ -0,0 +1,84 @@
.third-edit-box {
  .cus-submenu-title {
    padding: 0px 24px;
    background: #364150;
    margin: 0;
    height: 48px;
    line-height: 48px;
    width: 100%;
    overflow: hidden;
    font-size: 14px;
    white-space: nowrap;
    text-overflow: ellipsis;
    i {
      margin-right: 10px;
    }
  }
  .editboard {
    position: fixed;
    z-index: 1070;
    padding-top: 48px;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background: rgba(0, 0, 0, 0.35);
    .workplace {
      position: relative;
      width: calc(100vw - 235px);
      height: 100%;
      overflow-y: auto;
      left: 235px;
      background: #ffffff;
      .top-btn {
        position: absolute;
        z-index: 1;
        top: 12px;
        right: 20px;
        cursor: pointer;
      }
      .top-btn.submit {
        right: 100px;
      }
      .ant-col {
        padding: 10px;
      }
      .ant-card-head-title {
        text-align: center;
      }
      .ant-card-body {
        padding: 2px;
        position: relative;
        text-align: center;
        overflow: hidden;
        .card-operation {
          position: absolute;
          right: 0px;
          top: 0;
          height: 0px;
          overflow: hidden;
          transition: height 0.3s;
          button {
            height: 30px;
            padding: 0 10px;
            margin-top: 5px;
            margin-right: 10px;
            display: none;
          }
        }
      }
      .ant-card-body:hover {
        .card-operation {
          height: 40px;
          button {
            display: inline-block;
          }
        }
      }
      img {
        max-width: 100%;
      }
    }
  }
}
src/components/sidemenu/index.jsx
@@ -3,25 +3,17 @@
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
// import { Menu, Icon, Button, notification, Modal, Spin, Tabs, Card, Row, Col} from 'antd'
import { Menu, Icon, Button, notification, Modal, Spin, Tabs} from 'antd'
import HTML5Backend from 'react-dnd-html5-backend'
import { DndProvider } from 'react-dnd'
import { Menu, Icon } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import {modifyTabview, resetEditLevel} from '@/store/action'
import TransferForm from '@/components/transferform'
import Preview from '@/components/preview'
import DragElement from './dragelement'
import MenuForm from './menuform'
import zhCN from '@/locales/zh-CN/header.js'
import enUS from '@/locales/en-US/header.js'
import Api from '@/api'
import './index.scss'
// import nortable from '@/assets/img/normaltable.jpg'
const EditSecMenu = asyncComponent(() => import('./editsecmenu'))
const EditThdMenu = asyncComponent(() => import('./editthdmenu'))
const { SubMenu } = Menu
const { confirm } = Modal
const { TabPane } = Tabs
let previewList = null
class Sidemenu extends Component {
  static propTypes = {
@@ -37,17 +29,6 @@
    subMenulist: null, // 二级菜单
    editMenu: null, // 编辑三级菜单时设置
    rootSubmenuKeys: null,
    modalOptions: {
      visible: false,
      title: '',
      level: 'slevel',
      type: 'add',
      menu: null
    },
    confirmLoading: false,
    menuLoading: false,
    thawMvisible: false,
    thawmenulist: null,
    createThirdMenu: false,
    dict: (!localStorage.getItem('lang') || localStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
    openKeys: null,
@@ -55,8 +36,7 @@
  }
  async loadsubmenu (menu) {
    this.setState({menuLoading: true})
    let result = await Api.getSubMenuData(menu.MenuID)
    let result = await Api.getSystemConfig({func: 'sPC_Get_FunMenu', ParentID: menu.MenuID})
    if (result.status) {
      let param = sessionStorage.getItem('view_param') // 是否为打开新页面
      let msg = sessionStorage.getItem('UserID') + '&' + sessionStorage.getItem('SessionUid') + '&' + sessionStorage.getItem('LoginUID')
@@ -70,9 +50,7 @@
      }
      let parentID = result.data[submenuindex] ? result.data[submenuindex].ParentID : '' // 展开二级菜单ID
      this.setState({
        menuLoading: false,
        subMenulist: result.data.map((item, i) => {
      let menulist = result.data.map((item, i) => {
          let _smenu = {}
          _smenu.id = i
          _smenu.MenuID = item.ParentID
@@ -106,13 +84,18 @@
              _tmenu.MenuNo = child.MenuNo
              _tmenu.MenuName = child.MenuName
              _tmenu.text = child.MenuName
            _tmenu.type = _tmenu.PageParam.Template || _tmenu.type
              return _tmenu
            })
          }
          return _smenu
        }),
      })
      this.setState({
        subMenulist: menulist,
        rootSubmenuKeys: result.data.map(item => item.ParentID),
        openKeys: (this.props.collapse || !parentID) ? [] : [parentID]
        openKeys: (this.props.collapse || !parentID) ? [] : [parentID],
        editMenu: this.props.editLevel === 'level3' && menulist.filter(menu => menu.MenuID === this.state.editMenu.MenuID)[0]
      })
      if (tabindex !== null) {
@@ -120,6 +103,7 @@
        opentab.selected = true
        this.props.modifyTabview([opentab])
      }
      // this.props.modifyTabview([{
      //   Action: 'Index',
      //   Icon: 'Content/icons/L32X32/RoleM.png',
@@ -193,9 +177,9 @@
  enterSubEdit = (e) => {
    // 编辑二级菜单
    e.stopPropagation()
    previewList = null
    this.props.resetEditLevel('level2')
    Api.getMainMenuData().then(res => {
    // 获取一级菜单列表
    Api.getSystemConfig({func: 'sPC_Get_MainMenu'}).then(res => {
      this.setState({
        mainMenuList: res.data.map(item => {
          return {
@@ -210,402 +194,26 @@
  enterThrEdit = (e, menu) => {
    // 编辑三级菜单
    e.stopPropagation()
    previewList = null
    this.props.resetEditLevel('level3')
    this.setState({editMenu: menu})
  }
  handlePreviewList = (List) => {
    // 菜单顺序改变时,保存中间状态
    previewList = List
  }
  handleMenu = (menu) => {
    // 菜单编辑:修改、删除
    const _this = this
    if (previewList && !is(fromJS(previewList), fromJS(this.state.subMenulist))) {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.presave'],
        duration: 10
      })
    } else if (menu.type === 'close') {
      confirm({
        title: this.state.dict['header.menu.close'].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.submitInterface(param).then(res => {
            if (res.status) {
              _this.loadsubmenu(_this.props.mainMenu)
            } else {
              notification.warning({
                top: 92,
                message: res.message,
                duration: 10
              })
            }
          })
        },
        onCancel() {}
      })
    } else if (menu.type === 'edit' && this.props.editLevel === 'level2') {
      this.setState({
        modalOptions: {
          visible: true,
          title: this.state.dict['header.menu.editTitle'],
          level: 'slevel',
          type: 'edit',
          parentMenu: this.props.mainMenu,
          supMenuList: this.state.mainMenuList,
          menu: menu.card
        }
      })
    } else if (menu.type === 'edit' && this.props.editLevel === 'level3') {
      this.setState({
        modalOptions: {
          visible: true,
          title: this.state.dict['header.menu.editTitle'],
          level: 'tlevel',
          type: 'edit',
          parentMenu: this.state.editMenu,
          supMenuList: this.state.subMenulist,
          menu: menu.card
        }
      })
    }
  }
  createThMenu = () => {
    this.setState({
      modalOptions: {
        visible: true,
        title: this.state.dict['header.menu.addtitle'],
        level: 'tlevel',
        type: 'add',
        parentMenu: this.state.editMenu,
        supMenuList: this.state.subMenulist,
        menu: null
      }
    })
  }
  handleSubBtn = (type) => {
    // 操作按钮
    if (this.props.editLevel === 'level2') {
      if (type === 'add') {
        this.setState({
          modalOptions: {
            visible: true,
            title: this.state.dict['header.menu.addtitle'],
            level: 'slevel',
            type: 'add',
            parentMenu: this.props.mainMenu,
            supMenuList: this.state.mainMenuList,
            menu: null
          }
        })
      } else if (type === 'thaw') {
        this.setState({
          thawMvisible: true
        })
        Api.submitInterface({
          func: 'sPC_Get_FrozenMenu',
          ParentID: this.props.mainMenu.MenuID,
          TYPE: 20
        }).then(res => {
          if (res.status) {
            this.setState({
              thawmenulist: res.data.map(menu => {
                return {
                  key: menu.MenuID,
                  title: menu.MenuName
                }
              })
            })
          } else {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      } else if (type === 'confirm') {
        if (previewList && !is(fromJS(previewList), fromJS(this.state.subMenulist))) {
          let _this = this
          let param  = {}
          param.func = 'sPC_Menu_SortUpt'
          param.LText = []
          previewList.forEach((item, index) => {
            param.LText.push('selectmspace\'' + item.MenuID + '\'mspaceasmspaceMenuid,' + (index + 1) * 10 + 'mspaceasmspacesort')
          })
          param.LText = param.LText.join('mspaceunionmspace')
          confirm({
            title: this.state.dict['header.menu.resetorder'],
            content: '',
            okText: this.state.dict['header.confirm'],
            cancelText: this.state.dict['header.cancel'],
            onOk() {
              return Api.submitInterface(param).then(res => {
                if (res.status) {
                  _this.loadsubmenu(_this.props.mainMenu)
                } else {
                  notification.warning({
                    top: 92,
                    message: res.message,
                    duration: 10
                  })
                }
              })
            },
            onCancel() {}
          })
        } else {
          this.props.resetEditLevel(false)
        }
      } else if (type === 'close') {
        this.props.resetEditLevel(false)
      }
    } else {
      if (type === 'add') {
        this.setState({
          createThirdMenu: true
          // modalOptions: {
          //   visible: true,
          //   title: this.state.dict['header.menu.addtitle'],
          //   level: 'tlevel',
          //   type: 'add',
          //   parentMenu: this.state.editMenu,
          //   supMenuList: this.state.subMenulist,
          //   menu: null
          // }
        })
      } else if (type === 'thaw') {
        this.setState({
          thawMvisible: true
        })
        Api.submitInterface({
          func: 'sPC_Get_FrozenMenu',
          ParentID: this.state.editMenu.MenuID,
          TYPE: 30
        }).then(res => {
          if (res.status) {
            this.setState({
              thawmenulist: res.data.map(menu => {
                return {
                  key: menu.MenuID,
                  title: menu.MenuName
                }
              })
            })
          } else {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      } else if (type === 'confirm') {
        if (previewList && !is(fromJS(previewList), fromJS(this.state.editMenu.children))) {
          let _this = this
          let param  = {}
          param.func = 'sPC_Menu_SortUpt'
          param.LText = []
          previewList.forEach((item, index) => {
            param.LText.push('selectmspace\'' + item.MenuID + '\'mspaceasmspaceMenuid,' + (index + 1) * 10 + 'mspaceasmspacesort')
          })
          param.LText = param.LText.join('mspaceunionmspace')
          confirm({
            title: this.state.dict['header.menu.resetorder'],
            content: '',
            okText: this.state.dict['header.confirm'],
            cancelText: this.state.dict['header.cancel'],
            onOk() {
              return Api.submitInterface(param).then(res => {
                if (res.status) {
                  _this.loadsubmenu(_this.props.mainMenu)
                } else {
                  notification.warning({
                    top: 92,
                    message: res.message,
                    duration: 10
                  })
                }
              })
            },
            onCancel() {}
          })
        } else {
          this.props.resetEditLevel(false)
        }
      } else if (type === 'close') {
        this.props.resetEditLevel(false)
      }
    }
  }
  memuHandleSubmit = () => {
    let options = this.state.modalOptions
    if (options.type === 'add' && options.level === 'slevel') {
      // 新建菜单:提交
      this.menuFormRef.handleConfirm().then(param => {
        param.func = 'sPC_SndMenu_Add'
        param.Sort = (this.state.subMenulist.length + 1) * 10
        this.setState({
          confirmLoading: true
        })
        Api.submitInterface(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              modalOptions: {
                ...options,
                visible: false,
                parentMenu: null,
                supMenuList: null,
                menu: null
              }
            })
            this.loadsubmenu(this.props.mainMenu)
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      }, () => {})
    } else if (options.type === 'edit' && options.level === 'slevel') {
      // 编辑菜单:提交
      this.menuFormRef.handleConfirm().then(param => {
        param.func = 'sPC_SndMenu_Upt'
        this.setState({
          confirmLoading: true
        })
        Api.submitInterface(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              modalOptions: {
                ...options,
                visible: false,
                parentMenu: null,
                supMenuList: null,
                menu: null
              }
            })
            this.loadsubmenu(this.props.mainMenu)
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 10
            })
          }
        })
      }, () => {})
    }
  }
  memuHandleCancel = () => {
    let options = this.state.modalOptions
    this.setState({
      modalOptions: {
        ...options,
        visible: false,
        menu: null
      }
    })
  }
  callback = () => {
  }
  thawMemuSubmit = () => {
    if (this.refs.trawmenu.state.targetKeys.length === 0) {
      notification.warning({
        top: 92,
        message: this.state.dict['header.menu.thawmenu.select'],
        duration: 10
      })
    } else {
      this.setState({
        confirmLoading: true
      })
      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
        return new Promise((resolve) => {
          Api.submitInterface({
            func: 'sPC_MainMenu_ReDel',
            MenuID: item
          }).then(res => {
            if (res.status) {
              resolve('')
            } else {
              resolve(res.message)
            }
          })
        })
      })
      Promise.all(defers).then(res => {
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.error({
            top: 92,
            message: msg,
            duration: 15
          })
        } else {
          this.setState({
            confirmLoading: false,
            thawMvisible: false,
            thawmenulist: null,
            menulist: null
          })
  reload = () => {
          this.loadsubmenu(this.props.mainMenu)
        }
      })
    }
  }
  thawMemuCancel = () => {
    this.setState({
      thawMvisible: false,
      thawmenulist: null
    })
  exitEdit = () => {
    if (this.props.editLevel === 'level3') {
      this.setState({editMenu: null})
  }
  previewPicture = (url) => {
    this.setState({
      preview: url
    })
  }
  cancelPrePicture = () => {
    this.setState({
      preview: null
    })
    this.props.resetEditLevel(false)
  }
  render () {
    const editShow = (this.props.editState && !this.props.editLevel) || false
    return (
      <aside className={"side-menu ant-menu-dark" + (this.props.collapse ? ' side-menu-collapsed' : '') + (this.props.isiframe ? ' iframe' : '')}>
        {this.state.subMenulist && (!this.props.editLevel || this.props.editLevel === 'level1') &&
        {this.state.subMenulist && !(this.props.editLevel === 'level2' || this.props.editLevel === 'level3') &&
          <Menu openKeys={this.state.openKeys} onOpenChange={this.onOpenChange} mode="inline" theme="dark" inlineCollapsed={this.props.collapse}>
          {editShow && <li className="sup-menu"><Icon onClick={this.enterSubEdit} className="edit-check" type="edit" /></li>}
          {this.state.subMenulist.map((item, index) => {
@@ -633,148 +241,24 @@
            )
          })}
        </Menu>}
        {this.props.editLevel === 'level2' && !this.state.menuLoading &&
          <div>
            <DndProvider className="header-drag-menu" backend={HTML5Backend}>
              <DragElement
                list={this.state.subMenulist}
                handlePreviewList={this.handlePreviewList}
                handleMenu={this.handleMenu}
        {this.props.editLevel === 'level2' &&
          <EditSecMenu
            menulist={this.state.subMenulist}
            supMenuList={this.state.mainMenuList}
            supMenu={this.props.mainMenu}
            reload={this.reload}
            exitEdit={this.exitEdit}
              />
            </DndProvider>
            <div className="menu-add" onClick={() => {this.handleSubBtn('add')}}>
              <Icon type="plus" />
            </div>
            <div className="menu-btn">
              <Button type="primary" onClick={() => {this.handleSubBtn('thaw')}}>{this.state.dict['header.thawmenu']}</Button>
              <Button type="primary" onClick={() => {this.handleSubBtn('confirm')}}>{this.state.dict['header.confirm']}</Button>
              <Button onClick={() => {this.handleSubBtn('close')}}>{this.state.dict['header.close']}</Button>
            </div>
          </div>
        }
        {this.props.editLevel === 'level3' && this.state.editMenu && !this.state.menuLoading &&
          <div>
            <div className="cus-submenu-title">
              <Icon type={this.state.editMenu.PageParam.Icon} />
              <span>{this.state.editMenu.text}</span>
            </div>
            <DndProvider className="header-drag-menu" backend={HTML5Backend}>
              <DragElement
                list={this.state.editMenu.children}
                handlePreviewList={this.handlePreviewList}
                handleMenu={this.handleMenu}
        {this.props.editLevel === 'level3' && this.state.subMenulist &&
          <EditThdMenu
            menulist={this.state.editMenu.children}
            supMenuList={this.state.subMenulist}
            supMenu={this.state.editMenu}
            reload={this.reload}
            exitEdit={this.exitEdit}
              />
            </DndProvider>
            <div className="menu-add" onClick={() => {this.handleSubBtn('add')}}>
              <Icon type="plus" />
            </div>
            <div className="menu-btn">
              <Button type="primary" onClick={() => {this.handleSubBtn('thaw')}}>{this.state.dict['header.thawmenu']}</Button>
              <Button type="primary" onClick={() => {this.handleSubBtn('confirm')}}>{this.state.dict['header.confirm']}</Button>
              <Button onClick={() => {this.handleSubBtn('close')}}>{this.state.dict['header.close']}</Button>
            </div>
          </div>
        }
        <Modal
          title={this.state.modalOptions.title}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.modalOptions.visible}
          onOk={this.memuHandleSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.memuHandleCancel}
        >
          <MenuForm
            dict={this.state.dict}
            options={this.state.modalOptions}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />
        </Modal>
        <Modal
          title={this.state.dict['header.thawmenu']}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.thawMvisible}
          onOk={this.thawMemuSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.thawMemuCancel}
        >
          {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
          {this.state.thawmenulist && <TransferForm ref="trawmenu" dict={this.state.dict} menulist={this.state.thawmenulist}/>}
        </Modal>
        {/* {this.props.editLevel === 'level3' && this.state.createThirdMenu &&
        <div className="editboard">
          <div className="workplace">
            <Tabs defaultActiveKey="1" onChange={this.callback}>
              <TabPane tab="系统模板" key="1">
                <Row>
                  <Col span={8}>
                    <Card
                      title={
                        '基础表格'
                      }>
                      <img src={nortable} alt=""/>
                      <div className="card-operation">
                        <Button type="primary" onClick={() => {this.previewPicture(nortable)}}>预览</Button>
                        <Button type="primary" onClick={() => {this.createThMenu()}}>使用模板</Button>
                      </div>
                    </Card>
                  </Col>
                  <Col span={8}>
                    <Card
                      title={
                        '数据表格'
                      }>
                      <img src={nortable} alt=""/>
                      <div className="card-operation">
                        <Button type="primary" onClick={() => {this.previewPicture(nortable)}}>预览</Button>
                        <Button type="primary" onClick={() => {this.createThMenu()}}>使用模板</Button>
                      </div>
                    </Card>
                  </Col>
                </Row>
              </TabPane>
              <TabPane tab="自定义模板" key="2">
                <Row>
                  <Col span={8}>
                    <Card
                      title={
                        '基础表格'
                      }>
                      <img src={nortable} alt=""/>
                      <div className="card-operation">
                        <Button type="primary" onClick={() => {this.previewPicture(nortable)}}>预览</Button>
                        <Button type="primary" onClick={() => {this.createThMenu()}}>使用模板</Button>
                      </div>
                    </Card>
                  </Col>
                  <Col span={8}>
                    <Card
                      title={
                        '数据表格'
                      }>
                      <img src={nortable} alt=""/>
                      <div className="card-operation">
                        <Button type="primary" onClick={() => {this.previewPicture(nortable)}}>预览</Button>
                        <Button type="primary" onClick={() => {this.createThMenu()}}>使用模板</Button>
                      </div>
                    </Card>
                  </Col>
                </Row>
              </TabPane>
            </Tabs>
          </div>
        </div>} */}
        {<div className="editboard">
          <div className="workplace">
            <Tabs defaultActiveKey="1">
              <TabPane tab="编辑模板" key="1">
              </TabPane>
            </Tabs>
          </div>
        </div>}
        <Preview cancel={this.cancelPrePicture} preview={this.state.preview}/>
      </aside>
    )
  }
src/components/sidemenu/index.scss
@@ -69,62 +69,6 @@
      margin-left: 5px;
    }
  }
  .editboard {
    position: fixed;
    z-index: 10;
    top: 48px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background: rgba(0, 0, 0, 0.15);
    .workplace {
      position: relative;
      width: calc(100vw - 235px);
      height: 100%;
      overflow-y: auto;
      left: 235px;
      background: #ffffff;
      .ant-col {
        padding: 10px;
      }
      .ant-card-head-title {
        text-align: center;
      }
      .ant-card-body {
        padding: 2px;
        position: relative;
        text-align: center;
        overflow: hidden;
        .card-operation {
          position: absolute;
          right: 0px;
          top: 0;
          height: 0px;
          overflow: hidden;
          transition: height 0.3s;
          button {
            height: 30px;
            padding: 0 10px;
            margin-top: 5px;
            margin-right: 10px;
            display: none;
          }
        }
      }
      .ant-card-body:hover {
        .card-operation {
          height: 40px;
          button {
            display: inline-block;
          }
        }
      }
      img {
        max-width: 100%;
      }
    }
  }
  .sup-menu {
    position: relative;
    z-index: 1;
@@ -132,24 +76,24 @@
  .ant-menu-sub.ant-menu-inline .sub-menu {
    position: absolute;
    z-index: 1;
    width: 30px;
    left: 205px;
    width: 48px;
    left: 187px;
  }
  .cus-submenu-title {
    padding: 0px 24px;
    background: #364150;
    margin: 0;
    height: 48px;
    line-height: 48px;
    width: 100%;
    overflow: hidden;
    font-size: 14px;
    white-space: nowrap;
    text-overflow: ellipsis;
    i {
      margin-right: 10px;
    }
  }
  // .cus-submenu-title {
  //   padding: 0px 24px;
  //   background: #364150;
  //   margin: 0;
  //   height: 48px;
  //   line-height: 48px;
  //   width: 100%;
  //   overflow: hidden;
  //   font-size: 14px;
  //   white-space: nowrap;
  //   text-overflow: ellipsis;
  //   i {
  //     margin-right: 10px;
  //   }
  // }
}
.side-menu.iframe { // tab页中为iframe时
  max-height: 100vh;
src/components/sidemenu/menuform/index.jsx
@@ -1,143 +1,12 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, Icon } from 'antd'
import Utils from '@/utils/utils.js'
import './index.scss'
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    options: PropTypes.object
  }
  state = {
    formlist: [],
    menuform: {
      slevel: [
        {
          type: 'select',
          key: 'parentId',
          label: this.props.dict['header.menu.supMenu'],
          initVal: '',
          required: true,
          options: []
        },
        {
          type: 'text',
          key: 'menuName',
          label: this.props.dict['header.menu.menuName'],
          initVal: '',
          required: true,
          readonly: false
        },
        {
          type: 'select',
          key: 'icon',
          label: this.props.dict['header.menu.icon'],
          initVal: 'folder',
          required: true,
          options: [{
            MenuID: 'folder',
            text: 'folder'
          }, {
            MenuID: 'api',
            text: 'api'
          }]
        }
      ],
      tlevel: [
        {
          type: 'select',
          key: 'parentId',
          label: this.props.dict['header.menu.supMenu'],
          initVal: '',
          required: true,
          options: []
        },
        {
          type: 'text',
          key: 'menuName',
          label: this.props.dict['header.menu.menuName'],
          initVal: '',
          required: true,
          readonly: false
        },
        {
          type: 'text',
          key: 'menuNo',
          label: this.props.dict['header.menu.menuNo'],
          initVal: '',
          required: true,
          readonly: false
        }
      ]
    }
  }
  UNSAFE_componentWillMount () {
    this.resetform(this.props.options)
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (nextProps.options.visible && !is(fromJS(this.props.options), fromJS(nextProps.options))) {
      this.resetform(nextProps.options)
    }
  }
  resetform = (options) => {
    if (!options.visible) return
    let formlist = JSON.parse(JSON.stringify(this.state.menuform[options.level]))
    if (options.type === 'add' && options.level === 'slevel') {
      this.setState({
        formlist: formlist.map(item =>{
          if (item.key === 'parentId') {
            item.initVal = options.parentMenu.MenuID
            item.options = options.supMenuList
          }
          return item
        })
      })
    } else if (options.type === 'add' && options.level === 'tlevel') {
      this.setState({
        formlist: formlist.map(item =>{
          if (item.key === 'parentId') {
            item.initVal = options.parentMenu.MenuID
            item.options = options.supMenuList
          }
          return item
        })
      })
    } else if (options.type === 'edit' && options.level === 'slevel') {
      this.setState({
        formlist: formlist.map(item => {
          if (item.key === 'parentId') {
            item.initVal = options.parentMenu.MenuID
            item.options = options.supMenuList
          } else if (item.key === 'menuName') {
            item.initVal = options.menu.text
          } else if (item.key === 'icon') {
            item.initVal = options.menu.PageParam.Icon
          }
          return item
        })
      })
    } else if (options.type === 'edit' && options.level === 'tlevel') {
      this.setState({
        formlist: formlist.map(item => {
          if (item.key === 'parentId') {
            item.initVal = options.parentMenu.MenuID
            item.options = options.supMenuList
          } else if (item.key === 'menuName') {
            item.initVal = options.menu.text
          } else if (item.key === 'menuNo') {
            item.initVal = options.menu.MenuNo
          }
          return item
        })
      })
    }
    formlist: PropTypes.array
  }
  openTypeChange = (key, value) => {
@@ -164,9 +33,7 @@
  getFields() {
    const { getFieldDecorator } = this.props.form
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.hidden) return
    this.props.formlist.forEach((item, index) => {
      if (item.type === 'text') { // 文本搜索
        fields.push(
          <Col span={24} key={index}>
@@ -214,7 +81,6 @@
        )
      }
    })
    return fields
  }
@@ -223,64 +89,12 @@
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          if (this.props.options.type === 'add' && this.props.options.level === 'slevel') {
            // 二级菜单添加
            resolve({
              ParentID: values.parentId,
              MenuID: Utils.getuuid(),
              MenuName: values.menuName,
              PageParam: JSON.stringify({
                Icon: values.icon
              })
            })
          } else if (this.props.options.type === 'edit' && this.props.options.level === 'slevel') {
            resolve({
              ParentID: values.parentId,
              MenuID: this.props.options.menu.MenuID,
              MenuName: values.menuName,
              PageParam: JSON.stringify({
                Icon: values.icon
              })
            })
          } else if (this.props.options.type === 'add' && this.props.options.level === 'tlevel') {
            resolve({
              ParentID: values.parentId,
              MenuID: this.props.options.menu.MenuID,
              MenuName: values.menuName,
              PageParam: JSON.stringify({
                Icon: values.icon
              })
            })
          } else if (this.props.options.type === 'edit' && this.props.options.level === 'tlevel') {
            resolve({
              ParentID: values.parentId,
              MenuID: this.props.options.menu.MenuID,
              MenuName: values.menuName,
              MenuNo: values.menuNo,
              PageParam: JSON.stringify({
                Icon: values.icon
              })
            })
          }
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  handleReset = (type) => {
    // 重置
    if (type === 'add') {
      let formlist = this.state.formlist.map(item => {
        if (item.key === 'linkUrl') {
          item.hidden = true
        }
        return item
      })
      this.setState({formlist})
    }
    this.props.form.resetFields()
  }
  render() {
src/locales/en-US/header.js
@@ -1,5 +1,6 @@
export default {
  'header.confirm': 'Ok',
  'header.submit': 'Submit',
  'header.delete': 'Delete',
  'header.cancel': 'Cancel',
  'header.edit': 'Edit',
@@ -20,6 +21,7 @@
  'header.password.diff': 'Two passwords that you enter is inconsistent!',
  'header.password.resetsuccess': 'Password modified successfully!',
  'header.menu.close': 'Are you sure to delete the menu <<@M>> ?',
  'header.menu.update': 'Are you sure to modify the configuration information of the menu <<@M>> ?',
  'header.menu.presave': 'Menu order has been adjusted, Please save!',
  'header.menu.resetorder': 'Are you sure to adjust the menu sequence ?',
  'header.menu.addtitle': 'The new menu',
@@ -38,5 +40,12 @@
  'header.menu.thawmenu.target': 'Unfreeze',
  'header.menu.thawmenu.itemUnit': 'item',
  'header.menu.thawmenu.itemsUnit': 'items',
  'header.form.name': 'Name',
  'header.form.type': 'Type',
  'header.form.text': 'Text',
  'header.form.select': 'Select',
  'header.form.dateday': 'Date(Day)',
  'header.form.datetime': 'Date(Second)',
  'header.form.initval': 'Initial Value',
  'form.required.input': 'Please enter the '
}
src/locales/zh-CN/header.js
@@ -1,5 +1,6 @@
export default {
  'header.confirm': '确定',
  'header.submit': '提交',
  'header.delete': '删除',
  'header.cancel': '取消',
  'header.edit': '编辑',
@@ -20,6 +21,7 @@
  'header.password.diff': '两次输入密码不一致!',
  'header.password.resetsuccess': '密码修改成功!',
  'header.menu.close': '确定删除《@M》菜单吗?',
  'header.menu.update': '确定修改菜单《@M》的配置信息吗?',
  'header.menu.presave': '菜单顺序已调整,请保存!',
  'header.menu.resetorder': '确认调整菜单顺序吗?',
  'header.menu.addtitle': '新建菜单',
@@ -38,6 +40,13 @@
  'header.menu.thawmenu.target': '解除冻结',
  'header.menu.thawmenu.itemUnit': '项',
  'header.menu.thawmenu.itemsUnit': '项',
  'header.form.name': '名称',
  'header.form.type': '类型',
  'header.form.text': '文本',
  'header.form.select': '选择',
  'header.form.dateday': '日期(天)',
  'header.form.datetime': '日期(秒)',
  'header.form.initval': '初始值',
  'form.required.input': '请输入'
}
src/setupProxy.js
@@ -20,15 +20,6 @@
    }
  }))
  app.use(proxy('/mksepc', {
    target: 'http://minkesoft.com/mksepc',
    secure: false,
    changeOrigin: true,
    pathRewrite: {
    '^/mksepc': '/'
    }
  }))
  app.use(proxy('/local', { 
    target: 'http://127.0.0.1:8888',
    secure: false,
src/tabviews/commontable/index.jsx
@@ -38,7 +38,11 @@
  async loadconfig () {
    // 获取主菜单
    let result = await Api.getMainConfigsData(this.props.MenuNo)
    let param = {
      func: 'sPC_Get_LongParam',
      MenuID: this.props.MenuID
    }
    let result = await Api.getSystemConfig(param)
    if (result.status) {
      let newconfig = {}
      if (result.searches && result.searches.length > 0) {