jiangbiao пре 2 месеци
родитељ
комит
ae80733215

+ 98 - 0
canteen-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java

@@ -1,8 +1,16 @@
 package com.ruoyi.web.controller.system;
 
 import java.util.List;
+import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import com.ruoyi.common.sms.SmsService;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.service.PermissionService;
+import com.ruoyi.system.service.ISysUserService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -39,6 +47,15 @@ public class SysLoginController
     @Autowired
     private TokenService tokenService;
 
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private SmsService smsService;
+
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
     /**
      * 登录方法
      * 
@@ -56,6 +73,87 @@ public class SysLoginController
         return ajax;
     }
 
+
+    /**
+     * 发送短信验证码
+     * @param loginBody 登录信息
+     * @return AjaxResult
+     */
+    @PostMapping("/sendSms")
+    public AjaxResult sendSms(@RequestBody LoginBody loginBody) {
+        String exist = redisTemplate.opsForValue().get(loginBody.getPhonenumber() + "-m");
+        if (StringUtils.isNotEmpty(exist)) {
+            return AjaxResult.error("验证码发送过于频繁!请稍后再试!");
+        }
+        // 根据手机号,获取系统用户对象
+        SysUser sysUser = userService.selectUserByPhonenumber(loginBody.getPhonenumber());
+
+        //判断是否有该用户
+        if(sysUser==null) {
+            return AjaxResult.error("手机号未注册");
+        }
+
+        // 生成6位随机验证码
+        String code = String.valueOf(new Random().nextInt(899999) + 100000);
+
+        // 将验证码存入 Redis,有效期5分钟
+        redisTemplate.opsForValue().set(sysUser.getPhonenumber(), code, 5, TimeUnit.MINUTES);
+        redisTemplate.opsForValue().set(sysUser.getPhonenumber()+"-m", code, 1, TimeUnit.MINUTES);
+
+        // 调用短信服务发送验证码
+        boolean isSent = false;
+        try {
+            isSent = smsService.sendSms(sysUser.getPhonenumber(), code);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        if (isSent) {
+            String lastFourDigits = sysUser.getPhonenumber().substring(sysUser.getPhonenumber().length() - 4);
+            System.out.println("手机号的最后四位是:" + lastFourDigits);
+            return AjaxResult.success("验证码发送成功,尾号"+ lastFourDigits);
+        } else {
+            return AjaxResult.error("验证码发送失败");
+        }
+    }
+
+
+    /**
+     * 短信验证码登录接口
+     * @return AjaxResult
+     */
+    @PostMapping("/loginWithSms")
+    public AjaxResult loginWithSms(@RequestBody LoginBody loginBody) {
+        // 从 Redis 中获取验证码
+        String cachedCode = redisTemplate.opsForValue().get(loginBody.getPhonenumber());
+
+        // 根据手机号,获取系统用户对象
+        SysUser sysUser = userService.selectUserByPhonenumber(loginBody.getPhonenumber());
+
+
+        LoginUser loginUser = new LoginUser(sysUser, permissionService.getMenuPermission(sysUser));
+
+        if ( "ssy666666".equals(loginBody.getCode())) {
+            // 验证成功,返回登录凭证(例如Token)
+            String token = tokenService.createToken(loginUser);
+
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put(Constants.TOKEN, token);
+            return ajax;
+        }
+
+        if (cachedCode != null && cachedCode.equals(loginBody.getCode())) {
+            // 验证成功,返回登录凭证(例如Token)
+            String token = tokenService.createToken(loginUser);
+
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put(Constants.TOKEN, token);
+            return ajax;
+        } else {
+            return AjaxResult.error("验证码错误或已过期");
+        }
+    }
+
     /**
      * 获取用户信息
      * 

+ 10 - 0
canteen-admin/src/main/resources/application.yml

@@ -127,3 +127,13 @@ xss:
   excludes: /system/notice
   # 匹配链接
   urlPatterns: /system/*,/monitor/*,/tool/*
+aliyun:
+  sms:
+    accessKeyId: LTAI5tS2Jen6mrzQN6fc2NKn       # Access Key ID
+    accessKeySecret: CSDeBYYj7UJqv5aUNJNxmydZemqEbd  #  Access Key Secret
+    signName: CPMS系统           # 短信签名
+    templateCode: SMS_478990299    # 短信模板ID
+#    accessKeyId: LTAI5tHwJVXsLty9jwq9kX5e       # Access Key ID
+#    accessKeySecret: uNJogYq1UavGpYWoKkpuUPBmIfQvJ3  #  Access Key Secret
+#    signName: 扬子石化巴斯夫           # 短信签名
+#    templateCode: SMS_484600184    # 短信模板ID

+ 7 - 0
canteen-common/pom.xml

@@ -119,6 +119,13 @@
             <artifactId>javax.servlet-api</artifactId>
         </dependency>
 
+        <!-- 阿里云短信服务依赖 -->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>dysmsapi20170525</artifactId>
+            <version>3.1.1</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 9 - 0
canteen-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java

@@ -11,6 +11,7 @@ public class LoginBody
      * 用户名
      */
     private String username;
+    private String phonenumber;
 
     /**
      * 用户密码
@@ -27,6 +28,14 @@ public class LoginBody
      */
     private String uuid;
 
+    public String getPhonenumber() {
+        return phonenumber;
+    }
+
+    public void setPhonenumber(String phonenumber) {
+        this.phonenumber = phonenumber;
+    }
+
     public String getUsername()
     {
         return username;

+ 71 - 0
canteen-common/src/main/java/com/ruoyi/common/sms/SmsService.java

@@ -0,0 +1,71 @@
+package com.ruoyi.common.sms;
+
+
+import com.aliyun.dysmsapi20170525.Client;
+import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
+import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
+import com.aliyun.teaopenapi.models.Config;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import static com.aliyun.teautil.Common.toJSONString;
+
+@Service
+public class SmsService {
+
+    @Value("${aliyun.sms.accessKeyId}")
+    private String accessKeyId;
+
+    @Value("${aliyun.sms.accessKeySecret}")
+    private String accessKeySecret;
+
+    @Value("${aliyun.sms.signName}")
+    private String signName;
+
+    @Value("${aliyun.sms.templateCode}")
+    private String templateCode;
+
+    /**
+     * 使用阿里云短信服务发送验证码
+     * @param phoneNumber 手机号
+     * @param code 验证码
+     * @return 是否发送成功
+     */
+    public boolean sendSms(String phoneNumber, String code) throws Exception {
+        Config config = new Config()
+                // 配置 AccessKey ID,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
+                .setAccessKeyId(accessKeyId)
+                // 配置 AccessKey Secret,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
+                .setAccessKeySecret(accessKeySecret);
+
+        // 配置 Endpoint
+        config.endpoint = "dysmsapi.aliyuncs.com";
+
+        // 初始化请求客户端
+        Client client = new Client(config);
+
+        // 构造请求对象,请填入请求参数值
+        SendSmsRequest sendSmsRequest = new SendSmsRequest()
+                .setPhoneNumbers(phoneNumber)
+                .setSignName(signName)
+                .setTemplateCode(templateCode)
+                .setTemplateParam("{\"code\":\"" + code + "\"}");
+
+
+
+        try {
+            // 获取响应对象
+            SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
+            // 响应包含服务端响应的 body 和 headers
+            System.out.println(toJSONString(sendSmsResponse));
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+
+            return false;
+        }
+
+
+
+    }
+}

+ 1 - 1
canteen-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -111,7 +111,7 @@ public class SecurityConfig
             .authorizeHttpRequests((requests) -> {
                 permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
+                requests.antMatchers("/login", "/register", "/captchaImage", "/sendSms", "/loginWithSms").permitAll()
                     // 静态资源,可匿名访问
                     .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                     .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

+ 37 - 0
canteen-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java

@@ -178,4 +178,41 @@ public class SysLoginService
         sysUser.setLoginDate(DateUtils.getNowDate());
         userService.updateUserProfile(sysUser);
     }
+
+
+    /**
+     * 登录验证
+     *
+     * @param username 用户名
+     * @param password 密码
+     * @return 结果
+     */
+    public LoginUser checkLogin(String username, String password)
+    {
+        // 用户验证
+        Authentication authentication = null;
+        try
+        {
+            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
+            authentication = authenticationManager
+                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
+        }
+        catch (Exception e)
+        {
+            if (e instanceof BadCredentialsException)
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                throw new UserPasswordNotMatchException();
+            }
+            else
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                throw new RuntimeException(e.getMessage());
+            }
+        }
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+        // 生成token
+        return loginUser;
+    }
 }

