如何使用阿里云短信服务实现登录页面,手机验证码登录?

1:个人如何使用阿里云短信服务?

2022如何使用个人阿里云短信服务?_linxiMY的博客-CSDN博客添加完成之后,等待审核!一般2个小时就会出来审核结果了,这里我因为注册申请时填写规则有误,足足审核了7次才通过!点击进来以后,按照要求填写:因为一个账号只能选购一种,所以我这里就没法仔细演示了。然后点击添加即可,一把2-3个小时就可以申请出结果了。ConstantPropertiesUtils 工具类。点击登录阿里云短信服务控制台--->点击。3:创建一个SpringBoot 启动类。将下面的服务地址改为自己对应的地址。AccessKey 保存下来!4:添加一个配置工具类类。开启启动类调接口测试。https://blog.csdn.net/XikYu/article/details/127617049?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168232320316800192242795%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=168232320316800192242795&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-127617049-null-null.blog_rank_default&utm_term=%E9%98%BF%E9%87%8C%E4%BA%91&spm=1018.2226.3001.4450

2:直接上代码

2.1:建表SQL

CREATE TABLE `sys_user`
(
    `id`          varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'id',
    `username`    varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
    `password`    varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',
    `nickname`    varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '昵称',
    `email`       varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱',
    `phone`       varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话',
    `address`     varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地址',
    `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `avatarUrl`   varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2.2:后端代码

引入pom.xml 依 赖:

<dependencies>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
    </dependency>
</dependencies>

yml 文件:

server:
  port: 9999
spring:
  application:
    name: demo-end
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/数据库?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: root
  redis:
    host: ip地址
    port: 6379
    lettuce:
      pool:
        max-active: 8 # ????
        max-idle: 8 # ??????
        min-idle: 0 # ??????
        max-wait: 100ms # ??????
mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.xi.demoend.entity

application.properties:


aliyun.sms.regionId=default
aliyun.sms.accessKeyId=LTAI5tBP98NtTK3gC5mgRQBz
aliyun.sms.secret=gH1w8F0jEWVXSiClmAAnowRw93YTFg

common公共包下的类:

 全局统一返回结果:

package com.xialj.demoend.common;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @Author 
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:  全局统一返回结果
 * @Version V1.0
 */
@Data
@ApiModel(value = "全局统一返回结果")
@SuppressWarnings("all")
public class Result<T> {

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private T data;
    private Long total;

    public Result(){}

    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }

    public static <T> Result<T> build(Integer code, String message) {
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static<T> Result<T> ok(){
        return Result.ok(null);
    }

    /**
     * 操作成功
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static<T> Result<T> fail(){
        return Result.fail(null);
    }

    /**
     * 操作失败
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }

    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }

    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }

    public boolean isOk() {
        if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
            return true;
        }
        return false;
    }
}

 统一返回结果状态信息类:

package com.xialj.demoend.common;

import lombok.Getter;

/**
   * @Author 
   * @Date Created in  2023/2/23 17:25
   * @DESCRIPTION:  统一返回结果状态信息类
   * @Version V1.0
   */
@Getter
@SuppressWarnings("all")
public enum ResultCodeEnum {

    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    PARAM_ERROR( 202, "参数不正确"),
    SERVICE_ERROR(203, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    DATA_UPDATE_ERROR(205, "数据版本异常"),

    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),

    CODE_ERROR(210, "验证码错误"),
//    LOGIN_MOBLE_ERROR(211, "账号不正确"),
    LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手机号码格式不正确"),
    REGISTER_MOBLE_ERROR_NULL(214, "手机号码为空"),

    LOGIN_AURH(214, "需要登录"),
    LOGIN_ACL(215, "没有权限"),

    URL_ENCODE_ERROR( 216, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"),
    FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"),
    FETCH_USERINFO_ERROR( 219, "获取用户信息失败"),
    //LOGIN_ERROR( 23005, "登录失败"),

    PAY_RUN(220, "支付中"),
    CANCEL_ORDER_FAIL(225, "取消订单失败"),
    CANCEL_ORDER_NO(225, "不能取消预约"),

    HOSCODE_EXIST(230, "医院编号已经存在"),
    NUMBER_NO(240, "可预约号不足"),
    TIME_NO(250, "当前时间不可以预约"),

    SIGN_ERROR(300, "签名错误"),
    HOSPITAL_OPEN(310, "医院未开通,暂时不能访问"),
    HOSPITAL_LOCK(320, "医院被锁定,暂时不能访问"),
    HOSPITAL_LOCKKEY(330,"医院对应key不一致")
    ;

    private Integer code;
    private String message;

    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

untils包下的工具类:

ConstantPropertiesUtils 用来读取 application.properties文件中的配置

package com.xialj.demoend.utils;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * @Author 
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:
 * @Version V1.0
 */
@Component
public class ConstantPropertiesUtils implements InitializingBean {

    //InitializingBean  初始化bean  让spring 容器一初始化就加载
    @Value("${aliyun.sms.regionId}")
    private String regionId;

    @Value("${aliyun.sms.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.sms.secret}")
    private String secret;

    public static String REGION_Id;
    public static String ACCESS_KEY_ID;
    public static String SECRECT;

    @Override
    public void afterPropertiesSet() throws Exception {
        REGION_Id=regionId;
        ACCESS_KEY_ID=accessKeyId;
        SECRECT=secret;
    }
}

 RandomUtil 工具类用来生成6位验证码:

package com.xialj.demoend.utils;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
/**
 * @Author 
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:
 * @Version V1.0
 */
@SuppressWarnings("ALL")
public class RandomUtil {
    private static final Random random = new Random();

    private static final DecimalFormat fourdf = new DecimalFormat("0000");

    private static final DecimalFormat sixdf = new DecimalFormat("000000");

    public static String getFourBitRandom() {
        return fourdf.format(random.nextInt(10000));
    }

    public static String getSixBitRandom() {
        return sixdf.format(random.nextInt(1000000));
    }

    /**
     * 给定数组,抽取n个数据
     * @param list
     * @param n
     * @return
     */
    public static ArrayList getRandom(List list, int n) {

        Random random = new Random();

        HashMap<Object, Object> hashMap = new HashMap<Object, Object>();

// 生成随机数字并存入HashMap
        for (int i = 0; i < list.size(); i++) {

            int number = random.nextInt(100) + 1;

            hashMap.put(number, i);
        }

// 从HashMap导入数组
        Object[] robjs = hashMap.values().toArray();

        ArrayList r = new ArrayList();

// 遍历数组并打印数据
        for (int i = 0; i < n; i++) {
            r.add(list.get((int) robjs[i]));
            System.out.print(list.get((int) robjs[i]) + "\t");
        }
        System.out.print("\n");
        return r;
    }
}

User实体类:(实现了简单的手机验证码登录+email邮箱登录)

package com.xialj.demoend.entity;

import com.alibaba.druid.sql.visitor.functions.Insert;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Author 
 * @Date Created in  2023/2/24 13:07
 * @DESCRIPTION:   User 实体类
 * @Version V1.0
 */

@Data
public class User extends PageQuery implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * id
     */
    private String id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 昵称
     */
    private String nickname;

    /**
     * 邮箱
     */
    @ApiModelProperty(value = "联系人邮箱")
    @NotBlank(message = "邮箱不能为空", groups = {Insert.class})
    @NotNull(message = "邮箱不能为空", groups = {Insert.class})
    @Pattern(regexp = ".+@.+\\.com$", message = "Email格式不正确")
    private String email;

    /**
     * 电话
     */
    @ApiModelProperty(value = "联系人电话")
    @NotBlank(message = "手机号码不能为空", groups = {Insert.class})
    @NotNull(message = "手机号不能为空", groups = {Insert.class})
    @Length(min = 11, max = 11, message = "手机号只能为11位")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
    private String phone;

    /**
     * 地址
     */
    private String address;

    /**
     * 验证码
     */
    private Integer code;

    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date createTime;

    /**
     * 头像
     */
    private String avatarUrl;
}

MsmApiController:用来实现发送验证码的接口

package com.xialj.demoend.controller;


import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xialj.demoend.common.Result;
import com.xialj.demoend.common.ResultCodeEnum;
import com.xialj.demoend.common.paramCommon;
import com.xialj.demoend.entity.User;
import com.xialj.demoend.service.MsmService;
import com.xialj.demoend.utils.JsonSerializer;
import com.xialj.demoend.utils.RandomUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.mail.MessagingException;
import javax.validation.constraints.Email;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
 * @Author xlj
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:  主要是为了实现邮箱发送验证码,以及手机发送验证码登录
 * @Version V1.0
 */
@RestController
@RequestMapping("/api/msm")
@SuppressWarnings("ALL")
@Slf4j
@CrossOrigin
public class MsmApiController {
    @Autowired
    private MsmService msmService;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    //将手机验证码存放到redis  中,并设置过期时间
    @ApiOperation(value = "发送手机验证码")
    @PostMapping("sendPhoneCode")
    public Result sendCode(@RequestBody(required = true) @Validated User user){
        String phoneNum = user.getPhone();
        // phone  作为redis  中的key,  code  作为redis  中的value值
        String code = redisTemplate.opsForValue().get(phoneNum);
        if (!StringUtils.isEmpty(code)) {
            //这里为什么从redis 拿取 验证码  我理解的是 ,因为redis 验证码我们给他设置了时间限制,所以在规定时间内,验证码
            //可以多次使用,一旦时间到期之后,我们就需要从新生成6位数的验证码了。
            return Result.ok(code);
        }
        //生成六位验证码
        code = RandomUtil.getSixBitRandom();
        //调用service 方法,整合阿里云短信服务进行发送
        Boolean isSend = msmService.send(phoneNum,code);
        //返回的Boolean 值进行判断 ,如果发送信息成功,即存入到redis 中,如果没有则提示验证码发送失败
        if (isSend) {
            //放到redis中规定时间内有效
            redisTemplate.opsForValue().set(phoneNum,code,1, TimeUnit.MINUTES);
            redisTemplate.setDefaultSerializer(new JsonSerializer<>());
//            redisTemplate.opsForValue().set(phoneNum,code);
            String codeMessage = redisTemplate.opsForValue().get(phoneNum);
            Set<String> allKeys = redisTemplate.keys("*");
            for (String key : allKeys) {
                System.out.println(key);
                System.out.println(key.getClass().getName());
            }
            log.info("当前存储的验证码为:{}",codeMessage);
            return Result.ok(code);
        } else {
            return Result.fail().message(paramCommon.FAIL_MESSAGE);
        }
    }
}

MsmServiceImpl实现类:

package com.hospital.service.impl;
 
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.hospital.service.MsmService;
import com.hospital.utils.ConstantPropertiesUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
 
import java.util.HashMap;
import java.util.Map;
 
@Service
public class MsmServiceImpl implements MsmService {
    //根据手机号,存入验证码
    @Override
    public Boolean send(String phone, String code) {
        //判断手机号是否为空
        if (StringUtils.isEmpty(phone)) {
            return false;
        }
        //整合阿里云的短信服务
        DefaultProfile profile = DefaultProfile.
                getProfile(ConstantPropertiesUtils.REGION_Id,
                        ConstantPropertiesUtils.ACCESS_KEY_ID,
                        ConstantPropertiesUtils.SECRECT);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        //request.setProtocol(ProtocolType.HTTPS);
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
//        request.setSysAction();
 
        //手机号
        request.putQueryParameter("PhoneNumbers", phone);
        //签名名称
        request.putQueryParameter("SignName", "自己申请的短信签名");
        //模板code
        request.putQueryParameter("TemplateCode", "短信模板CODE");
        //验证码  使用json格式   {"code":"123456"}
        Map<String,Object> param = new HashMap();
        param.put("code",code);
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));
        //调用方法进行短信发送
        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            return response.getHttpResponse().isSuccess();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }
}

LoginController登录接口:(通过@Validated  对手机号,邮箱等参数进行校验)

package com.xialj.demoend.controller;

import cn.hutool.core.util.StrUtil;
import com.xialj.demoend.common.Result;
import com.xialj.demoend.entity.User;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * @Author 
 * @Date Created in  2023/3/18 14:30
 * @DESCRIPTION:
 * @Version V1.0
 */
@RestController
@RequestMapping("/user/login")
@Slf4j
@CrossOrigin
public class LoginController {
   @Autowired
   private RedisTemplate<String,String> redisTemplate;
   @ApiOperation("手机验证码登录接口")
   @PostMapping("/phoneCode")
   @SuppressWarnings("all")
   public Result phoneCodeLogin(@RequestBody @Validated User user) throws Throwable {
      Optional.ofNullable(user.getPhone()).orElseThrow((Supplier<Throwable>) () -> new RuntimeException("手机号码为null"));
      String phone = user.getPhone();
      log.info("当前获取的手机号为:{}",phone);
      //从redis中获取手机验证码
      String userPhoneKey = redisTemplate.opsForValue().get(phone);
      if (StringUtils.isEmpty(userPhoneKey)) {
         return Result.fail("手机验证码有误");
      }
      if (!userPhoneKey.equals(String.valueOf(user.getCode()))) {
         return Result.fail("手机验证码有误");
      }
      return Result.ok("登录成功");
   }
}

前端vue代码:

<template>
  <div class="cont1" id="mainContainer" v-title data-title="若梦管理系统">
    <p class="tip">Click on button in image container</p>
    <div class="cont" style="border-radius: 15px">
      <div class="form sign-in" style="line-height: 50px;">
        <h2 style="margin-top: 1px">后台管理系统</h2>
        <el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="100px">
          <el-form-item label="手机号" prop="phone" style="width: 50%;margin-left: 110px;margin-top: 80px">
            <el-input v-model.number="formData.phone" placeholder="请输入手机号" :maxlength="11" show-word-limit
                      clearable
                      prefix-icon='el-icon-mobile-phone' :style="{width: '200px'}"></el-input>
          </el-form-item>
          <el-form-item label="验证码" prop="yzm" style="width: 50%;margin-left: 110px;margin-top: 50px">
            <el-input v-model.number="formData.yzm" :maxlength="6" :minlength="6"
                      clearable show-word-limit
                      prefix-icon='el-icon-chat-round'
                      oninput="value=value.replace(/[^0-9.]/g,'')"
                      :style="{width: '200px'}">
              <template #append >
                <el-button class="test" style="width: 5px;
                margin-right: 10px;
                text-align: center;
                background-color: inherit;"
                            type="danger"
                            :disabled="remainingTime > 0"
                           @click="startTimer">
                  {{ remainingTime > 0 ? '('+remainingTime+'s)' : '获取' }}
                </el-button>
              </template>
            </el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" :loading="loading" @click="submitForm('/manage/home')"
                       class="submit">登录
            </el-button>
          </el-form-item>
        </el-form>
      </div>
      <div class="sub-cont">
        <div class="img">
          <div class="img__text m--up">
            <h2>第一次来?</h2>
            <p>注册并发现大量的新机会!</p>
          </div>
          <div class="img__text m--in">
            <h2>加入我们 ?</h2>
            <p>如果你已经有一个账户,只需登录即可 </p>
            <span>We've missed you!</span>
          </div>
          <div class="img__btn">
            <span class="m--up">邮箱登录</span>
            <span class="m--in">手机登录</span>
          </div>
        </div>
        <div class="form sign-up" style="line-height: 50px">
          <h2>Time to feel like home</h2>
          <el-form ref="elForm2" :model="formData" :rules="rules2" size="medium" label-width="100px">
            <el-form-item label="电子邮箱" prop="email" style="width: 50%;margin-left: 110px;margin-top: 80px">
              <el-input v-model="formData.email" placeholder="请输入邮箱" show-word-limit clearable
                        prefix-icon='el-icon-message' :style="{width: '200px'}"></el-input>
            </el-form-item>
            <el-form-item label="验证码" prop="yzm2" style="width: 50%;margin-left: 110px;margin-top: 50px">
              <el-input v-model.number="formData.yzm2" :maxlength="6" :minlength="6"
                        clearable show-word-limit
                        prefix-icon='el-icon-chat-round'
                        oninput="value=value.replace(/[^0-9.]/g,'')"
                        :style="{width: '200px'}">
                <template #append >
                  <el-button class="test" style="width: 5px;
                margin-right: 10px;
                text-align: center;
                background-color: inherit;"
                             type="danger"
                             :disabled="remainingTime > 0"
                             @click="startTimer2">
                    {{ remainingTime > 0 ? '('+remainingTime+'s)' : '获取' }}
                  </el-button>
                </template>

              </el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary"  :loading="loading2" @click="submitForm2('/manage/home')"
                         class="submit">登录
              </el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import {sendPhoneCode, sendEmailCode,phoneLogin,emailLogin} from "@/api/login.js";
export default {
  name: 'login',
  props: {
    msg: String
  },
  data() {
    return {
      remainingTime: 0,
      loading: false,
      loading2:false,
      timer: null,
      formData: {
        pwd: '',
        phone: '',
        email: '',
        yzm: '',
        yzm2: ''
      },
      rules: {
        phone: [{
          required: true,
          message: '请输入手机号',
          trigger: 'change'
        }, {
          pattern: /^1(3|4|5|7|8|9)\d{9}$/,
          message: '手机号格式错误',
          trigger: 'blur'
        }],
        yzm: [
          {required: true, message: '验证码不能为空', trigger: 'change'},
          // {type: 'number', message: '验证码必须为数字', trigger: ['blur', 'change']}
        ],
      },
      rules2: {
        email: [
          {required: true, message: '请输入邮箱地址', trigger: 'change'},
          {type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change']}
        ],
        yzm2: [
          {required: true, message: '验证码不能为空', trigger: 'change'},
          // {type: 'number', message: '验证码必须为数字', trigger: ['blur', 'change']}
        ]
      },
    }
  },
  methods: {
    //手机号登录
    submitForm(path) {
      this.$refs['elForm'].validate(valid => {
        if (!valid) return
        // 显示loading 加载效果
        this.loading = true;
        const user = {
          phone:this.formData.phone,
          code: this.formData.yzm
        }
        this.timer = setTimeout(() => {
          phoneLogin(user).then( res=>{
            if (res.code == 200){
              this.$message({
                type: 'success',
                message: '登录成功!'
              })
              // 处理业务逻辑 以及发送请求
              this.$router.push(path)
            }else {
              this.$message({
                type: 'error',
                message: '登录失败!'
              });
            }
          }).finally((
              this.loading = false
          ));
        }, 1000);
      })
    },
    //邮箱登录
    submitForm2(path) {
      this.$refs['elForm2'].validate(valid => {
        if (!valid) return
        // TODO 提交表单
        // 显示loading 加载效果
        this.loading2 = true;
        const user = {
          email:this.formData.email,
          code: this.formData.yzm2
        }
        this.timer = setTimeout(() => {
          // 处理业务逻辑 以及发送请求
          emailLogin(user).then(res=>{
            console.log(res)
            if (res.code == 200){
              this.$message({
                type: 'success',
                message: '登录成功!'
              })
              // 处理业务逻辑 以及发送请求
              this.$router.push(path)
            }else {
              this.$message({
                type:'error',
                message: '登录失败!'
              })
            }
          }).finally((
              this.loading2 = false
          ));
        }, 1000);
      })
    },
    //发送手机验证码
    sendCode() {
      // TODO 提交表单
      let user ={phone:this.formData.phone}
      console.log(user)
      sendPhoneCode(user).then(res => {
        if (res.code == 200) {
          this.$message({
            type: 'success',
            message: '验证码发送成功!'
          })
        } else {
            this.$message({
              type: 'warning',
              message: '验证码发送失败!'
            });
        }
      })
    },

    startTimer() {
      this.$refs['elForm'].validateField('phone', valid => {
        if (valid) return
        // TODO 提交表单
        this.remainingTime = 60;
        this.sendCode()
        const timer = setInterval(() => {
          this.remainingTime--;
          if (this.remainingTime === 0) {
            clearInterval(timer);
          }
        }, 1000);
      })
    },
    startTimer2() {
      this.$refs['elForm2'].validateField('email', valid => {
        if (valid) return
        // TODO 提交表单
        this.remainingTime = 60;
        this.sendCodeTwo()
        const timer = setInterval(() => {
          this.remainingTime--;
          if (this.remainingTime === 0) {
            clearInterval(timer);
          }
        }, 1000);
      })
    },
    //发送邮箱验证码
    sendCodeTwo() {
      // TODO 提交表单
      let user ={email:this.formData.email}
      console.log(user)
      sendEmailCode(user).then(res => {
        if (res.code == 200) {
          this.$message({
            type: 'success',
            message: '验证码发送成功!'
          })
        } else {
          this.$message({
            type: 'warning',
            message: '验证码发送失败!'
          });
        }
      })
    },
  },
    mounted() {
      document.querySelector('.img__btn').addEventListener('click', function () {
        const contEl = document.querySelector('.cont');
        contEl.classList.toggle('s--signup');
        contEl.addEventListener('transitionend', function () {
          if (contEl.classList.contains('s--signup')) {
            contEl.querySelectorAll('input').forEach(inputEl => inputEl.value = '');
          }
        }, {once: true});
      });
    },
    beforeDestroy() {
      // eslint-disable-next-line no-irregular-whitespace
      clearInterval(this.timer); // 清除定时器
      this.timer = null;
    },

}

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
*, *:before, *:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

input, button {
  border: none;
  outline: none;
  background: none;
  font-family: "Open Sans", Helvetica, Arial, sans-serif;
}

.tip {
  font-size: 20px;
  margin: 40px auto 50px;
  text-align: center;
}

.cont1::before {
  content: '';
  position: fixed;
  background-color: #ededed;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  background-image: linear-gradient(to bottom right ,#d3dae9,#14c2c2)
}

.cont {
  overflow: hidden;
  position: relative;
  width: 900px;
  height: 550px;
  margin: 0 auto 100px;
  background: #fff;
}

.form {
  position: relative;
  width: 640px;
  height: 100%;
  transition: transform 1.2s ease-in-out;
  padding: 50px 30px 0;
}

.sub-cont {
  overflow: hidden;
  position: absolute;
  left: 640px;
  top: 0;
  width: 900px;
  height: 100%;
  padding-left: 260px;
  background: #fff;
  transition: transform 1.2s ease-in-out;
}

.cont.s--signup .sub-cont {
  transform: translate3d(-640px, 0, 0);
}

button {
  display: block;
  margin: 0 auto;
  width: 260px;
  height: 36px;
  border-radius: 30px;
  color: #fff;
  font-size: 15px;
  cursor: pointer;
}

.img {
  overflow: hidden;
  z-index: 2;
  position: absolute;
  left: 0;
  top: 0;
  width: 260px;
  height: 100%;
  padding-top: 360px;
}

.img:before {
  content: "";
  position: absolute;
  right: 0;
  top: 0;
  width: 900px;
  height: 100%;
  background-image: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/142996/sections-3.jpg");
  background-size: cover;
  transition: transform 1.2s ease-in-out;
}

.img:after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
}

.cont.s--signup .img:before {
  transform: translate3d(640px, 0, 0);
}

.img__text {
  z-index: 2;
  position: absolute;
  left: 0;
  top: 50px;
  width: 100%;
  padding: 0 20px;
  text-align: center;
  color: #fff;
  transition: transform 1.2s ease-in-out;
}

.img__text h2 {
  margin-bottom: 10px;
  font-weight: normal;
}

.img__text p {
  font-size: 14px;
  line-height: 1.5;
}

.cont.s--signup .img__text.m--up {
  transform: translateX(520px);
}

.img__text.m--in {
  transform: translateX(-520px);
}

.cont.s--signup .img__text.m--in {
  transform: translateX(0);
}

.img__btn {
  overflow: hidden;
  z-index: 2;
  position: relative;
  width: 100px;
  height: 36px;
  margin: 0 auto;
  background: transparent;
  color: #fff;
  text-transform: uppercase;
  font-size: 15px;
  cursor: pointer;
}

.img__btn:after {
  content: "";
  z-index: 2;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border: 2px solid #fff;
  border-radius: 30px;
}

.img__btn span {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  transition: transform 1.2s;
}

.img__btn span.m--in {
  transform: translateY(-72px);
}

.cont.s--signup .img__btn span.m--in {
  transform: translateY(0);
}

.cont.s--signup .img__btn span.m--up {
  transform: translateY(72px);
}

h2 {
  width: 100%;
  font-size: 26px;
  text-align: center;
}

label {
  display: block;
  width: 260px;
  margin: 25px auto 0;
  text-align: center;
}

label span {
  font-size: 12px;
  color: #cfcfcf;
  text-transform: uppercase;
}

input {
  display: block;
  width: 100%;
  margin-top: 5px;
  padding-bottom: 5px;
  font-size: 16px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  text-align: center;
}

.forgot-pass {
  margin-top: 15px;
  text-align: center;
  font-size: 12px;
  color: #cfcfcf;
}

.submit {
  margin-top: 30px;
  margin-left: 50px;
  margin-bottom: 10px;
  background: #d4af7a;
  /*text-transform: uppercase;*/
}

.style2 {
  margin-top: 10px;
  margin-right: 100px;
  margin-bottom: 10px;
  background: darkgrey;
  text-transform: uppercase;
}

.fb-btn {
  border: 2px solid #d3dae9;
  color: #8fa1c7;
}

.fb-btn span {
  font-weight: bold;
  color: #455a81;
}

.sign-in {
  transition-timing-function: ease-out;
}

.cont.s--signup .sign-in {
  transition-timing-function: ease-in-out;
  transition-duration: 1.2s;
  transform: translate3d(640px, 0, 0);
}

.sign-up {
  transform: translate3d(-900px, 0, 0);
}

.cont.s--signup .sign-up {
  transform: translate3d(0, 0, 0);
}

.icon-link {
  position: absolute;
  left: 5px;
  bottom: 5px;
  width: 32px;
}

.icon-link img {
  width: 100%;
  vertical-align: top;
}

.icon-link--twitter {
  left: auto;
  right: 5px;
}
.test[disabled]:not(.is-loading) {
  opacity: 0.5;
  cursor: not-allowed;
  width: 5px;
  margin-right: 10px;
  text-align: center;
}


</style>

 页面效果图:

手机登录

 邮箱登录

 短信:

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入夏忆梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值