king
2019-09-13 207e7ed3d871717df4a02f9b27792850beebe779
2019-09-13
4 文件已重命名
10个文件已修改
22个文件已添加
6个文件已删除
1685 ■■■■ 已修改文件
package-lock.json 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/index.html 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/login-logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/loginbg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/404/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/404/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/footer/footer.jsx 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/footer/footer.scss 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/header.jsx 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.scss 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/loading/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/lostsvg/index.jsx 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/resetpwd/index.jsx 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/index.jsx 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/tabview.jsx 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/header.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/login.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/header.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/login.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/action-type.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/action.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/reducer.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.scss 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/iframe/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/404/index.jsx 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/404/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.scss 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personal/personal.jsx 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personal/personal.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -3065,6 +3065,11 @@
      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
    },
    "charenc": {
      "version": "0.0.2",
      "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
      "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
    },
    "chokidar": {
      "version": "2.1.8",
      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@@ -3554,6 +3559,11 @@
        "lru-cache": "4.1.5",
        "which": "1.3.1"
      }
    },
    "crypt": {
      "version": "0.0.2",
      "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
      "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
    },
    "crypto-browserify": {
      "version": "3.12.0",
@@ -8515,6 +8525,23 @@
        "object-visit": "1.0.1"
      }
    },
    "md5": {
      "version": "2.2.1",
      "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
      "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
      "requires": {
        "charenc": "0.0.2",
        "crypt": "0.0.2",
        "is-buffer": "1.1.6"
      },
      "dependencies": {
        "is-buffer": {
          "version": "1.1.6",
          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
          "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
        }
      }
    },
    "md5.js": {
      "version": "1.3.5",
      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
package.json
@@ -37,6 +37,7 @@
    "jest-environment-jsdom-fourteen": "0.1.0",
    "jest-resolve": "24.8.0",
    "jest-watch-typeahead": "0.3.1",
    "md5": "^2.2.1",
    "mini-css-extract-plugin": "0.5.0",
    "node-sass": "^4.12.0",
    "optimize-css-assets-webpack-plugin": "5.0.3",
@@ -69,7 +70,7 @@
    "workbox-webpack-plugin": "4.3.1"
  },
  "scripts": {
    "dev": "set PORT=3001 HOST=192.168.1.30 && node scripts/start.js",
    "dev": "set PORT=3001 && node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js"
  },
public/index.html
@@ -5,10 +5,7 @@
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="minkesoft"
    />
    <meta name="description" content="minkesoft" />
    <link rel="apple-touch-icon" href="logo.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>MinkeSoft</title>
src/api/index.js
@@ -1,6 +1,5 @@
import axios from 'axios'
// axios.defaults.baseURL = 'http://localhost:8888/dostar'
axios.defaults.crossDomain = true
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
axios.defaults.withCredentials = true
@@ -9,7 +8,9 @@
  config.url = config.url || '/dostar'
  config.method = 'post'
  config.data = config.data || {}
  config.data.userid = 'U000001'
  if (config.url !== '/login') {
    config.data.userid = sessionStorage.getItem('UserID') || ''
  }
  config.data = JSON.stringify(config.data)
  return config
}, (error) => {
@@ -30,6 +31,46 @@
      axios.defaults.baseURL = 'http://127.0.0.1:8888'
    }
  }
  /**
   * @description 登录系统
   */
  loginsystem (username, password) {
    return axios({
      url: '/login',
      data: {
        Username: username,
        Password: password
      }
    })
  }
  /**
   * @description 登出系统
   */
  logoutsystem () {
    return axios({
      url: '/dostar',
      data: {
        func: 'logout'
      }
    })
  }
  /**
   * @description 重置密码
   */
  resetpassword (originpwd, newpwd) {
    return axios({
      url: '/dostar',
      data: {
        func: 'ResetPassword',
        OriginPwd: originpwd,
        NewPwd: newpwd
      }
    })
  }
  /**
   * @description 获取主菜单数据
   */
src/assets/css/main.scss
@@ -3,10 +3,8 @@
  margin: 0;
  list-style: none;
  font-style: normal;
  /*防止点击闪烁*/
  -webkit-tap-highlight-color: transparent;
  /*缩放网页,文字大小不变*/
  -webkit-text-size-adjust: none;
  -webkit-tap-highlight-color: transparent; /*防止点击闪烁*/
  -webkit-text-size-adjust: none; /*缩放网页,文字大小不变*/
  font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
