SOURCE

<template>
  <div class="page-login">
    <div class="page-login-content">
      <div class="page-login-img-form">
        <div class="page-login-form">
          <h2>
            <span>WELCOME</span>
            {{loginTitle}}
          </h2>
          <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="80px" onsubmit="return false;">
            <el-form-item label="用户名" prop="username">
              <el-input
                v-model.trim="ruleForm.username"
                placeholder="请输入用户名"
                autocomplete="off"
                auto-complete="new-password"
                maxlength="20"
                @copy.prevent.native
                autofocus
                clearable
                ref="input"
              ></el-input>
            </el-form-item>
            <el-form-item label="密码" prop="pass">
              <el-input
                type="password"
                autocomplete="off"
                auto-complete="new-password"
                v-model.trim="ruleForm.pass"
                placeholder="请输入密码"
                maxlength="20"
                @copy.prevent.native
                @paste.prevent.native
                clearable
              ></el-input>
              <!-- @copy.prevent.native
              @paste.prevent.native-->
              <!-- show-password -->
            </el-form-item>
                <el-form-item label="1-1000正整数" prop="tenantNum" class="width100">
                  <el-input
                    type="text"
                    autocomplete="off"
                    v-model.number.trim="ruleForm.tenantNum"
                    minlength="1"
                    maxlength="4"
                    clearable
                  ></el-input>
                  <span class="tenantSetting-unit"></span>
                </el-form-item>
                <el-form-item label="价格 ( 元/月 )" prop="productPrice">
                  <el-input
                    v-model="ruleForm.productPrice"
                    autocomplete="off"
                    placeholder="请输入价格,限数字"
                    maxlength="11"
                    clearable
                    @blur="productPriceBlur"
                    @input="productPriceInput"
                  ></el-input>
                </el-form-item>
            <el-form-item label="验证码" prop="code">
              <el-input
                ref="verifycode"
                minlength="4"
                maxlength="4"
                v-model.trim="ruleForm.code"
                placeholder="请输入验证码"
                autocomplete="off"
                @copy.prevent.native
                @paste.prevent.native
                @keyup.native.enter="submitForm"
                clearable
              ></el-input>
              <verifycode v-model="refresh" @change="changeVerifycode" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="submitForm" :loading="loading">登 录</el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Verifycode from '@/components/Verifycode'
