Browse Source

admin登录 需要验证码

刘琳琳 2 days ago
parent
commit
134f8e7a67

+ 1 - 1
public/config.js

@@ -1,6 +1,6 @@
 window.g = {
   // ApiUrl: 'https://face.ldxk.edu.cn:8901/ywjl-fyzd', //计量
   ApiUrl: 'https://noise.hz-hanghui.com:8088/yx-fyzd', //浙江
-  // ApiUrl: 'http://192.168.11.17:9100/yx-fyzd', //浙江本地
+  // ApiUrl: 'http://192.168.77.6:9100/yx-fyzd', //浙江本地
 
 }

+ 8 - 0
src/api/user.js

@@ -8,6 +8,14 @@ export function login(data) {
   })
 }
 
+export function getCode(data) {
+  return request({
+    url: '/admin/auth/getCode',
+    method: 'post',
+    data
+  })
+}
+
 export function getInfo() {
   return request({
     url: '/admin/auth/doGetInfo',

+ 2 - 2
src/store/modules/user.js

@@ -156,9 +156,9 @@ const mutations = {
 const actions = {
   // user login
   login({ commit }, userInfo) {
-    const { username, password } = userInfo
+    const { username, password, phone, code } = userInfo
     return new Promise((resolve, reject) => {
-      login({ username: username.trim(), password: password }).then(response => {
+      login({ username: username.trim(), password: password, phone, code }).then(response => {
         // 标记登录,开始检测长时间未操作情况
         notLogOut()
 

+ 39 - 0
src/styles/iconfont/iconfont.css

@@ -0,0 +1,39 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 4803281 */
+  src: url('iconfont.woff2?t=1736127768797') format('woff2'),
+       url('iconfont.woff?t=1736127768797') format('woff'),
+       url('iconfont.ttf?t=1736127768797') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-eye:before {
+  content: "\e62a";
+}
+
+.icon-eye-open:before {
+  content: "\e62b";
+}
+
+.icon-password:before {
+  content: "\e626";
+}
+
+.icon-user:before {
+  content: "\e627";
+}
+
+.icon-phone:before {
+  content: "\e628";
+}
+
+.icon-captcha:before {
+  content: "\e629";
+}
+

File diff suppressed because it is too large
+ 0 - 0
src/styles/iconfont/iconfont.js


+ 51 - 0
src/styles/iconfont/iconfont.json

@@ -0,0 +1,51 @@
+{
+  "id": "4803281",
+  "name": "alipay-auth-platform-admin-icon",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "alipay-auth-platform-admin(航汇-支付宝授权平台)",
+  "glyphs": [
+    {
+      "icon_id": "43044158",
+      "name": "eye",
+      "font_class": "eye",
+      "unicode": "e62a",
+      "unicode_decimal": 58922
+    },
+    {
+      "icon_id": "43044159",
+      "name": "eye-open",
+      "font_class": "eye-open",
+      "unicode": "e62b",
+      "unicode_decimal": 58923
+    },
+    {
+      "icon_id": "43044016",
+      "name": "password",
+      "font_class": "password",
+      "unicode": "e626",
+      "unicode_decimal": 58918
+    },
+    {
+      "icon_id": "43044017",
+      "name": "user",
+      "font_class": "user",
+      "unicode": "e627",
+      "unicode_decimal": 58919
+    },
+    {
+      "icon_id": "43044018",
+      "name": "phone",
+      "font_class": "phone",
+      "unicode": "e628",
+      "unicode_decimal": 58920
+    },
+    {
+      "icon_id": "43044019",
+      "name": "captcha",
+      "font_class": "captcha",
+      "unicode": "e629",
+      "unicode_decimal": 58921
+    }
+  ]
+}

BIN
src/styles/iconfont/iconfont.ttf


BIN
src/styles/iconfont/iconfont.woff


BIN
src/styles/iconfont/iconfont.woff2


+ 1 - 0
src/styles/index.scss

@@ -3,6 +3,7 @@
 @import './transition.scss';
 @import './element-ui.scss';
 @import './sidebar.scss';
+@import "./iconfont/iconfont.css";
 
 body {
   height: 100%;

+ 211 - 91
src/views/login/index.vue

@@ -1,19 +1,19 @@
 <template>
   <div class="login-container">
-    <img class="bg" :src="bg" alt="" />
-    <img class="logo" :src="logo" alt="" />
-    <div class="affiche-box" v-if="noticeData.isShow">
+    <img class="bg" :src="bg" alt="">
+    <img class="logo" :src="logo" alt="">
+    <div v-if="noticeData.isShow" class="affiche-box">
       <h4>{{ noticeData.titile }}</h4>
       <p>
         {{ noticeData.content }}
       </p>
       <div class="qrcode">
-        <img :src="noticeData.picture" alt="" />
+        <img :src="noticeData.picture" alt="">
       </div>
     </div>
     <el-form
-      :rules="rules"
       ref="loginForm"
+      :rules="rules"
       :model="loginForm"
       class="login-form"
       auto-complete="on"
@@ -24,9 +24,7 @@
       </div>
 
       <el-form-item prop="username">
-        <span class="svg-container">
-          <svg-icon icon-class="user" />
-        </span>
+        <i class="iconfont icon-user form-left-container" />
         <el-input
           ref="username"
           v-model="loginForm.username"
@@ -39,9 +37,7 @@
       </el-form-item>
 
       <el-form-item prop="password">
-        <span class="svg-container">
-          <svg-icon icon-class="password" />
-        </span>
+        <i class="iconfont icon-password form-left-container" />
         <el-input
           :key="passwordType"
           ref="password"
@@ -53,157 +49,244 @@
           auto-complete="on"
           @keyup.enter.native="handleLogin"
         />
-        <span class="show-pwd" @click="showPwd">
-          <svg-icon
-            :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
-          />
-        </span>
+        <i :class="`iconfont icon-${passwordType === 'password' ? 'eye' : 'eye-open'} form-right-container`" @click="showPwd" />
       </el-form-item>
+      <template v-if="isAdmin">
+        <el-form-item prop="phone">
+          <i class="iconfont icon-phone form-left-container" />
+          <el-input
+            ref="phone"
+            v-model="loginForm.phone"
+            placeholder="手机号"
+            name="phone"
+            type="text"
+            tabindex="1"
+            auto-complete="on"
+          />
+        </el-form-item>
+
+        <div style="display: flex;align-items: center">
+          <el-form-item prop="code" style="flex: 1">
+            <i class="iconfont icon-captcha form-left-container" />
+            <el-input
+              ref="code"
+              v-model="loginForm.code"
+              placeholder="验证码"
+              name="code"
+              type="text"
+              tabindex="1"
+              auto-complete="on"
+            />
+          </el-form-item>
+          <el-button class="code_btn" type="primary" :disabled="isSending" :loading="submitLoading" @click="sendCode">
+            {{ isSending ? `${countdown}s后重试` : "发送验证码" }}
+          </el-button>
+        </div>
+      </template>
 
       <el-button
         :loading="loading"
         type="primary"
         style="width: 100%; margin-top: 10px; background: #3d22d7"
         @click.native.prevent="handleLogin"
-        >登录</el-button
-      >
+      >登录</el-button>
     </el-form>
   </div>
 </template>
 
 <script>
-import { validUsername } from "@/utils/validate";
-const path = require("path");
-import { systemNoticeGetNotice } from "@/api/user_manage";
-import { getPicture } from "@/api/user";
+import { validUsername } from '@/utils/validate'
+const path = require('path')
+import { systemNoticeGetNotice } from '@/api/user_manage'
+import { getPicture, getCode } from '@/api/user'
 
 export default {
-  name: "Login",
+  name: 'Login',
   data() {
-    const validateUsername = (rule, value, callback) => {
-      if (!validUsername(value)) {
-        callback(new Error("Please enter the correct user name"));
+    const validatePhone = (rule, value, callback) => {
+      const phoneReg = /^1[3-9]\d{9}$/
+      if (!value || !phoneReg.test(value)) {
+        callback(new Error('请输入正确的手机号码'))
       } else {
-        callback();
+        callback()
       }
-    };
-    const validatePassword = (rule, value, callback) => {
-      if (value.length < 6) {
-        callback(new Error("The password can not be less than 6 digits"));
-      } else {
-        callback();
-      }
-    };
+    }
     return {
       loginForm: {
-        username: "",
-        password: "",
+        username: '',
+        password: '',
+        phone: null,
+        code: ''
       },
       rules: {
+        username: [{
+          required: true,
+          whitespace: true,
+          message: '请输入你的账号',
+          trigger: ['change', 'blur'] }],
         password: [
-          { required: true, message: "请输入密码", trigger: "blur" },
+          { required: true, message: '请输入密码', trigger: 'blur' },
           {
             pattern:
               /^(((?=.*\d)(?=.*[a-z])(?=.*[A-Z]))|((?=.*\d)(?=.*[a-z])(?=.*[~!@#$%^&*]))|((?=.*\d)(?=.*[A-Z])(?=.*[~!@#$%^&*]))|((?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*]))|((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*]))).{10,32}$/,
             message:
-              "必须大小写字母、数字、特殊字符,4种组合中至少满足3种,且密码长度在10-32位之间。若无法登录,请联系管理员!",
-          },
+              '必须大小写字母、数字、特殊字符,4种组合中至少满足3种,且密码长度在10-32位之间。若无法登录,请联系管理员!'
+          }
         ],
+        phone: [{ required: true, trigger: ['change', 'blur'], validator: validatePhone }],
+        code: [{
+          required: true,
+          whitespace: true,
+          message: '请输入验证码',
+          trigger: ['change', 'blur'] }]
       },
       loading: false,
-      passwordType: "password",
+      passwordType: 'password',
       redirect: undefined,
       // 公告数据
       noticeData: {},
-      title: "防控终端管理平台",
-      bg:'',
-      logo:'',
-    };
+      title: '防控终端管理平台',
+      bg: '',
+      logo: '',
+
+      /** 验证码开始 **/
+      isSending: false,
+      submitLoading: false,
+      countdown: 60,
+      timer: null
+      /** 验证码结束 **/
+    }
+  },
+  computed: {
+    isAdmin() {
+      return this.loginForm.username == 'admin'
+    }
   },
   watch: {
     $route: {
-      handler: function (route) {
-        this.redirect = route.query && route.query.redirect;
+      handler: function(route) {
+        this.redirect = route.query && route.query.redirect
       },
-      immediate: true,
-    },
+      immediate: true
+    }
   },
   created() {
-    this.getPicture();
-    this.systemNoticeGetNotice();
+    this.getPicture()
+    this.systemNoticeGetNotice()
   },
   methods: {
     // 获取背景
     getPicture() {
       getPicture().then((res) => {
-        this.title = res.data.title;
-        this.bg = res.data.bg;
-        this.logo = res.data.logo;
-        document.title=res.data.title
-        this.changeFavicon(res.data.favicon);
-      });
+        this.title = res.data.title
+        this.bg = res.data.bg
+        this.logo = res.data.logo
+        document.title = res.data.title
+        this.changeFavicon(res.data.favicon)
+      })
     },
     // 更改favicon.icon
     changeFavicon(link) {
-      let $favicon = document.querySelector('link[rel="icon"]');
+      let $favicon = document.querySelector('link[rel="icon"]')
       if ($favicon !== null) {
-        $favicon.href = link;
+        $favicon.href = link
       } else {
-        $favicon = document.createElement("link");
-        $favicon.rel = "icon";
-        $favicon.href = link;
-        document.head.appendChild($favicon);
+        $favicon = document.createElement('link')
+        $favicon.rel = 'icon'
+        $favicon.href = link
+        document.head.appendChild($favicon)
       }
     },
     // 获取公告栏
     systemNoticeGetNotice() {
       systemNoticeGetNotice().then((res) => {
-        this.noticeData = res.data;
-      });
+        this.noticeData = res.data
+      })
     },
     showPwd() {
-      if (this.passwordType === "password") {
-        this.passwordType = "";
+      if (this.passwordType === 'password') {
+        this.passwordType = ''
       } else {
-        this.passwordType = "password";
+        this.passwordType = 'password'
       }
       this.$nextTick(() => {
-        this.$refs.password.focus();
-      });
+        this.$refs.password.focus()
+      })
     },
     handleLogin() {
       this.$refs.loginForm.validate((valid) => {
         if (valid) {
-          this.loading = true;
+          this.loading = true
+          if (!this.isAdmin) {
+            this.loginForm.phone = ''
+            this.loginForm.code = ''
+          }
           this.$store
-            .dispatch("user/login", this.loginForm)
+            .dispatch('user/login', this.loginForm)
             .then(() => {
               if (this.$store.getters.role === 1) {
-                this.$router.push({ path: "/index" });
+                this.$router.push({ path: '/index' })
               } else if (this.$store.getters.role === 2) {
-                this.$router.push({ path: "/index" });
+                this.$router.push({ path: '/index' })
               } else if (this.$store.getters.role === 3) {
-                this.$router.push({ path: "/index" });
+                this.$router.push({ path: '/index' })
               } else if (this.$store.getters.role === 4) {
-                this.$router.push({ path: "/index" });
+                this.$router.push({ path: '/index' })
               } else if (this.$store.getters.role === 5) {
-                this.$router.push({ path: "/index" });
+                this.$router.push({ path: '/index' })
               } else if (this.$store.getters.role === 99) {
-                this.$router.push({ path: "/machine_list/index" });
+                this.$router.push({ path: '/machine_list/index' })
               }
-              this.loading = false;
+              this.loading = false
             })
             .catch(() => {
-              this.loading = false;
-            });
+              this.loading = false
+            })
         } else {
-          console.log("error submit!!");
-          return false;
+          console.log('error submit!!')
+          return false
         }
-      });
+      })
     },
-  },
-};
+    // 发送验证码
+    sendCode() {
+      this.$refs.loginForm.validateField(['phone'], (valid) => {
+        console.log('发送验证码校验', valid)
+        // 字段校验成功则返回空串
+        if (!valid) {
+          const _this = this
+          _this.submitLoading = true
+          getCode({
+            username: _this.loginForm.username,
+            phone: _this.loginForm.phone
+          }).then(res => {
+            this.$message({
+              type: 'success',
+              message: '发送验证码成功!'
+            })
+            _this.isSending = true
+            _this.countdown = 60
+            // 模拟请求后端发送验证码
+            console.log('验证码已发送至手机号:', _this.loginForm.phone)
+
+            _this.timer = setInterval(() => {
+              if (_this.countdown > 0) {
+                _this.countdown -= 1
+              } else {
+                clearInterval(_this.timer)
+                _this.isSending = false
+              }
+            }, 1000)
+          }).finally(() => {
+            _this.submitLoading = false
+          })
+        } else {
+          return
+        }
+      })
+    }
+  }
+}
 </script>
 
 <style lang="scss">
@@ -224,7 +307,7 @@ $cursor: #fff;
 .login-container {
   .el-input {
     display: inline-block;
-    height: 47px;
+    height: 46px;
     width: 85%;
 
     input {
@@ -234,7 +317,8 @@ $cursor: #fff;
       border-radius: 0px;
       padding: 12px 5px 12px 15px;
       color: black;
-      height: 47px;
+      height: 46px;
+      line-height: 46px;
       caret-color: black;
 
       &:-webkit-autofill {
@@ -249,6 +333,8 @@ $cursor: #fff;
     background: rgba(255, 255, 255, 0.8);
     border-radius: 5px;
     color: #454545;
+    height: 46px;
+    line-height: 46px;
   }
 }
 </style>
@@ -299,13 +385,27 @@ $light_gray: #eee;
       }
     }
   }
-
-  .svg-container {
-    padding: 6px 5px 6px 15px;
+  .form-left-container {
+    height: 46px;
+    width: 30px;
+    text-align: right;
     color: $dark_gray;
     vertical-align: middle;
+    display: inline-block;
+  }
+
+  .form-right-container {
+    height: 46px;
     width: 30px;
+    text-align: center;
+    color: $dark_gray;
+    vertical-align: middle;
     display: inline-block;
+    cursor: pointer;
+  }
+
+  .icon-eye {
+    font-size: 14px;
   }
 
   .title-container {
@@ -330,6 +430,26 @@ $light_gray: #eee;
     user-select: none;
   }
 
+  .code_btn {
+    margin-bottom: 22px;
+    width: 115px;
+    height: 46px;
+    margin-left: 10px;
+    font-size: 14px;
+    border-radius: 4px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    background: #3d22d7;
+    border-color: #3d22d7;
+  }
+
+  .code_btn.is-disabled{
+    background: #6B74C8;
+    border-color: #6B74C8;
+  }
+
   .logo {
     position: absolute;
     right: 50px;

Some files were not shown because too many files changed in this diff