|
@@ -1,10 +1,10 @@
|
|
|
<template>
|
|
|
<div class="login-container">
|
|
|
- <img class="bg" src="../../assets/bg1.png" alt="" />
|
|
|
+ <img class="bg" src="../../assets/bg1.png" alt="">
|
|
|
<!-- <img class="logo" :src="logo" alt="" /> -->
|
|
|
<el-form
|
|
|
- :rules="rules"
|
|
|
ref="loginForm"
|
|
|
+ :rules="rules"
|
|
|
:model="loginForm"
|
|
|
class="login-form"
|
|
|
auto-complete="on"
|
|
@@ -15,9 +15,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"
|
|
@@ -30,9 +28,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"
|
|
@@ -44,109 +40,198 @@
|
|
|
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 { validUsername } from '@/utils/validate'
|
|
|
+const path = require('path')
|
|
|
+import { 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,
|
|
|
- title: "OTA中台",
|
|
|
- };
|
|
|
+ title: 'OTA中台',
|
|
|
+
|
|
|
+ /** 验证码开始 **/
|
|
|
+ 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() {},
|
|
|
methods: {
|
|
|
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.$router.push({ path: "/index" });
|
|
|
// return
|
|
|
- this.$refs.loginForm.validate(async (valid) => {
|
|
|
+ this.$refs.loginForm.validate(async(valid) => {
|
|
|
if (valid) {
|
|
|
- this.loading = true;
|
|
|
+ this.loading = true
|
|
|
try {
|
|
|
- await this.$store.dispatch("user/login", this.loginForm);
|
|
|
- this.$router.push({ path: "/index" });
|
|
|
- this.loading = false;
|
|
|
+ if (!this.isAdmin) {
|
|
|
+ this.loginForm.phone = ''
|
|
|
+ this.loginForm.code = ''
|
|
|
+ }
|
|
|
+ await this.$store.dispatch('user/login', this.loginForm)
|
|
|
+ this.$router.push({ path: '/index' })
|
|
|
+ this.loading = false
|
|
|
} catch (e) {
|
|
|
- await this.$store.dispatch("user/resetToken");
|
|
|
- this.loading = false;
|
|
|
+ await this.$store.dispatch('user/resetToken')
|
|
|
+ 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">
|
|
@@ -167,7 +252,7 @@ $cursor: #fff;
|
|
|
.login-container {
|
|
|
.el-input {
|
|
|
display: inline-block;
|
|
|
- height: 47px;
|
|
|
+ height: 46px;
|
|
|
width: 85%;
|
|
|
|
|
|
input {
|
|
@@ -177,7 +262,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 {
|
|
@@ -192,6 +278,8 @@ $cursor: #fff;
|
|
|
background: rgba(255, 255, 255, 0.8);
|
|
|
border-radius: 5px;
|
|
|
color: #454545;
|
|
|
+ height: 46px;
|
|
|
+ line-height: 46px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
@@ -243,12 +331,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 {
|
|
@@ -273,6 +376,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;
|