import { mapState, mapActions } from 'vuex'
export default {
  name: 'Login',
  components: {
    Verifycode
  },
  data () {
    const reg = /^[a-zA-Z][a-zA-Z0-9]{7,31}$/
    //  var const = /^\d{1,}((\.\d{1,})|(\d{0,}))$/  正数字或小数
    
    var reg1 = /^[1-9][0-9]{0,3}$/
    var validateChannelNum = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('CP/SP可接入数量不能为空'))
      }
      if (!(reg1.test(value) && Number(value) <= 1000)) {
        return callback(new Error('数量为1-1000内的整数,请重新输入'))
      }
      callback()
    }

    var validateProductPrice = (rule, value, callback, source, options) => {
      if (!value && value !== 0) {
        return callback(new Error('价格不能为空'))
      }
      if (value && !/^\d{1,}((\.\d{1,})|(\d{0,}))$/.test(value)) {
        return callback(new Error('请输入10000以内数字'))
      }
      if (Number(value) > 10000) {
        return callback(new Error('请输入10000以内数字'))
      }
      callback()
    }


    var checkUsername = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('用户名不能为空'))
      }
      if (!reg.test(value)) {
        return callback(new Error('请输入正确格式的用户名'))
      }
      callback()
    }
    var validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入密码'))
      }
      callback()
    }
    var validateCode = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入验证码'))
      }
      if (value.length < 4) {
        callback(new Error('请输入4位验证码'))
      }
      callback()
    }
    return {
      ruleForm: {
        username: '',
        pass: '',
        code: ''
      },
      rules: {
        username: [{
          validator: checkUsername,
          trigger: 'blur'
        }, {
          validator: checkUsername,
          trigger: 'change'
        }],
        pass: [{
          validator: validatePass,
          trigger: 'blur'
        }, {
          validator: validatePass,
          trigger: 'change'
        }],
        code: [{
          validator: validateCode,
          trigger: 'blur'
        }, {
          validator: validateCode,
          trigger: 'change'
        }]
      },
      loading: false,
      refresh: false
    }
  },
  computed: {
    ...mapState(['loginTitle']),
    // 参数
    getParams () {
      const { ruleForm: { username, pass, code } } = this
      return {
        adminId: username,
        passwd: pass,
        verifyCode: code
      }
    }
  },
  methods: {
    ...mapActions(['setKeyValue', 'setUserLogin', 'submitLogin', 'getMenu', 'setUserLogout']),
     productPriceBlur (val) {
      if (this.ruleForm.productPrice && !isNaN(this.ruleForm.productPrice)) {
        this.ruleForm.productPrice = Math.floor(this.ruleForm.productPrice * 100) / 100
      }
    },
    productPriceInput (val) {
    },
    changeVerifycode () {
      const { setVerifycode } = this
      setVerifycode()
    },
    // 设置验证码输入框:清空并聚焦
    setVerifycode () {
      const { $refs } = this
      this.ruleForm.code = ''
      this.$nextTick(() => {
        $refs.verifycode && $refs.verifycode.$el.querySelector('input').focus()
      })
    },
    // 跳转页面
    async jumpChangePage (path = '/changePassword', val = null) {
      const { $router, setUserLogin, ruleForm, getMenu } = this
      if (val) {
        const resp = await getMenu()
        if (resp && resp.length) {
          // 取出菜单中第一个子菜单的子菜单/一级子菜单
          const url = resp[0]['children'] && resp[0]['children'].length ? resp[0]['children'][0]['funcUrl'] : resp[0]['funcUrl']
          setUserLogin(val)
          this.$nextTick(() => {
            $router.replace(url)
          })
        }
        this.loading = false
      } else {
        setUserLogin(val || { adminId: ruleForm.username })
        this.$nextTick(() => {
          $router.replace(path || '/changePassword')
        })
      }
    },
    // 登录请求
    async login () {
      const { submitLogin, getParams, setVerifycode, setKeyValue, jumpChangePage } = this
      let str = '登录失败'
      try {
        const resp = await submitLogin(getParams)
        if (resp) {
          const { resultInfo, resultCode, data } = resp
          str = resultInfo || str
          switch (resultCode) {
            case '120000':
              str = ''
              setKeyValue({ key: 'isPrivacyStatement', value: true })
              jumpChangePage('/privacyStatement')
              break
            case '200000':
              str = '验证码错误'
              break
            case '200007':
              str = ''
              setKeyValue({ key: 'isFirstLogin', value: true })
              jumpChangePage()
              break
            case '200008':
              str = ''
              jumpChangePage()
              break
            default:
              if (resultCode === '000000') {
                str = ''
                jumpChangePage('', data)
              }
              break
          }
        }
        str && this.$message.warning(str)
      } catch (error) {
      }
      if (str) {
        setVerifycode()
        this.refresh = true
      }
      str && (this.loading = false)
    },
    // 登录事件
    submitForm () {
      const { $refs } = this
      $refs['ruleForm'].validate((valid) => {
        if (valid) {
          this.loading = true
          this.login()
        } else {
          return false
        }
      })
    },
    init () {
      this.$nextTick(() => {
        this.$refs.input.focus()
        this.setUserLogout()
      })
    }
  },
  created () {
  },
  mounted () {
  },
  beforeRouteEnter (to, from, next) {
    next(vm => {
      vm.init()
    })
  },
  watch: {
    'ruleForm.code': {
      handler (val) {
        this.ruleForm.code = `${val}`.replace(/[^a-zA-Z0-9]/g, '').slice(0, 4)
      },
      immediate: true,
      deep: true
    }
  }
}
</script>