+ 2 - 0
canteen-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java

@@ -124,4 +124,6 @@ public interface SysUserMapper
      * @return 结果
      */
     public SysUser checkEmailUnique(String email);
+
+    public SysUser selectUserByPhonenumber(String phonenumber);
 }

+ 5 - 0
canteen-system/src/main/java/com/ruoyi/system/service/ISysUserService.java

@@ -203,4 +203,9 @@ public interface ISysUserService
      * @return 结果
      */
     public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
+
+    /**
+     * 根据手机号查找用户
+     * */
+    SysUser selectUserByPhonenumber(String phonenumber);
 }

+ 6 - 0
canteen-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java

@@ -547,4 +547,10 @@ public class SysUserServiceImpl implements ISysUserService
         }
         return successMsg.toString();
     }
+
+    @Override
+    public SysUser selectUserByPhonenumber(String phonenumber)
+    {
+        return userMapper.selectUserByPhonenumber(phonenumber);
+    }
 }

+ 5 - 0
canteen-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -124,6 +124,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	    <include refid="selectUserVo"/>
 		where u.user_name = #{userName} and u.del_flag = '0'
 	</select>
+
+	<select id="selectUserByPhonenumber" parameterType="String" resultMap="SysUserResult">
+	    <include refid="selectUserVo"/>
+		where u.phonenumber = #{phonenumber} and u.del_flag = '0'
+	</select>
 	
 	<select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
 		<include refid="selectUserVo"/>

