king
2023-06-07 8ed1e158001e1a3f6f988c2037f7ef6f82df343d
2023-06-07
7个文件已修改
404 ■■■■ 已修改文件
public/options.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/changeuserbutton/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.scss 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/loginform.jsx 223 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/options.json
@@ -11,12 +11,12 @@
  "WXAppID": "",
  "WXminiAppID": "",
  "WXNotice": "false",
  "nginx": "true",
  "nginx": "false",
  "debugger": true,
  "licenseKey": "",
  "probation": "",
  "transfer": true,
  "keepPassword": "true",
  "keepPassword": "false",
  "platforms": ["H5", "wechat", "android", "ios", "wxMiniProgram"],
  "host": "http://bms-test.kresstools.cn",
  "service": "oc/"
src/api/index.js
@@ -53,7 +53,6 @@
    localStorage.removeItem('debug')
    localStorage.removeItem('role_id')
    localStorage.removeItem('mk_user_type')
    localStorage.removeItem('localRole_id')
    sessionStorage.clear()
    sessionStorage.setItem('loginError', JSON.stringify({url: res.config ? res.config.url : '', request: res.config ? res.config.data : '', response: JSON.stringify(res.data)}))
src/index.js
@@ -57,7 +57,6 @@
sessionStorage.setItem('departmentcode', localStorage.getItem('departmentcode') || '')
sessionStorage.setItem('organization', localStorage.getItem('organization') || '')
sessionStorage.setItem('mk_user_type', localStorage.getItem('mk_user_type') || '')
sessionStorage.setItem('localRole_id', localStorage.getItem('localRole_id') || '')
sessionStorage.setItem('lang', 'zh-CN')
if (sessionStorage.getItem('loginError')) {
src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -190,7 +190,6 @@
              // sessionStorage.setItem('debug', res.debug || '')
              // sessionStorage.setItem('role_id', res.role_id || '')
              // sessionStorage.setItem('mk_user_type', res.mk_user_type || '')
              // sessionStorage.setItem('localRole_id', res.role_id || '')
              localStorage.setItem('UserID', res.UserID)
              localStorage.setItem('LoginUID', res.LoginUID)
@@ -204,7 +203,6 @@
              localStorage.setItem('departmentcode', res.departmentcode || '')
              localStorage.setItem('organization', res.organization || '')
              localStorage.setItem('mk_user_type', res.mk_user_type || '')
              localStorage.setItem('localRole_id', res.role_id || '')
              
              sessionStorage.removeItem('CloudAvatar')
              sessionStorage.removeItem('cloudDataM')
src/views/login/index.jsx
@@ -5,7 +5,7 @@
import Api from '@/api'
import Utils from '@/utils/utils.js' 
// import MKEmitter from '@/utils/events.js'
import MKEmitter from '@/utils/events.js'
import options, { styles } from '@/store/options.js'
import zhCN from '@/locales/zh-CN/login.js'
import enUS from '@/locales/en-US/login.js'
@@ -52,7 +52,6 @@
    localStorage.removeItem('localDataM')
    localStorage.removeItem('debug')
    localStorage.removeItem('role_id')
    localStorage.removeItem('localRole_id')
    sessionStorage.clear()
  }
