注册发送邮箱验证码
This commit is contained in:
parent
fe6edf9e5d
commit
e4481507fa
@ -34,6 +34,8 @@ export default {
|
||||
position: absolute;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
display: block;
|
||||
left: 64px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,8 +1,8 @@
|
||||
import {createMemoryHistory, createRouter} from "vue-router";
|
||||
import {createRouter, createWebHashHistory} from "vue-router";
|
||||
import store from "./store";
|
||||
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{
|
||||
name: 'Main',
|
||||
|
@ -127,6 +127,7 @@ export default defineComponent({
|
||||
}
|
||||
.login-logo{
|
||||
height: 60px;
|
||||
width: 200px;
|
||||
}
|
||||
.title {
|
||||
background-color: #eaeaea;
|
||||
|
@ -13,8 +13,8 @@
|
||||
</div>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="0">
|
||||
<a href="http://www.alipay.com/">1st menu item</a>
|
||||
<a-menu-item key="0" @click="logout">
|
||||
<span>退出登录</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="1">
|
||||
<a href="http://www.taobao.com/">2nd menu item</a>
|
||||
@ -73,13 +73,14 @@ import dayjs from "dayjs";
|
||||
import {DownloadOutlined, RedoOutlined, DeleteOutlined, ShareAltOutlined,SettingFilled} from '@ant-design/icons-vue';
|
||||
import {useStore} from "vuex";
|
||||
import MainLogo from "../components/MainLogo.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
export default {
|
||||
name: "Main",
|
||||
components: {MainLogo, DownloadOutlined, RedoOutlined, DeleteOutlined, ShareAltOutlined,SettingFilled},
|
||||
setup() {
|
||||
const fileList = ref<FileItem[]>([])
|
||||
const store = useStore()
|
||||
const store = useStore(),router = useRouter()
|
||||
const userinfo = computed(() => store.state.loginUser)
|
||||
const loadFolderFiles = () => {
|
||||
api.folder.list().then(list => {
|
||||
@ -94,7 +95,11 @@ export default {
|
||||
reload() {
|
||||
location.reload()
|
||||
},
|
||||
formatDate(time) {
|
||||
logout(){
|
||||
store.commit('clearToken')
|
||||
router.replace('/login')
|
||||
},
|
||||
formatDate(time:string|number|Date) {
|
||||
return dayjs(time).format('MM-DD HH:mm')
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,11 @@
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>3.8.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 邮件发送依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.amqp</groupId>-->
|
||||
|
@ -21,12 +21,14 @@ public class SaTokenConfig {
|
||||
"/api/user/reg",
|
||||
"/api/user/forget",
|
||||
"/api/user/reset",
|
||||
"/api/user/check-email",
|
||||
"/api/user/check-account",
|
||||
"/swagger**",
|
||||
"/swagger-resources/**",
|
||||
"/v2/api-docs",
|
||||
"/picture/**"
|
||||
)
|
||||
.addExclude("/**")
|
||||
.addExclude("/api/**")
|
||||
.setError(new SaFilterErrorStrategy() {
|
||||
@Override
|
||||
public Object run(Throwable e) {
|
||||
|
@ -5,14 +5,17 @@ import cn.hutool.captcha.LineCaptcha;
|
||||
import cn.hutool.captcha.generator.RandomGenerator;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import xyz.longicorn.driver.dto.ApiResult;
|
||||
import xyz.longicorn.driver.service.EmailService;
|
||||
import xyz.longicorn.driver.util.RedisUtil;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@ -24,6 +27,8 @@ import java.util.concurrent.TimeUnit;
|
||||
public class CodeController {
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private EmailService emailService;
|
||||
|
||||
@RequestMapping("/code-id")
|
||||
public String createCodeId() {
|
||||
@ -74,4 +79,22 @@ public class CodeController {
|
||||
return ApiResult.success(data);
|
||||
}
|
||||
|
||||
@Value("${application.email-content}")
|
||||
private String codeTemplate;
|
||||
|
||||
@RequestMapping("/send-code")
|
||||
public ApiResult sendVerifyCode(String email) {
|
||||
RandomGenerator generator = new RandomGenerator("0123456789", 6);
|
||||
String code = generator.generate(); // 产生验证码
|
||||
// 发送验证码
|
||||
try {
|
||||
emailService.sendHTML(email, codeTemplate.replace("$code", code), "验证码");
|
||||
} catch (MessagingException e) {
|
||||
return ApiResult.error(1,"发送验证码失败");
|
||||
}
|
||||
// 记录该邮箱的验证码
|
||||
stringRedisTemplate.opsForValue().set("email:code:" + email, code,
|
||||
180, TimeUnit.SECONDS);
|
||||
return ApiResult.success(true);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package xyz.longicorn.driver.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import io.swagger.models.auth.In;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -55,6 +57,7 @@ public class UploadController {
|
||||
@SneakyThrows
|
||||
@PostMapping("/upload")
|
||||
public ApiResult upload(@RequestParam("parent") String parent, @RequestPart("file") MultipartFile file) {
|
||||
Integer uid =(Integer) StpUtil.getLoginId();
|
||||
//
|
||||
// 1.计算md5
|
||||
String md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
|
||||
@ -64,13 +67,13 @@ public class UploadController {
|
||||
if (parent.equals("/")) {
|
||||
fileInfo.setFolderId(0l);
|
||||
} else {
|
||||
FolderInfo folder = folderService.getByPath(1, parent);
|
||||
FolderInfo folder = folderService.getByPath(uid, parent);
|
||||
if (folder == null) {
|
||||
throw BizException.create("保存目录不存在");
|
||||
}
|
||||
fileInfo.setFolderId(folder.getId());
|
||||
}
|
||||
fileInfo.setUid(1);
|
||||
fileInfo.setUid(uid);
|
||||
fileInfo.setHash(md5);//
|
||||
fileInfo.setName(file.getOriginalFilename());
|
||||
fileInfo.setSize(file.getSize());
|
||||
|
@ -4,6 +4,7 @@ import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -11,7 +12,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import xyz.longicorn.driver.dto.ApiResult;
|
||||
import xyz.longicorn.driver.dto.LoginModel;
|
||||
import xyz.longicorn.driver.dto.LoginUserInfo;
|
||||
import xyz.longicorn.driver.pojo.LoginUser;
|
||||
import xyz.longicorn.driver.pojo.UserInfo;
|
||||
import xyz.longicorn.driver.service.UserService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -31,23 +34,65 @@ public class UserController {
|
||||
@SneakyThrows
|
||||
@PostMapping("/login")
|
||||
public ApiResult login(@Validated @RequestBody LoginModel model) {
|
||||
// 判断是否有验证码数据 有则需要判断验证码是否正确
|
||||
if (StringUtils.hasLength(model.getCodeId())) {
|
||||
String key = "code:" + model.getCodeId();
|
||||
String code1 = stringRedisTemplate.opsForValue().get(key);
|
||||
|
||||
String key = "code:" + model.getCodeId();
|
||||
String code1 = stringRedisTemplate.opsForValue().get(key);
|
||||
|
||||
if (code1 == null || !code1.equals(model.getCode())) {
|
||||
return ApiResult.error(1,"验证码无效");
|
||||
if (code1 == null || !code1.equals(model.getCode())) {
|
||||
return ApiResult.error(1, "验证码无效");
|
||||
}
|
||||
// 使原始验证码失效
|
||||
stringRedisTemplate.delete(key);
|
||||
}
|
||||
// 使原始验证码失效
|
||||
stringRedisTemplate.delete(key);
|
||||
|
||||
Thread.sleep(2);
|
||||
final LoginUser user = userService.login(model.getUsername(), model.getPassword());
|
||||
|
||||
return ApiResult.success(user);
|
||||
}
|
||||
|
||||
@PostMapping("/reg")
|
||||
public ApiResult reg(@RequestBody LoginUserInfo userInfo) {
|
||||
String code = stringRedisTemplate.opsForValue().get("email:code:" + userInfo.getEmail());
|
||||
if(code == null || !code.equalsIgnoreCase(userInfo.getCode())){
|
||||
return ApiResult.error(1,"验证码有误");
|
||||
}
|
||||
userService.signup(userInfo);
|
||||
return ApiResult.success(userInfo);
|
||||
}
|
||||
|
||||
@RequestMapping("/info")
|
||||
public ApiResult loginUserInfo() {
|
||||
return ApiResult.success(StpUtil.getSession().get("user"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮箱是否已经存在 不存在返回true 存在false
|
||||
*
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/check-email")
|
||||
public ApiResult checkEmail(String email) {
|
||||
return ApiResult.success(
|
||||
userService.getByEmail(email) == null
|
||||
);
|
||||
}
|
||||
|
||||
@RequestMapping("/check-account")
|
||||
public ApiResult checkAccount(String account) {
|
||||
return ApiResult.success(
|
||||
userService.getByAccount(account) == null
|
||||
);
|
||||
}
|
||||
/*
|
||||
注册的邮箱验证有2中方案
|
||||
1.填写验证码后才能提交注册(优点:不需要单独的激活业务 缺点:用户不一定能够及时收到正确验证码)
|
||||
-- 需要单独的业务同步发
|
||||
|
||||
2.直接注册 后台发送一封带有验证链接的邮件 (优点: 对于激活的时效性不需要太高(用消息队列 让其他服务发送) 缺点:必须有专门的激活业务,用户可能不会激活)
|
||||
-- 在注册完成后异步发送(推荐使用消息队列)
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ public class LoginModel {
|
||||
@NotBlank(message = "密码必须填写")
|
||||
private String password;
|
||||
// 验证码
|
||||
@NotBlank(message = "验证码必须填写")
|
||||
private String code;
|
||||
@NotBlank(message = "验证码必须填写")
|
||||
private String codeId;
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package xyz.longicorn.driver.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.longicorn.driver.pojo.UserInfo;
|
||||
|
||||
@Data
|
||||
public class LoginUserInfo extends UserInfo {
|
||||
private String code;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package xyz.longicorn.driver.pojo;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@ -17,7 +18,7 @@ import java.util.Date;
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class UserInfo implements Serializable {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
private String nickname;
|
||||
private String email;
|
||||
|
@ -0,0 +1,46 @@
|
||||
package xyz.longicorn.driver.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
@Service
|
||||
public class EmailService {
|
||||
@Resource
|
||||
private JavaMailSender javaMailSender;
|
||||
@Value("${spring.mail.from}")
|
||||
private String sender;
|
||||
|
||||
public void sendSimple(String email, String text, String subject) {
|
||||
// 简单邮件消息
|
||||
SimpleMailMessage message = new SimpleMailMessage();
|
||||
message.setSubject(subject); // 主题
|
||||
message.setText(text); // 内容
|
||||
message.setTo(email); // 收件人
|
||||
message.setFrom(sender); // 发件人
|
||||
javaMailSender.send(message);
|
||||
}
|
||||
|
||||
public void sendHTML(String email, String html, String subject) throws MessagingException {
|
||||
// 创建一个有内容类型的消息
|
||||
MimeMessage message = javaMailSender.createMimeMessage();
|
||||
// 消息内容设置助手
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
// 消息内容
|
||||
helper.setText(html, true); // 设置为html类型
|
||||
// 消息主题
|
||||
helper.setSubject(subject);
|
||||
// 接收者
|
||||
helper.setTo(email);
|
||||
// 发送者
|
||||
helper.setFrom(sender);
|
||||
// 发送
|
||||
javaMailSender.send(message);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package xyz.longicorn.driver.service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -21,6 +23,24 @@ public class UserService extends ServiceImpl<UserInfoMapper, UserInfo> {
|
||||
@Resource
|
||||
private LoginUserDao loginUserDao;
|
||||
|
||||
public UserInfo getByAccount(String account) {
|
||||
// 查询数据条件
|
||||
QueryWrapper q = new QueryWrapper();
|
||||
// 只能根据账号查询数据
|
||||
q.eq("account", account);
|
||||
q.last("limit 1");
|
||||
return baseMapper.selectOne(q);
|
||||
}
|
||||
|
||||
public UserInfo getByEmail(String email) {
|
||||
// 查询数据条件
|
||||
QueryWrapper q = new QueryWrapper();
|
||||
// 只能根据账号查询数据
|
||||
q.eq("email", email);
|
||||
q.last("limit 1");
|
||||
return baseMapper.selectOne(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用用户名和密码登录
|
||||
*
|
||||
@ -29,12 +49,7 @@ public class UserService extends ServiceImpl<UserInfoMapper, UserInfo> {
|
||||
* @return
|
||||
*/
|
||||
public LoginUser login(String account, String password) {
|
||||
// 查询数据条件
|
||||
QueryWrapper q = new QueryWrapper();
|
||||
// 只能根据账号查询数据
|
||||
q.eq("account", account);
|
||||
q.last("limit 1");
|
||||
UserInfo userInfo = baseMapper.selectOne(q);
|
||||
UserInfo userInfo = getByAccount(account);
|
||||
//
|
||||
if (userInfo == null) throw BizException.create("用户名不正确");
|
||||
// 获取密码并验证
|
||||
@ -46,7 +61,7 @@ public class UserService extends ServiceImpl<UserInfoMapper, UserInfo> {
|
||||
LoginUser user = new LoginUser();
|
||||
user.setAccount(account);
|
||||
StpUtil.login(userInfo.getId()); // 使用用户编号在sa-token 完成登录
|
||||
StpUtil.getSession().set("user",userInfo);
|
||||
StpUtil.getSession().set("user", userInfo);
|
||||
// 生成接口需要的token
|
||||
// user.setToken(IdUtil.fastSimpleUUID()); // 可以使用jwt生成token
|
||||
user.setToken(StpUtil.getTokenValue());
|
||||
@ -54,4 +69,25 @@ public class UserService extends ServiceImpl<UserInfoMapper, UserInfo> {
|
||||
user.setUserInfo(userInfo);
|
||||
return user;
|
||||
}
|
||||
|
||||
public UserInfo signup(UserInfo userInfo) {
|
||||
// 验证数据是否正确
|
||||
if (getByAccount(userInfo.getAccount()) != null) {
|
||||
throw BizException.create("用户名已经存在了");
|
||||
}
|
||||
if (getByEmail(userInfo.getEmail()) != null) {
|
||||
throw BizException.create("邮箱已经存在了");
|
||||
}
|
||||
// 随机的加密盐
|
||||
String salt = RandomUtil.randomString(6);
|
||||
userInfo.setSalt(salt);
|
||||
// 加密密码
|
||||
userInfo.setPassword(
|
||||
DigestUtil.md5Hex(userInfo.getPassword() + salt) // 1次md5加密
|
||||
);
|
||||
this.save(userInfo);
|
||||
//
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,27 @@
|
||||
spring:
|
||||
application:
|
||||
name: Driver
|
||||
mail:
|
||||
# 填写邮箱供应的SMTP地址
|
||||
# smtp.yandex.com
|
||||
host: smtp.qq.com
|
||||
# 用户名
|
||||
username: yaclty@qq.com
|
||||
# 填写密码 / 授权码 Qw!212er
|
||||
password: wojixltcsdlubfii
|
||||
|
||||
from: yaclty@qq.com
|
||||
# 发送服务器的端口
|
||||
port: 465
|
||||
# 配置连接属性 主要是加密传输
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
auth: true
|
||||
starttls:
|
||||
enable: true
|
||||
ssl:
|
||||
enable: true
|
||||
# 数据库
|
||||
datasource:
|
||||
name: defaultDataSource
|
||||
@ -72,4 +93,7 @@ mybatis-plus:
|
||||
type-aliases-package: xyz.longicorn.driver.pojo
|
||||
type-enums-package: xyz.longicorn.driver.pojo.enums
|
||||
sa-token:
|
||||
token-name: Authorization
|
||||
token-name: Authorization
|
||||
|
||||
application:
|
||||
email-content: 本次操作的验证码为:<b style="font-size:16px;color:red">$code</b>,验证码的有效期为3分钟
|
@ -96,8 +96,13 @@
|
||||
<el-button :loading="loginLoading" style="width: 100%" type="primary" @click="submitForm">登录
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<div class="forget-tips">
|
||||
<router-link class="reset-link" to="/forget">密码忘记了,点我重置密码!</router-link>
|
||||
<div class="forget-tips" style="overflow:hidden;">
|
||||
<div style="float: left">
|
||||
<router-link class="reset-link" to="/forget">密码忘记了,点我重置密码!</router-link>
|
||||
</div>
|
||||
<div style="float: right">
|
||||
<router-link class="reset-link" to="/reg">注册账号</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
@ -34,6 +34,7 @@ export default {
|
||||
})
|
||||
},
|
||||
logout(){
|
||||
this.$store.commit('clearToken')
|
||||
this.$router.replace('/login');
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,245 @@
|
||||
<style scoped>
|
||||
#page-login {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
background-color: pink;
|
||||
}
|
||||
|
||||
.login-wrapper {
|
||||
width: 800px;
|
||||
margin: auto;
|
||||
background-color: #fff;
|
||||
padding: 30px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.left-picture {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-right: dashed 1px #ccc;
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
margin: auto;
|
||||
fill: #999999;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
width: 350px;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.input-item {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.forget-tips {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reset-link {
|
||||
text-decoration: none;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.input-code-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btn-send {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<h1>Reg</h1>
|
||||
<div id="page-login">
|
||||
<div class="login-wrapper d-flex">
|
||||
<div class="flex-1 left-picture">
|
||||
<svg class="logo-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000">
|
||||
<path
|
||||
d="M549.766 97.925c19.974 4.609 50.703 35.339 62.995 55.312 35.339-13.828 36.875 41.484 46.094 55.312 23.047-16.901 46.094-35.339 46.094-55.312 0-21.51-30.729-35.339-30.729-41.484 0-12.292 38.411-12.292 41.484-12.292 50.703 0 106.016 39.948 106.016 96.797 0 27.656-9.219 41.484-33.802 70.677h32.266c21.51 0 27.656-3.073 55.312 7.682C923.125 294.591 960 348.367 960 389.852c0 3.073 0 9.219-1.536 13.828-4.609 3.073-12.292 3.073-16.901 4.609-15.365 1.536-32.266 6.146-47.63 7.682-47.63 0-50.703 0-53.776-1.536-1.536 1.536-1.536 0-1.536 4.609 0 3.073 7.682 44.557 10.755 67.604 9.219 56.849 12.292 115.234 19.974 173.62 1.536 7.682 7.682 15.365 9.219 23.047 3.073 13.828 6.146 27.656 6.146 39.948 0 153.646-245.833 208.958-321.119 208.958h-86.042c-115.234-9.219-248.906-52.24-301.145-138.281-4.609-7.682-18.437-39.948-18.437-50.703v-36.875c3.073-16.901 7.682-33.802 21.51-50.703v-84.505l12.292-132.135c-12.292 1.536-33.802 1.536-38.411 1.536-21.51 0-38.411-3.073-61.458-6.146-7.682-1.536-18.437-3.073-24.583-6.146-4.609-1.536-3.073-12.292-3.073-13.828 0-44.557 44.557-107.552 98.333-119.844 4.609-1.536 13.828-1.536 19.974-3.073l41.484-1.536c-13.828-10.755-36.875-46.094-36.875-59.922v-29.193c13.828-58.385 62.995-82.969 106.016-82.969 1.536 0 41.484 0 41.484 12.292 0 6.146-30.729 19.974-30.729 41.484 0 1.536 6.146 32.266 16.901 32.266 3.073 0-1.536-3.073 3.073-3.073 3.073 0 32.266 10.755 36.875 10.755h12.292l3.073-3.073c-19.974-16.901-30.729-36.875-36.875-53.776 12.292 7.682 18.438 9.219 29.193 9.219 27.656 0 46.094-15.365 78.359-29.193 24.583-10.755 52.24-13.828 78.359-18.437-12.292-9.219-24.583-16.901-36.875-23.047l38.411-1.536c7.68 1.537 15.362 4.61 23.044 6.146z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<h1 class="title">天牛网盘</h1>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="regForm"
|
||||
:rules="rules"
|
||||
status-icon
|
||||
size="large"
|
||||
@keyup.enter="submitForm"
|
||||
>
|
||||
<el-form-item label="" prop="nickname" class="input-item">
|
||||
<el-input v-model="regForm.nickname" placeholder="输入昵称" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="email" class="input-item">
|
||||
<el-input v-model="regForm.email" placeholder="输入邮箱" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="account" class="input-item">
|
||||
<el-input v-model="regForm.account" placeholder="输入用户名" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="password" class="input-item">
|
||||
<el-input v-model="regForm.password" placeholder="输入登录密码" type="password" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="password2" class="input-item">
|
||||
<el-input v-model="regForm.password2" placeholder="再次输入登录密码" type="password"
|
||||
autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="code" class="input-item input-code-item">
|
||||
<div style="display: flex;width: 100%">
|
||||
<div style="flex:1">
|
||||
<el-input v-model="regForm.code" placeholder="验证码" autocomplete="off"/>
|
||||
</div>
|
||||
<el-button :loading="sendCodeData.sending" :disabled="sendCodeData.countdown > 0" class="btn-send" @click="sendCode">
|
||||
{{ sendCodeData.countdown == 0 ? '发送验证码' : ('剩余' + sendCodeData.countdown + '秒') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button :loading="loginLoading" style="width: 100%" type="primary" @click="submitForm">立即注册
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<div class="forget-tips" style="overflow:hidden;">
|
||||
<router-link class="reset-link" replace to="/login">返回登录</router-link>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Reg.vue"
|
||||
}
|
||||
import {defineComponent, onMounted, reactive, ref} from 'vue'
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import {useRouter} from 'vue-router'
|
||||
import {useStore} from "vuex";
|
||||
import api from "../service/api";
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Reg',
|
||||
setup() {
|
||||
/**
|
||||
*
|
||||
* @type {Ref<FormInstance>}
|
||||
*/
|
||||
const form = ref(null);
|
||||
// 使用reactive将对象转换成响应对象
|
||||
const regForm = reactive({
|
||||
password: '',
|
||||
account: '',
|
||||
nickname: '',
|
||||
email: '',
|
||||
password2: '',
|
||||
code: ''
|
||||
})
|
||||
|
||||
|
||||
const checkPassword = (rule, value, callback) => {
|
||||
if (!value) callback(Error('请填写密码')) // 验证不通过
|
||||
else callback() // 验证通过
|
||||
}
|
||||
const emailValidator = (rule, value, callback) => {
|
||||
if (!value) callback(Error('邮箱不允许为空'))
|
||||
else if (!/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(value)) callback(Error('邮箱格式不正确'))
|
||||
else {
|
||||
api.user.checkEmail(value).then(b => {
|
||||
if (b) callback()
|
||||
else callback(Error('邮箱已被占用,请换一个'))
|
||||
})
|
||||
}
|
||||
};
|
||||
const checkPassword2 = (rule, value, callback) => {
|
||||
if (!value) callback(Error('请填写密码')) // 验证不通过
|
||||
else if (value != regForm.password) callback(Error('密码不一致')) // 验证不通过
|
||||
else callback() // 验证通过
|
||||
}
|
||||
const rules = reactive({
|
||||
account: [
|
||||
{required: true, message: '请填写用户名称', trigger: 'blur'}
|
||||
],
|
||||
password: [
|
||||
{validator: checkPassword, trigger: 'blur'}
|
||||
],
|
||||
password2: [
|
||||
{validator: checkPassword2, trigger: 'blur'}
|
||||
],
|
||||
email: [
|
||||
{validator: emailValidator, trigger: 'blur'}
|
||||
]
|
||||
})
|
||||
const router = useRouter(); // 获取路由对象
|
||||
const store = useStore();
|
||||
const regLoading = ref(false)
|
||||
const submitForm = () => {
|
||||
if (regLoading.value) return;
|
||||
// 验证表单
|
||||
form.value.validate(async (isValid) => {
|
||||
if (isValid) {
|
||||
// 设置loading未true
|
||||
regLoading.value = true
|
||||
try {
|
||||
await api.user.signup(regForm)
|
||||
ElMessage.success('注册成功')
|
||||
router.replace('/login').then().catch();
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || '登录错误')
|
||||
} finally {
|
||||
regLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
const sendCodeData = reactive({
|
||||
sending: false, // 是否在正在发送
|
||||
countdown: 0 // 倒计时
|
||||
})
|
||||
let timer = null
|
||||
const startCountDown = (time) => {
|
||||
sendCodeData.countdown = time
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
timer = setInterval(() => {
|
||||
sendCodeData.countdown--
|
||||
if (sendCodeData.countdown == 0) {
|
||||
// 停止倒计时
|
||||
clearInterval(timer)
|
||||
timer = null;
|
||||
}
|
||||
}, 1000);
|
||||
console.log('开始倒计时')
|
||||
}
|
||||
// 发送验证码
|
||||
const sendCode = async () => {
|
||||
if (regForm.email) {
|
||||
sendCodeData.sending = true
|
||||
try {
|
||||
await api.sendCode(regForm.email)
|
||||
// 应该禁用发送操作按钮
|
||||
ElMessage.info('发送验证码成功')
|
||||
startCountDown(60) // 60秒倒计时
|
||||
} catch (e) {
|
||||
throw e;
|
||||
console.log(e)
|
||||
} finally {
|
||||
sendCodeData.sending = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
regForm, submitForm, rules, form, loginLoading: regLoading, sendCode, sendCodeData
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -5,13 +5,16 @@ import {
|
||||
import router from "../router";
|
||||
|
||||
const API_PATH = "http://localhost:8080"
|
||||
class BizError extends Error{
|
||||
|
||||
class BizError extends Error {
|
||||
code = -1;
|
||||
constructor(message,code = -1) {
|
||||
|
||||
constructor(message, code = -1) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param api
|
||||
@ -77,7 +80,7 @@ function request(api, method = 'GET', postData = {}, progressChange = null) {
|
||||
return;
|
||||
}
|
||||
// 其他异常 直接抛出错误
|
||||
reject(new BizError(result.message,result.code))
|
||||
reject(new BizError(result.message, result.code))
|
||||
}
|
||||
}
|
||||
fetch(API_PATH + api, options)
|
||||
@ -98,8 +101,14 @@ export default {
|
||||
signup(params) {
|
||||
return request('/api/user/reg', 'POST', params);
|
||||
},
|
||||
info(){
|
||||
info() {
|
||||
return request('/api/user/info');
|
||||
},
|
||||
checkEmail(email) {
|
||||
return request('/api/user/check-email', 'GET', {email});
|
||||
},
|
||||
checkAccount(account) {
|
||||
return request('/api/user/check-account', 'GET', {account});
|
||||
}
|
||||
},
|
||||
folder: {
|
||||
@ -176,7 +185,10 @@ export default {
|
||||
return request('/api/share/create', 'POST', info)
|
||||
}
|
||||
},
|
||||
code(){
|
||||
code() {
|
||||
return request('/create');
|
||||
},
|
||||
sendCode(email) {
|
||||
return request('/send-code','GET',{email});
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user