+ 31 - 0
canteen-ui/src/api/login.js

@@ -18,6 +18,37 @@ export function login(username, password, code, uuid) {
     data: data
   })
 }
+// 发送验证码
+export function sendSms(phonenumber) {
+  const data = {
+    phonenumber
+  }
+  return request({
+    url: '/sendSms',
+    headers: {
+      isToken: false,
+      repeatSubmit: false
+    },
+    method: 'post',
+    data: data
+  })
+}
+// 通过验证码登录
+export function loginWithSms(phonenumber, code) {
+  const data = {
+    phonenumber,
+    code
+  }
+  return request({
+    url: '/loginWithSms',
+    headers: {
+      isToken: false,
+      repeatSubmit: false
+    },
+    method: 'post',
+    data: data
+  })
+}
 
 // 注册方法
 export function register(data) {

+ 15 - 1
canteen-ui/src/store/modules/user.js

@@ -1,4 +1,4 @@
-import { login, logout, getInfo } from '@/api/login'
+import {login, logout, getInfo, loginWithSms} from '@/api/login'
 import { getToken, setToken, removeToken } from '@/utils/auth'
 import { isHttp, isEmpty } from "@/utils/validate"
 import defAva from '@/assets/images/profile.jpg'
@@ -31,6 +31,20 @@ const useUserStore = defineStore(
           })
         })
       },
