Prechádzať zdrojové kódy

登陆页面优化,完成图片验证码功能和重置功能

UI 2 rokov pred
rodič
commit
24adde5b32

BIN
picture/Verification_1.jpg


+ 175 - 0
src/views/login/components/vueImageVerify.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="div" @click="createdCode">
+    <canvas id="div" :width="contentWidth" :height="contentHeight" />
+  </div>
+</template>
+<script>
+import Vue from 'vue'
+export default Vue.extend({
+  props: {
+    fontSizeMin: {
+      type: Number,
+      default: 25
+    },
+    fontSizeMax: {
+      type: Number,
+      default: 30
+    },
+    backgroundColorMin: {
+      type: Number,
+      default: 255
+    },
+    backgroundColorMax: {
+      type: Number,
+      default: 255
+    },
+    colorMin: {
+      type: Number,
+      default: 0
+    },
+    colorMax: {
+      type: Number,
+      default: 160
+    },
+    lineColorMin: {
+      type: Number,
+      default: 100
+    },
+    lineColorMax: {
+      type: Number,
+      default: 255
+    },
+    dotColorMin: {
+      type: Number,
+      default: 0
+    },
+    dotColorMax: {
+      type: Number,
+      default: 255
+    },
+    contentWidth: {
+      type: Number,
+      default: 120
+    },
+    contentHeight: {
+      type: Number,
+      default: 54
+    }
+  },
+  data() {
+    return {
+      identifyCode: ''
+    }
+  },
+  mounted() {
+    this.createdCode()
+  },
+  methods: {
+    // 生成4个随机数
+    createdCode() {
+      const len = 4
+      const codeList = []
+      const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz01234569'
+      const charsLen = chars.length
+      for (let i = 0; i < len; i++) {
+        codeList.push(chars.charAt(Math.floor(Math.random() * charsLen)))
+      }
+      this.identifyCode = codeList.join('')
+      this.$emit('getIdentifyCode', this.identifyCode.toLowerCase())
+      this.drawPic()
+      console.log(this.identifyCode)
+    },
+
+    // 生成一个随机数
+    randomNum(min, max) {
+      return Math.floor(Math.random() * (max - min) + min)
+    },
+    // 生成一个随机的颜色
+    randomColor(min, max) {
+      const r = this.randomNum(min, max)
+      const g = this.randomNum(min, max)
+      const b = this.randomNum(min, max)
+      return 'rgb(' + r + ',' + g + ',' + b + ')'
+    },
+
+    drawPic() {
+      const canvas = document.getElementById('div')
+      const ctx = canvas.getContext('2d')
+      ctx.textBaseline = 'bottom'
+      // 绘制背景
+      ctx.fillStyle = this.randomColor(
+        this.backgroundColorMin,
+        this.backgroundColorMax
+      )
+      ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
+      // 绘制文字
+      for (let i = 0; i < this.identifyCode.length; i++) {
+        this.drawText(ctx, this.identifyCode[i], i)
+      }
+      this.drawLine(ctx)
+      this.drawDot(ctx)
+    },
+
+    drawText(ctx, txt, i) {
+      ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
+      ctx.font =
+        this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei'
+      const x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))
+      const y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
+      var deg = this.randomNum(-45, 45)
+      // 修改坐标原点和旋转角度
+      ctx.translate(x, y)
+      ctx.rotate((deg * Math.PI) / 180)
+      ctx.fillText(txt, 0, 0)
+      // 恢复坐标原点和旋转角度
+      ctx.rotate((-deg * Math.PI) / 180)
+      ctx.translate(-x, -y)
+    },
+
+    // 绘制干扰线
+    drawLine(ctx) {
+      for (let i = 0; i < 5; i++) {
+        ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
+        ctx.beginPath()
+        ctx.moveTo(
+          this.randomNum(0, this.contentWidth),
+          this.randomNum(0, this.contentHeight)
+        )
+        ctx.lineTo(
+          this.randomNum(0, this.contentWidth),
+          this.randomNum(0, this.contentHeight)
+        )
+        ctx.stroke()
+      }
+    },
+
+    // 绘制干扰点
+    drawDot(ctx) {
+      for (let i = 0; i < 80; i++) {
+        ctx.fillStyle = this.randomColor(0, 255)
+        ctx.beginPath()
+        ctx.arc(
+          this.randomNum(0, this.contentWidth),
+          this.randomNum(0, this.contentHeight),
+          1,
+          0,
+          2 * Math.PI
+        )
+        ctx.fill()
+      }
+    }
+  }
+})
+</script>
+ <style scoped>
+.div {
+  margin: 0;
+  padding: 0;
+  height: 18px;
+}
+.div canvas {
+  margin-top: 0px;
+  margin-left: 6px;
+  height: 45px;
+}
+</style>