<style lang="scss">
.page-login {
  height: 100%;
  background: $primary-color url(../assets/images/login-bg.png) center center
    no-repeat;
  background-size: 100% 100%;
  &::before {
    position: absolute;
    content: "";
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
    background: url(../assets/images/login-bg2.png) center center no-repeat;
    background-size: 100% 100%;
  }
  .page-login-content {
    position: absolute;
    left: 8.35%;
    right: 8.35%;
    top: 8.25%;
    bottom: 9.25%;
    // background: #fff;
    // box-shadow: 0px 6px 50px 0px rgba(0, 45, 196, 0.43);
    border-radius: 20px;
    overflow: hidden;
    .page-login-img-form {
      height: 100%;
      position: relative;
      min-height: 400px;
      overflow-y: auto;
      &::after {
        position: absolute;
        content: "";
        left: 5.25%;
        top: 9.54%;
        width: 51.25%;
        height: 81.8%;
        background: url(../assets/images/login-img.png) center center no-repeat;
        background-size: 100% 100%;
      }
      .page-login-form {
        position: absolute;
        top: 18.5%;
        right: 10.625%;
        width: 27.5%;
        max-width: 440px;
        h2 {
          text-align: left;
          line-height: 60px;
          font-size: 39px;
          font-weight: bold;
          color: $text-color;
          white-space: nowrap;
          text-align: left;
          padding: 0 0 50px;
          span {
            display: block;
            font-size: 48px;
            line-height: 54px;
            font-weight: bold;
            color: #dae0f9;
            opacity: 0.55;
          }
        }
        .el-form {
          padding-bottom: 32px;
          .el-form-item {
            position: relative;
            height: 48px;
            margin-bottom: 32px;
            .el-form-item__error {
              text-indent: 57px;
            }
            &:last-child {
              padding-top: 30px;
              .el-button--primary {
                display: block;
                width: 100%;
                padding: 13px 30px;
                font-size: 20px;
                border-radius: 6px;
              }
            }
          }
          .el-form-item__label {
            z-index: 2;
            position: absolute;
            left: 44px;
            top: 50%;
            padding: 0;
            margin: 0;
            transform: translateY(-50%);
            width: 1px !important;
            height: 12px;
            background-color: #b3bfdb;
            overflow: hidden;
          }
          .el-form-item__content {
            margin-left: 0 !important;
          }
          .el-input__inner {
            width: 100%;
            padding: 8px 10% 8px 57px;
            height: 48px;
            border-radius: 8px;
            color: $text-color;
          }
          .el-input__suffix {
            display: flex;
            align-items: center;
          }
          .el-form-item:not(.is-error) .el-input__inner:not(:focus) {
            border-color: #f4f6fd;
          }
          .el-form-item:nth-child(1) .el-input__inner {
            background: #f4f6fd url(../assets/images/icon-login01.png) 11px
              center no-repeat;
          }
          .el-form-item:nth-child(2) .el-input__inner {
            background: #f4f6fd url(../assets/images/icon-login02.png) 11px
              center no-repeat;
          }
          .el-form-item:nth-child(3) .el-input__inner {
            background: #f4f6fd url(../assets/images/icon-login03.png) 11px
              center no-repeat;
          }
          .el-form-item:nth-child(3) {
            .el-input {
              width: calc(100% - 168px);
            }
            .el-input__inner {
              width: 100%;
            }
            .el-input + span {
              display: inline-block;
              margin: 0 0 0 18px;
              text-align: center;
              width: 150px;
              height: 48px;
              line-height: 48px;
              // background-color: #f4f6fd;
              border-radius: 8px;
              vertical-align: top;
              color: #b3bfdb;
              cursor: pointer;
              position: relative;
              vertical-align: middle;
              i {
                left: 50%;
                top: 50%;
                transform: translate(-50%, -50%);
                position: absolute;
                margin-top: -6px;
              }
            }
          }
        }
      }
    }
  }
  .el-input__inner::placeholder {
    font-size: 14px;
    color: #b3bfdb;
  }
  .el-input__inner::-webkit-input-placeholder {
    font-size: 14px;
    color: #b3bfdb;
  }
  .el-input__inner::-moz-placeholder {
    font-size: 14px;
    color: #b3bfdb;
  }

  .el-input__inner:-ms-input-placeholder {
    font-size: 14px;
    color: #b3bfdb !important;
  }
}
@media screen and (max-width: 1440px) {
  .page-login {
    .page-login-content .page-login-img-form .page-login-form {
      top: 13.875%;
      h2 {
        line-height: 50px;
        font-size: 32px;
        padding: 0 0 36px;
        span {
          font-size: 40px;
          line-height: 45px;
        }
      }
      .el-form .el-form-item:nth-child(3) .el-input {
        width: calc(100% - 158px);
      }
      .el-form .el-form-item:nth-child(3) .el-input + span {
        width: 140px;
      }
    }
  }
}
@media screen and (max-width: 1366px) {
  .page-login {
    .page-login-content .page-login-img-form .page-login-form {
      top: 13.16%;
      h2 {
        line-height: 45px;
        font-size: 28px;
        padding: 0 0 32px;
        span {
          font-size: 36px;
          line-height: 40px;
        }
      }
      .el-form .el-form-item {
        position: relative;
        height: 48px;
        margin-bottom: 24px;
        &:last-child {
          padding-top: 20px;
        }
      }
    }
    .el-input__inner::placeholder,
    .el-range-input::placeholder {
      font-size: 12px;
    }
    .el-input__inner::-webkit-input-placeholder,
    .el-range-input::-webkit-input-placeholder {
      font-size: 12px;
    }
    .el-input__inner::-moz-placeholder,
    .el-range-input::-moz-placeholder {
      font-size: 12px;
    }

    .el-input__inner:-ms-input-placeholder,
    .el-range-input:-ms-input-placeholder {
      font-size: 12px;
    }
  }
}
@media screen and (max-width: 1280px) {
  .page-login
    .page-login-content
    .page-login-img-form
    .page-login-form
    .el-form
    .el-form-item:nth-child(3)
    .el-input {
    width: calc(100% - 138px);
  }
  .page-login
    .page-login-content
    .page-login-img-form
    .page-login-form
    .el-form
    .el-form-item:nth-child(3)
    .el-input
    + span {
    width: 120px;
  }
}
</style>
console 命令行工具 X clear

                    
>
console