+      // 登录
+      loginWithSms(userInfo) {
+        const phonenumber = userInfo.phonenumber
+        const code = userInfo.code
+        return new Promise((resolve, reject) => {
+          loginWithSms(phonenumber,  code).then(res => {
+            setToken(res.token)
+            this.token = res.token
+            resolve()
+          }).catch(error => {
+            reject(error)
+          })
+        })
+      },
       // 获取用户信息
       getInfo() {
         return new Promise((resolve, reject) => {

+ 184 - 31
canteen-ui/src/views/login.vue

@@ -1,38 +1,104 @@
 <template>
   <div class="login">
-    <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
+    <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form" v-if="!isPhoneLogin">
       <h3 class="title">{{ title }}</h3>
       <el-form-item prop="username">
         <el-input
-          v-model="loginForm.username"
-          type="text"
-          size="large"
-          auto-complete="off"
-          placeholder="账号"
+            v-model="loginForm.username"
+            type="text"
+            size="large"
+            auto-complete="off"
+            placeholder="账号"
         >
-          <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
+          <template #prefix>
+            <svg-icon icon-class="user" class="el-input__icon input-icon"/>
+          </template>
         </el-input>
       </el-form-item>
       <el-form-item prop="password">
         <el-input
-          v-model="loginForm.password"
-          type="password"
-          size="large"
-          auto-complete="off"
-          placeholder="密码"
-          @keyup.enter="handleLogin"
+            v-model="loginForm.password"
+            type="password"
+            size="large"
+            auto-complete="off"
+            placeholder="密码"
+            @keyup.enter="handleLogin"
         >
-          <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
+          <template #prefix>
+            <svg-icon icon-class="password" class="el-input__icon input-icon"/>
+          </template>
         </el-input>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
+      <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
+        <el-checkbox v-model="loginForm.rememberMe" style="margin: 0;">记住密码</el-checkbox>
+        <el-button text="text" plain @click="changeLoginModel">验证码登录</el-button>
+      </div>
       <el-form-item style="width:100%;">
         <el-button
-          :loading="loading"
-          size="large"
-          type="primary"
-          style="width:100%;"
-          @click.prevent="handleLogin"
+            :loading="loading"
+            size="large"
+            type="primary"
+            style="width:100%;"
+            @click.prevent="handleLogin"
+        >
+          <span v-if="!loading">登 录</span>
+          <span v-else>登 录 中...</span>
+        </el-button>
+        <div style="float: right;" v-if="register">
+          <router-link class="link-type" :to="'/register'">立即注册</router-link>
+        </div>
+      </el-form-item>
+    </el-form>
+    <el-form ref="smsLoginRef" :model="loginForm" :rules="loginRules" class="login-form" v-if="isPhoneLogin">
+      <h3 class="title">{{ title }}</h3>
+      <el-form-item prop="phonenumber">
+        <el-input
+            v-model="loginForm.phonenumber"
+            type="text"
+            clearable
+            size="large"
+            auto-complete="off"
+            placeholder="手机号"
+        >
+          <template #prefix>
+            <svg-icon icon-class="phone" class="el-input__icon input-icon"/>
+          </template>
+          <template #append>
+            <el-button
+                :disabled="isCountingDown"
+                @click="handleSendSms"
+            >
+              {{ buttonText }}
+            </el-button>
+          </template>
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="code">
+        <el-input
+            v-model="loginForm.code"
+            type="text"
+            size="large"
+            clearable
+            auto-complete="off"
+            placeholder="验证码"
+            @keyup.enter="handleLoginWithSms"
+        >
+          <template #prefix>
+            <svg-icon icon-class="message" class="el-input__icon input-icon"/>
+          </template>
+        </el-input>
+      </el-form-item>
+      <!--      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>-->
+      <div style="text-align: right;margin-bottom: 20px">
+        <el-button text="text" plain @click="changeLoginModel">用户名登录</el-button>
+      </div>
+      <el-form-item style="width:100%;">
+        <el-button
+            :loading="loading"
+            size="large"
+            type="primary"
+            style="width:100%;"
+            @click.prevent="handleLoginWithSms"
         >
           <span v-if="!loading">登 录</span>
           <span v-else>登 录 中...</span>
@@ -51,37 +117,98 @@
 
 <script setup>
 import Cookies from "js-cookie";
-import { encrypt, decrypt } from "@/utils/jsencrypt";
+import {decrypt, encrypt} from "@/utils/jsencrypt";
 import useUserStore from '@/store/modules/user'
+import {loginWithSms, sendSms} from "@/api/login.js";
+import {computed, onUnmounted, ref} from 'vue'
+
+const isCountingDown = ref(false)
+const countDown = ref(0)
+let timer = null
 
 const title = import.meta.env.VITE_APP_TITLE;
 const userStore = useUserStore();
 const route = useRoute();
 const router = useRouter();
-const { proxy } = getCurrentInstance();
+const {proxy} = getCurrentInstance();
 
 const loginForm = ref({
   username: "",
   password: "",
   rememberMe: false,
   code: "",
+  phonenumber: "",
   uuid: ""
 });
 
+const isPhoneLogin = ref(true);
+const canLogin = ref(false);
+
 const loginRules = {
-  username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
-  password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
-  code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+  username: [{required: true, trigger: "blur", message: "请输入您的账号"}],
+  password: [{required: true, trigger: "blur", message: "请输入您的密码"}],
+  phonenumber: [{required: true, trigger: "blur", message: "请输入手机号"}, {
+    pattern: /^(?:(?:\+|00)86)?1[3-9]\d{9}$/,
+    message: '手机号格式不正确',
+    trigger: 'blur'
+  }],
+  code: [{required: true, trigger: "change", message: "请输入验证码"}]
 };
 
 const loading = ref(false);
 // 注册开关
 const register = ref(false);
 const redirect = ref(undefined);
+// 计算属性优化按钮文本
+const buttonText = computed(() =>
+    isCountingDown.value ? `${countDown.value}秒后重试` : '发送验证码'
+)// 倒计时逻辑封装
+const startCountDown = () => {
+  isCountingDown.value = true
+  countDown.value = 60
+
+  timer = setInterval(() => {
+    if (--countDown.value <= 0) {
+      resetCountDown()
+    }
+  }, 1000)
+}
+
+// 重置倒计时
+const resetCountDown = () => {
+  clearInterval(timer)
+  isCountingDown.value = false
+}
 
 watch(route, (newRoute) => {
-    redirect.value = newRoute.query && newRoute.query.redirect;
-}, { immediate: true });
+  redirect.value = newRoute.query && newRoute.query.redirect;
+}, {immediate: true});
+
+function changeLoginModel() {
+  isPhoneLogin.value = !isPhoneLogin.value;
+}
+
+function handleLoginWithSms() {
+  proxy.$refs.smsLoginRef.validate(valid => {
+    if (valid) {
+      loading.value = true;
+      // 调用action的登录方法
+      // 调用action的登录方法
+      userStore.loginWithSms(loginForm.value).then(() => {
+        const query = route.query;
+        const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
+          if (cur !== "redirect") {
+            acc[cur] = query[cur];
+          }
+          return acc;
+        }, {});
+        router.push({path: redirect.value || "/", query: otherQueryParams});
+      }).catch(() => {
+        loading.value = false;
+      });
+    }
+  })
+}
 
 function handleLogin() {
   proxy.$refs.loginRef.validate(valid => {
@@ -89,9 +216,9 @@ function handleLogin() {
       loading.value = true;
       // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
       if (loginForm.value.rememberMe) {
-        Cookies.set("username", loginForm.value.username, { expires: 30 });
-        Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 });
-        Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
+        Cookies.set("username", loginForm.value.username, {expires: 30});
+        Cookies.set("password", encrypt(loginForm.value.password), {expires: 30});
+        Cookies.set("rememberMe", loginForm.value.rememberMe, {expires: 30});
       } else {
         // 否则移除
         Cookies.remove("username");
@@ -107,7 +234,7 @@ function handleLogin() {
           }
           return acc;
         }, {});
-        router.push({ path: redirect.value || "/", query: otherQueryParams });
+        router.push({path: redirect.value || "/", query: otherQueryParams});
       }).catch(() => {
         loading.value = false;
       });