BIN
src/views/login/images/yu.png


+ 114 - 84
src/views/login/index.vue

@@ -64,24 +64,7 @@
         </el-form-item>
       </el-tooltip>
 
-      <!-- <el-form-item v-if="captchaEnabled" prop="code ">
-        <el-col :span="16">
-          <el-input
-            v-model="loginForm.code "
-            placeholder="验证码"
-            style="width:63%"
-            @keyup.enter.native="handleLogin"
-          >
-            <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
-          </el-input>
-          <div class="login-code">
-            <img :src="codeUrl" class="login-code-img" @click="getCode">
-          </div>
-        </el-col>
-      </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin-left: 20px;">记住密码</el-checkbox> -->
-
-      <el-form-item prop="code">
+      <!-- <el-form-item prop="code">
         <el-input
           v-model="loginForm.code"
           class="code"
@@ -96,15 +79,41 @@
           alt="验证码"
           @click="changeCode"
         >
+      </el-form-item> -->
+
+      <!-- 验证码 -->
+      <el-form-item>
+        <el-row :gutter="24">
+          <el-col :span="16" :offset="0">
+            <el-input
+              v-model="loginForm.code"
+              placeholder="请输入验证码"
+            />
+            <!-- 引入图标 -->
+            <!-- <el-input
+              v-model="loginForm.code"
+              prefix-icon="el-icon-info"
+              style="margin-left: 5px; fill: currentColor"
+            /> -->
+          </el-col>
+
+          <el-col :span="8" :offset="0">
+            <vue-image @getIdentifyCode="getIdentifyCodes" />
+          </el-col>
+        </el-row>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin-left: 8px;">记住密码</el-checkbox>
+
+      <!-- 记住密码 -->
+      <el-checkbox
+        v-model="loginForm.rememberMe"
+        style="margin-left: 8px"
+      >记住密码</el-checkbox>
 
       <!-- 按钮 -->
       <el-button
         :loading="loading"
         type="info"
         icon="el-icon el-icon-delete"
-
         style="width: 30%; margin-bottom: 20px; margin-left: 20px"
         @click="resetLoginForm"
       >
@@ -115,7 +124,7 @@
         :loading="loading"
         type="warning"
         icon="el-icon el-icon-circle-plus"
-        style="width:35%;margin-bottom: 20px; margin-left: 20px"
+        style="width: 35%; margin-bottom: 20px; margin-left: 20px"
         @click="registerForm($refs['loginForm'])"
       >
         注册
@@ -130,7 +139,6 @@
       >
         {{ $t("login.logIn") }}
       </el-button>
-
     </el-form>
 
     <el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog">
@@ -148,13 +156,13 @@
 import { validUsername } from '@/utils/validate'
 import LangSelect from '@/components/LangSelect'
 import SocialSign from './components/SocialSignin'