@@ -112,19 +111,36 @@
      localStorage.setItem('departmentcode', res.departmentcode || '')
      localStorage.setItem('organization', res.organization || '')
      localStorage.setItem('mk_user_type', res.mk_user_type || '')
      localStorage.setItem('localRole_id', res.role_id || '')
      localStorage.setItem('lang', 'zh-CN')
      let _url = window.location.href.split('#')[0]
      sessionStorage.setItem('UserID', res.UserID)
      sessionStorage.setItem('LoginUID', res.LoginUID)
      sessionStorage.setItem('User_Name', res.UserName)
      sessionStorage.setItem('Full_Name', res.FullName)
      sessionStorage.setItem('avatar', res.icon || '')
      sessionStorage.setItem('dataM', res.dataM ? 'true' : '')
      sessionStorage.setItem('debug', res.debug || '')
      sessionStorage.setItem('role_id', res.role_id || '')
      sessionStorage.setItem('departmentcode', res.departmentcode || '')
      sessionStorage.setItem('organization', res.organization || '')
      sessionStorage.setItem('mk_user_type', res.mk_user_type || '')
      // 记住密码时账号密码存入localStorage
      localStorage.setItem(_url, window.btoa(window.encodeURIComponent(JSON.stringify({username: param.username, password: param.password}))))
      if (res.paas_externalDatabase) {
        sessionStorage.setItem('externalDatabase', res.paas_externalDatabase)
        window.GLOB.externalDatabase = `[${res.paas_externalDatabase}]..`
      }
      let _param = {
        UserName: param.username,
        Password: param.password,
        BasePath: '/'
      localStorage.setItem(_href + 'lang', param.lang || 'zh-CN')
      sessionStorage.setItem('lang', param.lang || 'zh-CN')
      sessionStorage.removeItem('visitorUserID')
      sessionStorage.removeItem('visitorLoginUID')
      if (param.remember) { // 记住密码时账号密码存入localStorage
        localStorage.setItem(_href, window.btoa(window.encodeURIComponent(JSON.stringify({username: param.username, password: param.password}))))
      } else {
        localStorage.removeItem(_href)
      }
      
      // positecgroup
@@ -137,19 +153,47 @@
        return
      }
      sessionStorage.setItem('UserID', res.UserID)
      sessionStorage.setItem('LoginUID', res.LoginUID)
      sessionStorage.setItem('User_Name', res.UserName)
      sessionStorage.setItem('Full_Name', res.FullName)
      sessionStorage.setItem('avatar', res.icon || '')
      sessionStorage.setItem('dataM', res.dataM ? 'true' : '')
      sessionStorage.setItem('localDataM', res.dataM ? 'true' : '')
      sessionStorage.setItem('debug', res.debug || '')
      sessionStorage.setItem('role_id', res.role_id || '')
      sessionStorage.setItem('mk_user_type', res.mk_user_type || '')
      sessionStorage.setItem('localRole_id', res.role_id || '')
      let level = localStorage.getItem(_href + 'pwdlevel')
      if (level && process.env.NODE_ENV === 'production') {
        let visible = false
        let tip = '密码强度不够,请修改密码!'
        if (param.password.length < 8) {
          visible = true
        } else if (level === 'letter_num' && /^([^0-9]*|[^a-zA-Z]*)$/.test(param.password)) {
          visible = true
        } else if ((level === 'char_num' || level === 'char_num_90' || level === 'char_num_90_sms') && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(param.password)) {
          visible = true
        } else if ((level === 'char_num_90' || level === 'char_num_90_sms') && res.modifydate) {
          let s = (new Date().getTime() - new Date(res.modifydate).getTime()) / (1000 * 24 * 60 * 60)
          if (!isNaN(s) && s > 90) {
            visible = true
            tip = '您已90天未修改密码,请更换密码后使用!'
          }
        }
        if (visible) {
          message.warning(tip)
          this.setState({
            isDisabled: false
          })
          MKEmitter.emit('resetpassword', () => {
            const input = document.getElementById('password')
            if (input) {
              input.select()
            }
          })
          return
        }
      }
      if (process.env.NODE_ENV === 'production') {
        let _param = {
          UserName: param.username,
          Password: param.password,
          BasePath: '/'
        }
        Api.loginAndRedirect(_param).then(result => {
          if (result.IsError) {
            this.setState({
@@ -164,6 +208,7 @@
      } else {
        this.props.history.replace('/main')
      }
      this.props.history.replace('/main')
    } else if (res.ErrCode === 'Need_Get_Appkey' && options.sysType === 'SSO') {
      message.warning('应用尚未创建,请向云端同步应用!')
@@ -561,6 +606,26 @@
            res.indexlogo = res.indexlogo ? res.indexlogo.replace(/:8080/ig, '').replace(/http:/ig, 'https:') : ''
            res.loginlogo = res.loginlogo ? res.loginlogo.replace(/:8080/ig, '').replace(/http:/ig, 'https:') : ''
            // if (options.sysType === 'local' && window.GLOB.systemType !== 'production') {
            //   if (md5(('mk' + window.GLOB.appkey + res.sys_datetime + res.member_type + res.registry_date).toLowerCase()) !== res.secret_key) {
            //     Modal.warning({
            //       title: '密钥错误,请联系管理员!',
            //       okText: '知道了'
            //     })
            //     this.setState({
            //       auth: false,
            //       authError: '密钥错误,请联系管理员!'
            //     })
            //     return
            //   } else if (res.member_type === 'personal' && res.registry_date) {
            //     let saveDelay = 0
            //     try {
            //       saveDelay = parseInt((new Date().getTime() - new Date(res.registry_date).getTime()) / 4320000)
            //       sessionStorage.setItem('mkDelay', saveDelay)
            //     } catch(e) {}
            //   }
            // }
            if (!['shutter', 'linkage_navigation', 'linkage', 'menu_board', 'menu_board_navigation'].includes(res.menu_type)) {
              res.menu_type = 'shutter'
            }
@@ -876,14 +941,15 @@
  }
  render () {
    const { lineColor, loginlogo, bgImage, copyRight, webSite, ICP, loginWays, touristLogin } = this.state
    const { lineColor, bgImage, loginlogo, copyRight, webSite, ICP, loginWays, touristLogin } = this.state
    return (
      <div className="login-container" id="mk-login-view">
      <div className="login-container" id="mk-login-view" style={bgImage ? {backgroundImage: 'url(' + bgImage + ')'} : {}}>
        <div className="logo" style={lineColor ? {borderColor: lineColor} : {}}>
          {loginlogo ? <img src={loginlogo} alt=""/> : null}
          {this.state.platName ? <p className="plat-name">{this.state.platName}</p> : null}
        </div>
        <div className="login-middle" style={bgImage ? {backgroundImage: 'url(' + bgImage + ')'} : null}>
        <div className="login-middle" style={lineColor ? {borderColor: lineColor} : {}}>
          {loginWays ? <LoginForm
            platName={this.state.platName}
            dict={this.state.dict}
src/views/login/index.scss
@@ -1,18 +1,18 @@
.login-container {
  height: 100vh;
  min-height: 600px;
  background-color: #ffffff!important;
  background-color: var(--mk-sys-background);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center center;
  .logo {
    position: relative;
    height: 70px;
    padding-top: 10px;
    width: 990px;
    margin: 0 auto;
    height: 100px;
    padding-top: 30px;
    line-height: 80px;
    border-bottom: 2px solid var(--mk-sys-color);
    img {
      height: 47px;
      max-height: 100%;
    }
    .plat-name {
      position: absolute;
@@ -29,17 +29,30 @@
  .login-middle {
    position: relative;
    height: calc(100vh - 194px);
    min-height: 475px;
    background-color: #427CAA;
    background-image: url('http://bms-test.kresstools.cn/Content/images/login2/bg_mid.png');
    background-size: contain;
    background-repeat: no-repeat;
    min-height: 420px;
    background-size: cover;
    background-position: center center;
    border-bottom: 2px solid var(--mk-sys-color);
    .login-form-button {
      background-color: var(--mk-sys-color);
      border-color: var(--mk-sys-color);
    }
    .login-form-button[disabled] {
      background-color: var(--mk-sys-color5);
      border-color: var(--mk-sys-color5);
    }
    .login-way-wrap {
      .login-way.active, .login-way:hover {
        color: var(--mk-sys-color);
      }
    }
    .login-form {
      position: relative;
      float: right;
      margin-top: 6%;
      margin-top: 5%;
      margin-right: 20%;
      background: #ffffff;
      width: 22vw;
@@ -100,14 +113,8 @@
        margin: 0 1.6vw 0 10px;
      }
      .form-item-wrap {
        padding: 0.6vw 1.6vw 1.6vw;
        // padding: 0.6vw 1.6vw 0vw;
      }
      .title {
        color: #427CAA;
        font-size: 22px;
        font-weight: bold;
        margin: 20px 1.6vw 5px;
        // padding: 0.6vw 1.6vw 1.6vw;
        padding: 0.6vw 1.6vw 0vw;
      }
      h4 {
@@ -199,7 +206,6 @@
        font-size: 16px;
        height: calc(2vw + 5px);
        min-height: 30px;
        border-radius: 0;
      }
      .ant-form label {
        font-size: 16px;
@@ -210,11 +216,6 @@
      .anticon-eye {
        color: var(--mk-sys-color);
      }
      .login-form-button {
        border-radius: 0;
        background: #6fb3e9!important;
        border: 1px solid #6fb3e9!important;
      }
    }
    .login-sync-button {
      position: absolute;
@@ -224,17 +225,15 @@
  }
  .login-bottom {
    text-align: center;
    color: #666!important;
    color: var(--mk-sys-font-color);
    padding-top: 20px;
    font: 12px/150% Arial,Verdana,"\5b8b\4f53";
    p span.split {
      margin-right: 15px;
    }
    a {
      display: inline-block;
      margin-bottom: 5px;
      color: #666!important;
      font: 12px/150% Arial,Verdana,"\5b8b\4f53";
      color: var(--mk-sys-font-color);
    }
  }
  .ant-btn-primary[disabled] {
src/views/login/loginform.jsx
@@ -1,25 +1,29 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Icon, Input, Button, Modal, message } from 'antd'
import { UserOutlined } from '@ant-design/icons'
import { Form, Input, Button, Checkbox, Select, Modal, message } from 'antd'
import { UserOutlined, LockOutlined, QrcodeOutlined, RedoOutlined } from '@ant-design/icons'
import md5 from 'md5'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import options from '@/store/options.js'
import asyncLoadComponent from '@/utils/asyncLoadComponent'
import './index.scss'
const { warning } = Modal
let LoginVerCodeTimer = null
const QrCode = asyncLoadComponent(() => import('@/components/qrcode'))
class LoginTabForm extends Component {
  static propTpyes = {
    isDisabled: PropTypes.bool,
    changelang: PropTypes.func,
    handleSubmit: PropTypes.func,
    authLogin: PropTypes.func,
    dict: PropTypes.object,
    auth: PropTypes.bool,
    authError: PropTypes.string,
    touristLogin: PropTypes.bool,
    lang: PropTypes.string,
    langList: PropTypes.array,
@@ -29,14 +33,20 @@
  state = {
    activeKey: 'uname_pwd',
    scanId: '',
    username: '',
    password: '',
    remember: true,
    delay: null,
    loginWays: [],
    smsId: '',
    verdisabled: false
    verdisabled: false,
    hasScan: false,
    timeout: false
  }
  timer = null
  splitTime = 0
  UNSAFE_componentWillMount () {
    const { loginWays } = this.props
@@ -51,43 +61,76 @@
    }
    let smsId = ''
    let hasScan = false
    let _loginWays = []
    loginWays.forEach(item => {
      if (item.type === 'sms_vcode') {
        item.label = '短信登录'
        smsId = item.smsId
        _loginWays.push(item)
      } else if (item.type === 'uname_pwd') {
        item.label = '账号登录'
        _loginWays.push(item)
      } else if (item.type === 'app_scan') {
        _loginWays.push(item)
        hasScan = true
      }
    })
    let activeKey = _loginWays[0].type
    this.setState({
      smsId: smsId,
      loginWays: _loginWays,
      activeKey: _loginWays[0].type,
      remember
    })
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.loginWays), fromJS(nextProps.loginWays))) {
      let smsId = ''
      let _loginWays = []
      nextProps.loginWays.forEach(item => {
        if (item.type === 'sms_vcode') {
          smsId = item.smsId
          _loginWays.push(item)
        } else if (item.type === 'uname_pwd') {
          _loginWays.push(item)
        }
      activeKey,
      scanId: activeKey === 'app_scan' ? Utils.getuuid() : '',
      timeout: false,
      remember,
      hasScan
      })
    if (activeKey === 'app_scan') {
      this.splitTime = 0
      this.timer = setTimeout(() => {
        this.checkResult()
      }, 10000)
    }
  }
  checkResult = () => {
    const { scanId } = this.state
    this.splitTime += 10000
    let _param = {
      func: 'webapi_get_binding_key',
      scan_type: 'pc',
      id: scanId,
      UserName: ''
    }
    _param.userid = sessionStorage.getItem('visitorUserID')
    _param.LoginUID = sessionStorage.getItem('visitorLoginUID')
    if (this.splitTime >= 180000) {
      this.setState({
        smsId: smsId,
        loginWays: _loginWays,
        activeKey: _loginWays[0].type
        timeout: true
      })
      return
    }
    Api.getSystemConfig(_param).then(res => {
      if (!res.status) {
        message.warning(res.message)
        return
      } else if (res.thd_party_appid && res.thd_party_member_id && res.thd_party_openid) {
        this.props.authLogin(res.thd_party_appid, res.thd_party_openid, res.thd_party_member_id, scanId)
      } else {
        this.timer = setTimeout(() => {
          this.checkResult()
        }, 10000)
      }
    })
  }
  handleConfirm = () => {
@@ -121,9 +164,9 @@
    e.preventDefault()
    if (!this.props.auth) {
      warning({
        title: this.props.dict['login.auth.tip'],
        okText: this.props.dict['login.auth.ok'],
        cancelText: this.props.dict['login.auth.cancel'],
        title: this.props.authError || this.props.dict['login.auth.tip'],
        okText: this.props.dict['login.ok'],
        cancelText: this.props.dict['login.cancel'],
        onOk() {},
        onCancel() {}
      })
@@ -168,7 +211,7 @@
    if (_user) {
      try {
        _user = JSON.parse(window.decodeURIComponent(window.atob(_user)))
      } catch {
      } catch (e) {
        console.warn('Parse Failure')
        _user = ''
      }
@@ -193,7 +236,29 @@
  }
  onChangeTab = (activeKey) => {
    this.setState({activeKey})
    this.setState({activeKey, scanId: activeKey === 'app_scan' ? Utils.getuuid() : ''})
    if (this.state.activeKey === 'app_scan') {
      this.timer && clearTimeout(this.timer)
    }
    if (activeKey === 'app_scan') {
      this.splitTime = 0
      this.setState({timeout: false})
      this.timer = setTimeout(() => {
        this.checkResult()
      }, 10000)
    }
  }
  reCode = () => {
    this.splitTime = 0
    this.setState({timeout: false, scanId: Utils.getuuid()})
    this.timer = setTimeout(() => {
      this.checkResult()
    }, 10000)
  }
  getvercode = () => {
@@ -303,17 +368,20 @@
    this.setState = () => {
      return
    }
    this.timer && clearTimeout(this.timer)
  }
  render() {
    const { getFieldDecorator } = this.props.form
    const { activeKey, verdisabled, delay, loginWays } = this.state
    const { activeKey, verdisabled, delay, loginWays, remember, scanId, timeout, hasScan } = this.state
    const wayLabels = {app_scan: '扫码登录', uname_pwd: '账号登录', sms_vcode: '短信登录'}
    return (
      <Form className={`login-form login-form-${loginWays.length}`} id="login-form" onSubmit={this.handleSubmit}>
        <p className="title">{this.props.platName}</p>
        <div className="form-item-wrap">
          {activeKey === 'uname_pwd' ? <Form.Item>
      <Form className="login-form" id="login-form" onSubmit={this.handleSubmit}>
        <div className="login-way-title">{wayLabels[activeKey]}</div>
        {hasScan && activeKey !== 'app_scan' ? <div className="scan-icon" onClick={() => this.onChangeTab('app_scan')}><QrcodeOutlined /></div> : null}
        {activeKey === 'uname_pwd' ? <div className="form-item-wrap">
          <Form.Item>
            {getFieldDecorator('username', {
              rules: [{ required: true, message: this.props.dict['login.username.empty'] }],
              initialValue: this.state.username || '',
@@ -324,8 +392,8 @@
                autoComplete="off"
              />,
            )}
          </Form.Item> : null}
          {activeKey === 'uname_pwd' ? <Form.Item>
          </Form.Item>
          <Form.Item>
            {getFieldDecorator('password', {
              initialValue: this.state.password || '',
              rules: [
@@ -334,9 +402,40 @@
                  message: this.props.dict['login.password.empty'],
                }
              ]
            })(<Input.Password placeholder={this.props.dict['login.password']} prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
            })(<Input.Password placeholder={this.props.dict['login.password']} prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
          </Form.Item>
          {window.GLOB.keepKey ? <Form.Item className="minline">
            {getFieldDecorator('remember', {
              valuePropName: 'checked',
              initialValue: remember,
            })(<Checkbox onChange={this.rememberChange}>{this.props.dict['login.remember']}</Checkbox>)}
          </Form.Item> : <div style={{height: '30px', float: 'left'}}></div>}
          {this.props.langList && this.props.langList.length > 0 ? <Form.Item className="minline right">
            {getFieldDecorator('lang', {
              initialValue: this.props.lang,
            })(
              <Select
                onChange={(value) => {this.changelang(value)}}
                getPopupContainer={() => document.getElementById('login-form')}
              >
                {this.props.langList.map((item, index) => {
                  return <Select.Option key={index} value={item.Lang}>{item.LangName}</Select.Option>
                })}
              </Select>
            )}
          </Form.Item> : null}
          {activeKey === 'sms_vcode' ? <Form.Item>
          <Form.Item className="btn-login">
            <Button type="primary" htmlType="submit" className="login-form-button" disabled={this.props.isDisabled} loading={this.props.isDisabled}>
              {this.props.dict['login.submit']}
            </Button>
          </Form.Item>
          {options.sysType === 'cloud' && options.cdomain.indexOf('mk9h') > -1 ? <Form.Item className="register-line">
            <a href="http://www.minkesoft.com/signup" target="_blank" rel="noopener noreferrer" className="register">注册</a>
            <a href="http://www.minkesoft.com/forgotPwd" target="_blank" rel="noopener noreferrer" className="forgot">忘记密码?</a>
          </Form.Item> : null}
        </div> : null}
        {activeKey === 'sms_vcode' ? <div className="form-item-wrap">
          <Form.Item>
            {getFieldDecorator('phone', {
              rules: [{ required: true, message: this.props.dict['login.phone.empty'] }],
              initialValue: '',
@@ -346,8 +445,8 @@
                autoComplete="off"
              />
            )}
          </Form.Item> : null}
          {activeKey === 'sms_vcode' ? <Form.Item className="vercode">
          </Form.Item>
          <Form.Item className="vercode">
            {getFieldDecorator('vercode', {
              initialValue: '',
              rules: [
@@ -367,22 +466,48 @@
                autoComplete="off"
              />
            )}
          </Form.Item>
          {this.props.langList && this.props.langList.length > 0 ? <Form.Item className="minline right">
            {getFieldDecorator('lang', {
              initialValue: this.props.lang,
            })(
              <Select
                onChange={(value) => {this.changelang(value)}}
                getPopupContainer={() => document.getElementById('login-form')}
              >
                {this.props.langList.map((item, index) => {
                  return <Select.Option key={index} value={item.Lang}>{item.LangName}</Select.Option>
                })}
              </Select>
            )}
          </Form.Item> : null}
          {/* {activeKey === 'uname_pwd' ? <Form.Item className="minline">
            {getFieldDecorator('remember', {
              valuePropName: 'checked',
              initialValue: remember,
            })(<Checkbox onChange={this.rememberChange}>{this.props.dict['login.remember']}</Checkbox>)}
          </Form.Item> : null} */}
          {['uname_pwd', 'sms_vcode'].includes(activeKey) ? <Form.Item className="btn-login">
          <Form.Item className="btn-login">
            <Button type="primary" htmlType="submit" className="login-form-button" disabled={this.props.isDisabled} loading={this.props.isDisabled}>
              {this.props.dict['login.submit']}
            </Button>
          </Form.Item> : null}
          </Form.Item>
          {options.sysType === 'cloud' && options.cdomain.indexOf('mk9h') > -1 ? <Form.Item className="register-line">
            <a href="http://minkesoft.com/#/signup" target="_blank" rel="noopener noreferrer" className="register">注册</a>
            <a href="http://minkesoft.com/#/forgotPwd" target="_blank" rel="noopener noreferrer" className="forgot">忘记密码?</a>
            <a href="http://www.minkesoft.com/signup" target="_blank" rel="noopener noreferrer" className="register">注册</a>
            <a href="http://www.minkesoft.com/forgotPwd" target="_blank" rel="noopener noreferrer" className="forgot">忘记密码?</a>
          </Form.Item> : null}
        </div> : null}
        {activeKey === 'app_scan' ? <div className="form-item-wrap">
          <div className="form-scan-wrap">
            <div className="qr-wrap">
              {scanId ? <QrCode card={{qrWidth: 500, color: '#000000'}} value={`mkpcscan,${window.GLOB.appkey},${scanId}`}/> : null}
              {timeout ? <div className="qrcode-out">
                <RedoOutlined onClick={this.reCode} />
                二维码已失效。
              </div> : null}
            </div>
            请使用客户端扫一扫登录
          </div>
        </div> : null}
        <div className={'login-ways ' + (activeKey === 'app_scan' ? 'center' : '')}>
          {loginWays.map(item => {
            if (item.type === 'app_scan' || activeKey === item.type) return null
            return (<span key={item.type} onClick={() => this.onChangeTab(item.type)}>{item.label}</span>)
          })}
        </div>
      </Form>
    )