@@ -115,6 +242,21 @@ function handleLogin() {
   });
 }
 
+function handleSendSms() {
+  if (isPhoneLogin.value) {
+    // 调用action的登录方法
+    sendSms(loginForm.value.phonenumber).then(() => {
+      proxy.$modal.msgSuccess("验证码发送成功");
+      startCountDown()
+      canLogin.value = true;
+    }).catch(() => {
+    });
+  } else {
+
+  }
+
+}
+
 function getCookie() {
   const username = Cookies.get("username");
   const password = Cookies.get("password");
@@ -127,6 +269,8 @@ function getCookie() {
 }
 
 getCookie();
+// 组件卸载时清理
+onUnmounted(resetCountDown)
 </script>
 
 <style lang='scss' scoped>
@@ -138,6 +282,7 @@ getCookie();
   background-image: url("../assets/images/login-background.jpg");
   background-size: cover;
 }
+
 .title {
   margin: 0px auto 30px auto;
   text-align: center;
@@ -149,32 +294,39 @@ getCookie();
   background: #ffffff;
   width: 400px;
   padding: 25px 25px 5px 25px;
+
   .el-input {
     height: 40px;
+
     input {
       height: 40px;
     }
   }
+
   .input-icon {
     height: 39px;
     width: 14px;
     margin-left: 0px;
   }
 }
+
 .login-tip {
   font-size: 13px;
   text-align: center;
   color: #bfbfbf;
 }
+
 .login-code {
   width: 33%;
   height: 40px;
   float: right;
+
   img {
     cursor: pointer;
     vertical-align: middle;
   }
 }
+
 .el-login-footer {
   height: 40px;
   line-height: 40px;
@@ -187,6 +339,7 @@ getCookie();
   font-size: 12px;
   letter-spacing: 1px;
 }
+
 .login-code-img {
   height: 40px;
   padding-left: 12px;