-import Cookies from 'js-cookie'
+import VueImage from './components/vueImageVerify.vue'
 // import LoginFunc from '@/function-namespace/auth/LoginFunc'
 
 export default {
   name: 'Login',
   // eslint-disable-next-line vue/no-unused-components
-  components: { LangSelect, SocialSign },
+  components: { LangSelect, SocialSign, VueImage },
   data() {
     const validateUsername = (rule, value, callback) => {
       if (value.length < 6) {
@@ -221,25 +229,16 @@ export default {
     // window.removeEventListener('storage', this.afterQRScan)
   },
   methods: {
-    // getCode() {
-    //   getCodeImg().then(res => {
-    //     this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
-    //     if (this.captchaEnabled) {
-    //       this.codeUrl = 'data:image/gif;base64,' + res.img
-    //       this.loginForm.uuid = res.uuid
-    //     }
-    //   })
-    // },
-    // getCookie() {
-    //   const username = Cookies.get('username')
-    //   const password = Cookies.get('password')
-    //   const rememberMe = Cookies.get('rememberMe')
-    //   this.loginForm = {
-    //     username: username === undefined ? this.loginForm.username : username,
-    //     // password: password === undefined ? this.loginForm.password : decrypt(password),
-    //     rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
-    //   }
-    // },
+    getIdentifyCodes(value) {
+      console.log('------', value)
+      // 判断验证码输入是否有误 和输入的文本框
+      // if (this.verify.toLowerCase() != value.toLowerCase()) {
+      // Toast.fail('验证码有误')
+      // return
+      // }
+      this.valiatecode = value.toLowerCase()
+    },
+
     checkCapslock(e) {
       const { key } = e
       this.capsTooltip = key && key.length === 1 && key >= 'A' && key <= 'Z'
@@ -255,25 +254,32 @@ export default {
       })
     },
     handleLogin() {
-      this.$refs.loginForm.validate((valid) => {
+      // 验证码判断
+      // eslint-disable-next-line eqeqeq
+      if (this.valiatecode.toLowerCase() != this.loginForm.code.toLowerCase()) {
+        console.log(this.valiatecode, this.loginForm.code)
+        this.$notify({
+          title: 'warning',
+          message: '验证码错误',
+          type: 'warning',
+          duration: 2000
+        })
+        return
+      }
+      // 登陆判断
+      this.$refs.loginForm.validate(valid => {
         if (valid) {
           this.loading = true
-          if (this.loginForm.rememberMe) {
-            Cookies.set('username', this.loginForm.username, { expires: 30 })
-            // Cookies.set('password', encrypt(this.loginForm.password), { expires: 30 })
-            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
-          } else {
-            Cookies.remove('username')
-            Cookies.remove('password')
-            Cookies.remove('rememberMe')
-          }
-          this.$store
-            .dispatch('user/login', this.loginForm)
+          this.$notify({
+            title: 'Success',
+            message: '登录成功',
+            type: 'success',
+            duration: 2000
+          })
+
+          this.$store.dispatch('user/login', this.loginForm)
             .then(() => {
-              this.$router.push({
-                path: this.redirect || '/',
-                query: this.otherQuery
-              })
+              this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
               this.loading = false
             })
             .catch(() => {
@@ -285,6 +291,31 @@ export default {
         }
       })
     },
+
+    handleLogin_second() {
+      this.$refs.loginForm.validate(valid => {
+        if (valid) {
+          this.loading = true
+          this.$store.dispatch('user/login', this.loginForm)
+            .then(() => {
+              this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
+              this.loading = false
+            })
+            .catch(() => {
+              this.loading = false
+            })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+
+    resetLoginForm() {
+      // vue中刷新页面
+      this.$router.go(0)
+      // windows强制刷新:window.location.reload()
+    },
     getOtherQuery(query) {
       return Object.keys(query).reduce((acc, cur) => {
         if (cur !== 'redirect') {
@@ -313,7 +344,6 @@ export default {
     // }
   }
 }
-
 </script>
 
 <style lang="scss">
@@ -368,7 +398,7 @@ $bg: #2d3a4b;
 $dark_gray: #889aa4;
 $light_gray: #eee;
 
-.el-button--info{
+.el-button--info {
   background: #1890ff;
 }
 
@@ -382,7 +412,7 @@ $light_gray: #eee;
     margin-top: 5px;
     margin-left: 10px;
     height: 30px;
-    width:"60%",
+    width: "60%";
   }
   .login-form {
     position: relative;
@@ -444,29 +474,29 @@ $light_gray: #eee;
   }
 
   .login-code {
-  width: 33%;
-  height: 38px;
-  float: right;
-  img {
-    cursor: pointer;
-    vertical-align: middle;
+    width: 33%;
+    height: 38px;
+    float: right;
+    img {
+      cursor: pointer;
+      vertical-align: middle;
+    }
+  }
+  .el-login-footer {
+    height: 40px;
+    line-height: 40px;
+    position: fixed;
+    bottom: 0;
+    width: 100%;
+    text-align: center;
+    color: #fff;
+    font-family: Arial;
+    font-size: 12px;
+    letter-spacing: 1px;
+  }
+  .login-code-img {
+    height: 38px;
   }
-}
-.el-login-footer {
-  height: 40px;
-  line-height: 40px;
-  position: fixed;
-  bottom: 0;
-  width: 100%;
-  text-align: center;
-  color: #fff;
-  font-family: Arial;
-  font-size: 12px;
-  letter-spacing: 1px;
-}
-.login-code-img {
-  height: 38px;
-}
 
   .thirdparty-button {
     position: absolute;

+ 0 - 186
src/views/login/new_login.vue

@@ -1,186 +0,0 @@
-<template>
-  <div class="login_container">
-    <!--登录块-->
-    <div class="login_box">
-      <!--表单区域-->
-      <el-form
-        ref="loginFromRef"
-        :rules="loginRules"
-        :model="loginFrom"
-        class="login_from"
-        label-width="0px"
-      >
-        <h3 class="headline">力山特起重机智能运维系统</h3>
-        <!--用户名-->
-        <el-form-item prop="username">
-          <el-input
-            v-model="loginFrom.username"
-            prefix-icon="iconfont icon-denglu"
-            placeholder="用户名"
-          />
-        </el-form-item>
-        <!--密码-->
-        <el-form-item prop="password">
-
-          <el-input
-            v-model="loginFrom.password"
-            prefix-icon="iconfont icon-mima"
-            type="password"
-            placeholder="密码"
-          />
-        </el-form-item>
-
-        <el-form-item prop="verifyCode">
-          <el-col :span="16">
-            <el-input
-              v-model="loginFrom.verifyCode"
-              prefix-icon="el-icon-message"
-              placeholder="验证码"
-              class="verifyCode"
-            />
-          </el-col>
-          <el-col :span="8">
-            <img class="verifyCodeImg" :src="imgUrl" @click="resetImg">
-          </el-col>
-
-        </el-form-item>
-
-        <!--按钮-->
-        <el-form-item class="btn">
-          <el-button type="primary" @click="login">登录</el-button>
-          <!-- <el-button type="info" @click="resetLoginForm">重置</el-button> -->
-        </el-form-item>
-      </el-form>
-    </div>
-  </div>
-</template>
-<script>
-export default {
-  data() {
-    return {
-      // 表单数据
-      // imgUrl: 'http://localhost:9000/home/verifyCode?time=' + new Date(),
-      loginFrom: {
-        username: 'admin',
-        password: '123456',
-        verifyCode: ''
-      },
-      // 验证对象
-      loginRules: {
-        // 校验用户名
-        username: [
-          { required: true, message: '请输入用户名称', trigger: 'blur' }, // 必填项验证
-          {
-            min: 5,
-            max: 12,
-            message: '长度在 5 到 12 个字符',
-            trigger: 'blur'
-          } // 验证长度
-        ],
-        // 校验密码
-        password: [
-          { required: true, message: '请输入用户密码', trigger: 'blur' }, // 必填项验证
-          {
-            min: 6,
-            max: 10,
-            message: '长度在 6 到 10 个字符',
-            trigger: 'blur'
-          } // 验证长度
-        ]
-      },
-      imgSrc: require('../assets/bg.png')
-    }
-  },
-  methods: {
-    resetLoginForm() {
-      // 重置表单内容
-      this.$refs.loginFromRef.resetFields()
-    },
-    resetImg() {
-      this.imgUrl = 'http://localhost:9000/home/verifyCode?time=' + new Date()
-    },
-    login() {
-      // 登录请求
-      this.$refs.loginFromRef.validate(async(validate) => {
-        // 判断是否验证成功
-        if (!validate) return
-        const { data: res } = await this.$http.post(
-          'home/login',
-          this.loginFrom
-        )
-
-        // eslint-disable-next-line eqeqeq
-        if (res.status == '200') {
-          this.$message.success('登陆成功')
-          window.sessionStorage.setItem('user', res.id)
-          const { data: res1 } = await this.$http.get('menus', { params: {
-            id: window.sessionStorage.getItem('user')
-          }})
-          window.sessionStorage.setItem('menu', window.JSON.stringify(res1.menus))
-          window.sessionStorage.setItem('token', res.token)
-          // 跳转页面
-          this.$router.push({ path: '/home' })
-        // eslint-disable-next-line eqeqeq
-        } else if (res.status == '400') {
-          this.$message.error('用户名或密码错误')
-        // eslint-disable-next-line eqeqeq
-        } else if (res.status == '404') {
-          this.$message.error('账号未激活,请联系管理员')
-        } else {
-          this.$message.error('验证码输入错误')
-          this.imgUrl = 'http://localhost:9000/home/verifyCode?time=' + new Date()
-        }
-      })
-    }
-  }
-}
-</script>
-  <style lang="less" scoped>
-  .login_container {
-    background-color: #2b4b6b;
-    height: 100%;
-  }
-  .login_box {
-    background: rgba(78, 102, 112, 0.1);
-    width: 450px;
-    height: 330px;
-    border-radius: 5px;
-    position: absolute;
-    left: 50%;
-    top: 50%;
-    transform: translate(-50%, -50%);
-  }
-  .btn {
-    width: 100%;
-  }
-  .login_from {
-    position: absolute;
-    bottom: 0%;
-    width: 100%;
-    padding: 0 10px;
-    box-sizing: border-box;
-    .verifyCode {
-      width:"60%",
-    }
-    .verifyCodeImg {
-      margin-top: 5px;
-      margin-left: 10px;
-      height: 30px;
-      width:"60%",
-    }
-  }
-  .el-button {
-    margin-left: 10%;
-    width: 80%;
-  }
-  .el-form-item {
-    margin-left: 10%;
-    width: 80%;
-  }
-  .headline {
-    font-size: 20px;
-    color: white;
-    margin-left: 35%;
-  }
-  </style>
-