src/assets/img/login-logo.png
src/assets/img/loginbg.png
src/components/404/index.jsx
New file
@@ -0,0 +1,21 @@
import React, {Component} from 'react'
import Lostsvg from '@/components/lostsvg'
import './index.scss'
class NotFound extends Component {
  render () {
    return (
      <main className="ant-pro-basicLayout-content ant-layout-content box404">
        <div className="ant-result">
          <div className="ant-result-icon ant-result-image">
            <Lostsvg />
          </div>
          <div className="ant-result-title">404</div>
          <div className="ant-result-subtitle">抱歉,你访问的页面不存在,请联系管理员。</div>
        </div>
      </main>
    )
  }
}
export default NotFound
src/components/404/index.scss
New file
@@ -0,0 +1,3 @@
.box404 {
  max-height: calc(100vh - 110px);
}
src/components/footer/footer.jsx
File was deleted
src/components/footer/footer.scss
File was deleted
src/components/header/header.jsx
File was deleted
src/components/header/index.jsx
New file
@@ -0,0 +1,207 @@
import React, {Component} from 'react'
import { withRouter } from 'react-router-dom'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import {Dropdown, Menu, Icon, Modal, message, Form } from 'antd'
import md5 from 'md5'
import {toggleCollapse, modifyMainMenu, resetState} from '@/store/action'
import Resetpwd from '@/components/resetpwd'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/header.js'
import enUS from '@/locales/en-US/header.js'
import logourl from '../../assets/img/mlogo.png'
import avatar from '../../assets/img/avatar.jpg'
import './index.scss'
const { confirm } = Modal
class Header extends Component {
  static propTpyes = {
    collapse: PropTypes.bool,
    mainMenu: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.object
    ])
  }
  state = {
    menulist: null,
    visible: false,
    dict: (!sessionStorage.getItem('lang') || sessionStorage.getItem('lang') === 'zh-CN') ? zhCN : enUS,
    confirmLoading: false
  }
  handleCollapse = () => {
    // 展开、收起左侧菜单栏
    this.props.toggleCollapse(!this.props.collapse)
  }
  changePassword = () => {
    // 点击修改密码,显示弹窗
    this.setState({
      visible: true
    })
  }
  md5Password (pwd) {
    // md5密码加密
    const salt = 'minkesoft'
    return md5(md5(pwd + salt))
  }
  resetPwdSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      this.setState({
        confirmLoading: true
      })
      this.resetPwdSubmitexec(res)
    }, () => {})
  }
  async resetPwdSubmitexec (param) {
    // 登录提交
    let password = this.md5Password(param.originpwd)
    let newpassword = this.md5Password(param.password)
    let result = await Api.resetpassword(password, newpassword)
    if (result.status) {
      this.setState({
        visible: false,
        confirmLoading: false
      })
      message.success(this.state.dict['header.password.resetsuccess'])
    } else {
      message.warning(result.message)
      this.setState({
        confirmLoading: false
      })
    }
  }
  handleCancel = () => {
    // 取消时关闭修改密码模态框
    this.setState({
      visible: false
    })
  }
  logout = () => {
    // 退出登录
    let _this = this
    confirm({
      title: this.state.dict['header.logout.hint'],
      content: '',
      okText: this.state.dict['header.confirm'],
      cancelText: this.state.dict['header.cancel'],
      onOk() {
        return Api.logoutsystem().then(res => {
          if (res.status) {
            sessionStorage.removeItem('UserID')
            sessionStorage.removeItem('lang')
            _this.props.resetState()
            _this.props.history.replace('/login')
          } else {
            message.warning(res.message)
          }
        })
      },
      onCancel() {}
    })
  }
  changeMenu (value) {
    // 主菜单切换
    this.props.modifyMainMenu(value)
  }
  async loadmenu () {
    // 获取主菜单
    let result = await Api.getMainMenuData()
    if (result.status) {
      this.setState({
        menulist: result.data.map((menu, index) => { // 增加索引,用于打开新页面时查询菜单
          menu.index = index
          return menu
        })
      })
      let param = sessionStorage.getItem('view_param') // 是否为打开新页面
      if (param) {
        let i = parseInt(param.split('&')[0])
        this.props.modifyMainMenu(result.data[i] || result.data[0])
      } else {
        this.props.modifyMainMenu(result.data[0])
      }
    }
  }
  UNSAFE_componentWillMount () {
    // 组件加载时,获取菜单数据
    this.loadmenu()
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  render () {
    const menu = (
      <Menu className="header-dropdown">
        <Menu.Item key="1" onClick={this.changePassword}>{this.state.dict['header.password']}</Menu.Item>
        <Menu.Item key="2" onClick={this.logout}>{this.state.dict['header.logout']}</Menu.Item>
      </Menu>
    )
    return (
      <header className="header-container ant-menu-dark">
        <div className={this.props.collapse ? "collapse header-logo" : "header-logo"}><img src={logourl} alt=""/></div>
        <div className={this.props.collapse ? "collapse header-collapse" : "header-collapse"} onClick={this.handleCollapse}>
          <Icon type={this.props.collapse ? 'menu-unfold' : 'menu-fold'} />
        </div>
        {this.state.menulist && <ul className="header-menu">{
          this.state.menulist.map(item => {
            return (
              <li key={item.id} onClick={() => {this.changeMenu(item)}} className={this.props.selectmenu.id === item.id ? 'active' : ''}>
                {item.MenuName}
              </li>
            )
          })
        }</ul>}
        <Dropdown className="header-setting" overlay={menu}>
          <div>
            <img src={avatar} alt=""/>
            <span>
              admin <Icon type="down" />
            </span>
          </div>
        </Dropdown>
        <Modal
          title={this.state.dict['header.password']}
          okText={this.state.dict['header.confirm']}
          cancelText={this.state.dict['header.cancel']}
          visible={this.state.visible}
          onOk={this.resetPwdSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.handleCancel}
        >
          {this.state.visible && (<Resetpwd dict={this.state.dict} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>)}
        </Modal>
      </header>
    )
  }
}
const mapStateToProps = (state) => {
  return {
    collapse: state.collapse,
    selectmenu: state.selectedMainMenu
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    toggleCollapse: (collapse) => dispatch(toggleCollapse(collapse)),
    modifyMainMenu: (selectmenu) => dispatch(modifyMainMenu(selectmenu)),
    resetState: () => dispatch(resetState())
  }
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form.create()(Header)))
src/components/header/index.scss
File was renamed from src/components/header/header.scss
@@ -1,4 +1,3 @@
@import '../../assets/css/iconfont.css';
@import '../../assets/css/global.scss';
.header-container {
@@ -80,7 +79,6 @@
  }
}
.header-dropdown {
  margin-top: -5px;
  li {
    padding: 5px 25px;
  }
src/components/loading/index.jsx
New file
@@ -0,0 +1,20 @@
import React, {Component} from 'react'
class Loading extends Component {
  render () {
    return (
      <div className="page-loading-warp">
        <div className="ant-spin ant-spin-lg ant-spin-spinning">
          <span className="ant-spin-dot ant-spin-dot-spin">
            <i className="ant-spin-dot-item"></i>
            <i className="ant-spin-dot-item"></i>
            <i className="ant-spin-dot-item"></i>
            <i className="ant-spin-dot-item"></i>
          </span>
        </div>
      </div>
    )
  }
}
export default Loading
src/components/lostsvg/index.jsx
New file
@@ -0,0 +1,74 @@
import React, {Component} from 'react'
class Lostsvg extends Component {
  render () {
    return (
      <svg width="252" height="294">
        <defs><path d="M0 .387h251.772v251.772H0z"></path></defs>
        <g fill="none" fillRule="evenodd">
          <g transform="translate(0 .012)">
            <mask fill="#fff"></mask>
            <path d="M0 127.32v-2.095C0 56.279 55.892.387 124.838.387h2.096c68.946 0 124.838 55.892 124.838 124.838v2.096c0 68.946-55.892 124.838-124.838 124.838h-2.096C55.892 252.16 0 196.267 0 127.321" fill="#E4EBF7" mask="url(#b)"></path>
          </g>
          <path d="M39.755 130.84a8.276 8.276 0 1 1-16.468-1.66 8.276 8.276 0 0 1 16.468 1.66" fill="#FFF"></path>
          <path d="M36.975 134.297l10.482 5.943M48.373 146.508l-12.648 10.788" stroke="#FFF" strokeWidth="2"></path>
          <path d="M39.875 159.352a5.667 5.667 0 1 1-11.277-1.136 5.667 5.667 0 0 1 11.277 1.136M57.588 143.247a5.708 5.708 0 1 1-11.358-1.145 5.708 5.708 0 0 1 11.358 1.145M99.018 26.875l29.82-.014a4.587 4.587 0 1 0-.003-9.175l-29.82.013a4.587 4.587 0 1 0 .003 9.176M110.424 45.211l29.82-.013a4.588 4.588 0 0 0-.004-9.175l-29.82.013a4.587 4.587 0 1 0 .004 9.175" fill="#FFF"></path>
          <path d="M112.798 26.861v-.002l15.784-.006a4.588 4.588 0 1 0 .003 9.175l-15.783.007v-.002a4.586 4.586 0 0 0-.004-9.172M184.523 135.668c-.553 5.485-5.447 9.483-10.931 8.93-5.485-.553-9.483-5.448-8.93-10.932.552-5.485 5.447-9.483 10.932-8.93 5.485.553 9.483 5.447 8.93 10.932" fill="#FFF"></path>
          <path d="M179.26 141.75l12.64 7.167M193.006 156.477l-15.255 13.011" stroke="#FFF" strokeWidth="2"></path>
          <path d="M184.668 170.057a6.835 6.835 0 1 1-13.6-1.372 6.835 6.835 0 0 1 13.6 1.372M203.34 153.325a6.885 6.885 0 1 1-13.7-1.382 6.885 6.885 0 0 1 13.7 1.382" fill="#FFF"></path>
          <path d="M151.931 192.324a2.222 2.222 0 1 1-4.444 0 2.222 2.222 0 0 1 4.444 0zM225.27 116.056a2.222 2.222 0 1 1-4.445 0 2.222 2.222 0 0 1 4.444 0zM216.38 151.08a2.223 2.223 0 1 1-4.446-.001 2.223 2.223 0 0 1 4.446 0zM176.917 107.636a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zM195.291 92.165a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zM202.058 180.711a2.223 2.223 0 1 1-4.446 0 2.223 2.223 0 0 1 4.446 0z" stroke="#FFF" strokeWidth="2"></path>
          <path stroke="#FFF" strokeWidth="2" d="M214.404 153.302l-1.912 20.184-10.928 5.99M173.661 174.792l-6.356 9.814h-11.36l-4.508 6.484M174.941 125.168v-15.804M220.824 117.25l-12.84 7.901-15.31-7.902V94.39"></path>
          <path d="M166.588 65.936h-3.951a4.756 4.756 0 0 1-4.743-4.742 4.756 4.756 0 0 1 4.743-4.743h3.951a4.756 4.756 0 0 1 4.743 4.743 4.756 4.756 0 0 1-4.743 4.742" fill="#FFF"></path>
          <path d="M174.823 30.03c0-16.281 13.198-29.48 29.48-29.48 16.28 0 29.48 13.199 29.48 29.48 0 16.28-13.2 29.48-29.48 29.48-16.282 0-29.48-13.2-29.48-29.48" fill="#1890FF"></path>
          <path d="M205.952 38.387c.5.5.785 1.142.785 1.928s-.286 1.465-.785 1.964c-.572.5-1.214.75-2 .75-.785 0-1.429-.285-1.929-.785-.572-.5-.82-1.143-.82-1.929s.248-1.428.82-1.928c.5-.5 1.144-.75 1.93-.75.785 0 1.462.25 1.999.75m4.285-19.463c1.428 1.249 2.143 2.963 2.143 5.142 0 1.712-.427 3.13-1.219 4.25-.067.096-.137.18-.218.265-.416.429-1.41 1.346-2.956 2.699a5.07 5.07 0 0 0-1.428 1.75 5.207 5.207 0 0 0-.536 2.357v.5h-4.107v-.5c0-1.357.215-2.536.714-3.5.464-.964 1.857-2.464 4.178-4.536l.43-.5c.643-.785.964-1.643.964-2.535 0-1.18-.358-2.108-1-2.785-.678-.68-1.643-1.001-2.858-1.001-1.536 0-2.642.464-3.357 1.43-.37.5-.621 1.135-.76 1.904a1.999 1.999 0 0 1-1.971 1.63h-.004c-1.277 0-2.257-1.183-1.98-2.43.337-1.518 1.02-2.78 2.073-3.784 1.536-1.5 3.607-2.25 6.25-2.25 2.32 0 4.214.607 5.642 1.894" fill="#FFF"></path>
          <path d="M52.04 76.131s21.81 5.36 27.307 15.945c5.575 10.74-6.352 9.26-15.73 4.935-10.86-5.008-24.7-11.822-11.577-20.88" fill="#FFB594"></path>
          <path d="M90.483 67.504l-.449 2.893c-.753.49-4.748-2.663-4.748-2.663l-1.645.748-1.346-5.684s6.815-4.589 8.917-5.018c2.452-.501 9.884.94 10.7 2.278 0 0 1.32.486-2.227.69-3.548.203-5.043.447-6.79 3.132-1.747 2.686-2.412 3.624-2.412 3.624" fill="#FFC6A0"></path>
          <path d="M128.055 111.367c-2.627-7.724-6.15-13.18-8.917-15.478-3.5-2.906-9.34-2.225-11.366-4.187-1.27-1.231-3.215-1.197-3.215-1.197s-14.98-3.158-16.828-3.479c-2.37-.41-2.124-.714-6.054-1.405-1.57-1.907-2.917-1.122-2.917-1.122l-7.11-1.383c-.853-1.472-2.423-1.023-2.423-1.023l-2.468-.897c-1.645 9.976-7.74 13.796-7.74 13.796 1.795 1.122 15.703 8.3 15.703 8.3l5.107 37.11s-3.321 5.694 1.346 9.109c0 0 19.883-3.743 34.921-.329 0 0 3.047-2.546.972-8.806.523-3.01 1.394-8.263 1.736-11.622.385.772 2.019 1.918 3.14 3.477 0 0 9.407-7.365 11.052-14.012-.832-.723-1.598-1.585-2.267-2.453-.567-.736-.358-2.056-.765-2.717-.669-1.084-1.804-1.378-1.907-1.682" fill="#FFF"></path>
          <path d="M101.09 289.998s4.295 2.041 7.354 1.021c2.821-.94 4.53.668 7.08 1.178 2.55.51 6.874 1.1 11.686-1.26-.103-5.51-6.889-3.98-11.96-6.713-2.563-1.38-3.784-4.722-3.598-8.799h-9.402s-1.392 10.52-1.16 14.573" fill="#CBD1D1"></path>
          <path d="M101.067 289.826s2.428 1.271 6.759.653c3.058-.437 3.712.481 7.423 1.031 3.712.55 10.724-.069 11.823-.894.413 1.1-.343 2.063-.343 2.063s-1.512.603-4.812.824c-2.03.136-5.8.291-7.607-.503-1.787-1.375-5.247-1.903-5.728-.241-3.918.95-7.355-.286-7.355-.286l-.16-2.647z" fill="#2B0849"></path>
          <path d="M108.341 276.044h3.094s-.103 6.702 4.536 8.558c-4.64.618-8.558-2.303-7.63-8.558" fill="#A4AABA"></path>
          <path d="M57.542 272.401s-2.107 7.416-4.485 12.306c-1.798 3.695-4.225 7.492 5.465 7.492 6.648 0 8.953-.48 7.423-6.599-1.53-6.12.266-13.199.266-13.199h-8.669z" fill="#CBD1D1"></path>
          <path d="M51.476 289.793s2.097 1.169 6.633 1.169c6.083 0 8.249-1.65 8.249-1.65s.602 1.114-.619 2.165c-.993.855-3.597 1.591-7.39 1.546-4.145-.048-5.832-.566-6.736-1.168-.825-.55-.687-1.58-.137-2.062" fill="#2B0849"></path>
          <path d="M58.419 274.304s.033 1.519-.314 2.93c-.349 1.42-1.078 3.104-1.13 4.139-.058 1.151 4.537 1.58 5.155.034.62-1.547 1.294-6.427 1.913-7.252.619-.825-4.903-2.119-5.624.15" fill="#A4AABA"></path>
          <path d="M99.66 278.514l13.378.092s1.298-54.52 1.853-64.403c.554-9.882 3.776-43.364 1.002-63.128l-12.547-.644-22.849.78s-.434 3.966-1.195 9.976c-.063.496-.682.843-.749 1.365-.075.585.423 1.354.32 1.966-2.364 14.08-6.377 33.104-8.744 46.677-.116.666-1.234 1.009-1.458 2.691-.04.302.211 1.525.112 1.795-6.873 18.744-10.949 47.842-14.277 61.885l14.607-.014s2.197-8.57 4.03-16.97c2.811-12.886 23.111-85.01 23.111-85.01l3.016-.521 1.043 46.35s-.224 1.234.337 2.02c.56.785-.56 1.123-.392 2.244l.392 1.794s-.449 7.178-.898 11.89c-.448 4.71-.092 39.165-.092 39.165" fill="#7BB2F9"></path>
          <path d="M76.085 221.626c1.153.094 4.038-2.019 6.955-4.935M106.36 225.142s2.774-1.11 6.103-3.883" stroke="#648BD8" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M107.275 222.1s2.773-1.11 6.102-3.884" stroke="#648BD8" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M74.74 224.767s2.622-.591 6.505-3.365M86.03 151.634c-.27 3.106.3 8.525-4.336 9.123M103.625 149.88s.11 14.012-1.293 15.065c-2.219 1.664-2.99 1.944-2.99 1.944M99.79 150.438s.035 12.88-1.196 24.377M93.673 175.911s7.212-1.664 9.431-1.664M74.31 205.861a212.013 212.013 0 0 1-.979 4.56s-1.458 1.832-1.009 3.776c.449 1.944-.947 2.045-4.985 15.355-1.696 5.59-4.49 18.591-6.348 27.597l-.231 1.12M75.689 197.807a320.934 320.934 0 0 1-.882 4.754M82.591 152.233L81.395 162.7s-1.097.15-.5 2.244c.113 1.346-2.674 15.775-5.18 30.43M56.12 274.418h13.31" stroke="#648BD8" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M116.241 148.22s-17.047-3.104-35.893.2c.158 2.514-.003 4.15-.003 4.15s14.687-2.818 35.67-.312c.252-2.355.226-4.038.226-4.038" fill="#192064"></path>
          <path d="M106.322 151.165l.003-4.911a.81.81 0 0 0-.778-.815c-2.44-.091-5.066-.108-7.836-.014a.818.818 0 0 0-.789.815l-.003 4.906a.81.81 0 0 0 .831.813c2.385-.06 4.973-.064 7.73.017a.815.815 0 0 0 .842-.81" fill="#FFF"></path>
          <path d="M105.207 150.233l.002-3.076a.642.642 0 0 0-.619-.646 94.321 94.321 0 0 0-5.866-.01.65.65 0 0 0-.63.647v3.072a.64.64 0 0 0 .654.644 121.12 121.12 0 0 1 5.794.011c.362.01.665-.28.665-.642" fill="#192064"></path>
          <path d="M100.263 275.415h12.338M101.436 270.53c.006 3.387.042 5.79.111 6.506M101.451 264.548a915.75 915.75 0 0 0-.015 4.337M100.986 174.965l.898 44.642s.673 1.57-.225 2.692c-.897 1.122 2.468.673.898 2.243-1.57 1.57.897 1.122 0 3.365-.596 1.489-.994 21.1-1.096 35.146" stroke="#648BD8" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M46.876 83.427s-.516 6.045 7.223 5.552c11.2-.712 9.218-9.345 31.54-21.655-.786-2.708-2.447-4.744-2.447-4.744s-11.068 3.11-22.584 8.046c-6.766 2.9-13.395 6.352-13.732 12.801M104.46 91.057l.941-5.372-8.884-11.43-5.037 5.372-1.74 7.834a.321.321 0 0 0 .108.32c.965.8 6.5 5.013 14.347 3.544a.332.332 0 0 0 .264-.268" fill="#FFC6A0"></path>
          <path d="M93.942 79.387s-4.533-2.853-2.432-6.855c1.623-3.09 4.513 1.133 4.513 1.133s.52-3.642 3.121-3.642c.52-1.04 1.561-4.162 1.561-4.162s11.445 2.601 13.526 3.121c0 5.203-2.304 19.424-7.84 19.861-8.892.703-12.449-9.456-12.449-9.456" fill="#FFC6A0"></path>
          <path d="M113.874 73.446c2.601-2.081 3.47-9.722 3.47-9.722s-2.479-.49-6.64-2.05c-4.683-2.081-12.798-4.747-17.48.976-9.668 3.223-2.05 19.823-2.05 19.823l2.713-3.021s-3.935-3.287-2.08-6.243c2.17-3.462 3.92 1.073 3.92 1.073s.637-2.387 3.581-3.342c.355-.71 1.036-2.674 1.432-3.85a1.073 1.073 0 0 1 1.263-.704c2.4.558 8.677 2.019 11.356 2.662.522.125.871.615.82 1.15l-.305 3.248z" fill="#520038"></path>
          <path d="M104.977 76.064c-.103.61-.582 1.038-1.07.956-.489-.083-.801-.644-.698-1.254.103-.61.582-1.038 1.07-.956.488.082.8.644.698 1.254M112.132 77.694c-.103.61-.582 1.038-1.07.956-.488-.083-.8-.644-.698-1.254.103-.61.582-1.038 1.07-.956.488.082.8.643.698 1.254" fill="#552950"></path>
          <path stroke="#DB836E" strokeWidth="1.118" strokeLinecap="round" strokeLinejoin="round" d="M110.13 74.84l-.896 1.61-.298 4.357h-2.228"></path>
          <path d="M110.846 74.481s1.79-.716 2.506.537" stroke="#5C2552" strokeWidth="1.118" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M92.386 74.282s.477-1.114 1.113-.716c.637.398 1.274 1.433.558 1.99-.717.556.159 1.67.159 1.67" stroke="#DB836E" strokeWidth="1.118" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M103.287 72.93s1.83 1.113 4.137.954" stroke="#5C2552" strokeWidth="1.118" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M103.685 81.762s2.227 1.193 4.376 1.193M104.64 84.308s.954.398 1.511.318M94.693 81.205s2.308 7.4 10.424 7.639" stroke="#DB836E" strokeWidth="1.118" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M81.45 89.384s.45 5.647-4.935 12.787M69 82.654s-.726 9.282-8.204 14.206" stroke="#E4EBF7" strokeWidth="1.101" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M129.405 122.865s-5.272 7.403-9.422 10.768" stroke="#E4EBF7" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M119.306 107.329s.452 4.366-2.127 32.062" stroke="#E4EBF7" strokeWidth="1.101" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M150.028 151.232h-49.837a1.01 1.01 0 0 1-1.01-1.01v-31.688c0-.557.452-1.01 1.01-1.01h49.837c.558 0 1.01.453 1.01 1.01v31.688a1.01 1.01 0 0 1-1.01 1.01" fill="#F2D7AD"></path>
          <path d="M150.29 151.232h-19.863v-33.707h20.784v32.786a.92.92 0 0 1-.92.92" fill="#F4D19D"></path>
          <path d="M123.554 127.896H92.917a.518.518 0 0 1-.425-.816l6.38-9.113c.193-.277.51-.442.85-.442h31.092l-7.26 10.371z" fill="#F2D7AD"></path>
          <path fill="#CC9B6E" d="M123.689 128.447H99.25v-.519h24.169l7.183-10.26.424.298z"></path>
          <path d="M158.298 127.896h-18.669a2.073 2.073 0 0 1-1.659-.83l-7.156-9.541h19.965c.49 0 .95.23 1.244.622l6.69 8.92a.519.519 0 0 1-.415.83" fill="#F4D19D"></path>
          <path fill="#CC9B6E" d="M157.847 128.479h-19.384l-7.857-10.475.415-.31 7.7 10.266h19.126zM130.554 150.685l-.032-8.177.519-.002.032 8.177z"></path>
          <path fill="#CC9B6E" d="M130.511 139.783l-.08-21.414.519-.002.08 21.414zM111.876 140.932l-.498-.143 1.479-5.167.498.143zM108.437 141.06l-2.679-2.935 2.665-3.434.41.318-2.397 3.089 2.384 2.612zM116.607 141.06l-.383-.35 2.383-2.612-2.397-3.089.41-.318 2.665 3.434z"></path>
          <path d="M154.316 131.892l-3.114-1.96.038 3.514-1.043.092c-1.682.115-3.634.23-4.789.23-1.902 0-2.693 2.258 2.23 2.648l-2.645-.596s-2.168 1.317.504 2.3c0 0-1.58 1.217.561 2.58-.584 3.504 5.247 4.058 7.122 3.59 1.876-.47 4.233-2.359 4.487-5.16.28-3.085-.89-5.432-3.35-7.238" fill="#FFC6A0"></path>
          <path d="M153.686 133.577s-6.522.47-8.36.372c-1.836-.098-1.904 2.19 2.359 2.264 3.739.15 5.451-.044 5.451-.044" stroke="#DB836E" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M145.16 135.877c-1.85 1.346.561 2.355.561 2.355s3.478.898 6.73.617" stroke="#DB836E" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M151.89 141.71s-6.28.111-6.73-2.132c-.223-1.346.45-1.402.45-1.402M146.114 140.868s-1.103 3.16 5.44 3.533M151.202 129.932v3.477M52.838 89.286c3.533-.337 8.423-1.248 13.582-7.754" stroke="#DB836E" strokeWidth="1.051" strokeLinecap="round" strokeLinejoin="round"></path>
          <path d="M168.567 248.318a6.647 6.647 0 0 1-6.647-6.647v-66.466a6.647 6.647 0 1 1 13.294 0v66.466a6.647 6.647 0 0 1-6.647 6.647" fill="#5BA02E"></path>
          <path d="M176.543 247.653a6.647 6.647 0 0 1-6.646-6.647v-33.232a6.647 6.647 0 1 1 13.293 0v33.232a6.647 6.647 0 0 1-6.647 6.647" fill="#92C110"></path>
          <path d="M186.443 293.613H158.92a3.187 3.187 0 0 1-3.187-3.187v-46.134a3.187 3.187 0 0 1 3.187-3.187h27.524a3.187 3.187 0 0 1 3.187 3.187v46.134a3.187 3.187 0 0 1-3.187 3.187" fill="#F2D7AD"></path>
          <path d="M88.979 89.48s7.776 5.384 16.6 2.842" stroke="#E4EBF7" strokeWidth="1.101" strokeLinecap="round" strokeLinejoin="round"></path>
        </g>
      </svg>
    )
  }
}
export default Lostsvg
src/components/resetpwd/index.jsx
New file
@@ -0,0 +1,121 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Input } from 'antd'
class Resetpwd extends Component {
  static propTpyes = {
    dict: PropTypes.object
  }
  state = {
    confirmDirty: false,
    autoCompleteResult: []
  }
  onEnterSubmit = (e) => {
    // 表单回车提交
    if (e.key !== 'Enter') return
    this.props.resetPwdSubmit()
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  handleConfirmBlur = e => {
    const { value } = e.target
    this.setState({ confirmDirty: this.state.confirmDirty || !!value })
  }
  compareToFirstPassword = (rule, value, callback) => {
    const { form } = this.props
    if (value && value !== form.getFieldValue('password')) {
      callback(this.props.dict['header.password.diff'])
    } else {
      callback()
    }
  }
  validateToNextPassword = (rule, value, callback) => {
    const { form } = this.props
    if (value && this.state.confirmDirty) {
      form.validateFields(['confirm'], { force: true })
    }
    callback()
  }
  render() {
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} onKeyDown={this.onEnterSubmit}>
        <Form.Item label={this.props.dict['header.password.origin']}>
          {getFieldDecorator('originpwd', {
            rules: [
              {
                required: true,
                message: this.props.dict['header.password.origin.required']
              }
            ]
          })(<Input.Password />)}
        </Form.Item>
        <Form.Item label={this.props.dict['header.password.new']} hasFeedback>
          {getFieldDecorator('password', {
            rules: [
              {
                required: true,
                message: this.props.dict['header.password.new.required']
              },
              {
                min: 6,
                message: this.props.dict['header.password.minlen']
              },
              {
                max: 12,
                message: this.props.dict['header.password.maxlen']
              },
              {
                validator: this.validateToNextPassword
              }
            ]
          })(<Input.Password />)}
        </Form.Item>
        <Form.Item label={this.props.dict['header.password.confirm']} hasFeedback>
          {getFieldDecorator('confirm', {
            rules: [
              {
                required: true,
                message: this.props.dict['header.password.confirm.required']
              },
              {
                validator: this.compareToFirstPassword
              }
            ]
          })(<Input.Password onBlur={this.handleConfirmBlur} />)}
        </Form.Item>
      </Form>
    )
  }
}
export default Form.create()(Resetpwd)
src/components/sidemenu/index.jsx
File was renamed from src/components/sidemenu/sidemenu.jsx
@@ -1,5 +1,4 @@
import React, {Component} from 'react'
// import { Lifecycle } from 'react-router'
import { withRouter } from 'react-router-dom'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
@@ -7,11 +6,11 @@
import { Menu, Icon } from 'antd'
import {modifyTabview} from '@/store/action'
import Api from '@/api'
import './sidemenu.scss'
import './index.scss'
const { SubMenu } = Menu
class Smenu extends Component {
class Sidemenu extends Component {
  static propTypes = {
    collapse: PropTypes.bool,
    mainMenu: PropTypes.oneOfType([
@@ -29,11 +28,37 @@
  async loadsubmenu (menu) {
    let result = await Api.getSubMenuData(menu.MenuID)
    if (result.status) {
      let param = sessionStorage.getItem('view_param') // 是否为打开新页面
      let msg = sessionStorage.getItem('UserID') + '&' + sessionStorage.getItem('lang')
      let submenuindex = 0 // 展开二级菜单索引
      let tabindex = null // 打开的tab页
      if (param) {
        param = param.split('&')
        submenuindex = parseInt(param[1])
        tabindex = parseInt(param[2])
        sessionStorage.removeItem('view_param')
      }
      this.setState({
        subMenulist: result.data,
        subMenulist: result.data.map((item, i) => {
          if (item.children) {
            item.children = item.children.map((child, n) => {
              let _msg = window.btoa(menu.index + '&' + i + '&' + n + '&' + msg)
              child.src = '#/main/' + _msg
              return child
            })
          }
          return item
        }),
        rootSubmenuKeys: result.data.map(item => item.id),
        openKeys: this.props.collapse ? [] : [result.data[0].id]
        openKeys: this.props.collapse ? [] : [result.data[submenuindex].id]
      })
      if (tabindex !== null) {
        let opentab = result.data[submenuindex].children[tabindex]
        opentab.selected = true
        this.props.modifyTabview([opentab])
      }
    }
  }
@@ -47,24 +72,7 @@
    menu.selected = true
    tabs.push(menu)
    this.props.modifyTabview(tabs)
    // this.props.history.push('/main')
    // this.props.history.replace('/main')
    e.preventDefault()
  }
  // mixins = [ Lifecycle ]
  routerWillLeave(nextLocation) {
    if (!this.state.isSaved)
      return 'Your work is not saved! Are you sure you want to leave?'
  }
  componentDidMount () {
  }
  UNSAFE_componentWillMount () {
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
@@ -88,10 +96,6 @@
    }
  }
  componentDidUpdate () {
    // console.log('componentDidUpdate')
  }
  onOpenChange = openKeys => {
    const latestOpenKey = openKeys.find(key => this.state.openKeys.indexOf(key) === -1)
    if (this.state.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
@@ -104,7 +108,7 @@
  }
  render () {
    return (
      <aside className={"side-menu ant-menu-dark" + (this.props.collapse ? ' side-menu-collapsed' : '')}>
      <aside className={"side-menu ant-menu-dark" + (this.props.collapse ? ' side-menu-collapsed' : '') + (this.props.isiframe ? ' iframe' : '')}>
        {this.state.subMenulist &&
          <Menu openKeys={this.state.openKeys} onOpenChange={this.onOpenChange} mode="inline" theme="dark" inlineCollapsed={this.props.collapse}>
          {this.state.subMenulist.map(item => {
@@ -121,7 +125,7 @@
                {item.children.map(cell => {
                  return (
                    <Menu.Item key={cell.id}>
                      <a href="#/main/0345" id={cell.MenuID} data-item={JSON.stringify(cell)} onClick={this.changemenu.bind(this)}>{cell.MenuName}</a>
                      <a href={cell.src} id={cell.MenuID} data-item={JSON.stringify(cell)} onClick={this.changemenu.bind(this)}>{cell.MenuName}</a>
                    </Menu.Item>
                  )
                })}
@@ -138,6 +142,7 @@
  return {
    tabviews: state.tabviews,
    collapse: state.collapse,
    isiframe: state.isiframe,
    mainMenu: state.selectedMainMenu
  }
}
@@ -148,4 +153,4 @@
  }
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Smenu))
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Sidemenu))
src/components/sidemenu/index.scss
File was renamed from src/components/sidemenu/sidemenu.scss
@@ -5,7 +5,6 @@
.side-menu {
  flex: 0 0 235px;
  width: 235px;
  height: 100%;
  padding: 48px 0 20px;
  transition: width 0.2s, flex 0.2s;
  .ant-menu-item {
@@ -15,7 +14,9 @@
      padding-left: 48px;
    }
  }
}
.side-menu.iframe {
  height: 100%;
  max-height: 100vh;
  overflow-y: scroll;
  &::-webkit-scrollbar {
src/components/tabview/index.jsx
New file
@@ -0,0 +1,149 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import {Tabs, Icon} from 'antd'
import {modifyTabview, toggleIsiframe} from '@/store/action'
import asyncComponent from '@/utils/asyncComponent'
import NotFount from '@/components/404'
import './index.scss'
let Comps = {}
class Header extends Component {
  static propTpyes = {
    tabviews: PropTypes.array // 标签页数组
  }
  state = {
    selectedTabId: '', // 当前选中tab页面
    iFrameHeight: 0
  }
  handleTabview (menu) {
    // 关闭tab页,重新选择显示页
    let tabs = JSON.parse(JSON.stringify(this.props.tabviews))
    tabs = tabs.filter(tab => {
      if (tab.MenuID === this.state.selectedTabId) {
        tab.selected = true
      } else {
        tab.selected = false
      }
      return tab.MenuID !== menu.MenuID
    })
    if (menu.MenuID === this.state.selectedTabId) {
      tabs[0] && (tabs[0].selected = true)
    }
    this.props.modifyTabview(tabs)
  }
  changeTab (menu) {
    // 窗口切换
    this.setState({
      selectedTabId: menu.MenuID
    })
    this.resetWindow(menu)
  }
  selectcomponent (view) {
    // 根据tab页中菜单信息,选择所需的组件
    if (view.Remark === 'CommonTable') {
      return (<Comps.CommonTable MenuNo={view.MenuNo} key={view.MenuID}/>)
    } else if (view.LinkUrl.split('?')[0] === 'Main/Index') {
      return (<Comps.Iframe key={view.MenuID} title={view.MenuName} url={'http://qingqiumarket.cn/MKWMS/zh-CN/' + view.LinkUrl}/>)
    } else {
      return (<NotFount key={view.MenuID} />)
    }
  }
  resetWindow (view) {
    // 窗口在iframe与普通页面切换时,修改左侧菜单栏样式
    if (!view) return
    let _isiframe = this.props.isiframe
    if (view && view.Remark === 'CommonTable') {
      _isiframe = false
    } else if (view && view.LinkUrl.split('?')[0] === 'Main/Index') {
      _isiframe = true
    } else {
      _isiframe = false
    }
    if (_isiframe !== this.props.isiframe) {
      this.props.toggleIsiframe(_isiframe)
    }
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (nextProps.tabviews && !is(fromJS(this.props.tabviews), fromJS(nextProps.tabviews))) {
      // tab窗口页增加或删除
      if (nextProps.tabviews.length > this.props.tabviews.length) {
        // 查看新tab页需要组件是否加载
        let newtab = nextProps.tabviews[nextProps.tabviews.length - 1]
        if (!Comps.CommonTable && newtab.Remark === 'CommonTable') {
          Comps.CommonTable = asyncComponent(() => import('@/tabviews/commontable'))
        } else if (!Comps.Iframe && newtab.LinkUrl.split('?')[0] === 'Main/Index') {
          Comps.Iframe = asyncComponent(() => import('@/tabviews/iframe'))
        }
      }
      // 设置选中窗口
      let view = nextProps.tabviews.filter(tab => tab.selected)[0]
      this.setState({
        selectedTabId: view ? view.MenuID : ''
      })
      this.resetWindow(view)
    }
  }
  shouldComponentUpdate(nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  render () {
    return (
      <section className="flex-container content-box">
        <div className="content-header">
          {this.props.tabviews && this.props.tabviews.length > 0 &&
            <Tabs activeKey={this.state.selectedTabId}>
              {this.props.tabviews.map(view => {
                return (
                  <Tabs.TabPane
                    className="test"
                    tab={
                      <span>
                        <span className="tab-name" onClick={() => {this.changeTab(view)}}>
                          {view.MenuName}
                        </span>
                        <Icon type="close" onClick={() => {this.handleTabview(view)}}/>
                      </span>
                    }
                    key={view.MenuID}
                  >
                    {this.selectcomponent(view)}
                  </Tabs.TabPane>
                )
              })}
            </Tabs>
          }
        </div>
      </section>
    )
  }
}
const mapStateToProps = (state) => {
  return {
    tabviews: state.tabviews,
    isiframe: state.isiframe
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)),
    toggleIsiframe: (isiframe) => dispatch(toggleIsiframe(isiframe))
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(Header)
src/components/tabview/index.scss
src/components/tabview/tabview.jsx
File was deleted
src/index.js
@@ -1,5 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import React from 'react'
import ReactDOM from 'react-dom'
import Route from './router'
import {Provider} from 'react-redux'
import store from '@/store'
@@ -18,4 +18,4 @@
render(Route)
serviceWorker.unregister();
serviceWorker.unregister()
src/locales/en-US/header.js
New file
@@ -0,0 +1,17 @@
export default {
  'header.confirm': 'Ok',
  'header.cancel': 'Cancel',
  'header.logout': 'Logout',
  'header.logout.hint': 'Are you sure you want to log out?',
  'header.password': 'Change the password',
  'header.password.origin': 'Original Password',
  'header.password.origin.required': 'Please input your original password!',
  'header.password.new': 'Password',
  'header.password.new.required': 'Please input your password!',
  'header.password.confirm': 'Confirm Password',
  'header.password.confirm.required': 'Please confirm your password!',
  'header.password.minlen': 'The minimum password length is 6 digits!',
  'header.password.maxlen': 'The maximum password length is 12 bits!',
  'header.password.diff': 'Two passwords that you enter is inconsistent!',
  'header.password.resetsuccess': 'Password modified successfully!'
}
src/locales/en-US/login.js
New file
@@ -0,0 +1,9 @@
export default {
  'login.username': 'Username',
  'login.username.empty': 'Please input your username!',
  'login.password': 'Password',
  'login.password.empty': 'Please input your Password!',
  'login.remember': 'Remember me',
  'login.submit': 'Log in',
  'login.copyright': 'Copyrights by'
}
src/locales/zh-CN/header.js
New file
@@ -0,0 +1,17 @@
export default {
  'header.confirm': '确定',
  'header.cancel': '取消',
  'header.logout': '退出',
  'header.logout.hint': '您确定要退出吗?',
  'header.password': '修改密码',
  'header.password.origin': '原密码',
  'header.password.origin.required': '请输入原密码!',
  'header.password.new': '新密码',
  'header.password.new.required': '请输入新密码!',
  'header.password.confirm': '确认密码',
  'header.password.confirm.required': '请确认密码!',
  'header.password.minlen': '最小密码长度为6位!',
  'header.password.maxlen': '最大密码长度为12位!',
  'header.password.diff': '两次输入密码不一致!',
  'header.password.resetsuccess': '密码修改成功!'
}
src/locales/zh-CN/login.js
New file
@@ -0,0 +1,9 @@
export default {
  'login.username': '用户名',
  'login.username.empty': '请输入用户名!',
  'login.password': '密码',
  'login.password.empty': '请输入密码!',
  'login.remember': '记住密码',
  'login.submit': '登录',
  'login.copyright': '所有相关版权归'
}
src/router/index.js
@@ -1,37 +1,61 @@
import React, {Component} from 'react'
import {HashRouter, Switch, Route, Redirect} from 'react-router-dom'
import asyncComponent from '@/utils/asyncComponent'
const personal = asyncComponent(() => import('@/views/personal/personal'))
const main = asyncComponent(() => import('@/views/main'))
const login = asyncComponent(() => import('@/views/login'))
const NotFound = asyncComponent(() => import('@/views/404'))
const routers = [
  {path: '/login', name: 'login', component: login, auth: false},
  {path: '/main', name: 'main', component: main, auth: true},
  {path: '/main/:param', name: 'pmain', component: main, auth: true}
]
export default class RouteConfig extends Component {
  controlRoute (item, props) {
    if (!item.auth) { // 不需要授权,直接跳转(登录页)
      return (<item.component {...props}/>)
    }
    if (item.name === 'pmain') { // 新窗口打开,取url参数放入sessionStorage
      let _param = window.atob(props.match.params.param)
      sessionStorage.setItem('view_param', _param)
      return (<Redirect to={{ pathname: '/main'}}/>)
    }
    let userId = sessionStorage.getItem('UserID')
    if (userId) {
      return (<item.component {...props}/>)
    } else {
      let param = sessionStorage.getItem('view_param')
      if (param) {
        param = param.split('&')
        sessionStorage.setItem('UserID', param[3])
        sessionStorage.setItem('lang', param[4])
        return (<item.component {...props}/>)
      } else {
        return (<Redirect to={{ pathname: '/login', state: {from: props.location}}}/>)
      }
    }
  }
  render () {
    return (
      <HashRouter>
        <Switch>
          <Route path="/main" exact component={personal}/>
          <Route path="/main/:param" exact component={personal}/>
          {
            routers.map((item, index) => {
              return (
                <Route key={index} path={item.path} name={item.name} exact render={ props => {
                  return this.controlRoute(item, props)
                }}/>
              )
            })
          }
          <Redirect exact from="/" to="main"/>
          <Route component= {personal}/>
          <Route component= {NotFound}/>
        </Switch>
      </HashRouter>
    )
  }
}
// import React, { lazy } from 'react';
// import { Route } from 'react-router-dom';
// const RouteLis = [
//   {
//     component: lazy(() => import ('../views/home')),
//     path: '/'
//   }
// ];
// const RouterList = () => (
//   RouteLis.map((item, key) => {
//     return <Route key={key} exact path={item.path} component={item.component}/>;
//   })
// );
// export default RouterList;
}
src/store/action-type.js
@@ -5,4 +5,10 @@
export const Toggle_COLLAPSE = 'Toggle_COLLAPSE'
// 修改导航栏菜单
export const MODIFY_TABVIEW = 'MODIFY_TABVIEW'
export const MODIFY_TABVIEW = 'MODIFY_TABVIEW'
// 修改窗口样式,区分iframe与正常页面
export const TOGGLE_ISIFRAME = 'TOGGLE_ISIFRAME'
// 退出系统时参数重置
export const RESET_STATE = 'RESET_STATE'
src/store/action.js
@@ -23,3 +23,18 @@
    tabviews
  }
}
// 修改窗口样式,区分iframe与正常页面
export const toggleIsiframe = (isiframe) => {
  return {
    type: user.TOGGLE_ISIFRAME,
    isiframe
  }
}
// 退出系统时参数重置
export const resetState = () => {
  return {
    type: user.RESET_STATE
  }
}
src/store/reducer.js
@@ -3,7 +3,8 @@
let defaultState = {
  selectedMainMenu: '', // 已选主菜单
  tabviews: [], // 导航栏
  collapse: false // 是否收起侧边栏导航
  collapse: false, // 是否收起侧边栏导航
  isiframe: false // 是否为iframe窗口
}
// 用户消息
@@ -24,6 +25,21 @@
        ...state,
        tabviews: action.tabviews
      }
    case Type.TOGGLE_ISIFRAME:
      return {
        ...state,
        isiframe: action.isiframe
      }
    case Type.RESET_STATE:
      return {
        ...state,
        ...{
          selectedMainMenu: '',
          tabviews: [],
          collapse: false,
          isiframe: false
        }
      }
    default:
      return state
  }
src/tabviews/commontable/index.jsx
New file
@@ -0,0 +1,66 @@
import React, {Component} from 'react'
import { Form, Row, Col, Input, Button } from 'antd'
import './index.scss'
class AdvancedSearchForm extends React.Component {
  state = {
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const children = []
    for (let i = 0; i < 10; i++) {
      children.push(
        <Col span={6} key={i}>
          <Form.Item label={`菜单名称开始`}>
            {getFieldDecorator(`field-${i}`)(<Input placeholder="placeholder" />)}
          </Form.Item>
        </Col>
      )
    }
    return children
  }
  handleSearch = e => {
    e.preventDefault()
    this.props.form.validateFields((err, values) => {
      console.log('Received values of form: ', values)
    })
  }
  handleReset = () => {
    this.props.form.resetFields()
  }
  render() {
    return (
      <Form className="ant-advanced-search-form" onSubmit={this.handleSearch}>
        <Row gutter={24}>{this.getFields()}</Row>
        <Row>
          <Col span={24} style={{ textAlign: 'right' }}>
            <Button type="primary" htmlType="submit">
              搜索
            </Button>
            <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
              重置
            </Button>
          </Col>
        </Row>
      </Form>
    )
  }
}
const WrappedAdvancedSearchForm = Form.create()(AdvancedSearchForm)
export default class NormalTable extends Component {
  render() {
    return (
      <div>
        <WrappedAdvancedSearchForm />
        <div className="search-result-list">Search Result List</div>
      </div>
    )
  }
}
src/tabviews/commontable/index.scss
New file
@@ -0,0 +1,18 @@
.ant-advanced-search-form {
  padding: 0px 24px 20px;
  border-bottom: 1px solid #d9d9d9;
  // border-radius: 6px;
}
.ant-advanced-search-form .ant-form-item {
  display: flex;
  margin-bottom: 10px;
}
.ant-advanced-search-form .ant-form-item-control-wrapper {
  flex: 1;
}
.ant-form-item-label {
  width: 100px;
}
src/tabviews/iframe/index.jsx
New file
@@ -0,0 +1,20 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
class Iframe extends Component {
  static propTypes = {
    title: PropTypes.string,
    url: PropTypes.string
  }
  render () {
    return (
      <iframe
        title={this.props.title}
        src={this.props.url}
      />
    )
  }
}
export default Iframe
src/views/404/index.jsx
New file
@@ -0,0 +1,29 @@
import React, {Component} from 'react'
import { withRouter } from 'react-router-dom'
import Lostsvg from '@/components/lostsvg'
import './index.scss'
class NotFound extends Component {
  tomain () {
    this.props.history.replace('/main')
  }
  render () {
    return (
      <main className="ant-pro-basicLayout-content ant-layout-content">
        <div className="ant-result">
          <div className="ant-result-icon ant-result-image">
            <Lostsvg />
          </div>
          <div className="ant-result-title">404</div>
          <div className="ant-result-subtitle">抱歉,你访问的页面不存在,请联系管理员。</div>
          <div className="ant-result-extra">
            <button type="button" onClick={() => {this.tomain()}} className="ant-btn ant-btn-primary"><span>返回主页</span></button>
          </div>
        </div>
      </main>
    )
  }
}
export default withRouter(NotFound)
src/views/404/index.scss
src/views/login/index.jsx
New file
@@ -0,0 +1,161 @@
import React, {Component} from 'react'
import { Form, Icon, Input, Button, Checkbox, Dropdown, Menu, message } from 'antd'
import md5 from 'md5'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/login.js'
import enUS from '@/locales/en-US/login.js'
import logourl from '../../assets/img/login-logo.png'
import './index.scss'
class Login extends Component {
  state = {
    langs: [{
      name: '中文简体',
      value: 'zh-CN'
    }, {
      name: 'English',
      value: 'en-US'
    }],
    selectedlang: {
      name: '中文简体',
      value: 'zh-CN'
    },
    dict: zhCN,
    isDisabled: false
  }
  changelang (item) {
    // 切换语言
    this.setState({
      selectedlang: item,
      dict: item.value === 'zh-CN' ? zhCN : enUS
    })
  }
  md5Password (pwd) {
    // md5密码加密
    const salt = 'minkesoft'
    return md5(md5(pwd + salt))
  }
  handleSubmit = e => {
    // 登录参数检验
    e.preventDefault()
    this.props.form.validateFields((err, values) => {
      if (err) return
      this.setState({
        isDisabled: true
      })
      this.loginsubmit(values)
    })
  }
  async loginsubmit (param) {
    // 登录提交
    let password = this.md5Password(param.password)
    let result = await Api.loginsystem(param.username, password)
    if (result.status) {
      sessionStorage.setItem('UserID', result.userid)
      sessionStorage.setItem('lang', this.state.selectedlang.value)
      if (param.remember) { // 记住密码时账号密码存入localStorage
        localStorage.setItem('username', param.username)
        localStorage.setItem('password', param.password)
      } else {
        localStorage.removeItem('username')
        localStorage.removeItem('password')
      }
      if (this.props.location.state && this.props.location.state.from.pathname) {
        // 查看是否为其他页面跳转,路径存在时,跳回原页面
        this.props.history.replace(this.props.location.state.from.pathname)
      } else {
        this.props.history.replace('/main')
      }
    } else {
      message.warning(result.message)
      this.setState({
        isDisabled: false
      })
    }
  }
  render () {
    const { getFieldDecorator } = this.props.form
    const menu = (
      <Menu>
        {this.state.langs.map((item, index) => {
          return (
            <Menu.Item key={index} onClick={() => {this.changelang(item)}}>
              <span>{item.name}</span>
            </Menu.Item>
          )
        })}
      </Menu>
    )
    return (
      <div className="login-container">
        <div className="logo">
          <img src={logourl} alt=""/>
        </div>
        <div className="login-middle">
          <Form onSubmit={this.handleSubmit} className="login-form">
            <h4>明科商业智能开放平台</h4>
            <Form.Item>
              {getFieldDecorator('username', {
                rules: [{ required: true, message: this.state.dict['login.username.empty'] }],
                initialValue: localStorage.getItem('username') || '',
              })(
                <Input
                  prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
                  placeholder={this.state.dict['login.username']}
                />,
              )}
            </Form.Item>
            <Form.Item>
              {getFieldDecorator('password', {
                rules: [{ required: true, message: this.state.dict['login.password.empty'] }],
                initialValue: localStorage.getItem('password') || '',
              })(
                <Input
                  prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
                  type="password"
                  placeholder={this.state.dict['login.password']}
                />,
              )}
            </Form.Item>
            <Form.Item className="minline">
              {getFieldDecorator('remember', {
                valuePropName: 'checked',
                initialValue: true,
              })(<Checkbox>{this.state.dict['login.remember']}</Checkbox>)}
              <Dropdown overlay={menu} trigger={['click']} placement="bottomRight">
                <span className="ant-dropdown-link">
                  {this.state.selectedlang.name} <Icon type="down" />
                </span>
              </Dropdown>
            </Form.Item>
            <Form.Item>
              <Button type="primary" htmlType="submit" className="login-form-button" disabled={this.state.isDisabled}>
                {this.state.dict['login.submit']}
              </Button>
            </Form.Item>
          </Form>
        </div>
        <div className="login-bottom">
          <p>
            <span className="split">Copyright©2017</span>
            <span className="split">{this.state.dict['login.copyright']}</span>
            <span>北京明科普华信息技术有限公司</span>
          </p>
          <p>
            <span>ICP备案:</span>
            <span>京ICP备12007830号</span>
          </p>
        </div>
      </div>
    )
  }
}
export default Form.create()(Login)
src/views/login/index.scss
New file
@@ -0,0 +1,60 @@
.login-container {
  height: 100vh;
  min-height: 600px;
  background: #000000;
  .logo {
    height: 100px;
    padding-top: 30px;
    border-bottom: 2px solid #06b4f7;
    img {
      max-height: 100%;
    }
  }
  .login-middle {
    height: calc(100vh - 194px);
    min-height: 420px;
    background: url('../../assets/img/loginbg.png');
    background-size: cover;
    background-position: center center;
    border-bottom: 2px solid #06b4f7;
    .login-form {
      float: right;
      margin-top: 5%;
      margin-right: 20%;
      padding: 15px;
      background: #ffffff;
      width: 300px;
      border-radius: 5px;
      h4 {
        font-size: 18px;
        font-weight: bold;
        color: #0A95CB;
      }
      .minline {
        margin-bottom: 10px;
        margin-top: -10px;
      }
      button {
        width: 100%;
        height: 40px;
        line-height: 40px;
      }
      .ant-dropdown-link {
        float: right;
        cursor: pointer;
        line-height: 20px;
        margin-top: 10px;
      }
    }
  }
  .login-bottom {
    text-align: center;
    color: #ffffff;
    padding-top: 20px;
    p span.split {
      margin-right: 15px;
    }
  }
}
src/views/main/index.jsx
New file
@@ -0,0 +1,19 @@
import React, {Component} from 'react'
import Header from '@/components/header'
import Sidemenu from '@/components/sidemenu'
import Tabview from '@/components/tabview'
import './index.scss'
class Main extends Component {
  render () {
    return (
      <div className="flex-container">
        <Header key="header"/>
        <Sidemenu key="sidemenu"/>
        <Tabview key="tabview"/>
      </div>
    )
  }
}
export default Main
src/views/main/index.scss
New file
@@ -0,0 +1,5 @@
.flex-container {
  display: flex;
  flex: auto;
  height: 100%;
}
src/views/personal/personal.jsx
File was deleted
src/views/personal/personal.scss
File was deleted